@@ -11,6 +11,10 @@ export type RegistrationData = {
1111 alias : string ;
1212 email : string | null ;
1313} ;
14+ export type LoginData = {
15+ username : string ;
16+ password : string ;
17+ }
1418export type RegistrationResult = {
1519 resultCode : number ;
1620 message : string ;
@@ -29,6 +33,11 @@ export type AuthenticationHandlerConfig = {
2933 limits : LimitsConfig ;
3034}
3135
36+ export type UserInfo = {
37+ user : User ;
38+ sessions : Session [ ] ;
39+ }
40+
3241const SALT_ROUNDS = 12 ;
3342
3443function generateSessionId ( ) {
@@ -81,7 +90,7 @@ export class AuthenticationHandler {
8190 const userId = user . rows [ 0 ] . id ;
8291 const sessionId = generateSessionId ( ) ;
8392 let session = await this . #config. db . query < Session > (
84- `INSERT INTO sessions (session_id , user_id, created_at, active_ip_address, updated_at)
93+ `INSERT INTO sessions (session_key , user_id, created_at, active_ip_address, updated_at)
8594 VALUES ($1, $2, now(), $3, now());` ,
8695 [
8796 sessionId ,
@@ -169,15 +178,14 @@ Enjoy!`;
169178 return user . affectedRows > 0 ;
170179 }
171180
172-
173181 async getSession ( address : string , sessionId ?: string ) : Promise < Session | null > {
174182 if ( ! sessionId ) {
175183 return null ;
176184 }
177185 const session = await this . #config. db . query < Session > (
178186 `UPDATE sessions
179187 SET updated_at = now(), active_ip_address = $2
180- WHERE session_id = $1 AND updated_at >= now() - INTERVAL '7 days'
188+ WHERE session_key = $1 AND updated_at >= now() - INTERVAL '7 days'
181189 RETURNING *;` ,
182190 [ sessionId , address ]
183191 ) ;
@@ -186,4 +194,74 @@ Enjoy!`;
186194 }
187195 return session . rows [ 0 ] ;
188196 }
197+
198+ async loginUser ( address : string , data : LoginData ) : Promise < RegistrationResult > {
199+ const { username, password } = data ;
200+ const userResult = await this . #config. db . query < User > (
201+ `SELECT * FROM users WHERE username = $1;` ,
202+ [ username ]
203+ ) ;
204+ if ( userResult . rows . length == 0 || ! userResult . rows [ 0 ] . hashed_password ||
205+ ! await bcrypt . compare ( password , userResult . rows [ 0 ] . hashed_password ) ) {
206+ return {
207+ resultCode : 401 ,
208+ message : 'Invalid username or password' ,
209+ } ;
210+ }
211+ const user = userResult . rows [ 0 ] ;
212+ const sessionId = generateSessionId ( ) ;
213+ let session = await this . #config. db . query < Session > (
214+ `INSERT INTO sessions (session_key, user_id, created_at, active_ip_address, updated_at)
215+ VALUES ($1, $2, now(), $3, now());` ,
216+ [
217+ sessionId ,
218+ user . id ,
219+ address ,
220+ ]
221+ ) ;
222+ if ( session . affectedRows == 0 ) {
223+ return {
224+ resultCode : 500 ,
225+ message : 'Failed to initialize session' ,
226+ } ;
227+ }
228+ return {
229+ resultCode : 200 ,
230+ message : 'Login successful.' ,
231+ sessionId : sessionId
232+ } ;
233+ }
234+
235+ async logoutSession ( session : Session , id : number ) : Promise < void > {
236+ await this . #config. db . query (
237+ `DELETE FROM sessions WHERE id = $1 AND user_id = $2;` ,
238+ [ id , session . user_id ]
239+ ) ;
240+ }
241+
242+ async getUserInfo ( session : Session ) : Promise < UserInfo > {
243+ const userData = await this . #config. db . query < User > (
244+ `SELECT id, email, username, alias, verification_email, created_ip_address, created_at, active_at
245+ FROM users WHERE id = $1;` ,
246+ [ session . user_id ]
247+ ) ;
248+ if ( userData . rows . length == 0 ) {
249+ throw new Error ( 'User not found' ) ;
250+ }
251+
252+ // Don't include session_key for security reasons.
253+ const sessions = await this . #config. db . query < Session > (
254+ `SELECT id, url, user_id, created_at, active_ip_address, updated_at FROM sessions
255+ WHERE user_id = $1
256+ ORDER BY updated_at DESC;` ,
257+ [ session . user_id ]
258+ ) ;
259+
260+ return {
261+ user : userData . rows [ 0 ] ,
262+ sessions : sessions . rows ,
263+ } ;
264+ }
265+
266+
189267} ;
0 commit comments