@mettlelabs/mettle 0.0.0-beta.1 → 0.0.0-beta.1-linux-x64
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/THIRD_PARTY_NOTICES.md +11479 -0
- package/bin/mettle +4 -0
- package/harness/audit-investigation.mjs +203 -0
- package/harness/chunk-13tgmdey.mjs +33761 -0
- package/harness/chunk-1sygmp11.mjs +18142 -0
- package/harness/chunk-1ykxpmaz.mjs +7887 -0
- package/harness/chunk-2gt4cy7x.mjs +2290 -0
- package/harness/chunk-2pm2sayw.mjs +248 -0
- package/harness/chunk-32y07kkp.mjs +3747 -0
- package/harness/chunk-3m7jn5ac.mjs +16242 -0
- package/harness/chunk-3wvjs93w.mjs +538 -0
- package/harness/chunk-4bepyxmq.mjs +113 -0
- package/harness/chunk-4jtnt9k5.mjs +95 -0
- package/harness/chunk-50sbrf09.mjs +18972 -0
- package/harness/chunk-56csr8sw.mjs +322 -0
- package/harness/chunk-5cvb1jnb.mjs +41 -0
- package/harness/chunk-5wgmv4np.mjs +585 -0
- package/harness/chunk-65eyq32y.mjs +225 -0
- package/harness/chunk-6fnh6qhk.mjs +195 -0
- package/harness/chunk-6kgqw9ny.mjs +32303 -0
- package/harness/chunk-7b242j0n.mjs +14 -0
- package/harness/chunk-7bg2gnv2.mjs +7540 -0
- package/harness/chunk-ageqxj9v.mjs +63008 -0
- package/harness/chunk-b0qbt5jd.mjs +14 -0
- package/harness/chunk-b5g1r3fz.mjs +4785 -0
- package/harness/chunk-b71gpkxg.mjs +1514 -0
- package/harness/chunk-bdv1rx4a.mjs +20364 -0
- package/harness/chunk-c1631s2x.mjs +12241 -0
- package/harness/chunk-d5xgxsnp.mjs +74 -0
- package/harness/chunk-erg1fbh0.mjs +0 -0
- package/harness/chunk-fh78v9vn.mjs +19366 -0
- package/harness/chunk-fjx29qvp.mjs +50 -0
- package/harness/chunk-gryka6kg.mjs +39 -0
- package/harness/chunk-jb0r19et.mjs +180 -0
- package/harness/chunk-mfn574ss.mjs +179 -0
- package/harness/chunk-msg872ea.mjs +334 -0
- package/harness/chunk-nz5sv9as.mjs +1642 -0
- package/harness/chunk-p9d3cgvq.mjs +452 -0
- package/harness/chunk-pq6wvwxr.mjs +12 -0
- package/harness/chunk-qcm9arf8.mjs +7736 -0
- package/harness/chunk-qr8zfqjd.mjs +24 -0
- package/harness/chunk-rz2tz6jp.mjs +26 -0
- package/harness/chunk-sbkgc3kn.mjs +8 -0
- package/harness/chunk-v66qvpnb.mjs +169 -0
- package/harness/chunk-vjaxzab3.mjs +136 -0
- package/harness/chunk-vr1n5nza.mjs +1045 -0
- package/harness/chunk-vsf2zajv.mjs +3867 -0
- package/harness/chunk-wq253fj4.mjs +19041 -0
- package/harness/chunk-wyv7ceq4.mjs +0 -0
- package/harness/chunk-xnqknk2r.mjs +198 -0
- package/harness/chunk-xqyc4ca2.mjs +1890 -0
- package/harness/chunk-z6n9thea.mjs +45146 -0
- package/harness/chunk-zty0d3bw.mjs +0 -0
- package/harness/chunk-zvkxtj82.mjs +42 -0
- package/harness/issue-api-token.mjs +35 -0
- package/harness/launcher.mjs +159 -0
- package/harness/sandbox.mjs +132 -0
- package/harness/server.mjs +66322 -0
- package/package.json +13 -15
- package/bin/mettle.js +0 -51
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import {
|
|
2
|
+
sha256
|
|
3
|
+
} from "./chunk-2gt4cy7x.mjs";
|
|
4
|
+
import {
|
|
5
|
+
ApiPrincipalSchema,
|
|
6
|
+
ApiTokenRecordSchema,
|
|
7
|
+
BEARER_TOKEN_PATTERN
|
|
8
|
+
} from "./chunk-zvkxtj82.mjs";
|
|
9
|
+
import {
|
|
10
|
+
number
|
|
11
|
+
} from "./chunk-1sygmp11.mjs";
|
|
12
|
+
|
|
13
|
+
// apps/harness/src/api/auth.ts
|
|
14
|
+
import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
|
|
15
|
+
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
16
|
+
import { join, resolve } from "node:path";
|
|
17
|
+
var ApiTokenIssueRequestSchema = ApiPrincipalSchema.omit({
|
|
18
|
+
expiresAt: true
|
|
19
|
+
}).extend({
|
|
20
|
+
ttlSeconds: number().int().min(60).max(86400).default(3600)
|
|
21
|
+
});
|
|
22
|
+
function issueApiToken(input, now = Date.now()) {
|
|
23
|
+
const { ttlSeconds, ...authority } = ApiTokenIssueRequestSchema.parse(input);
|
|
24
|
+
const principal = ApiPrincipalSchema.parse({
|
|
25
|
+
...authority,
|
|
26
|
+
expiresAt: now + ttlSeconds * 1000
|
|
27
|
+
});
|
|
28
|
+
const token = randomBytes(32).toString("base64url");
|
|
29
|
+
const record = {
|
|
30
|
+
tokenSha256: sha256(token),
|
|
31
|
+
principal
|
|
32
|
+
};
|
|
33
|
+
return { token, record };
|
|
34
|
+
}
|
|
35
|
+
async function writePrivateFile(path, contents) {
|
|
36
|
+
await writeFile(path, contents, { flag: "wx", mode: 384 });
|
|
37
|
+
}
|
|
38
|
+
async function writeApiTokenFiles(request, outputDirectory) {
|
|
39
|
+
const { token, record } = issueApiToken(request);
|
|
40
|
+
const directory = resolve(outputDirectory);
|
|
41
|
+
const tokenFile = join(directory, "token.key");
|
|
42
|
+
const serverTokensFile = join(directory, "server-tokens.json");
|
|
43
|
+
await mkdir(directory, { mode: 448 });
|
|
44
|
+
try {
|
|
45
|
+
await writePrivateFile(tokenFile, `${token}
|
|
46
|
+
`);
|
|
47
|
+
await writePrivateFile(serverTokensFile, `${JSON.stringify([record], null, 2)}
|
|
48
|
+
`);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
await rm(directory, { recursive: true, force: true });
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
tokenFile,
|
|
55
|
+
serverTokensFile,
|
|
56
|
+
expiresAt: record.principal.expiresAt,
|
|
57
|
+
credentialsPrinted: false
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
class ApiError extends Error {
|
|
62
|
+
status;
|
|
63
|
+
code;
|
|
64
|
+
constructor(status, code) {
|
|
65
|
+
super(code);
|
|
66
|
+
this.status = status;
|
|
67
|
+
this.code = code;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function tokenAuthenticator(entries, now = Date.now) {
|
|
71
|
+
if (!entries.length)
|
|
72
|
+
throw new Error("At least one explicitly configured API token is required.");
|
|
73
|
+
const records = entries.map((entry) => {
|
|
74
|
+
const record = ApiTokenRecordSchema.parse(entry);
|
|
75
|
+
return {
|
|
76
|
+
hash: Buffer.from(record.tokenSha256, "hex"),
|
|
77
|
+
principal: record.principal
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
if (new Set(entries.map((entry) => entry.tokenSha256)).size !== entries.length)
|
|
81
|
+
throw new Error("Duplicate API token.");
|
|
82
|
+
return async (request) => {
|
|
83
|
+
const header = request.headers.get("authorization") ?? "";
|
|
84
|
+
const match = BEARER_TOKEN_PATTERN.exec(header);
|
|
85
|
+
if (!match)
|
|
86
|
+
throw new ApiError(401, "unauthorized");
|
|
87
|
+
const actual = createHash("sha256").update(match[1]).digest();
|
|
88
|
+
const record = records.find((entry) => timingSafeEqual(entry.hash, actual));
|
|
89
|
+
if (!record || record.principal.expiresAt <= now())
|
|
90
|
+
throw new ApiError(401, "unauthorized");
|
|
91
|
+
return structuredClone(record.principal);
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export { writeApiTokenFiles, ApiError, tokenAuthenticator };
|