From 9e430390b10dbd1e64276d8ce61214a002513f5c Mon Sep 17 00:00:00 2001 From: berniehuang2008 Date: Wed, 14 Feb 2024 14:59:54 +0800 Subject: [PATCH 1/4] [service] Verify --- services/verify/db.py | 24 +++++++++ services/verify/main.py | 106 ++++++++++++++++++++++++++++++++++++++ services/verify/utils.py | 6 +++ services/verify/verify.py | 65 +++++++++++++++++++++++ 4 files changed, 201 insertions(+) create mode 100644 services/verify/db.py create mode 100644 services/verify/main.py create mode 100644 services/verify/utils.py create mode 100644 services/verify/verify.py diff --git a/services/verify/db.py b/services/verify/db.py new file mode 100644 index 0000000..ddc743a --- /dev/null +++ b/services/verify/db.py @@ -0,0 +1,24 @@ +from pony.orm import Database, Required, PrimaryKey + +""" Create Database """ +db = Database() + + +class OutsideVerifyCode(db.Entity): + code = PrimaryKey(str) + session = Required(str) + expired = Required(int) + callbackURI = Required(str) + + +class InsideVerifyCode(db.Entity): + code = PrimaryKey(str) + session = Required(str) + expired = Required(int) + + +db.bind(provider="sqlite", filename="verify.db") + +db.generate_mapping(create_tables=True) + +from pony.orm import db_session diff --git a/services/verify/main.py b/services/verify/main.py new file mode 100644 index 0000000..5e0e606 --- /dev/null +++ b/services/verify/main.py @@ -0,0 +1,106 @@ +""" +[service] Verify Service + +* this: 本服务 +* s1: 调用本服务的服务 +* client: 用户的客户端 + +1. [s1] 请求内网api "/newVerify" 来进行一个新的验证 (需提供一个回调地址、一个 session ID) +2. [client] 通过路由请求内部api "/verifyOutsideCode" 进行验证 +3. [this] 将 [client] 重定向到 " ?s= &v= " (`SUCCESS` 为 `0/1`, 代表验证失败/成功, `INSIDE-CODE` 为内部验证码) +4. [s1] 请求内网api "/verifyInsideCode" 验证 `INSIDE-CODE` +5. [s1] 根据返回字段 `ok` 判断验证是否成功, `sess` 来恢复会话 + +""" +import flask +from flask import request + +import verify + +app = flask.Flask(__name__) + + +@app.route("/newVerify", methods=["GET"]) +def newVerify(): + """ + [内部] 进行一个新的验证 + + [Request] + method: str = [email] + session: str + callbackURI: str (建议使用绝对路径) + + [Response] + { + code: int + } + """ + method = request.args.get("method") + session = request.args.get("session") + callbackURI = request.args.get("callbackURI") + + code = verify.genOutsideCode(session, callbackURI) + + if method == "email": + # [TODO]: Send Email + print("Send Email:", code) + pass + + return {"code": 0} + + +@app.route("/verifyOutsideCode", methods=["GET"]) +def verifyOutsideCode(): + """ + [外部] 验证外部验证码 + + [Request] + code: str + + [Response] + Redirect + """ + code = request.args.get("code") + + result = verify.verifyOutsideCode(code) + if result: + sess = result["session"] + callbackURI = result["callbackURI"] + + insideCode = verify.genInsideCode(sess) + redirectURI = f"{callbackURI}?s=1&v={insideCode}" + else: + redirectURI = "ERROR: Invalid Verification Link" + + print("Redirect to", redirectURI) + + return redirectURI + + +@app.route("/verifyInsideCode", methods=["GET"]) +def verifyInsideCode(): + """ + [内部] 验证内部验证码 + + [Request] + code: str + + [Response] + { + code: int, + ok: bool, + sess: str + } + """ + code = request.args.get("code") + + result = verify.verifyInsideCode(code) + if result: + return {"code": 0, "ok": True, "sess": result["session"]} + else: + return {"code": -1} + + + +if __name__ == "__main__": + app.run("localhost", 5003) diff --git a/services/verify/utils.py b/services/verify/utils.py new file mode 100644 index 0000000..e75e6e0 --- /dev/null +++ b/services/verify/utils.py @@ -0,0 +1,6 @@ +import random +from hashlib import sha256 + + +def genRandHash(): + return sha256(str(random.getrandbits(256)).encode()).hexdigest() diff --git a/services/verify/verify.py b/services/verify/verify.py new file mode 100644 index 0000000..a15f473 --- /dev/null +++ b/services/verify/verify.py @@ -0,0 +1,65 @@ +import time +import db +import utils + + +def genOutsideCode(session, callbackURI): + """Generate a new outside code""" + with db.db_session: + code = utils.genRandHash() + expired = int(time.time()) + 60 * 10 # 10 minutes + + db.OutsideVerifyCode( + code=code, session=session, expired=expired, callbackURI=callbackURI + ) + + return code + + +def genInsideCode(session): + """Generate a new inside code""" + with db.db_session: + code = utils.genRandHash() + expired = int(time.time()) + 60 * 1 # 1 minutes + + db.InsideVerifyCode(code=code, session=session, expired=expired) + + return code + + +def verifyOutsideCode(code): + """Verify the outside code""" + with db.db_session: + result = db.OutsideVerifyCode.get(code=code) + + # [Check]: If code is valid + if result is None: + return None + + result = result.to_dict() + db.OutsideVerifyCode[code].delete() + + # [Check]: If code is expired + if result["expired"] < time.time(): + return None + + return result + + +def verifyInsideCode(code): + """Verify the inside code""" + with db.db_session: + result = db.InsideVerifyCode.get(code=code) + + # [Check]: If code is valid + if result is None: + return None + + result = result.to_dict() + db.InsideVerifyCode[code].delete() + + # [Check]: If code is expired + if result["expired"] < time.time(): + return None + + return result From fd69ae3c0d7e966d8d76e9dc4a2ecc59fb9f08d2 Mon Sep 17 00:00:00 2001 From: berniehuang2008 Date: Wed, 14 Feb 2024 19:19:26 +0800 Subject: [PATCH 2/4] [feat] send email logic --- services/verify/main.py | 19 +++-- services/verify/send.py | 161 ++++++++++++++++++++++++++++++++++++++ services/verify/verify.py | 1 + 3 files changed, 173 insertions(+), 8 deletions(-) create mode 100644 services/verify/send.py diff --git a/services/verify/main.py b/services/verify/main.py index 5e0e606..5c056e4 100644 --- a/services/verify/main.py +++ b/services/verify/main.py @@ -16,6 +16,7 @@ from flask import request import verify +import send app = flask.Flask(__name__) @@ -26,9 +27,10 @@ def newVerify(): [内部] 进行一个新的验证 [Request] - method: str = [email] + method: str (one of [email]) + target: str (e.g. "test@openteens.org") session: str - callbackURI: str (建议使用绝对路径) + callbackURI: str (建议使用带https的绝对路径) [Response] { @@ -36,16 +38,17 @@ def newVerify(): } """ method = request.args.get("method") + target = request.args.get("target") session = request.args.get("session") callbackURI = request.args.get("callbackURI") code = verify.genOutsideCode(session, callbackURI) if method == "email": - # [TODO]: Send Email - print("Send Email:", code) - pass - + send.sendEmail(target, code) + else: + return {"code": -1} + return {"code": 0} @@ -55,7 +58,7 @@ def verifyOutsideCode(): [外部] 验证外部验证码 [Request] - code: str + code: str (外部验证码) [Response] Redirect @@ -83,7 +86,7 @@ def verifyInsideCode(): [内部] 验证内部验证码 [Request] - code: str + code: str (内部验证码) [Response] { diff --git a/services/verify/send.py b/services/verify/send.py new file mode 100644 index 0000000..bcdba7c --- /dev/null +++ b/services/verify/send.py @@ -0,0 +1,161 @@ +def sendEmail(target, code): + """ + 发送验证邮件 + """ + + template = """ + + + + + 邮箱验证码 + + + + + + + + + +
+
+ + +
+
+
+
+ 尊敬的用户:您好! + + 您正在进行邮箱验证,请点击以下链接完成验证: + + 若不是您在操作,请忽略此邮件。 +
+ + 如果您无法点击以上链接,请将此链接复制到浏览器地址栏中访问。 + https://api.openteens.org/userVerify?code={} + +
+
+
+
+
+

此为系统邮件,请勿回复
+

+

—— OpenTeens 社区

+
+
+
+ + """ + + title = "OpenTeens 邮箱验证" + from_ = "OpenTeens " + to = target + content = template.format(code, code, code) + + diff --git a/services/verify/verify.py b/services/verify/verify.py index a15f473..b8947a5 100644 --- a/services/verify/verify.py +++ b/services/verify/verify.py @@ -1,4 +1,5 @@ import time + import db import utils From 8c9b43ebd6c0e0e43d2667ce6cb99e1f4607d51b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=81=E9=9D=99=E8=87=B4=E8=BF=9C?= <468835121@qq.com> Date: Sun, 18 Feb 2024 15:22:04 +0800 Subject: [PATCH 3/4] =?UTF-8?q?[fix]=20=E4=BF=AE=E5=A4=8D=E9=87=8D?= =?UTF-8?q?=E5=AE=9A=E5=90=91=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- services/verify/router.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/services/verify/router.py b/services/verify/router.py index eb229a0..0bf8f1b 100644 --- a/services/verify/router.py +++ b/services/verify/router.py @@ -15,6 +15,7 @@ import fastapi from fastapi import Request, Response +from starlette.responses import RedirectResponse import verify import send @@ -23,8 +24,6 @@ inter_router = None public_router = None -def redirect(url): - print("You redirected to:",url) def init(ri: fastapi.APIRouter, rp: fastapi.APIRouter): global inter_router @@ -127,7 +126,7 @@ def verifyOutsideCode(): else: redirectURI = "ERROR: Invalid Verification Link" - return redirect(redirectURI) + return RedirectResponse(redirectURI) def verifyInsideCode(): From ff0f54b6ea53e9ba48bacdd9ce43f2808242e778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=81=E9=9D=99=E8=87=B4=E8=BF=9C?= <468835121@qq.com> Date: Sun, 18 Feb 2024 15:32:30 +0800 Subject: [PATCH 4/4] =?UTF-8?q?[fix]=20=E4=BF=AE=E5=A4=8D=E9=87=8D?= =?UTF-8?q?=E5=AE=9A=E5=90=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- services/verify/router.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/verify/router.py b/services/verify/router.py index 0bf8f1b..0a871ea 100644 --- a/services/verify/router.py +++ b/services/verify/router.py @@ -157,4 +157,4 @@ def verifyInsideCode(): if __name__ == "__main__": init(fastapi.APIRouter()) - router.run("localhost", 5003) + # router.run("localhost", 5003)