Add comments
This commit is contained in:
		@@ -7,57 +7,96 @@ import Leaf
 | 
				
			|||||||
func routes(_ app: Application) throws {
 | 
					func routes(_ app: Application) throws {
 | 
				
			||||||
    // Render home page when root domain is loaded
 | 
					    // Render home page when root domain is loaded
 | 
				
			||||||
    app.get { req  -> EventLoopFuture<View> in
 | 
					    app.get { req  -> EventLoopFuture<View> in
 | 
				
			||||||
 | 
					        // Get data from config file at /Resources/config.json
 | 
				
			||||||
        let fileData = try String(contentsOfFile: "\(app.directory.resourcesDirectory)/config.json").data(using: .utf8)
 | 
					        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!)
 | 
					        let config: Config = try! JSONDecoder().decode(Config.self, from: fileData!)
 | 
				
			||||||
 | 
					        // Check if user is logged in
 | 
				
			||||||
        let loginStatus = req.session.data["loggedIn"] ?? "false"
 | 
					        let loginStatus = req.session.data["loggedIn"] ?? "false"
 | 
				
			||||||
 | 
					        // Change loginStatus to a boolean
 | 
				
			||||||
        let loginBool = loginStatus == "true" ? true : false
 | 
					        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 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
 | 
					    app.get("status", ":url") { req -> [String: String] in
 | 
				
			||||||
 | 
					        // Get URL from request parameters
 | 
				
			||||||
        let url = URL(string: "http://\(req.parameters.get("url")!)")
 | 
					        let url = URL(string: "http://\(req.parameters.get("url")!)")
 | 
				
			||||||
 | 
					        // Configure URLSession
 | 
				
			||||||
        let config = URLSessionConfiguration.default
 | 
					        let config = URLSessionConfiguration.default
 | 
				
			||||||
 | 
					        // Set request timeouts to 5s, then assume offline
 | 
				
			||||||
        config.timeoutIntervalForRequest = 5
 | 
					        config.timeoutIntervalForRequest = 5
 | 
				
			||||||
        config.timeoutIntervalForResource = 5
 | 
					        config.timeoutIntervalForResource = 5
 | 
				
			||||||
 | 
					        // Declare statusDict for storing website status
 | 
				
			||||||
        var statusDict: [String:String] = [:]
 | 
					        var statusDict: [String:String] = [:]
 | 
				
			||||||
 | 
					        // Declare URLSession request using URL from request parameters
 | 
				
			||||||
        var headReq = URLRequest(url: url!)
 | 
					        var headReq = URLRequest(url: url!)
 | 
				
			||||||
 | 
					        // Set HEAD request
 | 
				
			||||||
        headReq.httpMethod = "HEAD"
 | 
					        headReq.httpMethod = "HEAD"
 | 
				
			||||||
 | 
					        // Set request timeout to 5s, then assume offline
 | 
				
			||||||
        headReq.timeoutInterval = 5
 | 
					        headReq.timeoutInterval = 5
 | 
				
			||||||
 | 
					        // Create DispatchSemaphore to block thread until request is resolved and status stored
 | 
				
			||||||
        let semaphore = DispatchSemaphore(value: 0)
 | 
					        let semaphore = DispatchSemaphore(value: 0)
 | 
				
			||||||
 | 
					        // Run Async URLSession dataTask
 | 
				
			||||||
        URLSession.shared.dataTask(with: headReq, completionHandler:  { (_, response, error) in
 | 
					        URLSession.shared.dataTask(with: headReq, completionHandler:  { (_, response, error) in
 | 
				
			||||||
 | 
					            // If the response is valid
 | 
				
			||||||
            if let httpURLResponse = response as? HTTPURLResponse {
 | 
					            if let httpURLResponse = response as? HTTPURLResponse {
 | 
				
			||||||
 | 
					                // Store status code in statusDict
 | 
				
			||||||
                statusDict["code"] = String(httpURLResponse.statusCode)
 | 
					                statusDict["code"] = String(httpURLResponse.statusCode)
 | 
				
			||||||
 | 
					                // Store website status in statusDict
 | 
				
			||||||
                statusDict["down"] = "false"
 | 
					                statusDict["down"] = "false"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            // Signal DispatchSemaphore to stop blocking
 | 
				
			||||||
            semaphore.signal()
 | 
					            semaphore.signal()
 | 
				
			||||||
        }).resume()
 | 
					        }).resume()
 | 
				
			||||||
 | 
					        // Wait for semaphore signal
 | 
				
			||||||
        semaphore.wait()
 | 
					        semaphore.wait()
 | 
				
			||||||
 | 
					        // If statusDict is empty, return code 0, down true. Otherwise, return statusdict
 | 
				
			||||||
        return statusDict.count > 0 ? statusDict : ["code": "0", "down": "true"]
 | 
					        return statusDict.count > 0 ? statusDict : ["code": "0", "down": "true"]
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Render login page on GET request to /login
 | 
				
			||||||
    app.get("login") { req -> EventLoopFuture<View> in
 | 
					    app.get("login") { req -> EventLoopFuture<View> in
 | 
				
			||||||
 | 
					        // Get data from config file at /Resources/config.json
 | 
				
			||||||
        let fileData = try String(contentsOfFile: "\(app.directory.resourcesDirectory)/config.json").data(using: .utf8)
 | 
					        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!)
 | 
					        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))
 | 
					        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
 | 
					    app.post("login") { req -> Response in
 | 
				
			||||||
 | 
					        // Decode POST request data into Login struct
 | 
				
			||||||
        let data = try req.content.decode(Login.self)
 | 
					        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)
 | 
					        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!)
 | 
					        let config: Config = try! JSONDecoder().decode(Config.self, from: fileData!)
 | 
				
			||||||
 | 
					        // Get password from POST request data
 | 
				
			||||||
        let loginPassData = data.password?.data(using: .utf8)
 | 
					        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)!)
 | 
					        let loginPassHash = SHA256.hash(data: loginPassData ?? "".data(using: .utf8)!)
 | 
				
			||||||
 | 
					        // Convert hash to string
 | 
				
			||||||
        let stringHash = loginPassHash.map { String(format: "%02hhx", $0) }.joined()
 | 
					        let stringHash = loginPassHash.map { String(format: "%02hhx", $0) }.joined()
 | 
				
			||||||
 | 
					        // If hash in config matches provided hash
 | 
				
			||||||
        if stringHash == config.passwordHash {
 | 
					        if stringHash == config.passwordHash {
 | 
				
			||||||
 | 
					            // Set logged in to true in session
 | 
				
			||||||
            req.session.data["loggedIn"] = "true"
 | 
					            req.session.data["loggedIn"] = "true"
 | 
				
			||||||
 | 
					            // Redirect back to /
 | 
				
			||||||
            return try req.redirect(to: "/")
 | 
					            return try req.redirect(to: "/")
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
 | 
					            // If hashes do not match, return unauthorized error
 | 
				
			||||||
            throw Abort(.unauthorized)
 | 
					            throw Abort(.unauthorized)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Destroy session on GET request to logout
 | 
				
			||||||
    app.get("logout") { req -> Response in
 | 
					    app.get("logout") { req -> Response in
 | 
				
			||||||
 | 
					        // Destroy session
 | 
				
			||||||
        req.session.destroy()
 | 
					        req.session.destroy()
 | 
				
			||||||
 | 
					        // Redirect back to /
 | 
				
			||||||
        return try req.redirect(to: "/")
 | 
					        return try req.redirect(to: "/")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user