forked from Telodendria/Telodendria
Finish converting all existing documentation. Next up is writing new docs.
This commit is contained in:
parent
71fa96d10d
commit
b70c3f0bed
16 changed files with 1035 additions and 242 deletions
3
TODO.txt
3
TODO.txt
|
@ -32,10 +32,11 @@ Milestone: v0.3.0
|
|||
[ ] http-debug-server
|
||||
[ ] tp
|
||||
[ ] send-patch
|
||||
[ ] Log
|
||||
[x] Log
|
||||
[ ] TelodendriaConfig -> Config
|
||||
[x] HashMap
|
||||
[ ] HttpRouter
|
||||
[x] Html
|
||||
[ ] Str
|
||||
[ ] HeaderParser
|
||||
[ ] hdoc
|
||||
|
|
|
@ -568,7 +568,6 @@ HeaderParse(Stream * stream, HeaderExpr * expr)
|
|||
{
|
||||
/* Looks like we have an array. Slurp all the
|
||||
* dimensions */
|
||||
int block = 1;
|
||||
int i = wordLen;
|
||||
|
||||
expr->data.global.name[i] = '[';
|
||||
|
|
50
src/Util.c
50
src/Util.c
|
@ -168,56 +168,6 @@ UtilSleepMillis(long ms)
|
|||
return res;
|
||||
}
|
||||
|
||||
size_t
|
||||
UtilParseBytes(char *str)
|
||||
{
|
||||
size_t bytes = 0;
|
||||
|
||||
while (*str)
|
||||
{
|
||||
if (isdigit((unsigned char) *str))
|
||||
{
|
||||
bytes *= 10;
|
||||
bytes += *str - '0';
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (*str)
|
||||
{
|
||||
case 'K':
|
||||
bytes *= 1024;
|
||||
break;
|
||||
case 'M':
|
||||
bytes *= pow(1024, 2);
|
||||
break;
|
||||
case 'G':
|
||||
bytes *= pow(1024, 3);
|
||||
break;
|
||||
case 'k':
|
||||
bytes *= 1000;
|
||||
break;
|
||||
case 'm':
|
||||
bytes *= pow(1000, 2);
|
||||
break;
|
||||
case 'g':
|
||||
bytes *= pow(1000, 3);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*(str + 1))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
str++;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
UtilGetDelim(char **linePtr, size_t * n, int delim, Stream * stream)
|
||||
{
|
||||
|
|
|
@ -25,10 +25,37 @@
|
|||
#ifndef TELODENDRIA_CONFIG_H
|
||||
#define TELODENDRIA_CONFIG_H
|
||||
|
||||
/***
|
||||
* @Nm Config
|
||||
* @Nd Parse the Telodendria configuration into a structure.
|
||||
* @Dd April 28 2023
|
||||
* @Xr Db Json HttpServer Log
|
||||
*
|
||||
* .Nm
|
||||
* validates and maintains the Telodendria server's configuration data.
|
||||
* This API builds on the database and JSON APIs to add parsing
|
||||
* specific to Telodendria. It converts a configuration in its raw
|
||||
* form into a structure that is much easier and more convenient to
|
||||
* work with.
|
||||
* .Pp
|
||||
* Since very early on in Telodendria's development, the configuration
|
||||
* file has existed inside of the database. This API also offers
|
||||
* convenience methods for extracting the configuration out of the
|
||||
* database.
|
||||
* .Pp
|
||||
* This documentation does not describe the actual format of the
|
||||
* configuration file; for that, consult
|
||||
* .Xr telodendria-config 7 .
|
||||
*/
|
||||
|
||||
#include <HashMap.h>
|
||||
#include <Array.h>
|
||||
#include <Db.h>
|
||||
|
||||
/**
|
||||
* Bit flags that can be set in the flags field of the configuration
|
||||
* structure.
|
||||
*/
|
||||
typedef enum ConfigFlag
|
||||
{
|
||||
CONFIG_FEDERATION = (1 << 0),
|
||||
|
@ -39,11 +66,29 @@ typedef enum ConfigFlag
|
|||
CONFIG_LOG_SYSLOG = (1 << 5)
|
||||
} ConfigFlag;
|
||||
|
||||
/**
|
||||
* The configuration structure is not opaque like many of the other
|
||||
* structures present in the other public APIs. This is intentional;
|
||||
* defining functions for all of the fields would simply add too much
|
||||
* unnecessary overhead.
|
||||
*/
|
||||
typedef struct Config
|
||||
{
|
||||
/*
|
||||
* These are used internally and should not be touched outside of
|
||||
* the functions defined in this API.
|
||||
*/
|
||||
Db *db;
|
||||
DbRef *ref;
|
||||
|
||||
/*
|
||||
* Whether or not the parsing was successful. If this boolean
|
||||
* value is 0, then read the error message and assume that all
|
||||
* other fields are invalid.
|
||||
*/
|
||||
int ok;
|
||||
char *err;
|
||||
|
||||
char *serverName;
|
||||
char *baseUrl;
|
||||
char *identityServer;
|
||||
|
@ -58,28 +103,61 @@ typedef struct Config
|
|||
char *logTimestamp;
|
||||
int logLevel;
|
||||
|
||||
/*
|
||||
* An array of HttpServerConfig structures. Consult the HttpServer
|
||||
* API.
|
||||
*/
|
||||
Array *servers;
|
||||
|
||||
int ok;
|
||||
char *err;
|
||||
} Config;
|
||||
|
||||
Config *
|
||||
ConfigParse(HashMap *);
|
||||
/**
|
||||
* Parse a JSON object, extracting the necessary values, validating
|
||||
* them, and adding them to the configuration structure for use by the
|
||||
* caller. All values are copied, so the JSON object can be safely
|
||||
* freed after this function returns.
|
||||
* .Pp
|
||||
* If an error occurs, this function will not return NULL, but it will
|
||||
* set the ok flag to 0. The caller should always check the ok flag,
|
||||
* and if there is an error, it should display the error to the user.
|
||||
*/
|
||||
Config * ConfigParse(HashMap *);
|
||||
|
||||
void
|
||||
ConfigFree(Config *);
|
||||
/**
|
||||
* Free all the values inside of the given configuration structure,
|
||||
* as well as the structure itself, such that it is completely invalid
|
||||
* when this function returns.
|
||||
*/
|
||||
void ConfigFree(Config *);
|
||||
|
||||
extern int
|
||||
ConfigExists(Db *);
|
||||
/**
|
||||
* Check whether or not the configuration exists in the database,
|
||||
* returning a boolean value to indicate the status.
|
||||
*/
|
||||
extern int ConfigExists(Db *);
|
||||
|
||||
extern int
|
||||
ConfigCreateDefault(Db *);
|
||||
/**
|
||||
* Create a sane default configuration in the specified database.
|
||||
* This function returns a boolean value indicating whether or not it
|
||||
* was successful.
|
||||
*/
|
||||
extern int ConfigCreateDefault(Db *);
|
||||
|
||||
extern Config *
|
||||
ConfigLock(Db *);
|
||||
/**
|
||||
* Lock the configuration in the database using
|
||||
* .Fn DbLock ,
|
||||
* and then parse the object using
|
||||
* .Fn ConfigParse .
|
||||
* The return value of this function is the same as
|
||||
* .Fn ConfigParse .
|
||||
*/
|
||||
extern Config * ConfigLock(Db *);
|
||||
|
||||
extern int
|
||||
ConfigUnlock(Config *);
|
||||
/**
|
||||
* Unlock the specified configuration, returning it back to the
|
||||
* database. This function also invalidates all memory associated with
|
||||
* this config object, so values that should be retained after this is
|
||||
* called should be duplicated as necessary.
|
||||
*/
|
||||
extern int ConfigUnlock(Config *);
|
||||
|
||||
#endif /* TELODENDRIA_CONFIG_H */
|
||||
|
|
|
@ -24,6 +24,37 @@
|
|||
#ifndef TELODENDRIA_HTML_H
|
||||
#define TELODENDRIA_HTML_H
|
||||
|
||||
/***
|
||||
* @Nm Html
|
||||
* @Nd Utility functions for generating static HTML pages.
|
||||
* @Dd April 27 2023
|
||||
*
|
||||
* .Nm
|
||||
* provides some simple macros and functions for generating HTML
|
||||
* pages. These are very specific to Telodendria, as they automatically
|
||||
* apply the color scheme and make assumptions about the stylesheets
|
||||
* and scripts included.
|
||||
* .Pp
|
||||
* The following macros are available:
|
||||
* .Bl -tag -width Ds
|
||||
* .It HtmlBeginJs(stream)
|
||||
* Begin JavaScript output. This sets up the opening script tags, and
|
||||
* licenses the following JavaScript under the MIT license.
|
||||
* .It HtmlEndJs(stream)
|
||||
* End JavaScript output.
|
||||
* .It HtmlBeginStyle(stream)
|
||||
* Begin CSS output. This sets up the opening syle tags.
|
||||
* .It HtmlEndStyle(stream)
|
||||
* End CSS output.
|
||||
* .It HtmlBeginForm(stream, id)
|
||||
* Begin a new form with the specified ID. This sets up the opening
|
||||
* form tags, which includes placing the form in a div with class
|
||||
* 'form'.
|
||||
* .It HtmlEndForm(stream)
|
||||
* End HTML form output.
|
||||
* .El
|
||||
*/
|
||||
|
||||
#include <Stream.h>
|
||||
|
||||
#define HtmlBeginJs(stream) StreamPuts(stream, \
|
||||
|
@ -46,10 +77,18 @@
|
|||
"<p id=\"error-msg\"></p>" \
|
||||
"</div>");
|
||||
|
||||
extern void
|
||||
HtmlBegin(Stream *, char *);
|
||||
/**
|
||||
* Initialize an HTML page by writing the head and the beginning of the
|
||||
* body. After this function is called, the page's main HTML can be
|
||||
* written. This function takes the name of the page it is beginning.
|
||||
* The name is placed in the title tags, and is used as the page
|
||||
* header.
|
||||
*/
|
||||
extern void HtmlBegin(Stream *, char *);
|
||||
|
||||
extern void
|
||||
HtmlEnd(Stream *);
|
||||
/**
|
||||
* Finish an HTML page by writing any necessary closing tags.
|
||||
*/
|
||||
extern void HtmlEnd(Stream *);
|
||||
|
||||
#endif /* TELODENDRIA_HTML_H */
|
||||
|
|
|
@ -109,25 +109,88 @@ extern void LogConfigUnindent(LogConfig *);
|
|||
*/
|
||||
extern void LogConfigIndentSet(LogConfig *, size_t);
|
||||
|
||||
extern void
|
||||
LogConfigOutputSet(LogConfig *, Stream *);
|
||||
/**
|
||||
* Set the file stream that logging output should be written to. This
|
||||
* defaults to standard output, but it can be set to standard error,
|
||||
* or any other arbitrary stream. Passing a NULL value for the stream
|
||||
* pointer sets the log output to the standard output. Note that the
|
||||
* output stream is only used if
|
||||
* .Va LOG_FLAG_SYSLOG
|
||||
* is not set.
|
||||
*/
|
||||
extern void LogConfigOutputSet(LogConfig *, Stream *);
|
||||
|
||||
extern void
|
||||
LogConfigFlagSet(LogConfig *, int);
|
||||
/**
|
||||
* Set a number of boolean options on a log configuration. This
|
||||
* function uses bitwise operators, so multiple options can be set with
|
||||
* a single function call using bitwise OR operators. The flags are
|
||||
* defined as preprocessor macros, and are as follows:
|
||||
* .Bl -tag -width Ds
|
||||
* .It LOG_FLAG_COLOR
|
||||
* When set, enable color-coded output on TTYs. Note that colors are
|
||||
* implemented as ANSI escape sequences, and are not written to file
|
||||
* streams that are not actually connected to a TTY, to prevent those
|
||||
* sequences from being written to a file.
|
||||
* .Xr isatty 3
|
||||
* is checked before writing any terminal sequences.
|
||||
* .It LOG_FLAG_SYSLOG
|
||||
* When set, log output to the syslog using
|
||||
* .Xr syslog 3 ,
|
||||
* instead of logging to the file set by
|
||||
* .Fn LogConfigOutputSet .
|
||||
* This flag always overrides the stream set by that function,
|
||||
* regardless of when it was set, even if it was set after this flag
|
||||
* was set.
|
||||
* .El
|
||||
*/
|
||||
extern void LogConfigFlagSet(LogConfig *, int);
|
||||
|
||||
extern void
|
||||
LogConfigFlagClear(LogConfig *, int);
|
||||
/**
|
||||
* Clear a boolean flag from the specified log format. See above for
|
||||
* the list of flags.
|
||||
*/
|
||||
extern void LogConfigFlagClear(LogConfig *, int);
|
||||
|
||||
extern void
|
||||
LogConfigTimeStampFormatSet(LogConfig *, char *);
|
||||
/**
|
||||
* Set a custom timestamp to be prepended to each message if the
|
||||
* output is not going to the system log. Consult your system's
|
||||
* documentation for
|
||||
* .Xr strftime 3 .
|
||||
* A value of NULL disables the timestamp output before messages.
|
||||
*/
|
||||
extern void LogConfigTimeStampFormatSet(LogConfig *, char *);
|
||||
|
||||
extern void
|
||||
Logv(LogConfig *, int, const char *, va_list);
|
||||
/**
|
||||
* This function does the actual logging of messages using a
|
||||
* specified configuration. It takes the configuration, the log
|
||||
* level, a format string, and then a list of arguments, all in that
|
||||
* order. This function only logs messages if their level is above
|
||||
* or equal to the currently configured log level, making it easy to
|
||||
* turn some messages on or off.
|
||||
* .Pp
|
||||
* This function has the same usage as
|
||||
* .Xr vprintf 3 .
|
||||
* Consult that page for the list of format specifiers and their
|
||||
* arguments. This function is typically not used directly, see the
|
||||
* other log functions for the most common use cases.
|
||||
*/
|
||||
extern void Logv(LogConfig *, int, const char *, va_list);
|
||||
|
||||
extern void
|
||||
LogTo(LogConfig *, int, const char *,...);
|
||||
/**
|
||||
* Log a message using
|
||||
* .Fn Logv .
|
||||
* with the specified configuration. This function has the same usage
|
||||
* as
|
||||
* .Xr printf 3 .
|
||||
*/
|
||||
extern void LogTo(LogConfig *, int, const char *, ...);
|
||||
|
||||
extern void
|
||||
Log(int, const char *,...);
|
||||
/**
|
||||
* Log a message to the global log using
|
||||
* .Fn Logv .
|
||||
* This function has the same usage as
|
||||
* .Xr printf 3 .
|
||||
*/
|
||||
extern void Log(int, const char *, ...);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,6 +24,18 @@
|
|||
#ifndef TELODENDRIA_MATRIX_H
|
||||
#define TELODENDRIA_MATRIX_H
|
||||
|
||||
/***
|
||||
* @Nm Matrix
|
||||
* @Nd Functions for writing Matrix API Endpoints.
|
||||
* @Dd March 6 2023
|
||||
* @Xr HttpServer Log Config Db
|
||||
*
|
||||
* .Nm
|
||||
* provides some helper functions that bind to the HttpServer API and
|
||||
* add basic Matrix functionality, turning an HTTP server into a
|
||||
* Matrix homeserver.
|
||||
*/
|
||||
|
||||
#include <HttpServer.h>
|
||||
#include <HttpRouter.h>
|
||||
#include <Log.h>
|
||||
|
@ -32,6 +44,12 @@
|
|||
#include <Config.h>
|
||||
#include <Db.h>
|
||||
|
||||
/**
|
||||
* The valid errors that can be used with
|
||||
* .Fn MatrixErrorCreate .
|
||||
* These values exactly follow the errors defined in the Matrix
|
||||
* specification.
|
||||
*/
|
||||
typedef enum MatrixError
|
||||
{
|
||||
M_FORBIDDEN,
|
||||
|
@ -68,25 +86,70 @@ typedef enum MatrixError
|
|||
M_CANNOT_LEAVE_SERVER_NOTICE_ROOM
|
||||
} MatrixError;
|
||||
|
||||
/**
|
||||
* The arguments that should be passed through the void pointer to the
|
||||
* .Fn MatrixHttpHandler
|
||||
* function. This structure should be populated once, and then never
|
||||
* modified again for the duration of the HTTP server.
|
||||
*/
|
||||
typedef struct MatrixHttpHandlerArgs
|
||||
{
|
||||
Db *db;
|
||||
HttpRouter *router;
|
||||
} MatrixHttpHandlerArgs;
|
||||
|
||||
extern void
|
||||
MatrixHttpHandler(HttpServerContext *, void *);
|
||||
/**
|
||||
* The HTTP handler function that handles all Matrix homeserver
|
||||
* functionality. It should be passed into
|
||||
* .Fn HttpServerCreate ,
|
||||
* and it expects that a pointer to a MatrixHttpHandlerArgs
|
||||
* will be provided, because that is what the void pointer is
|
||||
* cast to.
|
||||
*/
|
||||
extern void MatrixHttpHandler(HttpServerContext *, void *);
|
||||
|
||||
extern HashMap *
|
||||
MatrixErrorCreate(MatrixError);
|
||||
/**
|
||||
* A convenience function that constructs an error payload, including
|
||||
* the error code and message, given just a MatrixError.
|
||||
*/
|
||||
extern HashMap * MatrixErrorCreate(MatrixError);
|
||||
|
||||
extern HashMap *
|
||||
MatrixGetAccessToken(HttpServerContext *, char **);
|
||||
/**
|
||||
* Read the request headers and parameters, and attempt to obtain an
|
||||
* access token from them. The Matrix specification says that an access
|
||||
* token can either be provided via the Authorization header, or in a
|
||||
* .Sy GET
|
||||
* parameter. This function checks both, and stores the access token it
|
||||
* finds in the passed character pointer.
|
||||
* .Pp
|
||||
* The specification does not say whether the header or parameter
|
||||
* should be preferred if both are provided. This function prefers the
|
||||
* header.
|
||||
* .Pp
|
||||
* If this function returns a non-NULL value, then the return value
|
||||
* should be immediately passed along to the client and no further
|
||||
* logic should be performed.
|
||||
*/
|
||||
extern HashMap * MatrixGetAccessToken(HttpServerContext *, char **);
|
||||
|
||||
extern HashMap *
|
||||
MatrixRateLimit(HttpServerContext *, Db *);
|
||||
/**
|
||||
* Determine whether or not the request should be rate limited. It is
|
||||
* expected that this function will be called before most, if not all
|
||||
* of the caller's logic.
|
||||
* .Pp
|
||||
* If this function returns a non-NULL value, then the return value
|
||||
* should be immediately passed along to the client and no further
|
||||
* logic should be performed.
|
||||
*/
|
||||
extern HashMap * MatrixRateLimit(HttpServerContext *, Db *);
|
||||
|
||||
extern HashMap *
|
||||
MatrixClientWellKnown(char *, char *);
|
||||
/**
|
||||
* Build a ``well-known'' JSON object, which contains information
|
||||
* about the homeserver base URL and identity server, both of which
|
||||
* should be provided by the caller in that order. This object can be
|
||||
* sent to a client as-is, or it can be added as a value nested inside
|
||||
* of a more complex response. Both occur in the Matrix specification.
|
||||
*/
|
||||
extern HashMap * MatrixClientWellKnown(char *, char *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,8 +24,63 @@
|
|||
#ifndef TELODENDRIA_MEMORY_H
|
||||
#define TELODENDRIA_MEMORY_H
|
||||
|
||||
/***
|
||||
* @Nm Memory
|
||||
* @Nd Smart memory management.
|
||||
* @Dd January 9 2023
|
||||
*
|
||||
* .Nm
|
||||
* is an API that allows for smart memory management and profiling. It
|
||||
* wraps the standard library functions
|
||||
* .Xr malloc 3 ,
|
||||
* .Xr realloc 3 ,
|
||||
* and
|
||||
* .Xr free 3 ,
|
||||
* and offers identical semantics, while providing functionality that
|
||||
* the standard library doesn't have, such as getting statistics on the
|
||||
* total memory allocated on the heap, and getting the size of a block
|
||||
* given a pointer. Additionally, thanks to preprocessor macros, the
|
||||
* exact file and line number at which an allocation, re-allocation, or
|
||||
* free occured can be obtained given a pointer. Finally, all the
|
||||
* blocks allocated on the heap can be iterated and evaluated, and a
|
||||
* callback function can be executed every time a memory operation
|
||||
* occurs.
|
||||
* .Pp
|
||||
* In the future, this API could include a garbage collector that
|
||||
* automatically frees memory it detects as being no longer in use.
|
||||
* However, this feature does not yet exist.
|
||||
* .Pp
|
||||
* A number of macros are available, which make the
|
||||
* .Nm
|
||||
* API much easier to use. They are as follows:
|
||||
* .Bl -bullet -offset indent
|
||||
* .It
|
||||
* .Fn Malloc "x"
|
||||
* .It
|
||||
* .Fn Realloc "x" "y"
|
||||
* .It
|
||||
* .Fn Free "x"
|
||||
* .El
|
||||
* .Pp
|
||||
* These macros expand to
|
||||
* .Fn MemoryAllocate ,
|
||||
* .Fn MemoryReallocate ,
|
||||
* and
|
||||
* .Fn MemoryFree
|
||||
* with the second and third parameters set to __FILE__ and __LINE__.
|
||||
* This allows
|
||||
* .Nm
|
||||
* to be used exactly how the standard library functions would be
|
||||
* used. In fact, the functions to which these macros expand are not
|
||||
* intended to be used directly; for the best results, use these
|
||||
* macros.
|
||||
*/
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* These values are passed into the memory hook function to indicate
|
||||
* the action that just happened.
|
||||
*/
|
||||
typedef enum MemoryAction
|
||||
{
|
||||
MEMORY_ALLOCATE,
|
||||
|
@ -38,45 +93,133 @@ typedef enum MemoryAction
|
|||
#define Realloc(x, s) MemoryReallocate(x, s, __FILE__, __LINE__)
|
||||
#define Free(x) MemoryFree(x, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* The memory information is opaque, but can be accessed using the
|
||||
* functions defined by this API.
|
||||
*/
|
||||
typedef struct MemoryInfo MemoryInfo;
|
||||
|
||||
extern void *
|
||||
MemoryAllocate(size_t, const char *, int);
|
||||
/**
|
||||
* Allocate the specified number of bytes on the heap. This function
|
||||
* has the same semantics as
|
||||
* .Xr malloc 3 ,
|
||||
* except that it takes the file name and line number at which the
|
||||
* allocation occurred.
|
||||
*/
|
||||
extern void * MemoryAllocate(size_t, const char *, int);
|
||||
|
||||
extern void *
|
||||
MemoryReallocate(void *, size_t, const char *, int);
|
||||
/**
|
||||
* Change the size of the object pointed to by the given pointer
|
||||
* to the given number of bytes. This function has the same semantics
|
||||
* as
|
||||
* .Xr realloc 3 ,
|
||||
* except that it takes the file name and line number at which the
|
||||
* reallocation occurred.
|
||||
*/
|
||||
extern void * MemoryReallocate(void *, size_t, const char *, int);
|
||||
|
||||
/**
|
||||
* Free the memory at the given pointer. This function has the same
|
||||
* semantics as
|
||||
* .Xr free 3 ,
|
||||
* except that it takes the file name and line number at which the
|
||||
* free occurred.
|
||||
*/
|
||||
extern void MemoryFree(void *, const char *, int);
|
||||
|
||||
/**
|
||||
* Get the total number of bytes that the program has allocated on the
|
||||
* heap. This operation iterates over all heap allocations made with
|
||||
* .Fn MemoryAllocate
|
||||
* and then returns a total count, in bytes.
|
||||
*/
|
||||
extern size_t MemoryAllocated(void);
|
||||
|
||||
/**
|
||||
* Iterate over all heap allocations made with
|
||||
* .Fn MemoryAllocate
|
||||
* and call
|
||||
* .Fn MemoryFree
|
||||
* on them. This function immediately invalidates all pointers to
|
||||
* blocks on the heap, and any subsequent attempt to read or write to
|
||||
* data on the heap will result in undefined behavior. This is
|
||||
* typically called at the end of the program, just before exit.
|
||||
*/
|
||||
extern void MemoryFreeAll(void);
|
||||
|
||||
/**
|
||||
* Fetch information about an allocation. This function takes a raw
|
||||
* pointer, and if
|
||||
* . Nm
|
||||
* knows about the pointer, it returns a structure that can be used
|
||||
* to obtain information about the block of memory that the pointer
|
||||
* points to.
|
||||
*/
|
||||
extern MemoryInfo * MemoryInfoGet(void *);
|
||||
|
||||
/**
|
||||
* Get the size in bytes of the block of memory represented by the
|
||||
* specified memory info structure.
|
||||
*/
|
||||
extern size_t MemoryInfoGetSize(MemoryInfo *);
|
||||
|
||||
/**
|
||||
* Get the file name in which the block of memory represented by the
|
||||
* specified memory info structure was allocated.
|
||||
*/
|
||||
extern const char * MemoryInfoGetFile(MemoryInfo *);
|
||||
|
||||
/**
|
||||
* Get the line number on which the block of memory represented by the
|
||||
* specified memory info structure was allocated.
|
||||
*/
|
||||
extern int MemoryInfoGetLine(MemoryInfo *);
|
||||
|
||||
/**
|
||||
* Get a pointer to the block of memory represented by the specified
|
||||
* memory info structure.
|
||||
*/
|
||||
extern void * MemoryInfoGetPointer(MemoryInfo *);
|
||||
|
||||
/**
|
||||
* This function takes a pointer to a function that takes the memory
|
||||
* info structure, as well as a void pointer for caller-provided
|
||||
* arguments. It iterates over all the heap memory currently allocated
|
||||
* at the time of calling, executing the function on each allocation.
|
||||
*/
|
||||
extern void MemoryIterate(void (*) (MemoryInfo *, void *), void *);
|
||||
|
||||
/**
|
||||
* Specify a function to be executed whenever a memory operation
|
||||
* occurs. The MemoryAction argument specifies the operation that
|
||||
* occurred on the block of memory represented by the memory info
|
||||
* structure. The function also takes a void pointer to caller-provided
|
||||
* arguments.
|
||||
*/
|
||||
extern void MemoryHook(void (*) (MemoryAction, MemoryInfo *, void *), void *);
|
||||
|
||||
/**
|
||||
* Read over the block of memory represented by the given memory info
|
||||
* structure and generate a hexadecimal and ASCII string for each
|
||||
* chunk of the block. This function takes a callback function that
|
||||
* takes the following parameters in order:
|
||||
* .Bl -bullet -offset indent
|
||||
* .It
|
||||
* The current offset from the beginning of the block of memory in
|
||||
* bytes.
|
||||
* .It
|
||||
* A null-terminated string containing the next 16 bytes of the block
|
||||
* encoded as space-separated hex values.
|
||||
* .It
|
||||
* A null-terminated string containing the ASCII representation of the
|
||||
* same 16 bytes of memory. This ASCII representation is safe to print
|
||||
* to a terminal or other text device, because non-printable characters
|
||||
* are encoded as a . (period).
|
||||
* .It
|
||||
* Caller-passed pointer.
|
||||
* .El
|
||||
*/
|
||||
extern void
|
||||
MemoryFree(void *, const char *, int);
|
||||
|
||||
extern size_t
|
||||
MemoryAllocated(void);
|
||||
|
||||
extern void
|
||||
MemoryFreeAll(void);
|
||||
|
||||
extern MemoryInfo *
|
||||
MemoryInfoGet(void *);
|
||||
|
||||
extern size_t
|
||||
MemoryInfoGetSize(MemoryInfo *);
|
||||
|
||||
extern const char *
|
||||
MemoryInfoGetFile(MemoryInfo *);
|
||||
|
||||
extern int
|
||||
MemoryInfoGetLine(MemoryInfo *);
|
||||
|
||||
extern void *
|
||||
MemoryInfoGetPointer(MemoryInfo *);
|
||||
|
||||
extern void
|
||||
MemoryIterate(void (*) (MemoryInfo *, void *), void *);
|
||||
|
||||
extern void
|
||||
MemoryHook(void (*) (MemoryAction, MemoryInfo *, void *), void *);
|
||||
|
||||
extern void
|
||||
MemoryHexDump(MemoryInfo *, void (*) (size_t, char *, char *, void *), void *);
|
||||
MemoryHexDump(MemoryInfo *, void (*) (size_t, char *, char *, void *), void *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,29 +24,82 @@
|
|||
#ifndef TELODENDRIA_QUEUE_H
|
||||
#define TELODENDRIA_QUEUE_H
|
||||
|
||||
/***
|
||||
* @Nm Queue
|
||||
* @Nd A simple static queue data structure.
|
||||
* @Dd November 25 2022
|
||||
* @Xr Array HashMap
|
||||
*
|
||||
* .Nm
|
||||
* implements a simple queue data structure that is statically sized.
|
||||
* This implementation does not actually store the values of the items
|
||||
* in it; it only stores pointers to the data. As such, you will have
|
||||
* to manually maintain data and make sure it remains valid as long as
|
||||
* it is in the queue. The advantage of this is that
|
||||
* .Nm
|
||||
* doesn't have to copy data, and thus doesn't care how big the data
|
||||
* is. Furthermore, any arbitrary data can be stored in the queue.
|
||||
* .Pp
|
||||
* This queue implementation operates on the heap. It is a circular
|
||||
* queue, and it does not grow as it is used. Once the size is set,
|
||||
* the queue never gets any bigger.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* These functions operate on a queue structure that is opaque to the
|
||||
* caller.
|
||||
*/
|
||||
typedef struct Queue Queue;
|
||||
|
||||
extern Queue *
|
||||
QueueCreate(size_t);
|
||||
/**
|
||||
* Allocate a new queue that is able to store the specified number of
|
||||
* items in it.
|
||||
*/
|
||||
extern Queue * QueueCreate(size_t);
|
||||
|
||||
extern void
|
||||
QueueFree(Queue *);
|
||||
/**
|
||||
* Free the memory associated with the specified queue structure. Note
|
||||
* that this function does not free any of the values stored in the
|
||||
* queue; it is the caller's job to manage memory for each item.
|
||||
* Typically, the caller would dequeue all the items in the queue and
|
||||
* deal with them before freeing the queue itself.
|
||||
*/
|
||||
extern void QueueFree(Queue *);
|
||||
|
||||
extern int
|
||||
QueuePush(Queue *, void *);
|
||||
/**
|
||||
* Push an element into the queue. This function returns a boolean
|
||||
* value indicating whether or not the push succeeded. Pushing items
|
||||
* into the queue will fail if the queue is full.
|
||||
*/
|
||||
extern int QueuePush(Queue *, void *);
|
||||
|
||||
extern void *
|
||||
QueuePop(Queue *);
|
||||
/**
|
||||
* Pop an element out of the queue. This function returns NULL if the
|
||||
* queue is empty. Otherwise, it returns a pointer to the item that is
|
||||
* next up in the queue.
|
||||
*/
|
||||
extern void * QueuePop(Queue *);
|
||||
|
||||
extern void *
|
||||
QueuePeek(Queue *);
|
||||
/**
|
||||
* Retrieve a pointer to the item that is next up in the queue without
|
||||
* actually discarding it, such that the next call to
|
||||
* .Fn QueuePeek
|
||||
* or
|
||||
* .Fn QueuePop
|
||||
* will return the same pointer.
|
||||
*/
|
||||
extern void * QueuePeek(Queue *);
|
||||
|
||||
extern int
|
||||
QueueFull(Queue *);
|
||||
/**
|
||||
* Determine whether or not the queue is full.
|
||||
*/
|
||||
extern int QueueFull(Queue *);
|
||||
|
||||
extern int
|
||||
QueueEmpty(Queue *);
|
||||
/**
|
||||
* Determine whether or not the queue is empty.
|
||||
*/
|
||||
extern int QueueEmpty(Queue *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,12 +24,58 @@
|
|||
|
||||
#ifndef TELODENDRIA_RAND_H
|
||||
#define TELODENDRIA_RAND_H
|
||||
|
||||
/***
|
||||
* @Nm Rand
|
||||
* @Nd Thread-safe random numbers.
|
||||
* @Dd February 16 2023
|
||||
* @Xr Util
|
||||
*
|
||||
* .Nm
|
||||
* is used for generating random numbers in a thread-safe way.
|
||||
* Currently, one generator state is shared across all threads, which
|
||||
* means that only one thread can generate random numbers at a time.
|
||||
* This state is protected with a mutex to guarantee this behavior.
|
||||
* In the future, a seed pool may be maintained to allow multiple
|
||||
* threads to generate random numbers at the same time.
|
||||
* .Pp
|
||||
* The generator state is seeded on the first call to a function that
|
||||
* needs it. The seed is determined by the current timestamp, the ID
|
||||
* of the process, and the thread ID. These should all be sufficiently
|
||||
* random sources, so the seed should be secure enough.
|
||||
* .Pp
|
||||
* .Nm
|
||||
* currently uses a simple Mersenne Twister algorithm to generate
|
||||
* random numbers. This algorithm was chosen because it is extremely
|
||||
* popular and widespread. While it is likely not cryptographically
|
||||
* secure, and does suffer some unfortunate pitfalls, this algorithm
|
||||
* has stood the test of time and is simple enough to implement, so
|
||||
* it was chosen over the alternatives.
|
||||
* .Pp
|
||||
* .Nm
|
||||
* does not use any random number generator functions from the C
|
||||
* standard library, since these are often flawed.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
extern int
|
||||
RandInt(unsigned int);
|
||||
/**
|
||||
* Generate a single random integer between 0 and the passed value.
|
||||
*/
|
||||
extern int RandInt(unsigned int);
|
||||
|
||||
extern void
|
||||
RandIntN(int *, size_t, unsigned int);
|
||||
/**
|
||||
* Generate the number of integers specified by the second argument
|
||||
* storing them into the buffer pointed to in the first argument.
|
||||
* Ensure that each number is between 0 and the third argument.
|
||||
* .Pp
|
||||
* This function allows a caller to get multiple random numbers at once
|
||||
* in a more efficient manner than repeatedly calling
|
||||
* .Fn RandInt ,
|
||||
* since each call to these functions
|
||||
* has to lock and unlock a mutex. It is therefore better to obtain
|
||||
* multiple random numbers in one pass if multiple are needed.
|
||||
*/
|
||||
extern void RandIntN(int *, size_t, unsigned int);
|
||||
|
||||
#endif /* TELODENDRIA_RAND_H */
|
||||
|
|
|
@ -24,7 +24,19 @@
|
|||
#ifndef TELODENDRIA_ROUTES_H
|
||||
#define TELODENDRIA_ROUTES_H
|
||||
|
||||
#include <string.h>
|
||||
/***
|
||||
* @Nm Routes
|
||||
* @Nd Matrix API endpoint handler functions.
|
||||
* @Dd April 28 2023
|
||||
* @Xr Matrix HttpRouter
|
||||
*
|
||||
* .Nm
|
||||
* provides all of the Matrix API route functions, which for the sake
|
||||
* of brevity are not documented here---consult the official Matrix
|
||||
* specification for documentation on Matrix routes and the
|
||||
* .Xr telodendria-admin
|
||||
* page for admin API routes.
|
||||
*/
|
||||
|
||||
#include <HashMap.h>
|
||||
#include <Array.h>
|
||||
|
@ -32,25 +44,34 @@
|
|||
#include <HttpRouter.h>
|
||||
#include <Matrix.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define MATRIX_PATH_EQUALS(pathPart, str) \
|
||||
((pathPart != NULL) && (strcmp(pathPart, str) == 0))
|
||||
|
||||
/**
|
||||
* Every route function takes this structure, which contains the data
|
||||
* it needs to successfully handle an API request.
|
||||
*/
|
||||
typedef struct RouteArgs
|
||||
{
|
||||
MatrixHttpHandlerArgs *matrixArgs;
|
||||
HttpServerContext *context;
|
||||
} RouteArgs;
|
||||
|
||||
HttpRouter *
|
||||
RouterBuild(void);
|
||||
/**
|
||||
* Build an HTTP router that sets up all the route functions to be
|
||||
* executed at the correct HTTP paths.
|
||||
*/
|
||||
extern HttpRouter * RouterBuild(void);
|
||||
|
||||
#define ROUTE(name) \
|
||||
extern void * \
|
||||
name(Array *, void *)
|
||||
|
||||
#define ROUTE_IMPL(name, matchesName, argsName) \
|
||||
#define ROUTE_IMPL(name, path, args) \
|
||||
void * \
|
||||
name(Array * matchesName, void * argsName)
|
||||
name(Array * path, void * args)
|
||||
|
||||
ROUTE(RouteVersions);
|
||||
ROUTE(RouteWellKnown);
|
||||
|
|
|
@ -24,24 +24,68 @@
|
|||
#ifndef TELODENDRIA_STR_H
|
||||
#define TELODENDRIA_STR_H
|
||||
|
||||
/***
|
||||
* @Nm Str
|
||||
* @Nd Functions for creating and manipulating strings.
|
||||
* @Dd February 15 2023
|
||||
* @Xr Memory
|
||||
*
|
||||
* .Nm
|
||||
* provides string-related functions. It is called
|
||||
* .Nm ,
|
||||
* not String, because some platforms (Windows) do not have
|
||||
* case-sensitive filesystems, which poses a problem since
|
||||
* .Pa string.h
|
||||
* is a standard library header.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
extern char *
|
||||
StrUtf8Encode(unsigned long);
|
||||
/**
|
||||
* Take a UTF-8 codepoint and encode it into a string buffer containing
|
||||
* between 1 and 4 bytes. The string buffer is allocated on the heap,
|
||||
* so it should be freed when it is no longer needed.
|
||||
*/
|
||||
extern char * StrUtf8Encode(unsigned long);
|
||||
|
||||
extern char *
|
||||
StrDuplicate(const char *);
|
||||
/**
|
||||
* Duplicate a null-terminated string, returning a new string on the
|
||||
* heap. This is useful when a function takes in a string that it needs
|
||||
* to store for long amounts of time, even perhaps after the original
|
||||
* string is gone.
|
||||
*/
|
||||
extern char * StrDuplicate(const char *);
|
||||
|
||||
extern char *
|
||||
StrSubstr(const char *, size_t, size_t);
|
||||
/**
|
||||
* Extract part of a null-terminated string, returning a new string on
|
||||
* the heap containing only the requested subsection. Like the
|
||||
* substring functions included with most programming languages, the
|
||||
* starting index is inclusive, and the ending index is exclusive.
|
||||
*/
|
||||
extern char * StrSubstr(const char *, size_t, size_t);
|
||||
|
||||
extern char *
|
||||
StrConcat(size_t,...);
|
||||
/**
|
||||
* A varargs function that takes a number of null-terminated strings
|
||||
* specified by the first argument, and returns a new string that
|
||||
* contains their concatenation. It works similarly to
|
||||
* .Xr strcat 3 ,
|
||||
* but it takes care of allocating memory big enough to hold all the
|
||||
* strings. Any string in the list may be NULL. If a NULL pointer is
|
||||
* passed, it is treated like an empty string.
|
||||
*/
|
||||
extern char * StrConcat(size_t,...);
|
||||
|
||||
extern int
|
||||
StrBlank(const char *str);
|
||||
/**
|
||||
* Return a boolean value indicating whether or not the null-terminated
|
||||
* string consists only of blank characters, as determined by
|
||||
* .Xr isblank 3 .
|
||||
*/
|
||||
extern int StrBlank(const char *str);
|
||||
|
||||
extern char *
|
||||
StrRandom(size_t);
|
||||
/**
|
||||
* Generate a string of the specified length, containing random
|
||||
* lowercase and uppercase letters.
|
||||
*/
|
||||
extern char * StrRandom(size_t);
|
||||
|
||||
#endif /* TELODENDRIA_STR_H */
|
||||
|
|
|
@ -24,26 +24,121 @@
|
|||
#ifndef TELODENDRIA_UIA_H
|
||||
#define TELODENDRIA_UIA_H
|
||||
|
||||
/***
|
||||
* @Nm Uia
|
||||
* @Nd User Interactive Authentication.
|
||||
* @Dd April 28 2023
|
||||
* @Xr User Db Cron
|
||||
*
|
||||
* .Nm
|
||||
* takes care of all the logic for performing user interactive
|
||||
* authentication as defined by the Matrix specification. API endpoints
|
||||
* that require authentication via user interactive authentication
|
||||
* build up flows and add any necessary parameters, and pass them all
|
||||
* into
|
||||
* .Fn UiaComplete .
|
||||
* The goal is to make it easy for the numerous API endpoints that
|
||||
* utilize this authentication mechanism to implement it.
|
||||
*/
|
||||
|
||||
#include <Array.h>
|
||||
#include <HashMap.h>
|
||||
#include <HttpServer.h>
|
||||
#include <Matrix.h>
|
||||
|
||||
/**
|
||||
* An opaque structure that represents a single stage, which consists
|
||||
* of the type and a JSON object that contains implementation-specific
|
||||
* parameters for completing the stage.
|
||||
*/
|
||||
typedef struct UiaStage UiaStage;
|
||||
|
||||
extern UiaStage *
|
||||
UiaStageBuild(char *, HashMap *);
|
||||
/**
|
||||
* Build a single stage with the type and a JSON object of parameters
|
||||
* the client may require to complete it. Consult the Matrix
|
||||
* specification for the valid types.
|
||||
*/
|
||||
extern UiaStage * UiaStageBuild(char *, HashMap *);
|
||||
|
||||
extern Array *
|
||||
UiaDummyFlow(void);
|
||||
/**
|
||||
* Build a flow that consists only of a dummy stage. This is useful
|
||||
* when an endpoint is required by the specification to use user
|
||||
* interactive authentication, but doesn't want to actually require
|
||||
* the user to do anything. Since the dummy flow is a fairly common
|
||||
* flow, it seemed sensible to have a function for it. Other flows are
|
||||
* built manually by the caller that that wishes to perform user
|
||||
* interactive authentication.
|
||||
*/
|
||||
extern Array * UiaDummyFlow(void);
|
||||
|
||||
extern void
|
||||
UiaCleanup(MatrixHttpHandlerArgs *);
|
||||
/**
|
||||
* This function should be called periodically to purge old sessions.
|
||||
* Sessions are only valid for a few minutes after their last access.
|
||||
* After that, they should be purged so that the database doesn't fill
|
||||
* up with old session files. This function is specifically designed
|
||||
* to be called via the Cron API.
|
||||
*/
|
||||
extern void UiaCleanup(MatrixHttpHandlerArgs *);
|
||||
|
||||
/**
|
||||
* Validate an auth object and maintain session state to track the
|
||||
* progress of a client through user interactive authentication flows.
|
||||
* The idea is that an API endpoint will not progress until user
|
||||
* interactive authentication has succeeded.
|
||||
* .Pp
|
||||
* This function does the bulk of the work for user interactive
|
||||
* authentication. It takes many parameters:
|
||||
* .Bl -bullet -offset indent
|
||||
* .It
|
||||
* An array of arrays of stages. Stages should be created with
|
||||
* .Fn UiaStageBuild
|
||||
* and then put into an array to create a flow. Those flows should then
|
||||
* be put into an array and passed as this parameter. It is important
|
||||
* to note here that because of the loose typing of the Array API, it
|
||||
* is very easy to make mistakes here; if you are implementing a new
|
||||
* endpoint that requires user interactive authentication, it is best
|
||||
* to refer to the source code of an existing endpoint to get a better
|
||||
* idea of how it works.
|
||||
* .It
|
||||
* An HTTP server context. This is required to set the response headers
|
||||
* in the even of an error.
|
||||
* .It
|
||||
* The database where user interactive authentication sessions are
|
||||
* persisted.
|
||||
* .It
|
||||
* The JSON request body that contains the client's auth object, which
|
||||
* will be read, parsed, and handled as appropriate.
|
||||
* .It
|
||||
* A pointer to a pointer where a JSON response can be placed if
|
||||
* necessary. If this function encounters a client error, such as a
|
||||
* failure to authenticate, or outstanding stages that have not yet
|
||||
* been completed, it will place a JSON response here that is expected
|
||||
* to be returned to the client. This response will include a
|
||||
* description of all the flows, stages, and the stage parameters.
|
||||
* .It
|
||||
* A valid configuration structure, because a few values are read from
|
||||
* the configuration during certain stages of authentication.
|
||||
* .El
|
||||
* .Pp
|
||||
* This function returns an integer value less than zero if it
|
||||
* experiences an internal failure, such as a failure to allocate
|
||||
* memory memory, or a corrupted database. It returns 0 if the client
|
||||
* has remaining stages to complete, including the current stage if
|
||||
* that one did not complete successfully. In this case, this function
|
||||
* will set the proper response headers and the passed response
|
||||
* pointer, so the caller should immediately return the response to
|
||||
* the client. This function returns 1 if and only if the client has
|
||||
* successfully completed all stages. Only in this latter case shall
|
||||
* the caller proceed with its logic.
|
||||
*/
|
||||
extern int
|
||||
UiaComplete(Array *, HttpServerContext *, Db *, HashMap *, HashMap **, Config *);
|
||||
|
||||
extern void
|
||||
UiaFlowsFree(Array *);
|
||||
/**
|
||||
* Free an array of flows, as described above. Even though the caller
|
||||
* constructs this array, it is convenient to free it in its
|
||||
* entirety in a single function call.
|
||||
*/
|
||||
extern void UiaFlowsFree(Array *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,21 +24,50 @@
|
|||
#ifndef TELODENDRIA_USER_H
|
||||
#define TELODENDRIA_USER_H
|
||||
|
||||
/***
|
||||
* @Nm User
|
||||
* @Nd Convenience functions for working with local users.
|
||||
* @Dd April 28 2023
|
||||
* @Xr Db
|
||||
*
|
||||
* The
|
||||
* .Nm
|
||||
* API provides a wrapper over the database and offers an easy way to
|
||||
* manage local users. It supports all of the locking mechanisms that
|
||||
* the database does, and provides features for authenticating local
|
||||
* users, among many other tasks.
|
||||
*/
|
||||
|
||||
#include <Db.h>
|
||||
|
||||
#include <Json.h>
|
||||
|
||||
#define USER_DEACTIVATE (1 << 0)
|
||||
#define USER_ISSUE_TOKENS (1 << 1)
|
||||
#define USER_CONFIG (1 << 2)
|
||||
#define USER_GRANT_PRIVILEGES (1 << 3)
|
||||
#define USER_PROC_CONTROL (1 << 4)
|
||||
|
||||
#define USER_NONE 0
|
||||
#define USER_ALL ((1 << 5) - 1)
|
||||
|
||||
/**
|
||||
* Many functions here operate on an opaque user structure.
|
||||
*/
|
||||
typedef struct User User;
|
||||
|
||||
/**
|
||||
* Local users can have privileges to access the administrator API.
|
||||
* These are the individual privileges that Telodendria supports.
|
||||
* Note that they are bit flags, so they can be bitwise OR-ed together
|
||||
* to have multiple privileges.
|
||||
*/
|
||||
typedef enum UserPrivileges
|
||||
{
|
||||
USER_NONE = 0,
|
||||
USER_DEACTIVATE = (1 << 0),
|
||||
USER_ISSUE_TOKENS = (1 << 1),
|
||||
USER_CONFIG = (1 << 2),
|
||||
USER_GRANT_PRIVILEGES = (1 << 3),
|
||||
USER_PROC_CONTROL = (1 << 4),
|
||||
USER_ALL = ((1 << 5) - 1)
|
||||
} UserPrivileges;
|
||||
|
||||
/**
|
||||
* A description of an access token, which users use to authenticate
|
||||
* with the client-server API.
|
||||
*/
|
||||
typedef struct UserAccessToken
|
||||
{
|
||||
char *user;
|
||||
|
@ -47,95 +76,214 @@ typedef struct UserAccessToken
|
|||
long lifetime;
|
||||
} UserAccessToken;
|
||||
|
||||
/**
|
||||
* Login information, which is in most cases returned to the user
|
||||
* upon a successful login.
|
||||
*/
|
||||
typedef struct UserLoginInfo
|
||||
{
|
||||
UserAccessToken *accessToken;
|
||||
char *refreshToken;
|
||||
} UserLoginInfo;
|
||||
|
||||
/**
|
||||
* A description of a Matrix user ID.
|
||||
*/
|
||||
typedef struct UserId
|
||||
{
|
||||
char *localpart;
|
||||
char *server;
|
||||
} UserId;
|
||||
|
||||
extern int
|
||||
UserValidate(char *, char *);
|
||||
/**
|
||||
* Take a localpart and domain as separate parameters and validate them
|
||||
* against the rules of the Matrix specification. The reasion the
|
||||
* domain is required is because the spec imposes limitations on the
|
||||
* length of the user ID, so the longer the domain name is, the shorter
|
||||
* the local part is allowed to be. This function is used to ensure
|
||||
* that client-provided Matrix IDs are valid on this server.
|
||||
*/
|
||||
extern int UserValidate(char *, char *);
|
||||
|
||||
extern int
|
||||
UserHistoricalValidate(char *, char *);
|
||||
/**
|
||||
* This function behaves just like
|
||||
* .Fn UserValidate ,
|
||||
* except that it is a little more lenient in what is considers to be
|
||||
* a valid Matrix ID. This is typically to validate users that exist
|
||||
* on other servers, since some usernames may exist that are not fully
|
||||
* spec compliant but remain in use since before the new restrictions
|
||||
* were put in place.
|
||||
*/
|
||||
extern int UserHistoricalValidate(char *, char *);
|
||||
|
||||
extern int
|
||||
UserExists(Db *, char *);
|
||||
/**
|
||||
* Determine whether the user identified by the specified localpart
|
||||
* exists in the database.
|
||||
*/
|
||||
extern int UserExists(Db *, char *);
|
||||
|
||||
extern User *
|
||||
UserCreate(Db *, char *, char *);
|
||||
/**
|
||||
* Create a new user with the specified localpart and password, in
|
||||
* that order.
|
||||
*/
|
||||
extern User * UserCreate(Db *, char *, char *);
|
||||
|
||||
extern User *
|
||||
UserLock(Db *, char *);
|
||||
/**
|
||||
* Take a localpart and obtain a database reference to the user
|
||||
* identified by that localpart. This function behaves analogously
|
||||
* to
|
||||
* .Fn DbLock ,
|
||||
* and in fact it uses it under the hood to ensure that the user can
|
||||
* only be modified by the thread that has locked it.
|
||||
*/
|
||||
extern User * UserLock(Db *, char *);
|
||||
|
||||
extern User *
|
||||
UserAuthenticate(Db *, char *);
|
||||
/**
|
||||
* Take an access token, figure out what user it belongs to, and then
|
||||
* returns a reference to that user. This function should be used by
|
||||
* most endpoints that require user authentication, since most
|
||||
* endpoints are authenticated via access tokens.
|
||||
*/
|
||||
extern User * UserAuthenticate(Db *, char *);
|
||||
|
||||
extern int
|
||||
UserUnlock(User *);
|
||||
/**
|
||||
* Return a user reference back to the database. This function uses
|
||||
* .Fn DbUnlock
|
||||
* under the hood.
|
||||
*/
|
||||
extern int UserUnlock(User *);
|
||||
|
||||
extern UserLoginInfo *
|
||||
UserLogin(User *, char *, char *, char *, int);
|
||||
/**
|
||||
* Log in a user. This function takes the user's password, desired
|
||||
* device ID and display name, and a boolean value indicating whether
|
||||
* or not the client supports refresh tokens. This function logs the
|
||||
* the user in and generates an access token to be returned to the
|
||||
* client.
|
||||
*/
|
||||
extern UserLoginInfo * UserLogin(User *, char *, char *, char *, int);
|
||||
|
||||
extern char *
|
||||
UserGetName(User *);
|
||||
/**
|
||||
* Get the localpart attached to a user object. This function may be
|
||||
* useful in the few cases where the localpart is not known already.
|
||||
*/
|
||||
extern char * UserGetName(User *);
|
||||
|
||||
extern int
|
||||
UserCheckPassword(User *, char *);
|
||||
/**
|
||||
* Take a password and verify it against a user object. Telodendria
|
||||
* does not store passwords in plain text, so this function hashes the
|
||||
* password and checks it against what is stored in the database.
|
||||
*/
|
||||
extern int UserCheckPassword(User *, char *);
|
||||
|
||||
extern int
|
||||
UserSetPassword(User *, char *);
|
||||
/**
|
||||
* Reset the given user's password by hashing a plain text password and
|
||||
* storing it in the database.
|
||||
*/
|
||||
extern int UserSetPassword(User *, char *);
|
||||
|
||||
extern int
|
||||
UserDeactivate(User *);
|
||||
|
||||
extern int
|
||||
UserDeactivated(User *);
|
||||
/**
|
||||
* Immediately deactivate the given user account such that it can no
|
||||
* longer be used to log in, but the username is still reserved. This
|
||||
* is to prevent future users from pretending to be a previous user
|
||||
* of a given localpart. The user is logged out; all access tokens are
|
||||
* invalidated.
|
||||
*/
|
||||
extern int UserDeactivated(User *);
|
||||
|
||||
extern HashMap *
|
||||
UserGetDevices(User *);
|
||||
/**
|
||||
* Fetches the devices that belong to the user, in JSON format,
|
||||
* identical to what's stored in the database. In fact, this JSON is
|
||||
* still linked to the database, so it should not be freed with
|
||||
* .Fn JsonFree .
|
||||
*/
|
||||
extern HashMap * UserGetDevices(User *);
|
||||
|
||||
extern UserAccessToken *
|
||||
UserAccessTokenGenerate(User *, char *, int);
|
||||
/**
|
||||
* Generate a new access token for the given user. This is mainly
|
||||
* used internally. It takes the device ID and a boolean value
|
||||
* indicating whether or not the token should expire.
|
||||
*/
|
||||
extern UserAccessToken * UserAccessTokenGenerate(User *, char *, int);
|
||||
|
||||
extern int
|
||||
UserAccessTokenSave(Db *, UserAccessToken *);
|
||||
/**
|
||||
* Write the specified access token to the database, returning a
|
||||
* boolean value indicating success.
|
||||
*/
|
||||
extern int UserAccessTokenSave(Db *, UserAccessToken *);
|
||||
|
||||
extern void
|
||||
UserAccessTokenFree(UserAccessToken *);
|
||||
/**
|
||||
* Free the memory associated with the given access token.
|
||||
*/
|
||||
extern void UserAccessTokenFree(UserAccessToken *);
|
||||
|
||||
extern int
|
||||
UserDeleteToken(User *, char *);
|
||||
/**
|
||||
* Delete a specific access token by name.
|
||||
*/
|
||||
extern int UserDeleteToken(User *, char *);
|
||||
|
||||
extern char *
|
||||
UserGetProfile(User *, char *);
|
||||
/**
|
||||
* Get a string property from the user's profile given the specified
|
||||
* key.
|
||||
*/
|
||||
extern char * UserGetProfile(User *, char *);
|
||||
|
||||
extern void
|
||||
UserSetProfile(User *, char *, char *);
|
||||
/**
|
||||
* Set a string property on the user's profile. A key/value pair should
|
||||
* be provided.
|
||||
*/
|
||||
extern void UserSetProfile(User *, char *, char *);
|
||||
|
||||
extern int
|
||||
UserDeleteTokens(User *, char *);
|
||||
/**
|
||||
* Delete all of the access tokens that belong to the specified user,
|
||||
* except for the one provided by name, unless NULL is provided for
|
||||
* the name.
|
||||
*/
|
||||
extern int UserDeleteTokens(User *, char *);
|
||||
|
||||
/**
|
||||
* Get the current privileges of the user as a packed bit field. Use
|
||||
* the flags defined in UserPrivileges to deterine what privileges a
|
||||
* user has.
|
||||
*/
|
||||
extern int UserGetPrivileges(User *);
|
||||
|
||||
/**
|
||||
* Set the privileges of the user.
|
||||
*/
|
||||
extern int UserSetPrivileges(User *, int);
|
||||
|
||||
/**
|
||||
* Decode the JSON that represents the user privileges into a packed
|
||||
* bit field for simple manipulation.
|
||||
*/
|
||||
extern int UserDecodePrivileges(JsonValue *);
|
||||
|
||||
/**
|
||||
* Encode the packed bit field that represents user privileges as a
|
||||
* JSON value.
|
||||
*/
|
||||
extern JsonValue *UserEncodePrivileges(int);
|
||||
|
||||
/**
|
||||
* Convert a string privilege into its bit in the bit field. This is
|
||||
* mainly intended to be used internally. At the time of writing, I
|
||||
* don't recall exactly why it's in the public API.
|
||||
*/
|
||||
extern int UserDecodePrivilege(const char *);
|
||||
|
||||
extern UserId *
|
||||
UserIdParse(char *, char *);
|
||||
/**
|
||||
* Parse either a localpart or a fully qualified Matrix ID. If the
|
||||
* first argument is a localpart, then the second argument is used as
|
||||
* the server name.
|
||||
*/
|
||||
extern UserId * UserIdParse(char *, char *);
|
||||
|
||||
extern void
|
||||
UserIdFree(UserId *);
|
||||
/**
|
||||
* Free the memory associated with the parsed Matrix ID.
|
||||
*/
|
||||
extern void UserIdFree(UserId *);
|
||||
|
||||
#endif /* TELODENDRIA_USER_H */
|
||||
|
|
|
@ -25,31 +25,81 @@
|
|||
#ifndef TELODENDRIA_UTIL_H
|
||||
#define TELODENDRIA_UTIL_H
|
||||
|
||||
/***
|
||||
* @Nm Util
|
||||
* @Nd Some misc. helper functions that don't need their own headers.
|
||||
* @Dd February 15 2023
|
||||
*
|
||||
* This header holds a number of random functions related to strings,
|
||||
* time, the filesystem, and other simple tasks that don't require a
|
||||
* full separate API. For the most part, the functions here are
|
||||
* entirely standalone, depending only on POSIX functions, however
|
||||
* there are a few that depend explicitly on a few other APIs. Those
|
||||
* are noted.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <Stream.h>
|
||||
|
||||
extern unsigned long
|
||||
UtilServerTs(void);
|
||||
/**
|
||||
* Get the current timestamp in milliseconds since the Unix epoch. This
|
||||
* uses
|
||||
* .Xr gettimeofday 2
|
||||
* and time_t, and converts it to a single number, which is then
|
||||
* returned to the caller.
|
||||
* .Pp
|
||||
* A note on the 2038 problem: as long as sizeof(long) >= 8, that is,
|
||||
* as long as the long data type is 64 bits or more, then everything
|
||||
* should be fine. On most, if not, all, 64-bit systems, long is 64
|
||||
* bits. I would expect Telodendria to break for 32 bit systems
|
||||
* eventually, but we should have a ways to go before that happens.
|
||||
* I didn't want to try to hack together some system to store larger
|
||||
* numbers than the architecture supports. But we can always
|
||||
* re-evaluate over the next few years.
|
||||
*/
|
||||
extern unsigned long UtilServerTs(void);
|
||||
|
||||
extern unsigned long
|
||||
UtilLastModified(char *);
|
||||
/**
|
||||
* Use
|
||||
* .Xr stat 2
|
||||
* to get the last modified time of the given file, or zero if there
|
||||
* was an error getting the last modified time of a file. This is
|
||||
* primarily useful for caching file data.
|
||||
*/
|
||||
extern unsigned long UtilLastModified(char *);
|
||||
|
||||
extern int
|
||||
UtilMkdir(const char *, const mode_t);
|
||||
/**
|
||||
* This function behaves just like the system call
|
||||
* .Xr mkdir 2 ,
|
||||
* but it creates any intermediate directories as necessary, unlike
|
||||
* .Xr mkdir 2 .
|
||||
*/
|
||||
extern int UtilMkdir(const char *, const mode_t);
|
||||
|
||||
extern int
|
||||
UtilSleepMillis(long);
|
||||
/**
|
||||
* Sleep the calling thread for the given number of milliseconds.
|
||||
* POSIX does not have a very friendly way to sleep, so this wraps
|
||||
* .Xr nanosleep 2
|
||||
* to make its usage much, much simpler.
|
||||
*/
|
||||
extern int UtilSleepMillis(long);
|
||||
|
||||
extern size_t
|
||||
UtilParseBytes(char *);
|
||||
/**
|
||||
* This function works identically to the POSIX
|
||||
* .Xr getdelim 3 ,
|
||||
* except that it assumes pointers were allocated with the Memory API
|
||||
* and it reads from a Stream instead of a file pointer.
|
||||
*/
|
||||
extern ssize_t UtilGetDelim(char **, size_t *, int, Stream *);
|
||||
|
||||
extern ssize_t
|
||||
UtilGetDelim(char **, size_t *, int, Stream *);
|
||||
|
||||
extern ssize_t
|
||||
UtilGetLine(char **, size_t *, Stream *);
|
||||
/**
|
||||
* This function is just a special case of
|
||||
* .Fn UtilGetDelim
|
||||
* that sets the delimiter to the newline character.
|
||||
*/
|
||||
extern ssize_t UtilGetLine(char **, size_t *, Stream *);
|
||||
|
||||
#endif /* TELODENDRIA_UTIL_H */
|
||||
|
|
|
@ -32,7 +32,7 @@ if which makewhatis 2>&1 > /dev/null; then
|
|||
fi
|
||||
|
||||
export PATH="$(pwd)/tools/bin:$(pwd)/build/tools:$PATH"
|
||||
export MANPATH="$(pwd)/man:$MANPATH"
|
||||
export MANPATH="$(pwd)/man:$(pwd)/build/man:$MANPATH"
|
||||
|
||||
if [ "$(uname)" = "OpenBSD" ]; then
|
||||
# Other platforms use different MALLOC_OPTIONS
|
||||
|
|
Loading…
Reference in a new issue