Add files via upload

This commit is contained in:
Kenneth Hendricks 2026-01-25 20:24:36 -05:00 committed by GitHub
parent 859220c7ca
commit a18aca4884
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 172 additions and 12 deletions

View file

@ -50,7 +50,9 @@ const notesBaseURL =
// State Variables
let unsafeSitesRegex = null;
let unsafeHostnamesRegex = null; // Domain-only regex for unsafe sites
let potentiallyUnsafeSitesRegex = null;
let potentiallyUnsafeHostnamesRegex = null; // Domain-only regex for potentially unsafe sites
let fmhySitesRegex = null;
let fmhyHostnamesRegex = null; // Domain-only regex for FMHY sites
let safeSites = [];
@ -108,7 +110,7 @@ const notesMapping = {
// Crystal Disk Info
"crystalmark.info": "crystaldiskinfo",
// CS.RIN.RU
"cs.rin.ru": "csrin-search",
"cs.rin.ru": "csrin-search", "csrin.org": "csrin-search",
// DODI Repacks
"dodi-repacks.site": "dodi-warning",
// FileBin
@ -237,6 +239,24 @@ const notesPatterns = [
{ pattern: /^rgshows\./i, noteSlug: "rgshows-autoplay" },
];
// Hardcoded site passwords - Maps domains to their passwords
const sitePasswords = {
"cs.rin.ru": "cs.rin.ru",
"csrin.org": "csrin.org",
"online-fix.me": "online-fix.me",
"ovagames.com": "www.ovagames.com",
"g4u.to": "404",
"elenemigos.com": "elenemigos.com",
"triahgames.com": "www.triahgames.com",
"soft98.ir": "soft98.ir",
};
// Get password for a domain
function getPasswordForDomain(hostname) {
const domain = hostname.replace(/^www\./, "").toLowerCase();
return sitePasswords[domain] || null;
}
// Get note slug for a domain
function getNoteSlugForDomain(hostname) {
const domain = hostname.replace(/^www\./, "").toLowerCase();
@ -442,6 +462,9 @@ async function fetchFilterLists() {
const unsafeText = await unsafeResponse.text();
unsafeSites = extractUrlsFromFilterList(unsafeText);
unsafeSitesRegex = generateRegexFromList(unsafeSites);
// Also generate hostname-only regex for domain-level matching
const unsafeHostnames = extractHostnamesFromUrls(unsafeSites);
unsafeHostnamesRegex = generateRegexFromList(unsafeHostnames);
}
if (potentiallyUnsafeResponse.ok) {
@ -450,6 +473,9 @@ async function fetchFilterLists() {
potentiallyUnsafeSitesRegex = generateRegexFromList(
potentiallyUnsafeSites
);
// Also generate hostname-only regex for domain-level matching
const potentiallyUnsafeHostnames = extractHostnamesFromUrls(potentiallyUnsafeSites);
potentiallyUnsafeHostnamesRegex = generateRegexFromList(potentiallyUnsafeHostnames);
}
if (fmhyResponse.ok) {
@ -839,11 +865,11 @@ browserAPI.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (status === "no_data" && !isRepoSite) {
console.log(`No match for full URL, trying domain: ${domain}`);
// Check domain against regex patterns
if (unsafeSitesRegex?.test(domain)) {
// Check domain against regex patterns (use hostname-only regex for domain matching)
if (unsafeHostnamesRegex?.test(domain)) {
status = "unsafe";
matchedUrl = `https://${domain}`;
} else if (potentiallyUnsafeSitesRegex?.test(domain)) {
} else if (potentiallyUnsafeHostnamesRegex?.test(domain)) {
status = "potentially_unsafe";
matchedUrl = `https://${domain}`;
} else if (fmhyHostnamesRegex?.test(domain)) {
@ -889,10 +915,13 @@ browserAPI.runtime.onMessage.addListener((message, sender, sendResponse) => {
reason = await getReasonForDomain(domain);
}
// Get password if available
const password = getPasswordForDomain(domain);
console.log(
`getSiteStatus result for ${url}: ${status}, matched: ${matchedUrl}`
);
sendResponse({ status: status, matchedUrl: matchedUrl, reason: reason });
sendResponse({ status: status, matchedUrl: matchedUrl, reason: reason, password: password });
} catch (error) {
console.error("Error in getSiteStatus handler:", error);
sendResponse({
@ -978,9 +1007,9 @@ function getStatusFromLists(url) {
if (starredSites.includes(url)) return "starred";
if (safeSites.includes(url)) return "safe";
// Then check domain-level
if (unsafeSitesRegex?.test(domain)) return "unsafe";
if (potentiallyUnsafeSitesRegex?.test(domain)) return "potentially_unsafe";
// Then check domain-level (use hostname-only regex for domain matching)
if (unsafeHostnamesRegex?.test(domain)) return "unsafe";
if (potentiallyUnsafeHostnamesRegex?.test(domain)) return "potentially_unsafe";
if (fmhyHostnamesRegex?.test(domain)) return "fmhy";
// Try domain-level checks for starred and safe
@ -1148,6 +1177,9 @@ async function initializeExtension() {
if (storedData.unsafeSites && storedData.unsafeSites.length > 0) {
unsafeSitesRegex = generateRegexFromList(storedData.unsafeSites);
// Also generate hostname-only regex for domain-level matching
const unsafeHostnames = extractHostnamesFromUrls(storedData.unsafeSites);
unsafeHostnamesRegex = generateRegexFromList(unsafeHostnames);
}
if (
@ -1157,6 +1189,9 @@ async function initializeExtension() {
potentiallyUnsafeSitesRegex = generateRegexFromList(
storedData.potentiallyUnsafeSites
);
// Also generate hostname-only regex for domain-level matching
const potentiallyUnsafeHostnames = extractHostnamesFromUrls(storedData.potentiallyUnsafeSites);
potentiallyUnsafeHostnamesRegex = generateRegexFromList(potentiallyUnsafeHostnames);
}
if (storedData.fmhySites && storedData.fmhySites.length > 0) {

View file

@ -182,6 +182,67 @@
transform: scale(1.1);
}
/* Password Section Styles */
#password-container {
margin-top: 15px;
padding: 10px;
background: var(--hover-bg);
border-radius: 8px;
text-align: left;
display: none;
}
#password-container.visible {
display: block;
}
#password-title {
font-size: 13px;
font-weight: 600;
color: #4ecdc4;
margin-bottom: 8px;
display: flex;
align-items: center;
gap: 6px;
}
#password-title svg {
stroke: #4ecdc4;
}
#password-content {
font-size: 14px;
font-weight: 600;
font-family: monospace;
color: var(--text-color);
background: var(--bg-color);
padding: 6px 10px;
border-radius: 4px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
#password-content:hover {
background: var(--hover-bg);
}
#password-content .copy-icon {
opacity: 0.5;
flex-shrink: 0;
}
#password-content:hover .copy-icon {
opacity: 1;
}
#password-content.copied {
background: #4ecdc4;
color: #000;
}
/* Reason Section Styles */
#reason-container {
margin-top: 15px;
@ -286,6 +347,13 @@
border-radius: 3px;
font-size: 11px;
}
#note-content img {
max-width: 100%;
height: auto;
border-radius: 4px;
margin: 8px 0;
}
</style>
</head>
@ -306,6 +374,22 @@
<p id="status-message" data-i18n="checkingSiteStatus">Checking site status...</p>
</div>
<p id="error-message"></p>
<div id="password-container">
<div id="password-title">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect width="18" height="11" x="3" y="11" rx="2" ry="2"></rect>
<path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
</svg>
<span>Password</span>
</div>
<div id="password-content">
<span id="password-text"></span>
<svg class="copy-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect>
<path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path>
</svg>
</div>
</div>
<div id="reason-container">
<div id="reason-title">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">

View file

@ -56,11 +56,28 @@ document.addEventListener("DOMContentLoaded", async () => {
function parseMarkdown(md) {
if (!md) return "";
// Store images to protect from URL linking
const imgTags = [];
let result = md
// Remove the main header (#### Title) since we show "FMHY Note" already
.replace(/^#{1,4}\s+.*$/gm, '')
// Trim leading/trailing whitespace
.trim()
.trim();
// Protect HTML img tags from URL linking
result = result.replace(/<img[^>]*>/gi, (match) => {
imgTags.push(match);
return `[[HTMLIMG_${imgTags.length - 1}]]`;
});
// Convert markdown images ![alt](url) to placeholder
result = result.replace(/!\[(.*?)\]\((.*?)\)/g, (match, alt, url) => {
imgTags.push(`<img src="${url}" alt="${alt}" />`);
return `[[HTMLIMG_${imgTags.length - 1}]]`;
});
result = result
// Bold (must come before italic)
.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
// Italic
@ -68,11 +85,14 @@ document.addEventListener("DOMContentLoaded", async () => {
// Markdown links [text](url) - use placeholder to avoid double-linking
.replace(/\[(.*?)\]\((.*?)\)/g, '[[LINK:$2:$1]]');
// Raw URLs (convert before restoring markdown links)
// Raw URLs (convert before restoring markdown links and images)
result = result.replace(/(https?:\/\/[^\s<>\)\]]+)/g, '<a href="$1" target="_blank">$1</a>');
// Restore markdown links from placeholders
result = result.replace(/\[\[LINK:(.*?):(.*?)\]\]/g, '<a href="$1" target="_blank">$2</a>');
// Restore images from placeholders
result = result.replace(/\[\[HTMLIMG_(\d+)\]\]/g, (match, index) => imgTags[parseInt(index)]);
result = result
// Code
@ -287,7 +307,7 @@ document.addEventListener("DOMContentLoaded", async () => {
}
// Update the popup with the result
handleStatusUpdate(response.status, displayUrl, response.reason);
handleStatusUpdate(response.status, displayUrl, response.reason, response.password);
} catch (error) {
console.error("Error checking site status:", error);
errorMessage.textContent = `Error: ${error.message}`;
@ -295,7 +315,7 @@ document.addEventListener("DOMContentLoaded", async () => {
}
}
function handleStatusUpdate(status, displayUrl, reason) {
function handleStatusUpdate(status, displayUrl, reason, password) {
let message;
// Handle reason display in dedicated container
@ -309,6 +329,27 @@ document.addEventListener("DOMContentLoaded", async () => {
reasonContainer.classList.remove("visible");
}
// Handle password display
const passwordContainer = document.getElementById("password-container");
const passwordText = document.getElementById("password-text");
const passwordContent = document.getElementById("password-content");
if (password && passwordContainer && passwordText) {
passwordText.textContent = password;
passwordContainer.classList.add("visible");
// Add click-to-copy functionality
passwordContent.onclick = async () => {
try {
await navigator.clipboard.writeText(password);
passwordContent.classList.add("copied");
setTimeout(() => passwordContent.classList.remove("copied"), 1000);
} catch (err) {
console.error("Failed to copy password:", err);
}
};
} else if (passwordContainer) {
passwordContainer.classList.remove("visible");
}
// Use i18n for status messages if available
const getMessage = window.i18n ? window.i18n.getMessage : (key, sub) => null;