|
|
@@ -8,36 +8,32 @@ const corsHeaders = {
|
|
|
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
|
|
|
}
|
|
|
|
|
|
-// Validate HMAC signature from ShopRenter using raw query string
|
|
|
-function validateHMACFromRawQuery(rawQueryString: string, clientSecret: string): boolean {
|
|
|
+// Validate HMAC signature from ShopRenter
|
|
|
+// Per ShopRenter documentation, HMAC is calculated from decoded parameter values
|
|
|
+function validateHMAC(params: URLSearchParams, clientSecret: string): boolean {
|
|
|
if (!clientSecret) {
|
|
|
console.error('[ShopRenter] Client secret is empty or undefined')
|
|
|
return false
|
|
|
}
|
|
|
|
|
|
- // Parse query string into key-value pairs preserving URL encoding
|
|
|
- const params = new Map<string, string>()
|
|
|
- let hmacValue = ''
|
|
|
-
|
|
|
- rawQueryString.split('&').forEach(pair => {
|
|
|
- const [key, ...valueParts] = pair.split('=')
|
|
|
- const value = valueParts.join('=') // Handle values that contain '='
|
|
|
- if (key === 'hmac') {
|
|
|
- hmacValue = value
|
|
|
- } else {
|
|
|
- params.set(key, value)
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
+ const hmacValue = params.get('hmac')
|
|
|
if (!hmacValue) {
|
|
|
console.error('[ShopRenter] HMAC missing from request')
|
|
|
return false
|
|
|
}
|
|
|
|
|
|
- // Build sorted query string without HMAC (using URL-encoded values)
|
|
|
- const sortedParams = Array.from(params.keys())
|
|
|
+ // Build data to validate: all params except hmac, sorted alphabetically
|
|
|
+ const dataToValidate: { [key: string]: string } = {}
|
|
|
+ for (const [key, value] of params.entries()) {
|
|
|
+ if (key !== 'hmac') {
|
|
|
+ dataToValidate[key] = value
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Sort parameters alphabetically by key and create query string
|
|
|
+ const sortedParams = Object.keys(dataToValidate)
|
|
|
.sort()
|
|
|
- .map(key => `${key}=${params.get(key)}`)
|
|
|
+ .map(key => `${key}=${dataToValidate[key]}`)
|
|
|
.join('&')
|
|
|
|
|
|
console.log(`[ShopRenter] HMAC validation - sorted params: ${sortedParams}`)
|
|
|
@@ -170,11 +166,8 @@ serve(wrapHandler('oauth-shoprenter-callback', async (req) => {
|
|
|
)
|
|
|
}
|
|
|
|
|
|
- // Validate HMAC using raw query string (preserves URL encoding)
|
|
|
- const rawQueryString = url.search.slice(1) // Remove leading '?'
|
|
|
- console.log(`[ShopRenter] Raw query string: ${rawQueryString}`)
|
|
|
-
|
|
|
- if (!validateHMACFromRawQuery(rawQueryString, shoprenterClientSecret)) {
|
|
|
+ // Validate HMAC using decoded parameter values (per ShopRenter docs)
|
|
|
+ if (!validateHMAC(url.searchParams, shoprenterClientSecret)) {
|
|
|
return new Response(
|
|
|
JSON.stringify({ error: 'HMAC validation failed' }),
|
|
|
{ status: 403, headers: { ...corsHeaders, 'Content-Type': 'application/json' } }
|