<commit_before>'use strict';
const Path = require('path');
const Fs = require('fs');
const Crypto = require('crypto');
const streamifier = require('streamifier');
const toArray = require('stream-to-array');
const tar = require('tar-stream');
const request = require('request');
const requestp = require('request-promise');

const config = require(Path.join(__dirname, 'config'));

const cert = Fs.readFileSync(Path.resolve(__dirname, config.cert_path));
const key = Fs.readFileSync(Path.resolve(__dirname, config.key_path));
const ca = Fs.readFileSync(Path.resolve(__dirname, config.update_server_ca_cert));
const signing_key = Fs.readFileSync(Path.resolve(__dirname, config.signing_server_pubkey));

function checkForUpdates () {
  console.log('uLinux Device Updater Daemon: Checking for updates');
  return new Promise(function(resolve, reject) {

    requestp.post({
      url: 'https://' + config.update_server + '/newUpdate',
      cert: cert,
      key: key,
      ca: ca,
      form: {
        timestamp: getLatestUpdateTimestamp(),
      },
      json: true
    }).then(function (res) {
      if (res.message) {
        resolve(res.updateId);
      } else {
        reject('No new update found!');
      }
    }).catch(function (err) {
      let wrapper = new Error('Got an error checking for updates');
      wrapper.cause = err;
      reject(wrapper);
    });

  });
}

function getLatestUpdateTimestamp() {
  let timestamp;

  try {
    timestamp = parseInt(Fs.readFileSync(
      Path.join(__dirname, 'last_update'),  { encoding: 'UTF-8' }
    ));
  } catch (error) {
    // File does not exist (never updated before), use UNIX epoch
    timestamp = 0;
  }

  return timestamp;
}

function downloadImage (updateId) {
  console.log('uLinux Device Updater Daemon: Downloading update with id ' + updateId);
  return new Promise(function(resolve, reject) {

    request.get({
      url: 'https://' + config.update_server + '/updates/' + updateId,
      cert: cert,
      key: key,
      ca: ca,
      encoding: null,
    }, function (err, response, body) {
      if (err) {
        let wrapper = new Error('Got an error retrieving the update image.');
        wrapper.cause = err;
        reject(wrapper);
      }
      else if (response.headers['content-type'].indexOf('application/json') != -1) {
        // Some error message
        let wrapper = new Error('Got an error retrieving the update image.');
        try {
          wrapper.cause = JSON.parse(new String(body, 'UTF-8'));
        } catch (e) {
          wrapper.cause =
            new Error('Could not parse error message produced by the API');
        }
        reject(wrapper);
      } else {
        // We're actually getting the file
        resolve(body);
      }
    });
  });
}

function verifyImage (buffer) {
  console.log('uLinux Device Updater Daemon: Verifying image');
  const pack = streamifier.createReadStream(buffer);
  const extract = tar.extract();

  let image, signature;

  return new Promise(function(resolve, reject) {
    extract.on('entry', function(header, stream, callback) {
      // header is the tar header
      // stream is the content body (might be an empty stream)
      // call next when you are done with this entry

      toArray(stream)
        .then(function (parts) {
          // concatenate all the array entries into the same buffer
          let buffers = [];
          for (let i = 0, l = parts.length; i < l ; ++i) {
            const part = parts[i];
            buffers.push((part instanceof Buffer) ? part : new Buffer(part));
          }

          let resBuffer = Buffer.concat(buffers);

          if (header.name === 'signature.txt') {
            signature = resBuffer.toString();
          }

          if (header.name === 'image.img') {
            image = resBuffer;
          }

          callback(); // tar-stream requires calling this to begin nexy entry
        });

    });

    const verify = Crypto.createVerify('RSA-SHA512');
    extract.on('finish', () => {
      if (!signature || !image) {
        reject(new Error('Signature or image is missing from downloaded tar file.'));
      } else {
        verify.write(image);
        verify.end();
        if(verify.verify(signing_key, signature, 'base64')){
          resolve(image);
        } else {
          reject(new Error('Image signature was not successfully verified.'));
        }
      }
    });

    pack.pipe(extract);

  });
}

function writeImageToDisk (buffer) {
  console.log('uLinux Device Updater Daemon: writing image to disk');
  Fs.writeFile(Path.join(__dirname, 'test'), buffer);
  // Save the timestamp for this update
  Fs.writeFile(Path.join(__dirname, 'last_update'), Math.round(Date.now()/1000));
}

function reboot () {
  // Perform reboot
  console.log('uLinux Device Updater Daemon: Rebooting device');
}

function performUpdate() {
  checkForUpdates()
    .then(downloadImage)
    .then(verifyImage)
    .then(writeImageToDisk)
    .then(reboot)
    .catch(function (err) {
      console.error('uLinux Device Updater Daemon:', err);
    });
}<commit_msg>porting to node v0.12<commit_after>'use strict';
var Path = require('path');
var Fs = require('fs');
var Crypto = require('crypto');
var streamifier = require('streamifier');
var toArray = require('stream-to-array');
var tar = require('tar-stream');
var request = require('request');
var requestp = require('request-promise');

var config = require(Path.join(__dirname, 'config'));

var cert = Fs.readFileSync(Path.resolve(__dirname, config.cert_path));
var key = Fs.readFileSync(Path.resolve(__dirname, config.key_path));
var ca = Fs.readFileSync(Path.resolve(__dirname, config.update_server_ca_cert));
var signing_key = Fs.readFileSync(Path.resolve(__dirname, config.signing_server_pubkey));

function checkForUpdates () {
  console.log('uLinux Device Updater Daemon: Checking for updates');
  return new Promise(function(resolve, reject) {

    requestp.post({
      url: 'https://' + config.update_server + '/newUpdate',
      cert: cert,
      key: key,
      ca: ca,
      form: {
        timestamp: getLatestUpdateTimestamp(),
      },
      json: true
    }).then(function (res) {
      if (res.message) {
        resolve(res.updateId);
      } else {
        reject('No new update found!');
      }
    }).catch(function (err) {
      var wrapper = new Error('Got an error checking for updates');
      wrapper.cause = err;
      reject(wrapper);
    });

  });
}

function getLatestUpdateTimestamp() {
  var timestamp;

  try {
    timestamp = parseInt(Fs.readFileSync(
      Path.join(config.image_path, '..', 'last_update'),  { encoding: 'UTF-8' }
    ));
  } catch (error) {
    // File does not exist (never updated before), use UNIX epoch
    timestamp = 0;
  }

  return timestamp;
}

function downloadImage (updateId) {
  console.log('uLinux Device Updater Daemon: Downloading update with id ' + updateId);
  return new Promise(function(resolve, reject) {

    request.get({
      url: 'https://' + config.update_server + '/updates/' + updateId,
      cert: cert,
      key: key,
      ca: ca,
      encoding: null,
    }, function (err, response, body) {
      if (err) {
        var wrapper = new Error('Got an error retrieving the update image.');
        wrapper.cause = err;
        reject(wrapper);
      }
      else if (response.headers['content-type'].indexOf('application/json') != -1) {
        // Some error message
        var wrapper = new Error('Got an error retrieving the update image.');
        try {
          wrapper.cause = JSON.parse(new String(body, 'UTF-8'));
        } catch (e) {
          wrapper.cause =
            new Error('Could not parse error message produced by the API');
        }
        reject(wrapper);
      } else {
        // We're actually getting the file
        resolve(body);
      }
    });
  });
}

function verifyImage (buffer) {
  console.log('uLinux Device Updater Daemon: Verifying image');
  var pack = streamifier.createReadStream(buffer);
  var extract = tar.extract();

  var image, signature;

  return new Promise(function(resolve, reject) {
    extract.on('entry', function(header, stream, callback) {
      // header is the tar header
      // stream is the content body (might be an empty stream)
      // call next when you are done with this entry

      toArray(stream)
        .then(function (parts) {
          // concatenate all the array entries into the same buffer
          var buffers = [];
          for (var i = 0, l = parts.length; i < l ; ++i) {
            var part = parts[i];
            buffers.push((part instanceof Buffer) ? part : new Buffer(part));
          }

          var resBuffer = Buffer.concat(buffers);

          if (header.name === 'signature.txt') {
            signature = resBuffer.toString();
          }

          if (header.name === 'image.img') {
            image = resBuffer;
          }

          callback(); // tar-stream requires calling this to begin nexy entry
        });

    });

    var verify = Crypto.createVerify('RSA-SHA512');
    extract.on('finish', function () {
      if (!signature || !image) {
        reject(new Error('Signature or image is missing from downloaded tar file.'));
      } else {
        verify.write(image);
        verify.end();
        if(verify.verify(signing_key, signature, 'base64')){
          resolve(image);
        } else {
          reject(new Error('Image signature was not successfully verified.'));
        }
      }
    });

    pack.pipe(extract);

  });
}

function writeImageToDisk (buffer) {
  console.log('uLinux Device Updater Daemon: writing image to disk');
  Fs.writeFile(config.image_path, buffer, function (err) {
    if (err) {
      console.log(err);
    }
  });
  // Save the timestamp for this update
  Fs.writeFile(Path.join(config.image_path, '..', 'last_update'), Math.round(Date.now()/1000), function (err) {
    if (err) {
      console.log(err);
    }
  });

}

function reboot () {
  // Perform reboot
  console.log('uLinux Device Updater Daemon: Rebooting device');
}

function performUpdate() {
  checkForUpdates()
    .then(downloadImage)
    .then(verifyImage)
    .then(writeImageToDisk)
    .then(reboot)
    .catch(function (err) {
      console.error('uLinux Device Updater Daemon:', err);
    });
}
{'fraction_non_alphanumeric': 0.13524031912823506, 'fraction_numerical': 0.0030161510021404943, 'mean_word_length': 2.6515097690941385, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 4, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5839402', 'n_tokens_mistral': 3045, 'n_tokens_neox': 2966, 'n_words': 817}