Skip to content

Commit

Permalink
Lots of fixes w/ scenario test; changing initiatedBy to be userId not…
Browse files Browse the repository at this point in the history
… credentialId or token, tests not fully passing yet
  • Loading branch information
mattschoch committed Aug 23, 2024
1 parent b30eb31 commit ca57f52
Show file tree
Hide file tree
Showing 33 changed files with 637 additions and 669 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { ConfigService } from '@narval/config-module'
import { AuthorizationRequest, Feed, HistoricalTransfer, JwtString } from '@narval/policy-engine-shared'
import { Alg, Payload, SigningAlg, decodeJwt, hash, hexToBase64Url, privateKeyToJwk, signJwt } from '@narval/signature'
import { Alg, Payload, SigningAlg, hash, hexToBase64Url, privateKeyToJwk, signJwt } from '@narval/signature'
import { Injectable } from '@nestjs/common'
import { omit } from 'lodash/fp'
import { privateKeyToAccount } from 'viem/accounts'
import { Config } from '../../../armory.config'
import { DataFeed } from '../../../data-feed/core/type/data-feed.type'
import { FiatId, Price } from '../../../shared/core/type/price.type'
import { Transfer } from '../../../shared/core/type/transfer-tracking.type'
import { ApplicationException } from '../../../shared/exception/application.exception'
import { TransferTrackingService } from '../../../transfer-tracking/core/service/transfer-tracking.service'

const buildHistoricalTranferRates = (rates: Price): Record<string, string> => {
Expand Down Expand Up @@ -87,21 +86,8 @@ export class HistoricalTransferFeedService implements DataFeed<HistoricalTransfe

static build(transfers: Transfer[]): HistoricalTransfer[] {
return transfers.map((transfer) => {
const initiatedBy = decodeJwt(transfer.initiatedBy).payload.sub
if (!initiatedBy) {
throw new ApplicationException({
message: 'Decoded JWT for approved transfer does not contain a sub field',
context: {
transfer,
initiatedBy,
decodedJwt: decodeJwt(transfer.initiatedBy)
},
suggestedHttpStatusCode: 500
})
}
return {
...omit('clientId', transfer),
initiatedBy,
amount: transfer.amount.toString(),
timestamp: transfer.createdAt.getTime(),
rates: buildHistoricalTranferRates(transfer.rates)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,17 @@ export class AuthorizationRequestService {
try {
const authzRequest = await this.authzRequestRepository.update({
id: requestId,
approvals: [sig]
approvals: [sig],
status: AuthorizationRequestStatus.APPROVING
})

await this.evaluate(authzRequest)
} catch (error) {
this.logger.error('Error approving authorization request', {
requestId,
sig,
error
})
await this.authzRequestApprovalRepository.updateMany({
requestId,
sig,
Expand Down Expand Up @@ -165,6 +171,17 @@ export class AuthorizationRequestService {
to: [FIAT_ID_USD]
})

// This should never happen, a successful permit always has a principal, so this is just a fail-safe check.
if (!evaluation.principal?.userId) {
throw new ApplicationException({
message: 'Principal userId not found',
context: {
evaluation
},
suggestedHttpStatusCode: HttpStatus.BAD_REQUEST
})
}

const transfer = {
resourceId: authzRequest.request.resourceId,
clientId: authzRequest.clientId,
Expand All @@ -173,9 +190,7 @@ export class AuthorizationRequestService {
to: intent.to,
token: intent.token,
chainId: authzRequest.request.transactionRequest.chainId,
// TODO: (@mattschoch) Get real initiator? -- this used to reference publicKey but
// should actually pull data out of a decoded JWT
initiatedBy: authzRequest.authentication,
initiatedBy: evaluation.principal?.userId,
createdAt: new Date(),
amount: BigInt(intent.amount),
rates: transferPrices[intent.token] || {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ApiClientIdGuard } from '../../../../shared/decorator/api-client-id-gua
import { ClientId } from '../../../../shared/decorator/client-id.decorator'
import { ErrorResponseDto } from '../../../../shared/dto/error-response.dto'
import { AuthorizationRequestService } from '../../../core/service/authorization-request.service'
import { AuthorizationRequestDto } from '../../../http/rest/dto/authorization-request.dto'
import { ApprovalDto, AuthorizationRequestDto } from '../../../http/rest/dto/authorization-request.dto'
import { AuthorizationResponseDto } from '../../../http/rest/dto/authorization-response.dto'
import { toCreateAuthorizationRequest } from '../../../http/rest/util'

Expand Down Expand Up @@ -70,9 +70,8 @@ export class AuthorizationRequestController {
status: HttpStatus.CREATED,
type: AuthorizationResponseDto
})
async approve(@Param('id') id: string, @Body() body: string): Promise<AuthorizationResponseDto> {
const authzRequest = await this.authorizationRequestService.approve(id, body)

async approve(@Param('id') id: string, @Body() body: ApprovalDto): Promise<AuthorizationResponseDto> {
const authzRequest = await this.authorizationRequestService.approve(id, body.signature)
return AuthorizationResponseDto.create(authzRequest)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AuthorizationRequest, SerializedAuthorizationRequest } from '@narval/policy-engine-shared'
import { AuthorizationRequest, JwtString, SerializedAuthorizationRequest } from '@narval/policy-engine-shared'
import { createZodDto } from 'nestjs-zod'
import { z } from 'zod'

export class AuthorizationRequestDto extends createZodDto(
SerializedAuthorizationRequest.pick({
Expand All @@ -10,3 +11,9 @@ export class AuthorizationRequestDto extends createZodDto(
approvals: AuthorizationRequest.shape.approvals.optional()
})
) {}

export class ApprovalDto extends createZodDto(
z.object({
signature: JwtString
})
) {}
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,10 @@ export class AuthorizationRequestRepository {
Pick<AuthorizationRequest, 'id'>
): Promise<AuthorizationRequest> {
const { id, clientId, status } = input
const approvals = (input.approvals || []).map((sig) => ({ sig }))
const approvals: Prisma.AuthorizationRequestApprovalCreateManyRequestInput[] = (input.approvals || []).map(
(sig) => ({ sig })
)
const errors = this.toErrors(clientId, input.errors)

// TODO (@wcalderipe, 19/01/24): Cover the skipDuplicate with tests.
await this.prismaService.authorizationRequest.update({
where: { id },
Expand Down

This file was deleted.

Loading

0 comments on commit ca57f52

Please sign in to comment.