@ternent/seal-cli 0.1.6
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 +143 -0
- package/bin/seal +6 -0
- package/dist/chunks/utils.es-586f669f.js +56 -0
- package/dist/chunks/utils.es-586f669f.js.map +1 -0
- package/dist/cli.js +296 -0
- package/dist/cli.js.map +1 -0
- package/dist/crypto.js +249 -0
- package/dist/crypto.js.map +1 -0
- package/dist/errors.js +22 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest.js +82 -0
- package/dist/manifest.js.map +1 -0
- package/dist/proof.js +232 -0
- package/dist/proof.js.map +1 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# @ternent/seal-cli
|
|
2
|
+
|
|
3
|
+
Seal signs files and manifests. It verifies artifacts offline. It emits portable proof JSON that `apps/proof` can verify in the browser without duplicate crypto logic.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add -D @ternent/seal-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Environment
|
|
12
|
+
|
|
13
|
+
`@ternent/seal-cli` reads signer material from environment variables:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
export SEAL_PRIVATE_KEY="$(cat private-key.pem)"
|
|
17
|
+
export SEAL_PUBLIC_KEY="$(cat public-key.pem)"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`SEAL_PUBLIC_KEY` is optional. If it is present, Seal verifies that it matches `SEAL_PRIVATE_KEY`.
|
|
21
|
+
|
|
22
|
+
## Commands
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
seal manifest create --input apps/proof/dist --out apps/proof/dist/dist-manifest.json
|
|
26
|
+
seal sign --input apps/proof/dist/dist-manifest.json --out apps/proof/dist/proof.json
|
|
27
|
+
seal verify --proof apps/proof/dist/proof.json --input apps/proof/dist/dist-manifest.json --json
|
|
28
|
+
seal public-key --json
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## GitHub Actions
|
|
32
|
+
|
|
33
|
+
Use the published GitHub Action:
|
|
34
|
+
|
|
35
|
+
```yaml
|
|
36
|
+
- name: Generate Seal artifacts
|
|
37
|
+
uses: samternent/seal-action@1.0.0
|
|
38
|
+
env:
|
|
39
|
+
SEAL_PRIVATE_KEY: ${{ secrets.SEAL_PRIVATE_KEY }}
|
|
40
|
+
SEAL_PUBLIC_KEY: ${{ secrets.SEAL_PUBLIC_KEY }}
|
|
41
|
+
with:
|
|
42
|
+
assets-directory: dist
|
|
43
|
+
package-name: @ternent/seal-cli
|
|
44
|
+
package-version: latest
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The action is intentionally narrow. Your workflow still needs to:
|
|
48
|
+
|
|
49
|
+
- check out the repo
|
|
50
|
+
- set up Node
|
|
51
|
+
- build the static directory you want to sign
|
|
52
|
+
|
|
53
|
+
Inputs:
|
|
54
|
+
|
|
55
|
+
- `assets-directory`: built static directory to sign
|
|
56
|
+
- `working-directory`: base directory for path resolution
|
|
57
|
+
- `manifest-name`: manifest output filename
|
|
58
|
+
- `proof-name`: proof output filename
|
|
59
|
+
- `public-key-name`: public key output filename
|
|
60
|
+
- `package-name`: npm package name to execute when `cli-command` is omitted
|
|
61
|
+
- `package-version`: npm version or dist-tag to execute when `cli-command` is omitted
|
|
62
|
+
- `cli-command`: command prefix used to invoke Seal
|
|
63
|
+
|
|
64
|
+
Outputs:
|
|
65
|
+
|
|
66
|
+
- `manifest-path`
|
|
67
|
+
- `proof-path`
|
|
68
|
+
- `public-key-path`
|
|
69
|
+
|
|
70
|
+
The default path is npm-backed: if `cli-command` is empty, the action runs `npm exec --yes --package=<package-name>@<package-version> seal`.
|
|
71
|
+
|
|
72
|
+
## Schemas
|
|
73
|
+
|
|
74
|
+
Manifest:
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"version": "1",
|
|
79
|
+
"type": "seal-manifest",
|
|
80
|
+
"root": "dist",
|
|
81
|
+
"files": {
|
|
82
|
+
"assets/index.js": "sha256:..."
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Proof:
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"version": "1",
|
|
92
|
+
"type": "seal-proof",
|
|
93
|
+
"algorithm": "ECDSA-P256-SHA256",
|
|
94
|
+
"createdAt": "2026-03-13T00:00:00.000Z",
|
|
95
|
+
"subject": {
|
|
96
|
+
"kind": "manifest",
|
|
97
|
+
"path": "dist-manifest.json",
|
|
98
|
+
"hash": "sha256:..."
|
|
99
|
+
},
|
|
100
|
+
"signer": {
|
|
101
|
+
"publicKey": "BASE64-SPKI",
|
|
102
|
+
"keyId": "..."
|
|
103
|
+
},
|
|
104
|
+
"signature": "..."
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Public key:
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"algorithm": "ECDSA-P256-SHA256",
|
|
113
|
+
"publicKey": "BASE64-SPKI",
|
|
114
|
+
"keyId": "..."
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Frontend Contract
|
|
119
|
+
|
|
120
|
+
`apps/proof` verifies published artifacts by fetching:
|
|
121
|
+
|
|
122
|
+
- `/dist-manifest.json`
|
|
123
|
+
- `/proof.json`
|
|
124
|
+
- `/public-key.json` (optional)
|
|
125
|
+
|
|
126
|
+
Browser verification reuses `@ternent/seal-cli/proof`, `@ternent/seal-cli/crypto`, `ternent-identity`, and `ternent-utils`.
|
|
127
|
+
|
|
128
|
+
Validation rules:
|
|
129
|
+
|
|
130
|
+
- parse `seal-proof`
|
|
131
|
+
- recompute the fetched manifest hash from raw bytes
|
|
132
|
+
- verify the embedded signature
|
|
133
|
+
- verify `signer.keyId`
|
|
134
|
+
- if `/public-key.json` exists, require its `publicKey` and `keyId` to match the proof signer
|
|
135
|
+
|
|
136
|
+
## Exit Codes
|
|
137
|
+
|
|
138
|
+
- `0` success
|
|
139
|
+
- `1` general failure
|
|
140
|
+
- `2` subject hash mismatch
|
|
141
|
+
- `3` signature invalid
|
|
142
|
+
- `4` invalid proof
|
|
143
|
+
- `5` key or config error
|
package/bin/seal
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
function formatIdentityKey(key) {
|
|
2
|
+
return `-----BEGIN PUBLIC KEY-----
|
|
3
|
+
${key}
|
|
4
|
+
-----END PUBLIC KEY-----`;
|
|
5
|
+
}
|
|
6
|
+
function getHashArray(hash) {
|
|
7
|
+
return Array.from(new Uint8Array(hash));
|
|
8
|
+
}
|
|
9
|
+
function getHashHex(hash) {
|
|
10
|
+
return hash.map((buf) => buf.toString(16).padStart(2, "0")).join("");
|
|
11
|
+
}
|
|
12
|
+
function canonicalize(value, seen) {
|
|
13
|
+
if (value === void 0) {
|
|
14
|
+
throw new TypeError("Cannot hash undefined");
|
|
15
|
+
}
|
|
16
|
+
const valueType = typeof value;
|
|
17
|
+
if (valueType === "function" || valueType === "symbol") {
|
|
18
|
+
throw new TypeError(`Cannot hash ${valueType} values`);
|
|
19
|
+
}
|
|
20
|
+
if (value === null || valueType === "string" || valueType === "number" || valueType === "boolean") {
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
if (valueType === "bigint") {
|
|
24
|
+
throw new TypeError("Cannot hash bigint values");
|
|
25
|
+
}
|
|
26
|
+
if (typeof value.toJSON === "function") {
|
|
27
|
+
return canonicalize(value.toJSON(), seen);
|
|
28
|
+
}
|
|
29
|
+
if (Array.isArray(value)) {
|
|
30
|
+
return value.map((item) => canonicalize(item, seen));
|
|
31
|
+
}
|
|
32
|
+
if (typeof value === "object") {
|
|
33
|
+
if (seen.has(value)) {
|
|
34
|
+
throw new TypeError("Cannot hash circular references");
|
|
35
|
+
}
|
|
36
|
+
seen.add(value);
|
|
37
|
+
const entries = Object.keys(value).sort();
|
|
38
|
+
const result = {};
|
|
39
|
+
for (const key of entries) {
|
|
40
|
+
result[key] = canonicalize(value[key], seen);
|
|
41
|
+
}
|
|
42
|
+
seen.delete(value);
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
throw new TypeError(`Cannot hash unsupported value type: ${valueType}`);
|
|
46
|
+
}
|
|
47
|
+
function canonicalStringify(data) {
|
|
48
|
+
return JSON.stringify(canonicalize(data, /* @__PURE__ */ new WeakSet()));
|
|
49
|
+
}
|
|
50
|
+
async function hashBytes(input) {
|
|
51
|
+
const bytes = input instanceof Uint8Array ? input : new Uint8Array(input);
|
|
52
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", bytes);
|
|
53
|
+
return getHashHex(getHashArray(hashBuffer));
|
|
54
|
+
}
|
|
55
|
+
export { canonicalStringify as c, formatIdentityKey as f, hashBytes as h };
|
|
56
|
+
//# sourceMappingURL=utils.es-586f669f.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.es-586f669f.js","sources":["../../../utils/dist/utils.es.js"],"sourcesContent":["function getBufferCtor() {\n const maybeBuffer = globalThis.Buffer;\n return maybeBuffer != null ? maybeBuffer : null;\n}\nfunction addNewLines(str) {\n let finalString = \"\";\n while (str.length > 0) {\n finalString += str.substring(0, 64) + \"\\n\";\n str = str.substring(64);\n }\n return finalString;\n}\nfunction removeLines(str) {\n return str.replaceAll(\"\\n\", \"\");\n}\nfunction stripIdentityKey(key) {\n return key.replace(\"-----BEGIN PUBLIC KEY-----\\n\", \"\").replace(\"\\n-----END PUBLIC KEY-----\", \"\");\n}\nfunction formatIdentityKey(key) {\n return `-----BEGIN PUBLIC KEY-----\n${key}\n-----END PUBLIC KEY-----`;\n}\nfunction stripEncryptionFile(file) {\n return file.replace(\"-----BEGIN AGE ENCRYPTED FILE-----\\n\", \"\").replace(\"\\n-----END AGE ENCRYPTED FILE-----\\n\", \"\");\n}\nfunction formatEncryptionFile(file) {\n return `-----BEGIN AGE ENCRYPTED FILE-----\n${file}\n-----END AGE ENCRYPTED FILE-----\n`;\n}\nfunction generateId() {\n const uint32 = crypto.getRandomValues(new Uint32Array(1))[0];\n return uint32.toString(16);\n}\nfunction arrayBufferToBase64(arrayBuffer) {\n const byteArray = new Uint8Array(arrayBuffer);\n const bufferCtor = getBufferCtor();\n if (bufferCtor) {\n return bufferCtor.from(byteArray).toString(\"base64\");\n }\n let byteString = \"\";\n for (let i = 0; i < byteArray.byteLength; i++) {\n byteString += String.fromCharCode(byteArray[i]);\n }\n return btoa(byteString);\n}\nfunction base64ToArrayBuffer(b64) {\n const bufferCtor = getBufferCtor();\n if (bufferCtor) {\n const bytes = Uint8Array.from(\n bufferCtor.from(b64, \"base64\").toString(\"binary\"),\n (char) => char.charCodeAt(0)\n );\n return bytes.buffer.slice(\n bytes.byteOffset,\n bytes.byteOffset + bytes.byteLength\n );\n }\n const byteString = atob(b64);\n const byteArray = new Uint8Array(byteString.length);\n for (let i = 0; i < byteString.length; i++) {\n byteArray[i] = byteString.charCodeAt(i);\n }\n return byteArray.buffer;\n}\nfunction b64encode(buf) {\n return arrayBufferToBase64(buf);\n}\nfunction b64decode(str) {\n return base64ToArrayBuffer(str);\n}\nfunction encode(data) {\n const payload = typeof data === \"string\" ? data : JSON.stringify(data);\n return new TextEncoder().encode(payload);\n}\nfunction decode(data) {\n return new TextDecoder(\"utf-8\").decode(new Uint8Array(data));\n}\nfunction getHashBuffer(data) {\n return crypto.subtle.digest(\"SHA-256\", encode(data));\n}\nfunction getHashArray(hash) {\n return Array.from(new Uint8Array(hash));\n}\nfunction getHashHex(hash) {\n return hash.map((buf) => buf.toString(16).padStart(2, \"0\")).join(\"\");\n}\nfunction canonicalize(value, seen) {\n if (value === void 0) {\n throw new TypeError(\"Cannot hash undefined\");\n }\n const valueType = typeof value;\n if (valueType === \"function\" || valueType === \"symbol\") {\n throw new TypeError(`Cannot hash ${valueType} values`);\n }\n if (value === null || valueType === \"string\" || valueType === \"number\" || valueType === \"boolean\") {\n return value;\n }\n if (valueType === \"bigint\") {\n throw new TypeError(\"Cannot hash bigint values\");\n }\n if (typeof value.toJSON === \"function\") {\n return canonicalize(value.toJSON(), seen);\n }\n if (Array.isArray(value)) {\n return value.map((item) => canonicalize(item, seen));\n }\n if (typeof value === \"object\") {\n if (seen.has(value)) {\n throw new TypeError(\"Cannot hash circular references\");\n }\n seen.add(value);\n const entries = Object.keys(value).sort();\n const result = {};\n for (const key of entries) {\n result[key] = canonicalize(value[key], seen);\n }\n seen.delete(value);\n return result;\n }\n throw new TypeError(`Cannot hash unsupported value type: ${valueType}`);\n}\nfunction canonicalStringify(data) {\n return JSON.stringify(canonicalize(data, /* @__PURE__ */ new WeakSet()));\n}\nasync function hashData(data) {\n const hash_buffer = await getHashBuffer(canonicalStringify(data));\n const hash_array = getHashArray(hash_buffer);\n return getHashHex(hash_array);\n}\nasync function hashBytes(input) {\n const bytes = input instanceof Uint8Array ? input : new Uint8Array(input);\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", bytes);\n return getHashHex(getHashArray(hashBuffer));\n}\nfunction generateColorStops(primaryColor, secondaryColor, steps) {\n const colors = [];\n for (let i = 0; i <= steps; i++) {\n const ratio = i / steps;\n const color = lerpColor(primaryColor, secondaryColor, ratio);\n colors.push(color);\n }\n return colors;\n}\nfunction lerpColor(color1, color2, ratio) {\n const r1 = parseInt(color1.substring(1, 3), 16);\n const g1 = parseInt(color1.substring(3, 5), 16);\n const b1 = parseInt(color1.substring(5, 7), 16);\n const r2 = parseInt(color2.substring(1, 3), 16);\n const g2 = parseInt(color2.substring(3, 5), 16);\n const b2 = parseInt(color2.substring(5, 7), 16);\n const r = Math.round(r1 + (r2 - r1) * ratio);\n const g = Math.round(g1 + (g2 - g1) * ratio);\n const b = Math.round(b1 + (b2 - b1) * ratio);\n return `#${(1 << 24 | r << 16 | g << 8 | b).toString(16).slice(1).toUpperCase()}`;\n}\nexport { addNewLines, arrayBufferToBase64, b64decode, b64encode, base64ToArrayBuffer, canonicalStringify, decode, encode, formatEncryptionFile, formatIdentityKey, generateColorStops, generateId, getHashArray, getHashBuffer, getHashHex, hashBytes, hashData, removeLines, stripEncryptionFile, stripIdentityKey };\n"],"names":[],"mappings":"AAkBA,SAAS,kBAAkB,KAAK;AAC9B,SAAO;AAAA,EACP;AAAA;AAEF;AA6DA,SAAS,aAAa,MAAM;AAC1B,SAAO,MAAM,KAAK,IAAI,WAAW,IAAI,CAAC;AACxC;AACA,SAAS,WAAW,MAAM;AACxB,SAAO,KAAK,IAAI,CAAC,QAAQ,IAAI,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,KAAK,EAAE;AACrE;AACA,SAAS,aAAa,OAAO,MAAM;AACjC,MAAI,UAAU,QAAQ;AACpB,UAAM,IAAI,UAAU,uBAAuB;AAAA,EAC5C;AACD,QAAM,YAAY,OAAO;AACzB,MAAI,cAAc,cAAc,cAAc,UAAU;AACtD,UAAM,IAAI,UAAU,eAAe,kBAAkB;AAAA,EACtD;AACD,MAAI,UAAU,QAAQ,cAAc,YAAY,cAAc,YAAY,cAAc,WAAW;AACjG,WAAO;AAAA,EACR;AACD,MAAI,cAAc,UAAU;AAC1B,UAAM,IAAI,UAAU,2BAA2B;AAAA,EAChD;AACD,MAAI,OAAO,MAAM,WAAW,YAAY;AACtC,WAAO,aAAa,MAAM,OAAQ,GAAE,IAAI;AAAA,EACzC;AACD,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,WAAO,MAAM,IAAI,CAAC,SAAS,aAAa,MAAM,IAAI,CAAC;AAAA,EACpD;AACD,MAAI,OAAO,UAAU,UAAU;AAC7B,QAAI,KAAK,IAAI,KAAK,GAAG;AACnB,YAAM,IAAI,UAAU,iCAAiC;AAAA,IACtD;AACD,SAAK,IAAI,KAAK;AACd,UAAM,UAAU,OAAO,KAAK,KAAK,EAAE,KAAI;AACvC,UAAM,SAAS,CAAA;AACf,eAAW,OAAO,SAAS;AACzB,aAAO,OAAO,aAAa,MAAM,MAAM,IAAI;AAAA,IAC5C;AACD,SAAK,OAAO,KAAK;AACjB,WAAO;AAAA,EACR;AACD,QAAM,IAAI,UAAU,uCAAuC,WAAW;AACxE;AACA,SAAS,mBAAmB,MAAM;AAChC,SAAO,KAAK,UAAU,aAAa,MAAsB,oBAAI,QAAS,CAAA,CAAC;AACzE;AAMA,eAAe,UAAU,OAAO;AAC9B,QAAM,QAAQ,iBAAiB,aAAa,QAAQ,IAAI,WAAW,KAAK;AACxE,QAAM,aAAa,MAAM,OAAO,OAAO,OAAO,WAAW,KAAK;AAC9D,SAAO,WAAW,aAAa,UAAU,CAAC;AAC5C;;"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
import { stat, readFile, readdir, mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { resolve, basename, join, relative, dirname } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { createSealHash, createSealProof, createSealPublicKeyArtifact, parseSealProofJson, verifySealProofAgainstBytes } from "./proof.js";
|
|
5
|
+
import { SEAL_MANIFEST_VERSION, SEAL_MANIFEST_TYPE, stringifySealManifest, parseSealManifestJson } from "./manifest.js";
|
|
6
|
+
import { EXIT_SUCCESS, EXIT_HASH_MISMATCH, EXIT_SIGNATURE_INVALID, SealCliError, EXIT_FAILURE, EXIT_INVALID_PROOF, EXIT_KEY_CONFIG, getExitCode } from "./errors.js";
|
|
7
|
+
import "./chunks/utils.es-586f669f.js";
|
|
8
|
+
import "./crypto.js";
|
|
9
|
+
function normalizeRelativePath(value) {
|
|
10
|
+
return value.split("\\").join("/");
|
|
11
|
+
}
|
|
12
|
+
async function collectFiles(rootPath, currentPath, files) {
|
|
13
|
+
const entries = await readdir(currentPath, { withFileTypes: true });
|
|
14
|
+
const sorted = entries.filter((entry) => entry.name !== ".DS_Store").sort((a, b) => a.name.localeCompare(b.name));
|
|
15
|
+
for (const entry of sorted) {
|
|
16
|
+
const entryPath = join(currentPath, entry.name);
|
|
17
|
+
if (entry.isDirectory()) {
|
|
18
|
+
await collectFiles(rootPath, entryPath, files);
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if (!entry.isFile()) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
const bytes = await readFile(entryPath);
|
|
25
|
+
const relativePath = normalizeRelativePath(relative(rootPath, entryPath));
|
|
26
|
+
files[relativePath] = await createSealHash(bytes);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async function createManifestArtifact(inputPath) {
|
|
30
|
+
const resolvedInput = resolve(inputPath);
|
|
31
|
+
const inputStat = await stat(resolvedInput);
|
|
32
|
+
const root = basename(resolvedInput);
|
|
33
|
+
const files = {};
|
|
34
|
+
if (inputStat.isDirectory()) {
|
|
35
|
+
await collectFiles(resolvedInput, resolvedInput, files);
|
|
36
|
+
} else if (inputStat.isFile()) {
|
|
37
|
+
const bytes = await readFile(resolvedInput);
|
|
38
|
+
files[root] = await createSealHash(bytes);
|
|
39
|
+
} else {
|
|
40
|
+
throw new Error("Manifest input must be a file or directory.");
|
|
41
|
+
}
|
|
42
|
+
const manifest = {
|
|
43
|
+
version: SEAL_MANIFEST_VERSION,
|
|
44
|
+
type: SEAL_MANIFEST_TYPE,
|
|
45
|
+
root,
|
|
46
|
+
files: Object.fromEntries(
|
|
47
|
+
Object.entries(files).sort(([left], [right]) => left.localeCompare(right))
|
|
48
|
+
)
|
|
49
|
+
};
|
|
50
|
+
return {
|
|
51
|
+
manifest,
|
|
52
|
+
content: `${stringifySealManifest(manifest)}
|
|
53
|
+
`
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
async function createProofArtifact(params) {
|
|
57
|
+
const bytes = await readFile(params.inputPath);
|
|
58
|
+
const raw = new TextDecoder().decode(bytes);
|
|
59
|
+
const parsedManifest = parseSealManifestJson(raw);
|
|
60
|
+
const proof = await createSealProof({
|
|
61
|
+
signer: {
|
|
62
|
+
privateKeyPem: params.privateKeyPem,
|
|
63
|
+
publicKeyPem: params.publicKeyPem
|
|
64
|
+
},
|
|
65
|
+
subject: {
|
|
66
|
+
kind: parsedManifest.ok ? "manifest" : "file",
|
|
67
|
+
path: basename(params.inputPath),
|
|
68
|
+
hash: await createSealHash(bytes)
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
return {
|
|
72
|
+
proof,
|
|
73
|
+
content: `${JSON.stringify(proof, null, 2)}
|
|
74
|
+
`
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
async function createPublicKeyArtifact(params) {
|
|
78
|
+
return createSealPublicKeyArtifact({
|
|
79
|
+
privateKeyPem: params.privateKeyPem,
|
|
80
|
+
publicKeyPem: params.publicKeyPem
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
async function verifyProofArtifact(params) {
|
|
84
|
+
const rawProof = await readFile(params.proofPath, "utf8");
|
|
85
|
+
const parsed = parseSealProofJson(rawProof);
|
|
86
|
+
if (!parsed.ok || !parsed.proof) {
|
|
87
|
+
throw new Error(parsed.errors.join(" "));
|
|
88
|
+
}
|
|
89
|
+
const subjectBytes = await readFile(params.inputPath);
|
|
90
|
+
const result = await verifySealProofAgainstBytes(parsed.proof, subjectBytes);
|
|
91
|
+
return {
|
|
92
|
+
proof: parsed.proof,
|
|
93
|
+
result
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function parseArgs(argv) {
|
|
97
|
+
const result = { _: [], flags: {} };
|
|
98
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
99
|
+
const arg = argv[index];
|
|
100
|
+
if (!arg.startsWith("--")) {
|
|
101
|
+
result._.push(arg);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
const [rawKey, inlineValue] = arg.slice(2).split("=");
|
|
105
|
+
const key = rawKey.trim();
|
|
106
|
+
const next = argv[index + 1];
|
|
107
|
+
const hasNextValue = inlineValue === void 0 && next && !next.startsWith("--");
|
|
108
|
+
const value = inlineValue ?? (hasNextValue ? next : void 0);
|
|
109
|
+
if (hasNextValue) {
|
|
110
|
+
index += 1;
|
|
111
|
+
}
|
|
112
|
+
if (value === void 0) {
|
|
113
|
+
result.flags[key] = true;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
const existing = result.flags[key];
|
|
117
|
+
if (existing === void 0) {
|
|
118
|
+
result.flags[key] = value;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (Array.isArray(existing)) {
|
|
122
|
+
existing.push(value);
|
|
123
|
+
result.flags[key] = existing;
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
result.flags[key] = [String(existing), value];
|
|
127
|
+
}
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
function getFlag(flags, key) {
|
|
131
|
+
const value = flags[key];
|
|
132
|
+
if (Array.isArray(value)) {
|
|
133
|
+
return value[value.length - 1];
|
|
134
|
+
}
|
|
135
|
+
return typeof value === "string" ? value : void 0;
|
|
136
|
+
}
|
|
137
|
+
function hasFlag(flags, key) {
|
|
138
|
+
return flags[key] === true;
|
|
139
|
+
}
|
|
140
|
+
function requireFlag(flags, key) {
|
|
141
|
+
const value = getFlag(flags, key);
|
|
142
|
+
if (!value) {
|
|
143
|
+
throw new SealCliError(`Missing --${key}`, EXIT_FAILURE);
|
|
144
|
+
}
|
|
145
|
+
return value;
|
|
146
|
+
}
|
|
147
|
+
function getEnvVar(env, name) {
|
|
148
|
+
const value = env[name];
|
|
149
|
+
return value && value.trim().length > 0 ? value : void 0;
|
|
150
|
+
}
|
|
151
|
+
async function writeOutputFile(filePath, content) {
|
|
152
|
+
const resolvedPath = resolve(filePath);
|
|
153
|
+
await mkdir(dirname(resolvedPath), { recursive: true });
|
|
154
|
+
await writeFile(resolvedPath, content, "utf8");
|
|
155
|
+
}
|
|
156
|
+
function outputResult(writer, json, quiet, value) {
|
|
157
|
+
if (quiet) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (typeof value === "string") {
|
|
161
|
+
writer.stdout(`${value}
|
|
162
|
+
`);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (json) {
|
|
166
|
+
writer.stdout(`${JSON.stringify(value, null, 2)}
|
|
167
|
+
`);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
writer.stdout(`${JSON.stringify(value, null, 2)}
|
|
171
|
+
`);
|
|
172
|
+
}
|
|
173
|
+
function outputError(writer, json, error) {
|
|
174
|
+
const exitCode = getExitCode(error);
|
|
175
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
176
|
+
if (json) {
|
|
177
|
+
writer.stderr(
|
|
178
|
+
`${JSON.stringify({ error: message, exitCode }, null, 2)}
|
|
179
|
+
`
|
|
180
|
+
);
|
|
181
|
+
} else {
|
|
182
|
+
writer.stderr(`${message}
|
|
183
|
+
`);
|
|
184
|
+
}
|
|
185
|
+
return exitCode;
|
|
186
|
+
}
|
|
187
|
+
function readSigningEnv(env) {
|
|
188
|
+
const privateKeyPem = getEnvVar(env, "SEAL_PRIVATE_KEY");
|
|
189
|
+
if (!privateKeyPem) {
|
|
190
|
+
throw new SealCliError(
|
|
191
|
+
"Missing SEAL_PRIVATE_KEY environment variable.",
|
|
192
|
+
EXIT_KEY_CONFIG
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
privateKeyPem,
|
|
197
|
+
publicKeyPem: getEnvVar(env, "SEAL_PUBLIC_KEY")
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
async function runCli(argv, params = {}) {
|
|
201
|
+
const parsed = parseArgs(argv);
|
|
202
|
+
const env = params.env ?? process.env;
|
|
203
|
+
const writer = params.writer ?? {
|
|
204
|
+
stdout: (value) => process.stdout.write(value),
|
|
205
|
+
stderr: (value) => process.stderr.write(value)
|
|
206
|
+
};
|
|
207
|
+
const json = hasFlag(parsed.flags, "json");
|
|
208
|
+
const quiet = hasFlag(parsed.flags, "quiet");
|
|
209
|
+
try {
|
|
210
|
+
const [command, subcommand] = parsed._;
|
|
211
|
+
if (command === "manifest" && subcommand === "create") {
|
|
212
|
+
const artifact = await createManifestArtifact(requireFlag(parsed.flags, "input"));
|
|
213
|
+
const outPath = getFlag(parsed.flags, "out");
|
|
214
|
+
if (outPath) {
|
|
215
|
+
await writeOutputFile(outPath, artifact.content);
|
|
216
|
+
outputResult(writer, json, quiet, json ? artifact.manifest : outPath);
|
|
217
|
+
} else {
|
|
218
|
+
outputResult(writer, true, quiet, artifact.manifest);
|
|
219
|
+
}
|
|
220
|
+
return EXIT_SUCCESS;
|
|
221
|
+
}
|
|
222
|
+
if (command === "sign") {
|
|
223
|
+
const signingEnv = readSigningEnv(env);
|
|
224
|
+
const artifact = await createProofArtifact({
|
|
225
|
+
inputPath: requireFlag(parsed.flags, "input"),
|
|
226
|
+
...signingEnv
|
|
227
|
+
});
|
|
228
|
+
const outPath = getFlag(parsed.flags, "out");
|
|
229
|
+
if (outPath) {
|
|
230
|
+
await writeOutputFile(outPath, artifact.content);
|
|
231
|
+
outputResult(writer, json, quiet, json ? artifact.proof : outPath);
|
|
232
|
+
} else {
|
|
233
|
+
outputResult(writer, true, quiet, artifact.proof);
|
|
234
|
+
}
|
|
235
|
+
return EXIT_SUCCESS;
|
|
236
|
+
}
|
|
237
|
+
if (command === "verify") {
|
|
238
|
+
const proofPath = requireFlag(parsed.flags, "proof");
|
|
239
|
+
const inputPath = requireFlag(parsed.flags, "input");
|
|
240
|
+
const { result } = await verifyProofArtifact({ proofPath, inputPath });
|
|
241
|
+
outputResult(
|
|
242
|
+
writer,
|
|
243
|
+
json,
|
|
244
|
+
quiet,
|
|
245
|
+
json ? result : [
|
|
246
|
+
`valid=${result.valid}`,
|
|
247
|
+
`hashMatch=${result.hashMatch}`,
|
|
248
|
+
`signatureValid=${result.signatureValid}`,
|
|
249
|
+
`keyId=${result.keyId}`,
|
|
250
|
+
`algorithm=${result.algorithm}`,
|
|
251
|
+
`subjectHash=${result.subjectHash}`
|
|
252
|
+
].join("\n")
|
|
253
|
+
);
|
|
254
|
+
if (!result.hashMatch) {
|
|
255
|
+
return EXIT_HASH_MISMATCH;
|
|
256
|
+
}
|
|
257
|
+
if (!result.signatureValid) {
|
|
258
|
+
return EXIT_SIGNATURE_INVALID;
|
|
259
|
+
}
|
|
260
|
+
return EXIT_SUCCESS;
|
|
261
|
+
}
|
|
262
|
+
if (command === "public-key") {
|
|
263
|
+
const artifact = await createPublicKeyArtifact(readSigningEnv(env));
|
|
264
|
+
outputResult(writer, true, quiet, artifact);
|
|
265
|
+
return EXIT_SUCCESS;
|
|
266
|
+
}
|
|
267
|
+
throw new SealCliError(
|
|
268
|
+
"Usage: seal manifest create --input <path> [--out <path>] [--json] [--quiet]\n seal sign --input <path> [--out <path>] [--json] [--quiet]\n seal verify --proof <proof.json> --input <path> [--json] [--quiet]\n seal public-key [--json] [--quiet]",
|
|
269
|
+
EXIT_FAILURE
|
|
270
|
+
);
|
|
271
|
+
} catch (error) {
|
|
272
|
+
if (error instanceof Error && error.message.includes("Proof")) {
|
|
273
|
+
return outputError(
|
|
274
|
+
writer,
|
|
275
|
+
json,
|
|
276
|
+
new SealCliError(error.message, EXIT_INVALID_PROOF)
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
if (error instanceof Error && (error.message.includes("public key") || error.message.includes("SEAL_PRIVATE_KEY") || error.message.includes("private key"))) {
|
|
280
|
+
return outputError(
|
|
281
|
+
writer,
|
|
282
|
+
json,
|
|
283
|
+
new SealCliError(error.message, EXIT_KEY_CONFIG)
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
return outputError(writer, json, error);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
const isDirectRun = typeof process !== "undefined" && process.argv[1] && fileURLToPath(import.meta.url) === resolve(process.argv[1]);
|
|
290
|
+
if (isDirectRun) {
|
|
291
|
+
runCli(process.argv.slice(2)).then((exitCode) => {
|
|
292
|
+
process.exitCode = exitCode;
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
export { runCli };
|
|
296
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sources":["../src/commands/manifest.ts","../src/commands/sign.ts","../src/commands/publicKey.ts","../src/commands/verify.ts","../src/cli.ts"],"sourcesContent":["import { readdir, readFile, stat } from \"node:fs/promises\";\nimport { basename, join, relative, resolve } from \"node:path\";\nimport { createSealHash } from \"../proof\";\nimport {\n SEAL_MANIFEST_TYPE,\n SEAL_MANIFEST_VERSION,\n stringifySealManifest,\n type SealManifestV1,\n} from \"../manifest\";\n\nfunction normalizeRelativePath(value: string): string {\n return value.split(\"\\\\\").join(\"/\");\n}\n\nasync function collectFiles(\n rootPath: string,\n currentPath: string,\n files: Record<string, SealManifestV1[\"files\"][string]>\n): Promise<void> {\n const entries = await readdir(currentPath, { withFileTypes: true });\n const sorted = entries\n .filter((entry) => entry.name !== \".DS_Store\")\n .sort((a, b) => a.name.localeCompare(b.name));\n\n for (const entry of sorted) {\n const entryPath = join(currentPath, entry.name);\n if (entry.isDirectory()) {\n await collectFiles(rootPath, entryPath, files);\n continue;\n }\n if (!entry.isFile()) {\n continue;\n }\n const bytes = await readFile(entryPath);\n const relativePath = normalizeRelativePath(relative(rootPath, entryPath));\n files[relativePath] = await createSealHash(bytes);\n }\n}\n\nexport async function createManifestArtifact(inputPath: string): Promise<{\n manifest: SealManifestV1;\n content: string;\n}> {\n const resolvedInput = resolve(inputPath);\n const inputStat = await stat(resolvedInput);\n const root = basename(resolvedInput);\n const files: SealManifestV1[\"files\"] = {};\n\n if (inputStat.isDirectory()) {\n await collectFiles(resolvedInput, resolvedInput, files);\n } else if (inputStat.isFile()) {\n const bytes = await readFile(resolvedInput);\n files[root] = await createSealHash(bytes);\n } else {\n throw new Error(\"Manifest input must be a file or directory.\");\n }\n\n const manifest: SealManifestV1 = {\n version: SEAL_MANIFEST_VERSION,\n type: SEAL_MANIFEST_TYPE,\n root,\n files: Object.fromEntries(\n Object.entries(files).sort(([left], [right]) => left.localeCompare(right))\n ),\n };\n\n return {\n manifest,\n content: `${stringifySealManifest(manifest)}\\n`,\n };\n}\n","import { basename } from \"node:path\";\nimport { readFile } from \"node:fs/promises\";\nimport { parseSealManifestJson } from \"../manifest\";\nimport { createSealProof, createSealHash, type SealProofV1 } from \"../proof\";\n\nexport async function createProofArtifact(params: {\n inputPath: string;\n privateKeyPem: string;\n publicKeyPem?: string;\n}): Promise<{\n proof: SealProofV1;\n content: string;\n}> {\n const bytes = await readFile(params.inputPath);\n const raw = new TextDecoder().decode(bytes);\n const parsedManifest = parseSealManifestJson(raw);\n const proof = await createSealProof({\n signer: {\n privateKeyPem: params.privateKeyPem,\n publicKeyPem: params.publicKeyPem,\n },\n subject: {\n kind: parsedManifest.ok ? \"manifest\" : \"file\",\n path: basename(params.inputPath),\n hash: await createSealHash(bytes),\n },\n });\n\n return {\n proof,\n content: `${JSON.stringify(proof, null, 2)}\\n`,\n };\n}\n","import { createSealPublicKeyArtifact } from \"../proof\";\n\nexport async function createPublicKeyArtifact(params: {\n privateKeyPem: string;\n publicKeyPem?: string;\n}) {\n return createSealPublicKeyArtifact({\n privateKeyPem: params.privateKeyPem,\n publicKeyPem: params.publicKeyPem,\n });\n}\n","import { readFile } from \"node:fs/promises\";\nimport {\n parseSealProofJson,\n verifySealProofAgainstBytes,\n type SealProofV1,\n} from \"../proof\";\n\nexport type VerifyArtifactResult = {\n valid: boolean;\n hashMatch: boolean;\n signatureValid: boolean;\n keyId: string;\n algorithm: \"ECDSA-P256-SHA256\";\n subjectHash: `sha256:${string}`;\n};\n\nexport async function verifyProofArtifact(params: {\n proofPath: string;\n inputPath: string;\n}): Promise<{\n proof: SealProofV1;\n result: VerifyArtifactResult;\n}> {\n const rawProof = await readFile(params.proofPath, \"utf8\");\n const parsed = parseSealProofJson(rawProof);\n if (!parsed.ok || !parsed.proof) {\n throw new Error(parsed.errors.join(\" \"));\n }\n\n const subjectBytes = await readFile(params.inputPath);\n const result = await verifySealProofAgainstBytes(parsed.proof, subjectBytes);\n return {\n proof: parsed.proof,\n result,\n };\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { createManifestArtifact } from \"./commands/manifest\";\nimport { createProofArtifact } from \"./commands/sign\";\nimport { createPublicKeyArtifact } from \"./commands/publicKey\";\nimport { verifyProofArtifact } from \"./commands/verify\";\nimport {\n EXIT_FAILURE,\n EXIT_HASH_MISMATCH,\n EXIT_INVALID_PROOF,\n EXIT_KEY_CONFIG,\n EXIT_SIGNATURE_INVALID,\n EXIT_SUCCESS,\n SealCliError,\n getExitCode,\n} from \"./errors\";\n\ntype ProcessEnvLike = Record<string, string | undefined>;\n\ndeclare const process: {\n argv: string[];\n env: ProcessEnvLike;\n stdout: { write: (value: string) => void };\n stderr: { write: (value: string) => void };\n exitCode?: number;\n};\n\ntype ParsedArgs = {\n _: string[];\n flags: Record<string, string | boolean | string[]>;\n};\n\ntype OutputWriter = {\n stdout: (value: string) => void;\n stderr: (value: string) => void;\n};\n\nfunction parseArgs(argv: string[]): ParsedArgs {\n const result: ParsedArgs = { _: [], flags: {} };\n for (let index = 0; index < argv.length; index += 1) {\n const arg = argv[index];\n if (!arg.startsWith(\"--\")) {\n result._.push(arg);\n continue;\n }\n\n const [rawKey, inlineValue] = arg.slice(2).split(\"=\");\n const key = rawKey.trim();\n const next = argv[index + 1];\n const hasNextValue = inlineValue === undefined && next && !next.startsWith(\"--\");\n const value = inlineValue ?? (hasNextValue ? next : undefined);\n\n if (hasNextValue) {\n index += 1;\n }\n\n if (value === undefined) {\n result.flags[key] = true;\n continue;\n }\n\n const existing = result.flags[key];\n if (existing === undefined) {\n result.flags[key] = value;\n continue;\n }\n\n if (Array.isArray(existing)) {\n existing.push(value);\n result.flags[key] = existing;\n continue;\n }\n\n result.flags[key] = [String(existing), value];\n }\n\n return result;\n}\n\nfunction getFlag(flags: ParsedArgs[\"flags\"], key: string): string | undefined {\n const value = flags[key];\n if (Array.isArray(value)) {\n return value[value.length - 1];\n }\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction hasFlag(flags: ParsedArgs[\"flags\"], key: string): boolean {\n return flags[key] === true;\n}\n\nfunction requireFlag(flags: ParsedArgs[\"flags\"], key: string): string {\n const value = getFlag(flags, key);\n if (!value) {\n throw new SealCliError(`Missing --${key}`, EXIT_FAILURE);\n }\n return value;\n}\n\nfunction getEnvVar(env: ProcessEnvLike, name: string): string | undefined {\n const value = env[name];\n return value && value.trim().length > 0 ? value : undefined;\n}\n\nasync function writeOutputFile(filePath: string, content: string): Promise<void> {\n const resolvedPath = resolve(filePath);\n await mkdir(dirname(resolvedPath), { recursive: true });\n await writeFile(resolvedPath, content, \"utf8\");\n}\n\nfunction outputResult(\n writer: OutputWriter,\n json: boolean,\n quiet: boolean,\n value: unknown\n): void {\n if (quiet) {\n return;\n }\n\n if (typeof value === \"string\") {\n writer.stdout(`${value}\\n`);\n return;\n }\n\n if (json) {\n writer.stdout(`${JSON.stringify(value, null, 2)}\\n`);\n return;\n }\n\n writer.stdout(`${JSON.stringify(value, null, 2)}\\n`);\n}\n\nfunction outputError(\n writer: OutputWriter,\n json: boolean,\n error: unknown\n): number {\n const exitCode = getExitCode(error);\n const message = error instanceof Error ? error.message : String(error);\n if (json) {\n writer.stderr(\n `${JSON.stringify({ error: message, exitCode }, null, 2)}\\n`\n );\n } else {\n writer.stderr(`${message}\\n`);\n }\n return exitCode;\n}\n\nfunction readSigningEnv(env: ProcessEnvLike): {\n privateKeyPem: string;\n publicKeyPem?: string;\n} {\n const privateKeyPem = getEnvVar(env, \"SEAL_PRIVATE_KEY\");\n if (!privateKeyPem) {\n throw new SealCliError(\n \"Missing SEAL_PRIVATE_KEY environment variable.\",\n EXIT_KEY_CONFIG\n );\n }\n\n return {\n privateKeyPem,\n publicKeyPem: getEnvVar(env, \"SEAL_PUBLIC_KEY\"),\n };\n}\n\nexport async function runCli(\n argv: string[],\n params: {\n env?: ProcessEnvLike;\n writer?: OutputWriter;\n } = {}\n): Promise<number> {\n const parsed = parseArgs(argv);\n const env = params.env ?? process.env;\n const writer: OutputWriter = params.writer ?? {\n stdout: (value) => process.stdout.write(value),\n stderr: (value) => process.stderr.write(value),\n };\n const json = hasFlag(parsed.flags, \"json\");\n const quiet = hasFlag(parsed.flags, \"quiet\");\n\n try {\n const [command, subcommand] = parsed._;\n\n if (command === \"manifest\" && subcommand === \"create\") {\n const artifact = await createManifestArtifact(requireFlag(parsed.flags, \"input\"));\n const outPath = getFlag(parsed.flags, \"out\");\n if (outPath) {\n await writeOutputFile(outPath, artifact.content);\n outputResult(writer, json, quiet, json ? artifact.manifest : outPath);\n } else {\n outputResult(writer, true, quiet, artifact.manifest);\n }\n return EXIT_SUCCESS;\n }\n\n if (command === \"sign\") {\n const signingEnv = readSigningEnv(env);\n const artifact = await createProofArtifact({\n inputPath: requireFlag(parsed.flags, \"input\"),\n ...signingEnv,\n });\n const outPath = getFlag(parsed.flags, \"out\");\n if (outPath) {\n await writeOutputFile(outPath, artifact.content);\n outputResult(writer, json, quiet, json ? artifact.proof : outPath);\n } else {\n outputResult(writer, true, quiet, artifact.proof);\n }\n return EXIT_SUCCESS;\n }\n\n if (command === \"verify\") {\n const proofPath = requireFlag(parsed.flags, \"proof\");\n const inputPath = requireFlag(parsed.flags, \"input\");\n const { result } = await verifyProofArtifact({ proofPath, inputPath });\n outputResult(\n writer,\n json,\n quiet,\n json\n ? result\n : [\n `valid=${result.valid}`,\n `hashMatch=${result.hashMatch}`,\n `signatureValid=${result.signatureValid}`,\n `keyId=${result.keyId}`,\n `algorithm=${result.algorithm}`,\n `subjectHash=${result.subjectHash}`,\n ].join(\"\\n\")\n );\n\n if (!result.hashMatch) {\n return EXIT_HASH_MISMATCH;\n }\n if (!result.signatureValid) {\n return EXIT_SIGNATURE_INVALID;\n }\n return EXIT_SUCCESS;\n }\n\n if (command === \"public-key\") {\n const artifact = await createPublicKeyArtifact(readSigningEnv(env));\n outputResult(writer, true, quiet, artifact);\n return EXIT_SUCCESS;\n }\n\n throw new SealCliError(\n \"Usage: seal manifest create --input <path> [--out <path>] [--json] [--quiet]\\n\" +\n \" seal sign --input <path> [--out <path>] [--json] [--quiet]\\n\" +\n \" seal verify --proof <proof.json> --input <path> [--json] [--quiet]\\n\" +\n \" seal public-key [--json] [--quiet]\",\n EXIT_FAILURE\n );\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"Proof\")) {\n return outputError(\n writer,\n json,\n new SealCliError(error.message, EXIT_INVALID_PROOF)\n );\n }\n if (\n error instanceof Error &&\n (error.message.includes(\"public key\") ||\n error.message.includes(\"SEAL_PRIVATE_KEY\") ||\n error.message.includes(\"private key\"))\n ) {\n return outputError(\n writer,\n json,\n new SealCliError(error.message, EXIT_KEY_CONFIG)\n );\n }\n return outputError(writer, json, error);\n }\n}\n\nconst isDirectRun =\n typeof process !== \"undefined\" &&\n process.argv[1] &&\n fileURLToPath(import.meta.url) === resolve(process.argv[1]);\n\nif (isDirectRun) {\n runCli(process.argv.slice(2)).then((exitCode) => {\n process.exitCode = exitCode;\n });\n}\n"],"names":[],"mappings":"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"}
|
package/dist/crypto.js
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { f as formatIdentityKey } from "./chunks/utils.es-586f669f.js";
|
|
2
|
+
function getBufferCtor() {
|
|
3
|
+
const maybeBuffer = globalThis.Buffer;
|
|
4
|
+
return maybeBuffer != null ? maybeBuffer : null;
|
|
5
|
+
}
|
|
6
|
+
function addNewLines(str) {
|
|
7
|
+
let finalString = "";
|
|
8
|
+
while (str.length > 0) {
|
|
9
|
+
finalString += str.substring(0, 64) + "\n";
|
|
10
|
+
str = str.substring(64);
|
|
11
|
+
}
|
|
12
|
+
return finalString;
|
|
13
|
+
}
|
|
14
|
+
function removeLines(str) {
|
|
15
|
+
return str.replaceAll("\n", "");
|
|
16
|
+
}
|
|
17
|
+
function arrayBufferToBase64(arrayBuffer) {
|
|
18
|
+
const byteArray = new Uint8Array(arrayBuffer);
|
|
19
|
+
const bufferCtor = getBufferCtor();
|
|
20
|
+
if (bufferCtor) {
|
|
21
|
+
return bufferCtor.from(byteArray).toString("base64");
|
|
22
|
+
}
|
|
23
|
+
let byteString = "";
|
|
24
|
+
for (let i = 0; i < byteArray.byteLength; i++) {
|
|
25
|
+
byteString += String.fromCharCode(byteArray[i]);
|
|
26
|
+
}
|
|
27
|
+
return btoa(byteString);
|
|
28
|
+
}
|
|
29
|
+
function base64ToArrayBuffer(b64) {
|
|
30
|
+
const bufferCtor = getBufferCtor();
|
|
31
|
+
if (bufferCtor) {
|
|
32
|
+
const bytes = Uint8Array.from(
|
|
33
|
+
bufferCtor.from(b64, "base64").toString("binary"),
|
|
34
|
+
(char) => char.charCodeAt(0)
|
|
35
|
+
);
|
|
36
|
+
return bytes.buffer.slice(
|
|
37
|
+
bytes.byteOffset,
|
|
38
|
+
bytes.byteOffset + bytes.byteLength
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
const byteString = atob(b64);
|
|
42
|
+
const byteArray = new Uint8Array(byteString.length);
|
|
43
|
+
for (let i = 0; i < byteString.length; i++) {
|
|
44
|
+
byteArray[i] = byteString.charCodeAt(i);
|
|
45
|
+
}
|
|
46
|
+
return byteArray.buffer;
|
|
47
|
+
}
|
|
48
|
+
function b64encode(buf) {
|
|
49
|
+
return arrayBufferToBase64(buf);
|
|
50
|
+
}
|
|
51
|
+
function b64decode(str) {
|
|
52
|
+
return base64ToArrayBuffer(str);
|
|
53
|
+
}
|
|
54
|
+
function encode(data) {
|
|
55
|
+
const payload = typeof data === "string" ? data : JSON.stringify(data);
|
|
56
|
+
return new TextEncoder().encode(payload);
|
|
57
|
+
}
|
|
58
|
+
function getHashBuffer(data) {
|
|
59
|
+
return crypto.subtle.digest("SHA-256", encode(data));
|
|
60
|
+
}
|
|
61
|
+
function getHashArray(hash) {
|
|
62
|
+
return Array.from(new Uint8Array(hash));
|
|
63
|
+
}
|
|
64
|
+
function getHashHex(hash) {
|
|
65
|
+
return hash.map((buf) => buf.toString(16).padStart(2, "0")).join("");
|
|
66
|
+
}
|
|
67
|
+
function canonicalize(value, seen) {
|
|
68
|
+
if (value === void 0) {
|
|
69
|
+
throw new TypeError("Cannot hash undefined");
|
|
70
|
+
}
|
|
71
|
+
const valueType = typeof value;
|
|
72
|
+
if (valueType === "function" || valueType === "symbol") {
|
|
73
|
+
throw new TypeError(`Cannot hash ${valueType} values`);
|
|
74
|
+
}
|
|
75
|
+
if (value === null || valueType === "string" || valueType === "number" || valueType === "boolean") {
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
if (valueType === "bigint") {
|
|
79
|
+
throw new TypeError("Cannot hash bigint values");
|
|
80
|
+
}
|
|
81
|
+
if (typeof value.toJSON === "function") {
|
|
82
|
+
return canonicalize(value.toJSON(), seen);
|
|
83
|
+
}
|
|
84
|
+
if (Array.isArray(value)) {
|
|
85
|
+
return value.map((item) => canonicalize(item, seen));
|
|
86
|
+
}
|
|
87
|
+
if (typeof value === "object") {
|
|
88
|
+
if (seen.has(value)) {
|
|
89
|
+
throw new TypeError("Cannot hash circular references");
|
|
90
|
+
}
|
|
91
|
+
seen.add(value);
|
|
92
|
+
const entries = Object.keys(value).sort();
|
|
93
|
+
const result = {};
|
|
94
|
+
for (const key of entries) {
|
|
95
|
+
result[key] = canonicalize(value[key], seen);
|
|
96
|
+
}
|
|
97
|
+
seen.delete(value);
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
throw new TypeError(`Cannot hash unsupported value type: ${valueType}`);
|
|
101
|
+
}
|
|
102
|
+
function canonicalStringify(data) {
|
|
103
|
+
return JSON.stringify(canonicalize(data, /* @__PURE__ */ new WeakSet()));
|
|
104
|
+
}
|
|
105
|
+
async function hashData(data) {
|
|
106
|
+
const hash_buffer = await getHashBuffer(canonicalStringify(data));
|
|
107
|
+
const hash_array = getHashArray(hash_buffer);
|
|
108
|
+
return getHashHex(hash_array);
|
|
109
|
+
}
|
|
110
|
+
async function importPrivateKeyFromPem(key) {
|
|
111
|
+
const b64key = key.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "");
|
|
112
|
+
return crypto.subtle.importKey(
|
|
113
|
+
"pkcs8",
|
|
114
|
+
base64ToArrayBuffer(removeLines(b64key)),
|
|
115
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
116
|
+
true,
|
|
117
|
+
["sign"]
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
async function exportPrivateKey(privateKey) {
|
|
121
|
+
return crypto.subtle.exportKey("jwk", privateKey);
|
|
122
|
+
}
|
|
123
|
+
function importPublicKey(points) {
|
|
124
|
+
return crypto.subtle.importKey(
|
|
125
|
+
"jwk",
|
|
126
|
+
{
|
|
127
|
+
crv: "P-256",
|
|
128
|
+
ext: true,
|
|
129
|
+
kty: "EC",
|
|
130
|
+
...points
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: "ECDSA",
|
|
134
|
+
namedCurve: "P-256"
|
|
135
|
+
},
|
|
136
|
+
true,
|
|
137
|
+
["verify"]
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
async function importPublicKeyFromPem(key) {
|
|
141
|
+
const b64key = key.replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLIC KEY-----", "");
|
|
142
|
+
return crypto.subtle.importKey(
|
|
143
|
+
"spki",
|
|
144
|
+
base64ToArrayBuffer(removeLines(b64key)),
|
|
145
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
146
|
+
true,
|
|
147
|
+
["verify"]
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
async function exportPublicKey(key) {
|
|
151
|
+
const exported = await crypto.subtle.exportKey("spki", key);
|
|
152
|
+
return b64encode(exported);
|
|
153
|
+
}
|
|
154
|
+
async function exportPublicKeyAsPem(key) {
|
|
155
|
+
const exportedPublicKey = await crypto.subtle.exportKey("spki", key);
|
|
156
|
+
return `-----BEGIN PUBLIC KEY-----
|
|
157
|
+
${addNewLines(arrayBufferToBase64(exportedPublicKey))}-----END PUBLIC KEY-----`;
|
|
158
|
+
}
|
|
159
|
+
async function derivePublicFromPrivatePEM(privateKeyPEM) {
|
|
160
|
+
const key = await importPrivateKeyFromPem(privateKeyPEM);
|
|
161
|
+
const priv = await exportPrivateKey(key);
|
|
162
|
+
const pub = await importPublicKey({ x: priv.x, y: priv.y });
|
|
163
|
+
return exportPublicKeyAsPem(pub);
|
|
164
|
+
}
|
|
165
|
+
async function signBytes(signingKey, data) {
|
|
166
|
+
const bytes = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
167
|
+
const signatureBuffer = await crypto.subtle.sign(
|
|
168
|
+
{
|
|
169
|
+
name: "ECDSA",
|
|
170
|
+
hash: {
|
|
171
|
+
name: "SHA-256"
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
signingKey,
|
|
175
|
+
bytes
|
|
176
|
+
);
|
|
177
|
+
return b64encode(signatureBuffer);
|
|
178
|
+
}
|
|
179
|
+
async function verifyBytes(signature, data, publicKey) {
|
|
180
|
+
const bytes = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
181
|
+
return crypto.subtle.verify(
|
|
182
|
+
{
|
|
183
|
+
name: "ECDSA",
|
|
184
|
+
hash: { name: "SHA-256" }
|
|
185
|
+
},
|
|
186
|
+
publicKey,
|
|
187
|
+
b64decode(signature),
|
|
188
|
+
bytes
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
function normalizePublicKeyBody(publicKeyBase64) {
|
|
192
|
+
return addNewLines(publicKeyBase64).trimEnd();
|
|
193
|
+
}
|
|
194
|
+
async function deriveKeyIdFromPublicKeyBase64(publicKeyBase64) {
|
|
195
|
+
return hashData(normalizePublicKeyBody(publicKeyBase64));
|
|
196
|
+
}
|
|
197
|
+
async function deriveKeyIdFromPublicKey(publicKey) {
|
|
198
|
+
const publicKeyBase64 = await exportPublicKey(publicKey);
|
|
199
|
+
return deriveKeyIdFromPublicKeyBase64(publicKeyBase64);
|
|
200
|
+
}
|
|
201
|
+
function utf8Bytes(value) {
|
|
202
|
+
return new TextEncoder().encode(value);
|
|
203
|
+
}
|
|
204
|
+
async function importPublicKeyFromBase64(publicKeyBase64) {
|
|
205
|
+
return importPublicKeyFromPem(formatIdentityKey(publicKeyBase64));
|
|
206
|
+
}
|
|
207
|
+
async function exportPublicKeyBase64(key) {
|
|
208
|
+
return exportPublicKey(key);
|
|
209
|
+
}
|
|
210
|
+
async function derivePublicKeyBase64FromPrivateKeyPem(privateKeyPem) {
|
|
211
|
+
const publicKeyPem = await derivePublicFromPrivatePEM(privateKeyPem);
|
|
212
|
+
const publicKey = await importPublicKeyFromPem(publicKeyPem);
|
|
213
|
+
return exportPublicKeyBase64(publicKey);
|
|
214
|
+
}
|
|
215
|
+
async function resolveSealSigner(input) {
|
|
216
|
+
const privateKey = await importPrivateKeyFromPem(input.privateKeyPem);
|
|
217
|
+
const publicKeyPem = input.publicKeyPem ? input.publicKeyPem : await derivePublicFromPrivatePEM(input.privateKeyPem);
|
|
218
|
+
const publicKey = await importPublicKeyFromPem(publicKeyPem);
|
|
219
|
+
const publicKeyBase64 = await exportPublicKeyBase64(publicKey);
|
|
220
|
+
const derivedPublicKeyBase64 = await derivePublicKeyBase64FromPrivateKeyPem(
|
|
221
|
+
input.privateKeyPem
|
|
222
|
+
);
|
|
223
|
+
if (publicKeyBase64 !== derivedPublicKeyBase64) {
|
|
224
|
+
throw new Error("Provided public key does not match the private key.");
|
|
225
|
+
}
|
|
226
|
+
const derivedKeyId = await deriveKeyIdFromPublicKey(publicKey);
|
|
227
|
+
if (input.keyId && input.keyId !== derivedKeyId) {
|
|
228
|
+
throw new Error("Provided keyId does not match the signer public key.");
|
|
229
|
+
}
|
|
230
|
+
const keyId = input.keyId ?? derivedKeyId;
|
|
231
|
+
return {
|
|
232
|
+
privateKey,
|
|
233
|
+
publicKey,
|
|
234
|
+
publicKeyPem,
|
|
235
|
+
publicKeyBase64,
|
|
236
|
+
keyId
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
async function signUtf8(signingKey, value) {
|
|
240
|
+
return signBytes(signingKey, utf8Bytes(value));
|
|
241
|
+
}
|
|
242
|
+
async function verifyUtf8(signature, value, publicKey) {
|
|
243
|
+
return verifyBytes(signature, utf8Bytes(value), publicKey);
|
|
244
|
+
}
|
|
245
|
+
async function verifyPublicKeyKeyId(publicKeyBase64, keyId) {
|
|
246
|
+
return await deriveKeyIdFromPublicKeyBase64(publicKeyBase64) === keyId;
|
|
247
|
+
}
|
|
248
|
+
export { derivePublicKeyBase64FromPrivateKeyPem, exportPublicKeyBase64, importPublicKeyFromBase64, resolveSealSigner, signUtf8, verifyPublicKeyKeyId, verifyUtf8 };
|
|
249
|
+
//# sourceMappingURL=crypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.js","sources":["../../identity/dist/identity.es.js","../src/crypto.ts"],"sourcesContent":["async function createIdentity() {\n return crypto.subtle.generateKey(\n { name: \"ECDSA\", namedCurve: \"P-256\" },\n true,\n [\"sign\", \"verify\"]\n );\n}\nfunction getBufferCtor() {\n const maybeBuffer = globalThis.Buffer;\n return maybeBuffer != null ? maybeBuffer : null;\n}\nfunction addNewLines(str) {\n let finalString = \"\";\n while (str.length > 0) {\n finalString += str.substring(0, 64) + \"\\n\";\n str = str.substring(64);\n }\n return finalString;\n}\nfunction removeLines(str) {\n return str.replaceAll(\"\\n\", \"\");\n}\nfunction stripIdentityKey(key) {\n return key.replace(\"-----BEGIN PUBLIC KEY-----\\n\", \"\").replace(\"\\n-----END PUBLIC KEY-----\", \"\");\n}\nfunction arrayBufferToBase64(arrayBuffer) {\n const byteArray = new Uint8Array(arrayBuffer);\n const bufferCtor = getBufferCtor();\n if (bufferCtor) {\n return bufferCtor.from(byteArray).toString(\"base64\");\n }\n let byteString = \"\";\n for (let i = 0; i < byteArray.byteLength; i++) {\n byteString += String.fromCharCode(byteArray[i]);\n }\n return btoa(byteString);\n}\nfunction base64ToArrayBuffer(b64) {\n const bufferCtor = getBufferCtor();\n if (bufferCtor) {\n const bytes = Uint8Array.from(\n bufferCtor.from(b64, \"base64\").toString(\"binary\"),\n (char) => char.charCodeAt(0)\n );\n return bytes.buffer.slice(\n bytes.byteOffset,\n bytes.byteOffset + bytes.byteLength\n );\n }\n const byteString = atob(b64);\n const byteArray = new Uint8Array(byteString.length);\n for (let i = 0; i < byteString.length; i++) {\n byteArray[i] = byteString.charCodeAt(i);\n }\n return byteArray.buffer;\n}\nfunction b64encode(buf) {\n return arrayBufferToBase64(buf);\n}\nfunction b64decode(str) {\n return base64ToArrayBuffer(str);\n}\nfunction encode(data) {\n const payload = typeof data === \"string\" ? data : JSON.stringify(data);\n return new TextEncoder().encode(payload);\n}\nfunction getHashBuffer(data) {\n return crypto.subtle.digest(\"SHA-256\", encode(data));\n}\nfunction getHashArray(hash) {\n return Array.from(new Uint8Array(hash));\n}\nfunction getHashHex(hash) {\n return hash.map((buf) => buf.toString(16).padStart(2, \"0\")).join(\"\");\n}\nfunction canonicalize(value, seen) {\n if (value === void 0) {\n throw new TypeError(\"Cannot hash undefined\");\n }\n const valueType = typeof value;\n if (valueType === \"function\" || valueType === \"symbol\") {\n throw new TypeError(`Cannot hash ${valueType} values`);\n }\n if (value === null || valueType === \"string\" || valueType === \"number\" || valueType === \"boolean\") {\n return value;\n }\n if (valueType === \"bigint\") {\n throw new TypeError(\"Cannot hash bigint values\");\n }\n if (typeof value.toJSON === \"function\") {\n return canonicalize(value.toJSON(), seen);\n }\n if (Array.isArray(value)) {\n return value.map((item) => canonicalize(item, seen));\n }\n if (typeof value === \"object\") {\n if (seen.has(value)) {\n throw new TypeError(\"Cannot hash circular references\");\n }\n seen.add(value);\n const entries = Object.keys(value).sort();\n const result = {};\n for (const key of entries) {\n result[key] = canonicalize(value[key], seen);\n }\n seen.delete(value);\n return result;\n }\n throw new TypeError(`Cannot hash unsupported value type: ${valueType}`);\n}\nfunction canonicalStringify(data) {\n return JSON.stringify(canonicalize(data, /* @__PURE__ */ new WeakSet()));\n}\nasync function hashData(data) {\n const hash_buffer = await getHashBuffer(canonicalStringify(data));\n const hash_array = getHashArray(hash_buffer);\n return getHashHex(hash_array);\n}\nfunction importPrivateKey(points, secret) {\n return crypto.subtle.importKey(\n \"jwk\",\n {\n crv: \"P-256\",\n ext: true,\n kty: \"EC\",\n ...points,\n d: secret\n },\n {\n name: \"ECDSA\",\n namedCurve: \"P-256\"\n },\n true,\n [\"sign\"]\n );\n}\nasync function importPrivateKeyFromPem(key) {\n const b64key = key.replace(\"-----BEGIN PRIVATE KEY-----\", \"\").replace(\"-----END PRIVATE KEY-----\", \"\");\n return crypto.subtle.importKey(\n \"pkcs8\",\n base64ToArrayBuffer(removeLines(b64key)),\n { name: \"ECDSA\", namedCurve: \"P-256\" },\n true,\n [\"sign\"]\n );\n}\nasync function exportPrivateKey(privateKey) {\n return crypto.subtle.exportKey(\"jwk\", privateKey);\n}\nasync function exportPrivateKeyAsPem(privateKey) {\n const exportedPrivateKey = await crypto.subtle.exportKey(\"pkcs8\", privateKey);\n return `-----BEGIN PRIVATE KEY-----\n${addNewLines(\n arrayBufferToBase64(exportedPrivateKey)\n )}-----END PRIVATE KEY-----`;\n}\nfunction importPublicKey(points) {\n return crypto.subtle.importKey(\n \"jwk\",\n {\n crv: \"P-256\",\n ext: true,\n kty: \"EC\",\n ...points\n },\n {\n name: \"ECDSA\",\n namedCurve: \"P-256\"\n },\n true,\n [\"verify\"]\n );\n}\nasync function importPublicKeyFromPem(key) {\n const b64key = key.replace(\"-----BEGIN PUBLIC KEY-----\", \"\").replace(\"-----END PUBLIC KEY-----\", \"\");\n return crypto.subtle.importKey(\n \"spki\",\n base64ToArrayBuffer(removeLines(b64key)),\n { name: \"ECDSA\", namedCurve: \"P-256\" },\n true,\n [\"verify\"]\n );\n}\nasync function exportPublicKey(key) {\n const exported = await crypto.subtle.exportKey(\"spki\", key);\n return b64encode(exported);\n}\nasync function exportPublicKeyAsPem(key) {\n const exportedPublicKey = await crypto.subtle.exportKey(\"spki\", key);\n return `-----BEGIN PUBLIC KEY-----\n${addNewLines(arrayBufferToBase64(exportedPublicKey))}-----END PUBLIC KEY-----`;\n}\nasync function derivePublicFromPrivatePEM(privateKeyPEM) {\n const key = await importPrivateKeyFromPem(privateKeyPEM);\n const priv = await exportPrivateKey(key);\n const pub = await importPublicKey({ x: priv.x, y: priv.y });\n return exportPublicKeyAsPem(pub);\n}\nasync function signBytes(signingKey, data) {\n const bytes = data instanceof Uint8Array ? data : new Uint8Array(data);\n const signatureBuffer = await crypto.subtle.sign(\n {\n name: \"ECDSA\",\n hash: {\n name: \"SHA-256\"\n }\n },\n signingKey,\n bytes\n );\n return b64encode(signatureBuffer);\n}\nasync function sign(signingKey, data) {\n const payload = typeof data === \"string\" ? data : JSON.stringify(data);\n const dataBuffer = new TextEncoder().encode(payload);\n return signBytes(signingKey, dataBuffer);\n}\nasync function verifyBytes(signature, data, publicKey) {\n const bytes = data instanceof Uint8Array ? data : new Uint8Array(data);\n return crypto.subtle.verify(\n {\n name: \"ECDSA\",\n hash: { name: \"SHA-256\" }\n },\n publicKey,\n b64decode(signature),\n bytes\n );\n}\nasync function verify(signature, data, publicKey) {\n const dataBuffer = new TextEncoder().encode(data);\n return verifyBytes(signature, dataBuffer, publicKey);\n}\nasync function verifyJson(signature, data, publicKey) {\n return verify(signature, JSON.stringify(data), publicKey);\n}\nfunction normalizePublicKeyBody(publicKeyBase64) {\n return addNewLines(publicKeyBase64).trimEnd();\n}\nasync function deriveKeyIdFromPublicKeyBase64(publicKeyBase64) {\n return hashData(normalizePublicKeyBody(publicKeyBase64));\n}\nasync function deriveKeyIdFromPublicKeyPem(publicKeyPem) {\n return hashData(stripIdentityKey(publicKeyPem));\n}\nasync function deriveKeyIdFromPublicKey(publicKey) {\n const publicKeyBase64 = await exportPublicKey(publicKey);\n return deriveKeyIdFromPublicKeyBase64(publicKeyBase64);\n}\nexport { createIdentity, deriveKeyIdFromPublicKey, deriveKeyIdFromPublicKeyBase64, deriveKeyIdFromPublicKeyPem, derivePublicFromPrivatePEM, exportPrivateKey, exportPrivateKeyAsPem, exportPublicKey, exportPublicKeyAsPem, importPrivateKey, importPrivateKeyFromPem, importPublicKey, importPublicKeyFromPem, sign, signBytes, verify, verifyBytes, verifyJson };\n","import {\n deriveKeyIdFromPublicKey,\n deriveKeyIdFromPublicKeyBase64,\n derivePublicFromPrivatePEM,\n exportPublicKey,\n importPrivateKeyFromPem,\n importPublicKeyFromPem,\n signBytes,\n verifyBytes,\n} from \"ternent-identity\";\nimport { formatIdentityKey } from \"ternent-utils\";\n\nexport type SealSignerInput = {\n privateKeyPem: string;\n publicKeyPem?: string;\n keyId?: string;\n};\n\nexport type ResolvedSealSigner = {\n privateKey: CryptoKey;\n publicKey: CryptoKey;\n publicKeyPem: string;\n publicKeyBase64: string;\n keyId: string;\n};\n\nfunction utf8Bytes(value: string): Uint8Array {\n return new TextEncoder().encode(value);\n}\n\nexport async function importPublicKeyFromBase64(\n publicKeyBase64: string\n): Promise<CryptoKey> {\n return importPublicKeyFromPem(formatIdentityKey(publicKeyBase64));\n}\n\nexport async function exportPublicKeyBase64(key: CryptoKey): Promise<string> {\n return exportPublicKey(key);\n}\n\nexport async function derivePublicKeyBase64FromPrivateKeyPem(\n privateKeyPem: string\n): Promise<string> {\n const publicKeyPem = await derivePublicFromPrivatePEM(privateKeyPem);\n const publicKey = await importPublicKeyFromPem(publicKeyPem);\n return exportPublicKeyBase64(publicKey);\n}\n\nexport async function resolveSealSigner(\n input: SealSignerInput\n): Promise<ResolvedSealSigner> {\n const privateKey = await importPrivateKeyFromPem(input.privateKeyPem);\n const publicKeyPem = input.publicKeyPem\n ? input.publicKeyPem\n : await derivePublicFromPrivatePEM(input.privateKeyPem);\n const publicKey = await importPublicKeyFromPem(publicKeyPem);\n const publicKeyBase64 = await exportPublicKeyBase64(publicKey);\n const derivedPublicKeyBase64 = await derivePublicKeyBase64FromPrivateKeyPem(\n input.privateKeyPem\n );\n\n if (publicKeyBase64 !== derivedPublicKeyBase64) {\n throw new Error(\"Provided public key does not match the private key.\");\n }\n\n const derivedKeyId = await deriveKeyIdFromPublicKey(publicKey);\n if (input.keyId && input.keyId !== derivedKeyId) {\n throw new Error(\"Provided keyId does not match the signer public key.\");\n }\n const keyId = input.keyId ?? derivedKeyId;\n\n return {\n privateKey,\n publicKey,\n publicKeyPem,\n publicKeyBase64,\n keyId,\n };\n}\n\nexport async function signUtf8(\n signingKey: CryptoKey,\n value: string\n): Promise<string> {\n return signBytes(signingKey, utf8Bytes(value));\n}\n\nexport async function verifyUtf8(\n signature: string,\n value: string,\n publicKey: CryptoKey\n): Promise<boolean> {\n return verifyBytes(signature, utf8Bytes(value), publicKey);\n}\n\nexport async function verifyPublicKeyKeyId(\n publicKeyBase64: string,\n keyId: string\n): Promise<boolean> {\n return (await deriveKeyIdFromPublicKeyBase64(publicKeyBase64)) === keyId;\n}\n"],"names":[],"mappings":"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"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const EXIT_SUCCESS = 0;
|
|
2
|
+
const EXIT_FAILURE = 1;
|
|
3
|
+
const EXIT_HASH_MISMATCH = 2;
|
|
4
|
+
const EXIT_SIGNATURE_INVALID = 3;
|
|
5
|
+
const EXIT_INVALID_PROOF = 4;
|
|
6
|
+
const EXIT_KEY_CONFIG = 5;
|
|
7
|
+
class SealCliError extends Error {
|
|
8
|
+
exitCode;
|
|
9
|
+
constructor(message, exitCode = EXIT_FAILURE) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = "SealCliError";
|
|
12
|
+
this.exitCode = exitCode;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function getExitCode(error) {
|
|
16
|
+
if (error instanceof SealCliError) {
|
|
17
|
+
return error.exitCode;
|
|
18
|
+
}
|
|
19
|
+
return EXIT_FAILURE;
|
|
20
|
+
}
|
|
21
|
+
export { EXIT_FAILURE, EXIT_HASH_MISMATCH, EXIT_INVALID_PROOF, EXIT_KEY_CONFIG, EXIT_SIGNATURE_INVALID, EXIT_SUCCESS, SealCliError, getExitCode };
|
|
22
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sources":["../src/errors.ts"],"sourcesContent":["export const EXIT_SUCCESS = 0;\nexport const EXIT_FAILURE = 1;\nexport const EXIT_HASH_MISMATCH = 2;\nexport const EXIT_SIGNATURE_INVALID = 3;\nexport const EXIT_INVALID_PROOF = 4;\nexport const EXIT_KEY_CONFIG = 5;\n\nexport class SealCliError extends Error {\n exitCode: number;\n\n constructor(message: string, exitCode = EXIT_FAILURE) {\n super(message);\n this.name = \"SealCliError\";\n this.exitCode = exitCode;\n }\n}\n\nexport function getExitCode(error: unknown): number {\n if (error instanceof SealCliError) {\n return error.exitCode;\n }\n return EXIT_FAILURE;\n}\n"],"names":[],"mappings":"AAAO,MAAM,eAAe;AACrB,MAAM,eAAe;AACrB,MAAM,qBAAqB;AAC3B,MAAM,yBAAyB;AAC/B,MAAM,qBAAqB;AAC3B,MAAM,kBAAkB;AAExB,MAAM,qBAAqB,MAAM;AAAA,EACtC;AAAA,EAEA,YAAY,SAAiB,WAAW,cAAc;AACpD,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,WAAW;AAAA,EAClB;AACF;AAEO,SAAS,YAAY,OAAwB;AAClD,MAAI,iBAAiB,cAAc;AACjC,WAAO,MAAM;AAAA,EACf;AACO,SAAA;AACT;;"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { SEAL_PROOF_TYPE, SEAL_PROOF_VERSION, SEAL_SIGNATURE_ALGORITHM, createSealHash, createSealProof, createSealPublicKeyArtifact, getSealProofSignableFields, getSealProofSigningPayload, parseSealProofJson, parseSealPublicKeyJson, validateSealProofShape, validateSealPublicKeyShape, verifySealProofAgainstBytes, verifySealProofSignature } from "./proof.js";
|
|
2
|
+
export { SEAL_MANIFEST_TYPE, SEAL_MANIFEST_VERSION, parseSealManifestJson, stringifySealManifest, validateSealManifestShape } from "./manifest.js";
|
|
3
|
+
export { derivePublicKeyBase64FromPrivateKeyPem, exportPublicKeyBase64, importPublicKeyFromBase64, resolveSealSigner, signUtf8, verifyPublicKeyKeyId, verifyUtf8 } from "./crypto.js";
|
|
4
|
+
export { EXIT_FAILURE, EXIT_HASH_MISMATCH, EXIT_INVALID_PROOF, EXIT_KEY_CONFIG, EXIT_SIGNATURE_INVALID, EXIT_SUCCESS, SealCliError, getExitCode } from "./errors.js";
|
|
5
|
+
import "./chunks/utils.es-586f669f.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;"}
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { c as canonicalStringify } from "./chunks/utils.es-586f669f.js";
|
|
2
|
+
const SEAL_MANIFEST_VERSION = "1";
|
|
3
|
+
const SEAL_MANIFEST_TYPE = "seal-manifest";
|
|
4
|
+
function isRecord(value) {
|
|
5
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
function hasOnlyKeys(value, allowed) {
|
|
8
|
+
return Object.keys(value).every((key) => allowed.includes(key));
|
|
9
|
+
}
|
|
10
|
+
function isSealHash(value) {
|
|
11
|
+
return typeof value === "string" && /^sha256:[0-9a-f]{64}$/.test(value);
|
|
12
|
+
}
|
|
13
|
+
function validateSealManifestShape(value) {
|
|
14
|
+
if (!isRecord(value)) {
|
|
15
|
+
return {
|
|
16
|
+
ok: false,
|
|
17
|
+
errors: ["Manifest must be a JSON object."],
|
|
18
|
+
manifest: null
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const errors = [];
|
|
22
|
+
if (!hasOnlyKeys(value, ["version", "type", "root", "files"])) {
|
|
23
|
+
errors.push("Manifest contains unsupported fields.");
|
|
24
|
+
}
|
|
25
|
+
if (value.version !== SEAL_MANIFEST_VERSION) {
|
|
26
|
+
errors.push(`Manifest version must be ${SEAL_MANIFEST_VERSION}.`);
|
|
27
|
+
}
|
|
28
|
+
if (value.type !== SEAL_MANIFEST_TYPE) {
|
|
29
|
+
errors.push(`Manifest type must be ${SEAL_MANIFEST_TYPE}.`);
|
|
30
|
+
}
|
|
31
|
+
if (typeof value.root !== "string" || value.root.length === 0) {
|
|
32
|
+
errors.push("Manifest root must be a non-empty string.");
|
|
33
|
+
}
|
|
34
|
+
if (!isRecord(value.files)) {
|
|
35
|
+
errors.push("Manifest files must be an object.");
|
|
36
|
+
}
|
|
37
|
+
if (errors.length > 0 || !isRecord(value.files)) {
|
|
38
|
+
return { ok: false, errors, manifest: null };
|
|
39
|
+
}
|
|
40
|
+
const filesEntries = Object.entries(value.files);
|
|
41
|
+
const files = {};
|
|
42
|
+
for (const [path, hash] of filesEntries) {
|
|
43
|
+
if (!path || path.includes("\\")) {
|
|
44
|
+
errors.push(`Manifest file path is invalid: ${path || "<empty>"}.`);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (!isSealHash(hash)) {
|
|
48
|
+
errors.push(`Manifest file hash is invalid for ${path}.`);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
files[path] = hash;
|
|
52
|
+
}
|
|
53
|
+
if (errors.length > 0) {
|
|
54
|
+
return { ok: false, errors, manifest: null };
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
ok: true,
|
|
58
|
+
errors: [],
|
|
59
|
+
manifest: {
|
|
60
|
+
version: SEAL_MANIFEST_VERSION,
|
|
61
|
+
type: SEAL_MANIFEST_TYPE,
|
|
62
|
+
root: value.root,
|
|
63
|
+
files
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function parseSealManifestJson(raw) {
|
|
68
|
+
try {
|
|
69
|
+
return validateSealManifestShape(JSON.parse(raw));
|
|
70
|
+
} catch {
|
|
71
|
+
return {
|
|
72
|
+
ok: false,
|
|
73
|
+
errors: ["Manifest JSON is not valid JSON."],
|
|
74
|
+
manifest: null
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function stringifySealManifest(manifest) {
|
|
79
|
+
return canonicalStringify(manifest);
|
|
80
|
+
}
|
|
81
|
+
export { SEAL_MANIFEST_TYPE, SEAL_MANIFEST_VERSION, parseSealManifestJson, stringifySealManifest, validateSealManifestShape };
|
|
82
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sources":["../src/manifest.ts"],"sourcesContent":["import { canonicalStringify } from \"ternent-utils\";\n\nexport const SEAL_MANIFEST_VERSION = \"1\" as const;\nexport const SEAL_MANIFEST_TYPE = \"seal-manifest\" as const;\n\nexport type SealHash = `sha256:${string}`;\n\nexport type SealManifestV1 = {\n version: typeof SEAL_MANIFEST_VERSION;\n type: typeof SEAL_MANIFEST_TYPE;\n root: string;\n files: Record<string, SealHash>;\n};\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction hasOnlyKeys(\n value: Record<string, unknown>,\n allowed: string[]\n): boolean {\n return Object.keys(value).every((key) => allowed.includes(key));\n}\n\nfunction isSealHash(value: unknown): value is SealHash {\n return typeof value === \"string\" && /^sha256:[0-9a-f]{64}$/.test(value);\n}\n\nexport function validateSealManifestShape(value: unknown): {\n ok: boolean;\n errors: string[];\n manifest: SealManifestV1 | null;\n} {\n if (!isRecord(value)) {\n return {\n ok: false,\n errors: [\"Manifest must be a JSON object.\"],\n manifest: null,\n };\n }\n\n const errors: string[] = [];\n\n if (!hasOnlyKeys(value, [\"version\", \"type\", \"root\", \"files\"])) {\n errors.push(\"Manifest contains unsupported fields.\");\n }\n\n if (value.version !== SEAL_MANIFEST_VERSION) {\n errors.push(`Manifest version must be ${SEAL_MANIFEST_VERSION}.`);\n }\n\n if (value.type !== SEAL_MANIFEST_TYPE) {\n errors.push(`Manifest type must be ${SEAL_MANIFEST_TYPE}.`);\n }\n\n if (typeof value.root !== \"string\" || value.root.length === 0) {\n errors.push(\"Manifest root must be a non-empty string.\");\n }\n\n if (!isRecord(value.files)) {\n errors.push(\"Manifest files must be an object.\");\n }\n\n if (errors.length > 0 || !isRecord(value.files)) {\n return { ok: false, errors, manifest: null };\n }\n\n const filesEntries = Object.entries(value.files);\n const files: Record<string, SealHash> = {};\n for (const [path, hash] of filesEntries) {\n if (!path || path.includes(\"\\\\\")) {\n errors.push(`Manifest file path is invalid: ${path || \"<empty>\"}.`);\n continue;\n }\n if (!isSealHash(hash)) {\n errors.push(`Manifest file hash is invalid for ${path}.`);\n continue;\n }\n files[path] = hash;\n }\n\n if (errors.length > 0) {\n return { ok: false, errors, manifest: null };\n }\n\n return {\n ok: true,\n errors: [],\n manifest: {\n version: SEAL_MANIFEST_VERSION,\n type: SEAL_MANIFEST_TYPE,\n root: value.root as string,\n files,\n },\n };\n}\n\nexport function parseSealManifestJson(raw: string): {\n ok: boolean;\n errors: string[];\n manifest: SealManifestV1 | null;\n} {\n try {\n return validateSealManifestShape(JSON.parse(raw));\n } catch {\n return {\n ok: false,\n errors: [\"Manifest JSON is not valid JSON.\"],\n manifest: null,\n };\n }\n}\n\nexport function stringifySealManifest(manifest: SealManifestV1): string {\n return canonicalStringify(manifest);\n}\n"],"names":[],"mappings":";AAEO,MAAM,wBAAwB;AAC9B,MAAM,qBAAqB;AAWlC,SAAS,SAAS,OAAkD;AAC3D,SAAA,QAAQ,KAAK,KAAK,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,YACP,OACA,SACS;AACF,SAAA,OAAO,KAAK,KAAK,EAAE,MAAM,CAAC,QAAQ,QAAQ,SAAS,GAAG,CAAC;AAChE;AAEA,SAAS,WAAW,OAAmC;AACrD,SAAO,OAAO,UAAU,YAAY,wBAAwB,KAAK,KAAK;AACxE;AAEO,SAAS,0BAA0B,OAIxC;AACI,MAAA,CAAC,SAAS,KAAK,GAAG;AACb,WAAA;AAAA,MACL,IAAI;AAAA,MACJ,QAAQ,CAAC,iCAAiC;AAAA,MAC1C,UAAU;AAAA,IAAA;AAAA,EAEd;AAEA,QAAM,SAAmB,CAAA;AAErB,MAAA,CAAC,YAAY,OAAO,CAAC,WAAW,QAAQ,QAAQ,OAAO,CAAC,GAAG;AAC7D,WAAO,KAAK,uCAAuC;AAAA,EACrD;AAEI,MAAA,MAAM,YAAY,uBAAuB;AACpC,WAAA,KAAK,4BAA4B,wBAAwB;AAAA,EAClE;AAEI,MAAA,MAAM,SAAS,oBAAoB;AAC9B,WAAA,KAAK,yBAAyB,qBAAqB;AAAA,EAC5D;AAEA,MAAI,OAAO,MAAM,SAAS,YAAY,MAAM,KAAK,WAAW,GAAG;AAC7D,WAAO,KAAK,2CAA2C;AAAA,EACzD;AAEA,MAAI,CAAC,SAAS,MAAM,KAAK,GAAG;AAC1B,WAAO,KAAK,mCAAmC;AAAA,EACjD;AAEA,MAAI,OAAO,SAAS,KAAK,CAAC,SAAS,MAAM,KAAK,GAAG;AAC/C,WAAO,EAAE,IAAI,OAAO,QAAQ,UAAU,KAAK;AAAA,EAC7C;AAEA,QAAM,eAAe,OAAO,QAAQ,MAAM,KAAK;AAC/C,QAAM,QAAkC,CAAA;AACxC,aAAW,CAAC,MAAM,IAAI,KAAK,cAAc;AACvC,QAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,GAAG;AACzB,aAAA,KAAK,kCAAkC,QAAQ,YAAY;AAClE;AAAA,IACF;AACI,QAAA,CAAC,WAAW,IAAI,GAAG;AACd,aAAA,KAAK,qCAAqC,OAAO;AACxD;AAAA,IACF;AACA,UAAM,QAAQ;AAAA,EAChB;AAEI,MAAA,OAAO,SAAS,GAAG;AACrB,WAAO,EAAE,IAAI,OAAO,QAAQ,UAAU,KAAK;AAAA,EAC7C;AAES,SAAA;AAAA,IACL,IAAI;AAAA,IACJ,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,SAAS;AAAA,MACT,MAAM;AAAA,MACN,MAAM,MAAM;AAAA,MACZ;AAAA,IACF;AAAA,EAAA;AAEN;AAEO,SAAS,sBAAsB,KAIpC;AACI,MAAA;AACF,WAAO,0BAA0B,KAAK,MAAM,GAAG,CAAC;AAAA,EAAA,QAChD;AACO,WAAA;AAAA,MACL,IAAI;AAAA,MACJ,QAAQ,CAAC,kCAAkC;AAAA,MAC3C,UAAU;AAAA,IAAA;AAAA,EAEd;AACF;AAEO,SAAS,sBAAsB,UAAkC;AACtE,SAAO,mBAAmB,QAAQ;AACpC;;"}
|
package/dist/proof.js
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { c as canonicalStringify, h as hashBytes } from "./chunks/utils.es-586f669f.js";
|
|
2
|
+
import { resolveSealSigner, signUtf8, verifyPublicKeyKeyId, importPublicKeyFromBase64, verifyUtf8 } from "./crypto.js";
|
|
3
|
+
const SEAL_PROOF_VERSION = "1";
|
|
4
|
+
const SEAL_PROOF_TYPE = "seal-proof";
|
|
5
|
+
const SEAL_SIGNATURE_ALGORITHM = "ECDSA-P256-SHA256";
|
|
6
|
+
function isRecord(value) {
|
|
7
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
8
|
+
}
|
|
9
|
+
function hasOnlyKeys(value, allowed) {
|
|
10
|
+
return Object.keys(value).every((key) => allowed.includes(key));
|
|
11
|
+
}
|
|
12
|
+
function isSealHash(value) {
|
|
13
|
+
return typeof value === "string" && /^sha256:[0-9a-f]{64}$/.test(value);
|
|
14
|
+
}
|
|
15
|
+
function isIsoDate(value) {
|
|
16
|
+
return !Number.isNaN(Date.parse(value));
|
|
17
|
+
}
|
|
18
|
+
function getSealProofSignableFields(proof) {
|
|
19
|
+
return {
|
|
20
|
+
version: proof.version,
|
|
21
|
+
type: proof.type,
|
|
22
|
+
algorithm: proof.algorithm,
|
|
23
|
+
createdAt: proof.createdAt,
|
|
24
|
+
subject: proof.subject,
|
|
25
|
+
signer: proof.signer
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function getSealProofSigningPayload(proof) {
|
|
29
|
+
return canonicalStringify(getSealProofSignableFields(proof));
|
|
30
|
+
}
|
|
31
|
+
async function createSealHash(bytes) {
|
|
32
|
+
const hash = await hashBytes(bytes);
|
|
33
|
+
return `sha256:${hash}`;
|
|
34
|
+
}
|
|
35
|
+
async function createSealProof(input) {
|
|
36
|
+
const signer = await resolveSealSigner(input.signer);
|
|
37
|
+
const fields = {
|
|
38
|
+
version: SEAL_PROOF_VERSION,
|
|
39
|
+
type: SEAL_PROOF_TYPE,
|
|
40
|
+
algorithm: SEAL_SIGNATURE_ALGORITHM,
|
|
41
|
+
createdAt: input.createdAt ?? new Date().toISOString(),
|
|
42
|
+
subject: input.subject,
|
|
43
|
+
signer: {
|
|
44
|
+
publicKey: signer.publicKeyBase64,
|
|
45
|
+
keyId: signer.keyId
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const signature = await signUtf8(
|
|
49
|
+
signer.privateKey,
|
|
50
|
+
getSealProofSigningPayload(fields)
|
|
51
|
+
);
|
|
52
|
+
return {
|
|
53
|
+
...fields,
|
|
54
|
+
signature
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
async function createSealPublicKeyArtifact(signer) {
|
|
58
|
+
const resolved = await resolveSealSigner(signer);
|
|
59
|
+
return {
|
|
60
|
+
algorithm: SEAL_SIGNATURE_ALGORITHM,
|
|
61
|
+
publicKey: resolved.publicKeyBase64,
|
|
62
|
+
keyId: resolved.keyId
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function validateSealProofShape(value) {
|
|
66
|
+
if (!isRecord(value)) {
|
|
67
|
+
return { ok: false, errors: ["Proof must be a JSON object."], proof: null };
|
|
68
|
+
}
|
|
69
|
+
const errors = [];
|
|
70
|
+
if (!hasOnlyKeys(value, [
|
|
71
|
+
"version",
|
|
72
|
+
"type",
|
|
73
|
+
"algorithm",
|
|
74
|
+
"createdAt",
|
|
75
|
+
"subject",
|
|
76
|
+
"signer",
|
|
77
|
+
"signature"
|
|
78
|
+
])) {
|
|
79
|
+
errors.push("Proof contains unsupported fields.");
|
|
80
|
+
}
|
|
81
|
+
if (value.version !== SEAL_PROOF_VERSION) {
|
|
82
|
+
errors.push(`Proof version must be ${SEAL_PROOF_VERSION}.`);
|
|
83
|
+
}
|
|
84
|
+
if (value.type !== SEAL_PROOF_TYPE) {
|
|
85
|
+
errors.push(`Proof type must be ${SEAL_PROOF_TYPE}.`);
|
|
86
|
+
}
|
|
87
|
+
if (value.algorithm !== SEAL_SIGNATURE_ALGORITHM) {
|
|
88
|
+
errors.push(`Proof algorithm must be ${SEAL_SIGNATURE_ALGORITHM}.`);
|
|
89
|
+
}
|
|
90
|
+
if (typeof value.createdAt !== "string" || !isIsoDate(value.createdAt)) {
|
|
91
|
+
errors.push("Proof createdAt must be an ISO timestamp.");
|
|
92
|
+
}
|
|
93
|
+
if (typeof value.signature !== "string" || value.signature.length === 0) {
|
|
94
|
+
errors.push("Proof signature must be a non-empty base64 string.");
|
|
95
|
+
}
|
|
96
|
+
if (!isRecord(value.subject)) {
|
|
97
|
+
errors.push("Proof subject must be an object.");
|
|
98
|
+
}
|
|
99
|
+
if (!isRecord(value.signer)) {
|
|
100
|
+
errors.push("Proof signer must be an object.");
|
|
101
|
+
}
|
|
102
|
+
if (errors.length > 0 || !isRecord(value.subject) || !isRecord(value.signer)) {
|
|
103
|
+
return { ok: false, errors, proof: null };
|
|
104
|
+
}
|
|
105
|
+
if (!hasOnlyKeys(value.subject, ["kind", "path", "hash"])) {
|
|
106
|
+
errors.push("Proof subject contains unsupported fields.");
|
|
107
|
+
}
|
|
108
|
+
if (!hasOnlyKeys(value.signer, ["publicKey", "keyId"])) {
|
|
109
|
+
errors.push("Proof signer contains unsupported fields.");
|
|
110
|
+
}
|
|
111
|
+
if (value.subject.kind !== "file" && value.subject.kind !== "manifest") {
|
|
112
|
+
errors.push("Proof subject kind must be file or manifest.");
|
|
113
|
+
}
|
|
114
|
+
if (typeof value.subject.path !== "string" || value.subject.path.length === 0) {
|
|
115
|
+
errors.push("Proof subject path must be a non-empty string.");
|
|
116
|
+
}
|
|
117
|
+
if (!isSealHash(value.subject.hash)) {
|
|
118
|
+
errors.push("Proof subject hash must be a sha256 hash.");
|
|
119
|
+
}
|
|
120
|
+
if (typeof value.signer.publicKey !== "string" || value.signer.publicKey.length === 0) {
|
|
121
|
+
errors.push("Proof signer publicKey must be a non-empty base64 string.");
|
|
122
|
+
}
|
|
123
|
+
if (typeof value.signer.keyId !== "string" || value.signer.keyId.length === 0) {
|
|
124
|
+
errors.push("Proof signer keyId must be a non-empty string.");
|
|
125
|
+
}
|
|
126
|
+
if (errors.length > 0) {
|
|
127
|
+
return { ok: false, errors, proof: null };
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
ok: true,
|
|
131
|
+
errors: [],
|
|
132
|
+
proof: value
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function parseSealProofJson(raw) {
|
|
136
|
+
try {
|
|
137
|
+
return validateSealProofShape(JSON.parse(raw));
|
|
138
|
+
} catch {
|
|
139
|
+
return {
|
|
140
|
+
ok: false,
|
|
141
|
+
errors: ["Proof JSON is not valid JSON."],
|
|
142
|
+
proof: null
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function validateSealPublicKeyShape(value) {
|
|
147
|
+
if (!isRecord(value)) {
|
|
148
|
+
return {
|
|
149
|
+
ok: false,
|
|
150
|
+
errors: ["Public key artifact must be a JSON object."],
|
|
151
|
+
artifact: null
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
const errors = [];
|
|
155
|
+
if (!hasOnlyKeys(value, ["algorithm", "publicKey", "keyId"])) {
|
|
156
|
+
errors.push("Public key artifact contains unsupported fields.");
|
|
157
|
+
}
|
|
158
|
+
if (value.algorithm !== SEAL_SIGNATURE_ALGORITHM) {
|
|
159
|
+
errors.push(`Public key artifact algorithm must be ${SEAL_SIGNATURE_ALGORITHM}.`);
|
|
160
|
+
}
|
|
161
|
+
if (typeof value.publicKey !== "string" || value.publicKey.length === 0) {
|
|
162
|
+
errors.push("Public key artifact publicKey must be a non-empty base64 string.");
|
|
163
|
+
}
|
|
164
|
+
if (typeof value.keyId !== "string" || value.keyId.length === 0) {
|
|
165
|
+
errors.push("Public key artifact keyId must be a non-empty string.");
|
|
166
|
+
}
|
|
167
|
+
if (errors.length > 0) {
|
|
168
|
+
return { ok: false, errors, artifact: null };
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
ok: true,
|
|
172
|
+
errors: [],
|
|
173
|
+
artifact: value
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function parseSealPublicKeyJson(raw) {
|
|
177
|
+
try {
|
|
178
|
+
return validateSealPublicKeyShape(JSON.parse(raw));
|
|
179
|
+
} catch {
|
|
180
|
+
return {
|
|
181
|
+
ok: false,
|
|
182
|
+
errors: ["Public key JSON is not valid JSON."],
|
|
183
|
+
artifact: null
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
async function verifySealProofSignature(proof) {
|
|
188
|
+
const validation = validateSealProofShape(proof);
|
|
189
|
+
if (!validation.ok || !validation.proof) {
|
|
190
|
+
return { ok: false, errors: validation.errors };
|
|
191
|
+
}
|
|
192
|
+
if (!await verifyPublicKeyKeyId(proof.signer.publicKey, proof.signer.keyId)) {
|
|
193
|
+
return {
|
|
194
|
+
ok: false,
|
|
195
|
+
errors: ["Proof signer keyId does not match signer public key."]
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
try {
|
|
199
|
+
const publicKey = await importPublicKeyFromBase64(proof.signer.publicKey);
|
|
200
|
+
const valid = await verifyUtf8(
|
|
201
|
+
proof.signature,
|
|
202
|
+
getSealProofSigningPayload(proof),
|
|
203
|
+
publicKey
|
|
204
|
+
);
|
|
205
|
+
if (!valid) {
|
|
206
|
+
return { ok: false, errors: ["Invalid signature."] };
|
|
207
|
+
}
|
|
208
|
+
return { ok: true, errors: [] };
|
|
209
|
+
} catch (caught) {
|
|
210
|
+
const message = caught instanceof Error ? caught.message : String(caught);
|
|
211
|
+
return {
|
|
212
|
+
ok: false,
|
|
213
|
+
errors: [`Failed to verify signature: ${message}`]
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
async function verifySealProofAgainstBytes(proof, bytes) {
|
|
218
|
+
const subjectHash = await createSealHash(bytes);
|
|
219
|
+
const signatureCheck = await verifySealProofSignature(proof);
|
|
220
|
+
const hashMatch = subjectHash === proof.subject.hash;
|
|
221
|
+
const signatureValid = signatureCheck.ok;
|
|
222
|
+
return {
|
|
223
|
+
valid: hashMatch && signatureValid,
|
|
224
|
+
hashMatch,
|
|
225
|
+
signatureValid,
|
|
226
|
+
keyId: proof.signer.keyId,
|
|
227
|
+
algorithm: proof.algorithm,
|
|
228
|
+
subjectHash
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
export { SEAL_PROOF_TYPE, SEAL_PROOF_VERSION, SEAL_SIGNATURE_ALGORITHM, createSealHash, createSealProof, createSealPublicKeyArtifact, getSealProofSignableFields, getSealProofSigningPayload, parseSealProofJson, parseSealPublicKeyJson, validateSealProofShape, validateSealPublicKeyShape, verifySealProofAgainstBytes, verifySealProofSignature };
|
|
232
|
+
//# sourceMappingURL=proof.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proof.js","sources":["../src/proof.ts"],"sourcesContent":["import { canonicalStringify, hashBytes } from \"ternent-utils\";\nimport {\n importPublicKeyFromBase64,\n resolveSealSigner,\n signUtf8,\n verifyPublicKeyKeyId,\n verifyUtf8,\n type SealSignerInput,\n} from \"./crypto\";\n\nexport const SEAL_PROOF_VERSION = \"1\" as const;\nexport const SEAL_PROOF_TYPE = \"seal-proof\" as const;\nexport const SEAL_SIGNATURE_ALGORITHM = \"ECDSA-P256-SHA256\" as const;\n\nexport type SealSubjectKind = \"file\" | \"manifest\";\n\nexport type SealProofV1 = {\n version: typeof SEAL_PROOF_VERSION;\n type: typeof SEAL_PROOF_TYPE;\n algorithm: typeof SEAL_SIGNATURE_ALGORITHM;\n createdAt: string;\n subject: {\n kind: SealSubjectKind;\n path: string;\n hash: `sha256:${string}`;\n };\n signer: {\n publicKey: string;\n keyId: string;\n };\n signature: string;\n};\n\nexport type SealPublicKeyArtifact = {\n algorithm: typeof SEAL_SIGNATURE_ALGORITHM;\n publicKey: string;\n keyId: string;\n};\n\ntype SealProofSignableFields = Omit<SealProofV1, \"signature\">;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction hasOnlyKeys(\n value: Record<string, unknown>,\n allowed: string[]\n): boolean {\n return Object.keys(value).every((key) => allowed.includes(key));\n}\n\nfunction isSealHash(value: unknown): value is `sha256:${string}` {\n return typeof value === \"string\" && /^sha256:[0-9a-f]{64}$/.test(value);\n}\n\nfunction isIsoDate(value: string): boolean {\n return !Number.isNaN(Date.parse(value));\n}\n\nexport function getSealProofSignableFields(\n proof: SealProofV1 | SealProofSignableFields\n): SealProofSignableFields {\n return {\n version: proof.version,\n type: proof.type,\n algorithm: proof.algorithm,\n createdAt: proof.createdAt,\n subject: proof.subject,\n signer: proof.signer,\n };\n}\n\nexport function getSealProofSigningPayload(\n proof: SealProofV1 | SealProofSignableFields\n): string {\n return canonicalStringify(getSealProofSignableFields(proof));\n}\n\nexport async function createSealHash(\n bytes: Uint8Array | ArrayBuffer\n): Promise<`sha256:${string}`> {\n const hash = await hashBytes(bytes);\n return `sha256:${hash}`;\n}\n\nexport async function createSealProof(input: {\n createdAt?: string;\n signer: SealSignerInput;\n subject: SealProofV1[\"subject\"];\n}): Promise<SealProofV1> {\n const signer = await resolveSealSigner(input.signer);\n const fields: SealProofSignableFields = {\n version: SEAL_PROOF_VERSION,\n type: SEAL_PROOF_TYPE,\n algorithm: SEAL_SIGNATURE_ALGORITHM,\n createdAt: input.createdAt ?? new Date().toISOString(),\n subject: input.subject,\n signer: {\n publicKey: signer.publicKeyBase64,\n keyId: signer.keyId,\n },\n };\n\n const signature = await signUtf8(\n signer.privateKey,\n getSealProofSigningPayload(fields)\n );\n\n return {\n ...fields,\n signature,\n };\n}\n\nexport async function createSealPublicKeyArtifact(\n signer: SealSignerInput\n): Promise<SealPublicKeyArtifact> {\n const resolved = await resolveSealSigner(signer);\n return {\n algorithm: SEAL_SIGNATURE_ALGORITHM,\n publicKey: resolved.publicKeyBase64,\n keyId: resolved.keyId,\n };\n}\n\nexport function validateSealProofShape(value: unknown): {\n ok: boolean;\n errors: string[];\n proof: SealProofV1 | null;\n} {\n if (!isRecord(value)) {\n return { ok: false, errors: [\"Proof must be a JSON object.\"], proof: null };\n }\n\n const errors: string[] = [];\n\n if (\n !hasOnlyKeys(value, [\n \"version\",\n \"type\",\n \"algorithm\",\n \"createdAt\",\n \"subject\",\n \"signer\",\n \"signature\",\n ])\n ) {\n errors.push(\"Proof contains unsupported fields.\");\n }\n\n if (value.version !== SEAL_PROOF_VERSION) {\n errors.push(`Proof version must be ${SEAL_PROOF_VERSION}.`);\n }\n if (value.type !== SEAL_PROOF_TYPE) {\n errors.push(`Proof type must be ${SEAL_PROOF_TYPE}.`);\n }\n if (value.algorithm !== SEAL_SIGNATURE_ALGORITHM) {\n errors.push(`Proof algorithm must be ${SEAL_SIGNATURE_ALGORITHM}.`);\n }\n if (typeof value.createdAt !== \"string\" || !isIsoDate(value.createdAt)) {\n errors.push(\"Proof createdAt must be an ISO timestamp.\");\n }\n if (typeof value.signature !== \"string\" || value.signature.length === 0) {\n errors.push(\"Proof signature must be a non-empty base64 string.\");\n }\n if (!isRecord(value.subject)) {\n errors.push(\"Proof subject must be an object.\");\n }\n if (!isRecord(value.signer)) {\n errors.push(\"Proof signer must be an object.\");\n }\n\n if (errors.length > 0 || !isRecord(value.subject) || !isRecord(value.signer)) {\n return { ok: false, errors, proof: null };\n }\n\n if (!hasOnlyKeys(value.subject, [\"kind\", \"path\", \"hash\"])) {\n errors.push(\"Proof subject contains unsupported fields.\");\n }\n if (!hasOnlyKeys(value.signer, [\"publicKey\", \"keyId\"])) {\n errors.push(\"Proof signer contains unsupported fields.\");\n }\n\n if (value.subject.kind !== \"file\" && value.subject.kind !== \"manifest\") {\n errors.push(\"Proof subject kind must be file or manifest.\");\n }\n if (typeof value.subject.path !== \"string\" || value.subject.path.length === 0) {\n errors.push(\"Proof subject path must be a non-empty string.\");\n }\n if (!isSealHash(value.subject.hash)) {\n errors.push(\"Proof subject hash must be a sha256 hash.\");\n }\n if (\n typeof value.signer.publicKey !== \"string\" ||\n value.signer.publicKey.length === 0\n ) {\n errors.push(\"Proof signer publicKey must be a non-empty base64 string.\");\n }\n if (typeof value.signer.keyId !== \"string\" || value.signer.keyId.length === 0) {\n errors.push(\"Proof signer keyId must be a non-empty string.\");\n }\n\n if (errors.length > 0) {\n return { ok: false, errors, proof: null };\n }\n\n return {\n ok: true,\n errors: [],\n proof: value as SealProofV1,\n };\n}\n\nexport function parseSealProofJson(raw: string): {\n ok: boolean;\n errors: string[];\n proof: SealProofV1 | null;\n} {\n try {\n return validateSealProofShape(JSON.parse(raw));\n } catch {\n return {\n ok: false,\n errors: [\"Proof JSON is not valid JSON.\"],\n proof: null,\n };\n }\n}\n\nexport function validateSealPublicKeyShape(value: unknown): {\n ok: boolean;\n errors: string[];\n artifact: SealPublicKeyArtifact | null;\n} {\n if (!isRecord(value)) {\n return {\n ok: false,\n errors: [\"Public key artifact must be a JSON object.\"],\n artifact: null,\n };\n }\n\n const errors: string[] = [];\n\n if (!hasOnlyKeys(value, [\"algorithm\", \"publicKey\", \"keyId\"])) {\n errors.push(\"Public key artifact contains unsupported fields.\");\n }\n if (value.algorithm !== SEAL_SIGNATURE_ALGORITHM) {\n errors.push(`Public key artifact algorithm must be ${SEAL_SIGNATURE_ALGORITHM}.`);\n }\n if (typeof value.publicKey !== \"string\" || value.publicKey.length === 0) {\n errors.push(\"Public key artifact publicKey must be a non-empty base64 string.\");\n }\n if (typeof value.keyId !== \"string\" || value.keyId.length === 0) {\n errors.push(\"Public key artifact keyId must be a non-empty string.\");\n }\n\n if (errors.length > 0) {\n return { ok: false, errors, artifact: null };\n }\n\n return {\n ok: true,\n errors: [],\n artifact: value as SealPublicKeyArtifact,\n };\n}\n\nexport function parseSealPublicKeyJson(raw: string): {\n ok: boolean;\n errors: string[];\n artifact: SealPublicKeyArtifact | null;\n} {\n try {\n return validateSealPublicKeyShape(JSON.parse(raw));\n } catch {\n return {\n ok: false,\n errors: [\"Public key JSON is not valid JSON.\"],\n artifact: null,\n };\n }\n}\n\nexport async function verifySealProofSignature(proof: SealProofV1): Promise<{\n ok: boolean;\n errors: string[];\n}> {\n const validation = validateSealProofShape(proof);\n if (!validation.ok || !validation.proof) {\n return { ok: false, errors: validation.errors };\n }\n\n if (!(await verifyPublicKeyKeyId(proof.signer.publicKey, proof.signer.keyId))) {\n return {\n ok: false,\n errors: [\"Proof signer keyId does not match signer public key.\"],\n };\n }\n\n try {\n const publicKey = await importPublicKeyFromBase64(proof.signer.publicKey);\n const valid = await verifyUtf8(\n proof.signature,\n getSealProofSigningPayload(proof),\n publicKey\n );\n if (!valid) {\n return { ok: false, errors: [\"Invalid signature.\"] };\n }\n return { ok: true, errors: [] };\n } catch (caught) {\n const message = caught instanceof Error ? caught.message : String(caught);\n return {\n ok: false,\n errors: [`Failed to verify signature: ${message}`],\n };\n }\n}\n\nexport async function verifySealProofAgainstBytes(\n proof: SealProofV1,\n bytes: Uint8Array | ArrayBuffer\n): Promise<{\n valid: boolean;\n hashMatch: boolean;\n signatureValid: boolean;\n keyId: string;\n algorithm: typeof SEAL_SIGNATURE_ALGORITHM;\n subjectHash: `sha256:${string}`;\n}> {\n const subjectHash = await createSealHash(bytes);\n const signatureCheck = await verifySealProofSignature(proof);\n const hashMatch = subjectHash === proof.subject.hash;\n const signatureValid = signatureCheck.ok;\n\n return {\n valid: hashMatch && signatureValid,\n hashMatch,\n signatureValid,\n keyId: proof.signer.keyId,\n algorithm: proof.algorithm,\n subjectHash,\n };\n}\n"],"names":[],"mappings":";;AAUO,MAAM,qBAAqB;AAC3B,MAAM,kBAAkB;AACxB,MAAM,2BAA2B;AA6BxC,SAAS,SAAS,OAAkD;AAC3D,SAAA,QAAQ,KAAK,KAAK,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK;AAC5E;AAEA,SAAS,YACP,OACA,SACS;AACF,SAAA,OAAO,KAAK,KAAK,EAAE,MAAM,CAAC,QAAQ,QAAQ,SAAS,GAAG,CAAC;AAChE;AAEA,SAAS,WAAW,OAA6C;AAC/D,SAAO,OAAO,UAAU,YAAY,wBAAwB,KAAK,KAAK;AACxE;AAEA,SAAS,UAAU,OAAwB;AACzC,SAAO,CAAC,OAAO,MAAM,KAAK,MAAM,KAAK,CAAC;AACxC;AAEO,SAAS,2BACd,OACyB;AAClB,SAAA;AAAA,IACL,SAAS,MAAM;AAAA,IACf,MAAM,MAAM;AAAA,IACZ,WAAW,MAAM;AAAA,IACjB,WAAW,MAAM;AAAA,IACjB,SAAS,MAAM;AAAA,IACf,QAAQ,MAAM;AAAA,EAAA;AAElB;AAEO,SAAS,2BACd,OACQ;AACD,SAAA,mBAAmB,2BAA2B,KAAK,CAAC;AAC7D;AAEA,eAAsB,eACpB,OAC6B;AACvB,QAAA,OAAO,MAAM,UAAU,KAAK;AAClC,SAAO,UAAU;AACnB;AAEA,eAAsB,gBAAgB,OAIb;AACvB,QAAM,SAAS,MAAM,kBAAkB,MAAM,MAAM;AACnD,QAAM,SAAkC;AAAA,IACtC,SAAS;AAAA,IACT,MAAM;AAAA,IACN,WAAW;AAAA,IACX,WAAW,MAAM,aAAa,IAAI,KAAA,EAAO,YAAY;AAAA,IACrD,SAAS,MAAM;AAAA,IACf,QAAQ;AAAA,MACN,WAAW,OAAO;AAAA,MAClB,OAAO,OAAO;AAAA,IAChB;AAAA,EAAA;AAGF,QAAM,YAAY,MAAM;AAAA,IACtB,OAAO;AAAA,IACP,2BAA2B,MAAM;AAAA,EAAA;AAG5B,SAAA;AAAA,IACL,GAAG;AAAA,IACH;AAAA,EAAA;AAEJ;AAEA,eAAsB,4BACpB,QACgC;AAC1B,QAAA,WAAW,MAAM,kBAAkB,MAAM;AACxC,SAAA;AAAA,IACL,WAAW;AAAA,IACX,WAAW,SAAS;AAAA,IACpB,OAAO,SAAS;AAAA,EAAA;AAEpB;AAEO,SAAS,uBAAuB,OAIrC;AACI,MAAA,CAAC,SAAS,KAAK,GAAG;AACb,WAAA,EAAE,IAAI,OAAO,QAAQ,CAAC,8BAA8B,GAAG,OAAO;EACvE;AAEA,QAAM,SAAmB,CAAA;AAGvB,MAAA,CAAC,YAAY,OAAO;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,CACD,GACD;AACA,WAAO,KAAK,oCAAoC;AAAA,EAClD;AAEI,MAAA,MAAM,YAAY,oBAAoB;AACjC,WAAA,KAAK,yBAAyB,qBAAqB;AAAA,EAC5D;AACI,MAAA,MAAM,SAAS,iBAAiB;AAC3B,WAAA,KAAK,sBAAsB,kBAAkB;AAAA,EACtD;AACI,MAAA,MAAM,cAAc,0BAA0B;AACzC,WAAA,KAAK,2BAA2B,2BAA2B;AAAA,EACpE;AACI,MAAA,OAAO,MAAM,cAAc,YAAY,CAAC,UAAU,MAAM,SAAS,GAAG;AACtE,WAAO,KAAK,2CAA2C;AAAA,EACzD;AACA,MAAI,OAAO,MAAM,cAAc,YAAY,MAAM,UAAU,WAAW,GAAG;AACvE,WAAO,KAAK,oDAAoD;AAAA,EAClE;AACA,MAAI,CAAC,SAAS,MAAM,OAAO,GAAG;AAC5B,WAAO,KAAK,kCAAkC;AAAA,EAChD;AACA,MAAI,CAAC,SAAS,MAAM,MAAM,GAAG;AAC3B,WAAO,KAAK,iCAAiC;AAAA,EAC/C;AAEA,MAAI,OAAO,SAAS,KAAK,CAAC,SAAS,MAAM,OAAO,KAAK,CAAC,SAAS,MAAM,MAAM,GAAG;AAC5E,WAAO,EAAE,IAAI,OAAO,QAAQ,OAAO,KAAK;AAAA,EAC1C;AAEI,MAAA,CAAC,YAAY,MAAM,SAAS,CAAC,QAAQ,QAAQ,MAAM,CAAC,GAAG;AACzD,WAAO,KAAK,4CAA4C;AAAA,EAC1D;AACI,MAAA,CAAC,YAAY,MAAM,QAAQ,CAAC,aAAa,OAAO,CAAC,GAAG;AACtD,WAAO,KAAK,2CAA2C;AAAA,EACzD;AAEA,MAAI,MAAM,QAAQ,SAAS,UAAU,MAAM,QAAQ,SAAS,YAAY;AACtE,WAAO,KAAK,8CAA8C;AAAA,EAC5D;AACI,MAAA,OAAO,MAAM,QAAQ,SAAS,YAAY,MAAM,QAAQ,KAAK,WAAW,GAAG;AAC7E,WAAO,KAAK,gDAAgD;AAAA,EAC9D;AACA,MAAI,CAAC,WAAW,MAAM,QAAQ,IAAI,GAAG;AACnC,WAAO,KAAK,2CAA2C;AAAA,EACzD;AAEE,MAAA,OAAO,MAAM,OAAO,cAAc,YAClC,MAAM,OAAO,UAAU,WAAW,GAClC;AACA,WAAO,KAAK,2DAA2D;AAAA,EACzE;AACI,MAAA,OAAO,MAAM,OAAO,UAAU,YAAY,MAAM,OAAO,MAAM,WAAW,GAAG;AAC7E,WAAO,KAAK,gDAAgD;AAAA,EAC9D;AAEI,MAAA,OAAO,SAAS,GAAG;AACrB,WAAO,EAAE,IAAI,OAAO,QAAQ,OAAO,KAAK;AAAA,EAC1C;AAEO,SAAA;AAAA,IACL,IAAI;AAAA,IACJ,QAAQ,CAAC;AAAA,IACT,OAAO;AAAA,EAAA;AAEX;AAEO,SAAS,mBAAmB,KAIjC;AACI,MAAA;AACF,WAAO,uBAAuB,KAAK,MAAM,GAAG,CAAC;AAAA,EAAA,QAC7C;AACO,WAAA;AAAA,MACL,IAAI;AAAA,MACJ,QAAQ,CAAC,+BAA+B;AAAA,MACxC,OAAO;AAAA,IAAA;AAAA,EAEX;AACF;AAEO,SAAS,2BAA2B,OAIzC;AACI,MAAA,CAAC,SAAS,KAAK,GAAG;AACb,WAAA;AAAA,MACL,IAAI;AAAA,MACJ,QAAQ,CAAC,4CAA4C;AAAA,MACrD,UAAU;AAAA,IAAA;AAAA,EAEd;AAEA,QAAM,SAAmB,CAAA;AAErB,MAAA,CAAC,YAAY,OAAO,CAAC,aAAa,aAAa,OAAO,CAAC,GAAG;AAC5D,WAAO,KAAK,kDAAkD;AAAA,EAChE;AACI,MAAA,MAAM,cAAc,0BAA0B;AACzC,WAAA,KAAK,yCAAyC,2BAA2B;AAAA,EAClF;AACA,MAAI,OAAO,MAAM,cAAc,YAAY,MAAM,UAAU,WAAW,GAAG;AACvE,WAAO,KAAK,kEAAkE;AAAA,EAChF;AACA,MAAI,OAAO,MAAM,UAAU,YAAY,MAAM,MAAM,WAAW,GAAG;AAC/D,WAAO,KAAK,uDAAuD;AAAA,EACrE;AAEI,MAAA,OAAO,SAAS,GAAG;AACrB,WAAO,EAAE,IAAI,OAAO,QAAQ,UAAU,KAAK;AAAA,EAC7C;AAEO,SAAA;AAAA,IACL,IAAI;AAAA,IACJ,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,EAAA;AAEd;AAEO,SAAS,uBAAuB,KAIrC;AACI,MAAA;AACF,WAAO,2BAA2B,KAAK,MAAM,GAAG,CAAC;AAAA,EAAA,QACjD;AACO,WAAA;AAAA,MACL,IAAI;AAAA,MACJ,QAAQ,CAAC,oCAAoC;AAAA,MAC7C,UAAU;AAAA,IAAA;AAAA,EAEd;AACF;AAEA,eAAsB,yBAAyB,OAG5C;AACK,QAAA,aAAa,uBAAuB,KAAK;AAC/C,MAAI,CAAC,WAAW,MAAM,CAAC,WAAW,OAAO;AACvC,WAAO,EAAE,IAAI,OAAO,QAAQ,WAAW,OAAO;AAAA,EAChD;AAEI,MAAA,CAAE,MAAM,qBAAqB,MAAM,OAAO,WAAW,MAAM,OAAO,KAAK,GAAI;AACtE,WAAA;AAAA,MACL,IAAI;AAAA,MACJ,QAAQ,CAAC,sDAAsD;AAAA,IAAA;AAAA,EAEnE;AAEI,MAAA;AACF,UAAM,YAAY,MAAM,0BAA0B,MAAM,OAAO,SAAS;AACxE,UAAM,QAAQ,MAAM;AAAA,MAClB,MAAM;AAAA,MACN,2BAA2B,KAAK;AAAA,MAChC;AAAA,IAAA;AAEF,QAAI,CAAC,OAAO;AACV,aAAO,EAAE,IAAI,OAAO,QAAQ,CAAC,oBAAoB,EAAE;AAAA,IACrD;AACA,WAAO,EAAE,IAAI,MAAM,QAAQ,CAAG,EAAA;AAAA,WACvB;AACP,UAAM,UAAU,kBAAkB,QAAQ,OAAO,UAAU,OAAO,MAAM;AACjE,WAAA;AAAA,MACL,IAAI;AAAA,MACJ,QAAQ,CAAC,+BAA+B,SAAS;AAAA,IAAA;AAAA,EAErD;AACF;AAEsB,eAAA,4BACpB,OACA,OAQC;AACK,QAAA,cAAc,MAAM,eAAe,KAAK;AACxC,QAAA,iBAAiB,MAAM,yBAAyB,KAAK;AACrD,QAAA,YAAY,gBAAgB,MAAM,QAAQ;AAChD,QAAM,iBAAiB,eAAe;AAE/B,SAAA;AAAA,IACL,OAAO,aAAa;AAAA,IACpB;AAAA,IACA;AAAA,IACA,OAAO,MAAM,OAAO;AAAA,IACpB,WAAW,MAAM;AAAA,IACjB;AAAA,EAAA;AAEJ;;"}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ternent/seal-cli",
|
|
3
|
+
"version": "0.1.6",
|
|
4
|
+
"description": "Deterministic artifact signing for Seal",
|
|
5
|
+
"license": "ISC",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"files": [
|
|
8
|
+
"bin",
|
|
9
|
+
"dist",
|
|
10
|
+
"README.md"
|
|
11
|
+
],
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/samternent/home.git",
|
|
15
|
+
"directory": "packages/seal-cli"
|
|
16
|
+
},
|
|
17
|
+
"homepage": "https://github.com/samternent/home/tree/main/packages/seal-cli",
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/samternent/home/issues"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"seal",
|
|
23
|
+
"integrity",
|
|
24
|
+
"signature",
|
|
25
|
+
"manifest",
|
|
26
|
+
"cli"
|
|
27
|
+
],
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"bin": {
|
|
32
|
+
"seal": "bin/seal"
|
|
33
|
+
},
|
|
34
|
+
"main": "dist/index.js",
|
|
35
|
+
"module": "dist/index.js",
|
|
36
|
+
"exports": {
|
|
37
|
+
".": "./dist/index.js",
|
|
38
|
+
"./proof": "./dist/proof.js",
|
|
39
|
+
"./manifest": "./dist/manifest.js",
|
|
40
|
+
"./crypto": "./dist/crypto.js",
|
|
41
|
+
"./errors": "./dist/errors.js"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"vite": "^2.9.18",
|
|
46
|
+
"vitest": "^1.6.0",
|
|
47
|
+
"ternent-identity": "0.0.13",
|
|
48
|
+
"ternent-utils": "1.1.1"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "vite build",
|
|
52
|
+
"test": "vitest run"
|
|
53
|
+
}
|
|
54
|
+
}
|