"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 }