@tinycloud/share-sdk 0.3.0-beta.0 → 0.3.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +455 -605
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +133 -53
- package/dist/index.d.ts +133 -53
- package/dist/index.js +452 -602
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -4614,25 +4614,25 @@ function encodeTo(int, target, offset = 0) {
|
|
|
4614
4614
|
function encodingLength(int) {
|
|
4615
4615
|
return varint_default.encodingLength(int);
|
|
4616
4616
|
}
|
|
4617
|
-
function create(code22,
|
|
4618
|
-
const size =
|
|
4617
|
+
function create(code22, digest3) {
|
|
4618
|
+
const size = digest3.byteLength;
|
|
4619
4619
|
const sizeOffset = encodingLength(code22);
|
|
4620
4620
|
const digestOffset = sizeOffset + encodingLength(size);
|
|
4621
4621
|
const bytes3 = new Uint8Array(digestOffset + size);
|
|
4622
4622
|
encodeTo(code22, bytes3, 0);
|
|
4623
4623
|
encodeTo(size, bytes3, sizeOffset);
|
|
4624
|
-
bytes3.set(
|
|
4625
|
-
return new Digest(code22, size,
|
|
4624
|
+
bytes3.set(digest3, digestOffset);
|
|
4625
|
+
return new Digest(code22, size, digest3, bytes3);
|
|
4626
4626
|
}
|
|
4627
4627
|
function decode4(multihash) {
|
|
4628
4628
|
const bytes3 = coerce2(multihash);
|
|
4629
4629
|
const [code22, sizeOffset] = decode3(bytes3);
|
|
4630
4630
|
const [size, digestOffset] = decode3(bytes3.subarray(sizeOffset));
|
|
4631
|
-
const
|
|
4632
|
-
if (
|
|
4631
|
+
const digest3 = bytes3.subarray(sizeOffset + digestOffset);
|
|
4632
|
+
if (digest3.byteLength !== size) {
|
|
4633
4633
|
throw new Error("Incorrect length");
|
|
4634
4634
|
}
|
|
4635
|
-
return new Digest(code22, size,
|
|
4635
|
+
return new Digest(code22, size, digest3, bytes3);
|
|
4636
4636
|
}
|
|
4637
4637
|
function equals2(a, b) {
|
|
4638
4638
|
if (a === b) {
|
|
@@ -4650,10 +4650,10 @@ var Digest = class {
|
|
|
4650
4650
|
/**
|
|
4651
4651
|
* Creates a multihash digest.
|
|
4652
4652
|
*/
|
|
4653
|
-
constructor(code22, size,
|
|
4653
|
+
constructor(code22, size, digest3, bytes3) {
|
|
4654
4654
|
this.code = code22;
|
|
4655
4655
|
this.size = size;
|
|
4656
|
-
this.digest =
|
|
4656
|
+
this.digest = digest3;
|
|
4657
4657
|
this.bytes = bytes3;
|
|
4658
4658
|
}
|
|
4659
4659
|
};
|
|
@@ -4734,8 +4734,8 @@ var CID = class _CID {
|
|
|
4734
4734
|
toV1() {
|
|
4735
4735
|
switch (this.version) {
|
|
4736
4736
|
case 0: {
|
|
4737
|
-
const { code: code22, digest:
|
|
4738
|
-
const multihash = create(code22,
|
|
4737
|
+
const { code: code22, digest: digest3 } = this.multihash;
|
|
4738
|
+
const multihash = create(code22, digest3);
|
|
4739
4739
|
return _CID.createV1(this.code, multihash);
|
|
4740
4740
|
}
|
|
4741
4741
|
case 1: {
|
|
@@ -4789,8 +4789,8 @@ var CID = class _CID {
|
|
|
4789
4789
|
return new _CID(version, code22, multihash, bytes3 ?? encodeCID(version, code22, multihash.bytes));
|
|
4790
4790
|
} else if (value[cidSymbol] === true) {
|
|
4791
4791
|
const { version, multihash, code: code22 } = value;
|
|
4792
|
-
const
|
|
4793
|
-
return _CID.create(version, code22,
|
|
4792
|
+
const digest3 = decode4(multihash);
|
|
4793
|
+
return _CID.create(version, code22, digest3);
|
|
4794
4794
|
} else {
|
|
4795
4795
|
return null;
|
|
4796
4796
|
}
|
|
@@ -4800,11 +4800,11 @@ var CID = class _CID {
|
|
|
4800
4800
|
* @param code - Code of the codec content is encoded in, see https://github.com/multiformats/multicodec/blob/master/table.csv
|
|
4801
4801
|
* @param digest - (Multi)hash of the of the content.
|
|
4802
4802
|
*/
|
|
4803
|
-
static create(version, code22,
|
|
4803
|
+
static create(version, code22, digest3) {
|
|
4804
4804
|
if (typeof code22 !== "number") {
|
|
4805
4805
|
throw new Error("String codecs are no longer supported");
|
|
4806
4806
|
}
|
|
4807
|
-
if (!(
|
|
4807
|
+
if (!(digest3.bytes instanceof Uint8Array)) {
|
|
4808
4808
|
throw new Error("Invalid digest");
|
|
4809
4809
|
}
|
|
4810
4810
|
switch (version) {
|
|
@@ -4812,12 +4812,12 @@ var CID = class _CID {
|
|
|
4812
4812
|
if (code22 !== DAG_PB_CODE) {
|
|
4813
4813
|
throw new Error(`Version 0 CID must use dag-pb (code: ${DAG_PB_CODE}) block encoding`);
|
|
4814
4814
|
} else {
|
|
4815
|
-
return new _CID(version, code22,
|
|
4815
|
+
return new _CID(version, code22, digest3, digest3.bytes);
|
|
4816
4816
|
}
|
|
4817
4817
|
}
|
|
4818
4818
|
case 1: {
|
|
4819
|
-
const bytes3 = encodeCID(version, code22,
|
|
4820
|
-
return new _CID(version, code22,
|
|
4819
|
+
const bytes3 = encodeCID(version, code22, digest3.bytes);
|
|
4820
|
+
return new _CID(version, code22, digest3, bytes3);
|
|
4821
4821
|
}
|
|
4822
4822
|
default: {
|
|
4823
4823
|
throw new Error("Invalid version");
|
|
@@ -4827,8 +4827,8 @@ var CID = class _CID {
|
|
|
4827
4827
|
/**
|
|
4828
4828
|
* Simplified version of `create` for CIDv0.
|
|
4829
4829
|
*/
|
|
4830
|
-
static createV0(
|
|
4831
|
-
return _CID.create(0, DAG_PB_CODE,
|
|
4830
|
+
static createV0(digest3) {
|
|
4831
|
+
return _CID.create(0, DAG_PB_CODE, digest3);
|
|
4832
4832
|
}
|
|
4833
4833
|
/**
|
|
4834
4834
|
* Simplified version of `create` for CIDv1.
|
|
@@ -4836,8 +4836,8 @@ var CID = class _CID {
|
|
|
4836
4836
|
* @param code - Content encoding format code.
|
|
4837
4837
|
* @param digest - Multihash of the content.
|
|
4838
4838
|
*/
|
|
4839
|
-
static createV1(code22,
|
|
4840
|
-
return _CID.create(1, code22,
|
|
4839
|
+
static createV1(code22, digest3) {
|
|
4840
|
+
return _CID.create(1, code22, digest3);
|
|
4841
4841
|
}
|
|
4842
4842
|
/**
|
|
4843
4843
|
* Decoded a CID from its binary representation. The byte array must contain
|
|
@@ -4870,8 +4870,8 @@ var CID = class _CID {
|
|
|
4870
4870
|
throw new Error("Incorrect length");
|
|
4871
4871
|
}
|
|
4872
4872
|
const digestBytes3 = multihashBytes.subarray(specs.multihashSize - specs.digestSize);
|
|
4873
|
-
const
|
|
4874
|
-
const cid2 = specs.version === 0 ? _CID.createV0(
|
|
4873
|
+
const digest3 = new Digest(specs.multihashCode, specs.digestSize, digestBytes3, multihashBytes);
|
|
4874
|
+
const cid2 = specs.version === 0 ? _CID.createV0(digest3) : _CID.createV1(specs.codec, digest3);
|
|
4875
4875
|
return [cid2, bytes3.subarray(specs.size)];
|
|
4876
4876
|
}
|
|
4877
4877
|
/**
|
|
@@ -4994,8 +4994,8 @@ var cidSymbol = /* @__PURE__ */ Symbol.for("@ipld/js-cid/CID");
|
|
|
4994
4994
|
var code = 85;
|
|
4995
4995
|
var SHA256_CODE = 18;
|
|
4996
4996
|
async function computeCid(bytes3) {
|
|
4997
|
-
const
|
|
4998
|
-
return CID.create(1, code,
|
|
4997
|
+
const digest3 = create(SHA256_CODE, (0, import_sha2.sha256)(new Uint8Array(bytes3)));
|
|
4998
|
+
return CID.create(1, code, digest3).toString();
|
|
4999
4999
|
}
|
|
5000
5000
|
function isCanonicalRawCid(cidString) {
|
|
5001
5001
|
let cid2;
|
|
@@ -5806,7 +5806,7 @@ async function signCompactUcanAuthorization(input) {
|
|
|
5806
5806
|
const publicKey = ed25519PublicKeyFromDidKey(principal);
|
|
5807
5807
|
const header = {
|
|
5808
5808
|
alg: "EdDSA",
|
|
5809
|
-
jwk: { alg: "EdDSA", crv: "Ed25519", kty: "OKP", x:
|
|
5809
|
+
jwk: { alg: "EdDSA", crv: "Ed25519", kty: "OKP", x: toBase64Url(publicKey) },
|
|
5810
5810
|
typ: "JWT",
|
|
5811
5811
|
ucv: "0.10.0"
|
|
5812
5812
|
};
|
|
@@ -5820,13 +5820,13 @@ async function signCompactUcanAuthorization(input) {
|
|
|
5820
5820
|
nnc: input.nonce,
|
|
5821
5821
|
prf: input.proofs
|
|
5822
5822
|
};
|
|
5823
|
-
const protectedSegment =
|
|
5824
|
-
const payloadSegment =
|
|
5823
|
+
const protectedSegment = toBase64Url(new TextEncoder().encode(canonicalize(header)));
|
|
5824
|
+
const payloadSegment = toBase64Url(new TextEncoder().encode(canonicalize(payload)));
|
|
5825
5825
|
const signingInput = new TextEncoder().encode(`${protectedSegment}.${payloadSegment}`);
|
|
5826
5826
|
const signature = await input.sign(signingInput);
|
|
5827
5827
|
if (signature.length !== 64) throw new TypeError("compact Authorization signature must be Ed25519");
|
|
5828
5828
|
return verifyCompactUcanAuthorization(
|
|
5829
|
-
`${protectedSegment}.${payloadSegment}.${
|
|
5829
|
+
`${protectedSegment}.${payloadSegment}.${toBase64Url(signature)}`
|
|
5830
5830
|
);
|
|
5831
5831
|
}
|
|
5832
5832
|
function verifyCompactUcanAuthorization(authorization, expectedCid) {
|
|
@@ -5834,9 +5834,9 @@ function verifyCompactUcanAuthorization(authorization, expectedCid) {
|
|
|
5834
5834
|
const segments = authorization.split(".");
|
|
5835
5835
|
if (segments.length !== 3 || segments.some((segment) => segment.length === 0)) throw new TypeError("compact Authorization must contain three segments");
|
|
5836
5836
|
const [headerSegment, payloadSegment, signatureSegment] = segments;
|
|
5837
|
-
const headerBytes =
|
|
5838
|
-
const payloadBytes =
|
|
5839
|
-
const signature =
|
|
5837
|
+
const headerBytes = fromBase64Url(headerSegment);
|
|
5838
|
+
const payloadBytes = fromBase64Url(payloadSegment);
|
|
5839
|
+
const signature = fromBase64Url(signatureSegment);
|
|
5840
5840
|
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
5841
5841
|
const header = JSON.parse(decoder.decode(headerBytes));
|
|
5842
5842
|
const payload = JSON.parse(decoder.decode(payloadBytes));
|
|
@@ -5849,7 +5849,7 @@ function verifyCompactUcanAuthorization(authorization, expectedCid) {
|
|
|
5849
5849
|
if (typeof payload.iss !== "string" || typeof payload.aud !== "string" || typeof payload.nnc !== "string" || !Number.isInteger(payload.nbf) || !Number.isInteger(payload.exp) || payload.nbf >= payload.exp || !Array.isArray(payload.prf) || payload.prf.some((proof) => typeof proof !== "string") || !Array.isArray(payload.fct) || payload.fct.length !== 1) throw new TypeError("compact Authorization payload is invalid");
|
|
5850
5850
|
const principal = payload.iss.split("#", 1)[0];
|
|
5851
5851
|
const publicKey = ed25519PublicKeyFromDidKey(principal);
|
|
5852
|
-
if (!equal(publicKey,
|
|
5852
|
+
if (!equal(publicKey, fromBase64Url(jwk.x))) throw new TypeError("compact Authorization JWK does not bind issuer");
|
|
5853
5853
|
if (!import_ed255192.ed25519.verify(signature, new TextEncoder().encode(`${headerSegment}.${payloadSegment}`), publicKey, { zip215: false })) throw new TypeError("compact Authorization signature is invalid");
|
|
5854
5854
|
const cid2 = CID.createV1(85, create(30, (0, import_blake3.blake3)(new TextEncoder().encode(authorization)))).toString();
|
|
5855
5855
|
if (expectedCid !== void 0 && cid2 !== expectedCid) throw new TypeError("compact Authorization CID mismatch");
|
|
@@ -5862,16 +5862,6 @@ function object(value, label) {
|
|
|
5862
5862
|
function assertExactKeys(value, keys, label) {
|
|
5863
5863
|
if (Object.keys(value).length !== keys.length || Object.keys(value).some((key) => !keys.includes(key))) throw new TypeError(`${label} has unknown or missing fields`);
|
|
5864
5864
|
}
|
|
5865
|
-
function decodeBase64Url(value) {
|
|
5866
|
-
if (!/^[A-Za-z0-9_-]+$/.test(value) || value.length % 4 === 1) throw new TypeError("compact Authorization segment is not base64url");
|
|
5867
|
-
const bytes3 = typeof Buffer !== "undefined" ? new Uint8Array(Buffer.from(value, "base64url")) : Uint8Array.from(atob(value.replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(value.length / 4) * 4, "=")), (character) => character.charCodeAt(0));
|
|
5868
|
-
const encoded = typeof Buffer !== "undefined" ? Buffer.from(bytes3).toString("base64url") : btoa(String.fromCharCode(...bytes3)).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
5869
|
-
if (encoded !== value) throw new TypeError("compact Authorization segment is not canonical");
|
|
5870
|
-
return bytes3;
|
|
5871
|
-
}
|
|
5872
|
-
function encodeBase64Url(value) {
|
|
5873
|
-
return typeof Buffer !== "undefined" ? Buffer.from(value).toString("base64url") : btoa(String.fromCharCode(...value)).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
5874
|
-
}
|
|
5875
5865
|
function equal(left, right) {
|
|
5876
5866
|
return left.length === right.length && left.every((byte, index) => byte === right[index]);
|
|
5877
5867
|
}
|
|
@@ -5989,8 +5979,8 @@ async function verifyEnvelopeV3(envelope, options) {
|
|
|
5989
5979
|
if (hex(sourceDigest) !== parsed.contentSourceDigestHex) return false;
|
|
5990
5980
|
const sortedCapabilities = [...policy.capabilityCeiling].sort((left, right) => canonicalize(left).localeCompare(canonicalize(right)));
|
|
5991
5981
|
const capabilityCeilingHashHex = hex((0, import_sha256.sha256)(new TextEncoder().encode(`${POLICY_CAPABILITY_V1_DOMAIN}${canonicalize(sortedCapabilities)}`)));
|
|
5992
|
-
const
|
|
5993
|
-
const nativeProjectionHashHex = hex((0, import_sha256.sha256)(new TextEncoder().encode(`${NATIVE_PROJECTION_V1_DOMAIN}${canonicalize(
|
|
5982
|
+
const nativeProjection2 = sortedCapabilities.map((capability) => capability.kind === "encryption" ? { service: "tinycloud.encryption", space: capability.resource, path: capability.resource, actions: [capability.action] } : { service: "tinycloud.kv", space: capability.resource.slice(0, capability.resource.indexOf("/kv/")), path: capability.resource.split("/kv/")[1], actions: [...capability.actions], caveat: { type: "xyz.tinycloud.resource/selector", kind: capability.selector, value: capability.resource } }).sort((left, right) => canonicalize(left).localeCompare(canonicalize(right)));
|
|
5983
|
+
const nativeProjectionHashHex = hex((0, import_sha256.sha256)(new TextEncoder().encode(`${NATIVE_PROJECTION_V1_DOMAIN}${canonicalize(nativeProjection2)}`)));
|
|
5994
5984
|
const expectedAttenuation = Object.fromEntries(sortedCapabilities.map((capability) => capability.kind === "encryption" ? [capability.resource, { [capability.action]: [{}] }] : [capability.resource, Object.fromEntries(capability.actions.map((action) => [action, [{ kind: capability.selector, type: "xyz.tinycloud.resource/selector", value: capability.resource }]]))]));
|
|
5995
5985
|
const kv = policy.capabilityCeiling.find((capability) => capability.kind === "kv");
|
|
5996
5986
|
const expectedKvActions = parsed.actions.flatMap((action) => action === "read" ? ["tinycloud.kv/get", "tinycloud.kv/metadata"] : action === "list" ? ["tinycloud.kv/list"] : ["tinycloud.kv/put"]);
|
|
@@ -6003,8 +5993,8 @@ async function verifyEnvelopeV3(envelope, options) {
|
|
|
6003
5993
|
const expectedBindingDigestHex = hex((0, import_sha256.sha256)(new TextEncoder().encode(canonicalize({ enforcerDid: binding.enforcerDid, nodeAudience: binding.nodeAudience }))));
|
|
6004
5994
|
if (binding.enforcerDid !== parsed.target.nodeAudience || binding.attestationBindingDigestHex !== expectedBindingDigestHex || bindingSignature.signerDid !== binding.nodeAudience || bindingSignature.suite !== "Ed25519" || Date.parse(binding.issuedAt) > Date.now() || Date.parse(binding.expiresAt) <= Date.now() || Date.parse(binding.expiresAt) < Date.parse(parsed.expiry)) return false;
|
|
6005
5995
|
try {
|
|
6006
|
-
const
|
|
6007
|
-
if (!import_ed255193.ed25519.verify(fromBase64Url(bindingSignature.value),
|
|
5996
|
+
const digest3 = (0, import_sha256.sha256)(new TextEncoder().encode(`${ATTESTED_ENFORCER_V2_DOMAIN}${canonicalize(unsignedBinding)}`));
|
|
5997
|
+
if (!import_ed255193.ed25519.verify(fromBase64Url(bindingSignature.value), digest3, ed25519PublicKeyFromDidKey(binding.nodeAudience), ED25519_VERIFY_OPTS2)) return false;
|
|
6008
5998
|
} catch {
|
|
6009
5999
|
return false;
|
|
6010
6000
|
}
|
|
@@ -6787,10 +6777,31 @@ async function parseAddressedEnvelope(value) {
|
|
|
6787
6777
|
return { envelope, policy: decoded, policyCid: envelope.authorizationTarget.policyCid };
|
|
6788
6778
|
}
|
|
6789
6779
|
|
|
6790
|
-
// src/
|
|
6791
|
-
var import_ed255195 = require("@noble/curves/ed25519");
|
|
6780
|
+
// src/addressed-publish.ts
|
|
6792
6781
|
var import_sha2562 = require("@noble/hashes/sha256");
|
|
6793
6782
|
|
|
6783
|
+
// src/authorization.ts
|
|
6784
|
+
async function authorizeShare(input) {
|
|
6785
|
+
if (input.resumeToken !== void 0) {
|
|
6786
|
+
if (input.resumeToken.length < 16 || input.resumeToken.length > 512) {
|
|
6787
|
+
return { state: "denied", reason: "rejected" };
|
|
6788
|
+
}
|
|
6789
|
+
return input.adapter.resume({
|
|
6790
|
+
envelope: input.envelope,
|
|
6791
|
+
method: input.method,
|
|
6792
|
+
resumeToken: input.resumeToken,
|
|
6793
|
+
...input.proof === void 0 ? {} : { proof: input.proof }
|
|
6794
|
+
});
|
|
6795
|
+
}
|
|
6796
|
+
return input.adapter.begin({ envelope: input.envelope, method: input.method });
|
|
6797
|
+
}
|
|
6798
|
+
function authorizationMethodForTarget(target) {
|
|
6799
|
+
if (target.kind === "recipientDid") return "openkey-device";
|
|
6800
|
+
if (target.kind === "email") return "email-claim";
|
|
6801
|
+
if (target.kind === "emailDomain") return "email-claim";
|
|
6802
|
+
return void 0;
|
|
6803
|
+
}
|
|
6804
|
+
|
|
6794
6805
|
// ../../node_modules/multiformats/dist/src/bytes.js
|
|
6795
6806
|
var empty2 = new Uint8Array(0);
|
|
6796
6807
|
function equals3(aa, bb) {
|
|
@@ -7132,6 +7143,347 @@ function rfc46482({ name, prefix, bitsPerChar, alphabet }) {
|
|
|
7132
7143
|
});
|
|
7133
7144
|
}
|
|
7134
7145
|
|
|
7146
|
+
// ../../node_modules/multiformats/dist/src/bases/base58.js
|
|
7147
|
+
var base58btc2 = baseX2({
|
|
7148
|
+
name: "base58btc",
|
|
7149
|
+
prefix: "z",
|
|
7150
|
+
alphabet: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
|
7151
|
+
});
|
|
7152
|
+
var base58flickr2 = baseX2({
|
|
7153
|
+
name: "base58flickr",
|
|
7154
|
+
prefix: "Z",
|
|
7155
|
+
alphabet: "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
|
|
7156
|
+
});
|
|
7157
|
+
|
|
7158
|
+
// src/targets.ts
|
|
7159
|
+
function validEmail(value) {
|
|
7160
|
+
return /^[^@\s]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i.test(value);
|
|
7161
|
+
}
|
|
7162
|
+
function validDomain(value) {
|
|
7163
|
+
return /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(?:\.(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?))+$/i.test(value);
|
|
7164
|
+
}
|
|
7165
|
+
function validRecipientDid(value) {
|
|
7166
|
+
if (value.length === 0 || value.length > 2048 || /[\u0000-\u0020\u007f]/.test(value)) return false;
|
|
7167
|
+
const parts = value.split(":");
|
|
7168
|
+
if (parts.length < 3 || parts[0] !== "did" || !/^[a-z0-9]+$/.test(parts[1] ?? "")) return false;
|
|
7169
|
+
const identifier = parts.slice(2);
|
|
7170
|
+
if (identifier.some((part) => part.length === 0)) return false;
|
|
7171
|
+
if (parts[1] === "web") {
|
|
7172
|
+
const host = identifier[0] ?? "";
|
|
7173
|
+
if (host.length > 253 || host.split(".").some((label) => !label || label.length > 63 || !/^[A-Za-z0-9-]+$/.test(label) || label.startsWith("-") || label.endsWith("-"))) return false;
|
|
7174
|
+
return identifier.slice(1).every((part) => /^[A-Za-z0-9._%-]+$/.test(part));
|
|
7175
|
+
}
|
|
7176
|
+
if (parts[1] === "pkh") return identifier.length >= 3 && identifier.every((part) => /^[A-Za-z0-9._%-]+$/.test(part));
|
|
7177
|
+
if (parts[1] === "key") {
|
|
7178
|
+
try {
|
|
7179
|
+
const bytes3 = base58btc2.decode(identifier.join(":"));
|
|
7180
|
+
return bytes3.length === 34 && bytes3[0] === 237 && bytes3[1] === 1;
|
|
7181
|
+
} catch {
|
|
7182
|
+
return false;
|
|
7183
|
+
}
|
|
7184
|
+
}
|
|
7185
|
+
return false;
|
|
7186
|
+
}
|
|
7187
|
+
function normalizeShareTarget(target) {
|
|
7188
|
+
if (target.kind === "bearer") return target;
|
|
7189
|
+
if (target.kind === "recipientDid") {
|
|
7190
|
+
if (!validRecipientDid(target.did)) throw new TypeError("recipient DID is invalid");
|
|
7191
|
+
return { kind: target.kind, did: target.did };
|
|
7192
|
+
}
|
|
7193
|
+
if (target.kind === "email") {
|
|
7194
|
+
if (!validEmail(target.address)) throw new TypeError("recipient email is invalid");
|
|
7195
|
+
const at = target.address.lastIndexOf("@");
|
|
7196
|
+
return { kind: target.kind, address: `${target.address.slice(0, at)}@${target.address.slice(at + 1).toLowerCase()}` };
|
|
7197
|
+
}
|
|
7198
|
+
if (!validDomain(target.domain)) throw new TypeError("recipient email domain is invalid");
|
|
7199
|
+
return { kind: target.kind, domain: target.domain.toLowerCase() };
|
|
7200
|
+
}
|
|
7201
|
+
function targetAuthorizationMethod(target) {
|
|
7202
|
+
return authorizationMethodForTarget(target);
|
|
7203
|
+
}
|
|
7204
|
+
async function publishTargetShare(input) {
|
|
7205
|
+
const target = normalizeShareTarget(input.target);
|
|
7206
|
+
if (target.kind === "bearer") return publishShare(input);
|
|
7207
|
+
if (input.targetAdapter === void 0) {
|
|
7208
|
+
return {
|
|
7209
|
+
state: "authorization-required",
|
|
7210
|
+
method: targetAuthorizationMethod(target)
|
|
7211
|
+
};
|
|
7212
|
+
}
|
|
7213
|
+
const source = input.source instanceof Uint8Array ? input.source.slice() : await (async () => {
|
|
7214
|
+
const chunks = [];
|
|
7215
|
+
let size = 0;
|
|
7216
|
+
for await (const chunk of input.source) {
|
|
7217
|
+
if (!(chunk instanceof Uint8Array)) throw new TypeError("addressed publication source yielded invalid bytes");
|
|
7218
|
+
size += chunk.byteLength;
|
|
7219
|
+
if (size > (input.maxBytes ?? 100 * 1024 * 1024)) throw new TypeError("addressed publication exceeds maxBytes");
|
|
7220
|
+
chunks.push(chunk.slice());
|
|
7221
|
+
}
|
|
7222
|
+
const bytes3 = new Uint8Array(size);
|
|
7223
|
+
let offset = 0;
|
|
7224
|
+
for (const chunk of chunks) {
|
|
7225
|
+
bytes3.set(chunk, offset);
|
|
7226
|
+
offset += chunk.byteLength;
|
|
7227
|
+
}
|
|
7228
|
+
return bytes3;
|
|
7229
|
+
})();
|
|
7230
|
+
const files = input.files === void 0 || input.files.length === 0 ? [{ bytes: source }] : input.files;
|
|
7231
|
+
const limit = input.maxBytes ?? SHARE_CONTENT_LIMIT;
|
|
7232
|
+
let totalBytes = 0;
|
|
7233
|
+
for (const file of files) {
|
|
7234
|
+
totalBytes += file.bytes.byteLength;
|
|
7235
|
+
if (!Number.isSafeInteger(totalBytes) || totalBytes > limit) {
|
|
7236
|
+
throw new SharePublishError("max-bytes-exceeded", "addressed publication exceeds the combined byte limit");
|
|
7237
|
+
}
|
|
7238
|
+
}
|
|
7239
|
+
return input.targetAdapter.publish({
|
|
7240
|
+
source,
|
|
7241
|
+
filename: input.filename,
|
|
7242
|
+
...input.files === void 0 ? {} : { files: input.files },
|
|
7243
|
+
...input.mediaType === void 0 ? {} : { mediaType: input.mediaType },
|
|
7244
|
+
...input.resourceKind === void 0 ? {} : { resourceKind: input.resourceKind },
|
|
7245
|
+
...input.actions === void 0 ? {} : { actions: input.actions },
|
|
7246
|
+
target,
|
|
7247
|
+
expiresAt: input.expiresAt ?? new Date((input.now?.() ?? Date.now()) + 7 * 24 * 60 * 60 * 1e3),
|
|
7248
|
+
origin: input.origin,
|
|
7249
|
+
...input.inline === void 0 ? {} : { inline: input.inline },
|
|
7250
|
+
upload: {
|
|
7251
|
+
...input.registryBaseUrl === void 0 ? {} : { registryBaseUrl: input.registryBaseUrl },
|
|
7252
|
+
...input.fetchFn === void 0 ? {} : { fetchFn: input.fetchFn },
|
|
7253
|
+
...input.authorizeUpload === void 0 ? {} : { authorizeUpload: input.authorizeUpload },
|
|
7254
|
+
...input.authorizationOrigin === void 0 ? {} : { authorizationOrigin: input.authorizationOrigin },
|
|
7255
|
+
...input.credentials === void 0 ? {} : { credentials: input.credentials },
|
|
7256
|
+
...input.allowInsecureRegistry === void 0 ? {} : { allowInsecureRegistry: input.allowInsecureRegistry },
|
|
7257
|
+
...input.uploadBlob === void 0 ? {} : { uploadBlob: input.uploadBlob }
|
|
7258
|
+
},
|
|
7259
|
+
...input.notify === void 0 ? {} : { notify: input.notify }
|
|
7260
|
+
});
|
|
7261
|
+
}
|
|
7262
|
+
|
|
7263
|
+
// src/addressed-publish.ts
|
|
7264
|
+
var POLICY_V1_DOMAIN = "xyz.tinycloud.policy/policy/v1\0";
|
|
7265
|
+
var POLICY_V2_DOMAIN = "xyz.tinycloud.policy/policy/v2\0";
|
|
7266
|
+
var POLICY_CAPABILITY_V1_DOMAIN2 = "xyz.tinycloud.policy/PolicyCapability/v1\0";
|
|
7267
|
+
var CONTENT_SOURCE_V1_DOMAIN2 = "xyz.tinycloud.policy/ContentSource/v1\0";
|
|
7268
|
+
var NATIVE_PROJECTION_V1_DOMAIN2 = "xyz.tinycloud.policy/NativeProjection/v1\0";
|
|
7269
|
+
var ENVELOPE_V3_DOMAIN = "xyz.tinycloud.share/envelope/v3\0";
|
|
7270
|
+
var textEncoder = new TextEncoder();
|
|
7271
|
+
function targetMatcher(target) {
|
|
7272
|
+
if (target.kind === "recipientDid") return { kind: "recipientDid", value: target.did };
|
|
7273
|
+
if (target.kind === "email") return { kind: "exactEmail", value: target.address };
|
|
7274
|
+
return { kind: "emailDomain", value: target.domain };
|
|
7275
|
+
}
|
|
7276
|
+
function targetKind(target) {
|
|
7277
|
+
return target.kind;
|
|
7278
|
+
}
|
|
7279
|
+
function assertSafeInput(input) {
|
|
7280
|
+
if (!/^[A-Za-z0-9_-]{16,128}$/.test(input.shareId)) throw new TypeError("addressed share id is invalid");
|
|
7281
|
+
if (input.filename.length === 0 || input.filename === "." || input.filename === ".." || /[/\\\u0000-\u001f\u007f]/.test(input.filename)) throw new TypeError("addressed filename is invalid");
|
|
7282
|
+
if (!Number.isSafeInteger(input.byteLength) || input.byteLength < 0 || input.byteLength > SHARE_CONTENT_LIMIT) throw new TypeError("addressed content length is invalid");
|
|
7283
|
+
if (input.actions.length === 0 || input.policyActions.length === 0) throw new TypeError("addressed share actions are empty");
|
|
7284
|
+
if (!Number.isFinite(input.expiresAt.getTime()) || input.expiresAt.getTime() <= Date.now()) throw new TypeError("addressed share expiry must be in the future");
|
|
7285
|
+
if (input.artifact === "html" && (input.resource.kind !== "prefix" || !input.actions.includes("read") || !input.actions.includes("list"))) throw new TypeError("html artifacts require a readable prefix");
|
|
7286
|
+
if (input.contentSource.shareId !== input.shareId || input.contentSource.selector !== input.resource.kind) throw new TypeError("addressed content source is not bound to the share");
|
|
7287
|
+
}
|
|
7288
|
+
function hex2(bytes3) {
|
|
7289
|
+
return [...bytes3].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
7290
|
+
}
|
|
7291
|
+
function digestHex(value, domain) {
|
|
7292
|
+
return hex2((0, import_sha2562.sha256)(textEncoder.encode(`${domain}${canonicalize(value)}`)));
|
|
7293
|
+
}
|
|
7294
|
+
function sortCanonical(values) {
|
|
7295
|
+
return [...values].sort((left, right) => canonicalize(left).localeCompare(canonicalize(right)));
|
|
7296
|
+
}
|
|
7297
|
+
function base32Lower2(bytes3) {
|
|
7298
|
+
const alphabet = "abcdefghijklmnopqrstuvwxyz234567";
|
|
7299
|
+
let output = "";
|
|
7300
|
+
let buffer = 0;
|
|
7301
|
+
let bits = 0;
|
|
7302
|
+
for (const byte of bytes3) {
|
|
7303
|
+
buffer = buffer << 8 | byte;
|
|
7304
|
+
bits += 8;
|
|
7305
|
+
while (bits >= 5) {
|
|
7306
|
+
output += alphabet[buffer >>> bits - 5 & 31];
|
|
7307
|
+
bits -= 5;
|
|
7308
|
+
}
|
|
7309
|
+
}
|
|
7310
|
+
if (bits > 0) output += alphabet[buffer << 5 - bits & 31];
|
|
7311
|
+
return output;
|
|
7312
|
+
}
|
|
7313
|
+
function rfc3339Seconds(value) {
|
|
7314
|
+
return new Date(Math.floor(value.getTime() / 1e3) * 1e3).toISOString().replace(".000Z", "Z");
|
|
7315
|
+
}
|
|
7316
|
+
function nativeProjection(capabilities) {
|
|
7317
|
+
return sortCanonical(capabilities.map((capability) => capability.kind === "encryption" ? { service: "tinycloud.encryption", space: capability.resource, path: capability.resource, actions: [capability.action] } : {
|
|
7318
|
+
service: "tinycloud.kv",
|
|
7319
|
+
space: capability.resource.slice(0, capability.resource.indexOf("/kv/")),
|
|
7320
|
+
path: capability.resource.slice(capability.resource.indexOf("/kv/") + 4),
|
|
7321
|
+
actions: [...capability.actions],
|
|
7322
|
+
caveat: { type: "xyz.tinycloud.resource/selector", kind: capability.selector, value: capability.resource }
|
|
7323
|
+
}));
|
|
7324
|
+
}
|
|
7325
|
+
async function createPolicy(options, capabilities) {
|
|
7326
|
+
const fields = {
|
|
7327
|
+
ownerDid: options.authority.ownerDid,
|
|
7328
|
+
createdAt: rfc3339Seconds(/* @__PURE__ */ new Date()),
|
|
7329
|
+
expiresAt: rfc3339Seconds(options.expiresAt),
|
|
7330
|
+
contentSource: options.contentSource,
|
|
7331
|
+
capabilityCeiling: [...capabilities]
|
|
7332
|
+
};
|
|
7333
|
+
const unsigned = options.credentialRequirement === void 0 ? { schema: "xyz.tinycloud.policy/policy/v1", ...fields } : { schema: "xyz.tinycloud.policy/policy/v2", ...fields, credentialRequirement: options.credentialRequirement };
|
|
7334
|
+
const domain = options.credentialRequirement === void 0 ? POLICY_V1_DOMAIN : POLICY_V2_DOMAIN;
|
|
7335
|
+
const policyDigestHex = digestHex(unsigned, domain);
|
|
7336
|
+
const signature = await options.authority.sign((0, import_sha2562.sha256)(textEncoder.encode(`${domain}${canonicalize(unsigned)}`)));
|
|
7337
|
+
if (signature.byteLength !== 64) throw new TypeError("policy signature must be Ed25519");
|
|
7338
|
+
const policy = {
|
|
7339
|
+
...unsigned,
|
|
7340
|
+
policyId: `pol_${base32Lower2(Uint8Array.from(policyDigestHex.match(/../g), (byte) => Number.parseInt(byte, 16)))}`,
|
|
7341
|
+
signature: { suite: "Ed25519", signerDid: options.authority.ownerDid, value: toBase64Url(signature) }
|
|
7342
|
+
};
|
|
7343
|
+
return { policy, policyCid: await computeCid(textEncoder.encode(canonicalize(policy))), policyDigestHex };
|
|
7344
|
+
}
|
|
7345
|
+
function publicationResult(input) {
|
|
7346
|
+
const result = {
|
|
7347
|
+
protocol: "tinycloud-share",
|
|
7348
|
+
version: SHARE_PUBLISH_RESULT_VERSION,
|
|
7349
|
+
url: input.url,
|
|
7350
|
+
link: { kind: input.options.inline === true ? "inline" : "compact", cid: input.envelopeCid },
|
|
7351
|
+
metadata: {
|
|
7352
|
+
protocol: "tinycloud-share",
|
|
7353
|
+
version: 1,
|
|
7354
|
+
shareId: input.options.shareId,
|
|
7355
|
+
origin: input.options.shareOrigin,
|
|
7356
|
+
target: { kind: targetKind(input.options.target), origin: input.options.nodeOrigin, nodeAudience: input.enforcerDid, spaceId: input.options.spaceId },
|
|
7357
|
+
resource: { ...input.options.resource },
|
|
7358
|
+
actions: [...input.options.actions],
|
|
7359
|
+
expiresAt: input.expiry,
|
|
7360
|
+
display: { filename: input.options.filename },
|
|
7361
|
+
recipientMatcher: { ...input.matcher },
|
|
7362
|
+
policyCid: input.policyCid,
|
|
7363
|
+
ownerDelegationCid: input.policyRootCid,
|
|
7364
|
+
enforcementDelegationCid: input.enforcementRootCid,
|
|
7365
|
+
ownerDid: input.options.authority.ownerDid,
|
|
7366
|
+
enforcerDid: input.enforcerDid,
|
|
7367
|
+
envelopeCid: input.envelopeCid,
|
|
7368
|
+
shareCid: input.envelopeCid
|
|
7369
|
+
},
|
|
7370
|
+
registryDeleteAfter: input.retention
|
|
7371
|
+
};
|
|
7372
|
+
Object.defineProperty(result, "toJSON", { enumerable: false, value: () => redactPublishedShare(result) });
|
|
7373
|
+
Object.defineProperty(result, "url", { enumerable: false, value: input.url });
|
|
7374
|
+
Object.defineProperty(result, "deliveryMaterial", { enumerable: false, value: input.deliveryMaterial });
|
|
7375
|
+
return result;
|
|
7376
|
+
}
|
|
7377
|
+
async function publishAddressedShare(options) {
|
|
7378
|
+
assertSafeInput(options);
|
|
7379
|
+
const target = normalizeShareTarget(options.target);
|
|
7380
|
+
if (target.kind === "bearer") throw new TypeError("addressed target is required");
|
|
7381
|
+
const expiry = rfc3339Seconds(options.expiresAt);
|
|
7382
|
+
const matcher = targetMatcher(target);
|
|
7383
|
+
const capabilities = sortCanonical([
|
|
7384
|
+
{ kind: "kv", resource: options.contentSource.kvResource, selector: options.resource.kind, actions: [...options.policyActions] },
|
|
7385
|
+
{ kind: "encryption", resource: options.contentSource.encryptionNetwork, action: "tinycloud.encryption/decrypt" }
|
|
7386
|
+
]);
|
|
7387
|
+
const created = await createPolicy(options, capabilities);
|
|
7388
|
+
const contentSourceDigestHex = digestHex(options.contentSource, CONTENT_SOURCE_V1_DOMAIN2);
|
|
7389
|
+
const capabilityCeilingHashHex = digestHex(capabilities, POLICY_CAPABILITY_V1_DOMAIN2);
|
|
7390
|
+
const nativeProjectionHashHex = digestHex(nativeProjection(capabilities), NATIVE_PROJECTION_V1_DOMAIN2);
|
|
7391
|
+
const commonRoot = {
|
|
7392
|
+
ownerDid: options.authority.ownerDid,
|
|
7393
|
+
policyId: created.policy.policyId,
|
|
7394
|
+
policyDigestHex: created.policyDigestHex,
|
|
7395
|
+
policyCid: created.policyCid,
|
|
7396
|
+
contentSourceDigestHex,
|
|
7397
|
+
capabilityCeilingHashHex,
|
|
7398
|
+
nativeProjectionHashHex,
|
|
7399
|
+
notBefore: new Date(created.policy.createdAt),
|
|
7400
|
+
expiresAt: new Date(expiry),
|
|
7401
|
+
nodeAudience: options.nodeAudience,
|
|
7402
|
+
capabilities
|
|
7403
|
+
};
|
|
7404
|
+
const policyRootReceipt = await options.authority.createOwnerRoot({ ...commonRoot, role: "policy-authority", audienceDid: `did:tinycloud:policy:${created.policyDigestHex}` });
|
|
7405
|
+
const enforcementRootReceipt = await options.authority.createOwnerRoot({ ...commonRoot, role: "policy-enforcement", audienceDid: options.enforcerDid });
|
|
7406
|
+
const policyRoot = { cid: policyRootReceipt.cid, authorization: policyRootReceipt.delegationHeader.Authorization.replace(/^Bearer\s+/i, ""), role: "policy-authority" };
|
|
7407
|
+
const enforcementRoot = { cid: enforcementRootReceipt.cid, authorization: enforcementRootReceipt.delegationHeader.Authorization.replace(/^Bearer\s+/i, ""), role: "policy-enforcement" };
|
|
7408
|
+
const registration = await options.authority.registerPolicy({
|
|
7409
|
+
policyCid: created.policyCid,
|
|
7410
|
+
policy: created.policy,
|
|
7411
|
+
policyRoot,
|
|
7412
|
+
enforcementRoot,
|
|
7413
|
+
contentSourceDigestHex,
|
|
7414
|
+
nativeProjectionHashHex,
|
|
7415
|
+
rootExpiresAt: expiry,
|
|
7416
|
+
enforcerDid: options.enforcerDid,
|
|
7417
|
+
expectedNodeAudience: options.nodeAudience
|
|
7418
|
+
});
|
|
7419
|
+
if (registration.policyCid !== created.policyCid || registration.policyRootCid !== policyRoot.cid || registration.enforcementRootCid !== enforcementRoot.cid) throw new Error("Policy/v3 registration receipt is not bound to the published roots");
|
|
7420
|
+
const unsigned = {
|
|
7421
|
+
version: 3,
|
|
7422
|
+
shareId: options.shareId,
|
|
7423
|
+
recipientMatcher: matcher,
|
|
7424
|
+
...options.deliveryEmail === void 0 ? {} : { deliveryEmail: options.deliveryEmail },
|
|
7425
|
+
actions: [...options.actions],
|
|
7426
|
+
resource: { ...options.resource },
|
|
7427
|
+
target: { origin: options.nodeOrigin, nodeAudience: registration.attestedEnforcerBinding.enforcerDid, spaceId: options.spaceId },
|
|
7428
|
+
policy: created.policy,
|
|
7429
|
+
policyCid: created.policyCid,
|
|
7430
|
+
policyRoot,
|
|
7431
|
+
enforcementRoot,
|
|
7432
|
+
attestedEnforcerBinding: registration.attestedEnforcerBinding,
|
|
7433
|
+
contentSource: options.contentSource,
|
|
7434
|
+
contentSourceDigestHex,
|
|
7435
|
+
encryptionNetwork: options.contentSource.encryptionNetwork,
|
|
7436
|
+
expiry,
|
|
7437
|
+
display: { filename: options.filename },
|
|
7438
|
+
encrypted: true,
|
|
7439
|
+
metadata: {
|
|
7440
|
+
mediaType: options.mediaType,
|
|
7441
|
+
byteLength: options.byteLength,
|
|
7442
|
+
filename: options.filename,
|
|
7443
|
+
...options.mediaType.startsWith("text/") ? { encoding: "utf-8" } : {},
|
|
7444
|
+
...options.artifact === void 0 ? {} : { artifact: options.artifact }
|
|
7445
|
+
}
|
|
7446
|
+
};
|
|
7447
|
+
unsignedShareEnvelopeV3Schema.parse(unsigned);
|
|
7448
|
+
const envelopeSignature = await options.authority.sign((0, import_sha2562.sha256)(textEncoder.encode(`${ENVELOPE_V3_DOMAIN}${canonicalize(unsigned)}`)));
|
|
7449
|
+
if (envelopeSignature.byteLength !== 64) throw new TypeError("v3 envelope signature must be Ed25519");
|
|
7450
|
+
const envelope = { ...unsigned, signature: { signerDid: options.authority.ownerDid, algorithm: "Ed25519", value: toBase64Url(envelopeSignature) } };
|
|
7451
|
+
shareEnvelopeV3Schema.parse(envelope);
|
|
7452
|
+
const envelopeKey = generateKey();
|
|
7453
|
+
try {
|
|
7454
|
+
const sealed = await seal(textEncoder.encode(canonicalize(envelope)), envelopeKey);
|
|
7455
|
+
let url;
|
|
7456
|
+
let retention = options.expiresAt.toISOString();
|
|
7457
|
+
if (options.inline === true) url = await encodeInlineShareUrl({ origin: options.shareOrigin, ciphertext: sealed.blob, key32: envelopeKey });
|
|
7458
|
+
else {
|
|
7459
|
+
const uploaded = await uploadShareBlob({ source: new Uint8Array([1]), filename: options.filename, origin: options.shareOrigin, ...options.upload }, { blob: sealed.blob, cid: sealed.cid, deleteAfter: retention, contentLength: sealed.blob.byteLength });
|
|
7460
|
+
retention = uploaded.deleteAfter;
|
|
7461
|
+
url = encodeShareUrl({ origin: options.shareOrigin, ciphertextCid: uploaded.cid, key32: envelopeKey });
|
|
7462
|
+
}
|
|
7463
|
+
await options.publishBinding?.({
|
|
7464
|
+
version: 3,
|
|
7465
|
+
shareCid: sealed.cid,
|
|
7466
|
+
shareId: options.shareId,
|
|
7467
|
+
policyCid: created.policyCid,
|
|
7468
|
+
policyRootCid: policyRoot.cid,
|
|
7469
|
+
enforcementRootCid: enforcementRoot.cid,
|
|
7470
|
+
contentSourceDigestHex
|
|
7471
|
+
});
|
|
7472
|
+
const deliveryMaterial = { envelope, sealedEnvelope: toBase64Url(sealed.blob), envelopeKey: toBase64Url(envelopeKey), shareCid: sealed.cid };
|
|
7473
|
+
options.onDeliveryMaterial?.(deliveryMaterial);
|
|
7474
|
+
return publicationResult({ options, url, envelopeCid: sealed.cid, matcher, policyCid: created.policyCid, policyRootCid: policyRoot.cid, enforcementRootCid: enforcementRoot.cid, enforcerDid: registration.attestedEnforcerBinding.enforcerDid, expiry, retention, deliveryMaterial });
|
|
7475
|
+
} finally {
|
|
7476
|
+
envelopeKey.fill(0);
|
|
7477
|
+
}
|
|
7478
|
+
}
|
|
7479
|
+
|
|
7480
|
+
// src/policy-authority.ts
|
|
7481
|
+
var import_ed255196 = require("@noble/curves/ed25519");
|
|
7482
|
+
|
|
7483
|
+
// src/owner-policy.ts
|
|
7484
|
+
var import_ed255195 = require("@noble/curves/ed25519");
|
|
7485
|
+
var import_sha2563 = require("@noble/hashes/sha256");
|
|
7486
|
+
|
|
7135
7487
|
// ../../node_modules/multiformats/dist/src/bases/base32.js
|
|
7136
7488
|
var base322 = rfc46482({
|
|
7137
7489
|
prefix: "b",
|
|
@@ -7200,18 +7552,6 @@ var base36upper2 = baseX2({
|
|
|
7200
7552
|
alphabet: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
7201
7553
|
});
|
|
7202
7554
|
|
|
7203
|
-
// ../../node_modules/multiformats/dist/src/bases/base58.js
|
|
7204
|
-
var base58btc2 = baseX2({
|
|
7205
|
-
name: "base58btc",
|
|
7206
|
-
prefix: "z",
|
|
7207
|
-
alphabet: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
|
7208
|
-
});
|
|
7209
|
-
var base58flickr2 = baseX2({
|
|
7210
|
-
name: "base58flickr",
|
|
7211
|
-
prefix: "Z",
|
|
7212
|
-
alphabet: "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
|
|
7213
|
-
});
|
|
7214
|
-
|
|
7215
7555
|
// ../../node_modules/multiformats/dist/src/vendor/varint.js
|
|
7216
7556
|
var encode_12 = encode4;
|
|
7217
7557
|
var MSB2 = 128;
|
|
@@ -7285,25 +7625,25 @@ function encodingLength2(int) {
|
|
|
7285
7625
|
}
|
|
7286
7626
|
|
|
7287
7627
|
// ../../node_modules/multiformats/dist/src/hashes/digest.js
|
|
7288
|
-
function create2(code3,
|
|
7289
|
-
const size =
|
|
7628
|
+
function create2(code3, digest3) {
|
|
7629
|
+
const size = digest3.byteLength;
|
|
7290
7630
|
const sizeOffset = encodingLength2(code3);
|
|
7291
7631
|
const digestOffset = sizeOffset + encodingLength2(size);
|
|
7292
7632
|
const bytes3 = new Uint8Array(digestOffset + size);
|
|
7293
7633
|
encodeTo2(code3, bytes3, 0);
|
|
7294
7634
|
encodeTo2(size, bytes3, sizeOffset);
|
|
7295
|
-
bytes3.set(
|
|
7296
|
-
return new Digest2(code3, size,
|
|
7635
|
+
bytes3.set(digest3, digestOffset);
|
|
7636
|
+
return new Digest2(code3, size, digest3, bytes3);
|
|
7297
7637
|
}
|
|
7298
7638
|
function decode8(multihash) {
|
|
7299
7639
|
const bytes3 = coerce3(multihash);
|
|
7300
7640
|
const [code3, sizeOffset] = decode7(bytes3);
|
|
7301
7641
|
const [size, digestOffset] = decode7(bytes3.subarray(sizeOffset));
|
|
7302
|
-
const
|
|
7303
|
-
if (
|
|
7642
|
+
const digest3 = bytes3.subarray(sizeOffset + digestOffset);
|
|
7643
|
+
if (digest3.byteLength !== size) {
|
|
7304
7644
|
throw new Error("Incorrect length");
|
|
7305
7645
|
}
|
|
7306
|
-
return new Digest2(code3, size,
|
|
7646
|
+
return new Digest2(code3, size, digest3, bytes3);
|
|
7307
7647
|
}
|
|
7308
7648
|
function equals4(a, b) {
|
|
7309
7649
|
if (a === b) {
|
|
@@ -7321,10 +7661,10 @@ var Digest2 = class {
|
|
|
7321
7661
|
/**
|
|
7322
7662
|
* Creates a multihash digest.
|
|
7323
7663
|
*/
|
|
7324
|
-
constructor(code3, size,
|
|
7664
|
+
constructor(code3, size, digest3, bytes3) {
|
|
7325
7665
|
this.code = code3;
|
|
7326
7666
|
this.size = size;
|
|
7327
|
-
this.digest =
|
|
7667
|
+
this.digest = digest3;
|
|
7328
7668
|
this.bytes = bytes3;
|
|
7329
7669
|
}
|
|
7330
7670
|
};
|
|
@@ -7407,8 +7747,8 @@ var CID2 = class _CID2 {
|
|
|
7407
7747
|
toV1() {
|
|
7408
7748
|
switch (this.version) {
|
|
7409
7749
|
case 0: {
|
|
7410
|
-
const { code: code3, digest:
|
|
7411
|
-
const multihash = create2(code3,
|
|
7750
|
+
const { code: code3, digest: digest3 } = this.multihash;
|
|
7751
|
+
const multihash = create2(code3, digest3);
|
|
7412
7752
|
return _CID2.createV1(this.code, multihash);
|
|
7413
7753
|
}
|
|
7414
7754
|
case 1: {
|
|
@@ -7462,8 +7802,8 @@ var CID2 = class _CID2 {
|
|
|
7462
7802
|
return new _CID2(version, code3, multihash, bytes3 ?? encodeCID2(version, code3, multihash.bytes));
|
|
7463
7803
|
} else if (value[cidSymbol2] === true) {
|
|
7464
7804
|
const { version, multihash, code: code3 } = value;
|
|
7465
|
-
const
|
|
7466
|
-
return _CID2.create(version, code3,
|
|
7805
|
+
const digest3 = decode8(multihash);
|
|
7806
|
+
return _CID2.create(version, code3, digest3);
|
|
7467
7807
|
} else {
|
|
7468
7808
|
return null;
|
|
7469
7809
|
}
|
|
@@ -7473,11 +7813,11 @@ var CID2 = class _CID2 {
|
|
|
7473
7813
|
* @param code - Code of the codec content is encoded in, see https://github.com/multiformats/multicodec/blob/master/table.csv
|
|
7474
7814
|
* @param digest - (Multi)hash of the of the content.
|
|
7475
7815
|
*/
|
|
7476
|
-
static create(version, code3,
|
|
7816
|
+
static create(version, code3, digest3) {
|
|
7477
7817
|
if (typeof code3 !== "number") {
|
|
7478
7818
|
throw new Error("String codecs are no longer supported");
|
|
7479
7819
|
}
|
|
7480
|
-
if (!(
|
|
7820
|
+
if (!(digest3.bytes instanceof Uint8Array)) {
|
|
7481
7821
|
throw new Error("Invalid digest");
|
|
7482
7822
|
}
|
|
7483
7823
|
switch (version) {
|
|
@@ -7485,12 +7825,12 @@ var CID2 = class _CID2 {
|
|
|
7485
7825
|
if (code3 !== DAG_PB_CODE2) {
|
|
7486
7826
|
throw new Error(`Version 0 CID must use dag-pb (code: ${DAG_PB_CODE2}) block encoding`);
|
|
7487
7827
|
} else {
|
|
7488
|
-
return new _CID2(version, code3,
|
|
7828
|
+
return new _CID2(version, code3, digest3, digest3.bytes);
|
|
7489
7829
|
}
|
|
7490
7830
|
}
|
|
7491
7831
|
case 1: {
|
|
7492
|
-
const bytes3 = encodeCID2(version, code3,
|
|
7493
|
-
return new _CID2(version, code3,
|
|
7832
|
+
const bytes3 = encodeCID2(version, code3, digest3.bytes);
|
|
7833
|
+
return new _CID2(version, code3, digest3, bytes3);
|
|
7494
7834
|
}
|
|
7495
7835
|
default: {
|
|
7496
7836
|
throw new Error("Invalid version");
|
|
@@ -7500,8 +7840,8 @@ var CID2 = class _CID2 {
|
|
|
7500
7840
|
/**
|
|
7501
7841
|
* Simplified version of `create` for CIDv0.
|
|
7502
7842
|
*/
|
|
7503
|
-
static createV0(
|
|
7504
|
-
return _CID2.create(0, DAG_PB_CODE2,
|
|
7843
|
+
static createV0(digest3) {
|
|
7844
|
+
return _CID2.create(0, DAG_PB_CODE2, digest3);
|
|
7505
7845
|
}
|
|
7506
7846
|
/**
|
|
7507
7847
|
* Simplified version of `create` for CIDv1.
|
|
@@ -7509,8 +7849,8 @@ var CID2 = class _CID2 {
|
|
|
7509
7849
|
* @param code - Content encoding format code.
|
|
7510
7850
|
* @param digest - Multihash of the content.
|
|
7511
7851
|
*/
|
|
7512
|
-
static createV1(code3,
|
|
7513
|
-
return _CID2.create(1, code3,
|
|
7852
|
+
static createV1(code3, digest3) {
|
|
7853
|
+
return _CID2.create(1, code3, digest3);
|
|
7514
7854
|
}
|
|
7515
7855
|
/**
|
|
7516
7856
|
* Decoded a CID from its binary representation. The byte array must contain
|
|
@@ -7543,8 +7883,8 @@ var CID2 = class _CID2 {
|
|
|
7543
7883
|
throw new Error("Incorrect length");
|
|
7544
7884
|
}
|
|
7545
7885
|
const digestBytes3 = multihashBytes.subarray(specs.multihashSize - specs.digestSize);
|
|
7546
|
-
const
|
|
7547
|
-
const cid2 = specs.version === 0 ? _CID2.createV0(
|
|
7886
|
+
const digest3 = new Digest2(specs.multihashCode, specs.digestSize, digestBytes3, multihashBytes);
|
|
7887
|
+
const cid2 = specs.version === 0 ? _CID2.createV0(digest3) : _CID2.createV1(specs.codec, digest3);
|
|
7548
7888
|
return [cid2, bytes3.subarray(specs.size)];
|
|
7549
7889
|
}
|
|
7550
7890
|
/**
|
|
@@ -7696,10 +8036,10 @@ function fromB64(value) {
|
|
|
7696
8036
|
throw new Error("base64url decoding is unavailable");
|
|
7697
8037
|
}
|
|
7698
8038
|
function cid(bytesValue) {
|
|
7699
|
-
return CID2.createV1(code2, create2(SHA256_CODE2, (0,
|
|
8039
|
+
return CID2.createV1(code2, create2(SHA256_CODE2, (0, import_sha2563.sha256)(bytesValue))).toString(base322.encoder);
|
|
7700
8040
|
}
|
|
7701
8041
|
function digest(bytesValue) {
|
|
7702
|
-
return b64((0,
|
|
8042
|
+
return b64((0, import_sha2563.sha256)(bytesValue));
|
|
7703
8043
|
}
|
|
7704
8044
|
function didKeyFromEd25519PublicKey2(publicKey) {
|
|
7705
8045
|
if (publicKey.length !== 32) throw new Error("share key public key must be 32 bytes");
|
|
@@ -7890,368 +8230,8 @@ function validateOwnerSharePolicyRegistrationBytes(bytesValue, expected) {
|
|
|
7890
8230
|
return validateOwnerSharePolicyRegistration(value, expected);
|
|
7891
8231
|
}
|
|
7892
8232
|
|
|
7893
|
-
// src/authorization.ts
|
|
7894
|
-
async function authorizeShare(input) {
|
|
7895
|
-
if (input.resumeToken !== void 0) {
|
|
7896
|
-
if (input.resumeToken.length < 16 || input.resumeToken.length > 512) {
|
|
7897
|
-
return { state: "denied", reason: "rejected" };
|
|
7898
|
-
}
|
|
7899
|
-
return input.adapter.resume({
|
|
7900
|
-
envelope: input.envelope,
|
|
7901
|
-
method: input.method,
|
|
7902
|
-
resumeToken: input.resumeToken,
|
|
7903
|
-
...input.proof === void 0 ? {} : { proof: input.proof }
|
|
7904
|
-
});
|
|
7905
|
-
}
|
|
7906
|
-
return input.adapter.begin({ envelope: input.envelope, method: input.method });
|
|
7907
|
-
}
|
|
7908
|
-
function authorizationMethodForTarget(target) {
|
|
7909
|
-
if (target.kind === "recipientDid") return "openkey-device";
|
|
7910
|
-
if (target.kind === "email") return "email-claim";
|
|
7911
|
-
if (target.kind === "emailDomain") return "email-claim";
|
|
7912
|
-
return void 0;
|
|
7913
|
-
}
|
|
7914
|
-
|
|
7915
|
-
// src/targets.ts
|
|
7916
|
-
function validEmail(value) {
|
|
7917
|
-
return /^[^@\s]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i.test(value);
|
|
7918
|
-
}
|
|
7919
|
-
function validDomain(value) {
|
|
7920
|
-
return /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(?:\.(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?))+$/i.test(value);
|
|
7921
|
-
}
|
|
7922
|
-
function validRecipientDid(value) {
|
|
7923
|
-
if (value.length === 0 || value.length > 2048 || /[\u0000-\u0020\u007f]/.test(value)) return false;
|
|
7924
|
-
const parts = value.split(":");
|
|
7925
|
-
if (parts.length < 3 || parts[0] !== "did" || !/^[a-z0-9]+$/.test(parts[1] ?? "")) return false;
|
|
7926
|
-
const identifier = parts.slice(2);
|
|
7927
|
-
if (identifier.some((part) => part.length === 0)) return false;
|
|
7928
|
-
if (parts[1] === "web") {
|
|
7929
|
-
const host = identifier[0] ?? "";
|
|
7930
|
-
if (host.length > 253 || host.split(".").some((label) => !label || label.length > 63 || !/^[A-Za-z0-9-]+$/.test(label) || label.startsWith("-") || label.endsWith("-"))) return false;
|
|
7931
|
-
return identifier.slice(1).every((part) => /^[A-Za-z0-9._%-]+$/.test(part));
|
|
7932
|
-
}
|
|
7933
|
-
if (parts[1] === "pkh") return identifier.length >= 3 && identifier.every((part) => /^[A-Za-z0-9._%-]+$/.test(part));
|
|
7934
|
-
if (parts[1] === "key") {
|
|
7935
|
-
try {
|
|
7936
|
-
const bytes3 = base58btc2.decode(identifier.join(":"));
|
|
7937
|
-
return bytes3.length === 34 && bytes3[0] === 237 && bytes3[1] === 1;
|
|
7938
|
-
} catch {
|
|
7939
|
-
return false;
|
|
7940
|
-
}
|
|
7941
|
-
}
|
|
7942
|
-
return false;
|
|
7943
|
-
}
|
|
7944
|
-
function normalizeShareTarget(target) {
|
|
7945
|
-
if (target.kind === "bearer") return target;
|
|
7946
|
-
if (target.kind === "recipientDid") {
|
|
7947
|
-
if (!validRecipientDid(target.did)) throw new TypeError("recipient DID is invalid");
|
|
7948
|
-
return { kind: target.kind, did: target.did };
|
|
7949
|
-
}
|
|
7950
|
-
if (target.kind === "email") {
|
|
7951
|
-
if (!validEmail(target.address)) throw new TypeError("recipient email is invalid");
|
|
7952
|
-
const at = target.address.lastIndexOf("@");
|
|
7953
|
-
return { kind: target.kind, address: `${target.address.slice(0, at)}@${target.address.slice(at + 1).toLowerCase()}` };
|
|
7954
|
-
}
|
|
7955
|
-
if (!validDomain(target.domain)) throw new TypeError("recipient email domain is invalid");
|
|
7956
|
-
return { kind: target.kind, domain: target.domain.toLowerCase() };
|
|
7957
|
-
}
|
|
7958
|
-
function targetAuthorizationMethod(target) {
|
|
7959
|
-
return authorizationMethodForTarget(target);
|
|
7960
|
-
}
|
|
7961
|
-
async function publishTargetShare(input) {
|
|
7962
|
-
const target = normalizeShareTarget(input.target);
|
|
7963
|
-
if (target.kind === "bearer") return publishShare(input);
|
|
7964
|
-
if (input.targetAdapter === void 0) {
|
|
7965
|
-
return {
|
|
7966
|
-
state: "authorization-required",
|
|
7967
|
-
method: targetAuthorizationMethod(target)
|
|
7968
|
-
};
|
|
7969
|
-
}
|
|
7970
|
-
const source = input.source instanceof Uint8Array ? input.source.slice() : await (async () => {
|
|
7971
|
-
const chunks = [];
|
|
7972
|
-
let size = 0;
|
|
7973
|
-
for await (const chunk of input.source) {
|
|
7974
|
-
if (!(chunk instanceof Uint8Array)) throw new TypeError("addressed publication source yielded invalid bytes");
|
|
7975
|
-
size += chunk.byteLength;
|
|
7976
|
-
if (size > (input.maxBytes ?? 100 * 1024 * 1024)) throw new TypeError("addressed publication exceeds maxBytes");
|
|
7977
|
-
chunks.push(chunk.slice());
|
|
7978
|
-
}
|
|
7979
|
-
const bytes3 = new Uint8Array(size);
|
|
7980
|
-
let offset = 0;
|
|
7981
|
-
for (const chunk of chunks) {
|
|
7982
|
-
bytes3.set(chunk, offset);
|
|
7983
|
-
offset += chunk.byteLength;
|
|
7984
|
-
}
|
|
7985
|
-
return bytes3;
|
|
7986
|
-
})();
|
|
7987
|
-
const files = input.files === void 0 || input.files.length === 0 ? [{ bytes: source }] : input.files;
|
|
7988
|
-
const limit = input.maxBytes ?? SHARE_CONTENT_LIMIT;
|
|
7989
|
-
let totalBytes = 0;
|
|
7990
|
-
for (const file of files) {
|
|
7991
|
-
totalBytes += file.bytes.byteLength;
|
|
7992
|
-
if (!Number.isSafeInteger(totalBytes) || totalBytes > limit) {
|
|
7993
|
-
throw new SharePublishError("max-bytes-exceeded", "addressed publication exceeds the combined byte limit");
|
|
7994
|
-
}
|
|
7995
|
-
}
|
|
7996
|
-
return input.targetAdapter.publish({
|
|
7997
|
-
source,
|
|
7998
|
-
filename: input.filename,
|
|
7999
|
-
...input.files === void 0 ? {} : { files: input.files },
|
|
8000
|
-
...input.mediaType === void 0 ? {} : { mediaType: input.mediaType },
|
|
8001
|
-
...input.resourceKind === void 0 ? {} : { resourceKind: input.resourceKind },
|
|
8002
|
-
...input.actions === void 0 ? {} : { actions: input.actions },
|
|
8003
|
-
target,
|
|
8004
|
-
expiresAt: input.expiresAt ?? new Date((input.now?.() ?? Date.now()) + 7 * 24 * 60 * 60 * 1e3),
|
|
8005
|
-
origin: input.origin,
|
|
8006
|
-
...input.inline === void 0 ? {} : { inline: input.inline },
|
|
8007
|
-
upload: {
|
|
8008
|
-
...input.registryBaseUrl === void 0 ? {} : { registryBaseUrl: input.registryBaseUrl },
|
|
8009
|
-
...input.fetchFn === void 0 ? {} : { fetchFn: input.fetchFn },
|
|
8010
|
-
...input.authorizeUpload === void 0 ? {} : { authorizeUpload: input.authorizeUpload },
|
|
8011
|
-
...input.authorizationOrigin === void 0 ? {} : { authorizationOrigin: input.authorizationOrigin },
|
|
8012
|
-
...input.credentials === void 0 ? {} : { credentials: input.credentials },
|
|
8013
|
-
...input.allowInsecureRegistry === void 0 ? {} : { allowInsecureRegistry: input.allowInsecureRegistry },
|
|
8014
|
-
...input.uploadBlob === void 0 ? {} : { uploadBlob: input.uploadBlob }
|
|
8015
|
-
},
|
|
8016
|
-
...input.notify === void 0 ? {} : { notify: input.notify }
|
|
8017
|
-
});
|
|
8018
|
-
}
|
|
8019
|
-
|
|
8020
|
-
// src/addressed-publish.ts
|
|
8021
|
-
var ENVELOPE_DOMAIN = "xyz.tinycloud.share/envelope/v2\0";
|
|
8022
|
-
function targetMatcher(target) {
|
|
8023
|
-
if (target.kind === "recipientDid") return { kind: "recipientDid", value: target.did };
|
|
8024
|
-
if (target.kind === "email") return { kind: "exactEmail", value: target.address };
|
|
8025
|
-
return { kind: "emailDomain", value: target.domain };
|
|
8026
|
-
}
|
|
8027
|
-
function targetKind(target) {
|
|
8028
|
-
return target.kind;
|
|
8029
|
-
}
|
|
8030
|
-
function assertSafeInput(input) {
|
|
8031
|
-
if (!/^[A-Za-z0-9_-]{16,128}$/.test(input.shareId)) throw new TypeError("addressed share id is invalid");
|
|
8032
|
-
if (input.filename.length === 0 || input.filename === "." || input.filename === ".." || /[/\\\u0000-\u001f\u007f]/.test(input.filename)) throw new TypeError("addressed filename is invalid");
|
|
8033
|
-
if (!Number.isSafeInteger(input.byteLength) || input.byteLength < 0 || input.byteLength > SHARE_CONTENT_LIMIT) throw new TypeError("addressed content length is invalid");
|
|
8034
|
-
if (input.actions.length === 0 || input.policyActions.length === 0) throw new TypeError("addressed share actions are empty");
|
|
8035
|
-
const expiry = input.expiresAt.getTime();
|
|
8036
|
-
if (!Number.isFinite(expiry) || expiry <= Date.now()) throw new TypeError("addressed share expiry must be in the future");
|
|
8037
|
-
if (input.artifact === "html" && (input.resource.kind !== "prefix" || !input.actions.includes("read") || !input.actions.includes("list"))) throw new TypeError("html artifacts require a readable prefix");
|
|
8038
|
-
if (input.contentSource.kind !== "kv") throw new TypeError("addressed policy publication requires a KV content source");
|
|
8039
|
-
}
|
|
8040
|
-
async function sha2564(value) {
|
|
8041
|
-
return toBase64Url(new Uint8Array(await crypto.subtle.digest("SHA-256", value)));
|
|
8042
|
-
}
|
|
8043
|
-
function publicationResult(input) {
|
|
8044
|
-
const result = {
|
|
8045
|
-
protocol: "tinycloud-share",
|
|
8046
|
-
version: SHARE_PUBLISH_RESULT_VERSION,
|
|
8047
|
-
url: input.url,
|
|
8048
|
-
link: { kind: input.options.inline === true ? "inline" : "compact", cid: input.envelopeCid },
|
|
8049
|
-
metadata: {
|
|
8050
|
-
protocol: "tinycloud-share",
|
|
8051
|
-
version: 1,
|
|
8052
|
-
shareId: input.options.shareId,
|
|
8053
|
-
origin: input.options.shareOrigin,
|
|
8054
|
-
target: {
|
|
8055
|
-
kind: targetKind(input.options.target),
|
|
8056
|
-
origin: input.options.nodeOrigin,
|
|
8057
|
-
nodeAudience: input.options.nodeAudience,
|
|
8058
|
-
spaceId: input.options.spaceId
|
|
8059
|
-
},
|
|
8060
|
-
resource: { ...input.options.resource },
|
|
8061
|
-
actions: [...input.options.actions],
|
|
8062
|
-
expiresAt: input.options.expiresAt.toISOString(),
|
|
8063
|
-
display: { filename: input.options.filename },
|
|
8064
|
-
recipientMatcher: { ...input.matcher },
|
|
8065
|
-
registrationCid: input.registration.registrationCid,
|
|
8066
|
-
policyCid: input.policyCid,
|
|
8067
|
-
ownerDelegationCid: input.registration.ownerDelegationCid,
|
|
8068
|
-
enforcementDelegationCid: input.enforcementDelegationCid,
|
|
8069
|
-
ownerDid: input.registration.ownerDid,
|
|
8070
|
-
shareKeyDid: input.shareKeyDid,
|
|
8071
|
-
enforcerDid: input.registration.enforcerDid,
|
|
8072
|
-
envelopeCid: input.envelopeCid,
|
|
8073
|
-
shareCid: input.shareCid
|
|
8074
|
-
},
|
|
8075
|
-
registryDeleteAfter: input.retention
|
|
8076
|
-
};
|
|
8077
|
-
Object.defineProperty(result, "toJSON", { enumerable: false, value: () => redactPublishedShare(result) });
|
|
8078
|
-
Object.defineProperty(result, "url", { enumerable: false, value: input.url });
|
|
8079
|
-
return result;
|
|
8080
|
-
}
|
|
8081
|
-
async function publishAddressedShare(options) {
|
|
8082
|
-
assertSafeInput(options);
|
|
8083
|
-
const target = normalizeShareTarget(options.target);
|
|
8084
|
-
if (target.kind === "bearer") throw new TypeError("addressed target is required");
|
|
8085
|
-
if (options.contentSource.kind !== "kv") throw new TypeError("addressed policy publication requires a KV content source");
|
|
8086
|
-
const contentSource = options.contentSource;
|
|
8087
|
-
const matcher = targetMatcher(target);
|
|
8088
|
-
const expiresAt = options.expiresAt.toISOString();
|
|
8089
|
-
const contentSourceDigest = options.contentSourceDigest ?? await sha2564(new TextEncoder().encode(canonicalize(contentSource)));
|
|
8090
|
-
const shareKey = await createDelegatedShareKey({ extractable: false });
|
|
8091
|
-
let envelopeKey;
|
|
8092
|
-
try {
|
|
8093
|
-
const permissions = [
|
|
8094
|
-
{
|
|
8095
|
-
service: "tinycloud.kv",
|
|
8096
|
-
path: options.resource.kind === "prefix" ? `${options.resource.path.replace(/\/+$/, "")}/` : options.resource.path,
|
|
8097
|
-
actions: [...options.policyActions]
|
|
8098
|
-
},
|
|
8099
|
-
...options.decryption === void 0 ? [] : [{
|
|
8100
|
-
service: "tinycloud.encryption",
|
|
8101
|
-
path: options.decryption.networkId,
|
|
8102
|
-
actions: [options.decryption.action]
|
|
8103
|
-
}]
|
|
8104
|
-
];
|
|
8105
|
-
const ownerDelegation = await options.authority.createOwnerDelegation({
|
|
8106
|
-
delegateDid: shareKey.did,
|
|
8107
|
-
spaceId: options.spaceId,
|
|
8108
|
-
permissions,
|
|
8109
|
-
expiresAt: options.expiresAt
|
|
8110
|
-
});
|
|
8111
|
-
const policy = {
|
|
8112
|
-
type: "TinyCloudSharePolicy",
|
|
8113
|
-
version: 2,
|
|
8114
|
-
shareId: options.shareId,
|
|
8115
|
-
ownerDid: options.authority.ownerDid,
|
|
8116
|
-
shareKeyDid: shareKey.did,
|
|
8117
|
-
recipientMatcher: matcher,
|
|
8118
|
-
target: {
|
|
8119
|
-
origin: options.nodeOrigin,
|
|
8120
|
-
nodeAudience: options.nodeAudience,
|
|
8121
|
-
enforcerDid: options.enforcerDid,
|
|
8122
|
-
spaceId: options.spaceId
|
|
8123
|
-
},
|
|
8124
|
-
resource: { ...options.resource },
|
|
8125
|
-
actions: [...options.policyActions],
|
|
8126
|
-
...options.decryption === void 0 ? {} : { decryption: options.decryption },
|
|
8127
|
-
contentSource,
|
|
8128
|
-
contentSourceDigest,
|
|
8129
|
-
ownerDelegationCid: ownerDelegation.delegationCid,
|
|
8130
|
-
expiresAt
|
|
8131
|
-
};
|
|
8132
|
-
const canonicalPolicy = await canonicalOwnerSharePolicy(policy);
|
|
8133
|
-
const policyProof = toBase64Url(await shareKey.sign(canonicalPolicy.bytes));
|
|
8134
|
-
const enforcementDelegation = await createPolicyEnforcementDelegation({
|
|
8135
|
-
ownerDelegation,
|
|
8136
|
-
shareKey,
|
|
8137
|
-
enforcerDid: options.enforcerDid,
|
|
8138
|
-
policyCid: canonicalPolicy.cid,
|
|
8139
|
-
shareId: options.shareId,
|
|
8140
|
-
spaceId: options.spaceId,
|
|
8141
|
-
nodeAudience: options.nodeAudience,
|
|
8142
|
-
path: options.resource.path,
|
|
8143
|
-
actions: options.policyActions,
|
|
8144
|
-
contentSourceDigest,
|
|
8145
|
-
expiresAt
|
|
8146
|
-
});
|
|
8147
|
-
const registration = await options.authority.registerOwnerSharePolicy({
|
|
8148
|
-
policy: { bytes: canonicalPolicy.bytes, cid: canonicalPolicy.cid, proof: policyProof },
|
|
8149
|
-
ownerDelegation,
|
|
8150
|
-
enforcementDelegation,
|
|
8151
|
-
contentSourceDigest
|
|
8152
|
-
});
|
|
8153
|
-
const authorityMaterialDigest = await sha2564(fromBase64Url(enforcementDelegation.dagCbor));
|
|
8154
|
-
const authorityTarget = {
|
|
8155
|
-
origin: options.nodeOrigin,
|
|
8156
|
-
nodeAudience: options.nodeAudience,
|
|
8157
|
-
enforcerDid: options.enforcerDid,
|
|
8158
|
-
spaceId: options.spaceId
|
|
8159
|
-
};
|
|
8160
|
-
const envelopeIdentity = {
|
|
8161
|
-
schema: "xyz.tinycloud.share/envelope/v2",
|
|
8162
|
-
version: 2,
|
|
8163
|
-
shareId: options.shareId,
|
|
8164
|
-
delegationCid: ownerDelegation.delegationCid,
|
|
8165
|
-
policyCid: canonicalPolicy.cid,
|
|
8166
|
-
target: authorityTarget,
|
|
8167
|
-
resource: options.resource,
|
|
8168
|
-
actions: options.policyActions,
|
|
8169
|
-
...options.decryption === void 0 ? {} : { decryption: options.decryption },
|
|
8170
|
-
contentSource,
|
|
8171
|
-
contentSourceDigest,
|
|
8172
|
-
expiresAt
|
|
8173
|
-
};
|
|
8174
|
-
const envelopeCid = await computeCid(new TextEncoder().encode(canonicalize(envelopeIdentity)));
|
|
8175
|
-
const shareCid = await computeCid(new TextEncoder().encode(canonicalize({ version: 2, shareId: options.shareId, policyCid: canonicalPolicy.cid, envelopeCid })));
|
|
8176
|
-
const outerUnsigned = { ...envelopeIdentity, envelopeCid, shareCid };
|
|
8177
|
-
const outerSignature = toBase64Url(await shareKey.sign(new TextEncoder().encode(`${ENVELOPE_DOMAIN}${canonicalize(outerUnsigned)}`)));
|
|
8178
|
-
const unsigned = {
|
|
8179
|
-
version: 2,
|
|
8180
|
-
shareId: options.shareId,
|
|
8181
|
-
recipientMatcher: matcher,
|
|
8182
|
-
...options.deliveryEmail === void 0 ? {} : { deliveryEmail: options.deliveryEmail },
|
|
8183
|
-
actions: [...options.actions],
|
|
8184
|
-
resource: { ...options.resource },
|
|
8185
|
-
target: { origin: options.nodeOrigin, nodeAudience: options.nodeAudience, spaceId: options.spaceId },
|
|
8186
|
-
delegationCid: ownerDelegation.delegationCid,
|
|
8187
|
-
authorityMaterialHandle: registration.registration.registrationCid,
|
|
8188
|
-
authorityMaterialDigest,
|
|
8189
|
-
contentSource,
|
|
8190
|
-
contentSourceDigest,
|
|
8191
|
-
authorizationTarget: { kind: "policy", policyCid: canonicalPolicy.cid, policyBytes: toBase64Url(canonicalPolicy.bytes) },
|
|
8192
|
-
display: { filename: options.filename },
|
|
8193
|
-
expiry: expiresAt,
|
|
8194
|
-
encrypted: true,
|
|
8195
|
-
metadata: {
|
|
8196
|
-
mediaType: options.mediaType,
|
|
8197
|
-
byteLength: options.byteLength,
|
|
8198
|
-
filename: options.filename,
|
|
8199
|
-
...options.mediaType.startsWith("text/") ? { encoding: "utf-8" } : {},
|
|
8200
|
-
...options.artifact === void 0 ? {} : { artifact: options.artifact }
|
|
8201
|
-
},
|
|
8202
|
-
ownerAuthority: {
|
|
8203
|
-
registrationCid: registration.registration.registrationCid,
|
|
8204
|
-
shareCid,
|
|
8205
|
-
envelopeCid,
|
|
8206
|
-
enforcementDelegation,
|
|
8207
|
-
registrationReceipt: registration,
|
|
8208
|
-
outerEnvelope: {
|
|
8209
|
-
...outerUnsigned,
|
|
8210
|
-
signature: { signerDid: shareKey.did, algorithm: "Ed25519", value: outerSignature }
|
|
8211
|
-
}
|
|
8212
|
-
}
|
|
8213
|
-
};
|
|
8214
|
-
unsignedShareEnvelopeV2Schema.parse(unsigned);
|
|
8215
|
-
const envelopeSignature = toBase64Url(await shareKey.sign(new TextEncoder().encode(`${ENVELOPE_DOMAIN}${canonicalize(unsigned)}`)));
|
|
8216
|
-
const envelope = { ...unsigned, signature: { signerDid: shareKey.did, algorithm: "Ed25519", value: envelopeSignature } };
|
|
8217
|
-
shareEnvelopeV2Schema.parse(envelope);
|
|
8218
|
-
envelopeKey = generateKey();
|
|
8219
|
-
const sealed = await seal(new TextEncoder().encode(canonicalize(envelope)), envelopeKey);
|
|
8220
|
-
let url;
|
|
8221
|
-
let retention = expiresAt;
|
|
8222
|
-
if (options.inline === true) {
|
|
8223
|
-
url = await encodeInlineShareUrl({ origin: options.shareOrigin, ciphertext: sealed.blob, key32: envelopeKey });
|
|
8224
|
-
} else {
|
|
8225
|
-
const uploaded = await uploadShareBlob({
|
|
8226
|
-
source: new Uint8Array([1]),
|
|
8227
|
-
filename: options.filename,
|
|
8228
|
-
origin: options.shareOrigin,
|
|
8229
|
-
...options.upload
|
|
8230
|
-
}, { blob: sealed.blob, cid: sealed.cid, deleteAfter: expiresAt, contentLength: sealed.blob.byteLength });
|
|
8231
|
-
retention = uploaded.deleteAfter;
|
|
8232
|
-
url = encodeShareUrl({ origin: options.shareOrigin, ciphertextCid: uploaded.cid, key32: envelopeKey });
|
|
8233
|
-
}
|
|
8234
|
-
return publicationResult({
|
|
8235
|
-
options,
|
|
8236
|
-
url,
|
|
8237
|
-
envelopeCid: sealed.cid,
|
|
8238
|
-
shareCid,
|
|
8239
|
-
matcher,
|
|
8240
|
-
registration: registration.registration,
|
|
8241
|
-
policyCid: canonicalPolicy.cid,
|
|
8242
|
-
enforcementDelegationCid: enforcementDelegation.cid,
|
|
8243
|
-
shareKeyDid: shareKey.did,
|
|
8244
|
-
retention
|
|
8245
|
-
});
|
|
8246
|
-
} finally {
|
|
8247
|
-
shareKey.clear();
|
|
8248
|
-
envelopeKey?.fill(0);
|
|
8249
|
-
}
|
|
8250
|
-
}
|
|
8251
|
-
|
|
8252
8233
|
// src/policy-authority.ts
|
|
8253
|
-
var
|
|
8254
|
-
var ENVELOPE_DOMAIN2 = "xyz.tinycloud.share/envelope/v2\0";
|
|
8234
|
+
var ENVELOPE_DOMAIN = "xyz.tinycloud.share/envelope/v2\0";
|
|
8255
8235
|
function record(value, keys, label) {
|
|
8256
8236
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${label} is invalid`);
|
|
8257
8237
|
const output = value;
|
|
@@ -8332,7 +8312,7 @@ async function verifyOuterEnvelope(value, envelope, policyCid, expectedEnforcerD
|
|
|
8332
8312
|
const signatureBytes = fromBase64Url(requiredString(signature.value, "outer signature"));
|
|
8333
8313
|
if (signatureBytes.length !== 64 || !import_ed255196.ed25519.verify(
|
|
8334
8314
|
signatureBytes,
|
|
8335
|
-
new TextEncoder().encode(`${
|
|
8315
|
+
new TextEncoder().encode(`${ENVELOPE_DOMAIN}${canonicalize(unsigned)}`),
|
|
8336
8316
|
ed25519PublicKeyFromDidKey(envelope.signature.signerDid),
|
|
8337
8317
|
{ zip215: false }
|
|
8338
8318
|
)) return void 0;
|
|
@@ -8397,13 +8377,13 @@ function createRegisteredPolicyAuthority(options) {
|
|
|
8397
8377
|
}
|
|
8398
8378
|
|
|
8399
8379
|
// src/cache.ts
|
|
8400
|
-
var
|
|
8380
|
+
var import_sha2564 = require("@noble/hashes/sha256");
|
|
8401
8381
|
function cacheKey(key) {
|
|
8402
8382
|
if (!key.cid || !key.expiresAt) throw new Error("share cache keys require CID and expiry");
|
|
8403
8383
|
return `${key.cid}\0${key.expiresAt}`;
|
|
8404
8384
|
}
|
|
8405
8385
|
function digest2(bytes3) {
|
|
8406
|
-
return (0,
|
|
8386
|
+
return (0, import_sha2564.sha256)(bytes3);
|
|
8407
8387
|
}
|
|
8408
8388
|
function equalBytes(left, right) {
|
|
8409
8389
|
if (left.byteLength !== right.byteLength) return false;
|
|
@@ -8605,6 +8585,7 @@ function historyRecordForPublishedShare(result, now = /* @__PURE__ */ new Date()
|
|
|
8605
8585
|
registeredAt: now.toISOString(),
|
|
8606
8586
|
expiresAt: result.metadata.expiresAt,
|
|
8607
8587
|
link: result.url,
|
|
8588
|
+
...result.deliveryMaterial === void 0 ? {} : { deliveryMaterial: result.deliveryMaterial },
|
|
8608
8589
|
...result.metadata.display.filename === void 0 ? {} : { filename: result.metadata.display.filename }
|
|
8609
8590
|
};
|
|
8610
8591
|
}
|
|
@@ -8789,11 +8770,11 @@ async function notifyShare(input) {
|
|
|
8789
8770
|
}
|
|
8790
8771
|
async function defaultIdempotencyKey(shareId, recipient) {
|
|
8791
8772
|
const canonicalRecipient = canonicalize(recipient.trim().toLowerCase());
|
|
8792
|
-
const
|
|
8773
|
+
const digest3 = new Uint8Array(await crypto.subtle.digest(
|
|
8793
8774
|
"SHA-256",
|
|
8794
8775
|
new TextEncoder().encode(canonicalRecipient)
|
|
8795
8776
|
));
|
|
8796
|
-
return `tinycloud-share:${shareId}:${toBase64Url(
|
|
8777
|
+
return `tinycloud-share:${shareId}:${toBase64Url(digest3)}`;
|
|
8797
8778
|
}
|
|
8798
8779
|
|
|
8799
8780
|
// src/lifecycle.ts
|
|
@@ -8850,7 +8831,7 @@ async function migrateShare(input) {
|
|
|
8850
8831
|
|
|
8851
8832
|
// src/recipient.ts
|
|
8852
8833
|
var import_ed255198 = require("@noble/curves/ed25519");
|
|
8853
|
-
var
|
|
8834
|
+
var import_sha2565 = require("@noble/hashes/sha256");
|
|
8854
8835
|
|
|
8855
8836
|
// src/protocol.ts
|
|
8856
8837
|
var SHARE_V2_PROTOCOL = Object.freeze({
|
|
@@ -8941,12 +8922,6 @@ function fromBase64(value, label) {
|
|
|
8941
8922
|
if (toBase64(out) !== value) throw new Error(`${label} is invalid`);
|
|
8942
8923
|
return out;
|
|
8943
8924
|
}
|
|
8944
|
-
async function digest3(value) {
|
|
8945
|
-
return toBase64Url(new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(canonicalize(value)))));
|
|
8946
|
-
}
|
|
8947
|
-
async function digestText2(value) {
|
|
8948
|
-
return toBase64Url(new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value))));
|
|
8949
|
-
}
|
|
8950
8925
|
async function digestBytes2(value) {
|
|
8951
8926
|
return toBase64Url(new Uint8Array(await crypto.subtle.digest("SHA-256", value)));
|
|
8952
8927
|
}
|
|
@@ -8956,24 +8931,9 @@ function trustedPublicKey(value) {
|
|
|
8956
8931
|
}
|
|
8957
8932
|
return value.invitationPublicKey;
|
|
8958
8933
|
}
|
|
8959
|
-
async function verifyWrapped(value, key, domain, trust) {
|
|
8960
|
-
const wrapper = object2(value, `${key} response`);
|
|
8961
|
-
if (Object.keys(wrapper).length !== 2 || !Object.hasOwn(wrapper, key) || !Object.hasOwn(wrapper, "proof")) throw new Error(`${key} response is invalid`);
|
|
8962
|
-
const artifact = object2(wrapper[key], `${key} artifact`);
|
|
8963
|
-
const proof = object2(wrapper.proof, `${key} proof`);
|
|
8964
|
-
if (proof.alg !== "EdDSA" || proof.kid !== trust.invitationKid) throw new Error(`${key} proof is invalid`);
|
|
8965
|
-
if (!import_ed255198.ed25519.verify(bytes2(proof.signature, `${key} signature`), new TextEncoder().encode(`${domain}${canonicalize(artifact)}`), trustedPublicKey(trust))) throw new Error(`${key} proof is invalid`);
|
|
8966
|
-
return artifact;
|
|
8967
|
-
}
|
|
8968
8934
|
function nativeAction(action) {
|
|
8969
8935
|
return action === "list" ? "tinycloud.kv/list" : action === "edit" ? "tinycloud.kv/put" : "tinycloud.kv/get";
|
|
8970
8936
|
}
|
|
8971
|
-
function uiAction(action) {
|
|
8972
|
-
return action === "tinycloud.kv/list" ? "list" : action === "tinycloud.kv/put" ? "edit" : "read";
|
|
8973
|
-
}
|
|
8974
|
-
function selectedAction(envelope) {
|
|
8975
|
-
return envelope.actions.includes("list") ? "tinycloud.kv/list" : envelope.actions.includes("edit") ? "tinycloud.kv/put" : "tinycloud.kv/get";
|
|
8976
|
-
}
|
|
8977
8937
|
function policyAttenuationForV3(envelope) {
|
|
8978
8938
|
const policy = object2(envelope.policy, "v3 policy");
|
|
8979
8939
|
if (!Array.isArray(policy.capabilityCeiling)) throw new Error("v3 policy capability ceiling is invalid");
|
|
@@ -9043,11 +9003,11 @@ function verifyV3PolicyAuthorization(input) {
|
|
|
9043
9003
|
if (!legacyShape && !v4Shape || POLICY_SESSION_DIGEST_FACT_KEYS.some((key) => !LOWER_SHA256_HEX.test(fact[key])) || v4Shape && (!LOWER_SHA256_HEX.test(fact.credentialIdAuditDigestHex) || !LOWER_SHA256_HEX.test(fact.presentationJtiAuditDigestHex)) || compact.payload.aud !== input.holderDid || compact.payload.iss.split("#", 1)[0] !== fact.nodeAudience || fact.profile !== "policy-session-ucan/v1" || fact.ownerDid !== policy.ownerDid || fact.policyId !== policy.policyId || fact.policyCid !== input.envelope.policyCid || fact.contentSourceDigestHex !== input.envelope.contentSourceDigestHex || fact.enforcerDid !== binding.enforcerDid || fact.nodeAudience !== binding.nodeAudience || fact.recipientDid !== input.holderDid || fact.policyDelegationCid !== input.envelope.policyRoot.cid || fact.enforcementDelegationCid !== input.envelope.enforcementRoot.cid || typeof fact.remainingRedelegationDepth !== "number" || !Number.isInteger(fact.remainingRedelegationDepth) || fact.remainingRedelegationDepth < 0 || fact.remainingRedelegationDepth > 8 || compact.payload.prf.length !== 2 || compact.payload.prf[0] !== input.envelope.policyRoot.cid || compact.payload.prf[1] !== input.envelope.enforcementRoot.cid || compact.payload.nbf > now || compact.payload.exp <= now || compact.payload.exp - compact.payload.nbf > 60 || canonicalize(compact.payload.att) !== canonicalize(policyAttenuationForV3(input.envelope))) throw new Error("v3 policy delegation signed binding mismatch");
|
|
9044
9004
|
return compact;
|
|
9045
9005
|
}
|
|
9046
|
-
function
|
|
9006
|
+
function hex3(value) {
|
|
9047
9007
|
return [...value].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
9048
9008
|
}
|
|
9049
9009
|
function canonicalHashHex(value) {
|
|
9050
|
-
return
|
|
9010
|
+
return hex3((0, import_sha2565.sha256)(new TextEncoder().encode(canonicalize(value))));
|
|
9051
9011
|
}
|
|
9052
9012
|
async function aesGcmDecrypt(key, blob) {
|
|
9053
9013
|
if (key.length !== 32 || blob.length < 28) throw new Error("encrypted content is malformed");
|
|
@@ -9079,25 +9039,6 @@ function parseV3InlineEncryptedEnvelope(bytes3, expected) {
|
|
|
9079
9039
|
}
|
|
9080
9040
|
return record2;
|
|
9081
9041
|
}
|
|
9082
|
-
async function verifyDetachedResponse(response, trust) {
|
|
9083
|
-
let value;
|
|
9084
|
-
try {
|
|
9085
|
-
value = await response.clone().json();
|
|
9086
|
-
} catch {
|
|
9087
|
-
throw new Error("share read response is invalid");
|
|
9088
|
-
}
|
|
9089
|
-
const record2 = object2(value, "share read response");
|
|
9090
|
-
const proof = object2(record2.proof, "share read detached proof");
|
|
9091
|
-
if (proof.alg !== "EdDSA" || proof.kid !== trust.invitationKid) throw new Error("share read detached proof is invalid");
|
|
9092
|
-
const unsigned = { ...record2 };
|
|
9093
|
-
delete unsigned.proof;
|
|
9094
|
-
if (!import_ed255198.ed25519.verify(bytes2(proof.signature, "share read signature"), new TextEncoder().encode(`${SHARE_V2_PROTOCOL.readResponseDomain}${canonicalize(unsigned)}`), trustedPublicKey(trust))) throw new Error("share read detached proof is invalid");
|
|
9095
|
-
}
|
|
9096
|
-
async function post(fetchFn, origin, path, body) {
|
|
9097
|
-
const response = await fetchFn(new URL(path, origin), { method: "POST", redirect: "error", headers: { accept: "application/json", "content-type": "application/json" }, body: JSON.stringify(body) });
|
|
9098
|
-
if (!response.ok) throw new Error("share authority rejected the request");
|
|
9099
|
-
return response.json();
|
|
9100
|
-
}
|
|
9101
9042
|
var ShareRecipientClient = class {
|
|
9102
9043
|
constructor(options) {
|
|
9103
9044
|
this.options = options;
|
|
@@ -9128,72 +9069,12 @@ var ShareRecipientClient = class {
|
|
|
9128
9069
|
v3ContentKey;
|
|
9129
9070
|
v3ContentEnvelope;
|
|
9130
9071
|
async beginChallenge(envelope) {
|
|
9131
|
-
|
|
9132
|
-
|
|
9133
|
-
const outer = object2(authority.outerEnvelope, "owner authority outer envelope");
|
|
9134
|
-
const enforcement = object2(authority.enforcementDelegation, "owner authority enforcement delegation");
|
|
9135
|
-
const target = object2(outer.target, "owner authority target");
|
|
9136
|
-
const outerResource = object2(outer.resource, "owner authority resource");
|
|
9137
|
-
const source = object2(outer.contentSource, "owner authority content source");
|
|
9138
|
-
if (!Array.isArray(outer.actions) || outer.actions.length === 0 || outer.actions.some((value) => typeof value !== "string")) throw new Error("owner authority outer envelope actions are invalid");
|
|
9139
|
-
const actions = [...outer.actions];
|
|
9140
|
-
const action = selectedAction(envelope);
|
|
9141
|
-
const challengeBody = { envelopeCid: authority.envelopeCid, shareCid: authority.shareCid, shareId: envelope.shareId, registrationCid: authority.registrationCid, delegationCid: envelope.delegationCid, policyCid: envelope.authorizationTarget.kind === "policy" ? envelope.authorizationTarget.policyCid : "", enforcementDelegationCid: String(enforcement.cid), enforcementDelegation: enforcement, outerEnvelope: outer, contentSource: source, contentSourceDigest: String(outer.contentSourceDigest), holderDid: this.options.holderDid, targetOrigin: String(target.origin), nodeAudience: String(target.nodeAudience), action, actions, resource: String(outerResource.path) };
|
|
9142
|
-
const requestBodyDigest = await digest3(challengeBody);
|
|
9143
|
-
const challenge = await verifyWrapped(await post(this.fetchFn, this.options.nodeOrigin, "/share/v2/policy/challenges", { ...challengeBody, requestBodyDigest }), "challenge", DOMAIN, this.options.trustedNode);
|
|
9144
|
-
if (challenge.type !== "TinyCloudSharePolicyChallenge" || challenge.version !== 2 || challenge.challengeId.length < 16 || challenge.nonce.length < 16 || challenge.shareCid !== authority.shareCid || challenge.shareId !== envelope.shareId || challenge.registrationCid !== authority.registrationCid || challenge.envelopeCid !== authority.envelopeCid || challenge.policyCid !== challengeBody.policyCid || challenge.delegationCid !== envelope.delegationCid || challenge.enforcementDelegationCid !== enforcement.cid || canonicalize(challenge.contentSource) !== canonicalize(source) || challenge.contentSourceDigest !== challengeBody.contentSourceDigest || challenge.requestBodyDigest !== requestBodyDigest || challenge.holderDid !== this.options.holderDid || challenge.targetOrigin !== challengeBody.targetOrigin || challenge.nodeAudience !== challengeBody.nodeAudience || challenge.action !== action || canonicalize(challenge.actions) !== canonicalize(actions) || challenge.resource !== challengeBody.resource || !Number.isFinite(Date.parse(challenge.expiresAt)) || Date.parse(challenge.expiresAt) <= Date.now()) throw new Error("share authority returned an unbound challenge");
|
|
9145
|
-
return challenge;
|
|
9072
|
+
void envelope;
|
|
9073
|
+
throw new Error("v2 Share recipient transport has been removed; use the embedded policy v3 envelope");
|
|
9146
9074
|
}
|
|
9147
9075
|
async establish(envelope) {
|
|
9148
|
-
|
|
9149
|
-
|
|
9150
|
-
const outer = object2(authority.outerEnvelope, "owner authority outer envelope");
|
|
9151
|
-
const enforcement = object2(authority.enforcementDelegation, "owner authority enforcement delegation");
|
|
9152
|
-
const target = object2(outer.target, "owner authority target");
|
|
9153
|
-
const outerResource = object2(outer.resource, "owner authority resource");
|
|
9154
|
-
const source = object2(outer.contentSource, "owner authority content source");
|
|
9155
|
-
if (!Array.isArray(outer.actions) || outer.actions.length === 0 || outer.actions.some((value) => typeof value !== "string")) throw new Error("owner authority outer envelope actions are invalid");
|
|
9156
|
-
const actions = [...outer.actions];
|
|
9157
|
-
const action = selectedAction(envelope);
|
|
9158
|
-
const challengeBody = { envelopeCid: authority.envelopeCid, shareCid: authority.shareCid, shareId: envelope.shareId, registrationCid: authority.registrationCid, delegationCid: envelope.delegationCid, policyCid: envelope.authorizationTarget.kind === "policy" ? envelope.authorizationTarget.policyCid : "", enforcementDelegationCid: String(enforcement.cid), enforcementDelegation: enforcement, outerEnvelope: outer, contentSource: source, contentSourceDigest: String(outer.contentSourceDigest), holderDid: this.options.holderDid, targetOrigin: String(target.origin), nodeAudience: String(target.nodeAudience), action, actions, resource: String(outerResource.path) };
|
|
9159
|
-
const requestBodyDigest = await digest3(challengeBody);
|
|
9160
|
-
const challenge = await verifyWrapped(await post(this.fetchFn, this.options.nodeOrigin, "/share/v2/policy/challenges", { ...challengeBody, requestBodyDigest }), "challenge", DOMAIN, this.options.trustedNode);
|
|
9161
|
-
if (challenge.type !== "TinyCloudSharePolicyChallenge" || challenge.version !== 2 || challenge.challengeId === void 0 || challenge.nonce === void 0 || challenge.shareCid !== authority.shareCid || challenge.shareId !== envelope.shareId || challenge.registrationCid !== authority.registrationCid || challenge.envelopeCid !== authority.envelopeCid || challenge.policyCid !== challengeBody.policyCid || challenge.delegationCid !== envelope.delegationCid || challenge.enforcementDelegationCid !== enforcement.cid || challenge.requestBodyDigest !== requestBodyDigest || canonicalize(challenge.contentSource) !== canonicalize(source) || challenge.contentSourceDigest !== challengeBody.contentSourceDigest || challenge.holderDid !== this.options.holderDid || challenge.targetOrigin !== challengeBody.targetOrigin || challenge.nodeAudience !== challengeBody.nodeAudience || challenge.action !== action || canonicalize(challenge.actions) !== canonicalize(actions) || challenge.resource !== challengeBody.resource || !Number.isFinite(Date.parse(challenge.expiresAt)) || Date.parse(challenge.expiresAt) <= Date.now()) throw new Error("share authority returned an unbound challenge");
|
|
9162
|
-
if (this.options.buildPresentation === void 0) throw new Error("share presentation builder is required");
|
|
9163
|
-
const material = await this.options.buildPresentation({ challenge, envelope, policy: {} });
|
|
9164
|
-
this.holderProof = material.proof;
|
|
9165
|
-
this.signer = material.sign;
|
|
9166
|
-
this.nativeSigner = material.sign;
|
|
9167
|
-
if (this.signer === void 0) throw new Error("share holder signer is required");
|
|
9168
|
-
const presentation = {
|
|
9169
|
-
type: "TinyCloudSharePolicyPresentation",
|
|
9170
|
-
version: 2,
|
|
9171
|
-
challengeId: challenge.challengeId,
|
|
9172
|
-
nonce: challenge.nonce,
|
|
9173
|
-
shareCid: authority.shareCid,
|
|
9174
|
-
shareId: envelope.shareId,
|
|
9175
|
-
delegationCid: envelope.delegationCid,
|
|
9176
|
-
policyCid: challengeBody.policyCid,
|
|
9177
|
-
contentSource: source,
|
|
9178
|
-
contentSourceDigest: challengeBody.contentSourceDigest,
|
|
9179
|
-
holderDid: material.holderDid,
|
|
9180
|
-
targetOrigin: challengeBody.targetOrigin,
|
|
9181
|
-
nodeAudience: challengeBody.nodeAudience,
|
|
9182
|
-
...challenge.enforcerDid === void 0 ? {} : { enforcerDid: challenge.enforcerDid },
|
|
9183
|
-
credentialDigest: material.credentialDigest ?? await digestText2(material.credential),
|
|
9184
|
-
action,
|
|
9185
|
-
actions,
|
|
9186
|
-
resource: challengeBody.resource,
|
|
9187
|
-
requestBodyDigest,
|
|
9188
|
-
issuedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9189
|
-
expiresAt: challenge.expiresAt,
|
|
9190
|
-
jti: toBase64Url(crypto.getRandomValues(new Uint8Array(16)))
|
|
9191
|
-
};
|
|
9192
|
-
const presentationProof = { alg: "EdDSA", kid: `${material.holderDid}#${material.holderDid.slice("did:key:".length)}`, signature: toBase64Url(await this.signer(new TextEncoder().encode(`${PRESENTATION_DOMAIN}${canonicalize(presentation)}`))) };
|
|
9193
|
-
const session = await verifyWrapped(await post(this.fetchFn, this.options.nodeOrigin, "/share/v2/policy/session", { challengeId: challenge.challengeId, nonce: challenge.nonce, presentation, credential: material.credential, proof: presentationProof, holderBinding: material.holderBinding, readSignerDid: material.holderDid }), "session", SESSION_DOMAIN, this.options.trustedNode);
|
|
9194
|
-
if (session.type !== "TinyCloudSharePolicySession" || session.version !== 2 || typeof session.sessionId !== "string" || session.shareCid !== authority.shareCid || session.shareId !== envelope.shareId || session.registrationCid !== authority.registrationCid || session.envelopeCid !== authority.envelopeCid || session.policyCid !== challengeBody.policyCid || session.delegationCid !== envelope.delegationCid || session.holderDid !== this.options.holderDid || session.targetOrigin !== challengeBody.targetOrigin || session.nodeAudience !== challengeBody.nodeAudience || session.action !== action || canonicalize(session.actions) !== canonicalize(actions) || canonicalize(session.contentSource) !== canonicalize(source) || session.contentSourceDigest !== challengeBody.contentSourceDigest || session.resource !== challengeBody.resource || typeof session.expiresAt !== "string" || !Number.isFinite(Date.parse(session.expiresAt)) || Date.parse(session.expiresAt) <= Date.now()) throw new Error("share authority returned an unbound session");
|
|
9195
|
-
this.session = { sessionId: session.sessionId, expiresAt: session.expiresAt, actions: actions.map(uiAction), resource: { kind: envelope.resource.kind, path: String(session.resource) } };
|
|
9196
|
-
return this.session;
|
|
9076
|
+
void envelope;
|
|
9077
|
+
throw new Error("v2 Share recipient transport has been removed; use the embedded policy v3 envelope");
|
|
9197
9078
|
}
|
|
9198
9079
|
async authorize(envelope) {
|
|
9199
9080
|
if (this.session === void 0) await this.establish(envelope);
|
|
@@ -9221,7 +9102,7 @@ var ShareRecipientClient = class {
|
|
|
9221
9102
|
} catch {
|
|
9222
9103
|
throw new Error("v3 attested Node audience is invalid");
|
|
9223
9104
|
}
|
|
9224
|
-
const challengeResponse = await this.fetchFn(new URL("/
|
|
9105
|
+
const challengeResponse = await this.fetchFn(new URL("/policy/v3/challenges", this.options.nodeOrigin), {
|
|
9225
9106
|
method: "POST",
|
|
9226
9107
|
redirect: "error",
|
|
9227
9108
|
headers: { accept: "application/json", "content-type": "application/json" },
|
|
@@ -9242,7 +9123,7 @@ var ShareRecipientClient = class {
|
|
|
9242
9123
|
throw new Error(accountless ? "v4 ceremony requires a verified credential and requirement" : "v3 ceremony requires a claim");
|
|
9243
9124
|
}
|
|
9244
9125
|
this.options.onStage?.("policy-admission");
|
|
9245
|
-
const delegationResponse = await this.fetchFn(new URL("/
|
|
9126
|
+
const delegationResponse = await this.fetchFn(new URL("/policy/v3/delegations", this.options.nodeOrigin), {
|
|
9246
9127
|
method: "POST",
|
|
9247
9128
|
redirect: "error",
|
|
9248
9129
|
headers: { accept: "application/json", "content-type": "application/json" },
|
|
@@ -9270,10 +9151,10 @@ var ShareRecipientClient = class {
|
|
|
9270
9151
|
if (envelope.version !== 3 || this.session === void 0 || this.v3Authorization === void 0 || this.v3NodeAudience === void 0 || signer === void 0) throw new Error("v3 policy session signer is required");
|
|
9271
9152
|
const encrypted = parseV3InlineEncryptedEnvelope(bytes3, envelope);
|
|
9272
9153
|
const receiverPrivateKey = crypto.getRandomValues(new Uint8Array(32));
|
|
9273
|
-
const receiverPublicKey =
|
|
9154
|
+
const receiverPublicKey = toBase64(import_ed255198.x25519.getPublicKey(receiverPrivateKey));
|
|
9274
9155
|
const receiverPublicKeyHash = canonicalHashHex(receiverPublicKey);
|
|
9275
9156
|
const body = { type: "tinycloud.encryption.decrypt/v1", targetNode: this.v3NodeAudience, networkId: encrypted.networkId, alg: encrypted.alg, keyVersion: encrypted.keyVersion, encryptedSymmetricKey: encrypted.encryptedSymmetricKey, encryptedSymmetricKeyHash: encrypted.encryptedSymmetricKeyHash, receiverPublicKey, receiverPublicKeyHash };
|
|
9276
|
-
const bodyHash =
|
|
9157
|
+
const bodyHash = hex3((0, import_sha2565.sha256)(new TextEncoder().encode(canonicalize(body))));
|
|
9277
9158
|
const session = verifyCompactUcanAuthorization(this.v3Authorization, this.session.sessionId);
|
|
9278
9159
|
const now = Math.floor(Date.now() / 1e3);
|
|
9279
9160
|
const invocation = await signCompactUcanAuthorization({
|
|
@@ -9293,18 +9174,18 @@ var ShareRecipientClient = class {
|
|
|
9293
9174
|
if (!response.ok) throw new Error(`v3 decrypt invocation rejected (${response.status})`);
|
|
9294
9175
|
const value = object2(await response.json(), "v3 decrypt response");
|
|
9295
9176
|
const allowed = ["type", "targetNode", "networkId", "invocationCid", "encryptedSymmetricKeyHash", "receiverPublicKeyHash", "wrappedKey", "alg", "keyVersion", "requestHash", "nodeId", "nodeSignature"];
|
|
9296
|
-
if (Object.keys(value).length !== allowed.length || Object.keys(value).some((key) => !allowed.includes(key)) || value.type !== "tinycloud.encryption.decrypt-result/v1" || value.targetNode !== body.targetNode || value.nodeId !== body.targetNode || value.networkId !== body.networkId || value.invocationCid !== invocation.cid || value.encryptedSymmetricKeyHash !== body.encryptedSymmetricKeyHash || value.receiverPublicKeyHash !== receiverPublicKeyHash || value.alg !== body.alg || value.keyVersion !== body.keyVersion || value.requestHash !==
|
|
9177
|
+
if (Object.keys(value).length !== allowed.length || Object.keys(value).some((key) => !allowed.includes(key)) || value.type !== "tinycloud.encryption.decrypt-result/v1" || value.targetNode !== body.targetNode || value.nodeId !== body.targetNode || value.networkId !== body.networkId || value.invocationCid !== invocation.cid || value.encryptedSymmetricKeyHash !== body.encryptedSymmetricKeyHash || value.receiverPublicKeyHash !== receiverPublicKeyHash || value.alg !== body.alg || value.keyVersion !== body.keyVersion || value.requestHash !== hex3((0, import_sha2565.sha256)(new TextEncoder().encode(`${invocation.cid}${bodyHash}`))) || typeof value.wrappedKey !== "string" || typeof value.nodeSignature !== "string") throw new Error("v3 decrypt response binding is invalid");
|
|
9297
9178
|
const unsigned = { ...value };
|
|
9298
9179
|
delete unsigned.nodeSignature;
|
|
9299
9180
|
const signature = fromBase64(value.nodeSignature, "v3 decrypt response signature");
|
|
9300
9181
|
if (signature.length !== 64 || !import_ed255198.ed25519.verify(signature, new TextEncoder().encode(canonicalize(unsigned)), ed25519PublicKeyFromDidKey(body.targetNode), { zip215: false })) throw new Error("v3 decrypt response signature is invalid");
|
|
9301
9182
|
const wrapped = fromBase64(value.wrappedKey, "v3 wrapped content key");
|
|
9302
|
-
if (wrapped.length <
|
|
9183
|
+
if (wrapped.length < 61 || wrapped[32] !== 1) throw new Error("v3 wrapped content key is malformed");
|
|
9303
9184
|
const shared = import_ed255198.x25519.getSharedSecret(receiverPrivateKey, wrapped.slice(0, 32));
|
|
9304
|
-
const symmetricKey = await aesGcmDecrypt(shared, wrapped.slice(
|
|
9185
|
+
const symmetricKey = await aesGcmDecrypt(shared, wrapped.slice(33));
|
|
9305
9186
|
shared.fill(0);
|
|
9306
9187
|
if (symmetricKey.length !== 32) throw new Error("v3 content key is malformed");
|
|
9307
|
-
const plaintext = await aesGcmDecrypt(symmetricKey,
|
|
9188
|
+
const plaintext = await aesGcmDecrypt(symmetricKey, fromBase64(encrypted.ciphertext, "v3 encrypted content"));
|
|
9308
9189
|
this.v3ContentKey?.fill(0);
|
|
9309
9190
|
this.v3ContentKey = symmetricKey;
|
|
9310
9191
|
this.v3ContentEnvelope = encrypted;
|
|
@@ -9319,47 +9200,16 @@ var ShareRecipientClient = class {
|
|
|
9319
9200
|
return new TextEncoder().encode(canonicalize({ ...this.v3ContentEnvelope, ciphertext: toBase64Url(await aesGcmEncrypt(this.v3ContentKey, bytes3)), metadata: { ...this.v3ContentEnvelope.metadata ?? {}, contentType: mediaType } }));
|
|
9320
9201
|
}
|
|
9321
9202
|
async resumeWithProof(envelope, resumeToken, proof) {
|
|
9322
|
-
|
|
9323
|
-
|
|
9324
|
-
|
|
9325
|
-
|
|
9326
|
-
const credential = material.credential;
|
|
9327
|
-
const holderDid = material.holderDid;
|
|
9328
|
-
const holderBinding = material.holderBinding;
|
|
9329
|
-
if (typeof nonce !== "string" || typeof credential !== "string" || typeof holderDid !== "string" || holderDid !== this.options.holderDid || typeof holderBinding !== "object" || holderBinding === null || presentationProof.alg !== "EdDSA" || typeof presentationProof.signature !== "string") throw new Error("share authorization proof is incomplete");
|
|
9330
|
-
const value = object2(await post(this.fetchFn, this.options.nodeOrigin, "/share/v2/policy/session", { challengeId: resumeToken, nonce, presentation, credential, proof: presentationProof, holderBinding, readSignerDid: holderDid }), "share policy session");
|
|
9331
|
-
const session = await verifyWrapped(value, "session", SESSION_DOMAIN, this.options.trustedNode);
|
|
9332
|
-
const authority = envelope.ownerAuthority;
|
|
9333
|
-
if (authority === void 0 || session.type !== "TinyCloudSharePolicySession" || session.version !== 2 || typeof session.sessionId !== "string" || session.shareCid !== authority.shareCid || session.shareId !== envelope.shareId || session.registrationCid !== authority.registrationCid || session.envelopeCid !== authority.envelopeCid || session.delegationCid !== envelope.delegationCid || typeof session.resource !== "string" || typeof session.expiresAt !== "string") throw new Error("share authority returned an unbound session");
|
|
9334
|
-
const policyCid = envelope.authorizationTarget.kind === "policy" ? envelope.authorizationTarget.policyCid : "";
|
|
9335
|
-
const actions = [...new Set(envelope.actions.map(nativeAction))].sort();
|
|
9336
|
-
if (session.policyCid !== policyCid || session.holderDid !== this.options.holderDid || session.targetOrigin !== envelope.target.origin || session.nodeAudience !== envelope.target.nodeAudience || session.action !== selectedAction(envelope) || canonicalize(session.actions) !== canonicalize(actions) || canonicalize(session.contentSource) !== canonicalize(envelope.contentSource) || session.contentSourceDigest !== envelope.contentSourceDigest || !Number.isFinite(Date.parse(session.expiresAt)) || Date.parse(session.expiresAt) <= Date.now()) throw new Error("share authority returned an unbound session");
|
|
9337
|
-
this.session = { sessionId: session.sessionId, expiresAt: session.expiresAt, actions: actions.map(uiAction), resource: { kind: envelope.resource.kind, path: String(session.resource) } };
|
|
9338
|
-
this.holderProof = presentationProof;
|
|
9339
|
-
this.signer ??= this.options.sign;
|
|
9340
|
-
return this.authorize(envelope);
|
|
9203
|
+
void envelope;
|
|
9204
|
+
void resumeToken;
|
|
9205
|
+
void proof;
|
|
9206
|
+
throw new Error("v2 Share recipient transport has been removed; use the embedded policy v3 envelope");
|
|
9341
9207
|
}
|
|
9342
9208
|
async nativeInvoke(request) {
|
|
9343
9209
|
if (this.session === void 0) throw new Error("share policy session is required");
|
|
9344
9210
|
const envelope = this.options.envelope;
|
|
9345
9211
|
if (envelope.version === 3) return this.nativeInvokeV3(request, envelope);
|
|
9346
|
-
|
|
9347
|
-
const authority = envelope.ownerAuthority;
|
|
9348
|
-
const action = request.action === "list" ? "tinycloud.kv/list" : request.action === "put" ? "tinycloud.kv/put" : request.action === "metadata" ? "tinycloud.kv/metadata" : "tinycloud.kv/get";
|
|
9349
|
-
const resource = typeof request.resource?.path === "string" ? request.resource.path : this.session.resource.path;
|
|
9350
|
-
const actions = [...new Set(this.session.actions.map(nativeAction).concat(action === "tinycloud.kv/metadata" ? [action] : []))].sort();
|
|
9351
|
-
const bodyBytes = request.body === void 0 ? void 0 : Uint8Array.from(request.body);
|
|
9352
|
-
const bodyDigest = bodyBytes === void 0 ? void 0 : toBase64Url(new Uint8Array(await crypto.subtle.digest("SHA-256", bodyBytes)));
|
|
9353
|
-
const outer = object2(authority.outerEnvelope, "owner authority outer envelope");
|
|
9354
|
-
const enforcement = object2(authority.enforcementDelegation, "owner authority enforcement delegation");
|
|
9355
|
-
const invocationBase = { type: "TinyCloudShareReadInvocation", version: 2, sessionId: this.session.sessionId, envelopeCid: authority.envelopeCid, shareCid: authority.shareCid, shareId: envelope.shareId, registrationCid: authority.registrationCid, delegationCid: envelope.delegationCid, policyCid: envelope.authorizationTarget.kind === "policy" ? envelope.authorizationTarget.policyCid : "", enforcementDelegationCid: String(enforcement.cid), contentSource: outer.contentSource, contentSourceDigest: String(outer.contentSourceDigest), holderDid: this.options.holderDid, targetOrigin: String(object2(outer.target, "owner authority target").origin), nodeAudience: String(object2(outer.target, "owner authority target").nodeAudience), action, actions, resource, ...action === "tinycloud.kv/list" ? { limit: 100 } : {}, ...bodyDigest === void 0 ? {} : { bodyDigest, ifMatch: request.ifMatch, contentType: request.contentType }, issuedAt: (/* @__PURE__ */ new Date()).toISOString(), expiresAt: new Date(Math.min(Date.now() + 6e4, Date.parse(this.session.expiresAt))).toISOString(), jti: toBase64Url(crypto.getRandomValues(new Uint8Array(16))) };
|
|
9356
|
-
const requestBodyDigest = await digest3(invocationBase);
|
|
9357
|
-
const invocation = { ...invocationBase, requestBodyDigest };
|
|
9358
|
-
const proof = { ...this.holderProof, signature: toBase64Url(await this.signer(new TextEncoder().encode(`${INVOCATION_DOMAIN}${canonicalize(invocation)}`))) };
|
|
9359
|
-
const signedRequest = { sessionId: this.session.sessionId, envelopeCid: authority.envelopeCid, shareCid: authority.shareCid, shareId: envelope.shareId, registrationCid: authority.registrationCid, delegationCid: envelope.delegationCid, policyCid: envelope.authorizationTarget.kind === "policy" ? envelope.authorizationTarget.policyCid : "", enforcementDelegationCid: String(enforcement.cid), contentSource: outer.contentSource, contentSourceDigest: String(outer.contentSourceDigest), holderDid: this.options.holderDid, nodeAudience: String(object2(outer.target, "owner authority target").nodeAudience), action, actions, resource, requestBodyDigest, invocation, proof };
|
|
9360
|
-
const response = await this.fetchFn(new URL("/share/v2/invoke", this.options.nodeOrigin), { method: "POST", redirect: "error", headers: { accept: "application/vnd.tinycloud.share+json", "content-type": "application/vnd.tinycloud.share+json" }, body: JSON.stringify({ request: signedRequest, ...action === "tinycloud.kv/list" ? { limit: 100 } : {}, ...bodyBytes === void 0 ? {} : { body: toBase64Url(bodyBytes), bodyDigest, ifMatch: request.ifMatch, contentType: request.contentType } }) });
|
|
9361
|
-
if (response.ok) await verifyDetachedResponse(response, this.options.trustedNode);
|
|
9362
|
-
return response;
|
|
9212
|
+
throw new Error("v2 Share invocation transport has been removed; use the embedded policy v3 envelope");
|
|
9363
9213
|
}
|
|
9364
9214
|
async nativeInvokeV3(request, envelope) {
|
|
9365
9215
|
const signer = this.nativeSigner ?? this.signer;
|