fix: harden bluebubbles short ids and fetch wrapper (#1369) (thanks @tyler6204)

This commit is contained in:
Peter Steinberger
2026-01-21 17:05:36 +00:00
parent c3adc50cb2
commit cd25d69b4d
10 changed files with 136 additions and 11 deletions

View File

@@ -38,6 +38,10 @@ vi.mock("./attachments.js", () => ({
sendBlueBubblesAttachment: vi.fn().mockResolvedValue({ messageId: "att-msg-123" }),
}));
vi.mock("./monitor.js", () => ({
resolveBlueBubblesMessageId: vi.fn((id: string) => id),
}));
describe("bluebubblesMessageActions", () => {
beforeEach(() => {
vi.clearAllMocks();
@@ -358,6 +362,106 @@ describe("bluebubblesMessageActions", () => {
);
});
it("uses toolContext currentChannelId when no explicit target is provided", async () => {
const { sendBlueBubblesReaction } = await import("./reactions.js");
const { resolveChatGuidForTarget } = await import("./send.js");
vi.mocked(resolveChatGuidForTarget).mockResolvedValueOnce("iMessage;-;+15550001111");
const cfg: ClawdbotConfig = {
channels: {
bluebubbles: {
serverUrl: "http://localhost:1234",
password: "test-password",
},
},
};
await bluebubblesMessageActions.handleAction({
action: "react",
params: {
emoji: "👍",
messageId: "msg-456",
},
cfg,
accountId: null,
toolContext: {
currentChannelId: "bluebubbles:chat_guid:iMessage;-;+15550001111",
},
});
expect(resolveChatGuidForTarget).toHaveBeenCalledWith(
expect.objectContaining({
target: { kind: "chat_guid", chatGuid: "iMessage;-;+15550001111" },
}),
);
expect(sendBlueBubblesReaction).toHaveBeenCalledWith(
expect.objectContaining({
chatGuid: "iMessage;-;+15550001111",
}),
);
});
it("resolves short messageId before reacting", async () => {
const { resolveBlueBubblesMessageId } = await import("./monitor.js");
const { sendBlueBubblesReaction } = await import("./reactions.js");
vi.mocked(resolveBlueBubblesMessageId).mockReturnValueOnce("resolved-uuid");
const cfg: ClawdbotConfig = {
channels: {
bluebubbles: {
serverUrl: "http://localhost:1234",
password: "test-password",
},
},
};
await bluebubblesMessageActions.handleAction({
action: "react",
params: {
emoji: "❤️",
messageId: "1",
chatGuid: "iMessage;-;+15551234567",
},
cfg,
accountId: null,
});
expect(resolveBlueBubblesMessageId).toHaveBeenCalledWith("1", { requireKnownShortId: true });
expect(sendBlueBubblesReaction).toHaveBeenCalledWith(
expect.objectContaining({
messageGuid: "resolved-uuid",
}),
);
});
it("propagates short-id errors from the resolver", async () => {
const { resolveBlueBubblesMessageId } = await import("./monitor.js");
vi.mocked(resolveBlueBubblesMessageId).mockImplementationOnce(() => {
throw new Error("short id expired");
});
const cfg: ClawdbotConfig = {
channels: {
bluebubbles: {
serverUrl: "http://localhost:1234",
password: "test-password",
},
},
};
await expect(
bluebubblesMessageActions.handleAction({
action: "react",
params: {
emoji: "❤️",
messageId: "999",
chatGuid: "iMessage;-;+15551234567",
},
cfg,
accountId: null,
}),
).rejects.toThrow("short id expired");
});
it("accepts message param for edit action", async () => {
const { editBlueBubblesMessage } = await import("./chat.js");