You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	Electron: Started integrating encryption
This commit is contained in:
		| @@ -353,7 +353,7 @@ class Application extends BaseApplication { | ||||
|  | ||||
| 			this.dispatch({ | ||||
| 				type: 'TAG_UPDATE_ALL', | ||||
| 				tags: tags, | ||||
| 				items: tags, | ||||
| 			}); | ||||
|  | ||||
| 			this.store().dispatch({ | ||||
|   | ||||
| @@ -5,6 +5,7 @@ const { FoldersScreenUtils } = require('lib/folders-screen-utils.js'); | ||||
| const { Setting } = require('lib/models/setting.js'); | ||||
| const { shim } = require('lib/shim.js'); | ||||
| const { BaseModel } = require('lib/base-model.js'); | ||||
| const MasterKey = require('lib/models/MasterKey'); | ||||
| const { _, setLocale } = require('lib/locale.js'); | ||||
| const os = require('os'); | ||||
| const fs = require('fs-extra'); | ||||
| @@ -354,7 +355,14 @@ class Application extends BaseApplication { | ||||
|  | ||||
| 		this.dispatch({ | ||||
| 			type: 'TAG_UPDATE_ALL', | ||||
| 			tags: tags, | ||||
| 			items: tags, | ||||
| 		}); | ||||
|  | ||||
| 		const masterKeys = await MasterKey.all(); | ||||
|  | ||||
| 		this.dispatch({ | ||||
| 			type: 'MASTERKEY_UPDATE_ALL', | ||||
| 			items: masterKeys, | ||||
| 		}); | ||||
|  | ||||
| 		this.store().dispatch({ | ||||
|   | ||||
| @@ -180,6 +180,8 @@ class SideBarComponent extends React.Component { | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		const itemTitle = folder.encryption_applied ? 'Encrypted 🔑' : folder.title; | ||||
|  | ||||
| 		return <a | ||||
| 			className="list-item" | ||||
| 			onDragOver={(event) => { onDragOver(event, folder) } } | ||||
| @@ -189,7 +191,7 @@ class SideBarComponent extends React.Component { | ||||
| 			data-type={BaseModel.TYPE_FOLDER} | ||||
| 			onContextMenu={(event) => this.itemContextMenu(event)} | ||||
| 			key={folder.id} | ||||
| 			style={style} onClick={() => {this.folderItem_click(folder)}}>{folder.title} | ||||
| 			style={style} onClick={() => {this.folderItem_click(folder)}}>{itemTitle} | ||||
| 		</a> | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -7,7 +7,7 @@ class FoldersScreenUtils { | ||||
|  | ||||
| 		this.dispatch({ | ||||
| 			type: 'FOLDER_UPDATE_ALL', | ||||
| 			folders: initialFolders, | ||||
| 			items: initialFolders, | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -272,11 +272,12 @@ class JoplinDatabase extends Database { | ||||
|  | ||||
| 			if (targetVersion == 9) { | ||||
| 				queries.push('CREATE TABLE master_keys (id TEXT PRIMARY KEY, created_time INT NOT NULL, updated_time INT NOT NULL, encryption_method INT NOT NULL, checksum TEXT NOT NULL, content TEXT NOT NULL);'); | ||||
| 				queries.push('ALTER TABLE notes ADD COLUMN encryption_cipher_text TEXT NOT NULL DEFAULT ""'); | ||||
| 				queries.push('ALTER TABLE folders ADD COLUMN encryption_cipher_text TEXT NOT NULL DEFAULT ""'); | ||||
| 				queries.push('ALTER TABLE tags ADD COLUMN encryption_cipher_text TEXT NOT NULL DEFAULT ""'); | ||||
| 				queries.push('ALTER TABLE note_tags ADD COLUMN encryption_cipher_text TEXT NOT NULL DEFAULT ""'); | ||||
| 				queries.push('ALTER TABLE resources ADD COLUMN encryption_cipher_text TEXT NOT NULL DEFAULT ""'); | ||||
| 				const tableNames = ['notes', 'folders', 'tags', 'note_tags', 'resources']; | ||||
| 				for (let i = 0; i < tableNames.length; i++) { | ||||
| 					const n = tableNames[i]; | ||||
| 					queries.push('ALTER TABLE ' + n + ' ADD COLUMN encryption_cipher_text TEXT NOT NULL DEFAULT ""'); | ||||
| 					queries.push('ALTER TABLE ' + n + ' ADD COLUMN encryption_applied INT NOT NULL DEFAULT 0'); | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			queries.push({ sql: 'UPDATE version SET version = ?', params: [targetVersion] }); | ||||
|   | ||||
| @@ -263,10 +263,6 @@ class BaseItem extends BaseModel { | ||||
| 		// List of keys that won't be encrypted - mostly foreign keys required to link items | ||||
| 		// with each others and timestamp required for synchronisation. | ||||
| 		const keepKeys = ['id', 'note_id', 'tag_id', 'parent_id', 'updated_time', 'type_']; | ||||
| 		 | ||||
| 		// const keepKeys = ['id', 'title', 'note_id', 'tag_id', 'parent_id', 'body', 'updated_time', 'type_']; | ||||
| 		// if ('title' in reducedItem) reducedItem.title = ''; | ||||
| 		// if ('body' in reducedItem) reducedItem.body = ''; | ||||
|  | ||||
| 		for (let n in reducedItem) { | ||||
| 			if (!reducedItem.hasOwnProperty(n)) continue; | ||||
| @@ -278,6 +274,7 @@ class BaseItem extends BaseModel { | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		reducedItem.encryption_applied = 1; | ||||
| 		reducedItem.encryption_cipher_text = cipherText; | ||||
|  | ||||
| 		return ItemClass.serialize(reducedItem) | ||||
| @@ -293,6 +290,7 @@ class BaseItem extends BaseModel { | ||||
| 		const plainItem = await ItemClass.unserialize(plainText); | ||||
| 		plainItem.updated_time = item.updated_time; | ||||
| 		plainItem.encryption_cipher_text = ''; | ||||
| 		plainItem.encryption_applied = 0; | ||||
| 		return ItemClass.save(plainItem, { autoTimestamp: false }); | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -157,7 +157,7 @@ class Folder extends BaseItem { | ||||
| 		return super.save(o, options).then((folder) => { | ||||
| 			this.dispatch({ | ||||
| 				type: 'FOLDER_UPDATE_ONE', | ||||
| 				folder: folder, | ||||
| 				item: folder, | ||||
| 			}); | ||||
| 			return folder; | ||||
| 		}); | ||||
|   | ||||
| @@ -70,7 +70,7 @@ class Tag extends BaseItem { | ||||
|  | ||||
| 		this.dispatch({ | ||||
| 			type: 'TAG_UPDATE_ONE', | ||||
| 			tag: await Tag.load(tagId), | ||||
| 			item: await Tag.load(tagId), | ||||
| 		}); | ||||
|  | ||||
| 		return output; | ||||
| @@ -84,7 +84,7 @@ class Tag extends BaseItem { | ||||
|  | ||||
| 		this.dispatch({ | ||||
| 			type: 'TAG_UPDATE_ONE', | ||||
| 			tag: await Tag.load(tagId), | ||||
| 			item: await Tag.load(tagId), | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| @@ -132,7 +132,7 @@ class Tag extends BaseItem { | ||||
| 		return super.save(o, options).then((tag) => { | ||||
| 			this.dispatch({ | ||||
| 				type: 'TAG_UPDATE_ONE', | ||||
| 				tag: tag, | ||||
| 				item: tag, | ||||
| 			}); | ||||
| 			return tag; | ||||
| 		}); | ||||
|   | ||||
| @@ -8,6 +8,7 @@ const defaultState = { | ||||
| 	notesParentType: null, | ||||
| 	folders: [], | ||||
| 	tags: [], | ||||
| 	masterKeys: [], | ||||
| 	searches: [], | ||||
| 	selectedNoteIds: [], | ||||
| 	selectedFolderId: null, | ||||
| @@ -29,6 +30,20 @@ const defaultState = { | ||||
| 	hasDisabledSyncItems: false, | ||||
| }; | ||||
|  | ||||
| function arrayHasEncryptedItems(array) { | ||||
| 	for (let i = 0; i < array.length; i++) { | ||||
| 		if (!!array[i].encryption_applied) return true; | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| function stateHasEncryptedItems(state) { | ||||
| 	if (arrayHasEncryptedItems(state.notes)) return true; | ||||
| 	if (arrayHasEncryptedItems(state.folders)) return true; | ||||
| 	if (arrayHasEncryptedItems(state.tags)) return true; | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| // When deleting a note, tag or folder | ||||
| function handleItemDelete(state, action) { | ||||
| 	let newState = Object.assign({}, state); | ||||
| @@ -72,9 +87,16 @@ function handleItemDelete(state, action) { | ||||
| 	return newState; | ||||
| } | ||||
|  | ||||
| function updateOneTagOrFolder(state, action) { | ||||
| 	let newItems = action.type === 'TAG_UPDATE_ONE' ? state.tags.splice(0) : state.folders.splice(0); | ||||
| 	let item = action.type === 'TAG_UPDATE_ONE' ? action.tag : action.folder; | ||||
| function updateOneItem(state, action) { | ||||
| 	// let newItems = action.type === 'TAG_UPDATE_ONE' ? state.tags.splice(0) : state.folders.splice(0); | ||||
| 	// let item = action.type === 'TAG_UPDATE_ONE' ? action.tag : action.folder; | ||||
| 	let itemsKey = null; | ||||
| 	if (action.type === 'TAG_UPDATE_ONE') itemsKey = 'tags'; | ||||
| 	if (action.type === 'FOLDER_UPDATE_ONE') itemsKey = 'folders'; | ||||
| 	if (action.type === 'MASTERKEY_UPDATE_ONE') itemsKey = 'masterKeys'; | ||||
|  | ||||
| 	let newItems = state[itemsKey].splice(0); | ||||
| 	let item = action.item; | ||||
|  | ||||
| 	var found = false; | ||||
| 	for (let i = 0; i < newItems.length; i++) { | ||||
| @@ -90,11 +112,13 @@ function updateOneTagOrFolder(state, action) { | ||||
|  | ||||
| 	let newState = Object.assign({}, state); | ||||
|  | ||||
| 	if (action.type === 'TAG_UPDATE_ONE') { | ||||
| 		newState.tags = newItems; | ||||
| 	} else { | ||||
| 		newState.folders = newItems; | ||||
| 	} | ||||
| 	newState[itemsKey] = newItems; | ||||
|  | ||||
| 	// if (action.type === 'TAG_UPDATE_ONE') { | ||||
| 	// 	newState.tags = newItems; | ||||
| 	// } else { | ||||
| 	// 	newState.folders = newItems; | ||||
| 	// } | ||||
|  | ||||
| 	return newState; | ||||
| } | ||||
| @@ -307,14 +331,14 @@ const reducer = (state = defaultState, action) => { | ||||
| 			case 'FOLDER_UPDATE_ALL': | ||||
|  | ||||
| 				newState = Object.assign({}, state); | ||||
| 				newState.folders = action.folders; | ||||
| 				newState.folders = action.items; | ||||
| 				break; | ||||
|  | ||||
| 			case 'TAG_UPDATE_ALL': | ||||
|  | ||||
| 				newState = Object.assign({}, state); | ||||
| 				newState.tags = action.tags; | ||||
| 				break;				 | ||||
| 				newState.tags = action.items; | ||||
| 				break; | ||||
|  | ||||
| 			case 'TAG_SELECT': | ||||
|  | ||||
| @@ -328,13 +352,10 @@ const reducer = (state = defaultState, action) => { | ||||
| 				break; | ||||
|  | ||||
| 			case 'TAG_UPDATE_ONE': | ||||
|  | ||||
| 				newState = updateOneTagOrFolder(state, action); | ||||
| 				break; | ||||
|  | ||||
| 			case 'FOLDER_UPDATE_ONE': | ||||
| 			case 'MASTERKEY_UPDATE_ONE': | ||||
|  | ||||
| 				newState = updateOneTagOrFolder(state, action); | ||||
| 				newState = updateOneItem(state, action); | ||||
| 				break; | ||||
|  | ||||
| 			case 'FOLDER_DELETE': | ||||
| @@ -342,6 +363,12 @@ const reducer = (state = defaultState, action) => { | ||||
| 				newState = handleItemDelete(state, action); | ||||
| 				break; | ||||
|  | ||||
| 			case 'MASTERKEY_UPDATE_ALL': | ||||
|  | ||||
| 				newState = Object.assign({}, state); | ||||
| 				newState.masterKeys = action.items; | ||||
| 				break; | ||||
|  | ||||
| 			case 'SYNC_STARTED': | ||||
|  | ||||
| 				newState = Object.assign({}, state); | ||||
| @@ -408,6 +435,11 @@ const reducer = (state = defaultState, action) => { | ||||
| 		throw error; | ||||
| 	} | ||||
|  | ||||
| 	if (action.type.indexOf('NOTE_UPDATE') === 0 || action.type.indexOf('FOLDER_UPDATE') === 0 || action.type.indexOf('TAG_UPDATE') === 0) { | ||||
| 		newState = Object.assign({}, newState); | ||||
| 		newState.hasEncryptedItems = stateHasEncryptedItems(newState); | ||||
| 	} | ||||
|  | ||||
| 	return newState; | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										15
									
								
								ReactNativeClient/lib/services/DecryptionWorker.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								ReactNativeClient/lib/services/DecryptionWorker.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| class DecryptionWorker { | ||||
|  | ||||
| 	constructor() { | ||||
| 		this.state_ = 'idle'; | ||||
| 	} | ||||
|  | ||||
| 	start() { | ||||
| 		if (this.state_ !== 'idle') return; | ||||
|  | ||||
| 		this.state_ = 'started'; | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| module.exports = DecryptionWorker; | ||||
| @@ -349,7 +349,7 @@ async function initialize(dispatch) { | ||||
|  | ||||
| 		dispatch({ | ||||
| 			type: 'TAG_UPDATE_ALL', | ||||
| 			tags: tags, | ||||
| 			items: tags, | ||||
| 		}); | ||||
|  | ||||
| 		let folderId = Setting.value('activeFolderId'); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user