1
1
import { promisify } from 'util'
2
2
import crypto from 'crypto'
3
3
import config from '../config/server'
4
+ import { ValueOf } from 'type-fest'
4
5
import { User } from '../database/users'
5
6
6
7
const randomBytes = promisify ( crypto . randomBytes )
@@ -29,9 +30,9 @@ export interface VerifyTokenData {
29
30
}
30
31
export type CtftimeAuthTokenData = string
31
32
32
- // Internal interface of type definitions for typing purposes only
33
- // - this interface does not describe a real data-structure
34
- interface TokenDataTypes {
33
+ // Internal map of type definitions for typing purposes only -
34
+ // this type does not describe a real data-structure
35
+ type TokenDataTypes = {
35
36
[ tokenKinds . auth ] : AuthTokenData ;
36
37
[ tokenKinds . team ] : TeamTokenData ;
37
38
[ tokenKinds . verify ] : VerifyTokenData ;
@@ -46,7 +47,7 @@ interface InternalTokenData<Kind extends tokenKinds> {
46
47
d : TokenDataTypes [ Kind ]
47
48
}
48
49
49
- const tokenExpiries = {
50
+ const tokenExpiries : Record < ValueOf < typeof tokenKinds > , number > = {
50
51
[ tokenKinds . auth ] : Infinity ,
51
52
[ tokenKinds . team ] : Infinity ,
52
53
[ tokenKinds . verify ] : config . loginTimeout ,
@@ -55,7 +56,7 @@ const tokenExpiries = {
55
56
56
57
const timeNow = ( ) => Math . floor ( Date . now ( ) / 1000 )
57
58
58
- const encryptToken = async ( content : unknown ) : Promise < string > => {
59
+ const encryptToken = async < Kind extends tokenKinds > ( content : InternalTokenData < Kind > ) : Promise < Token > => {
59
60
const iv = await randomBytes ( 12 )
60
61
const cipher = crypto . createCipheriv ( 'aes-256-gcm' , tokenKey , iv )
61
62
const cipherText = cipher . update ( JSON . stringify ( content ) )
@@ -64,7 +65,7 @@ const encryptToken = async (content: unknown): Promise<string> => {
64
65
return tokenContent . toString ( 'base64' )
65
66
}
66
67
67
- const decryptToken = async ( token : string ) : Promise < unknown | null > => {
68
+ const decryptToken = async < Kind extends tokenKinds > ( token : Token ) : Promise < InternalTokenData < Kind > | null > => {
68
69
try {
69
70
const tokenContent = Buffer . from ( token , 'base64' )
70
71
const iv = tokenContent . slice ( 0 , 12 )
@@ -73,14 +74,14 @@ const decryptToken = async (token: string): Promise<unknown | null> => {
73
74
cipher . setAuthTag ( authTag )
74
75
const plainText = cipher . update ( tokenContent . slice ( 12 , tokenContent . length - 16 ) )
75
76
cipher . final ( )
76
- return JSON . parse ( plainText . toString ( ) )
77
+ return JSON . parse ( plainText . toString ( ) ) as InternalTokenData < Kind >
77
78
} catch ( e ) {
78
79
return null
79
80
}
80
81
}
81
82
82
83
export const getData = async < Kind extends tokenKinds > ( expectedTokenKind : Kind , token : Token ) : Promise < TokenDataTypes [ Kind ] | null > => {
83
- const content = await decryptToken ( token ) as InternalTokenData < Kind > | null
84
+ const content = await decryptToken < Kind > ( token )
84
85
if ( content === null ) {
85
86
return null
86
87
}
@@ -99,6 +100,6 @@ export const getToken = async <Kind extends tokenKinds>(tokenKind: Kind, data: T
99
100
k : tokenKind ,
100
101
t : timeNow ( ) ,
101
102
d : data
102
- } ) as Token
103
+ } )
103
104
return token
104
105
}
0 commit comments