Skip to content

Commit 357069f

Browse files
committed
auth: display the auth page for unauthenticated API responses
1 parent f1735f3 commit 357069f

File tree

12 files changed

+75
-34
lines changed

12 files changed

+75
-34
lines changed

app/src/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ const App = () => {
1414
<ThemeProvider>
1515
<Layout>
1616
<Pages />
17-
<AlertContainer />
1817
</Layout>
18+
<AlertContainer />
1919
</ThemeProvider>
2020
</StoreProvider>
2121
);

app/src/api/grpc.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { ProtobufMessage } from '@improbable-eng/grpc-web/dist/typings/message';
33
import { Metadata } from '@improbable-eng/grpc-web/dist/typings/metadata';
44
import { UnaryMethodDefinition } from '@improbable-eng/grpc-web/dist/typings/service';
55
import { DEV_HOST } from 'config';
6+
import { AuthenticationError } from 'util/errors';
67
import { grpcLog as log } from 'util/log';
78

89
class GrpcClient {
@@ -32,6 +33,8 @@ class GrpcClient {
3233
if (status === grpc.Code.OK && message) {
3334
log.debug(' - message', message.toObject());
3435
resolve(message as TRes);
36+
} else if (status === grpc.Code.Unauthenticated) {
37+
reject(new AuthenticationError(`${statusMessage}`));
3538
} else {
3639
reject(new Error(`${status}: ${statusMessage}`));
3740
}

app/src/i18n/locales/en-US.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,7 @@
6363
"cmps.settings.GeneralSettings.balancesValue": "Optimize for {{mode}}",
6464
"cmps.settings.GeneralSettings.pageTitle": "Settings",
6565
"cmps.settings.UnitSettings.pageTitle": "Bitcoin Unit",
66-
"cmps.settings.UnitSettings.backText": "Settings"
66+
"cmps.settings.UnitSettings.backText": "Settings",
67+
"stores.uiStore.authErrorTitle": "Your session has expired",
68+
"stores.uiStore.authErrorMsg": "Please enter you password to continue"
6769
}

app/src/store/store.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { observable, when } from 'mobx';
1+
import { autorun, observable } from 'mobx';
22
import { IS_DEV, IS_TEST } from 'config';
33
import AppStorage from 'util/appStorage';
44
import CsvExporter from 'util/csv';
@@ -70,19 +70,23 @@ export class Store {
7070
await this.authStore.init();
7171
this.initialized = true;
7272

73-
// go to the Loop page when the user is authenticated. it can be from
74-
// entering a password or from loading the credentials from storage
75-
when(
76-
() => this.authStore.authenticated,
77-
async () => {
73+
// this function will automatically run whenever the authenticated
74+
// flag is changed
75+
autorun(async () => {
76+
if (this.authStore.authenticated) {
77+
// go to the Loop page when the user is authenticated. it can be from
78+
// entering a password or from loading the credentials from storage
7879
this.uiStore.goToLoop();
7980
// also fetch all the data we need
8081
await this.nodeStore.fetchInfo();
8182
await this.channelStore.fetchChannels();
8283
await this.swapStore.fetchSwaps();
8384
await this.nodeStore.fetchBalances();
84-
},
85-
);
85+
} else {
86+
// go to auth page if we are not authenticated
87+
this.uiStore.gotoAuth();
88+
}
89+
});
8690
}
8791
}
8892

app/src/store/stores/authStore.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { action, observable, toJS } from 'mobx';
1+
import { action, observable } from 'mobx';
22
import { Store } from 'store';
33

44
export default class AuthStore {
@@ -54,7 +54,8 @@ export default class AuthStore {
5454
async validate() {
5555
// test the credentials by making an API call to getInfo
5656
await this._store.api.lnd.getInfo();
57-
this._store.log.info('authentication successful', toJS(this));
57+
this._store.log.info('authentication successful');
58+
// setting this to true will automatically show the Loop page
5859
this.authenticated = true;
5960
}
6061

app/src/store/stores/buildSwapStore.ts

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -281,9 +281,8 @@ class BuildSwapStore {
281281
}
282282
});
283283
} catch (error) {
284-
runInAction('getTermsError', () => {
285-
this._store.uiStore.notify(error.message, 'Unable to fetch Loop Terms');
286-
});
284+
this._store.uiStore.handleError(error, 'Unable to fetch Loop Terms');
285+
this.goToPrevStep();
287286
}
288287
}
289288

@@ -310,9 +309,8 @@ class BuildSwapStore {
310309
this._store.log.info('updated buildSwapStore.quote', toJS(this.quote));
311310
});
312311
} catch (error) {
313-
runInAction('getQuoteError', () => {
314-
this._store.uiStore.notify(error.message, 'Unable to fetch Quote');
315-
});
312+
this._store.uiStore.handleError(error, 'Unable to fetch Quote');
313+
this.goToPrevStep();
316314
}
317315
}
318316

@@ -350,10 +348,8 @@ class BuildSwapStore {
350348
this._store.swapStore.fetchSwaps();
351349
});
352350
} catch (error) {
353-
runInAction('requestSwapError', () => {
354-
this._store.uiStore.notify(error.message, `Unable to Perform ${direction}`);
355-
this.goToPrevStep();
356-
});
351+
this._store.uiStore.handleError(error, `Unable to Perform ${direction}`);
352+
this.goToPrevStep();
357353
}
358354
}, delay);
359355
}

app/src/store/stores/channelStore.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,7 @@ export default class ChannelStore {
7979
this._store.log.info('updated channelStore.channels', toJS(this.channels));
8080
});
8181
} catch (error) {
82-
runInAction('fetchChannelsError', () => {
83-
this._store.uiStore.notify(error.message, 'Unable to fetch Channels');
84-
});
82+
this._store.uiStore.handleError(error, 'Unable to fetch Channels');
8583
}
8684
}
8785

app/src/store/stores/nodeStore.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,7 @@ export default class NodeStore {
4242
this._store.log.info('updated nodeStore info', toJS(this));
4343
});
4444
} catch (error) {
45-
runInAction('getInfoError', () => {
46-
this._store.uiStore.notify(error.message, 'Unable to fetch node info');
47-
});
45+
this._store.uiStore.handleError(error, 'Unable to fetch node info');
4846
}
4947
}
5048

@@ -63,9 +61,7 @@ export default class NodeStore {
6361
this._store.log.info('updated nodeStore.wallet', toJS(this.wallet));
6462
});
6563
} catch (error) {
66-
runInAction('fetchBalancesError', () => {
67-
this._store.uiStore.notify(error.message, 'Unable to fetch balances');
68-
});
64+
this._store.uiStore.handleError(error, 'Unable to fetch balances');
6965
}
7066
}
7167
}

app/src/store/stores/swapStore.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,8 @@ export default class SwapStore {
106106
this._store.log.info('updated swapStore.swaps', toJS(this.swaps));
107107
});
108108
} catch (error) {
109-
runInAction('fetchSwapsError', () => {
110-
this._store.uiStore.notify(error.message, 'Unable to fetch Swaps');
111-
});
109+
this._store.uiStore.handleError(error, 'Unable to fetch Swaps');
110+
if (this.pollingInterval) this.stopPolling();
112111
}
113112
}
114113

app/src/store/stores/uiStore.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import { action, observable, toJS } from 'mobx';
22
import { Alert } from 'types/state';
3+
import { AuthenticationError } from 'util/errors';
4+
import { prefixTranslation } from 'util/translate';
35
import { Store } from 'store';
46

7+
const { l } = prefixTranslation('stores.uiStore');
8+
59
type PageName = 'auth' | 'loop' | 'history' | 'settings';
610

711
type SettingName = 'general' | 'unit' | 'balance';
@@ -22,6 +26,13 @@ export default class UiStore {
2226
this._store = store;
2327
}
2428

29+
/** Change to the Auth page */
30+
@action.bound
31+
gotoAuth() {
32+
this.page = 'auth';
33+
this._store.log.info('Go to the Auth page');
34+
}
35+
2536
/** Change to the Loop page */
2637
@action.bound
2738
goToLoop() {
@@ -72,4 +83,15 @@ export default class UiStore {
7283
this.alerts.delete(id);
7384
this._store.log.info('Cleared alert', id, toJS(this.alerts));
7485
}
86+
87+
/** handle errors by showing a notification and/or the auth screen */
88+
handleError(error: Error, title?: string) {
89+
if (error instanceof AuthenticationError) {
90+
// this will automatically redirect to the auth page
91+
this._store.authStore.authenticated = false;
92+
this.notify(l('authErrorMsg'), l('authErrorTitle'));
93+
} else {
94+
this.notify(error.message, title);
95+
}
96+
}
7597
}

0 commit comments

Comments
 (0)