blob: c572523446d3dd6a6d22a36edc2bcc67cb8c4412 [file] [log] [blame]
Adrià Vilanova Martínez7e8796c2022-01-23 21:46:46 +01001import {MDCTooltip} from '@material/tooltip';
2import {waitFor} from 'poll-until-promise';
3
4import {isOptionEnabled} from '../../common/optionsUtils.js';
5
6import {createExtBadge} from './utils/common.js';
7
8const kViewUnifiedUserResponseEvent = 'TWPT_ViewUnifiedUserResponse';
9
10const kAbuseCategories = [
11 ['1', 'Account'],
12 ['2', 'Display name'],
13 ['3', 'Avatar'],
14];
15const kAbuseViolationCategories = {
16 0: 'NO_VIOLATION',
17 1: 'COMMUNITY_POLICY_VIOLATION',
18 2: 'LEGAL_VIOLATION',
19 3: 'CSAI_VIOLATION',
20 4: 'OTHER_VIOLATION',
21};
22const kAbuseViolationTypes = {
23 0: 'UNSPECIFIED',
24 23: 'ACCOUNT_DISABLED',
25 55: 'ACCOUNT_HAS_SERVICES_DISABLED',
26 35: 'ACCOUNT_HIJACKED',
27 96: 'ACCOUNT_LEAKED_CREDENTIALS',
28 92: 'ACCOUNT_NOT_SUPPORTED',
29 81: 'ARTISTIC_NUDITY',
30 66: 'BAD_BEHAVIOR_PATTERN',
31 78: 'BAD_ENGAGEMENT_BEHAVIOR_PATTERN',
32 79: 'BORDERLINE_HARASSMENT',
33 80: 'BORDERLINE_HATE_SPEECH',
34 38: 'BOTNET',
35 32: 'BRANDING_VIOLATION',
36 100: 'CAPITALIZING_TRAGIC_EVENTS',
37 105: 'CLOAKING',
38 49: 'COIN_MINING',
39 7: 'COMMERCIAL_CONTENT',
40 97: 'COPPA_REGULATED',
41 57: 'COPYRIGHT_CIRCUMVENTION',
42 8: 'COPYRIGHTED_CONTENT',
43 58: 'COURT_ORDER',
44 51: 'CSAI',
45 94: 'CSAI_INSPECT',
46 52: 'CSAI_CARTOON_HUMOR',
47 53: 'CSAI_SOLICITATION',
48 108: 'CSAI_NON_APPARENT',
49 67: 'DANGEROUS',
50 37: 'DATA_SCRAPING',
51 86: 'DECEPTIVE_OAUTH_IMPLEMENTATION',
52 46: 'DEFAMATORY_CONTENT',
53 36: 'DELINQUENT_BILLING',
54 30: 'DISRUPTION_ATTEMPT',
55 112: 'DOMESTIC_INTERFERENCE',
56 22: 'DOS',
57 9: 'DUPLICATE_CONTENT',
58 68: 'DUPLICATE_LOCAL_PAGE',
59 121: 'NON_QUALIFYING_ORGANIZATION',
60 115: 'EGREGIOUS_INTERACTION_WITH_MINOR',
61 83: 'ENGAGEMENT_COLLUSION',
62 41: 'EXPLOIT_ATTACKS',
63 65: 'FAKE_USER',
64 2: 'FRAUD',
65 21: 'FREE_TRIAL_VIOLATION',
66 43: 'GIBBERISH',
67 101: 'FOREIGN_INTERFERENCE',
68 59: 'GOVERNMENT_ORDER',
69 10: 'GRAPHICAL_VIOLENCE',
70 11: 'HARASSMENT',
71 12: 'HATE_SPEECH',
72 90: 'IDENTICAL_PRODUCT_NAME',
73 60: 'ILLEGAL_DRUGS',
74 13: 'IMPERSONATION',
75 69: 'IMPERSONATION_WITH_PII',
76 116: 'INAPPROPRIATE_INTERACTION_WITH_MINOR',
77 45: 'INAPPROPRIATE_CONTENT_SPEECH',
78 106: 'INTENTIONAL_THWARTING',
79 27: 'INTRUSION_ATTEMPT',
80 87: 'INVALID_API_USAGE',
81 14: 'INVALID_CONTENT',
82 20: 'INVALID_GCE_USAGE',
83 120: 'INVALID_STORAGE_USAGE',
84 15: 'INVALID_IMAGE_QUALITY',
85 88: 'INVALID_API_PRIVACY_POLICY_DISCLOSURE',
86 54: 'INVALID_USAGE_OF_IP_PROXYING',
87 99: 'KEYWORD_STUFFING',
88 61: 'LEGAL_COUNTERFEIT',
89 62: 'LEGAL_EXPORT',
90 63: 'LEGAL_PRIVACY',
91 33: 'LEGAL_REVIEW',
92 91: 'LEGAL_PROTECTED',
93 70: 'LOW_QUALITY_CONTENT',
94 93: 'LOW_REPUTATION_PHONE_NUMBER',
95 6: 'MALICIOUS_SOFTWARE',
96 40: 'MALWARE',
97 113: 'MISLEADING',
98 114: 'MISREP_OF_ID',
99 89: 'MEMBER_OF_ABUSIVE_GCE_NETWORK',
100 84: 'NON_CONSENSUAL_EXPLICIT_IMAGERY',
101 1: 'NONE',
102 102: 'OFF_TOPIC',
103 31: 'OPEN_PROXY',
104 28: 'PAYMENT_FRAUD',
105 16: 'PEDOPHILIA',
106 71: 'PERSONAL_INFORMATION_CONTENT',
107 25: 'PHISHING',
108 34: 'POLICY_REVIEW',
109 17: 'PORNOGRAPHY',
110 29: 'QUOTA_CIRCUMVENTION',
111 72: 'QUOTA_EXCEEDED',
112 73: 'REGULATED',
113 24: 'REPEATED_POLICY_VIOLATION',
114 104: 'RESOURCE_COMPROMISED',
115 107: 'REWARD_PROGRAMS_ABUSE',
116 74: 'ROGUE_PHARMA',
117 82: 'ESCORT',
118 75: 'SPAMMY_LOCAL_VERTICAL',
119 39: 'SEND_EMAIL_SPAM',
120 117: 'SEXTORTION',
121 118: 'SEX_TRAFFICKING',
122 44: 'SEXUALLY_EXPLICIT_CONTENT',
123 3: 'SHARDING',
124 95: 'SOCIAL_ENGINEERING',
125 109: 'SUSPICIOUS',
126 19: 'TRADEMARK_CONTENT',
127 50: 'TRAFFIC_PUMPING',
128 76: 'UNSAFE_RACY',
129 103: 'UNUSUAL_ACTIVITY_ALERT',
130 64: 'UNWANTED_CONTENT',
131 26: 'UNWANTED_SOFTWARE',
132 77: 'VIOLENT_EXTREMISM',
133 119: 'UNAUTH_IMAGES_OF_MINORS',
134 85: 'UNAUTHORIZED_SERVICE_RESELLING',
135 98: 'CSAI_EXTERNAL',
136 5: 'SPAM',
137 4: 'UNSAFE',
138 47: 'CHILD_PORNOGRAPHY_INCITATION',
139 18: 'TERRORISM_SUPPORT',
140 56: 'CSAI_WORST_OF_WORST',
141};
142
143export default class ExtraInfo {
144 constructor() {
145 this.lastProfile = {
146 body: {},
147 id: -1,
148 timestamp: 0,
149 };
150 this.setUpHandlers();
151 }
152
153 setUpHandlers() {
154 window.addEventListener(kViewUnifiedUserResponseEvent, e => {
155 if (e.detail.id < this.lastProfile.id) return;
156
157 this.lastProfile = {
158 body: e.detail.body,
159 id: e.detail.id,
160 timestamp: Date.now(),
161 };
162 });
163 }
164
165 // Add a pretty component which contains |info| to |node|.
166 addExtraInfoElement(info, node) {
167 // Don't create
168 if (info.length == 0) return;
169
170 let container = document.createElement('div');
171 container.classList.add('TWPT-extrainfo-container');
172
173 let badgeCell = document.createElement('div');
174 badgeCell.classList.add('TWPT-extrainfo-badge-cell');
175
176 let badge, badgeTooltip;
177 [badge, badgeTooltip] = createExtBadge();
178 badgeCell.append(badge);
179
180 let infoCell = document.createElement('div');
181 infoCell.classList.add('TWPT-extrainfo-info-cell');
182
183 for (const i of info) {
184 let iRow = document.createElement('div');
185 iRow.append(i);
186 infoCell.append(iRow);
187 }
188
189 container.append(badgeCell, infoCell);
190 node.append(container);
191 new MDCTooltip(badgeTooltip);
192 }
193
194 fieldInfo(field, value) {
195 let span = document.createElement('span');
196 span.append(document.createTextNode(field + ': '));
197
198 let valueEl = document.createElement('span');
199 valueEl.style.fontFamily = 'monospace';
200 valueEl.textContent = value;
201
202 span.append(valueEl);
203 return span;
204 }
205
206 // Profile functionality
207 injectAtProfile(card) {
208 waitFor(
209 () => {
210 let now = Date.now();
211 if (now - this.lastProfile.timestamp < 15 * 1000)
212 return Promise.resolve(this.lastProfile);
213 return Promise.reject('Didn\'t receive profile information');
214 },
215 {
216 interval: 500,
217 timeout: 15 * 1000,
218 })
219 .then(profile => {
220 let info = [];
221 const abuseViolationCategory = profile.body?.['1']?.['6'];
222 if (abuseViolationCategory) {
223 info.push(this.fieldInfo(
224 'Abuse category',
225 kAbuseViolationCategories[abuseViolationCategory] ??
226 abuseViolationCategory));
227 }
228
229 const profileAbuse = profile.body?.['1']?.['1']?.['8'];
230
231 for (const [index, category] of kAbuseCategories) {
232 const violation = profileAbuse?.[index]?.['1']?.['1'];
233 if (violation) {
234 info.push(this.fieldInfo(
235 category + ' policy violation',
236 kAbuseViolationTypes[violation]));
237 }
238 }
239
240 const appealCount = profileAbuse?.['4'];
241 if (appealCount !== undefined)
242 info.push(this.fieldInfo('Number of appeals', appealCount));
243
244 this.addExtraInfoElement(info, card);
245 })
246 .catch(err => {
247 console.error(
248 'extraInfo: error while injecting profile extra info: ', err);
249 });
250 }
251
252 injectAtProfileIfEnabled(card) {
253 isOptionEnabled('extrainfo').then(isEnabled => {
254 if (isEnabled) return this.injectAtProfile(card);
255 });
256 }
257}