@otskit/client
Advanced tools
@@ -34,4 +34,10 @@ /** | ||
| stamp(hash: Uint8Array | string): Promise<Uint8Array>; | ||
| /** | ||
| * proof: a pending .ots as bytes. Queries the calendars it references (allowlisted) and returns | ||
| * the upgraded .ots. Throws UpgradeError if no calendar has confirmed the timestamp yet, which is | ||
| * the normal state until Bitcoin mines the commitment (typically an hour or more after stamping). | ||
| */ | ||
| upgrade(proof: Uint8Array): Promise<Uint8Array>; | ||
| } | ||
| export { BROWSER_CALENDARS, type BrowserClientOptions, OpenTimestampsBrowserClient, bytesToHex, hashBlob, hashBytes }; |
+67
-0
@@ -23,2 +23,4 @@ // src/errors.ts | ||
| }; | ||
| var UpgradeError = class extends OpenTimestampsClientError { | ||
| }; | ||
| var NetworkError = class extends OpenTimestampsClientError { | ||
@@ -657,2 +659,59 @@ /** HTTP status code when the failure originates from an HTTP response. */ | ||
| // src/core/upgrade-core.ts | ||
| import { DetachedTimestampFile as DetachedTimestampFile2 } from "@otskit/core"; | ||
| function bytesEqual(a, b) { | ||
| if (a.length !== b.length) return false; | ||
| let diff = 0; | ||
| for (let i = 0; i < a.length; i++) { | ||
| diff |= a[i] ^ b[i]; | ||
| } | ||
| return diff === 0; | ||
| } | ||
| async function upgradeProofBytes(incompleteProof, networkLayer, logger, signal) { | ||
| let detached; | ||
| try { | ||
| detached = DetachedTimestampFile2.deserialize(incompleteProof); | ||
| } catch (error) { | ||
| throw new ValidationError("Invalid .ots proof format", { | ||
| /* v8 ignore next */ | ||
| ...error instanceof Error ? { cause: error } : {} | ||
| }); | ||
| } | ||
| if (detached.timestamp.isTimestampComplete()) { | ||
| logger?.info("Proof already complete; nothing to upgrade"); | ||
| return incompleteProof; | ||
| } | ||
| const before = detached.serializeToBytes(); | ||
| for (const subStamp of detached.timestamp.directlyVerified()) { | ||
| if (subStamp.isTimestampComplete()) continue; | ||
| for (const att of subStamp.attestations) { | ||
| if (att.kind !== "pending") continue; | ||
| if (!DEFAULT_CALENDAR_WHITELIST.contains(att.uri)) { | ||
| logger?.warn(`Ignoring attestation from non-whitelisted calendar ${att.uri}`); | ||
| continue; | ||
| } | ||
| try { | ||
| const upgraded = await new CalendarClient(att.uri, networkLayer, logger).getTimestamp( | ||
| subStamp.getDigest(), | ||
| signal | ||
| ); | ||
| subStamp.merge(upgraded); | ||
| } catch (err) { | ||
| if (err instanceof CommitmentNotFoundError) { | ||
| logger?.debug(`Calendar ${att.uri} has not confirmed yet`); | ||
| continue; | ||
| } | ||
| logger?.warn( | ||
| `Failed to query ${att.uri}: ${err instanceof Error ? err.message : String(err)}` | ||
| ); | ||
| } | ||
| } | ||
| } | ||
| const after = detached.serializeToBytes(); | ||
| if (bytesEqual(before, after)) { | ||
| throw new UpgradeError("No calendar has confirmed the timestamp yet (Bitcoin not yet mined)"); | ||
| } | ||
| return after; | ||
| } | ||
| // src/security/ssrf-web.ts | ||
@@ -737,2 +796,10 @@ async function assertSafeCalendarUrlStructural(url) { | ||
| } | ||
| /** | ||
| * proof: a pending .ots as bytes. Queries the calendars it references (allowlisted) and returns | ||
| * the upgraded .ots. Throws UpgradeError if no calendar has confirmed the timestamp yet, which is | ||
| * the normal state until Bitcoin mines the commitment (typically an hour or more after stamping). | ||
| */ | ||
| upgrade(proof) { | ||
| return upgradeProofBytes(proof, this.layer, this.logger); | ||
| } | ||
| }; | ||
@@ -739,0 +806,0 @@ export { |
+25
-7
@@ -741,9 +741,16 @@ "use strict"; | ||
| // src/core/upgrade.ts | ||
| // src/core/upgrade-core.ts | ||
| var import_core4 = require("@otskit/core"); | ||
| var bytesEqFast = (a, b) => Buffer.compare(Buffer.from(a), Buffer.from(b)) === 0; | ||
| async function orchestrateUpgrade(incompleteProof, _calendars, networkLayer, logger, signal) { | ||
| function bytesEqual(a, b) { | ||
| if (a.length !== b.length) return false; | ||
| let diff = 0; | ||
| for (let i = 0; i < a.length; i++) { | ||
| diff |= a[i] ^ b[i]; | ||
| } | ||
| return diff === 0; | ||
| } | ||
| async function upgradeProofBytes(incompleteProof, networkLayer, logger, signal) { | ||
| let detached; | ||
| try { | ||
| detached = import_core4.DetachedTimestampFile.deserialize(new Uint8Array(incompleteProof)); | ||
| detached = import_core4.DetachedTimestampFile.deserialize(incompleteProof); | ||
| } catch (error) { | ||
@@ -757,3 +764,3 @@ throw new ValidationError("Invalid .ots proof format", { | ||
| logger?.info("Proof already complete; nothing to upgrade"); | ||
| return Buffer.from(incompleteProof); | ||
| return incompleteProof; | ||
| } | ||
@@ -787,8 +794,19 @@ const before = detached.serializeToBytes(); | ||
| const after = detached.serializeToBytes(); | ||
| if (bytesEqFast(before, after)) { | ||
| if (bytesEqual(before, after)) { | ||
| throw new UpgradeError("No calendar has confirmed the timestamp yet (Bitcoin not yet mined)"); | ||
| } | ||
| return Buffer.from(after); | ||
| return after; | ||
| } | ||
| // src/core/upgrade.ts | ||
| async function orchestrateUpgrade(incompleteProof, _calendars, networkLayer, logger, signal) { | ||
| const upgraded = await upgradeProofBytes( | ||
| new Uint8Array(incompleteProof), | ||
| networkLayer, | ||
| logger, | ||
| signal | ||
| ); | ||
| return Buffer.from(upgraded); | ||
| } | ||
| // src/core/verify.ts | ||
@@ -795,0 +813,0 @@ var import_core6 = require("@otskit/core"); |
+25
-7
@@ -691,9 +691,16 @@ // src/types.ts | ||
| // src/core/upgrade.ts | ||
| // src/core/upgrade-core.ts | ||
| import { DetachedTimestampFile as DetachedTimestampFile2 } from "@otskit/core"; | ||
| var bytesEqFast = (a, b) => Buffer.compare(Buffer.from(a), Buffer.from(b)) === 0; | ||
| async function orchestrateUpgrade(incompleteProof, _calendars, networkLayer, logger, signal) { | ||
| function bytesEqual(a, b) { | ||
| if (a.length !== b.length) return false; | ||
| let diff = 0; | ||
| for (let i = 0; i < a.length; i++) { | ||
| diff |= a[i] ^ b[i]; | ||
| } | ||
| return diff === 0; | ||
| } | ||
| async function upgradeProofBytes(incompleteProof, networkLayer, logger, signal) { | ||
| let detached; | ||
| try { | ||
| detached = DetachedTimestampFile2.deserialize(new Uint8Array(incompleteProof)); | ||
| detached = DetachedTimestampFile2.deserialize(incompleteProof); | ||
| } catch (error) { | ||
@@ -707,3 +714,3 @@ throw new ValidationError("Invalid .ots proof format", { | ||
| logger?.info("Proof already complete; nothing to upgrade"); | ||
| return Buffer.from(incompleteProof); | ||
| return incompleteProof; | ||
| } | ||
@@ -737,8 +744,19 @@ const before = detached.serializeToBytes(); | ||
| const after = detached.serializeToBytes(); | ||
| if (bytesEqFast(before, after)) { | ||
| if (bytesEqual(before, after)) { | ||
| throw new UpgradeError("No calendar has confirmed the timestamp yet (Bitcoin not yet mined)"); | ||
| } | ||
| return Buffer.from(after); | ||
| return after; | ||
| } | ||
| // src/core/upgrade.ts | ||
| async function orchestrateUpgrade(incompleteProof, _calendars, networkLayer, logger, signal) { | ||
| const upgraded = await upgradeProofBytes( | ||
| new Uint8Array(incompleteProof), | ||
| networkLayer, | ||
| logger, | ||
| signal | ||
| ); | ||
| return Buffer.from(upgraded); | ||
| } | ||
| // src/core/verify.ts | ||
@@ -745,0 +763,0 @@ import { DetachedTimestampFile as DetachedTimestampFile3, OpSHA1, OpRIPEMD160 } from "@otskit/core"; |
+1
-1
| { | ||
| "name": "@otskit/client", | ||
| "version": "0.6.1", | ||
| "version": "0.7.0", | ||
| "description": "Official client SDK for OpenTimestamps calendars with resilience patterns", | ||
@@ -5,0 +5,0 @@ "author": "alexalves87", |
181268
1.92%3921
2.78%