mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 04:51:11 -05:00
Update email cancellation and location detection functions
Refactor Supabase function to use explicit JWT verification via auth.getUser, and enhance the location detection function with configurable geolocation API endpoints. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 364fb426-1d27-49b2-a244-a34e41c335e4 Replit-Commit-Checkpoint-Type: intermediate_checkpoint
This commit is contained in:
4
.replit
4
.replit
@@ -33,7 +33,3 @@ outputType = "webview"
|
||||
[[ports]]
|
||||
localPort = 5000
|
||||
externalPort = 80
|
||||
|
||||
[[ports]]
|
||||
localPort = 45303
|
||||
externalPort = 3000
|
||||
|
||||
@@ -5,31 +5,6 @@ const corsHeaders = {
|
||||
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
|
||||
};
|
||||
|
||||
// Helper function to decode JWT and extract user ID
|
||||
// Properly handles base64url encoding used by JWTs
|
||||
function decodeJWT(token: string): { sub: string } | null {
|
||||
try {
|
||||
const parts = token.split('.');
|
||||
if (parts.length !== 3) return null;
|
||||
|
||||
// JWT uses base64url encoding, convert to standard base64
|
||||
let base64 = parts[1].replace(/-/g, '+').replace(/_/g, '/');
|
||||
|
||||
// Add padding if needed
|
||||
while (base64.length % 4) {
|
||||
base64 += '=';
|
||||
}
|
||||
|
||||
// Decode and parse the payload
|
||||
const decoded = atob(base64);
|
||||
const payload = JSON.parse(decoded);
|
||||
return payload;
|
||||
} catch (error) {
|
||||
console.error('JWT decode error:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Deno.serve(async (req) => {
|
||||
// Handle CORS preflight requests
|
||||
if (req.method === 'OPTIONS') {
|
||||
@@ -37,18 +12,6 @@ Deno.serve(async (req) => {
|
||||
}
|
||||
|
||||
try {
|
||||
// Create admin client with service role key
|
||||
const supabaseAdmin = createClient(
|
||||
Deno.env.get('SUPABASE_URL') ?? '',
|
||||
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') ?? '',
|
||||
{
|
||||
auth: {
|
||||
autoRefreshToken: false,
|
||||
persistSession: false
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Get the user from the authorization header
|
||||
const authHeader = req.headers.get('Authorization');
|
||||
if (!authHeader) {
|
||||
@@ -56,17 +19,35 @@ Deno.serve(async (req) => {
|
||||
throw new Error('No authorization header provided. Please ensure you are logged in.');
|
||||
}
|
||||
|
||||
// Extract the JWT token from the Authorization header
|
||||
const token = authHeader.replace('Bearer ', '');
|
||||
console.log('Extracting user ID from JWT token...');
|
||||
|
||||
// Create admin client with service role key (no user token in global headers)
|
||||
// This ensures all DB operations run with full admin privileges
|
||||
const supabaseUrl = Deno.env.get('SUPABASE_URL');
|
||||
const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY');
|
||||
|
||||
// Parse JWT token to get user ID directly
|
||||
const payload = decodeJWT(token);
|
||||
if (!payload || !payload.sub) {
|
||||
console.error('Invalid JWT token structure');
|
||||
if (!supabaseUrl || !supabaseServiceKey) {
|
||||
throw new Error('Missing Supabase configuration');
|
||||
}
|
||||
|
||||
const supabaseAdmin = createClient(supabaseUrl, supabaseServiceKey, {
|
||||
auth: {
|
||||
autoRefreshToken: false,
|
||||
persistSession: false
|
||||
}
|
||||
});
|
||||
|
||||
// Verify the user's JWT token by passing it explicitly to getUser()
|
||||
// Note: verify_jwt = true in config.toml means Supabase has already validated the JWT
|
||||
const { data: { user }, error: authError } = await supabaseAdmin.auth.getUser(token);
|
||||
|
||||
if (authError || !user) {
|
||||
console.error('Auth verification failed:', authError);
|
||||
throw new Error('Invalid session token. Please refresh the page and try again.');
|
||||
}
|
||||
|
||||
const userId = payload.sub;
|
||||
const userId = user.id;
|
||||
console.log(`Cancelling email change for user ${userId}`);
|
||||
|
||||
// Call the database function to clear email change fields
|
||||
|
||||
@@ -25,10 +25,14 @@ serve(async (req) => {
|
||||
|
||||
console.log('Detecting location for IP:', clientIP);
|
||||
|
||||
// Use a free IP geolocation service with proper error handling
|
||||
// Use configurable geolocation service with proper error handling
|
||||
// Defaults to ip-api.com if not configured
|
||||
const geoApiUrl = Deno.env.get('GEOLOCATION_API_URL') || 'http://ip-api.com/json';
|
||||
const geoApiFields = Deno.env.get('GEOLOCATION_API_FIELDS') || 'status,country,countryCode';
|
||||
|
||||
let geoResponse;
|
||||
try {
|
||||
geoResponse = await fetch(`http://ip-api.com/json/${clientIP}?fields=status,country,countryCode`);
|
||||
geoResponse = await fetch(`${geoApiUrl}/${clientIP}?fields=${geoApiFields}`);
|
||||
} catch (fetchError) {
|
||||
console.error('Network error fetching location data:', fetchError);
|
||||
throw new Error('Network error: Unable to reach geolocation service');
|
||||
|
||||
Reference in New Issue
Block a user