From 43bdf9a74681628c34ea01501e0f5a7edbb04ee7 Mon Sep 17 00:00:00 2001 From: Arsen Musayelyan Date: Thu, 12 Nov 2020 13:23:25 -0800 Subject: [PATCH] Add login functionality --- .gitignore | 1 + Package.resolved | 4 +-- Package.swift | 4 ++- Resources/Views/base.leaf | 14 ++++++----- Resources/Views/card.leaf | 43 ++++++++++++++++++++++++++++++++ Resources/Views/home.leaf | 48 +++++------------------------------- Resources/Views/login.leaf | 30 ++++++++++++++++++++++ Sources/App/JSONDecode.swift | 2 +- Sources/App/configure.swift | 3 +++ Sources/App/context.swift | 7 ++++++ Sources/App/login.swift | 6 +++++ Sources/App/routes.swift | 35 +++++++++++++++++++++++++- 12 files changed, 144 insertions(+), 53 deletions(-) create mode 100644 Resources/Views/card.leaf create mode 100644 Resources/Views/login.leaf create mode 100644 Sources/App/context.swift create mode 100644 Sources/App/login.swift diff --git a/.gitignore b/.gitignore index 842f0f8..5d72a4a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ xcuserdata DerivedData/ .DS_Store file:* +Resources/config.json \ No newline at end of file diff --git a/Package.resolved b/Package.resolved index 50f34b3..27f968a 100644 --- a/Package.resolved +++ b/Package.resolved @@ -78,8 +78,8 @@ "repositoryURL": "https://github.com/apple/swift-crypto.git", "state": { "branch": null, - "revision": "9b9d1868601a199334da5d14f4ab2d37d4f8d0c5", - "version": "1.0.2" + "revision": "9680b7251cd2be22caaed8f1468bd9e8915a62fb", + "version": "1.1.2" } }, { diff --git a/Package.swift b/Package.swift index d071add..38be553 100644 --- a/Package.swift +++ b/Package.swift @@ -13,7 +13,8 @@ let package = Package( .package(url: "https://github.com/vapor/leaf", .exact("4.0.0-tau.1")), .package(url: "https://github.com/vapor/leaf-kit", .exact("1.0.0-tau.1.1")), // Leaf Error Middleware for custom error pages - .package(name: "LeafErrorMiddleware", url: "https://github.com/brokenhandsio/leaf-error-middleware.git", from: "2.0.0-beta") + .package(name: "LeafErrorMiddleware", url: "https://github.com/brokenhandsio/leaf-error-middleware.git", from: "2.0.0-beta"), + .package(url: "https://github.com/apple/swift-crypto.git", from: "1.1.2") ], targets: [ .target( @@ -21,6 +22,7 @@ let package = Package( dependencies: [ .product(name: "Vapor", package: "vapor"), .product(name: "Leaf", package: "leaf"), + .product(name: "Crypto", package: "swift-crypto"), "LeafErrorMiddleware" ], swiftSettings: [ diff --git a/Resources/Views/base.leaf b/Resources/Views/base.leaf index 0ff12a8..0f9fcdc 100644 --- a/Resources/Views/base.leaf +++ b/Resources/Views/base.leaf @@ -14,13 +14,15 @@
#(config.title) - #if(config.showSourceBtn): -
- +
+ - #endif +
diff --git a/Resources/Views/card.leaf b/Resources/Views/card.leaf new file mode 100644 index 0000000..0713837 --- /dev/null +++ b/Resources/Views/card.leaf @@ -0,0 +1,43 @@ +
+
+
+

#(service["name"])

+
+ + Status + Unavailable + +
+
+
+ #(service["description"]) +
+ #if(service["url"]): + + #endif +
+ #if(service["url"]): + + #endif +
\ No newline at end of file diff --git a/Resources/Views/home.leaf b/Resources/Views/home.leaf index a31734c..6ff3a70 100644 --- a/Resources/Views/home.leaf +++ b/Resources/Views/home.leaf @@ -7,49 +7,13 @@
#(node)
#for(service in services): -
-
-
-

#(service["name"])

-
- - Status - Unavailable - -
-
-
- #(service["description"]) -
- #if(service["url"]): - - #endif -
- #if(service["url"]): - + #if(!service["private"] == "true"): + #inline("card") + #else: + #if(loggedIn): + #inline("card") #endif -
+ #endif #endfor
#endfor diff --git a/Resources/Views/login.leaf b/Resources/Views/login.leaf new file mode 100644 index 0000000..1898102 --- /dev/null +++ b/Resources/Views/login.leaf @@ -0,0 +1,30 @@ +#define(body): +
+
+
+
+ +
+
+
+
+#enddefine +#inline("base") diff --git a/Sources/App/JSONDecode.swift b/Sources/App/JSONDecode.swift index 4206bd0..a987135 100644 --- a/Sources/App/JSONDecode.swift +++ b/Sources/App/JSONDecode.swift @@ -3,6 +3,6 @@ import Vapor struct Config: Codable { let title: String - let showSourceBtn: Bool + let passwordHash: String let services: [String:[[String:String]]] } \ No newline at end of file diff --git a/Sources/App/configure.swift b/Sources/App/configure.swift index def716c..769617b 100644 --- a/Sources/App/configure.swift +++ b/Sources/App/configure.swift @@ -8,6 +8,9 @@ public func configure(_ app: Application) throws { // Serve files from /Public app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory)) + app.middleware.use(app.sessions.middleware) + app.sessions.configuration.cookieName = "statusboard_session" + // Configure Leaf LeafOption.caching = app.environment.isRelease ? .default : .bypass LeafRenderer.Option.timeout = 200.0 diff --git a/Sources/App/context.swift b/Sources/App/context.swift new file mode 100644 index 0000000..924e447 --- /dev/null +++ b/Sources/App/context.swift @@ -0,0 +1,7 @@ +import Foundation +import Vapor + +struct LContext: Codable { + let config: Config + let loggedIn: Bool +} \ No newline at end of file diff --git a/Sources/App/login.swift b/Sources/App/login.swift new file mode 100644 index 0000000..8c9a823 --- /dev/null +++ b/Sources/App/login.swift @@ -0,0 +1,6 @@ +import Foundation +import Vapor + +struct Login: Codable { + let password: String? +} \ No newline at end of file diff --git a/Sources/App/routes.swift b/Sources/App/routes.swift index 493420b..7d1f06f 100644 --- a/Sources/App/routes.swift +++ b/Sources/App/routes.swift @@ -1,5 +1,6 @@ import Vapor import Foundation +import Crypto import Leaf func routes(_ app: Application) throws { @@ -7,7 +8,9 @@ func routes(_ app: Application) throws { app.get { req -> EventLoopFuture in let fileData = try String(contentsOfFile: "\(app.directory.resourcesDirectory)/config.json").data(using: .utf8) let config: Config = try! JSONDecoder().decode(Config.self, from: fileData!) - return req.view.render("home", ["config": config]) + let loginStatus = req.session.data["loggedIn"] ?? "false" + let loginBool = loginStatus == "true" ? true : false + return req.view.render("home", LContext(config: config, loggedIn: loginBool)) } app.get("status", ":url") { req -> EventLoopFuture<[String: String]> in @@ -18,4 +21,34 @@ func routes(_ app: Application) throws { ["down": String(json.isitdown), "code": String(json.response_code)] } } + + app.get("login") { req -> EventLoopFuture in + let fileData = try String(contentsOfFile: "\(app.directory.resourcesDirectory)/config.json").data(using: .utf8) + let config: Config = try! JSONDecoder().decode(Config.self, from: fileData!) + return req.view.render("login", LContext(config: config, loggedIn: false)) + } + + app.post("login") { req -> Response in + let data = try req.content.decode(Login.self) + let fileData = try String(contentsOfFile: "\(app.directory.resourcesDirectory)/config.json").data(using: .utf8) + let config: Config = try! JSONDecoder().decode(Config.self, from: fileData!) + let loginPassData = data.password?.data(using: .utf8) + let loginPassHash = SHA256.hash(data: loginPassData ?? "".data(using: .utf8)!) + let stringHash = loginPassHash.map { String(format: "%02hhx", $0) }.joined() + print("Recv: \(stringHash)") + print("Conf: \(config.passwordHash)") + if stringHash == config.passwordHash { + req.session.data["loggedIn"] = "true" + return try req.redirect(to: "/") + } else { + throw Abort(.unauthorized) + } + } + + app.get("logout") { req -> Response in + req.session.destroy() + return try req.redirect(to: "/") + } + + }