@stacksjs/auth 0.69.2 → 0.70.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authentication.d.ts +100 -30
- package/dist/index.js +1122 -1163
- package/package.json +4 -4
package/dist/authentication.d.ts
CHANGED
|
@@ -1,45 +1,114 @@
|
|
|
1
|
+
import type { UserModel, UsersTable } from '../../../orm/src/models/User';
|
|
2
|
+
|
|
1
3
|
declare interface Credentials {
|
|
2
4
|
password: string | undefined
|
|
5
|
+
email: string | undefined
|
|
3
6
|
[key: string]: string | undefined
|
|
4
7
|
}
|
|
5
8
|
declare type AuthToken = `${number}:${number}:${string}`
|
|
6
9
|
|
|
7
10
|
const authConfig = { username: 'email', password: 'password' }
|
|
8
11
|
|
|
9
|
-
let authUser:
|
|
12
|
+
let authUser: UserModel | null = null
|
|
10
13
|
|
|
11
14
|
export async function attempt(credentials: Credentials): Promise<boolean> {
|
|
12
15
|
let hashCheck = false
|
|
13
16
|
|
|
14
|
-
const user = await User.where(authConfig.username, credentials[authConfig.username]).first()
|
|
17
|
+
const user = await User.where(authConfig.username as keyof UsersTable, credentials[authConfig.username]).first()
|
|
15
18
|
const authPass = credentials[authConfig.password]
|
|
16
19
|
|
|
17
20
|
if (typeof authPass === 'string' && user?.password)
|
|
18
|
-
hashCheck = await verifyHash(authPass, user
|
|
19
|
-
|
|
20
|
-
if (hashCheck) {
|
|
21
|
-
if (user) {
|
|
22
|
-
authUser = user
|
|
21
|
+
hashCheck = await verifyHash(authPass, user.password, 'bcrypt')
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
if (hashCheck && user) {
|
|
24
|
+
authUser = user
|
|
25
|
+
return true
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
return false
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
export async function createAccessToken(user: UserModel, teamId?: number): Promise<AuthToken> {
|
|
32
|
+
const token = randomBytes(40).toString('hex')
|
|
33
|
+
|
|
34
|
+
const accessToken = await AccessToken.create({
|
|
35
|
+
team_id: teamId,
|
|
36
|
+
token,
|
|
37
|
+
name: 'auth-token',
|
|
38
|
+
expires_at: new Date(Date.now() + 1000 * 60 * 60 * 24 * 30),
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
if (!accessToken?.id)
|
|
42
|
+
throw new HttpError(500, 'Failed to create access token')
|
|
43
|
+
|
|
44
|
+
return `${accessToken.id}:${teamId || 0}:${token}`
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export async function login(credentials: Credentials): Promise<{ token: AuthToken } | null> {
|
|
48
|
+
const isValid = await attempt(credentials)
|
|
49
|
+
|
|
50
|
+
if (!isValid || !authUser)
|
|
51
|
+
return null
|
|
52
|
+
|
|
53
|
+
const teams = await authUser.userTeams()
|
|
54
|
+
const primaryTeam = teams[0]
|
|
55
|
+
|
|
56
|
+
const token = await createAccessToken(authUser, primaryTeam?.id)
|
|
57
|
+
return { token }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export async function validateToken(token: string): Promise<boolean> {
|
|
61
|
+
const parts = token.split(':')
|
|
62
|
+
|
|
63
|
+
if (parts.length !== 3)
|
|
64
|
+
return false
|
|
65
|
+
|
|
66
|
+
const [tokenId, teamId, plainToken] = parts
|
|
67
|
+
|
|
68
|
+
const accessToken = await AccessToken.where('id', Number(tokenId))
|
|
69
|
+
.where('token', plainToken)
|
|
70
|
+
.where('team_id', Number(teamId))
|
|
71
|
+
.first()
|
|
72
|
+
|
|
73
|
+
if (!accessToken)
|
|
74
|
+
return false
|
|
75
|
+
|
|
76
|
+
if (accessToken.expires_at && new Date(accessToken.expires_at) < new Date())
|
|
77
|
+
return false
|
|
78
|
+
|
|
79
|
+
await AccessToken.where('id', accessToken.id).update({
|
|
80
|
+
last_used_at: new Date(),
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
return true
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export async function getUserFromToken(token: string): Promise<UserModel | undefined> {
|
|
87
|
+
const parts = token.split(':')
|
|
88
|
+
|
|
89
|
+
if (parts.length !== 3)
|
|
90
|
+
return undefined
|
|
91
|
+
|
|
92
|
+
const [tokenId] = parts
|
|
93
|
+
|
|
94
|
+
const accessToken = await AccessToken.where('id', Number(tokenId)).first()
|
|
95
|
+
|
|
96
|
+
if (!accessToken?.user_id)
|
|
97
|
+
return undefined
|
|
98
|
+
|
|
99
|
+
return await User.find(accessToken.user_id)
|
|
100
|
+
}
|
|
101
|
+
|
|
31
102
|
export async function team(): Promise<TeamModel | undefined> {
|
|
32
103
|
if (authUser) {
|
|
33
104
|
const teams = await authUser.userTeams()
|
|
34
|
-
|
|
35
|
-
return teams[0].team
|
|
105
|
+
return teams[0]
|
|
36
106
|
}
|
|
37
107
|
|
|
38
108
|
const bearerToken = request.bearerToken()
|
|
39
109
|
|
|
40
|
-
if (!bearerToken)
|
|
110
|
+
if (!bearerToken)
|
|
41
111
|
return undefined
|
|
42
|
-
}
|
|
43
112
|
|
|
44
113
|
const parts = bearerToken.split(':')
|
|
45
114
|
|
|
@@ -50,31 +119,32 @@ export async function team(): Promise<TeamModel | undefined> {
|
|
|
50
119
|
const teamId = parts[1]
|
|
51
120
|
const plainString = parts[2]
|
|
52
121
|
|
|
53
|
-
const accessToken = await AccessToken.where('id', Number(tokenId))
|
|
122
|
+
const accessToken = await AccessToken.where('id', Number(tokenId))
|
|
123
|
+
.where('token', plainString)
|
|
124
|
+
.first()
|
|
54
125
|
|
|
55
|
-
if (Number(teamId) !== Number(accessToken?.team_id))
|
|
126
|
+
if (Number(teamId) !== Number(accessToken?.team_id))
|
|
56
127
|
return undefined
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const team = await Team.find(Number(accessToken?.team_id))
|
|
60
128
|
|
|
61
|
-
return
|
|
129
|
+
return await Team.find(Number(accessToken?.team_id))
|
|
62
130
|
}
|
|
63
131
|
|
|
64
|
-
export async function
|
|
65
|
-
|
|
66
|
-
const teams = await authUser.userTeams()
|
|
132
|
+
export async function revokeToken(token: string): Promise<void> {
|
|
133
|
+
const parts = token.split(':')
|
|
67
134
|
|
|
68
|
-
|
|
135
|
+
if (parts.length !== 3)
|
|
136
|
+
return
|
|
69
137
|
|
|
70
|
-
|
|
71
|
-
const accessToken = accessTokens[0]
|
|
138
|
+
const [tokenId] = parts
|
|
72
139
|
|
|
73
|
-
|
|
140
|
+
await AccessToken.where('id', Number(tokenId)).delete()
|
|
141
|
+
}
|
|
74
142
|
|
|
75
|
-
|
|
76
|
-
|
|
143
|
+
export async function logout(): Promise<void> {
|
|
144
|
+
const bearerToken = request.bearerToken()
|
|
77
145
|
|
|
78
|
-
|
|
79
|
-
|
|
146
|
+
if (bearerToken)
|
|
147
|
+
await revokeToken(bearerToken)
|
|
148
|
+
|
|
149
|
+
authUser = null
|
|
80
150
|
}
|