@majikah/majik-signature-client 0.6.13 → 0.6.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,7 +20,7 @@ Designed to be used natively within the Majikah ecosystem, it inherits all core
20
20
  You can instantiate and fully hydrate the client and its storage adapters in a single call using the static `create` method.
21
21
 
22
22
  ```typescript
23
- import { MajikSignatureClient } from "your-path-here"; // Update with actual package export
23
+ import { MajikSignatureClient } from "@majikah/majik-signature-client";
24
24
 
25
25
  // 1. Initialize and hydrate the client state, keys, contacts, and stamps
26
26
  const client = await MajikSignatureClient.create({
@@ -1,7 +1,6 @@
1
1
  import { MajikContactManagerJSON } from "./contacts/types";
2
2
  import { MajikSignatureStampJSON } from "./stamp/majik-signature-stamp";
3
3
  import { UserAppPreferences } from "./storage";
4
- export type ISODateString = string;
5
4
  export interface MAJIK_API_RESPONSE {
6
5
  success: boolean;
7
6
  message: string;
package/dist/index.d.ts CHANGED
@@ -7,6 +7,7 @@ export * from "./core/crypto/constants";
7
7
  export * from "./core/crypto/keystore-manager";
8
8
  export * from "./core/storage";
9
9
  export * from "./core/stamp/majik-signature-stamp";
10
+ export * from "@majikah/majik-key";
10
11
  export { DEFAULT_USER_APP_PREFERENCES } from "./core/client-state-manager";
11
12
  export * from "./core/utils/utilities";
12
13
  export { migrateMajikMessageJSON } from "./core/contacts/majik-contact-migration";
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ export * from "./core/crypto/constants";
6
6
  export * from "./core/crypto/keystore-manager";
7
7
  export * from "./core/storage";
8
8
  export * from "./core/stamp/majik-signature-stamp";
9
+ export * from "@majikah/majik-key";
9
10
  export { DEFAULT_USER_APP_PREFERENCES } from "./core/client-state-manager";
10
11
  export * from "./core/utils/utilities";
11
12
  export { migrateMajikMessageJSON } from "./core/contacts/majik-contact-migration";
@@ -16,7 +16,7 @@
16
16
  */
17
17
  import { MajikKey, MajikKeyAddress } from "@majikah/majik-key";
18
18
  import { MajikSignature } from "@majikah/majik-signature";
19
- import type { EnvelopeInfo, ExpectedSigner, MajikSignatureJSON, MajikSignerPublicKeys, SealInfo, SealVerificationResult, SignatoriesFilter, SignatoriesResult, SignatoryInfo, SignOptions, VerificationResult } from "@majikah/majik-signature";
19
+ import type { EnvelopeInfo, ExpectedSigner, MajikSignatureEnvelope, MajikSignatureEnvelopeJSON, MajikSignatureJSON, MajikSignerPublicKeys, SealInfo, SealVerificationResult, SignatoriesFilter, SignatoriesResult, SignatoryInfo, SignOptions, VerificationResult } from "@majikah/majik-signature";
20
20
  import { MAJIK_API_RESPONSE } from "./core/types";
21
21
  import { ImageSignatureStub, ImageSignOptions, ImageVerificationResult } from "@majikah/majik-signature/dist/core/stamp";
22
22
  import { MajikContactManager, MajikContactManagerAdapters } from "./core/contacts/majik-contact-manager";
@@ -320,6 +320,22 @@ export declare class MajikSignatureClient extends MajikKeyClient<MajikContact, M
320
320
  accountId?: string;
321
321
  expectedSigners?: ExpectedSigner[];
322
322
  }): Promise<ReturnType<typeof MajikSignature.signFile>>;
323
+ /**
324
+ * Sign a file with a detached signature envelope.
325
+ *
326
+ * @example
327
+ * const { blob: signedPdf } = await majik.signFileDetached(pdfBlob);
328
+ *
329
+ * @example — non-active account
330
+ * const { blob } = await majik.signFileDetached(wavBlob, { accountId: "acc_xyz" });
331
+ */
332
+ signFileDetached(file: Blob, options?: {
333
+ contentType?: string;
334
+ timestamp?: string;
335
+ mimeType?: string;
336
+ accountId?: string;
337
+ expectedSigners?: ExpectedSigner[];
338
+ }): Promise<ReturnType<typeof MajikSignature.signFileDetached>>;
323
339
  /**
324
340
  * Sign multiple file blobs with the active (or specified) account in one call.
325
341
  *
@@ -383,6 +399,23 @@ export declare class MajikSignatureClient extends MajikKeyClient<MajikContact, M
383
399
  handler?: string;
384
400
  reason?: string;
385
401
  }>;
402
+ /**
403
+ * Verify a file's detached signature.
404
+ *
405
+ * @example — verify a signed PDF's detached signature against a known contact
406
+ * const result = await majik.verifyFileDetached(signedPdf, envelope, { contactId: "contact_abc" });
407
+ * if (result.valid) console.log("Verified:", result.signerId, result.timestamp);
408
+ */
409
+ verifyFileDetached(file: Blob, envelope: MajikSignatureEnvelope | MajikSignatureEnvelopeJSON, options?: {
410
+ contactId?: string;
411
+ publicKeyBase64?: string;
412
+ key?: MajikKey;
413
+ expectedSignerId?: string;
414
+ mimeType?: string;
415
+ }): Promise<VerificationResult & {
416
+ handler?: string;
417
+ reason?: string;
418
+ }>;
386
419
  /**
387
420
  * Verify multiple files' embedded signatures against the same signer in
388
421
  * one call.
@@ -779,6 +779,48 @@ export class MajikSignatureClient extends MajikKeyClient {
779
779
  key?.lock();
780
780
  }
781
781
  }
782
+ /**
783
+ * Sign a file with a detached signature envelope.
784
+ *
785
+ * @example
786
+ * const { blob: signedPdf } = await majik.signFileDetached(pdfBlob);
787
+ *
788
+ * @example — non-active account
789
+ * const { blob } = await majik.signFileDetached(wavBlob, { accountId: "acc_xyz" });
790
+ */
791
+ async signFileDetached(file, options) {
792
+ const id = options?.accountId ?? this.getActiveAccount()?.id;
793
+ if (!id)
794
+ throw new Error("No active account — call setActiveAccount() first");
795
+ let key;
796
+ let shouldRelock = false;
797
+ try {
798
+ await this._keys.ensureUnlocked(id);
799
+ key = this._keys.get(id);
800
+ if (!key)
801
+ throw new Error(`Account not found in keystore: "${id}"`);
802
+ if (!key.hasSigningKeys) {
803
+ throw new Error(`Account "${id}" has no signing keys. ` +
804
+ `Re-import via importAccountFromMnemonicBackup() to enable signing.`);
805
+ }
806
+ shouldRelock = !(await this.isOnetimeUnlockEnabled());
807
+ const signedResponse = await MajikSignature.signFileDetached(file, key, {
808
+ contentType: options?.contentType,
809
+ timestamp: options?.timestamp,
810
+ mimeType: options?.mimeType,
811
+ expectedSigners: options?.expectedSigners,
812
+ });
813
+ return signedResponse;
814
+ }
815
+ catch (err) {
816
+ this._emit("error", err, { context: "signFileDetached" });
817
+ throw err;
818
+ }
819
+ finally {
820
+ if (shouldRelock)
821
+ key?.lock();
822
+ }
823
+ }
782
824
  /**
783
825
  * Sign multiple file blobs with the active (or specified) account in one call.
784
826
  *
@@ -897,7 +939,49 @@ export class MajikSignatureClient extends MajikKeyClient {
897
939
  const results = await MajikSignature.verifyFile(file, firstSig.extractPublicKeys(), {
898
940
  expectedSignerId: firstSig.signerId,
899
941
  mimeType: options?.mimeType,
900
- }, true);
942
+ });
943
+ return results[0];
944
+ }
945
+ catch (err) {
946
+ this._emit("error", err, { context: "verifyFile" });
947
+ throw err;
948
+ }
949
+ }
950
+ /**
951
+ * Verify a file's detached signature.
952
+ *
953
+ * @example — verify a signed PDF's detached signature against a known contact
954
+ * const result = await majik.verifyFileDetached(signedPdf, envelope, { contactId: "contact_abc" });
955
+ * if (result.valid) console.log("Verified:", result.signerId, result.timestamp);
956
+ */
957
+ async verifyFileDetached(file, envelope, options) {
958
+ try {
959
+ const publicKeys = await this._resolveSignerPublicKeys(options);
960
+ if (publicKeys) {
961
+ const results = await MajikSignature.verifyFileDetached(file, envelope, publicKeys, {
962
+ expectedSignerId: options?.expectedSignerId,
963
+ mimeType: options?.mimeType,
964
+ });
965
+ return results[0];
966
+ }
967
+ // No signer provided — extract and use self-reported keys from first signature.
968
+ const extracted = await MajikSignature.extractFrom(file, {
969
+ mimeType: options?.mimeType,
970
+ });
971
+ if (!extracted.length) {
972
+ return {
973
+ valid: false,
974
+ signerId: "",
975
+ contentHash: "",
976
+ timestamp: new Date().toISOString(),
977
+ reason: "No embedded signature found",
978
+ };
979
+ }
980
+ const firstSig = extracted[0];
981
+ const results = await MajikSignature.verifyFileDetached(file, envelope, firstSig.extractPublicKeys(), {
982
+ expectedSignerId: firstSig.signerId,
983
+ mimeType: options?.mimeType,
984
+ });
901
985
  return results[0];
902
986
  }
903
987
  catch (err) {
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@majikah/majik-signature-client",
3
3
  "type": "module",
4
4
  "description": "Majik Signature Client is a hybrid post-quantum content signing and verification library for the Majikah ecosystem. Built on top of Majik Key Client, 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.6.13",
5
+ "version": "0.6.15",
6
6
  "license": "Apache-2.0",
7
7
  "author": "Zelijah",
8
8
  "main": "./dist/index.js",
@@ -57,7 +57,7 @@
57
57
  "@majikah/majik-file": "^0.2.4",
58
58
  "@majikah/majik-key": "^0.3.4",
59
59
  "@majikah/majik-key-client": "^0.1.8",
60
- "@majikah/majik-signature": "^0.2.1",
60
+ "@majikah/majik-signature": "^0.2.3",
61
61
  "@stablelib/ed25519": "^2.1.0",
62
62
  "ed2curve": "^0.3.0",
63
63
  "fflate": "^0.8.3"