11import axios from "axios" ;
22import bcrypt from "bcrypt" ;
3+ import crypto from "crypto" ;
34import { FastifyInstance , FastifyReply , FastifyRequest } from "fastify" ;
45import jwt from "jsonwebtoken" ;
56import { LRUCache } from "lru-cache" ;
@@ -320,22 +321,31 @@ export function authRoutes(fastify: FastifyInstance) {
320321 throw new Error ( "Password is not valid" ) ;
321322 }
322323
323- var b64string = process . env . SECRET ;
324- var buf = new Buffer ( b64string ! , "base64" ) ; // Ta-da
325-
326- let token = jwt . sign (
324+ // Generate a secure session token
325+ var secret = Buffer . from ( process . env . SECRET ! , "base64" ) ;
326+ const token = jwt . sign (
327327 {
328- data : { id : user ! . id } ,
328+ data : {
329+ id : user ! . id ,
330+ // Add a unique identifier for this session
331+ sessionId : crypto . randomBytes ( 32 ) . toString ( 'hex' )
332+ }
329333 } ,
330- buf ,
331- { expiresIn : "7d" }
334+ secret ,
335+ {
336+ expiresIn : "8h" ,
337+ algorithm : 'HS256'
338+ }
332339 ) ;
333340
341+ // Store session with additional security info
334342 await prisma . session . create ( {
335343 data : {
336344 userId : user ! . id ,
337345 sessionToken : token ,
338- expires : new Date ( Date . now ( ) + 60 * 60 * 1000 ) ,
346+ expires : new Date ( Date . now ( ) + 8 * 60 * 60 * 1000 ) , // 8 hours
347+ userAgent : request . headers [ 'user-agent' ] || '' ,
348+ ipAddress : request . ip ,
339349 } ,
340350 } ) ;
341351
@@ -763,18 +773,12 @@ export function authRoutes(fastify: FastifyInstance) {
763773 password : string ;
764774 } ;
765775
766- const bearer = request . headers . authorization ! . split ( " " ) [ 1 ] ;
767-
768- let session = await prisma . session . findUnique ( {
769- where : {
770- sessionToken : bearer ,
771- } ,
772- } ) ;
776+ const session = await checkSession ( request ) ;
773777
774778 const hashedPass = await bcrypt . hash ( password , 10 ) ;
775779
776780 await prisma . user . update ( {
777- where : { id : session ?. userId } ,
781+ where : { id : session ?. id } ,
778782 data : {
779783 password : hashedPass ,
780784 } ,
@@ -831,13 +835,7 @@ export function authRoutes(fastify: FastifyInstance) {
831835 fastify . put (
832836 "/api/v1/auth/profile" ,
833837 async ( request : FastifyRequest , reply : FastifyReply ) => {
834- const bearer = request . headers . authorization ! . split ( " " ) [ 1 ] ;
835-
836- let session = await prisma . session . findUnique ( {
837- where : {
838- sessionToken : bearer ,
839- } ,
840- } ) ;
838+ const session = await checkSession ( request ) ;
841839
842840 const { name, email, language } = request . body as {
843841 name : string ;
@@ -846,7 +844,7 @@ export function authRoutes(fastify: FastifyInstance) {
846844 } ;
847845
848846 let user = await prisma . user . update ( {
849- where : { id : session ?. userId } ,
847+ where : { id : session ?. id } ,
850848 data : {
851849 name : name ,
852850 email : email ,
@@ -864,12 +862,7 @@ export function authRoutes(fastify: FastifyInstance) {
864862 fastify . put (
865863 "/api/v1/auth/profile/notifcations/emails" ,
866864 async ( request : FastifyRequest , reply : FastifyReply ) => {
867- const bearer = request . headers . authorization ! . split ( " " ) [ 1 ] ;
868- let session = await prisma . session . findUnique ( {
869- where : {
870- sessionToken : bearer ,
871- } ,
872- } ) ;
865+ const session = await checkSession ( request ) ;
873866
874867 const {
875868 notify_ticket_created,
@@ -879,7 +872,7 @@ export function authRoutes(fastify: FastifyInstance) {
879872 } = request . body as any ;
880873
881874 let user = await prisma . user . update ( {
882- where : { id : session ?. userId } ,
875+ where : { id : session ?. id } ,
883876 data : {
884877 notify_ticket_created : notify_ticket_created ,
885878 notify_ticket_assigned : notify_ticket_assigned ,
@@ -912,28 +905,37 @@ export function authRoutes(fastify: FastifyInstance) {
912905 fastify . put (
913906 "/api/v1/auth/user/role" ,
914907 async ( request : FastifyRequest , reply : FastifyReply ) => {
915- const { id, role } = request . body as { id : string ; role : boolean } ;
916- // check for atleast one admin on role downgrade
917- if ( role === false ) {
918- const admins = await prisma . user . findMany ( {
919- where : { isAdmin : true } ,
920- } ) ;
921- if ( admins . length === 1 ) {
922- reply . code ( 400 ) . send ( {
923- message : "Atleast one admin is required" ,
924- success : false ,
908+ const session = await checkSession ( request ) ;
909+
910+ if ( session ?. isAdmin ) {
911+ const { id, role } = request . body as { id : string ; role : boolean } ;
912+ // check for atleast one admin on role downgrade
913+ if ( role === false ) {
914+ const admins = await prisma . user . findMany ( {
915+ where : { isAdmin : true } ,
925916 } ) ;
926- return ;
917+ if ( admins . length === 1 ) {
918+ reply . code ( 400 ) . send ( {
919+ message : "Atleast one admin is required" ,
920+ success : false ,
921+ } ) ;
922+ return ;
923+ }
927924 }
928- }
929- await prisma . user . update ( {
930- where : { id } ,
931- data : {
932- isAdmin : role ,
933- } ,
934- } ) ;
925+ await prisma . user . update ( {
926+ where : { id } ,
927+ data : {
928+ isAdmin : role ,
929+ } ,
930+ } ) ;
935931
936- reply . send ( { success : true } ) ;
932+ reply . send ( { success : true } ) ;
933+ } else {
934+ reply . code ( 401 ) . send ( {
935+ message : "Unauthorized" ,
936+ success : false ,
937+ } ) ;
938+ }
937939 }
938940 ) ;
939941
@@ -955,4 +957,57 @@ export function authRoutes(fastify: FastifyInstance) {
955957 reply . send ( { success : true } ) ;
956958 }
957959 ) ;
960+
961+ // Add a new endpoint to list and manage active sessions
962+ fastify . get ( "/api/v1/auth/sessions" ,
963+ async ( request : FastifyRequest , reply : FastifyReply ) => {
964+ const currentUser = await checkSession ( request ) ;
965+ if ( ! currentUser ) {
966+ return reply . code ( 401 ) . send ( { message : "Unauthorized" } ) ;
967+ }
968+
969+ const sessions = await prisma . session . findMany ( {
970+ where : { userId : currentUser . id } ,
971+ select : {
972+ id : true ,
973+ userAgent : true ,
974+ ipAddress : true ,
975+ createdAt : true ,
976+ expires : true
977+ }
978+ } ) ;
979+
980+ reply . send ( { sessions } ) ;
981+ }
982+ ) ;
983+
984+ // Add ability to revoke specific sessions
985+ fastify . delete ( "/api/v1/auth/sessions/:sessionId" ,
986+ async ( request : FastifyRequest , reply : FastifyReply ) => {
987+ const currentUser = await checkSession ( request ) ;
988+ if ( ! currentUser ) {
989+ return reply . code ( 401 ) . send ( { message : "Unauthorized" } ) ;
990+ }
991+
992+ const { sessionId } = request . params as { sessionId : string } ;
993+
994+ // Only allow users to delete their own sessions
995+ const session = await prisma . session . findFirst ( {
996+ where : {
997+ id : sessionId ,
998+ userId : currentUser . id
999+ }
1000+ } ) ;
1001+
1002+ if ( ! session ) {
1003+ return reply . code ( 404 ) . send ( { message : "Session not found" } ) ;
1004+ }
1005+
1006+ await prisma . session . delete ( {
1007+ where : { id : sessionId }
1008+ } ) ;
1009+
1010+ reply . send ( { success : true } ) ;
1011+ }
1012+ ) ;
9581013}
0 commit comments