UNPKG

@worker-tools/deno-kv-storage

Version:

An implementation of the StorageArea (1,2,3) interface for Deno with an extensible system for supporting various database backends.

220 lines 8.73 kB
import { parseConnectionUri } from "../utils/utils.js"; import { ConnectionParamsError } from "../client/error.js"; import { fromFileUrl, isAbsolute } from "../deps.js"; /** * This function retrieves the connection options from the environmental variables * as they are, without any extra parsing * * It will throw if no env permission was provided on startup */ function getPgEnv() { return { database: Deno.env.get("PGDATABASE"), hostname: Deno.env.get("PGHOST"), port: Deno.env.get("PGPORT"), user: Deno.env.get("PGUSER"), password: Deno.env.get("PGPASSWORD"), applicationName: Deno.env.get("PGAPPNAME"), }; } function formatMissingParams(missingParams) { return `Missing connection parameters: ${missingParams.join(", ")}`; } /** * This validates the options passed are defined and have a value other than null * or empty string, it throws a connection error otherwise * * @param has_env_access This parameter will change the error message if set to true, * telling the user to pass env permissions in order to read environmental variables */ function assertRequiredOptions(options, requiredKeys, has_env_access) { const missingParams = []; for (const key of requiredKeys) { if (options[key] === "" || options[key] === null || options[key] === undefined) { missingParams.push(key); } } if (missingParams.length) { let missing_params_message = formatMissingParams(missingParams); if (!has_env_access) { missing_params_message += "\nConnection parameters can be read from environment variables only if Deno is run with env permission"; } throw new ConnectionParamsError(missing_params_message); } } function parseOptionsFromUri(connString) { let postgres_uri; try { const uri = parseConnectionUri(connString); postgres_uri = { application_name: uri.params.application_name, dbname: uri.path || uri.params.dbname, driver: uri.driver, host: uri.host || uri.params.host, password: uri.password || uri.params.password, port: uri.port || uri.params.port, // Compatibility with JDBC, not standard // Treat as sslmode=require sslmode: uri.params.ssl === "true" ? "require" : uri.params.sslmode, user: uri.user || uri.params.user, }; } catch (e) { // TODO // Use error cause throw new ConnectionParamsError(`Could not parse the connection string due to ${e}`); } if (!["postgres", "postgresql"].includes(postgres_uri.driver)) { throw new ConnectionParamsError(`Supplied DSN has invalid driver: ${postgres_uri.driver}.`); } // No host by default means socket connection const host_type = postgres_uri.host ? (isAbsolute(postgres_uri.host) ? "socket" : "tcp") : "socket"; let tls; switch (postgres_uri.sslmode) { case undefined: { break; } case "disable": { tls = { enabled: false, enforce: false, caCertificates: [] }; break; } case "prefer": { tls = { enabled: true, enforce: false, caCertificates: [] }; break; } case "require": { tls = { enabled: true, enforce: true, caCertificates: [] }; break; } default: { throw new ConnectionParamsError(`Supplied DSN has invalid sslmode '${postgres_uri.sslmode}'. Only 'disable', 'require', and 'prefer' are supported`); } } return { applicationName: postgres_uri.application_name, database: postgres_uri.dbname, hostname: postgres_uri.host, host_type, password: postgres_uri.password, port: postgres_uri.port, tls, user: postgres_uri.user, }; } const DEFAULT_OPTIONS = { applicationName: "deno_postgres", connection: { attempts: 1, }, host: "127.0.0.1", socket: "/tmp", host_type: "socket", port: 5432, tls: { enabled: true, enforce: false, caCertificates: [], }, }; export function createParams(params = {}) { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r; if (typeof params === "string") { params = parseOptionsFromUri(params); } let pgEnv = {}; let has_env_access = true; try { pgEnv = getPgEnv(); } catch (e) { if (e instanceof Deno.errors.PermissionDenied) { has_env_access = false; } else { throw e; } } const provided_host = (_a = params.hostname) !== null && _a !== void 0 ? _a : pgEnv.hostname; // If a host is provided, the default connection type is TCP const host_type = (_b = params.host_type) !== null && _b !== void 0 ? _b : (provided_host ? "tcp" : DEFAULT_OPTIONS.host_type); if (!["tcp", "socket"].includes(host_type)) { throw new ConnectionParamsError(`"${host_type}" is not a valid host type`); } let host; if (host_type === "socket") { const socket = provided_host !== null && provided_host !== void 0 ? provided_host : DEFAULT_OPTIONS.socket; try { if (!isAbsolute(socket)) { const parsed_host = new URL(socket, Deno.mainModule); // Resolve relative path if (parsed_host.protocol === "file:") { host = fromFileUrl(parsed_host); } else { throw new ConnectionParamsError("The provided host is not a file path"); } } else { host = socket; } } catch (e) { // TODO // Add error cause throw new ConnectionParamsError(`Could not parse host "${socket}" due to "${e}"`); } } else { host = provided_host !== null && provided_host !== void 0 ? provided_host : DEFAULT_OPTIONS.host; } let port; if (params.port) { port = Number(params.port); } else if (pgEnv.port) { port = Number(pgEnv.port); } else { port = DEFAULT_OPTIONS.port; } if (Number.isNaN(port) || port === 0) { throw new ConnectionParamsError(`"${(_c = params.port) !== null && _c !== void 0 ? _c : pgEnv.port}" is not a valid port number`); } if (host_type === "socket" && (params === null || params === void 0 ? void 0 : params.tls)) { throw new ConnectionParamsError(`No TLS options are allowed when host type is set to "socket"`); } const tls_enabled = !!((_e = (_d = params === null || params === void 0 ? void 0 : params.tls) === null || _d === void 0 ? void 0 : _d.enabled) !== null && _e !== void 0 ? _e : DEFAULT_OPTIONS.tls.enabled); const tls_enforced = !!((_g = (_f = params === null || params === void 0 ? void 0 : params.tls) === null || _f === void 0 ? void 0 : _f.enforce) !== null && _g !== void 0 ? _g : DEFAULT_OPTIONS.tls.enforce); if (!tls_enabled && tls_enforced) { throw new ConnectionParamsError("Can't enforce TLS when client has TLS encryption is disabled"); } // TODO // Perhaps username should be taken from the PC user as a default? const connection_options = { applicationName: (_j = (_h = params.applicationName) !== null && _h !== void 0 ? _h : pgEnv.applicationName) !== null && _j !== void 0 ? _j : DEFAULT_OPTIONS.applicationName, connection: { attempts: (_l = (_k = params === null || params === void 0 ? void 0 : params.connection) === null || _k === void 0 ? void 0 : _k.attempts) !== null && _l !== void 0 ? _l : DEFAULT_OPTIONS.connection.attempts, }, database: (_m = params.database) !== null && _m !== void 0 ? _m : pgEnv.database, hostname: host, host_type, password: (_o = params.password) !== null && _o !== void 0 ? _o : pgEnv.password, port, tls: { enabled: tls_enabled, enforce: tls_enforced, caCertificates: (_q = (_p = params === null || params === void 0 ? void 0 : params.tls) === null || _p === void 0 ? void 0 : _p.caCertificates) !== null && _q !== void 0 ? _q : [], }, user: (_r = params.user) !== null && _r !== void 0 ? _r : pgEnv.user, }; assertRequiredOptions(connection_options, ["applicationName", "database", "hostname", "host_type", "port", "user"], has_env_access); return connection_options; } //# sourceMappingURL=connection_params.js.map