@atproto/oauth-provider 0.16.5 → 0.17.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/CHANGELOG.md +32 -0
- package/dist/access-token/access-token-mode.js +2 -5
- package/dist/access-token/access-token-mode.js.map +1 -1
- package/dist/account/account-manager.js +25 -33
- package/dist/account/account-manager.js.map +1 -1
- package/dist/account/account-store.js +11 -32
- package/dist/account/account-store.js.map +1 -1
- package/dist/account/sign-in-data.js +9 -12
- package/dist/account/sign-in-data.js.map +1 -1
- package/dist/account/sign-up-input.js +14 -17
- package/dist/account/sign-up-input.js.map +1 -1
- package/dist/client/client-auth.js +1 -2
- package/dist/client/client-data.js +1 -2
- package/dist/client/client-id.js +2 -5
- package/dist/client/client-id.js.map +1 -1
- package/dist/client/client-info.js +1 -2
- package/dist/client/client-manager.js +86 -97
- package/dist/client/client-manager.js.map +1 -1
- package/dist/client/client-store.js +7 -26
- package/dist/client/client-store.js.map +1 -1
- package/dist/client/client-utils.js +10 -14
- package/dist/client/client-utils.js.map +1 -1
- package/dist/client/client.js +43 -53
- package/dist/client/client.js.map +1 -1
- package/dist/constants.js +28 -31
- package/dist/constants.js.map +1 -1
- package/dist/customization/branding.js +8 -11
- package/dist/customization/branding.js.map +1 -1
- package/dist/customization/build-customization-css.js +8 -11
- package/dist/customization/build-customization-css.js.map +1 -1
- package/dist/customization/build-customization-data.js +1 -4
- package/dist/customization/build-customization-data.js.map +1 -1
- package/dist/customization/colors.js +11 -14
- package/dist/customization/colors.js.map +1 -1
- package/dist/customization/customization.js +8 -11
- package/dist/customization/customization.js.map +1 -1
- package/dist/customization/links.js +7 -10
- package/dist/customization/links.js.map +1 -1
- package/dist/device/device-data.js +7 -10
- package/dist/device/device-data.js.map +1 -1
- package/dist/device/device-id.js +11 -16
- package/dist/device/device-id.js.map +1 -1
- package/dist/device/device-manager.js +32 -38
- package/dist/device/device-manager.js.map +1 -1
- package/dist/device/device-store.js +7 -25
- package/dist/device/device-store.js.map +1 -1
- package/dist/device/session-id.js +9 -13
- package/dist/device/session-id.js.map +1 -1
- package/dist/dpop/dpop-manager.d.ts +3 -3
- package/dist/dpop/dpop-manager.js +38 -43
- package/dist/dpop/dpop-manager.js.map +1 -1
- package/dist/dpop/dpop-nonce.d.ts +2 -2
- package/dist/dpop/dpop-nonce.d.ts.map +1 -1
- package/dist/dpop/dpop-nonce.js +14 -18
- package/dist/dpop/dpop-nonce.js.map +1 -1
- package/dist/dpop/dpop-proof.js +1 -2
- package/dist/errors/access-denied-error.js +2 -6
- package/dist/errors/access-denied-error.js.map +1 -1
- package/dist/errors/account-selection-required-error.js +2 -6
- package/dist/errors/account-selection-required-error.js.map +1 -1
- package/dist/errors/authorization-error.js +7 -12
- package/dist/errors/authorization-error.js.map +1 -1
- package/dist/errors/consent-required-error.js +2 -6
- package/dist/errors/consent-required-error.js.map +1 -1
- package/dist/errors/error-parser.js +14 -18
- package/dist/errors/error-parser.js.map +1 -1
- package/dist/errors/handle-unavailable-error.js +2 -7
- package/dist/errors/handle-unavailable-error.js.map +1 -1
- package/dist/errors/invalid-authorization-details-error.js +2 -6
- package/dist/errors/invalid-authorization-details-error.js.map +1 -1
- package/dist/errors/invalid-client-error.js +2 -6
- package/dist/errors/invalid-client-error.js.map +1 -1
- package/dist/errors/invalid-client-id-error.js +2 -6
- package/dist/errors/invalid-client-id-error.js.map +1 -1
- package/dist/errors/invalid-client-metadata-error.js +7 -11
- package/dist/errors/invalid-client-metadata-error.js.map +1 -1
- package/dist/errors/invalid-credentials-error.js +2 -7
- package/dist/errors/invalid-credentials-error.js.map +1 -1
- package/dist/errors/invalid-dpop-key-binding-error.js +2 -6
- package/dist/errors/invalid-dpop-key-binding-error.js.map +1 -1
- package/dist/errors/invalid-dpop-proof-error.js +2 -6
- package/dist/errors/invalid-dpop-proof-error.js.map +1 -1
- package/dist/errors/invalid-grant-error.js +2 -6
- package/dist/errors/invalid-grant-error.js.map +1 -1
- package/dist/errors/invalid-invite-code-error.d.ts +1 -1
- package/dist/errors/invalid-invite-code-error.d.ts.map +1 -1
- package/dist/errors/invalid-invite-code-error.js +2 -6
- package/dist/errors/invalid-invite-code-error.js.map +1 -1
- package/dist/errors/invalid-redirect-uri-error.js +2 -6
- package/dist/errors/invalid-redirect-uri-error.js.map +1 -1
- package/dist/errors/invalid-request-error.js +3 -7
- package/dist/errors/invalid-request-error.js.map +1 -1
- package/dist/errors/invalid-scope-error.js +2 -6
- package/dist/errors/invalid-scope-error.js.map +1 -1
- package/dist/errors/invalid-token-error.js +10 -15
- package/dist/errors/invalid-token-error.js.map +1 -1
- package/dist/errors/login-required-error.js +2 -6
- package/dist/errors/login-required-error.js.map +1 -1
- package/dist/errors/oauth-error.js +1 -9
- package/dist/errors/oauth-error.js.map +1 -1
- package/dist/errors/second-authentication-factor-required-error.js +2 -8
- package/dist/errors/second-authentication-factor-required-error.js.map +1 -1
- package/dist/errors/unauthorized-client-error.js +2 -6
- package/dist/errors/unauthorized-client-error.js.map +1 -1
- package/dist/errors/use-dpop-nonce-error.js +4 -8
- package/dist/errors/use-dpop-nonce-error.js.map +1 -1
- package/dist/errors/www-authenticate-error.js +4 -9
- package/dist/errors/www-authenticate-error.js.map +1 -1
- package/dist/index.js +14 -30
- package/dist/index.js.map +1 -1
- package/dist/lexicon/lexicon-data.js +1 -2
- package/dist/lexicon/lexicon-getter.js +6 -10
- package/dist/lexicon/lexicon-getter.js.map +1 -1
- package/dist/lexicon/lexicon-manager.js +10 -30
- package/dist/lexicon/lexicon-manager.js.map +1 -1
- package/dist/lexicon/lexicon-store.js +5 -10
- package/dist/lexicon/lexicon-store.js.map +1 -1
- package/dist/lib/csp/index.js +3 -8
- package/dist/lib/csp/index.js.map +1 -1
- package/dist/lib/hcaptcha.js +33 -43
- package/dist/lib/hcaptcha.js.map +1 -1
- package/dist/lib/html/build-document.js +19 -24
- package/dist/lib/html/build-document.js.map +1 -1
- package/dist/lib/html/escapers.js +10 -16
- package/dist/lib/html/escapers.js.map +1 -1
- package/dist/lib/html/html.js +1 -5
- package/dist/lib/html/html.js.map +1 -1
- package/dist/lib/html/hydration-data.js +6 -10
- package/dist/lib/html/hydration-data.js.map +1 -1
- package/dist/lib/html/index.js +3 -19
- package/dist/lib/html/index.js.map +1 -1
- package/dist/lib/html/tags.js +14 -23
- package/dist/lib/html/tags.js.map +1 -1
- package/dist/lib/html/util.js +1 -4
- package/dist/lib/html/util.js.map +1 -1
- package/dist/lib/http/accept.d.ts.map +1 -1
- package/dist/lib/http/accept.js +8 -8
- package/dist/lib/http/accept.js.map +1 -1
- package/dist/lib/http/context.js +1 -4
- package/dist/lib/http/context.js.map +1 -1
- package/dist/lib/http/headers.js +1 -4
- package/dist/lib/http/headers.js.map +1 -1
- package/dist/lib/http/index.js +10 -26
- package/dist/lib/http/index.js.map +1 -1
- package/dist/lib/http/method.js +1 -4
- package/dist/lib/http/method.js.map +1 -1
- package/dist/lib/http/middleware.js +11 -17
- package/dist/lib/http/middleware.js.map +1 -1
- package/dist/lib/http/parser.js +13 -20
- package/dist/lib/http/parser.js.map +1 -1
- package/dist/lib/http/path.js +1 -4
- package/dist/lib/http/path.js.map +1 -1
- package/dist/lib/http/request.d.ts.map +1 -1
- package/dist/lib/http/request.js +32 -47
- package/dist/lib/http/request.js.map +1 -1
- package/dist/lib/http/response.js +14 -27
- package/dist/lib/http/response.js.map +1 -1
- package/dist/lib/http/route.js +9 -12
- package/dist/lib/http/route.js.map +1 -1
- package/dist/lib/http/router.js +8 -13
- package/dist/lib/http/router.js.map +1 -1
- package/dist/lib/http/security-headers.js +10 -15
- package/dist/lib/http/security-headers.js.map +1 -1
- package/dist/lib/http/stream.js +12 -20
- package/dist/lib/http/stream.js.map +1 -1
- package/dist/lib/http/types.js +1 -2
- package/dist/lib/http/url.js +1 -4
- package/dist/lib/http/url.js.map +1 -1
- package/dist/lib/nsid.js +4 -8
- package/dist/lib/nsid.js.map +1 -1
- package/dist/lib/redis.js +4 -7
- package/dist/lib/redis.js.map +1 -1
- package/dist/lib/util/authorization-header.js +11 -15
- package/dist/lib/util/authorization-header.js.map +1 -1
- package/dist/lib/util/cast.js +3 -8
- package/dist/lib/util/cast.js.map +1 -1
- package/dist/lib/util/color.js +23 -32
- package/dist/lib/util/color.js.map +1 -1
- package/dist/lib/util/crypto.js +5 -10
- package/dist/lib/util/crypto.js.map +1 -1
- package/dist/lib/util/date.js +2 -6
- package/dist/lib/util/date.js.map +1 -1
- package/dist/lib/util/error.js +5 -8
- package/dist/lib/util/error.js.map +1 -1
- package/dist/lib/util/function.js +3 -8
- package/dist/lib/util/function.js.map +1 -1
- package/dist/lib/util/locale.js +3 -6
- package/dist/lib/util/locale.js.map +1 -1
- package/dist/lib/util/object.js +1 -4
- package/dist/lib/util/object.js.map +1 -1
- package/dist/lib/util/redirect-uri.js +3 -6
- package/dist/lib/util/redirect-uri.js.map +1 -1
- package/dist/lib/util/time.js +5 -9
- package/dist/lib/util/time.js.map +1 -1
- package/dist/lib/util/type.d.ts.map +1 -1
- package/dist/lib/util/type.js +1 -5
- package/dist/lib/util/type.js.map +1 -1
- package/dist/lib/util/ui8.js +3 -8
- package/dist/lib/util/ui8.js.map +1 -1
- package/dist/lib/util/well-known.js +1 -4
- package/dist/lib/util/well-known.js.map +1 -1
- package/dist/lib/util/zod-error.js +4 -8
- package/dist/lib/util/zod-error.js.map +1 -1
- package/dist/lib/write-form-redirect.js +9 -12
- package/dist/lib/write-form-redirect.js.map +1 -1
- package/dist/lib/write-html.js +12 -15
- package/dist/lib/write-html.js.map +1 -1
- package/dist/metadata/build-metadata.js +9 -12
- package/dist/metadata/build-metadata.js.map +1 -1
- package/dist/oauth-client.js +2 -18
- package/dist/oauth-client.js.map +1 -1
- package/dist/oauth-dpop.js +2 -18
- package/dist/oauth-dpop.js.map +1 -1
- package/dist/oauth-errors.js +24 -42
- package/dist/oauth-errors.js.map +1 -1
- package/dist/oauth-hooks.js +8 -15
- package/dist/oauth-hooks.js.map +1 -1
- package/dist/oauth-middleware.js +13 -16
- package/dist/oauth-middleware.js.map +1 -1
- package/dist/oauth-provider.js +108 -125
- package/dist/oauth-provider.js.map +1 -1
- package/dist/oauth-store.js +7 -23
- package/dist/oauth-store.js.map +1 -1
- package/dist/oauth-verifier.js +41 -53
- package/dist/oauth-verifier.js.map +1 -1
- package/dist/oidc/sub.js +2 -5
- package/dist/oidc/sub.js.map +1 -1
- package/dist/replay/replay-manager.js +6 -11
- package/dist/replay/replay-manager.js.map +1 -1
- package/dist/replay/replay-store-memory.js +5 -7
- package/dist/replay/replay-store-memory.js.map +1 -1
- package/dist/replay/replay-store-redis.js +3 -8
- package/dist/replay/replay-store-redis.js.map +1 -1
- package/dist/replay/replay-store.js +3 -8
- package/dist/replay/replay-store.js.map +1 -1
- package/dist/request/code.js +10 -15
- package/dist/request/code.js.map +1 -1
- package/dist/request/request-data.js +1 -5
- package/dist/request/request-data.js.map +1 -1
- package/dist/request/request-id.js +9 -13
- package/dist/request/request-id.js.map +1 -1
- package/dist/request/request-manager.js +61 -71
- package/dist/request/request-manager.js.map +1 -1
- package/dist/request/request-store.js +9 -27
- package/dist/request/request-store.js.map +1 -1
- package/dist/request/request-uri.js +17 -23
- package/dist/request/request-uri.js.map +1 -1
- package/dist/result/authorization-redirect-parameters.js +1 -2
- package/dist/result/authorization-result-authorize-page.js +1 -2
- package/dist/result/authorization-result-redirect.js +1 -2
- package/dist/router/assets/assets-manifest.d.ts.map +1 -1
- package/dist/router/assets/assets-manifest.js +14 -15
- package/dist/router/assets/assets-manifest.js.map +1 -1
- package/dist/router/assets/assets.d.ts.map +1 -1
- package/dist/router/assets/assets.js +25 -27
- package/dist/router/assets/assets.js.map +1 -1
- package/dist/router/assets/csrf.js +16 -25
- package/dist/router/assets/csrf.js.map +1 -1
- package/dist/router/assets/send-account-page.js +3 -6
- package/dist/router/assets/send-account-page.js.map +1 -1
- package/dist/router/assets/send-authorization-page.js +3 -6
- package/dist/router/assets/send-authorization-page.js.map +1 -1
- package/dist/router/assets/send-cookie-error-page.js +3 -6
- package/dist/router/assets/send-cookie-error-page.js.map +1 -1
- package/dist/router/assets/send-error-page.js +6 -9
- package/dist/router/assets/send-error-page.js.map +1 -1
- package/dist/router/assets/send-redirect.js +12 -20
- package/dist/router/assets/send-redirect.js.map +1 -1
- package/dist/router/create-account-page-middleware.js +11 -14
- package/dist/router/create-account-page-middleware.js.map +1 -1
- package/dist/router/create-api-middleware.js +83 -90
- package/dist/router/create-api-middleware.js.map +1 -1
- package/dist/router/create-authorization-page-middleware.js +43 -46
- package/dist/router/create-authorization-page-middleware.js.map +1 -1
- package/dist/router/create-oauth-middleware.js +31 -34
- package/dist/router/create-oauth-middleware.js.map +1 -1
- package/dist/router/error-handler.js +1 -2
- package/dist/router/middleware-options.js +1 -2
- package/dist/signer/access-token-payload.js +12 -15
- package/dist/signer/access-token-payload.js.map +1 -1
- package/dist/signer/api-token-payload.js +8 -11
- package/dist/signer/api-token-payload.js.map +1 -1
- package/dist/signer/signer.js +11 -17
- package/dist/signer/signer.js.map +1 -1
- package/dist/token/refresh-token.js +10 -15
- package/dist/token/refresh-token.js.map +1 -1
- package/dist/token/token-claims.js +1 -2
- package/dist/token/token-data.js +1 -2
- package/dist/token/token-id.js +10 -15
- package/dist/token/token-id.js.map +1 -1
- package/dist/token/token-manager.js +40 -51
- package/dist/token/token-manager.js.map +1 -1
- package/dist/token/token-store.js +7 -25
- package/dist/token/token-store.js.map +1 -1
- package/dist/types/authorization-response-error.js +8 -12
- package/dist/types/authorization-response-error.js.map +1 -1
- package/dist/types/color-hue.js +2 -5
- package/dist/types/color-hue.js.map +1 -1
- package/dist/types/email-otp.js +2 -5
- package/dist/types/email-otp.js.map +1 -1
- package/dist/types/email.js +6 -9
- package/dist/types/email.js.map +1 -1
- package/dist/types/handle.js +6 -9
- package/dist/types/handle.js.map +1 -1
- package/dist/types/invite-code.js +2 -5
- package/dist/types/invite-code.js.map +1 -1
- package/dist/types/par-response-error.js +5 -9
- package/dist/types/par-response-error.js.map +1 -1
- package/dist/types/password.js +3 -6
- package/dist/types/password.js.map +1 -1
- package/dist/types/rgb-color.js +7 -10
- package/dist/types/rgb-color.js.map +1 -1
- package/package.json +20 -22
- package/src/dpop/dpop-nonce.ts +1 -1
- package/src/errors/invalid-invite-code-error.ts +1 -1
- package/src/lib/http/accept.ts +4 -1
- package/src/lib/http/request.ts +4 -1
- package/src/lib/util/type.ts +0 -1
- package/src/router/assets/assets-manifest.ts +3 -1
- package/src/router/assets/assets.ts +2 -0
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.setupCsrfToken = setupCsrfToken;
|
|
7
|
-
exports.validateCsrfToken = validateCsrfToken;
|
|
8
|
-
exports.getCookieCsrf = getCookieCsrf;
|
|
9
|
-
exports.getHeadersCsrf = getHeadersCsrf;
|
|
10
|
-
const http_errors_1 = __importDefault(require("http-errors"));
|
|
11
|
-
const oauth_provider_api_1 = require("@atproto/oauth-provider-api");
|
|
12
|
-
const index_js_1 = require("../../lib/http/index.js");
|
|
13
|
-
const crypto_js_1 = require("../../lib/util/crypto.js");
|
|
1
|
+
import createHttpError from 'http-errors';
|
|
2
|
+
import { CSRF_COOKIE_NAME, CSRF_HEADER_NAME } from '@atproto/oauth-provider-api';
|
|
3
|
+
import { getCookie, setCookie, } from '../../lib/http/index.js';
|
|
4
|
+
import { randomHexId } from '../../lib/util/crypto.js';
|
|
14
5
|
const TOKEN_BYTE_LENGTH = 12;
|
|
15
6
|
const TOKEN_LENGTH = TOKEN_BYTE_LENGTH * 2; // 2 hex chars per byte
|
|
16
7
|
// @NOTE Cookie based CSRF protection is redundant with session cookies using
|
|
@@ -23,38 +14,38 @@ const CSRF_COOKIE_OPTIONS = {
|
|
|
23
14
|
path: `/`,
|
|
24
15
|
};
|
|
25
16
|
async function generateCsrfToken() {
|
|
26
|
-
return
|
|
17
|
+
return randomHexId(TOKEN_BYTE_LENGTH);
|
|
27
18
|
}
|
|
28
|
-
async function setupCsrfToken(req, res) {
|
|
19
|
+
export async function setupCsrfToken(req, res) {
|
|
29
20
|
const token = getCookieCsrf(req) || (await generateCsrfToken());
|
|
30
21
|
// Refresh cookie (See Chrome's "Lax+POST" behavior)
|
|
31
|
-
|
|
22
|
+
setCookie(res, CSRF_COOKIE_NAME, token, CSRF_COOKIE_OPTIONS);
|
|
32
23
|
}
|
|
33
|
-
async function validateCsrfToken(req, res) {
|
|
24
|
+
export async function validateCsrfToken(req, res) {
|
|
34
25
|
const cookieValue = getCookieCsrf(req);
|
|
35
26
|
const headerValue = getHeadersCsrf(req);
|
|
36
27
|
// Refresh cookie (See Chrome's "Lax+POST" behavior), or set a new one,
|
|
37
28
|
// allowing clients to retry with the new token.
|
|
38
|
-
|
|
29
|
+
setCookie(res, CSRF_COOKIE_NAME, cookieValue || (await generateCsrfToken()), CSRF_COOKIE_OPTIONS);
|
|
39
30
|
if (!headerValue) {
|
|
40
|
-
throw (
|
|
31
|
+
throw createHttpError(400, `Missing CSRF header`);
|
|
41
32
|
}
|
|
42
33
|
if (!cookieValue) {
|
|
43
|
-
throw (
|
|
34
|
+
throw createHttpError(400, `Missing CSRF cookie`);
|
|
44
35
|
}
|
|
45
36
|
if (cookieValue !== headerValue) {
|
|
46
|
-
throw (
|
|
37
|
+
throw createHttpError(400, `CSRF mismatch`);
|
|
47
38
|
}
|
|
48
39
|
}
|
|
49
|
-
function getCookieCsrf(req) {
|
|
50
|
-
const cookieValue =
|
|
40
|
+
export function getCookieCsrf(req) {
|
|
41
|
+
const cookieValue = getCookie(req, CSRF_COOKIE_NAME);
|
|
51
42
|
if (cookieValue?.length === TOKEN_LENGTH) {
|
|
52
43
|
return cookieValue;
|
|
53
44
|
}
|
|
54
45
|
return undefined;
|
|
55
46
|
}
|
|
56
|
-
function getHeadersCsrf(req) {
|
|
57
|
-
const headerValue = req.headers[
|
|
47
|
+
export function getHeadersCsrf(req) {
|
|
48
|
+
const headerValue = req.headers[CSRF_HEADER_NAME];
|
|
58
49
|
if (typeof headerValue === 'string' && headerValue.length === TOKEN_LENGTH) {
|
|
59
50
|
return headerValue;
|
|
60
51
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csrf.js","sourceRoot":"","sources":["../../../src/router/assets/csrf.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"csrf.js","sourceRoot":"","sources":["../../../src/router/assets/csrf.ts"],"names":[],"mappings":"AACA,OAAO,eAAe,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AAChF,OAAO,EAEL,SAAS,EACT,SAAS,GACV,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAEtD,MAAM,iBAAiB,GAAG,EAAE,CAAA;AAC5B,MAAM,YAAY,GAAG,iBAAiB,GAAG,CAAC,CAAA,CAAC,uBAAuB;AAElE,6EAA6E;AAC7E,0DAA0D;AAC1D,MAAM,mBAAmB,GAAqC;IAC5D,OAAO,EAAE,SAAS,EAAE,mBAAmB;IACvC,MAAM,EAAE,IAAI;IACZ,QAAQ,EAAE,KAAK,EAAE,wCAAwC;IACzD,QAAQ,EAAE,KAAK;IACf,IAAI,EAAE,GAAG;CACV,CAAA;AAED,KAAK,UAAU,iBAAiB;IAC9B,OAAO,WAAW,CAAC,iBAAiB,CAAC,CAAA;AACvC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAoB,EACpB,GAAmB;IAEnB,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,iBAAiB,EAAE,CAAC,CAAA;IAE/D,oDAAoD;IACpD,SAAS,CAAC,GAAG,EAAE,gBAAgB,EAAE,KAAK,EAAE,mBAAmB,CAAC,CAAA;AAC9D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,GAAoB,EACpB,GAAmB;IAEnB,MAAM,WAAW,GAAG,aAAa,CAAC,GAAG,CAAC,CAAA;IACtC,MAAM,WAAW,GAAG,cAAc,CAAC,GAAG,CAAC,CAAA;IAEvC,uEAAuE;IACvE,gDAAgD;IAChD,SAAS,CACP,GAAG,EACH,gBAAgB,EAChB,WAAW,IAAI,CAAC,MAAM,iBAAiB,EAAE,CAAC,EAC1C,mBAAmB,CACpB,CAAA;IAED,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,eAAe,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAA;IACnD,CAAC;IACD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,eAAe,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAA;IACnD,CAAC;IACD,IAAI,WAAW,KAAK,WAAW,EAAE,CAAC;QAChC,MAAM,eAAe,CAAC,GAAG,EAAE,eAAe,CAAC,CAAA;IAC7C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAoB;IAChD,MAAM,WAAW,GAAG,SAAS,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAA;IACpD,IAAI,WAAW,EAAE,MAAM,KAAK,YAAY,EAAE,CAAC;QACzC,OAAO,WAAW,CAAA;IACpB,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAoB;IACjD,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAA;IACjD,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,WAAW,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;QAC3E,OAAO,WAAW,CAAA;IACpB,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http'\nimport createHttpError from 'http-errors'\nimport { CSRF_COOKIE_NAME, CSRF_HEADER_NAME } from '@atproto/oauth-provider-api'\nimport {\n CookieSerializeOptions,\n getCookie,\n setCookie,\n} from '../../lib/http/index.js'\nimport { randomHexId } from '../../lib/util/crypto.js'\n\nconst TOKEN_BYTE_LENGTH = 12\nconst TOKEN_LENGTH = TOKEN_BYTE_LENGTH * 2 // 2 hex chars per byte\n\n// @NOTE Cookie based CSRF protection is redundant with session cookies using\n// `SameSite` and could probably be removed in the future.\nconst CSRF_COOKIE_OPTIONS: Readonly<CookieSerializeOptions> = {\n expires: undefined, // \"session\" cookie\n secure: true,\n httpOnly: false, // Need to be accessible from JavaScript\n sameSite: 'lax',\n path: `/`,\n}\n\nasync function generateCsrfToken() {\n return randomHexId(TOKEN_BYTE_LENGTH)\n}\n\nexport async function setupCsrfToken(\n req: IncomingMessage,\n res: ServerResponse,\n): Promise<void> {\n const token = getCookieCsrf(req) || (await generateCsrfToken())\n\n // Refresh cookie (See Chrome's \"Lax+POST\" behavior)\n setCookie(res, CSRF_COOKIE_NAME, token, CSRF_COOKIE_OPTIONS)\n}\n\nexport async function validateCsrfToken(\n req: IncomingMessage,\n res: ServerResponse,\n) {\n const cookieValue = getCookieCsrf(req)\n const headerValue = getHeadersCsrf(req)\n\n // Refresh cookie (See Chrome's \"Lax+POST\" behavior), or set a new one,\n // allowing clients to retry with the new token.\n setCookie(\n res,\n CSRF_COOKIE_NAME,\n cookieValue || (await generateCsrfToken()),\n CSRF_COOKIE_OPTIONS,\n )\n\n if (!headerValue) {\n throw createHttpError(400, `Missing CSRF header`)\n }\n if (!cookieValue) {\n throw createHttpError(400, `Missing CSRF cookie`)\n }\n if (cookieValue !== headerValue) {\n throw createHttpError(400, `CSRF mismatch`)\n }\n}\n\nexport function getCookieCsrf(req: IncomingMessage) {\n const cookieValue = getCookie(req, CSRF_COOKIE_NAME)\n if (cookieValue?.length === TOKEN_LENGTH) {\n return cookieValue\n }\n return undefined\n}\n\nexport function getHeadersCsrf(req: IncomingMessage) {\n const headerValue = req.headers[CSRF_HEADER_NAME]\n if (typeof headerValue === 'string' && headerValue.length === TOKEN_LENGTH) {\n return headerValue\n }\n return undefined\n}\n"]}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const assets_js_1 = require("./assets.js");
|
|
5
|
-
function sendAccountPageFactory(customization, options) {
|
|
6
|
-
const sendApp = (0, assets_js_1.sendWebAppFactory)('account-page', customization, options);
|
|
1
|
+
import { sendWebAppFactory } from './assets.js';
|
|
2
|
+
export function sendAccountPageFactory(customization, options) {
|
|
3
|
+
const sendApp = sendWebAppFactory('account-page', customization, options);
|
|
7
4
|
return async function sendAccountPage(req, res, data) {
|
|
8
5
|
return sendApp(req, res, {
|
|
9
6
|
data: { __deviceSessions: data.deviceSessions },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"send-account-page.js","sourceRoot":"","sources":["../../../src/router/assets/send-account-page.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"send-account-page.js","sourceRoot":"","sources":["../../../src/router/assets/send-account-page.ts"],"names":[],"mappings":"AAGA,OAAO,EAAqB,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAElE,MAAM,UAAU,sBAAsB,CACpC,aAA4B,EAC5B,OAA2B;IAE3B,MAAM,OAAO,GAAG,iBAAiB,CAAC,cAAc,EAAE,aAAa,EAAE,OAAO,CAAC,CAAA;IAEzE,OAAO,KAAK,UAAU,eAAe,CACnC,GAAoB,EACpB,GAAmB,EACnB,IAEC;QAED,OAAO,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE;YACvB,IAAI,EAAE,EAAE,gBAAgB,EAAE,IAAI,CAAC,cAAc,EAAE;SAChD,CAAC,CAAA;IACJ,CAAC,CAAA;AACH,CAAC","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http'\nimport type { ActiveDeviceSession } from '@atproto/oauth-provider-api'\nimport { Customization } from '../../customization/customization.js'\nimport { SendWebAppOptions, sendWebAppFactory } from './assets.js'\n\nexport function sendAccountPageFactory(\n customization: Customization,\n options?: SendWebAppOptions,\n) {\n const sendApp = sendWebAppFactory('account-page', customization, options)\n\n return async function sendAccountPage(\n req: IncomingMessage,\n res: ServerResponse,\n data: {\n deviceSessions: readonly ActiveDeviceSession[]\n },\n ): Promise<void> {\n return sendApp(req, res, {\n data: { __deviceSessions: data.deviceSessions },\n })\n }\n}\n"]}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const assets_js_1 = require("./assets.js");
|
|
5
|
-
function sendAuthorizePageFactory(customization, options) {
|
|
6
|
-
const sendApp = (0, assets_js_1.sendWebAppFactory)('authorization-page', customization, options);
|
|
1
|
+
import { sendWebAppFactory } from './assets.js';
|
|
2
|
+
export function sendAuthorizePageFactory(customization, options) {
|
|
3
|
+
const sendApp = sendWebAppFactory('authorization-page', customization, options);
|
|
7
4
|
return async function sendAuthorizePage(req, res, data) {
|
|
8
5
|
return sendApp(req, res, {
|
|
9
6
|
data: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"send-authorization-page.js","sourceRoot":"","sources":["../../../src/router/assets/send-authorization-page.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"send-authorization-page.js","sourceRoot":"","sources":["../../../src/router/assets/send-authorization-page.ts"],"names":[],"mappings":"AAGA,OAAO,EAAqB,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAElE,MAAM,UAAU,wBAAwB,CACtC,aAA4B,EAC5B,OAA2B;IAE3B,MAAM,OAAO,GAAG,iBAAiB,CAC/B,oBAAoB,EACpB,aAAa,EACb,OAAO,CACR,CAAA;IAED,OAAO,KAAK,UAAU,iBAAiB,CACrC,GAAoB,EACpB,GAAmB,EACnB,IAAsC;QAEtC,OAAO,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE;YACvB,IAAI,EAAE;gBACJ,eAAe,EAAE;oBACf,UAAU,EAAE,IAAI,CAAC,UAAU;oBAE3B,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE;oBACxB,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;oBACpC,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS;oBACzC,gBAAgB,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY;oBAE/C,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK;oBAC5B,SAAS,EAAE,IAAI,CAAC,UAAU,CAAC,UAAU;oBACrC,SAAS,EAAE,IAAI,CAAC,UAAU,CAAC,UAAU;oBACrC,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,MAAM;oBAClC,cAAc,EAAE,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,cAAc,CAAC;oBACvD,WAAW,EAAE,IAAI,CAAC,WAAW;iBAC9B;gBACD,UAAU,EAAE,IAAI,CAAC,QAAQ;aAC1B;SACF,CAAC,CAAA;IACJ,CAAC,CAAA;AACH,CAAC","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http'\nimport { Customization } from '../../customization/customization.js'\nimport { AuthorizationResultAuthorizePage } from '../../result/authorization-result-authorize-page.js'\nimport { SendWebAppOptions, sendWebAppFactory } from './assets.js'\n\nexport function sendAuthorizePageFactory(\n customization: Customization,\n options?: SendWebAppOptions,\n) {\n const sendApp = sendWebAppFactory(\n 'authorization-page',\n customization,\n options,\n )\n\n return async function sendAuthorizePage(\n req: IncomingMessage,\n res: ServerResponse,\n data: AuthorizationResultAuthorizePage,\n ): Promise<void> {\n return sendApp(req, res, {\n data: {\n __authorizeData: {\n requestUri: data.requestUri,\n\n clientId: data.client.id,\n clientMetadata: data.client.metadata,\n clientTrusted: data.client.info.isTrusted,\n clientFirstParty: data.client.info.isFirstParty,\n\n scope: data.parameters.scope,\n uiLocales: data.parameters.ui_locales,\n loginHint: data.parameters.login_hint,\n promptMode: data.parameters.prompt,\n permissionSets: Object.fromEntries(data.permissionSets),\n selectedSub: data.selectedSub,\n },\n __sessions: data.sessions,\n },\n })\n }\n}\n"]}
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const assets_js_1 = require("./assets.js");
|
|
5
|
-
function sendCookieErrorPageFactory(customization, options) {
|
|
6
|
-
const sendApp = (0, assets_js_1.sendWebAppFactory)('cookie-error-page', customization, options);
|
|
1
|
+
import { sendWebAppFactory } from './assets.js';
|
|
2
|
+
export function sendCookieErrorPageFactory(customization, options) {
|
|
3
|
+
const sendApp = sendWebAppFactory('cookie-error-page', customization, options);
|
|
7
4
|
return async function sendCookieErrorPage(req, res, data) {
|
|
8
5
|
return sendApp(req, res, {
|
|
9
6
|
status: 400,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"send-cookie-error-page.js","sourceRoot":"","sources":["../../../src/router/assets/send-cookie-error-page.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"send-cookie-error-page.js","sourceRoot":"","sources":["../../../src/router/assets/send-cookie-error-page.ts"],"names":[],"mappings":"AAEA,OAAO,EAAqB,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAElE,MAAM,UAAU,0BAA0B,CACxC,aAA4B,EAC5B,OAA2B;IAE3B,MAAM,OAAO,GAAG,iBAAiB,CAAC,mBAAmB,EAAE,aAAa,EAAE,OAAO,CAAC,CAAA;IAE9E,OAAO,KAAK,UAAU,mBAAmB,CACvC,GAAoB,EACpB,GAAmB,EACnB,IAA0B;QAE1B,OAAO,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE;YACvB,MAAM,EAAE,GAAG;YACX,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,EAAE;SACrD,CAAC,CAAA;IACJ,CAAC,CAAA;AACH,CAAC","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http'\nimport { Customization } from '../../customization/customization.js'\nimport { SendWebAppOptions, sendWebAppFactory } from './assets.js'\n\nexport function sendCookieErrorPageFactory(\n customization: Customization,\n options?: SendWebAppOptions,\n) {\n const sendApp = sendWebAppFactory('cookie-error-page', customization, options)\n\n return async function sendCookieErrorPage(\n req: IncomingMessage,\n res: ServerResponse,\n data: { continueUrl: URL },\n ) {\n return sendApp(req, res, {\n status: 400,\n data: { __continueUrl: data.continueUrl.toString() },\n })\n }\n}\n"]}
|
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
const assets_js_1 = require("./assets.js");
|
|
6
|
-
function sendErrorPageFactory(customization, options) {
|
|
7
|
-
const sendApp = (0, assets_js_1.sendWebAppFactory)('error-page', customization, options);
|
|
1
|
+
import { buildErrorPayload, buildErrorStatus, } from '../../errors/error-parser.js';
|
|
2
|
+
import { sendWebAppFactory } from './assets.js';
|
|
3
|
+
export function sendErrorPageFactory(customization, options) {
|
|
4
|
+
const sendApp = sendWebAppFactory('error-page', customization, options);
|
|
8
5
|
return async function sendErrorPage(req, res, err) {
|
|
9
6
|
return sendApp(req, res, {
|
|
10
|
-
status:
|
|
11
|
-
data: { __errorData:
|
|
7
|
+
status: buildErrorStatus(err),
|
|
8
|
+
data: { __errorData: buildErrorPayload(err) },
|
|
12
9
|
});
|
|
13
10
|
};
|
|
14
11
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"send-error-page.js","sourceRoot":"","sources":["../../../src/router/assets/send-error-page.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"send-error-page.js","sourceRoot":"","sources":["../../../src/router/assets/send-error-page.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,8BAA8B,CAAA;AACrC,OAAO,EAAqB,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAElE,MAAM,UAAU,oBAAoB,CAClC,aAA4B,EAC5B,OAA2B;IAE3B,MAAM,OAAO,GAAG,iBAAiB,CAAC,YAAY,EAAE,aAAa,EAAE,OAAO,CAAC,CAAA;IAEvE,OAAO,KAAK,UAAU,aAAa,CACjC,GAAoB,EACpB,GAAmB,EACnB,GAAY;QAEZ,OAAO,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE;YACvB,MAAM,EAAE,gBAAgB,CAAC,GAAG,CAAC;YAC7B,IAAI,EAAE,EAAE,WAAW,EAAE,iBAAiB,CAAC,GAAG,CAAC,EAAE;SAC9C,CAAC,CAAA;IACJ,CAAC,CAAA;AACH,CAAC","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http'\nimport { Customization } from '../../customization/customization.js'\nimport {\n buildErrorPayload,\n buildErrorStatus,\n} from '../../errors/error-parser.js'\nimport { SendWebAppOptions, sendWebAppFactory } from './assets.js'\n\nexport function sendErrorPageFactory(\n customization: Customization,\n options?: SendWebAppOptions,\n) {\n const sendApp = sendWebAppFactory('error-page', customization, options)\n\n return async function sendErrorPage(\n req: IncomingMessage,\n res: ServerResponse,\n err: unknown,\n ): Promise<void> {\n return sendApp(req, res, {\n status: buildErrorStatus(err),\n data: { __errorData: buildErrorPayload(err) },\n })\n }\n}\n"]}
|
|
@@ -1,45 +1,37 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.ERROR_REDIRECT_KEYS = exports.SUCCESS_REDIRECT_KEYS = void 0;
|
|
4
|
-
exports.buildRedirectUri = buildRedirectUri;
|
|
5
|
-
exports.buildRedirectMode = buildRedirectMode;
|
|
6
|
-
exports.buildRedirectParams = buildRedirectParams;
|
|
7
|
-
exports.sendAuthorizationResultRedirect = sendAuthorizationResultRedirect;
|
|
8
|
-
exports.sendRedirect = sendRedirect;
|
|
9
|
-
const authorization_error_js_1 = require("../../errors/authorization-error.js");
|
|
10
|
-
const write_form_redirect_js_1 = require("../../lib/write-form-redirect.js");
|
|
1
|
+
import { AuthorizationError } from '../../errors/authorization-error.js';
|
|
2
|
+
import { writeFormRedirect, } from '../../lib/write-form-redirect.js';
|
|
11
3
|
// https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-11#section-7.5.4
|
|
12
4
|
const REDIRECT_STATUS_CODE = 303;
|
|
13
|
-
|
|
5
|
+
export const SUCCESS_REDIRECT_KEYS = [
|
|
14
6
|
'code',
|
|
15
7
|
'id_token',
|
|
16
8
|
'access_token',
|
|
17
9
|
'expires_in',
|
|
18
10
|
'token_type',
|
|
19
11
|
];
|
|
20
|
-
|
|
12
|
+
export const ERROR_REDIRECT_KEYS = [
|
|
21
13
|
'error',
|
|
22
14
|
'error_description',
|
|
23
15
|
'error_uri',
|
|
24
16
|
];
|
|
25
|
-
function buildRedirectUri(parameters) {
|
|
17
|
+
export function buildRedirectUri(parameters) {
|
|
26
18
|
const uri = parameters.redirect_uri;
|
|
27
19
|
if (uri)
|
|
28
20
|
return uri;
|
|
29
|
-
throw new
|
|
21
|
+
throw new AuthorizationError(parameters, 'No redirect_uri', 'invalid_request');
|
|
30
22
|
}
|
|
31
|
-
function buildRedirectMode(parameters) {
|
|
23
|
+
export function buildRedirectMode(parameters) {
|
|
32
24
|
const mode = parameters.response_mode || 'query'; // @TODO default should depend on response_type
|
|
33
25
|
return mode;
|
|
34
26
|
}
|
|
35
|
-
function buildRedirectParams(issuer, parameters, redirect) {
|
|
27
|
+
export function buildRedirectParams(issuer, parameters, redirect) {
|
|
36
28
|
const params = [
|
|
37
29
|
['iss', issuer], // rfc9207
|
|
38
30
|
];
|
|
39
31
|
if (parameters.state != null) {
|
|
40
32
|
params.push(['state', parameters.state]);
|
|
41
33
|
}
|
|
42
|
-
const keys = 'code' in redirect ?
|
|
34
|
+
const keys = 'code' in redirect ? SUCCESS_REDIRECT_KEYS : ERROR_REDIRECT_KEYS;
|
|
43
35
|
for (const key of keys) {
|
|
44
36
|
const value = redirect[key];
|
|
45
37
|
if (value != null)
|
|
@@ -47,7 +39,7 @@ function buildRedirectParams(issuer, parameters, redirect) {
|
|
|
47
39
|
}
|
|
48
40
|
return params;
|
|
49
41
|
}
|
|
50
|
-
function sendAuthorizationResultRedirect(res, result, options) {
|
|
42
|
+
export function sendAuthorizationResultRedirect(res, result, options) {
|
|
51
43
|
const { issuer, parameters, redirect } = result;
|
|
52
44
|
return sendRedirect(res, {
|
|
53
45
|
redirectUri: buildRedirectUri(parameters),
|
|
@@ -55,7 +47,7 @@ function sendAuthorizationResultRedirect(res, result, options) {
|
|
|
55
47
|
params: buildRedirectParams(issuer, parameters, redirect),
|
|
56
48
|
}, options);
|
|
57
49
|
}
|
|
58
|
-
function sendRedirect(res, redirect, options) {
|
|
50
|
+
export function sendRedirect(res, redirect, options) {
|
|
59
51
|
res.setHeader('Cache-Control', 'no-store');
|
|
60
52
|
const { mode, redirectUri: uri, params } = redirect;
|
|
61
53
|
switch (mode) {
|
|
@@ -64,7 +56,7 @@ function sendRedirect(res, redirect, options) {
|
|
|
64
56
|
case 'fragment':
|
|
65
57
|
return writeFragment(res, uri, params);
|
|
66
58
|
case 'form_post':
|
|
67
|
-
return
|
|
59
|
+
return writeFormRedirect(res, 'post', uri, params, options);
|
|
68
60
|
}
|
|
69
61
|
// @ts-expect-error fool proof
|
|
70
62
|
throw new Error(`Unsupported mode: ${mode}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"send-redirect.js","sourceRoot":"","sources":["../../../src/router/assets/send-redirect.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"send-redirect.js","sourceRoot":"","sources":["../../../src/router/assets/send-redirect.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ServerResponse } from 'node:http'\nimport {\n OAuthAuthorizationRequestParameters,\n OAuthResponseMode,\n} from '@atproto/oauth-types'\nimport { AuthorizationError } from '../../errors/authorization-error.js'\nimport {\n WriteFormRedirectOptions,\n writeFormRedirect,\n} from '../../lib/write-form-redirect.js'\nimport { AuthorizationRedirectParameters } from '../../result/authorization-redirect-parameters.js'\nimport { AuthorizationResultRedirect } from '../../result/authorization-result-redirect.js'\n\n// https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-11#section-7.5.4\nconst REDIRECT_STATUS_CODE = 303\n\nexport const SUCCESS_REDIRECT_KEYS = [\n 'code',\n 'id_token',\n 'access_token',\n 'expires_in',\n 'token_type',\n] as const\n\nexport const ERROR_REDIRECT_KEYS = [\n 'error',\n 'error_description',\n 'error_uri',\n] as const\n\nexport type OAuthRedirectQueryParameter =\n | 'iss'\n | 'state'\n | (typeof SUCCESS_REDIRECT_KEYS)[number]\n | (typeof ERROR_REDIRECT_KEYS)[number]\n\nexport function buildRedirectUri(\n parameters: OAuthAuthorizationRequestParameters,\n): string {\n const uri = parameters.redirect_uri\n if (uri) return uri\n\n throw new AuthorizationError(parameters, 'No redirect_uri', 'invalid_request')\n}\n\nexport function buildRedirectMode(\n parameters: OAuthAuthorizationRequestParameters,\n): OAuthResponseMode {\n const mode = parameters.response_mode || 'query' // @TODO default should depend on response_type\n return mode\n}\n\nexport function buildRedirectParams(\n issuer: string,\n parameters: OAuthAuthorizationRequestParameters,\n redirect: AuthorizationRedirectParameters,\n): [OAuthRedirectQueryParameter, string][] {\n const params: [OAuthRedirectQueryParameter, string][] = [\n ['iss', issuer], // rfc9207\n ]\n\n if (parameters.state != null) {\n params.push(['state', parameters.state])\n }\n\n const keys = 'code' in redirect ? SUCCESS_REDIRECT_KEYS : ERROR_REDIRECT_KEYS\n for (const key of keys) {\n const value = redirect[key]\n if (value != null) params.push([key, value])\n }\n\n return params\n}\n\nexport function sendAuthorizationResultRedirect(\n res: ServerResponse,\n result: AuthorizationResultRedirect,\n options?: WriteFormRedirectOptions,\n) {\n const { issuer, parameters, redirect } = result\n\n return sendRedirect(\n res,\n {\n redirectUri: buildRedirectUri(parameters),\n mode: buildRedirectMode(parameters),\n params: buildRedirectParams(issuer, parameters, redirect),\n },\n options,\n )\n}\n\nexport type OAuthRedirectOptions = {\n mode: OAuthResponseMode\n redirectUri: string\n params: Iterable<[string, string]>\n}\n\nexport function sendRedirect(\n res: ServerResponse,\n redirect: OAuthRedirectOptions,\n options?: WriteFormRedirectOptions,\n): void {\n res.setHeader('Cache-Control', 'no-store')\n\n const { mode, redirectUri: uri, params } = redirect\n switch (mode) {\n case 'query':\n return writeQuery(res, uri, params)\n case 'fragment':\n return writeFragment(res, uri, params)\n case 'form_post':\n return writeFormRedirect(res, 'post', uri, params, options)\n }\n\n // @ts-expect-error fool proof\n throw new Error(`Unsupported mode: ${mode}`)\n}\n\nfunction writeQuery(\n res: ServerResponse,\n uri: string,\n params: Iterable<[string, string]>,\n): void {\n const url = new URL(uri)\n for (const [key, value] of params) url.searchParams.set(key, value)\n res.writeHead(REDIRECT_STATUS_CODE, { Location: url.href }).end()\n}\n\nfunction writeFragment(\n res: ServerResponse,\n uri: string,\n params: Iterable<[string, string]>,\n): void {\n const url = new URL(uri)\n const searchParams = new URLSearchParams()\n for (const [key, value] of params) searchParams.set(key, value)\n url.hash = searchParams.toString()\n res.writeHead(REDIRECT_STATUS_CODE, { Location: url.href }).end()\n}\n"]}
|
|
@@ -1,22 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const send_account_page_js_1 = require("./assets/send-account-page.js");
|
|
6
|
-
const send_error_page_js_1 = require("./assets/send-error-page.js");
|
|
7
|
-
function createAccountPageMiddleware(server, { onError }) {
|
|
1
|
+
import { Router, validateFetchDest, validateFetchMode, validateOrigin, writeRedirect, } from '../lib/http/index.js';
|
|
2
|
+
import { sendAccountPageFactory } from './assets/send-account-page.js';
|
|
3
|
+
import { sendErrorPageFactory } from './assets/send-error-page.js';
|
|
4
|
+
export function createAccountPageMiddleware(server, { onError }) {
|
|
8
5
|
const issuerUrl = new URL(server.issuer);
|
|
9
6
|
const issuerOrigin = issuerUrl.origin;
|
|
10
7
|
const securityOptions = {
|
|
11
8
|
hsts: issuerUrl.protocol === 'http:' ? false : undefined,
|
|
12
9
|
};
|
|
13
|
-
const sendAccountPage =
|
|
14
|
-
const sendErrorPage =
|
|
15
|
-
const router = new
|
|
10
|
+
const sendAccountPage = sendAccountPageFactory(server.customization, securityOptions);
|
|
11
|
+
const sendErrorPage = sendErrorPageFactory(server.customization, securityOptions);
|
|
12
|
+
const router = new Router(issuerUrl);
|
|
16
13
|
// Create password reset discovery endpoint
|
|
17
14
|
// https://www.w3.org/TR/change-password-url/
|
|
18
15
|
router.get('/.well-known/change-password', (_req, res) => {
|
|
19
|
-
|
|
16
|
+
writeRedirect(res, new URL('/account/reset-password', issuerUrl).toString());
|
|
20
17
|
});
|
|
21
18
|
// Create frontend account pages
|
|
22
19
|
router.get(/^\/account(?:\/.*)?$/, async function (req, res) {
|
|
@@ -24,9 +21,9 @@ function createAccountPageMiddleware(server, { onError }) {
|
|
|
24
21
|
res.setHeader('Referrer-Policy', 'same-origin');
|
|
25
22
|
res.setHeader('Cache-Control', 'no-store');
|
|
26
23
|
res.setHeader('Pragma', 'no-cache');
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
validateFetchMode(req, ['navigate']);
|
|
25
|
+
validateFetchDest(req, ['document']);
|
|
26
|
+
validateOrigin(req, issuerOrigin);
|
|
30
27
|
const { deviceId } = await server.deviceManager.load(req, res);
|
|
31
28
|
const deviceAccounts = await server.accountManager.listDeviceAccounts(deviceId);
|
|
32
29
|
sendAccountPage(req, res, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-account-page-middleware.js","sourceRoot":"","sources":["../../src/router/create-account-page-middleware.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"create-account-page-middleware.js","sourceRoot":"","sources":["../../src/router/create-account-page-middleware.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,MAAM,EACN,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,aAAa,GACd,MAAM,sBAAsB,CAAA;AAG7B,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAA;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAGlE,MAAM,UAAU,2BAA2B,CAKzC,MAAqB,EACrB,EAAE,OAAO,EAA+B;IAExC,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IACxC,MAAM,YAAY,GAAG,SAAS,CAAC,MAAM,CAAA;IAErC,MAAM,eAAe,GAA2B;QAC9C,IAAI,EAAE,SAAS,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;KACzD,CAAA;IAED,MAAM,eAAe,GAAG,sBAAsB,CAC5C,MAAM,CAAC,aAAa,EACpB,eAAe,CAChB,CAAA;IACD,MAAM,aAAa,GAAG,oBAAoB,CACxC,MAAM,CAAC,aAAa,EACpB,eAAe,CAChB,CAAA;IAED,MAAM,MAAM,GAAG,IAAI,MAAM,CAAgB,SAAS,CAAC,CAAA;IAEnD,2CAA2C;IAC3C,6CAA6C;IAC7C,MAAM,CAAC,GAAG,CAAC,8BAA8B,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;QACvD,aAAa,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC,yBAAyB,EAAE,SAAS,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAA;IAC9E,CAAC,CAAC,CAAA;IAEF,gCAAgC;IAChC,MAAM,CAAC,GAAG,CAAQ,sBAAsB,EAAE,KAAK,WAAW,GAAG,EAAE,GAAG;QAChE,IAAI,CAAC;YACH,GAAG,CAAC,SAAS,CAAC,iBAAiB,EAAE,aAAa,CAAC,CAAA;YAE/C,GAAG,CAAC,SAAS,CAAC,eAAe,EAAE,UAAU,CAAC,CAAA;YAC1C,GAAG,CAAC,SAAS,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;YAEnC,iBAAiB,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,CAAC,CAAA;YACpC,iBAAiB,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,CAAC,CAAA;YACpC,cAAc,CAAC,GAAG,EAAE,YAAY,CAAC,CAAA;YAEjC,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;YAC9D,MAAM,cAAc,GAClB,MAAM,MAAM,CAAC,cAAc,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAA;YAE1D,eAAe,CAAC,GAAG,EAAE,GAAG,EAAE;gBACxB,cAAc,EAAE,cAAc,CAAC,GAAG,CAChC,CAAC,aAAa,EAAuB,EAAE,CAAC,CAAC;oBACvC,OAAO,EAAE,aAAa,CAAC,OAAO;oBAC9B,aAAa,EAAE,MAAM,CAAC,kBAAkB,CAAC,aAAa,CAAC;iBACxD,CAAC,CACH;aACF,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,EAAE,CACP,GAAG,EACH,GAAG,EACH,GAAG,EACH,2CAA2C,GAAG,CAAC,GAAG,GAAG,CACtD,CAAA;YAED,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;gBACrB,OAAO,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;YACrC,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,OAAO,MAAM,CAAC,eAAe,EAAE,CAAA;AACjC,CAAC","sourcesContent":["import type { IncomingMessage, ServerResponse } from 'node:http'\nimport type { ActiveDeviceSession } from '@atproto/oauth-provider-api'\nimport {\n Middleware,\n Router,\n validateFetchDest,\n validateFetchMode,\n validateOrigin,\n writeRedirect,\n} from '../lib/http/index.js'\nimport { SecurityHeadersOptions } from '../lib/http/security-headers.js'\nimport type { OAuthProvider } from '../oauth-provider.js'\nimport { sendAccountPageFactory } from './assets/send-account-page.js'\nimport { sendErrorPageFactory } from './assets/send-error-page.js'\nimport type { MiddlewareOptions } from './middleware-options.js'\n\nexport function createAccountPageMiddleware<\n Ctx extends object | void = void,\n Req extends IncomingMessage = IncomingMessage,\n Res extends ServerResponse = ServerResponse,\n>(\n server: OAuthProvider,\n { onError }: MiddlewareOptions<Req, Res>,\n): Middleware<Ctx, Req, Res> {\n const issuerUrl = new URL(server.issuer)\n const issuerOrigin = issuerUrl.origin\n\n const securityOptions: SecurityHeadersOptions = {\n hsts: issuerUrl.protocol === 'http:' ? false : undefined,\n }\n\n const sendAccountPage = sendAccountPageFactory(\n server.customization,\n securityOptions,\n )\n const sendErrorPage = sendErrorPageFactory(\n server.customization,\n securityOptions,\n )\n\n const router = new Router<Ctx, Req, Res>(issuerUrl)\n\n // Create password reset discovery endpoint\n // https://www.w3.org/TR/change-password-url/\n router.get('/.well-known/change-password', (_req, res) => {\n writeRedirect(res, new URL('/account/reset-password', issuerUrl).toString())\n })\n\n // Create frontend account pages\n router.get<never>(/^\\/account(?:\\/.*)?$/, async function (req, res) {\n try {\n res.setHeader('Referrer-Policy', 'same-origin')\n\n res.setHeader('Cache-Control', 'no-store')\n res.setHeader('Pragma', 'no-cache')\n\n validateFetchMode(req, ['navigate'])\n validateFetchDest(req, ['document'])\n validateOrigin(req, issuerOrigin)\n\n const { deviceId } = await server.deviceManager.load(req, res)\n const deviceAccounts =\n await server.accountManager.listDeviceAccounts(deviceId)\n\n sendAccountPage(req, res, {\n deviceSessions: deviceAccounts.map(\n (deviceAccount): ActiveDeviceSession => ({\n account: deviceAccount.account,\n loginRequired: server.checkLoginRequired(deviceAccount),\n }),\n ),\n })\n } catch (err) {\n onError?.(\n req,\n res,\n err,\n `Failed to handle navigation request to \"${req.url}\"`,\n )\n\n if (!res.headersSent) {\n return sendErrorPage(req, res, err)\n }\n }\n })\n\n return router.buildMiddleware()\n}\n"]}
|