summaryrefslogtreecommitdiff
path: root/backend/api/src/net-util.zig
diff options
context:
space:
mode:
Diffstat (limited to 'backend/api/src/net-util.zig')
-rw-r--r--backend/api/src/net-util.zig140
1 files changed, 140 insertions, 0 deletions
diff --git a/backend/api/src/net-util.zig b/backend/api/src/net-util.zig
new file mode 100644
index 0000000..1cc8fb1
--- /dev/null
+++ b/backend/api/src/net-util.zig
@@ -0,0 +1,140 @@
+const z = @import( "std" );
+const u = @import( "util.zig" );
+const zap = @import( "zap" );
+const jwt = @import( "jwt" );
+const uuid = @import( "uuid" );
+
+const alloc = u.alloc;
+
+const JWT = jwt.JWT;
+const memcmp = z.mem.eql;
+const Status = zap.StatusCode;
+const Request = zap.Request;
+
+pub const ErrorResponse = struct {
+ status: []const u8 = "error",
+ msg: []const u8
+};
+
+const OkResponseTemplate = struct {
+ status: []const u8 = "ok"
+};
+
+fn MergeOk( comptime t: type ) type {
+ const ti = @typeInfo( t );
+ comptime if( ti.Struct.is_tuple )
+ return OkResponseTemplate;
+
+ return u.MergeTypes( OkResponseTemplate, t );
+}
+
+pub fn OkResponse( t: anytype ) MergeOk(@TypeOf(t)) {
+ const ret: MergeOk(@TypeOf(t)) = t;
+ return ret;
+}
+
+pub fn sendJson( r: Request, status: Status, t: anytype ) void {
+ r.setStatus( status );
+
+ const encoded = u.jsonStringify( t ) catch |e| {
+ z.debug.print( "Failed to encode JSON: {any} {any} {any}\n", .{t, e, @errorReturnTrace()} );
+ return;
+ };
+ defer alloc.free( encoded );
+
+ r.sendJson( encoded ) catch |e| {
+ z.debug.print( "Failed to send body: {s} {any} {any}\n", .{encoded, e, @errorReturnTrace()} );
+ };
+}
+
+pub fn sendJsonChunk( r: Request, status: Status, t: anytype ) void {
+ r.setStatus( status );
+ const encoded = u.jsonStringify( t ) catch |e| {
+ z.debug.print( "Failed to encode JSON: {any} {any} {any}\n", .{t, e, @errorReturnTrace()} );
+ return;
+ };
+ defer alloc.free( encoded );
+
+ z.debug.print( "sending {s}\n", .{ encoded } );
+ r.sendChunk( encoded ) catch |e| {
+ z.debug.print( "Failed to send body: {s} {any} {any}\n", .{encoded, e, @errorReturnTrace()} );
+ };
+}
+
+pub fn handleInvalidPostReq( r: Request ) bool {
+ if( r.method == null ) {
+ sendJson( r, .method_not_allowed, .{
+ .status = "error", .msg = "method is null"
+ } );
+ return true;
+ }
+
+ if( r.methodAsEnum() != .POST ) {
+ if( r.methodAsEnum() == .OPTIONS ) {
+ r.sendBody( "" ) catch {};
+ return true;
+ }
+
+ sendJson( r, .method_not_allowed, .{
+ .status = "error", .msg = "method not allowed"
+ } );
+ return true;
+ }
+
+ if( r.body == null ) {
+ sendJson( r, .bad_request, .{
+ .status = "error", .msg = "body is null"
+ } );
+ return true;
+ }
+ r.parseBody() catch {
+ sendJson( r, .bad_request, .{
+ .status = "error", .msg = "body is not valid json"
+ } );
+
+ return true;
+ };
+
+ return false;
+}
+
+///caller has to free
+pub fn getJwtSecret() ![]const u8 {
+ return u.readFile( "../data/jwt_secret.txt" );
+}
+
+///caller has to free
+pub fn parseJWT( t: type, str: []const u8 ) !JWT(t) {
+ const key = try getJwtSecret();
+ defer alloc.free( key );
+ const token = try jwt.decode(
+ alloc,
+ t,
+ str,
+ .{ .secret = key },
+ .{},
+ );
+
+ return token;
+}
+
+///caller has to free
+pub fn encodeJWT( data: anytype ) ![]const u8 {
+ const secret = try getJwtSecret();
+ defer alloc.free( secret );
+ const token = try jwt.encode(
+ alloc,
+ .{ .alg = .HS256 },
+ data,
+ .{ .secret = secret }
+ );
+
+ return token;
+}
+
+pub fn uuidv4() uuid.urn.Urn {
+ const id = uuid.v4.new();
+ const urn = uuid.urn.serialize(id);
+
+ return urn;
+}