{"version":3,"file":"PublicJwk.mjs","names":[],"sources":["../../../../src/modules/kms/jwk/PublicJwk.ts"],"sourcesContent":["import type { HashName } from '../../../crypto'\nimport { CredoError } from '../../../error'\nimport { MultiBaseEncoder, TypedArrayEncoder, VarintEncoder } from '../../../utils'\nimport type { Constructor } from '../../../utils/mixins'\nimport { zParseWithErrorHandling } from '../../../utils/zod'\nimport { KeyManagementError } from '../error/KeyManagementError'\nimport { legacyKeyIdFromPublicJwk } from '../legacy'\nimport { asymmetricPublicJwkMatches } from './equals'\nimport { getJwkHumanDescription } from './humanDescription'\nimport type { KnownJwaKeyAgreementAlgorithm, KnownJwaSignatureAlgorithm } from './jwa'\nimport { calculateJwkThumbprint } from './jwkThumbprint'\nimport { assertJwkAsymmetric, type KmsJwkPublicAsymmetric, publicJwkFromPrivateJwk, zKmsJwkPublic } from './knownJwk'\nimport {\n  Ed25519PublicJwk,\n  P256PublicJwk,\n  P384PublicJwk,\n  P521PublicJwk,\n  RsaPublicJwk,\n  Secp256k1PublicJwk,\n  X25519PublicJwk,\n} from './kty'\n\nexport const SupportedPublicJwks = [\n  Ed25519PublicJwk,\n  P256PublicJwk,\n  P384PublicJwk,\n  P521PublicJwk,\n  RsaPublicJwk,\n  Secp256k1PublicJwk,\n  X25519PublicJwk,\n]\nexport type SupportedPublicJwkClass = (typeof SupportedPublicJwks)[number]\nexport type SupportedPublicJwk =\n  | Ed25519PublicJwk\n  | P256PublicJwk\n  | P384PublicJwk\n  | P521PublicJwk\n  | RsaPublicJwk\n  | Secp256k1PublicJwk\n  | X25519PublicJwk\n\ntype ExtractByJwk<T, K> = T extends { jwk: infer J } ? (K extends J ? T : never) : never\n\ntype ExtractByPublicKey<T, K> = T extends { publicKey: infer J } ? (K extends J ? T : never) : never\n\nexport class PublicJwk<Jwk extends SupportedPublicJwk = SupportedPublicJwk> {\n  private constructor(private readonly jwk: Jwk) {}\n\n  public static fromUnknown(jwkJson: unknown) {\n    // We remove any private properties if they are present\n    const publicJwk = publicJwkFromPrivateJwk(zParseWithErrorHandling(zKmsJwkPublic, jwkJson, 'jwk is not a valid jwk'))\n    assertJwkAsymmetric(publicJwk)\n\n    let jwkInstance: SupportedPublicJwk\n    if (publicJwk.kty === 'RSA') {\n      jwkInstance = new RsaPublicJwk(publicJwk)\n    } else if (publicJwk.kty === 'EC') {\n      if (publicJwk.crv === 'P-256') {\n        jwkInstance = new P256PublicJwk({\n          ...publicJwk,\n          crv: publicJwk.crv,\n        })\n      } else if (publicJwk.crv === 'P-384') {\n        jwkInstance = new P384PublicJwk({\n          ...publicJwk,\n          crv: publicJwk.crv,\n        })\n      } else if (publicJwk.crv === 'P-521') {\n        jwkInstance = new P521PublicJwk({\n          ...publicJwk,\n          crv: publicJwk.crv,\n        })\n      } else if (publicJwk.crv === 'secp256k1') {\n        jwkInstance = new Secp256k1PublicJwk({\n          ...publicJwk,\n          crv: publicJwk.crv,\n        })\n      } else {\n        throw new KeyManagementError(\n          `Unsupported kty '${publicJwk.kty}' with crv '${publicJwk.crv}' for creating jwk instance`\n        )\n      }\n    } else if (publicJwk.crv === 'Ed25519') {\n      jwkInstance = new Ed25519PublicJwk({\n        ...publicJwk,\n        crv: publicJwk.crv,\n      })\n    } else if (publicJwk.crv === 'X25519') {\n      jwkInstance = new X25519PublicJwk({\n        ...publicJwk,\n        crv: publicJwk.crv,\n      })\n    } else {\n      throw new KeyManagementError(`Unsupported kty '${publicJwk.kty}' for creating jwk instance`)\n    }\n\n    return new PublicJwk(jwkInstance)\n  }\n\n  // FIXME: all Jwk combinations should be separate types.\n  // so not kty: EC, and crv: P-256 | P-384\n  // but: kty: EC, and crv: P-256 | kty: EC, and crv: P-384\n  // As the first approach messes with TypeScript's type inference\n  public static fromPublicJwk<Jwk extends KmsJwkPublicAsymmetric>(jwk: Jwk) {\n    return PublicJwk.fromUnknown(jwk) as PublicJwk<\n      ExtractByJwk<SupportedPublicJwk, Jwk> extends never ? SupportedPublicJwk : ExtractByJwk<SupportedPublicJwk, Jwk>\n    >\n  }\n\n  public toJson({ includeKid = true }: { includeKid?: boolean } = {}): Jwk['jwk'] {\n    if (includeKid) return this.jwk.jwk\n\n    const { kid, ...jwk } = this.jwk.jwk\n    return jwk\n  }\n\n  /**\n   * Get the signature algorithms supported for this jwk.\n   *\n   * If the jwk has an `alg` field defined it will only return that alg\n   * and otherwise return all known supported signature algorithms.\n   */\n  public get supportedSignatureAlgorithms(): KnownJwaSignatureAlgorithm[] {\n    const supportedSignatureAlgorithms: KnownJwaSignatureAlgorithm[] = this.jwk.supportedSignatureAlgorithms ?? []\n\n    if (this.jwk.jwk.alg) {\n      if (!supportedSignatureAlgorithms.includes(this.jwk.jwk.alg as KnownJwaSignatureAlgorithm)) {\n        throw new KeyManagementError(\n          `${this.jwkTypeHumanDescription} defines alg '${this.jwk.jwk.alg}' but this alg is not supported.`\n        )\n      }\n\n      return [this.jwk.jwk.alg] as this['supportedSignatureAlgorithms']\n    }\n\n    return supportedSignatureAlgorithms\n  }\n\n  public get supportedEncryptionKeyAgreementAlgorithms(): KnownJwaKeyAgreementAlgorithm[] {\n    return this.jwk.supportedEncryptionKeyAgreementAlgorithms ?? []\n  }\n\n  /**\n   * key type as defined in [JWA Specification](https://tools.ietf.org/html/rfc7518#section-6.1)\n   */\n  public get kty(): Jwk['jwk']['kty'] {\n    return this.jwk.jwk.kty\n  }\n\n  /**\n   * Get the key id for a public jwk. If the public jwk does not have\n   * a key id, an error will be thrown\n   */\n  public get keyId(): string {\n    if (this.jwk.jwk.kid) return this.jwk.jwk.kid\n\n    throw new KeyManagementError('Unable to determine keyId for jwk')\n  }\n\n  public get hasKeyId(): boolean {\n    return this.jwk.jwk.kid !== undefined\n  }\n\n  public set keyId(keyId: string) {\n    this.jwk.jwk.kid = keyId\n  }\n\n  public get legacyKeyId() {\n    return legacyKeyIdFromPublicJwk(this)\n  }\n\n  public get publicKey(): Jwk['publicKey'] {\n    return this.jwk.publicKey\n  }\n\n  /**\n   * Return the compressed public key. If the key type does not support compressed public keys, it will return null\n   */\n  public get compressedPublicKey(): Jwk['compressedPublicKey'] {\n    return this.jwk.compressedPublicKey\n  }\n\n  public get JwkClass() {\n    return this.jwk.constructor as SupportedPublicJwkClass\n  }\n\n  /**\n   * SHA-256 jwk thumbprint\n   */\n  public getJwkThumbprint(hashAlgorithm: HashName = 'sha-256') {\n    return calculateJwkThumbprint({\n      jwk: this.jwk.jwk,\n      hashAlgorithm: hashAlgorithm,\n    })\n  }\n\n  /**\n   * Get the first signature algorithm to use with this jwk. If the jwk has an `alg` field defined\n   * it will use that alg, and otherwise fall back to the first supported signature algorithm.\n   *\n   * If no algorithm is supported it will throw an error\n   */\n  public get signatureAlgorithm() {\n    const alg = this.supportedSignatureAlgorithms[0]\n    if (!alg) {\n      throw new KeyManagementError(`${this.jwkTypeHumanDescription} has no supported signature algorithms`)\n    }\n\n    return alg as this['supportedSignatureAlgorithms'][number]\n  }\n\n  public assertSignatureAlgorithmSupported(\n    alg: KnownJwaSignatureAlgorithm\n  ): asserts alg is this['supportedSignatureAlgorithms'][number] {\n    if (!this.supportedSignatureAlgorithms.includes(alg)) {\n      throw new KeyManagementError(`${this.jwkTypeHumanDescription} does not support signature alg '${alg}'.`)\n    }\n  }\n\n  public static fromPublicKey<Supported extends SupportedPublicJwk['publicKey']>(publicKey: Supported) {\n    let jwkInstance: SupportedPublicJwk\n\n    if (publicKey.kty === 'RSA') {\n      jwkInstance = RsaPublicJwk.fromPublicKey(publicKey)\n    } else if (publicKey.kty === 'EC') {\n      if (publicKey.crv === 'P-256') {\n        jwkInstance = P256PublicJwk.fromPublicKey(publicKey.publicKey)\n      } else if (publicKey.crv === 'P-384') {\n        jwkInstance = P384PublicJwk.fromPublicKey(publicKey.publicKey)\n      } else if (publicKey.crv === 'P-521') {\n        jwkInstance = P521PublicJwk.fromPublicKey(publicKey.publicKey)\n      } else if (publicKey.crv === 'secp256k1') {\n        jwkInstance = Secp256k1PublicJwk.fromPublicKey(publicKey.publicKey)\n      } else {\n        throw new KeyManagementError(\n          // @ts-expect-error\n          `Unsupported kty '${publicKey.kty}' with crv '${publicKey.crv}' for creating jwk instance based on public key bytes`\n        )\n      }\n    } else if (publicKey.crv === 'X25519') {\n      jwkInstance = X25519PublicJwk.fromPublicKey(publicKey.publicKey)\n    } else if (publicKey.crv === 'Ed25519') {\n      jwkInstance = Ed25519PublicJwk.fromPublicKey(publicKey.publicKey)\n    } else {\n      throw new KeyManagementError(\n        // @ts-expect-error\n        `Unsupported kty '${publicKey.kty}' for creating jwk instance based on public key bytes`\n      )\n    }\n\n    return new PublicJwk(jwkInstance) as PublicJwk<ExtractByPublicKey<SupportedPublicJwk, Supported>>\n  }\n\n  /**\n   * Returns the jwk encoded a Base58 multibase encoded multicodec key\n   */\n  public get fingerprint() {\n    const prefixBytes = VarintEncoder.encode(this.jwk.multicodecPrefix)\n    const prefixedPublicKey = new Uint8Array([...prefixBytes, ...this.jwk.multicodec])\n\n    return `z${TypedArrayEncoder.toBase58(prefixedPublicKey)}`\n  }\n\n  /**\n   * Create a jwk instance based on a Base58 multibase encoded multicodec key\n   */\n  public static fromFingerprint(fingerprint: string) {\n    const { data } = MultiBaseEncoder.decode(fingerprint)\n    const [code, byteLength] = VarintEncoder.decode(data)\n    const publicKey = data.slice(byteLength)\n\n    const PublicJwkClass = SupportedPublicJwks.find((JwkClass) => JwkClass.multicodecPrefix === code)\n    if (!PublicJwkClass) {\n      throw new KeyManagementError(`Unsupported multicodec public key with prefix '${code}'`)\n    }\n\n    const jwk = PublicJwkClass.fromMulticodec(publicKey)\n    return new PublicJwk(jwk)\n  }\n\n  /**\n   * Check whether this PublicJwk instance is of a specific type\n   */\n  public is<\n    Jwk1 extends SupportedPublicJwk,\n    Jwk2 extends SupportedPublicJwk = Jwk1,\n    Jwk3 extends SupportedPublicJwk = Jwk1,\n  >(\n    jwkType1: Constructor<Jwk1>,\n    jwkType2?: Constructor<Jwk2>,\n    jwkType3?: Constructor<Jwk3>\n  ): this is PublicJwk<Jwk1> | PublicJwk<Jwk2> | PublicJwk<Jwk3> {\n    const types = [jwkType1, jwkType2, jwkType3].filter(Boolean) as Constructor<SupportedPublicJwk>[]\n    return types.some((type) => this.jwk.constructor === type)\n  }\n\n  /**\n   * Convert the PublicJwk to another type.\n   *\n   * NOTE: only supported for Ed25519 to X25519 at the moment\n   */\n  public convertTo(\n    type: Jwk extends Ed25519PublicJwk ? typeof X25519PublicJwk : never\n  ): Jwk extends Ed25519PublicJwk ? PublicJwk<X25519PublicJwk> : never {\n    if (!this.is(Ed25519PublicJwk) || type !== X25519PublicJwk) {\n      throw new KeyManagementError('Unsupported key conversion. Only Ed25519 to X25519 is supported.')\n    }\n\n    return PublicJwk.fromPublicJwk(this.jwk.toX25519PublicJwk()) as Jwk extends Ed25519PublicJwk\n      ? PublicJwk<X25519PublicJwk>\n      : never\n  }\n\n  /**\n   * Check whether this jwk instance is the same as another jwk instance.\n   * It does this by comparing the key types and public keys, not other fields\n   * of the JWK such as keyId, use, etc..\n   */\n  public equals(other: PublicJwk) {\n    return asymmetricPublicJwkMatches(this.toJson(), other.toJson())\n  }\n\n  /**\n   * Get human description of a jwk type. This does\n   * not include the (public) key material\n   */\n  public get jwkTypeHumanDescription() {\n    return getJwkHumanDescription(this.toJson())\n  }\n\n  public static supportedPublicJwkClassForSignatureAlgorithm(alg: KnownJwaSignatureAlgorithm): SupportedPublicJwkClass {\n    const supportedPublicJwkClass = SupportedPublicJwks.find((JwkClass) =>\n      JwkClass.supportedSignatureAlgorithms.includes(alg)\n    )\n\n    if (!supportedPublicJwkClass) {\n      throw new CredoError(`Could not determine supported public jwk class for alg '${alg}'`)\n    }\n\n    return supportedPublicJwkClass\n  }\n}\n"],"mappings":"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"}