Add authentication to uploads
This commit is contained in:
parent
f14da6bafc
commit
ee41e3bcd3
@ -1,4 +1,7 @@
|
|||||||
{
|
{
|
||||||
"logPath": "\/var\/log\/caps.log",
|
"logPath": "\/var\/log\/caps.log",
|
||||||
"serveFiles": true
|
"serveFiles": true,
|
||||||
|
"writers" : [
|
||||||
|
"auth_key_1"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,8 @@ final class CapServer {
|
|||||||
|
|
||||||
private var saveImmediatelly = true
|
private var saveImmediatelly = true
|
||||||
|
|
||||||
|
private var writers: Set<String>
|
||||||
|
|
||||||
private var caps = [Int: Cap]() {
|
private var caps = [Int: Cap]() {
|
||||||
didSet {
|
didSet {
|
||||||
guard saveImmediatelly else {
|
guard saveImmediatelly else {
|
||||||
@ -26,12 +28,13 @@ final class CapServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var nextClassifierVersion: Int {
|
var nextClassifierVersion: Int {
|
||||||
caps.values.map { $0.classifierVersion }.max() ?? 1
|
caps.values.compactMap { $0.classifierVersion }.max() ?? 1
|
||||||
}
|
}
|
||||||
|
|
||||||
init(in folder: URL) throws {
|
init(in folder: URL, writers: [String]) throws {
|
||||||
self.imageFolder = folder.appendingPathComponent("images")
|
self.imageFolder = folder.appendingPathComponent("images")
|
||||||
self.dbFile = folder.appendingPathComponent("caps.json")
|
self.dbFile = folder.appendingPathComponent("caps.json")
|
||||||
|
self.writers = Set(writers)
|
||||||
|
|
||||||
var isDirectory: ObjCBool = false
|
var isDirectory: ObjCBool = false
|
||||||
guard fm.fileExists(atPath: folder.path, isDirectory: &isDirectory),
|
guard fm.fileExists(atPath: folder.path, isDirectory: &isDirectory),
|
||||||
@ -66,6 +69,17 @@ final class CapServer {
|
|||||||
folder(of: cap).appendingPathComponent(String(format: "%04d-%02d.jpg", cap, version))
|
folder(of: cap).appendingPathComponent(String(format: "%04d-%02d.jpg", cap, version))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: Authentication
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Counts
|
// MARK: Counts
|
||||||
|
|
||||||
private func updateCounts() throws {
|
private func updateCounts() throws {
|
||||||
|
@ -2,15 +2,20 @@ import Foundation
|
|||||||
|
|
||||||
struct Config: Codable {
|
struct Config: Codable {
|
||||||
|
|
||||||
|
/// The path to the log file
|
||||||
let logPath: String
|
let logPath: String
|
||||||
|
|
||||||
|
/// Serve files in the Public directory using Vapor
|
||||||
let serveFiles: Bool
|
let serveFiles: Bool
|
||||||
|
|
||||||
|
/// Authentication tokens for remotes allowed to write
|
||||||
|
let writers: [String]
|
||||||
|
|
||||||
var logURL: URL {
|
var logURL: URL {
|
||||||
.init(fileURLWithPath: logPath)
|
.init(fileURLWithPath: logPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
static var `default`: Config {
|
static var `default`: Config {
|
||||||
.init(logPath: "/var/log/caps.log", serveFiles: true)
|
.init(logPath: "/var/log/caps.log", serveFiles: true, writers: [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,8 @@ public func configure(_ app: Application) throws {
|
|||||||
app.middleware.use(middleware)
|
app.middleware.use(middleware)
|
||||||
}
|
}
|
||||||
|
|
||||||
server = try CapServer(in: URL(fileURLWithPath: publicDirectory))
|
server = try CapServer(in: URL(fileURLWithPath: publicDirectory),
|
||||||
|
writers: config.writers)
|
||||||
|
|
||||||
// Register routes to the router
|
// Register routes to the router
|
||||||
try routes(app)
|
try routes(app)
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
import Vapor
|
import Vapor
|
||||||
|
|
||||||
|
private func authorize(_ request: Request) throws {
|
||||||
|
let key = try request.query.get(String.self, at: "key")
|
||||||
|
guard server.hasAuthorization(for: key) else {
|
||||||
|
throw Abort(.forbidden)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Register your application's routes here.
|
/// Register your application's routes here.
|
||||||
///
|
///
|
||||||
/// [Learn More →](https://docs.vapor.codes/3.0/getting-started/structure/#routesswift)
|
/// [Learn More →](https://docs.vapor.codes/3.0/getting-started/structure/#routesswift)
|
||||||
@ -7,6 +14,7 @@ func routes(_ app: Application) throws {
|
|||||||
|
|
||||||
// Set the name of a cap
|
// Set the name of a cap
|
||||||
app.postCatching("name", ":n") { request in
|
app.postCatching("name", ":n") { request in
|
||||||
|
try authorize(request)
|
||||||
guard let cap = request.parameters.get("n", as: Int.self) else {
|
guard let cap = request.parameters.get("n", as: Int.self) else {
|
||||||
log("Invalid parameter for cap")
|
log("Invalid parameter for cap")
|
||||||
throw Abort(.badRequest)
|
throw Abort(.badRequest)
|
||||||
@ -20,6 +28,7 @@ func routes(_ app: Application) throws {
|
|||||||
|
|
||||||
// Upload an image
|
// Upload an image
|
||||||
app.postCatching("images", ":n") { request -> Data in
|
app.postCatching("images", ":n") { request -> Data in
|
||||||
|
try authorize(request)
|
||||||
guard let cap = request.parameters.get("n", as: Int.self) else {
|
guard let cap = request.parameters.get("n", as: Int.self) else {
|
||||||
log("Invalid parameter for cap")
|
log("Invalid parameter for cap")
|
||||||
throw Abort(.badRequest)
|
throw Abort(.badRequest)
|
||||||
@ -35,6 +44,7 @@ func routes(_ app: Application) throws {
|
|||||||
|
|
||||||
// Set a different version as the main image
|
// Set a different version as the main image
|
||||||
app.getCatching("switch", ":n", ":v") { request in
|
app.getCatching("switch", ":n", ":v") { request in
|
||||||
|
try authorize(request)
|
||||||
guard let cap = request.parameters.get("n", as: Int.self), cap >= 0 else {
|
guard let cap = request.parameters.get("n", as: Int.self), cap >= 0 else {
|
||||||
log("Invalid parameter for cap")
|
log("Invalid parameter for cap")
|
||||||
throw Abort(.badRequest)
|
throw Abort(.badRequest)
|
||||||
|
Loading…
Reference in New Issue
Block a user