xn-auth 0.2.39__py3-none-any.whl → 0.2.41__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
x_auth/controller.py CHANGED
@@ -1,6 +1,8 @@
1
+ from base64 import b64encode
1
2
  from datetime import timedelta
2
3
 
3
- from aiogram.utils.web_app import WebAppInitData, safe_parse_webapp_init_data
4
+ from aiogram.utils.auth_widget import check_signature
5
+ from aiogram.utils.web_app import WebAppInitData, safe_parse_webapp_init_data, WebAppUser
4
6
  from litestar import Response, post
5
7
  from litestar.connection import ASGIConnection
6
8
  from litestar.exceptions import NotAuthorizedException
@@ -8,7 +10,7 @@ from litestar.security.jwt import JWTCookieAuth
8
10
 
9
11
  from x_auth.middleware import JWTAuthMiddleware, Tok
10
12
  from x_auth.models import User
11
- from x_auth.types import AuthUser
13
+ from x_auth.types import AuthUser, TgUser, XyncUser
12
14
 
13
15
 
14
16
  async def retrieve_user_handler(token: Tok, _cn: ASGIConnection) -> AuthUser:
@@ -33,20 +35,32 @@ class Auth:
33
35
  exclude=["/schema", "/auth", "/public"] + (exc_paths or []),
34
36
  )
35
37
 
36
- @post("/auth/tma", tags=["Auth"], description="Gen JWToken from tg initData")
37
- async def tma(tid: str) -> Response[user_model.in_type(True)]:
38
- try:
39
- twaid: WebAppInitData = safe_parse_webapp_init_data(self.jwt.token_secret, tid)
40
- except ValueError:
41
- raise NotAuthorizedException(detail="Tg Initdata invalid")
42
- user_in = await user_model.tg2in(twaid.user)
38
+ async def user_proc(user: WebAppUser) -> Response[XyncUser]:
39
+ user_in = await user_model.tg2in(user)
43
40
  db_user, cr = await user_model.update_or_create(**user_in.df_unq()) # on login: update user in db from tg
44
41
  res = self.jwt.login(
45
42
  identifier=str(db_user.id),
46
43
  token_extras={"role": db_user.role, "blocked": db_user.blocked},
47
- response_body=user_model.validate(dict(db_user)),
44
+ response_body=XyncUser.model_validate({**user.model_dump(), "pub": b64encode(db_user.pub)}),
48
45
  )
49
46
  res.cookies[0].httponly = False
50
47
  return res
51
48
 
52
- self.handler = tma
49
+ # login for api endpoint
50
+ @post("/auth/twa", tags=["Auth"], description="Gen JWToken from tg login widget")
51
+ async def twa(data: TgUser) -> Response[XyncUser]: # widget
52
+ dct = data.dump()
53
+ if not check_signature(self.jwt.token_secret, dct.pop("hash"), **dct):
54
+ raise NotAuthorizedException("Tg login widget data invalid")
55
+ return await user_proc(WebAppUser(**dct))
56
+
57
+ @post("/auth/tma", tags=["Auth"], description="Gen JWToken from tg initData")
58
+ async def tma(tid: str) -> Response[XyncUser]:
59
+ try:
60
+ twaid: WebAppInitData = safe_parse_webapp_init_data(self.jwt.token_secret, tid)
61
+ except ValueError as e:
62
+ raise NotAuthorizedException(detail=f"Tg Initdata invalid {e}")
63
+ return await user_proc(twaid.user)
64
+
65
+ self.tma_handler = tma
66
+ self.twa_handler = twa
x_auth/models.py CHANGED
@@ -35,6 +35,10 @@ from x_model.types import BaseUpd
35
35
  from x_auth.enums import Lang, Role, PeerType
36
36
 
37
37
 
38
+ class UniqBinaryField(BinaryField):
39
+ indexable = True
40
+
41
+
38
42
  class Username(TortModel):
39
43
  id: int = BigIntField(True, description="tg_id")
40
44
  username: str = CharField(127, null=True)
@@ -49,10 +53,13 @@ class User(Model):
49
53
  username: OneToOneRelation[Username] = OneToOneField("models.Username", "user")
50
54
  username_id: int
51
55
  first_name: str | None = CharField(63)
56
+ pic: str | None = CharField(127, null=True)
52
57
  last_name: str | None = CharField(31, null=True)
53
58
  blocked: bool = BooleanField(default=False)
54
59
  lang: Lang | None = IntEnumField(Lang, default=Lang.ru, null=True)
55
60
  role: Role = IntEnumField(Role, default=Role.READER)
61
+ # prv = BinaryField(null=True) # len=32
62
+ pub = UniqBinaryField(unique=True, null=True) # len=32
56
63
 
57
64
  app: BackwardOneToOneRelation["App"]
58
65
 
@@ -65,6 +72,7 @@ class User(Model):
65
72
  "last_name": u.last_name,
66
73
  "username_id": un.id,
67
74
  "lang": u.language_code and Lang[u.language_code],
75
+ "pic": u.photo_url and u.photo_url.replace("https://t.me/i/userpic/320/", "")[:-4],
68
76
  }
69
77
  )
70
78
  if blocked is not None:
x_auth/types.py CHANGED
@@ -1,11 +1,26 @@
1
1
  from datetime import datetime
2
- from typing import Literal
2
+ from json import dumps
3
+ from typing import Literal, Self
3
4
 
4
- from msgspec import Struct
5
+ from aiogram.utils.web_app import WebAppUser
6
+ from msgspec import Struct, to_builtins, convert
5
7
 
6
8
  from x_auth.enums import Role
7
9
 
8
10
 
11
+ class Xs(Struct):
12
+ def dump(self, nones: bool = False) -> dict:
13
+ return {k: v for k, v in to_builtins(self).items() if nones or v is not None}
14
+
15
+ def json(self, nones: bool = False) -> str:
16
+ return dumps(self.dump())
17
+
18
+ @classmethod
19
+ def load(cls, obj, **kwargs) -> Self:
20
+ dct = dict(obj)
21
+ return convert({**dct, **kwargs}, cls) # , strict=False
22
+
23
+
9
24
  class AuthUser(Struct):
10
25
  id: int
11
26
  blocked: bool
@@ -35,3 +50,17 @@ class Replacement(Struct):
35
50
  proxy_port: int
36
51
  proxy_country_code: str
37
52
  created_at: datetime
53
+
54
+
55
+ class TgUser(Xs):
56
+ id: int
57
+ first_name: str
58
+ auth_date: int
59
+ hash: str
60
+ username: str | None = None
61
+ photo_url: str | None = None
62
+ last_name: str | None = None
63
+
64
+
65
+ class XyncUser(WebAppUser):
66
+ pub: bytes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xn-auth
3
- Version: 0.2.39
3
+ Version: 0.2.41
4
4
  Summary: Auth adapter for XN-Api framework
5
5
  Author-email: Artemiev <mixartemev@gmail.com>
6
6
  License: MIT
@@ -0,0 +1,10 @@
1
+ x_auth/controller.py,sha256=KGbXT-hX7Rp6eYZJGx_-ioAr3As73bbKjPhow41c1SE,2973
2
+ x_auth/enums.py,sha256=l4NTYsA-h0gyOp4PUe40Lb8LKoA94zL6EDkCmoGmBL0,732
3
+ x_auth/exceptions.py,sha256=2B4okJxhPyNqTJXlSTfblJUQJ60bLGXdgJIu6ue7S6w,162
4
+ x_auth/middleware.py,sha256=JfssQomDv0J_69GfS2a_2_uyRzs26zSY6IW1Vk7m8K0,2900
5
+ x_auth/models.py,sha256=kDk0je7f2TcfRrnCeTbB99ERBJmDaxGGjvIm53BIaYM,8996
6
+ x_auth/types.py,sha256=GTjNOm7XkyYDCdIaqByP2LzHnwCJRkWGOwdc4tVWFy0,1400
7
+ xn_auth-0.2.41.dist-info/METADATA,sha256=lPj2C37gFR3GN2b1xvIMxBzWbyU6KtTurQfNc3QBcTU,823
8
+ xn_auth-0.2.41.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
9
+ xn_auth-0.2.41.dist-info/top_level.txt,sha256=ydMDkzxgQPtW-E_MNDfUAroAFZvWSqU-x_kZSA7NSFo,7
10
+ xn_auth-0.2.41.dist-info/RECORD,,
@@ -1,10 +0,0 @@
1
- x_auth/controller.py,sha256=0QhqmqXOqFaWIUTWHlJKITQNmJQ5kXZOkLg7wSUTh60,2240
2
- x_auth/enums.py,sha256=l4NTYsA-h0gyOp4PUe40Lb8LKoA94zL6EDkCmoGmBL0,732
3
- x_auth/exceptions.py,sha256=2B4okJxhPyNqTJXlSTfblJUQJ60bLGXdgJIu6ue7S6w,162
4
- x_auth/middleware.py,sha256=JfssQomDv0J_69GfS2a_2_uyRzs26zSY6IW1Vk7m8K0,2900
5
- x_auth/models.py,sha256=Srhu7he0cxEdQ7smQbqlHBE0ChCqAMcj4E_y-WPZlRI,8684
6
- x_auth/types.py,sha256=j3WGcyH24DmFEdTT6U7xzb_fEm1tFcBZsANKMy7bydo,689
7
- xn_auth-0.2.39.dist-info/METADATA,sha256=MPxvb7MeAhnRbKke04ahT5ZlSZKnkvvGToy7qyAVaQM,823
8
- xn_auth-0.2.39.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
9
- xn_auth-0.2.39.dist-info/top_level.txt,sha256=ydMDkzxgQPtW-E_MNDfUAroAFZvWSqU-x_kZSA7NSFo,7
10
- xn_auth-0.2.39.dist-info/RECORD,,