mirror of https://github.com/laurent22/joplin.git
Mobile: Done UI for E2EE
parent
6ff19063ef
commit
e19c26fdd1
|
@ -101,9 +101,9 @@ class EncryptionConfigScreenComponent extends React.Component {
|
|||
|
||||
let answer = null;
|
||||
if (isEnabled) {
|
||||
answer = await dialogs.confirm(_('Disabling encryption means <b>all</b> your notes and attachments are going to be re-synchronised and sent unencrypted to the sync target. Do you wish to continue?'));
|
||||
answer = await dialogs.confirm(_('Disabling encryption means *all* your notes and attachments are going to be re-synchronised and sent unencrypted to the sync target. Do you wish to continue?'));
|
||||
} else {
|
||||
answer = await dialogs.prompt(_('Enabling encryption means <b>all</b> your notes and attachments are going to be re-synchronised and sent encrypted to the sync target. Do not lose the password as, for security purposes, this will be the <b>only</b> way to decrypt the data! To enable encryption, please enter your password below.'), '', '', { type: 'password' });
|
||||
answer = await dialogs.prompt(_('Enabling encryption means *all* your notes and attachments are going to be re-synchronised and sent encrypted to the sync target. Do not lose the password as, for security purposes, this will be the *only* way to decrypt the data! To enable encryption, please enter your password below.'), '', '', { type: 'password' });
|
||||
}
|
||||
|
||||
if (!answer) return;
|
||||
|
|
|
@ -346,7 +346,7 @@ class ScreenHeaderComponent extends Component {
|
|||
|
||||
menuOptionComponents.push(
|
||||
<MenuOption value={() => this.encryptionConfig_press()} key={'menuOption_encryptionConfig'} style={this.styles().contextMenuItem}>
|
||||
<Text style={this.styles().contextMenuItemText}>{_('Encryption Configuration')}</Text>
|
||||
<Text style={this.styles().contextMenuItemText}>{_('Encryption Config')}</Text>
|
||||
</MenuOption>);
|
||||
|
||||
menuOptionComponents.push(
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
const React = require('react'); const Component = React.Component;
|
||||
const { TextInput, TouchableOpacity, Linking, View, Switch, Slider, StyleSheet, Text, Button, ScrollView } = require('react-native');
|
||||
const EncryptionService = require('lib/services/EncryptionService');
|
||||
const { connect } = require('react-redux');
|
||||
const { ScreenHeader } = require('lib/components/screen-header.js');
|
||||
const { _ } = require('lib/locale.js');
|
||||
|
@ -9,6 +10,8 @@ const { themeStyle } = require('lib/components/global-style.js');
|
|||
const { time } = require('lib/time-utils.js');
|
||||
const Setting = require('lib/models/Setting.js');
|
||||
const shared = require('lib/components/shared/encryption-config-shared.js');
|
||||
const { dialogs } = require('lib/dialogs.js');
|
||||
const DialogBox = require('react-native-dialogbox').default;
|
||||
|
||||
class EncryptionConfigScreenComponent extends BaseScreenComponent {
|
||||
|
||||
|
@ -19,6 +22,11 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
|
|||
constructor() {
|
||||
super();
|
||||
|
||||
this.state = {
|
||||
passwordPromptShow: false,
|
||||
passwordPromptAnswer: '',
|
||||
};
|
||||
|
||||
shared.constructor(this);
|
||||
|
||||
this.styles_ = {};
|
||||
|
@ -67,6 +75,8 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
|
|||
fontSize: theme.fontSize,
|
||||
paddingTop: 5,
|
||||
paddingBottom: 5,
|
||||
marginTop: theme.marginTop,
|
||||
marginBottom: 5,
|
||||
},
|
||||
normalText: {
|
||||
flex: 1,
|
||||
|
@ -103,7 +113,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}}>{_('Password:')}</Text>
|
||||
<TextInput value={password} onChangeText={(text) => onPasswordChange(text)} style={{flex:1, marginRight: 10}}></TextInput>
|
||||
<TextInput secureTextEntry={true} value={password} onChangeText={(text) => onPasswordChange(text)} style={{flex:1, marginRight: 10}}></TextInput>
|
||||
<Text style={{fontSize: theme.fontSize, marginRight: 10}}>{passwordOk}</Text>
|
||||
<Button title={_('Save')} onPress={() => onSaveClick()}></Button>
|
||||
</View>
|
||||
|
@ -111,6 +121,36 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
|
|||
);
|
||||
}
|
||||
|
||||
passwordPromptComponent() {
|
||||
const theme = themeStyle(this.props.theme);
|
||||
|
||||
const onEnableClick = async () => {
|
||||
try {
|
||||
const password = this.state.passwordPromptAnswer;
|
||||
if (!password) throw new Error(_('Password cannot be empty'));
|
||||
await EncryptionService.instance().generateMasterKeyAndEnableEncryption(password);
|
||||
this.setState({ passwordPromptShow: false });
|
||||
} catch (error) {
|
||||
await dialogs.error(this, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={{flex:1, borderColor: theme.dividerColor, borderWidth: 1, padding: 10, marginTop: 10, marginBottom: 10}}>
|
||||
<Text style={{fontSize: theme.fontSize}}>{_('Enabling encryption means *all* your notes and attachments are going to be re-synchronised and sent encrypted to the sync target. Do not lose the password as, for security purposes, this will be the *only* way to decrypt the data! To enable encryption, please enter your password below.')}</Text>
|
||||
<TextInput secureTextEntry={true} value={this.state.passwordPromptAnswer} onChangeText={(text) => { this.setState({ passwordPromptAnswer: text }) }}></TextInput>
|
||||
<View style={{flexDirection: 'row'}}>
|
||||
<View style={{flex:1 , marginRight:10}} >
|
||||
<Button title={_('Enable')} onPress={() => { onEnableClick() }}></Button>
|
||||
</View>
|
||||
<View style={{flex:1}} >
|
||||
<Button title={_('Cancel')} onPress={() => { this.setState({ passwordPromptShow: false}) }}></Button>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const masterKeys = this.state.masterKeys;
|
||||
const decryptedItemsInfo = this.props.encryptionEnabled ? <Text style={this.styles().normalText}>{shared.decryptedStatText(this)}</Text> : null;
|
||||
|
@ -121,15 +161,40 @@ class EncryptionConfigScreenComponent extends BaseScreenComponent {
|
|||
mkComps.push(this.renderMasterKey(i+1, mk));
|
||||
}
|
||||
|
||||
const onToggleButtonClick = async () => {
|
||||
if (this.props.encryptionEnabled) {
|
||||
const ok = await dialogs.confirm(this, _('Disabling encryption means *all* your notes and attachments are going to be re-synchronised and sent unencrypted to the sync target. Do you wish to continue?'));
|
||||
if (!ok) return;
|
||||
|
||||
try {
|
||||
await EncryptionService.instance().disableEncryption();
|
||||
} catch (error) {
|
||||
await dialogs.error(this, error.message);
|
||||
}
|
||||
} else {
|
||||
this.setState({
|
||||
passwordPromptShow: true,
|
||||
passwordPromptAnswer: '',
|
||||
});
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
const passwordPromptComp = this.state.passwordPromptShow ? this.passwordPromptComponent() : null;
|
||||
const toggleButton = !this.state.passwordPromptShow ? <View style={{marginTop: 10}}><Button title={this.props.encryptionEnabled ? _('Disable encryption') : _('Enable encryption')} onPress={() => onToggleButtonClick()}></Button></View> : null;
|
||||
|
||||
return (
|
||||
<View style={this.rootStyle(this.props.theme).root}>
|
||||
<ScreenHeader title={_('Configuration')}/>
|
||||
<ScreenHeader title={_('Encryption Config')}/>
|
||||
<ScrollView style={this.styles().container}>
|
||||
<Text style={this.styles().titleText}>{_('Status')}</Text>
|
||||
<Text style={this.styles().normalText}>{_('Encryption is: %s', this.props.encryptionEnabled ? _('Enabled') : _('Disabled'))}</Text>
|
||||
{decryptedItemsInfo}
|
||||
{toggleButton}
|
||||
{passwordPromptComp}
|
||||
{mkComps}
|
||||
</ScrollView>
|
||||
<DialogBox ref={dialogbox => { this.dialogbox = dialogbox }}/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -58,7 +58,6 @@ shared.checkPasswords = async function(comp) {
|
|||
const ok = password ? await EncryptionService.instance().checkMasterKeyPassword(mk, password) : false;
|
||||
passwordChecks[mk.id] = ok;
|
||||
}
|
||||
console.info(passwordChecks);
|
||||
comp.setState({ passwordChecks: passwordChecks });
|
||||
}
|
||||
|
||||
|
|
|
@ -214,7 +214,9 @@ class Synchronizer {
|
|||
let ItemClass = BaseItem.itemClass(local);
|
||||
let path = BaseItem.systemPath(local);
|
||||
|
||||
// Safety check to avoid infinite loops:
|
||||
// Safety check to avoid infinite loops.
|
||||
// In fact this error is possible if the item is marked for sync (via sync_time or force_sync) while synchronisation is in
|
||||
// progress. In that case exit anyway to be sure we aren't in a loop and the item will be re-synced next time.
|
||||
if (donePaths.indexOf(path) > 0) throw new Error(sprintf('Processing a path that has already been done: %s. sync_time was not updated?', path));
|
||||
|
||||
let remote = await this.api().stat(path);
|
||||
|
|
|
@ -281,8 +281,12 @@ async function initialize(dispatch) {
|
|||
|
||||
const mainLogger = new Logger();
|
||||
mainLogger.addTarget('database', { database: logDatabase, source: 'm' });
|
||||
if (Setting.value('env') == 'dev') mainLogger.addTarget('console');
|
||||
mainLogger.setLevel(Logger.LEVEL_DEBUG);
|
||||
mainLogger.setLevel(Logger.LEVEL_INFO);
|
||||
|
||||
if (Setting.value('env') == 'dev') {
|
||||
mainLogger.addTarget('console');
|
||||
mainLogger.setLevel(Logger.LEVEL_DEBUG);
|
||||
}
|
||||
|
||||
reg.setLogger(mainLogger);
|
||||
reg.setShowErrorMessageBoxHandler((message) => { alert(message) });
|
||||
|
@ -345,7 +349,7 @@ async function initialize(dispatch) {
|
|||
await Setting.load();
|
||||
|
||||
if (Setting.value('firstStart')) {
|
||||
const locale = NativeModules.I18nManager.localeIdentifier
|
||||
let locale = NativeModules.I18nManager.localeIdentifier
|
||||
if (!locale) locale = defaultLocale();
|
||||
Setting.setValue('locale', closestSupportedLocale(locale));
|
||||
if (Setting.value('env') === 'dev') Setting.setValue('sync.target', SyncTargetRegistry.nameToId('onedrive_dev'));
|
||||
|
|
Loading…
Reference in New Issue