| 
									
										
										
										
											2017-07-06 11:01:29 -06:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var PromiseA = require('bluebird'); | 
					
						
							|  |  |  | var path = require('path'); | 
					
						
							|  |  |  | var fs = PromiseA.promisifyAll(require('fs')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports.create = function (deps, conf) { | 
					
						
							| 
									
										
										
										
											2017-07-07 17:53:12 -06:00
										 |  |  |   var hrIds = require('human-readable-ids').humanReadableIds; | 
					
						
							| 
									
										
										
										
											2017-07-06 11:01:29 -06:00
										 |  |  |   var scmp = require('scmp'); | 
					
						
							|  |  |  |   var storageDir = path.join(__dirname, '..', 'var'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function read(fileName) { | 
					
						
							|  |  |  |     return fs.readFileAsync(path.join(storageDir, fileName)) | 
					
						
							|  |  |  |     .then(JSON.parse, function (err) { | 
					
						
							| 
									
										
										
										
											2017-07-07 13:48:40 -06:00
										 |  |  |       if (err.code === 'ENOENT') { | 
					
						
							| 
									
										
										
										
											2017-07-06 11:01:29 -06:00
										 |  |  |         return {}; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       throw err; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   function write(fileName, obj) { | 
					
						
							|  |  |  |     return fs.mkdirAsync(storageDir).catch(function (err) { | 
					
						
							|  |  |  |       if (err.code !== 'EEXIST') { | 
					
						
							|  |  |  |         console.error('failed to mkdir', storageDir, err.toString()); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }).then(function () { | 
					
						
							|  |  |  |       return fs.writeFileAsync(path.join(storageDir, fileName), JSON.stringify(obj), 'utf8'); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   var owners = { | 
					
						
							|  |  |  |     _filename: 'owners.json' | 
					
						
							|  |  |  |   , all: function () { | 
					
						
							|  |  |  |       return read(this._filename).then(function (owners) { | 
					
						
							|  |  |  |         return Object.keys(owners).map(function (id) { | 
					
						
							|  |  |  |           var owner = owners[id]; | 
					
						
							|  |  |  |           owner.id = id; | 
					
						
							|  |  |  |           return owner; | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   , get: function (id) { | 
					
						
							|  |  |  |       // While we could directly read the owners file and access the id directly from
 | 
					
						
							|  |  |  |       // the resulting object I'm not sure of the details of how the object key lookup
 | 
					
						
							|  |  |  |       // works or whether that would expose us to timing attacks.
 | 
					
						
							|  |  |  |       // See https://codahale.com/a-lesson-in-timing-attacks/
 | 
					
						
							|  |  |  |       return this.all().then(function (owners) { | 
					
						
							|  |  |  |         return owners.filter(function (owner) { | 
					
						
							|  |  |  |           return scmp(id, owner.id); | 
					
						
							|  |  |  |         })[0]; | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   , exists: function (id) { | 
					
						
							|  |  |  |       return this.get(id).then(function (owner) { | 
					
						
							|  |  |  |         return !!owner; | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   , set: function (id, obj) { | 
					
						
							|  |  |  |       var self = this; | 
					
						
							|  |  |  |       return read(self._filename).then(function (owners) { | 
					
						
							|  |  |  |         obj.id = id; | 
					
						
							|  |  |  |         owners[id] = obj; | 
					
						
							|  |  |  |         return write(self._filename, owners); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-10 11:08:19 -06:00
										 |  |  |   var confCb; | 
					
						
							| 
									
										
										
										
											2017-07-06 11:01:29 -06:00
										 |  |  |   var config = { | 
					
						
							|  |  |  |     save: function (changes) { | 
					
						
							|  |  |  |       deps.messenger.send({ | 
					
						
							| 
									
										
										
										
											2017-07-06 13:09:20 -06:00
										 |  |  |         type: 'com.daplie.goldilocks/config' | 
					
						
							| 
									
										
										
										
											2017-07-06 11:01:29 -06:00
										 |  |  |       , changes: changes | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-10-10 11:08:19 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |       return new deps.PromiseA(function (resolve, reject) { | 
					
						
							|  |  |  |         var timeoutId = setTimeout(function () { | 
					
						
							|  |  |  |           reject(new Error('Did not receive config update from main process in a reasonable time')); | 
					
						
							|  |  |  |           confCb = null; | 
					
						
							|  |  |  |         }, 15*1000); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         confCb = function (config) { | 
					
						
							|  |  |  |           confCb = null; | 
					
						
							|  |  |  |           clearTimeout(timeoutId); | 
					
						
							|  |  |  |           resolve(config); | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2017-07-06 11:01:29 -06:00
										 |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2017-10-10 11:08:19 -06:00
										 |  |  |   function updateConf(config) { | 
					
						
							|  |  |  |     if (confCb) { | 
					
						
							|  |  |  |       confCb(config); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-07-06 11:01:29 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-07 17:53:12 -06:00
										 |  |  |   var mdnsId = { | 
					
						
							|  |  |  |     _filename: 'mdns-id' | 
					
						
							|  |  |  |   , get: function () { | 
					
						
							|  |  |  |       var self = this; | 
					
						
							|  |  |  |       return read("mdns-id").then(function (result) { | 
					
						
							|  |  |  |         if (typeof result !== 'string') { | 
					
						
							|  |  |  |           throw new Error('mDNS ID not present'); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return result; | 
					
						
							|  |  |  |       }).catch(function () { | 
					
						
							|  |  |  |         return self.set(hrIds.random()); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   , set: function (value) { | 
					
						
							|  |  |  |       var self = this; | 
					
						
							|  |  |  |       return write(self._filename, value).then(function () { | 
					
						
							|  |  |  |         return self.get(); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-06 11:01:29 -06:00
										 |  |  |   return { | 
					
						
							|  |  |  |     owners: owners | 
					
						
							|  |  |  |   , config: config | 
					
						
							| 
									
										
										
										
											2017-10-10 11:08:19 -06:00
										 |  |  |   , updateConf: updateConf | 
					
						
							| 
									
										
										
										
											2017-07-07 17:53:12 -06:00
										 |  |  |   , mdnsId: mdnsId | 
					
						
							| 
									
										
										
										
											2017-07-06 11:01:29 -06:00
										 |  |  |   }; | 
					
						
							|  |  |  | }; |