Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
e5f9390ba1 | |||
c5cbde1a3c | |||
e69c735d64 | |||
40ab464995 | |||
0672168541 | |||
4b379b106a | |||
1f72f00d2d | |||
a5ad7ea8a5 | |||
c16a65dbcd | |||
debd06f258 | |||
4e8c3efe6f | |||
330e851545 | |||
897314ee52 | |||
4b751522b9 | |||
a4820acc34 | |||
b032feac3e | |||
4a53c2f42a | |||
7314228c91 | |||
95b62bfbb0 | |||
91c43c5aac |
72
README.md
72
README.md
@ -1,4 +1,43 @@
|
||||
#node-wifi-scanner
|
||||
# Fork of node-wifi-scanner
|
||||
|
||||
This fork is used to add the ability to scan as sudo under linux.
|
||||
Why the fork?
|
||||
|
||||
- Add ability to execute command with prefix 'sudo' to get iwlist working on linux!
|
||||
- Uses promise instead of callback in module exports to make it easier and prevent callback hells.
|
||||
- Add `encrypted:boolean` to the output, to determine if the network is encrypted (Currently only works under iwlist/linux, otherwise just returns false)
|
||||
|
||||
|
||||
To use sudo, just pass `true` to the scan method and it will use sudo.
|
||||
For ex.
|
||||
```js
|
||||
const wifiScan = require("node-wifi-scanner");
|
||||
let result = await wifiScan.scan(true);
|
||||
```
|
||||
|
||||
Beforehand you should add the iwlist scan command to the sudoers file.
|
||||
`%mygroup ALL = (root) NOPASSWD: iwlist wlanX scan` [src](https://stackoverflow.com/questions/53710368/how-do-i-add-typescript-types-to-a-javascript-module-without-switching-to-typesc)
|
||||
|
||||
|
||||
### Installation
|
||||
`yarn add git+https://github.com/Tobstr02/node-wifi-scanner.git`
|
||||
or `npm install git+https://github.com/Tobstr02/node-wifi-scanner.git`
|
||||
|
||||
|
||||
### Type definitions
|
||||
I also tried to add type definitions (see /types/index.d.ts), but as far as i know i did it wrong haha.
|
||||
Since this is my first ever module (-fork) i don't really know how to do it. - Let me know in the issues tab or create a pull request :)
|
||||
But i added jsdoc to the functions to add the ability to make the coding process a bit cleaner.
|
||||
|
||||
|
||||
<br>
|
||||
<i>Fork from: [Node-Wifi-Scanner Github](https://github.com/ancasicolica/node-wifi-scanner/)</i>
|
||||
|
||||
|
||||
<br><br>
|
||||
----
|
||||
# Node-Wifi-Scanner
|
||||
|
||||
|
||||
[](https://travis-ci.org/ancasicolica/node-wifi-scanner)
|
||||
[]()
|
||||
@ -16,39 +55,24 @@ system language. The adaptions needed would have been too comprehensive for a pu
|
||||
## Operating Systems
|
||||
|
||||
It was tested with the following operating systems:
|
||||
* Mac OS-X
|
||||
* Windows 10
|
||||
* Ubuntu 14.04
|
||||
* Raspbian "Jessie"
|
||||
* Mac OS-X [Not tested by fork author]
|
||||
* Windows 10 [Not tested by fork author]
|
||||
* Ubuntu 14.04 [Tested by fork author]
|
||||
* Raspbian "Jessie" [Tested by fork author]
|
||||
|
||||
## Installation
|
||||
|
||||
npm i node-wifi-scanner
|
||||
yarn add git+https://git.gaminggeneration.de/tobiash/node-wifi-scanner
|
||||
|
||||
## Usage
|
||||
|
||||
### Command Line
|
||||
|
||||
Run the script ```scan``` in the bin folder.
|
||||
|
||||
### Code
|
||||
|
||||
const scanner = require('node-wifi-scanner');
|
||||
|
||||
scanner.scan((err, networks) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
console.log(networks);
|
||||
});
|
||||
|
||||
The tool returns an array with objects, each object representing a network with the following properties:
|
||||
|
||||
* channel: WiFi channel
|
||||
* ssid: SSID of the network (if available)
|
||||
* mac: MAC Address of the network access point (if available, otherwise empty string)
|
||||
* rssi: signal strength
|
||||
* encrypted: boolean - Is network encrypted?
|
||||
|
||||
In contrary to other wifi scanners no information about security is returned. This is due to the very different implementation
|
||||
of the command line tools which do not allow a flawless detection.
|
||||
@ -74,7 +98,7 @@ the operating system. Please note the following restrictions
|
||||
before using this tool in a productive system.
|
||||
|
||||
**Linux**: iwlist does only return all found networks if run as sudo! Otherwise you'll
|
||||
get only the network you're connected to.
|
||||
get only the network you're connected to. <i>That's where my fork comes in!!</i>
|
||||
|
||||
**Windows**: there are some network cards which do not
|
||||
return the MAC address and other parameters of the found networks. In this case
|
||||
@ -86,7 +110,7 @@ card, OS,...) as available. Thanks
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Christian Kuster
|
||||
Copyright (c) 2016-2024 Christian Kuster, Tobias Hopp
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
85
index.js
85
index.js
@ -1,9 +1,20 @@
|
||||
/**
|
||||
* node-wifi-scanner
|
||||
* Created by kc on 04.04.16.
|
||||
* @typedef {Object} WifiNetwork
|
||||
* @property {string} ssid - SSID of the wifi
|
||||
* @property {string} mac - MAC-Address of the wifi
|
||||
* @property {number} channel - Channel of the wifi
|
||||
* @property {number} rssi - Signalstrength of Wifi-Network (RSSI)
|
||||
* @property {boolean} encrypted - Encrypted
|
||||
*/
|
||||
|
||||
const exec = require('child_process').exec;
|
||||
|
||||
/**
|
||||
* node-wifi-scanner
|
||||
* Created by kc on 04.04.16. - Forked and updated by Tobias Hopp 27.03.2024
|
||||
*/
|
||||
|
||||
const {exec, spawn} = require('child_process');
|
||||
|
||||
const async = require('async');
|
||||
const _ = require('lodash');
|
||||
// The tools
|
||||
@ -57,34 +68,76 @@ function initTools(callback) {
|
||||
|
||||
/**
|
||||
* Scan the networks with the scanner detected before
|
||||
* @param callback
|
||||
* @param {Function|any} callback
|
||||
* @param {boolean} useSudo - Use sudo for access?
|
||||
*/
|
||||
function scanNetworks(callback) {
|
||||
exec(scanner.cmdLine, function (err, stdout) {
|
||||
function scanNetworks(callback, useSudo) {
|
||||
const cmd = scanner.cmdLine.split(" ");
|
||||
let args = cmd.slice(1);
|
||||
if(useSudo)
|
||||
args.unshift(cmd[0]);
|
||||
const child = spawn(useSudo ? "sudo" : cmd[0], args, { stdio: ['ignore', 'pipe', 'pipe'], detached: true });
|
||||
|
||||
child.on("error", (err) => callback(err, null) );
|
||||
|
||||
let stdoutData = '';
|
||||
child.stdout.on('data', (data) => {
|
||||
stdoutData += data;
|
||||
});
|
||||
|
||||
child.on('close', (code) => {
|
||||
if (code === 0) {
|
||||
// Prozess erfolgreich beendet, Ausgabe verarbeiten
|
||||
scanner.parseOutput(stdoutData, callback);
|
||||
} else {
|
||||
// Prozess mit Fehler beendet
|
||||
callback(new Error(`Exited with code ${code}`), null);
|
||||
}
|
||||
});
|
||||
|
||||
/*exec((useSudo ? "sudo ":"") + scanner.cmdLine, { shell: true }, function (err, stdout) {
|
||||
if (err) {
|
||||
callback(err, null);
|
||||
return;
|
||||
}
|
||||
scanner.parseOutput(stdout, callback);
|
||||
});
|
||||
});*/
|
||||
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* Scan for wifis
|
||||
* @param callback
|
||||
*/
|
||||
scan: function (callback) {
|
||||
if (!scanner) {
|
||||
initTools(function (err, s) {
|
||||
* Scan for wifi networks
|
||||
* @param {boolean} useSudo? - Defaults to false | Should sudo be used to get the output?
|
||||
* @return {Promise<WifiNetwork[]|null>} WiFinetwork Array or null
|
||||
* @rejects Returns error on reject
|
||||
*/
|
||||
scan: function (useSudo = false) {
|
||||
return new Promise( (resolve, reject) => {
|
||||
if (!scanner) {
|
||||
initTools(function (err, s) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
return reject(err);
|
||||
}
|
||||
scanner = s;
|
||||
scanNetworks(callback);
|
||||
scanNetworks((err, result) => {
|
||||
if(err)
|
||||
return reject(err);
|
||||
if(!result)
|
||||
result = [];
|
||||
resolve(result);
|
||||
}, useSudo && scanner == iwlist);
|
||||
|
||||
});
|
||||
return;
|
||||
}
|
||||
scanNetworks(callback);
|
||||
scanNetworks((err, result) => {
|
||||
if(err)
|
||||
return reject(err);
|
||||
if(!result)
|
||||
result = [];
|
||||
resolve(result);
|
||||
}, useSudo && scanner == iwlist);
|
||||
} );
|
||||
}
|
||||
};
|
||||
|
@ -26,7 +26,8 @@ function parseOutput(str, callback) {
|
||||
'ssid' : lines[i].substring(0, 32).trim(),
|
||||
'mac' : '', // There is no more mac on a mac
|
||||
'channel': parseInt(elements[1].trim(), 10),
|
||||
'rssi' : parseInt(elements[0].trim(), 10)
|
||||
'rssi' : parseInt(elements[0].trim(), 10),
|
||||
'encrypted': false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ const detector = tool + ' --help';
|
||||
|
||||
const macRegex = /([0-9a-zA-Z]{1}[0-9a-zA-Z]{1}[:]{1}){5}[0-9a-zA-Z]{1}[0-9a-zA-Z]{1}/;
|
||||
const cellRegex = /Cell [0-9]{2,} - Address:/;
|
||||
const encryptedRegex = /Encryption key:on/g;
|
||||
|
||||
/**
|
||||
* Parsing the output of iwlist, tool having a lot of different faces :-(
|
||||
@ -27,7 +28,8 @@ function parseOutput(str, callback) {
|
||||
let blocks = str.split(cellRegex);
|
||||
|
||||
blocks.forEach(block => {
|
||||
let network = {};
|
||||
let network = {encrypted: encryptedRegex.test(block)};
|
||||
|
||||
let lines = block.split('\n');
|
||||
if (macRegex.exec(lines[0])) {
|
||||
// First line is the mac address (always! (?))
|
||||
|
@ -41,7 +41,7 @@ function parseOutput(str, callback) {
|
||||
// Basic rates (MBit/s) : 1 2 5.5 11
|
||||
// Other rates (MBit/s) : 6 9 12 18 24 36 48 54
|
||||
for (let i = 1, l = blocks.length; i < l; i++) {
|
||||
let network = {};
|
||||
let network = {encrypted: false};
|
||||
let lines = blocks[i].split('\n');
|
||||
let regexChannel = /[a-zA-Z0-9()\s]+:[\s]*[0-9]+$/g;
|
||||
if (!lines || lines.length < 2) {
|
||||
|
11
package.json
11
package.json
@ -13,19 +13,18 @@
|
||||
"nmcli"
|
||||
],
|
||||
"author": {
|
||||
"name": "Christian Kuster, CH-8342 Wernetshausen",
|
||||
"email": "info@kusti.ch",
|
||||
"url": "http://www.kusti.ch/"
|
||||
"name": "Christian Kuster, Tobias Hopp",
|
||||
"email": "tobi@gaminggeneration.de"
|
||||
},
|
||||
"homepage": "https://github.com/ancasicolica/node-wifi-scanner",
|
||||
"homepage": "https://git.gaminggeneration.de/TobiasH/node-wifi-scanner/",
|
||||
"bugs": {
|
||||
"url": "https://github.com/ancasicolica/node-wifi-scanner/issues",
|
||||
"url": "https://git.gaminggeneration.de/TobiasH/node-wifi-scanner/issues/",
|
||||
"email": "info@ancasicolica.ch"
|
||||
},
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ancasicolica/node-wifi-scanner.git"
|
||||
"url": "https://git.gaminggeneration.de/TobiasH/node-wifi-scanner.git"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4.0.0",
|
||||
|
@ -1,67 +0,0 @@
|
||||
/**
|
||||
* Airport unit test
|
||||
* Created by kc on 04.04.16.
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const assert = require('assert');
|
||||
|
||||
const airport = require('../lib/airport');
|
||||
|
||||
describe('airport', () => {
|
||||
it('parses the output of file 1', function(done) {
|
||||
airport.parseOutput(fs.readFileSync(path.join(__dirname, 'fixtures','airport','airport01.txt'), { encoding: 'utf8' }), (err, info) => {
|
||||
|
||||
assert.ok(info);
|
||||
assert.equal(info.length, 36);
|
||||
|
||||
let ap = info[0];
|
||||
assert.equal(ap.mac, '');
|
||||
assert.equal(ap.ssid, 'OurTest');
|
||||
assert.equal(ap.rssi, -70);
|
||||
assert.strictEqual(ap.channel, 112);
|
||||
|
||||
ap = info[19];
|
||||
assert.equal(ap.mac, '00:35:1a:5b:45:b6');
|
||||
assert.equal(ap.ssid, 'PDANet1');
|
||||
assert.equal(ap.rssi, -78);
|
||||
assert.strictEqual(ap.channel, 11);
|
||||
|
||||
ap = info[25];
|
||||
assert.equal(ap.mac, '10:bd:18:ab:4d:8f');
|
||||
assert.equal(ap.ssid, 'TEST Training');
|
||||
assert.equal(ap.rssi, -71);
|
||||
assert.strictEqual(ap.channel, 6);
|
||||
|
||||
ap = info[35];
|
||||
assert.equal(ap.mac, '00:35:1a:90:56:00');
|
||||
assert.equal(ap.ssid, 'TEST-Wifi');
|
||||
assert.equal(ap.rssi, -67);
|
||||
assert.strictEqual(ap.channel, 1);
|
||||
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('parses the output of file 2', function(done) {
|
||||
airport.parseOutput(fs.readFileSync(path.join(__dirname, 'fixtures','airport','airport02.txt'), { encoding: 'utf8' }), (err, info) => {
|
||||
assert.ok(info);
|
||||
assert.equal(info.length, 4);
|
||||
|
||||
let ap = info[0];
|
||||
assert.equal(ap.mac, '7c:b7:33:ae:3b:06');
|
||||
assert.equal(ap.ssid, 'Raupo');
|
||||
assert.equal(ap.rssi, -80);
|
||||
assert.strictEqual(ap.channel, 64);
|
||||
|
||||
ap = info[3];
|
||||
assert.equal(ap.mac, '7c:b7:33:ae:3b:04');
|
||||
assert.equal(ap.ssid, 'Visitor Raupo');
|
||||
assert.equal(ap.rssi, -66);
|
||||
assert.strictEqual(ap.channel, 9);
|
||||
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
41
types/index.d.ts
vendored
Normal file
41
types/index.d.ts
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
declare module 'node-wifi-scanner' {
|
||||
type Callback<T> = (error: Error | null, result: T | null) => void;
|
||||
|
||||
interface WifiNetwork {
|
||||
ssid: string;
|
||||
mac: string;
|
||||
channel: number;
|
||||
rssi: number;
|
||||
}
|
||||
|
||||
interface Scanner {
|
||||
cmdLine: string;
|
||||
parseOutput(output: string, callback: Callback<WifiNetwork[]>): void;
|
||||
}
|
||||
|
||||
interface Tool {
|
||||
detector: string;
|
||||
}
|
||||
|
||||
const airport: Tool;
|
||||
const iwlist: Tool;
|
||||
const netsh: Tool;
|
||||
|
||||
/**
|
||||
* Initialize the scanner tools
|
||||
* @param callback Callback function
|
||||
*/
|
||||
function initTools(callback: Callback<Scanner>): void;
|
||||
|
||||
/**
|
||||
* Scan the networks
|
||||
* @param callback Callback function
|
||||
*/
|
||||
function scanNetworks(callback: Callback<WifiNetwork[]>): void;
|
||||
|
||||
/**
|
||||
* Scan for WiFi networks
|
||||
* @param callback Callback function
|
||||
*/
|
||||
function scan(callback: Callback<WifiNetwork[]>): void;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user