2.57 snac.c
  1/* snac - A simple, minimalistic ActivityPub instance */
  2/* copyright (c) 2022 - 2024 grunfink et al. / MIT license */
  3
  4#define XS_IMPLEMENTATION
  5
  6#include "xs.h"
  7#include "xs_hex.h"
  8#include "xs_io.h"
  9#include "xs_unicode.h"
 10#include "xs_json.h"
 11#include "xs_curl.h"
 12#include "xs_openssl.h"
 13#include "xs_socket.h"
 14#include "xs_unix_socket.h"
 15#include "xs_url.h"
 16#include "xs_httpd.h"
 17#include "xs_mime.h"
 18#include "xs_regex.h"
 19#include "xs_set.h"
 20#include "xs_time.h"
 21#include "xs_glob.h"
 22#include "xs_random.h"
 23#include "xs_match.h"
 24#include "xs_fcgi.h"
 25#include "xs_html.h"
 26
 27#include "snac.h"
 28
 29#include <sys/time.h>
 30#include <sys/stat.h>
 31
 32xs_str *srv_basedir = NULL;
 33xs_dict *srv_config = NULL;
 34xs_str *srv_baseurl = NULL;
 35
 36int dbglevel = 0;
 37
 38
 39int mkdirx(const char *pathname)
 40/* creates a directory with special permissions */
 41{
 42    int ret;
 43
 44    if ((ret = mkdir(pathname, DIR_PERM)) != -1) {
 45        /* try to the set the setgid bit, to allow system users
 46           to create files in these directories using the
 47           command-line tool. This may fail in some restricted
 48           environments, but it's of no use there anyway */
 49        chmod(pathname, DIR_PERM_ADD);
 50    }
 51
 52    return ret;
 53}
 54
 55
 56int valid_status(int status)
 57/* is this HTTP status valid? */
 58{
 59    return status >= 200 && status <= 299;
 60}
 61
 62
 63xs_str *tid(int offset)
 64/* returns a time-based Id */
 65{
 66    struct timeval tv;
 67
 68    gettimeofday(&tv, NULL);
 69
 70    return xs_fmt("%10d.%06d", tv.tv_sec + offset, tv.tv_usec);
 71}
 72
 73
 74double ftime(void)
 75/* returns the UNIX time as a float */
 76{
 77    xs *ntid = tid(0);
 78
 79    return atof(ntid);
 80}
 81
 82
 83int validate_uid(const char *uid)
 84/* returns if uid is a valid identifier */
 85{
 86    if (!uid || *uid == '\0')
 87        return 0;
 88
 89    while (*uid) {
 90        if (!(isalnum(*uid) || *uid == '_'))
 91            return 0;
 92
 93        uid++;
 94    }
 95
 96    return 1;
 97}
 98
 99
100void srv_log(xs_str *str)
101/* logs a debug message */
102{
103    if (xs_str_in(str, srv_basedir) != -1) {
104        /* replace basedir with ~ */
105        str = xs_replace_i(str, srv_basedir, "~");
106    }
107
108    xs *tm = xs_str_localtime(0, "%H:%M:%S");
109    fprintf(stderr, "%s %s\n", tm, str);
110
111    /* if the ~/log/ folder exists, also write to a file there */
112    xs *dt = xs_str_localtime(0, "%Y-%m-%d");
113    xs *lf = xs_fmt("%s/log/%s.log", srv_basedir, dt);
114    FILE *f;
115    if ((f = fopen(lf, "a")) != NULL) {
116        fprintf(f, "%s %s\n", tm, str);
117        fclose(f);
118    }
119
120    xs_free(str);
121}
122
123
124void snac_log(snac *snac, xs_str *str)
125/* prints a user debugging information */
126{
127    xs *o_str = str;
128    xs_str *msg = xs_fmt("[%s] %s", snac->uid, o_str);
129
130    if (xs_str_in(msg, snac->basedir) != -1) {
131        /* replace long basedir references with ~ */
132        msg = xs_replace_i(msg, snac->basedir, "~");
133    }
134
135    srv_log(msg);
136}
137
138
139xs_str *hash_password(const char *uid, const char *passwd, const char *nonce)
140/* hashes a password */
141{
142    xs *d_nonce = NULL;
143    xs *combi;
144    xs *hash;
145
146    if (nonce == NULL) {
147        unsigned int r;
148        xs_rnd_buf(&r, sizeof(r));
149        d_nonce = xs_fmt("%08x", r);
150        nonce = d_nonce;
151    }
152
153    combi = xs_fmt("%s:%s:%s", nonce, uid, passwd);
154    hash  = xs_sha1_hex(combi, strlen(combi));
155
156    return xs_fmt("%s:%s", nonce, hash);
157}
158
159
160int check_password(const char *uid, const char *passwd, const char *hash)
161/* checks a password */
162{
163    int ret = 0;
164    xs *spl = xs_split_n(hash, ":", 1);
165
166    if (xs_list_len(spl) == 2) {
167        xs *n_hash = hash_password(uid, passwd, xs_list_get(spl, 0));
168
169        ret = (strcmp(hash, n_hash) == 0);
170    }
171
172    return ret;
173}
174
175
176const char *http_status_text(int status)
177/* translate status codes to canonical status texts */
178{
179    switch (status) {
180#define HTTP_STATUS(code, name, text) case HTTP_STATUS_ ## name: return #text;
181#include "http_codes.h"
182#undef HTTP_STATUS
183        default: return "Unknown";
184    }
185}