Skip to content

Commit 4e51ee9

Browse files
committed
fix(matrix): validate CLI numeric option ranges
1 parent 3643de4 commit 4e51ee9

2 files changed

Lines changed: 68 additions & 7 deletions

File tree

extensions/matrix/src/cli.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,20 @@ describe("matrix CLI verification commands", () => {
401401
expect(runMatrixSelfVerificationMock).not.toHaveBeenCalled();
402402
});
403403

404+
it("rejects non-positive Matrix self-verification timeout values", async () => {
405+
const program = buildProgram();
406+
407+
await program.parseAsync(["matrix", "verify", "self", "--timeout-ms", "-1"], {
408+
from: "user",
409+
});
410+
411+
expect(process.exitCode).toBe(1);
412+
expect(consoleErrorMock).toHaveBeenCalledWith(
413+
"Self-verification failed: --timeout-ms must be a positive integer",
414+
);
415+
expect(runMatrixSelfVerificationMock).not.toHaveBeenCalled();
416+
});
417+
404418
it("requests Matrix self-verification and prints the follow-up SAS commands", async () => {
405419
requestMatrixVerificationMock.mockResolvedValue(
406420
mockMatrixVerificationSummary({
@@ -1076,6 +1090,34 @@ describe("matrix CLI verification commands", () => {
10761090
);
10771091
});
10781092

1093+
it("rejects negative Matrix initial sync limits at the CLI boundary", async () => {
1094+
const program = buildProgram();
1095+
1096+
await program.parseAsync(
1097+
[
1098+
"matrix",
1099+
"account",
1100+
"add",
1101+
"--homeserver",
1102+
"https://matrix.example.org",
1103+
"--user-id",
1104+
"@ops:example.org",
1105+
"--password",
1106+
"secret",
1107+
"--initial-sync-limit",
1108+
"-1",
1109+
],
1110+
{ from: "user" },
1111+
);
1112+
1113+
expect(process.exitCode).toBe(1);
1114+
expect(consoleErrorMock).toHaveBeenCalledWith(
1115+
"Account setup failed: --initial-sync-limit must be a non-negative integer",
1116+
);
1117+
expect(matrixSetupValidateInputMock).not.toHaveBeenCalled();
1118+
expect(matrixRuntimeReplaceConfigFileMock).not.toHaveBeenCalled();
1119+
});
1120+
10791121
it("enables E2EE and bootstraps verification from matrix account add", async () => {
10801122
matrixRuntimeLoadConfigMock.mockReturnValue({ channels: {} });
10811123
matrixSetupApplyAccountConfigMock.mockImplementation(

extensions/matrix/src/cli.ts

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,11 @@ function configureCliLogMode(verbose: boolean): void {
232232
setMatrixSdkConsoleLogging(verbose);
233233
}
234234

235-
function parseOptionalInt(value: string | undefined, fieldName: string): number | undefined {
235+
function parseOptionalInt(
236+
value: string | undefined,
237+
fieldName: string,
238+
opts: { min?: number } = {},
239+
): number | undefined {
236240
const trimmed = value?.trim();
237241
if (!trimmed) {
238242
return undefined;
@@ -244,6 +248,13 @@ function parseOptionalInt(value: string | undefined, fieldName: string): number
244248
if (parsed === undefined) {
245249
throw new Error(`${fieldName} must be an integer`);
246250
}
251+
if (opts.min !== undefined && parsed < opts.min) {
252+
throw new Error(
253+
opts.min === 1
254+
? `${fieldName} must be a positive integer`
255+
: `${fieldName} must be a non-negative integer`,
256+
);
257+
}
247258
return parsed;
248259
}
249260

@@ -289,6 +300,9 @@ async function addMatrixAccount(params: {
289300
useEnv?: boolean;
290301
enableEncryption?: boolean;
291302
}): Promise<MatrixCliAccountAddResult> {
303+
const initialSyncLimit = parseOptionalInt(params.initialSyncLimit, "--initial-sync-limit", {
304+
min: 0,
305+
});
292306
const runtime = getMatrixRuntime();
293307
const cfg = runtime.config.current() as CoreConfig;
294308
if (!matrixSetupAdapter.applyAccountConfig) {
@@ -305,7 +319,7 @@ async function addMatrixAccount(params: {
305319
accessToken: params.accessToken,
306320
password: params.password,
307321
deviceName: params.deviceName,
308-
initialSyncLimit: parseOptionalInt(params.initialSyncLimit, "--initial-sync-limit"),
322+
initialSyncLimit,
309323
useEnv: params.useEnv === true,
310324
};
311325
const accountId =
@@ -1159,15 +1173,18 @@ async function runMatrixCliVerificationSummaryCommand(params: {
11591173
async function runMatrixCliSelfVerificationCommand(
11601174
options: MatrixCliSelfVerificationCommandOptions,
11611175
): Promise<void> {
1162-
const { accountId, cfg } = resolveMatrixCliAccountContext(options.account);
1176+
let resolvedAccountId: string | undefined;
11631177
await runMatrixCliCommand({
11641178
verbose: options.verbose === true,
11651179
json: false,
1166-
run: async () =>
1167-
await runMatrixSelfVerification({
1180+
run: async () => {
1181+
const timeoutMs = parseOptionalInt(options.timeoutMs, "--timeout-ms", { min: 1 });
1182+
const { accountId, cfg } = resolveMatrixCliAccountContext(options.account);
1183+
resolvedAccountId = accountId;
1184+
return await runMatrixSelfVerification({
11681185
accountId,
11691186
cfg,
1170-
timeoutMs: parseOptionalInt(options.timeoutMs, "--timeout-ms"),
1187+
timeoutMs,
11711188
onRequested: (summary) => {
11721189
printAccountLabel(accountId);
11731190
printMatrixVerificationSummary(summary);
@@ -1184,7 +1201,8 @@ async function runMatrixCliSelfVerificationCommand(
11841201
console.log("Compare this SAS with the other Matrix client.");
11851202
},
11861203
confirmSas: async () => await promptMatrixVerificationSasMatch(),
1187-
}),
1204+
});
1205+
},
11881206
onText: (summary, verbose) => {
11891207
printMatrixVerificationSummary(summary);
11901208
console.log(`Device verified by owner: ${summary.deviceOwnerVerified ? "yes" : "no"}`);
@@ -1196,6 +1214,7 @@ async function runMatrixCliSelfVerificationCommand(
11961214
console.log("Self-verification complete.");
11971215
},
11981216
onTextError: () => {
1217+
const accountId = resolvedAccountId ?? options.account;
11991218
printGuidance([
12001219
`Run ${formatMatrixCliCommand("verify self", accountId)} again and accept the request in another verified Matrix client for this account.`,
12011220
`Then run ${formatMatrixCliCommand("verify status --verbose", accountId)} to confirm Cross-signing verified: yes and Signed by owner: yes.`,

0 commit comments

Comments
 (0)