mirror of
https://github.com/denoland/deno.git
synced 2024-12-11 10:07:54 -05:00
227 lines
5.4 KiB
JavaScript
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 };
|