Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(engine): last logged in ip address & number of days #1040

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions data/src/scripts/login_logout/login.rs2
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ softtimer(stat_replenish, 100);
softtimer(health_replenish, 100);
// random event timer
settimer(general_macro_events, 500);
// chest macro gas
// chest macro gas
~check_chest_macro_gas;
// for logout out during a general macro event, they respawn when you log back in
// queue:
// queue:
// - https://youtu.be/T0ulsgorBkY?list=PLn23LiLYLb1Y3P9S9qZbijcJihiD416jT
// - https://youtu.be/HwGAzcmvF9k?list=PLn23LiLYLb1Y3P9S9qZbijcJihiD416jT
// npc spawns only after interface is closed
Expand Down
4 changes: 2 additions & 2 deletions src/engine/World.ts
Original file line number Diff line number Diff line change
Expand Up @@ -863,7 +863,7 @@
try {
// if it throws then there was no available pid. otherwise guaranteed to not be -1.
pid = this.getNextPid(isClientConnected(player) ? player.client : null);
} catch (e) {

Check warning on line 866 in src/engine/World.ts

View workflow job for this annotation

GitHub Actions / build

'e' is defined but never used
// world full
if (isClientConnected(player)) {
player.client.send(Uint8Array.from([ 7 ]));
Expand Down Expand Up @@ -1588,7 +1588,7 @@
}
}

onLoginMessage(msg: any) {

Check warning on line 1591 in src/engine/World.ts

View workflow job for this annotation

GitHub Actions / build

Unexpected any. Specify a different type
const { type } = msg;

if (type === 'player_login') {
Expand Down Expand Up @@ -1623,14 +1623,14 @@
return;
}

const { username, lowMemory, reconnecting, staffmodlevel, muted_until } = msg;
const { username, password, lowMemory, reconnecting, staffmodlevel, muted_until } = msg;

let save = new Uint8Array();
if (reply === 0 || reply === 2) {
save = msg.save;
}

const player = PlayerLoading.load(username, new Packet(save), client);
const player = PlayerLoading.load(username, password, new Packet(save), client);
player.reconnecting = reconnecting;
player.staffModLevel = staffmodlevel;
player.lowMemory = lowMemory;
Expand Down Expand Up @@ -1658,7 +1658,7 @@
}
}

onFriendMessage({ opcode, data }: { opcode: FriendsServerOpcodes, data: any }) {

Check warning on line 1661 in src/engine/World.ts

View workflow job for this annotation

GitHub Actions / build

Unexpected any. Specify a different type
try {
if (opcode === FriendsServerOpcodes.UPDATE_FRIENDLIST) {
const username37 = BigInt(data.username37);
Expand Down
4 changes: 2 additions & 2 deletions src/engine/entity/NetworkPlayer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'dotenv/config';
import fs from 'fs';

Check warning on line 2 in src/engine/entity/NetworkPlayer.ts

View workflow job for this annotation

GitHub Actions / build

'fs' is defined but never used. Allowed unused vars must match /^_/u

import ServerProt from '#/network/rs225/server/prot/ServerProt.js';

Expand Down Expand Up @@ -51,8 +51,8 @@
opcalled: boolean = false;
opucalled: boolean = false;

constructor(username: string, username37: bigint, client: ClientSocket) {
super(username, username37);
constructor(username: string, username37: bigint, password: string | null, client: ClientSocket) {
super(username, username37, password);

this.client = client;
this.client.player = this;
Expand Down
20 changes: 17 additions & 3 deletions src/engine/entity/Player.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'dotenv/config';

import Packet from '#/io/Packet.js';
import {fromBase37, toDisplayName} from '#/util/JString.js';
import { toDisplayName } from '#/util/JString.js';

import FontType from '#/cache/config/FontType.js';
import Component from '#/cache/config/Component.js';
Expand Down Expand Up @@ -135,7 +135,7 @@
save() {
const sav = Packet.alloc(1);
sav.p2(0x2004); // magic
sav.p2(5); // version
sav.p2(6); // version

sav.p2(this.x);
sav.p2(this.z);
Expand Down Expand Up @@ -202,8 +202,17 @@
sav.p4(this.afkZones[index]);
}
sav.p2(this.lastAfkZone);

sav.p1((this.publicChat << 4) | (this.privateChat << 2) | this.tradeDuel);

if (this.lastAddress) {
sav.p1(this.lastAddress.length);
sav.pdata(this.lastAddress, 0, this.lastAddress.length);
} else {
sav.p1(0);
}
sav.p8(this.lastDate);

sav.p4(Packet.getcrc(sav.data, 0, sav.pos));
const data = sav.data.subarray(0, sav.pos);
sav.release();
Expand All @@ -214,6 +223,7 @@
username: string;
username37: bigint;
displayName: string;
password: string | null; // this is not saved anywhere, only used for ciphering the ip address.
body: number[] = [
0, // hair
10, // beard
Expand Down Expand Up @@ -328,10 +338,14 @@

muted_until: Date | null = null;

constructor(username: string, username37: bigint) {
lastAddress: Uint8Array | null = null;
lastDate: bigint = 0n;

constructor(username: string, username37: bigint, password: string | null) {
super(0, 3094, 3106, 1, 1, EntityLifeCycle.FOREVER, MoveRestrict.NORMAL, BlockWalk.NPC, MoveStrategy.SMART, InfoProt.PLAYER_FACE_COORD.id, InfoProt.PLAYER_FACE_ENTITY.id); // tutorial island.
this.username = username;
this.username37 = username37;
this.password = password;
this.displayName = toDisplayName(username);
this.vars = new Int32Array(VarPlayerType.count);
this.varsString = new Array(VarPlayerType.count);
Expand Down Expand Up @@ -1107,7 +1121,7 @@

// ----

getInventoryFromListener(listener: any) {

Check warning on line 1124 in src/engine/entity/Player.ts

View workflow job for this annotation

GitHub Actions / build

Unexpected any. Specify a different type
if (listener.source === -1) {
return World.getInventory(listener.type);
} else {
Expand Down
22 changes: 16 additions & 6 deletions src/engine/entity/PlayerLoading.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { NetworkPlayer } from '#/engine/entity/NetworkPlayer.js';
import Player, { getExpByLevel, getLevelByExp } from '#/engine/entity/Player.js';
import PlayerStat from '#/engine/entity/PlayerStat.js';

import Environment from '#/util/Environment.js';
import InvType from '#/cache/config/InvType.js';

export class PlayerLoading {
Expand All @@ -32,16 +31,16 @@ export class PlayerLoading {
save = new Packet(new Uint8Array());
}

return PlayerLoading.load(name, save, null);
return PlayerLoading.load(name, null, save, null);
}

static load(name: string, sav: Packet, client: ClientSocket | null) {
static load(name: string, password: string | null, sav: Packet, client: ClientSocket | null) {
const name37 = toBase37(name);
const safeName = fromBase37(name37);

const player = client
? new NetworkPlayer(safeName, name37, client)
: new Player(safeName, name37);
? new NetworkPlayer(safeName, name37, password, client)
: new Player(safeName, name37, password);

if (sav.data.length < 2) {
for (let i = 0; i < 21; i++) {
Expand All @@ -62,7 +61,7 @@ export class PlayerLoading {
}

const version = sav.g2();
if (version > 5) {
if (version > 6) {
throw new Error('Unsupported player save format');
}

Expand Down Expand Up @@ -150,6 +149,17 @@ export class PlayerLoading {
player.tradeDuel = packedChatModes & 0b11;
}

// last login info
if (version >= 6) {
const length = sav.g1();
if (length > 0) {
const lastAddress = new Uint8Array(length);
sav.gdata(lastAddress, 0, lastAddress.length);
player.lastAddress = lastAddress;
}
player.lastDate = sav.g8();
}

player.combatLevel = player.getCombatLevel();
player.lastResponse = World.currentTick;

Expand Down
35 changes: 26 additions & 9 deletions src/engine/script/handlers/PlayerOps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ import IfSetText from '#/network/server/model/IfSetText.js';
import IfSetNpcHead from '#/network/server/model/IfSetNpcHead.js';
import IfSetPosition from '#/network/server/model/IfSetPosition.js';

import ClientSocket from '#/server/ClientSocket.js';

import ColorConversion from '#/util/ColorConversion.js';

import {findPath} from '#/engine/GameMap.js';
Expand All @@ -61,6 +63,7 @@ import {
SkinColourValid
} from '#/engine/script/ScriptValidators.js';
import LoggerEventType from '#/server/logger/LoggerEventType.js';
import { decrypt, encrypt } from '#/util/Crypto.js';

const PlayerOps: CommandHandlers = {
[ScriptOpcode.FINDUID]: state => {
Expand Down Expand Up @@ -801,18 +804,32 @@ const PlayerOps: CommandHandlers = {
return;
}

const client = player.client;
const client: ClientSocket = player.client;
const password: string | null = player.password;
const remoteAddress: string | null = client.remoteAddress !== ClientSocket.NO_ADDRESS ? client.remoteAddress : null;

const remoteAddress = client.remoteAddress;
if (remoteAddress == null) {
return;
}
// if decrypt throws then the interface just won't even show on the client side
const lastAddress: string | null = player.lastAddress && password ? decrypt(player.lastAddress, password) : remoteAddress;
const lastDate: bigint = player.lastDate === 0n ? BigInt(Date.now()) : player.lastDate;

const lastLoginIp = new Uint32Array(new Uint8Array(remoteAddress.split('.').map(x => parseInt(x))).reverse().buffer)[0];
const nextDate: bigint = BigInt(Date.now());

// 201 sends welcome_screen if.
// not 201 sends welcome_screen_warning if.
player.lastLoginInfo(lastLoginIp, 0, 201, 0);
// message centre/recovery
const unreadMessageCount: number = 0;
const hasRecovery: boolean = true;
const daysSinceRecoveryChange: number = hasRecovery ? 201 : 0;

player.lastLoginInfo(
lastAddress ? new Uint32Array(new Uint8Array(lastAddress.split('.').map(Number)).reverse().buffer)[0] : 0,
Number(nextDate - lastDate) / (1000 * 60 * 60 * 24),
daysSinceRecoveryChange,
unreadMessageCount,
);

if (remoteAddress && password) {
player.lastAddress = encrypt(remoteAddress, password);
}
player.lastDate = nextDate;
},

[ScriptOpcode.BAS_READYANIM]: state => {
Expand Down
4 changes: 2 additions & 2 deletions src/network/rs225/client/handler/ClientCheatHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ export default class ClientCheatHandler extends MessageHandler<ClientCheat> {
} else if (cmd === 'bots') {
player.messageGame('Adding bots');
for (let i = 0; i < 1999; i++) {
const bot: Player = PlayerLoading.load(`bot${i}`, new Packet(new Uint8Array()), new NullClientSocket());
const bot: Player = PlayerLoading.load(`bot${i}`, null, new Packet(new Uint8Array()), new NullClientSocket());
World.addPlayer(bot);
}
} else if (cmd === 'lightbots') {
player.messageGame('Adding lightweight bots');
for (let i = 0; i < 1999; i++) {
const bot: Player = PlayerLoading.load(`bot${i}`, new Packet(new Uint8Array()), null);
const bot: Player = PlayerLoading.load(`bot${i}`, null, new Packet(new Uint8Array()), null);
World.addPlayer(bot);
}
} else if (cmd === 'teleall') {
Expand Down
4 changes: 3 additions & 1 deletion src/server/ClientSocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import Packet from '#/io/Packet.js';
import { NetworkPlayer } from '#/engine/entity/NetworkPlayer.js';

export default abstract class ClientSocket {
public static readonly NO_ADDRESS: string = 'unknown';

uuid = randomUUID();
remoteAddress = 'unknown';
remoteAddress = ClientSocket.NO_ADDRESS;
totalBytesRead = 0;
totalBytesWritten = 0;

Expand Down
3 changes: 3 additions & 0 deletions src/server/login/LoginThread.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ async function handleRequests(parentPort: ParentPort, msg: any) {
type: 'player_login',
socket,
username,
password,
lowMemory,
reconnecting,
...await client.playerLogin(username, password, uid)
Expand All @@ -75,6 +76,7 @@ async function handleRequests(parentPort: ParentPort, msg: any) {
type: 'player_login',
socket,
username,
password,
lowMemory,
reconnecting,
reply: 4,
Expand All @@ -86,6 +88,7 @@ async function handleRequests(parentPort: ParentPort, msg: any) {
type: 'player_login',
socket,
username,
password,
lowMemory,
reconnecting,
reply: 0,
Expand Down
25 changes: 25 additions & 0 deletions src/util/Crypto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import crypto from 'crypto';

export function encrypt(value: string, passphrase: string): Uint8Array | null {
try {
const iv = crypto.randomBytes(16);
const key = crypto.createHash('sha256').update(passphrase).digest();
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
return new Uint8Array(Buffer.concat([iv, Buffer.concat([cipher.update(value), cipher.final()])]));
} catch (err) {
console.error(err);
}
return null;
}

export function decrypt(bytes: Uint8Array, passphrase: string): string | null {
try {
const iv = bytes.subarray(0, 16);
const key = crypto.createHash('sha256').update(passphrase).digest();
const cipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
return Buffer.concat([cipher.update(bytes.subarray(16)), cipher.final()]).toString();
} catch (err) {
console.error(err);
}
return null;
}
Loading