@poe-platform/safe-bash 0.1.773 → 0.1.775
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/image-ast/index.browser.js +754 -162
- package/dist/image-ast/index.js +754 -162
- package/dist/pdf-ast/index.js +754 -162
- package/dist/pdf-ast/vendor/pdfjs-fonts.d.mts +12 -0
- package/dist/pdf-ast/vendor/pdfjs-fonts.mjs +702 -0
- package/dist/safe-bash/command-chunks/{chunk-B2MM5DIT.js → chunk-3444RZLY.js} +754 -162
- package/dist/safe-bash/command-chunks/{chunk-G3NVK25P.js → chunk-QLYJUVVM.js} +1 -1
- package/dist/safe-bash/command-chunks/{chunk-5VXZSNM2.js → chunk-ZY6PMCW5.js} +2 -2
- package/dist/safe-bash/core.browser.js +63 -7
- package/dist/safe-bash/shell/runtime.js +17 -9
- package/dist/safe-bash/shell/sync-posix-regex.d.ts +3 -0
- package/dist/safe-bash/shell/sync-posix-regex.js +48 -0
- package/dist/safe-bash-command-ffmpeg/index.js +7249 -7039
- package/dist/safe-bash-command-gpg/index.js +28 -7
- package/dist/safe-bash-command-imagemagick/index.js +2 -2
- package/dist/safe-bash-command-openssl/index.js +24 -6
- package/dist/safe-bash-command-pandoc/command.js +3 -3
- package/dist/safe-bash-command-pandoc/index.js +3 -3
- package/dist/safe-bash-command-pdfimages/index.js +754 -162
- package/dist/safe-bash-command-pdfinfo/index.js +754 -162
- package/dist/safe-bash-command-pdftk/index.js +754 -162
- package/dist/safe-bash-command-pdftoppm/index.js +754 -162
- package/dist/safe-bash-command-pdftotext/index.js +754 -162
- package/dist/safe-bash-command-qpdf/index.js +754 -162
- package/dist/safe-bash-command-sips/index.js +2 -2
- package/dist/safe-bash-command-soffice/index.js +1 -1
- package/dist/safe-bash-command-ssconvert/index.js +754 -162
- package/dist/safe-bash-command-ssh/index.js +124 -23
- package/dist/safe-bash-command-wkhtmltopdf/index.js +760 -162
- package/package.json +2 -2
- package/third-party/pdf-ast/THIRD_PARTY_NOTICES.md +29 -0
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
|
|
5
5
|
// packages/safe-bash-command-ssh/dist/index.js
|
|
6
6
|
init_buffer();
|
|
7
|
-
import { commandRuntimeIdentity, getCommandArguments, readBytes, writeText } from "../safe-bash-contracts/index.js";
|
|
7
|
+
import { FsError, commandRuntimeIdentity, getCommandArguments, readBytes, writeText } from "../safe-bash-contracts/index.js";
|
|
8
8
|
import { PublicDiagnostic } from "../safe-bash-contracts/diagnostics.js";
|
|
9
9
|
import { writeFileOutput } from "../safe-bash-contracts/filesystem-output-budget.js";
|
|
10
10
|
import { yieldTurn } from "../safe-bash-contracts/yield.js";
|
|
@@ -216,6 +216,78 @@ function parseOpenSshEd25519PublicKey(line) {
|
|
|
216
216
|
comment: parts.slice(idx + 2).join(" ")
|
|
217
217
|
};
|
|
218
218
|
}
|
|
219
|
+
function matchesGlob(value, pattern) {
|
|
220
|
+
let v = 0;
|
|
221
|
+
let p = 0;
|
|
222
|
+
let star = -1;
|
|
223
|
+
let retry = 0;
|
|
224
|
+
while (v < value.length) {
|
|
225
|
+
if (pattern[p] === "?" || pattern[p] === value[v]) {
|
|
226
|
+
v++;
|
|
227
|
+
p++;
|
|
228
|
+
} else if (pattern[p] === "*") {
|
|
229
|
+
star = p++;
|
|
230
|
+
retry = v;
|
|
231
|
+
} else if (star >= 0) {
|
|
232
|
+
p = star + 1;
|
|
233
|
+
v = ++retry;
|
|
234
|
+
} else
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
while (pattern[p] === "*")
|
|
238
|
+
p++;
|
|
239
|
+
return p === pattern.length;
|
|
240
|
+
}
|
|
241
|
+
function matchesPatterns(value, patterns) {
|
|
242
|
+
let matched = false;
|
|
243
|
+
for (const pattern of patterns.split(",")) {
|
|
244
|
+
const negative = pattern.startsWith("!");
|
|
245
|
+
if (matchesGlob(value, negative ? pattern.slice(1) : pattern)) {
|
|
246
|
+
if (negative)
|
|
247
|
+
return false;
|
|
248
|
+
matched = true;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return matched;
|
|
252
|
+
}
|
|
253
|
+
function parseAllowedSigner(line) {
|
|
254
|
+
const text = line.trim();
|
|
255
|
+
if (!text || text.startsWith("#"))
|
|
256
|
+
return void 0;
|
|
257
|
+
const fields = [];
|
|
258
|
+
let field = "";
|
|
259
|
+
let quoted = false;
|
|
260
|
+
for (const char of text) {
|
|
261
|
+
if (char === '"')
|
|
262
|
+
quoted = !quoted;
|
|
263
|
+
if (!quoted && (char === " " || char === " ")) {
|
|
264
|
+
if (field) {
|
|
265
|
+
fields.push(field);
|
|
266
|
+
field = "";
|
|
267
|
+
}
|
|
268
|
+
} else
|
|
269
|
+
field += char;
|
|
270
|
+
}
|
|
271
|
+
if (quoted)
|
|
272
|
+
return void 0;
|
|
273
|
+
if (field)
|
|
274
|
+
fields.push(field);
|
|
275
|
+
const principals = fields[0];
|
|
276
|
+
let index = 1;
|
|
277
|
+
let namespaces;
|
|
278
|
+
if (fields[index] !== "ssh-ed25519") {
|
|
279
|
+
const options = fields[index++];
|
|
280
|
+
if (!options?.startsWith('namespaces="') || !options.endsWith('"'))
|
|
281
|
+
return void 0;
|
|
282
|
+
namespaces = options.slice(12, -1);
|
|
283
|
+
if (!namespaces || namespaces.includes('"'))
|
|
284
|
+
return void 0;
|
|
285
|
+
}
|
|
286
|
+
if (!principals || fields[index] !== "ssh-ed25519" || !fields[index + 1])
|
|
287
|
+
return void 0;
|
|
288
|
+
const key = parseOpenSshEd25519PublicKey(`${fields[index]} ${fields[index + 1]}`);
|
|
289
|
+
return key ? { principals, ...namespaces === void 0 ? {} : { namespaces }, pubKey: key.pubKey } : void 0;
|
|
290
|
+
}
|
|
219
291
|
async function computeFingerprintSha256(pubKey) {
|
|
220
292
|
const blob = sshEd25519PubkeyBlob(pubKey);
|
|
221
293
|
const buf = blob.buffer.slice(blob.byteOffset, blob.byteOffset + blob.byteLength);
|
|
@@ -262,6 +334,20 @@ async function collectSourceBytes(source, maxBytes, signal) {
|
|
|
262
334
|
}
|
|
263
335
|
return result;
|
|
264
336
|
}
|
|
337
|
+
async function readLimitedFile(context, path, maxBytes) {
|
|
338
|
+
try {
|
|
339
|
+
const bytes = await context.fs.readFile(path, { ...maxBytes === Infinity ? {} : { maxBytes }, signal: context.signal });
|
|
340
|
+
if (bytes.byteLength > maxBytes) {
|
|
341
|
+
throw new PublicDiagnostic(`input exceeds maximum buffered size of ${maxBytes} bytes`);
|
|
342
|
+
}
|
|
343
|
+
return bytes;
|
|
344
|
+
} catch (error) {
|
|
345
|
+
if (error instanceof FsError && error.code === "EFBIG") {
|
|
346
|
+
throw new PublicDiagnostic(`input exceeds maximum buffered size of ${maxBytes} bytes`);
|
|
347
|
+
}
|
|
348
|
+
throw error;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
265
351
|
function createSshKeygenCommand(options = {}) {
|
|
266
352
|
const limits = settings(options);
|
|
267
353
|
return {
|
|
@@ -280,6 +366,7 @@ function createSshKeygenCommand(options = {}) {
|
|
|
280
366
|
let removeHost;
|
|
281
367
|
let yAction;
|
|
282
368
|
let namespace = "file";
|
|
369
|
+
let namespaceProvided = false;
|
|
283
370
|
let allowedSignersFile;
|
|
284
371
|
let signerIdentity;
|
|
285
372
|
let signatureFile;
|
|
@@ -304,9 +391,10 @@ function createSshKeygenCommand(options = {}) {
|
|
|
304
391
|
removeHost = args[++i];
|
|
305
392
|
else if (a === "-Y" && i + 1 < args.length)
|
|
306
393
|
yAction = args[++i];
|
|
307
|
-
else if (a === "-n" && i + 1 < args.length)
|
|
394
|
+
else if (a === "-n" && i + 1 < args.length) {
|
|
308
395
|
namespace = args[++i];
|
|
309
|
-
|
|
396
|
+
namespaceProvided = true;
|
|
397
|
+
} else if (a === "-I" && i + 1 < args.length)
|
|
310
398
|
signerIdentity = args[++i];
|
|
311
399
|
else if (a === "-s" && i + 1 < args.length)
|
|
312
400
|
signatureFile = args[++i];
|
|
@@ -318,7 +406,11 @@ function createSshKeygenCommand(options = {}) {
|
|
|
318
406
|
try {
|
|
319
407
|
if (findHost !== void 0) {
|
|
320
408
|
const khPath = pathPosix.resolve(context.cwd, fileArg ?? "/home/user/.ssh/known_hosts");
|
|
321
|
-
const khText = textDecoder.decode(await context
|
|
409
|
+
const khText = textDecoder.decode(await readLimitedFile(context, khPath, maxBytes).catch((error) => {
|
|
410
|
+
if (error instanceof FsError && error.code === "ENOENT")
|
|
411
|
+
return new Uint8Array(0);
|
|
412
|
+
throw error;
|
|
413
|
+
}));
|
|
322
414
|
const matches = khText.split("\n").filter((l) => l.trim().length > 0 && !l.startsWith("#") && l.split(/\s+/)[0]?.split(",").includes(findHost));
|
|
323
415
|
if (matches.length === 0)
|
|
324
416
|
return { exitCode: 1 };
|
|
@@ -328,7 +420,11 @@ function createSshKeygenCommand(options = {}) {
|
|
|
328
420
|
}
|
|
329
421
|
if (removeHost !== void 0) {
|
|
330
422
|
const khPath = pathPosix.resolve(context.cwd, fileArg ?? "/home/user/.ssh/known_hosts");
|
|
331
|
-
const khText = textDecoder.decode(await context
|
|
423
|
+
const khText = textDecoder.decode(await readLimitedFile(context, khPath, maxBytes).catch((error) => {
|
|
424
|
+
if (error instanceof FsError && error.code === "ENOENT")
|
|
425
|
+
return new Uint8Array(0);
|
|
426
|
+
throw error;
|
|
427
|
+
}));
|
|
332
428
|
const remaining = khText.split("\n").filter((l) => l.trim().length === 0 || l.startsWith("#") || !l.split(/\s+/)[0]?.split(",").includes(removeHost));
|
|
333
429
|
const outBytes = textEncoder.encode(`${remaining.join("\n")}
|
|
334
430
|
`);
|
|
@@ -341,13 +437,13 @@ ${khPath} updated.
|
|
|
341
437
|
if (yAction !== void 0) {
|
|
342
438
|
if (yAction === "sign") {
|
|
343
439
|
const keyPath = pathPosix.resolve(context.cwd, fileArg ?? "/home/user/.ssh/id_ed25519");
|
|
344
|
-
const keyPem = textDecoder.decode(await context
|
|
440
|
+
const keyPem = textDecoder.decode(await readLimitedFile(context, keyPath, maxBytes));
|
|
345
441
|
const parsed = parseOpenSshEd25519PrivateKey(keyPem);
|
|
346
442
|
if (!parsed)
|
|
347
443
|
throw new PublicDiagnostic(`invalid OpenSSH Ed25519 key: ${keyPath}`);
|
|
348
444
|
const { privateKey } = await importEd25519FromSeedAndPub(parsed.seed, parsed.pubKey);
|
|
349
445
|
const targetFile = positionalFiles[0];
|
|
350
|
-
const payload = targetFile ? await context
|
|
446
|
+
const payload = targetFile ? await readLimitedFile(context, pathPosix.resolve(context.cwd, targetFile), maxBytes) : await collectSourceBytes(context.stdin, maxBytes, context.signal);
|
|
351
447
|
const payloadBuf = payload.buffer.slice(payload.byteOffset, payload.byteOffset + payload.byteLength);
|
|
352
448
|
const msgHash = new Uint8Array(await globalThis.crypto.subtle.digest("SHA-512", payloadBuf));
|
|
353
449
|
const toSign = [];
|
|
@@ -389,7 +485,7 @@ Write signature to ${targetFile}.sig
|
|
|
389
485
|
}
|
|
390
486
|
if (yAction === "verify" || yAction === "check-novalidate" || yAction === "find-principals") {
|
|
391
487
|
const sigPath = pathPosix.resolve(context.cwd, signatureFile ?? positionalFiles[0] ?? "");
|
|
392
|
-
const sigPem = textDecoder.decode(await context
|
|
488
|
+
const sigPem = textDecoder.decode(await readLimitedFile(context, sigPath, maxBytes));
|
|
393
489
|
const b64 = sigPem.split("\n").map((l) => l.trim()).filter((l) => !l.startsWith("-----") && l.length > 0).join("");
|
|
394
490
|
const raw = base64ToBytes(b64);
|
|
395
491
|
if (raw.byteLength < 10 || textDecoder.decode(raw.slice(0, 6)) !== "SSHSIG") {
|
|
@@ -412,22 +508,27 @@ Write signature to ${targetFile}.sig
|
|
|
412
508
|
const rawSig = readSshString(sigBlob, spos);
|
|
413
509
|
if (!pubKey2 || !rawSig)
|
|
414
510
|
throw new PublicDiagnostic("invalid SSHSIG key/signature");
|
|
415
|
-
if (yAction
|
|
511
|
+
if (yAction !== "find-principals" && (!namespaceProvided || textDecoder.decode(sigNs) !== namespace)) {
|
|
512
|
+
throw new PublicDiagnostic("signature namespace does not match requested namespace");
|
|
513
|
+
}
|
|
514
|
+
if (yAction === "verify" || yAction === "find-principals") {
|
|
416
515
|
allowedSignersFile = fileArg;
|
|
417
|
-
if (allowedSignersFile) {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
516
|
+
if (!allowedSignersFile || yAction === "verify" && !signerIdentity) {
|
|
517
|
+
throw new PublicDiagnostic("allowed signers file and signer identity are required for verification");
|
|
518
|
+
}
|
|
519
|
+
const asText = textDecoder.decode(await readLimitedFile(context, pathPosix.resolve(context.cwd, allowedSignersFile), maxBytes));
|
|
520
|
+
const entries = asText.split("\n").map(parseAllowedSigner).filter((entry) => entry !== void 0);
|
|
521
|
+
const matching = entries.filter((entry) => entry.pubKey.every((byte, index) => byte === pubKey2[index]) && (yAction === "find-principals" || matchesPatterns(namespace, entry.namespaces ?? "*")));
|
|
522
|
+
if (yAction === "find-principals") {
|
|
523
|
+
if (matching.length === 0)
|
|
524
|
+
return { exitCode: 1 };
|
|
525
|
+
await writeText(context.stdout, `${matching.map((entry) => entry.principals).join("\n")}
|
|
425
526
|
`);
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
527
|
+
return { exitCode: 0 };
|
|
528
|
+
}
|
|
529
|
+
if (!matching.some((entry) => matchesPatterns(signerIdentity, entry.principals))) {
|
|
530
|
+
throw new PublicDiagnostic("signer is not authorized by allowed signers");
|
|
429
531
|
}
|
|
430
|
-
return { exitCode: 1 };
|
|
431
532
|
}
|
|
432
533
|
const payload = await collectSourceBytes(context.stdin, maxBytes, context.signal);
|
|
433
534
|
const payloadBuf = payload.buffer.slice(payload.byteOffset, payload.byteOffset + payload.byteLength);
|
|
@@ -457,7 +558,7 @@ Write signature to ${targetFile}.sig
|
|
|
457
558
|
}
|
|
458
559
|
if (derivePub) {
|
|
459
560
|
const keyPath = pathPosix.resolve(context.cwd, fileArg ?? "/home/user/.ssh/id_ed25519");
|
|
460
|
-
const pem = textDecoder.decode(await context
|
|
561
|
+
const pem = textDecoder.decode(await readLimitedFile(context, keyPath, maxBytes));
|
|
461
562
|
const parsed = parseOpenSshEd25519PrivateKey(pem);
|
|
462
563
|
if (!parsed)
|
|
463
564
|
throw new PublicDiagnostic(`invalid OpenSSH private key: ${keyPath}`);
|
|
@@ -468,7 +569,7 @@ Write signature to ${targetFile}.sig
|
|
|
468
569
|
}
|
|
469
570
|
if (showFingerprint) {
|
|
470
571
|
const keyPath = pathPosix.resolve(context.cwd, fileArg ?? "/home/user/.ssh/id_ed25519.pub");
|
|
471
|
-
const content = textDecoder.decode(await context
|
|
572
|
+
const content = textDecoder.decode(await readLimitedFile(context, keyPath, maxBytes));
|
|
472
573
|
const privParsed = parseOpenSshEd25519PrivateKey(content);
|
|
473
574
|
const pubParsed = privParsed ?? parseOpenSshEd25519PublicKey(content);
|
|
474
575
|
if (!pubParsed)
|