forked from Telodendria/Telodendria
Compare commits
22 commits
fix-double
...
master
Author | SHA1 | Date | |
---|---|---|---|
71491ab6fc | |||
5041e0c991 | |||
66c237727b | |||
505d01cea1 | |||
c7433bb745 | |||
8546ddb909 | |||
0e946b2422 | |||
12e11f74a1 | |||
3304f8c08f | |||
59e3a6d3e2 | |||
46dcf8ab59 | |||
21b830e514 | |||
42223c94bb | |||
e083ece2ed | |||
2fcd51e810 | |||
775b1d9571 | |||
6dd4440125 | |||
e263eca5dc | |||
ac9372a30a | |||
a8924b8437 | |||
ff85b72899 | |||
bccbb3bcac |
15 changed files with 298 additions and 37 deletions
27
.forgejo/workflows/compile.yaml
Normal file
27
.forgejo/workflows/compile.yaml
Normal file
|
@ -0,0 +1,27 @@
|
|||
name: Compile Telodendria
|
||||
run-name: Compile Telodendria on ${{ forgejo.actor }}
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'ma*'
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
"Compile Telodendria":
|
||||
strategy:
|
||||
matrix:
|
||||
os: [alpine]
|
||||
arch: [aarch64]
|
||||
runs-on: ["${{ matrix.os }}", "${{ matrix.arch }}"]
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Configure Telodendria
|
||||
run: ./configure
|
||||
- name: Configure & Build Cytoplasm
|
||||
run: make cytoplasm
|
||||
- name: Build Telodendria
|
||||
run: make
|
44
.forgejo/workflows/release.yaml
Normal file
44
.forgejo/workflows/release.yaml
Normal file
|
@ -0,0 +1,44 @@
|
|||
name: Release Telodendria
|
||||
run-name: Release Telodendria on ${{ forgejo.actor }}
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
"Release Telodendria":
|
||||
strategy:
|
||||
matrix:
|
||||
os: [alpine]
|
||||
arch: [aarch64]
|
||||
runs-on: ["${{ matrix.os }}", "${{ matrix.arch }}"]
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Archive submodules
|
||||
run: git submodule foreach --recursive 'git archive --format tar --prefix=$displaypath/ -o submodule.tar HEAD'
|
||||
- name: Archive repository
|
||||
run: git archive --format tar -o release.tar HEAD
|
||||
- name: Produce release archive
|
||||
run: |
|
||||
TOPDIR=$(pwd) git submodule --quiet foreach --recursive 'cd $TOPDIR; tar --concatenate --file=release.tar $displaypath/submodule.tar; rm -fv $displaypath/submodule.tar'
|
||||
gzip release.tar
|
||||
mkdir release
|
||||
mv release.tar.gz release/Telodendria-$GITHUB_REF_NAME.tar.gz
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Telodendria-$GITHUB_REF_NAME.tar.gz
|
||||
path: release/Telodendria-$GITHUB_REF_NAME.tar.gz
|
||||
- name: Publish release
|
||||
uses: actions/forgejo-release@v2
|
||||
with:
|
||||
tag: $GITHUB_REF_NAME
|
||||
title: "Telodendria $GITHUB_REF_NAME"
|
||||
release-dir: release/
|
||||
release-notes: "docs/CHANGELOG.md"
|
||||
direction: upload
|
||||
prerelease: true
|
|
@ -1,29 +0,0 @@
|
|||
name: Compile Telodendria
|
||||
run-name: Compile Telodendria on ${{ gitea.actor }}
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
"Compile Telodendria":
|
||||
strategy:
|
||||
matrix:
|
||||
os: [debian-v12.4, alpine-v3.19, openbsd-v7.4, freebsd-v14.0, netbsd-v9.3]
|
||||
arch: [x86, x86_64]
|
||||
exclude:
|
||||
# 32-bit OpenBSD does not behave well in QEMU. Even when using
|
||||
# QEMU to emulate i386, it utilizes 100% of its CPU core and is
|
||||
# still extremely sluggish. Thus, we don't have a working 32-bit
|
||||
# OpenBSD runner, so exclude it from the matrix configuration.
|
||||
- os: openbsd-v7.4
|
||||
arch: x86
|
||||
runs-on: ["${{ matrix.os }}", "${{ matrix.arch }}"]
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
- name: Configure Telodendria
|
||||
run: ./configure
|
||||
- name: Configure & Build Cytoplasm
|
||||
run: make cytoplasm
|
||||
- name: Build Telodendria
|
||||
run: make
|
|
@ -1 +1 @@
|
|||
Subproject commit 5d87da31cda74e6808eebca72e9475aabde86532
|
||||
Subproject commit 4f316ff7b3a955b831ca4aefb8679ddf3396a7d0
|
13
Schema/UserDirectoryRequest.json
Normal file
13
Schema/UserDirectoryRequest.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"header": "Schema\/UserDirectoryRequest.h",
|
||||
"types": {
|
||||
"UserDirectoryRequest": {
|
||||
"fields": {
|
||||
"search_term": { "type": "string" },
|
||||
"limit": { "type": "integer" }
|
||||
},
|
||||
"type": "struct"
|
||||
}
|
||||
},
|
||||
"guard": "TELODENDRIA_SCHEMA_USERDIRECTORYREQUEST_H"
|
||||
}
|
13
configure
vendored
13
configure
vendored
|
@ -34,7 +34,7 @@ case "$(uname)" in
|
|||
# These systems typically use GCC.
|
||||
SCRIPT_ARGS="${SCRIPT_ARGS} --cc=gcc"
|
||||
;;
|
||||
OpenBSD|FreeBSD)
|
||||
OpenBSD|FreeBSD|Darwin)
|
||||
# These systems typically use Clang.
|
||||
SCRIPT_ARGS="${SCRIPT_ARGS} --cc=clang"
|
||||
;;
|
||||
|
@ -231,15 +231,19 @@ compile_schema() {
|
|||
install_out() {
|
||||
src="$1"
|
||||
out="$2"
|
||||
dir=$(dirname "$out")
|
||||
|
||||
echo "${TAB}install -D \"$src\" \"$out\""
|
||||
echo "${TAB}mkdir -p \"$dir\""
|
||||
echo "${TAB}cp \"$src\" \"$out\""
|
||||
}
|
||||
|
||||
install_man() {
|
||||
src="${OUT}/man/man3/${BIN_NAME}-$(basename $1 .h).3"
|
||||
out="$2"
|
||||
dir=$(dirname "$out")
|
||||
|
||||
echo "${TAB}install -D \"$src\" \"$out\""
|
||||
echo "${TAB}mkdir -p \"$dir\""
|
||||
echo "${TAB}cp \"$src\" \"$out\""
|
||||
}
|
||||
|
||||
uninstall_out() {
|
||||
|
@ -287,7 +291,8 @@ ${TAB}done
|
|||
${BIN_NAME}: ${OUT}/bin/${BIN_NAME}
|
||||
|
||||
install: ${BIN_NAME}
|
||||
${TAB}install -D ${OUT}/bin/${BIN_NAME} \$(PREFIX)/bin/${BIN_NAME}
|
||||
${TAB}mkdir -p \$(PREFIX)/bin
|
||||
${TAB}cp ${OUT}/bin/${BIN_NAME} \$(PREFIX)/bin/${BIN_NAME}
|
||||
|
||||
uninstall:
|
||||
${TAB}rm \$(PREFIX)/bin/${BIN_NAME}
|
||||
|
|
|
@ -152,7 +152,7 @@ ParseIPv6(char **str, char **out)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
while ((c = Iterate(str)) && IsIPv6Char(c))
|
||||
while ((c = Iterate(str)) && IsIPv6Char(c) && digits < 8)
|
||||
{
|
||||
char *ipv4;
|
||||
if (isxdigit(c))
|
||||
|
|
|
@ -72,6 +72,7 @@ RouterBuild(void)
|
|||
|
||||
R("/_matrix/client/v3/profile/(.*)", RouteUserProfile);
|
||||
R("/_matrix/client/v3/profile/(.*)/(avatar_url|displayname)", RouteUserProfile);
|
||||
R("/_matrix/client/v3/user_directory/search", RouteUserDirectory);
|
||||
|
||||
R("/_matrix/client/v3/user/(.*)/filter", RouteFilter);
|
||||
R("/_matrix/client/v3/user/(.*)/filter/(.*)", RouteFilter);
|
||||
|
|
199
src/Routes/RouteUserDirectory.c
Normal file
199
src/Routes/RouteUserDirectory.c
Normal file
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* Copyright (C) 2022-2023 Jordan Bancino <@jordan:bancino.net>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without dirRequest.limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#include <Routes.h>
|
||||
|
||||
#include <Cytoplasm/Array.h>
|
||||
#include <Cytoplasm/HashMap.h>
|
||||
#include <Cytoplasm/Json.h>
|
||||
#include <Cytoplasm/Str.h>
|
||||
#include <Cytoplasm/Memory.h>
|
||||
#include <Cytoplasm/Db.h>
|
||||
|
||||
#include <Schema/UserDirectoryRequest.h>
|
||||
|
||||
#include <User.h>
|
||||
|
||||
ROUTE_IMPL(RouteUserDirectory, path, argp)
|
||||
{
|
||||
RouteArgs *args = argp;
|
||||
HashMap *response = NULL;
|
||||
HashMap *request = NULL;
|
||||
|
||||
Array *users = NULL;
|
||||
Array *results = NULL;
|
||||
|
||||
Db *db = args->matrixArgs->db;
|
||||
|
||||
Config config = { .ok = 0 };
|
||||
|
||||
User *user = NULL;
|
||||
|
||||
char *token = NULL;
|
||||
char *requesterName = NULL;
|
||||
char *msg = NULL;
|
||||
|
||||
UserDirectoryRequest dirRequest;
|
||||
|
||||
size_t i, included;
|
||||
|
||||
(void) path;
|
||||
|
||||
dirRequest.search_term = NULL;
|
||||
dirRequest.limit = 10;
|
||||
|
||||
|
||||
if (HttpRequestMethodGet(args->context) != HTTP_POST)
|
||||
{
|
||||
msg = "Request supports only POST.";
|
||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||
response = MatrixErrorCreate(M_UNRECOGNIZED, msg);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
request = JsonDecode(HttpServerStream(args->context));
|
||||
if (!request)
|
||||
{
|
||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||
response = MatrixErrorCreate(M_NOT_JSON, NULL);
|
||||
goto finish;
|
||||
}
|
||||
if (!UserDirectoryRequestFromJson(request, &dirRequest, &msg))
|
||||
{
|
||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||
response = MatrixErrorCreate(M_BAD_JSON, msg);
|
||||
goto finish;
|
||||
}
|
||||
if (!dirRequest.search_term)
|
||||
{
|
||||
msg = "Field 'search_term' not set.";
|
||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||
response = MatrixErrorCreate(M_BAD_JSON, msg);
|
||||
goto finish;
|
||||
|
||||
}
|
||||
|
||||
response = MatrixGetAccessToken(args->context, &token);
|
||||
if (response)
|
||||
{
|
||||
return response;
|
||||
}
|
||||
|
||||
/* TODO: Actually use information related to the user. */
|
||||
user = UserAuthenticate(db, token);
|
||||
if (!user)
|
||||
{
|
||||
HttpResponseStatus(args->context, HTTP_BAD_REQUEST);
|
||||
response = MatrixErrorCreate(M_UNKNOWN_TOKEN, NULL);
|
||||
goto finish;
|
||||
}
|
||||
requesterName = UserGetName(user);
|
||||
|
||||
response = HashMapCreate();
|
||||
results = ArrayCreate();
|
||||
|
||||
/* TODO: Check for users matching search term and users outside our
|
||||
* local server. */
|
||||
users = DbList(db, 1, "users");
|
||||
|
||||
ConfigLock(db, &config);
|
||||
if (!config.ok)
|
||||
{
|
||||
Log(LOG_ERR, "Directory endpoint failed to lock configuration.");
|
||||
HttpResponseStatus(args->context, HTTP_INTERNAL_SERVER_ERROR);
|
||||
response = MatrixErrorCreate(M_UNKNOWN, config.err);
|
||||
|
||||
goto finish;
|
||||
}
|
||||
|
||||
#define IncludedLtLimit ((int64_t) included < dirRequest.limit)
|
||||
for (i = 0, included = 0; i < ArraySize(users) && IncludedLtLimit; i++)
|
||||
#undef IncludedLtLimit
|
||||
{
|
||||
HashMap *obj;
|
||||
User *currentUser;
|
||||
char *name = ArrayGet(users, i);
|
||||
char *displayName;
|
||||
char *lowerDisplayName;
|
||||
char *avatarUrl;
|
||||
|
||||
if (!StrEquals(name, requesterName))
|
||||
{
|
||||
currentUser = UserLock(db, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
currentUser = user;
|
||||
}
|
||||
|
||||
displayName = UserGetProfile(currentUser, "displayname");
|
||||
lowerDisplayName = StrLower(displayName);
|
||||
avatarUrl = UserGetProfile(currentUser, "avatar_url");
|
||||
|
||||
/* Check for the user ID and display name. */
|
||||
if (strstr(name, dirRequest.search_term) ||
|
||||
(lowerDisplayName &&
|
||||
strstr(lowerDisplayName, dirRequest.search_term)))
|
||||
{
|
||||
included++;
|
||||
|
||||
obj = HashMapCreate();
|
||||
if (displayName)
|
||||
{
|
||||
JsonSet(obj, JsonValueString(displayName), 1, "display_name");
|
||||
}
|
||||
if (avatarUrl)
|
||||
{
|
||||
JsonSet(obj, JsonValueString(displayName), 1, "avatar_url");
|
||||
}
|
||||
if (name)
|
||||
{
|
||||
char *uID = StrConcat(4, "@", name, ":", config.serverName);
|
||||
JsonSet(obj, JsonValueString(uID), 1, "user_id");
|
||||
Free(uID);
|
||||
}
|
||||
ArrayAdd(results, JsonValueObject(obj));
|
||||
}
|
||||
if (lowerDisplayName)
|
||||
{
|
||||
Free(lowerDisplayName);
|
||||
}
|
||||
if (!StrEquals(name, requesterName))
|
||||
{
|
||||
UserUnlock(currentUser);
|
||||
}
|
||||
}
|
||||
JsonSet(response, JsonValueArray(results), 1, "results");
|
||||
JsonSet(response,
|
||||
JsonValueBoolean((int64_t) included == dirRequest.limit),
|
||||
1, "limited"
|
||||
);
|
||||
|
||||
finish:
|
||||
UserUnlock(user);
|
||||
JsonFree(request);
|
||||
DbListFree(users);
|
||||
ConfigUnlock(&config);
|
||||
UserDirectoryRequestFree(&dirRequest);
|
||||
return response;
|
||||
}
|
|
@ -384,7 +384,7 @@ UserCheckPassword(User * user, char *password)
|
|||
|
||||
tmp = StrConcat(2, password, salt);
|
||||
hashBytes = Sha256(tmp);
|
||||
hashedPwd = ShaToHex(hashBytes);
|
||||
hashedPwd = ShaToHex(hashBytes, HASH_SHA256);
|
||||
Free(tmp);
|
||||
Free(hashBytes);
|
||||
|
||||
|
@ -415,7 +415,7 @@ UserSetPassword(User * user, char *password)
|
|||
salt = StrRandom(16);
|
||||
tmpstr = StrConcat(2, password, salt);
|
||||
hashBytes = Sha256(tmpstr);
|
||||
hash = ShaToHex(hashBytes);
|
||||
hash = ShaToHex(hashBytes, HASH_SHA256);
|
||||
|
||||
JsonValueFree(HashMapSet(json, "salt", JsonValueString(salt)));
|
||||
JsonValueFree(HashMapSet(json, "password", JsonValueString(hash)));
|
||||
|
|
|
@ -86,6 +86,7 @@ ROUTE(RouteChangePwd);
|
|||
ROUTE(RouteDeactivate);
|
||||
ROUTE(RouteTokenValid);
|
||||
ROUTE(RouteUserProfile);
|
||||
ROUTE(RouteUserDirectory);
|
||||
ROUTE(RouteRequestToken);
|
||||
|
||||
ROUTE(RouteUiaFallback);
|
||||
|
|
Loading…
Reference in a new issue