Skip to content

Commit

Permalink
Rupato/BOT-1935/Handle-invalid-access-token (#16190)
Browse files Browse the repository at this point in the history
* fix: google drive issue

* fix: goodle drive error

* fix: renamed observables

* fix: added localize

* fix: added error message on the load modal popup

* fix: added error message on the load modal popup

* fix: removed google drive api call and handled with response of sign in

* fix: handled local storage check

* fix: handled naming

* fix: removed css

* fix: added file check

* fix: added refresh token

* fix: changed function return
  • Loading branch information
rupato-deriv authored Jul 30, 2024
1 parent de3dfc4 commit 39032b6
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export const notification_message = {
[NOTIFICATION_TYPE.BOT_IMPORT]: localize('You’ve successfully imported a bot.'),
[NOTIFICATION_TYPE.BOT_DELETE]: localize('You’ve successfully deleted a bot.'),
strategy_conversion: localize('Save this strategy as an XML file from Deriv Bot for faster re-imports.'),
google_drive_error: localize('Your session has expired. Please sign in again.'),
};

export const notification_style = {
Expand Down
53 changes: 47 additions & 6 deletions packages/bot-web-ui/src/stores/google-drive-store.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { action, makeObservable, observable } from 'mobx';
import { config, importExternal } from '@deriv/bot-skeleton';
import { config, importExternal, observer as globalObserver } from '@deriv/bot-skeleton';
import { getLanguage, localize } from '@deriv/translations';
import { NOTIFICATION_TYPE } from 'Components/bot-notification/bot-notification-utils';
import { notification_message, NOTIFICATION_TYPE } from 'Components/bot-notification/bot-notification-utils';
import { button_status } from 'Constants/button-status';
import {
rudderStackSendUploadStrategyCompletedEvent,
rudderStackSendUploadStrategyFailedEvent,
} from '../analytics/rudderstack-common-events';
import { getStrategyType } from '../analytics/utils';
import RootStore from './root-store';
import { botNotification } from 'Components/bot-notification/bot-notification';

export type TErrorWithStatus = Error & { status?: number; result?: { error: { message: string } } };

Expand Down Expand Up @@ -46,6 +47,8 @@ export interface IGoogleDriveStore {
title: string,
callback: (data: TPickerCallbackResponse) => void
) => void;
is_google_drive_token_valid: boolean;
setGoogleDriveTokenValid: (is_authenticated: boolean) => void;
}

export default class GoogleDriveStore implements IGoogleDriveStore {
Expand All @@ -65,6 +68,7 @@ export default class GoogleDriveStore implements IGoogleDriveStore {
makeObservable(this, {
is_authorised: observable,
upload_id: observable,
is_google_drive_token_valid: observable,
updateSigninStatus: action.bound,
saveFile: action.bound,
loadFile: action.bound,
Expand All @@ -77,6 +81,8 @@ export default class GoogleDriveStore implements IGoogleDriveStore {
createSaveFilePicker: action.bound,
createLoadFilePicker: action.bound,
showGoogleDriveFilePicker: action.bound,
setGoogleDriveTokenValid: action.bound,
verifyGoogleDriveAccessToken: action.bound,
});

this.root_store = root_store;
Expand All @@ -88,8 +94,13 @@ export default class GoogleDriveStore implements IGoogleDriveStore {
importExternal('https://apis.google.com/js/api.js').then(() => this.initialise());
}

is_google_drive_token_valid = true;
is_authorised = !!localStorage.getItem('google_access_token');

setGoogleDriveTokenValid = (is_google_drive_token_valid: boolean) => {
this.is_google_drive_token_valid = is_google_drive_token_valid;
};

setKey = () => {
const { SCOPE, DISCOVERY_DOCS } = config.GOOGLE_DRIVE;
this.client_id = process.env.GD_CLIENT_ID;
Expand All @@ -103,15 +114,22 @@ export default class GoogleDriveStore implements IGoogleDriveStore {
gapi.load('client:picker', () => gapi.client.load(this.discovery_docs));
};

setGoogleDriveTokenExpiry = (seconds: number) => {
const currentEpochTime = Math.floor(Date.now() / 1000);
const expiry_time = currentEpochTime + seconds;
localStorage.setItem('google_access_token_expiry', expiry_time.toString());
};

initialiseClient = () => {
this.client = google.accounts.oauth2.initTokenClient({
client_id: this.client_id,
scope: this.scope,
callback: (response: { access_token: string; error?: TErrorWithStatus }) => {
callback: (response: { expires_in: number; access_token: string; error?: TErrorWithStatus }) => {
if (response?.access_token && !response?.error) {
this.access_token = response.access_token;
this.updateSigninStatus(true);
localStorage.setItem('google_access_token', response.access_token);
this.setGoogleDriveTokenExpiry(response?.expires_in);
}
},
});
Expand All @@ -121,6 +139,28 @@ export default class GoogleDriveStore implements IGoogleDriveStore {
this.is_authorised = is_signed_in;
}

verifyGoogleDriveAccessToken = async () => {
const expiry_time = localStorage?.getItem('google_access_token_expiry');
if (expiry_time) {
const current_epoch_time = Math.floor(Date.now() / 1000);
if (current_epoch_time > Number(expiry_time)) {
try {
//request new access token if invalid
await this.client.requestAccessToken({ prompt: '' });
} catch (error) {
this.signOut();
this.setGoogleDriveTokenValid(false);
localStorage.removeItem('google_access_token_expiry');
botNotification(notification_message.google_drive_error, undefined, {
closeButton: false,
});
return 'not_verified';
}
}
}
return 'verified';
};

async signIn() {
if (!this.is_authorised) {
await this.client.requestAccessToken();
Expand All @@ -129,9 +169,9 @@ export default class GoogleDriveStore implements IGoogleDriveStore {

async signOut() {
if (this.access_token) {
await gapi.client.setToken({ access_token: '' });
await google.accounts.oauth2.revoke(this.access_token);
localStorage.removeItem('google_access_token');
await window?.gapi?.client?.setToken({ access_token: '' });
await window?.google?.accounts?.oauth2?.revoke(this.access_token);
localStorage?.removeItem('google_access_token');
this.access_token = '';
}
this.updateSigninStatus(false);
Expand Down Expand Up @@ -163,6 +203,7 @@ export default class GoogleDriveStore implements IGoogleDriveStore {
}

async loadFile() {
if (!this.is_google_drive_token_valid) return;
await this.signIn();

if (this.access_token) gapi.client.setToken({ access_token: this.access_token });
Expand Down
9 changes: 8 additions & 1 deletion packages/bot-web-ui/src/stores/load-modal-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -358,12 +358,19 @@ export default class LoadModalStore implements ILoadModalStore {

onDriveOpen = async () => {
const { google_drive } = this.root_store;
const { verifyGoogleDriveAccessToken } = google_drive;
const result = await verifyGoogleDriveAccessToken();
if (result === 'not_verified') return;

if (google_drive) {
google_drive.upload_id = uuidv4();
}
rudderStackSendUploadStrategyStartEvent({ upload_provider: 'google_drive', upload_id: google_drive.upload_id });
const { loadFile } = this.root_store.google_drive;
const { xml_doc, file_name } = await loadFile();
const load_file = await loadFile();
if (!load_file) return;
const xml_doc = load_file?.xml;
const file_name = load_file?.name;
await load({
block_string: xml_doc,
file_name,
Expand Down

0 comments on commit 39032b6

Please sign in to comment.