Skip to content

feat(extension): pin the Chrome id so a store install replaces a sideload - #223

Merged
ralyodio merged 1 commit into
masterfrom
pin-extension-id
Aug 1, 2026
Merged

feat(extension): pin the Chrome id so a store install replaces a sideload#223
ralyodio merged 1 commit into
masterfrom
pin-extension-id

Conversation

@ralyodio

@ralyodio ralyodio commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Why

Follow-up to the "still shows v0.9.0 after installing 0.9.2" report. The popup renders chrome.runtime.getManifest().version, which reports whichever copy is running — so that popup genuinely was 0.9.0. Two copies were installed at once.

Cause: with no key in the manifest, Chrome derives an unpacked extension's id from its install path, while the store's .crx gets an id derived from the store's signing key. They never match, so a store install lands beside an existing sideload rather than replacing it — two entries, two toolbar icons, and the stale one keeps answering.

Firefox never had this problem: it already pins its id via browser_specific_settings.gecko.id. This is the missing Chrome counterpart.

What

Adds key to manifest.chrome.json, set to the store's own signing public key for this listing. Both an unpacked build and the store .crx now resolve to jmojjohoigoecfkjlobdmiejcdjjbhnb, so Chrome treats them as one extension and an install replaces the other.

Version bumped 0.9.2 → 0.9.3 across package.json and both manifests, since the change only reaches anyone through a new extension-v* release.

Verification

  • Built dist/manifest.json carries the key; an unpacked install of it derives exactly the store id.
  • The manifest key is byte-identical (294 bytes) to the public key in the .crx tronbrowser.dev serves today — Chrome rejects a CRX whose key disagrees with its signature, so this had to match and does.
  • Extension suite: 290/290 pass, build clean.

Caveat

This cannot merge copies already installed — an existing sideload keeps its old path-derived id, so the stale entry has to be removed by hand once. After that, store and sideload stay a single extension.

Note the id is now load-bearing: signing.ts in tronbrowser.dev warns it can never be rotated without orphaning every install, so this key should be treated as permanent.

🤖 Generated with Claude Code

…load

Without a "key", Chrome derives an unpacked extension's id from its install
path, while the store's .crx gets an id derived from the store's signing
key. The two never match, so installing from the store landed a *second*
copy beside an existing sideload — each with its own toolbar icon, and the
old one still reporting its old version from getManifest(). That is exactly
what "still shows 0.9.0 after installing 0.9.2" was.

The key here is the store's own signing public key for this listing, so an
unpacked build and the store .crx both resolve to jmojjohoigoecfkjlobdmiejcdjjbhnb
and Chrome treats them as the same extension — an install replaces, upgrades
or downgrades the other instead of duplicating it. Firefox already pinned its
id via browser_specific_settings.gecko.id; this is the Chrome counterpart.

Verified from the built dist: an unpacked install resolves to the store id,
and the manifest key is byte-identical to the public key in the .crx the
store serves (Chrome rejects a CRX whose key disagrees with its signature).

This does not merge copies already installed — those carry the old
path-derived id, so remove the stale entry once.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

vu1nz Security Review

0 finding(s) in PR #?

No security issues found.

@ralyodio
ralyodio marked this pull request as ready for review August 1, 2026 09:14
@ralyodio
ralyodio merged commit c24d039 into master Aug 1, 2026
8 checks passed
@ralyodio
ralyodio deleted the pin-extension-id branch August 1, 2026 09:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant