BlurBase
Junior Member
- Aug 2, 2025
- 101
- 19
A simple F12 console script for Facebook that helps you:
Quote:
Script:
- Add or remove emails
- Remove phone numbers
- Remove logged-in devices
- Check and list linked emails
Quote:
Note: This script is intended for those who purchase Facebook accounts from third parties but cannot remove or change the existing information right after receiving the account.
Script:
Code:
// Initialize global variables to store data
let userId = null;
let emailList = [];
let emailDetails = [];
let trustedTypesPolicy = null;
// Function to handle safe HTML content with Trusted Types
function setSafeHTML(element, htmlContent) {
// Check and initialize Trusted Types if not already set
if (!trustedTypesPolicy && window.trustedTypes && window.trustedTypes.createPolicy) {
try {
trustedTypesPolicy = window.trustedTypes.createPolicy("extension-html-policy", {
createHTML: (input) => input,
});
} catch (error) {
console.log("Unable to create TrustedHTML policy, using fallback:", error);
}
}
// Assign safe HTML content
element.innerHTML = trustedTypesPolicy ? trustedTypesPolicy.createHTML(htmlContent) : htmlContent;
}
// Function to get user ID from CurrentUserInitialData
function getUserId() {
try {
userId = require("CurrentUserInitialData").ACCOUNT_ID;
} catch (error) {
console.log("Unable to retrieve user_id:", error);
}
}
// Function to send GraphQL request to Facebook
async function sendGraphQLRequest(params) {
const response = await fetch("https://accountscenter.facebook.com/api/graphql/", {
headers: {
accept: "*/*",
"accept-language": "en-US,en;q=0.9",
"content-type": "application/x-www-form-urlencoded",
priority: "u=1, i",
"sec-ch-prefers-color-scheme": "light",
"sec-ch-ua": '"Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"',
"sec-ch-ua-full-version-list": '"Chromium";v="128.0.6613.115", "Not;A=Brand";v="24.0.0.0", "Google Chrome";v="128.0.6613.115"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-model": '""',
"sec-ch-ua-platform": '"Windows"',
"sec-ch-ua-platform-version": '"10.0.0"',
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"x-asbd-id": "129477",
"x-fb-friendly-name": "CometIXTFacebookAuthenticityWizardTriggerRootQuery",
"x-fb-lsd": "y1DTil2xKxt97rVwoHzTaP=",
},
referrer: "https://www.facebook.com",
referrerPolicy: "strict-origin-when-cross-origin",
body: new URLSearchParams(params),
method: "POST",
mode: "cors",
credentials: "include",
});
return await response.json();
}
// Function to load email data from Facebook
async function loadEmailData() {
if (!userId) return;
emailList = [];
emailDetails = [];
try {
const { fb_dtsg } = getFormTokens();
const response = await sendGraphQLRequest({
av: userId,
dpr: "1",
fb_dtsg,
fb_api_caller_class: "RelayModern",
fb_api_req_friendly_name: "FXAccountsCenterContactPointRootQuery",
variables: '{"interface":"FB_WEB"}',
server_timestamps: "true",
doc_id: "9849298431773678",
});
const contactPoints = response.data?.fxcal_settings?.node?.all_contact_points || [];
contactPoints.forEach((point) => {
if (point.contact_point_type === "EMAIL") {
emailList.push(point.normalized_contact_point);
}
});
for (const email of emailList) {
const detailResponse = await sendGraphQLRequest({
av: userId,
fb_dtsg,
fb_api_caller_class: "RelayModern",
fb_api_req_friendly_name: "FXAccountsCenterContactDetailQuery",
variables: `{"contact_point_type":"email","interface":"FB_WEB","normalized_contact_point":"${email}"}`,
server_timestamps: "true",
doc_id: "24075759928744735",
});
const contactInfo = detailResponse.data?.fxcal_settings?.node?.read_contact_point?.contact_point_info || [];
const linkedAccounts = contactInfo.map((info) => ({
platform: info.owner_profile.platform_info.type,
status: info.contact_point_status,
}));
emailDetails.push({ email, linked: linkedAccounts });
}
} catch (error) {
console.error("Error loading email data:", error);
}
}
// Function to load Google Fonts
function loadGoogleFonts() {
try {
const preconnect1 = document.createElement("link");
preconnect1.rel = "preconnect";
preconnect1.href = "https://fonts.googleapis.com";
const preconnect2 = document.createElement("link");
preconnect2.rel = "preconnect";
preconnect2.href = "https://fonts.gstatic.com";
preconnect2.crossOrigin = "anonymous";
const fontLink = document.createElement("link");
fontLink.rel = "stylesheet";
fontLink.href = "https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800&display=swap";
document.head.append(preconnect1, preconnect2, fontLink);
} catch (error) {
console.log("Error loading fonts:", error);
}
}
// Function to get tokens from form or require
function getFormTokens() {
const tokens = {};
for (const name of ["fb_dtsg", "lsd", "jazoest"]) {
const input = document.querySelector(`input[name="${name}"]`);
if (input) tokens[name] = input.value;
}
if (window.require) {
try {
tokens.fb_dtsg = tokens.fb_dtsg || require("DTSGInitialData").token || require("DTSG").getToken();
tokens.lsd = tokens.lsd || require("LSD").token;
tokens.__user = require("CurrentUserInitialData").USER_ID;
} catch {}
}
tokens.jazoest = tokens.jazoest || "25443";
return tokens;
}
// Function to send verification email
async function sendVerificationEmail(email) {
const { fb_dtsg, lsd, jazoest, __user } = getFormTokens();
if (!fb_dtsg || !lsd) throw new Error("Unable to retrieve fb_dtsg/lsd");
const url =
"/developer/profile_email/send_confirmation_email/?" +
new URLSearchParams({
email,
referrer: "DeveloperRegistrationEmailContactUpdateDialog",
});
const params = new URLSearchParams({
__a: "1",
dpr: String(devicePixelRatio || 1),
fb_dtsg,
lsd,
jazoest,
});
if (__user) params.set("__user", __user);
const response = await fetch(url, {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"x-fb-lsd": lsd,
},
body: params.toString(),
});
return JSON.parse(String(await response.text()).replace(/^for\s*\(;;\);\s*/, ""));
}
// Function to check if an element is visible
function isElementVisible(element) {
if (!element) return false;
const style = getComputedStyle(element);
const rect = element.getBoundingClientRect();
return style.visibility !== "hidden" && style.display !== "none" && style.opacity !== "0" && rect.width > 60 && rect.height > 24 && rect.bottom > 0 && rect.right > 0;
}
// Function to get element text
function getElementText(element) {
return (element.getAttribute?.("aria-label") || element.innerText || element.textContent || "").trim().toLowerCase();
}
// List of keywords for "Continue" button
const continueKeywords = [
"continue",
"next",
"proceed",
"продолж",
"продовж",
"continuar",
"continua",
"continuare",
"proseguir",
"fortsetzen",
"weiter",
"继续",
"繼續",
"続行",
"次へ",
"계속",
"seguir",
"pokračovat",
"lanjut",
"ต่อ",
];
// Function to check if a button is a "Continue" button
function isContinueButton(text) {
return continueKeywords.some((keyword) => text.includes(keyword));
}
// Function to score a button to determine the best "Continue" button
function scoreButton(element) {
const text = getElementText(element);
let score = isContinueButton(text) ? 3 : 0;
const style = getComputedStyle(element).backgroundColor.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/i);
if (style) {
const [_, r, g, b] = style.slice(1).map(Number);
score += Math.hypot(r - 24, g - 119, b - 242) < 80 ? 3 : 0;
}
score += element.getBoundingClientRect().x > innerWidth / 2 ? 1 : 0;
return score;
}
// Function to find the best "Continue" button
function findBestContinueButton() {
const buttons = [...document.querySelectorAll('button,[role="button"],a[role="button"]')].filter(isElementVisible).filter((btn) => isContinueButton(getElementText(btn)));
return buttons.sort((a, b) => scoreButton(b) - scoreButton(a))[0] || null;
}
// Function to create user interface
function createUI() {
// Remove existing UI if present
const existingUI = document.getElementById("main-extension-ui");
if (existingUI) existingUI.remove();
loadGoogleFonts();
const uiContainer = document.createElement("div");
uiContainer.id = "main-extension-ui";
uiContainer.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
width: 500px;
max-height: 700px;
background: white;
border: 2px solid #1877f2;
border-radius: 12px;
box-shadow: 0 8px 32px rgba(0,0,0,0.2);
z-index: 999999;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
overflow: hidden;
transform: translateZ(0);
will-change: transform;
display: flex;
flex-direction: column;
`;
// Create header
const header = document.createElement("div");
header.style.cssText = `
background: linear-gradient(135deg, #1877f2, #0d5ed4);
color: white;
padding: 16px 20px;
font-weight: 700;
font-size: 18px;
display: flex;
justify-content: space-between;
align-items: center;
`;
const title = document.createElement("span");
title.textContent = "Catch Me If You Can";
const closeButton = document.createElement("button");
closeButton.id = "close-ui";
closeButton.textContent = "×";
closeButton.style.cssText = `
background: none;
border: none;
color: white;
font-size: 24px;
cursor: pointer;
padding: 0;
width: 30px;
height: 30px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.2s;
`;
closeButton.onmouseover = () => (closeButton.style.background = "rgba(255,255,255,0.2)");
closeButton.onmouseout = () => (closeButton.style.background = "none");
header.appendChild(title);
header.appendChild(closeButton);
// Create tab navigation
const tabsContainer = document.createElement("div");
tabsContainer.style.cssText = `
display: flex;
background: #f8f9fa;
border-bottom: 1px solid #e1e8ed;
`;
const tabs = [
{ id: "email-info", label: "Email", active: true },
{ id: "delete-email", label: "Delete Email", active: false },
{ id: "add-email", label: "Add Email", active: false },
{ id: "delete-phone", label: "Delete Phone", active: false },
{ id: "delete-trust", label: "Delete Device", active: false },
];
tabs.forEach((tab) => {
const tabButton = document.createElement("button");
tabButton.className = "tab-btn";
tabButton.dataset.tab = tab.id;
tabButton.textContent = tab.label;
tabButton.style.cssText = `
flex: 1;
padding: 5px 10px;
border: none;
background: ${tab.active ? "#1877f2" : "transparent"};
color: ${tab.active ? "white" : "#65676b"};
font-weight: 600;
font-size: 14px;
cursor: pointer;
transition: all 0.2s;
`;
tabButton.addEventListener("click", () => switchTab(tab.id));
tabsContainer.appendChild(tabButton);
});
// Create content area
const contentArea = document.createElement("div");
contentArea.id = "content-area";
contentArea.style.cssText = `
flex: 1;
overflow-y: auto;
padding: 20px;
min-height: 0;
`;
// Create status bar
const statusBar = document.createElement("div");
statusBar.id = "status-bar";
statusBar.style.cssText = `
padding: 12px 20px;
background: #f8f9fa;
border-top: 1px solid #e1e8ed;
font-size: 14px;
color: #65676b;
text-align: center;
`;
statusBar.textContent = "Ready to use";
// Create footer
const footer = document.createElement("div");
footer.style.cssText = `
padding: 8px 20px;
background: #e8f5e8;
border-top: 1px solid #d4edda;
font-size: 12px;
color: #155724;
text-align: center;
font-weight: 500;
`;
setSafeHTML(
footer,
`
<strong style="color: #0d5ed4;"><a href="#">BlurBase</a></strong>
`
);
// Append components to container
uiContainer.appendChild(header);
uiContainer.appendChild(tabsContainer);
uiContainer.appendChild(contentArea);
uiContainer.appendChild(statusBar);
uiContainer.appendChild(footer);
// Handle UI close event
closeButton.addEventListener("click", () => uiContainer.remove());
document.body.appendChild(uiContainer);
// Handle default tab based on URL
const currentUrl = window.location.href;
if (currentUrl.includes("accountscenter.facebook.com")) {
switchTab("email-info");
} else if (currentUrl.includes("developers.facebook.com/async/registration/dialog/") || currentUrl.includes("developers.facebook.com/apps")) {
switchTab("add-email");
} else if (currentUrl.includes("facebook.com") && currentUrl.includes("allactivity") && currentUrl.includes("category_key=RECOGNIZEDDEVICES")) {
switchTab("delete-trust");
} else {
showEmailInfoTab();
}
}
// Function to switch between tabs
function switchTab(tabId) {
const currentUrl = window.location.href;
if (tabId === "email-info" && !currentUrl.includes("accountscenter.facebook.com")) {
updateStatusBar("Redirecting to Account Center...", "info");
window.location.href = "https://accountscenter.facebook.com";
return;
} else if (
(tabId === "add-email" || tabId === "delete-phone") &&
!currentUrl.includes("developers.facebook.com/async/registration/dialog/") &&
!currentUrl.includes("developers.facebook.com/apps/")
) {
updateStatusBar("Redirecting to Facebook Developers...", "info");
window.location.href = "https://developers.facebook.com/async/registration/dialog/";
return;
} else if (tabId === "delete-trust" && (!currentUrl.includes("facebook.com") || !currentUrl.includes("allactivity") || !currentUrl.includes("category_key=RECOGNIZEDDEVICES"))) {
updateStatusBar("Redirecting to Activity page...", "info");
window.location.href = "https://www.facebook.com/4/allactivity?category_key=RECOGNIZEDDEVICES&entry_point=ayi_hub";
return;
}
document.querySelectorAll(".tab-btn").forEach((btn) => {
const isActive = btn.dataset.tab === tabId;
btn.style.background = isActive ? "#1877f2" : "transparent";
btn.style.color = isActive ? "white" : "#65676b";
});
if (tabId === "email-info") {
showEmailInfoTab();
} else if (tabId === "add-email") {
showAddEmailTab();
} else if (tabId === "delete-email") {
showDeleteEmailTab();
} else if (tabId === "delete-phone") {
showDeletePhoneTab();
} else if (tabId === "delete-trust") {
showDeleteTrustTab();
}
}
// Function to display Email Info tab
function showEmailInfoTab() {
const contentArea = document.getElementById("content-area");
if (!contentArea) return;
if (!window.location.href.includes("accountscenter.facebook.com")) {
setSafeHTML(
contentArea,
`
<div style="text-align: center; padding: 40px 20px;">
<div style="color: #e74c3c; font-size: 48px; margin-bottom: 16px;">!</div>
<h3 style="color: #1c1e21; margin-bottom: 12px;">Incorrect Page</h3>
<p style="color: #65676b; margin-bottom: 20px;">The Email Info feature requires you to be on the Account Center page.</p>
<button onclick="window.location.href='https://accountscenter.facebook.com'"
style="padding: 12px 24px; background: #1877f2; color: white; border: none; border-radius: 8px; cursor: pointer; font-weight: 600;">
Go to Account Center
</button>
</div>
`
);
return;
}
setSafeHTML(
contentArea,
`
<div style="margin-bottom: 16px;">
<div style="display: flex; gap: 10px; margin-bottom: 16px; flex-wrap: wrap;">
<button id="select-all-emails" style="padding: 5px 16px; background: #42b883; color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 13px;">Select All</button>
<button id="deselect-all-emails" style="padding: 5px 16px; background: #e74c3c; color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 13px;">Deselect All</button>
<button id="copy-selected-emails" style="padding: 5px 16px; background: #1877f2; color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 13px;">Copy Selected</button>
<button id="reload-email-data" style="padding: 5px 16px; background: #ff6b35; color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 13px;">Reload Data</button>
</div>
<div id="email-list-container"></div>
</div>
`
);
updateEmailList();
// Attach event listeners to buttons
document.getElementById("select-all-emails")?.addEventListener("click", () => {
document.querySelectorAll('input[type="checkbox"]').forEach((checkbox) => (checkbox.checked = true));
});
document.getElementById("deselect-all-emails")?.addEventListener("click", () => {
document.querySelectorAll('input[type="checkbox"]').forEach((checkbox) => (checkbox.checked = false));
});
document.getElementById("copy-selected-emails")?.addEventListener("click", () => {
const selectedEmails = [];
document.querySelectorAll('input[type="checkbox"]').forEach((checkbox, index) => {
if (checkbox.checked) selectedEmails.push(emailDetails[index].email);
});
if (selectedEmails.length === 0) {
updateStatusBar("Please select at least one email!", "error");
return;
}
navigator.clipboard
.writeText(selectedEmails.join(","))
.then(() => updateStatusBar(`Copied ${selectedEmails.length} email(s)!`, "success"))
.catch(() => updateStatusBar("Unable to copy emails.", "error"));
});
document.getElementById("reload-email-data")?.addEventListener("click", async () => {
const button = document.getElementById("reload-email-data");
button.disabled = true;
button.textContent = "Loading...";
updateStatusBar("Loading email data...", "info");
try {
await loadEmailData();
updateEmailList();
updateStatusBar(`Loaded ${emailDetails.length} email(s)`, "success");
} catch (error) {
updateStatusBar("Unable to load email data", "error");
}
button.disabled = false;
button.textContent = "Reload Data";
});
// Automatically load data if not already loaded
if (emailDetails.length === 0 && userId) {
setTimeout(async () => {
const button = document.getElementById("reload-email-data");
if (button) {
button.disabled = true;
button.textContent = "Auto-loading...";
updateStatusBar("Automatically loading email data from Account Center...", "info");
try {
await loadEmailData();
updateEmailList();
updateStatusBar(`Automatically loaded ${emailDetails.length} email(s) from Account Center`, "success");
} catch (error) {
updateStatusBar("Unable to automatically load email data", "error");
}
button.disabled = false;
button.textContent = "Reload Data";
}
}, 500);
}
}
// Function to update email list
function updateEmailList() {
const emailListContainer = document.getElementById("email-list-container");
if (!emailListContainer) return;
if (emailDetails.length > 0) {
setSafeHTML(
emailListContainer,
emailDetails
.map(
(item, index) => `
<div style="border: 1px solid #e1e8ed; border-radius: 8px; margin-bottom: 12px; padding: 16px; background: #f8f9fa;">
<div style="display: flex; align-items: center; margin-bottom: 12px;">
<input type="checkbox" id="email-${index}" style="margin-right: 12px; transform: scale(1.2);">
<label for="email-${index}" style="font-weight: 600; color: #1c1e21; cursor: pointer; flex: 1;">${item.email}</label>
</div>
<div style="margin-left: 32px;">
${item.linked
.map(
(link) => `
<div style="display: flex; justify-content: space-between; padding: 6px 12px; margin: 4px 0; background: white; border-radius: 6px; font-size: 13px;">
<span style="font-weight: 500;">${link.platform}</span>
<span style="padding: 2px 8px; border-radius: 4px; color: white; font-weight: 500; background: ${link.status === "CONFIRMED" ? "#42b883" : "#e74c3c"};">${
link.status
}</span>
</div>
`
)
.join("")}
</div>
</div>
`
)
.join("")
);
} else {
setSafeHTML(emailListContainer, `<div style="text-align: center; color: #65676b; padding: 20px;">No emails found. Click "Reload Data" to fetch.</div>`);
}
}
// Function to display Add Email tab
function showAddEmailTab() {
const contentArea = document.getElementById("content-area");
if (!contentArea) return;
const currentUrl = window.location.href;
if (!currentUrl.includes("developers.facebook.com/async/registration/dialog/") && !currentUrl.includes("developers.facebook.com/apps/")) {
setSafeHTML(
contentArea,
`
<div style="text-align: center; padding: 40px 20px;">
<div style="color: #e74c3c; font-size: 48px; margin-bottom: 16px;">!</div>
<h3 style="color: #1c1e21; margin-bottom: 12px;">Incorrect Page</h3>
<p style="color: #65676b; margin-bottom: 20px;">The Add Email feature requires you to be on the Facebook Developers page and have registered an app first.</p>
<button onclick="window.location.href='https://developers.facebook.com/async/registration/dialog/'"
style="padding: 12px 24px; background: #1877f2; color: white; border: none; border-radius: 8px; cursor: pointer; font-weight: 600;">
Go to Developers Page
</button>
</div>
`
);
return;
}
setSafeHTML(
contentArea,
`
<div style="margin-bottom: 20px;">
<h3 style="margin: 0 0 16px 0; color: #1c1e21; font-size: 16px;">Add Email to Facebook</h3>
<div style="display: grid; grid-template-columns: 1fr auto; gap: 12px; align-items: center; margin-bottom: 16px;">
<input id="add-email-input" type="email" placeholder="[email protected]" style="padding: 12px 16px; border: 2px solid #e1e8ed; border-radius: 8px; font-size: 14px; outline: none;">
<button id="send-email-btn" style="padding: 12px 20px; background: #1877f2; color: white; border: none; border-radius: 8px; cursor: pointer; font-weight: 600;">Send Confirmation</button>
</div>
<button id="open-email-confirm" style="display: none; padding: 10px 16px; background: #42b883; color: white; border: none; border-radius: 6px; cursor: pointer; margin-top: 8px;">Open Confirmation Link</button>
</div>
`
);
// Attach event listener for sending email
const emailInput = document.getElementById("add-email-input");
const sendButton = document.getElementById("send-email-btn");
const confirmButton = document.getElementById("open-email-confirm");
sendButton?.addEventListener("click", async () => {
const email = emailInput?.value?.trim();
if (!email) {
updateStatusBar("Please enter an email", "error");
return;
}
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
updateStatusBar("Invalid email format", "error");
return;
}
sendButton.disabled = true;
sendButton.textContent = "Sending...";
updateStatusBar("Sending confirmation email...", "info");
try {
await sendVerificationEmail(email);
updateStatusBar("Confirmation email sent successfully!", "success");
const confirmUrl =
`https://m.facebook.com/caa/reg/confirmation/?` +
new URLSearchParams({
reg_info: JSON.stringify({
contactpoint: email,
contactpoint_type: "email",
is_cp_auto_confirmed: false,
fb_conf_source: null,
confirmation_medium: null,
registration_flow_id: "38181147-d1ca-462e-8692-89f2e046f0b1",
}),
flow_info: JSON.stringify({
flow_name: "new_to_family_fb_default",
flow_type: "ntf",
}),
current_step: "10",
}).toString();
confirmButton.style.display = "inline-block";
confirmButton.onclick = () => window.open(confirmUrl, "_blank", "noopener");
} catch (error) {
updateStatusBar("Error: " + (error.message || "Unknown error"), "error");
}
sendButton.disabled = false;
sendButton.textContent = "Send Confirmation";
});
}
// Function to display Delete Email tab
function showDeleteEmailTab() {
const contentArea = document.getElementById("content-area");
if (!contentArea) return;
if (!window.location.href.includes("accountscenter.facebook.com")) {
setSafeHTML(
contentArea,
`
<div style="text-align: center; padding: 40px 20px;">
<div style="color: #e74c3c; font-size: 48px; margin-bottom: 16px;">!</div>
<h3 style="color: #1c1e21; margin-bottom: 12px;">Incorrect Page</h3>
<p style="color: #65676b; margin-bottom: 20px;">The Delete Email feature requires you to be on the Account Center page.</p>
<button onclick="window.location.href='https://accountscenter.facebook.com'"
style="padding: 12px 24px; background: #1877f2; color: white; border: none; border-radius: 8px; cursor: pointer; font-weight: 600;">
Go to Account Center
</button>
</div>
`
);
return;
}
setSafeHTML(
contentArea,
`
<div style="margin-bottom: 20px;">
<h3 style="margin: 0 0 16px 0; color: #1c1e21; font-size: 16px;">Delete Email from Facebook</h3>
<div style="background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 8px; padding: 16px; margin-bottom: 16px;">
<div style="color: #856404; font-size: 14px; line-height: 1.5;">
<strong>Warning:</strong> This action will permanently delete the email from your Facebook account.
Make sure before proceeding.
</div>
</div>
<div style="display: grid; grid-template-columns: 150px 1fr; gap: 12px; align-items: center; margin-bottom: 16px;">
<label style="font-weight: 600; color: #1c1e21;">Concurrency:</label>
<input id="delete-concurrency" type="number" value="50" min="1" max="10000" style="padding: 8px 12px; border: 2px solid #e1e8ed; border-radius: 6px; font-size: 14px; outline: none;">
</div>
<div style="display: flex; gap: 10px; margin-bottom: 16px;">
<button id="auto-delete-btn" style="padding: 8px 16px; background: #fd7e14; color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 13px;">Auto Delete All</button>
<button id="load-email-data-btn" style="padding: 8px 16px; background: #17a2b8; color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 13px;">Load Email Data</button>
</div>
<div id="loaded-emails-display" style="background: #e8f5e8; border: 1px solid #28a745; border-radius: 8px; padding: 16px; margin-bottom: 16px; display: none;">
<h4 style="margin: 0 0 12px 0; color: #155724; font-size: 14px;">Emails Loaded from Email Info Tab:</h4>
<div id="loaded-emails-list" style="max-height: 150px; overflow-y: auto; background: white; border-radius: 6px; padding: 12px;">
<!-- Email list will be displayed here -->
</div>
<div style="margin-top: 12px; display: flex; gap: 8px;">
<button id="delete-selected-loaded" style="padding: 8px 16px; background: #e74c3c; color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 13px;">Delete Selected</button>
<button id="delete-all-loaded" style="padding: 8px 16px; background: #dc3545; color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 13px;">Delete All</button>
<button id="clear-loaded-emails" style="padding: 8px 16px; background: #6c757d; color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 13px;">Clear List</button>
</div>
</div>
<div id="delete-email-stats" style="background: #f8f9fa; border-radius: 8px; padding: 16px; display: none;">
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; text-align: center;">
<div>
<div style="font-size: 24px; font-weight: 700; color: #e74c3c;" id="emails-deleted">0</div>
<div style="font-size: 12px; color: #65676b;">Deleted</div>
</div>
<div>
<div style="font-size: 24px; font-weight: 700; color: #dc3545;" id="delete-errors">0</div>
<div style="font-size: 12px; color: #65676b;">Errors</div>
</div>
<div>
<div style="font-size: 16px; font-weight: 600; color: #1877f2;" id="delete-status">Ready</div>
<div style="font-size: 12px; color: #65676b;">Status</div>
</div>
</div>
<div style="margin-top: 12px; display: flex; gap: 8px; justify-content: center;">
<button id="pause-delete" style="padding: 6px 12px; background: #f39c12; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 12px;" disabled>Pause</button>
<button id="stop-delete" style="padding: 6px 12px; background: #e74c3c; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 12px;" disabled>Stop</button>
<button id="clear-log" style="padding: 6px 12px; background: #6c757d; color: white; border: none; border-radius: 4px; cursor: pointer; font-size: 12px;">Clear Log</button>
</div>
</div>
<div id="delete-email-log" style="background: #f8f9fa; border-radius: 8px; padding: 16px; margin-top: 16px; display: none;">
<h4 style="margin: 0 0 12px 0; color: #1c1e21; font-size: 14px; display: flex; justify-content: space-between; align-items: center;">
<span>Activity Log</span>
<span id="log-count" style="font-size: 12px; color: #65676b;">0 entries</span>
</h4>
<div id="log-container" style="background: #ffffff; border: 1px solid #e1e8ed; border-radius: 6px; padding: 12px; height: 200px; overflow-y: auto; font-family: 'Courier New', monospace; font-size: 12px; line-height: 1.4;">
<div style="color: #65676b; text-align: center; padding: 20px;">Logs will be displayed here...</div>
</div>
</div>
</div>
`
);
// Attach event listeners to buttons
const autoDeleteButton = document.getElementById("auto-delete-btn");
const loadEmailButton = document.getElementById("load-email-data-btn");
const pauseButton = document.getElementById("pause-delete");
const stopButton = document.getElementById("stop-delete");
const clearLogButton = document.getElementById("clear-log");
clearLogButton?.addEventListener("click", () => {
logEntries = [];
const logContainer = document.getElementById("log-container");
if (logContainer) {
setSafeHTML(logContainer, `<div style="color: #65676b; text-align: center; padding: 20px;">Log cleared...</div>`);
}
updateLogCount();
});
loadEmailButton?.addEventListener("click", () => {
if (emailDetails.length > 0) {
displayLoadedEmails();
updateStatusBar(`Loaded ${emailDetails.length} email(s) from Email Info tab`, "success");
} else {
updateStatusBar("No email data found. Please go to the Email Info tab and reload data first.", "error");
}
});
autoDeleteButton?.addEventListener("click", () => {
if (emailDetails.length === 0) {
updateStatusBar("No emails found. Please load email data first using the 'Load Email Data' button.", "error");
return;
}
deleteEmails(emailDetails.map((item) => item.email));
});
pauseButton?.addEventListener("click", () => {
deleteState.paused = !deleteState.paused;
pauseButton.textContent = deleteState.paused ? "Resume" : "Pause";
updateDeleteStatus();
});
stopButton?.addEventListener("click", () => {
deleteState.stop = true;
deleteState.running = false;
pauseButton.disabled = true;
stopButton.disabled = true;
pauseButton.textContent = "Pause";
updateStatusBar("Email deletion process stopped!", "warning");
updateDeleteStatus();
});
// Auto-load emails if available
if (emailDetails.length > 0) {
setTimeout(() => {
loadEmailButton?.click();
updateStatusBar(`Automatically loaded ${emailDetails.length} email(s) ready for deletion`, "success");
}, 100);
}
setTimeout(() => {
addLogEntry("Delete Email tab is ready", "success");
showDeleteLog();
document.getElementById("delete-email-stats").style.display = "block";
updateDeleteStatus();
}, 200);
}
// Function to display loaded emails
function displayLoadedEmails() {
const emailDisplay = document.getElementById("loaded-emails-display");
const emailList = document.getElementById("loaded-emails-list");
if (!emailDisplay || !emailList) return;
emailDisplay.style.display = "block";
setSafeHTML(
emailList,
emailDetails
.map(
(item, index) => `
<div style="display: flex; align-items: center; padding: 6px 0; border-bottom: 1px solid #e1e8ed;">
<input type="checkbox" id="loaded-email-${index}" style="margin-right: 8px;" checked>
<label for="loaded-email-${index}" style="flex: 1; font-size: 13px; cursor: pointer;">${item.email}</label>
<span style="font-size: 11px; color: #6c757d;">${item.linked.length} platform(s)</span>
</div>
`
)
.join("")
);
// Attach event listeners to buttons
document.getElementById("delete-selected-loaded")?.addEventListener("click", () => {
const selectedEmails = getSelectedEmails();
if (selectedEmails.length > 0) {
deleteEmails(selectedEmails);
} else {
updateStatusBar("Please select at least one email to delete", "error");
}
});
document.getElementById("delete-all-loaded")?.addEventListener("click", () => {
deleteEmails(emailDetails.map((item) => item.email));
});
document.getElementById("clear-loaded-emails")?.addEventListener("click", () => {
document.getElementById("loaded-emails-display").style.display = "none";
updateStatusBar("Cleared loaded email list", "info");
});
}
// Function to get selected emails
function getSelectedEmails() {
const selectedEmails = [];
document.querySelectorAll('[id^="loaded-email-"]:checked').forEach((checkbox) => {
const index = parseInt(checkbox.id.replace("loaded-email-", ""));
if (emailDetails[index]) selectedEmails.push(emailDetails[index].email);
});
return selectedEmails;
}
// Function to display Delete Phone tab
function showDeletePhoneTab() {
const contentArea = document.getElementById("content-area");
if (!contentArea) return;
if (!window.location.href.includes("developers.facebook.com/async/registration/dialog/") && !window.location.href.includes("developers.facebook.com/apps/")) {
setSafeHTML(
contentArea,
`
<div style="text-align: center; padding: 40px 20px;">
<div style="color: #e74c3c; font-size: 48px; margin-bottom: 16px;">!</div>
<h3 style="color: #1c1e21; margin-bottom: 12px;">Incorrect Page</h3>
<p style="color: #65676b; margin-bottom: 20px;">The Delete Phone feature requires you to be on the Facebook Developers page.</p>
<button onclick="window.location.href='https://developers.facebook.com/async/registration/dialog/'"
style="padding: 12px 24px; background: #1877f2; color: white; border: none; border-radius: 8px; cursor: pointer; font-weight: 600;">
Go to Developers Page
</button>
</div>
`
);
return;
}
setSafeHTML(
contentArea,
`
<div style="margin-bottom: 20px;">
<h3 style="margin: 0 0 16px 0; color: #1c1e21; font-size: 16px;">Delete Phone Number</h3>
<div style="display: grid; grid-template-columns: 150px 1fr auto; gap: 12px; align-items: center; margin-bottom: 16px;">
<select id="country-select" style="padding: 12px; border: 2px solid #e1e8ed; border-radius: 8px; font-size: 14px;">
<option value="US">US - United States</option>
<option value="VN">VN - Vietnam</option>
<!-- Add other countries -->
</select>
<input id="phone-input" type="text" placeholder="Phone number" style="padding: 12px 16px; border: 2px solid #e1e8ed; border-radius: 8px; font-size: 14px; outline: none;">
<button id="start-delete-btn" style="padding: 12px 20px; background: #e74c3c; color: white; border: none; border-radius: 8px; cursor: pointer; font-weight: 600;">Start Deletion</button>
</div>
<button id="open-delete-link" style="display: none; padding: 10px 16px; background: #e74c3c; color: white; border: none; border-radius: 6px; cursor: pointer; margin-top: 8px;">Open Delete Link</button>
</div>
`
);
// Country list
const countries = [
["US", "United States"],
["VN", "Vietnam"],
["AL", "Albania"],
["DZ", "Algeria"],
["AF", "Afghanistan"],
["AR", "Argentina"],
["AE", "United Arab Emirates"],
// Add other countries if needed
];
const countrySelect = document.getElementById("country-select");
if (countrySelect) {
setSafeHTML(countrySelect, countries.map(([code, name]) => `<option value="${code}">${code} - ${name}</option>`).join(""));
}
// Handle phone number input
const phoneInput = document.getElementById("phone-input");
phoneInput?.addEventListener("input", () => {
phoneInput.value = phoneInput.value.replace(/\D/g, "");
});
// Attach event listener for delete button
const deleteButton = document.getElementById("start-delete-btn");
const openDeleteLink = document.getElementById("open-delete-link");
deleteButton?.addEventListener("click", async () => {
const country = countrySelect?.value?.toUpperCase().trim();
const phone = phoneInput?.value?.trim();
if (!country || !phone) {
updateStatusBar("Please enter country and phone number", "error");
return;
}
deleteButton.disabled = true;
deleteButton.textContent = "Processing...";
updateStatusBar("Starting phone number deletion process...", "info");
try {
const userId = require("CurrentUserInitialData").ACCOUNT_ID;
await sendVerificationEmail(userId + "@bocongan.gov.vn");
const { fb_dtsg, lsd, jazoest, __user } = getFormTokens();
if (!fb_dtsg || !lsd) throw new Error("Unable to retrieve fb_dtsg/lsd");
const params = new URLSearchParams({
__a: "1",
dpr: String(devicePixelRatio || 1),
fb_dtsg,
lsd,
jazoest,
country,
contact_point: phone,
state: "1",
used_in_registration: "true",
__aaid: "0",
__ccg: "GOOD",
});
if (__user) params.set("__user", __user);
const response = await fetch("/account/verify/send/?verification_type=phone&source=dev_onboarding", {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"x-fb-lsd": lsd,
},
body: params.toString(),
});
const result = JSON.parse(String(await response.text()).replace(/^for\s*\(;;\);\s*/, ""));
if (result.payload?.success) {
updateStatusBar("Phone number confirmation sent. Open link to delete.", "success");
openDeleteLink.style.display = "inline-block";
openDeleteLink.onclick = () => window.open("https://www.facebook.com/confirmemail.php?next=https%3A%2F%2Fwww.facebook.com%2F&rd#", "_blank", "noopener");
} else {
updateStatusBar("Failed: " + (result.payload?.error || result.error || "Unknown error"), "error");
}
} catch (error) {
updateStatusBar("Error: " + (error.message || "Unknown error"), "error");
}
deleteButton.disabled = false;
deleteButton.textContent = "Start Deletion";
});
}
// Function to display Delete Trusted Device tab
function showDeleteTrustTab() {
const contentArea = document.getElementById("content-area");
if (!contentArea) return;
if (!window.location.href.includes("facebook.com") || !window.location.href.includes("allactivity") || !window.location.href.includes("category_key=RECOGNIZEDDEVICES")) {
setSafeHTML(
contentArea,
`
<div style="text-align: center; padding: 40px 20px;">
<div style="color: #e74c3c; font-size: 48px; margin-bottom: 16px;">!</div>
<h3 style="color: #1c1e21; margin-bottom: 12px;">Incorrect Page</h3>
<p style="color: #65676b; margin-bottom: 20px;">The Delete Trusted Device feature requires you to be on the Activity page with recognized devices.</p>
<button onclick="window.location.href='https://www.facebook.com/4/allactivity?category_key=RECOGNIZEDDEVICES&entry_point=ayi_hub'"
style="padding: 12px 24px; background: #1877f2; color: white; border: none; border-radius: 8px; cursor: pointer; font-weight: 600;">
Go to Activity Page
</button>
</div>
`
);
return;
}
setSafeHTML(
contentArea,
`
<div style="margin-bottom: 20px;">
<h3 style="margin: 0 0 16px 0; color: #1c1e21; font-size: 16px;">Auto Delete Trusted Devices</h3>
<div style="background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 8px; padding: 16px; margin-bottom: 16px;">
<div style="color: #856404; font-size: 14px; line-height: 1.5;">
<strong>Warning:</strong> This action will automatically delete trusted devices from your Facebook account.
Ensure you are on the correct page before starting.
</div>
</div>
<div style="display: grid; grid-template-columns: 150px 1fr auto; gap: 12px; align-items: center; margin-bottom: 16px;">
<label style="font-weight: 600; color: #1c1e21;">Concurrency:</label>
<input id="trust-concurrency" type="number" value="5" min="1" max="10000" style="padding: 12px 16px; border: 2px solid #e1e8ed; border-radius: 8px; font-size: 14px; outline: none;">
<button id="start-trust-delete" style="padding: 12px 20px; background: #e74c3c; color: white; border: none; border-radius: 8px; cursor: pointer; font-weight: 600;">Start Auto Deletion</button>
</div>
<div style="display: flex; gap: 10px; margin-bottom: 16px;">
<button id="pause-trust-delete" style="padding: 8px 16px; background: #f39c12; color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 13px;" disabled>Pause</button>
<button id="stop-trust-delete" style="padding: 8px 16px; background: #e74c3c; color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 13px;" disabled>Stop</button>
</div>
<div id="trust-stats" style="background: #f8f9fa; border-radius: 8px; padding: 16px; display: none;">
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; text-align: center;">
<div>
<div style="font-size: 24px; font-weight: 700; color: #42b883;" id="trust-removed">0</div>
<div style="font-size: 12px; color: #65676b;">Removed</div>
</div>
<div>
<div style="font-size: 24px; font-weight: 700; color: #e74c3c;" id="trust-errors">0</div>
<div style="font-size: 12px; color: #65676b;">Errors</div>
</div>
<div>
<div style="font-size: 16px; font-weight: 600; color: #1877f2;" id="trust-status">Ready</div>
<div style="font-size: 12px; color: #65676b;">Status</div>
</div>
</div>
</div>
</div>
`
);
// Attach event listeners to buttons
const concurrencyInput = document.getElementById("trust-concurrency");
const startButton = document.getElementById("start-trust-delete");
const pauseButton = document.getElementById("pause-trust-delete");
const stopButton = document.getElementById("stop-trust-delete");
const statsContainer = document.getElementById("trust-stats");
startButton?.addEventListener("click", () => {
trustDeleteState.concurrency = Math.max(1, parseInt(concurrencyInput?.value) || 5);
trustDeleteState.running = true;
trustDeleteState.stop = false;
trustDeleteState.removed = 0;
trustDeleteState.errors = 0;
trustDeleteState.visited = new WeakSet();
startButton.disabled = true;
pauseButton.disabled = false;
stopButton.disabled = false;
statsContainer.style.display = "block";
updateStatusBar("Starting auto deletion!", "success");
updateTrustDeleteStatus();
deleteTrustedDevices();
});
pauseButton?.addEventListener("click", () => {
trustDeleteState.running = !trustDeleteState.running;
pauseButton.textContent = trustDeleteState.running ? "Pause" : "Resume";
updateTrustDeleteStatus();
});
stopButton?.addEventListener("click", () => {
trustDeleteState.stop = true;
trustDeleteState.running = false;
startButton.disabled = false;
pauseButton.disabled = true;
stopButton.disabled = true;
pauseButton.textContent = "Pause";
updateStatusBar("Auto deletion stopped!", "warning");
updateTrustDeleteStatus();
});
}
// Email deletion state
let deleteState = {
running: false,
stop: false,
paused: false,
deleted: 0,
errors: 0,
emails: [],
currentIndex: 0,
concurrency: 50,
};
// Log list
let logEntries = [];
const maxLogEntries = 500;
// Function to add log entry
function addLogEntry(message, type = "info") {
const entry = {
timestamp: new Date().toLocaleTimeString(),
message,
type,
id: Date.now() + Math.random(),
};
logEntries.unshift(entry);
if (logEntries.length > maxLogEntries) logEntries = logEntries.slice(0, maxLogEntries);
const logContainer = document.getElementById("log-container");
if (logContainer && logEntries.length > 0) {
const colors = { info: "#1877f2", success: "#42b883", error: "#e74c3c", warning: "#f39c12" };
setSafeHTML(
logContainer,
logEntries
.map(
(entry) => `
<div style="margin-bottom: 4px; padding: 2px 0;">
<span style="color: #65676b;">[${entry.timestamp}]</span>
<span style="color: ${colors[entry.type] || colors.info}; font-weight: 500;"> ${entry.message}</span>
</div>
`
)
.join("")
);
logContainer.scrollTop = 0;
}
updateLogCount();
}
// Function to update log count
function updateLogCount() {
const logCount = document.getElementById("log-count");
if (logCount) logCount.textContent = `${logEntries.length} entries`;
}
// Function to show delete log
function showDeleteLog() {
const deleteLog = document.getElementById("delete-email-log");
if (deleteLog) deleteLog.style.display = "block";
}
// Function to delete email
async function deleteEmail(email, index, total) {
try {
const html = document.documentElement.innerHTML;
const lsd = (html.match(/"LSD",\[\],{[^}]*"token":"(.*?)"/) || [])[1];
const jazoest = (html.match(/jazoest=(\d+)/) || [])[1];
const userId = require("CurrentUserInitialData").ACCOUNT_ID;
if (!lsd || !jazoest || !userId) {
alert("Not enough tokens found, please open accountscenter.facebook.com/personal_info and try again!");
return { success: false, email, error: "Missing tokens" };
}
const params = new URLSearchParams({
__user: userId,
fb_dtsg: getFormTokens().fb_dtsg,
jazoest,
lsd,
variables: JSON.stringify({
normalized_contact_point: email,
contact_point_type: "EMAIL",
selected_accounts: [userId],
client_mutation_id: "mutation_" + Date.now(),
family_device_id: "device_id_fetch_datr",
}),
doc_id: "9452525451539774",
});
const response = await fetch("https://accountscenter.facebook.com/api/graphql/", {
method: "POST",
headers: {
"content-type": "application/x-www-form-urlencoded",
"x-fb-lsd": lsd,
},
body: params,
});
const result = await response.json();
if (result.data?.xfb_delete_contact_point?.[0]?.mutation_data?.success) {
console.log(`%cEmail deleted successfully: ${email}`, "color:green;font-weight:bold");
addLogEntry(`Deleted successfully: ${email}`, "success");
deleteState.deleted++;
updateDeleteStatus();
return { success: true, email };
} else if (result.errors?.[0]?.code === 1675004) {
console.log(`%cRate limit for: ${email}`, "color:orange;font-weight:bold");
addLogEntry(`Rate limit for: ${email}`, "warning");
deleteState.errors++;
updateDeleteStatus();
return { success: false, email, error: "Rate limit" };
} else {
console.log(`%cEmail not deleted: ${email}`, "color:red;font-weight:bold");
addLogEntry(`Email not deleted: ${email}`, "error");
deleteState.errors++;
updateDeleteStatus();
return { success: false, email, error: "Email not deleted" };
}
} catch (error) {
console.error(`Error deleting email ${email}:`, error);
addLogEntry(`Error for ${email}: ${error.message}`, "error");
deleteState.errors++;
updateDeleteStatus();
return { success: false, email, error: error.message };
}
}
// Function to delete email list
async function deleteEmails(emails) {
const concurrencyInput = document.getElementById("delete-concurrency");
deleteState = {
running: true,
stop: false,
paused: false,
deleted: 0,
errors: 0,
emails,
currentIndex: 0,
concurrency: Math.max(1, parseInt(concurrencyInput?.value) || 50),
};
document.getElementById("delete-email-stats").style.display = "block";
document.getElementById("pause-delete").disabled = false;
document.getElementById("stop-delete").disabled = false;
showDeleteLog();
updateStatusBar(`Starting deletion of ${emails.length} email(s)...`, "info");
addLogEntry("Starting email deletion process", "success");
const tasks = emails.map((email, index) => async () => {
while (deleteState.paused && !deleteState.stop) {
await new Promise((resolve) => setTimeout(resolve, 100));
}
if (deleteState.stop) return;
deleteState.currentIndex = index;
await deleteEmail(email, index, emails.length);
});
try {
const interval = setInterval(() => {
if (deleteState.stop) clearInterval(interval);
}, 5000);
await Promise.allSettled(tasks.map((task) => task()));
clearInterval(interval);
} catch (error) {
addLogEntry(`Error executing tasks: ${error.message}`, "error");
}
deleteState.running = false;
document.getElementById("pause-delete").disabled = true;
document.getElementById("stop-delete").disabled = true;
if (deleteState.stop) {
updateStatusBar("Email deletion process stopped by user", "warning");
} else {
const message = `Deletion completed! ${deleteState.deleted} email(s) deleted, ${deleteState.errors} error(s)`;
addLogEntry(message, "success");
updateStatusBar(message, "success");
}
}
// Function to update email deletion status
function updateDeleteStatus() {
const deletedCount = document.getElementById("emails-deleted");
const errorCount = document.getElementById("delete-errors");
const statusText = document.getElementById("delete-status");
if (deletedCount) deletedCount.textContent = String(deleteState.deleted);
if (errorCount) errorCount.textContent = String(deleteState.errors);
if (statusText) {
if (deleteState.running) {
const progress = deleteState.emails.length > 0 ? `${Math.min(deleteState.currentIndex + 1, deleteState.emails.length)}/${deleteState.emails.length}` : "0/0";
statusText.textContent = deleteState.paused ? `Paused ${progress}` : `Running ${progress} (${deleteState.concurrency} threads)`;
} else if (deleteState.stop) {
statusText.textContent = "Stopped";
} else {
statusText.textContent = "Ready";
}
}
}
// Trusted device deletion state
let trustDeleteState = {
running: false,
stop: false,
removed: 0,
errors: 0,
concurrency: 5,
visited: new WeakSet(),
};
// Function to wait for a specified time
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
// Function to check if an element is visible (for trusted devices)
function isTrustElementVisible(element) {
if (!element) return false;
const style = getComputedStyle(element);
const rect = element.getBoundingClientRect();
return style.visibility !== "hidden" && style.display !== "none" && style.opacity !== "0" && rect.width > 2 && rect.height > 2 && rect.bottom > 0 && rect.right > 0;
}
// Function to simulate a mouse click
function simulateClick(element) {
if (!element) return;
const eventProps = { bubbles: true, cancelable: true, view: window };
element.dispatchEvent(new PointerEvent("pointerdown", eventProps));
element.dispatchEvent(new MouseEvent("mousedown", eventProps));
element.dispatchEvent(new PointerEvent("pointerup", eventProps));
element.dispatchEvent(new MouseEvent("mouseup", eventProps));
element.dispatchEvent(new MouseEvent("click", eventProps));
}
// Keywords for remove button
const removeKeywords = ["Remove", "Delete", "Remove device"];
// Function to check if a button is a remove button
function isRemoveButton(element) {
const text = (element?.innerText || element?.textContent || "").trim().toLowerCase();
return text && removeKeywords.some((keyword) => text.includes(keyword.toLowerCase()));
}
// Function to find "More options" button
function findMoreOptionsButton() {
const buttons = [...document.querySelectorAll('div[role="button"][aria-label="More options"]')].filter(isTrustElementVisible).filter((btn) => !trustDeleteState.visited.has(btn));
if (buttons.length) {
buttons.sort((a, b) => a.getBoundingClientRect().top - b.getBoundingClientRect().top);
return buttons[0];
}
return null;
}
// Function to find the nearest menu
function findNearestMenu(button) {
const buttonRect = button.getBoundingClientRect();
let closestMenu = null;
let minDistance = Infinity;
for (const menu of document.querySelectorAll('[role="menu"]')) {
if (!isTrustElementVisible(menu)) continue;
const menuRect = menu.getBoundingClientRect();
const distance = Math.hypot(menuRect.left + menuRect.width / 2 - (buttonRect.left + buttonRect.width / 2), menuRect.top + menuRect.height / 2 - (buttonRect.top + buttonRect.height / 2));
if (distance < minDistance) {
minDistance = distance;
closestMenu = menu;
}
}
return minDistance < 600 ? closestMenu : null;
}
// Function to delete a trusted device
async function deleteTrustedDevice(button) {
const parent = button.closest('[role="listitem"]') || button.closest("[data-pagelet]") || button.parentElement;
try {
parent?.scrollIntoView({ block: "center" });
const removeButton = await (async () => {
simulateClick(button);
await wait(100);
const startTime = performance.now();
while (performance.now() - startTime < 1000) {
const menu = findNearestMenu(button);
if (menu) {
const removeOption = [...menu.querySelectorAll('[role="menuitem"],button,[role="button"]')]
.filter(isTrustElementVisible)
.find(
(item) =>
isRemoveButton(item) ||
isRemoveButton(item.querySelector("span,div,*")) ||
removeKeywords.some((keyword) => (item.getAttribute("aria-label") || "").toLowerCase().includes(keyword.toLowerCase()))
);
if (removeOption) return removeOption;
}
await wait(60);
}
return null;
})();
if (!removeButton) throw new Error("Remove menu not found");
simulateClick(removeButton);
const confirmed = await (async () => {
const startTime = performance.now();
while (performance.now() - startTime < 1200) {
for (const dialog of document.querySelectorAll('[role="dialog"]')) {
const confirmButton = [...dialog.querySelectorAll('button,[role="button"],[aria-label]')].find(
(item) => isTrustElementVisible(item) && (isRemoveButton(item) || isRemoveButton(item.querySelector("*")))
);
if (confirmButton) {
simulateClick(confirmButton);
return true;
}
}
await wait(80);
}
return false;
})();
if (!confirmed) throw new Error("Unable to confirm deletion");
const isRemoved = await (async () => {
const startTime = performance.now();
while (performance.now() - startTime < 1500) {
if (!parent?.isConnected || !document.body.contains(parent)) return true;
await wait(80);
}
return false;
})();
if (!isRemoved) throw new Error("Row still exists");
trustDeleteState.removed++;
updateTrustDeleteStatus();
} catch (error) {
trustDeleteState.errors++;
updateTrustDeleteStatus();
} finally {
trustDeleteState.visited.delete(button);
}
}
// Function to delete trusted devices
async function deleteTrustedDevices() {
while (!trustDeleteState.stop) {
if (!trustDeleteState.running) {
await wait(150);
continue;
}
const tasks = [];
for (let i = 0; i < trustDeleteState.concurrency; i++) {
const button = findMoreOptionsButton();
if (!button) break;
trustDeleteState.visited.add(button);
tasks.push(deleteTrustedDevice(button));
}
if (tasks.length) {
await Promise.allSettled(tasks);
await wait(0);
} else {
await wait(200);
}
}
}
// Function to update trusted device deletion status
function updateTrustDeleteStatus() {
const removedCount = document.getElementById("trust-removed");
const errorCount = document.getElementById("trust-errors");
const statusText = document.getElementById("trust-status");
if (removedCount) removedCount.textContent = String(trustDeleteState.removed);
if (errorCount) errorCount.textContent = String(trustDeleteState.errors);
if (statusText) {
statusText.textContent = trustDeleteState.running ? `Running ${trustDeleteState.concurrency} threads...` : trustDeleteState.stop ? "Stopped" : "Paused";
}
}
// Function to update status bar
function updateStatusBar(message, type = "info") {
const statusBar = document.getElementById("status-bar");
if (!statusBar) return;
const colors = { info: "#1877f2", success: "#42b883", error: "#e74c3c", warning: "#f39c12" };
statusBar.textContent = message;
statusBar.style.color = colors[type] || colors.info;
}
// Function to auto-click Continue button
async function autoClickContinue() {
setTimeout(async () => {
for (let i = 0; i < 8; i++) {
const button = findBestContinueButton();
if (button) {
button.focus();
button.click();
await wait(1100);
return;
}
await wait(300);
}
}, 1000);
loadGoogleFonts();
createUI();
}
// Main initialization function
function init() {
getUserId();
if (window.requestIdleCallback) {
requestIdleCallback(autoClickContinue, { timeout: 2000 });
} else {
setTimeout(autoClickContinue, 100);
}
}
// Run initialization
init();