forked from ppfun/pixelplanet
parse pixel table
add iidtoip admin function
This commit is contained in:
parent
86adb162dc
commit
ae878d4518
|
@ -88,6 +88,7 @@ function Admintools() {
|
|||
<div style={{
|
||||
borderStyle: 'solid',
|
||||
borderColor: '#D4D4D4',
|
||||
userSelect: 'text',
|
||||
borderWidth: 2,
|
||||
padding: 5,
|
||||
display: 'inline-block',
|
||||
|
@ -121,13 +122,14 @@ function Admintools() {
|
|||
selectIPAction(sel.options[sel.selectedIndex].value);
|
||||
}}
|
||||
>
|
||||
{['ban', 'unban', 'whitelist', 'unwhitelist'].map((opt) => (
|
||||
<option
|
||||
value={opt}
|
||||
>
|
||||
{opt}
|
||||
</option>
|
||||
))}
|
||||
{['ban', 'unban', 'whitelist', 'unwhitelist', 'iidtoip']
|
||||
.map((opt) => (
|
||||
<option
|
||||
value={opt}
|
||||
>
|
||||
{opt}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<br />
|
||||
<textarea rows="10" cols="17" id="iparea" /><br />
|
||||
|
|
|
@ -71,9 +71,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 [table, setTable] = useState(null);
|
||||
const [iid, selectIid] = useState(keepState.iid);
|
||||
const [resp, setResp] = useState(null);
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
|
@ -90,6 +92,25 @@ 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;
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ textAlign: 'center', paddingLeft: '5%', paddingRight: '5%' }}>
|
||||
{resp && (
|
||||
|
@ -225,6 +246,13 @@ function ModWatchtools() {
|
|||
(ret) => {
|
||||
setSubmitting(false);
|
||||
setResp(ret.info);
|
||||
if (ret.rows) {
|
||||
setTable({
|
||||
columns: ret.columns,
|
||||
types: ret.types,
|
||||
rows: ret.rows,
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
}}
|
||||
|
@ -248,14 +276,104 @@ function ModWatchtools() {
|
|||
(ret) => {
|
||||
setSubmitting(false);
|
||||
setResp(ret.info);
|
||||
if (ret.rows) {
|
||||
setTable({
|
||||
columns: ret.columns,
|
||||
types: ret.types,
|
||||
rows: ret.rows,
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
}}
|
||||
>
|
||||
{(submitting) ? '...' : t`Get Users`}
|
||||
</button>
|
||||
<br />
|
||||
{(table) && (
|
||||
<React.Fragment key="pxltable">
|
||||
<div className="modaldivider" />
|
||||
<table
|
||||
style={{
|
||||
userSelect: 'text',
|
||||
fontSize: 11,
|
||||
}}
|
||||
>
|
||||
<thead>
|
||||
<tr>
|
||||
{columns.slice(1).map((col) => (
|
||||
<th>{col}</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{rows.map((row) => (
|
||||
<tr key={row[0]}>
|
||||
{row.slice(1).map((val, ind) => {
|
||||
const type = types[ind + 1];
|
||||
switch (type) {
|
||||
case 'ts': {
|
||||
const date = new Date(val);
|
||||
return (
|
||||
<td title={date.toLocaleDateString()}>
|
||||
{`${date.getHours()}:${date.getMinutes()}`}
|
||||
</td>
|
||||
);
|
||||
}
|
||||
case 'clr': {
|
||||
const color = colors[val];
|
||||
const style = (color) ? { backgroundColor: color } : {};
|
||||
return (<td style={style}>{val}</td>);
|
||||
}
|
||||
case 'coord': {
|
||||
const { ident } = canvases[selectedCanvas];
|
||||
const coords = `./#${ident},${val},47`;
|
||||
return (
|
||||
<td>
|
||||
<a href={coords}>{val}</a>
|
||||
</td>
|
||||
);
|
||||
}
|
||||
case 'flag': {
|
||||
const flag = val.toLowerCase();
|
||||
return (
|
||||
<td title={val}><img
|
||||
style={{
|
||||
height: '1em',
|
||||
imageRendering: 'crisp-edges',
|
||||
}}
|
||||
alt={val}
|
||||
src={`${window.ssv.assetserver}/cf/${flag}.gif`}
|
||||
/></td>
|
||||
);
|
||||
}
|
||||
case 'user': {
|
||||
const seperator = val.lastIndexOf(',');
|
||||
if (seperator === -1) {
|
||||
return (<td>{val}</td>);
|
||||
}
|
||||
return (
|
||||
<td title={val.slice(seperator + 1)}>
|
||||
{val.slice(0, seperator)}
|
||||
</td>
|
||||
);
|
||||
}
|
||||
default: {
|
||||
return (<td>{val}</td>);
|
||||
}
|
||||
}
|
||||
})}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// possible types:
|
||||
// 'coord', 'clr', 'ts', 'user', 'uuid', 'string', 'number', 'flag'
|
||||
|
||||
export default React.memo(ModWatchtools);
|
||||
|
|
|
@ -13,6 +13,7 @@ import { getIPv6Subnet } from '../utils/ip';
|
|||
import { validateCoorRange } from '../utils/validation';
|
||||
import CanvasCleaner from './CanvasCleaner';
|
||||
import { Blacklist, Whitelist, RegUser } from '../data/sql';
|
||||
import { getIPofIID } from '../data/sql/IPInfo';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import canvases from './canvases.json';
|
||||
import {
|
||||
|
@ -34,15 +35,20 @@ import rollbackCanvasArea from './rollback';
|
|||
export async function executeIPAction(action, ips, logger = null) {
|
||||
const ipArray = ips.split('\n');
|
||||
let out = '';
|
||||
const splitRegExp = /\s+/;
|
||||
for (let i = 0; i < ipArray.length; i += 1) {
|
||||
let ip = ipArray[i].trim();
|
||||
const ipLine = ip.split(splitRegExp);
|
||||
if (ipLine.length === 7) {
|
||||
// logger output
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
ip = ipLine[2];
|
||||
const ip = ipArray[i].trim();
|
||||
|
||||
if (action === 'iidtoip') {
|
||||
const resIp = await getIPofIID(ip);
|
||||
const idPart = ip.slice(0, ip.indexOf('-'));
|
||||
if (resIp) {
|
||||
out += `${idPart}: ${resIp}\n`;
|
||||
} else {
|
||||
out += `${idPart}: N/A\n`;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ip || ip.length < 8 || ip.indexOf(' ') !== -1) {
|
||||
out += `Couln't parse ${action} ${ip}\n`;
|
||||
continue;
|
||||
|
@ -210,8 +216,11 @@ export async function executeWatchAction(
|
|||
}
|
||||
const [x, y, u, v] = parseCoords;
|
||||
|
||||
if (u - x > 1000 || v - y > 1000) {
|
||||
return { info: 'Cann not watch larger than 1000x1000 area' };
|
||||
if ((u - x > 1000 || v - y > 1000)
|
||||
&& Date.now() - ts > 5 * 60 * 1000
|
||||
&& !iid
|
||||
) {
|
||||
return { info: 'Cann not watch so many pixels' };
|
||||
}
|
||||
|
||||
if (action === 'summary') {
|
||||
|
@ -224,11 +233,7 @@ export async function executeWatchAction(
|
|||
if (typeof ret === 'string') {
|
||||
return { info: ret };
|
||||
}
|
||||
return {
|
||||
info: null,
|
||||
columns: ['#pxls', 'IID', 'User', 'last', 'clr', 'ts'],
|
||||
rows: (ret.length > 300) ? ret.slice(-300) : ret,
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (action === 'all') {
|
||||
|
@ -241,11 +246,7 @@ export async function executeWatchAction(
|
|||
if (typeof ret === 'string') {
|
||||
return { info: ret };
|
||||
}
|
||||
return {
|
||||
info: null,
|
||||
columns: ['IID', 'User', 'last', 'clr', 'ts'],
|
||||
rows: ret,
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
return { info: 'Invalid action given' };
|
||||
|
|
|
@ -3,7 +3,11 @@ import readline from 'readline';
|
|||
|
||||
import { PIXELLOGGER_PREFIX } from './logger';
|
||||
import { getNamesToIds } from '../data/sql/RegUser';
|
||||
import { getIdsToIps, getIPofIID } from '../data/sql/IPInfo';
|
||||
import {
|
||||
getIdsToIps,
|
||||
getInfoToIps,
|
||||
getIPofIID,
|
||||
} from '../data/sql/IPInfo';
|
||||
import { getIPv6Subnet } from '../utils/ip';
|
||||
|
||||
|
||||
|
@ -64,10 +68,11 @@ export async function getSummaryFromArea(
|
|||
}
|
||||
try {
|
||||
await parseFile((parts) => {
|
||||
const [ts, ipFull, uid, cid, x, y,, clr] = parts;
|
||||
// eslint-disable-next-line eqeqeq
|
||||
if (canvasId == cid
|
||||
&& ts >= time
|
||||
const [tsStr, ipFull, uidStr, cid, x, y,, clrStr] = parts;
|
||||
const ts = parseInt(tsStr, 10);
|
||||
if (ts >= time
|
||||
// eslint-disable-next-line eqeqeq
|
||||
&& canvasId == cid
|
||||
&& x >= xUL
|
||||
&& x <= xBR
|
||||
&& y >= yUL
|
||||
|
@ -77,6 +82,8 @@ export async function getSummaryFromArea(
|
|||
if (filterIP && ip !== filterIP) {
|
||||
return;
|
||||
}
|
||||
const clr = parseInt(clrStr, 10);
|
||||
const uid = parseInt(uidStr, 10);
|
||||
let curVals = ips[ip];
|
||||
if (!curVals) {
|
||||
curVals = [0, ip, uid, 0, 0, 0, 0];
|
||||
|
@ -97,24 +104,63 @@ export async function getSummaryFromArea(
|
|||
const uid2Name = await getNamesToIds(uids);
|
||||
|
||||
const ipKeys = Object.keys(ips);
|
||||
const ip2Id = await getIdsToIps(ipKeys);
|
||||
const ip2Info = await getInfoToIps(ipKeys);
|
||||
|
||||
let printIIDs = false;
|
||||
let printUsers = false;
|
||||
const columns = ['rid', '#'];
|
||||
const types = ['number', 'number'];
|
||||
if (ip2Info.size > 0) {
|
||||
printIIDs = true;
|
||||
columns.push('IID', 'ct', 'cidr', 'org', 'pc');
|
||||
types.push('uuid', 'flag', 'string', 'string', 'string');
|
||||
}
|
||||
if (uid2Name.size > 0) {
|
||||
printUsers = true;
|
||||
columns.push('User');
|
||||
types.push('user');
|
||||
}
|
||||
columns.push('last', 'clr', 'time');
|
||||
types.push('coord', 'clr', 'ts');
|
||||
|
||||
const rows = [];
|
||||
for (let i = 0; i < ipKeys.length; i += 1) {
|
||||
const [pxls, ip, uid, x, y, clr, ts] = ips[ipKeys[i]];
|
||||
const userMd = (uid && uid2Name[uid])
|
||||
? `@[${uid2Name[uid]}](${uid})` : 'N/A';
|
||||
rows.push([
|
||||
pxls,
|
||||
ip2Id[ip] || 'N/A',
|
||||
userMd,
|
||||
`#d,${x},${y}`,
|
||||
clr,
|
||||
ts,
|
||||
]);
|
||||
const row = [i, pxls];
|
||||
if (printIIDs) {
|
||||
const ipInfo = ip2Info.get(ip);
|
||||
if (!ipInfo) {
|
||||
row.push('N/A', 'xx', 'N/A', 'N/A', 'N/A');
|
||||
}
|
||||
let { pcheck } = ipInfo;
|
||||
if (pcheck) {
|
||||
const seperator = pcheck.indexOf(',');
|
||||
if (seperator !== -1) {
|
||||
pcheck = pcheck.slice(0, seperator);
|
||||
}
|
||||
}
|
||||
row.push(
|
||||
ipInfo.uuid || 'N/A',
|
||||
ipInfo.country || 'xx',
|
||||
ipInfo.cidr || 'N/A',
|
||||
ipInfo.org || 'N/A',
|
||||
pcheck || 'N/A',
|
||||
);
|
||||
}
|
||||
if (printUsers) {
|
||||
const userMd = (uid && uid2Name.has(uid))
|
||||
? `${uid2Name.get(uid)},${uid}` : 'N/A';
|
||||
row.push(userMd);
|
||||
}
|
||||
row.push(`${x},${y}`, clr, ts);
|
||||
rows.push(row);
|
||||
}
|
||||
|
||||
return rows;
|
||||
return {
|
||||
columns,
|
||||
types,
|
||||
rows,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
@ -140,10 +186,11 @@ export async function getPixelsFromArea(
|
|||
}
|
||||
try {
|
||||
await parseFile((parts) => {
|
||||
const [ts, ipFull, uid, cid, x, y,, clr] = parts;
|
||||
// eslint-disable-next-line eqeqeq
|
||||
if (canvasId == cid
|
||||
&& ts >= time
|
||||
const [tsStr, ipFull, uidStr, cid, x, y,, clrStr] = parts;
|
||||
const ts = parseInt(tsStr, 10);
|
||||
if (ts >= time
|
||||
// eslint-disable-next-line eqeqeq
|
||||
&& canvasId == cid
|
||||
&& x >= xUL
|
||||
&& x <= xBR
|
||||
&& y >= yUL
|
||||
|
@ -153,6 +200,8 @@ export async function getPixelsFromArea(
|
|||
if (filterIP && ip !== filterIP) {
|
||||
return;
|
||||
}
|
||||
const clr = parseInt(clrStr, 10);
|
||||
const uid = parseInt(uidStr, 10);
|
||||
pixels.push([ip, uid, x, y, clr, ts]);
|
||||
if (!ips.includes(ip)) {
|
||||
ips.push(ip);
|
||||
|
@ -169,20 +218,42 @@ export async function getPixelsFromArea(
|
|||
|
||||
const pixelF = (pixels.length > 300) ? pixels.slice(maxRows * -1) : pixels;
|
||||
|
||||
let printIIDs = false;
|
||||
let printUsers = false;
|
||||
const columns = ['#'];
|
||||
const types = ['number'];
|
||||
if (!filterIP && ip2Id.size > 0) {
|
||||
printIIDs = true;
|
||||
columns.push('IID');
|
||||
types.push('uuid');
|
||||
}
|
||||
if (!filterIP && uid2Name.size > 0) {
|
||||
printUsers = true;
|
||||
columns.push('User');
|
||||
types.push('user');
|
||||
}
|
||||
columns.push('coord', 'clr', 'time');
|
||||
types.push('coord', 'clr', 'ts');
|
||||
|
||||
const rows = [];
|
||||
for (let i = 0; i < pixelF.length; i += 1) {
|
||||
const [ip, uid, x, y, clr, ts] = pixelF[i];
|
||||
const userMd = (uid && uid2Name[uid])
|
||||
? `@[${uid2Name[uid]}](${uid})` : 'N/A';
|
||||
const id = ip2Id[ip] || 'N/A';
|
||||
rows.push([
|
||||
id,
|
||||
userMd,
|
||||
`#d,${x},${y}`,
|
||||
clr,
|
||||
ts,
|
||||
]);
|
||||
const row = [i];
|
||||
if (printIIDs) {
|
||||
row.push(ip2Id.get(ip) || 'N/A');
|
||||
}
|
||||
if (printUsers) {
|
||||
const userMd = (uid && uid2Name.has(uid))
|
||||
? `${uid2Name.get(uid)},${uid}` : 'N/A';
|
||||
row.push(userMd);
|
||||
}
|
||||
row.push(`${x},${y}`, clr, ts);
|
||||
rows.push(row);
|
||||
}
|
||||
|
||||
return rows;
|
||||
return {
|
||||
columns,
|
||||
types,
|
||||
rows,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -90,34 +90,57 @@ const IPInfo = sequelize.define('IPInfo', {
|
|||
export async function getIPofIID(uuid) {
|
||||
let result = null;
|
||||
try {
|
||||
result = IPInfo.findOne({
|
||||
result = await IPInfo.findOne({
|
||||
attributes: ['ip'],
|
||||
where: { uuid },
|
||||
raw: true,
|
||||
});
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
if (result) {
|
||||
return result.id;
|
||||
return result.ip;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function getIdsToIps(ips) {
|
||||
const ipToIdMap = {};
|
||||
if (!ips.length) {
|
||||
const ipToIdMap = new Map();
|
||||
if (!ips.length || ips.length > 100) {
|
||||
return ipToIdMap;
|
||||
}
|
||||
const result = await IPInfo.findAll({
|
||||
attributes: ['ip', 'uuid'],
|
||||
where: {
|
||||
ip: ips,
|
||||
},
|
||||
raw: true,
|
||||
});
|
||||
result.forEach((obj) => {
|
||||
ipToIdMap[obj.ip] = obj.uuid;
|
||||
});
|
||||
try {
|
||||
const result = await IPInfo.findAll({
|
||||
attributes: ['ip', 'uuid'],
|
||||
where: { ip: ips },
|
||||
raw: true,
|
||||
});
|
||||
result.forEach((obj) => {
|
||||
ipToIdMap.set(obj.ip, obj.uuid);
|
||||
});
|
||||
} catch {
|
||||
// nothing
|
||||
}
|
||||
return ipToIdMap;
|
||||
}
|
||||
|
||||
export async function getInfoToIps(ips) {
|
||||
const ipToIdMap = new Map();
|
||||
if (!ips.length || ips.length > 100) {
|
||||
return ipToIdMap;
|
||||
}
|
||||
try {
|
||||
const result = await IPInfo.findAll({
|
||||
attributes: ['ip', 'uuid', 'country', 'cidr', 'org', 'pcheck'],
|
||||
where: { ip: ips },
|
||||
raw: true,
|
||||
});
|
||||
result.forEach((obj) => {
|
||||
ipToIdMap.set(obj.ip, obj);
|
||||
});
|
||||
} catch {
|
||||
// nothing
|
||||
}
|
||||
return ipToIdMap;
|
||||
}
|
||||
|
||||
|
|
|
@ -182,20 +182,24 @@ export async function findIdByNameOrId(searchString) {
|
|||
}
|
||||
|
||||
export async function getNamesToIds(ids) {
|
||||
const idToNameMap = {};
|
||||
if (!ids.length) {
|
||||
const idToNameMap = new Map();
|
||||
if (!ids.length || ids.length > 100) {
|
||||
return idToNameMap;
|
||||
}
|
||||
const result = await RegUser.findAll({
|
||||
attributes: ['id', 'name'],
|
||||
where: {
|
||||
id: ids,
|
||||
},
|
||||
raw: true,
|
||||
});
|
||||
result.forEach((obj) => {
|
||||
idToNameMap[obj.id] = obj.name;
|
||||
});
|
||||
try {
|
||||
const result = await RegUser.findAll({
|
||||
attributes: ['id', 'name'],
|
||||
where: {
|
||||
id: ids,
|
||||
},
|
||||
raw: true,
|
||||
});
|
||||
result.forEach((obj) => {
|
||||
idToNameMap.set(obj.id, obj.name);
|
||||
});
|
||||
} catch {
|
||||
// nothing
|
||||
}
|
||||
return idToNameMap;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user