@revojs/auth 0.2.65 → 0.3.1
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/index.d.ts +16 -0
- package/dist/index.js +63 -16
- package/dist/module/index.js +0 -1
- package/package.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -185,6 +185,19 @@ export declare function useClientAuth(scope: Scope): {
|
|
|
185
185
|
signOut(): Promise<unknown>;
|
|
186
186
|
};
|
|
187
187
|
export declare function requireAccount(scope: Scope, redirectUrl?: string): Promise<RequiredAccount>;
|
|
188
|
+
export declare function useSessionCookie(scope: Scope): {
|
|
189
|
+
name: string;
|
|
190
|
+
options: {
|
|
191
|
+
domain?: string;
|
|
192
|
+
expires?: Date;
|
|
193
|
+
httpOnly?: boolean;
|
|
194
|
+
maxAge?: number;
|
|
195
|
+
path?: string;
|
|
196
|
+
priority?: import("@revojs/server").CookiePriority;
|
|
197
|
+
sameSite?: import("@revojs/server").CookieSameSite;
|
|
198
|
+
secure: boolean;
|
|
199
|
+
};
|
|
200
|
+
};
|
|
188
201
|
export declare function readSessionCookie(scope: Scope): Promise<Session | undefined>;
|
|
189
202
|
export declare function getSession(scope: Scope): Promise<Session | undefined>;
|
|
190
203
|
export declare function setSession(scope: Scope, session: Session): Promise<void>;
|
|
@@ -235,10 +248,13 @@ export declare function useRoles(): Promise<Map<string, Role>>;
|
|
|
235
248
|
export declare function checkPassword(scope: Scope, account: Account, password: string): Promise<boolean>;
|
|
236
249
|
export declare function hashToken(value: string): Promise<string>;
|
|
237
250
|
export declare function requireOrganization(scope: Scope, organizationId: string, redirectUrl?: string): Promise<Authorization>;
|
|
251
|
+
export declare function requireToken(scope: Scope): Promise<Authorization>;
|
|
252
|
+
export declare function useAuthorization(scope: Scope): Authorization;
|
|
238
253
|
export declare function getPrincipal(scope: Scope, method: Method): Promise<Principal | false | undefined>;
|
|
239
254
|
export declare function createPrincipal(scope: Scope, method: Method): Promise<Principal | undefined>;
|
|
240
255
|
export declare function createSession(scope: Scope, principal: Principal): Promise<Session | undefined>;
|
|
241
256
|
export declare const ACCOUNT_STATE = "auth:account";
|
|
257
|
+
export declare const AUTHORIZATION_CONTEXT: import("revojs").Descriptor<Authorization>;
|
|
242
258
|
export declare const authIdSchema: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MinLengthAction<string, 1, undefined>, import("valibot").MaxLengthAction<string, 128, undefined>]>;
|
|
243
259
|
export declare const organizationNameSchema: import("valibot").SchemaWithPipe<readonly [import("valibot").StringSchema<undefined>, import("valibot").MaxLengthAction<string, 200, undefined>, import("valibot").TrimAction, import("valibot").MinLengthAction<string, 1, undefined>]>;
|
|
244
260
|
export declare const organizationParametersSchema: import("valibot").ObjectSchema<{
|
package/dist/index.js
CHANGED
|
@@ -2,9 +2,9 @@ import config from "#config/auth";
|
|
|
2
2
|
import permissionSources from "#permissions";
|
|
3
3
|
import roleSources from "#roles";
|
|
4
4
|
import { isClient, isServer } from "#variables";
|
|
5
|
-
import { deleteCookie, fetch, getState, sendForbidden, sendRedirect, sendUnauthorized, setCookie, setState, useCookies, useHeaders, useQuery, useUrl, withQuery } from "@revojs/server";
|
|
5
|
+
import { FetchError, deleteCookie, fetch, getState, sendForbidden, sendRedirect, sendUnauthorized, setCookie, setState, useCookies, useHeaders, useQuery, useUrl, withQuery } from "@revojs/server";
|
|
6
6
|
import { useStorageProvider } from "@revojs/storage";
|
|
7
|
-
import { BASE64_DECODE, BASE64_ENCODE, decoder, defineHook, digest, dispatchHook, encoder, equalsConstantTime, hashPassword, isPasswordHash, needsPasswordRehash, sign, verify, verifyPassword } from "revojs";
|
|
7
|
+
import { BASE64_DECODE, BASE64_ENCODE, decoder, defineContext, defineHook, digest, dispatchHook, encoder, equalsConstantTime, hashPassword, isPasswordHash, needsPasswordRehash, requireContext, setContext, sign, verify, verifyPassword } from "revojs";
|
|
8
8
|
import { mergeObjects } from "revojs/shared";
|
|
9
9
|
import { boolean, literal, maxLength, minLength, nullable, nullish, number, object, optional, parse, pipe, string, transform, trim, union } from "valibot";
|
|
10
10
|
//#region src/index.ts
|
|
@@ -38,7 +38,7 @@ async function requireAccount(scope, redirectUrl) {
|
|
|
38
38
|
headers: useHeaders(scope)
|
|
39
39
|
});
|
|
40
40
|
} catch (error) {
|
|
41
|
-
if (redirectUrl && error instanceof
|
|
41
|
+
if (redirectUrl && error instanceof FetchError && error.status === 401) {
|
|
42
42
|
const { pathname } = useUrl(scope);
|
|
43
43
|
if (redirectUrl !== pathname) globalThis.location.href = redirectUrl;
|
|
44
44
|
}
|
|
@@ -51,9 +51,14 @@ async function requireAccount(scope, redirectUrl) {
|
|
|
51
51
|
const cookie = await readSessionCookie(scope);
|
|
52
52
|
if (cookie?.id === resolved.session.id && cookie.accountId === resolved.account.id) return resolved;
|
|
53
53
|
}
|
|
54
|
-
const
|
|
54
|
+
const cookie = await readSessionCookie(scope);
|
|
55
|
+
let session;
|
|
55
56
|
let account;
|
|
56
|
-
if (
|
|
57
|
+
if (cookie) {
|
|
58
|
+
const storage = await useAccountStorage(scope);
|
|
59
|
+
[session, account] = await Promise.all([getSession(scope), storage.getAccountById(cookie.accountId)]);
|
|
60
|
+
}
|
|
61
|
+
if (session?.accountId !== account?.id) account = void 0;
|
|
57
62
|
if (session && account) {
|
|
58
63
|
const result = {
|
|
59
64
|
session,
|
|
@@ -71,8 +76,29 @@ async function requireAccount(scope, redirectUrl) {
|
|
|
71
76
|
}
|
|
72
77
|
throw new Error("Session is unavailable");
|
|
73
78
|
}
|
|
79
|
+
function useSessionCookie(scope) {
|
|
80
|
+
const { name, cookie } = config.session;
|
|
81
|
+
const { hostname } = useUrl(scope);
|
|
82
|
+
const secure = cookie.secure ?? ![
|
|
83
|
+
"localhost",
|
|
84
|
+
"127.0.0.1",
|
|
85
|
+
"[::1]"
|
|
86
|
+
].includes(hostname);
|
|
87
|
+
const options = {
|
|
88
|
+
...cookie,
|
|
89
|
+
secure
|
|
90
|
+
};
|
|
91
|
+
if (secure && cookie.path === "/" && cookie.domain === void 0 && !name.startsWith("__")) return {
|
|
92
|
+
name: `__Host-${name}`,
|
|
93
|
+
options
|
|
94
|
+
};
|
|
95
|
+
return {
|
|
96
|
+
name,
|
|
97
|
+
options
|
|
98
|
+
};
|
|
99
|
+
}
|
|
74
100
|
async function readSessionCookie(scope) {
|
|
75
|
-
const session = useCookies(scope)[
|
|
101
|
+
const session = useCookies(scope)[useSessionCookie(scope).name];
|
|
76
102
|
if (!session) return;
|
|
77
103
|
const index = session.lastIndexOf(".");
|
|
78
104
|
if (index <= 0) return;
|
|
@@ -98,10 +124,12 @@ async function getSession(scope) {
|
|
|
98
124
|
async function setSession(scope, session) {
|
|
99
125
|
const payload = encoder.encode(JSON.stringify(session)).toBase64(BASE64_ENCODE);
|
|
100
126
|
const cookie = payload + "." + await sign(scope, SESSION_PURPOSE, payload);
|
|
101
|
-
|
|
127
|
+
const { name, options } = useSessionCookie(scope);
|
|
128
|
+
setCookie(scope, name, cookie, options);
|
|
102
129
|
}
|
|
103
130
|
function clearSession(scope) {
|
|
104
|
-
|
|
131
|
+
const { name, options } = useSessionCookie(scope);
|
|
132
|
+
deleteCookie(scope, name, options);
|
|
105
133
|
}
|
|
106
134
|
function defineAuthProvider(provider) {
|
|
107
135
|
return { async fetch(scope) {
|
|
@@ -265,50 +293,68 @@ async function requireOrganization(scope, organizationId, redirectUrl) {
|
|
|
265
293
|
permissions: new Set(permissions)
|
|
266
294
|
};
|
|
267
295
|
} catch (error) {
|
|
268
|
-
if (redirectUrl && error instanceof
|
|
296
|
+
if (redirectUrl && error instanceof FetchError && error.status === 401) {
|
|
269
297
|
const { pathname } = useUrl(scope);
|
|
270
298
|
if (redirectUrl !== pathname) globalThis.location.href = redirectUrl;
|
|
271
299
|
}
|
|
272
300
|
throw error;
|
|
273
301
|
}
|
|
302
|
+
return await authorize(scope, organizationId, redirectUrl);
|
|
303
|
+
}
|
|
304
|
+
async function requireToken(scope) {
|
|
305
|
+
if (useHeaders(scope).authorization === void 0) throw sendUnauthorized(scope, void 0, { headers: new Headers({ "WWW-Authenticate": "Bearer" }) });
|
|
306
|
+
return await authorize(scope);
|
|
307
|
+
}
|
|
308
|
+
function useAuthorization(scope) {
|
|
309
|
+
return requireContext(scope, AUTHORIZATION_CONTEXT);
|
|
310
|
+
}
|
|
311
|
+
async function authorize(scope, organizationId, redirectUrl) {
|
|
274
312
|
const storage = await useAuthStorage(scope);
|
|
275
313
|
const header = useHeaders(scope).authorization;
|
|
276
314
|
let account;
|
|
277
315
|
let sessionId;
|
|
278
316
|
let token;
|
|
317
|
+
let organization;
|
|
318
|
+
let membership;
|
|
279
319
|
if (header === void 0) {
|
|
320
|
+
if (organizationId === void 0) throw sendUnauthorized(scope);
|
|
280
321
|
const authenticated = await requireAccount(scope, redirectUrl);
|
|
281
322
|
account = authenticated.account;
|
|
282
323
|
sessionId = authenticated.session.id;
|
|
324
|
+
[organization, membership] = await Promise.all([storage.getOrganization(organizationId), storage.getMembership(organizationId, account.id)]);
|
|
283
325
|
} else {
|
|
284
326
|
const value = /^Bearer ([\w-]{1,256})$/.exec(header)?.[1];
|
|
285
327
|
token = value ? await storage.getTokenByHash(await hashToken(value)) : void 0;
|
|
286
328
|
if (!token || token.expiresAt && token.expiresAt.getTime() <= Date.now()) throw sendUnauthorized(scope);
|
|
287
|
-
if (token.organizationId !== organizationId) throw sendForbidden(scope);
|
|
288
|
-
const stored = await
|
|
329
|
+
if (organizationId !== void 0 && token.organizationId !== organizationId) throw sendForbidden(scope);
|
|
330
|
+
const [stored, found, joined] = await Promise.all([
|
|
331
|
+
storage.getAccountById(token.accountId),
|
|
332
|
+
storage.getOrganization(token.organizationId),
|
|
333
|
+
storage.getMembership(token.organizationId, token.accountId)
|
|
334
|
+
]);
|
|
289
335
|
if (!stored) throw sendUnauthorized(scope);
|
|
290
336
|
account = {
|
|
291
337
|
id: stored.id,
|
|
292
338
|
email: stored.email,
|
|
293
339
|
createdAt: stored.createdAt
|
|
294
340
|
};
|
|
341
|
+
organization = found;
|
|
342
|
+
membership = joined;
|
|
295
343
|
if (!token.lastUsedAt || Date.now() - token.lastUsedAt.getTime() > TOKEN_TOUCH_INTERVAL) await storage.touchToken(token.id, /* @__PURE__ */ new Date());
|
|
296
344
|
}
|
|
297
|
-
const organization = await storage.getOrganization(organizationId);
|
|
298
|
-
const membership = await storage.getMembership(organizationId, account.id);
|
|
299
345
|
if (!organization || membership?.status !== "active") throw sendForbidden(scope);
|
|
300
346
|
let granted = new Array();
|
|
301
347
|
if (organization.accountId === account.id) granted = [...(await usePermissions()).keys()];
|
|
302
348
|
else if (membership.role) granted = (await useRoles()).get(membership.role)?.permissions ?? [];
|
|
303
349
|
const permissions = new Set(granted.filter((permission) => !token || token.permissions.includes(permission)));
|
|
304
|
-
return {
|
|
350
|
+
return setContext(scope, AUTHORIZATION_CONTEXT, {
|
|
305
351
|
account,
|
|
306
352
|
organization,
|
|
307
353
|
membership,
|
|
308
354
|
sessionId,
|
|
309
355
|
tokenId: token?.id,
|
|
310
356
|
permissions
|
|
311
|
-
};
|
|
357
|
+
});
|
|
312
358
|
}
|
|
313
359
|
async function getPrincipal(scope, method) {
|
|
314
360
|
if (method.type === "PASSWORD") {
|
|
@@ -486,6 +532,7 @@ async function createSession(scope, principal) {
|
|
|
486
532
|
return created;
|
|
487
533
|
}
|
|
488
534
|
var ACCOUNT_STATE = "auth:account";
|
|
535
|
+
var AUTHORIZATION_CONTEXT = defineContext("AUTHORIZATION_CONTEXT");
|
|
489
536
|
var authIdSchema = pipe(string(), minLength(1), maxLength(128));
|
|
490
537
|
var organizationNameSchema = pipe(string(), maxLength(200), trim(), minLength(1));
|
|
491
538
|
var organizationParametersSchema = object({ organizationId: authIdSchema });
|
|
@@ -572,4 +619,4 @@ var userInfoSchema = pipe(object({
|
|
|
572
619
|
var SESSION_PURPOSE = "revojs:auth:session";
|
|
573
620
|
var TOKEN_TOUCH_INTERVAL = 6e4;
|
|
574
621
|
//#endregion
|
|
575
|
-
export { ACCOUNT_STATE, AFTER_ACCOUNT_CREATE_HOOK, AFTER_ACCOUNT_GET_HOOK, AFTER_IDENTITY_CREATE_HOOK, AFTER_IDENTITY_GET_HOOK, AFTER_PRINCIPAL_CREATE_HOOK, AFTER_PRINCIPAL_GET_HOOK, AFTER_SESSION_CREATE_HOOK, AFTER_SESSION_GET_HOOK, BEFORE_ACCOUNT_CREATE_HOOK, BEFORE_ACCOUNT_GET_HOOK, BEFORE_IDENTITY_CREATE_HOOK, BEFORE_IDENTITY_GET_HOOK, BEFORE_PRINCIPAL_CREATE_HOOK, BEFORE_PRINCIPAL_GET_HOOK, BEFORE_SESSION_CREATE_HOOK, BEFORE_SESSION_GET_HOOK, authIdSchema, checkPassword, clearSession, createPrincipal, createSession, defineAuthProvider, definePermission, defineRole, getPrincipal, getSession, hashToken, membershipParametersSchema, methodSchema, organizationNameSchema, organizationParametersSchema, passkeyMethodSchema, passwordMethodSchema, principalSchema, providerMethodSchema, readSessionCookie, requireAccount, requireOrganization, roleSchema, setSession, useAccountStorage, useAuthStorage, useClientAuth, useOrganizationStorage, usePermissions, useRoles };
|
|
622
|
+
export { ACCOUNT_STATE, AFTER_ACCOUNT_CREATE_HOOK, AFTER_ACCOUNT_GET_HOOK, AFTER_IDENTITY_CREATE_HOOK, AFTER_IDENTITY_GET_HOOK, AFTER_PRINCIPAL_CREATE_HOOK, AFTER_PRINCIPAL_GET_HOOK, AFTER_SESSION_CREATE_HOOK, AFTER_SESSION_GET_HOOK, AUTHORIZATION_CONTEXT, BEFORE_ACCOUNT_CREATE_HOOK, BEFORE_ACCOUNT_GET_HOOK, BEFORE_IDENTITY_CREATE_HOOK, BEFORE_IDENTITY_GET_HOOK, BEFORE_PRINCIPAL_CREATE_HOOK, BEFORE_PRINCIPAL_GET_HOOK, BEFORE_SESSION_CREATE_HOOK, BEFORE_SESSION_GET_HOOK, authIdSchema, checkPassword, clearSession, createPrincipal, createSession, defineAuthProvider, definePermission, defineRole, getPrincipal, getSession, hashToken, membershipParametersSchema, methodSchema, organizationNameSchema, organizationParametersSchema, passkeyMethodSchema, passwordMethodSchema, principalSchema, providerMethodSchema, readSessionCookie, requireAccount, requireOrganization, requireToken, roleSchema, setSession, useAccountStorage, useAuthStorage, useAuthorization, useClientAuth, useOrganizationStorage, usePermissions, useRoles, useSessionCookie };
|
package/dist/module/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@revojs/auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -41,12 +41,12 @@
|
|
|
41
41
|
"watch": "vite build --watch"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@revojs/server": "
|
|
45
|
-
"@revojs/storage": "
|
|
46
|
-
"revojs": "
|
|
44
|
+
"@revojs/server": "0.3.1",
|
|
45
|
+
"@revojs/storage": "0.3.1",
|
|
46
|
+
"revojs": "0.3.1",
|
|
47
47
|
"valibot": "^1.5.0"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@revojs/tsconfig": "
|
|
50
|
+
"@revojs/tsconfig": "0.3.1"
|
|
51
51
|
}
|
|
52
52
|
}
|