From 3cd30c6c75d53b83fcd18123f1c0551687ea5ec6 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 24 Nov 2025 12:57:44 -0300 Subject: [PATCH 01/12] chore: remove validateAuthorizationHeader --- packages/core/src/index.ts | 1 - .../core/src/utils/authentication.spec.ts | 1 - packages/core/src/utils/authentication.ts | 41 ------------------- .../services/event-authorization.service.ts | 1 - 4 files changed, 44 deletions(-) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 73e615ba5..03e0248ff 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -15,7 +15,6 @@ export { computeHash, extractSignaturesFromHeader, signRequest, - validateAuthorizationHeader, type HashedEvent, } from './utils/authentication'; diff --git a/packages/core/src/utils/authentication.spec.ts b/packages/core/src/utils/authentication.spec.ts index 35d8b09c2..97651995c 100644 --- a/packages/core/src/utils/authentication.spec.ts +++ b/packages/core/src/utils/authentication.spec.ts @@ -6,7 +6,6 @@ import { computeHash, extractSignaturesFromHeader, signRequest, - validateAuthorizationHeader, } from './authentication'; import { generateId } from './generateId'; diff --git a/packages/core/src/utils/authentication.ts b/packages/core/src/utils/authentication.ts index abbe99e3d..d518a9e16 100644 --- a/packages/core/src/utils/authentication.ts +++ b/packages/core/src/utils/authentication.ts @@ -1,6 +1,4 @@ -import { encodeCanonicalJson } from '@rocket.chat/federation-crypto'; import { type Pdu, PersistentEventBase } from '@rocket.chat/federation-room'; -import nacl from 'tweetnacl'; import { type SigningKey } from '../types'; import { signJson } from './signJson'; @@ -66,45 +64,6 @@ export async function authorizationHeaders( return `X-Matrix origin="${origin}",destination="${destination}",key="${key}",sig="${signed}"`; } -export const validateAuthorizationHeader = async ( - origin: string, - signingKey: string, - destination: string, - method: string, - uri: string, - hash: string, - content?: T, -) => { - const canonicalJson = encodeCanonicalJson({ - method, - uri, - origin, - destination, - ...(content && { content }), - }); - - const signature = Uint8Array.from(atob(hash as string), (c) => - c.charCodeAt(0), - ); - const signingKeyBytes = Uint8Array.from(atob(signingKey as string), (c) => - c.charCodeAt(0), - ); - const messageBytes = new TextEncoder().encode(canonicalJson); - const isValid = nacl.sign.detached.verify( - messageBytes, - signature, - signingKeyBytes, - ); - - if (!isValid) { - throw new Error( - `Invalid signature from ${origin} for request to ${destination}`, - ); - } - - return true; -}; - export async function signRequest( origin: string, signingKey: SigningKey, diff --git a/packages/federation-sdk/src/services/event-authorization.service.ts b/packages/federation-sdk/src/services/event-authorization.service.ts index 3d67260c5..e4dc2b224 100644 --- a/packages/federation-sdk/src/services/event-authorization.service.ts +++ b/packages/federation-sdk/src/services/event-authorization.service.ts @@ -2,7 +2,6 @@ import { createLogger, extractSignaturesFromHeader, generateId, - validateAuthorizationHeader, } from '@rocket.chat/federation-core'; import type { EventID, From e5853b52566f353771dc513f3a8aea3c0d87d9f0 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 24 Nov 2025 13:00:01 -0300 Subject: [PATCH 02/12] chore: remove checkSignAndHashes --- packages/core/src/index.ts | 1 - .../core/src/utils/checkSignAndHashes.spec.ts | 164 ------------------ packages/core/src/utils/checkSignAndHashes.ts | 48 ----- 3 files changed, 213 deletions(-) delete mode 100644 packages/core/src/utils/checkSignAndHashes.spec.ts delete mode 100644 packages/core/src/utils/checkSignAndHashes.ts diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 03e0248ff..ff8be3cde 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -8,7 +8,6 @@ export { signEvent } from './utils/signEvent'; // Authentication utilities export { generateId } from './utils/generateId'; export { pruneEventDict } from './utils/pruneEventDict'; -export { checkSignAndHashes } from './utils/checkSignAndHashes'; export { authorizationHeaders, computeAndMergeHash, diff --git a/packages/core/src/utils/checkSignAndHashes.spec.ts b/packages/core/src/utils/checkSignAndHashes.spec.ts deleted file mode 100644 index 1268e5cb3..000000000 --- a/packages/core/src/utils/checkSignAndHashes.spec.ts +++ /dev/null @@ -1,164 +0,0 @@ -import 'reflect-metadata'; -import { afterAll, beforeAll, describe, expect, it, spyOn } from 'bun:test'; -import type { EventBase } from '../events/eventBase'; -import { EncryptionValidAlgorithm } from '../types'; -import * as authentication from '../utils/authentication'; -import type { HashedEvent } from './authentication'; -import { checkSignAndHashes } from './checkSignAndHashes'; -import { MatrixError } from './errors'; -import * as signJson from './signJson'; -import type { SignedJson } from './signJson'; - -describe('checkSignAndHashes', () => { - const originalAtob = globalThis.atob; - - const mockOrigin = 'example.com'; - const mockSignature = { - algorithm: EncryptionValidAlgorithm.ed25519, - version: 'key_version', - signature: 'bW9ja1NpZ25hdHVyZQ==', - }; - const mockPublicKey = 'bW9ja1B1YmxpY0tleQ=='; - const mockHash = 'mockHash'; - - const mockPdu = { - type: 'm.room.message', - content: { body: 'Hello' }, - hashes: { - sha256: mockHash, - }, - signatures: { - [mockOrigin]: { - 'ed25519:key_version': 'someSignature', - }, - }, - } as unknown as HashedEvent>; - - const getPublicKeyFromServerMock = ( - _origin: string, - _key: string, - ): Promise => { - return Promise.resolve(mockPublicKey); - }; - - beforeAll(() => { - globalThis.atob = (str: string): string => { - if (str === mockSignature.signature) { - return 'mockSignature'; - } - if (str === mockPublicKey) { - return 'mockPublicKey'; - } - - return originalAtob(str); - }; - }); - - afterAll(() => { - globalThis.atob = originalAtob; - }); - - it('should validate signature and hash successfully', async () => { - const getSignaturesSpy = spyOn( - signJson, - 'getSignaturesFromRemote', - ).mockResolvedValue([mockSignature]); - const verifyJsonSpy = spyOn( - signJson, - 'verifyJsonSignature', - ).mockReturnValue(true); - const computeHashSpy = spyOn(authentication, 'computeHash').mockReturnValue( - ['sha256', mockHash], - ); - - const result = await checkSignAndHashes( - mockPdu, - mockOrigin, - getPublicKeyFromServerMock, - ); - - expect(getSignaturesSpy).toHaveBeenCalledWith(mockPdu, mockOrigin); - expect(verifyJsonSpy).toHaveBeenCalled(); - expect(computeHashSpy).toHaveBeenCalledWith(mockPdu); - - expect(result).toEqual(mockPdu); - - getSignaturesSpy.mockRestore(); - verifyJsonSpy.mockRestore(); - computeHashSpy.mockRestore(); - }); - - it('should throw error for invalid signature', async () => { - const getSignaturesSpy = spyOn( - signJson, - 'getSignaturesFromRemote', - ).mockResolvedValue([mockSignature]); - const verifyJsonSpy = spyOn( - signJson, - 'verifyJsonSignature', - ).mockReturnValue(false); - const computeHashSpy = spyOn(authentication, 'computeHash').mockReturnValue( - ['sha256', mockHash], - ); - - let error: Error | undefined; - try { - await checkSignAndHashes(mockPdu, mockOrigin, getPublicKeyFromServerMock); - } catch (e) { - error = e as Error; - } - - expect(error).toBeInstanceOf(MatrixError); - expect(error?.message).toBe('Invalid signature'); - - getSignaturesSpy.mockRestore(); - verifyJsonSpy.mockRestore(); - computeHashSpy.mockRestore(); - }); - - it('should throw error for invalid hash', async () => { - const getSignaturesSpy = spyOn( - signJson, - 'getSignaturesFromRemote', - ).mockResolvedValue([mockSignature]); - const verifyJsonSpy = spyOn( - signJson, - 'verifyJsonSignature', - ).mockReturnValue(true); - const computeHashSpy = spyOn(authentication, 'computeHash').mockReturnValue( - ['sha256', 'differentHash'], - ); - - let error: Error | undefined; - try { - await checkSignAndHashes(mockPdu, mockOrigin, getPublicKeyFromServerMock); - } catch (e) { - error = e as Error; - } - getSignaturesSpy.mockRestore(); - verifyJsonSpy.mockRestore(); - computeHashSpy.mockRestore(); - - expect(error).toBeInstanceOf(MatrixError); - expect(error?.message).toBe('Invalid hash'); - }); - - it('should throw error if signature verification fails', async () => { - const getSignaturesSpy = spyOn(signJson, 'getSignaturesFromRemote'); - getSignaturesSpy.mockImplementation(() => { - throw new Error('Signature not found'); - }); - - let error: Error | undefined; - try { - await checkSignAndHashes(mockPdu, mockOrigin, getPublicKeyFromServerMock); - } catch (e) { - error = e as Error; - } - - expect(error).toBeInstanceOf(Error); - expect(error?.message).toBe('Signature not found'); - - getSignaturesSpy.mockRestore(); - }); -}); diff --git a/packages/core/src/utils/checkSignAndHashes.ts b/packages/core/src/utils/checkSignAndHashes.ts deleted file mode 100644 index 58171d0a4..000000000 --- a/packages/core/src/utils/checkSignAndHashes.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Pdu } from '@rocket.chat/federation-room'; -import { type HashedEvent, computeHash } from './authentication'; -import { MatrixError } from './errors'; -import { logger } from './logger'; -import { pruneEventDict } from './pruneEventDict'; -import { - type SignedJson, - getSignaturesFromRemote, - verifyJsonSignature, -} from './signJson'; - -export async function checkSignAndHashes>( - pdu: HashedEvent, - origin: string, - getPublicKeyFromServer: (origin: string, key: string) => Promise, -) { - const [signature] = await getSignaturesFromRemote(pdu, origin); - const publicKey = await getPublicKeyFromServer( - origin, - `${signature.algorithm}:${signature.version}`, - ); - - if ( - !verifyJsonSignature( - pruneEventDict(pdu), - origin, - Uint8Array.from(atob(signature.signature), (c) => c.charCodeAt(0)), - Uint8Array.from(atob(publicKey), (c) => c.charCodeAt(0)), - signature.algorithm, - signature.version, - ) - ) { - throw new MatrixError('400', 'Invalid signature'); - } - - const { - hashes: { sha256: expectedHash }, - } = pdu; - - const [, hash] = computeHash(pdu); - - if (hash !== expectedHash) { - logger.error({ msg: 'Invalid hash', hash, expectedHash }); - throw new MatrixError('400', 'Invalid hash'); - } - - return pdu; -} From 6617bad17397f0f30db9b116f2d742a4a449f685 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 24 Nov 2025 13:01:26 -0300 Subject: [PATCH 03/12] chore: remove getPublicKeyFromRemoteServer --- packages/core/src/index.ts | 1 - .../procedures/getPublicKeyFromServer.spec.ts | 232 ------------------ .../src/procedures/getPublicKeyFromServer.ts | 69 ------ 3 files changed, 302 deletions(-) delete mode 100644 packages/core/src/procedures/getPublicKeyFromServer.spec.ts delete mode 100644 packages/core/src/procedures/getPublicKeyFromServer.ts diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index ff8be3cde..892d5b486 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -70,7 +70,6 @@ export * from './models/event.model'; // Procedures export { makeJoinEventBuilder } from './procedures/makeJoin'; -export { getPublicKeyFromRemoteServer } from './procedures/getPublicKeyFromServer'; export { createLogger, logger } from './utils/logger'; diff --git a/packages/core/src/procedures/getPublicKeyFromServer.spec.ts b/packages/core/src/procedures/getPublicKeyFromServer.spec.ts deleted file mode 100644 index 4da5e4aa0..000000000 --- a/packages/core/src/procedures/getPublicKeyFromServer.spec.ts +++ /dev/null @@ -1,232 +0,0 @@ -import { afterEach, beforeEach, describe, expect, it } from 'bun:test'; -import { encodeCanonicalJson } from '@rocket.chat/federation-crypto'; -import nacl from 'tweetnacl'; -import { EncryptionValidAlgorithm } from '../types'; -import { generateKeyPairs } from '../utils/keys'; -import { getPublicKeyFromRemoteServer } from './getPublicKeyFromServer'; - -describe('getPublicKeyFromRemoteServer', () => { - let originalFetch: typeof globalThis.fetch; - let mockServerKeys: { - server_name: string; - verify_keys: Record; - old_verify_keys: Record; - signatures: Record>; - valid_until_ts: number; - }; - - const createValidServerKeyResponse = async () => { - const seed = nacl.randomBytes(32); - const keyPair = await generateKeyPairs( - seed, - EncryptionValidAlgorithm.ed25519, - 'test_key', - ); - const serverName = 'test.server'; - const keyId = `${keyPair.algorithm}:${keyPair.version}`; - const validUntil = Date.now() + 24 * 60 * 60 * 1000; - - const serverKey = { - server_name: serverName, - old_verify_keys: {}, - valid_until_ts: validUntil, - verify_keys: { - [keyId]: { - key: Buffer.from(keyPair.publicKey).toString('base64'), - }, - }, - }; - - const canonicalJson = encodeCanonicalJson(serverKey); - const signature = await keyPair.sign( - new TextEncoder().encode(canonicalJson), - ); - - return { - ...serverKey, - signatures: { - [serverName]: { - [keyId]: Buffer.from(signature).toString('base64'), - }, - }, - }; - }; - - beforeEach(async () => { - originalFetch = globalThis.fetch; - mockServerKeys = await createValidServerKeyResponse(); - - const mockFetch = async (input: RequestInfo | URL) => { - const url = input.toString(); - if (url.includes('/_matrix/key/v2/server')) { - return new Response(JSON.stringify(mockServerKeys), { - status: 200, - headers: { 'Content-Type': 'application/json' }, - }); - } - return new Response(null, { status: 404 }); - }; - mockFetch.preconnect = async () => undefined; - globalThis.fetch = mockFetch; - }); - - afterEach(() => { - globalThis.fetch = originalFetch; - }); - - it('should successfully retrieve and validate a public key', async () => { - const domain = 'test.server'; - const origin = 'test.server'; - const algorithmAndVersion = `${EncryptionValidAlgorithm.ed25519}:test_key`; - - const result = await getPublicKeyFromRemoteServer( - domain, - origin, - algorithmAndVersion, - ); - - expect(result).toBeDefined(); - expect(result.key).toBeDefined(); - expect(result.validUntil).toBeNumber(); - expect(result.validUntil).toBeGreaterThan(Date.now()); - }); - - it('should throw error when server key is expired', async () => { - mockServerKeys.valid_until_ts = Date.now() - 1000; - - await expect( - getPublicKeyFromRemoteServer( - 'test.server', - 'test.server', - `${EncryptionValidAlgorithm.ed25519}:test_key`, - ), - ).rejects.toThrow('Expired remote public key'); - }); - - it('should throw error when public key is not found', async () => { - mockServerKeys.verify_keys = {}; - - await expect( - getPublicKeyFromRemoteServer( - 'test.server', - 'test.server', - `${EncryptionValidAlgorithm.ed25519}:test_key`, - ), - ).rejects.toThrow('Public key not found'); - }); - - it('should throw error for invalid algorithm', async () => { - await expect( - getPublicKeyFromRemoteServer( - 'test.server', - 'test.server', - 'invalid_alg:test_key', - ), - ).rejects.toThrow('Invalid algorithm'); - }); - - it('should throw error for invalid algorithm format', async () => { - await expect( - getPublicKeyFromRemoteServer( - 'test.server', - 'test.server', - 'invalid_algorithm_format', - ), - ).rejects.toThrow('Invalid algorithm and version format'); - }); - - it('should handle network errors gracefully', async () => { - const errorFetch = async () => { - throw new Error('Network error'); - }; - errorFetch.preconnect = async () => undefined; - globalThis.fetch = errorFetch; - - await expect( - getPublicKeyFromRemoteServer( - 'test.server', - 'test.server', - `${EncryptionValidAlgorithm.ed25519}:test_key`, - ), - ).rejects.toThrow(); - }); - - it('should handle invalid server response', async () => { - const invalidJsonFetch = async () => { - return new Response('invalid json', { - status: 200, - headers: { 'Content-Type': 'application/json' }, - }); - }; - invalidJsonFetch.preconnect = async () => undefined; - globalThis.fetch = invalidJsonFetch; - - await expect( - getPublicKeyFromRemoteServer( - 'test.server', - 'test.server', - `${EncryptionValidAlgorithm.ed25519}:test_key`, - ), - ).rejects.toThrow(); - }); - - it('should successfully retrieve and validate a public key with different algorithm version', async () => { - const seed = nacl.randomBytes(32); - const keyPair = await generateKeyPairs( - seed, - EncryptionValidAlgorithm.ed25519, - 'another_version', - ); - const serverName = 'test.server'; - const keyId = `${keyPair.algorithm}:${keyPair.version}`; - - const specialMockFetch = async (input: RequestInfo | URL) => { - const url = input.toString(); - if (url.includes('/_matrix/key/v2/server')) { - const baseServerKey = { - server_name: serverName, - old_verify_keys: {}, - valid_until_ts: Date.now() + 24 * 60 * 60 * 1000, - verify_keys: { - [keyId]: { - key: Buffer.from(keyPair.publicKey).toString('base64'), - }, - }, - }; - - const canonicalJson = encodeCanonicalJson(baseServerKey); - const signature = await keyPair.sign( - new TextEncoder().encode(canonicalJson), - ); - - const fullServerKey = { - ...baseServerKey, - signatures: { - [serverName]: { - [keyId]: Buffer.from(signature).toString('base64'), - }, - }, - }; - - return new Response(JSON.stringify(fullServerKey), { - status: 200, - headers: { 'Content-Type': 'application/json' }, - }); - } - return new Response(null, { status: 404 }); - }; - specialMockFetch.preconnect = async () => undefined; - globalThis.fetch = specialMockFetch; - - const result = await getPublicKeyFromRemoteServer( - serverName, - serverName, - keyId, - ); - - expect(result).toBeDefined(); - expect(result.key).toBeDefined(); - expect(result.validUntil).toBeNumber(); - expect(result.validUntil).toBeGreaterThan(Date.now()); - }); -}); diff --git a/packages/core/src/procedures/getPublicKeyFromServer.ts b/packages/core/src/procedures/getPublicKeyFromServer.ts deleted file mode 100644 index 0819a7a1b..000000000 --- a/packages/core/src/procedures/getPublicKeyFromServer.ts +++ /dev/null @@ -1,69 +0,0 @@ -import type { ServerKey } from '../server'; -import { makeRequest } from '../utils/makeRequest'; - -import { - getSignaturesFromRemote, - isValidAlgorithm, - verifyJsonSignature, -} from '../utils/signJson'; - -export const getPublicKeyFromRemoteServer = async ( - domain: string, - origin: string, - algorithmAndVersion: string, -) => { - const [algorithm, version] = algorithmAndVersion.split(':'); - if (!algorithm || !version) { - throw new Error('Invalid algorithm and version format'); - } - - if (!isValidAlgorithm(algorithm)) { - throw new Error('Invalid algorithm'); - } - - const result = await makeRequest({ - method: 'GET', - domain, - uri: '/_matrix/key/v2/server', - signingName: origin, - }); - - if (result.valid_until_ts < Date.now()) { - throw new Error('Expired remote public key'); - } - - const publickey = result.verify_keys[algorithmAndVersion]?.key; - if (!publickey) { - throw new Error('Public key not found'); - } - - const [signature] = await getSignaturesFromRemote(result, domain); - if (!signature) { - throw new Error(`No valid signature found for ${domain}`); - } - - const publicKeyBytes = Uint8Array.from(atob(publickey), (c) => - c.charCodeAt(0), - ); - const signatureBytes = Uint8Array.from(atob(signature.signature), (c) => - c.charCodeAt(0), - ); - - if ( - !verifyJsonSignature( - result, - domain, - signatureBytes, - publicKeyBytes, - signature.algorithm, - signature.version, - ) - ) { - throw new Error('Invalid signature'); - } - - return { - key: publickey, - validUntil: result.valid_until_ts, - }; -}; From 6ab3be18713f777c5345d7ead861ff656cffcffe Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 24 Nov 2025 13:03:47 -0300 Subject: [PATCH 04/12] chore: remove verifyJsonSignature from @core --- packages/core/src/index.ts | 1 - packages/crypto/src/index.spec.ts | 58 ------------------------------- 2 files changed, 59 deletions(-) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 892d5b486..55d0ddfb5 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -24,7 +24,6 @@ export { isValidAlgorithm, getSignaturesFromRemote, verifySignature, - verifyJsonSignature, verifySignaturesFromRemote, signText, signData, diff --git a/packages/crypto/src/index.spec.ts b/packages/crypto/src/index.spec.ts index c689ddcd7..8b4c1dfa4 100644 --- a/packages/crypto/src/index.spec.ts +++ b/packages/crypto/src/index.spec.ts @@ -4,7 +4,6 @@ import { loadEd25519SignerFromSeed, loadEd25519VerifierFromPublicKey, signJson, - verifyJsonSignature, } from './utils/keys'; describe('signJson', () => { @@ -50,61 +49,4 @@ describe('signJson', () => { 'ZDz7K7NRz0OwgR6n96YMIyt9h8KUCb7T9TklId7S1UDVOwc2y45+tC12/51kxRxpUkaOgr+iBtSBBh74BIrsBQ', ); }); - - it('should verify a signature', async () => { - const json = { - method: 'PUT', - uri: '/_matrix/federation/v1/send/1743489715804', - origin: 'syn1.tunnel.dev.rocket.chat', - destination: 'syn2.tunnel.dev.rocket.chat', - content: { - edus: [ - { - content: { - push: [ - { - last_active_ago: 45931, - presence: 'offline', - user_id: '@debdut:syn1.tunnel.dev.rocket.chat', - }, - ], - }, - edu_type: 'm.presence', - }, - ], - origin: 'syn1.tunnel.dev.rocket.chat', - origin_server_ts: 1743490730808, - pdus: [], - }, - }; - - const signature = - 'ZDz7K7NRz0OwgR6n96YMIyt9h8KUCb7T9TklId7S1UDVOwc2y45+tC12/51kxRxpUkaOgr+iBtSBBh74BIrsBQ'; - - const keyv2serverresponsefromorigin = { - old_verify_keys: {}, - server_name: 'syn1.tunnel.dev.rocket.chat', - signatures: { - 'syn1.tunnel.dev.rocket.chat': { - 'ed25519:a_FAET': - 'MZF+8pncxhUNp7JzdSTIqriaANQ4QTYTe1AIqBNAtVhWcKz1Mc/6nzkP3/1HXZHAzCLYrmuFnTGb874XT4TJDg', - }, - }, - valid_until_ts: 1747753307525, - verify_keys: { - 'ed25519:a_FAET': { - key: 'kryovKVnhHESOdWuZ05ViNotRMVdEh/mG2yJ0npLzEo', - }, - }, - }; - - const verifyKey = - keyv2serverresponsefromorigin.verify_keys['ed25519:a_FAET'].key; - - const verifier = await loadEd25519VerifierFromPublicKey( - fromBase64ToBytes(verifyKey), - ); - - expect(verifyJsonSignature(json, signature, verifier)).resolves; - }); }); From 444f7ff8782e652b58889b8bac05fd98aa8959f4 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 24 Nov 2025 13:04:37 -0300 Subject: [PATCH 05/12] chore: remove verifySignature --- packages/core/src/index.ts | 1 - packages/core/src/utils/signJson.ts | 45 ----------------------------- 2 files changed, 46 deletions(-) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 55d0ddfb5..a35003017 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -23,7 +23,6 @@ export { signJson, isValidAlgorithm, getSignaturesFromRemote, - verifySignature, verifySignaturesFromRemote, signText, signData, diff --git a/packages/core/src/utils/signJson.ts b/packages/core/src/utils/signJson.ts index dc192b85a..4a9074b3e 100644 --- a/packages/core/src/utils/signJson.ts +++ b/packages/core/src/utils/signJson.ts @@ -88,51 +88,6 @@ export async function getSignaturesFromRemote< return remoteSignatures; } -export const verifySignature = ( - content: string, - signingName: string, - signature: Uint8Array, - publicKey: Uint8Array, - algorithm: EncryptionValidAlgorithm, - _version: string, -) => { - if (algorithm !== EncryptionValidAlgorithm.ed25519) { - throw new Error(`Invalid algorithm ${algorithm} for ${signingName}`); - } - - if ( - !nacl.sign.detached.verify( - new TextEncoder().encode(content), - signature, - publicKey, - ) - ) { - throw new Error(`Invalid signature for ${signingName}`); - } - return true; -}; - -export const verifyJsonSignature = ( - content: T, - signingName: string, - signature: Uint8Array, - publicKey: Uint8Array, - algorithm: EncryptionValidAlgorithm, - version: string, -) => { - const { signatures: _, unsigned: _unsigned, ...__rest } = content as any; - const canonicalJson = encodeCanonicalJson(__rest); - - return verifySignature( - canonicalJson, - signingName, - signature, - publicKey, - algorithm, - version, - ); -}; - export async function verifySignaturesFromRemote< T extends object & { signatures?: Record>; From a4ced738026119637f3950d96c2975af3d6bed5f Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 24 Nov 2025 13:08:13 -0300 Subject: [PATCH 06/12] chore: remove getKeyPair --- packages/core/src/utils/keys.spec.ts | 63 +--------------------------- packages/core/src/utils/keys.ts | 54 ------------------------ 2 files changed, 1 insertion(+), 116 deletions(-) diff --git a/packages/core/src/utils/keys.spec.ts b/packages/core/src/utils/keys.spec.ts index db5e40cc7..43b5ecb38 100644 --- a/packages/core/src/utils/keys.spec.ts +++ b/packages/core/src/utils/keys.spec.ts @@ -3,11 +3,7 @@ import fs from 'node:fs/promises'; import nacl from 'tweetnacl'; import { EncryptionValidAlgorithm } from '../types'; import { toUnpaddedBase64 } from './binaryData'; -import { - generateKeyPairs, - generateKeyPairsFromString, - getKeyPair, -} from './keys'; +import { generateKeyPairs, generateKeyPairsFromString } from './keys'; describe('keys', () => { describe('generateKeyPairs', () => { @@ -65,61 +61,4 @@ describe('keys', () => { expect(keyPair.privateKey).toEqual(expectedKeyPair.secretKey); }); }); - - describe('getKeyPair', () => { - const signingKeyPath = '/tmp/test-signing.key'; - let readFileSpy: ReturnType; - let writeFileSpy: ReturnType; - - beforeEach(() => { - readFileSpy = spyOn(fs, 'readFile'); - writeFileSpy = spyOn(fs, 'writeFile').mockResolvedValue(undefined); - }); - - afterEach(async () => { - readFileSpy.mockRestore(); - writeFileSpy.mockRestore(); - }); - - it('should generate and store new key pairs if file does not exist', async () => { - readFileSpy.mockRejectedValue(new Error('File not found')); - - const keyPairs = await getKeyPair({ signingKeyPath }); - - expect(keyPairs.length).toBe(1); - - const keyPair = keyPairs[0]; - - expect(keyPair.algorithm).toBe(EncryptionValidAlgorithm.ed25519); - expect(keyPair.version).toBe('0'); - expect(writeFileSpy).toHaveBeenCalledTimes(1); - - const writeCallArg = writeFileSpy.mock.calls[0][1] as string; - - expect(writeCallArg.startsWith('ed25519 0 ')).toBe(true); - }); - - it('should load key pairs from existing file', async () => { - const seed = nacl.randomBytes(nacl.sign.seedLength); - const seedString = toUnpaddedBase64(seed); - const fileContent = `${EncryptionValidAlgorithm.ed25519} 1 ${seedString}`; - - readFileSpy.mockResolvedValue(fileContent); - - const keyPairs = await getKeyPair({ signingKeyPath }); - - expect(keyPairs.length).toBe(1); - - const keyPair = keyPairs[0]; - - expect(keyPair.algorithm).toBe(EncryptionValidAlgorithm.ed25519); - expect(keyPair.version).toBe('1'); - - const expectedKeyPair = await nacl.sign.keyPair.fromSeed(seed); - - expect(keyPair.publicKey).toEqual(expectedKeyPair.publicKey); - expect(keyPair.privateKey).toEqual(expectedKeyPair.secretKey); - expect(writeFileSpy).not.toHaveBeenCalled(); - }); - }); }); diff --git a/packages/core/src/utils/keys.ts b/packages/core/src/utils/keys.ts index 39fc9bf3c..64135d0e2 100644 --- a/packages/core/src/utils/keys.ts +++ b/packages/core/src/utils/keys.ts @@ -1,8 +1,6 @@ -import fs from 'node:fs/promises'; import nacl from 'tweetnacl'; import { EncryptionValidAlgorithm } from '../types'; import type { SigningKey } from '../types'; -import { toUnpaddedBase64 } from './binaryData'; import { signData } from './signJson'; export async function generateKeyPairs( @@ -36,57 +34,5 @@ export async function generateKeyPairsFromString(content: string) { ); } -async function storeKeyPairs( - seeds: { - algorithm: string; - version: string; - seed: Uint8Array; - }[], - path: string, -) { - for await (const keyPair of seeds) { - await fs.writeFile( - path, - `${keyPair.algorithm} ${keyPair.version} ${toUnpaddedBase64(keyPair.seed)}`, - ); - } -} - -export const getKeyPair = async (config: { - signingKeyPath: string; -}): Promise => { - const { signingKeyPath } = config; - - const seeds = []; - - const existingKeyContent = await fs - .readFile(signingKeyPath, 'utf8') - .catch(() => null); - - if (existingKeyContent) { - const [algorithm, version, seed] = existingKeyContent.trim().split(' '); - seeds.push({ - algorithm: algorithm as EncryptionValidAlgorithm, - version, - seed: Uint8Array.from(atob(seed), (c) => c.charCodeAt(0)), - }); - } else { - seeds.push({ - algorithm: 'ed25519' as EncryptionValidAlgorithm, - version: '0', - seed: nacl.randomBytes(32), - }); - - await storeKeyPairs(seeds, signingKeyPath); - } - - return Promise.all( - seeds.map( - async (seed) => - await generateKeyPairs(seed.seed, seed.algorithm, seed.version), - ), - ); -}; - export const convertSigningKeyToBase64 = (signingKey: SigningKey): string => `${signingKey.algorithm} ${signingKey.version} ${Buffer.from(signingKey.privateKey.slice(0, 32)).toString('base64')}`; From d991e6b437f6e6718619997cc768d3e3669aa253 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 24 Nov 2025 13:11:27 -0300 Subject: [PATCH 07/12] chore: remove verifySignaturesFromRemote --- packages/core/src/index.ts | 1 - packages/core/src/utils/signJson.ts | 39 -------- .../federation-sdk/src/utils/signJson.spec.ts | 94 ------------------- 3 files changed, 134 deletions(-) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index a35003017..6e9a9e90a 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -23,7 +23,6 @@ export { signJson, isValidAlgorithm, getSignaturesFromRemote, - verifySignaturesFromRemote, signText, signData, } from './utils/signJson'; diff --git a/packages/core/src/utils/signJson.ts b/packages/core/src/utils/signJson.ts index 4a9074b3e..da8f7b03a 100644 --- a/packages/core/src/utils/signJson.ts +++ b/packages/core/src/utils/signJson.ts @@ -88,45 +88,6 @@ export async function getSignaturesFromRemote< return remoteSignatures; } -export async function verifySignaturesFromRemote< - T extends object & { - signatures?: Record>; - unsigned?: unknown; - }, ->( - jsonObject: T, - signingName: string, - getPublicKey: ( - algorithm: EncryptionValidAlgorithm, - version: string, - ) => Promise, -) { - const { signatures: _, unsigned: _unsigned, ...__rest } = jsonObject; - - const canonicalJson = encodeCanonicalJson(__rest); - - const signatures = await getSignaturesFromRemote(jsonObject, signingName); - - for await (const { algorithm, version, signature } of signatures) { - const publicKey = await getPublicKey( - algorithm as EncryptionValidAlgorithm, - version, - ); - - if ( - !nacl.sign.detached.verify( - new TextEncoder().encode(canonicalJson), - new Uint8Array(Buffer.from(signature, 'base64')), - publicKey, - ) - ) { - throw new Error(`Invalid signature for ${signingName}`); - } - } - - return true; -} - export async function signText( data: string | Uint8Array, signingKey: Uint8Array, diff --git a/packages/federation-sdk/src/utils/signJson.spec.ts b/packages/federation-sdk/src/utils/signJson.spec.ts index fc52d9eba..7ec7464c2 100644 --- a/packages/federation-sdk/src/utils/signJson.spec.ts +++ b/packages/federation-sdk/src/utils/signJson.spec.ts @@ -4,102 +4,8 @@ import { generateKeyPairsFromString, pruneEventDict, signJson, - verifySignaturesFromRemote, } from '@rocket.chat/federation-core'; -describe('verifySignaturesFromRemote', async () => { - test('it should verify a valid signature', async () => { - const serverName = 'synapse'; - const signature = await generateKeyPairsFromString( - 'ed25519 a_yNbw tBD7FfjyBHgT4TwhwzvyS9Dq2Z9ck38RRQKaZ6Sz2z8', - ); - - const signed = await signJson({}, signature, serverName); - - await verifySignaturesFromRemote( - signed, - serverName, - async () => signature.publicKey, - ); - - expect( - async () => - await verifySignaturesFromRemote( - signed, - serverName, - async () => signature.publicKey, - ), - ).not.toThrow(); - }); - - test('it should throw an error if the signature is invalid', async () => { - const serverName = 'synapse'; - const signature = await generateKeyPairsFromString( - 'ed25519 a_yNbw tBD7FfjyBHgT4TwhwzvyS9Dq2Z9ck38RRQKaZ6Sz2z8', - ); - - const signed = await signJson({}, signature, serverName); - - expect( - async () => - await verifySignaturesFromRemote(signed, serverName, async () => - Uint8Array.from( - atob('tBD7FfjyBHgT4TwhwzvyS9Dq2Z9ck38RRQKaZ6Sz2z8'), - (c) => c.charCodeAt(0), - ), - ), - ).toThrow(); - }); - - test('it should throw an error if there is no valid protocol version', async () => { - const serverName = 'synapse'; - - expect( - async () => - await verifySignaturesFromRemote( - { - signatures: { - [serverName]: { - [`${EncryptionValidAlgorithm.ed25519}1:a_yNbw`]: 'invalid', - }, - }, - }, - serverName, - async () => - Uint8Array.from( - atob('tBD7FfjyBHgT4TwhwzvyS9Dq2Z9ck38RRQKaZ6Sz2z8'), - (c) => c.charCodeAt(0), - ), - ), - ).toThrow( - `Invalid algorithm ${EncryptionValidAlgorithm.ed25519}1 for ${serverName}`, - ); - }); - - it('it should throw an error if the signature is invalid for the serverName', async () => { - const serverName = 'synapse'; - - expect( - async () => - await verifySignaturesFromRemote( - { - signatures: { - differentServer: { - [`${EncryptionValidAlgorithm.ed25519}1:a_yNbw`]: 'invalid', - }, - }, - }, - serverName, - async () => - Uint8Array.from( - atob('tBD7FfjyBHgT4TwhwzvyS9Dq2Z9ck38RRQKaZ6Sz2z8'), - (c) => c.charCodeAt(0), - ), - ), - ).toThrow(`Signatures not found for ${serverName}`); - }); -}); - // { // "content": { // "auth_events": [ From 738150c59def71ade5b29c42d2ca87130d86e11e Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 24 Nov 2025 13:11:58 -0300 Subject: [PATCH 08/12] chore: remove signText --- packages/core/src/index.ts | 1 - packages/core/src/utils/signJson.ts | 12 ------------ 2 files changed, 13 deletions(-) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 6e9a9e90a..1c0678a8f 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -23,7 +23,6 @@ export { signJson, isValidAlgorithm, getSignaturesFromRemote, - signText, signData, } from './utils/signJson'; diff --git a/packages/core/src/utils/signJson.ts b/packages/core/src/utils/signJson.ts index da8f7b03a..b72470ac5 100644 --- a/packages/core/src/utils/signJson.ts +++ b/packages/core/src/utils/signJson.ts @@ -88,18 +88,6 @@ export async function getSignaturesFromRemote< return remoteSignatures; } -export async function signText( - data: string | Uint8Array, - signingKey: Uint8Array, -) { - const signature = nacl.sign.detached( - typeof data === 'string' ? new TextEncoder().encode(data) : data, - signingKey, - ); - - return toUnpaddedBase64(signature); -} - export async function signData( data: string | Uint8Array, signingKey: Uint8Array, From bb62fed6a53085734eb2b518db72f99c518c649f Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 24 Nov 2025 13:12:38 -0300 Subject: [PATCH 09/12] chore: remove getSignaturesFromRemote --- packages/core/src/index.ts | 1 - packages/core/src/utils/signJson.ts | 33 ----------------------------- 2 files changed, 34 deletions(-) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 1c0678a8f..102170677 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -22,7 +22,6 @@ export type { ProtocolVersionKey, SignedJson } from './utils/signJson'; export { signJson, isValidAlgorithm, - getSignaturesFromRemote, signData, } from './utils/signJson'; diff --git a/packages/core/src/utils/signJson.ts b/packages/core/src/utils/signJson.ts index b72470ac5..a5bbcdae9 100644 --- a/packages/core/src/utils/signJson.ts +++ b/packages/core/src/utils/signJson.ts @@ -55,39 +55,6 @@ export const isValidAlgorithm = ( return Object.values(EncryptionValidAlgorithm).includes(algorithm as any); }; -export async function getSignaturesFromRemote< - T extends object & { - signatures?: Record>; - unsigned?: unknown; - }, ->(jsonObject: T, signingName: string) { - const { signatures, unsigned: _unsigned /*..._rest */ } = jsonObject; - const remoteSignatures = - signatures?.[signingName] && - Object.entries(signatures[signingName]) - .map(([keyId, signature]) => { - const [algorithm, version] = keyId.split(':'); - if (!isValidAlgorithm(algorithm)) { - throw new Error(`Invalid algorithm ${algorithm} for ${signingName}`); - } - - return { - algorithm, - version, - signature, - }; - }) - .filter(({ algorithm }) => - Object.values(EncryptionValidAlgorithm).includes(algorithm as any), - ); - - if (!remoteSignatures?.length) { - throw new Error(`Signatures not found for ${signingName}`); - } - - return remoteSignatures; -} - export async function signData( data: string | Uint8Array, signingKey: Uint8Array, From f6991b118a23cd5b88dc3fbc8c63f7224fb7fdb9 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 24 Nov 2025 13:15:59 -0300 Subject: [PATCH 10/12] chore: move signData to file used by tests only --- packages/core/src/index.ts | 1 - packages/core/src/utils/keys.spec.ts | 4 +--- packages/core/src/utils/keys.ts | 15 ++++++++++++++- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 102170677..4b3d53679 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -22,7 +22,6 @@ export type { ProtocolVersionKey, SignedJson } from './utils/signJson'; export { signJson, isValidAlgorithm, - signData, } from './utils/signJson'; // Binary data utilities diff --git a/packages/core/src/utils/keys.spec.ts b/packages/core/src/utils/keys.spec.ts index 43b5ecb38..ab8e2a36c 100644 --- a/packages/core/src/utils/keys.spec.ts +++ b/packages/core/src/utils/keys.spec.ts @@ -1,8 +1,6 @@ -import { afterEach, beforeEach, describe, expect, it, spyOn } from 'bun:test'; -import fs from 'node:fs/promises'; +import { describe, expect, it } from 'bun:test'; import nacl from 'tweetnacl'; import { EncryptionValidAlgorithm } from '../types'; -import { toUnpaddedBase64 } from './binaryData'; import { generateKeyPairs, generateKeyPairsFromString } from './keys'; describe('keys', () => { diff --git a/packages/core/src/utils/keys.ts b/packages/core/src/utils/keys.ts index 64135d0e2..9cab5c317 100644 --- a/packages/core/src/utils/keys.ts +++ b/packages/core/src/utils/keys.ts @@ -1,7 +1,20 @@ import nacl from 'tweetnacl'; import { EncryptionValidAlgorithm } from '../types'; import type { SigningKey } from '../types'; -import { signData } from './signJson'; + +// these functions are used by tests only + +async function signData( + data: string | Uint8Array, + signingKey: Uint8Array, +): Promise { + const signature = nacl.sign.detached( + typeof data === 'string' ? new TextEncoder().encode(data) : data, + signingKey, + ); + + return signature; +} export async function generateKeyPairs( seed: Uint8Array, From 798148865e4c49c3fba0b539621febbffc1cd314 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 24 Nov 2025 13:18:43 -0300 Subject: [PATCH 11/12] chore: move tweetnacl to devDependencies --- bun.lockb | Bin 98312 -> 100352 bytes bundle.ts | 1 - package.json | 6 +++--- packages/core/src/utils/signJson.ts | 13 ------------- packages/federation-sdk/package.json | 1 - rollup.config.js | 1 - 6 files changed, 3 insertions(+), 19 deletions(-) diff --git a/bun.lockb b/bun.lockb index 3fff2edf7fa1fdad2f99541cdc47f3b133ab5afa..99cc1f0f19f588a301fc7c10b25382a7a4bbeb6b 100755 GIT binary patch delta 7644 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 E2iAZ4EdT%j delta 7220 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 p; { return Object.values(EncryptionValidAlgorithm).includes(algorithm as any); }; - -export async function signData( - data: string | Uint8Array, - signingKey: Uint8Array, -): Promise { - const signature = nacl.sign.detached( - typeof data === 'string' ? new TextEncoder().encode(data) : data, - signingKey, - ); - - return signature; -} diff --git a/packages/federation-sdk/package.json b/packages/federation-sdk/package.json index f3d31abbb..a6ff8ab4b 100644 --- a/packages/federation-sdk/package.json +++ b/packages/federation-sdk/package.json @@ -23,7 +23,6 @@ "mongodb": "^6.16.0", "reflect-metadata": "^0.2.2", "tsyringe": "^4.10.0", - "tweetnacl": "^1.0.3", "zod": "^3.24.1" }, "license": "AGPL-3.0", diff --git a/rollup.config.js b/rollup.config.js index 941b3e93d..8c0343666 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -31,7 +31,6 @@ const isExternal = (id) => { 'pino', 'pino-std-serializers', 'sonic-boom', - 'tweetnacl', ].includes(id) ) { return true; From 88717e4f2708c65357abbaaec5d6ce6325214d58 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Mon, 24 Nov 2025 13:48:39 -0300 Subject: [PATCH 12/12] update bun.lock --- bun.lock | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/bun.lock b/bun.lock index d8c4e97c6..5eea50d60 100644 --- a/bun.lock +++ b/bun.lock @@ -10,7 +10,6 @@ "rollup": "^4.52.4", "rollup-plugin-dts": "^6.2.3", "tsyringe": "^4.10.0", - "tweetnacl": "^1.0.3", }, "devDependencies": { "@biomejs/biome": "^1.9.4", @@ -23,6 +22,7 @@ "sinon": "^20.0.0", "tsconfig-paths": "^4.2.0", "turbo": "~2.5.6", + "tweetnacl": "^1.0.3", "typescript": "~5.9.2", }, }, @@ -54,7 +54,7 @@ }, "packages/federation-sdk": { "name": "@rocket.chat/federation-sdk", - "version": "0.3.0", + "version": "0.3.1", "dependencies": { "@rocket.chat/emitter": "^0.31.25", "@rocket.chat/federation-core": "workspace:*", @@ -63,7 +63,6 @@ "mongodb": "^6.16.0", "reflect-metadata": "^0.2.2", "tsyringe": "^4.10.0", - "tweetnacl": "^1.0.3", "zod": "^3.24.1", }, "peerDependencies": { @@ -291,7 +290,7 @@ "buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], - "bun-types": ["bun-types@1.3.1", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-NMrcy7smratanWJ2mMXdpatalovtxVggkj11bScuWuiOoXTiKIu2eVS1/7qbyI/4yHedtsn175n4Sm4JcdHLXw=="], + "bun-types": ["bun-types@1.3.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-z3Xwlg7j2l9JY27x5Qn3Wlyos8YAp0kKRlrePAOjgjMGS5IG6E7Jnlx736vH9UVI4wUICwwhC9anYL++XeOgTQ=="], "chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="],