Skip to content

Commit 89e2923

Browse files
committed
add join parser
1 parent e2cae94 commit 89e2923

File tree

11 files changed

+169
-41
lines changed

11 files changed

+169
-41
lines changed

Diff for: index.js

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ mqClient.connect()
7474
if (udpUlJSON.pushData) {
7575
return udpHandler.pushDataParser(udpUlJSON)
7676
.then((pushData) => {
77+
console.log(pushData);
7778
return gatewayHandler.uploadPushData(pushData);
7879
});
7980
} else {

Diff for: lib/joinHandler/joinHandler.js

+123-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
const bluebird = require('bluebird');
2-
const { consts, utils } = require('../lora-lib');
2+
const { consts, utils, ERROR } = require('../lora-lib');
3+
const slice = utils.bufferSlice;
4+
const reverse = utils.bufferReverse;
5+
const cmac = require('node-aes-cmac').aesCmac;
6+
const crypto = require('crypto');
37

48
class JoinHandler {
59
constructor(DeviceInfo, log) {
@@ -8,25 +12,53 @@ class JoinHandler {
812
}
913

1014
parser(phyPayloadJSON) {
15+
const MACPayload = this.joinReqParser(phyPayloadJSON.macPayload);
1116
const phyPayload = {
1217
MHDR: phyPayloadJSON.mhdrJSON,
13-
MHDRRaw: phyPayloadJSON.mhdr,
14-
MACPayload: phyPayloadJSON.macPayload,
18+
MACPayload,
1519
MIC: phyPayloadJSON.mic,
1620
};
17-
return bluebird.resolve(phyPayload);
21+
22+
const MICfields = {
23+
MHDR: phyPayloadJSON.mhdr,
24+
AppEUI: MACPayload.AppEUI,
25+
DevEUI: MACPayload.DevEUI,
26+
DevNonce: MACPayload.DevNonce,
27+
MIC: phyPayloadJSON.mic,
28+
};
29+
30+
const query = { DevEUI: MACPayload.DevEUI };
31+
const attr = ['AppKey'];
32+
return this.DeviceInfo.readItem(query, attr)
33+
.then((res) => {
34+
return this.micVerification(MICfields, res.AppKey, phyPayloadJSON.mic);
35+
})
36+
.then(() => {
37+
return bluebird.resolve(phyPayload);
38+
});
39+
1840
}
1941

20-
packager(phyPayloadJSON) {
21-
const MHDR = this.MHDRPackager(phyPayloadJSON.MHDR);
22-
const MACPayload = phyPayloadJSON.MACPayload;
42+
packager(phyPayloadJSON, key) {
43+
phyPayloadJSON.MHDR = this.MHDRPackager(phyPayloadJSON.MHDR);
44+
const MACPayloadJSON = phyPayloadJSON.MACPayload;
45+
const MIC = this.joinMICCalculator(phyPayloadJSON, key, 'accept');
46+
let macpayload = Buffer.concat([
47+
reverse(MACPayloadJSON.AppNonce),
48+
reverse(MACPayloadJSON.NetID),
49+
reverse(MACPayloadJSON.DevAddr),
50+
reverse(MACPayloadJSON.DLSettings),
51+
reverse(MACPayloadJSON.RxDelay),
52+
]);
53+
if ('CFList' in MACPayloadJSON) {
54+
macpayload = Buffer.concat([macpayload, MACPayloadJSON.CFList]);
55+
}
2356

24-
/*this.DeviceInfo.createDeviceInfo(
25-
phyPayloadJSON.DevAddr,
26-
phyPayloadJSON.NwkSKey,
27-
phyPayloadJSON.AppSKey
28-
);*/
29-
return bluebird.resolve(Buffer.concat([MHDR, MACPayload]));
57+
macpayload = Buffer.concat([macpayload, MIC]);
58+
59+
const encmacpayload = this.AcptEncryption(macpayload, key);
60+
const phypayload = Buffer.concat([phyPayloadJSON.MHDR, encmacpayload]);
61+
return bluebird.resolve(phypayload);
3062
}
3163

3264
MHDRPackager(mhdr) {
@@ -35,6 +67,84 @@ class JoinHandler {
3567
utils.bitwiseAssigner(MHDR, consts.MAJOR_OFFSET, consts.MAJOR_LEN, mhdr.Major);
3668
return MHDR;
3769
}
70+
71+
joinReqParser (MACPayload) {
72+
const joinReqJSON = {};
73+
joinReqJSON.AppEUI = slice(MACPayload, consts.JOINEUI_OFFSET, consts.DEVEUI_OFFSET);
74+
joinReqJSON.DevEUI = slice(MACPayload, consts.DEVEUI_OFFSET, consts.DEVNONCE_OFFSET);
75+
joinReqJSON.DevNonce = slice(MACPayload, consts.DEVNONCE_OFFSET);
76+
return joinReqJSON;
77+
}
78+
79+
micVerification (requiredFields, key, receivedMIC) {
80+
return new bluebird((resolve, reject) => {
81+
const calculatedMIC = this.joinMICCalculator(requiredFields, key, 'request');
82+
if (receivedMIC.equals(calculatedMIC)) {
83+
return resolve({});
84+
} else {
85+
const errorMessage = {
86+
message: 'MIC Mismatch',
87+
DevEUI: requiredFields.DevEUI,
88+
AppEUI: requiredFields.AppEUI,
89+
};
90+
return reject(new ERROR.MICMismatchError(errorMessage));
91+
}
92+
93+
});
94+
};
95+
96+
joinMICCalculator (requiredFields, key, type) {
97+
let micPayload;
98+
let bufferArray;
99+
switch (type) {
100+
case 'request': {
101+
bufferArray = [
102+
reverse(requiredFields.MHDR),
103+
reverse(requiredFields.AppEUI),
104+
reverse(requiredFields.DevEUI),
105+
reverse(requiredFields.DevNonce)
106+
];
107+
micPayload = Buffer.concat(bufferArray, consts.BLOCK_LEN_REQ_MIC);
108+
break;
109+
}
110+
case 'accept': {
111+
bufferArray = [
112+
reverse(requiredFields.MHDR),
113+
reverse(requiredFields.MACPayload.AppNonce),
114+
reverse(requiredFields.MACPayload.NetID),
115+
reverse(requiredFields.MACPayload.DevAddr),
116+
reverse(requiredFields.MACPayload.DLSettings),
117+
reverse(requiredFields.MACPayload.RxDelay)
118+
];
119+
micPayload = Buffer.concat(bufferArray, consts.BLOCK_LEN_ACPT_MIC_BASE);
120+
if (requiredFields.MACPayload.hasOwnProperty('CFList')) {
121+
micPayload = Buffer.concat([
122+
micPayload,
123+
reverse(requiredFields.MACPayload.CFList)
124+
], consts.BLOCK_LEN_ACPT_MIC_BASE + requiredFields.CFList.length);
125+
}
126+
127+
break;
128+
}
129+
}
130+
const options = {
131+
returnAsBuffer: true,
132+
};
133+
134+
return cmac(
135+
key,
136+
micPayload,
137+
options
138+
).slice(0, consts.V102_CMAC_LEN);
139+
}
140+
141+
AcptEncryption (acpt, key) {
142+
const iv = '';
143+
const cipher = crypto.createDecipheriv(consts.ENCRYPTION_ALGO, key, iv);
144+
cipher.setAutoPadding(false);
145+
return cipher.update(acpt);
146+
};
147+
38148
}
39149

40150
module.exports = JoinHandler;

Diff for: lib/lora-lib

Diff for: lib/phyHandler/phyPackager.js

+17-10
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@ PHYPackager.FHDRPackager = function (FHDRJSON) {
2828
reverse(FHDRJSON.DevAddr).copy(FHDR, consts.MP_DEVADDR_OFFSET);
2929
reverse(FCtrl).copy(FHDR, consts.MP_FCTRL_OFFSET);
3030
slice(FHDRJSON.FCnt, consts.FCNT_LEAST_OFFSET).copy(FHDR, consts.MP_FCNT_OFFSET);
31+
console.log(FHDRJSON);
3132
if (FHDRJSON.FCtrl.FOptsLen > 0) {
3233
const FOpts = MACPackager.packager(FHDRJSON.FOpts);
34+
console.log(FOpts);
3335
FHDR = Buffer.concat([FHDR, FOpts]);
3436
}
3537

@@ -48,26 +50,31 @@ PHYPackager.FCtrlPackager = function (FCtrlJSON) {
4850
PHYPackager.prototype.packager = function (phyPayloadJSON) {
4951
const MType = phyPayloadJSON.MHDR.MType;
5052
const MACPayload = phyPayloadJSON.MACPayload;
51-
if (MACPayload.FPort !== 0 && !MACPayload.FPort) {
52-
MACPayload.FPort = Buffer.alloc(0);
53-
}
54-
55-
if (!MACPayload.FRMPayload) {
56-
MACPayload.FRMPayload = Buffer.alloc(0);
57-
} else if (MACPayload.FPort.readUInt8() == consts.MACCOMMANDPORT.readUInt8()) {
58-
MACPayload.FRMPayload = MACPackager.packager(MACPayload.FRMPayload);
59-
}
6053

6154
let MHDR;
6255
let FHDR;
6356

6457
//const MType = utils.bitwiseFilter(phyPayloadJSON.MHDR, consts.MTYPE_OFFSET, consts.MTYPE_LEN);
6558
switch (MType) {
6659
case consts.JOIN_ACCEPT: {
67-
return this.joinHandler.packager(phyPayloadJSON);
60+
const devaddr = MACPayload.DevAddr;
61+
return this.DeviceInfo.read(devaddr, ['AppKey'])
62+
.then((key) => {
63+
return this.joinHandler.packager(phyPayloadJSON, key.AppKey);
64+
});
6865
}
6966
case consts.UNCONFIRMED_DATA_DOWN:
7067
case consts.CONFIRMED_DATA_DOWN: {
68+
if (MACPayload.FPort !== 0 && !MACPayload.FPort) {
69+
MACPayload.FPort = Buffer.alloc(0);
70+
}
71+
72+
if (!MACPayload.FRMPayload) {
73+
MACPayload.FRMPayload = Buffer.alloc(0);
74+
} else if (MACPayload.FPort.readUInt8() == consts.MACCOMMANDPORT.readUInt8()) {
75+
MACPayload.FRMPayload = MACPackager.packager(MACPayload.FRMPayload);
76+
}
77+
7178
MHDR = PHYPackager.MHDRPackager(phyPayloadJSON.MHDR);
7279
FHDR = PHYPackager.FHDRPackager(MACPayload.FHDR);
7380
break;

Diff for: lib/phyHandler/phyParser.js

-1
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,6 @@ PHYParser.prototype.parser = function (phyPayloadRaw) {
253253
MACPayload: {
254254
FHDR: macPayloadJSON.fhdrJSON,
255255
},
256-
MIC: phyPayloadJSON.mic,
257256
};
258257

259258
if (macPayloadJSON.FPort) {

Diff for: lib/phyHandler/phyUtils.js

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ const _this = new function () {
5656

5757
block[consts.BLOCK_LENMSG_OFFSET] = msg.length;
5858
const cmacBlock = Buffer.concat([block, msg], consts.BLOCK_LEN + msg.length);
59+
console.log(cmacBlock);
5960
const options = { returnAsBuffer: true };
6061
return cmac(
6162
key,

Diff for: test/unit/lib/cmdHandler/MACCmdPackager.test.js

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ const maccommand = '01010245670389abcdef';
3030
describe('Test MACCmd Packager', () => {
3131
it('test packager', () => {
3232
const res = macCmdPackager.packager(cmdArr);
33+
console.log(res);
3334
expect(res.toString('hex')).to.equal(maccommand);
3435
});
3536
});

Diff for: test/unit/lib/mqClient/kafka/kafkaClient.test.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,15 @@ describe('Test MQ client', () => {
4747
const len = 10;
4848
const message = crypto.randomBytes(len).toString('hex');
4949

50-
mqClient.connect()
50+
return mqClient.connect()
5151
.then(() => {
5252
mqClient.message((res) => {
5353
expect(res.value).to.equal(message);
5454
done();
5555
});
56-
mqClient.publish(topic, message);
57-
});
56+
return mqClient.publish(topic, message);
57+
})
58+
.then(() => done(), done);
5859
}).timeout(config.mocha.timeout);
5960
after('Close MQ client', (done) => {
6061
mqClient.disconnect()

Diff for: test/unit/lib/phyHandler/phyPackager.test.js

+17-9
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,16 @@ const modelIns = {
2121
RedisModel: {},
2222
MySQLModel: {},
2323
};
24-
for (let model in Models.RedisModel) {
25-
modelIns.RedisModel[model] = new Models.RedisModel[model](db.RedisClient);
24+
for (let model in Models.RedisModels) {
25+
modelIns.RedisModel[model] = new Models.RedisModels[model](db.RedisClient);
2626
}
2727

28-
for (let model in Models.MySQLModel) {
29-
modelIns.MySQLModel[model] = new Models.MySQLModel[model](db.MySQLClient);
28+
for (let model in Models.MySQLModels) {
29+
modelIns.MySQLModel[model] = new Models.MySQLModels[model](db.MySQLClient);
3030
}
3131

3232
const PhyPackager = require(join('lib/phyHandler/phyPackager'));
33-
const phyPackager = new PhyPackager(modelIns.MySQLModel.DeviceInfo, null, log);
33+
const phyPackager = new PhyPackager(modelIns.RedisModel.DeviceInfo, null, log);
3434

3535
describe('Test PHY packager', () => {
3636

@@ -41,7 +41,7 @@ describe('Test PHY packager', () => {
4141
ADR: 0,
4242
ACK: 1,
4343
FPending: 0,
44-
FOptsLen: 1,
44+
FOptsLen: 5,
4545
};
4646

4747
});
@@ -57,7 +57,7 @@ describe('Test PHY packager', () => {
5757
});
5858

5959
it('Test FCtrl packager', () => {
60-
const expectedFCtrl = Buffer.from('21', 'hex');
60+
const expectedFCtrl = Buffer.from('25', 'hex');
6161
FCtrl = PhyPackager.FCtrlPackager(FCtrlJSON);
6262
expect(FCtrl.equals(expectedFCtrl)).to.be.true;
6363
});
@@ -67,15 +67,23 @@ describe('Test PHY packager', () => {
6767
DevAddr: crypto.randomBytes(consts.DEVADDR_LEN),
6868
FCtrl: FCtrlJSON,
6969
FCnt: crypto.randomBytes(consts.FCNT_LEN),
70-
FOpts: crypto.randomBytes(FCtrlJSON.FOptsLen),
70+
FOpts: [{
71+
'03': {
72+
TXPower: Buffer.from('01', 'hex'),
73+
ChMask: Buffer.from('00ff', 'hex'),
74+
Redundancy: Buffer.from('02', 'hex'),
75+
},
76+
}],
7177
};
7278
const expectedFHDR = Buffer.concat([
7379
reverse(FHDRJSON.DevAddr),
7480
reverse(FCtrl),
7581
reverse(FHDRJSON.FCnt.slice(consts.FCNT_LEAST_OFFSET)),
76-
reverse(FHDRJSON.FOpts),
82+
Buffer.from('030100ff02', 'hex'),
7783
]);
7884
const FHDR = PhyPackager.FHDRPackager(FHDRJSON);
85+
console.log(FHDR);
86+
console.log(expectedFHDR);
7987
expect(FHDR.equals(expectedFHDR)).to.be.true;
8088

8189
});

Diff for: test/unit/lib/udpHandler/udpHandler.test.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ describe('Test UDP parser', () => {
2525
let udpErrorIdentifier;
2626
before('Initial a handler', () => {
2727
udpHandler = new UDPHandler(log);
28-
const udpEUI = crypto.randomBytes(consts.GW_ID_LEN);
28+
const udpEUI = crypto.randomBytes(consts.GWEUI_LEN);
2929
const baseLen = 4;
3030
const base = Buffer.alloc(baseLen);
3131
base.writeUIntBE(0x02000000, 0, baseLen);
@@ -153,7 +153,7 @@ describe('Test UDP packager', (done) => {
153153
it('PULL_ACK', (done) => {
154154
udpPULLACKJSON = Object.assign({}, udpBaseJSON);
155155
udpPULLACKJSON.identifier.writeUInt8(consts.UDP_ID_PULL_ACK);
156-
udpPULLACKJSON.gatewayId = Buffer.alloc(consts.GW_ID_LEN);
156+
udpPULLACKJSON.gatewayId = Buffer.alloc(consts.GWEUI_LEN);
157157
udpHandler.packager(udpPULLACKJSON)
158158
.then((udpRecPULLACK) => {
159159
expect(udpRecPULLACK.equals(udpPULLACK)).to.be.true;

Diff for: test/unit/models/GatewayInfo.test.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ describe('Test GatewayInfo model', function () {
3737
let testMySQLGatewayInfo;
3838
const testUser = 'testUser';
3939
before('Get connection with database', function (done) {
40-
GatewayInfoRedis = new Models.RedisModel.GatewayInfo(_ioredis);
41-
GatewayInfoMySQL = new Models.MySQLModel.GatewayInfo(_sequelize);
40+
GatewayInfoRedis = new Models.RedisModels.GatewayInfo(_ioredis);
41+
GatewayInfoMySQL = new Models.MySQLModels.GatewayInfo(_sequelize);
4242
query = {
4343
gatewayId: testGatewayId,
4444
};

0 commit comments

Comments
 (0)