@openclaw/bluebubbles 2026.2.9 → 2026.2.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/bluebubbles",
3
- "version": "2026.2.9",
3
+ "version": "2026.2.12",
4
4
  "description": "OpenClaw BlueBubbles channel plugin",
5
5
  "type": "module",
6
6
  "devDependencies": {
@@ -254,9 +254,20 @@ function createMockRequest(
254
254
  body: unknown,
255
255
  headers: Record<string, string> = {},
256
256
  ): IncomingMessage {
257
+ const parsedUrl = new URL(url, "http://localhost");
258
+ const hasAuthQuery = parsedUrl.searchParams.has("guid") || parsedUrl.searchParams.has("password");
259
+ const hasAuthHeader =
260
+ headers["x-guid"] !== undefined ||
261
+ headers["x-password"] !== undefined ||
262
+ headers["x-bluebubbles-guid"] !== undefined ||
263
+ headers.authorization !== undefined;
264
+ if (!hasAuthQuery && !hasAuthHeader) {
265
+ parsedUrl.searchParams.set("password", "test-password");
266
+ }
267
+
257
268
  const req = new EventEmitter() as IncomingMessage;
258
269
  req.method = method;
259
- req.url = url;
270
+ req.url = `${parsedUrl.pathname}${parsedUrl.search}`;
260
271
  req.headers = headers;
261
272
  (req as unknown as { socket: { remoteAddress: string } }).socket = { remoteAddress: "127.0.0.1" };
262
273
 
@@ -546,40 +557,41 @@ describe("BlueBubbles webhook monitor", () => {
546
557
  expect(res.statusCode).toBe(401);
547
558
  });
548
559
 
549
- it("allows localhost requests without authentication", async () => {
560
+ it("requires authentication for loopback requests when password is configured", async () => {
550
561
  const account = createMockAccount({ password: "secret-token" });
551
562
  const config: OpenClawConfig = {};
552
563
  const core = createMockRuntime();
553
564
  setBlueBubblesRuntime(core);
565
+ for (const remoteAddress of ["127.0.0.1", "::1", "::ffff:127.0.0.1"]) {
566
+ const req = createMockRequest("POST", "/bluebubbles-webhook", {
567
+ type: "new-message",
568
+ data: {
569
+ text: "hello",
570
+ handle: { address: "+15551234567" },
571
+ isGroup: false,
572
+ isFromMe: false,
573
+ guid: "msg-1",
574
+ },
575
+ });
576
+ (req as unknown as { socket: { remoteAddress: string } }).socket = {
577
+ remoteAddress,
578
+ };
554
579
 
555
- const req = createMockRequest("POST", "/bluebubbles-webhook", {
556
- type: "new-message",
557
- data: {
558
- text: "hello",
559
- handle: { address: "+15551234567" },
560
- isGroup: false,
561
- isFromMe: false,
562
- guid: "msg-1",
563
- },
564
- });
565
- // Localhost address
566
- (req as unknown as { socket: { remoteAddress: string } }).socket = {
567
- remoteAddress: "127.0.0.1",
568
- };
569
-
570
- unregister = registerBlueBubblesWebhookTarget({
571
- account,
572
- config,
573
- runtime: { log: vi.fn(), error: vi.fn() },
574
- core,
575
- path: "/bluebubbles-webhook",
576
- });
580
+ const loopbackUnregister = registerBlueBubblesWebhookTarget({
581
+ account,
582
+ config,
583
+ runtime: { log: vi.fn(), error: vi.fn() },
584
+ core,
585
+ path: "/bluebubbles-webhook",
586
+ });
577
587
 
578
- const res = createMockResponse();
579
- const handled = await handleBlueBubblesWebhookRequest(req, res);
588
+ const res = createMockResponse();
589
+ const handled = await handleBlueBubblesWebhookRequest(req, res);
590
+ expect(handled).toBe(true);
591
+ expect(res.statusCode).toBe(401);
580
592
 
581
- expect(handled).toBe(true);
582
- expect(res.statusCode).toBe(200);
593
+ loopbackUnregister();
594
+ }
583
595
  });
584
596
 
585
597
  it("ignores unregistered webhook paths", async () => {
package/src/monitor.ts CHANGED
@@ -1533,10 +1533,6 @@ export async function handleBlueBubblesWebhookRequest(
1533
1533
  if (guid && guid.trim() === token) {
1534
1534
  return true;
1535
1535
  }
1536
- const remote = req.socket?.remoteAddress ?? "";
1537
- if (remote === "127.0.0.1" || remote === "::1" || remote === "::ffff:127.0.0.1") {
1538
- return true;
1539
- }
1540
1536
  return false;
1541
1537
  });
1542
1538