Update ESLint rules

parent 53e2a787
Pipeline #264 passed with stages
in 1 minute and 40 seconds
module.exports = {
extends: 'google',
parserOptions: {
ecmaVersion: 8,
sourceType: 'module',
},
rules: {
indent: ['error', 4],
camelcase: 'off',
'max-len': ['warn', {code: 120}],
'require-jsdoc': 'warn',
'arrow-parens': ['warn', 'as-needed'],
'space-before-function-paren': ['error', {anonymous: 'always', named: 'never'}],
},
};
---
parserOptions:
ecmaVersion: 8
sourceType: module
env:
node: true
extends:
- eslint:recommended
rules:
no-unused-vars: 'off'
no-console: 'off'
no-empty: 'off'
......@@ -10,6 +10,7 @@ cache:
- node_modules/
build:
stage: build
script:
- npm install
- npx gulp build
......@@ -20,3 +21,7 @@ build:
test:
script:
- npx qunit
lint:
script:
- npx qunit
import Session from './session';
import Message from './message';
import Property, { elementHeaderSize } from './property';
import Property, {elementHeaderSize} from './property';
// import { CFLBinaryPListParser } from './cflbinary';
export default class Client {
constructor(host, port, password) {
this.host = host;
this.port = port;
......@@ -51,7 +50,7 @@ export default class Client {
const replyHeader = await Message.parseRaw(reply);
console.debug('Reply:', {
reply, replyHeader
reply, replyHeader,
});
if (replyHeader.errorCode !== 0) {
......@@ -64,13 +63,9 @@ export default class Client {
while (true) {
const propHeader = await this.receivePropertyElementHeader();
console.debug('Received property element header:', propHeader);
const { name, flags, size } = await Property.parseRawElementHeader(propHeader);
console.debug('name', name);
console.debug('flags', flags);
console.debug('size', size);
const {name, flags, size} = await Property.parseRawElementHeader(propHeader);
const propData = await this.receive(size);
console.debug('prop data', propData);
if (flags & 1) {
const errorCode = Buffer.from(propData, 'binary').readInt32BE(0);
......@@ -94,7 +89,7 @@ export default class Client {
async setProperties(props) {
let payload = '';
for (let { name, prop } of props) {
for (let {prop} of props) {
console.debug('prop', prop);
payload += Property.composeRawElement(0, prop);
}
......@@ -111,16 +106,12 @@ export default class Client {
}
const propHeader = await this.receivePropertyElementHeader();
const { name, flags, size } = await Property.parseRawElementHeader(propHeader);
console.debug('name', name);
console.debug('flags', flags);
console.debug('size', size);
const {name, flags, size} = await Property.parseRawElementHeader(propHeader);
const propData = await this.receive(size);
console.debug('prop data', propData);
if (flags) {
const [errorCode] = Buffer.from(propData, 'binary').readUInt32BE(0);
const errorCode = Buffer.from(propData, 'binary').readUInt32BE(0);
console.log('error setting value for property', name, '-', errorCode);
return;
}
......@@ -128,8 +119,9 @@ export default class Client {
const prop = new Property(name, propData);
console.debug('prop', prop);
if (typeof prop.name === 'undefined' && typeof prop.value === 'undefined')
if (typeof prop.name === 'undefined' && typeof prop.value === 'undefined') {
console.debug('found empty prop end marker');
}
}
async getFeatures() {
......@@ -144,5 +136,4 @@ export default class Client {
const replyHeader = await Message.parseRaw(this.receiveMessageHeader());
return await this.receive(replyHeader.bodySize);
}
}
......@@ -10,7 +10,10 @@ export function generateACPKeystream(length) {
let key_idx = 0;
while (key_idx < length) {
key += String.fromCharCode((key_idx + 0x55 & 0xFF) ^ ACP_STATIC_KEY.charCodeAt(key_idx % ACP_STATIC_KEY.length));
key += String.fromCharCode(
(key_idx + 0x55 & 0xFF) ^
ACP_STATIC_KEY.charCodeAt(key_idx % ACP_STATIC_KEY.length)
);
key_idx++;
}
......
......@@ -3,7 +3,7 @@
* ACP message composition and parsing
*/
import { generateACPKeystream } from './keystream';
import {generateACPKeystream} from './keystream';
import adler32 from 'adler32';
/**
......@@ -29,7 +29,6 @@ export const headerMagic = 'acpp';
export const headerSize = 128;
export default class Message {
constructor(version, flags, unused, command, errorCode, key, body, bodySize) {
this.version = version;
this.flags = flags;
......@@ -65,7 +64,6 @@ export default class Message {
static unpackHeader(header_data) {
if (header_data.length !== headerSize) throw new Error('Header data must be 128 characters');
console.log('Unpacking header data', header_data);
const buffer = Buffer.from(header_data, 'binary');
const magic = buffer.slice(0, 4).toString();
......@@ -81,13 +79,10 @@ export default class Message {
const key = buffer.slice(48, 48 + 32).toString('binary');
const pad2 = buffer.slice(80, 80 + 48).toString('binary');
const unpacked = {packed: header_data, magic, version, header_checksum, body_checksum, body_size, flags, unused, command, error_code, key, pad1, pad2};
console.log('Unpacked', unpacked);
return unpacked;
return {magic, version, header_checksum, body_checksum, body_size, flags, unused, command, error_code, key, pad1, pad2};
}
static packHeader(header_data) {
console.log('Packing header data', header_data);
const {magic, version, header_checksum, body_checksum, body_size, flags, unused, command, error_code, key, pad1 = '', pad2 = ''} = header_data;
const buffer = Buffer.alloc(128);
......@@ -100,9 +95,9 @@ export default class Message {
buffer.writeInt32BE(unused, 24);
buffer.writeInt32BE(command, 28);
buffer.writeInt32BE(error_code, 32);
buffer.write(header_data.pad1 || ''.padEnd(12, '\u0000'), 36, 36 + 12, 'binary');
buffer.write(pad1 || ''.padEnd(12, '\u0000'), 36, 36 + 12, 'binary');
buffer.write(key, 48, 48 + 32, 'binary');
buffer.write(header_data.pad2 || ''.padEnd(48, '\u0000'), 80, 80 + 48, 'binary');
buffer.write(pad2 || ''.padEnd(48, '\u0000'), 80, 80 + 48, 'binary');
const packed = buffer.toString('binary');
console.log('Packed', packed);
......@@ -110,47 +105,55 @@ export default class Message {
}
static async parseRaw(data) {
if (headerSize > data.length)
if (headerSize > data.length) {
throw new Error(`Need to pass at least ${headerSize} bytes`);
}
const header_data = data.substr(0, headerSize);
const body_data = data.length > headerSize ? data.substr(headerSize) : undefined;
const {magic, version, header_checksum, body_checksum, body_size, flags, unused, command, error_code, key, pad1, pad2} = this.unpackHeader(header_data);
if (magic !== headerMagic)
if (magic !== headerMagic) {
throw new Error('Bad header magic');
}
const versions = [0x00000001, 0x00030001];
if (!versions.includes(version))
if (!versions.includes(version)) {
throw new Error('Unknown version ' + version);
}
const tmphdr = this.packHeader({
magic, version,
header_checksum: 0, body_checksum, body_size,
flags, unused, command, error_code, key,
pad1, pad2
pad1, pad2,
});
const expectedHeaderChecksum = adler32.sum(Buffer.from(tmphdr, 'binary'));
if (header_checksum !== expectedHeaderChecksum)
if (header_checksum !== expectedHeaderChecksum) {
throw new Error('Header checksum does not match');
}
if (body_data && body_size === -1)
if (body_data && body_size === -1) {
throw new Error('Cannot handle stream header with data attached');
}
if (body_data && body_size !== body_data.length)
if (body_data && body_size !== body_data.length) {
throw new Error('Message body size does not match available data');
}
if (body_data && body_checksum !== adler32.sum(Buffer.from(body_data, 'binary')))
if (body_data && body_checksum !== adler32.sum(Buffer.from(body_data, 'binary'))) {
throw new Error('Body checksum does not match');
}
// TODO: check flags
// TODO: check status
const commands = [1, 3, 4, 5, 6, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b];
if (!commands.includes(command))
if (!commands.includes(command)) {
throw new Error('Unknown command ' + command);
}
// TODO: check error code
......@@ -202,12 +205,12 @@ export default class Message {
return message.composeRawPacket();
}
static composeAuthCommand(flags, password, payload) {
static composeAuthCommand(flags, payload) {
const message = new Message(0x00030001, flags, 0, 0x1a, 0, generateACPHeaderKey(''), payload);
return message.composeRawPacket();
}
static composeFeatCommand(flags, password, payload) {
static composeFeatCommand(flags, payload) {
const message = new Message(0x00030001, flags, 0, 0x1b, 0, generateACPHeaderKey(''), payload);
return message.composeRawPacket();
}
......@@ -219,8 +222,8 @@ export default class Message {
composeRawPacket() {
let reply = this.composeHeader();
if (this.body)
reply += this.body;
if (this.body) reply += this.body;
return reply;
}
......@@ -229,13 +232,14 @@ export default class Message {
const tmphdr = this.constructor.packHeader({
magic: headerMagic, version: this.version,
header_checksum: 0, body_checksum: this.bodyChecksum, body_size: this.bodySize,
flags: this.flags, unused: this.unused, command: this.command, error_code: this.errorCode, key: this.key
flags: this.flags, unused: this.unused, command: this.command, error_code: this.errorCode, key: this.key,
});
const header = this.constructor.packHeader({
magic: headerMagic, version: this.version,
header_checksum: adler32.sum(Buffer.from(tmphdr, 'binary')), body_checksum: this.bodyChecksum, body_size: this.bodySize,
flags: this.flags, unused: this.unused, command: this.command, error_code: this.errorCode, key: this.key
header_checksum: adler32.sum(Buffer.from(tmphdr, 'binary')),
body_checksum: this.bodyChecksum, body_size: this.bodySize,
flags: this.flags, unused: this.unused, command: this.command, error_code: this.errorCode, key: this.key,
});
return header;
......@@ -248,5 +252,4 @@ export default class Message {
static get headerSize() {
return headerSize;
}
}
......@@ -541,5 +541,5 @@ export default [
// ['awce', '', '', undefined],
// ['wcgu', '', '', undefined],
// ['wcgs', '', '', undefined],
// ['awcc', '', '', undefined]
// ['awcc', '', '', undefined],
];
......@@ -3,14 +3,20 @@ import acpProperties from './properties';
export function generateACPProperties() {
const props = [];
for (let prop of acpProperties) {
const [name, type, description, validate] = prop;
if (name.length !== 4) throw new Error('Bad name in ACP properties list: ' + name);
const types = ['str', 'dec', 'hex', 'log', 'mac', 'cfb', 'bin'];
if (!types.includes(type)) throw new Error('Bad type in ACP properties list for name: ' + name + ' - ' + type);
if (!description) throw new Error('Missing description in ACP properties list for name: ' + name);
props.push({ name, type, description, validate });
props.push({name, type, description, validate});
}
return props;
}
......@@ -19,15 +25,15 @@ export const props = generateACPProperties();
export const elementHeaderSize = 12;
export default class Property {
constructor(name, value) {
if (name === '\x00\x00\x00\x00' && value === '\x00\x00\x00\x00') {
name = undefined;
value = undefined;
}
if (name && !this.constructor.getSupportedPropertyNames().includes(name))
if (name && !this.constructor.getSupportedPropertyNames().includes(name)) {
throw new Error('Invalid property name passed to Property constructor: ' + name);
}
if (value) {
const propType = this.constructor.getPropertyInfoString(name, 'type');
......@@ -42,8 +48,9 @@ export default class Property {
}
const validate = this.constructor.getPropertyInfoString(name, 'validate');
if (validate && !validate(value))
if (validate && !validate(value)) {
throw new Error('Invalid value passed to validator for property ' + name + ' - type: ' + typeof value);
}
}
this.name = name;
......@@ -74,9 +81,11 @@ export default class Property {
if (typeof value === 'string') {
if (value.length === 6) return value;
const macBytes = value.split(':');
if (macBytes.length === 6)
return ('').join(macBytes); // unhex
const mac_bytes = value.split(':');
if (mac_bytes.length === 6) {
return Buffer.from(''.join(mac_bytes), 'hex').toString('binary');
}
}
throw new Error('Invalid mac value: ' + value);
......@@ -182,7 +191,8 @@ export default class Property {
}
static async parseRawElement(data) {
const { name, flags, size } = await this.parseRawElementHeader(data.substr(0, elementHeaderSize));
// eslint-disable-next-line no-unused-vars
const {name, flags, size} = await this.parseRawElementHeader(data.substr(0, elementHeaderSize));
// TODO: handle flags
return new this(name, data.substr(elementHeaderSize));
}
......@@ -228,8 +238,9 @@ export default class Property {
}
static unpackHeader(header_data) {
if (header_data.length !== elementHeaderSize)
if (header_data.length !== elementHeaderSize) {
throw new Error('Header data must be 12 characters');
}
const buffer = Buffer.from(header_data, 'binary');
......@@ -239,5 +250,4 @@ export default class Property {
return {name, flags, size};
}
}
......@@ -3,7 +3,6 @@
import net from 'net';
export default class Session {
constructor(host, port, password) {
this.host = host;
this.port = port;
......@@ -22,7 +21,7 @@ export default class Session {
return new Promise((resolve, reject) => {
this.socket = new net.Socket();
const timeout = setTimeout(() => {
setTimeout(() => {
this.reading -= 1;
reject('Timeout');
}, _timeout);
......@@ -31,7 +30,7 @@ export default class Session {
console.log('Connected', err);
if (err) reject(err);
else resolve();
})
});
this.socket.on('close', had_error => {
this.socket = undefined;
......@@ -59,18 +58,21 @@ export default class Session {
data = await this.receiveSize(size, timeout);
if (this.decryptionMethod)
if (this.decryptionMethod) {
data = this.decryptionMethod(data);
}
return data;
}
send(data) {
if (!Buffer.isBuffer(data))
if (!Buffer.isBuffer(data)) {
data = Buffer.from(data, 'binary');
}
if (this.encryptionMethod)
if (this.encryptionMethod) {
data = this.encryptionMethod(data);
}
if (!this.socket) return;
......@@ -94,7 +96,6 @@ export default class Session {
return Promise.resolve(receivedChunks.join(''));
}
let updated = Date.now();
let timeout;
return new Promise((resolve, reject) => {
......@@ -142,12 +143,12 @@ export default class Session {
async receive(size, timeout = 10000) {
let data = await this.receiveSize(size, timeout);
if (this.decryptionMethod)
if (this.decryptionMethod) {
data = this.decryptionMethod(data);
}
return data;
}
}
export class ClientSession extends Session {
......
const {generateACPHeaderKey} = require('../dist/message');
const {generateACPKeystream, ACP_STATIC_KEY} = require('../dist/keystream');
const {generateACPKeystream} = require('../dist/keystream');
const QUnit = require('qunit');
......
const adler32 = require('adler32');
const {default: Client} = require('..');
const client = new Client('192.168.2.251', 5009, 'testing');
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment