feat(#292): implement protocol version checking

Add protocol version validation during connection handshake.
- Define FEDERATION_PROTOCOL_VERSION constant (1.0)
- Validate version on both outgoing and incoming connections
- Require exact version match for compatibility
- Log and audit version mismatches

Fixes #292

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-03 22:00:16 -06:00
parent d373ce591f
commit 14ae97bba4
3 changed files with 115 additions and 0 deletions

View File

@@ -21,6 +21,7 @@ import { FederationAuditService } from "./audit.service";
import { firstValueFrom } from "rxjs";
import type { ConnectionRequest, ConnectionDetails } from "./types/connection.types";
import type { PublicInstanceIdentity } from "./types/instance.types";
import { FEDERATION_PROTOCOL_VERSION } from "./constants";
@Injectable()
export class ConnectionService {
@@ -55,6 +56,9 @@ export class ConnectionService {
// Fetch remote instance identity
const remoteIdentity = await this.fetchRemoteIdentity(remoteUrl);
// Validate protocol version compatibility
this.validateProtocolVersion(remoteIdentity.capabilities.protocolVersion);
// Get our instance identity
const localIdentity = await this.federationService.getInstanceIdentity();
@@ -316,6 +320,25 @@ export class ConnectionService {
throw new UnauthorizedException("Invalid connection request signature");
}
// Validate protocol version compatibility
try {
this.validateProtocolVersion(request.capabilities.protocolVersion);
} catch (error) {
const errorMsg = error instanceof Error ? error.message : "Unknown error";
this.logger.warn(`Incompatible protocol version from ${request.instanceId}: ${errorMsg}`);
// Audit log: Connection rejected
this.auditService.logIncomingConnectionRejected({
workspaceId,
remoteInstanceId: request.instanceId,
remoteUrl: request.instanceUrl,
reason: "Incompatible protocol version",
error: errorMsg,
});
throw error;
}
// Create pending connection
const connection = await this.prisma.federationConnection.create({
data: {
@@ -403,4 +426,22 @@ export class ConnectionService {
disconnectedAt: connection.disconnectedAt,
};
}
/**
* Validate protocol version compatibility
* Currently requires exact version match
*/
private validateProtocolVersion(remoteVersion: string | undefined): void {
if (!remoteVersion) {
throw new BadRequestException(
`Protocol version not specified. Expected ${FEDERATION_PROTOCOL_VERSION}`
);
}
if (remoteVersion !== FEDERATION_PROTOCOL_VERSION) {
throw new BadRequestException(
`Incompatible protocol version. Expected ${FEDERATION_PROTOCOL_VERSION}, received ${remoteVersion}`
);
}
}
}