diff --git a/packages/dappmanager/src/api/auth/errors.ts b/packages/dappmanager/src/api/auth/errors.ts index 400a93b57..18a2742c2 100644 --- a/packages/dappmanager/src/api/auth/errors.ts +++ b/packages/dappmanager/src/api/auth/errors.ts @@ -1,6 +1,5 @@ import { HttpError } from "../utils.js"; -const ERROR_NOT_ADMIN_IP = "NOT_ADMIN_IP"; const ERROR_NOT_REGISTERED = "NOT_REGISTERED"; const ERROR_NOT_LOGGED_IN = "NOT_LOGGED_IN"; const ERROR_NOT_LOGGED_IN_NO_COOKIE = "NOT_LOGGED_IN_NO_COOKIE"; @@ -8,12 +7,6 @@ const ERROR_MISSING_CREDENTIALS = "MISSING_CREDENTIALS"; const ERROR_WRONG_CREDENTIALS = "WRONG_CREDENTIALS"; const ERROR_ALREADY_REGISTERED = "ALREADY_REGISTERED"; -export class NotAdminIpError extends HttpError { - constructor() { - super({ name: ERROR_NOT_ADMIN_IP, statusCode: 401 }); - } -} - export class NotRegisteredError extends HttpError { constructor() { super({ name: ERROR_NOT_REGISTERED, statusCode: 401 }); diff --git a/packages/dappmanager/src/api/middlewares/ethForward/utils/index.ts b/packages/dappmanager/src/api/middlewares/ethForward/utils/index.ts index eb23c52ea..4e33d0dd6 100644 --- a/packages/dappmanager/src/api/middlewares/ethForward/utils/index.ts +++ b/packages/dappmanager/src/api/middlewares/ethForward/utils/index.ts @@ -2,4 +2,3 @@ export * from "./decodeContent.js"; export * from "./decodeContentHash.js"; export * from "./decodeDnsLink.js"; export * from "./isEmpty.js"; -export * from "./sanitizeIpfsPath.js"; diff --git a/packages/dappmanager/src/daemons/natRenewal/defaultPortsToOpen.ts b/packages/dappmanager/src/daemons/natRenewal/defaultPortsToOpen.ts deleted file mode 100644 index 1c46973aa..000000000 --- a/packages/dappmanager/src/daemons/natRenewal/defaultPortsToOpen.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { PackagePort, PortProtocol } from "@dappnode/common"; - -// Default ports to open in case getPortsToOpen throws -const defaultPortsToOpen: PackagePort[] = [ - // - OpenVPN: 1194 UDP - { protocol: PortProtocol.UDP, portNumber: 1194 }, - // - SSH: 22 TCP (Ignore) - // {protocol: 'TCP', portNumber: 22}, - // - Alt HTTP: 8080 TCP - { protocol: PortProtocol.TCP, portNumber: 8090 }, - // - ETH: 30303 TCP, 30303 UDP - { protocol: PortProtocol.TCP, portNumber: 30303 }, - { protocol: PortProtocol.UDP, portNumber: 30303 }, - // - IPFS: 4001 TCP, 4002 UDP - { protocol: PortProtocol.TCP, portNumber: 4001 }, - { protocol: PortProtocol.UDP, portNumber: 4002 } -]; - -export default defaultPortsToOpen; diff --git a/packages/dappmanager/src/utils/chunkify.ts b/packages/dappmanager/src/utils/chunkify.ts deleted file mode 100644 index 85889e755..000000000 --- a/packages/dappmanager/src/utils/chunkify.ts +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Split an inclusive range into a sequence of contiguous inclusive ranges - * ``` - * [[a,b], [c,d] ... Sn] = chunkifyInclusiveRange([a,z], n) - * // where - * [a,z] = [a,b] U [c,d] U ... U Sn - * ``` - * @param from range start inclusive - * @param to range end inclusive - * @param chunks Maximum number of chunks, if range is big enough - */ -export function chunkifyInclusiveRangeBySize( - from: number, - to: number, - maxSize: number -): [number, number][] { - const totalItems = to - from + 1; - const chunkCount = Math.ceil(totalItems / maxSize); - const itemsPerChunk = Math.ceil(totalItems / chunkCount); - - const chunks: [number, number][] = []; - for (let i = 0; i < chunkCount; i++) { - const _from = from + i * itemsPerChunk; - const _to = Math.min(from + (i + 1) * itemsPerChunk - 1, to); - chunks.push([_from, _to]); - if (_to >= to) break; - } - return chunks; -} - -/** - * Split an inclusive range into a sequence of contiguous inclusive ranges - * ``` - * [[a,b], [c,d] ... Sn] = chunkifyInclusiveRange([a,z], n) - * // where - * [a,z] = [a,b] U [c,d] U ... U Sn - * ``` - * @param from range start inclusive - * @param to range end inclusive - * @param chunks Maximum number of chunks, if range is big enough - */ -export function chunkifyInclusiveRangeByCount( - from: number, - to: number, - chunkCount: number -): number[][] { - // Enforce chunkCount >= 1 - if (chunkCount < 1) chunkCount = 1; - - const totalItems = to - from + 1; - const itemsPerChunk = Math.ceil(totalItems / chunkCount); - - const chunks: number[][] = []; - for (let i = 0; i < chunkCount; i++) { - const _from = from + i * itemsPerChunk; - const _to = Math.min(from + (i + 1) * itemsPerChunk - 1, to); - chunks.push([_from, _to]); - if (_to >= to) break; - } - return chunks; -} diff --git a/packages/dappmanager/src/utils/distributedFile.ts b/packages/dappmanager/src/utils/distributedFile.ts deleted file mode 100644 index aa0aaf272..000000000 --- a/packages/dappmanager/src/utils/distributedFile.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { DistributedFile } from "@dappnode/common"; - -/** - * Stringifies a distributed file type into a single multiaddress string - * @param distributedFile - * @returns multiaddress "/ipfs/Qm" - */ -export function fileToMultiaddress(distributedFile?: DistributedFile): string { - if (!distributedFile || !distributedFile.hash) return ""; - - if (distributedFile.source === "ipfs") - return `/ipfs/${normalizeHash(distributedFile.hash)}`; - else return ""; -} - -/** - * Normalizes a hash removing it's prefixes - * - Remove any number of trailing slashes - * - Split by non alphanumeric character and return the last string - * "/ipfs/Qm" => "Qm" - * "ipfs" - * @param hash "/ipfs/Qm" | "ipfs:Qm" | "Qm" - * @returns "Qm" - */ -function normalizeHash(hash: string): string { - return ( - hash - // remove any number of trailing slashes - .replace(/\/+$/, "") - .trim() - // - .split(/[^a-zA-Z\d]/) - .slice(-1)[0] - ); -} diff --git a/packages/dappmanager/src/utils/highestVersion.ts b/packages/dappmanager/src/utils/highestVersion.ts deleted file mode 100644 index 1660f5989..000000000 --- a/packages/dappmanager/src/utils/highestVersion.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { valid, gt } from "semver"; - -export function highestVersion(v1: string, v2: string): string { - // If no version is passed return the other - if (!v1 && v2) return v2; - if (!v2 && v1) return v1; - if (!v1 && !v2) throw Error("Comparing two undefined versions"); - - // If any version is latest return latest - if (v1 == "latest" || v2 == "latest") return "latest"; - - // Compare semantic versions - if (!valid(v1) || !valid(v2)) { - throw new Error( - `Attempting to compare invalid versions, version1: ${v1} version2: ${v2}` - ); - } - if (gt(v1, v2)) { - return v1; - } else { - return v2; - } -} diff --git a/packages/dappmanager/src/utils/logs.ts b/packages/dappmanager/src/utils/logs.ts deleted file mode 100644 index 588067295..000000000 --- a/packages/dappmanager/src/utils/logs.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { applyRecursivelyToStringValues } from "@dappnode/utils"; - -const secretKeyRegex = /(password|passphrase|secret|private)/i; -export const maxLength = 100; - -/** - * Transform the info object - * 1. Any key in kwargs or the result that the name implies that contains - * sensitive data will be replace by ******** - * 2. When sending user settings the kwargs can potentially contain long - * base64 file contents. Trim them off - * 3. Limit the length of objects. - * RPC calls like copyTo may content really big dataUrls as kwargs, - * prevent them from cluttering the userActionLogs file - */ -export const logSafeObjects = applyRecursivelyToStringValues((value, key) => { - // Hide sensitive values - if (secretKeyRegex.test(key)) return "**********"; - - return ( - value - // Trim base64 values - .split(";base64,")[0] - // Limit string size - .slice(0, maxLength) - ); -}); diff --git a/packages/dappmanager/src/utils/promises.ts b/packages/dappmanager/src/utils/promises.ts deleted file mode 100644 index bfd717e43..000000000 --- a/packages/dappmanager/src/utils/promises.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { zipObject, keys, values } from "lodash-es"; - -/** - * Object version of Promise.all(). Resolves all values in an object - * JS version from https://stackoverflow.com/questions/29292921/how-to-use-promise-all-with-an-object-as-input - * @param promisesObj - */ -export async function promiseAllValues< - // eslint-disable-next-line @typescript-eslint/no-explicit-any - T extends { [key: string]: any } ->(promisesObj: { [K in keyof T]: Promise | undefined }): Promise { - const resolvedValues = zipObject( - keys(promisesObj), - await Promise.all(values(promisesObj)) - ); - return resolvedValues as T; -} diff --git a/packages/dappmanager/src/utils/retry.ts b/packages/dappmanager/src/utils/retry.ts deleted file mode 100644 index a50ef817f..000000000 --- a/packages/dappmanager/src/utils/retry.ts +++ /dev/null @@ -1,45 +0,0 @@ -export interface RetryOptions { - /** - * The maximum amount of times to retry the operation. Default is 5 - */ - retries?: number; - /** - * An optional Function that is invoked after the provided callback throws - * It expects a boolean to know if it should retry or not - * Useful to make retrying conditional on the type of error thrown - */ - shouldRetry?: (lastError: Error) => boolean; - /** - * Miliseconds to wait before retrying again - */ - retryDelay?: number; -} - -/** - * Retry a given function on error. - * @param fn Async callback to retry. Invoked with 1 parameter - * A Number identifying the attempt. The absolute first attempt (before any retries) is 1 - * @param opts - */ -export async function retry( - fn: (attempt: number) => A | Promise, - opts?: RetryOptions -): Promise { - const maxRetries = opts?.retries || 5; - const shouldRetry = opts?.shouldRetry; - - let lastError: Error = Error("RetryError"); - for (let i = 1; i <= maxRetries; i++) { - try { - return await fn(i); - } catch (e) { - lastError = e as Error; - if (shouldRetry && !shouldRetry(lastError)) { - break; - } else if (opts?.retryDelay !== undefined) { - await new Promise(r => setTimeout(r, opts?.retryDelay || 0)); - } - } - } - throw lastError; -} diff --git a/packages/dappmanager/src/utils/sanitize.ts b/packages/dappmanager/src/utils/sanitize.ts deleted file mode 100644 index 5b3f3bd7b..000000000 --- a/packages/dappmanager/src/utils/sanitize.ts +++ /dev/null @@ -1,14 +0,0 @@ -const defaultVersion = "*"; - -/** - * Strips a possible version appended to the name - */ -export function sanitizeRequestName(name: string): string { - name = name.split("@")[0]; - return name; -} - -export function sanitizeRequestVersion(version?: string): string { - if (!version) return defaultVersion; - return version; -} diff --git a/packages/dappmanager/src/utils/schema.ts b/packages/dappmanager/src/utils/schema.ts deleted file mode 100644 index 1b5b5a256..000000000 --- a/packages/dappmanager/src/utils/schema.ts +++ /dev/null @@ -1,21 +0,0 @@ -import Ajv from "ajv"; - -const ajv = new Ajv({ allErrors: true }); - -export function getValidator( - schema: { title: string }, - dataName?: string -): (data: T) => T { - const name = dataName || schema.title || "data"; - const validate = ajv.compile(schema); - return (data: T): T => { - if (!validate(data)) { - const { errors } = validate; - throw Error( - `Invalid ${name}:\n` + - ajv.errorsText(errors, { separator: "\n", dataVar: name }) - ); - } - return data; - }; -} diff --git a/packages/dappmanager/src/utils/tarExtractSingleFile.ts b/packages/dappmanager/src/utils/tarExtractSingleFile.ts deleted file mode 100644 index df3703c0d..000000000 --- a/packages/dappmanager/src/utils/tarExtractSingleFile.ts +++ /dev/null @@ -1,47 +0,0 @@ -import tar from "tar-stream"; -import { promisify } from "util"; -import { Writable, pipeline } from "stream"; - -/** - * Extracts a single file from a tar stream and pipes its contents - * to a Writable stream - */ -export async function tarExtractSingleFile( - tarReadableStream: NodeJS.ReadableStream, - fileContentSink: Writable, - targetFile: string -): Promise { - const extract = tar.extract(); - - return new Promise((resolve, reject) => { - let fileFound = false; - - extract.on("entry", async function (header, stream, next) { - if (!fileFound && header.name === targetFile && header.type === "file") { - fileFound = true; - - try { - await promisify(pipeline)(stream, fileContentSink); - } catch (e) { - extract.destroy(); - reject(e); - } finally { - next(); - } - } else { - // just auto drain the stream, to prevent too much backpressure - stream.on("end", () => next()); - stream.resume(); - } - }); - - extract.on("finish", function () { - if (fileFound) resolve(); - else reject(Error(`file ${targetFile} not found in tar`)); - }); - - extract.on("error", e => reject(e)); - - tarReadableStream.pipe(extract); - }); -} diff --git a/packages/dappmanager/src/utils/timeout.ts b/packages/dappmanager/src/utils/timeout.ts deleted file mode 100644 index 774b5d5a8..000000000 --- a/packages/dappmanager/src/utils/timeout.ts +++ /dev/null @@ -1,29 +0,0 @@ -// timestring does not have a @types package -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-ignore -import timestring from "timestring"; - -/** - * Parses a timeout string and returns a number in seconds - * @param timeout "20min", "5", undefined - */ -export function parseTimeoutSeconds( - timeout: number | string | undefined -): number | undefined { - switch (typeof timeout) { - case "number": { - return timeout; - } - case "string": { - if (!timeout) undefined; - // Timestring returns in seconds - const parsedString = timestring(timeout) || parseInt(timeout); - if (!parsedString) throw Error(`Error parsing timeout: ${timeout}`); - return parsedString; - } - case "undefined": - return undefined; - default: - return undefined; - } -} diff --git a/packages/dappmanager/src/utils/validate.ts b/packages/dappmanager/src/utils/validate.ts deleted file mode 100644 index b70ba6227..000000000 --- a/packages/dappmanager/src/utils/validate.ts +++ /dev/null @@ -1,73 +0,0 @@ -import fs from "fs"; -import pathUtil from "path"; -import { valid, validRange } from "semver"; -import * as isIPFS from "is-ipfs"; -import { logs } from "@dappnode/logger"; - -export function isEnsDomain(ensDomain: string): boolean { - const supportedDomains = ["eth"]; - - if (!ensDomain || typeof ensDomain !== "string") return false; - if (ensDomain.includes("/")) return false; - if (!ensDomain.includes(".")) return false; - // "kovan.dnp.dappnode.eth" => "eth" - const domain = ensDomain.split(".").slice(-1)[0] || ""; - if (!supportedDomains.includes(domain)) return false; - // If any negative condition was matched: - return true; -} - -/** - * Checks if the given string is a valid IPFS CID or path - * - * isIPFS.cid('QmYjtig7VJQ6XsnUjqqJvj7QaMcCAwtrgNdahSiFofrE7o') // true (CIDv0) - * isIPFS.cid('zdj7WWeQ43G6JJvLWQWZpyHuAMq6uYWRjkBXFad11vE2LHhQ7') // true (CIDv1) - * isIPFS.cid('noop') // false - * - * @param hash - * @returns - */ -export function isIpfsHash(hash: string): boolean { - if (!hash || typeof hash !== "string") return false; - // Correct hash prefix - - // Remove `ipfs/` or `/ipfs/` prefix - hash = hash.split("ipfs/")[1] || hash; - // Remove trailing and leading slashes - hash = hash.replace(/\/+$/, "").replace(/^\/+/, ""); - // Ignore any subpath after the hash - hash = hash.split("/")[0]; - - // Make sure hash if valid - return isIPFS.cid(hash); -} - -/** - * Must accept regular semvers and "*" - * @param version - */ -export function isSemver(version: string): boolean { - return Boolean(valid(version)); -} - -/** - * Must accept regular semvers and "*" - * @param version - */ -export function isSemverRange(version: string): boolean { - return Boolean(validRange(version)); -} - -export function validatePath(filePath: string): string { - // shell.mkdir('-p', fullPath); - // directory exists - const parentPath = pathUtil.parse(filePath).dir; - if (!fs.existsSync(parentPath)) { - logs.warn(`Parent path doesn't exist, creating it: ${parentPath}`); - fs.mkdirSync(parentPath, { recursive: true }); - } - - // returning so it can be used as - // > await fs.writeFileSync(validate.path(path), data) - return filePath; -}