Skip to content

Commit

Permalink
add encryption support
Browse files Browse the repository at this point in the history
  • Loading branch information
xyzshantaram committed Dec 18, 2021
1 parent 9e63ca2 commit aeea6ef
Show file tree
Hide file tree
Showing 8 changed files with 3,196 additions and 3,142 deletions.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"@tauri-apps/api": "^1.0.0-beta.8",
"@tauri-apps/cli": "^1.0.0-beta.10",
"@types/codemirror": "^5.60.4",
"@types/crypto-js": "^4.0.2",
"campfire.js": "^2.3.0",
"codemirror": "^5.63.1",
"esbuild": "^0.13.4",
Expand All @@ -15,8 +16,9 @@
"dependencies": {
"@types/dompurify": "^2.3.2",
"@types/marked": "^4.0.1",
"crypto-js": "^4.1.1",
"dompurify": "^2.3.4",
"macrolight": "^1.4.1"
},
"license": "MIT"
}
}
2 changes: 1 addition & 1 deletion src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rite"
version = "0.12.4"
version = "0.13.0"
description = "Your new distraction-free writing app."
authors = ["shantaram <[email protected]>"]
license = "MIT"
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"package": {
"productName": "rite",
"version": "0.12.4"
"version": "0.13.0"
},
"build": {
"distDir": "../static",
Expand Down
39 changes: 34 additions & 5 deletions static/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ import { dialog } from "@tauri-apps/api"
import { readTextFile } from "@tauri-apps/api/fs"
import { RiteEditor } from "./RiteEditor"
import { editorAlert, editorChoose, editorConfirm, editorPrompt, hidePrompt, toChoices } from "./prompt"
import { CommandHandler, getConfigPath, GH_REPO, GH_REPO_URL, groupByProp, isOlder, PromptChoice, RiteCommands, riteFetch, RiteFile } from "./utils"
import { AESDecrypt, AESEncrypt, CommandHandler, getConfigPath, GH_REPO, GH_REPO_URL, groupByProp, isOlder, PromptChoice, RiteCommands, riteFetch, RiteFile } from "./utils"
import { MODIFIABLE_SETTINGS, requestSetting, Setting } from "./config"
import cf from 'campfire.js'
import { open } from '@tauri-apps/api/shell'
import { http } from '@tauri-apps/api'
import { getPreviewHtml } from "./preview"

class UploadFormResult {
name: string;
revision: string;
contents: string | null;
contents: string;
public: boolean;
password: string;
}

class OpenFormResult {
Expand Down Expand Up @@ -116,6 +116,15 @@ const saveAs = async (editor: RiteEditor) => {
await editor.save(true);
}

/**
*
* @param editor A RiteEditor instance
* @param token The client token
* @param url URL of the Rite Cloud instance
* @param user username
* @param open Whether the user is opening a document or saving it.
* @returns
*/
const showCloudMenu = (editor: RiteEditor, token: string, url: string, user: string, open: boolean): Promise<UploadFormResult | OpenFormResult> => {
document.querySelector("#upload-menu")?.remove();

Expand Down Expand Up @@ -160,6 +169,8 @@ const showCloudMenu = (editor: RiteEditor, token: string, url: string, user: str
}
</div>
${!open ? `<div class='form-group'><label for='upload-password'>Password to encrypt this file with (Optional)</label><input type='password' id='upload-password'></div>` : ''}
<div id='outcome-group' class='form-group'>
<button type='button' id='upload-cancel'>Cancel</button>
<button id='upload-confirm'>Confirm</button>
Expand Down Expand Up @@ -222,11 +233,13 @@ const showCloudMenu = (editor: RiteEditor, token: string, url: string, user: str
else {
const publicCheckbox = form.querySelector("#upload-is-public")! as HTMLInputElement;
const revisionField = form.querySelector('#document-revision')! as HTMLInputElement;
const encrypted = form.querySelector('#upload-password') as HTMLInputElement;
resolve({
name: nameField.value,
revision: revisionField.value,
contents: editor.getContents(),
public: publicCheckbox.checked
public: publicCheckbox.checked,
password: encrypted.value
});
}
}
Expand All @@ -240,6 +253,10 @@ const saveToCloud = async (editor: RiteEditor) => {
return;
}

if (uploadDetails.password.trim() !== '') {
uploadDetails.contents = AESEncrypt(uploadDetails.contents, uploadDetails.password);
}

let url: string = editor.getConfigVar("cloud_url");
let doc = await riteFetch(`${url}/api/docs/upload`, "POST",
JSON.stringify({
Expand All @@ -249,6 +266,7 @@ const saveToCloud = async (editor: RiteEditor) => {
public: uploadDetails.public,
user: editor.getConfigVar("cloud_username"),
token: editor.getConfigVar("cloud_token"),
encrypted: !!(uploadDetails.password)
})
);
let ok = doc.ok;
Expand Down Expand Up @@ -284,9 +302,20 @@ const openFromCloud = async (editor: RiteEditor) => {
}));

let json = JSON.parse(doc.body);
let contents = json.contents;

if (doc.ok) {
editor.setContents(json.contents);
if (json.encrypted) {
const passphrase = await editorPrompt('This document is encrypted. Enter the password to decrypt it.', false);
try {
contents = AESDecrypt(json.contents, passphrase);
}
catch (e) {
await editorAlert(`Error decrypting contents: ${e}`);
return;
}
}
editor.setContents(contents);
editor.currentFile = null;
editor.updateFileName();
}
Expand Down
12 changes: 12 additions & 0 deletions static/src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { invoke, os } from '@tauri-apps/api';
import { editorAlert } from './prompt';
import { RiteEditor } from './RiteEditor';
import CryptoJS from 'crypto-js';

export type CommandHandler = (editor: RiteEditor) => void | Promise<void>;

Expand Down Expand Up @@ -169,4 +170,15 @@ export const groupByProp = (arr: Iterable<Record<string, any>>, prop: string) =>
}

return grouped;
}

export const AESDecrypt = (ciphertext: string, passphrase: string) => {
const bytes = CryptoJS.AES.decrypt(ciphertext, passphrase, {
format: CryptoJS.format.OpenSSL
});
return bytes.toString(CryptoJS.enc.Utf8);
};

export const AESEncrypt = (cleartext: string, passphrase: string) => {
return CryptoJS.AES.encrypt(cleartext, passphrase).toString(CryptoJS.format.OpenSSL);
}
4 changes: 2 additions & 2 deletions static/upload.css
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
margin-right: 2rem;
}

.form-group>select, .form-group>input[type='text'] {
.form-group>select, .form-group>input[type='text'], .form-group>input[type='password'] {
margin-left: auto;
width: 22ch !important;
border: none;
Expand Down Expand Up @@ -60,7 +60,7 @@
filter: brightness(1.2);
}

button, .form-group>input[type='text'], .form-group>input[type='checkbox'] {
button, .form-group>input[type='text'], .form-group>input[type='password'], .form-group>input[type='checkbox'] {
border: none;
background-color: var(--ui-elem-bg);
color: var(--ui-elem-fg);
Expand Down
Loading

0 comments on commit aeea6ef

Please sign in to comment.