"Fossies" - the Fresh Open Source Software Archive

Member "jitsi-meet-7555/react/features/base/jwt/functions.ts" (28 Sep 2023, 6536 Bytes) of package /linux/misc/jitsi-meet-7555.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) TypeScript source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "functions.ts": 7550_vs_7553.

    1 // @ts-expect-error
    2 import jwtDecode from 'jwt-decode';
    3 
    4 import { IReduxState } from '../../app/types';
    5 import { getLocalParticipant } from '../participants/functions';
    6 import { parseURLParams } from '../util/parseURLParams';
    7 
    8 import { JWT_VALIDATION_ERRORS, MEET_FEATURES } from './constants';
    9 import logger from './logger';
   10 
   11 /**
   12  * Retrieves the JSON Web Token (JWT), if any, defined by a specific
   13  * {@link URL}.
   14  *
   15  * @param {URL} url - The {@code URL} to parse and retrieve the JSON Web Token
   16  * (JWT), if any, from.
   17  * @returns {string} The JSON Web Token (JWT), if any, defined by the specified
   18  * {@code url}; otherwise, {@code undefined}.
   19  */
   20 export function parseJWTFromURLParams(url: URL | typeof window.location = window.location) {
   21     // @ts-ignore
   22     return parseURLParams(url, true, 'search').jwt;
   23 }
   24 
   25 /**
   26  * Returns the user name after decoding the jwt.
   27  *
   28  * @param {IReduxState} state - The app state.
   29  * @returns {string}
   30  */
   31 export function getJwtName(state: IReduxState) {
   32     const { user } = state['features/base/jwt'];
   33 
   34     return user?.name;
   35 }
   36 
   37 /**
   38  * Check if the given JWT feature is enabled.
   39  *
   40  * @param {IReduxState} state - The app state.
   41  * @param {string} feature - The feature we want to check.
   42  * @param {boolean} ifNoToken - Default value if there is no token.
   43  * @param {boolean} ifNotInFeatures - Default value if features prop exists but does not have the {@code feature}.
   44  * @returns {bolean}
   45  */
   46 export function isJwtFeatureEnabled(state: IReduxState, feature: string, ifNoToken = false, ifNotInFeatures = false) {
   47     const { jwt } = state['features/base/jwt'];
   48 
   49     if (!jwt) {
   50         return ifNoToken;
   51     }
   52 
   53     const { features } = getLocalParticipant(state) || {};
   54 
   55     // If `features` is undefined, act as if everything is enabled.
   56     if (typeof features === 'undefined') {
   57         return true;
   58     }
   59 
   60     if (typeof features[feature as keyof typeof features] === 'undefined') {
   61         return ifNotInFeatures;
   62     }
   63 
   64     return String(features[feature as keyof typeof features]) === 'true';
   65 }
   66 
   67 /**
   68  * Checks whether a given timestamp is a valid UNIX timestamp in seconds.
   69  * We convert to milliseconds during the check since `Date` works with milliseconds for UNIX timestamp values.
   70  *
   71  * @param {any} timestamp - A UNIX timestamp in seconds as stored in the jwt.
   72  * @returns {boolean} - Whether the timestamp is indeed a valid UNIX timestamp or not.
   73  */
   74 function isValidUnixTimestamp(timestamp: number | string) {
   75     return typeof timestamp === 'number' && timestamp * 1000 === new Date(timestamp * 1000).getTime();
   76 }
   77 
   78 /**
   79  * Returns a list with all validation errors for the given jwt.
   80  *
   81  * @param {string} jwt - The jwt.
   82  * @returns {Array} - An array containing all jwt validation errors.
   83  */
   84 export function validateJwt(jwt: string) {
   85     const errors: Object[] = [];
   86     const currentTimestamp = new Date().getTime();
   87 
   88     try {
   89         const header = jwtDecode(jwt, { header: true });
   90         const payload = jwtDecode(jwt);
   91 
   92         if (!header) {
   93             errors.push({ key: JWT_VALIDATION_ERRORS.HEADER_NOT_FOUND });
   94 
   95             return errors;
   96         }
   97 
   98         if (!payload) {
   99             errors.push({ key: JWT_VALIDATION_ERRORS.PAYLOAD_NOT_FOUND });
  100 
  101             return errors;
  102         }
  103 
  104         const {
  105             aud,
  106             context,
  107             exp,
  108             iss,
  109             nbf,
  110             sub
  111         } = payload;
  112 
  113         // JaaS only
  114         if (sub?.startsWith('vpaas-magic-cookie')) {
  115             const { kid } = header;
  116 
  117             // if Key ID is missing, we return the error immediately without further validations.
  118             if (!kid) {
  119                 errors.push({ key: JWT_VALIDATION_ERRORS.KID_NOT_FOUND });
  120 
  121                 return errors;
  122             }
  123 
  124             if (kid.substring(0, kid.indexOf('/')) !== sub) {
  125                 errors.push({ key: JWT_VALIDATION_ERRORS.KID_MISMATCH });
  126             }
  127 
  128             if (aud !== 'jitsi') {
  129                 errors.push({ key: JWT_VALIDATION_ERRORS.AUD_INVALID });
  130             }
  131 
  132             if (iss !== 'chat') {
  133                 errors.push({ key: JWT_VALIDATION_ERRORS.ISS_INVALID });
  134             }
  135 
  136             if (!context?.features) {
  137                 errors.push({ key: JWT_VALIDATION_ERRORS.FEATURES_NOT_FOUND });
  138             }
  139         }
  140 
  141         if (!isValidUnixTimestamp(nbf)) {
  142             errors.push({ key: JWT_VALIDATION_ERRORS.NBF_INVALID });
  143         } else if (currentTimestamp < nbf * 1000) {
  144             errors.push({ key: JWT_VALIDATION_ERRORS.NBF_FUTURE });
  145         }
  146 
  147         if (!isValidUnixTimestamp(exp)) {
  148             errors.push({ key: JWT_VALIDATION_ERRORS.EXP_INVALID });
  149         } else if (currentTimestamp > exp * 1000) {
  150             errors.push({ key: JWT_VALIDATION_ERRORS.TOKEN_EXPIRED });
  151         }
  152 
  153         if (!context) {
  154             errors.push({ key: JWT_VALIDATION_ERRORS.CONTEXT_NOT_FOUND });
  155         } else if (context.features) {
  156             const { features } = context;
  157             const meetFeatures = Object.values(MEET_FEATURES);
  158 
  159             Object.keys(features).forEach(feature => {
  160                 if (meetFeatures.includes(feature)) {
  161                     const featureValue = features[feature];
  162 
  163                     // cannot use truthy or falsy because we need the exact value and type check.
  164                     if (
  165                         featureValue !== true
  166                         && featureValue !== false
  167                         && featureValue !== 'true'
  168                         && featureValue !== 'false'
  169                     ) {
  170                         errors.push({
  171                             key: JWT_VALIDATION_ERRORS.FEATURE_VALUE_INVALID,
  172                             args: { feature }
  173                         });
  174                     }
  175                 } else {
  176                     errors.push({
  177                         key: JWT_VALIDATION_ERRORS.FEATURE_INVALID,
  178                         args: { feature }
  179                     });
  180                 }
  181             });
  182         }
  183     } catch (e: any) {
  184         logger.error(`Unspecified JWT error${e?.message ? `: ${e.message}` : ''}`);
  185     }
  186 
  187     return errors;
  188 }
  189 
  190 /**
  191  * Extracts and returns the expiration date of jwt.
  192  *
  193  * @param {string|undefined} jwt - The jwt to check.
  194  * @returns {Date} The expiration date of the jwt.
  195  */
  196 export function getJwtExpirationDate(jwt: string | undefined) {
  197     if (!jwt) {
  198         return;
  199     }
  200 
  201     const payload = jwtDecode(jwt);
  202 
  203     if (payload) {
  204         const { exp } = payload;
  205 
  206         return new Date(exp * 1000);
  207     }
  208 }