@redmix/auth-dbauth-api 0.0.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/dist/shared.js ADDED
@@ -0,0 +1,268 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var shared_exports = {};
30
+ __export(shared_exports, {
31
+ cookieName: () => cookieName,
32
+ dbAuthSession: () => dbAuthSession,
33
+ decryptSession: () => decryptSession,
34
+ encryptSession: () => encryptSession,
35
+ extractCookie: () => extractCookie,
36
+ extractHashingOptions: () => extractHashingOptions,
37
+ getDbAuthResponseBuilder: () => getDbAuthResponseBuilder,
38
+ getSession: () => getSession,
39
+ hashPassword: () => hashPassword,
40
+ hashToken: () => hashToken,
41
+ isLegacySession: () => isLegacySession,
42
+ legacyHashPassword: () => legacyHashPassword,
43
+ webAuthnSession: () => webAuthnSession
44
+ });
45
+ module.exports = __toCommonJS(shared_exports);
46
+ var import_node_crypto = __toESM(require("node:crypto"));
47
+ var import_api = require("@redmix/api");
48
+ var import_project_config = require("@redmix/project-config");
49
+ var DbAuthError = __toESM(require("./errors"));
50
+ const DEFAULT_SCRYPT_OPTIONS = {
51
+ cost: 2 ** 14,
52
+ blockSize: 8,
53
+ parallelization: 1
54
+ };
55
+ const getPort = () => {
56
+ let configPath;
57
+ try {
58
+ configPath = (0, import_project_config.getConfigPath)();
59
+ } catch {
60
+ return 8911;
61
+ }
62
+ return (0, import_project_config.getConfig)(configPath).api.port;
63
+ };
64
+ const eventGraphiQLHeadersCookie = (event) => {
65
+ if (process.env.NODE_ENV !== "development") {
66
+ return;
67
+ }
68
+ const impersationationHeader = (0, import_api.getEventHeader)(
69
+ event,
70
+ "rw-studio-impersonation-cookie"
71
+ );
72
+ if (impersationationHeader) {
73
+ return impersationationHeader;
74
+ }
75
+ try {
76
+ if (!(0, import_api.isFetchApiRequest)(event)) {
77
+ const jsonBody = JSON.parse(event.body ?? "{}");
78
+ return jsonBody?.extensions?.headers?.cookie || jsonBody?.extensions?.headers?.Cookie;
79
+ }
80
+ } catch {
81
+ return;
82
+ }
83
+ };
84
+ const legacyDecryptSession = (encryptedText) => {
85
+ const cypher = Buffer.from(encryptedText, "base64");
86
+ const salt = cypher.slice(8, 16);
87
+ const password = Buffer.concat([
88
+ Buffer.from(process.env.SESSION_SECRET, "binary"),
89
+ salt
90
+ ]);
91
+ const md5Hashes = [];
92
+ let digest = password;
93
+ for (let i = 0; i < 3; i++) {
94
+ md5Hashes[i] = import_node_crypto.default.createHash("md5").update(digest).digest();
95
+ digest = Buffer.concat([md5Hashes[i], password]);
96
+ }
97
+ const key = Buffer.concat([md5Hashes[0], md5Hashes[1]]);
98
+ const iv = md5Hashes[2];
99
+ const contents = cypher.slice(16);
100
+ const decipher = import_node_crypto.default.createDecipheriv("aes-256-cbc", key, iv);
101
+ return decipher.update(contents) + decipher.final("utf-8");
102
+ };
103
+ const extractCookie = (event) => {
104
+ return eventGraphiQLHeadersCookie(event) || (0, import_api.getEventHeader)(event, "Cookie");
105
+ };
106
+ const isLegacySession = (text) => {
107
+ if (!text) {
108
+ return false;
109
+ }
110
+ const [_encryptedText, iv] = text.split("|");
111
+ return !iv;
112
+ };
113
+ const decryptSession = (text) => {
114
+ if (!text || text.trim() === "") {
115
+ return [];
116
+ }
117
+ let decoded;
118
+ const [encryptedText, iv] = text.split("|");
119
+ try {
120
+ if (iv) {
121
+ const decipher = import_node_crypto.default.createDecipheriv(
122
+ "aes-256-cbc",
123
+ process.env.SESSION_SECRET.substring(0, 32),
124
+ Buffer.from(iv, "base64")
125
+ );
126
+ decoded = decipher.update(encryptedText, "base64", "utf-8") + decipher.final("utf-8");
127
+ } else {
128
+ decoded = legacyDecryptSession(text);
129
+ }
130
+ const [data, csrf] = decoded.split(";");
131
+ const json = JSON.parse(data);
132
+ return [json, csrf];
133
+ } catch {
134
+ throw new DbAuthError.SessionDecryptionError();
135
+ }
136
+ };
137
+ const encryptSession = (dataString) => {
138
+ const iv = import_node_crypto.default.randomBytes(16);
139
+ const cipher = import_node_crypto.default.createCipheriv(
140
+ "aes-256-cbc",
141
+ process.env.SESSION_SECRET.substring(0, 32),
142
+ iv
143
+ );
144
+ let encryptedData = cipher.update(dataString, "utf-8", "base64");
145
+ encryptedData += cipher.final("base64");
146
+ return `${encryptedData}|${iv.toString("base64")}`;
147
+ };
148
+ const getSession = (text, cookieNameOption) => {
149
+ if (typeof text === "undefined" || text === null) {
150
+ return null;
151
+ }
152
+ const cookies = text.split(";");
153
+ const sessionCookie = cookies.find((cookie) => {
154
+ return cookie.split("=")[0].trim() === cookieName(cookieNameOption);
155
+ });
156
+ if (!sessionCookie || sessionCookie === `${cookieName(cookieNameOption)}=`) {
157
+ return null;
158
+ }
159
+ return sessionCookie.replace(`${cookieName(cookieNameOption)}=`, "").trim();
160
+ };
161
+ const dbAuthSession = (event, cookieNameOption) => {
162
+ const sessionCookie = extractCookie(event);
163
+ if (!sessionCookie) {
164
+ return null;
165
+ }
166
+ const [session, _csrfToken] = decryptSession(
167
+ getSession(sessionCookie, cookieNameOption)
168
+ );
169
+ return session;
170
+ };
171
+ const webAuthnSession = (event) => {
172
+ const cookieHeader = extractCookie(event);
173
+ if (!cookieHeader) {
174
+ return null;
175
+ }
176
+ const webAuthnCookie = cookieHeader.split(";").find((cook) => {
177
+ return cook.split("=")[0].trim() === "webAuthn";
178
+ });
179
+ if (!webAuthnCookie || webAuthnCookie === "webAuthn=") {
180
+ return null;
181
+ }
182
+ return webAuthnCookie.split("=")[1].trim();
183
+ };
184
+ const hashToken = (token) => {
185
+ return import_node_crypto.default.createHash("sha256").update(token).digest("hex");
186
+ };
187
+ const hashPassword = (text, {
188
+ salt = import_node_crypto.default.randomBytes(32).toString("hex"),
189
+ options = DEFAULT_SCRYPT_OPTIONS
190
+ } = {}) => {
191
+ const encryptedString = import_node_crypto.default.scryptSync(text.normalize("NFC"), salt, 32, options).toString("hex");
192
+ const optionsToString = [
193
+ options.cost,
194
+ options.blockSize,
195
+ options.parallelization
196
+ ];
197
+ return [`${encryptedString}|${optionsToString.join("|")}`, salt];
198
+ };
199
+ const legacyHashPassword = (text, salt) => {
200
+ const useSalt = salt || import_node_crypto.default.randomBytes(32).toString("hex");
201
+ return [
202
+ import_node_crypto.default.pbkdf2Sync(text, useSalt, 1, 32, "SHA1").toString("hex"),
203
+ useSalt
204
+ ];
205
+ };
206
+ const cookieName = (name) => {
207
+ const port = getPort();
208
+ const cookieName2 = name?.replace("%port%", "" + port) ?? "session";
209
+ return cookieName2;
210
+ };
211
+ function getDbAuthResponseBuilder(event) {
212
+ return (response, corsHeaders) => {
213
+ const headers = {
214
+ ...Object.fromEntries(response.headers?.entries() || []),
215
+ ...corsHeaders
216
+ };
217
+ const dbAuthResponse = {
218
+ ...response,
219
+ headers
220
+ };
221
+ const setCookieHeaders = response.headers?.getSetCookie() || [];
222
+ if (setCookieHeaders.length > 0) {
223
+ delete headers["set-cookie"];
224
+ delete headers["Set-Cookie"];
225
+ if (supportsMultiValueHeaders(event)) {
226
+ dbAuthResponse.multiValueHeaders = {
227
+ // Netlify wants 'Set-Cookie' headers to be capitalized
228
+ // https://github.com/redwoodjs/redwood/pull/10889
229
+ "Set-Cookie": setCookieHeaders
230
+ };
231
+ } else {
232
+ headers["set-cookie"] = setCookieHeaders;
233
+ }
234
+ }
235
+ return dbAuthResponse;
236
+ };
237
+ }
238
+ function supportsMultiValueHeaders(event) {
239
+ return "multiValueHeaders" in event && (!event.headers || !("x-vercel-id" in event.headers));
240
+ }
241
+ const extractHashingOptions = (text) => {
242
+ const [_hash, ...options] = text.split("|");
243
+ if (options.length === 3) {
244
+ return {
245
+ cost: parseInt(options[0]),
246
+ blockSize: parseInt(options[1]),
247
+ parallelization: parseInt(options[2])
248
+ };
249
+ } else {
250
+ return {};
251
+ }
252
+ };
253
+ // Annotate the CommonJS export names for ESM import in node:
254
+ 0 && (module.exports = {
255
+ cookieName,
256
+ dbAuthSession,
257
+ decryptSession,
258
+ encryptSession,
259
+ extractCookie,
260
+ extractHashingOptions,
261
+ getDbAuthResponseBuilder,
262
+ getSession,
263
+ hashPassword,
264
+ hashToken,
265
+ isLegacySession,
266
+ legacyHashPassword,
267
+ webAuthnSession
268
+ });
package/package.json ADDED
@@ -0,0 +1,82 @@
1
+ {
2
+ "name": "@redmix/auth-dbauth-api",
3
+ "version": "0.0.1",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git+https://github.com/redmix-run/redmix.git",
7
+ "directory": "packages/auth-providers/dbAuth/api"
8
+ },
9
+ "license": "MIT",
10
+ "type": "commonjs",
11
+ "exports": {
12
+ ".": {
13
+ "default": {
14
+ "types": "./dist/index.d.ts",
15
+ "default": "./dist/index.js"
16
+ }
17
+ },
18
+ "./dist/decoder": {
19
+ "default": {
20
+ "types": "./dist/decoder.d.ts",
21
+ "default": "./dist/decoder.js"
22
+ }
23
+ },
24
+ "./dist/errors": {
25
+ "default": {
26
+ "types": "./dist/errors.d.ts",
27
+ "default": "./dist/errors.js"
28
+ }
29
+ },
30
+ "./dist/shared": {
31
+ "default": {
32
+ "types": "./dist/shared.d.ts",
33
+ "default": "./dist/shared.js"
34
+ }
35
+ },
36
+ "./dist/DbAuthHandler": {
37
+ "default": {
38
+ "types": "./dist/DbAuthHandler.d.ts",
39
+ "default": "./dist/DbAuthHandler.js"
40
+ }
41
+ }
42
+ },
43
+ "main": "./dist/index.js",
44
+ "types": "./dist/index.d.ts",
45
+ "files": [
46
+ "dist"
47
+ ],
48
+ "scripts": {
49
+ "build": "tsx ./build.mts && yarn build:types",
50
+ "build:pack": "yarn pack -o redmix-auth-dbauth-api.tgz",
51
+ "build:types": "tsc --build --verbose ./tsconfig.json",
52
+ "build:watch": "nodemon --watch src --ext \"js,jsx,ts,tsx,template\" --ignore dist --exec \"yarn build\"",
53
+ "check:attw": "yarn attw -P",
54
+ "check:package": "concurrently npm:check:attw yarn:publint",
55
+ "prepublishOnly": "NODE_ENV=production yarn build",
56
+ "test": "vitest run",
57
+ "test:watch": "vitest watch"
58
+ },
59
+ "dependencies": {
60
+ "@redmix/project-config": "0.0.1",
61
+ "base64url": "3.0.1",
62
+ "md5": "2.3.0",
63
+ "uuid": "10.0.0"
64
+ },
65
+ "devDependencies": {
66
+ "@arethetypeswrong/cli": "0.16.4",
67
+ "@redmix/api": "0.0.1",
68
+ "@redmix/framework-tools": "0.0.1",
69
+ "@simplewebauthn/server": "7.4.0",
70
+ "@types/md5": "2.3.5",
71
+ "@types/uuid": "10.0.0",
72
+ "concurrently": "8.2.2",
73
+ "publint": "0.3.11",
74
+ "tsx": "4.19.3",
75
+ "typescript": "5.6.2",
76
+ "vitest": "2.1.9"
77
+ },
78
+ "publishConfig": {
79
+ "access": "public"
80
+ },
81
+ "gitHead": "688027c97502c500ebbede9cdc7cc51545a8dcf3"
82
+ }