"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getUserClaims = exports.updateUserClaims = void 0; const app_1 = require("firebase-admin/app"); const auth_1 = require("firebase-admin/auth"); const firestore_1 = require("firebase-admin/firestore"); const https_1 = require("firebase-functions/v2/https"); const v2_1 = require("firebase-functions/v2"); // Initialize Firebase Admin if not already initialized if ((0, app_1.getApps)().length === 0) { (0, app_1.initializeApp)(); } (0, v2_1.setGlobalOptions)({ region: "us-central1", }); const auth = (0, auth_1.getAuth)(); const db = (0, firestore_1.getFirestore)(); // Helper function to validate authorization async function validateAuthorization(req) { const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith('Bearer ')) { throw new Error('Unauthorized: Missing or invalid authorization header'); } const idToken = authHeader.split('Bearer ')[1]; const decodedToken = await auth.verifyIdToken(idToken); const { orgId, role, territoryIds } = decodedToken; return { uid: decodedToken.uid, orgId, role, territoryIds: territoryIds || [] }; } // Helper function to check if user can manage claims for target org function canManageClaims(user, targetOrgId) { // Superadmin can manage any org if (user.role === 'superadmin') { return true; } // OrgAdmin can only manage their own org if (user.role === 'orgAdmin' && user.orgId === targetOrgId) { return true; } return false; } // POST /api/admin/users/:uid/claims exports.updateUserClaims = (0, https_1.onRequest)({ cors: true }, async (req, res) => { try { // Only allow POST requests if (req.method !== 'POST') { res.status(405).json({ error: 'Method not allowed' }); return; } // Validate authorization const authUser = await validateAuthorization(req); // Extract target user ID from path const targetUid = req.params.uid; if (!targetUid) { res.status(400).json({ error: 'Missing user ID in path' }); return; } // Parse request body const { orgId, role, territoryIds } = req.body; if (!orgId || !role || !Array.isArray(territoryIds)) { res.status(400).json({ error: 'Missing required fields: orgId, role, territoryIds' }); return; } // Validate role const validRoles = ['superadmin', 'orgAdmin', 'territoryManager', 'staff']; if (!validRoles.includes(role)) { res.status(400).json({ error: `Invalid role. Must be one of: ${ validRoles.join(', ')}` }); return; } // Check authorization if (!canManageClaims(authUser, orgId)) { res.status(403).json({ error: 'Insufficient permissions to manage claims for this organization' }); return; } // Validate territories exist in the org if (territoryIds.length > 0) { const territoryChecks = await Promise.all(territoryIds.map(async (territoryId) => { const territoryDoc = await db.collection('territories').doc(territoryId).get(); return territoryDoc.exists && territoryDoc.data()?.orgId === orgId; })); if (territoryChecks.some(valid => !valid)) { res.status(400).json({ error: 'One or more territory IDs are invalid or not in the specified organization' }); return; } } // Set custom user claims const customClaims = { orgId, role, territoryIds }; await auth.setCustomUserClaims(targetUid, customClaims); // Update user document in Firestore for UI consistency await db.collection('users').doc(targetUid).set({ orgId, role, territoryIds, updatedAt: new Date().toISOString(), updatedBy: authUser.uid }, { merge: true }); res.status(200).json({ success: true, claims: customClaims, message: 'User claims updated successfully' }); } catch (error) { console.error('Error updating user claims:', error); if (error instanceof Error) { if (error.message.includes('Unauthorized')) { res.status(401).json({ error: error.message }); } else if (error.message.includes('not found')) { res.status(404).json({ error: 'User not found' }); } else { res.status(500).json({ error: 'Internal server error' }); } } else { res.status(500).json({ error: 'Internal server error' }); } } }); // GET /api/admin/users/:uid/claims exports.getUserClaims = (0, https_1.onRequest)({ cors: true }, async (req, res) => { try { // Only allow GET requests if (req.method !== 'GET') { res.status(405).json({ error: 'Method not allowed' }); return; } // Validate authorization const authUser = await validateAuthorization(req); // Extract target user ID from path const targetUid = req.params.uid; if (!targetUid) { res.status(400).json({ error: 'Missing user ID in path' }); return; } // Get user record const userRecord = await auth.getUser(targetUid); const claims = userRecord.customClaims || {}; // Check if user can view these claims if (claims.orgId && !canManageClaims(authUser, claims.orgId)) { res.status(403).json({ error: 'Insufficient permissions to view claims for this user' }); return; } res.status(200).json({ uid: targetUid, email: userRecord.email, claims }); } catch (error) { console.error('Error getting user claims:', error); if (error instanceof Error) { if (error.message.includes('Unauthorized')) { res.status(401).json({ error: error.message }); } else if (error.message.includes('not found')) { res.status(404).json({ error: 'User not found' }); } else { res.status(500).json({ error: 'Internal server error' }); } } else { res.status(500).json({ error: 'Internal server error' }); } } }); // # sourceMappingURL=claims.js.map