@@ -9,6 +9,7 @@ use async_trait::async_trait;
9
9
use flareon_macros:: model;
10
10
use hmac:: { Hmac , KeyInit , Mac } ;
11
11
use sha2:: Sha512 ;
12
+ use thiserror:: Error ;
12
13
13
14
use crate :: admin:: { AdminModel , AdminModelManager , DefaultAdminModelManager } ;
14
15
use crate :: auth:: {
@@ -17,24 +18,33 @@ use crate::auth::{
17
18
} ;
18
19
use crate :: config:: SecretKey ;
19
20
use crate :: db:: migrations:: DynMigration ;
20
- use crate :: db:: { query, DatabaseBackend , Model } ;
21
+ use crate :: db:: { query, DatabaseBackend , LimitedString , Model } ;
21
22
use crate :: request:: { Request , RequestExt } ;
22
23
use crate :: FlareonApp ;
23
24
24
25
pub mod migrations;
25
26
27
+ pub ( crate ) const MAX_USERNAME_LENGTH : u32 = 255 ;
28
+
26
29
/// A user stored in the database.
27
30
#[ derive( Debug , Clone ) ]
28
31
#[ model]
29
32
pub struct DatabaseUser {
30
33
id : i64 ,
31
- username : String ,
34
+ username : LimitedString < MAX_USERNAME_LENGTH > ,
32
35
password : PasswordHash ,
33
36
}
34
37
38
+ #[ derive( Debug , Clone , Error ) ]
39
+ #[ non_exhaustive]
40
+ pub enum CreateUserError {
41
+ #[ error( "username is too long (max {MAX_USERNAME_LENGTH} characters, got {0})" ) ]
42
+ UsernameTooLong ( usize ) ,
43
+ }
44
+
35
45
impl DatabaseUser {
36
46
#[ must_use]
37
- pub fn new ( id : i64 , username : String , password : & Password ) -> Self {
47
+ pub fn new ( id : i64 , username : LimitedString < MAX_USERNAME_LENGTH > , password : & Password ) -> Self {
38
48
Self {
39
49
id,
40
50
username,
@@ -88,7 +98,13 @@ impl DatabaseUser {
88
98
username : T ,
89
99
password : U ,
90
100
) -> Result < Self > {
91
- let mut user = Self :: new ( 0 , username. into ( ) , & password. into ( ) ) ;
101
+ let username = username. into ( ) ;
102
+ let username_length = username. len ( ) ;
103
+ let username = LimitedString :: < MAX_USERNAME_LENGTH > :: new ( username) . map_err ( |_| {
104
+ AuthError :: backend_error ( CreateUserError :: UsernameTooLong ( username_length) )
105
+ } ) ?;
106
+
107
+ let mut user = Self :: new ( 0 , username, & password. into ( ) ) ;
92
108
user. save ( db) . await . map_err ( AuthError :: backend_error) ?;
93
109
94
110
Ok ( user)
@@ -109,7 +125,10 @@ impl DatabaseUser {
109
125
db : & DB ,
110
126
credentials : & DatabaseUserCredentials ,
111
127
) -> Result < Option < Self > > {
112
- let user = query ! ( DatabaseUser , $username == credentials. username( ) )
128
+ let username_limited =
129
+ LimitedString :: < MAX_USERNAME_LENGTH > :: new ( credentials. username ( ) . to_string ( ) )
130
+ . map_err ( |_| AuthError :: backend_error ( CreateUserError :: UsernameTooLong ( 0 ) ) ) ?;
131
+ let user = query ! ( DatabaseUser , $username == username_limited)
113
132
. get ( db)
114
133
. await
115
134
. map_err ( AuthError :: backend_error) ?;
@@ -339,7 +358,11 @@ mod tests {
339
358
340
359
#[ test]
341
360
fn session_auth_hash ( ) {
342
- let user = DatabaseUser :: new ( 1 , "testuser" . to_string ( ) , & Password :: new ( "password123" ) ) ;
361
+ let user = DatabaseUser :: new (
362
+ 1 ,
363
+ LimitedString :: new ( "testuser" ) . unwrap ( ) ,
364
+ & Password :: new ( "password123" ) ,
365
+ ) ;
343
366
let secret_key = SecretKey :: new ( b"supersecretkey" ) ;
344
367
345
368
let hash = user. session_auth_hash ( & secret_key) ;
@@ -348,7 +371,11 @@ mod tests {
348
371
349
372
#[ test]
350
373
fn database_user_traits ( ) {
351
- let user = DatabaseUser :: new ( 1 , "testuser" . to_string ( ) , & Password :: new ( "password123" ) ) ;
374
+ let user = DatabaseUser :: new (
375
+ 1 ,
376
+ LimitedString :: new ( "testuser" ) . unwrap ( ) ,
377
+ & Password :: new ( "password123" ) ,
378
+ ) ;
352
379
let user_ref: & dyn User = & user;
353
380
assert_eq ! ( user_ref. id( ) , Some ( UserId :: Int ( 1 ) ) ) ;
354
381
assert_eq ! ( user_ref. username( ) , Some ( "testuser" ) ) ;
@@ -378,7 +405,11 @@ mod tests {
378
405
#[ tokio:: test]
379
406
async fn get_by_id ( ) {
380
407
let mut mock_db = MockDatabaseBackend :: new ( ) ;
381
- let user = DatabaseUser :: new ( 1 , "testuser" . to_string ( ) , & Password :: new ( "password123" ) ) ;
408
+ let user = DatabaseUser :: new (
409
+ 1 ,
410
+ LimitedString :: new ( "testuser" ) . unwrap ( ) ,
411
+ & Password :: new ( "password123" ) ,
412
+ ) ;
382
413
383
414
mock_db
384
415
. expect_get :: < DatabaseUser > ( )
@@ -394,7 +425,11 @@ mod tests {
394
425
#[ tokio:: test]
395
426
async fn authenticate ( ) {
396
427
let mut mock_db = MockDatabaseBackend :: new ( ) ;
397
- let user = DatabaseUser :: new ( 1 , "testuser" . to_string ( ) , & Password :: new ( "password123" ) ) ;
428
+ let user = DatabaseUser :: new (
429
+ 1 ,
430
+ LimitedString :: new ( "testuser" ) . unwrap ( ) ,
431
+ & Password :: new ( "password123" ) ,
432
+ ) ;
398
433
399
434
mock_db
400
435
. expect_get :: < DatabaseUser > ( )
@@ -428,7 +463,11 @@ mod tests {
428
463
#[ tokio:: test]
429
464
async fn authenticate_invalid_password ( ) {
430
465
let mut mock_db = MockDatabaseBackend :: new ( ) ;
431
- let user = DatabaseUser :: new ( 1 , "testuser" . to_string ( ) , & Password :: new ( "password123" ) ) ;
466
+ let user = DatabaseUser :: new (
467
+ 1 ,
468
+ LimitedString :: new ( "testuser" ) . unwrap ( ) ,
469
+ & Password :: new ( "password123" ) ,
470
+ ) ;
432
471
433
472
mock_db
434
473
. expect_get :: < DatabaseUser > ( )
0 commit comments