import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { isEqual } from 'lodash'; ///: BEGIN:ONLY_INCLUDE_IN(flask) import { isObject } from '@metamask/utils'; import { SnapCaveatType, WALLET_SNAP_PERMISSION_KEY, } from '@metamask/rpc-methods'; ///: END:ONLY_INCLUDE_IN import { MetaMetricsEventCategory } from '../../../../shared/constants/metametrics'; import { PageContainerFooter } from '../../ui/page-container'; import PermissionsConnectFooter from '../permissions-connect-footer'; ///: BEGIN:ONLY_INCLUDE_IN(flask) import { RestrictedMethods } from '../../../../shared/constants/permissions'; ///: END:ONLY_INCLUDE_IN import { PermissionPageContainerContent } from '.'; export default class PermissionPageContainer extends Component { static propTypes = { approvePermissionsRequest: PropTypes.func.isRequired, rejectPermissionsRequest: PropTypes.func.isRequired, selectedIdentities: PropTypes.array, allIdentitiesSelected: PropTypes.bool, ///: BEGIN:ONLY_INCLUDE_IN(flask) currentPermissions: PropTypes.object, ///: END:ONLY_INCLUDE_IN request: PropTypes.object, requestMetadata: PropTypes.object, targetSubjectMetadata: PropTypes.shape({ name: PropTypes.string, origin: PropTypes.string.isRequired, subjectType: PropTypes.string.isRequired, extensionId: PropTypes.string, iconUrl: PropTypes.string, }), }; static defaultProps = { request: {}, requestMetadata: {}, selectedIdentities: [], allIdentitiesSelected: false, ///: BEGIN:ONLY_INCLUDE_IN(flask) currentPermissions: {}, ///: END:ONLY_INCLUDE_IN }; static contextTypes = { t: PropTypes.func, trackEvent: PropTypes.func, }; state = { selectedPermissions: this.getRequestedMethodState( this.getRequestedMethodNames(this.props), ), }; componentDidUpdate() { const newMethodNames = this.getRequestedMethodNames(this.props); if (!isEqual(Object.keys(this.state.selectedPermissions), newMethodNames)) { // this should be a new request, so just overwrite this.setState({ selectedPermissions: this.getRequestedMethodState(newMethodNames), }); } } getRequestedMethodState(methodNames) { return methodNames.reduce((acc, methodName) => { ///: BEGIN:ONLY_INCLUDE_IN(flask) if (methodName === RestrictedMethods.wallet_snap) { acc[methodName] = this.getDedupedSnapPermissions(); return acc; } ///: END:ONLY_INCLUDE_IN acc[methodName] = true; return acc; }, {}); } ///: BEGIN:ONLY_INCLUDE_IN(flask) getDedupedSnapPermissions() { const permission = this.props.request.permissions[WALLET_SNAP_PERMISSION_KEY]; const requestedSnaps = permission?.caveats[0].value; const currentSnaps = this.props.currentPermissions[WALLET_SNAP_PERMISSION_KEY]?.caveats[0] .value; if (!isObject(currentSnaps)) { return permission; } const requestedSnapKeys = requestedSnaps ? Object.keys(requestedSnaps) : []; const currentSnapKeys = currentSnaps ? Object.keys(currentSnaps) : []; const dedupedCaveats = requestedSnapKeys.reduce((acc, snapId) => { if (!currentSnapKeys.includes(snapId)) { acc[snapId] = {}; } return acc; }, {}); return { ...permission, caveats: [{ type: SnapCaveatType.SnapIds, value: dedupedCaveats }], }; } ///: END:ONLY_INCLUDE_IN getRequestedMethodNames(props) { return Object.keys(props.request.permissions || {}); } componentDidMount() { this.context.trackEvent({ category: MetaMetricsEventCategory.Auth, event: 'Tab Opened', properties: { action: 'Connect', legacy_event: true, }, }); } onCancel = () => { const { request, rejectPermissionsRequest } = this.props; rejectPermissionsRequest(request.metadata.id); }; onSubmit = () => { const { request: _request, approvePermissionsRequest, rejectPermissionsRequest, selectedIdentities, } = this.props; const request = { ..._request, permissions: { ..._request.permissions }, approvedAccounts: selectedIdentities.map( (selectedIdentity) => selectedIdentity.address, ), }; Object.keys(this.state.selectedPermissions).forEach((key) => { if (!this.state.selectedPermissions[key]) { delete request.permissions[key]; } }); if (Object.keys(request.permissions).length > 0) { approvePermissionsRequest(request); } else { rejectPermissionsRequest(request.metadata.id); } }; render() { const { requestMetadata, targetSubjectMetadata, selectedIdentities, allIdentitiesSelected, } = this.props; return (
this.onCancel()} cancelText={this.context.t('cancel')} onSubmit={() => this.onSubmit()} submitText={this.context.t('connect')} buttonSizeLarge={false} />
); } }