As browser security improves, many applications have implemented CORS headers to protect against unauthorized access. I'm working on a Chrome extension that needs to check if a certain URL is present on GitHub, before it opens the URL in a new tab. Let's explore what we can do.
The Manifest
Due to CORS headers, it is not possible to perform a fetch request for the HEAD
method on a domain that is not included in the headers. However, by utilizing a worker script (in Chrome Extension version 3), it is possible to bypass this restriction. Let's configure the manifest:
{
"manifest_version": 3,
"name": "My Extension Name",
"description": "My Extension Description",
"version": "1.0",
"content_scripts": [
{
"matches": [ "https://*/*" ],
"js": ["content.js"]
}
],
"background": {
"service_worker": "background.js"
},
"permissions": ["activeTab"]
"host_permissions": ["https://github.com/*"]
}
It's important to note that the host_permissions
array in the manifest file needs to include the URL that the extension will inspect, in this case "github.com" must be added in the array. If you fail to do so, you won't ever be able to fetch the data!
The Background Script
Interaction between the content and background scripts can be achieved through message passing. In our background.js
script we'll add an event listener.
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.checkIfUrlExists) {
fetch(request.checkIfUrlExists, { method: "HEAD" })
.then(response => sendResponse({ status: response.ok }))
.catch(error => sendResponse({ status: false, error: JSON.stringify(error) }))
}
return true
})
The Content Script
With the background script set up, we can use the chrome.runtime.sendMessage
API to send messages to it. To make it easier to use async/await in our extension, we'll wrap the call in a Promise:
async function checkIfUrlExists(url) {
const response = await new Promise(resolve => {
chrome.runtime.sendMessage({ checkIfUrlExists: url }, resolve)
})
return response.status
}
Resolve URLs
My extension needs to check if a certain URL is present on GitHub. Because I don't know the exact name of the file, I'll check multiple possibilities and return the first that has a successful response status:
async function resolveUrl(name) {
let repo = "https://github.com/keescbakker/my-workload-services"
let commits = repo + "/commits/master/apps/applicationsets"
let urls = [
`${commits}/${name}.yml`,
`${commits}/${name}.yaml`,
`${commits}/${name}-service.yml`,
`${commits}/${name}-service.yaml`,
`${commits}/${name}-site.yml`,
`${commits}/${name}-site.yaml`
]
for (let url of urls) {
if (await checkIfUrlExists(url)) {
return url
}
}
return null
}
Enjoy!
Top comments (0)