pubnub
Version:
Publish & Subscribe Real-time Messaging with PubNub
288 lines (254 loc) • 7.81 kB
text/typescript
/**
* Crypto module.
*/
import { PubNubFileConstructor, PubNubFileInterface } from '../types/file';
import { LoggerManager } from '../components/logger-manager';
import { Payload } from '../types/api';
/**
* Crypto module configuration.
*/
export type CryptoModuleConfiguration<C> = {
default: C;
cryptors?: C[];
};
export type CryptorConfiguration = {
/**
* Data encryption / decryption key.
*/
cipherKey?: string;
/**
* Request sign secret key.
*/
secretKey?: string;
/**
* Whether random initialization vector should be used or not.
*
* @default `true`
*/
useRandomIVs?: boolean;
/**
* Custom data encryption method.
*
* @deprecated Instead use {@link cryptoModule} for data encryption.
*/
customEncrypt?: (data: string | Payload) => string;
/**
* Custom data decryption method.
*
* @deprecated Instead use {@link cryptoModule} for data decryption.
*/
customDecrypt?: (data: string) => string;
/**
* Registered loggers' manager.
*
* @internal
*/
logger?: LoggerManager;
};
/**
* Base crypto module interface.
*/
export interface ICryptoModule {
/**
* Update module's logger.
*
* @param logger - Logger, which should be used by crypto module.
*
* @internal
*/
set logger(logger: LoggerManager);
// --------------------------------------------------------
// --------------------- Encryption -----------------------
// --------------------------------------------------------
// region Encryption
/**
* Encrypt data.
*
* @param data - Data which should be encrypted using `CryptoModule`.
*
* @returns Data encryption result.
*/
encrypt(data: ArrayBuffer | string): ArrayBuffer | string;
/**
* Encrypt file object.
*
* @param file - File object with data for encryption.
* @param File - File object constructor to create instance for encrypted data representation.
*
* @returns Asynchronous file encryption result.
*/
encryptFile(
file: PubNubFileInterface,
/* eslint-disable @typescript-eslint/no-explicit-any */
File: PubNubFileConstructor<PubNubFileInterface, any>,
): Promise<PubNubFileInterface | undefined>;
// endregion
// --------------------------------------------------------
// --------------------- Decryption -----------------------
// --------------------------------------------------------
// region Decryption
/**
* Encrypt data.
*
* @param data - Dta which should be encrypted using `CryptoModule`.
*
* @returns Data decryption result.
*/
decrypt(data: ArrayBuffer | string): ArrayBuffer | Payload | null;
/**
* Decrypt file object.
*
* @param file - Encrypted file object with data for decryption.
* @param File - File object constructor to create instance for decrypted data representation.
*
* @returns Asynchronous file decryption result.
*/
decryptFile(
file: PubNubFileInterface,
/* eslint-disable @typescript-eslint/no-explicit-any */
File: PubNubFileConstructor<PubNubFileInterface, any>,
): Promise<PubNubFileInterface | undefined>;
// endregion
}
export abstract class AbstractCryptoModule<C> implements ICryptoModule {
/**
* `String` to {@link ArrayBuffer} response decoder.
*
* @internal
*/
protected static encoder = new TextEncoder();
/**
* {@link ArrayBuffer} to {@link string} decoder.
*
* @internal
*/
protected static decoder = new TextDecoder();
/**
* Registered loggers' manager.
*
* @internal
*/
static logger: LoggerManager;
defaultCryptor: C;
cryptors: C[];
// --------------------------------------------------------
// --------------- Convenience functions ------------------
// --------------------------------------------------------
// region Convenience functions
/**
* Construct crypto module with legacy cryptor for encryption and both legacy and AES-CBC
* cryptors for decryption.
*
* @param config Cryptors configuration options.
*
* @returns Crypto module which encrypts data using legacy cryptor.
*
* @throws Error if `config.cipherKey` not set.
*/
static legacyCryptoModule(config: CryptorConfiguration): ICryptoModule {
throw new Error('Should be implemented by concrete crypto module implementation.');
}
/**
* Construct crypto module with AES-CBC cryptor for encryption and both AES-CBC and legacy
* cryptors for decryption.
*
* @param config Cryptors configuration options.
*
* @returns Crypto module which encrypts data using AES-CBC cryptor.
*
* @throws Error if `config.cipherKey` not set.
*/
static aesCbcCryptoModule(config: CryptorConfiguration): ICryptoModule {
throw new Error('Should be implemented by concrete crypto module implementation.');
}
// endregion
constructor(configuration: CryptoModuleConfiguration<C>) {
this.defaultCryptor = configuration.default;
this.cryptors = configuration.cryptors ?? [];
}
/**
* Assign registered loggers' manager.
*
* @param _logger - Registered loggers' manager.
*
* @internal
*/
set logger(_logger: LoggerManager) {
throw new Error('Method not implemented.');
}
// --------------------------------------------------------
// --------------------- Encryption -----------------------
// --------------------------------------------------------
// region Encryption
/**
* Encrypt data.
*
* @param data - Data which should be encrypted using {@link ICryptoModule}.
*
* @returns Data encryption result.
*/
abstract encrypt(data: ArrayBuffer | string): ArrayBuffer | string;
/**
* Encrypt file object.
*
* @param file - File object with data for encryption.
* @param File - File object constructor to create instance for encrypted data representation.
*
* @returns Asynchronous file encryption result.
*/
abstract encryptFile(
file: PubNubFileInterface,
/* eslint-disable @typescript-eslint/no-explicit-any */
File: PubNubFileConstructor<PubNubFileInterface, any>,
): Promise<PubNubFileInterface | undefined>;
// endregion
// --------------------------------------------------------
// --------------------- Decryption -----------------------
// --------------------------------------------------------
// region Decryption
/**
* Encrypt data.
*
* @param data - Dta which should be encrypted using `ICryptoModule`.
*
* @returns Data decryption result.
*/
abstract decrypt(data: ArrayBuffer | string): ArrayBuffer | Payload | null;
/**
* Decrypt file object.
*
* @param file - Encrypted file object with data for decryption.
* @param File - File object constructor to create instance for decrypted data representation.
*
* @returns Asynchronous file decryption result.
*/
abstract decryptFile(
file: PubNubFileInterface,
/* eslint-disable @typescript-eslint/no-explicit-any */
File: PubNubFileConstructor<PubNubFileInterface, any>,
): Promise<PubNubFileInterface | undefined>;
// endregion
// --------------------------------------------------------
// ----------------------- Helpers ------------------------
// --------------------------------------------------------
// region Helpers
/**
* Retrieve list of module's cryptors.
*
* @internal
*/
protected getAllCryptors() {
return [this.defaultCryptor, ...this.cryptors];
}
// endregion
/**
* Serialize crypto module information to string.
*
* @returns Serialized crypto module information.
*/
toString() {
return `AbstractCryptoModule { default: ${(
this.defaultCryptor as object
).toString()}, cryptors: [${this.cryptors.map((c) => (c as object).toString()).join(', ')}]}`;
}
}