"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.writeToFile = exports.upScoped = exports.up = exports.generateStarConfigs = exports.generateP2PConfigs = exports.generateHubSpokeConfigs = exports.fromConfigFile = void 0;
var Platform = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/platform"));
var Schema = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("@effect/schema/Schema"));
var Chunk = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Chunk"));
var Effect = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Effect"));
var Function = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Function"));
var HashMap = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/HashMap"));
var Option = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Option"));
var Predicate = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Predicate"));
var ReadonlyArray = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/ReadonlyArray"));
var Sink = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Sink"));
var Stream = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Stream"));
var Tuple = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("effect/Tuple"));
var InternetSchemas = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../InternetSchemas.js"));
var WireguardConfig = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../WireguardConfig.js"));
var WireguardErrors = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../WireguardErrors.js"));
var WireguardInterface = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../WireguardInterface.js"));
var WireguardKey = /*#__PURE__*/_interopRequireWildcard( /*#__PURE__*/require("../WireguardKey.js"));
function _getRequireWildcardCache(e) {
  if ("function" != typeof WeakMap) return null;
  var r = new WeakMap(),
    t = new WeakMap();
  return (_getRequireWildcardCache = function (e) {
    return e ? t : r;
  })(e);
}
function _interopRequireWildcard(e, r) {
  if (!r && e && e.__esModule) return e;
  if (null === e || "object" != typeof e && "function" != typeof e) return {
    default: e
  };
  var t = _getRequireWildcardCache(r);
  if (t && t.has(e)) return t.get(e);
  var n = {
      __proto__: null
    },
    a = Object.defineProperty && Object.getOwnPropertyDescriptor;
  for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) {
    var i = a ? Object.getOwnPropertyDescriptor(e, u) : null;
    i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u];
  }
  return n.default = e, t && t.set(e, n), n;
}
/** @internal */
const fromConfigFile = file => Effect.gen(function* (λ) {
  const fs = yield* λ(Platform.FileSystem.FileSystem);
  const fsConfig = yield* λ(fs.readFileString(file));
  const iniConfigEncoded = yield* λ(Schema.encode(WireguardConfig.WireguardIniConfig)(fsConfig));
  const config = yield* λ(Schema.decode(WireguardConfig.WireguardConfig)(iniConfigEncoded));
  return config;
});
/** @internal */
exports.fromConfigFile = fromConfigFile;
const writeToFile = exports.writeToFile = /*#__PURE__*/Function.dual(2, (file, config) => Effect.gen(function* (λ) {
  const path = yield* λ(Platform.Path.Path);
  const fs = yield* λ(Platform.FileSystem.FileSystem);
  const configEncoded = yield* λ(Schema.encode(WireguardConfig.WireguardConfig)(config));
  const iniConfigDecoded = yield* λ(Schema.decode(WireguardConfig.WireguardIniConfig)(configEncoded));
  yield* λ(fs.makeDirectory(path.dirname(file), {
    recursive: true
  }));
  yield* λ(fs.writeFileString(file, iniConfigDecoded));
}));
/** @internal */
const generateP2PConfigs = options => {
  const hub = options.aliceData;
  const spokes = ReadonlyArray.make(options.bobData);
  const configs = Predicate.isUndefined(options.cidrBlock) ? generateHubSpokeConfigs({
    preshareKeys: "generate",
    trustMap: "trustAllPeers",
    hubData: hub,
    spokeData: spokes
  }) : generateHubSpokeConfigs({
    preshareKeys: "generate",
    trustMap: "trustAllPeers",
    hubData: hub,
    spokeData: spokes,
    cidrBlock: options.cidrBlock,
    addressStartingIndex: options.addressStartingIndex
  });
  return Effect.map(configs, ([aliceConfig, [bobConfig]]) => Tuple.make(aliceConfig, bobConfig));
};
/** @internal */
exports.generateP2PConfigs = generateP2PConfigs;
const generateStarConfigs = options => {
  return Predicate.isUndefined(options.cidrBlock) ? generateHubSpokeConfigs({
    preshareKeys: "generate",
    trustMap: "trustAllPeers",
    hubData: options.hubData,
    spokeData: options.spokeData
  }) : generateHubSpokeConfigs({
    preshareKeys: "generate",
    trustMap: "trustAllPeers",
    cidrBlock: options.cidrBlock,
    addressStartingIndex: options.addressStartingIndex,
    hubData: options.hubData,
    spokeData: options.spokeData
  });
};
/** @internal */
exports.generateStarConfigs = generateStarConfigs;
const generateHubSpokeConfigs = options => Effect.gen(function* (λ) {
  const inputIsSetupData = Array.isArray(options.hubData);
  const ipsNeeded = ReadonlyArray.length(options.spokeData) + 1;
  // Bounds checking on the cidr block
  if (options.cidrBlock && options.cidrBlock.total < ipsNeeded) {
    return yield* λ(new WireguardErrors.WireguardError({
      message: "Not enough IPs in the CIDR block"
    }));
  }
  // Generate some ip addresses to use if the input data was just an endpoint
  const ips = options.cidrBlock?.range ? yield* λ(Function.pipe(options.cidrBlock?.range, Stream.drop(options.addressStartingIndex ?? 0), Stream.mapEffect(Schema.encode(InternetSchemas.Address)), Stream.run(Sink.collectAllN(ipsNeeded)), Effect.map(Chunk.toArray))) : yield* λ(Effect.succeed([]));
  // Convert all inputs to be SetupDataEncoded
  const hubSetupDataEncoded = inputIsSetupData ? options.hubData : Tuple.make(options.hubData, ips.at(0)?.ip ?? "");
  const spokeSetupDataEncoded = inputIsSetupData ? options.spokeData : ReadonlyArray.map(options.spokeData, (spoke, index) => Tuple.make(spoke, ips.at(index + 1)?.ip ?? ""));
  // Decode all SetupData inputs
  const hubSetupData = yield* λ(Schema.decode(InternetSchemas.SetupData)(hubSetupDataEncoded));
  const spokeSetupData = yield* λ(Effect.all(ReadonlyArray.map(spokeSetupDataEncoded, spoke => Schema.decode(InternetSchemas.SetupData)(spoke))));
  const spokeSetupDataBoth = ReadonlyArray.zip(spokeSetupDataEncoded, spokeSetupData);
  // Generate the keys for the hub
  const hubKeys = WireguardKey.generateKeyPair();
  // const hubPreshareKeys =
  //     options.preshareKeys === "generate"
  //         ? WireguardKey.generateKeyPair()
  //         : Predicate.isNotUndefined(options.preshareKeys)
  //           ? HashMap.get(options.preshareKeys, options.hubData).pipe(Option.getOrUndefined)
  //           : undefined;
  // This hub peer config will be added to all the spoke interface configs
  const hubPeerConfig = {
    PublicKey: hubKeys.publicKey,
    Endpoint: Tuple.getFirst(hubSetupDataEncoded),
    AllowedIPs: [`${Tuple.getSecond(hubSetupDataEncoded)}/32`]
  };
  // All these spoke peer configs will be added to the hub interface config
  const spokePeerConfigs = ReadonlyArray.map(spokeSetupDataBoth, ([spokeEncoded, spokeDecoded]) => {
    const keys = WireguardKey.generateKeyPair();
    const preshareKeys = options.preshareKeys === "generate" ? WireguardKey.generateKeyPair() : Predicate.isNotUndefined(options.preshareKeys) ? HashMap.get(options.preshareKeys, spokeDecoded).pipe(Option.getOrUndefined) : undefined;
    return {
      setupDataEncoded: spokeEncoded,
      setupDataDecoded: spokeDecoded,
      keys: {
        privateKey: keys.privateKey,
        privatePreshareKey: preshareKeys?.privateKey
      },
      peerConfig: {
        PublicKey: keys.publicKey,
        Endpoint: Tuple.getFirst(spokeEncoded),
        AllowedIPs: [`${Tuple.getSecond(spokeEncoded)}/32`]
      }
    };
  });
  // The hub interface config will have all the spoke peer configs
  const hubConfig = yield* λ(Schema.decode(WireguardConfig.WireguardConfig)({
    PrivateKey: hubKeys.privateKey,
    ListenPort: Tuple.getFirst(hubSetupData).listenPort,
    Peers: ReadonlyArray.map(spokePeerConfigs, ({
      peerConfig
    }) => peerConfig),
    Address: `${Tuple.getSecond(hubSetupDataEncoded)}/${options.cidrBlock?.mask ?? 24}`
  }));
  // Each spoke interface config will have the hub peer config
  const spokeConfigs = yield* λ(Function.pipe(spokePeerConfigs, ReadonlyArray.map(({
    setupDataDecoded,
    setupDataEncoded,
    keys: {
      privateKey
    }
  }) => Schema.decode(WireguardConfig.WireguardConfig)({
    PrivateKey: privateKey,
    Peers: [hubPeerConfig],
    ListenPort: Tuple.getFirst(setupDataDecoded).listenPort,
    Address: `${Tuple.getSecond(setupDataEncoded)}/${options.cidrBlock?.mask ?? 24}`
  })), Effect.allWith()));
  return Tuple.make(hubConfig, spokeConfigs);
});
/** @internal */
exports.generateHubSpokeConfigs = generateHubSpokeConfigs;
const up = exports.up = /*#__PURE__*/Function.dual(3, (config, options, interfaceObject) => Function.pipe(interfaceObject, Option.fromNullable, Option.map(Effect.succeed), Option.getOrElse(() => WireguardInterface.WireguardInterface.getNextAvailableInterface), Effect.flatMap(io => io.up(config, options))));
/** @internal */
const upScoped = exports.upScoped = /*#__PURE__*/Function.dual(3, (config, options, interfaceObject) => Function.pipe(interfaceObject, Option.fromNullable, Option.map(Effect.succeed), Option.getOrElse(() => WireguardInterface.WireguardInterface.getNextAvailableInterface), Effect.flatMap(io => io.upScoped(config, options))));
//# sourceMappingURL=wireguardConfig.js.map