mirror of
https://github.com/fmhy/FMHY-SafeGuard.git
synced 2026-03-11 08:55:40 +00:00
Add files via upload
This commit is contained in:
parent
859220c7ca
commit
a18aca4884
3 changed files with 172 additions and 12 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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  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;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue