Skip to content

Commit

Permalink
chore(backend): replace GrantReference with OutgoingPaymentGrant (#800)
Browse files Browse the repository at this point in the history
* chore(backend): add outgoing payment grants table

* chore(backend): remove grant reference
  • Loading branch information
wilsonianb committed Dec 1, 2022
1 parent 317ce0d commit cbbc416
Show file tree
Hide file tree
Showing 30 changed files with 598 additions and 973 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ exports.up = function (knex) {
table.uuid('assetId').notNullable()
table.foreign('assetId').references('assets.id')

table.string('grantId').nullable()
table.foreign('grantId').references('grantReferences.id')
table.string('clientId').nullable()

table.timestamp('createdAt').defaultTo(knex.fn.now())
table.timestamp('updatedAt').defaultTo(knex.fn.now())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ exports.up = function (knex) {
table.string('externalRef').nullable()
table.uuid('connectionId').nullable()

table.string('grantId').nullable()
table.foreign('grantId').references('grantReferences.id')
table.string('clientId').nullable()

table.uuid('assetId').notNullable()
table.foreign('assetId').references('assets.id')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
exports.up = function (knex) {
return knex.schema.createTable('outgoingPaymentGrants', function (table) {
table.string('id').notNullable().primary()
})
}

exports.down = function (knex) {
return knex.schema.dropTableIfExists('outgoingPaymentGrants')
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ exports.up = function (knex) {
table.string('description').nullable()
table.string('externalRef').nullable()

table.string('clientId').nullable()

table.string('grantId').nullable()
table.foreign('grantId').references('grantReferences.id')
table.foreign('grantId').references('outgoingPaymentGrants.id')

// Open payments payment pointer corresponding to wallet account
// from which to request funds for payment
Expand Down
2 changes: 0 additions & 2 deletions packages/backend/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ import { addDirectivesToSchema } from './graphql/directives'
import { Session } from './session/util'
import { createValidatorMiddleware, HttpMethod, isHttpMethod } from 'openapi'
import { PaymentPointerKeyService } from './paymentPointerKey/service'
import { GrantReferenceService } from './open_payments/grantReference/service'
import { AuthenticatedClient } from 'open-payments'

export interface AppContextData {
Expand Down Expand Up @@ -147,7 +146,6 @@ export interface AppServices {
apiKeyService: Promise<ApiKeyService>
sessionService: Promise<SessionService>
paymentPointerKeyService: Promise<PaymentPointerKeyService>
grantReferenceService: Promise<GrantReferenceService>
openPaymentsClient: Promise<AuthenticatedClient>
}

Expand Down
10 changes: 0 additions & 10 deletions packages/backend/src/graphql/resolvers/incoming_payment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import { createIncomingPayment } from '../../tests/incomingPayment'
import { createPaymentPointer } from '../../tests/paymentPointer'
import { truncateTables } from '../../tests/tableManager'
import { v4 as uuid } from 'uuid'
import { GrantReference } from '../../open_payments/grantReference/model'
import { GrantReferenceService } from '../../open_payments/grantReference/service'
import { IncomingPaymentService } from '../../open_payments/payment/incoming/service'
import {
IncomingPaymentResponse,
Expand All @@ -30,8 +28,6 @@ describe('Incoming Payment Resolver', (): void => {
let appContainer: TestContainer
let knex: Knex
let paymentPointerId: string
let grantReferenceService: GrantReferenceService
let grantRef: GrantReference
let incomingPaymentService: IncomingPaymentService

const asset = randomAsset()
Expand All @@ -40,7 +36,6 @@ describe('Incoming Payment Resolver', (): void => {
deps = await initIocContainer(Config)
appContainer = await createTestApp(deps)
knex = await deps.use('knex')
grantReferenceService = await deps.use('grantReferenceService')
incomingPaymentService = await deps.use('incomingPaymentService')
})

Expand All @@ -53,18 +48,13 @@ describe('Incoming Payment Resolver', (): void => {
describe('Payment pointer incoming payments', (): void => {
beforeEach(async (): Promise<void> => {
paymentPointerId = (await createPaymentPointer(deps, { asset })).id
grantRef = await grantReferenceService.create({
id: uuid(),
clientId: uuid()
})
})

getPageTests({
getClient: () => appContainer.apolloClient,
createModel: () =>
createIncomingPayment(deps, {
paymentPointerId,
grantId: grantRef.id,
incomingAmount: {
value: BigInt(123),
assetCode: asset.code,
Expand Down
5 changes: 0 additions & 5 deletions packages/backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ import { createAuthenticatedClient as createOpenPaymentsClient } from 'open-paym
import { createConnectionService } from './open_payments/connection/service'
import { createConnectionRoutes } from './open_payments/connection/routes'
import { createPaymentPointerKeyService } from './paymentPointerKey/service'
import { createGrantReferenceService } from './open_payments/grantReference/service'
import { createReceiverService } from './open_payments/receiver/service'

BigInt.prototype.toJSON = function () {
Expand Down Expand Up @@ -309,16 +308,12 @@ export function initIocContainer(
quoteService: await deps.use('quoteService')
})
})
container.singleton('grantReferenceService', async () => {
return createGrantReferenceService()
})
container.singleton('outgoingPaymentService', async (deps) => {
return await createOutgoingPaymentService({
logger: await deps.use('logger'),
knex: await deps.use('knex'),
accountingService: await deps.use('accountingService'),
receiverService: await deps.use('receiverService'),
grantReferenceService: await deps.use('grantReferenceService'),
makeIlpPlugin: await deps.use('makeIlpPlugin'),
peerService: await deps.use('peerService')
})
Expand Down
127 changes: 1 addition & 126 deletions packages/backend/src/open_payments/auth/middleware.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ import { HttpMethod, RequestValidator } from 'openapi'
import { createTestApp, TestContainer } from '../../tests/app'
import { createPaymentPointer } from '../../tests/paymentPointer'
import { truncateTables } from '../../tests/tableManager'
import { GrantReference } from '../grantReference/model'
import { GrantReferenceService } from '../grantReference/service'
import { setup, SetupOptions } from '../payment_pointer/model.test'
import { HttpSigContext, JWKWithRequired, KeyInfo } from 'auth'
import { generateTestKeys, generateSigHeaders } from 'auth/src/tests/signature'
Expand All @@ -39,7 +37,6 @@ describe('Auth Middleware', (): void => {
let ctx: HttpSigContext
let next: jest.MockedFunction<() => Promise<void>>
let validateRequest: RequestValidator<IntrospectionBody>
let grantReferenceService: GrantReferenceService
let mockKeyInfo: KeyInfo
const token = 'OS9M2PMHKUR64TB8N6BW7OZB8CDFONP219RP1LT0'
let generatedKeyPair: {
Expand Down Expand Up @@ -132,7 +129,6 @@ describe('Auth Middleware', (): void => {
path: requestPath,
method: HttpMethod.POST
})
grantReferenceService = await deps.use('grantReferenceService')
generatedKeyPair = await generateTestKeys()
requestMethod = HttpMethod.POST.toUpperCase() as RequestMethod
requestBody = {
Expand Down Expand Up @@ -235,33 +231,6 @@ describe('Auth Middleware', (): void => {
expect(next).not.toHaveBeenCalled()
scope.done()
})
test('returns 500 for not matching clientId', async (): Promise<void> => {
const grant = new TokenInfo(
{
active: true,
clientId: uuid(),
grant: uuid(),
access: [
{
type: AccessType.IncomingPayment,
actions: [AccessAction.Read],
identifier: ctx.paymentPointer.url
}
]
},
mockKeyInfo
)
await grantReferenceService.create({
id: grant.grant,
clientId: uuid()
})
const scope = mockAuthServer(grant.toJSON())
await expect(middleware(ctx, next)).rejects.toMatchObject({
status: 500
})
expect(next).not.toHaveBeenCalled()
scope.done()
})

test.each`
limitAccount
Expand Down Expand Up @@ -306,80 +275,13 @@ describe('Auth Middleware', (): void => {
mockKeyInfo
)
const scope = mockAuthServer(grant.toJSON())
const next = jest.fn().mockImplementation(async () => {
await expect(
GrantReference.query().findById(grant.grant)
).resolves.toBeUndefined()
})
const next = jest.fn()
await expect(middleware(ctx, next)).resolves.toBeUndefined()
expect(next).toHaveBeenCalled()
expect(ctx.grant).toEqual(grant)
scope.done()
}
)
const types = {
[AccessType.IncomingPayment]: Object.values(AccessAction),
[AccessType.OutgoingPayment]: Object.values(AccessAction).filter(
(action) => action !== AccessAction.Complete
),
[AccessType.Quote]: [
AccessAction.Create,
AccessAction.Read
// TODO
// AccessAction.ReadAll
]
}
Object.values(AccessType).forEach((type) => {
for (const action of types[type]) {
const description =
action === AccessAction.Create
? 'stores grant details'
: 'does not store grant details'
test(`${description} for ${type} on the ${action} path`, async (): Promise<void> => {
const actionPathMiddleware: AppMiddleware = createAuthMiddleware({
type: type,
action: action
})
const grant = new TokenInfo(
{
active: true,
clientId: uuid(),
grant: uuid(),
access: [
{
type: type,
actions: [action],
identifier: ctx.paymentPointer.url
}
]
},
mockKeyInfo
)
const scope = mockAuthServer(grant.toJSON())
let next
if (action === AccessAction.Create) {
next = jest.fn().mockImplementation(async () => {
await expect(
GrantReference.query().findById(grant.grant)
).resolves.toEqual({
id: grant.grant,
clientId: grant.clientId
})
})
} else {
next = jest.fn().mockImplementation(async () => {
await expect(
GrantReference.query().findById(grant.grant)
).resolves.toBeUndefined()
})
}
await expect(actionPathMiddleware(ctx, next)).resolves.toBeUndefined()
expect(next).toHaveBeenCalled()
expect(ctx.grant).toEqual(grant)
scope.isDone()
})
}
})

test('bypasses token introspection for configured DEV_ACCESS_TOKEN', async (): Promise<void> => {
ctx.headers.authorization = `GNAP ${Config.devAccessToken}`
Expand All @@ -390,33 +292,6 @@ describe('Auth Middleware', (): void => {
expect(next).toHaveBeenCalled()
})

test('sets the context and calls next if grant has been seen before', async (): Promise<void> => {
const grant = new TokenInfo(
{
active: true,
clientId: uuid(),
grant: uuid(),
access: [
{
type: AccessType.IncomingPayment,
actions: [AccessAction.Read],
identifier: ctx.paymentPointer.url
}
]
},
mockKeyInfo
)
await grantReferenceService.create({
id: grant.grant,
clientId: grant.clientId
})
const scope = mockAuthServer(grant.toJSON())
await expect(middleware(ctx, next)).resolves.toBeUndefined()
expect(next).toHaveBeenCalled()
expect(ctx.grant).toEqual(grant)
scope.done()
})

test('returns 200 with valid http signature without body', async (): Promise<void> => {
await prepareTest(false)
const grant = new TokenInfo(
Expand Down
26 changes: 0 additions & 26 deletions packages/backend/src/open_payments/auth/middleware.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { AccessType, AccessAction } from './grant'
import { Transaction } from 'objection'
import { GrantReference } from '../grantReference/model'
import { HttpSigContext, verifySigAndChallenge } from 'auth'

export function createAuthMiddleware({
Expand All @@ -15,10 +13,6 @@ export function createAuthMiddleware({
next: () => Promise<unknown>
): Promise<void> => {
const config = await ctx.container.use('config')
const grantReferenceService = await ctx.container.use(
'grantReferenceService'
)
const logger = await ctx.container.use('logger')
try {
const parts = ctx.request.headers.authorization?.split(' ')
if (parts?.length !== 2 || parts[0] !== 'GNAP') {
Expand Down Expand Up @@ -55,26 +49,6 @@ export function createAuthMiddleware({
ctx.throw(401, `Invalid signature`)
}
}
await GrantReference.transaction(async (trx: Transaction) => {
const grantRef = await grantReferenceService.get(grant.grant, trx)
if (grantRef) {
if (grantRef.clientId !== grant.clientId) {
logger.debug(
`clientID ${grant.clientId} for grant ${grant.grant} does not match internal reference clientId ${grantRef.clientId}.`
)
ctx.throw(500)
}
} else if (action === AccessAction.Create) {
// Grant and client ID's are only stored for create routes
await grantReferenceService.create(
{
id: grant.grant,
clientId: grant.clientId
},
trx
)
}
})
ctx.grant = grant

// Unless the relevant grant action is ReadAll/ListAll add the
Expand Down
10 changes: 0 additions & 10 deletions packages/backend/src/open_payments/connection/routes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,20 @@ import {
import { createIncomingPayment } from '../../tests/incomingPayment'
import { createPaymentPointer } from '../../tests/paymentPointer'
import base64url from 'base64url'
import { GrantReference } from '../grantReference/model'
import { GrantReferenceService } from '../grantReference/service'

describe('Connection Routes', (): void => {
let deps: IocContract<AppServices>
let appContainer: TestContainer
let knex: Knex
let config: IAppConfig
let connectionRoutes: ConnectionRoutes
let grantReferenceService: GrantReferenceService
let grantRef: GrantReference

beforeAll(async (): Promise<void> => {
config = Config
config.authServerGrantUrl = 'https://auth.wallet.example/authorize'
deps = await initIocContainer(config)
appContainer = await createTestApp(deps)
knex = await deps.use('knex')
grantReferenceService = await deps.use('grantReferenceService')
jestOpenAPI(await deps.use('openApi'))
})

Expand All @@ -51,13 +46,8 @@ describe('Connection Routes', (): void => {
config = await deps.use('config')

paymentPointer = await createPaymentPointer(deps, { asset })
grantRef = await grantReferenceService.create({
id: uuid(),
clientId: uuid()
})
incomingPayment = await createIncomingPayment(deps, {
paymentPointerId: paymentPointer.id,
grantId: grantRef.id,
description: 'hello world',
expiresAt: new Date(Date.now() + 30_000),
incomingAmount: {
Expand Down
Loading

0 comments on commit cbbc416

Please sign in to comment.