@lunora/auth 1.0.0-alpha.37 → 1.0.0-alpha.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter.mjs +1 -48
- package/dist/audit.mjs +2 -102
- package/dist/email-guard.mjs +1 -71
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +1 -16
- package/dist/middleware.d.mts +1 -1
- package/dist/middleware.d.ts +1 -1
- package/dist/middleware.mjs +1 -56
- package/dist/packem_shared/DEFAULT_AUTH_BASE_PATH-kIwlEt8i.mjs +1 -0
- package/dist/packem_shared/LunoraAuthAdminError-BiNYZM9j.mjs +1 -0
- package/dist/packem_shared/authAuditHook-Dx3sqf3G.mjs +1 -0
- package/dist/packem_shared/compileMigrationsSql-ChiudSmt.mjs +1 -0
- package/dist/packem_shared/{create-auth.d-COcIS_KU.d.mts → create-auth.d-De6IOirt.d.mts} +1 -1
- package/dist/packem_shared/{create-auth.d-COcIS_KU.d.ts → create-auth.d-De6IOirt.d.ts} +1 -1
- package/dist/packem_shared/createAuth-DS6PL8Mb.mjs +1 -0
- package/dist/packem_shared/emailGateDatabaseHooks-DzBD1Qoq.mjs +1 -0
- package/dist/packem_shared/sessionPresets-DpEFjXKV.mjs +1 -0
- package/dist/plugins-client.mjs +1 -2
- package/dist/plugins.mjs +1 -22
- package/dist/schema.d.mts +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/schema.mjs +1 -62
- package/dist/sql-store.mjs +1 -184
- package/dist/store.mjs +1 -183
- package/dist/turnstile-middleware.mjs +1 -34
- package/dist/turnstile.mjs +1 -59
- package/package.json +2 -2
- package/dist/packem_shared/DEFAULT_AUTH_BASE_PATH-DjcUWEQl.mjs +0 -11
- package/dist/packem_shared/LunoraAuthAdminError-CReJPMkx.mjs +0 -513
- package/dist/packem_shared/authAuditHook-3OJKhpQV.mjs +0 -119
- package/dist/packem_shared/compileMigrationsSql-Dl5N8z5q.mjs +0 -29
- package/dist/packem_shared/createAuth-s4i7WhAh.mjs +0 -72
- package/dist/packem_shared/emailGateDatabaseHooks-BGS4uJM9.mjs +0 -64
- package/dist/packem_shared/sessionPresets-Dwwd74_J.mjs +0 -38
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { LunoraError } from '@lunora/errors';
|
|
2
|
-
import { betterAuth } from 'better-auth';
|
|
3
|
-
import { validateSessionPolicy } from './sessionPresets-Dwwd74_J.mjs';
|
|
4
|
-
|
|
5
|
-
const MIN_SECRET_LENGTH = 32;
|
|
6
|
-
const isWeakSecret = (secret) => {
|
|
7
|
-
const trimmedLength = typeof secret === "string" ? secret.trim().length : 0;
|
|
8
|
-
return trimmedLength > 0 && trimmedLength < MIN_SECRET_LENGTH;
|
|
9
|
-
};
|
|
10
|
-
const isExplicitHttpBaseUrl = (baseURL) => {
|
|
11
|
-
if (typeof baseURL === "string") {
|
|
12
|
-
return baseURL.toLowerCase().startsWith("http://");
|
|
13
|
-
}
|
|
14
|
-
if (baseURL && typeof baseURL === "object") {
|
|
15
|
-
if (baseURL.protocol === "http") {
|
|
16
|
-
return true;
|
|
17
|
-
}
|
|
18
|
-
if (baseURL.protocol === "https") {
|
|
19
|
-
return false;
|
|
20
|
-
}
|
|
21
|
-
return typeof baseURL.fallback === "string" && baseURL.fallback.toLowerCase().startsWith("http://");
|
|
22
|
-
}
|
|
23
|
-
return false;
|
|
24
|
-
};
|
|
25
|
-
const hardenAuthOptions = (options) => {
|
|
26
|
-
if (isWeakSecret(options.secret)) {
|
|
27
|
-
const message = `@lunora/auth: AUTH_SECRET is only ${String(options.secret?.trim().length)} characters. Use at least ${String(MIN_SECRET_LENGTH)} for a brute-force-resistant secret — generate one with \`openssl rand -hex 32\`.`;
|
|
28
|
-
if (!isExplicitHttpBaseUrl(options.baseURL)) {
|
|
29
|
-
throw new LunoraError("INTERNAL", message);
|
|
30
|
-
}
|
|
31
|
-
console.warn(message);
|
|
32
|
-
}
|
|
33
|
-
const advanced = options.advanced ?? {};
|
|
34
|
-
return {
|
|
35
|
-
...options,
|
|
36
|
-
advanced: {
|
|
37
|
-
...advanced,
|
|
38
|
-
defaultCookieAttributes: advanced.defaultCookieAttributes ?? { httpOnly: true, path: "/", sameSite: "lax" },
|
|
39
|
-
...advanced.useSecureCookies === void 0 ? { useSecureCookies: !isExplicitHttpBaseUrl(options.baseURL) } : {}
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
};
|
|
43
|
-
const resolveAuthOptions = (options) => {
|
|
44
|
-
const hardened = hardenAuthOptions(options);
|
|
45
|
-
const needsRateLimitEnabled = hardened.rateLimit?.enabled === void 0;
|
|
46
|
-
const needsRateLimitStorage = hardened.rateLimit?.storage === void 0 && hardened.rateLimit?.enabled !== false;
|
|
47
|
-
return {
|
|
48
|
-
...hardened,
|
|
49
|
-
...needsRateLimitEnabled || needsRateLimitStorage ? {
|
|
50
|
-
rateLimit: {
|
|
51
|
-
...hardened.rateLimit,
|
|
52
|
-
...needsRateLimitEnabled ? { enabled: true } : {},
|
|
53
|
-
...needsRateLimitStorage ? { storage: "database" } : {}
|
|
54
|
-
}
|
|
55
|
-
} : {},
|
|
56
|
-
...hardened.session?.cookieCache === void 0 ? { session: { ...hardened.session, cookieCache: { enabled: true, maxAge: 60 } } } : {}
|
|
57
|
-
};
|
|
58
|
-
};
|
|
59
|
-
const createAuth = (options) => {
|
|
60
|
-
if (!options.secret || options.secret.trim() === "") {
|
|
61
|
-
throw new LunoraError(
|
|
62
|
-
"INTERNAL",
|
|
63
|
-
'@lunora/auth: `secret` is required. Set AUTH_SECRET locally in .dev.vars (`lunora env set AUTH_SECRET "$(openssl rand -hex 32)"`), and in production with `wrangler secret put AUTH_SECRET`.'
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
if (options.session) {
|
|
67
|
-
validateSessionPolicy(options.session);
|
|
68
|
-
}
|
|
69
|
-
return betterAuth(resolveAuthOptions(options));
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
export { createAuth, resolveAuthOptions };
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { LunoraError } from '@lunora/errors';
|
|
2
|
-
import { APIError } from 'better-auth/api';
|
|
3
|
-
import { assertEmailAllowed } from '../email-guard.mjs';
|
|
4
|
-
|
|
5
|
-
const statusString = (status) => {
|
|
6
|
-
switch (status) {
|
|
7
|
-
case 400: {
|
|
8
|
-
return "BAD_REQUEST";
|
|
9
|
-
}
|
|
10
|
-
case 422: {
|
|
11
|
-
return "UNPROCESSABLE_ENTITY";
|
|
12
|
-
}
|
|
13
|
-
case 429: {
|
|
14
|
-
return "TOO_MANY_REQUESTS";
|
|
15
|
-
}
|
|
16
|
-
default: {
|
|
17
|
-
return "INTERNAL_SERVER_ERROR";
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
const buildBeforeHook = (config) => async (user, context) => {
|
|
22
|
-
const email = typeof user.email === "string" ? user.email : void 0;
|
|
23
|
-
if (email === void 0 || email === "") {
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
let classification;
|
|
27
|
-
try {
|
|
28
|
-
classification = await assertEmailAllowed(email, config);
|
|
29
|
-
} catch (error) {
|
|
30
|
-
if (error instanceof LunoraError) {
|
|
31
|
-
throw new APIError(statusString(error.status), { code: error.code, message: error.message });
|
|
32
|
-
}
|
|
33
|
-
throw error;
|
|
34
|
-
}
|
|
35
|
-
config.onClassify?.(classification, user, context);
|
|
36
|
-
};
|
|
37
|
-
const emailGateDatabaseHooks = (config = {}) => {
|
|
38
|
-
return {
|
|
39
|
-
user: { create: { before: buildBeforeHook(config) } }
|
|
40
|
-
};
|
|
41
|
-
};
|
|
42
|
-
const withEmailGate = (options, config = {}) => {
|
|
43
|
-
const gate = buildBeforeHook(config);
|
|
44
|
-
const existing = options.databaseHooks?.user?.create?.before;
|
|
45
|
-
const before = existing ? async (user, context) => {
|
|
46
|
-
await gate(user, context);
|
|
47
|
-
return existing(user, context);
|
|
48
|
-
} : gate;
|
|
49
|
-
return {
|
|
50
|
-
...options,
|
|
51
|
-
databaseHooks: {
|
|
52
|
-
...options.databaseHooks,
|
|
53
|
-
user: {
|
|
54
|
-
...options.databaseHooks?.user,
|
|
55
|
-
create: {
|
|
56
|
-
...options.databaseHooks?.user?.create,
|
|
57
|
-
before
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
export { emailGateDatabaseHooks, withEmailGate };
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
const MINUTE = 60;
|
|
2
|
-
const HOUR = 60 * MINUTE;
|
|
3
|
-
const DAY = 24 * HOUR;
|
|
4
|
-
const validateSessionPolicy = (policy) => {
|
|
5
|
-
const durationFields = ["expiresIn", "updateAge", "freshAge"];
|
|
6
|
-
for (const field of durationFields) {
|
|
7
|
-
const value = policy[field];
|
|
8
|
-
if (value === void 0) {
|
|
9
|
-
continue;
|
|
10
|
-
}
|
|
11
|
-
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
|
|
12
|
-
throw new TypeError(`@lunora/auth: \`session.${field}\` must be a non-negative, finite number of seconds`);
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
return policy;
|
|
16
|
-
};
|
|
17
|
-
const sessionPresets = {
|
|
18
|
-
longLived: {
|
|
19
|
-
cookieCache: { enabled: true, maxAge: 60 },
|
|
20
|
-
expiresIn: 30 * DAY,
|
|
21
|
-
freshAge: DAY,
|
|
22
|
-
updateAge: DAY
|
|
23
|
-
},
|
|
24
|
-
rolling: {
|
|
25
|
-
cookieCache: { enabled: true, maxAge: 60 },
|
|
26
|
-
expiresIn: 7 * DAY,
|
|
27
|
-
freshAge: DAY,
|
|
28
|
-
updateAge: DAY
|
|
29
|
-
},
|
|
30
|
-
strict: {
|
|
31
|
-
cookieCache: { enabled: false },
|
|
32
|
-
expiresIn: HOUR,
|
|
33
|
-
freshAge: 5 * MINUTE,
|
|
34
|
-
updateAge: 15 * MINUTE
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export { sessionPresets, validateSessionPolicy };
|