diff --git a/package.json b/package.json index a6455c1..5423f17 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@types/ws": "^8.5.3", "@types/xml2js": "^0.4.11", "async-mutex": "^0.3.2", + "bcfg": "^0.1.7", "dotenv": "^16.0.1", "ethers": "^5.6.9", "express": "^4.18.1", diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 0000000..6b7f67b --- /dev/null +++ b/src/config.ts @@ -0,0 +1,35 @@ +// @ts-ignore +import BConfig from "bcfg"; +import { errorExit } from "./util.js"; + +const config = new BConfig("lumeweb-relay"); + +config.inject({ + relayPort: 8080, +}); + +config.load({ + env: true, + argv: true, +}); +try { + config.open("config.conf"); +} catch (e) {} + +for (const setting of ["relay-domain", "afraid-username", "relay-seed"]) { + if (!config.get(setting)) { + errorExit(`Required config option ${setting} not set`); + } +} + +let usingPocketGateway = true; + +export function usePocketGateway() { + return usingPocketGateway; +} + +export function updateUsePocketGateway(state: boolean): void { + usingPocketGateway = state; +} + +export default config; diff --git a/src/constant_vars.ts b/src/constant_vars.ts deleted file mode 100644 index 0df0f5a..0000000 --- a/src/constant_vars.ts +++ /dev/null @@ -1,34 +0,0 @@ -import fs from "fs"; -import dotenv from "dotenv"; -import path from "path"; -import { fileURLToPath } from "url"; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -const envPath = path.resolve(__dirname, "..", "lumerelay.env"); - -if (fs.existsSync(envPath)) { - dotenv.config({ path: envPath }); -} - -export const RELAY_PORT = process.env.RELAY_PORT ?? 8080; -export const RELAY_DOMAIN = process.env.RELAY_DOMAIN; -export const AFRAID_USERNAME = process.env.AFRAID_USERNAME; -export const AFRAID_PASSWORD = process.env.AFRAID_PASSWORD; -export const RELAY_SEED = process.env.RELAY_SEED; -export const POCKET_APP_ID = process.env.POCKET_APP_ID || false; -export const POCKET_APP_KEY = process.env.POCKET_APP_KEY || false; -export const POCKET_ACCOUNT_PUBLIC_KEY = - process.env.POCKET_ACCOUNT_PUBLIC_KEY || false; -export const POCKET_ACCOUNT_PRIVATE_KEY = - process.env.POCKET_ACCOUNT_PRIVATE_KEY || false; - -export const HSD_USE_EXTERNAL_NODE = process.env.HSD_USE_EXTERNAL_NODE || false; -export const HSD_NETWORK_TYPE = process.env.HSD_NETWORK || "main"; -export const HSD_HOST = process.env.HSD_HOST || "localhost"; -export const HSD_PORT = Number(process.env.HSD_PORT) || 12037; -export const HSD_API_KEY = process.env.HSD_API_KEY || "foo"; - -export const POCKET_HOST = process.env.POCKET_HOST || "localhost"; -export const POCKET_PORT = process.env.POCKET_PORT || 8081; diff --git a/src/constants.ts b/src/constants.ts deleted file mode 100644 index aef5747..0000000 --- a/src/constants.ts +++ /dev/null @@ -1,27 +0,0 @@ -import * as CONFIG from "./constant_vars.js"; - -let error = false; - -for (const constant in CONFIG) { - // @ts-ignore - if (CONFIG[constant] === null || CONFIG[constant] === undefined) { - console.error(`Missing constant ${constant}`); - error = true; - } -} - -if (error) { - process.exit(1); -} - -let usingPocketGateway = true; - -export function usePocketGateway() { - return usingPocketGateway; -} - -export function updateUsePocketGateway(state: boolean): void { - usingPocketGateway = state; -} - -export * from "./constant_vars.js"; diff --git a/src/dht.ts b/src/dht.ts index af00cc9..973d410 100644 --- a/src/dht.ts +++ b/src/dht.ts @@ -8,7 +8,7 @@ import { seedPhraseToSeed, validSeedPhrase, } from "libskynet"; -import { RELAY_SEED } from "./constant_vars"; +import config from "./config.js"; let server: { listen: (arg0: ed25519Keypair) => void; @@ -16,14 +16,14 @@ let server: { }; async function start() { - let [, err] = validSeedPhrase(RELAY_SEED as string); + const seed = config.str("relay-seed"); + + let [, err] = validSeedPhrase(seed); if (err !== null) { errorExit("RELAY_SEED is invalid. Aborting."); } - const keyPair = deriveMyskyRootKeypair( - seedPhraseToSeed(RELAY_SEED as string)[0] - ); + const keyPair = deriveMyskyRootKeypair(seedPhraseToSeed(seed)[0]); const node = new DHT({ keyPair }); diff --git a/src/dns.ts b/src/dns.ts index d711f01..1c75a2d 100644 --- a/src/dns.ts +++ b/src/dns.ts @@ -1,9 +1,3 @@ -import { - AFRAID_USERNAME, - AFRAID_PASSWORD, - RELAY_PORT, - RELAY_DOMAIN, -} from "./constants.js"; import cron from "node-cron"; import fetch from "node-fetch"; import { get as getDHT } from "./dht.js"; @@ -14,6 +8,7 @@ import { Parser } from "xml2js"; import { URL } from "url"; import { errorExit } from "./util.js"; import { pack } from "msgpackr"; +import config from "./config.js"; const { createHash } = await import("crypto"); @@ -43,7 +38,7 @@ export async function start() { await overwriteRegistryEntry( dht.defaultKeyPair, hashDataKey(REGISTRY_DHT_KEY), - pack(`${RELAY_DOMAIN}:${RELAY_PORT}`) + pack(`${config.str("relay-domain")}:${config.uint("relay-port")}`) ); cron.schedule("0 * * * *", ipUpdate); @@ -75,6 +70,7 @@ function encodeNumber(num: number): Uint8Array { } async function getDomainInfo() { + const relayDomain = config.str("relay-domain"); const parser = new Parser(); const url = new URL("https://freedns.afraid.org/api/"); @@ -86,7 +82,9 @@ async function getDomainInfo() { params.append("style", "xml"); const hash = createHash("sha1"); - hash.update(`${AFRAID_USERNAME}|${AFRAID_PASSWORD}`); + hash.update( + `${config.str("afraid-username")}|${config.str("afraid-password")}` + ); params.append("sha", hash.digest().toString("hex")); @@ -101,14 +99,14 @@ async function getDomainInfo() { let domain = null; for (const item of json.xml.item) { - if (item.host[0] === RELAY_DOMAIN) { + if (item.host[0] === relayDomain) { domain = item; break; } } if (!domain) { - errorExit(`Domain ${RELAY_DOMAIN} not found in afraid.org account`); + errorExit(`Domain ${relayDomain} not found in afraid.org account`); } return domain; diff --git a/src/relay.ts b/src/relay.ts index ada1990..497fe21 100644 --- a/src/relay.ts +++ b/src/relay.ts @@ -7,18 +7,18 @@ import { relay } from "@hyperswarm/dht-relay"; // @ts-ignore import Stream from "@hyperswarm/dht-relay/ws"; import { get as getDHT } from "./dht.js"; -import { RELAY_DOMAIN, RELAY_PORT } from "./constants.js"; // @ts-ignore import GLE from "greenlock-express"; // @ts-ignore import Greenlock from "@root/greenlock"; import path from "path"; import { fileURLToPath } from "url"; +import config from "./config.js"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -const config = { +const sslConfig = { packageRoot: path.dirname(__dirname), configDir: path.resolve(__dirname, "../", "./data/greenlock.d/"), cluster: false, @@ -27,14 +27,16 @@ const config = { }; export async function start() { - const greenlock = Greenlock.create(config); + const relayDomain = config.str("relay-domain"); + const relayPort = config.str("relay-port"); + const greenlock = Greenlock.create(sslConfig); await greenlock.add({ - subject: RELAY_DOMAIN, - altnames: [RELAY_DOMAIN], + subject: relayDomain, + altnames: [relayDomain], }); // @ts-ignore config.greenlock = greenlock; - GLE.init(config).ready(async (GLEServer: any) => { + GLE.init(sslConfig).ready(async (GLEServer: any) => { let httpsServer = GLEServer.httpsServer(); var httpServer = GLEServer.httpServer(); @@ -53,14 +55,14 @@ export async function start() { relay(dht, new Stream(false, socket)); }); await new Promise((resolve) => { - httpsServer.listen(RELAY_PORT, "0.0.0.0", function () { + httpsServer.listen(relayPort, "0.0.0.0", function () { console.info("Relay started on ", httpsServer.address()); resolve(null); }); }); await greenlock.get({ - servername: RELAY_DOMAIN, + servername: relayDomain, }); }); } diff --git a/src/rpc.ts b/src/rpc.ts index 55f3a6b..663b265 100644 --- a/src/rpc.ts +++ b/src/rpc.ts @@ -5,15 +5,6 @@ import { Mutex } from "async-mutex"; import { createRequire } from "module"; import NodeCache from "node-cache"; import { get as getDHT } from "./dht.js"; -import { - POCKET_ACCOUNT_PRIVATE_KEY, - POCKET_ACCOUNT_PUBLIC_KEY, - POCKET_APP_ID, - POCKET_APP_KEY, - POCKET_HOST, - POCKET_PORT, -} from "./constant_vars"; -import { updateUsePocketGateway, usePocketGateway } from "./constants"; import { Server as JSONServer } from "jayson/promise/index.js"; import { rpcMethods } from "./rpc/index.js"; import { @@ -27,6 +18,7 @@ import { JSONRPCResponseWithError, JSONRPCResponseWithResult, } from "jayson"; +import config, { updateUsePocketGateway, usePocketGateway } from "./config.js"; const require = createRequire(import.meta.url); @@ -217,8 +209,10 @@ export async function processRpcRequest( } export async function start() { - if (!POCKET_APP_ID || !POCKET_APP_KEY) { - const dispatchURL = new URL(`http://${POCKET_HOST}:${POCKET_PORT}`); + if (!config.str("pocket-app-id") || !config.str("pocket-app-key")) { + const dispatchURL = new URL( + `http://${config.str("pocket-host")}:${config.uint("pocket-port")}` + ); const rpcProvider = new HttpRpcProvider(dispatchURL); const configuration = new Configuration(); pocketServer = new Pocket([dispatchURL], rpcProvider, configuration); @@ -228,8 +222,8 @@ export async function start() { if (!usePocketGateway()) { updateAat( await unlockAccount( - POCKET_ACCOUNT_PRIVATE_KEY, - POCKET_ACCOUNT_PUBLIC_KEY, + config.str("pocket-account-private-key"), + config.str("pocket-account-public-key"), "0" ) ); diff --git a/src/rpc/algorand.ts b/src/rpc/algorand.ts index 41276a8..e9d14d0 100644 --- a/src/rpc/algorand.ts +++ b/src/rpc/algorand.ts @@ -4,7 +4,7 @@ import minimatch from "minimatch"; import HTTPClient from "algosdk/dist/cjs/src/client/client.js"; import { sprintf } from "sprintf-js"; import { RpcMethodList } from "./index.js"; -import { POCKET_APP_ID } from "../constants.js"; +import config from "../config.js"; const allowedEndpoints: { [endpoint: string]: ("GET" | "POST")[] } = { "/v2/teal/compile": ["POST"], @@ -60,7 +60,7 @@ export function proxyRestMethod( let apiUrl; try { - apiUrl = sprintf(apiServer, chainId, POCKET_APP_ID); + apiUrl = sprintf(apiServer, chainId, config.str("pocket-app-id")); } catch (e) { apiUrl = apiServer; } diff --git a/src/rpc/common.ts b/src/rpc/common.ts index 43fd411..5ef49d7 100644 --- a/src/rpc/common.ts +++ b/src/rpc/common.ts @@ -2,12 +2,8 @@ import { ethers } from "ethers"; import { PocketAAT } from "@pokt-network/pocket-js"; import { maybeMapChainId, reverseMapChainId } from "../util.js"; import { Connection } from "@solana/web3.js"; -import { - POCKET_APP_ID, - POCKET_APP_KEY, - usePocketGateway, -} from "../constants.js"; import { getAat, getPocketServer } from "../rpc.js"; +import config, { usePocketGateway } from "../config.js"; export const chainNetworks = require("../../networks.json"); @@ -20,14 +16,18 @@ const gatewayMethods: { } = { default: (chainId: string): RpcProviderMethod => { const provider = new ethers.providers.JsonRpcProvider({ - url: `https://${chainId}.gateway.pokt.network/v1/lb/${POCKET_APP_ID}`, - password: POCKET_APP_KEY, + url: `https://${chainId}.gateway.pokt.network/v1/lb/${config.str( + "pocket-api-id" + )}`, + password: config.str("pocket-api-key"), }); return provider.send.bind(provider); }, "sol-mainnet": (chainId: string): RpcProviderMethod => { const provider = new Connection( - `https://solana-mainnet.gateway.pokt.network/v1/lb/${POCKET_APP_ID}` + `https://solana-mainnet.gateway.pokt.network/v1/lb/${config.str( + "pocket-api-id" + )}` ); // @ts-ignore diff --git a/src/rpc/handshake.ts b/src/rpc/handshake.ts index 48c3c24..6fee46d 100644 --- a/src/rpc/handshake.ts +++ b/src/rpc/handshake.ts @@ -3,13 +3,8 @@ import { RpcMethodList } from "./index.js"; import rand from "random-key"; // @ts-ignore import SPVNode from "hsd/lib/node/spvnode.js"; -import { - HSD_API_KEY, - HSD_HOST, - HSD_NETWORK_TYPE, - HSD_PORT, - HSD_USE_EXTERNAL_NODE, -} from "../constants.js"; +import config from "../config.js"; + const { NodeClient } = require("hs-client"); let hsdServer: SPVNode; @@ -21,11 +16,7 @@ let clientArgs = { apiKey: rand.generate(), }; -if (!HSD_USE_EXTERNAL_NODE) { - process.env.HSD_NO_DNS = "true"; - process.env.HSD_NO_RS = "true"; - process.env.HSD_HTTP_HOST = "127.0.0.1"; - process.env.HSD_API_KEY = clientArgs.apiKey; +if (!config.bool("hsd-use-extenal-node")) { hsdServer = new SPVNode({ config: false, argv: false, @@ -41,10 +32,10 @@ if (!HSD_USE_EXTERNAL_NODE) { }); } else { clientArgs = { - network: HSD_NETWORK_TYPE, - host: HSD_HOST, - port: HSD_PORT, - apiKey: HSD_API_KEY, + network: config.str("hsd-network-type"), + host: config.str("hsd-host"), + port: config.uint("hsd-port"), + apiKey: config.str("hsd-api-key"), }; }