Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 78 additions & 17 deletions background-script.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@ function get_ios_id(uri) {
}

function update_color() {
chrome.browserAction.setIcon({ path: "res/images/FF_ext_icon_" + color + ".svg" });
chrome.action.setIcon({
path: {
"48": "res/images/FF_ext_icon_" + color + "-48.png",
"96": "res/images/FF_ext_icon_" + color + "-96.png",
"128": "res/images/FF_ext_icon_" + color + "-128.png"
}
});
}

function getTab() {
Expand Down Expand Up @@ -87,7 +93,13 @@ function get_domain_info(urlStr) {
color = "orange"
}

chrome.browserAction.setIcon({ path: "res/images/FF_ext_icon_" + color + ".svg" });
chrome.action.setIcon({
path: {
"48": "res/images/FF_ext_icon_" + color + "-48.png",
"96": "res/images/FF_ext_icon_" + color + "-96.png",
"128": "res/images/FF_ext_icon_" + color + "-128.png"
}
});
return { programs: programs, security_txt: security_txt, color: color, last_programs_update: CACHE.last_programs_update, lax: lax }
}

Expand Down Expand Up @@ -218,15 +230,35 @@ async function check_security_txt(urlStr, force_update) {
for (let i = 0; i < SECURITY_TXT_PATHS.length; ++i) {
const path = SECURITY_TXT_PATHS[i]
const security_txt_url = `${protocol}//${hostname}${path}`
const content = await fetch(security_txt_url, { cache: 'no-cache', redirect: 'manual' })
.then(r => r.status == 200 && r.text())
.then(txt => txt && !txt.startsWith("<") && txt)
if (content) {
/* update and stop if found */
CACHE.security_txt[hostname].content = content
CACHE.security_txt[hostname].url = security_txt_url
CACHE.security_txt[hostname].found = true
return

try {
const response = await fetch(security_txt_url, { cache: 'no-cache', redirect: 'follow' })

if (response.ok) {
const content = await response.text()

// Check if content looks like security.txt (not HTML)
if (content && content.trim().length > 0 && !content.trim().startsWith("<!DOCTYPE") && !content.trim().startsWith("<html")) {
console.log(`[VDP Finder] Found security.txt at ${security_txt_url}`)
CACHE.security_txt[hostname].content = content
CACHE.security_txt[hostname].url = security_txt_url
CACHE.security_txt[hostname].found = true
return
} else {
console.log(`[VDP Finder] ${security_txt_url} returned HTML or empty content`)
}
} else {
console.log(`[VDP Finder] ${security_txt_url} returned status ${response.status}`)
}
} catch (err) {
const errorType = err.message.includes('certificate') || err.message.includes('SSL') || err.message.includes('TLS') ? 'SSL/Certificate Error' : 'Network Error';
console.log(`[VDP Finder] ${errorType} fetching ${security_txt_url}: ${err.message}`)

// Note: SSL errors in service workers cannot bypass certificate warnings
// that the user may have accepted in the main browser window
if (errorType === 'SSL/Certificate Error') {
console.log(`[VDP Finder] Tip: If accessing via IP, try the hostname instead. Service workers cannot bypass SSL warnings.`)
}
}
}
}
Expand All @@ -240,17 +272,21 @@ async function update_cache(force_update) {

chrome.tabs.onUpdated.addListener(_ => {
getTab().then(tab => {
check_security_txt(tab.url, false).then(_ => {
get_domain_info(tab.url)
})
if (tab && tab.url) {
check_security_txt(tab.url, false).then(_ => {
get_domain_info(tab.url)
})
}
})
});

chrome.tabs.onActivated.addListener(_ => {
getTab().then(tab => {
check_security_txt(tab.url, false).then(_ => {
get_domain_info(tab.url)
})
if (tab && tab.url) {
check_security_txt(tab.url, false).then(_ => {
get_domain_info(tab.url)
})
}
})
});

Expand All @@ -269,6 +305,31 @@ chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
case "GET_DOMAIN_INFO":
sendResponse(get_domain_info(request.data))
break;
case "SECURITY_TXT_RESULT":
// Handle security.txt result from content script
if (request.data && request.data.hostname) {
CACHE.security_txt[request.data.hostname] = {
last_update: new Date(),
content: request.data.content || "",
url: request.data.url || "",
found: request.data.found || false
};
console.log(`[VDP Finder] Security.txt cache updated for ${request.data.hostname}: ${request.data.found ? 'found' : 'not found'}`);

// Update icon if this is the active tab
if (sender.tab) {
chrome.tabs.query({ active: true, currentWindow: true }, tabs => {
if (tabs[0] && tabs[0].id === sender.tab.id) {
get_domain_info(sender.tab.url);
}
});
}
}
break;
case "CHECK_SECURITY_TXT":
// Request from content script (handled by content script itself)
sendResponse({ received: true });
break;
default:
console.error(`Unhandled message "${request.msg}"`)
break;
Expand Down
69 changes: 69 additions & 0 deletions content-script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Content script runs in page context and can bypass SSL warnings user has accepted

const SECURITY_TXT_PATHS = ['/.well-known/security.txt', '/security.txt'];

async function fetchSecurityTxt() {
const protocol = window.location.protocol;
const hostname = window.location.hostname;

// Only check HTTP/HTTPS pages
if (!["http:", "https:"].includes(protocol)) {
return null;
}

for (const path of SECURITY_TXT_PATHS) {
const security_txt_url = `${protocol}//${hostname}${path}`;

try {
const response = await fetch(security_txt_url, {
cache: 'no-cache',
redirect: 'follow',
credentials: 'omit' // Don't send cookies for security.txt
});

if (response.ok) {
const content = await response.text();

// Check if content looks like security.txt (not HTML)
if (content &&
content.trim().length > 0 &&
!content.trim().startsWith("<!DOCTYPE") &&
!content.trim().startsWith("<html")) {

console.log(`[VDP Finder Content] Found security.txt at ${security_txt_url}`);
return {
found: true,
content: content,
url: security_txt_url,
hostname: hostname
};
}
}
} catch (err) {
console.log(`[VDP Finder Content] Failed to fetch ${security_txt_url}: ${err.message}`);
}
}

return {
found: false,
hostname: hostname
};
}

// Listen for requests from background script
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.msg === "CHECK_SECURITY_TXT") {
fetchSecurityTxt().then(sendResponse);
return true; // Will respond asynchronously
}
});

// Also check on page load and notify background
fetchSecurityTxt().then(result => {
if (result) {
chrome.runtime.sendMessage({
msg: "SECURITY_TXT_RESULT",
data: result
});
}
});
33 changes: 26 additions & 7 deletions manifest.json
Original file line number Diff line number Diff line change
@@ -1,30 +1,49 @@
{
"manifest_version": 2,
"manifest_version": 3,
"name": "YesWeHack VDP Finder",
"version": "1.1.2",
"version": "1.1.6",
"description": "This extension tells if visited sites have vulnerability disclosure programs",
"homepage_url": "https://github.com/yeswehack/yeswehack_vdp_finder",

"icons": {
"16": "res/images/icon-48.png",
"32": "res/images/icon-48.png",
"48": "res/images/FF_ext_icon_red-48.png",
"96": "res/images/FF_ext_icon_red-96.png"
"96": "res/images/FF_ext_icon_red-96.png",
"128": "res/images/FF_ext_icon_red-128.png"
},

"browser_action": {
"action": {
"default_title": "YesWeHack VDP Finder",
"default_popup": "popup.html",
"default_icon": {
"16": "res/images/icon-48.png",
"32": "res/images/icon-48.png",
"48": "res/images/FF_ext_icon_gray-48.png",
"96": "res/images/FF_ext_icon_gray-96.png"
"96": "res/images/FF_ext_icon_gray-96.png",
"128": "res/images/FF_ext_icon_red-128.png"
}
},

"background": {
"scripts": ["background-script.js"]
"service_worker": "background-script.js"
},

"content_scripts": [{
"matches": ["http://*/*", "https://*/*"],
"js": ["content-script.js"],
"run_at": "document_idle"
}],

"permissions": [
"tabs",
"<all_urls>"
"activeTab"
],

"host_permissions": [
"https://firebounty.com/*",
"https://publicsuffix.org/*",
"https://*/*",
"http://*/*"
]
}
9 changes: 8 additions & 1 deletion popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ function update_content(domain_info) {

document.addEventListener("DOMContentLoaded", _ => {
getTab().then(tab => {
if (!tab || !tab.url) {
$("#domain-host").innerText = "N/A";
return;
}

const url = new URL(tab.url)
$("#domain-host").innerText = url.hostname;

Expand All @@ -88,5 +93,7 @@ function getTab() {
/* on open */

getTab().then(tab => {
chrome.runtime.sendMessage({ msg: "GET_DOMAIN_INFO", data: tab.url }, update_content);
if (tab && tab.url) {
chrome.runtime.sendMessage({ msg: "GET_DOMAIN_INFO", data: tab.url }, update_content);
}
})
Binary file added res/images/FF_ext_icon_green-128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added res/images/FF_ext_icon_green-48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added res/images/FF_ext_icon_green-96.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added res/images/FF_ext_icon_orange-128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added res/images/FF_ext_icon_orange-48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added res/images/FF_ext_icon_orange-96.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added res/images/FF_ext_icon_yellow-128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added res/images/FF_ext_icon_yellow-48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added res/images/FF_ext_icon_yellow-96.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.