#include "exploit_cli.h" #include #include #include #include #include #include #include #include #include #include size_t write_file_callback(void *ptr, size_t size, size_t nmemb, FILE *stream) { return fwrite(ptr, size, nmemb, stream); } // Helper function to create directories recursively int mkdir_recursive(const char *dirf) { char tmp[MAX_PATH]; char *p = NULL; size_t len; snprintf(tmp, sizeof(tmp), "%s", dirf); len = strlen(tmp); if (tmp[len - 1] == '/') tmp[len - 1] = 0; for (p = tmp + 1; *p; p++) { if (*p == '/') { *p = 0; if (mkdir(tmp, 0777) && errno != EEXIST) { perror("mkdir"); return 1; } *p = '/'; } } if (mkdir(tmp, 0777) && errno != EEXIST) { perror("mkdir"); return 1; } return 0; } // Function to extract zip archive int extract_zip(const char *zip_path, const char *extract_path) { int err = 0; zip_t *za = zip_open(zip_path, 0, &err); if (!za) { print_error("Cannot open zip archive"); return 1; } if (mkdir_recursive(extract_path) != 0) { zip_close(za); return 1; } for (zip_int64_t i = 0; i < zip_get_num_entries(za, 0); i++) { struct zip_stat st; if (zip_stat_index(za, i, 0, &st) == 0) { char full_path[MAX_PATH]; snprintf(full_path, sizeof(full_path), "%s/%s", extract_path, st.name); if (st.name[strlen(st.name) - 1] == '/') { if (mkdir_recursive(full_path) != 0) { zip_close(za); return 1; } } else { // Create parent directory for file char *dirc = strdup(full_path); char *dname = dirname(dirc); if (mkdir_recursive(dname) != 0) { free(dirc); zip_close(za); return 1; } free(dirc); zip_file_t *zf = zip_fopen_index(za, i, 0); if (!zf) { print_error("Error opening file in zip"); zip_close(za); return 1; } FILE *fp = fopen(full_path, "wb"); if (!fp) { print_error("Error creating extracted file"); zip_fclose(zf); zip_close(za); return 1; } char buf[4096]; zip_uint64_t sum = 0; while (sum < st.size) { zip_int64_t len = zip_fread(zf, buf, sizeof(buf)); if (len < 0) { print_error("Error reading zip content"); fclose(fp); zip_fclose(zf); zip_close(za); return 1; } fwrite(buf, 1, len, fp); sum += len; } fclose(fp); zip_fclose(zf); } } } zip_close(za); return 0; } // Clone command implementation int cmd_clone(int argc, char *argv[]) { if (argc < 2) { printf("\033[33m📝 Usage: exp clone [output_directory]\033[0m\n"); return 1; } char *repo_path = argv[1]; char *output_dir = "."; // Check if output directory is specified if (argc > 2) { output_dir = argv[2]; } char *archive_url = NULL; // URL handling - SELALU menambahkan /archive di akhir URL if (strstr(repo_path, "http://") || strstr(repo_path, "https://")) { // URL already provided if (!strstr(repo_path, "/archive")) { asprintf(&archive_url, "%s/archive", repo_path); } else { archive_url = strdup(repo_path); } } else { // Convert username/repo format to URL asprintf(&archive_url, "https://exploit.or.id/%s/archive", repo_path); } print_info("Cloning repository..."); printf("From: %s\n", archive_url); char *url_copy = strdup(repo_path); char *last_slash = strrchr(url_copy, '/'); char folder_name[MAX_BUFFER]; if (last_slash && *(last_slash + 1) != '\0') { strncpy(folder_name, last_slash + 1, MAX_BUFFER - 1); folder_name[MAX_BUFFER - 1] = '\0'; // Remove /archive suffix if present char *archive_pos = strstr(folder_name, "/archive"); if (archive_pos) { *archive_pos = '\0'; } // Remove .git suffix if present char *git_suffix = strstr(folder_name, ".git"); if (git_suffix) { *git_suffix = '\0'; } } else { strcpy(folder_name, "repository"); } free(url_copy); // Construct output directory path char output_path[MAX_PATH]; snprintf(output_path, MAX_PATH, "%s/%s", output_dir, folder_name); // Check if output directory already exists struct stat st = {0}; if (stat(output_path, &st) == 0 && S_ISDIR(st.st_mode)) { print_error("Directory already exists"); return 1; } // Temporary zip file path char zip_file_path[MAX_PATH]; snprintf(zip_file_path, MAX_PATH, "%s/%s.zip", output_dir, folder_name); // Download repository archive CURL *curl; CURLcode res; FILE *fp; curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if (curl) { fp = fopen(zip_file_path, "wb"); if (!fp) { print_error("Error opening file for writing"); curl_easy_cleanup(curl); curl_global_cleanup(); return 1; } // Set headers to request ZIP file struct curl_slist *headers = NULL; headers = curl_slist_append(headers, "Accept: application/zip"); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_URL, archive_url); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_file_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); // Disable SSL verification for testing curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); // Enable following redirects curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 10L); // Disable verbose mode curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L); print_progress("Downloading repository archive..."); res = curl_easy_perform(curl); fclose(fp); curl_slist_free_all(headers); if (res != CURLE_OK) { print_error(curl_easy_strerror(res)); remove(zip_file_path); // Cleanup resources curl_easy_cleanup(curl); curl_global_cleanup(); return 1; } // Check HTTP response code long http_code = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code); if (http_code != 200) { print_error("Failed to download repository archive"); printf("HTTP response code: %ld\n", http_code); if (http_code == 404) { printf("Repository '%s' tidak ditemukan di server.\n", repo_path); printf("Pastikan repository tersebut ada dan Anda memiliki akses.\n"); } else if (http_code == 401 || http_code == 403) { print_error("Access denied"); printf("You may not have permission to access this repository.\n"); } else { print_error("HTTP error"); printf("Server returned HTTP code %ld\n", http_code); } remove(zip_file_path); curl_easy_cleanup(curl); curl_global_cleanup(); return 1; } // File downloaded successfully print_progress("Extracting archive..."); // Extract the ZIP archive if (extract_zip(zip_file_path, output_path) == 0) { printf("\033[32m✅ Successfully cloned to '%s/'\033[0m\n", output_path); remove(zip_file_path); printf("Clone complete.\n"); } else { print_error("Failed to extract archive"); printf("Archive saved at: %s (not removed for debugging)\n", zip_file_path); free(archive_url); curl_easy_cleanup(curl); curl_global_cleanup(); return 1; } curl_easy_cleanup(curl); } else { print_error("Failed to initialize curl"); curl_global_cleanup(); return 1; } free(archive_url); curl_global_cleanup(); return 0; }