progress towards telebit
This commit is contained in:
parent
61947a492d
commit
b814beb6bd
55
README.md
55
README.md
|
@ -91,16 +91,10 @@ email: 'jon@example.com' # must be valid (for certificate recovery and
|
||||||
agree_tos: true # agree to the Telebit, Greenlock, and Let's Encrypt TOSes
|
agree_tos: true # agree to the Telebit, Greenlock, and Let's Encrypt TOSes
|
||||||
community_member: true # receive infrequent relevant but non-critical updates
|
community_member: true # receive infrequent relevant but non-critical updates
|
||||||
telemetry: true # contribute to project telemetric data
|
telemetry: true # contribute to project telemetric data
|
||||||
secret: '' # JWT authorization secret. Generate like so:
|
secret: '' # Secret with which to sign Tokens for authorization
|
||||||
# node -e "console.log(crypto.randomBytes(16).toString('hex'))"
|
token: '' # A signed Token for authorization
|
||||||
remote_options:
|
|
||||||
https_redirect: false # don't redirect http to https remotely
|
|
||||||
servernames: # servernames that will be forwarded here
|
servernames: # servernames that will be forwarded here
|
||||||
- example.com
|
- example.com
|
||||||
local_ports: # ports to forward
|
|
||||||
3000: 'http'
|
|
||||||
8443: 'https'
|
|
||||||
5050: true
|
|
||||||
```
|
```
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
@ -152,8 +146,8 @@ You can **integrate telebit.js into your existing codebase** or use the **standa
|
||||||
Telebit CLI
|
Telebit CLI
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
Installs as `stunnel.js` with the alias `jstunnel`
|
Installs Telebit Remote as `telebit`
|
||||||
(for those that regularly use `stunnel` but still like commandline completion).
|
(for those that regularly use `telebit` but still like commandline completion).
|
||||||
|
|
||||||
### Install
|
### Install
|
||||||
|
|
||||||
|
@ -162,44 +156,44 @@ npm install -g telebit
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm install -g 'git+https://git@git.coolaj86.com/coolaj86/tunnel-client.js.git#v1'
|
npm install -g 'https://git.coolaj86.com/coolaj86/telebit.js.git#v1'
|
||||||
```
|
```
|
||||||
|
|
||||||
Or if you want to bow down to the kings of the centralized dictator-net:
|
Or if you want to bow down to the kings of the centralized dictator-net:
|
||||||
|
|
||||||
How to use `stunnel.js` with your own instance of `stunneld.js`:
|
How to use Telebit Remote with your own instance of Telebit Relay:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
stunnel.js \
|
telebit \
|
||||||
--locals <<external domain name>> \
|
--locals <<external domain name>> \
|
||||||
--stunneld wss://<<tunnel domain>>:<<tunnel port>> \
|
--relay wss://<<tunnel domain>>:<<tunnel port>> \
|
||||||
--secret <<128-bit hex key>>
|
--secret <<128-bit hex key>>
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
stunnel.js --locals john.example.com --stunneld wss://tunnel.example.com:443 --secret abc123
|
telebit --locals john.example.com --relay wss://tunnel.example.com:443 --secret abc123
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
stunnel.js \
|
telebit \
|
||||||
--locals <<protocol>>:<<external domain name>>:<<local port>> \
|
--locals <<protocol>>:<<external domain name>>:<<local port>> \
|
||||||
--stunneld wss://<<tunnel domain>>:<<tunnel port>> \
|
--relay wss://<<tunnel domain>>:<<tunnel port>> \
|
||||||
--secret <<128-bit hex key>>
|
--secret <<128-bit hex key>>
|
||||||
```
|
```
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
stunnel.js \
|
telebit \
|
||||||
--locals http:john.example.com:3000,https:john.example.com \
|
--locals http:john.example.com:3000,https:john.example.com \
|
||||||
--stunneld wss://tunnel.example.com:443 \
|
--relay wss://tunnel.example.com:443 \
|
||||||
--secret abc123
|
--secret abc123
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
--secret the same secret used by stunneld (used for authentication)
|
--secret the same secret used by the Telebit Relay (for authentication)
|
||||||
--locals comma separated list of <proto>:<servername>:<port> to which
|
--locals comma separated list of <proto>:<servername>:<port> to which
|
||||||
incoming http and https should be forwarded
|
incoming http and https should be forwarded
|
||||||
--stunneld the domain or ip address at which you are running stunneld.js
|
--relay the domain or ip address at which you are running Telebit Relay
|
||||||
-k, --insecure ignore invalid ssl certificates from stunneld
|
-k, --insecure ignore invalid ssl certificates from relay
|
||||||
```
|
```
|
||||||
|
|
||||||
Node.js Library
|
Node.js Library
|
||||||
|
@ -208,10 +202,10 @@ Node.js Library
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
var stunnel = require('stunnel');
|
var Telebit = require('telebit');
|
||||||
|
|
||||||
stunnel.connect({
|
Telebit.connect({
|
||||||
stunneld: 'wss://tunnel.example.com'
|
relay: 'wss://tunnel.example.com'
|
||||||
, token: '...'
|
, token: '...'
|
||||||
, locals: [
|
, locals: [
|
||||||
// defaults to sending http to local port 80 and https to local port 443
|
// defaults to sending http to local port 80 and https to local port 443
|
||||||
|
@ -251,7 +245,7 @@ local handler and the tunnel handler.
|
||||||
You could do a little magic like this:
|
You could do a little magic like this:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
stunnel.connect({
|
Telebit.connect({
|
||||||
// ...
|
// ...
|
||||||
, net: {
|
, net: {
|
||||||
createConnection: function (info, cb) {
|
createConnection: function (info, cb) {
|
||||||
|
@ -286,6 +280,15 @@ stunnel.connect({
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
TODO
|
||||||
|
====
|
||||||
|
|
||||||
|
Install for user
|
||||||
|
* https://wiki.archlinux.org/index.php/Systemd/User
|
||||||
|
* https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html
|
||||||
|
* `sudo launchctl load -w ~/Library/LaunchAgents/cloud.telebit.remote`
|
||||||
|
* https://serverfault.com/questions/194832/how-to-start-stop-restart-launchd-services-from-the-command-line
|
||||||
|
|
||||||
Browser Library
|
Browser Library
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
|
203
bin/telebit.js
203
bin/telebit.js
|
@ -4,9 +4,43 @@
|
||||||
|
|
||||||
var pkg = require('../package.json');
|
var pkg = require('../package.json');
|
||||||
|
|
||||||
var program = require('commander');
|
|
||||||
var url = require('url');
|
var url = require('url');
|
||||||
var stunnel = require('../wsclient.js');
|
var remote = require('../wsclient.js');
|
||||||
|
|
||||||
|
var argv = process.argv.slice(2);
|
||||||
|
//var Greenlock = require('greenlock');
|
||||||
|
|
||||||
|
var confIndex = argv.indexOf('--config');
|
||||||
|
var confpath;
|
||||||
|
if (-1 === confIndex) {
|
||||||
|
confIndex = argv.indexOf('-c');
|
||||||
|
}
|
||||||
|
confpath = argv[confIndex + 1];
|
||||||
|
|
||||||
|
function help() {
|
||||||
|
console.info('');
|
||||||
|
console.info('Usage:');
|
||||||
|
console.info('');
|
||||||
|
console.info('\ttelebit --config <path>');
|
||||||
|
console.info('');
|
||||||
|
console.info('Example:');
|
||||||
|
console.info('');
|
||||||
|
console.info('\ttelebit --config /etc/telebit/telebit.yml');
|
||||||
|
console.info('');
|
||||||
|
console.info('Config:');
|
||||||
|
console.info('');
|
||||||
|
console.info('\tSee https://git.coolaj86.com/coolaj86/telebit.js');
|
||||||
|
console.info('');
|
||||||
|
console.info('');
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-1 === confIndex || -1 !== argv.indexOf('-h') || -1 !== argv.indexOf('--help')) {
|
||||||
|
help();
|
||||||
|
}
|
||||||
|
if (!confpath || /^--/.test(confpath)) {
|
||||||
|
help();
|
||||||
|
}
|
||||||
|
|
||||||
var domainsMap = {};
|
var domainsMap = {};
|
||||||
var services = {};
|
var services = {};
|
||||||
|
@ -114,6 +148,78 @@ function collectProxies(val, memo) {
|
||||||
return memo;
|
return memo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function connectTunnel() {
|
||||||
|
var state = {};
|
||||||
|
var services = { https: {}, http: {}, tcp: {} };
|
||||||
|
state.net = {
|
||||||
|
createConnection: function (info, cb) {
|
||||||
|
// data is the hello packet / first chunk
|
||||||
|
// info = { data, servername, port, host, remoteFamily, remoteAddress, remotePort }
|
||||||
|
var net = require('net');
|
||||||
|
// socket = { write, push, end, events: [ 'readable', 'data', 'error', 'end' ] };
|
||||||
|
var socket = net.createConnection({ port: info.port, host: info.host }, cb);
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Note: the remote needs to know:
|
||||||
|
// what servernames to forward
|
||||||
|
// what ports to forward
|
||||||
|
// what udp ports to forward
|
||||||
|
// redirect http to https automatically
|
||||||
|
// redirect www to nowww automatically
|
||||||
|
Object.keys(state.config.localPorts).forEach(function (port) {
|
||||||
|
var proto = state.config.localPorts[port];
|
||||||
|
if (!proto) { return; }
|
||||||
|
if ('http' === proto) {
|
||||||
|
state.config.servernames.forEach(function (servername) {
|
||||||
|
services.http[servername] = port;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ('https' === proto) {
|
||||||
|
state.config.servernames.forEach(function (servername) {
|
||||||
|
services.https[servername] = port;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (true === proto) { proto = 'tcp'; }
|
||||||
|
if ('tcp' !== proto) { throw new Error("unsupported protocol '" + proto + "'"); }
|
||||||
|
//services[proxy.protocol]['*'] = proxy.port;
|
||||||
|
//services[proxy.protocol][proxy.hostname] = proxy.port;
|
||||||
|
services[proto]['*'] = port;
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.keys(program.services).forEach(function (protocol) {
|
||||||
|
var subServices = program.services[protocol];
|
||||||
|
Object.keys(subServices).forEach(function (hostname) {
|
||||||
|
console.info('[local proxy]', protocol + '://' + hostname + ' => ' + subServices[hostname]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
console.info('');
|
||||||
|
|
||||||
|
var tun = remote.connect({
|
||||||
|
relay: state.config.relay
|
||||||
|
, locals: state.config.servernames
|
||||||
|
, services: state.services
|
||||||
|
, net: state.net
|
||||||
|
, insecure: state.config.relay_ignore_invalid_certificates
|
||||||
|
, token: state.config.token
|
||||||
|
});
|
||||||
|
|
||||||
|
function sigHandler() {
|
||||||
|
console.log('SIGINT');
|
||||||
|
|
||||||
|
// We want to handle cleanup properly unless something is broken in our cleanup process
|
||||||
|
// that prevents us from exitting, in which case we want the user to be able to send
|
||||||
|
// the signal again and exit the way it normally would.
|
||||||
|
process.removeListener('SIGINT', sigHandler);
|
||||||
|
tun.end();
|
||||||
|
}
|
||||||
|
process.on('SIGINT', sigHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
var program = require('commander');
|
||||||
program
|
program
|
||||||
.version(pkg.version)
|
.version(pkg.version)
|
||||||
//.command('jsurl <url>')
|
//.command('jsurl <url>')
|
||||||
|
@ -134,63 +240,22 @@ program
|
||||||
.parse(process.argv)
|
.parse(process.argv)
|
||||||
;
|
;
|
||||||
|
|
||||||
function connectTunnel() {
|
|
||||||
program.net = {
|
|
||||||
createConnection: function (info, cb) {
|
|
||||||
// data is the hello packet / first chunk
|
|
||||||
// info = { data, servername, port, host, remoteFamily, remoteAddress, remotePort }
|
|
||||||
var net = require('net');
|
|
||||||
// socket = { write, push, end, events: [ 'readable', 'data', 'error', 'end' ] };
|
|
||||||
var socket = net.createConnection({ port: info.port, host: info.host }, cb);
|
|
||||||
return socket;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.keys(program.services).forEach(function (protocol) {
|
|
||||||
var subServices = program.services[protocol];
|
|
||||||
Object.keys(subServices).forEach(function (hostname) {
|
|
||||||
console.info('[local proxy]', protocol + '://' + hostname + ' => ' + subServices[hostname]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
console.info('');
|
|
||||||
|
|
||||||
var tun = stunnel.connect({
|
|
||||||
stunneld: program.stunneld
|
|
||||||
, locals: program.locals
|
|
||||||
, services: program.services
|
|
||||||
, net: program.net
|
|
||||||
, insecure: program.insecure
|
|
||||||
, token: program.token
|
|
||||||
});
|
|
||||||
|
|
||||||
function sigHandler() {
|
|
||||||
console.log('SIGINT');
|
|
||||||
|
|
||||||
// We want to handle cleanup properly unless something is broken in our cleanup process
|
|
||||||
// that prevents us from exitting, in which case we want the user to be able to send
|
|
||||||
// the signal again and exit the way it normally would.
|
|
||||||
process.removeListener('SIGINT', sigHandler);
|
|
||||||
tun.end();
|
|
||||||
}
|
|
||||||
process.on('SIGINT', sigHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
function rawTunnel() {
|
function rawTunnel() {
|
||||||
program.stunneld = program.stunneld || 'wss://tunnel.daplie.com';
|
program.relay = program.relay || 'wss://telebit.cloud';
|
||||||
|
|
||||||
if (!(program.secret || program.token)) {
|
if (!(program.secret || program.token)) {
|
||||||
console.error("You must use --secret or --token with --stunneld");
|
console.error("You must use --secret or --token with --relay");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var location = url.parse(program.stunneld);
|
var location = url.parse(program.relay);
|
||||||
if (!location.protocol || /\./.test(location.protocol)) {
|
if (!location.protocol || /\./.test(location.protocol)) {
|
||||||
program.stunneld = 'wss://' + program.stunneld;
|
program.relay = 'wss://' + program.relay;
|
||||||
location = url.parse(program.stunneld);
|
location = url.parse(program.relay);
|
||||||
}
|
}
|
||||||
var aud = location.hostname + (location.port ? ':' + location.port : '');
|
var aud = location.hostname + (location.port ? ':' + location.port : '');
|
||||||
program.stunneld = location.protocol + '//' + aud;
|
program.relay = location.protocol + '//' + aud;
|
||||||
|
|
||||||
if (!program.token) {
|
if (!program.token) {
|
||||||
var jwt = require('jsonwebtoken');
|
var jwt = require('jsonwebtoken');
|
||||||
|
@ -205,41 +270,6 @@ function rawTunnel() {
|
||||||
connectTunnel();
|
connectTunnel();
|
||||||
}
|
}
|
||||||
|
|
||||||
function daplieTunnel() {
|
|
||||||
//var OAUTH3 = require('oauth3.js');
|
|
||||||
var Oauth3Cli = require('oauth3.js/bin/oauth3.js');
|
|
||||||
require('oauth3.js/oauth3.tunnel.js');
|
|
||||||
return Oauth3Cli.login({
|
|
||||||
email: program.email
|
|
||||||
, providerUri: program.oauth3Url || 'oauth3.org'
|
|
||||||
}).then(function (oauth3) {
|
|
||||||
var data = { device: null, domains: [] };
|
|
||||||
var domains = Object.keys(domainsMap).filter(Boolean);
|
|
||||||
if (program.device) {
|
|
||||||
// TODO use device API to select device by id
|
|
||||||
data.device = { hostname: program.device };
|
|
||||||
if (true === program.device) {
|
|
||||||
data.device.hostname = require('os').hostname();
|
|
||||||
console.log("Using device hostname '" + data.device.hostname + "'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (domains.length) {
|
|
||||||
data.domains = domains;
|
|
||||||
}
|
|
||||||
return oauth3.api('tunnel.token', { data: data }).then(function (results) {
|
|
||||||
var token = new Buffer(results.jwt.split('.')[1], 'base64').toString('utf8');
|
|
||||||
console.info('');
|
|
||||||
console.info('tunnel token issued:');
|
|
||||||
console.info(token);
|
|
||||||
console.info('');
|
|
||||||
program.token = results.jwt;
|
|
||||||
program.stunneld = results.tunnelUrl || ('wss://' + token.aud + '/');
|
|
||||||
|
|
||||||
connectTunnel();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
program.locals = (program.locals || []).concat(program.domains || []);
|
program.locals = (program.locals || []).concat(program.domains || []);
|
||||||
program.locals.forEach(function (proxy) {
|
program.locals.forEach(function (proxy) {
|
||||||
// Create a map from which we can derive a list of all domains we want forwarded to us.
|
// Create a map from which we can derive a list of all domains we want forwarded to us.
|
||||||
|
@ -282,11 +312,6 @@ services.http['*'] = services.http['*'] || services.https['*'];
|
||||||
|
|
||||||
program.services = services;
|
program.services = services;
|
||||||
|
|
||||||
if (!(program.secret || program.token) && !program.stunneld) {
|
|
||||||
daplieTunnel();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
rawTunnel();
|
rawTunnel();
|
||||||
}
|
|
||||||
|
|
||||||
}());
|
}());
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
# Pre-req
|
||||||
|
# sudo adduser telebit --home /opt/telebit
|
||||||
|
# sudo mkdir -p /opt/telebit/
|
||||||
|
# sudo chown -R telebit:telebit /opt/telebit/
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Description=Telebit Relay
|
||||||
|
Documentation=https://git.coolaj86.com/coolaj86/telebit.js/
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target systemd-networkd-wait-online.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
# Restart on crash (bad signal), but not on 'clean' failure (error exit code)
|
||||||
|
# Allow up to 3 restarts within 10 seconds
|
||||||
|
# (it's unlikely that a user or properly-running script will do this)
|
||||||
|
Restart=on-abnormal
|
||||||
|
StartLimitInterval=10
|
||||||
|
StartLimitBurst=3
|
||||||
|
|
||||||
|
# User and group the process will run as
|
||||||
|
# (git is the de facto standard on most systems)
|
||||||
|
User=telebit
|
||||||
|
Group=telebit
|
||||||
|
|
||||||
|
WorkingDirectory=/opt/telebit
|
||||||
|
# custom directory cannot be set and will be the place where gitea exists, not the working directory
|
||||||
|
ExecStart=/opt/telebit/bin/node /opt/telebit/bin/telebit.js --config /etc/telebit/telebit.yml
|
||||||
|
ExecReload=/bin/kill -USR1 $MAINPID
|
||||||
|
|
||||||
|
# Limit the number of file descriptors and processes; see `man systemd.exec` for more limit settings.
|
||||||
|
# Unmodified gitea is not expected to use more than this.
|
||||||
|
LimitNOFILE=1048576
|
||||||
|
LimitNPROC=64
|
||||||
|
|
||||||
|
# Use private /tmp and /var/tmp, which are discarded after gitea stops.
|
||||||
|
PrivateTmp=true
|
||||||
|
# Use a minimal /dev
|
||||||
|
PrivateDevices=true
|
||||||
|
# Hide /home, /root, and /run/user. Nobody will steal your SSH-keys.
|
||||||
|
ProtectHome=true
|
||||||
|
# Make /usr, /boot, /etc and possibly some more folders read-only.
|
||||||
|
ProtectSystem=full
|
||||||
|
# ... except /opt/gitea because we want a place for the database
|
||||||
|
# and /var/log/gitea because we want a place where logs can go.
|
||||||
|
# This merely retains r/w access rights, it does not add any new.
|
||||||
|
# Must still be writable on the host!
|
||||||
|
ReadWriteDirectories=/opt/telebit /etc/telebit
|
||||||
|
|
||||||
|
# Note: in v231 and above ReadWritePaths has been renamed to ReadWriteDirectories
|
||||||
|
; ReadWritePaths=/opt/telebit /etc/telebit
|
||||||
|
|
||||||
|
# The following additional security directives only work with systemd v229 or later.
|
||||||
|
# They further retrict privileges that can be gained by gitea.
|
||||||
|
# Note that you may have to add capabilities required by any plugins in use.
|
||||||
|
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||||
|
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||||
|
NoNewPrivileges=true
|
||||||
|
|
||||||
|
# Caveat: Some features may need additional capabilities.
|
||||||
|
# For example an "upload" may need CAP_LEASE
|
||||||
|
; CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_LEASE
|
||||||
|
; AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_LEASE
|
||||||
|
; NoNewPrivileges=true
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
|
@ -0,0 +1,16 @@
|
||||||
|
email: 'jon@example.com' # must be valid (for certificate recovery and security alerts)
|
||||||
|
agree_tos: true # agree to the Telebit, Greenlock, and Let's Encrypt TOSes
|
||||||
|
community_member: true # receive infrequent relevant updates
|
||||||
|
telemetry: true # contribute to project telemetric data
|
||||||
|
relay: wss://telebit.cloud # Which Telebit Relay to use
|
||||||
|
secret: '' # Token or Secret to use for authorization
|
||||||
|
token: '' # Token or Secret to use for authorization
|
||||||
|
remote_options:
|
||||||
|
https_redirect: true # redirect http to https remotely (default)
|
||||||
|
servernames: # hostnames that direct to the Telebit Relay admin console
|
||||||
|
- example.com
|
||||||
|
- example.net
|
||||||
|
local_ports: # ports to forward
|
||||||
|
3000: 'http'
|
||||||
|
8443: 'https'
|
||||||
|
5050: true
|
|
@ -0,0 +1,8 @@
|
||||||
|
agree_tos: true # agree to the Telebit, Greenlock, and Let's Encrypt TOSes
|
||||||
|
community_member: true # receive infrequent relevant updates
|
||||||
|
telemetry: true # contribute to project telemetric data
|
||||||
|
remote_options:
|
||||||
|
https_redirect: true # redirect http to https remotely (default)
|
||||||
|
local_ports: # ports to forward
|
||||||
|
3001: 'http'
|
||||||
|
9443: 'https'
|
|
@ -0,0 +1,249 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#<pre><code>
|
||||||
|
|
||||||
|
# This is a 3 step process
|
||||||
|
# 1. First we need to figure out whether to use wget or curl for fetching remote files
|
||||||
|
# 2. Next we need to figure out whether to use unzip or tar for downloading releases
|
||||||
|
# 3. We need to actually install the stuff
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -u
|
||||||
|
|
||||||
|
###############################
|
||||||
|
# #
|
||||||
|
# http_get #
|
||||||
|
# boilerplate for curl / wget #
|
||||||
|
# #
|
||||||
|
###############################
|
||||||
|
|
||||||
|
# See https://git.coolaj86.com/coolaj86/snippets/blob/master/bash/http-get.sh
|
||||||
|
|
||||||
|
_my_http_get=""
|
||||||
|
_my_http_opts=""
|
||||||
|
_my_http_out=""
|
||||||
|
|
||||||
|
detect_http_get()
|
||||||
|
{
|
||||||
|
set +e
|
||||||
|
if type -p curl >/dev/null 2>&1; then
|
||||||
|
_my_http_get="curl"
|
||||||
|
_my_http_opts="-fsSL"
|
||||||
|
_my_http_out="-o"
|
||||||
|
elif type -p wget >/dev/null 2>&1; then
|
||||||
|
_my_http_get="wget"
|
||||||
|
_my_http_opts="--quiet"
|
||||||
|
_my_http_out="-O"
|
||||||
|
else
|
||||||
|
echo "Aborted, could not find curl or wget"
|
||||||
|
return 7
|
||||||
|
fi
|
||||||
|
set -e
|
||||||
|
}
|
||||||
|
|
||||||
|
http_get()
|
||||||
|
{
|
||||||
|
$_my_http_get $_my_http_opts $_my_http_out "$2" "$1"
|
||||||
|
touch "$2"
|
||||||
|
}
|
||||||
|
|
||||||
|
http_bash()
|
||||||
|
{
|
||||||
|
_http_url=$1
|
||||||
|
my_args=${2:-}
|
||||||
|
rm -rf my-tmp-runner.sh
|
||||||
|
$_my_http_get $_my_http_opts $_my_http_out my-tmp-runner.sh "$_http_url"; bash my-tmp-runner.sh $my_args; rm my-tmp-runner.sh
|
||||||
|
}
|
||||||
|
|
||||||
|
detect_http_get
|
||||||
|
|
||||||
|
###############################
|
||||||
|
## END HTTP_GET ##
|
||||||
|
###############################
|
||||||
|
|
||||||
|
my_email=${1:-}
|
||||||
|
my_relay=${2:-}
|
||||||
|
my_servernames=${3:-}
|
||||||
|
my_secret=${4:-}
|
||||||
|
my_user="telebit"
|
||||||
|
my_app="telebit"
|
||||||
|
my_bin="telebit.js"
|
||||||
|
my_name="Telebit Remote"
|
||||||
|
my_repo="telebit.js"
|
||||||
|
|
||||||
|
if [ -z "${my_email}" ]; then
|
||||||
|
echo ""
|
||||||
|
echo ""
|
||||||
|
echo "Telebit uses Greenlock for free automated ssl through Let's Encrypt."
|
||||||
|
echo ""
|
||||||
|
echo "To accept the Terms of Service for Telebit, Greenlock and Let's Encrypt,"
|
||||||
|
echo "please enter your email."
|
||||||
|
echo ""
|
||||||
|
read -p "email: " my_email
|
||||||
|
echo ""
|
||||||
|
# UX - just want a smooth transition
|
||||||
|
sleep 0.5
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "${my_relay}" ]; then
|
||||||
|
echo "What relay will you be using?"
|
||||||
|
echo ""
|
||||||
|
read -p "relay (ex: wss://telebit.cloud): " my_relay
|
||||||
|
echo ""
|
||||||
|
# UX - just want a smooth transition
|
||||||
|
sleep 0.5
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "${my_servernames}" ]; then
|
||||||
|
echo "What servername(s) will you be relaying here?"
|
||||||
|
echo ""
|
||||||
|
read -p "domain (ex: example.com,example.net): " my_servernames
|
||||||
|
echo ""
|
||||||
|
# UX - just want a smooth transition
|
||||||
|
sleep 0.5
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "${my_secret}" ]; then
|
||||||
|
echo "What's your authorization for the relay server?"
|
||||||
|
echo ""
|
||||||
|
read -p "auth: " my_secret
|
||||||
|
echo ""
|
||||||
|
# UX - just want a smooth transition
|
||||||
|
sleep 0.5
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if [ -z "${TELEBIT_PATH:-}" ]; then
|
||||||
|
echo 'TELEBIT_PATH="'${TELEBIT_PATH:-}'"'
|
||||||
|
TELEBIT_PATH=/opt/$my_app
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Installing $my_name to '$TELEBIT_PATH'"
|
||||||
|
|
||||||
|
echo "Installing node.js dependencies into $TELEBIT_PATH"
|
||||||
|
# v10.2+ has much needed networking fixes, but breaks ursa. v9.x has severe networking bugs. v8.x has working ursa, but requires tls workarounds"
|
||||||
|
NODEJS_VER="${NODEJS_VER:-v10}"
|
||||||
|
export NODEJS_VER
|
||||||
|
export NODE_PATH="$TELEBIT_PATH/lib/node_modules"
|
||||||
|
export NPM_CONFIG_PREFIX="$TELEBIT_PATH"
|
||||||
|
export PATH="$TELEBIT_PATH/bin:$PATH"
|
||||||
|
sleep 1
|
||||||
|
http_bash https://git.coolaj86.com/coolaj86/node-installer.sh/raw/branch/master/install.sh --no-dev-deps >/dev/null 2>/dev/null
|
||||||
|
|
||||||
|
my_tree="master"
|
||||||
|
my_node="$TELEBIT_PATH/bin/node"
|
||||||
|
my_secret=$($my_node -e "console.info(crypto.randomBytes(16).toString('hex'))")
|
||||||
|
my_npm="$my_node $TELEBIT_PATH/bin/npm"
|
||||||
|
my_tmp="$TELEBIT_PATH/tmp"
|
||||||
|
mkdir -p $my_tmp
|
||||||
|
|
||||||
|
echo "sudo mkdir -p '$TELEBIT_PATH'"
|
||||||
|
sudo mkdir -p "$TELEBIT_PATH"
|
||||||
|
echo "sudo mkdir -p '/etc/$my_user/'"
|
||||||
|
sudo mkdir -p "/etc/$my_user/"
|
||||||
|
|
||||||
|
set +e
|
||||||
|
#https://git.coolaj86.com/coolaj86/telebit.js.git
|
||||||
|
#https://git.coolaj86.com/coolaj86/telebit.js/archive/:tree:.tar.gz
|
||||||
|
#https://git.coolaj86.com/coolaj86/telebit.js/archive/:tree:.zip
|
||||||
|
my_unzip=$(type -p unzip)
|
||||||
|
my_tar=$(type -p tar)
|
||||||
|
if [ -n "$my_unzip" ]; then
|
||||||
|
rm -f $my_tmp/$my_app-$my_tree.zip
|
||||||
|
http_get https://git.coolaj86.com/coolaj86/$my_repo/archive/$my_tree.zip $my_tmp/$my_app-$my_tree.zip
|
||||||
|
# -o means overwrite, and there is no option to strip
|
||||||
|
$my_unzip -o $my_tmp/$my_app-$my_tree.zip -d $TELEBIT_PATH/ > /dev/null 2>&1
|
||||||
|
cp -ar $TELEBIT_PATH/$my_repo/* $TELEBIT_PATH/ > /dev/null
|
||||||
|
rm -rf $TELEBIT_PATH/$my_bin
|
||||||
|
elif [ -n "$my_tar" ]; then
|
||||||
|
rm -f $my_tmp/$my_app-$my_tree.tar.gz
|
||||||
|
http_get https://git.coolaj86.com/coolaj86/$my_repo/archive/$my_tree.tar.gz $my_tmp/$my_app-$my_tree.tar.gz
|
||||||
|
ls -lah $my_tmp/$my_app-$my_tree.tar.gz
|
||||||
|
$my_tar -xzf $my_tmp/$my_app-$my_tree.tar.gz --strip 1 -C $TELEBIT_PATH/
|
||||||
|
else
|
||||||
|
echo "Neither tar nor unzip found. Abort."
|
||||||
|
exit 13
|
||||||
|
fi
|
||||||
|
set -e
|
||||||
|
|
||||||
|
pushd $TELEBIT_PATH >/dev/null
|
||||||
|
$my_npm install >/dev/null 2>/dev/null
|
||||||
|
popd >/dev/null
|
||||||
|
|
||||||
|
cat << EOF > $TELEBIT_PATH/bin/$my_app
|
||||||
|
#!/bin/bash
|
||||||
|
$my_node $TELEBIT_PATH/bin/$my_bin
|
||||||
|
EOF
|
||||||
|
chmod a+x $TELEBIT_PATH/bin/$my_app
|
||||||
|
echo "sudo ln -sf $TELEBIT_PATH/bin/$my_app /usr/local/bin/$my_app"
|
||||||
|
sudo ln -sf $TELEBIT_PATH/bin/$my_app /usr/local/bin/$my_app
|
||||||
|
|
||||||
|
set +e
|
||||||
|
if type -p setcap >/dev/null 2>&1; then
|
||||||
|
#echo "Setting permissions to allow $my_app to run on port 80 and port 443 without sudo or root"
|
||||||
|
echo "sudo setcap cap_net_bind_service=+ep $TELEBIT_PATH/bin/node"
|
||||||
|
sudo setcap cap_net_bind_service=+ep $TELEBIT_PATH/bin/node
|
||||||
|
fi
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ -z "$(cat /etc/passwd | grep $my_user)" ]; then
|
||||||
|
echo "sudo adduser --home $TELEBIT_PATH --gecos '' --disabled-password $my_user"
|
||||||
|
sudo adduser --home $TELEBIT_PATH --gecos '' --disabled-password $my_user >/dev/null 2>&1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "/etc/$my_user/$my_app.yml" ]; then
|
||||||
|
echo "### Creating config file from template. sudo may be required"
|
||||||
|
#echo "sudo rsync -a examples/$my_app.yml /etc/$my_user/$my_app.yml"
|
||||||
|
sudo bash -c "echo 'email: $my_email' >> /etc/$my_user/$my_app.yml"
|
||||||
|
sudo bash -c "echo 'secret: $my_secret' >> /etc/$my_user/$my_app.yml"
|
||||||
|
sudo bash -c "echo 'servernames: [ $my_servernames ]' >> /etc/$my_user/$my_app.yml"
|
||||||
|
sudo bash -c "cat examples/$my_app.yml.tpl >> /etc/$my_user/$my_app.yml"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "sudo chown -R $my_user '$TELEBIT_PATH' '/etc/$my_user'"
|
||||||
|
sudo chown -R $my_user "$TELEBIT_PATH" "/etc/$my_user"
|
||||||
|
|
||||||
|
echo "### Adding $my_app is a system service"
|
||||||
|
echo "sudo rsync -a $TELEBIT_PATH/dist/etc/systemd/system/$my_app.service /etc/systemd/system/$my_app.service"
|
||||||
|
sudo rsync -a $TELEBIT_PATH/dist/etc/systemd/system/$my_app.service /etc/systemd/system/$my_app.service
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
echo "sudo systemctl enable $my_app"
|
||||||
|
sudo systemctl enable $my_app
|
||||||
|
echo "sudo systemctl start $my_app"
|
||||||
|
sudo systemctl restart $my_app
|
||||||
|
|
||||||
|
sleep 1
|
||||||
|
echo ""
|
||||||
|
echo ""
|
||||||
|
echo ""
|
||||||
|
echo "=============================================="
|
||||||
|
echo " Privacy Settings in Config"
|
||||||
|
echo "=============================================="
|
||||||
|
echo ""
|
||||||
|
echo "The example config file /etc/$my_user/$my_app.yml opts-in to"
|
||||||
|
echo "contributing telemetrics and receiving infrequent relevant updates"
|
||||||
|
echo "(probably once per quarter or less) such as important notes on"
|
||||||
|
echo "a new release, an important API change, etc. No spam."
|
||||||
|
echo ""
|
||||||
|
echo "Please edit the config file to meet your needs before starting."
|
||||||
|
echo ""
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo ""
|
||||||
|
echo "=============================================="
|
||||||
|
echo "Installed successfully. Last steps:"
|
||||||
|
echo "=============================================="
|
||||||
|
echo ""
|
||||||
|
echo "Edit the config and restart, if desired:"
|
||||||
|
echo ""
|
||||||
|
echo " sudo vim /etc/$my_user/$my_app.yml"
|
||||||
|
echo " sudo systemctl restart $my_app"
|
||||||
|
echo ""
|
||||||
|
echo "Or disabled the service and start manually:"
|
||||||
|
echo ""
|
||||||
|
echo " sudo systemctl stop $my_app"
|
||||||
|
echo " sudo systemctl disable $my_app"
|
||||||
|
echo " $my_app --config /etc/$my_user/$my_app.yml"
|
||||||
|
echo ""
|
||||||
|
sleep 1
|
|
@ -415,7 +415,7 @@ function run(copts) {
|
||||||
}
|
}
|
||||||
|
|
||||||
, onOpen: function () {
|
, onOpen: function () {
|
||||||
console.info("[open] connected to '" + copts.stunneld + "'");
|
console.info("[open] connected to '" + copts.relay + "'");
|
||||||
wsHandlers.refreshTimeout();
|
wsHandlers.refreshTimeout();
|
||||||
timeoutId = setTimeout(wsHandlers.checkTimeout, activityTimeout);
|
timeoutId = setTimeout(wsHandlers.checkTimeout, activityTimeout);
|
||||||
|
|
||||||
|
@ -500,8 +500,8 @@ function run(copts) {
|
||||||
timeoutId = null;
|
timeoutId = null;
|
||||||
var machine = require('tunnel-packer').create(packerHandlers);
|
var machine = require('tunnel-packer').create(packerHandlers);
|
||||||
|
|
||||||
console.info("[connect] '" + copts.stunneld + "'");
|
console.info("[connect] '" + copts.relay + "'");
|
||||||
var tunnelUrl = copts.stunneld.replace(/\/$/, '') + '/?access_token=' + tokens[0];
|
var tunnelUrl = copts.relay.replace(/\/$/, '') + '/?access_token=' + tokens[0];
|
||||||
wstunneler = new WebSocket(tunnelUrl, { rejectUnauthorized: !copts.insecure });
|
wstunneler = new WebSocket(tunnelUrl, { rejectUnauthorized: !copts.insecure });
|
||||||
wstunneler.on('open', wsHandlers.onOpen);
|
wstunneler.on('open', wsHandlers.onOpen);
|
||||||
wstunneler.on('close', wsHandlers.onClose);
|
wstunneler.on('close', wsHandlers.onClose);
|
||||||
|
|
Loading…
Reference in New Issue