/* This is part of WHY2 Copyright (C) 2022 Václav Šmejkal This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #define _XOPEN_SOURCE 500 #include #include #include #include #include #include #include #include #include #include #include #include int mod_cb(int a, int b) { return a % b; } int multiply_cb(int a, int b) { return a * b; } int subtract_cb(int a, int b) { return a - b; } int sum_cb(int a, int b) { return a + b; } int unlink_cb(const char *fpath, WHY2_UNUSED const struct stat *sb, WHY2_UNUSED int typeflag, WHY2_UNUSED struct FTW *ftwbuf) { int rv = remove(fpath); if (rv) perror(fpath); return rv; } int removeDirectory(char *path) { return nftw(path, unlink_cb, 64, FTW_DEPTH | FTW_PHYS); } void why2_directory(void) { struct stat st; char *buffer = why2_replace(WHY2_CONFIG_DIR, "{HOME}", getenv("HOME")); //CREATE USER CONFIG FOLDER if (stat(buffer, &st) == -1) { mkdir(buffer, 0700); } //DEALLOCATION why2_deallocate(buffer); } enum WHY2_EXIT_CODES why2_check_version(void) { if (why2_get_flags().no_check) return WHY2_SUCCESS; why2_set_memory_identifier("core_version_check"); why2_directory(); //MAKE SURE WHY2 DIR EXISTS //FILE-CHECK VARIABLES int not_found_buffer = 0; //GET VERSION FILE char *version_file = why2_replace(WHY2_VERSIONS_NAME, "{HOME}", getenv("HOME")); //CURL VARIABLES CURL *curl = curl_easy_init(); FILE *file_buffer = why2_fopen(version_file, "w+"); //GET versions.json curl_easy_setopt(curl, CURLOPT_URL, WHY2_VERSIONS_URL); curl_easy_setopt(curl, CURLOPT_WRITEDATA, file_buffer); curl_easy_setopt(curl, CURLOPT_TIMEOUT, WHY2_CURL_TIMEOUT); //DOWNLOAD versions.json curl_easy_perform(curl); //CLEANUP curl_easy_cleanup(curl); why2_deallocate(file_buffer); while (access(version_file, R_OK) != 0) { not_found_buffer++; if (not_found_buffer == WHY2_NOT_FOUND_TRIES) { if (!why2_get_flags().no_output) fprintf(stderr, "%s'%s' not found! Exiting...\n", WHY2_CLEAR_SCREEN, version_file); why2_clean_memory("core_version_check"); return WHY2_DOWNLOAD_FAILED; } if (!why2_get_flags().no_output) printf("%s'%s' not found (%dx)! Trying again in a second.\n", WHY2_CLEAR_SCREEN, version_file, not_found_buffer); sleep(1); } //JSON VARIABLES char *buffer; long buffer_size; struct json_object *parsed_json; struct json_object *active; //COUNT LENGTH OF buffer AND STORE IT IN bufferSize file_buffer = why2_fopen(version_file, "r"); fseek(file_buffer, 0, SEEK_END); buffer_size = ftell(file_buffer); rewind(file_buffer); //REWIND file_buffer (NO SHIT) //SET LENGTH OF buffer buffer = why2_calloc(buffer_size + 1, sizeof(char)); //LOAD jsonFile if (fread(buffer, buffer_size, 1, file_buffer) != 1) { if (!why2_get_flags().no_output) fprintf(stderr, "Reading file failed!\n"); // BELOW CODE IS COMMENTED OUT, BECAUSE IT IS PROBABLY UNNECESSARY // why2_clean_memory("core_version_check"); // return WHY2_DOWNLOAD_FAILED; } buffer[buffer_size] = '\0'; //CHECK FOR TEXT IN buffer if (strcmp(buffer, "") == 0) { if (!why2_get_flags().no_output) fprintf(stderr, "You probably aren't connected to internet! This release could be unsafe!\n\n"); //WAIT FOR 5 SECONDS sleep(5); why2_clean_memory("core_version_check"); return WHY2_SUCCESS; } //CLEANUP why2_deallocate(file_buffer); //GET parsed_json = json_tokener_parse(buffer); //yes, ik, i could use json_object_from_file, but I need to check for internet somehow json_object_object_get_ex(parsed_json, "active", &active); if (strcmp(WHY2_VERSION, json_object_get_string(active)) != 0) { //UPDATE if (why2_get_flags().update) { //CHECK FOR ROOT PERMISSIONS if (getuid() != 0) { if (!why2_get_flags().no_output) fprintf(stderr, "You need to be root to update!\t[I DO NOT RECOMMEND USING THIS]\n"); why2_clean_memory("core_version_check"); return WHY2_WHY2_UPDATE_FAILED; } //VARIABLES git_repository *repo = NULL; int exit_code; char *install_command; int install_code; //MESSAGE if (!why2_get_flags().no_output) printf("Your WHY2 version is outdated!\nUpdating...\t[BETA]\n\n"); //CHECK IF WHY2 REPO ISN'T ALREADY FOUND IN 'WHY2_UPDATE_NAME' if (access(WHY2_UPDATE_NAME, F_OK) == 0) { removeDirectory(WHY2_UPDATE_NAME); } git_libgit2_init(); //START GIT2 exit_code = git_clone(&repo, WHY2_UPDATE_URL, WHY2_UPDATE_NAME, NULL); //CLONE git_libgit2_shutdown(); //STOP GIT2 //CHECK FOR ERRORS if (exit_code != 0) { if (!why2_get_flags().no_output) fprintf(stderr, "Updating failed! (cloning)\n"); why2_clean_memory("core_version_check"); return WHY2_WHY2_UPDATE_FAILED; } //COUNT install_command LENGTH & ALLOCATE IT install_command = why2_replace(WHY2_UPDATE_COMMAND, "{DIR}", WHY2_UPDATE_NAME); install_code = system(install_command); //INSTALL //REMOVE versions.json - OTHERWISE WILL CAUSE SEGFAULT IN NEXT RUN remove(version_file); why2_deallocate(install_command); //CHECK FOR ERRORS if (install_code != 0) { if (!why2_get_flags().no_output) fprintf(stderr, "Updating failed! (installing)\n"); why2_clean_memory("core_version_check"); return WHY2_WHY2_UPDATE_FAILED; } } else { //COUNT WHY2_VERSIONS BEHIND int versions_index = -1; int versions_buffer = 0; struct json_object *deprecated; json_object_object_get_ex(parsed_json, "deprecated", &deprecated); //COUNT versions_index for (int i = 0; i < (int) json_object_array_length(deprecated); i++) { //IT'S A MATCH, BABY :D if (strcmp(json_object_get_string(json_object_array_get_idx(deprecated, i)), WHY2_VERSION) == 0) { versions_index = i; break; } } //versions.json DOESN'T CONTAIN WHY2_VERSION (THIS WILL NOT HAPPEN IF YOU WILL NOT EDIT IT) if (versions_index == -1) { if (!why2_get_flags().no_output) printf("Version %s not found! Check your flags.\n\n", WHY2_VERSION); } else { //COUNT versions_buffer versions_buffer = json_object_array_length(deprecated) - versions_index; if (!why2_get_flags().no_output) fprintf(stderr, "This release could be unsafe! You're %d versions behind! (%s/%s)\n\n", versions_buffer, WHY2_VERSION, json_object_get_string(active)); //WAIT FOR 5 SECONDS sleep(5); } } } //DEALLOCATION json_object_put(parsed_json); //THIS FREES EVERY json_object - AT LEAST JSON-C'S DOCUMENTATION SAYS THAT why2_deallocate(buffer); why2_deallocate(version_file); why2_reset_memory_identifier(); return WHY2_SUCCESS; } void why2_generate_text_key_chain(char *key, int *text_key_chain, int text_key_chain_size) { int number_buffer; int number_buffer_2 = 0; int number_buffer_3 = 0; int (*cb)(int, int); for (int i = 0; i < text_key_chain_size; i++) { //CHECK, IF number_buffer ISN'T GREATER THAN keyLength AND CUT WHY2_UNUSED LENGTH number_buffer = i % why2_get_key_length(); //SET tkch VERSION switch (why2_get_flags().version) { case WHY2_v1: number_buffer_2 = i; number_buffer_3 = number_buffer + (i < text_key_chain_size); break; case WHY2_v2: number_buffer_2 = i; number_buffer_3 = why2_get_key_length() - (number_buffer + (i < text_key_chain_size)); break; case WHY2_v3: number_buffer_2 = text_key_chain_size - (i + 1); number_buffer_3 = why2_get_key_length() - (number_buffer + (i < text_key_chain_size)); break; case WHY2_v4: number_buffer_2 = text_key_chain_size - (i + 1); number_buffer_3 = (why2_get_key_length() ^ text_key_chain_size) >> (((number_buffer ^ number_buffer_2) % 2) & (i < text_key_chain_size)); //gl fucker break; } //FILL textKeyChain if (why2_get_flags().version == WHY2_v4 && (number_buffer + 1) % 4 == 0) { cb = mod_cb; } else if ((number_buffer + 1) % 3 == 0) { cb = multiply_cb; } else if ((number_buffer + 1) % 2 == 0) { cb = subtract_cb; } else { cb = sum_cb; } text_key_chain[number_buffer_2] = cb(key[number_buffer], key[number_buffer_3]); } } void why2_deallocate_output(why2_output_flags flags) { why2_deallocate(flags.output_text); why2_deallocate(flags.used_key); flags.elapsed_time = 0; flags.exit_code = WHY2_SUCCESS; flags.repeated_key_size = 0; flags.unused_key_size = 0; flags.output_text = NULL; flags.used_key = NULL; } enum WHY2_EXIT_CODES why2_check_key(char *key) { if (strlen(key) < why2_get_key_length()) { if (!why2_get_flags().no_output) fprintf(stderr, "Key must be at least %lu characters long!\n", why2_get_key_length()); return WHY2_INVALID_KEY; } return WHY2_SUCCESS; } enum WHY2_EXIT_CODES why2_check_text(char *text) { if (strcmp(text, "") == 0) { if (!why2_get_flags().no_output) fprintf(stderr, "No text to encrypt!\n"); return WHY2_INVALID_TEXT; } return WHY2_SUCCESS; } unsigned long why2_count_int_length(int number) { int returning = 1; int buffer = 10; //CHECK FOR NEGATIVE NUMBER if (number < 0) { returning++; number *= -1; } //COUNT LENGTH while (buffer <= number) { buffer *= 10; returning++; } return returning; } unsigned long why2_count_unused_key_size(char *text, char *key) { unsigned long returning = 0; if ((long double) (strlen(key)) / 2 > strlen(text)) { returning = strlen(key) - 2 * strlen(text); } return returning; } unsigned long why2_count_repeated_key_size(char *text, char *key) { unsigned long returning = 0; if (strlen(key) < 2 * strlen(text)) { returning = 2 * strlen(text) - strlen(key); } return returning; } unsigned long why2_compare_time_micro(struct timeval startTime, struct timeval finishTime) { return (finishTime.tv_sec - startTime.tv_sec) * 1000000 + finishTime.tv_usec - startTime.tv_usec; } char *why2_generate_key(int key_length) { int number_buffer; unsigned int random_buffer; char *key; key = why2_malloc(key_length + 1); for (int i = 0; i < key_length; i++) { //GET RANDOM NUMBER if (getrandom(&random_buffer, sizeof(unsigned int), GRND_NONBLOCK) == -1) why2_die("getrandom fn failed!"); //SET numberBuffer TO RANDOM NUMBER BETWEEN 0 AND 52 number_buffer = (random_buffer % 52) + 1; //GET CHAR FROM numberBuffer if (number_buffer > 26) { number_buffer += 70; } else { number_buffer += 64; } key[i] = (char) number_buffer; } key[key_length] = '\0'; return key; } void why2_die(char *exit_msg) { fprintf(stderr, "%s\n", exit_msg); //ERR MSG why2_clean_memory(why2_get_default_memory_identifier()); //GARBAGE COLLECTOR exit(1); } char *why2_replace(char *string, char *old, char *new) //CODE FROM: https://www.geeksforgeeks.org/c-program-replace-word-text-another-given-word { char *result; int i, cnt = 0; int newLen = strlen(new); int oldLen = strlen(old); for (i = 0; string[i] != '\0'; i++) { if (strstr(&string[i], old) == &string[i]) { cnt++; i += oldLen - 1; } } result = (char*) why2_malloc(i + cnt * (newLen - oldLen) + 1); i = 0; while (*string) { // compare the substring with the result if (strstr(string, old) == string) { strcpy(&result[i], new); i += newLen; string += oldLen; } else result[i++] = *string++; } result[i] = '\0'; return result; } unsigned short why2_byte_format_length(char *s) { return ((s[1] - 1) << 7) | (s[0] - 1); //ADD THE FIRST TWO INDEXES TOGETHER TO GET LENGTH }