@wizeworks/lens-cloud 0.3.0-alpha.1 → 0.3.0-alpha.2
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 +57 -5
- package/dist/alerts/evaluate.d.ts.map +1 -1
- package/dist/alerts/evaluate.js +17 -2
- package/dist/alerts/evaluate.js.map +1 -1
- package/dist/alerts/notify.d.ts +13 -2
- package/dist/alerts/notify.d.ts.map +1 -1
- package/dist/alerts/notify.js +22 -16
- package/dist/alerts/notify.js.map +1 -1
- package/dist/app.d.ts +10 -2
- package/dist/app.d.ts.map +1 -1
- package/dist/auth/auth.d.ts +51 -0
- package/dist/auth/auth.d.ts.map +1 -0
- package/dist/auth/auth.js +63 -0
- package/dist/auth/auth.js.map +1 -0
- package/dist/auth/bridge.d.ts +7 -0
- package/dist/auth/bridge.d.ts.map +1 -0
- package/dist/auth/bridge.js +39 -0
- package/dist/auth/bridge.js.map +1 -0
- package/dist/auth/crypto.d.ts +0 -5
- package/dist/auth/crypto.d.ts.map +1 -1
- package/dist/auth/crypto.js +3 -20
- package/dist/auth/crypto.js.map +1 -1
- package/dist/auth/delete-user.d.ts +16 -0
- package/dist/auth/delete-user.d.ts.map +1 -0
- package/dist/auth/delete-user.js +21 -0
- package/dist/auth/delete-user.js.map +1 -0
- package/dist/auth/deps.d.ts +27 -0
- package/dist/auth/deps.d.ts.map +1 -0
- package/dist/auth/deps.js +3 -0
- package/dist/auth/deps.js.map +1 -0
- package/dist/auth/email-token.d.ts +8 -0
- package/dist/auth/email-token.d.ts.map +1 -0
- package/dist/auth/email-token.js +15 -0
- package/dist/auth/email-token.js.map +1 -0
- package/dist/auth/hooks.d.ts +4 -0
- package/dist/auth/hooks.d.ts.map +1 -0
- package/dist/auth/hooks.js +143 -0
- package/dist/auth/hooks.js.map +1 -0
- package/dist/auth/options.d.ts +17 -0
- package/dist/auth/options.d.ts.map +1 -0
- package/dist/auth/options.js +98 -0
- package/dist/auth/options.js.map +1 -0
- package/dist/auth/password.d.ts +10 -0
- package/dist/auth/password.d.ts.map +1 -0
- package/dist/auth/password.js +22 -0
- package/dist/auth/password.js.map +1 -0
- package/dist/auth/plugins.d.ts +4 -0
- package/dist/auth/plugins.d.ts.map +1 -0
- package/dist/auth/plugins.js +45 -0
- package/dist/auth/plugins.js.map +1 -0
- package/dist/auth/principal.d.ts +8 -3
- package/dist/auth/principal.d.ts.map +1 -1
- package/dist/auth/principal.js +13 -8
- package/dist/auth/principal.js.map +1 -1
- package/dist/auth/roles.d.ts +43 -3
- package/dist/auth/roles.d.ts.map +1 -1
- package/dist/auth/roles.js +15 -6
- package/dist/auth/roles.js.map +1 -1
- package/dist/auth/schema-names.d.ts +130 -0
- package/dist/auth/schema-names.d.ts.map +1 -0
- package/dist/auth/schema-names.js +53 -0
- package/dist/auth/schema-names.js.map +1 -0
- package/dist/auth/secret.d.ts +12 -0
- package/dist/auth/secret.d.ts.map +1 -0
- package/dist/auth/secret.js +32 -0
- package/dist/auth/secret.js.map +1 -0
- package/dist/auth/security-notices.d.ts +34 -0
- package/dist/auth/security-notices.d.ts.map +1 -0
- package/dist/auth/security-notices.js +81 -0
- package/dist/auth/security-notices.js.map +1 -0
- package/dist/auth/signup.d.ts +23 -0
- package/dist/auth/signup.d.ts.map +1 -0
- package/dist/auth/signup.js +61 -0
- package/dist/auth/signup.js.map +1 -0
- package/dist/auth/sso.d.ts +21 -0
- package/dist/auth/sso.d.ts.map +1 -0
- package/dist/auth/sso.js +35 -0
- package/dist/auth/sso.js.map +1 -0
- package/dist/auth/wire.d.ts +16 -0
- package/dist/auth/wire.d.ts.map +1 -0
- package/dist/auth/wire.js +47 -0
- package/dist/auth/wire.js.map +1 -0
- package/dist/cli-args.d.ts +1 -1
- package/dist/cli-args.d.ts.map +1 -1
- package/dist/cli-args.js +55 -14
- package/dist/cli-args.js.map +1 -1
- package/dist/cli.js +18 -2
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +26 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +35 -0
- package/dist/config.js.map +1 -1
- package/dist/db/db.d.ts +5 -2
- package/dist/db/db.d.ts.map +1 -1
- package/dist/db/db.js +15 -8
- package/dist/db/db.js.map +1 -1
- package/dist/db/migrate.d.ts +2 -2
- package/dist/db/migrate.d.ts.map +1 -1
- package/dist/db/migrate.js +15 -5
- package/dist/db/migrate.js.map +1 -1
- package/dist/db/schema-auth.d.ts +2 -0
- package/dist/db/schema-auth.d.ts.map +1 -0
- package/dist/db/schema-auth.js +93 -0
- package/dist/db/schema-auth.js.map +1 -0
- package/dist/db/schema-mail.d.ts +2 -0
- package/dist/db/schema-mail.d.ts.map +1 -0
- package/dist/db/schema-mail.js +8 -0
- package/dist/db/schema-mail.js.map +1 -0
- package/dist/db/schema-notify.d.ts +2 -0
- package/dist/db/schema-notify.d.ts.map +1 -0
- package/dist/db/schema-notify.js +26 -0
- package/dist/db/schema-notify.js.map +1 -0
- package/dist/db/schema-sso.d.ts +2 -0
- package/dist/db/schema-sso.d.ts.map +1 -0
- package/dist/db/schema-sso.js +17 -0
- package/dist/db/schema-sso.js.map +1 -0
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +8 -0
- package/dist/db/schema.js.map +1 -1
- package/dist/http/http.d.ts +2 -0
- package/dist/http/http.d.ts.map +1 -1
- package/dist/http/http.js +7 -3
- package/dist/http/http.js.map +1 -1
- package/dist/jobs.d.ts +1 -1
- package/dist/jobs.d.ts.map +1 -1
- package/dist/jobs.js +14 -3
- package/dist/jobs.js.map +1 -1
- package/dist/mail/blocks.d.ts +14 -0
- package/dist/mail/blocks.d.ts.map +1 -0
- package/dist/mail/blocks.js +35 -0
- package/dist/mail/blocks.js.map +1 -0
- package/dist/mail/content.d.ts +68 -0
- package/dist/mail/content.d.ts.map +1 -0
- package/dist/mail/content.js +6 -0
- package/dist/mail/content.js.map +1 -0
- package/dist/mail/emails-digest.d.ts +10 -0
- package/dist/mail/emails-digest.d.ts.map +1 -0
- package/dist/mail/emails-digest.js +55 -0
- package/dist/mail/emails-digest.js.map +1 -0
- package/dist/mail/emails-health.d.ts +6 -0
- package/dist/mail/emails-health.d.ts.map +1 -0
- package/dist/mail/emails-health.js +36 -0
- package/dist/mail/emails-health.js.map +1 -0
- package/dist/mail/emails-security.d.ts +14 -0
- package/dist/mail/emails-security.d.ts.map +1 -0
- package/dist/mail/emails-security.js +27 -0
- package/dist/mail/emails-security.js.map +1 -0
- package/dist/mail/emails-team.d.ts +11 -0
- package/dist/mail/emails-team.d.ts.map +1 -0
- package/dist/mail/emails-team.js +45 -0
- package/dist/mail/emails-team.js.map +1 -0
- package/dist/mail/emails.d.ts +9 -0
- package/dist/mail/emails.d.ts.map +1 -0
- package/dist/mail/emails.js +49 -0
- package/dist/mail/emails.js.map +1 -0
- package/dist/mail/layout.d.ts +6 -0
- package/dist/mail/layout.d.ts.map +1 -0
- package/dist/mail/layout.js +10 -0
- package/dist/mail/layout.js.map +1 -0
- package/dist/mail/mailer.d.ts +25 -0
- package/dist/mail/mailer.d.ts.map +1 -0
- package/dist/mail/mailer.js +49 -0
- package/dist/mail/mailer.js.map +1 -0
- package/dist/mail/preview.d.ts +6 -0
- package/dist/mail/preview.d.ts.map +1 -0
- package/dist/mail/preview.js +26 -0
- package/dist/mail/preview.js.map +1 -0
- package/dist/mail/resend.d.ts +11 -0
- package/dist/mail/resend.d.ts.map +1 -0
- package/dist/mail/resend.js +34 -0
- package/dist/mail/resend.js.map +1 -0
- package/dist/mail/samples.d.ts +3 -0
- package/dist/mail/samples.d.ts.map +1 -0
- package/dist/mail/samples.js +63 -0
- package/dist/mail/samples.js.map +1 -0
- package/dist/mail/stop-route.d.ts +4 -0
- package/dist/mail/stop-route.d.ts.map +1 -0
- package/dist/mail/stop-route.js +41 -0
- package/dist/mail/stop-route.js.map +1 -0
- package/dist/mail/svix.d.ts +8 -0
- package/dist/mail/svix.d.ts.map +1 -0
- package/dist/mail/svix.js +17 -0
- package/dist/mail/svix.js.map +1 -0
- package/dist/mail/templates.d.ts +12 -0
- package/dist/mail/templates.d.ts.map +1 -0
- package/dist/mail/templates.js +18 -0
- package/dist/mail/templates.js.map +1 -0
- package/dist/mail/text.d.ts +4 -0
- package/dist/mail/text.d.ts.map +1 -0
- package/dist/mail/text.js +17 -0
- package/dist/mail/text.js.map +1 -0
- package/dist/mail/theme.d.ts +26 -0
- package/dist/mail/theme.d.ts.map +1 -0
- package/dist/mail/theme.js +21 -0
- package/dist/mail/theme.js.map +1 -0
- package/dist/mail/unsubscribe.d.ts +14 -0
- package/dist/mail/unsubscribe.d.ts.map +1 -0
- package/dist/mail/unsubscribe.js +39 -0
- package/dist/mail/unsubscribe.js.map +1 -0
- package/dist/mail/webhook.d.ts +5 -0
- package/dist/mail/webhook.d.ts.map +1 -0
- package/dist/mail/webhook.js +41 -0
- package/dist/mail/webhook.js.map +1 -0
- package/dist/notify/digest-data.d.ts +31 -0
- package/dist/notify/digest-data.d.ts.map +1 -0
- package/dist/notify/digest-data.js +37 -0
- package/dist/notify/digest-data.js.map +1 -0
- package/dist/notify/digest.d.ts +17 -0
- package/dist/notify/digest.d.ts.map +1 -0
- package/dist/notify/digest.js +76 -0
- package/dist/notify/digest.js.map +1 -0
- package/dist/notify/health.d.ts +6 -0
- package/dist/notify/health.d.ts.map +1 -0
- package/dist/notify/health.js +43 -0
- package/dist/notify/health.js.map +1 -0
- package/dist/notify/team-describe.d.ts +22 -0
- package/dist/notify/team-describe.d.ts.map +1 -0
- package/dist/notify/team-describe.js +67 -0
- package/dist/notify/team-describe.js.map +1 -0
- package/dist/notify/team.d.ts +6 -0
- package/dist/notify/team.d.ts.map +1 -0
- package/dist/notify/team.js +56 -0
- package/dist/notify/team.js.map +1 -0
- package/dist/repo/alerts.d.ts +6 -2
- package/dist/repo/alerts.d.ts.map +1 -1
- package/dist/repo/alerts.js.map +1 -1
- package/dist/repo/auth-prune.d.ts +4 -0
- package/dist/repo/auth-prune.d.ts.map +1 -0
- package/dist/repo/auth-prune.js +8 -0
- package/dist/repo/auth-prune.js.map +1 -0
- package/dist/repo/mail-prefs.d.ts +35 -0
- package/dist/repo/mail-prefs.d.ts.map +1 -0
- package/dist/repo/mail-prefs.js +34 -0
- package/dist/repo/mail-prefs.js.map +1 -0
- package/dist/repo/orgs.d.ts +15 -25
- package/dist/repo/orgs.d.ts.map +1 -1
- package/dist/repo/orgs.js +18 -60
- package/dist/repo/orgs.js.map +1 -1
- package/dist/repo/suppressions.d.ts +8 -0
- package/dist/repo/suppressions.d.ts.map +1 -0
- package/dist/repo/suppressions.js +16 -0
- package/dist/repo/suppressions.js.map +1 -0
- package/dist/repo/users.d.ts +5 -16
- package/dist/repo/users.d.ts.map +1 -1
- package/dist/repo/users.js +2 -60
- package/dist/repo/users.js.map +1 -1
- package/dist/routes/alerts.d.ts.map +1 -1
- package/dist/routes/alerts.js +23 -6
- package/dist/routes/alerts.js.map +1 -1
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/index.js +4 -2
- package/dist/routes/index.js.map +1 -1
- package/dist/routes/me.d.ts +4 -0
- package/dist/routes/me.d.ts.map +1 -0
- package/dist/routes/me.js +37 -0
- package/dist/routes/me.js.map +1 -0
- package/dist/routes/notify.d.ts +4 -0
- package/dist/routes/notify.d.ts.map +1 -0
- package/dist/routes/notify.js +55 -0
- package/dist/routes/notify.js.map +1 -0
- package/dist/routes/orgs.d.ts.map +1 -1
- package/dist/routes/orgs.js +30 -53
- package/dist/routes/orgs.js.map +1 -1
- package/dist/routes/projects.d.ts.map +1 -1
- package/dist/routes/projects.js +4 -3
- package/dist/routes/projects.js.map +1 -1
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +45 -14
- package/dist/server.js.map +1 -1
- package/package.json +19 -6
- package/dist/routes/auth.d.ts +0 -4
- package/dist/routes/auth.d.ts.map +0 -1
- package/dist/routes/auth.js +0 -106
- package/dist/routes/auth.js.map +0 -1
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { SignupMode } from "../config.js";
|
|
2
|
+
import type { Db } from "../db/db.js";
|
|
3
|
+
import type { Mailer } from "../mail/mailer.js";
|
|
4
|
+
import type { AuthSecret } from "./secret.js";
|
|
5
|
+
/** What the Better Auth setup needs from the cloud. */
|
|
6
|
+
export interface AuthDeps {
|
|
7
|
+
db: Db;
|
|
8
|
+
/** The cloud's own origin, for links and passkeys, for example https://lens.example.com. */
|
|
9
|
+
publicUrl: string;
|
|
10
|
+
/** Origins allowed to send changes: the public one (and its 127.0.0.1 twin for a local default). */
|
|
11
|
+
trustedOrigins: string[];
|
|
12
|
+
/** Identity provider origins the cloud may fetch OIDC settings from (`--sso-origins`). */
|
|
13
|
+
ssoOrigins: string[];
|
|
14
|
+
secrets: AuthSecret[];
|
|
15
|
+
signup: SignupMode;
|
|
16
|
+
mailer: Mailer;
|
|
17
|
+
/** The first account's one-time token: null once an account exists. */
|
|
18
|
+
setup: {
|
|
19
|
+
token(): string | null;
|
|
20
|
+
done(): void;
|
|
21
|
+
};
|
|
22
|
+
checkPwned: boolean;
|
|
23
|
+
retentionDays: number;
|
|
24
|
+
}
|
|
25
|
+
/** A link into the dashboard. Tokens go in the hash, so they never reach a server log. */
|
|
26
|
+
export declare const appLink: (deps: Pick<AuthDeps, "publicUrl">, route: string, token: string) => string;
|
|
27
|
+
//# sourceMappingURL=deps.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../../src/auth/deps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,uDAAuD;AACvD,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,EAAE,CAAC;IACP,4FAA4F;IAC5F,SAAS,EAAE,MAAM,CAAC;IAClB,oGAAoG;IACpG,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,0FAA0F;IAC1F,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,KAAK,EAAE;QAAE,KAAK,IAAI,MAAM,GAAG,IAAI,CAAC;QAAC,IAAI,IAAI,IAAI,CAAA;KAAE,CAAC;IAChD,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,0FAA0F;AAC1F,eAAO,MAAM,OAAO,SAAU,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,SAAS,MAAM,SAAS,MAAM,KAAG,MACb,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deps.js","sourceRoot":"","sources":["../../src/auth/deps.ts"],"names":[],"mappings":"AAuBA,0FAA0F;AAC1F,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,IAAiC,EAAE,KAAa,EAAE,KAAa,EAAU,EAAE,CACjG,GAAG,IAAI,CAAC,SAAS,gBAAgB,KAAK,UAAU,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** The current email in a confirm link (a JWT Better Auth checks itself), when the link changes the email. */
|
|
2
|
+
export declare function emailChangeOf(token: unknown): string | undefined;
|
|
3
|
+
/** Both addresses of an email-change link: `from` is the address before the change. */
|
|
4
|
+
export declare function changeOf(token: unknown): {
|
|
5
|
+
from: string;
|
|
6
|
+
to: string;
|
|
7
|
+
} | undefined;
|
|
8
|
+
//# sourceMappingURL=email-token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-token.d.ts","sourceRoot":"","sources":["../../src/auth/email-token.ts"],"names":[],"mappings":"AAAA,8GAA8G;AAC9G,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAEhE;AAED,uFAAuF;AACvF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAOjF"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** The current email in a confirm link (a JWT Better Auth checks itself), when the link changes the email. */
|
|
2
|
+
export function emailChangeOf(token) {
|
|
3
|
+
return changeOf(token)?.from;
|
|
4
|
+
}
|
|
5
|
+
/** Both addresses of an email-change link: `from` is the address before the change. */
|
|
6
|
+
export function changeOf(token) {
|
|
7
|
+
try {
|
|
8
|
+
const payload = JSON.parse(Buffer.from(String(token).split(".")[1] ?? "", "base64url").toString("utf8"));
|
|
9
|
+
return typeof payload.updateTo === "string" && typeof payload.email === "string" ? { from: payload.email, to: payload.updateTo } : undefined;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=email-token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"email-token.js","sourceRoot":"","sources":["../../src/auth/email-token.ts"],"names":[],"mappings":"AAAA,8GAA8G;AAC9G,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,OAAO,QAAQ,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC;AAC/B,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,QAAQ,CAAC,KAAc;IACrC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAA4C,CAAC;QACpJ,OAAO,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,EAAE,EAAE,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/I,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/auth/hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAIrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AA2H1C,wBAAgB,SAAS,CAAC,IAAI,EAAE,QAAQ,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAWpE"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { APIError, createAuthMiddleware, getSessionFromCtx, isAPIError } from "better-auth/api";
|
|
2
|
+
import { isOrgRole } from "@wizeworks/lens-core";
|
|
3
|
+
import { audit } from "../repo/audit.js";
|
|
4
|
+
import { emailChangeOf } from "./email-token.js";
|
|
5
|
+
import { isLegacyHash } from "./password.js";
|
|
6
|
+
import { rememberPasskey, securityAfter } from "./security-notices.js";
|
|
7
|
+
const ROLE_PATHS = new Set(["/organization/invite-member", "/organization/update-member-role", "/organization/add-member"]);
|
|
8
|
+
const NEEDS_ORG = new Set(["/organization/invite-member", "/organization/update-member-role", "/organization/remove-member", "/organization/update", "/organization/leave"]);
|
|
9
|
+
/** Organization changes, as our audit log names them. */
|
|
10
|
+
const AUDITED = {
|
|
11
|
+
"/organization/update": "org.update",
|
|
12
|
+
"/organization/invite-member": "member.invite",
|
|
13
|
+
"/organization/cancel-invitation": "invite.cancel",
|
|
14
|
+
"/organization/accept-invitation": "member.join",
|
|
15
|
+
"/organization/remove-member": "member.remove",
|
|
16
|
+
"/organization/update-member-role": "member.role",
|
|
17
|
+
"/organization/leave": "member.leave",
|
|
18
|
+
};
|
|
19
|
+
const SECRET_KEYS = ["password", "newPassword", "currentPassword", "token", "code", "invitationId"];
|
|
20
|
+
/** SSO provider changes, as our audit log names them. Their bodies hold client secrets, so only names go in. */
|
|
21
|
+
const SSO_AUDITED = {
|
|
22
|
+
"/sso/register": "sso.create",
|
|
23
|
+
"/sso/update-provider": "sso.update",
|
|
24
|
+
"/sso/delete-provider": "sso.delete",
|
|
25
|
+
"/sso/verify-domain": "sso.verify",
|
|
26
|
+
};
|
|
27
|
+
/** The organization of the provider a request changes, found before the change (a deleted provider is gone after). */
|
|
28
|
+
const ssoOrgOf = new WeakMap();
|
|
29
|
+
/** The email of a member being removed, found before the row is gone, so the notice can name them. */
|
|
30
|
+
const removedEmailOf = new WeakMap();
|
|
31
|
+
async function rememberRemoved(ctx, body) {
|
|
32
|
+
const target = str(body.memberIdOrEmail);
|
|
33
|
+
if (!ctx.request || !target)
|
|
34
|
+
return;
|
|
35
|
+
if (target.includes("@"))
|
|
36
|
+
return void removedEmailOf.set(ctx.request, target);
|
|
37
|
+
const [row] = await ctx.context.adapter.findMany({ model: "member", where: [{ field: "id", value: target }], limit: 1 });
|
|
38
|
+
const found = row && (await ctx.context.internalAdapter.findUserById(row.userId));
|
|
39
|
+
if (found)
|
|
40
|
+
removedEmailOf.set(ctx.request, found.email);
|
|
41
|
+
}
|
|
42
|
+
const str = (v) => (typeof v === "string" ? v : undefined);
|
|
43
|
+
/** Better Auth signs in whoever opens an email-change link; with 2FA on, that must happen on a device already signed in. */
|
|
44
|
+
async function guardEmailChange(ctx) {
|
|
45
|
+
const email = emailChangeOf(ctx.query?.token);
|
|
46
|
+
if (!email || (await getSessionFromCtx(ctx)))
|
|
47
|
+
return;
|
|
48
|
+
const found = await ctx.context.internalAdapter.findUserByEmail(email);
|
|
49
|
+
if (found?.user?.twoFactorEnabled)
|
|
50
|
+
throw new APIError("UNAUTHORIZED", { message: "Sign in on this device first, then open the link again." });
|
|
51
|
+
}
|
|
52
|
+
/** SSO providers belong to an organization and have a DNS-safe id; OIDC keeps PKCE and SAML wants signed assertions. New ones say so outright. */
|
|
53
|
+
function guardSso(path, body) {
|
|
54
|
+
const create = path === "/sso/register";
|
|
55
|
+
if (create && !str(body.organizationId))
|
|
56
|
+
throw new APIError("BAD_REQUEST", { message: "Send organizationId: SSO providers belong to an organization." });
|
|
57
|
+
if (create && !/^[a-z0-9][a-z0-9-]{1,39}$/.test(str(body.providerId) ?? ""))
|
|
58
|
+
throw new APIError("BAD_REQUEST", { message: "The provider id is 2 to 40 lowercase letters, digits, and dashes." });
|
|
59
|
+
const oidc = body.oidcConfig;
|
|
60
|
+
const saml = body.samlConfig;
|
|
61
|
+
if (oidc && (create ? oidc.pkce !== true : oidc.pkce === false))
|
|
62
|
+
throw new APIError("BAD_REQUEST", { message: "OIDC providers must use PKCE." });
|
|
63
|
+
if (saml && (create ? saml.wantAssertionsSigned !== true : saml.wantAssertionsSigned === false))
|
|
64
|
+
throw new APIError("BAD_REQUEST", { message: "SAML providers must sign assertions." });
|
|
65
|
+
}
|
|
66
|
+
async function rememberSsoOrg(ctx, body) {
|
|
67
|
+
const providerId = str(body.providerId);
|
|
68
|
+
if (!ctx.request || !providerId)
|
|
69
|
+
return;
|
|
70
|
+
const row = await ctx.context.adapter.findOne({ model: "ssoProvider", where: [{ field: "providerId", value: providerId }] });
|
|
71
|
+
const orgId = str(body.organizationId) ?? row?.organizationId ?? undefined;
|
|
72
|
+
if (orgId)
|
|
73
|
+
ssoOrgOf.set(ctx.request, orgId);
|
|
74
|
+
}
|
|
75
|
+
/** One known role per member, the organization always named (never "the active one"), and a password to delete an account. */
|
|
76
|
+
const guard = async (ctx) => {
|
|
77
|
+
if (ctx.path === "/verify-email")
|
|
78
|
+
return guardEmailChange(ctx);
|
|
79
|
+
if (ctx.path === "/passkey/delete-passkey")
|
|
80
|
+
return rememberPasskey(ctx);
|
|
81
|
+
if (SSO_AUDITED[ctx.path]) {
|
|
82
|
+
guardSso(ctx.path, (ctx.body ?? {}));
|
|
83
|
+
return rememberSsoOrg(ctx, (ctx.body ?? {}));
|
|
84
|
+
}
|
|
85
|
+
const body = (ctx.body ?? {});
|
|
86
|
+
if (ROLE_PATHS.has(ctx.path) && body.role !== undefined && !isOrgRole(body.role))
|
|
87
|
+
throw new APIError("BAD_REQUEST", { message: "Pick one role: owner, admin, member, or viewer." });
|
|
88
|
+
if (NEEDS_ORG.has(ctx.path) && !str(body.organizationId))
|
|
89
|
+
throw new APIError("BAD_REQUEST", { message: "Send organizationId." });
|
|
90
|
+
if (ctx.path === "/delete-user" && !str(body.password) && !str(body.token))
|
|
91
|
+
throw new APIError("BAD_REQUEST", { message: "Enter your password." });
|
|
92
|
+
if (ctx.path === "/organization/remove-member")
|
|
93
|
+
await rememberRemoved(ctx, body);
|
|
94
|
+
};
|
|
95
|
+
/** A successful sign-in with an old hash stores a new one. */
|
|
96
|
+
async function upgradeHash(ctx) {
|
|
97
|
+
const body = ctx.body;
|
|
98
|
+
if (typeof body.email !== "string" || typeof body.password !== "string")
|
|
99
|
+
return;
|
|
100
|
+
const found = await ctx.context.internalAdapter.findUserByEmail(body.email);
|
|
101
|
+
const account = found && (await ctx.context.internalAdapter.findCredentialAccount(found.user.id));
|
|
102
|
+
if (found && account?.password && isLegacyHash(account.password))
|
|
103
|
+
await ctx.context.internalAdapter.updatePassword(found.user.id, await ctx.context.password.hash(body.password));
|
|
104
|
+
}
|
|
105
|
+
function orgIdOf(ctx) {
|
|
106
|
+
const r = ctx.context.returned;
|
|
107
|
+
return str(ctx.body?.organizationId) ?? r?.organizationId ?? r?.member?.organizationId ?? r?.invitation?.organizationId;
|
|
108
|
+
}
|
|
109
|
+
async function auditOrgChange(deps, ctx) {
|
|
110
|
+
const action = AUDITED[ctx.path];
|
|
111
|
+
const orgId = action && orgIdOf(ctx);
|
|
112
|
+
if (!action || !orgId)
|
|
113
|
+
return;
|
|
114
|
+
const actor = (await getSessionFromCtx(ctx))?.user.id;
|
|
115
|
+
const removed = ctx.request && removedEmailOf.get(ctx.request);
|
|
116
|
+
const detail = { ...Object.fromEntries(Object.entries((ctx.body ?? {})).filter(([k]) => !SECRET_KEYS.includes(k))), ...(removed ? { memberEmail: removed } : {}) };
|
|
117
|
+
await audit(deps.db, orgId, actor ? `user:${actor}` : "system", action, detail, Date.now());
|
|
118
|
+
}
|
|
119
|
+
async function auditSsoChange(deps, ctx) {
|
|
120
|
+
const action = SSO_AUDITED[ctx.path];
|
|
121
|
+
const orgId = action && ctx.request && ssoOrgOf.get(ctx.request);
|
|
122
|
+
if (!action || !orgId)
|
|
123
|
+
return;
|
|
124
|
+
const body = (ctx.body ?? {});
|
|
125
|
+
const actor = (await getSessionFromCtx(ctx))?.user.id;
|
|
126
|
+
const detail = { providerId: str(body.providerId), domain: str(body.domain), type: body.samlConfig ? "saml" : body.oidcConfig ? "oidc" : undefined };
|
|
127
|
+
await audit(deps.db, orgId, actor ? `user:${actor}` : "system", action, detail, Date.now());
|
|
128
|
+
}
|
|
129
|
+
export function authHooks(deps) {
|
|
130
|
+
return {
|
|
131
|
+
before: createAuthMiddleware(guard),
|
|
132
|
+
after: createAuthMiddleware(async (ctx) => {
|
|
133
|
+
if (isAPIError(ctx.context.returned) || ctx.context.returned instanceof Error)
|
|
134
|
+
return;
|
|
135
|
+
if (ctx.path === "/sign-in/email")
|
|
136
|
+
await upgradeHash(ctx);
|
|
137
|
+
await auditOrgChange(deps, ctx);
|
|
138
|
+
await auditSsoChange(deps, ctx);
|
|
139
|
+
await securityAfter(deps, ctx);
|
|
140
|
+
}),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/auth/hooks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { BetterAuthOptions } from "better-auth";
|
|
2
|
+
import { type AuthDeps } from "./deps.js";
|
|
3
|
+
export declare const AUTH_BASE_PATH = "/_wizelens/api/auth";
|
|
4
|
+
export declare const CLIENT_IP_HEADER = "x-wizelens-client-ip";
|
|
5
|
+
/** Who the person is and how they leave: change email, delete the account. Deleting checks organizations first (auth/delete-user.ts). */
|
|
6
|
+
export declare function userOptions(deps: AuthDeps, beforeDelete: (user: {
|
|
7
|
+
id: string;
|
|
8
|
+
}) => Promise<void>): BetterAuthOptions["user"];
|
|
9
|
+
/** Email and password, with links that open the dashboard. Without real mail there is nothing to verify with, so it is not asked for. */
|
|
10
|
+
export declare function passwordAuth(deps: AuthDeps): Pick<BetterAuthOptions, "emailAndPassword" | "emailVerification">;
|
|
11
|
+
/** Sessions live in the database only (no cookie cache), so signing out a device or a password reset works on the next request. */
|
|
12
|
+
export declare function sessionOptions(): Pick<BetterAuthOptions, "session" | "account" | "verification">;
|
|
13
|
+
/** Limits per client address, shared by every instance through the database. */
|
|
14
|
+
export declare function rateLimitOptions(): BetterAuthOptions["rateLimit"];
|
|
15
|
+
/** Every safety switch set on purpose: Better Auth relaxes some in test and development runs. */
|
|
16
|
+
export declare function advancedOptions(deps: AuthDeps): BetterAuthOptions["advanced"];
|
|
17
|
+
//# sourceMappingURL=options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/auth/options.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAKrD,OAAO,EAAE,KAAK,QAAQ,EAAW,MAAM,WAAW,CAAC;AAKnD,eAAO,MAAM,cAAc,wBAAwB,CAAC;AACpD,eAAO,MAAM,gBAAgB,yBAAyB,CAAC;AAIvD,yIAAyI;AACzI,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAc5H;AAED,yIAAyI;AACzI,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC,iBAAiB,EAAE,kBAAkB,GAAG,mBAAmB,CAAC,CAuB9G;AAED,mIAAmI;AACnI,wBAAgB,cAAc,IAAI,IAAI,CAAC,iBAAiB,EAAE,SAAS,GAAG,SAAS,GAAG,cAAc,CAAC,CAMhG;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,IAAI,iBAAiB,CAAC,WAAW,CAAC,CAqBjE;AAED,iGAAiG;AACjG,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAU7E"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { passwordChanged } from "../mail/emails-security.js";
|
|
3
|
+
import { unsuppress } from "../repo/suppressions.js";
|
|
4
|
+
import { sendSecurity } from "./security-notices.js";
|
|
5
|
+
import { changeEmailMail, deleteAccountMail, resetPasswordMail, verifyEmailMail } from "../mail/templates.js";
|
|
6
|
+
import { appLink } from "./deps.js";
|
|
7
|
+
import { passwordOptions } from "./password.js";
|
|
8
|
+
import { accountNames, rateLimitNames, sessionNames, userNames, verificationNames } from "./schema-names.js";
|
|
9
|
+
import { signupGate } from "./signup.js";
|
|
10
|
+
export const AUTH_BASE_PATH = "/_wizelens/api/auth";
|
|
11
|
+
export const CLIENT_IP_HEADER = "x-wizelens-client-ip";
|
|
12
|
+
const MINUTE = 60;
|
|
13
|
+
const DAY = 24 * 60 * MINUTE;
|
|
14
|
+
/** Who the person is and how they leave: change email, delete the account. Deleting checks organizations first (auth/delete-user.ts). */
|
|
15
|
+
export function userOptions(deps, beforeDelete) {
|
|
16
|
+
return {
|
|
17
|
+
...userNames,
|
|
18
|
+
validateUserInfo: signupGate(deps),
|
|
19
|
+
changeEmail: {
|
|
20
|
+
enabled: true,
|
|
21
|
+
sendChangeEmailConfirmation: async ({ user, newEmail, token }) => deps.mailer.send(changeEmailMail(user.email, newEmail, appLink(deps, "verify-email", token))),
|
|
22
|
+
},
|
|
23
|
+
deleteUser: {
|
|
24
|
+
enabled: true,
|
|
25
|
+
...(deps.mailer.live ? { sendDeleteAccountVerification: async ({ user, token }) => deps.mailer.send(deleteAccountMail(user.email, appLink(deps, "delete-account", token))) } : {}),
|
|
26
|
+
beforeDelete,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/** Email and password, with links that open the dashboard. Without real mail there is nothing to verify with, so it is not asked for. */
|
|
31
|
+
export function passwordAuth(deps) {
|
|
32
|
+
return {
|
|
33
|
+
emailAndPassword: {
|
|
34
|
+
enabled: true,
|
|
35
|
+
requireEmailVerification: deps.mailer.live,
|
|
36
|
+
autoSignIn: true,
|
|
37
|
+
minPasswordLength: 12,
|
|
38
|
+
maxPasswordLength: 128,
|
|
39
|
+
resetPasswordTokenExpiresIn: 30 * MINUTE,
|
|
40
|
+
revokeSessionsOnPasswordReset: true,
|
|
41
|
+
password: passwordOptions,
|
|
42
|
+
sendResetPassword: async ({ user, token }) => deps.mailer.send(resetPasswordMail(user.email, appLink(deps, "reset-password", token))),
|
|
43
|
+
onPasswordReset: async ({ user }) => sendSecurity(deps, user.id, (l) => passwordChanged(l, Date.now()), user.email),
|
|
44
|
+
customSyntheticUser: ({ coreFields, additionalFields, id }) => ({ ...coreFields, twoFactorEnabled: false, ...additionalFields, id }),
|
|
45
|
+
},
|
|
46
|
+
emailVerification: {
|
|
47
|
+
sendOnSignUp: deps.mailer.live,
|
|
48
|
+
autoSignInAfterVerification: true,
|
|
49
|
+
expiresIn: 60 * MINUTE,
|
|
50
|
+
sendVerificationEmail: async ({ user, token }) => deps.mailer.send(verifyEmailMail(user.email, appLink(deps, "verify-email", token))),
|
|
51
|
+
afterEmailVerification: async (user) => unsuppress(deps.db, user.email),
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/** Sessions live in the database only (no cookie cache), so signing out a device or a password reset works on the next request. */
|
|
56
|
+
export function sessionOptions() {
|
|
57
|
+
return {
|
|
58
|
+
session: { ...sessionNames, expiresIn: 14 * DAY, updateAge: DAY, freshAge: 15 * MINUTE, cookieCache: { enabled: false } },
|
|
59
|
+
account: { ...accountNames, encryptOAuthTokens: true },
|
|
60
|
+
verification: { ...verificationNames, storeIdentifier: "hashed" },
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** Limits per client address, shared by every instance through the database. */
|
|
64
|
+
export function rateLimitOptions() {
|
|
65
|
+
return {
|
|
66
|
+
enabled: true,
|
|
67
|
+
storage: "database",
|
|
68
|
+
...rateLimitNames,
|
|
69
|
+
window: 60,
|
|
70
|
+
max: 120,
|
|
71
|
+
customRules: {
|
|
72
|
+
"/sign-in/*": { window: 60, max: 10 },
|
|
73
|
+
"/sign-up/email": { window: 60, max: 5 },
|
|
74
|
+
"/two-factor/*": { window: 60, max: 10 },
|
|
75
|
+
"/request-password-reset": { window: 5 * MINUTE, max: 3 },
|
|
76
|
+
"/send-verification-email": { window: 5 * MINUTE, max: 3 },
|
|
77
|
+
"/change-password": { window: 60, max: 5 },
|
|
78
|
+
"/change-email": { window: 5 * MINUTE, max: 3 },
|
|
79
|
+
"/delete-user": { window: 5 * MINUTE, max: 5 },
|
|
80
|
+
"/get-session": { window: 10, max: 60 },
|
|
81
|
+
"/sso/register": { window: 60, max: 5 },
|
|
82
|
+
"/sso/verify-domain": { window: 60, max: 5 },
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/** Every safety switch set on purpose: Better Auth relaxes some in test and development runs. */
|
|
87
|
+
export function advancedOptions(deps) {
|
|
88
|
+
return {
|
|
89
|
+
cookiePrefix: "wizelens",
|
|
90
|
+
useSecureCookies: deps.publicUrl.startsWith("https://"),
|
|
91
|
+
defaultCookieAttributes: { sameSite: "lax", path: "/_wizelens" },
|
|
92
|
+
disableCSRFCheck: false,
|
|
93
|
+
disableOriginCheck: false,
|
|
94
|
+
ipAddress: { ipAddressHeaders: [CLIENT_IP_HEADER] },
|
|
95
|
+
database: { generateId: () => randomUUID(), validateSchema: true },
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.js","sourceRoot":"","sources":["../../src/auth/options.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const isLegacyHash: (hash: string) => boolean;
|
|
2
|
+
/** New hashes use Better Auth's scrypt; old ones still verify, and sign-in replaces them (auth/hooks.ts). */
|
|
3
|
+
export declare const passwordOptions: {
|
|
4
|
+
hash: (password: string) => Promise<string>;
|
|
5
|
+
verify: ({ hash, password }: {
|
|
6
|
+
hash: string;
|
|
7
|
+
password: string;
|
|
8
|
+
}) => Promise<boolean>;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=password.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password.d.ts","sourceRoot":"","sources":["../../src/auth/password.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,YAAY,SAAU,MAAM,KAAG,OAAqC,CAAC;AAclF,6GAA6G;AAC7G,eAAO,MAAM,eAAe;IAC1B,IAAI,aAAa,MAAM;IACvB,MAAM,uBAAuB;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE;CAChE,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { scrypt, timingSafeEqual } from "node:crypto";
|
|
2
|
+
import { hashPassword, verifyPassword } from "better-auth/crypto";
|
|
3
|
+
// Hashes from before Better Auth: "scrypt$<salt b64url>$<key b64url>", N=16384 r=8 p=1, 32-byte key, password as typed.
|
|
4
|
+
const LEGACY = { N: 16384, r: 8, p: 1, keylen: 32 };
|
|
5
|
+
export const isLegacyHash = (hash) => hash.startsWith("scrypt$");
|
|
6
|
+
function legacyKey(password, salt) {
|
|
7
|
+
return new Promise((ok, fail) => scrypt(password, salt, LEGACY.keylen, { N: LEGACY.N, r: LEGACY.r, p: LEGACY.p }, (e, k) => (e ? fail(e) : ok(k))));
|
|
8
|
+
}
|
|
9
|
+
async function verifyLegacy(hash, password) {
|
|
10
|
+
const [, salt, key] = hash.split("$");
|
|
11
|
+
if (!salt || !key)
|
|
12
|
+
return false;
|
|
13
|
+
const want = Buffer.from(key, "base64url");
|
|
14
|
+
const got = await legacyKey(password, Buffer.from(salt, "base64url"));
|
|
15
|
+
return want.length === got.length && timingSafeEqual(want, got);
|
|
16
|
+
}
|
|
17
|
+
/** New hashes use Better Auth's scrypt; old ones still verify, and sign-in replaces them (auth/hooks.ts). */
|
|
18
|
+
export const passwordOptions = {
|
|
19
|
+
hash: (password) => hashPassword(password),
|
|
20
|
+
verify: ({ hash, password }) => (isLegacyHash(hash) ? verifyLegacy(hash, password) : verifyPassword({ hash, password })),
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=password.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password.js","sourceRoot":"","sources":["../../src/auth/password.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAElE,wHAAwH;AACxH,MAAM,MAAM,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;AAEpD,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,IAAY,EAAW,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;AAElF,SAAS,SAAS,CAAC,QAAgB,EAAE,IAAY;IAC/C,OAAO,IAAI,OAAO,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtJ,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,IAAY,EAAE,QAAgB;IACxD,MAAM,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACtC,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IAChC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IAC3C,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC;IACtE,OAAO,IAAI,CAAC,MAAM,KAAK,GAAG,CAAC,MAAM,IAAI,eAAe,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AAClE,CAAC;AAED,6GAA6G;AAC7G,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,IAAI,EAAE,CAAC,QAAgB,EAAE,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC;IAClD,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAsC,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;CAC7J,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugins.d.ts","sourceRoot":"","sources":["../../src/auth/plugins.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGpD,OAAO,EAAE,KAAK,QAAQ,EAAW,MAAM,WAAW,CAAC;AA6CnD,eAAO,MAAM,WAAW,SAAU,QAAQ,KAAG,gBAAgB,EAAgI,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { passkey } from "@better-auth/passkey";
|
|
2
|
+
import { haveIBeenPwned, organization, twoFactor } from "better-auth/plugins";
|
|
3
|
+
import { inviteMail } from "../mail/templates.js";
|
|
4
|
+
import { appLink } from "./deps.js";
|
|
5
|
+
import { ac, authRoles } from "./roles.js";
|
|
6
|
+
import { orgSchema, passkeySchema, twoFactorSchema } from "./schema-names.js";
|
|
7
|
+
import { ssoPlugin } from "./sso.js";
|
|
8
|
+
const DAY = 24 * 60 * 60;
|
|
9
|
+
/** Only the cloud creates organizations and only our route deletes one; an invite opens only for its (verified, with mail) email. */
|
|
10
|
+
function orgPlugin(deps) {
|
|
11
|
+
return organization({
|
|
12
|
+
ac,
|
|
13
|
+
roles: authRoles,
|
|
14
|
+
creatorRole: "owner",
|
|
15
|
+
allowUserToCreateOrganization: false,
|
|
16
|
+
organizationLimit: 50,
|
|
17
|
+
membershipLimit: 1000,
|
|
18
|
+
invitationExpiresIn: 7 * DAY,
|
|
19
|
+
invitationLimit: 500,
|
|
20
|
+
cancelPendingInvitationsOnReInvite: true,
|
|
21
|
+
requireEmailVerificationOnInvitation: deps.mailer.live,
|
|
22
|
+
disableOrganizationDeletion: true,
|
|
23
|
+
schema: orgSchema,
|
|
24
|
+
sendInvitationEmail: async ({ id, email, role, organization: org, inviter }) => deps.mailer.send(inviteMail(email, inviter.user.name, org.name, String(role), appLink(deps, "invite", id))),
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
/** Codes from a phone app, with 10 one-time backup codes. Both are stored encrypted with the auth secret. */
|
|
28
|
+
function twoFactorPlugin() {
|
|
29
|
+
return twoFactor({
|
|
30
|
+
issuer: "WizeLens",
|
|
31
|
+
schema: twoFactorSchema,
|
|
32
|
+
totpOptions: { digits: 6, period: 30 },
|
|
33
|
+
backupCodeOptions: { amount: 10, length: 12, storeBackupCodes: "encrypted" },
|
|
34
|
+
trustDeviceMaxAge: 14 * DAY,
|
|
35
|
+
twoFactorCookieMaxAge: 5 * 60,
|
|
36
|
+
accountLockout: { enabled: true, maxFailedAttempts: 10, durationSeconds: 15 * 60 },
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/** Passkeys must check the person on the device (PIN, fingerprint), so a passkey is two factors by itself. */
|
|
40
|
+
function passkeyPlugin(deps) {
|
|
41
|
+
const url = new URL(deps.publicUrl);
|
|
42
|
+
return passkey({ rpID: url.hostname, rpName: "WizeLens", origin: deps.trustedOrigins, schema: passkeySchema, authenticatorSelection: { residentKey: "preferred", userVerification: "required" } });
|
|
43
|
+
}
|
|
44
|
+
export const authPlugins = (deps) => [orgPlugin(deps), twoFactorPlugin(), passkeyPlugin(deps), ssoPlugin(deps), ...(deps.checkPwned ? [haveIBeenPwned()] : [])];
|
|
45
|
+
//# sourceMappingURL=plugins.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugins.js","sourceRoot":"","sources":["../../src/auth/plugins.ts"],"names":[],"mappings":"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"}
|
package/dist/auth/principal.d.ts
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
import type { Ctx } from "../app.js";
|
|
2
2
|
import { type ApiKey, type Project } from "../repo/projects.js";
|
|
3
|
-
import {
|
|
3
|
+
import type { User } from "../repo/users.js";
|
|
4
4
|
import { type Permission, type Role } from "./roles.js";
|
|
5
|
-
|
|
6
|
-
/** Who is calling: a signed-in person, or a read key (AI agents and scripts). */
|
|
5
|
+
/** Who is calling: a signed-in person (a Better Auth session), or a read key (AI agents and scripts). */
|
|
7
6
|
export type Principal = {
|
|
8
7
|
kind: "user";
|
|
9
8
|
user: User;
|
|
9
|
+
sessionId: string;
|
|
10
10
|
} | {
|
|
11
11
|
kind: "key";
|
|
12
12
|
key: ApiKey & {
|
|
13
13
|
orgId: string;
|
|
14
14
|
};
|
|
15
15
|
};
|
|
16
|
+
/** The session of this request, read from the database each time (no cookie cache), so a revoked session stops at once. */
|
|
17
|
+
export declare function sessionOf(ctx: Ctx): Promise<{
|
|
18
|
+
user: User;
|
|
19
|
+
sessionId: string;
|
|
20
|
+
} | undefined>;
|
|
16
21
|
export declare function principalOf(ctx: Ctx): Promise<Principal | undefined>;
|
|
17
22
|
/** A signed-in person, or 401. Changes also need the dashboard header, so other sites cannot send them. */
|
|
18
23
|
export declare function requireUser(ctx: Ctx): Promise<User>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"principal.d.ts","sourceRoot":"","sources":["../../src/auth/principal.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"principal.d.ts","sourceRoot":"","sources":["../../src/auth/principal.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAGrC,OAAO,EAAE,KAAK,MAAM,EAAc,KAAK,OAAO,EAAgB,MAAM,qBAAqB,CAAC;AAC1F,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAO,KAAK,UAAU,EAAE,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AAE7D,yGAAyG;AACzG,MAAM,MAAM,SAAS,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAE3H,2HAA2H;AAC3H,wBAAsB,SAAS,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAAC,CAKhG;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAQ1E;AAED,2GAA2G;AAC3G,wBAAsB,WAAW,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAMzD;AAED,mHAAmH;AACnH,wBAAsB,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,IAAI,CAAA;CAAE,CAAC,CAMrH;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,oDAAoD;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,IAAI,CAAC;IACX,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,gEAAgE;AAChE,wBAAsB,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,GAAE,UAAmB,GAAG,OAAO,CAAC,aAAa,CAAC,CAWzH"}
|
package/dist/auth/principal.js
CHANGED
|
@@ -1,19 +1,24 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { fromNodeHeaders } from "better-auth/node";
|
|
2
|
+
import { bearerOf, fail, HttpError } from "../http/http.js";
|
|
2
3
|
import { membership } from "../repo/orgs.js";
|
|
3
4
|
import { keyByToken, projectInOrg } from "../repo/projects.js";
|
|
4
|
-
import { userBySession } from "../repo/users.js";
|
|
5
5
|
import { can } from "./roles.js";
|
|
6
|
-
|
|
6
|
+
/** The session of this request, read from the database each time (no cookie cache), so a revoked session stops at once. */
|
|
7
|
+
export async function sessionOf(ctx) {
|
|
8
|
+
const s = await ctx.app.auth.api.getSession({ headers: fromNodeHeaders(ctx.req.headers) });
|
|
9
|
+
if (!s)
|
|
10
|
+
return undefined;
|
|
11
|
+
const { id, email, name, emailVerified } = s.user;
|
|
12
|
+
return { user: { id, email, name, emailVerified, twoFactorEnabled: !!s.user.twoFactorEnabled }, sessionId: s.session.id };
|
|
13
|
+
}
|
|
7
14
|
export async function principalOf(ctx) {
|
|
8
|
-
const now = ctx.app.config.now();
|
|
9
15
|
const bearer = bearerOf(ctx.req);
|
|
10
16
|
if (bearer?.startsWith("wl_rk_")) {
|
|
11
|
-
const key = await keyByToken(ctx.app.db, bearer, now);
|
|
17
|
+
const key = await keyByToken(ctx.app.db, bearer, ctx.app.config.now());
|
|
12
18
|
return key?.kind === "read" ? { kind: "key", key } : undefined;
|
|
13
19
|
}
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
return user ? { kind: "user", user } : undefined;
|
|
20
|
+
const s = await sessionOf(ctx);
|
|
21
|
+
return s ? { kind: "user", ...s } : undefined;
|
|
17
22
|
}
|
|
18
23
|
/** A signed-in person, or 401. Changes also need the dashboard header, so other sites cannot send them. */
|
|
19
24
|
export async function requireUser(ctx) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"principal.js","sourceRoot":"","sources":["../../src/auth/principal.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"principal.js","sourceRoot":"","sources":["../../src/auth/principal.ts"],"names":[],"mappings":"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"}
|