Some checks failed
Close stale issues and PRs / stale (push) Has been cancelled
135 lines
3.3 KiB
TypeScript
135 lines
3.3 KiB
TypeScript
import fs from 'fs';
|
|
import jwt from 'jsonwebtoken';
|
|
import { v4 as uuidv4 } from 'uuid';
|
|
|
|
import { config } from './TestsConfig';
|
|
|
|
export type ITokenOptions = {
|
|
displayName?: string;
|
|
/**
|
|
* The duration for which the token is valid, e.g. "1h" for one hour.
|
|
*/
|
|
exp?: string;
|
|
/**
|
|
* The key ID to use for the token.
|
|
* If not provided, the kid configured with environment variables will be used (see env.example).
|
|
*/
|
|
keyId?: string;
|
|
/**
|
|
* The path to the private key file used to sign the token.
|
|
* If not provided, the path configured with environment variables will be used (see env.example).
|
|
*/
|
|
keyPath?: string;
|
|
/**
|
|
* Whether to set the 'moderator' flag.
|
|
*/
|
|
moderator?: boolean;
|
|
/**
|
|
* The room for which the token is valid, or '*'. Defaults to '*'.
|
|
*/
|
|
room?: string;
|
|
sub?: string;
|
|
/**
|
|
* Whether to set the 'visitor' flag.
|
|
*/
|
|
visitor?: boolean;
|
|
};
|
|
|
|
export type IToken = {
|
|
/**
|
|
* The JWT headers, for easy reference.
|
|
*/
|
|
headers?: any;
|
|
/**
|
|
* The signed JWT.
|
|
*/
|
|
jwt: string;
|
|
/**
|
|
* The options used to generate the token.
|
|
*/
|
|
options?: ITokenOptions;
|
|
/**
|
|
* The token's payload, for easy reference.
|
|
*/
|
|
payload?: any;
|
|
};
|
|
|
|
export function generatePayload(options: ITokenOptions): any {
|
|
const payload = {
|
|
'aud': 'jitsi',
|
|
'iss': 'chat',
|
|
'sub': options?.sub || '',
|
|
'context': {
|
|
'user': {
|
|
'name': options.displayName,
|
|
'id': uuidv4(),
|
|
'avatar': 'https://avatars0.githubusercontent.com/u/3671647',
|
|
'email': 'john.doe@jitsi.org'
|
|
},
|
|
'group': uuidv4(),
|
|
'features': {
|
|
'outbound-call': 'true',
|
|
'transcription': 'true',
|
|
'recording': 'true',
|
|
'sip-outbound-call': true,
|
|
'livestreaming': true
|
|
},
|
|
},
|
|
'room': options.room || '*'
|
|
};
|
|
|
|
if (options.moderator) {
|
|
// @ts-ignore
|
|
payload.context.user.moderator = true;
|
|
} else if (options.visitor) {
|
|
// @ts-ignore
|
|
payload.context.user.role = 'visitor';
|
|
}
|
|
|
|
return payload;
|
|
}
|
|
|
|
/**
|
|
* Generate a signed token.
|
|
*/
|
|
export function generateToken(options: ITokenOptions): IToken {
|
|
const keyId = options.keyId || config.jwt.kid;
|
|
const keyPath = options.keyPath || config.jwt.privateKeyPath;
|
|
const headers = {
|
|
algorithm: 'RS256',
|
|
noTimestamp: true,
|
|
expiresIn: options.exp || '24h',
|
|
keyid: keyId,
|
|
};
|
|
|
|
if (!keyId) {
|
|
throw new Error('No keyId provided (JWT_KID is not set?)');
|
|
}
|
|
|
|
if (!keyPath) {
|
|
throw new Error('No keyPath provided (JWT_PRIVATE_KEY_PATH is not set?)');
|
|
}
|
|
|
|
const key = fs.readFileSync(keyPath);
|
|
const payload = generatePayload({
|
|
...options,
|
|
displayName: options?.displayName || '',
|
|
sub: keyId.substring(0, keyId.indexOf('/'))
|
|
});
|
|
|
|
return {
|
|
headers,
|
|
// @ts-ignore
|
|
jwt: jwt.sign(payload, key, headers),
|
|
options,
|
|
payload
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Generated a signed token and return just the JWT string.
|
|
*/
|
|
export function generateJwt(options: ITokenOptions): string {
|
|
return generateToken(options).jwt;
|
|
}
|