Skip to content
This repository was archived by the owner on Feb 4, 2025. It is now read-only.

Commit 496a7cc

Browse files
committed
refactor(server): improve auth typings
Have stronger typings on private token machinery, fix type of register.register, and use the ValueOf utility type from type-fest.
1 parent c3ef4ce commit 496a7cc

File tree

2 files changed

+13
-11
lines changed

2 files changed

+13
-11
lines changed

server/auth/register.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ import { v4 as uuidv4 } from 'uuid'
22
import { makeUser, User } from '../database/users'
33
import { getToken, tokenKinds } from './token'
44
import { responses } from '../responses'
5+
import { ValueOf } from 'type-fest'
56

67
export const register = async (
7-
{ division, email, name, ctftimeId }: User
8-
): Promise<[typeof responses.goodRegister, { authToken: string }] | (typeof responses)[keyof typeof responses]> => {
8+
{ division, email, name, ctftimeId }: Pick<User, 'division' | 'email' | 'name' | 'ctftimeId'>
9+
): Promise<[typeof responses.goodRegister, { authToken: string }] | ValueOf<typeof responses>> => {
910
const userUuid = uuidv4()
1011
try {
1112
await makeUser({

server/auth/token.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { promisify } from 'util'
22
import crypto from 'crypto'
33
import config from '../config/server'
4+
import { ValueOf } from 'type-fest'
45
import { User } from '../database/users'
56

67
const randomBytes = promisify(crypto.randomBytes)
@@ -29,9 +30,9 @@ export interface VerifyTokenData {
2930
}
3031
export type CtftimeAuthTokenData = string
3132

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 = {
3536
[tokenKinds.auth]: AuthTokenData;
3637
[tokenKinds.team]: TeamTokenData;
3738
[tokenKinds.verify]: VerifyTokenData;
@@ -46,7 +47,7 @@ interface InternalTokenData<Kind extends tokenKinds> {
4647
d: TokenDataTypes[Kind]
4748
}
4849

49-
const tokenExpiries = {
50+
const tokenExpiries: Record<ValueOf<typeof tokenKinds>, number> = {
5051
[tokenKinds.auth]: Infinity,
5152
[tokenKinds.team]: Infinity,
5253
[tokenKinds.verify]: config.loginTimeout,
@@ -55,7 +56,7 @@ const tokenExpiries = {
5556

5657
const timeNow = () => Math.floor(Date.now() / 1000)
5758

58-
const encryptToken = async (content: unknown): Promise<string> => {
59+
const encryptToken = async <Kind extends tokenKinds>(content: InternalTokenData<Kind>): Promise<Token> => {
5960
const iv = await randomBytes(12)
6061
const cipher = crypto.createCipheriv('aes-256-gcm', tokenKey, iv)
6162
const cipherText = cipher.update(JSON.stringify(content))
@@ -64,7 +65,7 @@ const encryptToken = async (content: unknown): Promise<string> => {
6465
return tokenContent.toString('base64')
6566
}
6667

67-
const decryptToken = async (token: string): Promise<unknown | null> => {
68+
const decryptToken = async <Kind extends tokenKinds>(token: Token): Promise<InternalTokenData<Kind> | null> => {
6869
try {
6970
const tokenContent = Buffer.from(token, 'base64')
7071
const iv = tokenContent.slice(0, 12)
@@ -73,14 +74,14 @@ const decryptToken = async (token: string): Promise<unknown | null> => {
7374
cipher.setAuthTag(authTag)
7475
const plainText = cipher.update(tokenContent.slice(12, tokenContent.length - 16))
7576
cipher.final()
76-
return JSON.parse(plainText.toString())
77+
return JSON.parse(plainText.toString()) as InternalTokenData<Kind>
7778
} catch (e) {
7879
return null
7980
}
8081
}
8182

8283
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)
8485
if (content === null) {
8586
return null
8687
}
@@ -99,6 +100,6 @@ export const getToken = async <Kind extends tokenKinds>(tokenKind: Kind, data: T
99100
k: tokenKind,
100101
t: timeNow(),
101102
d: data
102-
}) as Token
103+
})
103104
return token
104105
}

0 commit comments

Comments
 (0)