Skip to content

Commit

Permalink
Merge pull request #633 from tjhorner/fix-javascript-csp
Browse files Browse the repository at this point in the history
Use userScripts API for JavaScript actions
  • Loading branch information
crittermike committed Jul 17, 2024
2 parents 2d626d4 + a6c6291 commit 31746ae
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 35 deletions.
4 changes: 3 additions & 1 deletion app/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,11 @@
"debugger",
"scripting",
"notifications",
"activeTab"
"activeTab",
"userScripts"
],
"host_permissions": ["*://*/*"],
"user_scripts": { },
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self'; style-src 'self' 'unsafe-inline'; style-src-elem 'self' 'unsafe-inline' https://cdn.materialdesignicons.com https://cdn.jsdelivr.net;"
},
Expand Down
26 changes: 26 additions & 0 deletions app/options/options.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@

<b-tabs v-model="activeTab" type="is-toggle" expanded>
<b-tab-item label="Shortcuts">
<b-message
title="Enable Developer Mode"
type="is-warning"
:active="needsDeveloperMode()"
:closable="false">
In order for JavaScript actions to work, you must first enable Developer Mode in your browser extension settings. Follow the instructions <a href="https://developer.chrome.com/docs/extensions/reference/api/userScripts#developer_mode_for_extension_users" target="_blank">here</a>, then come back and save your shortcuts.
</b-message>

<b-table
:data="keys"
ref="table"
Expand Down Expand Up @@ -196,6 +204,7 @@
</template>

<script>
import { v4 as uuid } from "uuid";
import TextInput from "./components/TextInput";
import LinkBar from "./components/LinkBar";
import SelectInput from "./components/SelectInput";
Expand All @@ -211,8 +220,25 @@ export default {
TextInput,
},
methods: {
needsDeveloperMode: function() {
const hasJsKeys = this.keys.some(key => key.action === 'javascript');
if (!hasJsKeys) {
return false;
}
try {
chrome.userScripts;
return false;
} catch {
return true;
}
},
saveShortcuts: async function() {
this.keys.forEach((key) => {
if (!key.id) {
key.id = uuid();
}
key.sites = key.sites || "";
key.sitesArray = key.sites.split('\n');
delete key.sidebarOpen;
Expand Down
3 changes: 1 addition & 2 deletions app/scripts/content.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
'use strict'
/* global Mousetrap */
import Mousetrap from 'mousetrap'
import './inject-scripts/inject.js'

if (typeof browser === "undefined") {
var browser = chrome;
Expand Down Expand Up @@ -45,7 +44,7 @@ Shortkeys.doAction = (keySetting) => {
// to the page MAIN world and dispatch this event from the content script
if (action === 'javascript') {
document.dispatchEvent(new CustomEvent('shortkeys_js_run', {
detail: keySetting.code // code to run
detail: keySetting.id
}))
return
} else if (action === 'trigger') {
Expand Down
8 changes: 0 additions & 8 deletions app/scripts/inject-scripts/inject.js

This file was deleted.

7 changes: 0 additions & 7 deletions app/scripts/inject-scripts/script-to-inject.js

This file was deleted.

50 changes: 50 additions & 0 deletions app/scripts/service_worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,56 @@ let handleAction = async (action, request = {}) => {
return true
}

async function registerUserScript() {
const keys = JSON.parse((await chrome.storage.local.get("keys")).keys) || []
const javascriptActions = keys.filter(key => key.action === "javascript")

const actionHandlersAsObject = javascriptActions.reduce((acc, cur) => {
acc += JSON.stringify(cur.id) + ":"
acc += "function() {" + cur.code + "},"
return acc
}, "{") + "}"

function registerHandlers() {
document.addEventListener('shortkeys_js_run', function(e) {
if (handlers[e.detail]) {
handlers[e.detail]()
}
})
}

const existingScripts = await chrome.userScripts.getScripts({
ids: ["shortkeys-actions"]
})

const scripts = [
{
id: "shortkeys-actions",
matches: [ "*://*/*" ],
world: "MAIN",
js: [
{
code: `const handlers = ${actionHandlersAsObject};\n${registerHandlers.toString()}\nregisterHandlers();`
}
]
}
]

if (existingScripts.length) {
await chrome.userScripts.update(scripts)
} else {
await chrome.userScripts.register(scripts)
}
}

chrome.storage.local.onChanged.addListener(registerUserScript)

chrome.runtime.onInstalled.addListener(function (details) {
if (details.reason === "update") {
registerUserScript()
}
})

browser.commands.onCommand.addListener(function (command) {
// Remove the integer and hyphen at the beginning.
command = command.split('-')[1]
Expand Down
50 changes: 35 additions & 15 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"build": "webextension-toolbox build"
},
"devDependencies": {
"@types/chrome": "^0.0.133",
"@types/chrome": "^0.0.267",
"@webextension-toolbox/webextension-toolbox": "^6.2.0"
},
"dependencies": {
Expand All @@ -21,6 +21,7 @@
"mousetrap": "^1.6.3",
"serialize-javascript": ">=2.1.1",
"style-loader": "^1.0.1",
"uuid": "^10.0.0",
"vue": "^2.6.11",
"vue-loader": "^15.8.3",
"vue-template-compiler": "^2.6.11",
Expand Down
1 change: 0 additions & 1 deletion webextension-toolbox.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ module.exports = {

config.entry = {
'scripts/service_worker': './scripts/service_worker.js',
'scripts/script-to-inject': './scripts/inject-scripts/script-to-inject.js',
'scripts/content': './scripts/content.js',
'options/options': './options/options.js',
};
Expand Down

0 comments on commit 31746ae

Please sign in to comment.