const { pointAtDevDb } = require('./setup'); pointAtDevDb(); process.env.ENABLE_LICENSING_IN_TESTS = 'true'; const crypto = require('crypto'); const express = require('express'); const request = require('supertest'); const licensingRouter = require('../src/controllers/licensing.controller'); const LicenseCache = require('../src/services/LicenseCacheService'); const { privateKey: TEST_PRIV_KEY, publicKey: TEST_PUB_KEY } = crypto.generateKeyPairSync('ed25519', { privateKeyEncoding: { type: 'pkcs8', format: 'pem' }, publicKeyEncoding: { type: 'spki', format: 'pem' } }); const { privateKey: OTHER_PRIV_KEY } = crypto.generateKeyPairSync('ed25519', { privateKeyEncoding: { type: 'pkcs8', format: 'pem' }, publicKeyEncoding: { type: 'spki', format: 'pem' } }); const TENANT_ID = '5b39bcb5-506a-456d-b7cb-91730b397cc1'; function createSignedJwt(claims, privKey = TEST_PRIV_KEY) { const headerB64 = Buffer.from(JSON.stringify({ alg: 'EdDSA', typ: 'JWT' })).toString('base64url'); const payloadB64 = Buffer.from(JSON.stringify(claims)).toString('base64url'); const data = Buffer.from(`${headerB64}.${payloadB64}`, 'utf8'); const sigB64 = crypto.sign(null, data, privKey).toString('base64url'); return `${headerB64}.${payloadB64}.${sigB64}`; } describe('Offline License Artifact Ingestion Endpoint (POST /api/license/ingest)', () => { let app; let originalPubKey; beforeEach(async () => { originalPubKey = process.env.SUPERADMIN_PUBLIC_KEY; process.env.SUPERADMIN_PUBLIC_KEY = TEST_PUB_KEY; await LicenseCache.del(TENANT_ID); app = express(); app.use(express.json()); app.use('/api/license', licensingRouter); }); afterEach(async () => { process.env.SUPERADMIN_PUBLIC_KEY = originalPubKey; await LicenseCache.del(TENANT_ID); }); it('successfully verifies and ingests a valid signed .lic.json artifact', async () => { const claims = { iss: 'super_admin_licensing_engine', sub: TENANT_ID, tenant_code: 'SCH-TEST', tenant_name: 'AFRICA-ALERT', term: 'Term 3 Offline', academic_year: '2026', max_students: 2500, max_staff: 350, nbf: Math.floor(Date.now() / 1000) - 100, exp: Math.floor(Date.now() / 1000) + 86400 * 90, status: 'active' }; const signedToken = createSignedJwt(claims); const artifact = { format_version: '1.0', issued_at: new Date().toISOString(), issued_by: 'Nextgen LMS SuperAdmin Governance Portal', tenant: { id: TENANT_ID, code: 'SCH-TEST', name: 'AFRICA-ALERT' }, license: { id: 'lic-offline-test-101', license_key: 'LIC-TERM3OFFLINE-2026-TEST', signed_license_token: signedToken, algorithm: 'EdDSA', term_name: 'Term 3 Offline', academic_year: '2026', start_date: '2026-07-01', end_date: '2026-10-01', grace_period_days: 7, max_students: 2500, max_staff: 350, status: 'active' }, checksum: crypto.createHash('sha256').update(signedToken).digest('hex') }; const res = await request(app) .post('/api/license/ingest') .set('x-tenant-id', TENANT_ID) .send(artifact); expect(res.status).toBe(200); expect(res.body.ok).toBe(true); expect(res.body.status).toBe('ACTIVE'); expect(res.body.license.license_key).toBe('LIC-TERM3OFFLINE-2026-TEST'); expect(res.body.license.term_name).toBe('Term 3 Offline'); }); it('rejects an artifact signed with an untrusted / invalid key', async () => { const claims = { iss: 'fake_super_admin', sub: TENANT_ID, term: 'Term Forged', exp: Math.floor(Date.now() / 1000) + 86400 * 90 }; const forgedToken = createSignedJwt(claims, OTHER_PRIV_KEY); const forgedArtifact = { format_version: '1.0', license: { signed_license_token: forgedToken, term_name: 'Term Forged' } }; const res = await request(app) .post('/api/license/ingest') .set('x-tenant-id', TENANT_ID) .send(forgedArtifact); expect(res.status).toBe(422); expect(res.body.error).toMatch(/Cryptographic Signature Verification Failed/i); }); it('successfully decrypts and ingests an AES-256-GCM encrypted license artifact package', async () => { const claims = { iss: 'super_admin_licensing_engine', sub: TENANT_ID, tenant_code: 'SCH-ENC', tenant_name: 'AFRICA-ALERT', term: 'Term 1 Encrypted', academic_year: '2026', max_students: 5000, max_staff: 400, exp: Math.floor(Date.now() / 1000) + 86400 * 90, status: 'active' }; const token = createSignedJwt(claims); const rawArtifact = { tenant: { id: TENANT_ID, code: 'SCH-ENC', name: 'AFRICA-ALERT' }, license: { id: 'lic-enc-001', license_key: 'LIC-ENC-2026', signed_license_token: token, term_name: 'Term 1 Encrypted', academic_year: '2026', start_date: '2026-07-01', end_date: '2026-10-01', max_students: 5000, max_staff: 400, status: 'active' } }; const secret = process.env.LICENSE_ARTIFACT_SECRET || TEST_PUB_KEY; const key = crypto.createHash('sha256').update(`${secret}:${TENANT_ID}`).digest(); const iv = crypto.randomBytes(12); const cipher = crypto.createCipheriv('aes-256-gcm', key, iv); const encrypted = Buffer.concat([cipher.update(JSON.stringify(rawArtifact), 'utf8'), cipher.final()]); const authTag = cipher.getAuthTag(); const encryptedEnvelope = { format_version: '2.0', encrypted: true, algorithm: 'AES-256-GCM + Ed25519', tenant_id: TENANT_ID, iv: iv.toString('hex'), auth_tag: authTag.toString('hex'), ciphertext: encrypted.toString('base64') }; const res = await request(app) .post('/api/license/ingest') .set('x-tenant-id', TENANT_ID) .send(encryptedEnvelope); expect(res.status).toBe(200); expect(res.body.ok).toBe(true); expect(res.body.license.term_name).toBe('Term 1 Encrypted'); }); it('rejects tampered ciphertext in an encrypted license artifact package', async () => { const encryptedEnvelope = { format_version: '2.0', encrypted: true, algorithm: 'AES-256-GCM + Ed25519', tenant_id: TENANT_ID, iv: crypto.randomBytes(12).toString('hex'), auth_tag: crypto.randomBytes(16).toString('hex'), ciphertext: Buffer.from('TAMPERED_CIPHERTEXT_BYTES').toString('base64') }; const res = await request(app) .post('/api/license/ingest') .set('x-tenant-id', TENANT_ID) .send(encryptedEnvelope); expect(res.status).toBe(422); expect(res.body.error).toMatch(/Artifact Decryption \/ Tamper Check Failed/i); }); it('rejects artifact when school name does not match local school identity', async () => { const claims = { iss: 'super_admin_licensing_engine', sub: TENANT_ID, tenant_name: 'Completely Different School Academy', term: 'Term 1', academic_year: '2026', exp: Math.floor(Date.now() / 1000) + 86400 * 90 }; const token = createSignedJwt(claims); const artifact = { tenant: { id: TENANT_ID, name: 'Completely Different School Academy' }, license: { id: 'lic-mismatch-001', signed_license_token: token } }; const res = await request(app) .post('/api/license/ingest') .set('x-tenant-id', TENANT_ID) .send(artifact); expect(res.status).toBe(422); expect(res.body.error).toMatch(/Institution Name Mismatch/i); }); });