add iid action to force captcha
add parsing of pixelLog by iid without canvas and coords
This commit is contained in:
parent
fb79e521fc
commit
f90c542046
|
@ -22,9 +22,9 @@ async function submitIIDAction(
|
|||
}
|
||||
|
||||
function ModIIDtools() {
|
||||
const [iIDAction, selectIIDAction] = useState('ban');
|
||||
const [iIDAction, selectIIDAction] = useState('givecaptcha');
|
||||
const [iid, selectIid] = useState('');
|
||||
const [resp, setResp] = useState(null);
|
||||
const [resp, setResp] = useState('');
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
|
||||
return (
|
||||
|
@ -62,7 +62,6 @@ function ModIIDtools() {
|
|||
selectIid(newIid);
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
|
@ -82,9 +81,12 @@ function ModIIDtools() {
|
|||
>
|
||||
{(submitting) ? '...' : t`Submit`}
|
||||
</button>
|
||||
</p>
|
||||
<textarea
|
||||
rows="10"
|
||||
cols="20"
|
||||
style={{
|
||||
width: '100%',
|
||||
}}
|
||||
rows={(resp) ? resp.split('\n').length : 10}
|
||||
id="iparea"
|
||||
value={resp}
|
||||
readOnly
|
||||
|
|
|
@ -88,12 +88,11 @@ async function submitWatchAction(
|
|||
|
||||
function ModWatchtools() {
|
||||
const [selectedCanvas, selectCanvas] = useState(0);
|
||||
const [colors, setColors] = useState([]);
|
||||
const [tlcoords, selectTLCoords] = useState(keepState.tlcoords);
|
||||
const [brcoords, selectBRCoords] = useState(keepState.brcoords);
|
||||
const [interval, selectInterval] = useState(keepState.interval);
|
||||
const [sortBy, setSortBy] = useState(0);
|
||||
const [table, setTable] = useState(null);
|
||||
const [table, setTable] = useState({});
|
||||
const [iid, selectIid] = useState(keepState.iid);
|
||||
const [resp, setResp] = useState(null);
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
|
@ -110,24 +109,8 @@ function ModWatchtools() {
|
|||
selectCanvas(canvasId);
|
||||
}, [canvasId]);
|
||||
|
||||
useEffect(() => {
|
||||
const colorsRGB = canvases[selectedCanvas].colors;
|
||||
const newColors = [];
|
||||
for (let i = 0; i < colorsRGB.length; i += 1) {
|
||||
const [r, g, b] = colorsRGB[i];
|
||||
newColors.push(`rgb(${r},${g},${b})`);
|
||||
}
|
||||
setColors(newColors);
|
||||
}, [selectedCanvas]);
|
||||
|
||||
let columns;
|
||||
let types;
|
||||
let rows;
|
||||
if (table) {
|
||||
columns = table.columns;
|
||||
types = table.types;
|
||||
rows = table.rows;
|
||||
}
|
||||
const { columns, types, rows } = table;
|
||||
const cidColumn = (types) ? (types.indexOf('cid')) : -1;
|
||||
|
||||
return (
|
||||
<div style={{ textAlign: 'center', paddingLeft: '5%', paddingRight: '5%' }}>
|
||||
|
@ -310,7 +293,7 @@ function ModWatchtools() {
|
|||
{(submitting) ? '...' : t`Get Users`}
|
||||
</button>
|
||||
<br />
|
||||
{(table) && (
|
||||
{(rows && columns && types) && (
|
||||
<React.Fragment key="pxltable">
|
||||
<div className="modaldivider" />
|
||||
<table
|
||||
|
@ -350,14 +333,23 @@ function ModWatchtools() {
|
|||
);
|
||||
}
|
||||
case 'clr': {
|
||||
const color = colors[val];
|
||||
const style = (color)
|
||||
? { backgroundColor: color }
|
||||
: undefined;
|
||||
return (<td style={style}>{val}</td>);
|
||||
const cid = (cidColumn > 0)
|
||||
? row[cidColumn] : selectedCanvas;
|
||||
const rgb = canvases[cid]
|
||||
&& canvases[cid].colors
|
||||
&& canvases[cid].colors[val];
|
||||
if (!rgb) {
|
||||
return (<td>{val}</td>);
|
||||
}
|
||||
const color = `rgb(${rgb[0]},${rgb[1]},${rgb[2]})`;
|
||||
return (
|
||||
<td style={{ backgroundColor: color }}>{val}</td>
|
||||
);
|
||||
}
|
||||
case 'coord': {
|
||||
const { ident } = canvases[selectedCanvas];
|
||||
const cid = (cidColumn > 0)
|
||||
? row[cidColumn] : selectedCanvas;
|
||||
const ident = canvases[cid] && canvases[cid].ident;
|
||||
const coords = `./#${ident},${val},47`;
|
||||
return (
|
||||
<td>
|
||||
|
@ -378,6 +370,12 @@ function ModWatchtools() {
|
|||
/></td>
|
||||
);
|
||||
}
|
||||
case 'cid': {
|
||||
const cid = (cidColumn > 0)
|
||||
? row[cidColumn] : selectedCanvas;
|
||||
const ident = canvases[cid] && canvases[cid].ident;
|
||||
return (<td>{ident}</td>);
|
||||
}
|
||||
case 'user': {
|
||||
const seperator = val.lastIndexOf(',');
|
||||
if (seperator === -1) {
|
||||
|
@ -405,6 +403,6 @@ function ModWatchtools() {
|
|||
}
|
||||
|
||||
// possible types:
|
||||
// 'coord', 'clr', 'ts', 'user', 'uuid', 'string', 'number', 'flag'
|
||||
// 'coord', 'clr', 'ts', 'user', 'uuid', 'string', 'number', 'flag', 'cid'
|
||||
|
||||
export default React.memo(ModWatchtools);
|
||||
|
|
|
@ -14,6 +14,7 @@ import { validateCoorRange } from '../utils/validation';
|
|||
import CanvasCleaner from './CanvasCleaner';
|
||||
import { Blacklist, Whitelist, RegUser } from '../data/sql';
|
||||
import { getIPofIID } from '../data/sql/IPInfo';
|
||||
import { forceCaptcha } from '../data/redis/captcha';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import canvases from './canvases.json';
|
||||
import {
|
||||
|
@ -21,6 +22,8 @@ import {
|
|||
protectCanvasArea,
|
||||
} from './Image';
|
||||
import {
|
||||
getIIDSummary,
|
||||
getIIDPixels,
|
||||
getSummaryFromArea,
|
||||
getPixelsFromArea,
|
||||
} from './parsePixelLog';
|
||||
|
@ -30,7 +33,7 @@ import rollbackCanvasArea from './rollback';
|
|||
* Execute IP based actions (banning, whitelist, etc.)
|
||||
* @param action what to do with the ip
|
||||
* @param ip already sanizized ip
|
||||
* @return true if successful
|
||||
* @return text of success
|
||||
*/
|
||||
export async function executeIPAction(action, ips, logger = null) {
|
||||
const ipArray = ips.split('\n');
|
||||
|
@ -40,11 +43,11 @@ export async function executeIPAction(action, ips, logger = null) {
|
|||
|
||||
if (action === 'iidtoip') {
|
||||
const resIp = await getIPofIID(ip);
|
||||
const idPart = ip.slice(0, ip.indexOf('-'));
|
||||
const iidPart = ip.slice(0, ip.indexOf('-'));
|
||||
if (resIp) {
|
||||
out += `${idPart}: ${resIp}\n`;
|
||||
out += `${iidPart}: ${resIp}\n`;
|
||||
} else {
|
||||
out += `${idPart}: N/A\n`;
|
||||
out += `${iidPart}: N/A\n`;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -94,6 +97,36 @@ export async function executeIPAction(action, ips, logger = null) {
|
|||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute IID based actions
|
||||
* @param action what to do with the iid
|
||||
* @param iid already sanizized iid
|
||||
* @return text of success
|
||||
*/
|
||||
export async function executeIIDAction(action, iid, logger = null) {
|
||||
const ip = await getIPofIID(iid);
|
||||
if (!ip) {
|
||||
return `Could not resolve ${iid}`;
|
||||
}
|
||||
const iidPart = iid.slice(0, iid.indexOf('-'));
|
||||
|
||||
switch (action) {
|
||||
case 'givecaptcha': {
|
||||
const succ = await forceCaptcha(ip);
|
||||
if (succ === null) {
|
||||
return 'Captchas are deactivated on this server.';
|
||||
}
|
||||
if (succ) {
|
||||
return `Forced captcha on ${iidPart}`;
|
||||
}
|
||||
return `${iidPart} would have gotten captcha anyway`;
|
||||
}
|
||||
default:
|
||||
return `Failed to ${action} ${iid}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Execute Image based actions (upload, protect, etc.)
|
||||
* @param action what to do with the image
|
||||
|
@ -197,9 +230,7 @@ export async function executeWatchAction(
|
|||
const ts = parseInt(time, 10);
|
||||
const canvas = canvases[canvasid];
|
||||
let error = null;
|
||||
if (!ulcoor || !brcoor) {
|
||||
error = 'Not all coordinates defined';
|
||||
} else if (!canvas) {
|
||||
if (!canvas) {
|
||||
error = 'Invalid canvas selected';
|
||||
} else if (!action) {
|
||||
error = 'No cleanaction given';
|
||||
|
@ -210,6 +241,28 @@ export async function executeWatchAction(
|
|||
return { info: error };
|
||||
}
|
||||
|
||||
let ret;
|
||||
if (!ulcoor && !brcoor && iid) {
|
||||
if (action === 'summary') {
|
||||
ret = await getIIDSummary(
|
||||
iid,
|
||||
time,
|
||||
);
|
||||
}
|
||||
if (action === 'all') {
|
||||
ret = await getIIDPixels(
|
||||
iid,
|
||||
time,
|
||||
);
|
||||
}
|
||||
if (typeof ret === 'string') {
|
||||
return { info: ret };
|
||||
}
|
||||
if (typeof ret !== 'undefined') {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
const parseCoords = validateCoorRange(ulcoor, brcoor, canvas.size);
|
||||
if (typeof parseCoords === 'string') {
|
||||
return { info: parseCoords };
|
||||
|
@ -224,31 +277,27 @@ export async function executeWatchAction(
|
|||
}
|
||||
|
||||
if (action === 'summary') {
|
||||
const ret = await getSummaryFromArea(
|
||||
ret = await getSummaryFromArea(
|
||||
canvasid,
|
||||
x, y, u, v,
|
||||
time,
|
||||
iid,
|
||||
);
|
||||
if (typeof ret === 'string') {
|
||||
return { info: ret };
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (action === 'all') {
|
||||
const ret = await getPixelsFromArea(
|
||||
ret = await getPixelsFromArea(
|
||||
canvasid,
|
||||
x, y, u, v,
|
||||
time,
|
||||
iid,
|
||||
);
|
||||
}
|
||||
if (typeof ret === 'string') {
|
||||
return { info: ret };
|
||||
}
|
||||
if (typeof ret !== 'undefined') {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return { info: 'Invalid action given' };
|
||||
}
|
||||
|
||||
|
@ -272,9 +321,7 @@ export async function executeCleanerAction(
|
|||
}
|
||||
const canvas = canvases[canvasid];
|
||||
let error = null;
|
||||
if (!ulcoor || !brcoor) {
|
||||
error = 'Not all coordinates defined';
|
||||
} else if (!canvas) {
|
||||
if (!canvas) {
|
||||
error = 'Invalid canvas selected';
|
||||
} else if (!action) {
|
||||
error = 'No cleanaction given';
|
||||
|
@ -319,9 +366,7 @@ export async function executeProtAction(
|
|||
}
|
||||
const canvas = canvases[canvasid];
|
||||
let error = null;
|
||||
if (!ulcoor || !brcoor) {
|
||||
error = 'Not all coordinates defined';
|
||||
} else if (!canvas) {
|
||||
if (!canvas) {
|
||||
error = 'Invalid canvas selected';
|
||||
} else if (!action) {
|
||||
error = 'No imageaction given';
|
||||
|
@ -392,9 +437,7 @@ export async function executeRollback(
|
|||
}
|
||||
const canvas = canvases[canvasid];
|
||||
let error = null;
|
||||
if (!ulcoor || !brcoor) {
|
||||
error = 'Not all coordinates defined';
|
||||
} else if (!canvas) {
|
||||
if (!canvas) {
|
||||
error = 'Invalid canvas selected';
|
||||
} else if (!date) {
|
||||
error = 'No date given';
|
||||
|
|
|
@ -39,6 +39,137 @@ function parseFile(cb) {
|
|||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Get summary of pixels per canvas placed by iid
|
||||
* @param iid Limit on one user (optional)
|
||||
* @param time timestamp of when to start
|
||||
* @return array of parsed pixel log lines
|
||||
* string if error
|
||||
*/
|
||||
export async function getIIDSummary(
|
||||
iid,
|
||||
time,
|
||||
) {
|
||||
const filterIP = await getIPofIID(iid);
|
||||
if (!filterIP) {
|
||||
return 'Could not resolve IID to IP';
|
||||
}
|
||||
const cids = {};
|
||||
|
||||
try {
|
||||
await parseFile((parts) => {
|
||||
const [tsStr, ipFull,, cid, x, y,, clrStr] = parts;
|
||||
const ts = parseInt(tsStr, 10);
|
||||
if (ts >= time) {
|
||||
const ip = getIPv6Subnet(ipFull);
|
||||
if (ip === filterIP) {
|
||||
const clr = parseInt(clrStr, 10);
|
||||
let curVals = cids[cid];
|
||||
if (!curVals) {
|
||||
curVals = [0, 0, 0, 0, 0];
|
||||
cids[cid] = curVals;
|
||||
}
|
||||
curVals[0] += 1;
|
||||
curVals[1] = x;
|
||||
curVals[2] = y;
|
||||
curVals[3] = clr;
|
||||
curVals[4] = ts;
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
return `Could not parse logfile: ${err.message}`;
|
||||
}
|
||||
|
||||
const columns = ['rid', '#', 'canvas', 'last', 'clr', 'time'];
|
||||
const types = ['number', 'number', 'cid', 'coord', 'clr', 'ts'];
|
||||
const rows = [];
|
||||
const cidKeys = Object.keys(cids);
|
||||
for (let i = 0; i < cidKeys.length; i += 1) {
|
||||
const cid = cidKeys[i];
|
||||
const [pxls, x, y, clr, ts] = cids[cid];
|
||||
rows.push([
|
||||
i,
|
||||
pxls,
|
||||
cid,
|
||||
`${x},${y}`,
|
||||
clr,
|
||||
ts,
|
||||
]);
|
||||
}
|
||||
|
||||
return {
|
||||
columns,
|
||||
types,
|
||||
rows,
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Get pixels by iid
|
||||
* @param iid Limit on one user (optional)
|
||||
* @param time timestamp of when to start
|
||||
* @return array of parsed pixel log lines
|
||||
* string if error
|
||||
*/
|
||||
export async function getIIDPixels(
|
||||
iid,
|
||||
time,
|
||||
maxRows = 300,
|
||||
) {
|
||||
const filterIP = await getIPofIID(iid);
|
||||
if (!filterIP) {
|
||||
return 'Could not resolve IID to IP';
|
||||
}
|
||||
const pixels = [];
|
||||
|
||||
try {
|
||||
await parseFile((parts) => {
|
||||
const [tsStr, ipFull,, cid, x, y,, clrStr] = parts;
|
||||
const ts = parseInt(tsStr, 10);
|
||||
if (ts >= time) {
|
||||
const ip = getIPv6Subnet(ipFull);
|
||||
if (ip === filterIP) {
|
||||
const clr = parseInt(clrStr, 10);
|
||||
pixels.push([
|
||||
cid,
|
||||
x,
|
||||
y,
|
||||
clr,
|
||||
ts,
|
||||
]);
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
return `Could not parse logfile: ${err.message}`;
|
||||
}
|
||||
|
||||
const pixelF = (pixels.length > maxRows)
|
||||
? pixels.slice(maxRows * -1)
|
||||
: pixels;
|
||||
|
||||
const columns = ['rid', 'canvas', 'coord', 'clr', 'time'];
|
||||
const types = ['number', 'cid', 'coord', 'clr', 'ts'];
|
||||
const rows = [];
|
||||
for (let i = 0; i < pixelF.length; i += 1) {
|
||||
const [cid, x, y, clr, ts] = pixelF[i];
|
||||
rows.push([
|
||||
i,
|
||||
cid,
|
||||
`${x},${y}`,
|
||||
clr,
|
||||
ts,
|
||||
]);
|
||||
}
|
||||
|
||||
return {
|
||||
columns,
|
||||
types,
|
||||
rows,
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Get summary of users placing in area of current day
|
||||
* @param canvasId id of canvas
|
||||
|
@ -86,15 +217,15 @@ export async function getSummaryFromArea(
|
|||
const uid = parseInt(uidStr, 10);
|
||||
let curVals = ips[ip];
|
||||
if (!curVals) {
|
||||
curVals = [0, ip, uid, 0, 0, 0, 0];
|
||||
curVals = [0, uid, 0, 0, 0, 0];
|
||||
ips[ip] = curVals;
|
||||
uids.push(uid);
|
||||
}
|
||||
curVals[0] += 1;
|
||||
curVals[3] = x;
|
||||
curVals[4] = y;
|
||||
curVals[5] = clr;
|
||||
curVals[6] = ts;
|
||||
curVals[2] = x;
|
||||
curVals[3] = y;
|
||||
curVals[4] = clr;
|
||||
curVals[5] = ts;
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
|
@ -125,7 +256,8 @@ export async function getSummaryFromArea(
|
|||
|
||||
const rows = [];
|
||||
for (let i = 0; i < ipKeys.length; i += 1) {
|
||||
const [pxls, ip, uid, x, y, clr, ts] = ips[ipKeys[i]];
|
||||
const ip = ipKeys[i];
|
||||
const [pxls, uid, x, y, clr, ts] = ips[ip];
|
||||
const row = [i, pxls];
|
||||
if (printIIDs) {
|
||||
const ipInfo = ip2Info.get(ip);
|
||||
|
@ -217,7 +349,9 @@ export async function getPixelsFromArea(
|
|||
const uid2Name = await getNamesToIds(uids);
|
||||
const ip2Id = await getIdsToIps(ips);
|
||||
|
||||
const pixelF = (pixels.length > 300) ? pixels.slice(maxRows * -1) : pixels;
|
||||
const pixelF = (pixels.length > maxRows)
|
||||
? pixels.slice(maxRows * -1)
|
||||
: pixels;
|
||||
|
||||
let printIIDs = false;
|
||||
let printUsers = false;
|
||||
|
|
|
@ -141,7 +141,6 @@ export async function checkCaptchaSolution(
|
|||
|
||||
/*
|
||||
* check if captcha is needed
|
||||
*
|
||||
* @param ip
|
||||
* @return boolean true if needed
|
||||
*/
|
||||
|
@ -157,3 +156,18 @@ export async function needCaptcha(ip) {
|
|||
logger.info(`CAPTCHA ${ip} got captcha`);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* force ip to get captcha
|
||||
* @param ip
|
||||
* @return true if we triggered captcha
|
||||
* false if user would have gotton one anyway
|
||||
*/
|
||||
export async function forceCaptcha(ip) {
|
||||
if (CAPTCHA_TIME < 0) {
|
||||
return null;
|
||||
}
|
||||
const key = `human:${getIPv6Subnet(ip)}`;
|
||||
const ret = await redis.del(key);
|
||||
return (ret > 0);
|
||||
}
|
||||
|
|
|
@ -88,6 +88,9 @@ const IPInfo = sequelize.define('IPInfo', {
|
|||
});
|
||||
|
||||
export async function getIPofIID(uuid) {
|
||||
if (!uuid) {
|
||||
return null;
|
||||
}
|
||||
let result = null;
|
||||
try {
|
||||
result = await IPInfo.findOne({
|
||||
|
|
|
@ -14,6 +14,7 @@ import { escapeMd } from '../../core/utils';
|
|||
import logger, { modtoolsLogger } from '../../core/logger';
|
||||
import {
|
||||
executeIPAction,
|
||||
executeIIDAction,
|
||||
executeImageAction,
|
||||
executeProtAction,
|
||||
executeRollback,
|
||||
|
@ -115,6 +116,17 @@ router.post('/', upload.single('image'), async (req, res, next) => {
|
|||
res.status(200).json(ret);
|
||||
return;
|
||||
}
|
||||
if (req.body.iidaction) {
|
||||
const {
|
||||
iidaction, iid,
|
||||
} = req.body;
|
||||
const ret = await executeIIDAction(
|
||||
iidaction,
|
||||
iid,
|
||||
);
|
||||
res.status(200).send(ret);
|
||||
return;
|
||||
}
|
||||
if (req.body.cleaneraction) {
|
||||
const {
|
||||
cleaneraction, ulcoor, brcoor, canvasid,
|
||||
|
|
Loading…
Reference in New Issue
Block a user