diff --git a/.swift-version b/.swift-version index 4d0dcda..bf77d54 100644 --- a/.swift-version +++ b/.swift-version @@ -1 +1 @@ -4.1.2 +4.2 diff --git a/.travis.yml b/.travis.yml index a14ce0f..554ad6e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ env: - MYSQL_PASSWORD=test - MYSQL_PORT=3306 -osx_image: xcode9.4 +osx_image: xcode10 before_install: - if [ $TRAVIS_OS_NAME == "osx" ]; then brew update; diff --git a/Package.resolved b/Package.resolved index 99c63d1..392d538 100644 --- a/Package.resolved +++ b/Package.resolved @@ -15,8 +15,8 @@ "repositoryURL": "https://github.com/IBM-Swift/BlueCryptor.git", "state": { "branch": null, - "revision": "30b6cf38322838d1e973e0626c6abf9602b03cf5", - "version": "1.0.9" + "revision": "a960efc2759c8816b00baed5db7b3d903a402e78", + "version": "1.0.14" } }, { @@ -24,17 +24,8 @@ "repositoryURL": "https://github.com/brokenhandsio/cmark-gfm.git", "state": { "branch": null, - "revision": "28d762c29119b5e1c3c0ba1e87198a6c0abcdd7a", - "version": "1.0.0" - } - }, - { - "package": "CommonCrypto", - "repositoryURL": "https://github.com/IBM-Swift/CommonCrypto.git", - "state": { - "branch": null, - "revision": "9156d238dbc4c15455b77b45e721b2bb0b995e31", - "version": "1.0.0" + "revision": "351e5cb1bc6a43567b8ff9b9b3f7357c58bdda83", + "version": "1.0.1" } }, { @@ -51,8 +42,8 @@ "repositoryURL": "https://github.com/vapor/core.git", "state": { "branch": null, - "revision": "7f56a09995bf3c8df562be456bdcda405d9d0678", - "version": "3.4.1" + "revision": "96ce86ebf9198328795c4b9cb711489460be083c", + "version": "3.4.4" } }, { @@ -60,8 +51,8 @@ "repositoryURL": "https://github.com/vapor/crypto.git", "state": { "branch": null, - "revision": "4b85405430df1892ee3aa1554bdb477e96cf46ad", - "version": "3.2.0" + "revision": "5605334590affd4785a5839806b4504407e054ac", + "version": "3.3.0" } }, { @@ -78,8 +69,8 @@ "repositoryURL": "https://github.com/vapor/database-kit.git", "state": { "branch": null, - "revision": "7a01659316b9f033fa2150d5cd5e9d3c3e46c2e3", - "version": "1.3.0" + "revision": "3a17dbbe9be5f8c37703e4b7982c1332ad6b00c4", + "version": "1.3.1" } }, { @@ -87,8 +78,8 @@ "repositoryURL": "https://github.com/vapor/fluent.git", "state": { "branch": null, - "revision": "270b6fa372f03809b9795e8f8b9d1c31267a0ff3", - "version": "3.0.0" + "revision": "dc258fe53880f80508df317df3c903ee2c2b9317", + "version": "3.1.0" } }, { @@ -114,8 +105,8 @@ "repositoryURL": "https://github.com/vapor/http.git", "state": { "branch": null, - "revision": "a192ee144ab53370b2c095c003f429746df85595", - "version": "3.1.0" + "revision": "272b22be8cb3364e42a4701c2e0676e37480ec5a", + "version": "3.1.5" } }, { @@ -150,8 +141,8 @@ "repositoryURL": "https://github.com/vapor/mysql.git", "state": { "branch": null, - "revision": "448f1ca28b3ea0f64a627bec22e5b0945d31b9f4", - "version": "3.0.2" + "revision": "355fdc8c60a4869026ff8f19e21f5d5bdbb08e62", + "version": "3.1.0" } }, { @@ -159,8 +150,8 @@ "repositoryURL": "https://github.com/vapor-community/pagination.git", "state": { "branch": null, - "revision": "91658b8ff9300a196190faaa300b33c5e975783c", - "version": "1.0.6" + "revision": "538dcab96e5aa93a22509ad11b1592891fc2ba80", + "version": "1.0.8" } }, { @@ -177,8 +168,8 @@ "repositoryURL": "https://github.com/vapor/redis.git", "state": { "branch": null, - "revision": "7ad1ad7715a90c468cc4fcf427f21635f8e8879e", - "version": "3.0.0" + "revision": "2fb20632db3ad86e2b3596cd34605f694a92c177", + "version": "3.0.2" } }, { @@ -204,8 +195,8 @@ "repositoryURL": "https://github.com/vapor/sql.git", "state": { "branch": null, - "revision": "bfbaa048f9e655218611b65da470efa7deb16616", - "version": "2.0.2" + "revision": "a35cf1dced4ddd32bb2dc8b6e765aea7bcf8d6e0", + "version": "2.1.0" } }, { @@ -213,8 +204,8 @@ "repositoryURL": "https://github.com/vapor/sqlite.git", "state": { "branch": null, - "revision": "635ad49b2d6395b63462abffcce58ee38be1e4cc", - "version": "3.0.0" + "revision": "ad2e9bc9f0ed00ef2c6a05f89c1cec605467c90f", + "version": "3.1.0" } }, { @@ -222,8 +213,8 @@ "repositoryURL": "https://github.com/apple/swift-nio.git", "state": { "branch": null, - "revision": "cf08e673dc41dc63d34065234c8fc432e8d334c4", - "version": "1.9.2" + "revision": "5d8148c8b45dfb449276557f22120694567dd1d2", + "version": "1.9.5" } }, { @@ -231,8 +222,8 @@ "repositoryURL": "https://github.com/apple/swift-nio-ssl.git", "state": { "branch": null, - "revision": "6617eb0d3afcb12170594968df01ca63afb58ac5", - "version": "1.2.0" + "revision": "8380fa29a2af784b067d8ee01c956626ca29f172", + "version": "1.3.1" } }, { @@ -258,8 +249,8 @@ "repositoryURL": "https://github.com/scinfu/SwiftSoup.git", "state": { "branch": null, - "revision": "f445c9067d28346e828e615e2b43cb07b20bca35", - "version": "1.7.2" + "revision": "11da8c685ddde2d519fad04a7daf8485bbbc773e", + "version": "1.7.5" } }, { @@ -276,8 +267,8 @@ "repositoryURL": "https://github.com/vapor/url-encoded-form.git", "state": { "branch": null, - "revision": "cbfe7ef6301557d3f2d0807a98165232ae06e1c6", - "version": "1.0.4" + "revision": "932024f363ee5ff59059cf7d67194a1c271d3d0c", + "version": "1.0.5" } }, { @@ -294,8 +285,8 @@ "repositoryURL": "https://github.com/vapor/vapor.git", "state": { "branch": null, - "revision": "54632a6c1e7ecd9923c0d00b612de936de1c4745", - "version": "3.0.8" + "revision": "157d3b15336caa882662cc75024dd04b2e225246", + "version": "3.1.0" } }, { @@ -312,8 +303,8 @@ "repositoryURL": "https://github.com/vapor/websocket.git", "state": { "branch": null, - "revision": "141cb4d3814dc8062cb0b2f43e72801b5dfcf272", - "version": "1.0.1" + "revision": "eb4277f75f1d96a3d15c852cdd89af1799093dcd", + "version": "1.1.0" } } ] diff --git a/Sources/App/Application/Services/Helper/ImageNameGenerator.swift b/Sources/App/Application/Services/Helper/ImageNameGenerator.swift new file mode 100644 index 0000000..8a36295 --- /dev/null +++ b/Sources/App/Application/Services/Helper/ImageNameGenerator.swift @@ -0,0 +1,20 @@ +import Foundation +import Random +import Vapor + +protocol ImageNameGenerator { + func generateImageName(from string: String) throws -> String +} + +final class ImageNameGeneratorDefault: ImageNameGenerator, Service { + + private let generator: DataGenerator + + init(generator: DataGenerator) { + self.generator = generator + } + + func generateImageName(from string: String) throws -> String { + return try generator.generateData(count: 16).base64URLEncodedString() + } +} diff --git a/Sources/App/Application/Services/Helper/StupidPasswordVerifier.swift b/Sources/App/Application/Services/Helper/StupidPasswordVerifier.swift new file mode 100644 index 0000000..3c8d434 --- /dev/null +++ b/Sources/App/Application/Services/Helper/StupidPasswordVerifier.swift @@ -0,0 +1,9 @@ +import Authentication +import Vapor + +final class StupidPasswordVeryfier: PasswordVerifier, Service { + + func verify(_ password: LosslessDataConvertible, created hash: LosslessDataConvertible) throws -> Bool { + return true + } +} diff --git a/Sources/App/Controllers/API/API+ImageController.swift b/Sources/App/Controllers/API/API+ImageController.swift index b809e5a..de7265d 100644 --- a/Sources/App/Controllers/API/API+ImageController.swift +++ b/Sources/App/Controllers/API/API+ImageController.swift @@ -17,14 +17,20 @@ extension API { func store(request: Request, form: ImageUploadForm) throws -> Future { + guard let imageExtension = form.name.split(separator: ".").last else { + return request.future(HTTPStatus.badRequest) + } + let repository = try request.make(ImageRepository.self) - let newImage = try Image(from: form, on: request) + let imageName = try request.make(ImageNameGenerator.self).generateImageName(from: form.name) + let imageFileName = imageName.appending(".").appending(imageExtension) + let newImage = try Image(from: imageFileName, on: request) let deleteTransaction = request.withPooledConnection(to: .mysql) { conn in MySQLDatabase.transactionExecute({ transaction in newImage.save(on: transaction).map { _ in - try repository.save(image: form.data, for: form.name) + try repository.save(image: form.data, for: imageFileName) } }, on: conn) } diff --git a/Sources/App/Extension/Environment+Util.swift b/Sources/App/Extension/Environment+Util.swift new file mode 100644 index 0000000..6488c41 --- /dev/null +++ b/Sources/App/Extension/Environment+Util.swift @@ -0,0 +1,8 @@ +import Vapor + +extension Environment { + + var isDevelopment: Bool { + return name == "development" + } +} diff --git a/Sources/App/Extension/URandom+Service.swift b/Sources/App/Extension/URandom+Service.swift new file mode 100644 index 0000000..a9c1020 --- /dev/null +++ b/Sources/App/Extension/URandom+Service.swift @@ -0,0 +1,4 @@ +import Random +import Vapor + +extension URandom: Service {} diff --git a/Sources/App/Middleware/AuthErrorMiddleware.swift b/Sources/App/Middleware/AuthErrorMiddleware.swift index 3a2b15a..579ab0e 100644 --- a/Sources/App/Middleware/AuthErrorMiddleware.swift +++ b/Sources/App/Middleware/AuthErrorMiddleware.swift @@ -8,7 +8,7 @@ final class AuthErrorMiddleware: Middleware, Service where A: Authenticatable return try next.respond(to: request) } - let response = request.makeResponse() + let response = request.response() response.http.status = .forbidden return Future.map(on: request) { response } } diff --git a/Sources/App/Models/Scheme/Image.swift b/Sources/App/Models/Scheme/Image.swift index 02b5c1d..4ea842f 100644 --- a/Sources/App/Models/Scheme/Image.swift +++ b/Sources/App/Models/Scheme/Image.swift @@ -37,10 +37,10 @@ final class Image: DatabaseModel { var createdAt: Date? var updatedAt: Date? - init(from form: ImageUploadForm, on container: Container) throws { + init(from name: String, on container: Container) throws { let relativePath = try container.make(FileConfig.self).imageRoot - self.path = relativePath.started(with: "/").finished(with: "/").appending(form.name) - self.altDescription = form.name + self.path = relativePath.started(with: "/").finished(with: "/").appending(name) + self.altDescription = name } func formPublic(on container: Container) throws -> Public { diff --git a/Sources/App/configure.swift b/Sources/App/configure.swift index dcfa4f0..c7084c6 100644 --- a/Sources/App/configure.swift +++ b/Sources/App/configure.swift @@ -4,6 +4,7 @@ import Crypto import FluentMySQL import Leaf import Redis +import Random import Vapor import VaporSecurityHeaders @@ -32,9 +33,23 @@ public func configure( return try container.make(ConfigProvider.self).make(NIOServerConfig.self) } + // data + let random = try URandom() + services.register(random, as: DataGenerator.self) + + // generator + services.register(ImageNameGenerator.self) { container in + ImageNameGeneratorDefault(generator: try container.make()) + } + // bcrypt try services.register(AuthenticationProvider()) - config.prefer(BCryptDigest.self, for: PasswordVerifier.self) + if environment.isDevelopment { + services.register(StupidPasswordVeryfier(), as: PasswordVerifier.self) + config.prefer(StupidPasswordVeryfier.self, for: PasswordVerifier.self) + } else { + config.prefer(BCryptDigest.self, for: PasswordVerifier.self) + } // router let router = EngineRouter.default() diff --git a/Tests/YubatakeTests/TestTools/ApplicationBuilder.swift b/Tests/YubatakeTests/TestTools/ApplicationBuilder.swift index 08e3723..7793dc2 100644 --- a/Tests/YubatakeTests/TestTools/ApplicationBuilder.swift +++ b/Tests/YubatakeTests/TestTools/ApplicationBuilder.swift @@ -12,7 +12,7 @@ final class ApplicationBuilder { class func build(forAdminTests: Bool, envArgs: [String]? = nil, customize: ((Config, Services) -> (Config, Services))? = nil) throws -> Application { var config = Config.default() - var env = try Environment.detect() + var env = Environment(name: "test", isRelease: false) var services = Services.default() if let environmentArgs = envArgs { diff --git a/Tests/YubatakeTests/TestTools/DataMaker.swift b/Tests/YubatakeTests/TestTools/DataMaker.swift index 80c1407..cddf80c 100644 --- a/Tests/YubatakeTests/TestTools/DataMaker.swift +++ b/Tests/YubatakeTests/TestTools/DataMaker.swift @@ -81,7 +81,7 @@ final class DataMaker { class func makeImage(_ name: String, on container: Container) throws -> (ImageUploadForm, Image){ let form = try decode(ImageUploadForm.self, from: ["image_file_data": "data", "image_file_name": name]) - let image = try Image(from: form, on: container) + let image = try Image(from: name, on: container) return (form, image) }