Skip to content

Fix Fanbox: download panel no longer appears (#334) - #335

Open
robrich82 wants to merge 4 commits into
leoding86:masterfrom
robrich82:fix/fanbox-cors-334
Open

Fix Fanbox: download panel no longer appears (#334)#335
robrich82 wants to merge 4 commits into
leoding86:masterfrom
robrich82:fix/fanbox-cors-334

Conversation

@robrich82

@robrich82 robrich82 commented Jul 23, 2026

Copy link
Copy Markdown

Fixes #334 (also the recurring form of #268).

Problem

On Fanbox posts the toolbar icon stays active (URL recognized) but the download panel never appears. The panel only mounts after Application.urlchangeHandler successfully calls adapter.getResource(), and for Fanbox that path was throwing.

Root causes

  1. MV3 CORS regression. FanboxPostParser fetched https://api.fanbox.cc/post.info directly from the content script. The page runs on *.fanbox.cc but the API is on api.fanbox.cc, so it's a cross-origin credentialed request. Under MV2 the blocking webRequest handler rewrote the response Access-Control-Allow-Origin / -Allow-Credentials headers; the MV3 migration dropped that, and declarativeNetRequest can't echo a dynamic origin for a credentialed request. So getResource() threw on CORS (matches the CORS/JSON errors reported in The application pop-up / option bar doesn't appear in Fanbox #268).

  2. Fanbox changed the post.info response shape. The post fields (user, type, body, coverImageUrl, …) are now nested under body.post instead of sitting directly on body, so standardContext() hit context.user = undefined.

  3. Origin required by the API. Once the request runs from the background it's CORS-free, but Fanbox rejected it with HTTP 400 because the background sender's Origin is moz-extension://… / chrome-extension://….

Changes

  • Fetch post.info from the background service worker (FanboxService.postInfo, action fanbox:postInfo). The background runs with host permissions, isn't subject to page CORS, and still sends the session cookie via credentials: 'include' (needed for supporter-only posts).
  • Unwrap body.post in FanboxPostParser, falling back to body for older responses.
  • declarativeNetRequest rule setting Origin/Referer to https://www.fanbox.cc on requests to api.fanbox.cc, scoped with excludedInitiatorDomains: ["fanbox.cc"] so it only touches the extension's own background request and never Fanbox's own SPA calls.
  • Firefox MV3 build: transform the manifest during the Firefox build to emit background.scripts instead of background.service_worker (Firefox implements MV3 backgrounds as event pages; background.service_worker fails to load). All initialization already runs at the top level of Bootstrap.js, so nothing is lost.

Testing

Built and loaded on Firefox 153. Verified the panel now appears on Fanbox posts (regular and supporter-only), the post parses, and downloads complete in Download Manager download mode.

Not included / out of scope

Legacy download mode (downloadMode: 1, which zips inside the content script) has separate, pre-existing Firefox-MV3 content-script CSP problems (JSZip's Function('return this')() is CSP-blocked, and injected library globals aren't visible in Firefox's content-script sandbox). Those are intentionally left out of this PR; Download Manager mode is unaffected and works.

Pixiv Omnia while the button works, doesn't support Fanbox, it should be removed, unless at some point work is done to add Fanbox support to Pixiv Omnia.

…eoding86#334)

The download panel stopped appearing on Fanbox posts. The content-script
parser fetched https://api.fanbox.cc/post.info directly, but the page runs on
*.fanbox.cc while the api is on api.fanbox.cc, making it a cross-origin
credentialed request. Under manifest v2 the blocking webRequest handler
rewrote the response Access-Control-Allow-Origin / -Allow-Credentials headers
to satisfy CORS; the manifest v3 migration dropped that and declarativeNetRequest
cannot echo a dynamic origin for a credentialed request, so getResource() threw
and the UI never mounted (issues leoding86#268, leoding86#334).

Delegate the api request to the background service worker, which runs with the
extension host permissions, isn't subject to page CORS, and still sends the
Fanbox session cookie via credentials: include.

- add FanboxService.postInfo() in the background
- route FanboxPostParser.parseContext() through fanbox:postInfo messaging
Firefox implements the manifest v3 background as an event page and does not
support background.service_worker, so loading the built extension failed with
"background.service_worker is currently disabled. Add background.scripts."

Transform the manifest during the Firefox build to convert
background.service_worker into background.scripts. All real initialization runs
at the top level of Bootstrap.js (which executes in both a service worker and an
event page); the only service-worker-specific hook (self.oninstall -> onBooted)
calls an empty method and sets an unused self.application, so nothing is lost.
The background post.info fetch is CORS-free but Fanbox rejected it with HTTP
400 because the extension background sends Origin: moz-extension://... (or
chrome-extension://...), which the api does not accept. MV2's blocking
webRequest used to rewrite this header.

Add a declarativeNetRequest rule that sets Origin/Referer to https://www.fanbox.cc
on requests to api.fanbox.cc. It is scoped with excludedInitiatorDomains:
[fanbox.cc] so it only touches the extension's own background request and never
Fanbox's own SPA calls (whose real page origin must be preserved for their CORS
to keep working).
Fanbox now nests the post data under body.post instead of putting the post
fields (user, type, body, coverImageUrl, ...) directly on body. Unwrap it,
falling back to body for older responses, so standardContext gets the fields
it expects.

@Fraetor Fraetor left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code looks sensible. How are you building it? I get errors when following the existing instructions in the readme, likely due to my npm/node version being way newer than it expects.

@robrich82

Copy link
Copy Markdown
Author
nvm install 16.18.0
nvm use 16.18.0
yarn install
yarn build:firefox

That will build it (though unsigned and you will have to load temporarily each time in about:debugging

If you want an XPI do the following:

In config/webpack.background.config.js at line 81 add the following (change yourusername to something unique):

                 /**
                 * LOCAL ONLY (do not commit): an explicit add-on id is required
                 * to install the build permanently or to self-sign it via AMO.
                 */
                json.browser_specific_settings = {
                  gecko: {
                    id: 'webextension-pixiv-toolkit-fork@yourusername'
                  }
                };
yarn build:firefox

zip dist/firefox into pixiv-toolkit-fanbox-fix.xpi

Then if using Firefox Developer edition:

about:config → set xpinstall.signatures.required = false

And load the XPI via Install Add-on From File in Extensions

If you are using the normal version of Firefox you'd need to sign up for a Mozilla Developer account and generate credentials at https://addons.mozilla.org/developers/addon/api/key/

Then using the current version of node (you can run nvm install latest then nvm use latest) as this doesn't work on the old version of node

npx web-ext sign --channel=unlisted --source-dir=dist/firefox --api-key=<JWT issuer> --api-secret=<JWT secret>

This will when finished output a signed XPI in web-ext-artifacts/

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.

Doesn't work anymore on fanbox

2 participants