|
| 1 | +<<<<<<< HEAD |
1 | 2 | import axios from "axios"; |
2 | 3 | import * as dotenv from "dotenv"; |
3 | 4 | import chalk from "chalk"; |
@@ -125,3 +126,132 @@ export async function scanUrl(url: string): Promise<void> { |
125 | 126 | console.error(chalk.red.bold("❌ Error:"), err.response?.data || err.message); |
126 | 127 | } |
127 | 128 | } |
| 129 | +======= |
| 130 | +import axios from "axios"; |
| 131 | +import * as dotenv from "dotenv"; |
| 132 | +import chalk from "chalk"; |
| 133 | +import cliProgress from "cli-progress"; |
| 134 | +import figlet from "figlet"; |
| 135 | +import moment from "moment"; |
| 136 | + |
| 137 | +dotenv.config(); |
| 138 | + |
| 139 | +const VIRUSTOTAL_API_KEY = process.env.VIRUSTOTAL_API_KEY; |
| 140 | + |
| 141 | +if (!VIRUSTOTAL_API_KEY) { |
| 142 | + throw new Error(chalk.red.bold("❌ Missing VirusTotal API Key in .env file!")); |
| 143 | +} |
| 144 | + |
| 145 | +export async function scanUrl(url: string): Promise<void> { |
| 146 | + try { |
| 147 | + console.log(chalk.blue.bold(figlet.textSync("Malware Sniffer", { horizontalLayout: "full" }))); |
| 148 | + console.log(chalk.blue.bold(`\n🚀 Starting URL Scan: ${chalk.underline(url)}\n`)); |
| 149 | + |
| 150 | + const startTime = moment(); |
| 151 | + |
| 152 | + const response = await axios.post( |
| 153 | + "https://www.virustotal.com/api/v3/urls", |
| 154 | + new URLSearchParams({ url }), |
| 155 | + { |
| 156 | + headers: { |
| 157 | + "x-apikey": VIRUSTOTAL_API_KEY, |
| 158 | + "Content-Type": "application/x-www-form-urlencoded", |
| 159 | + }, |
| 160 | + } |
| 161 | + ); |
| 162 | + |
| 163 | + const scanId = response.data.data.id; |
| 164 | + console.log(chalk.yellow.bold(`🔍 Scanning in progress...`)); |
| 165 | + console.log(chalk.cyan.bold(`📌 Scan ID: ${scanId}`)); |
| 166 | + |
| 167 | + const progressBar = new cliProgress.SingleBar( |
| 168 | + { |
| 169 | + format: `⏳ Progress: [{bar}] {percentage}% | ETA: {eta}s`, |
| 170 | + barCompleteChar: "█", |
| 171 | + barIncompleteChar: "░", |
| 172 | + }, |
| 173 | + cliProgress.Presets.shades_classic |
| 174 | + ); |
| 175 | + |
| 176 | + progressBar.start(100, 0); |
| 177 | + let status = "queued"; |
| 178 | + let scanResults: any; |
| 179 | + let elapsedTime = 0; |
| 180 | + |
| 181 | + while (status === "queued") { |
| 182 | + await new Promise((resolve) => setTimeout(resolve, 5000)); |
| 183 | + |
| 184 | + elapsedTime += 5; |
| 185 | + progressBar.update((elapsedTime / 30) * 100); |
| 186 | + |
| 187 | + const result = await axios.get( |
| 188 | + `https://www.virustotal.com/api/v3/analyses/${scanId}`, |
| 189 | + { |
| 190 | + headers: { "x-apikey": VIRUSTOTAL_API_KEY }, |
| 191 | + } |
| 192 | + ); |
| 193 | + |
| 194 | + scanResults = result.data.data.attributes; |
| 195 | + status = scanResults.status; |
| 196 | + |
| 197 | + if (status === "queued") { |
| 198 | + console.log(chalk.gray("⏳ Still processing... Waiting...")); |
| 199 | + } |
| 200 | + } |
| 201 | + |
| 202 | + progressBar.stop(); |
| 203 | + |
| 204 | + const engines = scanResults.results; |
| 205 | + const detectedEngines = Object.values(engines).filter((res: any) => res.category === "malicious").length; |
| 206 | + const totalEngines = Object.keys(engines).length; |
| 207 | + const safeScore = ((totalEngines - detectedEngines) / totalEngines) * 100; |
| 208 | + |
| 209 | + const endTime = moment(); |
| 210 | + const duration = moment.duration(endTime.diff(startTime)).seconds(); |
| 211 | + |
| 212 | + console.log("\n📊 " + chalk.bold.underline("Scan Results Summary:")); |
| 213 | + console.log(chalk.gray(`🕒 Scan Duration: ${duration} seconds`)); |
| 214 | + console.log(chalk.green.bold(`🔹 Total Engines Checked: ${totalEngines}`)); |
| 215 | + console.log(chalk.red.bold(`🔸 Malicious Detections: ${detectedEngines}`)); |
| 216 | + console.log(chalk.yellow.bold(`🟡 Suspicious Engines: ${Object.values(engines).filter((res: any) => res.category === "suspicious").length}`)); |
| 217 | + console.log(chalk.green.bold(`✅ Safe Score: ${safeScore.toFixed(2)}%`)); |
| 218 | + |
| 219 | + console.log("\n📈 " + chalk.bold("Detection Chart:")); |
| 220 | + console.log(chalk.green("🟩".repeat(Math.round(safeScore / 10))) + chalk.red("🟥".repeat(Math.round((100 - safeScore) / 10)))); |
| 221 | + console.log(chalk.green.bold(`Safe: ${safeScore.toFixed(2)}%`)); |
| 222 | + console.log(chalk.red.bold(`Malicious: ${(100 - safeScore).toFixed(2)}%\n`)); |
| 223 | + |
| 224 | + console.log(chalk.bold("🔍 Detailed Results:")); |
| 225 | + Object.entries(engines).forEach(([engine, data]: any) => { |
| 226 | + let categoryColor; |
| 227 | + switch (data.category) { |
| 228 | + case "malicious": |
| 229 | + categoryColor = chalk.red.bold("🛑 Malicious"); |
| 230 | + break; |
| 231 | + case "harmless": |
| 232 | + categoryColor = chalk.green.bold("✅ Harmless"); |
| 233 | + break; |
| 234 | + case "suspicious": |
| 235 | + categoryColor = chalk.yellow.bold("⚠️ Suspicious"); |
| 236 | + break; |
| 237 | + default: |
| 238 | + categoryColor = chalk.gray(data.category); |
| 239 | + } |
| 240 | + |
| 241 | + console.log( |
| 242 | + chalk.cyan(`📌 ${engine}:`) + |
| 243 | + ` ${categoryColor} | ` + |
| 244 | + chalk.gray(`Method: ${data.method}`) |
| 245 | + ); |
| 246 | + }); |
| 247 | + |
| 248 | + if (detectedEngines > 0) { |
| 249 | + console.log(chalk.red.bold("\n⚠️ WARNING: This URL is potentially unsafe!")); |
| 250 | + } else { |
| 251 | + console.log(chalk.green.bold("\n✅ This URL appears safe!")); |
| 252 | + } |
| 253 | + } catch (err: any) { |
| 254 | + console.error(chalk.red.bold("❌ Error:"), err.response?.data || err.message); |
| 255 | + } |
| 256 | +} |
| 257 | +>>>>>>> 913bfbc0c48e5bdbb30449cbd1df4b0c0c1ecd09 |
0 commit comments