Commit 8a92724a authored by Jarrod's avatar Jarrod 💬

Update

parent ab6d7cb1
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
############################
# npm
############################
node_modules
npm-debug.log
############################
# tmp, editor & OS files
############################
.tmp
*.swo
*.swp
*.swn
*.swm
.DS_STORE
*#
*~
.idea
nbproject
############################
# Tests
############################
coverage
############################
# Other
############################
.node_history
{
// To fix column positions for JSHint errors you may want to add `"indent": 1` to your
// **User** "jshint_options". This issue affects users with tabs for indentation.
// This fix was reverted due to a conflict with using the `"white": true` option.
// "indent": 1,
"evil": true,
"regexdash": true,
"browser": true,
"wsh": true,
"sub": true,
// Suppress warnings about mixed tabs and spaces
"smarttabs": true,
// Suppress warnings about trailing whitespace
"trailing": false,
// Suppress warnings about the use of expressions where fn calls or assignments are expected
"expr": true,
// Suppress warnings about using functions inside loops (useful for inifinityCounters)
"loopfunc": true,
// Suppress warnings about using assignments where conditionals are expected
"boss": true,
// Suppress warnings about "weird constructions"
// i.e. allow code like:
// (new (function OneTimeUsePrototype () { } ))
"supernew": true,
// Allow backwards, node-dependency-style commas
"laxcomma": true
// "bitwise": true,
// "camelcase": true,
// "node": true,
// "undef": true,
// "unused": true,
// "curly": true,
// "immed": true,
// "latedef": true,
// "noarg": true,
// "noempty": true,
// "plusplus": true,
// "quotmark": "single",
// "trailing": true,
// "asi": false,
// "eqnull": true,
// "eval": true,
// "sub": true,
// "supernew": true,
// "eqeqeq": true,
// "eqnull": true
}
*#
node_modules
ssl
.DS_STORE
*.swo
*.swp
*.swn
*.swm
*~
.idea
nbproject
.git
.gitignore
.tmp
.jshintrc
.editorconfig
CONTRIBUTING.md
*.md
**/*.md
test
<h1>
<a href="http://node-machine.org" title="Node-Machine public registry"><img alt="node-machine logo" title="Node-Machine Project" src="http://node-machine.org/images/machine-anthropomorph-for-white-bg.png" width="50" /></a>
machinepack-jwt-ng
machinepack-jwthelper
</h1>
### [Docs](http://node-machine.org/machinepack-jwt-ng) &nbsp; [Browse other machines](http://node-machine.org/machinepacks) &nbsp; [FAQ](http://node-machine.org/implementing/FAQ) &nbsp; [Newsgroup](https://groups.google.com/forum/?hl=en#!forum/node-machine)
### [Docs](http://node-machine.org/machinepack-jwthelper) &nbsp; [Browse other machines](http://node-machine.org/machinepacks) &nbsp; [FAQ](http://node-machine.org/implementing/FAQ) &nbsp; [Newsgroup](https://groups.google.com/forum/?hl=en#!forum/node-machine)
Interact with JWT tokens
Work with JWT tokens
## Installation &nbsp; [![NPM version](https://badge.fury.io/js/machinepack-jwt-ng.svg)](http://badge.fury.io/js/machinepack-jwt-ng) [![Build Status](https://travis-ci.org/https://git.linahan.id.au/jarrod/Cuckold-API.png?branch=master)](https://travis-ci.org/https://git.linahan.id.au/jarrod/Cuckold-API)
## Installation &nbsp; [![NPM version](https://badge.fury.io/js/machinepack-jwthelper.svg)](http://badge.fury.io/js/machinepack-jwthelper) [![Build Status](https://travis-ci.org/ssh://git@git.linahan.id.au:2711/jarrod/machinepack-jwt-ng.png?branch=master)](https://travis-ci.org/ssh://git@git.linahan.id.au:2711/jarrod/machinepack-jwt-ng)
~~$ npm install machinepack-jwt-ng~~
```sh
$ npm install machinepack-jwthelper
```
## Usage
For the latest usage documentation, version information, and test status of this module, see <a href="http://node-machine.org/machinepack-jwt-ng" title="Interact with JWT tokens (for node.js)">http://node-machine.org/machinepack-jwt-ng</a>. The generated manpages for each machine contain a complete reference of all expected inputs, possible exit states, and example return values. If you need more help, or find a bug, jump into [Gitter](https://gitter.im/node-machine/general) or leave a message in the project [newsgroup](https://groups.google.com/forum/?hl=en#!forum/node-machine).
For the latest usage documentation, version information, and test status of this module, see <a href="http://node-machine.org/machinepack-jwthelper" title="Work with JWT tokens (for node.js)">http://node-machine.org/machinepack-jwthelper</a>. The generated manpages for each machine contain a complete reference of all expected inputs, possible exit states, and example return values. If you need more help, or find a bug, jump into [Gitter](https://gitter.im/node-machine/general) or leave a message in the project [newsgroup](https://groups.google.com/forum/?hl=en#!forum/node-machine).
## About &nbsp; [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/node-machine/general?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
......
// ----------------------------------------------------------------------------
const os = require('os');
const jwt = require('./index.js');
// ----------------------------------------------------------------------------
let privateKey = '===';
let pubKey = '===';
// ----------------------------------------------------------------------------
// ~TODO: Load private key
// ~TODO: Load public key
// ----------------------------------------------------------------------------
jwt.configure({
algorithm: 'HS256',
expiresIn: '1 hour',
secret: privateKey,
});
// ----------------------------------------------------------------------------
// Add our pubkey for verifying
let hostname = os.hostname();
jwt.addPubkey(hostname, pubKey);
// Add other trusted nodes
jwt.addPubkey('CarrotBook.local','ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDspK/U09A5YDWbJZd4WKFI+p2ZqBcho+Bnk7M6rIMCEX/AZoZr97STXe3cWqzbQMjkqGBKpzx8VvZsJKDv3jqQ3QeMwigZM8YsGOOgyDkE8fvdU8k8ex8sM9+Ihp11Y/1HyABSVjxLp58z+3alTFEX0SqA1YKh8cDh0q/9Ppc6bX9/28scEIgDeJzL476Rqg0sGHATd4NpvLe0N9YVUhJ+PMeE6DYK+InZS3X/UmpJNGPMorYFE9GpT/n7LFtBaMSRVZUSfP3BSJkuss52FDzQidg0xT4XtooPf3I+XRyQFuOVDV2PbneehN0cthnnvRLJQK2IUTyPAruXYt4XZvTB jarrod@CarrotBook.local');
// ----------------------------------------------------------------------------
jwt.sign({ payload, config }).exec((err, data) => {
console.info(`Done in ${_end}ms `);
if (err) {
console.error('Failed to sign token: ', err.stack);
process.exit(1);
}
console.log('Signed token: ', data);
});
// ----------------------------------------------------------------------------
const mp = require('../index.js');
let config = {};
let payload = {
userId: 12,
username: 'Bob Tomkins',
};
let _start = Date.now();
console.info('Start ', _start);
mp.sign({ payload, config }).exec((err, data) => {
let _end = Date.now() - _start;
console.info(`Done in ${_end}ms `);
if (err) {
console.error('Failed to sign token: ', err.stack);
process.exit(1);
}
console.log('Signed token: ', data);
});
const mp = require('../index.js');
let _start = Date.now();
console.info('Start ', _start);
mp.verify({
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.bgGd720CeHP4kY9mGuMEoteBq4TP4d0W2XkpiI4bVgg",
"config": {
"secret": "12345",
"algorithm": "HS256",
"issuer": null
}
}).exec((err, data) => {
let _end = Date.now() - _start;
console.info(`Done in ${_end}ms `);
if (err) {
console.error('Failed to decode JWT', err);
process.exit(1);
}
console.log('Decoded token:', data);
});
module.exports = {
friendlyName: 'Add pubkey',
description: '',
cacheable: false,
sync: false,
inputs: {
},
exits: {
success: {
variableName: 'result',
description: 'Done.',
},
},
fn: function(inputs, exits
/*``*/
) {
return exits.success();
},
};
\ No newline at end of file
module.exports = {
friendlyName: 'Configure',
description: 'Set the default configuration options',
cacheable: false,
sync: false,
inputs: {
config: {
description: 'Configuration options used to sign this token',
required: false,
defaultsTo: { },
example: { }
},
},
exits: {
success: {
variableName: 'result',
description: 'Done.',
},
},
fn: function(inputs, exits) {
let config = require('../private/config')(inputs.config);
config.update(inputs.config);
return exits.success();
},
};
module.exports = {
friendlyName: 'Delete pubkey',
description: '',
cacheable: false,
sync: false,
inputs: {
},
exits: {
success: {
variableName: 'result',
description: 'Done.',
},
},
fn: function(inputs, exits
/*``*/
) {
return exits.success();
},
};
\ No newline at end of file
const verify = require('machine').build(require('./verify'));
const defaultConfig = require('../private/default-config');
module.exports = {
friendlyName: 'Extract JWT token data from a request',
friendlyName: 'From Request',
description: 'Find and parse a JWT from an Express/Sails.js request',
// sideEffects: "cacheable",
inputs: {
request: {
description: 'The (Express/Sails) request object',
example: 'express.req or sails.req',
type: 'ref',
required: true
req: {
description: ``,
required: true,
example: { }
},
config: {
description: 'Configuration object for signing this token',
type: 'ref',
description: 'Configuration options used to sign this token',
required: false,
defaultsTo: {},
example: defaultConfig
defaultsTo: { },
example: { }
}
},
exits: {
success: {
outputFriendlyName: 'Found and parsed JWT header',
outputType: 'ref',
variableName: 'result',
description: 'Done.',
},
badInput: {
description: "`req` doesn't appear to be an Express/Sails.js request",
},
notFound: {
outputFriendlyName: 'No Authorization header found',
description: "No JWT token was found in the request (in HTTP 'Authorization' looking like 'Bearer <JWT>')",
},
invalid: {
outputFriendlyName: 'Invalid Authorization header/JWT token'
description: "`req` doesn't appear to be an Express/Sails.js request",
}
},
fn: async function(inputs, exits) {
let req = inputs.request;
fn: function(inputs, exits) {
var verify = require('machine').build(require('./verify'));
let config = require('../private/config')(inputs.config);
if (!inputs.req.headers) {
return exits.badInput();
}
// Get the token
let token;
if (req.headers && 'authorization' in req.headers) {
let parts = req.headers.authorization.split(/\s+/);
if ('authorization' in inputs.req.headers && inputs.req.headers.authorization.match(/^Bearer [a-z0-9=_+%-]+/i)) {
let parts = inputs.req.headers.authorization.split(' ');
if (parts.length === 2) {
let scheme = parts[0];
let credentials = parts[1];
if (/^Bearer$/i.test(scheme)) {
token = credentials;
}
} else {
return exits.invalid();
token = parts[1];
}
} else {
return exits.notFound()
}
let tokenData;
try {
tokenData = await verify({ token: token, config: inputs.config });
} catch (err) { }
if (!tokenData) {
return exits.invalid();
if (!token) {
return exits.notFound()
}
return exits.success({
raw: token,
parsed: tokenData
verify({ token, config }).exec((err, data) => {
if (err) {
return exits.invalid(err.message)
}
return exits.success(data);
});
}
},
};
const jwt = require('jsonwebtoken');
const uuidv4 = require('uuid/v4');
const _ = require('lodash');
const defaultConfig = require('../private/default-config');
const verify = require('machine').build(require('./verify'));
const jwt = require('jsonwebtoken');
module.exports = {
friendlyName: 'Sign a JWT Token',
description: 'Sign a JWT Token for future API requests',
friendlyName: 'Sign a JWT token',
description: '',
sync: true,
inputs: {
payload: {
description: 'The payload for this JWT',
example: { name: 'bob' },
type: 'ref',
required: true
description: 'Payload for the resulting JWT',
required: true,
example: { }
},
config: {
description: 'Configuration object for signing this token',
type: 'ref',
description: 'Configuration options used to sign this token',
required: false,
defaultsTo: {},
example: defaultConfig
}
defaultsTo: { },
example: { }
},
},
exits: {
success: {
outputFriendlyName: 'Successfully signed JWT',
outputDescription: 'A dictionary of information about what went down.',
outputType: 'string'
}
variableName: 'result',
description: 'Done.',
},
},
fn: async function(inputs, exits) {
let config = _.defaults(inputs.config, defaultConfig);
let token = jwt.sign({
fn: function(inputs, exits) {
let config = require('../private/config')(inputs.config);
let jwtid = _.isFunction(config.id) ? config.id() : config.id;
jwt.sign({
data: inputs.payload
}, config.secret, {
algorithm: config.algorithm,
expiresIn: config.expiresIn,
issuer: config.issuer,
jwtid: uuidv4(),
jwtid
}, async function (err, token) {
if (err) {
return exits.error(err);
}
return exits.success(token);
});
},
let response = {
raw: token,
data: await verify({ token, config })
};
return exits.success(response);
}
};
const jwt = require('jsonwebtoken');
const defaultConfig = require('../private/default-config');
module.exports = {
friendlyName: 'Verify a given JWT Token',
description: 'Verify a JWT Token is valid',
friendlyName: 'Verify a JWT',
description: `Verify a given JWT and get it's decoded contents`,
sync: false,
inputs: {
token: {
description: 'The token to verify',
type: 'string',
description: 'JWT to decode & verify',
required: true,
example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c',
},
config: {
description: 'Configuration object for signing this token',
type: 'ref',
description: 'Configuration options used to sign this token',
required: false,
defaultsTo: {},
example: defaultConfig
}
example: {},
},
},
exits: {
success: {
outputFriendlyName: 'Verified the JWT token & return encoded data',
outputType: 'ref'
variableName: 'result',
description: 'Done.',
},
failed: {
outputFriendlyName: 'Could not verify the JWT token',
outputType: 'string'
description: 'Invalid token'
},
},
fn: async function(inputs, exits) {
let config = _.defaults(inputs.config, defaultConfig);
jwt.verify(inputs.token, config.secret, {algorithm: config.algorithm}, (err, data) => {
fn: function(inputs, exits) {
var jwt = require('jsonwebtoken');
var config = require('../private/config')(inputs.config);
if (!config.algorithms && config.algorithm) {
config.algorithms = [config.algorithm];
}
jwt.verify(inputs.token, config.secret, config, (err, data) => {
if (err) {
return exits.failed('Invalid token');
return exits.failed(err.message);
}
return exits.success(data);
});
}
},
};
This diff is collapsed.
{
"name": "machinepack-jwt-ng",
"description": "Interact with JWT tokens",
"version": "0.0.1",
"name": "machinepack-jwthelper",
"version": "0.1.0",
"description": "Work with JWT tokens",
"scripts": {
"test": "node ./node_modules/test-machinepack-mocha/bin/testmachinepack-mocha.js"
},
"keywords": [
"machinepack",
"machines"
"JWT Helper",
"machines",
"machinepack"
],
"author": "",
"license": "MIT",
"dependencies": {
"jsonwebtoken": "^8.4.0",
"lodash": "^4.17.11",
"machine": "^1.3.2",
"machine": "^12.2.5",
"test-machinepack": "^3.0.1",
"uuid": "^3.3.2"
},
"devDependencies": {
"test-machinepack-mocha": "^3.0.0"
},
"machinepack": {
"friendlyName": "jwtNg",
"friendlyName": "JWT Helper",
"machineDir": "machines/",
"machines": [
"sign",
"verify",
"from-request",
"verify"
"configure",
"add-pub-key",
"del-pubkey"
],
"machineDir": "machines/",
"testsUrl": "https://travis-ci.org/https://git.linahan.id.au/jarrod/Cuckold-API"
},
"devDependencies": {
"test-machinepack-mocha": "^2.0.0"
"testsUrl": "https://travis-ci.org/ssh://git@git.linahan.id.au:2711/jarrod/machinepack-jwt-ng"
},
"scripts": {
"test": "node ./node_modules/test-machinepack-mocha/bin/testmachinepack-mocha.js"
"repository": {
"type": "git",
"url": "ssh://git@git.linahan.id.au:2711/jarrod/machinepack-jwt-ng.git"
}
}
}
\ No newline at end of file
const os = require('os');
const uuidv4 = require('uuid/v4');
var _ = require('lodash');
let hostname = os.hostname();
// Used for verifying JWT
var knownPubkeys = {};
// Used for generating JWT
var signingConfig = {
algorithm: 'HS256',
issuer: hostname,
expiresIn: '1 day',
secret: uuidv4(),
id: () => {
return uuidv4();
}
};
module.exports = function(config) {
return _.defaults(config, signingConfig);
};
const os = require('os');
module.exports = {
algorithm: 'HS256',
issuer: os.hostname(),
expiresIn: '1 day',
secret: 'somesupersecretstring'
};
{
"machine": "configure",
"expectations": [
{
"using": { "config": { "x": "y" } },
"outcome": "success",
"todo": "Update private/config.js:defaultConfig for re-use"
}
]
}
{
"machine": "from-request",
"expectations": []
}
\ No newline at end of file
"expectations": [
{
"using": {
"req": {
"headers": {
"authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.bgGd720CeHP4kY9mGuMEoteBq4TP4d0W2XkpiI4bVgg"
}
},
"config": {
"algorithm": "HS256",
"secret": "12345",
"issuer": ""
}
},
"outcome": "success",
"output": { "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }