@aura-stack/auth 0.4.0-rc.5 → 0.4.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/dist/@types/index.d.ts +4 -3
- package/dist/@types/router.d.cjs +0 -17
- package/dist/@types/router.d.d.ts +3 -2
- package/dist/@types/router.d.js +0 -1
- package/dist/actions/callback/access-token.cjs +40 -25
- package/dist/actions/callback/access-token.d.ts +4 -3
- package/dist/actions/callback/access-token.js +3 -4
- package/dist/actions/callback/callback.cjs +287 -77
- package/dist/actions/callback/callback.d.ts +5 -26
- package/dist/actions/callback/callback.js +13 -10
- package/dist/actions/callback/userinfo.cjs +68 -7
- package/dist/actions/callback/userinfo.d.ts +4 -3
- package/dist/actions/callback/userinfo.js +8 -6
- package/dist/actions/csrfToken/csrfToken.cjs +63 -4
- package/dist/actions/csrfToken/csrfToken.d.ts +1 -3
- package/dist/actions/csrfToken/csrfToken.js +8 -6
- package/dist/actions/index.cjs +400 -175
- package/dist/actions/index.d.ts +3 -2
- package/dist/actions/index.js +21 -19
- package/dist/actions/session/session.cjs +40 -11
- package/dist/actions/session/session.d.ts +1 -3
- package/dist/actions/session/session.js +4 -4
- package/dist/actions/signIn/authorization.cjs +171 -132
- package/dist/actions/signIn/authorization.d.ts +21 -11
- package/dist/actions/signIn/authorization.js +8 -6
- package/dist/actions/signIn/signIn.cjs +220 -113
- package/dist/actions/signIn/signIn.d.ts +5 -25
- package/dist/actions/signIn/signIn.js +9 -7
- package/dist/actions/signOut/signOut.cjs +268 -119
- package/dist/actions/signOut/signOut.d.ts +1 -9
- package/dist/actions/signOut/signOut.js +10 -8
- package/dist/assert.cjs +117 -5
- package/dist/assert.d.ts +22 -3
- package/dist/assert.js +17 -3
- package/dist/chunk-4EKY7655.js +123 -0
- package/dist/chunk-4MYWAOLG.js +31 -0
- package/dist/chunk-4YHJ4IEQ.js +25 -0
- package/dist/chunk-54CZPKR4.js +25 -0
- package/dist/chunk-5LZ7TOM3.js +25 -0
- package/dist/{chunk-W6LG7BFW.js → chunk-5W4BRQYG.js} +24 -20
- package/dist/chunk-6MXFPFR3.js +143 -0
- package/dist/{chunk-3EUWD5BB.js → chunk-7QF22LHP.js} +13 -9
- package/dist/chunk-ALG3GIV4.js +95 -0
- package/dist/chunk-E6G5YCI6.js +25 -0
- package/dist/chunk-EBAMFRB7.js +34 -0
- package/dist/chunk-EEE7UM5T.js +25 -0
- package/dist/{chunk-TLE4PXY3.js → chunk-FRJFWTOY.js} +38 -7
- package/dist/chunk-FW4W3REU.js +25 -0
- package/dist/{chunk-HT4YLL7N.js → chunk-ICAZ4OVS.js} +10 -8
- package/dist/chunk-IPKO6UQN.js +25 -0
- package/dist/{chunk-YRCB5FLE.js → chunk-KJBAQZX2.js} +13 -0
- package/dist/chunk-KMMAZFSJ.js +25 -0
- package/dist/chunk-LDU7A2JE.js +25 -0
- package/dist/{chunk-N2APGLXA.js → chunk-NUDITUKX.js} +18 -16
- package/dist/chunk-OVHNRULD.js +33 -0
- package/dist/{chunk-JVFTCTTE.js → chunk-PHFH2MGS.js} +12 -9
- package/dist/chunk-QQVSRXGX.js +149 -0
- package/dist/chunk-TM5IPSNF.js +113 -0
- package/dist/{chunk-GA2SMTJO.js → chunk-TZB6MUXN.js} +33 -13
- package/dist/chunk-VNCNJKS2.js +267 -0
- package/dist/{chunk-IVET23KF.js → chunk-XGLBNXL4.js} +31 -14
- package/dist/chunk-XUP6KKNG.js +106 -0
- package/dist/cookie.cjs +24 -20
- package/dist/cookie.d.ts +4 -3
- package/dist/cookie.js +1 -1
- package/dist/env.cjs +56 -0
- package/dist/env.d.ts +7 -0
- package/dist/env.js +6 -0
- package/dist/errors.d.ts +4 -3
- package/dist/headers.cjs +28 -2
- package/dist/headers.d.ts +25 -1
- package/dist/headers.js +9 -3
- package/dist/{index-B8jeIElf.d.ts → index-CSyIJmCM.d.ts} +373 -45
- package/dist/index.cjs +1128 -483
- package/dist/index.d.ts +7 -67
- package/dist/index.js +83 -42
- package/dist/jose.cjs +62 -25
- package/dist/jose.d.ts +7 -5
- package/dist/jose.js +8 -6
- package/dist/logger.cjs +292 -0
- package/dist/logger.d.ts +8 -0
- package/dist/logger.js +8 -0
- package/dist/oauth/bitbucket.cjs +19 -15
- package/dist/oauth/bitbucket.d.ts +3 -2
- package/dist/oauth/bitbucket.js +1 -1
- package/dist/oauth/discord.cjs +27 -24
- package/dist/oauth/discord.d.ts +3 -2
- package/dist/oauth/discord.js +1 -1
- package/dist/oauth/figma.cjs +19 -16
- package/dist/oauth/figma.d.ts +3 -2
- package/dist/oauth/figma.js +1 -1
- package/dist/oauth/github.cjs +19 -8
- package/dist/oauth/github.d.ts +3 -2
- package/dist/oauth/github.js +1 -1
- package/dist/oauth/gitlab.cjs +19 -16
- package/dist/oauth/gitlab.d.ts +3 -2
- package/dist/oauth/gitlab.js +1 -1
- package/dist/oauth/index.cjs +266 -166
- package/dist/oauth/index.d.ts +3 -2
- package/dist/oauth/index.js +22 -21
- package/dist/oauth/mailchimp.cjs +19 -16
- package/dist/oauth/mailchimp.d.ts +3 -2
- package/dist/oauth/mailchimp.js +1 -1
- package/dist/oauth/pinterest.cjs +19 -16
- package/dist/oauth/pinterest.d.ts +3 -2
- package/dist/oauth/pinterest.js +1 -1
- package/dist/oauth/spotify.cjs +19 -16
- package/dist/oauth/spotify.d.ts +3 -2
- package/dist/oauth/spotify.js +1 -1
- package/dist/oauth/strava.cjs +19 -16
- package/dist/oauth/strava.d.ts +3 -2
- package/dist/oauth/strava.js +1 -1
- package/dist/oauth/x.cjs +19 -16
- package/dist/oauth/x.d.ts +3 -2
- package/dist/oauth/x.js +1 -1
- package/dist/schemas.cjs +16 -2
- package/dist/schemas.d.ts +17 -1
- package/dist/schemas.js +5 -3
- package/dist/secure.cjs +58 -16
- package/dist/secure.d.ts +4 -10
- package/dist/secure.js +5 -5
- package/dist/utils.cjs +94 -87
- package/dist/utils.d.ts +9 -39
- package/dist/utils.js +11 -9
- package/package.json +3 -4
- package/dist/chunk-42XB3YCW.js +0 -22
- package/dist/chunk-6R2YZ4AC.js +0 -22
- package/dist/chunk-A3N4PVAT.js +0 -70
- package/dist/chunk-B737EUJV.js +0 -22
- package/dist/chunk-CXLATHS5.js +0 -143
- package/dist/chunk-DIVDFNAP.js +0 -0
- package/dist/chunk-E3OXBRYF.js +0 -22
- package/dist/chunk-EIL2FPSS.js +0 -22
- package/dist/chunk-EMKJA2GJ.js +0 -89
- package/dist/chunk-FIPU4MLT.js +0 -21
- package/dist/chunk-FKRDCWBF.js +0 -22
- package/dist/chunk-HP34YGGJ.js +0 -22
- package/dist/chunk-IKHPGFCW.js +0 -14
- package/dist/chunk-IUYZQTJV.js +0 -30
- package/dist/chunk-KRNOMBXQ.js +0 -22
- package/dist/chunk-KSWLO5ZU.js +0 -102
- package/dist/chunk-N4SX7TZT.js +0 -96
- package/dist/chunk-STHEPPUZ.js +0 -11
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
6
|
var __export = (target, all) => {
|
|
9
7
|
for (var name in all)
|
|
@@ -17,14 +15,6 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
15
|
}
|
|
18
16
|
return to;
|
|
19
17
|
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
19
|
|
|
30
20
|
// src/actions/signOut/signOut.ts
|
|
@@ -36,13 +26,20 @@ module.exports = __toCommonJS(signOut_exports);
|
|
|
36
26
|
var import_zod2 = require("zod");
|
|
37
27
|
var import_router2 = require("@aura-stack/router");
|
|
38
28
|
|
|
39
|
-
// src/secure.ts
|
|
40
|
-
var import_crypto = __toESM(require("crypto"), 1);
|
|
41
|
-
|
|
42
29
|
// src/utils.ts
|
|
43
30
|
var import_router = require("@aura-stack/router");
|
|
44
31
|
|
|
45
32
|
// src/errors.ts
|
|
33
|
+
var AuthInternalError = class extends Error {
|
|
34
|
+
type = "AUTH_INTERNAL_ERROR";
|
|
35
|
+
code;
|
|
36
|
+
constructor(code, message, options2) {
|
|
37
|
+
super(message, options2);
|
|
38
|
+
this.code = code;
|
|
39
|
+
this.name = new.target.name;
|
|
40
|
+
Error.captureStackTrace(this, new.target);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
46
43
|
var AuthSecurityError = class extends Error {
|
|
47
44
|
type = "AUTH_SECURITY_ERROR";
|
|
48
45
|
code;
|
|
@@ -53,86 +50,180 @@ var AuthSecurityError = class extends Error {
|
|
|
53
50
|
Error.captureStackTrace(this, new.target);
|
|
54
51
|
}
|
|
55
52
|
};
|
|
56
|
-
var isAuthSecurityError = (error) => {
|
|
57
|
-
return error instanceof AuthSecurityError;
|
|
58
|
-
};
|
|
59
53
|
|
|
60
54
|
// src/utils.ts
|
|
61
55
|
var equals = (a, b) => {
|
|
62
56
|
if (a === null || b === null || a === void 0 || b === void 0) return false;
|
|
63
57
|
return a === b;
|
|
64
58
|
};
|
|
65
|
-
var
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const protocolMatch = decodedURL.match(/^([a-zA-Z][a-zA-Z0-9+.-]*:\/\/)/);
|
|
69
|
-
let protocol = "";
|
|
70
|
-
let rest = decodedURL;
|
|
71
|
-
if (protocolMatch) {
|
|
72
|
-
protocol = protocolMatch[1];
|
|
73
|
-
rest = decodedURL.slice(protocol.length);
|
|
74
|
-
const slashIndex = rest.indexOf("/");
|
|
75
|
-
if (slashIndex === -1) {
|
|
76
|
-
return protocol + rest;
|
|
77
|
-
}
|
|
78
|
-
const domain = rest.slice(0, slashIndex);
|
|
79
|
-
let path = rest.slice(slashIndex).replace(/\/\.\.\//g, "/").replace(/\/\.\.$/, "").replace(/\.{2,}/g, "").replace(/\/{2,}/g, "/");
|
|
80
|
-
if (path !== "/" && path.endsWith("/")) {
|
|
81
|
-
path = path.replace(/\/+$/, "/");
|
|
82
|
-
} else if (path !== "/") {
|
|
83
|
-
path = path.replace(/\/+$/, "");
|
|
84
|
-
}
|
|
85
|
-
return protocol + domain + path;
|
|
86
|
-
}
|
|
87
|
-
let sanitized = decodedURL.replace(/\/\.\.\//g, "/").replace(/\/\.\.$/, "").replace(/\.{2,}/g, "").replace(/\/{2,}/g, "/");
|
|
88
|
-
if (sanitized !== "/" && sanitized.endsWith("/")) {
|
|
89
|
-
sanitized = sanitized.replace(/\/+$/, "/");
|
|
90
|
-
} else if (sanitized !== "/") {
|
|
91
|
-
sanitized = sanitized.replace(/\/+$/, "");
|
|
92
|
-
}
|
|
93
|
-
return sanitized;
|
|
94
|
-
} catch {
|
|
95
|
-
return url.trim();
|
|
96
|
-
}
|
|
59
|
+
var getBaseURL = (request) => {
|
|
60
|
+
const url = new URL(request.url);
|
|
61
|
+
return `${url.origin}${url.pathname}`;
|
|
97
62
|
};
|
|
98
|
-
var
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
return
|
|
63
|
+
var extractPath = (url) => {
|
|
64
|
+
const pathRegex = /^https?:\/\/[a-zA-Z0-9_\-\.]+(:\d+)?(\/.*)$/;
|
|
65
|
+
const match = url.match(pathRegex);
|
|
66
|
+
return match && match[2] ? match[2] : "/";
|
|
67
|
+
};
|
|
68
|
+
var getErrorName = (error) => {
|
|
69
|
+
if (error instanceof Error) {
|
|
70
|
+
return error.name;
|
|
106
71
|
}
|
|
72
|
+
return typeof error === "string" ? error : "UnknownError";
|
|
107
73
|
};
|
|
108
74
|
|
|
109
75
|
// src/assert.ts
|
|
76
|
+
var import_crypto = require("crypto");
|
|
77
|
+
var unsafeChars = [
|
|
78
|
+
"<",
|
|
79
|
+
">",
|
|
80
|
+
'"',
|
|
81
|
+
"`",
|
|
82
|
+
" ",
|
|
83
|
+
"\r",
|
|
84
|
+
"\n",
|
|
85
|
+
" ",
|
|
86
|
+
"\\",
|
|
87
|
+
"%2F",
|
|
88
|
+
"%5C",
|
|
89
|
+
"%2f",
|
|
90
|
+
"%5c",
|
|
91
|
+
"\r\n",
|
|
92
|
+
"%0A",
|
|
93
|
+
"%0D",
|
|
94
|
+
"%0a",
|
|
95
|
+
"%0d",
|
|
96
|
+
"..",
|
|
97
|
+
"//",
|
|
98
|
+
"///",
|
|
99
|
+
"...",
|
|
100
|
+
"%20",
|
|
101
|
+
"\0"
|
|
102
|
+
];
|
|
110
103
|
var isValidURL = (value) => {
|
|
111
|
-
if (
|
|
112
|
-
|
|
113
|
-
|
|
104
|
+
if (!new RegExp(/^https?:\/\/[^/]/).test(value)) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
const match = value.match(/^(https?:\/\/)(.*)$/);
|
|
108
|
+
if (!match) return false;
|
|
109
|
+
const rest = match[2];
|
|
110
|
+
for (const char of unsafeChars) {
|
|
111
|
+
if (rest.includes(char)) return false;
|
|
112
|
+
}
|
|
113
|
+
const regex = /^https?:\/\/(?:[a-zA-Z0-9._-]+|localhost|\[[0-9a-fA-F:]+\])(?::\d{1,5})?(?:\/[a-zA-Z0-9._~!$&'()?#*+,;=:@-]*)*\/?$/;
|
|
114
|
+
return regex.test(match[0]);
|
|
114
115
|
};
|
|
115
116
|
var isJWTPayloadWithToken = (payload) => {
|
|
116
117
|
return typeof payload === "object" && payload !== null && "token" in payload && typeof payload?.token === "string";
|
|
117
118
|
};
|
|
119
|
+
var isRelativeURL = (value) => {
|
|
120
|
+
if (value.length > 100) return false;
|
|
121
|
+
for (const char of unsafeChars) {
|
|
122
|
+
if (value.includes(char)) return false;
|
|
123
|
+
}
|
|
124
|
+
const regex = /^\/[a-zA-Z0-9\-_\/.?&=#]*\/?$/;
|
|
125
|
+
return regex.test(value);
|
|
126
|
+
};
|
|
127
|
+
var isSameOrigin = (origin, expected) => {
|
|
128
|
+
const originURL = new URL(origin);
|
|
129
|
+
const expectedURL = new URL(expected);
|
|
130
|
+
return equals(originURL.origin, expectedURL.origin);
|
|
131
|
+
};
|
|
132
|
+
var patternToRegex = (pattern) => {
|
|
133
|
+
try {
|
|
134
|
+
if (pattern.length > 2048) return null;
|
|
135
|
+
pattern = pattern.replace(/\\/g, "");
|
|
136
|
+
const match = pattern.match(/^(https?):\/\/([a-zA-Z0-9.*-]{1,253})(?::(\d{1,5}|\*))?(?:\/.*)?$/);
|
|
137
|
+
if (!match) return null;
|
|
138
|
+
const [, protocol, host, port] = match;
|
|
139
|
+
const hasWildcard = host.includes("*");
|
|
140
|
+
if (hasWildcard && !host.startsWith("*.")) return null;
|
|
141
|
+
if (hasWildcard && host.slice(2).includes("*")) return null;
|
|
142
|
+
const domain = hasWildcard ? host.slice(2) : host;
|
|
143
|
+
const escapedDomain = domain.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
144
|
+
const hostRegex = hasWildcard ? `[^.]+\\.${escapedDomain}` : escapedDomain;
|
|
145
|
+
const portRegex = port === "*" ? ":\\d{1,5}" : port ? `:${port}` : "";
|
|
146
|
+
return new RegExp(`^${protocol}:\\/\\/${hostRegex}${portRegex}$`);
|
|
147
|
+
} catch {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
var isTrustedOrigin = (url, trustedOrigins) => {
|
|
152
|
+
if (!isValidURL(url) || trustedOrigins.length === 0) return false;
|
|
153
|
+
try {
|
|
154
|
+
const urlOrigin = new URL(url).origin;
|
|
155
|
+
for (const pattern of trustedOrigins) {
|
|
156
|
+
const regex = patternToRegex(pattern);
|
|
157
|
+
if (regex?.test(urlOrigin)) return true;
|
|
158
|
+
try {
|
|
159
|
+
if (isValidURL(pattern) && equals(new URL(pattern).origin, urlOrigin)) return true;
|
|
160
|
+
} catch {
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
} catch {
|
|
164
|
+
}
|
|
165
|
+
return false;
|
|
166
|
+
};
|
|
167
|
+
var safeEquals = (a, b) => {
|
|
168
|
+
const bufferA = Buffer.from(a);
|
|
169
|
+
const bufferB = Buffer.from(b);
|
|
170
|
+
if (bufferA.length !== bufferB.length) {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
return (0, import_crypto.timingSafeEqual)(bufferA, bufferB);
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
// src/env.ts
|
|
177
|
+
var import_meta = {};
|
|
178
|
+
var env = new Proxy({}, {
|
|
179
|
+
get(_, prop) {
|
|
180
|
+
if (typeof prop !== "string") return void 0;
|
|
181
|
+
const hasProperty = (process2) => {
|
|
182
|
+
return process2 && Object.prototype.hasOwnProperty.call(process2, prop);
|
|
183
|
+
};
|
|
184
|
+
try {
|
|
185
|
+
if (typeof process !== "undefined" && hasProperty(process.env)) {
|
|
186
|
+
return process.env[prop];
|
|
187
|
+
}
|
|
188
|
+
if (typeof import_meta !== "undefined" && hasProperty(import_meta.env)) {
|
|
189
|
+
return import_meta.env[prop];
|
|
190
|
+
}
|
|
191
|
+
if (typeof Deno !== "undefined" && Deno.env?.get) {
|
|
192
|
+
return Deno.env.get(prop);
|
|
193
|
+
}
|
|
194
|
+
if (typeof Bun !== "undefined" && hasProperty(Bun.env)) {
|
|
195
|
+
return Bun.env[prop];
|
|
196
|
+
}
|
|
197
|
+
const globalValue = globalThis[prop];
|
|
198
|
+
return typeof globalValue === "string" ? globalValue : void 0;
|
|
199
|
+
} catch {
|
|
200
|
+
return void 0;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// src/jose.ts
|
|
206
|
+
var import_jose = require("@aura-stack/jose");
|
|
207
|
+
var jwtVerificationOptions = {
|
|
208
|
+
algorithms: ["HS256"],
|
|
209
|
+
typ: "JWT"
|
|
210
|
+
};
|
|
118
211
|
|
|
119
212
|
// src/secure.ts
|
|
120
213
|
var verifyCSRF = async (jose, cookie, header) => {
|
|
121
214
|
try {
|
|
122
|
-
const cookiePayload = await jose.verifyJWS(cookie);
|
|
123
|
-
const headerPayload = await jose.verifyJWS(header);
|
|
215
|
+
const cookiePayload = await jose.verifyJWS(cookie, jwtVerificationOptions);
|
|
216
|
+
const headerPayload = await jose.verifyJWS(header, jwtVerificationOptions);
|
|
124
217
|
if (!isJWTPayloadWithToken(cookiePayload)) {
|
|
125
218
|
throw new AuthSecurityError("CSRF_TOKEN_INVALID", "Cookie payload missing token field.");
|
|
126
219
|
}
|
|
127
220
|
if (!isJWTPayloadWithToken(headerPayload)) {
|
|
128
221
|
throw new AuthSecurityError("CSRF_TOKEN_INVALID", "Header payload missing token field.");
|
|
129
222
|
}
|
|
130
|
-
|
|
131
|
-
const headerBuffer = Buffer.from(headerPayload.token);
|
|
132
|
-
if (!equals(headerBuffer.length, cookieBuffer.length)) {
|
|
223
|
+
if (!equals(cookiePayload.token.length, headerPayload.token.length)) {
|
|
133
224
|
throw new AuthSecurityError("CSRF_TOKEN_INVALID", "The CSRF tokens do not match.");
|
|
134
225
|
}
|
|
135
|
-
if (!
|
|
226
|
+
if (!safeEquals(cookiePayload.token, headerPayload.token)) {
|
|
136
227
|
throw new AuthSecurityError("CSRF_TOKEN_INVALID", "The CSRF tokens do not match.");
|
|
137
228
|
}
|
|
138
229
|
return true;
|
|
@@ -148,6 +239,26 @@ var cacheControl = {
|
|
|
148
239
|
Expires: "0",
|
|
149
240
|
Vary: "Cookie"
|
|
150
241
|
};
|
|
242
|
+
var contentSecurityPolicy = {
|
|
243
|
+
"Content-Security-Policy": [
|
|
244
|
+
"default-src 'none'",
|
|
245
|
+
"script-src 'self'",
|
|
246
|
+
"frame-src 'none'",
|
|
247
|
+
"object-src 'none'",
|
|
248
|
+
"frame-ancestors 'none'",
|
|
249
|
+
"base-uri 'none'"
|
|
250
|
+
].join("; ")
|
|
251
|
+
};
|
|
252
|
+
var secureHeaders = {
|
|
253
|
+
"X-Content-Type-Options": "nosniff",
|
|
254
|
+
"X-Frame-Options": "DENY",
|
|
255
|
+
"Referrer-Policy": "strict-origin-when-cross-origin"
|
|
256
|
+
};
|
|
257
|
+
var secureApiHeaders = {
|
|
258
|
+
...cacheControl,
|
|
259
|
+
...contentSecurityPolicy,
|
|
260
|
+
...secureHeaders
|
|
261
|
+
};
|
|
151
262
|
|
|
152
263
|
// src/cookie.ts
|
|
153
264
|
var import_cookie = require("@aura-stack/router/cookie");
|
|
@@ -166,11 +277,24 @@ var oauthCookieOptions = {
|
|
|
166
277
|
var expiredCookieAttributes = {
|
|
167
278
|
...defaultCookieOptions,
|
|
168
279
|
expires: /* @__PURE__ */ new Date(0),
|
|
169
|
-
maxAge: 0
|
|
280
|
+
maxAge: 0,
|
|
281
|
+
secure: true
|
|
170
282
|
};
|
|
171
283
|
|
|
172
284
|
// src/schemas.ts
|
|
173
285
|
var import_zod = require("zod");
|
|
286
|
+
var OAuthProviderCredentialsSchema = (0, import_zod.object)({
|
|
287
|
+
id: (0, import_zod.string)(),
|
|
288
|
+
name: (0, import_zod.string)(),
|
|
289
|
+
authorizeURL: (0, import_zod.string)().url(),
|
|
290
|
+
accessToken: (0, import_zod.string)().url(),
|
|
291
|
+
scope: (0, import_zod.string)(),
|
|
292
|
+
userInfo: (0, import_zod.string)().url(),
|
|
293
|
+
responseType: (0, import_zod.enum)(["code", "token", "id_token"]),
|
|
294
|
+
clientId: (0, import_zod.string)(),
|
|
295
|
+
clientSecret: (0, import_zod.string)(),
|
|
296
|
+
profile: import_zod.z.function().optional()
|
|
297
|
+
});
|
|
174
298
|
var OAuthProviderConfigSchema = (0, import_zod.object)({
|
|
175
299
|
authorizeURL: (0, import_zod.string)().url(),
|
|
176
300
|
accessToken: (0, import_zod.string)().url(),
|
|
@@ -238,58 +362,59 @@ var OAuthEnvSchema = (0, import_zod.object)({
|
|
|
238
362
|
});
|
|
239
363
|
|
|
240
364
|
// src/actions/signIn/authorization.ts
|
|
241
|
-
var
|
|
365
|
+
var getTrustedOrigins = async (request, trustedOrigins) => {
|
|
366
|
+
if (!trustedOrigins) return [];
|
|
367
|
+
const raw = typeof trustedOrigins === "function" ? await trustedOrigins(request) : trustedOrigins;
|
|
368
|
+
return Array.isArray(raw) ? raw : typeof raw === "string" ? [raw] : [];
|
|
369
|
+
};
|
|
370
|
+
var getOriginURL = async (request, context) => {
|
|
242
371
|
const headers = request.headers;
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
372
|
+
let origin = new URL(request.url).origin;
|
|
373
|
+
const trustedOrigins = await getTrustedOrigins(request, context?.trustedOrigins);
|
|
374
|
+
trustedOrigins.push(origin);
|
|
375
|
+
if (context?.trustedProxyHeaders) {
|
|
376
|
+
const protocol = headers.get("Forwarded")?.match(/proto=([^;]+)/i)?.[1] ?? headers.get("X-Forwarded-Proto") ?? "http";
|
|
377
|
+
const host = headers.get("Host") ?? headers.get("Forwarded")?.match(/host=([^;]+)/i)?.[1] ?? headers.get("X-Forwarded-Host") ?? null;
|
|
378
|
+
origin = `${protocol}://${host}`;
|
|
379
|
+
}
|
|
380
|
+
if (!isTrustedOrigin(origin, trustedOrigins)) {
|
|
381
|
+
context?.logger?.log("UNTRUSTED_ORIGIN", { structuredData: { origin } });
|
|
382
|
+
throw new AuthInternalError("UNTRUSTED_ORIGIN", "The constructed origin URL is not trusted.");
|
|
249
383
|
}
|
|
384
|
+
return origin;
|
|
250
385
|
};
|
|
251
|
-
var createRedirectTo = (request, redirectTo,
|
|
386
|
+
var createRedirectTo = async (request, redirectTo, context) => {
|
|
252
387
|
try {
|
|
253
388
|
const headers = request.headers;
|
|
254
|
-
const
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
if (
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
if (!isValidURL(referer) || !equals(refererURL.origin, hostedURL.origin)) {
|
|
273
|
-
throw new AuthSecurityError(
|
|
274
|
-
"POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED",
|
|
275
|
-
"The referer of the request does not match the hosted origin."
|
|
276
|
-
);
|
|
389
|
+
const requestOrigin = await getOriginURL(request, context);
|
|
390
|
+
const origins = await getTrustedOrigins(request, context?.trustedOrigins);
|
|
391
|
+
const validateURL = (url) => {
|
|
392
|
+
if (!isRelativeURL(url) && !isValidURL(url)) return "/";
|
|
393
|
+
if (isRelativeURL(url)) return url;
|
|
394
|
+
if (origins.length > 0) {
|
|
395
|
+
if (isTrustedOrigin(url, origins)) {
|
|
396
|
+
const urlOrigin = new URL(url).origin;
|
|
397
|
+
for (const pattern of origins) {
|
|
398
|
+
const regex = patternToRegex(pattern);
|
|
399
|
+
if (regex?.test(urlOrigin)) {
|
|
400
|
+
return isSameOrigin(url, request.url) ? extractPath(url) : url;
|
|
401
|
+
}
|
|
402
|
+
if (isValidURL(pattern) && equals(new URL(pattern).origin, urlOrigin)) return url;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
context?.logger?.log("OPEN_REDIRECT_ATTACK");
|
|
406
|
+
return "/";
|
|
277
407
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
if (origin) {
|
|
281
|
-
const originURL = new URL(sanitizeURL(getNormalizedOriginPath(origin)));
|
|
282
|
-
if (!isValidURL(origin) || !equals(originURL.origin, hostedURL.origin)) {
|
|
283
|
-
throw new AuthSecurityError("POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED", "Invalid origin (potential CSRF).");
|
|
408
|
+
if (isSameOrigin(url, requestOrigin)) {
|
|
409
|
+
return extractPath(url);
|
|
284
410
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
411
|
+
context?.logger?.log("OPEN_REDIRECT_ATTACK");
|
|
412
|
+
return "/";
|
|
413
|
+
};
|
|
414
|
+
return validateURL(redirectTo ?? headers.get("Referer") ?? headers.get("Origin") ?? "/");
|
|
288
415
|
} catch (error) {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
}
|
|
292
|
-
throw new AuthSecurityError("POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED", "Invalid origin (potential CSRF).");
|
|
416
|
+
context?.logger?.log("POTENTIAL_OPEN_REDIRECT_ATTACK_DETECTED");
|
|
417
|
+
return "/";
|
|
293
418
|
}
|
|
294
419
|
};
|
|
295
420
|
|
|
@@ -310,30 +435,54 @@ var signOutAction = (0, import_router2.createEndpoint)(
|
|
|
310
435
|
request,
|
|
311
436
|
headers,
|
|
312
437
|
searchParams: { redirectTo },
|
|
313
|
-
context
|
|
438
|
+
context
|
|
314
439
|
} = ctx;
|
|
440
|
+
const { jose, cookies, logger } = context;
|
|
315
441
|
const session = headers.getCookie(cookies.sessionToken.name);
|
|
316
442
|
const csrfToken = headers.getCookie(cookies.csrfToken.name);
|
|
317
443
|
const header = headers.getHeader("X-CSRF-Token");
|
|
444
|
+
logger?.log("SIGN_OUT_ATTEMPT", {
|
|
445
|
+
structuredData: {
|
|
446
|
+
has_session: Boolean(session),
|
|
447
|
+
has_csrf_token: Boolean(csrfToken),
|
|
448
|
+
has_csrf_header: Boolean(header)
|
|
449
|
+
}
|
|
450
|
+
});
|
|
318
451
|
if (!session) {
|
|
452
|
+
logger?.log("SESSION_TOKEN_MISSING");
|
|
319
453
|
throw new AuthSecurityError("SESSION_TOKEN_MISSING", "The sessionToken is missing.");
|
|
320
454
|
}
|
|
321
455
|
if (!csrfToken) {
|
|
456
|
+
logger?.log("CSRF_TOKEN_MISSING");
|
|
322
457
|
throw new AuthSecurityError("CSRF_TOKEN_MISSING", "The CSRF token is missing.");
|
|
323
458
|
}
|
|
324
459
|
if (!header) {
|
|
325
|
-
|
|
460
|
+
logger?.log("CSRF_HEADER_MISSING");
|
|
461
|
+
throw new AuthSecurityError("CSRF_HEADER_MISSING", "The CSRF header is missing.");
|
|
462
|
+
}
|
|
463
|
+
try {
|
|
464
|
+
await verifyCSRF(jose, csrfToken, header);
|
|
465
|
+
} catch (error) {
|
|
466
|
+
logger?.log("CSRF_TOKEN_INVALID", { structuredData: { error_type: getErrorName(error) } });
|
|
467
|
+
throw new AuthSecurityError("CSRF_TOKEN_INVALID", "CSRF token verification failed");
|
|
468
|
+
}
|
|
469
|
+
logger?.log("SIGN_OUT_CSRF_VERIFIED");
|
|
470
|
+
try {
|
|
471
|
+
await jose.decodeJWT(session);
|
|
472
|
+
logger?.log("SIGN_OUT_SUCCESS");
|
|
473
|
+
} catch (error) {
|
|
474
|
+
logger?.log("INVALID_JWT_TOKEN", { structuredData: { error_type: getErrorName(error) } });
|
|
326
475
|
}
|
|
327
|
-
|
|
328
|
-
await
|
|
329
|
-
|
|
330
|
-
const location = createRedirectTo(
|
|
331
|
-
new Request(normalizedOriginPath, {
|
|
476
|
+
const baseURL = getBaseURL(request);
|
|
477
|
+
const location = await createRedirectTo(
|
|
478
|
+
new Request(baseURL, {
|
|
332
479
|
headers: headers.toHeaders()
|
|
333
480
|
}),
|
|
334
|
-
redirectTo
|
|
481
|
+
redirectTo,
|
|
482
|
+
context
|
|
335
483
|
);
|
|
336
|
-
|
|
484
|
+
logger?.log("SIGN_OUT_REDIRECT", { structuredData: { location } });
|
|
485
|
+
const headersList = new import_router2.HeadersBuilder(secureApiHeaders).setHeader("Location", location).setCookie(cookies.csrfToken.name, "", expiredCookieAttributes).setCookie(cookies.sessionToken.name, "", expiredCookieAttributes).toHeaders();
|
|
337
486
|
return Response.json({ message: "Signed out successfully" }, { status: import_router2.statusCode.ACCEPTED, headers: headersList });
|
|
338
487
|
},
|
|
339
488
|
config
|
|
@@ -1,16 +1,8 @@
|
|
|
1
1
|
import * as _aura_stack_router from '@aura-stack/router';
|
|
2
|
-
import { z } from 'zod';
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
4
|
* @see https://datatracker.ietf.org/doc/html/rfc7009
|
|
6
5
|
*/
|
|
7
|
-
declare const signOutAction: _aura_stack_router.RouteEndpoint<"POST", "/signOut", {
|
|
8
|
-
schemas?: {
|
|
9
|
-
searchParams: z.ZodObject<{
|
|
10
|
-
token_type_hint: z.ZodLiteral<"session_token">;
|
|
11
|
-
redirectTo: z.ZodOptional<z.ZodString>;
|
|
12
|
-
}, z.core.$strip>;
|
|
13
|
-
} | undefined;
|
|
14
|
-
}>;
|
|
6
|
+
declare const signOutAction: _aura_stack_router.RouteEndpoint<"POST", "/signOut", {}>;
|
|
15
7
|
|
|
16
8
|
export { signOutAction };
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
signOutAction
|
|
3
|
-
} from "../../chunk-
|
|
4
|
-
import "../../chunk-
|
|
5
|
-
import "../../chunk-
|
|
6
|
-
import "../../chunk-
|
|
7
|
-
import "../../chunk-
|
|
8
|
-
import "../../chunk-
|
|
9
|
-
import "../../chunk-
|
|
3
|
+
} from "../../chunk-ALG3GIV4.js";
|
|
4
|
+
import "../../chunk-XUP6KKNG.js";
|
|
5
|
+
import "../../chunk-KJBAQZX2.js";
|
|
6
|
+
import "../../chunk-NUDITUKX.js";
|
|
7
|
+
import "../../chunk-4EKY7655.js";
|
|
8
|
+
import "../../chunk-QQVSRXGX.js";
|
|
9
|
+
import "../../chunk-5W4BRQYG.js";
|
|
10
|
+
import "../../chunk-EBAMFRB7.js";
|
|
11
|
+
import "../../chunk-FRJFWTOY.js";
|
|
12
|
+
import "../../chunk-4MYWAOLG.js";
|
|
10
13
|
import "../../chunk-RRLIF4PQ.js";
|
|
11
|
-
import "../../chunk-YRCB5FLE.js";
|
|
12
14
|
export {
|
|
13
15
|
signOutAction
|
|
14
16
|
};
|