forked from lda/telodendria
Implement filter validation by using j2s.
This commit is contained in:
parent
77d71989df
commit
5f3220372e
7 changed files with 169 additions and 112 deletions
|
@ -4,3 +4,5 @@ data
|
||||||
*.patch
|
*.patch
|
||||||
*.log
|
*.log
|
||||||
vgcore.*
|
vgcore.*
|
||||||
|
src/Schema
|
||||||
|
src/include/Schema
|
||||||
|
|
121
Schema/Filter.json
Normal file
121
Schema/Filter.json
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
{
|
||||||
|
"header": "Schema\/Filter.h",
|
||||||
|
"types": {
|
||||||
|
"FilterRoom": {
|
||||||
|
"fields": {
|
||||||
|
"not_rooms": {
|
||||||
|
"type": "[string]"
|
||||||
|
},
|
||||||
|
"state": {
|
||||||
|
"type": "FilterRoomEvent"
|
||||||
|
},
|
||||||
|
"include_leave": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"timeline": {
|
||||||
|
"type": "FilterRoomEvent"
|
||||||
|
},
|
||||||
|
"account_data": {
|
||||||
|
"type": "FilterRoomEvent"
|
||||||
|
},
|
||||||
|
"rooms": {
|
||||||
|
"type": "[string]"
|
||||||
|
},
|
||||||
|
"ephemeral": {
|
||||||
|
"type": "FilterRoomEvent"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "struct"
|
||||||
|
},
|
||||||
|
"FilterEventFormat": {
|
||||||
|
"fields": {
|
||||||
|
"federation": {
|
||||||
|
"name": "FILTER_FORMAT_FEDERATION"
|
||||||
|
},
|
||||||
|
"client": {
|
||||||
|
"name": "FILTER_FORMANT_CLIENT"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "enum"
|
||||||
|
},
|
||||||
|
"FilterEvent": {
|
||||||
|
"fields": {
|
||||||
|
"not_senders": {
|
||||||
|
"type": "[string]"
|
||||||
|
},
|
||||||
|
"limit": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"senders": {
|
||||||
|
"type": "[string]"
|
||||||
|
},
|
||||||
|
"types": {
|
||||||
|
"type": "[string]"
|
||||||
|
},
|
||||||
|
"not_types": {
|
||||||
|
"type": "[string]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "struct"
|
||||||
|
},
|
||||||
|
"Filter": {
|
||||||
|
"fields": {
|
||||||
|
"event_format": {
|
||||||
|
"type": "FilterEventFormat"
|
||||||
|
},
|
||||||
|
"presence": {
|
||||||
|
"type": "FilterEvent"
|
||||||
|
},
|
||||||
|
"account_data": {
|
||||||
|
"type": "FilterEvent"
|
||||||
|
},
|
||||||
|
"room": {
|
||||||
|
"type": "FilterRoom"
|
||||||
|
},
|
||||||
|
"event_fields": {
|
||||||
|
"type": "[string]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "struct"
|
||||||
|
},
|
||||||
|
"FilterRoomEvent": {
|
||||||
|
"fields": {
|
||||||
|
"not_rooms": {
|
||||||
|
"type": "[string]"
|
||||||
|
},
|
||||||
|
"not_senders": {
|
||||||
|
"type": "[string]"
|
||||||
|
},
|
||||||
|
"limit": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"senders": {
|
||||||
|
"type": "[string]"
|
||||||
|
},
|
||||||
|
"include_redundant_members": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"types": {
|
||||||
|
"type": "[string]"
|
||||||
|
},
|
||||||
|
"rooms": {
|
||||||
|
"type": "[string]"
|
||||||
|
},
|
||||||
|
"lazy_load_members": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"not_types": {
|
||||||
|
"type": "[string]"
|
||||||
|
},
|
||||||
|
"contains_url": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"unread_thread_notifications": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "struct"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"guard": "TELODENDRIA_SCHEMA_FILTER_H"
|
||||||
|
}
|
10
TODO.txt
10
TODO.txt
|
@ -31,16 +31,12 @@ Milestone: v0.4.0
|
||||||
[ ] Registration token endpoints
|
[ ] Registration token endpoints
|
||||||
|
|
||||||
[~] Cytoplasm
|
[~] Cytoplasm
|
||||||
[ ] HashMap/Json
|
|
||||||
[ ] Strip all keys except subset
|
|
||||||
[ ] Strip only subset of keys
|
|
||||||
[ ] Object validation - contains only certain keys,
|
|
||||||
with certain types, no extraneous keys, etc.
|
|
||||||
[~] Debug OpenSSL
|
[~] Debug OpenSSL
|
||||||
[x] Database corruption
|
[x] Database corruption
|
||||||
[ ] File descriptor exhaustion
|
[ ] File descriptor exhaustion
|
||||||
[ ] Random memory corruption after many requests.
|
[ ] Random memory corruption after many requests.
|
||||||
[ ] j2s
|
[~] j2s
|
||||||
|
[x] Properly support arrays of primitives.
|
||||||
[ ] How to set default value of true on boolean?
|
[ ] How to set default value of true on boolean?
|
||||||
- defaults probably need to be set at parser level, not
|
- defaults probably need to be set at parser level, not
|
||||||
enough to set it after.
|
enough to set it after.
|
||||||
|
@ -49,8 +45,6 @@ Milestone: v0.4.0
|
||||||
use the default. This will make debugging a lot easier.
|
use the default. This will make debugging a lot easier.
|
||||||
[ ] Make sure admin registration token is printed to log, not stdout.
|
[ ] Make sure admin registration token is printed to log, not stdout.
|
||||||
Unless they are the same, of course.
|
Unless they are the same, of course.
|
||||||
[x] Fix Json UTF-8 handling.
|
|
||||||
[ ] Update Makefile
|
|
||||||
|
|
||||||
Milestone: v0.5.0
|
Milestone: v0.5.0
|
||||||
-----------------
|
-----------------
|
||||||
|
|
88
src/Filter.c
88
src/Filter.c
|
@ -21,92 +21,12 @@
|
||||||
* 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 <Routes.h>
|
#include <Filter.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <Schema/Filter.h>
|
||||||
|
|
||||||
#include <HashMap.h>
|
|
||||||
#include <Memory.h>
|
|
||||||
#include <User.h>
|
|
||||||
#include <Json.h>
|
|
||||||
#include <Str.h>
|
|
||||||
|
|
||||||
static HashMap *
|
|
||||||
ValidateRoomFilter(HashMap * json)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static HashMap *
|
|
||||||
ValidateEventFields(Array * fields)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static HashMap *
|
|
||||||
ValidateEventFormat(char *fmt)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static HashMap *
|
|
||||||
ValidateEventFilter(HashMap * json)
|
|
||||||
{
|
|
||||||
JsonValue *val;
|
|
||||||
|
|
||||||
val = HashMapGet(json, "limit");
|
|
||||||
if (val)
|
|
||||||
{
|
|
||||||
if (JsonValueType(val) == JSON_INTEGER)
|
|
||||||
{
|
|
||||||
long limit = JsonValueAsInteger(val);
|
|
||||||
|
|
||||||
if (limit <= 0 || limit > 100)
|
|
||||||
{
|
|
||||||
return MatrixErrorCreate(M_BAD_JSON);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return MatrixErrorCreate(M_BAD_JSON);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
HashMap *
|
HashMap *
|
||||||
FilterValidate(HashMap * json)
|
FilterApply(Filter *filter, HashMap *event)
|
||||||
{
|
{
|
||||||
JsonValue *val;
|
return NULL;
|
||||||
HashMap *response = NULL;
|
|
||||||
|
|
||||||
#define VALIDATE(key, type, func, param) \
|
|
||||||
val = HashMapGet(json, key); \
|
|
||||||
if (val) \
|
|
||||||
{ \
|
|
||||||
if (JsonValueType(val) == type) \
|
|
||||||
{ \
|
|
||||||
response = func(param); \
|
|
||||||
if (response) \
|
|
||||||
{ \
|
|
||||||
goto finish; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
else \
|
|
||||||
{ \
|
|
||||||
return MatrixErrorCreate(M_BAD_JSON); \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
|
|
||||||
VALIDATE("account_data", JSON_OBJECT, ValidateEventFilter, JsonValueAsObject(val));
|
|
||||||
VALIDATE("event_fields", JSON_ARRAY, ValidateEventFields, JsonValueAsArray(val));
|
|
||||||
VALIDATE("event_format", JSON_STRING, ValidateEventFormat, JsonValueAsString(val));
|
|
||||||
VALIDATE("presence", JSON_OBJECT, ValidateEventFilter, JsonValueAsObject(val));
|
|
||||||
VALIDATE("room", JSON_OBJECT, ValidateRoomFilter, JsonValueAsObject(val));
|
|
||||||
|
|
||||||
#undef VALIDATE
|
|
||||||
|
|
||||||
finish:
|
|
||||||
return response;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,10 +30,10 @@
|
||||||
#include <Str.h>
|
#include <Str.h>
|
||||||
|
|
||||||
#include <User.h>
|
#include <User.h>
|
||||||
#include <Filter.h>
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <Schema/Filter.h>
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
GetServerName(Db * db)
|
GetServerName(Db * db)
|
||||||
{
|
{
|
||||||
|
@ -139,6 +139,10 @@ ROUTE_IMPL(RouteFilter, path, argp)
|
||||||
DbRef *ref;
|
DbRef *ref;
|
||||||
char *filterId;
|
char *filterId;
|
||||||
|
|
||||||
|
Filter filter = { 0 };
|
||||||
|
char *parseErr;
|
||||||
|
HashMap *filterJson;
|
||||||
|
|
||||||
request = JsonDecode(HttpServerStream(args->context));
|
request = JsonDecode(HttpServerStream(args->context));
|
||||||
if (!request)
|
if (!request)
|
||||||
{
|
{
|
||||||
|
@ -147,12 +151,14 @@ ROUTE_IMPL(RouteFilter, path, argp)
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
response = FilterValidate(request);
|
if (!FilterFromJson(request, &filter, &parseErr))
|
||||||
if (response)
|
|
||||||
{
|
{
|
||||||
|
/* TODO: send parseErr to client */
|
||||||
|
response = MatrixErrorCreate(M_BAD_JSON);
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
filterId = StrRandom(12);
|
filterId = StrRandom(12);
|
||||||
if (!filterId)
|
if (!filterId)
|
||||||
{
|
{
|
||||||
|
@ -170,12 +176,17 @@ ROUTE_IMPL(RouteFilter, path, argp)
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
DbJsonSet(ref, request);
|
filterJson = FilterToJson(&filter);
|
||||||
|
DbJsonSet(ref, filterJson);
|
||||||
DbUnlock(db, ref);
|
DbUnlock(db, ref);
|
||||||
|
|
||||||
|
Free(filterJson);
|
||||||
|
|
||||||
response = HashMapCreate();
|
response = HashMapCreate();
|
||||||
HashMapSet(response, "filter_id", JsonValueString(filterId));
|
HashMapSet(response, "filter_id", JsonValueString(filterId));
|
||||||
Free(filterId);
|
Free(filterId);
|
||||||
|
|
||||||
|
FilterFree(&filter);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
#ifndef TELODENDRIA_FILTER_H
|
#ifndef TELODENDRIA_FILTER_H
|
||||||
#define TELODENDRIA_FILTER_H
|
#define TELODENDRIA_FILTER_H
|
||||||
|
|
||||||
|
#include <Schema/Filter.h>
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* @Nm Filter
|
* @Nm Filter
|
||||||
* @Nd Validate JSON filters and apply them to events.
|
* @Nd Validate JSON filters and apply them to events.
|
||||||
|
@ -35,22 +37,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate a JSON filter as provided by a client. This function
|
* Apply the given filter to the given event, returning a
|
||||||
* takes in a filter and returns a JSON response if a validation
|
|
||||||
* error occurs. If an error occurs, the response should be returned
|
|
||||||
* to the client. If no error occurs, then NULL will be returned and
|
|
||||||
* the caller may proceed with the assumption that the filter is
|
|
||||||
* valid.
|
|
||||||
*/
|
|
||||||
extern HashMap *
|
|
||||||
FilterValidate(HashMap *);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply the given JSON filter to the given event, returning a
|
|
||||||
* new event JSON with the filter applied, or NULL if the event
|
* new event JSON with the filter applied, or NULL if the event
|
||||||
* is excluded totally by the rules of the filter.
|
* is excluded totally by the rules of the filter.
|
||||||
*/
|
*/
|
||||||
extern HashMap *
|
extern HashMap *
|
||||||
FilterEvent(HashMap *, HashMap *);
|
FilterApply(Filter *, HashMap *);
|
||||||
|
|
||||||
#endif /* TELODENDRIA_FILTER_H */
|
#endif /* TELODENDRIA_FILTER_H */
|
||||||
|
|
22
tools/bin/td
22
tools/bin/td
|
@ -105,7 +105,7 @@ setsubst() {
|
||||||
recipe_docs() {
|
recipe_docs() {
|
||||||
mkdir -p build/man/man3
|
mkdir -p build/man/man3
|
||||||
|
|
||||||
for header in $(find src -name '*.h'); do
|
for header in $(find src -name '*.h' -not -path '*Schema*'); do
|
||||||
basename=$(basename "$header")
|
basename=$(basename "$header")
|
||||||
man=$(echo "build/man/man3/$basename" | sed -e 's/\.h$/\.3/')
|
man=$(echo "build/man/man3/$basename" | sed -e 's/\.h$/\.3/')
|
||||||
|
|
||||||
|
@ -134,10 +134,28 @@ recipe_cytoplasm() {
|
||||||
cd - > /dev/null
|
cd - > /dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
recipe_schema() {
|
||||||
|
recipe_cytoplasm
|
||||||
|
|
||||||
|
mkdir -p "src/Schema" "src/include/Schema"
|
||||||
|
|
||||||
|
find Schema -name '*.json' | while IFS= read -r schema; do
|
||||||
|
header="src/include/Schema/$(basename $schema .json).h"
|
||||||
|
impl="src/Schema/$(basename $schema .json).c"
|
||||||
|
|
||||||
|
mod=$(mod_time $schema)
|
||||||
|
|
||||||
|
if [ $mod -gt $(mod_time $header) ] || [ $mod -gt $(mod_time $impl) ]; then
|
||||||
|
echo "J2S $(basename $schema .json)"
|
||||||
|
j2s -s "$schema" -h "$header" -c "$impl"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
# Build the source code, and generate the 'build/telodendria'
|
# Build the source code, and generate the 'build/telodendria'
|
||||||
# binary.
|
# binary.
|
||||||
recipe_build() {
|
recipe_build() {
|
||||||
recipe_cytoplasm
|
recipe_schema
|
||||||
|
|
||||||
cd src
|
cd src
|
||||||
mkdir -p ../build
|
mkdir -p ../build
|
||||||
|
|
Loading…
Reference in a new issue