/** * OpenStreetMap OAuth2 authentication module for the OpenEventDatabase demo pages. * This module handles authentication with OpenStreetMap and stores/retrieves auth info in localStorage. */ // Constants const OSM_AUTH_STORAGE_KEY = 'oedb_osm_auth'; /** * OSM Authentication class */ class OSMAuth { constructor() { // Initialize auth state this.isAuthenticated = false; this.username = ''; this.userId = ''; // Load auth info from localStorage this.loadAuthInfo(); } /** * Load authentication information from localStorage */ loadAuthInfo() { try { const authInfo = localStorage.getItem(OSM_AUTH_STORAGE_KEY); if (authInfo) { const parsedAuthInfo = JSON.parse(authInfo); this.isAuthenticated = true; this.username = parsedAuthInfo.username || ''; this.userId = parsedAuthInfo.userId || ''; console.log('Loaded OSM auth info from localStorage:', this.username); } } catch (error) { console.error('Error loading OSM auth info from localStorage:', error); } } /** * Save authentication information to localStorage * @param {string} username - The OSM username * @param {string} userId - The OSM user ID */ saveAuthInfo(username, userId) { try { const authInfo = { username: username, userId: userId, timestamp: new Date().toISOString() }; localStorage.setItem(OSM_AUTH_STORAGE_KEY, JSON.stringify(authInfo)); this.isAuthenticated = true; this.username = username; this.userId = userId; console.log('Saved OSM auth info to localStorage:', username); } catch (error) { console.error('Error saving OSM auth info to localStorage:', error); } } /** * Clear authentication information from localStorage */ clearAuthInfo() { try { localStorage.removeItem(OSM_AUTH_STORAGE_KEY); this.isAuthenticated = false; this.username = ''; this.userId = ''; console.log('Cleared OSM auth info from localStorage'); } catch (error) { console.error('Error clearing OSM auth info from localStorage:', error); } } /** * Check if the user is authenticated * @returns {boolean} - True if the user is authenticated, false otherwise */ isUserAuthenticated() { return this.isAuthenticated; } /** * Get the OSM username * @returns {string} - The OSM username */ getUsername() { return this.username; } /** * Get the OSM user ID * @returns {string} - The OSM user ID */ getUserId() { return this.userId; } /** * Render the authentication section * @param {string} clientId - The OAuth2 client ID * @param {string} redirectUri - The OAuth2 redirect URI * @param {string} scope - The OAuth2 scope * @returns {string} - The HTML for the authentication section */ renderAuthSection(clientId, redirectUri, scope = 'read_prefs') { let html = '
'; html += '

OpenStreetMap Authentication

'; if (this.isAuthenticated) { html += '
'; html += '
'; html += `

Logged in as ${this.username}

`; html += `

View OSM Profile

`; html += ``; html += ``; html += '
'; html += '
'; } else { html += ``; html += ''; html += 'Login with OpenStreetMap'; html += ''; } html += '
'; return html; } /** * Process the OAuth2 callback * @param {string} authCode - The authorization code from the callback * @param {string} clientId - The OAuth2 client ID * @param {string} clientSecret - The OAuth2 client secret * @param {string} redirectUri - The OAuth2 redirect URI * @returns {Promise} - A promise that resolves when the authentication is complete */ processAuthCallback(authCode, clientId, clientSecret, redirectUri) { return new Promise((resolve, reject) => { if (!authCode) { reject(new Error('No authorization code provided')); return; } console.log('Processing OAuth2 callback with auth code:', authCode); // Exchange authorization code for access token const tokenUrl = 'https://www.openstreetmap.org/oauth2/token'; const tokenData = { grant_type: 'authorization_code', code: authCode, redirect_uri: redirectUri, client_id: clientId, client_secret: clientSecret }; // Make the request fetch(tokenUrl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams(tokenData) }) .then(response => { if (!response.ok) { throw new Error(`Token request failed with status ${response.status}`); } return response.json(); }) .then(tokenInfo => { const accessToken = tokenInfo.access_token; if (!accessToken) { throw new Error('No access token in response'); } // Use access token to get user information return fetch('https://api.openstreetmap.org/api/0.6/user/details.json', { headers: { 'Authorization': `Bearer ${accessToken}` } }); }) .then(response => { if (!response.ok) { throw new Error(`User details request failed with status ${response.status}`); } return response.json(); }) .then(userInfo => { const user = userInfo.user || {}; const username = user.display_name || ''; const userId = user.id || ''; if (!username) { throw new Error('No username in user details'); } // Save auth info to localStorage this.saveAuthInfo(username, userId); resolve({ username: username, userId: userId }); }) .catch(error => { console.error('Error during OAuth2 authentication:', error); reject(error); }); }); } } // Create a global instance of the OSMAuth class const osmAuth = new OSMAuth(); /** * Initialize the authentication module * This should be called when the page loads */ function initAuth() { console.log('Initializing OSM auth module'); // Check if we have an authorization code in the URL const urlParams = new URLSearchParams(window.location.search); const authCode = urlParams.get('code'); if (authCode) { console.log('Authorization code found in URL'); // Get OAuth2 configuration from the page const clientId = document.getElementById('osmClientId')?.value || ''; const clientSecret = document.getElementById('osmClientSecret')?.value || ''; const redirectUri = document.getElementById('osmRedirectUri')?.value || ''; if (clientId && redirectUri) { // Process the authorization code osmAuth.processAuthCallback(authCode, clientId, clientSecret, redirectUri) .then(userInfo => { console.log('Authentication successful:', userInfo); // Remove the authorization code from the URL const url = new URL(window.location.href); url.searchParams.delete('code'); url.searchParams.delete('state'); window.history.replaceState({}, document.title, url.toString()); // Reload the page to update the UI window.location.reload(); }) .catch(error => { console.error('Authentication failed:', error); }); } else { console.error('Missing OAuth2 configuration'); } } } // Export the OSMAuth instance and helper functions window.osmAuth = osmAuth; window.initAuth = initAuth; // Initialize the auth module when the page loads document.addEventListener('DOMContentLoaded', initAuth);