diff --git a/bin/lamassu-coins b/bin/lamassu-coins new file mode 100755 index 00000000..57d5725c --- /dev/null +++ b/bin/lamassu-coins @@ -0,0 +1,5 @@ +#!/usr/bin/env node + +const install = require('../lib/blockchain/install') + +install.run() diff --git a/install b/install new file mode 100644 index 00000000..740377d4 --- /dev/null +++ b/install @@ -0,0 +1,205 @@ +#!/usr/bin/env bash +set -e + +export LOG_FILE=/tmp/install.log + +NODE_MODULES=/usr/local/share/.config/yarn/global/node_modules +CERT_DIR=/etc/ssl/certs +KEY_DIR=/etc/ssl/private +CONFIG_DIR=/etc/lamassu +MIGRATE_STATE_PATH=$CONFIG_DIR/.migrate +CA_KEY_PATH=$KEY_DIR/Lamassu_OP_Root_CA.key +CA_PATH=$CERT_DIR/Lamassu_OP_Root_CA.pem +SERVER_KEY_PATH=$KEY_DIR/Lamassu_OP.key +SERVER_CERT_PATH=$CERT_DIR/Lamassu_OP.pem +SEEDS_DIR=$HOME/seeds +SEED_FILE=$SEEDS_DIR/seed.txt +BACKUP_DIR=/var/backups/postgresql +BLOCKCHAIN_DIR=/mnt/blockchains + +# Look into http://unix.stackexchange.com/questions/140734/configure-localtime-dpkg-reconfigure-tzdata + +decho () { + echo `date +"%H:%M:%S"` $1 + echo `date +"%H:%M:%S"` $1 >> $LOG_FILE +} + +retry() { + local -r -i max_attempts="$1"; shift + local -r cmd="$@" + local -i attempt_num=1 + + until $cmd + do + if (( attempt_num == max_attempts )) + then + echo + echo "****************************************************************" + echo "Attempt $attempt_num failed and there are no more attempts left!" + return 1 + else + echo + echo "****************************************************************" + echo "Attempt $attempt_num failed! Trying again in $attempt_num seconds..." + sleep $(( attempt_num++ )) + fi + done +} + +rm -f $LOG_FILE + +cat <<'FIG' + _ +| | __ _ _ __ ___ __ _ ___ ___ _ _ ___ ___ _ ____ _____ _ __ +| |/ _` | '_ ` _ \ / _` / __/ __| | | |_____/ __|/ _ \ '__\ \ / / _ \ '__| +| | (_| | | | | | | (_| \__ \__ \ |_| |_____\__ \ __/ | \ V / __/ | +|_|\__,_|_| |_| |_|\__,_|___/___/\__,_| |___/\___|_| \_/ \___|_| +FIG + +echo -e "\nStarting \033[1mlamassu-server\033[0m install. This will take a few minutes...\n" + +if [ "$(whoami)" != "root" ]; then + echo -e "This script has to be run as \033[1mroot\033[0m user" + exit 3 +fi + +# So we don't run out of memory +decho "Enabling swap file for install only..." +fallocate -l 1G /swapfile >> $LOG_FILE 2>&1 +chmod 600 /swapfile >> $LOG_FILE 2>&1 +mkswap /swapfile >> $LOG_FILE 2>&1 +swapon /swapfile >> $LOG_FILE 2>&1 + +IP=$(ifconfig eth0 | grep "inet addr" | awk -F: '{print $2}' | awk '{print $1}') + +decho "Updating system..." +curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash - >> $LOG_FILE 2>&1 +apt update >> $LOG_FILE 2>&1 + +decho "Installing necessary packages..." +apt install nodejs python-minimal build-essential postgresql libpq-dev -y -q >> $LOG_FILE 2>&1 + +decho "Generating seed..." +mkdir -p $SEEDS_DIR >> $LOG_FILE 2>&1 +SEED=$(openssl rand -hex 32) +echo $SEED > $SEED_FILE + +decho "Installing yarn package manager for node..." +npm -g --unsafe-perm install yarn >> $LOG_FILE 2>&1 + +decho "Installing lamassu-server..." +retry 3 yarn global add pm2 >> $LOG_FILE 2>&1 +retry 3 yarn global add lamassu/lamassu-server#v5 >> $LOG_FILE 2>&1 + +decho "Creating postgres user..." +POSTGRES_PW=$(hkdf postgres-pw $SEED) +su -l postgres >> $LOG_FILE 2>&1 <> $LOG_FILE 2>&1 +mkdir -p $CONFIG_DIR >> $LOG_FILE 2>&1 + +decho "Generating SSL certificates..." + +openssl genrsa \ + -out $CA_KEY_PATH \ + 4096 >> $LOG_FILE 2>&1 + +openssl req \ + -x509 \ + -sha256 \ + -new \ + -nodes \ + -key $CA_KEY_PATH \ + -days 3560 \ + -out $CA_PATH \ + -subj "/C=IS/ST=/L=Reykjavik/O=Lamassu Operator CA/CN=lamassu-operator.is" \ + >> $LOG_FILE 2>&1 + +openssl genrsa \ + -out $SERVER_KEY_PATH \ + 4096 >> $LOG_FILE 2>&1 + +openssl req -new \ + -key $SERVER_KEY_PATH \ + -out /tmp/Lamassu_OP.csr.pem \ + -subj "/C=IS/ST=/L=Reykjavik/O=Lamassu Operator/CN=$IP" \ + -reqexts SAN \ + -sha256 \ + -config <(cat /etc/ssl/openssl.cnf \ + <(printf "[SAN]\nsubjectAltName=IP.1:$IP")) \ + >> $LOG_FILE 2>&1 + +openssl x509 \ + -req -in /tmp/Lamassu_OP.csr.pem \ + -CA $CA_PATH \ + -CAkey $CA_KEY_PATH \ + -CAcreateserial \ + -out $SERVER_CERT_PATH \ + -extfile <(cat /etc/ssl/openssl.cnf \ + <(printf "[SAN]\nsubjectAltName=IP.1:$IP")) \ + -extensions SAN \ + -days 3650 >> $LOG_FILE 2>&1 + +rm /tmp/Lamassu_OP.csr.pem + +cat < $CONFIG_DIR/lamassu.json +{ + "postgresql": "postgres://lamassu_pg:$POSTGRES_PW@localhost/lamassu", + "seedPath": "$SEED_FILE", + "caPath": "$CA_PATH", + "certPath": "$SERVER_CERT_PATH", + "keyPath": "$SERVER_KEY_PATH", + "hostname": "$IP", + "logLevel": "info", + "lamassuServerPath": "$NODE_MODULES/lamassu-server", + "migrateStatePath": "$MIGRATE_STATE_PATH", + "blockchainDir": "$BLOCKCHAIN_DIR" +} +EOF + +decho "Setting up database tables..." +lamassu-migrate >> $LOG_FILE 2>&1 + +decho "Setting up lamassu-admin..." +ADMIN_REGISTRATION_URL=`lamassu-register admin 2>> $LOG_FILE` +lamassu-apply-defaults >> $LOG_FILE 2>&1 + +decho "Starting lamassu-admin..." +pm2 start lamassu-admin-server >> $LOG_FILE 2>&1 +pm2 start lamassu-server --restart-delay 3000 >> $LOG_FILE 2>&1 +pm2 save >> $LOG_FILE 2>&1 +pm2 startup >> $LOG_FILE 2>&1 + +decho "Setting up backups..." +BIN=$(yarn global bin) +BACKUP_CMD=$BIN/lamassu-backup-pg +mkdir -p $BACKUP_DIR +BACKUP_CRON="@daily $BACKUP_CMD > /dev/null" +echo $BACKUP_CRON | crontab - >> $LOG_FILE 2>&1 +$BACKUP_CMD >> $LOG_FILE 2>&1 + +decho "Setting up firewall..." +ufw allow ssh >> $LOG_FILE 2>&1 +ufw allow 443/tcp >> $LOG_FILE 2>&1 # Admin +ufw allow 3000/tcp >> $LOG_FILE 2>&1 # Server +ufw -f enable >> $LOG_FILE 2>&1 + +decho "Disabling swap file..." +swapoff /swapfile >> $LOG_FILE 2>&1 + +echo +decho "Done! Now it's time to configure Lamassu stack." +echo +echo -e "\n*** IMPORTANT ***" +echo "In a private space, run lamassu-mnemonic, write down the words" +echo "and keep them in a safe place." +echo +echo "This secret will allow you to retrieve system passwords, including " +echo "the keys to some of your crypto accounts." +echo +echo +echo "Activation URL for lamassu-admin:" +echo $ADMIN_REGISTRATION_URL diff --git a/lib/blockchain/do-volume.js b/lib/blockchain/do-volume.js index 73623974..40b7f7fc 100644 --- a/lib/blockchain/do-volume.js +++ b/lib/blockchain/do-volume.js @@ -1,8 +1,10 @@ const fs = require('fs') +const options = require('../options') + const common = require('./common') -const MOUNT_POINT = '/mnt/blockchains' +const MOUNT_POINT = options.blockchainDir module.exports = {prepareVolume} @@ -13,7 +15,7 @@ function isMounted () { } function isFormatted (volumePath) { - const res = common.es(`file --dereference -s ${volumePath}`) + const res = common.es(`file --dereference -s ${volumePath}`).trim() return res !== `${volumePath}: data` } diff --git a/lib/blockchain/install.js b/lib/blockchain/install.js index 253ae7b1..e29a3c0b 100644 --- a/lib/blockchain/install.js +++ b/lib/blockchain/install.js @@ -24,6 +24,8 @@ const PLUGINS = { ZEC: require('./zcash.js') } +module.exports = {run} + function installedFilePath (crypto) { return path.resolve(options.blockchainDir, crypto.code, '.installed') } @@ -32,32 +34,18 @@ function isInstalled (crypto) { return fs.existsSync(installedFilePath(crypto)) } -const choices = _.map(c => { - const checked = isInstalled(c) - return { - name: c.display, - value: c.code, - checked, - disabled: checked && 'Installed' - } -}, cryptos) - -const questions = [] - -questions.push({ - type: 'checkbox', - name: 'crypto', - message: 'Which cryptocurrencies would you like to install?', - choices -}) - function processCryptos (codes) { if (_.isEmpty(codes)) { logger.info('No cryptos selected. Exiting.') process.exit(0) } - doVolume.prepareVolume() + const goodVolume = doVolume.prepareVolume() + + if (!goodVolume) { + logger.error('There was an error preparing the disk volume. Exiting.') + process.exit(1) + } logger.info('Thanks! Installing: %s. Will take a while...', _.join(', ', codes)) @@ -67,15 +55,6 @@ function processCryptos (codes) { logger.info('Installation complete.') } -inquirer.prompt(questions) -.then(answers => processCryptos(answers.crypto)) - -function plugin (crypto) { - const plugin = PLUGINS[crypto.cryptoCode] - if (!plugin) throw new Error(`No such plugin: ${crypto.cryptoCode}`) - return plugin -} - function setupCrypto (crypto) { logger.info(`Installing ${crypto.display}...`) const cryptoDir = path.resolve(options.blockchainDir, crypto.code) @@ -93,3 +72,33 @@ function setupCrypto (crypto) { process.chdir(oldDir) } +function plugin (crypto) { + const plugin = PLUGINS[crypto.cryptoCode] + if (!plugin) throw new Error(`No such plugin: ${crypto.cryptoCode}`) + return plugin +} + +function run () { + const choices = _.map(c => { + const checked = isInstalled(c) + return { + name: c.display, + value: c.code, + checked, + disabled: checked && 'Installed' + } + }, cryptos) + + const questions = [] + + questions.push({ + type: 'checkbox', + name: 'crypto', + message: 'Which cryptocurrencies would you like to install?', + choices + }) + + inquirer.prompt(questions) + .then(answers => processCryptos(answers.crypto)) +} + diff --git a/package.json b/package.json index 9a7297f7..882ba9bc 100644 --- a/package.json +++ b/package.json @@ -64,11 +64,10 @@ "lamassu-apply-defaults": "./bin/lamassu-apply-defaults", "hkdf": "./bin/hkdf", "lamassu-backup-pg": "./bin/lamassu-backup-pg", - "lamassu-install-bitcoind": "./bin/lamassu-install-bitcoind", - "lamassu-install-geth": "./bin/lamassu-install-geth", "lamassu-mnemonic": "./bin/lamassu-mnemonic", "lamassu-cancel": "./bin/lamassu-cancel", - "lamassu-nuke-db": "./bin/lamassu-nuke-db" + "lamassu-nuke-db": "./bin/lamassu-nuke-db", + "lamassu-coins": "./bin/lamassu-coins" }, "scripts": { "start": "node bin/lamassu-server",