vericrypt: initial commit
@@ -14,6 +14,7 @@ const SCOPES = [
|
|||||||
|
|
||||||
"mobile",
|
"mobile",
|
||||||
"web",
|
"web",
|
||||||
|
"vericrypt",
|
||||||
"desktop",
|
"desktop",
|
||||||
"crypto",
|
"crypto",
|
||||||
"editor",
|
"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/)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
});
|
||||||