initial changes

This commit is contained in:
2021-03-03 11:07:02 -06:00
parent 077d2a373a
commit 387cdf3b96
15 changed files with 1897 additions and 49 deletions

253
src/networking/packet.js Normal file
View File

@@ -0,0 +1,253 @@
import {randomBytes} from 'crypto';
import {Int64BE, Uint64BE} from 'int64-buffer';
import {sha256} from 'js-sha256';
import {TextEncoder} from 'text-encoding';
import {
be_ui8_array_to_i16,
be_ui8_array_to_i32,
be_ui8_array_to_ui16,
be_ui8_array_to_ui32,
i16_to_be_ui8_array,
i32_to_be_ui8_array,
i8_to_ui8_array,
ui16_to_be_ui8_array,
ui32_to_be_ui8_array,
ui8_array_to_i8,
ui8_array_to_ui8,
ui8_to_ui8_array,
} from '../utils/byte_order';
import JSChaCha20 from '../utils/jschacha20';
export default class packet {
constructor(token) { this.token = token; }
static HEADER = new TextEncoder().encode('repertory');
buffer = null;
decode_offset = 0;
token;
append_buffer = buffer => {
if (!(buffer instanceof Uint8Array)) {
throw new Error('Buffer must be of type Uint8Array');
}
this.buffer =
this.buffer ? new Uint8Array([...this.buffer, ...buffer ]) : buffer;
};
clear = () => {
this.buffer = null;
this.decode_offset = 0;
};
decode_buffer = length => {
if (!this.buffer) {
throw new Error('Invalid buffer');
}
const ret =
this.buffer.slice(this.decode_offset, this.decode_offset + length);
this.decode_offset += length;
return Buffer.from(ret);
};
decode_stat = () => {
const mode = this.decode_ui16();
const nlink = this.decode_ui16();
const uid = this.decode_ui32();
const gid = this.decode_ui32();
const atime = this.decode_ui64();
const mtime = this.decode_ui64();
const ctime = this.decode_ui64();
const birth_time = this.decode_ui64();
const size = this.decode_ui64();
const blocks = this.decode_ui64();
const blksize = this.decode_ui32();
const flags = this.decode_ui32();
const directory = !!this.decode_ui8();
return {
mode, nlink, uid, gid, atime, mtime, ctime, birth_time, size, blocks,
blksize, flags, directory,
}
};
decode_utf8 = () => {
if (!this.buffer) {
throw new Error('Invalid buffer');
}
const startIndex = this.decode_offset;
const endIndex = this.buffer.indexOf(0, startIndex);
if (endIndex >= 0) {
let ret = '';
for (let i = startIndex; i < endIndex; i++) {
ret += String.fromCharCode(this.buffer[i]);
}
this.decode_offset = endIndex + 1;
return ret;
}
throw new Error('String not found in buffer');
};
decode_i8 =
() => { return ui8_array_to_i8(this.buffer, this.decode_offset++); };
decode_ui8 =
() => { return ui8_array_to_ui8(this.buffer, this.decode_offset++); };
decode_i16 = () => {
const ret = be_ui8_array_to_i16(this.buffer, this.decode_offset);
this.decode_offset += 2;
return ret;
};
decode_ui16 = () => {
const ret = be_ui8_array_to_ui16(this.buffer, this.decode_offset);
this.decode_offset += 2;
return ret;
};
decode_i32 = () => {
const ret = be_ui8_array_to_i32(this.buffer, this.decode_offset);
this.decode_offset += 4;
return ret;
};
decode_ui32 = () => {
const ret = be_ui8_array_to_ui32(this.buffer, this.decode_offset);
this.decode_offset += 4;
return ret;
};
decode_i64 = () => {
const ret = new Int64BE(
this.buffer.slice(this.decode_offset, this.decode_offset + 8),
);
this.decode_offset += 8;
return ret.toString(10);
};
decode_ui64 = () => {
const ret = new Uint64BE(
this.buffer.slice(this.decode_offset, this.decode_offset + 8),
);
this.decode_offset += 8;
return ret.toString(10);
};
decrypt = async () => {
try {
const hash = sha256.create();
hash.update(new TextEncoder().encode(this.token));
const key = Uint8Array.from(hash.array());
const nonce = this.buffer.slice(0, 12);
this.buffer = new JSChaCha20(key, nonce, 0)
.decrypt(
this.buffer.slice(12),
);
this.decode_offset = packet.HEADER.length;
const header = this.buffer.slice(0, 9);
if (header.toString() !== packet.HEADER.toString()) {
return Promise.reject(new Error('Header does not match'));
}
return this.buffer;
} catch (e) {
return Promise.reject(e);
}
};
encode_buffer = buffer => { this.append_buffer(new Uint8Array(buffer)); };
encode_i8 = num => { this.append_buffer(i8_to_ui8_array(num)); };
encode_top_i8 = num => { this.push_buffer(i8_to_ui8_array(num)); };
encode_u8 = num => { this.append_buffer(ui8_to_ui8_array(num)); };
encode_top_u8 = num => { this.push_buffer(ui8_to_ui8_array(num)); };
encode_i16 = num => { this.append_buffer(i16_to_be_ui8_array(num)); };
encode_top_i16 = num => { this.push_buffer(i16_to_be_ui8_array(num)); };
encode_ui16 = num => { this.append_buffer(ui16_to_be_ui8_array(num)); };
encode_top_ui16 = num => { this.push_buffer(ui16_to_be_ui8_array(num)); };
encode_i32 = num => { this.append_buffer(i32_to_be_ui8_array(num)); };
encode_top_i32 = num => { this.push_buffer(i32_to_be_ui8_array(num)); };
encode_ui32 = num => { this.append_buffer(ui32_to_be_ui8_array(num)); };
encode_top_ui32 = num => { this.push_buffer(ui32_to_be_ui8_array(num)); };
encode_i64 = num => {
this.append_buffer(new Uint8Array(new Int64BE(num).toArray()));
};
encode_top_i64 =
num => { this.push_buffer(new Uint8Array(new Int64BE(num).toArray())); };
encode_ui64 = num => {
this.append_buffer(new Uint8Array(new Uint64BE(num).toArray()));
};
encode_top_ui64 =
num => { this.push_buffer(new Uint8Array(new Uint64BE(num).toArray())); };
encode_utf8 = str => {
if (!(typeof str === 'string' || str instanceof String)) {
throw new Error('Value must be of type string');
}
const buffer = new Uint8Array([...new TextEncoder().encode(str), 0 ]);
this.append_buffer(buffer);
};
encode_top_utf8 = str => {
if (!(typeof str === 'string' || str instanceof String)) {
throw new Error('Value must be of type string');
}
const buffer = new Uint8Array([...new TextEncoder().encode(str), 0 ]);
this.push_buffer(buffer);
};
encrypt = async nonce => {
try {
this.push_buffer(packet.HEADER);
const hash = sha256.create();
hash.update(new TextEncoder().encode(this.token));
const key = Uint8Array.from(hash.array());
if (!nonce) {
nonce = Uint8Array.from(randomBytes(12));
}
this.buffer = new JSChaCha20(key, nonce, 0).encrypt(this.buffer);
this.push_buffer(nonce);
return this.buffer;
} catch (e) {
return Promise.reject(e);
}
};
push_buffer = buffer => {
if (!(buffer instanceof Uint8Array)) {
throw new Error('Buffer must be of type Uint8Array');
}
this.buffer =
this.buffer ? new Uint8Array([...buffer, ...this.buffer ]) : buffer;
};
}