31
31
PaymentHistoryPoint ,
32
32
TinyURL ,
33
33
UpdateUserPassword ,
34
+ UpdateUserPubkey ,
34
35
User ,
35
36
UserConfig ,
36
37
Wallet ,
41
42
async def create_account (
42
43
user_id : Optional [str ] = None ,
43
44
username : Optional [str ] = None ,
45
+ pubkey : Optional [str ] = None ,
44
46
email : Optional [str ] = None ,
45
47
password : Optional [str ] = None ,
46
48
user_config : Optional [UserConfig ] = None ,
@@ -52,14 +54,17 @@ async def create_account(
52
54
now_ph = db .timestamp_placeholder ("now" )
53
55
await (conn or db ).execute (
54
56
f"""
55
- INSERT INTO accounts (id, username, pass, email, extra, created_at, updated_at)
56
- VALUES (:user, :username, :password, :email, :extra, { now_ph } , { now_ph } )
57
+ INSERT INTO accounts
58
+ (id, username, pass, email, pubkey, extra, created_at, updated_at)
59
+ VALUES
60
+ (:user, :username, :password, :email, :pubkey, :extra, { now_ph } , { now_ph } )
57
61
""" ,
58
62
{
59
63
"user" : user_id ,
60
64
"username" : username ,
61
65
"password" : password ,
62
66
"email" : email ,
67
+ "pubkey" : pubkey ,
63
68
"extra" : extra ,
64
69
"now" : now ,
65
70
},
@@ -88,7 +93,7 @@ async def update_account(
88
93
if username :
89
94
assert not user .username or username == user .username , "Cannot change username."
90
95
account = await get_account_by_username (username )
91
- assert not account or account .id == user_id , "Username already in exists."
96
+ assert not account or account .id == user_id , "Username already exists."
92
97
93
98
username = user .username or username
94
99
email = user .email or email
@@ -161,7 +166,7 @@ async def get_account(
161
166
) -> Optional [User ]:
162
167
row = await (conn or db ).fetchone (
163
168
"""
164
- SELECT id, email, username, created_at, updated_at, extra
169
+ SELECT id, email, username, pubkey, created_at, updated_at, extra
165
170
FROM accounts WHERE id = :id
166
171
""" ,
167
172
{"id" : user_id },
@@ -210,28 +215,56 @@ async def verify_user_password(user_id: str, password: str) -> bool:
210
215
return pwd_context .verify (password , existing_password )
211
216
212
217
213
- # TODO: , conn: Optional[Connection] = None ??, maybe also not a crud function
214
- async def update_user_password (data : UpdateUserPassword ) -> Optional [User ]:
215
- assert data .password == data .password_repeat , "Passwords do not match."
218
+ async def update_user_password (data : UpdateUserPassword , last_login_time : int ) -> User :
216
219
217
- # old accounts do not have a pasword
218
- if await get_user_password (data .user_id ):
219
- assert data .password_old , "Missing old password"
220
- old_pwd_ok = await verify_user_password (data .user_id , data .password_old )
221
- assert old_pwd_ok , "Invalid credentials."
220
+ assert 0 <= time () - last_login_time <= settings .auth_credetials_update_threshold , (
221
+ "You can only update your credentials in the first"
222
+ f" { settings .auth_credetials_update_threshold } seconds after login."
223
+ " Please login again!"
224
+ )
225
+ assert data .password == data .password_repeat , "Passwords do not match."
222
226
223
227
pwd_context = CryptContext (schemes = ["bcrypt" ], deprecated = "auto" )
224
228
225
- now = int (time ())
226
- now_ph = db .timestamp_placeholder ("now" )
227
229
await db .execute (
228
230
f"""
229
- UPDATE accounts SET pass = :pass, updated_at = { now_ph }
231
+ UPDATE accounts
232
+ SET pass = :pass, updated_at = { db .timestamp_placeholder ("now" )}
230
233
WHERE id = :user
231
234
""" ,
232
235
{
233
236
"pass" : pwd_context .hash (data .password ),
234
- "now" : now ,
237
+ "now" : int (time ()),
238
+ "user" : data .user_id ,
239
+ },
240
+ )
241
+
242
+ user = await get_user (data .user_id )
243
+ assert user , "Updated account couldn't be retrieved"
244
+ return user
245
+
246
+
247
+ async def update_user_pubkey (data : UpdateUserPubkey , last_login_time : int ) -> User :
248
+
249
+ assert 0 <= time () - last_login_time <= settings .auth_credetials_update_threshold , (
250
+ "You can only update your credentials in the first"
251
+ f" { settings .auth_credetials_update_threshold } seconds after login."
252
+ " Please login again!"
253
+ )
254
+
255
+ user = await get_account_by_pubkey (data .pubkey )
256
+ if user :
257
+ assert user .id == data .user_id , "Public key already in use."
258
+
259
+ await db .execute (
260
+ f"""
261
+ UPDATE accounts
262
+ SET pubkey = :pubkey, updated_at = { db .timestamp_placeholder ("now" )}
263
+ WHERE id = :user
264
+ """ ,
265
+ {
266
+ "pubkey" : data .pubkey ,
267
+ "now" : int (time ()),
235
268
"user" : data .user_id ,
236
269
},
237
270
)
@@ -246,7 +279,7 @@ async def get_account_by_username(
246
279
) -> Optional [User ]:
247
280
row = await (conn or db ).fetchone (
248
281
"""
249
- SELECT id, username, email, created_at, updated_at
282
+ SELECT id, username, pubkey, email, created_at, updated_at
250
283
FROM accounts WHERE username = :username
251
284
""" ,
252
285
{"username" : username },
@@ -255,12 +288,26 @@ async def get_account_by_username(
255
288
return User (** row ) if row else None
256
289
257
290
291
+ async def get_account_by_pubkey (
292
+ pubkey : str , conn : Optional [Connection ] = None
293
+ ) -> Optional [User ]:
294
+ row = await (conn or db ).fetchone (
295
+ """
296
+ SELECT id, username, pubkey, email, created_at, updated_at
297
+ FROM accounts WHERE pubkey = :pubkey
298
+ """ ,
299
+ {"pubkey" : pubkey },
300
+ )
301
+
302
+ return User (** row ) if row else None
303
+
304
+
258
305
async def get_account_by_email (
259
306
email : str , conn : Optional [Connection ] = None
260
307
) -> Optional [User ]:
261
308
row = await (conn or db ).fetchone (
262
309
"""
263
- SELECT id, username, email, created_at, updated_at
310
+ SELECT id, username, pubkey, email, created_at, updated_at
264
311
FROM accounts WHERE email = :email
265
312
""" ,
266
313
{"email" : email },
@@ -281,7 +328,7 @@ async def get_account_by_username_or_email(
281
328
async def get_user (user_id : str , conn : Optional [Connection ] = None ) -> Optional [User ]:
282
329
user = await (conn or db ).fetchone (
283
330
"""
284
- SELECT id, email, username, pass, extra, created_at, updated_at
331
+ SELECT id, email, username, pubkey, pass, extra, created_at, updated_at
285
332
FROM accounts WHERE id = :id
286
333
""" ,
287
334
{"id" : user_id },
@@ -306,6 +353,7 @@ async def get_user(user_id: str, conn: Optional[Connection] = None) -> Optional[
306
353
id = user ["id" ],
307
354
email = user ["email" ],
308
355
username = user ["username" ],
356
+ pubkey = user ["pubkey" ],
309
357
extensions = [
310
358
e for e in extensions if User .is_extension_for_user (e [0 ], user ["id" ])
311
359
],
0 commit comments