forked from coolaj86/telebit.js
		
	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 | 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 | ||||||
| ======= | ======= | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										205
									
								
								bin/telebit.js
									
									
									
									
									
								
							
							
						
						
									
										205
									
								
								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) { | rawTunnel(); | ||||||
|   daplieTunnel(); |  | ||||||
| } |  | ||||||
| else { |  | ||||||
|   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 () { |   , 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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user