Skip to content

Commit bc826cf

Browse files
authored
Supabase constraints (#343)
* add constraints * fix tests * fix * fix * fix * fix rls * fix RLS * misc fixes * remove useless test
1 parent 563d766 commit bc826cf

File tree

13 files changed

+206
-74
lines changed

13 files changed

+206
-74
lines changed

packages/editor/src/app/main/components/Navigation.tsx

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
/* eslint-disable jsx-a11y/anchor-is-valid */
22

3-
import {
4-
AtlassianNavigation,
5-
PrimaryButton,
6-
} from "@atlaskit/atlassian-navigation";
3+
import { AtlassianNavigation } from "@atlaskit/atlassian-navigation";
4+
import Button from "@atlaskit/button";
75
import { observer } from "mobx-react-lite";
86
import { useCallback } from "react";
97
import { VscSignIn } from "react-icons/vsc";
108
import { Link, useLocation, useNavigate } from "react-router-dom";
119
import { SessionStore } from "../../../store/local/SessionStore";
12-
import { toDocs, toLoginScreen } from "../../routes/routes";
10+
import { toDocs, toLoginScreen, toRegisterScreen } from "../../routes/routes";
1311
import { Logo } from "./Logo";
1412
import styles from "./Navigation.module.css";
1513
import { ProfilePopup } from "./ProfilePopup";
@@ -29,15 +27,10 @@ export const Navigation = observer((props: { sessionStore: SessionStore }) => {
2927
const navigate = useNavigate();
3028
const location = useLocation();
3129

30+
const isLoggedIn = sessionStore.isLoggedIn;
3231
const renderProfile = useCallback(() => {
33-
return (
34-
<>
35-
{sessionStore.isLoggedIn && (
36-
<ProfilePopup sessionStore={sessionStore} />
37-
)}
38-
</>
39-
);
40-
}, [sessionStore]);
32+
return <>{isLoggedIn && <ProfilePopup sessionStore={sessionStore} />}</>;
33+
}, [isLoggedIn, sessionStore]);
4134

4235
return (
4336
<AtlassianNavigation
@@ -68,19 +61,35 @@ export const Navigation = observer((props: { sessionStore: SessionStore }) => {
6861
renderSignIn={observer(() => (
6962
<>
7063
{!sessionStore.isLoggedIn && (
71-
<PrimaryButton
72-
onClick={() =>
73-
navigate(toLoginScreen(), { state: { from: location } })
74-
}
75-
iconBefore={
76-
<VscSignIn style={{ width: "16px", height: "16px" }} />
77-
}>
78-
{" "}
79-
Sign in{" "}
80-
{/* {typeof sessionStore.user === "string"
64+
<>
65+
<Button
66+
style={{ borderRadius: "8px" }}
67+
appearance="subtle"
68+
onClick={() =>
69+
navigate(toLoginScreen(), { state: { from: location } })
70+
}>
71+
{" "}
72+
Log in
73+
{/* {typeof sessionStore.user === "string"
8174
? sessionStore.user
8275
: sessionStore.user.type} */}
83-
</PrimaryButton>
76+
</Button>
77+
<Button
78+
style={{ borderRadius: "8px" }}
79+
appearance="primary"
80+
onClick={() =>
81+
navigate(toRegisterScreen(), { state: { from: location } })
82+
}
83+
iconBefore={
84+
<VscSignIn style={{ width: "16px", height: "16px" }} />
85+
}>
86+
{" "}
87+
Sign up for free{" "}
88+
{/* {typeof sessionStore.user === "string"
89+
? sessionStore.user
90+
: sessionStore.user.type} */}
91+
</Button>
92+
</>
8493
)}
8594
</>
8695
))}

packages/editor/src/app/main/components/documentMenu/ForkAlert.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Link, useLocation, useNavigate } from "react-router-dom";
44
import { DocumentResource } from "../../../../store/DocumentResource";
55

66
import { SessionStore } from "../../../../store/local/SessionStore";
7-
import { toLoginScreen } from "../../../routes/routes";
7+
import { toRegisterScreen } from "../../../routes/routes";
88
import styles from "./ForkAlert.module.css";
99

1010
export const ForkAlert = observer(
@@ -39,8 +39,8 @@ export const ForkAlert = observer(
3939
<span>save a copy</span>
4040
</a>
4141
) : (
42-
<Link to={toLoginScreen()} state={{ from: location }}>
43-
<span>sign in to save a copy</span>
42+
<Link to={toRegisterScreen()} state={{ from: location }}>
43+
<span>sign up to save a copy</span>
4444
</Link>
4545
);
4646

packages/editor/src/app/supabase-auth/SupabaseSessionStore.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,10 @@ export class SupabaseSessionStore extends SessionStore {
153153
}
154154
}
155155

156-
// TODO: first check if username is available?
157-
156+
// create workspace
158157
const workspaceId = this.getIdentifierForNewDocument();
159158
{
160-
// TODO: use syncmanager
159+
// TODO: use syncmanager?
161160
const ydoc = new Y.Doc();
162161
const ret = new BaseResource(ydoc, workspaceId);
163162
ret.create("!project");
@@ -167,10 +166,10 @@ export class SupabaseSessionStore extends SessionStore {
167166
remote.dispose();
168167
}
169168

170-
// TODO: manage aliases
169+
// create profile
171170
const profileId = this.getIdentifierForNewDocument();
172171
{
173-
// TODO: use syncmanager
172+
// TODO: use syncmanager?
174173
const ydoc = new Y.Doc();
175174
const ret = new BaseResource(ydoc, profileId);
176175
ret.create("!profile");
@@ -258,6 +257,7 @@ export class SupabaseSessionStore extends SessionStore {
258257
} else {
259258
runInAction(() => {
260259
setDefaultShorthandResolver(new DefaultShorthandResolver()); // hacky
260+
this.userId = undefined;
261261
this.user = {
262262
type: "guest-user",
263263
supabase: this.supabase,

packages/editor/src/store/DocConnection.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,14 @@ export class DocConnection extends lifecycle.Disposable {
6262
this.manager?.dispose();
6363
let newManager: SyncManager | undefined = undefined;
6464

65-
if (sessionStore.user && sessionStore.documentCoordinator) {
65+
if (this.sessionStore.user && this.sessionStore.documentCoordinator) {
66+
// This is hacky, we should clear cache and probably dispose all docconnections when the sessionstore changes
6667
newManager = SyncManager.load(identifier, this.sessionStore);
68+
const cacheKey = DocConnection.getCacheKey(
69+
this.sessionStore,
70+
identifier
71+
);
72+
cache.set(cacheKey, this);
6773
}
6874
runInAction(() => {
6975
this.manager = newManager;
@@ -292,6 +298,7 @@ export class DocConnection extends lifecycle.Disposable {
292298
const cacheKey = DocConnection.getCacheKey(sessionStore, identifier);
293299
let connection = cache.get(cacheKey);
294300
if (!connection) {
301+
// console.log("DocConnection load debug", cacheKey);
295302
const syncManager = SyncManager.load(identifier, sessionStore);
296303

297304
connection = new DocConnection(identifier, syncManager, sessionStore);

packages/editor/src/store/yjs-sync/DocumentCoordinator.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ export class DocumentCoordinator extends lifecycle.Disposable {
133133
throw new Error("not initialized");
134134
}
135135

136+
// console.log("Coordinator load debug", idStr, this.userId);
136137
if (this.loadedDocuments.has(idStr)) {
137138
// we expect loadDocument only to be called once per document
138139
throw new Error("loadDocument: document already loaded");

packages/editor/src/store/yjs-sync/IDBHelper.ts

Lines changed: 0 additions & 23 deletions
This file was deleted.

packages/editor/src/store/yjs-sync/remote/TypeCellRemote.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ export class TypeCellRemote extends Remote {
123123
id: uuid.generateUuid(),
124124
created_at: date,
125125
updated_at: date,
126-
data: "\\x" + hash.toHexString(data),
126+
data: "\\x" + hash.toHexString(data.buffer),
127127
nano_id: this.identifier.documentId,
128128
public_access_level: this.identifier.documentId.endsWith("/.inbox")
129129
? "write"

packages/editor/tests/end-to-end/login/login.spec.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
import { DEFAULT_PROVIDER } from "../setup/config";
22
import { expect, test } from "../setup/fixtures";
33

4-
test("Sign in button exists", async ({ page }) => {
5-
await page.goto("/");
6-
const button = page.locator("header button");
7-
await expect(button).toHaveText("Sign in");
8-
});
9-
104
if (DEFAULT_PROVIDER === "supabase") {
115
test("Sign in by email (supabase)", async ({
126
page,
@@ -20,7 +14,7 @@ if (DEFAULT_PROVIDER === "supabase") {
2014
aliceContext = aliceContext;
2115

2216
await page.goto("/");
23-
const button = page.locator("button", { hasText: "Sign in" });
17+
const button = page.locator("button", { hasText: "Log in" });
2418

2519
await button.click();
2620

@@ -61,7 +55,7 @@ if (DEFAULT_PROVIDER === "supabase") {
6155
aliceContext = aliceContext;
6256

6357
await page.goto("/");
64-
const button = page.locator("button", { hasText: "Sign in" });
58+
const button = page.locator("button", { hasText: "Log in" });
6559

6660
await button.click();
6761

packages/editor/tests/end-to-end/setup/userFixtures.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ export const testWithUsers = base.extend<
9191
aliceUser: [
9292
async ({}, use, workerInfo) => {
9393
const aliceUser: TestUser = {
94-
username: "alice-" + SESSION_ID + "-" + workerInfo.workerIndex,
94+
username: "alice_" + SESSION_ID + "_" + workerInfo.workerIndex,
9595
password: "myPw123ABC@#$",
9696
};
9797

@@ -102,7 +102,7 @@ export const testWithUsers = base.extend<
102102
bobUser: [
103103
async ({}, use, workerInfo) => {
104104
const bobUser: TestUser = {
105-
username: "bob-" + SESSION_ID + "-" + workerInfo.workerIndex,
105+
username: "bob_" + SESSION_ID + "_" + workerInfo.workerIndex,
106106
password: "myB0bPw123ABC@#$",
107107
};
108108

packages/server/supabase/migrations/20230324133839_initial.sql

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ BEGIN
8383
SELECT MIN(check_document_access(uid, parent_id)) FROM document_relations r WHERE child_id = doc_id
8484
);
8585
END;
86-
$$ LANGUAGE plpgsql;
86+
$$ LANGUAGE plpgsql SECURITY DEFINER;
8787

8888
create policy "Enable insert for authenticated users only"
8989
on "public"."documents"
@@ -152,8 +152,4 @@ for select
152152
to public
153153
using (true);
154154

155-
156-
157-
158-
-- TODO: prevent select * using https://stackoverflow.com/questions/74283527/postgresql-remove-ability-to-query-every-row-in-a-table
159-
-- TODO: validate formats of nanoids and usernames
155+
-- TODO: prevent select * using https://stackoverflow.com/questions/74283527/postgresql-remove-ability-to-query-every-row-in-a-table

0 commit comments

Comments
 (0)