mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-10 00:31:22 +00:00
fix: harden synology chat TLS helper defaults
This commit is contained in:
@@ -93,6 +93,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Device pairing: reject rotating device tokens into roles that were never approved during pairing, and keep reconnect role checks bounded to the paired device's approved role set. (#60462) Thanks @eleqtrizit.
|
||||
- Mobile pairing/security: fail closed for internal `/pair` setup-code issuance, cleanup, and approval paths when gateway pairing scopes are missing, and keep approval-time requested-scope enforcement on the internal command path. (#55996) Thanks @coygeek.
|
||||
- Exec approvals/node host: forward prepared `system.run` approval plans on the async node invoke path so mutable script operands keep their approval-time binding and drift revalidation instead of dropping back to unbound execution.
|
||||
- Synology Chat/security: default low-level HTTPS helper TLS verification to on so helper/API defaults match the shipped safe account default, and only explicit `allowInsecureSsl: true` opts out.
|
||||
|
||||
## 2026.4.2
|
||||
|
||||
|
||||
@@ -94,6 +94,20 @@ describe("sendMessage", () => {
|
||||
const callArgs = httpsRequest.mock.calls[0];
|
||||
expect(callArgs[0]).toBe("https://nas.example.com/incoming");
|
||||
});
|
||||
|
||||
it("verifies TLS by default", async () => {
|
||||
mockSuccessResponse();
|
||||
await settleTimers(sendMessage("https://nas.example.com/incoming", "Hello"));
|
||||
const httpsRequest = vi.mocked(https.request);
|
||||
expect(httpsRequest.mock.calls[0]?.[1]).toMatchObject({ rejectUnauthorized: true });
|
||||
});
|
||||
|
||||
it("only disables TLS verification when explicitly requested", async () => {
|
||||
mockSuccessResponse();
|
||||
await settleTimers(sendMessage("https://nas.example.com/incoming", "Hello", undefined, true));
|
||||
const httpsRequest = vi.mocked(https.request);
|
||||
expect(httpsRequest.mock.calls[0]?.[1]).toMatchObject({ rejectUnauthorized: false });
|
||||
});
|
||||
});
|
||||
|
||||
describe("sendFileUrl", () => {
|
||||
@@ -114,6 +128,15 @@ describe("sendFileUrl", () => {
|
||||
);
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it("verifies TLS by default", async () => {
|
||||
mockSuccessResponse();
|
||||
await settleTimers(
|
||||
sendFileUrl("https://nas.example.com/incoming", "https://example.com/file.png"),
|
||||
);
|
||||
const httpsRequest = vi.mocked(https.request);
|
||||
expect(httpsRequest.mock.calls[0]?.[1]).toMatchObject({ rejectUnauthorized: true });
|
||||
});
|
||||
});
|
||||
|
||||
// Helper to mock the user_list API response for fetchChatUsers / resolveLegacyWebhookNameToChatUserId
|
||||
@@ -293,4 +316,15 @@ describe("fetchChatUsers", () => {
|
||||
|
||||
expect(users).toEqual([{ user_id: 4, username: "jmn67", nickname: "jmn" }]);
|
||||
});
|
||||
|
||||
it("verifies TLS by default for user_list lookups", async () => {
|
||||
mockUserListResponse([{ user_id: 4, username: "jmn67", nickname: "jmn" }]);
|
||||
const freshUrl =
|
||||
"https://fresh-nas.example.com/webapi/entry.cgi?api=SYNO.Chat.External&method=chatbot&version=2&token=%22fresh%22";
|
||||
|
||||
await fetchChatUsers(freshUrl);
|
||||
|
||||
const httpsGet = vi.mocked((https as any).get);
|
||||
expect(httpsGet.mock.calls[0]?.[1]).toMatchObject({ rejectUnauthorized: true });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -82,7 +82,7 @@ export async function sendMessage(
|
||||
incomingUrl: string,
|
||||
text: string,
|
||||
userId?: string | number,
|
||||
allowInsecureSsl = true,
|
||||
allowInsecureSsl = false,
|
||||
): Promise<boolean> {
|
||||
// Synology Chat API requires user_ids (numeric) to specify the recipient
|
||||
// The @mention is optional but user_ids is mandatory
|
||||
@@ -123,7 +123,7 @@ export async function sendFileUrl(
|
||||
incomingUrl: string,
|
||||
fileUrl: string,
|
||||
userId?: string | number,
|
||||
allowInsecureSsl = true,
|
||||
allowInsecureSsl = false,
|
||||
): Promise<boolean> {
|
||||
const body = buildWebhookBody({ file_url: fileUrl }, userId);
|
||||
|
||||
@@ -145,7 +145,7 @@ export async function sendFileUrl(
|
||||
*/
|
||||
export async function fetchChatUsers(
|
||||
incomingUrl: string,
|
||||
allowInsecureSsl = true,
|
||||
allowInsecureSsl = false,
|
||||
log?: { warn: (...args: unknown[]) => void },
|
||||
): Promise<ChatUser[]> {
|
||||
const now = Date.now();
|
||||
@@ -246,7 +246,7 @@ function parseNumericUserId(userId?: string | number): number | undefined {
|
||||
return Number.isNaN(numericId) ? undefined : numericId;
|
||||
}
|
||||
|
||||
function doPost(url: string, body: string, allowInsecureSsl = true): Promise<boolean> {
|
||||
function doPost(url: string, body: string, allowInsecureSsl = false): Promise<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
let parsedUrl: URL;
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user