diff --git a/README.md b/README.md
index 37ee8c5..3abc4fb 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
一个 python 实现的 Rustdesk API 接口,支持 WebUI 管理
-
+
@@ -137,7 +137,7 @@ services:
## 开发计划
-- [ ] 分享设备给其他已注册用户
+- [-] 分享设备给其他已注册用户
> 说明:类似网盘url分享,url激活后可以获得某个或某组或某个标签下的设备
> 备注:其实web api作为中间件,可做的不多,更多功能还是需要修改客户端来实现,就不太值当了。
diff --git a/api/admin_user.py b/api/admin_user.py
index fbfaeab..898a04d 100644
--- a/api/admin_user.py
+++ b/api/admin_user.py
@@ -93,6 +93,7 @@ admin.site.register(models.RustDeskToken, models.RustDeskTokenAdmin)
admin.site.register(models.RustDeskTag, models.RustDeskTagAdmin)
admin.site.register(models.RustDeskPeer, models.RustDeskPeerAdmin)
admin.site.register(models.RustDesDevice, models.RustDesDeviceAdmin)
+admin.site.register(models.ShareLink, models.ShareLinkAdmin)
admin.site.unregister(Group)
admin.site.site_header = 'RustDesk自建Web'
admin.site.site_title = '未定义'
\ No newline at end of file
diff --git a/api/migrations/0001_initial.py b/api/migrations/0001_initial.py
index d647e1e..6ead33e 100644
--- a/api/migrations/0001_initial.py
+++ b/api/migrations/0001_initial.py
@@ -1,4 +1,4 @@
-# Generated by Django 4.2.7 on 2023-12-04 21:05
+# Generated by Django 4.2.7 on 2023-12-14 12:08
from django.db import migrations, models
@@ -138,6 +138,34 @@ class Migration(migrations.Migration):
"ordering": ("-username",),
},
),
+ migrations.CreateModel(
+ name="ShareLink",
+ fields=[
+ (
+ "id",
+ models.AutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("uid", models.CharField(max_length=16, verbose_name="用户ID")),
+ ("shash", models.CharField(max_length=60, verbose_name="链接Key")),
+ ("peers", models.CharField(max_length=20, verbose_name="机器ID列表")),
+ ("is_used", models.BooleanField(default=False, verbose_name="是否使用")),
+ ("is_expired", models.BooleanField(default=False, verbose_name="是否过期")),
+ (
+ "create_time",
+ models.DateTimeField(auto_now_add=True, verbose_name="生成时间"),
+ ),
+ ],
+ options={
+ "verbose_name": "分享链接",
+ "verbose_name_plural": "链接列表",
+ "ordering": ("-create_time",),
+ },
+ ),
migrations.CreateModel(
name="UserProfile",
fields=[
diff --git a/api/models_work.py b/api/models_work.py
index 9ec1fa2..0d3968e 100644
--- a/api/models_work.py
+++ b/api/models_work.py
@@ -87,4 +87,28 @@ class RustDesDeviceAdmin(admin.ModelAdmin):
list_display = ('rid', 'hostname', 'memory', 'uuid', 'version', 'create_time', 'update_time')
search_fields = ('hostname', 'memory')
list_filter = ('rid', )
-
\ No newline at end of file
+
+
+
+class ShareLink(models.Model):
+ ''' 分享链接
+ '''
+ uid = models.CharField(verbose_name='用户ID', max_length=16)
+ shash = models.CharField(verbose_name='链接Key', max_length=60)
+ peers = models.CharField(verbose_name='机器ID列表', max_length=20)
+ is_used = models.BooleanField(verbose_name='是否使用', default=False)
+ is_expired = models.BooleanField(verbose_name='是否过期', default=False)
+ create_time = models.DateTimeField(verbose_name='生成时间', auto_now_add=True)
+
+
+
+ class Meta:
+ ordering = ('-create_time',)
+ verbose_name = "分享链接"
+ verbose_name_plural = "链接列表"
+
+
+class ShareLinkAdmin(admin.ModelAdmin):
+ list_display = ('shash', 'uid', 'peers', 'is_used', 'is_expired', 'create_time')
+ search_fields = ('peers', )
+ list_filter = ('is_used', 'uid', 'is_expired' )
\ No newline at end of file
diff --git a/api/templates/base.html b/api/templates/base.html
new file mode 100644
index 0000000..0bc6073
--- /dev/null
+++ b/api/templates/base.html
@@ -0,0 +1,44 @@
+{% load static %}
+
+
+
+{% block title %}{% endblock %}
+
+
+
+
+{% block link %}{% endblock %}
+
+
+
+
+
+
+- 首页
+- 分享
+
+{% if u.is_admin %}
+- 管理后台
+
+{% endif %}
+
+
+
+
+
+{% block content %}{% endblock %}
+
+
+
\ No newline at end of file
diff --git a/api/templates/msg.html b/api/templates/msg.html
new file mode 100644
index 0000000..86ff15c
--- /dev/null
+++ b/api/templates/msg.html
@@ -0,0 +1,12 @@
+{% extends "base.html" %}
+{% block title %}{{title}}{% endblock %}
+{% block legend_name %}信息{% endblock %}
+{% block content %}
+
+
+{% autoescape off %}
+ {{msg}}
+ {% endautoescape %}
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/api/templates/share.html b/api/templates/share.html
new file mode 100644
index 0000000..29cb3dc
--- /dev/null
+++ b/api/templates/share.html
@@ -0,0 +1,105 @@
+
+{% extends "base.html" %}{% load static %}
+{% block title %}分享机器{% endblock %}
+{% block link %}{% endblock %}
+{% block legend_name %}分享机器给其他用户{% endblock %}
+{% block content %}
+
+
+
+
+
1、链接有效期为15分钟,切勿随意分享给他人。
+
2、所分享的机器,被分享人享有相同的权限,如果机器设置了保存密码,被分享人也可以直接连接。
+
3、为保障安全,链接有效期为15分钟、链接仅有效1次。链接一旦被(非分享人的登录用户)访问,分享生效,后续访问链接失效。
+
+
+
+
+
+
+
+
+
+
+
+ | 链接地址 |
+ 创建时间 |
+ ID列表 |
+
+
+
+
+ {% for one in sharelinks %}
+
+ | {{one.shash}} |
+ {{one.create_time}} |
+ {{one.peers}} |
+
+
+ {% endfor %}
+
+
+
+
+
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/api/templates/show_work.html b/api/templates/show_work.html
index 4ca8970..992480f 100644
--- a/api/templates/show_work.html
+++ b/api/templates/show_work.html
@@ -1,46 +1,7 @@
-{% load static %}
-
-
-
- RustDesk WebUI
-
-
-
-
-
-
-
-
-
-
-
- - 首页
-
-
-
-
-
- {% if u.is_admin %}
- - 管理后台
-
- {% endif %}
-
-
-
-
-
+{% extends "base.html" %}
+{% block title %}RustDesk WebUI{% endblock %}
+{% block legend_name %}综合屏{% endblock %}
+{% block content %}
@@ -154,5 +115,4 @@ layui.use('element', function(){
-
-
\ No newline at end of file
+{% endblock %}
\ No newline at end of file
diff --git a/api/urls.py b/api/urls.py
index 28cd52f..e28f707 100644
--- a/api/urls.py
+++ b/api/urls.py
@@ -18,4 +18,5 @@ urlpatterns = [
#url(r'^register',views.register),
url(r'^user_action',views.user_action), # 前端
url(r'^work',views.work), # 前端
+ url(r'^share',views.share), # 前端
]
diff --git a/api/views_api.py b/api/views_api.py
index 5dc381e..2c4dc86 100644
--- a/api/views_api.py
+++ b/api/views_api.py
@@ -11,17 +11,7 @@ from django.db.models import Q
import copy
from .views_front import *
-salt = 'xiaomo'
-EFFECTIVE_SECONDS = 7200
-def getStrMd5(s):
- if not isinstance(s, (str,)):
- s = str(s)
-
- myHash = hashlib.md5()
- myHash.update(s.encode())
-
- return myHash.hexdigest()
def login(request):
result = {}
@@ -45,7 +35,7 @@ def login(request):
user.rid = rid
user.uuid = uuid
user.autoLogin = autoLogin
- user.rtype = rtype
+ user.rtype = rtype
user.deviceInfo = json.dumps(deviceInfo)
user.save()
diff --git a/api/views_front.py b/api/views_front.py
index 8a4ddf7..3f48324 100644
--- a/api/views_front.py
+++ b/api/views_front.py
@@ -6,7 +6,7 @@ from django.http import JsonResponse
from django.db.models import Q
from django.contrib.auth.decorators import login_required
from django.contrib import auth
-from api.models import RustDeskPeer, RustDesDevice, UserProfile
+from api.models import RustDeskPeer, RustDesDevice, UserProfile, ShareLink
from django.forms.models import model_to_dict
from itertools import chain
@@ -14,7 +14,20 @@ from django.db.models.fields import DateTimeField, DateField, CharField, TextFie
import datetime
from django.db.models import Model
import json
+import time
+import hashlib
+salt = 'xiaomo'
+EFFECTIVE_SECONDS = 7200
+
+def getStrMd5(s):
+ if not isinstance(s, (str,)):
+ s = str(s)
+
+ myHash = hashlib.md5()
+ myHash.update(s.encode())
+
+ return myHash.hexdigest()
def model_to_dict2(instance, fields=None, exclude=None, replace=None, default=None):
"""
@@ -87,7 +100,8 @@ def model_to_dict2(instance, fields=None, exclude=None, replace=None, default=No
def index(request):
- #return render(request, 'login3.html', {'info':''})
+ if request.user and request.user.username!='AnonymousUser':
+ return HttpResponseRedirect('/api/work')
return HttpResponseRedirect('/api/user_action?action=login')
@@ -199,3 +213,87 @@ def work(request):
print(all_info)
return render(request, 'show_work.html', {'single_info':single_info, 'all_info':all_info, 'u':u})
+
+
+def check_sharelink_expired(sharelink):
+ now = datetime.datetime.now()
+ if sharelink.create_time > now:
+ return False
+ if (now - sharelink.create_time).seconds <15 * 60:
+ return False
+ else:
+ sharelink.is_expired = True
+ sharelink.save()
+ return True
+
+
+@login_required(login_url='/api/user_action?action=login')
+def share(request):
+ peers = RustDeskPeer.objects.filter(Q(uid=request.user.id))
+ sharelinks = ShareLink.objects.filter(Q(uid=request.user.id) & Q(is_used=False) & Q(is_expired=False))
+
+
+ # 省资源:处理已过期请求,不主动定时任务轮询请求,在任意地方请求时,检查是否过期,过期则保存。
+ now = datetime.datetime.now()
+ for sl in sharelinks:
+ check_sharelink_expired(sl)
+ sharelinks = ShareLink.objects.filter(Q(uid=request.user.id) & Q(is_used=False) & Q(is_expired=False))
+ peers = [{'id':ix+1, 'name':f'{p.rid}|{p.alias}'} for ix, p in enumerate(peers)]
+ sharelinks = [{'shash':s.shash, 'is_used':s.is_used, 'is_expired':s.is_expired, 'create_time':s.create_time, 'peers':s.peers} for ix, s in enumerate(sharelinks)]
+
+ if request.method == 'GET':
+ url = request.build_absolute_uri()
+ if url.endswith('share'):
+ return render(request, 'share.html', {'peers':peers, 'sharelinks':sharelinks})
+ else:
+ shash = url.split('/')[-1]
+ sharelink = ShareLink.objects.filter(Q(shash=shash))
+ msg = ''
+ title = '成功'
+ if not sharelink:
+ title = '错误'
+ msg = f'链接{url}:
分享链接不存在或已失效。'
+ else:
+ sharelink = sharelink[0]
+ if str(request.user.id) == str(sharelink.uid):
+ title = '错误'
+ msg = f'链接{url}:
咱就说,你不能把链接分享给自己吧?!'
+ else:
+ sharelink.is_used = True
+ sharelink.save()
+ peers = sharelink.peers
+ peers = peers.split(',')
+ # 自己的peers若重叠,需要跳过
+ peers_self_ids = [x.rid for x in RustDeskPeer.objects.filter(Q(uid=request.user.id))]
+ peers_share = RustDeskPeer.objects.filter(rid__in=peers)
+ peers_share_ids = [x.rid for x in peers_share]
+
+ for peer in peers_share:
+ if peer.rid in peers_self_ids:
+ continue
+ peer = RustDeskPeer.objects.get(rid=peer.rid)
+ peer.id = None
+ peer.uid = request.user.id
+ peer.save()
+ msg += f"{peer.rid},"
+
+ msg += '已被成功获取。'
+
+ return render(request, 'msg.html', {'title':msg, 'msg':msg})
+ else:
+ data = request.POST.get('data', '[]')
+
+ data = json.loads(data)
+ if not data:
+ return JsonResponse({'code':0, 'msg':'数据为空。'})
+ rustdesk_ids = [x['title'].split('|')[0] for x in data]
+ rustdesk_ids = ','.join(rustdesk_ids)
+ sharelink = ShareLink(
+ uid=request.user.id,
+ shash = getStrMd5(str(time.time())+salt),
+ peers=rustdesk_ids,
+ )
+ sharelink.save()
+
+ return JsonResponse({'code':1, 'shash':sharelink.shash})
+
diff --git a/db.sqlite3_bak b/db.sqlite3_bak
new file mode 100644
index 0000000..8968aa7
Binary files /dev/null and b/db.sqlite3_bak differ
diff --git a/db/db.sqlite3 b/db/db.sqlite3
index 451e995..8968aa7 100644
Binary files a/db/db.sqlite3 and b/db/db.sqlite3 differ