commit ccce01d

default  ·  2023-04-09 19:31:56 +0000 UTC
parent 4ced03b
More mastoapi work.
1 files changed,  +162, -17
+162, -17
  1@@ -71,6 +71,56 @@ xs_dict *app_get(const char *id)
  2 }
  3 
  4 
  5+int token_add(const char *id, const xs_dict *token)
  6+/* stores a token */
  7+{
  8+    int status = 201;
  9+    xs *fn     = xs_fmt("%s/token/", srv_basedir);
 10+    FILE *f;
 11+
 12+    mkdirx(fn);
 13+    fn = xs_str_cat(fn, id);
 14+    fn = xs_str_cat(fn, ".json");
 15+
 16+    if ((f = fopen(fn, "w")) != NULL) {
 17+        xs *j = xs_json_dumps_pp(token, 4);
 18+        fwrite(j, strlen(j), 1, f);
 19+        fclose(f);
 20+    }
 21+    else
 22+        status = 500;
 23+
 24+    return status;
 25+}
 26+
 27+
 28+xs_dict *token_get(const char *id)
 29+/* gets a token */
 30+{
 31+    xs *fn         = xs_fmt("%s/token/%s.json", srv_basedir, id);
 32+    xs_dict *token = NULL;
 33+    FILE *f;
 34+
 35+    if ((f = fopen(fn, "r")) != NULL) {
 36+        xs *j = xs_readall(f);
 37+        fclose(f);
 38+
 39+        token = xs_json_loads(j);
 40+    }
 41+
 42+    return token;
 43+}
 44+
 45+
 46+int token_del(const char *id)
 47+/* deletes a token */
 48+{
 49+    xs *fn = xs_fmt("%s/token/%s.json", srv_basedir, id);
 50+
 51+    return unlink(fn);
 52+}
 53+
 54+
 55 const char *login_page = ""
 56 "<!DOCTYPE html>\n"
 57 "<body><h1>%s OAuth identify</h1>\n"
 58@@ -176,7 +226,18 @@ int oauth_post_handler(const xs_dict *req, const char *q_path,
 59                     *body = xs_fmt("%s?code=%s", redir, code);
 60                     status = 303;
 61 
 62-                    srv_debug(0, xs_fmt("oauth x-snac-login: redirect to %s", *body));
 63+                    srv_debug(0, xs_fmt("oauth x-snac-login: success, redirect to %s", *body));
 64+
 65+                    /* assign the login to the app */
 66+                    xs *app = app_get(cid);
 67+
 68+                    if (app != NULL) {
 69+                        app = xs_dict_set(app, "uid",  login);
 70+                        app = xs_dict_set(app, "code", code);
 71+                        app_add(cid, app);
 72+                    }
 73+                    else
 74+                        srv_log(xs_fmt("oauth x-snac-login: error getting app %s", cid));
 75                 }
 76                 else
 77                     srv_debug(0, xs_fmt("oauth x-snac-login: login '%s' incorrect", login));
 78@@ -198,19 +259,44 @@ int oauth_post_handler(const xs_dict *req, const char *q_path,
 79         const char *ruri  = xs_dict_get(msg, "redirect_uri");
 80 
 81         if (gtype && code && cid && csec && ruri) {
 82-            xs *rsp   = xs_dict_new();
 83-            xs *cat   = xs_number_new(time(NULL));
 84-            xs *token = random_str();
 85+            xs *app = app_get(cid);
 86 
 87-            rsp = xs_dict_append(rsp, "access_token", token);
 88-            rsp = xs_dict_append(rsp, "token_type",   "Bearer");
 89-            rsp = xs_dict_append(rsp, "created_at",   cat);
 90+            if (app == NULL) {
 91+                status = 401;
 92+                srv_log(xs_fmt("oauth token: invalid app %s", cid));
 93+            }
 94+            else
 95+            if (strcmp(csec, xs_dict_get(app, "client_secret")) != 0) {
 96+                status = 401;
 97+                srv_log(xs_fmt("oauth token: invalid client_secret for app %s", cid));
 98+            }
 99+            else {
100+                xs *rsp   = xs_dict_new();
101+                xs *cat   = xs_number_new(time(NULL));
102+                xs *tokid = random_str();
103 
104-            *body  = xs_json_dumps_pp(rsp, 4);
105-            *ctype = "application/json";
106-            status = 200;
107+                rsp = xs_dict_append(rsp, "access_token", tokid);
108+                rsp = xs_dict_append(rsp, "token_type",   "Bearer");
109+                rsp = xs_dict_append(rsp, "created_at",   cat);
110+
111+                *body  = xs_json_dumps_pp(rsp, 4);
112+                *ctype = "application/json";
113+                status = 200;
114+
115+                const char *uid = xs_dict_get(app, "uid");
116+
117+                srv_debug(0, xs_fmt("oauth token: "
118+                                "successful login for %s, new token %s", uid, tokid));
119+
120+                xs *token = xs_dict_new();
121+                token = xs_dict_append(token, "token",         tokid);
122+                token = xs_dict_append(token, "client_id",     cid);
123+                token = xs_dict_append(token, "client_secret", csec);
124+                token = xs_dict_append(token, "uid",           uid);
125+                token = xs_dict_append(token, "code",          code);
126 
127-            srv_debug(0, xs_fmt("oauth token: successful login, token %s", token));
128+                token_add(tokid, token);
129+            }
130         }
131         else {
132             srv_debug(0, xs_fmt("oauth token: invalid or unset arguments"));
133@@ -221,15 +307,28 @@ int oauth_post_handler(const xs_dict *req, const char *q_path,
134     if (strcmp(cmd, "/revoke") == 0) {
135         const char *cid   = xs_dict_get(msg, "client_id");
136         const char *csec  = xs_dict_get(msg, "client_secret");
137-        const char *token = xs_dict_get(msg, "token");
138+        const char *tokid = xs_dict_get(msg, "token");
139+
140+        if (cid && csec && tokid) {
141+            xs *token = token_get(tokid);
142 
143-        if (cid && csec && token) {
144             *body  = xs_str_new("{}");
145             *ctype = "application/json";
146-            status = 200;
147+
148+            if (token == NULL || strcmp(csec, xs_dict_get(token, "client_secret")) != 0) {
149+                srv_debug(0, xs_fmt("oauth revoke: bad secret for token %s", tokid));
150+                status = 403;
151+            }
152+            else {
153+                token_del(tokid);
154+                srv_debug(0, xs_fmt("oauth revoke: revoked token %s", tokid));
155+                status = 200;
156+            }
157+        }
158+        else {
159+            srv_debug(0, xs_fmt("oauth revoke: invalid or unset arguments"));
160+            status = 403;
161         }
162-        else
163-            status = 400;
164     }
165 
166     return status;
167@@ -242,6 +341,8 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path,
168     if (!xs_startswith(q_path, "/api/v1/"))
169         return 0;
170 
171+    srv_debug(0, xs_fmt("mastoapi_get_handler %s", q_path));
172+
173     {
174         xs *j = xs_json_dumps_pp(req, 4);
175         printf("mastoapi get:\n%s\n", j);
176@@ -250,12 +351,56 @@ int mastoapi_get_handler(const xs_dict *req, const char *q_path,
177     int status   = 404;
178     xs_dict *msg = xs_dict_get(req, "q_vars");
179     xs *cmd      = xs_replace(q_path, "/api/v1", "");
180+    char *v;
181 
182-    srv_debug(0, xs_fmt("mastoapi_get_handler %s", q_path));
183+    snac snac = {0};
184+    int logged_in = 0;
185+
186+    /* if there is an authorization field, try to validate it */
187+    if (!xs_is_null(v = xs_dict_get(req, "authorization")) && xs_startswith(v, "Bearer ")) {
188+        xs *tokid = xs_replace(v, "Bearer ", "");
189+        xs *token = token_get(tokid);
190+
191+        if (token != NULL) {
192+            const char *uid = xs_dict_get(token, "uid");
193+
194+            if (!xs_is_null(uid) && user_open(&snac, uid)) {
195+                logged_in = 1;
196+                srv_debug(0, xs_fmt("mastoapi auth: valid token for user %s", uid));
197+            }
198+            else
199+                srv_log(xs_fmt("mastoapi auth: corrupted token %s", tokid));
200+        }
201+        else
202+            srv_log(xs_fmt("mastoapi auth: invalid token %s", tokid));
203+    }
204 
205     if (strcmp(cmd, "/accounts/verify_credentials") == 0) {
206+        if (logged_in) {
207+            xs_dict *acct = xs_dict_new();
208+
209+            acct = xs_dict_append(acct, "id",           xs_dict_get(snac.config, "uid"));
210+            acct = xs_dict_append(acct, "username",     xs_dict_get(snac.config, "uid"));
211+            acct = xs_dict_append(acct, "acct",         xs_dict_get(snac.config, "uid"));
212+            acct = xs_dict_append(acct, "display_name", xs_dict_get(snac.config, "name"));
213+            acct = xs_dict_append(acct, "created_at",   xs_dict_get(snac.config, "published"));
214+            acct = xs_dict_append(acct, "note",         xs_dict_get(snac.config, "bio"));
215+            acct = xs_dict_append(acct, "url",          snac.actor);
216+            acct = xs_dict_append(acct, "avatar",       xs_dict_get(snac.config, "avatar"));
217+
218+            *body  = xs_json_dumps_pp(acct, 4);
219+            *ctype = "application/json";
220+            status = 200;
221+        }
222+        else {
223+            status = 422;   // "Unprocessable entity" (no login)
224+        }
225     }
226 
227+    /* user cleanup */
228+    if (logged_in)
229+        user_free(&snac);
230+
231     return status;
232 }
233