| ... | @@ -254,16 +254,16 @@ pub fn Handlers(comptime T: type) type { | ... | @@ -254,16 +254,16 @@ pub fn Handlers(comptime T: type) type { |
| 254 | const Self = @This(); | 254 | const Self = @This(); |
| 255 | pub var clients: []Client = &.{}; | 255 | pub var clients: []Client = &.{}; |
| 256 | | 256 | |
| 257 | pub fn login(response: *std.http.Server.Response, body_writer: anytype, alloc: std.mem.Allocator, query: UrlValues) !void { | 257 | pub fn login(request: *std.http.Server.Request, body_writer: anytype, alloc: std.mem.Allocator, query: UrlValues, request_headers: *const std.StringHashMapUnmanaged(string), response_status: *std.http.Status, response_headers: *std.ArrayListUnmanaged(std.http.Header)) !void { |
| 258 | if (query.get("with")) |with| { | 258 | if (query.get("with")) |with| { |
| 259 | const client = clientByProviderId(Self.clients, with) orelse return try fail(response, body_writer, "Client with that ID not found!\n", .{}); | 259 | const client = clientByProviderId(Self.clients, with) orelse return try fail(response_status, body_writer, "Client with that ID not found!\n", .{}); |
| 260 | return try loginOne(response, alloc, T, client, T.callbackPath); | 260 | return try loginOne(request, alloc, T, client, T.callbackPath, request_headers, response_status, response_headers); |
| 261 | } | 261 | } |
| 262 | if (Self.clients.len == 1) { | 262 | if (Self.clients.len == 1) { |
| 263 | return try loginOne(response, alloc, T, clients[0], T.callbackPath); | 263 | return try loginOne(request, alloc, T, clients[0], T.callbackPath, request_headers, response_status, response_headers); |
| 264 | } | 264 | } |
| 265 | | 265 | |
| 266 | try response.headers.append("Content-Type", "text/html"); | 266 | try response_headers.append(alloc, .{ .name = "Content-Type", .value = "text/html" }); |
| 267 | const page = files.@"/selector.pek"; | 267 | const page = files.@"/selector.pek"; |
| 268 | const tmpl = comptime pek.parse(page); | 268 | const tmpl = comptime pek.parse(page); |
| 269 | try pek.compile(Base, alloc, body_writer, tmpl, .{ | 269 | try pek.compile(Base, alloc, body_writer, tmpl, .{ |
| ... | @@ -271,18 +271,19 @@ pub fn Handlers(comptime T: type) type { | ... | @@ -271,18 +271,19 @@ pub fn Handlers(comptime T: type) type { |
| 271 | }); | 271 | }); |
| 272 | } | 272 | } |
| 273 | | 273 | |
| 274 | pub fn callback(response: *std.http.Server.Response, body_writer: anytype, alloc: std.mem.Allocator, query: UrlValues) !void { | 274 | pub fn callback(request: *std.http.Server.Request, body_writer: anytype, alloc: std.mem.Allocator, query: UrlValues, request_headers: *const std.StringHashMapUnmanaged(string), response_status: *std.http.Status, response_headers: *std.ArrayListUnmanaged(std.http.Header)) !void { |
| 275 | const state = query.get("state") orelse return try fail(response, body_writer, "", .{}); | 275 | _ = request; |
| 276 | const client = clientByProviderId(Self.clients, state) orelse return try fail(response, body_writer, "error: No handler found for provider: {s}\n", .{state}); | 276 | const state = query.get("state") orelse return try fail(response_status, body_writer, "", .{}); |
| 277 | const code = query.get("code") orelse return try fail(response, body_writer, "", .{}); | 277 | const client = clientByProviderId(Self.clients, state) orelse return try fail(response_status, body_writer, "error: No handler found for provider: {s}\n", .{state}); |
| | 278 | const code = query.get("code") orelse return try fail(response_status, body_writer, "", .{}); |
| 278 | | 279 | |
| 279 | var params = UrlValues.init(alloc); | 280 | var params = UrlValues.init(alloc); |
| 280 | try params.add("client_id", client.id); | 281 | try params.append("client_id", client.id); |
| 281 | try params.add("client_secret", client.secret); | 282 | try params.append("client_secret", client.secret); |
| 282 | try params.add("grant_type", "authorization_code"); | 283 | try params.append("grant_type", "authorization_code"); |
| 283 | try params.add("code", code); | 284 | try params.append("code", code); |
| 284 | try params.add("redirect_uri", try redirectUri(response, alloc, T.callbackPath)); | 285 | try params.append("redirect_uri", try redirectUri(request_headers, alloc, T.callbackPath)); |
| 285 | try params.add("state", "none"); | 286 | try params.append("state", "none"); |
| 286 | | 287 | |
| 287 | const req = try zfetch.Request.init(alloc, client.provider.token_url, null); | 288 | const req = try zfetch.Request.init(alloc, client.provider.token_url, null); |
| 288 | | 289 | |
| ... | @@ -299,9 +300,9 @@ pub fn Handlers(comptime T: type) type { | ... | @@ -299,9 +300,9 @@ pub fn Handlers(comptime T: type) type { |
| 299 | const val = try extras.parse_json(alloc, body_content); | 300 | const val = try extras.parse_json(alloc, body_content); |
| 300 | | 301 | |
| 301 | const tt = val.value.object.get("token_type").?.string; | 302 | const tt = val.value.object.get("token_type").?.string; |
| 302 | if (!std.mem.eql(u8, tt, "bearer")) return fail(response, body_writer, "oauth2: invalid token type: {s}", .{tt}); | 303 | if (!std.mem.eql(u8, tt, "bearer")) return fail(response_status, body_writer, "oauth2: invalid token type: {s}", .{tt}); |
| 303 | | 304 | |
| 304 | const at = val.value.object.get("access_token") orelse return try fail(response, body_writer, "Identity Provider Login Error!\n{s}", .{body_content}); | 305 | const at = val.value.object.get("access_token") orelse return try fail(response_status, body_writer, "Identity Provider Login Error!\n{s}", .{body_content}); |
| 305 | | 306 | |
| 306 | const req2 = try zfetch.Request.init(alloc, client.provider.me_url, null); | 307 | const req2 = try zfetch.Request.init(alloc, client.provider.me_url, null); |
| 307 | var headers2 = zfetch.Headers.init(alloc); | 308 | var headers2 = zfetch.Headers.init(alloc); |
| ... | @@ -317,43 +318,42 @@ pub fn Handlers(comptime T: type) type { | ... | @@ -317,43 +318,42 @@ pub fn Handlers(comptime T: type) type { |
| 317 | | 318 | |
| 318 | const id = try fixId(alloc, val2.value.object.get(client.provider.id_prop).?); | 319 | const id = try fixId(alloc, val2.value.object.get(client.provider.id_prop).?); |
| 319 | const name = val2.value.object.get(client.provider.name_prop).?.string; | 320 | const name = val2.value.object.get(client.provider.name_prop).?.string; |
| 320 | try T.saveInfo(response, alloc, client.provider, id, name, val.value, val2.value); | 321 | try T.saveInfo(response_headers, alloc, client.provider, id, name, val.value, val2.value); |
| 321 | | 322 | |
| 322 | try response.headers.append("Location", T.doneUrl); | 323 | try response_headers.append(alloc, .{ .name = "Location", .value = T.doneUrl }); |
| 323 | response.status = .found; | 324 | response_status.* = .found; |
| 324 | } | 325 | } |
| 325 | }; | 326 | }; |
| 326 | } | 327 | } |
| 327 | | 328 | |
| 328 | fn loginOne(response: *std.http.Server.Response, alloc: std.mem.Allocator, comptime T: type, client: Client, callbackPath: string) !void { | 329 | fn loginOne(request: *std.http.Server.Request, alloc: std.mem.Allocator, comptime T: type, client: Client, callbackPath: string, request_headers: *const std.StringHashMapUnmanaged(string), response_status: *std.http.Status, response_headers: *std.ArrayListUnmanaged(std.http.Header)) !void { |
| 329 | if (try T.isLoggedIn(response, alloc)) { | 330 | if (try T.isLoggedIn(request, alloc)) { |
| 330 | try response.headers.append("Location", T.doneUrl); | 331 | try response_headers.append(alloc, .{ .name = "Location", .value = T.doneUrl }); |
| 331 | } else { | 332 | } else { |
| 332 | const idp = client.provider; | 333 | const idp = client.provider; |
| 333 | var params = UrlValues.init(alloc); | 334 | var params = UrlValues.init(alloc); |
| 334 | try params.add("client_id", client.id); | 335 | try params.append("client_id", client.id); |
| 335 | try params.add("redirect_uri", try redirectUri(response, alloc, callbackPath)); | 336 | try params.append("redirect_uri", try redirectUri(request_headers, alloc, callbackPath)); |
| 336 | try params.add("response_type", "code"); | 337 | try params.append("response_type", "code"); |
| 337 | try params.add("scope", idp.scope); | 338 | try params.append("scope", idp.scope); |
| 338 | try params.add("duration", "temporary"); | 339 | try params.append("duration", "temporary"); |
| 339 | try params.add("state", idp.id); | 340 | try params.append("state", idp.id); |
| 340 | const authurl = try std.mem.join(alloc, "?", &.{ idp.authorize_url, try params.encode() }); | 341 | const authurl = try std.mem.join(alloc, "?", &.{ idp.authorize_url, try params.encode() }); |
| 341 | try response.headers.append("Location", authurl); | 342 | try response_headers.append(alloc, .{ .name = "Location", .value = authurl }); |
| 342 | } | 343 | } |
| 343 | response.status = .found; | 344 | response_status.* = .found; |
| 344 | } | 345 | } |
| 345 | | 346 | |
| 346 | fn fail(response: *std.http.Server.Response, body_writer: anytype, comptime err: string, args: anytype) !void { | 347 | fn fail(response_status: *std.http.Status, body_writer: anytype, comptime err: string, args: anytype) !void { |
| 347 | response.status = .bad_request; | 348 | response_status.* = .bad_request; |
| 348 | try body_writer.print(err, args); | 349 | try body_writer.print(err, args); |
| 349 | } | 350 | } |
| 350 | | 351 | |
| 351 | fn redirectUri(response: *std.http.Server.Response, alloc: std.mem.Allocator, callbackPath: string) !string { | 352 | fn redirectUri(request_headers: *const std.StringHashMapUnmanaged(string), alloc: std.mem.Allocator, callbackPath: string) !string { |
| 352 | const headers = response.request.headers; | 353 | const xproto = request_headers.get("X-Forwarded-Proto") orelse ""; |
| 353 | const xproto = headers.getFirstValue("X-Forwarded-Proto") orelse ""; | | |
| 354 | const maybe_tls = std.mem.eql(u8, xproto, "https"); | 354 | const maybe_tls = std.mem.eql(u8, xproto, "https"); |
| 355 | const proto: string = if (maybe_tls) "https" else "http"; | 355 | const proto: string = if (maybe_tls) "https" else "http"; |
| 356 | const host = response.request.headers.getFirstValue("host").?; | 356 | const host = request_headers.get("host").?; |
| 357 | return try std.fmt.allocPrint(alloc, "{s}://{s}{s}", .{ proto, host, callbackPath }); | 357 | return try std.fmt.allocPrint(alloc, "{s}://{s}{s}", .{ proto, host, callbackPath }); |
| 358 | } | 358 | } |
| 359 | | 359 | |