Skip to content

Commit b5e3b80

Browse files
committed
Performance improvements: Add missing indices for better query performance.
1 parent 056002f commit b5e3b80

File tree

2 files changed

+188
-0
lines changed

2 files changed

+188
-0
lines changed

CHANGELOG

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ Dates should be in`YYYY-MM-DD` format and versions are in [semantic versioning](
55

66
## v0.7.15 2025-06-08
77

8+
### Fixed
9+
10+
- Set search paths to empty string and fully qualified table references to close security hole
11+
- Created missing indices on foreign keys.
12+
813
### Maintenance
914

1015
- Updated Supabase, Svelte, SvelteKit, eslint, vitest minor versions.
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
-- Create missing indexes to improve query performance.
2+
create index assignments_profile_idx on assignments(profileid);
3+
create index assignments_role_idx on assignments(roleid);
4+
create index comments_org_idx on comments(orgid);
5+
create index comments_person_idx on comments(who);
6+
create index hows_process_idx on hows(processid);
7+
create index processes_accountable_idx on processes(accountable);
8+
create index processes_how_idx on processes(howid);
9+
create index profiles_supervisor_idx on profiles(supervisor);
10+
create index roles_team_index on roles(team);
11+
create index suggestions_lead_index on suggestions(lead);
12+
create index suggestions_who_idx on suggestions(who);
13+
14+
-- More efficient calls to auth.uid().
15+
alter policy "People are viewable by themselves."
16+
on people
17+
using (id = (select auth.uid()));
18+
19+
alter policy "People can update themselves."
20+
on people
21+
using (id = (select auth.uid()));
22+
23+
alter policy "People can delete themselves."
24+
on people
25+
using (id = (select auth.uid()));
26+
27+
alter policy "Admins can update a user's profile, as can a user of their own profile."
28+
on profiles
29+
using ((select auth.uid()) = personid or isAdmin(orgid));
30+
31+
alter policy "Admins can delete a profile, as can users of their own profile."
32+
on profiles
33+
using ((select auth.uid()) = personid or isAdmin(orgid));
34+
35+
alter policy "allow comments by members"
36+
on suggestions
37+
using (isAdmin(orgid) or who = (select auth.uid()));
38+
39+
alter policy "Any admin or the person who reported it can delete a suggestion"
40+
on suggestions
41+
using (isAdmin(orgid) or who = (select auth.uid()));
42+
43+
alter policy "Any admin or the person who reported it can update a comment."
44+
on comments
45+
using (isAdmin(orgid) or who = (select auth.uid()));
46+
47+
alter policy "Any admin or the person who reported it can delete a comment."
48+
on comments
49+
using (isAdmin(orgid) or who = (select auth.uid()));
50+
51+
-- Disallow mutable search paths
52+
create or replace function isAdmin("_orgid" uuid)
53+
returns boolean
54+
language sql
55+
security definer set search_path = ''
56+
as $$
57+
select exists (
58+
select personid from public.profiles where
59+
public.profiles.orgid = _orgid and
60+
public.profiles.personid = (select auth.uid()) and
61+
public.profiles.admin = true
62+
);
63+
$$;
64+
65+
create or replace function getProfileID("_orgid" uuid)
66+
returns uuid
67+
language sql
68+
security definer set search_path = ''
69+
as $$
70+
select id from public.profiles where public.profiles.orgid = _orgid and personid = (select auth.uid())
71+
$$;
72+
73+
create or replace function isEditableHow("_orgid" uuid, "_processid" uuid)
74+
returns boolean
75+
language sql
76+
security definer set search_path = ''
77+
as $$
78+
select (
79+
public.isAdmin(_orgid)
80+
-- If no one is accountable, anyone in the org can update it.
81+
or ((select accountable from public.processes where id = _processid) = null and public.isMember(_orgid))
82+
-- If the person is accountable, they can update it.
83+
or exists (select roleid from public.assignments where (select accountable from public.processes where id = _processid) = roleid and public.assignments.profileid = public.getProfileID(_orgid))
84+
-- If there is a how for this process that contains an assignment with this person's ID, they can update it.
85+
or exists (
86+
select id
87+
from public.hows where
88+
hows.processid = _processid AND
89+
(select roleid from public.assignments where public.assignments.profileid = public.getProfileID(_orgid)) = ANY(public.hows.responsible)
90+
)
91+
);
92+
$$;
93+
94+
create or replace function public.create_org(adminname text, orgname text, invite uuid, uid uuid, email text)
95+
returns uuid
96+
language plpgsql
97+
security definer set search_path to ''
98+
as $function$
99+
declare
100+
orgid uuid;
101+
begin
102+
raise log 'Starting org create';
103+
-- Invite already used? Return null;
104+
if not exists (select * from public.invites where id = invite and used = false) then
105+
raise log 'No valid invite';
106+
return null;
107+
end if;
108+
-- Use the invite
109+
raise log 'Updating invite';
110+
update public.invites set used = true, who = uid where id = invite;
111+
-- Create the organization
112+
raise log 'Creating the org';
113+
insert into public.orgs (name) values (orgName) returning id into orgid;
114+
-- Add the user into the profiles for the organization
115+
raise log 'Adding the profile';
116+
insert into public.profiles (orgid, personid, name, email, admin) values (orgid, uid, adminName, email, true);
117+
-- Return the org id
118+
return orgid;
119+
end;
120+
$function$
121+
;
122+
123+
create or replace function path_available(_path text)
124+
returns boolean
125+
language plpgsql
126+
security definer set search_path = ''
127+
as $$
128+
begin
129+
if not exists (select from public.orgs where _path = any(paths))
130+
then
131+
return true;
132+
else
133+
return false;
134+
end if;
135+
end;
136+
$$;
137+
138+
create or replace function public.handle_new_profile()
139+
returns trigger
140+
language plpgsql
141+
security definer set search_path = ''
142+
as $$
143+
begin
144+
update public.profiles set personid = people.id from public.people where public.people.email = new.email AND new.email = public.profiles.email;
145+
return new;
146+
end;
147+
$$;
148+
149+
create or replace function public.handle_new_person()
150+
returns trigger
151+
language plpgsql
152+
security definer set search_path = ''
153+
as $$
154+
begin
155+
-- Insert the new user into the people table.
156+
insert into public.people (id, email)
157+
values (new.id, new.email);
158+
-- If any profile has this email address, update the profile's personid.
159+
update public.profiles set personid = new.id where email = new.email;
160+
-- Return the new row.
161+
return new;
162+
end;
163+
$$;
164+
165+
create or replace function getVisibility("_orgid" uuid)
166+
returns visibility
167+
language sql
168+
security definer set search_path = ''
169+
as $$
170+
select visibility from public.orgs where id = _orgid;
171+
$$;
172+
173+
create or replace function isMember("_orgid" uuid)
174+
returns boolean
175+
language sql
176+
security definer set search_path = ''
177+
as $$
178+
select exists (
179+
select personid from public.profiles where
180+
public.profiles.orgid = _orgid and
181+
public.profiles.personid = auth.uid()
182+
);
183+
$$;

0 commit comments

Comments
 (0)