mirror of
https://github.com/jjbrunton/Sauci.git
synced 2026-10-31 18:19:43 +00:00
Add intensity-based preferences and harden E2EE payload verification
This commit is contained in:
1 parent
e23f4557bb
commit
0a919f06fc
20 files changed
+2033
-251
No files matched your search
@@ -67,14 +67,14 @@ Deno.serve(async (req) => {
|
||||
return json({ error: "Missing encryption metadata" }, 400);
|
||||
}
|
||||
|
||||
const adminPrivateKeyJwkStr = Deno.env.get("ADMIN_PRIVATE_KEY_JWK");
|
||||
if (!adminPrivateKeyJwkStr) {
|
||||
const adminPrivateKeyJwk = getAdminPrivateKey(keysMetadata.admin_key_id);
|
||||
if (!adminPrivateKeyJwk) {
|
||||
return json({ error: "Admin decryption key not configured" }, 500);
|
||||
}
|
||||
|
||||
const rawAesKey = await unwrapWithAdminKey(
|
||||
keysMetadata.admin_wrapped_key,
|
||||
JSON.parse(adminPrivateKeyJwkStr)
|
||||
adminPrivateKeyJwk
|
||||
);
|
||||
|
||||
const aesKey = await crypto.subtle.importKey(
|
||||
@@ -166,3 +166,28 @@ async function assertSuperAdmin(
|
||||
throw new Error("Access denied");
|
||||
}
|
||||
}
|
||||
|
||||
function getAdminPrivateKey(keyId?: string | null): JsonWebKey | null {
|
||||
const keysJson = Deno.env.get("ADMIN_KEYS_JSON");
|
||||
if (keysJson && keyId) {
|
||||
try {
|
||||
const keys = JSON.parse(keysJson);
|
||||
if (keys[keyId]) {
|
||||
return keys[keyId];
|
||||
}
|
||||
} catch {
|
||||
console.error("Failed to parse ADMIN_KEYS_JSON");
|
||||
}
|
||||
}
|
||||
|
||||
const singleKeyJson = Deno.env.get("ADMIN_PRIVATE_KEY_JWK");
|
||||
if (singleKeyJson) {
|
||||
try {
|
||||
return JSON.parse(singleKeyJson);
|
||||
} catch {
|
||||
console.error("Failed to parse ADMIN_PRIVATE_KEY_JWK");
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -177,20 +177,42 @@ Deno.serve(async (req) => {
|
||||
);
|
||||
}
|
||||
|
||||
// Update user's profile with couple_id
|
||||
await supabase
|
||||
.from("profiles")
|
||||
.update({ couple_id: couple.id })
|
||||
.eq("id", user.id);
|
||||
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
couple_id: couple.id,
|
||||
invite_code: couple.invite_code
|
||||
}),
|
||||
{ headers: { ...corsHeaders, "Content-Type": "application/json" } }
|
||||
);
|
||||
// Update user's profile with couple_id
|
||||
await supabase
|
||||
.from("profiles")
|
||||
.update({ couple_id: couple.id })
|
||||
.eq("id", user.id);
|
||||
|
||||
const { data: safePacks, error: safePacksError } = await supabase
|
||||
.from("question_packs")
|
||||
.select("id")
|
||||
.lte("avg_intensity", 2)
|
||||
.eq("is_public", true);
|
||||
|
||||
if (safePacksError) {
|
||||
console.error("Failed to fetch safe packs:", safePacksError);
|
||||
} else if (safePacks?.length) {
|
||||
const { error: insertError } = await supabase
|
||||
.from("couple_packs")
|
||||
.insert(safePacks.map((pack: { id: string }) => ({
|
||||
couple_id: couple.id,
|
||||
pack_id: pack.id,
|
||||
enabled: true,
|
||||
})));
|
||||
|
||||
if (insertError) {
|
||||
console.error("Failed to enable safe packs:", insertError);
|
||||
}
|
||||
}
|
||||
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
couple_id: couple.id,
|
||||
invite_code: couple.invite_code
|
||||
}),
|
||||
{ headers: { ...corsHeaders, "Content-Type": "application/json" } }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
-- Add intensity levels for content balance
|
||||
|
||||
ALTER TABLE profiles
|
||||
ADD COLUMN IF NOT EXISTS max_intensity INTEGER DEFAULT 2
|
||||
CHECK (max_intensity >= 1 AND max_intensity <= 5);
|
||||
|
||||
UPDATE profiles
|
||||
SET max_intensity = CASE
|
||||
WHEN show_explicit_content IS TRUE THEN 5
|
||||
ELSE 2
|
||||
END
|
||||
WHERE max_intensity IS NULL;
|
||||
|
||||
ALTER TABLE question_packs
|
||||
ADD COLUMN IF NOT EXISTS min_intensity INTEGER,
|
||||
ADD COLUMN IF NOT EXISTS max_intensity INTEGER,
|
||||
ADD COLUMN IF NOT EXISTS avg_intensity NUMERIC(3,2);
|
||||
|
||||
CREATE OR REPLACE FUNCTION update_question_pack_intensity_stats(target_pack_id UUID)
|
||||
RETURNS void
|
||||
LANGUAGE plpgsql
|
||||
SET search_path = 'public'
|
||||
AS $$
|
||||
BEGIN
|
||||
UPDATE question_packs qp
|
||||
SET min_intensity = stats.min_intensity,
|
||||
max_intensity = stats.max_intensity,
|
||||
avg_intensity = stats.avg_intensity
|
||||
FROM (
|
||||
SELECT pack_id,
|
||||
MIN(intensity) AS min_intensity,
|
||||
MAX(intensity) AS max_intensity,
|
||||
ROUND(AVG(intensity)::numeric, 2) AS avg_intensity
|
||||
FROM questions
|
||||
WHERE pack_id = target_pack_id
|
||||
GROUP BY pack_id
|
||||
) stats
|
||||
WHERE qp.id = stats.pack_id;
|
||||
|
||||
IF NOT FOUND THEN
|
||||
UPDATE question_packs
|
||||
SET min_intensity = NULL,
|
||||
max_intensity = NULL,
|
||||
avg_intensity = NULL
|
||||
WHERE id = target_pack_id;
|
||||
END IF;
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION handle_question_intensity_change()
|
||||
RETURNS TRIGGER
|
||||
LANGUAGE plpgsql
|
||||
SET search_path = 'public'
|
||||
AS $$
|
||||
BEGIN
|
||||
IF TG_OP = 'DELETE' THEN
|
||||
PERFORM update_question_pack_intensity_stats(OLD.pack_id);
|
||||
RETURN OLD;
|
||||
END IF;
|
||||
|
||||
IF TG_OP = 'UPDATE' AND NEW.pack_id IS DISTINCT FROM OLD.pack_id THEN
|
||||
PERFORM update_question_pack_intensity_stats(OLD.pack_id);
|
||||
END IF;
|
||||
|
||||
PERFORM update_question_pack_intensity_stats(NEW.pack_id);
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
DROP TRIGGER IF EXISTS question_pack_intensity_stats ON questions;
|
||||
|
||||
CREATE TRIGGER question_pack_intensity_stats
|
||||
AFTER INSERT OR UPDATE OR DELETE ON questions
|
||||
FOR EACH ROW EXECUTE FUNCTION handle_question_intensity_change();
|
||||
|
||||
UPDATE question_packs qp
|
||||
SET min_intensity = stats.min_intensity,
|
||||
max_intensity = stats.max_intensity,
|
||||
avg_intensity = stats.avg_intensity
|
||||
FROM (
|
||||
SELECT pack_id,
|
||||
MIN(intensity) AS min_intensity,
|
||||
MAX(intensity) AS max_intensity,
|
||||
ROUND(AVG(intensity)::numeric, 2) AS avg_intensity
|
||||
FROM questions
|
||||
GROUP BY pack_id
|
||||
) stats
|
||||
WHERE qp.id = stats.pack_id;
|
||||
Reference in new issue
Block a user