Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TLRV2-15] Add CI to bloom api #5

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: run bloom tests
name: run bloom api tests
on:
pull_request:
branches:
Expand All @@ -18,3 +18,5 @@ jobs:
- name: run test
run: yarn test
shell: bash
env:
ONRAMP_WEBHOOK_KEY: ${{ secrets.ONRAMP_WEBHOOK_KEY }}
8 changes: 8 additions & 0 deletions lib/mongo-interface.ts → lib/mongo-database.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import { Mongoose, Schema } from 'mongoose'

export interface MongoDatabaseInterface {
WebhookErrorModel: any
WebhookReceiptModel: any

init: (dbName: string, config?: any) => Promise<void>
dropDatabase: () => Promise<void>
}

export interface WebhookError {
requestInput: any
errorMessage: any
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"ethereumjs-util": "^7.1.4",
"ethers": "^5.5.0",
"express": "^4.17.1",
"mini-route-loader": "^0.22.0",
"mini-route-loader": "^0.25.1",
"mongodb": "^3.6.5",
"mongoose": "^6.2.9",
"nodemailer": "^6.7.3",
Expand Down
12 changes: 5 additions & 7 deletions server/config/routes.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
[
{"type":"get","uri":"/api/ping","method":"ping","controller":"api"},

{"type":"post","uri":"/api/webhook","method":"receiveBNPLKYC","controller":"api"},
{"type":"post","uri":"/api/bnpl-kyc/webhook","method":"receiveBNPLKYC","controller":"api"},
{"type":"post","uri":"/api/bnpl-lender/webhook","method":"receiveBNPLLender","controller":"api"},
{"type":"post","uri":"/api/mortgage-borrower/webhook","method":"receiveMortgageBorrower","controller":"api"} ,
{"type":"post","uri":"/api/mortgage-lender/webhook","method":"receiveMortgageLender","controller":"api"}
{"type":"post","uri":"/api/webhook","method":"receiveWebhook","controller":"api", "appendParams":{"type":"BNPL_KYC"}},
{"type":"post","uri":"/api/bnpl-kyc/webhook","method":"receiveWebhook","controller":"api", "appendParams":{"type":"BNPL_KYC"}},
{"type":"post","uri":"/api/bnpl-lender/webhook","method":"receiveWebhook","controller":"api", "appendParams":{"type":"BNPL_Lender"}},
{"type":"post","uri":"/api/mortgage-borrower/webhook","method":"receiveWebhook","controller":"api", "appendParams":{"type":"Mortgage_Borrower"}},
{"type":"post","uri":"/api/mortgage-lender/webhook","method":"receiveWebhook","controller":"api", "appendParams":{"type":"Mortgage_Lender"}}





]
111 changes: 17 additions & 94 deletions server/controllers/api-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ import { isCatchClause } from 'typescript'

import AppHelper from '../../lib/app-helper'
import { sendEmail } from '../../lib/mail-sender'
import MongoInterface, { WebhookReceipt } from '../../lib/mongo-interface'
import {
MongoDatabaseInterface,
WebhookReceipt,
} from '../../lib/mongo-database'

const crypto = require('crypto')

export default class ApiController {
constructor(public mongoInterface: MongoInterface) {}
constructor(public mongoDatabase: MongoDatabaseInterface) {}

ping: APICall = async (req: any, res: any) => {
return res.status(200).send({ success: true })
Expand All @@ -19,11 +22,13 @@ export default class ApiController {

*/

shouldSendEmail(): boolean {
return AppHelper.getEnvironmentName() == 'production'
}

async sendErrorEmail(loggedError: any): Promise<any> {
try {
const shouldSendEmail = AppHelper.getEnvironmentName() == 'production'

if (shouldSendEmail) {
if (this.shouldSendEmail()) {
const emailMessageText = `An error has been logged: ${loggedError.errorMessage} `

const sentEmail = await sendEmail('Bloom API Error', emailMessageText)
Expand All @@ -42,7 +47,7 @@ export default class ApiController {
.digest('base64')

if (signature !== expectedSignature) {
const loggedError = await this.mongoInterface.WebhookErrorModel.create({
const loggedError = await this.mongoDatabase.WebhookErrorModel.create({
requestInput: req.rawBody,
errorMessage: 'Invalid HMAC signature',
createdAt: Date.now(),
Expand All @@ -66,13 +71,13 @@ export default class ApiController {
let loggedError

try {
createdRecord = await this.mongoInterface.WebhookReceiptModel.create(
createdRecord = await this.mongoDatabase.WebhookReceiptModel.create(
receipt
)
} catch (error: any) {
console.log('error', error)

const loggedError = await this.mongoInterface.WebhookErrorModel.create({
const loggedError = await this.mongoDatabase.WebhookErrorModel.create({
requestInput: receipt,
errorMessage: error.message,
createdAt: Date.now(),
Expand All @@ -83,7 +88,7 @@ export default class ApiController {
}

try {
if (shouldSendEmail) {
if (this.shouldSendEmail()) {
const emailMessageText: string = createdRecord
? `A ${receipt.type} webhook has been received with request_id: ${receipt.requestId}`
: `A ${receipt.type} error has been logged with request_id: ${receipt.requestId}`
Expand All @@ -99,63 +104,7 @@ export default class ApiController {
return { createdRecord, sentEmail }
}

receiveBNPLKYC: APICall = async (req: any, res: any) => {
const inputParams = req.body

const verifySignatureResult = await this.verifyHmacSignature(req)

if (!verifySignatureResult.success) {
return res.status(401).send(verifySignatureResult)
}

const receipt: WebhookReceipt = {
requestId: inputParams.requestId,
user: inputParams.user,
template: inputParams.template,
profile: inputParams.profile,
application: inputParams.application,
createdAt: Date.now(),
type: 'BNPL_KYC',
}

const { createdRecord, sentEmail } = await this.storeAndBroadcastReceipt(
receipt
)

return res.status(200).send({
success: !!createdRecord,
})
}

receiveBNPLLender: APICall = async (req: any, res: any) => {
const inputParams = req.body

const verifySignatureResult = await this.verifyHmacSignature(req)

if (!verifySignatureResult.success) {
return res.status(401).send(verifySignatureResult)
}

const receipt: WebhookReceipt = {
requestId: inputParams.requestId,
user: inputParams.user,
template: inputParams.template,
profile: inputParams.profile,
application: inputParams.application,
createdAt: Date.now(),
type: 'BNPL_Lender',
}

const { createdRecord, sentEmail } = await this.storeAndBroadcastReceipt(
receipt
)

return res.status(200).send({
success: !!createdRecord,
})
}

receiveMortgageBorrower: APICall = async (req: any, res: any) => {
receiveWebhook: APICall = async (req: any, res: any) => {
const inputParams = req.body

const verifySignatureResult = await this.verifyHmacSignature(req)
Expand All @@ -164,33 +113,7 @@ export default class ApiController {
return res.status(401).send(verifySignatureResult)
}

const receipt: WebhookReceipt = {
requestId: inputParams.requestId,
user: inputParams.user,
template: inputParams.template,
profile: inputParams.profile,
application: inputParams.application,
createdAt: Date.now(),
type: 'Mortgage_Borrower',
}

const { createdRecord, sentEmail } = await this.storeAndBroadcastReceipt(
receipt
)

return res.status(200).send({
success: !!createdRecord,
})
}

receiveMortgageLender: APICall = async (req: any, res: any) => {
const inputParams = req.body

const verifySignatureResult = await this.verifyHmacSignature(req)

if (!verifySignatureResult.success) {
return res.status(401).send(verifySignatureResult)
}
const webhookType = req.router.params.type

const receipt: WebhookReceipt = {
requestId: inputParams.requestId,
Expand All @@ -199,7 +122,7 @@ export default class ApiController {
profile: inputParams.profile,
application: inputParams.application,
createdAt: Date.now(),
type: 'Mortgage_Lender',
type: webhookType,
}

const { createdRecord, sentEmail } = await this.storeAndBroadcastReceipt(
Expand Down
14 changes: 13 additions & 1 deletion server/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import AppHelper from '../lib/app-helper'
import FileHelper from '../lib/file-helper'
import MongoDatabase from '../lib/mongo-database'

import ApiController from './controllers/api-controller'
import WebServer from './server'

const serverConfig = FileHelper.readJSONFile(
Expand All @@ -8,7 +11,16 @@ const serverConfig = FileHelper.readJSONFile(

async function init(): Promise<void> {
const webServer = new WebServer()
await webServer.start(serverConfig)

const dbName = AppHelper.getDbName()

const mongoDatabase = new MongoDatabase()

await mongoDatabase.init(dbName)

const apiController = new ApiController(mongoDatabase)

await webServer.start(apiController, serverConfig)
}

void init()
29 changes: 14 additions & 15 deletions server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ import cors from 'cors'
import express from 'express'
import MiniRouteLoader from 'mini-route-loader'

import AppHelper from '../lib/app-helper'
import FileHelper from '../lib/file-helper'
import MongoInterface from '../lib/mongo-interface'
//import MongoInterface from '../lib/mongo-database'

import ApiController from './controllers/api-controller'

Expand All @@ -20,15 +19,8 @@ const routes = FileHelper.readJSONFile('./server/config/routes.json')

export default class WebServer {
server: https.Server | http.Server | undefined
mongoInterface: MongoInterface = new MongoInterface()

async start(serverConfig: any): Promise<void> {
const dbName = AppHelper.getDbName()

await this.mongoInterface.init(dbName)

const apiController = new ApiController(this.mongoInterface)

async start(apiController: ApiController, serverConfig: any): Promise<void> {
const app = express()
const apiPort = serverConfig.port ? serverConfig.port : 3000

Expand All @@ -48,17 +40,24 @@ export default class WebServer {
})
)


if(!process.env.ONRAMP_WEBHOOK_KEY ){
throw(new Error('Missing Webhook Key'))
if (!process.env.ONRAMP_WEBHOOK_KEY) {
throw new Error('Missing Webhook Key')
}

this.server = http.createServer(app)
// this.server = http.createServer(app)

MiniRouteLoader.loadRoutes(app, routes, apiController)

app.listen(apiPort, () => {
this.server = app.listen(apiPort, () => {
console.log(`API Server listening at http://localhost:${apiPort}`)
})
}

async stop(): Promise<boolean> {
if (this.server) {
this.server.close()
}

return true
}
}
Loading