diff --git a/src/App.tsx b/src/App.tsx
index 2be9298..039f896 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -2,6 +2,7 @@ import * as React from 'react';
import { connect } from 'react-redux';
import { withRouter } from 'react-router';
import { BrowserRouter } from 'react-router-dom';
+import { createSelector } from 'reselect';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import { amber500, amber700, lightBlue500, darkBlack, white } from 'material-ui/styles/colors';
@@ -130,7 +131,7 @@ class App extends React.PureComponent {
};
props: {
- credentials?: store.CredentialsType;
+ credentials: store.CredentialsType;
};
constructor(props: any) {
@@ -170,7 +171,7 @@ class App extends React.PureComponent {
-
+
@@ -178,9 +179,30 @@ class App extends React.PureComponent {
}
}
+const credentialsSelector = createSelector(
+ (state: store.StoreState) => state.credentials.value,
+ (state: store.StoreState) => state.credentials.error,
+ (state: store.StoreState) => state.credentials.fetching,
+ (state: store.StoreState) => state.encryptionKey.key,
+ (value, error, fetching, encryptionKey) => {
+ if (value === null) {
+ return {value, error, fetching};
+ }
+
+ return {
+ error: error,
+ fetching: fetching,
+ value: {
+ ...value,
+ encryptionKey: encryptionKey,
+ }
+ };
+ }
+);
+
const mapStateToProps = (state: store.StoreState) => {
return {
- credentials: state.credentials,
+ credentials: credentialsSelector(state),
};
};
diff --git a/src/LoginGate.tsx b/src/LoginGate.tsx
index 6321e3f..6692261 100644
--- a/src/LoginGate.tsx
+++ b/src/LoginGate.tsx
@@ -1,18 +1,16 @@
import * as React from 'react';
-import { connect } from 'react-redux';
-import { withRouter } from 'react-router';
import Container from './widgets/Container';
import ExternalLink from './widgets/ExternalLink';
import SyncGate from './SyncGate';
import LoginForm from './components/LoginForm';
-import { store, StoreState, CredentialsType } from './store';
+import { store, CredentialsType } from './store';
import { fetchCredentials } from './store/actions';
import * as C from './constants';
-class Root extends React.PureComponent {
+class Root extends React.Component {
props: {
credentials: CredentialsType;
};
@@ -65,13 +63,4 @@ class Root extends React.PureComponent {
}
}
-const mapStateToProps = (state: StoreState) => {
- return {
- credentials: state.credentials,
- };
-};
-
-// FIXME: withRouter is only needed here because of https://github.com/ReactTraining/react-router/issues/5795
-export default withRouter(connect(
- mapStateToProps
-)(Root));
+export default Root;
diff --git a/src/store/index.ts b/src/store/index.ts
index f927dc8..e165e65 100644
--- a/src/store/index.ts
+++ b/src/store/index.ts
@@ -6,13 +6,14 @@ import { createLogger } from 'redux-logger';
import promiseMiddleware from './promise-middleware';
import reducers from './reducers';
-import { CredentialsType, JournalsType, EntriesType } from './reducers';
+import { CredentialsTypeRemote, JournalsType, EntriesType } from './reducers';
export { CredentialsType, CredentialsData, JournalsType, JournalsData, EntriesType, EntriesData } from './reducers';
export interface StoreState {
fetchCount: number;
- credentials: CredentialsType;
+ credentials: CredentialsTypeRemote;
+ encryptionKey: {key: string};
cache: {
journals: JournalsType;
entries: EntriesType;
diff --git a/src/store/reducers.ts b/src/store/reducers.ts
index bacbdf0..ecf373a 100644
--- a/src/store/reducers.ts
+++ b/src/store/reducers.ts
@@ -17,9 +17,12 @@ interface FetchTypeInterface {
error?: Error;
}
-export interface CredentialsData {
+export interface CredentialsDataRemote {
serviceApiUrl: string;
credentials: EteSync.Credentials;
+}
+
+export interface CredentialsData extends CredentialsDataRemote {
encryptionKey: string;
}
@@ -33,6 +36,7 @@ function fetchTypeRecord() {
}
export type CredentialsType = FetchType;
+export type CredentialsTypeRemote = FetchType;
export type JournalsData = List;
@@ -47,23 +51,6 @@ const EntriesFetchRecord = fetchTypeRecord();
export type EntriesTypeImmutable = Map>>;
export type EntriesType = Map>;
-function credentialsIdentityReducer(state: CredentialsType = {value: null}, action: any, extend: boolean = false) {
- if (action.error) {
- return {
- value: null,
- error: action.payload,
- };
- } else {
- const fetching = (action.payload === undefined) ? true : undefined;
- const payload = (action.payload === undefined) ? null : action.payload;
- let value = payload;
- return {
- fetching,
- value,
- };
- }
-}
-
function fetchTypeIdentityReducer(
state: Record> = fetchTypeRecord()(), action: any, extend: boolean = false) {
if (action.error) {
@@ -91,10 +78,50 @@ function fetchTypeIdentityReducer(
}
}
+const encryptionKeyReducer = handleActions(
+ {
+ [actions.fetchCredentials.toString()]: (
+ state: {key: string | null}, action: any) => {
+ if (action.error) {
+ return {key: null};
+ } else if (action.payload === undefined) {
+ return {key: null};
+ } else {
+ return {key: action.payload.encryptionKey};
+ }
+ },
+ [actions.logout.toString()]: (state: {key: string | null}, action: any) => {
+ return {out: true, key: null};
+ },
+ },
+ {key: null}
+);
+
const credentials = handleActions(
{
- [actions.fetchCredentials.toString()]: credentialsIdentityReducer,
- [actions.logout.toString()]: (state: CredentialsType, action: any) => {
+ [actions.fetchCredentials.toString()]: (
+ state: CredentialsTypeRemote, action: any, extend: boolean = false) => {
+ if (action.error) {
+ return {
+ value: null,
+ error: action.payload,
+ };
+ } else if (action.payload === undefined) {
+ return {
+ fetching: true,
+ value: null,
+ };
+ } else {
+ const {
+ encryptionKey, // We don't want to set encryption key here.
+ ...payload
+ } = action.payload;
+ return {
+ value: payload,
+ };
+ }
+ },
+ [actions.logout.toString()]: (state: CredentialsTypeRemote, action: any) => {
return {out: true, value: null};
},
},
@@ -159,10 +186,15 @@ const fetchCount = handleAction(
const credentialsPersistConfig = {
key: 'credentials',
- storage: session,
+ storage: localforage,
whitelist: ['value'],
};
+const encryptionKeyPersistConfig = {
+ key: 'encryptionKey',
+ storage: session,
+};
+
const journalsSerialize = (state: JournalsData) => {
if (state === null) {
return null;
@@ -240,6 +272,7 @@ const cachePersistConfig = {
const reducers = combineReducers({
fetchCount,
credentials: persistReducer(credentialsPersistConfig, credentials),
+ encryptionKey: persistReducer(encryptionKeyPersistConfig, encryptionKeyReducer),
cache: persistReducer(cachePersistConfig, combineReducers({
entries,
journals,