From 104c4cfde74d8bba237f16f74d11448b925fe9df Mon Sep 17 00:00:00 2001 From: Paul Liverman III Date: Mon, 23 Apr 2018 05:00:42 -0700 Subject: [PATCH] init --- applications/api.moon | 40 ++++++++++++ config.moon | 20 ++++++ install.sh | 142 ++++++++++++++++++++++++++++++++++++++++++ locator.moon | 1 + locator_config.moon | 28 +++++++++ migrations.moon | 29 +++++++++ models.moon | 2 + models/APIKeys.moon | 24 +++++++ models/Tasks.moon | 4 ++ 9 files changed, 290 insertions(+) create mode 100644 applications/api.moon create mode 100644 config.moon create mode 100644 install.sh create mode 100644 locator.moon create mode 100644 locator_config.moon create mode 100644 migrations.moon create mode 100644 models.moon create mode 100644 models/APIKeys.moon create mode 100644 models/Tasks.moon diff --git a/applications/api.moon b/applications/api.moon new file mode 100644 index 0000000..dc53550 --- /dev/null +++ b/applications/api.moon @@ -0,0 +1,40 @@ +import Application from require "lapis" +import json_params, capture_errors_json, yield_error, assert_valid from require "lapis.application" +-- import assert_valid from require "lapis.validate" +-- +import APIKeys, Tasks from require "models" +-- import Keys, Tasks from require "models" +-- import locate from require "locator" +-- import random from locate "calc" +-- import escape_similar_to from locate "db" + +class API extends Application + @path: "/v1" + @name: "api_" + + @before_filter( capture_errors_json json_params => + @api_key = APIKeys\find key: @params.api_key + yield_error "api_key not specified!" unless @api_key + ) + + [new: "/new"]: => + assert_valid @params, { + {"content", exists: true, min_length: 1, "Task content not specified."} + } + + task, err = Tasks\create { + user_id: @api_key.user_id + content: @params.content + } + yield_error err unless task + + return json: { success: true, :task } + + -- /new { content: "string" } + -- /do { id: # + -- /undo { id: # } + -- /get { id: # } + -- /random { count: #, done: bool } (both args optional, defaults count 1, done false) + -- /list { count: #, done: bool, page: #, order: asc/desc } (if done not specified, returns all, default count is 50, default page is 1, default order is latest first + -- + -- Add ability to send out subscription webhooks. diff --git a/config.moon b/config.moon new file mode 100644 index 0000000..95bcdf8 --- /dev/null +++ b/config.moon @@ -0,0 +1,20 @@ +-- sql_password: '$POSTGRES_PASSWORD' +-- session_secret: '$(cat /dev/urandom | head -c 12 | base64)' +-- _domain: '$DOMAIN_NAME' +-- _port: '$PORT' + +config = require "lapis.config" +import sql_password, session_secret, _domain, _port from require "secret" + +config "production", -> + postgres -> + host "127.0.0.1" + user "simplex" + password sql_password + database "simplex" + domain _domain + port _port + + num_workers 4 + code_cache "on" + digest_rounds 12 -- NOTE not sure if this is used anywhere diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..f73d7b8 --- /dev/null +++ b/install.sh @@ -0,0 +1,142 @@ +#!/bin/bash + +set -o errexit + +INSTALL_DIR=$(pwd) +OPENRESTY_VERSION=1.13.6.1 +LUAROCKS_VERSION=2.4.1 +POSTGRES_PASSWORD=$(cat /dev/urandom | head -c 12 | base64) + +read -p "Enter email address for use with certbot-auto: " EMAIL_ADDRESS +read -p "Enter the domain name this will be running on: " DOMAIN_NAME +read -p "Enter the port this will be running on: " PORT + +if [ -z EMAIL_ADDRESS ] +then + EMAIL_ADDRESS=no-one@example.com +fi + +if [ -z PORT ] +then + PORT=9872 +fi + +### PREREQUISITES ### + +if ! command -v nginx >/dev/null 2>&1 +then + sudo apt-get install nginx -y +fi + +if ! command -v certbot-auto >/dev/null 2>&1 +then + wget https://dl.eff.org/certbot-auto + chmod a+x ./certbot-auto + sudo mv ./certbot-auto /bin/certbot-auto +fi + +if ! command -v psql >/dev/null 2>&1 +then + sudo apt-get install postgresql -y +fi + +if ! command -v openresty >/dev/null 2>&1 || [ ! -d '/usr/loca/openresty' ] +then + sudo apt-get install wget curl lua5.1 liblua5.1-0-dev zip unzip libreadline-dev libncurses5-dev libpcre3-dev openssl libssl-dev perl make build-essential -y + cd .. + wget https://openresty.org/download/openresty-$OPENRESTY_VERSION.tar.gz + tar xvf openresty-$OPENRESTY_VERSION.tar.gz + cd openresty-$OPENRESTY_VERSION + ./configure + make + sudo make install + cd .. + rm -rf openresty-$OPENRESTY_VERSION* + cd $INSTALL_DIR +fi + +if ! command -v luarocks >/dev/null 2>&1 +then + sudo apt-get install wget curl lua5.1 liblua5.1-0-dev zip unzip libreadline-dev libncurses5-dev libpcre3-dev openssl libssl-dev perl make build-essential -y + cd .. + wget https://keplerproject.github.io/luarocks/releases/luarocks-$LUAROCKS_VERSION.tar.gz + tar xvf luarocks-$LUAROCKS_VERSION.tar.gz + cd luarocks-$LUAROCKS_VERSION + ./configure + make build + sudo make install + cd .. + rm -rf luarocks-$LUAROCKS_VERSION* + cd $INSTALL_DIR +fi + +# sudo luarocks install luacrypto # needed for lapis, but lapis doesn't install it +sudo luarocks install lapis +sudo luarocks install moonscript +sudo luarocks install bcrypt +sudo luarocks install lapis-console # not used yet, but I totally will + +# Certificate +sudo nginx -s stop +sudo certbot-auto certonly --standalone --agree-tos -m $EMAIL_ADDRESS -d $DOMAIN_NAME +sudo nginx + +# Database access +sudo -u postgres createuser simplex +sudo -u postgres createdb simplex +sudo -u postgres bash -c 'psql -c "ALTER USER simplex WITH ENCRYPTED PASSWORD '\'$POSTGRES_PASSWORD\''; GRANT ALL PRIVILEGES ON DATABASE simplex TO simplex;"' + +# Secrets setup +echo "{ + sql_password: '$POSTGRES_PASSWORD' + session_secret: '$(cat /dev/urandom | head -c 12 | base64)' + _domain: '$DOMAIN_NAME' + _port: '$PORT' +}" > ./secret.moon + +# Compile, Run migrations +moonc . +lapis migrate production + +# As-a-Service +sudo echo "[Unit] +Description=simplex server + +[Service] +User=www-data +Type=forking +WorkingDirectory=$INSTALL_DIR +ExecStart=$(which lapis) server production +ExecReload=$(which lapis) build production +ExecStop=$(which lapis) term + +[Install] +WantedBy=multi-user.target" > /etc/systemd/system/ +sudo systemctl daemon-reload +sudo systemctl enable simplex.service + +# Proxy +sudo echo "server { + listen 443 ssl; + server_name $DOMAIN_NAME; + + ssl_certificate /etc/letsencrypt/live/$DOMAIN_NAME/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/$DOMAIN_NAME/privkey.pem; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_prefer_server_ciphers on; + ssl_ciphers \"EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH\"; + ssl_ecdh_curve secp384r1; + ssl_session_cache shared:SSL:10m; + ssl_session_tickets off; + ssl_stapling on; + ssl_stapling_verify on; + ssl_dhparam $INSTALL_DIR/dhparams.pem; + + location / { + proxy_pass http://127.0.0.1:$PORT + } +}" > /etc/nginx/sites-enabled/simplex-proxy.conf + +# Change owner, start service +sudo chown -R www-data:www-data ./ +sudo service simplex start diff --git a/locator.moon b/locator.moon new file mode 100644 index 0000000..175dafd --- /dev/null +++ b/locator.moon @@ -0,0 +1 @@ +return require "locator.init" diff --git a/locator_config.moon b/locator_config.moon new file mode 100644 index 0000000..0daefc0 --- /dev/null +++ b/locator_config.moon @@ -0,0 +1,28 @@ +{ + { + path: "applications.users" + remote: { + name: "users" + fetch: "https://github.com/lazuscripts/users" + } + } + { + path: "applications" + } + { + path: "utility" + remote: { + name: "utility" + fetch: "https://github.com/lazuscripts/utility" + } + } + + + { + path: "locator" + remote: { + name: "locator" + fetch: "https://github.com/lazuscripts/locator" + } + } +} diff --git a/migrations.moon b/migrations.moon new file mode 100644 index 0000000..979bbbb --- /dev/null +++ b/migrations.moon @@ -0,0 +1,29 @@ +import create_table, types, create_index from require "lapis.db.schema" +import make_migrations, autoload from require "locator" +import settings from autoload "utility" + +make_migrations { + [1524503851]: => + create_table "tasks", { + {"id", types.serial primary_key: true} + {"user_id", types.foreign_key} + {"content", types.text} + {"done", types.boolean default: false} + + {"created_at", types.time} + {"updated_at", types.time} + } + create_table "api_keys", { + {"user_id", types.foreign_key} + {"key", types.varchar unique: true} + + {"created_at", types.time} + {"updated_at", types.time} + } + + create_index "api_keys", "user_id" + create_index "api_keys", "key" + create_index "tasks", "id" + create_index "tasks", "user_id" + create_index "tasks", "user_id", "done" +} diff --git a/models.moon b/models.moon new file mode 100644 index 0000000..1d293dc --- /dev/null +++ b/models.moon @@ -0,0 +1,2 @@ +import autoload from require "locator" +return autoload "models" diff --git a/models/APIKeys.moon b/models/APIKeys.moon new file mode 100644 index 0000000..2e8bc6a --- /dev/null +++ b/models/APIKeys.moon @@ -0,0 +1,24 @@ +bcrypt = require "bcrypt" + +import Model from require "lapis.db.model" +import encode_base64 from require "lapis.util.encoding" +import autoload from require "locator" +import settings from autoload "utility" + +class APIKeys extends Model + @primary_key: "user_id" + @table_name: => "api_keys" + + @create: (user={}, opts) => + unless (user.name and user.digest) + error "API Keys need to be created using a user model." + + values = {} + while true + values.key = encode_base64 bcrypt.digest "#{settings["simplex.key-increment"]}#{user.name}#{user.digest}", settings["users.bcrypt-digest-rounds"] + settings["simplex.key-increment"] += 1 + unless APIKeys\find key: values.key + settings.set "simplex.key-increment" + break + + super values, opts diff --git a/models/Tasks.moon b/models/Tasks.moon new file mode 100644 index 0000000..b4f5d66 --- /dev/null +++ b/models/Tasks.moon @@ -0,0 +1,4 @@ +import Model from require "lapis.db.model" + +class Tasks extends Model + @timestamp: true