From 75f31ec396f7b928684bfdcf8e02bcd92af5df33 Mon Sep 17 00:00:00 2001 From: James Griffin Date: Tue, 1 Jan 2019 13:47:53 -0400 Subject: [PATCH] Add Token input and Details Display --- Jot.xcodeproj/project.pbxproj | 24 +- Jot/Main.storyboard | 557 ++------------------------ Jot/UI/JwtDetailsTableView.swift | 84 ++++ Jot/UI/JwtDetailsUpdate.swift | 30 ++ Jot/UI/JwtDetailsViewController.swift | 36 ++ Jot/ViewController.swift | 22 - 6 files changed, 202 insertions(+), 551 deletions(-) create mode 100644 Jot/UI/JwtDetailsTableView.swift create mode 100644 Jot/UI/JwtDetailsUpdate.swift create mode 100644 Jot/UI/JwtDetailsViewController.swift delete mode 100644 Jot/ViewController.swift diff --git a/Jot.xcodeproj/project.pbxproj b/Jot.xcodeproj/project.pbxproj index 2610cb3..ab5143f 100644 --- a/Jot.xcodeproj/project.pbxproj +++ b/Jot.xcodeproj/project.pbxproj @@ -9,7 +9,9 @@ /* Begin PBXBuildFile section */ 821E160721D7ED3F00E2D71A /* TokenDeserializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821E160621D7ED3F00E2D71A /* TokenDeserializer.swift */; }; 821E162821DA9A3700E2D71A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 821E162721DA9A3700E2D71A /* Main.storyboard */; }; - 821E165621DAA54900E2D71A /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821E165521DAA54900E2D71A /* ViewController.swift */; }; + 821E165621DAA54900E2D71A /* JwtDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821E165521DAA54900E2D71A /* JwtDetailsViewController.swift */; }; + 822C7E8321DBB46D006DD285 /* JwtDetailsUpdate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 822C7E8221DBB46D006DD285 /* JwtDetailsUpdate.swift */; }; + 822C7E8521DBB929006DD285 /* JwtDetailsTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 822C7E8421DBB929006DD285 /* JwtDetailsTableView.swift */; }; 82CAF46A21D7D41800FED241 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAF46921D7D41800FED241 /* AppDelegate.swift */; }; 82CAF46C21D7D41C00FED241 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 82CAF46B21D7D41C00FED241 /* Assets.xcassets */; }; 82CAF47B21D7D41C00FED241 /* JotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82CAF47A21D7D41C00FED241 /* JotTests.swift */; }; @@ -32,7 +34,9 @@ /* Begin PBXFileReference section */ 821E160621D7ED3F00E2D71A /* TokenDeserializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenDeserializer.swift; sourceTree = ""; }; 821E162721DA9A3700E2D71A /* Main.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; - 821E165521DAA54900E2D71A /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 821E165521DAA54900E2D71A /* JwtDetailsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JwtDetailsViewController.swift; sourceTree = ""; }; + 822C7E8221DBB46D006DD285 /* JwtDetailsUpdate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JwtDetailsUpdate.swift; sourceTree = ""; }; + 822C7E8421DBB929006DD285 /* JwtDetailsTableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JwtDetailsTableView.swift; sourceTree = ""; }; 82CAF46621D7D41800FED241 /* Jot.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Jot.app; sourceTree = BUILT_PRODUCTS_DIR; }; 82CAF46921D7D41800FED241 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 82CAF46B21D7D41C00FED241 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -65,6 +69,16 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 822C7E8121DBB43C006DD285 /* UI */ = { + isa = PBXGroup; + children = ( + 821E165521DAA54900E2D71A /* JwtDetailsViewController.swift */, + 822C7E8221DBB46D006DD285 /* JwtDetailsUpdate.swift */, + 822C7E8421DBB929006DD285 /* JwtDetailsTableView.swift */, + ); + path = UI; + sourceTree = ""; + }; 82CAF45D21D7D41700FED241 = { isa = PBXGroup; children = ( @@ -86,12 +100,12 @@ 82CAF46821D7D41800FED241 /* Jot */ = { isa = PBXGroup; children = ( + 822C7E8121DBB43C006DD285 /* UI */, 82CAF48621D7D54B00FED241 /* Signing */, 82CAF48521D7D53C00FED241 /* Token */, 82CAF46921D7D41800FED241 /* AppDelegate.swift */, 82CAF46B21D7D41C00FED241 /* Assets.xcassets */, 821E162721DA9A3700E2D71A /* Main.storyboard */, - 821E165521DAA54900E2D71A /* ViewController.swift */, 82CAF47021D7D41C00FED241 /* Info.plist */, 82CAF47121D7D41C00FED241 /* Jot.entitlements */, ); @@ -236,11 +250,13 @@ files = ( 821E160721D7ED3F00E2D71A /* TokenDeserializer.swift in Sources */, 82CAF48D21D7D60100FED241 /* Header.swift in Sources */, + 822C7E8521DBB929006DD285 /* JwtDetailsTableView.swift in Sources */, 82CAF48B21D7D5B700FED241 /* Payload.swift in Sources */, 82CAF46A21D7D41800FED241 /* AppDelegate.swift in Sources */, - 821E165621DAA54900E2D71A /* ViewController.swift in Sources */, + 821E165621DAA54900E2D71A /* JwtDetailsViewController.swift in Sources */, 82CAF48F21D7D81800FED241 /* Signature.swift in Sources */, 82CAF48821D7D56D00FED241 /* Jwt.swift in Sources */, + 822C7E8321DBB46D006DD285 /* JwtDetailsUpdate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Jot/Main.storyboard b/Jot/Main.storyboard index 3bf7292..016029c 100644 --- a/Jot/Main.storyboard +++ b/Jot/Main.storyboard @@ -15,7 +15,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -47,7 +47,7 @@ - + @@ -59,62 +59,18 @@ - + - + - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -148,12 +104,6 @@ - - - - - - @@ -166,130 +116,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -337,291 +163,10 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - Default - - - - - - - Left to Right - - - - - - - Right to Left - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -658,15 +203,7 @@ - - - - - - - - - + @@ -684,7 +221,7 @@ - + @@ -701,10 +238,10 @@ - + - + @@ -715,15 +252,15 @@ - - + + - - + + @@ -734,29 +271,9 @@ - - - - - - - - - - - - - - - - - - - - - - + + @@ -767,41 +284,21 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + diff --git a/Jot/UI/JwtDetailsTableView.swift b/Jot/UI/JwtDetailsTableView.swift new file mode 100644 index 0000000..b16bf72 --- /dev/null +++ b/Jot/UI/JwtDetailsTableView.swift @@ -0,0 +1,84 @@ +// +// JwtDetailsTableView.swift +// Jot +// +// Created by James Griffin-Allwood on 2019-01-01. +// Copyright © 2019 James Griffin-Allwood. All rights reserved. +// + +import Foundation +import Cocoa + +extension JwtDetailsViewController: NSTableViewDelegate, NSTableViewDataSource { + func numberOfRows(in tableView: NSTableView) -> Int { + return getDataArray().count + } + + func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? + { + guard let payloadRow = getDataArray().object(at: row) as? [String: Any] else { + return "None" + } + + guard let columnId = tableColumn?.identifier.rawValue else { + return "None" + } + + return displayString(value: payloadRow[columnId], row: row) + } + + func getDataArray() -> NSArray { + guard let tokenPayload = self.jwt?.payload else { + return [] + } + + return NSArray(array: tokenPayload.map { ["PayloadKey": $0, "PayloadValue": $1] }) + } + + private func displayString(value: Any?, row: Int) -> String { + if let stringValue = value as? String { + return stringValue + } + + if let booleanValue = value as? Bool { + return String(booleanValue) + } + + if let number = value as? Int { + return isDateRow(row) + ? iso8601Date(number) + : String(number) + } + + return value != nil ? "Complex Object" : "None" + } + + private func isDateRow(_ row: Int) -> Bool { + guard let payloadRow = getDataArray().object(at: row) as? [String: Any] else { + return false + } + + guard let payloadRowKey = payloadRow["PayloadKey"] as? String else { + return false + } + + switch payloadRowKey { + case StandardJwtDateKeys.issuedAt.rawValue, StandardJwtDateKeys.expiry.rawValue: + return true + default: + return false + } + } + + private func iso8601Date(_ timestamp: Int) -> String { + let date = Date(timeIntervalSince1970: TimeInterval(timestamp)) + let formatter = ISO8601DateFormatter() + + return formatter.string(from: date) + } +} + +enum StandardJwtDateKeys: String { + case issuedAt = "iat" + case expiry = "exp" +} diff --git a/Jot/UI/JwtDetailsUpdate.swift b/Jot/UI/JwtDetailsUpdate.swift new file mode 100644 index 0000000..9ec89f5 --- /dev/null +++ b/Jot/UI/JwtDetailsUpdate.swift @@ -0,0 +1,30 @@ +// +// JwtDetailsUpdate.swift +// Jot +// +// Created by James Griffin-Allwood on 2019-01-01. +// Copyright © 2019 James Griffin-Allwood. All rights reserved. +// + +import Foundation +import Cocoa +import os.log + +extension JwtDetailsViewController: NSTextStorageDelegate { + func textStorage(_ textStorage: NSTextStorage, didProcessEditing editedMask: NSTextStorageEditActions, range editedRange: NSRange, changeInLength delta: Int) { + guard textStorage.string.count > 0 else { + return + } + + guard let token = Jwt(token: textStorage.string) else { + os_log("%@ is not a valid JWT Token", log: OSLog.default, type: .error, textStorage.string) + return + } + + self.jwt = token + + jwtAlgOutput.stringValue = token.header.alg.rawValue + jwtTypOutput.stringValue = token.header.typ.rawValue + jwtDetailsTable.reloadData() + } +} diff --git a/Jot/UI/JwtDetailsViewController.swift b/Jot/UI/JwtDetailsViewController.swift new file mode 100644 index 0000000..e493fae --- /dev/null +++ b/Jot/UI/JwtDetailsViewController.swift @@ -0,0 +1,36 @@ +// +// JwtDetailsViewController.swift +// Jot +// +// Created by James Griffin-Allwood on 2018-12-31. +// Copyright © 2018 James Griffin-Allwood. All rights reserved. +// + +import Foundation +import Cocoa + +class JwtDetailsViewController: NSViewController { + + var jwt: Jwt? + + @IBOutlet weak var jwtImportButton: NSButton! + @IBOutlet var jwtInput: NSTextView! + @IBOutlet weak var jwtAlgOutput: NSTextField! + @IBOutlet weak var jwtTypOutput: NSTextField! + @IBOutlet weak var jwtDetailsTable: NSTableView! + + override func viewDidLoad() { + super.viewDidLoad() + jwtInput.textStorage?.delegate = self + jwtDetailsTable.delegate = self + jwtDetailsTable.dataSource = self + } + + @IBAction func importToken(_ sender: NSButton) { + guard let tokenString = NSPasteboard.general.string(forType: .string) else { + return + } + + jwtInput.textStorage?.setAttributedString(NSAttributedString(string: tokenString)) + } +} diff --git a/Jot/ViewController.swift b/Jot/ViewController.swift deleted file mode 100644 index 87a02b8..0000000 --- a/Jot/ViewController.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// ViewController.swift -// Jot -// -// Created by James Griffin-Allwood on 2018-12-31. -// Copyright © 2018 James Griffin-Allwood. All rights reserved. -// - -import Foundation -import Cocoa - -class ViewController: NSViewController { - override func viewDidLoad() { - super.viewDidLoad() - } - - override var representedObject: Any? { - didSet { - // Update the view, if already loaded. - } - } -}