@scalemule/nextjs 0.1.14 → 0.1.16
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/client.d.mts +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js +2 -1
- package/dist/client.mjs +2 -1
- package/dist/{index-BIIUrnPr.d.mts → index-DTWyUcyd.d.mts} +22 -1
- package/dist/{index-BIIUrnPr.d.ts → index-DTWyUcyd.d.ts} +22 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +81 -19
- package/dist/index.mjs +82 -20
- package/dist/ledvery-CxPzZpxP.d.mts +44 -0
- package/dist/ledvery-CxPzZpxP.d.ts +44 -0
- package/dist/server/auth.js +2 -1
- package/dist/server/auth.mjs +2 -1
- package/dist/server/index.d.mts +4 -3
- package/dist/server/index.d.ts +4 -3
- package/dist/server/index.js +327 -50
- package/dist/server/index.mjs +321 -51
- package/dist/server/ledvery.d.mts +1 -0
- package/dist/server/ledvery.d.ts +1 -0
- package/dist/server/ledvery.js +331 -0
- package/dist/server/ledvery.mjs +328 -0
- package/dist/server/webhook-handler.d.mts +2 -2
- package/dist/server/webhook-handler.d.ts +2 -2
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +2 -1
- package/dist/testing.mjs +2 -1
- package/dist/{webhook-handler-BjFbqZuq.d.ts → webhook-handler-C07AK4QB.d.ts} +1 -1
- package/dist/{webhook-handler-BqzCYRNJ.d.mts → webhook-handler-CUp_A0_p.d.mts} +1 -1
- package/package.json +7 -1
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
declare const SM_LEDVERY_STATE_COOKIE = "sm_ledvery_state";
|
|
2
|
+
declare const SM_LEDVERY_PKCE_VERIFIER_COOKIE = "sm_ledvery_pkce_verifier";
|
|
3
|
+
declare const SM_LEDVERY_NONCE_COOKIE = "sm_ledvery_nonce";
|
|
4
|
+
declare const SM_LEDVERY_ID_TOKEN_COOKIE = "sm_ledvery_id_token";
|
|
5
|
+
declare const SM_LEDVERY_ACCESS_TOKEN_COOKIE = "sm_ledvery_access_token";
|
|
6
|
+
interface SessionCookieOverrides {
|
|
7
|
+
maxAge?: number;
|
|
8
|
+
domain?: string;
|
|
9
|
+
path?: string;
|
|
10
|
+
sameSite?: 'strict' | 'lax' | 'none';
|
|
11
|
+
secure?: boolean;
|
|
12
|
+
}
|
|
13
|
+
interface LedverySessionData {
|
|
14
|
+
idToken: string;
|
|
15
|
+
accessToken?: string;
|
|
16
|
+
claims: Record<string, unknown>;
|
|
17
|
+
expiresAt: string;
|
|
18
|
+
}
|
|
19
|
+
declare function getLedverySession(request: Request): LedverySessionData | null;
|
|
20
|
+
|
|
21
|
+
interface LedveryRoutesConfig {
|
|
22
|
+
issuer: string;
|
|
23
|
+
clientId: string;
|
|
24
|
+
clientSecret?: string;
|
|
25
|
+
redirectUri: string;
|
|
26
|
+
defaultScope?: string;
|
|
27
|
+
postLoginRedirect?: string;
|
|
28
|
+
postLogoutRedirect?: string;
|
|
29
|
+
cookies?: SessionCookieOverrides;
|
|
30
|
+
storeAccessToken?: boolean;
|
|
31
|
+
fetch?: typeof fetch;
|
|
32
|
+
gatewayUrl?: string;
|
|
33
|
+
}
|
|
34
|
+
type RouteHandler = (request: Request, context: {
|
|
35
|
+
params: Promise<{
|
|
36
|
+
action?: string[];
|
|
37
|
+
}>;
|
|
38
|
+
}) => Promise<Response>;
|
|
39
|
+
declare function createLedveryRoutes(config: LedveryRoutesConfig): {
|
|
40
|
+
GET: RouteHandler;
|
|
41
|
+
POST: RouteHandler;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export { type LedveryRoutesConfig as L, SM_LEDVERY_ACCESS_TOKEN_COOKIE as S, type LedverySessionData as a, SM_LEDVERY_ID_TOKEN_COOKIE as b, SM_LEDVERY_NONCE_COOKIE as c, SM_LEDVERY_PKCE_VERIFIER_COOKIE as d, SM_LEDVERY_STATE_COOKIE as e, createLedveryRoutes as f, getLedverySession as g };
|
package/dist/server/auth.js
CHANGED
|
@@ -6,11 +6,12 @@ require('next/server');
|
|
|
6
6
|
|
|
7
7
|
// src/types/index.ts
|
|
8
8
|
var ScaleMuleApiError = class extends Error {
|
|
9
|
-
constructor(error) {
|
|
9
|
+
constructor(error, status) {
|
|
10
10
|
super(error.message);
|
|
11
11
|
this.name = "ScaleMuleApiError";
|
|
12
12
|
this.code = error.code;
|
|
13
13
|
this.field = error.field;
|
|
14
|
+
this.status = status;
|
|
14
15
|
}
|
|
15
16
|
};
|
|
16
17
|
|
package/dist/server/auth.mjs
CHANGED
|
@@ -4,11 +4,12 @@ import 'next/server';
|
|
|
4
4
|
|
|
5
5
|
// src/types/index.ts
|
|
6
6
|
var ScaleMuleApiError = class extends Error {
|
|
7
|
-
constructor(error) {
|
|
7
|
+
constructor(error, status) {
|
|
8
8
|
super(error.message);
|
|
9
9
|
this.name = "ScaleMuleApiError";
|
|
10
10
|
this.code = error.code;
|
|
11
11
|
this.field = error.field;
|
|
12
|
+
this.status = status;
|
|
12
13
|
}
|
|
13
14
|
};
|
|
14
15
|
|
package/dist/server/index.d.mts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { S as ServerConfig } from '../webhook-handler-
|
|
2
|
-
export { a as ScaleMuleServer, V as VideoFailedEvent, b as VideoReadyEvent, c as VideoTranscodedEvent, d as VideoUploadedEvent, W as WebhookEvent, e as WebhookRoutesConfig, f as createServerClient, g as createWebhookHandler, h as createWebhookRoutes, p as parseWebhookEvent, r as registerVideoWebhook, i as resolveGatewayUrl, v as verifyWebhookSignature } from '../webhook-handler-
|
|
3
|
-
import { p as ClientContext, A as ApiError } from '../index-
|
|
1
|
+
import { S as ServerConfig } from '../webhook-handler-CUp_A0_p.mjs';
|
|
2
|
+
export { a as ScaleMuleServer, V as VideoFailedEvent, b as VideoReadyEvent, c as VideoTranscodedEvent, d as VideoUploadedEvent, W as WebhookEvent, e as WebhookRoutesConfig, f as createServerClient, g as createWebhookHandler, h as createWebhookRoutes, p as parseWebhookEvent, r as registerVideoWebhook, i as resolveGatewayUrl, v as verifyWebhookSignature } from '../webhook-handler-CUp_A0_p.mjs';
|
|
3
|
+
import { p as ClientContext, A as ApiError } from '../index-DTWyUcyd.mjs';
|
|
4
|
+
export { L as LedveryRoutesConfig, a as LedverySessionData, S as SM_LEDVERY_ACCESS_TOKEN_COOKIE, b as SM_LEDVERY_ID_TOKEN_COOKIE, c as SM_LEDVERY_NONCE_COOKIE, d as SM_LEDVERY_PKCE_VERIFIER_COOKIE, e as SM_LEDVERY_STATE_COOKIE, f as createLedveryRoutes, g as getLedverySession } from '../ledvery-CxPzZpxP.mjs';
|
|
4
5
|
import { NextRequest, NextResponse } from 'next/server';
|
|
5
6
|
import '@scalemule/money';
|
|
6
7
|
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { S as ServerConfig } from '../webhook-handler-
|
|
2
|
-
export { a as ScaleMuleServer, V as VideoFailedEvent, b as VideoReadyEvent, c as VideoTranscodedEvent, d as VideoUploadedEvent, W as WebhookEvent, e as WebhookRoutesConfig, f as createServerClient, g as createWebhookHandler, h as createWebhookRoutes, p as parseWebhookEvent, r as registerVideoWebhook, i as resolveGatewayUrl, v as verifyWebhookSignature } from '../webhook-handler-
|
|
3
|
-
import { p as ClientContext, A as ApiError } from '../index-
|
|
1
|
+
import { S as ServerConfig } from '../webhook-handler-C07AK4QB.js';
|
|
2
|
+
export { a as ScaleMuleServer, V as VideoFailedEvent, b as VideoReadyEvent, c as VideoTranscodedEvent, d as VideoUploadedEvent, W as WebhookEvent, e as WebhookRoutesConfig, f as createServerClient, g as createWebhookHandler, h as createWebhookRoutes, p as parseWebhookEvent, r as registerVideoWebhook, i as resolveGatewayUrl, v as verifyWebhookSignature } from '../webhook-handler-C07AK4QB.js';
|
|
3
|
+
import { p as ClientContext, A as ApiError } from '../index-DTWyUcyd.js';
|
|
4
|
+
export { L as LedveryRoutesConfig, a as LedverySessionData, S as SM_LEDVERY_ACCESS_TOKEN_COOKIE, b as SM_LEDVERY_ID_TOKEN_COOKIE, c as SM_LEDVERY_NONCE_COOKIE, d as SM_LEDVERY_PKCE_VERIFIER_COOKIE, e as SM_LEDVERY_STATE_COOKIE, f as createLedveryRoutes, g as getLedverySession } from '../ledvery-CxPzZpxP.js';
|
|
4
5
|
import { NextRequest, NextResponse } from 'next/server';
|
|
5
6
|
import '@scalemule/money';
|
|
6
7
|
|
package/dist/server/index.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var money = require('@scalemule/money');
|
|
4
4
|
var headers = require('next/headers');
|
|
5
5
|
var server = require('next/server');
|
|
6
|
+
var ledvery = require('@scalemule/ledvery');
|
|
6
7
|
var crypto$1 = require('crypto');
|
|
7
8
|
|
|
8
9
|
var __create = Object.create;
|
|
@@ -1918,11 +1919,12 @@ var require_semver2 = __commonJS({
|
|
|
1918
1919
|
|
|
1919
1920
|
// src/types/index.ts
|
|
1920
1921
|
var ScaleMuleApiError = class extends Error {
|
|
1921
|
-
constructor(error) {
|
|
1922
|
+
constructor(error, status) {
|
|
1922
1923
|
super(error.message);
|
|
1923
1924
|
this.name = "ScaleMuleApiError";
|
|
1924
1925
|
this.code = error.code;
|
|
1925
1926
|
this.field = error.field;
|
|
1927
|
+
this.status = status;
|
|
1926
1928
|
}
|
|
1927
1929
|
};
|
|
1928
1930
|
|
|
@@ -3780,6 +3782,323 @@ function createAnalyticsRoutes(config = {}) {
|
|
|
3780
3782
|
return { POST };
|
|
3781
3783
|
}
|
|
3782
3784
|
|
|
3785
|
+
// src/server/ledvery-cookies.ts
|
|
3786
|
+
var SM_LEDVERY_STATE_COOKIE = "sm_ledvery_state";
|
|
3787
|
+
var SM_LEDVERY_PKCE_VERIFIER_COOKIE = "sm_ledvery_pkce_verifier";
|
|
3788
|
+
var SM_LEDVERY_NONCE_COOKIE = "sm_ledvery_nonce";
|
|
3789
|
+
var SM_LEDVERY_ID_TOKEN_COOKIE = "sm_ledvery_id_token";
|
|
3790
|
+
var SM_LEDVERY_ACCESS_TOKEN_COOKIE = "sm_ledvery_access_token";
|
|
3791
|
+
var FLOW_COOKIE_MAX_AGE = 60 * 10;
|
|
3792
|
+
var SESSION_COOKIE_MAX_AGE = 60 * 60;
|
|
3793
|
+
function flowCookieOptions() {
|
|
3794
|
+
return {
|
|
3795
|
+
httpOnly: true,
|
|
3796
|
+
secure: process.env.NODE_ENV === "production",
|
|
3797
|
+
sameSite: "lax",
|
|
3798
|
+
path: "/",
|
|
3799
|
+
maxAge: FLOW_COOKIE_MAX_AGE
|
|
3800
|
+
};
|
|
3801
|
+
}
|
|
3802
|
+
function sessionCookieOptions(maxAge) {
|
|
3803
|
+
return {
|
|
3804
|
+
httpOnly: true,
|
|
3805
|
+
secure: process.env.NODE_ENV === "production",
|
|
3806
|
+
sameSite: "lax",
|
|
3807
|
+
path: "/",
|
|
3808
|
+
maxAge: maxAge ? Math.min(maxAge, SESSION_COOKIE_MAX_AGE) : SESSION_COOKIE_MAX_AGE
|
|
3809
|
+
};
|
|
3810
|
+
}
|
|
3811
|
+
function setLedveryFlowCookies(response, params) {
|
|
3812
|
+
const opts = flowCookieOptions();
|
|
3813
|
+
setCookie(response, SM_LEDVERY_STATE_COOKIE, params.state, opts);
|
|
3814
|
+
setCookie(response, SM_LEDVERY_PKCE_VERIFIER_COOKIE, params.codeVerifier, opts);
|
|
3815
|
+
setCookie(response, SM_LEDVERY_NONCE_COOKIE, params.nonce, opts);
|
|
3816
|
+
}
|
|
3817
|
+
function validateAndConsumeLedveryFlowCookies(request, callbackState) {
|
|
3818
|
+
const cookieState = getCookie(request, SM_LEDVERY_STATE_COOKIE);
|
|
3819
|
+
const codeVerifier = getCookie(request, SM_LEDVERY_PKCE_VERIFIER_COOKIE);
|
|
3820
|
+
const nonce = getCookie(request, SM_LEDVERY_NONCE_COOKIE);
|
|
3821
|
+
if (!cookieState) return "Missing Ledvery state cookie - session may have expired";
|
|
3822
|
+
if (!callbackState) return "Missing state parameter in callback";
|
|
3823
|
+
if (!constantTimeEqual(cookieState, callbackState)) return "Ledvery state mismatch - possible CSRF attack";
|
|
3824
|
+
if (!codeVerifier) return "Missing PKCE verifier cookie";
|
|
3825
|
+
if (!nonce) return "Missing nonce cookie";
|
|
3826
|
+
return { codeVerifier, nonce };
|
|
3827
|
+
}
|
|
3828
|
+
function setLedverySession(response, session, opts) {
|
|
3829
|
+
const cookieOpts = sessionCookieOptions(opts?.cookies?.maxAge);
|
|
3830
|
+
if (opts?.cookies?.domain) cookieOpts.domain = opts.cookies.domain;
|
|
3831
|
+
if (opts?.cookies?.path) cookieOpts.path = opts.cookies.path;
|
|
3832
|
+
if (opts?.cookies?.sameSite) cookieOpts.sameSite = opts.cookies.sameSite;
|
|
3833
|
+
if (opts?.cookies?.secure !== void 0) cookieOpts.secure = opts.cookies.secure;
|
|
3834
|
+
const sessionPayload = JSON.stringify({
|
|
3835
|
+
claims: session.claims,
|
|
3836
|
+
expiresAt: session.expiresAt
|
|
3837
|
+
});
|
|
3838
|
+
setCookie(response, SM_LEDVERY_ID_TOKEN_COOKIE, sessionPayload, cookieOpts);
|
|
3839
|
+
if (opts?.storeAccessToken && session.accessToken) {
|
|
3840
|
+
setCookie(response, SM_LEDVERY_ACCESS_TOKEN_COOKIE, session.accessToken, cookieOpts);
|
|
3841
|
+
}
|
|
3842
|
+
}
|
|
3843
|
+
function getLedverySession(request) {
|
|
3844
|
+
const raw = getCookie(request, SM_LEDVERY_ID_TOKEN_COOKIE);
|
|
3845
|
+
if (!raw) return null;
|
|
3846
|
+
try {
|
|
3847
|
+
const parsed = JSON.parse(raw);
|
|
3848
|
+
return {
|
|
3849
|
+
idToken: "",
|
|
3850
|
+
// not stored in cookie for size
|
|
3851
|
+
claims: parsed.claims,
|
|
3852
|
+
expiresAt: parsed.expiresAt
|
|
3853
|
+
};
|
|
3854
|
+
} catch {
|
|
3855
|
+
return null;
|
|
3856
|
+
}
|
|
3857
|
+
}
|
|
3858
|
+
function clearLedverySession(response) {
|
|
3859
|
+
deleteCookie(response, SM_LEDVERY_ID_TOKEN_COOKIE);
|
|
3860
|
+
deleteCookie(response, SM_LEDVERY_ACCESS_TOKEN_COOKIE);
|
|
3861
|
+
}
|
|
3862
|
+
function clearLedveryFlowCookies(response) {
|
|
3863
|
+
deleteCookie(response, SM_LEDVERY_STATE_COOKIE);
|
|
3864
|
+
deleteCookie(response, SM_LEDVERY_PKCE_VERIFIER_COOKIE);
|
|
3865
|
+
deleteCookie(response, SM_LEDVERY_NONCE_COOKIE);
|
|
3866
|
+
}
|
|
3867
|
+
function getCookie(request, name) {
|
|
3868
|
+
const header = request.headers.get("cookie") || "";
|
|
3869
|
+
const match = header.match(new RegExp(`(?:^|;\\s*)${name}=([^;]*)`));
|
|
3870
|
+
return match ? decodeURIComponent(match[1]) : void 0;
|
|
3871
|
+
}
|
|
3872
|
+
function setCookie(response, name, value, opts) {
|
|
3873
|
+
const parts = [
|
|
3874
|
+
`${name}=${encodeURIComponent(value)}`,
|
|
3875
|
+
`Path=${opts.path}`,
|
|
3876
|
+
`Max-Age=${opts.maxAge}`,
|
|
3877
|
+
`SameSite=${opts.sameSite.charAt(0).toUpperCase() + opts.sameSite.slice(1)}`
|
|
3878
|
+
];
|
|
3879
|
+
if (opts.httpOnly) parts.push("HttpOnly");
|
|
3880
|
+
if (opts.secure) parts.push("Secure");
|
|
3881
|
+
if (opts.domain) parts.push(`Domain=${opts.domain}`);
|
|
3882
|
+
response.headers.append("Set-Cookie", parts.join("; "));
|
|
3883
|
+
}
|
|
3884
|
+
function deleteCookie(response, name) {
|
|
3885
|
+
response.headers.append("Set-Cookie", `${name}=; Path=/; Max-Age=0; HttpOnly; SameSite=Lax`);
|
|
3886
|
+
}
|
|
3887
|
+
|
|
3888
|
+
// src/server/redirect.ts
|
|
3889
|
+
function normalizeOrigin(origin) {
|
|
3890
|
+
try {
|
|
3891
|
+
const u = new URL(origin);
|
|
3892
|
+
return `${u.protocol}//${u.host}`.toLowerCase();
|
|
3893
|
+
} catch {
|
|
3894
|
+
return null;
|
|
3895
|
+
}
|
|
3896
|
+
}
|
|
3897
|
+
function isSafeSchemeRelative(input) {
|
|
3898
|
+
return !(input.startsWith("//") || input.startsWith("\\"));
|
|
3899
|
+
}
|
|
3900
|
+
function validateSafeRedirect(input, opts = {}) {
|
|
3901
|
+
const defaultPath = opts.defaultPath ?? "/";
|
|
3902
|
+
if (!input || typeof input !== "string") return defaultPath;
|
|
3903
|
+
const trimmed = input.trim();
|
|
3904
|
+
if (!trimmed) return defaultPath;
|
|
3905
|
+
if (!isSafeSchemeRelative(trimmed)) return defaultPath;
|
|
3906
|
+
const colon = trimmed.indexOf(":");
|
|
3907
|
+
if (colon > 0 && colon < 15) {
|
|
3908
|
+
const scheme = trimmed.slice(0, colon).toLowerCase();
|
|
3909
|
+
if (/^[a-z][a-z0-9+.-]*$/.test(scheme) && scheme !== "http" && scheme !== "https") {
|
|
3910
|
+
return defaultPath;
|
|
3911
|
+
}
|
|
3912
|
+
}
|
|
3913
|
+
if (trimmed.startsWith("/")) {
|
|
3914
|
+
if (trimmed.length > 1 && trimmed[1] === "\\") return defaultPath;
|
|
3915
|
+
return trimmed;
|
|
3916
|
+
}
|
|
3917
|
+
const allowed = (opts.allowedOrigins ?? []).map(normalizeOrigin).filter((o) => o !== null);
|
|
3918
|
+
try {
|
|
3919
|
+
const parsed = new URL(trimmed);
|
|
3920
|
+
const origin = `${parsed.protocol}//${parsed.host}`.toLowerCase();
|
|
3921
|
+
if (!allowed.includes(origin)) return defaultPath;
|
|
3922
|
+
if (opts.stripSameOriginHost !== false) {
|
|
3923
|
+
return `${parsed.pathname}${parsed.search}${parsed.hash}` || "/";
|
|
3924
|
+
}
|
|
3925
|
+
return trimmed;
|
|
3926
|
+
} catch {
|
|
3927
|
+
return defaultPath;
|
|
3928
|
+
}
|
|
3929
|
+
}
|
|
3930
|
+
function isSafeRedirect(input, opts = {}) {
|
|
3931
|
+
if (!input || typeof input !== "string") return false;
|
|
3932
|
+
const defaultPath = `__unsafe_sentinel_${Math.random()}`;
|
|
3933
|
+
const resolved = validateSafeRedirect(input, { ...opts, defaultPath });
|
|
3934
|
+
return resolved !== defaultPath;
|
|
3935
|
+
}
|
|
3936
|
+
|
|
3937
|
+
// src/server/ledvery.ts
|
|
3938
|
+
function createLedveryRoutes(config) {
|
|
3939
|
+
const client = new ledvery.LedveryClient({
|
|
3940
|
+
issuer: config.issuer,
|
|
3941
|
+
clientId: config.clientId,
|
|
3942
|
+
clientSecret: config.clientSecret,
|
|
3943
|
+
redirectUri: config.redirectUri,
|
|
3944
|
+
fetch: config.fetch
|
|
3945
|
+
});
|
|
3946
|
+
const postLoginRedirect = config.postLoginRedirect || "/";
|
|
3947
|
+
const postLogoutRedirect = config.postLogoutRedirect || "/";
|
|
3948
|
+
const defaultScope = config.defaultScope || "openid email profile";
|
|
3949
|
+
async function handleLogin(request) {
|
|
3950
|
+
const url = new URL(request.url);
|
|
3951
|
+
const returnTo = url.searchParams.get("returnTo");
|
|
3952
|
+
const validatedReturnTo = validateSafeRedirect(returnTo, { defaultPath: postLoginRedirect });
|
|
3953
|
+
const authResult = await client.createAuthorizationUrl({
|
|
3954
|
+
scope: defaultScope
|
|
3955
|
+
});
|
|
3956
|
+
const response = new Response(null, {
|
|
3957
|
+
status: 302,
|
|
3958
|
+
headers: { Location: authResult.url }
|
|
3959
|
+
});
|
|
3960
|
+
setLedveryFlowCookies(response, {
|
|
3961
|
+
state: authResult.state,
|
|
3962
|
+
codeVerifier: authResult.codeVerifier,
|
|
3963
|
+
nonce: authResult.nonce
|
|
3964
|
+
});
|
|
3965
|
+
if (validatedReturnTo !== postLoginRedirect) {
|
|
3966
|
+
response.headers.append(
|
|
3967
|
+
"Set-Cookie",
|
|
3968
|
+
`sm_ledvery_return_to=${encodeURIComponent(validatedReturnTo)}; Path=/; Max-Age=600; HttpOnly; SameSite=Lax${process.env.NODE_ENV === "production" ? "; Secure" : ""}`
|
|
3969
|
+
);
|
|
3970
|
+
}
|
|
3971
|
+
return response;
|
|
3972
|
+
}
|
|
3973
|
+
async function handleCallback(request) {
|
|
3974
|
+
const url = new URL(request.url);
|
|
3975
|
+
const code = url.searchParams.get("code");
|
|
3976
|
+
const callbackState = url.searchParams.get("state");
|
|
3977
|
+
if (!code) {
|
|
3978
|
+
const error = url.searchParams.get("error");
|
|
3979
|
+
const errorDesc = url.searchParams.get("error_description");
|
|
3980
|
+
return new Response(
|
|
3981
|
+
JSON.stringify({ error: error || "missing_code", message: errorDesc || "No authorization code in callback" }),
|
|
3982
|
+
{ status: 403, headers: { "Content-Type": "application/json" } }
|
|
3983
|
+
);
|
|
3984
|
+
}
|
|
3985
|
+
const flowResult = validateAndConsumeLedveryFlowCookies(request, callbackState);
|
|
3986
|
+
if (typeof flowResult === "string") {
|
|
3987
|
+
return new Response(
|
|
3988
|
+
JSON.stringify({ error: "state_mismatch", message: flowResult }),
|
|
3989
|
+
{ status: 403, headers: { "Content-Type": "application/json" } }
|
|
3990
|
+
);
|
|
3991
|
+
}
|
|
3992
|
+
let session;
|
|
3993
|
+
try {
|
|
3994
|
+
session = await client.exchangeCode({
|
|
3995
|
+
code,
|
|
3996
|
+
codeVerifier: flowResult.codeVerifier,
|
|
3997
|
+
receivedState: callbackState,
|
|
3998
|
+
expectedState: getCookieValue(request, "sm_ledvery_state"),
|
|
3999
|
+
expectedNonce: flowResult.nonce
|
|
4000
|
+
});
|
|
4001
|
+
} catch (err) {
|
|
4002
|
+
return new Response(
|
|
4003
|
+
JSON.stringify({ error: "code_exchange_failed", message: err instanceof Error ? err.message : "Code exchange failed" }),
|
|
4004
|
+
{ status: 403, headers: { "Content-Type": "application/json" } }
|
|
4005
|
+
);
|
|
4006
|
+
}
|
|
4007
|
+
const returnTo = getCookieValue(request, "sm_ledvery_return_to");
|
|
4008
|
+
const redirectTo = validateSafeRedirect(returnTo, { defaultPath: postLoginRedirect });
|
|
4009
|
+
const response = new Response(null, {
|
|
4010
|
+
status: 302,
|
|
4011
|
+
headers: { Location: redirectTo }
|
|
4012
|
+
});
|
|
4013
|
+
setLedverySession(response, {
|
|
4014
|
+
idToken: session.idToken,
|
|
4015
|
+
accessToken: session.accessToken,
|
|
4016
|
+
claims: session.claims,
|
|
4017
|
+
expiresAt: session.expiresAt.toISOString()
|
|
4018
|
+
}, {
|
|
4019
|
+
storeAccessToken: config.storeAccessToken,
|
|
4020
|
+
cookies: config.cookies
|
|
4021
|
+
});
|
|
4022
|
+
clearLedveryFlowCookies(response);
|
|
4023
|
+
response.headers.append("Set-Cookie", "sm_ledvery_return_to=; Path=/; Max-Age=0; HttpOnly; SameSite=Lax");
|
|
4024
|
+
return response;
|
|
4025
|
+
}
|
|
4026
|
+
function handleSession(request) {
|
|
4027
|
+
const session = getLedverySession(request);
|
|
4028
|
+
if (!session) {
|
|
4029
|
+
return new Response(JSON.stringify({ session: null }), {
|
|
4030
|
+
status: 200,
|
|
4031
|
+
headers: { "Content-Type": "application/json" }
|
|
4032
|
+
});
|
|
4033
|
+
}
|
|
4034
|
+
const expiresAt = new Date(session.expiresAt);
|
|
4035
|
+
if (expiresAt <= /* @__PURE__ */ new Date()) {
|
|
4036
|
+
return new Response(JSON.stringify({ session: null }), {
|
|
4037
|
+
status: 200,
|
|
4038
|
+
headers: { "Content-Type": "application/json" }
|
|
4039
|
+
});
|
|
4040
|
+
}
|
|
4041
|
+
return new Response(
|
|
4042
|
+
JSON.stringify({
|
|
4043
|
+
session: {
|
|
4044
|
+
sub: session.claims.sub,
|
|
4045
|
+
email: session.claims.email,
|
|
4046
|
+
email_verified: session.claims.email_verified,
|
|
4047
|
+
name: session.claims.name,
|
|
4048
|
+
idp: session.claims.idp,
|
|
4049
|
+
expiresAt: session.expiresAt
|
|
4050
|
+
}
|
|
4051
|
+
}),
|
|
4052
|
+
{ status: 200, headers: { "Content-Type": "application/json" } }
|
|
4053
|
+
);
|
|
4054
|
+
}
|
|
4055
|
+
function handleLogout(_request) {
|
|
4056
|
+
if (config.gatewayUrl) {
|
|
4057
|
+
const rpLogoutUrl = `${config.gatewayUrl}/v1/auth/oauth/ledvery/logout?post_logout_redirect_uri=${encodeURIComponent(postLogoutRedirect)}`;
|
|
4058
|
+
const response2 = new Response(null, {
|
|
4059
|
+
status: 302,
|
|
4060
|
+
headers: { Location: rpLogoutUrl }
|
|
4061
|
+
});
|
|
4062
|
+
clearLedverySession(response2);
|
|
4063
|
+
return response2;
|
|
4064
|
+
}
|
|
4065
|
+
const response = new Response(null, {
|
|
4066
|
+
status: 302,
|
|
4067
|
+
headers: { Location: postLogoutRedirect }
|
|
4068
|
+
});
|
|
4069
|
+
clearLedverySession(response);
|
|
4070
|
+
return response;
|
|
4071
|
+
}
|
|
4072
|
+
async function handler(request, context) {
|
|
4073
|
+
const params = await context.params;
|
|
4074
|
+
const action = params.action?.[0] || "";
|
|
4075
|
+
switch (action) {
|
|
4076
|
+
case "login":
|
|
4077
|
+
return handleLogin(request);
|
|
4078
|
+
case "callback":
|
|
4079
|
+
return handleCallback(request);
|
|
4080
|
+
case "session":
|
|
4081
|
+
return handleSession(request);
|
|
4082
|
+
case "logout":
|
|
4083
|
+
return handleLogout();
|
|
4084
|
+
default:
|
|
4085
|
+
return new Response(
|
|
4086
|
+
JSON.stringify({ error: "not_found", message: `Unknown Ledvery route: ${action}` }),
|
|
4087
|
+
{ status: 404, headers: { "Content-Type": "application/json" } }
|
|
4088
|
+
);
|
|
4089
|
+
}
|
|
4090
|
+
}
|
|
4091
|
+
return {
|
|
4092
|
+
GET: handler,
|
|
4093
|
+
POST: handler
|
|
4094
|
+
};
|
|
4095
|
+
}
|
|
4096
|
+
function getCookieValue(request, name) {
|
|
4097
|
+
const header = request.headers.get("cookie") || "";
|
|
4098
|
+
const match = header.match(new RegExp(`(?:^|;\\s*)${name}=([^;]*)`));
|
|
4099
|
+
return match ? decodeURIComponent(match[1]) : void 0;
|
|
4100
|
+
}
|
|
4101
|
+
|
|
3783
4102
|
// src/server/push.ts
|
|
3784
4103
|
function errorResponse2(code, message, status) {
|
|
3785
4104
|
return new Response(
|
|
@@ -5096,55 +5415,6 @@ async function prefetchBundles(keys) {
|
|
|
5096
5415
|
await Promise.all(keys.map((key) => getBundle(key)));
|
|
5097
5416
|
}
|
|
5098
5417
|
|
|
5099
|
-
// src/server/redirect.ts
|
|
5100
|
-
function normalizeOrigin(origin) {
|
|
5101
|
-
try {
|
|
5102
|
-
const u = new URL(origin);
|
|
5103
|
-
return `${u.protocol}//${u.host}`.toLowerCase();
|
|
5104
|
-
} catch {
|
|
5105
|
-
return null;
|
|
5106
|
-
}
|
|
5107
|
-
}
|
|
5108
|
-
function isSafeSchemeRelative(input) {
|
|
5109
|
-
return !(input.startsWith("//") || input.startsWith("\\"));
|
|
5110
|
-
}
|
|
5111
|
-
function validateSafeRedirect(input, opts = {}) {
|
|
5112
|
-
const defaultPath = opts.defaultPath ?? "/";
|
|
5113
|
-
if (!input || typeof input !== "string") return defaultPath;
|
|
5114
|
-
const trimmed = input.trim();
|
|
5115
|
-
if (!trimmed) return defaultPath;
|
|
5116
|
-
if (!isSafeSchemeRelative(trimmed)) return defaultPath;
|
|
5117
|
-
const colon = trimmed.indexOf(":");
|
|
5118
|
-
if (colon > 0 && colon < 15) {
|
|
5119
|
-
const scheme = trimmed.slice(0, colon).toLowerCase();
|
|
5120
|
-
if (/^[a-z][a-z0-9+.-]*$/.test(scheme) && scheme !== "http" && scheme !== "https") {
|
|
5121
|
-
return defaultPath;
|
|
5122
|
-
}
|
|
5123
|
-
}
|
|
5124
|
-
if (trimmed.startsWith("/")) {
|
|
5125
|
-
if (trimmed.length > 1 && trimmed[1] === "\\") return defaultPath;
|
|
5126
|
-
return trimmed;
|
|
5127
|
-
}
|
|
5128
|
-
const allowed = (opts.allowedOrigins ?? []).map(normalizeOrigin).filter((o) => o !== null);
|
|
5129
|
-
try {
|
|
5130
|
-
const parsed = new URL(trimmed);
|
|
5131
|
-
const origin = `${parsed.protocol}//${parsed.host}`.toLowerCase();
|
|
5132
|
-
if (!allowed.includes(origin)) return defaultPath;
|
|
5133
|
-
if (opts.stripSameOriginHost !== false) {
|
|
5134
|
-
return `${parsed.pathname}${parsed.search}${parsed.hash}` || "/";
|
|
5135
|
-
}
|
|
5136
|
-
return trimmed;
|
|
5137
|
-
} catch {
|
|
5138
|
-
return defaultPath;
|
|
5139
|
-
}
|
|
5140
|
-
}
|
|
5141
|
-
function isSafeRedirect(input, opts = {}) {
|
|
5142
|
-
if (!input || typeof input !== "string") return false;
|
|
5143
|
-
const defaultPath = `__unsafe_sentinel_${Math.random()}`;
|
|
5144
|
-
const resolved = validateSafeRedirect(input, { ...opts, defaultPath });
|
|
5145
|
-
return resolved !== defaultPath;
|
|
5146
|
-
}
|
|
5147
|
-
|
|
5148
5418
|
// src/server/security-headers.ts
|
|
5149
5419
|
var DEFAULT_PERMISSIONS_POLICY = {
|
|
5150
5420
|
// Conference track features — allow self-origin only.
|
|
@@ -5219,6 +5489,11 @@ exports.DEFAULT_PERMISSIONS_POLICY = DEFAULT_PERMISSIONS_POLICY;
|
|
|
5219
5489
|
exports.KNOWN_ACCOUNTS_COOKIE_NAME = KNOWN_ACCOUNTS_COOKIE_NAME;
|
|
5220
5490
|
exports.OAUTH_STATE_COOKIE_NAME = OAUTH_STATE_COOKIE_NAME;
|
|
5221
5491
|
exports.SESSION_COOKIE_NAME = SESSION_COOKIE_NAME;
|
|
5492
|
+
exports.SM_LEDVERY_ACCESS_TOKEN_COOKIE = SM_LEDVERY_ACCESS_TOKEN_COOKIE;
|
|
5493
|
+
exports.SM_LEDVERY_ID_TOKEN_COOKIE = SM_LEDVERY_ID_TOKEN_COOKIE;
|
|
5494
|
+
exports.SM_LEDVERY_NONCE_COOKIE = SM_LEDVERY_NONCE_COOKIE;
|
|
5495
|
+
exports.SM_LEDVERY_PKCE_VERIFIER_COOKIE = SM_LEDVERY_PKCE_VERIFIER_COOKIE;
|
|
5496
|
+
exports.SM_LEDVERY_STATE_COOKIE = SM_LEDVERY_STATE_COOKIE;
|
|
5222
5497
|
exports.ScaleMuleError = ScaleMuleError;
|
|
5223
5498
|
exports.ScaleMuleServer = ScaleMuleServer;
|
|
5224
5499
|
exports.USER_ID_COOKIE_NAME = USER_ID_COOKIE_NAME;
|
|
@@ -5235,6 +5510,7 @@ exports.configureSecrets = configureSecrets;
|
|
|
5235
5510
|
exports.createAnalyticsRoutes = createAnalyticsRoutes;
|
|
5236
5511
|
exports.createAuthMiddleware = createAuthMiddleware;
|
|
5237
5512
|
exports.createAuthRoutes = createAuthRoutes;
|
|
5513
|
+
exports.createLedveryRoutes = createLedveryRoutes;
|
|
5238
5514
|
exports.createNotificationRoutes = createNotificationRoutes;
|
|
5239
5515
|
exports.createPushRoutes = createPushRoutes;
|
|
5240
5516
|
exports.createServerClient = createServerClient;
|
|
@@ -5251,6 +5527,7 @@ exports.getBundle = getBundle;
|
|
|
5251
5527
|
exports.getCSRFToken = getCSRFToken;
|
|
5252
5528
|
exports.getKnownAccountsCookieRaw = getKnownAccountsCookieRaw;
|
|
5253
5529
|
exports.getKnownAccountsFromRequest = getKnownAccountsFromRequest;
|
|
5530
|
+
exports.getLedverySession = getLedverySession;
|
|
5254
5531
|
exports.getMySqlBundle = getMySqlBundle;
|
|
5255
5532
|
exports.getOAuthBundle = getOAuthBundle;
|
|
5256
5533
|
exports.getPostgresBundle = getPostgresBundle;
|