#define _POSIX_C_SOURCE 200809L #include #include #include #include #include #include "string-util.h" #include "auth.h" #include "http.h" #include "config.h" #include "log.h" #define CLIENT_NAME "ap_client" #define PROTOCOL_PREFIX "https://" static const char *app_register_url = "/api/v1/apps"; static const char *login_url = "/oauth/token"; int read_local_credentials() { if (!(config->access_token) || !*(config->access_token) || !(config->instance_url) || !*(config->instance_url)) { log_msg(LOG_ERROR, "read_local_credentials", "access_token not found"); return -1; } printf("token: %s\niu: %s\n", config->access_token, config->instance_url); return 0; } bool is_logged_in() { if (config->access_token) return true; return false; } const char *get_access_token() { return (const char *)config->access_token; } const char *get_instance_url() { return (const char *)config->instance_url; } struct register_call_arg { char *url; char *domain; char *post_data; void (*callback)(bool); }; static void *register_call(void *req_arg) { struct register_call_arg *arg; char *resp; json_t *root; arg = (struct register_call_arg *)req_arg; if (!arg || !(arg->url)) { log_msg(LOG_ERROR, "register_call", "invalid arguments"); goto error; } resp = post_request(arg->url, arg->post_data); if (!resp) { log_msg(LOG_ERROR, "register_call", "failed to send http request"); goto error; } if (!resp) { log_msg(LOG_ERROR, "register_call", "null response"); goto error; } root = json_loads(resp, 0, NULL); if (!root) { log_msg(LOG_ERROR, "register_call", "failed to parse json"); goto error; } if (!json_is_object(root)) { log_msg(LOG_ERROR, "register_call", "json root is not object"); goto error; } json_t *cid = json_object_get(root, "client_id"); json_t *csec = json_object_get(root, "client_secret"); if (!json_is_string(cid) || !json_is_string(csec)) { log_msg(LOG_ERROR, "register_call", "invalid client_id or client_secret"); goto error; } config_set_client_id(json_string_value(cid)); config_set_client_secret(json_string_value(csec)); config_set_instance_url(arg->domain); if (!*(config->client_id) || !*(config->client_secret)) { log_msg(LOG_ERROR, "register_call", "invalid client_id or client_secret"); goto error; } free(arg->url); if (arg->post_data) free(arg->post_data); free(arg); free(resp); json_decref(root); (*(arg->callback))(true); return NULL; error: if (arg) { if (arg->url) free(arg->url); if (arg->post_data) free(arg->post_data); free(arg); } if (resp) free(resp); if (root) json_decref(root); (*(arg->callback))(false); return NULL; } int register_app(const char *instance, void (*callback)(bool success)) { size_t size; char *instance_prefix; char *url, *req_data; struct register_call_arg *arg; json_t *root; json_error_t error; pthread_t t; if (!instance || strlen(instance) < 1 || !callback) { log_msg(LOG_ERROR, "register_app", "invalid argument"); return -1; } size = sizeof(PROTOCOL_PREFIX) + sizeof(instance) + 1; instance_prefix = malloc(size); if (!instance_prefix) { err(1, NULL); return -1; } strlcpy(instance_prefix, PROTOCOL_PREFIX, size); strlcat(instance_prefix, instance, size); root = json_pack_ex(&error, 1, "{s:s, s:s, s:s}", "client_name", CLIENT_NAME, "redirect_uris", "urn:ietf:wg:oauth:2.0:oob", "scopes", "read write push"); if (!root) { log_msg(LOG_ERROR, "register_app", "json pack error: line %d: %s", error.line, error.text); return -1; } req_data = json_dumps(root, 0); json_decref(root); if (!req_data) { log_msg(LOG_ERROR, "register_app", "failed to dump json"); return -1; } size = strlen(instance_prefix) + strlen(app_register_url) + 1; url = malloc(size); if (!url) { err(1, NULL); return -1; } strlcpy(url, instance_prefix, size); strlcat(url, app_register_url, size); arg = calloc(1, sizeof(struct register_call_arg)); if (!arg) { err(1, NULL); return -1; } arg->url = url; arg->domain = instance_prefix; arg->post_data = req_data; arg->callback = callback; return pthread_create(&t, NULL, ®ister_call, arg); } struct login_call_arg { char *url; char *post_data; void (*callback)(bool); }; static void *login_call(void *req_arg) { struct login_call_arg *arg = NULL; char *resp = NULL; json_t *root = NULL; arg = (struct login_call_arg *)req_arg; if (!arg || !(arg->url)) { log_msg(LOG_ERROR, "login_call", "invalid arguments"); goto error; } resp = post_request(arg->url, arg->post_data); if (!resp) { log_msg(LOG_ERROR, "login_call", "failed to send http request"); goto error; } if (!resp) { log_msg(LOG_ERROR, "login_call", "null response"); goto error; } root = json_loads(resp, 0, NULL); if (!root) { log_msg(LOG_ERROR, "login_call", "failed to parse json"); goto error; } if (!json_is_object(root)) { log_msg(LOG_ERROR, "login_call", "json root is not object"); goto error; } json_t *access_token_j = json_object_get(root, "access_token"); json_t *scope_j = json_object_get(root, "scope"); if (!json_is_string(access_token_j) || !json_is_string(scope_j) || strlen(json_string_value(access_token_j)) < 1 || strlen(json_string_value(scope_j)) < 1) { log_msg(LOG_ERROR, "login_call", "invalid access_token or scope"); goto error; } config_set_access_token(json_string_value(access_token_j)); /* scope = strdup(json_string_value(scope_j)); */ if (config_save()) { log_msg(LOG_ERROR, "login_call", "failed to save config"); goto error; } free(arg->url); if (arg->post_data) free(arg->post_data); free(arg); free(resp); json_decref(root); (*(arg->callback))(true); printf("access_token: %s", config->access_token); return NULL; error: if (arg) { if (arg->url) free(arg->url); if (arg->post_data) free(arg->post_data); free(arg); } if (resp) free(resp); if (root) json_decref(root); (*(arg->callback))(false); return NULL; } int login( const char *email, const char *password, void (*callback)(bool success)) { json_t *root; json_error_t error; pthread_t t; size_t size; char *url, *req_data; struct login_call_arg *arg; if (!email || strlen(email) < 1 || !password || strlen(password) < 1) { log_msg(LOG_ERROR, "login", "invalid argument"); return -1; } if (!(config->client_id) || !*(config->client_id) || !(config->client_secret) || !*(config->client_secret) || !(config->instance_url) || !*(config->instance_url)) { log_msg(LOG_ERROR, "login", "invalid client_id or client_secret"); return -1; } root = json_pack_ex(&error, 1, "{s:s, s:s, s:s, s:s, s:s}", "client_id", config->client_id, "client_secret", config->client_secret, "grant_type", "password", "username", email, "password", password); if (!root) { log_msg(LOG_ERROR, "login", "json pack error: line %d: %s", error.line, error.text); return -1; } req_data = json_dumps(root, 0); json_decref(root); if (!req_data) { log_msg(LOG_ERROR, "login", "failed to dump json"); return -1; } size = strlen(config->instance_url) + strlen(login_url) + 1; url = malloc(size); if (!url) { err(1, NULL); return -1; } strlcpy(url, config->instance_url, size); strlcat(url, login_url, size); arg = calloc(1, sizeof(struct login_call_arg)); if (!arg) { err(1, NULL); return -1; } arg->url = url; arg->post_data = req_data; arg->callback = callback; return pthread_create(&t, NULL, &login_call, arg); }