@contentgrowth/content-auth 0.0.3 → 0.1.0
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/backend/index.d.ts
CHANGED
|
@@ -1057,21 +1057,18 @@ interface AuthConfig {
|
|
|
1057
1057
|
* Use 'postgres' or 'mysql' if passing a Drizzle instance for those DBs.
|
|
1058
1058
|
*/
|
|
1059
1059
|
provider?: "sqlite" | "postgres" | "mysql";
|
|
1060
|
+
/**
|
|
1061
|
+
* Use Cloudflare native crypto.subtle for password hashing to avoid CPU limits.
|
|
1062
|
+
* Defaults to true. Set to false to use Better Auth's default (Scrypt/Argon2).
|
|
1063
|
+
*/
|
|
1064
|
+
useCloudflareNativeHashing?: boolean;
|
|
1060
1065
|
[key: string]: any;
|
|
1061
1066
|
}
|
|
1062
|
-
declare const createAuth: (config: AuthConfig) => better_auth.Auth<
|
|
1063
|
-
database: (options: better_auth.BetterAuthOptions) => better_auth.DBAdapter<better_auth.BetterAuthOptions>;
|
|
1064
|
-
secret: string;
|
|
1065
|
-
baseURL: string | undefined;
|
|
1066
|
-
}>;
|
|
1067
|
+
declare const createAuth: (config: AuthConfig) => better_auth.Auth<any>;
|
|
1067
1068
|
declare const authMiddleware: (auth: any) => (c: Context) => Promise<any>;
|
|
1068
1069
|
declare const createAuthApp: (config: AuthConfig) => {
|
|
1069
1070
|
app: Hono<hono_types.BlankEnv, hono_types.BlankSchema, "/">;
|
|
1070
|
-
auth: better_auth.Auth<
|
|
1071
|
-
database: (options: better_auth.BetterAuthOptions) => better_auth.DBAdapter<better_auth.BetterAuthOptions>;
|
|
1072
|
-
secret: string;
|
|
1073
|
-
baseURL: string | undefined;
|
|
1074
|
-
}>;
|
|
1071
|
+
auth: better_auth.Auth<any>;
|
|
1075
1072
|
};
|
|
1076
1073
|
|
|
1077
1074
|
export { type AuthConfig, authMiddleware, createAuth, createAuthApp, schema };
|
package/dist/backend/index.js
CHANGED
|
@@ -89,6 +89,80 @@ var invitations = sqliteTable("invitations", {
|
|
|
89
89
|
inviterId: text("inviterId").notNull().references(() => users.id, { onDelete: "cascade" })
|
|
90
90
|
});
|
|
91
91
|
|
|
92
|
+
// src/backend/native-hashing.ts
|
|
93
|
+
async function hashPassword(password) {
|
|
94
|
+
const salt = crypto.getRandomValues(new Uint8Array(16));
|
|
95
|
+
const enc = new TextEncoder();
|
|
96
|
+
const keyMaterial = await crypto.subtle.importKey(
|
|
97
|
+
"raw",
|
|
98
|
+
enc.encode(password),
|
|
99
|
+
{ name: "PBKDF2" },
|
|
100
|
+
false,
|
|
101
|
+
["deriveBits", "deriveKey"]
|
|
102
|
+
);
|
|
103
|
+
const hashBuffer = await crypto.subtle.deriveBits(
|
|
104
|
+
{
|
|
105
|
+
name: "PBKDF2",
|
|
106
|
+
salt,
|
|
107
|
+
iterations: 1e5,
|
|
108
|
+
hash: "SHA-256"
|
|
109
|
+
},
|
|
110
|
+
keyMaterial,
|
|
111
|
+
256
|
|
112
|
+
// 32 bytes
|
|
113
|
+
);
|
|
114
|
+
const saltB64 = btoa(String.fromCharCode(...new Uint8Array(salt)));
|
|
115
|
+
const hashB64 = btoa(String.fromCharCode(...new Uint8Array(hashBuffer)));
|
|
116
|
+
return `pbkdf2:100000:${saltB64}:${hashB64}`;
|
|
117
|
+
}
|
|
118
|
+
async function verifyPassword(passwordOrData, storedHash) {
|
|
119
|
+
let password;
|
|
120
|
+
let hash;
|
|
121
|
+
if (typeof passwordOrData === "object" && passwordOrData !== null) {
|
|
122
|
+
password = passwordOrData.password;
|
|
123
|
+
hash = passwordOrData.hash;
|
|
124
|
+
} else {
|
|
125
|
+
password = passwordOrData;
|
|
126
|
+
hash = storedHash;
|
|
127
|
+
}
|
|
128
|
+
if (!hash) {
|
|
129
|
+
console.error("[Auth] verifyPassword called with empty/undefined hash");
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
const parts = hash.split(":");
|
|
133
|
+
if (parts.length !== 4) return false;
|
|
134
|
+
const [alg, iterationsStr, saltB64, hashB64] = parts;
|
|
135
|
+
if (alg !== "pbkdf2") return false;
|
|
136
|
+
const iterations = parseInt(iterationsStr, 10);
|
|
137
|
+
const salt = Uint8Array.from(atob(saltB64), (c) => c.charCodeAt(0));
|
|
138
|
+
const originalHash = Uint8Array.from(atob(hashB64), (c) => c.charCodeAt(0));
|
|
139
|
+
const enc = new TextEncoder();
|
|
140
|
+
const keyMaterial = await crypto.subtle.importKey(
|
|
141
|
+
"raw",
|
|
142
|
+
enc.encode(password),
|
|
143
|
+
{ name: "PBKDF2" },
|
|
144
|
+
false,
|
|
145
|
+
["deriveBits", "deriveKey"]
|
|
146
|
+
);
|
|
147
|
+
const hashBuffer = await crypto.subtle.deriveBits(
|
|
148
|
+
{
|
|
149
|
+
name: "PBKDF2",
|
|
150
|
+
salt,
|
|
151
|
+
iterations,
|
|
152
|
+
hash: "SHA-256"
|
|
153
|
+
},
|
|
154
|
+
keyMaterial,
|
|
155
|
+
256
|
|
156
|
+
);
|
|
157
|
+
const newHash = new Uint8Array(hashBuffer);
|
|
158
|
+
if (newHash.length !== originalHash.length) return false;
|
|
159
|
+
let result = 0;
|
|
160
|
+
for (let i = 0; i < newHash.length; i++) {
|
|
161
|
+
result |= newHash[i] ^ originalHash[i];
|
|
162
|
+
}
|
|
163
|
+
return result === 0;
|
|
164
|
+
}
|
|
165
|
+
|
|
92
166
|
// src/backend/index.ts
|
|
93
167
|
var createAuth = (config) => {
|
|
94
168
|
let db;
|
|
@@ -98,7 +172,7 @@ var createAuth = (config) => {
|
|
|
98
172
|
} else {
|
|
99
173
|
db = config.database;
|
|
100
174
|
}
|
|
101
|
-
const { database, secret, baseUrl, provider: _, ...rest } = config;
|
|
175
|
+
const { database, secret, baseUrl, provider: _, useCloudflareNativeHashing = true, ...rest } = config;
|
|
102
176
|
let adapterOptions = {
|
|
103
177
|
provider,
|
|
104
178
|
schema: {
|
|
@@ -111,11 +185,23 @@ var createAuth = (config) => {
|
|
|
111
185
|
invitation: invitations
|
|
112
186
|
}
|
|
113
187
|
};
|
|
188
|
+
const emailConfig = rest.emailAndPassword || { enabled: true };
|
|
189
|
+
const { emailAndPassword, ...otherOptions } = rest;
|
|
190
|
+
const emailPasswordOptions = {
|
|
191
|
+
...emailConfig
|
|
192
|
+
};
|
|
193
|
+
if (useCloudflareNativeHashing) {
|
|
194
|
+
emailPasswordOptions.password = {
|
|
195
|
+
hash: hashPassword,
|
|
196
|
+
verify: verifyPassword
|
|
197
|
+
};
|
|
198
|
+
}
|
|
114
199
|
const auth = betterAuth({
|
|
115
200
|
database: drizzleAdapter(db, adapterOptions),
|
|
116
201
|
secret,
|
|
117
202
|
baseURL: baseUrl,
|
|
118
|
-
|
|
203
|
+
emailAndPassword: emailPasswordOptions,
|
|
204
|
+
...otherOptions
|
|
119
205
|
});
|
|
120
206
|
return auth;
|
|
121
207
|
};
|
package/dist/index.js
CHANGED