-
Notifications
You must be signed in to change notification settings - Fork 1
Message #20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Message #20
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,266 @@ | ||
| 'use strict'; | ||
| const JWTDecoder = require('../oicMsg/jose/jwt/decode'); | ||
| const JWTSigner = require('../oicMsg/jose/jwt/sign'); | ||
|
|
||
| /** | ||
| * @fileoverview | ||
| * Message is the top layer class that handles common functionality among the | ||
| * different serialization and deserialization types, such as claim | ||
| * verification. When sending request, it must be possible to serialize the | ||
| * information to a format that can be transmitted over-the-wire. Likewise, when | ||
| * receiving responses it must be possible to de-serialize these into an | ||
| * internal representation. Because of this a number of methods have been added | ||
| * to the token profile to support serialization to and deserialization from a | ||
| * number of representations that are used in the OAuth2 and OIDC protocol | ||
| * exchange. | ||
| */ | ||
|
|
||
| /** | ||
| * Message | ||
| * @class | ||
| * @constructor | ||
| */ | ||
| class Message { | ||
| constructor(claims) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add javadoc for what |
||
| if (claims) { | ||
| this.claims = claims; | ||
| } else { | ||
| this.claims = {}; | ||
| } | ||
|
|
||
| this.initData(); | ||
|
|
||
| /** Provided required claims */ | ||
| this.requiredClaims = {}; | ||
|
|
||
| /** Provided optional claims */ | ||
| this.optionalClaims = {}; | ||
|
|
||
| /** Expected required claim values */ | ||
| this.verificationClaims = {}; | ||
|
|
||
| /** Expected optional verification claims that are known */ | ||
| this.optionalVerificationClaims = {}; | ||
|
|
||
| /** None algorithm type */ | ||
| this.noneAlgorithm = false; | ||
|
|
||
| /** Required claims */ | ||
| this.optionsToPayload = []; | ||
|
|
||
| /** Other option values */ | ||
| this.optionsForObjects = []; | ||
|
|
||
| /** Known required claims */ | ||
| this.knownOptionalClaims = []; | ||
|
|
||
| /** Required verification claims */ | ||
| this.claimsForVerification = [] | ||
|
|
||
| /** Key value map of claims that make up the payload of a Message */ | ||
| this.cParam = {}; | ||
|
|
||
| /** Map of allowed values for each claim of Message */ | ||
| this.cAllowedValues = {}; | ||
|
|
||
| return this; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do you need to |
||
| } | ||
|
|
||
| initData() { | ||
| this.noneAlgorithm = false; | ||
| } | ||
|
|
||
| /** | ||
| * Add optional claims | ||
| * @param {?Object<string, string>} optionalClaims Claims that are not required | ||
| * */ | ||
| addOptionalClaims(optionalClaims) { | ||
| this.optionalClaims = optionalClaims; | ||
| this.optionalVerificationClaims = {}; | ||
| for (let i = 0; i < Object.keys(optionalClaims).length; i++){ | ||
| let key = optionalClaims[i]; | ||
| if (key) { | ||
| this.optionalVerificationClaims[key] = key; | ||
| } | ||
| }; | ||
| } | ||
|
|
||
| /** Check for missing required claims */ | ||
| validateRequiredFields() { | ||
| for (let i = 0; i < this.optionsToPayload.length; i++){ | ||
| let key = this.optionsToPayload[i]; | ||
| if (!this[key] === undefined) { | ||
| throw new Error('You are missing a required parameter'); | ||
| } | ||
| }; | ||
| } | ||
|
|
||
| /** Fetch Required claims */ | ||
| getRequiredClaims() { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are these getters defined by the API? |
||
| this.requiredClaims = {}; | ||
| for (let i = 0; i < this.optionsToPayload.length; i++){ | ||
| let key = this.optionsToPayload[i]; | ||
| this.requiredClaims[key] = this[key]; | ||
| } | ||
| return this.requiredClaims; | ||
| } | ||
|
|
||
| /** | ||
| * Fetch optional claims | ||
| */ | ||
| getOptionalClaims() { | ||
| return this.optionalClaims; | ||
| } | ||
|
|
||
| /** Fetch expected verification values for required claims */ | ||
| getVerificationClaims() { | ||
| return this.verificationClaims; | ||
| } | ||
|
|
||
| /** Fetch expected verification values for optional claims */ | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can end your comments with a fullstop: Also define |
||
| getOptionalVerificationClaims() { | ||
| return this.optionalVerificationClaims; | ||
| } | ||
|
|
||
| /** | ||
| * User explicitly wants to set None Algorithm attribute | ||
| * @param {?boolean} boolVal Bool value that determines none algorithm setting | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can this be null? |
||
| * */ | ||
| setNoneAlgorithm(boolVal) { | ||
| this.noneAlgorithm = boolVal; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this is null, you need to convert to boolean: |
||
| } | ||
|
|
||
| /** Fetch current none algorithm bool value */ | ||
| getNoneAlgorithm() { | ||
| return this.noneAlgorithm; | ||
| } | ||
|
|
||
| /** | ||
| * Throws error if required verification claims are not present | ||
| * @param {?Object<string, string>} claimsToVerify Claims that need to be verified | ||
| * */ | ||
| validateRequiredVerificationClaims(claimsToVerify) { | ||
| for (let i = 0; i < this.claimsForVerification.length; i++){ | ||
| let key = this.claimsForVerification[i]; | ||
| if (!claimsToVerify[key]) { | ||
| throw new Error(`Missing required verification claim: ${key}`); | ||
| } | ||
| }; | ||
| this.verificationClaims = claimsToVerify; | ||
| } | ||
|
|
||
| /** | ||
| * Throws error if required non Required verification claims are not present | ||
| * @param {?Object<string, string>} claimsToVerify Claims that need to be verified | ||
| */ | ||
| validateOptionalVerificationClaims(claimsToVerify) { | ||
| if (this.optionalVerificationClaims['nbf'] || | ||
| this.optionalVerificationClaims['exp']) { | ||
| this.optionalVerificationClaimsCheck('clockTolerance', claimsToVerify); | ||
| } | ||
| if (this.optionalVerificationClaims['aud']) { | ||
| this.optionalVerificationClaimsCheck('aud', claimsToVerify); | ||
| } | ||
| } | ||
|
|
||
| optionalVerificationClaimsCheck(key, claimsToVerify) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add javadoc for this function |
||
| if (!claimsToVerify[key]) { | ||
| throw new Error(`Missing required verification claim: ${key}`); | ||
| } else { | ||
| this.verificationClaims[key] = claimsToVerify[key]; | ||
| if (key == 'aud') { | ||
| this.claimsForVerification['aud'] = 'aud'; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Serialization of JWT type | ||
| * Signs JWT and checks for valid input | ||
| * @param secretOrPublicKey is a string or buffer containing either the secret | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This javadoc definition is incorrect: |
||
| for HMAC algorithms, or the PEM encoded public key for RSA and ECDSA | ||
| * @param options consists of other inputs that are not part of the payload, | ||
| for ex : 'algorithm' | ||
| * @param callback is called with the decoded payload if the signature is | ||
| valid and optional expiration, audience, or issuer are valid. If not, it will | ||
| be called with the error. When supplied, the function acts asynchronously. | ||
| **/ | ||
| toJWT(secretOrPrivateKey, options, callback) { | ||
| return JWTSigner.prototype.sign( | ||
| this, secretOrPrivateKey, options, callback); | ||
| } | ||
|
|
||
| /** | ||
| * Deserialization of JWT type | ||
| * Signs JWT and checks for valid input | ||
| * @param {string} signedJWT Signed JWT string | ||
| * @param {*} secretOrPublicKey String or buffer containing either the secret for HMAC algorithms, or the PEM encoded public key for RSA and ECDSA | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use more explicit types
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When comments are too long split to second line. Indent the second line by 4 spaces. |
||
| * @param {?Object<string, string>} claimsToVerify Dictionary contains claims that need to be verified | ||
| * @param {?Object<string, string>} options Consists of other inputs that are not part of the payload, for ex : 'algorithm' | ||
| * @param {*} callback Called with the decoded payload if the signature is valid and optional expiration, audience, or issuer are valid. If not, it | ||
| will be called with the error. When supplied, the function acts | ||
| asynchronously. | ||
| **/ | ||
| fromJWT(signedJWT, secretOrPrivateKey, claimsToVerify, options, callback) { | ||
| this.validateRequiredVerificationClaims(claimsToVerify); | ||
| this.validateOptionalVerificationClaims(claimsToVerify); | ||
| return JWTDecoder.prototype.decode( | ||
| signedJWT, secretOrPrivateKey, this, options, callback); | ||
| } | ||
|
|
||
| /** | ||
| * Serialization of JSON type | ||
| * @param {?Object<string, string>} obj Object that needs to be converted to JSON | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where is the |
||
| */ | ||
| static toJSON(obj) { | ||
| if (obj) { | ||
| this.claims = JSON.stringify(obj); | ||
| }else if (typeof this.claims !== String){ | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix spacing. Also typeof returns a string |
||
| this.claims = JSON.stringify(this.claims); | ||
| } | ||
| return this.claims; | ||
| } | ||
|
|
||
| /** | ||
| * Deserialization of JSON type | ||
| * @param {string} jsonString Json object that needs to be deserialized | ||
| * */ | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| static fromJSON(jsonString) { | ||
| return JSON.parse(jsonString); | ||
| } | ||
|
|
||
| /** | ||
| * Serialization of URL Encoded type | ||
| * @param {?Object<string, string>} obj Object that needs to be URL encoded | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Define |
||
| */ | ||
| static toUrlEncoded(obj) { | ||
| if (!obj) { | ||
| obj = | ||
| Object.assign({}, this.getRequiredClaims(), this.getOptionalClaims()); | ||
| } | ||
| const str = []; | ||
| for (const p in obj) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When traversing an object, you should check You can also use
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
| if (obj.hasOwnProperty(p)){ | ||
| str.push(`${encodeURIComponent(p)}=${encodeURIComponent(obj[p])}`); | ||
| } | ||
| return str.join('&'); | ||
| } | ||
|
|
||
| /** | ||
| * Deserialization of URL Encoded string | ||
| * @param {string} urlEncodedString encoded string that needs to be deserialized | ||
| * */ | ||
| static fromUrlEncoded(urlEncodedString) { | ||
| if (typeof urlEncodedString === 'string') { | ||
| const obj = {}; | ||
| urlEncodedString.replace(/([^=&]+)=([^&]*)/g, (m, key, value) => { | ||
| obj[decodeURIComponent(key)] = decodeURIComponent(value); | ||
| }); | ||
| return obj; | ||
| } else { | ||
| return urlEncodedString; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| module.exports = Message; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This class doesn't have unit tests. Please provide tests.