fix(security): harden uploads and wecom binding
This commit is contained in:
+13
-18
@@ -9,8 +9,9 @@ from fastapi.responses import PlainTextResponse
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.exc import IntegrityError
|
||||
from app.config import settings
|
||||
from app.database import get_db
|
||||
from app.database import async_session, get_db
|
||||
from app.middleware.auth import get_current_user, require_director
|
||||
from app.models.user import User
|
||||
from app.services.wecom import wecom_client, store_bind_token, consume_bind_token
|
||||
@@ -116,21 +117,20 @@ async def wecom_callback_event(request: Request):
|
||||
# Triggers for binding
|
||||
if (msg_type == "text" and content == "绑定") or (msg_type == "event" and event == "click" and event_key == "BIND_ACCOUNT"):
|
||||
_log.info("wecom bind triggered")
|
||||
_handle_bind_request(from_user)
|
||||
await _handle_bind_request(from_user)
|
||||
return PlainTextResponse(content="success")
|
||||
|
||||
_log.info("wecom message ignored (no matching action)")
|
||||
return PlainTextResponse(content="success")
|
||||
|
||||
|
||||
def _handle_bind_request(wecom_userid: str):
|
||||
async def _handle_bind_request(wecom_userid: str):
|
||||
"""Generate bind token, store it, and push a bind link to the user."""
|
||||
if not wecom_userid:
|
||||
return
|
||||
|
||||
import asyncio
|
||||
|
||||
bind_token = store_bind_token(wecom_userid)
|
||||
async with async_session() as db:
|
||||
bind_token = await store_bind_token(db, wecom_userid)
|
||||
|
||||
content = (
|
||||
f"【账号绑定】\n\n"
|
||||
@@ -139,16 +139,7 @@ def _handle_bind_request(wecom_userid: str):
|
||||
f"绑定后可使用企微一键登录,并接收填报提醒通知。"
|
||||
)
|
||||
|
||||
try:
|
||||
# Must run async in sync context
|
||||
loop = asyncio.get_event_loop()
|
||||
except RuntimeError:
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
|
||||
loop.run_until_complete(
|
||||
wecom_client.send_text_message([wecom_userid], content)
|
||||
)
|
||||
await wecom_client.send_text_message([wecom_userid], content)
|
||||
|
||||
|
||||
# ── Bind confirmation (JWT-protected) ──
|
||||
@@ -163,7 +154,7 @@ async def bind_confirm(
|
||||
if not data.token:
|
||||
raise HTTPException(status_code=400, detail="token 不能为空")
|
||||
|
||||
wecom_userid = consume_bind_token(data.token)
|
||||
wecom_userid = await consume_bind_token(db, data.token)
|
||||
if not wecom_userid:
|
||||
raise HTTPException(status_code=400, detail="绑定链接已过期或无效,请重新在企微发送「绑定」")
|
||||
|
||||
@@ -181,7 +172,11 @@ async def bind_confirm(
|
||||
)
|
||||
user = result.scalar_one()
|
||||
user.wecom_userid = wecom_userid
|
||||
await db.commit()
|
||||
try:
|
||||
await db.commit()
|
||||
except IntegrityError as exc:
|
||||
await db.rollback()
|
||||
raise HTTPException(status_code=409, detail="该企业微信已绑定其他账号") from exc
|
||||
|
||||
return {"code": 200, "msg": "绑定成功", "wecom_userid": wecom_userid}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user