@drawnagency/primitives 0.1.53 → 0.1.55
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/auth/cookies.d.ts +3 -0
- package/dist/auth/cookies.d.ts.map +1 -1
- package/dist/auth/index.d.ts +1 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +7 -1
- package/dist/{chunk-YEOGH3QH.js → chunk-B5VYSTPB.js} +18 -1
- package/dist/index.js +7 -1
- package/package.json +1 -1
- package/src/auth/cookies.ts +25 -1
- package/src/auth/index.ts +1 -1
- package/src/components/shell/EditorShell.tsx +1 -1
package/dist/auth/cookies.d.ts
CHANGED
|
@@ -2,7 +2,10 @@ import type { Session, CookieLike } from "./types";
|
|
|
2
2
|
export declare const SESSION_COOKIE = "bp-session";
|
|
3
3
|
export declare const AUDIENCE_COOKIE = "bp-audience";
|
|
4
4
|
export declare const SESSION_MAX_AGE_SECONDS: number;
|
|
5
|
+
export declare const AUDIENCE_MAX_AGE_SECONDS: number;
|
|
5
6
|
export declare function signSessionToken(session: Session): Promise<string>;
|
|
6
7
|
export declare function verifySessionToken(token: string): Promise<Session | null>;
|
|
8
|
+
export declare function signAudienceToken(audience: string): Promise<string>;
|
|
9
|
+
export declare function verifyAudienceToken(token: string): Promise<string | null>;
|
|
7
10
|
export declare function setSessionCookie(cookies: CookieLike, token: string, isProduction: boolean): void;
|
|
8
11
|
//# sourceMappingURL=cookies.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../../src/auth/cookies.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAGnD,eAAO,MAAM,cAAc,eAAe,CAAC;AAC3C,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAC7C,eAAO,MAAM,uBAAuB,QAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"cookies.d.ts","sourceRoot":"","sources":["../../src/auth/cookies.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAGnD,eAAO,MAAM,cAAc,eAAe,CAAC;AAC3C,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAC7C,eAAO,MAAM,uBAAuB,QAAe,CAAC;AACpD,eAAO,MAAM,wBAAwB,QAAoB,CAAC;AAE1D,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAWxE;AAED,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAe/E;AAMD,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAMzE;AAED,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAS/E;AAED,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,UAAU,EACnB,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,OAAO,GACpB,IAAI,CAQN"}
|
package/dist/auth/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type { Role, Session, SiteUser, Audience, SignInMethod, SignInResult, TokenExchangeType, TokenExchangeResult, AuthProvider, CookieLike, AuthContext, } from "./types";
|
|
2
2
|
export { requireSessionSecret, isSameOriginRequest, safeNextPath } from "./security";
|
|
3
|
-
export { signSessionToken, verifySessionToken, setSessionCookie, SESSION_COOKIE, AUDIENCE_COOKIE, SESSION_MAX_AGE_SECONDS } from "./cookies";
|
|
3
|
+
export { signSessionToken, verifySessionToken, signAudienceToken, verifyAudienceToken, setSessionCookie, SESSION_COOKIE, AUDIENCE_COOKIE, SESSION_MAX_AGE_SECONDS, AUDIENCE_MAX_AGE_SECONDS } from "./cookies";
|
|
4
4
|
export { LastOwnerError } from "./errors";
|
|
5
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/auth/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,EACZ,UAAU,EACV,WAAW,GACZ,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACrF,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,cAAc,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,EACZ,UAAU,EACV,WAAW,GACZ,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACrF,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,cAAc,EAAE,eAAe,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;AAC/M,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/auth/index.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AUDIENCE_COOKIE,
|
|
3
|
+
AUDIENCE_MAX_AGE_SECONDS,
|
|
3
4
|
LastOwnerError,
|
|
4
5
|
SESSION_COOKIE,
|
|
5
6
|
SESSION_MAX_AGE_SECONDS,
|
|
6
7
|
setSessionCookie,
|
|
8
|
+
signAudienceToken,
|
|
7
9
|
signSessionToken,
|
|
10
|
+
verifyAudienceToken,
|
|
8
11
|
verifySessionToken
|
|
9
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-B5VYSTPB.js";
|
|
10
13
|
import {
|
|
11
14
|
isSameOriginRequest,
|
|
12
15
|
requireSessionSecret,
|
|
@@ -15,6 +18,7 @@ import {
|
|
|
15
18
|
import "../chunk-WKZ7OENC.js";
|
|
16
19
|
export {
|
|
17
20
|
AUDIENCE_COOKIE,
|
|
21
|
+
AUDIENCE_MAX_AGE_SECONDS,
|
|
18
22
|
LastOwnerError,
|
|
19
23
|
SESSION_COOKIE,
|
|
20
24
|
SESSION_MAX_AGE_SECONDS,
|
|
@@ -22,6 +26,8 @@ export {
|
|
|
22
26
|
requireSessionSecret,
|
|
23
27
|
safeNextPath,
|
|
24
28
|
setSessionCookie,
|
|
29
|
+
signAudienceToken,
|
|
25
30
|
signSessionToken,
|
|
31
|
+
verifyAudienceToken,
|
|
26
32
|
verifySessionToken
|
|
27
33
|
};
|
|
@@ -7,6 +7,7 @@ import * as jose from "jose";
|
|
|
7
7
|
var SESSION_COOKIE = "bp-session";
|
|
8
8
|
var AUDIENCE_COOKIE = "bp-audience";
|
|
9
9
|
var SESSION_MAX_AGE_SECONDS = 60 * 60 * 24;
|
|
10
|
+
var AUDIENCE_MAX_AGE_SECONDS = 60 * 60 * 24 * 30;
|
|
10
11
|
async function signSessionToken(session) {
|
|
11
12
|
return new jose.SignJWT({
|
|
12
13
|
userId: session.userId,
|
|
@@ -18,7 +19,7 @@ async function signSessionToken(session) {
|
|
|
18
19
|
async function verifySessionToken(token) {
|
|
19
20
|
const secret = requireSessionSecret();
|
|
20
21
|
try {
|
|
21
|
-
const { payload } = await jose.jwtVerify(token, secret);
|
|
22
|
+
const { payload } = await jose.jwtVerify(token, secret, { algorithms: ["HS256"] });
|
|
22
23
|
const role = payload.role;
|
|
23
24
|
if (role !== "owner" && role !== "editor") return null;
|
|
24
25
|
return {
|
|
@@ -31,6 +32,19 @@ async function verifySessionToken(token) {
|
|
|
31
32
|
return null;
|
|
32
33
|
}
|
|
33
34
|
}
|
|
35
|
+
async function signAudienceToken(audience) {
|
|
36
|
+
return new jose.SignJWT({ audience }).setProtectedHeader({ alg: "HS256" }).setExpirationTime(`${AUDIENCE_MAX_AGE_SECONDS}s`).setIssuedAt().sign(requireSessionSecret());
|
|
37
|
+
}
|
|
38
|
+
async function verifyAudienceToken(token) {
|
|
39
|
+
const secret = requireSessionSecret();
|
|
40
|
+
try {
|
|
41
|
+
const { payload } = await jose.jwtVerify(token, secret, { algorithms: ["HS256"] });
|
|
42
|
+
const audience = payload.audience;
|
|
43
|
+
return typeof audience === "string" && audience !== "" ? audience : null;
|
|
44
|
+
} catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
34
48
|
function setSessionCookie(cookies, token, isProduction) {
|
|
35
49
|
cookies.set(SESSION_COOKIE, token, {
|
|
36
50
|
httpOnly: true,
|
|
@@ -53,8 +67,11 @@ export {
|
|
|
53
67
|
SESSION_COOKIE,
|
|
54
68
|
AUDIENCE_COOKIE,
|
|
55
69
|
SESSION_MAX_AGE_SECONDS,
|
|
70
|
+
AUDIENCE_MAX_AGE_SECONDS,
|
|
56
71
|
signSessionToken,
|
|
57
72
|
verifySessionToken,
|
|
73
|
+
signAudienceToken,
|
|
74
|
+
verifyAudienceToken,
|
|
58
75
|
setSessionCookie,
|
|
59
76
|
LastOwnerError
|
|
60
77
|
};
|
package/dist/index.js
CHANGED
|
@@ -61,13 +61,16 @@ import {
|
|
|
61
61
|
} from "./chunk-24SUF2BC.js";
|
|
62
62
|
import {
|
|
63
63
|
AUDIENCE_COOKIE,
|
|
64
|
+
AUDIENCE_MAX_AGE_SECONDS,
|
|
64
65
|
LastOwnerError,
|
|
65
66
|
SESSION_COOKIE,
|
|
66
67
|
SESSION_MAX_AGE_SECONDS,
|
|
67
68
|
setSessionCookie,
|
|
69
|
+
signAudienceToken,
|
|
68
70
|
signSessionToken,
|
|
71
|
+
verifyAudienceToken,
|
|
69
72
|
verifySessionToken
|
|
70
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-B5VYSTPB.js";
|
|
71
74
|
import {
|
|
72
75
|
isSameOriginRequest,
|
|
73
76
|
requireSessionSecret,
|
|
@@ -100,6 +103,7 @@ import {
|
|
|
100
103
|
} from "./chunk-DKOUFIP6.js";
|
|
101
104
|
export {
|
|
102
105
|
AUDIENCE_COOKIE,
|
|
106
|
+
AUDIENCE_MAX_AGE_SECONDS,
|
|
103
107
|
AudienceColorSchema,
|
|
104
108
|
AudienceNameSchema,
|
|
105
109
|
AudienceSchema,
|
|
@@ -177,8 +181,10 @@ export {
|
|
|
177
181
|
sanitizeMediaName,
|
|
178
182
|
setMediaProvider,
|
|
179
183
|
setSessionCookie,
|
|
184
|
+
signAudienceToken,
|
|
180
185
|
signSessionToken,
|
|
181
186
|
slugifyAudienceName,
|
|
182
187
|
toSectionId,
|
|
188
|
+
verifyAudienceToken,
|
|
183
189
|
verifySessionToken
|
|
184
190
|
};
|
package/package.json
CHANGED
package/src/auth/cookies.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { requireSessionSecret } from "./security";
|
|
|
5
5
|
export const SESSION_COOKIE = "bp-session";
|
|
6
6
|
export const AUDIENCE_COOKIE = "bp-audience";
|
|
7
7
|
export const SESSION_MAX_AGE_SECONDS = 60 * 60 * 24;
|
|
8
|
+
export const AUDIENCE_MAX_AGE_SECONDS = 60 * 60 * 24 * 30;
|
|
8
9
|
|
|
9
10
|
export async function signSessionToken(session: Session): Promise<string> {
|
|
10
11
|
return new jose.SignJWT({
|
|
@@ -22,7 +23,7 @@ export async function signSessionToken(session: Session): Promise<string> {
|
|
|
22
23
|
export async function verifySessionToken(token: string): Promise<Session | null> {
|
|
23
24
|
const secret = requireSessionSecret(); // throws on misconfiguration, before try
|
|
24
25
|
try {
|
|
25
|
-
const { payload } = await jose.jwtVerify(token, secret);
|
|
26
|
+
const { payload } = await jose.jwtVerify(token, secret, { algorithms: ["HS256"] });
|
|
26
27
|
const role = payload.role;
|
|
27
28
|
if (role !== "owner" && role !== "editor") return null;
|
|
28
29
|
return {
|
|
@@ -36,6 +37,29 @@ export async function verifySessionToken(token: string): Promise<Session | null>
|
|
|
36
37
|
}
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
// The audience cookie must be unforgeable: middleware trusts its value to gate
|
|
41
|
+
// viewer content, so it carries a signed JWT, not a plaintext audience name.
|
|
42
|
+
// SESSION_SECRET is generated per-site by the provisioner, so the signature
|
|
43
|
+
// alone also prevents cross-site replay — no siteId claim needed.
|
|
44
|
+
export async function signAudienceToken(audience: string): Promise<string> {
|
|
45
|
+
return new jose.SignJWT({ audience })
|
|
46
|
+
.setProtectedHeader({ alg: "HS256" })
|
|
47
|
+
.setExpirationTime(`${AUDIENCE_MAX_AGE_SECONDS}s`)
|
|
48
|
+
.setIssuedAt()
|
|
49
|
+
.sign(requireSessionSecret());
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function verifyAudienceToken(token: string): Promise<string | null> {
|
|
53
|
+
const secret = requireSessionSecret(); // throws on misconfiguration, before try
|
|
54
|
+
try {
|
|
55
|
+
const { payload } = await jose.jwtVerify(token, secret, { algorithms: ["HS256"] });
|
|
56
|
+
const audience = payload.audience;
|
|
57
|
+
return typeof audience === "string" && audience !== "" ? audience : null;
|
|
58
|
+
} catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
39
63
|
export function setSessionCookie(
|
|
40
64
|
cookies: CookieLike,
|
|
41
65
|
token: string,
|
package/src/auth/index.ts
CHANGED
|
@@ -13,5 +13,5 @@ export type {
|
|
|
13
13
|
} from "./types";
|
|
14
14
|
|
|
15
15
|
export { requireSessionSecret, isSameOriginRequest, safeNextPath } from "./security";
|
|
16
|
-
export { signSessionToken, verifySessionToken, setSessionCookie, SESSION_COOKIE, AUDIENCE_COOKIE, SESSION_MAX_AGE_SECONDS } from "./cookies";
|
|
16
|
+
export { signSessionToken, verifySessionToken, signAudienceToken, verifyAudienceToken, setSessionCookie, SESSION_COOKIE, AUDIENCE_COOKIE, SESSION_MAX_AGE_SECONDS, AUDIENCE_MAX_AGE_SECONDS } from "./cookies";
|
|
17
17
|
export { LastOwnerError } from "./errors";
|
|
@@ -444,7 +444,7 @@ export default function EditorShell({
|
|
|
444
444
|
if (restoredContent) {
|
|
445
445
|
return {
|
|
446
446
|
section: { id, ...restoredContent },
|
|
447
|
-
meta: restoredIndex.sections[id] ?? existing?.meta ?? { type: restoredContent.type, status: "draft", access: [
|
|
447
|
+
meta: restoredIndex.sections[id] ?? existing?.meta ?? { type: restoredContent.type, status: "draft", access: [] },
|
|
448
448
|
};
|
|
449
449
|
}
|
|
450
450
|
if (existing) {
|