@better-auth/infra 0.2.3 → 0.2.5
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/index.d.mts +4 -7
- package/dist/index.mjs +93 -18
- package/package.json +7 -4
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EMAIL_TEMPLATES, EmailConfig, EmailTemplateId, EmailTemplateVariables, SendBulkEmailsOptions, SendBulkEmailsResult, SendEmailOptions, SendEmailResult, createEmailSender, sendBulkEmails, sendEmail } from "./email.mjs";
|
|
2
2
|
import * as _$better_auth0 from "better-auth";
|
|
3
|
-
import { Account, AuthContext, BetterAuthPlugin, GenericEndpointContext,
|
|
3
|
+
import { Account, AuthContext, BetterAuthPlugin, GenericEndpointContext, Session, User } from "better-auth";
|
|
4
4
|
import * as _$jose from "jose";
|
|
5
5
|
import * as zod from "zod";
|
|
6
6
|
import z$1 from "zod";
|
|
@@ -170,9 +170,6 @@ interface SecurityEvent {
|
|
|
170
170
|
}
|
|
171
171
|
type SecurityEventType = "unknown_device" | "credential_stuffing" | "impossible_travel" | "geo_blocked" | "bot_blocked" | "suspicious_ip_detected" | "velocity_exceeded" | "free_trial_abuse" | "compromised_password" | "stale_account_reactivation";
|
|
172
172
|
//#endregion
|
|
173
|
-
//#region src/validation/matchers.d.ts
|
|
174
|
-
type Matcher = (context: HookEndpointContext) => boolean;
|
|
175
|
-
//#endregion
|
|
176
173
|
//#region src/sentinel/sentinel.d.ts
|
|
177
174
|
declare const sentinel: (options?: SentinelOptions) => {
|
|
178
175
|
id: "sentinel";
|
|
@@ -249,7 +246,7 @@ declare const sentinel: (options?: SentinelOptions) => {
|
|
|
249
246
|
};
|
|
250
247
|
hooks: {
|
|
251
248
|
before: ({
|
|
252
|
-
matcher:
|
|
249
|
+
matcher: (context: _$better_auth0.HookEndpointContext) => boolean;
|
|
253
250
|
handler: (inputContext: _$better_call0.MiddlewareInputContext<_$better_call0.MiddlewareOptions>) => Promise<{
|
|
254
251
|
context: {
|
|
255
252
|
method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
|
|
@@ -421,7 +418,7 @@ declare const sentinel: (options?: SentinelOptions) => {
|
|
|
421
418
|
};
|
|
422
419
|
} | undefined>;
|
|
423
420
|
} | {
|
|
424
|
-
matcher:
|
|
421
|
+
matcher: (context: _$better_auth0.HookEndpointContext) => boolean;
|
|
425
422
|
handler: (inputContext: _$better_call0.MiddlewareInputContext<_$better_call0.MiddlewareOptions>) => Promise<void>;
|
|
426
423
|
})[];
|
|
427
424
|
after: {
|
|
@@ -729,7 +726,7 @@ interface DashIdRow {
|
|
|
729
726
|
id: string;
|
|
730
727
|
}
|
|
731
728
|
//#endregion
|
|
732
|
-
//#region ../../node_modules/.bun/@better-auth+scim@1.6.
|
|
729
|
+
//#region ../../node_modules/.bun/@better-auth+scim@1.6.4+f772dc2362714ab9/node_modules/@better-auth/scim/dist/index.d.mts
|
|
733
730
|
//#region src/types.d.ts
|
|
734
731
|
interface SCIMProvider {
|
|
735
732
|
id: string;
|
package/dist/index.mjs
CHANGED
|
@@ -1398,7 +1398,7 @@ function createSecurityClient(apiUrl, apiKey, options, onSecurityEvent) {
|
|
|
1398
1398
|
}
|
|
1399
1399
|
//#endregion
|
|
1400
1400
|
//#region src/validation/matchers.ts
|
|
1401
|
-
const
|
|
1401
|
+
const all = new Set([
|
|
1402
1402
|
"/sign-up/email",
|
|
1403
1403
|
"/email-otp/verify-email",
|
|
1404
1404
|
"/sign-in/email-otp",
|
|
@@ -1413,9 +1413,7 @@ const paths = [
|
|
|
1413
1413
|
"/request-password-reset",
|
|
1414
1414
|
"/send-verification-email",
|
|
1415
1415
|
"/change-email"
|
|
1416
|
-
];
|
|
1417
|
-
const all = new Set(paths);
|
|
1418
|
-
new Set(paths.slice(1, 12));
|
|
1416
|
+
]);
|
|
1419
1417
|
/**
|
|
1420
1418
|
* Path is one of `[
|
|
1421
1419
|
* '/sign-up/email',
|
|
@@ -1687,7 +1685,6 @@ function createEmailHooks(options = {}) {
|
|
|
1687
1685
|
emailValidationOptions: emailConfig
|
|
1688
1686
|
}) : void 0, onDisposableEmail)] : []] };
|
|
1689
1687
|
}
|
|
1690
|
-
createEmailHooks();
|
|
1691
1688
|
//#endregion
|
|
1692
1689
|
//#region src/validation/phone.ts
|
|
1693
1690
|
/**
|
|
@@ -2757,10 +2754,76 @@ const jwtValidateMiddleware = (options) => createAuthMiddleware(async (ctx) => {
|
|
|
2757
2754
|
});
|
|
2758
2755
|
//#endregion
|
|
2759
2756
|
//#region src/version.ts
|
|
2760
|
-
const PLUGIN_VERSION = "0.2.
|
|
2757
|
+
const PLUGIN_VERSION = "0.2.5";
|
|
2761
2758
|
//#endregion
|
|
2762
2759
|
//#region src/routes/auth/config.ts
|
|
2763
2760
|
const PLUGIN_OPTIONS_EXCLUDE_KEYS = { stripe: new Set(["stripeClient"]) };
|
|
2761
|
+
const EXACT_SENSITIVE_STRING_KEYS_LOWER = new Set([...new Set([
|
|
2762
|
+
"accessToken",
|
|
2763
|
+
"apiKey",
|
|
2764
|
+
"apiSecret",
|
|
2765
|
+
"authorization",
|
|
2766
|
+
"authToken",
|
|
2767
|
+
"bearerToken",
|
|
2768
|
+
"clientSecret",
|
|
2769
|
+
"consumerSecret",
|
|
2770
|
+
"encPrivateKey",
|
|
2771
|
+
"encPrivateKeyPass",
|
|
2772
|
+
"encryptionKey",
|
|
2773
|
+
"encryptionSecret",
|
|
2774
|
+
"idToken",
|
|
2775
|
+
"password",
|
|
2776
|
+
"privateKey",
|
|
2777
|
+
"privateKeyPass",
|
|
2778
|
+
"refreshToken",
|
|
2779
|
+
"secret",
|
|
2780
|
+
"secretKey",
|
|
2781
|
+
"signingSecret",
|
|
2782
|
+
"stripeWebhookSecret",
|
|
2783
|
+
"webhookSecret"
|
|
2784
|
+
])].map((k) => k.toLowerCase()));
|
|
2785
|
+
/**
|
|
2786
|
+
* Case-insensitive suffixes for unknown plugin options
|
|
2787
|
+
* Matching is more permissive to account for unknown plugin options
|
|
2788
|
+
*/
|
|
2789
|
+
const SENSITIVE_KEY_SUFFIXES_LOWER = [
|
|
2790
|
+
"secret",
|
|
2791
|
+
"password",
|
|
2792
|
+
"passphrase",
|
|
2793
|
+
"privatekey",
|
|
2794
|
+
"keypass",
|
|
2795
|
+
"apikey",
|
|
2796
|
+
"token",
|
|
2797
|
+
"signingkey",
|
|
2798
|
+
"credentials",
|
|
2799
|
+
"authheader"
|
|
2800
|
+
];
|
|
2801
|
+
const REDACTED_SIMPLE_STRING = "[REDACTED]";
|
|
2802
|
+
function snakeCaseToCamelCase(key) {
|
|
2803
|
+
return key.replace(/_([a-zA-Z])/g, (_, ch) => ch.toUpperCase());
|
|
2804
|
+
}
|
|
2805
|
+
function keyVariantsForMatching(key) {
|
|
2806
|
+
const trimmed = key.replace(/^[\s._-]+/, "");
|
|
2807
|
+
if (!trimmed) return [key];
|
|
2808
|
+
const out = new Set([key, trimmed]);
|
|
2809
|
+
if (trimmed.includes("_")) out.add(snakeCaseToCamelCase(trimmed));
|
|
2810
|
+
return [...out];
|
|
2811
|
+
}
|
|
2812
|
+
function shouldRedactSensitiveStringKey(key) {
|
|
2813
|
+
const variants = keyVariantsForMatching(key);
|
|
2814
|
+
const compactLower = key.replace(/[\s._-]/g, "").toLowerCase();
|
|
2815
|
+
const forms = new Set([compactLower]);
|
|
2816
|
+
for (const raw of variants) {
|
|
2817
|
+
forms.add(raw);
|
|
2818
|
+
forms.add(raw.toLowerCase());
|
|
2819
|
+
}
|
|
2820
|
+
for (const form of forms) {
|
|
2821
|
+
const fl = form.toLowerCase();
|
|
2822
|
+
if (EXACT_SENSITIVE_STRING_KEYS_LOWER.has(fl)) return true;
|
|
2823
|
+
for (const suffix of SENSITIVE_KEY_SUFFIXES_LOWER) if (fl.endsWith(suffix)) return true;
|
|
2824
|
+
}
|
|
2825
|
+
return false;
|
|
2826
|
+
}
|
|
2764
2827
|
function isPlainSerializable(value) {
|
|
2765
2828
|
if (value === null || typeof value !== "object") return true;
|
|
2766
2829
|
if (Array.isArray(value)) return true;
|
|
@@ -2769,22 +2832,28 @@ function isPlainSerializable(value) {
|
|
|
2769
2832
|
if (constructor && constructor.name !== "Object" && constructor.name !== "Array") return false;
|
|
2770
2833
|
return true;
|
|
2771
2834
|
}
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2835
|
+
/**
|
|
2836
|
+
* Sanitize any plain JSON-like subtree from Better Auth options
|
|
2837
|
+
*/
|
|
2838
|
+
function sanitizeConfig(value, visiting, excludeKeys) {
|
|
2839
|
+
if (value === null || value === void 0) return value;
|
|
2840
|
+
if (typeof value === "function") return void 0;
|
|
2841
|
+
if (typeof value !== "object") return value;
|
|
2842
|
+
const obj = value;
|
|
2777
2843
|
if (visiting.has(obj)) return void 0;
|
|
2778
2844
|
visiting.add(obj);
|
|
2779
2845
|
try {
|
|
2780
|
-
|
|
2781
|
-
if (Array.isArray(options)) return options.map((item) => sanitizePluginOptions(pluginId, item, visiting)).filter((item) => item !== void 0);
|
|
2846
|
+
if (Array.isArray(value)) return value.map((item) => sanitizeConfig(item, visiting, excludeKeys)).filter((item) => item !== void 0);
|
|
2782
2847
|
const result = {};
|
|
2783
|
-
for (const [key,
|
|
2848
|
+
for (const [key, val] of Object.entries(value)) {
|
|
2784
2849
|
if (excludeKeys?.has(key)) continue;
|
|
2785
|
-
if (typeof
|
|
2786
|
-
if (
|
|
2787
|
-
|
|
2850
|
+
if (typeof val === "function") continue;
|
|
2851
|
+
if (typeof val === "string" && shouldRedactSensitiveStringKey(key)) {
|
|
2852
|
+
result[key] = REDACTED_SIMPLE_STRING;
|
|
2853
|
+
continue;
|
|
2854
|
+
}
|
|
2855
|
+
if (val !== null && typeof val === "object" && !isPlainSerializable(val)) continue;
|
|
2856
|
+
const sanitized = sanitizeConfig(val, visiting, excludeKeys);
|
|
2788
2857
|
if (sanitized !== void 0) result[key] = sanitized;
|
|
2789
2858
|
}
|
|
2790
2859
|
return result;
|
|
@@ -2792,6 +2861,9 @@ function sanitizePluginOptions(pluginId, options, visiting = /* @__PURE__ */ new
|
|
|
2792
2861
|
visiting.delete(obj);
|
|
2793
2862
|
}
|
|
2794
2863
|
}
|
|
2864
|
+
function sanitizePluginOptions(pluginId, options) {
|
|
2865
|
+
return sanitizeConfig(options, /* @__PURE__ */ new WeakSet(), PLUGIN_OPTIONS_EXCLUDE_KEYS[pluginId]);
|
|
2866
|
+
}
|
|
2795
2867
|
function estimateEntropy(str) {
|
|
2796
2868
|
const unique = new Set(str).size;
|
|
2797
2869
|
if (unique === 0) return 0;
|
|
@@ -2807,7 +2879,7 @@ const getConfig = (options) => {
|
|
|
2807
2879
|
return {
|
|
2808
2880
|
version: ctx.context.version || null,
|
|
2809
2881
|
socialProviders: Object.keys(ctx.context.options.socialProviders || {}),
|
|
2810
|
-
emailAndPassword: ctx.context.options.emailAndPassword,
|
|
2882
|
+
emailAndPassword: sanitizeConfig(ctx.context.options.emailAndPassword, /* @__PURE__ */ new WeakSet(), void 0),
|
|
2811
2883
|
plugins: ctx.context.options.plugins?.map((plugin) => {
|
|
2812
2884
|
const base = {
|
|
2813
2885
|
id: plugin.id,
|
|
@@ -5424,11 +5496,14 @@ function getSSOPlugin(ctx) {
|
|
|
5424
5496
|
const DEFAULT_MAX_SAML_METADATA_SIZE = 100 * 1024;
|
|
5425
5497
|
const RSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
|
|
5426
5498
|
const SHA1 = "http://www.w3.org/2000/09/xmldsig#sha1";
|
|
5499
|
+
/** @public */
|
|
5427
5500
|
const DEPRECATED_SIGNATURE_ALGORITHMS = [RSA_SHA1];
|
|
5501
|
+
/** @public */
|
|
5428
5502
|
const DEPRECATED_DIGEST_ALGORITHMS = [SHA1];
|
|
5429
5503
|
function validateSAMLMetadataSize(metadataXml, maxSize = DEFAULT_MAX_SAML_METADATA_SIZE) {
|
|
5430
5504
|
if (new TextEncoder().encode(metadataXml).byteLength > maxSize) throw new Error(`IdP metadata exceeds maximum allowed size (${Math.round(maxSize / 1024)}KB)`);
|
|
5431
5505
|
}
|
|
5506
|
+
/** @public */
|
|
5432
5507
|
function extractAlgorithmsFromSAMLMetadata(metadataXml) {
|
|
5433
5508
|
const signatureAlgorithms = [];
|
|
5434
5509
|
const digestAlgorithms = [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/infra",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "Dashboard and analytics plugin for Better Auth",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
@@ -68,9 +68,9 @@
|
|
|
68
68
|
"@types/node": "catalog:",
|
|
69
69
|
"better-auth": "catalog:",
|
|
70
70
|
"expo-crypto": "^14.0.2",
|
|
71
|
-
"happy-dom": "^20.
|
|
72
|
-
"msw": "^2.13.
|
|
73
|
-
"tsdown": "^0.21.
|
|
71
|
+
"happy-dom": "^20.9.0",
|
|
72
|
+
"msw": "^2.13.3",
|
|
73
|
+
"tsdown": "^0.21.9",
|
|
74
74
|
"typescript": "catalog:",
|
|
75
75
|
"zod": "catalog:"
|
|
76
76
|
},
|
|
@@ -92,6 +92,9 @@
|
|
|
92
92
|
"expo-device": ">=6.0.0"
|
|
93
93
|
},
|
|
94
94
|
"peerDependenciesMeta": {
|
|
95
|
+
"react-native": {
|
|
96
|
+
"optional": true
|
|
97
|
+
},
|
|
95
98
|
"@react-native-async-storage/async-storage": {
|
|
96
99
|
"optional": true
|
|
97
100
|
},
|