Reveal URLs — Arhitektūra

Šis dokuments apraksta, kā ir strukturēts Reveal URLs paplašinājums un kā darbojas tā pamatloģika, līdzstrādniekiem un tehniskiem lasītājiem. Tajā pastāvīgi ir atsauces uz reāliem failiem un simboliem formā path symbol, lai katru apgalvojumu varētu pārbaudīt pirmkodā. Lietotājam paredzētajam aprakstam skatiet manual. Manuālās pārbaudes soļiem skatiet manual test plan.

Pārskats

Reveal URLs ir viena MV3 WebExtension, kas tiek veidota Chrome, Edge, Opera, Firefox un Thunderbird no vienas kopīgas, tīras kodola bāzes. Safari ir atlikts uz vēlāku posmu: tam ir manifest un to var build-ot, ja tas tiek norādīts atsevišķi, taču tas nav iekļauts ne noklusētajā build-ā, ne CI. Paplašinājums atklāj katras saites galamērķa URL blakus pašai saitei renderētā e-pastā un iezīmē saiti, kuras redzamais teksts nosauc citu registrable domēnu nekā tas, kurš atrodas tās href.

Repozitorijs ir pnpm un TypeScript monorepo, ko raksturo pnpm-workspace.yaml un package.json, bet "private": true liedz to publiskot kā pakotni. Bundling tiek vadīts ar tooling/build.mjs, kas kompilē kopīgās pakotnes un plānos entry points katram engine ielādējamā dist/<target>/ direktorijā. webextension-polyfill tiek iepakots katrā script bundle, nevis atstāts kā runtime global.

Divi native e-pasta papildinājumi paplašina to pašu noteikšanas loģiku uz virsmām, kuras WebExtension nesasniedz: Outlook Add-in uz Office.js un Gmail Add-on uz Apps Script CardService. Abi atkārtoti izmanto tikai PURE analīzi no packages/core/src/findings.ts, ar analyseAnchors, analyseHtml, neitrālo modeli Finding[], loģiku hostMismatch un registrable domēna noteikšanu ar tldts. Atšķiras tikai host adapteris un attēlošana. Outlook izmanto DOMParser un darbojas client-side. Gmail izmanto node-html-parser un darbojas server-side Google Apps Script V8 infrastruktūrā. Tā kā neviena no šīm platformām neļauj mainīt izlasītā ziņojuma DOM, abi rāda paneli vai karti ar atradumiem, nevis inline annotation. linkProcessor.ts DOM-mutation ceļš un REVEAL_URLS_CSS tur netiek izmantoti. Relatīvs href tiek atrisināts tikai pret uzticamu <base href> pašā e-pastā un citādi tiek izlaists.

Koda bāze skaidri nošķir atbildības:

Repozitorija izkārtojums

packages/core — tīrais kodols

Neviens modulis šeit neimportē extension API kā browser.*, chrome.* vai messenger.*, un neviens neizmanto string-to-markup DOM sinks kā innerHTML vai insertAdjacentHTML. Šis noteikums tiek mehāniski nodrošināts ar packages/core/test/purity.test.ts, kas savāc src/**/*.ts, izņem komentāru saturu ar stripComments un pārbauda, ka ne EXTENSION_API_PATTERN, ne UNSAFE_DOM_PATTERN nesakrīt ar nevienu moduli. Publiskā virsma tiek reeksportēta no packages/core/src/index.ts, un vienīgā runtime atkarība ir tldts.

Galvenie moduļi ir:

packages/webext — browser API ietvari

Šie moduļi DRĪKST izmantot browser.*, un tā ir vienīgā vieta, kur tiek skartas WebExtension APIs. Publiskā virsma tiek reeksportēta no packages/webext/src/index.ts. Šeit atrodas content.ts, contentRegistration.ts, storage.ts, background.ts, toolbarAction.ts, messageDisplay.ts, messageDisplayBackground.ts un options/options.ts.

extensions/<engine> — plāni ieejas punkti un manifesti

Katrs engine nes savu manifest.json un savu icons/. Chrome, Firefox un Thunderbird papildus nes src/ direktoriju ar entry points. Edge, Opera un Safari nes tikai manifestus un ikonas un atkārtoti izmanto Chrome src/. Piemēram, extensions/chrome/src/content.ts satur tikai void createContentController().bootstrap();, bet extensions/chrome/src/background.ts izsauc registerBackground, registerContentReconciliation un registerToolbarToggle. extensions/thunderbird/src/background.ts izsauc registerBackground un registerMessageDisplay. extensions/_template ir scaffold, nevis build target.

tooling, features un smoke testi

tooling ietver build.mjs, version.mjs un icons.mjs. features ietver Gherkin scenārijus, step definitions un uzticamos doubles failos features/support/webext.ts un features/support/world.ts. Katram engine ir arī extensions/<engine>/test/manifest.smoke.test.mjs, bet _template izmanto template.smoke.test.mjs.

Atklāšanas plūsma

Content ceļš sākas engine entry pointā, piemēram, extensions/chrome/src/content.ts, kas izsauc createContentController().bootstrap() no packages/webext/src/content.ts.

Bootstrap

createContentController bootstrap tiek izpildīts reizi katram frame. Tas iegūst frame savā kontrolē pirms jebkura await ar claimBootstrap, ielādē config caur loadConfigWithRetry, injicē stylesheet ar injectStyles tikai pēc veiksmīga lasījuma un atjauno marķieri ar releaseBootstrap, ja ielāde pilnībā neizdodas. Kad config.enabled ir ieslēgts, tas izsauc start, bet jebkurā gadījumā reģistrē listeneri onConfigChanged.

Aktīvās vietnes noteikuma atrisināšana

start un applyConfig izmanto resolveSiteRule, lai izlemtu, vai un kur veikt annotation. Vispirms tiek pārbaudīta paša dokumenta atrašanās vieta ar resolveForHref, kas filtrē config.sites līdz ieslēgtajiem noteikumiem un atstāj izvēli selectMostSpecific ziņā. Ja dokuments nesakrīt un tā izcelsme ir opaque vai inherited, kā to pārbauda hasOpaqueOrigin, seko fallback ar readTopHref, readOpenerHref un readReferrer, aizsargāts pret cross-origin lasījumiem.

Ierobežošana līdz satura saknei un izmaiņu novērošana

start saglabā contentRoot, izveido annotator ar createAnnotator(config) un apstrādā katru sakni no selectRoots(doc, contentRoot), kas ietin querySelectorAll try/catch blokā, lai nederīgs selector droši pārvērstos par []. Pēc tam tas novēro doc.body ar OBSERVER_OPTIONS. processMutations filtrē katru izmaiņu pēc root, un processAddedNode aptver mezglus root iekšienē, pašu root un mezglus, kas to satur. applyConfig veic teardown, restart vai reflow atkarībā no aktīvā noteikuma un contentRoot izmaiņām.

Vienas saites marķēšana

Annotator dzīvo failā packages/core/src/linkProcessor.ts. createAnnotator atgriež Annotator ar Map, data-ru tokenu no generateToken un aktīvo config. process(root) iztīra atvienotos ierakstus, savāc a[href] elementus ar collectAnchors, atrisina URL ar resolveAnnotatableUrl, izmanto fast path isAnnotationIntact, kad renderējums nav mainījies, un aprēķina mismatch ar hostMismatch, pirms izsaukt annotateAnchor.

annotateAnchor renderē tikai SAFE-DOM. Režīmā "inline" tas pievieno <span class="reveal-urls-url"> ar textContent un <br>. Režīmā "title" tas saglabā esošo title, aizstāj to ar URL un, ja mismatch tiek uzsvērts, pievieno <span class="reveal-urls-warn"> ar REVEAL_URLS_WARN_LABEL. Izveidotie mezgli saņem data-ru="<token>", un configFingerprint tiek izmantots reflow iedarbināšanai. truncateUrl strādā pāri [...displayHref] un izmanto URL_ELLIPSIS.

Host neatbilstība

packages/core/src/hostMismatch.ts hostMismatch salīdzina saites redzamo tekstu ar tās href registrable domēna līmenī, nevis pēc neapstrādāta host. extractHostCandidates sadala tekstu tokenos un samazina tos ar hostCandidate, kas prasa punktu un tldts atpazītu public suffix. Href host un kandidāti tiek reducēti ar tldts.getDomain. Ikviens kandidāts ar atšķirīgu domēnu rada mismatch.

Stili un kontrasts

packages/core/src/styles.ts glabā REVEAL_URLS_CSS un helper-us applyColour, applyFontOverrides un applyContrastBackdrop. applyContrastBackdrop nolasa elementa aprēķināto krāsu un pirmo opaque fonu ar getComputedStyle, pēc tam izmanto needsWhiteBackdrop no packages/core/src/contrast.ts, lai izlemtu, vai uzlikt style.backgroundColor = "white". contrast.ts sniedz parseColour, relativeLuminance un contrastRatio.

Konfigurējami host un satura ierobežošana

SiteRule failā packages/core/src/config.ts nosaka, KUR annotation darbojas caur match un allFrames, un KURŠ container to ierobežo caur contentRoot, kopā ar enabled un atzīmi builtin. DEFAULT_SITES aptver Gmail, Proton ar allFrames un abus Outlook host-us. Config apvieno globālos toggles, colours, font overrides un sarakstu sites.

Match pattern mehānisms

packages/core/src/matchPattern.ts glabā restrictive gramatiku MATCH_PATTERN: tikai http un https, izvēles *. wildcard host, glob path, bez port, bez * scheme un bez <all_urls>. matchesPattern salīdzina URL ar validētu pattern un deleģē path daļu pathGlobMatches. parsePatternParts sadala pattern host, path, scheme un wildcardHost.

Kad noteikumi pārklājas, darbojas princips "most specific wins". compareSiteSpecificity sarindo exact host pirms wildcard host, pēc tam garāku literal host, pēc tam literalāku path ar literalPathLength, un beigās ASCII tiebreak. selectMostSpecific atgriež viskonkrētāko ieslēgto noteikumu, kas atbilst URL.

permissions.getAll() var ziņot grants pilnajā WebExtension gramatikā (<all_urls>, *://*/*, https://*/*, *://*.host/*, https://host/*), kurus MATCH_PATTERN noraidītu. parseGrantedOrigin pārvērš tos par GrantedOriginParts, originCovers pārbauda pārklājumu pāri match, un matchAllowsOriginFallback ziņo, vai path ir precīzi ORIGIN_FALLBACK_PATH, tas ir, /*.

Dinamiskā reģistrācija

packages/webext/src/contentRegistration.ts reģistrē vienu dynamic content script katram lietotāja pievienotam noteikumam. Built-ins tiek apkalpoti ar static content_scripts entries un nekad netiek reģistrēti dinamiski. desiredContentScripts filtrē config.sites, izmanto isOriginGranted, originCovers un contentScriptId, un iestata matchOriginAsFallback: true tikai tad, ja to atļauj matchAllowsOriginFallback(rule.match).

reconcileContentScriptsOnce nolasa piešķirtās izcelsmes, saglabāto config un live registrations un saskaņo tās ar property-aware diff. sameRegistration normalizē gan vēlamo descriptor, gan live read-back. Tā kā nav updateContentScripts, izmainīts script tiek noņemts un reģistrēts no jauna. reconcileContentScripts izmanto inFlight promise, lai serializētu trigger-us, kas var notikt tuvu viens otram.

Skaidri piešķirtas atļaujas plūsma

Static manifesti deklarē optional_host_permissions (http://*/*, https://*/*), lai lietotājs runtime laikā varētu piešķirt atļauju papildu host-am. packages/webext/src/options/options.ts addSite validē visu kandidāta rule ar normaliseSiteRule, iegūst origin ar matchOrigin un izsauc browser.permissions.request Add pogas click gesture iekšienē. Tikai pēc apstiprinājuma tiek pievienota rinda builtin:false.

Config, storage un kanoniskais modelis

Vienīgais validācijas funnel

normaliseConfig failā packages/core/src/config.ts ir vienīgais kanoniskais lasīšanas ceļš. Tas pārveido un ierobežo katru lauku, atgriežas pie noklusējuma vērtības nederīgu datu gadījumā un nekad nemet exception. Tas ir būvēts no validatoriem kā normaliseBoolean, normaliseRenderMode, normaliseMaxLength, normaliseIgnoreHosts, normaliseMatchColour, normaliseMismatchColour, normaliseCssSize, normaliseFontWeight, normaliseContentRoot, normaliseMatchPattern un normaliseSites. normaliseSites izmet nederīgus entries, noņem dublikātus pēc match, uzspiež builtin: true pārklājošiem built-in noteikumiem un atjauno trūkstošos built-ins.

Glabāšana

packages/webext/src/storage.ts aptin WebExtension storage API. configArea izmanto browser.storage.sync, ja tas ir pieejams, un pāriet uz browser.storage.local, piemēram, Thunderbird. getConfig, setConfig un onConfigChanged vienmēr laiž vērtības cauri normaliseConfig, tāpēc bojāts store nekad nevar atdot nederīgu Config. Abas add-on formas izmanto to pašu funnel virs savām host storage sistēmām.

Kanoniskais config modelis un mērķēti atjauninājumi

Trīs write path lasa kanonisko config, izmaina tieši vienu lietu un raksta to atpakaļ, nesaglabājot nepabeigtus form edits:

toggleEnabled failā packages/webext/src/toolbarAction.ts seko tam pašam modelim arī background pusē.

Build pa engine un manifesta līgums

tooling/build.mjs vada vienotu esbuild build katram WebExtension target. Descriptor TARGETS nosaka SOURCE TARGET katram target. Chrome, Firefox un Thunderbird ir savs src/. Edge, Opera un Safari izmanto chrome kā avotu. Outlook add-in ir savs avots. ACTIVE_TARGETS, tas ir, Chrome, Edge, Firefox, Opera un Thunderbird, ir tie, kas tiek build-oti ar --all un --package. Safari un Outlook tiek build-oti tikai tad, kad ir skaidri nosaukti, bet Gmail izmanto make build-gmail.

Gmail bundle mērķē Apps Script V8 runtime, kam nav ne ES modules, ne native URL. Tādēļ tas tiek build-ots kā ESM, pēc tam no tā tiek noņemts export {…}, lai trigger funkcijas paliktu globālas. Neliels URL polyfill tiek iekļauts tikai vajadzības gadījumā. buildTarget iztīra dist/<target>/, nokopē manifest.json un icons/, iesaiņo scripts kā IIFE, options lapu kā ESM un nokopē options.html un options.css.

tooling/version.mjs stamp-ē versijas. Tas paņem MAJOR.MINOR no root package.json, atrod augstāko BUILD number un pievieno to katram target manifestam. Outlook add-in nes gan manifest.json, gan manifest.xml. tooling/icons.mjs, kas darbojas ar make icons, rasterises assets/icon.svg failos icon48.png un icon128.png.

Manifesta līgums ir definēts failos extensions/<engine>/test/manifest.smoke.test.mjs, kur tiek pārbaudīta katra manifesta forma un katra referenced file esamība.

Internacionalizācija (i18n)

Reveal URLs ir lokalizēts daudzās valodās līdzās angļu valodai. Vienīgais šī kopuma avots ir packages/core/src/locales.json, kas satur SUPPORTED_LOCALES, vietējos nosaukumus un noklusējuma valodu. Katrs neangļu string ir machine-translated un gaida cilvēka pārskatīšanu. Izcelsmes marķieris atšķiras pa formātiem: _locales to nes description, site catalogues to pieraksta site/i18n/README.md, bet tulkotie docs pirmajā rindā nes HTML komentāru.

Ir trīs neatkarīgas lokalizācijas virsmas:

“Aktīvo vietņu” slēpšana pasta klientā (AD-3)

Mail client target, piemēram, Thunderbird, jau redz visus rendered messages, tāpēc host-os balstītais “Active sites” redaktors tur ir lieks. Lēmums tiek nests ar mailClient: true failā tooling/build.mjs.

Drošības un privātuma nostāja

Testēšana