
- Complete NestJS TypeScript implementation with WebSocket support - Direct messaging (DM) and group chat functionality - End-to-end encryption with AES encryption and key pairs - Media file support (images, videos, audio, documents) up to 100MB - Push notifications with Firebase Cloud Messaging integration - Mention alerts and real-time typing indicators - User authentication with JWT and Passport - SQLite database with TypeORM entities and relationships - Comprehensive API documentation with Swagger/OpenAPI - File upload handling with secure access control - Online/offline status tracking and presence management - Message editing, deletion, and reply functionality - Notification management with automatic cleanup - Health check endpoint for monitoring - CORS configuration for cross-origin requests - Environment-based configuration management - Structured for Flutter SDK integration Features implemented: ✅ Real-time messaging with Socket.IO ✅ User registration and authentication ✅ Direct messages and group chats ✅ Media file uploads and management ✅ End-to-end encryption ✅ Push notifications ✅ Mention alerts ✅ Typing indicators ✅ Message read receipts ✅ Online status tracking ✅ File access control ✅ Comprehensive API documentation Ready for Flutter SDK development and production deployment.
239 lines
8.9 KiB
JavaScript
239 lines
8.9 KiB
JavaScript
"use strict";
|
||
Object.defineProperty(exports, "__esModule", { value: true });
|
||
exports.shake256 = exports.shake128 = exports.keccak_512 = exports.keccak_384 = exports.keccak_256 = exports.keccak_224 = exports.sha3_512 = exports.sha3_384 = exports.sha3_256 = exports.sha3_224 = exports.Keccak = void 0;
|
||
exports.keccakP = keccakP;
|
||
/**
|
||
* SHA3 (keccak) hash function, based on a new "Sponge function" design.
|
||
* Different from older hashes, the internal state is bigger than output size.
|
||
*
|
||
* Check out [FIPS-202](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf),
|
||
* [Website](https://keccak.team/keccak.html),
|
||
* [the differences between SHA-3 and Keccak](https://crypto.stackexchange.com/questions/15727/what-are-the-key-differences-between-the-draft-sha-3-standard-and-the-keccak-sub).
|
||
*
|
||
* Check out `sha3-addons` module for cSHAKE, k12, and others.
|
||
* @module
|
||
*/
|
||
const _u64_ts_1 = require("./_u64.js");
|
||
// prettier-ignore
|
||
const utils_ts_1 = require("./utils.js");
|
||
// No __PURE__ annotations in sha3 header:
|
||
// EVERYTHING is in fact used on every export.
|
||
// Various per round constants calculations
|
||
const _0n = BigInt(0);
|
||
const _1n = BigInt(1);
|
||
const _2n = BigInt(2);
|
||
const _7n = BigInt(7);
|
||
const _256n = BigInt(256);
|
||
const _0x71n = BigInt(0x71);
|
||
const SHA3_PI = [];
|
||
const SHA3_ROTL = [];
|
||
const _SHA3_IOTA = [];
|
||
for (let round = 0, R = _1n, x = 1, y = 0; round < 24; round++) {
|
||
// Pi
|
||
[x, y] = [y, (2 * x + 3 * y) % 5];
|
||
SHA3_PI.push(2 * (5 * y + x));
|
||
// Rotational
|
||
SHA3_ROTL.push((((round + 1) * (round + 2)) / 2) % 64);
|
||
// Iota
|
||
let t = _0n;
|
||
for (let j = 0; j < 7; j++) {
|
||
R = ((R << _1n) ^ ((R >> _7n) * _0x71n)) % _256n;
|
||
if (R & _2n)
|
||
t ^= _1n << ((_1n << /* @__PURE__ */ BigInt(j)) - _1n);
|
||
}
|
||
_SHA3_IOTA.push(t);
|
||
}
|
||
const IOTAS = (0, _u64_ts_1.split)(_SHA3_IOTA, true);
|
||
const SHA3_IOTA_H = IOTAS[0];
|
||
const SHA3_IOTA_L = IOTAS[1];
|
||
// Left rotation (without 0, 32, 64)
|
||
const rotlH = (h, l, s) => (s > 32 ? (0, _u64_ts_1.rotlBH)(h, l, s) : (0, _u64_ts_1.rotlSH)(h, l, s));
|
||
const rotlL = (h, l, s) => (s > 32 ? (0, _u64_ts_1.rotlBL)(h, l, s) : (0, _u64_ts_1.rotlSL)(h, l, s));
|
||
/** `keccakf1600` internal function, additionally allows to adjust round count. */
|
||
function keccakP(s, rounds = 24) {
|
||
const B = new Uint32Array(5 * 2);
|
||
// NOTE: all indices are x2 since we store state as u32 instead of u64 (bigints to slow in js)
|
||
for (let round = 24 - rounds; round < 24; round++) {
|
||
// Theta θ
|
||
for (let x = 0; x < 10; x++)
|
||
B[x] = s[x] ^ s[x + 10] ^ s[x + 20] ^ s[x + 30] ^ s[x + 40];
|
||
for (let x = 0; x < 10; x += 2) {
|
||
const idx1 = (x + 8) % 10;
|
||
const idx0 = (x + 2) % 10;
|
||
const B0 = B[idx0];
|
||
const B1 = B[idx0 + 1];
|
||
const Th = rotlH(B0, B1, 1) ^ B[idx1];
|
||
const Tl = rotlL(B0, B1, 1) ^ B[idx1 + 1];
|
||
for (let y = 0; y < 50; y += 10) {
|
||
s[x + y] ^= Th;
|
||
s[x + y + 1] ^= Tl;
|
||
}
|
||
}
|
||
// Rho (ρ) and Pi (π)
|
||
let curH = s[2];
|
||
let curL = s[3];
|
||
for (let t = 0; t < 24; t++) {
|
||
const shift = SHA3_ROTL[t];
|
||
const Th = rotlH(curH, curL, shift);
|
||
const Tl = rotlL(curH, curL, shift);
|
||
const PI = SHA3_PI[t];
|
||
curH = s[PI];
|
||
curL = s[PI + 1];
|
||
s[PI] = Th;
|
||
s[PI + 1] = Tl;
|
||
}
|
||
// Chi (χ)
|
||
for (let y = 0; y < 50; y += 10) {
|
||
for (let x = 0; x < 10; x++)
|
||
B[x] = s[y + x];
|
||
for (let x = 0; x < 10; x++)
|
||
s[y + x] ^= ~B[(x + 2) % 10] & B[(x + 4) % 10];
|
||
}
|
||
// Iota (ι)
|
||
s[0] ^= SHA3_IOTA_H[round];
|
||
s[1] ^= SHA3_IOTA_L[round];
|
||
}
|
||
(0, utils_ts_1.clean)(B);
|
||
}
|
||
/** Keccak sponge function. */
|
||
class Keccak extends utils_ts_1.Hash {
|
||
// NOTE: we accept arguments in bytes instead of bits here.
|
||
constructor(blockLen, suffix, outputLen, enableXOF = false, rounds = 24) {
|
||
super();
|
||
this.pos = 0;
|
||
this.posOut = 0;
|
||
this.finished = false;
|
||
this.destroyed = false;
|
||
this.enableXOF = false;
|
||
this.blockLen = blockLen;
|
||
this.suffix = suffix;
|
||
this.outputLen = outputLen;
|
||
this.enableXOF = enableXOF;
|
||
this.rounds = rounds;
|
||
// Can be passed from user as dkLen
|
||
(0, utils_ts_1.anumber)(outputLen);
|
||
// 1600 = 5x5 matrix of 64bit. 1600 bits === 200 bytes
|
||
// 0 < blockLen < 200
|
||
if (!(0 < blockLen && blockLen < 200))
|
||
throw new Error('only keccak-f1600 function is supported');
|
||
this.state = new Uint8Array(200);
|
||
this.state32 = (0, utils_ts_1.u32)(this.state);
|
||
}
|
||
clone() {
|
||
return this._cloneInto();
|
||
}
|
||
keccak() {
|
||
(0, utils_ts_1.swap32IfBE)(this.state32);
|
||
keccakP(this.state32, this.rounds);
|
||
(0, utils_ts_1.swap32IfBE)(this.state32);
|
||
this.posOut = 0;
|
||
this.pos = 0;
|
||
}
|
||
update(data) {
|
||
(0, utils_ts_1.aexists)(this);
|
||
data = (0, utils_ts_1.toBytes)(data);
|
||
(0, utils_ts_1.abytes)(data);
|
||
const { blockLen, state } = this;
|
||
const len = data.length;
|
||
for (let pos = 0; pos < len;) {
|
||
const take = Math.min(blockLen - this.pos, len - pos);
|
||
for (let i = 0; i < take; i++)
|
||
state[this.pos++] ^= data[pos++];
|
||
if (this.pos === blockLen)
|
||
this.keccak();
|
||
}
|
||
return this;
|
||
}
|
||
finish() {
|
||
if (this.finished)
|
||
return;
|
||
this.finished = true;
|
||
const { state, suffix, pos, blockLen } = this;
|
||
// Do the padding
|
||
state[pos] ^= suffix;
|
||
if ((suffix & 0x80) !== 0 && pos === blockLen - 1)
|
||
this.keccak();
|
||
state[blockLen - 1] ^= 0x80;
|
||
this.keccak();
|
||
}
|
||
writeInto(out) {
|
||
(0, utils_ts_1.aexists)(this, false);
|
||
(0, utils_ts_1.abytes)(out);
|
||
this.finish();
|
||
const bufferOut = this.state;
|
||
const { blockLen } = this;
|
||
for (let pos = 0, len = out.length; pos < len;) {
|
||
if (this.posOut >= blockLen)
|
||
this.keccak();
|
||
const take = Math.min(blockLen - this.posOut, len - pos);
|
||
out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos);
|
||
this.posOut += take;
|
||
pos += take;
|
||
}
|
||
return out;
|
||
}
|
||
xofInto(out) {
|
||
// Sha3/Keccak usage with XOF is probably mistake, only SHAKE instances can do XOF
|
||
if (!this.enableXOF)
|
||
throw new Error('XOF is not possible for this instance');
|
||
return this.writeInto(out);
|
||
}
|
||
xof(bytes) {
|
||
(0, utils_ts_1.anumber)(bytes);
|
||
return this.xofInto(new Uint8Array(bytes));
|
||
}
|
||
digestInto(out) {
|
||
(0, utils_ts_1.aoutput)(out, this);
|
||
if (this.finished)
|
||
throw new Error('digest() was already called');
|
||
this.writeInto(out);
|
||
this.destroy();
|
||
return out;
|
||
}
|
||
digest() {
|
||
return this.digestInto(new Uint8Array(this.outputLen));
|
||
}
|
||
destroy() {
|
||
this.destroyed = true;
|
||
(0, utils_ts_1.clean)(this.state);
|
||
}
|
||
_cloneInto(to) {
|
||
const { blockLen, suffix, outputLen, rounds, enableXOF } = this;
|
||
to || (to = new Keccak(blockLen, suffix, outputLen, enableXOF, rounds));
|
||
to.state32.set(this.state32);
|
||
to.pos = this.pos;
|
||
to.posOut = this.posOut;
|
||
to.finished = this.finished;
|
||
to.rounds = rounds;
|
||
// Suffix can change in cSHAKE
|
||
to.suffix = suffix;
|
||
to.outputLen = outputLen;
|
||
to.enableXOF = enableXOF;
|
||
to.destroyed = this.destroyed;
|
||
return to;
|
||
}
|
||
}
|
||
exports.Keccak = Keccak;
|
||
const gen = (suffix, blockLen, outputLen) => (0, utils_ts_1.createHasher)(() => new Keccak(blockLen, suffix, outputLen));
|
||
/** SHA3-224 hash function. */
|
||
exports.sha3_224 = (() => gen(0x06, 144, 224 / 8))();
|
||
/** SHA3-256 hash function. Different from keccak-256. */
|
||
exports.sha3_256 = (() => gen(0x06, 136, 256 / 8))();
|
||
/** SHA3-384 hash function. */
|
||
exports.sha3_384 = (() => gen(0x06, 104, 384 / 8))();
|
||
/** SHA3-512 hash function. */
|
||
exports.sha3_512 = (() => gen(0x06, 72, 512 / 8))();
|
||
/** keccak-224 hash function. */
|
||
exports.keccak_224 = (() => gen(0x01, 144, 224 / 8))();
|
||
/** keccak-256 hash function. Different from SHA3-256. */
|
||
exports.keccak_256 = (() => gen(0x01, 136, 256 / 8))();
|
||
/** keccak-384 hash function. */
|
||
exports.keccak_384 = (() => gen(0x01, 104, 384 / 8))();
|
||
/** keccak-512 hash function. */
|
||
exports.keccak_512 = (() => gen(0x01, 72, 512 / 8))();
|
||
const genShake = (suffix, blockLen, outputLen) => (0, utils_ts_1.createXOFer)((opts = {}) => new Keccak(blockLen, suffix, opts.dkLen === undefined ? outputLen : opts.dkLen, true));
|
||
/** SHAKE128 XOF with 128-bit security. */
|
||
exports.shake128 = (() => genShake(0x1f, 168, 128 / 8))();
|
||
/** SHAKE256 XOF with 256-bit security. */
|
||
exports.shake256 = (() => genShake(0x1f, 136, 256 / 8))();
|
||
//# sourceMappingURL=sha3.js.map
|