@backendsystems/nibble 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/bin/install.js +100 -29
  2. package/package.json +2 -2
package/bin/install.js CHANGED
@@ -1,49 +1,120 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ const https = require('https');
4
+ const fs = require('fs');
5
+ const os = require('os');
3
6
  const path = require('path');
4
- const BinWrapper = require('bin-wrapper');
7
+ const crypto = require('crypto');
8
+ const tar = require('tar');
5
9
 
6
10
  const PROJECT = 'nibble';
7
11
  const OWNER = 'backendsystems';
8
12
  const ROOT = path.resolve(__dirname, '..');
9
13
  const VENDOR_DIR = path.join(ROOT, 'vendor');
10
- const PACKAGE_JSON = require(path.join(ROOT, 'package.json'));
11
-
12
- function buildWrapper() {
13
- const tag = `v${PACKAGE_JSON.version}`;
14
- const base = `https://github.com/${OWNER}/${PROJECT}/releases/download/${tag}`;
15
- const binName = process.platform === 'win32' ? `${PROJECT}.exe` : PROJECT;
16
- const supportedOs = ['linux', 'darwin', 'win32'];
17
- const supportedArch = ['x64', 'arm64'];
18
-
19
- const wrapper = new BinWrapper({ skipCheck: true });
20
- for (const os of supportedOs) {
21
- let osTarget = os;
22
- if (os === 'win32') {
23
- osTarget = 'windows';
24
- }
14
+ const { version } = require(path.join(ROOT, 'package.json'));
15
+
16
+ const platformMap = { linux: 'linux', darwin: 'darwin', win32: 'windows' };
17
+ const archMap = { x64: 'amd64', arm64: 'arm64' };
18
+
19
+ const osPlatform = platformMap[process.platform];
20
+ const osArch = archMap[process.arch];
21
+
22
+ if (!osPlatform || !osArch) {
23
+ console.error(`Unsupported platform: ${process.platform}/${process.arch}`);
24
+ process.exit(1);
25
+ }
25
26
 
26
- for (const arch of supportedArch) {
27
- let archTarget = arch;
28
- if (arch === 'x64') {
29
- archTarget = 'amd64';
30
- }
27
+ const tag = `v${version}`;
28
+ const base = `https://github.com/${OWNER}/${PROJECT}/releases/download/${tag}`;
29
+ const archiveName = `${PROJECT}_${osPlatform}_${osArch}.tar.gz`;
30
+ const binName = process.platform === 'win32' ? `${PROJECT}.exe` : PROJECT;
31
+ const destPath = path.join(VENDOR_DIR, binName);
31
32
 
32
- wrapper.src(`${base}/${PROJECT}_${osTarget}_${archTarget}.tar.gz`, os, arch);
33
+ function download(url, dest) {
34
+ return new Promise((resolve, reject) => {
35
+ const file = fs.createWriteStream(dest);
36
+ function get(url) {
37
+ https.get(url, (res) => {
38
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
39
+ return get(res.headers.location);
40
+ }
41
+ if (res.statusCode !== 200) {
42
+ return reject(new Error(`HTTP ${res.statusCode} downloading ${url}`));
43
+ }
44
+ res.pipe(file);
45
+ file.on('finish', () => file.close(resolve));
46
+ file.on('error', reject);
47
+ }).on('error', reject);
33
48
  }
34
- }
49
+ get(url);
50
+ });
51
+ }
52
+
53
+ function fetch(url) {
54
+ return new Promise((resolve, reject) => {
55
+ function get(url) {
56
+ https.get(url, (res) => {
57
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
58
+ return get(res.headers.location);
59
+ }
60
+ if (res.statusCode !== 200) {
61
+ return reject(new Error(`HTTP ${res.statusCode} fetching ${url}`));
62
+ }
63
+ const chunks = [];
64
+ res.on('data', c => chunks.push(c));
65
+ res.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
66
+ res.on('error', reject);
67
+ }).on('error', reject);
68
+ }
69
+ get(url);
70
+ });
71
+ }
35
72
 
36
- return wrapper.dest(VENDOR_DIR).use(binName);
73
+ function sha256File(filePath) {
74
+ return new Promise((resolve, reject) => {
75
+ const hash = crypto.createHash('sha256');
76
+ fs.createReadStream(filePath)
77
+ .on('data', d => hash.update(d))
78
+ .on('end', () => resolve(hash.digest('hex')))
79
+ .on('error', reject);
80
+ });
81
+ }
82
+
83
+ function parseChecksum(checksumsTxt, filename) {
84
+ for (const line of checksumsTxt.split('\n')) {
85
+ const [hash, name] = line.trim().split(/\s+/);
86
+ if (name === filename) return hash;
87
+ }
88
+ return null;
37
89
  }
38
90
 
39
91
  async function main() {
40
- console.log(`Installing ${PROJECT} ${PACKAGE_JSON.version}...`);
41
- const bin = buildWrapper();
42
- await bin.run();
43
- console.log('Installed nibble binary successfully');
92
+ console.log(`Installing ${PROJECT} ${version} for ${osPlatform}/${osArch}...`);
93
+ fs.mkdirSync(VENDOR_DIR, { recursive: true });
94
+
95
+ const checksumsTxt = await fetch(`${base}/checksums.txt`);
96
+ const expectedHash = parseChecksum(checksumsTxt, archiveName);
97
+ if (!expectedHash) {
98
+ throw new Error(`No checksum found for ${archiveName} in checksums.txt`);
99
+ }
100
+
101
+ const tmpFile = path.join(os.tmpdir(), archiveName);
102
+ try {
103
+ await download(`${base}/${archiveName}`, tmpFile);
104
+
105
+ const actualHash = await sha256File(tmpFile);
106
+ if (actualHash !== expectedHash) {
107
+ throw new Error(`Checksum mismatch for ${archiveName}: expected ${expectedHash}, got ${actualHash}`);
108
+ }
109
+
110
+ await tar.extract({ file: tmpFile, cwd: VENDOR_DIR, filter: p => p === binName });
111
+ console.log(`Installed ${PROJECT} to ${destPath}`);
112
+ } finally {
113
+ try { fs.unlinkSync(tmpFile); } catch {}
114
+ }
44
115
  }
45
116
 
46
117
  main().catch((err) => {
47
- console.error(`nibble install failed: ${err.message}`);
118
+ console.error(`${PROJECT} install failed: ${err.message}`);
48
119
  process.exit(1);
49
120
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backendsystems/nibble",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Fast local network scanner with hardware identification and a terminal UI",
5
5
  "bin": {
6
6
  "nibble": "bin/nibble.js"
@@ -9,7 +9,7 @@
9
9
  "postinstall": "node bin/install.js"
10
10
  },
11
11
  "dependencies": {
12
- "bin-wrapper": "^4.1.0"
12
+ "tar": "^7.0.0"
13
13
  },
14
14
  "repository": {
15
15
  "type": "git",