@stacksjs/auth 0.70.258 → 0.70.259

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/token.js CHANGED
@@ -1,21 +1 @@
1
- import { Buffer } from "node:buffer";
2
- import { createHmac, randomBytes } from "node:crypto";
3
- import process from "node:process";
4
-
5
- export class TokenManager {
6
- static generateJWT(userId, expiresInSeconds = 3600) {
7
- const appKey = process.env.APP_KEY;
8
- if (!appKey)
9
- throw Error("APP_KEY is not set. JWT tokens cannot be generated without a secure application key.");
10
- const header = {
11
- alg: "HS256",
12
- typ: "JWT"
13
- }, nowSeconds = Math.floor(Date.now() / 1000), payload = {
14
- sub: userId,
15
- iat: nowSeconds,
16
- exp: nowSeconds + expiresInSeconds,
17
- jti: randomBytes(16).toString("hex")
18
- }, encodedHeader = Buffer.from(JSON.stringify(header)).toString("base64url"), encodedPayload = Buffer.from(JSON.stringify(payload)).toString("base64url"), signature = createHmac("sha256", appKey).update(`${encodedHeader}.${encodedPayload}`).digest("base64url");
19
- return `${encodedHeader}.${encodedPayload}.${signature}`;
20
- }
21
- }
1
+ import{Buffer}from"node:buffer";import{createHmac,randomBytes}from"node:crypto";import process from"node:process";export class TokenManager{static generateJWT(userId,expiresInSeconds=3600){const appKey=process.env.APP_KEY;if(!appKey)throw Error("APP_KEY is not set. JWT tokens cannot be generated without a secure application key.");const header={alg:"HS256",typ:"JWT"},nowSeconds=Math.floor(Date.now()/1000),payload={sub:userId,iat:nowSeconds,exp:nowSeconds+expiresInSeconds,jti:randomBytes(16).toString("hex")},encodedHeader=Buffer.from(JSON.stringify(header)).toString("base64url"),encodedPayload=Buffer.from(JSON.stringify(payload)).toString("base64url"),signature=createHmac("sha256",appKey).update(`${encodedHeader}.${encodedPayload}`).digest("base64url");return`${encodedHeader}.${encodedPayload}.${signature}`}}
package/dist/tokens.js CHANGED
@@ -1,209 +1,35 @@
1
- import process from "node:process";
2
- import { createHash, randomBytes } from "node:crypto";
3
- import { db } from "@stacksjs/database";
4
- import { HttpError } from "@stacksjs/error-handling";
5
- import { getCurrentRequest } from "@stacksjs/router";
6
- import { env } from "@stacksjs/env";
7
- import { parseSqlDateTime, sqlDateTime, sqlDateTimeLiteral, sqlHelpers } from "@stacksjs/database";
8
- const dbDriver = env.DB_CONNECTION || "sqlite", sql = sqlHelpers(dbDriver), { isPostgres, isMysql, now, boolTrue, boolFalse } = sql;
9
- function appNow() {
10
- return sqlDateTimeLiteral();
11
- }
12
- function param(index) {
13
- return sql.param(index);
14
- }
15
- function hashToken(token) {
16
- return createHash("sha256").update(token).digest("hex");
17
- }
18
- function bearerLookupHash(bearer) {
19
- const colonIdx = bearer.indexOf(":"), lookup = colonIdx === -1 ? bearer : bearer.substring(0, colonIdx);
20
- return hashToken(lookup);
21
- }
22
- function generateSecureToken(bytes = 40) {
23
- return randomBytes(bytes).toString("hex");
24
- }
25
- export async function getPasswordChangedAt(userId, q = db) {
26
- if (userId === null || userId === void 0)
27
- return null;
28
- try {
29
- const value = (await q.unsafe(`
1
+ import process from"node:process";import{createHash,randomBytes}from"node:crypto";import{db}from"@stacksjs/database";import{HttpError}from"@stacksjs/error-handling";import{getCurrentRequest}from"@stacksjs/router";import{env}from"@stacksjs/env";import{parseSqlDateTime,sqlDateTime,sqlDateTimeLiteral,sqlHelpers}from"@stacksjs/database";const dbDriver=env.DB_CONNECTION||"sqlite",sql=sqlHelpers(dbDriver),{isPostgres,isMysql,now,boolTrue,boolFalse}=sql;function appNow(){return sqlDateTimeLiteral()}function param(index){return sql.param(index)}function hashToken(token){return createHash("sha256").update(token).digest("hex")}function bearerLookupHash(bearer){const colonIdx=bearer.indexOf(":"),lookup=colonIdx===-1?bearer:bearer.substring(0,colonIdx);return hashToken(lookup)}function generateSecureToken(bytes=40){return randomBytes(bytes).toString("hex")}export async function getPasswordChangedAt(userId,q=db){if(userId===null||userId===void 0)return null;try{const value=(await q.unsafe(`
30
2
  SELECT password_changed_at FROM users WHERE id = ${param(1)} LIMIT 1
31
- `, [userId]))[0]?.password_changed_at;
32
- if (value === null || value === void 0)
33
- return null;
34
- return parseSqlDateTime(value);
35
- } catch {
36
- return null;
37
- }
38
- }
39
- export function isIssuedBeforePasswordChange(createdAt, changedAt) {
40
- if (!changedAt)
41
- return !1;
42
- if (createdAt === null || createdAt === void 0)
43
- return !1;
44
- const created = parseSqlDateTime(createdAt);
45
- if (!created)
46
- return !1;
47
- return created.getTime() < changedAt.getTime();
48
- }
49
- export async function tokens(userId) {
50
- return (await db.unsafe(`
3
+ `,[userId]))[0]?.password_changed_at;if(value===null||value===void 0)return null;return parseSqlDateTime(value)}catch{return null}}export function isIssuedBeforePasswordChange(createdAt,changedAt){if(!changedAt)return!1;if(createdAt===null||createdAt===void 0)return!1;const created=parseSqlDateTime(createdAt);if(!created)return!1;return created.getTime()<changedAt.getTime()}export async function tokens(userId){return(await db.unsafe(`
51
4
  SELECT t.*, c.provider as client_provider
52
5
  FROM oauth_access_tokens t
53
6
  LEFT JOIN oauth_clients c ON t.oauth_client_id = c.id
54
7
  WHERE t.user_id = ${param(1)}
55
8
  AND t.revoked = ${boolFalse}
56
9
  ORDER BY t.created_at DESC
57
- `, [userId])).map((row) => ({
58
- id: row.id,
59
- userId: row.user_id,
60
- clientId: row.oauth_client_id,
61
- name: row.name || "access-token",
62
- scopes: parseScopes(row.scopes),
63
- revoked: !!row.revoked,
64
- expiresAt: row.expires_at ? new Date(row.expires_at) : null,
65
- createdAt: new Date(row.created_at),
66
- updatedAt: row.updated_at ? new Date(row.updated_at) : new Date
67
- }));
68
- }
69
- export async function findToken(plainTextToken) {
70
- const hashedToken = bearerLookupHash(plainTextToken), row = (await db.unsafe(`
10
+ `,[userId])).map((row)=>({id:row.id,userId:row.user_id,clientId:row.oauth_client_id,name:row.name||"access-token",scopes:parseScopes(row.scopes),revoked:!!row.revoked,expiresAt:row.expires_at?new Date(row.expires_at):null,createdAt:new Date(row.created_at),updatedAt:row.updated_at?new Date(row.updated_at):new Date}))}export async function findToken(plainTextToken){const hashedToken=bearerLookupHash(plainTextToken),row=(await db.unsafe(`
71
11
  SELECT * FROM oauth_access_tokens
72
12
  WHERE token = ${param(1)}
73
13
  AND revoked = ${boolFalse}
74
14
  AND (expires_at IS NULL OR expires_at > ${appNow()})
75
15
  LIMIT 1
76
- `, [hashedToken]))[0];
77
- if (!row)
78
- return null;
79
- if (isIssuedBeforePasswordChange(row.created_at, await getPasswordChangedAt(row.user_id)))
80
- return null;
81
- return {
82
- id: row.id,
83
- userId: row.user_id,
84
- clientId: row.oauth_client_id,
85
- name: row.name || "access-token",
86
- scopes: parseScopes(row.scopes),
87
- revoked: !!row.revoked,
88
- expiresAt: row.expires_at ? new Date(row.expires_at) : null,
89
- createdAt: new Date(row.created_at),
90
- updatedAt: row.updated_at ? new Date(row.updated_at) : new Date
91
- };
92
- }
93
- export async function currentAccessToken() {
94
- const request = getCurrentRequest();
95
- if (!request)
96
- return null;
97
- const attached = request._currentAccessToken;
98
- if (attached)
99
- return attached;
100
- const bearerToken = request.bearerToken?.();
101
- if (!bearerToken)
102
- return null;
103
- const token = await findToken(bearerToken);
104
- if (token)
105
- request._currentAccessToken = token;
106
- return token;
107
- }
108
- export const token = currentAccessToken;
109
- export async function tokenCan(scope) {
110
- const accessToken = await currentAccessToken();
111
- if (!accessToken)
112
- return !1;
113
- if (accessToken.scopes.includes("*"))
114
- return !0;
115
- return accessToken.scopes.includes(scope);
116
- }
117
- export async function tokenCant(scope) {
118
- return !await tokenCan(scope);
119
- }
120
- export async function tokenCanAll(scopes) {
121
- const accessToken = await currentAccessToken();
122
- if (!accessToken)
123
- return !1;
124
- if (accessToken.scopes.includes("*"))
125
- return !0;
126
- return scopes.every((scope) => accessToken.scopes.includes(scope));
127
- }
128
- export async function tokenCanAny(scopes) {
129
- const accessToken = await currentAccessToken();
130
- if (!accessToken)
131
- return !1;
132
- if (accessToken.scopes.includes("*"))
133
- return !0;
134
- return scopes.some((scope) => accessToken.scopes.includes(scope));
135
- }
136
- export async function tokenAbilities() {
137
- return (await currentAccessToken())?.scopes || [];
138
- }
139
- export async function createToken(userId, name = "access-token", scopes = ["*"], options = {}) {
140
- const {
141
- expiresInMinutes = 60,
142
- withRefreshToken = !0,
143
- refreshExpiresInDays = 30
144
- } = options, client = (await db.unsafe(`
16
+ `,[hashedToken]))[0];if(!row)return null;if(isIssuedBeforePasswordChange(row.created_at,await getPasswordChangedAt(row.user_id)))return null;return{id:row.id,userId:row.user_id,clientId:row.oauth_client_id,name:row.name||"access-token",scopes:parseScopes(row.scopes),revoked:!!row.revoked,expiresAt:row.expires_at?new Date(row.expires_at):null,createdAt:new Date(row.created_at),updatedAt:row.updated_at?new Date(row.updated_at):new Date}}export async function currentAccessToken(){const request=getCurrentRequest();if(!request)return null;const attached=request._currentAccessToken;if(attached)return attached;const bearerToken=request.bearerToken?.();if(!bearerToken)return null;const token=await findToken(bearerToken);if(token)request._currentAccessToken=token;return token}export const token=currentAccessToken;export async function tokenCan(scope){const accessToken=await currentAccessToken();if(!accessToken)return!1;if(accessToken.scopes.includes("*"))return!0;return accessToken.scopes.includes(scope)}export async function tokenCant(scope){return!await tokenCan(scope)}export async function tokenCanAll(scopes){const accessToken=await currentAccessToken();if(!accessToken)return!1;if(accessToken.scopes.includes("*"))return!0;return scopes.every((scope)=>accessToken.scopes.includes(scope))}export async function tokenCanAny(scopes){const accessToken=await currentAccessToken();if(!accessToken)return!1;if(accessToken.scopes.includes("*"))return!0;return scopes.some((scope)=>accessToken.scopes.includes(scope))}export async function tokenAbilities(){return(await currentAccessToken())?.scopes||[]}export async function createToken(userId,name="access-token",scopes=["*"],options={}){const{expiresInMinutes=60,withRefreshToken=!0,refreshExpiresInDays=30}=options,client=(await db.unsafe(`
145
17
  SELECT id FROM oauth_clients WHERE personal_access_client = ${boolTrue} LIMIT 1
146
- `))[0];
147
- if (!client)
148
- throw new HttpError(500, "No personal access client found. Run ./buddy auth:setup first.");
149
- const plainTextToken = generateSecureToken(40), hashedToken = hashToken(plainTextToken), expiresAt = new Date;
150
- expiresAt.setMinutes(expiresAt.getMinutes() + expiresInMinutes);
151
- if (isPostgres)
152
- await db.unsafe(`
18
+ `))[0];if(!client)throw new HttpError(500,"No personal access client found. Run ./buddy auth:setup first.");const plainTextToken=generateSecureToken(40),hashedToken=hashToken(plainTextToken),expiresAt=new Date;expiresAt.setMinutes(expiresAt.getMinutes()+expiresInMinutes);if(isPostgres)await db.unsafe(`
153
19
  INSERT INTO oauth_access_tokens (user_id, oauth_client_id, token, name, scopes, revoked, expires_at, created_at, updated_at)
154
20
  VALUES ($1, $2, $3, $4, $5, false, $6, ${appNow()}, ${appNow()})
155
- `, [userId, client.id, hashedToken, name, JSON.stringify(scopes), sqlDateTime(expiresAt)]);
156
- else
157
- await db.unsafe(`
21
+ `,[userId,client.id,hashedToken,name,JSON.stringify(scopes),sqlDateTime(expiresAt)]);else await db.unsafe(`
158
22
  INSERT INTO oauth_access_tokens (user_id, oauth_client_id, token, name, scopes, revoked, expires_at, created_at, updated_at)
159
23
  VALUES (?, ?, ?, ?, ?, 0, ?, ${appNow()}, ${appNow()})
160
- `, [userId, client.id, hashedToken, name, JSON.stringify(scopes), sqlDateTime(expiresAt)]);
161
- const row = (await db.unsafe(`
24
+ `,[userId,client.id,hashedToken,name,JSON.stringify(scopes),sqlDateTime(expiresAt)]);const row=(await db.unsafe(`
162
25
  SELECT * FROM oauth_access_tokens WHERE token = ${param(1)} LIMIT 1
163
- `, [hashedToken]))[0];
164
- if (!row)
165
- throw new HttpError(500, "Failed to create access token \u2014 inserted row not found");
166
- const accessToken = {
167
- id: row.id,
168
- userId: row.user_id,
169
- clientId: row.oauth_client_id,
170
- name: row.name,
171
- scopes: parseScopes(row.scopes),
172
- revoked: !1,
173
- expiresAt,
174
- createdAt: new Date(row.created_at),
175
- updatedAt: new Date(row.updated_at)
176
- };
177
- let refreshTokenPlain;
178
- if (withRefreshToken) {
179
- refreshTokenPlain = generateSecureToken(40);
180
- const hashedRefreshToken = hashToken(refreshTokenPlain), refreshExpiresAt = new Date;
181
- refreshExpiresAt.setDate(refreshExpiresAt.getDate() + refreshExpiresInDays);
182
- if (isPostgres)
183
- await db.unsafe(`
26
+ `,[hashedToken]))[0];if(!row)throw new HttpError(500,"Failed to create access token \u2014 inserted row not found");const accessToken={id:row.id,userId:row.user_id,clientId:row.oauth_client_id,name:row.name,scopes:parseScopes(row.scopes),revoked:!1,expiresAt,createdAt:new Date(row.created_at),updatedAt:new Date(row.updated_at)};let refreshTokenPlain;if(withRefreshToken){refreshTokenPlain=generateSecureToken(40);const hashedRefreshToken=hashToken(refreshTokenPlain),refreshExpiresAt=new Date;refreshExpiresAt.setDate(refreshExpiresAt.getDate()+refreshExpiresInDays);if(isPostgres)await db.unsafe(`
184
27
  INSERT INTO oauth_refresh_tokens (access_token_id, token, revoked, expires_at, created_at)
185
28
  VALUES ($1, $2, false, $3, ${appNow()})
186
- `, [accessToken.id, hashedRefreshToken, sqlDateTime(refreshExpiresAt)]);
187
- else
188
- await db.unsafe(`
29
+ `,[accessToken.id,hashedRefreshToken,sqlDateTime(refreshExpiresAt)]);else await db.unsafe(`
189
30
  INSERT INTO oauth_refresh_tokens (access_token_id, token, revoked, expires_at, created_at)
190
31
  VALUES (?, ?, 0, ?, ${appNow()})
191
- `, [accessToken.id, hashedRefreshToken, sqlDateTime(refreshExpiresAt)]);
192
- }
193
- return {
194
- accessToken,
195
- plainTextToken,
196
- refreshToken: refreshTokenPlain,
197
- expiresIn: expiresInMinutes * 60
198
- };
199
- }
200
- export async function refreshToken(refreshTokenPlain, options = {}) {
201
- const {
202
- expiresInMinutes = 60,
203
- refreshExpiresInDays = 30
204
- } = options, hashedRefreshToken = hashToken(refreshTokenPlain);
205
- return await db.transaction(async (rawTrx) => {
206
- const trx = rawTrx, forUpdate = isPostgres || isMysql ? " FOR UPDATE" : "", refreshRow = (await trx.unsafe(`
32
+ `,[accessToken.id,hashedRefreshToken,sqlDateTime(refreshExpiresAt)])}return{accessToken,plainTextToken,refreshToken:refreshTokenPlain,expiresIn:expiresInMinutes*60}}export async function refreshToken(refreshTokenPlain,options={}){const{expiresInMinutes=60,refreshExpiresInDays=30}=options,hashedRefreshToken=hashToken(refreshTokenPlain);return await db.transaction(async(rawTrx)=>{const trx=rawTrx,forUpdate=isPostgres||isMysql?" FOR UPDATE":"",refreshRow=(await trx.unsafe(`
207
33
  SELECT r.*, t.user_id, t.oauth_client_id, t.name, t.scopes
208
34
  FROM oauth_refresh_tokens r
209
35
  JOIN oauth_access_tokens t ON r.access_token_id = t.id
@@ -211,281 +37,124 @@ export async function refreshToken(refreshTokenPlain, options = {}) {
211
37
  AND r.revoked = ${boolFalse}
212
38
  AND (r.expires_at IS NULL OR r.expires_at > ${appNow()})
213
39
  LIMIT 1${forUpdate}
214
- `, [hashedRefreshToken]))[0];
215
- if (!refreshRow)
216
- throw new HttpError(401, "Invalid or expired refresh token");
217
- if (isIssuedBeforePasswordChange(refreshRow.created_at, await getPasswordChangedAt(refreshRow.user_id, trx)))
218
- throw new HttpError(401, "Invalid or expired refresh token");
219
- await trx.unsafe(`
40
+ `,[hashedRefreshToken]))[0];if(!refreshRow)throw new HttpError(401,"Invalid or expired refresh token");if(isIssuedBeforePasswordChange(refreshRow.created_at,await getPasswordChangedAt(refreshRow.user_id,trx)))throw new HttpError(401,"Invalid or expired refresh token");await trx.unsafe(`
220
41
  UPDATE oauth_refresh_tokens
221
42
  SET revoked = ${boolTrue}
222
43
  WHERE id = ${param(1)}
223
- `, [refreshRow.id]);
224
- await trx.unsafe(`
44
+ `,[refreshRow.id]);await trx.unsafe(`
225
45
  UPDATE oauth_access_tokens
226
46
  SET revoked = ${boolTrue}
227
47
  WHERE id = ${param(1)}
228
- `, [refreshRow.access_token_id]);
229
- const plainTextToken = generateSecureToken(40), hashedToken = hashToken(plainTextToken), expiresAt = new Date;
230
- expiresAt.setMinutes(expiresAt.getMinutes() + expiresInMinutes);
231
- if (isPostgres)
232
- await trx.unsafe(`
48
+ `,[refreshRow.access_token_id]);const plainTextToken=generateSecureToken(40),hashedToken=hashToken(plainTextToken),expiresAt=new Date;expiresAt.setMinutes(expiresAt.getMinutes()+expiresInMinutes);if(isPostgres)await trx.unsafe(`
233
49
  INSERT INTO oauth_access_tokens (user_id, oauth_client_id, token, name, scopes, revoked, expires_at, created_at, updated_at)
234
50
  VALUES ($1, $2, $3, $4, $5, false, $6, ${appNow()}, ${appNow()})
235
- `, [refreshRow.user_id, refreshRow.oauth_client_id, hashedToken, refreshRow.name, refreshRow.scopes, sqlDateTime(expiresAt)]);
236
- else
237
- await trx.unsafe(`
51
+ `,[refreshRow.user_id,refreshRow.oauth_client_id,hashedToken,refreshRow.name,refreshRow.scopes,sqlDateTime(expiresAt)]);else await trx.unsafe(`
238
52
  INSERT INTO oauth_access_tokens (user_id, oauth_client_id, token, name, scopes, revoked, expires_at, created_at, updated_at)
239
53
  VALUES (?, ?, ?, ?, ?, 0, ?, ${appNow()}, ${appNow()})
240
- `, [refreshRow.user_id, refreshRow.oauth_client_id, hashedToken, refreshRow.name, refreshRow.scopes, sqlDateTime(expiresAt)]);
241
- const row = (await trx.unsafe(`
54
+ `,[refreshRow.user_id,refreshRow.oauth_client_id,hashedToken,refreshRow.name,refreshRow.scopes,sqlDateTime(expiresAt)]);const row=(await trx.unsafe(`
242
55
  SELECT * FROM oauth_access_tokens WHERE token = ${param(1)} LIMIT 1
243
- `, [hashedToken]))[0], accessToken = {
244
- id: row.id,
245
- userId: row.user_id,
246
- clientId: row.oauth_client_id,
247
- name: row.name,
248
- scopes: parseScopes(row.scopes),
249
- revoked: !1,
250
- expiresAt,
251
- createdAt: new Date(row.created_at),
252
- updatedAt: new Date(row.updated_at)
253
- };
254
- if (isIssuedBeforePasswordChange(row.created_at, await getPasswordChangedAt(refreshRow.user_id, trx)))
255
- throw new HttpError(401, "Invalid or expired refresh token");
256
- const newRefreshTokenPlain = generateSecureToken(40), newHashedRefreshToken = hashToken(newRefreshTokenPlain), refreshExpiresAt = new Date;
257
- refreshExpiresAt.setDate(refreshExpiresAt.getDate() + refreshExpiresInDays);
258
- if (isPostgres)
259
- await trx.unsafe(`
56
+ `,[hashedToken]))[0],accessToken={id:row.id,userId:row.user_id,clientId:row.oauth_client_id,name:row.name,scopes:parseScopes(row.scopes),revoked:!1,expiresAt,createdAt:new Date(row.created_at),updatedAt:new Date(row.updated_at)};if(isIssuedBeforePasswordChange(row.created_at,await getPasswordChangedAt(refreshRow.user_id,trx)))throw new HttpError(401,"Invalid or expired refresh token");const newRefreshTokenPlain=generateSecureToken(40),newHashedRefreshToken=hashToken(newRefreshTokenPlain),refreshExpiresAt=new Date;refreshExpiresAt.setDate(refreshExpiresAt.getDate()+refreshExpiresInDays);if(isPostgres)await trx.unsafe(`
260
57
  INSERT INTO oauth_refresh_tokens (access_token_id, token, revoked, expires_at, created_at)
261
58
  VALUES ($1, $2, false, $3, ${appNow()})
262
- `, [accessToken.id, newHashedRefreshToken, sqlDateTime(refreshExpiresAt)]);
263
- else
264
- await trx.unsafe(`
59
+ `,[accessToken.id,newHashedRefreshToken,sqlDateTime(refreshExpiresAt)]);else await trx.unsafe(`
265
60
  INSERT INTO oauth_refresh_tokens (access_token_id, token, revoked, expires_at, created_at)
266
61
  VALUES (?, ?, 0, ?, ${appNow()})
267
- `, [accessToken.id, newHashedRefreshToken, sqlDateTime(refreshExpiresAt)]);
268
- return {
269
- accessToken,
270
- plainTextToken,
271
- refreshToken: newRefreshTokenPlain,
272
- expiresIn: expiresInMinutes * 60
273
- };
274
- });
275
- }
276
- export async function validateRefreshToken(refreshTokenPlain) {
277
- const hashedRefreshToken = hashToken(refreshTokenPlain);
278
- return (await db.unsafe(`
62
+ `,[accessToken.id,newHashedRefreshToken,sqlDateTime(refreshExpiresAt)]);return{accessToken,plainTextToken,refreshToken:newRefreshTokenPlain,expiresIn:expiresInMinutes*60}})}export async function validateRefreshToken(refreshTokenPlain){const hashedRefreshToken=hashToken(refreshTokenPlain);return(await db.unsafe(`
279
63
  SELECT id FROM oauth_refresh_tokens
280
64
  WHERE token = ${param(1)}
281
65
  AND revoked = ${boolFalse}
282
66
  AND (expires_at IS NULL OR expires_at > ${appNow()})
283
67
  LIMIT 1
284
- `, [hashedRefreshToken])).length > 0;
285
- }
286
- export async function revokeRefreshToken(refreshTokenPlain) {
287
- const hashedRefreshToken = hashToken(refreshTokenPlain);
288
- await db.unsafe(`
68
+ `,[hashedRefreshToken])).length>0}export async function revokeRefreshToken(refreshTokenPlain){const hashedRefreshToken=hashToken(refreshTokenPlain);await db.unsafe(`
289
69
  UPDATE oauth_refresh_tokens
290
70
  SET revoked = ${boolTrue}
291
71
  WHERE token = ${param(1)}
292
- `, [hashedRefreshToken]);
293
- }
294
- export async function revokeAllRefreshTokens(userId) {
295
- await db.unsafe(`
72
+ `,[hashedRefreshToken])}export async function revokeAllRefreshTokens(userId){await db.unsafe(`
296
73
  UPDATE oauth_refresh_tokens
297
74
  SET revoked = ${boolTrue}
298
75
  WHERE access_token_id IN (
299
76
  SELECT id FROM oauth_access_tokens WHERE user_id = ${param(1)}
300
77
  )
301
- `, [userId]);
302
- }
303
- export async function deleteExpiredRefreshTokens() {
304
- const result = await db.unsafe(`
78
+ `,[userId])}export async function deleteExpiredRefreshTokens(){const result=await db.unsafe(`
305
79
  DELETE FROM oauth_refresh_tokens
306
80
  WHERE expires_at < ${appNow()}
307
- `);
308
- return result?.changes || result?.rowCount || 0;
309
- }
310
- export async function deleteRevokedRefreshTokens(daysOld = 7) {
311
- const cutoffDate = new Date;
312
- cutoffDate.setDate(cutoffDate.getDate() - daysOld);
313
- const result = await db.unsafe(`
81
+ `);return result?.changes||result?.rowCount||0}export async function deleteRevokedRefreshTokens(daysOld=7){const cutoffDate=new Date;cutoffDate.setDate(cutoffDate.getDate()-daysOld);const result=await db.unsafe(`
314
82
  DELETE FROM oauth_refresh_tokens
315
83
  WHERE revoked = ${boolTrue} AND created_at < ${param(1)}
316
- `, [sqlDateTime(cutoffDate)]);
317
- return result?.changes || result?.rowCount || 0;
318
- }
319
- export async function revokeToken(plainTextToken) {
320
- const hashedToken = bearerLookupHash(plainTextToken);
321
- await db.unsafe(`
84
+ `,[sqlDateTime(cutoffDate)]);return result?.changes||result?.rowCount||0}export async function revokeToken(plainTextToken){const hashedToken=bearerLookupHash(plainTextToken);await db.unsafe(`
322
85
  UPDATE oauth_refresh_tokens
323
86
  SET revoked = ${boolTrue}
324
87
  WHERE access_token_id IN (
325
88
  SELECT id FROM oauth_access_tokens WHERE token = ${param(1)}
326
89
  )
327
- `, [hashedToken]);
328
- await db.unsafe(`
90
+ `,[hashedToken]);await db.unsafe(`
329
91
  UPDATE oauth_access_tokens
330
92
  SET revoked = ${boolTrue}, updated_at = ${appNow()}
331
93
  WHERE token = ${param(1)}
332
- `, [hashedToken]);
333
- }
334
- export async function revokeTokenById(tokenId) {
335
- await db.unsafe(`
94
+ `,[hashedToken])}export async function revokeTokenById(tokenId){await db.unsafe(`
336
95
  UPDATE oauth_refresh_tokens
337
96
  SET revoked = ${boolTrue}
338
97
  WHERE access_token_id = ${param(1)}
339
- `, [tokenId]);
340
- await db.unsafe(`
98
+ `,[tokenId]);await db.unsafe(`
341
99
  UPDATE oauth_access_tokens
342
100
  SET revoked = ${boolTrue}, updated_at = ${appNow()}
343
101
  WHERE id = ${param(1)}
344
- `, [tokenId]);
345
- }
346
- export async function revokeAllTokens(userId) {
347
- await revokeAllRefreshTokens(userId);
348
- await db.unsafe(`
102
+ `,[tokenId])}export async function revokeAllTokens(userId){await revokeAllRefreshTokens(userId);await db.unsafe(`
349
103
  UPDATE oauth_access_tokens
350
104
  SET revoked = ${boolTrue}, updated_at = ${appNow()}
351
105
  WHERE user_id = ${param(1)}
352
- `, [userId]);
353
- }
354
- export async function revokeOtherTokens(userId) {
355
- const current = await currentAccessToken();
356
- if (!current)
357
- return revokeAllTokens(userId);
358
- if (isPostgres) {
359
- await db.unsafe(`
106
+ `,[userId])}export async function revokeOtherTokens(userId){const current=await currentAccessToken();if(!current)return revokeAllTokens(userId);if(isPostgres){await db.unsafe(`
360
107
  UPDATE oauth_refresh_tokens
361
108
  SET revoked = true
362
109
  WHERE access_token_id IN (
363
110
  SELECT id FROM oauth_access_tokens WHERE user_id = $1 AND id != $2
364
111
  )
365
- `, [userId, current.id]);
366
- await db.unsafe(`
112
+ `,[userId,current.id]);await db.unsafe(`
367
113
  UPDATE oauth_access_tokens
368
114
  SET revoked = true, updated_at = ${appNow()}
369
115
  WHERE user_id = $1 AND id != $2
370
- `, [userId, current.id]);
371
- } else {
372
- await db.unsafe(`
116
+ `,[userId,current.id])}else{await db.unsafe(`
373
117
  UPDATE oauth_refresh_tokens
374
118
  SET revoked = 1
375
119
  WHERE access_token_id IN (
376
120
  SELECT id FROM oauth_access_tokens WHERE user_id = ? AND id != ?
377
121
  )
378
- `, [userId, current.id]);
379
- await db.unsafe(`
122
+ `,[userId,current.id]);await db.unsafe(`
380
123
  UPDATE oauth_access_tokens
381
124
  SET revoked = 1, updated_at = ${appNow()}
382
125
  WHERE user_id = ? AND id != ?
383
- `, [userId, current.id]);
384
- }
385
- }
386
- export async function deleteExpiredTokens() {
387
- await db.unsafe(`
126
+ `,[userId,current.id])}}export async function deleteExpiredTokens(){await db.unsafe(`
388
127
  DELETE FROM oauth_refresh_tokens
389
128
  WHERE access_token_id IN (
390
129
  SELECT id FROM oauth_access_tokens WHERE expires_at < ${appNow()}
391
130
  )
392
- `);
393
- const result = await db.unsafe(`
131
+ `);const result=await db.unsafe(`
394
132
  DELETE FROM oauth_access_tokens
395
133
  WHERE expires_at < ${appNow()}
396
- `);
397
- return result?.changes || result?.rowCount || 0;
398
- }
399
- export async function deleteRevokedTokens(daysOld = 7) {
400
- const cutoffDate = new Date;
401
- cutoffDate.setDate(cutoffDate.getDate() - daysOld);
402
- await db.unsafe(`
134
+ `);return result?.changes||result?.rowCount||0}export async function deleteRevokedTokens(daysOld=7){const cutoffDate=new Date;cutoffDate.setDate(cutoffDate.getDate()-daysOld);await db.unsafe(`
403
135
  DELETE FROM oauth_refresh_tokens
404
136
  WHERE access_token_id IN (
405
137
  SELECT id FROM oauth_access_tokens WHERE revoked = ${boolTrue} AND updated_at < ${param(1)}
406
138
  )
407
- `, [sqlDateTime(cutoffDate)]);
408
- const result = await db.unsafe(`
139
+ `,[sqlDateTime(cutoffDate)]);const result=await db.unsafe(`
409
140
  DELETE FROM oauth_access_tokens
410
141
  WHERE revoked = ${boolTrue} AND updated_at < ${param(1)}
411
- `, [sqlDateTime(cutoffDate)]);
412
- return result?.changes || result?.rowCount || 0;
413
- }
414
- export async function clients(userId) {
415
- return (await db.unsafe(`
142
+ `,[sqlDateTime(cutoffDate)]);return result?.changes||result?.rowCount||0}export async function clients(userId){return(await db.unsafe(`
416
143
  SELECT * FROM oauth_clients
417
144
  WHERE user_id = ${param(1)} AND revoked = ${boolFalse}
418
145
  ORDER BY created_at DESC
419
- `, [userId])).map(mapToOAuthClient);
420
- }
421
- export async function findClient(clientId) {
422
- const row = (await db.unsafe(`
146
+ `,[userId])).map(mapToOAuthClient)}export async function findClient(clientId){const row=(await db.unsafe(`
423
147
  SELECT * FROM oauth_clients WHERE id = ${param(1)} LIMIT 1
424
- `, [clientId]))[0];
425
- return row ? mapToOAuthClient(row) : null;
426
- }
427
- export async function createClient(options) {
428
- const secret = generateSecureToken(40);
429
- if (isPostgres)
430
- await db.unsafe(`
148
+ `,[clientId]))[0];return row?mapToOAuthClient(row):null}export async function createClient(options){const secret=generateSecureToken(40);if(isPostgres)await db.unsafe(`
431
149
  INSERT INTO oauth_clients (name, secret, provider, redirect, personal_access_client, password_client, revoked, created_at)
432
150
  VALUES ($1, $2, 'local', $3, $4, $5, false, ${appNow()})
433
- `, [
434
- options.name,
435
- secret,
436
- options.redirect,
437
- options.personalAccessClient || !1,
438
- options.passwordClient || !1
439
- ]);
440
- else
441
- await db.unsafe(`
151
+ `,[options.name,secret,options.redirect,options.personalAccessClient||!1,options.passwordClient||!1]);else await db.unsafe(`
442
152
  INSERT INTO oauth_clients (name, secret, provider, redirect, personal_access_client, password_client, revoked, created_at)
443
153
  VALUES (?, ?, 'local', ?, ?, ?, 0, ${appNow()})
444
- `, [
445
- options.name,
446
- secret,
447
- options.redirect,
448
- options.personalAccessClient ? 1 : 0,
449
- options.passwordClient ? 1 : 0
450
- ]);
451
- const inserted = await db.unsafe(`
154
+ `,[options.name,secret,options.redirect,options.personalAccessClient?1:0,options.passwordClient?1:0]);const inserted=await db.unsafe(`
452
155
  SELECT * FROM oauth_clients WHERE secret = ${param(1)} LIMIT 1
453
- `, [secret]);
454
- return {
455
- client: mapToOAuthClient(inserted[0]),
456
- plainTextSecret: secret
457
- };
458
- }
459
- export async function revokeClient(clientId) {
460
- await db.unsafe(`
156
+ `,[secret]);return{client:mapToOAuthClient(inserted[0]),plainTextSecret:secret}}export async function revokeClient(clientId){await db.unsafe(`
461
157
  UPDATE oauth_clients
462
158
  SET revoked = ${boolTrue}, updated_at = ${appNow()}
463
159
  WHERE id = ${param(1)}
464
- `, [clientId]);
465
- }
466
- export function parseScopes(scopes) {
467
- if (!scopes)
468
- return [];
469
- if (Array.isArray(scopes))
470
- return scopes;
471
- try {
472
- const parsed = JSON.parse(scopes);
473
- return Array.isArray(parsed) ? parsed : [];
474
- } catch {
475
- return [];
476
- }
477
- }
478
- function mapToOAuthClient(row) {
479
- return {
480
- id: row.id,
481
- name: row.name,
482
- secret: row.secret,
483
- provider: row.provider,
484
- redirect: row.redirect,
485
- personalAccessClient: Boolean(row.personal_access_client),
486
- passwordClient: Boolean(row.password_client),
487
- revoked: Boolean(row.revoked),
488
- createdAt: row.created_at ? new Date(row.created_at) : new Date,
489
- updatedAt: row.updated_at ? new Date(row.updated_at) : null
490
- };
491
- }
160
+ `,[clientId])}export function parseScopes(scopes){if(!scopes)return[];if(Array.isArray(scopes))return scopes;try{const parsed=JSON.parse(scopes);return Array.isArray(parsed)?parsed:[]}catch{return[]}}function mapToOAuthClient(row){return{id:row.id,name:row.name,secret:row.secret,provider:row.provider,redirect:row.redirect,personalAccessClient:Boolean(row.personal_access_client),passwordClient:Boolean(row.password_client),revoked:Boolean(row.revoked),createdAt:row.created_at?new Date(row.created_at):new Date,updatedAt:row.updated_at?new Date(row.updated_at):null}}