@vess-id/ai-identity 0.0.1 → 0.0.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.mjs CHANGED
@@ -366,7 +366,51 @@ async function getVerifier(publicKey) {
366
366
  };
367
367
  }
368
368
 
369
+ // src/did/did-utils.ts
370
+ function createDidJwk(publicKey) {
371
+ const publicJwk = {
372
+ kty: publicKey.kty,
373
+ crv: publicKey.crv,
374
+ x: publicKey.x,
375
+ y: publicKey.y,
376
+ use: publicKey.use,
377
+ alg: publicKey.alg
378
+ };
379
+ const cleanedJwk = Object.fromEntries(
380
+ Object.entries(publicJwk).filter(([_, v]) => v !== void 0)
381
+ );
382
+ const encoded = Buffer.from(JSON.stringify(cleanedJwk)).toString("base64url");
383
+ return `did:jwk:${encoded}`;
384
+ }
385
+ function extractPublicKey(privateKey) {
386
+ const { d, key_ops, ...publicKey } = privateKey;
387
+ return publicKey;
388
+ }
389
+ function extractPublicKeyFromDid(did) {
390
+ if (!did.startsWith("did:jwk:")) {
391
+ throw new Error("Only did:jwk format is supported");
392
+ }
393
+ const encoded = did.replace("did:jwk:", "");
394
+ return JSON.parse(Buffer.from(encoded, "base64url").toString());
395
+ }
396
+ function isValidDidJwk(did) {
397
+ if (!did.startsWith("did:jwk:")) {
398
+ return false;
399
+ }
400
+ try {
401
+ const encoded = did.replace("did:jwk:", "");
402
+ const decoded = JSON.parse(Buffer.from(encoded, "base64url").toString());
403
+ return typeof decoded === "object" && decoded.kty !== void 0;
404
+ } catch {
405
+ return false;
406
+ }
407
+ }
408
+ function getKeyIdFromDid(did) {
409
+ return `${did}#0`;
410
+ }
411
+
369
412
  // src/utils/sdjwt-client.ts
413
+ import { subtle as subtle2 } from "crypto";
370
414
  var SDJwtClient = class {
371
415
  static instances = /* @__PURE__ */ new Map();
372
416
  static keyManager;
@@ -571,6 +615,212 @@ var SDJwtClient = class {
571
615
  verifierCount: this.verifierCache.size
572
616
  };
573
617
  }
618
+ /**
619
+ * Create a verifier function from an external public key
620
+ * This is used for verifying SD-JWTs when you don't have the private key
621
+ * (e.g., API side verifying credentials issued by MCP)
622
+ */
623
+ static async getVerifierFromPublicKey(publicKey) {
624
+ const key = await subtle2.importKey(
625
+ "jwk",
626
+ publicKey,
627
+ {
628
+ name: "ECDSA",
629
+ namedCurve: "P-256"
630
+ },
631
+ true,
632
+ ["verify"]
633
+ );
634
+ return async (data, signatureBase64url) => {
635
+ const encoder = new TextEncoder();
636
+ const signature = Uint8Array.from(
637
+ atob(signatureBase64url.replace(/-/g, "+").replace(/_/g, "/")),
638
+ (c) => c.charCodeAt(0)
639
+ );
640
+ const isValid = await subtle2.verify(
641
+ {
642
+ name: "ECDSA",
643
+ hash: { name: "SHA-256" }
644
+ },
645
+ key,
646
+ signature,
647
+ encoder.encode(data)
648
+ );
649
+ return isValid;
650
+ };
651
+ }
652
+ /**
653
+ * Get SDJwtVcInstance for verification with an external public key
654
+ * Used when verifying credentials without having the issuer's private key
655
+ */
656
+ static async getVerificationInstance(publicKey) {
657
+ const cacheKey = `verify:${JSON.stringify(publicKey)}`;
658
+ if (!this.instances.has(cacheKey)) {
659
+ const dummySigner = async () => "dummy";
660
+ const verifier = await this.getVerifierFromPublicKey(publicKey);
661
+ const instance = new SDJwtVcInstance({
662
+ signer: dummySigner,
663
+ verifier,
664
+ signAlg: ES256.alg,
665
+ hasher: digest,
666
+ hashAlg: "sha-256",
667
+ saltGenerator: generateSalt
668
+ });
669
+ this.instances.set(cacheKey, instance);
670
+ }
671
+ return this.instances.get(cacheKey);
672
+ }
673
+ /**
674
+ * Get SDJwtVcInstance for decoding without verification
675
+ */
676
+ static async getDecodingInstance() {
677
+ const cacheKey = "decode:dummy";
678
+ if (!this.instances.has(cacheKey)) {
679
+ const dummySigner = async () => "dummy";
680
+ const dummyVerifier = async () => false;
681
+ const instance = new SDJwtVcInstance({
682
+ signer: dummySigner,
683
+ verifier: dummyVerifier,
684
+ signAlg: ES256.alg,
685
+ hasher: digest,
686
+ hashAlg: "sha-256",
687
+ saltGenerator: generateSalt
688
+ });
689
+ this.instances.set(cacheKey, instance);
690
+ }
691
+ return this.instances.get(cacheKey);
692
+ }
693
+ /**
694
+ * Verify an SD-JWT with an external public key
695
+ * Use this when you have the issuer's public key but not their private key
696
+ *
697
+ * @param credential - The SD-JWT credential string
698
+ * @param publicKey - The issuer's public key (JWK format)
699
+ * @returns Verification result with valid flag and payload
700
+ *
701
+ * @example
702
+ * ```typescript
703
+ * const publicKey = extractPublicKeyFromDid(issuerDid)
704
+ * const result = await SDJwtClient.verifyWithExternalKey(credential, publicKey)
705
+ * if (result.valid) {
706
+ * console.log('Verified claims:', result.payload.claims)
707
+ * }
708
+ * ```
709
+ */
710
+ static async verifyWithExternalKey(credential, publicKey) {
711
+ try {
712
+ const sdJwtInstance = await this.getVerificationInstance(publicKey);
713
+ const verificationResult = await sdJwtInstance.verify(credential, {});
714
+ if (!verificationResult) {
715
+ return { valid: false, error: "Verification failed" };
716
+ }
717
+ const claims = await sdJwtInstance.getClaims(credential);
718
+ return {
719
+ valid: true,
720
+ payload: verificationResult.payload,
721
+ claims
722
+ };
723
+ } catch (error) {
724
+ return {
725
+ valid: false,
726
+ error: error.message
727
+ };
728
+ }
729
+ }
730
+ /**
731
+ * Verify an SD-JWT by extracting the issuer's public key from the DID
732
+ * Automatically resolves did:jwk DIDs
733
+ *
734
+ * @param credential - The SD-JWT credential string
735
+ * @returns Verification result with valid flag and payload
736
+ *
737
+ * @example
738
+ * ```typescript
739
+ * const result = await SDJwtClient.verifyWithIssuerDid(credential)
740
+ * if (result.valid) {
741
+ * console.log('Issuer:', result.payload.iss)
742
+ * }
743
+ * ```
744
+ */
745
+ static async verifyWithIssuerDid(credential) {
746
+ try {
747
+ const decoded = await this.decodeWithoutVerification(credential);
748
+ if (!decoded.payload) {
749
+ return { valid: false, error: "Failed to decode credential" };
750
+ }
751
+ const issuerDid = decoded.payload.iss || decoded.payload.issuer;
752
+ if (!issuerDid || typeof issuerDid !== "string") {
753
+ return { valid: false, error: "Issuer DID not found in credential" };
754
+ }
755
+ const publicKey = extractPublicKeyFromDid(issuerDid);
756
+ const result = await this.verifyWithExternalKey(credential, publicKey);
757
+ return {
758
+ ...result,
759
+ issuerDid
760
+ };
761
+ } catch (error) {
762
+ return {
763
+ valid: false,
764
+ error: error.message
765
+ };
766
+ }
767
+ }
768
+ /**
769
+ * Decode an SD-JWT without verification
770
+ * Use this when you need to inspect the credential before verification
771
+ * or when you don't have the issuer's public key
772
+ *
773
+ * WARNING: The returned payload has not been verified!
774
+ * Only use this for inspection purposes, not for authorization decisions.
775
+ *
776
+ * @param credential - The SD-JWT credential string
777
+ * @returns Decoded JWT payload, header, and disclosures
778
+ *
779
+ * @example
780
+ * ```typescript
781
+ * const decoded = await SDJwtClient.decodeWithoutVerification(credential)
782
+ * console.log('Issuer (unverified):', decoded.payload?.iss)
783
+ * console.log('Disclosures:', decoded.disclosures?.length)
784
+ * ```
785
+ */
786
+ static async decodeWithoutVerification(credential) {
787
+ try {
788
+ const sdJwtInstance = await this.getDecodingInstance();
789
+ const decoded = await sdJwtInstance.decode(credential);
790
+ if (!decoded || !decoded.jwt) {
791
+ return { error: "Failed to decode SD-JWT" };
792
+ }
793
+ const claims = await decoded.getClaims(digest);
794
+ return {
795
+ payload: decoded.jwt.payload,
796
+ header: decoded.jwt.header,
797
+ disclosures: decoded.disclosures,
798
+ claims
799
+ };
800
+ } catch (error) {
801
+ return { error: error.message };
802
+ }
803
+ }
804
+ /**
805
+ * Extract issuer DID from an SD-JWT without verification
806
+ * Useful for determining the issuer before verification
807
+ *
808
+ * @param credential - The SD-JWT credential string
809
+ * @returns The issuer DID or null if not found
810
+ */
811
+ static extractIssuerDid(credential) {
812
+ try {
813
+ const parts = credential.split("~");
814
+ if (parts.length === 0) return null;
815
+ const jwt = parts[0];
816
+ const jwtParts = jwt.split(".");
817
+ if (jwtParts.length !== 3) return null;
818
+ const payload = JSON.parse(Buffer.from(jwtParts[1], "base64url").toString());
819
+ return payload.iss || payload.issuer || null;
820
+ } catch {
821
+ return null;
822
+ }
823
+ }
574
824
  };
575
825
 
576
826
  // src/agent/agent-did-manager.ts
@@ -586,7 +836,7 @@ var AgentDIDManager = class {
586
836
  */
587
837
  async generateAgentDID(agentId) {
588
838
  const keyPair = await SDJwtClient.generateKeyPair();
589
- const did = this.createDidJwk(keyPair.publicKey);
839
+ const did = createDidJwk(keyPair.publicKey);
590
840
  await this.keyManager.storeKey(did, keyPair.privateKey);
591
841
  this.agentDIDMap.set(agentId, did);
592
842
  await this.saveAgentDIDMapping(agentId, did);
@@ -628,7 +878,7 @@ var AgentDIDManager = class {
628
878
  }
629
879
  return {
630
880
  privateKey,
631
- publicKey: this.extractPublicKey(privateKey)
881
+ publicKey: extractPublicKey(privateKey)
632
882
  };
633
883
  }
634
884
  /**
@@ -670,31 +920,6 @@ var AgentDIDManager = class {
670
920
  return [];
671
921
  }
672
922
  }
673
- /**
674
- * Create did:jwk from public key
675
- */
676
- createDidJwk(publicKey) {
677
- const publicJwk = {
678
- kty: publicKey.kty,
679
- crv: publicKey.crv,
680
- x: publicKey.x,
681
- y: publicKey.y,
682
- use: publicKey.use,
683
- alg: publicKey.alg
684
- };
685
- const encoded = Buffer.from(JSON.stringify(publicJwk)).toString("base64url");
686
- return `did:jwk:${encoded}`;
687
- }
688
- /**
689
- * Extract public key from private key
690
- */
691
- extractPublicKey(privateKey) {
692
- const { d, key_ops, ...publicKey } = privateKey;
693
- return {
694
- ...publicKey
695
- // Remove key_ops for public key
696
- };
697
- }
698
923
  /**
699
924
  * Save agent ID -> DID mapping to persistent storage
700
925
  */
@@ -911,7 +1136,7 @@ var UserIdentityManager = class {
911
1136
  */
912
1137
  async createUserDID() {
913
1138
  const keyPair = await SDJwtClient.generateKeyPair();
914
- const did = this.createDidJwk(keyPair.publicKey);
1139
+ const did = createDidJwk(keyPair.publicKey);
915
1140
  await this.keyManager.storeKey(did, keyPair.privateKey);
916
1141
  await this.saveUserDID(did);
917
1142
  this.currentUserDID = did;
@@ -928,7 +1153,7 @@ var UserIdentityManager = class {
928
1153
  }
929
1154
  return {
930
1155
  privateKey,
931
- publicKey: this.extractPublicKey(privateKey)
1156
+ publicKey: extractPublicKey(privateKey)
932
1157
  };
933
1158
  }
934
1159
  /**
@@ -969,34 +1194,11 @@ var UserIdentityManager = class {
969
1194
  await this.clearUserDID();
970
1195
  return await this.createUserDID();
971
1196
  }
972
- /**
973
- * Create did:jwk from public key
974
- */
975
- createDidJwk(publicKey) {
976
- const publicJwk = {
977
- kty: publicKey.kty,
978
- crv: publicKey.crv,
979
- x: publicKey.x,
980
- y: publicKey.y,
981
- use: publicKey.use,
982
- alg: publicKey.alg
983
- };
984
- const encoded = Buffer.from(JSON.stringify(publicJwk)).toString("base64url");
985
- return `did:jwk:${encoded}`;
986
- }
987
- /**
988
- * Extract public key from private key
989
- */
990
- extractPublicKey(privateKey) {
991
- const { d, key_ops, ...publicKey } = privateKey;
992
- return publicKey;
993
- }
994
1197
  /**
995
1198
  * Resolve did:jwk locally
996
1199
  */
997
1200
  resolveDidJwkLocally(did) {
998
- const encoded = did.replace("did:jwk:", "");
999
- const publicJwk = JSON.parse(Buffer.from(encoded, "base64url").toString());
1201
+ const publicJwk = extractPublicKeyFromDid(did);
1000
1202
  return this.createDidDocument(did, publicJwk);
1001
1203
  }
1002
1204
  /**
@@ -2970,7 +3172,7 @@ var MetricsManager = class {
2970
3172
  /**
2971
3173
  * End tracking an operation
2972
3174
  */
2973
- endOperation(operationId, success, error) {
3175
+ endOperation(_operationId, success, error) {
2974
3176
  const endTime = performance.now();
2975
3177
  const operation = this.operations[this.operations.length - 1];
2976
3178
  if (operation) {
@@ -4492,15 +4694,20 @@ export {
4492
4694
  checkPermissionWithVP,
4493
4695
  configure,
4494
4696
  createAjv,
4697
+ createDidJwk,
4495
4698
  defaultConstraintEvaluator,
4496
4699
  evaluateConstraints,
4700
+ extractPublicKey,
4701
+ extractPublicKeyFromDid,
4497
4702
  generateKeyPair,
4498
4703
  generateNonce,
4499
4704
  getClient,
4705
+ getKeyIdFromDid,
4500
4706
  getRequiredRelations,
4501
4707
  getRequiredScopes,
4502
4708
  indexActions,
4503
4709
  indexCapabilities,
4710
+ isValidDidJwk,
4504
4711
  loadActionRegistryFromFile,
4505
4712
  loadActionRegistryFromObject,
4506
4713
  planDelegationForVC,