• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

suculent / thinx-device-api / #252646970

27 Oct 2017 03:17PM UTC coverage: 12.466% (+1.3%) from 11.197%
#252646970

push

suculent
added support for displaying/exporting extended SigFox attributes

37 of 1808 branches covered (2.05%)

Branch coverage included in aggregate %.

735 of 4385 relevant lines covered (16.76%)

0.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

4.23
/lib/thinx/device.js
1
/** This THiNX-RTM API module is responsible for managing devices. */
2

3
var Device = (function() {
1✔
4

5
        var app_config = require("../../conf/config.json");
1✔
6
        if (typeof(process.env.CIRCLE_USERNAME) !== "undefined") {
1!
7
                console.log("ยป Configuring for Circle CI...");
×
8
                app_config = require("../../conf/config-test.json");
×
9
        }
10
        var fs = require("fs");
1✔
11
        var db = app_config.database_uri;
1✔
12

13
        var prefix = "";
1✔
14
        try {
1✔
15
                var pfx_path = app_config.project_root + '/conf/.thx_prefix';
1✔
16
                if (fs.existsSync(pfx_path)) {
1!
17
                        prefix = fs.readFileSync(pfx_path) + "_";
×
18
                }
19
        } catch (e) {
20
                //console.log(e);
21
        }
22

23
        var devicelib = require("nano")(db).use(prefix + "managed_devices");
1✔
24

25
        var sha256 = require("sha256");
1✔
26
        var uuidV1 = require("uuid/v1");
1✔
27
        var alog = require("./audit");
1✔
28
        var deploy = require("./deployment");
1✔
29
        var apikey = require("./apikey");
1✔
30
        var repository = require("./repository");
1✔
31
        var redis = require("redis");
1✔
32
        var client = redis.createClient();
1✔
33
        var exec = require("child_process");
1✔
34

35
        var _private = {
1✔
36

37
                updateFromPath: function(path, ott, callback) {
38

39
                        // Arduino: single *.bin file only
40
                        // Platformio: single *.bin file only
41
                        // Lua: init.lua, config.lua (will deprecate in favor of thinx.json), thinx.lua
42
                        // Micropython: boot.py, thinx.py, thinx.json, optionally other *.pys and data within the directory structure
43
                        // MongooseOS: to be evaluated, should support both
44

45
                        if (path.indexOf("/") === path.length) {
×
46
                                console.log(
×
47
                                        "Trailing slash detected. This should be a multi-file update.");
48

49
                        } else {
50

51
                                console.log(
×
52
                                        "Trailing slash not detected. This is a single-file update.");
53

54
                                // Detect contents of this folder first, then use specific platform method
55
                                repository.getPlatform(path, function(success, platform) {
×
56

57
                                        if (!success) {
×
58
                                                console.log("[device] getPlatform error", platform);
×
59
                                                return;
×
60
                                        }
61

62
                                        if (platform === "arduino" || platform === "platformio") {
×
63
                                                _private.update_binary(path, ott, callback);
×
64

65
                                        } else if (platform === "nodemcu") {
×
66
                                                console.log(
×
67
                                                        "Multi-file update for NodeMCU not yet fully supported.");
68
                                                _private.update_multiple(path, ott, callback);
×
69

70
                                        } else if (platform === "micropython") {
×
71
                                                console.log(
×
72
                                                        "Multi-file update for Micropython not yet fully supported.");
73
                                                _private.update_multiple(path, ott, callback);
×
74

75
                                        } else if (platform === "mongoose") {
×
76
                                                console.log("Firmware update for MongooseOS not yet supported.");
×
77
                                                _private.update_multiple(path, ott, callback);
×
78

79
                                        } else if (platform === "nodejs") {
×
80
                                                console.log("Firmware update for node.js not yet supported.");
×
81
                                        }
82

83
                                }); // repository.getPlatform
84
                        }
85
                },
86

87
                update_multiple: function(path, ott, callback) {
88

89
                        var directories = fs.readdirSync(path).filter(
×
90
                                file => fs.lstatSync(path.join(path, file)).isDirectory()
×
91
                        );
92

93
                        var artefact_filenames = [];
×
94

95
                        // Fetch header name and language type
96
                        var platforms_path = app_config.project_root + "/platforms";
×
97
                        console.log("Platforms path: " + platforms_path);
×
98
                        var platform_descriptor = require(platforms_path + "/descriptor.json");
×
99
                        var header_file_name = platform_descriptor.header;
×
100
                        var platform_language = platform_descriptor.language;
×
101
                        var header_path = path + "/" + header_file_name;
×
102
                        if (typeof(header_file_name) !== "undefined") {
×
103
                                // TODO: Check file existence
104
                                artefact_filenames.push(header_file_name);
×
105
                        }
106

107
                        var extensions = app.config.project_root + "/languages/" + language +
×
108
                                "/descriptor.json";
109

110
                        // Match all files with those extensions + header
111
                        var all_files = fs.readdirSync(path);
×
112
                        var artifact_filenames = [];
×
113
                        var selected_files = [];
×
114
                        for (var findex in artifact_filenames) {
×
115
                                var file = all_files[findex];
×
116
                                for (var xindex in extensions) {
×
117
                                        if (file.indexOf(extensions[xindex]) !== -1) {
×
118
                                                selected_files.push(file);
×
119
                                        } else if (file.indexOf(header_file_name) !== -1) {
×
120
                                                selected_files.push(file);
×
121
                                        }
122
                                }
123
                        }
124

125
                        var buffer = {};
×
126
                        buffer.type = "file";
×
127
                        buffer.files = [];
×
128

129
                        for (var aindex in selected_files) {
×
130
                                var apath = path + "/" + selected_files[aindex];
×
131
                                var descriptor = {
×
132
                                        name: selected_files[aindex],
133
                                        data: fs.readFileSync(apath)
134
                                };
135
                                buffer.files.push(descriptor);
×
136
                        }
137

138
                        // Respond with json containing all the files...
139
                        callback(true, buffer);
×
140
                },
141

142
                // Simple Single-File/OTT Update
143
                update_binary: function(path, ott, callback) {
144
                        fs.open(path, "r", function(err, fd) {
×
145
                                if (err) {
×
146
                                        callback(false, {
×
147
                                                success: false,
148
                                                status: "not_found"
149
                                        });
150
                                        return console.log(err);
×
151
                                } else {
152
                                        var buffer = fs.readFileSync(path);
×
153
                                        fs.close(fd, function() {
×
154
                                                console.log(
×
155
                                                        "Sending firmware update from " + path + "...");
156
                                        });
157
                                        if (typeof(ott) !== "undefined") {
×
158
                                                client.expire("ott:" + ott, 3600); // TODO: FIXME: Should be 0, like this the OTT is valid for 60 minutes after first use
×
159
                                        }
160
                                        callback(true, buffer);
×
161
                                }
162
                        }); // fs.open (single-file)
163
                },
164

165
                checkinExistingDevice: function(device, reg, callback) {
166

167
                                console.log("[OID:" + reg.owner +
×
168
                                        "] [DEVICE_CHECKIN] Checkin Existing device: " +
169
                                        JSON.stringify(reg));
170

171
                                // Override/update last checkin timestamp
172
                                device.lastupdate = new Date();
×
173

174
                                // firmware from device overrides server
175
                                if (typeof(reg.firmware) !== "undefined" && reg.firmware !== null) {
×
176
                                        device.firmware = reg.firmware;
×
177
                                }
178

179
                                // version from device overrides server
180
                                if (typeof(reg.version) !== "undefined" && reg.version !== null) {
×
181
                                        device.version = reg.version;
×
182
                                }
183

184
                                // commit from device overrides server
185
                                if (typeof(reg.commit) !== "undefined" && reg.commit !== null) {
×
186
                                        device.commit = reg.commit;
×
187
                                }
188

189
                                // push from device overrides server
190
                                if (typeof(reg.push) !== "undefined" && reg.push !== null) {
×
191
                                        device.push = reg.push;
×
192
                                }
193

194
                                // name from server overrides device
195
                                if (typeof(reg.alias) !== "undefined" && reg.alias !== null) {
×
196
                                        if (typeof(device.alias) === "undefined") {
×
197
                                                device.alias = reg.alias;
×
198
                                        }
199
                                }
200

201
                                // Extended SigFox Support
202

203
                                // status, snr, station, lat, long
204
                                if (typeof(reg.status) !== "undefined" && reg.status !== null) {
×
205
                                        device.status = reg.status;
×
206
                                }
207

208
                                if (typeof(reg.snr) !== "undefined" && reg.snr !== null) {
×
209
                                        device.snr = reg.snr;
×
210
                                }
211

212
                                if (typeof(reg.station) !== "undefined" && reg.station !== null) {
×
213
                                        device.station = reg.station;
×
214
                                }
215

216
                                // Includes
217

218
                                if (typeof(reg.lat) !== "undefined" && reg.lat !== null) {
×
219
                                        device.lat = reg.lat;
×
220
                                }
221

222
                                if (typeof(reg.lon) !== "undefined" && reg.lon !== null) {
×
223
                                        device.lon = reg.lon;
×
224
                                }
225

226
                                //
227
                                // UDID Dance
228
                                //
229

230
                                var udid;
231

232
                                if (typeof(device._id) === "undefined") {
×
233
                                        console.log("Existing device should have in ID!");
×
234
                                }
235

236
                                if (typeof(reg.udid) !== "undefined") {
×
237
                                        udid = reg.udid;
×
238
                                }
239

240
                                if (typeof(device._id) !== "undefined") {
×
241
                                        udid = device._id;
×
242
                                }
243

244
                                if (typeof(udid) == "undefined") {
×
245
                                        console.log("UDID must be given, exiting");
×
246
                                        callback(false, "udid_atomic_error");
×
247
                                }
248

249
                                // console.log("Atomic update for device " + udid + " with data " + JSON.stringify(device));
250

251
                                devicelib.atomic("devicelib", "modify", udid, device, function(error, body) {
×
252
                                        if (!error) {
×
253
                                                var registration_response = {
×
254
                                                        registration: {
255
                                                                success: true,
256
                                                                status: "OK",
257
                                                                owner: device.owner,
258
                                                                alias: device.alias,
259
                                                                udid: udid,
260
                                                                auto_update: device.auto_update
261
                                                        }
262
                                                };
263
                                                callback(true, registration_response);
×
264
                                                console.log("Device checkin complete with response: " + JSON.stringify(
×
265
                                                        registration_response));
266
                                        } else {
267
                                                console.log(error, body);
×
268
                                                callback(false, {
×
269
                                                        registration: {
270
                                                                success: false,
271
                                                                status: "insert_failed"
272
                                                        }
273
                                                });
274
                                        }
275
                                });
276
                        } // checkin function
277
        };
278

279
        // public
280
        var _public = {
1✔
281

282
                normalizedMAC: function(_mac) {
283

284
                        if ((typeof(_mac) === "undefined") || (_mac === null)) {
×
285
                                //throw Error("Undefined MAC!");
286
                                return "UN:DE:FI:NE:D_";
×
287
                        }
288

289
                        if (_mac === "") {
×
290
                                //throw Error("Empty MAC!");
291
                                return "EM:PT:YM:AC:__";
×
292
                        }
293

294
                        var mac_addr = _mac.toString();
×
295
                        // console.log("[device.js] Normalizing MAC: '" + mac + "'");
296

297
                        if (mac_addr.length == 17) {
×
298
                                return mac_addr.toUpperCase();
×
299
                        } else {
300
                                var retval = "";
×
301

302
                                var ms = mac_addr.toUpperCase();
×
303
                                if (ms.indexOf(":") !== -1) {
×
304
                                        ms = ms.replace(/:/g, "");
×
305
                                }
306
                                var m = ms.split("");
×
307
                                for (var step = 0; step <= m.length - 2; step += 2) {
×
308
                                        retval += m[step].toString();
×
309
                                        if (typeof(m[step + 1]) !== "undefined") {
×
310
                                                retval += m[step + 1].toString();
×
311
                                        }
312
                                        // add ":" of this is not last step
313
                                        if (step < m.length - 2) {
×
314
                                                retval += ":";
×
315
                                        }
316
                                }
317
                                return retval;
×
318
                        }
319
                },
320

321
                storeOTT: function(body, callback) {
322
                        var new_ott = sha256(Date());
×
323
                        client.set("ott:" + new_ott, JSON.stringify(body), function(err) {
×
324
                                if (err) {
×
325
                                        callback(false, err);
×
326
                                } else {
327
                                        callback(true, {
×
328
                                                ott: new_ott
329
                                        });
330
                                        client.expire("ott:" + new_ott, 86400);
×
331
                                }
332
                        });
333
                },
334

335
                fetchOTT: function(ott, callback) {
336
                        client.get("ott:" + ott, function(err, json_keys) {
×
337
                                callback(err, json_keys);
×
338
                        });
339
                },
340

341
                register: function(body, api_key, callback) {
342

343
                        var reg = body;
×
344

345
                        //
346
                        // Validate input parameters
347
                        //
348

349
                        console.log("โ€ข Registration with API Key: " + api_key + " and body " + JSON.stringify(body));
×
350

351
                        if (typeof(reg) === "undefined") {
×
352
                                callback(false, "no_registration_info");
×
353
                                return;
×
354
                        }
355

356
                        var rdict = {};
×
357

358
                        rdict.registration = {};
×
359

360
                        var mac = _public.normalizedMAC(reg.mac);
×
361
                        if (typeof(mac) === "undefined") {
×
362
                                throw Error("Missing MAC in device.js:354");
×
363
                        }
364
                        var fw = "unknown";
×
365
                        if (!reg.hasOwnProperty("firmware")) {
×
366
                                fw = "undefined";
×
367
                        } else {
368
                                fw = reg.firmware;
×
369
                                //console.log("Setting firmware " + fw);
370
                        }
371

372
                        // Headers must contain Authentication header
373
                        if (typeof(api_key) === "undefined") {
×
374
                                console.log("ERROR: Registration requests now require API key!");
×
375
                                alog.log(owner, "Attempt to register witout API Key!");
×
376
                                callback(false, "authentication");
×
377
                                return;
×
378
                        }
379

380
                        // Until 2.0.0
381
                        if (typeof(reg.owner) === "undefined") {
×
382
                                console.log("searching for owner in: " + JSON.stringify(reg));
×
383
                                callback(false, "old_protocol_owner:-" + owner + "-");
×
384
                                return;
×
385
                        }
386

387
                        // Since 2.0.0a
388
                        var platform = "unknown";
×
389
                        if (typeof(reg.platform) !== "undefined") {
×
390
                                platform = reg.platform;
×
391
                        }
392

393
                        var push = reg.push;
×
394
                        var alias = reg.alias;
×
395
                        var owner = reg.owner;
×
396
                        var version = reg.version;
×
397
                        var udid;
398

399
                        apikey.verify(owner, api_key, function(success, message) {
×
400

401
                                if (success === false) {
×
402
                                        alog.log(owner, "Attempt to use invalid API Key: " +
×
403
                                                api_key +
404
                                                " on device registration.");
405
                                        callback(false, message);
×
406
                                        return;
×
407
                                }
408

409
                                alog.log(owner,
×
410
                                        "Attempt to register device: " + reg.udid + " alias: " + alias);
411
                                console.log(owner,
×
412
                                        "Attempt to register device: " + reg.udid + " alias: " + alias);
413

414
                                deploy.initWithOwner(owner); // creates user path if does not exist
×
415

416
                                alog.log(owner, "Using API Key: " + api_key);
×
417

418
                                // TODO: If device gives udid, get by udid (existing), otherwise use new.
419

420
                                success = false;
×
421
                                var status = "OK";
×
422
                                var firmware_version = "1.0.0"; // default
×
423

424
                                if (typeof(version) !== "undefined") {
×
425
                                        //console.log("Device declares version: " + version);
426
                                        firmware_version = version;
×
427
                                }
428

429
                                var known_owner = "";
×
430

431
                                var checksum = null;
×
432
                                if (typeof(reg.checksum) !== "undefined") {
×
433
                                        checksum = reg.checksum;
×
434
                                }
435

436
                                var udid = uuidV1(); // is returned to device which should immediately take over this value instead of mac for new registration
×
437
                                if (typeof(reg.udid) !== "undefined") {
×
438
                                        if (reg.udid.length > 4) {
×
439
                                                udid = reg.udid;
×
440
                                        }
441
                                }
442

443
                                //
444
                                // Construct response
445
                                //
446

447
                                var response = {};
×
448

449
                                if (
×
450
                                        (typeof(rdict.registration) !== "undefined") &&
×
451
                                        (rdict.registration !== null)
452
                                ) {
453
                                        response = rdict.registration;
×
454
                                }
455

456
                                response.success = success;
×
457
                                response.status = status;
×
458

459
                                if (known_owner === "") {
×
460
                                        known_owner = owner;
×
461
                                }
462

463
                                if (owner != known_owner) {
×
464
                                        // TODO: Fail from device side, notify admin.
465
                                        console.log("owner is not known_owner (" + owner + ", " +
×
466
                                                known_owner +
467
                                                ")");
468
                                        response.owner = known_owner;
×
469
                                        owner = known_owner; // should force update in device library
×
470
                                }
471

472
                                //
473
                                // Construct device descriptor and check for firmware
474
                                //
475

476
                                //console.log("Device firmware: " + fw);
477

478
                                var mqtt = "/" + owner + "/" + udid;
×
479

480
                                var device = {
×
481
                                        mac: mac,
482
                                        firmware: fw,
483
                                        checksum: checksum,
484
                                        push: push,
485
                                        alias: alias,
486
                                        owner: owner,
487
                                        source: null,
488
                                        version: firmware_version,
489
                                        udid: udid,
490
                                        mqtt: mqtt,
491
                                        platform: platform,
492
                                        lastupdate: new Date(),
493
                                        lastkey: sha256(api_key),
494
                                        auto_update: false,
495
                                        description: "new device",
496
                                        icon: "01",
497
                                        status: " ",
498
                                        snr: " ",
499
                                        station: " ",
500
                                        lat: 0,
501
                                        lon: 0
502
                                };
503

504
                                var update = deploy.hasUpdateAvailable(device);
×
505
                                if (update === true) {
×
506
                                        //console.log("Firmware update available.");
507
                                        var firmwareUpdateDescriptor = deploy.latestFirmwareEnvelope(
×
508
                                                device);
509

510
                                        var rmac = firmwareUpdateDescriptor.mac || mac;
×
511
                                        if (typeof(rmac) === "undefined") {
×
512
                                                throw Error("Missing MAC in device.js:491");
×
513
                                        }
514
                                        response.status = "FIRMWARE_UPDATE";
×
515
                                        response.success = true;
×
516
                                        response.url = firmwareUpdateDescriptor.url;
×
517
                                        response.mac = _public.normalizedMAC(rmac);
×
518
                                        response.commit = firmwareUpdateDescriptor.commit;
×
519
                                        response.version = firmwareUpdateDescriptor.version;
×
520
                                        response.checksum = firmwareUpdateDescriptor.checksum;
×
521
                                } else if (update === false) {
×
522
                                        response.success = true;
×
523
                                        console.log("No firmware update available.");
×
524
                                } else {
525
                                        console.log("Update semver response: " + update);
×
526
                                }
527

528
                                // KNOWN DEVICES:
529
                                // - see if new firmware is available and reply FIRMWARE_UPDATE with url
530
                                // - see if alias or owner changed
531
                                // - otherwise reply just OK
532

533
                                //
534
                                // Fiund out, whether device with presented udid exists (owner MUST match to verified API key owner)
535
                                //
536

537
                                devicelib.get(udid, function(error, existing) {
×
538

539
                                        if (!error && (typeof(existing) !== "undefined") && (existing.owner == owner)) {
×
540

541
                                                // If exists, checkin as existing device...
542
                                                _private.checkinExistingDevice(existing, reg, callback);
×
543
                                                return;
×
544

545
                                        } else {
546

547
                                                // If does not exist, search by MAC address first and if not found, create new...
548
                                                devicelib.view("devicelib", "devices_by_mac", {
×
549
                                                                key: _public.normalizedMAC(reg.mac),
550
                                                                include_docs: true
551
                                                        },
552

553
                                                        function(err, body) {
554

555
                                                                if (err) {
×
556
                                                                        console.log(
×
557
                                                                                "Device with this UUID/MAC not found. Seems like new one..."
558
                                                                        );
559
                                                                } else {
560

561
                                                                        console.log("Known device identified by MAC address: ");
×
562
                                                                        console.log(JSON.stringify(body));
×
563

564
                                                                        if (typeof(body.rows) === "undefined") {
×
565

566
                                                                                console.log("ERROR: THE BODY IS:" + JSON.stringify(body));
×
567

568
                                                                        } else {
569

570
                                                                                if (body.rows.length === 0) {
×
571
                                                                                        // device not found by mac; this is a new device...
572
                                                                                } else {
573

574
                                                                                        console.log("ROWS:" + JSON.stringify(body.rows));
×
575

576
                                                                                        // In case device does not declare UDID but valid MAC address instead,
577
                                                                                        // it will be assigned that UDID.
578
                                                                                        var xisting = body.rows[0];
×
579
                                                                                        if (typeof(xisting) !== "undefined") {
×
580
                                                                                                console.log("Checking-in existing device by known MAC...");
×
581
                                                                                                if (typeof(xisting.value) !== "undefined") {
×
582
                                                                                                        xisting = xisting.value;
×
583
                                                                                                        reg.udid = xisting.udid;
×
584
                                                                                                }
585
                                                                                                _private.checkinExistingDevice(xisting, reg, callback);
×
586
                                                                                                return;
×
587
                                                                                        } else {
588
                                                                                                console.log("No existing device...");
×
589
                                                                                        }
590
                                                                                }
591
                                                                        }
592
                                                                }
593

594
                                                                //
595
                                                                // New device
596
                                                                //
597

598
                                                                // TODO: FIXME: Add the API Key to mqtt_passwords for respective device id?
599

600
                                                                // TODO: FIXME: Create ACL on new user creation
601

602
                                                                // - search for ACL record
603
                                                                // - if found, do nothing
604
                                                                // - if not found, search for mqtt_passwords and if exists, create ACL record
605

606
                                                                console.log("[OID:" + owner +
×
607
                                                                        "] [DEVICE_NEW] New device: " + JSON.stringify(
608
                                                                                reg));
609

610
                                                                var TOOL = exec.execSync("which mosquitto_passwd").toString()
×
611
                                                                        .replace(
612
                                                                                "\n", "");
613

614
                                                                console.log("mosquitto_passwd detection result: " + TOOL);
×
615

616
                                                                if (TOOL.length > 1) {
×
617

618
                                                                        var CMD = TOOL + " -b " + app_config.project_root +
×
619
                                                                                "/mqtt_passwords " + udid +
620
                                                                                " " +
621
                                                                                api_key;
622
                                                                        var temp = exec.execSync(CMD);
×
623
                                                                        console.log("[REGISTER] Creating mqtt account..." + CMD);
×
624
                                                                        if (typeof(temp.data) !== "undefined" && temp.data.toString() !==
×
625
                                                                                "") {
626
                                                                                console.log("[REGISTER_ERROR] MQTT: " + JSON.stringify(temp));
×
627
                                                                        }
628
                                                                }
629

630
                                                                device.source = null;
×
631

632
                                                                device.lastupdate = new Date();
×
633
                                                                if (typeof(fw) !== "undefined" && fw !== null) {
×
634
                                                                        device.firmware = fw;
×
635
                                                                }
636
                                                                if (typeof(push) !== "undefined" && push !== null) {
×
637
                                                                        device.push = push;
×
638
                                                                }
639
                                                                if (typeof(alias) !== "undefined" && alias !== null) {
×
640
                                                                        device.alias = alias;
×
641
                                                                } else {
642
                                                                        device.alias = require('sillyname')();
×
643
                                                                }
644
                                                                if (typeof(platform) !== "undefined" && platform !== null) {
×
645
                                                                        device.platform = platform;
×
646
                                                                }
647

648
                                                                // Extended SigFox Support
649

650
                                                                // status, snr, station, lat, long
651
                                                                if (typeof(reg.status) !== "undefined" && reg.status !== null) {
×
652
                                                                        device.status = reg.status;
×
653
                                                                }
654

655
                                                                if (typeof(reg.snr) !== "undefined" && reg.snr !== null) {
×
656
                                                                        device.snr = reg.snr;
×
657
                                                                }
658

659
                                                                if (typeof(reg.station) !== "undefined" && reg.station !== null) {
×
660
                                                                        device.station = reg.station;
×
661
                                                                }
662

663
                                                                // Includes
664

665
                                                                if (typeof(reg.lat) !== "undefined" && reg.lat !== null) {
×
666
                                                                        device.lat = reg.lat;
×
667
                                                                }
668

669
                                                                if (typeof(reg.lon) !== "undefined" && reg.lon !== null) {
×
670
                                                                        device.lon = reg.lon;
×
671
                                                                }
672

673
                                                                console.log("Inserting known device..." + JSON.stringify(
×
674
                                                                        device));
675

676
                                                                devicelib.insert(device, udid, function(err, body,
×
677
                                                                        header) {
678
                                                                        if (!err) {
×
679
                                                                                console.log("Device info created.");
×
680
                                                                                callback(true, {
×
681
                                                                                        registration: {
682
                                                                                                success: true,
683
                                                                                                owner: owner,
684
                                                                                                alias: device.alias,
685
                                                                                                udid: udid,
686
                                                                                                status: "OK"
687
                                                                                        }
688
                                                                                });
689
                                                                                return;
×
690
                                                                        } else {
691
                                                                                reg.success = false;
×
692
                                                                                reg.status = "Insert failed";
×
693
                                                                                console.log("Device record update failed." +
×
694
                                                                                        err);
695
                                                                                console.log("CHECK6:");
×
696
                                                                                console.log(reg);
×
697
                                                                                console.log("CHECK6.1:");
×
698
                                                                                console.log(rdict);
×
699
                                                                                var json = JSON.stringify(rdict);
×
700
                                                                                callback(false, json);
×
701
                                                                        }
702
                                                                }); // insert
703
                                                        }); // view
704
                                        }
705
                                }); // get
706

707
                        }); // verify
708

709
                },
710

711
                ott_request: function(owner, body, api_key, callback) {
712
                        apikey.verify(owner, api_key, function(success, message) {
×
713
                                console.log("OTTR: " + success.toString(), message);
×
714
                                if (success) {
×
715
                                        console.log("Requesting OTT...");
×
716
                                        _public.storeOTT(body, callback);
×
717
                                } else {
718
                                        callback(false, "OTT_API_KEY_NOT_VALID");
×
719
                                }
720
                        });
721
                },
722

723
                ott_update: function(ott, callback) {
724

725
                        console.log("Fetching OTT...");
×
726

727
                        client.get("ott:" + ott, function(err, info) {
×
728

729
                                if (err) {
×
730
                                        callback(false, {
×
731
                                                success: false,
732
                                                status: "OTT_UPDATE_NOT_FOUND",
733
                                                ott: ott
734
                                        });
735
                                        console.log(err);
×
736
                                        return;
×
737
                                }
738

739
                                var ott_info = JSON.parse(info);
×
740
                                console.log("ott_info: " + JSON.stringify(ott_info));
×
741

742
                                deploy.initWithDevice(ott_info);
×
743
                                console.log("LFP for ott_info");
×
744

745
                                var path = deploy.latestFirmwarePath(ott_info.owner, ott_info.udid);
×
746
                                if ((path !== "undefined") && path !== null) {
×
747
                                        _private.updateFromPath(path, ott, callback);
×
748
                                } else {
749
                                        callback(false, {
×
750
                                                success: false,
751
                                                status: "OTT_UPDATE_NOT_AVAILABLE"
752
                                        });
753
                                }
754

755
                        });
756

757
                },
758

759
                firmware: function(body, api_key, callback) {
760

761
                        if (typeof(body.registration) !== "undefined") {
×
762
                                body = body.registration;
×
763
                        }
764

765
                        var mac = null; // will deprecate
×
766
                        var udid = body.udid;
×
767
                        var checksum = body.checksum;
×
768
                        var commit = body.commit;
×
769
                        var alias = body.alias;
×
770
                        var owner = body.owner;
×
771

772
                        var forced;
773
                        var ott = null;
×
774

775
                        // allow custom overrides
776

777
                        // Currently supported overrides:
778
                        // force = force update (re-install current firmware)
779
                        // ott = return one-time URL instead of data
780

781
                        if (typeof(body !== "undefined")) {
×
782
                                if (typeof(body.forced) !== "undefined") {
×
783
                                        forced = body.forced;
×
784
                                        console.log("forced: " + forced);
×
785
                                } else {
786
                                        forced = false;
×
787
                                }
788
                                if (typeof(body.ott) !== "undefined") {
×
789
                                        ott = body.ott;
×
790
                                        console.log("ott: " + ott);
×
791
                                } else {
792
                                        ott = null;
×
793
                                }
794
                        }
795

796

797
                        //
798
                        // Standard / Forced Update
799
                        //
800

801
                        if (typeof(body.mac) === "undefined") {
×
802
                                console.log("missing_mac in " + JSON.stringify(body));
×
803
                                callback(false, {
×
804
                                        success: false,
805
                                        status: "missing_mac"
806
                                });
807

808
                                return;
×
809
                        }
810

811
                        // Headers must contain Authentication header
812
                        if (typeof(api_key) !== "undefined") {
×
813
                                // OK
814
                        } else {
815
                                console.log("ERROR: Update requests must contain API key!");
×
816
                                callback(false, {
×
817
                                        success: false,
818
                                        status: "authentication"
819
                                });
820
                                return;
×
821
                        }
822

823
                        apikey.verify(owner, api_key, function(success, message) {
×
824

825
                                if ((success === false) && (ott === null)) {
×
826
                                        alog.log(owner, "Attempt to use invalid API Key: " +
×
827
                                                api_key +
828
                                                " on device registration.");
829
                                        callback(false, message);
×
830
                                        return;
×
831
                                }
832

833
                                alog.log(owner, "Attempt to register device: " + udid +
×
834
                                        " alias: " +
835
                                        alias);
836

837
                                devicelib.get(udid, function(err, device) {
×
838

839
                                        if (err) {
×
840
                                                console.log(err);
×
841
                                                return;
×
842
                                        }
843

844
                                        console.log(
×
845
                                                "Getting latest firmware update descriptor from envelope for: " +
846
                                                JSON.stringify(device));
847
                                        deploy.initWithDevice(device);
×
848
                                        var firmwareUpdateDescriptor = deploy.latestFirmwareEnvelope(
×
849
                                                device);
850
                                        var rmac = firmwareUpdateDescriptor.mac || mac;
×
851
                                        if (typeof(rmac) === "undefined") {
×
852
                                                throw Error("Missing MAC in device.js:778");
×
853
                                        }
854
                                        mac = _public.normalizedMAC(rmac);
×
855

856
                                        console.log(
×
857
                                                "Seaching for possible firmware update... (owner:" +
858
                                                device.owner + ")");
859

860
                                        // Check update availability
861
                                        //console.log("UA check for device");
862
                                        var updateAvailable = deploy.hasUpdateAvailable(device);
×
863

864
                                        if (updateAvailable === false) {
×
865
                                                // Find-out whether user has responded to any actionable notification regarding this device
866
                                                client.get("nid:" + udid, function(err, json_keys) {
×
867
                                                        if (!err) {
×
868
                                                                console.log(json_keys);
×
869
                                                                if (json_keys === null) return;
×
870
                                                                if (typeof(json_keys) === "undefined") return;
×
871
                                                                var not = JSON.parse(json_keys);
×
872
                                                                if ((typeof(not) !== "undefined") && not.done === true) {
×
873
                                                                        console.log(
×
874
                                                                                "Device firmware current, deleting NID notification...");
875
                                                                        client.expire("nid:" + udid, 0);
×
876
                                                                } else {
877
                                                                        console.log("Keeping nid:" + udid + ", not done yet...");
×
878
                                                                }
879
                                                        }
880
                                                });
881
                                        }
882

883
                                        // Find-out whether user has responded to any actionable notification regarding this device
884
                                        client.get("nid:" + udid, function(err, json_keys) {
×
885
                                                if (err) {
×
886
                                                        console.log("Device has no NID for actionable notification.");
×
887
                                                        // no NID, that's OK...
888
                                                        // nid will be deleted on successful download/update (e.g. when device is current)
889
                                                } else {
890
                                                        if (json_keys !== null) {
×
891
                                                                var not = JSON.parse(json_keys);
×
892
                                                                console.log("Device has NID:" + json_keys);
×
893
                                                                if (not.done === true) {
×
894
                                                                        console.log("User sent reply.");
×
895
                                                                        // update allowed by user
896
                                                                } else {
897
                                                                        console.log("Device is still waiting for reply.");
×
898
                                                                        // update not allowed by user
899
                                                                }
900
                                                        }
901
                                                }
902

903
                                                // Check path validity
904
                                                //console.log("Fetching latest firmware path for device...");
905
                                                var path = deploy.latestFirmwarePath(device.owner, device.udid);
×
906
                                                if (path === null) {
×
907
                                                        console.log("No update available.");
×
908
                                                        callback(false, {
×
909
                                                                success: false,
910
                                                                status: "UPDATE_NOT_FOUND"
911
                                                        });
912
                                                        return;
×
913
                                                }
914

915
                                                // Forced update is implemented through enforcing update availability,
916
                                                // BUT! TODO FIMXE what if no firmware is built yet? Pat must not be valid.
917
                                                if ((forced === true) && (path !== null)) {
×
918
                                                        console.log("Using force, path is not null...");
×
919
                                                        updateAvailable = true;
×
920
                                                }
921

922
                                                if (updateAvailable) {
×
923

924
                                                        // Forced update
925
                                                        if (forced === true) {
×
926
                                                                _public.updateFromPath(path, ott, callback);
×
927
                                                                return;
×
928
                                                        }
929

930
                                                        // Start OTT Update
931
                                                        if (ott !== null) {
×
932
                                                                console.log("Requesting OTT update...");
×
933
                                                                _public.ott_request(owner, body, api_key, callback);
×
934
                                                                // Perform OTT Update
935
                                                        } else if (ott === null) {
×
936
                                                                console.log("Requesting normal update...");
×
937
                                                                _public.updateFromPath(path, ott, callback);
×
938
                                                        }
939

940
                                                } else {
941
                                                        console.log("No firmware update available for " +
×
942
                                                                JSON.stringify(device));
943
                                                        callback(false, {
×
944
                                                                success: false,
945
                                                                status: "OK"
946
                                                        });
947
                                                }
948
                                        });
949
                                }); // device
950
                        }); // apikey
951
                },
952

953
                edit: function(owner, changes, callback) {
954

955
                                if (typeof(changes) === "undefined") {
×
956
                                        callback(false, "changes_undefined");
×
957
                                        return;
×
958
                                }
959

960
                                var change = changes; // bulk operations are not required so far
×
961
                                var udid;
962

963
                                udid = change.udid;
×
964
                                console.log("Processing change " + JSON.stringify(change) +
×
965
                                        " for udid " +
966
                                        udid);
967

968
                                if (udid !== null) {
×
969

970
                                        if (typeof(owner) === "undefined") {
×
971
                                                callback(false, "owner_undefined");
×
972
                                                return;
×
973
                                        }
974

975
                                        if (typeof(udid) === "undefined") {
×
976
                                                callback(false, "udid_undefined");
×
977
                                                return;
×
978
                                        }
979

980
                                        update_device(owner, udid, change, callback);
×
981
                                }
982

983
                                function update_device(owner, udid, changes, update_callback) {
984

985
                                        devicelib.view("devicelib", "devices_by_owner", {
×
986
                                                        key: owner,
987
                                                        include_docs: true
988
                                                },
989

990
                                                function(err, body) {
991

992
                                                        if (err) {
×
993
                                                                console.log(err);
×
994
                                                                update_callback(false, {
×
995
                                                                        success: false,
996
                                                                        status: "device_not_found"
997
                                                                });
998
                                                                return;
×
999
                                                        }
1000

1001
                                                        if (body.rows.length === 0) {
×
1002
                                                                //console.log(JSON.stringify(body));
1003
                                                                update_callback(false, {
×
1004
                                                                        success: false,
1005
                                                                        status: "no_such_device"
1006
                                                                });
1007
                                                                return;
×
1008
                                                        }
1009
                                                        var doc;
1010
                                                        for (var dindex in body.rows) {
×
1011
                                                                if (body.rows[dindex].hasOwnProperty("value")) {
×
1012
                                                                        var dev = body.rows[dindex].value;
×
1013
                                                                        if (udid.indexOf(dev.udid) != -1) {
×
1014
                                                                                doc = dev;
×
1015
                                                                                break;
×
1016
                                                                        }
1017
                                                                }
1018
                                                        }
1019

1020
                                                        if (typeof(doc) === "undefined") return;
×
1021

1022
                                                        if (typeof(change.alias) !== "undefined") {
×
1023
                                                                doc.alias = change.alias;
×
1024
                                                        }
1025

1026
                                                        if (typeof(change.owner) !== "undefined") {
×
1027
                                                                doc.owner = change.owner;
×
1028
                                                        }
1029

1030
                                                        if (typeof(change.keyhash) !== "undefined") {
×
1031
                                                                doc.keyhash = change.keyhash;
×
1032
                                                        }
1033

1034
                                                        if (typeof(change.auto_update) !== "undefined") {
×
1035
                                                                doc.auto_update = change.auto_update;
×
1036
                                                        }
1037

1038
                                                        if (typeof(change.description) !== "undefined") {
×
1039
                                                                doc.description = change.description;
×
1040
                                                        }
1041

1042
                                                        if (typeof(change.category) !== "undefined") {
×
1043
                                                                doc.category = change.category;
×
1044
                                                        }
1045

1046
                                                        if (typeof(change.tags) !== "undefined") {
×
1047
                                                                doc.tags = change.tags;
×
1048
                                                        }
1049

1050
                                                        if (typeof(change.icon) !== "undefined") {
×
1051
                                                                doc.icon = change.icon;
×
1052
                                                        }
1053

1054
                                                        devicelib.atomic("devicelib", "modify", udid, doc, function(err, body) {
×
1055
                                                                if (err) {
×
1056
                                                                        console.log("/api/device/edit ERROR:" + err);
×
1057
                                                                        update_callback(false, {
×
1058
                                                                                success: false,
1059
                                                                                status: "device_not_changed"
1060
                                                                        });
1061
                                                                } else {
1062
                                                                        update_callback(true, {
×
1063
                                                                                success: true,
1064
                                                                                change: change
1065
                                                                        });
1066
                                                                }
1067
                                                        });
1068

1069
                                                });
1070
                                } // inline func end
1071
                        } // edit:
1072
        };
1073

1074
        return _public;
1✔
1075

1076
})();
1077

1078
exports.register = Device.register;
1✔
1079
exports.ott_request = Device.ott_request;
1✔
1080
exports.ott_update = Device.ott_update;
1✔
1081
exports.firmware = Device.firmware;
1✔
1082
exports.edit = Device.edit;
1✔
1083
exports.normalizedMAC = Device.normalizedMAC;
1✔
1084

1085
// Internals requiring <testability
1086

1087
exports.storeOTT = Device.storeOTT;
1✔
1088
exports.fetchOTT = Device.fetchOTT;
1✔
1089

1090
// Private
1091

1092
//exports.updateFromPath = Device.updateFromPath;
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc