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 };
|
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
|
// Check if we have anything to substitute
|
||||||
// ============================================================
|
// ============================================================
|
||||||
@@ -947,9 +879,7 @@
|
|||||||
try {
|
try {
|
||||||
// Try JSON
|
// Try JSON
|
||||||
const body = JSON.parse(options.body);
|
const body = JSON.parse(options.body);
|
||||||
const { modified, replacements } = isClaudeCode()
|
const { modified, replacements } = processBody(body);
|
||||||
? processBodyClaudeCode(body)
|
|
||||||
: processBody(body);
|
|
||||||
|
|
||||||
if (modified) {
|
if (modified) {
|
||||||
options = { ...options, body: JSON.stringify(body) };
|
options = { ...options, body: JSON.stringify(body) };
|
||||||
@@ -959,10 +889,8 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Not JSON — try raw string substitution (form data, etc.).
|
// Not JSON — try raw string substitution (form data, etc.)
|
||||||
// Skip on claude.ai/code: raw bodies there are typically tool
|
if (options.body.length > MIN_STRING_LENGTH) {
|
||||||
// traffic, not user input.
|
|
||||||
if (options.body.length > MIN_STRING_LENGTH && !isClaudeCode()) {
|
|
||||||
const result = substituteAll(options.body);
|
const result = substituteAll(options.body);
|
||||||
if (result.modified) {
|
if (result.modified) {
|
||||||
options = { ...options, body: result.text };
|
options = { ...options, body: result.text };
|
||||||
@@ -1016,22 +944,17 @@
|
|||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const parsed = JSON.parse(body);
|
const parsed = JSON.parse(body);
|
||||||
const { modified, replacements } = isClaudeCode()
|
const { modified, replacements } = processBody(parsed);
|
||||||
? processBodyClaudeCode(parsed)
|
|
||||||
: processBody(parsed);
|
|
||||||
if (modified) {
|
if (modified) {
|
||||||
body = JSON.stringify(parsed);
|
body = JSON.stringify(parsed);
|
||||||
notifySubstitutions(replacements);
|
notifySubstitutions(replacements);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Not JSON — raw string. Skip on claude.ai/code; raw bodies there
|
// Not JSON — raw string
|
||||||
// are typically tool traffic, not user input.
|
const result = substituteAll(body);
|
||||||
if (!isClaudeCode()) {
|
if (result.modified) {
|
||||||
const result = substituteAll(body);
|
body = result.text;
|
||||||
if (result.modified) {
|
notifySubstitutions(result.replacements);
|
||||||
body = result.text;
|
|
||||||
notifySubstitutions(result.replacements);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,19 @@
|
|||||||
* because sites like claude.ai have strict CSP that blocks inline scripts.
|
* because sites like claude.ai have strict CSP that blocks inline scripts.
|
||||||
*/
|
*/
|
||||||
(function () {
|
(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.__ssOriginalFetch = window.fetch;
|
||||||
window.__ssOriginalXHROpen = XMLHttpRequest.prototype.open;
|
window.__ssOriginalXHROpen = XMLHttpRequest.prototype.open;
|
||||||
window.__ssOriginalXHRSend = XMLHttpRequest.prototype.send;
|
window.__ssOriginalXHRSend = XMLHttpRequest.prototype.send;
|
||||||
|
|||||||
@@ -15,6 +15,17 @@
|
|||||||
if (window.__silentSendInjected) return;
|
if (window.__silentSendInjected) return;
|
||||||
window.__silentSendInjected = true;
|
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
|
// Merge active profiles into flat identity object
|
||||||
function mergeProfiles(data) {
|
function mergeProfiles(data) {
|
||||||
const profiles = data?.profiles || [];
|
const profiles = data?.profiles || [];
|
||||||
|
|||||||
Reference in New Issue
Block a user