Files
upstream-mirror 30810eecd7
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 2s
snapshot of https://github.com/RocketChat/Rocket.Chat.git (develop, 2026-09-16; blobs > 131072B omitted)
2026-09-16 01:21:02 +05:00

199 lines
6.1 KiB
TypeScript

const { subtle } = crypto;
export const randomUUID = () => crypto.randomUUID();
export const getRandomValues = crypto.getRandomValues.bind(crypto);
interface IAesGcmParams extends AesGcmParams {
name: 'AES-GCM';
}
interface IAesCbcParams extends AesCbcParams {
name: 'AES-CBC';
}
interface IAesCtrParams extends AesCtrParams {
name: 'AES-CTR';
}
interface IRsaOaepParams extends RsaOaepParams {
name: 'RSA-OAEP';
}
type ParamsMap = {
'AES-GCM': IAesGcmParams;
'AES-CTR': IAesCtrParams;
'AES-CBC': IAesCbcParams;
'RSA-OAEP': IRsaOaepParams;
};
type ParamsOf<TKey extends IKey> = TKey['algorithm'] extends { name: infer TName extends keyof ParamsMap } ? ParamsMap[TName] : never;
type HasUsage<TKey extends IKey, TUsage extends KeyUsage> = TUsage extends TKey['usages'][number]
? TKey
: TKey & `The provided key cannot be used for ${TUsage}`;
export const encryptBuffer = <TKey extends IKey, TParams extends ParamsOf<TKey>>(
key: HasUsage<TKey, 'encrypt'>,
params: TParams,
data: BufferSource,
): Promise<ArrayBuffer> => subtle.encrypt(params, key, data);
export const decryptBuffer = <TKey extends IKey>(
key: HasUsage<TKey, 'decrypt'>,
params: ParamsOf<TKey>,
data: BufferSource,
): Promise<ArrayBuffer> => subtle.decrypt(params, key, data);
export const deriveBits = (...args: Parameters<typeof subtle.deriveBits>) => subtle.deriveBits(...args);
type AesParams = {
name: 'AES-CBC' | 'AES-GCM' | 'AES-CTR';
length: 128 | 256;
};
type ModeOf<T extends `AES-${'CBC' | 'GCM' | 'CTR'}`> = T extends `AES-${infer Mode}` ? Mode : never;
type Permutations<T> = T extends [infer First]
? [First]
: T extends [infer First, infer Second]
? [First, Second] | [Second, First]
: never;
export interface IKey<
TAlgorithm extends CryptoKey['algorithm'] = CryptoKey['algorithm'],
TExtractable extends CryptoKey['extractable'] = CryptoKey['extractable'],
TType extends CryptoKey['type'] = CryptoKey['type'],
TUsages extends CryptoKey['usages'] = CryptoKey['usages'],
> extends CryptoKey {
readonly algorithm: TAlgorithm;
readonly extractable: TExtractable;
readonly type: TType;
readonly usages: Permutations<TUsages>;
}
export async function generateKey<
const T extends AesParams,
const TExtractable extends boolean = boolean,
const TUsages extends KeyUsage[] = KeyUsage[],
>(algorithm: T, extractable: TExtractable, keyUsages: TUsages): Promise<IKey<T, TExtractable, 'secret', TUsages>> {
const key = await subtle.generateKey(algorithm, extractable, keyUsages);
return key as IKey<T, TExtractable, 'secret', TUsages>;
}
type Filter<TItem extends KeyUsage, TArray extends KeyUsage[], Out extends KeyUsage[] = []> = TArray extends [
infer First extends KeyUsage,
...infer Rest extends KeyUsage[],
]
? First extends TItem
? Filter<TItem, Rest, [...Out, First]>
: Filter<TItem, Rest, Out>
: Out;
export interface IKeyPair<
T extends KeyAlgorithm = KeyAlgorithm,
TExtractable extends boolean = boolean,
TUsages extends KeyUsage[] = KeyUsage[],
> extends CryptoKeyPair {
publicKey: IKey<T, TExtractable, 'public', Filter<'encrypt', TUsages>>;
privateKey: IKey<T, TExtractable, 'private', Filter<'decrypt', TUsages>>;
}
type RsaParams = {
name: 'RSA-OAEP';
modulusLength: 2048;
publicExponent: Uint8Array<ArrayBuffer>;
hash: { name: 'SHA-256' };
};
export async function generateKeyPair<
const T extends RsaParams,
const TExtractable extends boolean = boolean,
const TUsages extends KeyUsage[] = KeyUsage[],
>(algorithm: T, extractable: TExtractable, keyUsages: TUsages): Promise<IKeyPair<T, TExtractable, TUsages>> {
const keyPair = await subtle.generateKey(algorithm, extractable, keyUsages);
return keyPair as IKeyPair<T, TExtractable, TUsages>;
}
type KeyToJwk<T extends IKey> = T['extractable'] extends false
? never
: T['algorithm'] extends AesParams
? {
kty: 'oct';
alg: `A${T['algorithm']['length']}${ModeOf<T['algorithm']['name']>}`;
ext: true;
k: string;
key_ops: T['usages'];
}
: [T['algorithm'], T['type']] extends [RsaParams, 'public']
? {
kty: 'RSA';
alg: 'RSA-OAEP-256';
e: string;
ext: true;
key_ops: T['usages'];
n: string;
}
: [T['algorithm'], T['type']] extends [RsaParams, 'private']
? {
kty: 'RSA';
alg: 'RSA-OAEP-256';
e: string;
ext: true;
d: string;
dp: string;
dq: string;
key_ops: T['usages'];
n: string;
p: string;
q: string;
qi: string;
}
: never;
export type Exported<TFormat extends KeyFormat, TKey extends IKey = IKey> = TFormat extends 'jwk' ? KeyToJwk<TKey> : ArrayBuffer;
export async function exportKey<const TFormat extends KeyFormat = KeyFormat, const TKey extends IKey = IKey>(
format: TFormat,
key: TKey,
): Promise<Exported<TFormat, TKey>> {
const exportedKey = await subtle.exportKey(format, key);
return exportedKey as Exported<TFormat, TKey>;
}
type KtyParams = {
oct: AesParams;
RSA: RsaParams;
};
export async function importJwk<
const TKeyData extends JsonWebKey,
const TAlgorithm extends (TKeyData extends { kty: infer Kty extends keyof KtyParams } ? KtyParams[Kty] : KeyAlgorithm),
const TExtractable extends boolean = boolean,
const TUsages extends KeyUsage[] = KeyUsage[],
const TKeyType extends KeyType = TKeyData extends { kty: 'oct' }
? 'secret'
: TKeyData extends { kty: 'RSA'; key_ops: [infer Op] }
? Op extends 'encrypt'
? 'public'
: 'private'
: KeyType,
>(
jwk: TKeyData,
algorithm: TAlgorithm,
extractable: TExtractable,
keyUsages: TUsages,
): Promise<IKey<TAlgorithm, TExtractable, TKeyType, TUsages>> {
const key = await subtle.importKey('jwk', jwk, algorithm, extractable, keyUsages);
return key as IKey<TAlgorithm, TExtractable, TKeyType, TUsages>;
}
export async function importRaw<
const TAlgorithm extends KeyAlgorithm = KeyAlgorithm,
const TExtractable extends boolean = boolean,
const TUsages extends KeyUsage[] = KeyUsage[],
>(
rawKey: BufferSource,
algorithm: TAlgorithm,
extractable: TExtractable,
keyUsages: TUsages,
): Promise<IKey<TAlgorithm, TExtractable, 'secret', TUsages>> {
const key = await subtle.importKey('raw', rawKey, algorithm, extractable, keyUsages);
return key as IKey<TAlgorithm, TExtractable, 'secret', TUsages>;
}