/* * Wire * Copyright (C) 2023 Wire Swiss GmbH * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * */ import React, {useState} from 'react'; import {OAuthClient} from '@wireapp/api-client/lib/oauth/OAuthClient'; import {FormattedMessage} from 'react-intl'; import {connect} from 'react-redux'; import {AnyAction, Dispatch} from 'redux'; import {container} from 'tsyringe'; import { Button, ButtonVariant, ContainerXS, Text, Paragraph, Box, Link, LinkVariant, COLOR_V2, H2, QUERY, useMatchMedia, } from '@wireapp/react-ui-kit'; import * as Icon from 'Components/Icon'; import {AssetRemoteData} from 'src/script/assets/AssetRemoteData'; import {AssetRepository} from 'src/script/assets/AssetRepository'; import {handleEscDown, handleKeyDown} from 'Util/KeyboardUtil'; import {t} from 'Util/LocalizerUtil'; import {loadDataUrl} from 'Util/util'; import { boxCSS, buttonCSS, buttonsCSS, containerCSS, headerCSS, listCSS, mobileButtonsCSS, mobileButtonCSS, mobileTextCSS, teamImageCSS, textCSS, } from './OauthPermissions.styles'; import {Page} from './Page'; import {Config} from '../../Config'; import {actionRoot} from '../module/action'; import {bindActionCreators, RootState} from '../module/reducer'; import * as SelfSelector from '../module/selector/SelfSelector'; import {oAuthParams, oAuthScope, oAuthScopesToString} from '../util/oauthUtil'; interface Props extends React.HTMLProps { assetRepository?: AssetRepository; } export enum Scope { WRITE_CONVERSATIONS = 'write:conversations', WRITE_CONVERSATIONS_CODE = 'write:conversations_code', READ_SELF = 'read:self', READ_FEATURE_CONFIGS = 'read:feature_configs', } const scopeText: Record = { [Scope.WRITE_CONVERSATIONS]: t('oauth.scope.write_conversations'), [Scope.WRITE_CONVERSATIONS_CODE]: t('oauth.scope.write_conversations_code'), [Scope.READ_SELF]: t('oauth.scope.read_self'), [Scope.READ_FEATURE_CONFIGS]: t('oauth.scope.read_feature_configs'), }; const OAuthPermissionsComponent = ({ doLogout, getOAuthApp, selfUser, selfTeamId, assetRepository = container.resolve(AssetRepository), postOauthCode, getSelf, getTeam, }: Props & ConnectedProps & DispatchProps) => { const [teamImage, setTeamImage] = React.useState(undefined); const isMobile = useMatchMedia(QUERY.mobile); const [oAuthApp, setOAuthApp] = useState(null); const oauthParams = oAuthParams(window.location); const oauthScope = oAuthScope(oauthParams); const cleanedScopes = oAuthScopesToString(oauthScope); const onContinue = async () => { try { const url = await postOauthCode({...oauthParams, scope: cleanedScopes}); window.location.replace(url); } catch (error) { console.error(error); } }; const onCancel = () => { window.location.replace(`${oauthParams.redirect_uri}?error=access_denied`); }; React.useEffect(() => { const getUserData = async () => { await getSelf(); if (selfTeamId) { const team = await getTeam(selfTeamId); const teamIcon = AssetRemoteData.v3(team.icon, selfUser.qualified_id?.domain); if (teamIcon.identifier === 'default') { setTeamImage(`${Config.getConfig().APP_BASE}/image/logo/wire-logo-120.png`); } else { const teamImageBlob = await assetRepository.load(teamIcon); setTeamImage(teamImageBlob && (await loadDataUrl(teamImageBlob))); } } if (oauthParams.client_id) { setOAuthApp(!!oauthParams.client_id ? await getOAuthApp(oauthParams.client_id) : null); } else { throw Error('OAuth client not found'); } }; getUserData().catch(error => { console.error(error); if (error.message === 'OAuth client not found') { window.location.replace('/'); } else { doLogout().catch(error => { console.error(error); }); } }); }, [ assetRepository, doLogout, getOAuthApp, getSelf, getTeam, oauthParams.client_id, selfTeamId, selfUser.qualified_id?.domain, ]); return ( {!oAuthApp ? ( ) : ( <>

{t('oauth.headline')}

{typeof teamImage === 'string' && teamIcon} {selfUser.email} {t('oauth.logout')} {t('oauth.subhead')} {oauthParams.scope.length > 1 && (
    {oauthScope.map((scope, index) => (
  • {scopeText[scope]}
  • ))}
( {chunks} ), }} />
)} {t('oauth.details')}
( {chunks} ), }} /> )}
); }; type ConnectedProps = ReturnType; const mapStateToProps = (state: RootState) => ({ selfUser: SelfSelector.getSelf(state), selfTeamId: SelfSelector.getSelfTeamId(state), }); type DispatchProps = ReturnType; const mapDispatchToProps = (dispatch: Dispatch) => bindActionCreators( { getSelf: actionRoot.selfAction.fetchSelf, getOAuthApp: actionRoot.authAction.doGetOAuthApplication, doLogout: actionRoot.authAction.doLogout, getTeam: actionRoot.authAction.doGetTeamData, postOauthCode: actionRoot.authAction.doPostOAuthCode, }, dispatch, ); const OAuthPermissions = connect(mapStateToProps, mapDispatchToProps)(OAuthPermissionsComponent); export {OAuthPermissions};