Skip to content

Instantly share code, notes, and snippets.

@Joannis
Created April 6, 2019 09:27
Show Gist options
  • Save Joannis/b6ebfb674b87c7ad0c3b815879518a6b to your computer and use it in GitHub Desktop.
Save Joannis/b6ebfb674b87c7ad0c3b815879518a6b to your computer and use it in GitHub Desktop.
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