spoof-d 0.1.0

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 (5) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +250 -0
  3. package/bin/cmd.js +313 -0
  4. package/index.js +1115 -0
  5. package/package.json +57 -0
package/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) Feross Aboukhadijeh
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,250 @@
1
+ # spoof-d
2
+
3
+ [![npm version](https://img.shields.io/npm/v/spoof-d)](https://www.npmjs.com/package/spoof-d)
4
+ [![license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
5
+ [![GitHub forks](https://img.shields.io/github/forks/TT5H/spoof-d)](https://github.com/TT5H/spoof-d/network)
6
+ [![GitHub stars](https://img.shields.io/github/stars/TT5H/spoof-d)](https://github.com/TT5H/spoof-d/stargazers)
7
+
8
+ > **✅ Cross-Platform Support**: This is a modernized fork of the original `spoof` project, updated for compatibility with modern macOS (Sequoia 15.4+, Tahoe 26+), Windows 10/11, and Linux. All platforms are now fully supported!
9
+
10
+ ### Easily spoof your MAC address on macOS, Windows, and Linux!
11
+
12
+ A Node.js utility for changing MAC addresses across all major platforms. Features reliable macOS support, modern Windows PowerShell integration, and Linux `ip link` commands. This fork includes enhanced error handling, automatic verification, retry logic, and improved cross-platform compatibility.
13
+
14
+ ## About This Fork
15
+
16
+ This repository ([TT5H/spoof-d](https://github.com/TT5H/spoof-d)) is a fork of [basedbytes/spoofy](https://github.com/basedbytes/spoofy), which itself is a fork of the original `spoof` project. This fork extends the functionality with full cross-platform support and enhanced features.
17
+
18
+ ### What's Changed
19
+
20
+ - **✅ Full Cross-Platform Support**: Complete Windows 10/11 and Linux support (not just macOS)
21
+ - **Modern macOS Support**: Fixed MAC spoofing for macOS Sequoia 15.4+ and Tahoe 26+
22
+ - **Windows Support**: Full Windows 10/11 support using PowerShell and registry methods with automatic fallback
23
+ - **Linux Support**: Modern Linux support using `ip link` commands (replaces deprecated `ifconfig`)
24
+ - **Enhanced Error Handling**: Custom error classes with actionable suggestions and better error messages
25
+ - **Automatic Verification**: Verifies MAC address changes after setting them
26
+ - **Retry Logic**: Automatic retry with exponential backoff for transient failures
27
+ - **Timeout Handling**: Prevents hanging operations with configurable timeouts
28
+ - **Better Validation**: Comprehensive input validation with helpful error messages
29
+ - **Removed `airport` dependency**: The deprecated `airport -z` command has been replaced with modern `networksetup` commands
30
+ - **Timing-sensitive MAC changes**: WiFi MAC addresses are now changed in the brief window after power-on but before network connection
31
+ - **Improved interface detection**: Better cross-platform interface detection using modern system commands
32
+ - **Cleaner codebase**: Removed deprecated code paths and unnecessary constants
33
+
34
+ ## Key Features
35
+
36
+ ### Enhanced Error Handling
37
+ - **Custom error classes** with specific error types (ValidationError, PermissionError, NetworkError, etc.)
38
+ - **Actionable suggestions** provided with every error message
39
+ - **Better error context** to help diagnose issues quickly
40
+
41
+ ### Reliability Features
42
+ - **Automatic verification** of MAC address changes after setting them
43
+ - **Retry logic** with exponential backoff for transient failures
44
+ - **Timeout handling** to prevent hanging operations
45
+ - **Comprehensive validation** of inputs before attempting changes
46
+
47
+ ### Cross-Platform Excellence
48
+ - **Windows**: PowerShell integration with registry fallback
49
+ - **macOS**: Modern networksetup commands with WiFi timing handling
50
+ - **Linux**: Modern ip link commands with ifconfig fallback
51
+ - **Unified API** across all platforms
52
+
53
+ ## Installation
54
+
55
+ ### From npm (recommended)
56
+
57
+ ```bash
58
+ npm install -g spoof-d
59
+ ```
60
+
61
+ After installation, use the `spoofy` command (the package name is `spoof-d`, but the command is still `spoofy`).
62
+
63
+ After installation, you can use the `spoofy` command from anywhere.
64
+
65
+ ### From source
66
+
67
+ ```bash
68
+ git clone https://github.com/TT5H/spoof-d.git
69
+ cd spoof-d
70
+ npm install
71
+ npm install -g .
72
+ ```
73
+
74
+ This gives you the latest development version with all the latest features.
75
+
76
+ ## Quick Start
77
+
78
+ ### List network interfaces
79
+
80
+ **macOS/Linux:**
81
+ ```bash
82
+ spoofy list
83
+ ```
84
+
85
+ **Windows (run PowerShell as Administrator):**
86
+ ```powershell
87
+ spoofy list
88
+ ```
89
+
90
+ ### Randomize MAC address
91
+
92
+ **macOS (WiFi is typically `en0`):**
93
+ ```bash
94
+ sudo spoofy randomize en0
95
+ ```
96
+
97
+ **Windows:**
98
+ ```powershell
99
+ # Run PowerShell as Administrator
100
+ spoofy randomize "Ethernet"
101
+ ```
102
+
103
+ **Linux:**
104
+ ```bash
105
+ sudo spoofy randomize eth0
106
+ ```
107
+
108
+ **Note:** WiFi will disconnect briefly and may need to reconnect to networks. On Windows, ensure you're running as Administrator.
109
+
110
+ ## Usage
111
+
112
+ You can always see up-to-date usage instructions by running `spoofy --help`.
113
+
114
+ ### List available devices
115
+
116
+ ```bash
117
+ spoofy list
118
+ ```
119
+
120
+ Output:
121
+
122
+ ```
123
+ - "Ethernet" on device "en4" with MAC address 70:56:51:BE:B3:00
124
+ - "Wi-Fi" on device "en0" with MAC address 70:56:51:BE:B3:01 currently set to 70:56:51:BE:B3:02
125
+ - "Bluetooth PAN" on device "en1"
126
+ ```
127
+
128
+ ### List only Wi-Fi devices
129
+
130
+ ```bash
131
+ spoofy list --wifi
132
+ ```
133
+
134
+ ### Randomize MAC address _(requires root)_
135
+
136
+ Using hardware port name:
137
+
138
+ ```bash
139
+ sudo spoofy randomize wi-fi
140
+ ```
141
+
142
+ Or using device name:
143
+
144
+ ```bash
145
+ sudo spoofy randomize en0
146
+ ```
147
+
148
+ ### Set specific MAC address _(requires root)_
149
+
150
+ ```bash
151
+ sudo spoofy set 00:11:22:33:44:55 en0
152
+ ```
153
+
154
+ ### Reset to original MAC address _(requires root)_
155
+
156
+ ```bash
157
+ sudo spoofy reset wi-fi
158
+ ```
159
+
160
+ **Note**: On macOS, restarting your computer will also reset your MAC address to the original hardware address.
161
+
162
+ ## Platform Support
163
+
164
+ ### macOS ✅
165
+
166
+ - ✅ **Fully supported** and tested on macOS Tahoe 26.2
167
+ - ✅ Works on macOS Sequoia 15.4+
168
+ - ⚠️ Older versions may work but are untested
169
+ - Uses `networksetup` and `ifconfig` commands
170
+ - Special handling for WiFi interfaces on modern macOS
171
+
172
+ ### Windows ✅
173
+
174
+ - ✅ **Fully supported** on Windows 10 and Windows 11
175
+ - ✅ Uses PowerShell `Get-NetAdapter` and `Set-NetAdapter` commands
176
+ - ✅ Falls back to registry method for compatibility
177
+ - ⚠️ Requires Administrator privileges (run PowerShell/CMD as Administrator)
178
+ - Some network adapters may not support MAC address changes (hardware limitation)
179
+
180
+ **Windows Usage:**
181
+ ```powershell
182
+ # Run PowerShell or CMD as Administrator
183
+ spoofy list
184
+ spoofy randomize "Ethernet"
185
+ spoofy set 00:11:22:33:44:55 "Wi-Fi"
186
+ ```
187
+
188
+ ### Linux ✅
189
+
190
+ - ✅ **Fully supported** using modern `ip link` commands
191
+ - ✅ Falls back to `ifconfig` if `ip` command is not available
192
+ - ⚠️ Requires root privileges (use `sudo`)
193
+ - Works with most modern Linux distributions
194
+
195
+ **Linux Usage:**
196
+ ```bash
197
+ sudo spoofy list
198
+ sudo spoofy randomize eth0
199
+ sudo spoofy set 00:11:22:33:44:55 wlan0
200
+ ```
201
+
202
+ ## Known Issues
203
+
204
+ - WiFi will briefly disconnect when changing MAC address
205
+ - Some network restrictions or hardware may prevent MAC spoofing
206
+ - Requires sudo/root privileges for all MAC address changes
207
+
208
+ ## Troubleshooting
209
+
210
+ ### macOS
211
+ 1. Make sure you're running with `sudo` (required for network changes)
212
+ 2. Ensure WiFi is turned on before attempting to change MAC
213
+ 3. On modern macOS, you may need to reconnect to WiFi after the change
214
+ 4. Try running `networksetup -detectnewhardware` if changes don't take effect
215
+
216
+ ### Windows
217
+ 1. **Run as Administrator**: Right-click PowerShell or Command Prompt and select "Run as Administrator"
218
+ 2. Some network adapters don't support MAC address changes (hardware limitation)
219
+ 3. If `Set-NetAdapter` fails, the tool will automatically try the registry method
220
+ 4. You may need to disable and re-enable the adapter manually if changes don't take effect
221
+ 5. Check adapter compatibility: Some virtual adapters and certain hardware may not support MAC spoofing
222
+
223
+ ### Linux
224
+ 1. Make sure you're running with `sudo` (required for network changes)
225
+ 2. Ensure the `ip` command is available (usually in `iproute2` package)
226
+ 3. Some network interfaces may be managed by NetworkManager - you may need to disable it temporarily
227
+ 4. Virtual interfaces and certain hardware may not support MAC address changes
228
+
229
+ ## Contributing
230
+
231
+ This is an active fork. Contributions, bug reports, and feature requests are welcome!
232
+
233
+ To contribute:
234
+ 1. Fork this repository
235
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
236
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
237
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
238
+ 5. Open a Pull Request
239
+
240
+ ## License
241
+
242
+ MIT License (inherited from original project)
243
+
244
+ ## Credits
245
+
246
+ - **This fork**: [TT5H/spoof-d](https://github.com/TT5H/spoof-d) - Enhanced cross-platform support with improved error handling
247
+ - **Parent fork**: [basedbytes/spoofy](https://github.com/basedbytes/spoofy) - Modernized macOS support
248
+ - **Original project**: `spoof` by Feross Aboukhadijeh
249
+
250
+ This fork maintains compatibility with modern operating systems and extends support to Windows and Linux.
package/bin/cmd.js ADDED
@@ -0,0 +1,313 @@
1
+ #!/usr/bin/env node
2
+
3
+ const chalk = require("chalk");
4
+ const minimist = require("minimist");
5
+ const spoof = require("../");
6
+ const { stripIndent } = require("common-tags");
7
+ const cp = require("child_process");
8
+
9
+ const argv = minimist(process.argv.slice(2), {
10
+ alias: {
11
+ v: "version",
12
+ },
13
+ boolean: ["version"],
14
+ });
15
+ const cmd = argv._[0];
16
+
17
+ try {
18
+ init();
19
+ } catch (err) {
20
+ handleError(err);
21
+ process.exitCode = -1;
22
+ }
23
+
24
+ function handleError(err) {
25
+ if (err.code) {
26
+ // Custom error with code and suggestions
27
+ console.error(chalk.red(`✗ ${err.name || "Error"}:`), err.message);
28
+
29
+ if (err.suggestions && err.suggestions.length > 0) {
30
+ console.error(chalk.yellow("\nSuggestions:"));
31
+ err.suggestions.forEach((suggestion, index) => {
32
+ console.error(chalk.gray(` ${index + 1}. ${suggestion}`));
33
+ });
34
+ }
35
+ } else {
36
+ // Standard error
37
+ console.error(chalk.red("✗ Error:"), err.message);
38
+
39
+ // Provide helpful suggestions for common errors
40
+ if (err.message.includes("ENOENT") || err.message.includes("spawn")) {
41
+ console.error(chalk.yellow("\nThis might be a system command issue. Suggestions:"));
42
+ if (process.platform === "linux") {
43
+ console.error(chalk.gray(" • Install iproute2: sudo apt-get install iproute2"));
44
+ } else if (process.platform === "win32") {
45
+ console.error(chalk.gray(" • Ensure PowerShell is installed and in PATH"));
46
+ }
47
+ } else if (err.message.includes("permission") || err.message.includes("Permission")) {
48
+ console.error(chalk.yellow("\nPermission issue. Suggestions:"));
49
+ if (process.platform === "win32") {
50
+ console.error(chalk.gray(" • Run PowerShell/CMD as Administrator"));
51
+ } else {
52
+ console.error(chalk.gray(" • Use sudo: sudo spoofy <command>"));
53
+ }
54
+ }
55
+ }
56
+
57
+ if (process.env.DEBUG) {
58
+ console.error(chalk.gray("\nStack trace:"));
59
+ console.error(err.stack);
60
+ }
61
+ }
62
+
63
+ function init() {
64
+ if (cmd === "version" || argv.version) {
65
+ version();
66
+ } else if (cmd === "list" || cmd === "ls") {
67
+ list();
68
+ } else if (cmd === "set") {
69
+ const mac = argv._[1];
70
+ const devices = argv._.slice(2);
71
+ set(mac, devices);
72
+ } else if (cmd === "randomize") {
73
+ const devices = argv._.slice(1);
74
+ randomize(devices);
75
+ } else if (cmd === "reset") {
76
+ const devices = argv._.slice(1);
77
+ reset(devices);
78
+ } else if (cmd === "normalize") {
79
+ const mac = argv._[1];
80
+ normalize(mac);
81
+ } else {
82
+ help();
83
+ }
84
+ }
85
+
86
+ function help() {
87
+ const platform = process.platform;
88
+ let example = "";
89
+ let note = "";
90
+
91
+ if (platform === "win32") {
92
+ example = ` spoofy randomize "Ethernet"`;
93
+ note = "\n Note: On Windows, run PowerShell or CMD as Administrator.";
94
+ } else if (platform === "darwin") {
95
+ example = ` spoofy randomize en0`;
96
+ note = "\n Note: On macOS/Linux, use sudo for MAC address changes.";
97
+ } else {
98
+ example = ` sudo spoofy randomize eth0`;
99
+ note = "\n Note: On Linux, use sudo for MAC address changes.";
100
+ }
101
+
102
+ const message = stripIndent`
103
+ spoofy - Cross-platform MAC address spoofing utility
104
+
105
+ Example (randomize MAC address):
106
+ ${example}${note}
107
+
108
+ Usage:
109
+ spoofy list [--wifi] List available devices.
110
+ spoofy set <mac> <devices>... Set device MAC address.
111
+ spoofy randomize [--local] <devices>... Set device MAC address randomly.
112
+ spoofy reset <devices>... Reset device MAC address to default.
113
+ spoofy normalize <mac> Given a MAC address, normalize it.
114
+ spoofy help Shows this help message.
115
+ spoofy version | --version | -v Show package version.
116
+
117
+ Options:
118
+ --wifi Try to only show wireless interfaces.
119
+ --local Set the locally administered flag on randomized MACs.
120
+
121
+ Platform Support:
122
+ ✅ macOS (Sequoia 15.4+, Tahoe 26+)
123
+ ✅ Windows 10/11
124
+ ✅ Linux (modern distributions)
125
+ `;
126
+ console.log(message);
127
+ }
128
+
129
+ function version() {
130
+ console.log(require("../package.json").version);
131
+ }
132
+
133
+ function set(mac, devices) {
134
+ if (!mac) {
135
+ throw new Error("MAC address is required. Usage: spoofy set <mac> <device>");
136
+ }
137
+
138
+ if (!devices || devices.length === 0) {
139
+ throw new Error("Device name is required. Usage: spoofy set <mac> <device>");
140
+ }
141
+
142
+ devices.forEach((device) => {
143
+ const it = spoof.findInterface(device);
144
+
145
+ if (!it) {
146
+ throw new Error(
147
+ `Could not find device "${device}". ` +
148
+ "List available devices using: spoofy list"
149
+ );
150
+ }
151
+
152
+ setMACAddress(it.device, mac, it.port);
153
+ });
154
+ }
155
+
156
+ function normalize(mac) {
157
+ if (!mac) {
158
+ throw new Error("MAC address is required. Usage: spoofy normalize <mac>");
159
+ }
160
+
161
+ try {
162
+ const normalized = spoof.normalize(mac);
163
+ if (!normalized) {
164
+ throw new Error(`"${mac}" is not a valid MAC address`);
165
+ }
166
+ console.log(normalized);
167
+ } catch (err) {
168
+ throw new Error(
169
+ `Could not normalize MAC address "${mac}": ${err.message}`
170
+ );
171
+ }
172
+ }
173
+
174
+ function randomize(devices) {
175
+ if (!devices || devices.length === 0) {
176
+ throw new Error("Device name is required. Usage: spoofy randomize <device>");
177
+ }
178
+
179
+ devices.forEach((device) => {
180
+ const it = spoof.findInterface(device);
181
+
182
+ if (!it) {
183
+ throw new Error(
184
+ `Could not find device "${device}". ` +
185
+ "List available devices using: spoofy list"
186
+ );
187
+ }
188
+
189
+ const mac = spoof.randomize(argv.local);
190
+ console.log(chalk.blue("ℹ"), `Generated random MAC address: ${chalk.bold.cyan(mac)}`);
191
+ setMACAddress(it.device, mac, it.port);
192
+ });
193
+ }
194
+
195
+ function reset(devices) {
196
+ if (!devices || devices.length === 0) {
197
+ throw new Error("Device name is required. Usage: spoofy reset <device>");
198
+ }
199
+
200
+ devices.forEach((device) => {
201
+ const it = spoof.findInterface(device);
202
+
203
+ if (!it) {
204
+ throw new Error(
205
+ `Could not find device "${device}". ` +
206
+ "List available devices using: spoofy list"
207
+ );
208
+ }
209
+
210
+ if (!it.address) {
211
+ throw new Error(
212
+ `Could not read hardware MAC address for "${device}". ` +
213
+ "The device may not have a MAC address or may be a virtual interface."
214
+ );
215
+ }
216
+
217
+ console.log(chalk.blue("ℹ"), `Resetting to hardware MAC address: ${chalk.bold.cyan(it.address)}`);
218
+ setMACAddress(it.device, it.address, it.port);
219
+ });
220
+ }
221
+
222
+ function list() {
223
+ const targets = [];
224
+ if (argv.wifi) {
225
+ if (process.platform === "win32") {
226
+ targets.push("wi-fi", "wireless", "wlan");
227
+ } else {
228
+ targets.push("wi-fi");
229
+ }
230
+ }
231
+
232
+ const interfaces = spoof.findInterfaces(targets);
233
+
234
+ if (interfaces.length === 0) {
235
+ console.log(chalk.yellow("No network interfaces found."));
236
+ return;
237
+ }
238
+
239
+ interfaces.forEach((it) => {
240
+ const line = [];
241
+ line.push(
242
+ "-",
243
+ chalk.bold.green(it.port || it.device),
244
+ "on device",
245
+ chalk.bold.green(it.device)
246
+ );
247
+
248
+ if (it.status && process.platform === "win32") {
249
+ line.push(chalk.gray(`(${it.status})`));
250
+ }
251
+
252
+ if (it.address) {
253
+ line.push("with MAC address", chalk.bold.cyan(it.address));
254
+ }
255
+ if (it.currentAddress && it.currentAddress !== it.address) {
256
+ line.push("currently set to", chalk.bold.red(it.currentAddress));
257
+ }
258
+ console.log(line.join(" "));
259
+ });
260
+ }
261
+
262
+ function setMACAddress(device, mac, port) {
263
+ // Check for admin/root privileges
264
+ if (process.platform === "win32") {
265
+ // On Windows, check if running as administrator
266
+ try {
267
+ const output = cp
268
+ .execSync(
269
+ 'powershell -Command "[Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent() | Select-Object -ExpandProperty IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)"',
270
+ { stdio: "pipe", shell: true }
271
+ )
272
+ .toString()
273
+ .trim()
274
+ .toLowerCase();
275
+
276
+ if (output !== "true") {
277
+ throw new Error(
278
+ "Must run as Administrator to change network settings. " +
279
+ "Right-click Command Prompt or PowerShell and select 'Run as Administrator'"
280
+ );
281
+ }
282
+ } catch (err) {
283
+ if (err.message.includes("Must run as Administrator")) {
284
+ throw err;
285
+ }
286
+ // If check fails, warn but continue (might work anyway)
287
+ console.warn(chalk.yellow("Warning: Could not verify administrator privileges. Operation may fail."));
288
+ }
289
+ } else if (process.platform !== "win32") {
290
+ // Unix-like systems (macOS, Linux)
291
+ if (process.getuid && process.getuid() !== 0) {
292
+ throw new Error(
293
+ "Must run as root (or using sudo) to change network settings"
294
+ );
295
+ }
296
+ }
297
+
298
+ try {
299
+ spoof.setInterfaceMAC(device, mac, port);
300
+ console.log(
301
+ chalk.green("✓") +
302
+ " Successfully set MAC address to " +
303
+ chalk.bold.cyan(mac) +
304
+ " on " +
305
+ chalk.bold.green(device)
306
+ );
307
+
308
+ // Note: Verification is already done in setInterfaceMAC, so we don't need to do it again here
309
+ } catch (err) {
310
+ // Error is already formatted by handleError in the catch block above
311
+ throw err;
312
+ }
313
+ }