@majikah/majik-signature 0.2.3 → 0.2.4
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/core/constants.d.ts +12 -0
- package/dist/core/constants.js +19 -0
- package/dist/core/embed/majik-embed.d.ts +4 -4
- package/dist/core/embed/majik-embed.js +3 -4
- package/dist/core/envelope.d.ts +49 -2
- package/dist/core/envelope.js +144 -6
- package/dist/majik-signature.d.ts +2 -2
- package/package.json +1 -1
package/dist/core/constants.d.ts
CHANGED
|
@@ -59,3 +59,15 @@ export declare const MAJIK_TIMESTAMP_VERSION: 1;
|
|
|
59
59
|
export declare const MAJIK_TSA_DOMAIN: "majikah-tsa-v-1:";
|
|
60
60
|
export declare const MAJIK_NOTARY_VERSION: 1;
|
|
61
61
|
export declare const MAJIK_NOTARY_MEMO_DOMAIN: "majik-notary-v-1:";
|
|
62
|
+
export declare const MJKSIG_MAGIC: number[];
|
|
63
|
+
export declare const MJKSIG_MAGIC_LEN: number;
|
|
64
|
+
export declare const MJKSIG_VERSION = 1;
|
|
65
|
+
export declare const MJKSIG_SUPPORTED_VERSIONS: readonly [1];
|
|
66
|
+
export declare const MJKSIG_HEADER_LEN: number;
|
|
67
|
+
/**
|
|
68
|
+
* Proposed IANA media type / conventional file extension for this format.
|
|
69
|
+
* Referenced here so both live in one place ahead of registration —
|
|
70
|
+
* update if/when the registration settles on different values.
|
|
71
|
+
*/
|
|
72
|
+
export declare const MJKSIG_MEDIA_TYPE: "application/vnd.majikah.mjksig";
|
|
73
|
+
export declare const MJKSIG_FILE_EXTENSION: ".mjksig";
|
package/dist/core/constants.js
CHANGED
|
@@ -58,3 +58,22 @@ export const MAJIK_TIMESTAMP_VERSION = 1;
|
|
|
58
58
|
export const MAJIK_TSA_DOMAIN = `majikah-tsa-v-${MAJIK_TIMESTAMP_VERSION}:`;
|
|
59
59
|
export const MAJIK_NOTARY_VERSION = 1;
|
|
60
60
|
export const MAJIK_NOTARY_MEMO_DOMAIN = `majik-notary-v-${MAJIK_NOTARY_VERSION}:`;
|
|
61
|
+
// ─── MJKSIG binary format ───────────────────────────────────────────────────
|
|
62
|
+
//
|
|
63
|
+
// Layout: [magic(6)][version(1)][reserved(1)][payloadLen(4, BE u32)][payload JSON]
|
|
64
|
+
// Header length is fixed at 12 bytes regardless of version — only the
|
|
65
|
+
// payload shape may change between versions, never the header layout.
|
|
66
|
+
// This lets fromMJKSIG() always locate and validate the header before it
|
|
67
|
+
// needs to know anything about the payload's internal shape.
|
|
68
|
+
export const MJKSIG_MAGIC = [0x4d, 0x4a, 0x4b, 0x53, 0x49, 0x47]; // "MJKSIG"
|
|
69
|
+
export const MJKSIG_MAGIC_LEN = MJKSIG_MAGIC.length;
|
|
70
|
+
export const MJKSIG_VERSION = 0x01;
|
|
71
|
+
export const MJKSIG_SUPPORTED_VERSIONS = [MJKSIG_VERSION];
|
|
72
|
+
export const MJKSIG_HEADER_LEN = MJKSIG_MAGIC_LEN + 1 + 1 + 4; // 12
|
|
73
|
+
/**
|
|
74
|
+
* Proposed IANA media type / conventional file extension for this format.
|
|
75
|
+
* Referenced here so both live in one place ahead of registration —
|
|
76
|
+
* update if/when the registration settles on different values.
|
|
77
|
+
*/
|
|
78
|
+
export const MJKSIG_MEDIA_TYPE = "application/vnd.majikah.mjksig";
|
|
79
|
+
export const MJKSIG_FILE_EXTENSION = ".mjksig";
|
|
@@ -75,7 +75,7 @@ export declare class MajikSignatureEmbed {
|
|
|
75
75
|
contentType?: string;
|
|
76
76
|
timestamp?: string;
|
|
77
77
|
expectedSigners?: ExpectedSigner[];
|
|
78
|
-
existingEnvelope?: MajikSignatureEnvelope | MajikSignatureEnvelopeJSON;
|
|
78
|
+
existingEnvelope?: MajikSignatureEnvelope | MajikSignatureEnvelopeJSON | Uint8Array | Blob;
|
|
79
79
|
}, debug?: boolean): Promise<{
|
|
80
80
|
blob: Blob;
|
|
81
81
|
envelope: MajikSignatureEnvelope;
|
|
@@ -98,14 +98,14 @@ export declare class MajikSignatureEmbed {
|
|
|
98
98
|
expectedSignerId?: string;
|
|
99
99
|
}, debug?: boolean): Promise<VerificationResult[]>;
|
|
100
100
|
/**
|
|
101
|
-
* Verify a file against a provided, detached envelope (instance or JSON).
|
|
101
|
+
* Verify a file against a provided, detached envelope (instance, blob or JSON).
|
|
102
102
|
* Still strips the file in case it also contains an embedded envelope,
|
|
103
103
|
* ensuring verification runs against the clean original bytes.
|
|
104
104
|
*/
|
|
105
|
-
static verifyDetached(file: Blob, envelopeInput: MajikSignatureEnvelope | MajikSignatureEnvelopeJSON, publicKeys: MajikSignerPublicKeys, MajikSig: MajikSignatureStaticAdapter, options?: ExtractOptions & {
|
|
105
|
+
static verifyDetached(file: Blob, envelopeInput: MajikSignatureEnvelope | MajikSignatureEnvelopeJSON | Uint8Array | Blob, publicKeys: MajikSignerPublicKeys, MajikSig: MajikSignatureStaticAdapter, options?: ExtractOptions & {
|
|
106
106
|
expectedSignerId?: string;
|
|
107
107
|
}, debug?: boolean): Promise<VerificationResult[]>;
|
|
108
|
-
static verifyDetachedWithKey(file: Blob, envelopeInput: MajikSignatureEnvelope | MajikSignatureEnvelopeJSON, key: MajikKey, MajikSig: MajikSignatureStaticAdapter, options?: ExtractOptions & {
|
|
108
|
+
static verifyDetachedWithKey(file: Blob, envelopeInput: MajikSignatureEnvelope | MajikSignatureEnvelopeJSON | Uint8Array | Blob, key: MajikKey, MajikSig: MajikSignatureStaticAdapter, options?: ExtractOptions & {
|
|
109
109
|
expectedSignerId?: string;
|
|
110
110
|
}, debug?: boolean): Promise<VerificationResult[]>;
|
|
111
111
|
/**
|
|
@@ -133,9 +133,8 @@ export class MajikSignatureEmbed {
|
|
|
133
133
|
*/
|
|
134
134
|
static async signDetached(file, key, MajikSig, options, debug = false) {
|
|
135
135
|
const { bytes, mimeType, handler } = await MajikSignatureEmbed._prepare(file, options);
|
|
136
|
-
// ── Resolve the working envelope ─────────────────────────────────────────
|
|
137
136
|
const envelope = options?.existingEnvelope
|
|
138
|
-
? MajikSignatureEnvelope.from(options.existingEnvelope)
|
|
137
|
+
? await MajikSignatureEnvelope.from(options.existingEnvelope)
|
|
139
138
|
: await MajikSignatureEmbed._readEnvelope(handler, bytes);
|
|
140
139
|
envelope.assertCanSign(key);
|
|
141
140
|
const originalBytes = await handler.strip(bytes);
|
|
@@ -218,13 +217,13 @@ export class MajikSignatureEmbed {
|
|
|
218
217
|
}
|
|
219
218
|
// ── verifyDetached ─────────────────────────────────────────────────────────
|
|
220
219
|
/**
|
|
221
|
-
* Verify a file against a provided, detached envelope (instance or JSON).
|
|
220
|
+
* Verify a file against a provided, detached envelope (instance, blob or JSON).
|
|
222
221
|
* Still strips the file in case it also contains an embedded envelope,
|
|
223
222
|
* ensuring verification runs against the clean original bytes.
|
|
224
223
|
*/
|
|
225
224
|
static async verifyDetached(file, envelopeInput, publicKeys, MajikSig, options, debug = false) {
|
|
226
225
|
const { bytes, handler } = await MajikSignatureEmbed._prepare(file, options);
|
|
227
|
-
const envelope = MajikSignatureEnvelope.from(envelopeInput);
|
|
226
|
+
const envelope = await MajikSignatureEnvelope.from(envelopeInput);
|
|
228
227
|
const originalBytes = await handler.strip(bytes);
|
|
229
228
|
if (debug) {
|
|
230
229
|
console.log("verifyDetached — original bytes hash:", bytesToBase64(hashContent(originalBytes)));
|
package/dist/core/envelope.d.ts
CHANGED
|
@@ -161,6 +161,43 @@ export declare class MajikSignatureEnvelope {
|
|
|
161
161
|
toJSON(): MajikSignatureEnvelopeJSON;
|
|
162
162
|
serialize(): string;
|
|
163
163
|
static deserialize(base64: string): MajikSignatureEnvelope;
|
|
164
|
+
/**
|
|
165
|
+
* Raw MJKSIG bytes, no Blob wrapper. Exposed as a public escape hatch for
|
|
166
|
+
* non-browser contexts (Node scripts, tests, direct fs writes) where
|
|
167
|
+
* wrapping in a Blob just to immediately unwrap it again is pure overhead.
|
|
168
|
+
* toMJKSIG() is the primary API for anything Blob-facing.
|
|
169
|
+
*/
|
|
170
|
+
toMJKSIGBytes(): Uint8Array;
|
|
171
|
+
/**
|
|
172
|
+
* Encode this envelope as an MJKSIG file Blob.
|
|
173
|
+
* Always writes the current MJKSIG_VERSION — encoding an old payload
|
|
174
|
+
* shape under an old version tag is not supported; old versions only
|
|
175
|
+
* ever appear when *reading* pre-existing MJKSIG binaries.
|
|
176
|
+
*/
|
|
177
|
+
toMJKSIG(): Blob;
|
|
178
|
+
/**
|
|
179
|
+
* Decode MJKSIG bytes back into a MajikSignatureEnvelope.
|
|
180
|
+
* Validates magic bytes, version, and declared payload length before
|
|
181
|
+
* attempting to parse — a truncated or corrupted buffer fails fast with
|
|
182
|
+
* a clear reason rather than an obscure JSON.parse error.
|
|
183
|
+
*
|
|
184
|
+
* Accepts either a Blob (as produced by toMJKSIG()) or raw Uint8Array
|
|
185
|
+
* (as produced by toMJKSIGBytes(), or read directly off disk) — mirrors
|
|
186
|
+
* the same "accept either shape" pattern as from(). Reading a Blob
|
|
187
|
+
* requires awaiting its bytes, which is why this method is async.
|
|
188
|
+
*/
|
|
189
|
+
static fromMJKSIG(input: Blob | Uint8Array): Promise<MajikSignatureEnvelope>;
|
|
190
|
+
/**
|
|
191
|
+
* Cheap structural sniff — checks magic bytes only, does not parse or
|
|
192
|
+
* validate the payload. For a Blob, slices only the header bytes rather
|
|
193
|
+
* than reading the whole file, so this stays cheap even on large inputs.
|
|
194
|
+
*/
|
|
195
|
+
static isMJKSIG(input: Blob | Uint8Array): Promise<boolean>;
|
|
196
|
+
/**
|
|
197
|
+
* Read just the version byte without parsing the payload.
|
|
198
|
+
* Returns null if the input isn't MJKSIG-shaped at all.
|
|
199
|
+
*/
|
|
200
|
+
static getMJKSIGVersion(input: Blob | Uint8Array): Promise<number | null>;
|
|
164
201
|
static empty(): MajikSignatureEnvelope;
|
|
165
202
|
/**
|
|
166
203
|
* Parse a raw string or plain object into a MajikSignatureEnvelope.
|
|
@@ -174,8 +211,18 @@ export declare class MajikSignatureEnvelope {
|
|
|
174
211
|
* This is the only place that knows about the legacy on-disk shape.
|
|
175
212
|
*/
|
|
176
213
|
static fromJSON(json: MajikSignatureEnvelopeJSON | MajikSignatureJSON | string): MajikSignatureEnvelope;
|
|
177
|
-
/**
|
|
178
|
-
|
|
214
|
+
/**
|
|
215
|
+
* Accepts an instance, its JSON shape, or MJKSIG bytes/Blob — normalizes to
|
|
216
|
+
* an instance. This is the single entry point that lets every downstream
|
|
217
|
+
* caller (verifyDetached, verifyDetachedWithKey, signDetached's
|
|
218
|
+
* existingEnvelope option) transparently accept a detached envelope
|
|
219
|
+
* regardless of which form it arrived in.
|
|
220
|
+
*
|
|
221
|
+
* Now async: resolving a Blob input requires awaiting its bytes. Every
|
|
222
|
+
* existing call site is already inside an async method, so this only
|
|
223
|
+
* costs an added `await` at each call site — no structural changes.
|
|
224
|
+
*/
|
|
225
|
+
static from(input: MajikSignatureEnvelope | MajikSignatureEnvelopeJSON | Uint8Array | Blob): Promise<MajikSignatureEnvelope>;
|
|
179
226
|
validate(): void;
|
|
180
227
|
isValid(): boolean;
|
|
181
228
|
}
|
package/dist/core/envelope.js
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
*/
|
|
20
20
|
import { sha3_512 } from "@noble/hashes/sha3.js";
|
|
21
21
|
import { bytesToHex } from "@noble/hashes/utils.js";
|
|
22
|
-
import { MAJIK_ENVELOPE_VERSION, MAJIK_SEAL_DOMAIN } from "./constants";
|
|
22
|
+
import { MAJIK_ENVELOPE_VERSION, MAJIK_SEAL_DOMAIN, MJKSIG_HEADER_LEN, MJKSIG_MAGIC, MJKSIG_MAGIC_LEN, MJKSIG_MEDIA_TYPE, MJKSIG_SUPPORTED_VERSIONS, MJKSIG_VERSION, } from "./constants";
|
|
23
23
|
import { MajikSignatureAllowlistError, MajikSignatureError, MajikSignatureKeyError, MajikSignatureSerializationError, MajikSignatureValidationError, } from "./errors";
|
|
24
24
|
import { hashContent, bytesToBase64 } from "./hash";
|
|
25
25
|
// ─── MajikSignatureEnvelope ────────────────────────────────────────────────────
|
|
@@ -490,6 +490,131 @@ export class MajikSignatureEnvelope {
|
|
|
490
490
|
throw new MajikSignatureSerializationError("Failed to deserialize envelope from base64", err);
|
|
491
491
|
}
|
|
492
492
|
}
|
|
493
|
+
// ── MJKSIG binary format ─────────────────────────────────────────────────
|
|
494
|
+
//
|
|
495
|
+
// A dedicated, versioned, self-identifying binary container for a detached
|
|
496
|
+
// envelope — distinct from serialize()/deserialize() (plain base64 of the
|
|
497
|
+
// JSON, no header) which remains for lightweight in-app round-tripping.
|
|
498
|
+
// MJKSIG is the wire/on-disk format intended for out-of-band travel,
|
|
499
|
+
// storage, and eventual IANA registration.
|
|
500
|
+
// ── MJKSIG binary format ─────────────────────────────────────────────────
|
|
501
|
+
//
|
|
502
|
+
// A dedicated, versioned, self-identifying binary container for a detached
|
|
503
|
+
// envelope — distinct from serialize()/deserialize() (plain base64 of the
|
|
504
|
+
// JSON, no header) which remains for lightweight in-app round-tripping.
|
|
505
|
+
// MJKSIG is the wire/on-disk format intended for out-of-band travel,
|
|
506
|
+
// storage, and eventual IANA registration.
|
|
507
|
+
/**
|
|
508
|
+
* Raw MJKSIG bytes, no Blob wrapper. Exposed as a public escape hatch for
|
|
509
|
+
* non-browser contexts (Node scripts, tests, direct fs writes) where
|
|
510
|
+
* wrapping in a Blob just to immediately unwrap it again is pure overhead.
|
|
511
|
+
* toMJKSIG() is the primary API for anything Blob-facing.
|
|
512
|
+
*/
|
|
513
|
+
toMJKSIGBytes() {
|
|
514
|
+
const payloadJson = new TextEncoder().encode(JSON.stringify(this.toJSON()));
|
|
515
|
+
const out = new Uint8Array(MJKSIG_HEADER_LEN + payloadJson.length);
|
|
516
|
+
out.set(MJKSIG_MAGIC, 0);
|
|
517
|
+
out[MJKSIG_MAGIC_LEN] = MJKSIG_VERSION;
|
|
518
|
+
out[MJKSIG_MAGIC_LEN + 1] = 0x00; // reserved — always 0 in v1
|
|
519
|
+
const lenOffset = MJKSIG_MAGIC_LEN + 2;
|
|
520
|
+
out[lenOffset] = (payloadJson.length >>> 24) & 0xff;
|
|
521
|
+
out[lenOffset + 1] = (payloadJson.length >>> 16) & 0xff;
|
|
522
|
+
out[lenOffset + 2] = (payloadJson.length >>> 8) & 0xff;
|
|
523
|
+
out[lenOffset + 3] = payloadJson.length & 0xff;
|
|
524
|
+
out.set(payloadJson, MJKSIG_HEADER_LEN);
|
|
525
|
+
return out;
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Encode this envelope as an MJKSIG file Blob.
|
|
529
|
+
* Always writes the current MJKSIG_VERSION — encoding an old payload
|
|
530
|
+
* shape under an old version tag is not supported; old versions only
|
|
531
|
+
* ever appear when *reading* pre-existing MJKSIG binaries.
|
|
532
|
+
*/
|
|
533
|
+
toMJKSIG() {
|
|
534
|
+
const bytes = this.toMJKSIGBytes();
|
|
535
|
+
return new Blob([bytes], {
|
|
536
|
+
type: MJKSIG_MEDIA_TYPE,
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Decode MJKSIG bytes back into a MajikSignatureEnvelope.
|
|
541
|
+
* Validates magic bytes, version, and declared payload length before
|
|
542
|
+
* attempting to parse — a truncated or corrupted buffer fails fast with
|
|
543
|
+
* a clear reason rather than an obscure JSON.parse error.
|
|
544
|
+
*
|
|
545
|
+
* Accepts either a Blob (as produced by toMJKSIG()) or raw Uint8Array
|
|
546
|
+
* (as produced by toMJKSIGBytes(), or read directly off disk) — mirrors
|
|
547
|
+
* the same "accept either shape" pattern as from(). Reading a Blob
|
|
548
|
+
* requires awaiting its bytes, which is why this method is async.
|
|
549
|
+
*/
|
|
550
|
+
static async fromMJKSIG(input) {
|
|
551
|
+
const raw = input instanceof Blob ? new Uint8Array(await input.arrayBuffer()) : input;
|
|
552
|
+
return MajikSignatureEnvelope.#parseMJKSIGBytes(raw);
|
|
553
|
+
}
|
|
554
|
+
/** Core MJKSIG byte parser — shared by fromMJKSIG() after Blob resolution. */
|
|
555
|
+
static #parseMJKSIGBytes(raw) {
|
|
556
|
+
if (raw.length < MJKSIG_HEADER_LEN + 1) {
|
|
557
|
+
// +1 == at least one byte of payload JSON
|
|
558
|
+
throw new MajikSignatureSerializationError("Malformed MJKSIG: too short to contain a valid header");
|
|
559
|
+
}
|
|
560
|
+
for (let i = 0; i < MJKSIG_MAGIC_LEN; i++) {
|
|
561
|
+
if (raw[i] !== MJKSIG_MAGIC[i]) {
|
|
562
|
+
throw new MajikSignatureSerializationError('Malformed MJKSIG: missing "MJKSIG" magic bytes');
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
const version = raw[MJKSIG_MAGIC_LEN];
|
|
566
|
+
if (!MJKSIG_SUPPORTED_VERSIONS.includes(version)) {
|
|
567
|
+
throw new MajikSignatureSerializationError(`Unsupported MJKSIG version: ${version} (supported: ${MJKSIG_SUPPORTED_VERSIONS.join(", ")})`);
|
|
568
|
+
}
|
|
569
|
+
const lenOffset = MJKSIG_MAGIC_LEN + 2;
|
|
570
|
+
const payloadLen = (raw[lenOffset] << 24) |
|
|
571
|
+
(raw[lenOffset + 1] << 16) |
|
|
572
|
+
(raw[lenOffset + 2] << 8) |
|
|
573
|
+
raw[lenOffset + 3];
|
|
574
|
+
if (payloadLen <= 0) {
|
|
575
|
+
throw new MajikSignatureSerializationError("Malformed MJKSIG: invalid payload length");
|
|
576
|
+
}
|
|
577
|
+
const payloadStart = MJKSIG_HEADER_LEN;
|
|
578
|
+
const payloadEnd = payloadStart + payloadLen;
|
|
579
|
+
if (payloadEnd > raw.length) {
|
|
580
|
+
throw new MajikSignatureSerializationError("Malformed MJKSIG: declared payload length exceeds buffer");
|
|
581
|
+
}
|
|
582
|
+
const json = new TextDecoder().decode(raw.slice(payloadStart, payloadEnd));
|
|
583
|
+
// fromJSON() runs full #validateShape() — MJKSIG framing validity does
|
|
584
|
+
// NOT imply envelope validity, so this is not a redundant check.
|
|
585
|
+
return MajikSignatureEnvelope.fromJSON(json);
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Cheap structural sniff — checks magic bytes only, does not parse or
|
|
589
|
+
* validate the payload. For a Blob, slices only the header bytes rather
|
|
590
|
+
* than reading the whole file, so this stays cheap even on large inputs.
|
|
591
|
+
*/
|
|
592
|
+
static async isMJKSIG(input) {
|
|
593
|
+
const header = input instanceof Blob
|
|
594
|
+
? new Uint8Array(await input.slice(0, MJKSIG_MAGIC_LEN).arrayBuffer())
|
|
595
|
+
: input;
|
|
596
|
+
if (header.length < MJKSIG_MAGIC_LEN)
|
|
597
|
+
return false;
|
|
598
|
+
for (let i = 0; i < MJKSIG_MAGIC_LEN; i++) {
|
|
599
|
+
if (header[i] !== MJKSIG_MAGIC[i])
|
|
600
|
+
return false;
|
|
601
|
+
}
|
|
602
|
+
return true;
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Read just the version byte without parsing the payload.
|
|
606
|
+
* Returns null if the input isn't MJKSIG-shaped at all.
|
|
607
|
+
*/
|
|
608
|
+
static async getMJKSIGVersion(input) {
|
|
609
|
+
const header = input instanceof Blob
|
|
610
|
+
? new Uint8Array(await input.slice(0, MJKSIG_MAGIC_LEN + 1).arrayBuffer())
|
|
611
|
+
: input;
|
|
612
|
+
if (!(await MajikSignatureEnvelope.isMJKSIG(header)))
|
|
613
|
+
return null;
|
|
614
|
+
if (header.length < MJKSIG_MAGIC_LEN + 1)
|
|
615
|
+
return null;
|
|
616
|
+
return header[MJKSIG_MAGIC_LEN];
|
|
617
|
+
}
|
|
493
618
|
// ── Creation / parsing ───────────────────────────────────────────────────────
|
|
494
619
|
static empty() {
|
|
495
620
|
return new MajikSignatureEnvelope({
|
|
@@ -533,11 +658,24 @@ export class MajikSignatureEnvelope {
|
|
|
533
658
|
MajikSignatureEnvelope.#validateShape(promoted);
|
|
534
659
|
return new MajikSignatureEnvelope(promoted);
|
|
535
660
|
}
|
|
536
|
-
/**
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
661
|
+
/**
|
|
662
|
+
* Accepts an instance, its JSON shape, or MJKSIG bytes/Blob — normalizes to
|
|
663
|
+
* an instance. This is the single entry point that lets every downstream
|
|
664
|
+
* caller (verifyDetached, verifyDetachedWithKey, signDetached's
|
|
665
|
+
* existingEnvelope option) transparently accept a detached envelope
|
|
666
|
+
* regardless of which form it arrived in.
|
|
667
|
+
*
|
|
668
|
+
* Now async: resolving a Blob input requires awaiting its bytes. Every
|
|
669
|
+
* existing call site is already inside an async method, so this only
|
|
670
|
+
* costs an added `await` at each call site — no structural changes.
|
|
671
|
+
*/
|
|
672
|
+
static async from(input) {
|
|
673
|
+
if (input instanceof MajikSignatureEnvelope)
|
|
674
|
+
return input;
|
|
675
|
+
if (input instanceof Uint8Array || input instanceof Blob) {
|
|
676
|
+
return MajikSignatureEnvelope.fromMJKSIG(input);
|
|
677
|
+
}
|
|
678
|
+
return MajikSignatureEnvelope.fromJSON(input);
|
|
541
679
|
}
|
|
542
680
|
validate() {
|
|
543
681
|
MajikSignatureEnvelope.#validateShape(this.toJSON());
|
|
@@ -150,7 +150,7 @@ export declare class MajikSignature {
|
|
|
150
150
|
timestamp?: string;
|
|
151
151
|
mimeType?: string;
|
|
152
152
|
expectedSigners?: ExpectedSigner[];
|
|
153
|
-
existingEnvelope?: MajikSignatureEnvelope | MajikSignatureEnvelopeJSON;
|
|
153
|
+
existingEnvelope?: MajikSignatureEnvelope | MajikSignatureEnvelopeJSON | Uint8Array | Blob;
|
|
154
154
|
}): ReturnType<typeof MajikSignatureEmbed.signDetached>;
|
|
155
155
|
/**
|
|
156
156
|
* Verify a file's embedded signatures.
|
|
@@ -167,7 +167,7 @@ export declare class MajikSignature {
|
|
|
167
167
|
* Returns one VerificationResult per signer.
|
|
168
168
|
* Pass options.expectedSignerId to verify only a specific signer.
|
|
169
169
|
*/
|
|
170
|
-
static verifyFileDetached(file: Blob, envelope: MajikSignatureEnvelope | MajikSignatureEnvelopeJSON, keyOrPublicKeys: MajikKey | MajikSignerPublicKeys, options?: {
|
|
170
|
+
static verifyFileDetached(file: Blob, envelope: MajikSignatureEnvelope | MajikSignatureEnvelopeJSON | Uint8Array | Blob, keyOrPublicKeys: MajikKey | MajikSignerPublicKeys, options?: {
|
|
171
171
|
expectedSignerId?: string;
|
|
172
172
|
mimeType?: string;
|
|
173
173
|
}, debug?: boolean): Promise<VerificationResult[]>;
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@majikah/majik-signature",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"description": "Majik Signature is a hybrid post-quantum content signing and verification library for the Majikah ecosystem. Built on top of Majik Key, it provides tamper-proof, forgery-resistant digital signatures for any content format — using a dual-algorithm architecture that combines classical Ed25519 with post-quantum ML-DSA-87 (FIPS-204).",
|
|
5
|
-
"version": "0.2.
|
|
5
|
+
"version": "0.2.4",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"author": "Zelijah",
|
|
8
8
|
"main": "./dist/index.js",
|