webfinger.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /* snac - A simple, minimalistic ActivityPub instance */
  2. /* copyright (c) 2022 grunfink - MIT license */
  3. #include "xs.h"
  4. #include "xs_encdec.h"
  5. #include "xs_json.h"
  6. #include "xs_curl.h"
  7. #include "snac.h"
  8. void webfinger_request(char *qs, int *status, char **actor, char **user)
  9. /* queries the webfinger for qs and fills the required fields */
  10. {
  11. xs *payload = NULL;
  12. int p_size = 0;
  13. xs *url = NULL;
  14. xs *headers = xs_dict_new();
  15. if (xs_startswith(qs, "https:/" "/")) {
  16. /* actor query: pick the host */
  17. xs *s = xs_replace(qs, "https:/" "/", "");
  18. xs *l = xs_split_n(s, "/", 1);
  19. url = xs_fmt("https:/" "/%s/.well-known/webfinger?resource=%s",
  20. xs_list_get(l, 0), qs);
  21. }
  22. else {
  23. /* it's a user */
  24. xs *s = xs_dup(qs);
  25. xs *l;
  26. if (xs_startswith(s, "@"))
  27. s = xs_crop(s, 1, 0);
  28. l = xs_split_n(s, "@", 1);
  29. if (xs_list_len(l) == 2) {
  30. url = xs_fmt("https:/" "/%s/.well-known/webfinger?resource:acct:%s",
  31. xs_list_get(l, 1), qs);
  32. }
  33. }
  34. if (url == NULL) {
  35. *status = 400;
  36. return;
  37. }
  38. headers = xs_dict_append(headers, "accept", "application/json");
  39. xs_http_request("GET", url, headers, NULL, 0, status, &payload, &p_size);
  40. }
  41. void webfinger_get_handler(d_char *req, char *q_path, int *status,
  42. char **body, int *b_size, char **ctype)
  43. /* serves webfinger queries */
  44. {
  45. if (strcmp(q_path, "/.well-known/webfinger") != 0)
  46. return;
  47. char *q_vars = xs_dict_get(req, "q_vars");
  48. char *resource = xs_dict_get(q_vars, "resource");
  49. if (resource == NULL) {
  50. *status = 400;
  51. return;
  52. }
  53. snac snac;
  54. int found = 0;
  55. if (xs_startswith(resource, "https:/" "/")) {
  56. /* actor search: find a user with this actor */
  57. xs *list = user_list();
  58. char *p, *uid;
  59. p = list;
  60. while (xs_list_iter(&p, &uid)) {
  61. if (user_open(&snac, uid)) {
  62. if (strcmp(snac.actor, resource) == 0) {
  63. found = 1;
  64. break;
  65. }
  66. user_free(&snac);
  67. }
  68. }
  69. }
  70. else
  71. if (xs_startswith(resource, "acct:")) {
  72. /* it's an account name */
  73. xs *an = xs_replace(resource, "acct:", "");
  74. xs *l = NULL;
  75. /* strip a possible leading @ */
  76. if (xs_startswith(an, "@"))
  77. an = xs_crop(an, 1, 0);
  78. l = xs_split_n(an, "@", 1);
  79. if (xs_list_len(l) == 2) {
  80. char *uid = xs_list_get(l, 0);
  81. char *host = xs_list_get(l, 1);
  82. if (strcmp(host, xs_dict_get(srv_config, "host")) == 0)
  83. found = user_open(&snac, uid);
  84. }
  85. }
  86. if (found) {
  87. /* build the object */
  88. xs *acct;
  89. xs *aaj = xs_dict_new();
  90. xs *links = xs_list_new();
  91. xs *obj = xs_dict_new();
  92. d_char *j;
  93. acct = xs_fmt("acct:%s@%s",
  94. xs_dict_get(snac.config, "uid"), xs_dict_get(srv_config, "host"));
  95. aaj = xs_dict_append(aaj, "rel", "self");
  96. aaj = xs_dict_append(aaj, "type", "application/activity+json");
  97. aaj = xs_dict_append(aaj, "href", snac.actor);
  98. links = xs_list_append(links, aaj);
  99. obj = xs_dict_append(obj, "subject", acct);
  100. obj = xs_dict_append(obj, "links", links);
  101. j = xs_json_dumps_pp(obj, 4);
  102. user_free(&snac);
  103. *status = 200;
  104. *body = j;
  105. *ctype = "application/json";
  106. }
  107. }