1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-21 09:38:01 +02:00

Chore: Convert E2EE related files to TypeScript

This commit is contained in:
Laurent Cozic 2021-08-07 12:22:37 +01:00
parent 3fb77c4e37
commit c3f10d31cb
21 changed files with 237 additions and 158 deletions

View File

@ -69,6 +69,9 @@ readme/
packages/app-cli/app/LinkSelector.d.ts
packages/app-cli/app/LinkSelector.js
packages/app-cli/app/LinkSelector.js.map
packages/app-cli/app/command-e2ee.d.ts
packages/app-cli/app/command-e2ee.js
packages/app-cli/app/command-e2ee.js.map
packages/app-cli/app/command-settingschema.d.ts
packages/app-cli/app/command-settingschema.js
packages/app-cli/app/command-settingschema.js.map
@ -159,6 +162,9 @@ packages/app-desktop/commands/toggleSafeMode.js.map
packages/app-desktop/gui/Button/Button.d.ts
packages/app-desktop/gui/Button/Button.js
packages/app-desktop/gui/Button/Button.js.map
packages/app-desktop/gui/ClipperConfigScreen.d.ts
packages/app-desktop/gui/ClipperConfigScreen.js
packages/app-desktop/gui/ClipperConfigScreen.js.map
packages/app-desktop/gui/ConfigScreen/ButtonBar.d.ts
packages/app-desktop/gui/ConfigScreen/ButtonBar.js
packages/app-desktop/gui/ConfigScreen/ButtonBar.js.map
@ -195,6 +201,9 @@ packages/app-desktop/gui/DialogTitle.js.map
packages/app-desktop/gui/DropboxLoginScreen.d.ts
packages/app-desktop/gui/DropboxLoginScreen.js
packages/app-desktop/gui/DropboxLoginScreen.js.map
packages/app-desktop/gui/EncryptionConfigScreen.d.ts
packages/app-desktop/gui/EncryptionConfigScreen.js
packages/app-desktop/gui/EncryptionConfigScreen.js.map
packages/app-desktop/gui/ErrorBoundary.d.ts
packages/app-desktop/gui/ErrorBoundary.js
packages/app-desktop/gui/ErrorBoundary.js.map
@ -720,6 +729,9 @@ packages/app-mobile/components/screens/Note.js.map
packages/app-mobile/components/screens/UpgradeSyncTargetScreen.d.ts
packages/app-mobile/components/screens/UpgradeSyncTargetScreen.js
packages/app-mobile/components/screens/UpgradeSyncTargetScreen.js.map
packages/app-mobile/components/screens/encryption-config.d.ts
packages/app-mobile/components/screens/encryption-config.js
packages/app-mobile/components/screens/encryption-config.js.map
packages/app-mobile/root.d.ts
packages/app-mobile/root.js
packages/app-mobile/root.js.map
@ -876,6 +888,9 @@ packages/lib/commands/historyForward.js.map
packages/lib/commands/synchronize.d.ts
packages/lib/commands/synchronize.js
packages/lib/commands/synchronize.js.map
packages/lib/components/shared/encryption-config-shared.d.ts
packages/lib/components/shared/encryption-config-shared.js
packages/lib/components/shared/encryption-config-shared.js.map
packages/lib/database.d.ts
packages/lib/database.js
packages/lib/database.js.map
@ -1062,6 +1077,9 @@ packages/lib/services/DecryptionWorker.js.map
packages/lib/services/EncryptionService.d.ts
packages/lib/services/EncryptionService.js
packages/lib/services/EncryptionService.js.map
packages/lib/services/EncryptionService.test.d.ts
packages/lib/services/EncryptionService.test.js
packages/lib/services/EncryptionService.test.js.map
packages/lib/services/ExternalEditWatcher.d.ts
packages/lib/services/ExternalEditWatcher.js
packages/lib/services/ExternalEditWatcher.js.map
@ -1500,6 +1518,9 @@ packages/lib/services/synchronizer/utils/types.js.map
packages/lib/shim.d.ts
packages/lib/shim.js
packages/lib/shim.js.map
packages/lib/testing/syncTargetUtils.d.ts
packages/lib/testing/syncTargetUtils.js
packages/lib/testing/syncTargetUtils.js.map
packages/lib/testing/test-utils-synchronizer.d.ts
packages/lib/testing/test-utils-synchronizer.js
packages/lib/testing/test-utils-synchronizer.js.map

21
.gitignore vendored
View File

@ -54,6 +54,9 @@ lerna-debug.log
packages/app-cli/app/LinkSelector.d.ts
packages/app-cli/app/LinkSelector.js
packages/app-cli/app/LinkSelector.js.map
packages/app-cli/app/command-e2ee.d.ts
packages/app-cli/app/command-e2ee.js
packages/app-cli/app/command-e2ee.js.map
packages/app-cli/app/command-settingschema.d.ts
packages/app-cli/app/command-settingschema.js
packages/app-cli/app/command-settingschema.js.map
@ -144,6 +147,9 @@ packages/app-desktop/commands/toggleSafeMode.js.map
packages/app-desktop/gui/Button/Button.d.ts
packages/app-desktop/gui/Button/Button.js
packages/app-desktop/gui/Button/Button.js.map
packages/app-desktop/gui/ClipperConfigScreen.d.ts
packages/app-desktop/gui/ClipperConfigScreen.js
packages/app-desktop/gui/ClipperConfigScreen.js.map
packages/app-desktop/gui/ConfigScreen/ButtonBar.d.ts
packages/app-desktop/gui/ConfigScreen/ButtonBar.js
packages/app-desktop/gui/ConfigScreen/ButtonBar.js.map
@ -180,6 +186,9 @@ packages/app-desktop/gui/DialogTitle.js.map
packages/app-desktop/gui/DropboxLoginScreen.d.ts
packages/app-desktop/gui/DropboxLoginScreen.js
packages/app-desktop/gui/DropboxLoginScreen.js.map
packages/app-desktop/gui/EncryptionConfigScreen.d.ts
packages/app-desktop/gui/EncryptionConfigScreen.js
packages/app-desktop/gui/EncryptionConfigScreen.js.map
packages/app-desktop/gui/ErrorBoundary.d.ts
packages/app-desktop/gui/ErrorBoundary.js
packages/app-desktop/gui/ErrorBoundary.js.map
@ -705,6 +714,9 @@ packages/app-mobile/components/screens/Note.js.map
packages/app-mobile/components/screens/UpgradeSyncTargetScreen.d.ts
packages/app-mobile/components/screens/UpgradeSyncTargetScreen.js
packages/app-mobile/components/screens/UpgradeSyncTargetScreen.js.map
packages/app-mobile/components/screens/encryption-config.d.ts
packages/app-mobile/components/screens/encryption-config.js
packages/app-mobile/components/screens/encryption-config.js.map
packages/app-mobile/root.d.ts
packages/app-mobile/root.js
packages/app-mobile/root.js.map
@ -861,6 +873,9 @@ packages/lib/commands/historyForward.js.map
packages/lib/commands/synchronize.d.ts
packages/lib/commands/synchronize.js
packages/lib/commands/synchronize.js.map
packages/lib/components/shared/encryption-config-shared.d.ts
packages/lib/components/shared/encryption-config-shared.js
packages/lib/components/shared/encryption-config-shared.js.map
packages/lib/database.d.ts
packages/lib/database.js
packages/lib/database.js.map
@ -1047,6 +1062,9 @@ packages/lib/services/DecryptionWorker.js.map
packages/lib/services/EncryptionService.d.ts
packages/lib/services/EncryptionService.js
packages/lib/services/EncryptionService.js.map
packages/lib/services/EncryptionService.test.d.ts
packages/lib/services/EncryptionService.test.js
packages/lib/services/EncryptionService.test.js.map
packages/lib/services/ExternalEditWatcher.d.ts
packages/lib/services/ExternalEditWatcher.js
packages/lib/services/ExternalEditWatcher.js.map
@ -1485,6 +1503,9 @@ packages/lib/services/synchronizer/utils/types.js.map
packages/lib/shim.d.ts
packages/lib/shim.js
packages/lib/shim.js.map
packages/lib/testing/syncTargetUtils.d.ts
packages/lib/testing/syncTargetUtils.js
packages/lib/testing/syncTargetUtils.js.map
packages/lib/testing/test-utils-synchronizer.d.ts
packages/lib/testing/test-utils-synchronizer.js
packages/lib/testing/test-utils-synchronizer.js.map

View File

@ -1,11 +1,11 @@
const { BaseCommand } = require('./base-command.js');
const { _ } = require('@joplin/lib/locale');
const EncryptionService = require('@joplin/lib/services/EncryptionService').default;
const DecryptionWorker = require('@joplin/lib/services/DecryptionWorker').default;
const BaseItem = require('@joplin/lib/models/BaseItem').default;
const Setting = require('@joplin/lib/models/Setting').default;
const shim = require('@joplin/lib/shim').default;
const pathUtils = require('@joplin/lib/path-utils');
import { _ } from '@joplin/lib/locale';
import EncryptionService from '@joplin/lib/services/EncryptionService';
import DecryptionWorker from '@joplin/lib/services/DecryptionWorker';
import BaseItem from '@joplin/lib/models/BaseItem';
import Setting from '@joplin/lib/models/Setting';
import shim from '@joplin/lib/shim';
import * as pathUtils from '@joplin/lib/path-utils';
const imageType = require('image-type');
const readChunk = require('read-chunk');
@ -28,10 +28,10 @@ class Command extends BaseCommand {
];
}
async action(args) {
async action(args: any) {
const options = args.options;
const askForMasterKey = async error => {
const askForMasterKey = async (error: any) => {
const masterKeyId = error.masterKeyId;
const password = await this.prompt(_('Enter master password:'), { type: 'string', secure: true });
if (!password) {
@ -155,9 +155,9 @@ class Command extends BaseCommand {
const targetPath = args.path;
if (!targetPath) throw new Error('Please specify the sync target path.');
const dirPaths = function(targetPath) {
const paths = [];
fs.readdirSync(targetPath).forEach(path => {
const dirPaths = function(targetPath: string) {
const paths: string[] = [];
fs.readdirSync(targetPath).forEach((path: string) => {
paths.push(path);
});
return paths;

View File

@ -1,4 +1,4 @@
const {main} = require('@joplin/lib/testing/syncTargetUtils');
const { main } = require('@joplin/lib/testing/syncTargetUtils');
const syncTargetType = process.argv.length <= 2 ? 'normal' : process.argv[2];

View File

@ -0,0 +1,4 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

View File

@ -0,0 +1,4 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

View File

@ -0,0 +1,4 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

View File

@ -0,0 +1,4 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

View File

@ -1,13 +1,14 @@
const React = require('react');
const { connect } = require('react-redux');
const bridge = require('electron').remote.require('./bridge').default;
const { themeStyle } = require('@joplin/lib/theme');
const { _ } = require('@joplin/lib/locale');
const ClipperServer = require('@joplin/lib/ClipperServer').default;
const Setting = require('@joplin/lib/models/Setting').default;
const { clipboard } = require('electron');
const ExtensionBadge = require('./ExtensionBadge.min');
const EncryptionService = require('@joplin/lib/services/EncryptionService').default;
import bridge from '../services/bridge';
import { themeStyle } from '@joplin/lib/theme';
import { _ } from '@joplin/lib/locale';
import ClipperServer from '@joplin/lib/ClipperServer';
import Setting from '@joplin/lib/models/Setting';
import EncryptionService from '@joplin/lib/services/EncryptionService';
import { AppState } from '../app';
class ClipperConfigScreenComponent extends React.Component {
constructor() {
@ -18,12 +19,12 @@ class ClipperConfigScreenComponent extends React.Component {
disableClipperServer_click() {
Setting.setValue('clipperServer.autoStart', false);
ClipperServer.instance().stop();
void ClipperServer.instance().stop();
}
enableClipperServer_click() {
Setting.setValue('clipperServer.autoStart', true);
ClipperServer.instance().start();
void ClipperServer.instance().start();
}
chromeButton_click() {
@ -165,7 +166,7 @@ class ClipperConfigScreenComponent extends React.Component {
}
}
const mapStateToProps = state => {
const mapStateToProps = (state: AppState) => {
return {
themeId: state.settings.theme,
clipperServer: state.clipperServer,
@ -176,4 +177,4 @@ const mapStateToProps = state => {
const ClipperConfigScreen = connect(mapStateToProps)(ClipperConfigScreenComponent);
module.exports = { ClipperConfigScreen };
export default ClipperConfigScreen;

View File

@ -6,14 +6,14 @@ import { _ } from '@joplin/lib/locale';
import bridge from '../../services/bridge';
import Setting, { AppType, SyncStartupOperation } from '@joplin/lib/models/Setting';
import control_PluginsStates from './controls/plugins/PluginsStates';
import EncryptionConfigScreen from '../EncryptionConfigScreen';
const { connect } = require('react-redux');
const { themeStyle } = require('@joplin/lib/theme');
const pathUtils = require('@joplin/lib/path-utils');
const SyncTargetRegistry = require('@joplin/lib/SyncTargetRegistry');
const shared = require('@joplin/lib/components/shared/config-shared.js');
const { EncryptionConfigScreen } = require('../EncryptionConfigScreen.min');
const { ClipperConfigScreen } = require('../ClipperConfigScreen.min');
import ClipperConfigScreen from '../ClipperConfigScreen';
const { KeymapConfigScreen } = require('../KeymapConfig/KeymapConfigScreen');
const settingKeyToControl: any = {

View File

@ -1,17 +1,23 @@
const React = require('react');
const { connect } = require('react-redux');
const Setting = require('@joplin/lib/models/Setting').default;
const EncryptionService = require('@joplin/lib/services/EncryptionService').default;
const { themeStyle } = require('@joplin/lib/theme');
const { _ } = require('@joplin/lib/locale');
const time = require('@joplin/lib/time').default;
const shim = require('@joplin/lib/shim').default;
const dialogs = require('./dialogs').default;
const shared = require('@joplin/lib/components/shared/encryption-config-shared.js');
const bridge = require('electron').remote.require('./bridge').default;
import Setting from '@joplin/lib/models/Setting';
import EncryptionService from '@joplin/lib/services/EncryptionService';
import { themeStyle } from '@joplin/lib/theme';
import { _ } from '@joplin/lib/locale';
import time from '@joplin/lib/time';
import { State } from '@joplin/lib/reducer';
import shim from '@joplin/lib/shim';
import dialogs from './dialogs';
import bridge from '../services/bridge';
import shared from '@joplin/lib/components/shared/encryption-config-shared';
import { MasterKeyEntity } from '../../lib/services/database/types';
class EncryptionConfigScreenComponent extends React.Component {
constructor(props) {
interface Props {
}
class EncryptionConfigScreenComponent extends React.Component<Props> {
constructor(props: Props) {
super(props);
shared.constructor(this, props);
@ -27,7 +33,7 @@ class EncryptionConfigScreenComponent extends React.Component {
shared.componentDidMount(this);
}
componentDidUpdate(prevProps) {
componentDidUpdate(prevProps: Props) {
shared.componentDidUpdate(this, prevProps);
}
@ -35,7 +41,7 @@ class EncryptionConfigScreenComponent extends React.Component {
return shared.checkPasswords(this);
}
renderMasterKey(mk) {
renderMasterKey(mk: MasterKeyEntity) {
const theme = themeStyle(this.props.themeId);
const passwordStyle = {
@ -49,7 +55,7 @@ class EncryptionConfigScreenComponent extends React.Component {
return shared.onSavePasswordClick(this, mk);
};
const onPasswordChange = event => {
const onPasswordChange = (event: any) => {
return shared.onPasswordChange(this, mk, event.target.value);
};
@ -188,7 +194,7 @@ class EncryptionConfigScreenComponent extends React.Component {
<button
style={theme.buttonStyle}
onClick={() => {
onToggleButtonClick();
void onToggleButtonClick();
}}
>
{this.props.encryptionEnabled ? _('Disable encryption') : _('Enable encryption')}
@ -288,7 +294,7 @@ class EncryptionConfigScreenComponent extends React.Component {
}
}
const mapStateToProps = state => {
const mapStateToProps = (state: State) => {
return {
themeId: state.settings.theme,
masterKeys: state.masterKeys,
@ -302,4 +308,4 @@ const mapStateToProps = state => {
const EncryptionConfigScreen = connect(mapStateToProps)(EncryptionConfigScreenComponent);
module.exports = { EncryptionConfigScreen };
export default EncryptionConfigScreen;

View File

@ -1,23 +1,28 @@
const React = require('react');
const { TextInput, TouchableOpacity, Linking, View, StyleSheet, Text, Button, ScrollView } = require('react-native');
const EncryptionService = require('@joplin/lib/services/EncryptionService').default;
const { connect } = require('react-redux');
const { ScreenHeader } = require('../screen-header.js');
const { _ } = require('@joplin/lib/locale');
const { BaseScreenComponent } = require('../base-screen.js');
const { themeStyle } = require('../global-style.js');
const time = require('@joplin/lib/time').default;
const shared = require('@joplin/lib/components/shared/encryption-config-shared.js');
const { dialogs } = require('../../utils/dialogs.js');
const DialogBox = require('react-native-dialogbox').default;
const { dialogs } = require('../../utils/dialogs.js');
import EncryptionService from '@joplin/lib/services/EncryptionService';
import { _ } from '@joplin/lib/locale';
import time from '@joplin/lib/time';
import shared from '@joplin/lib/components/shared/encryption-config-shared';
import { MasterKeyEntity } from '../../../lib/services/database/types';
import { State } from '@joplin/lib/reducer';
class EncryptionConfigScreenComponent extends BaseScreenComponent {
static navigationOptions() {
interface Props {
}
class EncryptionConfigScreenComponent extends BaseScreenComponent<Props> {
static navigationOptions(): any {
return { header: null };
}
constructor(props) {
constructor(props: Props) {
super(props);
this.state = {
@ -35,7 +40,7 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
this.isMounted_ = false;
}
initState(props) {
initState(props: Props) {
return shared.initState(this, props);
}
@ -48,7 +53,7 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
shared.componentDidMount(this);
}
componentDidUpdate(prevProps) {
componentDidUpdate(prevProps: Props) {
shared.componentDidUpdate(this, prevProps);
}
@ -96,21 +101,21 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
return this.styles_[themeId];
}
renderMasterKey(num, mk) {
renderMasterKey(_num: number, mk: MasterKeyEntity) {
const theme = themeStyle(this.props.themeId);
const onSaveClick = () => {
return shared.onSavePasswordClick(this, mk);
};
const onPasswordChange = text => {
const onPasswordChange = (text: string) => {
return shared.onPasswordChange(this, mk, text);
};
const password = this.state.passwords[mk.id] ? this.state.passwords[mk.id] : '';
const passwordOk = this.state.passwordChecks[mk.id] === true ? '✔' : '❌';
const inputStyle = { flex: 1, marginRight: 10, color: theme.color };
const inputStyle: any = { flex: 1, marginRight: 10, color: theme.color };
inputStyle.borderBottomWidth = 1;
inputStyle.borderBottomColor = theme.dividerColor;
@ -120,7 +125,7 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
<Text style={this.styles().normalText}>{_('Created: %s', time.formatMsToLocal(mk.created_time))}</Text>
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<Text style={{ flex: 0, fontSize: theme.fontSize, marginRight: 10, color: theme.color }}>{_('Password:')}</Text>
<TextInput selectionColor={theme.textSelectionColor} keyboardAppearance={theme.keyboardAppearance} secureTextEntry={true} value={password} onChangeText={text => onPasswordChange(text)} style={inputStyle}></TextInput>
<TextInput selectionColor={theme.textSelectionColor} keyboardAppearance={theme.keyboardAppearance} secureTextEntry={true} value={password} onChangeText={(text: string) => onPasswordChange(text)} style={inputStyle}></TextInput>
<Text style={{ fontSize: theme.fontSize, marginRight: 10, color: theme.color }}>{passwordOk}</Text>
<Button title={_('Save')} onPress={() => onSaveClick()}></Button>
</View>
@ -155,7 +160,7 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
style={this.styles().normalTextInput}
secureTextEntry={true}
value={this.state.passwordPromptAnswer}
onChangeText={text => {
onChangeText={(text: string) => {
this.setState({ passwordPromptAnswer: text });
}}
></TextInput>
@ -167,7 +172,7 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
style={this.styles().normalTextInput}
secureTextEntry={true}
value={this.state.passwordPromptConfirmAnswer}
onChangeText={text => {
onChangeText={(text: string) => {
this.setState({ passwordPromptConfirmAnswer: text });
}}
></TextInput>
@ -176,7 +181,7 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
<Button
title={_('Enable')}
onPress={() => {
onEnableClick();
void onEnableClick();
}}
></Button>
</View>
@ -286,7 +291,7 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
<View style={{ flex: 1, height: 20 }}></View>
</ScrollView>
<DialogBox
ref={dialogbox => {
ref={(dialogbox: any) => {
this.dialogbox = dialogbox;
}}
/>
@ -295,7 +300,7 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
}
}
const EncryptionConfigScreen = connect(state => {
const EncryptionConfigScreen = connect((state: State) => {
return {
themeId: state.settings.theme,
masterKeys: state.masterKeys,
@ -306,4 +311,4 @@ const EncryptionConfigScreen = connect(state => {
};
})(EncryptionConfigScreenComponent);
module.exports = { EncryptionConfigScreen };
export default EncryptionConfigScreen;

View File

@ -63,7 +63,7 @@ const { LogScreen } = require('./components/screens/log.js');
const { StatusScreen } = require('./components/screens/status.js');
const { SearchScreen } = require('./components/screens/search.js');
const { OneDriveLoginScreen } = require('./components/screens/onedrive-login.js');
const { EncryptionConfigScreen } = require('./components/screens/encryption-config.js');
import EncryptionConfigScreen from './components/screens/encryption-config';
const { DropboxLoginScreen } = require('./components/screens/dropbox-login.js');
const { MenuContext } = require('react-native-popup-menu');
const { SideMenu } = require('./components/side-menu.js');

View File

@ -21,9 +21,12 @@ import ShareService from './services/share/ShareService';
import TaskQueue from './TaskQueue';
import ItemUploader from './services/synchronizer/ItemUploader';
import { FileApi } from './file-api';
import JoplinDatabase from './JoplinDatabase';
const { sprintf } = require('sprintf-js');
const { Dirnames } = require('./services/synchronizer/utils/types');
const logger = Logger.create('Synchronizer');
interface RemoteItem {
id: string;
path?: string;
@ -62,7 +65,7 @@ export default class Synchronizer {
public static verboseMode: boolean = true;
private db_: any;
private db_: JoplinDatabase;
private api_: FileApi;
private appType_: string;
private logger_: Logger = new Logger();
@ -87,7 +90,7 @@ export default class Synchronizer {
public dispatch: Function;
public constructor(db: any, api: FileApi, appType: string) {
public constructor(db: JoplinDatabase, api: FileApi, appType: string) {
this.db_ = db;
this.api_ = api;
this.appType_ = appType;
@ -214,9 +217,9 @@ export default class Synchronizer {
}
if (Synchronizer.verboseMode) {
this.logger().info(line.join(': '));
logger.info(line.join(': '));
} else {
this.logger().debug(line.join(': '));
logger.debug(line.join(': '));
}
if (!this.progressReport_[action]) this.progressReport_[action] = 0;
@ -234,7 +237,7 @@ export default class Synchronizer {
}
async logSyncSummary(report: any) {
this.logger().info('Operations completed: ');
logger.info('Operations completed: ');
for (const n in report) {
if (!report.hasOwnProperty(n)) continue;
if (n == 'errors') continue;
@ -243,20 +246,20 @@ export default class Synchronizer {
if (n == 'state') continue;
if (n == 'startTime') continue;
if (n == 'completedTime') continue;
this.logger().info(`${n}: ${report[n] ? report[n] : '-'}`);
logger.info(`${n}: ${report[n] ? report[n] : '-'}`);
}
const folderCount = await Folder.count();
const noteCount = await Note.count();
const resourceCount = await Resource.count();
this.logger().info(`Total folders: ${folderCount}`);
this.logger().info(`Total notes: ${noteCount}`);
this.logger().info(`Total resources: ${resourceCount}`);
logger.info(`Total folders: ${folderCount}`);
logger.info(`Total notes: ${noteCount}`);
logger.info(`Total resources: ${resourceCount}`);
if (Synchronizer.reportHasErrors(report)) {
this.logger().warn('There was some errors:');
logger.warn('There was some errors:');
for (let i = 0; i < report.errors.length; i++) {
const e = report.errors[i];
this.logger().warn(e);
logger.warn(e);
}
}
}
@ -291,8 +294,8 @@ export default class Synchronizer {
for (const r of lastRequests) {
const timestamp = time.unixMsToLocalHms(r.timestamp);
this.logger().info(`Req ${timestamp}: ${r.request}`);
this.logger().info(`Res ${timestamp}: ${r.response}`);
logger.info(`Req ${timestamp}: ${r.request}`);
logger.info(`Res ${timestamp}: ${r.response}`);
}
}
@ -394,11 +397,11 @@ export default class Synchronizer {
// plain text.
try {
if (this.resourceService()) {
this.logger().info('Indexing resources...');
logger.info('Indexing resources...');
await this.resourceService().indexNoteResources();
}
} catch (error) {
this.logger().error('Error indexing resources:', error);
logger.error('Error indexing resources:', error);
}
// Before synchronising make sure all share_id properties are set
@ -417,10 +420,10 @@ export default class Synchronizer {
try {
const syncTargetInfo = await this.migrationHandler().checkCanSync();
this.logger().info('Sync target info:', syncTargetInfo);
logger.info('Sync target info:', syncTargetInfo);
if (!syncTargetInfo.version) {
this.logger().info('Sync target is new - setting it up...');
logger.info('Sync target is new - setting it up...');
await this.migrationHandler().upgrade(Setting.value('syncVersion'));
}
} catch (error) {
@ -433,7 +436,7 @@ export default class Synchronizer {
syncLock = await this.lockHandler().acquireLock(LockType.Sync, this.appType_, this.clientId_);
this.lockHandler().startAutoLockRefresh(syncLock, (error: any) => {
this.logger().warn('Could not refresh lock - cancelling sync. Error was:', error);
logger.warn('Could not refresh lock - cancelling sync. Error was:', error);
this.syncTargetIsLocked_ = true;
void this.cancel();
});
@ -518,7 +521,7 @@ export default class Synchronizer {
} catch (error) {
if (error.code === 'rejectedByTarget') {
this.progressReport_.errors.push(error);
this.logger().warn(`Rejected by target: ${path}: ${error.message}`);
logger.warn(`Rejected by target: ${path}: ${error.message}`);
completeItemProcessing(path);
continue;
} else {
@ -577,7 +580,7 @@ export default class Synchronizer {
// already been done" on the next loop, and sync
// will never finish because we'll always end up
// here.
this.logger().info(`Need to upload a resource, but blob is not present: ${path}`);
logger.info(`Need to upload a resource, but blob is not present: ${path}`);
await handleCannotSyncItem(ItemClass, syncTargetId, local, 'Trying to upload resource, but only metadata is present.');
action = null;
} else {
@ -589,7 +592,7 @@ export default class Synchronizer {
const localResourceContentPath = result.path;
if (resource.size >= 10 * 1000 * 1000) {
this.logger().warn(`Uploading a large resource (resourceId: ${local.id}, size:${resource.size} bytes) which may tie up the sync process.`);
logger.warn(`Uploading a large resource (resourceId: ${local.id}, size:${resource.size} bytes) which may tie up the sync process.`);
}
await this.apiCall('put', remoteContentPath, null, { path: localResourceContentPath, source: 'file', shareId: resource.share_id });
@ -750,7 +753,7 @@ export default class Synchronizer {
if (this.downloadQueue_) await this.downloadQueue_.stop();
this.downloadQueue_ = new TaskQueue('syncDownload');
this.downloadQueue_.logger_ = this.logger();
this.downloadQueue_.logger_ = logger;
if (syncSteps.indexOf('delta') >= 0) {
// At this point all the local items that have changed have been pushed to remote
@ -779,7 +782,7 @@ export default class Synchronizer {
wipeOutFailSafe: Setting.value('sync.wipeOutFailSafe'),
logger: this.logger(),
logger: logger,
});
const remotes: RemoteItem[] = listResult.items;
@ -860,7 +863,7 @@ export default class Synchronizer {
} catch (error) {
if (error.code === 'rejectedByTarget') {
this.progressReport_.errors.push(error);
this.logger().warn(`Rejected by target: ${path}: ${error.message}`);
logger.warn(`Rejected by target: ${path}: ${error.message}`);
action = null;
} else {
error.message = `On file ${path}: ${error.message}`;
@ -876,7 +879,7 @@ export default class Synchronizer {
if (action == 'createLocal' || action == 'updateLocal') {
if (content === null) {
this.logger().warn(`Remote has been deleted between now and the delta() call? In that case it will be handled during the next sync: ${path}`);
logger.warn(`Remote has been deleted between now and the delta() call? In that case it will be handled during the next sync: ${path}`);
continue;
}
content = ItemClass.filter(content);
@ -914,11 +917,11 @@ export default class Synchronizer {
if (!hasAutoEnabledEncryption && content.type_ === BaseModel.TYPE_MASTER_KEY && !masterKeysBefore) {
hasAutoEnabledEncryption = true;
this.logger().info('One master key was downloaded and none was previously available: automatically enabling encryption');
this.logger().info('Using master key: ', content.id);
logger.info('One master key was downloaded and none was previously available: automatically enabling encryption');
logger.info('Using master key: ', content.id);
await this.encryptionService().enableEncryption(content);
await this.encryptionService().loadMasterKeysFromSettings();
this.logger().info('Encryption has been enabled with downloaded master key as active key. However, note that no password was initially supplied. It will need to be provided by user.');
logger.info('Encryption has been enabled with downloaded master key as active key. However, note that no password was initially supplied. It will need to be provided by user.');
}
if (content.encryption_applied) this.dispatch({ type: 'SYNC_GOT_ENCRYPTED_ITEM' });
@ -989,7 +992,7 @@ export default class Synchronizer {
// Only log an info statement for this since this is a common condition that is reported
// in the application, and needs to be resolved by the user.
// Or it's a temporary issue that will be resolved on next sync.
this.logger().info(error.message);
logger.info(error.message);
if (error.code === 'failSafe' || error.code === 'lockError') {
// Get the message to display on UI, but not in testing to avoid poluting stdout
@ -998,10 +1001,10 @@ export default class Synchronizer {
}
} else if (error.code === 'unknownItemType') {
this.progressReport_.errors.push(_('Unknown item type downloaded - please upgrade Joplin to the latest version'));
this.logger().error(error);
logger.error(error);
} else {
this.logger().error(error);
if (error.details) this.logger().error('Details:', error.details);
logger.error(error);
if (error.details) logger.error('Details:', error.details);
// Don't save to the report errors that are due to things like temporary network errors or timeout.
if (!shim.fetchRequestCanBeRetried(error)) {
@ -1019,7 +1022,7 @@ export default class Synchronizer {
this.syncTargetIsLocked_ = false;
if (this.cancelling()) {
this.logger().info('Synchronisation was cancelled.');
logger.info('Synchronisation was cancelled.');
this.cancelling_ = false;
}
@ -1029,7 +1032,7 @@ export default class Synchronizer {
try {
await this.shareService_.maintenance();
} catch (error) {
this.logger().error('Could not run share service maintenance:', error);
logger.error('Could not run share service maintenance:', error);
}
}

View File

@ -1,14 +1,15 @@
const EncryptionService = require('../../services/EncryptionService').default;
const { _ } = require('../../locale');
const BaseItem = require('../../models/BaseItem').default;
const Setting = require('../../models/Setting').default;
const MasterKey = require('../../models/MasterKey').default;
const { reg } = require('../../registry.js');
const shim = require('../../shim').default;
import EncryptionService from '../../services/EncryptionService';
import { _ } from '../../locale';
import BaseItem from '../../models/BaseItem';
import Setting from '../../models/Setting';
import MasterKey from '../../models/MasterKey';
import { reg } from '../../registry.js';
import shim from '../../shim';
import { MasterKeyEntity } from '../../services/database/types';
const shared = {};
const shared: any = {};
shared.constructor = function(comp, props) {
shared.constructor = function(comp: any, props: any) {
comp.state = {
passwordChecks: {},
stats: {
@ -22,7 +23,7 @@ shared.constructor = function(comp, props) {
shared.refreshStatsIID_ = null;
};
shared.refreshStats = async function(comp) {
shared.refreshStats = async function(comp: any) {
const stats = await BaseItem.encryptedItemsStats();
comp.setState({
stats: stats,
@ -34,7 +35,7 @@ shared.reencryptData = async function() {
if (!ok) return;
await BaseItem.forceSyncAll();
reg.waitForSyncFinishedThenSync();
void reg.waitForSyncFinishedThenSync();
Setting.setValue('encryption.shouldReencrypt', Setting.SHOULD_REENCRYPT_NO);
alert(_('Your data is going to be re-encrypted and synced again.'));
};
@ -43,7 +44,7 @@ shared.dontReencryptData = function() {
Setting.setValue('encryption.shouldReencrypt', Setting.SHOULD_REENCRYPT_NO);
};
shared.upgradeMasterKey = async function(comp, masterKey) {
shared.upgradeMasterKey = async function(comp: any, masterKey: MasterKeyEntity) {
const passwordCheck = comp.state.passwordChecks[masterKey.id];
if (!passwordCheck) {
alert(_('Please enter your password in the master key list below before upgrading the key.'));
@ -54,14 +55,14 @@ shared.upgradeMasterKey = async function(comp, masterKey) {
const password = comp.state.passwords[masterKey.id];
const newMasterKey = await EncryptionService.instance().upgradeMasterKey(masterKey, password);
await MasterKey.save(newMasterKey);
reg.waitForSyncFinishedThenSync();
void reg.waitForSyncFinishedThenSync();
alert(_('The master key has been upgraded successfully!'));
} catch (error) {
alert(_('Could not upgrade master key: %s', error.message));
}
};
shared.componentDidMount = async function(comp) {
shared.componentDidMount = async function(comp: any) {
shared.componentDidUpdate(comp);
shared.refreshStats(comp);
@ -81,7 +82,7 @@ shared.componentDidMount = async function(comp) {
}, 3000);
};
shared.componentDidUpdate = async function(comp, prevProps = null) {
shared.componentDidUpdate = async function(comp: any, prevProps: any = null) {
if (prevProps && comp.props.passwords !== prevProps.passwords) {
comp.setState({ passwords: Object.assign({}, comp.props.passwords) });
}
@ -98,7 +99,7 @@ shared.componentWillUnmount = function() {
}
};
shared.checkPasswords = async function(comp) {
shared.checkPasswords = async function(comp: any) {
const passwordChecks = Object.assign({}, comp.state.passwordChecks);
for (let i = 0; i < comp.props.masterKeys.length; i++) {
const mk = comp.props.masterKeys[i];
@ -109,14 +110,14 @@ shared.checkPasswords = async function(comp) {
comp.setState({ passwordChecks: passwordChecks });
};
shared.decryptedStatText = function(comp) {
shared.decryptedStatText = function(comp: any) {
const stats = comp.state.stats;
const doneCount = stats.encrypted !== null ? stats.total - stats.encrypted : '-';
const totalCount = stats.total !== null ? stats.total : '-';
return _('Decrypted items: %s / %s', doneCount, totalCount);
};
shared.onSavePasswordClick = function(comp, mk) {
shared.onSavePasswordClick = function(comp: any, mk: MasterKeyEntity) {
const password = comp.state.passwords[mk.id];
if (!password) {
Setting.deleteObjectValue('encryption.passwordCache', mk.id);
@ -127,10 +128,10 @@ shared.onSavePasswordClick = function(comp, mk) {
comp.checkPasswords();
};
shared.onPasswordChange = function(comp, mk, password) {
shared.onPasswordChange = function(comp: any, mk: MasterKeyEntity, password: string) {
const passwords = Object.assign({}, comp.state.passwords);
passwords[mk.id] = password;
comp.setState({ passwords: passwords });
};
module.exports = shared;
export default shared;

View File

@ -9,6 +9,13 @@ import KvStore from './KvStore';
const EventEmitter = require('events');
interface DecryptionResult {
skippedItemCount?: number;
decryptedItemCounts?: number;
decryptedItemCount?: number;
error: any;
}
export default class DecryptionWorker {
public static instance_: DecryptionWorker = null;
@ -107,7 +114,7 @@ export default class DecryptionWorker {
this.dispatch(action);
}
async start_(options: any = null) {
private async start_(options: any = null): Promise<DecryptionResult> {
if (options === null) options = {};
if (!('masterKeyNotLoadedHandler' in options)) options.masterKeyNotLoadedHandler = 'throw';
if (!('errorHandler' in options)) options.errorHandler = 'log';
@ -260,10 +267,11 @@ export default class DecryptionWorker {
let decryptedItemCount = 0;
for (const itemType in decryptedItemCounts) decryptedItemCount += decryptedItemCounts[itemType];
const finalReport = {
const finalReport: DecryptionResult = {
skippedItemCount: skippedItemCount,
decryptedItemCounts: decryptedItemCounts,
decryptedItemCount: decryptedItemCount,
error: null,
};
this.dispatchReport(Object.assign({}, finalReport, { state: 'idle' }));
@ -276,7 +284,7 @@ export default class DecryptionWorker {
return finalReport;
}
async start(options: any) {
public async start(options: any = {}) {
this.startCalls_.push(true);
let output = null;
try {

View File

@ -1,14 +1,12 @@
/* eslint-disable no-unused-vars, @typescript-eslint/no-unused-vars, prefer-const */
import { fileContentEqual, setupDatabaseAndSynchronizer, supportDir, switchClient, objectsEqual, checkThrowAsync } from '../testing/test-utils';
import Folder from '../models/Folder';
import Note from '../models/Note';
import Setting from '../models/Setting';
import BaseItem from '../models/BaseItem';
import MasterKey from '../models/MasterKey';
import EncryptionService from '../services/EncryptionService';
const { fileContentEqual, setupDatabaseAndSynchronizer, supportDir, switchClient, objectsEqual, checkThrowAsync } = require('../testing/test-utils.js');
const Folder = require('../models/Folder').default;
const Note = require('../models/Note').default;
const Setting = require('../models/Setting').default;
const BaseItem = require('../models/BaseItem').default;
const MasterKey = require('../models/MasterKey').default;
const EncryptionService = require('../services/EncryptionService').default;
let service = null;
let service: EncryptionService = null;
describe('services_EncryptionService', function() {
@ -85,7 +83,7 @@ describe('services_EncryptionService', function() {
encryptionMethod: EncryptionService.METHOD_SJCL_2,
});
const hasThrown = await checkThrowAsync(async () => await service.upgradeMasterKey(masterKey, '777'));
await checkThrowAsync(async () => await service.upgradeMasterKey(masterKey, '777'));
}));
it('should require a checksum only for old master keys', (async () => {
@ -128,7 +126,7 @@ describe('services_EncryptionService', function() {
encryptionMethod: EncryptionService.METHOD_SJCL,
}));
const masterKey3 = await MasterKey.save(await service.generateMasterKey('123456'));
await MasterKey.save(await service.generateMasterKey('123456'));
const needUpgrade = service.masterKeysThatNeedUpgrading(await MasterKey.all());

View File

@ -46,7 +46,7 @@ export default class EncryptionService {
private chunkSize_ = 5000;
private loadedMasterKeys_: Record<string, string> = {};
private activeMasterKeyId_: string = null;
private defaultEncryptionMethod_ = EncryptionService.METHOD_SJCL_1A;
public defaultEncryptionMethod_ = EncryptionService.METHOD_SJCL_1A; // public because used in tests
private defaultMasterKeyEncryptionMethod_ = EncryptionService.METHOD_SJCL_4;
private logger_ = new Logger();

View File

@ -16,6 +16,7 @@ const migrations = [
import Setting from '../../models/Setting';
const { sprintf } = require('sprintf-js');
import JoplinError from '../../JoplinError';
import { FileApi } from '../../file-api';
interface SyncTargetInfo {
version: number;
@ -23,12 +24,12 @@ interface SyncTargetInfo {
export default class MigrationHandler extends BaseService {
private api_: any = null;
private api_: FileApi = null;
private lockHandler_: LockHandler = null;
private clientType_: string;
private clientId_: string;
constructor(api: any, lockHandler: LockHandler, clientType: string, clientId: string) {
constructor(api: FileApi, lockHandler: LockHandler, clientType: string, clientId: string) {
super();
this.api_ = api;
this.lockHandler_ = lockHandler;

View File

@ -1,18 +1,16 @@
import LockHandler from '../../services/synchronizer/LockHandler';
import MigrationHandler from '../../services/synchronizer/MigrationHandler';
import { Dirnames } from '../../services/synchronizer/utils/types';
import { setSyncTargetName, fileApi, synchronizer, decryptionWorker, encryptionService, setupDatabaseAndSynchronizer, switchClient, expectThrow, expectNotThrow } from '../../testing/test-utils';
import { deploySyncTargetSnapshot, testData, checkTestData } from '../../testing/syncTargetUtils';
import Setting from '../../models/Setting';
import MasterKey from '../../models/MasterKey';
// To create a sync target snapshot for the current syncVersion:
// - In test-utils, set syncTargetName_ to "filesystem"
// - Then run:
// gulp buildTests -L && node tests-build/support/createSyncTargetSnapshot.js normal && node tests-build/support/createSyncTargetSnapshot.js e2ee
const { setSyncTargetName, fileApi, synchronizer, decryptionWorker, encryptionService, setupDatabaseAndSynchronizer, switchClient, expectThrow, expectNotThrow } = require('../../testing/test-utils.js');
const { deploySyncTargetSnapshot, testData, checkTestData } = require('../../testing/syncTargetUtils');
import Setting from '../../models/Setting';
import MasterKey from '../../models/MasterKey';
const specTimeout = 60000 * 10; // Nextcloud tests can be slow
let lockHandler_: LockHandler = null;

View File

@ -1,12 +1,12 @@
const { syncDir, synchronizer, supportDir, loadEncryptionMasterKey, setupDatabaseAndSynchronizer, switchClient } = require('../testing/test-utils.js');
const Setting = require('../models/Setting').default;
const Folder = require('../models/Folder').default;
const Note = require('../models/Note').default;
const Tag = require('../models/Tag').default;
const Resource = require('../models/Resource').default;
const markdownUtils = require('../markdownUtils').default;
const shim = require('../shim').default;
const fs = require('fs-extra');
import { syncDir, synchronizer, supportDir, loadEncryptionMasterKey, setupDatabaseAndSynchronizer, switchClient } from '../testing/test-utils';
import Setting from '../models/Setting';
import Folder from '../models/Folder';
import Note from '../models/Note';
import Tag from '../models/Tag';
import Resource from '../models/Resource';
import markdownUtils from '../markdownUtils';
import shim from '../shim';
import * as fs from 'fs-extra';
const snapshotBaseDir = `${supportDir}/syncTargetSnapshots`;
@ -36,8 +36,8 @@ const testData = {
},
};
async function createTestData(data) {
async function recurseStruct(s, parentId = '') {
async function createTestData(data: any) {
async function recurseStruct(s: any, parentId: string = '') {
for (const n in s) {
if (n.toLowerCase().includes('folder')) {
const folder = await Folder.save({ title: n, parent_id: parentId });
@ -60,8 +60,8 @@ async function createTestData(data) {
await recurseStruct(data);
}
async function checkTestData(data) {
async function recurseCheck(s) {
async function checkTestData(data: any) {
async function recurseCheck(s: any) {
for (const n in s) {
const obj = s[n];
@ -98,13 +98,13 @@ async function checkTestData(data) {
await recurseCheck(data);
}
async function deploySyncTargetSnapshot(syncTargetType, syncVersion) {
async function deploySyncTargetSnapshot(syncTargetType: string, syncVersion: number) {
const sourceDir = `${snapshotBaseDir}/${syncVersion}/${syncTargetType}`;
await fs.remove(syncDir);
await fs.copy(sourceDir, syncDir);
}
async function main(syncTargetType) {
async function main(syncTargetType: string) {
const validSyncTargetTypes = ['normal', 'e2ee'];
if (!validSyncTargetTypes.includes(syncTargetType)) throw new Error(`Sync target type must be: ${validSyncTargetTypes.join(', ')}`);
@ -129,7 +129,7 @@ async function main(syncTargetType) {
console.info(`Sync target snapshot created in: ${destDir}`);
}
module.exports = {
export {
checkTestData,
main,
testData,