dumbtv
dumbtv가 ADB로 Fire TV에서 광고·추적·업데이트 알림을 제거, 루트·앱 변경 없이, 무료 오픈소스
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기Browser extension for the Locke desktop app — holds AI web-app requests (ChatGPT, Claude, Gemini, and more) until Locke has screened them for sensitive data. Source published for transparency; not open source.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
The browser piece of Locke — Sonomos's on-device
privacy screen for AI apps.
On supported AI chat surfaces such as ChatGPT, Claude, Gemini, Grok and
Perplexity, this extension holds in-scope requests and asks the Locke desktop
app to screen them before they reach the provider. The request is sent, sent
redacted, or blocked — decided entirely on your device. Screening
transfers request content to the local desktop app; allowed or redacted
requests then continue to the website the user is using.
Formerly the Sonomos Desktop Connector.README 전문 보기 ↗The browser piece of Locke — Sonomos's on-device privacy screen for AI apps.
On supported AI chat surfaces such as ChatGPT, Claude, Gemini, Grok and Perplexity, this extension holds in-scope requests and asks the Locke desktop app to screen them before they reach the provider. The request is sent, sent redacted, or blocked — decided entirely on your device. Screening transfers request content to the local desktop app; allowed or redacted requests then continue to the website the user is using.
Formerly the Sonomos Desktop Connector.
| 🏠 Product | sonomos.ai/locke — what Locke is and how to get it |
| 📖 Help & guides | sonomos.ai/support — how the desktop app and this extension work together |
| 🔒 Security & trust | trust.sonomos.ai — security posture, and SECURITY.md for reporting |
| 💬 Questions | GitHub Discussions, or sonomos.ai for anything else |
| 📚 How it works | the wiki, HONEST.md for exactly what is and isn't covered |
This source is published for transparency. It is not open source. The repository is licensed under the PolyForm Strict License 1.0.0 — see
LICENSE. You may read and run it for noncommercial purposes, including auditing and rebuilding it to check that what ships matches this source. You may not redistribute it, modify it, or make derivative works, and commercial use needs a separate licence ([email protected]). Bug and security reports are welcome (SECURITY.md); pull requests cannot be accepted (CONTRIBUTING.md).
This is a deliberately simple hold-and-enforce capture surface. It contains no
detection or redaction logic of its own: when a page on any website sends a bodied
request, the extension holds it, ships the raw request to the Locke
desktop app — which classifies it and screens only AI-shaped traffic — and applies the verdict — send it unchanged (allow), send the
app's rebuilt request (redact), or block it. All scanning and redaction happen
in the desktop app. The failure posture is fail-closed: no verdict, no
send.
It covers every website in the browser; the desktop app decides which requests are AI traffic. Locke screens desktop / native AI apps by a separate path that this extension does not feed; the two are independent, and this repository is only the browser half.
Once installed, it is almost invisible. It works silently: no prompts, no notifications, no injected page UI. The page-visible behaviour is the screening round-trip itself — an in-scope request waits for its verdict, and a blocked one fails the way a network error would. When healthy it is quiet — the toolbar badge is empty on a healthy connection and only shows a glyph when the desktop app is unreachable, so it surfaces only when something is actually wrong. The only user-visible touchpoints are (1) that badge, which appears only on a connection problem, and (2) an opt-in popup showing connection status and whether anything is actually screening — two separate facts, because a reachable desktop app does not prove the screener behind it is alive.
Read
HONEST.mdbefore reading this section as a coverage claim. Only requests with a BODY are screened. A prompt that reaches a provider as a top-level navigation — address bar, default search engine,?q=deep link,<form>submit — is not screened on any host, search hosts included. Screening navigation-borne prompts is deferred to 1.x.Every website is in scope (the discovery gate, super PR #15). The shim runs on every http(s) page and holds every bodied fetch/XHR; the Locke desktop app's on-device classifier decides which are AI traffic and screens only those. Requests classified not-AI are released unchanged. With the desktop app down, every bodied request is blocked — on every site — unless the user opened a fail-open window in the desktop app.
content/shim.js) — runs in the page's
MAIN world and wraps outbound fetch and XMLHttpRequest. If the request
carries a body and its host is not switched off, the shim HOLDS it, captures
the exact body bytes, synthesizes the raw HTTP request, relays it with a
coverage hint, and enforces the verdict it gets back. The hint comes from
the AI web surface catalog (shared/ai-surfaces.json → web_hosts and
capture_path_allowlist, baked into content/web-surfaces.generated.js):
capture_path — a catalog host's prompt path, screened regardless of the
classifier; catalog_host — a catalog host off its prompt paths (sign-in,
sentinel, billing; and the web_screening: "none" search hosts' own
pages); open_web — everything else. The last two are classified first
and screened only if the classifier calls them AI. So a path missing from
an allow-list (e.g. claude.ai's same-origin attachment upload) now
depends on the classifier rather than going out unseen; see
HONEST.md. It also holds a cross-origin
object write initiated by one of those pages — the pre-signed PUT an AI
web app uses to send an attachment straight to S3 / GCS / Azure Blob, which
never addresses an AI host and so was previously unscreened. That scope is
bounded by the initiator, not the destination: nothing is added to the
surface catalog and no host permission is requested, because the shim already
runs inside the page. That upload is always a capture_path. The
fetch wrapper may
snapshot their inputs before deciding scope; see the minimization follow-up
in DATA-FLOW.md.
navigator.sendBeacon is also wrapped, but a beacon cannot be held at all, so
one carrying data to a catalog prompt path is refused rather than let
through; elsewhere it cannot be classified and is sent. What the
extension does not cover — WebSocket, unrecognised upload shapes,
prompts carried in a query string — is catalogued in
HONEST.md.Page (chatgpt.com, claude.ai, gemini.google.com, …)
│ fetch / XHR to an AI web surface
▼
content/shim.js ─── MAIN world; HOLDS in-scope outbound calls,
│ window.postMessage synthesizes the raw HTTP request (base64),
▼ (SONOMOS_CAPTURE ⇄ enforces the verdict. FAIL CLOSED.
│ SONOMOS_VERDICT)
content/content-script.js ─── isolated world; round-trip relay
│ chrome.runtime.sendMessage { type: 'capture', requestB64 }
▼
background/service-worker.js
│ - heartbeat health checks (~30 s, backs off) + connection badge
│ - presence beacon → desktop app (fixed 30 s, never backs off)
│ - native-messaging client → the native messaging host
│ - local audit ring buffer (events and diagnostic metadata, no bodies)
▼ connectNative port (4-byte length-prefixed JSON over stdio)
native messaging host (ai.sonomos.desktop — installed by the desktop app)
│ one connection per held request; forwards bytes, parses nothing
▼ content-screening path uses native messaging, not HTTP
Locke desktop app (parse + screen + redact)
The desktop app returns a verdict, with a whole rebuilt raw request on redact.
The shim acts on it while the page's request is still held: send as held,
re-issue with the rebuilt body bytes (and its Content-Type), or block. Anything
short of a clean verdict — timeout, missing host, half-parsed receipt — blocks.
That is where this repository ends. Everything past the native-messaging boundary — how the held request is parsed, what detects PII, how a redacted request is rebuilt — happens inside the Locke desktop app and is not published here.
The extension ships inside the Locke desktop installer; installing the desktop app is the supported path and it needs no separate steps.
The rest of this section is how a Sonomos maintainer loads this source as an
unpacked extension. It is not a grant of any right to do so — the licence is
read-only (see LICENSE).
Install and run the Locke desktop app. It is what screens requests, and
it is also what installs and registers the native messaging host
(ai.sonomos.desktop) the extension talks to. Without it the extension has
nothing to report to and every in-scope request fails closed. Neither the
host nor its installer is part of this repository.
Build the per-browser trees, then load from dist/ — not from the
repo root, whose manifest.json is a superset carrying both background
families and is not valid for either browser as-is:
npm run package
chrome://extensions → Developer mode → "Load
unpacked" → select dist/chromium/.about:debugging → "This Firefox" → "Load Temporary Add-on" →
select dist/firefox/manifest.json.Chromium-family only: the load's extension ID has to be authorised.
Chromium derives an unpacked extension's ID (32 letters a–p) from the
absolute path it was loaded from, so every checkout gets its own — and the
native-messaging manifest allows only the published store IDs by default.
Until that ID is added to the manifest's allowed_origins, the browser
refuses to start the host ("access to the specified native messaging host
is forbidden") and the popup shows Setup. That manifest belongs to the
Locke desktop app's installer, so authorising a development ID is a
desktop-app-side step; this repository has no command for it.
Firefox is unaffected — a temporary add-on keeps the fixed gecko ID the manifest already allows.
| Path | Purpose |
|---|---|
manifest.json | MV3 manifest. Content scripts scoped to the AI web-surface list; one loopback host permission. Carries both browser families' keys — npm run package strips the wrong ones per target. |
background/service-worker.js | Heartbeat, connection badge, native-messaging client, capture relay, audit log |
content/shim.js | MAIN-world fetch/XHR interception of AI web surfaces; holds, synthesizes the raw request, enforces the verdict |
content/content-script.js | Isolated-world round-trip relay: shim ⇄ service worker |
content/web-surfaces.generated.js | Generated SONOMOS_WEB_HOSTS global (run npm run generate) |
shared/vocab.generated.js | Generated INFRASTRUCTURE_REASONS, from the vendored shared/vocab.json (run npm run generate) |
popup/ | Extension action popup (connection status) |
shared/ | Shared constants, browser-API polyfill, health client, ai-surfaces.json catalog |
scripts/store-build.mjs | Per-target staging + the store-rule checks npm run validate / npm run package gate on |
scripts/zip.mjs | Dependency-free deterministic ZIP writer (forward-slash entry names — see its header) |
npm run validate # check the tree against Chrome Web Store / Edge / AMO rules
npm run package # validate, then write dist/locke-extension-<version>-{chromium,firefox}.zip
The chromium zip serves both the Chrome Web Store and Edge Add-ons; the firefox
zip goes to AMO. npm run package refuses to emit an artifact that fails
validation. Listing copy, permission justifications, and the human checklist
live in docs/store/LISTING.md.
npm run package builds the two store artifacts — one Chromium zip
that serves both the Chrome Web Store and Edge Add-ons, and one Firefox
zip for AMO.
Submitting them is always a deliberate act, never a side effect of merging, by one of two routes:
main. release.yml is
workflow_dispatch-only, and scripts/release-gate.mjs publishes only
when this repository has no v<version> release tag yet.vX.Y.Z tag, where the
scripts/hooks/pre-push hook runs preflight and then
scripts/publish.mjs --store=all.Neither route has a second-person approval step.
docs/store/RELEASE-PIPELINE.md — the
operator's guide: the bump → PR → merge → dispatch sequence, what the
pre-push hook does on a branch versus a tag, dry runs, reproducible builds,
and a troubleshooting table for the ways each store says no.docs/store/CREDENTIALS.md — every store
credential, where to get it, and how each one expires (the Edge API key
every 72 days; the Chrome refresh token every 7 while the OAuth consent
screen is in Testing).Policy — who may release, and what is actually enforced versus merely
committed to — is docs/security/RELEASE-POLICY.md.
The extension handles the content of in-scope requests, including prompts, conversation text and uploaded file bytes. It sends them to the local Locke desktop app through native messaging with the request method, destination, path/query and page-set headers. Those headers can contain authentication information; the browser-added Cookie header is not captured. The separate cross-origin upload path omits the presigned URL's query from the screening copy. Allowed/redacted requests still go to the user's chosen website.
Content scripts run on every http/https page (no <all_urls> grant, so no
file://), and every bodied request is relayed to the local desktop app for
classification; only requests it classifies as AI, and catalog prompt paths,
are screened. Provider policy and disabled-site settings take sites out. This is not complete coverage of every action on a supported site.
See HONEST.md and the data flow.
The extension does not persist request bodies. It does keep local diagnostic metadata (a 100-entry audit buffer), settings and disabled-site configuration; connection/screening state and counters use browser-session storage. Metadata can include URLs or paths and is not guaranteed anonymous. Desktop-app retention is separate: see the Locke privacy policy and the extension retention inventory.
Store privacy declarations must describe this local handling. The source's
Firefox required: ["none"] declaration and missing data-consent experience
remain unresolved; documentation changes do not fix them or authorize a
release. See the store review checklist.
See SECURITY.md. TL;DR:
allow or redact verdict; anything short of that blocks it. Out-of-scope
requests are not relayed for screening; see the fetch snapshot caveat above.ai.sonomos.desktop), which relays to the Locke
desktop app over a user-only 0600 Unix domain socket. There is no HTTP
daemon for request content and no screening URL for a policy to redirect.
The single host_permissions entry
is loopback (http://127.0.0.1/*) and supports the
{ browser, version } presence beacon and Chromium registration requests
containing { id, browser, version } — see
docs/security/PERMISSIONS.md.<all_urls>);
scripts/store-build.mjs::validate rejects a wildcard host in any of its
spellings at build time and in the pre-push gate.ai.sonomos.desktop. The extension keeps it
in exactly one place, shared/constants.js, and it has to match the
registration the Locke desktop app writes; a mismatch means the browser
launches nothing and the extension fails closed.Both checks run locally (npm run validate or npm run package, and the
scripts/hooks/pre-push hook), and a contributor can bypass the hook with
git push --no-verify.
.github/workflows/ re-asserts them, and those workflows now run on pushes
to main and on pull requests — but branch protection is not configured, so
nothing there gates a merge yet. release.yml is the deliberate exception
in the other direction: it is workflow_dispatch-only, so nothing publishes
to a store without somebody choosing to.
The Scorecard and SLSA badges above are aspirational because the release
pipeline has not run yet, not because it cannot; see
docs/security/RELEASE-POLICY.md.
Because local screening necessarily handles prompts, files and request metadata, and claims about that handling deserve to be checkable. Publishing the source lets anyone verify the properties that matter:
127.0.0.1; allowed or redacted
page requests still go to their original remote destinations.
scripts/audit-payload.mjs checks the shipped extension for unexpected
endpoint references in CI; you can inspect the source yourself.package.json declares none, so there is no
third-party code in what ships and no supply chain to take on faith.docs/security/RELEASE-POLICY.md.HONEST.md documents what
the extension does not cover — WebSocket traffic, address-bar prompts, and
more — rather than letting silence imply completeness.The publication is one-way by design: the licence permits reading and
noncommercial verification, not reuse. See LICENSE.
| I want to… | Go to |
|---|---|
| Install or use Locke | sonomos.ai/support |
| Understand how the extension and desktop app work together | sonomos.ai/support, or the wiki |
| Ask about security posture, compliance, audits | trust.sonomos.ai |
| Report a bug in this extension | GitHub issues |
| Report a vulnerability | SECURITY.md — not a public issue |
| Ask anything else | GitHub Discussions, or sonomos.ai |
| Commercial licensing | [email protected] |
Locke and Sonomos are products of Sonomos, Inc. This repository contains the browser extension only; the Locke desktop app is distributed from sonomos.ai/locke.
content/content-script.jsai.sonomos.desktop) — a stdin/stdout JSON host
that relays each held request to the Locke desktop app and returns the
verdict. It forwards bytes; it parses nothing. It is installed and
registered by the Locke desktop app and is not part of this
repository.off disconnected, ! no bridge, …
warming, ? unknown). The opt-in popup surfaces the connection status and, as a
separate row, whether screening is Active (a real verdict came back on a
request that was fully screened), Unavailable, or Not yet confirmed — the
honest answer when the desktop app is reachable but nothing has yet proved the
screener behind it screened what was sent. A request that went out under the user's
fail-open setting reads "Not yet confirmed" too, never "Active": the receipt
proves the app answered AND that those bytes were never examined. The popup
also counts anything that went out that way.chrome.storage.managed (see managed-schema.json).