mirror of
https://github.com/amigan/aim-oscar-server.git
synced 2024-11-21 20:19:47 -05:00
split auth and chat servers
This commit is contained in:
parent
aad0acfd15
commit
19e26cddbb
15 changed files with 175 additions and 97 deletions
|
@ -5,7 +5,8 @@
|
|||
"license": "MIT",
|
||||
"scripts": {
|
||||
"dev:tsc": "tsc --watch",
|
||||
"dev:nodemon": "nodemon --watch ./dist --delay 200ms",
|
||||
"dev:nodemon:auth": "nodemon --watch ./dist --delay 200ms dist/src/main-auth.js",
|
||||
"dev:nodemon:chat": "nodemon --watch ./dist --delay 200ms dist/src/main-chat.js",
|
||||
"start": "tsc && node ./dist/index.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -1,24 +1,6 @@
|
|||
import net from "net";
|
||||
import { FLAP, SNAC, TLV, TLVType } from './structures';
|
||||
import { logDataStream } from './util';
|
||||
import { FLAGS_EMPTY } from './consts';
|
||||
|
||||
import GenericServiceControls from "./services/0x01-GenericServiceControls";
|
||||
import LocationServices from "./services/0x02-LocationSerices";
|
||||
import BuddyListManagement from "./services/0x03-BuddyListManagement";
|
||||
import ICBM from "./services/0x04-ICBM";
|
||||
import Invitation from "./services/0x06-Invitation";
|
||||
import Administration from "./services/0x07-Administration";
|
||||
import Popups from "./services/0x08-Popups";
|
||||
import PrivacyManagement from "./services/0x09-PrivacyManagement";
|
||||
import UserLookup from "./services/0x0a-UserLookup";
|
||||
import UsageStats from "./services/0x0b-UsageStats";
|
||||
import ChatNavigation from "./services/0x0d-ChatNavigation";
|
||||
import Chat from "./services/0x0e-Chat";;
|
||||
import DirectorySearch from "./services/0x0f-DirectorySearch";
|
||||
import ServerStoredBuddyIcons from "./services/0x10-ServerStoredBuddyIcons";
|
||||
import SSI from "./services/0x13-SSI";
|
||||
import AuthorizationRegistrationService from "./services/0x17-AuthorizationRegistration";
|
||||
|
||||
import BaseService from "./services/base";
|
||||
|
||||
|
@ -30,15 +12,15 @@ export interface User {
|
|||
|
||||
export default class Communicator {
|
||||
|
||||
private keepaliveInterval? : NodeJS.Timer;
|
||||
private _sequenceNumber = 0;
|
||||
private messageBuffer = Buffer.alloc(0);
|
||||
public services : {[key: number]: BaseService} = {};
|
||||
public user? : User;
|
||||
|
||||
constructor(public socket : net.Socket) {
|
||||
// Hold on to the socket
|
||||
this.socket = socket;
|
||||
constructor(public socket : net.Socket) {}
|
||||
|
||||
startListening() {
|
||||
this.socket.on('data', (data : Buffer) => {
|
||||
// we could get multiple FLAP messages, keep a running buffer of incoming
|
||||
// data and shift-off however many successful FLAPs we can make
|
||||
|
@ -60,36 +42,23 @@ export default class Communicator {
|
|||
}
|
||||
});
|
||||
|
||||
this.registerServices();
|
||||
this.start();
|
||||
}
|
||||
this.keepaliveInterval = setInterval(() => {
|
||||
const keepaliveFlap = new FLAP(0x05, this.nextReqID, Buffer.from(""));
|
||||
this.socket.write(keepaliveFlap.toBuffer());
|
||||
}, 4 * 60 * 1000);
|
||||
|
||||
this.socket.on('close', () => {
|
||||
if (this.keepaliveInterval) {
|
||||
clearInterval(this.keepaliveInterval);
|
||||
}
|
||||
});
|
||||
|
||||
start() {
|
||||
// Start negotiating a connection
|
||||
const hello = new FLAP(0x01, 0, Buffer.from([0x00, 0x00, 0x00, 0x01]));
|
||||
this.send(hello);
|
||||
}
|
||||
|
||||
registerServices() {
|
||||
const services = [
|
||||
new GenericServiceControls(this),
|
||||
new LocationServices(this),
|
||||
new BuddyListManagement(this),
|
||||
new ICBM(this),
|
||||
new Invitation(this),
|
||||
new Administration(this),
|
||||
new Popups(this),
|
||||
new PrivacyManagement(this),
|
||||
new UserLookup(this),
|
||||
new UsageStats(this),
|
||||
new ChatNavigation(this),
|
||||
new Chat(this),
|
||||
new DirectorySearch(this),
|
||||
new ServerStoredBuddyIcons(this),
|
||||
// new SSI(this),
|
||||
new AuthorizationRegistrationService(this),
|
||||
];
|
||||
|
||||
registerServices(services : BaseService[] = []) {
|
||||
// Make a map of the service number to the service handler
|
||||
this.services = {};
|
||||
services.forEach((service) => {
|
||||
|
@ -97,8 +66,8 @@ export default class Communicator {
|
|||
});
|
||||
}
|
||||
|
||||
_getNewSequenceNumber() {
|
||||
return ++this._sequenceNumber;
|
||||
get nextReqID() {
|
||||
return ++this._sequenceNumber & 0xFFFF;
|
||||
}
|
||||
|
||||
send(message : FLAP) {
|
||||
|
@ -136,8 +105,8 @@ export default class Communicator {
|
|||
Object.values(this.services).forEach((subtype) => {
|
||||
servicesOffered.push(Buffer.from([0x00, subtype.service]));
|
||||
});
|
||||
const resp = new FLAP(2, this._getNewSequenceNumber(),
|
||||
new SNAC(0x01, 0x03, FLAGS_EMPTY, 0, Buffer.concat(servicesOffered)));
|
||||
const resp = new FLAP(2, this.nextReqID,
|
||||
new SNAC(0x01, 0x03, Buffer.concat(servicesOffered)));
|
||||
this.send(resp);
|
||||
return;
|
||||
}
|
||||
|
|
21
src/haxor-proxy.ts
Normal file
21
src/haxor-proxy.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import net from "net";
|
||||
|
||||
const server = net.createServer((socket) => {
|
||||
socket.setTimeout(5 * 60 * 1000); // 5 minute timeout
|
||||
socket.on('timeout', () => {
|
||||
console.log('socket timeout');
|
||||
socket.end();
|
||||
});
|
||||
|
||||
socket.on('end', () => {
|
||||
console.log('client disconnected...');
|
||||
});
|
||||
});
|
||||
|
||||
server.on('error', (err) => {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
server.listen(9999, () => {
|
||||
console.log('proxy ready');
|
||||
})
|
|
@ -1,9 +1,11 @@
|
|||
import net from 'net';
|
||||
import Communicator from './communicator';
|
||||
|
||||
import AuthorizationRegistrationService from "./services/0x17-AuthorizationRegistration";
|
||||
|
||||
const server = net.createServer((socket) => {
|
||||
console.log('client connected...');
|
||||
socket.setTimeout(30000);
|
||||
socket.setTimeout(5 * 60 * 1000); // 5 minute timeout
|
||||
|
||||
socket.on('error', (e) => {
|
||||
console.error('socket encountered an error:', e);
|
||||
|
@ -19,7 +21,12 @@ const server = net.createServer((socket) => {
|
|||
console.log('client disconnected...');
|
||||
});
|
||||
|
||||
new Communicator(socket);
|
||||
const comm = new Communicator(socket);
|
||||
const services = [
|
||||
new AuthorizationRegistrationService(comm),
|
||||
];
|
||||
comm.registerServices(services);
|
||||
comm.startListening();
|
||||
});
|
||||
|
||||
server.on('error', (err) => {
|
||||
|
@ -27,5 +34,5 @@ server.on('error', (err) => {
|
|||
});
|
||||
|
||||
server.listen(5190, () => {
|
||||
console.log('OSCAR ready on :5190');
|
||||
console.log('AUTH ready on :5190');
|
||||
});
|
66
src/main-chat.ts
Normal file
66
src/main-chat.ts
Normal file
|
@ -0,0 +1,66 @@
|
|||
import net from 'net';
|
||||
import Communicator from './communicator';
|
||||
|
||||
import GenericServiceControls from "./services/0x01-GenericServiceControls";
|
||||
import LocationServices from "./services/0x02-LocationSerices";
|
||||
import BuddyListManagement from "./services/0x03-BuddyListManagement";
|
||||
import ICBM from "./services/0x04-ICBM";
|
||||
import Invitation from "./services/0x06-Invitation";
|
||||
import Administration from "./services/0x07-Administration";
|
||||
import Popups from "./services/0x08-Popups";
|
||||
import PrivacyManagement from "./services/0x09-PrivacyManagement";
|
||||
import UserLookup from "./services/0x0a-UserLookup";
|
||||
import UsageStats from "./services/0x0b-UsageStats";
|
||||
import ChatNavigation from "./services/0x0d-ChatNavigation";
|
||||
import Chat from "./services/0x0e-Chat";;
|
||||
import DirectorySearch from "./services/0x0f-DirectorySearch";
|
||||
import ServerStoredBuddyIcons from "./services/0x10-ServerStoredBuddyIcons";
|
||||
import SSI from "./services/0x13-SSI";
|
||||
|
||||
const server = net.createServer((socket) => {
|
||||
console.log('client connected...');
|
||||
socket.setTimeout(5 * 60 * 1000); // 5 minute timeout
|
||||
|
||||
socket.on('error', (e) => {
|
||||
console.error('socket encountered an error:', e);
|
||||
socket.end();
|
||||
});
|
||||
|
||||
socket.on('timeout', () => {
|
||||
console.log('socket timeout');
|
||||
socket.end();
|
||||
});
|
||||
|
||||
socket.on('end', () => {
|
||||
console.log('client disconnected...');
|
||||
});
|
||||
|
||||
const comm = new Communicator(socket);
|
||||
const services = [
|
||||
new GenericServiceControls(comm),
|
||||
new LocationServices(comm),
|
||||
new BuddyListManagement(comm),
|
||||
new ICBM(comm),
|
||||
new Invitation(comm),
|
||||
new Administration(comm),
|
||||
new Popups(comm),
|
||||
new PrivacyManagement(comm),
|
||||
new UserLookup(comm),
|
||||
new UsageStats(comm),
|
||||
new ChatNavigation(comm),
|
||||
new Chat(comm),
|
||||
new DirectorySearch(comm),
|
||||
new ServerStoredBuddyIcons(comm),
|
||||
new SSI(comm),
|
||||
];
|
||||
comm.registerServices(services);
|
||||
comm.startListening();
|
||||
});
|
||||
|
||||
server.on('error', (err) => {
|
||||
throw err;
|
||||
});
|
||||
|
||||
server.listen(5191, () => {
|
||||
console.log('CHAT ready on :5191');
|
||||
});
|
|
@ -1,7 +1,7 @@
|
|||
import BaseService from './base';
|
||||
import Communicator from '../communicator';
|
||||
import { FLAP, Rate, RateClass, RatedServiceGroup, RateGroupPair, SNAC, TLV } from '../structures';
|
||||
import { FLAGS_EMPTY, USER_STATUS_VARIOUS, USER_STATUS } from '../consts';
|
||||
import { USER_STATUS_VARIOUS, USER_STATUS } from '../consts';
|
||||
import { char, word, dword, dot2num } from '../structures/bytes';
|
||||
|
||||
export default class GenericServiceControls extends BaseService {
|
||||
|
@ -31,8 +31,8 @@ export default class GenericServiceControls extends BaseService {
|
|||
}
|
||||
|
||||
if (message.payload.subtype === 0x06) { // Client ask server for rate limits info
|
||||
const resp = new FLAP(0x02, this._getNewSequenceNumber(),
|
||||
SNAC.forRateClass(0x01, 0x07, FLAGS_EMPTY, 0, [
|
||||
const resp = new FLAP(0x02, this.nextReqID,
|
||||
SNAC.forRateClass(0x01, 0x07, [
|
||||
new Rate(
|
||||
new RateClass(1, 80, 2500, 2000, 1500, 800, 3400 /*fake*/, 6000, 0, 0),
|
||||
new RatedServiceGroup(1, [new RateGroupPair(0x00, 0x00)])
|
||||
|
@ -40,8 +40,8 @@ export default class GenericServiceControls extends BaseService {
|
|||
]))
|
||||
this.send(resp);
|
||||
|
||||
const motd = new FLAP(0x02, this._getNewSequenceNumber(),
|
||||
new SNAC(0x01, 0x13, FLAGS_EMPTY, 0, Buffer.concat([
|
||||
const motd = new FLAP(0x02, this.nextReqID,
|
||||
new SNAC(0x01, 0x13, Buffer.concat([
|
||||
word(0x0004),
|
||||
(new TLV(0x0B, Buffer.from("Hello world!"))).toBuffer(),
|
||||
])))
|
||||
|
@ -85,8 +85,8 @@ export default class GenericServiceControls extends BaseService {
|
|||
|
||||
const buf = Buffer.concat([payloadHeader, ...tlvs.map((tlv) => tlv.toBuffer())])
|
||||
|
||||
const resp = new FLAP(0x02, this._getNewSequenceNumber(),
|
||||
new SNAC(0x01, 0x0f, FLAGS_EMPTY, 0, buf));
|
||||
const resp = new FLAP(0x02, this.nextReqID,
|
||||
new SNAC(0x01, 0x0f, buf));
|
||||
|
||||
this.send(resp);
|
||||
return;
|
||||
|
@ -97,8 +97,8 @@ export default class GenericServiceControls extends BaseService {
|
|||
Object.values(this.communicator.services).forEach((subtype) => {
|
||||
serviceVersions.push(Buffer.from([0x00, subtype.service, 0x00, subtype.version]));
|
||||
});
|
||||
const resp = new FLAP(0x02, this._getNewSequenceNumber(),
|
||||
new SNAC(0x01, 0x18, FLAGS_EMPTY, 0, Buffer.concat(serviceVersions)));
|
||||
const resp = new FLAP(0x02, this.nextReqID,
|
||||
new SNAC(0x01, 0x18, Buffer.concat(serviceVersions)));
|
||||
this.send(resp);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import Communicator from '../communicator';
|
|||
|
||||
import { FLAP, SNAC, TLV } from '../structures';
|
||||
import { char, word, dword, dot2num } from '../structures/bytes';
|
||||
import { FLAGS_EMPTY, USER_STATUS, USER_STATUS_VARIOUS } from '../consts';
|
||||
import { USER_STATUS, USER_STATUS_VARIOUS } from '../consts';
|
||||
|
||||
export default class LocationServices extends BaseService {
|
||||
constructor(communicator : Communicator) {
|
||||
|
@ -17,8 +17,8 @@ export default class LocationServices extends BaseService {
|
|||
|
||||
// request location service parameters and limitations
|
||||
if (message.payload.subtype === 0x02) {
|
||||
const resp = new FLAP(0x02, this._getNewSequenceNumber(),
|
||||
new SNAC(0x02,0x03, FLAGS_EMPTY, 0, [
|
||||
const resp = new FLAP(0x02, this.nextReqID,
|
||||
new SNAC(0x02,0x03, [
|
||||
new TLV(0x01, word(0x400)), // max profile length
|
||||
new TLV(0x02, word(0x10)), // max capabilities
|
||||
new TLV(0x03, word(0xA)), // unknown
|
||||
|
|
|
@ -16,8 +16,8 @@ export default class BuddyListManagement extends BaseService {
|
|||
}
|
||||
|
||||
if (message.payload.subtype === 0x02) {
|
||||
const resp = new FLAP(0x02, this._getNewSequenceNumber(),
|
||||
new SNAC(0x03, 0x03, FLAGS_EMPTY, 0, [
|
||||
const resp = new FLAP(0x02, this.nextReqID,
|
||||
new SNAC(0x03, 0x03, [
|
||||
new TLV(0x01, word(600)), // 600 max buddies
|
||||
new TLV(0x02, word(750)), // 750 max watchers
|
||||
new TLV(0x03, word(512)), // 512 max online notifications ?
|
||||
|
|
|
@ -17,7 +17,7 @@ interface ChannelSettings {
|
|||
|
||||
export default class ICBM extends BaseService {
|
||||
private channel : ChannelSettings = {
|
||||
channel: 2,
|
||||
channel: 0,
|
||||
messageFlags: 3,
|
||||
maxMessageSnacSize: 512,
|
||||
maxSenderWarningLevel: 999,
|
||||
|
@ -26,6 +26,8 @@ export default class ICBM extends BaseService {
|
|||
unknown: 1000,
|
||||
};
|
||||
|
||||
private channels : ChannelSettings[] = [];
|
||||
|
||||
constructor(communicator : Communicator) {
|
||||
super({service: 0x04, version: 0x01}, communicator)
|
||||
}
|
||||
|
@ -52,8 +54,12 @@ export default class ICBM extends BaseService {
|
|||
}
|
||||
|
||||
const payload = message.payload.payload;
|
||||
const channel = payload.readUInt16BE(0);
|
||||
|
||||
// TODO: set settings based on channel provided
|
||||
|
||||
this.channel = {
|
||||
channel: payload.readUInt16BE(0),
|
||||
channel,
|
||||
messageFlags: payload.readUInt32BE(2),
|
||||
maxMessageSnacSize: payload.readUInt16BE(6),
|
||||
maxSenderWarningLevel: payload.readUInt16BE(8),
|
||||
|
@ -79,8 +85,8 @@ export default class ICBM extends BaseService {
|
|||
// It's identical to the channel set request the client
|
||||
// sends earlier. Also the 3.x client sends a channel set request
|
||||
// so early
|
||||
const resp = new FLAP(0x02, this._getNewSequenceNumber(),
|
||||
new SNAC(0x04, 0x05, FLAGS_EMPTY, 0, payload));
|
||||
const resp = new FLAP(0x02, this.nextReqID,
|
||||
new SNAC(0x04, 0x05, payload));
|
||||
this.send(resp);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@ export default class PrivacyManagement extends BaseService {
|
|||
}
|
||||
|
||||
if (message.payload.subtype === 0x02) {
|
||||
const resp = new FLAP(0x02, this._getNewSequenceNumber(),
|
||||
new SNAC(0x09, 0x03, FLAGS_EMPTY, 0, [
|
||||
const resp = new FLAP(0x02, this.nextReqID,
|
||||
new SNAC(0x09, 0x03, [
|
||||
new TLV(0x01, word(200)), // max visible list size
|
||||
new TLV(0x02, word(200)) // max invisible list size
|
||||
]));
|
||||
|
|
|
@ -2,6 +2,7 @@ import crypto from 'crypto';
|
|||
import BaseService from './base';
|
||||
import Communicator, { User } from '../communicator';
|
||||
import { FLAP, SNAC, TLV, ErrorCode, TLVType } from '../structures';
|
||||
import { word } from '../structures/bytes';
|
||||
|
||||
const { AIM_MD5_STRING, FLAGS_EMPTY } = require('../consts');
|
||||
|
||||
|
@ -44,8 +45,8 @@ export default class AuthorizationRegistrationService extends BaseService {
|
|||
const username = userTLV.payload.toString('ascii');
|
||||
|
||||
if (!users[username]) {
|
||||
const authResp = new FLAP(2, this._getNewSequenceNumber(),
|
||||
new SNAC(0x17, 0x03, FLAGS_EMPTY, 0, [
|
||||
const authResp = new FLAP(2, this.nextReqID,
|
||||
new SNAC(0x17, 0x03, [
|
||||
TLV.forUsername(username), // username
|
||||
TLV.forError(ErrorCode.IncorrectNick) // incorrect nick/password
|
||||
]));
|
||||
|
@ -67,22 +68,25 @@ export default class AuthorizationRegistrationService extends BaseService {
|
|||
|
||||
if (digest !== (passwordHashTLV as TLV).payload.toString('hex')) {
|
||||
console.log('Invalid password for', username);
|
||||
const authResp = new FLAP(2, this._getNewSequenceNumber(),
|
||||
new SNAC(0x17, 0x03, FLAGS_EMPTY, 0, [
|
||||
const authResp = new FLAP(2, this.nextReqID,
|
||||
new SNAC(0x17, 0x03, [
|
||||
TLV.forUsername(username), // username
|
||||
TLV.forError(ErrorCode.IncorrectNick) // incorrect nick/password
|
||||
]));
|
||||
this.send(authResp);
|
||||
|
||||
// Close this connection
|
||||
const plsLeave = new FLAP(4, this.nextReqID, Buffer.from([]));
|
||||
this.send(plsLeave);
|
||||
return;
|
||||
}
|
||||
|
||||
const host = this.communicator.socket.localAddress.split(':').pop();
|
||||
const port = this.communicator.socket.localPort;
|
||||
const chatHost = this.communicator.socket.localAddress.split(':').pop() + ':5191';
|
||||
|
||||
const authResp = new FLAP(2, this._getNewSequenceNumber(),
|
||||
new SNAC(0x17, 0x03, FLAGS_EMPTY, 0, [
|
||||
const authResp = new FLAP(2, this.nextReqID,
|
||||
new SNAC(0x17, 0x03, [
|
||||
TLV.forUsername(username), // username
|
||||
TLV.forBOSAddress(`${host}:${port}`), // BOS address
|
||||
TLV.forBOSAddress(chatHost), // BOS address
|
||||
TLV.forCookie(JSON.stringify({cookie: 'uwu', user: 'toof'})) // Authorization cookie
|
||||
]));
|
||||
|
||||
|
@ -93,8 +97,8 @@ export default class AuthorizationRegistrationService extends BaseService {
|
|||
case 0x06: // Request md5 authkey
|
||||
const MD5AuthKeyHeader = Buffer.alloc(2, 0xFF, 'hex');
|
||||
MD5AuthKeyHeader.writeUInt16BE(this.cipher.length);
|
||||
const md5ReqResp = new FLAP(2, this._getNewSequenceNumber(),
|
||||
new SNAC(0x17, 0x07, FLAGS_EMPTY, 0,
|
||||
const md5ReqResp = new FLAP(2, this.nextReqID,
|
||||
new SNAC(0x17, 0x07,
|
||||
Buffer.concat([MD5AuthKeyHeader, Buffer.from(this.cipher, 'binary')]),
|
||||
));
|
||||
this.send(md5ReqResp);
|
||||
|
|
|
@ -6,7 +6,7 @@ interface ServiceFamilyVersion {
|
|||
version : number,
|
||||
}
|
||||
|
||||
export default class BaseService {
|
||||
export default abstract class BaseService {
|
||||
public service : number;
|
||||
public version : number;
|
||||
|
||||
|
@ -20,8 +20,8 @@ export default class BaseService {
|
|||
this.communicator.send(message);
|
||||
}
|
||||
|
||||
_getNewSequenceNumber() {
|
||||
return this.communicator._getNewSequenceNumber();
|
||||
get nextReqID() {
|
||||
return this.communicator.nextReqID;
|
||||
}
|
||||
|
||||
handleMessage(message : FLAP) : void {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import assert from "assert";
|
||||
import { FLAGS_EMPTY } from "../consts";
|
||||
import { TLV } from "./TLV";
|
||||
|
||||
export class RateClass {
|
||||
|
@ -60,13 +61,16 @@ export class Rate {
|
|||
}
|
||||
}
|
||||
|
||||
let snacID = 0x2000;
|
||||
|
||||
export class SNAC {
|
||||
constructor(public service : number, public subtype : number, public flags : Buffer, public requestID : number , public payload : (TLV[] | Buffer) = Buffer.alloc(0)) {
|
||||
constructor(public service : number, public subtype : number, public payload : (TLV[] | Buffer) = Buffer.alloc(0), public requestID : number = 0, public flags : Buffer = FLAGS_EMPTY) {
|
||||
this.service = service;
|
||||
this.subtype = subtype;
|
||||
this.flags = flags;
|
||||
this.requestID = requestID;
|
||||
this.payload = payload;
|
||||
|
||||
this.requestID = requestID || (snacID++);
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
static fromBuffer(buf : Buffer, payloadLength = 0) {
|
||||
|
@ -105,17 +109,17 @@ export class SNAC {
|
|||
}
|
||||
}
|
||||
|
||||
return new SNAC(service, subtype, flags, requestID, payload);
|
||||
return new SNAC(service, subtype, payload, requestID, flags);
|
||||
}
|
||||
|
||||
static forRateClass(service : number, subtype : number, flags : Buffer, requestID : number, rates : Rate[]) : SNAC {
|
||||
static forRateClass(service : number, subtype : number, rates : Rate[]) : SNAC {
|
||||
const payloadHeader = Buffer.alloc(2, 0x00);
|
||||
payloadHeader.writeUInt16BE(rates.length);
|
||||
|
||||
const payloadBody = rates.map((rateClass) => rateClass.toBuffer());
|
||||
const payload = Buffer.concat([payloadHeader, ...payloadBody]);
|
||||
|
||||
return new SNAC(service, subtype, flags, requestID, payload);
|
||||
return new SNAC(service, subtype, payload);
|
||||
}
|
||||
|
||||
toString() {
|
||||
|
|
|
@ -134,7 +134,7 @@ function bufferFromWebText(webtext : string) : Buffer {
|
|||
return Buffer.from(webtext.replace(/\s/g, ''), 'hex');
|
||||
}
|
||||
|
||||
const FLAPSpec = [
|
||||
const SNAC_01_0F = [
|
||||
byte("FLAP Header"),
|
||||
byte("Channel"),
|
||||
word("Sequence ID"),
|
||||
|
@ -189,5 +189,5 @@ const exampleWebText = ''+
|
|||
`
|
||||
|
||||
if (require.main === module) {
|
||||
printBuffer(bufferFromWebText(exampleWebText), FLAPSpec);
|
||||
printBuffer(bufferFromWebText(exampleWebText), SNAC_01_0F);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import {FLAGS_EMPTY} from "../src/consts";
|
|||
const tests = [
|
||||
() => {
|
||||
// Construct and test a CLI_AUTH_REQUEST
|
||||
const md5_auth_req = new FLAP(0x02, 0, new SNAC(0x17, 0x06, FLAGS_EMPTY, 0, [new TLV(0x01, Buffer.from("toof"))]));
|
||||
const md5_auth_req = new FLAP(0x02, 0, new SNAC(0x17, 0x06, [new TLV(0x01, Buffer.from("toof"))]));
|
||||
assert(md5_auth_req.channel === 2);
|
||||
assert(md5_auth_req.payload instanceof SNAC);
|
||||
assert(md5_auth_req.payload.service === 23);
|
||||
|
|
Loading…
Reference in a new issue