commit 0cd4633edb9d53d5403e94006b755b3c47e2f239 Author: RainSun Date: Sat Feb 22 09:45:11 2020 +0800 finish v1 diff --git a/ReadMe.md b/ReadMe.md new file mode 100644 index 0000000..f318a44 --- /dev/null +++ b/ReadMe.md @@ -0,0 +1,51 @@ +# ccb + +## 错误代码一览 +* 200:成功 +* /login + * 用户登录或者注册 + * 100:校验失败 + * 101:用户不存在 + * 102:user_info获取失败 + * 103:新用户插入失败 + * 104: 签名失败 + * 105: 用户未激活,未重新发送邮件 + * 106:密码错误 + * 107:注册成功,验证码已下发 + * 108:用户未激活,已重新发送邮件 +* /activation + * 接受开启账户的uuid + * 400:校验失败 + * 401: active用户不存在 + * 402: active覆写失败 + * 403:签名失败 + * 404:用户不存在 + * 405:user_info获取失败 + * 406:该用户已经激活过了 + * 407:验证码非本人所有 +* /download + * 更新到本地 + * 500:校验失败 + * 501:签名失败 + * 502:密码错误 + * 101:用户不存在 + * 102:user_info获取失败 +* /upload + * 上传到云端 + * 300:校验失败 + * 301:codebook用户不存在 + * 302:codebook覆写失败 + * 303:密码错误 + * 304:签名失败 + * 101:用户不存在 + * 102:user_info获取失败 +# 功能总结 +* 注册/登录 + * 用户发来邮箱地址和密码(密码加密一下) + * 前后端校验 + * 如果注册过,就返回200 + * 前端收到了codebook就把用户密码加密的存起来 + * 之后就可以免登录刷新 + * 如果没注册过就给那个邮箱发验证邮件,内容是uuid,同时放进数据库里 内容为 mail_addr codebook is_active uuid update_time password + * 上传 + * 下载 \ No newline at end of file diff --git a/canary.png b/canary.png new file mode 100644 index 0000000..1f5b367 Binary files /dev/null and b/canary.png differ diff --git a/ccb.py b/ccb.py new file mode 100644 index 0000000..d00984b --- /dev/null +++ b/ccb.py @@ -0,0 +1,45 @@ +# 将lib里边的文件加到路由中 +import sys +sys.path.append('./lib') +from flask import Flask, escape, url_for, request, render_template, redirect, abort, send_from_directory, Response, make_response +from allFunction import manageLogin, manageActivation, manageDownload, manageUpload + +app = Flask(__name__) + + +if __name__ == '__main__': + app.run() + +# 测试用根路由 +@app.route('/api/') +def sayHello(): + return 'Hello! Glad to serve you, please go to the official website: https://ccb.canary.moe' + +# 登录或者注册 +@app.route('/api/login', methods=["POST"]) +def login(): + res = manageLogin(request) + return res + +# 激活账户 +@app.route('/api/activation', methods=["POST"]) +def activation(): + res = manageActivation(request) + return res + +# 更新本地数据 +@app.route('/api/download', methods=["POST"]) +def download(): + res = manageDownload(request) + return res + +# 更新云端数据 +@app.route('/api/upload', methods=["POST"]) +def upload(): + res = manageUpload(request) + return res + +# 访问拦截器转发到根路由 +@app.errorhandler(404) +def miss(e): + return redirect('/api') \ No newline at end of file diff --git a/gunicorn.conf.py b/gunicorn.conf.py new file mode 100644 index 0000000..425b510 --- /dev/null +++ b/gunicorn.conf.py @@ -0,0 +1,13 @@ +# 并行工作线程数 +workers = 4 +# 监听内网端口5000【按需要更改】 +bind = '127.0.0.1:5005' +# 设置守护进程【关闭连接时,程序仍在运行】 +daemon = True +# 设置超时时间120s,默认为30s。按自己的需求进行设置 +timeout = 120 +# 设置访问日志和错误信息日志路径 +accesslog = './logs/acess.log' +errorlog = './logs/error.log' +#自动重启 +autostart = True \ No newline at end of file diff --git a/lib/allFunction.py b/lib/allFunction.py new file mode 100644 index 0000000..281237a --- /dev/null +++ b/lib/allFunction.py @@ -0,0 +1,191 @@ +# 引入数据库操作函数 +from db import searchUser, insertUser, updateCodebook, ActivateUser, searchUserByUuid +# 引入json +import json +# 引入时间 +import datetime +# 引入发送邮件 +from mail import sendMail +# 引入md5 +from hashlib import md5 +# 引入随机数 +import random +# 主处理逻辑函数----------------------------------------------------------- + +# 处理用户登录 前端发送 mail_addr password update_time +def manageLogin(request): + # json化,应该能当dict用 + try: + data_cache = json.loads(request.form['data']) + except Exception as e: + return {'errcode': 100, 'errmsg': '校验失败'} + checked = checkData(data_cache) + if checked: + # 校验通过 + user_info = searchUser(data_cache['mail_addr']) + if user_info['errcode'] == 200: + # 用户登录 + user_info = user_info['user_info'] + if user_info['active']: + # 已经激活的账户 + if user_info['password'] == data_cache['password']: + # 密码正确 + return {'errcode': 200, 'errmsg': 'ok', 'update_time': user_info['update_time']} + else: + # 密码错误 + return {'errcode': 106, 'errmsg': '密码错误'} + else: + # 没激活的用户 + time_difference = int(data_cache['update_time']) - int(user_info['update_time']) + if time_difference > 1000 * 60 * 5: + # 超过五分钟,重新发送uuid + send_str = '非常感谢您的使用,您的验证码为:' + user_info['uuid'] + sendMail('欢迎注册Canary Codebook', send_str, [user_info['mail_addr']]) + return {'errcode': 108, 'errmsg': '用户未激活,已重新发送邮件'} + else: + return {'errcode': 105, 'errmsg': '用户未激活,未重新发送邮件'} + elif user_info['errcode'] == 101: + # 用户注册 + user_data = createUserData(data_cache) + insert_res = insertUser(user_data) + if insert_res['errcode'] == 200: + # 新用户插入成功,发送邮件 + send_str = '非常感谢您的使用,您的验证码为:' + user_data['uuid'] + sendMail('欢迎注册Canary Codebook', send_str, [user_data['mail_addr']]) + return {'errcode': 107, 'errmsg': '注册成功,验证码已下发'} + else: + # 用户插入失败 + return insert_res + else: + # 查询错误 + return user_info + else: + return {'errcode': 104, 'errmsg': '签名失败'} + + +# 处理激活用户 用户发来uuid mail_addr +def manageActivation(request): + # json化,应该能当dict用 + try: + data_cache = json.loads(request.form['data']) + except Exception as e: + return {'errcode': 400, 'errmsg': '校验失败'} + checked = checkData(data_cache) + if checked: + # 校验通过 + # 判断用户之前是否未激活 + user_info = searchUserByUuid(data_cache['uuid']) + if user_info['errcode'] == 200: + # 用户存在 + user_info = user_info['user_info'] + if user_info['mail_addr'] == data_cache['mail_addr']: + # 是自己的激活码 + if user_info['active']: + return {'errcode': 406, 'errmsg': '该用户已经激活过了', 'update_time': user_info['update_time']} + else: + # 进入激活程序 + active_res = ActivateUser(data_cache['uuid']) + if active_res['errcode'] == 200: + # 激活成功 + return {'errcode': 200, 'errmsg': 'ok', 'update_time': user_info['update_time']} + else: + # 激活失败 + return active_res + else: + # 输入的不是自己的激活码 + return {'errcode': 407, 'errmsg': '验证码非本人所有'} + else: + # 用户不存在或者错误 + return user_info + else: + return {'errcode': 403, 'errmsg': '签名失败'} + +# 处理云端覆写本地数据 用户发来 mail_addr password +def manageDownload(request): + # json化,应该能当dict用 + try: + data_cache = json.loads(request.form['data']) + except Exception as e: + return {'errcode': 500, 'errmsg': '校验失败'} + checked = checkData(data_cache) + if checked: + # 校验通过 + # 获取用户信息 + user_info = searchUser(data_cache['mail_addr']) + if user_info['errcode'] == 200: + user_info = user_info['user_info'] + if user_info['password'] == data_cache['password']: + # 密码正确 + return {'errcode': 200, 'errmsg': 'ok', 'codebook': user_info['codebook']} + else: + # 密码错误 + return {'errcode': 502, 'errmsg': '密码错误'} + else: + return user_info + else: + return {'errcode': 501, 'errmsg': '签名失败'} + +# 处理本地覆写云端数据 用户发来 mail_addr password codebook update_time +def manageUpload(request): + # json化,应该能当dict用 + try: + data_cache = json.loads(request.form['data']) + except Exception as e: + return {'errcode': 300, 'errmsg': '校验失败'} + checked = checkData(data_cache) + if checked: + # 校验通过 + # 获取用户信息 + user_info = searchUser(data_cache['mail_addr']) + if user_info['errcode'] == 200: + user_info = user_info['user_info'] + if user_info['password'] == data_cache['password']: + # 密码正确 + return updateCodebook(user_info['mail_addr'], data_cache['codebook'], data_cache['update_time']) + else: + # 密码错误 + return {'errcode': 502, 'errmsg': '密码错误'} + else: + return user_info + else: + return {'errcode': 304, 'errmsg': '签名失败'} + +# 工具函数--------------------------------------------------------------- + +# MD5 校验 +def checkData(data): + d = data.copy() + try: + d.pop('sign') + except KeyError: + pass + d = str(d) + d = d.replace(' ', '') + md = md5() + md.update(d.encode('utf-8')) + r = md.hexdigest().upper() + # return r == data['sign'] + return True + +# 创建用户初始信息 +def createUserData(data): + user_info = { + 'mail_addr' : data['mail_addr'], + 'password': data['password'], + 'update_time': data['update_time'], + 'codebook': '', + 'active': False, + 'uuid': create_uuid() + } + return user_info + +#生成唯一的名称字符串,防止重名问题 +def create_uuid(): + # 生成当前时间 + nowTime = datetime.datetime.now().strftime("%Y%m%d%H%M%S") + # 生成的随机整数n,其中0<=n<=100 + randomNum = random.randint(0, 100) + if randomNum <= 10: + randomNum = str(0) + str(randomNum) + uniqueNum = str(nowTime) + str(randomNum) + return uniqueNum \ No newline at end of file diff --git a/lib/db.py b/lib/db.py new file mode 100644 index 0000000..e3bc8e3 --- /dev/null +++ b/lib/db.py @@ -0,0 +1,80 @@ +from pymongo import MongoClient +from bson import ObjectId, json_util +import re + +# 主环境 (生产环境为production,开发环境为development) +setting = 'development' + +# 获取数据集 +def col(arg): + conn = MongoClient('mongodb://ccb:srVgEGwTf4@localhost:27017/ccb') + if setting == 'development': + arg += '_test' + if arg == 'user_info': + return conn.ccb.user_info + elif arg == 'user_info_test': + return conn.ccb.user_info_test + else: + return False + + +# 查询有无用户 +def searchUser(mail_addr): + try: + user_info = col('user_info').find_one({"mail_addr": mail_addr}) + if user_info: + return {'errcode': 200, 'user_info': user_info, 'errmsg': 'ok'} + else: + return {'errcode': 101, 'errmsg': '用户不存在'} + except Exception as e: + print(e) + # id不合法 + return {'errcode': 102, 'errmsg': 'user_info获取失败'} + +# 插入一个新的用户 +def insertUser(data): + try: + col('user_info').insert_one(data) + except Exception as e: + # 插入失败 + return {'errcode': 103, 'errmsg': '新用户插入失败'} + return {'errcode': 200, 'errmsg': '新用户插入成功'} + +# 更新密码本 +def updateCodebook(mail_addr, content, update_time): + try: + res = col('user_info').update({"mail_addr": mail_addr}, + {'$set': {'codebook': content, 'update_time': update_time}}) + # 判断有没有是否成功 + if(res['updatedExisting']): + return {'errcode': 200, 'errmsg': 'codebook覆写成功', 'update_time': update_time} + else: + return { 'errcode': 301, 'errmsg': 'codebook用户不存在'} + except Exception as e: + return {'errcode': 302, 'errmsg': 'codebook覆写失败'} + +# 激活用户 +def ActivateUser(uuid): + try: + res = col('user_info').update({"uuid": uuid}, + {'$set': {'active': True}}) + # 判断有没有是否成功 + if(res['updatedExisting']): + return {'errcode': 200, 'errmsg': 'active覆写成功'} + else: + return { 'errcode': 401, 'errmsg': 'active用户不存在'} + except Exception as e: + return {'errcode': 402, 'errmsg': 'active覆写失败'} + +# 查询有无用户 +def searchUserByUuid(uuid): + try: + user_info = col('user_info').find_one({"uuid": uuid}) + if user_info: + return {'errcode': 200, 'user_info': user_info, 'errmsg': 'ok'} + else: + return {'errcode': 404, 'errmsg': '用户不存在'} + except Exception as e: + print(e) + # id不合法 + return {'errcode': 405, 'errmsg': 'user_info获取失败'} \ No newline at end of file diff --git a/lib/mail.py b/lib/mail.py new file mode 100644 index 0000000..aabfc6e --- /dev/null +++ b/lib/mail.py @@ -0,0 +1,32 @@ +# coding=utf-8 +import smtplib +from email.mime.text import MIMEText +# 发送纯文本格式的邮件 + +def sendMail(title, content, mailto_list): + msg = MIMEText(content, 'plain', 'utf-8') + #发送邮箱地址 + sender = 'canarycodebook@163.com' + #邮箱授权码,非登陆密码 + password = 'eTn49CftDfaytar' + #收件箱地址 + #receiver = '19xxxxxxx9@qq.com' + # mailto_list = ['1144131090@qq.com','nayiyewosile@qq.com'] #群发邮箱地址 + + #smtp服务器 + smtp_server = 'smtp.163.com' + #发送邮箱地址 + msg['From'] = sender + #收件箱地址 + #msg['To'] = receiver + msg['To'] =';'.join(mailto_list) #发送多人邮件写法 + #主题 + msg['Subject'] = title + + server = smtplib.SMTP(smtp_server,25) # SMTP协议默认端口是25 + server.login(sender,password) #ogin()方法用来登录SMTP服务器 + server.set_debuglevel(1) #打印出和SMTP服务器交互的所有信息。 + server.sendmail(sender,mailto_list,msg.as_string()) #msg.as_string()把MIMEText对象变成str server.quit() + + # 第一个参数为发送者,第二个参数为接收者,可以添加多个例如:['hello@163.com','xxx@qq.com',]# 第三个参数为发送的内容 + server.quit() \ No newline at end of file diff --git a/start.sh b/start.sh new file mode 100644 index 0000000..a8480d9 --- /dev/null +++ b/start.sh @@ -0,0 +1,4 @@ +#!/bin/sh +cd /home/pi/data/ccb/backEnd +. venv/bin/activate +gunicorn ccb:app -c gunicorn.conf.py \ No newline at end of file diff --git a/test.py b/test.py new file mode 100644 index 0000000..cf80123 --- /dev/null +++ b/test.py @@ -0,0 +1,34 @@ +# coding=utf-8 +import smtplib +from email.mime.text import MIMEText +# 发送纯文本格式的邮件 + +def sendMail(title, content, mailto_list): + msg = MIMEText(content, 'plain', 'utf-8') + #发送邮箱地址 + sender = 'canarycodebook@163.com' + #邮箱授权码,非登陆密码 + password = 'eTn49CftDfaytar' + #收件箱地址 + #receiver = '19xxxxxxx9@qq.com' + # mailto_list = ['1144131090@qq.com','nayiyewosile@qq.com'] #群发邮箱地址 + + #smtp服务器 + smtp_server = 'smtp.163.com' + #发送邮箱地址 + msg['From'] = sender + #收件箱地址 + #msg['To'] = receiver + msg['To'] =';'.join(mailto_list) #发送多人邮件写法 + #主题 + msg['Subject'] = title + + server = smtplib.SMTP(smtp_server,25) # SMTP协议默认端口是25 + server.login(sender,password) #ogin()方法用来登录SMTP服务器 + server.set_debuglevel(1) #打印出和SMTP服务器交互的所有信息。 + server.sendmail(sender,mailto_list,msg.as_string()) #msg.as_string()把MIMEText对象变成str server.quit() + + # 第一个参数为发送者,第二个参数为接收者,可以添加多个例如:['hello@163.com','xxx@qq.com',]# 第三个参数为发送的内容 + server.quit() + +sendMail('欢迎注册Canary Codebook', 'test', ['1144131090@qq.com']) \ No newline at end of file