Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 93c41f4c12 | |||
| a9d7d53d90 | |||
| aebbc46e79 | |||
| 3770a7f988 | |||
| 54d063ab2c | |||
| 70e4518d76 | |||
| ca54fa11f0 | |||
| 38732db8a4 | |||
| c7439be1a5 | |||
| 152e7b1426 | |||
| 49c89da2da |
@@ -148,6 +148,7 @@ class DocumentSerializer(BaseResourceSerializer):
|
||||
"title",
|
||||
"accesses",
|
||||
"abilities",
|
||||
"is_e2ee",
|
||||
"link_role",
|
||||
"link_reach",
|
||||
"created_at",
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.1 on 2024-09-12 13:53
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0005_remove_document_is_public_alter_document_link_reach_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='document',
|
||||
name='is_e2ee',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
||||
@@ -329,6 +329,7 @@ class Document(BaseModel):
|
||||
link_role = models.CharField(
|
||||
max_length=20, choices=LinkRoleChoices.choices, default=LinkRoleChoices.READER
|
||||
)
|
||||
is_e2ee = models.BooleanField(default=False)
|
||||
|
||||
_content = None
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ def test_api_documents_retrieve_anonymous_public():
|
||||
"versions_retrieve": False,
|
||||
},
|
||||
"accesses": [],
|
||||
"is_e2ee": False,
|
||||
"link_reach": "public",
|
||||
"link_role": document.link_role,
|
||||
"title": document.title,
|
||||
@@ -87,6 +88,7 @@ def test_api_documents_retrieve_authenticated_unrelated_public_or_authenticated(
|
||||
"versions_retrieve": False,
|
||||
},
|
||||
"accesses": [],
|
||||
"is_e2ee": False,
|
||||
"link_reach": reach,
|
||||
"link_role": document.link_role,
|
||||
"title": document.title,
|
||||
@@ -194,6 +196,7 @@ def test_api_documents_retrieve_authenticated_related_direct():
|
||||
"title": document.title,
|
||||
"content": document.content,
|
||||
"abilities": document.get_abilities(user),
|
||||
"is_e2ee": False,
|
||||
"link_reach": document.link_reach,
|
||||
"link_role": document.link_role,
|
||||
"created_at": document.created_at.isoformat().replace("+00:00", "Z"),
|
||||
@@ -332,6 +335,7 @@ def test_api_documents_retrieve_authenticated_related_team_members(
|
||||
"title": document.title,
|
||||
"content": document.content,
|
||||
"abilities": document.get_abilities(user),
|
||||
"is_e2ee": False,
|
||||
"link_reach": "restricted",
|
||||
"link_role": document.link_role,
|
||||
"created_at": document.created_at.isoformat().replace("+00:00", "Z"),
|
||||
@@ -452,6 +456,7 @@ def test_api_documents_retrieve_authenticated_related_team_administrators(
|
||||
"title": document.title,
|
||||
"content": document.content,
|
||||
"abilities": document.get_abilities(user),
|
||||
"is_e2ee": False,
|
||||
"link_reach": "restricted",
|
||||
"link_role": document.link_role,
|
||||
"created_at": document.created_at.isoformat().replace("+00:00", "Z"),
|
||||
@@ -576,6 +581,7 @@ def test_api_documents_retrieve_authenticated_related_team_owners(
|
||||
"title": document.title,
|
||||
"content": document.content,
|
||||
"abilities": document.get_abilities(user),
|
||||
"is_e2ee": False,
|
||||
"link_reach": "restricted",
|
||||
"link_role": document.link_role,
|
||||
"created_at": document.created_at.isoformat().replace("+00:00", "Z"),
|
||||
|
||||
+17
-10
@@ -1,4 +1,4 @@
|
||||
import { Block, BlockNoteEditor as BlockNoteEditorCore } from '@blocknote/core';
|
||||
import { Block, BlockNoteEditor as BlockNoteEditorCore, PartialBlock } from '@blocknote/core';
|
||||
import '@blocknote/core/fonts/inter.css';
|
||||
import { BlockNoteView } from '@blocknote/mantine';
|
||||
import '@blocknote/mantine/style.css';
|
||||
@@ -104,19 +104,25 @@ export const BlockNoteContent = ({
|
||||
// TODO decrypt doc.content
|
||||
//localStorage.getItem('KEY');
|
||||
|
||||
const docId = 'uuid-du-doc';
|
||||
const purpose = `doc:${docId}`;
|
||||
const docId = doc.id;
|
||||
const purpose = `docs:${docId}`;
|
||||
const key = e2eClient.findKeyByPurpose(purpose);
|
||||
console.log('purpose', purpose, 'key', key);
|
||||
let plaintextContent: Array<PartialBlock> | undefined;
|
||||
if (!key) {
|
||||
alert('probleme de key');
|
||||
// return;
|
||||
return;
|
||||
} else {
|
||||
const decryptedMessage = e2eClient.decrypt(
|
||||
doc.content,
|
||||
key.keychainFingerprint,
|
||||
);
|
||||
if (doc.content) {
|
||||
plaintextContent = JSON.parse(e2eClient.decrypt(
|
||||
doc.content,
|
||||
key.keychainFingerprint,
|
||||
) as string) as Array<PartialBlock>;
|
||||
|
||||
console.log('decryptedMessage', decryptedMessage);
|
||||
console.log('decryptedMessage', plaintextContent);
|
||||
} else {
|
||||
plaintextContent = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return BlockNoteEditorCore.create({
|
||||
@@ -129,10 +135,11 @@ export const BlockNoteContent = ({
|
||||
// },
|
||||
// },
|
||||
uploadFile,
|
||||
initialContent: JSON.parse(doc.content),
|
||||
initialContent: plaintextContent,
|
||||
});
|
||||
}, [doc.content, storedEditor, uploadFile]);
|
||||
|
||||
console.log("useSaveDoc", doc.id, provider.document, canSave, editor);
|
||||
useSaveDoc(doc.id, provider.document, canSave, editor);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -20,11 +20,11 @@ const useSaveDoc = (
|
||||
});
|
||||
const e2eClient = useE2ESDKClient();
|
||||
const [initialDoc, setInitialDoc] = useState<string>(
|
||||
toBase64(Y.encodeStateAsUpdate(doc)),
|
||||
JSON.stringify(editor.document)
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setInitialDoc(toBase64(Y.encodeStateAsUpdate(doc)));
|
||||
setInitialDoc(JSON.stringify(editor.document));
|
||||
}, [doc]);
|
||||
|
||||
/**
|
||||
@@ -40,7 +40,7 @@ const useSaveDoc = (
|
||||
transaction: Y.Transaction,
|
||||
) => {
|
||||
if (!transaction.local) {
|
||||
setInitialDoc(toBase64(Y.encodeStateAsUpdate(updatedDoc)));
|
||||
setInitialDoc(JSON.stringify(editor.document));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -55,11 +55,11 @@ const useSaveDoc = (
|
||||
* Check if the doc has been updated and can be saved.
|
||||
*/
|
||||
const hasChanged = useCallback(() => {
|
||||
const newDoc = toBase64(Y.encodeStateAsUpdate(doc));
|
||||
return initialDoc !== newDoc;
|
||||
return initialDoc !== JSON.stringify(editor.document);
|
||||
}, [doc, initialDoc]);
|
||||
|
||||
const shouldSave = useCallback(() => {
|
||||
console.log('hasChanged', hasChanged(), 'canSave', canSave);
|
||||
return hasChanged() && canSave;
|
||||
}, [canSave, hasChanged]);
|
||||
|
||||
@@ -69,9 +69,9 @@ const useSaveDoc = (
|
||||
|
||||
// TODO encode the content
|
||||
|
||||
const docId = 'uuid-du-doc';
|
||||
const purpose = `doc:${docId}`;
|
||||
const purpose = `docs:${docId}`;
|
||||
const key = e2eClient.findKeyByPurpose(purpose);
|
||||
console.log("purpose", purpose, "key", key);
|
||||
if (!key) {
|
||||
alert('probleme de key');
|
||||
return;
|
||||
@@ -87,7 +87,7 @@ const useSaveDoc = (
|
||||
|
||||
updateDoc({
|
||||
id: docId,
|
||||
content: newDoc,
|
||||
content: encrypted,
|
||||
});
|
||||
}, [docId, editor?.document, updateDoc]);
|
||||
|
||||
@@ -100,10 +100,12 @@ const useSaveDoc = (
|
||||
}
|
||||
|
||||
const onSave = (e?: Event) => {
|
||||
console.log('entered onSave');
|
||||
if (!shouldSave()) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('will save');
|
||||
saveDoc();
|
||||
|
||||
/**
|
||||
@@ -122,7 +124,7 @@ const useSaveDoc = (
|
||||
};
|
||||
|
||||
// Save every minute
|
||||
timeout.current = setInterval(onSave, 60000);
|
||||
timeout.current = setInterval(onSave, 1000);
|
||||
// Save when the user leaves the page
|
||||
addEventListener('beforeunload', onSave);
|
||||
// Save when the user navigates to another page
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { e2esdkClient } from '@/core/auth/useAuthStore';
|
||||
|
||||
import { APIError, errorCauses, fetchAPI } from '@/api';
|
||||
|
||||
@@ -13,6 +14,7 @@ export const createDoc = async ({ title }: CreateDocParam): Promise<Doc> => {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
title,
|
||||
is_e2ee: true
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -20,7 +22,16 @@ export const createDoc = async ({ title }: CreateDocParam): Promise<Doc> => {
|
||||
throw new APIError('Failed to create the doc', await errorCauses(response));
|
||||
}
|
||||
|
||||
return response.json() as Promise<Doc>;
|
||||
const resp = await (response.json() as Promise<Doc>);
|
||||
|
||||
const { keychainFingerprint } = await e2esdkClient.createNewKeychain(
|
||||
`docs:${resp.id}`,
|
||||
'secretBox'
|
||||
);
|
||||
|
||||
console.log('new e2ee keychain registered', keychainFingerprint);
|
||||
|
||||
return resp;
|
||||
};
|
||||
|
||||
interface CreateDocProps {
|
||||
|
||||
@@ -37,6 +37,7 @@ export interface Doc {
|
||||
accesses: Access[];
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
is_e2ee: boolean;
|
||||
abilities: {
|
||||
destroy: boolean;
|
||||
link_configuration: boolean;
|
||||
|
||||
Reference in New Issue
Block a user