add default cooldown for unregistered first-connections

This commit is contained in:
HF 2023-06-29 17:17:14 +02:00
parent 924fb41741
commit d5469f7dc6
4 changed files with 39 additions and 22 deletions

View File

@ -50,8 +50,12 @@ setInterval(() => {
* @param i Chunk coordinates
* @param j
* @param pixels Array of individual pixels within the chunk, with:
* [[offset, color], [offset2, color2],...]
* Offset is the offset of the pixel within the chunk
* [[offset, color], [offset2, color2],...]
* Offset is the offset of the pixel within the chunk
* @param connectedTs Timestamp when connection got established.
* if the connection is younger than the cooldown of the canvas,
* we fill up the cd on first pixel to nerf one-connection
* ip-changing cheaters
* @return Promise<Object>
*/
export default async function drawByOffsets(
@ -60,6 +64,7 @@ export default async function drawByOffsets(
i,
j,
pixels,
connectedTs,
) {
let wait = 0;
let coolDown = 0;
@ -122,12 +127,13 @@ export default async function drawByOffsets(
const bcd = canvas.bcd * factor;
const pcd = (canvas.pcd) ? canvas.pcd * factor : bcd;
const userId = user.id;
const pxlOffsets = [];
/*
* validate pixels
*/
let ranked = canvas.ranked && user.id && pcd;
let ranked = canvas.ranked && userId && pcd;
for (let u = 0; u < pixels.length; u += 1) {
const [offset, color] = pixels[u];
pxlOffsets.push(offset);
@ -135,7 +141,7 @@ export default async function drawByOffsets(
const [x, y, z] = getPixelFromChunkOffset(i, j, offset, canvasSize, is3d);
pixelLogger.info(
// eslint-disable-next-line max-len
`${startTime} ${user.ip} ${user.id} ${canvasId} ${x} ${y} ${z} ${color}`,
`${startTime} ${user.ip} ${userId} ${canvasId} ${x} ${y} ${z} ${color}`,
);
const maxSize = (is3d) ? tileSize * tileSize * THREE_CANVAS_HEIGHT
@ -170,11 +176,17 @@ export default async function drawByOffsets(
}
}
const { cds } = canvas;
// start with almost filled cd on new connections
let cdIfNull = cds - pcd + 1000 - startTime + connectedTs;
if (cdIfNull < 0 || userId || bcd === 0) {
cdIfNull = 0;
}
let needProxycheck;
[retCode, pxlCnt, wait, coolDown, needProxycheck] = await allowPlace(
ip,
user.id,
userId,
user.country,
ranked,
canvasId,
@ -182,7 +194,8 @@ export default async function drawByOffsets(
clrIgnore,
req,
bcd, pcd,
canvas.cds,
cds,
cdIfNull,
pxlOffsets,
);

View File

@ -39,6 +39,7 @@ export default function allowPlace(
bcd,
pcd,
cds,
cdIfNull,
pxls,
) {
const isalKey = `${ALLOWED_PREFIX}:${ip}`;
@ -67,7 +68,7 @@ export default function allowPlace(
return client.placePxl(
// eslint-disable-next-line max-len
isalKey, captKey, ipCdKey, idCdKey, chunkKey, rankset, dailyset, DAILY_CRANKED_KEY, PREV_DAY_TOP_KEY,
clrIgnore, bcd, pcd, cds, id, cc, req,
clrIgnore, bcd, pcd, cds, cdIfNull, id, cc, req,
...pxls,
);
}

View File

@ -20,10 +20,10 @@
-- bcd: number baseCooldown (fixed to cdFactor and 0 if admin)
-- pcd: number set pixel cooldown (fixed to cdFactor and 0 if admin)
-- cds: max cooldown of canvas
-- cdIfNull: cooldown to use when no cooldown is stored
-- userId: '0' if not logged in
-- cc country code
-- req: requirements of canvas
-- 'nope', unsigned integer or 'top'
-- req: requirements of canvas ('nope', unsigned integer or 'top')
-- off1, chunk offset of first pixel
-- off2, chunk offset of second pixel
-- ..., infinite pixels possible
@ -63,23 +63,23 @@ else
end
end
-- check if requirements for canvas met
if ARGV[7] ~= "nope" then
if ARGV[5] == "0" then
if ARGV[8] ~= "nope" then
if ARGV[6] == "0" then
-- not logged in
ret[1] = 6
return ret;
end
if ARGV[7] == "top" then
local pr = redis.call('zrank', KEYS[9], ARGV[5])
if ARGV[8] == "top" then
local pr = redis.call('zrank', KEYS[9], ARGV[6])
if not pr or pr > 9 then
-- not in yesterdays top 10
ret[1] = 12;
return ret;
end
else
local req = tonumber(ARGV[7])
local req = tonumber(ARGV[8])
if req > 0 then
local sc = tonumber(redis.call('zscore', KEYS[6], ARGV[5]))
local sc = tonumber(redis.call('zscore', KEYS[6], ARGV[6]))
if not sc or sc < req then
-- not enough pxls placed
ret[1] = 7;
@ -91,7 +91,7 @@ end
-- get cooldown of user
local cd = redis.call('pttl', KEYS[3])
if cd < 0 then
cd = 0
cd = tonumber(ARGV[5])
end
if KEYS[4] ~= "nope" then
local icd = redis.call('pttl', KEYS[4])
@ -106,7 +106,7 @@ local cli = tonumber(ARGV[1])
local bcd = tonumber(ARGV[2])
local pcd = tonumber(ARGV[3])
local cds = tonumber(ARGV[4])
for c = 8,#ARGV do
for c = 9,#ARGV do
local off = tonumber(ARGV[c]) * 8
-- get color of pixel on canvas
local sclr = redis.call('bitfield', KEYS[5], 'get', 'u8', off)
@ -144,10 +144,11 @@ if pxlcnt > 0 then
end
-- increment pixelcount
if KEYS[7] ~= 'nope' then
redis.call('zincrby', KEYS[6], pxlcnt, ARGV[5])
redis.call('zincrby', KEYS[7], pxlcnt, ARGV[5])
if ARGV[6] ~= 'xx' then
redis.call('zincrby', KEYS[8], pxlcnt, ARGV[6])
redis.call('zincrby', KEYS[6], pxlcnt, ARGV[6])
redis.call('zincrby', KEYS[7], pxlcnt, ARGV[6])
-- increase country stats only by registered users
if ARGV[7] ~= 'xx' then
redis.call('zincrby', KEYS[8], pxlcnt, ARGV[7])
end
end
end

View File

@ -75,6 +75,7 @@ class SocketServer {
wss.on('connection', (ws, req) => {
ws.timeLastMsg = Date.now();
ws.connectedTs = ws.timeLastMsg;
ws.canvasId = null;
const { user } = req;
ws.user = user;
@ -538,7 +539,7 @@ class SocketServer {
switch (opcode) {
case PIXEL_UPDATE_OP: {
const { canvasId } = ws;
const { canvasId, connectedTs } = ws;
if (canvasId === null) {
logger.info(`Closing websocket without canvas from ${ip}`);
@ -560,6 +561,7 @@ class SocketServer {
canvasId,
i, j,
pixels,
connectedTs,
);
if (retCode > 9 && retCode !== 13) {