ignatz před 4 roky
rodič
revize
6136a7290a
15 změnil soubory, kde provedl 139 přidání a 56 odebrání
  1. 11 20
      account/decorators.py
  2. 15 7
      account/views.py
  3. binární
      db.sqlite3
  4. 2 11
      docs/account.md
  5. 0 0
      docs/file.md
  6. 0 0
      docs/folder.md
  7. 7 1
      docs/group.md
  8. 7 3
      file/views.py
  9. 10 5
      folder/views.py
  10. 1 1
      group/models.py
  11. 12 6
      group/views.py
  12. 15 0
      private.rsa
  13. 0 0
      public.rsa
  14. 57 1
      utils/crypto.py
  15. 2 1
      utils/debug.py

+ 11 - 20
account/decorators.py

@@ -4,22 +4,8 @@ from .models import User
 from utils.http import make_json_response
 
 
-def user_passes_test(test_func, error):
-    def decorator(view_func):
-        @wraps(view_func)
-        def _wrapped_view(request, *args, **kwargs):
-            if test_func(request):
-                return view_func(request, *args, **kwargs)
-            return make_json_response(code=401, error=error)
-        return _wrapped_view
-    return decorator
-
-
-def login_required(function=None, error='未登录'):
-    """
-    Decorator for views that checks that the _user is logged in, redirecting
-    to the log-in page if necessary.
-    """
+def login_required(error='未登录'):
+    # 判断是否登录的decorator
     def is_login(request):
         if request.method != 'POST':
             return False
@@ -39,7 +25,12 @@ def login_required(function=None, error='未登录'):
             request.user = user
         return True
 
-    actual_decorator = user_passes_test(is_login, error)
-    if function:
-        return actual_decorator(function)
-    return actual_decorator
+    def decorator(view_func):
+        @wraps(view_func)
+        def _wrapped_view(request, *args, **kwargs):
+            if is_login(request):
+                return view_func(request, *args, **kwargs)
+            return make_json_response(code=401, error=error)
+        return _wrapped_view
+
+    return decorator

+ 15 - 7
account/views.py

@@ -5,7 +5,8 @@ from django.shortcuts import render
 from datetime import datetime, time
 from .models import User, LoginToken
 from django.http import JsonResponse
-from utils.decorators import debug_view
+from utils.debug import debug_view
+from utils.crypto import secure_transport
 from utils.http import make_json_response
 from .models import get_user
 from django.views.decorators.http import require_POST
@@ -20,7 +21,8 @@ def auth_with_username_or_email(username, password):
     return user
 
 
-@debug_view('username', 'password', 'email')
+@secure_transport
+@debug_view('password', 'email')
 @require_POST
 def register(request):
     username = request.POST.get('username', '')
@@ -43,7 +45,8 @@ def register(request):
         return make_json_response(code=500, error=str(e))
 
 
-@debug_view('username', 'password')
+@secure_transport
+@debug_view('password')
 @require_POST
 def login(request):
     username = request.POST.get('username', '')
@@ -81,7 +84,8 @@ def login(request):
     return make_json_response(token=token)
 
 
-@debug_view('username', 'token')
+@secure_transport
+@debug_view()
 @login_required
 def logout(request):
     user = get_user(request)
@@ -92,7 +96,8 @@ def logout(request):
     return make_json_response()
 
 
-@debug_view('username', 'email')
+@secure_transport
+@debug_view('email')
 @require_POST
 def send_email_verification_code(request):
     data = request.POST
@@ -115,12 +120,14 @@ def send_email_verification_code(request):
         return make_json_response(code=500, error='验证码发送失败')
 
 
-@debug_view('username', 'token')
+@secure_transport
+@debug_view()
 @require_POST
 def check_token(request):
     data = request.POST
     username = data.get('username')
     token = data.get('token')
+    print(username)
     try:
         user = User.objects.get(username=username)
     except:
@@ -133,7 +140,8 @@ def check_token(request):
         return make_json_response(code=303, error='验证码无效')
 
 
-@debug_view('username', 'password', 'token')
+@secure_transport
+@debug_view('password')
 @require_POST
 def reset_password(request):
     data = request.POST

binární
db.sqlite3


+ 2 - 11
account/api.md → docs/account.md

@@ -42,16 +42,7 @@
 
 ## reset_password
 ### params
-'username', 'email', 'token'
+'username', 'password', 'token'
 ### return
 - code=302, error='用户不存在'
-- code=301, error='邮箱错误'
-- code=500, error='验证码发送失败'
-
-## check_token
-### params
-'username', 'token'
-### return
-- code=302, error='用户不存在'
-- code=303, error='验证码无效'
-- code=200
+- code=303, error='验证码无效'

+ 0 - 0
file/api.md → docs/file.md


+ 0 - 0
folder/api.md → docs/folder.md


+ 7 - 1
group/group.md → docs/group.md

@@ -32,4 +32,10 @@
 - code=401, error='未登录'
 - code=403, error='群不存在'
 - code=421, error='群主不可退群'
-- code=200
+- code=200
+
+## group_list
+### params
+'username', 'token'
+### return
+- code=200, group_list

+ 7 - 3
file/views.py

@@ -8,15 +8,17 @@ from .judgement_function import judge_filepath, format_size
 from django.utils.http import urlquote
 import os
 from account.models import get_user
-from utils.decorators import debug_view
+from utils.debug import debug_view
 from utils.http import make_json_response
 from utils.permission import can_delete
+from utils.crypto import secure_transport
 
 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 
 # Create your views here.
 
 
+@secure_transport
 @debug_view(template_name='upload_file.html')
 @login_required
 def upload_file(request):
@@ -56,7 +58,8 @@ def upload_file(request):
     return make_json_response()
 
 
-@debug_view('username', 'token', 'file_id')
+@secure_transport
+@debug_view('file_id')
 @login_required
 def download_file(request):
     user = get_user(request)
@@ -76,7 +79,8 @@ def download_file(request):
     return response
 
 
-@debug_view('username', 'token', 'file_id')
+@secure_transport
+@debug_view('file_id')
 @login_required
 def delete_file(request):
     data = request.POST

+ 10 - 5
folder/views.py

@@ -1,14 +1,16 @@
 from account.decorators import login_required
 from .models import Folder
 from account.models import get_user
-from utils.decorators import debug_view
+from utils.debug import debug_view
 from utils.http import make_json_response
 from utils.permission import can_delete
+from utils.crypto import secure_transport
 
 # Create your views here.
 
 
-@debug_view('username', 'token')
+@secure_transport
+@debug_view()
 @login_required
 def get_root_folder(request):
     # 获取根目录
@@ -17,7 +19,8 @@ def get_root_folder(request):
 
 
 # 在根目录下列出所有文件夹与文件
-@debug_view('username', 'token', 'folder_id')
+@secure_transport
+@debug_view('folder_id')
 @login_required
 def folder_list(request):
     data = request.POST
@@ -37,7 +40,8 @@ def folder_list(request):
 
 
 # 增文件夹
-@debug_view('username', 'token', 'father_folder_id', 'folder_name')
+@secure_transport
+@debug_view('father_folder_id', 'folder_name')
 @login_required
 def add_folder(request):
     data = request.POST
@@ -61,7 +65,8 @@ def add_folder(request):
 
 
 # 删除文件夹
-@debug_view('username', 'token', 'folder_id')
+@secure_transport
+@debug_view('folder_id')
 @login_required
 def delete_folder(request):
     data = request.POST

+ 1 - 1
group/models.py

@@ -31,5 +31,5 @@ class Group(models.Model):
 # 信号接收函数,每当新建Group实例的时候自动调用
 @receiver(post_save, sender=Group)
 def add_creator_to_group_members(sender, instance, created, **kwargs):
-    if created and instance.creator not in instance.members:
+    if created and not instance.members.filter(username=instance.creator.username):
         instance.members.add(instance.creator)

+ 12 - 6
group/views.py

@@ -1,13 +1,15 @@
 from account.decorators import login_required
 from .models import Group
 from account.models import User, get_user
-from utils.decorators import debug_view
+from utils.debug import debug_view
 from utils.http import make_json_response
+from utils.crypto import secure_transport
 
 # Create your views here.
 
 
-@debug_view('username', 'token', 'group_id')
+@secure_transport
+@debug_view('group_id')
 @login_required
 def get_group_root_folder(request):
     user = get_user(request)
@@ -21,7 +23,8 @@ def get_group_root_folder(request):
     return make_json_response(root_folder_id=root_folder.folder_id)
 
 
-@debug_view('username', 'token', 'group_id')
+@secure_transport
+@debug_view('group_id')
 @login_required
 def join_group(request):
     user = get_user(request)
@@ -38,7 +41,8 @@ def join_group(request):
     return make_json_response()
 
 
-@debug_view('username', 'token', 'group_name')
+@secure_transport
+@debug_view('group_name')
 @login_required
 def create_group(request):
     user = get_user(request)
@@ -51,7 +55,8 @@ def create_group(request):
     return make_json_response()
 
 
-@debug_view('username', 'token', 'group_id')
+@secure_transport
+@debug_view('group_id')
 @login_required
 def quit_group(request):
     user = get_user(request)
@@ -69,7 +74,8 @@ def quit_group(request):
 
 
 # 获取你所在的所有群组
-@debug_view('username', 'token')
+@secure_transport
+@debug_view()
 @login_required
 def group_list(request):
     user = get_user(request)

+ 15 - 0
private.rsa

@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQCRQZ5O/AOAjeYAaSFf6Rjhqovws78I716I9oGF7WxCIPmcaUa1
+YuyLOncCCuPsaw69+RMWjdbOBp8hd4PPM/d4mKTOVEYUE0SfxhhDTZaM5CzQEUXU
+yXy7icQTGR5wBjrbjU1yHCKOf5PJJZZQWB06husSFZ40TdL7FdlBpZ1u1QIDAQAB
+AoGATKE/cQ/GkTVK14Ce2MhSFgsxFGTfLUmKp9rT7eGZMTHQPVHUubBcdf779Znl
+MD4yYspZ5ZYickJQBQnWAaO6s5om/Pt0PBFNzAz/WzZaccQtYKOe/6v022splsjp
+N6StlV2l/vL0JpZYEWTEEYtiRQR1aHqdX9ce5UrH9k6YqYECQQDSZTvlA5sp3PV/
+9WHa1WgzouKO4N8PbtXlavQdNflpJQD9278SKAUSPex5Qzyh8fgmV3jg8dcY9MTz
+itx1M+RRAkEAsL3WoDz7Vh4R8dG6Dxf7OGa01CB9OGn7nj1LsCk0EEYo55dHm9on
+QXtM9lQB9brT6bP6eEqbk9xyNzySfDJVRQJABcqbl3Y98y0N5PPQOcHeGG3HZr9x
+5G7cnHARQCyYLPjDyjkeTVWkrhfeRog/RwXuGsAVp7uAfENgmIOeBevjwQJASjYL
+7pBsgEZ0BnOnijrpk08c0o0pxwxJSLI4G6nRYJv1BPkyajB5lzcso6m2gPWHkXOu
+0d+R384Kb0MRxvBjeQJBAMUijpXwAlAkPwmSaLxEzJmlA2rOOt4W61M56e9bkTJP
+ET+w2P5QZxhjHlHnmSyFSuV9jYHKfZyUEilghraZ3y0=
+-----END RSA PRIVATE KEY-----

+ 0 - 0
utils/public.rsa → public.rsa


+ 57 - 1
utils/crypto.py

@@ -1,18 +1,74 @@
-from Crypto import Random
+import base64
+
 from Crypto.PublicKey import RSA
 from Crypto.Cipher import PKCS1_v1_5 as PKCS1_cipher
+from Crypto.Cipher import AES
+from functools import wraps
+from utils.http import make_json_response
+import json
 
+IV = '16-Bytes--String'
 
 with open('public.rsa') as f:
     key = f.read()
     public_key = RSA.import_key(key)
     public_cipher = PKCS1_cipher.new(public_key)
+    print(public_key.exportKey().decode(encoding='utf-8'))
 
 with open('private.rsa') as f:
     key = f.read()
     private_key = RSA.import_key(key)
     private_cipher = PKCS1_cipher.new(private_key)
+    # print(private_key.exportKey().decode(encoding='utf-8'))
+
+
+# 安全传输decorator
+def secure_transport(view_func):
+    @wraps(view_func)
+    def _wrapped_view(request, *args, **kwargs):
+        data = request.POST
+        enc_key = data.get('enc_key')
+        cipher_text = data.get('cipher_text')
+        if not enc_key or not cipher_text:
+            print('无加密')
+            return view_func(request, *args, **kwargs)
+        aes_key = private_cipher.decrypt(base64.b64decode(enc_key.encode('utf-8')), b'error').decode('utf-8')
+        print(f'key={aes_key}')
+
+        aes_cipher = AES.new(aes_key.encode('utf-8'), AES.MODE_CBC, IV.encode('utf-8'))
+        decrypted = aes_cipher.decrypt(base64.b64decode(cipher_text.encode('utf-8')))
+        # print(decrypted)
+        decrypted = decrypted[:-decrypted[-1]]
+        # print(decrypted)
+        plain_text = decrypted.decode('utf-8')
+        print(plain_text)
+
+        loaded = json.loads(plain_text)
+        dec_request = request
+        dec_request.POST = {**request.POST, **loaded}
+
+        raw_response = view_func(dec_request, *args, **kwargs)
+
+        content = raw_response.content
+        padding = 16 - len(content) % 16
+        content += bytes([padding] * padding)
+        print(content)
+
+        aes_cipher = AES.new(aes_key.encode('utf-8'), AES.MODE_CBC, IV.encode('utf-8'))
+        enc_content = base64.b64encode(aes_cipher.encrypt(content)).decode('utf-8')
+        print(enc_content)
+        return make_json_response(enc_content=enc_content)
+    return _wrapped_view
+
+
+def test():
+    plain_text = '{"username": "user1"}'
+    encrypted = public_cipher.encrypt(bytes(plain_text.encode('utf8')))
+    cipher_text = base64.b64encode(encrypted)
+    print(cipher_text.decode('utf8'))
 
+    decrypted = private_cipher.decrypt(base64.b64decode(cipher_text), b'error')
+    print(decrypted.decode('utf8'))
 
 # print(public_key.exportKey().decode('utf-8'))
 

+ 2 - 1
utils/decorators.py → utils/debug.py

@@ -6,6 +6,7 @@ from django.shortcuts import render
 from django.http import JsonResponse
 
 DEBUG = settings.DEBUG
+DEFAULT_ITEMS = ['username', 'token', 'enc_key', 'cipher_text']
 
 
 def debug_view(*items, template_name='debug.html'):
@@ -14,7 +15,7 @@ def debug_view(*items, template_name='debug.html'):
         def _wrapped_view(request, *args, **kwargs):
             if DEBUG and request.method == 'GET':
                 print('render debug view')
-                return render(request, template_name, {'items': items})
+                return render(request, template_name, {'items': [*items, *DEFAULT_ITEMS]})
             else:
                 return view_func(request, *args, **kwargs)
         return _wrapped_view