diff options
Diffstat (limited to 'backend/api/src/net-util.zig')
| -rw-r--r-- | backend/api/src/net-util.zig | 140 |
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; +} |
