appc-security
Advanced tools
Comparing version 0.0.15 to 0.1.0
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
/** | ||
@@ -2,0 +4,0 @@ * This code is closed source and Confidential and Proprietary to |
@@ -0,6 +1,13 @@ | ||
'use strict'; | ||
/** | ||
* SecurityError class | ||
* | ||
* @param {String|*} message error message | ||
* @param {String|*} code error code | ||
* @param {Number|*} status status code | ||
* @returns {void} | ||
*/ | ||
function SecurityError(message, code, status) { | ||
this.constructor.prototype.__proto__ = Error.prototype; | ||
Object.setPrototypeOf(this.constructor, Object.getPrototypeOf(Error)); | ||
Error.captureStackTrace(this, this.constructor); | ||
@@ -7,0 +14,0 @@ this.name = this.constructor.name; |
116
lib/index.js
@@ -1,19 +0,15 @@ | ||
/** | ||
* This code is closed source and Confidential and Proprietary to | ||
* Appcelerator, Inc. All Rights Reserved. This code MUST not be | ||
* modified, copied or otherwise redistributed without express | ||
* written permission of Appcelerator. This file is licensed as | ||
* part of the Appcelerator Platform and governed under the terms | ||
* of the Appcelerator license agreement. | ||
*/ | ||
var crypto = require('crypto'), | ||
SecurityError = require('./error'); | ||
'use strict'; | ||
var ITERATIONS = 100000; | ||
var SALT_LENGTH = 512; | ||
var IV_LENGTH = 32; | ||
var HMAC_LENGTH = 64; | ||
var KEY_LENGTH = 32; | ||
var DEBUG = false; | ||
const crypto = require('crypto'); | ||
const jwt = require('jsonwebtoken'); | ||
const SecurityError = require('./error'); | ||
let ITERATIONS = 100000; | ||
let SALT_LENGTH = 512; | ||
let IV_LENGTH = 32; | ||
let HMAC_LENGTH = 64; | ||
let KEY_LENGTH = 32; | ||
let DEBUG = false; | ||
/** | ||
@@ -23,3 +19,3 @@ * simple SHA1 | ||
function sha1(value, encoding) { | ||
var cipher = crypto.createHash('SHA1'); | ||
let cipher = crypto.createHash('SHA1'); | ||
cipher.update(value); | ||
@@ -37,3 +33,3 @@ return cipher.digest(encoding || 'hex'); | ||
function constantTimeCompare(a, b) { | ||
var sentinel; | ||
let sentinel; | ||
@@ -45,3 +41,3 @@ /* istanbul ignore if */ | ||
for (var c = 0; c <= (a.length - 1); c++) { | ||
for (let c = 0; c <= (a.length - 1); c++) { | ||
sentinel |= a.charCodeAt(c) ^ b.charCodeAt(c); | ||
@@ -62,3 +58,4 @@ } | ||
size = size || SALT_LENGTH / 2; | ||
var value = new Buffer(crypto.randomBytes(size)); | ||
// eslint-disable-next-line security/detect-new-buffer | ||
let value = new Buffer(crypto.randomBytes(size)); | ||
return value.toString(encoding || 'hex'); | ||
@@ -93,4 +90,5 @@ } | ||
try { | ||
var keySizeFactor = 256 / size, | ||
let keySizeFactor = 256 / size, | ||
// create random IV | ||
// eslint-disable-next-line security/detect-new-buffer | ||
iv = new Buffer(generateLargeRandomValue(IV_LENGTH / 2), 'hex'), | ||
@@ -109,3 +107,3 @@ // create an HMAC | ||
// encrypt the plainText | ||
var encrypted = cipher.update(plainText, 'utf-8', 'hex'); | ||
let encrypted = cipher.update(plainText, 'utf-8', 'hex'); | ||
encrypted += cipher.final('hex'); | ||
@@ -119,3 +117,3 @@ | ||
hmac.update(iv.toString('hex')); | ||
var hmacEncoding = hmac.digest('hex'); | ||
let hmacEncoding = hmac.digest('hex'); | ||
@@ -140,5 +138,6 @@ /* istanbul ignore if */ | ||
// shared keys and salt + pepper which only the two parties will know | ||
var encryptedText = hmacEncoding + salt + iv.toString('hex') + encrypted; | ||
let encryptedText = hmacEncoding + salt + iv.toString('hex') + encrypted; | ||
if (encoding && encoding !== 'hex') { | ||
// if we need to return a different encoding than hex, encode it | ||
// eslint-disable-next-line security/detect-new-buffer | ||
encryptedText = new Buffer(encryptedText, 'hex').toString(encoding); | ||
@@ -153,4 +152,3 @@ } | ||
}; | ||
} | ||
catch (E) { | ||
} catch (E) { | ||
throw new SecurityError('encryption failed'); | ||
@@ -176,4 +174,4 @@ } | ||
if (encoding && encoding !== 'hex') { | ||
encrypted = new Buffer(encrypted, encoding); | ||
encrypted = encrypted.toString('hex'); | ||
// eslint-disable-next-line security/detect-new-buffer | ||
encrypted = new Buffer(encrypted, encoding).toString('hex'); | ||
} | ||
@@ -184,3 +182,3 @@ if (encrypted.length <= HMAC_LENGTH + SALT_LENGTH + IV_LENGTH) { | ||
try { | ||
var keySizeFactor = 256 / size, | ||
let keySizeFactor = 256 / size, | ||
hmacValue = encrypted.substring(0, HMAC_LENGTH), | ||
@@ -223,3 +221,4 @@ salt = encrypted.substring(HMAC_LENGTH, HMAC_LENGTH + SALT_LENGTH), | ||
// create our derived key | ||
var derivedKey = crypto.pbkdf2Sync(key, saltAndPepper, ITERATIONS, KEY_LENGTH / keySizeFactor, 'SHA1'), | ||
let derivedKey = crypto.pbkdf2Sync(key, saltAndPepper, ITERATIONS, KEY_LENGTH / keySizeFactor, 'SHA1'), | ||
// eslint-disable-next-line security/detect-new-buffer | ||
ivKey = new Buffer(iv, 'hex'), | ||
@@ -235,6 +234,5 @@ // create our decryption cipher | ||
var decrypted = cipher.update(encryptedBuf, 'hex', 'utf-8'); | ||
let decrypted = cipher.update(encryptedBuf, 'hex', 'utf-8'); | ||
return decrypted + cipher.final('utf-8'); | ||
} | ||
catch (E) { | ||
} catch (E) { | ||
if (E instanceof SecurityError) { | ||
@@ -264,4 +262,3 @@ throw E; | ||
metadata.$ks = key_secret; | ||
var jwt = require('jsonwebtoken'), | ||
object = { | ||
let object = { | ||
apikey: apikey, | ||
@@ -278,2 +275,3 @@ headers: metadata | ||
encoded = jwt.sign(object, secret, options); | ||
// eslint-disable-next-line security/detect-new-buffer | ||
return new Buffer(encoded).toString(encoding || 'utf8'); | ||
@@ -293,12 +291,11 @@ } | ||
try { | ||
var jwt = require('jsonwebtoken'), | ||
buf = new Buffer(token, encoding || 'utf8').toString(), | ||
decoded = jwt.decode(buf, {complete: true}), | ||
// eslint-disable-next-line security/detect-new-buffer | ||
let buf = new Buffer(token, encoding || 'utf8').toString(), | ||
decoded = jwt.decode(buf, { complete: true }), | ||
secret = crypto.pbkdf2Sync(decoded.payload.apikey, sha1(decoded.payload.apikey + decoded.payload.headers.$ks + master_secret), 100, 16, 'SHA1').toString('base64'); | ||
return jwt.verify(buf, secret, {algorithm: 'HS256', issuer: 'https://security.appcelerator.com'}); | ||
} | ||
catch (e) { | ||
return jwt.verify(buf, secret, { algorithm: 'HS256', issuer: 'https://security.appcelerator.com' }); | ||
} catch (e) { | ||
// console.log(e.stack); | ||
var message = e.message.replace(/jwt/g, 'token'); | ||
var ex = new SecurityError(message); | ||
let message = e.message.replace(/jwt/g, 'token'); | ||
let ex = new SecurityError(message); | ||
if (e.expiredAt) { | ||
@@ -315,7 +312,6 @@ ex.expiredAt = e.expiredAt; | ||
function generateAPITokenHTTPAuthorization (token, secret, headers, headerName) { | ||
var jwt = require('jsonwebtoken'), | ||
decoded = jwt.decode(token, {complete: true}), | ||
let decoded = jwt.decode(token, { complete: true }), | ||
hmac = crypto.createHmac('SHA256', decoded && decoded.payload && decoded.payload.headers && decoded.payload.headers.$ks); | ||
hmac.update(token); | ||
var result = 'APIKey ' + hmac.digest('hex') + ' ' + token; | ||
let result = 'APIKey ' + hmac.digest('hex') + ' ' + token; | ||
headers && (headers[headerName || 'authorization'] = result); | ||
@@ -325,3 +321,5 @@ return result; | ||
var AuthorizationRegExp = /^APIKey\s(\w+)\s([\w\.=-]+)$/; | ||
// eslint-disable-next-line no-useless-escape | ||
const AuthorizationRegExp = /^APIKey\s(\w+)\s([\w\.=-]+)$/; | ||
/** | ||
@@ -335,7 +333,7 @@ * verify a HTTP Authorization header as a valid API key and return the | ||
} | ||
var tok = AuthorizationRegExp.exec(authorization); | ||
let tok = AuthorizationRegExp.exec(authorization); | ||
if (!tok || tok.length !== 3) { | ||
throw new SecurityError('invalid authorization'); | ||
} | ||
var token = tok[2], | ||
let token = tok[2], | ||
encoded = verifySessionTokenForAPIKey(token, secret, encoding), | ||
@@ -351,13 +349,13 @@ hmac = crypto.createHmac('SHA256', encoded.headers && encoded.headers.$ks); | ||
// export our APIs | ||
exports.sha1 = sha1; | ||
exports.generateLargeRandomValue = generateLargeRandomValue; | ||
exports.encrypt = encrypt; | ||
exports.decrypt = decrypt; | ||
exports.createSessionTokenFromAPIKey = createSessionTokenFromAPIKey; | ||
exports.verifySessionTokenForAPIKey = verifySessionTokenForAPIKey; | ||
exports.generateAPITokenHTTPAuthorization = generateAPITokenHTTPAuthorization; | ||
exports.validateAPITokenFromHTTPAuthorization = validateAPITokenFromHTTPAuthorization; | ||
// exports | ||
module.exports.sha1 = sha1; | ||
module.exports.generateLargeRandomValue = generateLargeRandomValue; | ||
module.exports.encrypt = encrypt; | ||
module.exports.decrypt = decrypt; | ||
module.exports.createSessionTokenFromAPIKey = createSessionTokenFromAPIKey; | ||
module.exports.verifySessionTokenForAPIKey = verifySessionTokenForAPIKey; | ||
module.exports.generateAPITokenHTTPAuthorization = generateAPITokenHTTPAuthorization; | ||
module.exports.validateAPITokenFromHTTPAuthorization = validateAPITokenFromHTTPAuthorization; | ||
// jscs:disable jsDoc | ||
// accessors | ||
Object.defineProperty(exports, 'Middleware', { | ||
@@ -364,0 +362,0 @@ get: function () { |
@@ -1,4 +0,4 @@ | ||
var seclib = require('./index'), | ||
urllib = require('url'), | ||
SecurityError = require('./error'); | ||
const urllib = require('url'); | ||
const seclib = require('./index'); | ||
const SecurityError = require('./error'); | ||
@@ -8,3 +8,3 @@ /** | ||
*/ | ||
function accepts (req) { | ||
function accepts(req) { | ||
var header = req.headers && req.headers.accept; | ||
@@ -35,5 +35,5 @@ if (header) { | ||
*/ | ||
function isSecure (req) { | ||
return req.secure || | ||
req.headers && req.headers.host && req.headers.host.indexOf('https://') === 0; | ||
function isSecure(req) { | ||
return req.secure | ||
|| req.headers && req.headers.host && req.headers.host.indexOf('https://') === 0; | ||
} | ||
@@ -44,3 +44,3 @@ | ||
*/ | ||
function makeRelativeUrl (req, relpath) { | ||
function makeRelativeUrl(req, relpath) { | ||
var url = (isSecure(req) ? 'https' : 'http') + '://' + req.get('host') + req.originalUrl; | ||
@@ -53,3 +53,3 @@ return urllib.resolve(url, relpath); | ||
*/ | ||
function redirectUrl (req, resp, redirectTo, redirectUrlParam) { | ||
function redirectUrl(req, resp, redirectTo, redirectUrlParam) { | ||
// we want to redirect to a specified url | ||
@@ -68,3 +68,3 @@ var fullUrl = encodeURIComponent(makeRelativeUrl(req, req.url)); | ||
*/ | ||
function redirect (req, resp, redirectTo, redirectUrlParam) { | ||
function redirect(req, resp, redirectTo, redirectUrlParam) { | ||
resp.redirect(redirectUrl(req, resp, redirectTo, redirectUrlParam)); | ||
@@ -76,3 +76,3 @@ } | ||
*/ | ||
function unauthorized (req, resp, errorHandler, redirectTo, redirectUrlParam, renderUnauthorized, reason, error) { | ||
function unauthorized(req, resp, errorHandler, redirectTo, redirectUrlParam, renderUnauthorized, reason, error) { | ||
if (errorHandler) { | ||
@@ -136,3 +136,3 @@ // custom error handling | ||
*/ | ||
return function middleware (req, resp, next) { | ||
return function middleware(req, resp, next) { | ||
if (!urlpattern || urlpattern.test(req.url)) { | ||
@@ -152,4 +152,3 @@ var value = req.headers && req.headers[header]; | ||
} | ||
} | ||
catch (E) { | ||
} catch (E) { | ||
if (required) { | ||
@@ -156,0 +155,0 @@ // console.log(E.stack); |
{ | ||
"name": "appc-security", | ||
"version": "0.0.15", | ||
"description": "Appcelerator Security Best Practices Library for Node", | ||
"version": "0.1.0", | ||
"description": "Appcelerator Security Library for Node.JS", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "grunt" | ||
"test": "eslint --ext .js ./ && mocha" | ||
}, | ||
@@ -23,20 +23,18 @@ "repository": { | ||
"homepage": "https://github.com/appcelerator/appc-security", | ||
"dependencies": { | ||
"jsonwebtoken": "^8.3.0" | ||
}, | ||
"devDependencies": { | ||
"express": "^4.13.3", | ||
"grunt": "^0.4.5", | ||
"grunt-appc-coverage": "^0.1.5", | ||
"grunt-appc-js": "*", | ||
"grunt-bump": "^0.3.0", | ||
"grunt-cli": "^0.1.13", | ||
"grunt-kahvesi": "*", | ||
"grunt-mocha-test": "^0.12.7", | ||
"load-grunt-tasks": "^1.0.0", | ||
"mocha": "^2.1.0", | ||
"request": "^2.61.0", | ||
"should": "^4.6.1", | ||
"time-grunt": "^1.0.0" | ||
"eslint": "^5.3.0", | ||
"eslint-config-axway": "^3.0.0", | ||
"eslint-plugin-mocha": "^5.2.0", | ||
"express": "^4.16.3", | ||
"mocha": "^5.2.0", | ||
"request": "^2.88.0", | ||
"should": "^13.2.3" | ||
}, | ||
"dependencies": { | ||
"jsonwebtoken": "^5.7.0" | ||
"engines": { | ||
"npm": ">=3.3.10", | ||
"node": ">=6.14.0" | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
7
49765
11
1286
2
+ Addedjsonwebtoken@8.5.1(transitive)
+ Addedlodash.includes@4.3.0(transitive)
+ Addedlodash.isboolean@3.0.3(transitive)
+ Addedlodash.isinteger@4.0.4(transitive)
+ Addedlodash.isnumber@3.0.3(transitive)
+ Addedlodash.isplainobject@4.0.6(transitive)
+ Addedlodash.isstring@4.0.1(transitive)
+ Addedlodash.once@4.1.1(transitive)
+ Addedms@2.1.3(transitive)
+ Addedsemver@5.7.2(transitive)
- Removedjsonwebtoken@5.7.0(transitive)
- Removedms@0.7.3(transitive)
- Removedxtend@4.0.2(transitive)
Updatedjsonwebtoken@^8.3.0