vericrypt: initial commit

This commit is contained in:
Abdullah Atta
2023-07-31 11:30:54 +05:00
committed by Abdullah Atta
parent 3c9678c6d5
commit 2b1812b5de
64 changed files with 7067 additions and 0 deletions

View File

@@ -14,6 +14,7 @@ const SCOPES = [
"mobile", "mobile",
"web", "web",
"vericrypt",
"desktop", "desktop",
"crypto", "crypto",
"editor", "editor",

23
apps/vericrypt/.gitignore vendored Normal file
View File

@@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

39
apps/vericrypt/index.html Normal file
View File

@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="An open source utility to verify Notesnook data encryption in a safe & reliable way."
/>
<link rel="apple-touch-icon" href="/logo192.png" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>Notesnook Vericrypt</title>
<script type="module" src="/src/index.tsx"></script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

4938
apps/vericrypt/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
{
"name": "@notesnook/vericrypt",
"version": "1.2.0",
"private": true,
"devDependencies": {
"@types/platform": "^1.3.4",
"@types/react": "17.0.2",
"@types/react-dom": "17.0.2",
"@vitejs/plugin-react-swc": "^3.3.2",
"autoprefixer": "^10.4.14",
"vite": "^4.3.9",
"vite-plugin-env-compatible": "^1.1.1",
"vite-plugin-svgr": "^3.2.0"
},
"dependencies": {
"@emotion/react": "^11.10.0",
"@microsoft/signalr-protocol-msgpack": "^7.0.9",
"@notesnook/crypto": "file:../../packages/crypto",
"@notesnook/crypto-worker": "file:../../packages/crypto-worker",
"@notesnook/theme": "file:../../packages/theme",
"@theme-ui/components": "^0.14.7",
"@theme-ui/core": "^0.14.7",
"buffer": "^6.0.3",
"clipboard-polyfill": "^4.0.0",
"platform": "^1.3.6",
"react": "17.0.2",
"react-dom": "17.0.2",
"react-icons": "^4.10.1"
},
"scripts": {
"start": "vite",
"build": "vite build"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

View File

@@ -0,0 +1,71 @@
/* open-sans-regular - latin */
@font-face {
font-family: "Open Sans";
font-display: swap;
font-style: normal;
font-weight: 400;
src: local(""),
url("./assets/fonts/open-sans-v20-latin-regular.woff2") format("woff2"),
/* Chrome 26+, Opera 23+, Firefox 39+ */
url("./assets/fonts/open-sans-v20-latin-regular.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* open-sans-italic - latin */
@font-face {
font-family: "Open Sans";
font-display: swap;
font-style: italic;
font-weight: 400;
src: local(""),
url("./assets/fonts/open-sans-v20-latin-italic.woff2") format("woff2"),
/* Chrome 26+, Opera 23+, Firefox 39+ */
url("./assets/fonts/open-sans-v20-latin-italic.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* open-sans-600 - latin */
@font-face {
font-family: "Open Sans";
font-display: swap;
font-style: normal;
font-weight: 600;
src: local(""),
url("./assets/fonts/open-sans-v20-latin-600.woff2") format("woff2"),
/* Chrome 26+, Opera 23+, Firefox 39+ */
url("./assets/fonts/open-sans-v20-latin-600.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* open-sans-600italic - latin */
@font-face {
font-family: "Open Sans";
font-display: swap;
font-style: italic;
font-weight: 600;
src: local(""),
url("./assets/fonts/open-sans-v20-latin-600italic.woff2") format("woff2"),
/* Chrome 26+, Opera 23+, Firefox 39+ */
url("./assets/fonts/open-sans-v20-latin-600italic.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* open-sans-700 - latin */
@font-face {
font-family: "Open Sans";
font-display: swap;
font-style: normal;
font-weight: 700;
src: local(""),
url("./assets/fonts/open-sans-v20-latin-700.woff2") format("woff2"),
/* Chrome 26+, Opera 23+, Firefox 39+ */
url("./assets/fonts/open-sans-v20-latin-700.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* open-sans-700italic - latin */
@font-face {
font-family: "Open Sans";
font-display: swap;
font-style: italic;
font-weight: 700;
src: local(""),
url("./assets/fonts/open-sans-v20-latin-700italic.woff2") format("woff2"),
/* Chrome 26+, Opera 23+, Firefox 39+ */
url("./assets/fonts/open-sans-v20-latin-700italic.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}

165
apps/vericrypt/src/app.tsx Normal file
View File

@@ -0,0 +1,165 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Image, Flex, Text } from "@theme-ui/components";
import { ThemeProvider } from "@emotion/react";
import "./app.css";
import { MdVpnKey, MdCheck } from "react-icons/md";
import { BiPlus } from "react-icons/bi";
import { getDefaultAccentColor, useTheme } from "@notesnook/theme";
import { Hero } from "./components/hero";
import { LoginToNotesnook } from "./components/step-1";
import { GetAccountSalt } from "./components/step-2";
import { EnterAccountPassword } from "./components/step-3";
import { PasteEncryptedData, SyncRequestBody } from "./components/step-4";
import { StepSeperator } from "./components/step-seperator";
import { Footer } from "./components/footer";
import { useState } from "react";
import { NNCrypto } from "@notesnook/crypto";
import { Code } from "./components/code";
import { Accordion } from "./components/accordion";
import { DecryptedResult } from "./components/decrypted-result";
import Map from "./assets/images/map.svg";
const instructions = [
"Go to Notesnook",
"Open Settings",
<>
Click on <Code text="Backup data recovery key" />
</>,
"Enter your account password for verification",
"Confirm that your generated encryption key matches"
];
function App() {
const [password, setPassword] = useState<string>();
const [salt, setSalt] = useState<string>();
const [key, setKey] = useState<string>();
const [data, setData] = useState<SyncRequestBody | undefined>();
const theme = useTheme({ accent: getDefaultAccentColor(), theme: "light" });
return (
<ThemeProvider theme={theme}>
<Flex sx={{ flexDirection: "column" }}>
<Image src={Map} sx={{ position: "absolute", opacity: 0.1 }} />
<Hero />
<Flex
sx={{
flexDirection: "column",
alignItems: "center"
}}
>
<LoginToNotesnook />
<StepSeperator />
<GetAccountSalt onSaltSubmitted={setSalt} />
{salt && (
<>
<StepSeperator icon={BiPlus} />
<EnterAccountPassword onPasswordSubmitted={setPassword} />
</>
)}
{salt && password && (
<>
<StepSeperator
icon={MdVpnKey}
tooltip="Click to see derived encryption key"
onShowPopup={async () => {
if (!password) return false;
const { key } = await new NNCrypto().exportKey(
password,
salt
);
setKey(key);
return true;
}}
popup={{
title: "Your data encryption key",
body: key ? (
<>
<Text
as="code"
sx={{
fontFamily: "monospace",
mt: 2,
bg: "bgSecondary",
p: 1,
borderRadius: 5
}}
>
{key}
</Text>
<Accordion
title="How to verify your encryption key?"
sx={{
border: "1px solid var(--border)",
mt: 2,
borderRadius: "default"
}}
>
<Text variant="body" sx={{ mx: 2 }}>
Now that you have derived your encryption key,
you&apos;ll want to verify it to make sure we
didn&apos;t just make it up. To do so, follow these
steps:
<Text as="ol" variant="body" sx={{ mb: 2 }}>
{instructions?.map((item, index) => (
<Text
key={index.toString()}
as="li"
sx={{ mt: 1 }}
>
{item}
</Text>
))}
</Text>
</Text>
</Accordion>
</>
) : undefined
}}
/>
<PasteEncryptedData onEncryptedDataPasted={setData} />
</>
)}
{password && salt && data && (
<>
<StepSeperator icon={MdCheck} />
<DecryptedResult
password={password}
salt={salt}
data={data}
onRestartProcess={() => {
setSalt(undefined);
setPassword(undefined);
setKey(undefined);
setData(undefined);
}}
/>
</>
)}
</Flex>
<Footer />
</Flex>
</ThemeProvider>
);
}
export default App;

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -0,0 +1,61 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Flex, FlexProps, Text } from "@theme-ui/components";
import { PropsWithChildren, useState } from "react";
import { IoChevronDown, IoChevronUp } from "react-icons/io5";
type AccordionProps = FlexProps & {
title: string;
color?: string;
};
export function Accordion({
title,
children,
sx,
color = "icon",
...restProps
}: PropsWithChildren<AccordionProps>) {
const [isContentHidden, setIsContentHidden] = useState<boolean>(true);
return (
<Flex sx={{ flexDirection: "column", ...sx }} {...restProps}>
<Flex
sx={{
justifyContent: "space-between",
alignItems: "center",
p: 2,
cursor: "pointer",
color: color
}}
onClick={() => {
setIsContentHidden((state) => !state);
}}
>
<Text variant="subtitle" sx={{ color }}>
{title}
</Text>
{isContentHidden ? (
<IoChevronDown size={16} color={color} />
) : (
<IoChevronUp size={16} color={color} />
)}
</Flex>
{!isContentHidden && children}
</Flex>
);
}

View File

@@ -0,0 +1,44 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Text, Link } from "@theme-ui/components";
type CodeProps = { text: string; href?: string };
export function Code(props: CodeProps) {
return (
<Text
as="code"
sx={{
bg: "bgSecondary",
px: 1,
borderRadius: 5,
fontFamily: "monospace",
border: "1px solid var(--border)",
cursor: props.href ? "pointer" : "unset"
}}
>
{props.href ? (
<Link href={props.href} color="primary">
{props.text}
</Link>
) : (
props.text
)}
</Text>
);
}

View File

@@ -0,0 +1,184 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Flex, Button, Text, Link } from "@theme-ui/components";
import { StepContainer } from "./step-container";
import { SyncRequestBody } from "./step-4";
import { NNCrypto } from "@notesnook/crypto";
import { useEffect, useState } from "react";
import { FcDataEncryption } from "react-icons/fc";
import { Code } from "./code";
import { getSourceUrl } from "../utils/links";
import { writeText } from "clipboard-polyfill";
import { Accordion } from "./accordion";
import { ErrorsList } from "./errors-list";
type DecryptedResultProps = {
password: string;
salt: string;
data: SyncRequestBody;
onRestartProcess: () => void;
};
export function DecryptedResult(props: DecryptedResultProps) {
const [isDecrypting, setIsDecrypting] = useState(true);
const [decryptedData, setDecryptedData] = useState<string>();
const [error, setError] = useState<string | undefined>();
useEffect(() => {
(async function () {
try {
const data: any = {
notes: [],
notebooks: [],
content: [],
attachments: []
};
const crypto = new NNCrypto();
const key = await crypto.exportKey(props.password, props.salt);
for (const arrayKey in data) {
const array = data[arrayKey];
for (const encryptedItem of (props.data as any)[arrayKey]) {
const { data } = await crypto.decrypt(key, encryptedItem, "text");
array.push(JSON.parse(data as string));
}
}
setDecryptedData(JSON.stringify(data, undefined, " "));
} catch (e) {
const error = e as Error;
setError(error.message);
} finally {
setIsDecrypting(false);
}
})();
}, [props]);
if (error)
return (
<StepContainer
as="form"
sx={{
flexDirection: "column"
}}
>
<Text variant="title">Decryption failed</Text>
<ErrorsList errors={[error]} />
</StepContainer>
);
if (isDecrypting)
return (
<StepContainer
as="form"
sx={{
flexDirection: "column",
justifyContent: "center",
alignItems: "center"
}}
>
<FcDataEncryption size={50} />
<Text variant="title" sx={{ mt: 2 }}>
Decrypting your data...
</Text>
</StepContainer>
);
return (
<StepContainer
sx={{
flexDirection: "column",
border: "2px solid var(--primary)"
}}
>
<Flex sx={{ justifyContent: "space-between", alignItems: "center" }}>
<Text variant="title">Your data has been decrypted</Text>
<Code
text="src/components/DecryptedResult.tsx"
href={getSourceUrl("src/components/DecryptedResult.tsx")}
/>
</Flex>
<Text variant="body">
This is your data in it&apos;s raw decrypted format. Feel free to scroll
through and see what it contains.
</Text>
<Text
as="pre"
variant="body"
sx={{
maxHeight: 400,
overflowY: "auto",
fontFamily: "monospace",
whiteSpace: "pre-wrap",
color: "icon",
mt: 2
}}
>
{decryptedData}
</Text>
<Accordion
title="What happens now?"
sx={{
border: "1px solid var(--border)",
mt: 2,
borderRadius: "default"
}}
>
<Text as="p" variant="body" sx={{ mx: 2 }}>
Congratulations! You successfully verified Notesnook&apos;s data
encryption claims.
</Text>
<Text as="p" variant="body" sx={{ mx: 2, mt: 2 }}>
Of course, this is just one part (a very crucial one) of proving that
you can trust Notesnook with your data. If you have any other
preservations, let us know by reaching out to us at{" "}
<Link href="mailto:support@streetwriters.co">
support@streetwriters.co
</Link>{" "}
or{" "}
<Link href="https://discord.gg/">joining our Discord community</Link>.
We&apos;ll do our best to alleviate all your worries.
</Text>
<Text as="p" variant="body" sx={{ mx: 2, mt: 2, fontWeight: "bold" }}>
What about open sourcing Notesnook?
</Text>
<Text as="p" variant="body" sx={{ mx: 2, my: 2 }}>
Open sourcing is another part of garnering our users&apos; trust. We
have <Link href="https://notesnook.com/roadmap">plans</Link> to begin
open sourcing in May but open sourcing will not make this tool
obsolete. Verifying the integrity of encrypted data at any point in
time is very important even if the software is open source.
</Text>
</Accordion>
<Flex sx={{ alignSelf: "center", mt: 4 }}>
<Button
variant="secondary"
sx={{ mr: 2 }}
onClick={async () => {
if (!decryptedData) return;
await writeText(decryptedData);
}}
>
Copy data as JSON
</Button>
<Button variant="primary" onClick={props.onRestartProcess}>
Start again
</Button>
</Flex>
</StepContainer>
);
}

View File

@@ -0,0 +1,57 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Button, Flex, Text } from "@theme-ui/components";
import { Accordion } from "./accordion";
type ErrorsListProps = {
errors: string[];
};
export function ErrorsList(props: ErrorsListProps) {
return (
<Accordion
title={`${props.errors.length} errors occured`}
sx={{ bg: "errorBg", borderRadius: "default", mt: 2 }}
color="#E53935"
>
<Flex sx={{ flexDirection: "column", px: 2, pb: 2 }}>
<Text variant="body" sx={{ color: "error" }}>
{props.errors.map((error, index) => (
<>
{error}
<br />
</>
))}
</Text>
<Button
sx={{ bg: "error", color: "static", alignSelf: "start", mt: 2 }}
onClick={() =>
window.open(
"https://github.com/streetwriters/notesnook/issues/new",
"_blank",
"noopener"
)
}
>
Send us a bug report
</Button>
</Flex>
</Accordion>
);
}

View File

@@ -0,0 +1,41 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Flex, Text } from "@theme-ui/components";
import { appVersion } from "../utils/version";
export function Footer() {
return (
<Flex
sx={{
flexDirection: "column",
mt: 100,
pt: 50,
pb: 50,
borderTop: "1px solid var(--border)",
alignItems: "center",
justifyContent: "center"
}}
>
<Text variant="body">Notesnook Vericrypt (v{appVersion})</Text>
<Text variant="subBody">
© {new Date().getFullYear()} Streetwriters LLC
</Text>
</Flex>
);
}

View File

@@ -0,0 +1,132 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Flex, Box, Link, Text } from "@theme-ui/components";
import { appVersion } from "../utils/version";
import {
MdOutlineShield,
MdVpnKey,
MdOutlineStorage,
MdOutlineEnhancedEncryption
} from "react-icons/md";
import { getAppUrl } from "../utils/links";
const Algorithms = [
{
key: "argon2",
title: "Encryption key derivation (PKDF)",
name: "Argon2",
icon: MdVpnKey
},
{
key: "aes-gcm",
title: "Encryption key storage",
name: "AES-GCM 256",
icon: MdOutlineStorage
},
{
key: "xchacha",
title: "Data encryption",
name: "XChaXCha-Poly1305-IETF",
icon: MdOutlineEnhancedEncryption
}
];
export function Hero() {
return (
<Flex
sx={{
flexDirection: "column",
mt: 150,
mb: 100,
justifyContent: "center",
alignItems: "center"
}}
>
<Text
variant="heading"
sx={{
textAlign: "center",
display: "flex",
alignItems: "center",
fontSize: 52
}}
>
<MdOutlineShield /> Notesnook Vericrypt
</Text>
<Text
sx={{
fontSize: "subheading",
textAlign: "center",
color: "fontTertiary"
}}
>
An open source utility to verify Notesnook data encryption claims in a
provable way.
</Text>
<Flex sx={{ mt: 2, zIndex: 10 }}>
<Text variant="body" sx={{ px: 1 }}>
v{appVersion}
</Text>
<Link
href={getAppUrl("vericrypt")}
variant="text.body"
sx={{ px: 1, borderLeft: "1px solid var(--border)" }}
>
See source code
</Link>
</Flex>
<Box
sx={{
mt: 100,
display: "grid",
gridTemplateColumns: "1fr 1fr 1fr",
rowGap: 2
}}
>
{Algorithms.map((alg) => (
<Flex
sx={{
flexDirection: "column",
mr: 4,
p: 2,
borderRadius: "default",
bg: "black",
width: 250
}}
key={alg.key}
>
<alg.icon color={"var(--fontSecondary)"} />
<Text variant="subtitle" sx={{ color: "fontSecondary" }}>
{alg.title}
</Text>
<Text
variant="body"
sx={{
fontSize: "subtitle",
color: "fontSecondary"
}}
>
{alg.name}
</Text>
</Flex>
))}
</Box>
</Flex>
);
}

View File

@@ -0,0 +1,33 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Code } from "./code";
type KeyComboProps = { combo: string[] };
export function KeyCombo(props: KeyComboProps) {
return (
<>
{props.combo.map((key, index) => (
<>
<Code text={key} />
{index < props.combo.length - 1 ? " + " : ""}
</>
))}
</>
);
}

View File

@@ -0,0 +1,93 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Button, Link, Text } from "@theme-ui/components";
import { StepContainer } from "./step-container";
import { Code } from "./code";
import { getPackageUrl } from "../utils/links";
export function LoginToNotesnook() {
return (
<StepContainer
onSubmit={(e) => {
e.preventDefault();
document.getElementById("step_2")?.scrollIntoView({
behavior: "smooth",
block: "center"
});
return false;
}}
onSubmitCapture={() => false}
as="form"
sx={{ flexDirection: "column" }}
>
<Text variant="title">Welcome to Vericrypt</Text>
<Text as="p" variant="body" sx={{ mt: 1 }}>
<del>
Trust is a huge problem in closed source end-to-end encrypted
applications. How can you be sure that the app is actually encrypting
your data?
</del>
</Text>
<Text as="p" variant="body" sx={{ mt: 1 }}>
The only way to earn a user&apos;s trust is by allowing them to see how
the underlying encryption actually works. To do this,{" "}
<Link
target="_blank"
href="https://blog.notesnook.com/notesnook-is-going-open-source"
sx={{ color: "primary", fontWeight: "bold" }}
>
we have completely open sourced Notesnook.
</Link>
</Text>
<Text as="p" variant="body" sx={{ mt: 1 }}>
Yes, that&apos;s right. Notesnook is now 100% open source under the
GPLv3 license. That includes the app, the encryption library, the
backend server, and everything else.
</Text>
<Text as="p" variant="body" sx={{ mt: 1 }}>
However, even with an open source app, how can you be sure that the app
is actually encrypting your data? That is why we have made this tool
(also open source), which uses{" "}
<Code text="@notesnook/crypto" href={getPackageUrl("crypto")} /> the
main library for all cryptographic operations inside Notesnook.
</Text>
<Text as="p" variant="body" sx={{ mt: 1 }}>
Vericrypt will allow you to verify all encryption claims made by
Notesnook in a practical &amp; provable way right inside your browser.
</Text>
<Text
as="p"
variant="body"
sx={{ mt: 1, bg: "bgSecondary", p: 2, borderRadius: 5 }}
>
When you use this tool, you&apos;ll be guided each step of the way to
extract/insert raw data from raw sources.{" "}
<b>The whole process happens completely in your browser offline</b> and
you can even disconnect your internet to make sure we aren&apos;t just
saying that.
</Text>
<Button
sx={{ alignSelf: "center", mt: 2 }}
onClick={() => window.open("https://app.notesnook.com/login", "_blank")}
>
Login to Notesnook
</Button>
</StepContainer>
);
}

View File

@@ -0,0 +1,217 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Flex, Text, Image, Input } from "@theme-ui/components";
import { StepContainer } from "./step-container";
import DevtoolsApplicationTab from "../assets/screenshots/devtools_application_tab.png";
import DevtoolsSelectDB from "../assets/screenshots/devtools_select_db.png";
import DevtoolsSalt from "../assets/screenshots/devtools_salt.png";
import DevtoolsFirefoxStorageTab from "../assets/screenshots/firefox/firefox_storage_tab.png";
import DevtoolsSelectDBFirefox from "../assets/screenshots//firefox/firefox_keyvalue_pairs.png";
import DevtoolsSaltFirefox from "../assets/screenshots/firefox/firefox_user_object.png";
import { Accordion } from "./accordion";
import { getCombo } from "../utils/keycombos";
import Platform from "platform";
import { KeyCombo } from "./key-combo";
import { Code } from "./code";
import { useState } from "react";
import { getSourceUrl } from "../utils/links";
type GetAccountSaltProps = {
onSaltSubmitted: (salt: string) => void;
};
const steps = {
chromium: [
"Focus the Notesnook tab in your browser.",
<>
Press <KeyCombo combo={getCombo("chromium", "developerTools")} /> to open
Developer Tools.
</>,
<Flex key="switch-to-application-tab" sx={{ flexDirection: "column" }}>
<Text as="p">
Switch to the <Code text="Application" /> tab.
</Text>
<Image src={DevtoolsApplicationTab} width={300} sx={{ mt: 1 }} />
</Flex>,
<>
From the side menu, expand <Code text="IndexedDB" /> which is under the
Storage heading.
</>,
`You'll see a number of databases . Expand the one that starts with "Notesnook".`,
<Flex key="click-on-keyvaluepairs" sx={{ flexDirection: "column" }}>
<Text as="p">
Click on <Code text="keyvaluepairs" />.
</Text>
<Image src={DevtoolsSelectDB} width={200} sx={{ mt: 1 }} />
</Flex>,
<>
On the right panel, you&apos;ll see an input with the placeholder
&quot;Start from key&quot; at the top. Type <Code text="user" /> in that
input.
</>,
`At the top of the list, you'll see an entry with key "user". Expand the value.`,
<Flex key="key-named-salt" sx={{ flexDirection: "column" }}>
<Text as="p">
You&apos;ll see a key named <Code text="salt" />. Copy the value against
it.
</Text>
<Image src={DevtoolsSalt} width={400} sx={{ mt: 1 }} />
</Flex>
],
firefox: [
"Focus the Notesnook tab in your browser.",
<>
Press <KeyCombo combo={getCombo("firefox", "developerTools")} /> to open
Developer Tools.
</>,
<Flex key="switch-to-storage-tab" sx={{ flexDirection: "column" }}>
<Text as="p">
Switch to the <Code text="Storage" /> tab.
</Text>
<Image src={DevtoolsFirefoxStorageTab} width={300} sx={{ mt: 1 }} />
</Flex>,
<>
From the side menu, expand <Code text="IndexedDB" /> which is under the
Storage heading.
</>,
`You'll see a number of databases . Expand the one that starts with "Notesnook".`,
<Flex key="click-on-keyvaluepairs" sx={{ flexDirection: "column" }}>
<Text as="p">
Click on <Code text="keyvaluepairs" />.
</Text>
<Image src={DevtoolsSelectDBFirefox} width={200} sx={{ mt: 1 }} />
</Flex>,
<>
On the right panel, you&apos;ll see an input with the placeholder
&quot;Start from key&quot; at the top. Type <Code text="user" /> in that
input. If you don&apos;t see the &apos;user&apos; object, scroll to end
using <Code text="Page down" /> key in key-value pair list and then search
again.
</>,
`At the top of the list, you'll see an entry with key "user". Expand the value.`,
<Flex key="key-named-salt" sx={{ flexDirection: "column" }}>
<Text as="p">
You&apos;ll see a key named <Code text="salt" />. Right click and copy
the value against it.
</Text>
<Image src={DevtoolsSaltFirefox} width={400} sx={{ mt: 1 }} />
</Flex>
]
};
const isChromium = Platform.name === "Chrome";
const isFirefox = Platform.name === "Firefox";
const instructions = isChromium
? steps.chromium
: isFirefox
? steps.firefox
: null;
console.log(Platform.name);
export function GetAccountSalt(props: GetAccountSaltProps) {
const [isSaltValid, setIsSaltValid] = useState<boolean>();
return (
<StepContainer
onSubmit={(e) => {
e.preventDefault();
if (isSaltValid) {
document.getElementById("step_3")?.scrollIntoView({
behavior: "smooth",
block: "center"
});
}
return false;
}}
onSubmitCapture={() => false}
inputMode="text"
id="step_2"
as="form"
sx={{ flexDirection: "column" }}
>
<Flex sx={{ justifyContent: "space-between", alignItems: "center" }}>
<Text variant="title">Account salt</Text>
<Code
text="src/components/step-2.tsx"
href={getSourceUrl("src/components/step-2.tsx")}
/>
</Flex>
<Accordion
title="How to get your account salt?"
sx={{
border: "1px solid var(--border)",
mt: 2,
borderRadius: "default"
}}
>
<Text variant="body" sx={{ mx: 2 }}>
We&apos;ll be extracting your account&apos;s salt right from
Notesnook&apos;s local database that lives in your web browser. So put
on your seat belt and let&apos;s get some salt!
</Text>
<Text as="ol" variant="body" sx={{ mb: 2 }}>
{instructions?.map((item, index) => (
<Text key={index.toString()} as="li" sx={{ mt: 1 }}>
{item}
</Text>
))}
</Text>
</Accordion>
<Input
variant="forms.clean"
id="salt"
name="salt"
type="text"
placeholder="Enter your account salt"
sx={{
mt: 2,
fontSize: "subheading",
fontFamily: "monospace",
textAlign: "center",
color:
isSaltValid === true
? "primary"
: isSaltValid === false
? "error"
: "text"
}}
spellCheck={false}
onChange={(e) => {
setIsSaltValid(undefined);
try {
const value = e.target.value;
const isValid = Buffer.from(value, "base64").length === 16;
if (!isValid) setIsSaltValid(false);
else {
setIsSaltValid(true);
props.onSaltSubmitted(value);
}
} catch (e) {
console.error(e);
setIsSaltValid(false);
}
}}
/>
</StepContainer>
);
}

View File

@@ -0,0 +1,88 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Flex, Text, Input } from "@theme-ui/components";
import { getSourceUrl } from "../utils/links";
import { Code } from "./code";
import { StepContainer } from "./step-container";
type EnterAccountPasswordProps = {
onPasswordSubmitted: (password: string) => void;
};
export function EnterAccountPassword(props: EnterAccountPasswordProps) {
return (
<StepContainer
onSubmit={(e) => {
e.preventDefault();
document.getElementById("step_4")?.scrollIntoView({
behavior: "smooth",
block: "center"
});
return false;
}}
onSubmitCapture={() => false}
inputMode="text"
id="step_3"
as="form"
sx={{ flexDirection: "column" }}
>
<Flex sx={{ justifyContent: "space-between", alignItems: "center" }}>
<Text variant="title">Account password</Text>
<Code
text="src/components/step-3.tsx"
href={getSourceUrl("src/components/step-3.tsx")}
/>
</Flex>
<Flex
sx={{
bg: "bgSecondary",
mt: 2,
p: 2,
borderRadius: "default",
flexDirection: "column"
}}
>
<Text variant="subtitle">
Will my account password be sent to the server?
</Text>
<Text as="p" variant="body">
Never. Your password never ever leaves this browser tab. Everything
takes place locally. This is the most fundamental part of zero
knowledge data encryption.
</Text>
</Flex>
<Input
variant="forms.clean"
id="password"
name="password"
type="password"
placeholder="Enter your account password"
sx={{
mt: 2,
fontSize: "subheading",
fontFamily: "monospace",
textAlign: "center"
}}
onChange={(e) => {
props.onPasswordSubmitted(e.target.value);
}}
/>
</StepContainer>
);
}

View File

@@ -0,0 +1,397 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Flex, Text, Image, Textarea } from "@theme-ui/components";
import { StepContainer } from "./step-container";
import DevtoolsRequestsFilter from "../assets/screenshots/devtools_requests_filter.png";
import DevtoolsRequestsWS from "../assets/screenshots/devtools_requests_ws.png";
import DevtoolsRequestsWSMessages from "../assets/screenshots/devtools_requests_ws_messages.png";
import DevtoolsRequestsWSMessagesSelect from "../assets/screenshots/devtools_requests_ws_messages_select.png";
import DevtoolsRequestsWSMessagesCopy from "../assets/screenshots/devtools_requests_ws_messages_copy.png";
// Firefox does not support extracting raw WebSocket response data yet.
// Once it does we can start using these.
// import FirefoxDevtoolsRequestsWS from "../assets/screenshots/firefox/devtools_requests_ws.png";
// import FirefoxDevtoolsRequestsFilter from "../assets/screenshots/firefox/devtools_requests_filter.png";
// import FirefoxDevtoolsRequestsWSResponse from "../assets/screenshots/firefox/devtools_requests_ws_response.png";
// import FirefoxDevtoolsRequestsWSResponseSizeColumn from "../assets/screenshots/firefox/devtools_requests_ws_response_sizecolumn.png";
// import FirefoxDevtoolsRequestsWSMessagesSelect from "../assets/screenshots/firefox/devtools_requests_ws_messages_select.png";
// import FirefoxDevtoolsRequestsWSMessagesCopy from "../assets/screenshots/firefox/devtools_requests_ws_messages_copy.png";
import { Accordion } from "./accordion";
import { getCombo } from "../utils/keycombos";
import Platform from "platform";
import { KeyCombo } from "./key-combo";
import { Code } from "./code";
import { useState, useEffect } from "react";
import { ErrorsList } from "./errors-list";
import { getSourceUrl } from "../utils/links";
import { MessagePackHubProtocol } from "@microsoft/signalr-protocol-msgpack";
type PasteEncryptedDataProps = {
onEncryptedDataPasted: (data?: SyncRequestBody) => void;
};
type EncryptedSyncItem = {
alg: string;
cipher: string;
format: "base64";
id: string;
iv: string;
length: number;
salt: string;
v: number;
};
export type SyncRequestBody = {
notes: EncryptedSyncItem[];
content: EncryptedSyncItem[];
notebooks: EncryptedSyncItem[];
attachments: EncryptedSyncItem[];
};
const SAMPLE_CURL = `Paste raw base64 encoded data here.`;
const steps = {
chromium: [
"Focus the Notesnook tab in your browser.",
<>
Press <KeyCombo combo={getCombo("chromium", "developerTools")} /> to open
Developer Tools.
</>,
<>
Switch to the <Code text="Network" /> tab.
</>,
<Flex key="toggle-ws" sx={{ flexDirection: "column" }}>
<Text as="p">
Make sure you have <Code text="WS" /> toggled instead of{" "}
<Code text="Fetch/XHR" />
</Text>
<Image src={DevtoolsRequestsWS} width={400} sx={{ mt: 1 }} />
</Flex>,
<Flex key="type-sync-in-filter" sx={{ flexDirection: "column" }}>
<Text as="p">
In the filter input, type <Code text="sync" /> to filter out sync
requests.
</Text>
<Image src={DevtoolsRequestsFilter} width={400} sx={{ mt: 1 }} />
</Flex>,
<>
<b>Refresh the page by pressing F5</b> (this is done so we can capture the
websocket request that happens on startup).
</>,
<>
Wait until a request starting with <Code text="sync?access_token=" /> pops
up. It&apos;ll probably be the only one popping up and might take a bit so
don&apos;t panic if you don&apos;t see anything.
</>,
<>Left-click on this request to open its details.</>,
<Flex key="switch-to-code-tab" sx={{ flexDirection: "column" }}>
<Text as="p">
Switch to the <Code text="Messages" /> tab.
</Text>
<Image src={DevtoolsRequestsWSMessages} width={400} sx={{ mt: 1 }} />
</Flex>,
<>
At this point, you will a list of Binary messages. None of these will
appear really useful. This is normal.
</>,
<>
Now try editing one of your notes and syncing. (Make sure to keep the{" "}
<Code text="Network" /> tab open.)
</>,
<Flex key="new-binary-messages" sx={{ flexDirection: "column" }}>
<Text as="p">
You will see a bunch of new <Code text="Binary Messages" /> appear in
the list. Find the one with the largest Length (in KBs). Also make sure
the output type is set to <Code text="Base64" /> as in the screenshot
below.
</Text>
<Image
src={DevtoolsRequestsWSMessagesSelect}
width={700}
sx={{ mt: 1, maxWidth: "95%" }}
/>
</Flex>,
<Flex key="click-copy-button" sx={{ flexDirection: "column" }}>
<Text as="p">Click on the copy button to copy the payload.</Text>
<Image src={DevtoolsRequestsWSMessagesCopy} width={200} sx={{ mt: 1 }} />
</Flex>,
<> Paste it below to see the decrypted data.</>
],
firefox: []
// firefox: [
// "Focus the Notesnook tab in your browser.",
// <>
// Press <KeyCombo combo={getCombo("firefox", "developerTools")} /> to open
// Developer Tools.
// </>,
// <>
// Switch to the <Code text="Network" /> tab.
// </>,
// <Flex sx={{ flexDirection: "column" }}>
// <Text as="p">
// Make sure you have <Code text="WS" /> toggled instead of{" "}
// <Code text="Fetch/XHR" />
// </Text>
// <Image src={FirefoxDevtoolsRequestsWS} width={400} sx={{ mt: 1 }} />
// </Flex>,
// <Flex sx={{ flexDirection: "column" }}>
// <Text as="p">
// In the filter input, type <Code text="sync" /> to filter out sync
// requests.
// </Text>
// <Image src={FirefoxDevtoolsRequestsFilter} width={400} sx={{ mt: 1 }} />
// </Flex>,
// <>
// <b>Refresh the page by pressing F5</b> (this is done so we can capture the
// websocket request that happens on startup).
// </>,
// <>
// Wait until a request starting with <Code text="sync?access_token=" /> pops
// up. It'll probably be the only one popping up and might take a bit so
// don't panic if you don't see anything.
// </>,
// <>Left-click on this request to open its details.</>,
// <Flex sx={{ flexDirection: "column" }}>
// <Text as="p">
// Switch to the <Code text="Response" /> tab.
// </Text>
// <Image
// src={FirefoxDevtoolsRequestsWSResponse}
// width={400}
// sx={{ mt: 1 }}
// />
// </Flex>,
// <>
// At this point, you will a list of Binary messages. None of these will
// appear really useful. This is normal.
// </>,
// <Flex sx={{ flexDirection: "column" }}>
// <Text as="p">
// To help in finding the right request, <Code text="Right click" /> on the
// table header &amp; enable the <Code text="Size" /> column.
// </Text>
// <Image
// src={FirefoxDevtoolsRequestsWSResponseSizeColumn}
// width={300}
// sx={{ mt: 1 }}
// />
// </Flex>,
// <>
// Now try editing one of your notes and syncing. (Make sure to keep the{" "}
// <Code text="Network" /> tab open.)
// </>,
// <Flex sx={{ flexDirection: "column" }}>
// <Text as="p">
// You will see a bunch of new items appear in the table. Find the one with
// the largest Length (in KBs).
// </Text>
// <Image
// src={FirefoxDevtoolsRequestsWSMessagesSelect}
// width={700}
// sx={{ mt: 1, maxWidth: "95%" }}
// />
// </Flex>,
// <Flex sx={{ flexDirection: "column" }}>
// <Text as="p">
// Right-click on the item &amp; click on <Code text="Copy Message" />
// </Text>
// <Image
// src={FirefoxDevtoolsRequestsWSMessagesCopy}
// width={400}
// sx={{ mt: 1 }}
// />
// </Flex>,
// <> Paste it below to see the decrypted data.</>,
// ],
};
const isChromium = Platform.name === "Chrome";
const isFirefox = Platform.name === "Firefox";
const instructions = isChromium
? steps.chromium
: isFirefox
? steps.chromium
: null;
export function PasteEncryptedData(props: PasteEncryptedDataProps) {
const { onEncryptedDataPasted } = props;
const [error, setError] = useState<string | undefined>();
const [encryptedData, setEncryptedData] = useState<
SyncRequestBody | undefined
>();
useEffect(() => {
onEncryptedDataPasted(encryptedData);
}, [encryptedData, onEncryptedDataPasted]);
return (
<StepContainer id="step_4" as="form" sx={{ flexDirection: "column" }}>
<Flex sx={{ justifyContent: "space-between", alignItems: "center" }}>
<Text variant="title">Paste raw encrypted data</Text>
<Code
text="src/components/step-4.tsx"
href={getSourceUrl("src/components/step-4.tsx")}
/>
</Flex>
<Accordion
title="How to get raw encrypted data?"
sx={{
border: "1px solid var(--border)",
mt: 2,
borderRadius: "default"
}}
>
{!isChromium && (
<Flex sx={{ bg: "errorBg", p: 1 }}>
<Text as="p" variant="body" sx={{ color: "error" }}>
Currently Firefox does not support pasting raw data from the
WebSocket response view.{" "}
<b>Please use a Chromium-based browser</b> for grabbing the
necessary data.
</Text>
</Flex>
)}
<Text variant="body" sx={{ mx: 2 }}>
To make this whole process verifiable &amp; trustworthy, we need to
extract the raw data that Notesnook sends to its servers during sync.
That way you can be sure that the data leaving your device is actually
encrypted or not.
</Text>
<Text as="ol" variant="body" sx={{ mb: 2 }}>
{instructions?.map((item, index) => (
<Text key={index.toString()} as="li" sx={{ mt: 1 }}>
{item}
</Text>
))}
</Text>
</Accordion>
<Textarea
variant="forms.clean"
placeholder={SAMPLE_CURL}
spellCheck={false}
sx={{
mt: 2,
fontSize: "body",
fontFamily: "monospace",
whiteSpace: "pre-wrap",
height: 280
}}
onChange={(e) => {
try {
setError(undefined);
const base64Data = e.target.value;
const protocol = new MessagePackHubProtocol();
const messages = protocol
.parseMessages(toArrayBuffer(base64Data), {
log: console.log
})
.filter((m) => m.type === 1);
if (!messages.length) {
setError("Invalid message.");
return setEncryptedData(undefined);
}
const syncData: SyncRequestBody = {
attachments: [],
content: [],
notebooks: [],
notes: []
};
for (const message of messages) {
if (message.type === 1) {
const { items, types } = message.arguments[0] as {
items?: string[];
types?: string[];
};
if (!items || !types) continue;
for (let i = 0; i < types.length; ++i) {
const itemType = types[i];
const item = JSON.parse(items[i]) as EncryptedSyncItem;
switch (itemType) {
case "note":
syncData.notes.push(item);
break;
case "notebook":
syncData.notebooks.push(item);
break;
case "content":
syncData.content.push(item);
break;
case "attachment":
syncData.attachments.push(item);
break;
default:
continue;
}
}
}
}
if (syncData.notes.length <= 0 && syncData.content.length <= 0) {
throw new Error(
"The pasted data does not contain any notes. Please select another payload."
);
}
setEncryptedData(syncData);
} catch (e) {
console.error(e);
const error = e as Error;
setError(error.message);
}
}}
/>
{error ? <ErrorsList errors={[error]} /> : null}
{encryptedData && (
<Flex
sx={{
bg: "shade",
border: "2px solid var(--primary)",
mt: 2,
p: 2,
borderRadius: "default",
flexDirection: "column"
}}
>
<Text variant="subtitle">Parsing complete</Text>
<Text as="p" variant="body">
We found {encryptedData.notes.length} note(s),{" "}
{encryptedData.content.length} content(s),{" "}
{encryptedData.notebooks.length} notebook(s) &amp;{" "}
{encryptedData.attachments.length} attachments.
</Text>
</Flex>
)}
</StepContainer>
);
}
function toArrayBuffer(payload: string) {
const binary_string = window.atob(payload);
const len = binary_string.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes.buffer;
}

View File

@@ -0,0 +1,41 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Flex, FlexProps } from "@theme-ui/components";
export function StepContainer({
children,
sx,
...restProps
}: React.PropsWithChildren<FlexProps>) {
return (
<Flex
sx={{
width: "40%",
boxShadow: "0px 0px 20px 0px #00000011",
p: 4,
borderRadius: "default",
bg: "background",
...sx,
}}
{...restProps}
>
{children}
</Flex>
);
}

View File

@@ -0,0 +1,119 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Flex, Text } from "@theme-ui/components";
import { useState } from "react";
import { IconType } from "react-icons";
import { MdClose } from "react-icons/md";
import { ThemeProvider } from "@emotion/react";
import { getDefaultAccentColor, useTheme } from "@notesnook/theme";
type StepSeperatorProps = {
icon?: IconType;
onShowPopup?: () => Promise<boolean>;
tooltip?: string;
popup?: { title: string; body?: JSX.Element };
};
export function StepSeperator(props: StepSeperatorProps) {
const [showPopup, setShowPopup] = useState<boolean>(false);
const theme = useTheme(
{ accent: getDefaultAccentColor(), theme: "dark" },
false
);
return (
<Flex
sx={{
height: 200,
width: 2,
bg: "bgSecondary",
justifyContent: "center",
alignItems: "center",
position: "relative"
}}
>
<Flex
sx={{
position: "absolute",
flexDirection: "column",
justifyContent: "center",
alignItems: "center"
}}
tabIndex={1}
>
{props.icon && (
<Flex
sx={{
bg: "background",
p: 2,
boxShadow: "0px 0px 10px 0px #00000011",
borderRadius: 50,
transition: "transform 100ms ease-out",
cursor: "pointer",
":hover": {
transform: "scale(1.1)"
}
}}
title={props.tooltip}
onClick={async () => {
if (showPopup) return setShowPopup(false);
if (!showPopup && props.onShowPopup)
setShowPopup(await props.onShowPopup());
}}
>
<props.icon size={20} />
</Flex>
)}
{showPopup && props.popup && (
<Flex
sx={{
position: "absolute",
top: 60,
p: 2,
width: 400
}}
>
<ThemeProvider theme={theme}>
<Flex
sx={{
bg: "background",
borderRadius: "default",
boxShadow: "0px 0px 10px 0px #00000011",
p: 2,
flexDirection: "column",
color: "icon"
}}
>
<Flex
sx={{ justifyContent: "space-between", alignItems: "center" }}
>
<Text variant="title">{props.popup.title}</Text>
<MdClose
style={{ cursor: "pointer" }}
onClick={() => setShowPopup(false)}
/>
</Flex>
{props.popup.body}
</Flex>
</ThemeProvider>
</Flex>
)}
</Flex>
</Flex>
);
}

26
apps/vericrypt/src/global.d.ts vendored Normal file
View File

@@ -0,0 +1,26 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* eslint-disable no-var */
import "vite/client";
import "vite-plugin-svgr/client";
declare global {
var APP_VERSION: string;
}

View File

@@ -0,0 +1,30 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import "./polyfills";
import React from "react";
import ReactDOM from "react-dom";
import App from "./app";
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
);

View File

@@ -0,0 +1,21 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { Buffer } from "buffer";
window.Buffer = Buffer;

19
apps/vericrypt/src/react-app-env.d.ts vendored Normal file
View File

@@ -0,0 +1,19 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

View File

@@ -0,0 +1,42 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import Platform from "platform";
const isMac = Platform.os?.toString().toLowerCase().includes("mac");
const combos = {
macos: {
chromium: { developerTools: ["Cmd", "Opt", "J"] },
firefox: { developerTools: ["Command", "Option", "K"] }
},
others: {
chromium: { developerTools: ["Control", "Shift", "J"] },
firefox: { developerTools: ["Control", "Shift", "K"] }
}
};
type KeyboardTypes = keyof typeof combos;
type Browsers = keyof (typeof combos)[KeyboardTypes];
type ComboIds = keyof (typeof combos)[KeyboardTypes][Browsers];
export function getCombo(browser: Browsers, id: ComboIds): string[] {
const keyboardType: KeyboardTypes = isMac ? "macos" : "others";
return combos[keyboardType][browser][id];
}

View File

@@ -0,0 +1,36 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
type Packages = "crypto" | "importer" | "enex";
type Apps = "vericrypt" | "importer";
export function getSourceUrl(path: string) {
const baseUrl = `https://github.com/streetwriters/notesnook/tree/master/apps/vericrypt`;
return `${baseUrl}/${path}`;
}
export function getPackageUrl(packageId: Packages) {
const baseUrl = `https://github.com/streetwriters/notesnook/tree/master/packages`;
return `${baseUrl}/${packageId}`;
}
export function getAppUrl(appId: Apps) {
const baseUrl = `https://github.com/streetwriters/notesnook/tree/master/apps`;
return `${baseUrl}/${appId}`;
}

View File

@@ -0,0 +1,20 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
export const appVersion = APP_VERSION;

View File

@@ -0,0 +1,11 @@
{
"extends": "../../tsconfig",
"compilerOptions": {
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"jsx": "react-jsx",
"maxNodeModuleJsDepth": 5,
"noEmit": true
},
"include": ["src"]
}

View File

@@ -0,0 +1,68 @@
/*
This file is part of the Notesnook project (https://notesnook.com/)
Copyright (C) 2023 Streetwriters (Private) Limited
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { defineConfig } from "vite";
import svgrPlugin from "vite-plugin-svgr";
import autoprefixer from "autoprefixer";
import { version } from "./package.json";
import envCompatible from "vite-plugin-env-compatible";
export default defineConfig({
envPrefix: "REACT_APP_",
build: {
outDir: "build",
minify: "esbuild",
cssMinify: true,
emptyOutDir: true,
sourcemap: false,
rollupOptions: {
output: {
assetFileNames: "assets/[name]-[hash:12][extname]",
chunkFileNames: "assets/[name]-[hash:12].js"
}
}
},
define: {
APP_VERSION: `"${version}"`
},
logLevel: process.env.NODE_ENV === "production" ? "warn" : "info",
resolve: {
dedupe: ["react", "react-dom", "@emotion/react"]
},
server: {
port: 3000
},
worker: {
format: "es"
},
css: {
postcss: {
plugins: [autoprefixer()]
}
},
plugins: [
envCompatible(),
svgrPlugin({
svgrOptions: {
icon: true
// ...svgr options (https://react-svgr.com/docs/options/)
}
})
]
});