const isDebugMode = window.location.search.includes('debug=true'); let debugLogContainer = null; let debugLogCounter = 0; const cookieDomain = '.' + getMainDomain(window.location.href); firebaseDebugLog(true, 'cookieDomain-' + cookieDomain); let refreshInterval; let logoutInProgress = false; let pendingCred = null; document.addEventListener('DOMContentLoaded', function () { // Create debug overlay if debug mode is enabled if (isDebugMode) { createDebugOverlay(); } //Safe to expose as they are identification values not auth keys const firebaseConfig = { apiKey: "AIzaSyA6qrL3tY40YlRkSK4XTS7zijAJ4n15MNU", authDomain: "sso.consequence.net", projectId: "consequence-25a8e", storageBucket: "consequence-25a8e.appspot.com", messagingSenderId: "993189234631", appId: "1:993189234631:web:4d0a240cc0ab799b65fbe2", measurementId: "G-V7CZFS1TQG" }; firebase.initializeApp(firebaseConfig); // Check for native Facebook OAuth callback first (Option 5) handleFacebookOAuthCallback().then(handled => { if (handled) { firebaseDebugLog(true, 'Facebook OAuth callback handled, skipping Firebase redirect check'); return; } // If not a Facebook OAuth callback, check for Firebase redirect result return firebase.auth().getRedirectResult(); }).then(async (result) => { if (!result) return; // Already handled by Facebook OAuth callback if (!result || !result.user) return; const user = result.user; const idToken = await user.getIdToken(); const response = await login(user, idToken); if (response && response.success) { window.location.reload(); } else { console.log("WP login failed after redirect"); } }) .catch((e) => { console.log("getRedirectResult error:", e.code, e.message, e); }); var googleLoginBtn = document.getElementById('googleLoginBtn'); var facebookLoginBtn = document.getElementById('facebook-login'); var twitterLoginBtn = document.getElementById('twitter-login'); var appleLoginBtn = document.getElementById('apple-login'); var logoutBtn = document.getElementById('logoutBtn'); if (googleLoginBtn) { googleLoginBtn.addEventListener('click', function () { var provider = new firebase.auth.GoogleAuthProvider(); provider.setCustomParameters({ prompt: 'select_account' }); handleSignInWithProvider(provider, 'google'); }); } // Facebook Authentication if (facebookLoginBtn) { facebookLoginBtn.addEventListener('click', function () { var provider = new firebase.auth.FacebookAuthProvider(); // provider.setCustomParameters({ // auth_type: 'reauthenticate' // }); handleSignInWithProvider(provider, 'facebook'); }); } // Twitter Authentication if (twitterLoginBtn) { twitterLoginBtn.addEventListener('click', function () { var provider = new firebase.auth.TwitterAuthProvider(); provider.setCustomParameters({ 'force_login': 'true' // Forces the user to reauthenticate }); handleSignInWithProvider(provider, 'twitter'); }); } // Apple Authentication if (appleLoginBtn) { appleLoginBtn.addEventListener('click', function () { var provider = new firebase.auth.OAuthProvider('apple.com'); handleSignInWithProvider(provider, 'apple'); }); } if (logoutBtn) { logoutBtn.addEventListener('click', function () { logout(); }); } firebase.auth().onAuthStateChanged((user) => { firebaseDebugLog(true, '---Start onAuthStateChanged---'); if (logoutInProgress == true) return; // Don't logout if Facebook OAuth is in progress (Option 5 only) if (localStorage.getItem('fb_oauth_processing') === 'true') { firebaseDebugLog(true, 'Facebook OAuth in progress, skipping auth state check'); firebaseDebugLog(true, '---End onAuthStateChanged---'); return; } if (user) { syncGeoToLambda(user.email); firebaseDebugLog(true, 'User signed in:' + user); // regenerateIdToken(user); // Start the refresh process if (checkCookieExists()) { firebaseDebugLog(true, 'CookieExists'); startTokenRefresh(user); } else { firebaseDebugLog(true, 'No CookieExists'); firebaseDebugLog(true, 'No sessioncookie found, logout'); localStorage.setItem('localLogout', 2); //1=local, 2=auto logout(); } } else { firebaseDebugLog(true, 'No user signed in'); clearInterval(refreshInterval); // Clear the interval on sign-out firebaseDebugLog(true, 'On authstatechange check cookie'); // checkSessionCookie(); } firebaseDebugLog(true, '---End onAuthStateChanged---'); }); async function handleSignInWithProvider(provider, pname) { firebaseDebugLog(true, '---Start handleSignInWithProvider'); const loader = document.getElementById('loginSpinner'); try { localStorage.setItem('loggedInLocally', 'true'); logoutInProgress = true; // Option 5: Use native Facebook OAuth for mobile devices ONLY // This includes: mobile regular browsers AND mobile in-app browsers // Desktop in-app browsers will use standard popup flow // This bypasses Firebase's /__/auth/ handler which is blocked by nginx if (pname === 'facebook' && isMobileDevice()) { firebaseDebugLog(true, 'Using custom Facebook OAuth (Option 5) for mobile device'); await handleFacebookNativeAuth(); return; } if (isInAppBrowser()) { await firebase.auth().signInWithRedirect(provider); return; } const result = await firebase.auth().signInWithPopup(provider); loader.style.display = 'flex'; document.getElementById('socialLogin').style.display = 'none'; document.querySelector('.sfba-close').style.display = 'none'; const user = result.user; firebaseDebugLog(true, 'handleSignInWithProvider-' + user); const idToken = await user.getIdToken(); firebaseDebugLog(true, 'ID Token:-' + idToken); const response = await login(user, idToken); if (!response || !response.success) { // Handle unsuccessful login localStorage.removeItem('loggedInLocally'); document.getElementById('socialLogin').style.display = 'block'; document.querySelector('.sfba-close').style.display = 'block'; loader.style.display = 'none'; throw new Error('Failed to authenticate.'); } logoutInProgress = false; window.location.reload(); // Reload the page on successful login } catch (error) { logoutInProgress = false; firebaseDebugLog(true, 'Error during Firebase authentication:' + error.message); localStorage.removeItem('loggedInLocally'); // Ensure localStorage is cleaned up handleLoginError(error); } firebaseDebugLog(true, '---End handleSignInWithProvider'); } function login(user, idToken) { firebaseDebugLog(true, '---Start Login'); return new Promise((resolve, reject) => { jQuery.ajax({ url: firebaseAuthAjax.ajax_url, method: 'POST', data: { action: 'firebase_login', nonce: firebaseAuthAjax.nonce, email: user.email, display_name: user.displayName, provider_id: user.providerData[0].uid, provider_name: user.providerData[0].providerId, idToken: idToken, firebase_uid: user.uid }, success: function (response) { firebaseDebugLog(true, 'login success response:-' + response); setCookie('ssosession', idToken, 24, cookieDomain); syncGeoToLambda(user.email); resolve(response); firebaseDebugLog(true, '---End Login'); }, error: function (error) { firebaseDebugLog(true, 'Error logging in:-' + error); reject(error); } }); }); } async function handleLoginError(error) { if (error.code === 'auth/account-exists-with-different-credential') { jQuery('.temp-preferences').show(); jQuery('.temp-preferences .sfba-before-login').show(); jQuery(".socialLogin").hide(); var email = error.email; // Store credential in memory - cannot reliably serialize Firebase credentials to JSON pendingCred = error.credential; try { var methods = await firebase.auth().fetchSignInMethodsForEmail(email); if (methods.length > 0) { localStorage.setItem('existingProvider', methods[0]); jQuery(".sfba-mask").removeClass("sfba-active"); jQuery(".sfba-link-mask").addClass('sfba-active'); handleLinkModel(methods[0]); } } catch (fetchError) { firebaseDebugLog(true, 'Error fetching sign-in methods: ' + fetchError.message); } } else if (error.code === 'auth/popup-blocked' || error.code === 'auth/popup-closed-by-user') { firebaseDebugLog(true, 'Popup blocked or closed by user'); // Note: Cannot redirect here as we don't have provider context } else { firebaseDebugLog(true, error.message); jQuery('.temp-preferences').hide(); jQuery('.temp-preferences .sfba-before-login').hide(); jQuery(".socialLogin").show(); localStorage.removeItem('Firebaseuserstorage'); } } function handleLinkModel(provider) { // Hide all link buttons first, then show only the relevant one jQuery(".sfba-social-btn-link").hide(); if (provider == 'google.com') { jQuery("#socialLoginLink .link-message .provider-name").html("Google"); jQuery(".sfba-social-btn-link.sfba-login-with-google-btn").show(); } else if (provider == 'facebook.com') { jQuery("#socialLoginLink .link-message .provider-name").html("Facebook"); jQuery(".sfba-social-btn-link.sfba-login-with-facebook-btn").show(); } else if (provider == 'apple.com') { jQuery("#socialLoginLink .link-message .provider-name").html("Apple"); jQuery(".sfba-social-btn-link.sfba-login-with-apple-btn").show(); } else { firebaseDebugLog(true, 'Provider doesnt exist: ' + provider); } } function getAuthProvider(providerId) { switch (providerId) { case firebase.auth.GoogleAuthProvider.PROVIDER_ID: return new firebase.auth.GoogleAuthProvider(); case firebase.auth.FacebookAuthProvider.PROVIDER_ID: return new firebase.auth.FacebookAuthProvider(); case 'apple.com': return new firebase.auth.OAuthProvider('apple.com'); default: throw new Error('No provider found for the given provider ID.'); } } // Modal for SSO Social media buttons and Add ARtist/Tags jQuery(".sfba-show").on("click", function () { var errorElement = document.getElementById("errorMessage"); if (errorElement) { errorElement.innerHTML = ''; } jQuery(".sfba-mask").addClass("sfba-active"); }); // Close popup jQuery(".sfba-close").on("click", function () { jQuery(".sfba-mask").removeClass("sfba-active"); }); // Close popup jQuery(".sfba-link-close").on("click", function () { jQuery(".sfba-link-mask").removeClass("sfba-active"); }); jQuery(".sfba-show-pref").on("click", function () { jQuery(".sfba-mask-pref").addClass("sfba-active"); }); jQuery(".sfba-close-pref").on("click", function () { jQuery(".sfba-mask-pref").removeClass("sfba-active"); }); jQuery('.tab-nav span').on('click', function () { if (jQuery(this).text() == 'My Tags') { jQuery('#all-preferences .tab-nav ul li').removeClass('active'); jQuery('#all-preferences .tab-nav ul li:nth-child(2)').addClass('active'); jQuery('#all-preferences #all-artists').removeClass('active'); jQuery('#all-preferences #all-tags').addClass('active'); } else { jQuery('#all-preferences .tab-nav ul li').addClass('active'); jQuery('#all-preferences .tab-nav ul li:nth-child(2)').removeClass('active'); jQuery('#all-preferences #all-artists').addClass('active'); jQuery('#all-preferences #all-tags').removeClass('active'); } jQuery([jQuery(this).parent()[0], jQuery(jQuery(this).data('href'))[0]]).addClass('active').siblings('.active').removeClass('active'); }); // Delete Artists/Tags jQuery('body').on('click', '.preference-delete, .preference-add.deleteid', function () { var preftype = jQuery(this).data("preftype"); var currentemailaddress = jQuery("#current-email-address").val(); if (jQuery(this).hasClass('deleteid')) { jQuery(this).removeClass('deleteid'); jQuery(this).addClass('addid'); jQuery(this).find('span.pref-add').html('').html('✛'); jQuery(this).find('span.pref-add').css('color', '#009b1a'); var delId = jQuery(this).data("addid"); if (preftype == "artist") { jQuery(".my-artist-list li").each(function () { if (jQuery(this).find("a").attr("data-delid") == delId) { jQuery(this).remove(); } }); } else { jQuery(".my-tags-list li").each(function () { if (jQuery(this).find("a").attr("data-delid") == delId) { jQuery(this).remove(); } }); } } else { var delId = jQuery(this).data("delid"); jQuery(this).parent().remove(); if (preftype == "artist") { jQuery(".preferences-list ul.artist-list li").each(function () { if (jQuery(this).find("a").attr("data-addid") == delId) { jQuery(this).find('span.pref-add').html('').html('✛'); jQuery(this).find('span.pref-add').css('color', '#009b1a'); } }); } else { jQuery(".preferences-list ul.post_tag-list li").each(function () { if (jQuery(this).find("a").attr("data-addid") == delId) { jQuery(this).find('span.pref-add').html('').html('✛'); jQuery(this).find('span.pref-add').css('color', '#009b1a'); } }); } } jQuery.ajax({ type: 'POST', url: firebaseAuthAjax.ajax_url, cache: true, data: { action: 'delete_preferences_action', currentemailaddress: currentemailaddress, delId: delId, preftype: preftype, }, success: function (response) { if (preftype == "artist") { if (jQuery('ul.my-artist-list').find('li').length === 0) { jQuery('.preferences-list.my-artists-ul').html('

Please click the "plus" icon to the right to add Artists to your profile

'); } } else { if (jQuery('ul.my-tags-list').find('li').length === 0) { jQuery('.preferences-list.my-tags-ul').html('

Please click the "plus" icon to the right to add Tags to your profile

'); } } } }); }); let currentAjaxRequest = null; jQuery('.search-preferences').keyup(function (event) { if ((event.key === 'Enter' && jQuery(this).val().length > 2) || jQuery(this).val().length > 2) { jQuery('.search-pref-btn').click(); } if (event.key === 'Backspace') { jQuery('.search-pref-btn').click(); } }); jQuery('.search-pref-btn').on('click', function () { jQuery('.filterButton').removeClass('active'); searchTerm = jQuery(this).prev().val(); var ptype = jQuery(this).data('type'); var preftype = ''; var prefidstring = ''; var textpref = ''; var arrayinside = false; if (ptype === 'artist') { preftype = "artist"; prefidstring = jQuery("#artist_id").val(); textpref = "Artist"; } else if (ptype === 'post_tag') { preftype = "tags"; prefidstring = jQuery("#tag_id").val(); textpref = "Tags"; } if (searchTerm != "") { // Make AJAX request if (currentAjaxRequest) { currentAjaxRequest.abort(); } currentAjaxRequest = jQuery.ajax({ type: 'POST', url: firebaseAuthAjax.ajax_url, dataType: 'json', data: { action: 'preferences_search_action', nonce: firebaseAuthAjax.nonce, search_term: searchTerm, ptype: ptype }, success: function (response) { currentAjaxRequest = null; jQuery('.' + ptype + '-list li').css("display", "none"); jQuery('.' + ptype + '-list li.nonpop-search-data').remove(); var jsonString = JSON.stringify(response); var dataArray = JSON.parse(jsonString); setTimeout(function () { if (Array.isArray(dataArray) && dataArray.length > 0) { jQuery('.post_tag-list p').remove(); jQuery('.artist-list p').remove(); $.each(dataArray, function (index, item) { if (prefidstring !== '' && prefidstring.includes(item.term_id)) { arrayinside = true; } if (arrayinside) { jQuery('.' + ptype + '-list').append('
  • ' + item.name + '
  • '); } else { jQuery('.' + ptype + '-list').append('
  • ' + item.name + '
  • '); } jQuery('.' + ptype + '-list li.nonpop-search-data').css("display", "block"); }); } else { if (jQuery('.not-found').length === 0) { jQuery('.' + ptype + '-list').append('

    No ' + textpref + ' found

    '); } } }, 500); } }); } else { jQuery('.filterButton:first-child').addClass('active'); jQuery('.' + ptype + '-list li').css("display", "block"); jQuery('.' + ptype + '-list li.nonpop-search-data').remove(); } }); jQuery('.filterButton').on('click', function () { jQuery('.post_tag-list p').remove(); jQuery('.artist-list p').remove(); jQuery('.filterButton').removeClass("active"); var filter = jQuery(this).data('filter'); jQuery(this).addClass("active"); jQuery(this).parent().prev().find('.search-preferences').val(filter); var preid = jQuery(this).parent().parent().attr('id'); if (preid === 'all-artists') { var ptype = 'artist'; } else { var ptype = 'post_tag'; } if (ptype == "artist") { var customclass = '.artist-list li'; } else if (ptype == "post_tag") { var customclass = '.post_tag-list li'; } if (filter == "ALL") { jQuery('.' + ptype + '-list li').css("display", "block"); jQuery('.' + ptype + '-list li.nonpop-search-data').remove(); } else { jQuery(customclass).each(function () { var firstLetter = jQuery(this).text().charAt(0).toUpperCase(); if (firstLetter === filter) { jQuery(this).show(); } else { jQuery(this).hide(); } }); jQuery('.' + ptype + '-list li.nonpop-search-data').remove(); } }); // Add Artists/Tags jQuery('body').on('click', '.preference-add.addid', function () { var preftype = jQuery(this).data("preftype"); var currentemailaddress = jQuery("#current-email-address").val(); var newValueartist = '', newValuetags = '', artistadd = '', tagsadd = ''; if (preftype == 'artist') { newValueartist = jQuery(this).data('addid'); artistname = jQuery(this).data('title'); artistadd = '
  • ' + artistname + '
  • '; } else { newValuetags = jQuery(this).data('addid'); tagsname = jQuery(this).data('title'); tagsadd = '
  • ' + tagsname + '
  • '; } jQuery(this).find('span.pref-add').html('').html('✕'); jQuery(this).find('span.pref-add').css('color', '#ff0000'); jQuery(this).removeClass('addid'); jQuery(this).addClass('deleteid'); jQuery.ajax({ type: 'POST', url: firebaseAuthAjax.ajax_url, cache: true, data: { action: 'add_preferences_action', currentemailaddress: currentemailaddress, preftype: preftype, newValueartist: newValueartist, newValuetags: newValuetags, }, success: function (response) { if (artistadd != '') { if (jQuery(".my-artists-ul").find('p').length) { jQuery(".my-artists-ul").html(''); jQuery(".my-artists-ul").append('
    '); jQuery(".my-artists-ul p").css("display", "none"); } else { // jQuery(".my-artists-ul ul").append(artistadd); appendLi('.my-artist-list', artistadd, artistname); } } if (tagsadd != '') { if (jQuery(".my-tags-ul").find('p').length) { jQuery(".my-tags-ul").html(''); jQuery(".my-tags-ul").append('
    '); jQuery(".my-tags-ul p").css("display", "none"); } else { // jQuery(".my-tags-ul ul").append(tagsadd); appendLi('.my-tags-list', tagsadd, tagsname); } } } }); }); // Delete Artists/Tags jQuery('body').on('click', '.preference-delete, .preference-add.deleteid', function () { var preftype = jQuery(this).data("preftype"); var currentemailaddress = jQuery("#current-email-address").val(); if (jQuery(this).hasClass('deleteid')) { jQuery(this).removeClass('deleteid'); jQuery(this).addClass('addid'); jQuery(this).find('span.pref-add').html('').html('✛'); jQuery(this).find('span.pref-add').css('color', '#009b1a'); var delId = jQuery(this).data("addid"); if (preftype == "artist") { jQuery(".my-artist-list li").each(function () { if (jQuery(this).find("a").attr("data-delid") == delId) { jQuery(this).remove(); } }); } else { jQuery(".my-tags-list li").each(function () { if (jQuery(this).find("a").attr("data-delid") == delId) { jQuery(this).remove(); } }); } } else { var delId = jQuery(this).data("delid"); if (preftype == "artist") { jQuery(".preferences-list ul.artist-list li").each(function () { if (jQuery(this).find("a").attr("data-addid") == delId) { jQuery(this).find('span.pref-add').html('').html('✛'); jQuery(this).find('span.pref-add').css('color', '#009b1a'); } }); } else { jQuery(".preferences-list ul.post_tag-list li").each(function () { if (jQuery(this).find("a").attr("data-addid") == delId) { jQuery(this).find('span.pref-add').html('').html('✛'); jQuery(this).find('span.pref-add').css('color', '#009b1a'); } }); } } jQuery.ajax({ type: 'POST', url: firebaseAuthAjax.ajax_url, cache: true, data: { action: 'delete_preferences_action', currentemailaddress: currentemailaddress, delId: delId, preftype: preftype, }, success: function (response) { if (preftype == "artist") { if (jQuery('ul.my-artist-list').find('li').length === 0) { jQuery('.preferences-list.my-artists-ul').html('

    Please click the "plus" icon to the right to add Artists to your profile

    '); } } else { if (jQuery('ul.my-tags-list').find('li').length === 0) { jQuery('.preferences-list.my-tags-ul').html('

    Please click the "plus" icon to the right to add Tags to your profile

    '); } } } }); }); function appendLi(selector, litoadd, textname) { var $list = jQuery(selector); var $newItem = jQuery(litoadd); var textnameIsNumeric = !isNaN(textname); var inserted = false; $list.children('li').each(function () { var $currentItem = jQuery(this); var currentTextName = $currentItem.find('span:first').text(); var currentIsNumeric = !isNaN(currentTextName); if (textnameIsNumeric && currentIsNumeric) { if (parseFloat(textname) < parseFloat(currentTextName)) { $currentItem.before($newItem); inserted = true; return false; } } else if (!textnameIsNumeric && !currentIsNumeric) { if (String(textname).toLowerCase() < String(currentTextName).toLowerCase()) { $currentItem.before($newItem); inserted = true; return false; } } else if (textnameIsNumeric && !currentIsNumeric) { $currentItem.before($newItem); inserted = true; return false; } }); if (!inserted) { $list.append($newItem); } } jQuery(".sfba-social-btn-link").on("click", async function () { jQuery(".sfba-link-mask").removeClass('sfba-active'); var existingProvider = localStorage.getItem('existingProvider'); localStorage.removeItem('existingProvider'); var authProvider = getAuthProvider(existingProvider); try { // Step 1: Sign in with the existing (original) provider var result = await firebase.auth().signInWithPopup(authProvider); var user = result.user; var idToken = await user.getIdToken(); // Step 2: Log in / create the WordPress user (reuses the same login() helper) var loginResponse = await login(user, idToken); if (!loginResponse || !loginResponse.success) { localStorage.removeItem('loggedInLocally'); throw new Error('Failed to authenticate with WordPress.'); } // Step 3: Link the pending credential (from the failed sign-in attempt) if (pendingCred) { try { // var linkResult = await user.linkWithCredential(pendingCred); // // Update cookie with fresh token from the now-linked account // var newIdToken = await linkResult.user.getIdToken(true); setCookie('ssosession', idToken, 24, cookieDomain); firebaseDebugLog(true, 'Account linking successful'); } catch (linkError) { firebaseDebugLog(true, 'Error linking account (non-fatal): ' + linkError.message); // Linking failed but user is already logged in — proceed with existing token } pendingCred = null; } window.location.reload(); } catch (error) { firebaseDebugLog(true, 'Error during account link flow: ' + error.message); } }); /** * Handle native Facebook OAuth (Option 5) * Redirects to Facebook OAuth URL */ async function handleFacebookNativeAuth() { firebaseDebugLog(true, '=== NATIVE FACEBOOK OAUTH (Option 5) ==='); // Facebook App ID (from Facebook Developer Console) const facebookAppId = '2018160385090572'; // Build Facebook OAuth URL const redirectUri = encodeURIComponent(window.location.origin + window.location.pathname); const state = Math.random().toString(36).substring(7); // Random state for security localStorage.setItem('fb_oauth_state', state); localStorage.setItem('fb_oauth_redirect', window.location.href); const facebookAuthUrl = `https://www.facebook.com/v12.0/dialog/oauth?` + `client_id=${facebookAppId}` + `&redirect_uri=${redirectUri}` + `&state=${state}` + `&scope=email,public_profile` + `&response_type=token`; firebaseDebugLog(true, 'Redirecting to Facebook OAuth:', facebookAuthUrl); // Redirect to Facebook window.location.href = facebookAuthUrl; } /** * Handle Facebook OAuth callback * Called on page load to check if we're returning from Facebook OAuth */ async function handleFacebookOAuthCallback() { // Check if login just completed (prevent reload loop) if (sessionStorage.getItem('fb_login_complete') === 'true') { firebaseDebugLog(true, 'Facebook login already completed this session, skipping callback'); sessionStorage.removeItem('fb_login_complete'); return false; } firebaseDebugLog(true, 'Checking for Facebook OAuth callback...'); // Check if URL has Facebook OAuth response (access_token in hash) const hash = window.location.hash; if (!hash || hash.indexOf('access_token=') === -1) { firebaseDebugLog(true, 'No access_token in hash, not a Facebook OAuth callback'); return false; } // Prevent multiple executions if (localStorage.getItem('fb_oauth_processing') === 'true') { firebaseDebugLog(true, 'Already processing Facebook OAuth, skipping'); return true; // Return true to prevent other handlers } localStorage.setItem('fb_oauth_processing', 'true'); firebaseDebugLog(true, '=== FACEBOOK OAUTH CALLBACK DETECTED ==='); try { // Parse the hash fragment const params = new URLSearchParams(hash.substring(1)); const accessToken = params.get('access_token'); const state = params.get('state'); firebaseDebugLog(true, 'Parsed access_token length:', accessToken?.length); firebaseDebugLog(true, 'Parsed state:', state); // Verify state to prevent CSRF const savedState = localStorage.getItem('fb_oauth_state'); firebaseDebugLog(true, 'Saved state:', savedState); if (state !== savedState) { firebaseDebugLog(true, 'ERROR: State mismatch, possible CSRF attack'); localStorage.removeItem('fb_oauth_processing'); return false; } // Exchange Facebook access token for Firebase credential firebaseDebugLog(true, 'Creating Facebook credential from access token'); const credential = firebase.auth.FacebookAuthProvider.credential(accessToken); firebaseDebugLog(true, 'Signing into Firebase with Facebook credential'); const result = await firebase.auth().signInWithCredential(credential); firebaseDebugLog(true, 'Firebase signInWithCredential successful'); const user = result.user; firebaseDebugLog(true, 'User:', user.email, 'UID:', user.uid); // Get Firebase ID token const idToken = await user.getIdToken(); firebaseDebugLog(true, 'Got Firebase ID token, length:', idToken.length); // Login to WordPress firebaseDebugLog(true, 'Calling WordPress login'); const loginResponse = await login(user, idToken); if (!loginResponse || !loginResponse.success) { firebaseDebugLog(true, 'ERROR: WordPress login failed'); localStorage.removeItem('fb_oauth_processing'); throw new Error('Failed to authenticate with WordPress.'); } firebaseDebugLog(true, 'WordPress login successful!'); // Clean up localStorage.removeItem('fb_oauth_state'); localStorage.removeItem('fb_oauth_processing'); localStorage.removeItem('fb_oauth_redirect'); // Set flag to prevent re-processing on reload sessionStorage.setItem('fb_login_complete', 'true'); // Clean hash from URL and reload window.location.hash = ''; window.location.reload(); return true; } catch (error) { firebaseDebugLog(true, 'ERROR in Facebook OAuth callback:', error.code, error.message); localStorage.removeItem('fb_oauth_processing'); // Handle account-exists-with-different-credential error (same as standard flow) if (error.code === 'auth/account-exists-with-different-credential') { // Clean the hash from URL first window.location.hash = ''; jQuery('.temp-preferences').show(); jQuery('.temp-preferences .sfba-before-login').show(); jQuery(".socialLogin").hide(); var email = error.email; // Store credential in memory pendingCred = error.credential; try { var methods = await firebase.auth().fetchSignInMethodsForEmail(email); if (methods.length > 0) { localStorage.setItem('existingProvider', methods[0]); jQuery(".sfba-mask").removeClass("sfba-active"); jQuery(".sfba-link-mask").addClass('sfba-active'); handleLinkModel(methods[0]); } } catch (fetchError) { firebaseDebugLog(true, 'Error fetching sign-in methods: ' + fetchError.message); } } return false; } } }); function logout() { firebaseDebugLog(true, '---Start Logout'); logoutInProgress = true; if (localStorage.getItem('localLogout') === null || localStorage.getItem('localLogout') == 1) { logoutPopup(); } localStorage.removeItem('localLogout'); // Sign out from Firebase firebase.auth().signOut().then(function () { firebaseDebugLog(true, 'User signed out from Firebase.'); // Perform an AJAX request to log the user out from WordPress jQuery.ajax({ url: firebaseAuthAjax.ajax_url, type: 'POST', data: { action: 'firebase_logout' // nonce: firebaseAuthAjax.nonce }, success: function (response) { if (response.success) { localStorage.removeItem('loggedInLocally'); logoutInProgress = false; document.cookie = 'ssosession=; path=/; domain=' + cookieDomain + '; expires=Thu, 01 Jan 1970 00:00:00 UTC;'; window.location.reload(); // Reload the page after successful logout } else { firebaseDebugLog(true, 'Logout failed: ', response.data.message); } firebaseDebugLog(true, '---End Logout'); }, error: function (xhr, status, error) { firebaseDebugLog(true, 'Error logging out: ', xhr.responseText); } }); }).catch(function (error) { firebaseDebugLog(true, 'Firebase logout failed: ', error.message); }); } function loginPopup() { const popupOverlay = document.createElement('div'); popupOverlay.className = 'popup-overlay'; popupOverlay.innerHTML = ``; // Append overlay to the body document.body.appendChild(popupOverlay); // Display the popup popupOverlay.style.display = 'block'; } function logoutPopup() { const popupOverlay = document.createElement('div'); popupOverlay.className = 'popup-overlay'; popupOverlay.innerHTML = ``; // Append overlay to the body document.body.appendChild(popupOverlay); // Display the popup popupOverlay.style.display = 'block'; } function checkCookieExists() { const sessionCookie = getCookie('ssosession'); if (sessionCookie) { return sessionCookie; } return null; } function getCookie(name) { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop().split(';').shift(); } function startTokenRefresh(user) { firebaseDebugLog('refreshInterval-' + new Date().toLocaleString() + '---' + refreshInterval); // Clear any existing intervals clearInterval(refreshInterval); // Refresh the token every 50 minutes (3000 seconds) refreshInterval = setInterval(() => { regenerateIdToken(user); }, 50 * 60 * 1000); // 50 minutes in milliseconds } function regenerateIdToken(user) { user.getIdToken(true) .then((idToken) => { firebaseDebugLog('New ID Token:' + idToken); setCookie('ssosession', idToken, 24, cookieDomain); }) .catch((error) => { firebaseDebugLog('Error getting ID token:', error); }); } function setCookie(name, value, hours, domain) { const expires = new Date(Date.now() + hours * 60 * 60 * 1000).toUTCString(); const cookieValue = `${name}=${encodeURIComponent(value)}; expires=${expires}; path=/; domain=${domain}; secure=false; SameSite=Lax`; firebaseDebugLog('cookieValue' + cookieValue); document.cookie = cookieValue; } function getMainDomain(url) { const urlObject = new URL(url); const hostParts = urlObject.hostname.split('.'); // If the host has two or more parts, join the last two parts as the main domain if (hostParts.length >= 2) { const mainDomain = hostParts.slice(-2).join('.'); return mainDomain; } // Fallback for a single part (e.g., localhost) return urlObject.hostname; } function createDebugOverlay() { // Create overlay container debugLogContainer = document.createElement('div'); debugLogContainer.id = 'firebase-debug-overlay'; debugLogContainer.style.cssText = ` position: fixed; top: 0; left: 0; width: 300px; height: 70vh; max-height: 70vh; background: rgba(0, 0, 0, 0.9); color: #0f0; font-family: monospace; font-size: 11px; padding: 10px; overflow-y: auto; z-index: 999999; border-right: 2px solid #0f0; border-bottom: 2px solid #0f0; `; // Add title bar with download button const titleBar = document.createElement('div'); titleBar.style.cssText = 'display: flex; justify-content: space-between; align-items: center; margin-bottom: 5px;'; const title = document.createElement('div'); title.textContent = '🔥 Firebase Debug Log'; title.style.cssText = 'font-weight: bold; color: #ff0;'; const downloadBtn = document.createElement('button'); downloadBtn.textContent = '📥 Download'; downloadBtn.style.cssText = ` background: #0f0; color: #000; border: none; padding: 3px 8px; font-size: 10px; font-weight: bold; cursor: pointer; border-radius: 3px; `; downloadBtn.addEventListener('click', function (e) { e.stopPropagation(); downloadDebugLog(); }); titleBar.appendChild(title); titleBar.appendChild(downloadBtn); debugLogContainer.appendChild(titleBar); // Add close instruction const closeMsg = document.createElement('div'); closeMsg.textContent = '(Tap log area to close)'; closeMsg.style.cssText = 'font-size: 9px; color: #888; margin-bottom: 5px;'; debugLogContainer.appendChild(closeMsg); // Make it closable (but not the download button) debugLogContainer.addEventListener('click', function (e) { if (e.target !== downloadBtn) { debugLogContainer.style.display = 'none'; } }); document.body.appendChild(debugLogContainer); console.log('Debug overlay created'); } function firebaseDebugLog(stat = false, ...messages) { if (isDebugMode && stat) { console.log('Firebase:-', ...messages); // Also write to overlay if it exists if (debugLogContainer) { try { debugLogCounter++; const logEntry = document.createElement('div'); logEntry.style.cssText = 'margin: 2px 0; padding: 2px; border-bottom: 1px solid #333;'; const timestamp = new Date().toLocaleTimeString(); const messageText = messages.map(m => typeof m === 'object' ? JSON.stringify(m) : String(m) ).join(' '); logEntry.innerHTML = `[${debugLogCounter}] ${timestamp}
    ${messageText}`; debugLogContainer.appendChild(logEntry); // Auto-scroll to bottom debugLogContainer.scrollTop = debugLogContainer.scrollHeight; } catch (e) { console.error('Failed to write to debug log:', e); } } } } // Wrapper function for backward compatibility function debugLog(stat = false, ...messages) { firebaseDebugLog(stat, ...messages); } function downloadDebugLog() { if (!debugLogContainer) { console.error('Debug log container not found'); return; } // Collect all log entries const logEntries = debugLogContainer.querySelectorAll('div'); let logText = 'Firebase Authentication Debug Log\n'; logText += '=================================\n'; logText += 'Generated: ' + new Date().toLocaleString() + '\n'; logText += 'URL: ' + window.location.href + '\n'; logText += 'User Agent: ' + navigator.userAgent + '\n'; logText += '=================================\n\n'; // Extract text from each log entry logEntries.forEach((entry, index) => { // Skip the title and close message if (index > 1) { const text = entry.innerText || entry.textContent; if (text && text.trim()) { logText += text + '\n'; } } }); // Create blob and download const blob = new Blob([logText], { type: 'text/plain' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'firebase-debug-log-' + Date.now() + '.txt'; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); console.log('Debug log downloaded'); } function isInAppBrowser() { const ua = navigator.userAgent || ""; return /FBAN|FBAV|Instagram|Line|Twitter|Snapchat|MicroMessenger/i.test(ua); } function isMobileDevice() { const ua = navigator.userAgent || ""; // Check for mobile devices (iPhone, iPad, Android, etc.) return /iPhone|iPad|iPod|Android|webOS|BlackBerry|IEMobile|Opera Mini/i.test(ua); } function getCurrentGeoData() { return { country: typeof COS_COUNTRY !== 'undefined' ? COS_COUNTRY : '', state: typeof COS_STATE !== 'undefined' ? COS_STATE : '', city: typeof COS_CITY !== 'undefined' ? COS_CITY : '', latitude: typeof COS_LATITUDE !== 'undefined' ? COS_LATITUDE : '', longitude: typeof COS_LONGITUDE !== 'undefined' ? COS_LONGITUDE : '', }; } function hasGeoChanged(currentGeo, lastSyncedGeo) { return ( currentGeo.country !== (lastSyncedGeo.country || '') || currentGeo.state !== (lastSyncedGeo.state || '') || currentGeo.city !== (lastSyncedGeo.city || '') || String(currentGeo.latitude) !== String(lastSyncedGeo.latitude || '') || String(currentGeo.longitude) !== String(lastSyncedGeo.longitude || '') ); } async function syncGeoToLambda(userEmail) { if (!userEmail) return; const currentGeo = getCurrentGeoData(); const lastSyncedGeo = JSON.parse(localStorage.getItem('COS_GEO_DATA') || '{}'); if (currentGeo && !hasGeoChanged(currentGeo, lastSyncedGeo)) { return; } try { const response = await fetch('/wp-admin/admin-ajax.php', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ action: 'save_geo_to_dynamodb', geo: JSON.stringify(currentGeo), userEmail: userEmail }) }); localStorage.setItem('COS_GEO_DATA', JSON.stringify(currentGeo)); const result = await response.json(); // console.log('Geo synced:', result); } catch (err) { console.error('Geo sync failed:', err); } } ; window.dataLayer = window.dataLayer || []; function trackIframeClick() { window.addEventListener('blur', function (e) { if (document.activeElement.nodeName == "IFRAME" && (document.activeElement.src != '' || document.activeElement.name != '')) { var type = ''; var iframeURL = document.activeElement.src; if (document.activeElement.src != '') { if (document.activeElement.src.indexOf('spotify') != -1) type = 'spotify'; if (document.activeElement.src.indexOf('itunes') != -1) type = 'itunes'; if (document.activeElement.src.indexOf('youtube') != -1) type = 'youtube'; if (document.activeElement.src.indexOf('tunein') != -1) type = 'tunein'; if (document.activeElement.src.indexOf('acast') != -1) type = 'acast'; if (document.activeElement.src.indexOf('anchor') != -1) type = 'anchor'; if (document.activeElement.src.indexOf('apple') != -1) type = 'apple'; } else if (document.activeElement.name != '') { if (document.activeElement.name.indexOf('frame-product') != -1) { type = 'cosstore'; iframeURL = document.activeElement.name; } } try { const fullUrl = new URL(iframeURL); const gaItem = { 'eventCategory': 'iframe', 'eventAction': 'iframe_click', 'eventLabel': type, 'eventUrl': fullUrl.href, 'eventReferrer': window.parent.location.href, 'event': 'cos_click', 'eventValue': 1, }; window.dataLayer.push(gaItem); } catch (error) { console.log('iframe click', 'error', error); } } }); } trackIframeClick(); function trackSearchClicks() { const trackedLinks = document.querySelectorAll('a.track-links'); trackedLinks.forEach(function (link) { link.addEventListener('click', function (event) { try { const href = this.getAttribute('href'); const type = this.getAttribute('data-type'); const fullUrl = new URL(href, window.location.href); const gaItem = { 'eventCategory': 'search', 'eventAction': 'search_click', 'eventLabel': type, 'eventUrl': fullUrl.href, 'eventReferrer': window.parent.location.href, 'event': 'cos_search_click', 'eventValue': 1, }; window.dataLayer.push(gaItem); } catch (error) { console.log('search click', 'error', error); } }); }); } trackSearchClicks();; /** * Check if key exists in local storage * @param string key * @return boolean */ function localStorageHas (key) { var item = localStorage.getItem(key); return ( item !== null ); } /** * Retrive an object from local storage. * @param string key * @return mixed */ function localStorageGet (key) { var item = localStorage.getItem(key); if ( ! item ) return; if ( item[0] === '{' || item[0] === '[' ) return JSON.parse(item); return item; } /** * Save some value to local storage. * @param string key * @param string value */ function localStorageSet (key, value) { if ( value === undefined ) $.error("Can't store undefinded value"); if ( typeof(value) === 'object' || typeof(value) === 'array' ) { value = JSON.stringify(value); } if ( typeof(value) !== 'string' ) $.error("Can't store unrecognized format value"); localStorage.setItem(key, value); } /** * Remove element from local storage. * @param string key */ function localStorageRemove (key) { localStorage.removeItem(key); }; window.jQuery = window.$ = jQuery; $(document).ready(function () { /* // FIXED TOP NAV $(document).on("scroll", function() { if ($(document).scrollTop() > 400) { $(".fixed-top").addClass("scrolled slideInDown"); } else { $(".fixed-top").removeClass("scrolled"); } }); // FIXED TOP CATEGORIES NAV INNER PAGE $(document).on("scroll", function() { if ($(document).scrollTop() > 1200) { $(".cats-bar").addClass("scrolled slideInDown"); } else { $(".cats-bar").removeClass("scrolled"); } }); */ // MENU $(".but-menu").click(function () { $("#menu").addClass("reveal slideInLeft"); $('html').css('overflow', 'hidden'); $('body').bind('touchmove', function (e) { e.preventDefault() }); }); $(".menu-close").click(function () { $("#menu").removeClass("reveal"); $('html').css('overflow', 'scroll'); $('body').unbind('touchmove'); }); // MENU CATS $(document).ready(function() { // 1. Identify "flat" items (no sub-menu) and add the CSS flag $('.accordion .col').each(function() { // If this column does not contain a sub-menu list if ($(this).find('.sub-cats').length === 0) { // Add a class so CSS can hide the arrow icon $(this).find('.menu-item').addClass('no-sub'); } }); // 2. Unified Click Handler $(".menu-item").on('click', function(e) { // Stop default behavior and event clashing e.preventDefault(); e.stopImmediatePropagation(); var $this = $(this); var $parentCol = $this.closest('.col'); var $subMenu = $parentCol.find('.sub-cats'); var $link = $parentCol.find('.menu-d a').attr('href'); // Close all other open submenus $(".sub-cats").not($subMenu).hide(); $(".menu-item").not($this).removeClass("open"); // IF SUBMENU EXISTS: Toggle the accordion if ($subMenu.length > 0) { $this.toggleClass("open"); $subMenu.stop(true, true).toggle(); } // IF NO SUBMENU: Navigate to the destination URL else if ($link) { window.location.href = $link; } }); }); // SEARCH $(".but-search").click(function () { $("#search-bar").addClass("reveal slideInDown"); }); $(".search-close").click(function () { $("#search-bar").removeClass("reveal"); }); $("#search_404").click(function () { $("#search-bar").addClass("reveal slideInDown"); }); // FIXED FILTERS / TRENDING BAR ON SCROLL /* $('.fixed-bar.trending-bar').scrollToFixed({ marginTop: 130 }); */ $(window).on('load', function () { if ( $('.mobile-bar-drop').length > 0 && typeof $.fn.scrollToFixed === 'function' ) { $('.mobile-bar-drop').scrollToFixed({ marginTop: 110 }); } }); // FIXED AD ON SCROLL /* $('.fixed-ad-scroll').scrollToFixed({ marginTop: 140, zIndex: 10, limit: function() { var limit = $('#footer').offset().top - $('.fixed-ad-scroll').outerHeight(true) - 0; return limit; } }); */ /* $('.fixed-ad-scroll-bottom').scrollToFixed({ marginTop:400, limit: function() { var limit; if ($('.post-related').length > 0) { limit = $('.post-related').offset().top - $('.fixed-ad-scroll-bottom').outerHeight(true) - 80; } else { limit = $('#footer').offset().top - $('.fixed-ad-scroll-bottom').outerHeight(true) - 40; } return limit; } }); */ // FIXED SOCIAL ON SCROLL /* $('.social-follow.fixed').scrollToFixed({ marginTop: 200, limit: function() { var limit = $('.post-tags').offset().top - $('.social-follow.fixed').outerHeight(true) - 40; return limit; } }); */ // FIXED VIDEO ON SCROLL /* $('.fixed-watch-video').scrollToFixed({ marginTop: 200, limit: function() { var limit; if ($('.post-related').length > 0) { limit = $('.post-related').offset().top - $('.fixed-watch-video').outerHeight(true) - 80; } else { limit = $('#footer').offset().top - $('.fixed-watch-video').outerHeight(true) - 40; } return limit; } }); */ // FIXED SQUARE ON SCROLL /* $('.fixed-ad-aside').scrollToFixed({ marginTop: 200, limit: function() { var limit; if ($('.post-related').length > 0) { limit = $('.post-related').offset().top - $('.fixed-ad-aside').outerHeight(true) - 80; } else { limit = $('#footer').offset().top - $('.fixed-ad-aside').outerHeight(true) - 40; } if ($('.fixed-watch-video').length > 0) { limit += $('.fixed-watch-video').outerHeight(true); } return limit; } }); */ // READER'S RATING $(document).on("scroll", function () { if ($(document).scrollTop() > 200) { $(".reader-rating").addClass("scrolled bounceInUp"); } else { $(".reader-rating").removeClass("scrolled"); } }); // MOBILE BAR DROP $(".open-drop").click(function () { $(".open-drop").toggleClass("open"); }); $(".open-drop").click(function () { $(".mobile-bar-drop ul").toggle(); }); // VIDEOS PLAYLIST $(".video-playlist a").click(function () { var parent_div = $(this).closest('div'); var src = $(parent_div).attr('data-src'); var type = $(parent_div).attr('data-type'); var poster = $(parent_div).attr('data-poster'); var title = $(parent_div).attr('data-title'); var videoObj = $(this).parents(".mod-playlist").find(".video-js"); if (videoObj.length !== 0) { var player = videojs(videoObj.attr('id')); if (src == player.src()) { return; } if (player.ads && player.ads.isInAdMode()) { return; } player.poster(poster); player.src([{ type: type, src: src }]); player.play(); player.on('loadstart', function (event) { $('#' + player.id() + '_title').text(title) }); $(this).parents('.col-video-scrollable').find('p.play-now a').text('Play Now'); $(this).parents('.video-playlist').find('p.play-now a').text('Now Playing'); } }); // VIDEOS Playing Now Text $("p.play-now a").first().text('Now Playing'); // MOBILE ADHESION //$(".mobile-adhesion").delay(5000).fadeOut('slow'); /* // RENDER PENDING ADS function renderPendingAds() { $(".ad_pending").each(function(i, e){ renderAd($(e).attr('data-adunit'), $(e).attr('data-size'), $(e).attr('id')); $(e).removeClass('ad_pending'); }); } // REGULAR ADS renderPendingAds(); // INFINITE SCROLL ADS $(document.body).on('post-load', function () { renderPendingAds(); }); */ resizeIframes(); }); // IFRAME RESIZING function resizeIframes() { $("iframe").each(function (i, v) { if ($(v).hasClass('no-resize')) { return; } var domains = ['spotify', 'apple', 'vevo', 'music.amazon']; if (typeof $(v).attr('src') !== 'undefined') { $(domains).each(function (di, dv) { if ($(v).attr('src').indexOf(dv) !== -1) { $(v).attr('height', 450); } }); if ($(v).attr('src').indexOf('anchor') !== -1) { $(v).attr('height', 160); $(v).attr('scrolling', 'no'); } } }); } // inifiite scroll on category and tag pages (function ($) { $(document.body).on('post-load', function () { window.EncoreAdSystem.observerAds(); embedInitiate(); }); })(jQuery); // For initial load window.addEventListener('load', function () { embedInitiate(); }); function embedInitiate() { if (window.instgrm) { window.instgrm.Embeds.process(); } if (window.twttr && window.twttr.widgets && typeof window.twttr.widgets.load === 'function') { window.twttr.widgets.load(); } if (typeof window.tiktokEmbedLoad === 'function') { window.tiktokEmbedLoad(); } } // ajax load more - next page in infinite scroll window.almComplete = function (alm) { resizeIframes(); setupAllDfpAds(); //setupIframeOnDemand(); if (typeof initGallery === 'function') initGallery(); // actual code in partials/common/_gallery.php window.EncoreAdSystem.observerAds(); } $(document).ready(function () { if (typeof initGallery === 'function') initGallery(); // actual code in partials/common/_gallery.php }); window.almUrlUpdate = function (permalink, type) { gtag("event", "page_view", { page_path: window.location.pathname, custom_map: { 'dimension1': 'Categories', 'dimension2': 'Tags', 'dimension3': 'Authors', 'dimension4': 'Artists', 'dimension6': 'page_id', 'dimension7': 'Primary Category', 'dimension9': 'Paged Article', 'dimension10': 'Primary Search Term' } }); } // iframe on demand for youtube function setupIframeOnDemand() { $(".embed-youtube-on-demand").click(function () { var id = $(this).children('img').attr('data-id'); var iframe = ''; $(this).replaceWith(iframe); }); } $(function () { var url = new URL(window.location.href); if (url.searchParams.get('app')) { $("a").attr('href', function (index, item) { if (item) return item + (item.indexOf('?') != -1 ? "&app=true" : "?app=true"); }); } var subId3 = ''; if (subId3 = url.searchParams.get('subId3')) { $("a").attr('href', function (index, item) { if (item && item.indexOf('ticketmaster') !== -1) return item + (item.indexOf('?') != -1 ? "&subId3=" + subId3 : "?subId3=" + subId3); }); } let appleRegex = /(itunes.apple.com|podcasts.apple.com)([A-Za-z0-9\/_-]+)/gm; $("a").attr('href', function (index, item) { let affId = 'at=1001l36gv'; if (item && item.match(appleRegex) && item.indexOf(affId) === -1) { if (item.indexOf('?') != -1) return item + "&" + affId; else return item + "?" + affId; } }); });;