UNPKG

the-wireguard-effect

Version:

Cross platform wireguard api client for nodejs built on wireguard-go with effect-ts

1,076 lines 34.6 kB
/** * Internet schemas for wireguard configuration. * * @since 1.0.0 */ import * as Array from "effect/Array"; import * as Brand from "effect/Brand"; import * as Duration from "effect/Duration"; import * as Effect from "effect/Effect"; import * as Function from "effect/Function"; import * as ParseResult from "effect/ParseResult"; import * as Predicate from "effect/Predicate"; import * as Schema from "effect/Schema"; import * as Stream from "effect/Stream"; import * as String from "effect/String"; import * as Tuple from "effect/Tuple"; import * as net from "node:net"; import * as internal from "./internal/internetSchemas.js"; /** * Transforms a `number` of seconds into a `Duration`. * * @since 1.0.0 * @category Schemas * @example * import * as Duration from "effect/Duration"; * import * as Schema from "effect/Schema"; * import { DurationFromSeconds } from "the-wireguard-effect/InternetSchemas"; * * const decodeDuration = Schema.decodeSync(DurationFromSeconds); * const duration = decodeDuration(11); * assert.strictEqual(Duration.toSeconds(duration), 11); */ export class DurationFromSeconds extends /*#__PURE__*/Schema.transform(Schema.Int, Schema.DurationFromSelf, { decode: Duration.seconds, encode: Duration.toSeconds }).annotations({ identifier: "DurationFromSeconds", description: "A duration from a number of seconds" }) {} /** * Transforms a `string` of seconds into a `Duration`. * * @since 1.0.0 * @category Schemas * @example * import * as Duration from "effect/Duration"; * import * as Schema from "effect/Schema"; * import { DurationFromSecondsString } from "the-wireguard-effect/InternetSchemas"; * * const decodeDurationString = Schema.decodeSync( * DurationFromSecondsString * ); * const duration = decodeDurationString("12"); * assert.strictEqual(Duration.toSeconds(duration), 12); */ export class DurationFromSecondsString extends /*#__PURE__*/Schema.compose(Schema.NumberFromString, DurationFromSeconds).annotations({ identifier: "DurationFromSecondsString", description: "A duration from a string of seconds" }) {} /** * @since 1.0.0 * @category Branded constructors */ export const PortBrand = /*#__PURE__*/Brand.nominal(); /** * An operating system port number. * * @since 1.0.0 * @category Schemas * @example * import * as Schema from "effect/Schema"; * import { Port, PortBrand } from "the-wireguard-effect/InternetSchemas"; * * const port: PortBrand = PortBrand(8080); * assert.strictEqual(port, 8080); * * const decodePort = Schema.decodeSync(Port); * assert.strictEqual(decodePort(8080), 8080); * * assert.throws(() => decodePort(65536)); * assert.doesNotThrow(() => decodePort(8080)); */ export const Port = /*#__PURE__*/Schema.Int.pipe(Schema.between(0, 2 ** 16 - 1)).pipe(Schema.fromBrand(PortBrand)).annotations({ identifier: "Port", title: "An OS port number", description: "An operating system's port number between 0 and 65535 (inclusive)" }); /** * @since 1.0.0 * @category Schemas */ export const IPv4Family = /*#__PURE__*/Schema.Literal("ipv4").annotations({ identifier: "IPv4Family", description: "An ipv4 family" }); /** * @since 1.0.0 * @category Branded constructors */ export const IPv4Brand = /*#__PURE__*/Brand.nominal(); /** * An IPv4 address. * * @since 1.0.0 * @category Schemas * @example * import * as Schema from "effect/Schema"; * import { IPv4 } from "the-wireguard-effect/InternetSchemas"; * * const decodeIPv4 = Schema.decodeSync(IPv4); * assert.deepEqual(decodeIPv4("1.1.1.1"), { * family: "ipv4", * ip: "1.1.1.1", * }); * * assert.throws(() => decodeIPv4("1.1.a.1")); * assert.doesNotThrow(() => decodeIPv4("1.1.1.2")); */ export const IPv4 = /*#__PURE__*/Schema.transform(Function.pipe(Schema.String, Schema.filter(str => net.isIPv4(str))), Schema.Struct({ family: IPv4Family, ip: Schema.String.pipe(Schema.fromBrand(IPv4Brand)) }), { encode: ({ ip }) => ip, decode: ip => ({ ip, family: "ipv4" }) }).annotations({ identifier: "IPv4", title: "An ipv4 address", description: "An ipv4 address in dot-decimal notation with no leading zeros" }); /** * @since 1.0.0 * @category Branded constructors */ export const IPv4BigintBrand = /*#__PURE__*/Brand.nominal(); /** * An IPv4 as a bigint. * * @since 1.0.0 * @category Schemas * @example * import * as Schema from "effect/Schema"; * import { * IPv4Bigint, * IPv4BigintBrand, * } from "the-wireguard-effect/InternetSchemas"; * * const x: IPv4BigintBrand = IPv4BigintBrand(748392749382n); * assert.strictEqual(x, 748392749382n); * * const decodeIPv4Bigint = Schema.decodeSync(IPv4Bigint); * const encodeIPv4Bigint = Schema.encodeSync(IPv4Bigint); * * assert.deepEqual(decodeIPv4Bigint("1.1.1.1"), { * family: "ipv4", * value: 16843009n, * }); * assert.deepEqual(decodeIPv4Bigint("254.254.254.254"), { * family: "ipv4", * value: 4278124286n, * }); * * assert.strictEqual( * encodeIPv4Bigint({ * value: IPv4BigintBrand(16843009n), * family: "ipv4", * }), * "1.1.1.1" * ); * assert.strictEqual( * encodeIPv4Bigint({ * value: IPv4BigintBrand(4278124286n), * family: "ipv4", * }), * "254.254.254.254" * ); */ export const IPv4Bigint = /*#__PURE__*/Schema.transformOrFail(IPv4, Schema.Struct({ family: IPv4Family, value: Schema.BigIntFromSelf.pipe(Schema.fromBrand(IPv4BigintBrand)) }), { encode: ({ value }) => { const padded = value.toString(16).replace(/:/g, "").padStart(8, "0"); const groups = []; for (let i = 0; i < 8; i += 2) { const h = padded.slice(i, i + 2); groups.push(parseInt(h, 16)); } return Schema.decode(IPv4)(groups.join(".")).pipe(Effect.mapError(({ issue }) => issue)); }, decode: ({ ip }) => Function.pipe(ip, String.split("."), Array.map(s => Number.parseInt(s, 10)), Array.map(n => n.toString(16)), Array.map(String.padStart(2, "0")), Array.join(""), hex => BigInt(`0x${hex}`), value => ({ value, family: "ipv4" }), Effect.succeed) }).annotations({ identifier: "IPv4Bigint", description: "An ipv4 address as a bigint" }); /** * @since 1.0.0 * @category Schemas */ export const IPv6Family = /*#__PURE__*/Schema.Literal("ipv6").annotations({ identifier: "IPv6Family", description: "An ipv6 family" }); /** * @since 1.0.0 * @category Branded constructors */ export const IPv6Brand = /*#__PURE__*/Brand.nominal(); /** * An IPv6 address. * * @since 1.0.0 * @category Schemas * @example * import * as Schema from "effect/Schema"; * import { IPv6 } from "the-wireguard-effect/InternetSchemas"; * * const decodeIPv6 = Schema.decodeSync(IPv6); * assert.deepEqual(decodeIPv6("2001:0db8:85a3:0000:0000:8a2e:0370:7334"), { * family: "ipv6", * ip: "2001:0db8:85a3:0000:0000:8a2e:0370:7334", * }); * * assert.throws(() => * decodeIPv6("2001:0db8:85a3:0000:0000:8a2e:0370:7334:") * ); * assert.throws(() => decodeIPv6("2001::85a3::0000::0370:7334")); * assert.doesNotThrow(() => * decodeIPv6("2001:0db8:85a3:0000:0000:8a2e:0370:7334") * ); */ export const IPv6 = /*#__PURE__*/Schema.transform(Function.pipe(Schema.String, Schema.filter(str => net.isIPv6(str))), Schema.Struct({ family: IPv6Family, ip: Schema.String.pipe(Schema.fromBrand(IPv6Brand)) }), { encode: ({ ip }) => ip, decode: ip => ({ ip, family: "ipv6" }) }).annotations({ identifier: "IPv6", description: "An ipv6 address" }); /** * @since 1.0.0 * @category Branded constructors */ export const IPv6BigintBrand = /*#__PURE__*/Brand.nominal(); /** * An IPv6 as a bigint. * * @since 1.0.0 * @category Schemas * @example * import * as Schema from "effect/Schema"; * import { * IPv6Bigint, * IPv6BigintBrand, * } from "the-wireguard-effect/InternetSchemas"; * * const y: IPv6BigintBrand = IPv6BigintBrand(748392749382n); * assert.strictEqual(y, 748392749382n); * * const decodeIPv6Bigint = Schema.decodeSync(IPv6Bigint); * const encodeIPv6Bigint = Schema.encodeSync(IPv6Bigint); * * assert.deepEqual( * decodeIPv6Bigint("4cbd:ff70:e62b:a048:686c:4e7e:a68a:c377"), * { value: 102007852745154114519525620108359287671n, family: "ipv6" } * ); * assert.deepEqual( * decodeIPv6Bigint("d8c6:3feb:46e6:b80c:5a07:6227:ac19:caf6"), * { value: 288142618299897818094313964584331496182n, family: "ipv6" } * ); * * assert.deepEqual( * encodeIPv6Bigint({ * value: IPv6BigintBrand(102007852745154114519525620108359287671n), * family: "ipv6", * }), * "4cbd:ff70:e62b:a048:686c:4e7e:a68a:c377" * ); * assert.deepEqual( * encodeIPv6Bigint({ * value: IPv6BigintBrand(288142618299897818094313964584331496182n), * family: "ipv6", * }), * "d8c6:3feb:46e6:b80c:5a07:6227:ac19:caf6" * ); */ export const IPv6Bigint = /*#__PURE__*/Schema.transformOrFail(IPv6, Schema.Struct({ family: IPv6Family, value: Schema.BigIntFromSelf.pipe(Schema.fromBrand(IPv6BigintBrand)) }), { encode: ({ value }) => { const hex = value.toString(16).padStart(32, "0"); const groups = []; for (let i = 0; i < 8; i++) { groups.push(hex.slice(i * 4, (i + 1) * 4)); } return Schema.decode(IPv6)(groups.join(":")).pipe(Effect.mapError(({ issue }) => issue)); }, decode: ({ ip }) => { function paddedHex(octet) { return parseInt(octet, 16).toString(16).padStart(4, "0"); } let groups = []; const halves = ip.split("::"); // if (halves.length === 2) { if (Tuple.isTupleOf(2)(halves)) { let first = halves[0].split(":"); let last = halves[1].split(":"); if (first.length === 1 && first[0] === "") { first = []; } if (last.length === 1 && last[0] === "") { last = []; } const remaining = 8 - (first.length + last.length); if (!remaining) { throw new Error("Error parsing groups"); } groups = groups.concat(first); for (let i = 0; i < remaining; i++) { groups.push("0"); } groups = groups.concat(last); } else if (halves.length === 1) { groups = ip.split(":"); } else { throw new Error("Too many :: groups found"); } groups = groups.map(group => parseInt(group, 16).toString(16)); if (groups.length !== 8) { throw new Error("Invalid number of groups"); } return Effect.succeed({ value: BigInt(`0x${groups.map(paddedHex).join("")}`), family: "ipv6" }); } }).annotations({ identifier: "IPv6Bigint", description: "An ipv6 address as a bigint" }); /** * @since 1.0.0 * @category Schemas * @see {@link IPv4Family} * @see {@link IPv6Family} */ export const Family = /*#__PURE__*/Schema.Union(IPv4Family, IPv6Family).annotations({ identifier: "Family", description: "An ipv4 or ipv6 family" }); /** * An IP address, which is either an IPv4 or IPv6 address. * * @since 1.0.0 * @category Schemas * @example * import * as Schema from "effect/Schema"; * import { Address } from "the-wireguard-effect/InternetSchemas"; * * const decodeAddress = Schema.decodeSync(Address); * * assert.throws(() => decodeAddress("1.1.b.1")); * assert.throws(() => * decodeAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334:") * ); * * assert.doesNotThrow(() => decodeAddress("1.1.1.2")); * assert.doesNotThrow(() => * decodeAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334") * ); * * @see {@link IPv4} * @see {@link IPv6} */ export const Address = /*#__PURE__*/Schema.Union(IPv4, IPv6).annotations({ identifier: "Address", description: "An ipv4 or ipv6 address" }); /** * An IP address as a bigint. * * @since 1.0.0 * @category Schemas */ export const AddressBigint = /*#__PURE__*/Schema.Union(IPv4Bigint, IPv6Bigint).annotations({ identifier: "AddressBigint", description: "An ipv4 or ipv6 address as a bigint" }); /** * @since 1.0.0 * @category Branded constructors */ export const IPv4CidrMaskBrand = /*#__PURE__*/Brand.nominal(); /** * An ipv4 cidr mask, which is a number between 0 and 32. * * @since 1.0.0 * @category Schemas * @example * import * as Schema from "effect/Schema"; * import { * IPv4CidrMask, * IPv4CidrMaskBrand, * } from "the-wireguard-effect/InternetSchemas"; * * const mask: IPv4CidrMaskBrand = IPv4CidrMaskBrand(24); * assert.strictEqual(mask, 24); * * const decodeMask = Schema.decodeSync(IPv4CidrMask); * assert.strictEqual(decodeMask(24), 24); * * assert.throws(() => decodeMask(33)); * assert.doesNotThrow(() => decodeMask(0)); * assert.doesNotThrow(() => decodeMask(32)); */ export const IPv4CidrMask = /*#__PURE__*/Schema.Int.pipe(Schema.between(0, 32)).pipe(Schema.fromBrand(IPv4CidrMaskBrand)).annotations({ identifier: "IPv4CidrMask", description: "An ipv4 cidr mask" }); /** * @since 1.0.0 * @category Branded constructors */ export const IPv6CidrMaskBrand = /*#__PURE__*/Brand.nominal(); /** * An ipv6 cidr mask, which is a number between 0 and 128. * * @since 1.0.0 * @category Schemas * @example * import * as Schema from "effect/Schema"; * import { * IPv6CidrMask, * IPv6CidrMaskBrand, * } from "the-wireguard-effect/InternetSchemas"; * * const mask: IPv6CidrMaskBrand = IPv6CidrMaskBrand(64); * assert.strictEqual(mask, 64); * * const decodeMask = Schema.decodeSync(IPv6CidrMask); * assert.strictEqual(decodeMask(64), 64); * * assert.throws(() => decodeMask(129)); * assert.doesNotThrow(() => decodeMask(0)); * assert.doesNotThrow(() => decodeMask(128)); */ export const IPv6CidrMask = /*#__PURE__*/Schema.Int.pipe(Schema.between(0, 128)).pipe(Schema.fromBrand(IPv6CidrMaskBrand)).annotations({ identifier: "IPv6CidrMask", description: "An ipv6 cidr mask" }); /** * @since 1.0.0 * @category Api interface */ export class CidrBlockBase extends /*#__PURE__*/Schema.Class("CidrBlockMixin")({ address: Address, mask: /*#__PURE__*/Schema.Union(IPv4CidrMask, IPv6CidrMask) }) { /** @since 1.0.0 */ family = this.address.family; /** @internal */ onFamily({ onIPv4, onIPv6 }) { const isIPv4 = () => this.family === "ipv4"; const isIPv6 = () => this.family === "ipv6"; if (isIPv4()) { return onIPv4(this); } else if (isIPv6()) { return onIPv6(this); } else { return Function.absurd(this.family); } } /** * The first address in the range given by this address' subnet, often * referred to as the Network Address. * * @since 1.0.0 */ get networkAddressAsBigint() { return Effect.gen(this, function* () { const bits = this.family === "ipv4" ? 32 : 128; const bigIntegerAddress = yield* this.onFamily({ onIPv4: self => Schema.decode(IPv4Bigint)(self.address.ip), onIPv6: self => Schema.decode(IPv6Bigint)(self.address.ip) }); const intermediate = bigIntegerAddress.value.toString(2).padStart(bits, "0").slice(0, this.mask); const networkAddressString = intermediate + "0".repeat(bits - this.mask); const networkAddressBigInt = BigInt(`0b${networkAddressString}`); return this.onFamily({ onIPv4: _self => IPv4BigintBrand(networkAddressBigInt), onIPv6: _self => IPv6BigintBrand(networkAddressBigInt) }); }); } /** * The first address in the range given by this address' subnet, often * referred to as the Network Address. * * @since 1.0.0 */ networkAddress() { return this.onFamily({ onIPv4: self => Function.pipe(self.networkAddressAsBigint, Effect.flatMap(value => Schema.encode(IPv4Bigint)({ value, family: "ipv4" })), Effect.flatMap(Schema.decode(IPv4))), onIPv6: self => Function.pipe(self.networkAddressAsBigint, Effect.flatMap(value => Schema.encode(IPv6Bigint)({ value, family: "ipv6" })), Effect.flatMap(Schema.decode(IPv6))) }); } /** * The last address in the range given by this address' subnet, often * referred to as the Broadcast Address. * * @since 1.0.0 */ get broadcastAddressAsBigint() { return Effect.gen(this, function* () { const bits = this.family === "ipv4" ? 32 : 128; const bigIntegerAddress = yield* this.onFamily({ onIPv4: self => Schema.decode(IPv4Bigint)(self.address.ip), onIPv6: self => Schema.decode(IPv6Bigint)(self.address.ip) }); const intermediate = bigIntegerAddress.value.toString(2).padStart(bits, "0").slice(0, this.mask); const broadcastAddressString = intermediate + "1".repeat(bits - this.mask); const broadcastAddressBigInt = BigInt(`0b${broadcastAddressString}`); return this.onFamily({ onIPv4: _self => IPv4BigintBrand(broadcastAddressBigInt), onIPv6: _self => IPv6BigintBrand(broadcastAddressBigInt) }); }); } /** * The last address in the range given by this address' subnet, often * referred to as the Broadcast Address. * * @since 1.0.0 */ broadcastAddress() { return this.onFamily({ onIPv4: self => Function.pipe(self.broadcastAddressAsBigint, Effect.flatMap(value => Schema.encode(IPv4Bigint)({ value, family: "ipv4" })), Effect.flatMap(Schema.decode(IPv4))), onIPv6: self => Function.pipe(self.broadcastAddressAsBigint, Effect.flatMap(value => Schema.encode(IPv6Bigint)({ value, family: "ipv6" })), Effect.flatMap(Schema.decode(IPv6))) }); } /** * A stream of all addresses in the range given by this address' subnet. * * @since 1.0.0 */ get range() { return this.onFamily({ onIPv4: self => Effect.gen(function* () { const minValue = yield* self.networkAddressAsBigint; const maxValue = yield* self.broadcastAddressAsBigint; return Function.pipe(Stream.iterate(minValue, x => IPv4BigintBrand(x + 1n)), Stream.takeWhile(n => n <= maxValue), Stream.flatMap(value => Schema.encode(IPv4Bigint)({ value, family: "ipv4" })), Stream.mapEffect(Schema.decode(IPv4))); }).pipe(Stream.unwrap), onIPv6: self => Effect.gen(function* () { const minValue = yield* self.networkAddressAsBigint; const maxValue = yield* self.broadcastAddressAsBigint; return Function.pipe(Stream.iterate(minValue, x => IPv6BigintBrand(x + 1n)), Stream.takeWhile(n => n <= maxValue), Stream.flatMap(value => Schema.encode(IPv6Bigint)({ value, family: "ipv6" })), Stream.mapEffect(Schema.decode(IPv6))); }).pipe(Stream.unwrap) }); } /** * The total number of addresses in the range given by this address' subnet. * * @since 1.0.0 */ get total() { return Effect.gen(this, function* () { const minValue = yield* this.networkAddressAsBigint; const maxValue = yield* this.broadcastAddressAsBigint; return maxValue - minValue + 1n; }); } /** * Finds the smallest CIDR block that contains all the given IP addresses. * * @since 1.0.0 */ static cidrBlockForRange = inputs => Effect.gen(function* () { const bigIntMinAndMax = args => { return args.reduce(([min, max], e) => { return [e < min ? e : min, e > max ? e : max]; }, [args[0], args[0]]); }; const bigints = yield* Function.pipe(inputs, Array.map(address => address.family === "ipv4" ? Schema.decode(IPv4Bigint)(address.ip) : Schema.decode(IPv6Bigint)(address.ip)), Array.map(x => x), Array.map(Effect.map(({ value }) => value)), Effect.all); const bits = inputs[0].family === "ipv4" ? 32 : 128; const [min, max] = bigIntMinAndMax(bigints); const leadingZerosInMin = bits - min.toString(2).length; const leadingZerosInMax = bits - max.toString(2).length; const cidrMask = Math.min(leadingZerosInMin, leadingZerosInMax); const cidrAddress = inputs[0].family === "ipv4" ? yield* Schema.encode(IPv4Bigint)({ value: IPv4BigintBrand(min), family: "ipv4" }) : yield* Schema.encode(IPv6Bigint)({ value: IPv6BigintBrand(min), family: "ipv6" }); return yield* Schema.decode(CidrBlockFromString)(`${cidrAddress}/${cidrMask}`); }); } /** * @since 1.0.0 * @category Schemas */ export const IPv4CidrBlock = /*#__PURE__*/Schema.transformOrFail(Schema.Struct({ address: IPv4, mask: IPv4CidrMask }), CidrBlockBase, { encode: data => Effect.gen(function* () { const address = yield* Schema.decode(IPv4)(data.address); const mask = yield* Schema.decode(IPv4CidrMask)(data.mask); return { address, mask }; }).pipe(Effect.mapError(({ issue }) => issue)), decode: data => ParseResult.succeed({ address: data.address.ip, mask: data.mask }) }).annotations({ identifier: "IPv4CidrBlock", description: "An ipv4 cidr block" }); /** * A schema that transforms a `string` into a `CidrBlock`. * * @since 1.0.0 * @category Schemas */ export const IPv4CidrBlockFromString = /*#__PURE__*/Schema.transform(Schema.TemplateLiteral(Schema.String, Schema.Literal("/"), Schema.Number), IPv4CidrBlock, { decode: str => { const [address, mask] = internal.splitLiteral(str, "/"); return { address, mask: Number.parseInt(mask, 10) }; }, encode: ({ address, mask }) => `${address}/${mask}` }).annotations({ identifier: "IPv4CidrBlockFromString", description: "An ipv4 cidr block from string" }); /** * @since 1.0.0 * @category Schemas */ export const IPv6CidrBlock = /*#__PURE__*/Schema.transformOrFail(Schema.Struct({ address: IPv6, mask: IPv6CidrMask }), CidrBlockBase, { encode: data => Effect.gen(function* () { const address = yield* Schema.decode(IPv6)(data.address); const mask = yield* Schema.decode(IPv6CidrMask)(data.mask); return { address, mask }; }).pipe(Effect.mapError(({ issue }) => issue)), decode: data => ParseResult.succeed({ address: data.address.ip, mask: data.mask }) }).annotations({ identifier: "IPv6CidrBlock", description: "An ipv6 cidr block" }); /** * A schema that transforms a `string` into a `CidrBlock`. * * @since 1.0.0 * @category Schemas */ export const IPv6CidrBlockFromString = /*#__PURE__*/Schema.transform(Schema.TemplateLiteral(Schema.String, Schema.Literal("/"), Schema.Number), IPv6CidrBlock, { decode: str => { const [address, mask] = internal.splitLiteral(str, "/"); return { address, mask: Number.parseInt(mask, 10) }; }, encode: ({ address, mask }) => `${address}/${mask}` }).annotations({ identifier: "IPv6CidrBlockFromString", description: "An ipv6 cidr block from string" }); /** * @since 1.0.0 * @category Schemas */ export const CidrBlock = /*#__PURE__*/Schema.Union(IPv4CidrBlock, IPv6CidrBlock); /** * A schema that transforms a `string` into a `CidrBlock`. * * @since 1.0.0 * @category Schemas */ export const CidrBlockFromString = /*#__PURE__*/Schema.transform(Schema.TemplateLiteral(Schema.String, Schema.Literal("/"), Schema.Number), CidrBlock, { decode: str => { const [address, mask] = internal.splitLiteral(str, "/"); return { address, mask: Number.parseInt(mask, 10) }; }, encode: ({ address, mask }) => `${address}/${mask}` }).annotations({ identifier: "CidrBlockFromString", description: "A cidr block" }); /** * An IPv4 wireguard endpoint, which consists of an IPv4 address followed by a * nat port then an optional local port. If only one port is provided, it is * assumed that the nat port and listen port are the same. * * @since 1.0.0 * @category Schemas * @example * import * as Schema from "effect/Schema"; * import { IPv4Endpoint } from "the-wireguard-effect/InternetSchemas"; * * const decodeEndpoint = Schema.decodeSync(IPv4Endpoint); * const endpoint1 = decodeEndpoint("1.2.3.4:51820"); * const endpoint2 = decodeEndpoint("1.2.3.4:51820:41820"); * * const endpoint3 = decodeEndpoint({ * ip: "1.2.3.4", * port: 51820, * family: "ipv4", * }); * * const endpoint4 = decodeEndpoint({ * ip: "1.2.3.4", * natPort: 51820, * listenPort: 41820, * family: "ipv4", * }); */ export const IPv4Endpoint = /*#__PURE__*/Schema.transform(Schema.Union(Schema.Struct({ ip: Schema.String, port: Schema.Number, family: IPv4Family }), Schema.Struct({ ip: Schema.String, natPort: Schema.Number, listenPort: Schema.Number, family: IPv4Family }), Schema.TemplateLiteral(Schema.String, Schema.Literal(":"), Schema.Number), Schema.TemplateLiteral(Schema.String, Schema.Literal(":"), Schema.Number, Schema.Literal(":"), Schema.Number)), Schema.Struct({ address: IPv4, natPort: Port, listenPort: Port }), { decode: data => { const isObjectInput = !Predicate.isString(data); const [ip, natPort, listenPort] = isObjectInput ? [data.ip, "natPort" in data ? `${data.natPort}` : `${data.port}`, "listenPort" in data ? `${data.listenPort}` : undefined] : internal.splitLiteral(data, ":"); const natPortParsed = Number.parseInt(natPort, 10); const listenPortParsed = Predicate.isNotUndefined(listenPort) ? Number.parseInt(listenPort, 10) : natPortParsed; return { address: ip, natPort: natPortParsed, listenPort: listenPortParsed }; }, encode: ({ address, listenPort, natPort }) => `${address}:${natPort}:${listenPort}` }).annotations({ identifier: "IPv4Endpoint", description: "An ipv4 wireguard endpoint" }); /** * An IPv6 wireguard endpoint, which consists of an IPv6 address in square * brackets followed by a nat port then an optional local port. If only one port * is provided, it is assumed that the nat port and listen port are the same. * * @since 1.0.0 * @category Schemas * @example * import * as Schema from "effect/Schema"; * import { IPv6Endpoint } from "the-wireguard-effect/InternetSchemas"; * * const decodeEndpoint = Schema.decodeSync(IPv6Endpoint); * const endpoint1 = decodeEndpoint( * "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:51820" * ); * const endpoint2 = decodeEndpoint( * "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:51820:41820" * ); * * const endpoint3 = decodeEndpoint({ * ip: "2001:0db8:85a3:0000:0000:8a2e:0370:7334", * port: 51820, * family: "ipv6", * }); * * const endpoint4 = decodeEndpoint({ * ip: "2001:0db8:85a3:0000:0000:8a2e:0370:7334", * natPort: 51820, * listenPort: 41820, * family: "ipv6", * }); */ export const IPv6Endpoint = /*#__PURE__*/Schema.transform(Schema.Union(Schema.Struct({ ip: Schema.String, port: Schema.Number, family: IPv6Family }), Schema.Struct({ ip: Schema.String, natPort: Schema.Number, listenPort: Schema.Number, family: IPv6Family }), Schema.TemplateLiteral(Schema.Literal("["), Schema.String, Schema.Literal("]"), Schema.Literal(":"), Schema.Number), Schema.TemplateLiteral(Schema.Literal("["), Schema.String, Schema.Literal("]"), Schema.Literal(":"), Schema.Number, Schema.Literal(":"), Schema.Number)), Schema.Struct({ address: IPv6, natPort: Port, listenPort: Port }), { decode: data => { const isObjectInput = !Predicate.isString(data); const [ip, natPort, listenPort] = isObjectInput ? [data.ip, "natPort" in data ? `${data.natPort}` : `${data.port}`, "listenPort" in data ? `${data.listenPort}` : undefined] : [internal.splitLiteral(data, "]")[0].slice(1), ...internal.tail(internal.splitLiteral(internal.splitLiteral(data, "]")[1], ":"))]; const natPortParsed = Number.parseInt(natPort, 10); const listenPortParsed = Predicate.isNotUndefined(listenPort) ? Number.parseInt(listenPort, 10) : natPortParsed; return { address: ip.slice(1), natPort: natPortParsed, listenPort: listenPortParsed }; }, encode: ({ address, listenPort, natPort }) => `[${address}]:${natPort}:${listenPort}` }).annotations({ identifier: "IPv6Endpoint", description: "An ipv6 wireguard endpoint" }); /** * A hostname wireguard endpoint, which consists of a hostname followed by a\ * Nat port then an optional local port. If only one port is provided, it is * assumed that the nat port and listen port are the same. * * @since 1.0.0 * @category Schemas */ export const HostnameEndpoint = /*#__PURE__*/Schema.transform(Schema.Union(Schema.Struct({ host: Schema.String, port: Schema.Number }), Schema.Struct({ host: Schema.String, natPort: Schema.Number, listenPort: Schema.Number }), Schema.TemplateLiteral(Schema.String, Schema.Literal(":"), Schema.Number), Schema.TemplateLiteral(Schema.String, Schema.Literal(":"), Schema.Number, Schema.Literal(":"), Schema.Number)), Schema.Struct({ host: Schema.String, natPort: Port, listenPort: Port }), { decode: data => { const isObjectInput = !Predicate.isString(data); const [host, natPort, listenPort] = isObjectInput ? [data.host, "natPort" in data ? `${data.natPort}` : `${data.port}`, "listenPort" in data ? `${data.listenPort}` : undefined] : internal.splitLiteral(data, ":"); const natPortParsed = Number.parseInt(natPort, 10); const listenPortParsed = Predicate.isNotUndefined(listenPort) ? Number.parseInt(listenPort, 10) : natPortParsed; return { host, natPort: natPortParsed, listenPort: listenPortParsed }; }, encode: ({ host, listenPort, natPort }) => `${host}:${natPort}:${listenPort}` }).annotations({ identifier: "HostnameEndpoint", description: "A hostname endpoint" }); /** * A wireguard endpoint, which is either an IPv4 or IPv6 endpoint. * * @since 1.0.0 * @category Schemas * @example * import * as Schema from "effect/Schema"; * * import { Endpoint } from "the-wireguard-effect/InternetSchemas"; * * const decodeEndpoint = Schema.decodeSync(Endpoint); * const endpoint1 = decodeEndpoint("1.2.3.4:51820"); * const endpoint2 = decodeEndpoint("1.2.3.4:51820:41820"); * * const endpoint3 = decodeEndpoint({ * ip: "1.2.3.4", * port: 51820, * family: "ipv4", * }); * * const endpoint4: Endpoint = decodeEndpoint({ * ip: "1.2.3.4", * natPort: 51820, * listenPort: 41820, * family: "ipv4", * }); * * const endpoint5 = decodeEndpoint( * "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:51820" * ); * const endpoint6 = decodeEndpoint( * "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:51820:41820" * ); * * const endpoint7 = decodeEndpoint({ * ip: "2001:0db8:85a3:0000:0000:8a2e:0370:7334", * port: 51820, * family: "ipv6", * }); * * const endpoint8: Endpoint = decodeEndpoint({ * ip: "2001:0db8:85a3:0000:0000:8a2e:0370:7334", * natPort: 51820, * listenPort: 41820, * family: "ipv6", * }); * * @see {@link IPv4Endpoint} * @see {@link IPv6Endpoint} * @see {@link HostnameEndpoint} */ export const Endpoint = /*#__PURE__*/Schema.Union(IPv4Endpoint, IPv6Endpoint, HostnameEndpoint).annotations({ identifier: "Endpoint", description: "An ipv4, ipv6, or hostname wireguard endpoint" }); /** * A wireguard setup data, which consists of an endpoint followed by an address. * * @since 1.0.0 * @category Schemas * @example * import * as Schema from "effect/Schema"; * import { SetupData } from "the-wireguard-effect/InternetSchemas"; * * const decodeSetupData = Schema.decodeSync(SetupData); * const setupData = decodeSetupData(["1.1.1.1:51280", "10.0.0.1"]); * * @see {@link IPv4} * @see {@link IPv4EndpointSchema} */ export const IPv4SetupData = /*#__PURE__*/Schema.Tuple(IPv4Endpoint, IPv4).annotations({ identifier: "SetupData", description: "A wireguard setup data" }); /** * A wireguard setup data, which consists of an endpoint followed by an address. * * @since 1.0.0 * @category Schemas * @example * import * as Schema from "effect/Schema"; * import { SetupData } from "the-wireguard-effect/InternetSchemas"; * * const decodeSetupData = Schema.decodeSync(SetupData); * const setupData = decodeSetupData(["1.1.1.1:51280", "10.0.0.1"]); * * @see {@link IPv6} * @see {@link IPv6EndpointSchema} */ export const IPv6SetupData = /*#__PURE__*/Schema.Tuple(IPv6Endpoint, IPv6).annotations({ identifier: "SetupData", description: "A wireguard setup data" }); /** * A wireguard setup data, which consists of an endpoint followed by an address. * * @since 1.0.0 * @category Schemas * @see {@link IPv4} * @see {@link HostnameEndpoint} */ export const HostnameIPv4SetupData = /*#__PURE__*/Schema.Tuple(HostnameEndpoint, IPv4).annotations({ identifier: "HostnameIPv4SetupData", description: "A wireguard hostname+ipv4 setup data" }); /** * A wireguard setup data, which consists of an endpoint followed by an address. * * @since 1.0.0 * @category Schemas * @see {@link IPv6} * @see {@link HostnameEndpoint} */ export const HostnameIPv6SetupData = /*#__PURE__*/Schema.Tuple(HostnameEndpoint, IPv6).annotations({ identifier: "HostnameIPv6SetupData", description: "A wireguard hostname+ipv6 setup data" }); /** * A wireguard setup data, which consists of an endpoint followed by an address. * * @since 1.0.0 * @category Schemas * @example * import * as Schema from "effect/Schema"; * import { SetupData } from "the-wireguard-effect/InternetSchemas"; * * const decodeSetupData = Schema.decodeSync(SetupData); * const setupData = decodeSetupData(["1.1.1.1:51280", "10.0.0.1"]); * * @see {@link Address} * @see {@link Endpoint} */ export const SetupData = /*#__PURE__*/Schema.Union(IPv4SetupData, IPv6SetupData, HostnameIPv4SetupData, HostnameIPv6SetupData).annotations({ identifier: "SetupData", description: "A wireguard setup data" }); //# sourceMappingURL=InternetSchemas.js.map