summaryrefslogtreecommitdiff
path: root/mastoapi.c
diff options
context:
space:
mode:
authorGravatar default2023-04-09 21:31:56 +0200
committerGravatar default2023-04-09 21:31:56 +0200
commitccce01d285874faa858b6dd639416ca2d014ad07 (patch)
treea3d5b8b6bcb2bf1e824b5da095c272469a3e3730 /mastoapi.c
parentOAuth login now works. (diff)
downloadsnac2-ccce01d285874faa858b6dd639416ca2d014ad07.tar.gz
snac2-ccce01d285874faa858b6dd639416ca2d014ad07.tar.xz
snac2-ccce01d285874faa858b6dd639416ca2d014ad07.zip
More mastoapi work.
Diffstat (limited to 'mastoapi.c')
-rw-r--r--mastoapi.c179
1 files changed, 162 insertions, 17 deletions
diff --git a/mastoapi.c b/mastoapi.c
index ddf29a7..b80d8c8 100644
--- a/mastoapi.c
+++ b/mastoapi.c
@@ -71,6 +71,56 @@ xs_dict *app_get(const char *id)
71} 71}
72 72
73 73
74int token_add(const char *id, const xs_dict *token)
75/* stores a token */
76{
77 int status = 201;
78 xs *fn = xs_fmt("%s/token/", srv_basedir);
79 FILE *f;
80
81 mkdirx(fn);
82 fn = xs_str_cat(fn, id);
83 fn = xs_str_cat(fn, ".json");
84
85 if ((f = fopen(fn, "w")) != NULL) {
86 xs *j = xs_json_dumps_pp(token, 4);
87 fwrite(j, strlen(j), 1, f);
88 fclose(f);
89 }
90 else
91 status = 500;
92
93 return status;
94}
95
96
97xs_dict *token_get(const char *id)
98/* gets a token */
99{
100 xs *fn = xs_fmt("%s/token/%s.json", srv_basedir, id);
101 xs_dict *token = NULL;
102 FILE *f;
103
104 if ((f = fopen(fn, "r")) != NULL) {
105 xs *j = xs_readall(f);
106 fclose(f);
107
108 token = xs_json_loads(j);
109 }
110
111 return token;
112}
113
114
115int token_del(const char *id)
116/* deletes a token */
117{
118 xs *fn = xs_fmt("%s/token/%s.json", srv_basedir, id);
119
120 return unlink(fn);
121}
122
123
74const char *login_page = "" 124const char *login_page = ""
75"<!DOCTYPE html>\n" 125"<!DOCTYPE html>\n"
76"<body><h1>%s OAuth identify</h1>\n" 126"<body><h1>%s OAuth identify</h1>\n"
@@ -176,7 +226,18 @@ int oauth_post_handler(const xs_dict *req, const char *q_path,
176 *body = xs_fmt("%s?code=%s", redir, code); 226 *body = xs_fmt("%s?code=%s", redir, code);
177 status = 303; 227 status = 303;
178 228
179 srv_debug(0, xs_fmt("oauth x-snac-login: redirect to %s", *body)); 229 srv_debug(0, xs_fmt("oauth x-snac-login: success, redirect to %s", *body));
230
231 /* assign the login to the app */
232 xs *app = app_get(cid);
233
234 if (app != NULL) {
235 app = xs_dict_set(app, "uid", login);
236 app = xs_dict_set(app, "code", code);
237 app_add(cid, app);
238 }
239 else
240 srv_log(xs_fmt("oauth x-snac-login: error getting app %s", cid));
180 } 241 }
181 else 242 else
182 srv_debug(0, xs_fmt("oauth x-snac-login: login '%s' incorrect", login)); 243 srv_debug(0, xs_fmt("oauth x-snac-login: login '%s' incorrect", login));
@@ -198,19 +259,44 @@ int oauth_post_handler(const xs_dict *req, const char *q_path,
198 const char *ruri = xs_dict_get(msg, "redirect_uri"); 259 const char *ruri = xs_dict_get(msg, "redirect_uri");
199 260
200 if (gtype && code && cid && csec && ruri) { 261 if (gtype && code && cid && csec && ruri) {
201 xs *rsp = xs_dict_new(); 262 xs *app = app_get(cid);
202 xs *cat = xs_number_new(time(NULL));
203 xs *token = random_str();
204 263
205 rsp = xs_dict_append(rsp, "access_token", token); 264 if (app == NULL) {
206 rsp = xs_dict_append(rsp, "token_type", "Bearer"); 265 status = 401;
207 rsp = xs_dict_append(rsp, "created_at", cat); 266 srv_log(xs_fmt("oauth token: invalid app %s", cid));
267 }
268 else
269 if (strcmp(csec, xs_dict_get(app, "client_secret")) != 0) {
270 status = 401;
271 srv_log(xs_fmt("oauth token: invalid client_secret for app %s", cid));
272 }
273 else {
274 xs *rsp = xs_dict_new();
275 xs *cat = xs_number_new(time(NULL));
276 xs *tokid = random_str();
208 277
209 *body = xs_json_dumps_pp(rsp, 4); 278 rsp = xs_dict_append(rsp, "access_token", tokid);
210 *ctype = "application/json"; 279 rsp = xs_dict_append(rsp, "token_type", "Bearer");
211 status = 200; 280 rsp = xs_dict_append(rsp, "created_at", cat);
281
282 *body = xs_json_dumps_pp(rsp, 4);
283 *ctype = "application/json";
284 status = 200;
285
286 const char *uid = xs_dict_get(app, "uid");
287
288 srv_debug(0, xs_fmt("oauth token: "
289 "successful login for %s, new token %s", uid, tokid));
290
291 xs *token = xs_dict_new();
292 token = xs_dict_append(token, "token", tokid);
293 token = xs_dict_append(token, "client_id", cid);
294 token = xs_dict_append(token, "client_secret", csec);
295 token = xs_dict_append(token, "uid", uid);
296 token = xs_dict_append(token, "code", code);
212 297
213 srv_debug(0, xs_fmt("oauth token: successful login, token %s", token)); 298 token_add(tokid, token);
299 }
214 } 300 }
215 else { 301 else {
216 srv_debug(0, xs_fmt("oauth token: invalid or unset arguments")); 302 srv_debug(0, xs_fmt("oauth token: invalid or unset arguments"));
@@ -221,15 +307,28 @@ int oauth_post_handler(const xs_dict *req, const char *q_path,
221 if (strcmp(cmd, "/revoke") == 0) { 307 if (strcmp(cmd, "/revoke") == 0) {
222 const char *cid = xs_dict_get(msg, "client_id"); 308 const char *cid = xs_dict_get(msg, "client_id");
223 const char *csec = xs_dict_get(msg, "client_secret"); 309 const char *csec = xs_dict_get(msg, "client_secret");
224 const char *token = xs_dict_get(msg, "token"); 310 const char *tokid = xs_dict_get(msg, "token");
311
312 if (cid && csec && tokid) {
313 xs *token = token_get(tokid);
225 314
226 if (cid && csec && token) {
227 *body = xs_str_new("{}"); 315 *body = xs_str_new("{}");
228 *ctype = "application/json"; 316 *ctype = "application/json";
229 status = 200; 317
318 if (token == NULL || strcmp(csec, xs_dict_get(token, "client_secret")) != 0) {
319 srv_debug(0, xs_fmt("oauth revoke: bad secret for token %s", tokid));
320 status = 403;
321 }
322 else {
323 token_del(tokid);
324 srv_debug(0, xs_fmt("oauth revoke: revoked token %s", tokid));
325 status = 200;
326 }
327 }
328 else {
329 srv_debug(0, xs_fmt("oauth revoke: invalid or unset arguments"));
330 status = 403;
230 } 331 }
231 else
232 status = 400;
233 } 332 }
234 333
235 return status; 334 return status;
@@ -242,6 +341,8 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path,
242 if (!xs_startswith(q_path, "/api/v1/")) 341 if (!xs_startswith(q_path, "/api/v1/"))
243 return 0; 342 return 0;
244 343
344 srv_debug(0, xs_fmt("mastoapi_get_handler %s", q_path));
345
245 { 346 {
246 xs *j = xs_json_dumps_pp(req, 4); 347 xs *j = xs_json_dumps_pp(req, 4);
247 printf("mastoapi get:\n%s\n", j); 348 printf("mastoapi get:\n%s\n", j);
@@ -250,12 +351,56 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path,
250 int status = 404; 351 int status = 404;
251 xs_dict *msg = xs_dict_get(req, "q_vars"); 352 xs_dict *msg = xs_dict_get(req, "q_vars");
252 xs *cmd = xs_replace(q_path, "/api/v1", ""); 353 xs *cmd = xs_replace(q_path, "/api/v1", "");
354 char *v;
253 355
254 srv_debug(0, xs_fmt("mastoapi_get_handler %s", q_path)); 356 snac snac = {0};
357 int logged_in = 0;
358
359 /* if there is an authorization field, try to validate it */
360 if (!xs_is_null(v = xs_dict_get(req, "authorization")) && xs_startswith(v, "Bearer ")) {
361 xs *tokid = xs_replace(v, "Bearer ", "");
362 xs *token = token_get(tokid);
363
364 if (token != NULL) {
365 const char *uid = xs_dict_get(token, "uid");
366
367 if (!xs_is_null(uid) && user_open(&snac, uid)) {
368 logged_in = 1;
369 srv_debug(0, xs_fmt("mastoapi auth: valid token for user %s", uid));
370 }
371 else
372 srv_log(xs_fmt("mastoapi auth: corrupted token %s", tokid));
373 }
374 else
375 srv_log(xs_fmt("mastoapi auth: invalid token %s", tokid));
376 }
255 377
256 if (strcmp(cmd, "/accounts/verify_credentials") == 0) { 378 if (strcmp(cmd, "/accounts/verify_credentials") == 0) {
379 if (logged_in) {
380 xs_dict *acct = xs_dict_new();
381
382 acct = xs_dict_append(acct, "id", xs_dict_get(snac.config, "uid"));
383 acct = xs_dict_append(acct, "username", xs_dict_get(snac.config, "uid"));
384 acct = xs_dict_append(acct, "acct", xs_dict_get(snac.config, "uid"));
385 acct = xs_dict_append(acct, "display_name", xs_dict_get(snac.config, "name"));
386 acct = xs_dict_append(acct, "created_at", xs_dict_get(snac.config, "published"));
387 acct = xs_dict_append(acct, "note", xs_dict_get(snac.config, "bio"));
388 acct = xs_dict_append(acct, "url", snac.actor);
389 acct = xs_dict_append(acct, "avatar", xs_dict_get(snac.config, "avatar"));
390
391 *body = xs_json_dumps_pp(acct, 4);
392 *ctype = "application/json";
393 status = 200;
394 }
395 else {
396 status = 422; // "Unprocessable entity" (no login)
397 }
257 } 398 }
258 399
400 /* user cleanup */
401 if (logged_in)
402 user_free(&snac);
403
259 return status; 404 return status;
260} 405}
261 406