1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

Prevent external domains from submitting more than one perm request at a time (#8148)

This commit is contained in:
Erik Marks 2020-03-06 07:49:35 -08:00 committed by GitHub
parent 293741766f
commit 0775c61f09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -44,6 +44,8 @@ export class PermissionsController {
restrictedMethods: Object.keys(this._restrictedMethods), restrictedMethods: Object.keys(this._restrictedMethods),
store: this.store, store: this.store,
}) })
this.pendingApprovals = new Map()
this.pendingApprovalOrigins = new Set()
this._initializePermissions(restoredPermissions) this._initializePermissions(restoredPermissions)
} }
@ -137,7 +139,7 @@ export class PermissionsController {
async approvePermissionsRequest (approved, accounts) { async approvePermissionsRequest (approved, accounts) {
const { id } = approved.metadata const { id } = approved.metadata
const approval = this.pendingApprovals[id] const approval = this.pendingApprovals.get(id)
if (!approval) { if (!approval) {
log.warn(`Permissions request with id '${id}' not found`) log.warn(`Permissions request with id '${id}' not found`)
@ -158,7 +160,7 @@ export class PermissionsController {
})) }))
} }
delete this.pendingApprovals[id] this._removePendingApproval(id)
} }
/** /**
@ -167,7 +169,7 @@ export class PermissionsController {
* @param {string} id - the id of the rejected request * @param {string} id - the id of the rejected request
*/ */
async rejectPermissionsRequest (id) { async rejectPermissionsRequest (id) {
const approval = this.pendingApprovals[id] const approval = this.pendingApprovals.get(id)
if (!approval) { if (!approval) {
log.warn(`Permissions request with id '${id}' not found`) log.warn(`Permissions request with id '${id}' not found`)
@ -175,7 +177,7 @@ export class PermissionsController {
} }
approval.reject(ethErrors.provider.userRejectedRequest()) approval.reject(ethErrors.provider.userRejectedRequest())
delete this.pendingApprovals[id] this._removePendingApproval(id)
} }
/** /**
@ -385,6 +387,38 @@ export class PermissionsController {
}) })
} }
/**
* Adds a pending approval.
* @param {string} id - The id of the pending approval.
* @param {string} origin - The origin of the pending approval.
* @param {Function} resolve - The function resolving the pending approval Promise.
* @param {Function} reject - The function rejecting the pending approval Promise.
*/
_addPendingApproval (id, origin, resolve, reject) {
if (
this.pendingApprovalOrigins.has(origin) ||
this.pendingApprovals.has(id)
) {
throw new Error(
`Pending approval with id ${id} or origin ${origin} already exists.`
)
}
this.pendingApprovals.set(id, { origin, resolve, reject })
this.pendingApprovalOrigins.add(origin)
}
/**
* Removes the pending approval with the given id.
* @param {string} id - The id of the pending approval to remove.
*/
_removePendingApproval (id) {
const { origin } = this.pendingApprovals.get(id)
this.pendingApprovalOrigins.delete(origin)
this.pendingApprovals.delete(id)
}
/** /**
* A convenience method for retrieving a login object * A convenience method for retrieving a login object
* or creating a new one if needed. * or creating a new one if needed.
@ -396,8 +430,6 @@ export class PermissionsController {
// these permission requests are almost certainly stale // these permission requests are almost certainly stale
const initState = { ...restoredState, permissionsRequests: [] } const initState = { ...restoredState, permissionsRequests: [] }
this.pendingApprovals = {}
this.permissions = new RpcCap({ this.permissions = new RpcCap({
// Supports passthrough methods: // Supports passthrough methods:
@ -418,12 +450,18 @@ export class PermissionsController {
* @param {string} req - The internal rpc-cap user request object. * @param {string} req - The internal rpc-cap user request object.
*/ */
requestUserApproval: async (req) => { requestUserApproval: async (req) => {
const { metadata: { id } } = req const { origin, metadata: { id } } = req
if (this.pendingApprovalOrigins.has(origin)) {
throw ethErrors.rpc.resourceUnavailable(
'Permission request already pending; please wait.'
)
}
this._platform.openExtensionInBrowser(`connect/${id}`) this._platform.openExtensionInBrowser(`connect/${id}`)
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.pendingApprovals[id] = { resolve, reject } this._addPendingApproval(id, origin, resolve, reject)
}) })
}, },
}, initState) }, initState)