From 5d8cf17e22beb8b220e950ae93ab641644112266 Mon Sep 17 00:00:00 2001 From: Arsen Musayelyan Date: Sun, 15 Nov 2020 11:51:49 -0800 Subject: [PATCH] Add comments --- Sources/App/routes.swift | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/Sources/App/routes.swift b/Sources/App/routes.swift index 480cccb..e8aa3f7 100644 --- a/Sources/App/routes.swift +++ b/Sources/App/routes.swift @@ -7,57 +7,96 @@ import Leaf func routes(_ app: Application) throws { // Render home page when root domain is loaded app.get { req -> EventLoopFuture in + // Get data from config file at /Resources/config.json let fileData = try String(contentsOfFile: "\(app.directory.resourcesDirectory)/config.json").data(using: .utf8) + // Decode JSON file to Config struct let config: Config = try! JSONDecoder().decode(Config.self, from: fileData!) + // Check if user is logged in let loginStatus = req.session.data["loggedIn"] ?? "false" + // Change loginStatus to a boolean let loginBool = loginStatus == "true" ? true : false + // Render home.leaf with config and login status as context return req.view.render("home", LContext(config: config, loggedIn: loginBool)) } + // Return website status when /status/:url is loaded app.get("status", ":url") { req -> [String: String] in + // Get URL from request parameters let url = URL(string: "http://\(req.parameters.get("url")!)") + // Configure URLSession let config = URLSessionConfiguration.default + // Set request timeouts to 5s, then assume offline config.timeoutIntervalForRequest = 5 config.timeoutIntervalForResource = 5 + // Declare statusDict for storing website status var statusDict: [String:String] = [:] + // Declare URLSession request using URL from request parameters var headReq = URLRequest(url: url!) + // Set HEAD request headReq.httpMethod = "HEAD" + // Set request timeout to 5s, then assume offline headReq.timeoutInterval = 5 + // Create DispatchSemaphore to block thread until request is resolved and status stored let semaphore = DispatchSemaphore(value: 0) + // Run Async URLSession dataTask URLSession.shared.dataTask(with: headReq, completionHandler: { (_, response, error) in + // If the response is valid if let httpURLResponse = response as? HTTPURLResponse { + // Store status code in statusDict statusDict["code"] = String(httpURLResponse.statusCode) + // Store website status in statusDict statusDict["down"] = "false" } + // Signal DispatchSemaphore to stop blocking semaphore.signal() }).resume() + // Wait for semaphore signal semaphore.wait() + // If statusDict is empty, return code 0, down true. Otherwise, return statusdict return statusDict.count > 0 ? statusDict : ["code": "0", "down": "true"] } + // Render login page on GET request to /login app.get("login") { req -> EventLoopFuture in + // Get data from config file at /Resources/config.json let fileData = try String(contentsOfFile: "\(app.directory.resourcesDirectory)/config.json").data(using: .utf8) + // Decode JSON file to Config struct let config: Config = try! JSONDecoder().decode(Config.self, from: fileData!) + // Render home.leaf with config as context return req.view.render("login", LContext(config: config, loggedIn: false)) } + // Verify credentials and log in on POST request to /login app.post("login") { req -> Response in + // Decode POST request data into Login struct let data = try req.content.decode(Login.self) + // Get data from config file at /Resources/config.json let fileData = try String(contentsOfFile: "\(app.directory.resourcesDirectory)/config.json").data(using: .utf8) + // Decode JSON file to Config struct let config: Config = try! JSONDecoder().decode(Config.self, from: fileData!) + // Get password from POST request data let loginPassData = data.password?.data(using: .utf8) + // Hash password in POST data using SHA256.hash() from SwiftCrypto let loginPassHash = SHA256.hash(data: loginPassData ?? "".data(using: .utf8)!) + // Convert hash to string let stringHash = loginPassHash.map { String(format: "%02hhx", $0) }.joined() + // If hash in config matches provided hash if stringHash == config.passwordHash { + // Set logged in to true in session req.session.data["loggedIn"] = "true" + // Redirect back to / return try req.redirect(to: "/") } else { + // If hashes do not match, return unauthorized error throw Abort(.unauthorized) } } + // Destroy session on GET request to logout app.get("logout") { req -> Response in + // Destroy session req.session.destroy() + // Redirect back to / return try req.redirect(to: "/") }