|
@@ -9,7 +9,7 @@ const corsHeaders = {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Validate HMAC signature from ShopRenter
|
|
// Validate HMAC signature from ShopRenter
|
|
|
-// Per ShopRenter documentation, HMAC is calculated from code, shopname, and timestamp only
|
|
|
|
|
|
|
+// Per ShopRenter documentation, HMAC is calculated from all query params except 'hmac' itself
|
|
|
function validateHMAC(params: URLSearchParams, clientSecret: string): boolean {
|
|
function validateHMAC(params: URLSearchParams, clientSecret: string): boolean {
|
|
|
if (!clientSecret) {
|
|
if (!clientSecret) {
|
|
|
console.error('[ShopRenter] Client secret is empty or undefined')
|
|
console.error('[ShopRenter] Client secret is empty or undefined')
|
|
@@ -22,20 +22,20 @@ function validateHMAC(params: URLSearchParams, clientSecret: string): boolean {
|
|
|
return false
|
|
return false
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Get the required parameters for HMAC validation
|
|
|
|
|
- // Per ShopRenter docs, only code, shopname, and timestamp are included
|
|
|
|
|
- const code = params.get('code')
|
|
|
|
|
- const shopname = params.get('shopname')
|
|
|
|
|
- const timestamp = params.get('timestamp')
|
|
|
|
|
-
|
|
|
|
|
- if (!code || !shopname || !timestamp) {
|
|
|
|
|
- console.error('[ShopRenter] Missing required parameters for HMAC validation')
|
|
|
|
|
- return false
|
|
|
|
|
|
|
+ // Get all parameters except 'hmac' and sort them alphabetically
|
|
|
|
|
+ // Per ShopRenter docs pseudocode: const { hmac, ...dataToValidate } = params;
|
|
|
|
|
+ const dataToValidate: Record<string, string> = {}
|
|
|
|
|
+ for (const [key, value] of params.entries()) {
|
|
|
|
|
+ if (key !== 'hmac') {
|
|
|
|
|
+ dataToValidate[key] = value
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Create query string with parameters in alphabetical order
|
|
|
|
|
- // Per ShopRenter docs: code, shopname, timestamp (alphabetically sorted)
|
|
|
|
|
- const sortedParams = `code=${code}&shopname=${shopname}×tamp=${timestamp}`
|
|
|
|
|
|
|
+ // Sort parameters alphabetically by key and create query string
|
|
|
|
|
+ const sortedParams = Object.keys(dataToValidate)
|
|
|
|
|
+ .sort()
|
|
|
|
|
+ .map(key => `${key}=${dataToValidate[key]}`)
|
|
|
|
|
+ .join('&')
|
|
|
|
|
|
|
|
console.log(`[ShopRenter] HMAC validation - sorted params: ${sortedParams}`)
|
|
console.log(`[ShopRenter] HMAC validation - sorted params: ${sortedParams}`)
|
|
|
console.log(`[ShopRenter] HMAC validation - client secret length: ${clientSecret.length}`)
|
|
console.log(`[ShopRenter] HMAC validation - client secret length: ${clientSecret.length}`)
|
|
@@ -144,15 +144,19 @@ serve(wrapHandler('oauth-shoprenter-callback', async (req) => {
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Get environment variables
|
|
|
|
|
- const shoprenterClientId = Deno.env.get('SHOPRENTER_APP_CLIENT_ID')
|
|
|
|
|
- const shoprenterClientSecret = Deno.env.get('SHOPRENTER_APP_CLIENT_SECRET')
|
|
|
|
|
|
|
+ // Get environment variables (support both naming conventions with fallback)
|
|
|
|
|
+ const shoprenterClientId = Deno.env.get('SHOPRENTER_APP_CLIENT_ID') || Deno.env.get('SHOPRENTER_CLIENT_ID')
|
|
|
|
|
+ const shoprenterClientSecret = Deno.env.get('SHOPRENTER_APP_CLIENT_SECRET') || Deno.env.get('SHOPRENTER_CLIENT_SECRET')
|
|
|
const frontendUrl = Deno.env.get('FRONTEND_URL') || 'https://shopcall.ai'
|
|
const frontendUrl = Deno.env.get('FRONTEND_URL') || 'https://shopcall.ai'
|
|
|
const supabaseUrl = Deno.env.get('SUPABASE_URL')!
|
|
const supabaseUrl = Deno.env.get('SUPABASE_URL')!
|
|
|
const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
|
|
const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
|
|
|
|
|
|
|
|
|
|
+ // Log which environment variables are being used
|
|
|
|
|
+ console.log(`[ShopRenter] Using client ID from: ${Deno.env.get('SHOPRENTER_APP_CLIENT_ID') ? 'SHOPRENTER_APP_CLIENT_ID' : 'SHOPRENTER_CLIENT_ID'}`)
|
|
|
|
|
+ console.log(`[ShopRenter] Using client secret from: ${Deno.env.get('SHOPRENTER_APP_CLIENT_SECRET') ? 'SHOPRENTER_APP_CLIENT_SECRET' : 'SHOPRENTER_CLIENT_SECRET'}`)
|
|
|
|
|
+
|
|
|
if (!shoprenterClientId || !shoprenterClientSecret) {
|
|
if (!shoprenterClientId || !shoprenterClientSecret) {
|
|
|
- console.error('SHOPRENTER_APP_CLIENT_ID or SHOPRENTER_APP_CLIENT_SECRET not configured')
|
|
|
|
|
|
|
+ console.error('ShopRenter client credentials not configured. Set either SHOPRENTER_APP_CLIENT_ID/SECRET or SHOPRENTER_CLIENT_ID/SECRET')
|
|
|
return new Response(
|
|
return new Response(
|
|
|
JSON.stringify({ error: 'ShopRenter integration not configured' }),
|
|
JSON.stringify({ error: 'ShopRenter integration not configured' }),
|
|
|
{ status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|
|
{ status: 500, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|