| 
							- const TEMP_DIR = ".tmp-zips/";
 - const CUR_VER_PREFIX = '0.5';
 - const MF_DIR = 'plugins';
 - const fs = require("fs");
 - 
 - const Ajv = require('ajv'); //https://github.com/epoberezkin/ajv
 - const ajv = new Ajv({allErrors:true});
 - const validate = ajv.compile(require('./manifest.json'));
 - 
 - const request = require("request");
 - const { execSync } = require('child_process');
 - const AdmZip = require('adm-zip'); //https://github.com/cthackers/adm-zip
 - const hashFiles = require('hash-files'); //https://github.com/mac-/hash-files
 - const manifestsToTest = getManifestsThatApply();
 - 
 - if(manifestsToTest.length === 0){
 -     console.log("No manifest files to test.");
 -     return;
 - }
 - 
 - //virus total stuff
 - const VIRUS_TOTAL_ENABLED = false;
 - const vt = require("node-virustotal"); //https://github.com/natewatson999/node-virustotal
 - const con = vt.MakePublicConnection();
 - if(VIRUS_TOTAL_ENABLED){
 -     con.setKey(process.env.VT_API_KEY);
 -     con.setDelay(15000);
 -     jasmine.DEFAULT_TIMEOUT_INTERVAL = manifestsToTest.length * 4 * con.getDelay();
 - }
 - 
 - describe("test manifests", function() {
 -     
 -     beforeEach(()=>{
 -         execSync(`mkdir -p ${TEMP_DIR}`)
 -     });
 -     
 -     afterEach(()=>{
 -         execSync(`rm ${TEMP_DIR}*.zip`)
 -         fs.rmdirSync(TEMP_DIR);
 -     });
 - 
 -     const testMF = (filePath) => {
 -         it("valid properties and zip files", function(done) {
 - 
 -             try {
 -                 if (!filePath.toLowerCase().endsWith('.json')) {
 -                     fail("manifests should have .json extension");
 -                 }
 - 
 -                 const fileContent = fs.readFileSync(filePath, 'utf8');
 -                 const mfObj = JSON.parse(fileContent);
 -                 const valid = validate(mfObj);
 -                 if (!valid) {
 -                     validate.errors.map(e => e.message += ` in ${filePath}`)
 -                     fail(validate.errors);
 -                 }
 - 
 -                 if (!(/^[a-zA-Z0-9_\-]*$/).test(mfObj.slug)) {
 -                     fail(`slug does not match regex in ${filePath}`);
 -                 }
 - 
 -                 const fileName = filePath.replace('plugins/', '');
 -                 if (fileName.replace('.json', '') !== mfObj.slug) {
 -                     fail(`slug '${mfObj.slug}' does not match fileName: ${fileName}`);
 -                 }
 - 
 -                 if (mfObj.version && !mfObj.version.startsWith(CUR_VER_PREFIX)) {
 -                     fail(`version '${mfObj.version}' must start with '${CUR_VER_PREFIX}'`);
 -                 }
 - 
 -                 if(mfObj.downloads){
 -                     const urlsChecked = [];
 -                     let lastSha256;
 -                     ['win', 'lin', 'mac'].map(os => {
 -                         const osObj = mfObj.downloads[os];
 -                         if(osObj && osObj.download && osObj.sha256){
 -                             const zipUrl = osObj.download;
 -                             if(urlsChecked.includes(zipUrl)){
 -                                 if(lastSha256 !== osObj.sha256){
 -                                     fail("SHA256 should be the same if the download URL is the same");
 -                                 }
 -                             } else {
 -                                 urlsChecked.push(zipUrl);
 -                                 lastSha256 = osObj.sha256;
 -                                 testOneZip(mfObj.slug, osObj, done);
 -                             }
 -                         }
 -                     });
 -                 }
 - 
 -             } catch(err){
 -                 fail(`Error while trying to validate manifest: ${filePath}\n${err}`);
 -             }
 -         });
 -     };
 - 
 -     manifestsToTest.map(testMF);
 - });
 - 
 - function testOneZip(expectedRootDir, osObj, done) {
 -     const urlParts = osObj.download.split('/');
 -     const zipName = urlParts[urlParts.length - 1].split('\?')[0];
 -     request(osObj.download).pipe(fs.createWriteStream(TEMP_DIR+zipName)).on('finish', ()=>{
 - 
 -         console.log(`Downloaded ${TEMP_DIR+zipName}`);
 -         const zip = new AdmZip(TEMP_DIR+zipName);
 -         const zipEntries = zip.getEntries();
 -         // zipEntries.map(ze=>console.log(ze.toString()));
 - 
 -         const slugDirFound = zipEntries.find(ze => ze.isDirectory && 
 -             (ze.entryName === expectedRootDir+'/' || ze.entryName === expectedRootDir+'\\')
 -         );
 -         
 -         if(slugDirFound){
 -             const invalidEntry = zipEntries.find(ze => !ze.entryName.startsWith(slugDirFound.entryName));
 -             if(invalidEntry){
 -                 fail(`Zip entries should all be under a dir named ${expectedRootDir} but this entry was found: ${invalidEntry.entryName}`);
 -             }
 -         } else {
 -             fail(`Zip should have one dir named ${expectedRootDir}`);            
 -         }
 - 
 - 
 -         if(VIRUS_TOTAL_ENABLED){
 -             con.FileEvaluation(zipName, "application/zip", fs.readFileSync(TEMP_DIR+zipName), function(data) {
 -                 console.log(data);
 -                 if(osObj.sha256 !== data.sha256){
 -                     throw new Error(`Invalid sha256 value.  manifest:${osObj.sha256} virustotal:${data.sha256}`);
 -                 }
 -                 if(data.positives > 2){
 -                     throw new Error(`Too many positives from virustotal.`);   
 -                 }
 -                 done();
 -             }, function(err) {
 -                 if (err){ throw err; }
 -                 done();
 -             });
 -         } else {
 -             hashFiles({files:[TEMP_DIR+zipName], algorithm:'sha256'}, function(error, hash) {
 -                 if(osObj.sha256 !== hash){
 -                     throw new Error(`Invalid sha256 value.  manifest:${osObj.sha256} hash:${hash}`);
 -                 }
 -                 done();
 -             });
 -         }
 -     });
 - }
 - 
 - function getManifestsThatApply(){
 -     let paths = "";
 -     if(process.env.TEST_MANIFEST){
 -          paths = process.env.TEST_MANIFEST;
 -     } else {
 -         paths = execSync(`git diff -w --stat --name-only origin/master -- ${MF_DIR}/`, {encoding:'utf8'});
 -     }
 -     return paths.trim().split('\n').filter(s=>s.trim() !== '');
 - }
 
 
  |