Skip to content

Commit

Permalink
Add: admin routes and basic authentication
Browse files Browse the repository at this point in the history
  • Loading branch information
flipsimon committed Oct 19, 2023
1 parent 8b44677 commit bec48b6
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 2 deletions.
29 changes: 29 additions & 0 deletions packages/repco-cli/src/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { fetch, Headers, RequestInit, HeadersInit } from 'undici'

Check warning on line 1 in packages/repco-cli/src/client.ts

View workflow job for this annotation

GitHub Actions / build-and-test

Delete `,·HeadersInit·`

Check warning on line 1 in packages/repco-cli/src/client.ts

View workflow job for this annotation

GitHub Actions / build-and-test

'HeadersInit' is defined but never used. Allowed unused vars must match /^_/u

interface RepcoRequestInit extends RequestInit { body?: any }

Check warning on line 3 in packages/repco-cli/src/client.ts

View workflow job for this annotation

GitHub Actions / build-and-test

Replace `·body?:·any··` with `⏎··body?:·any⏎`
export async function request(path: string, init: RepcoRequestInit = {}) {
const url = process.env.REPCO_URL + '/api/admin' + path

Check warning on line 5 in packages/repco-cli/src/client.ts

View workflow job for this annotation

GitHub Actions / build-and-test

Delete `··`
const token = process.env.REPCO_ADMIN_TOKEN

Check warning on line 6 in packages/repco-cli/src/client.ts

View workflow job for this annotation

GitHub Actions / build-and-test

Delete `··`
const headers = new Headers(init.headers)

Check warning on line 7 in packages/repco-cli/src/client.ts

View workflow job for this annotation

GitHub Actions / build-and-test

Delete `··`
headers.set('authorization', 'Bearer ' + token)

Check warning on line 8 in packages/repco-cli/src/client.ts

View workflow job for this annotation

GitHub Actions / build-and-test

Delete `··`
headers.set('accept', 'application/json')

Check warning on line 9 in packages/repco-cli/src/client.ts

View workflow job for this annotation

GitHub Actions / build-and-test

Delete `··`

if (init.body) {

Check warning on line 11 in packages/repco-cli/src/client.ts

View workflow job for this annotation

GitHub Actions / build-and-test

Delete `··`
init.body = JSON.stringify(init.body)

Check warning on line 12 in packages/repco-cli/src/client.ts

View workflow job for this annotation

GitHub Actions / build-and-test

Delete `····`
headers.set('content-type', 'application/json')
}

const res = await fetch(url, { ...init, headers })
if (!res.ok) {
const text = await res.text()
let error
try {
const data = JSON.parse(text)
error = data.error
} catch (_err) {
error = text
}
throw new Error('Remote error: ' + error)
}
return res.json()
}
20 changes: 19 additions & 1 deletion packages/repco-cli/src/commands/debug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,27 @@ import prettyMs from 'pretty-ms'
import { SingleBar } from 'cli-progress'
import { EntityForm, Repo } from 'repco-core'
import { createCommand, createCommandGroup } from '../parse.js'
import { request } from '../client.js'

const round = (x: number) => Math.round(x * 100) / 100

export const authTest = createCommand({
name: 'auth-test',
help: 'Test authentication to repco server',
options: {
},
async run(opts, args) {
try {
const res = await request('/test');
console.log('GET /test', res)
const res2 = await request('/test', { method: 'POST' , body: { foo: 'bar'}});
console.log('GET /test', res2)
} catch (err) {
console.error('got error', err)
}
}
})

export const createContent = createCommand({
name: 'create-content',
help: 'Create dummy content',
Expand Down Expand Up @@ -70,5 +88,5 @@ function createItem() {
export const commands = createCommandGroup({
name: 'debug',
help: 'Development helpers',
commands: [createContent],
commands: [createContent, authTest],
})
1 change: 1 addition & 0 deletions packages/repco-server/src/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export function runServer(prisma: PrismaClient, port: number) {
app.use(graphqlHandler)
app.use((_req, res, next) => {
res.locals.prisma = prisma
res.locals.log = logger.logger
next()
})
app.use((req, _res, next) => {
Expand Down
81 changes: 81 additions & 0 deletions packages/repco-server/src/routes/admin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import express from 'express'
import { ServerError } from '../error.js'

export const router = express.Router()

const ADMIN_TOKEN = process.env.REPCO_ADMIN_TOKEN

// check auth
router.use((req, res, next) => {
if (!ADMIN_TOKEN || ADMIN_TOKEN.length < 16) {
res.locals.log.warn('ADMIN_TOKEN is not set or too short (min 16 characters needed). Admin access disabled.')
return next(new ServerError(403, 'Unauthorized'))
}

const authHeader = req.headers['authorization'];
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return next(new ServerError(403, 'Unauthorized'))
}

const token = authHeader.substring(7)
if (token != ADMIN_TOKEN) {
return next(new ServerError(403, 'Unauthorized'))
}

next()
})

router.get('/test', async (req, res) => {
await new Promise((resolve) => setTimeout(resolve, 1000))
res.send({ ok: true })
})

router.post('/test', async (req, res) => {
const body = req.body
console.log('received body', body)
res.send({ ok: true })
})


// create repo
router.post('/repo', async (req, res) => {
const body = req.body
console.log('received body', body)
res.send({ ok: true })
})
// list repos
router.get('/repo', async (req, res) => {
const body = req.body
console.log('received body', body)
res.send({ ok: true })
})


// create datasource
router.post('/repo/:repodid/ds', async (req, res) => {
const body = req.body
console.log('received body', body)
res.send({ ok: true })
})

// modify datasource
router.put('/repo/:repodid/ds/:dsuid', async (req, res) => {
const body = req.body
console.log('received body', body)
res.send({ ok: true })
})
// get datasource
router.get('/repo/:repodid/ds/:dsuid', async (req, res) => {
const body = req.body
console.log('received body', body)
res.send({ ok: true })
})
// list datasources
router.get('/repo/:repodid/ds', async (req, res) => {
const body = req.body
console.log('received body', body)
res.send({ ok: true })
})



5 changes: 4 additions & 1 deletion packages/repco-server/src/routes/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,20 @@ import {
flattenStream,
sendNdJsonStream,
} from '../util.js'
import { router as adminRouter } from './admin.js'

const router = express.Router()

// const HEADER_JSON = 'application/json'
const HEADER_CAR = 'application/vnd.ipld.car'

router.use('/admin', adminRouter)

router.get('/repos', async (_req, res) => {
res.json(await Repo.list(getLocals(res).prisma))
})

router.get('/health', (_req, res) => {
router.get('/health', (_req, res, next) => {
res.send({ ok: true })
})

Expand Down

0 comments on commit bec48b6

Please sign in to comment.