snac.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  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("cannot open %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. int snac_open(snac *snac, char *uid)
  99. /* opens a user */
  100. {
  101. int ret = 0;
  102. memset(snac, '\0', sizeof(struct _snac));
  103. if (validate_uid(uid)) {
  104. xs *cfg_file;
  105. FILE *f;
  106. snac->uid = xs_str_new(uid);
  107. snac->basedir = xs_fmt("%s/user/%s", srv_basedir, uid);
  108. cfg_file = xs_fmt("%s/user.json", snac->basedir);
  109. if ((f = fopen(cfg_file, "r")) != NULL) {
  110. xs *cfg_data;
  111. /* read full config file */
  112. cfg_data = xs_readall(f);
  113. fclose(f);
  114. if ((snac->config = xs_json_loads(cfg_data)) != NULL) {
  115. xs *key_file = xs_fmt("%s/key.json", snac->basedir);
  116. if ((f = fopen(key_file, "r")) != NULL) {
  117. xs *key_data;
  118. key_data = xs_readall(f);
  119. fclose(f);
  120. if ((snac->key = xs_json_loads(key_data)) != NULL) {
  121. snac->actor = xs_fmt("%s/%s", srv_baseurl, uid);
  122. ret = 1;
  123. }
  124. else
  125. srv_log(xs_fmt("cannot parse %s", key_file));
  126. }
  127. else
  128. srv_log(xs_fmt("error opening '%s'", key_file));
  129. }
  130. else
  131. srv_log(xs_fmt("cannot parse %s", cfg_file));
  132. }
  133. else
  134. srv_log(xs_fmt("error opening '%s'", cfg_file));
  135. }
  136. else
  137. srv_log(xs_fmt("invalid user '%s'", uid));
  138. return ret;
  139. }
  140. void snac_free(snac *snac)
  141. /* frees a user snac */
  142. {
  143. free(snac->uid);
  144. free(snac->basedir);
  145. free(snac->config);
  146. free(snac->key);
  147. free(snac->actor);
  148. }
  149. void snac_debug(snac *snac, int level, d_char *str)
  150. /* prints a user debugging information */
  151. {
  152. xs *msg = str;
  153. if (dbglevel >= level) {
  154. xs *tm = xs_local_time("%H:%M:%S");
  155. fprintf(stderr, "%s [%s] %s\n", tm, snac->uid, msg);
  156. }
  157. }