mirror of
https://github.com/christianvidalwolf-prog/Craze-Data-check.git
synced 2026-08-03 12:35:25 +02:00
Security: Enable RLS support by passing user JWT in Supabase requests
Replaced hardcoded anon key as Bearer token with authHeaders() helper that uses the authenticated user's access_token when available, enabling Row Level Security policies to identify the calling user correctly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
7a32605189
commit
dec24f52f4
+37
-43
@@ -1,5 +1,12 @@
|
|||||||
const SUPABASE_URL = 'https://hwithddwaapyhnfwcesj.supabase.co';
|
const SUPABASE_URL = 'https://hwithddwaapyhnfwcesj.supabase.co';
|
||||||
const SUPABASE_KEY = 'sb_publishable_fGXkh0bSrAOqSk2jWKAzSg_NJD9YPCv';
|
const SUPABASE_ANON_KEY = 'sb_publishable_fGXkh0bSrAOqSk2jWKAzSg_NJD9YPCv';
|
||||||
|
|
||||||
|
function authHeaders(token?: string): Record<string, string> {
|
||||||
|
return {
|
||||||
|
'apikey': SUPABASE_ANON_KEY,
|
||||||
|
'Authorization': `Bearer ${token ?? SUPABASE_ANON_KEY}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export interface ExcelRow extends Array<any> {}
|
export interface ExcelRow extends Array<any> {}
|
||||||
|
|
||||||
@@ -14,17 +21,14 @@ export async function getAllSyncedRows(token?: string): Promise<Record<string, S
|
|||||||
`${SUPABASE_URL}/rest/v1/products?select=product_id,data,status&order=updated_at.desc`,
|
`${SUPABASE_URL}/rest/v1/products?select=product_id,data,status&order=updated_at.desc`,
|
||||||
{
|
{
|
||||||
cache: 'no-store',
|
cache: 'no-store',
|
||||||
headers: {
|
headers: authHeaders(token),
|
||||||
'apikey': SUPABASE_KEY,
|
|
||||||
'Authorization': `Bearer ${SUPABASE_KEY}`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const errText = await response.text();
|
const errText = await response.text();
|
||||||
console.error('getAllSyncedRows failed:', response.status, errText);
|
console.error('getAllSyncedRows failed:', response.status, errText);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
const rows = await response.json();
|
const rows = await response.json();
|
||||||
const result: Record<string, SyncedRow> = {};
|
const result: Record<string, SyncedRow> = {};
|
||||||
@@ -46,9 +50,8 @@ export async function saveRowToSupabase(articleNo: string, rowData: ExcelRow, to
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'apikey': SUPABASE_KEY,
|
...authHeaders(token),
|
||||||
'Authorization': `Bearer ${SUPABASE_KEY}`,
|
'Prefer': 'resolution=merge-duplicates',
|
||||||
'Prefer': 'resolution=merge-duplicates'
|
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
product_id: articleNo,
|
product_id: articleNo,
|
||||||
@@ -61,12 +64,12 @@ export async function saveRowToSupabase(articleNo: string, rowData: ExcelRow, to
|
|||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const err = await response.json().catch(() => ({}));
|
const err = await response.json().catch(() => ({}));
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: `${response.status} ${response.statusText}: ${err.message || err.error_description || 'Unknown error'}`
|
error: `${response.status} ${response.statusText}: ${err.message || err.error_description || 'Unknown error'}`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return { success: true };
|
return { success: true };
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error('Error saving to Supabase:', error);
|
console.error('Error saving to Supabase:', error);
|
||||||
@@ -99,9 +102,8 @@ export async function saveHistoryEntry(
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'apikey': SUPABASE_KEY,
|
...authHeaders(token),
|
||||||
'Authorization': `Bearer ${SUPABASE_KEY}`,
|
'Prefer': 'return=minimal',
|
||||||
'Prefer': 'return=minimal'
|
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
product_id: productId,
|
product_id: productId,
|
||||||
@@ -116,12 +118,12 @@ export async function saveHistoryEntry(
|
|||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const err = await response.json().catch(() => ({}));
|
const err = await response.json().catch(() => ({}));
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: `History ${response.status}: ${err.message || 'Unknown error'}`
|
error: `History ${response.status}: ${err.message || 'Unknown error'}`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return { success: true };
|
return { success: true };
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error('Error saving history to Supabase:', error);
|
console.error('Error saving history to Supabase:', error);
|
||||||
@@ -135,18 +137,14 @@ export async function getHistory(token?: string): Promise<HistoryEntry[]> {
|
|||||||
`${SUPABASE_URL}/rest/v1/products_history?select=*&order=changed_at.desc&limit=100`,
|
`${SUPABASE_URL}/rest/v1/products_history?select=*&order=changed_at.desc&limit=100`,
|
||||||
{
|
{
|
||||||
cache: 'no-store',
|
cache: 'no-store',
|
||||||
headers: {
|
headers: authHeaders(token),
|
||||||
'apikey': SUPABASE_KEY,
|
|
||||||
// Try using only the ANON key just in case RLS or token expiry is failing silently
|
|
||||||
'Authorization': `Bearer ${SUPABASE_KEY}`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const err = await response.text();
|
const err = await response.text();
|
||||||
return [{
|
return [{
|
||||||
id: 'error-' + Date.now(),
|
id: -1,
|
||||||
product_id: 'ERROR',
|
product_id: 'ERROR',
|
||||||
article_name: `Failed: ${response.status} ${err}`,
|
article_name: `Failed: ${response.status} ${err}`,
|
||||||
old_data: [],
|
old_data: [],
|
||||||
@@ -159,13 +157,13 @@ export async function getHistory(token?: string): Promise<HistoryEntry[]> {
|
|||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error('Error fetching history:', error);
|
console.error('Error fetching history:', error);
|
||||||
return [{
|
return [{
|
||||||
id: 'error-' + Date.now(),
|
id: -2,
|
||||||
product_id: 'EXCEPTION',
|
product_id: 'EXCEPTION',
|
||||||
article_name: `Message: ${error.message}`,
|
article_name: `Message: ${error.message}`,
|
||||||
old_data: [],
|
old_data: [],
|
||||||
new_data: [],
|
new_data: [],
|
||||||
changed_at: new Date().toISOString(),
|
changed_at: new Date().toISOString(),
|
||||||
changed_by: 'system'
|
changed_by: 'system'
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -176,10 +174,7 @@ export async function deleteHistoryEntry(id: string, token?: string): Promise<bo
|
|||||||
`${SUPABASE_URL}/rest/v1/products_history?id=eq.${encodeURIComponent(id)}`,
|
`${SUPABASE_URL}/rest/v1/products_history?id=eq.${encodeURIComponent(id)}`,
|
||||||
{
|
{
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
headers: {
|
headers: authHeaders(token),
|
||||||
'apikey': SUPABASE_KEY,
|
|
||||||
'Authorization': `Bearer ${SUPABASE_KEY}`
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -198,9 +193,8 @@ export async function resetAllPendingRows(token?: string): Promise<boolean> {
|
|||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'apikey': SUPABASE_KEY,
|
...authHeaders(token),
|
||||||
'Authorization': `Bearer ${SUPABASE_KEY}`,
|
'Prefer': 'return=minimal',
|
||||||
'Prefer': 'return=minimal'
|
|
||||||
},
|
},
|
||||||
body: JSON.stringify({ status: 'synced' })
|
body: JSON.stringify({ status: 'synced' })
|
||||||
}
|
}
|
||||||
@@ -211,4 +205,4 @@ export async function resetAllPendingRows(token?: string): Promise<boolean> {
|
|||||||
console.error('Error resetting pending rows in Supabase:', error);
|
console.error('Error resetting pending rows in Supabase:', error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user