mirror of
https://codeberg.org/timelimit/timelimit-server.git
synced 2025-10-03 09:49:32 +02:00
Remove GUI from the admin API
This commit is contained in:
parent
719af663f5
commit
1f210b32c8
4 changed files with 27 additions and 40 deletions
8
package-lock.json
generated
8
package-lock.json
generated
|
@ -166,12 +166,6 @@
|
||||||
"integrity": "sha512-Ja2m6hE6Qp/yp8+AuVJI1+te89H+TARXamrKFYJAuoztxaQmxmhQ5WdfrqgPre0ZCstA/nP+NKXsGgQv1yk8Tw==",
|
"integrity": "sha512-Ja2m6hE6Qp/yp8+AuVJI1+te89H+TARXamrKFYJAuoztxaQmxmhQ5WdfrqgPre0ZCstA/nP+NKXsGgQv1yk8Tw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/escape-html": {
|
|
||||||
"version": "0.0.20",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/escape-html/-/escape-html-0.0.20.tgz",
|
|
||||||
"integrity": "sha512-6dhZJLbA7aOwkYB2GDGdIqJ20wmHnkDzaxV9PJXe7O02I2dSFTERzRB6JrX6cWKaS+VqhhY7cQUMCbO5kloFUw==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"@types/express": {
|
"@types/express": {
|
||||||
"version": "4.17.2",
|
"version": "4.17.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.2.tgz",
|
||||||
|
@ -5591,7 +5585,7 @@
|
||||||
},
|
},
|
||||||
"yargs": {
|
"yargs": {
|
||||||
"version": "3.10.0",
|
"version": "3.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
|
"resolved": "http://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
|
||||||
"integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
|
"integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"camelcase": "1.2.1",
|
"camelcase": "1.2.1",
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
"@types/basic-auth": "^1.1.2",
|
"@types/basic-auth": "^1.1.2",
|
||||||
"@types/body-parser": "^1.17.1",
|
"@types/body-parser": "^1.17.1",
|
||||||
"@types/email-templates": "^6.0.0",
|
"@types/email-templates": "^6.0.0",
|
||||||
"@types/escape-html": "0.0.20",
|
|
||||||
"@types/express": "^4.17.2",
|
"@types/express": "^4.17.2",
|
||||||
"@types/http-errors": "^1.6.2",
|
"@types/http-errors": "^1.6.2",
|
||||||
"@types/lodash": "^4.14.144",
|
"@types/lodash": "^4.14.144",
|
||||||
|
@ -51,7 +50,6 @@
|
||||||
"ejs": "^2.7.1",
|
"ejs": "^2.7.1",
|
||||||
"email-addresses": "^3.1.0",
|
"email-addresses": "^3.1.0",
|
||||||
"email-templates": "^6.0.3",
|
"email-templates": "^6.0.3",
|
||||||
"escape-html": "^1.0.3",
|
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"http-errors": "^1.7.3",
|
"http-errors": "^1.7.3",
|
||||||
"iab_verifier": "^0.1.2",
|
"iab_verifier": "^0.1.2",
|
||||||
|
|
|
@ -15,14 +15,13 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { urlencoded } from 'body-parser'
|
import { json } from 'body-parser'
|
||||||
import * as escape from 'escape-html'
|
|
||||||
import { Router } from 'express'
|
import { Router } from 'express'
|
||||||
import { BadRequest, Conflict, Forbidden } from 'http-errors'
|
import { BadRequest, Conflict } from 'http-errors'
|
||||||
import { Database } from '../database'
|
import { Database } from '../database'
|
||||||
import { addPurchase } from '../function/purchase'
|
import { addPurchase } from '../function/purchase'
|
||||||
import { getStatusMessage, setStatusMessage } from '../function/statusmessage'
|
import { getStatusMessage, setStatusMessage } from '../function/statusmessage'
|
||||||
import { generateAuthToken, generatePurchaseId } from '../util/token'
|
import { generatePurchaseId } from '../util/token'
|
||||||
import { WebsocketApi } from '../websocket'
|
import { WebsocketApi } from '../websocket'
|
||||||
|
|
||||||
export const createAdminRouter = ({ database, websocket }: {
|
export const createAdminRouter = ({ database, websocket }: {
|
||||||
|
@ -31,12 +30,6 @@ export const createAdminRouter = ({ database, websocket }: {
|
||||||
}) => {
|
}) => {
|
||||||
const router = Router()
|
const router = Router()
|
||||||
|
|
||||||
const serverToken = generateAuthToken()
|
|
||||||
|
|
||||||
router.get('/', (_, res) => {
|
|
||||||
res.send('<html><body><a href="/admin/status">status</a><br><a href="/admin/status-message">Status message</a><br><a href="/admin/unlock-premium">unlock premium</a></body></html>')
|
|
||||||
})
|
|
||||||
|
|
||||||
router.get('/status', (_, res) => {
|
router.get('/status', (_, res) => {
|
||||||
res.json({
|
res.json({
|
||||||
websocketClients: websocket.countConnections()
|
websocketClients: websocket.countConnections()
|
||||||
|
@ -47,23 +40,21 @@ export const createAdminRouter = ({ database, websocket }: {
|
||||||
try {
|
try {
|
||||||
const currentStatusMessage = await getStatusMessage({ database })
|
const currentStatusMessage = await getStatusMessage({ database })
|
||||||
|
|
||||||
res.send('<html><body><form action="/admin/status-message" method="post"><textarea name="smessage" rows="20" cols="100">' + escape(currentStatusMessage) + '</textarea><input type="submit" value="Save"><input type="hidden" name="token" value="' + escape(serverToken) + '"></form></body></html>')
|
res.json({
|
||||||
|
statusMessage: currentStatusMessage
|
||||||
|
})
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
next(ex)
|
next(ex)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
router.post('/status-message', urlencoded({ extended: false }), async (req, res, next) => {
|
router.post('/status-message', json(), async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
if (typeof req.body !== 'object' || typeof req.body.smessage !== 'string' || typeof req.body.token !== 'string') {
|
if (typeof req.body !== 'object' || typeof req.body.message !== 'string') {
|
||||||
throw new BadRequest()
|
throw new BadRequest()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.body.token !== serverToken) {
|
const newStatusMessage = req.body.message as string
|
||||||
throw new Forbidden()
|
|
||||||
}
|
|
||||||
|
|
||||||
const newStatusMessage = req.body.smessage as string
|
|
||||||
|
|
||||||
await setStatusMessage({ database, newStatusMessage })
|
await setStatusMessage({ database, newStatusMessage })
|
||||||
|
|
||||||
|
@ -75,24 +66,16 @@ export const createAdminRouter = ({ database, websocket }: {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
router.get('/unlock-premium', (_, res) => (
|
router.post('/unlock-premium', json(), async (req, res, next) => {
|
||||||
res.send('<html><body><form action="/admin/unlock-premium" method="post">mail: <input name="mail" /><br><input type="radio" name="duration" value="month" />Month<br /><input type="radio" name="duration" value="year" />Year<br><input type="submit" value="Unlock"><input type="hidden" name="token" value="' + escape(serverToken) + '"></form></body></html>')
|
|
||||||
))
|
|
||||||
|
|
||||||
router.post('/unlock-premium', urlencoded({ extended: false }), async (req, res, next) => {
|
|
||||||
try {
|
try {
|
||||||
if (typeof req.body !== 'object' || typeof req.body.mail !== 'string' || typeof req.body.duration !== 'string' || typeof req.body.token !== 'string') {
|
if (typeof req.body !== 'object' || typeof req.body.mail !== 'string' || typeof req.body.duration !== 'string') {
|
||||||
throw new BadRequest()
|
throw new BadRequest()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.body.token !== serverToken) {
|
|
||||||
throw new Forbidden()
|
|
||||||
}
|
|
||||||
|
|
||||||
const mail: string = req.body.mail
|
const mail: string = req.body.mail
|
||||||
const type: string = req.body.duration
|
const type: string = req.body.duration
|
||||||
|
|
||||||
if (type !== 'month' && type !== 'year') {
|
if (type !== 'month' && type !== 'year' || mail === '') {
|
||||||
throw new BadRequest()
|
throw new BadRequest()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* server component for the TimeLimit App
|
* server component for the TimeLimit App
|
||||||
* Copyright (C) 2019 Jonas Lochmann
|
* Copyright (C) 2019 - 2020 Jonas Lochmann
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
@ -38,7 +38,7 @@ export const createApi = ({ database, websocket, connectedDevicesManager }: {
|
||||||
|
|
||||||
app.disable('x-powered-by')
|
app.disable('x-powered-by')
|
||||||
|
|
||||||
app.get('/time', (req, res) => {
|
app.get('/time', (_, res) => {
|
||||||
res.json({
|
res.json({
|
||||||
ms: Date.now()
|
ms: Date.now()
|
||||||
})
|
})
|
||||||
|
@ -53,6 +53,18 @@ export const createApi = ({ database, websocket, connectedDevicesManager }: {
|
||||||
app.use(
|
app.use(
|
||||||
'/admin',
|
'/admin',
|
||||||
(req, res, next) => {
|
(req, res, next) => {
|
||||||
|
// required for webbrowser CORS support
|
||||||
|
res.header('Access-Control-Allow-Origin', '*')
|
||||||
|
res.header('Access-Control-Allow-Headers', 'Authorization, Content-Type, Accept')
|
||||||
|
res.header('Access-Control-Allow-Methods', 'GET, POST')
|
||||||
|
|
||||||
|
// without it, browsers ignore the cors headers
|
||||||
|
if (req.method === 'OPTIONS') {
|
||||||
|
res.sendStatus(204)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const user = basicAuth(req)
|
const user = basicAuth(req)
|
||||||
|
|
||||||
if (adminToken !== '' && user && user.pass === adminToken) {
|
if (adminToken !== '' && user && user.pass === adminToken) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue