install.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. /**
  2. * Node Sodium install script to help support Windows
  3. *
  4. * @Author Pedro Paixao
  5. * @email paixaop at gmail dot com
  6. * @License MIT
  7. */
  8. var https = require('https');
  9. var fs = require('fs');
  10. var path = require('path');
  11. var exec = require('child_process').exec;
  12. var os = require('os');
  13. var libFiles = [
  14. 'libsodium.dll',
  15. 'libsodium.exp',
  16. 'libsodium.lib',
  17. 'libsodium.pdb',
  18. ];
  19. var includeFiles = [
  20. 'include/sodium/core.h',
  21. 'include/sodium/crypto_aead_aes256gcm.h',
  22. 'include/sodium/crypto_aead_chacha20poly1305.h',
  23. 'include/sodium/crypto_auth.h',
  24. 'include/sodium/crypto_auth_hmacsha256.h',
  25. 'include/sodium/crypto_auth_hmacsha512.h',
  26. 'include/sodium/crypto_auth_hmacsha512256.h',
  27. 'include/sodium/crypto_box.h',
  28. 'include/sodium/crypto_box_curve25519xsalsa20poly1305.h',
  29. 'include/sodium/crypto_core_hchacha20.h',
  30. 'include/sodium/crypto_core_hsalsa20.h',
  31. 'include/sodium/crypto_core_salsa20.h',
  32. 'include/sodium/crypto_core_salsa2012.h',
  33. 'include/sodium/crypto_core_salsa208.h',
  34. 'include/sodium/crypto_generichash.h',
  35. 'include/sodium/crypto_generichash_blake2b.h',
  36. 'include/sodium/crypto_hash.h',
  37. 'include/sodium/crypto_hash_sha256.h',
  38. 'include/sodium/crypto_hash_sha512.h',
  39. 'include/sodium/crypto_int32.h',
  40. 'include/sodium/crypto_int64.h',
  41. 'include/sodium/crypto_onetimeauth.h',
  42. 'include/sodium/crypto_onetimeauth_poly1305.h',
  43. 'include/sodium/crypto_pwhash.h',
  44. 'include/sodium/crypto_pwhash_argon2i.h',
  45. 'include/sodium/crypto_pwhash_scryptsalsa208sha256.h',
  46. 'include/sodium/crypto_scalarmult.h',
  47. 'include/sodium/crypto_scalarmult_curve25519.h',
  48. 'include/sodium/crypto_secretbox.h',
  49. 'include/sodium/crypto_secretbox_xsalsa20poly1305.h',
  50. 'include/sodium/crypto_shorthash.h',
  51. 'include/sodium/crypto_shorthash_siphash24.h',
  52. 'include/sodium/crypto_sign.h',
  53. 'include/sodium/crypto_sign_ed25519.h',
  54. 'include/sodium/crypto_sign_edwards25519sha512batch.h',
  55. 'include/sodium/crypto_stream.h',
  56. 'include/sodium/crypto_stream_chacha20.h',
  57. 'include/sodium/crypto_stream_salsa20.h',
  58. 'include/sodium/crypto_stream_salsa2012.h',
  59. 'include/sodium/crypto_stream_salsa208.h',
  60. 'include/sodium/crypto_stream_xsalsa20.h',
  61. 'include/sodium/crypto_uint16.h',
  62. 'include/sodium/crypto_uint32.h',
  63. 'include/sodium/crypto_uint64.h',
  64. 'include/sodium/crypto_uint8.h',
  65. 'include/sodium/crypto_verify_16.h',
  66. 'include/sodium/crypto_verify_32.h',
  67. 'include/sodium/crypto_verify_64.h',
  68. 'include/sodium/export.h',
  69. 'include/sodium/randombytes.h',
  70. 'include/sodium/randombytes_salsa20_random.h',
  71. 'include/sodium/randombytes_sysrandom.h',
  72. 'include/sodium/runtime.h',
  73. 'include/sodium/utils.h',
  74. 'include/sodium/version.h',
  75. 'include/sodium.h'
  76. ];
  77. function recursePathList(paths) {
  78. if (0 === paths.length) {
  79. return;
  80. }
  81. var file = paths.shift();
  82. if (!fs.existsSync(file)) {
  83. try {
  84. fs.mkdirSync(file, 0755);
  85. } catch (e) {
  86. throw new Error("Failed to create path: " + file + " with " + e.toString());
  87. }
  88. }
  89. recursePathList(paths);
  90. }
  91. function createFullPath(fullPath) {
  92. var normPath = path.normalize(fullPath);
  93. var file = '';
  94. var pathList = [];
  95. var parts = [];
  96. if (normPath.indexOf('/') !== -1) {
  97. parts = normPath.split('/');
  98. } else {
  99. parts = normPath.split('\\');
  100. }
  101. for (var i = 0, max = parts.length; i < max; i++) {
  102. if (parts[i]) {
  103. file = path.join(file, parts[i]);
  104. pathList.push(file);
  105. }
  106. }
  107. if (0 === pathList.length)
  108. throw new Error("Path list was empty");
  109. else
  110. recursePathList(pathList);
  111. }
  112. function exists(path) {
  113. try {
  114. fs.accessSync(path, fs.F_OK);
  115. return true;
  116. } catch (e) {
  117. return false;
  118. }
  119. }
  120. function download(url, dest, cb) {
  121. if(exists(dest)) {
  122. console.log('File ' + dest + ' alredy exists, run make clean if you want to download it again.');
  123. cb(null);
  124. }
  125. var file = fs.createWriteStream(dest);
  126. var request = https.get(url, function(response) {
  127. response.pipe(file);
  128. file.on('finish', function() {
  129. file.close(cb); // close() is async, call cb after close completes.
  130. });
  131. }).on('error', function(err) { // Handle errors
  132. fs.unlink(dest); // Delete the file async. (But we don't check the result)
  133. if (cb) cb(err);
  134. });
  135. }
  136. function getPlatformToolsVersion() {
  137. var platformTools = {
  138. 2010: 'v100',
  139. 2012: 'v110',
  140. 2013: 'v120',
  141. 2015: 'v140'
  142. }
  143. checkMSVSVersion();
  144. var ver = platformTools[process.env.npm_config_msvs_version];
  145. if (!ver) {
  146. throw new Error('Please set msvs_version');
  147. }
  148. return ver;
  149. }
  150. function downloadAll(files, baseURL, basePath, next) {
  151. if (0 === files.length) {
  152. next();
  153. return;
  154. }
  155. var file = files.shift();
  156. var url = baseURL + '/' + file;
  157. var path = basePath + '/' + file;
  158. console.log('Download: ' + url);
  159. download(url, path, function(err) {
  160. if (err) {
  161. throw err;
  162. }
  163. downloadAll(files, baseURL, basePath, next);
  164. });
  165. }
  166. function copyFile(source, target, cb) {
  167. var cbCalled = false;
  168. var rd = fs.createReadStream(source);
  169. rd.on("error", function(err) {
  170. done(err);
  171. });
  172. var wr = fs.createWriteStream(target);
  173. wr.on("error", function(err) {
  174. done(err);
  175. });
  176. wr.on("close", function(ex) {
  177. done();
  178. });
  179. rd.pipe(wr);
  180. function done(err) {
  181. if (!cbCalled) {
  182. cb(err);
  183. cbCalled = true;
  184. }
  185. }
  186. }
  187. function copyFiles(files, next) {
  188. if (0 === files.length) {
  189. next();
  190. return;
  191. }
  192. var file = files.shift();
  193. var from = 'deps/build/lib/' + file;
  194. var to = 'build/Release/' + file;
  195. copyFile(from, to, function(err) {
  196. if (err) {
  197. throw err;
  198. }
  199. console.log('Copy ' + from + ' to ' + to);
  200. copyFiles(files, next);
  201. })
  202. }
  203. function gypConfigure(next) {
  204. var gyp = exec('node-gyp configure');
  205. gyp.stdout.on('data', function(data) {
  206. process.stdout.write(data.toString());
  207. });
  208. gyp.stderr.on('data', function(data) {
  209. process.stdout.write(data.toString());
  210. });
  211. gyp.on('close', function(code) {
  212. console.log('Done.');
  213. next();
  214. });
  215. }
  216. function doDownloads(next) {
  217. var baseURL = 'https://raw.githubusercontent.com/paixaop/libsodium-bin/master';
  218. console.log('Download libsodium.lib');
  219. var ver = getPlatformToolsVersion();
  220. console.log('Platform Tool is ' + ver);
  221. switch (os.arch()) {
  222. case 'x64':
  223. arch = 'x64';
  224. break;
  225. case 'ia32':
  226. arch = 'Win32';
  227. break;
  228. default:
  229. throw new Error('No pre-compiled binary available for this platform ' + os.arch());
  230. }
  231. // Older versions of node-sodium will try and download from the 'root' of baseURL
  232. // Added libsodium_version to package.json to support multiple binary versions of
  233. // libsodium
  234. var package = require('./package.json');
  235. if( package.libsodium_version ) {
  236. baseURL += '/' + package.libsodium_version;
  237. }
  238. var libURL = baseURL + '/' + arch + '/Release/' + ver + '/dynamic';
  239. files = libFiles.slice(0); // clone array
  240. downloadAll(files, libURL, 'deps/build/lib', function() {
  241. console.log('Libs for version ' + ver + ' downloaded.');
  242. downloadAll(includeFiles, baseURL, 'deps/build', function() {
  243. console.log('Include files downloaded.');
  244. next();
  245. });
  246. });
  247. }
  248. function run(cmdLine, expectedExitCode, next) {
  249. var child = exec(cmdLine);
  250. if (typeof expectedExitCode === 'undefined') {
  251. expectedExitCode = 0;
  252. }
  253. child.stdout.on('data', function(data) {
  254. process.stdout.write(data.toString());
  255. });
  256. child.stderr.on('data', function(data) {
  257. process.stdout.write(data.toString());
  258. });
  259. child.on('exit', function(code) {
  260. if (code !== expectedExitCode) {
  261. throw new Error(cmdLine + ' exited with code ' + code);
  262. }
  263. if (!next) process.exit(0);
  264. next();
  265. });
  266. }
  267. function errorSetMSVSVersion() {
  268. console.log('Please set your Microsoft Visual Studio version before you run npm install');
  269. console.log('Example for Visual Studio 2015:\n');
  270. console.log(' For you user only:\n');
  271. console.log(' npm config set msvs_version 2015\n');
  272. console.log(' Global:\n');
  273. console.log(' npm config set msvs_version 2015 --global\n');
  274. console.log('Supported values are 2010, 2012, 2013, 2015\n');
  275. process.exit(1);
  276. }
  277. function errorInvalidMSVSVersion() {
  278. console.log('Invalid msvs_version ' + msvsVersion + '\n');
  279. console.log('Please set your Microsoft Visual Studio version before you run npm install');
  280. console.log('Example for Visual Studio 2015:\n');
  281. console.log(' For you user only:\n');
  282. console.log(' npm config set msvs_version 2015\n');
  283. console.log(' Global:\n');
  284. console.log(' npm config set msvs_version 2015 --global\n');
  285. console.log('Supported values are 2010, 2012, 2013, 2015\n');
  286. process.exit(1);
  287. }
  288. function checkMSVSVersion() {
  289. if (!process.env.npm_config_msvs_version) {
  290. errorSetMSVSVersion();
  291. }
  292. console.log('MS Version: ' + process.env.npm_config_msvs_version);
  293. if (process.env.npm_config_msvs_version.search(/^2010|2012|2013|2015$/)) {
  294. errorInvalidMSVSVersion();
  295. }
  296. }
  297. function isPreInstallMode() {
  298. if (!process.argv[2] || process.argv[2].search(/^--preinstall|--install/)) {
  299. console.log('please call install with --preinstall or --install');
  300. process.exit(1);
  301. }
  302. if (process.argv[2] === '--preinstall') {
  303. return true;
  304. }
  305. return false;
  306. }
  307. // Start
  308. if (os.platform() !== 'win32') {
  309. if (isPreInstallMode()) {
  310. run('make libsodium');
  311. } else {
  312. run('make nodesodium');
  313. }
  314. } else {
  315. checkMSVSVersion();
  316. if (isPreInstallMode()) {
  317. console.log('Preinstall Mode');
  318. createFullPath("deps/build/include/sodium");
  319. createFullPath("deps/build/lib");
  320. createFullPath("build/Release");
  321. doDownloads(function() {
  322. console.log('Prebuild steps completed. Binary libsodium distribution installed in ./deps/build');
  323. process.exit(0);
  324. });
  325. } else {
  326. console.log('Install Mode');
  327. run('node-gyp rebuild', 0, function() {
  328. console.log('Copy lib files to Release folder');
  329. files = libFiles.slice(0); // clone array
  330. copyFiles(files, function() {
  331. console.log('Done copying files.');
  332. process.exit(0);
  333. });
  334. });
  335. }
  336. }