fix(auth): strip line breaks from pasted keys

This commit is contained in:
Peter Steinberger
2026-02-09 11:25:54 -06:00
parent fb8c653f53
commit 42a07791c4
15 changed files with 293 additions and 30 deletions

View File

@@ -4,6 +4,7 @@ import type { AnyAgentTool } from "./common.js";
import { fetchWithSsrFGuard } from "../../infra/net/fetch-guard.js";
import { SsrFBlockedError } from "../../infra/net/ssrf.js";
import { wrapExternalContent, wrapWebContent } from "../../security/external-content.js";
import { normalizeSecretInput } from "../../utils/normalize-secret-input.js";
import { stringEnum } from "../schema/typebox.js";
import { jsonResult, readNumberParam, readStringParam } from "./common.js";
import {
@@ -120,9 +121,9 @@ function resolveFirecrawlConfig(fetch?: WebFetchConfig): FirecrawlFetchConfig {
function resolveFirecrawlApiKey(firecrawl?: FirecrawlFetchConfig): string | undefined {
const fromConfig =
firecrawl && "apiKey" in firecrawl && typeof firecrawl.apiKey === "string"
? firecrawl.apiKey.trim()
? normalizeSecretInput(firecrawl.apiKey)
: "";
const fromEnv = (process.env.FIRECRAWL_API_KEY ?? "").trim();
const fromEnv = normalizeSecretInput(process.env.FIRECRAWL_API_KEY);
return fromConfig || fromEnv || undefined;
}

View File

@@ -81,8 +81,18 @@ describe("web_search grok config resolution", () => {
});
it("returns undefined when no apiKey is available", () => {
expect(resolveGrokApiKey({})).toBeUndefined();
expect(resolveGrokApiKey(undefined)).toBeUndefined();
const previous = process.env.XAI_API_KEY;
try {
delete process.env.XAI_API_KEY;
expect(resolveGrokApiKey({})).toBeUndefined();
expect(resolveGrokApiKey(undefined)).toBeUndefined();
} finally {
if (previous === undefined) {
delete process.env.XAI_API_KEY;
} else {
process.env.XAI_API_KEY = previous;
}
}
});
it("uses default model when not specified", () => {

View File

@@ -3,6 +3,7 @@ import type { OpenClawConfig } from "../../config/config.js";
import type { AnyAgentTool } from "./common.js";
import { formatCliCommand } from "../../cli/command-format.js";
import { wrapWebContent } from "../../security/external-content.js";
import { normalizeSecretInput } from "../../utils/normalize-secret-input.js";
import { jsonResult, readNumberParam, readStringParam } from "./common.js";
import {
CacheEntry,
@@ -142,8 +143,10 @@ function resolveSearchEnabled(params: { search?: WebSearchConfig; sandboxed?: bo
function resolveSearchApiKey(search?: WebSearchConfig): string | undefined {
const fromConfig =
search && "apiKey" in search && typeof search.apiKey === "string" ? search.apiKey.trim() : "";
const fromEnv = (process.env.BRAVE_API_KEY ?? "").trim();
search && "apiKey" in search && typeof search.apiKey === "string"
? normalizeSecretInput(search.apiKey)
: "";
const fromEnv = normalizeSecretInput(process.env.BRAVE_API_KEY);
return fromConfig || fromEnv || undefined;
}
@@ -222,7 +225,7 @@ function resolvePerplexityApiKey(perplexity?: PerplexityConfig): {
}
function normalizeApiKey(key: unknown): string {
return typeof key === "string" ? key.trim() : "";
return normalizeSecretInput(key);
}
function inferPerplexityBaseUrlFromApiKey(apiKey?: string): PerplexityBaseUrlHint | undefined {