cjdns.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. var dgram = require('dgram'),
  2. bencode = require('bencode'),
  3. sys = require('util'),
  4. crypto = require('crypto'),
  5. path = require('path'),
  6. fs = require('fs');
  7. var CJDNS = function (config) {
  8. if (!config.config) {
  9. throw 'Please, add "config":"path/to/your/cjdroute.conf" to ~/.cjdnsadmin file!';
  10. }
  11. this.configFile = path.resolve(config.config.replace(/^~\//, process.env.HOME + '/'));
  12. this.config = fs.readFileSync(this.configFile);
  13. if (!this.config) {
  14. throw 'Can\'t read config file! path: ' + this.configFile;
  15. }
  16. this.oldConfig = this.config;
  17. this.parseConfig();
  18. this.host = (this.config.admin.bind || 'localhost:11234').split(':');
  19. this.port = this.host[1] || '80';
  20. this.host = this.host[0];
  21. this.password = this.config.admin.password;
  22. this.send({q: 'ping'}, function (err, msg) {
  23. if (msg && msg.q === 'pong') {
  24. sys.log('Cjdns Admin backend found and ready to work!');
  25. } else {
  26. sys.log(msg);
  27. }
  28. });
  29. };
  30. CJDNS.prototype.parseConfig = function() {
  31. var config;
  32. eval('config = ' + this.config);
  33. this.config = config;
  34. };
  35. CJDNS.prototype.checkConfig = function (config) {
  36. return config && config.UDPInterface && config.UDPInterface[0] && config.UDPInterface[0].connectTo;
  37. };
  38. CJDNS.prototype.saveConfig = function(newConfig, callback) {
  39. var cjdns = this,
  40. conf,
  41. reserveConf;
  42. if (this.checkConfig(newConfig)) {
  43. conf = JSON.parse(JSON.stringify(this.config));
  44. conf.interfaces = newConfig;
  45. this.config = JSON.parse(JSON.stringify(conf));
  46. conf = JSON.stringify(conf, null, 4);
  47. reserveConf = path.dirname(this.configFile) + '/' + path.basename(this.configFile) + '.' + (new Date()).getTime() + path.extname(this.configFile);
  48. //save current version to yourConfDir/<confName>.<timestamp>.conf
  49. fs.writeFile(
  50. reserveConf,
  51. this.oldConfig,
  52. function (err, data) {
  53. if (!err) {
  54. //save new config only if old conf saved!
  55. fs.writeFile(cjdns.configFile, conf, function (err, data) {
  56. callback(err, {
  57. msg: 'Old config saved to "' + reserveConf + '"'
  58. });
  59. });
  60. cjdns.oldConfig = conf;
  61. } else {
  62. callback({
  63. error: 'Can\'t save old config!'
  64. },{
  65. msg: 'Can\'t save old config!'
  66. });
  67. }
  68. }
  69. );
  70. } else {
  71. callback({
  72. error: 'Config is not valid!'
  73. });
  74. }
  75. };
  76. CJDNS.prototype.send = function(data, callback, otherSocket) {
  77. var msg = new Buffer(bencode.encode(data)),
  78. socket = otherSocket || dgram.createSocket('udp4');
  79. socket.on('message', function (msg) {
  80. var response = bencode.decode(msg, 'utf8');
  81. callback(null, response);
  82. if (!otherSocket) {
  83. socket.close();
  84. }
  85. });
  86. socket.send(msg, 0, msg.length, this.port, this.host, function(err, bytes) {
  87. if (err) {
  88. callback(err);
  89. }
  90. });
  91. };
  92. CJDNS.prototype.sendAuth = function(data, callback, otherSocket) {
  93. var cjdns = this,
  94. request = {
  95. q: 'auth',
  96. aq: data.q
  97. };
  98. if (data.args) {
  99. request.args = data.args;
  100. }
  101. function makeHash (password, cookie, request) {
  102. var hash = password + '' + cookie,
  103. sha256 = crypto.createHash('sha256');
  104. sha256.update(hash);
  105. hash = sha256.digest('hex');
  106. request.hash = hash;
  107. hash = bencode.encode(request);
  108. sha256 = crypto.createHash('sha256');
  109. sha256.update(hash);
  110. hash = sha256.digest('hex');
  111. return hash;
  112. }
  113. this.send({q:'cookie'}, function (err, data) {
  114. if (err) {
  115. callback(err);
  116. return;
  117. }
  118. request.cookie = data.cookie;
  119. request.hash = makeHash(cjdns.password, request.cookie, request);
  120. cjdns.send(request, callback, otherSocket);
  121. });
  122. };
  123. CJDNS.prototype.subscribe = function (callback) {
  124. var logsSocket = dgram.createSocket('udp4'),
  125. cjdns = this;
  126. if (this.logsId) {
  127. this.unsubscribe();
  128. }
  129. if (this.logsPing) {
  130. clearInterval(this.logsPing);
  131. this.logsPing = undefined;
  132. }
  133. this.sendAuth({
  134. q: 'AdminLog_subscribe',
  135. args: {
  136. level: 'KEYS'
  137. }
  138. }, callback, logsSocket);
  139. this.logsPing = setInterval(function () {
  140. cjdns.sendAuth({
  141. q: 'ping'
  142. }, function () {}, logsSocket);
  143. }, 9000);
  144. };
  145. CJDNS.prototype.unsubscribe = function (callback) {
  146. if (this.logsId) {
  147. this.sendAuth({
  148. q: 'AdminLog_unsubscribe',
  149. args: {
  150. streamId: this.logsId
  151. }
  152. });
  153. }
  154. };
  155. module.exports = CJDNS;