mates-fullstack 1.0.0-beta.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/README.md +311 -0
- package/dist/arctic-auth.d.ts +101 -0
- package/dist/arctic-auth.d.ts.map +1 -0
- package/dist/arctic-auth.js +538 -0
- package/dist/arctic-auth.js.map +1 -0
- package/dist/asset-manifest.d.ts +14 -0
- package/dist/asset-manifest.d.ts.map +1 -0
- package/dist/asset-manifest.js +102 -0
- package/dist/asset-manifest.js.map +1 -0
- package/dist/browser.d.ts +18 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +25 -0
- package/dist/browser.js.map +1 -0
- package/dist/build-esbuild.d.ts +29 -0
- package/dist/build-esbuild.d.ts.map +1 -0
- package/dist/build-esbuild.js +699 -0
- package/dist/build-esbuild.js.map +1 -0
- package/dist/build-prod.d.ts +126 -0
- package/dist/build-prod.d.ts.map +1 -0
- package/dist/build-prod.js +1014 -0
- package/dist/build-prod.js.map +1 -0
- package/dist/cli-new.d.ts +14 -0
- package/dist/cli-new.d.ts.map +1 -0
- package/dist/cli-new.js +637 -0
- package/dist/cli-new.js.map +1 -0
- package/dist/client.d.ts +43 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +130 -0
- package/dist/client.js.map +1 -0
- package/dist/cors.d.ts +16 -0
- package/dist/cors.d.ts.map +1 -0
- package/dist/cors.js +60 -0
- package/dist/cors.js.map +1 -0
- package/dist/ctx.d.ts +78 -0
- package/dist/ctx.d.ts.map +1 -0
- package/dist/ctx.js +280 -0
- package/dist/ctx.js.map +1 -0
- package/dist/dev-watcher.d.ts +23 -0
- package/dist/dev-watcher.d.ts.map +1 -0
- package/dist/dev-watcher.js +136 -0
- package/dist/dev-watcher.js.map +1 -0
- package/dist/docs-generator.d.ts +69 -0
- package/dist/docs-generator.d.ts.map +1 -0
- package/dist/docs-generator.js +557 -0
- package/dist/docs-generator.js.map +1 -0
- package/dist/docs-page.d.ts +20 -0
- package/dist/docs-page.d.ts.map +1 -0
- package/dist/docs-page.js +1152 -0
- package/dist/docs-page.js.map +1 -0
- package/dist/download.d.ts +78 -0
- package/dist/download.d.ts.map +1 -0
- package/dist/download.js +202 -0
- package/dist/download.js.map +1 -0
- package/dist/env-loader.d.ts +76 -0
- package/dist/env-loader.d.ts.map +1 -0
- package/dist/env-loader.js +213 -0
- package/dist/env-loader.js.map +1 -0
- package/dist/errors.d.ts +146 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +386 -0
- package/dist/errors.js.map +1 -0
- package/dist/head.d.ts +31 -0
- package/dist/head.d.ts.map +1 -0
- package/dist/head.js +245 -0
- package/dist/head.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/internal-prefixes.d.ts +16 -0
- package/dist/internal-prefixes.d.ts.map +1 -0
- package/dist/internal-prefixes.js +16 -0
- package/dist/internal-prefixes.js.map +1 -0
- package/dist/internal.d.ts +25 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +25 -0
- package/dist/internal.js.map +1 -0
- package/dist/jwt.d.ts +166 -0
- package/dist/jwt.d.ts.map +1 -0
- package/dist/jwt.js +261 -0
- package/dist/jwt.js.map +1 -0
- package/dist/log.d.ts +44 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +66 -0
- package/dist/log.js.map +1 -0
- package/dist/logger.d.ts +76 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +138 -0
- package/dist/logger.js.map +1 -0
- package/dist/main-runner.d.ts +59 -0
- package/dist/main-runner.d.ts.map +1 -0
- package/dist/main-runner.js +157 -0
- package/dist/main-runner.js.map +1 -0
- package/dist/mates-auth.d.ts +82 -0
- package/dist/mates-auth.d.ts.map +1 -0
- package/dist/mates-auth.js +323 -0
- package/dist/mates-auth.js.map +1 -0
- package/dist/middleware.d.ts +30 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +67 -0
- package/dist/middleware.js.map +1 -0
- package/dist/project-resolver.d.ts +102 -0
- package/dist/project-resolver.d.ts.map +1 -0
- package/dist/project-resolver.js +271 -0
- package/dist/project-resolver.js.map +1 -0
- package/dist/rate-limit.d.ts +37 -0
- package/dist/rate-limit.d.ts.map +1 -0
- package/dist/rate-limit.js +109 -0
- package/dist/rate-limit.js.map +1 -0
- package/dist/redirect.d.ts +84 -0
- package/dist/redirect.d.ts.map +1 -0
- package/dist/redirect.js +105 -0
- package/dist/redirect.js.map +1 -0
- package/dist/renderer.d.ts +91 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/renderer.js +630 -0
- package/dist/renderer.js.map +1 -0
- package/dist/request-logger.d.ts +12 -0
- package/dist/request-logger.d.ts.map +1 -0
- package/dist/request-logger.js +55 -0
- package/dist/request-logger.js.map +1 -0
- package/dist/rest.d.ts +25 -0
- package/dist/rest.d.ts.map +1 -0
- package/dist/rest.js +93 -0
- package/dist/rest.js.map +1 -0
- package/dist/router.d.ts +71 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +222 -0
- package/dist/router.js.map +1 -0
- package/dist/rpc-registry.d.ts +84 -0
- package/dist/rpc-registry.d.ts.map +1 -0
- package/dist/rpc-registry.js +271 -0
- package/dist/rpc-registry.js.map +1 -0
- package/dist/rpc-runner.d.ts +82 -0
- package/dist/rpc-runner.d.ts.map +1 -0
- package/dist/rpc-runner.js +564 -0
- package/dist/rpc-runner.js.map +1 -0
- package/dist/sanitize.d.ts +61 -0
- package/dist/sanitize.d.ts.map +1 -0
- package/dist/sanitize.js +193 -0
- package/dist/sanitize.js.map +1 -0
- package/dist/security-headers.d.ts +114 -0
- package/dist/security-headers.d.ts.map +1 -0
- package/dist/security-headers.js +121 -0
- package/dist/security-headers.js.map +1 -0
- package/dist/server-fn.d.ts +323 -0
- package/dist/server-fn.d.ts.map +1 -0
- package/dist/server-fn.js +373 -0
- package/dist/server-fn.js.map +1 -0
- package/dist/server-public.d.ts +13 -0
- package/dist/server-public.d.ts.map +1 -0
- package/dist/server-public.js +12 -0
- package/dist/server-public.js.map +1 -0
- package/dist/server-timeout.d.ts +38 -0
- package/dist/server-timeout.d.ts.map +1 -0
- package/dist/server-timeout.js +46 -0
- package/dist/server-timeout.js.map +1 -0
- package/dist/server.d.ts +100 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +1218 -0
- package/dist/server.js.map +1 -0
- package/dist/socket-router.d.ts +153 -0
- package/dist/socket-router.d.ts.map +1 -0
- package/dist/socket-router.js +612 -0
- package/dist/socket-router.js.map +1 -0
- package/dist/sso.d.ts +90 -0
- package/dist/sso.d.ts.map +1 -0
- package/dist/sso.js +261 -0
- package/dist/sso.js.map +1 -0
- package/dist/ssr-context.d.ts +49 -0
- package/dist/ssr-context.d.ts.map +1 -0
- package/dist/ssr-context.js +85 -0
- package/dist/ssr-context.js.map +1 -0
- package/dist/ssr-globals.d.ts +32 -0
- package/dist/ssr-globals.d.ts.map +1 -0
- package/dist/ssr-globals.js +1010 -0
- package/dist/ssr-globals.js.map +1 -0
- package/dist/ssr-template.d.ts +73 -0
- package/dist/ssr-template.d.ts.map +1 -0
- package/dist/ssr-template.js +507 -0
- package/dist/ssr-template.js.map +1 -0
- package/dist/stack-mapper.d.ts +25 -0
- package/dist/stack-mapper.d.ts.map +1 -0
- package/dist/stack-mapper.js +139 -0
- package/dist/stack-mapper.js.map +1 -0
- package/dist/stream.d.ts +89 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +299 -0
- package/dist/stream.js.map +1 -0
- package/dist/upload.d.ts +69 -0
- package/dist/upload.d.ts.map +1 -0
- package/dist/upload.js +110 -0
- package/dist/upload.js.map +1 -0
- package/dist/validate.d.ts +58 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +89 -0
- package/dist/validate.js.map +1 -0
- package/dist/verify-package.d.ts +3 -0
- package/dist/verify-package.d.ts.map +1 -0
- package/dist/verify-package.js +128 -0
- package/dist/verify-package.js.map +1 -0
- package/package.json +79 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mates-fullstack — main-runner.ts
|
|
3
|
+
*
|
|
4
|
+
* Imports server/main.ts at startup to trigger module-level
|
|
5
|
+
* onRequest() / onRequest() / onResponse() registrations.
|
|
6
|
+
*
|
|
7
|
+
* server/main.ts is a pure side-effect module:
|
|
8
|
+
*
|
|
9
|
+
* import { onRequest, onRequest, onResponse } from "mates-fullstack";
|
|
10
|
+
*
|
|
11
|
+
* onRequest(async (c) => {
|
|
12
|
+
* if (new URL(req.url).pathname === "/stripe-webhook") {
|
|
13
|
+
* return new Response("ok");
|
|
14
|
+
* }
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* onRequest(async (payload, ctx) => {
|
|
18
|
+
* await rateLimit(payload, ctx, { max: 100 });
|
|
19
|
+
* await auth(payload, ctx, { cookie: "session" });
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* onResponse(async (data, ctx) => {
|
|
23
|
+
* ctx.resHeaders["x-response-time"] = "...";
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* There is no default export, no main function, no lifecycle —
|
|
27
|
+
* just module-level calls that register hooks into the global arrays
|
|
28
|
+
* in middleware.ts.
|
|
29
|
+
*
|
|
30
|
+
* In dev hot-reload:
|
|
31
|
+
* 1. clearMiddleware() is called to reset the hook arrays
|
|
32
|
+
* 2. main.ts is re-imported (cache-busted) to re-register
|
|
33
|
+
*/
|
|
34
|
+
/**
|
|
35
|
+
* Import server/main.ts to register its onRequest/onResponse hooks.
|
|
36
|
+
* If the file doesn't exist, does nothing (optional file).
|
|
37
|
+
*
|
|
38
|
+
* @throws if the file exists but fails to import (syntax/runtime error).
|
|
39
|
+
* A broken main.ts breaks every RPC request so we crash loudly.
|
|
40
|
+
*/
|
|
41
|
+
export declare function importMainFile(mainFile: string): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Re-import server/main.ts in dev hot-reload.
|
|
44
|
+
* Clears all existing hooks first so re-registration starts fresh.
|
|
45
|
+
* Uses a cache-bust timestamp to force a fresh module evaluation.
|
|
46
|
+
* On import error, logs and keeps the previously registered hooks.
|
|
47
|
+
*/
|
|
48
|
+
export declare function reloadMainFile(mainFile: string): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Watch server/main.ts for changes and reload on save.
|
|
51
|
+
* Returns a cleanup function that stops the watcher.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* const stop = watchMainFile(paths.mainFile, () => {
|
|
55
|
+
* console.log("main.ts reloaded");
|
|
56
|
+
* });
|
|
57
|
+
*/
|
|
58
|
+
export declare function watchMainFile(mainFile: string, onReload?: () => void): () => void;
|
|
59
|
+
//# sourceMappingURL=main-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main-runner.d.ts","sourceRoot":"","sources":["../src/main-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AASH;;;;;;GAMG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAWpE;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBpE;AAID;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,MAAM,IAAI,GACpB,MAAM,IAAI,CA6DZ"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mates-fullstack — main-runner.ts
|
|
3
|
+
*
|
|
4
|
+
* Imports server/main.ts at startup to trigger module-level
|
|
5
|
+
* onRequest() / onRequest() / onResponse() registrations.
|
|
6
|
+
*
|
|
7
|
+
* server/main.ts is a pure side-effect module:
|
|
8
|
+
*
|
|
9
|
+
* import { onRequest, onRequest, onResponse } from "mates-fullstack";
|
|
10
|
+
*
|
|
11
|
+
* onRequest(async (c) => {
|
|
12
|
+
* if (new URL(req.url).pathname === "/stripe-webhook") {
|
|
13
|
+
* return new Response("ok");
|
|
14
|
+
* }
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* onRequest(async (payload, ctx) => {
|
|
18
|
+
* await rateLimit(payload, ctx, { max: 100 });
|
|
19
|
+
* await auth(payload, ctx, { cookie: "session" });
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* onResponse(async (data, ctx) => {
|
|
23
|
+
* ctx.resHeaders["x-response-time"] = "...";
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* There is no default export, no main function, no lifecycle —
|
|
27
|
+
* just module-level calls that register hooks into the global arrays
|
|
28
|
+
* in middleware.ts.
|
|
29
|
+
*
|
|
30
|
+
* In dev hot-reload:
|
|
31
|
+
* 1. clearMiddleware() is called to reset the hook arrays
|
|
32
|
+
* 2. main.ts is re-imported (cache-busted) to re-register
|
|
33
|
+
*/
|
|
34
|
+
import fs from "node:fs";
|
|
35
|
+
import path from "node:path";
|
|
36
|
+
import { clearMiddleware, middlewareStats } from "./middleware.js";
|
|
37
|
+
import { devLog, devError } from "./log.js";
|
|
38
|
+
// ─── Loader ───────────────────────────────────────────────────────────────────
|
|
39
|
+
/**
|
|
40
|
+
* Import server/main.ts to register its onRequest/onResponse hooks.
|
|
41
|
+
* If the file doesn't exist, does nothing (optional file).
|
|
42
|
+
*
|
|
43
|
+
* @throws if the file exists but fails to import (syntax/runtime error).
|
|
44
|
+
* A broken main.ts breaks every RPC request so we crash loudly.
|
|
45
|
+
*/
|
|
46
|
+
export async function importMainFile(mainFile) {
|
|
47
|
+
if (!fs.existsSync(mainFile))
|
|
48
|
+
return;
|
|
49
|
+
try {
|
|
50
|
+
await import(mainFile);
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
throw new Error(`[mates-fullstack] Failed to import server/main.ts: ${err?.message ?? err}\n` +
|
|
54
|
+
`Fix the error in server/main.ts before starting the server.`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Re-import server/main.ts in dev hot-reload.
|
|
59
|
+
* Clears all existing hooks first so re-registration starts fresh.
|
|
60
|
+
* Uses a cache-bust timestamp to force a fresh module evaluation.
|
|
61
|
+
* On import error, logs and keeps the previously registered hooks.
|
|
62
|
+
*/
|
|
63
|
+
export async function reloadMainFile(mainFile) {
|
|
64
|
+
if (!fs.existsSync(mainFile))
|
|
65
|
+
return;
|
|
66
|
+
// Clear hooks BEFORE re-importing so the new registrations start clean
|
|
67
|
+
clearMiddleware();
|
|
68
|
+
try {
|
|
69
|
+
await import(`${mainFile}?t=${Date.now()}`);
|
|
70
|
+
const stats = middlewareStats();
|
|
71
|
+
devLog(`server/main.ts reloaded ` +
|
|
72
|
+
`(${stats.request} onRequest, ${stats.response} onResponse hooks)`);
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
devError(`Failed to reload server/main.ts: ${err?.message ?? err}\n` +
|
|
76
|
+
`Previous hooks have been cleared. Fix the error and save again.`);
|
|
77
|
+
// Leave hooks empty — better than running stale hooks
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// ─── Watcher ──────────────────────────────────────────────────────────────────
|
|
81
|
+
/**
|
|
82
|
+
* Watch server/main.ts for changes and reload on save.
|
|
83
|
+
* Returns a cleanup function that stops the watcher.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* const stop = watchMainFile(paths.mainFile, () => {
|
|
87
|
+
* console.log("main.ts reloaded");
|
|
88
|
+
* });
|
|
89
|
+
*/
|
|
90
|
+
export function watchMainFile(mainFile, onReload) {
|
|
91
|
+
if (!fs.existsSync(mainFile)) {
|
|
92
|
+
// Watch directory for the file to be created
|
|
93
|
+
const dir = path.dirname(mainFile);
|
|
94
|
+
const basename = path.basename(mainFile);
|
|
95
|
+
if (!fs.existsSync(dir))
|
|
96
|
+
return () => { };
|
|
97
|
+
let debounce = null;
|
|
98
|
+
const watcher = fs.watch(dir, (_event, filename) => {
|
|
99
|
+
if (filename !== basename)
|
|
100
|
+
return;
|
|
101
|
+
if (debounce)
|
|
102
|
+
clearTimeout(debounce);
|
|
103
|
+
debounce = setTimeout(async () => {
|
|
104
|
+
await reloadMainFile(mainFile);
|
|
105
|
+
onReload?.();
|
|
106
|
+
}, 50);
|
|
107
|
+
});
|
|
108
|
+
return () => {
|
|
109
|
+
if (debounce)
|
|
110
|
+
clearTimeout(debounce);
|
|
111
|
+
watcher.close();
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
let debounce = null;
|
|
115
|
+
// Watch the file directly
|
|
116
|
+
const fileWatcher = fs.watch(mainFile, () => {
|
|
117
|
+
if (debounce)
|
|
118
|
+
clearTimeout(debounce);
|
|
119
|
+
debounce = setTimeout(async () => {
|
|
120
|
+
await reloadMainFile(mainFile);
|
|
121
|
+
onReload?.();
|
|
122
|
+
}, 50);
|
|
123
|
+
});
|
|
124
|
+
// Also watch directory for atomic saves (vim, emacs rename on write)
|
|
125
|
+
const dir = path.dirname(mainFile);
|
|
126
|
+
const basename = path.basename(mainFile);
|
|
127
|
+
let dirDebounce = null;
|
|
128
|
+
const dirWatcher = fs.watch(dir, (event, filename) => {
|
|
129
|
+
if (filename !== basename || event !== "rename")
|
|
130
|
+
return;
|
|
131
|
+
if (dirDebounce)
|
|
132
|
+
clearTimeout(dirDebounce);
|
|
133
|
+
dirDebounce = setTimeout(async () => {
|
|
134
|
+
await reloadMainFile(mainFile);
|
|
135
|
+
onReload?.();
|
|
136
|
+
}, 50);
|
|
137
|
+
});
|
|
138
|
+
return () => {
|
|
139
|
+
if (debounce)
|
|
140
|
+
clearTimeout(debounce);
|
|
141
|
+
if (dirDebounce)
|
|
142
|
+
clearTimeout(dirDebounce);
|
|
143
|
+
try {
|
|
144
|
+
fileWatcher.close();
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
/* already closed */
|
|
148
|
+
}
|
|
149
|
+
try {
|
|
150
|
+
dirWatcher.close();
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
/* already closed */
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=main-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main-runner.js","sourceRoot":"","sources":["../src/main-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { CookieOptions, Context } from "./ctx.js";
|
|
2
|
+
import { type JwtPayload } from "./jwt.js";
|
|
3
|
+
export type AuthDuration = number | string;
|
|
4
|
+
export interface MatesAuthClaims extends JwtPayload {
|
|
5
|
+
/** Canonical user id used by matesAuth. Mirrored to `sub` in JWTs. */
|
|
6
|
+
userId?: string;
|
|
7
|
+
/** Common display-name aliases. */
|
|
8
|
+
userName?: string;
|
|
9
|
+
username?: string;
|
|
10
|
+
name?: string;
|
|
11
|
+
email?: string;
|
|
12
|
+
roles?: string[];
|
|
13
|
+
[key: string]: unknown;
|
|
14
|
+
}
|
|
15
|
+
export interface MatesAuthContext extends MatesAuthClaims {
|
|
16
|
+
/** True only when `matesAuth()` verified an access token or refreshed it. */
|
|
17
|
+
isAuthenticated?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface MatesAuthOptions {
|
|
20
|
+
/** JWT/HMAC secret. Falls back to AUTH_JWT_SECRET or JWT_SECRET. */
|
|
21
|
+
secret?: string;
|
|
22
|
+
/** Throw `AuthError(401)` when expired/invalid tokens require logout. Default: true. */
|
|
23
|
+
throwErrorIfTokensExpired?: boolean;
|
|
24
|
+
/** Access token cookie name. Default: "mates_access". */
|
|
25
|
+
accessCookieName?: string;
|
|
26
|
+
/** Refresh token cookie name. Default: "mates_refresh". */
|
|
27
|
+
refreshCookieName?: string;
|
|
28
|
+
/** Access token lifetime. Default: "15m". */
|
|
29
|
+
accessExpiresIn?: AuthDuration;
|
|
30
|
+
/** Refresh token lifetime. Default: "30d". */
|
|
31
|
+
refreshExpiresIn?: AuthDuration;
|
|
32
|
+
/** Cookie path. Default: "/". */
|
|
33
|
+
path?: string;
|
|
34
|
+
/** Cookie domain. */
|
|
35
|
+
domain?: string;
|
|
36
|
+
/** SameSite policy. Default: "lax". */
|
|
37
|
+
sameSite?: CookieOptions["sameSite"];
|
|
38
|
+
/** Secure flag. Default: true in production, false otherwise. */
|
|
39
|
+
secure?: boolean;
|
|
40
|
+
/** Refresh hook. Return fresh access claims, or null to force logout. */
|
|
41
|
+
onRefresh?: (userId: string, refreshPayload: JwtPayload, ctx: Context) => Promise<MatesAuthClaims | null> | MatesAuthClaims | null;
|
|
42
|
+
/** Optional post-verify hook for tokenVersion, disabled users, etc. */
|
|
43
|
+
onVerify?: (auth: MatesAuthClaims, ctx: Context) => Promise<boolean> | boolean;
|
|
44
|
+
/** Extract the canonical user id from claims. */
|
|
45
|
+
getUserId?: (claims: Record<string, unknown>) => string | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Expected issuer (`iss` claim) for tokens.
|
|
48
|
+
* If set, tokens with a different `iss` are rejected.
|
|
49
|
+
*/
|
|
50
|
+
issuer?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Expected audience (`aud` claim) for tokens.
|
|
53
|
+
* If set, tokens without this `aud` are rejected.
|
|
54
|
+
*/
|
|
55
|
+
audience?: string;
|
|
56
|
+
}
|
|
57
|
+
export interface AuthLoginOptions extends Partial<MatesAuthOptions> {
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Register the built-in auth middleware. Call once at module level in
|
|
61
|
+
* server/main.ts. It verifies httpOnly access/refresh tokens, updates
|
|
62
|
+
* `ctx.auth`, and clears cookies on logout.
|
|
63
|
+
*/
|
|
64
|
+
export declare function matesAuth(options?: MatesAuthOptions): void;
|
|
65
|
+
export declare const auth: {
|
|
66
|
+
/**
|
|
67
|
+
* Create access/refresh token pair, set httpOnly cookies, and update
|
|
68
|
+
* `ctx.auth` for this request.
|
|
69
|
+
*/
|
|
70
|
+
login(ctx: Context, payload: MatesAuthClaims, options?: AuthLoginOptions): Promise<{
|
|
71
|
+
accessToken: string;
|
|
72
|
+
refreshToken: string;
|
|
73
|
+
auth: MatesAuthContext;
|
|
74
|
+
}>;
|
|
75
|
+
/** Clear access and refresh cookies. */
|
|
76
|
+
logout(ctx: Context, options?: Partial<MatesAuthOptions>): void;
|
|
77
|
+
hashPassword: typeof hashPassword;
|
|
78
|
+
verifyPassword: typeof verifyPassword;
|
|
79
|
+
};
|
|
80
|
+
export declare function hashPassword(password: string): Promise<string>;
|
|
81
|
+
export declare function verifyPassword(password: string, hash: string): Promise<boolean>;
|
|
82
|
+
//# sourceMappingURL=mates-auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mates-auth.d.ts","sourceRoot":"","sources":["../src/mates-auth.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEvD,OAAO,EAAO,KAAK,UAAU,EAAuB,MAAM,UAAU,CAAC;AAIrE,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,CAAC;AAE3C,MAAM,WAAW,eAAgB,SAAQ,UAAU;IACjD,sEAAsE;IACtE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mCAAmC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,gBAAiB,SAAQ,eAAe;IACvD,6EAA6E;IAC7E,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wFAAwF;IACxF,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,yDAAyD;IACzD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,2DAA2D;IAC3D,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,6CAA6C;IAC7C,eAAe,CAAC,EAAE,YAAY,CAAC;IAC/B,8CAA8C;IAC9C,gBAAgB,CAAC,EAAE,YAAY,CAAC;IAChC,iCAAiC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qBAAqB;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,QAAQ,CAAC,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IACrC,iEAAiE;IACjE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,yEAAyE;IACzE,SAAS,CAAC,EAAE,CACV,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,UAAU,EAC1B,GAAG,EAAE,OAAO,KACT,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,GAAG,eAAe,GAAG,IAAI,CAAC;IAC9D,uEAAuE;IACvE,QAAQ,CAAC,EAAE,CACT,IAAI,EAAE,eAAe,EACrB,GAAG,EAAE,OAAO,KACT,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IAChC,iDAAiD;IACjD,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,GAAG,SAAS,CAAC;IACpE;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAiB,SAAQ,OAAO,CAAC,gBAAgB,CAAC;CAAG;AAyBtE;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,OAAO,GAAE,gBAAqB,GAAG,IAAI,CAc9D;AAED,eAAO,MAAM,IAAI;IACf;;;OAGG;eAEI,OAAO,WACH,eAAe,YACf,gBAAgB,GACxB,QAAQ;QACT,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,MAAM,gBAAgB,CAAC;KACxB,CAAC;IAUF,wCAAwC;gBAC5B,OAAO,YAAW,QAAQ,gBAAgB,CAAC,GAAQ,IAAI;;;CAQpE,CAAC;AA6UF,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAepE;AAED,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,CAAC,CAuBlB"}
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import { AuthError } from "./errors.js";
|
|
3
|
+
import { jwt } from "./jwt.js";
|
|
4
|
+
import { onRequest } from "./middleware.js";
|
|
5
|
+
import { onSocketConnect } from "./socket-router.js";
|
|
6
|
+
const ACCESS_TOKEN_TYPE = "access";
|
|
7
|
+
const REFRESH_TOKEN_TYPE = "refresh";
|
|
8
|
+
let activeConfig = null;
|
|
9
|
+
/**
|
|
10
|
+
* Register the built-in auth middleware. Call once at module level in
|
|
11
|
+
* server/main.ts. It verifies httpOnly access/refresh tokens, updates
|
|
12
|
+
* `ctx.auth`, and clears cookies on logout.
|
|
13
|
+
*/
|
|
14
|
+
export function matesAuth(options = {}) {
|
|
15
|
+
const config = resolveConfig(options, false);
|
|
16
|
+
activeConfig = config;
|
|
17
|
+
// HTTP path
|
|
18
|
+
onRequest(async (c) => {
|
|
19
|
+
await processAuthRequest(c, config);
|
|
20
|
+
});
|
|
21
|
+
// WebSocket path — runs during the socket upgrade handshake
|
|
22
|
+
// Reads httpOnly cookies, verifies JWT, populates ctx.auth
|
|
23
|
+
onSocketConnect(async (ctx) => {
|
|
24
|
+
await processAuthRequest(ctx, config);
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
export const auth = {
|
|
28
|
+
/**
|
|
29
|
+
* Create access/refresh token pair, set httpOnly cookies, and update
|
|
30
|
+
* `ctx.auth` for this request.
|
|
31
|
+
*/
|
|
32
|
+
async login(ctx, payload, options = {}) {
|
|
33
|
+
const config = resolveConfig(options);
|
|
34
|
+
const authPayload = normalizeAuthPayload(payload, config);
|
|
35
|
+
const userId = requireUserId(authPayload, config);
|
|
36
|
+
const tokenPair = await signTokenPair(authPayload, userId, config);
|
|
37
|
+
setTokenCookies(ctx, tokenPair, config);
|
|
38
|
+
ctx.auth = { ...authPayload, userId, sub: userId, isAuthenticated: true };
|
|
39
|
+
return { ...tokenPair, auth: ctx.auth };
|
|
40
|
+
},
|
|
41
|
+
/** Clear access and refresh cookies. */
|
|
42
|
+
logout(ctx, options = {}) {
|
|
43
|
+
const config = resolveConfig(options);
|
|
44
|
+
clearAuthCookies(ctx, config);
|
|
45
|
+
ctx.auth = null;
|
|
46
|
+
},
|
|
47
|
+
hashPassword,
|
|
48
|
+
verifyPassword,
|
|
49
|
+
};
|
|
50
|
+
// ─── Refresh token JTI store ──────────────────────────────────────────────────
|
|
51
|
+
// Tracks consumed refresh token JTIs to prevent replay attacks.
|
|
52
|
+
// Single-process only — for multi-instance deployments, use onRefresh to
|
|
53
|
+
// check a shared store (Redis, DB) and return null to force re-login.
|
|
54
|
+
const _consumedJtis = new Map(); // jti → exp (unix seconds)
|
|
55
|
+
function _isJtiConsumed(jti) {
|
|
56
|
+
const now = Math.floor(Date.now() / 1000);
|
|
57
|
+
// Opportunistic cleanup of expired entries
|
|
58
|
+
for (const [k, exp] of _consumedJtis) {
|
|
59
|
+
if (exp < now)
|
|
60
|
+
_consumedJtis.delete(k);
|
|
61
|
+
}
|
|
62
|
+
return _consumedJtis.has(jti);
|
|
63
|
+
}
|
|
64
|
+
function _consumeJti(jti, exp) {
|
|
65
|
+
_consumedJtis.set(jti, exp);
|
|
66
|
+
}
|
|
67
|
+
async function processAuthRequest(ctx, config) {
|
|
68
|
+
ctx.auth = null;
|
|
69
|
+
ctx.httpCookie = ctx.cookie;
|
|
70
|
+
const accessRaw = ctx.cookie.get(config.accessCookieName);
|
|
71
|
+
const refreshRaw = ctx.cookie.get(config.refreshCookieName);
|
|
72
|
+
const tokensWerePresent = Boolean(accessRaw || refreshRaw);
|
|
73
|
+
if (!tokensWerePresent)
|
|
74
|
+
return;
|
|
75
|
+
const accessPayload = accessRaw
|
|
76
|
+
? await verifyTypedToken(accessRaw, ACCESS_TOKEN_TYPE, config)
|
|
77
|
+
: null;
|
|
78
|
+
if (accessPayload) {
|
|
79
|
+
const verified = await validateVerifiedAuth(accessPayload, ctx, config);
|
|
80
|
+
if (!verified)
|
|
81
|
+
return logoutOrThrow(ctx, config, "Unauthorized");
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const refreshPayload = refreshRaw
|
|
85
|
+
? await verifyTypedToken(refreshRaw, REFRESH_TOKEN_TYPE, config)
|
|
86
|
+
: null;
|
|
87
|
+
if (!refreshPayload) {
|
|
88
|
+
return logoutOrThrow(ctx, config, "Authentication expired");
|
|
89
|
+
}
|
|
90
|
+
// Reject replayed refresh tokens
|
|
91
|
+
const refreshJti = typeof refreshPayload.jti === "string" ? refreshPayload.jti : null;
|
|
92
|
+
if (!refreshJti || _isJtiConsumed(refreshJti)) {
|
|
93
|
+
return logoutOrThrow(ctx, config, "Authentication expired");
|
|
94
|
+
}
|
|
95
|
+
const userId = config.getUserId(refreshPayload);
|
|
96
|
+
if (!userId) {
|
|
97
|
+
return logoutOrThrow(ctx, config, "Authentication expired");
|
|
98
|
+
}
|
|
99
|
+
const freshClaims = config.onRefresh
|
|
100
|
+
? await config.onRefresh(userId, refreshPayload, ctx)
|
|
101
|
+
: refreshClaimsToAuth(refreshPayload, userId);
|
|
102
|
+
if (!freshClaims) {
|
|
103
|
+
return logoutOrThrow(ctx, config, "Authentication expired");
|
|
104
|
+
}
|
|
105
|
+
const authPayload = normalizeAuthPayload(freshClaims, config);
|
|
106
|
+
const freshUserId = requireUserId(authPayload, config);
|
|
107
|
+
if (freshUserId !== userId) {
|
|
108
|
+
return logoutOrThrow(ctx, config, "Authentication expired");
|
|
109
|
+
}
|
|
110
|
+
const verified = await validateVerifiedAuth(authPayload, ctx, config);
|
|
111
|
+
if (!verified)
|
|
112
|
+
return logoutOrThrow(ctx, config, "Unauthorized");
|
|
113
|
+
const tokens = await signTokenPair(authPayload, freshUserId, config);
|
|
114
|
+
setTokenCookies(ctx, tokens, config);
|
|
115
|
+
// Consume the used refresh JTI — prevents replay of the same token
|
|
116
|
+
_consumeJti(refreshJti, typeof refreshPayload.exp === "number" ? refreshPayload.exp : 0);
|
|
117
|
+
}
|
|
118
|
+
async function validateVerifiedAuth(payload, ctx, config) {
|
|
119
|
+
const authPayload = normalizeAuthPayload(payload, config);
|
|
120
|
+
const userId = config.getUserId(authPayload);
|
|
121
|
+
if (!userId)
|
|
122
|
+
return false;
|
|
123
|
+
if (config.onVerify) {
|
|
124
|
+
const valid = await config.onVerify(authPayload, ctx);
|
|
125
|
+
if (!valid)
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
ctx.auth = { ...authPayload, userId, sub: userId, isAuthenticated: true };
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
async function signTokenPair(payload, userId, config) {
|
|
132
|
+
const tokens = jwt(config.secret);
|
|
133
|
+
const signOptions = {
|
|
134
|
+
expiresIn: config.accessExpiresIn,
|
|
135
|
+
issuer: config.issuer,
|
|
136
|
+
audience: config.audience,
|
|
137
|
+
};
|
|
138
|
+
const accessToken = await tokens.sign({
|
|
139
|
+
...stripJwtTiming(payload),
|
|
140
|
+
sub: userId,
|
|
141
|
+
userId,
|
|
142
|
+
tokenType: ACCESS_TOKEN_TYPE,
|
|
143
|
+
}, signOptions);
|
|
144
|
+
const refreshToken = await tokens.sign({ sub: userId, userId, tokenType: REFRESH_TOKEN_TYPE }, { ...signOptions, expiresIn: config.refreshExpiresIn, includeJti: true });
|
|
145
|
+
return { accessToken, refreshToken };
|
|
146
|
+
}
|
|
147
|
+
function setTokenCookies(ctx, tokens, config) {
|
|
148
|
+
ctx.cookie.set(config.accessCookieName, tokens.accessToken, {
|
|
149
|
+
...baseCookieOptions(config),
|
|
150
|
+
httpOnly: true,
|
|
151
|
+
maxAge: parseDuration(config.accessExpiresIn),
|
|
152
|
+
});
|
|
153
|
+
ctx.cookie.set(config.refreshCookieName, tokens.refreshToken, {
|
|
154
|
+
...baseCookieOptions(config),
|
|
155
|
+
httpOnly: true,
|
|
156
|
+
maxAge: parseDuration(config.refreshExpiresIn),
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
async function verifyTypedToken(token, tokenType, config) {
|
|
160
|
+
const payload = await jwt(config.secret).verify(token, {
|
|
161
|
+
issuer: config.issuer,
|
|
162
|
+
audience: config.audience,
|
|
163
|
+
});
|
|
164
|
+
if (!payload || payload.tokenType !== tokenType)
|
|
165
|
+
return null;
|
|
166
|
+
return payload;
|
|
167
|
+
}
|
|
168
|
+
function logoutOrThrow(ctx, config, message) {
|
|
169
|
+
clearAuthCookies(ctx, config);
|
|
170
|
+
ctx.auth = null;
|
|
171
|
+
if (config.throwErrorIfTokensExpired) {
|
|
172
|
+
throw new AuthError(message);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function clearAuthCookies(ctx, config) {
|
|
176
|
+
const options = cookieDeleteOptions(config);
|
|
177
|
+
ctx.cookie.delete(config.accessCookieName, options);
|
|
178
|
+
ctx.cookie.delete(config.refreshCookieName, options);
|
|
179
|
+
}
|
|
180
|
+
function normalizeAuthPayload(payload, config) {
|
|
181
|
+
const userId = config.getUserId(payload);
|
|
182
|
+
const clean = stripJwtTiming(payload);
|
|
183
|
+
delete clean.tokenType;
|
|
184
|
+
if (userId) {
|
|
185
|
+
clean.userId = userId;
|
|
186
|
+
clean.sub = userId;
|
|
187
|
+
}
|
|
188
|
+
return clean;
|
|
189
|
+
}
|
|
190
|
+
function requireUserId(payload, config) {
|
|
191
|
+
const userId = config.getUserId(payload);
|
|
192
|
+
if (!userId) {
|
|
193
|
+
throw new AuthError("Auth payload must include userId, id, or sub");
|
|
194
|
+
}
|
|
195
|
+
return userId;
|
|
196
|
+
}
|
|
197
|
+
function refreshClaimsToAuth(refreshPayload, userId) {
|
|
198
|
+
const clean = stripJwtTiming(refreshPayload);
|
|
199
|
+
delete clean.tokenType;
|
|
200
|
+
delete clean.jti;
|
|
201
|
+
return { ...clean, userId, sub: userId };
|
|
202
|
+
}
|
|
203
|
+
function stripJwtTiming(payload) {
|
|
204
|
+
const { iat: _iat, exp: _exp, nbf: _nbf, iss: _iss, aud: _aud, ...rest } = payload;
|
|
205
|
+
return { ...rest };
|
|
206
|
+
}
|
|
207
|
+
function defaultGetUserId(claims) {
|
|
208
|
+
const value = claims.userId ?? claims.id ?? claims.sub;
|
|
209
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
210
|
+
}
|
|
211
|
+
function resolveConfig(options = {}, inheritPrevious = true) {
|
|
212
|
+
const previous = inheritPrevious ? activeConfig : null;
|
|
213
|
+
const secret = options.secret ??
|
|
214
|
+
previous?.secret ??
|
|
215
|
+
process.env.AUTH_JWT_SECRET ??
|
|
216
|
+
process.env.JWT_SECRET;
|
|
217
|
+
if (!secret || secret.length < 8) {
|
|
218
|
+
throw new Error("[mates-fullstack] matesAuth: secret must be configured via " +
|
|
219
|
+
"matesAuth({ secret }), AUTH_JWT_SECRET, or JWT_SECRET.");
|
|
220
|
+
}
|
|
221
|
+
const refreshExpiresIn = options.refreshExpiresIn ?? previous?.refreshExpiresIn ?? "30d";
|
|
222
|
+
return {
|
|
223
|
+
secret,
|
|
224
|
+
throwErrorIfTokensExpired: options.throwErrorIfTokensExpired ??
|
|
225
|
+
previous?.throwErrorIfTokensExpired ??
|
|
226
|
+
true,
|
|
227
|
+
accessCookieName: options.accessCookieName ?? previous?.accessCookieName ?? "mates_access",
|
|
228
|
+
refreshCookieName: options.refreshCookieName ??
|
|
229
|
+
previous?.refreshCookieName ??
|
|
230
|
+
"mates_refresh",
|
|
231
|
+
accessExpiresIn: options.accessExpiresIn ?? previous?.accessExpiresIn ?? "15m",
|
|
232
|
+
refreshExpiresIn,
|
|
233
|
+
path: options.path ?? previous?.path ?? "/",
|
|
234
|
+
domain: options.domain ?? previous?.domain,
|
|
235
|
+
sameSite: options.sameSite ?? previous?.sameSite ?? "lax",
|
|
236
|
+
secure: options.secure ??
|
|
237
|
+
previous?.secure ??
|
|
238
|
+
process.env.NODE_ENV === "production",
|
|
239
|
+
onRefresh: options.onRefresh ?? previous?.onRefresh,
|
|
240
|
+
onVerify: options.onVerify ?? previous?.onVerify,
|
|
241
|
+
getUserId: options.getUserId ?? previous?.getUserId ?? defaultGetUserId,
|
|
242
|
+
issuer: options.issuer ?? previous?.issuer,
|
|
243
|
+
audience: options.audience ?? previous?.audience,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
function baseCookieOptions(config) {
|
|
247
|
+
return {
|
|
248
|
+
path: config.path,
|
|
249
|
+
domain: config.domain,
|
|
250
|
+
sameSite: config.sameSite,
|
|
251
|
+
secure: config.secure,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
function cookieDeleteOptions(config) {
|
|
255
|
+
return { path: config.path, domain: config.domain };
|
|
256
|
+
}
|
|
257
|
+
function parseDuration(value) {
|
|
258
|
+
if (typeof value === "number")
|
|
259
|
+
return Math.floor(value);
|
|
260
|
+
const str = value.trim();
|
|
261
|
+
if (/^\d+$/.test(str))
|
|
262
|
+
return Number(str);
|
|
263
|
+
const match = str.match(/^(\d+(?:\.\d+)?)\s*(s|m|h|d|w)$/i);
|
|
264
|
+
if (!match) {
|
|
265
|
+
throw new Error(`[mates-fullstack] matesAuth: invalid duration "${value}". ` +
|
|
266
|
+
"Use seconds or strings like 15m, 1h, 30d.");
|
|
267
|
+
}
|
|
268
|
+
const amount = Number(match[1]);
|
|
269
|
+
const unit = match[2].toLowerCase();
|
|
270
|
+
const multipliers = {
|
|
271
|
+
s: 1,
|
|
272
|
+
m: 60,
|
|
273
|
+
h: 3600,
|
|
274
|
+
d: 86400,
|
|
275
|
+
w: 604800,
|
|
276
|
+
};
|
|
277
|
+
return Math.floor(amount * multipliers[unit]);
|
|
278
|
+
}
|
|
279
|
+
const HASH_ALGORITHM = "scrypt";
|
|
280
|
+
const KEY_LENGTH = 64;
|
|
281
|
+
const SALT_LENGTH = 32;
|
|
282
|
+
const SCRYPT_N = 16384;
|
|
283
|
+
const SCRYPT_R = 8;
|
|
284
|
+
const SCRYPT_P = 1;
|
|
285
|
+
export async function hashPassword(password) {
|
|
286
|
+
const salt = new Uint8Array(crypto.randomBytes(SALT_LENGTH));
|
|
287
|
+
const derivedKey = crypto.scryptSync(password, salt, KEY_LENGTH, {
|
|
288
|
+
N: SCRYPT_N,
|
|
289
|
+
r: SCRYPT_R,
|
|
290
|
+
p: SCRYPT_P,
|
|
291
|
+
});
|
|
292
|
+
return [
|
|
293
|
+
HASH_ALGORITHM,
|
|
294
|
+
String(SCRYPT_N),
|
|
295
|
+
String(SCRYPT_R),
|
|
296
|
+
String(SCRYPT_P),
|
|
297
|
+
Buffer.from(salt).toString("base64url"),
|
|
298
|
+
derivedKey.toString("base64url"),
|
|
299
|
+
].join(":");
|
|
300
|
+
}
|
|
301
|
+
export async function verifyPassword(password, hash) {
|
|
302
|
+
try {
|
|
303
|
+
const parts = hash.split(":");
|
|
304
|
+
if (parts.length !== 6 || parts[0] !== HASH_ALGORITHM)
|
|
305
|
+
return false;
|
|
306
|
+
const N = Number(parts[1]);
|
|
307
|
+
const r = Number(parts[2]);
|
|
308
|
+
const p = Number(parts[3]);
|
|
309
|
+
const salt = new Uint8Array(Buffer.from(parts[4], "base64url"));
|
|
310
|
+
const expectedKey = new Uint8Array(Buffer.from(parts[5], "base64url"));
|
|
311
|
+
const actualKey = crypto.scryptSync(password, salt, KEY_LENGTH, {
|
|
312
|
+
N,
|
|
313
|
+
r,
|
|
314
|
+
p,
|
|
315
|
+
});
|
|
316
|
+
return (expectedKey.length === actualKey.length &&
|
|
317
|
+
crypto.timingSafeEqual(expectedKey, actualKey));
|
|
318
|
+
}
|
|
319
|
+
catch {
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
//# sourceMappingURL=mates-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mates-auth.js","sourceRoot":"","sources":["../src/mates-auth.ts"],"names":[],"mappings":"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"}
|