|
- const fs = require("fs");
- const request = require("request");
- const { exec } = require('child_process');
- const vt = require("node-virustotal");//https://github.com/natewatson999/node-virustotal
- const con = vt.MakePublicConnection();
- const archArr = ['win', 'lin', 'mac'];
- const verbose = true;
-
- //VT_API_KEY is set in travisci (or set when run locally)
- con.setKey(process.env.VT_API_KEY);
- if(verbose){console.log('key', con.getKey());}
-
- //15 seconds between calls is required by virus total (4 per minute)
- //https://www.virustotal.com/en/documentation/public-api/v2/
- con.setDelay(15000);
- if(verbose){console.log('delay', con.getDelay());}
-
- //We always just check all JSON because it's easy.
- //However, we only want to check zip files of manifests that have changed.
- exec('git diff -w --stat --name-only origin/master -- plugins/', (error, stdout, stderr) => {
- if (error) {
- console.error(`exec error: ${error}`);
- return;
- }
- const changedManifestFiles = stdout.trim().split('\n');
- testAllManifests(changedManifestFiles);
- });
-
- function testAllManifests(changedManifestFiles){
- console.log("changedManifestFiles", changedManifestFiles);
- fs.readdir('plugins', function(err, files) {
- if (err){ throw err; }
-
- for (let index in files) {
- const filePath = `plugins/${files[index]}`;
- if(!filePath.toLowerCase().endsWith('.json')){
- throw new Error("manifests should have .json extension");
- }
- fs.readFile(filePath, 'utf8', (err, data) => {
- if (err){ throw err; }
- if(verbose){console.log("testing: ", filePath);}
-
- const shouldTestZip = changedManifestFiles.includes(filePath);
- testOneManifest(filePath, data, shouldTestZip);
- });
- }
- });
- }
-
- function testOneManifest(filePath, fileContent, shouldTestZip = false) {
- let manifestObj;
- try {
- manifestObj = JSON.parse(fileContent);
- } catch(err){
- console.error(`Invalid JSON: ${filePath}`);
- throw err;
- }
-
- if (manifestObj.downloads) {
- let zipUrlsChecked = [];
- let lastSha256;
-
- archArr.map(arch => {
- const archObj = manifestObj.downloads[arch];
- if (archObj && archObj.download) {
- if(zipUrlsChecked.includes(archObj.download)){
- if(lastSha256 !== archObj.sha256){
- throw new Error('SHA256 should be the same if the download URL is the same.');
- }
- } else {
- zipUrlsChecked.push(archObj.download);
- lastSha256 = archObj.sha256;
-
- if(shouldTestZip){
- testOneArch(archObj);
- } else {
- if(verbose){console.log("not testing zip because the manifest hasn't changed: ", filePath);}
- }
- }
- }
- });
- }
- }
-
- function testOneArch(archObj) {
- const urlParts = archObj.download.split('/');
- const zipName = urlParts[urlParts.length - 1].split('\?')[0];
- if(verbose){console.log(`Downloading ${archObj.download}`);}
- request(archObj.download).pipe(fs.createWriteStream(zipName)).on('finish', ()=>{
- con.FileEvaluation(zipName, "application/zip", fs.readFileSync(zipName), function(data) {
- console.log(data);
- if(archObj.sha256 !== data.sha256){
- throw new Error(`Invalid sha256 value. manifest:${archObj.sha256} virustotal:${data.sha256}`);
- }
- if(data.positives > 2){
- throw new Error(`Too many positives from virustotal.`);
- }
- }, function(err) {
- if (err){ throw err; }
- });
- });
- }
|