Skip to content

Commit 4138d7c

Browse files
steipetePandah97
andcommitted
test(mattermost): cover UTF-16-safe slash logs
Co-authored-by: 黄剑雄0668001315 <[email protected]>
1 parent 68b5c8a commit 4138d7c

2 files changed

Lines changed: 59 additions & 29 deletions

File tree

extensions/mattermost/src/mattermost/slash-http.test.ts

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -713,8 +713,9 @@ describe("slash-http", () => {
713713

714714
it("logs when command lookup by id returns a deleted command before fallback", async () => {
715715
const registeredCommand = createRegisteredCommand();
716+
const commandId = `${"i".repeat(199)}😀tail`;
716717
const command = {
717-
id: "cmd-1\r\nspoofed",
718+
id: commandId,
718719
token: "valid-token",
719720
team_id: "t1",
720721
trigger: "oc_status",
@@ -748,9 +749,9 @@ describe("slash-http", () => {
748749

749750
expect(log).toHaveBeenCalledTimes(1);
750751
const message = firstLogMessage(log);
751-
expect(message).not.toMatch(/[\r\n\t]/u);
752-
expect(message).toContain("deleted command cmd-1 spoofed");
753-
expect(message).toContain("using team list fallback");
752+
expect(message).toBe(
753+
`mattermost: slash command lookup by id returned deleted command ${"i".repeat(199)} for /oc_status; using team list fallback`,
754+
);
754755
});
755756

756757
it("rejects current commands with a mismatched method or callback URL", async () => {
@@ -923,4 +924,35 @@ describe("slash-http", () => {
923924
expect(message).not.toContain("secret-query");
924925
expect(message).not.toContain("user:pass");
925926
});
927+
928+
it("keeps upstream lookup error previews UTF-16 safe", async () => {
929+
const registeredCommand = createRegisteredCommand();
930+
const client = createCommandLookupClient({
931+
commandLookupError: new Error("primary failure"),
932+
listLookupError: new Error(`${"e".repeat(299)}😀tail`),
933+
});
934+
const log = vi.fn();
935+
936+
await expect(
937+
validateMattermostSlashCommandToken({
938+
accountId: "default",
939+
client,
940+
registeredCommand,
941+
payload: {
942+
token: "valid-token",
943+
team_id: "t1",
944+
channel_id: "c1",
945+
user_id: "u1",
946+
command: "/oc_status",
947+
text: "",
948+
},
949+
log,
950+
}),
951+
).resolves.toBe(false);
952+
953+
expect(log).toHaveBeenCalledTimes(1);
954+
expect(firstLogMessage(log)).toBe(
955+
`mattermost: slash command registration check failed for /oc_status: ${"e".repeat(299)}; command lookup: primary failure`,
956+
);
957+
});
926958
});

extensions/mattermost/src/mattermost/slash-http.ts

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -143,33 +143,31 @@ function isDeletedMattermostCommand(command: { delete_at?: number }): boolean {
143143

144144
function sanitizeCommandLookupError(error: unknown): string {
145145
const raw = error instanceof Error ? error.message : String(error);
146-
return truncateUtf16Safe(
147-
raw
148-
.replace(/[\r\n\t]/gu, " ")
149-
.replace(/https?:\/\/[^\s)\]}]+/giu, (urlText) => {
150-
try {
151-
const url = new URL(urlText);
152-
if (url.username || url.password) {
153-
url.username = "redacted";
154-
url.password = "redacted";
155-
}
156-
for (const key of url.searchParams.keys()) {
157-
if (SECRET_LOG_KEYS.has(key.toLowerCase())) {
158-
url.searchParams.set(key, "redacted");
159-
}
146+
const sanitized = raw
147+
.replace(/[\r\n\t]/gu, " ")
148+
.replace(/https?:\/\/[^\s)\]}]+/giu, (urlText) => {
149+
try {
150+
const url = new URL(urlText);
151+
if (url.username || url.password) {
152+
url.username = "redacted";
153+
url.password = "redacted";
154+
}
155+
for (const key of url.searchParams.keys()) {
156+
if (SECRET_LOG_KEYS.has(key.toLowerCase())) {
157+
url.searchParams.set(key, "redacted");
160158
}
161-
return url.toString();
162-
} catch {
163-
return urlText;
164159
}
165-
})
166-
.replace(/(^|[^\w-])(Bearer|Token)\s+[A-Za-z0-9._~+/=-]+/giu, "$1$2 [redacted]")
167-
.replace(
168-
/\b(token|authorization|access_token|refresh_token|client_secret|botToken)\b(\s*["']?\s*(?:=|:)\s*["']?)[^"',\s;}]+/giu,
169-
"$1$2[redacted]",
170-
),
171-
300,
172-
);
160+
return url.toString();
161+
} catch {
162+
return urlText;
163+
}
164+
})
165+
.replace(/(^|[^\w-])(Bearer|Token)\s+[A-Za-z0-9._~+/=-]+/giu, "$1$2 [redacted]")
166+
.replace(
167+
/\b(token|authorization|access_token|refresh_token|client_secret|botToken)\b(\s*["']?\s*(?:=|:)\s*["']?)[^"',\s;}]+/giu,
168+
"$1$2[redacted]",
169+
);
170+
return truncateUtf16Safe(sanitized, 300);
173171
}
174172

175173
function sanitizeMattermostLogValue(value: string): string {

0 commit comments

Comments
 (0)