• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

cameri / nostream / 24277709975

11 Apr 2026 07:31AM UTC coverage: 46.576% (+0.01%) from 46.562%
24277709975

Pull #426

github

web-flow
Merge 2bd7e76b0 into 0e96e47b7
Pull Request #426: FIXES TODO in callbacks: implement strict validation for all payment callbacks

406 of 985 branches covered (41.22%)

Branch coverage included in aggregate %.

21 of 52 new or added lines in 8 files covered. (40.38%)

4 existing lines in 3 files now uncovered.

1240 of 2549 relevant lines covered (48.65%)

9.07 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

18.42
/src/controllers/callbacks/opennode-callback-controller.ts
1
import { Request, Response } from 'express'
2

3
import { Invoice, InvoiceStatus } from '../../@types/invoice'
2✔
4
import { createLogger } from '../../factories/logger-factory'
2✔
5
import { fromOpenNodeInvoice } from '../../utils/transform'
2✔
6
import { IController } from '../../@types/controllers'
7
import { IPaymentsService } from '../../@types/services'
8
import { opennodeCallbackBodySchema } from '../../schemas/opennode-callback-schema'
2✔
9
import { validateSchema } from '../../utils/validation'
2✔
10

11
const debug = createLogger('opennode-callback-controller')
2✔
12

13
export class OpenNodeCallbackController implements IController {
2✔
14
  public constructor(
15
    private readonly paymentsService: IPaymentsService,
×
16
  ) {}
17

18
  public async handleRequest(
19
    request: Request,
20
    response: Response,
21
  ) {
22
    debug('request headers: %o', request.headers)
×
23
    debug('request body: %O', request.body)
×
24

NEW
25
    const bodyValidation = validateSchema(opennodeCallbackBodySchema)(request.body)
×
NEW
26
    if (bodyValidation.error) {
×
NEW
27
      debug('opennode callback request rejected: invalid body %o', bodyValidation.error)
×
NEW
28
      response
×
29
        .status(400)
30
        .setHeader('content-type', 'text/plain; charset=utf8')
31
        .send('Malformed body')
NEW
32
      return
×
33
    }
34

UNCOV
35
    const invoice = fromOpenNodeInvoice(request.body)
×
36

37
    debug('invoice', invoice)
×
38

39
    let updatedInvoice: Invoice
40
    try {
×
41
      updatedInvoice = await this.paymentsService.updateInvoiceStatus(invoice)
×
42
    } catch (error) {
43
      console.error(`Unable to persist invoice ${invoice.id}`, error)
×
44

45
      throw error
×
46
    }
47

48
    if (
×
49
      updatedInvoice.status !== InvoiceStatus.COMPLETED
×
50
      && !updatedInvoice.confirmedAt
51
    ) {
52
      response
×
53
        .status(200)
54
        .send()
55

56
      return
×
57
    }
58

59
    invoice.amountPaid = invoice.amountRequested
×
60
    updatedInvoice.amountPaid = invoice.amountRequested
×
61

62
    try {
×
63
      await this.paymentsService.confirmInvoice({
×
64
        id: invoice.id,
65
        pubkey: invoice.pubkey,
66
        status: updatedInvoice.status,
67
        amountPaid: updatedInvoice.amountRequested,
68
        confirmedAt: updatedInvoice.confirmedAt,
69
      })
70
      await this.paymentsService.sendInvoiceUpdateNotification(updatedInvoice)
×
71
    } catch (error) {
72
      console.error(`Unable to confirm invoice ${invoice.id}`, error)
×
73

74
      throw error
×
75
    }
76

77
    response
×
78
      .status(200)
79
      .setHeader('content-type', 'text/plain; charset=utf8')
80
      .send('OK')
81
  }
82
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc