[Closes #55] Generate predictable MAC address (but avoid sneaky data leakage)
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
import * as xmlrpc from 'xmlrpc';
|
||||
import * as crypto from 'crypto';
|
||||
import * as uuid from 'uuid';
|
||||
import * as url from 'url';
|
||||
import { LoginParameters } from './classes/LoginParameters';
|
||||
import { LoginResponse } from './classes/LoginResponse';
|
||||
import { ClientEvents } from './classes/ClientEvents';
|
||||
import { Utils } from './classes/Utils';
|
||||
import { BotOptionFlags } from './enums/BotOptionFlags';
|
||||
|
||||
export class LoginHandler
|
||||
@@ -12,23 +12,6 @@ export class LoginHandler
|
||||
private clientEvents: ClientEvents;
|
||||
private options: BotOptionFlags;
|
||||
|
||||
static GenerateMAC(): string
|
||||
{
|
||||
const hexDigits = '0123456789ABCDEF';
|
||||
let macAddress = '';
|
||||
for (let i = 0; i < 6; i++)
|
||||
{
|
||||
macAddress += hexDigits.charAt(Math.round(Math.random() * 15));
|
||||
macAddress += hexDigits.charAt(Math.round(Math.random() * 15));
|
||||
if (i !== 5)
|
||||
{
|
||||
macAddress += ':';
|
||||
}
|
||||
}
|
||||
|
||||
return macAddress;
|
||||
}
|
||||
|
||||
constructor(ce: ClientEvents, options: BotOptionFlags)
|
||||
{
|
||||
this.clientEvents = ce;
|
||||
@@ -61,7 +44,16 @@ export class LoginHandler
|
||||
rejectUnauthorized: false,
|
||||
timeout: 60000
|
||||
};
|
||||
const viewerDigest = 'ce50e500-e6f0-15ab-4b9d-0591afb91ffe';
|
||||
const client = (secure) ? xmlrpc.createSecureClient(secureClientOptions) : xmlrpc.createClient(secureClientOptions);
|
||||
|
||||
const nameHash = Utils.SHA1String(params.firstName + params.lastName + viewerDigest);
|
||||
const macAddress: string[] = [];
|
||||
for (let i = 0; i < 12; i = i + 2)
|
||||
{
|
||||
macAddress.push(nameHash.substr(i, 2));
|
||||
}
|
||||
|
||||
client.methodCall('login_to_simulator',
|
||||
[
|
||||
{
|
||||
@@ -74,8 +66,8 @@ export class LoginHandler
|
||||
'patch': '1',
|
||||
'build': '0',
|
||||
'platform': 'win',
|
||||
'mac': LoginHandler.GenerateMAC(),
|
||||
'viewer_digest': uuid.v4(),
|
||||
'mac': macAddress.join(':'),
|
||||
'viewer_digest': viewerDigest,
|
||||
'user_agent': 'node-metaverse',
|
||||
'author': 'nmv@caspertech.co.uk',
|
||||
'options': [
|
||||
|
||||
@@ -359,7 +359,7 @@ export class Comms
|
||||
private async groupChatExpired(groupID: UUID): Promise<void>
|
||||
{
|
||||
// Reconnect to group chat since it's been idle for 15 minutes
|
||||
await this.agent.currentRegion.clientCommands.comms.endGroupChatSession(groupID, false);
|
||||
await this.agent.currentRegion.clientCommands.comms.endGroupChatSession(groupID);
|
||||
await this.agent.currentRegion.clientCommands.comms.startGroupChatSession(groupID, '');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import { GlobalPosition } from './public/interfaces/GlobalPosition';
|
||||
import { Quaternion } from './Quaternion';
|
||||
import { Vector3 } from './Vector3';
|
||||
import Timeout = NodeJS.Timeout;
|
||||
import * as crypto from 'crypto';
|
||||
|
||||
export class Utils
|
||||
{
|
||||
@@ -28,6 +29,11 @@ export class Utils
|
||||
return Buffer.from(str + '\0', 'utf8');
|
||||
}
|
||||
|
||||
static SHA1String(str: string): string
|
||||
{
|
||||
return crypto.createHash('sha1').update(str).digest('hex');
|
||||
}
|
||||
|
||||
static BufferToStringSimple(buf: Buffer): string
|
||||
{
|
||||
if (buf.length === 0)
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
import { CommandsBase } from './CommandsBase';
|
||||
import { UUID } from '../UUID';
|
||||
import { Utils } from '../Utils';
|
||||
import { ImprovedInstantMessageMessage } from '../messages/ImprovedInstantMessage';
|
||||
import { Vector3 } from '../Vector3';
|
||||
import { ChatFromViewerMessage } from '../messages/ChatFromViewer';
|
||||
import * as LLSD from '@caspertech/llsd';
|
||||
import { AssetType } from '../../enums/AssetType';
|
||||
import { ChatType } from '../../enums/ChatType';
|
||||
import { FilterResponse } from '../../enums/FilterResponse';
|
||||
import { InstantMessageDialog } from '../../enums/InstantMessageDialog';
|
||||
import { ScriptDialogReplyMessage } from '../messages/ScriptDialogReply';
|
||||
import { InstantMessageOnline } from '../../enums/InstantMessageOnline';
|
||||
import { PacketFlags } from '../../enums/PacketFlags';
|
||||
import { GroupChatSessionJoinEvent } from '../../events/GroupChatSessionJoinEvent';
|
||||
import { ScriptDialogEvent } from '../../events/ScriptDialogEvent';
|
||||
import { StartLureMessage } from '../messages/StartLure';
|
||||
import { InventoryItem } from '../InventoryItem';
|
||||
import { InventoryFolder } from '../InventoryFolder';
|
||||
import { InstantMessageOnline } from '../../enums/InstantMessageOnline';
|
||||
import { AssetType } from '../../enums/AssetType';
|
||||
|
||||
import { InventoryItem } from '../InventoryItem';
|
||||
import { ChatFromViewerMessage } from '../messages/ChatFromViewer';
|
||||
import { ImprovedInstantMessageMessage } from '../messages/ImprovedInstantMessage';
|
||||
import { ScriptDialogReplyMessage } from '../messages/ScriptDialogReply';
|
||||
import { StartLureMessage } from '../messages/StartLure';
|
||||
import { Utils } from '../Utils';
|
||||
import { UUID } from '../UUID';
|
||||
import { Vector3 } from '../Vector3';
|
||||
import { CommandsBase } from './CommandsBase';
|
||||
import Timer = NodeJS.Timer;
|
||||
|
||||
import * as LLSD from '@caspertech/llsd';
|
||||
|
||||
export class CommunicationsCommands extends CommandsBase
|
||||
{
|
||||
async giveInventory(to: UUID | string, itemOrFolder: InventoryItem | InventoryFolder): Promise<void>
|
||||
@@ -389,7 +388,7 @@ export class CommunicationsCommands extends CommandsBase
|
||||
});
|
||||
}
|
||||
|
||||
public async endGroupChatSession(groupID: UUID | string, removeEntry = true): Promise<void>
|
||||
public async endGroupChatSession(groupID: UUID | string): Promise<void>
|
||||
{
|
||||
if (typeof groupID === 'string')
|
||||
{
|
||||
@@ -423,63 +422,55 @@ export class CommunicationsCommands extends CommandsBase
|
||||
im.EstateBlock = {
|
||||
EstateID: 0
|
||||
};
|
||||
if (removeEntry)
|
||||
{
|
||||
this.agent.deleteChatSession(groupID);
|
||||
}
|
||||
this.agent.deleteChatSession(groupID);
|
||||
const sequenceNo = this.circuit.sendMessage(im, PacketFlags.Reliable);
|
||||
return this.circuit.waitForAck(sequenceNo, 10000);
|
||||
}
|
||||
|
||||
startGroupChatSession(groupID: UUID | string, message: string): Promise<void>
|
||||
public async startGroupChatSession(groupID: UUID | string, message: string): Promise<void>
|
||||
{
|
||||
return new Promise<void>((resolve, reject) =>
|
||||
if (typeof groupID === 'string')
|
||||
{
|
||||
if (typeof groupID === 'string')
|
||||
{
|
||||
groupID = new UUID(groupID);
|
||||
}
|
||||
groupID = new UUID(groupID);
|
||||
}
|
||||
|
||||
const circuit = this.circuit;
|
||||
const agentName = this.agent.firstName + ' ' + this.agent.lastName;
|
||||
const im: ImprovedInstantMessageMessage = new ImprovedInstantMessageMessage();
|
||||
im.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: circuit.sessionID
|
||||
};
|
||||
im.MessageBlock = {
|
||||
FromGroup: false,
|
||||
ToAgentID: groupID,
|
||||
ParentEstateID: 0,
|
||||
RegionID: UUID.zero(),
|
||||
Position: Vector3.getZero(),
|
||||
Offline: 0,
|
||||
Dialog: InstantMessageDialog.SessionGroupStart,
|
||||
ID: groupID,
|
||||
Timestamp: Math.floor(new Date().getTime() / 1000),
|
||||
FromAgentName: Utils.StringToBuffer(agentName),
|
||||
Message: Utils.StringToBuffer(message),
|
||||
BinaryBucket: Utils.StringToBuffer('')
|
||||
};
|
||||
im.EstateBlock = {
|
||||
EstateID: 0
|
||||
};
|
||||
const waitForJoin = this.currentRegion.clientEvents.onGroupChatSessionJoin.subscribe((event: GroupChatSessionJoinEvent) =>
|
||||
if (this.agent.hasChatSession(groupID))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const circuit = this.circuit;
|
||||
const agentName = this.agent.firstName + ' ' + this.agent.lastName;
|
||||
const im: ImprovedInstantMessageMessage = new ImprovedInstantMessageMessage();
|
||||
im.AgentData = {
|
||||
AgentID: this.agent.agentID,
|
||||
SessionID: circuit.sessionID
|
||||
};
|
||||
im.MessageBlock = {
|
||||
FromGroup: false,
|
||||
ToAgentID: groupID,
|
||||
ParentEstateID: 0,
|
||||
RegionID: UUID.zero(),
|
||||
Position: Vector3.getZero(),
|
||||
Offline: 0,
|
||||
Dialog: InstantMessageDialog.SessionGroupStart,
|
||||
ID: groupID,
|
||||
Timestamp: Math.floor(new Date().getTime() / 1000),
|
||||
FromAgentName: Utils.StringToBuffer(agentName),
|
||||
Message: Utils.StringToBuffer(message),
|
||||
BinaryBucket: Utils.StringToBuffer('')
|
||||
};
|
||||
im.EstateBlock = {
|
||||
EstateID: 0
|
||||
};
|
||||
circuit.sendMessage(im, PacketFlags.Reliable);
|
||||
await Utils.waitOrTimeOut(this.currentRegion.clientEvents.onGroupChatSessionJoin, 10000, (event: GroupChatSessionJoinEvent) =>
|
||||
{
|
||||
if (event.sessionID.toString() === groupID.toString())
|
||||
{
|
||||
if (event.sessionID.toString() === groupID.toString())
|
||||
{
|
||||
if (event.success)
|
||||
{
|
||||
waitForJoin.unsubscribe();
|
||||
resolve();
|
||||
}
|
||||
else
|
||||
{
|
||||
reject();
|
||||
}
|
||||
}
|
||||
});
|
||||
circuit.sendMessage(im, PacketFlags.Reliable);
|
||||
return FilterResponse.Finish;
|
||||
}
|
||||
return FilterResponse.NoMatch;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -510,12 +501,16 @@ export class CommunicationsCommands extends CommandsBase
|
||||
|
||||
async sendGroupMessage(groupID: UUID | string, message: string): Promise<number>
|
||||
{
|
||||
await this.startGroupChatSession(groupID, message);
|
||||
|
||||
if (typeof groupID === 'string')
|
||||
{
|
||||
groupID = new UUID(groupID);
|
||||
}
|
||||
|
||||
if (!this.agent.hasChatSession(groupID))
|
||||
{
|
||||
await this.startGroupChatSession(groupID, message);
|
||||
}
|
||||
|
||||
const circuit = this.circuit;
|
||||
const agentName = this.agent.firstName + ' ' + this.agent.lastName;
|
||||
const im: ImprovedInstantMessageMessage = new ImprovedInstantMessageMessage();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@caspertech/node-metaverse",
|
||||
"version": "0.5.32",
|
||||
"version": "0.5.33",
|
||||
"description": "A node.js interface for Second Life.",
|
||||
"main": "dist/lib/index.js",
|
||||
"types": "dist/lib/index.d.ts",
|
||||
|
||||
Reference in New Issue
Block a user