add admintools to user area
This commit is contained in:
parent
bc7613b431
commit
1d081991ba
|
@ -492,6 +492,7 @@ export function receiveMe(
|
|||
dailyRanking,
|
||||
minecraftname,
|
||||
canvases,
|
||||
userlvl,
|
||||
} = me;
|
||||
return {
|
||||
type: 'RECEIVE_ME',
|
||||
|
@ -504,6 +505,7 @@ export function receiveMe(
|
|||
dailyRanking,
|
||||
minecraftname,
|
||||
canvases,
|
||||
userlvl,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -79,7 +79,8 @@ export type Action =
|
|||
ranking: number,
|
||||
dailyRanking: number,
|
||||
minecraftname: string,
|
||||
canvases: Object
|
||||
canvases: Object,
|
||||
userlvl: number,
|
||||
}
|
||||
| { type: 'RECEIVE_STATS', totalRanking: Object, totalDailyRanking: Object }
|
||||
| { type: 'SET_NAME', name: string }
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
* Html for adminpage
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/server';
|
||||
|
||||
import Html from './Html';
|
||||
|
||||
const Admin = () => (
|
||||
<form method="post" action="admintools" encType="multipart/form-data">
|
||||
<p>------Image Upload------</p>
|
||||
<p>file:</p>
|
||||
<select name="imageaction">
|
||||
<option value="build">build</option>
|
||||
<option value="protect">protect</option>
|
||||
<option value="wipe">wipe</option>
|
||||
</select>
|
||||
<input type="file" name="image" /><br />
|
||||
<p><span>canvasId (d: default, m: moon):</span>
|
||||
<input type="text" name="canvasident" /></p>
|
||||
<span>x:</span>
|
||||
<input type="number" name="x" min="-40000" max="40000" /><br />
|
||||
<span>y:</span>
|
||||
<input type="number" name="y" min="-40000" max="40000" /><br />
|
||||
<br />
|
||||
<p>---------IP actions---------</p>
|
||||
<select name="action">
|
||||
<option value="ban">ban</option>
|
||||
<option value="unban">unban</option>
|
||||
<option value="whitelist">whitelist</option>
|
||||
<option value="unwhitelist">unwhitelist</option>
|
||||
</select>
|
||||
<br />
|
||||
<textarea rows="10" cols="100" name="ip" /><br />
|
||||
<p>-----------------------</p>
|
||||
<button type="submit" name="upload">Submit</button>
|
||||
</form>
|
||||
);
|
||||
|
||||
const title = 'PixelPlanet.fun AdminTools';
|
||||
const description = 'admin access on pixelplanet';
|
||||
const body = <Admin />;
|
||||
|
||||
const adminHtml = `<!doctype html>${
|
||||
ReactDOM.renderToStaticMarkup(
|
||||
<Html
|
||||
title={title}
|
||||
description={description}
|
||||
body={body}
|
||||
/>,
|
||||
)
|
||||
}`;
|
||||
|
||||
export default adminHtml;
|
232
src/components/Admintools.jsx
Normal file
232
src/components/Admintools.jsx
Normal file
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
* Html for adminpage
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import type { State } from '../reducers';
|
||||
|
||||
|
||||
async function submitAction(
|
||||
action,
|
||||
canvas,
|
||||
coords,
|
||||
callback,
|
||||
) {
|
||||
const data = new FormData();
|
||||
const fileSel = document.getElementById('imgfile');
|
||||
const file = (!fileSel.files || !fileSel.files[0])
|
||||
? null : fileSel.files[0];
|
||||
data.append('imageaction', action);
|
||||
data.append('image', file);
|
||||
data.append('canvasid', canvas);
|
||||
data.append('coords', coords);
|
||||
const resp = await fetch('./admintools', {
|
||||
credentials: 'include',
|
||||
method: 'POST',
|
||||
body: data,
|
||||
});
|
||||
callback(await resp.text());
|
||||
}
|
||||
|
||||
async function submitIPAction(
|
||||
action,
|
||||
callback,
|
||||
) {
|
||||
const data = new FormData();
|
||||
const iplist = document.getElementById('iparea').value;
|
||||
data.append('ip', iplist);
|
||||
data.append('ipaction', action);
|
||||
const resp = await fetch('./admintools', {
|
||||
credentials: 'include',
|
||||
method: 'POST',
|
||||
body: data,
|
||||
});
|
||||
callback(await resp.text());
|
||||
}
|
||||
|
||||
|
||||
function Admintools({
|
||||
canvasId,
|
||||
canvases,
|
||||
}) {
|
||||
const [selectedCanvas, selectCanvas] = useState(canvasId);
|
||||
const [imageAction, selectImageAction] = useState('build');
|
||||
const [iPAction, selectIPAction] = useState('ban');
|
||||
const [resp, setResp] = useState(null);
|
||||
const [coords, selectCoords] = useState('X_Y');
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
|
||||
let descAction;
|
||||
switch (imageAction) {
|
||||
case 'build':
|
||||
descAction = 'Build image on canvas.';
|
||||
break;
|
||||
case 'protect':
|
||||
descAction = 'Build image and set it to protected.';
|
||||
break;
|
||||
case 'wipe':
|
||||
descAction = 'Build image, but reset cooldown to unset-pixel cd.';
|
||||
break;
|
||||
default:
|
||||
// nothing
|
||||
}
|
||||
|
||||
return (
|
||||
<p style={{ textAlign: 'center', paddingLeft: '5%', paddingRight: '5%' }}>
|
||||
{resp && (
|
||||
<div style={{
|
||||
borderStyle: 'solid',
|
||||
borderColor: '#D4D4D4',
|
||||
borderWidth: 2,
|
||||
padding: 5,
|
||||
display: 'inline-block',
|
||||
}}
|
||||
>
|
||||
{resp.split('\n').map((line) => (
|
||||
<p className="modaltext">
|
||||
{line}
|
||||
</p>
|
||||
))}
|
||||
<span
|
||||
role="button"
|
||||
tabIndex={-1}
|
||||
className="modallink"
|
||||
onClick={() => setResp(null)}
|
||||
>
|
||||
Close
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<h3 className="modaltitle">Image Upload</h3>
|
||||
<p className="modalcotext">Upload images to canvas</p>
|
||||
<p className="modalcotext">Choose Canvas:
|
||||
<select
|
||||
onChange={(e) => {
|
||||
const sel = e.target;
|
||||
selectCanvas(sel.options[sel.selectedIndex].value);
|
||||
}}
|
||||
>
|
||||
{
|
||||
Object.keys(canvases).map((canvas) => ((canvases[canvas].v)
|
||||
? null
|
||||
: (
|
||||
<option
|
||||
selected={canvas === selectedCanvas}
|
||||
value={canvas}
|
||||
>
|
||||
{
|
||||
canvases[canvas].title
|
||||
}
|
||||
</option>
|
||||
)))
|
||||
}
|
||||
</select>
|
||||
</p>
|
||||
<p className="modalcotext">
|
||||
File:
|
||||
<input type="file" name="image" id="imgfile" />
|
||||
</p>
|
||||
<select
|
||||
onChange={(e) => {
|
||||
const sel = e.target;
|
||||
selectImageAction(sel.options[sel.selectedIndex].value);
|
||||
}}
|
||||
>
|
||||
{['build', 'protect', 'wipe'].map((opt) => (
|
||||
<option
|
||||
value={opt}
|
||||
selected={imageAction === opt}
|
||||
>
|
||||
{opt}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<p className="modalcotext">{descAction}</p>
|
||||
<p className="modalcotext">
|
||||
Coordinates in X_Y format:
|
||||
<input
|
||||
value={coords}
|
||||
style={{
|
||||
display: 'inline-block',
|
||||
width: '100%',
|
||||
maxWidth: '15em',
|
||||
}}
|
||||
type="text"
|
||||
onChange={(evt) => {
|
||||
selectCoords(evt.target.value.trim());
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
if (submitting) {
|
||||
return;
|
||||
}
|
||||
setSubmitting(true);
|
||||
submitAction(
|
||||
imageAction,
|
||||
selectedCanvas,
|
||||
coords,
|
||||
(ret) => {
|
||||
setSubmitting(false);
|
||||
setResp(ret);
|
||||
},
|
||||
);
|
||||
}}
|
||||
>
|
||||
{(submitting) ? '...' : 'Submit'}
|
||||
</button>
|
||||
<br />
|
||||
<div className="modaldivider" />
|
||||
<h3 className="modaltitle">IP Actions</h3>
|
||||
<p className="modalcotext">Do stuff with IPs (one IP per line)</p>
|
||||
<select
|
||||
onChange={(e) => {
|
||||
const sel = e.target;
|
||||
selectIPAction(sel.options[sel.selectedIndex].value);
|
||||
}}
|
||||
>
|
||||
{['ban', 'unban', 'whitelist', 'unwhitelist'].map((opt) => (
|
||||
<option
|
||||
value={opt}
|
||||
selected={iPAction === opt}
|
||||
>
|
||||
{opt}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<br />
|
||||
<textarea rows="10" cols="100" id="iparea" /><br />
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
if (submitting) {
|
||||
return;
|
||||
}
|
||||
setSubmitting(true);
|
||||
submitIPAction(
|
||||
iPAction,
|
||||
(ret) => {
|
||||
setSubmitting(false);
|
||||
setResp(ret);
|
||||
},
|
||||
);
|
||||
}}
|
||||
>
|
||||
{(submitting) ? '...' : 'Submit'}
|
||||
</button>
|
||||
</p>
|
||||
);
|
||||
}
|
||||
|
||||
function mapStateToProps(state: State) {
|
||||
const { canvasId, canvases } = state.canvas;
|
||||
return { canvasId, canvases };
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(Admintools);
|
|
@ -31,6 +31,9 @@ class Tabs extends Component {
|
|||
<div className="tabs">
|
||||
<ol className="tab-list">
|
||||
{children.map((child) => {
|
||||
if (!child.props) {
|
||||
return undefined;
|
||||
}
|
||||
const { label } = child.props;
|
||||
|
||||
return (
|
||||
|
@ -45,7 +48,9 @@ class Tabs extends Component {
|
|||
</ol>
|
||||
<div className="tab-content">
|
||||
{children.map((child) => {
|
||||
if (child.props.label !== activeTab) return undefined;
|
||||
if (!child.props || child.props.label !== activeTab) {
|
||||
return undefined;
|
||||
}
|
||||
return child.props.children;
|
||||
})}
|
||||
</div>
|
||||
|
|
|
@ -19,6 +19,8 @@ import Rankings from './Rankings';
|
|||
|
||||
// eslint-disable-next-line max-len
|
||||
const Converter = React.lazy(() => import(/* webpackChunkName: "converter" */ './Converter'));
|
||||
// eslint-disable-next-line max-len
|
||||
const Admintools = React.lazy(() => import(/* webpackChunkName: "admintools" */ './Admintools'));
|
||||
|
||||
const logoStyle = {
|
||||
marginRight: 5,
|
||||
|
@ -82,7 +84,14 @@ const LogInArea = ({ register, forgotPassword, me }) => (
|
|||
);
|
||||
|
||||
const UserAreaModal = ({
|
||||
name, register, forgotPassword, doMe, logout, setUserName, setUserMailreg,
|
||||
name,
|
||||
register,
|
||||
forgotPassword,
|
||||
doMe,
|
||||
logout,
|
||||
setUserName,
|
||||
setUserMailreg,
|
||||
userlvl,
|
||||
}) => (
|
||||
<p style={{ textAlign: 'center' }}>
|
||||
{(name === null)
|
||||
|
@ -110,6 +119,13 @@ const UserAreaModal = ({
|
|||
<Converter />
|
||||
</Suspense>
|
||||
</div>
|
||||
{userlvl && (
|
||||
<div label="Admintools">
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<Admintools />
|
||||
</Suspense>
|
||||
</div>
|
||||
)}
|
||||
</Tabs>
|
||||
)}
|
||||
<p>Also join our Discord:
|
||||
|
@ -149,8 +165,8 @@ function mapDispatchToProps(dispatch) {
|
|||
}
|
||||
|
||||
function mapStateToProps(state: State) {
|
||||
const { name } = state.user;
|
||||
return { name };
|
||||
const { name, userlvl } = state.user;
|
||||
return { name, userlvl };
|
||||
}
|
||||
|
||||
const data = {
|
||||
|
|
|
@ -48,6 +48,7 @@ export async function imageABGR2Canvas(
|
|||
const [ucx, ucy] = getChunkOfPixel(size, x, y);
|
||||
const [lcx, lcy] = getChunkOfPixel(size, x + width, y + height);
|
||||
|
||||
let totalPxlCnt = 0;
|
||||
logger.info(`Loading to chunks from ${ucx} / ${ucy} to ${lcx} / ${lcy} ...`);
|
||||
let chunk;
|
||||
for (let cx = ucx; cx <= lcx; cx += 1) {
|
||||
|
@ -83,12 +84,14 @@ export async function imageABGR2Canvas(
|
|||
const ret = await RedisCanvas.setChunk(cx, cy, chunk, canvasId);
|
||||
if (ret) {
|
||||
logger.info(`Loaded ${pxlCnt} pixels into chunk ${cx}, ${cy}.`);
|
||||
totalPxlCnt += pxlCnt;
|
||||
}
|
||||
}
|
||||
chunk = null;
|
||||
}
|
||||
}
|
||||
logger.info('Image loading done.');
|
||||
return totalPxlCnt;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -148,6 +148,7 @@ class User {
|
|||
ranking: regUser.ranking,
|
||||
dailyRanking: regUser.dailyRanking,
|
||||
mailreg: !!(regUser.password),
|
||||
userlvl: this.isAdmin() ? 1 : 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,8 @@ export type UserState = {
|
|||
isOnMobile: boolean,
|
||||
// small notifications for received cooldown
|
||||
notification: string,
|
||||
// 1: Admin, 0: ordinary user
|
||||
userlvl: number,
|
||||
};
|
||||
|
||||
const initialState: UserState = {
|
||||
|
@ -53,6 +55,7 @@ const initialState: UserState = {
|
|||
minecraftname: null,
|
||||
isOnMobile: false,
|
||||
notification: null,
|
||||
userlvl: 0,
|
||||
};
|
||||
|
||||
export default function user(
|
||||
|
@ -171,6 +174,7 @@ export default function user(
|
|||
ranking,
|
||||
dailyRanking,
|
||||
minecraftname,
|
||||
userlvl,
|
||||
} = action;
|
||||
const messages = (action.messages) ? action.messages : [];
|
||||
return {
|
||||
|
@ -183,6 +187,7 @@ export default function user(
|
|||
ranking,
|
||||
dailyRanking,
|
||||
minecraftname,
|
||||
userlvl,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/**
|
||||
* basic admin api
|
||||
* is used by ../components/Admintools
|
||||
*
|
||||
* @flow
|
||||
*
|
||||
|
@ -15,7 +16,6 @@ import sharp from 'sharp';
|
|||
import multer from 'multer';
|
||||
|
||||
import { getIPFromRequest, getIPv6Subnet } from '../utils/ip';
|
||||
import { getIdFromObject } from '../core/utils';
|
||||
import redis from '../data/redis';
|
||||
import session from '../core/session';
|
||||
import passport from '../core/passport';
|
||||
|
@ -27,8 +27,6 @@ import { MINUTE } from '../core/constants';
|
|||
import canvases from './canvases.json';
|
||||
import { imageABGR2Canvas } from '../core/Image';
|
||||
|
||||
import adminHtml from '../components/Admin';
|
||||
|
||||
|
||||
const router = express.Router();
|
||||
const limiter = expressLimiter(router, redis);
|
||||
|
@ -73,7 +71,7 @@ router.use(async (req, res, next) => {
|
|||
}
|
||||
if (!req.user.isAdmin()) {
|
||||
logger.info(
|
||||
`ADMINTOOLS: ${ip}/${req.user.id} wrongfully tried to access admintools`,
|
||||
`ADMINTOOLS: ${ip} / ${req.user.id} tried to access admintools`,
|
||||
);
|
||||
res.status(403).send('You are not allowed to access this page');
|
||||
return;
|
||||
|
@ -91,7 +89,7 @@ router.use(async (req, res, next) => {
|
|||
* @param ip already sanizized ip
|
||||
* @return true if successful
|
||||
*/
|
||||
async function executeAction(action: string, ips: string): boolean {
|
||||
async function executeIPAction(action: string, ips: string): boolean {
|
||||
const ipArray = ips.split('\n');
|
||||
let out = '';
|
||||
const splitRegExp = /\s+/;
|
||||
|
@ -104,7 +102,7 @@ async function executeAction(action: string, ips: string): boolean {
|
|||
ip = ipLine[2];
|
||||
}
|
||||
if (!ip || ip.length < 8 || ip.indexOf(' ') !== -1) {
|
||||
out += `Couln't parse ${action} ${ip}<br>\n`;
|
||||
out += `Couln't parse ${action} ${ip}\n`;
|
||||
continue;
|
||||
}
|
||||
const ipKey = getIPv6Subnet(ip);
|
||||
|
@ -137,84 +135,106 @@ async function executeAction(action: string, ips: string): boolean {
|
|||
await redis.del(key);
|
||||
break;
|
||||
default:
|
||||
out += `Failed to ${action} ${ip}<br>\n`;
|
||||
out += `Failed to ${action} ${ip}\n`;
|
||||
}
|
||||
out += `Succseefully did ${action} ${ip}<br>\n`;
|
||||
out += `Succseefully did ${action} ${ip}\n`;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute Image based actions (upload, protect, etc.)
|
||||
* @param action what to do with the image
|
||||
* @param file imagefile
|
||||
* @param coords coord sin X_Y format
|
||||
* @param canvasid numerical canvas id
|
||||
* @return [ret, msg] http status code and message
|
||||
*/
|
||||
async function executeImageAction(
|
||||
action: string,
|
||||
file: Object,
|
||||
coords: string,
|
||||
canvasid: string,
|
||||
) {
|
||||
const splitCoords = coords.trim().split('_');
|
||||
if (splitCoords.length !== 2) {
|
||||
return [403, 'Invalid Coordinate Format'];
|
||||
}
|
||||
const [x, y] = splitCoords.map((z) => Math.floor(Number(z)));
|
||||
|
||||
let error = null;
|
||||
if (Number.isNaN(x)) {
|
||||
error = 'x is not a valid number';
|
||||
} else if (Number.isNaN(y)) {
|
||||
error = 'y is not a valid number';
|
||||
} else if (!action) {
|
||||
error = 'No imageaction given';
|
||||
} else if (!canvasid) {
|
||||
error = 'No canvas specified';
|
||||
} else if (!canvases[canvasid]) {
|
||||
error = 'Invalid canvas selected';
|
||||
}
|
||||
if (error !== null) {
|
||||
return [403, error];
|
||||
}
|
||||
|
||||
const canvas = canvases[canvasid];
|
||||
|
||||
if (canvas.v) {
|
||||
return [403, 'Can not upload Image to 3D canvas'];
|
||||
}
|
||||
|
||||
const canvasMaxXY = canvas.size / 2;
|
||||
const canvasMinXY = -canvasMaxXY;
|
||||
if (x < canvasMinXY || y < canvasMinXY
|
||||
|| x >= canvasMaxXY || y >= canvasMaxXY) {
|
||||
return [403, 'Coordinates are outside of canvas'];
|
||||
}
|
||||
|
||||
const protect = (action === 'protect');
|
||||
const wipe = (action === 'wipe');
|
||||
|
||||
try {
|
||||
const { data, info } = await sharp(file.buffer)
|
||||
.ensureAlpha()
|
||||
.raw()
|
||||
.toBuffer({ resolveWithObject: true });
|
||||
|
||||
const pxlCount = await imageABGR2Canvas(
|
||||
canvasid,
|
||||
x, y,
|
||||
data,
|
||||
info.width, info.height,
|
||||
wipe, protect,
|
||||
);
|
||||
|
||||
return [
|
||||
200,
|
||||
`Successfully loaded image wth ${pxlCount} pixels to ${x}/${y}`,
|
||||
];
|
||||
} catch {
|
||||
return [400, 'Can not read image file'];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check for POST parameters,
|
||||
*/
|
||||
router.post('/', upload.single('image'), async (req, res, next) => {
|
||||
try {
|
||||
if (req.file) {
|
||||
const { imageaction, canvasident } = req.body;
|
||||
|
||||
let error = null;
|
||||
if (Number.isNaN(req.body.x)) {
|
||||
error = 'x is not a valid number';
|
||||
} else if (Number.isNaN(req.body.y)) {
|
||||
error = 'y is not a valid number';
|
||||
} else if (!imageaction) {
|
||||
error = 'No imageaction given';
|
||||
} else if (!canvasident) {
|
||||
error = 'No canvas specified';
|
||||
}
|
||||
if (error !== null) {
|
||||
res.status(403).send(error);
|
||||
return;
|
||||
}
|
||||
const x = parseInt(req.body.x, 10);
|
||||
const y = parseInt(req.body.y, 10);
|
||||
|
||||
const canvasId = getIdFromObject(canvases, canvasident);
|
||||
if (canvasId === null) {
|
||||
res.status(403).send('This canvas does not exist');
|
||||
return;
|
||||
}
|
||||
|
||||
const canvas = canvases[canvasId];
|
||||
|
||||
if (canvas.v) {
|
||||
res.status(403).send('Can not upload Image to 3D canvas');
|
||||
return;
|
||||
}
|
||||
|
||||
const canvasMaxXY = canvas.size / 2;
|
||||
const canvasMinXY = -canvasMaxXY;
|
||||
if (x < canvasMinXY || y < canvasMinXY
|
||||
|| x >= canvasMaxXY || y >= canvasMaxXY) {
|
||||
res.status(403).send('Coordinates are outside of canvas');
|
||||
return;
|
||||
}
|
||||
|
||||
const protect = (imageaction === 'protect');
|
||||
const wipe = (imageaction === 'wipe');
|
||||
|
||||
await sharp(req.file.buffer)
|
||||
.ensureAlpha()
|
||||
.raw()
|
||||
.toBuffer({ resolveWithObject: true })
|
||||
.then(({ err, data, info }) => {
|
||||
if (err) throw err;
|
||||
return imageABGR2Canvas(
|
||||
canvasId,
|
||||
x, y,
|
||||
data,
|
||||
info.width, info.height,
|
||||
wipe, protect,
|
||||
);
|
||||
});
|
||||
|
||||
res.status(200).send('Successfully loaded image');
|
||||
if (req.body.imageaction) {
|
||||
const { imageaction, coords, canvasid } = req.body;
|
||||
const [ret, msg] = await executeImageAction(
|
||||
imageaction,
|
||||
req.file,
|
||||
coords,
|
||||
canvasid,
|
||||
);
|
||||
res.status(ret).send(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.body.ip) {
|
||||
const ret = await executeAction(req.body.action, req.body.ip);
|
||||
} if (req.body.ipaction) {
|
||||
const ret = await executeIPAction(req.body.ipaction, req.body.ip);
|
||||
res.status(200).send(ret);
|
||||
return;
|
||||
}
|
||||
|
@ -231,8 +251,8 @@ router.post('/', upload.single('image'), async (req, res, next) => {
|
|||
*/
|
||||
router.get('/', async (req: Request, res: Response, next) => {
|
||||
try {
|
||||
const { ip, action } = req.query;
|
||||
if (!action) {
|
||||
const { ip, ipaction } = req.query;
|
||||
if (!ipaction) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
|
@ -241,9 +261,9 @@ router.get('/', async (req: Request, res: Response, next) => {
|
|||
return;
|
||||
}
|
||||
|
||||
const ret = await executeAction(action, ip);
|
||||
const ret = await executeIPAction(ipaction, ip);
|
||||
|
||||
res.json({ action: 'success', messages: ret.split('\n') });
|
||||
res.json({ ipaction: 'success', messages: ret.split('\n') });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
|
@ -251,10 +271,7 @@ router.get('/', async (req: Request, res: Response, next) => {
|
|||
|
||||
|
||||
router.use(async (req: Request, res: Response) => {
|
||||
res.set({
|
||||
'Content-Type': 'text/html',
|
||||
});
|
||||
res.status(200).send(adminHtml);
|
||||
res.status(400).send('Invalid request');
|
||||
});
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user