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

feat: sentry proxy #112

Merged
merged 1 commit into from
Jun 20, 2022
Merged
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
44 changes: 43 additions & 1 deletion src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Koa from 'koa'
import koaBodyparser from 'koa-bodyparser'
import serve from 'koa-static'
import fetch from 'node-fetch'
import { URL } from 'url'
import { join } from 'path'
import { getApiKey } from './api-key'
import { sendBzzTransaction, sendNativeTransaction } from './blockchain'
Expand All @@ -17,6 +18,8 @@ import { getPath } from './path'
import { port } from './port'
import { getStatus } from './status'
import { swap } from './swap'
import { captureException } from '@sentry/electron'
import { bufferRequest } from './utility'

export function runServer() {
const app = new Koa()
Expand All @@ -32,14 +35,52 @@ export function runServer() {
context.set('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, OPTIONS')
await next()
})
app.use(koaBodyparser())
app.use(koaBodyparser({ onerror: logger.error }))
const router = new Router()

// Open endpoints without any authentication
router.get('/info', context => {
context.body = { name: 'bee-desktop' }
})

/**
* This is proxy endpoint for Sentry to circumvent ad-blockers
* @see https://docs.sentry.io/platforms/javascript/troubleshooting/#using-the-tunnel-option
*/
router.all('/sentry', async context => {
// OPTION request is used to verify that Desktop can proxy the requests
if (context.request.method.toLowerCase() === 'options') {
context.status = 204

return
}

try {
// We can't use the `context.request.body` as the incoming request is not valid JSON
// It is multiline string where each line contain a JSON field and because of that the `koa-bodyparser`
// is not able to correctly detect and parse the body and because of that nothing is attached.
// So we need to Buffer the body into string ourselves.
const envelope = await bufferRequest(context.req)
const pieces = envelope.split('\n')
const header = JSON.parse(pieces[0])
const dnsUrl = new URL(header.dsn)
const projectId = dnsUrl.pathname.endsWith('/') ? dnsUrl.pathname.slice(0, -1) : dnsUrl.pathname
const url = `https://${dnsUrl.host}/api/${projectId}/envelope/`
const response = await fetch(url, {
method: 'POST',
body: envelope,
})

context.body = await response.json()
} catch (e) {
logger.error(e)
captureException(e)

context.status = 400
context.body = { status: 'invalid request' }
}
})

router.use(async (context, next) => {
const { authorization } = context.headers

Expand Down Expand Up @@ -122,6 +163,7 @@ export function runServer() {
await swap(privateKeyString, context.request.body.dai, '10000', swapEndpoint)
context.body = { success: true }
})

app.use(router.routes())
app.use(router.allowedMethods())
const server = app.listen(port.value)
Expand Down
11 changes: 11 additions & 0 deletions src/utility.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
import { Readable } from 'stream'

export async function wait(ms: number): Promise<void> {
return new Promise(resolve => {
setTimeout(resolve, ms)
})
}

export async function bufferRequest(red: Readable): Promise<string> {
const arr = []
for await (const redElement of red) {
arr.push(redElement)
}

return Buffer.concat(arr).toString('utf8')
}