mirror of
https://github.com/tiennm99/ccs.git
synced 2026-09-03 06:18:55 +00:00
fix(cliproxy): harden oauth trace snippet redaction
This commit is contained in:
@@ -53,12 +53,21 @@ describe('redactString', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('redacts JSON-style token payloads in plain strings', () => {
|
test('redacts JSON-style token payloads in plain strings', () => {
|
||||||
const out = redactString('{"access_token":"AT_SECRET","refresh_token":"RT_SECRET"}');
|
const out = redactString(
|
||||||
|
'{"access_token":"AT_SECRET","refresh_token":"RT_SECRET","token":"TOKEN_SECRET"}'
|
||||||
|
);
|
||||||
expect(out).not.toContain('AT_SECRET');
|
expect(out).not.toContain('AT_SECRET');
|
||||||
expect(out).not.toContain('RT_SECRET');
|
expect(out).not.toContain('RT_SECRET');
|
||||||
|
expect(out).not.toContain('TOKEN_SECRET');
|
||||||
expect(out).toContain(REDACTED_PLACEHOLDER);
|
expect(out).toContain(REDACTED_PLACEHOLDER);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('preserves JSON-style separator spacing while redacting token payloads', () => {
|
||||||
|
const out = redactString('{"access_token" : "AT_SECRET"}');
|
||||||
|
expect(out).not.toContain('AT_SECRET');
|
||||||
|
expect(out).toContain(`"access_token" : "${REDACTED_PLACEHOLDER}"`);
|
||||||
|
});
|
||||||
|
|
||||||
test('redacts line-leading key/value formats', () => {
|
test('redacts line-leading key/value formats', () => {
|
||||||
const out = redactString(
|
const out = redactString(
|
||||||
'access_token=AT_SECRET refresh_token=RT_SECRET client_secret: CS_SECRET'
|
'access_token=AT_SECRET refresh_token=RT_SECRET client_secret: CS_SECRET'
|
||||||
@@ -68,7 +77,13 @@ describe('redactString', () => {
|
|||||||
expect(out).not.toContain('CS_SECRET');
|
expect(out).not.toContain('CS_SECRET');
|
||||||
expect(out).toContain(`access_token=${REDACTED_PLACEHOLDER}`);
|
expect(out).toContain(`access_token=${REDACTED_PLACEHOLDER}`);
|
||||||
expect(out).toContain(`refresh_token=${REDACTED_PLACEHOLDER}`);
|
expect(out).toContain(`refresh_token=${REDACTED_PLACEHOLDER}`);
|
||||||
expect(out).toContain(`client_secret=${REDACTED_PLACEHOLDER}`);
|
expect(out).toContain(`client_secret: ${REDACTED_PLACEHOLDER}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('preserves URL-style suffixes in line-leading key/value snippets', () => {
|
||||||
|
const out = redactString('access_token=AT_SECRET&keep=1');
|
||||||
|
expect(out).not.toContain('AT_SECRET');
|
||||||
|
expect(out).toBe(`access_token=${REDACTED_PLACEHOLDER}&keep=1`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -41,15 +41,15 @@ const QUERY_PARAM_REGEX = new RegExp(
|
|||||||
const BEARER_REGEX = /Bearer\s+[A-Za-z0-9._\-~+/=]+/gi;
|
const BEARER_REGEX = /Bearer\s+[A-Za-z0-9._\-~+/=]+/gi;
|
||||||
|
|
||||||
const KV_SEPARATORS = String.raw`(?:=|:)`;
|
const KV_SEPARATORS = String.raw`(?:=|:)`;
|
||||||
const VALUE_FRAGMENT = String.raw`[^\s,;\]}\"']+`;
|
const VALUE_FRAGMENT = String.raw`[^\s,;&\]}\"']+`;
|
||||||
const STRING_KV_KEYS = SENSITIVE_QUERY_KEYS.filter((key) => key !== 'authorization');
|
const STRING_KV_KEYS = [...SENSITIVE_QUERY_KEYS, 'token'].filter((key) => key !== 'authorization');
|
||||||
const SENSITIVE_KEY_GROUP = `(${STRING_KV_KEYS.join('|')})`;
|
const SENSITIVE_KEY_GROUP = `(${STRING_KV_KEYS.join('|')})`;
|
||||||
const LEADING_KV_REGEX = new RegExp(
|
const LEADING_KV_REGEX = new RegExp(
|
||||||
String.raw`(^|\s)${SENSITIVE_KEY_GROUP}\s*${KV_SEPARATORS}\s*${VALUE_FRAGMENT}`,
|
String.raw`(^|\s)${SENSITIVE_KEY_GROUP}(\s*${KV_SEPARATORS}\s*)${VALUE_FRAGMENT}`,
|
||||||
'gi'
|
'gi'
|
||||||
);
|
);
|
||||||
const QUOTED_JSON_KV_REGEX = new RegExp(
|
const QUOTED_JSON_KV_REGEX = new RegExp(
|
||||||
String.raw`([\"'])${SENSITIVE_KEY_GROUP}\1\s*:\s*([\"'])[^\\]*?\3`,
|
String.raw`([\"'])${SENSITIVE_KEY_GROUP}\1(\s*:\s*)([\"'])(?:\\.|(?!\4).)*?\4`,
|
||||||
'gi'
|
'gi'
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -61,10 +61,13 @@ export function redactString(s: string): string {
|
|||||||
.replace(BEARER_REGEX, `Bearer ${REDACTED}`)
|
.replace(BEARER_REGEX, `Bearer ${REDACTED}`)
|
||||||
.replace(
|
.replace(
|
||||||
QUOTED_JSON_KV_REGEX,
|
QUOTED_JSON_KV_REGEX,
|
||||||
(_full, quoteKey, key, quoteVal) =>
|
(_full, quoteKey, key, separator, quoteVal) =>
|
||||||
`${quoteKey}${key}${quoteKey}:${quoteVal}${REDACTED}${quoteVal}`
|
`${quoteKey}${key}${quoteKey}${separator}${quoteVal}${REDACTED}${quoteVal}`
|
||||||
)
|
)
|
||||||
.replace(LEADING_KV_REGEX, (_full, prefix, key) => `${prefix}${key}=${REDACTED}`);
|
.replace(
|
||||||
|
LEADING_KV_REGEX,
|
||||||
|
(_full, prefix, key, separator) => `${prefix}${key}${separator}${REDACTED}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Redact a parsed URL by name; returns redacted href or original on parse error. */
|
/** Redact a parsed URL by name; returns redacted href or original on parse error. */
|
||||||
|
|||||||
@@ -524,8 +524,9 @@ export async function preflightCheck(provider: CLIProxyProvider): Promise<Prefli
|
|||||||
return { proceed: true, accountId: defaultAccount?.id || '' };
|
return { proceed: true, accountId: defaultAccount?.id || '' };
|
||||||
}
|
}
|
||||||
|
|
||||||
const { pauseAccountForQuotaCooldown, restoreExpiredQuotaPauses } =
|
const { pauseAccountForQuotaCooldown, restoreExpiredQuotaPauses } = await import(
|
||||||
await import('../accounts/account-safety');
|
'../accounts/account-safety'
|
||||||
|
);
|
||||||
restoreExpiredQuotaPauses();
|
restoreExpiredQuotaPauses();
|
||||||
|
|
||||||
const config = loadOrCreateUnifiedConfig();
|
const config = loadOrCreateUnifiedConfig();
|
||||||
|
|||||||
@@ -112,8 +112,9 @@ export async function runImageAnalysisCheck(results: HealthCheck): Promise<void>
|
|||||||
* Fix image analysis configuration issues
|
* Fix image analysis configuration issues
|
||||||
*/
|
*/
|
||||||
export async function fixImageAnalysisConfig(): Promise<boolean> {
|
export async function fixImageAnalysisConfig(): Promise<boolean> {
|
||||||
const { updateConfig, loadOrCreateUnifiedConfig } =
|
const { updateConfig, loadOrCreateUnifiedConfig } = await import(
|
||||||
await import('../../config/config-loader-facade');
|
'../../config/config-loader-facade'
|
||||||
|
);
|
||||||
|
|
||||||
const config = loadOrCreateUnifiedConfig();
|
const config = loadOrCreateUnifiedConfig();
|
||||||
let fixed = false;
|
let fixed = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user