bedrock-portal-nethernet 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +2 -0
- package/README.md +12 -0
- package/dist/datatypes/compiler-minecraft.d.ts +4 -0
- package/dist/datatypes/compiler-minecraft.js +224 -0
- package/dist/datatypes/minecraft.d.ts +15 -0
- package/dist/datatypes/minecraft.js +146 -0
- package/dist/datatypes/util.d.ts +7 -0
- package/dist/datatypes/util.js +53 -0
- package/dist/datatypes/varlong.d.ts +24 -0
- package/dist/datatypes/varlong.js +67 -0
- package/dist/handshake/constants.d.ts +1 -0
- package/dist/handshake/constants.js +4 -0
- package/dist/handshake/keyExchange.d.ts +2 -0
- package/dist/handshake/keyExchange.js +74 -0
- package/dist/handshake/loginVerify.d.ts +3 -0
- package/dist/handshake/loginVerify.js +65 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -0
- package/dist/nethernet/Connection.d.ts +22 -0
- package/dist/nethernet/Connection.js +127 -0
- package/dist/nethernet/Nethernet.d.ts +16 -0
- package/dist/nethernet/Nethernet.js +80 -0
- package/dist/options.d.ts +27 -0
- package/dist/options.js +44 -0
- package/dist/server.d.ts +36 -0
- package/dist/server.js +131 -0
- package/dist/serverPlayer.d.ts +78 -0
- package/dist/serverPlayer.js +275 -0
- package/dist/signaling/Signal.d.ts +23 -0
- package/dist/signaling/Signal.js +160 -0
- package/dist/signaling/struct.d.ts +23 -0
- package/dist/signaling/struct.js +51 -0
- package/dist/transforms/framer.d.ts +18 -0
- package/dist/transforms/framer.js +111 -0
- package/dist/transforms/serializer.d.ts +9 -0
- package/dist/transforms/serializer.js +74 -0
- package/dist/types/Item.d.ts +97 -0
- package/dist/types/Item.js +66 -0
- package/package.json +43 -0
package/.gitattributes
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# BedrockPortalNethernet
|
|
2
|
+
[](http://npmjs.com/package/bedrock-portal-nethernet)
|
|
3
|
+
[](https://discord.gg/KTyd9HWuBD)
|
|
4
|
+
|
|
5
|
+
A simple server implementation for the Bedrock Edition Nethernet protocol used by [BedrockPortal](https://github.com/LucienHH/bedrock-portal). Join our [Discord](https://discord.com/invite/KTyd9HWuBD) for support.
|
|
6
|
+
|
|
7
|
+
Based on bedrock-protocol but stripped down to only the necessary components for the Nethernet protocol.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
```shell
|
|
11
|
+
npm install bedrock-portal-nethernet
|
|
12
|
+
```
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
const UUID = require('uuid-1345');
|
|
4
|
+
const minecraft = require('./minecraft');
|
|
5
|
+
const { Read, Write, SizeOf } = require('./varlong');
|
|
6
|
+
/**
|
|
7
|
+
* UUIDs
|
|
8
|
+
*/
|
|
9
|
+
Read.uuid = ['native', (buffer, offset) => {
|
|
10
|
+
return {
|
|
11
|
+
value: UUID.stringify(buffer.slice(offset, 16 + offset)),
|
|
12
|
+
size: 16
|
|
13
|
+
};
|
|
14
|
+
}];
|
|
15
|
+
Write.uuid = ['native', (value, buffer, offset) => {
|
|
16
|
+
const buf = UUID.parse(value);
|
|
17
|
+
buf.copy(buffer, offset);
|
|
18
|
+
return offset + 16;
|
|
19
|
+
}];
|
|
20
|
+
SizeOf.uuid = ['native', 16];
|
|
21
|
+
/**
|
|
22
|
+
* Rest of buffer
|
|
23
|
+
*/
|
|
24
|
+
Read.restBuffer = ['native', (buffer, offset) => {
|
|
25
|
+
return {
|
|
26
|
+
value: buffer.slice(offset),
|
|
27
|
+
size: buffer.length - offset
|
|
28
|
+
};
|
|
29
|
+
}];
|
|
30
|
+
Write.restBuffer = ['native', (value, buffer, offset) => {
|
|
31
|
+
value.copy(buffer, offset);
|
|
32
|
+
return offset + value.length;
|
|
33
|
+
}];
|
|
34
|
+
SizeOf.restBuffer = ['native', (value) => {
|
|
35
|
+
return value.length;
|
|
36
|
+
}];
|
|
37
|
+
/**
|
|
38
|
+
* Encapsulated data with length prefix
|
|
39
|
+
*/
|
|
40
|
+
Read.encapsulated = ['parametrizable', (compiler, { lengthType, type }) => {
|
|
41
|
+
return compiler.wrapCode(`
|
|
42
|
+
const payloadSize = ${compiler.callType(lengthType, 'offset')}
|
|
43
|
+
const { value, size } = ctx.${type}(buffer, offset + payloadSize.size)
|
|
44
|
+
return { value, size: size + payloadSize.size }
|
|
45
|
+
`.trim());
|
|
46
|
+
}];
|
|
47
|
+
Write.encapsulated = ['parametrizable', (compiler, { lengthType, type }) => {
|
|
48
|
+
return compiler.wrapCode(`
|
|
49
|
+
const buf = Buffer.allocUnsafe(buffer.length - offset)
|
|
50
|
+
const payloadSize = (ctx.${type})(value, buf, 0)
|
|
51
|
+
let size = (ctx.${lengthType})(payloadSize, buffer, offset)
|
|
52
|
+
size += buf.copy(buffer, size, 0, payloadSize)
|
|
53
|
+
return size
|
|
54
|
+
`.trim());
|
|
55
|
+
}];
|
|
56
|
+
SizeOf.encapsulated = ['parametrizable', (compiler, { lengthType, type }) => {
|
|
57
|
+
return compiler.wrapCode(`
|
|
58
|
+
const payloadSize = (ctx.${type})(value)
|
|
59
|
+
return (ctx.${lengthType})(payloadSize) + payloadSize
|
|
60
|
+
`.trim());
|
|
61
|
+
}];
|
|
62
|
+
/**
|
|
63
|
+
* Read NBT until end of buffer or \0
|
|
64
|
+
*/
|
|
65
|
+
Read.nbtLoop = ['context', (buffer, offset) => {
|
|
66
|
+
const values = [];
|
|
67
|
+
while (buffer[offset] != 0) {
|
|
68
|
+
const n = ctx.nbt(buffer, offset);
|
|
69
|
+
values.push(n.value);
|
|
70
|
+
offset += n.size;
|
|
71
|
+
}
|
|
72
|
+
return { value: values, size: buffer.length - offset };
|
|
73
|
+
}];
|
|
74
|
+
Write.nbtLoop = ['context', (value, buffer, offset) => {
|
|
75
|
+
for (const val of value) {
|
|
76
|
+
offset = ctx.nbt(val, buffer, offset);
|
|
77
|
+
}
|
|
78
|
+
buffer.writeUint8(0, offset);
|
|
79
|
+
return offset + 1;
|
|
80
|
+
}];
|
|
81
|
+
SizeOf.nbtLoop = ['context', (value, buffer, offset) => {
|
|
82
|
+
let size = 1;
|
|
83
|
+
for (const val of value) {
|
|
84
|
+
size += ctx.nbt(val, buffer, offset);
|
|
85
|
+
}
|
|
86
|
+
return size;
|
|
87
|
+
}];
|
|
88
|
+
/**
|
|
89
|
+
* Read rotation float encoded as a byte
|
|
90
|
+
*/
|
|
91
|
+
Read.byterot = ['context', (buffer, offset) => {
|
|
92
|
+
const val = buffer.readUint8(offset);
|
|
93
|
+
return { value: (val * (360 / 256)), size: 1 };
|
|
94
|
+
}];
|
|
95
|
+
Write.byterot = ['context', (value, buffer, offset) => {
|
|
96
|
+
const val = (value / (360 / 256));
|
|
97
|
+
buffer.writeUint8(val, offset);
|
|
98
|
+
return offset + 1;
|
|
99
|
+
}];
|
|
100
|
+
SizeOf.byterot = ['context', (value, buffer, offset) => {
|
|
101
|
+
return 1;
|
|
102
|
+
}];
|
|
103
|
+
/**
|
|
104
|
+
* NBT
|
|
105
|
+
*/
|
|
106
|
+
Read.nbt = ['native', minecraft.nbt[0]];
|
|
107
|
+
Write.nbt = ['native', minecraft.nbt[1]];
|
|
108
|
+
SizeOf.nbt = ['native', minecraft.nbt[2]];
|
|
109
|
+
Read.lnbt = ['native', minecraft.lnbt[0]];
|
|
110
|
+
Write.lnbt = ['native', minecraft.lnbt[1]];
|
|
111
|
+
SizeOf.lnbt = ['native', minecraft.lnbt[2]];
|
|
112
|
+
/**
|
|
113
|
+
* Bits
|
|
114
|
+
*/
|
|
115
|
+
Read.bitflags = ['parametrizable', (compiler, { type, flags, shift, big }) => {
|
|
116
|
+
let fstr = JSON.stringify(flags);
|
|
117
|
+
if (Array.isArray(flags)) {
|
|
118
|
+
fstr = '{';
|
|
119
|
+
flags.map((v, k) => fstr += `"${v}": ${big ? 1n << BigInt(k) : 1 << k}` + (big ? 'n,' : ','));
|
|
120
|
+
fstr += '}';
|
|
121
|
+
}
|
|
122
|
+
else if (shift) {
|
|
123
|
+
fstr = '{';
|
|
124
|
+
for (const key in flags)
|
|
125
|
+
fstr += `"${key}": ${1 << flags[key]},`;
|
|
126
|
+
fstr += '}';
|
|
127
|
+
}
|
|
128
|
+
return compiler.wrapCode(`
|
|
129
|
+
const { value: _value, size } = ${compiler.callType(type, 'offset')}
|
|
130
|
+
const value = { _value }
|
|
131
|
+
const flags = ${fstr}
|
|
132
|
+
for (const key in flags) {
|
|
133
|
+
value[key] = (_value & flags[key]) == flags[key]
|
|
134
|
+
}
|
|
135
|
+
return { value, size }
|
|
136
|
+
`.trim());
|
|
137
|
+
}];
|
|
138
|
+
Write.bitflags = ['parametrizable', (compiler, { type, flags, shift, big }) => {
|
|
139
|
+
let fstr = JSON.stringify(flags);
|
|
140
|
+
if (Array.isArray(flags)) {
|
|
141
|
+
fstr = '{';
|
|
142
|
+
flags.map((v, k) => fstr += `"${v}": ${big ? 1n << BigInt(k) : 1 << k}` + (big ? 'n,' : ','));
|
|
143
|
+
fstr += '}';
|
|
144
|
+
}
|
|
145
|
+
else if (shift) {
|
|
146
|
+
fstr = '{';
|
|
147
|
+
for (const key in flags)
|
|
148
|
+
fstr += `"${key}": ${1 << flags[key]},`;
|
|
149
|
+
fstr += '}';
|
|
150
|
+
}
|
|
151
|
+
return compiler.wrapCode(`
|
|
152
|
+
const flags = ${fstr}
|
|
153
|
+
let val = value._value ${big ? '|| 0n' : ''}
|
|
154
|
+
for (const key in flags) {
|
|
155
|
+
if (value[key]) val |= flags[key]
|
|
156
|
+
}
|
|
157
|
+
return (ctx.${type})(val, buffer, offset)
|
|
158
|
+
`.trim());
|
|
159
|
+
}];
|
|
160
|
+
SizeOf.bitflags = ['parametrizable', (compiler, { type, flags, shift, big }) => {
|
|
161
|
+
let fstr = JSON.stringify(flags);
|
|
162
|
+
if (Array.isArray(flags)) {
|
|
163
|
+
fstr = '{';
|
|
164
|
+
flags.map((v, k) => fstr += `"${v}": ${big ? 1n << BigInt(k) : 1 << k}` + (big ? 'n,' : ','));
|
|
165
|
+
fstr += '}';
|
|
166
|
+
}
|
|
167
|
+
else if (shift) {
|
|
168
|
+
fstr = '{';
|
|
169
|
+
for (const key in flags)
|
|
170
|
+
fstr += `"${key}": ${1 << flags[key]},`;
|
|
171
|
+
fstr += '}';
|
|
172
|
+
}
|
|
173
|
+
return compiler.wrapCode(`
|
|
174
|
+
const flags = ${fstr}
|
|
175
|
+
let val = value._value ${big ? '|| 0n' : ''}
|
|
176
|
+
for (const key in flags) {
|
|
177
|
+
if (value[key]) val |= flags[key]
|
|
178
|
+
}
|
|
179
|
+
return (ctx.${type})(val)
|
|
180
|
+
`.trim());
|
|
181
|
+
}];
|
|
182
|
+
/**
|
|
183
|
+
* Command Packet
|
|
184
|
+
* - used for determining the size of the following enum
|
|
185
|
+
*/
|
|
186
|
+
Read.enum_size_based_on_values_len = ['parametrizable', (compiler) => {
|
|
187
|
+
return compiler.wrapCode(js(() => {
|
|
188
|
+
if (values_len <= 0xff)
|
|
189
|
+
return { value: 'byte', size: 0 };
|
|
190
|
+
if (values_len <= 0xffff)
|
|
191
|
+
return { value: 'short', size: 0 };
|
|
192
|
+
if (values_len <= 0xffffff)
|
|
193
|
+
return { value: 'int', size: 0 };
|
|
194
|
+
}));
|
|
195
|
+
}];
|
|
196
|
+
Write.enum_size_based_on_values_len = ['parametrizable', (compiler) => {
|
|
197
|
+
return str(() => {
|
|
198
|
+
if (value.values_len <= 0xff)
|
|
199
|
+
_enum_type = 'byte';
|
|
200
|
+
else if (value.values_len <= 0xffff)
|
|
201
|
+
_enum_type = 'short';
|
|
202
|
+
else if (value.values_len <= 0xffffff)
|
|
203
|
+
_enum_type = 'int';
|
|
204
|
+
return offset;
|
|
205
|
+
});
|
|
206
|
+
}];
|
|
207
|
+
SizeOf.enum_size_based_on_values_len = ['parametrizable', (compiler) => {
|
|
208
|
+
return str(() => {
|
|
209
|
+
if (value.values_len <= 0xff)
|
|
210
|
+
_enum_type = 'byte';
|
|
211
|
+
else if (value.values_len <= 0xffff)
|
|
212
|
+
_enum_type = 'short';
|
|
213
|
+
else if (value.values_len <= 0xffffff)
|
|
214
|
+
_enum_type = 'int';
|
|
215
|
+
return 0;
|
|
216
|
+
});
|
|
217
|
+
}];
|
|
218
|
+
function js(fn) {
|
|
219
|
+
return fn.toString().split('\n').slice(1, -1).join('\n').trim();
|
|
220
|
+
}
|
|
221
|
+
function str(fn) {
|
|
222
|
+
return fn.toString() + ')();(()=>{}';
|
|
223
|
+
}
|
|
224
|
+
module.exports = { Read, Write, SizeOf };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
declare function writeUUID(value: any, buffer: any, offset: any): any;
|
|
2
|
+
declare function writeNbt(value: any, buffer: any, offset: any): any;
|
|
3
|
+
declare function writeNbtLE(value: any, buffer: any, offset: any): any;
|
|
4
|
+
declare function writeEntityMetadata(value: any, buffer: any, offset: any, _ref2: any): any;
|
|
5
|
+
declare function writeIpAddress(value: any, buffer: any, offset: any): any;
|
|
6
|
+
declare function writeEndOfArray(value: any, buffer: any, offset: any, typeArgs: any): any;
|
|
7
|
+
export let uuid: (number | typeof writeUUID)[];
|
|
8
|
+
export let nbt: (typeof writeNbt)[];
|
|
9
|
+
export let lnbt: (typeof writeNbtLE)[];
|
|
10
|
+
export let entityMetadataLoop: (typeof writeEntityMetadata)[];
|
|
11
|
+
export let ipAddress: (number | typeof writeIpAddress)[];
|
|
12
|
+
export let endOfArray: (typeof writeEndOfArray)[];
|
|
13
|
+
export let zigzag32: any;
|
|
14
|
+
export let zigzag64: any;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
const nbt = require('prismarine-nbt');
|
|
4
|
+
const UUID = require('uuid-1345');
|
|
5
|
+
const protoLE = nbt.protos.little;
|
|
6
|
+
const protoLEV = nbt.protos.littleVarint;
|
|
7
|
+
// TODO: deal with this:
|
|
8
|
+
const zigzag = require('prismarine-nbt/zigzag');
|
|
9
|
+
function readUUID(buffer, offset) {
|
|
10
|
+
if (offset + 16 > buffer.length) {
|
|
11
|
+
throw new PartialReadError();
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
value: UUID.stringify(buffer.slice(offset, 16 + offset)),
|
|
15
|
+
size: 16
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function writeUUID(value, buffer, offset) {
|
|
19
|
+
const buf = UUID.parse(value);
|
|
20
|
+
buf.copy(buffer, offset);
|
|
21
|
+
return offset + 16;
|
|
22
|
+
}
|
|
23
|
+
// Little Endian + varints
|
|
24
|
+
function readNbt(buffer, offset) {
|
|
25
|
+
return protoLEV.read(buffer, offset, 'nbt');
|
|
26
|
+
}
|
|
27
|
+
function writeNbt(value, buffer, offset) {
|
|
28
|
+
return protoLEV.write(value, buffer, offset, 'nbt');
|
|
29
|
+
}
|
|
30
|
+
function sizeOfNbt(value) {
|
|
31
|
+
return protoLEV.sizeOf(value, 'nbt');
|
|
32
|
+
}
|
|
33
|
+
// Little Endian
|
|
34
|
+
function readNbtLE(buffer, offset) {
|
|
35
|
+
const r = protoLE.read(buffer, offset, 'nbt');
|
|
36
|
+
// End size is 3 for some reason
|
|
37
|
+
if (r.value.type === 'end')
|
|
38
|
+
return { value: r.value, size: 1 };
|
|
39
|
+
return r;
|
|
40
|
+
}
|
|
41
|
+
function writeNbtLE(value, buffer, offset) {
|
|
42
|
+
if (value.type === 'end') {
|
|
43
|
+
buffer.writeInt8(0, offset);
|
|
44
|
+
return offset + 1;
|
|
45
|
+
}
|
|
46
|
+
return protoLE.write(value, buffer, offset, 'nbt');
|
|
47
|
+
}
|
|
48
|
+
function sizeOfNbtLE(value) {
|
|
49
|
+
if (value.type === 'end')
|
|
50
|
+
return 1;
|
|
51
|
+
return protoLE.sizeOf(value, 'nbt');
|
|
52
|
+
}
|
|
53
|
+
function readEntityMetadata(buffer, offset, _ref) {
|
|
54
|
+
const type = _ref.type;
|
|
55
|
+
const endVal = _ref.endVal;
|
|
56
|
+
let cursor = offset;
|
|
57
|
+
const metadata = [];
|
|
58
|
+
let item;
|
|
59
|
+
while (true) {
|
|
60
|
+
if (offset + 1 > buffer.length)
|
|
61
|
+
throw new PartialReadError();
|
|
62
|
+
item = buffer.readUInt8(cursor);
|
|
63
|
+
if (item === endVal) {
|
|
64
|
+
return {
|
|
65
|
+
value: metadata,
|
|
66
|
+
size: cursor + 1 - offset
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const results = this.read(buffer, cursor, type, {});
|
|
70
|
+
metadata.push(results.value);
|
|
71
|
+
cursor += results.size;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function writeEntityMetadata(value, buffer, offset, _ref2) {
|
|
75
|
+
const type = _ref2.type;
|
|
76
|
+
const endVal = _ref2.endVal;
|
|
77
|
+
const self = this;
|
|
78
|
+
value.forEach(function (item) {
|
|
79
|
+
offset = self.write(item, buffer, offset, type, {});
|
|
80
|
+
});
|
|
81
|
+
buffer.writeUInt8(endVal, offset);
|
|
82
|
+
return offset + 1;
|
|
83
|
+
}
|
|
84
|
+
function sizeOfEntityMetadata(value, _ref3) {
|
|
85
|
+
const type = _ref3.type;
|
|
86
|
+
let size = 1;
|
|
87
|
+
for (let i = 0; i < value.length; ++i) {
|
|
88
|
+
size += this.sizeOf(value[i], type, {});
|
|
89
|
+
}
|
|
90
|
+
return size;
|
|
91
|
+
}
|
|
92
|
+
function readIpAddress(buffer, offset) {
|
|
93
|
+
const address = buffer[offset] + '.' + buffer[offset + 1] + '.' + buffer[offset + 2] + '.' + buffer[offset + 3];
|
|
94
|
+
return {
|
|
95
|
+
size: 4,
|
|
96
|
+
value: address
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function writeIpAddress(value, buffer, offset) {
|
|
100
|
+
const address = value.split('.');
|
|
101
|
+
address.forEach(function (b) {
|
|
102
|
+
buffer[offset] = parseInt(b);
|
|
103
|
+
offset++;
|
|
104
|
+
});
|
|
105
|
+
return offset;
|
|
106
|
+
}
|
|
107
|
+
function readEndOfArray(buffer, offset, typeArgs) {
|
|
108
|
+
const type = typeArgs.type;
|
|
109
|
+
let cursor = offset;
|
|
110
|
+
const elements = [];
|
|
111
|
+
while (cursor < buffer.length) {
|
|
112
|
+
const results = this.read(buffer, cursor, type, {});
|
|
113
|
+
elements.push(results.value);
|
|
114
|
+
cursor += results.size;
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
value: elements,
|
|
118
|
+
size: cursor - offset
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function writeEndOfArray(value, buffer, offset, typeArgs) {
|
|
122
|
+
const type = typeArgs.type;
|
|
123
|
+
const self = this;
|
|
124
|
+
value.forEach(function (item) {
|
|
125
|
+
offset = self.write(item, buffer, offset, type, {});
|
|
126
|
+
});
|
|
127
|
+
return offset;
|
|
128
|
+
}
|
|
129
|
+
function sizeOfEndOfArray(value, typeArgs) {
|
|
130
|
+
const type = typeArgs.type;
|
|
131
|
+
let size = 0;
|
|
132
|
+
for (let i = 0; i < value.length; ++i) {
|
|
133
|
+
size += this.sizeOf(value[i], type, {});
|
|
134
|
+
}
|
|
135
|
+
return size;
|
|
136
|
+
}
|
|
137
|
+
module.exports = {
|
|
138
|
+
uuid: [readUUID, writeUUID, 16],
|
|
139
|
+
nbt: [readNbt, writeNbt, sizeOfNbt],
|
|
140
|
+
lnbt: [readNbtLE, writeNbtLE, sizeOfNbtLE],
|
|
141
|
+
entityMetadataLoop: [readEntityMetadata, writeEntityMetadata, sizeOfEntityMetadata],
|
|
142
|
+
ipAddress: [readIpAddress, writeIpAddress, 4],
|
|
143
|
+
endOfArray: [readEndOfArray, writeEndOfArray, sizeOfEndOfArray],
|
|
144
|
+
zigzag32: zigzag.interpret.zigzag32,
|
|
145
|
+
zigzag64: zigzag.interpret.zigzag64
|
|
146
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function getFiles(dir: string): string[];
|
|
2
|
+
export declare function sleep(ms: number): Promise<unknown>;
|
|
3
|
+
export declare function waitFor(cb: (resolve: (value?: any) => void, reject: (reason?: any) => void) => void, withTimeout: number, onTimeout: () => Promise<void>): Promise<unknown>;
|
|
4
|
+
export declare function serialize(obj?: {}, fmt?: string | number): string;
|
|
5
|
+
export declare function uuidFrom(string: string): string;
|
|
6
|
+
export declare function nextUUID(): string;
|
|
7
|
+
export declare const isDebug: boolean | undefined;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.isDebug = void 0;
|
|
7
|
+
exports.getFiles = getFiles;
|
|
8
|
+
exports.sleep = sleep;
|
|
9
|
+
exports.waitFor = waitFor;
|
|
10
|
+
exports.serialize = serialize;
|
|
11
|
+
exports.uuidFrom = uuidFrom;
|
|
12
|
+
exports.nextUUID = nextUUID;
|
|
13
|
+
const fs_1 = __importDefault(require("fs"));
|
|
14
|
+
const uuid_1345_1 = __importDefault(require("uuid-1345"));
|
|
15
|
+
function getFiles(dir) {
|
|
16
|
+
let results = [];
|
|
17
|
+
const list = fs_1.default.readdirSync(dir);
|
|
18
|
+
list.forEach((file) => {
|
|
19
|
+
file = dir + '/' + file;
|
|
20
|
+
const stat = fs_1.default.statSync(file);
|
|
21
|
+
if (stat && stat.isDirectory()) {
|
|
22
|
+
results = results.concat(getFiles(file));
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
results.push(file);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
return results;
|
|
29
|
+
}
|
|
30
|
+
function sleep(ms) {
|
|
31
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
32
|
+
}
|
|
33
|
+
async function waitFor(cb, withTimeout, onTimeout) {
|
|
34
|
+
let t;
|
|
35
|
+
const ret = await Promise.race([
|
|
36
|
+
new Promise((resolve, reject) => cb(resolve, reject)),
|
|
37
|
+
new Promise(resolve => { t = setTimeout(() => resolve('timeout'), withTimeout); }),
|
|
38
|
+
]);
|
|
39
|
+
clearTimeout(t);
|
|
40
|
+
if (ret === 'timeout')
|
|
41
|
+
await onTimeout();
|
|
42
|
+
return ret;
|
|
43
|
+
}
|
|
44
|
+
function serialize(obj = {}, fmt) {
|
|
45
|
+
return JSON.stringify(obj, (k, v) => typeof v === 'bigint' ? v.toString() : v, fmt);
|
|
46
|
+
}
|
|
47
|
+
function uuidFrom(string) {
|
|
48
|
+
return uuid_1345_1.default.v3({ namespace: '6ba7b811-9dad-11d1-80b4-00c04fd430c8', name: string });
|
|
49
|
+
}
|
|
50
|
+
function nextUUID() {
|
|
51
|
+
return uuidFrom(Date.now().toString());
|
|
52
|
+
}
|
|
53
|
+
exports.isDebug = process.env.DEBUG?.includes('bedrock-portal-nethernet');
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads a 64-bit VarInt as a BigInt
|
|
3
|
+
*/
|
|
4
|
+
declare function readVarLong(buffer: any, offset: any): {
|
|
5
|
+
value: bigint;
|
|
6
|
+
size: number;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Writes a zigzag encoded 64-bit VarInt as a BigInt
|
|
10
|
+
*/
|
|
11
|
+
declare function writeVarLong(value: any, buffer: any, offset: any): any;
|
|
12
|
+
declare function sizeOfVarLong(value: any): number;
|
|
13
|
+
export namespace Read {
|
|
14
|
+
let varint64: (string | typeof readVarLong)[];
|
|
15
|
+
}
|
|
16
|
+
export namespace Write {
|
|
17
|
+
let varint64_1: (string | typeof writeVarLong)[];
|
|
18
|
+
export { varint64_1 as varint64 };
|
|
19
|
+
}
|
|
20
|
+
export namespace SizeOf {
|
|
21
|
+
let varint64_2: (string | typeof sizeOfVarLong)[];
|
|
22
|
+
export { varint64_2 as varint64 };
|
|
23
|
+
}
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
function sizeOfVarLong(value) {
|
|
3
|
+
if (typeof value.valueOf() === 'object') {
|
|
4
|
+
value = (BigInt(value[0]) << 32n) | BigInt(value[1]);
|
|
5
|
+
}
|
|
6
|
+
else if (typeof value !== 'bigint') {
|
|
7
|
+
value = BigInt(value);
|
|
8
|
+
}
|
|
9
|
+
let cursor = 0;
|
|
10
|
+
while (value > 127n) {
|
|
11
|
+
value >>= 7n;
|
|
12
|
+
cursor++;
|
|
13
|
+
}
|
|
14
|
+
return cursor + 1;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Reads a 64-bit VarInt as a BigInt
|
|
18
|
+
*/
|
|
19
|
+
function readVarLong(buffer, offset) {
|
|
20
|
+
let result = BigInt(0);
|
|
21
|
+
let shift = 0n;
|
|
22
|
+
let cursor = offset;
|
|
23
|
+
let size = 0;
|
|
24
|
+
// eslint-disable-next-line no-constant-condition
|
|
25
|
+
while (true) {
|
|
26
|
+
if (cursor + 1 > buffer.length) {
|
|
27
|
+
throw new Error('unexpected buffer end');
|
|
28
|
+
}
|
|
29
|
+
const b = buffer.readUInt8(cursor);
|
|
30
|
+
result |= (BigInt(b) & 0x7fn) << shift; // Add the bits to our number, except MSB
|
|
31
|
+
cursor++;
|
|
32
|
+
if (!(b & 0x80)) { // If the MSB is not set, we return the number
|
|
33
|
+
size = cursor - offset;
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
shift += 7n; // we only have 7 bits, MSB being the return-trigger
|
|
37
|
+
if (shift > 63n)
|
|
38
|
+
throw new Error(`varint is too big: ${shift}`);
|
|
39
|
+
}
|
|
40
|
+
return { value: result, size };
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Writes a zigzag encoded 64-bit VarInt as a BigInt
|
|
44
|
+
*/
|
|
45
|
+
function writeVarLong(value, buffer, offset) {
|
|
46
|
+
// if an array, turn it into a BigInt
|
|
47
|
+
if (typeof value.valueOf() === 'object') {
|
|
48
|
+
value = BigInt.asIntN(64, (BigInt(value[0]) << 32n)) | BigInt(value[1]);
|
|
49
|
+
}
|
|
50
|
+
else if (typeof value !== 'bigint') {
|
|
51
|
+
value = BigInt(value);
|
|
52
|
+
}
|
|
53
|
+
let cursor = 0;
|
|
54
|
+
while (value > 127n) { // keep writing in 7 bit slices
|
|
55
|
+
const num = Number(value & 0xffn);
|
|
56
|
+
buffer.writeUInt8(num | 0x80, offset + cursor);
|
|
57
|
+
cursor++;
|
|
58
|
+
value >>= 7n;
|
|
59
|
+
}
|
|
60
|
+
buffer.writeUInt8(Number(value), offset + cursor);
|
|
61
|
+
return offset + cursor + 1;
|
|
62
|
+
}
|
|
63
|
+
module.exports = {
|
|
64
|
+
Read: { varint64: ['native', readVarLong] },
|
|
65
|
+
Write: { varint64: ['native', writeVarLong] },
|
|
66
|
+
SizeOf: { varint64: ['native', sizeOfVarLong] },
|
|
67
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const PUBLIC_KEY = "MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAECRXueJeTDqNRRgJi/vlRufByu/2G0i2Ebt6YMar5QX/R0DIIyrJMcUpruK4QveTfJSTp3Shlq4Gk34cD/4GUWwkv0DVuzeuB+tXija7HBxii03NHDbPAD0AKnLr2wdAp";
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PUBLIC_KEY = void 0;
|
|
4
|
+
exports.PUBLIC_KEY = 'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAECRXueJeTDqNRRgJi/vlRufByu/2G0i2Ebt6YMar5QX/R0DIIyrJMcUpruK4QveTfJSTp3Shlq4Gk34cD/4GUWwkv0DVuzeuB+tXija7HBxii03NHDbPAD0AKnLr2wdAp';
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KeyExchange = KeyExchange;
|
|
4
|
+
const jsonwebtoken_1 = require("jsonwebtoken");
|
|
5
|
+
const crypto_1 = require("crypto");
|
|
6
|
+
const serverPlayer_1 = require("../serverPlayer");
|
|
7
|
+
const debug = require('debug')('bedrock-portal-nethernet');
|
|
8
|
+
const SALT = '🧂';
|
|
9
|
+
const curve = 'secp384r1';
|
|
10
|
+
const pem = { format: 'pem', type: 'sec1' };
|
|
11
|
+
const der = { format: 'der', type: 'spki' };
|
|
12
|
+
function KeyExchange(client) {
|
|
13
|
+
// Generate a key pair at program start up
|
|
14
|
+
client.ecdhKeyPair = (0, crypto_1.generateKeyPairSync)('ec', { namedCurve: curve });
|
|
15
|
+
client.publicKeyDER = client.ecdhKeyPair.publicKey.export(der);
|
|
16
|
+
client.privateKeyPEM = client.ecdhKeyPair.privateKey.export(pem);
|
|
17
|
+
client.clientX509 = client.publicKeyDER.toString('base64');
|
|
18
|
+
function startClientboundEncryption(publicKey) {
|
|
19
|
+
debug('[encrypt] Client pub key base64: ', publicKey);
|
|
20
|
+
// const pubKeyDer = crypto.createPublicKey({ key: Buffer.from(publicKey.key, 'base64'), ...der })
|
|
21
|
+
// Shared secret from the client's public key + our private key
|
|
22
|
+
// client.sharedSecret = crypto.diffieHellman({ privateKey: client.ecdhKeyPair.privateKey, publicKey: pubKeyDer })
|
|
23
|
+
// Secret hash we use for packet encryption:
|
|
24
|
+
// From the public key of the remote and the private key
|
|
25
|
+
// of the local, a shared secret is generated using ECDH.
|
|
26
|
+
// The secret key bytes are then computed as
|
|
27
|
+
// sha256(server_token + shared_secret). These secret key
|
|
28
|
+
// bytes are 32 bytes long.
|
|
29
|
+
// const secretHash = crypto.createHash('sha256')
|
|
30
|
+
// secretHash.update(SALT)
|
|
31
|
+
// secretHash.update(client.sharedSecret)
|
|
32
|
+
const token = (0, jsonwebtoken_1.sign)({
|
|
33
|
+
salt: toBase64(SALT),
|
|
34
|
+
signedToken: client.clientX509,
|
|
35
|
+
}, client.ecdhKeyPair.privateKey, { algorithm: 'ES384', header: { x5u: client.clientX509, alg: 'ES384' } });
|
|
36
|
+
client.write('server_to_client_handshake', { token });
|
|
37
|
+
// client.secretKeyBytes = secretHash.digest()
|
|
38
|
+
// // The encryption scheme is AES/CFB8/NoPadding with the
|
|
39
|
+
// // secret key being the result of the sha256 above and
|
|
40
|
+
// // the IV being the first 16 bytes of this secret key.
|
|
41
|
+
// const initial = client.secretKeyBytes.slice(0, 16)
|
|
42
|
+
// client.startEncryption(initial)
|
|
43
|
+
}
|
|
44
|
+
function startServerboundEncryption(token) {
|
|
45
|
+
debug('[encrypt] Starting serverbound encryption', token);
|
|
46
|
+
const jwt = token?.token;
|
|
47
|
+
if (!jwt) {
|
|
48
|
+
throw Error('Server did not return a valid JWT, cannot start encryption');
|
|
49
|
+
}
|
|
50
|
+
// No verification here, not needed
|
|
51
|
+
const [header, payload] = jwt.split('.').map(k => Buffer.from(k, 'base64'));
|
|
52
|
+
const head = JSON.parse(String(header));
|
|
53
|
+
const body = JSON.parse(String(payload));
|
|
54
|
+
const pubKeyDer = (0, crypto_1.createPublicKey)({ key: Buffer.from(head.x5u, 'base64'), format: 'der', type: 'spki' });
|
|
55
|
+
// Shared secret from the client's public key + our private key
|
|
56
|
+
client.sharedSecret = (0, crypto_1.diffieHellman)({ privateKey: client.ecdhKeyPair.privateKey, publicKey: pubKeyDer });
|
|
57
|
+
const salt = Buffer.from(body.salt, 'base64');
|
|
58
|
+
const secretHash = (0, crypto_1.createHash)('sha256');
|
|
59
|
+
secretHash.update(salt);
|
|
60
|
+
secretHash.update(client.sharedSecret);
|
|
61
|
+
client.secretKeyBytes = secretHash.digest();
|
|
62
|
+
// const iv = client.secretKeyBytes.slice(0, 16)
|
|
63
|
+
// client.startEncryption(iv)
|
|
64
|
+
// It works! First encrypted packet :)
|
|
65
|
+
client.write('client_to_server_handshake', {});
|
|
66
|
+
client.emit('join');
|
|
67
|
+
client.status = serverPlayer_1.ClientStatus.Initializing;
|
|
68
|
+
}
|
|
69
|
+
client.on('server.client_handshake', startClientboundEncryption);
|
|
70
|
+
client.on('client.server_handshake', startServerboundEncryption);
|
|
71
|
+
}
|
|
72
|
+
function toBase64(string) {
|
|
73
|
+
return Buffer.from(string).toString('base64');
|
|
74
|
+
}
|