@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/LICENSE +21 -0
- package/README.md +148 -0
- package/dist/DbAuthHandler.d.ts +373 -0
- package/dist/DbAuthHandler.d.ts.map +1 -0
- package/dist/DbAuthHandler.js +934 -0
- package/dist/decoder.d.ts +5 -0
- package/dist/decoder.d.ts.map +1 -0
- package/dist/decoder.js +46 -0
- package/dist/errors.d.ts +94 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +285 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/shared.d.ts +46 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +268 -0
- package/package.json +82 -0
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
|
+
}
|