snac.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /* snac - A simple, minimalistic ActivityPub instance */
  2. /* copyright (c) 2022 grunfink - MIT license */
  3. #define XS_IMPLEMENTATION
  4. #include "xs.h"
  5. #include "xs_io.h"
  6. #include "xs_encdec.h"
  7. #include "xs_json.h"
  8. #include "xs_curl.h"
  9. #include "xs_openssl.h"
  10. #include "xs_socket.h"
  11. #include "xs_httpd.h"
  12. #include "snac.h"
  13. #include <sys/time.h>
  14. d_char *srv_basedir = NULL;
  15. d_char *srv_config = NULL;
  16. d_char *srv_baseurl = NULL;
  17. int dbglevel = 0;
  18. d_char *xs_time(char *fmt, int local)
  19. /* returns a d_char with a formated time */
  20. {
  21. time_t t = time(NULL);
  22. struct tm tm;
  23. char tmp[64];
  24. if (local)
  25. localtime_r(&t, &tm);
  26. else
  27. gmtime_r(&t, &tm);
  28. strftime(tmp, sizeof(tmp), fmt, &tm);
  29. return xs_str_new(tmp);
  30. }
  31. d_char *tid(void)
  32. /* returns a time-based Id */
  33. {
  34. struct timeval tv;
  35. struct timezone tz;
  36. gettimeofday(&tv, &tz);
  37. return xs_fmt("%10d.%06d", tv.tv_sec, tv.tv_usec);
  38. }
  39. void srv_debug(int level, d_char *str)
  40. /* logs a debug message */
  41. {
  42. xs *msg = str;
  43. if (dbglevel >= level) {
  44. xs *tm = xs_local_time("%H:%M:%S");
  45. fprintf(stderr, "%s %s\n", tm, msg);
  46. }
  47. }
  48. int srv_open(char *basedir)
  49. /* opens a server */
  50. {
  51. int ret = 0;
  52. xs *cfg_file = NULL;
  53. FILE *f;
  54. srv_basedir = xs_str_new(basedir);
  55. cfg_file = xs_fmt("%s/server.json", basedir);
  56. if ((f = fopen(cfg_file, "r")) == NULL)
  57. srv_log(xs_fmt("error opening '%s'", cfg_file));
  58. else {
  59. xs *cfg_data;
  60. /* read full config file */
  61. cfg_data = xs_readall(f);
  62. /* parse */
  63. srv_config = xs_json_loads(cfg_data);
  64. if (srv_config == NULL)
  65. srv_log(xs_fmt("cannot parse '%s'", cfg_file));
  66. else {
  67. char *host;
  68. char *prefix;
  69. char *dbglvl;
  70. host = xs_dict_get(srv_config, "host");
  71. prefix = xs_dict_get(srv_config, "prefix");
  72. dbglvl = xs_dict_get(srv_config, "dbglevel");
  73. if (host == NULL || prefix == NULL)
  74. srv_log(xs_str_new("cannot get server data"));
  75. else {
  76. srv_baseurl = xs_fmt("https://%s%s", host, prefix);
  77. dbglevel = (int) xs_number_get(dbglvl);
  78. if ((dbglvl = getenv("DEBUG")) != NULL) {
  79. dbglevel = atoi(dbglvl);
  80. srv_log(xs_fmt("DEBUG level set to %d from environment", dbglevel));
  81. }
  82. ret = 1;
  83. }
  84. }
  85. }
  86. return ret;
  87. }
  88. int validate_uid(char *uid)
  89. /* returns if uid is a valid identifier */
  90. {
  91. while (*uid) {
  92. if (!(isalnum(*uid) || *uid == '_'))
  93. return 0;
  94. uid++;
  95. }
  96. return 1;
  97. }
  98. void snac_free(snac *snac)
  99. /* frees a user snac */
  100. {
  101. free(snac->uid);
  102. free(snac->basedir);
  103. free(snac->config);
  104. free(snac->key);
  105. free(snac->actor);
  106. }
  107. int snac_open(snac *snac, char *uid)
  108. /* opens a user */
  109. {
  110. int ret = 0;
  111. memset(snac, '\0', sizeof(struct _snac));
  112. if (validate_uid(uid)) {
  113. xs *cfg_file;
  114. FILE *f;
  115. snac->uid = xs_str_new(uid);
  116. snac->basedir = xs_fmt("%s/user/%s", srv_basedir, uid);
  117. cfg_file = xs_fmt("%s/user.json", snac->basedir);
  118. if ((f = fopen(cfg_file, "r")) != NULL) {
  119. xs *cfg_data;
  120. /* read full config file */
  121. cfg_data = xs_readall(f);
  122. fclose(f);
  123. if ((snac->config = xs_json_loads(cfg_data)) != NULL) {
  124. xs *key_file = xs_fmt("%s/key.json", snac->basedir);
  125. if ((f = fopen(key_file, "r")) != NULL) {
  126. xs *key_data;
  127. key_data = xs_readall(f);
  128. fclose(f);
  129. if ((snac->key = xs_json_loads(key_data)) != NULL) {
  130. snac->actor = xs_fmt("%s/%s", srv_baseurl, uid);
  131. ret = 1;
  132. }
  133. else
  134. srv_log(xs_fmt("cannot parse '%s'", key_file));
  135. }
  136. else
  137. srv_log(xs_fmt("error opening '%s'", key_file));
  138. }
  139. else
  140. srv_log(xs_fmt("cannot parse '%s'", cfg_file));
  141. }
  142. else
  143. srv_log(xs_fmt("error opening '%s'", cfg_file));
  144. }
  145. else
  146. srv_log(xs_fmt("invalid user '%s'", uid));
  147. if (!ret)
  148. snac_free(snac);
  149. return ret;
  150. }
  151. void snac_debug(snac *snac, int level, d_char *str)
  152. /* prints a user debugging information */
  153. {
  154. xs *msg = str;
  155. if (dbglevel >= level) {
  156. xs *tm = xs_local_time("%H:%M:%S");
  157. fprintf(stderr, "%s [%s] %s\n", tm, snac->uid, msg);
  158. }
  159. }