Created
April 6, 2019 09:27
-
-
Save Joannis/b6ebfb674b87c7ad0c3b815879518a6b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import MeowVapor | |
import JWT | |
final class CMSContext: Service { | |
struct Value { | |
public let meow: Meow.Context | |
public let token: AdministrativeUserToken? | |
public let user: AdministrativeUser? | |
} | |
fileprivate var value: Value! | |
fileprivate var permissionChecked: Bool | |
var meow: Meow.Context { return value.meow } | |
var user: AdministrativeUser? { return value.user } | |
init(container: Container) { | |
permissionChecked = false | |
} | |
} | |
fileprivate enum AuthorizationError: Error { | |
case notAuthenticated | |
} | |
extension Request { | |
func cms() throws -> CMSContext { | |
return try make(CMSContext.self) | |
} | |
func assertNotAuthenticated() throws { | |
try cms().permissionChecked = true | |
} | |
@discardableResult | |
func assertAuthenticated() throws -> AdministrativeUser { | |
let context = try self.cms() | |
context.permissionChecked = true | |
guard let user = context.value?.user else { | |
throw AuthorizationError.notAuthenticated | |
} | |
return user | |
} | |
} | |
struct CMSContextMiddleware: Middleware { | |
init() {} | |
func respond(to request: Request, chainingTo next: Responder) throws -> EventLoopFuture<Response> { | |
let token: AdministrativeUserToken? | |
if let cookie = request.http.cookies.all["Token"]?.string { | |
token = try JWT<AdministrativeUserToken>(from: cookie, verifiedUsing: request.make(JWTSigner.self)).payload | |
} else { | |
token = nil | |
} | |
let meow = try request.make(Meow.Context.self) | |
let context: Future<CMSContext.Value> | |
if let token = token { | |
context = token.user.resolve(in: meow).map { user in | |
return CMSContext.Value(meow: meow, token: token, user: user) | |
} | |
} else { | |
context = request.eventLoop.future(CMSContext.Value(meow: meow, token: nil, user: nil)) | |
} | |
return context.flatMap { context in | |
let cmsContext = try request.make(CMSContext.self) | |
cmsContext.value = context | |
return try next.respond(to: request).always { | |
guard cmsContext.permissionChecked else { | |
fatalError("Internal security check failed") | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment