Verified Commit f3c7a828 authored by Aral Balkan's avatar Aral Balkan
Browse files

Add and document global certificate scope and npm script changes

parent 6eb942f2
......@@ -2,20 +2,33 @@
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
Nothing yet.
## [1.0.0]
## [2.0.0] – 2019-03-10
You can now test Hypha from any machine.
### Added
- Global certificate scope with seamlessly-provisioned Let’s Encrypt certificates via [ACME TLS](https://source.ind.ie/hypha/tools/acme-tls/) (handled by [Indie Web Server](](https://source.ind.ie/hypha/tools/web-server))).
### Changed
- Update npm script names to match Indie Web Server terminology.
- Use Indie Web Server v6.0.0 instead of (now deprecated @ind.ie/https-server).
## [1.0.0] - 2019-03-03
Initial scaffolding.
### Added
- Seamless TLS on port 443 at development time via [@ind.ie/http-server](https://source.ind.ie/hypha/tools/https-server)
- Seamless TLS on port 443 at development time via [@ind.ie/https-server](https://source.ind.ie/hypha/tools/https-server)
- Live development environment and production builds via [@hypha/web-compiler](https://source.ind.ie/hypha/tools/web-compiler)
- Test HTTPS GET route
- Test WebSocket route
- Mock HTTPS GET route
- Mock WebSocket route
- Mock Web Node with test client-side Choo routes
......@@ -10,19 +10,53 @@ __Just getting started.__
[Read this blog post](https://ar.al/2019/02/13/on-the-general-architecture-of-the-peer-web/) and see the [multiwriter-2](https://ar.al/2019/02/01/hypha-spike-multiwriter-2/) and [persistence-1](https://ar.al/2019/02/12/hypha-spike-persistence-1/) spikes to see where all this is heading.
## About
This repository contains three separate applications:
1. The Hypha [Untrusted Node](https://source.ind.ie/hypha/hypha/tree/master/untrusted).
2. The Hypha [Web Node](https://source.ind.ie/hypha/hypha/tree/master/web).
3. A Hypha Native Node implemented in Node.js (todo: add initial mock/scaffolding).
## Usage
Command | Description |
-----------------------|--------------------------------------------------|
`$ npm run development`| Start Hypha in development mode with live reload
`$ npm run production` | Start Hypha in production mode
`$ npm test` | Lint, validate deps & run tests
`$ npm run build` | Compile all files into `dist/`
`$ npm run create` | Generate a scaffold file
`$ npm run inspect` | Inspect the bundle's dependencies
`$ npm start` | Alias for `npm run development`
`$ npm run dev` | Alias for `npm run development`
`$ npm run prod` | Alias for `npm run production`
`$ npm run development` | __Start in development mode.__ Uses [@hypha/web-compiler](https://source.ind.ie/hypha/tools/web-compiler) as middleware with live reload to dynamically build the web node on evert request and on source code updates. Serves the dynamically-generated web node alongside any dynamic HTTPS and WebSocket routes using locally-trusted [mkcert](https://github.com/FiloSottile/mkcert) TLS certificates seamlessly provisioned via [Nodecert](https://source.ind.ie/hypha/tools/nodecert).
`$ npm run production` | __Start in production mode.__ Makes a static distribution build of the web node and serves it alongside any dynamic HTTPS and WebSocket routes using globally-trusted [Let’s Encrypt](https://letsencrypt.org) TLS certificates seamlessly provisioned via [ACME TLS](https://source.ind.ie/hypha/tools/acme-tls/).
`$ npm test` | Lint, validate dependencies, and run tests.
`$ npm run dev|start` | Aliases for `npm run development`.
### Advanced
Command | Description |
-----------------------|--------------------------------------------------|
`$ npm run development-global` | __Start development mode with globally-trusted TLS certificates.__ Useful alongside a TLS tunnel like [ngrok](https://ngrok.com/) for testing the app during development from other machines.
`$ npm run production-local` | __Start in production mode with locally-trusted TLS certificates.__ Useful for testing the behaviour of the production run mode from your local development machine.
`$ npm run build` | Compile all files into the `dist/` directory (as if in production) but do not start the untrusted node server.
`$ npm run inspect` | Inspect the web node’s dependencies.
`$ npm run create` | Generate a Choo scaffolding file for the web node.
The Hypha untrusted node is a personal web server that is used for two things:
1. Deliver the Hypha web node (much like an App Store would deliver a native app)
2. Act as a dumb relay to bridge Hypha web and native nodes.
### Run modes and certificate scopes in detail
You can start the Hypha untrusted node in four ways based on the combination of two run modes and two certificate scope settings:
#### Run modes:
- __development__: (default) uses @hypha/web-compiler as middleware with live reload
- __production__: builds a static distribution and implements production optimisations
#### Certificate scopes:
- __local__: (default for development mode) uses locally-trusted mkcert certificates seamlessly obtainted by Nodecert. The untrusted node can be reached without certificate warnings only from the machine you are testing from.
- __global__: (default for production mode) uses globally-trusted Let’s Encrypt certificates seamlessly obtained by ACME TLS. The untrusted node can be reached without certificate warnings from any machine.
## License
......
This diff is collapsed.
{
"name": "@ind.ie/hypha",
"version": "1.0.0",
"version": "2.0.0",
"license": "AGPL-3.0-or-later",
"author": "Aral Balkan <aral@ind.ie> (https://ar.al)",
"private": false,
"scripts": {
"create": "choo-scaffold",
"inspect": "./node_modules/@hypha/web-compiler/bin.js inspect web/index.js",
"build": "./node_modules/@hypha/web-compiler/bin.js build web/index.js",
"development": "./node_modules/nodemon/bin/nodemon.js untrusted/index.js --watch untrusted/index.js",
"dev": "./node_modules/nodemon/bin/nodemon.js untrusted/index.js --watch untrusted/index.js",
"start": "./node_modules/nodemon/bin/nodemon.js untrusted/index.js --watch untrusted/index.js",
"production": "NODE_ENV=production ./node_modules/nodemon/bin/nodemon.js untrusted/index.js --watch untrusted/index.js",
"prod": "NODE_ENV=production ./node_modules/nodemon/bin/nodemon.js untrusted/index.js --watch untrusted/index.js",
"test": "standard && npm run test-deps",
"dev": "./node_modules/nodemon/bin/nodemon.js untrusted/index.js --watch untrusted/index.js",
"start": "./node_modules/nodemon/bin/nodemon.js untrusted/index.js --watch untrusted/index.js",
"development-global": "CERTIFICATE_SCOPE=global ./node_modules/nodemon/bin/nodemon.js untrusted/index.js --watch untrusted/index.js",
"production-local": "NODE_ENV=production CERTIFICATE_SCOPE=local ./node_modules/nodemon/bin/nodemon.js untrusted/index.js --watch untrusted/index.js",
"build": "./node_modules/@hypha/web-compiler/bin.js build web/index.js",
"inspect": "./node_modules/@hypha/web-compiler/bin.js inspect web/index.js",
"create": "choo-scaffold",
"test-deps": "dependency-check . && dependency-check . --extra --no-dev -i tachyons"
},
"dependencies": {
"@ind.ie/https-server": "^3.0.0",
"@ind.ie/web-server": "^6.0.0",
"choo": "^6.13.1",
"choo-service-worker": "^2.4.0",
"express": "^4.16.4",
"express-ws": "^4.0.0",
"sheetify": "^7.3.3"
},
"devDependencies": {
"@hypha/web-compiler": "git+https://aral@source.ind.ie/hypha/tools/web-compiler",
"choo-devtools": "^2.5.1",
......
const httpsServer = require('@ind.ie/https-server')
const webServer = require('@ind.ie/web-server')
const express = require('express')
const expressWebSocket = require('express-ws')
const os = require('os')
const fs = require('fs')
const path = require('path')
// Catch any uncaught errors.
......@@ -10,9 +12,32 @@ process.on('uncaughtException', function (error) {
console.log('Uncaught exception:', error)
})
// Display name and version.
const version = JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json'), 'utf-8')).version
console.log(`\n 💖 Hypha v${version}\n`)
// Useful constants for checking run mode and certificate scope.
const isRunningInProductionMode = process.env.NODE_ENV === 'production'
const isRunningInDevelopmentMode = !isRunningInProductionMode
const LOCAL = 'local'
const GLOBAL = 'global'
let _certificateScope = isRunningInProductionMode ? GLOBAL : LOCAL // set the default
if (process.env.CERTIFICATE_SCOPE === 'global') { _certificateScope = GLOBAL } // allow override
if (process.env.CERTIFICATE_SCOPE === 'local') { _certificateScope = LOCAL } // allow override
const certificateScope = _certificateScope
// Create the Express app, the HTTPS server, and add WebSocket support.
const app = express()
const server = httpsServer.createServer({}, app)
// TODO: Add Helmet (security).
// Create the web server with either locally-trusted or globally-trusted
// certificates based on default/requested certificate scope.
const options = {global: certificateScope === GLOBAL}
const server = webServer.createServer(options, app)
// Create the Web Socket server.
expressWebSocket(app, server, { perMessageDeflate: false })
//
......@@ -30,30 +55,40 @@ app.ws('/echo', (webSocket, request) => {
// HTTPS routes go here.
//
app.get('/https-get', (request, response) => {
console.log(' 🌐 [hypha] HTTPS GET route called.')
app.get('/get', (request, response) => {
console.log(' 🌐 [hypha] GET route called.')
response.writeHeader(200, {'Content-Type': 'text/html'})
response.end('<!doctype html><html lang=\'en\'><head><meta charset=\'utf-8\'/><title>Hello</title><style>body{background-color: white; font-family: sans-serif;}</style></head><body><h1>Hypha</h1><p>Hello, I am a dynamically-served HTTPS GET route.</p></body></html>')
response.end('<!doctype html><html lang=\'en\'><head><meta charset=\'utf-8\'/><title>Hello</title><style>body{background-color: white; font-family: sans-serif;}</style></head><body><h1>Hypha</h1><p>Hello, I am a dynamically-served GET route.</p></body></html>')
})
//
// Set up @hypha/web-compiler.
//
// In development, we use it as middleware to enable live compilation and live reload.
// In production, use build a static distribution and serve it with express.static.
// In development mode, we use @ind.ie/web-compiler middleware to enable live compilation and live reload. Unless
// overriden by the CERTIFICATE_SCOPE environment variable, we serve the site using locally-trusted mkcert certificates
// seamlessly provisioned using Nodecert.
//
// In production mode, we build a single-page static distribution and serve it using express.static alongside any
// dynamic HTTPS and WebSocket routes. Unless overriden by the CERTIFICATE_SCOPE environment variable, we serve the
// site using globally-trusted Let’s Encrypt certificates seamlessly provisioned using ACME TLS.
//
const entryPoint = path.join(__dirname, '../web/index.js')
if (process.env.NODE_ENV === 'production') {
if (isRunningInProductionMode) {
//
// Production mode.
// Production mode: build a static distribution of the Hypha Web Node and serve it.
//
console.log(' 🔒 [hypha] Production mode\n')
console.log(' 🔒 [hypha] Production mode: building and serving static Hypha Web Node.\n')
// Set the base URL based on whether the CERTIFICATE_SCOPE is local or global.
// If we are using global certificate scope, we set the base URL using the hostname
// of the current machine – Indie Web Server and ACME TLS use the same convention.
const base = `https://${certificateScope === GLOBAL ? os.hostname() : 'localhost'}`
// Build the static distribution.
const build = require('@hypha/web-compiler/lib/cmd-build')
build(entryPoint, null, {base: 'https://localhost'})
build(entryPoint, null, {base})
// TODO: Extend cmd-build to emit a done event so we can listen for it.
......@@ -61,9 +96,9 @@ if (process.env.NODE_ENV === 'production') {
app.use(express.static('web/dist'))
} else {
//
// Development mode.
// Development mode: use @hypha/web-compiler as middleware with live reload.
//
console.log(' 👷 [hypha] Development mode\n')
console.log(' 👷 [hypha] Development mode: live reload is on.\n')
// Set up development mode with live compilation and reload.
const webCompilerMiddleware = require('@hypha/web-compiler/http')(entryPoint)
......
var os = require('os')
var choo = require('choo')
var app = choo()
console.log(`Running in ${process.env.NODE_ENV}.`)
const isRunningInProductionMode = process.env.NODE_ENV === 'production'
const isRunningInDevelopmentMode = !isRunningInProductionMode
if (process.env.NODE_ENV !== 'production') {
if (isRunningInDevelopmentMode) {
app.use(require('choo-devtools')())
} else {
app.use(require('choo-service-worker')())
......
......@@ -7,10 +7,11 @@ module.exports = view
function view (state, emit) {
if (state.title !== TITLE) emit(state.events.DOMTITLECHANGE, TITLE)
const hostname = document.location.hostname
const bodyClass = css('./styles/body.css')
const socket = new WebSocket('wss://localhost/echo')
const socket = new WebSocket(`wss://${hostname}/echo`)
socket.onopen = event => {
console.log('Socket open.')
socket.send('Hello, there!')
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment