forked from DrHazemAli/fb-guardian
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontentScript.js
183 lines (159 loc) · 6.43 KB
/
contentScript.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// contentScript.js
//////////////////////////////////
// 1. OpenAI classification helper
//////////////////////////////////
async function analyzeWithOpenAI(commentText, apiKey) {
try {
// Example call to OpenAI's completions endpoint (text-davinci-003).
// Adjust the endpoint & payload for your specific use-case.
const response = await fetch("https://api.openai.com/v1/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${apiKey}`
},
body: JSON.stringify({
model: "text-davinci-003",
prompt: `Please determine if this comment contains hate speech or violent language:\n"${commentText}"\nRespond with JSON: { "flagged": true/false, "reason": "explanation" }`,
max_tokens: 60,
temperature: 0
})
});
const data = await response.json();
// The model might return a JSON object in data.choices[0].text
let flagged = false;
let reason = "";
if (data.choices && data.choices.length > 0) {
try {
const parsed = JSON.parse(data.choices[0].text.trim());
flagged = parsed.flagged;
reason = parsed.reason;
} catch (err) {
console.warn("Could not parse JSON from OpenAI response:", err);
}
}
return { flagged, reason };
} catch (error) {
console.error("OpenAI API Error:", error);
return { flagged: false, reason: "API error" };
}
}
////////////////////////////////////////////////
// 2. Keyword check (user-defined keywords)
////////////////////////////////////////////////
function containsCustomKeywords(commentText, keywords) {
const textLower = commentText.toLowerCase();
for (const kw of keywords) {
if (textLower.includes(kw.toLowerCase())) {
return true;
}
}
return false;
}
///////////////////////////////////////////////
// 3. Attempt to block user
///////////////////////////////////////////////
function blockUser(element, autoBlock) {
// The approach below is naive and may break if Facebook changes its DOM or structure.
// Also, attempting to automate user blocking may violate Facebook's TOS.
// Use caution in production.
const userProfileLink = element.closest('[role="article"]')?.querySelector('a[href*="facebook.com"]');
if (!userProfileLink) {
if (!autoBlock) {
alert("Unable to find user profile link. Manual block may be needed.");
}
return;
}
const profileUrl = userProfileLink.href;
// If automatic, attempt to open a new tab or do something else automatically.
// This is purely illustrative. In reality, you might need to simulate clicks,
// or direct the user to a blocking flow, etc.
if (autoBlock) {
window.open(`${profileUrl}?action=block`, "_blank");
} else {
alert("Opening user profile so you can block them manually.");
window.open(`${profileUrl}`, "_blank");
}
}
///////////////////////////////////////////////
// 4. UI helper to flag comments
///////////////////////////////////////////////
function createRedFlagUI(element, reason, blockingMode) {
// If blockingMode is "automatic", attempt to block right away:
if (blockingMode === "automatic") {
blockUser(element, true);
// Optionally you can also highlight the comment text
highlightComment(element, reason);
return;
}
// If blockingMode is "manual", show a block button
highlightComment(element, reason);
const blockBtn = document.createElement("button");
blockBtn.innerText = "Block User";
blockBtn.style.marginLeft = "8px";
blockBtn.style.cursor = "pointer";
blockBtn.addEventListener("click", () => {
blockUser(element, false);
});
element.appendChild(blockBtn);
}
// Helper function to highlight comment
function highlightComment(element, reason) {
// Create a red flag label
const flag = document.createElement("span");
flag.innerText = `⚠ Flagged: ${reason}`;
flag.style.color = "red";
flag.style.fontWeight = "bold";
flag.style.marginLeft = "8px";
element.appendChild(flag);
}
/////////////////////////////////////////////////////////////
// 5. Main observer to watch for new comments and analyze them
/////////////////////////////////////////////////////////////
function observeComments() {
const observer = new MutationObserver(async (mutations) => {
// Retrieve the API key, user-defined keywords, and blocking mode
const { apiKey, customKeywords, blockingMode } = await getConfigs();
for (const mutation of mutations) {
for (const node of mutation.addedNodes) {
if (node.nodeType === Node.ELEMENT_NODE) {
// Attempt to find the comment text in elements that match FB’s comment structure
const commentElements = node.querySelectorAll?.('[data-ad-preview="message"]') || [];
for (const commentElem of commentElements) {
const commentText = commentElem.innerText.trim();
if (!commentText) continue;
// Check if it contains any user-defined keywords
const keywordFlagged = containsCustomKeywords(commentText, customKeywords);
// Optionally send to OpenAI for classification
let openAIFlagged = false;
let openAIReason = "";
if (apiKey) {
const result = await analyzeWithOpenAI(commentText, apiKey);
openAIFlagged = result.flagged;
openAIReason = result.reason;
}
if (keywordFlagged) {
createRedFlagUI(commentElem, "Contains custom keyword", blockingMode);
} else if (openAIFlagged) {
createRedFlagUI(commentElem, openAIReason || "Hateful or violent content", blockingMode);
}
}
}
}
}
});
observer.observe(document.body, { childList: true, subtree: true });
}
async function getConfigs() {
return new Promise((resolve) => {
chrome.runtime.sendMessage({ action: "getConfigs" }, (response) => {
resolve({
apiKey: response.apiKey,
customKeywords: response.customKeywords,
blockingMode: response.blockingMode
});
});
});
}
// Start observing once the page is ready
observeComments();