@revealui/core 0.14.7 → 0.15.3
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/api/rest.d.ts.map +1 -1
- package/dist/api/rest.js +5 -11
- package/dist/license.d.ts +2 -0
- package/dist/license.d.ts.map +1 -1
- package/dist/license.js +32 -10
- package/dist/sentry-environment.d.ts +37 -0
- package/dist/sentry-environment.d.ts.map +1 -0
- package/dist/sentry-environment.js +129 -0
- package/dist/session-cookie-domain.d.ts +39 -0
- package/dist/session-cookie-domain.d.ts.map +1 -0
- package/dist/session-cookie-domain.js +106 -0
- package/package.json +14 -4
package/dist/api/rest.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rest.d.ts","sourceRoot":"","sources":["../../src/api/rest.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EACV,MAAM,EACN,YAAY,EAGZ,cAAc,EAGd,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,cAAc;IAC7C,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;IACX,GAAG,CAAC,EAAE,CAAC,CAAC;IACR,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrD;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;
|
|
1
|
+
{"version":3,"file":"rest.d.ts","sourceRoot":"","sources":["../../src/api/rest.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EACV,MAAM,EACN,YAAY,EAGZ,cAAc,EAGd,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,cAAc;IAC7C,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;IACX,GAAG,CAAC,EAAE,CAAC,CAAC;IACR,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrD;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;AAuaD,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,gBAAgB,GACzB,OAAO,CAAC,QAAQ,CAAC,CAiGnB;AAGD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,gBAAgB,GACzB;IACD,GAAG,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChE,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjE,GAAG,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChE,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnE,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClE,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CACrE,CAaA"}
|
package/dist/api/rest.js
CHANGED
|
@@ -153,8 +153,10 @@ function getCorsOriginsFromConfig(config) {
|
|
|
153
153
|
return [];
|
|
154
154
|
}
|
|
155
155
|
/**
|
|
156
|
-
* Get allowed CORS origin for a request
|
|
157
|
-
*
|
|
156
|
+
* Get allowed CORS origin for a request.
|
|
157
|
+
* The allowlist comes from config, then REVEALUI_CORS_ORIGINS.
|
|
158
|
+
* A request origin on that list is returned. A missing list, an empty list,
|
|
159
|
+
* or a non-matching origin returns an empty allow-origin so nothing is granted.
|
|
158
160
|
*/
|
|
159
161
|
function getAllowedOrigin(request, config) {
|
|
160
162
|
let allowedOrigins = getCorsOriginsFromConfig(config);
|
|
@@ -163,18 +165,10 @@ function getAllowedOrigin(request, config) {
|
|
|
163
165
|
allowedOrigins = process.env.REVEALUI_CORS_ORIGINS.split(',').map((s) => s.trim());
|
|
164
166
|
}
|
|
165
167
|
const origin = request.headers.get('origin');
|
|
166
|
-
// If config has specific origins and request origin matches, use it
|
|
167
168
|
if (allowedOrigins.length > 0 && origin && allowedOrigins.includes(origin)) {
|
|
168
169
|
return origin;
|
|
169
170
|
}
|
|
170
|
-
|
|
171
|
-
// In production, this should never be reached if CORS is properly configured
|
|
172
|
-
if (process.env.NODE_ENV === 'development') {
|
|
173
|
-
return '*';
|
|
174
|
-
}
|
|
175
|
-
// In production, if no allowed origins configured, deny all (secure default)
|
|
176
|
-
// This prevents accidental exposure in production
|
|
177
|
-
return origin || '';
|
|
171
|
+
return '';
|
|
178
172
|
}
|
|
179
173
|
/**
|
|
180
174
|
* Get standard CORS headers for a response
|
package/dist/license.d.ts
CHANGED
|
@@ -201,6 +201,8 @@ export declare const REFRESH_ACCEPT_DAYS = 30;
|
|
|
201
201
|
* the bind succeeds. It never mints and never grants entitlement on its own.
|
|
202
202
|
*/
|
|
203
203
|
export declare function validateLicenseKeyForRefresh(licenseKey: string, publicKey: string | readonly string[], expectedCustomerId: string, refreshAcceptDays?: number): Promise<LicensePayload | null>;
|
|
204
|
+
/** Authenticated operator containment: validates issuer/signature/customer, not entitlement expiry. */
|
|
205
|
+
export declare function validateLicenseKeyForOperator(licenseKey: string, publicKey: string | readonly string[], expectedCustomerId: string): Promise<LicensePayload | null>;
|
|
204
206
|
/**
|
|
205
207
|
* Outcome of a signing-keypair self-test. See {@link selfVerifyLicenseKeypair}.
|
|
206
208
|
*/
|
package/dist/license.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"license.d.ts","sourceRoot":"","sources":["../src/license.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"license.d.ts","sourceRoot":"","sources":["../src/license.ts"],"names":[],"mappings":"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"}
|
package/dist/license.js
CHANGED
|
@@ -281,6 +281,12 @@ export async function validateLicenseKeyForRefresh(licenseKey, publicKey, expect
|
|
|
281
281
|
return null;
|
|
282
282
|
return verifyAndParseLicenseJwt(licenseKey, publicKey, refreshAcceptDays * 86_400, bound);
|
|
283
283
|
}
|
|
284
|
+
/** Authenticated operator containment: validates issuer/signature/customer, not entitlement expiry. */
|
|
285
|
+
export async function validateLicenseKeyForOperator(licenseKey, publicKey, expectedCustomerId) {
|
|
286
|
+
if (!expectedCustomerId.trim())
|
|
287
|
+
return null;
|
|
288
|
+
return verifyAndParseLicenseJwt(licenseKey, publicKey, 0, expectedCustomerId, true);
|
|
289
|
+
}
|
|
284
290
|
/**
|
|
285
291
|
* Shared verify + parse path for {@link validateLicenseKey} and
|
|
286
292
|
* {@link validateLicenseKeyForRefresh}. The ONLY behavioral difference between
|
|
@@ -288,7 +294,7 @@ export async function validateLicenseKeyForRefresh(licenseKey, publicKey, expect
|
|
|
288
294
|
* still accepted — so the rotation-aware multi-key loop and the payload schema
|
|
289
295
|
* live in exactly one place.
|
|
290
296
|
*/
|
|
291
|
-
async function verifyAndParseLicenseJwt(licenseKey, publicKey, clockToleranceSeconds, expectedCustomerId) {
|
|
297
|
+
async function verifyAndParseLicenseJwt(licenseKey, publicKey, clockToleranceSeconds, expectedCustomerId, operator = false) {
|
|
292
298
|
const candidates = typeof publicKey === 'string' ? [publicKey] : [...publicKey];
|
|
293
299
|
if (candidates.length === 0)
|
|
294
300
|
return null;
|
|
@@ -303,12 +309,27 @@ async function verifyAndParseLicenseJwt(licenseKey, publicKey, clockToleranceSec
|
|
|
303
309
|
for (const candidate of ordered) {
|
|
304
310
|
try {
|
|
305
311
|
const key = await jose.importSPKI(candidate, 'EdDSA');
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
+
let payload;
|
|
313
|
+
if (operator) {
|
|
314
|
+
const verified = await jose.compactVerify(licenseKey, key, { algorithms: ['EdDSA'] });
|
|
315
|
+
const claims = JSON.parse(new TextDecoder().decode(verified.payload));
|
|
316
|
+
if (claims.iss !== LICENSE_ISSUER ||
|
|
317
|
+
!(claims.aud === LICENSE_AUDIENCE ||
|
|
318
|
+
(Array.isArray(claims.aud) && claims.aud.includes(LICENSE_AUDIENCE))) ||
|
|
319
|
+
(claims.nbf !== undefined &&
|
|
320
|
+
(typeof claims.nbf !== 'number' || claims.nbf > Date.now() / 1000))) {
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
payload = claims;
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
({ payload } = await jose.jwtVerify(licenseKey, key, {
|
|
327
|
+
algorithms: ['EdDSA'],
|
|
328
|
+
clockTolerance: clockToleranceSeconds,
|
|
329
|
+
issuer: LICENSE_ISSUER,
|
|
330
|
+
audience: LICENSE_AUDIENCE,
|
|
331
|
+
}));
|
|
332
|
+
}
|
|
312
333
|
verifiedPayload = payload;
|
|
313
334
|
verified = true;
|
|
314
335
|
break;
|
|
@@ -882,17 +903,18 @@ export async function generateLicenseKey(payload, privateKey, expiresInSeconds =
|
|
|
882
903
|
// Strip the optional jti from the spread so jose.setJti() is the single
|
|
883
904
|
// source of the claim (avoids a duplicate field in the payload).
|
|
884
905
|
const { jti: _ignoredJti, ...rest } = payload;
|
|
906
|
+
const issuedAt = Math.floor(Date.now() / 1000);
|
|
885
907
|
const builder = new jose.SignJWT({ ...rest })
|
|
886
908
|
.setProtectedHeader(header)
|
|
887
|
-
.setIssuedAt()
|
|
909
|
+
.setIssuedAt(issuedAt)
|
|
888
910
|
// Phase 1 audit B-2: enforce nbf so tokens cannot be replayed pre-issue
|
|
889
911
|
// by a clock-skewed client.
|
|
890
|
-
.setNotBefore(
|
|
912
|
+
.setNotBefore(issuedAt)
|
|
891
913
|
.setJti(jti)
|
|
892
914
|
.setIssuer(LICENSE_ISSUER)
|
|
893
915
|
.setAudience(LICENSE_AUDIENCE);
|
|
894
916
|
if (expiresInSeconds !== null) {
|
|
895
|
-
builder.setExpirationTime(
|
|
917
|
+
builder.setExpirationTime(issuedAt + expiresInSeconds);
|
|
896
918
|
}
|
|
897
919
|
return builder.sign(key);
|
|
898
920
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sentry `environment` for a deploy.
|
|
3
|
+
*
|
|
4
|
+
* `NODE_ENV=production` is set on staging as well as production, so it is not
|
|
5
|
+
* a safe Sentry label. Prefer `SENTRY_ENVIRONMENT` (then `REVEALUI_DEPLOY_ENV`,
|
|
6
|
+
* then `NEXT_PUBLIC_SENTRY_ENVIRONMENT`). When those are unset, derive the
|
|
7
|
+
* label from public hosts. A `*.staging.revealui.com` host is never reported
|
|
8
|
+
* as production. Vercel preview stays `preview`.
|
|
9
|
+
*/
|
|
10
|
+
export type SentryEnvironmentName = 'production' | 'staging' | 'preview' | 'development' | 'test';
|
|
11
|
+
/** Non-secret label. Set `SENTRY_ENVIRONMENT=staging` on staging Vercel and Fly. */
|
|
12
|
+
export declare const SENTRY_ENVIRONMENT_VAR = "SENTRY_ENVIRONMENT";
|
|
13
|
+
export interface SentryEnvironmentSource {
|
|
14
|
+
SENTRY_ENVIRONMENT?: string | undefined;
|
|
15
|
+
REVEALUI_DEPLOY_ENV?: string | undefined;
|
|
16
|
+
NEXT_PUBLIC_SENTRY_ENVIRONMENT?: string | undefined;
|
|
17
|
+
NODE_ENV?: string | undefined;
|
|
18
|
+
VERCEL_ENV?: string | undefined;
|
|
19
|
+
REVEALUI_API_URL?: string | undefined;
|
|
20
|
+
NEXT_PUBLIC_API_URL?: string | undefined;
|
|
21
|
+
API_URL?: string | undefined;
|
|
22
|
+
REVEALUI_PUBLIC_SERVER_URL?: string | undefined;
|
|
23
|
+
NEXT_PUBLIC_SERVER_URL?: string | undefined;
|
|
24
|
+
VERCEL_PROJECT_PRODUCTION_URL?: string | undefined;
|
|
25
|
+
VERCEL_URL?: string | undefined;
|
|
26
|
+
SESSION_COOKIE_DOMAIN?: string | undefined;
|
|
27
|
+
PASSKEY_RP_ID?: string | undefined;
|
|
28
|
+
PASSKEY_ORIGIN?: string | undefined;
|
|
29
|
+
CORS_ORIGIN?: string | undefined;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Resolve the Sentry environment label.
|
|
33
|
+
* Staging hosts report `staging`, or `preview` when that explicit label is set.
|
|
34
|
+
* They do not report `production`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function resolveSentryEnvironment(env: SentryEnvironmentSource): SentryEnvironmentName;
|
|
37
|
+
//# sourceMappingURL=sentry-environment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sentry-environment.d.ts","sourceRoot":"","sources":["../src/sentry-environment.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,MAAM,MAAM,qBAAqB,GAAG,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,GAAG,MAAM,CAAC;AAElG,oFAAoF;AACpF,eAAO,MAAM,sBAAsB,uBAAuB,CAAC;AAE3D,MAAM,WAAW,uBAAuB;IACtC,kBAAkB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,mBAAmB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,8BAA8B,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpD,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,mBAAmB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,0BAA0B,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChD,sBAAsB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,6BAA6B,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnD,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,qBAAqB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC;AAyED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,uBAAuB,GAAG,qBAAqB,CAoD5F"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sentry `environment` for a deploy.
|
|
3
|
+
*
|
|
4
|
+
* `NODE_ENV=production` is set on staging as well as production, so it is not
|
|
5
|
+
* a safe Sentry label. Prefer `SENTRY_ENVIRONMENT` (then `REVEALUI_DEPLOY_ENV`,
|
|
6
|
+
* then `NEXT_PUBLIC_SENTRY_ENVIRONMENT`). When those are unset, derive the
|
|
7
|
+
* label from public hosts. A `*.staging.revealui.com` host is never reported
|
|
8
|
+
* as production. Vercel preview stays `preview`.
|
|
9
|
+
*/
|
|
10
|
+
import { isStagingRevealHost, normalizeRequestHost } from './session-cookie-domain.js';
|
|
11
|
+
/** Non-secret label. Set `SENTRY_ENVIRONMENT=staging` on staging Vercel and Fly. */
|
|
12
|
+
export const SENTRY_ENVIRONMENT_VAR = 'SENTRY_ENVIRONMENT';
|
|
13
|
+
const HOST_KEYS = [
|
|
14
|
+
'REVEALUI_API_URL',
|
|
15
|
+
'NEXT_PUBLIC_API_URL',
|
|
16
|
+
'API_URL',
|
|
17
|
+
'REVEALUI_PUBLIC_SERVER_URL',
|
|
18
|
+
'NEXT_PUBLIC_SERVER_URL',
|
|
19
|
+
'VERCEL_PROJECT_PRODUCTION_URL',
|
|
20
|
+
'VERCEL_URL',
|
|
21
|
+
'SESSION_COOKIE_DOMAIN',
|
|
22
|
+
'PASSKEY_RP_ID',
|
|
23
|
+
'PASSKEY_ORIGIN',
|
|
24
|
+
'CORS_ORIGIN',
|
|
25
|
+
];
|
|
26
|
+
const PRODUCTION_HOSTS = new Set([
|
|
27
|
+
'revealui.com',
|
|
28
|
+
'www.revealui.com',
|
|
29
|
+
'api.revealui.com',
|
|
30
|
+
'admin.revealui.com',
|
|
31
|
+
'docs.revealui.com',
|
|
32
|
+
]);
|
|
33
|
+
function lockedEnvironment(raw) {
|
|
34
|
+
if (raw == null)
|
|
35
|
+
return null;
|
|
36
|
+
const value = raw.trim().toLowerCase();
|
|
37
|
+
switch (value) {
|
|
38
|
+
case 'production':
|
|
39
|
+
case 'staging':
|
|
40
|
+
case 'preview':
|
|
41
|
+
case 'development':
|
|
42
|
+
case 'test':
|
|
43
|
+
return value;
|
|
44
|
+
default:
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function firstLocked(...values) {
|
|
49
|
+
for (const value of values) {
|
|
50
|
+
const locked = lockedEnvironment(value);
|
|
51
|
+
if (locked)
|
|
52
|
+
return locked;
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
function splitComma(raw) {
|
|
57
|
+
const parts = [];
|
|
58
|
+
let start = 0;
|
|
59
|
+
for (let index = 0; index <= raw.length; index += 1) {
|
|
60
|
+
if (index === raw.length || raw.charCodeAt(index) === 44) {
|
|
61
|
+
const part = raw.slice(start, index).trim();
|
|
62
|
+
if (part.length > 0)
|
|
63
|
+
parts.push(part);
|
|
64
|
+
start = index + 1;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return parts;
|
|
68
|
+
}
|
|
69
|
+
function collectHosts(env) {
|
|
70
|
+
const hosts = [];
|
|
71
|
+
for (const key of HOST_KEYS) {
|
|
72
|
+
const raw = env[key];
|
|
73
|
+
if (typeof raw !== 'string' || raw.trim().length === 0)
|
|
74
|
+
continue;
|
|
75
|
+
for (const part of splitComma(raw)) {
|
|
76
|
+
const host = normalizeRequestHost(part);
|
|
77
|
+
if (host)
|
|
78
|
+
hosts.push(host);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return hosts;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Resolve the Sentry environment label.
|
|
85
|
+
* Staging hosts report `staging`, or `preview` when that explicit label is set.
|
|
86
|
+
* They do not report `production`.
|
|
87
|
+
*/
|
|
88
|
+
export function resolveSentryEnvironment(env) {
|
|
89
|
+
const hosts = collectHosts(env);
|
|
90
|
+
let stagingHost = false;
|
|
91
|
+
let productionHost = false;
|
|
92
|
+
for (const host of hosts) {
|
|
93
|
+
if (isStagingRevealHost(host))
|
|
94
|
+
stagingHost = true;
|
|
95
|
+
if (PRODUCTION_HOSTS.has(host))
|
|
96
|
+
productionHost = true;
|
|
97
|
+
}
|
|
98
|
+
const explicit = firstLocked(env.SENTRY_ENVIRONMENT, env.REVEALUI_DEPLOY_ENV, env.NEXT_PUBLIC_SENTRY_ENVIRONMENT);
|
|
99
|
+
if (stagingHost) {
|
|
100
|
+
if (explicit === 'staging' ||
|
|
101
|
+
explicit === 'preview' ||
|
|
102
|
+
explicit === 'development' ||
|
|
103
|
+
explicit === 'test') {
|
|
104
|
+
return explicit;
|
|
105
|
+
}
|
|
106
|
+
return 'staging';
|
|
107
|
+
}
|
|
108
|
+
if (explicit)
|
|
109
|
+
return explicit;
|
|
110
|
+
if (productionHost)
|
|
111
|
+
return 'production';
|
|
112
|
+
const vercel = lockedEnvironment(env.VERCEL_ENV);
|
|
113
|
+
if (vercel === 'preview' ||
|
|
114
|
+
vercel === 'development' ||
|
|
115
|
+
vercel === 'test' ||
|
|
116
|
+
vercel === 'staging') {
|
|
117
|
+
return vercel;
|
|
118
|
+
}
|
|
119
|
+
const nodeEnv = lockedEnvironment(env.NODE_ENV);
|
|
120
|
+
if (nodeEnv === 'development' ||
|
|
121
|
+
nodeEnv === 'test' ||
|
|
122
|
+
nodeEnv === 'staging' ||
|
|
123
|
+
nodeEnv === 'preview') {
|
|
124
|
+
return nodeEnv;
|
|
125
|
+
}
|
|
126
|
+
if (nodeEnv === 'production' || vercel === 'production')
|
|
127
|
+
return 'production';
|
|
128
|
+
return 'development';
|
|
129
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session cookie domain for a request host (GAP-343).
|
|
3
|
+
*
|
|
4
|
+
* Staging hosts always resolve to `staging.revealui.com` so a production
|
|
5
|
+
* `SESSION_COOKIE_DOMAIN` (for example `.revealui.com`) is not attached to
|
|
6
|
+
* the staging subtree. Every other host returns `configuredDomain` unchanged.
|
|
7
|
+
* This function does not read the environment and does not apply the
|
|
8
|
+
* production-only gate. Callers keep that gate.
|
|
9
|
+
*/
|
|
10
|
+
/** Cookie Domain attribute for the staging.revealui.com subtree. No leading dot. */
|
|
11
|
+
export declare const STAGING_SESSION_COOKIE_DOMAIN = "staging.revealui.com";
|
|
12
|
+
/**
|
|
13
|
+
* Hostname from a Host or X-Forwarded-Host value.
|
|
14
|
+
* Strips a scheme, path, trailing dot, and numeric port. Uses the first
|
|
15
|
+
* comma-separated entry. Returns null when nothing usable remains.
|
|
16
|
+
* String methods only (no regular expressions).
|
|
17
|
+
*/
|
|
18
|
+
export declare function normalizeRequestHost(raw: string | null | undefined): string | null;
|
|
19
|
+
/**
|
|
20
|
+
* True for `staging.revealui.com` and any host under `*.staging.revealui.com`.
|
|
21
|
+
* Label-boundary match: `evilstaging.revealui.com` and
|
|
22
|
+
* `staging.revealui.com.evil.com` are not staging hosts.
|
|
23
|
+
*/
|
|
24
|
+
export declare function isStagingRevealHost(requestHost: string | null | undefined): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Cookie Domain for this request.
|
|
27
|
+
*
|
|
28
|
+
* Staging hosts return `staging.revealui.com` even when `configuredDomain`
|
|
29
|
+
* is the production domain or unset. Every other host, including a missing
|
|
30
|
+
* host, returns `configuredDomain` exactly (including `undefined`).
|
|
31
|
+
*/
|
|
32
|
+
export declare function sessionCookieDomainForHost(requestHost: string | null | undefined, configuredDomain: string | undefined): string | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Public request host. Prefer `Host` so a client-supplied `X-Forwarded-Host`
|
|
35
|
+
* cannot override the host the platform already set. Fall back to
|
|
36
|
+
* `X-Forwarded-Host` only when `Host` is absent.
|
|
37
|
+
*/
|
|
38
|
+
export declare function requestHostFromHeaders(getHeader: (name: string) => string | null | undefined): string | null;
|
|
39
|
+
//# sourceMappingURL=session-cookie-domain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-cookie-domain.d.ts","sourceRoot":"","sources":["../src/session-cookie-domain.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,oFAAoF;AACpF,eAAO,MAAM,6BAA6B,yBAAyB,CAAC;AAEpE;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CA0ClF;AAUD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAKnF;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACtC,gBAAgB,EAAE,MAAM,GAAG,SAAS,GACnC,MAAM,GAAG,SAAS,CAKpB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,GACrD,MAAM,GAAG,IAAI,CAMf"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session cookie domain for a request host (GAP-343).
|
|
3
|
+
*
|
|
4
|
+
* Staging hosts always resolve to `staging.revealui.com` so a production
|
|
5
|
+
* `SESSION_COOKIE_DOMAIN` (for example `.revealui.com`) is not attached to
|
|
6
|
+
* the staging subtree. Every other host returns `configuredDomain` unchanged.
|
|
7
|
+
* This function does not read the environment and does not apply the
|
|
8
|
+
* production-only gate. Callers keep that gate.
|
|
9
|
+
*/
|
|
10
|
+
/** Cookie Domain attribute for the staging.revealui.com subtree. No leading dot. */
|
|
11
|
+
export const STAGING_SESSION_COOKIE_DOMAIN = 'staging.revealui.com';
|
|
12
|
+
/**
|
|
13
|
+
* Hostname from a Host or X-Forwarded-Host value.
|
|
14
|
+
* Strips a scheme, path, trailing dot, and numeric port. Uses the first
|
|
15
|
+
* comma-separated entry. Returns null when nothing usable remains.
|
|
16
|
+
* String methods only (no regular expressions).
|
|
17
|
+
*/
|
|
18
|
+
export function normalizeRequestHost(raw) {
|
|
19
|
+
if (raw == null)
|
|
20
|
+
return null;
|
|
21
|
+
let value = raw.trim().toLowerCase();
|
|
22
|
+
if (value.length === 0)
|
|
23
|
+
return null;
|
|
24
|
+
const comma = value.indexOf(',');
|
|
25
|
+
if (comma !== -1) {
|
|
26
|
+
value = value.slice(0, comma).trim();
|
|
27
|
+
}
|
|
28
|
+
if (value.length === 0)
|
|
29
|
+
return null;
|
|
30
|
+
const scheme = value.indexOf('://');
|
|
31
|
+
if (scheme !== -1) {
|
|
32
|
+
value = value.slice(scheme + 3);
|
|
33
|
+
}
|
|
34
|
+
const slash = value.indexOf('/');
|
|
35
|
+
if (slash !== -1) {
|
|
36
|
+
value = value.slice(0, slash);
|
|
37
|
+
}
|
|
38
|
+
if (value.startsWith('[')) {
|
|
39
|
+
const end = value.indexOf(']');
|
|
40
|
+
if (end === -1)
|
|
41
|
+
return null;
|
|
42
|
+
const bracketed = value.slice(0, end + 1);
|
|
43
|
+
return bracketed.length > 2 ? bracketed : null;
|
|
44
|
+
}
|
|
45
|
+
const colon = value.lastIndexOf(':');
|
|
46
|
+
if (colon !== -1) {
|
|
47
|
+
const port = value.slice(colon + 1);
|
|
48
|
+
if (port.length > 0 && isAllDigits(port)) {
|
|
49
|
+
value = value.slice(0, colon);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (value.endsWith('.')) {
|
|
53
|
+
value = value.slice(0, -1);
|
|
54
|
+
}
|
|
55
|
+
if (value.length === 0)
|
|
56
|
+
return null;
|
|
57
|
+
return value;
|
|
58
|
+
}
|
|
59
|
+
function isAllDigits(value) {
|
|
60
|
+
for (let i = 0; i < value.length; i++) {
|
|
61
|
+
const code = value.charCodeAt(i);
|
|
62
|
+
if (code < 48 || code > 57)
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* True for `staging.revealui.com` and any host under `*.staging.revealui.com`.
|
|
69
|
+
* Label-boundary match: `evilstaging.revealui.com` and
|
|
70
|
+
* `staging.revealui.com.evil.com` are not staging hosts.
|
|
71
|
+
*/
|
|
72
|
+
export function isStagingRevealHost(requestHost) {
|
|
73
|
+
const host = normalizeRequestHost(requestHost);
|
|
74
|
+
if (!host)
|
|
75
|
+
return false;
|
|
76
|
+
if (host === STAGING_SESSION_COOKIE_DOMAIN)
|
|
77
|
+
return true;
|
|
78
|
+
return host.endsWith(`.${STAGING_SESSION_COOKIE_DOMAIN}`);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Cookie Domain for this request.
|
|
82
|
+
*
|
|
83
|
+
* Staging hosts return `staging.revealui.com` even when `configuredDomain`
|
|
84
|
+
* is the production domain or unset. Every other host, including a missing
|
|
85
|
+
* host, returns `configuredDomain` exactly (including `undefined`).
|
|
86
|
+
*/
|
|
87
|
+
export function sessionCookieDomainForHost(requestHost, configuredDomain) {
|
|
88
|
+
if (isStagingRevealHost(requestHost)) {
|
|
89
|
+
return STAGING_SESSION_COOKIE_DOMAIN;
|
|
90
|
+
}
|
|
91
|
+
return configuredDomain;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Public request host. Prefer `Host` so a client-supplied `X-Forwarded-Host`
|
|
95
|
+
* cannot override the host the platform already set. Fall back to
|
|
96
|
+
* `X-Forwarded-Host` only when `Host` is absent.
|
|
97
|
+
*/
|
|
98
|
+
export function requestHostFromHeaders(getHeader) {
|
|
99
|
+
const host = getHeader('host');
|
|
100
|
+
if (typeof host === 'string' && host.trim().length > 0)
|
|
101
|
+
return host;
|
|
102
|
+
const forwarded = getHeader('x-forwarded-host');
|
|
103
|
+
if (typeof forwarded === 'string' && forwarded.trim().length > 0)
|
|
104
|
+
return forwarded;
|
|
105
|
+
return null;
|
|
106
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@revealui/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.3",
|
|
4
4
|
"description": "RevealUI's runtime engine — admin UI, REST API, auth, rich text, plugin system, and access control. The heart of the open-source platform.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"dependencies": {
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
"pg": "^8.22.0",
|
|
24
24
|
"yjs": "^13.6.31",
|
|
25
25
|
"zod": "^4.4.3",
|
|
26
|
-
"@revealui/contracts": "0.
|
|
27
|
-
"@revealui/presentation": "0.
|
|
26
|
+
"@revealui/contracts": "0.13.2",
|
|
27
|
+
"@revealui/presentation": "0.15.2",
|
|
28
28
|
"@revealui/resilience": "0.2.4",
|
|
29
|
-
"@revealui/security": "0.
|
|
29
|
+
"@revealui/security": "0.10.1",
|
|
30
30
|
"@revealui/utils": "0.3.6"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
@@ -66,6 +66,16 @@
|
|
|
66
66
|
"import": "./dist/deployment-mode.js",
|
|
67
67
|
"default": "./dist/deployment-mode.js"
|
|
68
68
|
},
|
|
69
|
+
"./session-cookie-domain": {
|
|
70
|
+
"types": "./dist/session-cookie-domain.d.ts",
|
|
71
|
+
"import": "./dist/session-cookie-domain.js",
|
|
72
|
+
"default": "./dist/session-cookie-domain.js"
|
|
73
|
+
},
|
|
74
|
+
"./sentry-environment": {
|
|
75
|
+
"types": "./dist/sentry-environment.d.ts",
|
|
76
|
+
"import": "./dist/sentry-environment.js",
|
|
77
|
+
"default": "./dist/sentry-environment.js"
|
|
78
|
+
},
|
|
69
79
|
"./margin-governor": {
|
|
70
80
|
"types": "./dist/margin-governor.d.ts",
|
|
71
81
|
"import": "./dist/margin-governor.js",
|