From 00efeb290face4ad5a8e503a74cc5c90b8937200 Mon Sep 17 00:00:00 2001 From: Carlos Torres Date: Sat, 4 Apr 2020 23:53:45 -0700 Subject: [PATCH] Migrated to ArgumentParser --- Package.swift | 5 +- Sources/tlatia/main.swift | 144 ++++++++++++++++++++++---------------- 2 files changed, 85 insertions(+), 64 deletions(-) diff --git a/Package.swift b/Package.swift index e4a51b0..468de8d 100644 --- a/Package.swift +++ b/Package.swift @@ -8,14 +8,15 @@ let package = Package( dependencies: [ // Dependencies declare other packages that this package depends on. // .package(url: /* package url */, from: "1.0.0"), - .package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMinor(from: "1.0.0")) + .package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", .upToNextMinor(from: "1.0.0")), + .package(url: "https://github.com/apple/swift-argument-parser", .upToNextMinor(from: "0.0.1")), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages which this package depends on. .target( name: "tlatia", - dependencies: ["CryptoSwift"]), + dependencies: ["CryptoSwift", "ArgumentParser"]), .testTarget( name: "tlatiaTests", dependencies: ["tlatia"]), diff --git a/Sources/tlatia/main.swift b/Sources/tlatia/main.swift index 9ed49b4..f34b84c 100644 --- a/Sources/tlatia/main.swift +++ b/Sources/tlatia/main.swift @@ -3,88 +3,108 @@ // import Foundation +import ArgumentParser -func encrypt(file: String, withPassword password: String, toFile outputPath: String) throws { - let body = try String(contentsOfFile: file) +public struct RuntimeError: Error, CustomStringConvertible { + var message: String - if let key = Key.init(withPassword: password) { - if let encoder = Encoder(withKey: key) { - let base64Encoded = try encoder.encrypt(body) - try base64Encoded.write(to: URL(fileURLWithPath: outputPath), atomically: true, encoding: String.Encoding.utf8) - } + public init(_ message: String) { + self.message = message } -} -func decrypt(file: String, withPassword password: String, toFile outputPath: String) throws { - let body = try String(contentsOfFile: file) - - if let key = Key.init(withPassword: password) { - if let encoder = Encoder(withKey: key) { - let decodedBody = try encoder.decrypt(body) - try decodedBody.write(to: URL(fileURLWithPath: outputPath), atomically: true, encoding: String.Encoding.utf8) - } + public var description: String { + message } } -enum Operation: String { - case encrypt; - case decrypt; +struct Tlatia: ParsableCommand { + static var configuration = CommandConfiguration( + abstract: "A encryption/decryption utility", + subcommands: [Encrypt.self, Decrypt.self] + ) } -guard CommandLine.argc == 4 else { - print("Usage: tlatia OPERATION INPUT OUTPUT") - exit(EXIT_FAILURE) -} +extension Tlatia { + struct Encrypt: ParsableCommand { + static var configuration = CommandConfiguration(abstract: "Encrypts a file using password") -let operationString = CommandLine.arguments[1] -let inputFilePath = CommandLine.arguments[2] -let outputFilePath = CommandLine.arguments[3] + @Argument(help: "The path to the file for encryption") + var inputPath: String -guard FileManager.default.fileExists(atPath: inputFilePath) else { - print("No such input file") - exit(EXIT_FAILURE) -} + @Argument(help: "The path to the encrypted file") + var outputPath: String -func getPasswordEncryption() throws -> String { - let password = String(cString: getpass("Enter the password: ")) - let passwordRetry = String(cString: getpass("Enter the password again: ")) + func validate() throws { + guard FileManager.default.fileExists(atPath: inputPath) else { + throw RuntimeError("The input file does not exist.") + } + } - guard password != "" || passwordRetry != "" else { - print("Passwords can't be empty") - exit(EXIT_FAILURE) - } + func run() throws { + let password = try getPasswordEncryption() + let body = try String(contentsOfFile: inputPath) - guard password == passwordRetry else { - print("Passwords don't match") - exit(EXIT_FAILURE) - } + if let key = Key.init(withPassword: password) { + if let encoder = Encoder(withKey: key) { + let base64Encoded = try encoder.encrypt(body) + try base64Encoded.write(to: URL(fileURLWithPath: outputPath), atomically: true, encoding: String.Encoding.utf8) + } + } + } - return password -} + func getPasswordEncryption() throws -> String { + let password = String(cString: getpass("Enter the password: ")) + let passwordRetry = String(cString: getpass("Enter the password again: ")) + + guard password != "" || passwordRetry != "" else { + throw RuntimeError("Passwords can't be empty") + } -func getPasswordDecryption() throws -> String { - let password = String(cString: getpass("Enter the password: ")) + guard password == passwordRetry else { + throw RuntimeError("Passwords don't match") + } - guard password != "" else { - print("Passwords can't be empty") - exit(EXIT_FAILURE) + return password + } } - return password -} + struct Decrypt: ParsableCommand { + static var configuration = CommandConfiguration(abstract: "Decrypts a file using a password") -if let operation = Operation(rawValue: operationString) { - switch operation { - case .encrypt: - let password = try getPasswordEncryption() - try encrypt(file: inputFilePath, withPassword: password, toFile: outputFilePath) - case .decrypt: - let password = try getPasswordDecryption() - try decrypt(file: inputFilePath, withPassword: password, toFile: outputFilePath) - } + @Argument(help: "The path to the file for encryption") + var inputPath: String + + @Argument(help: "The path to the encrypted file") + var outputPath: String + + func validate() throws { + guard FileManager.default.fileExists(atPath: inputPath) else { + throw RuntimeError("The input file does not exist.") + } + } + + func run() throws { + let password = try getPasswordDecryption() + let body = try String(contentsOfFile: inputPath) - exit(EXIT_SUCCESS) + if let key = Key.init(withPassword: password) { + if let encoder = Encoder(withKey: key) { + let decodedBody = try encoder.decrypt(body) + try decodedBody.write(to: URL(fileURLWithPath: outputPath), atomically: true, encoding: String.Encoding.utf8) + } + } + } + + func getPasswordDecryption() throws -> String { + let password = String(cString: getpass("Enter the password: ")) + + guard password != "" else { + throw RuntimeError("Passwords can't be empty") + } + + return password + } + } } -print("There's no such operation \"\(operationString)\"") -exit(EXIT_FAILURE) \ No newline at end of file +Tlatia.main() \ No newline at end of file