-
Notifications
You must be signed in to change notification settings - Fork 5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move rate limit controller to init function
- Loading branch information
Showing
9 changed files
with
300 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
55 changes: 55 additions & 0 deletions
55
app/scripts/controller-init/snaps/rate-limit-controller-init.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { ControllerMessenger } from '@metamask/base-controller'; | ||
import { ControllerInitRequest } from '../types'; | ||
import { buildControllerInitRequestMock } from '../test/utils'; | ||
import { RateLimitControllerInit } from './rate-limit-controller-init'; | ||
import { RateLimitController } from '@metamask/rate-limit-controller'; | ||
import { | ||
getRateLimitControllerInitMessenger, | ||
getRateLimitControllerMessenger, | ||
RateLimitControllerInitMessenger, | ||
RateLimitControllerMessenger, | ||
} from './rate-limit-controller-messenger'; | ||
|
||
jest.mock('@metamask/rate-limit-controller'); | ||
|
||
function getInitRequestMock(): jest.Mocked< | ||
ControllerInitRequest<RateLimitControllerMessenger, RateLimitControllerInitMessenger> | ||
Check failure on line 16 in app/scripts/controller-init/snaps/rate-limit-controller-init.test.ts GitHub Actions / Test lint / Test lint
|
||
> { | ||
const baseControllerMessenger = new ControllerMessenger<never, never>(); | ||
|
||
const requestMock = { | ||
...buildControllerInitRequestMock(), | ||
controllerMessenger: getRateLimitControllerMessenger(baseControllerMessenger), | ||
initMessenger: getRateLimitControllerInitMessenger(baseControllerMessenger), | ||
}; | ||
|
||
return requestMock; | ||
} | ||
|
||
describe('RateLimitController', () => { | ||
it('initializes the controller', () => { | ||
const { controller } = RateLimitControllerInit(getInitRequestMock()); | ||
expect(controller).toBeInstanceOf(RateLimitController); | ||
}); | ||
|
||
it('passes the proper arguments to the controller', () => { | ||
RateLimitControllerInit(getInitRequestMock()); | ||
|
||
const controllerMock = jest.mocked(RateLimitController); | ||
expect(controllerMock).toHaveBeenCalledWith({ | ||
messenger: expect.any(Object), | ||
implementations: { | ||
showInAppNotification: { | ||
method: expect.any(Function), | ||
rateLimitCount: 5, | ||
rateLimitTimeout: 60_000, | ||
}, | ||
showNativeNotification: { | ||
method: expect.any(Function), | ||
rateLimitCount: 2, | ||
rateLimitTimeout: 300_000, | ||
} | ||
} | ||
}); | ||
}); | ||
}); |
108 changes: 108 additions & 0 deletions
108
app/scripts/controller-init/snaps/rate-limit-controller-init.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import { | ||
RateLimitController, | ||
RateLimitedApiMap, | ||
} from '@metamask/rate-limit-controller'; | ||
import log from 'loglevel'; | ||
import { TRIGGER_TYPES } from '@metamask/notification-services-controller/notification-services'; | ||
import { ControllerInitFunction } from '../types'; | ||
import { | ||
RateLimitControllerInitMessenger, | ||
RateLimitControllerMessenger, | ||
} from './rate-limit-controller-messenger'; | ||
|
||
/** | ||
* Initialize the Snap insights controller. | ||
* | ||
* @param request - The request object. | ||
* @param request.controllerMessenger - The controller messenger to use for the | ||
* controller. | ||
* @param request.persistedState - The persisted state of the extension. | ||
* @param request.initMessenger - The init messenger. This has access to | ||
* different functions than the controller messenger, and should be used for | ||
* initialization purposes only. | ||
* @param request.showNotification - Function to show a notification. | ||
* @returns The initialized controller. | ||
*/ | ||
export const RateLimitControllerInit: ControllerInitFunction< | ||
RateLimitController<RateLimitedApiMap>, | ||
RateLimitControllerMessenger, | ||
RateLimitControllerInitMessenger | ||
> = ({ | ||
controllerMessenger, | ||
initMessenger, | ||
persistedState, | ||
showNotification, | ||
}) => { | ||
const controller = new RateLimitController({ | ||
state: persistedState.RateLimitController, | ||
// @ts-expect-error: Property `#private` in type` RestrictedMessenger` | ||
// refers to a different member that cannot be accessed from within type | ||
// `RestrictedControllerMessenger`. | ||
// TODO: Remove this when switched to `RestrictedMessenger`. | ||
messenger: controllerMessenger, | ||
|
||
implementations: { | ||
showNativeNotification: { | ||
method: (origin, message) => { | ||
const subjectMetadataState = initMessenger.call( | ||
'SubjectMetadataController:getState', | ||
); | ||
|
||
const originMetadata = subjectMetadataState.subjectMetadata[origin]; | ||
|
||
showNotification(originMetadata?.name ?? origin, message).catch( | ||
(error: unknown) => { | ||
log.error('Failed to create notification', error); | ||
}, | ||
); | ||
|
||
return null; | ||
}, | ||
|
||
// 2 calls per 5 minutes | ||
rateLimitCount: 2, | ||
rateLimitTimeout: 300_000, | ||
}, | ||
|
||
showInAppNotification: { | ||
method: (origin, args) => { | ||
const { message, title, footerLink, interfaceId } = args; | ||
|
||
const detailedView = { | ||
title, | ||
...(footerLink ? { footerLink } : {}), | ||
interfaceId, | ||
}; | ||
|
||
const notification = { | ||
data: { | ||
message, | ||
origin, | ||
...(interfaceId ? { detailedView } : {}), | ||
}, | ||
type: TRIGGER_TYPES.SNAP, | ||
readDate: null, | ||
}; | ||
|
||
initMessenger.call( | ||
'NotificationServicesController:updateMetamaskNotificationsList', | ||
// @ts-expect-error: `notification` is not compatible with the | ||
// expected type. | ||
// TODO: Look into the type mismatch. | ||
notification, | ||
); | ||
|
||
return null; | ||
}, | ||
|
||
// 5 calls per minute | ||
rateLimitCount: 5, | ||
rateLimitTimeout: 60_000, | ||
}, | ||
}, | ||
}); | ||
|
||
return { | ||
controller, | ||
}; | ||
}; |
28 changes: 28 additions & 0 deletions
28
app/scripts/controller-init/snaps/rate-limit-controller-messenger.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { | ||
ControllerMessenger, | ||
RestrictedMessenger, | ||
} from '@metamask/base-controller'; | ||
import { | ||
getRateLimitControllerInitMessenger, | ||
getRateLimitControllerMessenger, | ||
} from './rate-limit-controller-messenger'; | ||
|
||
describe('getRateLimitControllerMessenger', () => { | ||
it('returns a restricted controller messenger', () => { | ||
const controllerMessenger = new ControllerMessenger<never, never>(); | ||
const rateLimitControllerMessenger = | ||
getRateLimitControllerMessenger(controllerMessenger); | ||
|
||
expect(rateLimitControllerMessenger).toBeInstanceOf(RestrictedMessenger); | ||
}); | ||
}); | ||
|
||
describe('getRateLimitControllerInitMessenger', () => { | ||
it('returns a restricted controller messenger', () => { | ||
const controllerMessenger = new ControllerMessenger<never, never>(); | ||
const rateLimitControllerInitMessenger = | ||
getRateLimitControllerInitMessenger(controllerMessenger); | ||
|
||
expect(rateLimitControllerInitMessenger).toBeInstanceOf(RestrictedMessenger); | ||
}); | ||
}); |
75 changes: 75 additions & 0 deletions
75
app/scripts/controller-init/snaps/rate-limit-controller-messenger.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { ControllerMessenger } from '@metamask/base-controller'; | ||
import { | ||
SnapInstalled, | ||
SnapUpdated, | ||
SnapDisabled, | ||
SnapEnabled, | ||
SnapUninstalled, | ||
HandleSnapRequest, | ||
GetAllSnaps, | ||
} from '@metamask/snaps-controllers'; | ||
import { | ||
GetPermissions, | ||
GetSubjectMetadataState, | ||
} from '@metamask/permission-controller'; | ||
import { NotificationServicesControllerUpdateMetamaskNotificationsList } from '@metamask/notification-services-controller/notification-services'; | ||
|
||
type Actions = GetPermissions | HandleSnapRequest | GetAllSnaps; | ||
|
||
type Events = | ||
| SnapInstalled | ||
| SnapUpdated | ||
| SnapUninstalled | ||
| SnapEnabled | ||
| SnapDisabled; | ||
|
||
export type RateLimitControllerMessenger = ReturnType< | ||
typeof getRateLimitControllerMessenger | ||
>; | ||
|
||
/** | ||
* Get a restricted controller messenger for the rate limit controller. This is | ||
* scoped to the actions and events that the rate limit controller is allowed to | ||
* handle. | ||
* | ||
* @param controllerMessenger - The controller messenger to restrict. | ||
* @returns The restricted controller messenger. | ||
*/ | ||
export function getRateLimitControllerMessenger( | ||
controllerMessenger: ControllerMessenger<Actions, Events>, | ||
) { | ||
return controllerMessenger.getRestricted({ | ||
name: 'RateLimitController', | ||
allowedEvents: [], | ||
allowedActions: [], | ||
}); | ||
} | ||
|
||
type InitActions = | ||
| GetSubjectMetadataState | ||
| NotificationServicesControllerUpdateMetamaskNotificationsList; | ||
|
||
export type RateLimitControllerInitMessenger = ReturnType< | ||
typeof getRateLimitControllerInitMessenger | ||
>; | ||
|
||
/** | ||
* Get a restricted controller messenger for the rate limit controller. This is | ||
* scoped to the actions and events that the rate limit controller is allowed to | ||
* handle. | ||
* | ||
* @param controllerMessenger - The controller messenger to restrict. | ||
* @returns The restricted controller messenger. | ||
*/ | ||
export function getRateLimitControllerInitMessenger( | ||
controllerMessenger: ControllerMessenger<InitActions, never>, | ||
) { | ||
return controllerMessenger.getRestricted({ | ||
name: 'RateLimitController', | ||
allowedActions: [ | ||
'SubjectMetadataController:getState', | ||
'NotificationServicesController:updateMetamaskNotificationsList', | ||
], | ||
allowedEvents: [], | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.