mirror of
				https://git.coolaj86.com/coolaj86/telebit.js.git
				synced 2025-11-04 02:32:47 +00:00 
			
		
		
		
	progress towards telebit
This commit is contained in:
		
							parent
							
								
									ca2e825fe7
								
							
						
					
					
						commit
						e8c580d115
					
				
							
								
								
									
										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
 | 
			
		||||
community_member: true            # receive infrequent relevant but non-critical updates
 | 
			
		||||
telemetry: true                   # contribute to project telemetric data
 | 
			
		||||
secret: ''                        # JWT authorization secret. Generate like so:
 | 
			
		||||
                                  #   node -e "console.log(crypto.randomBytes(16).toString('hex'))"
 | 
			
		||||
remote_options:
 | 
			
		||||
  https_redirect: false           # don't redirect http to https remotely
 | 
			
		||||
secret: ''                        # Secret with which to sign Tokens for authorization
 | 
			
		||||
token: ''                         # A signed Token for authorization
 | 
			
		||||
servernames:                      # servernames that will be forwarded here
 | 
			
		||||
  - 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
 | 
			
		||||
-----------
 | 
			
		||||
 | 
			
		||||
Installs as `stunnel.js` with the alias `jstunnel`
 | 
			
		||||
(for those that regularly use `stunnel` but still like commandline completion).
 | 
			
		||||
Installs Telebit Remote as `telebit`
 | 
			
		||||
(for those that regularly use `telebit` but still like commandline completion).
 | 
			
		||||
 | 
			
		||||
### Install
 | 
			
		||||
 | 
			
		||||
@ -162,44 +156,44 @@ npm install -g telebit
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```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:
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
stunnel.js \
 | 
			
		||||
telebit \
 | 
			
		||||
  --locals <<external domain name>> \
 | 
			
		||||
  --stunneld wss://<<tunnel domain>>:<<tunnel port>> \
 | 
			
		||||
  --relay wss://<<tunnel domain>>:<<tunnel port>> \
 | 
			
		||||
  --secret <<128-bit hex key>>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```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
 | 
			
		||||
stunnel.js \
 | 
			
		||||
telebit \
 | 
			
		||||
  --locals <<protocol>>:<<external domain name>>:<<local port>> \
 | 
			
		||||
  --stunneld wss://<<tunnel domain>>:<<tunnel port>> \
 | 
			
		||||
  --relay wss://<<tunnel domain>>:<<tunnel port>> \
 | 
			
		||||
  --secret <<128-bit hex key>>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
stunnel.js \
 | 
			
		||||
telebit \
 | 
			
		||||
  --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          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
 | 
			
		||||
                  incoming http and https should be forwarded
 | 
			
		||||
--stunneld        the domain or ip address at which you are running stunneld.js
 | 
			
		||||
-k, --insecure    ignore invalid ssl certificates from stunneld
 | 
			
		||||
--relay        the domain or ip address at which you are running Telebit Relay
 | 
			
		||||
-k, --insecure    ignore invalid ssl certificates from relay
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Node.js Library
 | 
			
		||||
@ -208,10 +202,10 @@ Node.js Library
 | 
			
		||||
### Example
 | 
			
		||||
 | 
			
		||||
```javascript
 | 
			
		||||
var stunnel = require('stunnel');
 | 
			
		||||
var Telebit = require('telebit');
 | 
			
		||||
 | 
			
		||||
stunnel.connect({
 | 
			
		||||
  stunneld: 'wss://tunnel.example.com'
 | 
			
		||||
Telebit.connect({
 | 
			
		||||
  relay: 'wss://tunnel.example.com'
 | 
			
		||||
, token: '...'
 | 
			
		||||
, locals: [
 | 
			
		||||
    // 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:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
stunnel.connect({
 | 
			
		||||
Telebit.connect({
 | 
			
		||||
  // ...
 | 
			
		||||
, net: {
 | 
			
		||||
  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
 | 
			
		||||
=======
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										205
									
								
								bin/telebit.js
									
									
									
									
									
								
							
							
						
						
									
										205
									
								
								bin/telebit.js
									
									
									
									
									
								
							@ -4,9 +4,43 @@
 | 
			
		||||
 | 
			
		||||
var pkg = require('../package.json');
 | 
			
		||||
 | 
			
		||||
var program = require('commander');
 | 
			
		||||
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 services = {};
 | 
			
		||||
@ -114,6 +148,78 @@ function collectProxies(val, 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
 | 
			
		||||
  .version(pkg.version)
 | 
			
		||||
  //.command('jsurl <url>')
 | 
			
		||||
@ -134,63 +240,22 @@ program
 | 
			
		||||
  .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() {
 | 
			
		||||
  program.stunneld = program.stunneld || 'wss://tunnel.daplie.com';
 | 
			
		||||
  program.relay = program.relay || 'wss://telebit.cloud';
 | 
			
		||||
 | 
			
		||||
  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);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  var location = url.parse(program.stunneld);
 | 
			
		||||
  var location = url.parse(program.relay);
 | 
			
		||||
  if (!location.protocol || /\./.test(location.protocol)) {
 | 
			
		||||
    program.stunneld = 'wss://' + program.stunneld;
 | 
			
		||||
    location = url.parse(program.stunneld);
 | 
			
		||||
    program.relay = 'wss://' + program.relay;
 | 
			
		||||
    location = url.parse(program.relay);
 | 
			
		||||
  }
 | 
			
		||||
  var aud = location.hostname + (location.port ? ':' + location.port : '');
 | 
			
		||||
  program.stunneld = location.protocol + '//' + aud;
 | 
			
		||||
  program.relay = location.protocol + '//' + aud;
 | 
			
		||||
 | 
			
		||||
  if (!program.token) {
 | 
			
		||||
    var jwt = require('jsonwebtoken');
 | 
			
		||||
@ -205,41 +270,6 @@ function rawTunnel() {
 | 
			
		||||
  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.forEach(function (proxy) {
 | 
			
		||||
  // 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;
 | 
			
		||||
 | 
			
		||||
if (!(program.secret || program.token) && !program.stunneld) {
 | 
			
		||||
  daplieTunnel();
 | 
			
		||||
}
 | 
			
		||||
else {
 | 
			
		||||
  rawTunnel();
 | 
			
		||||
}
 | 
			
		||||
rawTunnel();
 | 
			
		||||
 | 
			
		||||
}());
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										66
									
								
								dist/etc/systemd/system/telebitd.service
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								dist/etc/systemd/system/telebitd.service
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -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
 | 
			
		||||
							
								
								
									
										16
									
								
								examples/telebit.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								examples/telebit.yml
									
									
									
									
									
										Normal file
									
								
							@ -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
 | 
			
		||||
							
								
								
									
										8
									
								
								examples/telebit.yml.tpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								examples/telebit.yml.tpl
									
									
									
									
									
										Normal file
									
								
							@ -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'
 | 
			
		||||
							
								
								
									
										249
									
								
								installer/get.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								installer/get.sh
									
									
									
									
									
										Normal file
									
								
							@ -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 () {
 | 
			
		||||
      console.info("[open] connected to '" + copts.stunneld + "'");
 | 
			
		||||
      console.info("[open] connected to '" + copts.relay + "'");
 | 
			
		||||
      wsHandlers.refreshTimeout();
 | 
			
		||||
      timeoutId = setTimeout(wsHandlers.checkTimeout, activityTimeout);
 | 
			
		||||
 | 
			
		||||
@ -500,8 +500,8 @@ function run(copts) {
 | 
			
		||||
    timeoutId = null;
 | 
			
		||||
    var machine = require('tunnel-packer').create(packerHandlers);
 | 
			
		||||
 | 
			
		||||
    console.info("[connect] '" + copts.stunneld + "'");
 | 
			
		||||
    var tunnelUrl = copts.stunneld.replace(/\/$/, '') + '/?access_token=' + tokens[0];
 | 
			
		||||
    console.info("[connect] '" + copts.relay + "'");
 | 
			
		||||
    var tunnelUrl = copts.relay.replace(/\/$/, '') + '/?access_token=' + tokens[0];
 | 
			
		||||
    wstunneler = new WebSocket(tunnelUrl, { rejectUnauthorized: !copts.insecure });
 | 
			
		||||
    wstunneler.on('open', wsHandlers.onOpen);
 | 
			
		||||
    wstunneler.on('close', wsHandlers.onClose);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user