diff --git a/litecoin-core/data/app/.gitkeep b/litecoin-core/data/app/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/litecoin-core/data/litecoin/.gitkeep b/litecoin-core/data/litecoin/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/litecoin-core/docker-compose.yml b/litecoin-core/docker-compose.yml new file mode 100644 index 0000000000..e9ba86209f --- /dev/null +++ b/litecoin-core/docker-compose.yml @@ -0,0 +1,56 @@ +services: + app_proxy: + environment: + APP_HOST: litecoin-core_app_1 + APP_PORT: 3000 + + app: + image: ghcr.io/ryleastark/umbrel-litecoin-core-gui:v0.3.2@sha256:901ea227a6f95b4f6b453596f2d40ca69fe03383ae0e9cf793eb6df8c3253517 + user: "1000:1000" + init: true + restart: on-failure + stop_grace_period: 15m30s + ports: + - "${APP_LITECOIN_P2P_PORT}:${APP_LITECOIN_P2P_PORT}" + - "${APP_LITECOIN_RPC_PORT}:${APP_LITECOIN_RPC_PORT}" + volumes: + - ${APP_DATA_DIR}/data:/data + environment: + LITECOIN_DIR: /data/litecoin + APP_STATE_DIR: /data/app + APPS_SUBNET: "${NETWORK_IP}/16" + P2P_PORT: "${APP_LITECOIN_P2P_PORT}" + P2P_WHITEBIND_PORT: "${APP_LITECOIN_P2P_WHITEBIND_PORT}" + RPC_PORT: "${APP_LITECOIN_RPC_PORT}" + TOR_PORT: "${APP_LITECOIN_TOR_PORT}" + ZMQ_RAWBLOCK_PORT: "${APP_LITECOIN_ZMQ_RAWBLOCK_PORT}" + ZMQ_RAWTX_PORT: "${APP_LITECOIN_ZMQ_RAWTX_PORT}" + ZMQ_HASHBLOCK_PORT: "${APP_LITECOIN_ZMQ_HASHBLOCK_PORT}" + ZMQ_SEQUENCE_PORT: "${APP_LITECOIN_ZMQ_SEQUENCE_PORT}" + ZMQ_HASHTX_PORT: "${APP_LITECOIN_ZMQ_HASHTX_PORT}" + TOR_HOST: "${APP_LITECOIN_TOR_PROXY_IP}" + TOR_SOCKS_PORT: "9050" + TOR_CONTROL_PORT: "9051" + TOR_CONTROL_PASSWORD: "moneyprintergobrrr" + LITECOIND_IP: "${APP_LITECOIN_NODE_IP}" + RPC_USER: "${APP_LITECOIN_RPC_USER}" + RPC_PASS: "${APP_LITECOIN_RPC_PASS}" + DEVICE_DOMAIN_NAME: "${DEVICE_DOMAIN_NAME}" + P2P_HIDDEN_SERVICE: "${APP_LITECOIN_P2P_HIDDEN_SERVICE}" + RPC_HIDDEN_SERVICE: "${APP_LITECOIN_RPC_HIDDEN_SERVICE}" + networks: + default: + ipv4_address: "${APP_LITECOIN_NODE_IP}" + + tor: + image: ghcr.io/getumbrel/tor:0.4.9.11@sha256:e382b8629c0dfef6ceb396b062622d4e4e955b19d6f16b883fd2c0723ad5671a + user: "1000:1000" + restart: on-failure + volumes: + - ${APP_DATA_DIR}/torrc:/etc/tor/torrc:ro + - ${TOR_DATA_DIR}:/data + environment: + HOME: "/tmp" + networks: + default: + ipv4_address: "${APP_LITECOIN_TOR_PROXY_IP}" diff --git a/litecoin-core/exports.sh b/litecoin-core/exports.sh new file mode 100644 index 0000000000..fb09c4f351 --- /dev/null +++ b/litecoin-core/exports.sh @@ -0,0 +1,34 @@ +# Network services +export APP_LITECOIN_NODE_IP="10.21.23.8" +export APP_LITECOIN_TOR_PROXY_IP="10.21.23.10" + +# Persistent node state +export APP_LITECOIN_DATA_DIR="${EXPORTS_APP_DIR}/data/litecoin" + +# Litecoin mainnet listeners +export APP_LITECOIN_RPC_PORT="19332" +export APP_LITECOIN_P2P_PORT="19333" +export APP_LITECOIN_P2P_WHITEBIND_PORT="19335" +export APP_LITECOIN_TOR_PORT="19334" +export APP_LITECOIN_ZMQ_RAWBLOCK_PORT="29342" +export APP_LITECOIN_ZMQ_RAWTX_PORT="29343" +export APP_LITECOIN_ZMQ_HASHBLOCK_PORT="29344" +export APP_LITECOIN_ZMQ_SEQUENCE_PORT="29345" +export APP_LITECOIN_ZMQ_HASHTX_PORT="29346" +export APP_LITECOIN_NETWORK="mainnet" + +# Persist generated RPC credentials across restarts and updates. +LITECOIN_ENV_FILE="${EXPORTS_APP_DIR}/.env" +if [[ ! -f "${LITECOIN_ENV_FILE}" ]]; then + LITECOIN_RPC_USER="umbrel" + LITECOIN_RPC_DETAILS=$("${EXPORTS_APP_DIR}/scripts/rpcauth.py" "${LITECOIN_RPC_USER}") + LITECOIN_RPC_PASS=$(printf '%s\n' "${LITECOIN_RPC_DETAILS}" | tail -1) + printf "export APP_LITECOIN_RPC_USER='%s'\nexport APP_LITECOIN_RPC_PASS='%s'\n" "${LITECOIN_RPC_USER}" "${LITECOIN_RPC_PASS}" > "${LITECOIN_ENV_FILE}" +fi +. "${LITECOIN_ENV_FILE}" + +# Tor hidden-service hostnames are absent until Tor has started once. +rpc_hidden_service_file="${EXPORTS_TOR_DATA_DIR}/app-${EXPORTS_APP_ID}-rpc/hostname" +p2p_hidden_service_file="${EXPORTS_TOR_DATA_DIR}/app-${EXPORTS_APP_ID}-p2p/hostname" +export APP_LITECOIN_RPC_HIDDEN_SERVICE="$(cat "${rpc_hidden_service_file}" 2>/dev/null || echo "notyetset.onion")" +export APP_LITECOIN_P2P_HIDDEN_SERVICE="$(cat "${p2p_hidden_service_file}" 2>/dev/null || echo "notyetset.onion")" diff --git a/litecoin-core/hooks/pre-start b/litecoin-core/hooks/pre-start new file mode 100755 index 0000000000..42f16e8c4d --- /dev/null +++ b/litecoin-core/hooks/pre-start @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -euo pipefail + +DATA_DIR="${APP_DATA_DIR}/data" +LITECOIN_DIR="${DATA_DIR}/litecoin" +APP_STATE_DIR="${DATA_DIR}/app" + +# Umbrel installs package assets as root. The node and UI both run as uid/gid 1000. +mkdir -p "${LITECOIN_DIR}" "${APP_STATE_DIR}" +chown -R 1000:1000 "${LITECOIN_DIR}" "${APP_STATE_DIR}" +find "${LITECOIN_DIR}" "${APP_STATE_DIR}" -type d -exec chmod u+rwx {} + +find "${LITECOIN_DIR}" "${APP_STATE_DIR}" -type f -exec chmod u+rw {} + + +# Start enough of the stack to generate the Tor hostnames before normal startup. +HIDDEN_SERVICE_FILE="${TOR_DATA_DIR}/app-${APP_ID}-rpc/hostname" +if [[ ! -f "${HIDDEN_SERVICE_FILE}" ]]; then + "${UMBREL_ROOT}/scripts/app" compose "${APP_ID}" up --detach app + "${UMBREL_ROOT}/scripts/app" compose "${APP_ID}" up --detach tor + echo "App: ${APP_ID} - Generating Tor hidden services..." + for _ in $(seq 1 100); do + [[ -f "${HIDDEN_SERVICE_FILE}" ]] && break + sleep 0.1 + done +fi diff --git a/litecoin-core/scripts/rpcauth.py b/litecoin-core/scripts/rpcauth.py new file mode 100755 index 0000000000..fb96b907a8 --- /dev/null +++ b/litecoin-core/scripts/rpcauth.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +# Copyright (c) 2015-2018 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from argparse import ArgumentParser +from base64 import urlsafe_b64encode +from binascii import hexlify +from getpass import getpass +from os import urandom + +import hmac + + +def generate_salt(size): + """Create size byte hex salt""" + return hexlify(urandom(size)).decode() + + +def generate_password(): + """Create 32 byte b64 password""" + return urlsafe_b64encode(urandom(32)).decode("utf-8") + + +def password_to_hmac(salt, password): + m = hmac.new(bytearray(salt, "utf-8"), bytearray(password, "utf-8"), "SHA256") + return m.hexdigest() + + +def main(): + parser = ArgumentParser(description="Create login credentials for a JSON-RPC user") + parser.add_argument("username", help="the username for authentication") + parser.add_argument("password", help='leave empty to generate a random password or specify "-" to prompt for password', nargs="?") + args = parser.parse_args() + + if not args.password: + args.password = generate_password() + elif args.password == "-": + args.password = getpass() + + # Create 16 byte hex salt + salt = generate_salt(16) + password_hmac = password_to_hmac(salt, args.password) + + print("String to be appended to bitcoin.conf:") + print("rpcauth={0}:{1}${2}".format(args.username, salt, password_hmac)) + print("Your password:\n{0}".format(args.password)) + + +if __name__ == "__main__": + main() diff --git a/litecoin-core/torrc.template b/litecoin-core/torrc.template new file mode 100644 index 0000000000..17ef932142 --- /dev/null +++ b/litecoin-core/torrc.template @@ -0,0 +1,13 @@ +SocksPort 0.0.0.0:9050 +ControlPort 0.0.0.0:9051 +CookieAuthentication 1 +CookieAuthFileGroupReadable 1 +HashedControlPassword 16:39AF5EEFA4FC1D986022FDFB13663669FE50FB6DE9A3B4FE4FC7D82010 # moneyprintergobrrr + +# Litecoin Core P2P Hidden Service +HiddenServiceDir /data/app-$APP_ID-p2p +HiddenServicePort $APP_LITECOIN_P2P_PORT $APP_LITECOIN_NODE_IP:$APP_LITECOIN_TOR_PORT + +# Litecoin Core RPC Hidden Service +HiddenServiceDir /data/app-$APP_ID-rpc +HiddenServicePort $APP_LITECOIN_RPC_PORT $APP_LITECOIN_NODE_IP:$APP_LITECOIN_RPC_PORT diff --git a/litecoin-core/umbrel-app.yml b/litecoin-core/umbrel-app.yml new file mode 100644 index 0000000000..7631fe8cc7 --- /dev/null +++ b/litecoin-core/umbrel-app.yml @@ -0,0 +1,76 @@ +manifestVersion: 1 +id: litecoin-core +category: bitcoin +name: Litecoin Node +version: "0.21.5.6-gui.0.3.2" +tagline: Run your personal Litecoin node + +description: >- + Run a Litecoin node on your Umbrel. It keeps a copy of the Litecoin blockchain + and checks transactions for itself. + + + Connect your wallet or other apps to your own node instead of a public service. + Your activity stays on your own hardware. + + + Use the built-in dashboard to check sync progress, peers, network activity, and + node settings. + +releaseNotes: "" + +developer: Litecoin Project and Rylea Stark +website: https://litecoin.org +dependencies: [] +repo: https://github.com/RyleaStark/umbrel-litecoin-core-gui +support: https://github.com/RyleaStark/umbrel-litecoin-core-gui/issues + +port: 2111 +gallery: [] +path: "" + +defaultUsername: "" +defaultPassword: "" + +widgets: + - id: "stats" + type: "four-stats" + refresh: "5s" + endpoint: "app:3000/api/widget/stats" + link: "" + example: + type: "four-stats" + link: "" + items: + - title: "Connections" + text: "11" + subtext: "peers" + - title: "Mempool" + text: "24" + subtext: "MB" + - title: "Hashrate" + text: "2" + subtext: "PH/s" + - title: "Blockchain size" + text: "140" + subtext: "GB" + - id: "sync" + type: "text-with-progress" + refresh: "2s" + endpoint: "app:3000/api/widget/sync" + link: "" + example: + type: "text-with-progress" + link: "" + title: "Blockchain sync" + text: "83%" + progressLabel: "In progress" + progress: 0.83 + +backupIgnore: + - data/litecoin/blocks + - data/litecoin/chainstate + - data/litecoin/indexes + +submitter: Rylea Stark +submission: https://github.com/getumbrel/umbrel-apps/pull/5970