From bdeb224e3314e08ce766c05d16c2cc8f1fb060e6 Mon Sep 17 00:00:00 2001 From: Shivam Sharma <56030049+shivamsharma2509@users.noreply.github.com> Date: Sat, 26 Oct 2024 13:03:42 +0530 Subject: [PATCH 1/7] Add files via upload --- src/Auth.c | 287 +++++++++++++++++++++++++++++++++++++++++++++++++ src/AuthUI.c | 42 ++++++++ src/auth.h | 12 +++ src/config.cfg | 2 + 4 files changed, 343 insertions(+) create mode 100644 src/Auth.c create mode 100644 src/AuthUI.c create mode 100644 src/auth.h create mode 100644 src/config.cfg diff --git a/src/Auth.c b/src/Auth.c new file mode 100644 index 0000000..32077a1 --- /dev/null +++ b/src/Auth.c @@ -0,0 +1,287 @@ +#define GOA_API_IS_SUBJECT_TO_CHANGE + +#include "auth.h" +#include +#include +#include + +#include +#include +#include +#include +#include + +#define PORT 8080 +#define AUTHORIZATION_URL "https://github.com/login/oauth/authorize" +#define TOKEN_URL "https://github.com/login/oauth/access_token" + +/* Global variables */ + +static gchar *auth_code = NULL; +static GoaClient *client; +GtkWidget *token_label; + +/* Function to load configuration from file */ + +void load_config(char **client_id, char **client_secret) { + + FILE *file = fopen("config.cfg", "r"); + if (file == NULL) { + g_error("Could not open config.cfg file"); + return; + } + + char line[256]; + while (fgets(line, sizeof(line), file)) { + + char *key = strtok(line, "="); + char *value = strtok(NULL, "\n"); + + if (key != NULL && value != NULL) { + if (strcmp(key, "CLIENT_ID") == 0) { + *client_id = g_strdup(value); + g_print("Loaded CLIENT_ID: %s\n", *client_id); + } + + else if (strcmp(key, "CLIENT_SECRET") == 0) { + *client_secret = g_strdup(value); + g_print("Loaded CLIENT_SECRET: %s\n", *client_secret); + } + } + + else { + g_warning("Malformed line in config.cfg: %s", line); + } + } + + fclose(file); + + if (*client_id == NULL || *client_secret == NULL) { + g_error("Client ID or Client Secret not found in config.cfg"); + } +} + +/* Function to handle writing data received from curl */ + +size_t write_callback(void *ptr, size_t size, size_t nmemb, char **data) { + size_t realsize = size * nmemb; + *data = strndup(ptr, realsize); // Duplicate the data received + return realsize; +} + +/* Function to handle HTTP requests */ + +static enum MHD_Result handle_request(void *cls, struct MHD_Connection *connection, + const char *url, const char *method, + const char *version, const char *upload_data, + size_t *upload_data_size, void **con_cls) { + g_print("Received request for URL: %s with method: %s\n", url, method); + + if (strcmp(url, "/callback") == 0) { + + if (strcmp(method, "GET") == 0) { + + const char *code = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "code"); + + if (code) { + auth_code = g_strdup(code); + g_print("Authorization code received: %s\n", auth_code); + + char *client_id = NULL; + char *client_secret = NULL; + + load_config(&client_id, &client_secret); + + if (client_id == NULL || client_secret == NULL) { + g_error("Client ID or Client Secret is NULL. Check config.cfg file."); + } + + /* Exchange authorization code for access token using libcurl */ + + CURL *curl; + CURLcode res; + + curl_global_init(CURL_GLOBAL_DEFAULT); + curl = curl_easy_init(); + + if (curl) { + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers, "Accept: application/json"); + + curl_easy_setopt(curl, CURLOPT_URL, TOKEN_URL); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_POST, 1L); + + gchar *post_data = g_strdup_printf("client_id=%s&client_secret=%s&code=%s", + client_id, client_secret, auth_code); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data); + + char *response = NULL; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); + + res = curl_easy_perform(curl); + + if (res != CURLE_OK) { + g_warning("curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); + } + + else { + g_print("Response: %s\n", response); + + /* Parse JSON response to extract the access token */ + + json_object *json_response = json_tokener_parse(response); + json_object *json_access_token; + + if (json_object_object_get_ex(json_response, "access_token", &json_access_token)) { + + const char *access_token = json_object_get_string(json_access_token); + g_print("Access Token: %s\n", access_token); + gtk_label_set_text(GTK_LABEL(token_label), access_token); + + /* Save the access token to a file */ + + FILE *token_file = fopen("access_token.txt", "w"); + + if (token_file) { + fprintf(token_file, "%s\n", access_token); + fclose(token_file); + } + else { + g_warning("Failed to open access_token.txt for writing."); + } + } + else { + g_warning("Failed to extract access token from response."); + gtk_label_set_text(GTK_LABEL(token_label), "Failed to extract access token."); + } + + json_object_put(json_response); // free json object + } + + g_free(post_data); + curl_easy_cleanup(curl); + if (response) { + free(response); + } + } + curl_global_cleanup(); + + g_free(client_id); + g_free(client_secret); + } + + const char *response_html = "

Authentication successful! You can close this window.

"; + struct MHD_Response *response_obj = MHD_create_response_from_buffer(strlen(response_html), (void *)response_html, MHD_RESPMEM_PERSISTENT); + + int ret = MHD_queue_response(connection, MHD_HTTP_OK, response_obj); + MHD_destroy_response(response_obj); + return ret; + } + } + + return MHD_NO; +} + +/* Function to start the local server */ + +void start_local_server() { + struct MHD_Daemon *daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, PORT, NULL, NULL, &handle_request, NULL, MHD_OPTION_END); + + if (daemon == NULL) { + g_error("Failed to start local server."); + } + g_print("Local server started on port %d\n", PORT); +} + +/* Function to start the OAuth2 flow */ + +void start_oauth_flow() { + char *client_id = NULL; + char *client_secret = NULL; + load_config(&client_id, &client_secret); + + if (client_id == NULL) { + g_error("Client ID is NULL. Check config.cfg file."); + } + + gchar *auth_url = g_strdup_printf( + "%s?client_id=%s&redirect_uri=http://localhost:8080/callback&scope=user", + AUTHORIZATION_URL, client_id); + + g_print("Visit the following URL to authorize the application:\n%s\n", auth_url); + + /* Open the URL in the default browser */ + + gchar *command = g_strdup_printf("xdg-open '%s'", auth_url); + system(command); + g_free(command); + + g_free(auth_url); + g_free(client_id); + g_free(client_secret); +} + +/* Callback when the GoaClient is ready */ + +void on_goa_ready(GObject *source_object, GAsyncResult *res, gpointer user_data) { + GError *error = NULL; + client = goa_client_new_finish(res, &error); + + if (error) { + g_warning("Failed to initialize GoaClient: %s", error->message); + g_error_free(error); + return; + } + + g_print("GoaClient initialized successfully.\n"); +} + +/* Initialize the GoaClient */ + +void initialize_goa() { + goa_client_new(NULL, on_goa_ready, NULL); +} + +/* Main function */ + +int main(int argc, char *argv[]) { + gtk_init(&argc, &argv); + + /* Create a simple GTK window */ + + GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(window), "OAuth2 Authentication"); + gtk_window_set_default_size(GTK_WINDOW(window), 400, 200); + + /* Create a label to display the access token */ + + token_label = gtk_label_new("No token received yet."); + + /* Create an "Authenticate" button */ + + GtkWidget *auth_button = gtk_button_new_with_label("Authenticate"); + g_signal_connect(auth_button, "clicked", G_CALLBACK(start_oauth_flow), NULL); + + /* Create a vertical box to hold the label and button */ + + GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); + gtk_box_pack_start(GTK_BOX(vbox), token_label, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox), auth_button, TRUE, TRUE, 0); + + gtk_container_add(GTK_CONTAINER(window), vbox); + + g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); + + /* Initialize the GoaClient and start the local server */ + + initialize_goa(); + start_local_server(); + + gtk_widget_show_all(window); + gtk_main(); + + return 0; +} + diff --git a/src/AuthUI.c b/src/AuthUI.c new file mode 100644 index 0000000..3d7d1dd --- /dev/null +++ b/src/AuthUI.c @@ -0,0 +1,42 @@ +#include +#include "auth.h" + +// Declare token_label as a global variable +GtkWidget *token_label; + +static void activate(GtkApplication *app, gpointer user_data) { + GtkWidget *window; + GtkWidget *button; + GtkWidget *grid; + + window = gtk_application_window_new(app); + gtk_window_set_title(GTK_WINDOW(window), "OAuth2 Authentication"); + gtk_window_set_default_size(GTK_WINDOW(window), 400, 200); + + grid = gtk_grid_new(); + gtk_container_add(GTK_CONTAINER(window), grid); + + button = gtk_button_new_with_label("Authenticate"); + g_signal_connect(button, "clicked", G_CALLBACK(authenticate_user), NULL); + gtk_grid_attach(GTK_GRID(grid), button, 0, 0, 1, 1); + + token_label = gtk_label_new("Access token will be displayed here."); + gtk_grid_attach(GTK_GRID(grid), token_label, 0, 1, 1, 1); + + gtk_widget_show_all(window); + + initialize_goa(); +} + +int main(int argc, char **argv) { + GtkApplication *app; + int status; + + app = gtk_application_new("org.example.OAuth", G_APPLICATION_DEFAULT_FLAGS); + g_signal_connect(app, "activate", G_CALLBACK(activate), NULL); + status = g_application_run(G_APPLICATION(app), argc, argv); + g_object_unref(app); + + return status; +} + diff --git a/src/auth.h b/src/auth.h new file mode 100644 index 0000000..8b840d2 --- /dev/null +++ b/src/auth.h @@ -0,0 +1,12 @@ +// auth.h +#ifndef AUTH_H +#define AUTH_H + +#include +#include + +// Function prototype for authenticate_user +void authenticate_user(GtkWidget *widget, gpointer data); + +#endif // AUTH_H + diff --git a/src/config.cfg b/src/config.cfg new file mode 100644 index 0000000..f2516b0 --- /dev/null +++ b/src/config.cfg @@ -0,0 +1,2 @@ +CLIENT_ID=Ov23lirB62bclUpviNM1 +CLIENT_SECRET=c409cb708c71b58f854da44cbd5c1fff56e6a6d3 From 2441440c6e66012ff1de4fb38b716df5a0b2ab84 Mon Sep 17 00:00:00 2001 From: Shivam Sharma <56030049+shivamsharma2509@users.noreply.github.com> Date: Sun, 27 Oct 2024 11:22:16 +0530 Subject: [PATCH 2/7] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 562cd3f..d4d5da9 100644 --- a/README.md +++ b/README.md @@ -48,3 +48,5 @@ NOTE: The communication protocol between frontends and backends has changed (Job - [Nilanjana Lodh's Google Summer of Code 2017 Final Report](https://nilanjanalodh.github.io/common-print-dialog-gsoc17/) - [Gaurav Guleria's Google Summer of Code 2022 Final Report](https://github.com/TinyTrebuchet/gsoc22/) + +- [Shivam Sharma's Google Summer of Code 2024 Final Report](https://github.com/shivamsharma2509/GSOC24) From 283e1fbe770b42b527bf70a949916e1c1ac16d21 Mon Sep 17 00:00:00 2001 From: Shivam Sharma <56030049+shivamsharma2509@users.noreply.github.com> Date: Tue, 29 Oct 2024 14:09:19 +0530 Subject: [PATCH 3/7] Delete src/AuthUI.c --- src/AuthUI.c | 42 ------------------------------------------ 1 file changed, 42 deletions(-) delete mode 100644 src/AuthUI.c diff --git a/src/AuthUI.c b/src/AuthUI.c deleted file mode 100644 index 3d7d1dd..0000000 --- a/src/AuthUI.c +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include "auth.h" - -// Declare token_label as a global variable -GtkWidget *token_label; - -static void activate(GtkApplication *app, gpointer user_data) { - GtkWidget *window; - GtkWidget *button; - GtkWidget *grid; - - window = gtk_application_window_new(app); - gtk_window_set_title(GTK_WINDOW(window), "OAuth2 Authentication"); - gtk_window_set_default_size(GTK_WINDOW(window), 400, 200); - - grid = gtk_grid_new(); - gtk_container_add(GTK_CONTAINER(window), grid); - - button = gtk_button_new_with_label("Authenticate"); - g_signal_connect(button, "clicked", G_CALLBACK(authenticate_user), NULL); - gtk_grid_attach(GTK_GRID(grid), button, 0, 0, 1, 1); - - token_label = gtk_label_new("Access token will be displayed here."); - gtk_grid_attach(GTK_GRID(grid), token_label, 0, 1, 1, 1); - - gtk_widget_show_all(window); - - initialize_goa(); -} - -int main(int argc, char **argv) { - GtkApplication *app; - int status; - - app = gtk_application_new("org.example.OAuth", G_APPLICATION_DEFAULT_FLAGS); - g_signal_connect(app, "activate", G_CALLBACK(activate), NULL); - status = g_application_run(G_APPLICATION(app), argc, argv); - g_object_unref(app); - - return status; -} - From 0e2fee0aab411741ae36fb529bdf88b1fe2e7442 Mon Sep 17 00:00:00 2001 From: Shivam Sharma <56030049+shivamsharma2509@users.noreply.github.com> Date: Tue, 29 Oct 2024 14:09:43 +0530 Subject: [PATCH 4/7] Delete src/Auth.c --- src/Auth.c | 287 ----------------------------------------------------- 1 file changed, 287 deletions(-) delete mode 100644 src/Auth.c diff --git a/src/Auth.c b/src/Auth.c deleted file mode 100644 index 32077a1..0000000 --- a/src/Auth.c +++ /dev/null @@ -1,287 +0,0 @@ -#define GOA_API_IS_SUBJECT_TO_CHANGE - -#include "auth.h" -#include -#include -#include - -#include -#include -#include -#include -#include - -#define PORT 8080 -#define AUTHORIZATION_URL "https://github.com/login/oauth/authorize" -#define TOKEN_URL "https://github.com/login/oauth/access_token" - -/* Global variables */ - -static gchar *auth_code = NULL; -static GoaClient *client; -GtkWidget *token_label; - -/* Function to load configuration from file */ - -void load_config(char **client_id, char **client_secret) { - - FILE *file = fopen("config.cfg", "r"); - if (file == NULL) { - g_error("Could not open config.cfg file"); - return; - } - - char line[256]; - while (fgets(line, sizeof(line), file)) { - - char *key = strtok(line, "="); - char *value = strtok(NULL, "\n"); - - if (key != NULL && value != NULL) { - if (strcmp(key, "CLIENT_ID") == 0) { - *client_id = g_strdup(value); - g_print("Loaded CLIENT_ID: %s\n", *client_id); - } - - else if (strcmp(key, "CLIENT_SECRET") == 0) { - *client_secret = g_strdup(value); - g_print("Loaded CLIENT_SECRET: %s\n", *client_secret); - } - } - - else { - g_warning("Malformed line in config.cfg: %s", line); - } - } - - fclose(file); - - if (*client_id == NULL || *client_secret == NULL) { - g_error("Client ID or Client Secret not found in config.cfg"); - } -} - -/* Function to handle writing data received from curl */ - -size_t write_callback(void *ptr, size_t size, size_t nmemb, char **data) { - size_t realsize = size * nmemb; - *data = strndup(ptr, realsize); // Duplicate the data received - return realsize; -} - -/* Function to handle HTTP requests */ - -static enum MHD_Result handle_request(void *cls, struct MHD_Connection *connection, - const char *url, const char *method, - const char *version, const char *upload_data, - size_t *upload_data_size, void **con_cls) { - g_print("Received request for URL: %s with method: %s\n", url, method); - - if (strcmp(url, "/callback") == 0) { - - if (strcmp(method, "GET") == 0) { - - const char *code = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "code"); - - if (code) { - auth_code = g_strdup(code); - g_print("Authorization code received: %s\n", auth_code); - - char *client_id = NULL; - char *client_secret = NULL; - - load_config(&client_id, &client_secret); - - if (client_id == NULL || client_secret == NULL) { - g_error("Client ID or Client Secret is NULL. Check config.cfg file."); - } - - /* Exchange authorization code for access token using libcurl */ - - CURL *curl; - CURLcode res; - - curl_global_init(CURL_GLOBAL_DEFAULT); - curl = curl_easy_init(); - - if (curl) { - struct curl_slist *headers = NULL; - headers = curl_slist_append(headers, "Accept: application/json"); - - curl_easy_setopt(curl, CURLOPT_URL, TOKEN_URL); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - curl_easy_setopt(curl, CURLOPT_POST, 1L); - - gchar *post_data = g_strdup_printf("client_id=%s&client_secret=%s&code=%s", - client_id, client_secret, auth_code); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data); - - char *response = NULL; - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); - - res = curl_easy_perform(curl); - - if (res != CURLE_OK) { - g_warning("curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); - } - - else { - g_print("Response: %s\n", response); - - /* Parse JSON response to extract the access token */ - - json_object *json_response = json_tokener_parse(response); - json_object *json_access_token; - - if (json_object_object_get_ex(json_response, "access_token", &json_access_token)) { - - const char *access_token = json_object_get_string(json_access_token); - g_print("Access Token: %s\n", access_token); - gtk_label_set_text(GTK_LABEL(token_label), access_token); - - /* Save the access token to a file */ - - FILE *token_file = fopen("access_token.txt", "w"); - - if (token_file) { - fprintf(token_file, "%s\n", access_token); - fclose(token_file); - } - else { - g_warning("Failed to open access_token.txt for writing."); - } - } - else { - g_warning("Failed to extract access token from response."); - gtk_label_set_text(GTK_LABEL(token_label), "Failed to extract access token."); - } - - json_object_put(json_response); // free json object - } - - g_free(post_data); - curl_easy_cleanup(curl); - if (response) { - free(response); - } - } - curl_global_cleanup(); - - g_free(client_id); - g_free(client_secret); - } - - const char *response_html = "

Authentication successful! You can close this window.

"; - struct MHD_Response *response_obj = MHD_create_response_from_buffer(strlen(response_html), (void *)response_html, MHD_RESPMEM_PERSISTENT); - - int ret = MHD_queue_response(connection, MHD_HTTP_OK, response_obj); - MHD_destroy_response(response_obj); - return ret; - } - } - - return MHD_NO; -} - -/* Function to start the local server */ - -void start_local_server() { - struct MHD_Daemon *daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, PORT, NULL, NULL, &handle_request, NULL, MHD_OPTION_END); - - if (daemon == NULL) { - g_error("Failed to start local server."); - } - g_print("Local server started on port %d\n", PORT); -} - -/* Function to start the OAuth2 flow */ - -void start_oauth_flow() { - char *client_id = NULL; - char *client_secret = NULL; - load_config(&client_id, &client_secret); - - if (client_id == NULL) { - g_error("Client ID is NULL. Check config.cfg file."); - } - - gchar *auth_url = g_strdup_printf( - "%s?client_id=%s&redirect_uri=http://localhost:8080/callback&scope=user", - AUTHORIZATION_URL, client_id); - - g_print("Visit the following URL to authorize the application:\n%s\n", auth_url); - - /* Open the URL in the default browser */ - - gchar *command = g_strdup_printf("xdg-open '%s'", auth_url); - system(command); - g_free(command); - - g_free(auth_url); - g_free(client_id); - g_free(client_secret); -} - -/* Callback when the GoaClient is ready */ - -void on_goa_ready(GObject *source_object, GAsyncResult *res, gpointer user_data) { - GError *error = NULL; - client = goa_client_new_finish(res, &error); - - if (error) { - g_warning("Failed to initialize GoaClient: %s", error->message); - g_error_free(error); - return; - } - - g_print("GoaClient initialized successfully.\n"); -} - -/* Initialize the GoaClient */ - -void initialize_goa() { - goa_client_new(NULL, on_goa_ready, NULL); -} - -/* Main function */ - -int main(int argc, char *argv[]) { - gtk_init(&argc, &argv); - - /* Create a simple GTK window */ - - GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_title(GTK_WINDOW(window), "OAuth2 Authentication"); - gtk_window_set_default_size(GTK_WINDOW(window), 400, 200); - - /* Create a label to display the access token */ - - token_label = gtk_label_new("No token received yet."); - - /* Create an "Authenticate" button */ - - GtkWidget *auth_button = gtk_button_new_with_label("Authenticate"); - g_signal_connect(auth_button, "clicked", G_CALLBACK(start_oauth_flow), NULL); - - /* Create a vertical box to hold the label and button */ - - GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); - gtk_box_pack_start(GTK_BOX(vbox), token_label, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(vbox), auth_button, TRUE, TRUE, 0); - - gtk_container_add(GTK_CONTAINER(window), vbox); - - g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); - - /* Initialize the GoaClient and start the local server */ - - initialize_goa(); - start_local_server(); - - gtk_widget_show_all(window); - gtk_main(); - - return 0; -} - From b8c0b07df8f4fa5b972b2edec06a0a0dd80818e4 Mon Sep 17 00:00:00 2001 From: Shivam Sharma <56030049+shivamsharma2509@users.noreply.github.com> Date: Tue, 29 Oct 2024 14:53:38 +0530 Subject: [PATCH 5/7] Add files via upload --- src/Auth.c | 275 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 src/Auth.c diff --git a/src/Auth.c b/src/Auth.c new file mode 100644 index 0000000..f82e774 --- /dev/null +++ b/src/Auth.c @@ -0,0 +1,275 @@ +#define GOA_API_IS_SUBJECT_TO_CHANGE + +#include "auth.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define PORT 8080 +#define AUTHORIZATION_URL "https://github.com/login/oauth/authorize" +#define TOKEN_URL "https://github.com/login/oauth/access_token" +#define TOKEN_FILE "access_token.txt" + +/* Global variables */ + +static gchar *auth_code = NULL; +static GoaClient *client; +GtkWidget *token_label; + +/* Function to load configuration from file */ + +void load_config(char **client_id, char **client_secret) { + FILE *file = fopen("config.cfg", "r"); + if (file == NULL) { + g_error("Could not open config.cfg file"); + return; + } + + char line[256]; + while (fgets(line, sizeof(line), file)) { + char *key = strtok(line, "="); + char *value = strtok(NULL, "\n"); + + if (key != NULL && value != NULL) { + if (strcmp(key, "CLIENT_ID") == 0) { + *client_id = g_strdup(value); + g_print("Loaded CLIENT_ID: %s\n", *client_id); + } else if (strcmp(key, "CLIENT_SECRET") == 0) { + *client_secret = g_strdup(value); + g_print("Loaded CLIENT_SECRET: %s\n", *client_secret); + } + } else { + g_warning("Malformed line in config.cfg: %s", line); + } + } + + fclose(file); + + if (*client_id == NULL || *client_secret == NULL) { + g_error("Client ID or Client Secret not found in config.cfg"); + } +} + +/* Function to handle writing data received from curl */ + +size_t write_callback(void *ptr, size_t size, size_t nmemb, char **data) { + size_t realsize = size * nmemb; + *data = strndup(ptr, realsize); // Duplicate the data received + return realsize; +} + +/* Function to handle HTTP requests */ + +static enum MHD_Result handle_request(void *cls, struct MHD_Connection *connection, + const char *url, const char *method, + const char *version, const char *upload_data, + size_t *upload_data_size, void **con_cls) { + g_print("Received request for URL: %s with method: %s\n", url, method); + + if (strcmp(url, "/callback") == 0) { + if (strcmp(method, "GET") == 0) { + const char *code = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "code"); + + if (code) { + auth_code = g_strdup(code); + g_print("Authorization code received: %s\n", auth_code); + + char *client_id = NULL; + char *client_secret = NULL; + load_config(&client_id, &client_secret); + + if (client_id == NULL || client_secret == NULL) { + g_error("Client ID or Client Secret is NULL. Check config.cfg file."); + } + + /* Exchange authorization code for access token using libcurl */ + + CURL *curl; + CURLcode res; + + curl_global_init(CURL_GLOBAL_DEFAULT); + curl = curl_easy_init(); + if (curl) { + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers, "Accept: application/json"); + + curl_easy_setopt(curl, CURLOPT_URL, TOKEN_URL); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl, CURLOPT_POST, 1L); + + gchar *post_data = g_strdup_printf("client_id=%s&client_secret=%s&code=%s", + client_id, client_secret, auth_code); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data); + + char *response = NULL; + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); + + res = curl_easy_perform(curl); + if (res != CURLE_OK) { + g_warning("curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); + } + else { + g_print("Response: %s\n", response); + + /* Parse JSON response to extract the access token */ + + json_object *json_response = json_tokener_parse(response); + json_object *json_access_token; + + if (json_object_object_get_ex(json_response, "access_token", &json_access_token)) { + const char *access_token = json_object_get_string(json_access_token); + g_print("Access Token: %s\n", access_token); + gtk_label_set_text(GTK_LABEL(token_label), access_token); + + /* Save the access token to a file with restricted permissions */ + + FILE *token_file = fopen(TOKEN_FILE, "w"); + if (token_file) { + fprintf(token_file, "%s\n", access_token); + fclose(token_file); + if (chmod(TOKEN_FILE, S_IRUSR | S_IWUSR) < 0) { + g_warning("Failed to set file permissions for %s", TOKEN_FILE); + } + } + else { + g_warning("Failed to open %s for writing.", TOKEN_FILE); + } + } + else { + g_warning("Failed to extract access token from response."); + gtk_label_set_text(GTK_LABEL(token_label), "Failed to extract access token."); + } + json_object_put(json_response); // free json object + } + + g_free(post_data); + curl_easy_cleanup(curl); + if (response) { + free(response); + } + } + curl_global_cleanup(); + + g_free(client_id); + g_free(client_secret); + } + + const char *response_html = "

Authentication successful! You can close this window.
Happy Printing!!

"; + struct MHD_Response *response_obj = MHD_create_response_from_buffer(strlen(response_html), (void *)response_html, MHD_RESPMEM_PERSISTENT); + int ret = MHD_queue_response(connection, MHD_HTTP_OK, response_obj); + MHD_destroy_response(response_obj); + return ret; + } + } + + return MHD_NO; +} + +/* Function to start the local server */ + +void start_local_server() { + struct MHD_Daemon *daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, PORT, NULL, NULL, &handle_request, NULL, MHD_OPTION_END); + if (daemon == NULL) { + g_error("Failed to start local server."); + } + g_print("Local server started on port %d\n", PORT); +} + +/* Function to start the OAuth2 flow */ + +void start_oauth_flow() { + char *client_id = NULL; + char *client_secret = NULL; + load_config(&client_id, &client_secret); + + if (client_id == NULL) { + g_error("Client ID is NULL. Check config.cfg file."); + } + + gchar *auth_url = g_strdup_printf( + "%s?client_id=%s&redirect_uri=http://localhost:%d/callback&scope=user", + AUTHORIZATION_URL, client_id, PORT); + + g_print("Visit the following URL to authorize the application:\n%s\n", auth_url); + + /* Open the URL in the default browser */ + + gchar *command = g_strdup_printf("xdg-open '%s'", auth_url); + system(command); + g_free(command); + + g_free(auth_url); + g_free(client_id); + g_free(client_secret); +} + +/* Callback when the GoaClient is ready */ + +void on_goa_ready(GObject *source_object, GAsyncResult *res, gpointer user_data) { + GError *error = NULL; + client = goa_client_new_finish(res, &error); + + if (error) { + g_warning("Failed to initialize GoaClient: %s", error->message); + g_error_free(error); + return; + } + + g_print("GoaClient initialized successfully.\n"); +} + +/* Initialize the GoaClient */ + +void initialize_goa() { + goa_client_new(NULL, on_goa_ready, NULL); +} + +/* Main function */ + +int main(int argc, char *argv[]) { + gtk_init(&argc, &argv); + + /* Create a simple GTK window */ + + GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(window), "OAuth2 Authentication"); + gtk_window_set_default_size(GTK_WINDOW(window), 400, 200); + + /* Create a label to display the access token */ + + token_label = gtk_label_new("No token received yet."); + + /* Create an "Authenticate" button */ + GtkWidget *auth_button = gtk_button_new_with_label("Authenticate"); + g_signal_connect(auth_button, "clicked", G_CALLBACK(start_oauth_flow), NULL); + + /* Create a vertical box to hold the label and button */ + + GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); + gtk_box_pack_start(GTK_BOX(vbox), token_label, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox), auth_button, TRUE, TRUE, 0); + + gtk_container_add(GTK_CONTAINER(window), vbox); + + g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); + + /* Initialize the GoaClient and start the local server */ + + initialize_goa(); + start_local_server(); + + gtk_widget_show_all(window); + gtk_main(); + + return 0; +} + From e70bb311f6e36ea14d4b4004150ee051fe918f45 Mon Sep 17 00:00:00 2001 From: Shivam Sharma <56030049+shivamsharma2509@users.noreply.github.com> Date: Tue, 29 Oct 2024 14:57:50 +0530 Subject: [PATCH 6/7] Update Makefile.am --- src/Makefile.am | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Makefile.am b/src/Makefile.am index 47839d3..fe41fc9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -20,6 +20,7 @@ cups_SOURCES = \ print_backend_cups.c \ backend_helper.c backend_helper.h \ cups-notifier.c cups-notifier.h + Auth.c auth.h cups_CPPFLAGS = $(CPDB_CFLAGS) cups_CPPFLAGS += $(LIBCUPSFILTERS_CFLAGS) cups_CPPFLAGS += $(GLIB_CFLAGS) @@ -32,6 +33,7 @@ cups_LDADD += $(LIBCUPSFILTERS_LIBS) cups_LDADD += $(GLIB_LIBS) cups_LDADD += $(GIO_LIBS) cups_LDADD += $(GIOUNIX_LIBS) +cups_LDADD += -lcurl -ljson-c # ================================ # Tests ("make test"/"make check") From c922e1f123610941c3c14096b51dc95e8d9b53a7 Mon Sep 17 00:00:00 2001 From: Shivam Sharma <56030049+shivamsharma2509@users.noreply.github.com> Date: Tue, 29 Oct 2024 15:02:35 +0530 Subject: [PATCH 7/7] Update print_backend_cups.c --- src/print_backend_cups.c | 48 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/print_backend_cups.c b/src/print_backend_cups.c index 57cbde6..3f625e1 100644 --- a/src/print_backend_cups.c +++ b/src/print_backend_cups.c @@ -1,3 +1,9 @@ +#define GOA_API_IS_SUBJECT_TO_CHANGE + +#include "auth.h" +#include +#include + #include #include #include @@ -496,6 +502,25 @@ static gboolean on_handle_ping(PrintBackend *interface, return TRUE; } +static gboolean send_print_job_with_token(PrinterCUPS *printer, + const gchar *printer_id, + int num_settings, + GVariant *settings, + const gchar *title, + const char *access_token, + char *jobid_out, + char *socket_out) +{ + if(!access_token){ + g_warning("No access token available. Authentication is required."); + return FALSE; + } + + print_socket(printer, num_settings, settings, jobid_out, socket_out, title); + g_message("Print job sent successfully."); + + return TRUE; +} static gboolean on_handle_print_socket(PrintBackend *interface, GDBusMethodInvocation *invocation, const gchar *printer_id, @@ -506,18 +531,41 @@ static gboolean on_handle_print_socket(PrintBackend *interface, { const char *dialog_name = g_dbus_method_invocation_get_sender(invocation); PrinterCUPS *p = get_printer_by_name(b, dialog_name, printer_id); + + if(!p){ + g_dbus_method_invocation_return_error(invocation, G_IO_ERROR, G_IO_ERROR_FAILED, "Printer not found"); + return FALSE; + } + + /* Call OAuth function to retrieve access token */ + char *access_token = get_access_token(); + if(!access_token){ + g_dbus_method_invocation_return_error(invocation, G_IO_ERROR, G_IO_ERROR_FAILED, "Authentication required"); + return FALSE; + } // Call the renamed function char jobid[32]; char socket[256]; print_socket(p, num_settings, settings, jobid, socket, title); + + gboolean success = send_print_job_with_token(p, printer_id, num_settings, settings, title, access_token, jobid, socket); + if(!success){ + g_dbus_method_invocation_return_error(invocation, G_IO_ERROR, G_IO_ERROR_FAILED, "Failed to send print job."); + g_free(access_token); + return FALSE; + } // Complete the D-Bus method call with the result print_backend_complete_print_socket(interface, invocation, jobid, socket); + + //Free access token if dynamically allocated + g_free(access_token); return TRUE; } + static gboolean on_handle_get_all_options(PrintBackend *interface, GDBusMethodInvocation *invocation, const gchar *printer_name,