@@ -44,7 +44,6 @@ pub struct NewUser<'a> {
4444 pub name : Option < & ' a str > ,
4545 pub gh_avatar : Option < & ' a str > ,
4646 pub gh_access_token : & ' a str ,
47- pub api_token : & ' a str ,
4847}
4948
5049impl < ' a > NewUser < ' a > {
@@ -53,16 +52,14 @@ impl<'a> NewUser<'a> {
5352 email : Option < & ' a str > ,
5453 name : Option < & ' a str > ,
5554 gh_avatar : Option < & ' a str > ,
56- gh_access_token : & ' a str ,
57- api_token : & ' a str ) -> Self {
55+ gh_access_token : & ' a str ) -> Self {
5856 NewUser {
5957 gh_id : gh_id,
6058 gh_login : gh_login,
6159 email : email,
6260 name : name,
6361 gh_avatar : gh_avatar,
6462 gh_access_token : gh_access_token,
65- api_token : api_token,
6663 }
6764 }
6865
@@ -134,8 +131,7 @@ impl User {
134131 email : Option < & str > ,
135132 name : Option < & str > ,
136133 avatar : Option < & str > ,
137- access_token : & str ,
138- api_token : & str ) -> CargoResult < User > {
134+ access_token : & str ) -> CargoResult < User > {
139135 // TODO: this is racy, but it looks like any other solution is...
140136 // interesting! For now just do the racy thing which will report
141137 // more errors than it needs to.
@@ -159,13 +155,12 @@ impl User {
159155 None => { }
160156 }
161157 let stmt = conn. prepare ( "INSERT INTO users
162- (email, gh_access_token, api_token,
158+ (email, gh_access_token,
163159 gh_login, name, gh_avatar, gh_id)
164- VALUES ($1, $2, $3, $4, $5, $6, $7 )
160+ VALUES ($1, $2, $3, $4, $5, $6)
165161 RETURNING *" ) ?;
166162 let rows = stmt. query ( & [ & email,
167163 & access_token,
168- & api_token,
169164 & login,
170165 & name,
171166 & avatar,
@@ -175,11 +170,6 @@ impl User {
175170 } ) ?) )
176171 }
177172
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-
183173 /// Converts this `User` model into an `EncodableUser` for JSON serialization.
184174 pub fn encodable ( self ) -> EncodableUser {
185175 let User { id, email, api_token : _, gh_access_token : _,
@@ -300,8 +290,6 @@ pub fn github_access_token(req: &mut Request) -> CargoResult<Response> {
300290 let ( handle, resp) = http:: github ( req. app ( ) , "/user" , & token) ?;
301291 let ghuser: GithubUser = http:: parse_github_response ( handle, resp) ?;
302292
303- // Into the database!
304- let api_token = User :: new_api_token ( ) ;
305293 let user = User :: find_or_insert ( req. tx ( ) ?,
306294 ghuser. id ,
307295 & ghuser. login ,
@@ -311,8 +299,7 @@ pub fn github_access_token(req: &mut Request) -> CargoResult<Response> {
311299 . map ( |s| & s[ ..] ) ,
312300 ghuser. avatar_url . as_ref ( )
313301 . map ( |s| & s[ ..] ) ,
314- & token. access_token ,
315- & api_token) ?;
302+ & token. access_token ) ?;
316303 req. session ( ) . insert ( "user_id" . to_string ( ) , user. id . to_string ( ) ) ;
317304 req. mut_extensions ( ) . insert ( user) ;
318305 me ( req)
@@ -328,10 +315,12 @@ pub fn logout(req: &mut Request) -> CargoResult<Response> {
328315pub fn reset_token ( req : & mut Request ) -> CargoResult < Response > {
329316 let user = req. user ( ) ?;
330317
331- let token = User :: new_api_token ( ) ;
332318 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 ) ?;
335324
336325 #[ derive( RustcEncodable ) ]
337326 struct R { api_token : String }
@@ -424,3 +413,50 @@ pub fn updates(req: &mut Request) -> CargoResult<Response> {
424413 struct Meta { more : bool }
425414 Ok ( req. json ( & R { versions : versions, crates : crates, meta : Meta { more : more } } ) )
426415}
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