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; |