From e33f25b03bfba45ba268e340710da324e43df918 Mon Sep 17 00:00:00 2001 From: Tomasz Edward Posluszny Date: Wed, 12 Aug 2026 00:49:37 +0200 Subject: [PATCH 1/2] Guard argv[1], and stop describing 1.0.0 as unreleased MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `pathToFileURL(process.argv[1])` throws when argv[1] is undefined, which it is under `node -e` and in some loaders. That turned a guard meant to skip the CLI on import into a crash at import time. Found by importing the module to compute a digest; package.mjs was unaffected only because a normal script run always has argv[1]. 1.0.0 is live on the Chrome Web Store, so the extension name is not an unreleased change — it shipped. The Unreleased section goes back to empty and 1.0.0 records the published name. The changelog also still called it a "tree digest", which is what the digest was called before the verification approach changed. Co-Authored-By: Claude Opus 5 (1M context) --- CHANGELOG.md | 11 +++-------- scripts/verify-install.mjs | 4 +++- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71579d6..9b5bc29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ Every released version has a [GitHub Release](https://github.com/devpeer-net/website-blocker/releases) carrying the exact `.zip` that is uploaded to the Chrome Web Store, its SHA-256, a build -provenance attestation, and a tree digest you can regenerate from an installed copy to +provenance attestation, and a content digest you can regenerate from an installed copy to check that the store is serving that same build. See [docs/RELEASING.md](docs/RELEASING.md) for how a release is cut and how to verify one. @@ -12,15 +12,10 @@ full semver, because Chrome rejects pre-release suffixes such as `1.1.0-rc.1`. ## [Unreleased] -### Changed - -- The extension name and store summary are the final listing copy: - `Website Blocker - Block Distracting Sites, Private & Simple`. The toolbar tooltip stays - plain `Website Blocker`. - ## [1.0.0] — 2026-08-08 -First release. +First release. Published to the Chrome Web Store as +`Website Blocker - Block Distracting Sites, Private & Simple`. ### Added diff --git a/scripts/verify-install.mjs b/scripts/verify-install.mjs index 9f6ab19..be9e8d6 100644 --- a/scripts/verify-install.mjs +++ b/scripts/verify-install.mjs @@ -187,7 +187,9 @@ function report(label, digest, count, extra = '') { console.log(`${label.padEnd(10)} ${digest} (${count} files${extra})`) } -if (import.meta.url === pathToFileURL(process.argv[1]).href) main() +// argv[1] is undefined under `node -e` and in some loaders, and pathToFileURL throws on +// undefined — which would crash package.mjs's import rather than skipping the CLI. +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) main() function main() { const options = {} From f6956c98f6bb9547a948d0f17eb974d75a608cf2 Mon Sep 17 00:00:00 2001 From: Tomasz Edward Posluszny Date: Wed, 12 Aug 2026 01:00:57 +0200 Subject: [PATCH 2/2] Point at the live listing, and drop the deny-non-TLS rule 1.0.1 aside, three facts changed when the extension went live. README said "Not yet on the Chrome Web Store". It is: ilkclodiadkjmnclbkghbnbhnplnfhia. The install section leads with the store and keeps the unpacked route for people who would rather build it, with a pointer to the verification the store cannot give you. The deny-non-TLS statement in bucket-policy.json is removed rather than applied. It was generic S3 hardening applied without asking what it defends. The object is a public document whose whole content is already world-readable, the URL given to the store is https, and the only attacker it excludes is one who can already intercept the connection but wants nothing more than to reword a privacy policy. That is not worth a Deny that can fail closed later, and leaving it committed but unapplied would have made the repository describe a bucket that does not exist. legal/README.md records the reasoning so it does not get re-added by reflex. CWS_EXTENSION_ID is set as a repository variable and the repo homepage points at the listing. Co-Authored-By: Claude Opus 5 (1M context) --- README.md | 16 +++++++++++----- legal/README.md | 12 +++++++++--- legal/bucket-policy.json | 15 --------------- 3 files changed, 20 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 382ef5a..39709bb 100644 --- a/README.md +++ b/README.md @@ -19,17 +19,23 @@ switching blocking off — and keeps everything else frictionless. ## Install -Not yet on the Chrome Web Store. Take the zip from the -[latest release](https://github.com/devpeer-net/website-blocker/releases/latest) — or build -it yourself: +**[Website Blocker on the Chrome Web Store](https://chromewebstore.google.com/detail/website-blocker-block-dis/ilkclodiadkjmnclbkghbnbhnplnfhia)** + +You do not have to take the store's word for what it is serving. Every release publishes a +content digest, and [`scripts/verify-install.mjs`](scripts/verify-install.mjs) checks the +installed extension against it — see [Releases](#releases). + +Or run it unpacked, from the zip on the +[latest release](https://github.com/devpeer-net/website-blocker/releases/latest) or from +source: ```bash pnpm install pnpm build ``` -Either way, open `chrome://extensions`, turn on **Developer mode**, choose **Load -unpacked**, and select the `dist/` folder (or the unzipped release). +Then open `chrome://extensions`, turn on **Developer mode**, choose **Load unpacked**, and +select the `dist/` folder (or the unzipped release). Two settings are worth changing right after installing: diff --git a/legal/README.md b/legal/README.md index c75f143..a7ed958 100644 --- a/legal/README.md +++ b/legal/README.md @@ -6,9 +6,15 @@ as a single public object on S3: https://website-blocker-extension.s3.us-east-1.amazonaws.com/privacy.html `bucket-policy.json` is the policy applied to that bucket. It grants anonymous -`s3:GetObject` on exactly that one key — the bucket is not listable and no other object is -readable — and denies everything over plain HTTP, so the policy the listing cites cannot be -tampered with in transit. +`s3:GetObject` on exactly that one key; the bucket is not listable and no other object is +readable. + +There is deliberately no deny-non-TLS rule. The usual reason for one is confidentiality or +integrity of something worth intercepting, and this is a public document whose entire +content is already world-readable. The URL given to the Web Store is `https://`, so that is +what anyone actually follows. Blocking plain HTTP would buy a defence against an attacker +who can already MITM the connection but only wants to reword a privacy policy — which is +not a threat worth a rule that can fail closed later. aws s3api put-bucket-policy --bucket website-blocker-extension \ --policy file://legal/bucket-policy.json diff --git a/legal/bucket-policy.json b/legal/bucket-policy.json index 35beeae..d45e1d6 100644 --- a/legal/bucket-policy.json +++ b/legal/bucket-policy.json @@ -7,21 +7,6 @@ "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::website-blocker-extension/privacy.html" - }, - { - "Sid": "DenyInsecureTransport", - "Effect": "Deny", - "Principal": "*", - "Action": "s3:*", - "Resource": [ - "arn:aws:s3:::website-blocker-extension", - "arn:aws:s3:::website-blocker-extension/*" - ], - "Condition": { - "Bool": { - "aws:SecureTransport": "false" - } - } } ] }