@@ -44,7 +44,6 @@ pub struct NewUser<'a> {
44
44
pub name : Option < & ' a str > ,
45
45
pub gh_avatar : Option < & ' a str > ,
46
46
pub gh_access_token : & ' a str ,
47
- pub api_token : & ' a str ,
48
47
}
49
48
50
49
impl < ' a > NewUser < ' a > {
@@ -53,16 +52,14 @@ impl<'a> NewUser<'a> {
53
52
email : Option < & ' a str > ,
54
53
name : Option < & ' a str > ,
55
54
gh_avatar : Option < & ' a str > ,
56
- gh_access_token : & ' a str ,
57
- api_token : & ' a str ) -> Self {
55
+ gh_access_token : & ' a str ) -> Self {
58
56
NewUser {
59
57
gh_id : gh_id,
60
58
gh_login : gh_login,
61
59
email : email,
62
60
name : name,
63
61
gh_avatar : gh_avatar,
64
62
gh_access_token : gh_access_token,
65
- api_token : api_token,
66
63
}
67
64
}
68
65
@@ -134,8 +131,7 @@ impl User {
134
131
email : Option < & str > ,
135
132
name : Option < & str > ,
136
133
avatar : Option < & str > ,
137
- access_token : & str ,
138
- api_token : & str ) -> CargoResult < User > {
134
+ access_token : & str ) -> CargoResult < User > {
139
135
// TODO: this is racy, but it looks like any other solution is...
140
136
// interesting! For now just do the racy thing which will report
141
137
// more errors than it needs to.
@@ -159,13 +155,12 @@ impl User {
159
155
None => { }
160
156
}
161
157
let stmt = conn. prepare ( "INSERT INTO users
162
- (email, gh_access_token, api_token,
158
+ (email, gh_access_token,
163
159
gh_login, name, gh_avatar, gh_id)
164
- VALUES ($1, $2, $3, $4, $5, $6, $7 )
160
+ VALUES ($1, $2, $3, $4, $5, $6)
165
161
RETURNING *" ) ?;
166
162
let rows = stmt. query ( & [ & email,
167
163
& access_token,
168
- & api_token,
169
164
& login,
170
165
& name,
171
166
& avatar,
@@ -175,11 +170,6 @@ impl User {
175
170
} ) ?) )
176
171
}
177
172
178
- /// Generates a new crates.io API token.
179
- pub fn new_api_token ( ) -> String {
180
- thread_rng ( ) . gen_ascii_chars ( ) . take ( 32 ) . collect ( )
181
- }
182
-
183
173
/// Converts this `User` model into an `EncodableUser` for JSON serialization.
184
174
pub fn encodable ( self ) -> EncodableUser {
185
175
let User { id, email, api_token : _, gh_access_token : _,
@@ -300,8 +290,6 @@ pub fn github_access_token(req: &mut Request) -> CargoResult<Response> {
300
290
let ( handle, resp) = http:: github ( req. app ( ) , "/user" , & token) ?;
301
291
let ghuser: GithubUser = http:: parse_github_response ( handle, resp) ?;
302
292
303
- // Into the database!
304
- let api_token = User :: new_api_token ( ) ;
305
293
let user = User :: find_or_insert ( req. tx ( ) ?,
306
294
ghuser. id ,
307
295
& ghuser. login ,
@@ -311,8 +299,7 @@ pub fn github_access_token(req: &mut Request) -> CargoResult<Response> {
311
299
. map ( |s| & s[ ..] ) ,
312
300
ghuser. avatar_url . as_ref ( )
313
301
. map ( |s| & s[ ..] ) ,
314
- & token. access_token ,
315
- & api_token) ?;
302
+ & token. access_token ) ?;
316
303
req. session ( ) . insert ( "user_id" . to_string ( ) , user. id . to_string ( ) ) ;
317
304
req. mut_extensions ( ) . insert ( user) ;
318
305
me ( req)
@@ -328,10 +315,12 @@ pub fn logout(req: &mut Request) -> CargoResult<Response> {
328
315
pub fn reset_token ( req : & mut Request ) -> CargoResult < Response > {
329
316
let user = req. user ( ) ?;
330
317
331
- let token = User :: new_api_token ( ) ;
332
318
let conn = req. tx ( ) ?;
333
- conn. execute ( "UPDATE users SET api_token = $1 WHERE id = $2" ,
334
- & [ & token, & user. id ] ) ?;
319
+ let rows = conn. query ( "UPDATE users SET api_token = DEFAULT \
320
+ WHERE id = $1 RETURNING api_token", & [ & user. id ] ) ?;
321
+ let token = rows. iter ( ) . next ( )
322
+ . map ( |r| r. get ( "api_token" ) )
323
+ . chain_error ( || NotFound ) ?;
335
324
336
325
#[ derive( RustcEncodable ) ]
337
326
struct R { api_token : String }
@@ -424,3 +413,50 @@ pub fn updates(req: &mut Request) -> CargoResult<Response> {
424
413
struct Meta { more : bool }
425
414
Ok ( req. json ( & R { versions : versions, crates : crates, meta : Meta { more : more } } ) )
426
415
}
416
+
417
+ #[ cfg( test) ]
418
+ mod tests {
419
+ use super :: * ;
420
+ use diesel:: pg:: PgConnection ;
421
+ use dotenv:: dotenv;
422
+ use std:: env;
423
+
424
+ fn connection ( ) -> PgConnection {
425
+ let _ = dotenv ( ) ;
426
+ let database_url = env:: var ( "TEST_DATABASE_URL" )
427
+ . expect ( "TEST_DATABASE_URL must be set to run tests" ) ;
428
+ let conn = PgConnection :: establish ( & database_url) . unwrap ( ) ;
429
+ conn. begin_test_transaction ( ) . unwrap ( ) ;
430
+ conn
431
+ }
432
+
433
+ #[ test]
434
+ fn new_users_have_different_api_tokens ( ) {
435
+ let conn = connection ( ) ;
436
+ let user1 = NewUser :: new ( 1 , "foo" , None , None , None , "foo" )
437
+ . create_or_update ( & conn) . unwrap ( ) ;
438
+ let user2 = NewUser :: new ( 2 , "bar" , None , None , None , "bar" )
439
+ . create_or_update ( & conn) . unwrap ( ) ;
440
+
441
+ assert_ne ! ( user1. id, user2. id) ;
442
+ assert_ne ! ( user1. api_token, user2. api_token) ;
443
+ assert_eq ! ( 32 , user1. api_token. len( ) ) ;
444
+ }
445
+
446
+ #[ test]
447
+ fn updating_existing_user_doesnt_change_api_token ( ) {
448
+ let conn = connection ( ) ;
449
+ let user_after_insert = NewUser :: new ( 1 , "foo" , None , None , None , "foo" )
450
+ . create_or_update ( & conn) . unwrap ( ) ;
451
+ let original_token = user_after_insert. api_token ;
452
+ NewUser :: new ( 1 , "bar" , None , None , None , "bar_token" )
453
+ . create_or_update ( & conn) . unwrap ( ) ;
454
+ let mut users = users:: table. load :: < User > ( & conn) . unwrap ( ) ;
455
+ assert_eq ! ( 1 , users. len( ) ) ;
456
+ let user = users. pop ( ) . unwrap ( ) ;
457
+
458
+ assert_eq ! ( "bar" , user. gh_login) ;
459
+ assert_eq ! ( "bar_token" , user. gh_access_token) ;
460
+ assert_eq ! ( original_token, user. api_token) ;
461
+ }
462
+ }
0 commit comments