Skip to content

Commit

Permalink
feature(app):
Browse files Browse the repository at this point in the history
- localstorage changes to cookie
- add autologin, logout request
- manager page
  • Loading branch information
MorvanZhou committed May 15, 2024
1 parent 7a283e9 commit 682723b
Show file tree
Hide file tree
Showing 12 changed files with 247 additions and 235 deletions.
4 changes: 2 additions & 2 deletions src/retk/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ def __init__(self):
)

self.REFRESH_TOKEN_EXPIRE_DELTA = datetime.timedelta(days=self.JWT_REFRESH_EXPIRED_DAYS)
self.ACCESS_TOKEN_EXPIRE_DELTA = datetime.timedelta(minutes=self.JWT_ACCESS_EXPIRED_MINS)

# self.ACCESS_TOKEN_EXPIRE_DELTA = datetime.timedelta(minutes=self.JWT_ACCESS_EXPIRED_MINS)
self.ACCESS_TOKEN_EXPIRE_DELTA = datetime.timedelta(seconds=5)

@lru_cache()
def get_settings() -> Settings:
Expand Down
12 changes: 8 additions & 4 deletions src/retk/const/response_codes.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class CodeEnum(IntEnum):
ACCOUNT_EXIST_TRY_FORGET_PASSWORD = 30
USER_DISABLED = 31
NOT_PERMITTED = 32
EXPIRED_ACCESS_TOKEN = 33
EXPIRED_OR_NO_ACCESS_TOKEN = 33
USER_NOT_EXIST = 34
INVALID_PARAMS = 35

Expand Down Expand Up @@ -89,9 +89,13 @@ class CodeMessage:
zh="账户已存在,请尝试通过忘记密码找回",
en="Account exists, try forget password to recover",
),
CodeEnum.USER_DISABLED: CodeMessage(zh="用户已被禁用", en="User has been disabled"),
CodeEnum.USER_DISABLED: CodeMessage(
zh="因违反平台规则,此账户已被禁用",
en="This account has been disabled due to violation of platform rules"
),
CodeEnum.NOT_PERMITTED: CodeMessage(zh="无权限", en="Not permitted"),
CodeEnum.EXPIRED_ACCESS_TOKEN: CodeMessage(zh="访问令牌已过期", en="Access token has expired"),
CodeEnum.EXPIRED_OR_NO_ACCESS_TOKEN: CodeMessage(zh="访问令牌已过期或失效",
en="Access token has expired or invalid"),
CodeEnum.USER_NOT_EXIST: CodeMessage(zh="用户不存在", en="User does not exist"),
CodeEnum.INVALID_PARAMS: CodeMessage(zh="无效参数", en="Invalid parameter"),
}
Expand Down Expand Up @@ -130,7 +134,7 @@ class CodeMessage:
CodeEnum.ACCOUNT_EXIST_TRY_FORGET_PASSWORD: 422,
CodeEnum.USER_DISABLED: 403,
CodeEnum.NOT_PERMITTED: 403,
CodeEnum.EXPIRED_ACCESS_TOKEN: 200,
CodeEnum.EXPIRED_OR_NO_ACCESS_TOKEN: 200,
CodeEnum.USER_NOT_EXIST: 404,
CodeEnum.INVALID_PARAMS: 400,
}
Expand Down
10 changes: 8 additions & 2 deletions src/retk/controllers/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,19 @@ async def login(
) -> JSONResponse:
# TODO: 后台应记录成功登录用户名和 IP、时间.
# 当尝试登录 IP 不在历史常登录 IP 地理位置时,应进行多因素二次验证用户身份,防止用户因密码泄漏被窃取账户
u, code = await user.get_by_email(req.email, disabled=False, exclude_manager=False)
u, code = await user.get_by_email(req.email, disabled=None, exclude_manager=False)
if code != const.CodeEnum.OK:
raise json_exception(
request_id=req_id,
code=code,
language=req.language,
)
if u["disabled"]:
raise json_exception(
request_id=req_id,
code=const.CodeEnum.USER_DISABLED,
language=req.language,
)

if not await account.manager.is_right_password(
email=u["email"],
Expand Down Expand Up @@ -146,7 +152,7 @@ async def auto_login(
payload = jwt_decode(token=token)
except Exception: # pylint: disable=broad-except
return r
u, code = await user.get(uid=payload["uid"])
u, code = await user.get(uid=payload["uid"], disabled=False)
if code != const.CodeEnum.OK:
return r
return schemas.user.get_user_info_response_from_u_dict(u, request_id=req_id)
Expand Down
4 changes: 2 additions & 2 deletions src/retk/controllers/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ async def get_user_info(
req: schemas.manager.GetUserRequest,
) -> schemas.user.UserInfoResponse:
if __check_use_uid(au=au, req=req):
u, code = await user.get(uid=req.uid, exclude_manager=True)
u, code = await user.get(uid=req.uid, disabled=None, exclude_manager=True)
else:
u, code = await user.get_by_email(email=req.email, exclude_manager=True)
u, code = await user.get_by_email(email=req.email, disabled=None, exclude_manager=True)
maybe_raise_json_exception(au=au, code=code)
return schemas.user.get_user_info_response_from_u_dict(u=u, request_id=au.request_id)

Expand Down
2 changes: 1 addition & 1 deletion src/retk/core/files/importing/async_tasks/obsidian/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ async def upload_obsidian_task( # noqa: C901
logger.debug(f"obsidian upload, uid={uid}, filter time: {t2 - t1:.2f}")

# add new md files with only title
u, code = await core.user.get(uid=uid)
u, code = await core.user.get(uid=uid, disabled=False)
au = AuthedUser(
u=convert_user_dict_to_authed_user(u),
request_id=request_id,
Expand Down
2 changes: 1 addition & 1 deletion src/retk/core/files/importing/async_tasks/text/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ async def update_text_task( # noqa: C901
)
return

u, code = await core.user.get(uid=uid)
u, code = await core.user.get(uid=uid, disabled=False)
au = AuthedUser(
u=convert_user_dict_to_authed_user(u),
request_id=request_id,
Expand Down
19 changes: 12 additions & 7 deletions src/retk/core/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ async def patch( # noqa: C901
if res.modified_count != 1:
return None, const.CodeEnum.OPERATION_FAILED

return await get(uid=au.u.id)
return await get(uid=au.u.id, disabled=None)


def __get_user_condition(condition: dict, exclude_manager: bool) -> dict:
Expand All @@ -145,7 +145,7 @@ def __get_user_condition(condition: dict, exclude_manager: bool) -> dict:

async def get_by_email(
email: str,
disabled: bool = False,
disabled: Optional[bool] = False,
exclude_manager: bool = False,
) -> Tuple[Optional[tps.UserMeta], const.CodeEnum]:
if config.get_settings().ONE_USER:
Expand All @@ -158,23 +158,28 @@ async def get_by_email(
async def get_account(
account: str,
source: int,
disabled: bool = False,
disabled: Optional[bool] = False,
exclude_manager: bool = False,
) -> Tuple[Optional[tps.UserMeta], const.CodeEnum]:
c = {"source": source, "account": account, "disabled": disabled}
c = {"source": source, "account": account}
if disabled is not None:
c["disabled"] = disabled
c = __get_user_condition(condition=c, exclude_manager=exclude_manager)
u = await client.coll.users.find_one(c)
if u is None:
return None, const.CodeEnum.ACCOUNT_OR_PASSWORD_ERROR
return u, const.CodeEnum.OK


async def get(uid: str, exclude_manager: bool = False) -> Tuple[Optional[tps.UserMeta], const.CodeEnum]:
c = {"id": uid, "disabled": False}
async def get(uid: str, disabled: Optional[bool] = False, exclude_manager: bool = False) -> Tuple[
Optional[tps.UserMeta], const.CodeEnum]:
c = {"id": uid}
if disabled is not None:
c["disabled"] = disabled
c = __get_user_condition(condition=c, exclude_manager=exclude_manager)
u = await client.coll.users.find_one(c)
if u is None:
return None, const.CodeEnum.USER_DISABLED
return None, const.CodeEnum.USER_NOT_EXIST
if u["usedSpace"] < 0:
# reset usedSpace to 0
await client.coll.users.update_one(
Expand Down
25 changes: 18 additions & 7 deletions src/retk/routes/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def verify_referer(referer: Optional[str] = Header(None)):


async def __process_auth_headers( # noqa: C901
is_refresh_token: bool,
refresh_token_id: str,
token: str = Header(alias="Authorization", default=""),
request_id: str = Header(
Expand All @@ -70,7 +71,7 @@ async def __process_auth_headers( # noqa: C901
if token is None or token == "":
raise json_exception(
request_id=request_id,
code=const.CodeEnum.INVALID_AUTH,
code=const.CodeEnum.INVALID_AUTH if is_refresh_token else const.CodeEnum.EXPIRED_OR_NO_ACCESS_TOKEN,
log_msg="empty token",
)
au = AuthedUser(
Expand All @@ -86,19 +87,19 @@ async def __process_auth_headers( # noqa: C901
if is_access is None:
code = const.CodeEnum.INVALID_AUTH
err = "invalid token"
elif (is_access and refresh_token_id != "") or (not is_access and refresh_token_id == ""):
elif is_access == is_refresh_token:
code = const.CodeEnum.INVALID_AUTH
err = "invalid token"
elif refresh_token_id != "" and payload["uid"] != refresh_token_id:
elif is_refresh_token and payload["uid"] != refresh_token_id:
code = const.CodeEnum.INVALID_AUTH
err = "invalid token"
else:
u, code = await core.user.get(uid=payload["uid"])
u, code = await core.user.get(uid=payload["uid"], disabled=False)
if code != const.CodeEnum.OK:
err = f"get user failed, code={code}"

except jwt.exceptions.ExpiredSignatureError:
code = const.CodeEnum.EXPIRED_AUTH if refresh_token_id != "" else const.CodeEnum.EXPIRED_ACCESS_TOKEN
code = const.CodeEnum.EXPIRED_AUTH if is_refresh_token else const.CodeEnum.EXPIRED_OR_NO_ACCESS_TOKEN
err = "auth expired"
except jwt.exceptions.DecodeError:
code = const.CodeEnum.INVALID_AUTH
Expand Down Expand Up @@ -126,7 +127,12 @@ async def process_normal_headers(
default="", alias="RequestId", max_length=const.settings.MD_MAX_LENGTH
)
) -> AuthedUser:
return await __process_auth_headers(refresh_token_id="", token=token, request_id=request_id)
return await __process_auth_headers(
is_refresh_token=False,
refresh_token_id="",
token=token,
request_id=request_id
)


async def process_refresh_token_headers(
Expand All @@ -136,7 +142,12 @@ async def process_refresh_token_headers(
default="", alias="RequestId", max_length=const.settings.MD_MAX_LENGTH
)
) -> AuthedUser:
return await __process_auth_headers(refresh_token_id=id_, token=token, request_id=request_id)
return await __process_auth_headers(
is_refresh_token=True,
refresh_token_id=id_,
token=token,
request_id=request_id
)


async def process_no_auth_headers(
Expand Down
5 changes: 1 addition & 4 deletions src/retk/safety.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@
cookie_domain = None
cookie_secure = False

if vue_app_mode == "dev":
cookie_samesite = "strict"
else:
cookie_samesite = "strict"
cookie_samesite = "strict"


class CSPMiddleware(BaseHTTPMiddleware):
Expand Down
Loading

0 comments on commit 682723b

Please sign in to comment.