You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					121 lines
				
				3.2 KiB
			
		
		
			
		
	
	
					121 lines
				
				3.2 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								/*global module*/
							 | 
						||
| 
								 | 
							
								var Buffer = require('safe-buffer').Buffer;
							 | 
						||
| 
								 | 
							
								var DataStream = require('./data-stream');
							 | 
						||
| 
								 | 
							
								var jwa = require('jwa');
							 | 
						||
| 
								 | 
							
								var Stream = require('stream');
							 | 
						||
| 
								 | 
							
								var toString = require('./tostring');
							 | 
						||
| 
								 | 
							
								var util = require('util');
							 | 
						||
| 
								 | 
							
								var JWS_REGEX = /^[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.([a-zA-Z0-9\-_]+)?$/;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function isObject(thing) {
							 | 
						||
| 
								 | 
							
								  return Object.prototype.toString.call(thing) === '[object Object]';
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function safeJsonParse(thing) {
							 | 
						||
| 
								 | 
							
								  if (isObject(thing))
							 | 
						||
| 
								 | 
							
								    return thing;
							 | 
						||
| 
								 | 
							
								  try { return JSON.parse(thing); }
							 | 
						||
| 
								 | 
							
								  catch (e) { return undefined; }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function headerFromJWS(jwsSig) {
							 | 
						||
| 
								 | 
							
								  var encodedHeader = jwsSig.split('.', 1)[0];
							 | 
						||
| 
								 | 
							
								  return safeJsonParse(Buffer.from(encodedHeader, 'base64').toString('binary'));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function securedInputFromJWS(jwsSig) {
							 | 
						||
| 
								 | 
							
								  return jwsSig.split('.', 2).join('.');
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function signatureFromJWS(jwsSig) {
							 | 
						||
| 
								 | 
							
								  return jwsSig.split('.')[2];
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function payloadFromJWS(jwsSig, encoding) {
							 | 
						||
| 
								 | 
							
								  encoding = encoding || 'utf8';
							 | 
						||
| 
								 | 
							
								  var payload = jwsSig.split('.')[1];
							 | 
						||
| 
								 | 
							
								  return Buffer.from(payload, 'base64').toString(encoding);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function isValidJws(string) {
							 | 
						||
| 
								 | 
							
								  return JWS_REGEX.test(string) && !!headerFromJWS(string);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function jwsVerify(jwsSig, algorithm, secretOrKey) {
							 | 
						||
| 
								 | 
							
								  if (!algorithm) {
							 | 
						||
| 
								 | 
							
								    var err = new Error("Missing algorithm parameter for jws.verify");
							 | 
						||
| 
								 | 
							
								    err.code = "MISSING_ALGORITHM";
							 | 
						||
| 
								 | 
							
								    throw err;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  jwsSig = toString(jwsSig);
							 | 
						||
| 
								 | 
							
								  var signature = signatureFromJWS(jwsSig);
							 | 
						||
| 
								 | 
							
								  var securedInput = securedInputFromJWS(jwsSig);
							 | 
						||
| 
								 | 
							
								  var algo = jwa(algorithm);
							 | 
						||
| 
								 | 
							
								  return algo.verify(securedInput, signature, secretOrKey);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function jwsDecode(jwsSig, opts) {
							 | 
						||
| 
								 | 
							
								  opts = opts || {};
							 | 
						||
| 
								 | 
							
								  jwsSig = toString(jwsSig);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!isValidJws(jwsSig))
							 | 
						||
| 
								 | 
							
								    return null;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var header = headerFromJWS(jwsSig);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!header)
							 | 
						||
| 
								 | 
							
								    return null;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var payload = payloadFromJWS(jwsSig);
							 | 
						||
| 
								 | 
							
								  if (header.typ === 'JWT' || opts.json)
							 | 
						||
| 
								 | 
							
								    payload = JSON.parse(payload, opts.encoding);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return {
							 | 
						||
| 
								 | 
							
								    header: header,
							 | 
						||
| 
								 | 
							
								    payload: payload,
							 | 
						||
| 
								 | 
							
								    signature: signatureFromJWS(jwsSig)
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function VerifyStream(opts) {
							 | 
						||
| 
								 | 
							
								  opts = opts || {};
							 | 
						||
| 
								 | 
							
								  var secretOrKey = opts.secret||opts.publicKey||opts.key;
							 | 
						||
| 
								 | 
							
								  var secretStream = new DataStream(secretOrKey);
							 | 
						||
| 
								 | 
							
								  this.readable = true;
							 | 
						||
| 
								 | 
							
								  this.algorithm = opts.algorithm;
							 | 
						||
| 
								 | 
							
								  this.encoding = opts.encoding;
							 | 
						||
| 
								 | 
							
								  this.secret = this.publicKey = this.key = secretStream;
							 | 
						||
| 
								 | 
							
								  this.signature = new DataStream(opts.signature);
							 | 
						||
| 
								 | 
							
								  this.secret.once('close', function () {
							 | 
						||
| 
								 | 
							
								    if (!this.signature.writable && this.readable)
							 | 
						||
| 
								 | 
							
								      this.verify();
							 | 
						||
| 
								 | 
							
								  }.bind(this));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.signature.once('close', function () {
							 | 
						||
| 
								 | 
							
								    if (!this.secret.writable && this.readable)
							 | 
						||
| 
								 | 
							
								      this.verify();
							 | 
						||
| 
								 | 
							
								  }.bind(this));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								util.inherits(VerifyStream, Stream);
							 | 
						||
| 
								 | 
							
								VerifyStream.prototype.verify = function verify() {
							 | 
						||
| 
								 | 
							
								  try {
							 | 
						||
| 
								 | 
							
								    var valid = jwsVerify(this.signature.buffer, this.algorithm, this.key.buffer);
							 | 
						||
| 
								 | 
							
								    var obj = jwsDecode(this.signature.buffer, this.encoding);
							 | 
						||
| 
								 | 
							
								    this.emit('done', valid, obj);
							 | 
						||
| 
								 | 
							
								    this.emit('data', valid);
							 | 
						||
| 
								 | 
							
								    this.emit('end');
							 | 
						||
| 
								 | 
							
								    this.readable = false;
							 | 
						||
| 
								 | 
							
								    return valid;
							 | 
						||
| 
								 | 
							
								  } catch (e) {
							 | 
						||
| 
								 | 
							
								    this.readable = false;
							 | 
						||
| 
								 | 
							
								    this.emit('error', e);
							 | 
						||
| 
								 | 
							
								    this.emit('close');
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								VerifyStream.decode = jwsDecode;
							 | 
						||
| 
								 | 
							
								VerifyStream.isValid = isValidJws;
							 | 
						||
| 
								 | 
							
								VerifyStream.verify = jwsVerify;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = VerifyStream;
							 |