Finish authenticated API endpoints on cgi_blerg
[blerg.git] / cgi / cgi_blerg.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <cgi-util.h>
5 #include <yajl/yajl_gen.h>
6 #include "database.h"
7 #include "tags.h"
8 #include "auth.h"
9 #include "app.h"
10 #include "config.h"
11
12 yajl_gen_config yajl_c = { 0, 0 };
13
14 void respond_simple_data(unsigned const char *data, int len) {
15         printf("Content-length: %d\r\n\r\n", len);
16         write(0, data, len);
17 }
18
19 void respond_404() {
20         printf("Status: 404 Not Found\r\n");
21         printf("Content-type: text/html\r\n");
22         printf("Content-length: %d\r\n\r\n", strlen(CONTENT_404));
23
24         printf(CONTENT_404);
25 }
26
27 void respond_405() {
28         printf("Status: 405 Method Not Allowed\r\n");
29         printf("Content-type: text/html\r\n");
30         printf("Content-length: %d\r\n\r\n", strlen(CONTENT_405));
31
32         printf(CONTENT_405);
33 }
34
35 void respond_JSON_Failure() {
36         respond_simple_data(JSON_FAILURE, strlen(JSON_FAILURE));
37 }
38
39 void respond_JSON_Success() {
40         respond_simple_data(JSON_SUCCESS, strlen(JSON_SUCCESS));
41 }
42
43 void respond_for_range(struct blerg *b, uint64_t from, uint64_t to) {
44         const unsigned char *ybuf;
45         unsigned int len;
46         uint64_t i;
47         yajl_gen g;
48         uint64_t record_count = blerg_get_record_count(b);
49
50         printf("Content-type: application/json\r\n\r\n");
51
52         if (from > to || from >= record_count || to >= record_count || to - from > 99) {
53                 respond_JSON_Failure();
54                 return;
55         }
56
57         g = yajl_gen_alloc(&yajl_c, NULL);
58         yajl_gen_array_open(g);
59
60         for (i = to; i != from - 1; i--) {
61                 json_generate_one_record(g, NULL, b, i);
62                 yajl_gen_get_buf(g, &ybuf, &len);
63                 write(0, ybuf, len);
64                 yajl_gen_clear(g);
65         }
66
67         yajl_gen_array_close(g);
68         yajl_gen_get_buf(g, &ybuf, &len);
69         write(0, ybuf, len);
70         yajl_gen_free(g);
71 }
72
73 void respond_taglist(struct tag *results, int i) {
74         const unsigned char *ybuf;
75         unsigned int len;
76         struct blerg *b;
77         yajl_gen g;
78
79         i--;
80
81         printf("Content-type: application/json\r\n\r\n");
82         g = yajl_gen_alloc(&yajl_c, NULL);
83
84         yajl_gen_array_open(g);
85
86         while (i >= 0) {
87                 b = blerg_open(results[i].author);
88                 if (b != NULL) {
89                         json_generate_one_record(g, results[i].author, b, results[i].record);
90                         blerg_close(b);
91                 }
92                 yajl_gen_get_buf(g, &ybuf, &len);
93                 write(0, ybuf, len);
94                 yajl_gen_clear(g);
95
96                 i--;
97         }
98
99         yajl_gen_array_close(g);
100         yajl_gen_get_buf(g, &ybuf, &len);
101         write(0, ybuf, len);
102         yajl_gen_free(g);
103 }
104
105 int main(int argc, char *argv[]) {
106         char *path;
107         char *request_method;
108         int ret, len;
109         struct url_info info;
110         char *data;
111
112         if (cgi_init() != CGIERR_NONE)
113                 exit(0);
114
115         path = getenv("PATH_INFO");
116         if (path == NULL) {
117                 respond_404();
118                 exit(0);
119         }
120         request_method = getenv("REQUEST_METHOD");
121
122         if (strncmp(path, "/get", 4) == 0 && strlen(path) > 4) {
123                 if (strncmp(request_method, "GET", 4) != 0) {
124                         respond_405();
125                         exit(0);
126                 }
127
128                 if (path[4] != '/') {
129                         respond_404();
130                         exit(0);
131                 }
132
133                 ret = parse_url_info(path + 5, &info);
134                 if ((ret & URL_INFO_AUTHOR) == 0) {
135                         respond_404();
136                         exit(0);
137                 }
138
139                 if (!blerg_exists(info.author)) {
140                         respond_404();
141                         exit(0);
142                 }
143
144                 struct blerg *b = blerg_open(info.author);
145
146                 if ((ret & URL_INFO_RECORD) && (ret & URL_INFO_RECORD_TO)) {
147                         respond_for_range(b, info.record, info.record_to);
148                 } else if (ret & URL_INFO_RECORD) {
149                         ret = blerg_fetch(b, info.record, &data, &len);
150
151                         if (ret == 0) {
152                                 respond_404();
153                                 exit(0);
154                         }
155                         respond_simple_data(data, len);
156                 } else {
157                         uint64_t record_count, from, to;
158                         record_count = blerg_get_record_count(b);
159                         if (record_count == 0) {
160                                 respond_simple_data("[]", 2);
161                         } else {
162                                 to = record_count - 1;
163                                 from = (record_count > 50 ? to - 49 : 0);
164                                 respond_for_range(b, from, to);
165                         }
166                 }
167
168                 blerg_close(b);
169         } else if (strncmp(path, "/tag", 4) == 0 && strlen(path) > 4) {
170                 if (strcmp(request_method, "GET") != 0) {
171                         respond_405();
172                         exit(0);
173                 }
174
175                 if (path[4] != '/') {
176                         respond_404();
177                         exit(0);
178                 }
179
180                 ret = parse_url_info(path + 5, &info);
181                 if ((ret & URL_INFO_AUTHOR) == 0) {
182                         respond_404();
183                         exit(0);
184                 }
185
186                 if (!tag_exists(info.author)) {
187                         respond_404();
188                         exit(0);
189                 }
190
191                 int recs = 50;
192                 struct tag *taglist = tag_list(info.author, 0, &recs, -1);
193
194                 if (recs == 0) {
195                         respond_simple_data("[]", 2);
196                 } else {
197                         respond_taglist(taglist, recs);
198                 }
199         } else if (strncmp(path, "/put", 4) == 0) {
200                 if (strcmp(request_method, "POST") != 0) {
201                         respond_405();
202                         exit(0);
203                 }
204
205                 if (path[4] == '/') {
206                         respond_404();
207                         exit(0);
208                 }
209
210                 const char *username = cgi_getentrystr("username");
211                 const char *data = cgi_getentrystr("data");
212                 if (username == NULL || username[0] == 0 ||
213                     data == NULL || data[0] == 0) {
214                         respond_JSON_Failure();
215                         exit(0);
216                 }
217
218                 const char *given_token = cgi_getcookie("auth");
219                 if (!auth_check_token(username, given_token)) {
220                         respond_JSON_Failure();
221                         exit(0);
222                 }
223
224                 struct blerg *b = blerg_open(username);
225                 if (b == NULL) {
226                         respond_JSON_Failure();
227                         exit(0);
228                 }
229                 ret = blerg_store(b, data, strlen(data));
230                 blerg_close(b);
231                 if (ret == -1) {
232                         respond_JSON_Failure();
233                         exit(0);
234                 }
235
236                 respond_JSON_Success();
237         } else if (strncmp(path, "/info", 5) == 0) {
238                 if (strcmp(request_method, "GET") != 0) {
239                         respond_405();
240                         exit(0);
241                 }
242
243                 if (path[5] != '/') {
244                         respond_404();
245                         exit(0);
246                 }
247
248                 ret = parse_url_info(path + 6, &info);
249                 if ((ret & URL_INFO_AUTHOR) == 0) {
250                         respond_404();
251                         exit(0);
252                 }
253
254                 if (!blerg_exists(info.author)) {
255                         respond_404();
256                         exit(0);
257                 }
258
259                 struct blerg *b = blerg_open(info.author);
260                 uint64_t record_count = blerg_get_record_count(b);
261                 blerg_close(b);
262
263                 char number[21];
264                 yajl_gen g = yajl_gen_alloc(&yajl_c, NULL);
265                 yajl_gen_map_open(g);
266                 yajl_gen_string(g, "record_count", 12);
267                 snprintf(number, 21, "%llu", record_count);
268                 yajl_gen_string(g, number, strlen(number));
269                 yajl_gen_map_close(g);
270
271                 const unsigned char *ybuf;
272                 yajl_gen_get_buf(g, &ybuf, &len);
273
274                 printf("Content-type: application/json\r\n");
275                 printf("Content-length: %d\r\n\r\n", len);
276                 write(0, ybuf, len);
277
278                 yajl_gen_free(g);
279         } else if (strncmp(path, "/create", 8) == 0) {
280                 if (strcmp(request_method, "POST") != 0) {
281                         respond_405();
282                         exit(0);
283                 }
284
285                 const char *username = cgi_getentrystr("username");
286                 const char *password = cgi_getentrystr("password");
287                 if (username == NULL || username[0] == 0 ||
288                     password == NULL || password[0] == 0) {
289                         respond_JSON_Failure();
290                         exit(0);
291                 }
292
293                 if (blerg_exists(username)) {
294                         respond_JSON_Failure();
295                         exit(0);
296                 }
297
298                 struct blerg *b = blerg_open(username);
299                 blerg_close(b);
300                 auth_set_password(username, password);
301                 
302                 respond_JSON_Success();
303         } else if (strncmp(path, "/login", 7) == 0) {
304                 if (strcmp(request_method, "POST") != 0) {
305                         respond_405();
306                         exit(0);
307                 }
308
309                 const char *username = cgi_getentrystr("username");
310                 const char *password = cgi_getentrystr("password");
311                 if (username == NULL || username[0] == 0 ||
312                     password == NULL || password[0] == 0) {
313                         respond_JSON_Failure();
314                         exit(0);
315                 }
316
317                 if (!auth_login(username, password)) {
318                         respond_JSON_Failure();
319                         exit(0);
320                 }
321
322                 char *token = auth_get_token(username);
323                 printf("Set-Cookie: auth=%s\r\n", token);
324                 free(token);
325
326                 respond_JSON_Success();
327         } else if (strncmp(path, "/logout", 8) == 0) {
328                 if (strcmp(request_method, "POST") != 0) {
329                         respond_405();
330                         exit(0);
331                 }
332
333                 const char *username = cgi_getentrystr("username");
334                 if (username == NULL || username[0] == 0) {
335                         respond_JSON_Failure();
336                         exit(0);
337                 }
338
339
340                 const char *given_token = cgi_getcookie("auth");
341                 if (auth_check_token(username, given_token)) {
342                         auth_logout(username);
343                         respond_JSON_Success();
344                 } else {
345                         respond_JSON_Failure();
346                 }
347         } else {
348                 respond_404();
349                 exit(0);
350         }
351
352         cgi_quit();
353 }