diff --git a/keyserver/src/responders/website-responders.js b/keyserver/src/responders/website-responders.js --- a/keyserver/src/responders/website-responders.js +++ b/keyserver/src/responders/website-responders.js @@ -388,7 +388,10 @@ dataLoaded: viewer.loggedIn, windowActive: true, userPolicies: {}, - primaryIdentityPublicKey: null, + cryptoStore: { + primaryIdentityKeys: null, + notificationIdentityKeys: null, + }, _persist: null, }); const jsonStream = streamJSON(res, initialReduxState); diff --git a/lib/types/crypto-types.js b/lib/types/crypto-types.js new file mode 100644 --- /dev/null +++ b/lib/types/crypto-types.js @@ -0,0 +1,11 @@ +// @flow + +export type OLMIdentityKeys = { + +ed25519: string, + +curve25519: string, +}; + +export type CryptoStore = { + +primaryIdentityKeys: ?OLMIdentityKeys, + +notificationIdentityKeys: ?OLMIdentityKeys, +}; diff --git a/lib/types/redux-types.js b/lib/types/redux-types.js --- a/lib/types/redux-types.js +++ b/lib/types/redux-types.js @@ -12,6 +12,7 @@ QueueActivityUpdatesPayload, SetThreadUnreadStatusPayload, } from './activity-types.js'; +import type { CryptoStore } from './crypto-types.js'; import type { ClientDBDraftInfo, DraftStore } from './draft-types.js'; import type { EnabledApps, SupportedApps } from './enabled-apps.js'; import type { @@ -120,7 +121,7 @@ sessionID: ?string, deviceToken?: void, cookie?: void, - primaryIdentityPublicKey: ?string, + cryptoStore: CryptoStore, ... }; export type AppState = NativeAppState | WebAppState; diff --git a/web/account/log-in-form.react.js b/web/account/log-in-form.react.js --- a/web/account/log-in-form.react.js +++ b/web/account/log-in-form.react.js @@ -11,7 +11,7 @@ import SIWELoginForm from './siwe-login-form.react.js'; import TraditionalLoginForm from './traditional-login-form.react.js'; import OrBreak from '../components/or-break.react.js'; -import { setPrimaryIdentityKeys } from '../redux/primary-identity-public-key-reducer.js'; +import { setPrimaryIdentityKeys } from '../redux/crypto-store-reducer.js'; import { useSelector } from '../redux/redux-utils.js'; function LoginForm(): React.Node { @@ -20,7 +20,7 @@ const dispatch = useDispatch(); const primaryIdentityPublicKey = useSelector( - state => state.primaryIdentityPublicKey, + state => state.cryptoStore.primaryIdentityKeys?.ed25519, ); React.useEffect(() => { @@ -34,12 +34,11 @@ await olm.init(); const identityAccount = new olm.Account(); identityAccount.create(); - const { ed25519: identityED25519 } = JSON.parse( - identityAccount.identity_keys(), - ); + const { ed25519: identityED25519, curve25519: identityCurve25519 } = + JSON.parse(identityAccount.identity_keys()); dispatch({ type: setPrimaryIdentityKeys, - payload: identityED25519, + payload: { ed25519: identityED25519, curve25519: identityCurve25519 }, }); })(); }, [dispatch, primaryIdentityPublicKey]); diff --git a/web/account/siwe-login-form.react.js b/web/account/siwe-login-form.react.js --- a/web/account/siwe-login-form.react.js +++ b/web/account/siwe-login-form.react.js @@ -71,7 +71,7 @@ }, [dispatchActionPromise, getSIWENonceCall, siweNonceShouldBeFetched]); const primaryIdentityPublicKey = useSelector( - state => state.primaryIdentityPublicKey, + state => state.cryptoStore.primaryIdentityKeys?.ed25519, ); const callSIWEAuthEndpoint = React.useCallback( diff --git a/web/account/traditional-login-form.react.js b/web/account/traditional-login-form.react.js --- a/web/account/traditional-login-form.react.js +++ b/web/account/traditional-login-form.react.js @@ -38,7 +38,7 @@ const modalContext = useModalContext(); const primaryIdentityPublicKey = useSelector( - state => state.primaryIdentityPublicKey, + state => state.cryptoStore.primaryIdentityKeys?.ed25519, ); const usernameInputRef = React.useRef(); diff --git a/web/redux/primary-identity-public-key-reducer.js b/web/redux/crypto-store-reducer.js rename from web/redux/primary-identity-public-key-reducer.js rename to web/redux/crypto-store-reducer.js --- a/web/redux/primary-identity-public-key-reducer.js +++ b/web/redux/crypto-store-reducer.js @@ -4,26 +4,30 @@ logOutActionTypes, deleteAccountActionTypes, } from 'lib/actions/user-actions.js'; +import type { CryptoStore } from 'lib/types/crypto-types.js'; import { setNewSessionActionType } from 'lib/utils/action-utils.js'; import type { Action } from './redux-setup.js'; const setPrimaryIdentityKeys = 'SET_PRIMARY_IDENTITY_KEYS'; -function reducePrimaryIdentityPublicKey( - state: ?string, - action: Action, -): ?string { +function reduceCryptoStore(state: CryptoStore, action: Action): CryptoStore { if (action.type === setPrimaryIdentityKeys) { - return action.payload; + return { + ...state, + primaryIdentityKeys: action.payload, + }; } else if ( action.type === logOutActionTypes.success || action.type === deleteAccountActionTypes.success || (action.type === setNewSessionActionType && action.payload.sessionChange.cookieInvalidated) ) { - return null; + return { + primaryIdentityKeys: null, + notificationIdentityKeys: null, + }; } return state; } -export { setPrimaryIdentityKeys, reducePrimaryIdentityPublicKey }; +export { setPrimaryIdentityKeys, reduceCryptoStore }; diff --git a/web/redux/redux-setup.js b/web/redux/redux-setup.js --- a/web/redux/redux-setup.js +++ b/web/redux/redux-setup.js @@ -13,6 +13,7 @@ import { isLoggedIn } from 'lib/selectors/user-selectors.js'; import { invalidSessionDowngrade } from 'lib/shared/account-utils.js'; import type { Shape } from 'lib/types/core.js'; +import type { CryptoStore, OLMIdentityKeys } from 'lib/types/crypto-types.js'; import type { DraftStore } from 'lib/types/draft-types.js'; import type { EnabledApps } from 'lib/types/enabled-apps.js'; import type { EntryStore } from 'lib/types/entry-types.js'; @@ -39,12 +40,12 @@ updateCalendarCommunityFilter, clearCalendarCommunityFilter, } from './action-types.js'; -import { reduceDeviceID } from './device-id-reducer.js'; -import reduceNavInfo from './nav-reducer.js'; import { - reducePrimaryIdentityPublicKey, + reduceCryptoStore, setPrimaryIdentityKeys, -} from './primary-identity-public-key-reducer.js'; +} from './crypto-store-reducer.js'; +import { reduceDeviceID } from './device-id-reducer.js'; +import reduceNavInfo from './nav-reducer.js'; import { getVisibility } from './visibility.js'; import { filterThreadIDsBelongingToCommunity } from '../selectors/calendar-selectors.js'; import { activeThreadSelector } from '../selectors/nav-selectors.js'; @@ -80,7 +81,7 @@ dataLoaded: boolean, windowActive: boolean, userPolicies: UserPolicies, - primaryIdentityPublicKey: ?string, + cryptoStore: CryptoStore, _persist: ?PersistState, }; @@ -99,7 +100,7 @@ type: 'SET_DEVICE_ID', payload: string, } - | { +type: 'SET_PRIMARY_IDENTITY_KEYS', payload: ?string } + | { +type: 'SET_PRIMARY_IDENTITY_KEYS', payload: ?OLMIdentityKeys } | { +type: 'UPDATE_CALENDAR_COMMUNITY_FILTER', +payload: string, @@ -197,10 +198,7 @@ state.threadStore.threadInfos, ), deviceID: reduceDeviceID(state.deviceID, action), - primaryIdentityPublicKey: reducePrimaryIdentityPublicKey( - state.primaryIdentityPublicKey, - action, - ), + cryptoStore: reduceCryptoStore(state.cryptoStore, action), }; return validateState(oldState, state); diff --git a/web/root.js b/web/root.js --- a/web/root.js +++ b/web/root.js @@ -5,12 +5,13 @@ import { Router, Route } from 'react-router'; import { createStore, applyMiddleware, type Store } from 'redux'; import { composeWithDevTools } from 'redux-devtools-extension/logOnlyInProduction.js'; -import { persistReducer, persistStore } from 'redux-persist'; +import { createMigrate, persistReducer, persistStore } from 'redux-persist'; import { PersistGate } from 'redux-persist/es/integration/react.js'; import storage from 'redux-persist/es/storage/index.js'; import thunk from 'redux-thunk'; import { reduxLoggerMiddleware } from 'lib/utils/action-logger.js'; +import { isDev } from 'lib/utils/dev-utils.js'; import App from './app.react.js'; import ErrorBoundary from './error-boundary.react.js'; @@ -20,16 +21,27 @@ import history from './router-history.js'; import Socket from './socket.react.js'; +const migrations = { + [1]: state => { + const { + primaryIdentityPublicKey, + ...stateWithoutPrimaryIdentityPublicKey + } = state; + return { + ...stateWithoutPrimaryIdentityPublicKey, + cryptoStore: { + primaryIdentityKeys: null, + notificationIdentityKeys: null, + }, + }; + }, +}; const persistConfig = { key: 'root', storage, - whitelist: [ - 'enabledApps', - 'deviceID', - 'draftStore', - 'primaryIdentityPublicKey', - ], - version: 0, + whitelist: ['enabledApps', 'deviceID', 'draftStore'], + migrate: (createMigrate(migrations, { debug: isDev }): any), + version: 1, }; declare var preloadedState: AppState;