forked from Telodendria/Telodendria
Compare commits
No commits in common. "d050cef9fdb842edcffe63150e5845440cc39abc" and "af4fd5dcebf73fe88f6ac7fe690d19834ea16b49" have entirely different histories.
d050cef9fd
...
af4fd5dceb
61 changed files with 687 additions and 554 deletions
|
@ -1,13 +0,0 @@
|
||||||
N: Jordan Bancino
|
|
||||||
E: jordan@bancino.net
|
|
||||||
M: @jordan:bancino.net
|
|
||||||
W: https://bancino.net
|
|
||||||
D: Project Lead
|
|
||||||
L: United States
|
|
||||||
|
|
||||||
N: LDA
|
|
||||||
E: marie@doskel.net
|
|
||||||
E: ldasta@tedomum.fr
|
|
||||||
E: lda@freetards.xyz
|
|
||||||
D: Developer
|
|
||||||
L: France
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,88 +0,0 @@
|
||||||
{
|
|
||||||
"guard": "TELODENDRIA_SCHEMA_CONFIG_H",
|
|
||||||
"header": "Schema\/Config.h",
|
|
||||||
"include": [ "Cytoplasm\/Db.h", "Cytoplasm/HttpServer.h" ],
|
|
||||||
|
|
||||||
"types": {
|
|
||||||
"ConfigTls": {
|
|
||||||
"fields": {
|
|
||||||
"cert": { "type": "string", "required": true },
|
|
||||||
"key": { "type": "string", "required": true }
|
|
||||||
},
|
|
||||||
"type": "struct"
|
|
||||||
},
|
|
||||||
|
|
||||||
"ConfigListener": {
|
|
||||||
"fields": {
|
|
||||||
"port": { "type": "integer", "required": true },
|
|
||||||
"threads": { "type": "integer", "required": false },
|
|
||||||
"maxConnections": { "type": "integer", "required": false },
|
|
||||||
"tls": { "type": "ConfigTls", "required": false }
|
|
||||||
},
|
|
||||||
"type": "struct"
|
|
||||||
},
|
|
||||||
"ConfigRunAs": {
|
|
||||||
"fields": {
|
|
||||||
"uid": { "type": "string", "required": false },
|
|
||||||
"gid": { "type": "string", "required": true }
|
|
||||||
},
|
|
||||||
"type": "struct"
|
|
||||||
},
|
|
||||||
"ConfigLogOutput": {
|
|
||||||
"fields": {
|
|
||||||
"stdout": { "name": "CONFIG_LOG_OUTPUT_STDOUT" },
|
|
||||||
"file": { "name": "CONFIG_LOG_OUTPUT_FILE" },
|
|
||||||
"syslog": { "name": "CONFIG_LOG_OUTPUT_SYSLOG" }
|
|
||||||
},
|
|
||||||
"type": "enum"
|
|
||||||
},
|
|
||||||
"ConfigLogLevel": {
|
|
||||||
"fields": {
|
|
||||||
"message": { "name": "CONFIG_LOG_LEVEL_MESSAGE" },
|
|
||||||
"debug": { "name": "CONFIG_LOG_LEVEL_DEBUG" },
|
|
||||||
"notice": { "name": "CONFIG_LOG_LEVEL_NOTICE" },
|
|
||||||
"warning": { "name": "CONFIG_LOG_LEVEL_WARNING" },
|
|
||||||
"error": { "name": "CONFIG_LOG_LEVEL_ERROR" }
|
|
||||||
},
|
|
||||||
"type": "enum"
|
|
||||||
},
|
|
||||||
"ConfigLogConfig": {
|
|
||||||
"fields": {
|
|
||||||
"output": { "type": "ConfigLogOutput", "required": true },
|
|
||||||
"level": { "type": "ConfigLogLevel", "required": false },
|
|
||||||
"timestampFormat":{ "type": "string", "required": false },
|
|
||||||
"color": { "type": "boolean", "required": false }
|
|
||||||
},
|
|
||||||
"type": "struct"
|
|
||||||
},
|
|
||||||
|
|
||||||
"Db *": { "type": "extern" },
|
|
||||||
"DbRef *": { "type": "extern" },
|
|
||||||
"char *": { "type": "extern" },
|
|
||||||
|
|
||||||
"Config": {
|
|
||||||
"fields": {
|
|
||||||
"db": { "type": "Db *", "ignore": true },
|
|
||||||
"ref": { "type": "DbRef *", "ignore": true },
|
|
||||||
|
|
||||||
"ok": { "type": "boolean", "ignore": true },
|
|
||||||
"err": { "type": "char *", "ignore": true },
|
|
||||||
|
|
||||||
"listen": { "type": "[ConfigListener]", "required": true },
|
|
||||||
"runAs": { "type": "ConfigRunAs", "required": false },
|
|
||||||
"log": { "type": "ConfigLogConfig", "required": true },
|
|
||||||
|
|
||||||
"serverName": { "type": "string", "required": true },
|
|
||||||
"baseUrl": { "type": "string", "required": false },
|
|
||||||
"identityServer": { "type": "string", "required": false },
|
|
||||||
"pid": { "type": "string", "required": false },
|
|
||||||
|
|
||||||
"maxCache": { "type": "integer", "required": false },
|
|
||||||
|
|
||||||
"federation": { "type": "boolean", "required": true },
|
|
||||||
"registration": { "type": "boolean", "required": true }
|
|
||||||
},
|
|
||||||
"type": "struct"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -31,7 +31,6 @@ The following endpoints were added:
|
||||||
|
|
||||||
### Bug Fixes & General Improvements
|
### Bug Fixes & General Improvements
|
||||||
|
|
||||||
- Use `j2s` for parsing the configuration
|
|
||||||
- Fixed a double-free in `RouteUserProfile()` that would cause errors
|
- Fixed a double-free in `RouteUserProfile()` that would cause errors
|
||||||
with certain Matrix clients. (#35)
|
with certain Matrix clients. (#35)
|
||||||
- Improved compatibility with NetBSD on various platforms.
|
- Improved compatibility with NetBSD on various platforms.
|
||||||
|
@ -44,8 +43,6 @@ parsing request bodies.
|
||||||
|
|
||||||
### New Features
|
### New Features
|
||||||
|
|
||||||
- Implemented a `"pid"` option in the configuration, allowing Telodendria
|
|
||||||
to write its process ID to a specified file.
|
|
||||||
- Moved all administrator API endpoints to `/_telodendria/admin/v1`,
|
- Moved all administrator API endpoints to `/_telodendria/admin/v1`,
|
||||||
because later revisions of the administrator API may break clients, so
|
because later revisions of the administrator API may break clients, so
|
||||||
we want a way to give those breaking revisions new endpoints.
|
we want a way to give those breaking revisions new endpoints.
|
||||||
|
|
|
@ -213,44 +213,3 @@ comments to the appropriate header.
|
||||||
If your pull request does not also include proper documentation, it
|
If your pull request does not also include proper documentation, it
|
||||||
will likely be rejected.
|
will likely be rejected.
|
||||||
|
|
||||||
### Be Recognized!
|
|
||||||
|
|
||||||
If your pull request gets approved, you should be recognized for your
|
|
||||||
contributions to the project!
|
|
||||||
|
|
||||||
To have your work recognized, add your information to the `CONTRIBUTORS.txt`
|
|
||||||
file in the root of the Telodendria repository if it isn't there already.
|
|
||||||
You should do this as a part of your pull request so that when it is merged,
|
|
||||||
your information will be automatically added to the repository.
|
|
||||||
|
|
||||||
The `CONTRIBUTORS.txt` file loosely follows the Linux kernel's
|
|
||||||
[CREDITS](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/CREDITS)
|
|
||||||
file format. It is designed to be human-readable, but also parsable by
|
|
||||||
scripts.
|
|
||||||
|
|
||||||
The following fields are available:
|
|
||||||
|
|
||||||
```
|
|
||||||
(N) Name
|
|
||||||
(E) Email
|
|
||||||
(M) Matrix ID
|
|
||||||
(W) Website
|
|
||||||
(D) Description of contribution
|
|
||||||
(L) Physical location
|
|
||||||
```
|
|
||||||
|
|
||||||
Here are the rules:
|
|
||||||
|
|
||||||
* All fields are optional. If you don't want to include a field, that's
|
|
||||||
okay, simply omit it.
|
|
||||||
* All fields identify you however you wish. The goal is to recognize you for
|
|
||||||
your contribution, but if you wish to remain anonymous, you don't have to
|
|
||||||
use your real information.
|
|
||||||
* All fields can be specified multiple times. For example, if you have
|
|
||||||
multiple email addresses, websites, or Matrix IDs and you want to include
|
|
||||||
all of them, you absolutely may. Likewise, if you have made multiple
|
|
||||||
contributions, you can add multiple description entries.
|
|
||||||
* You can make up your own fields if you want. Just add their description
|
|
||||||
above.
|
|
||||||
* Leave exactly one blank like between entries in this file.
|
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,8 @@ key-value form:
|
||||||
"serverName": "telodendria.io",
|
"serverName": "telodendria.io",
|
||||||
"listen": [
|
"listen": [
|
||||||
{
|
{
|
||||||
"port": 8008
|
"port": 8008,
|
||||||
|
"tls": false
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -50,7 +51,7 @@ Here are the top-level directives:
|
||||||
this is a concern, a reverse-proxy such as `relayd` can be placed
|
this is a concern, a reverse-proxy such as `relayd` can be placed
|
||||||
in front of Telodendria to block access to undesired APIs.
|
in front of Telodendria to block access to undesired APIs.
|
||||||
|
|
||||||
- **tls:** `Object`
|
- **tls:** `Object|null|false`
|
||||||
|
|
||||||
Telodendria can be compiled with TLS support. If it is, then a
|
Telodendria can be compiled with TLS support. If it is, then a
|
||||||
particular listener can be set to use TLS for connections. If
|
particular listener can be set to use TLS for connections. If
|
||||||
|
@ -105,9 +106,6 @@ Here are the top-level directives:
|
||||||
or you want to start over. **serverName** should be a DNS name that
|
or you want to start over. **serverName** should be a DNS name that
|
||||||
can be publicly resolved. This directive is required.
|
can be publicly resolved. This directive is required.
|
||||||
|
|
||||||
- **pid:** `String`
|
|
||||||
Configure the file Telodendria writes its PID to.
|
|
||||||
|
|
||||||
- **baseUrl:** `String`
|
- **baseUrl:** `String`
|
||||||
|
|
||||||
Set the server's base URL. **baseUrl** should be a valid URL,
|
Set the server's base URL. **baseUrl** should be a valid URL,
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
491
src/Config.c
491
src/Config.c
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
@ -22,89 +21,405 @@
|
||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
#include <Schema/Config.h>
|
#include <Config.h>
|
||||||
#include <Cytoplasm/Memory.h>
|
#include <Cytoplasm/Memory.h>
|
||||||
#include <Cytoplasm/Json.h>
|
#include <Cytoplasm/Json.h>
|
||||||
#include <Cytoplasm/HashMap.h>
|
#include <Cytoplasm/HashMap.h>
|
||||||
#include <Cytoplasm/Array.h>
|
#include <Cytoplasm/Array.h>
|
||||||
#include <Cytoplasm/Str.h>
|
#include <Cytoplasm/Str.h>
|
||||||
#include <Cytoplasm/Db.h>
|
#include <Cytoplasm/Db.h>
|
||||||
|
#include <Cytoplasm/HttpServer.h>
|
||||||
#include <Cytoplasm/Log.h>
|
#include <Cytoplasm/Log.h>
|
||||||
#include <Cytoplasm/Int64.h>
|
#include <Cytoplasm/Int64.h>
|
||||||
#include <Cytoplasm/Util.h>
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <grp.h>
|
|
||||||
#include <pwd.h>
|
|
||||||
|
|
||||||
#ifndef HOST_NAME_MAX
|
#ifndef HOST_NAME_MAX
|
||||||
#define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
|
#define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void
|
#define CONFIG_REQUIRE(key, type) \
|
||||||
ConfigParse(HashMap * config, Config *tConfig)
|
value = HashMapGet(config, key); \
|
||||||
|
if (!value) \
|
||||||
|
{ \
|
||||||
|
tConfig->err = "Missing required " key " directive."; \
|
||||||
|
goto error; \
|
||||||
|
} \
|
||||||
|
if (JsonValueType(value) == JSON_NULL) \
|
||||||
|
{ \
|
||||||
|
tConfig->err = "Missing value for " key " directive."; \
|
||||||
|
goto error; \
|
||||||
|
} \
|
||||||
|
if (JsonValueType(value) != type) \
|
||||||
|
{ \
|
||||||
|
tConfig->err = "Expected " key " to be of type " #type; \
|
||||||
|
goto error; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CONFIG_COPY_STRING(into) \
|
||||||
|
into = StrDuplicate(JsonValueAsString(value));
|
||||||
|
|
||||||
|
#define CONFIG_OPTIONAL_STRING(into, key, default) \
|
||||||
|
value = HashMapGet(config, key); \
|
||||||
|
if (value && JsonValueType(value) != JSON_NULL) \
|
||||||
|
{ \
|
||||||
|
if (JsonValueType(value) != JSON_STRING) \
|
||||||
|
{ \
|
||||||
|
tConfig->err = "Expected " key " to be of type JSON_STRING"; \
|
||||||
|
goto error; \
|
||||||
|
} \
|
||||||
|
into = StrDuplicate(JsonValueAsString(value)); \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
|
into = default ? StrDuplicate(default) : NULL; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CONFIG_OPTIONAL_INTEGER(into, key, default) \
|
||||||
|
value = HashMapGet(config, key); \
|
||||||
|
if (value && JsonValueType(value) != JSON_NULL) \
|
||||||
|
{ \
|
||||||
|
if (JsonValueType(value) != JSON_INTEGER) \
|
||||||
|
{ \
|
||||||
|
tConfig->err = "Expected " key " to be of type JSON_INTEGER"; \
|
||||||
|
goto error; \
|
||||||
|
} \
|
||||||
|
into = Int64Low(JsonValueAsInteger(value)); \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
|
into = default; \
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ConfigParseRunAs(Config * tConfig, HashMap * config)
|
||||||
|
{
|
||||||
|
JsonValue *value;
|
||||||
|
|
||||||
|
CONFIG_REQUIRE("uid", JSON_STRING);
|
||||||
|
CONFIG_COPY_STRING(tConfig->uid);
|
||||||
|
|
||||||
|
CONFIG_OPTIONAL_STRING(tConfig->gid, "gid", tConfig->uid);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
error:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ConfigParseListen(Config * tConfig, Array * listen)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
|
if (!ArraySize(listen))
|
||||||
|
{
|
||||||
|
tConfig->err = "Listen array cannot be empty; you must specify at least one listener.";
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tConfig->servers)
|
||||||
|
{
|
||||||
|
tConfig->servers = ArrayCreate();
|
||||||
|
if (!tConfig->servers)
|
||||||
|
{
|
||||||
|
tConfig->err = "Unable to allocate memory for listener configurations.";
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ArraySize(listen); i++)
|
||||||
|
{
|
||||||
|
JsonValue *val = ArrayGet(listen, i);
|
||||||
|
HashMap *obj;
|
||||||
|
HttpServerConfig *serverCfg = Malloc(sizeof(HttpServerConfig));
|
||||||
|
|
||||||
|
if (!serverCfg)
|
||||||
|
{
|
||||||
|
tConfig->err = "Unable to allocate memory for listener configuration.";
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (JsonValueType(val) != JSON_OBJECT)
|
||||||
|
{
|
||||||
|
tConfig->err = "Invalid value in listener array. All listeners must be objects.";
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj = JsonValueAsObject(val);
|
||||||
|
|
||||||
|
serverCfg->port = Int64Low(JsonValueAsInteger(HashMapGet(obj, "port")));
|
||||||
|
serverCfg->threads = Int64Low(JsonValueAsInteger(HashMapGet(obj, "threads")));
|
||||||
|
serverCfg->maxConnections = Int64Low(JsonValueAsInteger(HashMapGet(obj, "maxConnections")));
|
||||||
|
|
||||||
|
if (!serverCfg->port)
|
||||||
|
{
|
||||||
|
Free(serverCfg);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!serverCfg->threads)
|
||||||
|
{
|
||||||
|
serverCfg->threads = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!serverCfg->maxConnections)
|
||||||
|
{
|
||||||
|
serverCfg->maxConnections = 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = HashMapGet(obj, "tls");
|
||||||
|
if ((JsonValueType(val) == JSON_BOOLEAN && !JsonValueAsBoolean(val)) || JsonValueType(val) == JSON_NULL)
|
||||||
|
{
|
||||||
|
serverCfg->flags = HTTP_FLAG_NONE;
|
||||||
|
serverCfg->tlsCert = NULL;
|
||||||
|
serverCfg->tlsKey = NULL;
|
||||||
|
}
|
||||||
|
else if (JsonValueType(val) != JSON_OBJECT)
|
||||||
|
{
|
||||||
|
tConfig->err = "Invalid value for listener.tls. It must be an object.";
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serverCfg->flags = HTTP_FLAG_TLS;
|
||||||
|
|
||||||
|
obj = JsonValueAsObject(val);
|
||||||
|
serverCfg->tlsCert = StrDuplicate(JsonValueAsString(HashMapGet(obj, "cert")));
|
||||||
|
serverCfg->tlsKey = StrDuplicate(JsonValueAsString(HashMapGet(obj, "key")));
|
||||||
|
|
||||||
|
if (!serverCfg->tlsCert || !serverCfg->tlsKey)
|
||||||
|
{
|
||||||
|
tConfig->err = "TLS cert and key must both be valid file names.";
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ArrayAdd(tConfig->servers, serverCfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
error:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ConfigParseLog(Config * tConfig, HashMap * config)
|
||||||
|
{
|
||||||
|
JsonValue *value;
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
CONFIG_REQUIRE("output", JSON_STRING);
|
||||||
|
str = JsonValueAsString(value);
|
||||||
|
|
||||||
|
if (StrEquals(str, "stdout"))
|
||||||
|
{
|
||||||
|
tConfig->flags |= CONFIG_LOG_STDOUT;
|
||||||
|
}
|
||||||
|
else if (StrEquals(str, "file"))
|
||||||
|
{
|
||||||
|
tConfig->flags |= CONFIG_LOG_FILE;
|
||||||
|
}
|
||||||
|
else if (StrEquals(str, "syslog"))
|
||||||
|
{
|
||||||
|
tConfig->flags |= CONFIG_LOG_SYSLOG;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tConfig->err = "Invalid value for log.output";
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
CONFIG_OPTIONAL_STRING(str, "level", "message");
|
||||||
|
|
||||||
|
if (StrEquals(str, "message"))
|
||||||
|
{
|
||||||
|
tConfig->logLevel = LOG_INFO;
|
||||||
|
}
|
||||||
|
else if (StrEquals(str, "debug"))
|
||||||
|
{
|
||||||
|
tConfig->logLevel = LOG_DEBUG;
|
||||||
|
}
|
||||||
|
else if (StrEquals(str, "notice"))
|
||||||
|
{
|
||||||
|
tConfig->logLevel = LOG_NOTICE;
|
||||||
|
}
|
||||||
|
else if (StrEquals(str, "warning"))
|
||||||
|
{
|
||||||
|
tConfig->logLevel = LOG_WARNING;
|
||||||
|
}
|
||||||
|
else if (StrEquals(str, "error"))
|
||||||
|
{
|
||||||
|
tConfig->logLevel = LOG_ERR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tConfig->err = "Invalid value for log.level.";
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Free(str);
|
||||||
|
|
||||||
|
CONFIG_OPTIONAL_STRING(tConfig->logTimestamp, "timestampFormat", "default");
|
||||||
|
|
||||||
|
if (StrEquals(tConfig->logTimestamp, "none"))
|
||||||
|
{
|
||||||
|
Free(tConfig->logTimestamp);
|
||||||
|
tConfig->logTimestamp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = HashMapGet(config, "color");
|
||||||
|
if (value && JsonValueType(value) != JSON_NULL)
|
||||||
|
{
|
||||||
|
if (JsonValueType(value) != JSON_BOOLEAN)
|
||||||
|
{
|
||||||
|
tConfig->err = "Expected type JSON_BOOLEAN for log.color.";
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (JsonValueAsBoolean(value))
|
||||||
|
{
|
||||||
|
tConfig->flags |= CONFIG_LOG_COLOR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
error:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ConfigFree(Config * tConfig)
|
||||||
|
{
|
||||||
|
if (!tConfig)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Free(tConfig->serverName);
|
||||||
|
Free(tConfig->baseUrl);
|
||||||
|
Free(tConfig->identityServer);
|
||||||
|
|
||||||
|
Free(tConfig->uid);
|
||||||
|
Free(tConfig->gid);
|
||||||
|
|
||||||
|
Free(tConfig->logTimestamp);
|
||||||
|
|
||||||
|
if (tConfig->servers)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < ArraySize(tConfig->servers); i++)
|
||||||
|
{
|
||||||
|
HttpServerConfig *serverCfg = ArrayGet(tConfig->servers, i);
|
||||||
|
|
||||||
|
Free(serverCfg->tlsCert);
|
||||||
|
Free(serverCfg->tlsKey);
|
||||||
|
Free(serverCfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayFree(tConfig->servers);
|
||||||
|
}
|
||||||
|
|
||||||
|
Free(tConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
Config *
|
||||||
|
ConfigParse(HashMap * config)
|
||||||
|
{
|
||||||
|
Config *tConfig;
|
||||||
|
JsonValue *value;
|
||||||
|
|
||||||
if (!config)
|
if (!config)
|
||||||
{
|
{
|
||||||
tConfig->ok = 0;
|
return NULL;
|
||||||
tConfig->err = "Invalid object given as config.";
|
}
|
||||||
return;
|
|
||||||
|
tConfig = Malloc(sizeof(Config));
|
||||||
|
if (!tConfig)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(tConfig, 0, sizeof(Config));
|
memset(tConfig, 0, sizeof(Config));
|
||||||
|
|
||||||
tConfig->maxCache = Int64Create(0, 0);
|
CONFIG_REQUIRE("listen", JSON_ARRAY);
|
||||||
|
if (!ConfigParseListen(tConfig, JsonValueAsArray(value)))
|
||||||
if (!ConfigFromJson(config, tConfig, &tConfig->err))
|
|
||||||
{
|
{
|
||||||
ConfigFree(tConfig);
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (!tConfig->baseUrl)
|
|
||||||
|
CONFIG_REQUIRE("serverName", JSON_STRING);
|
||||||
|
CONFIG_COPY_STRING(tConfig->serverName);
|
||||||
|
|
||||||
|
value = HashMapGet(config, "baseUrl");
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
CONFIG_COPY_STRING(tConfig->baseUrl);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
size_t len = strlen(tConfig->serverName) + 10;
|
size_t len = strlen(tConfig->serverName) + 10;
|
||||||
|
|
||||||
tConfig->baseUrl = Malloc(len);
|
tConfig->baseUrl = Malloc(len);
|
||||||
if (!tConfig->baseUrl)
|
if (!tConfig->baseUrl)
|
||||||
{
|
{
|
||||||
tConfig->err = "Couldn't allocate enough memory for 'baseUrl'.";
|
tConfig->err = "Error allocating memory for default config value 'baseUrl'.";
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
snprintf(tConfig->baseUrl, len, "https://%s/", tConfig->serverName);
|
|
||||||
|
snprintf(tConfig->baseUrl, len, "https://%s", tConfig->serverName);
|
||||||
}
|
}
|
||||||
if (!tConfig->log.timestampFormat)
|
|
||||||
|
CONFIG_OPTIONAL_STRING(tConfig->identityServer, "identityServer", NULL);
|
||||||
|
|
||||||
|
value = HashMapGet(config, "runAs");
|
||||||
|
if (value && JsonValueType(value) != JSON_NULL)
|
||||||
{
|
{
|
||||||
tConfig->log.timestampFormat = StrDuplicate("default");
|
if (JsonValueType(value) == JSON_OBJECT)
|
||||||
}
|
|
||||||
for (i = 0; i < ArraySize(tConfig->listen); i++)
|
|
||||||
{
|
{
|
||||||
ConfigListener *listener = ArrayGet(tConfig->listen, i);
|
if (!ConfigParseRunAs(tConfig, JsonValueAsObject(value)))
|
||||||
if (Int64Eq(listener->maxConnections, Int64Create(0, 0)))
|
|
||||||
{
|
{
|
||||||
listener->maxConnections = Int64Create(0, 32);
|
goto error;
|
||||||
}
|
}
|
||||||
if (Int64Eq(listener->threads, Int64Create(0, 0)))
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
listener->threads = Int64Create(0, 4);
|
tConfig->err = "Config directive 'runAs' should be a JSON object that contains a 'uid' and 'gid'.";
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
if (Int64Eq(listener->port, Int64Create(0, 0)))
|
}
|
||||||
|
|
||||||
|
CONFIG_OPTIONAL_INTEGER(tConfig->maxCache, "maxCache", 0);
|
||||||
|
|
||||||
|
CONFIG_REQUIRE("federation", JSON_BOOLEAN);
|
||||||
|
if (JsonValueAsBoolean(value))
|
||||||
{
|
{
|
||||||
listener->port = Int64Create(0, 8008);
|
tConfig->flags |= CONFIG_FEDERATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CONFIG_REQUIRE("registration", JSON_BOOLEAN);
|
||||||
|
if (JsonValueAsBoolean(value))
|
||||||
|
{
|
||||||
|
tConfig->flags |= CONFIG_REGISTRATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CONFIG_REQUIRE("log", JSON_OBJECT);
|
||||||
|
if (!ConfigParseLog(tConfig, JsonValueAsObject(value)))
|
||||||
|
{
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
tConfig->ok = 1;
|
tConfig->ok = 1;
|
||||||
tConfig->err = NULL;
|
tConfig->err = NULL;
|
||||||
return;
|
return tConfig;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
tConfig->ok = 0;
|
tConfig->ok = 0;
|
||||||
return;
|
return tConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -116,91 +431,75 @@ ConfigExists(Db * db)
|
||||||
int
|
int
|
||||||
ConfigCreateDefault(Db * db)
|
ConfigCreateDefault(Db * db)
|
||||||
{
|
{
|
||||||
Config config;
|
|
||||||
ConfigListener *listener;
|
|
||||||
|
|
||||||
HashMap *json;
|
|
||||||
JsonValue *val;
|
|
||||||
|
|
||||||
DbRef *ref;
|
DbRef *ref;
|
||||||
|
HashMap *json;
|
||||||
|
Array *listeners;
|
||||||
|
HashMap *listen;
|
||||||
|
|
||||||
size_t len;
|
char hostname[HOST_NAME_MAX + 1];
|
||||||
|
|
||||||
memset(&config, 0, sizeof(Config));
|
if (!db)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
config.log.output = CONFIG_LOG_OUTPUT_FILE;
|
}
|
||||||
|
|
||||||
config.runAs.gid = StrDuplicate(getgrgid(getgid())->gr_name);
|
|
||||||
config.runAs.uid = StrDuplicate(getpwuid(getuid())->pw_name);
|
|
||||||
|
|
||||||
config.registration = 0;
|
|
||||||
config.federation = 1;
|
|
||||||
|
|
||||||
/* Create serverName and baseUrl. */
|
|
||||||
config.serverName = Malloc(HOST_NAME_MAX + 1);
|
|
||||||
memset(config.serverName, 0, HOST_NAME_MAX + 1);
|
|
||||||
gethostname(config.serverName, HOST_NAME_MAX);
|
|
||||||
len = strlen(config.serverName) + 10;
|
|
||||||
config.baseUrl = Malloc(len);
|
|
||||||
snprintf(config.baseUrl, len, "https://%s/", config.serverName);
|
|
||||||
|
|
||||||
/* Add simple listener without TLS. */
|
|
||||||
config.listen = ArrayCreate();
|
|
||||||
listener = Malloc(sizeof(ConfigListener));
|
|
||||||
listener->maxConnections = Int64Create(0, 32);
|
|
||||||
listener->port = Int64Create(0, 8008);
|
|
||||||
listener->threads = Int64Create(0, 4);
|
|
||||||
|
|
||||||
ArrayAdd(config.listen, listener);
|
|
||||||
|
|
||||||
/* Write it all out to the configuration file. */
|
|
||||||
json = ConfigToJson(&config);
|
|
||||||
val = JsonGet(json, 1, "listen");
|
|
||||||
val = ArrayGet(JsonValueAsArray(val), 0);
|
|
||||||
JsonValueFree(HashMapDelete(JsonValueAsObject(val), "tls"));
|
|
||||||
|
|
||||||
ref = DbCreate(db, 1, "config");
|
ref = DbCreate(db, 1, "config");
|
||||||
if (!ref)
|
if (!ref)
|
||||||
{
|
{
|
||||||
ConfigFree(&config);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
DbJsonSet(ref, json);
|
|
||||||
DbUnlock(db, ref);
|
|
||||||
|
|
||||||
ConfigFree(&config);
|
json = DbJson(ref);
|
||||||
JsonFree(json);
|
|
||||||
|
|
||||||
return 1;
|
JsonSet(json, JsonValueString("file"), 2, "log", "output");
|
||||||
|
|
||||||
|
listeners = ArrayCreate();
|
||||||
|
listen = HashMapCreate();
|
||||||
|
HashMapSet(listen, "port", JsonValueInteger(Int64Create(0, 8008)));
|
||||||
|
HashMapSet(listen, "tls", JsonValueBoolean(0));
|
||||||
|
ArrayAdd(listeners, JsonValueObject(listen));
|
||||||
|
HashMapSet(json, "listen", JsonValueArray(listeners));
|
||||||
|
|
||||||
|
if (gethostname(hostname, HOST_NAME_MAX + 1) < 0)
|
||||||
|
{
|
||||||
|
strncpy(hostname, "localhost", HOST_NAME_MAX);
|
||||||
|
}
|
||||||
|
HashMapSet(json, "serverName", JsonValueString(hostname));
|
||||||
|
|
||||||
|
HashMapSet(json, "federation", JsonValueBoolean(1));
|
||||||
|
HashMapSet(json, "registration", JsonValueBoolean(0));
|
||||||
|
|
||||||
|
return DbUnlock(db, ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
Config *
|
||||||
ConfigLock(Db * db, Config *config)
|
ConfigLock(Db * db)
|
||||||
{
|
{
|
||||||
|
Config *config;
|
||||||
DbRef *ref = DbLock(db, 1, "config");
|
DbRef *ref = DbLock(db, 1, "config");
|
||||||
|
|
||||||
if (!ref)
|
if (!ref)
|
||||||
{
|
{
|
||||||
config->ok = 0;
|
return NULL;
|
||||||
config->err = "Couldn't lock configuration.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigParse(DbJson(ref), config);
|
config = ConfigParse(DbJson(ref));
|
||||||
if (config->ok)
|
if (config)
|
||||||
{
|
{
|
||||||
config->db = db;
|
config->db = db;
|
||||||
config->ref = ref;
|
config->ref = ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
ConfigUnlock(Config *config)
|
ConfigUnlock(Config * config)
|
||||||
{
|
{
|
||||||
Db *db;
|
Db *db;
|
||||||
DbRef *dbRef;
|
DbRef *dbRef;
|
||||||
|
|
||||||
if (!config->ok)
|
if (!config)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -209,25 +508,5 @@ ConfigUnlock(Config *config)
|
||||||
dbRef = config->ref;
|
dbRef = config->ref;
|
||||||
|
|
||||||
ConfigFree(config);
|
ConfigFree(config);
|
||||||
config->ok = 0;
|
|
||||||
|
|
||||||
return DbUnlock(db, dbRef);
|
return DbUnlock(db, dbRef);
|
||||||
}
|
}
|
||||||
int
|
|
||||||
ConfigLogLevelToSyslog(ConfigLogLevel level)
|
|
||||||
{
|
|
||||||
switch (level)
|
|
||||||
{
|
|
||||||
case CONFIG_LOG_LEVEL_NOTICE:
|
|
||||||
return LOG_NOTICE;
|
|
||||||
case CONFIG_LOG_LEVEL_ERROR:
|
|
||||||
return LOG_ERR;
|
|
||||||
case CONFIG_LOG_LEVEL_MESSAGE:
|
|
||||||
return LOG_INFO;
|
|
||||||
case CONFIG_LOG_LEVEL_DEBUG:
|
|
||||||
return LOG_DEBUG;
|
|
||||||
case CONFIG_LOG_LEVEL_WARNING:
|
|
||||||
return LOG_WARNING;
|
|
||||||
}
|
|
||||||
return LOG_INFO;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
146
src/Main.c
146
src/Main.c
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
@ -103,11 +102,8 @@ Main(Array * args)
|
||||||
char *dbPath;
|
char *dbPath;
|
||||||
|
|
||||||
/* Program configuration */
|
/* Program configuration */
|
||||||
Config tConfig;
|
Config *tConfig;
|
||||||
Stream *logFile;
|
Stream *logFile;
|
||||||
Stream *pidFile;
|
|
||||||
|
|
||||||
char *pidPath;
|
|
||||||
|
|
||||||
/* User validation */
|
/* User validation */
|
||||||
struct passwd *userInfo;
|
struct passwd *userInfo;
|
||||||
|
@ -136,9 +132,8 @@ start:
|
||||||
exit = EXIT_SUCCESS;
|
exit = EXIT_SUCCESS;
|
||||||
flags = 0;
|
flags = 0;
|
||||||
dbPath = NULL;
|
dbPath = NULL;
|
||||||
|
tConfig = NULL;
|
||||||
logFile = NULL;
|
logFile = NULL;
|
||||||
pidFile = NULL;
|
|
||||||
pidPath = NULL;
|
|
||||||
userInfo = NULL;
|
userInfo = NULL;
|
||||||
groupInfo = NULL;
|
groupInfo = NULL;
|
||||||
cron = NULL;
|
cron = NULL;
|
||||||
|
@ -266,20 +261,33 @@ start:
|
||||||
|
|
||||||
Log(LOG_NOTICE, "Loading configuration...");
|
Log(LOG_NOTICE, "Loading configuration...");
|
||||||
|
|
||||||
ConfigLock(matrixArgs.db, &tConfig);
|
tConfig = ConfigLock(matrixArgs.db);
|
||||||
if (!tConfig.ok)
|
if (!tConfig)
|
||||||
{
|
{
|
||||||
Log(LOG_ERR, tConfig.err);
|
Log(LOG_ERR, "Error locking the configuration.");
|
||||||
|
Log(LOG_ERR, "The configuration object is corrupted or otherwise invalid.");
|
||||||
|
Log(LOG_ERR, "Please restore from a backup.");
|
||||||
|
exit = EXIT_FAILURE;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
else if (!tConfig->ok)
|
||||||
|
{
|
||||||
|
Log(LOG_ERR, tConfig->err);
|
||||||
exit = EXIT_FAILURE;
|
exit = EXIT_FAILURE;
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tConfig.log.timestampFormat || !StrEquals(tConfig.log.timestampFormat, "default"))
|
if (!tConfig->logTimestamp || !StrEquals(tConfig->logTimestamp, "default"))
|
||||||
{
|
{
|
||||||
LogConfigTimeStampFormatSet(LogConfigGlobal(), tConfig.log.timestampFormat);
|
LogConfigTimeStampFormatSet(LogConfigGlobal(), tConfig->logTimestamp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Free(tConfig->logTimestamp);
|
||||||
|
tConfig->logTimestamp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tConfig.log.color)
|
if (tConfig->flags & CONFIG_LOG_COLOR)
|
||||||
{
|
{
|
||||||
LogConfigFlagSet(LogConfigGlobal(), LOG_FLAG_COLOR);
|
LogConfigFlagSet(LogConfigGlobal(), LOG_FLAG_COLOR);
|
||||||
}
|
}
|
||||||
|
@ -288,13 +296,9 @@ start:
|
||||||
LogConfigFlagClear(LogConfigGlobal(), LOG_FLAG_COLOR);
|
LogConfigFlagClear(LogConfigGlobal(), LOG_FLAG_COLOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
LogConfigLevelSet(
|
LogConfigLevelSet(LogConfigGlobal(), flags & ARG_VERBOSE ? LOG_DEBUG : tConfig->logLevel);
|
||||||
LogConfigGlobal(),
|
|
||||||
flags & ARG_VERBOSE ?
|
|
||||||
LOG_DEBUG :
|
|
||||||
ConfigLogLevelToSyslog(tConfig.log.level));
|
|
||||||
|
|
||||||
if (tConfig.log.output == CONFIG_LOG_OUTPUT_FILE)
|
if (tConfig->flags & CONFIG_LOG_FILE)
|
||||||
{
|
{
|
||||||
logFile = StreamOpen("telodendria.log", "a");
|
logFile = StreamOpen("telodendria.log", "a");
|
||||||
|
|
||||||
|
@ -302,18 +306,18 @@ start:
|
||||||
{
|
{
|
||||||
Log(LOG_ERR, "Unable to open log file for appending.");
|
Log(LOG_ERR, "Unable to open log file for appending.");
|
||||||
exit = EXIT_FAILURE;
|
exit = EXIT_FAILURE;
|
||||||
tConfig.log.output = CONFIG_LOG_OUTPUT_STDOUT;
|
tConfig->flags &= CONFIG_LOG_STDOUT;
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log(LOG_INFO, "Logging to the log file. Check there for all future messages.");
|
Log(LOG_INFO, "Logging to the log file. Check there for all future messages.");
|
||||||
LogConfigOutputSet(LogConfigGlobal(), logFile);
|
LogConfigOutputSet(LogConfigGlobal(), logFile);
|
||||||
}
|
}
|
||||||
else if (tConfig.log.output == CONFIG_LOG_OUTPUT_STDOUT)
|
else if (tConfig->flags & CONFIG_LOG_STDOUT)
|
||||||
{
|
{
|
||||||
Log(LOG_DEBUG, "Already logging to standard output.");
|
Log(LOG_DEBUG, "Already logging to standard output.");
|
||||||
}
|
}
|
||||||
else if (tConfig.log.output == CONFIG_LOG_OUTPUT_SYSLOG)
|
else if (tConfig->flags & CONFIG_LOG_SYSLOG)
|
||||||
{
|
{
|
||||||
Log(LOG_INFO, "Logging to the syslog. Check there for all future messages.");
|
Log(LOG_INFO, "Logging to the syslog. Check there for all future messages.");
|
||||||
LogConfigFlagSet(LogConfigGlobal(), LOG_FLAG_SYSLOG);
|
LogConfigFlagSet(LogConfigGlobal(), LOG_FLAG_SYSLOG);
|
||||||
|
@ -323,6 +327,13 @@ start:
|
||||||
* messages get passed to the syslog */
|
* messages get passed to the syslog */
|
||||||
setlogmask(LOG_UPTO(LOG_DEBUG));
|
setlogmask(LOG_UPTO(LOG_DEBUG));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log(LOG_ERR, "Unknown logging method in flags: '%d'", tConfig->flags);
|
||||||
|
Log(LOG_ERR, "This is a programmer error; please report it.");
|
||||||
|
exit = EXIT_FAILURE;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
/* If a token was created with a default config, print it to the
|
/* If a token was created with a default config, print it to the
|
||||||
* log */
|
* log */
|
||||||
|
@ -332,30 +343,14 @@ start:
|
||||||
Free(token);
|
Free(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tConfig.pid)
|
|
||||||
{
|
|
||||||
pidFile = StreamOpen(tConfig.pid, "w+");
|
|
||||||
if (!pidFile)
|
|
||||||
{
|
|
||||||
char *msg = "Couldn't lock PID file at '%s'";
|
|
||||||
Log(LOG_ERR, msg, tConfig.pid);
|
|
||||||
exit = EXIT_FAILURE;
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
pidPath = StrDuplicate(tConfig.pid);
|
|
||||||
StreamPrintf(pidFile, "%ld", (long) getpid());
|
|
||||||
StreamClose(pidFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
Log(LOG_DEBUG, "Configuration:");
|
Log(LOG_DEBUG, "Configuration:");
|
||||||
LogConfigIndent(LogConfigGlobal());
|
LogConfigIndent(LogConfigGlobal());
|
||||||
Log(LOG_DEBUG, "Server Name: %s", tConfig.serverName);
|
Log(LOG_DEBUG, "Server Name: %s", tConfig->serverName);
|
||||||
Log(LOG_DEBUG, "Base URL: %s", tConfig.baseUrl);
|
Log(LOG_DEBUG, "Base URL: %s", tConfig->baseUrl);
|
||||||
Log(LOG_DEBUG, "Identity Server: %s", tConfig.identityServer);
|
Log(LOG_DEBUG, "Identity Server: %s", tConfig->identityServer);
|
||||||
Log(LOG_DEBUG, "Run As: %s:%s", tConfig.runAs.uid, tConfig.runAs.gid);
|
Log(LOG_DEBUG, "Run As: %s:%s", tConfig->uid, tConfig->gid);
|
||||||
Log(LOG_DEBUG, "Max Cache: %ld", tConfig.maxCache);
|
Log(LOG_DEBUG, "Max Cache: %ld", tConfig->maxCache);
|
||||||
Log(LOG_DEBUG, "Registration: %s", tConfig.registration ? "true" : "false");
|
Log(LOG_DEBUG, "Flags: %x", tConfig->flags);
|
||||||
Log(LOG_DEBUG, "Federation: %s", tConfig.federation ? "true" : "false");
|
|
||||||
LogConfigUnindent(LogConfigGlobal());
|
LogConfigUnindent(LogConfigGlobal());
|
||||||
|
|
||||||
httpServers = ArrayCreate();
|
httpServers = ArrayCreate();
|
||||||
|
@ -367,51 +362,41 @@ start:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Bind servers before possibly dropping permissions. */
|
/* Bind servers before possibly dropping permissions. */
|
||||||
for (i = 0; i < ArraySize(tConfig.listen); i++)
|
for (i = 0; i < ArraySize(tConfig->servers); i++)
|
||||||
{
|
{
|
||||||
ConfigListener *serverCfg = ArrayGet(tConfig.listen, i);
|
HttpServerConfig *serverCfg = ArrayGet(tConfig->servers, i);
|
||||||
|
|
||||||
HttpServerConfig args;
|
|
||||||
|
|
||||||
args.port = serverCfg->port;
|
|
||||||
args.threads = serverCfg->maxConnections;
|
|
||||||
args.maxConnections = serverCfg->maxConnections;
|
|
||||||
args.tlsCert = serverCfg->tls.cert;
|
|
||||||
args.tlsKey = serverCfg->tls.key;
|
|
||||||
args.flags = args.tlsCert && args.tlsKey ? HTTP_FLAG_TLS : HTTP_FLAG_NONE;
|
|
||||||
|
|
||||||
Log(LOG_DEBUG, "HTTP listener: %lu", i);
|
Log(LOG_DEBUG, "HTTP listener: %lu", i);
|
||||||
LogConfigIndent(LogConfigGlobal());
|
LogConfigIndent(LogConfigGlobal());
|
||||||
Log(LOG_DEBUG, "Port: %hu", serverCfg->port);
|
Log(LOG_DEBUG, "Port: %hu", serverCfg->port);
|
||||||
Log(LOG_DEBUG, "Threads: %u", serverCfg->threads);
|
Log(LOG_DEBUG, "Threads: %u", serverCfg->threads);
|
||||||
Log(LOG_DEBUG, "Max Connections: %u", serverCfg->maxConnections);
|
Log(LOG_DEBUG, "Max Connections: %u", serverCfg->maxConnections);
|
||||||
Log(LOG_DEBUG, "Flags: %d", args.flags);
|
Log(LOG_DEBUG, "Flags: %d", serverCfg->flags);
|
||||||
Log(LOG_DEBUG, "TLS Cert: %s", serverCfg->tls.cert);
|
Log(LOG_DEBUG, "TLS Cert: %s", serverCfg->tlsCert);
|
||||||
Log(LOG_DEBUG, "TLS Key: %s", serverCfg->tls.key);
|
Log(LOG_DEBUG, "TLS Key: %s", serverCfg->tlsKey);
|
||||||
LogConfigUnindent(LogConfigGlobal());
|
LogConfigUnindent(LogConfigGlobal());
|
||||||
|
|
||||||
|
serverCfg->handler = MatrixHttpHandler;
|
||||||
|
serverCfg->handlerArgs = &matrixArgs;
|
||||||
|
|
||||||
args.handler = MatrixHttpHandler;
|
if (serverCfg->flags & HTTP_FLAG_TLS)
|
||||||
args.handlerArgs = &matrixArgs;
|
|
||||||
|
|
||||||
if (args.flags & HTTP_FLAG_TLS)
|
|
||||||
{
|
{
|
||||||
if (UInt64Eq(UtilLastModified(serverCfg->tls.cert), UInt64Create(0, 0)))
|
if (UInt64Eq(UtilLastModified(serverCfg->tlsCert), UInt64Create(0, 0)))
|
||||||
{
|
{
|
||||||
Log(LOG_ERR, "%s: %s", strerror(errno), serverCfg->tls.cert);
|
Log(LOG_ERR, "%s: %s", strerror(errno), serverCfg->tlsCert);
|
||||||
exit = EXIT_FAILURE;
|
exit = EXIT_FAILURE;
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UInt64Eq(UtilLastModified(serverCfg->tls.key), UInt64Create(0, 0)))
|
if (UInt64Eq(UtilLastModified(serverCfg->tlsKey), UInt64Create(0, 0)))
|
||||||
{
|
{
|
||||||
Log(LOG_ERR, "%s: %s", strerror(errno), serverCfg->tls.key);
|
Log(LOG_ERR, "%s: %s", strerror(errno), serverCfg->tlsKey);
|
||||||
exit = EXIT_FAILURE;
|
exit = EXIT_FAILURE;
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
server = HttpServerCreate(&args);
|
server = HttpServerCreate(serverCfg);
|
||||||
if (!server)
|
if (!server)
|
||||||
{
|
{
|
||||||
Log(LOG_ERR, "Unable to create HTTP server on port %d: %s",
|
Log(LOG_ERR, "Unable to create HTTP server on port %d: %s",
|
||||||
|
@ -432,10 +417,10 @@ start:
|
||||||
|
|
||||||
Log(LOG_DEBUG, "Running as uid:gid: %d:%d.", getuid(), getgid());
|
Log(LOG_DEBUG, "Running as uid:gid: %d:%d.", getuid(), getgid());
|
||||||
|
|
||||||
if (tConfig.runAs.uid && tConfig.runAs.gid)
|
if (tConfig->uid && tConfig->gid)
|
||||||
{
|
{
|
||||||
userInfo = getpwnam(tConfig.runAs.uid);
|
userInfo = getpwnam(tConfig->uid);
|
||||||
groupInfo = getgrnam(tConfig.runAs.gid);
|
groupInfo = getgrnam(tConfig->gid);
|
||||||
|
|
||||||
if (!userInfo || !groupInfo)
|
if (!userInfo || !groupInfo)
|
||||||
{
|
{
|
||||||
|
@ -465,7 +450,7 @@ start:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log(LOG_DEBUG, "Set uid/gid to %s:%s.", tConfig.runAs.uid, tConfig.runAs.gid);
|
Log(LOG_DEBUG, "Set uid/gid to %s:%s.", tConfig->uid, tConfig->gid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -477,7 +462,7 @@ start:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (tConfig.runAs.uid && tConfig.runAs.gid)
|
if (tConfig->uid && tConfig->gid)
|
||||||
{
|
{
|
||||||
if (getuid() != userInfo->pw_uid || getgid() != groupInfo->gr_gid)
|
if (getuid() != userInfo->pw_uid || getgid() != groupInfo->gr_gid)
|
||||||
{
|
{
|
||||||
|
@ -490,16 +475,17 @@ start:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tConfig.maxCache)
|
if (!tConfig->maxCache)
|
||||||
{
|
{
|
||||||
Log(LOG_WARNING, "Database caching is disabled.");
|
Log(LOG_WARNING, "Database caching is disabled.");
|
||||||
Log(LOG_WARNING, "If this is not what you intended, check the config file");
|
Log(LOG_WARNING, "If this is not what you intended, check the config file");
|
||||||
Log(LOG_WARNING, "and ensure that maxCache is a valid number of bytes.");
|
Log(LOG_WARNING, "and ensure that maxCache is a valid number of bytes.");
|
||||||
}
|
}
|
||||||
|
|
||||||
DbMaxCacheSet(matrixArgs.db, tConfig.maxCache);
|
DbMaxCacheSet(matrixArgs.db, tConfig->maxCache);
|
||||||
|
|
||||||
ConfigUnlock(&tConfig);
|
ConfigUnlock(tConfig);
|
||||||
|
tConfig = NULL;
|
||||||
|
|
||||||
cron = CronCreate(60 * 1000); /* 1-minute tick */
|
cron = CronCreate(60 * 1000); /* 1-minute tick */
|
||||||
if (!cron)
|
if (!cron)
|
||||||
|
@ -606,7 +592,7 @@ finish:
|
||||||
Log(LOG_DEBUG, "Stopped and freed job scheduler.");
|
Log(LOG_DEBUG, "Stopped and freed job scheduler.");
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigUnlock(&tConfig);
|
ConfigUnlock(tConfig);
|
||||||
Log(LOG_DEBUG, "Unlocked configuration.");
|
Log(LOG_DEBUG, "Unlocked configuration.");
|
||||||
|
|
||||||
DbClose(matrixArgs.db);
|
DbClose(matrixArgs.db);
|
||||||
|
@ -615,12 +601,6 @@ finish:
|
||||||
HttpRouterFree(matrixArgs.router);
|
HttpRouterFree(matrixArgs.router);
|
||||||
Log(LOG_DEBUG, "Freed routing tree.");
|
Log(LOG_DEBUG, "Freed routing tree.");
|
||||||
|
|
||||||
if (pidPath)
|
|
||||||
{
|
|
||||||
remove(pidPath);
|
|
||||||
Free(pidPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Uninstall the memory hook because it uses the Log
|
* Uninstall the memory hook because it uses the Log
|
||||||
* API, whose configuration is being freed now, so it
|
* API, whose configuration is being freed now, so it
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
@ -68,14 +67,13 @@ ROUTE_IMPL(RouteChangePwd, path, argp)
|
||||||
|
|
||||||
char *msg;
|
char *msg;
|
||||||
|
|
||||||
Config config;
|
Config *config = ConfigLock(db);
|
||||||
|
|
||||||
ConfigLock(db, &config);
|
if (!config)
|
||||||
if (!config.ok)
|
|
||||||
{
|
{
|
||||||
Log(LOG_ERR, "%s", config.err);
|
Log(LOG_ERR, "Password endpoint failed to lock configuration.");
|
||||||
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
|
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
|
||||||
return MatrixErrorCreate(M_UNKNOWN, config.err);
|
return MatrixErrorCreate(M_UNKNOWN, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) path;
|
(void) path;
|
||||||
|
@ -158,7 +156,7 @@ ROUTE_IMPL(RouteChangePwd, path, argp)
|
||||||
response = HashMapCreate();
|
response = HashMapCreate();
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
ConfigUnlock(&config);
|
ConfigUnlock(config);
|
||||||
UserUnlock(user);
|
UserUnlock(user);
|
||||||
JsonFree(request);
|
JsonFree(request);
|
||||||
return response;
|
return response;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
@ -37,10 +36,10 @@ ROUTE_IMPL(RouteConfig, path, argp)
|
||||||
char *msg;
|
char *msg;
|
||||||
|
|
||||||
User *user = NULL;
|
User *user = NULL;
|
||||||
Config config;
|
Config *config = NULL;
|
||||||
|
|
||||||
HashMap *request = NULL;
|
HashMap *request = NULL;
|
||||||
Config newConf;
|
Config *newConf;
|
||||||
HashMap *newJson = NULL;
|
HashMap *newJson = NULL;
|
||||||
|
|
||||||
(void) path;
|
(void) path;
|
||||||
|
@ -67,19 +66,20 @@ ROUTE_IMPL(RouteConfig, path, argp)
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigLock(args->matrixArgs->db, &config);
|
config = ConfigLock(args->matrixArgs->db);
|
||||||
if (!config.ok)
|
if (!config)
|
||||||
{
|
{
|
||||||
Log(LOG_ERR, "%s", config.err);
|
msg = "Internal server error while locking configuration.";
|
||||||
|
Log(LOG_ERR, "Config endpoint failed to lock configuration.");
|
||||||
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
|
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
|
||||||
response = MatrixErrorCreate(M_UNKNOWN, config.err);
|
response = MatrixErrorCreate(M_UNKNOWN, msg);
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (HttpRequestMethodGet(args->context))
|
switch (HttpRequestMethodGet(args->context))
|
||||||
{
|
{
|
||||||
case HTTP_GET:
|
case HTTP_GET:
|
||||||
response = JsonDuplicate(DbJson(config.ref));
|
response = JsonDuplicate(DbJson(config->ref));
|
||||||
break;
|
break;
|
||||||
case HTTP_POST:
|
case HTTP_POST:
|
||||||
request = JsonDecode(HttpServerStream(args->context));
|
request = JsonDecode(HttpServerStream(args->context));
|
||||||
|
@ -90,10 +90,18 @@ ROUTE_IMPL(RouteConfig, path, argp)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigParse(request, &newConf);
|
newConf = ConfigParse(request);
|
||||||
if (newConf.ok)
|
if (!newConf)
|
||||||
{
|
{
|
||||||
if (DbJsonSet(config.ref, request))
|
msg = "Internal server error while parsing config.";
|
||||||
|
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
response = MatrixErrorCreate(M_UNKNOWN, msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newConf->ok)
|
||||||
|
{
|
||||||
|
if (DbJsonSet(config->ref, request))
|
||||||
{
|
{
|
||||||
response = HashMapCreate();
|
response = HashMapCreate();
|
||||||
/*
|
/*
|
||||||
|
@ -112,10 +120,10 @@ ROUTE_IMPL(RouteConfig, path, argp)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
response = MatrixErrorCreate(M_BAD_JSON, newConf.err);
|
response = MatrixErrorCreate(M_BAD_JSON, newConf->err);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigFree(&newConf);
|
ConfigFree(newConf);
|
||||||
JsonFree(request);
|
JsonFree(request);
|
||||||
break;
|
break;
|
||||||
case HTTP_PUT:
|
case HTTP_PUT:
|
||||||
|
@ -127,14 +135,22 @@ ROUTE_IMPL(RouteConfig, path, argp)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
newJson = JsonDuplicate(DbJson(config.ref));
|
newJson = JsonDuplicate(DbJson(config->ref));
|
||||||
JsonMerge(newJson, request);
|
JsonMerge(newJson, request);
|
||||||
|
|
||||||
ConfigParse(newJson, &newConf);
|
newConf = ConfigParse(newJson);
|
||||||
|
|
||||||
if (newConf.ok)
|
if (!newConf)
|
||||||
{
|
{
|
||||||
if (DbJsonSet(config.ref, newJson))
|
msg = "Internal server error while parsing config.";
|
||||||
|
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
response = MatrixErrorCreate(M_UNKNOWN, msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newConf->ok)
|
||||||
|
{
|
||||||
|
if (DbJsonSet(config->ref, newJson))
|
||||||
{
|
{
|
||||||
response = HashMapCreate();
|
response = HashMapCreate();
|
||||||
/*
|
/*
|
||||||
|
@ -153,10 +169,10 @@ ROUTE_IMPL(RouteConfig, path, argp)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
response = MatrixErrorCreate(M_BAD_JSON, newConf.err);
|
response = MatrixErrorCreate(M_BAD_JSON, newConf->err);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigFree(&newConf);
|
ConfigFree(newConf);
|
||||||
JsonFree(request);
|
JsonFree(request);
|
||||||
JsonFree(newJson);
|
JsonFree(newJson);
|
||||||
break;
|
break;
|
||||||
|
@ -169,6 +185,6 @@ ROUTE_IMPL(RouteConfig, path, argp)
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
UserUnlock(user);
|
UserUnlock(user);
|
||||||
ConfigUnlock(&config);
|
ConfigUnlock(config);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
@ -46,19 +45,17 @@ ROUTE_IMPL(RouteDeactivate, path, argp)
|
||||||
|
|
||||||
Db *db = args->matrixArgs->db;
|
Db *db = args->matrixArgs->db;
|
||||||
User *user = NULL;
|
User *user = NULL;
|
||||||
Config config;
|
Config *config = ConfigLock(db);
|
||||||
|
|
||||||
|
|
||||||
char *msg;
|
char *msg;
|
||||||
|
|
||||||
(void) path;
|
(void) path;
|
||||||
|
|
||||||
ConfigLock(db, &config);
|
if (!config)
|
||||||
if (!config.ok)
|
|
||||||
{
|
{
|
||||||
Log(LOG_ERR, "%s", config.err);
|
Log(LOG_ERR, "Deactivate endpoint failed to lock configuration.");
|
||||||
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
|
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
|
||||||
response = MatrixErrorCreate(M_UNKNOWN, config.err);
|
response = MatrixErrorCreate(M_UNKNOWN, NULL);
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,6 +148,6 @@ ROUTE_IMPL(RouteDeactivate, path, argp)
|
||||||
finish:
|
finish:
|
||||||
JsonFree(request);
|
JsonFree(request);
|
||||||
UserUnlock(user);
|
UserUnlock(user);
|
||||||
ConfigUnlock(&config);
|
ConfigUnlock(config);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
@ -40,17 +39,16 @@ GetServerName(Db * db)
|
||||||
{
|
{
|
||||||
char *name;
|
char *name;
|
||||||
|
|
||||||
Config config;
|
Config *config = ConfigLock(db);
|
||||||
|
|
||||||
ConfigLock(db, &config);
|
if (!config)
|
||||||
if (!config.ok)
|
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
name = StrDuplicate(config.serverName);
|
name = StrDuplicate(config->serverName);
|
||||||
|
|
||||||
ConfigUnlock(&config);
|
ConfigUnlock(config);
|
||||||
|
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
@ -65,14 +64,13 @@ ROUTE_IMPL(RouteLogin, path, argp)
|
||||||
|
|
||||||
char *msg;
|
char *msg;
|
||||||
|
|
||||||
Config config;
|
Config *config = ConfigLock(db);
|
||||||
|
|
||||||
ConfigLock(db, &config);
|
if (!config)
|
||||||
if (!config.ok)
|
|
||||||
{
|
{
|
||||||
Log(LOG_ERR, "%s", config.err);
|
Log(LOG_ERR, "Login endpoint failed to lock configuration.");
|
||||||
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
|
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
|
||||||
return MatrixErrorCreate(M_UNKNOWN, config.err);
|
return MatrixErrorCreate(M_UNKNOWN, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) path;
|
(void) path;
|
||||||
|
@ -151,7 +149,7 @@ ROUTE_IMPL(RouteLogin, path, argp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
userId = UserIdParse(userIdentifier.user, config.serverName);
|
userId = UserIdParse(userIdentifier.user, config->serverName);
|
||||||
if (!userId)
|
if (!userId)
|
||||||
{
|
{
|
||||||
msg = "Invalid user ID.";
|
msg = "Invalid user ID.";
|
||||||
|
@ -160,7 +158,7 @@ ROUTE_IMPL(RouteLogin, path, argp)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!StrEquals(userId->server, config.serverName)
|
if (!StrEquals(userId->server, config->serverName)
|
||||||
|| !UserExists(db, userId->localpart))
|
|| !UserExists(db, userId->localpart))
|
||||||
{
|
{
|
||||||
msg = "Unknown user ID.";
|
msg = "Unknown user ID.";
|
||||||
|
@ -223,13 +221,13 @@ ROUTE_IMPL(RouteLogin, path, argp)
|
||||||
}
|
}
|
||||||
|
|
||||||
fullUsername = StrConcat(4, "@", UserGetName(user), ":",
|
fullUsername = StrConcat(4, "@", UserGetName(user), ":",
|
||||||
config.serverName);
|
config->serverName);
|
||||||
HashMapSet(response, "user_id", JsonValueString(fullUsername));
|
HashMapSet(response, "user_id", JsonValueString(fullUsername));
|
||||||
Free(fullUsername);
|
Free(fullUsername);
|
||||||
|
|
||||||
HashMapSet(response, "well_known",
|
HashMapSet(response, "well_known",
|
||||||
JsonValueObject(
|
JsonValueObject(
|
||||||
MatrixClientWellKnown(config.baseUrl, config.identityServer)));
|
MatrixClientWellKnown(config->baseUrl, config->identityServer)));
|
||||||
|
|
||||||
UserAccessTokenFree(loginInfo->accessToken);
|
UserAccessTokenFree(loginInfo->accessToken);
|
||||||
Free(loginInfo->refreshToken);
|
Free(loginInfo->refreshToken);
|
||||||
|
@ -247,7 +245,7 @@ ROUTE_IMPL(RouteLogin, path, argp)
|
||||||
|
|
||||||
UserIdFree(userId);
|
UserIdFree(userId);
|
||||||
JsonFree(request);
|
JsonFree(request);
|
||||||
ConfigUnlock(&config);
|
ConfigUnlock(config);
|
||||||
|
|
||||||
LoginRequestFree(&loginRequest);
|
LoginRequestFree(&loginRequest);
|
||||||
LoginRequestUserIdentifierFree(&userIdentifier);
|
LoginRequestUserIdentifierFree(&userIdentifier);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
@ -73,7 +72,7 @@ ROUTE_IMPL(RouteRegister, path, argp)
|
||||||
char *session;
|
char *session;
|
||||||
DbRef *sessionRef;
|
DbRef *sessionRef;
|
||||||
|
|
||||||
Config config;
|
Config *config = ConfigLock(db);
|
||||||
|
|
||||||
regReq.username = NULL;
|
regReq.username = NULL;
|
||||||
regReq.password = NULL;
|
regReq.password = NULL;
|
||||||
|
@ -82,12 +81,15 @@ ROUTE_IMPL(RouteRegister, path, argp)
|
||||||
regReq.refresh_token = 0;
|
regReq.refresh_token = 0;
|
||||||
regReq.inhibit_login = 0;
|
regReq.inhibit_login = 0;
|
||||||
|
|
||||||
ConfigLock(db, &config);
|
|
||||||
if (!config.ok)
|
|
||||||
|
|
||||||
|
if (!config)
|
||||||
{
|
{
|
||||||
Log(LOG_ERR, "%s", config.err);
|
msg = "Internal server error while locking configuration.";
|
||||||
|
Log(LOG_ERR, "Registration endpoint failed to lock configuration.");
|
||||||
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
|
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
|
||||||
return MatrixErrorCreate(M_UNKNOWN, config.err);
|
return MatrixErrorCreate(M_UNKNOWN, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ArraySize(path) == 0)
|
if (ArraySize(path) == 0)
|
||||||
|
@ -115,7 +117,7 @@ ROUTE_IMPL(RouteRegister, path, argp)
|
||||||
|
|
||||||
if (regReq.username)
|
if (regReq.username)
|
||||||
{
|
{
|
||||||
if (!UserValidate(regReq.username, config.serverName))
|
if (!UserValidate(regReq.username, config->serverName))
|
||||||
{
|
{
|
||||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
response = MatrixErrorCreate(M_INVALID_USERNAME, NULL);
|
response = MatrixErrorCreate(M_INVALID_USERNAME, NULL);
|
||||||
|
@ -133,7 +135,7 @@ ROUTE_IMPL(RouteRegister, path, argp)
|
||||||
uiaFlows = ArrayCreate();
|
uiaFlows = ArrayCreate();
|
||||||
ArrayAdd(uiaFlows, RouteRegisterRegFlow());
|
ArrayAdd(uiaFlows, RouteRegisterRegFlow());
|
||||||
|
|
||||||
if (config.registration)
|
if (config->flags & CONFIG_REGISTRATION)
|
||||||
{
|
{
|
||||||
ArrayAdd(uiaFlows, UiaDummyFlow());
|
ArrayAdd(uiaFlows, UiaDummyFlow());
|
||||||
}
|
}
|
||||||
|
@ -180,7 +182,7 @@ ROUTE_IMPL(RouteRegister, path, argp)
|
||||||
response = HashMapCreate();
|
response = HashMapCreate();
|
||||||
|
|
||||||
fullUsername = StrConcat(4,
|
fullUsername = StrConcat(4,
|
||||||
"@", UserGetName(user), ":", config.serverName);
|
"@", UserGetName(user), ":", config->serverName);
|
||||||
HashMapSet(response, "user_id", JsonValueString(fullUsername));
|
HashMapSet(response, "user_id", JsonValueString(fullUsername));
|
||||||
Free(fullUsername);
|
Free(fullUsername);
|
||||||
|
|
||||||
|
@ -257,7 +259,7 @@ finish:
|
||||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
response = MatrixErrorCreate(M_MISSING_PARAM, msg);
|
response = MatrixErrorCreate(M_MISSING_PARAM, msg);
|
||||||
}
|
}
|
||||||
else if (!UserValidate(username, config.serverName))
|
else if (!UserValidate(username, config->serverName))
|
||||||
{
|
{
|
||||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
response = MatrixErrorCreate(M_INVALID_USERNAME, NULL);
|
response = MatrixErrorCreate(M_INVALID_USERNAME, NULL);
|
||||||
|
@ -281,6 +283,6 @@ finish:
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
ConfigUnlock(&config);
|
ConfigUnlock(config);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
@ -52,22 +51,23 @@ ROUTE_IMPL(RouteUiaFallback, path, argp)
|
||||||
HashMap *request;
|
HashMap *request;
|
||||||
HashMap *response;
|
HashMap *response;
|
||||||
int uiaResult;
|
int uiaResult;
|
||||||
Config config;
|
Config *config;
|
||||||
Array *flows;
|
Array *flows;
|
||||||
Array *flow;
|
Array *flow;
|
||||||
|
|
||||||
ConfigLock(args->matrixArgs->db, &config);
|
config = ConfigLock(args->matrixArgs->db);
|
||||||
if (!config.ok)
|
if (!config)
|
||||||
{
|
{
|
||||||
Log(LOG_ERR, "%s", config.err);
|
msg = "Internal server error: failed to lock configuration.";
|
||||||
|
Log(LOG_ERR, "UIA fallback failed to lock configuration.");
|
||||||
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
|
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
|
||||||
return MatrixErrorCreate(M_UNKNOWN, config.err);
|
return MatrixErrorCreate(M_UNKNOWN, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
request = JsonDecode(HttpServerStream(args->context));
|
request = JsonDecode(HttpServerStream(args->context));
|
||||||
if (!request)
|
if (!request)
|
||||||
{
|
{
|
||||||
ConfigUnlock(&config);
|
ConfigUnlock(config);
|
||||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||||
return MatrixErrorCreate(M_NOT_JSON, NULL);
|
return MatrixErrorCreate(M_NOT_JSON, NULL);
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ ROUTE_IMPL(RouteUiaFallback, path, argp)
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonFree(request);
|
JsonFree(request);
|
||||||
ConfigUnlock(&config);
|
ConfigUnlock(config);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
else if (HttpRequestMethodGet(args->context) != HTTP_GET)
|
else if (HttpRequestMethodGet(args->context) != HTTP_GET)
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
@ -51,18 +50,16 @@ ROUTE_IMPL(RouteUserProfile, path, argp)
|
||||||
|
|
||||||
char *msg;
|
char *msg;
|
||||||
|
|
||||||
Config config;
|
Config *config = ConfigLock(db);
|
||||||
|
|
||||||
ConfigLock(db, &config);
|
if (!config)
|
||||||
|
|
||||||
if (!config.ok)
|
|
||||||
{
|
{
|
||||||
Log(LOG_ERR, "%s", config.err);
|
Log(LOG_ERR, "User profile endpoint failed to lock configuration.");
|
||||||
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
|
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
|
||||||
return MatrixErrorCreate(M_UNKNOWN, config.err);
|
return MatrixErrorCreate(M_UNKNOWN, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
serverName = config.serverName;
|
serverName = config->serverName;
|
||||||
|
|
||||||
username = ArrayGet(path, 0);
|
username = ArrayGet(path, 0);
|
||||||
userId = UserIdParse(username, serverName);
|
userId = UserIdParse(username, serverName);
|
||||||
|
@ -183,9 +180,11 @@ ROUTE_IMPL(RouteUserProfile, path, argp)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
finish:
|
finish:
|
||||||
ConfigUnlock(&config);
|
ConfigUnlock(config);
|
||||||
|
|
||||||
/* Username is handled by the router, freeing it would cause issues. */
|
/* Username is handled by the router, freeing it *will* cause issues
|
||||||
|
* (see #33). I honestly don't know how it didn't come to bite us sooner.
|
||||||
|
Free(username); */
|
||||||
Free(entry);
|
Free(entry);
|
||||||
UserIdFree(userId);
|
UserIdFree(userId);
|
||||||
UserUnlock(user);
|
UserUnlock(user);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
@ -36,19 +35,21 @@ ROUTE_IMPL(RouteWellKnown, path, argp)
|
||||||
RouteArgs *args = argp;
|
RouteArgs *args = argp;
|
||||||
HashMap *response;
|
HashMap *response;
|
||||||
|
|
||||||
Config config;
|
Config *config = ConfigLock(args->matrixArgs->db);
|
||||||
|
|
||||||
ConfigLock(args->matrixArgs->db, &config);
|
char *msg;
|
||||||
if (!config.ok)
|
|
||||||
|
if (!config)
|
||||||
{
|
{
|
||||||
Log(LOG_ERR, "%s", config.err);
|
Log(LOG_ERR, "Well-known endpoint failed to lock configuration.");
|
||||||
|
msg = "Internal server error: couldn't lock database.";
|
||||||
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
|
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
|
||||||
return MatrixErrorCreate(M_UNKNOWN, config.err);
|
return MatrixErrorCreate(M_UNKNOWN, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StrEquals(ArrayGet(path, 0), "client"))
|
if (StrEquals(ArrayGet(path, 0), "client"))
|
||||||
{
|
{
|
||||||
response = MatrixClientWellKnown(config.baseUrl, config.identityServer);
|
response = MatrixClientWellKnown(config->baseUrl, config->identityServer);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -56,6 +57,6 @@ ROUTE_IMPL(RouteWellKnown, path, argp)
|
||||||
response = MatrixErrorCreate(M_NOT_FOUND, NULL);
|
response = MatrixErrorCreate(M_NOT_FOUND, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigUnlock(&config);
|
ConfigUnlock(config);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
@ -45,15 +44,14 @@ ROUTE_IMPL(RouteWhoami, path, argp)
|
||||||
char *deviceID;
|
char *deviceID;
|
||||||
char *msg;
|
char *msg;
|
||||||
|
|
||||||
Config config;
|
Config *config = ConfigLock(db);
|
||||||
|
|
||||||
ConfigLock(db, &config);
|
if (!config)
|
||||||
|
|
||||||
if (!config.ok)
|
|
||||||
{
|
{
|
||||||
Log(LOG_ERR, "%s", config.err);
|
msg = "Internal server error: couldn't lock database.";
|
||||||
|
Log(LOG_ERR, "Who am I endpoint failed to lock configuration.");
|
||||||
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
|
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
|
||||||
return MatrixErrorCreate(M_UNKNOWN, config.err);
|
return MatrixErrorCreate(M_UNKNOWN, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) path;
|
(void) path;
|
||||||
|
@ -77,7 +75,7 @@ ROUTE_IMPL(RouteWhoami, path, argp)
|
||||||
|
|
||||||
response = HashMapCreate();
|
response = HashMapCreate();
|
||||||
|
|
||||||
userID = StrConcat(4, "@", UserGetName(user), ":", config.serverName);
|
userID = StrConcat(4, "@", UserGetName(user), ":", config->serverName);
|
||||||
deviceID = StrDuplicate(UserGetDeviceId(user));
|
deviceID = StrDuplicate(UserGetDeviceId(user));
|
||||||
|
|
||||||
UserUnlock(user);
|
UserUnlock(user);
|
||||||
|
@ -89,6 +87,6 @@ ROUTE_IMPL(RouteWhoami, path, argp)
|
||||||
Free(deviceID);
|
Free(deviceID);
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
ConfigUnlock(&config);
|
ConfigUnlock(config);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
@ -136,7 +135,7 @@ TelodendriaPrintHeader(void)
|
||||||
Log(LOG_INFO, "Telodendria v" TELODENDRIA_VERSION " (%s v%s)", CytoplasmGetName(), CytoplasmGetVersion());
|
Log(LOG_INFO, "Telodendria v" TELODENDRIA_VERSION " (%s v%s)", CytoplasmGetName(), CytoplasmGetVersion());
|
||||||
Log(LOG_INFO, "");
|
Log(LOG_INFO, "");
|
||||||
Log(LOG_INFO,
|
Log(LOG_INFO,
|
||||||
"Copyright (C) 2024 Jordan Bancino <@jordan:bancino.net>");
|
"Copyright (C) 2023 Jordan Bancino <@jordan:bancino.net>");
|
||||||
Log(LOG_INFO,
|
Log(LOG_INFO,
|
||||||
"Documentation/Support: https://telodendria.io");
|
"Documentation/Support: https://telodendria.io");
|
||||||
Log(LOG_INFO, "");
|
Log(LOG_INFO, "");
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
@ -206,7 +205,7 @@ UiaStageBuild(char *type, HashMap * params)
|
||||||
|
|
||||||
int
|
int
|
||||||
UiaComplete(Array * flows, HttpServerContext * context, Db * db,
|
UiaComplete(Array * flows, HttpServerContext * context, Db * db,
|
||||||
HashMap * request, HashMap ** response, Config config)
|
HashMap * request, HashMap ** response, Config * config)
|
||||||
{
|
{
|
||||||
JsonValue *val;
|
JsonValue *val;
|
||||||
HashMap *auth;
|
HashMap *auth;
|
||||||
|
@ -363,10 +362,10 @@ UiaComplete(Array * flows, HttpServerContext * context, Db * db,
|
||||||
|
|
||||||
type = JsonValueAsString(HashMapGet(identifier, "type"));
|
type = JsonValueAsString(HashMapGet(identifier, "type"));
|
||||||
userId = UserIdParse(JsonValueAsString(HashMapGet(identifier, "user")),
|
userId = UserIdParse(JsonValueAsString(HashMapGet(identifier, "user")),
|
||||||
config.serverName);
|
config->serverName);
|
||||||
|
|
||||||
if (!type || !StrEquals(type, "m.id.user")
|
if (!type || !StrEquals(type, "m.id.user")
|
||||||
|| !userId || !StrEquals(userId->server, config.serverName))
|
|| !userId || !StrEquals(userId->server, config->serverName))
|
||||||
{
|
{
|
||||||
HttpResponseStatus(context, HTTP_UNAUTHORIZED);
|
HttpResponseStatus(context, HTTP_UNAUTHORIZED);
|
||||||
ret = BuildResponse(flows, db, response, session, dbRef);
|
ret = BuildResponse(flows, db, response, session, dbRef);
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
@ -49,12 +48,68 @@
|
||||||
* .Xr telodendria-config 7 .
|
* .Xr telodendria-config 7 .
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Schema/Config.h>
|
|
||||||
|
|
||||||
#include <Cytoplasm/HashMap.h>
|
#include <Cytoplasm/HashMap.h>
|
||||||
#include <Cytoplasm/Array.h>
|
#include <Cytoplasm/Array.h>
|
||||||
#include <Cytoplasm/Db.h>
|
#include <Cytoplasm/Db.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bit flags that can be set in the flags field of the configuration
|
||||||
|
* structure.
|
||||||
|
*/
|
||||||
|
typedef enum ConfigFlag
|
||||||
|
{
|
||||||
|
CONFIG_FEDERATION = (1 << 0),
|
||||||
|
CONFIG_REGISTRATION = (1 << 1),
|
||||||
|
CONFIG_LOG_COLOR = (1 << 2),
|
||||||
|
CONFIG_LOG_FILE = (1 << 3),
|
||||||
|
CONFIG_LOG_STDOUT = (1 << 4),
|
||||||
|
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;
|
||||||
|
|
||||||
|
char *uid;
|
||||||
|
char *gid;
|
||||||
|
|
||||||
|
unsigned int flags;
|
||||||
|
|
||||||
|
size_t maxCache;
|
||||||
|
|
||||||
|
char *logTimestamp;
|
||||||
|
int logLevel;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An array of HttpServerConfig structures. Consult the HttpServer
|
||||||
|
* API.
|
||||||
|
*/
|
||||||
|
Array *servers;
|
||||||
|
} Config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a JSON object, extracting the necessary values, validating
|
* Parse a JSON object, extracting the necessary values, validating
|
||||||
* them, and adding them to the configuration structure for use by the
|
* them, and adding them to the configuration structure for use by the
|
||||||
|
@ -65,7 +120,14 @@
|
||||||
* set the ok flag to 0. The caller should always check the ok flag,
|
* 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.
|
* and if there is an error, it should display the error to the user.
|
||||||
*/
|
*/
|
||||||
extern void ConfigParse(HashMap *, Config *);
|
extern Config * ConfigParse(HashMap *);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
extern void ConfigFree(Config *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether or not the configuration exists in the database,
|
* Check whether or not the configuration exists in the database,
|
||||||
|
@ -88,7 +150,7 @@ extern int ConfigCreateDefault(Db *);
|
||||||
* The return value of this function is the same as
|
* The return value of this function is the same as
|
||||||
* .Fn ConfigParse .
|
* .Fn ConfigParse .
|
||||||
*/
|
*/
|
||||||
extern void ConfigLock(Db *, Config *);
|
extern Config * ConfigLock(Db *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unlock the specified configuration, returning it back to the
|
* Unlock the specified configuration, returning it back to the
|
||||||
|
@ -98,9 +160,4 @@ extern void ConfigLock(Db *, Config *);
|
||||||
*/
|
*/
|
||||||
extern int ConfigUnlock(Config *);
|
extern int ConfigUnlock(Config *);
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a ConfigLogLevel into a valid syslog level.
|
|
||||||
*/
|
|
||||||
extern int ConfigLogLevelToSyslog(ConfigLogLevel);
|
|
||||||
|
|
||||||
#endif /* TELODENDRIA_CONFIG_H */
|
#endif /* TELODENDRIA_CONFIG_H */
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
@ -133,7 +132,7 @@ extern void UiaCleanup(MatrixHttpHandlerArgs *);
|
||||||
* the caller proceed with its logic.
|
* the caller proceed with its logic.
|
||||||
*/
|
*/
|
||||||
extern int
|
extern int
|
||||||
UiaComplete(Array *, HttpServerContext *, Db *, HashMap *, HashMap **, Config);
|
UiaComplete(Array *, HttpServerContext *, Db *, HashMap *, HashMap **, Config *);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Free an array of flows, as described above. Even though the caller
|
* Free an array of flows, as described above. Even though the caller
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net> with
|
* Copyright (C) 2022-2024 Jordan Bancino <@jordan:bancino.net>
|
||||||
* other valuable contributors. See CONTRIBUTORS.txt for the full list.
|
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation files
|
* obtaining a copy of this software and associated documentation files
|
||||||
|
|
Loading…
Reference in a new issue