@aventara/access 0.0.0-stage → 1.0.0-rc.1
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 +877 -0
- package/LICENSE +91 -0
- package/LICENSE-ADDITIONAL-PERMISSION.md +9 -0
- package/README.md +2536 -2
- package/dist/access/access-options.d.ts +74 -0
- package/dist/access/access-options.js +5 -0
- package/dist/access/access.error.d.ts +35 -0
- package/dist/access/access.error.js +11 -0
- package/dist/access/access.factory.d.ts +275 -0
- package/dist/access/access.factory.js +440 -0
- package/dist/access/better-auth.hardening.d.ts +120 -0
- package/dist/access/better-auth.hardening.js +420 -0
- package/dist/access/better-auth.loader.d.ts +67 -0
- package/dist/access/better-auth.loader.js +65 -0
- package/dist/access/better-auth.range.d.ts +9 -0
- package/dist/access/better-auth.range.js +28 -0
- package/dist/access/better-auth.require.d.ts +90 -0
- package/dist/access/better-auth.require.js +6 -0
- package/dist/access/better-auth.require.node.d.ts +7 -0
- package/dist/access/better-auth.require.node.js +52 -0
- package/dist/access/claims.mapper.d.ts +79 -0
- package/dist/access/claims.mapper.js +152 -0
- package/dist/access/key-set.cache.d.ts +10 -0
- package/dist/access/key-set.cache.js +63 -0
- package/dist/access/policies-block.checker.d.ts +64 -0
- package/dist/access/policies-block.checker.js +138 -0
- package/dist/access/principal.subject.d.ts +22 -0
- package/dist/access/principal.subject.js +89 -0
- package/dist/access/profile.policy.d.ts +74 -0
- package/dist/access/profile.policy.js +110 -0
- package/dist/access/request.state.d.ts +89 -0
- package/dist/access/request.state.js +266 -0
- package/dist/access/session.hooks.d.ts +114 -0
- package/dist/access/session.hooks.js +258 -0
- package/dist/access/token.verifier.d.ts +35 -0
- package/dist/access/token.verifier.js +69 -0
- package/dist/access-schema.d.ts +48 -0
- package/dist/access-schema.js +5 -0
- package/dist/access-warning.emitter.d.ts +4 -0
- package/dist/access-warning.emitter.js +24 -0
- package/dist/access.builder.d.ts +340 -0
- package/dist/access.builder.js +75 -0
- package/dist/access.engine.d.ts +155 -0
- package/dist/access.engine.js +477 -0
- package/dist/audit/audit-event.d.ts +135 -0
- package/dist/audit/audit-event.js +8 -0
- package/dist/audit/audit.log.d.ts +122 -0
- package/dist/audit/audit.log.js +345 -0
- package/dist/audit/audit.schema.d.ts +143 -0
- package/dist/audit/audit.schema.js +50 -0
- package/dist/auth/index.d.ts +12 -0
- package/dist/auth/index.js +2 -0
- package/dist/aventara-where.translator.d.ts +19 -0
- package/dist/aventara-where.translator.js +87 -0
- package/dist/beacon/beacon.check.d.ts +59 -0
- package/dist/beacon/beacon.check.js +128 -0
- package/dist/beacon/beacon.schema.d.ts +41 -0
- package/dist/beacon/beacon.schema.js +48 -0
- package/dist/beacon/beacon.store.d.ts +29 -0
- package/dist/beacon/beacon.store.js +78 -0
- package/dist/better-auth/access.client-plugin.d.ts +75 -0
- package/dist/better-auth/access.client-plugin.js +133 -0
- package/dist/better-auth/access.plugin.d.ts +164 -0
- package/dist/better-auth/access.plugin.js +348 -0
- package/dist/better-auth/access.provider.d.ts +80 -0
- package/dist/better-auth/access.provider.js +100 -0
- package/dist/better-auth/index.d.ts +7 -0
- package/dist/better-auth/index.js +4 -0
- package/dist/better-auth/organization.bridge.d.ts +66 -0
- package/dist/better-auth/organization.bridge.js +144 -0
- package/dist/canonical-json.writer.d.ts +12 -0
- package/dist/canonical-json.writer.js +30 -0
- package/dist/cli/avaccess.bin.d.ts +2 -0
- package/dist/cli/avaccess.bin.js +26 -0
- package/dist/cli/avaccess.program.d.ts +15 -0
- package/dist/cli/avaccess.program.js +166 -0
- package/dist/cli/beacon-pins.file.d.ts +14 -0
- package/dist/cli/beacon-pins.file.js +62 -0
- package/dist/cli/beacon.loader.d.ts +20 -0
- package/dist/cli/beacon.loader.js +71 -0
- package/dist/cli/cli.context.d.ts +49 -0
- package/dist/cli/cli.context.js +66 -0
- package/dist/cli/diff.command.d.ts +2 -0
- package/dist/cli/diff.command.js +66 -0
- package/dist/cli/generate.command.d.ts +2 -0
- package/dist/cli/generate.command.js +82 -0
- package/dist/cli/keys.command.d.ts +2 -0
- package/dist/cli/keys.command.js +96 -0
- package/dist/cli/lock.file.d.ts +31 -0
- package/dist/cli/lock.file.js +181 -0
- package/dist/cli/module.loader.d.ts +13 -0
- package/dist/cli/module.loader.js +63 -0
- package/dist/cli/policies.diff.d.ts +16 -0
- package/dist/cli/policies.diff.js +101 -0
- package/dist/cli/pull.command.d.ts +2 -0
- package/dist/cli/pull.command.js +234 -0
- package/dist/cli/push.command.d.ts +2 -0
- package/dist/cli/push.command.js +59 -0
- package/dist/cli/registry.client.d.ts +63 -0
- package/dist/cli/registry.client.js +287 -0
- package/dist/cli/schema.command.d.ts +2 -0
- package/dist/cli/schema.command.js +60 -0
- package/dist/cli/serve.command.d.ts +6 -0
- package/dist/cli/serve.command.js +200 -0
- package/dist/cli/status.command.d.ts +2 -0
- package/dist/cli/status.command.js +31 -0
- package/dist/cli/translator.flag.d.ts +6 -0
- package/dist/cli/translator.flag.js +24 -0
- package/dist/cli/verify.command.d.ts +2 -0
- package/dist/cli/verify.command.js +40 -0
- package/dist/client/access-client.factory.d.ts +92 -0
- package/dist/client/access-client.factory.js +269 -0
- package/dist/client/access-verbs.schema.d.ts +66 -0
- package/dist/client/access-verbs.schema.js +159 -0
- package/dist/client/verb-rate.limiter.d.ts +116 -0
- package/dist/client/verb-rate.limiter.js +358 -0
- package/dist/foreign/foreign-facts.d.ts +30 -0
- package/dist/foreign/foreign-facts.js +75 -0
- package/dist/foreign/foreign.merger.d.ts +10 -0
- package/dist/foreign/foreign.merger.js +52 -0
- package/dist/foreign-references.check.d.ts +6 -0
- package/dist/foreign-references.check.js +131 -0
- package/dist/generator/client.emitter.d.ts +28 -0
- package/dist/generator/client.emitter.js +411 -0
- package/dist/generator/copied-modules.reader.d.ts +14 -0
- package/dist/generator/copied-modules.reader.js +80 -0
- package/dist/generator/namespace.facts.d.ts +28 -0
- package/dist/generator/namespace.facts.js +32 -0
- package/dist/generator/orm.translator.d.ts +48 -0
- package/dist/generator/orm.translator.js +29 -0
- package/dist/generator/prisma7/prisma-schema.reader.d.ts +9 -0
- package/dist/generator/prisma7/prisma-schema.reader.js +394 -0
- package/dist/generator/prisma7/prisma-where.translator.d.ts +73 -0
- package/dist/generator/prisma7/prisma-where.translator.js +138 -0
- package/dist/generator/prisma7/prisma7.translator.d.ts +2 -0
- package/dist/generator/prisma7/prisma7.translator.js +87 -0
- package/dist/generator/schema.emitter.d.ts +14 -0
- package/dist/generator/schema.emitter.js +23 -0
- package/dist/generator/tsconfig.reader.d.ts +44 -0
- package/dist/generator/tsconfig.reader.js +110 -0
- package/dist/generator/typescript-literal.writer.d.ts +5 -0
- package/dist/generator/typescript-literal.writer.js +42 -0
- package/dist/guardrails/guardrails-contract.d.ts +45 -0
- package/dist/guardrails/guardrails-contract.js +12 -0
- package/dist/guardrails/guardrails.builder.d.ts +48 -0
- package/dist/guardrails/guardrails.builder.js +32 -0
- package/dist/guardrails/guardrails.compiler.d.ts +10 -0
- package/dist/guardrails/guardrails.compiler.js +254 -0
- package/dist/guardrails/guardrails.composer.d.ts +7 -0
- package/dist/guardrails/guardrails.composer.js +95 -0
- package/dist/guardrails/guardrails.hash.d.ts +10 -0
- package/dist/guardrails/guardrails.hash.js +38 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +6 -0
- package/dist/kiosk/kiosk-verbs.schema.d.ts +19 -0
- package/dist/kiosk/kiosk-verbs.schema.js +61 -0
- package/dist/kiosk/kiosk.plugin.d.ts +217 -0
- package/dist/kiosk/kiosk.plugin.js +877 -0
- package/dist/kiosk/kiosk.schema.d.ts +176 -0
- package/dist/kiosk/kiosk.schema.js +101 -0
- package/dist/kiosk/kiosk.store.d.ts +171 -0
- package/dist/kiosk/kiosk.store.js +478 -0
- package/dist/kiosk/lan-range.policy.d.ts +31 -0
- package/dist/kiosk/lan-range.policy.js +113 -0
- package/dist/kiosk/pin.policy.d.ts +9 -0
- package/dist/kiosk/pin.policy.js +143 -0
- package/dist/kiosk/session-use.marker.d.ts +4 -0
- package/dist/kiosk/session-use.marker.js +16 -0
- package/dist/lock/lock-contract.d.ts +38 -0
- package/dist/lock/lock-contract.js +67 -0
- package/dist/lock/lock.verifier.d.ts +27 -0
- package/dist/lock/lock.verifier.js +62 -0
- package/dist/mcp/agent-scope.gate.d.ts +13 -0
- package/dist/mcp/agent-scope.gate.js +75 -0
- package/dist/mcp/agent.grant.d.ts +40 -0
- package/dist/mcp/agent.grant.js +92 -0
- package/dist/mcp/mcp-options.d.ts +60 -0
- package/dist/mcp/mcp-options.js +72 -0
- package/dist/oauth/access-token.verifier.d.ts +66 -0
- package/dist/oauth/access-token.verifier.js +201 -0
- package/dist/oauth/oauth-provider.hardening.d.ts +62 -0
- package/dist/oauth/oauth-provider.hardening.js +261 -0
- package/dist/passwords/argon2id.hasher.d.ts +97 -0
- package/dist/passwords/argon2id.hasher.js +256 -0
- package/dist/passwords/node-rs-argon2.adapter.d.ts +25 -0
- package/dist/passwords/node-rs-argon2.adapter.js +42 -0
- package/dist/passwords/passwords.options.d.ts +79 -0
- package/dist/passwords/passwords.options.js +212 -0
- package/dist/policies-contract.d.ts +219 -0
- package/dist/policies-contract.js +8 -0
- package/dist/policies.compiler.d.ts +38 -0
- package/dist/policies.compiler.js +1433 -0
- package/dist/policies.decider.d.ts +103 -0
- package/dist/policies.decider.js +390 -0
- package/dist/policies.hash.d.ts +10 -0
- package/dist/policies.hash.js +54 -0
- package/dist/predicate.evaluator.d.ts +62 -0
- package/dist/predicate.evaluator.js +378 -0
- package/dist/random-secret.generator.d.ts +2 -0
- package/dist/random-secret.generator.js +15 -0
- package/dist/read-governed-unique.check.d.ts +3 -0
- package/dist/read-governed-unique.check.js +21 -0
- package/dist/reference-reads.check.d.ts +16 -0
- package/dist/reference-reads.check.js +158 -0
- package/dist/registry/access.registry.d.ts +173 -0
- package/dist/registry/access.registry.js +865 -0
- package/dist/registry/beacon.ledger.d.ts +30 -0
- package/dist/registry/beacon.ledger.js +93 -0
- package/dist/registry/ownership.check.d.ts +54 -0
- package/dist/registry/ownership.check.js +221 -0
- package/dist/registry/registry.endpoints.d.ts +50 -0
- package/dist/registry/registry.endpoints.js +193 -0
- package/dist/registry/registry.key.d.ts +7 -0
- package/dist/registry/registry.key.js +13 -0
- package/dist/registry/registry.options.d.ts +13 -0
- package/dist/registry/registry.options.js +28 -0
- package/dist/registry/registry.refusal.d.ts +6 -0
- package/dist/registry/registry.refusal.js +11 -0
- package/dist/registry/registry.schema.d.ts +238 -0
- package/dist/registry/registry.schema.js +127 -0
- package/dist/resources/auth-tables.catalog.d.ts +96 -0
- package/dist/resources/auth-tables.catalog.js +110 -0
- package/dist/resources/auth-tables.guard.d.ts +106 -0
- package/dist/resources/auth-tables.guard.js +462 -0
- package/dist/scope.resolver.d.ts +144 -0
- package/dist/scope.resolver.js +529 -0
- package/dist/sha256.digest.d.ts +2 -0
- package/dist/sha256.digest.js +81 -0
- package/dist/standalone/access.server.d.ts +41 -0
- package/dist/standalone/access.server.js +301 -0
- package/dist/standalone/index.d.ts +1 -0
- package/dist/standalone/index.js +1 -0
- package/package.json +102 -3
- package/skill/SKILL.md +170 -0
- package/skill/reference/callers.md +99 -0
- package/skill/reference/errors.md +89 -0
- package/skill/reference/recipes.md +281 -0
- package/skill/reference/rules.md +153 -0
- package/skill/reference/setup.md +334 -0
- package/src/aventara-where.translator.ts +116 -0
- package/src/beacon/beacon.check.ts +204 -0
- package/src/canonical-json.writer.ts +51 -0
- package/src/generator/prisma7/prisma-where.translator.ts +243 -0
- package/src/policies-contract.ts +215 -0
- package/src/policies.decider.ts +662 -0
- package/src/predicate.evaluator.ts +574 -0
- package/src/scope.resolver.ts +819 -0
- package/src/sha256.digest.ts +85 -0
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
// `createAccess`: Better Auth with Access's concerns beside it. Better Auth's own
|
|
2
|
+
// options sit in the `betterAuth` block, typed as Better Auth types them and passed
|
|
3
|
+
// to `betterAuth()` as they are; Access adds its blocks beside it (`policies`,
|
|
4
|
+
// `principal`, `profile`, `registry`, `audit`, `resources`, `passwords`) and installs two plugins of its own:
|
|
5
|
+
// Better Auth's `jwt()`, whose tokens carry `sub` and the declared claims under one
|
|
6
|
+
// fixed issuer and audience, and the Access plugin, which holds the service
|
|
7
|
+
// profile's refusals, with `registry: { enabled: true }` the registry's tables and
|
|
8
|
+
// routes, and with `audit` the hooks that log sessions and tokens (and, for
|
|
9
|
+
// `audit: true`, the audit table). Agents' and services' OAuth tokens are Better Auth's
|
|
10
|
+
// own: its OAuth provider (`@better-auth/oauth-provider`), which the app adds to
|
|
11
|
+
// `betterAuth.plugins` itself, issues them, and Access issues none. With `mcp`, Access
|
|
12
|
+
// reads the provider's tokens for the MCP endpoint: `access.mcp` is the framework's
|
|
13
|
+
// `mcp.authorization`, and an agent's principal is held to its token's audience and
|
|
14
|
+
// scopes. With `audience`, the service opts in to tokens addressed to it alone (RFC
|
|
15
|
+
// 8707). Either way Access checks the provider and requires PKCE of every
|
|
16
|
+
// authorization request. Over Better Auth's tables the engine runs
|
|
17
|
+
// built-in rules beside the app's (`resources`): a table no key opens is closed, an
|
|
18
|
+
// opened one takes only the writes Better Auth's hooks do not guard, and a secret
|
|
19
|
+
// column is never readable. Passwords are hashed with argon2id (`passwords`) unless
|
|
20
|
+
// the app set Better Auth's `emailAndPassword.password` hook itself. The instance mounts nothing: the app mounts
|
|
21
|
+
// `access.handler` the way it would mount Better Auth's. It satisfies the
|
|
22
|
+
// framework's access provider by shape (`policy`, `state`) without importing it.
|
|
23
|
+
//
|
|
24
|
+
// Building it reads no network and opens no port: Better Auth itself is built on
|
|
25
|
+
// the first request, `access.api` read or `state` call.
|
|
26
|
+
import { auditDestinationOf, createAuditLog, } from "../audit/audit.log.js";
|
|
27
|
+
import { auditSchema, kioskAuditSchema } from "../audit/audit.schema.js";
|
|
28
|
+
import { adapterBeaconStore, beaconSchema, } from "../beacon/beacon.schema.js";
|
|
29
|
+
import { accessClient, meEndpoint, } from "../client/access-client.factory.js";
|
|
30
|
+
import { verbRateLimiter, } from "../client/verb-rate.limiter.js";
|
|
31
|
+
import { kioskPlugin, } from "../kiosk/kiosk.plugin.js";
|
|
32
|
+
import { kioskSchema } from "../kiosk/kiosk.schema.js";
|
|
33
|
+
import { PIN_LENGTH } from "../kiosk/pin.policy.js";
|
|
34
|
+
import { authorizationServerOf, checkMcpOptions, } from "../mcp/mcp-options.js";
|
|
35
|
+
import { createAccessTokenVerifier, mcpAuthorizationOf, userInfoAudience, } from "../oauth/access-token.verifier.js";
|
|
36
|
+
import { checkOAuthProvider, checkResourceUrl, oauthUseOf, pkceGuard, } from "../oauth/oauth-provider.hardening.js";
|
|
37
|
+
import { passwordsOf, pinHasherOf, } from "../passwords/passwords.options.js";
|
|
38
|
+
import { isRecord } from "../policies.compiler.js";
|
|
39
|
+
import { POLICIES_FORMAT } from "../policies-contract.js";
|
|
40
|
+
import { createRegistry, } from "../registry/access.registry.js";
|
|
41
|
+
import { registryEndpoints, registryOnRequest, } from "../registry/registry.endpoints.js";
|
|
42
|
+
import { registryOptionsOf, } from "../registry/registry.options.js";
|
|
43
|
+
import { registrySchema } from "../registry/registry.schema.js";
|
|
44
|
+
import { checkResourcesOptions, } from "../resources/auth-tables.guard.js";
|
|
45
|
+
import { AccessError } from "./access.error.js";
|
|
46
|
+
import { baseURLOf, cookieCacheOn, crossSiteSessionCookie, refuseInstalledPlugins, refuseKioskOptions, refuseUnverifiedInvitations, } from "./better-auth.hardening.js";
|
|
47
|
+
import { loadBetterAuth } from "./better-auth.loader.js";
|
|
48
|
+
import { issuedClaims, } from "./claims.mapper.js";
|
|
49
|
+
import { betterAuthTablesFor, checkPoliciesBlock, guardedPolicy, } from "./policies-block.checker.js";
|
|
50
|
+
import { checkProfile } from "./profile.policy.js";
|
|
51
|
+
import { meOf, requestIdentity, requestState, sessionStillLive, verbMeOf, } from "./request.state.js";
|
|
52
|
+
import { sessionCookies, sessionWatch, signInIdentifier, withoutSessionCookies, } from "./session.hooks.js";
|
|
53
|
+
import { createTokenVerifier } from "./token.verifier.js";
|
|
54
|
+
/**
|
|
55
|
+
* The plugins `createAccess` installs itself, by id, as a sentence names each.
|
|
56
|
+
*/
|
|
57
|
+
const INSTALLED_PLUGINS = {
|
|
58
|
+
"aventara-access": "aventaraAccess()",
|
|
59
|
+
jwt: "jwt()",
|
|
60
|
+
};
|
|
61
|
+
/** The shortest and longest a token may live, in seconds, and the default. */
|
|
62
|
+
/**
|
|
63
|
+
* The `policies` block of a registry-only server, which has no rules of its own: no
|
|
64
|
+
* Resource, no claim beside `sub`, and so every policy question is denied.
|
|
65
|
+
*/
|
|
66
|
+
const REGISTRY_ONLY_POLICIES = {
|
|
67
|
+
rules: {
|
|
68
|
+
format: POLICIES_FORMAT,
|
|
69
|
+
claims: {},
|
|
70
|
+
schema: {},
|
|
71
|
+
roles: {},
|
|
72
|
+
govern: {},
|
|
73
|
+
grants: [],
|
|
74
|
+
denies: [],
|
|
75
|
+
},
|
|
76
|
+
claims: {},
|
|
77
|
+
};
|
|
78
|
+
const TOP_LEVEL = new Set([
|
|
79
|
+
"betterAuth",
|
|
80
|
+
"policies",
|
|
81
|
+
"principal",
|
|
82
|
+
"profile",
|
|
83
|
+
"registry",
|
|
84
|
+
"audit",
|
|
85
|
+
"resources",
|
|
86
|
+
"passwords",
|
|
87
|
+
"mcp",
|
|
88
|
+
"audience",
|
|
89
|
+
]);
|
|
90
|
+
const refuse = (message) => {
|
|
91
|
+
throw new AccessError("ACCESS_OPTIONS_INVALID", message);
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Builds an Access instance: Better Auth (from the `betterAuth` block, with `jwt()`
|
|
95
|
+
* and the Access plugin installed), the policy engine (from `policies.rules`) and
|
|
96
|
+
* the request state the framework's `access` option reads. It mounts nothing and
|
|
97
|
+
* opens no connection; `better-auth` is loaded here, and must be the exact version
|
|
98
|
+
* Access is built against.
|
|
99
|
+
*/
|
|
100
|
+
export function createAccess(options) {
|
|
101
|
+
if (!isRecord(options)) {
|
|
102
|
+
return refuse("createAccess takes one object: `{ betterAuth, policies, principal?, profile?, registry?, audit?, resources?, passwords?, mcp?, audience? }`.");
|
|
103
|
+
}
|
|
104
|
+
for (const key of Object.keys(options)) {
|
|
105
|
+
if (!TOP_LEVEL.has(key)) {
|
|
106
|
+
refuse(`createAccess does not take \`${key}\`; it takes \`betterAuth\`, \`policies\`, \`principal\`, \`profile\`, \`registry\`, \`audit\`, \`resources\`, \`passwords\`, \`mcp\` and \`audience\`.`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const { betterAuth: block, policies, principal, profile, registry, audit, resources, passwords, mcp, audience, } = options;
|
|
110
|
+
if (block === undefined) {
|
|
111
|
+
return refuse("the `betterAuth` option is missing: pass Better Auth's options there, as `betterAuth({...})` takes them (`{ database, ... }`).");
|
|
112
|
+
}
|
|
113
|
+
if (!isRecord(block)) {
|
|
114
|
+
return refuse("`betterAuth` holds Better Auth's options, as `betterAuth({...})` takes them.");
|
|
115
|
+
}
|
|
116
|
+
const { kind, kiosk: kioskSettings } = checkProfile(profile);
|
|
117
|
+
const plugins = refuseInstalledPlugins(block.plugins, {
|
|
118
|
+
by: "createAccess",
|
|
119
|
+
at: "betterAuth.plugins",
|
|
120
|
+
installs: INSTALLED_PLUGINS,
|
|
121
|
+
me: true,
|
|
122
|
+
kiosk: kind === "kiosk",
|
|
123
|
+
registry: isRecord(registry) && registry.enabled === true,
|
|
124
|
+
});
|
|
125
|
+
if (policies === undefined &&
|
|
126
|
+
!(isRecord(registry) && registry.enabled === true)) {
|
|
127
|
+
return refuse("the `policies` option is missing: pass `{ rules, claims }`, the rules (`definePolicies(model)…`) and the claims they read. Only a registry-only server (`registry: { enabled: true }`) may leave it out.");
|
|
128
|
+
}
|
|
129
|
+
const checked = checkPoliciesBlock(policies ?? REGISTRY_ONLY_POLICIES, principal);
|
|
130
|
+
const { claims, claimsOf, tokenTtl } = checked;
|
|
131
|
+
const auditTo = auditDestinationOf(audit);
|
|
132
|
+
// The audit log, when on: events reach the table through Better Auth's adapter
|
|
133
|
+
// (once Better Auth is built), or the app's sink.
|
|
134
|
+
const auditLog = auditTo === undefined
|
|
135
|
+
? undefined
|
|
136
|
+
: createAuditLog(auditTo, async () => (await instance().$context));
|
|
137
|
+
const registrySettings = registryOptionsOf(registry);
|
|
138
|
+
const registryOn = registrySettings !== undefined;
|
|
139
|
+
const opened = checkResourcesOptions(resources);
|
|
140
|
+
// The rules read the organization plugin's memberships when `members` opens
|
|
141
|
+
// them: a membership an unverified account took by invitation is refused.
|
|
142
|
+
if (opened.members) {
|
|
143
|
+
refuseUnverifiedInvitations(plugins, "`resources: { members: true }`");
|
|
144
|
+
}
|
|
145
|
+
const modules = loadBetterAuth();
|
|
146
|
+
// Better Auth's `emailAndPassword` with the argon2id hook in it, unless the app
|
|
147
|
+
// set its own `password` hook (then the block passes through as given), and with
|
|
148
|
+
// that hook the one that rehashes a password at the profile at sign-in.
|
|
149
|
+
const { emailAndPassword, rehash } = passwordsOf(passwords, block, modules, async () => await instance().$context);
|
|
150
|
+
// Every token's issuer and audience, fixed now: the app's base URL.
|
|
151
|
+
const writtenBase = baseURLOf(block, modules, "betterAuth.baseURL");
|
|
152
|
+
const issuer = new URL(writtenBase).origin;
|
|
153
|
+
// With `mcp` or `audience`: the resources whose tokens Better Auth's OAuth provider
|
|
154
|
+
// issues and Access reads, the provider checked, and with `mcp` the issuer as the
|
|
155
|
+
// authorization server the framework names.
|
|
156
|
+
const checkedMcp = checkMcpOptions(mcp, "mcp", issuer);
|
|
157
|
+
const ownAudience = audience === undefined
|
|
158
|
+
? undefined
|
|
159
|
+
: checkResourceUrl(audience, "audience", issuer);
|
|
160
|
+
let server;
|
|
161
|
+
const oauth = oauthUseOf(checkedMcp, ownAudience, userInfoAudience(block, modules));
|
|
162
|
+
if (oauth !== undefined) {
|
|
163
|
+
if (kind === "service") {
|
|
164
|
+
refuse(`\`${oauth.by}\` reads the tokens Better Auth's OAuth provider issues after its user signs in and consents in a browser, and the \`service\` profile hands no caller a session: use the \`web\` profile.`);
|
|
165
|
+
}
|
|
166
|
+
if (checkedMcp !== undefined) {
|
|
167
|
+
server = authorizationServerOf(issuer, "betterAuth.baseURL");
|
|
168
|
+
}
|
|
169
|
+
checkOAuthProvider(plugins, oauth, { at: "betterAuth.plugins" });
|
|
170
|
+
}
|
|
171
|
+
// A session cookie a browser sends from any site is read only from the origins
|
|
172
|
+
// Better Auth trusts (`state`, below), so there must be some.
|
|
173
|
+
const crossSite = crossSiteSessionCookie(block, "betterAuth.trustedOrigins");
|
|
174
|
+
// With Better Auth's cookie cache on, a session read from its cookie may have
|
|
175
|
+
// been revoked since: a token is issued only for a session the store still has.
|
|
176
|
+
const cookieCache = cookieCacheOn(block);
|
|
177
|
+
// On a till network's plain http: base URL (`profile.insecureLan`), the ranges it
|
|
178
|
+
// is served on: Better Auth's logger warns of them when it starts.
|
|
179
|
+
const servedOnLan = kioskSettings === undefined
|
|
180
|
+
? undefined
|
|
181
|
+
: refuseKioskOptions(block, plugins, cookieCache, writtenBase, "betterAuth.baseURL", kioskSettings.insecureLan);
|
|
182
|
+
// Better Auth's database adapter, once Better Auth is built: the registry stores
|
|
183
|
+
// its tables through it, whichever adapter the app gave Better Auth.
|
|
184
|
+
const registryStore = registryOn
|
|
185
|
+
? createRegistry(async () => (await instance().$context).adapter, registrySettings)
|
|
186
|
+
: undefined;
|
|
187
|
+
// The Access server (the registry on) whose rules name a namespace is one of the
|
|
188
|
+
// org's namespaces: it keeps its own beacon, through Better Auth's adapter.
|
|
189
|
+
const beaconStore = registryOn && typeof checked.file.namespace === "string"
|
|
190
|
+
? adapterBeaconStore(async () => (await instance().$context).adapter)
|
|
191
|
+
: undefined;
|
|
192
|
+
const schema = {
|
|
193
|
+
...(registryStore === undefined ? {} : registrySchema),
|
|
194
|
+
...(beaconStore === undefined ? {} : beaconSchema),
|
|
195
|
+
...(auditTo?.kind === "table"
|
|
196
|
+
? kioskSettings === undefined
|
|
197
|
+
? auditSchema
|
|
198
|
+
: kioskAuditSchema
|
|
199
|
+
: {}),
|
|
200
|
+
...(kioskSettings === undefined ? {} : kioskSchema),
|
|
201
|
+
};
|
|
202
|
+
// The requests `access.client`'s calls build, each standing for the caller's: the
|
|
203
|
+
// Access plugin runs Better Auth's router origin check on them (a direct API call
|
|
204
|
+
// skips the router).
|
|
205
|
+
const clientCalls = new WeakSet();
|
|
206
|
+
const claimsFor = (source) => issuedClaims(source, claims, claimsOf);
|
|
207
|
+
// The kiosk profile's routes and its hook: PINs hashed with argon2id at the
|
|
208
|
+
// `passwords` profile, whatever hashes the app's passwords.
|
|
209
|
+
const kiosk = kioskSettings === undefined
|
|
210
|
+
? undefined
|
|
211
|
+
: kioskPlugin({
|
|
212
|
+
settings: kioskSettings,
|
|
213
|
+
endpoint: modules.createAuthEndpoint,
|
|
214
|
+
serverOnly: modules.createAuthEndpoint.serverOnly,
|
|
215
|
+
middleware: modules.createAuthMiddleware,
|
|
216
|
+
refusal: modules.APIError,
|
|
217
|
+
getSessionFromCtx: modules.getSessionFromCtx,
|
|
218
|
+
cookies: modules.cookies,
|
|
219
|
+
oauthState: modules.getOAuthState,
|
|
220
|
+
pins: pinHasherOf(passwords, modules, async () => await instance().$context, PIN_LENGTH.max),
|
|
221
|
+
claimsFor: claimsFor,
|
|
222
|
+
auditLog,
|
|
223
|
+
secureDevice: issuer.startsWith("https:"),
|
|
224
|
+
});
|
|
225
|
+
const watch = sessionWatch({
|
|
226
|
+
kind,
|
|
227
|
+
auditLog,
|
|
228
|
+
modules,
|
|
229
|
+
plugins,
|
|
230
|
+
...(kiosk === undefined
|
|
231
|
+
? {}
|
|
232
|
+
: {
|
|
233
|
+
sessionCreating: kiosk.sessionCreating,
|
|
234
|
+
sessionCreated: kiosk.sessionCreated,
|
|
235
|
+
}),
|
|
236
|
+
});
|
|
237
|
+
const NO_HOOKS = [];
|
|
238
|
+
const watchedBefore = watch.hooks === undefined ? NO_HOOKS : watch.hooks.before;
|
|
239
|
+
const watchedAfter = watch.hooks === undefined ? NO_HOOKS : watch.hooks.after;
|
|
240
|
+
const accessPlugin = {
|
|
241
|
+
id: "aventara-access",
|
|
242
|
+
...(Object.keys(schema).length === 0 ? {} : { schema }),
|
|
243
|
+
// A push's key is checked before Better Auth reads its body, on any mount.
|
|
244
|
+
...(registryStore === undefined
|
|
245
|
+
? {}
|
|
246
|
+
: { onRequest: registryOnRequest(registryStore) }),
|
|
247
|
+
endpoints: {
|
|
248
|
+
...(registryStore === undefined
|
|
249
|
+
? {}
|
|
250
|
+
: registryEndpoints(registryStore, modules.createAuthEndpoint)),
|
|
251
|
+
...meEndpoint(modules.createAuthEndpoint,
|
|
252
|
+
// An agent's access token opens nothing over HTTP but the MCP endpoint: the
|
|
253
|
+
// route answers it `null`. `access.client.verbs.me` below answers it, for the
|
|
254
|
+
// MCP `me` tool, marked for `agentOf`.
|
|
255
|
+
async (headers, request) => meOf(await identityOf(headers, request))),
|
|
256
|
+
...(kiosk === undefined ? {} : kiosk.endpoints),
|
|
257
|
+
},
|
|
258
|
+
...(servedOnLan === undefined
|
|
259
|
+
? watch.init === undefined
|
|
260
|
+
? {}
|
|
261
|
+
: { init: watch.init }
|
|
262
|
+
: {
|
|
263
|
+
init: (context) => {
|
|
264
|
+
context.logger.warn(`Aventara Access: the kiosk profile is served on ${issuer}, plain http:, under \`profile.insecureLan\` (${servedOnLan.map((range) => range.cidr).join(", ")}). Device credentials, PIN sessions and PINs cross that network in the clear: keep it to the tills alone (a router of their own, WPA3, no guest devices), and run nothing else on the server's address, since cookies are not kept apart by port.`);
|
|
265
|
+
return watch.init?.(context);
|
|
266
|
+
},
|
|
267
|
+
}),
|
|
268
|
+
hooks: {
|
|
269
|
+
before: [
|
|
270
|
+
{
|
|
271
|
+
matcher: (context) => typeof context?.request === "object" &&
|
|
272
|
+
context.request !== null &&
|
|
273
|
+
clientCalls.has(context.request),
|
|
274
|
+
handler: modules.originCheckMiddleware,
|
|
275
|
+
},
|
|
276
|
+
...(oauth === undefined ? [] : [pkceGuard(modules)]),
|
|
277
|
+
...watchedBefore,
|
|
278
|
+
...(kiosk === undefined ? [] : kiosk.hooks.before),
|
|
279
|
+
],
|
|
280
|
+
after: [
|
|
281
|
+
...(rehash === undefined ? [] : [rehash]),
|
|
282
|
+
...watchedAfter,
|
|
283
|
+
...(kiosk === undefined ? [] : kiosk.hooks.after),
|
|
284
|
+
],
|
|
285
|
+
},
|
|
286
|
+
};
|
|
287
|
+
const effective = {
|
|
288
|
+
...block,
|
|
289
|
+
...(emailAndPassword === undefined ? {} : { emailAndPassword }),
|
|
290
|
+
plugins: [
|
|
291
|
+
...plugins,
|
|
292
|
+
modules.jwt({
|
|
293
|
+
// A PIN session gets no token (below), so `/get-session` hands out none
|
|
294
|
+
// beside any session on the kiosk profile; `GET /token` still does for a
|
|
295
|
+
// session opened with full credentials.
|
|
296
|
+
...(kind === "kiosk" ? { disableSettingJwtHeader: true } : {}),
|
|
297
|
+
jwt: {
|
|
298
|
+
issuer,
|
|
299
|
+
audience: issuer,
|
|
300
|
+
expirationTime: `${tokenTtl}s`,
|
|
301
|
+
definePayload: async (source) => {
|
|
302
|
+
// A session on a kiosk device is bound to it: a token would carry
|
|
303
|
+
// it anywhere, past the device's lock.
|
|
304
|
+
if (typeof source.session.kioskDeviceId === "string") {
|
|
305
|
+
throw new modules.APIError("FORBIDDEN", {
|
|
306
|
+
code: "KIOSK_SESSION_NOT_ALLOWED",
|
|
307
|
+
message: "A session bound to a kiosk device is not issued a token.",
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
if (cookieCache) {
|
|
311
|
+
await sessionStillLive(() => instance().$context, source.session, () => new modules.APIError("UNAUTHORIZED", {
|
|
312
|
+
message: "The session has ended.",
|
|
313
|
+
}));
|
|
314
|
+
}
|
|
315
|
+
return claimsFor(source);
|
|
316
|
+
},
|
|
317
|
+
},
|
|
318
|
+
}),
|
|
319
|
+
accessPlugin,
|
|
320
|
+
],
|
|
321
|
+
};
|
|
322
|
+
// Better Auth's tables as it is built (its plugins' fields included): a declared
|
|
323
|
+
// claim the default mapping reads must come from a field the user cannot set, and
|
|
324
|
+
// the rules' schema names each table (on the Prisma adapter, the models it reads;
|
|
325
|
+
// on any other, the app's `authTables`).
|
|
326
|
+
const facts = betterAuthTablesFor({
|
|
327
|
+
options: effective,
|
|
328
|
+
modules,
|
|
329
|
+
checked,
|
|
330
|
+
resources: opened,
|
|
331
|
+
});
|
|
332
|
+
// The engine the framework asks, with Access's built-in rules over Better Auth's
|
|
333
|
+
// tables. Built on the first read of `access.policy`, which is the framework's
|
|
334
|
+
// construction: a `resources` key whose tables are missing refuses the app's
|
|
335
|
+
// start, while a tool that reads only `access.options` (`npx auth generate`,
|
|
336
|
+
// before the schema has the tables) loads the configuration.
|
|
337
|
+
let guarded;
|
|
338
|
+
const policyOf = () => {
|
|
339
|
+
guarded ??= guardedPolicy({
|
|
340
|
+
checked,
|
|
341
|
+
auditLog,
|
|
342
|
+
resources: opened,
|
|
343
|
+
tables: facts.tables,
|
|
344
|
+
naming: facts.naming,
|
|
345
|
+
});
|
|
346
|
+
return guarded;
|
|
347
|
+
};
|
|
348
|
+
let auth;
|
|
349
|
+
const instance = () => {
|
|
350
|
+
auth ??= modules.betterAuth(effective);
|
|
351
|
+
return auth;
|
|
352
|
+
};
|
|
353
|
+
const keys = async () => (await instance().api.getJwks());
|
|
354
|
+
const tokensFor = (resource) => createAccessTokenVerifier({
|
|
355
|
+
keys,
|
|
356
|
+
issuer,
|
|
357
|
+
resource,
|
|
358
|
+
userInfo: userInfoAudience(block, modules),
|
|
359
|
+
context: async () => await instance().$context,
|
|
360
|
+
claimsFor,
|
|
361
|
+
});
|
|
362
|
+
const agents = checkedMcp === undefined ? undefined : tokensFor(checkedMcp.resource);
|
|
363
|
+
const ownTokens = ownAudience === undefined ? undefined : tokensFor(ownAudience);
|
|
364
|
+
const identityOf = requestIdentity({
|
|
365
|
+
auth: instance,
|
|
366
|
+
verifier: createTokenVerifier({
|
|
367
|
+
claims,
|
|
368
|
+
keys,
|
|
369
|
+
issuer,
|
|
370
|
+
tokenTtl,
|
|
371
|
+
}),
|
|
372
|
+
...(agents === undefined ? {} : { agents }),
|
|
373
|
+
...(ownTokens === undefined ? {} : { audience: ownTokens }),
|
|
374
|
+
kind,
|
|
375
|
+
crossSite,
|
|
376
|
+
claimsFor,
|
|
377
|
+
});
|
|
378
|
+
const state = requestState(identityOf, checked.principal);
|
|
379
|
+
const client = accessClient({
|
|
380
|
+
block,
|
|
381
|
+
kind,
|
|
382
|
+
claims,
|
|
383
|
+
baseOf: modules.getBaseURL,
|
|
384
|
+
isDynamicBaseURL: modules.isDynamicBaseURLConfig,
|
|
385
|
+
// Read untyped: Better Auth's API type is the app's, and `call` names its endpoints itself.
|
|
386
|
+
api: () => instance().api,
|
|
387
|
+
identityOf: async (headers, request) => verbMeOf(await identityOf(headers, request)),
|
|
388
|
+
calls: clientCalls,
|
|
389
|
+
refusal: modules.APIError,
|
|
390
|
+
identify: signInIdentifier(plugins),
|
|
391
|
+
context: () => instance()
|
|
392
|
+
.$context,
|
|
393
|
+
limit: verbRateLimiter({
|
|
394
|
+
context: async () => (await instance().$context),
|
|
395
|
+
ipOf: modules.getIP,
|
|
396
|
+
refusal: modules.APIError,
|
|
397
|
+
auditLog,
|
|
398
|
+
}),
|
|
399
|
+
});
|
|
400
|
+
const access = {
|
|
401
|
+
client,
|
|
402
|
+
// On the service profile, the handler's own last step: no session cookie
|
|
403
|
+
// leaves, whatever plugin or route set it.
|
|
404
|
+
handler: kind === "service"
|
|
405
|
+
? async (request) => withoutSessionCookies(await instance().handler(request), sessionCookies((await instance().$context)))
|
|
406
|
+
: (request) => instance().handler(request),
|
|
407
|
+
options: effective,
|
|
408
|
+
$Infer: Object.freeze({}),
|
|
409
|
+
...(registryStore === undefined
|
|
410
|
+
? {}
|
|
411
|
+
: { registry: Object.freeze({ ...registryStore.operator }) }),
|
|
412
|
+
...(kiosk === undefined
|
|
413
|
+
? {}
|
|
414
|
+
: {
|
|
415
|
+
kiosk: Object.freeze(kiosk.operator(async () => (await instance().$context))),
|
|
416
|
+
}),
|
|
417
|
+
...(beaconStore === undefined
|
|
418
|
+
? {}
|
|
419
|
+
: { beacon: Object.freeze(beaconStore) }),
|
|
420
|
+
...(agents === undefined || server === undefined
|
|
421
|
+
? {}
|
|
422
|
+
: { mcp: mcpAuthorizationOf(agents, server) }),
|
|
423
|
+
state,
|
|
424
|
+
};
|
|
425
|
+
// `api` is read on use: reading it builds Better Auth. Not enumerable, so a walk
|
|
426
|
+
// over the instance (a configuration check, a log line) builds nothing.
|
|
427
|
+
Object.defineProperty(access, "api", {
|
|
428
|
+
get: () => instance().api,
|
|
429
|
+
enumerable: false,
|
|
430
|
+
});
|
|
431
|
+
// `policy` is built on first read, with the built-in rules over Better Auth's
|
|
432
|
+
// tables; not enumerable either, so a tool that loads the configuration and walks
|
|
433
|
+
// it (`npx auth generate`, which merges what the module exports) runs no startup
|
|
434
|
+
// check. The framework reads it by name.
|
|
435
|
+
Object.defineProperty(access, "policy", {
|
|
436
|
+
get: policyOf,
|
|
437
|
+
enumerable: false,
|
|
438
|
+
});
|
|
439
|
+
return access;
|
|
440
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { type LanRange } from "../kiosk/lan-range.policy.js";
|
|
2
|
+
import type { BetterAuthModules } from "./better-auth.loader.js";
|
|
3
|
+
/** Better Auth's options, as the checks read them: any object. */
|
|
4
|
+
export type BetterAuthBlock = {
|
|
5
|
+
readonly [key: string]: unknown;
|
|
6
|
+
};
|
|
7
|
+
/** The id of the Access plugin: `aventaraAccess()`, or the one `createAccess` installs. */
|
|
8
|
+
export declare const ACCESS_PLUGIN_ID = "aventara-access";
|
|
9
|
+
/** The id of Better Auth's `jwt()` plugin. */
|
|
10
|
+
export declare const JWT_PLUGIN_ID = "jwt";
|
|
11
|
+
/** A plugin id as Better Auth's checks could take it: no case, no surrounding space. */
|
|
12
|
+
export declare const normalisedId: (id: unknown) => string | undefined;
|
|
13
|
+
/** How a refusal names the one that installs the plugins it guards. */
|
|
14
|
+
type PluginInstaller = {
|
|
15
|
+
/** Who installs them, as the sentence names it: `createAccess`, `aventaraAccess()`. */
|
|
16
|
+
readonly by: string;
|
|
17
|
+
/** Where the app put the plugin, as the sentence names it: `betterAuth.plugins`, `plugins`. */
|
|
18
|
+
readonly at: string;
|
|
19
|
+
/** The plugins it installs, by id, as a sentence names each. */
|
|
20
|
+
readonly installs: {
|
|
21
|
+
readonly [id: string]: string;
|
|
22
|
+
};
|
|
23
|
+
/** The one plugin of the list that is the installer's own (`aventaraAccess()` in its own list), skipped. */
|
|
24
|
+
readonly own?: unknown;
|
|
25
|
+
/** The installer serves Access's own `me` route (`createAccess`): a plugin defining it is refused too. */
|
|
26
|
+
readonly me?: boolean;
|
|
27
|
+
/** The installer serves the kiosk profile's routes: a plugin defining one (`/kiosk/…`) is refused too. */
|
|
28
|
+
readonly kiosk?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* The installer serves the registry (`registry: { enabled: true }`): a plugin
|
|
31
|
+
* defining one of its routes, or a middleware whose path reaches them, is refused
|
|
32
|
+
* too. Other plugins' `onRequest` and `hooks` run in the app's own process, inside
|
|
33
|
+
* its trust boundary, and are not checked.
|
|
34
|
+
*/
|
|
35
|
+
readonly registry?: boolean;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* The plugins of a Better Auth configuration, refusing one the installer puts in
|
|
39
|
+
* itself (under any case or spacing of its id) and one that defines `jwt()`'s
|
|
40
|
+
* endpoints. `ACCESS_PLUGIN_DUPLICATE`, with a sentence naming the plugin.
|
|
41
|
+
*/
|
|
42
|
+
export declare const refuseInstalledPlugins: (plugins: unknown, installer: PluginInstaller) => readonly unknown[];
|
|
43
|
+
/**
|
|
44
|
+
* The issuer and audience of every token: the origin of Better Auth's base URL,
|
|
45
|
+
* fixed when Access starts, as Better Auth resolves it (`baseURL`, else its
|
|
46
|
+
* environment variables, `BETTER_AUTH_URL` first), or a dynamic `baseURL`'s
|
|
47
|
+
* `fallback`. Better Auth's own default follows the request's host when the base URL
|
|
48
|
+
* is dynamic or unset; a fixed one keeps a token from one host or app from passing
|
|
49
|
+
* as another's.
|
|
50
|
+
*/
|
|
51
|
+
export declare const issuerOf: (block: BetterAuthBlock, modules: Pick<BetterAuthModules, "getBaseURL" | "isDynamicBaseURLConfig">, baseURLAt: string) => string;
|
|
52
|
+
/** Better Auth's base URL as {@link issuerOf} resolves it, as it was written (before the URL parser reads it). */
|
|
53
|
+
export declare const baseURLOf: (block: BetterAuthBlock, modules: Pick<BetterAuthModules, "getBaseURL" | "isDynamicBaseURLConfig">, baseURLAt: string) => string;
|
|
54
|
+
/**
|
|
55
|
+
* Whether the session cookie is `sameSite: "none"`: what Better Auth sets it with,
|
|
56
|
+
* `advanced.cookies.session_token.attributes` over `advanced.defaultCookieAttributes`.
|
|
57
|
+
* Refuses it when Better Auth trusts no origin: a session cookie a browser sends
|
|
58
|
+
* from any site is read only from the origins Better Auth trusts, so there must be
|
|
59
|
+
* some.
|
|
60
|
+
*/
|
|
61
|
+
export declare const crossSiteSessionCookie: (block: BetterAuthBlock, trustedOriginsAt: string) => boolean;
|
|
62
|
+
/** Whether Better Auth's cookie cache is on: a session read from its cookie may have been revoked since. */
|
|
63
|
+
export declare const cookieCacheOn: (block: BetterAuthBlock) => boolean;
|
|
64
|
+
/**
|
|
65
|
+
* The kiosk profile's refusals of Better Auth's options, each a way around the
|
|
66
|
+
* device binding of a session:
|
|
67
|
+
*
|
|
68
|
+
* - the cookie cache: a session the device's lock ended would still be answered
|
|
69
|
+
* from its cookie;
|
|
70
|
+
* - `secondaryStorage` without `session.storeSessionInDatabase`: a device's sessions
|
|
71
|
+
* must be found in the database to be ended;
|
|
72
|
+
* - `bearer()`: it hands every session's token to page code (`set-auth-token`) and
|
|
73
|
+
* reads it back from `Authorization`, where no device credential goes with it;
|
|
74
|
+
* - `multiSession()`: it keeps every session the browser signed into and switches
|
|
75
|
+
* back to one by its token, so a cashier would restore the manager before them;
|
|
76
|
+
* - `crossSubDomainCookies` and `SameSite=None`: the device's credential and the
|
|
77
|
+
* session would be sent to other hosts, or from other sites;
|
|
78
|
+
* - a plain http: base URL but on a loopback host, or (`profile.insecureLan`) on an
|
|
79
|
+
* IPv4 address inside one of the till network's ranges: the device's credential
|
|
80
|
+
* and the sessions would cross the network in the clear. On such a LAN address no
|
|
81
|
+
* cookie may be `Secure` (or named `__Secure-` or `__Host-`): a browser drops it
|
|
82
|
+
* over http, and the till would silently hold no session.
|
|
83
|
+
*
|
|
84
|
+
* Answers the ranges an http: base URL is served on under `profile.insecureLan`,
|
|
85
|
+
* for the startup warning; `undefined` when it is https: or loopback.
|
|
86
|
+
*/
|
|
87
|
+
export declare const refuseKioskOptions: (block: BetterAuthBlock, plugins: readonly unknown[], cookieCache: boolean,
|
|
88
|
+
/** The app's base URL as written (`baseURLOf`), and where the app set it. */
|
|
89
|
+
written: string, baseURLAt: string,
|
|
90
|
+
/** `profile.insecureLan`, read. */
|
|
91
|
+
insecureLan: readonly LanRange[] | undefined) => readonly LanRange[] | undefined;
|
|
92
|
+
/**
|
|
93
|
+
* Better Auth's Prisma adapter's naming, when `database` is that adapter: read from
|
|
94
|
+
* the adapter the factory builds (its id, and `usePlural`). Building it touches no
|
|
95
|
+
* database, and Better Auth builds its own from the factory again when it starts,
|
|
96
|
+
* with its own options, so this one leaves nothing behind.
|
|
97
|
+
*/
|
|
98
|
+
export declare const prismaAdapterOf: (database: unknown, options: unknown) => {
|
|
99
|
+
readonly usePlural: boolean;
|
|
100
|
+
} | undefined;
|
|
101
|
+
/** The organization plugin among `plugins`, with its options; `undefined` when it is not installed. */
|
|
102
|
+
export declare const organizationPluginOf: (plugins: readonly unknown[]) => {
|
|
103
|
+
readonly options: BetterAuthBlock;
|
|
104
|
+
} | undefined;
|
|
105
|
+
/**
|
|
106
|
+
* Refuses an organization plugin whose invitations a session with an unverified
|
|
107
|
+
* email may accept, when Access trusts its memberships (`reads` says how).
|
|
108
|
+
*
|
|
109
|
+
* Better Auth's advisory GHSA-fmh4-wcc4-5jm3: from better-auth 1.6.14 on, with
|
|
110
|
+
* Better Auth's own invitation ids, `acceptInvitation` takes a session whose email
|
|
111
|
+
* matches the invitation's and is not verified, unless the organization plugin sets
|
|
112
|
+
* `requireEmailVerificationOnInvitation: true`. Anyone who signs up with the invited
|
|
113
|
+
* address first and learns the invitation's id (a forwarded email, an admin screen,
|
|
114
|
+
* an invitation list) joins at the invited role. Better Auth ships no fix (the
|
|
115
|
+
* advisory lists `>= 1.6.14` with none; the GitHub advisory database's entry still
|
|
116
|
+
* says `< 1.6.11` only), so Access refuses to trust a membership the plugin let in
|
|
117
|
+
* that way. Fail closed: only `true`, given explicitly, passes.
|
|
118
|
+
*/
|
|
119
|
+
export declare const refuseUnverifiedInvitations: (plugins: readonly unknown[], reads: string) => void;
|
|
120
|
+
export {};
|