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.
- package/index.js +248 -0
- 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
|
+
}
|