Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Desktop: Resolves #8625: Show missing sync password warning and link to FAQ #8644

Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintignore
Expand Up @@ -516,6 +516,7 @@ packages/lib/commands/index.js
packages/lib/commands/openMasterPasswordDialog.js
packages/lib/commands/synchronize.js
packages/lib/components/EncryptionConfigScreen/utils.js
packages/lib/components/shared/config/shouldShowMissingPasswordWarning.js
packages/lib/components/shared/note-screen-shared.js
packages/lib/components/shared/reduxSharedMiddleware.js
packages/lib/database-driver-better-sqlite.js
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -502,6 +502,7 @@ packages/lib/commands/index.js
packages/lib/commands/openMasterPasswordDialog.js
packages/lib/commands/synchronize.js
packages/lib/components/EncryptionConfigScreen/utils.js
packages/lib/components/shared/config/shouldShowMissingPasswordWarning.js
packages/lib/components/shared/note-screen-shared.js
packages/lib/components/shared/reduxSharedMiddleware.js
packages/lib/database-driver-better-sqlite.js
Expand Down
34 changes: 33 additions & 1 deletion packages/app-desktop/gui/ConfigScreen/ConfigScreen.tsx
Expand Up @@ -12,14 +12,17 @@ const { connect } = require('react-redux');
const { themeStyle } = require('@joplin/lib/theme');
const pathUtils = require('@joplin/lib/path-utils');
import SyncTargetRegistry from '@joplin/lib/SyncTargetRegistry';
const shared = require('@joplin/lib/components/shared/config-shared.js');
const shared = require('@joplin/lib/components/shared/config/config-shared.js');
import ClipperConfigScreen from '../ClipperConfigScreen';
import restart from '../../services/restart';
import PluginService from '@joplin/lib/services/plugins/PluginService';
import { getDefaultPluginsInstallState, updateDefaultPluginsInstallState } from '@joplin/lib/services/plugins/defaultPlugins/defaultPluginsUtils';
import getDefaultPluginsInfo from '@joplin/lib/services/plugins/defaultPlugins/desktopDefaultPluginsInfo';
import JoplinCloudConfigScreen from '../JoplinCloudConfigScreen';
import ToggleAdvancedSettingsButton from './controls/ToggleAdvancedSettingsButton';
import shouldShowMissingPasswordWarning from '@joplin/lib/components/shared/config/shouldShowMissingPasswordWarning';
import shim from '@joplin/lib/shim';
import StyledLink from '../style/StyledLink';
const { KeymapConfigScreen } = require('../KeymapConfig/KeymapConfigScreen');

const settingKeyToControl: any = {
Expand Down Expand Up @@ -181,6 +184,35 @@ class ConfigScreenComponent extends React.Component<any, any> {
if (section.name === 'sync') {
const syncTargetMd = SyncTargetRegistry.idToMetadata(settings['sync.target']);
const statusStyle = { ...theme.textStyle, marginTop: 10 };
const warningStyle = { ...theme.textStyle, color: theme.colorWarn };

// Don't show the missing password warning if the user just changed the sync target (but hasn't
// saved yet).
const matchesSavedTarget = settings['sync.target'] === this.props.settings['sync.target'];
if (matchesSavedTarget && shouldShowMissingPasswordWarning(settings['sync.target'], settings)) {
const openMissingPasswordFAQ = () =>
bridge().openExternal('https://joplinapp.org/faq#why-did-my-sync-and-encryption-passwords-disappear-after-updating-joplin');

const macInfoLink = (
<StyledLink href="#"
onClick={openMissingPasswordFAQ}
style={theme.linkStyle}
>
{_('Why is my password missing?')}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possible alternative:

Suggested change
{_('Why is my password missing?')}
{_('Help')}

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, just Help would be good. That's a temporary message that we'll keep just for the ARM64 transition, so we don't want to create too many new translatable strings for it

</StyledLink>
);

// The FAQ section related to missing passwords is specific to MacOS/ARM -- only show it
// in that case.
const showMacInfoLink = shim.isMac();
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may make sense to update this condition such that the warning is only shown on ARM 64 Macs. I only have access to an x86_64 Mac, however, so would be unable to test an ARM64-specific condition manually.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes please enable it only for ARM64. I think you just need to check process.arch === 'arm64'


settingComps.push(
<p key='missing-password-warning' style={warningStyle}>
{_('Warning: Missing password.')}
{showMacInfoLink ? macInfoLink : null}
</p>
);
}

if (syncTargetMd.supportsConfigCheck) {
const messages = shared.checkSyncConfigMessages(this);
Expand Down
21 changes: 20 additions & 1 deletion packages/app-desktop/gui/MainScreen/MainScreen.tsx
Expand Up @@ -20,6 +20,7 @@ import NoteListWrapper from '../NoteListWrapper/NoteListWrapper';
import { AppState } from '../../app.reducer';
import { saveLayout, loadLayout } from '../ResizableLayout/utils/persist';
import Setting from '@joplin/lib/models/Setting';
import shouldShowMissingPasswordWarning from '@joplin/lib/components/shared/config/shouldShowMissingPasswordWarning';
import produce from 'immer';
import shim from '@joplin/lib/shim';
import bridge from '../../services/bridge';
Expand Down Expand Up @@ -67,6 +68,7 @@ interface Props {
shouldUpgradeSyncTarget: boolean;
hasDisabledSyncItems: boolean;
hasDisabledEncryptionItems: boolean;
hasMissingSyncCredentials: boolean;
showMissingMasterKeyMessage: boolean;
showNeedUpgradingMasterKeyMessage: boolean;
showShouldReencryptMessage: boolean;
Expand Down Expand Up @@ -561,6 +563,16 @@ class MainScreenComponent extends React.Component<Props, State> {
});
};

const onViewSyncSettingsScreen = () => {
this.props.dispatch({
type: 'NAV_GO',
routeName: 'Config',
props: {
defaultSection: 'sync',
},
});
};

const onViewPluginScreen = () => {
this.props.dispatch({
type: 'NAV_GO',
Expand Down Expand Up @@ -598,6 +610,12 @@ class MainScreenComponent extends React.Component<Props, State> {
_('Disable safe mode and restart'),
onDisableSafeModeAndRestart
);
} else if (this.props.hasMissingSyncCredentials) {
msg = this.renderNotificationMessage(
_('The synchronisation password is missing.'),
_('Set the password'),
onViewSyncSettingsScreen
);
} else if (this.props.shouldUpgradeSyncTarget) {
msg = this.renderNotificationMessage(
_('The sync target needs to be upgraded before Joplin can sync. The operation may take a few minutes to complete and the app needs to be restarted. To proceed please click on the link.'),
Expand Down Expand Up @@ -662,7 +680,7 @@ class MainScreenComponent extends React.Component<Props, State> {

public messageBoxVisible(props: Props = null) {
if (!props) props = this.props;
return props.hasDisabledSyncItems || props.showMissingMasterKeyMessage || props.showNeedUpgradingMasterKeyMessage || props.showShouldReencryptMessage || props.hasDisabledEncryptionItems || this.props.shouldUpgradeSyncTarget || props.isSafeMode || this.showShareInvitationNotification(props) || this.props.needApiAuth || this.props.showInstallTemplatesPlugin;
return props.hasDisabledSyncItems || props.showMissingMasterKeyMessage || props.hasMissingSyncCredentials || props.showNeedUpgradingMasterKeyMessage || props.showShouldReencryptMessage || props.hasDisabledEncryptionItems || this.props.shouldUpgradeSyncTarget || props.isSafeMode || this.showShareInvitationNotification(props) || this.props.needApiAuth || this.props.showInstallTemplatesPlugin;
}

public registerCommands() {
Expand Down Expand Up @@ -875,6 +893,7 @@ const mapStateToProps = (state: AppState) => {
showNeedUpgradingMasterKeyMessage: showNeedUpgradingEnabledMasterKeyMessage,
showShouldReencryptMessage: state.settings['encryption.shouldReencrypt'] >= Setting.SHOULD_REENCRYPT_YES,
shouldUpgradeSyncTarget: state.settings['sync.upgradeState'] === Setting.SYNC_UPGRADE_STATE_SHOULD_DO,
hasMissingSyncCredentials: shouldShowMissingPasswordWarning(state.settings['sync.target'], state.settings),
pluginsLegacy: state.pluginsLegacy,
plugins: state.pluginService.plugins,
pluginHtmlContents: state.pluginService.pluginHtmlContents,
Expand Down
Expand Up @@ -20,7 +20,7 @@ const { _ } = require('@joplin/lib/locale');
const { BaseScreenComponent } = require('../../base-screen.js');
const { Dropdown } = require('../../Dropdown');
const { themeStyle } = require('../../global-style.js');
const shared = require('@joplin/lib/components/shared/config-shared.js');
const shared = require('@joplin/lib/components/shared/config/config-shared.js');
import SyncTargetRegistry from '@joplin/lib/SyncTargetRegistry';
import { openDocumentTree } from '@joplin/react-native-saf-x';
import biometricAuthenticate from '../../biometrics/biometricAuthenticate';
Expand Down
@@ -1,7 +1,7 @@
const Setting = require('../../models/Setting').default;
const SyncTargetRegistry = require('../../SyncTargetRegistry').default;
const ObjectUtils = require('../../ObjectUtils');
const { _ } = require('../../locale');
const Setting = require('../../../models/Setting').default;
const SyncTargetRegistry = require('../../../SyncTargetRegistry').default;
const ObjectUtils = require('../../../ObjectUtils');
const { _ } = require('../../../locale');
const { createSelector } = require('reselect');
const Logger = require('@joplin/utils/Logger').default;

Expand Down
@@ -0,0 +1,13 @@
import SyncTargetRegistry from '../../../SyncTargetRegistry';

const shouldShowMissingPasswordWarning = (syncTargetId: number, settings: any) => {
laurent22 marked this conversation as resolved.
Show resolved Hide resolved
// List of sync targets that expect a non-empty password setting
const targetsExpectingPassword = [
'webdav', 'nextcloud', 'amazon_s3', 'joplinServer', 'joplinCloud',
].map(name => SyncTargetRegistry.nameToId(name));
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usually sync target properties go in the SyncTargetXxx.ts class so that it's easy to find them back all in the same place. In that case you'd create a new property in BaseSyncTarget, probably true by default since most sync targets require a password, and you'd override for those that don't.


const expectsPassword = targetsExpectingPassword.includes(syncTargetId);
return expectsPassword && settings[`sync.${syncTargetId}.password`] === '';
};

export default shouldShowMissingPasswordWarning;
Expand Up @@ -5,7 +5,7 @@ import shim from '../../../shim';
import PluginService, { defaultPluginSetting, DefaultPluginsInfo, PluginSettings } from '../PluginService';
import Logger from '@joplin/utils/Logger';
import * as React from 'react';
const shared = require('../../../components/shared/config-shared.js');
const shared = require('../../../components/shared/config/config-shared.js');

const logger = Logger.create('defaultPluginsUtils');

Expand Down
5 changes: 5 additions & 0 deletions readme/faq.md
Expand Up @@ -141,6 +141,11 @@ In this case, [make sure you enter the correct WebDAV URL](https://github.com/la
- Check the WebDAV URL - to get the correct URL, go to Nextcloud and, in the left sidebar, click on "Settings" and copy the WebDAV URL from there. **Do not forget to add the folder you've created to that URL**. For example, if the base the WebDAV URL is "https://example.com/nextcloud/remote.php/webdav/" and you want the notes to be synced in the "Joplin" directory, you need to give the URL "https://example.com/nextcloud/remote.php/webdav/Joplin" **and you need to create the "Joplin" directory yourself**.
- Did you enable **2FA** (Multi-factor authentication) on Nextcloud? In that case, you need to [create an app password for Joplin in the Nextcloud admin interface](https://github.com/laurent22/joplin/issues/1453#issuecomment-486640902).

## Why did my sync and encryption passwords disappear after updating Joplin?

- With version 2.12, Joplin supports M1 Macs natively! As a result, upgrading Joplin on one of these systems causes Joplin to lose access to information stored by older versions of the app in the system keychain. This includes sync and encryption passwords.
- Re-entering the passwords should fix related sync and encryption issues.

## How can I use self-signed SSL certificates on Android?

If you want to serve using https but can't or don't want to use SSL certificates signed by trusted certificate authorities (like "Let's Encrypt"), it's possible to generate a custom CA and sign your certificates with it. You can generate the CA and certificates using [openssl](https://gist.github.com/fntlnz/cf14feb5a46b2eda428e000157447309), but I like to use a tool called [mkcert](https://github.com/FiloSottile/mkcert) for it's simplicity. Finally, you have to add your CA certificate to Android settings so that Android can recognize the certificates you signed with your CA as valid ([link](https://support.google.com/nexus/answer/2844832?hl=en-GB)).
Expand Down