Skip to content

Commit

Permalink
Add support for access token lifetime
Browse files Browse the repository at this point in the history
  • Loading branch information
cheton committed Dec 10, 2016
1 parent 5c99c8a commit e420486
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 43 deletions.
22 changes: 12 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,16 +88,17 @@ $ cnc -h
Options:
-h, --help output usage information
-V, --version output the version number
-p, --port set listen port (default: 8000)
-l, --host set listen address or hostname (default: 0.0.0.0)
-b, --backlog set listen backlog (default: 511)
-c, --config <filename> set config file (default: ~/.cncrc)
-v, --verbose increase the verbosity level
-m, --mount [<url>:]<path> set the mount point for serving static files (default: /static:static)
-w, --watch-directory <path> watch a directory for changes
--allow-remote-access allow remote access to the server
-h, --help output usage information
-V, --version output the version number
-p, --port set listen port (default: 8000)
-l, --host set listen address or hostname (default: 0.0.0.0)
-b, --backlog set listen backlog (default: 511)
-c, --config <filename> set config file (default: ~/.cncrc)
-v, --verbose increase the verbosity level
-m, --mount [<url>:]<path> set the mount point for serving static files (default: /static:static)
-w, --watch-directory <path> watch a directory for changes
--access-token-lifetime <lifetime> access token lifetime in seconds or a time span string (default: 30d)
--allow-remote-access allow remote access to the server
Examples:
Expand All @@ -111,6 +112,7 @@ Instead of passing command line options for `--watch-directory` and `--allow-rem
```json
{
"watchDirectory": "/path/to/dir",
"accessTokenLifetime": "30d",
"allowRemoteAccess": false
}
```
Expand Down
14 changes: 9 additions & 5 deletions src/app/api/api.users.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import bcrypt from 'bcrypt-nodejs';
import _ from 'lodash';
import uuid from 'uuid';
import settings from '../config/settings';
import log from '../lib/log';
import {
ERR_BAD_REQUEST,
ERR_UNAUTHORIZED,
Expand All @@ -13,11 +14,12 @@ import {
ERR_INTERNAL_SERVER_ERROR
} from './constants';

// Generate session token
// Generate access token
// https://github.com/auth0/node-jsonwebtoken#jwtsignpayload-secretorprivatekey-options-callback
// Note. Do not use password and other sensitive fields in the payload
const generateToken = (payload, secret = settings.secret) => {
const generateAccessToken = (payload, secret = settings.secret) => {
const token = jwt.sign(payload, secret, {
expiresIn: 60 * 60 * 24 // expires in 24 hours
expiresIn: settings.accessTokenLifetime
});

return token;
Expand All @@ -44,7 +46,7 @@ export const signin = (req, res) => {
if (enabledUsers.length === 0) {
const user = { id: '', name: '' };
const payload = { ...user };
const token = generateToken(payload, settings.secret); // generate new token
const token = generateAccessToken(payload, settings.secret); // generate access token
res.send({
enabled: false, // session is disabled
token: token,
Expand All @@ -68,7 +70,7 @@ export const signin = (req, res) => {
id: user.id,
name: user.name
};
const token = generateToken(payload, settings.secret); // generate new token
const token = generateAccessToken(payload, settings.secret); // generate access token
res.send({
enabled: true, // session is enabled
token: token, // new token
Expand All @@ -85,6 +87,8 @@ export const signin = (req, res) => {
return;
}

log.debug(`jwt.verify: id=${user.id}, name="${user.name}", iat=${new Date(user.iat * 1000).toISOString()}, exp=${new Date(user.exp * 1000).toISOString()}`);

user = _.find(enabledUsers, { id: user.id, name: user.name });
if (!user) {
res.status(ERR_UNAUTHORIZED).send({
Expand Down
10 changes: 5 additions & 5 deletions src/app/config/settings.base.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,20 @@ const secret = pkg.version;
const getUserHome = () => (process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME']);

export default {
cncrc: path.resolve(getUserHome(), RCFILE),
verbosity: 0,
version: pkg.version,

// The secret key is loaded from the config file (defaults to "~/.cncrc")
// @see "src/app/index.js"
secret: secret,

cncrc: path.resolve(getUserHome(), RCFILE),
// Access Token Lifetime
accessTokenLifetime: '30d', // https://github.com/zeit/ms

// Allow remote access
// Allow Remote Access
allowRemoteAccess: false,

// version from package.json
version: pkg.version,

// Express view engine
view: {
// Set html (w/o dot) as the default extension
Expand Down
49 changes: 26 additions & 23 deletions src/app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,10 @@ import { readConfigFileSync, writeConfigFileSync } from './lib/config-file';
import settings from './config/settings';

const createServer = (options, callback) => {
const {
port = 0,
host,
backlog,
configFile,
verbosity,
mount,
watchDirectory,
allowRemoteAccess = false
} = { ...options };
options = { ...options };

const routes = [];
const cncrc = path.resolve(configFile || settings.cncrc);
const cncrc = path.resolve(options.configFile || settings.cncrc);
const config = readConfigFileSync(cncrc);

// cncrc
Expand All @@ -45,11 +37,11 @@ const createServer = (options, callback) => {
}

{ // routes
if (mount) {
if (typeof options.mount === 'object') {
routes.push({
type: 'static',
route: mount.url,
directory: mount.path
route: options.mount.url,
directory: options.mount.path
});
}

Expand All @@ -61,6 +53,8 @@ const createServer = (options, callback) => {
}

{ // verbosity
const verbosity = options.verbosity;

// https://github.com/winstonjs/winston#logging-levels
if (verbosity === 1) {
_.set(settings, 'verbosity', verbosity);
Expand All @@ -77,32 +71,41 @@ const createServer = (options, callback) => {
}

{ // watchDirectory
config.watchDirectory = _.get(config, 'watchDirectory', watchDirectory);
const watchDirectory = options.watchDirectory || config.watchDirectory;

if (config.watchDirectory) {
if (fs.existsSync(config.watchDirectory)) {
log.info(`Start watching ${chalk.yellow(JSON.stringify(config.watchDirectory))} for file changes.`);
if (watchDirectory) {
if (fs.existsSync(watchDirectory)) {
log.info(`Start watching ${chalk.yellow(JSON.stringify(watchDirectory))} for file changes.`);

// Start monitor service
monitor.start({ watchDirectory: config.watchDirectory });
monitor.start({ watchDirectory: watchDirectory });
} else {
log.error(`The directory ${chalk.yellow(JSON.stringify(config.watchDirectory))} does not exist.`);
log.error(`The directory ${chalk.yellow(JSON.stringify(watchDirectory))} does not exist.`);
}
}
}

{ // accessTokenLifetime
const accessTokenLifetime = options.accessTokenLifetime || config.accessTokenLifetime;

if (accessTokenLifetime) {
_.set(settings, 'accessTokenLifetime', accessTokenLifetime);
}
}

{ // allowRemoteAccess
config.allowRemoteAccess = _.get(config, 'allowRemoteAccess', allowRemoteAccess);
const allowRemoteAccess = (!!options.allowRemoteAccess) || (!!config.allowRemoteAccess);

if (config.allowRemoteAccess) {
if (allowRemoteAccess) {
if (_.size(config.users) === 0) {
log.warn('You\'ve enabled remote access to the server. It\'s recommended to create an user account to protect against malicious attacks.');
}

_.set(settings, 'allowRemoteAccess', config.allowRemoteAccess);
_.set(settings, 'allowRemoteAccess', allowRemoteAccess);
}
}

const { port = 0, host, backlog } = options;
webappengine({ port, host, backlog, routes })
.on('ready', (server) => {
// Start cncengine service
Expand Down
2 changes: 2 additions & 0 deletions src/cnc.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ program
.option('-v, --verbose', 'increase the verbosity level', increaseVerbosityLevel, 0)
.option('-m, --mount [<url>:]<path>', 'set the mount point for serving static files (default: /static:static)', parseMountPoint, { url: '/static', path: 'static' })
.option('-w, --watch-directory <path>', 'watch a directory for changes')
.option('--access-token-lifetime <lifetime>', 'access token lifetime in seconds or a time span string (default: 30d)')
.option('--allow-remote-access', 'allow remote access to the server', false);

program.on('--help', () => {
Expand Down Expand Up @@ -66,6 +67,7 @@ const cnc = (options = {}, callback) => {
verbosity: program.verbose,
mount: program.mount,
watchDirectory: program.watchDirectory,
accessTokenLifetime: program.accessTokenLifetime,
allowRemoteAccess: program.allowRemoteAccess,
...options // Override command-line options if specified
}, callback);
Expand Down

0 comments on commit e420486

Please sign in to comment.