Naresh1993 commited on
Commit
b9401aa
·
verified ·
1 Parent(s): 29b6b4d

Add 1 files

Browse files
Files changed (1) hide show
  1. index.html +467 -1
index.html CHANGED
@@ -140,5 +140,471 @@
140
  <div class="p-4 rounded-lg pii-medium">
141
  <div class="flex items-center mb-2">
142
  <div class="w-3 h-3 rounded-full bg-yellow-500 mr-2"></div>
143
- <h3 class="font
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  </html>
 
140
  <div class="p-4 rounded-lg pii-medium">
141
  <div class="flex items-center mb-2">
142
  <div class="w-3 h-3 rounded-full bg-yellow-500 mr-2"></div>
143
+ <h3 class="font-medium">Potential PII</h3>
144
+ </div>
145
+ <p class="text-sm text-gray-700">Fields that might contain personal data based on naming patterns or field types.</p>
146
+ </div>
147
+ <div class="p-4 rounded-lg pii-low">
148
+ <div class="flex items-center mb-2">
149
+ <div class="w-3 h-3 rounded-full bg-blue-500 mr-2"></div>
150
+ <h3 class="font-medium">Low Risk</h3>
151
+ </div>
152
+ <p class="text-sm text-gray-700">Fields that are unlikely to contain personal data but should still be reviewed.</p>
153
+ </div>
154
+ </div>
155
+ </div>
156
+ </div>
157
+
158
+ <div id="loginState" class="flex flex-col items-center justify-center py-20">
159
+ <div class="bg-white rounded-xl shadow-md p-8 max-w-md w-full text-center">
160
+ <i class="fab fa-salesforce text-5xl text-blue-500 mb-4"></i>
161
+ <h2 class="text-2xl font-bold text-gray-800 mb-2">Salesforce PII Analyzer</h2>
162
+ <p class="text-gray-600 mb-6">Login with your Salesforce account to analyze your org for potential Personally Identifiable Information (PII) data.</p>
163
+ <div id="loginButtonCenter" class="bg-blue-500 hover:bg-blue-600 text-white px-6 py-3 rounded-lg shadow-md transition-colors cursor-pointer flex items-center justify-center mx-auto w-full max-w-xs">
164
+ <i class="fab fa-salesforce mr-2"></i>
165
+ Login with Salesforce
166
+ </div>
167
+ </div>
168
+ </div>
169
+
170
+ <div id="loadingState" class="hidden flex flex-col items-center justify-center py-20">
171
+ <div class="bg-white rounded-xl shadow-md p-8 max-w-md w-full text-center">
172
+ <div class="loading-spinner mx-auto mb-4"></div>
173
+ <h2 class="text-xl font-bold text-gray-800 mb-2" id="loadingText">Connecting to Salesforce...</h2>
174
+ <p class="text-gray-600" id="loadingSubtext">Please wait while we authenticate your session.</p>
175
+ </div>
176
+ </div>
177
+ </div>
178
+
179
+ <script>
180
+ // Configuration
181
+ const CLIENT_ID = '3MVG9pRzvMkjMb6lZlt3YjDQwe2tA1wWE4jHVJ.VZJj4i8T6gJQBWmwdVJZqgNrm4sY.sp0SJQCH2TfULXjG_';
182
+ const CALLBACK_URL = 'https://login.salesforce.com/services/oauth2/success';
183
+ const LOGIN_URL = 'https://login.salesforce.com';
184
+ const API_VERSION = '56.0';
185
+
186
+ // DOM elements
187
+ const loginButton = document.getElementById('loginButton');
188
+ const loginButtonCenter = document.getElementById('loginButtonCenter');
189
+ const logoutButton = document.getElementById('logoutButton');
190
+ const userInfo = document.getElementById('userInfo');
191
+ const userName = document.getElementById('userName');
192
+ const userPhoto = document.getElementById('userPhoto');
193
+ const orgName = document.getElementById('orgName');
194
+ const appContent = document.getElementById('appContent');
195
+ const loginState = document.getElementById('loginState');
196
+ const loadingState = document.getElementById('loadingState');
197
+ const loadingText = document.getElementById('loadingText');
198
+ const loadingSubtext = document.getElementById('loadingSubtext');
199
+ const resultsContainer = document.getElementById('resultsContainer');
200
+ const totalObjects = document.getElementById('totalObjects');
201
+ const piiFields = document.getElementById('piiFields');
202
+ const progressFill = document.getElementById('progressFill');
203
+ const progressText = document.getElementById('progressText');
204
+ const filterSelect = document.getElementById('filterSelect');
205
+
206
+ // State
207
+ let accessToken = null;
208
+ let instanceUrl = null;
209
+ let userId = null;
210
+ let orgId = null;
211
+ let objectsData = [];
212
+ let piiCount = 0;
213
+
214
+ // Initialize
215
+ document.addEventListener('DOMContentLoaded', () => {
216
+ // Check for OAuth response in URL
217
+ if (window.location.hash) {
218
+ handleOAuthResponse();
219
+ }
220
+
221
+ // Set up event listeners
222
+ loginButton.addEventListener('click', initiateOAuth);
223
+ loginButtonCenter.addEventListener('click', initiateOAuth);
224
+ logoutButton.addEventListener('click', logout);
225
+ filterSelect.addEventListener('change', filterResults);
226
+ });
227
+
228
+ // OAuth Functions
229
+ function initiateOAuth() {
230
+ const authUrl = `${LOGIN_URL}/services/oauth2/authorize?response_type=token` +
231
+ `&client_id=${CLIENT_ID}` +
232
+ `&redirect_uri=${encodeURIComponent(CALLBACK_URL)}` +
233
+ `&scope=api%20refresh_token%20web` +
234
+ `&prompt=login%20consent`;
235
+
236
+ // Show loading state
237
+ loginState.classList.add('hidden');
238
+ loadingState.classList.remove('hidden');
239
+ loadingText.textContent = 'Redirecting to Salesforce...';
240
+ loadingSubtext.textContent = 'Please login with your Salesforce credentials';
241
+
242
+ // Redirect to Salesforce login
243
+ window.location.href = authUrl;
244
+ }
245
+
246
+ function handleOAuthResponse() {
247
+ const hash = window.location.hash.substring(1);
248
+ const params = new URLSearchParams(hash);
249
+
250
+ if (params.has('access_token')) {
251
+ // Get OAuth parameters
252
+ accessToken = params.get('access_token');
253
+ instanceUrl = params.get('instance_url');
254
+ userId = params.get('id').split('/').pop();
255
+ orgId = params.get('id').split('/')[4];
256
+
257
+ // Clean up URL
258
+ history.replaceState({}, document.title, window.location.pathname);
259
+
260
+ // Show loading state
261
+ loginState.classList.add('hidden');
262
+ loadingState.classList.remove('hidden');
263
+ loadingText.textContent = 'Loading org data...';
264
+ loadingSubtext.textContent = 'Fetching object metadata from your Salesforce org';
265
+
266
+ // Fetch user info and start analysis
267
+ fetchUserInfo();
268
+ } else if (params.has('error')) {
269
+ // Handle OAuth error
270
+ console.error('OAuth error:', params.get('error_description'));
271
+ showLoginState();
272
+ }
273
+ }
274
+
275
+ async function fetchUserInfo() {
276
+ try {
277
+ const response = await fetch(`${instanceUrl}/services/data/v${API_VERSION}/query?q=` +
278
+ encodeURIComponent(`SELECT Name, Username, SmallPhotoUrl FROM User WHERE Id = '${userId}'`), {
279
+ headers: {
280
+ 'Authorization': `Bearer ${accessToken}`
281
+ }
282
+ });
283
+
284
+ const data = await response.json();
285
+
286
+ if (data.records && data.records.length > 0) {
287
+ const user = data.records[0];
288
+
289
+ // Update UI with user info
290
+ userName.textContent = user.Name;
291
+ userPhoto.src = user.SmallPhotoUrl;
292
+ orgName.textContent = `Org: ${orgId}`;
293
+ userInfo.classList.remove('hidden');
294
+ loginButton.classList.add('hidden');
295
+
296
+ // Start analysis
297
+ analyzeOrg();
298
+ }
299
+ } catch (error) {
300
+ console.error('Error fetching user info:', error);
301
+ showLoginState();
302
+ }
303
+ }
304
+
305
+ // Analysis Functions
306
+ async function analyzeOrg() {
307
+ try {
308
+ loadingText.textContent = 'Analyzing your Salesforce org...';
309
+ loadingSubtext.textContent = 'This may take a few moments depending on your org size';
310
+
311
+ // Get all objects in the org
312
+ const objectsResponse = await fetch(`${instanceUrl}/services/data/v${API_VERSION}/sobjects`, {
313
+ headers: {
314
+ 'Authorization': `Bearer ${accessToken}`
315
+ }
316
+ });
317
+
318
+ const objects = await objectsResponse.json();
319
+ objectsData = objects.sobjects.filter(obj => obj.queryable && !obj.name.endsWith('ChangeEvent'));
320
+ totalObjects.textContent = objectsData.length;
321
+
322
+ // Update progress
323
+ updateProgress(0);
324
+
325
+ // Analyze each object
326
+ for (let i = 0; i < objectsData.length; i++) {
327
+ const obj = objectsData[i];
328
+ await analyzeObject(obj);
329
+ updateProgress(((i + 1) / objectsData.length) * 100);
330
+ }
331
+
332
+ // Show results
333
+ loadingState.classList.add('hidden');
334
+ appContent.classList.remove('hidden');
335
+ renderResults();
336
+ } catch (error) {
337
+ console.error('Error analyzing org:', error);
338
+ loadingText.textContent = 'Error analyzing org';
339
+ loadingSubtext.textContent = error.message;
340
+ }
341
+ }
342
+
343
+ async function analyzeObject(obj) {
344
+ try {
345
+ // Get object describe
346
+ const describeResponse = await fetch(`${instanceUrl}/services/data/v${API_VERSION}/sobjects/${obj.name}/describe`, {
347
+ headers: {
348
+ 'Authorization': `Bearer ${accessToken}`
349
+ }
350
+ });
351
+
352
+ const describe = await describeResponse.json();
353
+ obj.fields = describe.fields;
354
+
355
+ // Analyze fields for PII
356
+ obj.piiFields = [];
357
+ obj.piiScore = 0;
358
+
359
+ for (const field of obj.fields) {
360
+ const piiRisk = detectPII(field);
361
+ if (piiRisk.level > 0) {
362
+ obj.piiFields.push({
363
+ ...field,
364
+ piiRisk
365
+ });
366
+
367
+ // Add to PII count if high or medium risk
368
+ if (piiRisk.level >= 2) {
369
+ piiCount++;
370
+ piiFields.textContent = piiCount;
371
+ }
372
+ }
373
+ }
374
+
375
+ // Calculate object PII score (0-100)
376
+ if (obj.piiFields.length > 0) {
377
+ const highRiskCount = obj.piiFields.filter(f => f.piiRisk.level === 3).length;
378
+ const medRiskCount = obj.piiFields.filter(f => f.piiRisk.level === 2).length;
379
+ obj.piiScore = Math.min(100, (highRiskCount * 5) + (medRiskCount * 2));
380
+ }
381
+ } catch (error) {
382
+ console.error(`Error analyzing object ${obj.name}:`, error);
383
+ obj.error = error.message;
384
+ }
385
+ }
386
+
387
+ function detectPII(field) {
388
+ const fieldName = field.name.toLowerCase();
389
+ const fieldLabel = field.label.toLowerCase();
390
+ const fieldType = field.type;
391
+
392
+ // Common PII patterns
393
+ const piiPatterns = {
394
+ high: [
395
+ 'ssn', 'social', 'security', 'taxid', 'tax id', 'creditcard', 'credit card',
396
+ 'cardnumber', 'card number', 'passport', 'drivinglicense', 'driving license',
397
+ 'bankaccount', 'bank account', 'routingnumber', 'routing number', 'dob',
398
+ 'dateofbirth', 'date of birth', 'mothersmaiden', 'mothers maiden'
399
+ ],
400
+ medium: [
401
+ 'name', 'firstname', 'first name', 'lastname', 'last name', 'middlename',
402
+ 'middle name', 'email', 'phone', 'mobile', 'address', 'street', 'city',
403
+ 'state', 'zip', 'postalcode', 'postal code', 'country', 'gender', 'race',
404
+ 'ethnicity', 'salary', 'income', 'health', 'medical', 'insurance'
405
+ ]
406
+ };
407
+
408
+ // Check for high risk PII
409
+ for (const pattern of piiPatterns.high) {
410
+ if (fieldName.includes(pattern) || fieldLabel.includes(pattern)) {
411
+ return {
412
+ level: 3,
413
+ reason: `Field name suggests high risk PII (${pattern})`
414
+ };
415
+ }
416
+ }
417
+
418
+ // Check for medium risk PII
419
+ for (const pattern of piiPatterns.medium) {
420
+ if (fieldName.includes(pattern) || fieldLabel.includes(pattern)) {
421
+ return {
422
+ level: 2,
423
+ reason: `Field name suggests potential PII (${pattern})`
424
+ };
425
+ }
426
+ }
427
+
428
+ // Check field types that might contain PII
429
+ if (fieldType === 'email') {
430
+ return {
431
+ level: 2,
432
+ reason: 'Email field type may contain PII'
433
+ };
434
+ }
435
+
436
+ if (fieldType === 'phone' || fieldType === 'textarea') {
437
+ return {
438
+ level: 1,
439
+ reason: `${fieldType} field type may contain PII`
440
+ };
441
+ }
442
+
443
+ // No PII detected
444
+ return {
445
+ level: 0,
446
+ reason: 'No obvious PII indicators'
447
+ };
448
+ }
449
+
450
+ // UI Functions
451
+ function updateProgress(percent) {
452
+ progressFill.style.width = `${percent}%`;
453
+ progressText.textContent = `${Math.round(percent)}%`;
454
+ }
455
+
456
+ function renderResults() {
457
+ resultsContainer.innerHTML = '';
458
+
459
+ // Sort objects by PII score (descending)
460
+ const sortedObjects = [...objectsData].sort((a, b) => b.piiScore - a.piiScore);
461
+
462
+ for (const obj of sortedObjects) {
463
+ if (obj.piiFields.length > 0) {
464
+ const objectCard = document.createElement('div');
465
+ objectCard.className = 'bg-gray-50 rounded-lg border border-gray-200 overflow-hidden slide-in';
466
+
467
+ // Object header
468
+ const header = document.createElement('div');
469
+ header.className = 'flex items-center justify-between p-4 bg-white border-b border-gray-200 cursor-pointer';
470
+ header.innerHTML = `
471
+ <div class="flex items-center">
472
+ <div class="w-3 h-3 rounded-full ${getPiiColorClass(obj.piiScore)} mr-3"></div>
473
+ <div>
474
+ <h4 class="font-medium text-gray-800">${obj.label} (${obj.name})</h4>
475
+ <div class="text-xs text-gray-500">${obj.piiFields.length} potential PII fields</div>
476
+ </div>
477
+ </div>
478
+ <div class="flex items-center">
479
+ <span class="text-sm font-medium ${getPiiTextColorClass(obj.piiScore)} mr-2">
480
+ PII Score: ${obj.piiScore}
481
+ </span>
482
+ <i class="fas fa-chevron-down text-gray-400 transition-transform"></i>
483
+ </div>
484
+ `;
485
+
486
+ // Fields container (initially hidden)
487
+ const fieldsContainer = document.createElement('div');
488
+ fieldsContainer.className = 'hidden p-4 bg-white';
489
+
490
+ // Add fields to container
491
+ obj.piiFields.sort((a, b) => b.piiRisk.level - a.piiRisk.level).forEach(field => {
492
+ const fieldDiv = document.createElement('div');
493
+ fieldDiv.className = `p-3 mb-2 rounded-md ${getPiiFieldClass(field.piiRisk.level)}`;
494
+ fieldDiv.innerHTML = `
495
+ <div class="flex justify-between items-start">
496
+ <div>
497
+ <div class="font-medium">${field.label} (${field.name})</div>
498
+ <div class="text-sm text-gray-600 mt-1">${field.piiRisk.reason}</div>
499
+ </div>
500
+ <span class="text-xs font-medium px-2 py-1 rounded-full ${getPiiRiskBadgeClass(field.piiRisk.level)}">
501
+ ${getPiiRiskLabel(field.piiRisk.level)}
502
+ </span>
503
+ </div>
504
+ <div class="text-xs text-gray-500 mt-2">
505
+ <span class="font-medium">Type:</span> ${field.type} |
506
+ <span class="font-medium">Length:</span> ${field.length || 'N/A'} |
507
+ <span class="font-medium">API Name:</span> ${field.name}
508
+ </div>
509
+ `;
510
+ fieldsContainer.appendChild(fieldDiv);
511
+ });
512
+
513
+ // Toggle fields visibility on header click
514
+ header.addEventListener('click', () => {
515
+ const icon = header.querySelector('i');
516
+ fieldsContainer.classList.toggle('hidden');
517
+ icon.classList.toggle('fa-chevron-down');
518
+ icon.classList.toggle('fa-chevron-up');
519
+ });
520
+
521
+ objectCard.appendChild(header);
522
+ objectCard.appendChild(fieldsContainer);
523
+ resultsContainer.appendChild(objectCard);
524
+ }
525
+ }
526
+ }
527
+
528
+ function filterResults() {
529
+ const filterValue = filterSelect.value;
530
+ const allCards = resultsContainer.querySelectorAll('.bg-gray-50');
531
+
532
+ allCards.forEach(card => {
533
+ const objectName = card.querySelector('h4').textContent;
534
+ const isStandard = !objectName.includes('__c');
535
+ const hasPII = !card.querySelector('.hidden');
536
+
537
+ switch (filterValue) {
538
+ case 'all':
539
+ card.style.display = 'block';
540
+ break;
541
+ case 'pii':
542
+ card.style.display = hasPII ? 'block' : 'none';
543
+ break;
544
+ case 'standard':
545
+ card.style.display = isStandard ? 'block' : 'none';
546
+ break;
547
+ case 'custom':
548
+ card.style.display = isStandard ? 'none' : 'block';
549
+ break;
550
+ }
551
+ });
552
+ }
553
+
554
+ function getPiiColorClass(score) {
555
+ if (score >= 60) return 'bg-red-500';
556
+ if (score >= 30) return 'bg-yellow-500';
557
+ return 'bg-blue-500';
558
+ }
559
+
560
+ function getPiiTextColorClass(score) {
561
+ if (score >= 60) return 'text-red-600';
562
+ if (score >= 30) return 'text-yellow-600';
563
+ return 'text-blue-600';
564
+ }
565
+
566
+ function getPiiFieldClass(level) {
567
+ if (level === 3) return 'pii-high';
568
+ if (level === 2) return 'pii-medium';
569
+ return 'pii-low';
570
+ }
571
+
572
+ function getPiiRiskBadgeClass(level) {
573
+ if (level === 3) return 'bg-red-100 text-red-800';
574
+ if (level === 2) return 'bg-yellow-100 text-yellow-800';
575
+ return 'bg-blue-100 text-blue-800';
576
+ }
577
+
578
+ function getPiiRiskLabel(level) {
579
+ if (level === 3) return 'High Risk';
580
+ if (level === 2) return 'Medium Risk';
581
+ return 'Low Risk';
582
+ }
583
+
584
+ function showLoginState() {
585
+ loadingState.classList.add('hidden');
586
+ appContent.classList.add('hidden');
587
+ loginState.classList.remove('hidden');
588
+ loginButton.classList.remove('hidden');
589
+ userInfo.classList.add('hidden');
590
+ }
591
+
592
+ function logout() {
593
+ // Clear OAuth data
594
+ accessToken = null;
595
+ instanceUrl = null;
596
+ userId = null;
597
+ orgId = null;
598
+ objectsData = [];
599
+ piiCount = 0;
600
+
601
+ // Reset UI
602
+ showLoginState();
603
+ totalObjects.textContent = '0';
604
+ piiFields.textContent = '0';
605
+ progressFill.style.width = '0%';
606
+ progressText.textContent = '0%';
607
+ }
608
+ </script>
609
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Naresh1993/deepsitetest" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
610
  </html>