From c44f1cf93da383e58cb1e30a55570fcb4f738ca8 Mon Sep 17 00:00:00 2001 From: Leo Joseph <58416454+rleojoseph@users.noreply.github.com> Date: Fri, 6 Jan 2023 11:18:55 +0900 Subject: [PATCH] [MINI-5706] Fix for Access Token permission issue (#238) * Fix for Access Token permission issue --- .github/CODEOWNERS | 2 +- .github/pull_request_template | 2 +- js-miniapp-sample/src/pages/auth-token.js | 110 ++++++++++-------- .../src/services/permissions/actions.js | 9 +- .../src/services/permissions/reducers.js | 36 ++++-- js-miniapp-sample/src/services/reducers.js | 4 +- 6 files changed, 100 insertions(+), 63 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c2fb4a985..fc6bfb6da 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,3 +1,3 @@ # See https://help.github.com/en/articles/about-code-owners -@rakutentech/miniapp-technology +* @rakutentech/miniapp-technology diff --git a/.github/pull_request_template b/.github/pull_request_template index 004a4abf9..321601e3d 100644 --- a/.github/pull_request_template +++ b/.github/pull_request_template @@ -6,4 +6,4 @@ Explain your rationale of technical decisions you made (unless discussed before) Add links to github/jira issues, design documents and other relevant resources (e.g. previous discussions, platform/tool documentation etc.) # Checklist -- [ ] I have completed all steps in the [Contribution Checklist](../.github/CONTRIBUTING.md#checklist) +- [ ] I have completed all steps in the [Contribution Checklist](../blob/master.github/CONTRIBUTING.md#checklist) diff --git a/js-miniapp-sample/src/pages/auth-token.js b/js-miniapp-sample/src/pages/auth-token.js index 1dfbc84d5..d6fa0d235 100644 --- a/js-miniapp-sample/src/pages/auth-token.js +++ b/js-miniapp-sample/src/pages/auth-token.js @@ -6,7 +6,6 @@ import { FormGroup, Typography, CardContent, - ListItemText, FormControl, TextField, } from '@material-ui/core'; @@ -19,6 +18,7 @@ import { CustomPermissionName, CustomPermissionStatus, AccessTokenData, + MiniAppError, } from 'js-miniapp-sdk'; import { connect } from 'react-redux'; @@ -70,37 +70,45 @@ const useStyles = makeStyles((theme) => ({ const initialState = { isLoading: false, isError: false, - hasRequestedPermissions: false, error: null, + permissionDenied: false, }; const dataFetchReducer = (state, action) => { switch (action.type) { - case 'FETCH_INIT': + case 'TOKEN_FETCH_INIT': return { ...state, isLoading: true, isError: false, - hasRequestedPermissions: false, error: null, + permissionDenied: false, }; - case 'FETCH_SUCCESS': + case 'TOKEN_FETCH_SUCCESS': return { ...state, isLoading: false, isError: false, - hasRequestedPermissions: true, error: null, + permissionDenied: false, }; - case 'FETCH_FAILURE': + case 'TOKEN_FETCH_FAILURE': return { ...state, isLoading: false, isError: true, error: - (typeof action.miniAppError == 'string' - ? action.miniAppError - : action.miniAppError.message) || '', + (typeof action.error == 'string' + ? action.error + : action.error.message) || '', + }; + case 'PERMISSION_FAILURE': + return { + ...state, + isLoading: false, + isError: false, + error: null, + permissionDenied: true, }; default: throw new Error(); @@ -110,6 +118,7 @@ const dataFetchReducer = (state, action) => { type AuthTokenProps = { permissions: CustomPermissionName[], accessToken: AccessTokenData, + error: MiniAppError, getAccessToken: (audience: string, scopes: string[]) => Promise, requestPermissions: ( permissions: CustomPermission[] @@ -152,19 +161,17 @@ function AuthToken(props: AuthTokenProps) { permission.status === CustomPermissionStatus.ALLOWED ) .map((permission) => permission.name); + if (!hasPermission(CustomPermissionName.ACCESS_TOKEN, permissions)) { + requestAccessToken(); + } else { + dispatch({ type: 'PERMISSION_FAILURE', permissionDenied: true }); + } + } else { + dispatch({ type: 'PERMISSION_FAILURE', permissionDenied: true }); } }) - .then((permissions) => - Promise.all([ - hasPermission(CustomPermissionName.ACCESS_TOKEN, permissions) - ? props.getAccessToken(scope.audience, scope.scopes) - : null, - ]) - ) - .then(() => dispatch({ type: 'FETCH_SUCCESS' })) - .catch((miniAppError) => { - console.error(miniAppError); - dispatch({ type: 'FETCH_FAILURE', miniAppError }); + .catch((error) => { + dispatch({ type: 'PERMISSION_FAILURE', permissionDenied: true }); }); } @@ -173,10 +180,21 @@ function AuthToken(props: AuthTokenProps) { return permissionList.indexOf(permission) > -1; } + function requestAccessToken() { + props + .getAccessToken(scope.audience, scope.scopes) + .then((permissions) => { + dispatch({ type: 'TOKEN_FETCH_SUCCESS' }); + }) + .catch((e) => { + dispatch({ type: 'TOKEN_FETCH_FAILURE', error: e }); + }); + } + function handleClick(e) { if (!state.isLoading) { e.preventDefault(); - dispatch({ type: 'FETCH_INIT' }); + dispatch({ type: 'TOKEN_FETCH_INIT' }); requestAccessTokenPermission(); } } @@ -201,19 +219,6 @@ function AuthToken(props: AuthTokenProps) { ); } - function AccessToken() { - const hasDeniedPermission = - state.hasRequestedPermissions && - !hasPermission(CustomPermissionName.ACCESS_TOKEN); - - return hasDeniedPermission ? ( - - ) : null; - } - return ( @@ -239,30 +244,41 @@ function AuthToken(props: AuthTokenProps) { {ButtonWrapper()} - {!state.isLoading && !state.isError && props.accessToken && ( - - Token: {props.accessToken.token} - - )} - {!state.isLoading && !state.isError && props.accessToken && ( - - Valid until: {displayDate(props.accessToken.validUntil)} + {!state.isLoading && + !state.isError && + !state.permissionDenied && + props.accessToken && ( + + Token: {props.accessToken.token} + + )} + {!state.isLoading && + !state.isError && + !state.permissionDenied && + props.accessToken && ( + + Valid until: {displayDate(props.accessToken.validUntil)} + + )} + {!state.isLoading && state.isError && !state.permissionDenied && ( + + {state.error} )} - {!state.isLoading && state.isError && ( + {!state.isLoading && state.permissionDenied && ( - Something went wrong, please try again later. + ACCESS_TOKEN Permission is denied by the user )} -
{AccessToken()}
); } -const mapStateToProps = (state) => { +const mapStateToProps = (state, props) => { return { + ...props, permissions: state.permissions, accessToken: state.user.accessToken, error: state.error, diff --git a/js-miniapp-sample/src/services/permissions/actions.js b/js-miniapp-sample/src/services/permissions/actions.js index 09ac1e95c..d89c6a44c 100644 --- a/js-miniapp-sample/src/services/permissions/actions.js +++ b/js-miniapp-sample/src/services/permissions/actions.js @@ -1,6 +1,7 @@ import MiniApp, { CustomPermission, CustomPermissionResult, + MiniAppError, } from 'js-miniapp-sdk'; import { @@ -8,9 +9,10 @@ import { REQUEST_PERMISSIONS_FAILURE, } from './types'; -type PermissionsSuccessAction = { +type PermissionsAction = { type: String, permissions: CustomPermissionResult[], + error: MiniAppError }; const requestCustomPermissions = ( @@ -26,13 +28,14 @@ const requestCustomPermissions = ( return permissions; }) - .catch((_) => { + .catch((e) => { dispatch({ type: REQUEST_PERMISSIONS_FAILURE, + error: e, }); }); }; }; export { requestCustomPermissions }; -export type { PermissionsSuccessAction }; +export type { PermissionsAction }; diff --git a/js-miniapp-sample/src/services/permissions/reducers.js b/js-miniapp-sample/src/services/permissions/reducers.js index c07d4bf5d..9f319b469 100644 --- a/js-miniapp-sample/src/services/permissions/reducers.js +++ b/js-miniapp-sample/src/services/permissions/reducers.js @@ -1,13 +1,23 @@ import { CustomPermissionName, CustomPermissionStatus } from 'js-miniapp-sdk'; -import type { PermissionsSuccessAction } from './actions'; -import { REQUEST_PERMISSIONS_SUCCESS } from './types'; +import type { PermissionsAction } from './actions'; +import { REQUEST_PERMISSIONS_SUCCESS, REQUEST_PERMISSIONS_FAILURE } from './types'; -const defaultState: CustomPermissionName[] = []; +type PermissionsState = { + type: REQUEST_PERMISSIONS_FAILURE, + permissions: CustomPermissionResult[], + error: MiniAppError +}; + +const defaultState: PermissionsState = { + type: undefined, + permissions: [], + error: null +}; -const grantedPermissionsReducer = ( +const PermissionsReducer = ( state: CustomPermissionName[] = defaultState, - action: PermissionsSuccessAction + action: PermissionsAction ): CustomPermissionName[] => { switch (action.type) { case REQUEST_PERMISSIONS_SUCCESS: @@ -17,15 +27,23 @@ const grantedPermissionsReducer = ( const allowed = action.permissions .filter((it) => it.status === CustomPermissionStatus.ALLOWED) .map((it) => it.name); - - const array = state + const array = state.permissions .concat(allowed) .filter((permission) => denied.indexOf(permission) <= -1); - return Array.from(new Set(array)); + return { + type: REQUEST_PERMISSIONS_SUCCESS, + permissions: array, + error: action.error, + }; + case REQUEST_PERMISSIONS_FAILURE: + return { + ...defaultState, + error: action.error, + }; default: return state; } }; -export { grantedPermissionsReducer }; +export { PermissionsReducer }; diff --git a/js-miniapp-sample/src/services/reducers.js b/js-miniapp-sample/src/services/reducers.js index a30921048..78b6516e9 100644 --- a/js-miniapp-sample/src/services/reducers.js +++ b/js-miniapp-sample/src/services/reducers.js @@ -7,7 +7,7 @@ import { SecureStorageStatusReducer, } from './landing/reducers'; import MessageReducer from './message/reducers'; -import { grantedPermissionsReducer } from './permissions/reducers'; +import { PermissionsReducer } from './permissions/reducers'; import storageReducer from './secure-storage/reducers'; import userReducer from './user/reducers'; import { UUIDReducer } from './uuid/reducers'; @@ -15,7 +15,7 @@ import { UUIDReducer } from './uuid/reducers'; export default combineReducers({ message: MessageReducer, home: HomeStateReducer, - permissions: grantedPermissionsReducer, + permissions: PermissionsReducer, user: userReducer, uuid: UUIDReducer, info: HostEnvironmentInfoReducer,