xn-auth 0.2.39__tar.gz → 0.2.41__tar.gz

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.
@@ -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
@@ -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
@@ -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:
@@ -0,0 +1,66 @@
1
+ from datetime import datetime
2
+ from json import dumps
3
+ from typing import Literal, Self
4
+
5
+ from aiogram.utils.web_app import WebAppUser
6
+ from msgspec import Struct, to_builtins, convert
7
+
8
+ from x_auth.enums import Role
9
+
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
+
24
+ class AuthUser(Struct):
25
+ id: int
26
+ blocked: bool
27
+ role: Role
28
+
29
+
30
+ class Proxy(Struct):
31
+ id: str
32
+ username: str
33
+ password: str
34
+ proxy_address: str
35
+ port: int
36
+ valid: bool
37
+ last_verification: datetime
38
+ country_code: str
39
+ city_name: str
40
+ created_at: datetime
41
+
42
+
43
+ class Replacement(Struct):
44
+ id: int
45
+ reason: Literal["auto_invalidated", "auto_out_of_rotation"]
46
+ replaced_with: str
47
+ replaced_with_port: int
48
+ replaced_with_country_code: str
49
+ proxy: str
50
+ proxy_port: int
51
+ proxy_country_code: str
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
@@ -1,37 +0,0 @@
1
- from datetime import datetime
2
- from typing import Literal
3
-
4
- from msgspec import Struct
5
-
6
- from x_auth.enums import Role
7
-
8
-
9
- class AuthUser(Struct):
10
- id: int
11
- blocked: bool
12
- role: Role
13
-
14
-
15
- class Proxy(Struct):
16
- id: str
17
- username: str
18
- password: str
19
- proxy_address: str
20
- port: int
21
- valid: bool
22
- last_verification: datetime
23
- country_code: str
24
- city_name: str
25
- created_at: datetime
26
-
27
-
28
- class Replacement(Struct):
29
- id: int
30
- reason: Literal["auto_invalidated", "auto_out_of_rotation"]
31
- replaced_with: str
32
- replaced_with_port: int
33
- replaced_with_country_code: str
34
- proxy: str
35
- proxy_port: int
36
- proxy_country_code: str
37
- created_at: datetime
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes