|
|
|
@ -5,7 +5,8 @@ import { IReduxState } from '../../app/types'; |
|
|
|
|
import { getLocalParticipant } from '../participants/functions'; |
|
|
|
|
import { parseURLParams } from '../util/parseURLParams'; |
|
|
|
|
|
|
|
|
|
import { MEET_FEATURES } from './constants'; |
|
|
|
|
import { JWT_VALIDATION_ERRORS, MEET_FEATURES } from './constants'; |
|
|
|
|
import logger from './logger'; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Retrieves the JSON Web Token (JWT), if any, defined by a specific |
|
|
|
@ -78,23 +79,24 @@ function isValidUnixTimestamp(timestamp: number | string) { |
|
|
|
|
* Returns a list with all validation errors for the given jwt. |
|
|
|
|
* |
|
|
|
|
* @param {string} jwt - The jwt. |
|
|
|
|
* @returns {Array<string>} - An array containing all jwt validation errors. |
|
|
|
|
* @returns {Array} - An array containing all jwt validation errors. |
|
|
|
|
*/ |
|
|
|
|
export function validateJwt(jwt: string) { |
|
|
|
|
const errors: string[] = []; |
|
|
|
|
|
|
|
|
|
if (!jwt) { |
|
|
|
|
return errors; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const errors: Object[] = []; |
|
|
|
|
const currentTimestamp = new Date().getTime(); |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
const header = jwtDecode(jwt, { header: true }); |
|
|
|
|
const payload = jwtDecode(jwt); |
|
|
|
|
|
|
|
|
|
if (!header || !payload) { |
|
|
|
|
errors.push('- Missing header or payload'); |
|
|
|
|
if (!header) { |
|
|
|
|
errors.push({ key: JWT_VALIDATION_ERRORS.HEADER_NOT_FOUND }); |
|
|
|
|
|
|
|
|
|
return errors; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!payload) { |
|
|
|
|
errors.push({ key: JWT_VALIDATION_ERRORS.PAYLOAD_NOT_FOUND }); |
|
|
|
|
|
|
|
|
|
return errors; |
|
|
|
|
} |
|
|
|
@ -114,42 +116,42 @@ export function validateJwt(jwt: string) { |
|
|
|
|
|
|
|
|
|
// if Key ID is missing, we return the error immediately without further validations.
|
|
|
|
|
if (!kid) { |
|
|
|
|
errors.push('- Key ID(kid) missing'); |
|
|
|
|
errors.push({ key: JWT_VALIDATION_ERRORS.KID_NOT_FOUND }); |
|
|
|
|
|
|
|
|
|
return errors; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (kid.substring(0, kid.indexOf('/')) !== sub) { |
|
|
|
|
errors.push('- Key ID(kid) does not match sub'); |
|
|
|
|
errors.push({ key: JWT_VALIDATION_ERRORS.KID_MISMATCH }); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (aud !== 'jitsi') { |
|
|
|
|
errors.push('- invalid `aud` value. It should be `jitsi`'); |
|
|
|
|
errors.push({ key: JWT_VALIDATION_ERRORS.AUD_INVALID }); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (iss !== 'chat') { |
|
|
|
|
errors.push('- invalid `iss` value. It should be `chat`'); |
|
|
|
|
errors.push({ key: JWT_VALIDATION_ERRORS.ISS_INVALID }); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!context?.features) { |
|
|
|
|
errors.push('- `features` object is missing from the payload'); |
|
|
|
|
errors.push({ key: JWT_VALIDATION_ERRORS.FEATURES_NOT_FOUND }); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!isValidUnixTimestamp(nbf)) { |
|
|
|
|
errors.push('- invalid `nbf` value'); |
|
|
|
|
errors.push({ key: JWT_VALIDATION_ERRORS.NBF_INVALID }); |
|
|
|
|
} else if (currentTimestamp < nbf * 1000) { |
|
|
|
|
errors.push('- `nbf` value is in the future'); |
|
|
|
|
errors.push({ key: JWT_VALIDATION_ERRORS.NBF_FUTURE }); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!isValidUnixTimestamp(exp)) { |
|
|
|
|
errors.push('- invalid `exp` value'); |
|
|
|
|
errors.push({ key: JWT_VALIDATION_ERRORS.EXP_INVALID }); |
|
|
|
|
} else if (currentTimestamp > exp * 1000) { |
|
|
|
|
errors.push('- token is expired'); |
|
|
|
|
errors.push({ key: JWT_VALIDATION_ERRORS.TOKEN_EXPIRED }); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!context) { |
|
|
|
|
errors.push('- `context` object is missing from the payload'); |
|
|
|
|
errors.push({ key: JWT_VALIDATION_ERRORS.CONTEXT_NOT_FOUND }); |
|
|
|
|
} else if (context.features) { |
|
|
|
|
const { features } = context; |
|
|
|
|
const meetFeatures = Object.values(MEET_FEATURES); |
|
|
|
@ -165,15 +167,21 @@ export function validateJwt(jwt: string) { |
|
|
|
|
&& featureValue !== 'true' |
|
|
|
|
&& featureValue !== 'false' |
|
|
|
|
) { |
|
|
|
|
errors.push(`- Invalid value for feature: ${feature}`); |
|
|
|
|
errors.push({ |
|
|
|
|
key: JWT_VALIDATION_ERRORS.FEATURE_VALUE_INVALID, |
|
|
|
|
args: { feature } |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
errors.push(`- Invalid feature: ${feature}`); |
|
|
|
|
errors.push({ |
|
|
|
|
key: JWT_VALIDATION_ERRORS.FEATURE_INVALID, |
|
|
|
|
args: { feature } |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
} catch (e: any) { |
|
|
|
|
errors.push(e ? e.message : '- unspecified jwt error'); |
|
|
|
|
logger.error(`Unspecified JWT error${e?.message ? `: ${e.message}` : ''}`); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return errors; |
|
|
|
|