Add api_cmd_encrypt and use in api_init_encrypt

This commit is contained in:
x3 2022-01-09 19:32:13 +01:00
parent 6cf62ab039
commit 605f47f761
Signed by: x3
GPG Key ID: 7E9961E8AD0E240E
3 changed files with 89 additions and 36 deletions

View File

@ -34,7 +34,6 @@ make
- Make deleting from mylist possible, with - Make deleting from mylist possible, with
- Name regexes, - Name regexes,
- If file is not found at a scan - If file is not found at a scan
- Use api\_cmd style in api\_encrypt\_init
- Buffer up mylistadd api cmds when waiting for ratelimit - Buffer up mylistadd api cmds when waiting for ratelimit
- Handle C-c gracefully at any time - Handle C-c gracefully at any time
- Write -h page, and maybe a man page too - Write -h page, and maybe a man page too

116
src/api.c
View File

@ -44,6 +44,7 @@
static enum error api_cmd_logout(struct api_result *res); static enum error api_cmd_logout(struct api_result *res);
static enum error api_cmd_auth(const char *uname, const char *pass, static enum error api_cmd_auth(const char *uname, const char *pass,
struct api_result *res); struct api_result *res);
static enum error api_cmd_encrypt(const char *uname, struct api_result *res);
static bool api_authed = false; static bool api_authed = false;
static char api_session[API_SMAXSIZE] = {0}; /* No escaping is needed */ static char api_session[API_SMAXSIZE] = {0}; /* No escaping is needed */
@ -94,41 +95,44 @@ static int api_escaped_sring_info(const struct printf_info *info, size_t n,
static enum error api_init_encrypt(const char *api_key, const char *uname) static enum error api_init_encrypt(const char *api_key, const char *uname)
{ {
char buffer[API_BUFSIZE];
MD5Context md5_ctx; MD5Context md5_ctx;
char *salt_start = buffer + 4 /* 209 [salt here] ... */, *salt_end; struct api_result res;
ssize_t r_len, salt_len; enum error err;
size_t salt_len;
if (net_send(buffer, snprintf(buffer, sizeof(buffer), if (api_cmd_encrypt(uname, &res) != NOERR)
"ENCRYPT user=%s&type=1", uname)) == -1) {
return ERR_API_COMMFAIL;
}
r_len = net_read(buffer, sizeof(buffer));
if (strncmp(buffer, "209", 3) != 0) {
uio_error("We expected 209 response, but got: %.*s",
(int)r_len, buffer);
return ERR_API_ENCRYPTFAIL; return ERR_API_ENCRYPTFAIL;
}
salt_end = strchr(salt_start, ' '); if (res.code != 209) {
if (!salt_end) { err = ERR_API_ENCRYPTFAIL;
uio_error("Cannot find space after salt in response"); switch (res.code) {
return ERR_API_ENCRYPTFAIL; case 309:
uio_error("You'r API key is not defined. Define it here: "
"http://anidb.net/perl-bin/animedb.pl?show=profile");
break;
case 509:
uio_error("No such encryption type. Maybe client is outdated?");
break;
case 394:
uio_error("No user with name: '%s' found by AniDB", uname);
break;
default:
uio_error("Unknown encrypt failure: %ld", res.code);
}
return err;
} }
salt_len = salt_end - salt_start; salt_len = strlen(res.encrypt.salt);
md5Init(&md5_ctx); md5Init(&md5_ctx);
md5Update(&md5_ctx, (uint8_t*)api_key, strlen(api_key)); md5Update(&md5_ctx, (uint8_t*)api_key, strlen(api_key));
md5Update(&md5_ctx, (uint8_t*)salt_start, salt_len); md5Update(&md5_ctx, (uint8_t*)res.encrypt.salt, salt_len);
md5Finalize(&md5_ctx); md5Finalize(&md5_ctx);
memcpy(e_key, md5_ctx.digest, sizeof(e_key)); memcpy(e_key, md5_ctx.digest, sizeof(e_key));
#if 1 #if 1
char *buffpos = buffer; char bf[sizeof(e_key) * 2 + 1];
for (int i = 0; i < 16; i++) util_byte2hex(e_key, sizeof(e_key), false, bf);
buffpos += sprintf(buffpos, "%02x", e_key[i]); uio_debug("Encryption key is: '%s'", bf);
uio_debug("Encryption key is: '%s'", buffer);
#endif #endif
api_encryption = true; api_encryption = true;
@ -497,11 +501,11 @@ static ssize_t api_send(char *buffer, size_t data_len, size_t buf_size)
read_len = net_read(buffer, buf_size); read_len = net_read(buffer, buf_size);
if (read_len < 0) { if (read_len < 0) {
uio_error("!!! BAD PLACE EINTR !!! report pls"); uio_error("!!! BAD PLACE EINTR !!! report pls");
return en; /* This could lead so some problems if we also want to return read_len; /* This could lead so some problems if we also want to
log out. If we hit this, the msg got sent, but we log out. If we hit this, the msg got sent, but we
couldn't read the response. That means, in the couldn't read the response. That means, in the
logout call, this msg's data will be read logout call, this msg's data will be read
Let's see if this ever comes up */ Let's see if this ever comes up */
} }
api_ratelimit_sent(); api_ratelimit_sent();
@ -573,10 +577,54 @@ static char *api_get_field_mod(char *buffer, int32_t field_num)
} }
#endif #endif
static enum error api_cmd_encrypt(const char *uname, struct api_result *res)
{
pthread_mutex_lock(&api_work_mx);
char buffer[API_BUFSIZE];
long code;
enum error err = NOERR;
/* Usernames can't contain '&' */
ssize_t res_len = api_send(buffer, snprintf(buffer, sizeof(buffer),
"ENCRYPT user=%s&type=1", uname),
sizeof(buffer));
if (res_len < 0) {
if (res_len == -2 && should_exit)
err = ERR_SHOULD_EXIT;
else
err = ERR_API_COMMFAIL;
goto end;
}
code = api_res_code(buffer);
if (code == -1) {
err = ERR_API_RESP_INVALID;
goto end;
}
if (code == 209) {
char *fs;
size_t fl;
bool gfl = api_get_field(buffer, 2, &fs, &fl);
assert(gfl);
(void)gfl;
assert(sizeof(res->encrypt.salt) > fl);
memcpy(res->encrypt.salt, fs, fl);
res->encrypt.salt[fl] = '\0';
}
res->code = (uint16_t)code;
end:
pthread_mutex_unlock(&api_work_mx);
return err;
}
enum error api_cmd_version(struct api_result *res) enum error api_cmd_version(struct api_result *res)
{ {
char buffer[API_BUFSIZE] = "VERSION"; char buffer[API_BUFSIZE] = "VERSION";
size_t res_len = api_send(buffer, strlen(buffer), sizeof(buffer)); ssize_t res_len = api_send(buffer, strlen(buffer), sizeof(buffer));
long code; long code;
enum error err = NOERR; enum error err = NOERR;
pthread_mutex_lock(&api_work_mx); pthread_mutex_lock(&api_work_mx);
@ -619,11 +667,11 @@ static enum error api_cmd_auth(const char *uname, const char *pass,
pthread_mutex_lock(&api_work_mx); pthread_mutex_lock(&api_work_mx);
char buffer[API_BUFSIZE]; char buffer[API_BUFSIZE];
long code; long code;
size_t res_len = api_send(buffer, snprintf(buffer, sizeof(buffer), enum error err = NOERR;
ssize_t res_len = api_send(buffer, snprintf(buffer, sizeof(buffer),
"AUTH user=%s&pass=%B&protover=" API_VERSION "&client=caniadd&" "AUTH user=%s&pass=%B&protover=" API_VERSION "&client=caniadd&"
"clientver=" PROG_VERSION "&enc=UTF-8", uname, pass), "clientver=" PROG_VERSION "&enc=UTF-8", uname, pass),
sizeof(buffer)); sizeof(buffer));
enum error err = NOERR;
if (res_len < 0) { if (res_len < 0) {
if (res_len == -2 && should_exit) if (res_len == -2 && should_exit)
@ -669,7 +717,7 @@ static enum error api_cmd_logout(struct api_result *res)
{ {
pthread_mutex_lock(&api_work_mx); pthread_mutex_lock(&api_work_mx);
char buffer[API_BUFSIZE]; char buffer[API_BUFSIZE];
size_t res_len = api_send(buffer, snprintf(buffer, sizeof(buffer), ssize_t res_len = api_send(buffer, snprintf(buffer, sizeof(buffer),
"LOGOUT s=%s", api_session), sizeof(buffer)); "LOGOUT s=%s", api_session), sizeof(buffer));
long code; long code;
enum error err = NOERR; enum error err = NOERR;
@ -702,7 +750,7 @@ enum error api_cmd_uptime(struct api_result *res)
if (!api_ka_now) if (!api_ka_now)
pthread_mutex_lock(&api_work_mx); pthread_mutex_lock(&api_work_mx);
char buffer[API_BUFSIZE]; char buffer[API_BUFSIZE];
size_t res_len = api_send(buffer, snprintf(buffer, sizeof(buffer), ssize_t res_len = api_send(buffer, snprintf(buffer, sizeof(buffer),
"UPTIME s=%s", api_session), sizeof(buffer)); "UPTIME s=%s", api_session), sizeof(buffer));
long code; long code;
enum error err = NOERR; enum error err = NOERR;
@ -744,7 +792,7 @@ enum error api_cmd_mylistadd(int64_t size, const uint8_t *hash,
{ {
char buffer[API_BUFSIZE]; char buffer[API_BUFSIZE];
char hash_str[ED2K_HASH_SIZE * 2 + 1]; char hash_str[ED2K_HASH_SIZE * 2 + 1];
size_t res_len; ssize_t res_len;
enum error err = NOERR; enum error err = NOERR;
long code; long code;
pthread_mutex_lock(&api_work_mx); pthread_mutex_lock(&api_work_mx);

View File

@ -11,9 +11,11 @@
#define API_BUFSIZE 1400 #define API_BUFSIZE 1400
/* Session key maximum size, including '\0' */ /* Session key maximum size, including '\0' */
#define API_SMAXSIZE 16 #define API_SMAXSIZE 16
/* Encryption salt maximum size, including '\0' */
#define API_SALTMAXSIZE 16
/* The session timeout in miliseconds */ /* The session timeout in miliseconds */
#define API_TIMEOUT 30 * 60 * 1000 #define API_TIMEOUT 30 * 60 * 1000
/* How many miliseconds to wait between sends */ /* How many miliseconds to wait between sends */
#define API_SENDWAIT 2 * 1000 #define API_SENDWAIT 2 * 1000
/* The number of packets that are exccempt from the ratelimit */ /* The number of packets that are exccempt from the ratelimit */
@ -54,6 +56,9 @@ struct api_auth_result {
char *banned_reason; char *banned_reason;
}; };
}; };
struct api_encrypt_result {
char salt[API_SALTMAXSIZE];
};
struct api_uptime_result { struct api_uptime_result {
int32_t ms; int32_t ms;
}; };
@ -78,6 +83,7 @@ struct api_result {
struct api_auth_result auth; struct api_auth_result auth;
struct api_uptime_result uptime; struct api_uptime_result uptime;
e(mylistadd); e(mylistadd);
e(encrypt);
}; };
}; };
#undef e #undef e