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