ultimate-jekyll-manager 0.0.119 → 0.0.121
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +102 -2
- package/README.md +171 -2
- package/TODO.md +10 -2
- package/_backup/form-manager.backup.js +1020 -0
- package/dist/assets/js/libs/auth/pages.js +64 -136
- package/dist/assets/js/libs/form-manager.js +643 -775
- package/dist/assets/js/pages/account/sections/api-keys.js +37 -52
- package/dist/assets/js/pages/account/sections/connections.js +37 -46
- package/dist/assets/js/pages/account/sections/delete.js +46 -66
- package/dist/assets/js/pages/account/sections/profile.js +37 -56
- package/dist/assets/js/pages/account/sections/security.js +100 -126
- package/dist/assets/js/pages/admin/notifications/new/index.js +72 -157
- package/dist/assets/js/pages/blog/index.js +29 -51
- package/dist/assets/js/pages/contact/index.js +110 -144
- package/dist/assets/js/pages/download/index.js +38 -86
- package/dist/assets/js/pages/oauth2/index.js +17 -17
- package/dist/assets/js/pages/payment/checkout/index.js +23 -36
- package/dist/assets/js/pages/test/libraries/form-manager/index.js +194 -0
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/signin.html +2 -2
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/signup.html +2 -2
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/contact.html +10 -37
- package/dist/defaults/dist/pages/test/libraries/form-manager.html +181 -0
- package/dist/gulp/tasks/serve.js +18 -0
- package/dist/lib/logger.js +1 -1
- package/firebase-debug.log +420 -0
- package/package.json +11 -7
- package/.playwright-mcp/page-2025-10-22T19-11-27-666Z.png +0 -0
- package/.playwright-mcp/page-2025-10-22T19-11-57-357Z.png +0 -0
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Security Section JavaScript
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Libraries
|
|
2
6
|
import authorizedFetch from '__main_assets__/js/libs/authorized-fetch.js';
|
|
3
7
|
import { FormManager } from '__main_assets__/js/libs/form-manager.js';
|
|
4
8
|
import { getPrerenderedIcon } from '__main_assets__/js/libs/prerendered-icons.js';
|
|
@@ -6,7 +10,11 @@ import { getPrerenderedIcon } from '__main_assets__/js/libs/prerendered-icons.js
|
|
|
6
10
|
let webManager = null;
|
|
7
11
|
let firebaseAuth = null;
|
|
8
12
|
let signinMethodForms = new Map(); // Store FormManager instances for signin methods
|
|
9
|
-
let
|
|
13
|
+
let signoutAllFormManager = null; // FormManager instance for sign out all sessions
|
|
14
|
+
|
|
15
|
+
// Check query string for popup parameter
|
|
16
|
+
const url = new URL(window.location.href);
|
|
17
|
+
const useAuthPopup = url.searchParams.get('authPopup') === 'true' || window !== window.top;
|
|
10
18
|
|
|
11
19
|
// Initialize security section
|
|
12
20
|
export function init(wm) {
|
|
@@ -17,7 +25,9 @@ export function init(wm) {
|
|
|
17
25
|
|
|
18
26
|
// Load security data
|
|
19
27
|
export function loadData(account) {
|
|
20
|
-
if (!account)
|
|
28
|
+
if (!account) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
21
31
|
|
|
22
32
|
console.log('[DEBUG] security.js - loadData() called with account:', account);
|
|
23
33
|
|
|
@@ -106,7 +116,7 @@ async function updateSigninMethods() {
|
|
|
106
116
|
$googleEmail: !!$googleEmail,
|
|
107
117
|
$googleForm: !!$googleForm,
|
|
108
118
|
$connectButton: !!$connectButton,
|
|
109
|
-
$disconnectButton: !!$disconnectButton
|
|
119
|
+
$disconnectButton: !!$disconnectButton,
|
|
110
120
|
});
|
|
111
121
|
|
|
112
122
|
if ($googleEmail && $connectButton && $disconnectButton) {
|
|
@@ -161,7 +171,9 @@ function update2FAStatus(twoFactorData) {
|
|
|
161
171
|
// Update active sessions
|
|
162
172
|
async function updateActiveSessions(account) {
|
|
163
173
|
const $sessionsList = document.getElementById('active-sessions-list');
|
|
164
|
-
if (!$sessionsList)
|
|
174
|
+
if (!$sessionsList) {
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
165
177
|
|
|
166
178
|
const sessions = [];
|
|
167
179
|
|
|
@@ -179,7 +191,7 @@ async function updateActiveSessions(account) {
|
|
|
179
191
|
region: account.activity.geolocation?.region,
|
|
180
192
|
country: account.activity.geolocation?.country,
|
|
181
193
|
timestamp: account.activity.created?.timestamp,
|
|
182
|
-
timestampUNIX: account.activity.created?.timestampUNIX
|
|
194
|
+
timestampUNIX: account.activity.created?.timestampUNIX,
|
|
183
195
|
};
|
|
184
196
|
sessions.push(currentSession);
|
|
185
197
|
}
|
|
@@ -195,9 +207,7 @@ async function updateActiveSessions(account) {
|
|
|
195
207
|
tries: 2,
|
|
196
208
|
body: {
|
|
197
209
|
command: 'user:get-active-sessions',
|
|
198
|
-
payload: {
|
|
199
|
-
// id: 'app',
|
|
200
|
-
},
|
|
210
|
+
payload: {},
|
|
201
211
|
},
|
|
202
212
|
});
|
|
203
213
|
|
|
@@ -240,7 +250,6 @@ async function updateActiveSessions(account) {
|
|
|
240
250
|
sessions.push(sessionObj);
|
|
241
251
|
});
|
|
242
252
|
}
|
|
243
|
-
|
|
244
253
|
} catch (error) {
|
|
245
254
|
console.error('Failed to get active sessions:', error);
|
|
246
255
|
}
|
|
@@ -259,7 +268,7 @@ async function updateActiveSessions(account) {
|
|
|
259
268
|
region: account.lastActivity.geolocation?.region,
|
|
260
269
|
country: account.lastActivity.geolocation?.country,
|
|
261
270
|
timestamp: account.lastActivity.timestamp,
|
|
262
|
-
timestampUNIX: account.lastActivity.timestampUNIX
|
|
271
|
+
timestampUNIX: account.lastActivity.timestampUNIX,
|
|
263
272
|
};
|
|
264
273
|
|
|
265
274
|
// Only add if it's different from current session (different IP or timestamp)
|
|
@@ -319,21 +328,16 @@ function initializeSigninMethodForms() {
|
|
|
319
328
|
console.log('[DEBUG] security.js - Initializing password FormManager');
|
|
320
329
|
|
|
321
330
|
const formManager = new FormManager($passwordForm, {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
submitButtonSuccessText: 'Email Sent'
|
|
331
|
+
allowResubmit: false,
|
|
332
|
+
submittingText: 'Sending...',
|
|
333
|
+
submittedText: 'Email Sent!',
|
|
326
334
|
});
|
|
327
335
|
|
|
328
336
|
signinMethodForms.set('password', formManager);
|
|
329
337
|
|
|
330
|
-
formManager.
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
} catch (error) {
|
|
334
|
-
formManager.showError(error);
|
|
335
|
-
formManager.setFormState('ready');
|
|
336
|
-
}
|
|
338
|
+
formManager.on('submit', async () => {
|
|
339
|
+
await handleChangePassword();
|
|
340
|
+
formManager.showSuccess('Password reset email sent!');
|
|
337
341
|
});
|
|
338
342
|
}
|
|
339
343
|
|
|
@@ -345,44 +349,24 @@ function initializeSigninMethodForms() {
|
|
|
345
349
|
console.log('[DEBUG] security.js - Google form exists:', !!$googleForm);
|
|
346
350
|
|
|
347
351
|
const formManager = new FormManager($googleForm, {
|
|
348
|
-
|
|
349
|
-
showSpinner: true
|
|
352
|
+
submittingText: 'Connecting...',
|
|
350
353
|
});
|
|
351
354
|
|
|
352
355
|
signinMethodForms.set('google', formManager);
|
|
353
356
|
console.log('[DEBUG] security.js - Google FormManager initialized and stored');
|
|
354
357
|
|
|
355
|
-
formManager.
|
|
356
|
-
event.preventDefault();
|
|
357
|
-
const { submitButton } = event.detail;
|
|
358
|
-
|
|
358
|
+
formManager.on('submit', async ({ $submitButton }) => {
|
|
359
359
|
// Determine action from the clicked button's data-action attribute
|
|
360
|
-
const action = submitButton?.getAttribute('data-action');
|
|
361
|
-
|
|
362
|
-
try {
|
|
363
|
-
if (action === 'disconnect') {
|
|
364
|
-
await disconnectGoogleProvider();
|
|
365
|
-
} else if (action === 'connect') {
|
|
366
|
-
await connectGoogleProvider();
|
|
367
|
-
}
|
|
360
|
+
const action = $submitButton?.getAttribute('data-action');
|
|
368
361
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
updateSigninMethods();
|
|
374
|
-
} catch (error) {
|
|
375
|
-
// Reset form state
|
|
376
|
-
formManager.setFormState('ready');
|
|
377
|
-
|
|
378
|
-
// If user cancelled, also update the display to ensure button state is correct
|
|
379
|
-
if (error.message === 'Disconnection cancelled') {
|
|
380
|
-
updateSigninMethods();
|
|
381
|
-
} else {
|
|
382
|
-
// Show error for other failures
|
|
383
|
-
formManager.showError(error);
|
|
384
|
-
}
|
|
362
|
+
if (action === 'disconnect') {
|
|
363
|
+
await disconnectGoogleProvider();
|
|
364
|
+
} else if (action === 'connect') {
|
|
365
|
+
await connectGoogleProvider();
|
|
385
366
|
}
|
|
367
|
+
|
|
368
|
+
// Update display after success
|
|
369
|
+
updateSigninMethods();
|
|
386
370
|
});
|
|
387
371
|
}
|
|
388
372
|
|
|
@@ -397,44 +381,31 @@ function initializeSigninMethodForms() {
|
|
|
397
381
|
function initializeSignoutAllForm() {
|
|
398
382
|
const $form = document.getElementById('signout-all-sessions-form');
|
|
399
383
|
|
|
400
|
-
if ($form && !
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
showSpinner: true
|
|
384
|
+
if ($form && !signoutAllFormManager) {
|
|
385
|
+
signoutAllFormManager = new FormManager($form, {
|
|
386
|
+
submittingText: 'Signing out...',
|
|
404
387
|
});
|
|
405
388
|
|
|
406
|
-
|
|
407
|
-
event.preventDefault();
|
|
408
|
-
|
|
389
|
+
signoutAllFormManager.on('submit', async () => {
|
|
409
390
|
// 1ms wait to allow form state to update and show processing
|
|
410
391
|
await new Promise(resolve => setTimeout(resolve, 1));
|
|
411
392
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
}
|
|
393
|
+
// Confirm sign out
|
|
394
|
+
if (!confirm('Are you sure you want to sign out of all sessions? This will log you out everywhere, including this device.')) {
|
|
395
|
+
throw new Error('Sign out cancelled.');
|
|
396
|
+
}
|
|
417
397
|
|
|
418
|
-
|
|
419
|
-
|
|
398
|
+
// Sign out of all sessions
|
|
399
|
+
await webManager.auth().signOut();
|
|
420
400
|
|
|
421
|
-
|
|
422
|
-
|
|
401
|
+
// Show success message
|
|
402
|
+
signoutAllFormManager.showSuccess('Successfully signed out of all sessions.');
|
|
423
403
|
|
|
424
|
-
|
|
425
|
-
// so we might not need to reset form state
|
|
426
|
-
} catch (error) {
|
|
427
|
-
if (error.message !== 'Sign out cancelled') {
|
|
428
|
-
signoutAllForm.showError(error);
|
|
429
|
-
}
|
|
430
|
-
signoutAllForm.setFormState('ready');
|
|
431
|
-
}
|
|
404
|
+
// Note: The page will likely redirect due to auth state change
|
|
432
405
|
});
|
|
433
406
|
}
|
|
434
407
|
}
|
|
435
408
|
|
|
436
|
-
|
|
437
|
-
|
|
438
409
|
// Connect Google provider
|
|
439
410
|
async function connectGoogleProvider() {
|
|
440
411
|
// Dynamic import of Firebase auth methods
|
|
@@ -442,35 +413,38 @@ async function connectGoogleProvider() {
|
|
|
442
413
|
|
|
443
414
|
const provider = new GoogleAuthProvider();
|
|
444
415
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
416
|
+
// Use popup if query parameter is set, otherwise use redirect
|
|
417
|
+
if (useAuthPopup) {
|
|
418
|
+
try {
|
|
419
|
+
const result = await linkWithPopup(firebaseAuth.currentUser, provider);
|
|
420
|
+
webManager.utilities().showNotification('Google account connected successfully', 'success');
|
|
449
421
|
|
|
450
|
-
|
|
451
|
-
|
|
422
|
+
// Force refresh of the current user to get updated provider data
|
|
423
|
+
await firebaseAuth.currentUser.reload();
|
|
452
424
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
425
|
+
return result;
|
|
426
|
+
} catch (error) {
|
|
427
|
+
// Check if we should fallback to redirect
|
|
428
|
+
if (error.code === 'auth/popup-blocked'
|
|
429
|
+
|| error.code === 'auth/popup-closed-by-user'
|
|
430
|
+
|| error.code === 'auth/cancelled-popup-request') {
|
|
459
431
|
|
|
460
|
-
|
|
432
|
+
console.log('Popup failed, falling back to redirect:', error.code);
|
|
461
433
|
|
|
462
|
-
|
|
463
|
-
try {
|
|
434
|
+
// Fallback to redirect
|
|
464
435
|
await linkWithRedirect(firebaseAuth.currentUser, provider);
|
|
465
436
|
// This will redirect the page, so no immediate result
|
|
466
|
-
}
|
|
467
|
-
throw
|
|
437
|
+
} else if (error.code === 'auth/credential-already-in-use') {
|
|
438
|
+
throw new Error('This Google account is already linked to another user');
|
|
439
|
+
} else {
|
|
440
|
+
throw error;
|
|
468
441
|
}
|
|
469
|
-
} else if (error.code === 'auth/credential-already-in-use') {
|
|
470
|
-
throw new Error('This Google account is already linked to another user');
|
|
471
|
-
} else {
|
|
472
|
-
throw error;
|
|
473
442
|
}
|
|
443
|
+
} else {
|
|
444
|
+
// Use redirect by default
|
|
445
|
+
console.log('Using redirect for Google account linking');
|
|
446
|
+
await linkWithRedirect(firebaseAuth.currentUser, provider);
|
|
447
|
+
// This will redirect the page, so no immediate result
|
|
474
448
|
}
|
|
475
449
|
}
|
|
476
450
|
|
|
@@ -481,7 +455,7 @@ async function disconnectGoogleProvider() {
|
|
|
481
455
|
|
|
482
456
|
// Confirm disconnection
|
|
483
457
|
if (!confirm('Are you sure you want to disconnect your Google account?')) {
|
|
484
|
-
throw new Error('Disconnection cancelled');
|
|
458
|
+
throw new Error('Disconnection cancelled.');
|
|
485
459
|
}
|
|
486
460
|
|
|
487
461
|
// Dynamic import of Firebase auth methods
|
|
@@ -508,22 +482,16 @@ async function disconnectGoogleProvider() {
|
|
|
508
482
|
|
|
509
483
|
// Handle change password
|
|
510
484
|
async function handleChangePassword() {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
}
|
|
485
|
+
const user = webManager.auth().getUser();
|
|
486
|
+
if (!user || !user.email) {
|
|
487
|
+
throw new Error('Please log in to reset your password.');
|
|
488
|
+
}
|
|
516
489
|
|
|
517
|
-
|
|
518
|
-
|
|
490
|
+
// Import Firebase auth method
|
|
491
|
+
const { sendPasswordResetEmail } = await import('@firebase/auth');
|
|
519
492
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
webManager.utilities().showNotification('Password reset email sent. Please check your inbox.', 'info');
|
|
523
|
-
} catch (error) {
|
|
524
|
-
console.error('Failed to send password reset:', error);
|
|
525
|
-
throw new Error(error.message || 'Failed to send password reset email. Please try again.');
|
|
526
|
-
}
|
|
493
|
+
// Send password reset email
|
|
494
|
+
await sendPasswordResetEmail(firebaseAuth, user.email);
|
|
527
495
|
}
|
|
528
496
|
|
|
529
497
|
// Handle 2FA button click
|
|
@@ -540,10 +508,11 @@ async function handle2FAClick(event) {
|
|
|
540
508
|
}
|
|
541
509
|
}
|
|
542
510
|
|
|
543
|
-
|
|
544
511
|
// Get device from user agent string
|
|
545
512
|
function getDeviceFromUserAgent(userAgent) {
|
|
546
|
-
if (!userAgent)
|
|
513
|
+
if (!userAgent) {
|
|
514
|
+
return 'Unknown Device';
|
|
515
|
+
}
|
|
547
516
|
|
|
548
517
|
const ua = userAgent.toLowerCase();
|
|
549
518
|
|
|
@@ -568,7 +537,9 @@ function getDeviceFromUserAgent(userAgent) {
|
|
|
568
537
|
|
|
569
538
|
// Get browser from user agent string
|
|
570
539
|
function getBrowserFromUserAgent(userAgent) {
|
|
571
|
-
if (!userAgent)
|
|
540
|
+
if (!userAgent) {
|
|
541
|
+
return 'Unknown Browser';
|
|
542
|
+
}
|
|
572
543
|
|
|
573
544
|
const ua = userAgent.toLowerCase();
|
|
574
545
|
|
|
@@ -585,7 +556,9 @@ function getBrowserFromUserAgent(userAgent) {
|
|
|
585
556
|
|
|
586
557
|
// Get platform name from platform string
|
|
587
558
|
function getPlatformName(platform) {
|
|
588
|
-
if (!platform)
|
|
559
|
+
if (!platform) {
|
|
560
|
+
return 'Unknown Device';
|
|
561
|
+
}
|
|
589
562
|
|
|
590
563
|
const platformLower = platform.toLowerCase();
|
|
591
564
|
|
|
@@ -652,7 +625,6 @@ function formatSessionLocation(session) {
|
|
|
652
625
|
return parts.length > 0 ? parts.join(', ') : null;
|
|
653
626
|
}
|
|
654
627
|
|
|
655
|
-
|
|
656
628
|
// Generate fake sessions for development mode
|
|
657
629
|
function generateFakeSessions() {
|
|
658
630
|
const now = Date.now();
|
|
@@ -665,42 +637,44 @@ function generateFakeSessions() {
|
|
|
665
637
|
platform: 'Windows',
|
|
666
638
|
ip: '98.137.246.8',
|
|
667
639
|
timestamp: new Date(now - (3 * oneHour)).toISOString(),
|
|
668
|
-
timestampUNIX: Math.floor((now - (3 * oneHour)) / 1000)
|
|
640
|
+
timestampUNIX: Math.floor((now - (3 * oneHour)) / 1000),
|
|
669
641
|
},
|
|
670
642
|
'session_def456': {
|
|
671
643
|
_current: false,
|
|
672
644
|
platform: 'Darwin', // macOS
|
|
673
645
|
ip: '192.168.1.42',
|
|
674
646
|
timestamp: new Date(now - (8 * oneHour)).toISOString(),
|
|
675
|
-
timestampUNIX: Math.floor((now - (8 * oneHour)) / 1000)
|
|
647
|
+
timestampUNIX: Math.floor((now - (8 * oneHour)) / 1000),
|
|
676
648
|
},
|
|
677
649
|
'session_ghi789': {
|
|
678
650
|
_current: false,
|
|
679
651
|
platform: 'Linux',
|
|
680
652
|
ip: '45.62.189.3',
|
|
681
653
|
timestamp: new Date(now - (oneDay)).toISOString(),
|
|
682
|
-
timestampUNIX: Math.floor((now - (oneDay)) / 1000)
|
|
654
|
+
timestampUNIX: Math.floor((now - (oneDay)) / 1000),
|
|
683
655
|
},
|
|
684
656
|
'session_jkl012': {
|
|
685
657
|
_current: false,
|
|
686
658
|
platform: 'Win32',
|
|
687
659
|
ip: '203.0.113.45',
|
|
688
660
|
timestamp: new Date(now - (2 * oneDay)).toISOString(),
|
|
689
|
-
timestampUNIX: Math.floor((now - (2 * oneDay)) / 1000)
|
|
661
|
+
timestampUNIX: Math.floor((now - (2 * oneDay)) / 1000),
|
|
690
662
|
},
|
|
691
663
|
'session_mno345': {
|
|
692
664
|
_current: false,
|
|
693
665
|
platform: 'Mac',
|
|
694
666
|
ip: '172.217.16.195',
|
|
695
667
|
timestamp: new Date(now - (5 * oneDay)).toISOString(),
|
|
696
|
-
timestampUNIX: Math.floor((now - (5 * oneDay)) / 1000)
|
|
697
|
-
}
|
|
668
|
+
timestampUNIX: Math.floor((now - (5 * oneDay)) / 1000),
|
|
669
|
+
},
|
|
698
670
|
};
|
|
699
671
|
}
|
|
700
672
|
|
|
701
673
|
// Format date helper
|
|
702
674
|
function formatDate(timestamp) {
|
|
703
|
-
if (!timestamp)
|
|
675
|
+
if (!timestamp) {
|
|
676
|
+
return 'Unknown';
|
|
677
|
+
}
|
|
704
678
|
|
|
705
679
|
const date = new Date(timestamp);
|
|
706
680
|
const now = new Date();
|