Files
memegoat/backend/src/crypto/crypto.service.spec.ts
Mathis HERRIOT 0c045e8d3c refactor: remove unused tests, mocks, and outdated e2e configurations
Deleted unused e2e tests, mocks (`cuid2`, `jose`, `ml-kem`, `sha3`), and their associated jest configurations. Simplified services by ensuring proper dependency imports, resolving circular references, and improving TypeScript type usage for enhanced maintainability and testability. Upgraded Dockerfile base image to match new development standards.
2026-01-14 13:51:32 +01:00

188 lines
5.9 KiB
TypeScript

import { ConfigService } from "@nestjs/config";
import { Test, TestingModule } from "@nestjs/testing";
jest.mock("@noble/post-quantum/ml-kem.js", () => ({
ml_kem768: {
keygen: jest.fn(() => ({
publicKey: new Uint8Array(1184),
secretKey: new Uint8Array(2400),
})),
encapsulate: jest.fn((_pk: Uint8Array) => ({
cipherText: new Uint8Array(1088),
sharedSecret: new Uint8Array(32),
})),
decapsulate: jest.fn(
(_ct: Uint8Array, _sk: Uint8Array) => new Uint8Array(32),
),
},
}));
jest.mock("jose", () => ({
generateSecret: jest.fn().mockResolvedValue(new Uint8Array(32)),
CompactEncrypt: jest.fn().mockImplementation(() => ({
setProtectedHeader: jest.fn().mockReturnThis(),
encrypt: jest.fn().mockResolvedValue("mocked.jwe.token.parts.here"),
})),
compactDecrypt: jest.fn().mockImplementation((jwe) => {
if (jwe === "invalid.jwe.content") {
throw new Error("Invalid JWE");
}
return Promise.resolve({
plaintext: new TextEncoder().encode("This is a secret message 🤫"),
});
}),
SignJWT: jest.fn().mockImplementation(() => ({
setProtectedHeader: jest.fn().mockReturnThis(),
setIssuedAt: jest.fn().mockReturnThis(),
setExpirationTime: jest.fn().mockReturnThis(),
sign: jest.fn().mockResolvedValue("mocked.jwt.token"),
})),
jwtVerify: jest.fn().mockImplementation((token) => {
if (token === "invalid.token.here") {
throw new Error("Invalid token");
}
return Promise.resolve({
payload: { sub: "1234567890", name: "John Doe", admin: true },
});
}),
CompactSign: jest.fn().mockImplementation(() => ({
setProtectedHeader: jest.fn().mockReturnThis(),
sign: jest.fn().mockResolvedValue("mocked.jws.token"),
})),
compactVerify: jest.fn().mockImplementation((jws) => {
if (jws.includes("tampered") || jws.split(".").length !== 3) {
throw new Error("Tampered or invalid content");
}
const payload =
jws === "mocked.jws.token"
? "Important document content"
: "Original content";
return Promise.resolve({
payload: new TextEncoder().encode(payload),
});
}),
}));
import { CryptoService } from "./crypto.service";
import { EncryptionService } from "./services/encryption.service";
import { HashingService } from "./services/hashing.service";
import { JwtService } from "./services/jwt.service";
import { PostQuantumService } from "./services/post-quantum.service";
describe("CryptoService", () => {
let service: CryptoService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
CryptoService,
HashingService,
JwtService,
EncryptionService,
PostQuantumService,
{
provide: ConfigService,
useValue: {
get: jest.fn().mockReturnValue("test-secret"),
},
},
],
}).compile();
service = module.get<CryptoService>(CryptoService);
});
it("should be defined", () => {
expect(service).toBeDefined();
});
describe("Argon2 Password Hashing", () => {
it("should hash and verify a password", async () => {
const password = "mySecurePassword123!";
const hash = await service.hashPassword(password);
expect(hash).toBeDefined();
expect(hash).not.toBe(password);
const isValid = await service.verifyPassword(password, hash);
expect(isValid).toBe(true);
const isInvalid = await service.verifyPassword("wrongPassword", hash);
expect(isInvalid).toBe(false);
});
});
describe("JWT jose", () => {
it("should generate and verify a JWT", async () => {
const payload = { sub: "1234567890", name: "John Doe", admin: true };
const token = await service.generateJwt(payload);
expect(token).toBeDefined();
const verifiedPayload = await service.verifyJwt(token);
expect(verifiedPayload.sub).toBe(payload.sub);
expect(verifiedPayload.name).toBe(payload.name);
expect(verifiedPayload.admin).toBe(payload.admin);
});
it("should throw for invalid token", async () => {
await expect(service.verifyJwt("invalid.token.here")).rejects.toThrow();
});
});
describe("Encryption/Decryption (JWE)", () => {
it("should encrypt and decrypt content", async () => {
const content = "This is a secret message 🤫";
const jwe = await service.encryptContent(content);
expect(jwe).toBeDefined();
expect(typeof jwe).toBe("string");
expect(jwe.split(".").length).toBe(5); // JWE compact serialization has 5 parts
const decrypted = await service.decryptContent(jwe);
expect(decrypted).toBe(content);
});
it("should fail to decrypt invalid content", async () => {
await expect(
service.decryptContent("invalid.jwe.content"),
).rejects.toThrow();
});
});
describe("Signature (JWS)", () => {
it("should sign and verify content signature", async () => {
const content = "Important document content";
const jws = await service.signContent(content);
expect(jws).toBeDefined();
expect(typeof jws).toBe("string");
expect(jws.split(".").length).toBe(3); // JWS compact serialization has 3 parts
const verifiedContent = await service.verifyContentSignature(jws);
expect(verifiedContent).toBe(content);
});
it("should fail to verify tampered content", async () => {
const content = "Original content";
const jws = await service.signContent(content);
const _parts = jws.split(".");
// Tamper with the payload (middle part)
const tamperedJws = "this.is.tampered";
await expect(service.verifyContentSignature(tamperedJws)).rejects.toThrow();
});
});
describe("Post-Quantum @noble/post-quantum", () => {
it("should generate keypair, encapsulate and decapsulate", () => {
const { publicKey, secretKey } = service.generatePostQuantumKeyPair();
expect(publicKey).toBeDefined();
expect(secretKey).toBeDefined();
const { cipherText, sharedSecret } = service.encapsulate(publicKey);
expect(cipherText).toBeDefined();
expect(sharedSecret).toBeDefined();
const decapsulatedSecret = service.decapsulate(cipherText, secretKey);
expect(decapsulatedSecret).toEqual(sharedSecret);
});
});
});