UNPKG

ultimate-jekyll-manager

Version:
140 lines (115 loc) 4.64 kB
// This file is required by /token page to generate custom auth tokens for extensions/apps import authorizedFetch from '__main_assets__/js/libs/authorized-fetch.js'; import webManager from 'web-manager'; // Module export default function () { const $status = document.getElementById('token-status'); const $error = document.getElementById('token-error'); const $errorMessage = document.getElementById('token-error-message'); // Get URL params const url = new URL(window.location.href); const authReturnUrl = url.searchParams.get('authReturnUrl'); // Handle DOM ready webManager.dom().ready() .then(async () => { // Log console.log('[Token] Initialized. authReturnUrl:', authReturnUrl); // Validate authReturnUrl if present if (authReturnUrl && !webManager.isValidRedirectUrl(authReturnUrl)) { showError('Invalid redirect URL'); return; } // Wait for auth to be ready and get user webManager.auth().listen({ once: true }, async (state) => { const user = state.user; // Should not happen since page requires auth, but just in case if (!user) { showError('Not authenticated. Please sign in first.'); return; } try { // Generate custom token updateStatus('Generating secure token...'); const token = await generateCustomToken(); // Update status updateStatus('Token generated successfully!'); // Handle redirect or URL update if (authReturnUrl) { // Redirect to return URL with token updateStatus('Redirecting...'); const returnUrl = new URL(authReturnUrl); returnUrl.searchParams.set('authToken', token); // LEGACY: Reformat token for desktop app deep links // TODO: Remove this block when legacy desktop app support is no longer needed _legacyTranslateTokenRedirect(returnUrl, token); const redirectUrl = returnUrl.toString(); console.log('[Token] Redirecting to:', redirectUrl); // Show retry button after a delay in case the redirect was cancelled (e.g. custom protocol dialog) setTimeout(() => { updateStatus('If you were not redirected, <a href="' + webManager.utilities().escapeHTML(redirectUrl) + '">click here to try again</a>.', true); }, 3000); window.location.href = redirectUrl; } else { // Add token to current URL (for browser extensions) // Extension background will detect this and close the tab url.searchParams.set('authToken', token); window.history.replaceState({}, '', url.toString()); updateStatus('You can close this tab now.'); } } catch (error) { console.error('[Token] Error generating token:', error); showError(error.message || 'Failed to generate token. Please try again.'); } }); }); // Generate custom token via backend-manager API async function generateCustomToken() { const serverApiURL = `${webManager.getApiUrl()}/backend-manager/user/token`; const response = await authorizedFetch(serverApiURL, { method: 'POST', timeout: 60000, response: 'json', tries: 2, }); // Extract token from response const token = response?.token; if (!token) { throw new Error('No token received from server'); } return token; } // Update status message (rawHtml=true only when caller has pre-escaped the content) function updateStatus(message, rawHtml) { if (!$status) { return; } const $p = document.createElement('p'); $p.className = 'text-muted small'; if (rawHtml) { $p.innerHTML = message; } else { $p.textContent = message; } $status.innerHTML = ''; $status.appendChild($p); } // Show error message function showError(message) { if ($error && $errorMessage) { $errorMessage.textContent = message; $error.classList.remove('d-none'); } if ($status) { $status.classList.add('d-none'); } } // LEGACY: Reformat token for desktop app deep links // Legacy desktop apps expect ?payload={"token":"X"} instead of ?authToken=X for custom protocol URLs // TODO: Remove this function AND its call above when legacy desktop app support is no longer needed function _legacyTranslateTokenRedirect(returnUrl, token) { if (returnUrl.protocol !== 'http:' && returnUrl.protocol !== 'https:') { returnUrl.searchParams.delete('authToken'); returnUrl.searchParams.set('payload', JSON.stringify({ token: token })); } } }