galaxytus 1.0.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 (2) hide show
  1. package/index.js +248 -0
  2. package/package.json +26 -0
package/index.js ADDED
@@ -0,0 +1,248 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import chalk from 'chalk';
5
+ import ora from 'ora';
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+ import os from 'os';
9
+
10
+ // Tentukan lokasi penyimpanan API Key di komputer user (~/.galaxytus.json)
11
+ const CONFIG_PATH = path.join(os.homedir(), '.galaxytus.json');
12
+
13
+ // URL API Pusat
14
+ const API_URL = 'http://localhost:3000/api/v1/scan';
15
+
16
+ // --- FUNGSI UTAMA: Menyedot isi file dengan Proteksi Memori (OOM) ---
17
+ function readProjectFiles(dir, fileList = []) {
18
+ const files = fs.readdirSync(dir);
19
+
20
+ files.forEach(file => {
21
+ const filePath = path.join(dir, file);
22
+
23
+ // 1. BLACKLIST: Abaikan folder framework dan file biner raksasa
24
+ const ignoredNames = ['.git', 'node_modules', '.next', 'dist', 'build', 'vendor', 'storage', 'public'];
25
+ const ignoredExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.mp4', '.mp3', '.zip', '.tar', '.gz', '.pdf', '.sqlite', '.db', '.log', '.exe', '.dll'];
26
+
27
+ if (ignoredNames.includes(file) || ignoredExtensions.some(ext => file.toLowerCase().endsWith(ext))) {
28
+ return;
29
+ }
30
+
31
+ const stats = fs.statSync(filePath);
32
+
33
+ if (stats.isDirectory()) {
34
+ readProjectFiles(filePath, fileList);
35
+ } else {
36
+ // 2. PROTEKSI RAM: Batasi ukuran file maksimal 1 MB
37
+ if (stats.size > 1048576) {
38
+ return;
39
+ }
40
+
41
+ try {
42
+ const content = fs.readFileSync(filePath, 'utf-8');
43
+ fileList.push({
44
+ fileName: filePath.replace(process.cwd(), ''),
45
+ content: content
46
+ });
47
+ } catch (err) {
48
+ // Abaikan file yang gagal dibaca
49
+ }
50
+ }
51
+ });
52
+
53
+ return fileList;
54
+ }
55
+
56
+ const program = new Command();
57
+
58
+ program
59
+ .name('galaxytus')
60
+ .description('Galaxytus AI Security Agent CLI')
61
+ .version('1.0.0');
62
+
63
+ // ─── COMMAND: LOGIN ───
64
+ program
65
+ .command('login')
66
+ .description('Hubungkan terminal dengan akun Galaxytus AI')
67
+ .argument('<user_api_keys>', 'API Key dari Dashboard Galaxytus')
68
+ .action((apiKey) => {
69
+ const config = { apiKey };
70
+ fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
71
+ fs.chmodSync(CONFIG_PATH, 0o600);
72
+ console.log(chalk.green('✔ Berhasil!'), 'API Key telah disimpan dengan aman di komputer Anda.');
73
+ console.log(chalk.cyan('➜ Ketik:'), chalk.bold('galaxytus scan <project_id>'), 'untuk mulai memindai.');
74
+ });
75
+
76
+ // ─── COMMAND: LOGOUT ───
77
+ program
78
+ .command('logout')
79
+ .description('Hapus sesi login Galaxytus dari komputer ini')
80
+ .action(() => {
81
+ if (fs.existsSync(CONFIG_PATH)) {
82
+ fs.unlinkSync(CONFIG_PATH); // Menghancurkan file kredensial
83
+ console.log(chalk.green('✔ Sesi Dihapus!'), 'Anda telah berhasil logout.');
84
+ console.log('Jalankan', chalk.yellow('galaxytus login <api_key>'), 'untuk masuk kembali.');
85
+ } else {
86
+ console.log(chalk.yellow('ℹ Anda memang belum login.'));
87
+ }
88
+ });
89
+
90
+ // ─── COMMAND: CREATE ───
91
+ program
92
+ .command('create')
93
+ .description('Daftarkan project baru (URL live atau folder lokal)')
94
+ .argument('[url]', 'URL target (opsional, contoh: https://example.com)')
95
+ .action(async (url) => {
96
+ if (!fs.existsSync(CONFIG_PATH)) {
97
+ console.log(chalk.red('✖ Error:'), 'Anda belum login.');
98
+ process.exit(1);
99
+ }
100
+
101
+ const { apiKey } = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8'));
102
+
103
+ const currentFolder = process.cwd();
104
+ const folderName = path.basename(currentFolder);
105
+
106
+ const finalUrl = url || `local://${folderName}`;
107
+ const projectName = url ? url : folderName;
108
+
109
+ const spinner = ora(`Mendaftarkan project '${projectName}' ke sistem Galaxytus...`).start();
110
+
111
+ try {
112
+ const response = await fetch('http://localhost:3000/api/v1/project', {
113
+ method: 'POST',
114
+ headers: {
115
+ 'Authorization': `Bearer ${apiKey}`,
116
+ 'Content-Type': 'application/json'
117
+ },
118
+ body: JSON.stringify({ targetUrl: finalUrl, projectName: projectName })
119
+ });
120
+
121
+ const data = await response.json();
122
+
123
+ if (!response.ok) {
124
+ spinner.fail(chalk.red('Gagal mendaftar project'));
125
+
126
+ // --- LOGIKA BARU: AUTO-LOGOUT KALAU EXPIRED ---
127
+ if (response.status === 403 && data.error.includes("kedaluwarsa")) {
128
+ console.log(chalk.yellow('\n⚠ PERINGATAN KEAMANAN:'));
129
+ console.log('API Key Anda telah kedaluwarsa (Batas 30 Hari).');
130
+ console.log('Sesi Anda di komputer ini telah dihapus otomatis untuk keamanan.');
131
+
132
+ // Hancurkan kunci dari komputer (Auto-Logout)
133
+ if (fs.existsSync(CONFIG_PATH)) fs.unlinkSync(CONFIG_PATH);
134
+
135
+ console.log(chalk.cyan('\n➜ Silakan generate API Key baru di: https://dashboard.galaxytus.ai'));
136
+ console.log('➜ Lalu login kembali dengan perintah:', chalk.white.bold('galaxytus login <key_baru>'));
137
+ process.exit(1);
138
+ }
139
+
140
+ // Error biasa
141
+ console.log(chalk.yellow('Alasan:'), data.error);
142
+ process.exit(1);
143
+ }
144
+
145
+ spinner.succeed(chalk.green('Project Berhasil Didaftarkan!'));
146
+ console.log(chalk.white('\nNama Project :'), chalk.blue(projectName));
147
+ console.log(chalk.white('Project ID :'), chalk.cyan.bold(data.projectId));
148
+ console.log('\n➜ Mulai pemindaian lokal dengan perintah:');
149
+ console.log(chalk.yellow(`galaxytus scan ${data.projectId}\n`));
150
+
151
+ } catch (error) {
152
+ spinner.fail(chalk.red('Koneksi Terputus'));
153
+ console.log(chalk.yellow('\nDetail Error:'), error.message);
154
+ }
155
+ });
156
+
157
+ // ─── COMMAND: SCAN ───
158
+ program
159
+ .command('scan')
160
+ .description('Jalankan pemindaian keamanan AI pada source code di folder saat ini')
161
+ .argument('<project_id>', 'UUID Project Anda')
162
+ .action(async (projectId) => {
163
+ if (!fs.existsSync(CONFIG_PATH)) {
164
+ console.log(chalk.red('✖ Error:'), 'Anda belum login.');
165
+ process.exit(1);
166
+ }
167
+
168
+ const { apiKey } = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf-8'));
169
+
170
+ console.log(chalk.hex('#4ade80').bold('\n[ G A L A X Y T U S A I ]\n'));
171
+
172
+ const currentFolder = process.cwd();
173
+ const folderName = path.basename(currentFolder);
174
+
175
+ console.log(chalk.blue('📂 Target Folder :'), currentFolder);
176
+ console.log(chalk.blue('📦 Project Name :'), folderName, '\n');
177
+
178
+ const spinnerFolder = ora('Menganalisis dan membungkus source code lokal...').start();
179
+
180
+ // --- PROSES MENYEDOT KODE ---
181
+ let sourceCodeData = [];
182
+ try {
183
+ sourceCodeData = readProjectFiles(currentFolder);
184
+ spinnerFolder.succeed(chalk.green(`Berhasil menyedot ${sourceCodeData.length} file kode (bebas file sampah)!`));
185
+ } catch (err) {
186
+ spinnerFolder.fail(chalk.red('Gagal membaca file di folder ini.'));
187
+ console.log(chalk.yellow('Detail Error:'), err.message);
188
+ process.exit(1);
189
+ }
190
+
191
+ // --- MENGIRIM KE API ---
192
+ const spinner = ora('Mengirim kode ke markas Galaxytus dan membangunkan AI...').start();
193
+
194
+ try {
195
+ const response = await fetch(API_URL, {
196
+ method: 'POST',
197
+ headers: {
198
+ 'Authorization': `Bearer ${apiKey}`,
199
+ 'Content-Type': 'application/json'
200
+ },
201
+ body: JSON.stringify({
202
+ projectId: projectId,
203
+
204
+ // 🚀 FIX: Sesuaikan nama parameter dengan backend!
205
+ targetUrl: `local://${currentFolder}`,
206
+ sourceType: 'local_cli',
207
+
208
+ sourceCode: sourceCodeData
209
+ });
210
+
211
+ const data = await response.json();
212
+
213
+ if (!response.ok) {
214
+ spinner.fail(chalk.red('Pemindaian Gagal'));
215
+
216
+ // --- LOGIKA BARU: AUTO-LOGOUT KALAU EXPIRED ---
217
+ if (response.status === 403 && data.error.includes("kedaluwarsa")) {
218
+ console.log(chalk.yellow('\n⚠ PERINGATAN KEAMANAN:'));
219
+ console.log('API Key Anda telah kedaluwarsa (Batas 30 Hari).');
220
+ console.log('Sesi Anda di komputer ini telah dihapus otomatis untuk keamanan.');
221
+
222
+ // Hancurkan kunci dari komputer (Auto-Logout)
223
+ if (fs.existsSync(CONFIG_PATH)) fs.unlinkSync(CONFIG_PATH);
224
+
225
+ console.log(chalk.cyan('\n➜ Silakan generate API Key baru di: https://dashboard.galaxytus.ai'));
226
+ console.log('➜ Lalu login kembali dengan perintah:', chalk.white.bold('galaxytus login <key_baru>'));
227
+ process.exit(1);
228
+ }
229
+
230
+ // Error biasa
231
+ console.log(chalk.yellow('Alasan:'), data.error);
232
+ process.exit(1);
233
+ }
234
+
235
+ spinner.succeed(chalk.green('AI Agent Berhasil Menerima Kode!'));
236
+ console.log('');
237
+ console.log(chalk.white('Scan ID :'), chalk.cyan(data.scanId));
238
+ console.log(chalk.white('Status :'), chalk.yellow('RUNNING / PENDING'));
239
+ console.log(chalk.white('Dashboard :'), chalk.underline.blue(data.dashboardUrl));
240
+ console.log('\n➜ Pantau temuan celah keamanan (Vulnerabilities) di tautan dashboard di atas.\n');
241
+
242
+ } catch (error) {
243
+ spinner.fail(chalk.red('Koneksi Terputus'));
244
+ console.log(chalk.yellow('Detail Error:'), error.message);
245
+ }
246
+ });
247
+
248
+ program.parse(process.argv);
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "galaxytus",
3
+ "version": "1.0.0",
4
+ "description": "Galaxytus AI Security Agent CLI",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "galaxytus": "./index.js"
8
+ },
9
+ "scripts": {
10
+ "test": "echo \"Error: no test specified\" && exit 1"
11
+ },
12
+ "keywords": [
13
+ "security",
14
+ "ai",
15
+ "pentest",
16
+ "gemini",
17
+ "cli"
18
+ ],
19
+ "author": "Nama Lu",
20
+ "license": "MIT",
21
+ "dependencies": {
22
+ "chalk": "^4.1.2",
23
+ "commander": "^11.0.0",
24
+ "ora": "^5.4.1"
25
+ }
26
+ }