vericrypt: initial commit
@@ -14,6 +14,7 @@ const SCOPES = [
|
||||
|
||||
"mobile",
|
||||
"web",
|
||||
"vericrypt",
|
||||
"desktop",
|
||||
"crypto",
|
||||
"editor",
|
||||
|
||||
23
apps/vericrypt/.gitignore
vendored
Normal 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
@@ -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
46
apps/vericrypt/package.json
Normal 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"
|
||||
]
|
||||
}
|
||||
}
|
||||
BIN
apps/vericrypt/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
apps/vericrypt/public/logo192.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
3
apps/vericrypt/public/robots.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
||||
71
apps/vericrypt/src/app.css
Normal 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
@@ -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'll want to verify it to make sure we
|
||||
didn'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;
|
||||
BIN
apps/vericrypt/src/assets/fonts/open-sans-v20-latin-600.woff
Normal file
BIN
apps/vericrypt/src/assets/fonts/open-sans-v20-latin-600.woff2
Normal file
BIN
apps/vericrypt/src/assets/fonts/open-sans-v20-latin-700.woff
Normal file
BIN
apps/vericrypt/src/assets/fonts/open-sans-v20-latin-700.woff2
Normal file
BIN
apps/vericrypt/src/assets/fonts/open-sans-v20-latin-italic.woff
Normal file
BIN
apps/vericrypt/src/assets/fonts/open-sans-v20-latin-italic.woff2
Normal file
BIN
apps/vericrypt/src/assets/fonts/open-sans-v20-latin-regular.woff
Normal file
1
apps/vericrypt/src/assets/images/map.svg
Normal file
|
After Width: | Height: | Size: 169 KiB |
|
After Width: | Height: | Size: 25 KiB |
BIN
apps/vericrypt/src/assets/screenshots/devtools_requests_copy.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 44 KiB |
BIN
apps/vericrypt/src/assets/screenshots/devtools_requests_ws.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 127 KiB |
BIN
apps/vericrypt/src/assets/screenshots/devtools_salt.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
apps/vericrypt/src/assets/screenshots/devtools_select_db.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 26 KiB |
61
apps/vericrypt/src/components/accordion.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
44
apps/vericrypt/src/components/code.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
184
apps/vericrypt/src/components/decrypted-result.tsx
Normal 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'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'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'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' 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>
|
||||
);
|
||||
}
|
||||
57
apps/vericrypt/src/components/errors-list.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
41
apps/vericrypt/src/components/footer.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
132
apps/vericrypt/src/components/hero.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
33
apps/vericrypt/src/components/key-combo.tsx
Normal 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 ? " + " : ""}
|
||||
</>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
93
apps/vericrypt/src/components/step-1.tsx
Normal 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'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'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 & 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'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'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>
|
||||
);
|
||||
}
|
||||
217
apps/vericrypt/src/components/step-2.tsx
Normal 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'll see an input with the placeholder
|
||||
"Start from key" 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'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'll see an input with the placeholder
|
||||
"Start from key" at the top. Type <Code text="user" /> in that
|
||||
input. If you don't see the 'user' 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'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'll be extracting your account's salt right from
|
||||
Notesnook's local database that lives in your web browser. So put
|
||||
on your seat belt and let'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>
|
||||
);
|
||||
}
|
||||
88
apps/vericrypt/src/components/step-3.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
397
apps/vericrypt/src/components/step-4.tsx
Normal 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'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 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 & 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 & 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 & 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) &{" "}
|
||||
{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;
|
||||
}
|
||||
41
apps/vericrypt/src/components/step-container.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
119
apps/vericrypt/src/components/step-seperator.tsx
Normal 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
@@ -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;
|
||||
}
|
||||
30
apps/vericrypt/src/index.tsx
Normal 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")
|
||||
);
|
||||
21
apps/vericrypt/src/polyfills.ts
Normal 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
@@ -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/>.
|
||||
*/
|
||||
|
||||
42
apps/vericrypt/src/utils/keycombos.ts
Normal 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];
|
||||
}
|
||||
36
apps/vericrypt/src/utils/links.ts
Normal 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}`;
|
||||
}
|
||||
20
apps/vericrypt/src/utils/version.ts
Normal 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;
|
||||
11
apps/vericrypt/tsconfig.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "../../tsconfig",
|
||||
"compilerOptions": {
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"jsx": "react-jsx",
|
||||
"maxNodeModuleJsDepth": 5,
|
||||
"noEmit": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
68
apps/vericrypt/vite.config.ts
Normal 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/)
|
||||
}
|
||||
})
|
||||
]
|
||||
});
|
||||