46 lines
1.4 KiB
Swift
46 lines
1.4 KiB
Swift
import Foundation
|
|
import Clairvoyant
|
|
import Vapor
|
|
|
|
final class Authenticator: MetricAccessManager {
|
|
|
|
private var writers: Set<String>
|
|
|
|
init(writers: [String]) {
|
|
self.writers = Set(writers)
|
|
}
|
|
|
|
|
|
func hasAuthorization(for key: String) -> Bool {
|
|
// Note: This is not a constant-time compare, so there may be an opportunity
|
|
// for timing attack here. Sets perform hashed lookups, so this may be less of an issue,
|
|
// and we're not doing anything critical in this application.
|
|
// Worst case, an unauthorized person with a lot of free time and energy to hack this system
|
|
// is able to change contents of the database, which are backed up in any case.
|
|
writers.contains(key)
|
|
}
|
|
|
|
func metricListAccess(isAllowedForToken accessToken: AccessToken) throws {
|
|
guard let key = String(data: accessToken, encoding: .utf8) else {
|
|
return
|
|
}
|
|
guard hasAuthorization(for: key) else {
|
|
throw MetricError.accessDenied
|
|
}
|
|
}
|
|
|
|
func metricAccess(to metric: MetricId, isAllowedForToken accessToken: AccessToken) throws {
|
|
try metricListAccess(isAllowedForToken: accessToken)
|
|
}
|
|
|
|
|
|
func authorize(_ request: Request) throws {
|
|
guard let key = request.headers.first(name: "key") else {
|
|
throw Abort(.badRequest) // 400
|
|
}
|
|
guard hasAuthorization(for: key) else {
|
|
throw Abort(.forbidden) // 403
|
|
}
|
|
}
|
|
}
|