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 %} + + + + + +

+ +
+{% block legend_name %}{% endblock %} +
+ +{% 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次。链接一旦被(非分享人的登录用户)访问,分享生效,后续访问链接失效。
+ +
+ + + + + + + + + + + + + + + + + {% for one in sharelinks %} + + + + + + + {% endfor %} + +
链接地址创建时间ID列表
{{one.shash}} {{one.create_time}} {{one.peers}}
+
+ + +
+ + +{% 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 - - - - - - - - - - - - -
- 综合屏 -
- +{% 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