forked from Telodendria/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
|
||||
*.log
|
||||
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
|
||||
|
||||
[~] 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
|
||||
[x] Database corruption
|
||||
[ ] File descriptor exhaustion
|
||||
[ ] Random memory corruption after many requests.
|
||||
[ ] j2s
|
||||
[~] j2s
|
||||
[x] Properly support arrays of primitives.
|
||||
[ ] How to set default value of true on boolean?
|
||||
- defaults probably need to be set at parser level, not
|
||||
enough to set it after.
|
||||
|
@ -49,8 +45,6 @@ Milestone: v0.4.0
|
|||
use the default. This will make debugging a lot easier.
|
||||
[ ] Make sure admin registration token is printed to log, not stdout.
|
||||
Unless they are the same, of course.
|
||||
[x] Fix Json UTF-8 handling.
|
||||
[ ] Update Makefile
|
||||
|
||||
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
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#include <Routes.h>
|
||||
#include <Filter.h>
|
||||
|
||||
#include <string.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;
|
||||
}
|
||||
#include <Schema/Filter.h>
|
||||
|
||||
HashMap *
|
||||
FilterValidate(HashMap * json)
|
||||
FilterApply(Filter *filter, HashMap *event)
|
||||
{
|
||||
JsonValue *val;
|
||||
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;
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -30,10 +30,10 @@
|
|||
#include <Str.h>
|
||||
|
||||
#include <User.h>
|
||||
#include <Filter.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <Schema/Filter.h>
|
||||
|
||||
static char *
|
||||
GetServerName(Db * db)
|
||||
{
|
||||
|
@ -139,6 +139,10 @@ ROUTE_IMPL(RouteFilter, path, argp)
|
|||
DbRef *ref;
|
||||
char *filterId;
|
||||
|
||||
Filter filter = { 0 };
|
||||
char *parseErr;
|
||||
HashMap *filterJson;
|
||||
|
||||
request = JsonDecode(HttpServerStream(args->context));
|
||||
if (!request)
|
||||
{
|
||||
|
@ -147,12 +151,14 @@ ROUTE_IMPL(RouteFilter, path, argp)
|
|||
goto finish;
|
||||
}
|
||||
|
||||
response = FilterValidate(request);
|
||||
if (response)
|
||||
if (!FilterFromJson(request, &filter, &parseErr))
|
||||
{
|
||||
/* TODO: send parseErr to client */
|
||||
response = MatrixErrorCreate(M_BAD_JSON);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
|
||||
filterId = StrRandom(12);
|
||||
if (!filterId)
|
||||
{
|
||||
|
@ -170,12 +176,17 @@ ROUTE_IMPL(RouteFilter, path, argp)
|
|||
goto finish;
|
||||
}
|
||||
|
||||
DbJsonSet(ref, request);
|
||||
filterJson = FilterToJson(&filter);
|
||||
DbJsonSet(ref, filterJson);
|
||||
DbUnlock(db, ref);
|
||||
|
||||
Free(filterJson);
|
||||
|
||||
response = HashMapCreate();
|
||||
HashMapSet(response, "filter_id", JsonValueString(filterId));
|
||||
Free(filterId);
|
||||
|
||||
FilterFree(&filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#ifndef TELODENDRIA_FILTER_H
|
||||
#define TELODENDRIA_FILTER_H
|
||||
|
||||
#include <Schema/Filter.h>
|
||||
|
||||
/***
|
||||
* @Nm Filter
|
||||
* @Nd Validate JSON filters and apply them to events.
|
||||
|
@ -35,22 +37,11 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* Validate a JSON filter as provided by a client. This function
|
||||
* 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
|
||||
* Apply the given filter to the given event, returning a
|
||||
* new event JSON with the filter applied, or NULL if the event
|
||||
* is excluded totally by the rules of the filter.
|
||||
*/
|
||||
extern HashMap *
|
||||
FilterEvent(HashMap *, HashMap *);
|
||||
FilterApply(Filter *, HashMap *);
|
||||
|
||||
#endif /* TELODENDRIA_FILTER_H */
|
||||
|
|
22
tools/bin/td
22
tools/bin/td
|
@ -105,7 +105,7 @@ setsubst() {
|
|||
recipe_docs() {
|
||||
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")
|
||||
man=$(echo "build/man/man3/$basename" | sed -e 's/\.h$/\.3/')
|
||||
|
||||
|
@ -134,10 +134,28 @@ recipe_cytoplasm() {
|
|||
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'
|
||||
# binary.
|
||||
recipe_build() {
|
||||
recipe_cytoplasm
|
||||
recipe_schema
|
||||
|
||||
cd src
|
||||
mkdir -p ../build
|
||||
|
|
Loading…
Reference in a new issue