Revert claude.ai/code to blanket skip
Drops the narrow field-based walker. Matching only known user-input fields is brittle: the moment Anthropic renames prompt/input/messages the walker silently stops substituting and real data leaks. Preferring robustness over convenience here — the extension stays dormant on claude.ai/code regardless of future API shape changes, and users handle redaction manually on that one app. The word-boundary mapping fix from the previous commit is unaffected. https://claude.ai/code/session_01Y2YprLMx348eWD5C9Z4zpV
This commit is contained in:
+9
-86
@@ -754,74 +754,6 @@
|
||||
return { modified, replacements: allReplacements };
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Claude Code (claude.ai/code) — narrow walker
|
||||
//
|
||||
// The web Claude Code app streams tool-call traffic (file paths, shell
|
||||
// commands, GitHub URLs) through the same API as user messages. Deep-walking
|
||||
// every string corrupts that traffic and makes tools fail. Instead we only
|
||||
// substitute at paths that carry user-typed input:
|
||||
// - top-level `prompt` (classic claude.ai chat field)
|
||||
// - `attachments[].extracted_content` and `.file_name` (pasted content)
|
||||
// - `messages[].content` / content parts where role === 'user'
|
||||
// Anything outside these paths — tool_use, tool_result, system, tools,
|
||||
// metadata, IDs — passes through untouched.
|
||||
// ============================================================
|
||||
function isClaudeCode() {
|
||||
return location.hostname === 'claude.ai' && /^\/code(\/|$)/.test(location.pathname);
|
||||
}
|
||||
|
||||
function processBodyClaudeCode(body) {
|
||||
let modified = false;
|
||||
const allReplacements = [];
|
||||
|
||||
function processString(s) {
|
||||
if (typeof s !== 'string' || s.length < MIN_STRING_LENGTH) return s;
|
||||
const r = substituteAll(s);
|
||||
if (r.modified) {
|
||||
allReplacements.push(...r.replacements);
|
||||
modified = true;
|
||||
return r.text;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
if (body && typeof body === 'object') {
|
||||
if (typeof body.prompt === 'string') body.prompt = processString(body.prompt);
|
||||
if (typeof body.input === 'string') body.input = processString(body.input);
|
||||
|
||||
if (Array.isArray(body.attachments)) {
|
||||
for (const att of body.attachments) {
|
||||
if (!att || typeof att !== 'object') continue;
|
||||
if (typeof att.extracted_content === 'string') {
|
||||
att.extracted_content = processString(att.extracted_content);
|
||||
}
|
||||
if (typeof att.file_name === 'string') {
|
||||
att.file_name = processString(att.file_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(body.messages)) {
|
||||
for (const msg of body.messages) {
|
||||
if (!msg || msg.role !== 'user') continue;
|
||||
if (typeof msg.content === 'string') {
|
||||
msg.content = processString(msg.content);
|
||||
} else if (Array.isArray(msg.content)) {
|
||||
for (const part of msg.content) {
|
||||
// Only text parts — never tool_use / tool_result / image payloads
|
||||
if (part?.type === 'text' && typeof part.text === 'string') {
|
||||
part.text = processString(part.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { modified, replacements: allReplacements };
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Check if we have anything to substitute
|
||||
// ============================================================
|
||||
@@ -947,9 +879,7 @@
|
||||
try {
|
||||
// Try JSON
|
||||
const body = JSON.parse(options.body);
|
||||
const { modified, replacements } = isClaudeCode()
|
||||
? processBodyClaudeCode(body)
|
||||
: processBody(body);
|
||||
const { modified, replacements } = processBody(body);
|
||||
|
||||
if (modified) {
|
||||
options = { ...options, body: JSON.stringify(body) };
|
||||
@@ -959,10 +889,8 @@
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
// Not JSON — try raw string substitution (form data, etc.).
|
||||
// Skip on claude.ai/code: raw bodies there are typically tool
|
||||
// traffic, not user input.
|
||||
if (options.body.length > MIN_STRING_LENGTH && !isClaudeCode()) {
|
||||
// Not JSON — try raw string substitution (form data, etc.)
|
||||
if (options.body.length > MIN_STRING_LENGTH) {
|
||||
const result = substituteAll(options.body);
|
||||
if (result.modified) {
|
||||
options = { ...options, body: result.text };
|
||||
@@ -1016,22 +944,17 @@
|
||||
) {
|
||||
try {
|
||||
const parsed = JSON.parse(body);
|
||||
const { modified, replacements } = isClaudeCode()
|
||||
? processBodyClaudeCode(parsed)
|
||||
: processBody(parsed);
|
||||
const { modified, replacements } = processBody(parsed);
|
||||
if (modified) {
|
||||
body = JSON.stringify(parsed);
|
||||
notifySubstitutions(replacements);
|
||||
}
|
||||
} catch (e) {
|
||||
// Not JSON — raw string. Skip on claude.ai/code; raw bodies there
|
||||
// are typically tool traffic, not user input.
|
||||
if (!isClaudeCode()) {
|
||||
const result = substituteAll(body);
|
||||
if (result.modified) {
|
||||
body = result.text;
|
||||
notifySubstitutions(result.replacements);
|
||||
}
|
||||
// Not JSON — raw string
|
||||
const result = substituteAll(body);
|
||||
if (result.modified) {
|
||||
body = result.text;
|
||||
notifySubstitutions(result.replacements);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,19 @@
|
||||
* because sites like claude.ai have strict CSP that blocks inline scripts.
|
||||
*/
|
||||
(function () {
|
||||
// Claude Code (claude.ai/code) streams real file paths, shell commands, and
|
||||
// tool-call traffic through the same HTTP surface as user messages. Any
|
||||
// substitution there corrupts tool execution. We deliberately stay out of
|
||||
// it entirely so the extension stays robust to API shape changes — the user
|
||||
// handles redaction manually on this one app.
|
||||
if (
|
||||
location.hostname === 'claude.ai' &&
|
||||
/^\/code(\/|$)/.test(location.pathname)
|
||||
) {
|
||||
window.__ssSkipHost = true;
|
||||
return;
|
||||
}
|
||||
|
||||
window.__ssOriginalFetch = window.fetch;
|
||||
window.__ssOriginalXHROpen = XMLHttpRequest.prototype.open;
|
||||
window.__ssOriginalXHRSend = XMLHttpRequest.prototype.send;
|
||||
|
||||
@@ -15,6 +15,17 @@
|
||||
if (window.__silentSendInjected) return;
|
||||
window.__silentSendInjected = true;
|
||||
|
||||
// Skip Claude Code (web) entirely. Its tool-call traffic shares the HTTP
|
||||
// surface with user messages; any selective walker becomes brittle the
|
||||
// moment Anthropic changes a field name. Leaving the app untouched is the
|
||||
// robust choice — the user handles redaction manually here.
|
||||
if (
|
||||
location.hostname === 'claude.ai' &&
|
||||
/^\/code(\/|$)/.test(location.pathname)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Merge active profiles into flat identity object
|
||||
function mergeProfiles(data) {
|
||||
const profiles = data?.profiles || [];
|
||||
|
||||
Reference in New Issue
Block a user