"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var OperationalCredentialsServer_exports = {};
__export(OperationalCredentialsServer_exports, {
  OperationalCredentialsServer: () => OperationalCredentialsServer
});
module.exports = __toCommonJS(OperationalCredentialsServer_exports);
var import_CommissioningServer = require("#behavior/system/commissioning/CommissioningServer.js");
var import_ProductDescriptionServer = require("#behavior/system/product-description/ProductDescriptionServer.js");
var import_access_control = require("#behaviors/access-control");
var import_operational_credentials = require("#clusters/operational-credentials");
var import_general = require("#general");
var import_model = require("#model");
var import_protocol = require("#protocol");
var import_types = require("#types");
var import_OperationalCredentialsBehavior = require("./OperationalCredentialsBehavior.js");
var import_VendorIdVerification = require("./VendorIdVerification.js");
/**
 * @license
 * Copyright 2022-2025 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
const logger = import_general.Logger.get("OperationalCredentials");
import_operational_credentials.OperationalCredentials.Cluster.commands = {
  ...import_operational_credentials.OperationalCredentials.Cluster.commands,
  attestationRequest: (0, import_types.Command)(
    0,
    (0, import_types.TlvObject)({ attestationNonce: (0, import_types.TlvField)(0, import_types.TlvByteString) }),
    1,
    import_operational_credentials.OperationalCredentials.TlvAttestationResponse,
    { invokeAcl: import_model.AccessLevel.Administer }
  ),
  csrRequest: (0, import_types.Command)(
    4,
    (0, import_types.TlvObject)({
      csrNonce: (0, import_types.TlvField)(0, import_types.TlvByteString),
      isForUpdateNoc: (0, import_types.TlvOptionalField)(1, import_types.TlvBoolean)
    }),
    5,
    import_operational_credentials.OperationalCredentials.TlvCsrResponse,
    { invokeAcl: import_model.AccessLevel.Administer }
  )
};
class OperationalCredentialsServer extends import_OperationalCredentialsBehavior.OperationalCredentialsBehavior {
  initialize() {
    if (!this.state.supportedFabrics) {
      this.state.supportedFabrics = 254;
    }
    this.state.commissionedFabrics = this.state.fabrics.length;
    this.reactTo(this.endpoint.lifecycle.online, this.#nodeOnline);
  }
  async attestationRequest({ attestationNonce }) {
    (0, import_protocol.assertRemoteActor)(this.context);
    if (attestationNonce.byteLength !== 32) {
      throw new import_types.StatusResponseError("Invalid attestation nonce length", import_types.StatusCode.InvalidCommand);
    }
    const certification = await this.getCertification();
    const session = this.context.session;
    import_protocol.NodeSession.assert(session);
    const attestationElements = import_protocol.TlvAttestation.encode({
      declaration: certification.declaration,
      attestationNonce,
      timestamp: 0
    });
    const attestationSignature = (await certification.sign(session, attestationElements)).bytes;
    return { attestationElements, attestationSignature };
  }
  async csrRequest({ csrNonce, isForUpdateNoc }) {
    (0, import_protocol.assertRemoteActor)(this.context);
    if (csrNonce.byteLength !== 32) {
      throw new import_types.StatusResponseError("Invalid csr nonce length", import_types.StatusCode.InvalidCommand);
    }
    const session = this.context.session;
    import_protocol.NodeSession.assert(session);
    if (isForUpdateNoc && session.isPase) {
      throw new import_types.StatusResponseError(
        "csrRequest for UpdateNoc received on a PASE session",
        import_types.StatusCode.InvalidCommand
      );
    }
    const commissioner = this.env.get(import_protocol.DeviceCommissioner);
    const failsafeContext = commissioner.failsafeContext;
    if (failsafeContext.fabricIndex !== void 0) {
      throw new import_types.StatusResponseError(
        `csrRequest received after ${failsafeContext.forUpdateNoc ? "UpdateNOC" : "AddNOC"} already invoked`,
        import_types.StatusCode.ConstraintError
      );
    }
    const certification = await this.getCertification();
    (0, import_protocol.assertRemoteActor)(this.context);
    const certSigningRequest = await failsafeContext.createCertificateSigningRequest(
      isForUpdateNoc ?? false,
      this.context.session.id
    );
    const nocsrElements = import_protocol.TlvCertSigningRequest.encode({ certSigningRequest, csrNonce });
    const attestationSignature = (await certification.sign(session, nocsrElements)).bytes;
    return { nocsrElements, attestationSignature };
  }
  async certificateChainRequest({ certificateType }) {
    const certification = await this.getCertification();
    switch (certificateType) {
      case import_operational_credentials.OperationalCredentials.CertificateChainType.DacCertificate:
        return { certificate: certification.certificate };
      case import_operational_credentials.OperationalCredentials.CertificateChainType.PaiCertificate:
        return { certificate: certification.intermediateCertificate };
      default:
        throw new import_types.StatusResponseError(
          `Unsupported certificate type: ${certificateType}`,
          import_types.StatusCode.InvalidCommand
        );
    }
  }
  #mapNocErrors(error) {
    if (error instanceof import_protocol.MatterFabricConflictError) {
      return {
        statusCode: import_operational_credentials.OperationalCredentials.NodeOperationalCertStatus.FabricConflict,
        debugText: error.message
      };
    } else if (error instanceof import_protocol.FabricTableFullError) {
      return {
        statusCode: import_operational_credentials.OperationalCredentials.NodeOperationalCertStatus.TableFull,
        debugText: error.message
      };
    } else if (error instanceof import_general.CryptoVerifyError || error instanceof import_protocol.CertificateError || error instanceof import_types.ValidationError || error instanceof import_general.UnexpectedDataError) {
      return {
        statusCode: import_operational_credentials.OperationalCredentials.NodeOperationalCertStatus.InvalidNoc,
        debugText: error.message
      };
    } else if (error instanceof import_protocol.PublicKeyError) {
      return {
        statusCode: import_operational_credentials.OperationalCredentials.NodeOperationalCertStatus.InvalidPublicKey,
        debugText: error.message
      };
    } else if (error instanceof import_protocol.MatterFabricInvalidAdminSubjectError) {
      return {
        statusCode: import_operational_credentials.OperationalCredentials.NodeOperationalCertStatus.InvalidAdminSubject,
        debugText: error.message
      };
    }
    throw error;
  }
  async addNoc({
    nocValue,
    icacValue,
    ipkValue,
    caseAdminSubject,
    adminVendorId
  }) {
    (0, import_protocol.assertRemoteActor)(this.context);
    const failsafeContext = this.#failsafeContext;
    if (failsafeContext.fabricIndex !== void 0) {
      throw new import_types.StatusResponseError(
        `AddNoc is illegal after ${failsafeContext.forUpdateNoc ? "UpdateNOC" : "AddNOC"} in the same failsafe context`,
        import_types.StatusCode.ConstraintError
      );
    }
    if (!failsafeContext.hasRootCert) {
      return {
        statusCode: import_operational_credentials.OperationalCredentials.NodeOperationalCertStatus.InvalidNoc,
        debugText: "Root certificate not found"
      };
    }
    if (failsafeContext.csrSessionId !== this.context.session.id) {
      return {
        statusCode: import_operational_credentials.OperationalCredentials.NodeOperationalCertStatus.MissingCsr,
        debugText: "CSR not found in failsafe context"
      };
    }
    if (failsafeContext.forUpdateNoc) {
      throw new import_types.StatusResponseError(
        `AddNoc is illegal after CsrRequest for UpdateNOC in same failsafe context`,
        import_types.StatusCode.ConstraintError
      );
    }
    const state = this.state;
    if (state.commissionedFabrics >= state.supportedFabrics) {
      return {
        statusCode: import_operational_credentials.OperationalCredentials.NodeOperationalCertStatus.TableFull,
        debugText: `No more fabrics can be added because limit ${state.supportedFabrics} reached`
      };
    }
    let fabric;
    try {
      fabric = await failsafeContext.buildFabric({
        nocValue,
        icacValue,
        adminVendorId,
        ipkValue,
        caseAdminSubject
      });
    } catch (error) {
      logger.info("Building fabric for addNoc failed", error);
      return this.#mapNocErrors(error);
    }
    await this.endpoint.act((agent) => agent.get(import_access_control.AccessControlServer).addDefaultCaseAcl(fabric, [caseAdminSubject]));
    const session = this.context.session;
    import_protocol.NodeSession.assert(session);
    await failsafeContext.addFabric(fabric);
    try {
      if (session.isPase) {
        logger.debug(`Add Fabric ${fabric.fabricIndex} to PASE session ${session.name}`);
        session.addAssociatedFabric(fabric);
      }
      const existingFabricIndex = this.state.fabrics.findIndex((f) => f.fabricIndex === fabric.fabricIndex);
      const existingNocIndex = this.state.nocs.findIndex((n) => n.fabricIndex === fabric.fabricIndex);
      if (existingFabricIndex !== -1 || existingNocIndex !== -1) {
        throw new import_general.MatterFlowError(
          `FabricIndex ${fabric.fabricIndex} already exists in state. This should not happen`
        );
      }
    } catch (e) {
      await fabric.remove(session.id);
      throw e;
    }
    logger.info(`addNoc success, adminVendorId ${adminVendorId}, caseAdminSubject ${caseAdminSubject}`);
    return {
      statusCode: import_operational_credentials.OperationalCredentials.NodeOperationalCertStatus.Ok,
      fabricIndex: fabric.fabricIndex
    };
  }
  async updateNoc({ nocValue, icacValue }) {
    (0, import_protocol.assertRemoteActor)(this.context);
    import_protocol.NodeSession.assert(this.context.session);
    const timedOp = this.#failsafeContext;
    if (timedOp.fabricIndex !== void 0) {
      throw new import_types.StatusResponseError(
        `UpdateNoc is illegal after ${timedOp.forUpdateNoc ? "UpdateNOC" : "AddNOC"} in same failsafe context`,
        import_types.StatusCode.ConstraintError
      );
    }
    if (timedOp.forUpdateNoc === false) {
      throw new import_types.StatusResponseError(
        "UpdateNoc is illegal after CsrRequest for AddNOC in same failsafe context",
        import_types.StatusCode.ConstraintError
      );
    }
    if (timedOp.rootCertSet) {
      return {
        statusCode: import_operational_credentials.OperationalCredentials.NodeOperationalCertStatus.MissingCsr
      };
    }
    if (timedOp.forUpdateNoc === void 0) {
      return {
        statusCode: import_operational_credentials.OperationalCredentials.NodeOperationalCertStatus.MissingCsr
      };
    }
    if (this.context.session.associatedFabric.fabricIndex !== timedOp.associatedFabric?.fabricIndex) {
      throw new import_types.StatusResponseError(
        "Fabric of this session and the failsafe context do not match",
        import_types.StatusCode.ConstraintError
      );
    }
    try {
      const updatedFabric = await timedOp.buildUpdatedFabric(nocValue, icacValue);
      await timedOp.updateFabric(updatedFabric);
      return {
        statusCode: import_operational_credentials.OperationalCredentials.NodeOperationalCertStatus.Ok,
        fabricIndex: updatedFabric.fabricIndex
      };
    } catch (error) {
      logger.info("Building fabric for updateNoc failed", error);
      return this.#mapNocErrors(error);
    }
  }
  async updateFabricLabel({ label }) {
    (0, import_protocol.assertRemoteActor)(this.context);
    const fabric = this.context.session.associatedFabric;
    const currentFabricIndex = fabric.fabricIndex;
    const fabrics = this.env.get(import_protocol.FabricManager);
    const conflictingLabelFabric = fabrics.find((f) => f.label === label && f.fabricIndex !== currentFabricIndex);
    if (conflictingLabelFabric !== void 0) {
      return {
        statusCode: import_operational_credentials.OperationalCredentials.NodeOperationalCertStatus.LabelConflict,
        debugText: `Label ${label} already used by fabric ${conflictingLabelFabric.fabricIndex}`
      };
    }
    await fabric.setLabel(label);
    return { statusCode: import_operational_credentials.OperationalCredentials.NodeOperationalCertStatus.Ok, fabricIndex: fabric.fabricIndex };
  }
  async removeFabric({ fabricIndex }) {
    (0, import_protocol.assertRemoteActor)(this.context);
    const fabric = this.env.get(import_protocol.FabricManager).findByIndex(fabricIndex);
    if (fabric === void 0) {
      return {
        statusCode: import_operational_credentials.OperationalCredentials.NodeOperationalCertStatus.InvalidFabricIndex,
        debugText: `Fabric ${fabricIndex} not found`
      };
    }
    await fabric.leave(this.context.session.id);
    return {
      statusCode: import_operational_credentials.OperationalCredentials.NodeOperationalCertStatus.Ok,
      fabricIndex
    };
  }
  async addTrustedRootCertificate({
    rootCaCertificate
  }) {
    const failsafeContext = this.#failsafeContext;
    if (failsafeContext.rootCertSet) {
      throw new import_types.StatusResponseError(
        "Trusted root certificate already added in this FailSafe context",
        import_types.StatusCode.ConstraintError
      );
    }
    if (failsafeContext.fabricIndex !== void 0) {
      throw new import_types.StatusResponseError(
        `Cannot add trusted root certificates after ${failsafeContext.forUpdateNoc ? "UpdateNOC" : "AddNOC"}`,
        import_types.StatusCode.ConstraintError
      );
    }
    try {
      await failsafeContext.setRootCert(rootCaCertificate);
    } catch (error) {
      logger.info("Error installing root certificate:", error);
      if (error instanceof import_general.CryptoVerifyError || error instanceof import_protocol.CertificateError || error instanceof import_types.ValidationError || error instanceof import_general.UnexpectedDataError) {
        throw new import_types.StatusResponseError(error.message, import_types.StatusCode.InvalidCommand);
      }
      throw error;
    }
    const fabrics = this.env.get(import_protocol.FabricManager);
    const trustedRootCertificates = fabrics.map((fabric) => fabric.rootCert);
    trustedRootCertificates.push(rootCaCertificate);
    this.state.trustedRootCertificates = trustedRootCertificates;
  }
  async signVidVerificationRequest({
    fabricIndex,
    clientChallenge
  }) {
    (0, import_protocol.assertRemoteActor)(this.context);
    import_protocol.NodeSession.assert(this.context.session);
    const fabrics = this.env.get(import_protocol.FabricManager);
    if (!fabrics.has(fabricIndex)) {
      throw new import_types.StatusResponse.ConstraintErrorError(`Fabric with index ${fabricIndex} does not exist`);
    }
    const fabric = fabrics.for(fabricIndex);
    const { fabricBindingVersion, signatureData } = import_VendorIdVerification.VendorIdVerification.dataToSign({
      attChallenge: this.context.session.attestationChallengeKey,
      clientChallenge,
      fabricIndex,
      fabric: fabric.config
    });
    return {
      fabricIndex,
      fabricBindingVersion,
      signature: (await fabric.sign(signatureData)).bytes
    };
  }
  async setVidVerificationStatement({
    vendorId,
    vidVerificationStatement,
    vvsc
  }) {
    (0, import_protocol.assertRemoteActor)(this.context);
    const fabric = this.context.session.associatedFabric;
    if (vendorId === void 0 && vidVerificationStatement === void 0 && vvsc === void 0) {
      throw new import_types.StatusResponse.InvalidCommandError(
        "At least one of vendorId, vidVerificationStatement or vvsc must be provided"
      );
    }
    if (vendorId !== void 0 && !import_types.VendorId.isValid(vendorId)) {
      throw new import_types.StatusResponse.ConstraintErrorError(`Invalid vendorId: ${vendorId}`);
    }
    await fabric.updateVendorVerificationData(vendorId, vidVerificationStatement, vvsc);
  }
  async #updateFabrics() {
    const fabrics = this.env.get(import_protocol.FabricManager);
    this.state.fabrics = fabrics.map((fabric) => ({
      fabricId: fabric.fabricId,
      label: fabric.label,
      nodeId: fabric.nodeId,
      rootPublicKey: fabric.rootPublicKey,
      vendorId: fabric.rootVendorId,
      vidVerificationStatement: fabric.vidVerificationStatement,
      fabricIndex: fabric.fabricIndex
    }));
    this.state.nocs = fabrics.map((fabric) => ({
      noc: fabric.operationalCert,
      icac: fabric.intermediateCACert ?? null,
      vvsc: fabric.vvsc,
      fabricIndex: fabric.fabricIndex
    }));
    this.state.trustedRootCertificates = fabrics.map((fabric) => fabric.rootCert);
    this.state.commissionedFabrics = fabrics.length;
    await this.context.transaction.commit();
  }
  async getCertification() {
    const certification = this.internal.certification ?? (this.internal.certification = new import_protocol.DeviceCertification(
      this.env.get(import_general.Crypto),
      this.state.certification,
      this.agent.get(import_ProductDescriptionServer.ProductDescriptionServer).state
    ));
    await certification.construction;
    return certification;
  }
  async #handleAddedFabric({ fabricIndex }) {
    await this.#updateFabrics();
    this.agent.get(import_CommissioningServer.CommissioningServer).handleFabricChange(fabricIndex, import_protocol.FabricAction.Added);
  }
  async #handleUpdatedFabric({ fabricIndex }) {
    await this.#updateFabrics();
    this.agent.get(import_CommissioningServer.CommissioningServer).handleFabricChange(fabricIndex, import_protocol.FabricAction.Updated);
  }
  async #handleRemovedFabric({ fabricIndex }) {
    await this.#updateFabrics();
    this.agent.get(import_CommissioningServer.CommissioningServer).handleFabricChange(fabricIndex, import_protocol.FabricAction.Removed);
  }
  async #handleFailsafeClosed() {
    await this.#updateFabrics();
  }
  async #nodeOnline() {
    const fabricManager = this.env.get(import_protocol.FabricManager);
    this.reactTo(fabricManager.events.added, this.#handleAddedFabric, { lock: true });
    this.reactTo(fabricManager.events.updated, this.#handleUpdatedFabric, { lock: true });
    this.reactTo(fabricManager.events.deleted, this.#handleRemovedFabric, { lock: true });
    this.reactTo(fabricManager.events.failsafeClosed, this.#handleFailsafeClosed, { lock: true });
    await this.#updateFabrics();
  }
  get #failsafeContext() {
    return this.env.get(import_protocol.DeviceCommissioner).failsafeContext;
  }
}
((OperationalCredentialsServer2) => {
  class Internal {
    certification;
    commissionedFabric;
  }
  OperationalCredentialsServer2.Internal = Internal;
  class State extends import_OperationalCredentialsBehavior.OperationalCredentialsBehavior.State {
    /**
     * Device certification information.
     *
     * Device certification provides a cryptographic certificate that asserts the official status of a device.
     * Production consumer-facing devices are certified by the CSA.
     *
     * Development devices and those intended for personal use may use a development certificate.  This is the
     * default if you do not provide an official certification in {@link ServerOptions.certification}.
     */
    certification = void 0;
    [import_protocol.Val.properties](_endpoint, session) {
      return {
        get currentFabricIndex() {
          return session.fabric ?? import_types.FabricIndex.NO_FABRIC;
        }
      };
    }
  }
  OperationalCredentialsServer2.State = State;
})(OperationalCredentialsServer || (OperationalCredentialsServer = {}));
//# sourceMappingURL=OperationalCredentialsServer.js.map
