Skip to content

Commit

Permalink
Merge branch '2852/mk/get-or-create-ip-grants' into 2852/mk/improve-i…
Browse files Browse the repository at this point in the history
…p-grant-lookups
  • Loading branch information
mkurapov committed Aug 23, 2024
2 parents a150607 + 5a69214 commit e521b58
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 2 deletions.
55 changes: 55 additions & 0 deletions packages/backend/src/open_payments/grant/service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,61 @@ describe('Grant Service', (): void => {
expect(authServerServiceGetOrCreateSoy).toHaveBeenCalled()
})

test('creates new grant with additional subset actions', async () => {
const newOpenPaymentsGrant = mockGrant()
const openPaymentsGrantRequestSpy = jest
.spyOn(openPaymentsClient.grant, 'request')
.mockResolvedValueOnce({
...newOpenPaymentsGrant
})

const options = {
authServer: authServer.url,
accessType: AccessType.IncomingPayment,
accessActions: [
AccessAction.Create,
AccessAction.ReadAll,
AccessAction.ListAll
]
}

const authServerServiceGetOrCreateSoy = jest.spyOn(
authServerService,
'getOrCreate'
)

const grant = await grantService.getOrCreate(options)

assert(!isGrantError(grant))
expect(grant.accessActions.sort()).toEqual(
[
AccessAction.Create,
AccessAction.ReadAll,
AccessAction.ListAll,
AccessAction.List,
AccessAction.Read
].sort()
)
expect(openPaymentsGrantRequestSpy).toHaveBeenCalledWith(
{ url: options.authServer },
{
access_token: {
access: [
{
// eslint-disable-next-line @typescript-eslint/no-explicit-any
type: options.accessType as any,
actions: options.accessActions
}
]
},
interact: {
start: ['redirect']
}
}
)
expect(authServerServiceGetOrCreateSoy).toHaveBeenCalled()
})

test('creates new grant and deletes old one after being unable to rotate existing token', async () => {
const existingGrant = await Grant.query(knex).insertAndFetch({
authServerId: authServer.id,
Expand Down
28 changes: 26 additions & 2 deletions packages/backend/src/open_payments/grant/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ export async function getExistingGrant(
})
.whereNull('deletedAt')
.andWhere('authServer.url', options.authServer)
.andWhere('accessActions', '@>', options.accessActions) // all options.accessActions are a subset of saved accessActions
// all options.accessActions are a subset of saved accessActions
// e.g. if [ReadAll, Create] is saved, requesting just [Create] would still match
.andWhere('accessActions', '@>', options.accessActions)
.withGraphJoined('authServer')
}

Expand Down Expand Up @@ -142,7 +144,7 @@ async function requestNewGrant(
return Grant.query(deps.knex)
.insertAndFetch({
accessType: options.accessType,
accessActions: options.accessActions,
accessActions: addSubsetActions(options.accessActions),
accessToken: openPaymentsGrant.access_token.value,
managementId: retrieveManagementId(openPaymentsGrant.access_token.manage),
authServerId,
Expand Down Expand Up @@ -199,6 +201,28 @@ async function deleteGrant(
})
}

function addSubsetActions(accessActions: AccessAction[]): AccessAction[] {
const newAccessActions = [...accessActions]

// Read is a subset action of ReadAll
if (
accessActions.includes(AccessAction.ReadAll) &&
!accessActions.includes(AccessAction.Read)
) {
newAccessActions.push(AccessAction.Read)
}

// List is a subset action of ListAll
if (
accessActions.includes(AccessAction.ListAll) &&
!accessActions.includes(AccessAction.List)
) {
newAccessActions.push(AccessAction.List)
}

return newAccessActions
}

function retrieveManagementId(managementUrl: string): string {
const managementUrlParts = managementUrl.split('/')
const managementId = managementUrlParts.pop() || managementUrlParts.pop() // handle trailing slash
Expand Down

0 comments on commit e521b58

Please sign in to comment.