fazer-lang 2.7.0 → 2.8.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/CHANGELOG.md +13 -0
- package/README.md +8 -0
- package/docs/CLI_TOOLS.md +48 -0
- package/docs/stdlib.md +25 -0
- package/fazer.js +816 -74
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [2.7.0] - 2026-01-23
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **OSINT CLI Tools**: >30 native commands available directly from terminal (`fazer geo`, `scan`, `whois`, `sub`, etc.).
|
|
9
|
+
- **New Built-in Functions**: Added `abs`, `min`, `max`, `pow`, `sqrt`, `pad_start`, `pad_end`, `cp`, `mv`, `ls`, `mkdir`, `rm`, `download`, `env_set`.
|
|
10
|
+
- **Recursion**: Added support for recursive file operations (e.g., `rm` recursive).
|
|
11
|
+
- **HTTP Redirects**: `download` function now automatically follows redirects.
|
|
12
|
+
- **Cross-Platform**: CLI tools now use Node.js native modules (`net`, `dns`, `http`) for better Linux compatibility.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
- **Documentation**: Major update to `README.md` and new `CLI_TOOLS.md` guide.
|
|
16
|
+
- **Error Handling**: Improved stability and error reporting for CLI commands.
|
|
17
|
+
|
|
5
18
|
## [2.6.0] - 2026-01-22
|
|
6
19
|
|
|
7
20
|
### Added
|
package/README.md
CHANGED
|
@@ -24,6 +24,13 @@ Exécuter un script :
|
|
|
24
24
|
fazer mon_script.fz
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
+
Utiliser les outils CLI (OSINT) :
|
|
28
|
+
```bash
|
|
29
|
+
fazer geo 8.8.8.8
|
|
30
|
+
fazer scan google.com
|
|
31
|
+
fazer whois microsoft.com
|
|
32
|
+
```
|
|
33
|
+
|
|
27
34
|
## Création d'Exécutable (.exe)
|
|
28
35
|
|
|
29
36
|
Transformez vos scripts Fazer en applications Windows portables et natives :
|
|
@@ -45,6 +52,7 @@ Documentation détaillée par section :
|
|
|
45
52
|
* [Guide de Démarrage](https://github.com/viced-1920/fazer-lang/blob/main/docs/getting-started.md)
|
|
46
53
|
* [Syntaxe du Langage](https://github.com/viced-1920/fazer-lang/blob/main/docs/syntax.md)
|
|
47
54
|
* [Bibliothèque Standard (Stdlib)](https://github.com/viced-1920/fazer-lang/blob/main/docs/stdlib.md)
|
|
55
|
+
* [Outils CLI (OSINT & Sys)](https://github.com/viced-1920/fazer-lang/blob/main/docs/CLI_TOOLS.md)
|
|
48
56
|
* [Exemples](https://github.com/viced-1920/fazer-lang/blob/main/docs/examples.md)
|
|
49
57
|
|
|
50
58
|
## Fonctionnalités Clés
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Fazer CLI - Outils & Commandes
|
|
2
|
+
|
|
3
|
+
Fazer intègre une suite complète d'outils CLI (>30 commandes) pour l'OSINT, le réseau, la cryptographie et l'administration système.
|
|
4
|
+
|
|
5
|
+
## Utilisation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
fazer <commande> [arguments...]
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 🌐 Réseau & OSINT
|
|
12
|
+
|
|
13
|
+
* **`geo <ip/domain>`** : Géolocalisation précise (Pays, Ville, ISP, Map).
|
|
14
|
+
* **`ip`** : Affiche votre IP publique actuelle.
|
|
15
|
+
* **`scan <host> [ports]`** : Scanner de ports TCP rapide.
|
|
16
|
+
* **`ping <host> [port]`** : Ping TCP pour vérifier la connectivité.
|
|
17
|
+
* **`whois <domain>`** : Informations WHOIS complètes.
|
|
18
|
+
* **`sub <domain>`** : Énumération de sous-domaines (via Certificate Transparency).
|
|
19
|
+
* **`dns <domain>`** : Résolution DNS (A, MX, TXT, NS, SOA).
|
|
20
|
+
* **`tech <url>`** : Détection de technologies (Headers, Cookies, Server).
|
|
21
|
+
* **`headers <url>`** : Affiche les en-têtes HTTP.
|
|
22
|
+
* **`ssl <host> [port]`** : Inspecte le certificat SSL/TLS (Issuer, Validité, Fingerprint).
|
|
23
|
+
* **`curl <url>`** : Affiche le corps de la réponse HTTP (GET).
|
|
24
|
+
* **`robots <url>`** : Récupère et affiche le fichier robots.txt.
|
|
25
|
+
|
|
26
|
+
## 🔒 Cryptographie & Encodage
|
|
27
|
+
|
|
28
|
+
* **`b64 <enc|dec> <str>`** : Encodage/Décodage Base64.
|
|
29
|
+
* **`hex <enc|dec> <str>`** : Encodage/Décodage Hexadécimal.
|
|
30
|
+
* **`url <enc|dec> <str>`** : Encodage/Décodage URL.
|
|
31
|
+
* **`md5 <str>`** : Hash MD5.
|
|
32
|
+
* **`sha1 <str>`** : Hash SHA1.
|
|
33
|
+
* **`sha256 <str>`** : Hash SHA256.
|
|
34
|
+
* **`uuid`** : Génère un UUID v4 aléatoire.
|
|
35
|
+
|
|
36
|
+
## 💻 Système & Utilitaires
|
|
37
|
+
|
|
38
|
+
* **`ls [dir]`** : Liste les fichiers et dossiers.
|
|
39
|
+
* **`cat <file>`** : Affiche le contenu d'un fichier.
|
|
40
|
+
* **`grep <regex> <file>`** : Recherche un motif dans un fichier.
|
|
41
|
+
* **`wc <file>`** : Compte les lignes et caractères d'un fichier.
|
|
42
|
+
* **`whoami`** : Affiche l'utilisateur et la machine actuels.
|
|
43
|
+
* **`env`** : Affiche les variables d'environnement.
|
|
44
|
+
* **`pass [len]`** : Génère un mot de passe sécurisé (défaut 16 chars).
|
|
45
|
+
* **`calc <expr>`** : Calculatrice mathématique (ex: `10 * 5 + 2`).
|
|
46
|
+
* **`now`** : Affiche la date et le timestamp actuels.
|
|
47
|
+
* **`coin`** : Pile ou Face.
|
|
48
|
+
* **`dice`** : Lance un dé (1-6).
|
package/docs/stdlib.md
CHANGED
|
@@ -115,3 +115,28 @@ Télécharge un fichier depuis une URL vers un chemin local.
|
|
|
115
115
|
```fazer
|
|
116
116
|
success := download("https://example.com/image.png", "img.png")
|
|
117
117
|
```
|
|
118
|
+
|
|
119
|
+
## Terminal Avancé (UI & FX)
|
|
120
|
+
|
|
121
|
+
Fonctionnalités pour créer des interfaces en ligne de commande (TUI) riches et animées.
|
|
122
|
+
|
|
123
|
+
### Couleurs & Styles (TrueColor)
|
|
124
|
+
* `rgb(r, g, b, text)` : Texte en couleur TrueColor (16 millions de couleurs).
|
|
125
|
+
* `bg_rgb(r, g, b, text)` : Arrière-plan en couleur TrueColor.
|
|
126
|
+
* `gradient(text, r1, g1, b1, r2, g2, b2)` : Applique un dégradé linéaire sur le texte entre deux couleurs RGB.
|
|
127
|
+
* `style(text, style_name)` : Styles de base ("bold", "dim", "red", "blue", etc.).
|
|
128
|
+
|
|
129
|
+
### Curseur & Affichage
|
|
130
|
+
* `term_clear()` : Efface l'écran.
|
|
131
|
+
* `term_pos(row, col)` : Déplace le curseur.
|
|
132
|
+
* `term_hide()` / `cursor_hide()` : Masque le curseur.
|
|
133
|
+
* `term_show()` / `cursor_show()` : Affiche le curseur.
|
|
134
|
+
* `term_title(text)` : Change le titre de la fenêtre du terminal.
|
|
135
|
+
* `cursor_save()` : Sauvegarde la position du curseur.
|
|
136
|
+
* `cursor_restore()` : Restaure la position sauvegardée.
|
|
137
|
+
|
|
138
|
+
### Composants UI
|
|
139
|
+
* `ui_bar(val, max, width, char)` : Génère une barre de progression.
|
|
140
|
+
* Exemple : `ui_bar(50, 100, 20)` -> `██████████ `
|
|
141
|
+
* `box(title, line1, line2, ...)` : Affiche une boîte encadrée.
|
|
142
|
+
|
package/fazer.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
const fs = require("fs");
|
|
12
12
|
const path = require("path");
|
|
13
13
|
const crypto = require("crypto");
|
|
14
|
+
const os = require("os");
|
|
14
15
|
const { Lexer, createToken, EmbeddedActionsParser } = require("chevrotain");
|
|
15
16
|
|
|
16
17
|
/* ────────────────────────────────────────────────────────────────────────── */
|
|
@@ -21,6 +22,7 @@ const WhiteSpace = createToken({ name: "WhiteSpace", pattern: /[ \t\r\n]+/, grou
|
|
|
21
22
|
const Comment = createToken({ name: "Comment", pattern: /(#|\/\/)[^\n]*/, group: Lexer.SKIPPED });
|
|
22
23
|
|
|
23
24
|
const Assign = createToken({ name: "Assign", pattern: /:=/ });
|
|
25
|
+
const SingleEq = createToken({ name: "SingleEq", pattern: /=/ });
|
|
24
26
|
|
|
25
27
|
const Arrow = createToken({ name: "Arrow", pattern: /->|→/ });
|
|
26
28
|
const DoublePipe = createToken({ name: "DoublePipe", pattern: /->>|\|>|→>/ });
|
|
@@ -116,6 +118,7 @@ const allTokens = [
|
|
|
116
118
|
NotEq,
|
|
117
119
|
Greater,
|
|
118
120
|
Less,
|
|
121
|
+
SingleEq,
|
|
119
122
|
|
|
120
123
|
LParen,
|
|
121
124
|
RParen,
|
|
@@ -174,7 +177,7 @@ class FazerParser extends EmbeddedActionsParser {
|
|
|
174
177
|
const t1 = $.LA(1).tokenType;
|
|
175
178
|
if (t1 === Mut) return true;
|
|
176
179
|
const t2 = $.LA(2).tokenType;
|
|
177
|
-
return t1 === Identifier && t2 === Assign;
|
|
180
|
+
return t1 === Identifier && (t2 === Assign || t2 === SingleEq);
|
|
178
181
|
},
|
|
179
182
|
ALT: () => $.SUBRULE($.assignStmt)
|
|
180
183
|
},
|
|
@@ -261,7 +264,19 @@ class FazerParser extends EmbeddedActionsParser {
|
|
|
261
264
|
$.RULE("assignStmt", () => {
|
|
262
265
|
const mutTok = $.OPTION(() => $.CONSUME(Mut));
|
|
263
266
|
const idTok = $.CONSUME(Identifier);
|
|
264
|
-
|
|
267
|
+
|
|
268
|
+
const op = $.OR([
|
|
269
|
+
{ ALT: () => $.CONSUME(Assign) },
|
|
270
|
+
{ ALT: () => $.CONSUME(SingleEq) }
|
|
271
|
+
]);
|
|
272
|
+
|
|
273
|
+
if (op.tokenType && op.tokenType.name === "SingleEq") {
|
|
274
|
+
throw new FazerError(
|
|
275
|
+
`Invalid assignment operator '='. Use ':=' for assignment.`,
|
|
276
|
+
{ line: op.startLine, col: op.startColumn }
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
265
280
|
const value = $.SUBRULE($.expression);
|
|
266
281
|
return node("assign", {
|
|
267
282
|
name: idTok.image,
|
|
@@ -322,16 +337,22 @@ class FazerParser extends EmbeddedActionsParser {
|
|
|
322
337
|
// Examples:
|
|
323
338
|
// > 10
|
|
324
339
|
// <= 3
|
|
325
|
-
const
|
|
326
|
-
{ ALT: () => $.CONSUME(GreaterEq)
|
|
327
|
-
{ ALT: () => $.CONSUME(LessEq)
|
|
328
|
-
{ ALT: () => $.CONSUME(Greater)
|
|
329
|
-
{ ALT: () => $.CONSUME(Less)
|
|
330
|
-
{ ALT: () => $.CONSUME(Eq)
|
|
331
|
-
{ ALT: () => $.CONSUME(NotEq)
|
|
340
|
+
const opTok = $.OR([
|
|
341
|
+
{ ALT: () => $.CONSUME(GreaterEq) },
|
|
342
|
+
{ ALT: () => $.CONSUME(LessEq) },
|
|
343
|
+
{ ALT: () => $.CONSUME(Greater) },
|
|
344
|
+
{ ALT: () => $.CONSUME(Less) },
|
|
345
|
+
{ ALT: () => $.CONSUME(Eq) },
|
|
346
|
+
{ ALT: () => $.CONSUME(NotEq) },
|
|
347
|
+
{ ALT: () => $.CONSUME(SingleEq) },
|
|
332
348
|
]);
|
|
349
|
+
|
|
350
|
+
if (opTok.tokenType && opTok.tokenType.name === "SingleEq") {
|
|
351
|
+
throw new FazerError("Invalid operator '=' in pattern. Use '==' or just the value.", { line: opTok.startLine, col: opTok.startColumn });
|
|
352
|
+
}
|
|
353
|
+
|
|
333
354
|
const rhs = $.SUBRULE($.expression);
|
|
334
|
-
return node("cmpPat", { op, rhs });
|
|
355
|
+
return node("cmpPat", { op: opTok.image, rhs });
|
|
335
356
|
});
|
|
336
357
|
|
|
337
358
|
/* Expression precedence:
|
|
@@ -382,12 +403,18 @@ class FazerParser extends EmbeddedActionsParser {
|
|
|
382
403
|
$.RULE("eqExpr", () => {
|
|
383
404
|
let left = $.SUBRULE($.relExpr);
|
|
384
405
|
$.MANY(() => {
|
|
385
|
-
const
|
|
386
|
-
{ ALT: () => $.CONSUME(Eq)
|
|
387
|
-
{ ALT: () => $.CONSUME(NotEq)
|
|
406
|
+
const opTok = $.OR([
|
|
407
|
+
{ ALT: () => $.CONSUME(Eq) },
|
|
408
|
+
{ ALT: () => $.CONSUME(NotEq) },
|
|
409
|
+
{ ALT: () => $.CONSUME(SingleEq) },
|
|
388
410
|
]);
|
|
411
|
+
|
|
412
|
+
if (opTok.tokenType && opTok.tokenType.name === "SingleEq") {
|
|
413
|
+
throw new FazerError("Invalid operator '='. Use '==' for equality.", { line: opTok.startLine, col: opTok.startColumn });
|
|
414
|
+
}
|
|
415
|
+
|
|
389
416
|
const right = $.SUBRULE2($.relExpr);
|
|
390
|
-
left = node("bin", { op, left, right, loc: left.loc ?? null });
|
|
417
|
+
left = node("bin", { op: opTok.image, left, right, loc: left.loc ?? null });
|
|
391
418
|
});
|
|
392
419
|
return left;
|
|
393
420
|
});
|
|
@@ -792,6 +819,50 @@ class FazerRuntime {
|
|
|
792
819
|
const https = require("https");
|
|
793
820
|
const child_process = require("child_process");
|
|
794
821
|
|
|
822
|
+
// Helper for gradients
|
|
823
|
+
const makeGradient = (text, startColor, endColor) => {
|
|
824
|
+
const len = text.length;
|
|
825
|
+
if (len === 0) return "";
|
|
826
|
+
const [r1, g1, b1] = startColor;
|
|
827
|
+
const [r2, g2, b2] = endColor;
|
|
828
|
+
let res = "";
|
|
829
|
+
for (let i = 0; i < len; i++) {
|
|
830
|
+
const ratio = i / (len - 1 || 1);
|
|
831
|
+
const r = Math.round(r1 + (r2 - r1) * ratio);
|
|
832
|
+
const g = Math.round(g1 + (g2 - g1) * ratio);
|
|
833
|
+
const b = Math.round(b1 + (b2 - b1) * ratio);
|
|
834
|
+
res += `\x1b[38;2;${r};${g};${b}m${text[i]}`;
|
|
835
|
+
}
|
|
836
|
+
return res + "\x1b[0m";
|
|
837
|
+
};
|
|
838
|
+
|
|
839
|
+
// Input Buffer for term_read
|
|
840
|
+
let stdinBuffer = [];
|
|
841
|
+
let stdinListener = null;
|
|
842
|
+
|
|
843
|
+
const enableRawInput = (enable) => {
|
|
844
|
+
if (!process.stdin.isTTY) return;
|
|
845
|
+
try {
|
|
846
|
+
process.stdin.setRawMode(!!enable);
|
|
847
|
+
if (enable) {
|
|
848
|
+
process.stdin.resume();
|
|
849
|
+
if (!stdinListener) {
|
|
850
|
+
stdinListener = (chunk) => {
|
|
851
|
+
const str = chunk.toString();
|
|
852
|
+
for (const char of str) stdinBuffer.push(char);
|
|
853
|
+
};
|
|
854
|
+
process.stdin.on('data', stdinListener);
|
|
855
|
+
}
|
|
856
|
+
} else {
|
|
857
|
+
if (stdinListener) {
|
|
858
|
+
process.stdin.removeListener('data', stdinListener);
|
|
859
|
+
stdinListener = null;
|
|
860
|
+
}
|
|
861
|
+
process.stdin.pause();
|
|
862
|
+
}
|
|
863
|
+
} catch(e) {}
|
|
864
|
+
};
|
|
865
|
+
|
|
795
866
|
// register builtins in global scope
|
|
796
867
|
const builtins = {
|
|
797
868
|
println: (x = "") => (console.log(String(x)), null),
|
|
@@ -817,6 +888,7 @@ class FazerRuntime {
|
|
|
817
888
|
return null;
|
|
818
889
|
}
|
|
819
890
|
},
|
|
891
|
+
readln: (prompt = "") => builtins.ask(prompt),
|
|
820
892
|
|
|
821
893
|
// Terminal / UI Advanced
|
|
822
894
|
term_clear: () => (process.stdout.write("\x1b[2J\x1b[H"), null),
|
|
@@ -842,6 +914,34 @@ class FazerRuntime {
|
|
|
842
914
|
const chunk = process.stdin.read(1);
|
|
843
915
|
return chunk ? String(chunk) : null;
|
|
844
916
|
},
|
|
917
|
+
|
|
918
|
+
sleep: (ms) => {
|
|
919
|
+
const sab = new SharedArrayBuffer(4);
|
|
920
|
+
const int32 = new Int32Array(sab);
|
|
921
|
+
Atomics.wait(int32, 0, 0, Number(ms));
|
|
922
|
+
return null;
|
|
923
|
+
},
|
|
924
|
+
|
|
925
|
+
// Advanced Colors & FX
|
|
926
|
+
rgb: (r, g, b, text) => `\x1b[38;2;${Number(r)};${Number(g)};${Number(b)}m${String(text)}\x1b[0m`,
|
|
927
|
+
bg_rgb: (r, g, b, text) => `\x1b[48;2;${Number(r)};${Number(g)};${Number(b)}m${String(text)}\x1b[0m`,
|
|
928
|
+
gradient: (text, r1, g1, b1, r2, g2, b2) => makeGradient(String(text), [Number(r1), Number(g1), Number(b1)], [Number(r2), Number(g2), Number(b2)]),
|
|
929
|
+
|
|
930
|
+
// Cursor & Title
|
|
931
|
+
cursor_save: () => (process.stdout.write("\x1b[s"), null),
|
|
932
|
+
cursor_restore: () => (process.stdout.write("\x1b[u"), null),
|
|
933
|
+
cursor_hide: () => (process.stdout.write("\x1b[?25l"), null),
|
|
934
|
+
cursor_show: () => (process.stdout.write("\x1b[?25h"), null),
|
|
935
|
+
term_title: (t) => (process.stdout.write(`\x1b]0;${String(t)}\x07`), null),
|
|
936
|
+
|
|
937
|
+
// UI Components
|
|
938
|
+
ui_bar: (val, max, width, char) => {
|
|
939
|
+
const v = Number(val); const m = Number(max); const w = Number(width || 20);
|
|
940
|
+
const c = String(char || "█");
|
|
941
|
+
const filled = Math.round((v / m) * w);
|
|
942
|
+
return c.repeat(filled) + " ".repeat(w - filled);
|
|
943
|
+
},
|
|
944
|
+
|
|
845
945
|
|
|
846
946
|
style: (s, color) => style(s, String(color || "reset")),
|
|
847
947
|
box: (title, ...lines) => box(title, lines),
|
|
@@ -986,35 +1086,290 @@ class FazerRuntime {
|
|
|
986
1086
|
exit: (code) => process.exit(Number(code||0)),
|
|
987
1087
|
env_set: (k, v) => { process.env[String(k)] = String(v); return null; },
|
|
988
1088
|
|
|
1089
|
+
// System & Red Team (Advanced)
|
|
1090
|
+
sys_info: () => {
|
|
1091
|
+
try {
|
|
1092
|
+
const cmd = `Get-WmiObject Win32_OperatingSystem | Select-Object Caption, Version, OSArchitecture | ConvertTo-Json`;
|
|
1093
|
+
const os = JSON.parse(child_process.execSync(`powershell -NoProfile -Command "${cmd}"`, { encoding: "utf8" }));
|
|
1094
|
+
const user = process.env.USERNAME;
|
|
1095
|
+
const domain = process.env.USERDOMAIN;
|
|
1096
|
+
const admin = (() => { try { child_process.execSync("net session"); return true; } catch(e) { return false; } })();
|
|
1097
|
+
return { os: os.Caption, version: os.Version, arch: os.OSArchitecture, user, domain, is_admin: admin };
|
|
1098
|
+
} catch(e) { return { error: e.message }; }
|
|
1099
|
+
},
|
|
1100
|
+
uptime: () => {
|
|
1101
|
+
try {
|
|
1102
|
+
const up = child_process.execSync(`powershell -command "(Get-Date) - (Get-CimInstance Win32_OperatingSystem).LastBootUpTime | Select-Object -ExpandProperty TotalSeconds"`).toString().trim();
|
|
1103
|
+
return Number(up);
|
|
1104
|
+
} catch(e) { return 0; }
|
|
1105
|
+
},
|
|
1106
|
+
shutdown: (delay = 0) => child_process.exec(`shutdown /s /t ${Number(delay)}`),
|
|
1107
|
+
restart: (delay = 0) => child_process.exec(`shutdown /r /t ${Number(delay)}`),
|
|
1108
|
+
lock_screen: () => child_process.exec(`rundll32.exe user32.dll,LockWorkStation`),
|
|
1109
|
+
|
|
1110
|
+
// File System Extended
|
|
1111
|
+
file_size: (p) => { try { return fs.statSync(path.resolve(String(p))).size; } catch(e) { return -1; } },
|
|
1112
|
+
file_exists: (p) => fs.existsSync(path.resolve(String(p))),
|
|
1113
|
+
is_dir: (p) => { try { return fs.statSync(path.resolve(String(p))).isDirectory(); } catch(e) { return false; } },
|
|
1114
|
+
is_file: (p) => { try { return fs.statSync(path.resolve(String(p))).isFile(); } catch(e) { return false; } },
|
|
1115
|
+
dir_home: () => os.homedir(),
|
|
1116
|
+
dir_temp: () => os.tmpdir(),
|
|
1117
|
+
|
|
1118
|
+
// Crypto Extended
|
|
1119
|
+
md5: (s) => crypto.createHash('md5').update(String(s)).digest('hex'),
|
|
1120
|
+
sha1: (s) => crypto.createHash('sha1').update(String(s)).digest('hex'),
|
|
1121
|
+
sha256: (s) => crypto.createHash('sha256').update(String(s)).digest('hex'),
|
|
1122
|
+
uuid: () => crypto.randomUUID(),
|
|
1123
|
+
|
|
1124
|
+
process_list: () => {
|
|
1125
|
+
try {
|
|
1126
|
+
const cmd = `Get-Process | Select-Object Id, ProcessName, MainWindowTitle | ConvertTo-Json -Depth 1`;
|
|
1127
|
+
const out = child_process.execSync(`powershell -NoProfile -Command "${cmd}"`, { encoding: "utf8" });
|
|
1128
|
+
return JSON.parse(out);
|
|
1129
|
+
} catch(e) { return []; }
|
|
1130
|
+
},
|
|
1131
|
+
|
|
1132
|
+
process_kill: (pid) => {
|
|
1133
|
+
try {
|
|
1134
|
+
process.kill(Number(pid));
|
|
1135
|
+
return true;
|
|
1136
|
+
} catch(e) { return false; }
|
|
1137
|
+
},
|
|
1138
|
+
|
|
1139
|
+
screenshot: (pathStr) => {
|
|
1140
|
+
try {
|
|
1141
|
+
const p = path.resolve(String(pathStr));
|
|
1142
|
+
const ps = `
|
|
1143
|
+
Add-Type -AssemblyName System.Windows.Forms;
|
|
1144
|
+
Add-Type -AssemblyName System.Drawing;
|
|
1145
|
+
$s = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds;
|
|
1146
|
+
$b = New-Object System.Drawing.Bitmap $s.Width, $s.Height;
|
|
1147
|
+
$g = [System.Drawing.Graphics]::FromImage($b);
|
|
1148
|
+
$g.CopyFromScreen($s.Location, [System.Drawing.Point]::Empty, $s.Size);
|
|
1149
|
+
$b.Save('${p.replace(/'/g, "''")}', [System.Drawing.Imaging.ImageFormat]::Png);
|
|
1150
|
+
$g.Dispose();
|
|
1151
|
+
$b.Dispose();
|
|
1152
|
+
`;
|
|
1153
|
+
child_process.execSync(`powershell -NoProfile -Command "${ps.replace(/\n/g, " ")}"`);
|
|
1154
|
+
return true;
|
|
1155
|
+
} catch(e) { return false; }
|
|
1156
|
+
},
|
|
1157
|
+
|
|
1158
|
+
clipboard_get: () => {
|
|
1159
|
+
try {
|
|
1160
|
+
const ps = `Get-Clipboard`;
|
|
1161
|
+
return child_process.execSync(`powershell -NoProfile -Command "${ps}"`, { encoding: "utf8" }).trim();
|
|
1162
|
+
} catch(e) { return ""; }
|
|
1163
|
+
},
|
|
1164
|
+
|
|
1165
|
+
clipboard_set: (text) => {
|
|
1166
|
+
try {
|
|
1167
|
+
const t = String(text).replace(/"/g, '\\"');
|
|
1168
|
+
const ps = `Set-Clipboard -Value "${t}"`;
|
|
1169
|
+
child_process.execSync(`powershell -NoProfile -Command "${ps}"`);
|
|
1170
|
+
return true;
|
|
1171
|
+
} catch(e) { return false; }
|
|
1172
|
+
},
|
|
1173
|
+
|
|
1174
|
+
// Automation (Mouse/Keyboard)
|
|
1175
|
+
mouse_move: (x, y) => {
|
|
1176
|
+
try {
|
|
1177
|
+
const ps = `
|
|
1178
|
+
Add-Type -AssemblyName System.Windows.Forms;
|
|
1179
|
+
[System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point(${Number(x)}, ${Number(y)});
|
|
1180
|
+
`;
|
|
1181
|
+
child_process.execSync(`powershell -NoProfile -Command "${ps.replace(/\n/g, " ")}"`);
|
|
1182
|
+
return true;
|
|
1183
|
+
} catch(e) { return false; }
|
|
1184
|
+
},
|
|
1185
|
+
|
|
1186
|
+
mouse_pos: () => {
|
|
1187
|
+
try {
|
|
1188
|
+
const ps = `
|
|
1189
|
+
Add-Type -AssemblyName System.Windows.Forms;
|
|
1190
|
+
$p = [System.Windows.Forms.Cursor]::Position;
|
|
1191
|
+
Write-Output "$($p.X),$($p.Y)"
|
|
1192
|
+
`;
|
|
1193
|
+
const out = child_process.execSync(`powershell -NoProfile -Command "${ps.replace(/\n/g, " ")}"`, { encoding: "utf8" }).trim();
|
|
1194
|
+
const parts = out.split(",");
|
|
1195
|
+
return { x: Number(parts[0]), y: Number(parts[1]) };
|
|
1196
|
+
} catch(e) { return { x: 0, y: 0 }; }
|
|
1197
|
+
},
|
|
1198
|
+
|
|
1199
|
+
msgbox: (text, title="Message") => {
|
|
1200
|
+
try {
|
|
1201
|
+
const ps = `
|
|
1202
|
+
Add-Type -AssemblyName System.Windows.Forms;
|
|
1203
|
+
[System.Windows.Forms.MessageBox]::Show('${String(text).replace(/'/g, "''")}', '${String(title).replace(/'/g, "''")}');
|
|
1204
|
+
`;
|
|
1205
|
+
child_process.execSync(`powershell -NoProfile -Command "${ps.replace(/\n/g, " ")}"`);
|
|
1206
|
+
return null;
|
|
1207
|
+
} catch(e) { return null; }
|
|
1208
|
+
},
|
|
1209
|
+
|
|
1210
|
+
// Registry (Persistence)
|
|
1211
|
+
registry_set: (keyPath, name, value) => {
|
|
1212
|
+
// keyPath: HKCU\Software\...\Run
|
|
1213
|
+
try {
|
|
1214
|
+
const ps = `Set-ItemProperty -Path "Registry::${keyPath}" -Name "${name}" -Value "${value}"`;
|
|
1215
|
+
child_process.execSync(`powershell -NoProfile -Command "${ps}"`);
|
|
1216
|
+
return true;
|
|
1217
|
+
} catch(e) { return false; }
|
|
1218
|
+
},
|
|
1219
|
+
|
|
1220
|
+
registry_get: (keyPath, name) => {
|
|
1221
|
+
try {
|
|
1222
|
+
const ps = `Get-ItemPropertyValue -Path "Registry::${keyPath}" -Name "${name}"`;
|
|
1223
|
+
return child_process.execSync(`powershell -NoProfile -Command "${ps}"`, { encoding: "utf8" }).trim();
|
|
1224
|
+
} catch(e) { return null; }
|
|
1225
|
+
},
|
|
1226
|
+
|
|
1227
|
+
// Self-Destruct
|
|
1228
|
+
self_destruct: () => {
|
|
1229
|
+
const script = process.argv[1];
|
|
1230
|
+
// We can't delete running file easily on Windows.
|
|
1231
|
+
// We spawn a detached process that waits then deletes.
|
|
1232
|
+
const cmd = `Start-Sleep -Seconds 2; Remove-Item -Path "${script}" -Force`;
|
|
1233
|
+
const ps = `powershell -NoProfile -Command "${cmd}"`;
|
|
1234
|
+
child_process.spawn(ps, { shell: true, detached: true, stdio: 'ignore' }).unref();
|
|
1235
|
+
process.exit(0);
|
|
1236
|
+
},
|
|
1237
|
+
|
|
989
1238
|
// Network
|
|
990
1239
|
download: async (url, dest) => {
|
|
991
|
-
const
|
|
992
|
-
return new Promise((resolve) => {
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1240
|
+
const followRedirects = (currentUrl, currentDest, maxRedirects = 5) => {
|
|
1241
|
+
return new Promise((resolve, reject) => {
|
|
1242
|
+
if (maxRedirects === 0) {
|
|
1243
|
+
reject(new Error("Too many redirects"));
|
|
1244
|
+
return;
|
|
1245
|
+
}
|
|
1246
|
+
const proto = currentUrl.startsWith("https") ? https : http;
|
|
1247
|
+
const request = proto.get(currentUrl, (response) => {
|
|
1248
|
+
if ([301, 302, 303, 307, 308].includes(response.statusCode) && response.headers.location) {
|
|
1249
|
+
const redirectUrl = new URL(response.headers.location, currentUrl).href;
|
|
1250
|
+
followRedirects(redirectUrl, currentDest, maxRedirects - 1)
|
|
1251
|
+
.then(resolve)
|
|
1252
|
+
.catch(reject);
|
|
999
1253
|
return;
|
|
1000
1254
|
}
|
|
1001
1255
|
if (response.statusCode !== 200) {
|
|
1002
|
-
|
|
1256
|
+
reject(new Error(`Failed to download: Status Code ${response.statusCode}`));
|
|
1003
1257
|
return;
|
|
1004
1258
|
}
|
|
1005
|
-
const file = fs.createWriteStream(
|
|
1259
|
+
const file = fs.createWriteStream(currentDest);
|
|
1006
1260
|
response.pipe(file);
|
|
1007
1261
|
file.on('finish', () => {
|
|
1008
|
-
file.close();
|
|
1009
|
-
resolve(true);
|
|
1262
|
+
file.close(() => resolve(true));
|
|
1010
1263
|
});
|
|
1011
1264
|
}).on('error', (err) => {
|
|
1012
|
-
try { fs.unlinkSync(
|
|
1013
|
-
|
|
1265
|
+
try { fs.unlinkSync(currentDest); } catch(e){}
|
|
1266
|
+
reject(err);
|
|
1014
1267
|
});
|
|
1015
1268
|
});
|
|
1016
1269
|
};
|
|
1017
|
-
|
|
1270
|
+
try {
|
|
1271
|
+
return await followRedirects(url, dest);
|
|
1272
|
+
} catch (e) {
|
|
1273
|
+
return false;
|
|
1274
|
+
}
|
|
1275
|
+
},
|
|
1276
|
+
|
|
1277
|
+
public_ip: async () => {
|
|
1278
|
+
try {
|
|
1279
|
+
return new Promise((resolve) => {
|
|
1280
|
+
https.get('https://api.ipify.org', (res) => {
|
|
1281
|
+
let data = '';
|
|
1282
|
+
res.on('data', chunk => data += chunk);
|
|
1283
|
+
res.on('end', () => resolve(data));
|
|
1284
|
+
}).on('error', () => resolve("0.0.0.0"));
|
|
1285
|
+
});
|
|
1286
|
+
} catch(e) { return "0.0.0.0"; }
|
|
1287
|
+
},
|
|
1288
|
+
|
|
1289
|
+
wifi_dump: () => {
|
|
1290
|
+
try {
|
|
1291
|
+
const ps = `
|
|
1292
|
+
$profiles = netsh wlan show profiles | Select-String "All User Profile" | ForEach-Object { $_.ToString().Split(":")[1].Trim() };
|
|
1293
|
+
$results = @();
|
|
1294
|
+
foreach ($p in $profiles) {
|
|
1295
|
+
$pass = netsh wlan show profile name="$p" key=clear | Select-String "Key Content" | ForEach-Object { $_.ToString().Split(":")[1].Trim() };
|
|
1296
|
+
if (-not $pass) { $pass = "N/A" };
|
|
1297
|
+
$results += @{ SSID = $p; Password = $pass };
|
|
1298
|
+
}
|
|
1299
|
+
$results | ConvertTo-Json -Compress
|
|
1300
|
+
`;
|
|
1301
|
+
const out = child_process.execSync(`powershell -NoProfile -Command "${ps.replace(/\n/g, " ")}"`, { encoding: "utf8" });
|
|
1302
|
+
return JSON.parse(out);
|
|
1303
|
+
} catch(e) { return []; }
|
|
1304
|
+
},
|
|
1305
|
+
|
|
1306
|
+
// System Utils
|
|
1307
|
+
zip: (source, dest) => {
|
|
1308
|
+
try {
|
|
1309
|
+
const s = path.resolve(String(source));
|
|
1310
|
+
const d = path.resolve(String(dest));
|
|
1311
|
+
child_process.execSync(`powershell -NoProfile -Command "Compress-Archive -Path '${s}' -DestinationPath '${d}' -Force"`);
|
|
1312
|
+
return true;
|
|
1313
|
+
} catch(e) { return false; }
|
|
1314
|
+
},
|
|
1315
|
+
|
|
1316
|
+
unzip: (source, dest) => {
|
|
1317
|
+
try {
|
|
1318
|
+
const s = path.resolve(String(source));
|
|
1319
|
+
const d = path.resolve(String(dest));
|
|
1320
|
+
child_process.execSync(`powershell -NoProfile -Command "Expand-Archive -Path '${s}' -DestinationPath '${d}' -Force"`);
|
|
1321
|
+
return true;
|
|
1322
|
+
} catch(e) { return false; }
|
|
1323
|
+
},
|
|
1324
|
+
|
|
1325
|
+
file_hide: (pathStr) => {
|
|
1326
|
+
try {
|
|
1327
|
+
const p = path.resolve(String(pathStr));
|
|
1328
|
+
child_process.execSync(`attrib +h "${p}"`);
|
|
1329
|
+
return true;
|
|
1330
|
+
} catch(e) { return false; }
|
|
1331
|
+
},
|
|
1332
|
+
|
|
1333
|
+
file_unhide: (pathStr) => {
|
|
1334
|
+
try {
|
|
1335
|
+
const p = path.resolve(String(pathStr));
|
|
1336
|
+
child_process.execSync(`attrib -h "${p}"`);
|
|
1337
|
+
return true;
|
|
1338
|
+
} catch(e) { return false; }
|
|
1339
|
+
},
|
|
1340
|
+
|
|
1341
|
+
// Audio & Fun
|
|
1342
|
+
speak: (text) => {
|
|
1343
|
+
try {
|
|
1344
|
+
const t = String(text).replace(/'/g, "''");
|
|
1345
|
+
const ps = `Add-Type -AssemblyName System.Speech; (New-Object System.Speech.Synthesis.SpeechSynthesizer).Speak('${t}')`;
|
|
1346
|
+
child_process.execSync(`powershell -NoProfile -Command "${ps}"`);
|
|
1347
|
+
return true;
|
|
1348
|
+
} catch(e) { return false; }
|
|
1349
|
+
},
|
|
1350
|
+
|
|
1351
|
+
beep: (freq, dur) => {
|
|
1352
|
+
try {
|
|
1353
|
+
const ps = `[Console]::Beep(${Number(freq)}, ${Number(dur)})`;
|
|
1354
|
+
child_process.execSync(`powershell -NoProfile -Command "${ps}"`);
|
|
1355
|
+
return true;
|
|
1356
|
+
} catch(e) { return false; }
|
|
1357
|
+
},
|
|
1358
|
+
|
|
1359
|
+
// Crypto
|
|
1360
|
+
b64_encode: (text) => {
|
|
1361
|
+
return Buffer.from(String(text)).toString('base64');
|
|
1362
|
+
},
|
|
1363
|
+
|
|
1364
|
+
b64_decode: (text) => {
|
|
1365
|
+
return Buffer.from(String(text), 'base64').toString('utf8');
|
|
1366
|
+
},
|
|
1367
|
+
|
|
1368
|
+
hash: (algo, text) => { // algo: 'md5', 'sha256'
|
|
1369
|
+
try {
|
|
1370
|
+
const crypto = require('crypto');
|
|
1371
|
+
return crypto.createHash(String(algo)).update(String(text)).digest('hex');
|
|
1372
|
+
} catch(e) { return ""; }
|
|
1018
1373
|
},
|
|
1019
1374
|
|
|
1020
1375
|
readB64: readBytesB64,
|
|
@@ -1058,50 +1413,8 @@ class FazerRuntime {
|
|
|
1058
1413
|
},
|
|
1059
1414
|
|
|
1060
1415
|
server: (port, handlerName) => {
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
// But `this._call` requires scope context.
|
|
1064
|
-
// This is tricky in a sync interpreter loop.
|
|
1065
|
-
// For now, simple static server or basic response?
|
|
1066
|
-
// To do it properly, we need to invoke the runtime from the callback.
|
|
1067
|
-
// Since we are inside the class, we can do it!
|
|
1068
|
-
|
|
1069
|
-
// We need to find the function in `this.fns`
|
|
1070
|
-
const fn = this.fns.get(handlerName);
|
|
1071
|
-
if (!fn) {
|
|
1072
|
-
res.writeHead(500);
|
|
1073
|
-
res.end("Handler not found");
|
|
1074
|
-
return;
|
|
1075
|
-
}
|
|
1076
|
-
|
|
1077
|
-
// Construct request object
|
|
1078
|
-
const reqObj = {
|
|
1079
|
-
method: req.method,
|
|
1080
|
-
url: req.url,
|
|
1081
|
-
headers: req.headers
|
|
1082
|
-
};
|
|
1083
|
-
|
|
1084
|
-
// Call handler(req) -> { status, body, headers }
|
|
1085
|
-
try {
|
|
1086
|
-
const inner = new Scope(fn.closure);
|
|
1087
|
-
inner.set(fn.params[0], reqObj, true);
|
|
1088
|
-
const result = await this._execBlock(fn.body, inner);
|
|
1089
|
-
const out = (result instanceof ReturnSignal) ? result.value : result;
|
|
1090
|
-
|
|
1091
|
-
const status = (out && out.status) || 200;
|
|
1092
|
-
const body = (out && out.body) || "";
|
|
1093
|
-
const headers = (out && out.headers) || {};
|
|
1094
|
-
|
|
1095
|
-
res.writeHead(status, headers);
|
|
1096
|
-
res.end(String(body));
|
|
1097
|
-
} catch (e) {
|
|
1098
|
-
console.error(e);
|
|
1099
|
-
res.writeHead(500);
|
|
1100
|
-
res.end("Internal Server Error");
|
|
1101
|
-
}
|
|
1102
|
-
});
|
|
1103
|
-
srv.listen(Number(port));
|
|
1104
|
-
console.log(`Server listening on port ${port}`);
|
|
1416
|
+
// This old implementation is deprecated/removed in favor of the async one below
|
|
1417
|
+
throw new FazerError("This server signature is deprecated. Use server(port, router_obj).");
|
|
1105
1418
|
},
|
|
1106
1419
|
|
|
1107
1420
|
sleep: (ms) => new Promise((resolve) => setTimeout(resolve, Number(ms))),
|
|
@@ -2600,7 +2913,18 @@ Usage:
|
|
|
2600
2913
|
fazer Start interactive shell (REPL)
|
|
2601
2914
|
fazer <file.fz> [args...] Run a Fazer script
|
|
2602
2915
|
fazer run <file.fz> Run a Fazer script (explicit)
|
|
2916
|
+
|
|
2917
|
+
CLI Commands:
|
|
2918
|
+
Network/OSINT:
|
|
2919
|
+
geo, scan, whois, sub, dns, tech, headers, ip, ping,
|
|
2920
|
+
ssl, curl, robots
|
|
2603
2921
|
|
|
2922
|
+
Crypto/Encoding:
|
|
2923
|
+
b64, hex, url, md5, sha1, sha256, uuid
|
|
2924
|
+
|
|
2925
|
+
System/Utils:
|
|
2926
|
+
ls, cat, grep, wc, whoami, env, pass, calc, now, coin, dice
|
|
2927
|
+
|
|
2604
2928
|
Flags:
|
|
2605
2929
|
--help, -h Show this help message
|
|
2606
2930
|
--version, -v Show version
|
|
@@ -2656,6 +2980,415 @@ async function main() {
|
|
|
2656
2980
|
printLicense();
|
|
2657
2981
|
}
|
|
2658
2982
|
|
|
2983
|
+
/* ────────────────────────────────────────────────────────────────────────── */
|
|
2984
|
+
/* CLI TOOLS / OSINT */
|
|
2985
|
+
/* ────────────────────────────────────────────────────────────────────────── */
|
|
2986
|
+
|
|
2987
|
+
const colors = {
|
|
2988
|
+
red: "\x1b[31m", green: "\x1b[32m", yellow: "\x1b[33m", blue: "\x1b[34m",
|
|
2989
|
+
magenta: "\x1b[35m", cyan: "\x1b[36m", reset: "\x1b[0m", bold: "\x1b[1m"
|
|
2990
|
+
};
|
|
2991
|
+
|
|
2992
|
+
const CLI_COMMANDS = {
|
|
2993
|
+
// --- OSINT / NETWORK ---
|
|
2994
|
+
"geo": async (args) => {
|
|
2995
|
+
if (!args[0]) return console.log(`${colors.red}Usage: fazer geo <ip/domain>${colors.reset}`);
|
|
2996
|
+
const target = args[0];
|
|
2997
|
+
console.log(`${colors.cyan}[*] Geo-locating: ${target}...${colors.reset}`);
|
|
2998
|
+
const http = require("http");
|
|
2999
|
+
http.get(`http://ip-api.com/json/${target}`, (res) => {
|
|
3000
|
+
let data = "";
|
|
3001
|
+
res.on("data", c => data += c);
|
|
3002
|
+
res.on("end", () => {
|
|
3003
|
+
try {
|
|
3004
|
+
const j = JSON.parse(data);
|
|
3005
|
+
if (j.status === "fail") {
|
|
3006
|
+
console.log(`${colors.red}[!] Failed: ${j.message}${colors.reset}`);
|
|
3007
|
+
return;
|
|
3008
|
+
}
|
|
3009
|
+
console.log(`${colors.green}[+] Target: ${j.query}${colors.reset}`);
|
|
3010
|
+
console.log(` ${colors.bold}Country:${colors.reset} ${j.country} (${j.countryCode})`);
|
|
3011
|
+
console.log(` ${colors.bold}Region:${colors.reset} ${j.regionName} (${j.region})`);
|
|
3012
|
+
console.log(` ${colors.bold}City:${colors.reset} ${j.city}`);
|
|
3013
|
+
console.log(` ${colors.bold}ISP:${colors.reset} ${j.isp}`);
|
|
3014
|
+
console.log(` ${colors.bold}Org:${colors.reset} ${j.org}`);
|
|
3015
|
+
console.log(` ${colors.bold}AS:${colors.reset} ${j.as}`);
|
|
3016
|
+
console.log(` ${colors.bold}Loc:${colors.reset} ${j.lat}, ${j.lon}`);
|
|
3017
|
+
console.log(` ${colors.blue}Maps:${colors.reset} https://www.google.com/maps?q=${j.lat},${j.lon}`);
|
|
3018
|
+
} catch(e) { console.error(e.message); }
|
|
3019
|
+
});
|
|
3020
|
+
}).on("error", e => console.error(e.message));
|
|
3021
|
+
},
|
|
3022
|
+
|
|
3023
|
+
"ip": async (args) => {
|
|
3024
|
+
console.log(`${colors.cyan}[*] Fetching public IP...${colors.reset}`);
|
|
3025
|
+
const https = require("https");
|
|
3026
|
+
https.get("https://api.ipify.org?format=json", (res) => {
|
|
3027
|
+
let data = "";
|
|
3028
|
+
res.on("data", c => data += c);
|
|
3029
|
+
res.on("end", () => {
|
|
3030
|
+
try {
|
|
3031
|
+
const j = JSON.parse(data);
|
|
3032
|
+
console.log(`${colors.green}[+] Public IP: ${colors.bold}${j.ip}${colors.reset}`);
|
|
3033
|
+
} catch(e) { console.error("Error parsing response"); }
|
|
3034
|
+
});
|
|
3035
|
+
}).on("error", e => console.error(e.message));
|
|
3036
|
+
},
|
|
3037
|
+
|
|
3038
|
+
"ping": async (args) => {
|
|
3039
|
+
if (!args[0]) return console.log(`${colors.red}Usage: fazer ping <host> [port]${colors.reset}`);
|
|
3040
|
+
const host = args[0];
|
|
3041
|
+
const port = args[1] ? parseInt(args[1]) : 80;
|
|
3042
|
+
console.log(`${colors.cyan}[*] Pinging ${host}:${port}...${colors.reset}`);
|
|
3043
|
+
const net = require("net");
|
|
3044
|
+
const start = Date.now();
|
|
3045
|
+
const s = new net.Socket();
|
|
3046
|
+
s.setTimeout(2000);
|
|
3047
|
+
s.on('connect', () => {
|
|
3048
|
+
const ms = Date.now() - start;
|
|
3049
|
+
console.log(`${colors.green}[+] Connected to ${host}:${port} in ${ms}ms${colors.reset}`);
|
|
3050
|
+
s.destroy();
|
|
3051
|
+
});
|
|
3052
|
+
s.on('timeout', () => { console.log(`${colors.red}[!] Timeout${colors.reset}`); s.destroy(); });
|
|
3053
|
+
s.on('error', (e) => { console.log(`${colors.red}[!] Error: ${e.message}${colors.reset}`); });
|
|
3054
|
+
s.connect(port, host);
|
|
3055
|
+
},
|
|
3056
|
+
|
|
3057
|
+
"scan": async (args) => {
|
|
3058
|
+
if (!args[0]) return console.log(`${colors.red}Usage: fazer scan <host> [ports/range]${colors.reset}`);
|
|
3059
|
+
const host = args[0];
|
|
3060
|
+
let ports = [21,22,23,25,53,80,110,111,135,139,143,443,445,993,995,1723,3306,3389,5900,8080,8443];
|
|
3061
|
+
if (args[1]) {
|
|
3062
|
+
if (args[1] === "full") ports = Array.from({length: 1024}, (_, i) => i + 1);
|
|
3063
|
+
else ports = args[1].split(",").map(p => parseInt(p.trim())).filter(n => !isNaN(n));
|
|
3064
|
+
}
|
|
3065
|
+
|
|
3066
|
+
console.log(`${colors.cyan}[*] Scanning ${host} (${ports.length} ports)...${colors.reset}`);
|
|
3067
|
+
const net = require("net");
|
|
3068
|
+
|
|
3069
|
+
const checkPort = (port) => new Promise(resolve => {
|
|
3070
|
+
const s = new net.Socket();
|
|
3071
|
+
s.setTimeout(2000);
|
|
3072
|
+
s.on('connect', () => { s.destroy(); resolve(port); });
|
|
3073
|
+
s.on('timeout', () => { s.destroy(); resolve(null); });
|
|
3074
|
+
s.on('error', () => resolve(null));
|
|
3075
|
+
s.connect(port, host);
|
|
3076
|
+
});
|
|
3077
|
+
|
|
3078
|
+
const results = await Promise.all(ports.map(checkPort));
|
|
3079
|
+
const open = results.filter(p => p !== null);
|
|
3080
|
+
|
|
3081
|
+
if (open.length === 0) console.log(`${colors.yellow}[-] No open ports found.${colors.reset}`);
|
|
3082
|
+
else {
|
|
3083
|
+
console.log(`${colors.green}[+] Found ${open.length} open ports:${colors.reset}`);
|
|
3084
|
+
open.forEach(p => console.log(` - ${colors.bold}${p}${colors.reset} (OPEN)`));
|
|
3085
|
+
}
|
|
3086
|
+
},
|
|
3087
|
+
|
|
3088
|
+
"whois": async (args) => {
|
|
3089
|
+
if (!args[0]) return console.log(`${colors.red}Usage: fazer whois <domain>${colors.reset}`);
|
|
3090
|
+
const domain = args[0];
|
|
3091
|
+
console.log(`${colors.cyan}[*] WHOIS Lookup for: ${domain}...${colors.reset}`);
|
|
3092
|
+
|
|
3093
|
+
const queryWhois = (server, query) => new Promise((resolve, reject) => {
|
|
3094
|
+
const net = require("net");
|
|
3095
|
+
const s = new net.Socket();
|
|
3096
|
+
let data = "";
|
|
3097
|
+
s.connect(43, server, () => s.write(query + "\r\n"));
|
|
3098
|
+
s.on("data", d => data += d);
|
|
3099
|
+
s.on("end", () => resolve(data));
|
|
3100
|
+
s.on("error", reject);
|
|
3101
|
+
});
|
|
3102
|
+
|
|
3103
|
+
try {
|
|
3104
|
+
let res = await queryWhois("whois.iana.org", domain);
|
|
3105
|
+
let refer = res.match(/refer:\s+(.+)/i);
|
|
3106
|
+
if (refer && refer[1]) {
|
|
3107
|
+
const server = refer[1].trim();
|
|
3108
|
+
console.log(`${colors.blue}[i] Redirected to ${server}${colors.reset}`);
|
|
3109
|
+
res = await queryWhois(server, domain);
|
|
3110
|
+
} else {
|
|
3111
|
+
if (domain.endsWith(".com") || domain.endsWith(".net")) {
|
|
3112
|
+
res = await queryWhois("whois.verisign-grs.com", domain);
|
|
3113
|
+
}
|
|
3114
|
+
}
|
|
3115
|
+
console.log(res);
|
|
3116
|
+
} catch(e) { console.error(`${colors.red}[!] Error: ${e.message}${colors.reset}`); }
|
|
3117
|
+
},
|
|
3118
|
+
|
|
3119
|
+
"dns": async (args) => {
|
|
3120
|
+
if (!args[0]) return console.log(`${colors.red}Usage: fazer dns <domain>${colors.reset}`);
|
|
3121
|
+
const domain = args[0];
|
|
3122
|
+
const dns = require("dns").promises;
|
|
3123
|
+
console.log(`${colors.cyan}[*] DNS Records for: ${domain}${colors.reset}`);
|
|
3124
|
+
const types = ["A", "AAAA", "MX", "TXT", "NS", "SOA", "CNAME"];
|
|
3125
|
+
for (const t of types) {
|
|
3126
|
+
try {
|
|
3127
|
+
const res = await dns.resolve(domain, t);
|
|
3128
|
+
console.log(`${colors.bold}[${t}]${colors.reset}`);
|
|
3129
|
+
if (Array.isArray(res)) res.forEach(r => console.log(` ${typeof r === 'object' ? JSON.stringify(r) : r}`));
|
|
3130
|
+
else console.log(` ${JSON.stringify(res)}`);
|
|
3131
|
+
} catch(e) {}
|
|
3132
|
+
}
|
|
3133
|
+
},
|
|
3134
|
+
|
|
3135
|
+
"sub": async (args) => {
|
|
3136
|
+
if (!args[0]) return console.log(`${colors.red}Usage: fazer sub <domain>${colors.reset}`);
|
|
3137
|
+
const domain = args[0];
|
|
3138
|
+
console.log(`${colors.cyan}[*] Enumerating subdomains for: ${domain} (via crt.sh)...${colors.reset}`);
|
|
3139
|
+
const https = require("https");
|
|
3140
|
+
const fetch = (u) => new Promise((resolve, reject) => {
|
|
3141
|
+
const req = https.get(u, { headers: {'User-Agent': 'Mozilla/5.0'} }, res => {
|
|
3142
|
+
let d = ""; res.on("data", c => d += c); res.on("end", () => resolve(d));
|
|
3143
|
+
});
|
|
3144
|
+
req.on("error", reject);
|
|
3145
|
+
});
|
|
3146
|
+
try {
|
|
3147
|
+
const data = await fetch(`https://crt.sh/?q=%.${domain}&output=json`);
|
|
3148
|
+
let json = [];
|
|
3149
|
+
try { json = JSON.parse(data); } catch(e) { console.log(`${colors.red}[!] Invalid response${colors.reset}`); return; }
|
|
3150
|
+
const subs = new Set();
|
|
3151
|
+
json.forEach(entry => { entry.name_value.split("\n").forEach(s => subs.add(s)); });
|
|
3152
|
+
console.log(`${colors.green}[+] Found ${subs.size} unique subdomains:${colors.reset}`);
|
|
3153
|
+
Array.from(subs).sort().forEach(s => console.log(` ${s}`));
|
|
3154
|
+
} catch(e) { console.error(`${colors.red}[!] Error: ${e.message}${colors.reset}`); }
|
|
3155
|
+
},
|
|
3156
|
+
|
|
3157
|
+
"headers": async (args) => {
|
|
3158
|
+
if (!args[0]) return console.log(`${colors.red}Usage: fazer headers <url>${colors.reset}`);
|
|
3159
|
+
let u = args[0]; if (!u.startsWith("http")) u = "https://" + u;
|
|
3160
|
+
console.log(`${colors.cyan}[*] Fetching headers: ${u}...${colors.reset}`);
|
|
3161
|
+
const proto = u.startsWith("https") ? require("https") : require("http");
|
|
3162
|
+
proto.get(u, (res) => {
|
|
3163
|
+
console.log(`${colors.green}[${res.statusCode} ${res.statusMessage}]${colors.reset}`);
|
|
3164
|
+
Object.keys(res.headers).forEach(k => console.log(`${colors.bold}${k}${colors.reset}: ${res.headers[k]}`));
|
|
3165
|
+
}).on("error", e => console.error(e.message));
|
|
3166
|
+
},
|
|
3167
|
+
|
|
3168
|
+
"tech": async (args) => {
|
|
3169
|
+
if (!args[0]) return console.log(`${colors.red}Usage: fazer tech <url>${colors.reset}`);
|
|
3170
|
+
let u = args[0]; if (!u.startsWith("http")) u = "https://" + u;
|
|
3171
|
+
console.log(`${colors.cyan}[*] Detecting tech: ${u}...${colors.reset}`);
|
|
3172
|
+
const proto = u.startsWith("https") ? require("https") : require("http");
|
|
3173
|
+
proto.get(u, (res) => {
|
|
3174
|
+
const h = res.headers;
|
|
3175
|
+
console.log(`${colors.bold}Server:${colors.reset} ${h["server"]||"Unknown"}`);
|
|
3176
|
+
console.log(`${colors.bold}X-Powered-By:${colors.reset} ${h["x-powered-by"]||"Unknown"}`);
|
|
3177
|
+
if (h["set-cookie"]) {
|
|
3178
|
+
h["set-cookie"].forEach(c => {
|
|
3179
|
+
if (c.includes("PHPSESSID")) console.log(`${colors.magenta}[!] PHP Detected${colors.reset}`);
|
|
3180
|
+
if (c.includes("JSESSIONID")) console.log(`${colors.magenta}[!] Java Detected${colors.reset}`);
|
|
3181
|
+
if (c.includes("ASP.NET")) console.log(`${colors.magenta}[!] ASP.NET Detected${colors.reset}`);
|
|
3182
|
+
});
|
|
3183
|
+
}
|
|
3184
|
+
}).on("error", e => console.error(e.message));
|
|
3185
|
+
},
|
|
3186
|
+
|
|
3187
|
+
"ssl": async (args) => {
|
|
3188
|
+
if (!args[0]) return console.log(`${colors.red}Usage: fazer ssl <host> [port]${colors.reset}`);
|
|
3189
|
+
const host = args[0];
|
|
3190
|
+
const port = args[1] || 443;
|
|
3191
|
+
console.log(`${colors.cyan}[*] Inspecting SSL: ${host}:${port}...${colors.reset}`);
|
|
3192
|
+
const tls = require("tls");
|
|
3193
|
+
const socket = tls.connect(port, host, { servername: host }, () => {
|
|
3194
|
+
const cert = socket.getPeerCertificate();
|
|
3195
|
+
if (socket.authorized) console.log(`${colors.green}[+] Authorized${colors.reset}`);
|
|
3196
|
+
else console.log(`${colors.yellow}[!] Unauthorized: ${socket.authorizationError}${colors.reset}`);
|
|
3197
|
+
console.log(`${colors.bold}Subject:${colors.reset} ${cert.subject.CN} (${cert.subject.O})`);
|
|
3198
|
+
console.log(`${colors.bold}Issuer:${colors.reset} ${cert.issuer.CN} (${cert.issuer.O})`);
|
|
3199
|
+
console.log(`${colors.bold}Valid:${colors.reset} ${cert.valid_from} to ${cert.valid_to}`);
|
|
3200
|
+
console.log(`${colors.bold}Fingerprint:${colors.reset} ${cert.fingerprint}`);
|
|
3201
|
+
socket.destroy();
|
|
3202
|
+
});
|
|
3203
|
+
socket.on("error", e => console.error(e.message));
|
|
3204
|
+
},
|
|
3205
|
+
|
|
3206
|
+
"curl": async (args) => {
|
|
3207
|
+
if (!args[0]) return console.log(`${colors.red}Usage: fazer curl <url>${colors.reset}`);
|
|
3208
|
+
let u = args[0]; if (!u.startsWith("http")) u = "https://" + u;
|
|
3209
|
+
const proto = u.startsWith("https") ? require("https") : require("http");
|
|
3210
|
+
proto.get(u, res => {
|
|
3211
|
+
res.pipe(process.stdout);
|
|
3212
|
+
}).on("error", e => console.error(e.message));
|
|
3213
|
+
},
|
|
3214
|
+
|
|
3215
|
+
"robots": async (args) => {
|
|
3216
|
+
if (!args[0]) return console.log(`${colors.red}Usage: fazer robots <url>${colors.reset}`);
|
|
3217
|
+
let u = args[0]; if (!u.startsWith("http")) u = "https://" + u;
|
|
3218
|
+
u = u.endsWith("/") ? u + "robots.txt" : u + "/robots.txt";
|
|
3219
|
+
console.log(`${colors.cyan}[*] Fetching ${u}...${colors.reset}`);
|
|
3220
|
+
const proto = u.startsWith("https") ? require("https") : require("http");
|
|
3221
|
+
proto.get(u, res => {
|
|
3222
|
+
if (res.statusCode !== 200) console.log(`${colors.yellow}[!] Status: ${res.statusCode}${colors.reset}`);
|
|
3223
|
+
res.pipe(process.stdout);
|
|
3224
|
+
}).on("error", e => console.error(e.message));
|
|
3225
|
+
},
|
|
3226
|
+
|
|
3227
|
+
// --- CRYPTO / ENCODING ---
|
|
3228
|
+
"b64": async (args) => {
|
|
3229
|
+
if (!args[0]) return console.log(`${colors.red}Usage: fazer b64 <enc/dec> <string>${colors.reset}`);
|
|
3230
|
+
const mode = args[0]; const str = args.slice(1).join(" ");
|
|
3231
|
+
if (mode === "enc") console.log(Buffer.from(str).toString("base64"));
|
|
3232
|
+
else if (mode === "dec") console.log(Buffer.from(str, "base64").toString("utf8"));
|
|
3233
|
+
else console.log("Unknown mode. Use enc or dec.");
|
|
3234
|
+
},
|
|
3235
|
+
|
|
3236
|
+
"hex": async (args) => {
|
|
3237
|
+
if (!args[0]) return console.log(`${colors.red}Usage: fazer hex <enc/dec> <string>${colors.reset}`);
|
|
3238
|
+
const mode = args[0]; const str = args.slice(1).join(" ");
|
|
3239
|
+
if (mode === "enc") console.log(Buffer.from(str).toString("hex"));
|
|
3240
|
+
else if (mode === "dec") console.log(Buffer.from(str, "hex").toString("utf8"));
|
|
3241
|
+
},
|
|
3242
|
+
|
|
3243
|
+
"md5": async (args) => {
|
|
3244
|
+
if (!args[0]) return console.log(`${colors.red}Usage: fazer md5 <string>${colors.reset}`);
|
|
3245
|
+
console.log(require("crypto").createHash("md5").update(args.join(" ")).digest("hex"));
|
|
3246
|
+
},
|
|
3247
|
+
|
|
3248
|
+
"sha1": async (args) => {
|
|
3249
|
+
if (!args[0]) return console.log(`${colors.red}Usage: fazer sha1 <string>${colors.reset}`);
|
|
3250
|
+
console.log(require("crypto").createHash("sha1").update(args.join(" ")).digest("hex"));
|
|
3251
|
+
},
|
|
3252
|
+
|
|
3253
|
+
"sha256": async (args) => {
|
|
3254
|
+
if (!args[0]) return console.log(`${colors.red}Usage: fazer sha256 <string>${colors.reset}`);
|
|
3255
|
+
console.log(require("crypto").createHash("sha256").update(args.join(" ")).digest("hex"));
|
|
3256
|
+
},
|
|
3257
|
+
|
|
3258
|
+
"url": async (args) => {
|
|
3259
|
+
if (!args[0]) return console.log(`${colors.red}Usage: fazer url <enc/dec> <string>${colors.reset}`);
|
|
3260
|
+
const mode = args[0]; const str = args.slice(1).join(" ");
|
|
3261
|
+
if (mode === "enc") console.log(encodeURIComponent(str));
|
|
3262
|
+
else if (mode === "dec") console.log(decodeURIComponent(str));
|
|
3263
|
+
},
|
|
3264
|
+
|
|
3265
|
+
"uuid": async (args) => {
|
|
3266
|
+
console.log(require("crypto").randomUUID());
|
|
3267
|
+
},
|
|
3268
|
+
|
|
3269
|
+
// --- SYSTEM / UTILS ---
|
|
3270
|
+
"ls": async (args) => {
|
|
3271
|
+
const fs = require("fs");
|
|
3272
|
+
const p = args[0] || ".";
|
|
3273
|
+
try {
|
|
3274
|
+
const files = fs.readdirSync(p);
|
|
3275
|
+
files.forEach(f => {
|
|
3276
|
+
const stat = fs.statSync(require("path").join(p, f));
|
|
3277
|
+
const isDir = stat.isDirectory();
|
|
3278
|
+
console.log(isDir ? `${colors.blue}${f}/${colors.reset}` : f);
|
|
3279
|
+
});
|
|
3280
|
+
} catch(e) { console.error(e.message); }
|
|
3281
|
+
},
|
|
3282
|
+
|
|
3283
|
+
"cat": async (args) => {
|
|
3284
|
+
if (!args[0]) return console.log(`${colors.red}Usage: fazer cat <file>${colors.reset}`);
|
|
3285
|
+
try { require("fs").createReadStream(args[0]).pipe(process.stdout); } catch(e) { console.error(e.message); }
|
|
3286
|
+
},
|
|
3287
|
+
|
|
3288
|
+
"grep": async (args) => {
|
|
3289
|
+
if (!args[1]) return console.log(`${colors.red}Usage: fazer grep <pattern> <file>${colors.reset}`);
|
|
3290
|
+
const pat = new RegExp(args[0]);
|
|
3291
|
+
const file = args[1];
|
|
3292
|
+
try {
|
|
3293
|
+
const content = require("fs").readFileSync(file, "utf8");
|
|
3294
|
+
content.split("\n").forEach((line, i) => {
|
|
3295
|
+
if (pat.test(line)) console.log(`${colors.magenta}${i+1}:${colors.reset} ${line.trim()}`);
|
|
3296
|
+
});
|
|
3297
|
+
} catch(e) { console.error(e.message); }
|
|
3298
|
+
},
|
|
3299
|
+
|
|
3300
|
+
"wc": async (args) => {
|
|
3301
|
+
if (!args[0]) return console.log(`${colors.red}Usage: fazer wc <file>${colors.reset}`);
|
|
3302
|
+
try {
|
|
3303
|
+
const c = require("fs").readFileSync(args[0], "utf8");
|
|
3304
|
+
console.log(`Lines: ${c.split("\n").length}, Chars: ${c.length}`);
|
|
3305
|
+
} catch(e) { console.error(e.message); }
|
|
3306
|
+
},
|
|
3307
|
+
|
|
3308
|
+
"whoami": async (args) => {
|
|
3309
|
+
const os = require("os");
|
|
3310
|
+
console.log(`${os.userInfo().username} @ ${os.hostname()} (${os.platform()} ${os.release()})`);
|
|
3311
|
+
},
|
|
3312
|
+
|
|
3313
|
+
"env": async (args) => {
|
|
3314
|
+
Object.keys(process.env).forEach(k => console.log(`${colors.bold}${k}${colors.reset}=${process.env[k]}`));
|
|
3315
|
+
},
|
|
3316
|
+
|
|
3317
|
+
"pass": async (args) => {
|
|
3318
|
+
const len = args[0] ? parseInt(args[0]) : 16;
|
|
3319
|
+
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+";
|
|
3320
|
+
let res = "";
|
|
3321
|
+
for(let i=0; i<len; i++) res += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
3322
|
+
console.log(res);
|
|
3323
|
+
},
|
|
3324
|
+
|
|
3325
|
+
"calc": async (args) => {
|
|
3326
|
+
if (!args[0]) return console.log(`${colors.red}Usage: fazer calc <expr>${colors.reset}`);
|
|
3327
|
+
try { console.log(eval(args.join(" "))); } catch(e) { console.error("Error"); }
|
|
3328
|
+
},
|
|
3329
|
+
|
|
3330
|
+
"now": async (args) => {
|
|
3331
|
+
console.log(new Date().toISOString());
|
|
3332
|
+
console.log("Timestamp: " + Date.now());
|
|
3333
|
+
},
|
|
3334
|
+
|
|
3335
|
+
"coin": async (args) => {
|
|
3336
|
+
const r = Math.random() < 0.5 ? "Pile (Heads)" : "Face (Tails)";
|
|
3337
|
+
console.log(colors.yellow(r));
|
|
3338
|
+
},
|
|
3339
|
+
|
|
3340
|
+
"dice": async (args) => {
|
|
3341
|
+
const r = Math.floor(Math.random() * 6) + 1;
|
|
3342
|
+
console.log(colors.yellow("🎲 " + r));
|
|
3343
|
+
},
|
|
3344
|
+
|
|
3345
|
+
"uptime": async (args) => {
|
|
3346
|
+
const up = process.uptime();
|
|
3347
|
+
const h = Math.floor(up / 3600);
|
|
3348
|
+
const m = Math.floor((up % 3600) / 60);
|
|
3349
|
+
const s = Math.floor(up % 60);
|
|
3350
|
+
console.log(colors.cyan(`Uptime: ${h}h ${m}m ${s}s`));
|
|
3351
|
+
},
|
|
3352
|
+
|
|
3353
|
+
"mem": async (args) => {
|
|
3354
|
+
const used = process.memoryUsage();
|
|
3355
|
+
console.log(colors.cyan("Memory Usage:"));
|
|
3356
|
+
console.log(` RSS: ${Math.round(used.rss / 1024 / 1024)} MB`);
|
|
3357
|
+
console.log(` Heap Used: ${Math.round(used.heapUsed / 1024 / 1024)} MB`);
|
|
3358
|
+
console.log(` External: ${Math.round(used.external / 1024 / 1024)} MB`);
|
|
3359
|
+
},
|
|
3360
|
+
|
|
3361
|
+
"disk": async (args) => {
|
|
3362
|
+
try {
|
|
3363
|
+
require("child_process").exec("wmic logicaldisk get size,freespace,caption", (err, stdout) => {
|
|
3364
|
+
if(err) console.log(colors.red("Error fetching disk info"));
|
|
3365
|
+
else console.log(colors.cyan(stdout.trim()));
|
|
3366
|
+
});
|
|
3367
|
+
} catch(e) { console.log(colors.red("Disk info unavailable")); }
|
|
3368
|
+
},
|
|
3369
|
+
|
|
3370
|
+
"rot13": async (args) => {
|
|
3371
|
+
if(!args[0]) return console.log(colors.red("Usage: fazer rot13 <text>"));
|
|
3372
|
+
const input = args.join(" ");
|
|
3373
|
+
const out = input.replace(/[a-zA-Z]/g, (c) => {
|
|
3374
|
+
const base = c <= 'Z' ? 65 : 97;
|
|
3375
|
+
return String.fromCharCode(base + (c.charCodeAt(0) - base + 13) % 26);
|
|
3376
|
+
});
|
|
3377
|
+
console.log(colors.green(out));
|
|
3378
|
+
},
|
|
3379
|
+
|
|
3380
|
+
"reverse": async (args) => {
|
|
3381
|
+
if(!args[0]) return console.log(colors.red("Usage: fazer reverse <text>"));
|
|
3382
|
+
console.log(colors.green(args.join(" ").split("").reverse().join("")));
|
|
3383
|
+
}
|
|
3384
|
+
|
|
3385
|
+
};
|
|
3386
|
+
|
|
3387
|
+
if (CLI_COMMANDS[cmd]) {
|
|
3388
|
+
await CLI_COMMANDS[cmd](argv.slice(1));
|
|
3389
|
+
return;
|
|
3390
|
+
}
|
|
3391
|
+
|
|
2659
3392
|
let fileArg = null;
|
|
2660
3393
|
let forwarded = [];
|
|
2661
3394
|
|
|
@@ -2705,7 +3438,16 @@ async function main() {
|
|
|
2705
3438
|
|
|
2706
3439
|
const parser = new FazerParser();
|
|
2707
3440
|
parser.input = lex.tokens;
|
|
2708
|
-
|
|
3441
|
+
let ast;
|
|
3442
|
+
try {
|
|
3443
|
+
ast = parser.program();
|
|
3444
|
+
} catch (e) {
|
|
3445
|
+
if (e.name === "FazerError") {
|
|
3446
|
+
console.error(prettyError(e, filePath, code));
|
|
3447
|
+
process.exit(1);
|
|
3448
|
+
}
|
|
3449
|
+
throw e;
|
|
3450
|
+
}
|
|
2709
3451
|
|
|
2710
3452
|
if (parser.errors.length) {
|
|
2711
3453
|
const e = parser.errors[0];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fazer-lang",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.0",
|
|
4
4
|
"description": "Fazer — The ultimate automation language. Batteries-included: Native EXE Build, Red Team Tools (Crypto/Reg/Shell), Icons, HTTP Server, System Exec, Clipboard, Discord, and Pipe Operators (->). Secure, powerful, and robust.",
|
|
5
5
|
"main": "fazer.js",
|
|
6
6
|
"types": "index.d.ts",
|