37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "manifest_version": 3,
3 | "name": "OnlyFans Cookie Helper",
4 | "version": "2.3.0",
5 | "description": "Helper extension that makes it easier to copy config.json values for the DIGITALCRIMINALS/OnlyFans scraper",
6 | "icons": {
7 | "48": "icons/cookie.png"
8 | },
9 | "background": {
10 | "service_worker": "background/background.js"
11 | },
12 | "permissions": [
13 | "cookies",
14 | "clipboardWrite",
15 | "storage"
16 | ],
17 | "host_permissions": [
18 | "*://*.onlyfans.com/"
19 | ],
20 | "action": {
21 | "browser_style": true,
22 | "default_icon": {
23 | "48": "icons/cookie.png"
24 | },
25 | "default_title": "OnlyFans Cookie Helper",
26 | "default_popup": "popup/cookies.html"
27 | },
28 | "content_scripts": [
29 | {
30 | "matches": [
31 | "*://*.onlyfans.com/*",
32 | "*://*.onlyfans.com/"
33 | ],
34 | "js": [
35 | "content_scripts/bcToken.js"
36 | ]
37 | }
38 | ]
39 | }
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | Copyright (c) 2020-2024 Marcus
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OnlyFans Cookie Helper
2 |
3 | An extension made to make it easier to copy the correct `config.json` values when using [datawhores/OF-Scraper](https://github.com/datawhores/OF-Scraper) or [DIGITALCRIMINALS/OnlyFans](https://github.com/DIGITALCRIMINALS/OnlyFans).
4 |
5 | ## How to install
6 |
7 | Extension is only available on the Firefox addon store, but not on the Chrome web store. For Chromium-based browsers, alternatively installation methods are necessary.
8 | One of these days I might explore putting it on the Chrome web store, but for a few different reasons I bit am hesitant to so (one of them being the paywall Google has to publish extensions).
9 |
10 | ### Firefox
11 |
12 | #### Option 1 (Recommended)
13 |
14 | Install it from the [Firefox Addon Store (AMO)](https://addons.mozilla.org/en-US/firefox/addon/onlyfans/)
15 |
16 | **NOTE**: Mozilla disabled the addon on February 27th 2024 citing the reason:
17 | > Acceptable Use, specifically Sexual content: This content contains sexual or pornographic content that violates Mozilla’s Acceptable Use Policy.
18 |
19 | I have replied to them to appeal, since the addon doesn't contain (or link to) any sexual content, but still awaiting any further reply from Mozilla.
20 | If you need to \[re-\]install the addon, please use option 2 or 3 for the time being.
21 |
22 | #### Option 2
23 |
24 | Go to [Releases](https://github.com/M-rcus/OnlyFans-Cookie-Helper/releases), download the `.xpi` file and install it by typing `about:addons` into your URL bar, pressing `CTRL+Shift+A` or clicking the "hamburger menu" top-right of the Firefox window and then "Addons".
25 |
26 | 
27 |
28 | #### Option 3
29 |
30 | Follow the [Trying it out](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Your_first_WebExtension#Trying_it_out) steps on their developer website.
31 |
32 | ### Chrome / Chromium
33 |
34 | These steps MAY work on other Chromium-based browsers, such as: Brave, Microsoft Edge, Vivaldi and Opera (to name a few).
35 | No guarantees though, I only do simple tests on a basic Chromium install, as my primary browser is Firefox.
36 |
37 | #### Option 1
38 |
39 | This option is only available as of v2.2.0. This is **VERY unofficial way** of installing the extension and you might a few warnings about it being unsafe (which is _generally_ true).
40 | If you are not comfortable with that, you can either choose to use Firefox instead or try option 2 below.
41 |
42 | 1. Go to [Releases](https://github.com/M-rcus/OnlyFans-Cookie-Helper/releases) and click the `.crx` file. Your browser might prompt you to install the extension. You can then just click 'Add extension'.
43 | - From my testing, Google Chrome and Brave give you an error when doing this. It does seem to work on "Ungoogled Chromium". Besides that I am not sure whether it will work or not.
44 |
45 | If it _does not_ prompt you to install the extension, you can try the following:
46 |
47 | 1. Right-click on the `.crx` download link and click "Save link as..."
48 | - As I mentioned, it will likely ask you (sometimes multiple times) if you want to keep the file as it can be malicious. You want to keep the file.
49 | 2. In your Chromium-browser, go to your URL bar and hit enter after typing in `chrome://extensions`
50 | 3. Find the `.crx` file that you just downloaded.
51 | 4. Click and drag the `.crx` file into your Chromium browser window, where `chrome://extensions` is open.
52 | 5. It should prompt you to add the extension.
53 |
54 | #### Option 2
55 |
56 | 1. Download the ZIP file of the version - `Source code (.zip)`
57 | 2. Extract the ZIP into a folder.
58 | 3. In your Chromium-browser, go to your URL bar and hit enter after typing in `chrome://extensions`
59 | 4. Click on "Load unpacked". **Select** the extracted folder and click "Open".
60 |
61 | ## How to use
62 |
63 | Make sure you're logged into the OnlyFans website normally.
64 |
65 | After installing the extension, click the cookie icon.
66 | A popup should show up (see [preview](#preview)) with a JSON-formatted text.
67 | There's a a "Copy to clipboard" button at the bottom of the popup that should copy the text to your clipboard.
68 | If it does not work, you can just copy the text manually by selecting it.
69 |
70 | Once you've copied the text to clipboard, you can paste it into the `auth.json` file in your profiles folder.
71 | The default `auth.json` file should be located in `/.profiles/OnlyFans/default/auth.json`, but may not show up until you've started up the OnlyFans software at least once.
72 |
73 | You can also create a new folder and a separate `auth.json` file, which is useful if you have multiple accounts.
74 | For example:
75 | - `/.profiles/OnlyFans/my-personal-account/auth.json`
76 | - `/.profiles/OnlyFans/my-secret-account/auth.json`
77 |
78 | ### Preview
79 |
80 | Screenshot as of extension version v1.0.3, which means it's slightly outdated.
81 | A few things to note:
82 | - `auth_hash`, `auth_uniq_`, `email` and `password` are _typically empty_. Don't panic if they don't have any values, as it's completely normal.
83 | - The `username` field is by default set to "u" plus the same number as `auth_id`. It _does not_ need to be your actual OnlyFans username.
84 |
85 | 
86 |
87 | ## Permissions
88 |
89 | Overview of permissions and why they're required.
90 |
91 | - `cookies`
92 | - Values such as `auth_id` and `sess` are contained within cookies.
93 | - Keep in mind that the `cookies` permission only applies for `onlyfans.com` and no other websites.
94 | - `clipboardWrite`
95 | - To copy the `auth.json` values into your clipboard
96 | - `storage`
97 | - This is specifically just to "synchronize" the `x_bc` value to the popup (so it can be copied).
98 | - `x_bc` isn't available via the regular `cookies` permission, so we need a workaround (which utilizes the `storage` permission).
99 | - `contextualIdentities`
100 | - On Firefox, it's used to support multi-account containers.
101 | - ~~On Chromium-based browsers (Google Chrome, Brave, Microsoft Edge, Vivaldi, Opera etc.) it does nothing. However, it may give a warning. The extension should still work even with this warning.~~ - This should no longer happen as of v2.2.0.
102 |
103 | ## LICENSE
104 |
105 | [MIT License](./LICENSE.md)
106 |
107 | ## Mirrors
108 |
109 | This project is currently mirrored to three different providers:
110 |
111 | - [GitHub](https://github.com/M-rcus/OnlyFans-Cookie-Helper)
112 | - [GitLab](https://gitlab.com/Maarcus/OnlyFans-Cookie-Helper)
113 | - [GitGud.io](https://gitgud.io/Maarcus/OnlyFans-Cookie-Helper)
114 |
115 | Those are the only 'official' sources for this extension.
116 | Anyone else can of course freely mirror the project as they see fit.
117 |
118 | ## Sellout (Tips)
119 |
120 | If you find the extension useful and would like to send me a tip, then I'll gladly take some crypto <3
121 |
122 | - Bitcoin: `bc1qps35rpadgmpf2a7vmuq45xnt7qscymtlnny6mx`
123 | - Dogecoin: `DAjtoHdXFFhRc3qJq8sqCWpQLLDB8t3L6n`
124 | - Litecoin: `LbX5iqVfYoRz7kPAPQoEKdqiN7Y9PRxsAg`
125 |
126 | Alternatively, PayPal, though crypto is preferred: https://paypal.me/maaaarcus
--------------------------------------------------------------------------------
/popup/cookies.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Shamelessly copied from: https://techoverflow.net/2018/03/30/copying-strings-to-the-clipboard-using-pure-javascript/
3 | *
4 | * Only used as a fallback if for some reason the Clipboard API
5 | * does not exist... heh.
6 | */
7 | async function copyStringToClipboard (str) {
8 | // Create new element
9 | var el = document.createElement('textarea');
10 | // Set value (string to be copied)
11 | el.value = str;
12 | // Set non-editable to avoid focus and move outside of view
13 | el.setAttribute('readonly', '');
14 | el.style = {position: 'absolute', left: '-9999px'};
15 | document.body.appendChild(el);
16 | // Select text inside element
17 | el.select();
18 | // Copy text to clipboard
19 | document.execCommand('copy');
20 | // Remove temporary element
21 | document.body.removeChild(el);
22 | }
23 |
24 | const containerNames = {};
25 | const containersEnabled = browser.contextualIdentities !== undefined;
26 |
27 | /**
28 | * Get the correct bcToken from storage
29 | */
30 | async function getBcTokenSha(id)
31 | {
32 | return new Promise((resolve, reject) => {
33 | chrome.storage.local.get(['bcTokens'], function(data) {
34 | const bcTokens = data.bcTokens || {};
35 |
36 | if (bcTokens[id]) {
37 | resolve(bcTokens[id]);
38 | return;
39 | }
40 |
41 | resolve(null);
42 | });
43 | });
44 | }
45 |
46 | async function getContainers()
47 | {
48 | /**
49 | * Prefill popup with "no container" cookies
50 | */
51 | grabCookies();
52 |
53 | /**
54 | * Non-Firefox browser or containers not enabled.
55 | */
56 | if (!containersEnabled) {
57 | return;
58 | }
59 |
60 | /**
61 | * Containers are enabled, but none found.
62 | */
63 | let containers = await browser.contextualIdentities.query({});
64 | if (containers.length < 1) {
65 | return;
66 | }
67 |
68 | // Sort container list by name.
69 | containers.sort(function(a, b) {
70 | const nameA = a.name.toLowerCase();
71 | const nameB = b.name.toLowerCase();
72 |
73 | if (nameA < nameB) {
74 | return -1;
75 | }
76 |
77 | if (nameA > nameB) {
78 | return 1;
79 | }
80 |
81 | return 0;
82 | });
83 |
84 | const containerSection = document.querySelector('#container-list');
85 | containerSection.classList.remove('hidden');
86 |
87 | const optionList = containerSection.querySelector('select');
88 |
89 | for (const container of containers)
90 | {
91 | const storeId = container.cookieStoreId;
92 | const { name } = container;
93 |
94 | containerNames[storeId] = name;
95 |
96 | const option = document.createElement('option');
97 | option.setAttribute('value', storeId);
98 | option.textContent = name;
99 |
100 | optionList.insertAdjacentElement('beforeend', option);
101 | }
102 |
103 | optionList.addEventListener('change', function(event) {
104 | const storeId = event.target.value;
105 |
106 | if (!storeId || storeId.length < 1) {
107 | grabCookies(null);
108 | return;
109 | }
110 |
111 | grabCookies(storeId);
112 | });
113 | }
114 |
115 | async function grabCookies(cookieStoreId) {
116 | /**
117 | * Grab the cookies from the browser...
118 | */
119 | const cookieOpts = {
120 | domain: '.onlyfans.com',
121 | };
122 |
123 | /**
124 | * Container tabs
125 | */
126 | if (cookieStoreId) {
127 | cookieOpts.storeId = cookieStoreId;
128 | }
129 |
130 | const cookies = await browser.cookies.getAll(cookieOpts);
131 |
132 | /**
133 | * We only care about `name` and `value` in each cookie entry.
134 | */
135 | const mappedCookies = {};
136 | for (const cookie of cookies)
137 | {
138 | mappedCookies[cookie.name] = cookie.value;
139 | }
140 |
141 | /**
142 | * Define and check if `authId` exists
143 | * if not, return and call it a day...
144 | *
145 | * Also define the other elements.
146 | */
147 | const authId = mappedCookies.auth_id;
148 | const sess = mappedCookies.sess;
149 | const copyBtn = document.querySelector('#copy-to-clipboard');
150 | const jsonElement = document.querySelector('#json');
151 | const errorElement = document.querySelector('#errorMessage');
152 |
153 | /**
154 | * If authId isn't specified, user is not logged into
155 | * OnlyFans... or at least we assume so.
156 | */
157 | if (!authId || !sess) {
158 | let errorMessage = 'Could not find valid cookie values, make sure you are logged into OnlyFans.';
159 | if (containersEnabled) {
160 | const containerName = containerNames[cookieStoreId] || 'Default (no container)';
161 | errorMessage = `Could not find valid cookie values in container: ${containerName} Make sure you are logged into OnlyFans.`;
162 | }
163 |
164 | errorElement.innerHTML = errorMessage;
165 | errorElement.classList.remove('hidden');
166 |
167 | if (!copyBtn.classList.contains('hidden')) {
168 | copyBtn.classList.add('hidden');
169 | jsonElement.classList.add('hidden');
170 | }
171 |
172 | return;
173 | }
174 |
175 | // See `background/background.js` as to why we use `st` here
176 | const st = mappedCookies.st;
177 | const bcToken = await getBcTokenSha(st);
178 | if (!bcToken) {
179 | let errorMessage = 'Could not find valid x_bc value. Please open OnlyFans.com once and make sure it fully loads. If you are not logged in, please log in and refresh the page.';
180 | if (containersEnabled) {
181 | const containerName = containerNames[cookieStoreId] || 'Default (no container)';
182 | errorMessage = `Could not find valid x_bc value. Please open OnlyFans.com once in container: ${containerName} Make sure it fully loads. If you are not logged in, please log in and refresh the page.`;
183 | }
184 |
185 | errorElement.innerHTML = errorMessage;
186 | errorElement.classList.remove('hidden');
187 |
188 | if (!copyBtn.classList.contains('hidden')) {
189 | copyBtn.classList.add('hidden');
190 | jsonElement.classList.add('hidden');
191 | }
192 |
193 | return;
194 | }
195 |
196 | copyBtn.classList.remove('hidden');
197 | jsonElement.classList.remove('hidden');
198 | errorElement.classList.add('hidden');
199 |
200 | /**
201 | * Fill out the object that OnlyFans excepts
202 | */
203 | const config = {
204 | username: 'u' + authId,
205 | cookie: `auth_id=${authId}; sess=${sess}; auth_hash=; auth_uniq_${authId}=; auth_uid_${authId}=;`,
206 | // TODO: Still need to handle this better...
207 | user_agent: navigator.userAgent,
208 | x_bc: bcToken,
209 | support_2fa: true,
210 | active: true,
211 | email: "",
212 | password: "",
213 | hashed: false,
214 | };
215 |
216 | /**
217 | * Then we print it to the popup :)
218 | *
219 | * Third parameter to JSON.stringify() is for spacing the indentation.
220 | */
221 | const authConfig = {
222 | auth: config,
223 | };
224 |
225 | const cookieJson = JSON.stringify(authConfig, null, 2);
226 | jsonElement.textContent = cookieJson;
227 |
228 | /**
229 | * Use yee yee ghetto ass method as a fallback
230 | * method for copying to clipboard.
231 | */
232 | const clipboardWriteText = browser.clipboard.writeText || copyStringToClipboard;
233 | const oldBtnText = copyBtn.innerHTML;
234 | copyBtn.addEventListener('click', async () => {
235 | try {
236 | await clipboardWriteText(cookieJson);
237 |
238 | copyBtn.textContent = 'Copied to clipboard!';
239 | copyBtn.setAttribute('disabled', '1');
240 | }
241 | catch (err) {
242 | console.error(err);
243 | }
244 |
245 | setTimeout(() => {
246 | copyBtn.textContent = oldBtnText;
247 | copyBtn.removeAttribute('disabled');
248 | }, 2500);
249 | });
250 | }
251 |
252 | document.addEventListener('DOMContentLoaded', async () => {
253 | await getContainers();
254 | });
255 |
--------------------------------------------------------------------------------
/lib/browser-polyfill.min.js:
--------------------------------------------------------------------------------
1 | (function(a,b){if("function"==typeof define&&define.amd)define("webextension-polyfill",["module"],b);else if("undefined"!=typeof exports)b(module);else{var c={exports:{}};b(c),a.browser=c.exports}})("undefined"==typeof globalThis?"undefined"==typeof self?this:self:globalThis,function(a){"use strict";if("undefined"==typeof browser||Object.getPrototypeOf(browser)!==Object.prototype){if("object"!=typeof chrome||!chrome||!chrome.runtime||!chrome.runtime.id)throw new Error("This script should only be loaded in a browser extension.");a.exports=(a=>{const b={alarms:{clear:{minArgs:0,maxArgs:1},clearAll:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getAll:{minArgs:0,maxArgs:0}},bookmarks:{create:{minArgs:1,maxArgs:1},get:{minArgs:1,maxArgs:1},getChildren:{minArgs:1,maxArgs:1},getRecent:{minArgs:1,maxArgs:1},getSubTree:{minArgs:1,maxArgs:1},getTree:{minArgs:0,maxArgs:0},move:{minArgs:2,maxArgs:2},remove:{minArgs:1,maxArgs:1},removeTree:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1},update:{minArgs:2,maxArgs:2}},browserAction:{disable:{minArgs:0,maxArgs:1,fallbackToNoCallback:!0},enable:{minArgs:0,maxArgs:1,fallbackToNoCallback:!0},getBadgeBackgroundColor:{minArgs:1,maxArgs:1},getBadgeText:{minArgs:1,maxArgs:1},getPopup:{minArgs:1,maxArgs:1},getTitle:{minArgs:1,maxArgs:1},openPopup:{minArgs:0,maxArgs:0},setBadgeBackgroundColor:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setBadgeText:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setIcon:{minArgs:1,maxArgs:1},setPopup:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setTitle:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0}},browsingData:{remove:{minArgs:2,maxArgs:2},removeCache:{minArgs:1,maxArgs:1},removeCookies:{minArgs:1,maxArgs:1},removeDownloads:{minArgs:1,maxArgs:1},removeFormData:{minArgs:1,maxArgs:1},removeHistory:{minArgs:1,maxArgs:1},removeLocalStorage:{minArgs:1,maxArgs:1},removePasswords:{minArgs:1,maxArgs:1},removePluginData:{minArgs:1,maxArgs:1},settings:{minArgs:0,maxArgs:0}},commands:{getAll:{minArgs:0,maxArgs:0}},contextMenus:{remove:{minArgs:1,maxArgs:1},removeAll:{minArgs:0,maxArgs:0},update:{minArgs:2,maxArgs:2}},cookies:{get:{minArgs:1,maxArgs:1},getAll:{minArgs:1,maxArgs:1},getAllCookieStores:{minArgs:0,maxArgs:0},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}},devtools:{inspectedWindow:{eval:{minArgs:1,maxArgs:2,singleCallbackArg:!1}},panels:{create:{minArgs:3,maxArgs:3,singleCallbackArg:!0}}},downloads:{cancel:{minArgs:1,maxArgs:1},download:{minArgs:1,maxArgs:1},erase:{minArgs:1,maxArgs:1},getFileIcon:{minArgs:1,maxArgs:2},open:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},pause:{minArgs:1,maxArgs:1},removeFile:{minArgs:1,maxArgs:1},resume:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1},show:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0}},extension:{isAllowedFileSchemeAccess:{minArgs:0,maxArgs:0},isAllowedIncognitoAccess:{minArgs:0,maxArgs:0}},history:{addUrl:{minArgs:1,maxArgs:1},deleteAll:{minArgs:0,maxArgs:0},deleteRange:{minArgs:1,maxArgs:1},deleteUrl:{minArgs:1,maxArgs:1},getVisits:{minArgs:1,maxArgs:1},search:{minArgs:1,maxArgs:1}},i18n:{detectLanguage:{minArgs:1,maxArgs:1},getAcceptLanguages:{minArgs:0,maxArgs:0}},identity:{launchWebAuthFlow:{minArgs:1,maxArgs:1}},idle:{queryState:{minArgs:1,maxArgs:1}},management:{get:{minArgs:1,maxArgs:1},getAll:{minArgs:0,maxArgs:0},getSelf:{minArgs:0,maxArgs:0},setEnabled:{minArgs:2,maxArgs:2},uninstallSelf:{minArgs:0,maxArgs:1}},notifications:{clear:{minArgs:1,maxArgs:1},create:{minArgs:1,maxArgs:2},getAll:{minArgs:0,maxArgs:0},getPermissionLevel:{minArgs:0,maxArgs:0},update:{minArgs:2,maxArgs:2}},pageAction:{getPopup:{minArgs:1,maxArgs:1},getTitle:{minArgs:1,maxArgs:1},hide:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setIcon:{minArgs:1,maxArgs:1},setPopup:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},setTitle:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0},show:{minArgs:1,maxArgs:1,fallbackToNoCallback:!0}},permissions:{contains:{minArgs:1,maxArgs:1},getAll:{minArgs:0,maxArgs:0},remove:{minArgs:1,maxArgs:1},request:{minArgs:1,maxArgs:1}},runtime:{getBackgroundPage:{minArgs:0,maxArgs:0},getPlatformInfo:{minArgs:0,maxArgs:0},openOptionsPage:{minArgs:0,maxArgs:0},requestUpdateCheck:{minArgs:0,maxArgs:0},sendMessage:{minArgs:1,maxArgs:3},sendNativeMessage:{minArgs:2,maxArgs:2},setUninstallURL:{minArgs:1,maxArgs:1}},sessions:{getDevices:{minArgs:0,maxArgs:1},getRecentlyClosed:{minArgs:0,maxArgs:1},restore:{minArgs:0,maxArgs:1}},storage:{local:{clear:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}},managed:{get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1}},sync:{clear:{minArgs:0,maxArgs:0},get:{minArgs:0,maxArgs:1},getBytesInUse:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}}},tabs:{captureVisibleTab:{minArgs:0,maxArgs:2},create:{minArgs:1,maxArgs:1},detectLanguage:{minArgs:0,maxArgs:1},discard:{minArgs:0,maxArgs:1},duplicate:{minArgs:1,maxArgs:1},executeScript:{minArgs:1,maxArgs:2},get:{minArgs:1,maxArgs:1},getCurrent:{minArgs:0,maxArgs:0},getZoom:{minArgs:0,maxArgs:1},getZoomSettings:{minArgs:0,maxArgs:1},highlight:{minArgs:1,maxArgs:1},insertCSS:{minArgs:1,maxArgs:2},move:{minArgs:2,maxArgs:2},query:{minArgs:1,maxArgs:1},reload:{minArgs:0,maxArgs:2},remove:{minArgs:1,maxArgs:1},removeCSS:{minArgs:1,maxArgs:2},sendMessage:{minArgs:2,maxArgs:3},setZoom:{minArgs:1,maxArgs:2},setZoomSettings:{minArgs:1,maxArgs:2},update:{minArgs:1,maxArgs:2}},topSites:{get:{minArgs:0,maxArgs:0}},webNavigation:{getAllFrames:{minArgs:1,maxArgs:1},getFrame:{minArgs:1,maxArgs:1}},webRequest:{handlerBehaviorChanged:{minArgs:0,maxArgs:0}},windows:{create:{minArgs:0,maxArgs:1},get:{minArgs:1,maxArgs:2},getAll:{minArgs:0,maxArgs:1},getCurrent:{minArgs:0,maxArgs:1},getLastFocused:{minArgs:0,maxArgs:1},remove:{minArgs:1,maxArgs:1},update:{minArgs:2,maxArgs:2}}};if(0===Object.keys(b).length)throw new Error("api-metadata.json has not been included in browser-polyfill");class c extends WeakMap{constructor(a,b=void 0){super(b),this.createItem=a}get(a){return this.has(a)||this.set(a,this.createItem(a)),super.get(a)}}const d=a=>a&&"object"==typeof a&&"function"==typeof a.then,e=(b,c)=>(...d)=>{a.runtime.lastError?b.reject(a.runtime.lastError):c.singleCallbackArg||1>=d.length&&!1!==c.singleCallbackArg?b.resolve(d[0]):b.resolve(d)},f=a=>1==a?"argument":"arguments",g=(a,b)=>function(c,...d){if(d.lengthb.maxArgs)throw new Error(`Expected at most ${b.maxArgs} ${f(b.maxArgs)} for ${a}(), got ${d.length}`);return new Promise((f,g)=>{if(b.fallbackToNoCallback)try{c[a](...d,e({resolve:f,reject:g},b))}catch(e){console.warn(`${a} API method doesn't seem to support the callback parameter, `+"falling back to call it without a callback: ",e),c[a](...d),b.fallbackToNoCallback=!1,b.noCallback=!0,f()}else b.noCallback?(c[a](...d),f()):c[a](...d,e({resolve:f,reject:g},b))})},h=(a,b,c)=>new Proxy(b,{apply(b,d,e){return c.call(d,a,...e)}});let i=Function.call.bind(Object.prototype.hasOwnProperty);const j=(a,b={},c={})=>{let d=Object.create(null),e={has(b,c){return c in a||c in d},get(e,f,k){if(f in d)return d[f];if(!(f in a))return;let l=a[f];if("function"==typeof l){if("function"==typeof b[f])l=h(a,a[f],b[f]);else if(i(c,f)){let b=g(f,c[f]);l=h(a,a[f],b)}else l=l.bind(a);}else if("object"==typeof l&&null!==l&&(i(b,f)||i(c,f)))l=j(l,b[f],c[f]);else if(i(c,"*"))l=j(l,b[f],c["*"]);else return Object.defineProperty(d,f,{configurable:!0,enumerable:!0,get(){return a[f]},set(b){a[f]=b}}),l;return d[f]=l,l},set(b,c,e,f){return c in d?d[c]=e:a[c]=e,!0},defineProperty(a,b,c){return Reflect.defineProperty(d,b,c)},deleteProperty(a,b){return Reflect.deleteProperty(d,b)}},f=Object.create(a);return new Proxy(f,e)},k=a=>({addListener(b,c,...d){b.addListener(a.get(c),...d)},hasListener(b,c){return b.hasListener(a.get(c))},removeListener(b,c){b.removeListener(a.get(c))}});let l=!1;const m=new c(a=>"function"==typeof a?function(b,c,e){let f,g,h=!1,i=new Promise(a=>{f=function(b){l||(console.warn("Returning a Promise is the preferred way to send a reply from an onMessage/onMessageExternal listener, as the sendResponse will be removed from the specs (See https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/runtime/onMessage)",new Error().stack),l=!0),h=!0,a(b)}});try{g=a(b,c,f)}catch(a){g=Promise.reject(a)}const j=!0!==g&&d(g);if(!0!==g&&!j&&!h)return!1;const k=a=>{a.then(a=>{e(a)},a=>{let b;b=a&&(a instanceof Error||"string"==typeof a.message)?a.message:"An unexpected error occurred",e({__mozWebExtensionPolyfillReject__:!0,message:b})}).catch(a=>{console.error("Failed to send onMessage rejected reply",a)})};return j?k(g):k(i),!0}:a),n=({reject:b,resolve:c},d)=>{a.runtime.lastError?a.runtime.lastError.message==="The message port closed before a response was received."?c():b(a.runtime.lastError):d&&d.__mozWebExtensionPolyfillReject__?b(new Error(d.message)):c(d)},o=(a,b,c,...d)=>{if(d.lengthb.maxArgs)throw new Error(`Expected at most ${b.maxArgs} ${f(b.maxArgs)} for ${a}(), got ${d.length}`);return new Promise((a,b)=>{const e=n.bind(null,{resolve:a,reject:b});d.push(e),c.sendMessage(...d)})},p={runtime:{onMessage:k(m),onMessageExternal:k(m),sendMessage:o.bind(null,"sendMessage",{minArgs:1,maxArgs:3})},tabs:{sendMessage:o.bind(null,"sendMessage",{minArgs:2,maxArgs:3})}},q={clear:{minArgs:1,maxArgs:1},get:{minArgs:1,maxArgs:1},set:{minArgs:1,maxArgs:1}};return b.privacy={network:{"*":q},services:{"*":q},websites:{"*":q}},j(a,p,b)})(chrome)}else a.exports=browser});
2 | //# sourceMappingURL=browser-polyfill.min.js.map
3 |
4 | // webextension-polyfill v.0.6.0 (https://github.com/mozilla/webextension-polyfill)
5 |
6 | /* This Source Code Form is subject to the terms of the Mozilla Public
7 | * License, v. 2.0. If a copy of the MPL was not distributed with this
8 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
9 |
--------------------------------------------------------------------------------