-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathAirUnpacker.js
103 lines (102 loc) · 4.35 KB
/
AirUnpacker.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
const EncryptionLib = require('./encryption_test.js');
function AirUnpacker(inbuffer) {
//Turns a buffer into something like a readable stream.
this.buffer = inbuffer;
this.readerIndex = 0;
//readVariableLengthData (reads length and then the data)
this.getBuffer = function() {
return this.buffer;
}
this.setReaderIndex = function(newIndex) {
this.readerIndex = newIndex;
}
this.readInt = function() {
var readedInt = this.buffer.readUInt32BE(this.readerIndex);
this.readerIndex += 4;
return readedInt;
}
this.unpackInt = this.readInt;
this.readArrayHeader = this.readInt;
this.unpackArrayHeader = this.readArrayHeader;
this.readLong = function() { //THE FOLLOWING IS UNTESTED
var readedLong = this.buffer.readBigUInt64BE(this.readerIndex);
this.readerIndex += 8;
return Number(readedLong);
}
this.unpackLong = this.readLong;
this.readShort = function() { //THE FOLLOWING IS UNTESTED
var readedShort = this.buffer.readUInt16BE(this.readerIndex);
this.readerIndex += 2;
return readedShort;
}
this.unpackShort = this.readShort;
//TODO: ADD READ BOOLEAN
this.readBoolean = function() {
// var readedBool = this.buffer.slice(readerIndex, readerIndex + 1);
// readerIndex += 1;
var readedBoolAsInt = this.buffer.readInt8(this.readerIndex);
//Booleans are stored in a whole byte. We pretend it's an integer and check if it's 1 or 0
this.readerIndex += 1;
return (readedBoolAsInt == 1) ? true : false; //Returns true if the int is 1, otherwise returns false.
}
this.unpackBoolean = this.readBoolean;
this.readUTF8StringArray = function() { //THE FOLLOWING IS UNTESTED
var arrayLength = this.readInt();
var finalarr = [];
for (var i = 0; i < arrayLength; i++) {
var item = this.readVariableLengthUTF8String();
finalarr.push(item);
}
return finalarr;
}
this.unpackUTF8StringArray = this.readUTF8StringArray;
this.readUtf8String = function(length) {
var outputstr = this.buffer.toString('utf8',this.readerIndex, this.readerIndex + length);
this.readerIndex += length;
return outputstr;
}
this.unpackUtf8String = this.readUtf8String;
//TODO: Sort out the UTF8 string madness (Utf8 vs UTF8 vs just string)
this.readVariableLengthUTF8String = function() {
//Assumes there's an int length and the data immediately after
var length = this.readInt();
return this.readUtf8String(length);
}
this.unpackVariableLengthUTF8String = this.readVariableLengthUTF8String;
this.readString = this.readVariableLengthUTF8String;
this.unpackString = this.readVariableLengthUTF8String;
this.readBytes = function(length) {
var outputBuffer = this.buffer.slice(this.readerIndex, this.readerIndex + length);
this.readerIndex += length;
return outputBuffer;
};
this.unpackBytes = this.readBytes;
this.readPayload = function() {
var length = this.readInt();
return this.readBytes(length);
};
this.unpackPayload = this.readPayload;
this.readBytesToEnd = function() { //THE FOLLOWING IS UNTESTED
var outputBuffer = this.buffer.slice(this.readerIndex, this.buffer.length);
this.readerIndex = this.buffer.length;
return outputBuffer;
}
this.unpackBytesToEnd = this.readBytesToEnd;
this.readVariableLengthData = function() { //Change this to readVariableLengthBuffer?
var length = this.readInt();
return this.readBytes(length);
}
this.unpackVariableLengthData = this.readVariableLengthData;
this.decryptRestOfData = async function() {
var salt = this.readBytes(EncryptionLib.SALT_LENGTH);
var iv = this.readBytes(EncryptionLib.IV_LENGTH);
var encrypted = this.readBytesToEnd();
var decryptedData = await EncryptionLib.decryptWithSaltIVAndData(salt, iv, encrypted);
return Buffer.from(decryptedData);
}
//TODO: Function to read the rest of the data?
//TODO: Maybe build decryption into AirUnpacker?
}
//TODO: When packing a conversation and including the latest_text, make sure to deal with it if it's null!
// Maybe add a function that auto-puts something like "Unknown" if the value is null
module.exports = AirUnpacker;