From 7bcb13a5f3528ea4f130519f34e62e5e500b0986 Mon Sep 17 00:00:00 2001 From: Nathan Lie Date: Thu, 10 Oct 2024 19:34:46 +0200 Subject: [PATCH] fix(backend): fix OP resource tests (#2969) * feat(backend): create operator kratos identity on backend startup * chore: formatting * Add migration files * Update migration files * Fix file name for migrations * feat(auth): create basic tenant service and model plus graphql schema * feat(auth): add basic tenant schema and appropriate resources like model and service * feat(backend): add apollo client do dependencies * feat(auth): delete tenant * chore(auth): format * feat(backend): create tenant service implementation * feat(packages): make multi tenant work wip * feat(backend): update resolvers with tenant id and finish the tenant creation * feat(backend): small changes to schema + mapping of tenant to graphql + bruno * fix: outgoing/quote tests * fix: combined payments tests * chore: formatting * fix: update tenant id requirements for some services * chore: fix rebase issues * chore: try to fix apollo errors in ilp payment method tests --------- Co-authored-by: bsanduc Co-authored-by: golobitch --- .../generated/graphql.ts | 4 +- packages/auth/src/index.ts | 36 ----- ...27115832_update_resources_with_tenantId.js | 8 -- .../src/graphql/generated/graphql.schema.json | 32 ++--- .../backend/src/graphql/generated/graphql.ts | 4 +- .../resolvers/outgoing_payment.test.ts | 3 + .../src/graphql/resolvers/quote.test.ts | 3 - .../backend/src/graphql/resolvers/quote.ts | 1 - .../src/graphql/resolvers/tenant_endpoints.ts | 44 ------ packages/backend/src/graphql/schema.graphql | 4 +- .../backend/src/open_payments/grant/model.ts | 1 - .../src/open_payments/grant/service.test.ts | 126 ++++-------------- .../src/open_payments/grant/service.ts | 3 - .../payment/incoming/model.test.ts | 11 +- .../payment/incoming/routes.test.ts | 10 +- .../payment/incoming_remote/service.ts | 15 +-- .../payment/outgoing/service.test.ts | 27 +--- .../open_payments/payment/outgoing/service.ts | 8 +- .../src/open_payments/quote/routes.test.ts | 6 +- .../backend/src/open_payments/quote/routes.ts | 2 - .../src/open_payments/quote/service.test.ts | 13 -- .../src/open_payments/quote/service.ts | 11 +- .../src/open_payments/receiver/service.ts | 23 +--- .../wallet_address/routes.test.ts | 8 +- .../src/payment-method/ilp/service.test.ts | 5 + .../backend/src/shared/pagination.test.ts | 1 - packages/backend/src/tests/outgoingPayment.ts | 3 +- packages/frontend/app/generated/graphql.ts | 6 +- .../src/generated/graphql.ts | 4 +- test/integration/lib/generated/graphql.ts | 4 +- 30 files changed, 99 insertions(+), 327 deletions(-) diff --git a/localenv/mock-account-servicing-entity/generated/graphql.ts b/localenv/mock-account-servicing-entity/generated/graphql.ts index dea9da36e2..5cff685570 100644 --- a/localenv/mock-account-servicing-entity/generated/graphql.ts +++ b/localenv/mock-account-servicing-entity/generated/graphql.ts @@ -243,6 +243,8 @@ export type CreateOutgoingPaymentFromIncomingPaymentInput = { incomingPayment: Scalars['String']['input']; /** Additional metadata associated with the outgoing payment. */ metadata?: InputMaybe; + /** ID of a tenant */ + tenantId: Scalars['ID']['input']; /** Id of the wallet address under which the outgoing payment will be created */ walletAddressId: Scalars['String']['input']; }; @@ -315,8 +317,6 @@ export type CreateQuoteInput = { receiveAmount?: InputMaybe; /** Wallet address URL of the receiver */ receiver: Scalars['String']['input']; - /** ID of the tenant */ - tenantId: Scalars['ID']['input']; /** Id of the wallet address under which the quote will be created */ walletAddressId: Scalars['String']['input']; }; diff --git a/packages/auth/src/index.ts b/packages/auth/src/index.ts index f4c6c664f4..c0fccfb93f 100644 --- a/packages/auth/src/index.ts +++ b/packages/auth/src/index.ts @@ -105,42 +105,6 @@ export function initIocContainer( } ) - container.singleton( - 'tenantService', - async (deps: IocContract) => { - const [logger, knex] = await Promise.all([ - deps.use('logger'), - deps.use('knex') - ]) - - return createTenantService({ logger, knex }) - } - ) - - container.singleton( - 'tenantService', - async (deps: IocContract) => { - const [logger, knex] = await Promise.all([ - deps.use('logger'), - deps.use('knex') - ]) - - return createTenantService({ logger, knex }) - } - ) - - container.singleton( - 'tenantService', - async (deps: IocContract) => { - const [logger, knex] = await Promise.all([ - deps.use('logger'), - deps.use('knex') - ]) - - return createTenantService({ logger, knex }) - } - ) - container.singleton( 'accessService', async (deps: IocContract) => { diff --git a/packages/backend/migrations/20240827115832_update_resources_with_tenantId.js b/packages/backend/migrations/20240827115832_update_resources_with_tenantId.js index 6d9f201a57..e68c0d1864 100644 --- a/packages/backend/migrations/20240827115832_update_resources_with_tenantId.js +++ b/packages/backend/migrations/20240827115832_update_resources_with_tenantId.js @@ -20,10 +20,6 @@ exports.up = function (knex) { table.uuid('tenantId').notNullable() table.foreign('tenantId').references('id').inTable('tenants') }) - .table('grants', function (table) { - table.uuid('tenantId').notNullable() - table.foreign('tenantId').references('id').inTable('tenants') - }) } /** @@ -48,8 +44,4 @@ exports.down = function (knex) { table.dropForeign(['tenantId']) table.dropColumn('tenantId') }) - .table('grants', function (table) { - table.dropForeign(['tenantId']) - table.dropColumn('tenantId') - }) } diff --git a/packages/backend/src/graphql/generated/graphql.schema.json b/packages/backend/src/graphql/generated/graphql.schema.json index 256fd74825..969790acb3 100644 --- a/packages/backend/src/graphql/generated/graphql.schema.json +++ b/packages/backend/src/graphql/generated/graphql.schema.json @@ -1536,6 +1536,22 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "tenantId", + "description": "ID of a tenant", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "walletAddressId", "description": "Id of the wallet address under which the outgoing payment will be created", @@ -1990,22 +2006,6 @@ "isDeprecated": false, "deprecationReason": null }, - { - "name": "tenantId", - "description": "ID of the tenant", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "walletAddressId", "description": "Id of the wallet address under which the quote will be created", diff --git a/packages/backend/src/graphql/generated/graphql.ts b/packages/backend/src/graphql/generated/graphql.ts index dea9da36e2..5cff685570 100644 --- a/packages/backend/src/graphql/generated/graphql.ts +++ b/packages/backend/src/graphql/generated/graphql.ts @@ -243,6 +243,8 @@ export type CreateOutgoingPaymentFromIncomingPaymentInput = { incomingPayment: Scalars['String']['input']; /** Additional metadata associated with the outgoing payment. */ metadata?: InputMaybe; + /** ID of a tenant */ + tenantId: Scalars['ID']['input']; /** Id of the wallet address under which the outgoing payment will be created */ walletAddressId: Scalars['String']['input']; }; @@ -315,8 +317,6 @@ export type CreateQuoteInput = { receiveAmount?: InputMaybe; /** Wallet address URL of the receiver */ receiver: Scalars['String']['input']; - /** ID of the tenant */ - tenantId: Scalars['ID']['input']; /** Id of the wallet address under which the quote will be created */ walletAddressId: Scalars['String']['input']; }; diff --git a/packages/backend/src/graphql/resolvers/outgoing_payment.test.ts b/packages/backend/src/graphql/resolvers/outgoing_payment.test.ts index 94fb6e33f2..045336701e 100644 --- a/packages/backend/src/graphql/resolvers/outgoing_payment.test.ts +++ b/packages/backend/src/graphql/resolvers/outgoing_payment.test.ts @@ -740,6 +740,7 @@ describe('OutgoingPayment Resolvers', (): void => { const input = { walletAddressId: payment.walletAddressId, + tenantId, incomingPayment: mockIncomingPaymentUrl, debitAmount: { value: BigInt(56), @@ -781,6 +782,7 @@ describe('OutgoingPayment Resolvers', (): void => { const input = { walletAddressId: uuid(), + tenantId, incomingPayment: mockIncomingPaymentUrl, debitAmount: { value: BigInt(56), @@ -832,6 +834,7 @@ describe('OutgoingPayment Resolvers', (): void => { const input = { walletAddressId: uuid(), + tenantId, incomingPayment: mockIncomingPaymentUrl, debitAmount: { value: BigInt(56), diff --git a/packages/backend/src/graphql/resolvers/quote.test.ts b/packages/backend/src/graphql/resolvers/quote.test.ts index ef2ef4dbf1..4d1f5f467b 100644 --- a/packages/backend/src/graphql/resolvers/quote.test.ts +++ b/packages/backend/src/graphql/resolvers/quote.test.ts @@ -71,7 +71,6 @@ describe('Quote Resolvers', (): void => { ): Promise => { return await createQuote(deps, { walletAddressId, - tenantId, receiver, debitAmount: { value: BigInt(56), @@ -195,7 +194,6 @@ describe('Quote Resolvers', (): void => { } input = { walletAddressId: uuid(), - tenantId: uuid(), receiver, debitAmount } @@ -217,7 +215,6 @@ describe('Quote Resolvers', (): void => { ) const input = { walletAddressId, - tenantId, debitAmount: amount, receiveAmount, receiver diff --git a/packages/backend/src/graphql/resolvers/quote.ts b/packages/backend/src/graphql/resolvers/quote.ts index fcd20fb237..16bd2863e1 100644 --- a/packages/backend/src/graphql/resolvers/quote.ts +++ b/packages/backend/src/graphql/resolvers/quote.ts @@ -42,7 +42,6 @@ export const createQuote: MutationResolvers['createQuote'] = const quoteService = await ctx.container.use('quoteService') const options: CreateQuoteOptions = { walletAddressId: args.input.walletAddressId, - tenantId: args.input.tenantId, receiver: args.input.receiver, method: 'ilp' } diff --git a/packages/backend/src/graphql/resolvers/tenant_endpoints.ts b/packages/backend/src/graphql/resolvers/tenant_endpoints.ts index 14197d73ce..7813a8c47a 100644 --- a/packages/backend/src/graphql/resolvers/tenant_endpoints.ts +++ b/packages/backend/src/graphql/resolvers/tenant_endpoints.ts @@ -1,10 +1,5 @@ -import { ApolloContext } from '../../app' -import { Pagination, SortOrder } from '../../shared/baseModel' -import { getPageInfo } from '../../shared/pagination' import { EndpointType, TenantEndpoint } from '../../tenant/endpoints/model' import { - ResolversTypes, - TenantResolvers, TenantEndpoint as SchemaTenantEndpoint, TenantEndpointType } from '../generated/graphql' @@ -14,45 +9,6 @@ export const mapTenantEndpointTypeToModelEndpointType = { [EndpointType.WebhookBaseUrl]: TenantEndpointType.WebhookBaseUrl } -export const getTenantEndpoints: TenantResolvers['endpoints'] = - async ( - parent, - args, - ctx - ): Promise => { - if (!parent.id) { - throw new Error('missing tenant id') - } - const tenantEndpointService = await ctx.container.use( - 'tenantEndpointService' - ) - - const { sortOrder, ...pagination } = args - const order = sortOrder === 'ASC' ? SortOrder.Asc : SortOrder.Desc - - const tenantEndpoints = await tenantEndpointService.getPage( - parent.id, - pagination, - order - ) - - console.log('TENANT ENDPOINTS: ', tenantEndpoints) - - const pageInfo = await getPageInfo({ - getPage: (pagination_?: Pagination, sortOrder_?: SortOrder) => - tenantEndpointService.getPage(parent.id!, pagination_, sortOrder_), - page: tenantEndpoints - }) - - return { - pageInfo, - edges: tenantEndpoints.map((endpoint: TenantEndpoint) => ({ - cursor: `${endpoint.tenantId}${endpoint.type}`, - node: tenantEndpointToGraphql(endpoint) - })) - } - } - export function tenantEndpointToGraphql( tenantEndpoint: TenantEndpoint ): SchemaTenantEndpoint { diff --git a/packages/backend/src/graphql/schema.graphql b/packages/backend/src/graphql/schema.graphql index 4a313ae595..de5d32885a 100644 --- a/packages/backend/src/graphql/schema.graphql +++ b/packages/backend/src/graphql/schema.graphql @@ -1071,8 +1071,6 @@ input CreateQuoteInput { receiver: String! "Unique key to ensure duplicate or retried requests are processed only once. See [idempotence](https://en.wikipedia.org/wiki/Idempotence)" idempotencyKey: String - "ID of the tenant" - tenantId: ID! } type QuoteResponse { @@ -1110,6 +1108,8 @@ input CreateOutgoingPaymentFromIncomingPaymentInput { metadata: JSONObject "Unique key to ensure duplicate or retried requests are processed only once. See [idempotence](https://en.wikipedia.org/wiki/Idempotence)" idempotencyKey: String + "ID of a tenant" + tenantId: ID! } input CreateIncomingPaymentInput { diff --git a/packages/backend/src/open_payments/grant/model.ts b/packages/backend/src/open_payments/grant/model.ts index ce73fbc385..ed2c77daa7 100644 --- a/packages/backend/src/open_payments/grant/model.ts +++ b/packages/backend/src/open_payments/grant/model.ts @@ -32,7 +32,6 @@ export class Grant extends BaseModel { public managementId!: string public accessType!: AccessType public accessActions!: AccessAction[] - public tenantId!: string public expiresAt?: Date | null public deletedAt?: Date diff --git a/packages/backend/src/open_payments/grant/service.test.ts b/packages/backend/src/open_payments/grant/service.test.ts index bb833a4e65..eb10c65d71 100644 --- a/packages/backend/src/open_payments/grant/service.test.ts +++ b/packages/backend/src/open_payments/grant/service.test.ts @@ -21,10 +21,6 @@ import { import { v4 as uuid } from 'uuid' import { GrantError, isGrantError } from './errors' import { AuthServerService } from '../authServer/service' -import { createTenant } from '../../tests/tenant' -import { EndpointType } from '../../tenant/endpoints/model' - -const nock = (global as unknown as { nock: typeof import('nock') }).nock describe('Grant Service', (): void => { let deps: IocContract @@ -33,7 +29,6 @@ describe('Grant Service', (): void => { let openPaymentsClient: AuthenticatedClient let authServerService: AuthServerService let knex: Knex - let tenantId: string beforeAll(async (): Promise => { deps = await initIocContainer(Config) @@ -45,23 +40,6 @@ describe('Grant Service', (): void => { }) beforeEach(async (): Promise => { - const config = await deps.use('config') - const tenantEmail = faker.internet.email() - nock(config.kratosAdminUrl) - .get('/identities') - .query({ credentials_identifier: tenantEmail }) - .reply(200, [{ id: uuid(), metadata_public: {} }]) - .persist() - tenantId = ( - await createTenant(deps, { - email: tenantEmail, - idpSecret: 'testsecret', - idpConsentEndpoint: faker.internet.url(), - endpoints: [ - { type: EndpointType.WebhookBaseUrl, value: faker.internet.url() } - ] - }) - ).id jest.useFakeTimers() jest.setSystemTime(Date.now()) }) @@ -86,7 +64,6 @@ describe('Grant Service', (): void => { test('gets existing grant', async () => { const existingGrant = await Grant.query(knex).insertAndFetch({ - tenantId, authServerId: authServer.id, accessToken: uuid(), managementId: uuid(), @@ -102,8 +79,7 @@ describe('Grant Service', (): void => { const options = { authServer: authServer.url, accessType: AccessType.IncomingPayment, - accessActions: [AccessAction.ReadAll], - tenantId + accessActions: [AccessAction.ReadAll] } const grant = await grantService.getOrCreate(options) @@ -115,7 +91,6 @@ describe('Grant Service', (): void => { test('updates expired grant (by rotating existing token)', async () => { const existingGrant = await Grant.query(knex).insertAndFetch({ - tenantId, authServerId: authServer.id, accessToken: uuid(), managementId: uuid(), @@ -144,8 +119,7 @@ describe('Grant Service', (): void => { const options = { authServer: authServer.url, accessType: AccessType.IncomingPayment, - accessActions: [AccessAction.Create, AccessAction.ReadAll], - tenantId + accessActions: [AccessAction.Create, AccessAction.ReadAll] } const grant = await grantService.getOrCreate(options) @@ -153,7 +127,6 @@ describe('Grant Service', (): void => { assert(!isGrantError(grant)) expect(grant).toMatchObject({ id: existingGrant.id, - tenantId, authServerId: existingGrant.authServerId, accessToken: rotatedAccessToken.access_token.value, expiresAt: new Date( @@ -181,8 +154,7 @@ describe('Grant Service', (): void => { const options = { authServer: authServer.url, accessType: AccessType.IncomingPayment, - accessActions: [AccessAction.Create, AccessAction.Read], - tenantId + accessActions: [AccessAction.Create, AccessAction.Read] } const authServerServiceGetOrCreateSoy = jest.spyOn( @@ -195,7 +167,6 @@ describe('Grant Service', (): void => { assert(!isGrantError(grant)) expect(grant).toMatchObject({ authServerId: authServer.id, - tenantId, accessType: options.accessType, accessActions: options.accessActions, accessToken: newOpenPaymentsGrant.access_token.value, @@ -239,8 +210,7 @@ describe('Grant Service', (): void => { AccessAction.Create, AccessAction.ReadAll, AccessAction.ListAll - ], - tenantId + ] } const authServerServiceGetOrCreateSoy = jest.spyOn( @@ -282,7 +252,6 @@ describe('Grant Service', (): void => { test('creates new grant and deletes old one after being unable to rotate existing token', async () => { const existingGrant = await Grant.query(knex).insertAndFetch({ - tenantId, authServerId: authServer.id, accessToken: uuid(), managementId: uuid(), @@ -311,8 +280,7 @@ describe('Grant Service', (): void => { const options = { authServer: authServer.url, accessType: AccessType.IncomingPayment, - accessActions: [AccessAction.Create, AccessAction.Read], - tenantId + accessActions: [AccessAction.Create, AccessAction.Read] } const grant = await grantService.getOrCreate(options) @@ -320,7 +288,6 @@ describe('Grant Service', (): void => { assert(!isGrantError(grant)) expect(grant.id).not.toBe(existingGrant.id) expect(grant).toMatchObject({ - tenantId, accessType: options.accessType, accessActions: options.accessActions, authServerId: authServer.id, @@ -347,8 +314,7 @@ describe('Grant Service', (): void => { const options = { authServer: authServer.url, accessType: AccessType.IncomingPayment, - accessActions: [AccessAction.Create, AccessAction.ReadAll], - tenantId + accessActions: [AccessAction.Create, AccessAction.ReadAll] } const error = await grantService.getOrCreate(options) @@ -365,8 +331,7 @@ describe('Grant Service', (): void => { const options = { authServer: authServer.url, accessType: AccessType.IncomingPayment, - accessActions: [AccessAction.Create, AccessAction.ReadAll], - tenantId + accessActions: [AccessAction.Create, AccessAction.ReadAll] } const error = await grantService.getOrCreate(options) @@ -387,7 +352,6 @@ describe('Grant Service', (): void => { test('gets existing grant (identical match)', async () => { const existingGrant = await Grant.query(knex).insertAndFetch({ - tenantId, authServerId: authServer.id, accessToken: uuid(), managementId: uuid(), @@ -398,8 +362,7 @@ describe('Grant Service', (): void => { const options = { authServer: authServer.url, accessType: AccessType.IncomingPayment, - accessActions: [AccessAction.ReadAll], - tenantId + accessActions: [AccessAction.ReadAll] } await expect( @@ -409,7 +372,6 @@ describe('Grant Service', (): void => { test('gets existing grant (requested actions are a subset of saved actions)', async () => { const existingGrant = await Grant.query(knex).insertAndFetch({ - tenantId, authServerId: authServer.id, accessToken: uuid(), managementId: uuid(), @@ -424,8 +386,7 @@ describe('Grant Service', (): void => { const options = { authServer: authServer.url, accessType: AccessType.IncomingPayment, - accessActions: [AccessAction.ReadAll, AccessAction.Create], - tenantId + accessActions: [AccessAction.ReadAll, AccessAction.Create] } await expect( @@ -435,7 +396,6 @@ describe('Grant Service', (): void => { test('ignores deleted grants', async () => { await Grant.query(knex).insertAndFetch({ - tenantId, authServerId: authServer.id, accessToken: uuid(), managementId: uuid(), @@ -447,8 +407,7 @@ describe('Grant Service', (): void => { const options = { authServer: authServer.url, accessType: AccessType.IncomingPayment, - accessActions: [AccessAction.ReadAll], - tenantId + accessActions: [AccessAction.ReadAll] } await expect( @@ -458,7 +417,6 @@ describe('Grant Service', (): void => { test('ignores different accessType', async () => { await Grant.query(knex).insertAndFetch({ - tenantId, authServerId: authServer.id, accessToken: uuid(), managementId: uuid(), @@ -469,8 +427,7 @@ describe('Grant Service', (): void => { const options = { authServer: authServer.url, accessType: AccessType.OutgoingPayment, - accessActions: [AccessAction.ReadAll], - tenantId + accessActions: [AccessAction.ReadAll] } await expect( @@ -480,7 +437,6 @@ describe('Grant Service', (): void => { test('ignores different auth server url', async () => { await Grant.query(knex).insertAndFetch({ - tenantId, authServerId: authServer.id, accessToken: uuid(), managementId: uuid(), @@ -491,8 +447,7 @@ describe('Grant Service', (): void => { const options = { authServer: uuid(), accessType: AccessType.IncomingPayment, - accessActions: [AccessAction.ReadAll], - tenantId + accessActions: [AccessAction.ReadAll] } await expect( @@ -502,7 +457,6 @@ describe('Grant Service', (): void => { test('ignores insufficient accessActions', async () => { await Grant.query(knex).insertAndFetch({ - tenantId, authServerId: authServer.id, accessToken: uuid(), managementId: uuid(), @@ -513,8 +467,7 @@ describe('Grant Service', (): void => { const options = { authServer: authServer.id, accessType: AccessType.IncomingPayment, - accessActions: [AccessAction.ReadAll, AccessAction.Create], - tenantId + accessActions: [AccessAction.ReadAll, AccessAction.Create] } await expect( @@ -534,7 +487,6 @@ describe('Grant Service', (): void => { test('deletes grant', async () => { const existingGrant = await Grant.query(knex).insertAndFetch({ - tenantId, authServerId: authServer.id, accessToken: uuid(), managementId: uuid(), @@ -563,7 +515,6 @@ describe('Grant Service', (): void => { test('gets existing grant', async () => { const existingGrant = await Grant.query(knex).insertAndFetch({ - tenantId, authServerId: authServer.id, accessToken: uuid(), managementId: uuid(), @@ -579,8 +530,7 @@ describe('Grant Service', (): void => { const options = { authServer: authServer.url, accessType: AccessType.IncomingPayment, - accessActions: [AccessAction.ReadAll], - tenantId + accessActions: [AccessAction.ReadAll] } const grant = await grantService.getOrCreate(options) @@ -592,7 +542,6 @@ describe('Grant Service', (): void => { test('updates expired grant (by rotating existing token)', async () => { const existingGrant = await Grant.query(knex).insertAndFetch({ - tenantId, authServerId: authServer.id, accessToken: uuid(), managementId: uuid(), @@ -621,8 +570,7 @@ describe('Grant Service', (): void => { const options = { authServer: authServer.url, accessType: AccessType.IncomingPayment, - accessActions: [AccessAction.Create, AccessAction.ReadAll], - tenantId + accessActions: [AccessAction.Create, AccessAction.ReadAll] } const grant = await grantService.getOrCreate(options) @@ -630,7 +578,6 @@ describe('Grant Service', (): void => { assert(!isGrantError(grant)) expect(grant).toMatchObject({ id: existingGrant.id, - tenantId, authServerId: existingGrant.authServerId, accessToken: rotatedAccessToken.access_token.value, expiresAt: new Date( @@ -658,8 +605,7 @@ describe('Grant Service', (): void => { const options = { authServer: authServer.url, accessType: AccessType.IncomingPayment, - accessActions: [AccessAction.Create, AccessAction.Read], - tenantId + accessActions: [AccessAction.Create, AccessAction.Read] } const authServerServiceGetOrCreateSoy = jest.spyOn( @@ -671,7 +617,6 @@ describe('Grant Service', (): void => { assert(!isGrantError(grant)) expect(grant).toMatchObject({ - tenantId, authServerId: authServer.id, accessType: options.accessType, accessActions: options.accessActions, @@ -716,8 +661,7 @@ describe('Grant Service', (): void => { AccessAction.Create, AccessAction.ReadAll, AccessAction.ListAll - ], - tenantId + ] } const authServerServiceGetOrCreateSoy = jest.spyOn( @@ -759,7 +703,6 @@ describe('Grant Service', (): void => { test('creates new grant and deletes old one after being unable to rotate existing token', async () => { const existingGrant = await Grant.query(knex).insertAndFetch({ - tenantId, authServerId: authServer.id, accessToken: uuid(), managementId: uuid(), @@ -788,8 +731,7 @@ describe('Grant Service', (): void => { const options = { authServer: authServer.url, accessType: AccessType.IncomingPayment, - accessActions: [AccessAction.Create, AccessAction.Read], - tenantId + accessActions: [AccessAction.Create, AccessAction.Read] } const grant = await grantService.getOrCreate(options) @@ -797,7 +739,6 @@ describe('Grant Service', (): void => { assert(!isGrantError(grant)) expect(grant.id).not.toBe(existingGrant.id) expect(grant).toMatchObject({ - tenantId, accessType: options.accessType, accessActions: options.accessActions, authServerId: authServer.id, @@ -824,8 +765,7 @@ describe('Grant Service', (): void => { const options = { authServer: authServer.url, accessType: AccessType.IncomingPayment, - accessActions: [AccessAction.Create, AccessAction.ReadAll], - tenantId + accessActions: [AccessAction.Create, AccessAction.ReadAll] } const error = await grantService.getOrCreate(options) @@ -842,8 +782,7 @@ describe('Grant Service', (): void => { const options = { authServer: authServer.url, accessType: AccessType.IncomingPayment, - accessActions: [AccessAction.Create, AccessAction.ReadAll], - tenantId + accessActions: [AccessAction.Create, AccessAction.ReadAll] } const error = await grantService.getOrCreate(options) @@ -864,7 +803,6 @@ describe('Grant Service', (): void => { test('gets existing grant (identical match)', async () => { const existingGrant = await Grant.query(knex).insertAndFetch({ - tenantId, authServerId: authServer.id, accessToken: uuid(), managementId: uuid(), @@ -875,8 +813,7 @@ describe('Grant Service', (): void => { const options = { authServer: authServer.url, accessType: AccessType.IncomingPayment, - accessActions: [AccessAction.ReadAll], - tenantId + accessActions: [AccessAction.ReadAll] } await expect( @@ -886,7 +823,6 @@ describe('Grant Service', (): void => { test('gets existing grant (requested actions are a subset of saved actions)', async () => { const existingGrant = await Grant.query(knex).insertAndFetch({ - tenantId, authServerId: authServer.id, accessToken: uuid(), managementId: uuid(), @@ -901,8 +837,7 @@ describe('Grant Service', (): void => { const options = { authServer: authServer.url, accessType: AccessType.IncomingPayment, - accessActions: [AccessAction.ReadAll, AccessAction.Create], - tenantId + accessActions: [AccessAction.ReadAll, AccessAction.Create] } await expect( @@ -912,7 +847,6 @@ describe('Grant Service', (): void => { test('ignores deleted grants', async () => { await Grant.query(knex).insertAndFetch({ - tenantId, authServerId: authServer.id, accessToken: uuid(), managementId: uuid(), @@ -924,8 +858,7 @@ describe('Grant Service', (): void => { const options = { authServer: authServer.url, accessType: AccessType.IncomingPayment, - accessActions: [AccessAction.ReadAll], - tenantId + accessActions: [AccessAction.ReadAll] } await expect( @@ -935,7 +868,6 @@ describe('Grant Service', (): void => { test('ignores different accessType', async () => { await Grant.query(knex).insertAndFetch({ - tenantId, authServerId: authServer.id, accessToken: uuid(), managementId: uuid(), @@ -946,8 +878,7 @@ describe('Grant Service', (): void => { const options = { authServer: authServer.url, accessType: AccessType.OutgoingPayment, - accessActions: [AccessAction.ReadAll], - tenantId + accessActions: [AccessAction.ReadAll] } await expect( @@ -957,7 +888,6 @@ describe('Grant Service', (): void => { test('ignores different auth server url', async () => { await Grant.query(knex).insertAndFetch({ - tenantId, authServerId: authServer.id, accessToken: uuid(), managementId: uuid(), @@ -968,8 +898,7 @@ describe('Grant Service', (): void => { const options = { authServer: uuid(), accessType: AccessType.IncomingPayment, - accessActions: [AccessAction.ReadAll], - tenantId + accessActions: [AccessAction.ReadAll] } await expect( @@ -979,7 +908,6 @@ describe('Grant Service', (): void => { test('ignores insufficient accessActions', async () => { await Grant.query(knex).insertAndFetch({ - tenantId, authServerId: authServer.id, accessToken: uuid(), managementId: uuid(), @@ -990,8 +918,7 @@ describe('Grant Service', (): void => { const options = { authServer: authServer.id, accessType: AccessType.IncomingPayment, - accessActions: [AccessAction.ReadAll, AccessAction.Create], - tenantId + accessActions: [AccessAction.ReadAll, AccessAction.Create] } await expect( @@ -1011,7 +938,6 @@ describe('Grant Service', (): void => { test('deletes grant', async () => { const existingGrant = await Grant.query(knex).insertAndFetch({ - tenantId, authServerId: authServer.id, accessToken: uuid(), managementId: uuid(), diff --git a/packages/backend/src/open_payments/grant/service.ts b/packages/backend/src/open_payments/grant/service.ts index 0ea8b10c34..a57f259763 100644 --- a/packages/backend/src/open_payments/grant/service.ts +++ b/packages/backend/src/open_payments/grant/service.ts @@ -40,7 +40,6 @@ interface GrantOptions { authServer: string accessType: AccessType accessActions: AccessAction[] - tenantId: string } interface UpdateOptions { @@ -99,7 +98,6 @@ export async function getExistingGrant( // 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) - .andWhere('tenantId', options.tenantId) .withGraphJoined('authServer') } @@ -150,7 +148,6 @@ async function requestNewGrant( accessToken: openPaymentsGrant.access_token.value, managementId: retrieveManagementId(openPaymentsGrant.access_token.manage), authServerId, - tenantId: options.tenantId, expiresAt: openPaymentsGrant.access_token.expires_in ? new Date( Date.now() + openPaymentsGrant.access_token.expires_in * 1000 diff --git a/packages/backend/src/open_payments/payment/incoming/model.test.ts b/packages/backend/src/open_payments/payment/incoming/model.test.ts index 142a87e999..cc69b660ad 100644 --- a/packages/backend/src/open_payments/payment/incoming/model.test.ts +++ b/packages/backend/src/open_payments/payment/incoming/model.test.ts @@ -46,6 +46,7 @@ describe('Models', (): void => { let walletAddress: WalletAddress let baseUrl: string let incomingPayment: IncomingPayment + let tenantId: string beforeEach(async (): Promise => { const config = await deps.use('config') @@ -55,7 +56,7 @@ describe('Models', (): void => { .query({ credentials_identifier: tenantEmail }) .reply(200, [{ id: uuid(), metadata_public: {} }]) .persist() - const tenantId = ( + tenantId = ( await createTenant(deps, { email: tenantEmail, idpSecret: 'testsecret', @@ -77,7 +78,7 @@ describe('Models', (): void => { describe('toOpenPaymentsType', () => { test('returns incoming payment', async () => { expect(incomingPayment.toOpenPaymentsType(walletAddress)).toEqual({ - id: `${baseUrl}${IncomingPayment.urlPath}/${incomingPayment.id}`, + id: `${baseUrl}/${tenantId}${IncomingPayment.urlPath}/${incomingPayment.id}`, walletAddress: walletAddress.url, completed: incomingPayment.completed, receivedAmount: serializeAmount(incomingPayment.receivedAmount), @@ -105,7 +106,7 @@ describe('Models', (): void => { streamCredentials ) ).toEqual({ - id: `${baseUrl}${IncomingPayment.urlPath}/${incomingPayment.id}`, + id: `${baseUrl}/${tenantId}${IncomingPayment.urlPath}/${incomingPayment.id}`, walletAddress: walletAddress.url, completed: incomingPayment.completed, receivedAmount: serializeAmount(incomingPayment.receivedAmount), @@ -130,7 +131,7 @@ describe('Models', (): void => { expect( incomingPayment.toOpenPaymentsTypeWithMethods(walletAddress) ).toEqual({ - id: `${baseUrl}${IncomingPayment.urlPath}/${incomingPayment.id}`, + id: `${baseUrl}/${tenantId}${IncomingPayment.urlPath}/${incomingPayment.id}`, walletAddress: walletAddress.url, completed: incomingPayment.completed, receivedAmount: serializeAmount(incomingPayment.receivedAmount), @@ -161,7 +162,7 @@ describe('Models', (): void => { streamCredentials ) ).toEqual({ - id: `${baseUrl}${IncomingPayment.urlPath}/${incomingPayment.id}`, + id: `${baseUrl}/${tenantId}${IncomingPayment.urlPath}/${incomingPayment.id}`, walletAddress: walletAddress.url, completed: incomingPayment.completed, receivedAmount: serializeAmount(incomingPayment.receivedAmount), diff --git a/packages/backend/src/open_payments/payment/incoming/routes.test.ts b/packages/backend/src/open_payments/payment/incoming/routes.test.ts index 4cd61c1f3e..c9174bbb2f 100644 --- a/packages/backend/src/open_payments/payment/incoming/routes.test.ts +++ b/packages/backend/src/open_payments/payment/incoming/routes.test.ts @@ -193,6 +193,9 @@ describe('Incoming Payment Routes', (): void => { async (error): Promise => { const ctx = setup>({ reqOpts: { body: {} }, + params: { + tenantId + }, walletAddress }) const createSpy = jest @@ -231,6 +234,9 @@ describe('Incoming Payment Routes', (): void => { method: 'POST', url: `/incoming-payments` }, + params: { + tenantId + }, walletAddress, client }) @@ -253,7 +259,7 @@ describe('Incoming Payment Routes', (): void => { .pop() expect(ctx.response.body).toEqual({ - id: `${baseUrl}/incoming-payments/${incomingPaymentId}`, + id: `${baseUrl}/${tenantId}/incoming-payments/${incomingPaymentId}`, walletAddress: walletAddress.url, incomingAmount: incomingAmount ? amount : undefined, expiresAt: expiresAt || expect.any(String), @@ -353,7 +359,7 @@ describe('Incoming Payment Routes', (): void => { await expect(incomingPaymentRoutes.get(ctx)).resolves.toBeUndefined() expect(ctx.response).toSatisfyApiSpec() expect(ctx.body).toEqual({ - authServer: config.authServerGrantUrl, + authServer: `${config.authServerGrantUrl}/${tenantId}`, receivedAmount: { value: '0', assetCode: asset.code, diff --git a/packages/backend/src/open_payments/payment/incoming_remote/service.ts b/packages/backend/src/open_payments/payment/incoming_remote/service.ts index 9e8154ea01..7d5a3f2614 100644 --- a/packages/backend/src/open_payments/payment/incoming_remote/service.ts +++ b/packages/backend/src/open_payments/payment/incoming_remote/service.ts @@ -16,7 +16,6 @@ import { isGrantError } from '../../grant/errors' interface CreateRemoteIncomingPaymentArgs { walletAddressUrl: string - tenantId: string expiresAt?: Date incomingAmount?: Amount metadata?: Record @@ -24,8 +23,7 @@ interface CreateRemoteIncomingPaymentArgs { export interface RemoteIncomingPaymentService { get( - url: string, - tenantId: string + url: string ): Promise< OpenPaymentsIncomingPaymentWithPaymentMethods | RemoteIncomingPaymentError > @@ -54,7 +52,7 @@ export async function createRemoteIncomingPaymentService( } return { - get: (url, tenantId) => get(deps, url, tenantId), + get: (url) => get(deps, url), create: (args) => create(deps, args) } } @@ -105,7 +103,6 @@ async function createIncomingPayment( const grantOptions = { authServer: walletAddress.authServer, - tenantId: createArgs.tenantId, accessType: AccessType.IncomingPayment, accessActions: [AccessAction.Create, AccessAction.ReadAll] } @@ -179,8 +176,7 @@ async function createIncomingPayment( async function get( deps: ServiceDependencies, - url: string, - tenantId: string + url: string ): Promise< OpenPaymentsIncomingPaymentWithPaymentMethods | RemoteIncomingPaymentError > { @@ -203,7 +199,6 @@ async function get( return getIncomingPayment(deps, { url, - tenantId, authServerUrl: publicIncomingPayment.authServer }) } @@ -212,12 +207,10 @@ async function getIncomingPayment( deps: ServiceDependencies, { url, - tenantId, authServerUrl, retryOnTokenError = true }: { url: string - tenantId: string authServerUrl: string retryOnTokenError?: boolean } @@ -225,7 +218,6 @@ async function getIncomingPayment( OpenPaymentsIncomingPaymentWithPaymentMethods | RemoteIncomingPaymentError > { const grantOptions = { - tenantId, authServer: authServerUrl, accessType: AccessType.IncomingPayment, accessActions: [AccessAction.ReadAll] @@ -279,7 +271,6 @@ async function getIncomingPayment( return getIncomingPayment(deps, { url, - tenantId, authServerUrl, retryOnTokenError: false }) diff --git a/packages/backend/src/open_payments/payment/outgoing/service.test.ts b/packages/backend/src/open_payments/payment/outgoing/service.test.ts index 9c4954bc57..b7e46195d7 100644 --- a/packages/backend/src/open_payments/payment/outgoing/service.test.ts +++ b/packages/backend/src/open_payments/payment/outgoing/service.test.ts @@ -345,7 +345,6 @@ describe('OutgoingPaymentService', (): void => { test('throws error if cannot find liquidity account for SENDING payment', async () => { const quote = await createQuote(deps, { walletAddressId, - tenantId, receiver, debitAmount, method: 'ilp' @@ -515,7 +514,6 @@ describe('OutgoingPaymentService', (): void => { test('throws error if cannot find liquidity account for SENDING payment', async () => { const quote = await createQuote(deps, { walletAddressId, - tenantId, receiver, debitAmount, method: 'ilp' @@ -653,7 +651,6 @@ describe('OutgoingPaymentService', (): void => { expect(!isOutgoingPaymentError(payment)).toBeTruthy() expect(quoteSpy).toHaveBeenCalledWith({ walletAddressId, - tenantId, receiver: incomingPaymentUrl, debitAmount, method: 'ilp' @@ -780,7 +777,6 @@ describe('OutgoingPaymentService', (): void => { expect(payment).toBe(quoteCreateResponse) expect(quoteSpy).toHaveBeenCalledWith({ walletAddressId, - tenantId, receiver: incomingPaymentUrl, debitAmount, method: 'ilp' @@ -822,7 +818,6 @@ describe('OutgoingPaymentService', (): void => { const peer = await createPeer(deps) const quote = await createQuote(deps, { walletAddressId, - tenantId, receiver, debitAmount, method: 'ilp' @@ -887,7 +882,6 @@ describe('OutgoingPaymentService', (): void => { it('fails to create on unknown wallet address', async () => { const { id: quoteId } = await createQuote(deps, { walletAddressId, - tenantId, receiver, debitAmount, validDestination: false, @@ -934,7 +928,6 @@ describe('OutgoingPaymentService', (): void => { it('fails to create on invalid quote wallet address', async () => { const quote = await createQuote(deps, { walletAddressId, - tenantId, receiver, debitAmount, validDestination: false, @@ -952,7 +945,6 @@ describe('OutgoingPaymentService', (): void => { it('fails to create on expired quote', async () => { const quote = await createQuote(deps, { walletAddressId, - tenantId, receiver, debitAmount, validDestination: false, @@ -978,7 +970,6 @@ describe('OutgoingPaymentService', (): void => { async ({ state }): Promise => { const quote = await createQuote(deps, { walletAddressId, - tenantId, receiver, debitAmount, method: 'ilp' @@ -1001,7 +992,6 @@ describe('OutgoingPaymentService', (): void => { test('fails to create on inactive wallet address', async () => { const { id: quoteId } = await createQuote(deps, { walletAddressId, - tenantId, receiver, debitAmount, validDestination: false, @@ -1032,7 +1022,6 @@ describe('OutgoingPaymentService', (): void => { [0, 1].map(async (_) => { return await createQuote(deps, { walletAddressId, - tenantId, receiver, debitAmount, method: 'ilp' @@ -1083,10 +1072,8 @@ describe('OutgoingPaymentService', (): void => { let options: UnionOmit let interval: string beforeEach(async (): Promise => { - console.log('tenantId=', tenantId) quote = await createQuote(deps, { walletAddressId, - tenantId, receiver, debitAmount, method: 'ilp' @@ -1329,6 +1316,7 @@ describe('OutgoingPaymentService', (): void => { } const payment = await createOutgoingPayment(deps, { walletAddressId, + tenantId, client, ...opts }) @@ -1363,7 +1351,6 @@ describe('OutgoingPaymentService', (): void => { assert.ok(incomingPayment.walletAddress) const createdPayment = await setup({ - tenantId, receiver: incomingPayment.getUrl(incomingPayment.walletAddress), receiveAmount, method: 'ilp' @@ -1396,7 +1383,6 @@ describe('OutgoingPaymentService', (): void => { .spyOn(telemetryService!, 'incrementCounter') .mockImplementation(() => Promise.resolve()) const createdPayment = await setup({ - tenantId, receiver, debitAmount, method: 'ilp' @@ -1447,7 +1433,6 @@ describe('OutgoingPaymentService', (): void => { assert.ok(incomingPayment.walletAddress) const createdPayment = await setup({ - tenantId, receiver: incomingPayment.getUrl(incomingPayment.walletAddress), receiveAmount, method: 'ilp' @@ -1483,7 +1468,6 @@ describe('OutgoingPaymentService', (): void => { const spyCounter = jest.spyOn(telemetryService, 'incrementCounter') const createdPayment = await setup({ - tenantId, receiver, debitAmount, receiveAmount, @@ -1538,7 +1522,6 @@ describe('OutgoingPaymentService', (): void => { assert.ok(incomingPayment.receivedAmount?.assetScale) const createdPayment = await setup({ - tenantId, receiver: incomingPayment.getUrl(incomingPayment.walletAddress), receiveAmount, method: 'ilp' @@ -1561,7 +1544,6 @@ describe('OutgoingPaymentService', (): void => { test('COMPLETED (with incoming payment initially partially paid)', async (): Promise => { const createdPayment = await setup( { - tenantId, receiver, receiveAmount, method: 'ilp' @@ -1599,7 +1581,6 @@ describe('OutgoingPaymentService', (): void => { test('SENDING -> FAILED (partial payment then retryable Pay error)', async (): Promise => { const createdPayment = await setup({ - tenantId, receiver, debitAmount, method: 'ilp' @@ -1650,7 +1631,6 @@ describe('OutgoingPaymentService', (): void => { test('FAILED (non-retryable error)', async (): Promise => { const createdPayment = await setup({ - tenantId, receiver, debitAmount, method: 'ilp' @@ -1682,7 +1662,6 @@ describe('OutgoingPaymentService', (): void => { test('SENDING→COMPLETED (partial payment, resume, complete)', async (): Promise => { const createdPayment = await setup({ - tenantId, receiver, receiveAmount, method: 'ilp' @@ -1714,7 +1693,6 @@ describe('OutgoingPaymentService', (): void => { test('COMPLETED (already fully paid)', async (): Promise => { const createdPayment = await setup( { - tenantId, receiver, receiveAmount, method: 'ilp' @@ -1746,7 +1724,6 @@ describe('OutgoingPaymentService', (): void => { test('COMPLETED (already fully paid)', async (): Promise => { const { id: paymentId } = await setup( { - tenantId, receiver, receiveAmount, method: 'ilp' @@ -1772,7 +1749,6 @@ describe('OutgoingPaymentService', (): void => { test('FAILED (source asset changed)', async (): Promise => { const { id: paymentId } = await setup( { - tenantId, receiver, receiveAmount, method: 'ilp' @@ -1797,7 +1773,6 @@ describe('OutgoingPaymentService', (): void => { }) test('FAILED (destination asset changed)', async (): Promise => { const createdPayment = await setup({ - tenantId, receiver, debitAmount, method: 'ilp' diff --git a/packages/backend/src/open_payments/payment/outgoing/service.ts b/packages/backend/src/open_payments/payment/outgoing/service.ts index afcbd80128..de4e109fdb 100644 --- a/packages/backend/src/open_payments/payment/outgoing/service.ts +++ b/packages/backend/src/open_payments/payment/outgoing/service.ts @@ -225,8 +225,7 @@ async function createOutgoingPayment( receiver: incomingPayment, debitAmount, method: 'ilp', - walletAddressId, - tenantId: options.tenantId + walletAddressId }) if (isQuoteError(quoteOrError)) { @@ -288,10 +287,7 @@ async function createOutgoingPayment( throw OutgoingPaymentError.InsufficientGrant } } - const receiver = await deps.receiverService.get( - payment.receiver, - options.tenantId - ) + const receiver = await deps.receiverService.get(payment.receiver) if (!receiver) { throw OutgoingPaymentError.InvalidQuote } diff --git a/packages/backend/src/open_payments/quote/routes.test.ts b/packages/backend/src/open_payments/quote/routes.test.ts index 7dff1bcc35..5da9721a10 100644 --- a/packages/backend/src/open_payments/quote/routes.test.ts +++ b/packages/backend/src/open_payments/quote/routes.test.ts @@ -45,8 +45,7 @@ describe('Quote Routes', (): void => { const createWalletAddressQuote = async ({ walletAddressId, - client, - tenantId + client }: { walletAddressId: string tenantId: string @@ -54,7 +53,6 @@ describe('Quote Routes', (): void => { }): Promise => { return await createQuote(deps, { walletAddressId, - tenantId, receiver, debitAmount: { value: BigInt(56), @@ -219,7 +217,6 @@ describe('Quote Routes', (): void => { await expect(quoteRoutes.create(ctx)).resolves.toBeUndefined() expect(quoteSpy).toHaveBeenCalledWith({ walletAddressId: walletAddress.id, - tenantId: walletAddress.tenantId, receiver, debitAmount: options.debitAmount && { ...options.debitAmount, @@ -279,7 +276,6 @@ describe('Quote Routes', (): void => { await expect(quoteRoutes.create(ctx)).resolves.toBeUndefined() expect(quoteSpy).toHaveBeenCalledWith({ walletAddressId: walletAddress.id, - tenantId: walletAddress.tenantId, receiver, client, method: 'ilp' diff --git a/packages/backend/src/open_payments/quote/routes.ts b/packages/backend/src/open_payments/quote/routes.ts index a20073fc30..d0069280fc 100644 --- a/packages/backend/src/open_payments/quote/routes.ts +++ b/packages/backend/src/open_payments/quote/routes.ts @@ -73,9 +73,7 @@ async function createQuote( ctx: CreateContext ): Promise { const { body } = ctx.request - const { tenantId } = ctx.params const options: CreateQuoteOptions = { - tenantId, walletAddressId: ctx.walletAddress.id, receiver: body.receiver, client: ctx.client, diff --git a/packages/backend/src/open_payments/quote/service.test.ts b/packages/backend/src/open_payments/quote/service.test.ts index 2a282a342e..8c36d18913 100644 --- a/packages/backend/src/open_payments/quote/service.test.ts +++ b/packages/backend/src/open_payments/quote/service.test.ts @@ -131,7 +131,6 @@ describe('QuoteService', (): void => { createModel: ({ client }) => createQuote(deps, { walletAddressId: sendingWalletAddress.id, - tenantId, receiver: `${receivingWalletAddress.url}/incoming-payments/${uuid()}`, debitAmount: { value: BigInt(56), @@ -177,7 +176,6 @@ describe('QuoteService', (): void => { }) options = { walletAddressId: sendingWalletAddress.id, - tenantId, receiver: incomingPayment.getUrl(receivingWalletAddress), method: 'ilp' } @@ -373,7 +371,6 @@ describe('QuoteService', (): void => { }) const options: CreateQuoteOptions = { walletAddressId: sendingWalletAddress.id, - tenantId, receiver: incomingPayment.getUrl(receivingWalletAddress), receiveAmount, method: 'ilp' @@ -446,7 +443,6 @@ describe('QuoteService', (): void => { await expect( quoteService.create({ walletAddressId: sendingWalletAddress.id, - tenantId, receiver: receiver.incomingPayment!.id, method: 'ilp' }) @@ -464,7 +460,6 @@ describe('QuoteService', (): void => { await expect( quoteService.create({ walletAddressId: uuid(), - tenantId, receiver: `${receivingWalletAddress.url}/incoming-payments/${uuid()}`, debitAmount, method: 'ilp' @@ -481,7 +476,6 @@ describe('QuoteService', (): void => { await expect( quoteService.create({ walletAddressId: walletAddress.id, - tenantId, receiver: `${receivingWalletAddress.url}/incoming-payments/${uuid()}`, debitAmount, method: 'ilp' @@ -493,7 +487,6 @@ describe('QuoteService', (): void => { await expect( quoteService.create({ walletAddressId: sendingWalletAddress.id, - tenantId, receiver: `${receivingWalletAddress.url}/incoming-payments/${uuid()}`, debitAmount, method: 'ilp' @@ -516,7 +509,6 @@ describe('QuoteService', (): void => { await expect( quoteService.create({ walletAddressId: sendingWalletAddress.id, - tenantId, receiver: receiver.incomingPayment!.id, method: 'ilp', debitAmount: { @@ -546,7 +538,6 @@ describe('QuoteService', (): void => { }) const options: CreateQuoteOptions = { walletAddressId: sendingWalletAddress.id, - tenantId, receiver: incomingPayment.getUrl(receivingWalletAddress), method: 'ilp' } @@ -618,7 +609,6 @@ describe('QuoteService', (): void => { const quote = await quoteService.create({ walletAddressId: sendingWalletAddress.id, - tenantId, receiver: receiver.incomingPayment!.id, method: 'ilp' }) @@ -657,7 +647,6 @@ describe('QuoteService', (): void => { await expect( quoteService.create({ walletAddressId: sendingWalletAddress.id, - tenantId, receiver: receiver.incomingPayment!.id, method: 'ilp' }) @@ -728,7 +717,6 @@ describe('QuoteService', (): void => { const quote = await quoteService.create({ walletAddressId: sendingWalletAddress.id, - tenantId, receiver: receiver.incomingPayment!.id, debitAmount: { value: debitAmountValue, @@ -772,7 +760,6 @@ describe('QuoteService', (): void => { await expect( quoteService.create({ walletAddressId: sendingWalletAddress.id, - tenantId, receiver: receiver.incomingPayment!.id, debitAmount: { value: debitAmountValue, diff --git a/packages/backend/src/open_payments/quote/service.ts b/packages/backend/src/open_payments/quote/service.ts index 0ce81fe63d..4a3512e960 100644 --- a/packages/backend/src/open_payments/quote/service.ts +++ b/packages/backend/src/open_payments/quote/service.ts @@ -61,7 +61,6 @@ async function getQuote( interface QuoteOptionsBase { walletAddressId: string - tenantId: string receiver: string method: 'ilp' client?: string @@ -77,10 +76,9 @@ interface QuoteOptionsWithReceiveAmount extends QuoteOptionsBase { debitAmount?: never } -export type CreateQuoteOptions = { tenantId: string } & ( +export type CreateQuoteOptions = | QuoteOptionsWithDebitAmount | QuoteOptionsWithReceiveAmount -) async function createQuote( deps: ServiceDependencies, @@ -148,7 +146,7 @@ async function createQuote( client: options.client, feeId: sendingFee?.id, estimatedExchangeRate: quote.estimatedExchangeRate, - tenantId: options.tenantId + tenantId: walletAddress.tenantId }) .withGraphFetched('[asset, fee, walletAddress]') @@ -183,10 +181,7 @@ export async function resolveReceiver( deps: ServiceDependencies, options: CreateQuoteOptions ): Promise { - const receiver = await deps.receiverService.get( - options.receiver, - options.tenantId - ) + const receiver = await deps.receiverService.get(options.receiver) if (!receiver) { deps.logger.info( { receiver: options.receiver }, diff --git a/packages/backend/src/open_payments/receiver/service.ts b/packages/backend/src/open_payments/receiver/service.ts index 10a12f1c57..cfd04f55f1 100644 --- a/packages/backend/src/open_payments/receiver/service.ts +++ b/packages/backend/src/open_payments/receiver/service.ts @@ -17,7 +17,6 @@ import { isRemoteIncomingPaymentError } from '../payment/incoming_remote/errors' interface CreateReceiverArgs { walletAddressUrl: string - tenantId: string expiresAt?: Date incomingAmount?: Amount metadata?: Record @@ -25,7 +24,7 @@ interface CreateReceiverArgs { // A receiver is resolved from an incoming payment export interface ReceiverService { - get(url: string, tenantId: string): Promise + get(url: string): Promise create(args: CreateReceiverArgs): Promise } @@ -51,7 +50,7 @@ export async function createReceiverService( } return { - get: (url, tenantId) => getReceiver(deps, url, tenantId), + get: (url) => getReceiver(deps, url), create: (url) => createReceiver(deps, url) } } @@ -136,8 +135,7 @@ async function createLocalIncomingPayment( async function getReceiver( deps: ServiceDependencies, - url: string, - tenantId: string + url: string ): Promise { try { const localIncomingPayment = await getLocalIncomingPayment(deps, url) @@ -145,11 +143,7 @@ async function getReceiver( return new Receiver(localIncomingPayment, true) } - const remoteIncomingPayment = await getRemoteIncomingPayment( - deps, - url, - tenantId - ) + const remoteIncomingPayment = await getRemoteIncomingPayment(deps, url) if (remoteIncomingPayment) { return new Receiver(remoteIncomingPayment, false) } @@ -218,13 +212,10 @@ export async function getLocalIncomingPayment( async function getRemoteIncomingPayment( deps: ServiceDependencies, - url: string, - tenantId: string + url: string ): Promise { - const incomingPaymentOrError = await deps.remoteIncomingPaymentService.get( - url, - tenantId - ) + const incomingPaymentOrError = + await deps.remoteIncomingPaymentService.get(url) if (isRemoteIncomingPaymentError(incomingPaymentOrError)) { return undefined diff --git a/packages/backend/src/open_payments/wallet_address/routes.test.ts b/packages/backend/src/open_payments/wallet_address/routes.test.ts index a049eadf70..cdc7b48065 100644 --- a/packages/backend/src/open_payments/wallet_address/routes.test.ts +++ b/packages/backend/src/open_payments/wallet_address/routes.test.ts @@ -143,8 +143,8 @@ describe('Wallet Address Routes', (): void => { publicName: walletAddress.publicName, assetCode: walletAddress.asset.code, assetScale: walletAddress.asset.scale, - authServer: config.authServerGrantUrl, - resourceServer: config.openPaymentsUrl, + authServer: `${config.authServerGrantUrl}/${tenantId}`, + resourceServer: `${config.openPaymentsUrl}/${tenantId}`, additionalProperties: { [addProp.fieldKey]: addProp.fieldValue } @@ -185,8 +185,8 @@ describe('Wallet Address Routes', (): void => { publicName: walletAddress.publicName, assetCode: walletAddress.asset.code, assetScale: walletAddress.asset.scale, - authServer: config.authServerGrantUrl, - resourceServer: config.openPaymentsUrl + authServer: `${config.authServerGrantUrl}/${tenantId}`, + resourceServer: `${config.openPaymentsUrl}/${tenantId}` }) }) }) diff --git a/packages/backend/src/payment-method/ilp/service.test.ts b/packages/backend/src/payment-method/ilp/service.test.ts index 3b50a0acbf..c44d47e468 100644 --- a/packages/backend/src/payment-method/ilp/service.test.ts +++ b/packages/backend/src/payment-method/ilp/service.test.ts @@ -78,6 +78,11 @@ describe('IlpPaymentService', (): void => { .post('/recovery/link') .reply(200, { recovery_link: faker.internet.url() }) .persist() + + nock(config.authAdminApiUrl) + .post('') + .reply(200, { data: { createAuthTenant: { success: true } } }) + .persist() tenantId = ( await createTenant(deps, { email: tenantEmail, diff --git a/packages/backend/src/shared/pagination.test.ts b/packages/backend/src/shared/pagination.test.ts index 97af6fe728..5bba323d4d 100644 --- a/packages/backend/src/shared/pagination.test.ts +++ b/packages/backend/src/shared/pagination.test.ts @@ -269,7 +269,6 @@ describe('Pagination', (): void => { for (let i = 0; i < num; i++) { const quote = await createQuote(deps, { walletAddressId: defaultWalletAddress.id, - tenantId: defaultWalletAddress.tenantId, receiver: secondaryWalletAddress.url, debitAmount, validDestination: false, diff --git a/packages/backend/src/tests/outgoingPayment.ts b/packages/backend/src/tests/outgoingPayment.ts index e54abfadd0..d96e042fa7 100644 --- a/packages/backend/src/tests/outgoingPayment.ts +++ b/packages/backend/src/tests/outgoingPayment.ts @@ -29,8 +29,7 @@ export async function createOutgoingPayment( receiver: options.receiver, validDestination: options.validDestination, exchangeRate: options.exchangeRate, - method: options.method, - tenantId: options.tenantId + method: options.method } if (options.debitAmount) quoteOptions.debitAmount = options.debitAmount if (options.receiveAmount) quoteOptions.receiveAmount = options.receiveAmount diff --git a/packages/frontend/app/generated/graphql.ts b/packages/frontend/app/generated/graphql.ts index 8ad9bd8d01..d292352fc0 100644 --- a/packages/frontend/app/generated/graphql.ts +++ b/packages/frontend/app/generated/graphql.ts @@ -243,6 +243,8 @@ export type CreateOutgoingPaymentFromIncomingPaymentInput = { incomingPayment: Scalars['String']['input']; /** Additional metadata associated with the outgoing payment. */ metadata?: InputMaybe; + /** ID of a tenant */ + tenantId: Scalars['ID']['input']; /** Id of the wallet address under which the outgoing payment will be created */ walletAddressId: Scalars['String']['input']; }; @@ -315,8 +317,6 @@ export type CreateQuoteInput = { receiveAmount?: InputMaybe; /** Wallet address URL of the receiver */ receiver: Scalars['String']['input']; - /** ID of the tenant */ - tenantId: Scalars['ID']['input']; /** Id of the wallet address under which the quote will be created */ walletAddressId: Scalars['String']['input']; }; @@ -2756,7 +2756,7 @@ export type ListTenantsQueryVariables = Exact<{ }>; -export type ListTenantsQuery = { __typename?: 'Query', tenants: { __typename?: 'TenantsConnection', edges: Array<{ __typename?: 'TenantEdge', node: { __typename?: 'Tenant', id: string, createdAt: string } }>, pageInfo: { __typename?: 'PageInfo', startCursor?: string | null, endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean } } }; +export type ListTenantsQuery = { __typename?: 'Query', tenants: { __typename?: 'TenantsConnection', edges: Array<{ __typename?: 'TenantEdge', node: { __typename?: 'Tenant', id: string, createdAt: string, email: string } }>, pageInfo: { __typename?: 'PageInfo', startCursor?: string | null, endCursor?: string | null, hasNextPage: boolean, hasPreviousPage: boolean } } }; export type CreateTenantMutationVariables = Exact<{ input: CreateTenantInput; diff --git a/packages/mock-account-service-lib/src/generated/graphql.ts b/packages/mock-account-service-lib/src/generated/graphql.ts index dea9da36e2..5cff685570 100644 --- a/packages/mock-account-service-lib/src/generated/graphql.ts +++ b/packages/mock-account-service-lib/src/generated/graphql.ts @@ -243,6 +243,8 @@ export type CreateOutgoingPaymentFromIncomingPaymentInput = { incomingPayment: Scalars['String']['input']; /** Additional metadata associated with the outgoing payment. */ metadata?: InputMaybe; + /** ID of a tenant */ + tenantId: Scalars['ID']['input']; /** Id of the wallet address under which the outgoing payment will be created */ walletAddressId: Scalars['String']['input']; }; @@ -315,8 +317,6 @@ export type CreateQuoteInput = { receiveAmount?: InputMaybe; /** Wallet address URL of the receiver */ receiver: Scalars['String']['input']; - /** ID of the tenant */ - tenantId: Scalars['ID']['input']; /** Id of the wallet address under which the quote will be created */ walletAddressId: Scalars['String']['input']; }; diff --git a/test/integration/lib/generated/graphql.ts b/test/integration/lib/generated/graphql.ts index dea9da36e2..5cff685570 100644 --- a/test/integration/lib/generated/graphql.ts +++ b/test/integration/lib/generated/graphql.ts @@ -243,6 +243,8 @@ export type CreateOutgoingPaymentFromIncomingPaymentInput = { incomingPayment: Scalars['String']['input']; /** Additional metadata associated with the outgoing payment. */ metadata?: InputMaybe; + /** ID of a tenant */ + tenantId: Scalars['ID']['input']; /** Id of the wallet address under which the outgoing payment will be created */ walletAddressId: Scalars['String']['input']; }; @@ -315,8 +317,6 @@ export type CreateQuoteInput = { receiveAmount?: InputMaybe; /** Wallet address URL of the receiver */ receiver: Scalars['String']['input']; - /** ID of the tenant */ - tenantId: Scalars['ID']['input']; /** Id of the wallet address under which the quote will be created */ walletAddressId: Scalars['String']['input']; };