"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 PaseClient_exports = {};
__export(PaseClient_exports, {
  PaseClient: () => PaseClient
});
module.exports = __toCommonJS(PaseClient_exports);
var import_Mark = require("#common/Mark.js");
var import_general = require("@matter/general");
var import_types = require("@matter/types");
var import_PeerCommunicationError = require("../../peer/PeerCommunicationError.js");
var import_errors = require("../../protocol/errors.js");
var import_PaseMessenger = require("./PaseMessenger.js");
/**
 * @license
 * Copyright 2022-2026 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
const logger = import_general.Logger.get("PaseClient");
const MAX_PASSCODE_GENERATION_ATTEMPTS = 100;
class PaseClient {
  #sessions;
  constructor(sessions) {
    this.#sessions = sessions;
  }
  static async generatePakePasscodeVerifier(crypto, setupPinCode, pbkdfParameters) {
    const { w0, L } = await import_general.Spake2p.computeW0L(crypto, pbkdfParameters, setupPinCode);
    return import_general.Bytes.concat(import_general.Bytes.fromBigInt(w0, 32), L);
  }
  static generateRandomPasscode(crypto) {
    for (let i = 0; i < MAX_PASSCODE_GENERATION_ATTEMPTS; i++) {
      const passcode = crypto.randomUint32 & 134217727;
      if (passcode >= 1 && passcode <= 99999998 && !import_types.CommissioningOptions.FORBIDDEN_PASSCODES.includes(passcode)) {
        return passcode;
      }
    }
    throw new import_general.InternalError(
      `Unable to generate valid passcode in ${MAX_PASSCODE_GENERATION_ATTEMPTS} tries; entropy source is broken`
    );
  }
  static generateRandomDiscriminator(crypto) {
    return crypto.randomUint16 % 4096;
  }
  async pair(initiatorSessionParams, exchange, channel, setupPin, options) {
    const messenger = new import_PaseMessenger.PaseClientMessenger(exchange);
    const abort = new import_general.Abort({ abort: options?.abort });
    try {
      return await this.#doPair(initiatorSessionParams, messenger, exchange, channel, setupPin, abort);
    } catch (error) {
      if (!(0, import_general.causedBy)(error, import_general.NetworkError, import_PeerCommunicationError.TransientPeerCommunicationError, import_errors.RetransmissionLimitReachedError)) {
        try {
          await messenger.sendError(import_types.SecureChannelStatusCode.InvalidParam);
        } catch (e) {
          import_general.MatterError.accept(e);
          logger.debug("Failed to send InvalidParam on PASE error:", e);
        }
      }
      throw error;
    } finally {
      abort.close();
      try {
        await messenger.close();
      } catch (e) {
        logger.error("Unhandled error closing PASE messenger:", e);
      }
    }
  }
  async #doPair(initiatorSessionParams, messenger, exchange, channel, setupPin, abort) {
    const { crypto } = this.#sessions;
    const initiatorRandom = crypto.randomBytes(32);
    const initiatorSessionId = await abort.attempt(this.#sessions.getNextAvailableSessionId());
    const requestPayload = await abort.attempt(
      messenger.sendPbkdfParamRequest(
        {
          initiatorRandom,
          initiatorSessionId,
          passcodeId: import_PaseMessenger.DEFAULT_PASSCODE_ID,
          hasPbkdfParameters: false,
          initiatorSessionParams
        },
        { abort: abort.signal }
      )
    );
    const {
      responsePayload,
      response: { pbkdfParameters, responderSessionId, responderSessionParams }
    } = await messenger.readPbkdfParamResponse({ abort: abort.signal });
    if (pbkdfParameters === void 0) {
      throw new import_general.UnexpectedDataError("Missing requested PbkdfParameters in the response. Commissioning failed.");
    }
    if (responderSessionParams !== void 0) {
      exchange.session.timingParameters = responderSessionParams;
    }
    const peerSessionParameters = {
      ...exchange.session.parameters,
      ...responderSessionParams ?? {}
    };
    const { w0, w1 } = await abort.attempt(import_general.Spake2p.computeW0W1(crypto, pbkdfParameters, setupPin));
    const spake2p = import_general.Spake2p.create(
      crypto,
      await abort.attempt(crypto.computeHash([import_PaseMessenger.SPAKE_CONTEXT, requestPayload, responsePayload])),
      w0
    );
    const X = spake2p.computeX();
    await abort.attempt(messenger.sendPasePake1({ x: X }, { abort: abort.signal }));
    const { y: Y, verifier } = await messenger.readPasePake2({ abort: abort.signal });
    const { Ke, hAY, hBX } = await abort.attempt(spake2p.computeSecretAndVerifiersFromY(w1, X, Y));
    if (!import_general.Bytes.areEqual(verifier, hBX)) {
      throw new import_general.UnexpectedDataError(
        "Received incorrect key confirmation from the receiver. Commissioning failed."
      );
    }
    await messenger.sendPasePake3({ verifier: hAY });
    await messenger.waitForSuccess({ description: "PasePake3-Success" });
    const secureSession = await this.#sessions.createSecureSession({
      channel,
      id: initiatorSessionId,
      fabric: void 0,
      peerNodeId: import_types.NodeId.UNSPECIFIED_NODE_ID,
      peerSessionId: responderSessionId,
      sharedSecret: Ke,
      salt: new Uint8Array(0),
      isInitiator: true,
      isResumption: false,
      peerSessionParameters
    });
    logger.info("Paired successfully", import_Mark.Mark.OUTBOUND, messenger.channelName, exchange.diagnostics);
    return secureSession;
  }
}
//# sourceMappingURL=PaseClient.js.map
