@betterportal/auth-default 10.6.21 → 10.6.23
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/README.md +140 -10
- package/bsb-plugin.json +1 -1
- package/lib/account.d.ts +16 -0
- package/lib/account.d.ts.map +1 -0
- package/lib/account.js +274 -0
- package/lib/account.js.map +1 -0
- package/lib/accountUI.d.ts +5 -0
- package/lib/accountUI.d.ts.map +1 -0
- package/lib/accountUI.js +68 -0
- package/lib/accountUI.js.map +1 -0
- package/lib/bp-contracts/org.betterportal.auth.default.json +2031 -707
- package/lib/clientAddress.d.ts +10 -0
- package/lib/clientAddress.d.ts.map +1 -0
- package/lib/clientAddress.js +35 -0
- package/lib/clientAddress.js.map +1 -0
- package/lib/config.d.ts +3 -0
- package/lib/config.d.ts.map +1 -0
- package/lib/config.js +28 -0
- package/lib/config.js.map +1 -0
- package/lib/defaultAuthManifest.d.ts +7 -0
- package/lib/defaultAuthManifest.d.ts.map +1 -1
- package/lib/factors.d.ts +18 -0
- package/lib/factors.d.ts.map +1 -0
- package/lib/factors.js +95 -0
- package/lib/factors.js.map +1 -0
- package/lib/identity.d.ts +106 -0
- package/lib/identity.d.ts.map +1 -0
- package/lib/identity.js +315 -0
- package/lib/identity.js.map +1 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +4 -0
- package/lib/index.js.map +1 -1
- package/lib/mail.d.ts +19 -0
- package/lib/mail.d.ts.map +1 -0
- package/lib/mail.js +102 -0
- package/lib/mail.js.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/.bp-generated/registry.d.ts +435 -11
- package/lib/plugins/service-betterportal-auth-default/.bp-generated/registry.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-auth-default/.bp-generated/registry.js +85 -0
- package/lib/plugins/service-betterportal-auth-default/.bp-generated/registry.js.map +1 -1
- package/lib/plugins/service-betterportal-auth-default/bp-routes/account/GET.d.ts +34 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/account/GET.d.ts.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/account/GET.js +25 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/account/GET.js.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/account/POST.d.ts +42 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/account/POST.d.ts.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/account/POST.js +27 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/account/POST.js.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/account/_renderer.bootstrap5/GET.d.ts +2 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/account/_renderer.bootstrap5/GET.d.ts.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/account/_renderer.bootstrap5/GET.js +2 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/account/_renderer.bootstrap5/GET.js.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/account/_renderer.bootstrap5/POST.d.ts +2 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/account/_renderer.bootstrap5/POST.d.ts.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/account/_renderer.bootstrap5/POST.js +2 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/account/_renderer.bootstrap5/POST.js.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/account/index.d.ts +3 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/account/index.d.ts.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/account/index.js +3 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/account/index.js.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/login/_renderer.bootstrap5/GET.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-auth-default/bp-routes/login/_renderer.bootstrap5/GET.js +11 -8
- package/lib/plugins/service-betterportal-auth-default/bp-routes/login/_renderer.bootstrap5/GET.js.map +1 -1
- package/lib/plugins/service-betterportal-auth-default/bp-routes/refresh/POST.d.ts +3 -1
- package/lib/plugins/service-betterportal-auth-default/bp-routes/refresh/POST.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-auth-default/bp-routes/refresh/POST.js +10 -23
- package/lib/plugins/service-betterportal-auth-default/bp-routes/refresh/POST.js.map +1 -1
- package/lib/plugins/service-betterportal-auth-default/bp-routes/register/_renderer.bootstrap5/GET.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-auth-default/bp-routes/register/_renderer.bootstrap5/GET.js +2 -2
- package/lib/plugins/service-betterportal-auth-default/bp-routes/register/_renderer.bootstrap5/GET.js.map +1 -1
- package/lib/plugins/service-betterportal-auth-default/bp-routes/social/GET.d.ts +34 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/social/GET.d.ts.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/social/GET.js +26 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/social/GET.js.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/social/POST.d.ts +31 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/social/POST.d.ts.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/social/POST.js +23 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/social/POST.js.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/social/_renderer.bootstrap5/GET.d.ts +3 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/social/_renderer.bootstrap5/GET.d.ts.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/social/_renderer.bootstrap5/GET.js +36 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/social/_renderer.bootstrap5/GET.js.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/social/index.d.ts +3 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/social/index.d.ts.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/social/index.js +3 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/social/index.js.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/users/GET.d.ts +32 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/users/GET.d.ts.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/users/GET.js +39 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/users/GET.js.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/users/POST.d.ts +41 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/users/POST.d.ts.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/users/POST.js +103 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/users/POST.js.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/users/_renderer.bootstrap5/GET.d.ts +3 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/users/_renderer.bootstrap5/GET.d.ts.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/users/_renderer.bootstrap5/GET.js +19 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/users/_renderer.bootstrap5/GET.js.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/users/index.d.ts +3 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/users/index.d.ts.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/users/index.js +3 -0
- package/lib/plugins/service-betterportal-auth-default/bp-routes/users/index.js.map +1 -0
- package/lib/plugins/service-betterportal-auth-default/index.d.ts +41 -4
- package/lib/plugins/service-betterportal-auth-default/index.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-auth-default/index.js +205 -9
- package/lib/plugins/service-betterportal-auth-default/index.js.map +1 -1
- package/lib/plugins/service-betterportal-auth-default/loginFlow.d.ts +17 -2
- package/lib/plugins/service-betterportal-auth-default/loginFlow.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-auth-default/loginFlow.js +83 -62
- package/lib/plugins/service-betterportal-auth-default/loginFlow.js.map +1 -1
- package/lib/plugins/service-betterportal-auth-default/logoutFlow.js +1 -1
- package/lib/plugins/service-betterportal-auth-default/logoutFlow.js.map +1 -1
- package/lib/plugins/service-betterportal-auth-default/registrationFlow.d.ts +4 -2
- package/lib/plugins/service-betterportal-auth-default/registrationFlow.d.ts.map +1 -1
- package/lib/plugins/service-betterportal-auth-default/registrationFlow.js +15 -17
- package/lib/plugins/service-betterportal-auth-default/registrationFlow.js.map +1 -1
- package/lib/schemas/service-betterportal-auth-default.json +26 -2
- package/lib/schemas/service-betterportal-auth-default.plugin.json +27 -3
- package/lib/social.d.ts +40 -0
- package/lib/social.d.ts.map +1 -0
- package/lib/social.js +178 -0
- package/lib/social.js.map +1 -0
- package/lib/storage.d.ts +72 -0
- package/lib/storage.d.ts.map +1 -0
- package/lib/storage.js +427 -0
- package/lib/storage.js.map +1 -0
- package/package.json +13 -6
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type BetterPortalEvent } from "@betterportal/framework/lib/runtime/h3.js";
|
|
2
|
+
interface ProxyTrust {
|
|
3
|
+
trustedProxyHeaders?: boolean;
|
|
4
|
+
cfProxy?: boolean;
|
|
5
|
+
trustedProxyIps?: string[];
|
|
6
|
+
}
|
|
7
|
+
/** Forwarding headers are authoritative only through explicitly trusted socket peers. */
|
|
8
|
+
export declare function clientAddress(event: BetterPortalEvent, trust: ProxyTrust): string | undefined;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=clientAddress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clientAddress.d.ts","sourceRoot":"","sources":["../src/clientAddress.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,KAAK,iBAAiB,EAAE,MAAM,2CAA2C,CAAC;AAEnG,UAAU,UAAU;IAAG,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE;AAOrG,yFAAyF;AACzF,wBAAgB,aAAa,CAAC,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE,UAAU,GAAG,MAAM,GAAG,SAAS,CAiB7F"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { isIP } from "node:net";
|
|
2
|
+
import { getEventPeerIp } from "@betterportal/framework/lib/runtime/h3.js";
|
|
3
|
+
function normalizeIp(value) {
|
|
4
|
+
if (!value || !isIP(value) || value.includes("%"))
|
|
5
|
+
return undefined;
|
|
6
|
+
if (isIP(value) === 4)
|
|
7
|
+
return value;
|
|
8
|
+
return new URL(`http://[${value}]`).hostname.slice(1, -1);
|
|
9
|
+
}
|
|
10
|
+
/** Forwarding headers are authoritative only through explicitly trusted socket peers. */
|
|
11
|
+
export function clientAddress(event, trust) {
|
|
12
|
+
const peer = normalizeIp(getEventPeerIp(event));
|
|
13
|
+
const trusted = new Set((trust.trustedProxyIps ?? []).map(normalizeIp).filter(Boolean));
|
|
14
|
+
if (!peer || !trusted.has(peer))
|
|
15
|
+
return peer;
|
|
16
|
+
if (trust.cfProxy) {
|
|
17
|
+
const cloudflare = normalizeIp(event.req.headers.get("cf-connecting-ip")?.trim());
|
|
18
|
+
if (cloudflare)
|
|
19
|
+
return cloudflare;
|
|
20
|
+
}
|
|
21
|
+
if (!trust.trustedProxyHeaders)
|
|
22
|
+
return peer;
|
|
23
|
+
const forwarded = event.req.headers.get("x-forwarded-for");
|
|
24
|
+
if (!forwarded || forwarded.length > 4096)
|
|
25
|
+
return peer;
|
|
26
|
+
const hops = forwarded.split(",").map(value => normalizeIp(value.trim()));
|
|
27
|
+
if (hops.length > 32 || hops.some(hop => !hop))
|
|
28
|
+
return peer;
|
|
29
|
+
// Stop at the nearest untrusted hop: addresses to its left can be supplied by that client.
|
|
30
|
+
let address = peer;
|
|
31
|
+
for (let i = hops.length - 1; i >= 0 && trusted.has(address); i--)
|
|
32
|
+
address = hops[i];
|
|
33
|
+
return address;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=clientAddress.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clientAddress.js","sourceRoot":"","sources":["../src/clientAddress.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,cAAc,EAA0B,MAAM,2CAA2C,CAAC;AAGnG,SAAS,WAAW,CAAC,KAAyB;IAC5C,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IACpE,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACpC,OAAO,IAAI,GAAG,CAAC,WAAW,KAAK,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5D,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,aAAa,CAAC,KAAwB,EAAE,KAAiB;IACvE,MAAM,IAAI,GAAG,WAAW,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IACxF,IAAI,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7C,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,UAAU,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QAClF,IAAI,UAAU;YAAE,OAAO,UAAU,CAAC;IACpC,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,mBAAmB;QAAE,OAAO,IAAI,CAAC;IAC5C,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAC3D,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,MAAM,GAAG,IAAI;QAAE,OAAO,IAAI,CAAC;IACvD,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC1E,IAAI,IAAI,CAAC,MAAM,GAAG,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5D,2FAA2F;IAC3F,IAAI,OAAO,GAAG,IAAI,CAAC;IACnB,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE;QAAE,OAAO,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;IACtF,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/lib/config.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAEtE,eAAO,MAAM,iBAAiB,EAAE,sBAAsB,EA0BrD,CAAC"}
|
package/lib/config.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export const AuthConfigSchemas = [
|
|
2
|
+
{
|
|
3
|
+
id: "default-auth.tenant", title: "Account isolation", scope: "tenant",
|
|
4
|
+
description: "Account directory boundaries. Locked permanently when the first user is created.",
|
|
5
|
+
jsonSchema: { userIsolation: "string", directoryAdminAppId: "string" },
|
|
6
|
+
fields: [
|
|
7
|
+
{ key: "userIsolation", title: "User isolation", description: "Account directory boundary; cannot change after user creation.", scope: "tenant", visibility: "protected", ownership: "bp", sourceOfTruth: "bp", required: false, defaultValue: "app", ui: { control: "select", options: [{ value: "app", label: "Separate accounts per app" }, { value: "tenant", label: "Shared accounts in this tenant" }] } },
|
|
8
|
+
{ key: "directoryAdminAppId", title: "Directory administration app", description: "For shared tenant accounts, the app whose authorized administrators may disable accounts, revoke all sessions and change shared groups. Must be an app in this tenant.", scope: "tenant", visibility: "protected", ownership: "bp", sourceOfTruth: "bp", required: false }
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
id: "default-auth.app", title: "Default authentication", scope: "app",
|
|
13
|
+
description: "Registration, first-login roles, MFA, email delivery and social connections for this app.",
|
|
14
|
+
jsonSchema: { registration: "string", defaultRoleIds: "string", requireMfa: "boolean", mailTransport: "string", mailUrl: "string", mailFrom: "string", mailApiKey: "string", mailHeaders: "string", socialConnections: "string" },
|
|
15
|
+
fields: [
|
|
16
|
+
{ key: "registration", title: "Registration", defaultValue: "invite-only", ui: { control: "select", options: [{ value: "invite-only", label: "Invitations only" }, { value: "public", label: "Public registration" }, { value: "closed", label: "Closed" }] } },
|
|
17
|
+
{ key: "defaultRoleIds", title: "Default role IDs", description: "JSON array of existing app role IDs. Applied once at first completed login. Empty by default.", defaultValue: "[]" },
|
|
18
|
+
{ key: "requireMfa", title: "Require multi-factor authentication", defaultValue: false },
|
|
19
|
+
{ key: "mailTransport", title: "Email delivery", ui: { control: "select", options: [{ value: "postal", label: "Postal HTTP API" }, { value: "http", label: "Custom HTTP API" }] } },
|
|
20
|
+
{ key: "mailUrl", title: "Email API URL" },
|
|
21
|
+
{ key: "mailFrom", title: "Sender email" },
|
|
22
|
+
{ key: "mailApiKey", title: "Postal API key", visibility: "secret" },
|
|
23
|
+
{ key: "mailHeaders", title: "Custom HTTP headers", description: "JSON object of server-side headers.", visibility: "secret" },
|
|
24
|
+
{ key: "socialConnections", title: "Social connections", description: "JSON array of Google, Microsoft or GitHub connections. Each app requires its own registered redirect URL.", visibility: "secret" }
|
|
25
|
+
].map(field => ({ description: field.title, scope: "app", visibility: "protected", ownership: "bp", sourceOfTruth: "bp", required: false, ...field }))
|
|
26
|
+
}
|
|
27
|
+
];
|
|
28
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -27,6 +27,13 @@ export declare const RuntimeJwtClaimsContract: av.ObjectSchema<{
|
|
|
27
27
|
tokenType: av.EnumSchema<readonly ["access", "refresh", "cp-envelope", "setup", "install"]>;
|
|
28
28
|
authProvider: av.OptionalSchema<av.StringSchema>;
|
|
29
29
|
refreshContext: av.OptionalSchema<av.BaseSchema<unknown, import("@betterportal/framework").JsonObject>>;
|
|
30
|
+
elevation: av.OptionalSchema<av.ObjectSchema<{
|
|
31
|
+
assurance: av.EnumSchema<readonly ["confirmed", "mfa"]>;
|
|
32
|
+
verifiedAt: av.IntSchema;
|
|
33
|
+
expiresAt: av.IntSchema;
|
|
34
|
+
}>>;
|
|
35
|
+
sessionId: av.OptionalSchema<av.StringSchema>;
|
|
36
|
+
sessionVersion: av.OptionalSchema<av.IntSchema>;
|
|
30
37
|
providerSubject: av.OptionalSchema<av.StringSchema>;
|
|
31
38
|
provider: av.OptionalSchema<av.ObjectSchema<{
|
|
32
39
|
username: av.OptionalSchema<av.StringSchema>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaultAuthManifest.d.ts","sourceRoot":"","sources":["../src/defaultAuthManifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAGhB,cAAc,EACd,wBAAwB,EACzB,MAAM,yBAAyB,CAAC;AAEjC,eAAO,MAAM,wBAAwB;;;;;EAKnC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAExE,eAAO,MAAM,2BAA2B,EAAE,SAAS,gBAAgB,EASlE,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,SAAS,wBAAwB,EAarE,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,SAAS,kBAAkB,EAS7D,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,cAsBhC,CAAC;AAEH,eAAO,MAAM,wBAAwB
|
|
1
|
+
{"version":3,"file":"defaultAuthManifest.d.ts","sourceRoot":"","sources":["../src/defaultAuthManifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAGhB,cAAc,EACd,wBAAwB,EACzB,MAAM,yBAAyB,CAAC;AAEjC,eAAO,MAAM,wBAAwB;;;;;EAKnC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAExE,eAAO,MAAM,2BAA2B,EAAE,SAAS,gBAAgB,EASlE,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,SAAS,wBAAwB,EAarE,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,SAAS,kBAAkB,EAS7D,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,cAsBhC,CAAC;AAEH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAkB,CAAC"}
|
package/lib/factors.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type IdentityService, type User } from "./identity.js";
|
|
2
|
+
import type { AuthTransaction, Scope } from "./storage.js";
|
|
3
|
+
export interface FactorRequest {
|
|
4
|
+
method?: string;
|
|
5
|
+
code?: string;
|
|
6
|
+
credential?: unknown;
|
|
7
|
+
}
|
|
8
|
+
export declare class Factors {
|
|
9
|
+
private readonly identity;
|
|
10
|
+
constructor(identity: IdentityService);
|
|
11
|
+
hasFactors(user: User): Promise<boolean>;
|
|
12
|
+
prepare(user: User, origin: string, enroll?: boolean): Promise<{
|
|
13
|
+
public: Record<string, unknown>;
|
|
14
|
+
private: Record<string, unknown>;
|
|
15
|
+
}>;
|
|
16
|
+
complete(tx: AuthTransaction, scope: Scope, user: User, data: Record<string, unknown>, input: FactorRequest): Promise<string[] | undefined>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=factors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factors.d.ts","sourceRoot":"","sources":["../src/factors.ts"],"names":[],"mappings":"AAEA,OAAO,EAAoC,KAAK,eAAe,EAAE,KAAK,IAAI,EAAE,MAAM,eAAe,CAAC;AAClG,OAAO,KAAK,EAAE,eAAe,EAAe,KAAK,EAAE,MAAM,cAAc,CAAC;AAGxE,MAAM,WAAW,aAAa;IAAG,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE;AACvF,qBAAa,OAAO;IACN,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,eAAe;IAEhD,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC;IAIxC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,UAAQ,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC;IAgBnI,QAAQ,CAAC,EAAE,EAAE,eAAe,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,SAAS,CAAC;CA0ClJ"}
|
package/lib/factors.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { generateSecret, generateURI, verify } from "otplib";
|
|
2
|
+
import { generateAuthenticationOptions, generateRegistrationOptions, verifyAuthenticationResponse, verifyRegistrationResponse } from "@simplewebauthn/server";
|
|
3
|
+
import { AuthError, newSecret, secretHash } from "./identity.js";
|
|
4
|
+
export class Factors {
|
|
5
|
+
identity;
|
|
6
|
+
constructor(identity) {
|
|
7
|
+
this.identity = identity;
|
|
8
|
+
}
|
|
9
|
+
// This is account-wide: an unusable passkey must not turn MFA into password-only login.
|
|
10
|
+
async hasFactors(user) {
|
|
11
|
+
if (user.totp)
|
|
12
|
+
return true;
|
|
13
|
+
return this.identity.storage.transaction(user, async (tx) => (await tx.list("passkey", user)).some(p => p.userId === user.id));
|
|
14
|
+
}
|
|
15
|
+
async prepare(user, origin, enroll = false) {
|
|
16
|
+
const rpId = new URL(origin).hostname;
|
|
17
|
+
const keys = await this.identity.storage.transaction(user, async (tx) => (await tx.list("passkey", user)).filter(p => p.userId === user.id && p.rpId === rpId));
|
|
18
|
+
const methods = enroll ? ["totp", "passkey"] : [...(user.totp ? ["totp"] : []), ...(keys.length ? ["passkey"] : []), ...(user.recoveryCodes?.length ? ["recovery"] : [])];
|
|
19
|
+
if (!methods.length)
|
|
20
|
+
throw new AuthError("No authentication factor is available for this app. Sign in to an app where your passkey works and add an authenticator in Account, then try again.", 403);
|
|
21
|
+
const options = enroll
|
|
22
|
+
? await generateRegistrationOptions({ rpName: "BetterPortal", rpID: rpId, userName: user.username, userID: new Uint8Array(Buffer.from(secretHash(`${user.tenantId}:${user.appId}:${user.id}`), "hex")), excludeCredentials: keys.map(p => ({ id: p.id })), authenticatorSelection: { residentKey: "preferred", userVerification: "required" } })
|
|
23
|
+
: await generateAuthenticationOptions({ rpID: rpId, allowCredentials: keys.map(p => ({ id: p.id })), userVerification: "required" });
|
|
24
|
+
const secret = enroll ? generateSecret() : undefined;
|
|
25
|
+
// WebAuthn options may include undefined optional fields; expose their JSON wire representation.
|
|
26
|
+
const publicOptions = JSON.parse(JSON.stringify(options));
|
|
27
|
+
return {
|
|
28
|
+
public: { methods, options: publicOptions, enroll, ...(secret ? { totpSecret: secret, totpUri: generateURI({ issuer: "BetterPortal", label: user.username, secret }) } : {}) },
|
|
29
|
+
private: { origin, rpId, challenge: options.challenge, enroll, ...(secret ? { totpSecret: this.identity.cipher.encrypt(secret) } : {}) }
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
async complete(tx, scope, user, data, input) {
|
|
33
|
+
try {
|
|
34
|
+
const dir = { tenantId: user.tenantId, appId: user.appId };
|
|
35
|
+
const enroll = data.enroll === true;
|
|
36
|
+
if (input.method === "totp") {
|
|
37
|
+
const encrypted = enroll ? String(data.totpSecret ?? "") : user.totp;
|
|
38
|
+
if (!encrypted)
|
|
39
|
+
throw new AuthError("Authenticator not available.");
|
|
40
|
+
if (!/^[0-9]{6}$/.test(input.code ?? ""))
|
|
41
|
+
throw new AuthError("Enter a six-digit authenticator code.");
|
|
42
|
+
const result = await verify({ secret: this.identity.cipher.decrypt(encrypted), token: input.code ?? "", epochTolerance: [30, 0], ...(user.totpLastStep === undefined ? {} : { afterTimeStep: user.totpLastStep }) });
|
|
43
|
+
if (!result.valid || !("timeStep" in result))
|
|
44
|
+
throw new AuthError("Invalid or reused verification code.");
|
|
45
|
+
user.totpLastStep = result.timeStep;
|
|
46
|
+
if (enroll)
|
|
47
|
+
user.totp = encrypted;
|
|
48
|
+
}
|
|
49
|
+
else if (input.method === "passkey") {
|
|
50
|
+
if (enroll) {
|
|
51
|
+
const result = await verifyRegistrationResponse({ response: input.credential, expectedChallenge: String(data.challenge), expectedOrigin: String(data.origin), expectedRPID: String(data.rpId), requireUserVerification: true });
|
|
52
|
+
if (!result.verified || !result.registrationInfo)
|
|
53
|
+
throw new AuthError("Passkey registration failed.");
|
|
54
|
+
const { credential } = result.registrationInfo;
|
|
55
|
+
if (await tx.get("passkey", credential.id, dir))
|
|
56
|
+
throw new AuthError("Passkey already registered.");
|
|
57
|
+
await tx.put("passkey", dir, { id: credential.id, userId: user.id, rpId: String(data.rpId), publicKey: Buffer.from(credential.publicKey).toString("base64url"), counter: credential.counter, name: "Passkey" });
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
const response = input.credential;
|
|
61
|
+
const key = await tx.get("passkey", response?.id ?? "", dir);
|
|
62
|
+
if (!key || key.userId !== user.id || key.rpId !== data.rpId)
|
|
63
|
+
throw new AuthError("Passkey unavailable.");
|
|
64
|
+
const result = await verifyAuthenticationResponse({ response, expectedChallenge: String(data.challenge), expectedOrigin: String(data.origin), expectedRPID: key.rpId, requireUserVerification: true, credential: { id: key.id, publicKey: new Uint8Array(Buffer.from(key.publicKey, "base64url")), counter: key.counter } });
|
|
65
|
+
if (!result.verified)
|
|
66
|
+
throw new AuthError("Passkey verification failed.");
|
|
67
|
+
await tx.put("passkey", dir, { ...key, counter: result.authenticationInfo.newCounter });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else if (input.method === "recovery" && !enroll) {
|
|
71
|
+
const hash = secretHash(input.code ?? "");
|
|
72
|
+
if (!user.recoveryCodes?.includes(hash))
|
|
73
|
+
throw new AuthError("Invalid recovery code.");
|
|
74
|
+
user.recoveryCodes = user.recoveryCodes.filter(c => c !== hash);
|
|
75
|
+
}
|
|
76
|
+
else
|
|
77
|
+
throw new AuthError("Choose an available verification method.");
|
|
78
|
+
let codes;
|
|
79
|
+
if (enroll) {
|
|
80
|
+
user.refreshVersion++;
|
|
81
|
+
codes = Array.from({ length: 10 }, () => newSecret().slice(0, 20));
|
|
82
|
+
user.recoveryCodes = codes.map(secretHash);
|
|
83
|
+
}
|
|
84
|
+
await tx.put("user", dir, user);
|
|
85
|
+
await this.identity.audit(tx, scope, user.id, enroll ? "factor.enrolled" : input.method === "recovery" ? "factor.recovered" : "factor.verified");
|
|
86
|
+
return codes;
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
if (error instanceof AuthError)
|
|
90
|
+
throw error;
|
|
91
|
+
throw new AuthError("Authentication factor verification failed.");
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=factors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factors.js","sourceRoot":"","sources":["../src/factors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { type BpTokenIssuer, type JwtClaims } from "@betterportal/framework";
|
|
2
|
+
import type { AuthStorage, AuthTransaction, RecordValue, Scope } from "./storage.js";
|
|
3
|
+
export declare class AuthError extends Error {
|
|
4
|
+
readonly status: number;
|
|
5
|
+
constructor(message: string, status?: number);
|
|
6
|
+
}
|
|
7
|
+
export interface IdentityPolicy {
|
|
8
|
+
isolation: "app" | "tenant";
|
|
9
|
+
registration: "public" | "invite-only" | "closed";
|
|
10
|
+
defaultRoleIds: string[];
|
|
11
|
+
allowedRoleIds: string[];
|
|
12
|
+
requireMfa: boolean;
|
|
13
|
+
canManageDirectory?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface User extends RecordValue {
|
|
16
|
+
username: string;
|
|
17
|
+
tenantId: string;
|
|
18
|
+
appId: string;
|
|
19
|
+
passwordHash?: string;
|
|
20
|
+
email?: string;
|
|
21
|
+
emailVerified: boolean;
|
|
22
|
+
name?: string;
|
|
23
|
+
picture?: string;
|
|
24
|
+
enabled: boolean;
|
|
25
|
+
refreshVersion: number;
|
|
26
|
+
createdAt: number;
|
|
27
|
+
updatedAt: number;
|
|
28
|
+
totp?: string;
|
|
29
|
+
totpLastStep?: number;
|
|
30
|
+
recoveryCodes?: string[];
|
|
31
|
+
}
|
|
32
|
+
export interface Challenge extends RecordValue {
|
|
33
|
+
purpose: string;
|
|
34
|
+
userId?: string;
|
|
35
|
+
hash: string;
|
|
36
|
+
expiresAt: number;
|
|
37
|
+
attempts: number;
|
|
38
|
+
data: Record<string, unknown>;
|
|
39
|
+
}
|
|
40
|
+
export interface Session extends RecordValue {
|
|
41
|
+
userId: string;
|
|
42
|
+
userAppId: string;
|
|
43
|
+
version: number;
|
|
44
|
+
jti: string;
|
|
45
|
+
previousJtis: string[];
|
|
46
|
+
expiresAt: number;
|
|
47
|
+
createdAt: number;
|
|
48
|
+
revoked: boolean;
|
|
49
|
+
}
|
|
50
|
+
export declare const secretHash: (value: string) => string;
|
|
51
|
+
export declare const newSecret: () => string;
|
|
52
|
+
export declare const normalizeAccountIdentifier: (value: string) => string;
|
|
53
|
+
export declare function isValidEmail(value: string): boolean;
|
|
54
|
+
export declare function equalSecret(a: string, b: string): boolean;
|
|
55
|
+
export declare class SecretCipher {
|
|
56
|
+
private readonly key;
|
|
57
|
+
constructor(key: Buffer);
|
|
58
|
+
encrypt(value: string): string;
|
|
59
|
+
decrypt(value: string): string;
|
|
60
|
+
}
|
|
61
|
+
export declare function validatePassword(value: string): void;
|
|
62
|
+
export declare function hashPassword(value: string): Promise<string>;
|
|
63
|
+
export declare function verifyPassword(hash: string | undefined, value: string): Promise<boolean>;
|
|
64
|
+
export declare class IdentityService {
|
|
65
|
+
readonly storage: AuthStorage;
|
|
66
|
+
readonly cipher: SecretCipher;
|
|
67
|
+
constructor(storage: AuthStorage, cipher: SecretCipher);
|
|
68
|
+
private directory;
|
|
69
|
+
effectiveIsolation(tenantId: string, requested?: "app" | "tenant"): Promise<"app" | "tenant">;
|
|
70
|
+
hasNoUsers(): Promise<boolean>;
|
|
71
|
+
bootstrapAvailable(scope: Scope): Promise<boolean>;
|
|
72
|
+
createUser(scope: Scope, policy: IdentityPolicy, input: {
|
|
73
|
+
username: string;
|
|
74
|
+
password?: string;
|
|
75
|
+
email?: string;
|
|
76
|
+
name?: string;
|
|
77
|
+
verified?: boolean;
|
|
78
|
+
}, roles?: string[], root?: boolean): Promise<User>;
|
|
79
|
+
createInTransaction(tx: AuthTransaction, scope: Scope, policy: IdentityPolicy, input: {
|
|
80
|
+
username: string;
|
|
81
|
+
email?: string;
|
|
82
|
+
name?: string;
|
|
83
|
+
verified?: boolean;
|
|
84
|
+
}, passwordHash?: string, roles?: string[], root?: boolean): Promise<User>;
|
|
85
|
+
findUser(scope: Scope, policy: IdentityPolicy, identifier: string, byId?: boolean): Promise<User | undefined>;
|
|
86
|
+
authenticate(scope: Scope, policy: IdentityPolicy, username: string, password: string): Promise<User | undefined>;
|
|
87
|
+
updateUser(scope: Scope, policy: IdentityPolicy, id: string, update: (user: User, tx: AuthTransaction) => Promise<void>): Promise<User>;
|
|
88
|
+
roles(tx: AuthTransaction, scope: Scope, user: User, policy: IdentityPolicy, initialize?: boolean): Promise<string[]>;
|
|
89
|
+
issueSession(scope: Scope, policy: IdentityPolicy, user: User, issuer: BpTokenIssuer, refreshSeconds: number): Promise<import("@betterportal/framework").BpIssuedTokenPair>;
|
|
90
|
+
refresh(scope: Scope, policy: IdentityPolicy, claims: JwtClaims, issuer: BpTokenIssuer): Promise<import("@betterportal/framework").BpIssuedTokenPair | undefined>;
|
|
91
|
+
assertActiveSession(tx: AuthTransaction, scope: Scope, claims: JwtClaims, user: User): Promise<void>;
|
|
92
|
+
revokeSession(scope: Scope, claims: JwtClaims): Promise<void>;
|
|
93
|
+
challenge(scope: Scope, purpose: string, data: Record<string, unknown>, userId?: string, lifetimeSeconds?: number): Promise<{
|
|
94
|
+
id: string;
|
|
95
|
+
secret: string;
|
|
96
|
+
}>;
|
|
97
|
+
challengeInTransaction(tx: AuthTransaction, scope: Scope, purpose: string, data: Record<string, unknown>, userId?: string, lifetimeSeconds?: number): Promise<{
|
|
98
|
+
id: string;
|
|
99
|
+
secret: string;
|
|
100
|
+
}>;
|
|
101
|
+
consume<T>(scope: Scope, purpose: string, id: string, secret: string, complete: (challenge: Challenge, tx: AuthTransaction) => Promise<T>): Promise<T>;
|
|
102
|
+
consumeWithPreparation<T, P>(scope: Scope, purpose: string, id: string, secret: string, prepare: (challenge: Challenge) => Promise<P>, complete: (challenge: Challenge, tx: AuthTransaction, prepared: P) => Promise<T>): Promise<T>;
|
|
103
|
+
rateLimit(scope: Scope, action: string, actor: string, max?: number, seconds?: number): Promise<void>;
|
|
104
|
+
audit(tx: AuthTransaction, scope: Scope, actor: string, event: string, data?: Record<string, unknown>): Promise<void>;
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=identity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"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"}
|