#include #include #include #include #include #include #include #include #include #include #define YELLOW "\033[1;33m" #define RESET "\033[0m" size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) { return fwrite(ptr, size, nmemb, stream); } int mkdir_recursive(const char *dir) { char tmp[1024]; char *p = NULL; size_t len; snprintf(tmp, sizeof(tmp), "%s", dir); 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; } 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) { fprintf(stderr, "Error: Cannot open zip archive '%s'\n", zip_path); 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[1024]; 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 { // buat direktori parent file dulu 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) { fprintf(stderr, "Error opening file in zip: %s\n", zip_strerror(za)); zip_close(za); return 1; } FILE *fp = fopen(full_path, "wb"); if (!fp) { perror("Error creating extracted file"); zip_fclose(zf); zip_close(za); return 1; } char buf[1024]; zip_int64_t sum = 0; while (sum < st.size) { zip_int64_t len = zip_fread(zf, buf, sizeof(buf)); if (len < 0) { fprintf(stderr, "Error reading zip content: %s\n", zip_strerror(za)); 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; } void hxb_clone(const char *repo_url, const char *parent_dir) { CURL *curl; CURLcode res; FILE *fp; char *archive_url = NULL; char zip_file_path[512]; printf("Cloning from: %s\n", repo_url); if (!strstr(repo_url, "/archive")) { asprintf(&archive_url, "%s/archive", repo_url); } else { archive_url = strdup(repo_url); } // Ambil nama folder terakhir dari repo_url char *url_copy = strdup(repo_url); char *last_slash = strrchr(url_copy, '/'); char folder_name[256]; if (last_slash && *(last_slash + 1) != '\0') { strncpy(folder_name, last_slash + 1, sizeof(folder_name) - 1); folder_name[sizeof(folder_name) - 1] = '\0'; // hilangkan "/archive" kalau ada char *archive_pos = strstr(folder_name, "/archive"); if (archive_pos) *archive_pos = '\0'; } else { strcpy(folder_name, "output"); } free(url_copy); // Gabungkan parent_dir + folder_name char output_dir[512]; snprintf(output_dir, sizeof(output_dir), "%s/%s", parent_dir, folder_name); // Cek apakah folder output_dir sudah ada struct stat st = {0}; if (stat(output_dir, &st) == 0 && S_ISDIR(st.st_mode)) { fprintf(stderr, "Error: Directory '%s' already exists.\n", output_dir); free(archive_url); return; } snprintf(zip_file_path, sizeof(zip_file_path), "%s.zip", output_dir); curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if (curl) { fp = fopen(zip_file_path, "wb"); if (!fp) { perror("Error opening file for writing"); free(archive_url); curl_easy_cleanup(curl); return; } curl_easy_setopt(curl, CURLOPT_URL, archive_url); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp); res = curl_easy_perform(curl); fclose(fp); if (res != CURLE_OK) { fprintf(stderr, "Download error: %s\n", curl_easy_strerror(res)); remove(zip_file_path); } else { printf("Downloaded archive: %s\n", zip_file_path); if (extract_zip(zip_file_path, output_dir) == 0) { printf("Extracted to '%s/'\n", output_dir); remove(zip_file_path); printf("Clone complete.\n"); } else { fprintf(stderr, "Extraction failed.\n"); } } curl_easy_cleanup(curl); } else { fprintf(stderr, "Error initializing curl.\n"); } free(archive_url); curl_global_cleanup(); } int main(int argc, char *argv[]) { printf("\n=============================================\n"); printf(YELLOW " ExploitHub Cloner - HaxorSec@2025\n" RESET); printf("=============================================\n\n"); const char *repo_url = NULL; const char *output_parent_dir = NULL; for (int i = 1; i < argc; i++) { if ((strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "--output") == 0) && i + 1 < argc) { output_parent_dir = argv[++i]; } else if (!repo_url) { repo_url = argv[i]; } } if (!repo_url) { fprintf(stderr, "Usage: %s [-o|--output ]\n", argv[0]); return 1; } if (!output_parent_dir) { output_parent_dir = "."; } hxb_clone(repo_url, output_parent_dir); return 0; }