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