47e73ceee8 | ||
---|---|---|
bin | ||
boot | ||
dist | ||
etc | ||
lib | ||
snippets | ||
tests | ||
.gitignore | ||
.jshintrc | ||
LICENSE | ||
README.md | ||
add-subtree.sh | ||
install-helper.sh | ||
install.sh | ||
package.json | ||
setup-dev-deps.sh | ||
uninstall.sh | ||
walnut.js |
README.md
walnut
An opinionated, constrained, secure application framework with a hard shell - like iOS, but for a home server.
Security Features
- JSON-only APIs
- JWT (not cookie*) authentication
- no server-rendered html
- disallows urlencoded forms, except for secured webhooks
- disallows cookies, except for protected static assets
- api.* subdomain for apis
- assets.* subdomain for protected assets
- must sit behind a trusted https proxy (such as Goldilocks
- HTTPS-only (checks for X-Forwarded-For)
- AES, RSA, and ECDSA encryption and signing
- Safe against CSRF, XSS, and SQL injection
- Safe against Compression attacks
*Cookies are used only for GETs and only where using a token would be less secure - such as images which would otherwise require the token to be passed into the img src. They are also scoped such that CSRF attacks are not possible.
Application Features
- JSON-only expressjs APIs
- Capability-based permissions system for (oauth3-discoverable) packages such as
- large file access (files@daplie.com)
- database access (data@daplie.com)
- scheduling (for background tasks, alerts, alarms, calendars, reminders, etc) (events@daplie.com)
- payments (credit card) (payments@daplie.com)
- email (email@daplie.com)
- SMS (texting) (tel@daplie.com)
- voice (calls and answering machine) (tel@daplie.com)
- lamba-style functions (functions@daplie.com)
- Per-app, per-site, and per-user configurations
- Multi-Tentated Application Management
- Built-in OAuth2 & OAuth3 support
curl https://daplie.me/install-scripts | bash
daplie-install-walnut
You could also, of course, try installing from the repository directly (especially if you have goldilocks or some similar already installed)
mkdir -p /srv/walnut/
git clone git@git.daplie.com:Daplie/walnut.js.git /srv/walnut/core
pushd /srv/walnut/core
git checkout v1
popd
bash /srv/walnut/core/install-helper.sh
Initial Configuration
Once installed and started you can visit https://localhost.daplie.me:3000.
curl http://localhost.daplie.me:3000 -H 'X-Forwarded-Proto: https'
API
API docs are here https://git.daplie.com/Daplie/com.example.hello
Structure
Currently being tested with Ubuntu, Raspbian, and Debian on Digital Ocean, Raspberry Pi, and Heroku.
/srv/walnut/
├── setup.sh (in-progress)
├── core
│ ├── bin
│ ├── boot
│ ├── holepunch
│ └── lib
├── etc
│ └── client-api-grants
├── node_modules
├── packages
│ ├── apis
│ ├── pages
│ └── services
└── var
└── sites
core
contains all walnut codenode_modules
is a flat installation of all dependenciescerts
is a directory for Let's Encrypt (or custom) certificatesvar
is a directory for database files and suchpackages
contains 3 types of packages
Will install to
/srv/walnut/core/
/etc/walnut
/opt/walnut
/var/log/walnut
/etc/systemd/system/walnut.service
/etc/tmpfiles.d/walnut.conf
Implementation details
Initialization
needs to know its primary domain
POST https://api.<domain.tld>/api/com.daplie.walnut.init
{ "domain": "<domain.tld>" }
The following domains are required to point to WALNUT server
<domain.tld>
www.<domain.tld>
api.<domain.tld>
assets.<domain.tld>
cloud.<domain.tld>
api.cloud.<domain.tld>
Example /etc/goldilocks/goldilocks.yml
:
tls:
email: domains@example.com
servernames:
- example.com
- www.example.com
- api.example.com
- assets.example.com
- cloud.example.com
- api.cloud.example.com
http:
trust_proxy: true
modules:
- name: proxy
domains:
- '*'
address: '127.0.0.1:3000'
Resetting the Initialization
Once you run the app the initialization files will appear in these locations
/srv/walnut/var/com.daplie.walnut.config.sqlite3
/srv/walnut/config/<domain.tld>/config.json
Deleting those files will rese
Accessing static apps
Static apps are stored in packages/pages
# App ID as files with a list of packages they should load
# note that '#' is used in place of '/' because files and folders may not contain '/' in their names
/srv/walnut/packages/sites/<domain.tld#path> # https://domain.tld/path
/srv/walnut/packages/sites/<domain.tld> # https://domain.tld and https://domain.tld/foo match
# packages are directories with reverse dns name # For the sake of debugging these packages can be accessed directly, without a site by
/srv/walnut/packages/pages/<tld.domain.package> # matches apps.<domain.tld>/<package-name> and <domain.tld>/apps/<package-name>
Accessing REST APIs
# Apps are granted access to use a package by listing it in the grants file by the name of the app url (domain.tld)
/srv/walnut/packages/client-api-grants/<domain.tld> # matches api.<domain.tld>/api/ and contains a list of allowed REST APIs
# the REST apis themselves are submatched as api.<domain.tld>/api/<tld.domain.package>
# packages are directories with reverse dns name, a package.json, and an index.js
/srv/walnut/packages/rest/<tld.domain.package>
Example tree with contents:
Here com.example.hello
is a package with a REST API and a static page
and foobar.me
is a WALNUT-configured domain (smithfam.net, etc).
The packages:
/srv/walnut/packages/
├── api
├── pages
│ └── com.example.hello
│ └── index.html
│ '''
│ <html>
│ <head><title>com.example.hello</title></head>
│ <body>
│ <h1>com.example.hello</h1>
│ </body>
│ </html>
│ '''
│
├── rest
│ └── com.example.hello
│ ├── package.json
│ └── index.js
│ '''
│ 'use strict';
│
│ module.exports.create = function (conf, deps, app) {
│
│ app.use('/', function (req, res) {
│ console.log('[com.example.hello] req.url', req.url);
│ res.send({ message: 'hello' });
│ });
│
│ return deps.Promise.resolve();
│ };
│
│ '''
│
└── services
The permissions:
/srv/walnut/packages/
├── client-api-grants
│ └── cloud.foobar.me
│ '''
│ com.example.hello # refers to /srv/walnut/packages/rest/com.example.hello
│ '''
│
└── sites
└── daplie.me
'''
com.example.hello # refers to /srv/walnut/packages/pages/com.example.hello
'''
API
req.apiUrlPrefix => https://api.example.com/api/tld.domain.pkg
TODO
- HTTPS Key Pinning
- Heroku (pending completion of PostgreSQL support)
- GunDB Support
- OpenID support