1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-29 16:30:56 -05:00
denoland-deno/ext/node/polyfills/internal/blocklist.mjs

227 lines
5.4 KiB
JavaScript

// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
import { primordials } from "ext:core/mod.js";
import {
op_blocklist_add_address,
op_blocklist_add_range,
op_blocklist_add_subnet,
op_blocklist_check,
op_blocklist_new,
op_socket_address_get_serialization,
op_socket_address_parse,
} from "ext:core/ops";
import {
validateInt32,
validateObject,
validatePort,
validateString,
validateUint32,
} from "ext:deno_node/internal/validators.mjs";
import { ERR_INVALID_ARG_VALUE } from "ext:deno_node/internal/errors.ts";
import { customInspectSymbol } from "ext:deno_node/internal/util.mjs";
import { inspect } from "ext:deno_node/internal/util/inspect.mjs";
const { Symbol } = primordials;
const internalBlockList = Symbol("blocklist");
class BlockList {
constructor() {
this[internalBlockList] = op_blocklist_new();
}
[customInspectSymbol](depth, options) {
if (depth < 0) {
return this;
}
const opts = {
...options,
depth: options.depth == null ? null : options.depth - 1,
};
return `BlockList ${
inspect({
rules: [], // TODO(satyarohith): provide the actual rules
}, opts)
}`;
}
addAddress(address, family = "ipv4") {
if (!SocketAddress.isSocketAddress(address)) {
validateString(address, "address");
validateString(family, "family");
new SocketAddress({
address,
family,
});
} else {
address = address.address;
}
op_blocklist_add_address(this[internalBlockList], address);
}
addRange(start, end, family = "ipv4") {
if (!SocketAddress.isSocketAddress(start)) {
validateString(start, "start");
validateString(family, "family");
new SocketAddress({
address: start,
family,
});
} else {
start = start.address;
}
if (!SocketAddress.isSocketAddress(end)) {
validateString(end, "end");
validateString(family, "family");
new SocketAddress({
address: end,
family,
});
} else {
end = end.address;
}
const ret = op_blocklist_add_range(this[internalBlockList], start, end);
if (ret === false) {
throw new ERR_INVALID_ARG_VALUE("start", start, "must come before end");
}
}
addSubnet(network, prefix, family = "ipv4") {
if (!SocketAddress.isSocketAddress(network)) {
validateString(network, "network");
validateString(family, "family");
new SocketAddress({
address: network,
family,
});
} else {
network = network.address;
family = network.family;
}
switch (family) {
case "ipv4":
validateInt32(prefix, "prefix", 0, 32);
break;
case "ipv6":
validateInt32(prefix, "prefix", 0, 128);
break;
}
op_blocklist_add_subnet(this[internalBlockList], network, prefix);
}
check(address, family = "ipv4") {
if (!SocketAddress.isSocketAddress(address)) {
validateString(address, "address");
validateString(family, "family");
try {
new SocketAddress({
address,
family,
});
} catch {
// Ignore the error. If it's not a valid address, return false.
return false;
}
} else {
family = address.family;
address = address.address;
}
try {
return op_blocklist_check(this[internalBlockList], address, family);
} catch (_) {
// Node API expects false as return value if the address is invalid.
// Example: `blocklist.check("1.1.1.1", "ipv6")` should return false.
return false;
}
}
get rules() {
// TODO(satyarohith): return the actual rules
return [];
}
}
const kDetail = Symbol("kDetail");
class SocketAddress {
static isSocketAddress(value) {
return value?.[kDetail] !== undefined;
}
constructor(options = kEmptyObject) {
validateObject(options, "options");
let { family = "ipv4" } = options;
const {
address = (family === "ipv4" ? "127.0.0.1" : "::"),
port = 0,
flowlabel = 0,
} = options;
if (typeof family?.toLowerCase === "function") {
// deno-lint-ignore prefer-primordials
family = family.toLowerCase();
}
switch (family) {
case "ipv4":
break;
case "ipv6":
break;
default:
throw new ERR_INVALID_ARG_VALUE("options.family", options.family);
}
validateString(address, "options.address");
validatePort(port, "options.port");
validateUint32(flowlabel, "options.flowlabel", false);
this[kDetail] = {
address,
port,
family,
flowlabel,
};
const useInput = op_socket_address_parse(
address,
port,
family,
);
if (!useInput) {
const { 0: address_, 1: family_ } = op_socket_address_get_serialization();
this[kDetail].address = address_;
this[kDetail].family = family_;
}
}
get address() {
return this[kDetail].address;
}
get port() {
return this[kDetail].port;
}
get family() {
return this[kDetail].family;
}
get flowlabel() {
// TODO(satyarohith): Implement this in Rust.
// The flow label can be changed internally.
return this[kDetail].flowlabel;
}
toJSON() {
return {
address: this.address,
port: this.port,
family: this.family,
flowlabel: this.flowlabel,
};
}
}
export { BlockList, SocketAddress };