5a9b5b4510
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
43 lines
2.6 KiB
JavaScript
43 lines
2.6 KiB
JavaScript
#!/usr/bin/env node
|
|
/** url-whitelist-rules — дом сборки project-URL-whitelist паттернов (config-seam).
|
|
* База неизменна; проектные домены приходят списком; пусто = fail-CLOSED. Чистый. */
|
|
|
|
export const DEFAULT_PROJECT_URL_WHITELIST = Object.freeze(['liderra.ru', 'github.com/liderra']);
|
|
export const BASE_NAVIGATE_HOSTS = Object.freeze(['localhost', '127.0.0.1']);
|
|
export const BASE_WEBFETCH_WHITELIST_PATTERNS = Object.freeze([
|
|
'^https?://docs\\.anthropic\\.com/',
|
|
'^https?://github\\.com/(?:anthropics|deck|deck-platform)/',
|
|
'^https?://(?:www\\.)?npmjs\\.com/package/',
|
|
'^https?://stackoverflow\\.com/questions/',
|
|
]);
|
|
export const WEBFETCH_SCHEME_BLOCK_PATTERNS = Object.freeze(['^data:', '^javascript:']);
|
|
export const BASE_COMMIT_MSG_FRAGS = Object.freeze([
|
|
'github\\.com/(?:deck|deck-platform)', 'api\\.anthropic\\.com', 'docs\\.anthropic\\.com',
|
|
]);
|
|
|
|
/** Экранировать regex-спецсимволы; `/` не трогаем (литеральный разделитель пути). */
|
|
export function escapeDomain(d) {
|
|
return String(d).replace(/[.+^${}()|[\]\\?*]/g, '\\$&');
|
|
}
|
|
function hostOnly(domains) {
|
|
return (domains || []).filter((d) => typeof d === 'string' && d && !d.includes('/'));
|
|
}
|
|
/** navigate: один host-альтернация-паттерн с границей (?:[:/?#]|$); возврат — одноэлементный массив. */
|
|
export function buildNavigateWhitelistPatterns(projectDomains) {
|
|
const hosts = [...BASE_NAVIGATE_HOSTS, ...hostOnly(projectDomains)];
|
|
return ['^https?://(?:' + hosts.map(escapeDomain).join('|') + ')(?:[:/?#]|$)'];
|
|
}
|
|
/** WebFetch: база + на каждый проектный домен `^https?://<d>/`. */
|
|
export function buildWebFetchWhitelistPatterns(projectDomains) {
|
|
const proj = (projectDomains || []).filter((d) => typeof d === 'string' && d);
|
|
return [...BASE_WEBFETCH_WHITELIST_PATTERNS, ...proj.map((d) => '^https?://' + escapeDomain(d) + '/')];
|
|
}
|
|
/** commit-message negative-lookahead: блок URL, чей домен НЕ из (база ∪ проект). */
|
|
export function buildCommitMessageUrlPattern(projectDomains) {
|
|
const proj = (projectDomains || []).filter((d) => typeof d === 'string' && d);
|
|
const frags = [...BASE_COMMIT_MSG_FRAGS, ...proj.map(escapeDomain)];
|
|
// Host-terminator (?:[:/?#]|$) after the allowlist alternation closes subdomain-suffix
|
|
// spoofs (liderra.ru.evil.com / github.com/liderra-evil); mirrors buildNavigateWhitelistPatterns.
|
|
return new RegExp('\\bhttps?:\\/\\/(?!(?:' + frags.join('|') + ')(?:[:/?#]|$))\\S+', 'i');
|
|
}
|