Configuration file / token-based auth support #95
@@ -43,11 +43,25 @@ You will be assigned a URL similar to `heavy-puma-9.sub.example.com:1234`.
|
|||||||
|
|
||||||
If your server is acting as a reverse proxy (i.e. nginx) and is able to listen on port 80, then you do not need the `:1234` part of the hostname for the `lt` client.
|
If your server is acting as a reverse proxy (i.e. nginx) and is able to listen on port 80, then you do not need the `:1234` part of the hostname for the `lt` client.
|
||||||
|
|
||||||
|
### configuration
|
||||||
|
|
||||||
|
The localtunnel server can also be configured with an _optional_, YAML-based configuration file (`localtunnel.yml`). When launched, the server will work its way up the file tree in search of this file (starting from the current working directory). An example is shown below.
|
||||||
|
|
||||||
|
```
|
||||||
|
port: 3000
|
||||||
|
domain: server.com
|
||||||
|
secure: true
|
||||||
|
require_token: true
|
||||||
|
tokens:
|
||||||
|
# John Doe
|
||||||
|
- VJtD3D6BXi9mZmqFT9ezAYq9fLjwUQ4WPZWUiaopRsy3HvMotRdhgbwiCuzrnhYv
|
||||||
|
```
|
||||||
|
|
||||||
## REST API
|
## REST API
|
||||||
|
|
||||||
### POST /api/tunnels
|
### POST /api/tunnels
|
||||||
|
|
||||||
Create a new tunnel. A LocalTunnel client posts to this enpoint to request a new tunnel with a specific name or a randomly assigned name.
|
Create a new tunnel. A LocalTunnel client posts to this endpoint to request a new tunnel with a specific name or a randomly assigned name.
|
||||||
|
|
||||||
### GET /api/status
|
### GET /api/status
|
||||||
|
|
||||||
|
|||||||
+7
-3
@@ -2,15 +2,15 @@
|
|||||||
|
|
||||||
import 'localenv';
|
import 'localenv';
|
||||||
import optimist from 'optimist';
|
import optimist from 'optimist';
|
||||||
|
|
||||||
import log from 'book';
|
import log from 'book';
|
||||||
import Debug from 'debug';
|
import Debug from 'debug';
|
||||||
|
|
||||||
import CreateServer from '../server';
|
import CreateServer from '../server';
|
||||||
|
import config from '../lib/config';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
const debug = Debug('localtunnel');
|
const debug = Debug('localtunnel');
|
||||||
|
|
||||||
const argv = optimist
|
let argv = optimist
|
||||||
.usage('Usage: $0 --port [num]')
|
.usage('Usage: $0 --port [num]')
|
||||||
.options('secure', {
|
.options('secure', {
|
||||||
default: false,
|
default: false,
|
||||||
@@ -38,10 +38,14 @@ if (argv.help) {
|
|||||||
process.exit();
|
process.exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
argv = _.merge(argv, config);
|
||||||
|
|
||||||
const server = CreateServer({
|
const server = CreateServer({
|
||||||
max_tcp_sockets: argv['max-sockets'],
|
max_tcp_sockets: argv['max-sockets'],
|
||||||
secure: argv.secure,
|
secure: argv.secure,
|
||||||
domain: argv.domain,
|
domain: argv.domain,
|
||||||
|
require_token: argv.require_token,
|
||||||
|
tokens: argv.tokens
|
||||||
});
|
});
|
||||||
|
|
||||||
server.listen(argv.port, argv.address, () => {
|
server.listen(argv.port, argv.address, () => {
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import findup from 'find-up';
|
||||||
|
import yaml from 'js-yaml';
|
||||||
|
import deepFreeze from 'deep-freeze';
|
||||||
|
import fs from 'fs';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
let config = {};
|
||||||
|
|
||||||
|
let configFile = findup.sync('localtunnel.yaml') || findup.sync('localtunnel.yml');
|
||||||
|
|
||||||
|
if (configFile) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
config = yaml.safeLoad(fs.readFileSync(configFile, 'utf8'));
|
||||||
|
} catch(e) {
|
||||||
|
const err = new Error(`Unable to load config file: ${configFile}`);
|
||||||
|
err.code = 'CONFIG_LOAD_ERROR';
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_.defaultsDeep(config, {
|
||||||
|
'require_token': false,
|
||||||
|
'tokens': []
|
||||||
|
});
|
||||||
|
|
||||||
|
config = deepFreeze(config || {});
|
||||||
|
|
||||||
|
export default config;
|
||||||
@@ -9,13 +9,18 @@
|
|||||||
"url": "git://github.com/localtunnel/server.git"
|
"url": "git://github.com/localtunnel/server.git"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"bluebird": "3.5.1",
|
||||||
"book": "1.3.3",
|
"book": "1.3.3",
|
||||||
"debug": "3.1.0",
|
"debug": "3.1.0",
|
||||||
|
"deep-freeze": "0.0.1",
|
||||||
"esm": "3.0.34",
|
"esm": "3.0.34",
|
||||||
|
"findup": "0.1.5",
|
||||||
"human-readable-ids": "1.0.3",
|
"human-readable-ids": "1.0.3",
|
||||||
|
"js-yaml": "3.12.0",
|
||||||
"koa": "2.5.1",
|
"koa": "2.5.1",
|
||||||
"koa-router": "7.4.0",
|
"koa-router": "7.4.0",
|
||||||
"localenv": "0.2.2",
|
"localenv": "0.2.2",
|
||||||
|
"lodash": "4.17.10",
|
||||||
"optimist": "0.6.1",
|
"optimist": "0.6.1",
|
||||||
"pump": "3.0.0",
|
"pump": "3.0.0",
|
||||||
"tldjs": "2.3.1"
|
"tldjs": "2.3.1"
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import ClientManager from './lib/ClientManager';
|
|||||||
const debug = Debug('localtunnel:server');
|
const debug = Debug('localtunnel:server');
|
||||||
|
|
||||||
export default function(opt) {
|
export default function(opt) {
|
||||||
|
|
||||||
opt = opt || {};
|
opt = opt || {};
|
||||||
|
|
||||||
const validHosts = (opt.domain) ? [opt.domain] : undefined;
|
const validHosts = (opt.domain) ? [opt.domain] : undefined;
|
||||||
@@ -28,6 +29,30 @@ export default function(opt) {
|
|||||||
const app = new Koa();
|
const app = new Koa();
|
||||||
const router = new Router();
|
const router = new Router();
|
||||||
|
|
||||||
|
app.use(async (ctx, next) => {
|
||||||
|
try {
|
||||||
|
await next();
|
||||||
|
} catch (err) {
|
||||||
|
ctx.status = err.status || 500;
|
||||||
|
ctx.body = err.message;
|
||||||
|
ctx.app.emit('error', err, ctx);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (opt.require_token) {
|
||||||
|
app.use((ctx, next) => {
|
||||||
|
const token = ctx.request.query.token;
|
||||||
|
if (!token || opt.tokens.indexOf(token) === -1) {
|
||||||
|
const err = new Error(`Missing or unknown token.`);
|
||||||
|
err.status = 511;
|
||||||
|
err.code = 'TOKEN_ERROR';
|
||||||
|
throw err;
|
||||||
|
} else {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
router.get('/api/status', async (ctx, next) => {
|
router.get('/api/status', async (ctx, next) => {
|
||||||
const stats = manager.stats;
|
const stats = manager.stats;
|
||||||
ctx.body = {
|
ctx.body = {
|
||||||
|
|||||||
@@ -25,6 +25,12 @@ any-promise@^1.1.0:
|
|||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
|
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
|
||||||
|
|
||||||
|
argparse@^1.0.7:
|
||||||
|
version "1.0.10"
|
||||||
|
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
|
||||||
|
dependencies:
|
||||||
|
sprintf-js "~1.0.2"
|
||||||
|
|
||||||
array-find-index@^1.0.1:
|
array-find-index@^1.0.1:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
|
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
|
||||||
@@ -41,6 +47,10 @@ balanced-match@^1.0.0:
|
|||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||||
|
|
||||||
|
[email protected]:
|
||||||
|
version "3.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9"
|
||||||
|
|
||||||
[email protected]:
|
[email protected]:
|
||||||
version "1.3.3"
|
version "1.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/book/-/book-1.3.3.tgz#53654254bfe083db102e461544ae9f84be199985"
|
resolved "https://registry.yarnpkg.com/book/-/book-1.3.3.tgz#53654254bfe083db102e461544ae9f84be199985"
|
||||||
@@ -111,6 +121,10 @@ [email protected]:
|
|||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
|
resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b"
|
||||||
|
|
||||||
|
colors@~0.6.0-1:
|
||||||
|
version "0.6.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc"
|
||||||
|
|
||||||
[email protected]:
|
[email protected]:
|
||||||
version "1.0.6"
|
version "1.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818"
|
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818"
|
||||||
@@ -125,6 +139,10 @@ [email protected]:
|
|||||||
version "2.5.0"
|
version "2.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.5.0.tgz#d777b6a4d847d423e5d475da864294ac1ff5aa9d"
|
resolved "https://registry.yarnpkg.com/commander/-/commander-2.5.0.tgz#d777b6a4d847d423e5d475da864294ac1ff5aa9d"
|
||||||
|
|
||||||
|
commander@~2.1.0:
|
||||||
|
version "2.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/commander/-/commander-2.1.0.tgz#d121bbae860d9992a3d517ba96f56588e47c6781"
|
||||||
|
|
||||||
component-emitter@^1.2.0:
|
component-emitter@^1.2.0:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
|
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
|
||||||
@@ -187,6 +205,10 @@ deep-equal@~1.0.1:
|
|||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
|
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
|
||||||
|
|
||||||
|
[email protected]:
|
||||||
|
version "0.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/deep-freeze/-/deep-freeze-0.0.1.tgz#3a0b0005de18672819dfd38cd31f91179c893e84"
|
||||||
|
|
||||||
delayed-stream@~1.0.0:
|
delayed-stream@~1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||||
@@ -251,6 +273,10 @@ [email protected]:
|
|||||||
version "3.0.34"
|
version "3.0.34"
|
||||||
resolved "https://registry.yarnpkg.com/esm/-/esm-3.0.34.tgz#f86afa35c83a0f535da01d15e625e45794ebddc8"
|
resolved "https://registry.yarnpkg.com/esm/-/esm-3.0.34.tgz#f86afa35c83a0f535da01d15e625e45794ebddc8"
|
||||||
|
|
||||||
|
esprima@^4.0.0:
|
||||||
|
version "4.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
|
||||||
|
|
||||||
esprima@~3.0.0:
|
esprima@~3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.0.0.tgz#53cf247acda77313e551c3aa2e73342d3fb4f7d9"
|
resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.0.0.tgz#53cf247acda77313e551c3aa2e73342d3fb4f7d9"
|
||||||
@@ -272,6 +298,13 @@ find-up@^1.0.0:
|
|||||||
path-exists "^2.0.0"
|
path-exists "^2.0.0"
|
||||||
pinkie-promise "^2.0.0"
|
pinkie-promise "^2.0.0"
|
||||||
|
|
||||||
|
[email protected]:
|
||||||
|
version "0.1.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/findup/-/findup-0.1.5.tgz#8ad929a3393bac627957a7e5de4623b06b0e2ceb"
|
||||||
|
dependencies:
|
||||||
|
colors "~0.6.0-1"
|
||||||
|
commander "~2.1.0"
|
||||||
|
|
||||||
foreach@~2.0.1:
|
foreach@~2.0.1:
|
||||||
version "2.0.5"
|
version "2.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
|
resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
|
||||||
@@ -428,6 +461,13 @@ isexe@^2.0.0:
|
|||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
|
||||||
|
|
||||||
|
[email protected]:
|
||||||
|
version "3.12.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1"
|
||||||
|
dependencies:
|
||||||
|
argparse "^1.0.7"
|
||||||
|
esprima "^4.0.0"
|
||||||
|
|
||||||
keygrip@~1.0.2:
|
keygrip@~1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.0.2.tgz#ad3297c557069dea8bcfe7a4fa491b75c5ddeb91"
|
resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.0.2.tgz#ad3297c557069dea8bcfe7a4fa491b75c5ddeb91"
|
||||||
@@ -586,6 +626,10 @@ lodash.toarray@^4.4.0:
|
|||||||
version "4.4.0"
|
version "4.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561"
|
resolved "https://registry.yarnpkg.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz#24c4bfcd6b2fba38bfd0594db1179d8e9b656561"
|
||||||
|
|
||||||
|
[email protected]:
|
||||||
|
version "4.17.10"
|
||||||
|
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
|
||||||
|
|
||||||
loud-rejection@^1.0.0:
|
loud-rejection@^1.0.0:
|
||||||
version "1.6.0"
|
version "1.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
|
resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
|
||||||
@@ -938,6 +982,10 @@ spdx-license-ids@^3.0.0:
|
|||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87"
|
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz#7a7cd28470cc6d3a1cfe6d66886f6bc430d3ac87"
|
||||||
|
|
||||||
|
sprintf-js@~1.0.2:
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
||||||
|
|
||||||
stackframe@^0.3.1:
|
stackframe@^0.3.1:
|
||||||
version "0.3.1"
|
version "0.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-0.3.1.tgz#33aa84f1177a5548c8935533cbfeb3420975f5a4"
|
resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-0.3.1.tgz#33aa84f1177a5548c8935533cbfeb3420975f5a4"
|
||||||
|
|||||||
Reference in New Issue
Block a user