package Ġdo ist . ff s . routes Ċ Ċ import Ġdo ist . ff s . auth . Arg on 2 Password Ċ import Ġdo ist . ff s . auth . Session Ċ import Ġdo ist . ff s . db . User Queries Ċ import Ġdo ist . ff s . db . capt uring Last Insert Id Ċ import Ġdo ist . ff s . db . users Ċ import Ġdo ist . ff s . plugins . database Ċ import Ġio . ktor . http . HttpHeaders Ċ import Ġio . ktor . http . HttpStatusCode Ċ import Ġio . ktor . server . application . Application Ċ import Ġio . ktor . server . application . call Ċ import Ġio . ktor . server . auth . authenticate Ċ import Ġio . ktor . server . request . receive Parameters Ċ import Ġio . ktor . server . response . header Ċ import Ġio . ktor . server . response . respond Ċ import Ġio . ktor . server . routing . Route Ċ import Ġio . ktor . server . routing . delete Ċ import Ġio . ktor . server . routing . post Ċ import Ġio . ktor . server . routing . put Ċ import Ġio . ktor . server . routing . route Ċ import Ġio . ktor . server . routing . routing Ċ import Ġio . ktor . server . sessions . sessions Ċ import Ġio . ktor . server . sessions . set Ċ import Ġio . ktor . server . util . get OrFail Ċ import Ġkotlinx . coroutines . delay Ċ import Ġkotlin . random . Random Ċ Ċ const Ġval ĠPATH _ USERS Ġ= Ġ"/ users " Ċ const Ġval ĠPATH _ REGISTER Ġ= Ġ"/ register " Ċ const Ġval ĠPATH _ LOGIN Ġ= Ġ"/ login " Ċ Ċ @ Suppress (" FunctionName ") Ċ fun ĠPATH _ USER ( id : ĠAny ) Ġ= Ġ"$ PATH _ USERS /$ id " Ċ Ċ fun ĠApplication . install User Routes () Ġ{ ĊĠĠĠ Ġrouting Ġ{ ĊĠĠĠĠĠĠĠ Ġroute ( PATH _ USERS ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġregister User () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlogin User () ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġauthenticate (" session ") Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġupdate User () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdelete User () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ } Ċ Ċ /** Ċ Ġ* ĠRegister Ġa Ġuser . Ċ Ġ* Ċ Ġ* ĠOn Ġsuccess , Ġrespon ds Ġ` 2 0 1 ĠCreated ` Ġwith Ġan Ġempty Ġbody . Ċ Ġ* Ċ Ġ* Ġ| ĠParameter Ġ Ġ| ĠRequired Ġ| ĠDescription ĠĠĠĠĠĠĠĠĠĠ Ġ| Ċ Ġ* Ġ| Ġ---------- Ġ| Ġ-------- Ġ| Ġ---------------- ----- Ġ| Ċ Ġ* Ġ| Ġ` name ` ĠĠĠĠ Ġ| ĠYes ĠĠĠĠĠ Ġ| ĠName Ġof Ġthe Ġuser . ĠĠĠĠ Ġ| Ċ Ġ* Ġ| Ġ` email ` ĠĠĠ Ġ| ĠYes ĠĠĠĠĠ Ġ| ĠEmail Ġof Ġthe Ġuser . ĠĠĠ Ġ| Ċ Ġ* Ġ| Ġ` password ` Ġ| ĠYes ĠĠĠĠĠ Ġ| ĠPassword Ġof Ġthe Ġuser . Ġ| Ċ Ġ*/ Ċ private Ġfun ĠRoute . register User () Ġ= Ġpost ( PATH _ REGISTER ) Ġ{ ĊĠĠĠ Ġval Ġparams Ġ= Ġcall . receive Parameters () ĊĠĠĠ Ġval Ġname Ġ= Ġparams . get OrFail (" name ") ĊĠĠĠ Ġval Ġemail Ġ= Ġparams . get OrFail (" email ") ĊĠĠĠ Ġval Ġpassword Ġ= Ġparams . get OrFail (" password ") ĊĊĠĠĠ Ġif Ġ( validate Email ( email ) Ġ&& Ġvalidate Password ( password )) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġid Ġ= Ġdatabase . capt uring Last Insert Id Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġusers . insert ( name Ġ= Ġname , Ġemail Ġ= Ġemail , Ġpassword Ġ= ĠArg on 2 Password . encode ( password )) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġcall . sessions . set ( Session ( id )) ĊĠĠĠĠĠĠĠ Ġcall . response . header ( HttpHeaders . Location , ĠPATH _ USER ( id )) ĊĠĠĠĠĠĠĠ Ġcall . respond ( HttpStatusCode . Created ) ĊĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠ Ġcall . respond ( HttpStatusCode . BadRequest ) ĊĠĠĠ Ġ} Ċ } Ċ Ċ /** Ċ Ġ* ĠLog Ġin Ġa Ġuser . Ċ Ġ* Ċ Ġ* ĠOn Ġsuccess , Ġrespon ds Ġ` 2 0 0 ĠOK ` Ġwith Ġthe Ġuser Ġdata . Ċ Ġ* Ċ Ġ* Ġ| ĠParameter Ġ Ġ| ĠRequired Ġ| ĠDescription ĠĠĠĠĠĠĠĠĠĠ Ġ| Ċ Ġ* Ġ| Ġ---------- Ġ| Ġ-------- Ġ| Ġ---------------- ----- Ġ| Ċ Ġ* Ġ| Ġ` email ` ĠĠĠ Ġ| ĠYes ĠĠĠĠĠ Ġ| ĠEmail Ġof Ġthe Ġuser . ĠĠĠ Ġ| Ċ Ġ* Ġ| Ġ` password ` Ġ| ĠYes ĠĠĠĠĠ Ġ| ĠPassword Ġof Ġthe Ġuser . Ġ| Ċ Ġ*/ Ċ private Ġfun ĠRoute . login User () Ġ= Ġpost ( PATH _ LOGIN ) Ġ{ ĊĠĠĠ Ġval Ġparams Ġ= Ġcall . receive Parameters () ĊĠĠĠ Ġval Ġemail Ġ= Ġparams . get OrFail (" email ") ĊĠĠĠ Ġval Ġpassword Ġ= Ġparams . get OrFail (" password ") ĊĊĠĠĠ Ġval Ġid Ġ= Ġdatabase . users . select Id By Email ( email Ġ= Ġemail ). execute As One OrNull () ĊĠĠĠ Ġif Ġ( id Ġ!= Ġnull Ġ&& Ġdatabase . users . test Password ( id , Ġpassword )) Ġ{ ĊĠĠĠĠĠĠĠ Ġcall . sessions . set ( Session ( id )) ĊĠĠĠĠĠĠĠ Ġcall . respond ( HttpStatusCode . OK , Ġdatabase . users . select ById ( id Ġ= Ġid ). execute As One ()) ĊĠĠĠĠĠĠĠ Ġreturn @ post ĊĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠ Ġcall . respond ( HttpStatusCode . Unauthorized ) ĊĠĠĠ Ġ} Ċ } Ċ Ċ /** Ċ Ġ* ĠUpdate Ġa Ġuser . Ċ Ġ* Ċ Ġ* ĠOn Ġsuccess , Ġrespon ds Ġ` 2 0 4 ĠNo ĠContent ` Ġwith Ġan Ġempty Ġbody . Ċ Ġ* Ċ Ġ* Ġ| ĠParameter ĠĠĠĠĠĠĠĠĠ Ġ| ĠRequired ĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ| ĠDescription ĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ| Ċ Ġ* Ġ| Ġ---------------- -- Ġ| Ġ-------------------------------- ----- Ġ| Ġ---------------- --------- Ġ| Ċ Ġ* Ġ| Ġ` name ` ĠĠĠĠĠĠĠĠĠĠĠĠ Ġ| ĠNo ĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ| ĠName Ġof Ġthe Ġuser . ĠĠĠĠĠĠĠĠ Ġ| Ċ Ġ* Ġ| Ġ` email ` ĠĠĠĠĠĠĠĠĠĠĠ Ġ| ĠNo ĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ| ĠEmail Ġof Ġthe Ġuser . ĠĠĠĠĠĠĠ Ġ| Ċ Ġ* Ġ| Ġ` password ` ĠĠĠĠĠĠĠĠ Ġ| ĠNo ĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ| ĠPassword Ġof Ġthe Ġuser . ĠĠĠĠ Ġ| Ċ Ġ* Ġ| Ġ` current _ password ` Ġ| ĠIf Ġ` email ` Ġor Ġ` password Ġare Ġprovided Ġ Ġ| ĠCurrent Ġuser Ġpassword . ĠĠĠ Ġ| Ċ Ġ*/ Ċ private Ġfun ĠRoute . update User () Ġ= Ġput ("{ id }") Ġ{ ĊĠĠĠ Ġval Ġid Ġ= Ġcall . parameters . get OrFail < Long >(" id ") ĊĠĠĠ Ġval Ġparams Ġ= Ġcall . receive Parameters () ĊĠĠĠ Ġval Ġcurrent Password Ġ= Ġparams [" current _ password "] ĊĠĠĠ Ġval Ġname Ġ= Ġparams [" name "] ĊĠĠĠ Ġval Ġemail Ġ= Ġparams [" email "] ĊĠĠĠ Ġval Ġpassword Ġ= Ġparams [" password "] ĊĊĠĠĠ Ġauthorize ForUser ( id Ġ= Ġid ) ĊĊĠĠĠ Ġval Ġvalid Current Password Ġ= Ġdatabase . users . test Password ( id , Ġcurrent Password Ġ?: Ġ"") ĊĠĠĠ Ġval Ġresponse Ġ= Ġdatabase . transaction With Result < HttpStatusCode > Ġ{ ĊĠĠĠĠĠĠĠ Ġ// ĠUpdate Ġname , Ġif Ġprovided . ĊĠĠĠĠĠĠĠ Ġname ?. let Ġ{ Ġname Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdatabase . users . update Name ( id Ġ= Ġid , Ġname Ġ= Ġname ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġ// ĠUpdate Ġemail , Ġif Ġprovided Ġand Ġcurrent Ġpassword Ġis Ġvalid . ĊĠĠĠĠĠĠĠ Ġemail ?. let Ġ{ Ġemail Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( valid Current Password ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( validate Email ( email )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdatabase . users . update Email ( id Ġ= Ġid , Ġemail Ġ= Ġemail ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrollback ( HttpStatusCode . BadRequest ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrollback ( HttpStatusCode . Forbidden ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġ// ĠUpdate Ġpassword , Ġif Ġprovided Ġand Ġcurrent Ġpassword Ġis Ġvalid . ĊĠĠĠĠĠĠĠ Ġpassword ?. let Ġ{ Ġpassword Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( valid Current Password ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( validate Password ( password )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdatabase . users . update Password ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġid Ġ= Ġid , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġpassword Ġ= ĠArg on 2 Password . encode ( password ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrollback ( HttpStatusCode . BadRequest ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġrollback ( HttpStatusCode . Forbidden ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġ// ĠIf Ġwe 're Ġhere Ġand Ġno Ġrollback s Ġhappened , Ġthe Ġrequest Ġwas Ġprocessed Ġsuccessfully . ĊĠĠĠĠĠĠĠ ĠHttpStatusCode . No Content ĊĠĠĠ Ġ} ĊĠĠĠ Ġcall . respond ( response ) Ċ } Ċ Ċ /** Ċ Ġ* ĠDelete Ġa Ġuser . Ċ Ġ* Ċ Ġ* ĠOn Ġsuccess , Ġrespon ds Ġ` 2 0 4 ĠNo ĠContent ` Ġwith Ġan Ġempty Ġbody . Ċ Ġ* Ċ Ġ* Ġ| ĠParameter ĠĠĠĠĠĠĠĠĠ Ġ| ĠRequired Ġ Ġ| ĠDescription ĠĠĠĠĠĠĠĠĠĠĠĠ Ġ| Ċ Ġ* Ġ| Ġ---------------- -- Ġ| Ġ--------- Ġ| Ġ---------------- ------- Ġ| Ċ Ġ* Ġ| Ġ` current _ password ` Ġ| ĠYes ĠĠĠĠĠĠ Ġ| ĠCurrent Ġuser Ġpassword . Ġ Ġ| Ċ Ġ*/ Ċ private Ġfun ĠRoute . delete User () Ġ= Ġdelete ("{ id }") Ġ{ ĊĠĠĠ Ġval Ġid Ġ= Ġcall . parameters . get OrFail < Long >(" id ") ĊĠĠĠ Ġval Ġparams Ġ= Ġcall . receive Parameters () ĊĠĠĠ Ġval Ġcurrent Password Ġ= Ġparams . get OrFail (" current _ password ") ĊĊĠĠĠ Ġauthorize ForUser ( id Ġ= Ġid ) ĊĊĠĠĠ Ġif Ġ( database . users . test Password ( id , Ġcurrent Password )) Ġ{ ĊĠĠĠĠĠĠĠ Ġdatabase . users . delete ( id Ġ= Ġid ) ĊĠĠĠĠĠĠĠ Ġcall . respond ( HttpStatusCode . No Content ) ĊĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠ Ġcall . respond ( HttpStatusCode . Forbidden ) ĊĠĠĠ Ġ} Ċ } Ċ Ċ /** Ċ Ġ* ĠValid ates Ġthe Ġemail . Ċ Ġ*/ Ċ private Ġval ĠE MAIL _ REG EXP Ġ= Ġ( ĊĠĠĠ Ġ"^ (? = .{ 1 , 6 4 }@ )[ \\ p { L } 0 - 9 _- ]+ ([ \\. + ][ \\ p { L } 0 - 9 _- ]+ )* " Ġ+ ĊĠĠĠĠĠĠĠ Ġ"@ [^ - ][ \\ p { L } 0 - 9 - ]+ (\\ .[ \\ p { L } 0 - 9 - ]+ )* " Ġ+ ĊĠĠĠĠĠĠĠ Ġ"( \\ .[ \\ p { L } ]{ 2 , })\ $" ĊĠĠĠ Ġ). to Regex () Ċ private Ġfun Ġvalidate Email ( email : ĠString ): ĠBoolean Ġ{ ĊĠĠĠ Ġreturn Ġemail . matches ( EMAIL _ REG EXP ) Ċ } Ċ Ċ /** Ċ Ġ* ĠValid ates Ġthe Ġpassword . Ċ Ġ*/ Ċ private Ġval ĠPASSWORD _ REG EXP Ġ= Ġ". { 8 , }". to Regex () Ċ private Ġfun Ġvalidate Password ( password : ĠString ): ĠBoolean Ġ{ ĊĠĠĠ Ġreturn Ġpassword . matches ( PASSWORD _ REG EXP ) Ċ } Ċ Ċ /** Ċ Ġ* ĠTests Ġthe Ġpassword Ġfor Ġuser Ġwith Ġ[ id ]. Ċ Ġ*/ Ċ private Ġsuspend Ġfun ĠUser Queries . test Password ( ĊĠĠĠ Ġid : ĠLong , ĊĠĠĠ Ġpassword : ĠString Ċ ): ĠBoolean Ġ{ ĊĠĠĠ Ġval Ġencoded Ġ= Ġselect Password ById ( id Ġ= Ġid ). execute As One OrNull () ĊĠĠĠ Ġif Ġ( encoded Ġ!= Ġnull Ġ&& ĠArg on 2 Password . matches ( password , Ġencoded )) Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġtrue ĊĠĠĠ Ġ} ĊĠĠĠ Ġ// ĠW aste Ġtime Ġto Ġhelp Ġmit igate Ġtiming Ġattacks . ĊĠĠĠ Ġ@ Suppress (" Magic Number ") ĊĠĠĠ Ġdelay ( Random . next Long ( 2 0 0 , Ġ 4 0 0 )) ĊĠĠĠ Ġreturn Ġfalse Ċ } Ċ