-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Staging to prod #270
Staging to prod #270
Changes from 9 commits
ffc81a8
30d9050
6de16b9
53a6dcc
6209690
720a7bc
70155fd
d8ab5c5
b5e5281
c34008c
4a6dc2e
ceb5942
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,3 +27,4 @@ jobs: | |
- run: | | ||
supabase link --project-ref $PRODUCTION_PROJECT_ID | ||
supabase db push | ||
supabase functions deploy |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,3 +27,4 @@ jobs: | |
- run: | | ||
supabase link --project-ref $STAGING_PROJECT_ID | ||
supabase db push | ||
supabase functions deploy |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
URL=http://host.docker.internal:54321 | ||
ANON_KEY=ey.. | ||
SERVICE_ROLE_KEY=ey... | ||
ALLOWED_ORIGIN=http://localhost:5173 | ||
SMTP_HOST=... | ||
SMTP_USER=... | ||
SMTP_PASSWORD=... | ||
SMTP_FROM=... | ||
SMTP_PORT=... |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
ALLOWED_ORIGIN=http://localhost:5173 | ||
SMTP_HOST=host.docker.internal | ||
SMTP_USER="" | ||
SMTP_PASSWORD="" | ||
[email protected] | ||
SMTP_PORT=1025 | ||
SMTP_SECURE=false |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
import { SupabaseClient } from "npm:@supabase/supabase-js"; | ||
import { sub } from "npm:date-fns"; | ||
|
||
export interface CheckResult { | ||
isAllowed: boolean; | ||
reason: string | undefined; | ||
lookupData: ContactRequestLookupData | undefined; | ||
} | ||
|
||
export interface ContactRequestLookupData { | ||
senderUsername: string; | ||
senderEmail: string; | ||
senderUserId: string; | ||
recipientUserId: string; | ||
} | ||
|
||
export async function checkIfContactRequestIsAllowed( | ||
recipientContactName: string, | ||
token: string, | ||
supabaseClient: SupabaseClient, | ||
supabaseServiceRoleClient: SupabaseClient | ||
): Promise<CheckResult> { | ||
// Get the user (= sender) data from the token | ||
const { data: senderData, error: senderDataError } = | ||
await supabaseClient.auth.getUser(token); | ||
|
||
console.log(senderData); | ||
|
||
if (senderDataError) { | ||
console.log(senderDataError); | ||
return { isAllowed: false, reason: "unauthorized", lookupData: undefined }; | ||
} | ||
|
||
// Lookup the sender username | ||
const { data: senderLookupData, error: senderLookupDataError } = | ||
await supabaseServiceRoleClient | ||
.from("profiles") | ||
.select("*") | ||
.eq("id", senderData.user.id) | ||
.single(); | ||
|
||
console.log(senderLookupData); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we log this? |
||
|
||
if (senderLookupDataError) { | ||
console.log(senderLookupDataError); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. console.error |
||
return { isAllowed: false, reason: "not_found", lookupData: undefined }; | ||
} | ||
|
||
// Lookup the recipient user id | ||
const { data: recipientData, error: recipientDataError } = | ||
await supabaseServiceRoleClient | ||
.from("profiles") | ||
.select("*") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we be more sparse which fields we select? |
||
.eq("username", recipientContactName) | ||
.single(); | ||
|
||
if (recipientDataError) { | ||
console.log(recipientDataError); | ||
return { isAllowed: false, reason: "not_found", lookupData: undefined }; | ||
} | ||
|
||
// Check if the user has already tried to contact the recipient | ||
const { data: requestsToRecipient, error: requestsToRecipientError } = | ||
await supabaseClient | ||
.from("contact_requests") | ||
.select("*") | ||
.eq("user_id", senderData.user.id) | ||
.eq("contact_id", recipientData.id) | ||
.not("contact_mail_id", "is", null); // only count sent emails | ||
|
||
if (requestsToRecipientError) { | ||
console.log(requestsToRecipientError); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. console.error? |
||
return { | ||
isAllowed: false, | ||
reason: "internal_server_error", | ||
lookupData: undefined, | ||
}; | ||
} | ||
|
||
if (requestsToRecipient.length > 0) { | ||
return { | ||
isAllowed: false, | ||
reason: "already_contacted_the_recipient_before", | ||
lookupData: undefined, | ||
}; | ||
} | ||
|
||
// Check if the user has sent 3 contact requests in the last 24 hours | ||
const { data: requestsOfLast24h, error: requestsOfLast24hError } = | ||
await supabaseClient | ||
.from("contact_requests") | ||
.select("*") | ||
.eq("user_id", senderData.user.id) | ||
.not("contact_mail_id", "is", null) // only count sent emails | ||
.gt("created_at", sub(new Date(), { days: 1 }).toISOString()); | ||
|
||
if (requestsOfLast24hError) { | ||
console.log(requestsOfLast24hError); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. console.error |
||
return { | ||
isAllowed: false, | ||
reason: "internal_server_error", | ||
lookupData: undefined, | ||
}; | ||
} | ||
|
||
if (requestsOfLast24h.length >= 3) { | ||
return { | ||
isAllowed: false, | ||
reason: "already_sent_more_than_3_contact_requests", | ||
lookupData: undefined, | ||
}; | ||
} | ||
|
||
return { | ||
isAllowed: true, | ||
reason: undefined, | ||
lookupData: { | ||
senderUsername: senderLookupData.username, | ||
senderEmail: senderData.user.email, | ||
senderUserId: senderData.user.id, | ||
recipientUserId: recipientData.id, | ||
}, | ||
}; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
const ALLOWED_ORIGIN = Deno.env.get("ALLOWED_ORIGIN"); | ||
|
||
export const corsHeaders = { | ||
"Access-Control-Allow-Origin": ALLOWED_ORIGIN, | ||
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS", | ||
"Access-Control-Allow-Headers": | ||
"Content-Type,Authorization,x-client-info,apikey", | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import { createClient } from "https://esm.sh/@supabase/supabase-js@2"; | ||
import { checkIfContactRequestIsAllowed } from "../_shared/checks.ts"; | ||
import { corsHeaders } from "../_shared/cors.ts"; | ||
|
||
const SUPABASE_URL = Deno.env.get("SUPABASE_URL"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No check if these vars don't exisit There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. implemented |
||
const SUPABASE_ANON_KEY = Deno.env.get("SUPABASE_ANON_KEY"); | ||
const SUPABASE_SERVICE_ROLE_KEY = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY"); | ||
|
||
const handler = async (_request: Request): Promise<Response> => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No error handling at all? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why _request? |
||
if (_request.method === "OPTIONS") { | ||
return new Response(null, { headers: corsHeaders, status: 204 }); | ||
} | ||
|
||
const { recipientContactName } = await _request.json(); | ||
|
||
const authHeader = _request.headers.get("Authorization")!; | ||
|
||
const supabaseClient = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, { | ||
global: { headers: { Authorization: authHeader } }, | ||
}); | ||
|
||
const supabaseServiceRoleClient = createClient( | ||
SUPABASE_URL, | ||
SUPABASE_SERVICE_ROLE_KEY | ||
); | ||
|
||
const token = authHeader.replace("Bearer ", ""); | ||
|
||
const { isAllowed, reason } = await checkIfContactRequestIsAllowed( | ||
recipientContactName, | ||
token, | ||
supabaseClient, | ||
supabaseServiceRoleClient | ||
); | ||
|
||
if (!isAllowed) { | ||
return new Response( | ||
JSON.stringify({ | ||
isContactRequestAllowed: false, | ||
reason, | ||
}), | ||
{ | ||
status: 200, // We have to use 200 here to allow the client to read the response body | ||
headers: { | ||
...corsHeaders, | ||
"Content-Type": "application/json", | ||
}, | ||
} | ||
); | ||
} | ||
|
||
return new Response( | ||
JSON.stringify({ | ||
isContactRequestAllowed: true, | ||
reason: undefined, | ||
}), | ||
{ | ||
status: 200, | ||
headers: { | ||
...corsHeaders, | ||
"Content-Type": "application/json", | ||
}, | ||
} | ||
); | ||
}; | ||
|
||
Deno.serve(handler); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we lo this?