Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
5e9d98c
fix the tests
debdutdeb Sep 15, 2025
8cbcc04
test changes
debdutdeb Sep 15, 2025
453b8ab
mistakenly committed
debdutdeb Sep 15, 2025
71af331
fix import order in test file
debdutdeb Sep 15, 2025
fc13a07
update lockfile
debdutdeb Sep 15, 2025
644d4dc
.... playing with it
debdutdeb Aug 30, 2025
6b81995
committing
debdutdeb Sep 3, 2025
3fa2276
show old test working
debdutdeb Sep 3, 2025
9a9e87d
..
debdutdeb Sep 4, 2025
e682d4b
committing all
debdutdeb Sep 4, 2025
31c2418
...
debdutdeb Sep 8, 2025
0070e01
biome lint
debdutdeb Sep 8, 2025
0d8ec53
correct event signature validation
debdutdeb Sep 8, 2025
9ed8bc4
reduce lines
debdutdeb Sep 8, 2025
b04ff5d
now using in the services, more incoming
debdutdeb Sep 8, 2025
c0f71e1
fix tests for request service
debdutdeb Sep 8, 2025
92512b5
...
debdutdeb Sep 15, 2025
fd22b03
tests are passing at this point
debdutdeb Sep 15, 2025
1bb49d7
ts all there
debdutdeb Sep 16, 2025
df8a8f6
reduce diff 1
debdutdeb Sep 16, 2025
53b0cce
2
debdutdeb Sep 16, 2025
c69bb92
remove my bun hack
debdutdeb Sep 16, 2025
9ba45fd
fix races
debdutdeb Sep 16, 2025
df62bf7
all lints
debdutdeb Sep 16, 2025
ba83208
add mongo to ci? dump later
debdutdeb Sep 16, 2025
1b0cc56
,,
debdutdeb Sep 16, 2025
74d3b4a
fix cachekey
debdutdeb Sep 17, 2025
0885012
better
debdutdeb Sep 17, 2025
6bdda06
Merge remote-tracking branch 'origin/main' into fdr108-use-crypto-eve…
debdutdeb Nov 5, 2025
760e926
fix: all import package names
debdutdeb Nov 5, 2025
265c47c
fix: allow svs to fetch keys as it needs
debdutdeb Nov 5, 2025
f77a240
fix: repassing some tests
debdutdeb Nov 5, 2025
aa3ea98
fix: passing event service tests
debdutdeb Nov 5, 2025
58d5e7f
fix: signature verification service tests
debdutdeb Nov 5, 2025
ae6ea98
chore: sep tests that require mongo
debdutdeb Nov 5, 2025
84f5e49
refactor: better error handling and remove server service
debdutdeb Nov 5, 2025
1f17ab0
refactor: rename own server key mmethod to more accurate one
debdutdeb Nov 5, 2025
9ee83a0
fix: keyservice.getownserverkeyresponse
debdutdeb Nov 5, 2025
33df512
fix: linter complains
debdutdeb Nov 5, 2025
57276c8
fix: broken tests
debdutdeb Nov 5, 2025
dca5761
fix: crypto thrown error type
debdutdeb Nov 5, 2025
8c4d820
chore: workflow file formatting
debdutdeb Nov 5, 2025
d62c230
update lock file
debdutdeb Nov 5, 2025
87b4e77
Merge remote-tracking branch 'origin/main' into fdr108-use-crypto-eve…
sampaiodiego Nov 24, 2025
54c9c61
restore bun.lock
sampaiodiego Nov 24, 2025
59ac6d6
test: improve config instance
sampaiodiego Nov 24, 2025
a0b18a8
fix: delay KeyRepository inject
sampaiodiego Nov 24, 2025
def6e7e
test: fix tests
sampaiodiego Nov 24, 2025
8bde57b
fix: config getSigningKey
sampaiodiego Nov 24, 2025
1cb5955
fix: remove database options from config
sampaiodiego Nov 24, 2025
637807c
Merge remote-tracking branch 'origin/main' into fdr108-use-crypto-eve…
sampaiodiego Nov 25, 2025
653eb6d
revert sdk methods changes
sampaiodiego Nov 25, 2025
0ed45f6
sign join event
sampaiodiego Nov 25, 2025
dbd133a
fix get server key
sampaiodiego Nov 25, 2025
f9f5bc1
revert additional check on getRoomVersion
sampaiodiego Nov 25, 2025
b79a356
code cleanup
sampaiodiego Nov 25, 2025
fec7759
Merge remote-tracking branch 'origin/main' into fdr108-use-crypto-eve…
sampaiodiego Nov 25, 2025
5531ab7
more cleanup
sampaiodiego Nov 25, 2025
665d272
remove duplicated getRoomVersion
sampaiodiego Nov 25, 2025
76a4314
validate request destination
sampaiodiego Nov 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
- run: bun lint:ci
- run: bun tsc --noEmit
- uses: supercharge/mongodb-github-action@1.12.0
- run: RUN_MONGO_TESTS=1 bun test packages/federation-sdk/src/services/state.service.spec.ts packages/federation-sdk/src/services/room.service.spec.ts
- run: LOG_LEVEL=debug bun run test:withMongo
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v5
with:
Expand Down
13 changes: 11 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,14 @@
"[typescript]": {
"editor.defaultFormatter": "biomejs.biome"
},
"typescript.enablePromptUseWorkspaceTsdk": true
}
"typescript.enablePromptUseWorkspaceTsdk": true,
"[json]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[jsonc]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[javascript]": {
"editor.defaultFormatter": "biomejs.biome"
}
}
Binary file modified bun.lockb
Binary file not shown.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"test": "bun test",
"build": "turbo build",
"test:coverage": "bun test --coverage",
"test:withMongo": "export RUN_MONGO_TESTS=1; grep -r runIfMongoExists packages/federation-sdk/src/services/ | awk -F: '/spec/ { print $1 }' | xargs bun test {}",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

Script executed:

# First, check the package.json file to see current state and dependencies
cat package.json | head -100

Repository: RocketChat/homeserver


<shell_result>
Repository: RocketChat/homeserver
Exit code: 0

stdout:

{
	"name": "homeserver",
	"module": "index.ts",
	"private": true,
	"type": "module",
	"devDependencies": {
		"@biomejs/biome": "^1.9.4",
		"@types/bun": "latest",
		"@types/express": "^5.0.1",
		"@types/node": "^22.15.18",
		"@types/sinon": "^17.0.4",
		"husky": "^9.1.7",
		"lint-staged": "^16.1.2",
		"sinon": "^20.0.0",
		"tsconfig-paths": "^4.2.0",
		"turbo": "~2.5.6",
		"typescript": "~5.9.2"
	},
	"workspaces": ["packages/*"],
	"dependencies": {
		"dotenv": "^16.5.0",
		"memoize": "^10.1.0",
		"reflect-metadata": "^0.2.2",
		"rollup": "^4.52.4",
		"rollup-plugin-dts": "^6.2.3",
		"tsyringe": "^4.10.0",
		"tweetnacl": "^1.0.3"
	},
	"husky": {
		"hooks": {
			"pre-commit": "bun test"
		}
	},
	"packageManager": "bun@1.1.10",
	"lint-staged": {
		"**.{js|ts|cjs|mjs|d.cts|d.mts|jsx|tsx|json|jsonc}": [
			"biome check --files-ignore-unknown=true --diagnostic-level=error",
			"biome check --write --no-errors-on-unmatched --diagnostic-level=error",
			"biome check --write --organize-imports-enabled=false --no-errors-on-unmatched --diagnostic-level=error",
			"biome check --write --unsafe --no-errors-on-unmatched --diagnostic-level=error",
			"biome format --write --no-errors-on-unmatched --diagnostic-level=error",
			"biome lint --write --no-errors-on-unmatched --diagnostic-level=error"
		],
		"*": ["biome check --no-errors-on-unmatched --files-ignore-unknown=true"]
	},
	"scripts": {
		"prepare": "husky",
		"start": "bun run index.ts",
		"test": "bun test",
		"build": "turbo build",
		"test:coverage": "bun test --coverage",
		"test:withMongo": "export RUN_MONGO_TESTS=1; grep -r runIfMongoExists packages/federation-sdk/src/services/ | awk -F: '/spec/ { print $1 }' | xargs bun test {}",
		"lint": "bunx @biomejs/biome lint --diagnostic-level=error",
		"lint:ci": "bunx @biomejs/biome ci --diagnostic-level=error",
		"lint:fix": "bunx @biomejs/biome lint --fix",
		"tsc": "tsc --noEmit",
		"bundle:sdk": "bun run build && bun run bundle.ts"
	}
}

</shell_result>


Script executed:

# Look for cross-env in current devDependencies
rg "cross-env" package.json

Repository: RocketChat/homeserver


<shell_result>
Repository: RocketChat/homeserver
Exit code: 1

</shell_result>


Script executed:

# Check if packages/federation-sdk/src/services/ exists and what test files are there
fd "\.spec\." packages/federation-sdk/src/services/

Repository: RocketChat/homeserver


<shell_result>
Repository: RocketChat/homeserver
Exit code: 0

stdout:

packages/federation-sdk/src/services/event.service.spec.ts
packages/federation-sdk/src/services/federation-request.service.spec.ts
packages/federation-sdk/src/services/key.service.spec.ts
packages/federation-sdk/src/services/room.service.spec.ts
packages/federation-sdk/src/services/signature-verification.service.spec.ts
packages/federation-sdk/src/services/state.service.spec.ts

</shell_result>


Script executed:

# Search for runIfMongoExists to understand the function and its usage
rg "runIfMongoExists" --type ts --type js -B2 -A2

Repository: RocketChat/homeserver


<shell_result>
Repository: RocketChat/homeserver
Exit code: 0

stdout:

packages/federation-sdk/src/services/event.service.spec.ts-	UserID,
packages/federation-sdk/src/services/event.service.spec.ts-} from '@rocket.chat/federation-room';
packages/federation-sdk/src/services/event.service.spec.ts:import { runIfMongoExists } from '../__mocks__/block-if-no-mongo';
packages/federation-sdk/src/services/event.service.spec.ts-import { repositories } from '../__mocks__/repositories.spec';
packages/federation-sdk/src/services/event.service.spec.ts-import { eventService } from '../__mocks__/services.spec';
--
packages/federation-sdk/src/services/event.service.spec.ts-};
packages/federation-sdk/src/services/event.service.spec.ts-
packages/federation-sdk/src/services/event.service.spec.ts:runIfMongoExists(() =>
packages/federation-sdk/src/services/event.service.spec.ts-	describe('EventService', async () => {
packages/federation-sdk/src/services/event.service.spec.ts-		const { getHomeserverFinalAddress: originalServerDiscovery } = await import(
--
packages/federation-sdk/src/services/signature-verification.service.spec.ts-	UserID,
packages/federation-sdk/src/services/signature-verification.service.spec.ts-} from '@rocket.chat/federation-room';
packages/federation-sdk/src/services/signature-verification.service.spec.ts:import { runIfMongoExists } from '../__mocks__/block-if-no-mongo';
packages/federation-sdk/src/services/signature-verification.service.spec.ts-import { keyService } from '../__mocks__/services.spec';
packages/federation-sdk/src/services/signature-verification.service.spec.ts-import { AppConfig, ConfigService } from './config.service';
--
packages/federation-sdk/src/services/signature-verification.service.spec.ts-};
packages/federation-sdk/src/services/signature-verification.service.spec.ts-
packages/federation-sdk/src/services/signature-verification.service.spec.ts:runIfMongoExists(() =>
packages/federation-sdk/src/services/signature-verification.service.spec.ts-	describe('SignatureVerificationService', async () => {
packages/federation-sdk/src/services/signature-verification.service.spec.ts-		let service: SignatureVerificationService;
--
packages/federation-sdk/src/services/state.service.spec.ts-} from '@rocket.chat/federation-room';
packages/federation-sdk/src/services/state.service.spec.ts-import { type WithId } from 'mongodb';
packages/federation-sdk/src/services/state.service.spec.ts:import { runIfMongoExists } from '../__mocks__/block-if-no-mongo';
packages/federation-sdk/src/services/state.service.spec.ts-import { signer } from '../__mocks__/singer.spec';
packages/federation-sdk/src/services/state.service.spec.ts-import { EventRepository } from '../repositories/event.repository';
--
packages/federation-sdk/src/services/state.service.spec.ts-}
packages/federation-sdk/src/services/state.service.spec.ts-
packages/federation-sdk/src/services/state.service.spec.ts:runIfMongoExists(() =>
packages/federation-sdk/src/services/state.service.spec.ts-	describe('StateService', async () => {
packages/federation-sdk/src/services/state.service.spec.ts-		const databaseConfig = {
--
packages/federation-sdk/src/__mocks__/block-if-no-mongo.ts:export function runIfMongoExists(t: () => void) {
packages/federation-sdk/src/__mocks__/block-if-no-mongo.ts-	if (!process.env.RUN_MONGO_TESTS) {
packages/federation-sdk/src/__mocks__/block-if-no-mongo.ts-		console.warn('Skipping tests that require a database');
--
packages/federation-sdk/src/services/key.service.spec.ts-import { afterEach, beforeEach } from 'node:test';
packages/federation-sdk/src/services/key.service.spec.ts-
packages/federation-sdk/src/services/key.service.spec.ts:import { runIfMongoExists } from '../__mocks__/block-if-no-mongo';
packages/federation-sdk/src/services/key.service.spec.ts-import { keyService } from '../__mocks__/services.spec';
packages/federation-sdk/src/services/key.service.spec.ts-import { signer } from '../__mocks__/singer.spec';
packages/federation-sdk/src/services/key.service.spec.ts-
packages/federation-sdk/src/services/key.service.spec.ts:runIfMongoExists(() =>
packages/federation-sdk/src/services/key.service.spec.ts-	describe('KeyService', async () => {
packages/federation-sdk/src/services/key.service.spec.ts-		// fetch mocking

</shell_result>


Script executed:

# Check the git diff or current state to understand what was changed related to this
git diff HEAD package.json 2>/dev/null | head -50 || echo "Git diff not available"

Repository: RocketChat/homeserver


<shell_result>
Repository: RocketChat/homeserver
Exit code: 0

</shell_result>


Script executed:

# Check if all spec files use runIfMongoExists
rg "runIfMongoExists" packages/federation-sdk/src/services/*.spec.ts

Repository: RocketChat/homeserver


<shell_result>
Repository: RocketChat/homeserver
Exit code: 0

stdout:

packages/federation-sdk/src/services/state.service.spec.ts:import { runIfMongoExists } from '../__mocks__/block-if-no-mongo';
packages/federation-sdk/src/services/state.service.spec.ts:runIfMongoExists(() =>
packages/federation-sdk/src/services/signature-verification.service.spec.ts:import { runIfMongoExists } from '../__mocks__/block-if-no-mongo';
packages/federation-sdk/src/services/signature-verification.service.spec.ts:runIfMongoExists(() =>
packages/federation-sdk/src/services/key.service.spec.ts:import { runIfMongoExists } from '../__mocks__/block-if-no-mongo';
packages/federation-sdk/src/services/key.service.spec.ts:runIfMongoExists(() =>
packages/federation-sdk/src/services/event.service.spec.ts:import { runIfMongoExists } from '../__mocks__/block-if-no-mongo';
packages/federation-sdk/src/services/event.service.spec.ts:runIfMongoExists(() =>

</shell_result>


Script executed:

# Look at the full block-if-no-mongo implementation to understand the pattern
cat packages/federation-sdk/src/__mocks__/block-if-no-mongo.ts

Repository: RocketChat/homeserver


<shell_result>
Repository: RocketChat/homeserver
Exit code: 0

stdout:

export function runIfMongoExists(t: () => void) {
	if (!process.env.RUN_MONGO_TESTS) {
		console.warn('Skipping tests that require a database');
		return;
	}

	t();
}

</shell_result>


Script executed:

# Check bun documentation or any example of how bun test handles arguments
grep -r "bun test" . --include="*.json" --include="*.md" --include="*.sh" 2>/dev/null | head -20

Repository: RocketChat/homeserver


<shell_result>
Repository: RocketChat/homeserver
Exit code: 0

stdout:

./.vscode/tasks.json:			"script": "bun test --inspect-wait=localhost:6499/ ${file} -t ${input:test-name}",
./packages/federation-sdk/package.json:		"test": "bun test"
./package.json:			"pre-commit": "bun test"
./package.json:		"test": "bun test",
./package.json:		"test:coverage": "bun test --coverage",
./package.json:		"test:withMongo": "export RUN_MONGO_TESTS=1; grep -r runIfMongoExists packages/federation-sdk/src/services/ | awk -F: '/spec/ { print $1 }' | xargs bun test {}",

</shell_result>


Script executed:

# Verify if there's a package-lock or bun.lockb that shows what's installed
ls -la | grep -E "bun\.lock|package-lock"

Repository: RocketChat/homeserver


<shell_result>
Repository: RocketChat/homeserver
Exit code: 0

stdout:

-rw-r--r-- 1 jailuser jailuser 57243 Nov 25 22:29 bun.lock
-rwxr-xr-x 1 jailuser jailuser 98312 Nov 25 22:29 bun.lockb

</shell_result>


Improve cross-platform compatibility of the test script.

The test:withMongo script has several portability issues:

  1. export RUN_MONGO_TESTS=1 is bash/zsh-specific and will fail on Windows
  2. Unix utilities (grep, awk, xargs) are not available on Windows by default
  3. The {} placeholder in xargs bun test {} is unnecessary—xargs appends arguments by default

Currently, the script runs only the 4 spec files that import runIfMongoExists (event, key, signature-verification, and state services).

Recommended approach: Use a Node/Bun script instead of shell utilities for cross-platform compatibility. Create a script at scripts/test-mongo.ts (or .js):

import { globSync } from "bun";
import { execSync } from "child_process";
import fs from "fs";

// Find test files that import runIfMongoExists
const specFiles = globSync("packages/federation-sdk/src/services/**/*.spec.ts");
const mongoTests = specFiles.filter(file => 
  fs.readFileSync(file, "utf-8").includes("runIfMongoExists")
);

// Run tests with environment variable set
process.env.RUN_MONGO_TESTS = "1";
execSync(`bun test ${mongoTests.join(" ")}`, { stdio: "inherit" });

Then update package.json:

-		"test:withMongo": "export RUN_MONGO_TESTS=1; grep -r runIfMongoExists packages/federation-sdk/src/services/ | awk -F: '/spec/ { print $1 }' | xargs bun test {}",
+		"test:withMongo": "bun run ./scripts/test-mongo.ts",

This approach is cross-platform, easier to maintain, and avoids adding new dependencies like cross-env.

🤖 Prompt for AI Agents
In package.json around line 52, the test:withMongo script uses shell-specific
commands (export, grep, awk, xargs) which break on Windows; replace it by
creating a cross-platform Node/Bun script at scripts/test-mongo.ts that (1)
globs the service spec files, (2) filters those that import "runIfMongoExists",
(3) sets process.env.RUN_MONGO_TESTS = "1", and (4) invokes the test runner with
the matched files (using execSync/spawn with stdio inherited); then update
package.json to call that script (e.g. run the TypeScript/JS script with
Bun/Node) instead of the current shell pipeline.

"lint": "bunx @biomejs/biome lint --diagnostic-level=error",
"lint:ci": "bunx @biomejs/biome ci --diagnostic-level=error",
"lint:fix": "bunx @biomejs/biome lint --fix",
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Types
export { EncryptionValidAlgorithm } from './types';
export type { SignedEvent, SigningKey } from './types';
export type * from './types';

// Event utilities
export { signEvent } from './utils/signEvent';
Expand Down
32 changes: 32 additions & 0 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,35 @@ export type SigningKey = {
publicKey: Uint8Array;
sign(data: Uint8Array): Promise<Uint8Array>;
};

export type KeyV2ServerResponse = {
// still valid for signing events
old_verify_keys: Record<
string,
{
expired_ts: number;
key: string;
}
>;
server_name: string;
signatures: Record<string, Record<string, string>>;
valid_until_ts: number;
// only federation requests
verify_keys: Record<
string, // keyAlgo:algoVersion => KeyId
{
key: string; // base64 encoded
}
>;
};

export type ServerKey = {
serverName: string;
keyId: string;
key: string;
pem: string;

_createdAt: Date;
_updatedAt: Date;
Comment on lines +55 to +56
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_ prefixes don't make sense

expiresAt: Date;
};
4 changes: 2 additions & 2 deletions packages/core/src/utils/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ export async function fetch<T>(
body() {
if (!body) {
body = new Promise<Buffer>((resBody, rejBody) => {
// TODO: Make @hs/core fetch size limit configurable
// TODO: Make @rocket.chat/federation-core fetch size limit configurable
let total = 0;
const MAX_RESPONSE_BYTES = 50 * 1024 * 1024; // 50 MB

Expand Down Expand Up @@ -233,7 +233,7 @@ export async function fetch<T>(
reject(err);
});

// TODO: Make @hs/core fetch timeout configurable
// TODO: Make @rocket.chat/federation-core fetch timeout configurable
request.setTimeout(20_000, () => {
request.destroy(new Error('Request timed out after 20s'));
});
Expand Down
1 change: 1 addition & 0 deletions packages/crypto/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export {
toBinaryData,
fromBinaryData,
fromBase64ToBytes,
InvalidSignatureError,
} from './utils/data-types';

export { isValidAlgorithm } from './utils/constants';
Expand Down
3 changes: 2 additions & 1 deletion packages/crypto/src/keys/ed25519.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
ed25519PublicKeyRawToPem,
} from '../rfc/8410/ed25519-pem';
import { EncryptionValidAlgorithm } from '../utils/constants';
import { InvalidSignatureError } from '../utils/data-types';

export class Ed25519VerifierKeyImpl implements VerifierKey {
algorithm = EncryptionValidAlgorithm.ed25519;
Expand Down Expand Up @@ -44,7 +45,7 @@ export class Ed25519VerifierKeyImpl implements VerifierKey {
} else if (verified) {
resolve();
} else {
reject(new Error('Invalid signature'));
reject(new InvalidSignatureError());
}
},
);
Expand Down
105 changes: 0 additions & 105 deletions packages/crypto/src/tsconfig.json

This file was deleted.

4 changes: 4 additions & 0 deletions packages/crypto/src/utils/data-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,7 @@ export function encodeCanonicalJson(value: unknown): string {
export function fromBase64ToBytes(base64: string): Uint8Array {
return Buffer.from(base64, 'base64');
}

export class InvalidSignatureError extends Error {
name = 'InvalidSignatureError';
}
64 changes: 61 additions & 3 deletions packages/crypto/src/utils/utils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { describe, expect, it } from 'bun:test';
import { encodeCanonicalJson, fromBase64ToBytes } from './data-types';
import {
InvalidSignatureError,
encodeCanonicalJson,
fromBase64ToBytes,
} from './data-types';
import {
loadEd25519SignerFromSeed,
loadEd25519VerifierFromPublicKey,
Expand Down Expand Up @@ -99,9 +103,63 @@ describe('Signing and verifying payloads', async () => {
'0',
);

expect(verifyJsonSignature({}, signature, verifier)).rejects.toThrowError(
'Invalid signature',
expect(verifyJsonSignature({}, signature, verifier)).rejects.toThrow(
InvalidSignatureError,
);
});

it('should validate signature (paranoid test 2)', async () => {
const event = {
auth_events: [
'$Hvb-xPPDhTvlXZe2kMubgj8J7iUa5W7YvjTqMTffgUA',
'$Ulggyo4m1OlI08Z0jJDVeceigjSZP9SdEFVoAn9mEh8',
'$G2TzsvetG2YlHr20tZLHCCzOd-yxPa1jeFT8OU4_6kg',
'$kXOAfDVvahrwzHEOInzmG941IeEJTn-qUOY0YnLIigs',
],
content: {
// displayname: 'debdut1',
membership: 'join' as const,
},
depth: 10,
hashes: { sha256: '6MnKSCFJy1fYf6ukILBEbqx2DkoaD1wRyKXhv689a0A' },
origin: 'syn1.tunnel.dev.rocket.chat',
origin_server_ts: 1757328411218,
prev_events: ['$kXOAfDVvahrwzHEOInzmG941IeEJTn-qUOY0YnLIigs'],
room_id: '!VoUasOLSpcdtRbGHdT:syn2.tunnel.dev.rocket.chat',
sender: '@debdut1:syn1.tunnel.dev.rocket.chat',
state_key: '@debdut1:syn1.tunnel.dev.rocket.chat',
type: 'm.room.member' as const,
signatures: {
'syn1.tunnel.dev.rocket.chat': {
'ed25519:a_FAET':
'eJlvqxPWPe3u+BM4wOwID9YBlh/ZfVVxGYyA5WgpNs5Fe1+c36qrvCKHuXGGjfQoZFrHmZ3/GJw2pv5EvxCZAA',
},
},
unsigned: {
age: 1,
replaces_state: '$kXOAfDVvahrwzHEOInzmG941IeEJTn-qUOY0YnLIigs',
prev_content: { displayname: 'debdut1', membership: 'invite' },
prev_sender: '@debdut:syn2.tunnel.dev.rocket.chat',
},
};

const { unsigned, signatures, ...rest } = event;

const key = 'kryovKVnhHESOdWuZ05ViNotRMVdEh/mG2yJ0npLzEo';

const verifier = await loadEd25519VerifierFromPublicKey(
fromBase64ToBytes(key),
'0',
);

const serialized = encodeCanonicalJson(rest);

const signature =
signatures['syn1.tunnel.dev.rocket.chat']['ed25519:a_FAET'];

const signatureBytes = fromBase64ToBytes(signature);

await verifier.verify(serialized, signatureBytes);
});
});

Expand Down
8 changes: 8 additions & 0 deletions packages/federation-sdk/src/__mocks__/block-if-no-mongo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export function runIfMongoExists(t: () => void) {
if (!process.env.RUN_MONGO_TESTS) {
console.warn('Skipping tests that require a database');
return;
}

t();
}
50 changes: 50 additions & 0 deletions packages/federation-sdk/src/__mocks__/repositories.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
EventStagingStore,
EventStore,
ServerKey,
} from '@rocket.chat/federation-core';
import { EventStagingRepository } from '../repositories/event-staging.repository';
import { EventRepository } from '../repositories/event.repository';
import { KeyRepository } from '../repositories/key.repository';
import { Lock, LockRepository } from '../repositories/lock.repository';
import {
StateGraphRepository,
type StateGraphStore,
} from '../repositories/state-graph.repository';

import { DatabaseConnectionService } from '../services/database-connection.service';

const databaseConfig = {
uri: 'mongodb://localhost:27017/',
name: 'matrix_test',
poolSize: 100,
};

const database = new DatabaseConnectionService(databaseConfig);

const db = await database.getDb();

const keysCollection = db.collection<ServerKey>('test_keys');
const eventsCollection = db.collection<EventStore>('test_events');
const eventStagingCollection =
db.collection<EventStagingStore>('test_event_staging');
const lockCollection = db.collection<Lock>('test_locks');
const statesCollection = db.collection<StateGraphStore>('test_states');

const keyRepository = new KeyRepository(keysCollection);

const eventStagingRepository = new EventStagingRepository(
eventStagingCollection,
);
const lockRepository = new LockRepository(lockCollection);
const stateRepository = new StateGraphRepository(statesCollection);

const eventsRepository = new EventRepository(eventsCollection);

export const repositories = {
keys: keyRepository,
locks: lockRepository,
eventStaging: eventStagingRepository,
states: stateRepository,
events: eventsRepository,
};
Loading