faire-auth 1.0.0
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/LICENSE +661 -0
- package/README.md +34 -0
- package/dist/access-B5bBI4uT.mjs +39 -0
- package/dist/access-Crt-IJ2P.cjs +51 -0
- package/dist/adapter-factory-BXei1QRX.mjs +881 -0
- package/dist/adapter-factory-DT-_2aHJ.cjs +893 -0
- package/dist/adapters/drizzle-adapter/index.cjs +208 -0
- package/dist/adapters/drizzle-adapter/index.d.cts +48 -0
- package/dist/adapters/drizzle-adapter/index.d.mts +48 -0
- package/dist/adapters/drizzle-adapter/index.mjs +207 -0
- package/dist/adapters/index.cjs +23 -0
- package/dist/adapters/index.d.cts +157 -0
- package/dist/adapters/index.d.mts +157 -0
- package/dist/adapters/index.mjs +17 -0
- package/dist/adapters/kysely-adapter/index.cjs +11 -0
- package/dist/adapters/kysely-adapter/index.d.cts +52 -0
- package/dist/adapters/kysely-adapter/index.d.mts +52 -0
- package/dist/adapters/kysely-adapter/index.mjs +9 -0
- package/dist/adapters/memory-adapter/index.cjs +9 -0
- package/dist/adapters/memory-adapter/index.d.cts +15 -0
- package/dist/adapters/memory-adapter/index.d.mts +15 -0
- package/dist/adapters/memory-adapter/index.mjs +9 -0
- package/dist/adapters/mongodb-adapter/index.cjs +9 -0
- package/dist/adapters/mongodb-adapter/index.d.cts +4 -0
- package/dist/adapters/mongodb-adapter/index.d.mts +4 -0
- package/dist/adapters/mongodb-adapter/index.mjs +9 -0
- package/dist/adapters/prisma-adapter/index.cjs +156 -0
- package/dist/adapters/prisma-adapter/index.d.cts +35 -0
- package/dist/adapters/prisma-adapter/index.d.mts +35 -0
- package/dist/adapters/prisma-adapter/index.mjs +155 -0
- package/dist/adapters/test.cjs +797 -0
- package/dist/adapters/test.d.cts +82 -0
- package/dist/adapters/test.d.mts +82 -0
- package/dist/adapters/test.mjs +793 -0
- package/dist/api/index.cjs +20 -0
- package/dist/api/index.d.cts +3 -0
- package/dist/api/index.d.mts +3 -0
- package/dist/api/index.mjs +20 -0
- package/dist/api/middleware/index.cjs +16 -0
- package/dist/api/middleware/index.d.cts +16 -0
- package/dist/api/middleware/index.d.mts +16 -0
- package/dist/api/middleware/index.mjs +11 -0
- package/dist/api-Bm89BLgN.cjs +1899 -0
- package/dist/api-_B7qO28y.mjs +1892 -0
- package/dist/auth-Bo9PDt5j.cjs +739 -0
- package/dist/auth-Ds4AG4h4.mjs +709 -0
- package/dist/bearer-0SeEmaS4.mjs +54 -0
- package/dist/bearer-CHeREcGT.cjs +60 -0
- package/dist/bun-sqlite-dialect-CfkBo2v5.mjs +155 -0
- package/dist/bun-sqlite-dialect-wuaC2-gh.cjs +156 -0
- package/dist/chunk-Ceigfy4P.mjs +39 -0
- package/dist/chunk-oakRccI5.cjs +60 -0
- package/dist/client/index.cjs +22 -0
- package/dist/client/index.d.cts +8 -0
- package/dist/client/index.d.mts +8 -0
- package/dist/client/index.mjs +19 -0
- package/dist/client/lynx/index.cjs +79 -0
- package/dist/client/lynx/index.d.cts +156 -0
- package/dist/client/lynx/index.d.mts +156 -0
- package/dist/client/lynx/index.mjs +76 -0
- package/dist/client/plugins/index.cjs +11 -0
- package/dist/client/plugins/index.d.cts +17 -0
- package/dist/client/plugins/index.d.mts +17 -0
- package/dist/client/plugins/index.mjs +10 -0
- package/dist/client/react/index.cjs +79 -0
- package/dist/client/react/index.d.cts +156 -0
- package/dist/client/react/index.d.mts +156 -0
- package/dist/client/react/index.mjs +76 -0
- package/dist/client/solid/index.cjs +51 -0
- package/dist/client/solid/index.d.cts +90 -0
- package/dist/client/solid/index.d.mts +90 -0
- package/dist/client/solid/index.mjs +50 -0
- package/dist/client/svelte/index.cjs +28 -0
- package/dist/client/svelte/index.d.cts +110 -0
- package/dist/client/svelte/index.d.mts +110 -0
- package/dist/client/svelte/index.mjs +28 -0
- package/dist/client/vue/index.cjs +68 -0
- package/dist/client/vue/index.d.cts +123 -0
- package/dist/client/vue/index.d.mts +123 -0
- package/dist/client/vue/index.mjs +67 -0
- package/dist/cookies-B5xeA6i8.cjs +456 -0
- package/dist/cookies-Ch1JfQIz.mjs +367 -0
- package/dist/crypto/index.cjs +11 -0
- package/dist/crypto/index.d.cts +22 -0
- package/dist/crypto/index.d.mts +22 -0
- package/dist/crypto/index.mjs +5 -0
- package/dist/crypto-CcTxYH82.cjs +57 -0
- package/dist/crypto-CyQRFtkq.mjs +41 -0
- package/dist/db/index.cjs +40 -0
- package/dist/db/index.d.cts +4 -0
- package/dist/db/index.d.mts +4 -0
- package/dist/db/index.mjs +16 -0
- package/dist/db-BTKyYu-_.cjs +1180 -0
- package/dist/db-xiJtoDgz.mjs +1119 -0
- package/dist/defu-B0Svx_x4.cjs +34 -0
- package/dist/defu-SZkpHhbR.mjs +28 -0
- package/dist/email-verification-C-AsfJsb.cjs +247 -0
- package/dist/email-verification-CWhj2qfb.mjs +228 -0
- package/dist/hono-BEq1NYVX.cjs +526 -0
- package/dist/hono-Cdukwu5K.cjs +13 -0
- package/dist/hono-CoKYWnXA.mjs +7 -0
- package/dist/hono-Covz10jU.mjs +508 -0
- package/dist/hono-DOM31WQz.d.cts +18 -0
- package/dist/hono-DuE14mmj.d.mts +18 -0
- package/dist/index-B-WeOMzg.d.cts +13350 -0
- package/dist/index-B09P9p5_.d.cts +33 -0
- package/dist/index-B5_0QTLg.d.mts +3 -0
- package/dist/index-B7SKyR_a.d.cts +3 -0
- package/dist/index-BVHscLQl.d.cts +992 -0
- package/dist/index-C2-2QDyS.d.cts +35 -0
- package/dist/index-CTwrVluH.d.mts +41 -0
- package/dist/index-CWAqWfoZ.d.cts +27 -0
- package/dist/index-CYSShrFx.d.mts +27 -0
- package/dist/index-Qu-iJGNr.d.mts +992 -0
- package/dist/index-cs4Sh0En.d.cts +41 -0
- package/dist/index-jlessPI0.d.mts +13350 -0
- package/dist/index-ppgcFe12.d.mts +33 -0
- package/dist/index-to0RO38U.d.mts +35 -0
- package/dist/index.cjs +85 -0
- package/dist/index.d.cts +5 -0
- package/dist/index.d.mts +5 -0
- package/dist/index.mjs +27 -0
- package/dist/integrations/next-js.cjs +50 -0
- package/dist/integrations/next-js.d.cts +23 -0
- package/dist/integrations/next-js.d.mts +23 -0
- package/dist/integrations/next-js.mjs +49 -0
- package/dist/integrations/node.cjs +139 -0
- package/dist/integrations/node.d.cts +22 -0
- package/dist/integrations/node.d.mts +22 -0
- package/dist/integrations/node.mjs +134 -0
- package/dist/integrations/react-start.cjs +37 -0
- package/dist/integrations/react-start.d.cts +17 -0
- package/dist/integrations/react-start.d.mts +17 -0
- package/dist/integrations/react-start.mjs +37 -0
- package/dist/integrations/solid-start.cjs +14 -0
- package/dist/integrations/solid-start.d.cts +13 -0
- package/dist/integrations/solid-start.d.mts +13 -0
- package/dist/integrations/solid-start.mjs +13 -0
- package/dist/integrations/svelte-kit.cjs +52 -0
- package/dist/integrations/svelte-kit.d.cts +42 -0
- package/dist/integrations/svelte-kit.d.mts +42 -0
- package/dist/integrations/svelte-kit.mjs +49 -0
- package/dist/ip-B5SwXaMB.cjs +54 -0
- package/dist/ip-BjNYspCH.mjs +36 -0
- package/dist/json-B1v2qRTQ.mjs +24 -0
- package/dist/json-CcJ2HjGo.cjs +30 -0
- package/dist/kysely-adapter-Bxi7sPdG.cjs +288 -0
- package/dist/kysely-adapter-DRuoT_X8.mjs +270 -0
- package/dist/logged-CyGfp8_H.mjs +187 -0
- package/dist/logged-DQK3C64b.cjs +193 -0
- package/dist/memory-adapter-BlnDIAAX.cjs +154 -0
- package/dist/memory-adapter-Db3tsJTn.mjs +148 -0
- package/dist/middleware-CE6OhDkq.mjs +29 -0
- package/dist/middleware-CWvRH4EW.cjs +47 -0
- package/dist/mongodb-adapter-C_qGQED5.mjs +291 -0
- package/dist/mongodb-adapter-C_qfK87x.cjs +297 -0
- package/dist/node-sqlite-dialect-BfBzyOAg.mjs +155 -0
- package/dist/node-sqlite-dialect-mJWC8LWQ.cjs +156 -0
- package/dist/oauth2/index.cjs +25 -0
- package/dist/oauth2/index.d.cts +42 -0
- package/dist/oauth2/index.d.mts +42 -0
- package/dist/oauth2/index.mjs +16 -0
- package/dist/oauth2-B8M0lW9l.mjs +159 -0
- package/dist/oauth2-BLeOEi7Y.cjs +177 -0
- package/dist/origin-check-8Gajklvh.mjs +228 -0
- package/dist/origin-check-id9lTnqZ.cjs +246 -0
- package/dist/parser-CdncAl9i.cjs +83 -0
- package/dist/parser-CeAer-RM.mjs +71 -0
- package/dist/passkey-B6N20LSS.cjs +512 -0
- package/dist/passkey-DJsR_GX3.mjs +505 -0
- package/dist/plugins/access/index.cjs +4 -0
- package/dist/plugins/access/index.d.cts +2 -0
- package/dist/plugins/access/index.d.mts +2 -0
- package/dist/plugins/access/index.mjs +3 -0
- package/dist/plugins/bearer/index.cjs +7 -0
- package/dist/plugins/bearer/index.d.cts +4 -0
- package/dist/plugins/bearer/index.d.mts +4 -0
- package/dist/plugins/bearer/index.mjs +7 -0
- package/dist/plugins/index.cjs +49 -0
- package/dist/plugins/index.d.cts +9326 -0
- package/dist/plugins/index.d.mts +9326 -0
- package/dist/plugins/index.mjs +26 -0
- package/dist/plugins/passkey/index.cjs +15 -0
- package/dist/plugins/passkey/index.d.cts +4 -0
- package/dist/plugins/passkey/index.d.mts +4 -0
- package/dist/plugins/passkey/index.mjs +15 -0
- package/dist/plugins-C1lm2Wj3.cjs +5254 -0
- package/dist/plugins-Dai1QkRU.mjs +5199 -0
- package/dist/request-1NL_1lyJ.mjs +58 -0
- package/dist/request-CPNlp-DK.cjs +100 -0
- package/dist/schema-D-qjygfE.cjs +179 -0
- package/dist/schema-DTIwLLmf.mjs +125 -0
- package/dist/session-De9POJTW.cjs +641 -0
- package/dist/session-rH8ougDl.mjs +538 -0
- package/dist/social-providers/index.cjs +10 -0
- package/dist/social-providers/index.d.cts +2 -0
- package/dist/social-providers/index.d.mts +2 -0
- package/dist/social-providers/index.mjs +5 -0
- package/dist/social-providers-DcFNUT0S.cjs +13 -0
- package/dist/social-providers-DoYJhBe3.mjs +9 -0
- package/dist/state--f7fwIGh.cjs +99 -0
- package/dist/state-CqJfCIl9.mjs +86 -0
- package/dist/test-utils/index.cjs +27492 -0
- package/dist/test-utils/index.d.cts +4584 -0
- package/dist/test-utils/index.d.mts +4584 -0
- package/dist/test-utils/index.mjs +27490 -0
- package/dist/types/index.cjs +0 -0
- package/dist/types/index.d.cts +3 -0
- package/dist/types/index.d.mts +3 -0
- package/dist/types/index.mjs +1 -0
- package/dist/url-BoUuoIwZ.mjs +88 -0
- package/dist/url-D2yvKaM7.cjs +118 -0
- package/dist/utils/cookies.cjs +51 -0
- package/dist/utils/cookies.d.cts +179 -0
- package/dist/utils/cookies.d.mts +179 -0
- package/dist/utils/cookies.mjs +7 -0
- package/dist/utils-44aDDP8f.cjs +2 -0
- package/dist/utils-D4vZd1-9.mjs +4 -0
- package/dist/vanilla-Bu2PmFzE.cjs +30 -0
- package/dist/vanilla-TfHqeiC7.mjs +25 -0
- package/package.json +470 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
const require_chunk = require('./chunk-oakRccI5.cjs');
|
|
2
|
+
const require_crypto = require('./crypto-CcTxYH82.cjs');
|
|
3
|
+
const require_email_verification = require('./email-verification-C-AsfJsb.cjs');
|
|
4
|
+
let __faire_auth_core_env = require("@faire-auth/core/env");
|
|
5
|
+
let __faire_auth_core_error = require("@faire-auth/core/error");
|
|
6
|
+
|
|
7
|
+
//#region src/oauth2/utils.ts
|
|
8
|
+
const decryptOAuthToken = (token, ctx, options) => {
|
|
9
|
+
if (!token) return token;
|
|
10
|
+
if (options.account?.encryptOAuthTokens) return (0, require_crypto.crypto_exports.symmetricDecrypt)({
|
|
11
|
+
key: ctx.get("context").secret,
|
|
12
|
+
data: token
|
|
13
|
+
});
|
|
14
|
+
return token;
|
|
15
|
+
};
|
|
16
|
+
const setTokenUtil = (token, ctx, options) => {
|
|
17
|
+
if (options.account?.encryptOAuthTokens && token) return (0, require_crypto.crypto_exports.symmetricEncrypt)({
|
|
18
|
+
key: ctx.get("context").secret,
|
|
19
|
+
data: token
|
|
20
|
+
});
|
|
21
|
+
return token;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/oauth2/link-account.ts
|
|
26
|
+
const handleOAuthUserInfo = async (ctx, { userInfo, account, callbackURL, disableSignUp, overrideUserInfo }, options) => {
|
|
27
|
+
const context = ctx.get("context");
|
|
28
|
+
const redirectOnError = (reason) => {
|
|
29
|
+
const errorURL = options.onAPIError?.errorURL ?? `${context.baseURL}/error`;
|
|
30
|
+
return {
|
|
31
|
+
type: "redirect",
|
|
32
|
+
response: ctx.redirect(`${errorURL}?error=${reason}`, 302)
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
const dbUser = await context.internalAdapter.findOAuthUser(userInfo.email.toLowerCase(), account.accountId, account.providerId).catch((e) => {
|
|
36
|
+
__faire_auth_core_env.logger.error("Better auth was unable to query your database.\nError: ", e);
|
|
37
|
+
return "error";
|
|
38
|
+
});
|
|
39
|
+
if (dbUser === "error") return redirectOnError("internal_server_error");
|
|
40
|
+
let user = dbUser?.user ?? null;
|
|
41
|
+
const isRegister = user == null;
|
|
42
|
+
if (dbUser) {
|
|
43
|
+
const hasBeenLinked = dbUser.accounts.find((a) => a.providerId === account.providerId && a.accountId === account.accountId);
|
|
44
|
+
if (!hasBeenLinked) {
|
|
45
|
+
if (!(options.account?.accountLinking?.trustedProviders)?.includes(account.providerId) && !userInfo.emailVerified || options.account?.accountLinking?.enabled === false) {
|
|
46
|
+
if ((0, __faire_auth_core_env.isDevelopment)()) __faire_auth_core_env.logger.warn(`User already exist but account isn't linked to ${account.providerId}. To read more about how account linking works in Faire Auth see https://www.faire-auth.com/docs/concepts/users-accounts#account-linking.`);
|
|
47
|
+
return {
|
|
48
|
+
type: "error",
|
|
49
|
+
reason: "account_not_linked"
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
await context.internalAdapter.linkAccount({
|
|
54
|
+
providerId: account.providerId,
|
|
55
|
+
accountId: userInfo.id.toString(),
|
|
56
|
+
userId: dbUser.user.id,
|
|
57
|
+
accessToken: await setTokenUtil(account.accessToken, ctx, options),
|
|
58
|
+
refreshToken: await setTokenUtil(account.refreshToken, ctx, options),
|
|
59
|
+
idToken: account.idToken,
|
|
60
|
+
accessTokenExpiresAt: account.accessTokenExpiresAt,
|
|
61
|
+
refreshTokenExpiresAt: account.refreshTokenExpiresAt,
|
|
62
|
+
scope: account.scope
|
|
63
|
+
});
|
|
64
|
+
} catch (e) {
|
|
65
|
+
__faire_auth_core_env.logger.error("Unable to link account", e);
|
|
66
|
+
return {
|
|
67
|
+
type: "error",
|
|
68
|
+
reason: "unable_to_link_account"
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
if (userInfo.emailVerified && !dbUser.user.emailVerified && userInfo.email.toLowerCase() === dbUser.user.email) await context.internalAdapter.updateUser(dbUser.user.id, { emailVerified: true });
|
|
72
|
+
} else {
|
|
73
|
+
if (options.account?.updateAccountOnSignIn !== false) {
|
|
74
|
+
const updateData = Object.fromEntries(Object.entries({
|
|
75
|
+
idToken: account.idToken,
|
|
76
|
+
accessToken: await setTokenUtil(account.accessToken, ctx, options),
|
|
77
|
+
refreshToken: await setTokenUtil(account.refreshToken, ctx, options),
|
|
78
|
+
accessTokenExpiresAt: account.accessTokenExpiresAt,
|
|
79
|
+
refreshTokenExpiresAt: account.refreshTokenExpiresAt,
|
|
80
|
+
scope: account.scope
|
|
81
|
+
}).filter(([, value]) => value !== void 0 && value !== ""));
|
|
82
|
+
if (Object.keys(updateData).length > 0) await context.internalAdapter.updateAccount(hasBeenLinked.id, updateData);
|
|
83
|
+
}
|
|
84
|
+
if (userInfo.emailVerified && !dbUser.user.emailVerified && userInfo.email.toLowerCase() === dbUser.user.email) await context.internalAdapter.updateUser(dbUser.user.id, { emailVerified: true });
|
|
85
|
+
}
|
|
86
|
+
if (overrideUserInfo === true) {
|
|
87
|
+
const { id: _,...restUserInfo } = userInfo;
|
|
88
|
+
await context.internalAdapter.updateUser(dbUser.user.id, {
|
|
89
|
+
...restUserInfo,
|
|
90
|
+
email: userInfo.email.toLowerCase(),
|
|
91
|
+
emailVerified: userInfo.email.toLowerCase() === dbUser.user.email ? dbUser.user.emailVerified || userInfo.emailVerified : userInfo.emailVerified
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
if (disableSignUp === true) return {
|
|
96
|
+
type: "error",
|
|
97
|
+
reason: "signup_disabled",
|
|
98
|
+
isRegister: false
|
|
99
|
+
};
|
|
100
|
+
try {
|
|
101
|
+
const { id: _,...restUserInfo } = userInfo;
|
|
102
|
+
user = await context.internalAdapter.createOAuthUser({
|
|
103
|
+
...restUserInfo,
|
|
104
|
+
email: userInfo.email.toLowerCase()
|
|
105
|
+
}, {
|
|
106
|
+
accessToken: await setTokenUtil(account.accessToken, ctx, options),
|
|
107
|
+
refreshToken: await setTokenUtil(account.refreshToken, ctx, options),
|
|
108
|
+
idToken: account.idToken,
|
|
109
|
+
accessTokenExpiresAt: account.accessTokenExpiresAt,
|
|
110
|
+
refreshTokenExpiresAt: account.refreshTokenExpiresAt,
|
|
111
|
+
scope: account.scope,
|
|
112
|
+
providerId: account.providerId,
|
|
113
|
+
accountId: userInfo.id.toString()
|
|
114
|
+
}).then((res) => res.user);
|
|
115
|
+
if (!userInfo.emailVerified && user && options.emailVerification?.sendOnSignUp === true) {
|
|
116
|
+
const token = await require_email_verification.createEmailVerificationToken(context.secret, user.email, void 0, options.emailVerification.expiresIn);
|
|
117
|
+
const url = `${context.baseURL}/verify-email?token=${token}${callbackURL ? `&callbackURL=${callbackURL}` : ""}`;
|
|
118
|
+
await options.emailVerification.sendVerificationEmail?.({
|
|
119
|
+
user,
|
|
120
|
+
url,
|
|
121
|
+
token
|
|
122
|
+
}, ctx);
|
|
123
|
+
}
|
|
124
|
+
} catch (e) {
|
|
125
|
+
__faire_auth_core_env.logger.error(e instanceof Error ? e.message : String(e), e);
|
|
126
|
+
if (e instanceof __faire_auth_core_error.APIError) return {
|
|
127
|
+
type: "error",
|
|
128
|
+
reason: e.message,
|
|
129
|
+
isRegister: false
|
|
130
|
+
};
|
|
131
|
+
return {
|
|
132
|
+
type: "error",
|
|
133
|
+
reason: "unable_to_create_user",
|
|
134
|
+
isRegister: false
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (!user) return {
|
|
139
|
+
type: "error",
|
|
140
|
+
reason: "unable_to_create_user",
|
|
141
|
+
isRegister: false
|
|
142
|
+
};
|
|
143
|
+
const session = await context.internalAdapter.createSession(user.id);
|
|
144
|
+
if (!session) return {
|
|
145
|
+
type: "error",
|
|
146
|
+
reason: "unable_to_create_session",
|
|
147
|
+
isRegister: false
|
|
148
|
+
};
|
|
149
|
+
return {
|
|
150
|
+
type: "success",
|
|
151
|
+
data: {
|
|
152
|
+
session,
|
|
153
|
+
user
|
|
154
|
+
},
|
|
155
|
+
isRegister
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
//#endregion
|
|
160
|
+
Object.defineProperty(exports, 'decryptOAuthToken', {
|
|
161
|
+
enumerable: true,
|
|
162
|
+
get: function () {
|
|
163
|
+
return decryptOAuthToken;
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
Object.defineProperty(exports, 'handleOAuthUserInfo', {
|
|
167
|
+
enumerable: true,
|
|
168
|
+
get: function () {
|
|
169
|
+
return handleOAuthUserInfo;
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
Object.defineProperty(exports, 'setTokenUtil', {
|
|
173
|
+
enumerable: true,
|
|
174
|
+
get: function () {
|
|
175
|
+
return setTokenUtil;
|
|
176
|
+
}
|
|
177
|
+
});
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { a as getTrustedOrigins, i as getProtocol, n as getHost, r as getOrigin } from "./url-BoUuoIwZ.mjs";
|
|
2
|
+
import { r as createMiddleware } from "./middleware-CE6OhDkq.mjs";
|
|
3
|
+
import { logger } from "@faire-auth/core/env";
|
|
4
|
+
import { False, isPromise } from "@faire-auth/core/static";
|
|
5
|
+
|
|
6
|
+
//#region src/utils/wildcard.ts
|
|
7
|
+
/**
|
|
8
|
+
* Escapes a character if it has a special meaning in regular expressions
|
|
9
|
+
* and returns the character as is if it doesn't
|
|
10
|
+
*/
|
|
11
|
+
const escapeRegExpChar = (char) => {
|
|
12
|
+
if (char === "-" || char === "^" || char === "$" || char === "+" || char === "." || char === "(" || char === ")" || char === "|" || char === "[" || char === "]" || char === "{" || char === "}" || char === "*" || char === "?" || char === "\\") return `\\${char}`;
|
|
13
|
+
return char;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Escapes all characters in a given string that have a special meaning in regular expressions
|
|
17
|
+
*/
|
|
18
|
+
const escapeRegExpString = (str) => {
|
|
19
|
+
let result = "";
|
|
20
|
+
for (const char of str) result += escapeRegExpChar(char);
|
|
21
|
+
return result;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Transforms one or more glob patterns into a RegExp pattern
|
|
25
|
+
*/
|
|
26
|
+
const transform = (pattern, separator = true) => {
|
|
27
|
+
if (Array.isArray(pattern)) return `(?:${pattern.map((p) => `^${transform(p, separator)}$`).join("|")})`;
|
|
28
|
+
const truthySeparator = typeof separator === "string" || separator;
|
|
29
|
+
let separatorSplitter = "";
|
|
30
|
+
let separatorMatcher = "";
|
|
31
|
+
let wildcard = ".";
|
|
32
|
+
if (separator === true) {
|
|
33
|
+
separatorSplitter = "/";
|
|
34
|
+
separatorMatcher = "[/\\\\]";
|
|
35
|
+
wildcard = "[^/\\\\]";
|
|
36
|
+
} else if (typeof separator === "string") {
|
|
37
|
+
separatorSplitter = separator;
|
|
38
|
+
separatorMatcher = escapeRegExpString(separatorSplitter);
|
|
39
|
+
if (separatorMatcher.length > 1) {
|
|
40
|
+
separatorMatcher = `(?:${separatorMatcher})`;
|
|
41
|
+
wildcard = `((?!${separatorMatcher}).)`;
|
|
42
|
+
} else wildcard = `[^${separatorMatcher}]`;
|
|
43
|
+
}
|
|
44
|
+
const requiredSeparator = truthySeparator ? `${separatorMatcher}+?` : "";
|
|
45
|
+
const optionalSeparator = truthySeparator ? `${separatorMatcher}*?` : "";
|
|
46
|
+
const segments = truthySeparator ? pattern.split(separatorSplitter) : [pattern];
|
|
47
|
+
let result = "";
|
|
48
|
+
for (let s = 0; s < segments.length; s++) {
|
|
49
|
+
const segment = segments[s];
|
|
50
|
+
const nextSegment = segments[s + 1];
|
|
51
|
+
let currentSeparator = "";
|
|
52
|
+
if (segment == null && s > 0) continue;
|
|
53
|
+
if (truthySeparator) if (s === segments.length - 1) currentSeparator = optionalSeparator;
|
|
54
|
+
else if (nextSegment !== "**") currentSeparator = requiredSeparator;
|
|
55
|
+
else currentSeparator = "";
|
|
56
|
+
if (truthySeparator && segment === "**") {
|
|
57
|
+
if (currentSeparator) {
|
|
58
|
+
result += s === 0 ? "" : currentSeparator;
|
|
59
|
+
result += `(?:${wildcard}*?${currentSeparator})*?`;
|
|
60
|
+
}
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (segment != null) for (let c = 0; c < segment.length; c++) {
|
|
64
|
+
const char = segment[c];
|
|
65
|
+
switch (char) {
|
|
66
|
+
case "\\":
|
|
67
|
+
if (c < segment.length - 1) {
|
|
68
|
+
result += escapeRegExpChar(segment[c + 1]);
|
|
69
|
+
c++;
|
|
70
|
+
}
|
|
71
|
+
break;
|
|
72
|
+
case "?":
|
|
73
|
+
result += wildcard;
|
|
74
|
+
break;
|
|
75
|
+
case "*":
|
|
76
|
+
result += `${wildcard}*?`;
|
|
77
|
+
break;
|
|
78
|
+
default: if (char != null) result += escapeRegExpChar(char);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
result += currentSeparator;
|
|
82
|
+
}
|
|
83
|
+
return result;
|
|
84
|
+
};
|
|
85
|
+
const isMatch = (regexp, sample) => {
|
|
86
|
+
if (typeof sample !== "string") throw new TypeError(`Sample must be a string, but ${typeof sample} given`);
|
|
87
|
+
return regexp.test(sample);
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Compiles one or more glob patterns into a RegExp and returns an isMatch function.
|
|
91
|
+
* The isMatch function takes a sample string as its only argument and returns `true`
|
|
92
|
+
* if the string matches the pattern(s).
|
|
93
|
+
*
|
|
94
|
+
* ```js
|
|
95
|
+
* wildcardMatch('src/*.js')('src/index.js') //=> true
|
|
96
|
+
* ```
|
|
97
|
+
*
|
|
98
|
+
* ```js
|
|
99
|
+
* const isMatch = wildcardMatch('*.example.com', '.')
|
|
100
|
+
* isMatch('foo.example.com') //=> true
|
|
101
|
+
* isMatch('foo.bar.com') //=> false
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
function wildcardMatch(pattern, options) {
|
|
105
|
+
if (typeof pattern !== "string" && !Array.isArray(pattern)) throw new TypeError(`The first argument must be a single pattern string or an array of patterns, but ${typeof pattern} given`);
|
|
106
|
+
if (typeof options === "string" || typeof options === "boolean") options = { separator: options };
|
|
107
|
+
if (arguments.length === 2 && !(typeof options === "undefined" || typeof options === "object" && options !== null && !Array.isArray(options))) throw new TypeError(`The second argument must be an options object or a string/boolean separator, but ${typeof options} given`);
|
|
108
|
+
options = options ?? {};
|
|
109
|
+
if (options.separator === "\\") throw new Error("\\ is not a valid separator because it is used for escaping. Try setting the separator to `true` instead");
|
|
110
|
+
const regexpPattern = transform(pattern, options.separator);
|
|
111
|
+
const regexp = new RegExp(`^${regexpPattern}$`, options.flags);
|
|
112
|
+
const fn = isMatch.bind(null, regexp);
|
|
113
|
+
fn.options = options;
|
|
114
|
+
fn.pattern = pattern;
|
|
115
|
+
fn.regexp = regexp;
|
|
116
|
+
return fn;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
//#endregion
|
|
120
|
+
//#region src/api/middleware/origin-check.ts
|
|
121
|
+
const RELATIVE_PATH_RE = /^\/(?!\/|\\|%2f|%5c)[\w\-.\+/@]*(?:\?[\w\-.\+/=&%@]*)?$/;
|
|
122
|
+
const matchesPattern = (url, pattern) => {
|
|
123
|
+
if (url.startsWith("/")) return false;
|
|
124
|
+
if (pattern.includes("*")) {
|
|
125
|
+
if (pattern.includes("://")) return wildcardMatch(pattern)(getOrigin(url) || url);
|
|
126
|
+
return wildcardMatch(pattern)(getHost(url));
|
|
127
|
+
}
|
|
128
|
+
const protocol = getProtocol(url);
|
|
129
|
+
return protocol === "http:" || protocol === "https:" || !protocol ? pattern === getOrigin(url) : url.startsWith(pattern);
|
|
130
|
+
};
|
|
131
|
+
const validateURL = (url, label, trustedOrigins, logger$1, ctx) => {
|
|
132
|
+
if (url == null) return null;
|
|
133
|
+
let isTrustedOrigin = false;
|
|
134
|
+
trustedOrigins.forEach((origin) => {
|
|
135
|
+
if (isTrustedOrigin === false && (matchesPattern(url, origin) || url.startsWith("/") && label !== "origin" && RELATIVE_PATH_RE.test(url))) isTrustedOrigin = true;
|
|
136
|
+
});
|
|
137
|
+
if (!isTrustedOrigin) {
|
|
138
|
+
logger$1.error(`Invalid ${label}: ${url}`);
|
|
139
|
+
logger$1.info(`If it's a valid URL, please add ${url} to trustedOrigins in your auth config\n`, `Current list of trustedOrigins: ${[...trustedOrigins].join(", ")}`);
|
|
140
|
+
return ctx.json({
|
|
141
|
+
success: False,
|
|
142
|
+
message: `Invalid ${label}`
|
|
143
|
+
}, 403);
|
|
144
|
+
}
|
|
145
|
+
return null;
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* A middleware to validate callbackURL and origin against
|
|
149
|
+
* trustedOrigins.
|
|
150
|
+
*/
|
|
151
|
+
const initOriginCheckMiddleware = (options, context) => {
|
|
152
|
+
const log = {
|
|
153
|
+
info: (message, ...args) => options.logger?.log?.("info", message, ...args) ?? logger.info,
|
|
154
|
+
error: (message, ...args) => options.logger?.log?.("error", message, ...args) ?? logger.error
|
|
155
|
+
};
|
|
156
|
+
return createMiddleware()(async (ctx, next) => {
|
|
157
|
+
if (ctx.get("isServer") === true || ctx.req.method !== "POST") return await next();
|
|
158
|
+
const needsBody = [
|
|
159
|
+
"POST",
|
|
160
|
+
"PUT",
|
|
161
|
+
"PATCH"
|
|
162
|
+
].includes(ctx.req.method);
|
|
163
|
+
const usesCookies = ctx.req.header("cookie") != null;
|
|
164
|
+
const originHeader = ctx.req.header("origin") ?? ctx.req.header("referer");
|
|
165
|
+
const queryCallbackURL = ctx.req.query("callbackURL");
|
|
166
|
+
const { ready, dynamicPromise, trustedOrigins } = getTrustedOrigins(options, context, ctx.req);
|
|
167
|
+
let body = null;
|
|
168
|
+
if (needsBody) try {
|
|
169
|
+
body = await ctx.req.raw.clone().json();
|
|
170
|
+
} catch {}
|
|
171
|
+
const callbackURL = body?.callbackURL ?? queryCallbackURL;
|
|
172
|
+
const redirectURL = body?.redirectTo;
|
|
173
|
+
const errorCallbackURL = body?.errorCallbackURL;
|
|
174
|
+
const newUserCallbackURL = body?.newUserCallbackURL;
|
|
175
|
+
let ret = null;
|
|
176
|
+
if (usesCookies && !options.advanced?.disableCSRFCheck) {
|
|
177
|
+
if (!ready) await dynamicPromise;
|
|
178
|
+
ret = validateURL(originHeader, "origin", trustedOrigins, log, ctx);
|
|
179
|
+
if (ret) return ret;
|
|
180
|
+
}
|
|
181
|
+
if (callbackURL != null) {
|
|
182
|
+
if (!ready) await dynamicPromise;
|
|
183
|
+
ret = validateURL(callbackURL, "callbackURL", trustedOrigins, log, ctx);
|
|
184
|
+
if (ret) return ret;
|
|
185
|
+
}
|
|
186
|
+
if (redirectURL != null) {
|
|
187
|
+
if (!ready) await dynamicPromise;
|
|
188
|
+
ret = validateURL(redirectURL, "redirectURL", trustedOrigins, log, ctx);
|
|
189
|
+
if (ret) return ret;
|
|
190
|
+
}
|
|
191
|
+
if (errorCallbackURL != null) {
|
|
192
|
+
if (!ready) await dynamicPromise;
|
|
193
|
+
ret = validateURL(errorCallbackURL, "errorCallbackURL", trustedOrigins, log, ctx);
|
|
194
|
+
if (ret) return ret;
|
|
195
|
+
}
|
|
196
|
+
if (newUserCallbackURL != null) {
|
|
197
|
+
if (!ready) await dynamicPromise;
|
|
198
|
+
ret = validateURL(newUserCallbackURL, "newUserCallbackURL", trustedOrigins, log, ctx);
|
|
199
|
+
if (ret) return ret;
|
|
200
|
+
}
|
|
201
|
+
return await next();
|
|
202
|
+
});
|
|
203
|
+
};
|
|
204
|
+
/**
|
|
205
|
+
* Validates callback URLs against trusted origins.
|
|
206
|
+
* @template V - The context variables type.
|
|
207
|
+
* @param getValue - Function to get the callback URL(s) from the context.
|
|
208
|
+
* @returns The middleware function.
|
|
209
|
+
*/
|
|
210
|
+
const originCheck = (getValue) => {
|
|
211
|
+
return createMiddleware()(async (ctx, next) => {
|
|
212
|
+
if (ctx.get("isServer") === true) return await next();
|
|
213
|
+
const context = ctx.get("context");
|
|
214
|
+
let callbackURL = getValue(ctx);
|
|
215
|
+
if (isPromise(callbackURL)) callbackURL = await callbackURL;
|
|
216
|
+
if (!callbackURL) return await next();
|
|
217
|
+
const callbacks = Array.isArray(callbackURL) ? callbackURL : [callbackURL];
|
|
218
|
+
let ret;
|
|
219
|
+
for (const url of callbacks) {
|
|
220
|
+
ret = validateURL(url, "callbackURL", context.trustedOrigins, context.logger, ctx);
|
|
221
|
+
if (ret) return ret;
|
|
222
|
+
}
|
|
223
|
+
return await next();
|
|
224
|
+
});
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
//#endregion
|
|
228
|
+
export { originCheck as n, wildcardMatch as r, initOriginCheckMiddleware as t };
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
const require_chunk = require('./chunk-oakRccI5.cjs');
|
|
2
|
+
const require_url = require('./url-D2yvKaM7.cjs');
|
|
3
|
+
const require_middleware = require('./middleware-CWvRH4EW.cjs');
|
|
4
|
+
let __faire_auth_core_env = require("@faire-auth/core/env");
|
|
5
|
+
let __faire_auth_core_static = require("@faire-auth/core/static");
|
|
6
|
+
|
|
7
|
+
//#region src/utils/wildcard.ts
|
|
8
|
+
/**
|
|
9
|
+
* Escapes a character if it has a special meaning in regular expressions
|
|
10
|
+
* and returns the character as is if it doesn't
|
|
11
|
+
*/
|
|
12
|
+
const escapeRegExpChar = (char) => {
|
|
13
|
+
if (char === "-" || char === "^" || char === "$" || char === "+" || char === "." || char === "(" || char === ")" || char === "|" || char === "[" || char === "]" || char === "{" || char === "}" || char === "*" || char === "?" || char === "\\") return `\\${char}`;
|
|
14
|
+
return char;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Escapes all characters in a given string that have a special meaning in regular expressions
|
|
18
|
+
*/
|
|
19
|
+
const escapeRegExpString = (str) => {
|
|
20
|
+
let result = "";
|
|
21
|
+
for (const char of str) result += escapeRegExpChar(char);
|
|
22
|
+
return result;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Transforms one or more glob patterns into a RegExp pattern
|
|
26
|
+
*/
|
|
27
|
+
const transform = (pattern, separator = true) => {
|
|
28
|
+
if (Array.isArray(pattern)) return `(?:${pattern.map((p) => `^${transform(p, separator)}$`).join("|")})`;
|
|
29
|
+
const truthySeparator = typeof separator === "string" || separator;
|
|
30
|
+
let separatorSplitter = "";
|
|
31
|
+
let separatorMatcher = "";
|
|
32
|
+
let wildcard = ".";
|
|
33
|
+
if (separator === true) {
|
|
34
|
+
separatorSplitter = "/";
|
|
35
|
+
separatorMatcher = "[/\\\\]";
|
|
36
|
+
wildcard = "[^/\\\\]";
|
|
37
|
+
} else if (typeof separator === "string") {
|
|
38
|
+
separatorSplitter = separator;
|
|
39
|
+
separatorMatcher = escapeRegExpString(separatorSplitter);
|
|
40
|
+
if (separatorMatcher.length > 1) {
|
|
41
|
+
separatorMatcher = `(?:${separatorMatcher})`;
|
|
42
|
+
wildcard = `((?!${separatorMatcher}).)`;
|
|
43
|
+
} else wildcard = `[^${separatorMatcher}]`;
|
|
44
|
+
}
|
|
45
|
+
const requiredSeparator = truthySeparator ? `${separatorMatcher}+?` : "";
|
|
46
|
+
const optionalSeparator = truthySeparator ? `${separatorMatcher}*?` : "";
|
|
47
|
+
const segments = truthySeparator ? pattern.split(separatorSplitter) : [pattern];
|
|
48
|
+
let result = "";
|
|
49
|
+
for (let s = 0; s < segments.length; s++) {
|
|
50
|
+
const segment = segments[s];
|
|
51
|
+
const nextSegment = segments[s + 1];
|
|
52
|
+
let currentSeparator = "";
|
|
53
|
+
if (segment == null && s > 0) continue;
|
|
54
|
+
if (truthySeparator) if (s === segments.length - 1) currentSeparator = optionalSeparator;
|
|
55
|
+
else if (nextSegment !== "**") currentSeparator = requiredSeparator;
|
|
56
|
+
else currentSeparator = "";
|
|
57
|
+
if (truthySeparator && segment === "**") {
|
|
58
|
+
if (currentSeparator) {
|
|
59
|
+
result += s === 0 ? "" : currentSeparator;
|
|
60
|
+
result += `(?:${wildcard}*?${currentSeparator})*?`;
|
|
61
|
+
}
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (segment != null) for (let c = 0; c < segment.length; c++) {
|
|
65
|
+
const char = segment[c];
|
|
66
|
+
switch (char) {
|
|
67
|
+
case "\\":
|
|
68
|
+
if (c < segment.length - 1) {
|
|
69
|
+
result += escapeRegExpChar(segment[c + 1]);
|
|
70
|
+
c++;
|
|
71
|
+
}
|
|
72
|
+
break;
|
|
73
|
+
case "?":
|
|
74
|
+
result += wildcard;
|
|
75
|
+
break;
|
|
76
|
+
case "*":
|
|
77
|
+
result += `${wildcard}*?`;
|
|
78
|
+
break;
|
|
79
|
+
default: if (char != null) result += escapeRegExpChar(char);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
result += currentSeparator;
|
|
83
|
+
}
|
|
84
|
+
return result;
|
|
85
|
+
};
|
|
86
|
+
const isMatch = (regexp, sample) => {
|
|
87
|
+
if (typeof sample !== "string") throw new TypeError(`Sample must be a string, but ${typeof sample} given`);
|
|
88
|
+
return regexp.test(sample);
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Compiles one or more glob patterns into a RegExp and returns an isMatch function.
|
|
92
|
+
* The isMatch function takes a sample string as its only argument and returns `true`
|
|
93
|
+
* if the string matches the pattern(s).
|
|
94
|
+
*
|
|
95
|
+
* ```js
|
|
96
|
+
* wildcardMatch('src/*.js')('src/index.js') //=> true
|
|
97
|
+
* ```
|
|
98
|
+
*
|
|
99
|
+
* ```js
|
|
100
|
+
* const isMatch = wildcardMatch('*.example.com', '.')
|
|
101
|
+
* isMatch('foo.example.com') //=> true
|
|
102
|
+
* isMatch('foo.bar.com') //=> false
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
function wildcardMatch(pattern, options) {
|
|
106
|
+
if (typeof pattern !== "string" && !Array.isArray(pattern)) throw new TypeError(`The first argument must be a single pattern string or an array of patterns, but ${typeof pattern} given`);
|
|
107
|
+
if (typeof options === "string" || typeof options === "boolean") options = { separator: options };
|
|
108
|
+
if (arguments.length === 2 && !(typeof options === "undefined" || typeof options === "object" && options !== null && !Array.isArray(options))) throw new TypeError(`The second argument must be an options object or a string/boolean separator, but ${typeof options} given`);
|
|
109
|
+
options = options ?? {};
|
|
110
|
+
if (options.separator === "\\") throw new Error("\\ is not a valid separator because it is used for escaping. Try setting the separator to `true` instead");
|
|
111
|
+
const regexpPattern = transform(pattern, options.separator);
|
|
112
|
+
const regexp = new RegExp(`^${regexpPattern}$`, options.flags);
|
|
113
|
+
const fn = isMatch.bind(null, regexp);
|
|
114
|
+
fn.options = options;
|
|
115
|
+
fn.pattern = pattern;
|
|
116
|
+
fn.regexp = regexp;
|
|
117
|
+
return fn;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
//#endregion
|
|
121
|
+
//#region src/api/middleware/origin-check.ts
|
|
122
|
+
const RELATIVE_PATH_RE = /^\/(?!\/|\\|%2f|%5c)[\w\-.\+/@]*(?:\?[\w\-.\+/=&%@]*)?$/;
|
|
123
|
+
const matchesPattern = (url, pattern) => {
|
|
124
|
+
if (url.startsWith("/")) return false;
|
|
125
|
+
if (pattern.includes("*")) {
|
|
126
|
+
if (pattern.includes("://")) return wildcardMatch(pattern)(require_url.getOrigin(url) || url);
|
|
127
|
+
return wildcardMatch(pattern)(require_url.getHost(url));
|
|
128
|
+
}
|
|
129
|
+
const protocol = require_url.getProtocol(url);
|
|
130
|
+
return protocol === "http:" || protocol === "https:" || !protocol ? pattern === require_url.getOrigin(url) : url.startsWith(pattern);
|
|
131
|
+
};
|
|
132
|
+
const validateURL = (url, label, trustedOrigins, logger$1, ctx) => {
|
|
133
|
+
if (url == null) return null;
|
|
134
|
+
let isTrustedOrigin = false;
|
|
135
|
+
trustedOrigins.forEach((origin) => {
|
|
136
|
+
if (isTrustedOrigin === false && (matchesPattern(url, origin) || url.startsWith("/") && label !== "origin" && RELATIVE_PATH_RE.test(url))) isTrustedOrigin = true;
|
|
137
|
+
});
|
|
138
|
+
if (!isTrustedOrigin) {
|
|
139
|
+
logger$1.error(`Invalid ${label}: ${url}`);
|
|
140
|
+
logger$1.info(`If it's a valid URL, please add ${url} to trustedOrigins in your auth config\n`, `Current list of trustedOrigins: ${[...trustedOrigins].join(", ")}`);
|
|
141
|
+
return ctx.json({
|
|
142
|
+
success: __faire_auth_core_static.False,
|
|
143
|
+
message: `Invalid ${label}`
|
|
144
|
+
}, 403);
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* A middleware to validate callbackURL and origin against
|
|
150
|
+
* trustedOrigins.
|
|
151
|
+
*/
|
|
152
|
+
const initOriginCheckMiddleware = (options, context) => {
|
|
153
|
+
const log = {
|
|
154
|
+
info: (message, ...args) => options.logger?.log?.("info", message, ...args) ?? __faire_auth_core_env.logger.info,
|
|
155
|
+
error: (message, ...args) => options.logger?.log?.("error", message, ...args) ?? __faire_auth_core_env.logger.error
|
|
156
|
+
};
|
|
157
|
+
return require_middleware.createMiddleware()(async (ctx, next) => {
|
|
158
|
+
if (ctx.get("isServer") === true || ctx.req.method !== "POST") return await next();
|
|
159
|
+
const needsBody = [
|
|
160
|
+
"POST",
|
|
161
|
+
"PUT",
|
|
162
|
+
"PATCH"
|
|
163
|
+
].includes(ctx.req.method);
|
|
164
|
+
const usesCookies = ctx.req.header("cookie") != null;
|
|
165
|
+
const originHeader = ctx.req.header("origin") ?? ctx.req.header("referer");
|
|
166
|
+
const queryCallbackURL = ctx.req.query("callbackURL");
|
|
167
|
+
const { ready, dynamicPromise, trustedOrigins } = require_url.getTrustedOrigins(options, context, ctx.req);
|
|
168
|
+
let body = null;
|
|
169
|
+
if (needsBody) try {
|
|
170
|
+
body = await ctx.req.raw.clone().json();
|
|
171
|
+
} catch {}
|
|
172
|
+
const callbackURL = body?.callbackURL ?? queryCallbackURL;
|
|
173
|
+
const redirectURL = body?.redirectTo;
|
|
174
|
+
const errorCallbackURL = body?.errorCallbackURL;
|
|
175
|
+
const newUserCallbackURL = body?.newUserCallbackURL;
|
|
176
|
+
let ret = null;
|
|
177
|
+
if (usesCookies && !options.advanced?.disableCSRFCheck) {
|
|
178
|
+
if (!ready) await dynamicPromise;
|
|
179
|
+
ret = validateURL(originHeader, "origin", trustedOrigins, log, ctx);
|
|
180
|
+
if (ret) return ret;
|
|
181
|
+
}
|
|
182
|
+
if (callbackURL != null) {
|
|
183
|
+
if (!ready) await dynamicPromise;
|
|
184
|
+
ret = validateURL(callbackURL, "callbackURL", trustedOrigins, log, ctx);
|
|
185
|
+
if (ret) return ret;
|
|
186
|
+
}
|
|
187
|
+
if (redirectURL != null) {
|
|
188
|
+
if (!ready) await dynamicPromise;
|
|
189
|
+
ret = validateURL(redirectURL, "redirectURL", trustedOrigins, log, ctx);
|
|
190
|
+
if (ret) return ret;
|
|
191
|
+
}
|
|
192
|
+
if (errorCallbackURL != null) {
|
|
193
|
+
if (!ready) await dynamicPromise;
|
|
194
|
+
ret = validateURL(errorCallbackURL, "errorCallbackURL", trustedOrigins, log, ctx);
|
|
195
|
+
if (ret) return ret;
|
|
196
|
+
}
|
|
197
|
+
if (newUserCallbackURL != null) {
|
|
198
|
+
if (!ready) await dynamicPromise;
|
|
199
|
+
ret = validateURL(newUserCallbackURL, "newUserCallbackURL", trustedOrigins, log, ctx);
|
|
200
|
+
if (ret) return ret;
|
|
201
|
+
}
|
|
202
|
+
return await next();
|
|
203
|
+
});
|
|
204
|
+
};
|
|
205
|
+
/**
|
|
206
|
+
* Validates callback URLs against trusted origins.
|
|
207
|
+
* @template V - The context variables type.
|
|
208
|
+
* @param getValue - Function to get the callback URL(s) from the context.
|
|
209
|
+
* @returns The middleware function.
|
|
210
|
+
*/
|
|
211
|
+
const originCheck = (getValue) => {
|
|
212
|
+
return require_middleware.createMiddleware()(async (ctx, next) => {
|
|
213
|
+
if (ctx.get("isServer") === true) return await next();
|
|
214
|
+
const context = ctx.get("context");
|
|
215
|
+
let callbackURL = getValue(ctx);
|
|
216
|
+
if ((0, __faire_auth_core_static.isPromise)(callbackURL)) callbackURL = await callbackURL;
|
|
217
|
+
if (!callbackURL) return await next();
|
|
218
|
+
const callbacks = Array.isArray(callbackURL) ? callbackURL : [callbackURL];
|
|
219
|
+
let ret;
|
|
220
|
+
for (const url of callbacks) {
|
|
221
|
+
ret = validateURL(url, "callbackURL", context.trustedOrigins, context.logger, ctx);
|
|
222
|
+
if (ret) return ret;
|
|
223
|
+
}
|
|
224
|
+
return await next();
|
|
225
|
+
});
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
//#endregion
|
|
229
|
+
Object.defineProperty(exports, 'initOriginCheckMiddleware', {
|
|
230
|
+
enumerable: true,
|
|
231
|
+
get: function () {
|
|
232
|
+
return initOriginCheckMiddleware;
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
Object.defineProperty(exports, 'originCheck', {
|
|
236
|
+
enumerable: true,
|
|
237
|
+
get: function () {
|
|
238
|
+
return originCheck;
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
Object.defineProperty(exports, 'wildcardMatch', {
|
|
242
|
+
enumerable: true,
|
|
243
|
+
get: function () {
|
|
244
|
+
return wildcardMatch;
|
|
245
|
+
}
|
|
246
|
+
});
|