// SPDX-License-Identifier: GPL-3.0-or-later
#include "aclk_otp.h"
#include "aclk_util.h"
#include "aclk.h"
#include "daemon/common.h"
#include "mqtt_websockets/c-rbuf/include/ringbuffer.h"
static int aclk_https_request(https_req_t *request, https_req_response_t *response) {
int rc;
// wrapper for ACLK only which loads ACLK specific proxy settings
// then only calls https_request
struct mqtt_wss_proxy proxy_conf = { .host = NULL, .port = 0, .type = MQTT_WSS_DIRECT };
aclk_set_proxy((char**)&proxy_conf.host, &proxy_conf.port, &proxy_conf.type);
if (proxy_conf.type == MQTT_WSS_PROXY_HTTP) {
request->proxy_host = (char*)proxy_conf.host; // TODO make it const as well
request->proxy_port = proxy_conf.port;
}
rc = https_request(request, response);
freez((char*)proxy_conf.host);
return rc;
}
struct auth_data {
char *client_id;
char *username;
char *passwd;
};
#define PARSE_ENV_JSON_CHK_TYPE(it, type, name) \
if (json_object_get_type(json_object_iter_peek_value(it)) != type) { \
error("value of key \"%s\" should be %s", name, #type); \
goto exit; \
}
#define JSON_KEY_CLIENTID "clientID"
#define JSON_KEY_USER "username"
#define JSON_KEY_PASS "password"
#define JSON_KEY_TOPICS "topics"
static int parse_passwd_response(const char *json_str, struct auth_data *auth) {
int rc = 1;
json_object *json;
struct json_object_iterator it;
struct json_object_iterator itEnd;
json = json_tokener_parse(json_str);
if (!json) {
error("JSON-C failed to parse the payload of http response of /env endpoint");
return 1;
}
it = json_object_iter_begin(json);
itEnd = json_object_iter_end(json);
while (!json_object_iter_equal(&it, &itEnd)) {
if (!strcmp(json_object_iter_peek_name(&it), JSON_KEY_CLIENTID)) {
PARSE_ENV_JSON_CHK_TYPE(&it, json_type_string, JSON_KEY_CLIENTID)
auth->client_id = strdupz(json_object_get_string(json_object_iter_peek_value(&it)));
json_object_iter_next(&it);
continue;
}
if (!strcmp(json_object_iter_peek_name(&it), JSON_KEY_USER)) {
PARSE_ENV_JSON_CHK_TYPE(&it, json_type_string, JSON_KEY_USER)
auth->username = strdupz(json_object_get_string(json_object_iter_peek_value(&it)));
json_object_iter_next(&it);
continue;
}
if (!strcmp(json_object_iter_peek_name(&it), JSON_KEY_PASS)) {
PARSE_ENV_JSON_CHK_TYPE(&it, json_type_string, JSON_KEY_PASS)
auth->passwd = strdupz(json_object_get_string(json_object_iter_peek_value(&it)));
json_object_iter_next(&it);
continue;
}
if (!strcmp(json_object_iter_peek_name(&it), JSON_KEY_TOPICS)) {
PARSE_ENV_JSON_CHK_TYPE(&it, json_type_array, JSON_KEY_TOPICS)
if (aclk_generate_topic_cache(json_object_iter_peek_value(&it))) {
error("Failed to generate topic cache!");
goto exit;
}
json_object_iter_next(&it);
continue;
}
error("Unknown key \"%s\" in passwd response payload. Ignoring", json_object_iter_peek_name(&it));
json_object_iter_next(&it);
}
if (!auth->client_id) {
error(JSON_KEY_CLIENTID " is compulsory key in /password response");
goto exit;
}
if (!auth->passwd) {
error(JSON_KEY_PASS " is compulsory in /password response");
goto exit;
}
if (!auth->username) {
error(JSON_KEY_USER " is compulsory in /password response");
goto exit;
}
rc = 0;
exit:
json_object_put(json);
return rc;
}
#define JSON_KEY_ERTRY "errorNonRetryable"
#define JSON_KEY_EDELAY "errorRetryDelaySeconds"
#define JSON_KEY_EEC "errorCode"
#define JSON_KEY_EMSGKEY "errorMsgKey"
#define JSON_KEY_EMSG "errorMessage"
#if JSON_C_MINOR_VERSION >= 13
static const char *get_json_str_by_path(json_object *json, const char *path) {
json_object *ptr;
if (json_pointer_get(json, path, &ptr)) {
error("Missing compulsory key \"%s\" in error response", path);
return NULL;
}
if (json_object_get_type(ptr) != json_type_string) {
error("Value of Key \"%s\" in error response should be string", path);
return NULL;
}
return json_object_get_string(ptr);
}
static int aclk_parse_otp_error(const char *json_str) {
int rc = 1;
json_object *json, *ptr;
const char *ec;
const char *ek;
const char *emsg;
int block_retry