A lightweight IOT application server with a hard shell written for node.js
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
tigerbot 64ac14d2b7 removed unused modules from package.json 7 years ago
bin removed unused modules from package.json 7 years ago
boot update deps and add a bunch of debug logging 7 years ago
dist add example config file 7 years ago
etc include special and auto cert dirs 8 years ago
lib dummy photo app 7 years ago
snippets add undo instructions 9 years ago
tests apppath => pagespath 9 years ago
.gitignore remove unused files 9 years ago
.jshintrc add .jshintrc 7 years ago
LICENSE open source, again 9 years ago
README.md Merge branch 'master' of git.daplie.com:Daplie/walnut.js 7 years ago
add-subtree.sh add subtree script 7 years ago
install.sh fixed incomplete changed from commit dc226f8 7 years ago
package.json removed unused modules from package.json 7 years ago
setup-dev-deps.sh refactoring to use fs config 8 years ago
uninstall.sh update installer 7 years ago
walnut.js removed letsencrypt and other 7 years ago

README.md

walnut

Small, light, and secure iot application framework.

curl https://daplie.me/install-scripts | bash

daplie-install-cloud

If the pretty url isn't working, for whatever reason, you also try the direct one

# curl https://git.daplie.com/Daplie/daplie-snippets/raw/master/install.sh | bash
# daplie-install-cloud

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.sh

Features

  • Works with Goldilocks for secure, Let's Encrypt maneged, https-only serving

  • IOT Application server written in Node.js

  • Small memory footprint (for a node app)

  • Secure

    • Uses JWT, not Cookies*
    • 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
  • Multi-Tentated Application Management

  • Built-in OAuth2 & OAuth3 support

*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.

In Progress

  • HTTPS Key Pinning
  • Heroku (pending completion of PostgreSQL support)
  • GunDB Support
  • OpenID support

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 code
  • node_modules is a flat installation of all dependencies
  • certs is a directory for Let's Encrypt (or custom) certificates
  • var is a directory for database files and such
  • packages 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