wsnipz 1.0.0 → 1.2.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.
- package/dist/banner.js +2 -2
- package/dist/discord.js +7 -8
- package/dist/index.js +36 -9
- package/dist/mouse.js +66 -0
- package/dist/prompts.js +134 -69
- package/dist/ui.js +7 -7
- package/dist/updater.js +97 -0
- package/dist/version.js +5 -0
- package/package.json +1 -1
package/dist/banner.js
CHANGED
|
@@ -7,7 +7,7 @@ exports.printBanner = printBanner;
|
|
|
7
7
|
const figlet_1 = __importDefault(require("figlet"));
|
|
8
8
|
const chalk_1 = __importDefault(require("chalk"));
|
|
9
9
|
const ui_1 = require("./ui");
|
|
10
|
-
const
|
|
10
|
+
const version_1 = require("./version");
|
|
11
11
|
function printBanner() {
|
|
12
12
|
const art = figlet_1.default.textSync('WSniper', {
|
|
13
13
|
font: 'Standard',
|
|
@@ -20,6 +20,6 @@ function printBanner() {
|
|
|
20
20
|
const line = chalk_1.default.gray('─'.repeat(tag.length));
|
|
21
21
|
console.log(chalk_1.default.gray(tag));
|
|
22
22
|
console.log(line);
|
|
23
|
-
console.log(chalk_1.default.gray(` v${VERSION} • proxies
|
|
23
|
+
console.log(chalk_1.default.gray(` v${version_1.VERSION} • rotating proxies • interactive mode`));
|
|
24
24
|
console.log();
|
|
25
25
|
}
|
package/dist/discord.js
CHANGED
|
@@ -33,7 +33,7 @@ async function checkUsername(username, token, pool) {
|
|
|
33
33
|
const res = await axios_1.default.request(config);
|
|
34
34
|
if (res.status === 204 || res.status === 200) {
|
|
35
35
|
if (res.data?.taken === true) {
|
|
36
|
-
return { status: 'taken', message: '
|
|
36
|
+
return { status: 'taken', message: 'Username already taken' };
|
|
37
37
|
}
|
|
38
38
|
return { status: 'available' };
|
|
39
39
|
}
|
|
@@ -43,29 +43,28 @@ async function checkUsername(username, token, pool) {
|
|
|
43
43
|
}
|
|
44
44
|
if (res.status === 400) {
|
|
45
45
|
if (res.data?.taken === true) {
|
|
46
|
-
return { status: 'taken', message: '
|
|
46
|
+
return { status: 'taken', message: 'Username already taken' };
|
|
47
47
|
}
|
|
48
48
|
const usernameErrors = res.data?.errors?.username?._errors || [];
|
|
49
49
|
const codes = usernameErrors.map((e) => e.code).filter(Boolean);
|
|
50
50
|
if (codes.includes('USERNAME_TOO_MANY_RESULTS')) {
|
|
51
|
-
return { status: 'taken', message: '
|
|
51
|
+
return { status: 'taken', message: 'Username already taken' };
|
|
52
52
|
}
|
|
53
53
|
if (codes.length > 0) {
|
|
54
54
|
return { status: 'invalid', message: codes.join(', ') };
|
|
55
55
|
}
|
|
56
|
-
return { status: 'invalid', message: '
|
|
56
|
+
return { status: 'invalid', message: 'Invalid format' };
|
|
57
57
|
}
|
|
58
58
|
if (res.status === 401 || res.status === 403) {
|
|
59
|
-
return { status: 'error', message: `
|
|
59
|
+
return { status: 'error', message: `Invalid token (${res.status})` };
|
|
60
60
|
}
|
|
61
61
|
return { status: 'error', message: `HTTP ${res.status}` };
|
|
62
62
|
}
|
|
63
63
|
catch (err) {
|
|
64
|
-
return { status: 'error', message: err?.code || err?.message || '
|
|
64
|
+
return { status: 'error', message: err?.code || err?.message || 'Network error' };
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
async function validateToken(token, pool) {
|
|
68
|
-
// A lightweight check: a known-taken username should return 400 (taken) rather than 401.
|
|
69
68
|
const res = await checkUsername('discord', token, pool);
|
|
70
|
-
return res.status !== 'error' || !res.message?.includes('
|
|
69
|
+
return res.status !== 'error' || !res.message?.includes('Invalid token');
|
|
71
70
|
}
|
package/dist/index.js
CHANGED
|
@@ -9,35 +9,57 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
9
9
|
const banner_1 = require("./banner");
|
|
10
10
|
const prompts_1 = require("./prompts");
|
|
11
11
|
const config_1 = require("./config");
|
|
12
|
+
const mouse_1 = require("./mouse");
|
|
13
|
+
const updater_1 = require("./updater");
|
|
14
|
+
const version_1 = require("./version");
|
|
12
15
|
const program = new commander_1.Command();
|
|
13
16
|
function guardInteractive() {
|
|
14
17
|
if (!process.stdin.isTTY) {
|
|
15
|
-
console.error(chalk_1.default.yellow('\nwsniper
|
|
16
|
-
'
|
|
18
|
+
console.error(chalk_1.default.yellow('\nwsniper is an interactive tool: please run it in a real terminal.\n' +
|
|
19
|
+
'Example: ') +
|
|
17
20
|
chalk_1.default.cyan('wsniper') +
|
|
18
|
-
chalk_1.default.gray('
|
|
21
|
+
chalk_1.default.gray(' or ') +
|
|
19
22
|
chalk_1.default.cyan('wsniper config'));
|
|
20
23
|
return false;
|
|
21
24
|
}
|
|
22
25
|
return true;
|
|
23
26
|
}
|
|
27
|
+
let sessionHooks = false;
|
|
28
|
+
function startInteractiveSession() {
|
|
29
|
+
if (sessionHooks)
|
|
30
|
+
return;
|
|
31
|
+
sessionHooks = true;
|
|
32
|
+
(0, mouse_1.enableMouse)();
|
|
33
|
+
process.on('exit', mouse_1.disableMouse);
|
|
34
|
+
process.on('SIGINT', () => {
|
|
35
|
+
(0, mouse_1.disableMouse)();
|
|
36
|
+
console.log(chalk_1.default.gray('\nInterrupted.'));
|
|
37
|
+
process.exit(0);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function clearScreen() {
|
|
41
|
+
process.stdout.write('\x1b[2J\x1b[3J\x1b[H');
|
|
42
|
+
}
|
|
24
43
|
program
|
|
25
44
|
.name('wsniper')
|
|
26
|
-
.description('
|
|
27
|
-
.version(
|
|
45
|
+
.description('Discord username availability checker with rotating proxies')
|
|
46
|
+
.version(version_1.VERSION);
|
|
28
47
|
program
|
|
29
48
|
.command('config')
|
|
30
|
-
.description('
|
|
49
|
+
.description('Configure the Discord token and proxies')
|
|
31
50
|
.action(async () => {
|
|
32
51
|
if (!guardInteractive())
|
|
33
52
|
return;
|
|
53
|
+
clearScreen();
|
|
34
54
|
(0, banner_1.printBanner)();
|
|
55
|
+
await (0, updater_1.checkForUpdates)();
|
|
56
|
+
startInteractiveSession();
|
|
35
57
|
const config = (0, config_1.loadConfig)();
|
|
36
58
|
await (0, prompts_1.configureSettings)(config, (c) => (0, config_1.saveConfig)(c));
|
|
37
59
|
});
|
|
38
60
|
program
|
|
39
61
|
.command('path')
|
|
40
|
-
.description('
|
|
62
|
+
.description('Show the config file path')
|
|
41
63
|
.action(() => {
|
|
42
64
|
console.log(config_1.CONFIG_PATH);
|
|
43
65
|
});
|
|
@@ -45,15 +67,20 @@ program
|
|
|
45
67
|
.action(async () => {
|
|
46
68
|
if (!guardInteractive())
|
|
47
69
|
return;
|
|
70
|
+
clearScreen();
|
|
48
71
|
(0, banner_1.printBanner)();
|
|
72
|
+
await (0, updater_1.checkForUpdates)();
|
|
73
|
+
startInteractiveSession();
|
|
49
74
|
const config = (0, config_1.loadConfig)();
|
|
50
75
|
await (0, prompts_1.mainMenu)(config, (c) => (0, config_1.saveConfig)(c));
|
|
51
76
|
});
|
|
52
77
|
program.parseAsync(process.argv).catch((err) => {
|
|
53
78
|
if (err?.name === 'ExitPromptError') {
|
|
54
|
-
|
|
79
|
+
(0, mouse_1.disableMouse)();
|
|
80
|
+
console.log(chalk_1.default.gray('\nInterrupted.'));
|
|
55
81
|
return;
|
|
56
82
|
}
|
|
57
|
-
|
|
83
|
+
(0, mouse_1.disableMouse)();
|
|
84
|
+
console.error(chalk_1.default.red('\nAn error occurred:'), err?.message || err);
|
|
58
85
|
process.exit(1);
|
|
59
86
|
});
|
package/dist/mouse.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.enableMouse = enableMouse;
|
|
4
|
+
exports.disableMouse = disableMouse;
|
|
5
|
+
let enabled = false;
|
|
6
|
+
let patched = false;
|
|
7
|
+
let leftover = '';
|
|
8
|
+
const ARROW_UP = '\x1b[A';
|
|
9
|
+
const ARROW_DOWN = '\x1b[B';
|
|
10
|
+
const MOUSE_SEQ = /\x1b\[<(\d+);(\d+);(\d+)[Mm]/g;
|
|
11
|
+
const PARTIAL_TAIL = /\x1b\[[<>]?\d*(;\d*){0,2}$/;
|
|
12
|
+
function translate(buf) {
|
|
13
|
+
let s = leftover + buf.toString('latin1');
|
|
14
|
+
leftover = '';
|
|
15
|
+
let out = '';
|
|
16
|
+
let last = 0;
|
|
17
|
+
let m;
|
|
18
|
+
MOUSE_SEQ.lastIndex = 0;
|
|
19
|
+
while ((m = MOUSE_SEQ.exec(s)) !== null) {
|
|
20
|
+
out += s.slice(last, m.index);
|
|
21
|
+
const button = parseInt(m[1], 10);
|
|
22
|
+
if (button === 64)
|
|
23
|
+
out += ARROW_UP;
|
|
24
|
+
else if (button === 65)
|
|
25
|
+
out += ARROW_DOWN;
|
|
26
|
+
last = MOUSE_SEQ.lastIndex;
|
|
27
|
+
}
|
|
28
|
+
const remainder = s.slice(last);
|
|
29
|
+
const partial = remainder.match(PARTIAL_TAIL);
|
|
30
|
+
if (partial) {
|
|
31
|
+
leftover = partial[0];
|
|
32
|
+
out += remainder.slice(0, remainder.length - partial[0].length);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
out += remainder;
|
|
36
|
+
}
|
|
37
|
+
if (out.length === 0)
|
|
38
|
+
return Buffer.alloc(0);
|
|
39
|
+
return Buffer.from(out, 'latin1');
|
|
40
|
+
}
|
|
41
|
+
function enableMouse() {
|
|
42
|
+
if (enabled)
|
|
43
|
+
return;
|
|
44
|
+
process.stdout.write('\x1b[?1000h\x1b[?1006h');
|
|
45
|
+
if (!patched) {
|
|
46
|
+
const stdin = process.stdin;
|
|
47
|
+
const origEmit = stdin.emit.bind(stdin);
|
|
48
|
+
stdin.emit = function (event, ...args) {
|
|
49
|
+
if (event === 'data' && Buffer.isBuffer(args[0])) {
|
|
50
|
+
const translated = translate(args[0]);
|
|
51
|
+
if (translated.length === 0)
|
|
52
|
+
return true;
|
|
53
|
+
args[0] = translated;
|
|
54
|
+
}
|
|
55
|
+
return origEmit(event, ...args);
|
|
56
|
+
};
|
|
57
|
+
patched = true;
|
|
58
|
+
}
|
|
59
|
+
enabled = true;
|
|
60
|
+
}
|
|
61
|
+
function disableMouse() {
|
|
62
|
+
if (!enabled)
|
|
63
|
+
return;
|
|
64
|
+
process.stdout.write('\x1b[?1006l\x1b[?1000l');
|
|
65
|
+
enabled = false;
|
|
66
|
+
}
|
package/dist/prompts.js
CHANGED
|
@@ -16,38 +16,41 @@ const generators_1 = require("./generators");
|
|
|
16
16
|
const checker_1 = require("./checker");
|
|
17
17
|
const ui_1 = require("./ui");
|
|
18
18
|
exports.PATTERN_CHOICES = [
|
|
19
|
-
{ name: '
|
|
20
|
-
{ name: '
|
|
21
|
-
{ name: '
|
|
22
|
-
{ name: '
|
|
23
|
-
{ name: '
|
|
24
|
-
{ name: '
|
|
19
|
+
{ name: 'Letters only (a-z)', value: 'letters' },
|
|
20
|
+
{ name: 'Digits only (0-9)', value: 'digits' },
|
|
21
|
+
{ name: 'Letters + Digits', value: 'letters+digits' },
|
|
22
|
+
{ name: 'Letters + Special characters (._)', value: 'letters+special' },
|
|
23
|
+
{ name: 'Letters + Digits + Special characters', value: 'letters+digits+special' },
|
|
24
|
+
{ name: 'Digits + Special characters', value: 'digits+special' },
|
|
25
25
|
];
|
|
26
26
|
exports.PROXY_FORMAT_LINES = [
|
|
27
|
-
chalk_1.default.gray('
|
|
27
|
+
chalk_1.default.gray('One proxy per line. Use # to comment.'),
|
|
28
28
|
'',
|
|
29
29
|
chalk_1.default.white(' http://ip:port'),
|
|
30
|
-
chalk_1.default.white(' http://
|
|
30
|
+
chalk_1.default.white(' http://user:pass@ip:port'),
|
|
31
31
|
chalk_1.default.white(' https://ip:port'),
|
|
32
32
|
chalk_1.default.white(' socks4://ip:port'),
|
|
33
33
|
chalk_1.default.white(' socks5://ip:port'),
|
|
34
|
-
chalk_1.default.white(' socks5://
|
|
35
|
-
chalk_1.default.gray(' ip:port -> http
|
|
36
|
-
chalk_1.default.gray(' ip:port:
|
|
34
|
+
chalk_1.default.white(' socks5://user:pass@ip:port'),
|
|
35
|
+
chalk_1.default.gray(' ip:port -> http by default'),
|
|
36
|
+
chalk_1.default.gray(' ip:port:user:pass -> http by default'),
|
|
37
37
|
];
|
|
38
38
|
async function mainMenu(config, save) {
|
|
39
|
+
if (!config.token && !config.proxy) {
|
|
40
|
+
await onboarding(config, save);
|
|
41
|
+
}
|
|
39
42
|
while (true) {
|
|
40
43
|
const { choice } = await inquirer_1.default.prompt({
|
|
41
44
|
type: 'list',
|
|
42
45
|
name: 'choice',
|
|
43
|
-
message: '
|
|
46
|
+
message: 'What do you want to do?',
|
|
44
47
|
choices: [
|
|
45
|
-
{ name: '
|
|
48
|
+
{ name: 'Launch the checker', value: 'check' },
|
|
46
49
|
{
|
|
47
|
-
name: `
|
|
50
|
+
name: `Settings ${config.token ? chalk_1.default.green('(token ok)') : chalk_1.default.red('(no token)')}`,
|
|
48
51
|
value: 'config',
|
|
49
52
|
},
|
|
50
|
-
{ name: '
|
|
53
|
+
{ name: 'Quit', value: 'quit' },
|
|
51
54
|
],
|
|
52
55
|
});
|
|
53
56
|
if (choice === 'check') {
|
|
@@ -57,56 +60,118 @@ async function mainMenu(config, save) {
|
|
|
57
60
|
await configureSettings(config, save);
|
|
58
61
|
}
|
|
59
62
|
else {
|
|
60
|
-
console.log(chalk_1.default.gray('\
|
|
63
|
+
console.log(chalk_1.default.gray('\nGoodbye!'));
|
|
61
64
|
break;
|
|
62
65
|
}
|
|
63
66
|
}
|
|
64
67
|
}
|
|
68
|
+
async function onboarding(config, save) {
|
|
69
|
+
console.log((0, ui_1.box)('Welcome to WSniper', [
|
|
70
|
+
chalk_1.default.white('This tool checks Discord username availability'),
|
|
71
|
+
chalk_1.default.white('via the official Discord API.'),
|
|
72
|
+
'',
|
|
73
|
+
chalk_1.default.gray('To run checks you need:'),
|
|
74
|
+
chalk_1.default.gray(' • A Discord token (always required to authenticate)'),
|
|
75
|
+
chalk_1.default.gray(' • Proxies (recommended, to rotate your IP)'),
|
|
76
|
+
]));
|
|
77
|
+
console.log();
|
|
78
|
+
const { hasProxies } = await inquirer_1.default.prompt({
|
|
79
|
+
type: 'confirm',
|
|
80
|
+
name: 'hasProxies',
|
|
81
|
+
message: 'Do you have proxies to use?',
|
|
82
|
+
default: false,
|
|
83
|
+
});
|
|
84
|
+
if (hasProxies) {
|
|
85
|
+
const pool = await loadProxyFile(config);
|
|
86
|
+
if (pool.size === 0) {
|
|
87
|
+
console.log(chalk_1.default.red(' No valid proxies found in the file.'));
|
|
88
|
+
}
|
|
89
|
+
console.log(chalk_1.default.green(` ${pool.size} proxy(s) loaded.`));
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
console.log((0, ui_1.box)('No proxies', [
|
|
93
|
+
chalk_1.default.yellow('Checks will run on your own IP address.'),
|
|
94
|
+
chalk_1.default.gray('This is RISKY: Discord may rate-limit or ban'),
|
|
95
|
+
chalk_1.default.gray('your account/IP on mass scanning.'),
|
|
96
|
+
'',
|
|
97
|
+
chalk_1.default.gray('You can add proxies later in Settings.'),
|
|
98
|
+
]));
|
|
99
|
+
}
|
|
100
|
+
console.log();
|
|
101
|
+
console.log((0, ui_1.box)('Discord token required', [
|
|
102
|
+
chalk_1.default.white('The availability API requires authentication:'),
|
|
103
|
+
chalk_1.default.gray('your token is sent with each request to authorize'),
|
|
104
|
+
chalk_1.default.gray('the check, even when using proxies.'),
|
|
105
|
+
'',
|
|
106
|
+
chalk_1.default.yellow('Warning: using your account token carries risk.'),
|
|
107
|
+
chalk_1.default.gray('Use an alt account if possible.'),
|
|
108
|
+
]));
|
|
109
|
+
console.log();
|
|
110
|
+
const { token } = await inquirer_1.default.prompt({
|
|
111
|
+
type: 'password',
|
|
112
|
+
name: 'token',
|
|
113
|
+
mask: '*',
|
|
114
|
+
message: 'Discord token:',
|
|
115
|
+
validate: (v) => (v && v.length > 10 ? true : 'Invalid token'),
|
|
116
|
+
});
|
|
117
|
+
config.token = token;
|
|
118
|
+
save(config);
|
|
119
|
+
console.log(chalk_1.default.green('\n Setup complete!'));
|
|
120
|
+
console.log(chalk_1.default.gray(' You can change these anytime in Settings.\n'));
|
|
121
|
+
}
|
|
122
|
+
async function loadProxyFile(config) {
|
|
123
|
+
console.log((0, ui_1.box)('Proxy format', exports.PROXY_FORMAT_LINES));
|
|
124
|
+
console.log();
|
|
125
|
+
const { file } = await inquirer_1.default.prompt({
|
|
126
|
+
type: 'input',
|
|
127
|
+
name: 'file',
|
|
128
|
+
message: 'Path to the proxy .txt file:',
|
|
129
|
+
default: 'proxies.txt',
|
|
130
|
+
validate: (v) => v && fs_1.default.existsSync(v) ? true : 'File not found',
|
|
131
|
+
});
|
|
132
|
+
const { rotating } = await inquirer_1.default.prompt({
|
|
133
|
+
type: 'confirm',
|
|
134
|
+
name: 'rotating',
|
|
135
|
+
message: 'Are your proxies rotating (the provider changes the IP automatically)?',
|
|
136
|
+
default: true,
|
|
137
|
+
});
|
|
138
|
+
const pool = proxies_1.ProxyPool.loadFromFile(file, rotating);
|
|
139
|
+
config.proxy = { file, rotating, loaded: pool.list };
|
|
140
|
+
return pool;
|
|
141
|
+
}
|
|
65
142
|
async function ensureProxyPool(config) {
|
|
66
143
|
const choices = [];
|
|
67
144
|
if (config.proxy && config.proxy.file && fs_1.default.existsSync(config.proxy.file)) {
|
|
68
145
|
const n = config.proxy.loaded?.length ?? 0;
|
|
69
146
|
choices.push({
|
|
70
|
-
name: `
|
|
147
|
+
name: `Use saved proxies (${n} • ${config.proxy.rotating ? 'rotating' : 'static'})`,
|
|
71
148
|
value: 'saved',
|
|
72
149
|
});
|
|
73
150
|
}
|
|
74
|
-
choices.push({ name: '
|
|
75
|
-
choices.push({ name: '
|
|
151
|
+
choices.push({ name: 'Load a new proxy file', value: 'new' });
|
|
152
|
+
choices.push({ name: 'Direct connection (no proxy)', value: 'direct' });
|
|
76
153
|
const { mode } = await inquirer_1.default.prompt({
|
|
77
154
|
type: 'list',
|
|
78
155
|
name: 'mode',
|
|
79
|
-
message: '
|
|
156
|
+
message: 'Proxy configuration:',
|
|
80
157
|
choices,
|
|
81
158
|
});
|
|
82
159
|
if (mode === 'direct') {
|
|
83
|
-
console.log(
|
|
160
|
+
console.log((0, ui_1.box)('No proxies', [
|
|
161
|
+
chalk_1.default.yellow('Checks will run on your own IP address.'),
|
|
162
|
+
chalk_1.default.gray('RISKY: Discord may rate-limit or ban your'),
|
|
163
|
+
chalk_1.default.gray('account/IP on mass scanning.'),
|
|
164
|
+
]));
|
|
84
165
|
return null;
|
|
85
166
|
}
|
|
86
167
|
if (mode === 'saved') {
|
|
87
168
|
return proxies_1.ProxyPool.loadFromFile(config.proxy.file, config.proxy.rotating);
|
|
88
169
|
}
|
|
89
|
-
|
|
90
|
-
console.log();
|
|
91
|
-
const { file } = await inquirer_1.default.prompt({
|
|
92
|
-
type: 'input',
|
|
93
|
-
name: 'file',
|
|
94
|
-
message: 'Chemin du fichier .txt de proxies :',
|
|
95
|
-
default: 'proxies.txt',
|
|
96
|
-
validate: (v) => v && fs_1.default.existsSync(v) ? true : 'Fichier introuvable',
|
|
97
|
-
});
|
|
98
|
-
const { rotating } = await inquirer_1.default.prompt({
|
|
99
|
-
type: 'confirm',
|
|
100
|
-
name: 'rotating',
|
|
101
|
-
message: "Vos proxies sont-ils rotatifs (le fournisseur change l'IP automatiquement) ?",
|
|
102
|
-
default: true,
|
|
103
|
-
});
|
|
104
|
-
const pool = proxies_1.ProxyPool.loadFromFile(file, rotating);
|
|
170
|
+
const pool = await loadProxyFile(config);
|
|
105
171
|
if (pool.size === 0) {
|
|
106
|
-
console.log(chalk_1.default.red('
|
|
172
|
+
console.log(chalk_1.default.red(' No valid proxies found in the file.'));
|
|
107
173
|
}
|
|
108
|
-
|
|
109
|
-
console.log(chalk_1.default.green(` ${pool.size} proxy(s) chargé(s).`));
|
|
174
|
+
console.log(chalk_1.default.green(` ${pool.size} proxy(s) loaded.`));
|
|
110
175
|
return pool;
|
|
111
176
|
}
|
|
112
177
|
async function ensureToken(config, save) {
|
|
@@ -114,7 +179,7 @@ async function ensureToken(config, save) {
|
|
|
114
179
|
const { reuse } = await inquirer_1.default.prompt({
|
|
115
180
|
type: 'confirm',
|
|
116
181
|
name: 'reuse',
|
|
117
|
-
message: '
|
|
182
|
+
message: 'Use the saved token?',
|
|
118
183
|
default: true,
|
|
119
184
|
});
|
|
120
185
|
if (reuse)
|
|
@@ -124,8 +189,8 @@ async function ensureToken(config, save) {
|
|
|
124
189
|
type: 'password',
|
|
125
190
|
name: 'token',
|
|
126
191
|
mask: '*',
|
|
127
|
-
message: '
|
|
128
|
-
validate: (v) => (v && v.length > 10 ? true : '
|
|
192
|
+
message: 'Discord token:',
|
|
193
|
+
validate: (v) => (v && v.length > 10 ? true : 'Invalid token'),
|
|
129
194
|
});
|
|
130
195
|
config.token = token;
|
|
131
196
|
save(config);
|
|
@@ -135,28 +200,28 @@ async function runChecker(config, save) {
|
|
|
135
200
|
const { pattern } = await inquirer_1.default.prompt({
|
|
136
201
|
type: 'list',
|
|
137
202
|
name: 'pattern',
|
|
138
|
-
message: 'Type
|
|
203
|
+
message: 'Type of username to generate:',
|
|
139
204
|
choices: exports.PATTERN_CHOICES,
|
|
140
205
|
});
|
|
141
206
|
const maxLen = 32;
|
|
142
207
|
const { length } = await inquirer_1.default.prompt({
|
|
143
208
|
type: 'number',
|
|
144
209
|
name: 'length',
|
|
145
|
-
message: `
|
|
210
|
+
message: `Username length (2-${maxLen}):`,
|
|
146
211
|
default: 4,
|
|
147
|
-
validate: (v) => v >= 2 && v <= maxLen ? true : `
|
|
212
|
+
validate: (v) => v >= 2 && v <= maxLen ? true : `Between 2 and ${maxLen}`,
|
|
148
213
|
});
|
|
149
214
|
const maxUnique = (0, generators_1.maxUniqueFor)(pattern, length);
|
|
150
215
|
const { count } = await inquirer_1.default.prompt({
|
|
151
216
|
type: 'number',
|
|
152
217
|
name: 'count',
|
|
153
|
-
message: '
|
|
218
|
+
message: 'How many usernames to check?',
|
|
154
219
|
default: 50,
|
|
155
|
-
validate: (v) => v >= 1 && v <= 100000 ? true : '
|
|
220
|
+
validate: (v) => v >= 1 && v <= 100000 ? true : 'Between 1 and 100000',
|
|
156
221
|
});
|
|
157
222
|
const effectiveCount = Math.min(count, maxUnique);
|
|
158
223
|
if (effectiveCount < count) {
|
|
159
|
-
console.log(chalk_1.default.yellow(`
|
|
224
|
+
console.log(chalk_1.default.yellow(` Only ${maxUnique} possible combinations for "${(0, generators_1.patternLabel)(pattern)}" of length ${length}.`));
|
|
160
225
|
}
|
|
161
226
|
const token = await ensureToken(config, save);
|
|
162
227
|
const pool = await ensureProxyPool(config);
|
|
@@ -164,21 +229,21 @@ async function runChecker(config, save) {
|
|
|
164
229
|
const { concurrency } = await inquirer_1.default.prompt({
|
|
165
230
|
type: 'number',
|
|
166
231
|
name: 'concurrency',
|
|
167
|
-
message: '
|
|
232
|
+
message: 'Concurrency (simultaneous requests):',
|
|
168
233
|
default: pool && pool.size > 0 ? Math.min(pool.size, 10) : 1,
|
|
169
|
-
validate: (v) => (v >= 1 && v <= 100 ? true : '
|
|
234
|
+
validate: (v) => (v >= 1 && v <= 100 ? true : 'Between 1 and 100'),
|
|
170
235
|
});
|
|
171
236
|
const { delay } = await inquirer_1.default.prompt({
|
|
172
237
|
type: 'number',
|
|
173
238
|
name: 'delay',
|
|
174
|
-
message: '
|
|
239
|
+
message: 'Delay between requests (ms):',
|
|
175
240
|
default: 0,
|
|
176
241
|
validate: (v) => v >= 0 ? true : '>= 0',
|
|
177
242
|
});
|
|
178
243
|
const usernames = (0, generators_1.generateUsernames)(pattern, length, effectiveCount);
|
|
179
|
-
console.log(chalk_1.default.cyan(`\
|
|
244
|
+
console.log(chalk_1.default.cyan(`\nGenerating ${usernames.length} usernames (${(0, generators_1.patternLabel)(pattern)}, length ${length})...`));
|
|
180
245
|
const stats = { available: 0, taken: 0, invalid: 0, errors: 0, total: usernames.length };
|
|
181
|
-
const spinner = (0, ora_1.default)({ text: '
|
|
246
|
+
const spinner = (0, ora_1.default)({ text: 'Checking...', spinner: 'dots' }).start();
|
|
182
247
|
const onProgress = (done, total, r) => {
|
|
183
248
|
if (r.status === 'available')
|
|
184
249
|
stats.available++;
|
|
@@ -196,7 +261,7 @@ async function runChecker(config, save) {
|
|
|
196
261
|
`${chalk_1.default.gray('?' + stats.errors)}`;
|
|
197
262
|
if (r.status === 'available') {
|
|
198
263
|
spinner.stop();
|
|
199
|
-
console.log(chalk_1.default.green.bold(' ✓
|
|
264
|
+
console.log(chalk_1.default.green.bold(' ✓ AVAILABLE: ') + chalk_1.default.white.bold(r.username));
|
|
200
265
|
spinner.start();
|
|
201
266
|
}
|
|
202
267
|
};
|
|
@@ -207,9 +272,9 @@ async function runChecker(config, save) {
|
|
|
207
272
|
delayMs: delay,
|
|
208
273
|
onProgress,
|
|
209
274
|
});
|
|
210
|
-
spinner.succeed(chalk_1.default.green('
|
|
275
|
+
spinner.succeed(chalk_1.default.green('Check complete!'));
|
|
211
276
|
console.log();
|
|
212
|
-
console.log((0, ui_1.box)('
|
|
277
|
+
console.log((0, ui_1.box)('Summary', (0, ui_1.summaryLines)(stats)));
|
|
213
278
|
console.log();
|
|
214
279
|
const available = results.filter((r) => r.status === 'available');
|
|
215
280
|
if (available.length > 0) {
|
|
@@ -217,27 +282,27 @@ async function runChecker(config, save) {
|
|
|
217
282
|
const stamp = Date.now();
|
|
218
283
|
const availFile = `available_${stamp}.txt`;
|
|
219
284
|
fs_1.default.writeFileSync(availFile, available.map((r) => r.username).join('\n'), 'utf-8');
|
|
220
|
-
console.log(chalk_1.default.green(`\n
|
|
285
|
+
console.log(chalk_1.default.green(`\n Available usernames saved: ${chalk_1.default.bold(availFile)}`));
|
|
221
286
|
}
|
|
222
287
|
else {
|
|
223
|
-
console.log(chalk_1.default.gray('
|
|
288
|
+
console.log(chalk_1.default.gray(' No available usernames found.'));
|
|
224
289
|
}
|
|
225
290
|
const stamp = Date.now();
|
|
226
291
|
const resFile = `results_${stamp}.txt`;
|
|
227
292
|
fs_1.default.writeFileSync(resFile, results.map((r) => `${r.username}\t${r.status}${r.message ? '\t' + r.message : ''}`).join('\n'), 'utf-8');
|
|
228
|
-
console.log(chalk_1.default.gray(`
|
|
293
|
+
console.log(chalk_1.default.gray(` Full results: ${resFile}\n`));
|
|
229
294
|
}
|
|
230
295
|
async function configureSettings(config, save) {
|
|
231
|
-
console.log((0, ui_1.box)('
|
|
232
|
-
`Token : ${config.token ? chalk_1.default.green('
|
|
233
|
-
`Proxies : ${config.proxy ? `${config.proxy.loaded?.length ?? 0} • ${config.proxy.rotating ? '
|
|
234
|
-
`
|
|
296
|
+
console.log((0, ui_1.box)('Current configuration', [
|
|
297
|
+
`Token : ${config.token ? chalk_1.default.green('set') + chalk_1.default.gray(' (' + config.token.slice(0, 6) + '...)') : chalk_1.default.red('not set')}`,
|
|
298
|
+
`Proxies : ${config.proxy ? `${config.proxy.loaded?.length ?? 0} • ${config.proxy.rotating ? 'rotating' : 'static'}` : chalk_1.default.red('not configured')}`,
|
|
299
|
+
`File : ${config.proxy?.file ?? '-'}`,
|
|
235
300
|
]));
|
|
236
301
|
console.log();
|
|
237
302
|
const { setToken } = await inquirer_1.default.prompt({
|
|
238
303
|
type: 'confirm',
|
|
239
304
|
name: 'setToken',
|
|
240
|
-
message: '
|
|
305
|
+
message: 'Set a new Discord token?',
|
|
241
306
|
default: !config.token,
|
|
242
307
|
});
|
|
243
308
|
if (setToken) {
|
|
@@ -245,17 +310,17 @@ async function configureSettings(config, save) {
|
|
|
245
310
|
type: 'password',
|
|
246
311
|
name: 'token',
|
|
247
312
|
mask: '*',
|
|
248
|
-
message: '
|
|
249
|
-
validate: (v) => (v && v.length > 10 ? true : '
|
|
313
|
+
message: 'Discord token:',
|
|
314
|
+
validate: (v) => (v && v.length > 10 ? true : 'Invalid token'),
|
|
250
315
|
});
|
|
251
316
|
config.token = token;
|
|
252
317
|
save(config);
|
|
253
|
-
console.log(chalk_1.default.green(' Token
|
|
318
|
+
console.log(chalk_1.default.green(' Token saved.'));
|
|
254
319
|
}
|
|
255
320
|
const pool = await ensureProxyPool(config);
|
|
256
321
|
if (pool) {
|
|
257
322
|
config.proxy = { ...config.proxy, loaded: pool.list };
|
|
258
323
|
}
|
|
259
324
|
save(config);
|
|
260
|
-
console.log(chalk_1.default.green('\nConfiguration
|
|
325
|
+
console.log(chalk_1.default.green('\nConfiguration saved.'));
|
|
261
326
|
}
|
package/dist/ui.js
CHANGED
|
@@ -73,12 +73,12 @@ function statusLabel(status) {
|
|
|
73
73
|
function availableTable(results) {
|
|
74
74
|
const available = results.filter((r) => r.status === 'available');
|
|
75
75
|
if (available.length === 0)
|
|
76
|
-
return chalk_1.default.gray('
|
|
76
|
+
return chalk_1.default.gray('No available usernames found.');
|
|
77
77
|
const table = new cli_table3_1.default({
|
|
78
78
|
head: [
|
|
79
79
|
chalk_1.default.cyan.bold('#'),
|
|
80
|
-
chalk_1.default.cyan.bold('
|
|
81
|
-
chalk_1.default.cyan.bold('
|
|
80
|
+
chalk_1.default.cyan.bold('Username'),
|
|
81
|
+
chalk_1.default.cyan.bold('Status'),
|
|
82
82
|
],
|
|
83
83
|
colWidths: [6, 26, 16],
|
|
84
84
|
style: { head: [], border: ['gray'] },
|
|
@@ -90,10 +90,10 @@ function availableTable(results) {
|
|
|
90
90
|
}
|
|
91
91
|
function summaryLines(stats) {
|
|
92
92
|
return [
|
|
93
|
-
` ${chalk_1.default.green.bold('
|
|
94
|
-
` ${chalk_1.default.red('
|
|
95
|
-
` ${chalk_1.default.yellow('
|
|
96
|
-
` ${chalk_1.default.gray('
|
|
93
|
+
` ${chalk_1.default.green.bold('Available')} : ${stats.available}`,
|
|
94
|
+
` ${chalk_1.default.red('Taken')} : ${stats.taken}`,
|
|
95
|
+
` ${chalk_1.default.yellow('Invalid')} : ${stats.invalid}`,
|
|
96
|
+
` ${chalk_1.default.gray('Errors')} : ${stats.errors}`,
|
|
97
97
|
` ${chalk_1.default.cyan('Total')} : ${stats.total}`,
|
|
98
98
|
];
|
|
99
99
|
}
|
package/dist/updater.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.isNewer = isNewer;
|
|
7
|
+
exports.checkForUpdates = checkForUpdates;
|
|
8
|
+
const axios_1 = __importDefault(require("axios"));
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const child_process_1 = require("child_process");
|
|
11
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
12
|
+
const version_1 = require("./version");
|
|
13
|
+
const REGISTRY_URL = `https://registry.npmjs.org/${version_1.PACKAGE_NAME}/latest`;
|
|
14
|
+
function parseSemver(v) {
|
|
15
|
+
const clean = v.replace(/^v/, '').trim();
|
|
16
|
+
const parts = clean.split('.').map((p) => parseInt(p, 10) || 0);
|
|
17
|
+
return [parts[0] || 0, parts[1] || 0, parts[2] || 0];
|
|
18
|
+
}
|
|
19
|
+
function isNewer(remote, local) {
|
|
20
|
+
const r = parseSemver(remote);
|
|
21
|
+
const l = parseSemver(local);
|
|
22
|
+
for (let i = 0; i < 3; i++) {
|
|
23
|
+
if (r[i] > l[i])
|
|
24
|
+
return true;
|
|
25
|
+
if (r[i] < l[i])
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
async function fetchLatestVersion() {
|
|
31
|
+
try {
|
|
32
|
+
const res = await axios_1.default.get(REGISTRY_URL, {
|
|
33
|
+
timeout: 5000,
|
|
34
|
+
validateStatus: () => true,
|
|
35
|
+
proxy: false,
|
|
36
|
+
});
|
|
37
|
+
if (res.status === 200 && res.data?.version) {
|
|
38
|
+
return res.data.version;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// network error or unreachable, skip update check
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
async function promptUpdate(latest) {
|
|
47
|
+
const { install } = await inquirer_1.default.prompt({
|
|
48
|
+
type: 'confirm',
|
|
49
|
+
name: 'install',
|
|
50
|
+
message: 'A new update was detected. Do you want to install it? (y/n)',
|
|
51
|
+
default: true,
|
|
52
|
+
});
|
|
53
|
+
return install;
|
|
54
|
+
}
|
|
55
|
+
function installUpdate() {
|
|
56
|
+
return new Promise((resolve) => {
|
|
57
|
+
console.log(chalk_1.default.cyan(' Installing update...'));
|
|
58
|
+
const child = (0, child_process_1.spawn)('npm', ['install', '-g', version_1.PACKAGE_NAME], {
|
|
59
|
+
stdio: 'inherit',
|
|
60
|
+
shell: true,
|
|
61
|
+
});
|
|
62
|
+
child.on('close', () => {
|
|
63
|
+
resolve();
|
|
64
|
+
});
|
|
65
|
+
child.on('error', () => {
|
|
66
|
+
console.log(chalk_1.default.red(' Failed to install update automatically.'));
|
|
67
|
+
console.log(chalk_1.default.gray(` Run manually: npm install -g ${version_1.PACKAGE_NAME}`));
|
|
68
|
+
resolve();
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
async function checkForUpdates() {
|
|
73
|
+
const latest = await fetchLatestVersion();
|
|
74
|
+
if (!latest)
|
|
75
|
+
return;
|
|
76
|
+
if (!isNewer(latest, version_1.VERSION))
|
|
77
|
+
return;
|
|
78
|
+
console.log();
|
|
79
|
+
console.log(boxUpdate(`Update available ${chalk_1.default.gray(version_1.VERSION)} -> ${chalk_1.default.green(latest)}`));
|
|
80
|
+
const install = await promptUpdate(latest);
|
|
81
|
+
if (install) {
|
|
82
|
+
await installUpdate();
|
|
83
|
+
console.log(chalk_1.default.green(' Update complete. Please relaunch wsniper.'));
|
|
84
|
+
process.exit(0);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
console.log(chalk_1.default.gray(' Skipping update. Continuing...\n'));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function boxUpdate(message) {
|
|
91
|
+
const inner = ` ${message} `;
|
|
92
|
+
const width = inner.length;
|
|
93
|
+
const top = chalk_1.default.gray('┌' + '─'.repeat(width) + '┐');
|
|
94
|
+
const mid = chalk_1.default.gray('│') + inner + chalk_1.default.gray('│');
|
|
95
|
+
const bot = chalk_1.default.gray('└' + '─'.repeat(width) + '┘');
|
|
96
|
+
return [top, mid, bot].join('\n');
|
|
97
|
+
}
|
package/dist/version.js
ADDED
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name": "wsnipz", "version": "1.
|
|
1
|
+
{"name": "wsnipz", "version": "1.2.0", "description": "A modern Discord username availability checker CLI with rotating proxy support.", "main": "dist/index.js", "bin": {"wsniper": "dist/index.js", "wsnipz": "dist/index.js"}, "files": ["dist"], "scripts": {"build": "tsc", "dev": "ts-node src/index.ts", "start": "node dist/index.js", "prepublishOnly": "npm run build"}, "keywords": ["discord", "username", "checker", "sniper", "cli", "proxy", "availability", "wsnipz"], "author": "", "license": "MIT", "engines": {"node": ">=16"}, "dependencies": {"axios": "^1.7.7", "chalk": "^4.1.2", "cli-table3": "^0.6.5", "commander": "^11.1.0", "figlet": "^1.8.0", "inquirer": "^8.2.6", "ora": "^5.4.1", "proxy-agent": "^5.0.0"}, "devDependencies": {"@types/figlet": "^1.7.0", "@types/inquirer": "^8.2.10", "@types/node": "^20.16.0", "ts-node": "^10.9.2", "typescript": "^5.6.0"}}
|