Skip to content

Commit

Permalink
Improve integration with new chrome web store
Browse files Browse the repository at this point in the history
  • Loading branch information
NeverDecaf committed Nov 22, 2023
1 parent e5b52d6 commit 703a907
Show file tree
Hide file tree
Showing 8 changed files with 294 additions and 49 deletions.
Binary file modified Chromium Web Store.crx
Binary file not shown.
8 changes: 8 additions & 0 deletions src/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@
"message": "Always download CRX files",
"description": ""
},
"options_webstoreIntegrationTooltip": {
"message": "Enable Install/Uninstall buttons on the Chrome Web Store. (Could expose information about which extensions you have installed to Google.)",
"description": ""
},
"options_webstoreIntegration": {
"message": "Enable Chrome Web Store Integration",
"description": ""
},
"options_importExportInstallAllButton": {
"message": "Install All",
"description": ""
Expand Down
11 changes: 10 additions & 1 deletion src/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"name": "__MSG_extension_Name__",
"description": "__MSG_extension_Description__",
"default_locale": "en",
"version": "1.5.4",
"version": "1.5.4.1",
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqF/d41Q7agjkUzYq8ZGbQr8XW8mmEIMXOnR1uCTnYLL+Dm9Z+LO50xZukOISNy6zFxpI8ts/OGLsm+I2x9+UprUU4/EVdmxuwegFE6NBoEhHoRNYY0gbXZkaU8YY/XwzjVY/k18DDhl5NYPEnF6uq4Oyidg+xtd3W4+iGYczuOLER1Tp5y614zOTphcvFYhvUkCijQ6HT1TtRq/34SlFoRQqo4SFiLriK451xWIcfwiMLIekWrdoQa1v8dqIlMA3r6CKc0QykJpSYbiyormWiZ0hl2HLpkZ85mD9V0eDQ5RCtb6vkybK7INcq4yKQV4YkXhr9NpX9U4re4dlFQjEJQIDAQAB",
"permissions": [
"management",
Expand Down Expand Up @@ -53,5 +53,14 @@
},
"storage": {
"managed_schema": "managed_storage.json"
},
"web_accessible_resources": [
{
"resources": ["scripts/chromeApi.js"],
"matches": ["https://chromewebstore.google.com/*"]
}
],
"externally_connectable": {
"matches": ["https://chromewebstore.google.com/*"]
}
}
58 changes: 48 additions & 10 deletions src/options.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,75 @@
</head>
<body>
<div id="app">
<h2 data-localize="__MSG_options_updateHeading__">Update Options</h2>
<h2 data-localize="__MSG_options_updateHeading__">
Update Options
</h2>
<div>
<label title="__MSG_options_autoUpdateTooltip__">
<input type="checkbox" id="auto_update"/> <span data-localize="__MSG_options_autoUpdate__">Automatically check for extension updates</span>
<input type="checkbox" id="auto_update" />
<span data-localize="__MSG_options_autoUpdate__"
>Automatically check for extension updates</span
>
</label>
<label class="sub">
<span data-localize="__MSG_options_updateDelay__" data-param1="<input id='update_period_in_minutes' type='number' value='60'/>">Check for updates every <input id='update_period_in_minutes' type='number' value='60'/> minutes</span>
<span
data-localize="__MSG_options_updateDelay__"
data-param1="<input id='update_period_in_minutes' type='number' value='60'/>"
>Check for updates every
<input
id="update_period_in_minutes"
type="number"
value="60"
/>
minutes</span
>
</label>
</div>
<div>
<label title="__MSG_options_updateWebstoreTooltip__">
<input type="checkbox" id="check_store_apps"/> <span data-localize="__MSG_options_updateWebstore__">Check for updates to web store extensions</span>
<input type="checkbox" id="check_store_apps" />
<span data-localize="__MSG_options_updateWebstore__"
>Check for updates to web store extensions</span
>
</label>
</div>
<div>
<label title="__MSG_options_updateNonWebstoreTooltip__">
<input type="checkbox" id="check_external_apps"/> <span data-localize="__MSG_options_updateNonWebstore__">Check for updates to non-web store extensions</span>
<input type="checkbox" id="check_external_apps" />
<span data-localize="__MSG_options_updateNonWebstore__"
>Check for updates to non-web store extensions</span
>
</label>
</div>
<h2 data-localize="__MSG_options_ignoredExtensionsHeading__">Ignored Extensions</h2>
<div id='updatetoggle'></div>
<h2 data-localize="__MSG_options_ignoredExtensionsHeading__">
Ignored Extensions
</h2>
<div id="updatetoggle"></div>
<h2 data-localize="__MSG_options_advanced__">Advanced</h2>
<div>
<label title="__MSG_options_manuallyInstallTooltip__">
<input type="checkbox" id="manually_install" /> <span data-localize="__MSG_options_manuallyInstall__">Always download CRX files</span>
<input type="checkbox" id="manually_install" />
<span data-localize="__MSG_options_manuallyInstall__"
>Always download CRX files</span
> </label
><br />
<label title="__MSG_options_webstoreIntegrationTooltip__">
<input type="checkbox" id="webstore_integration" />
<span data-localize="__MSG_options_webstoreIntegration__"
>Enable Web Store Integration</span
>
</label>
</div>
<h2 data-localize="__MSG_options_importExportHeading__">Import / Export</h2>
<h2 data-localize="__MSG_options_importExportHeading__">
Import / Export
</h2>
<div>
<textarea id="import_export_list"></textarea>
<input type="button" value="__MSG_options_importExportInstallAllButton__" id="import_all_button"></input>
<input
type="button"
value="__MSG_options_importExportInstallAllButton__"
id="import_all_button"
/>
</div>
</div>
<script src="scripts/util.js"></script>
Expand Down
109 changes: 109 additions & 0 deletions src/scripts/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,3 +202,112 @@ chrome.downloads.onChanged.addListener((d) => {
}
});
chrome.contextMenus.onClicked.addListener(handleContextClick);

// below functions are for the new chrome web store:
// port is used for functions with callbacks:
chrome.runtime.onConnectExternal.addListener((port) => {
var port_disconnected = false;
port.onDisconnect.addListener(() => {
port_disconnected = true;
});
port.onMessage.addListener(function (msg, port) {
// console.log("recieved msg through port:", msg);
switch (msg.func) {
case "onInstalled":
var [callback, ..._] = msg.args;
chrome.management.onInstalled.addListener(function cb() {
if (port_disconnected) {
chrome.management.onInstalled.removeListener(cb);
return;
}
port.postMessage({
args: arguments,
callbackIndex: callback,
err: chrome.runtime.lastError,
});
});
break;
case "onUninstalled":
var [callback, ..._] = msg.args;
chrome.management.onUninstalled.addListener(function cb() {
if (port_disconnected) {
chrome.management.onUninstalled.removeListener(cb);
return;
}
port.postMessage({
args: arguments,
callbackIndex: callback,
err: chrome.runtime.lastError,
});
});
break;
case "uninstall":
var [ext_id, options, callback, ..._] = msg.args;
chrome.management.uninstall(ext_id, options, function () {
port.postMessage({
args: arguments,
callbackIndex: callback,
err: chrome.runtime.lastError,
});
});
break;
case "setEnabled":
var [ext_id, enabled, callback, ..._] = msg.args;
chrome.management.setEnabled(ext_id, enabled, function () {
port.postMessage({
args: arguments,
callbackIndex: callback,
err: chrome.runtime.lastError,
});
});
break;
}
});
});
chrome.runtime.onMessageExternal.addListener(function (
request,
sender,
sendResponse,
) {
// console.log("recieved msg through runtime:", request);
switch (request.func) {
case "getExtensionStatus":
var [id, ext, ..._] = request.args;
chrome.management.getAll((exts) => {
const this_ext = exts.filter((extInfo) => extInfo.id === id);
if (!this_ext.length) {
sendResponse({ args: ["installable"] });
return;
}
sendResponse({
args: [this_ext[0].enabled ? "enabled" : "disabled"],
});
});
break;
case "getAll":
var [id, ..._] = request.args;
chrome.management.getAll((exts) => {
// instead of exposing entire extension list, filter to only the relevant extension.
sendResponse({
args: [exts.filter((extInfo) => extInfo.id === id)],
});
});
break;
case "beginInstallWithManifest3":
var [extInfo, href, ..._] = request.args;

promptInstall(
buildExtensionUrl(href),
true,
WEBSTORE.chrome,
msgHandler,
);
sendResponse({
// because a "cancel" in the context of chromium-web-store won't be detected,
// we must throw user_cancelled here to ensure the button doesn't get stuck on loading spinner.
// The behaviour of this is similar to sending success ("") so this should be fine.
args: ["user_cancelled"],
});
break;
}
});
97 changes: 97 additions & 0 deletions src/scripts/chromeApi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// https://source.chromium.org/chromium/chromium/src/+/main:chrome/common/extensions/api/webstore_private.json
const ncws_re = /.*detail(?:\/[^\/]+)?\/([a-z]{32})/i; // copied from util.js since it's out of context
const THIS_EXT_ID = ncws_re.exec(window.location.href)[1];
const EXT_ID = "ocaahdebbfolfmndjeplogmgcagdmblk"; // need to hardcode this so it's available immediately. (chrome.runtime.id will be undefined in this context)

const port = chrome.runtime.connect(EXT_ID, { name: "windowchromeport" });
const CALLBACKS = [];
port.onMessage.addListener((msg, port) => {
if (msg.callbackIndex !== undefined) {
if (msg.err) {
// "throw" error
chrome.runtime.lastError = msg.err;
}
CALLBACKS[msg.callbackIndex].apply(...Array.from(msg.args));
}
});
window.chrome.webstorePrivate = {
getExtensionStatus: function (id, manifest, cb) {
chrome.runtime.sendMessage(
EXT_ID,
{ func: "getExtensionStatus", args: [id, manifest] },
(resp) => {
resp.args && cb(...resp.args);
},
);
},
beginInstallWithManifest3: function (extinfo, cb) {
chrome.runtime.sendMessage(
EXT_ID,
{
func: "beginInstallWithManifest3",
args: [extinfo, window.location.href],
},
(resp) => {
resp.args && cb(...resp.args);
},
);
},
isInIncognitoMode: (cb) => cb(false), // just return false since it's likely this extension isn't running in incognito
getReferrerChain: (cb) => cb("EgIIAA=="),
completeInstall: function (id, cb) {
// will never be called since we cancel all install attempts with "user_cancelled"
// instead we rely on the onInstalled listener to continue the flow correctly (behaviour might be slightly different,
// for example an extension installed tooltip will not show.)
cb(true);
},
};
window.chrome.management = {
setEnabled: function (extId, enabled, callback) {
port.postMessage({
func: "setEnabled",
args: [extId, enabled, CALLBACKS.length],
});
CALLBACKS.push(callback);
},
install: function () {
console.log(
"chrome.management.install not implemented, but called with args:",
arguments,
);
},
uninstall: function (extId, options, callback) {
port.postMessage({
func: "uninstall",
args: [extId, options, CALLBACKS.length],
});
CALLBACKS.push(callback);
},
getAll: function (cb) {
chrome.runtime.sendMessage(
EXT_ID,
{ func: "getAll", args: [THIS_EXT_ID] },
(resp) => {
resp.args && cb(...resp.args);
},
);
},
onInstalled: {
addListener: function (callback) {
port.postMessage({
func: "onInstalled",
args: [CALLBACKS.length],
});
CALLBACKS.push(callback);
},
},
onUninstalled: {
addListener: function (callback) {
port.postMessage({
func: "onUninstalled",
args: [CALLBACKS.length],
});
CALLBACKS.push(callback);
},
},
};
// window.chrome.runtime.getManifest = () => true; // this is referenced in the CWS source but omitting it seems to have no effect
Loading

0 comments on commit 703a907

Please sign in to comment.