You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

120 lines
4.3KB

  1. const TEMP_DIR = ".tmp-zips/";
  2. const fs = require("fs");
  3. const request = require("request");
  4. const { execSync } = require('child_process');
  5. const AdmZip = require('adm-zip'); //https://github.com/cthackers/adm-zip
  6. const hashFiles = require('hash-files'); //https://github.com/mac-/hash-files
  7. const manifestsToTest = getManifestsThatApply();
  8. if(manifestsToTest.length === 0){
  9. console.log("No manifest zip files to test.");
  10. process.exit(0);
  11. }
  12. //virus total stuff
  13. const VIRUS_TOTAL_ENABLED = false;
  14. const vt = require("node-virustotal"); //https://github.com/natewatson999/node-virustotal
  15. const con = vt.MakePublicConnection();
  16. if(VIRUS_TOTAL_ENABLED){
  17. con.setKey(process.env.VT_API_KEY);
  18. con.setDelay(15000);
  19. jasmine.DEFAULT_TIMEOUT_INTERVAL = manifestsToTest.length * 4 * con.getDelay();
  20. }
  21. describe("zips", function() {
  22. beforeEach(()=>{
  23. execSync(`mkdir -p ${TEMP_DIR}`)
  24. });
  25. afterEach(()=>{
  26. execSync(`rm ${TEMP_DIR}/*.zip`)
  27. fs.rmdirSync(TEMP_DIR);
  28. });
  29. const testZipsInMF = (filePath) => {
  30. it("valid zip files in manifest", function(done) {
  31. const mfObj = JSON.parse(fs.readFileSync(filePath, 'utf8'));
  32. if(mfObj.downloads){
  33. const urlsChecked = [];
  34. let lastSha256;
  35. ['win', 'lin', 'mac'].map(os => {
  36. const osObj = mfObj.downloads[os];
  37. if(osObj && osObj.download && osObj.sha256){
  38. const zipUrl = osObj.download;
  39. if(urlsChecked.includes(zipUrl)){
  40. if(lastSha256 !== osObj.sha256){
  41. fail("SHA256 should be the same if the download URL is the same");
  42. }
  43. } else {
  44. urlsChecked.push(zipUrl);
  45. lastSha256 = osObj.sha256;
  46. testOneZip(mfObj.slug, osObj, done);
  47. }
  48. }
  49. });
  50. }
  51. });
  52. };
  53. manifestsToTest.map(testZipsInMF);
  54. });
  55. function testOneZip(expectedRootDir, osObj, done) {
  56. const urlParts = osObj.download.split('/');
  57. const zipName = urlParts[urlParts.length - 1].split('\?')[0];
  58. request(osObj.download).pipe(fs.createWriteStream(TEMP_DIR+zipName)).on('finish', ()=>{
  59. console.log(`Downloaded ${TEMP_DIR+zipName}`);
  60. const zip = new AdmZip(TEMP_DIR+zipName);
  61. const zipEntries = zip.getEntries();
  62. // zipEntries.map(ze=>console.log(ze.toString()));
  63. const slugDirFound = zipEntries.find(ze => ze.isDirectory &&
  64. (ze.entryName === expectedRootDir+'/' || ze.entryName === expectedRootDir+'\\')
  65. );
  66. if(!slugDirFound){
  67. fail(`Zip should have one dir named ${expectedRootDir}`);
  68. }
  69. const invalidEntry = zipEntries.find(ze => !ze.entryName.startsWith(slugDirFound.entryName));
  70. if(invalidEntry){
  71. fail(`Zip entries should all be under a dir named ${expectedRootDir} but this entry was found: ${invalidEntry.entryName}`);
  72. }
  73. if(VIRUS_TOTAL_ENABLED){
  74. con.FileEvaluation(zipName, "application/zip", fs.readFileSync(TEMP_DIR+zipName), function(data) {
  75. console.log(data);
  76. if(osObj.sha256 !== data.sha256){
  77. throw new Error(`Invalid sha256 value. manifest:${osObj.sha256} virustotal:${data.sha256}`);
  78. }
  79. if(data.positives > 2){
  80. throw new Error(`Too many positives from virustotal.`);
  81. }
  82. done();
  83. }, function(err) {
  84. if (err){ throw err; }
  85. done();
  86. });
  87. } else {
  88. hashFiles({files:[TEMP_DIR+zipName], algorithm:'sha256'}, function(error, hash) {
  89. if(osObj.sha256 !== hash){
  90. throw new Error(`Invalid sha256 value. manifest:${osObj.sha256} hash:${hash}`);
  91. }
  92. done();
  93. });
  94. }
  95. });
  96. }
  97. function getManifestsThatApply(){
  98. let paths = "";
  99. if(process.env.TEST_MANIFEST_ZIPS){
  100. paths = process.env.TEST_MANIFEST_ZIPS;
  101. } else {
  102. paths = execSync('git diff -w --stat --name-only origin/master -- plugins/', {encoding:'utf8'});
  103. }
  104. return paths.trim().split('\n').filter(s=>s.trim() !== '');
  105. }