diff --git a/CHANGELOG.md b/CHANGELOG.md index 3843773..1b40bd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,26 @@ +# 1.0 Official Release +New Features: +- Fully 10.15 support +- New selections during loaner configuration + - Days + - Weeks + - Months +- Gmail support while requesting an extension +- Loan status in UI menu bar +- User information populated from Jamf Pro + +Changes: +- Removed old functions +- Restructured the code +- Cleaner and sleek UI +- Code converted to Swift 5 + +Bugfixes: +- Justification not included in email +- Shared secret bug where it wasn't being properly cased +- Authentication was being performed more than once +- UI freezes during authentication + # 0.3 Beta Release - Generic authentication supported now - Uses a shared secret using SHA256 hash comparison diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftAppKit.dylib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftAppKit.dylib deleted file mode 100755 index 6762ae8..0000000 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftAppKit.dylib and /dev/null differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftCore.dylib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftCore.dylib index bbc24b1..8a54baa 100755 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftCore.dylib and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftCore.dylib differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftCoreData.dylib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftCoreData.dylib deleted file mode 100755 index 71c564b..0000000 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftCoreData.dylib and /dev/null differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftCoreFoundation.dylib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftCoreFoundation.dylib index 58d4b82..de1ece4 100755 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftCoreFoundation.dylib and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftCoreFoundation.dylib differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftCoreGraphics.dylib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftCoreGraphics.dylib index fe5dafa..150895e 100755 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftCoreGraphics.dylib and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftCoreGraphics.dylib differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftCoreImage.dylib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftCoreImage.dylib deleted file mode 100755 index 4d9b67d..0000000 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftCoreImage.dylib and /dev/null differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftDarwin.dylib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftDarwin.dylib index 86853ad..e65b374 100755 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftDarwin.dylib and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftDarwin.dylib differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftDispatch.dylib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftDispatch.dylib index 072e7a6..506629b 100755 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftDispatch.dylib and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftDispatch.dylib differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftFoundation.dylib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftFoundation.dylib index 976b7d7..88d1d2d 100755 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftFoundation.dylib and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftFoundation.dylib differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftIOKit.dylib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftIOKit.dylib index f489676..5234ab7 100755 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftIOKit.dylib and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftIOKit.dylib differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftMetal.dylib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftMetal.dylib deleted file mode 100755 index eb8682b..0000000 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftMetal.dylib and /dev/null differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftObjectiveC.dylib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftObjectiveC.dylib index eb9f043..329ae96 100755 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftObjectiveC.dylib and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftObjectiveC.dylib differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftQuartzCore.dylib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftQuartzCore.dylib deleted file mode 100755 index 277c3f8..0000000 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftQuartzCore.dylib and /dev/null differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftXPC.dylib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftXPC.dylib index e2f4e55..787db40 100755 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftXPC.dylib and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftXPC.dylib differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftos.dylib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftos.dylib index 3e79412..81e972c 100755 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftos.dylib and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Frameworks/libswiftos.dylib differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Info.plist b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Info.plist index 61830fc..2c2ce5a 100644 --- a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Info.plist +++ b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Info.plist @@ -3,7 +3,7 @@ BuildMachineOSBuild - 18G29g + 19D62e CFBundleDevelopmentRegion en CFBundleExecutable @@ -27,21 +27,21 @@ MacOSX CFBundleVersion - 231 + 403 DTCompiler com.apple.compilers.llvm.clang.1_0 DTPlatformBuild - 10E1001 + 11C504 DTPlatformVersion GM DTSDKBuild - 18E219 + 19B90 DTSDKName - macosx10.14 + macosx10.15 DTXcode - 1020 + 1130 DTXcodeBuild - 10E1001 + 11C504 LSMinimumSystemVersion 10.12 LSUIElement diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/MacOS/LoanShark b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/MacOS/LoanShark index e1f15aa..82e0577 100755 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/MacOS/LoanShark and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/MacOS/LoanShark differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/AppIcon.icns b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/AppIcon.icns index e56750f..0f21315 100644 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/AppIcon.icns and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/AppIcon.icns differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Assets.car b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Assets.car index b62ba33..45cf1c1 100644 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Assets.car and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Assets.car differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/20Z-7b-FQf-view-zCF-fv-Dwm.nib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/20Z-7b-FQf-view-zCF-fv-Dwm.nib index cc8bca3..496d608 100644 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/20Z-7b-FQf-view-zCF-fv-Dwm.nib and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/20Z-7b-FQf-view-zCF-fv-Dwm.nib differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/DSB-g8-MKz-view-tZ7-t3-3n5.nib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/DSB-g8-MKz-view-tZ7-t3-3n5.nib index e4fd5ef..13b5a4d 100644 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/DSB-g8-MKz-view-tZ7-t3-3n5.nib and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/DSB-g8-MKz-view-tZ7-t3-3n5.nib differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/Info.plist b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/Info.plist index 0b0fa3f..9e6be12 100644 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/Info.plist and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/Info.plist differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/MainMenu.nib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/MainMenu.nib index 9561bc3..39efe74 100644 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/MainMenu.nib and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/MainMenu.nib differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/NSViewController-20Z-7b-FQf.nib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/NSViewController-20Z-7b-FQf.nib deleted file mode 100644 index d1b2797..0000000 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/NSViewController-20Z-7b-FQf.nib and /dev/null differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/NSViewController-DSB-g8-MKz.nib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/NSViewController-DSB-g8-MKz.nib deleted file mode 100644 index 5db4018..0000000 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/NSViewController-DSB-g8-MKz.nib and /dev/null differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/NSViewController-lRq-Sq-zZ6.nib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/NSViewController-lRq-Sq-zZ6.nib deleted file mode 100644 index e6612c2..0000000 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/NSViewController-lRq-Sq-zZ6.nib and /dev/null differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/NSWindowController-c2Q-3e-TR7.nib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/NSWindowController-c2Q-3e-TR7.nib new file mode 100644 index 0000000..05e396e Binary files /dev/null and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/NSWindowController-c2Q-3e-TR7.nib differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/NSWindowController-smC-sj-ZbX.nib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/NSWindowController-smC-sj-ZbX.nib new file mode 100644 index 0000000..eda868b Binary files /dev/null and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/NSWindowController-smC-sj-ZbX.nib differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/XfG-lQ-9wD-view-SH2-yM-fko.nib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/XfG-lQ-9wD-view-SH2-yM-fko.nib index 6512711..212607e 100644 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/XfG-lQ-9wD-view-SH2-yM-fko.nib and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/XfG-lQ-9wD-view-SH2-yM-fko.nib differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/authentication.nib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/authentication.nib index 7dc60dd..8b3a67e 100644 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/authentication.nib and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/authentication.nib differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/extensionRequest.nib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/extensionRequest.nib index 0c7ae22..bcce6a4 100644 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/extensionRequest.nib and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/extensionRequest.nib differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/gZa-NH-KiA-view-wv6-hf-89Z.nib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/gZa-NH-KiA-view-wv6-hf-89Z.nib index 3d68e3a..d6fee90 100644 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/gZa-NH-KiA-view-wv6-hf-89Z.nib and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/gZa-NH-KiA-view-wv6-hf-89Z.nib differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/lRq-Sq-zZ6-view-IOZ-KI-u6s.nib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/lRq-Sq-zZ6-view-IOZ-KI-u6s.nib index 4d0d930..2ae8a6e 100644 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/lRq-Sq-zZ6-view-IOZ-KI-u6s.nib and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/lRq-Sq-zZ6-view-IOZ-KI-u6s.nib differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/lockoutWindow.nib b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/lockoutWindow.nib index af8b7a6..39b7ae4 100644 Binary files a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/lockoutWindow.nib and b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/Resources/Base.lproj/Main.storyboardc/lockoutWindow.nib differ diff --git a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/_CodeSignature/CodeResources b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/_CodeSignature/CodeResources index bc13a27..b03b86b 100644 --- a/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/_CodeSignature/CodeResources +++ b/Installer/payload/Library/Application Support/LoanShark/LoanShark.app/Contents/_CodeSignature/CodeResources @@ -6,99 +6,77 @@ Resources/AppIcon.icns - tPPJf3hsKdKxQZcLityOy+D7BwI= + f1woeoLmRpFGeUbX9McX2ctWhfs= Resources/Assets.car - ecpdoa5Yf4iMsDY2tGscnRyZ19c= + HR7AICQ41PNc6CfbMHxAomukXYM= Resources/Base.lproj/Main.storyboardc/20Z-7b-FQf-view-zCF-fv-Dwm.nib - Lu9ACwjfZi4CtWLpAHyzJRW8YD4= + g66kNdvTWTfqUtESx47AEdRlICk= Resources/Base.lproj/Main.storyboardc/DSB-g8-MKz-view-tZ7-t3-3n5.nib - qUzLa3PgWoj0Duk88Mbz/qEhvDQ= + 2qmpQo6uWFeVRatfDCrYyUdfStk= Resources/Base.lproj/Main.storyboardc/Info.plist - 7Owt5kxRfci/AgNMam4Pb3mQJcI= + by8wG3/Ohx9nHZtwzi2SQJHMF1o= Resources/Base.lproj/Main.storyboardc/MainMenu.nib - /hLG3QJXZJGPDhA/D1tip7Nyp9A= + TxiPXeeAKqwiA3gVCA57Ctolbzk= - Resources/Base.lproj/Main.storyboardc/NSViewController-20Z-7b-FQf.nib + Resources/Base.lproj/Main.storyboardc/NSWindowController-c2Q-3e-TR7.nib - wcBzjyR2FyZhGSndtF/uMMXkxvw= + /MpzTplvgchA7AkAegD+zsm1zfQ= - Resources/Base.lproj/Main.storyboardc/NSViewController-DSB-g8-MKz.nib + Resources/Base.lproj/Main.storyboardc/NSWindowController-smC-sj-ZbX.nib - uz8UGctdmKZmrxzgpx2vjzttDXc= - - Resources/Base.lproj/Main.storyboardc/NSViewController-lRq-Sq-zZ6.nib - - sKI+/Q2Ma8sVX3cggSscUn6ALjc= + Sf1ft2YdiiszYSpoe/fRuH8+VBc= Resources/Base.lproj/Main.storyboardc/XfG-lQ-9wD-view-SH2-yM-fko.nib - 95AGleG4WYB3G9X9M+tmk5fBUW8= + w9gRrHoVDtOZjnekzkrzM3Qz7ms= Resources/Base.lproj/Main.storyboardc/authentication.nib - BJwjBFD3Y7cSNV3nggpsBLzjrZw= + jXqgaIcfTlczEUsdpie+ObvWRIU= Resources/Base.lproj/Main.storyboardc/extensionRequest.nib - yY6BX56eVFskyQRPZXHAmhZQ2Ck= + S8byuRqsnrx0mjAUXXmZxMS3LGE= Resources/Base.lproj/Main.storyboardc/gZa-NH-KiA-view-wv6-hf-89Z.nib - LTJAYnCWf21JYEaq0VGXVPdZz2o= + pJuBNOc/U4tbPizVQwTDt/hIMmU= Resources/Base.lproj/Main.storyboardc/lRq-Sq-zZ6-view-IOZ-KI-u6s.nib - 9RcLF5UrlpPEB+sqq1KFVZtIxzk= + czXYzT9f+JNK0oEXYnJGqgqatnk= Resources/Base.lproj/Main.storyboardc/lockoutWindow.nib - 3x8NiQbf8b0DvuzCKWodmxVmuCA= + qxNJ+M2EimPACmNm9x0KmBEnlkM= files2 - Frameworks/libswiftAppKit.dylib - - cdhash - - 7U9e4MrnQf4AHB2d9ChbaXc5F9o= - - requirement - identifier "com.apple.dt.runtime.swiftAppKit" and anchor apple generic and certificate leaf[subject.CN] = "Mac Developer: tylermorgan210@gmail.com (SM8UP534NU)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */ - Frameworks/libswiftCore.dylib cdhash - lTXVXd9EH1LlgP6k6rrLXxSAFZg= + DAB3tx5oe1BPe58m7BD+ymSfz50= requirement identifier "com.apple.dt.runtime.swiftCore" and anchor apple generic and certificate leaf[subject.CN] = "Mac Developer: tylermorgan210@gmail.com (SM8UP534NU)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */ - Frameworks/libswiftCoreData.dylib - - cdhash - - g4Z8LvBzXUGBNiwXfxm65+sPDY4= - - requirement - identifier "com.apple.dt.runtime.swiftCoreData" and anchor apple generic and certificate leaf[subject.CN] = "Mac Developer: tylermorgan210@gmail.com (SM8UP534NU)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */ - Frameworks/libswiftCoreFoundation.dylib cdhash - jKfoRcb6sIjXKUtzdQ7TjHItSyU= + cpLlFWoICj2wsQqFDQ5r2/staFU= requirement identifier "com.apple.dt.runtime.swiftCoreFoundation" and anchor apple generic and certificate leaf[subject.CN] = "Mac Developer: tylermorgan210@gmail.com (SM8UP534NU)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */ @@ -107,25 +85,16 @@ cdhash - pcGe0u7jebFDZJHdlCpm3nZtaso= + yZB3ug8lMsJZ20bSHtAyokf7A94= requirement identifier "com.apple.dt.runtime.swiftCoreGraphics" and anchor apple generic and certificate leaf[subject.CN] = "Mac Developer: tylermorgan210@gmail.com (SM8UP534NU)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */ - Frameworks/libswiftCoreImage.dylib - - cdhash - - oae8QmfHRtnuhDbAAOsatPxKcNQ= - - requirement - identifier "com.apple.dt.runtime.swiftCoreImage" and anchor apple generic and certificate leaf[subject.CN] = "Mac Developer: tylermorgan210@gmail.com (SM8UP534NU)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */ - Frameworks/libswiftDarwin.dylib cdhash - gsiiivYLbC6crwfu8aXDZXmq7BA= + kqtGe4XgH/+uXCz33IisAYNu8kU= requirement identifier "com.apple.dt.runtime.swiftDarwin" and anchor apple generic and certificate leaf[subject.CN] = "Mac Developer: tylermorgan210@gmail.com (SM8UP534NU)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */ @@ -134,7 +103,7 @@ cdhash - IfzSdVAswTobwu3j2lTfgo7Bgrw= + m4Jc2sDid4U0VLsG4PsZTm/ZY+k= requirement identifier "com.apple.dt.runtime.swiftDispatch" and anchor apple generic and certificate leaf[subject.CN] = "Mac Developer: tylermorgan210@gmail.com (SM8UP534NU)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */ @@ -143,7 +112,7 @@ cdhash - wlbMC+rCGY2HHFBeEEbAMWUqebI= + bW7FTLllQTXLUTGBkHpGUxft5QQ= requirement identifier "com.apple.dt.runtime.swiftFoundation" and anchor apple generic and certificate leaf[subject.CN] = "Mac Developer: tylermorgan210@gmail.com (SM8UP534NU)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */ @@ -152,43 +121,25 @@ cdhash - L3ODwwXgH6WXocJaG4WMkS49rcA= + bgTFEmqjHa94p8qV12R+DQg4+Vk= requirement identifier "com.apple.dt.runtime.swiftIOKit" and anchor apple generic and certificate leaf[subject.CN] = "Mac Developer: tylermorgan210@gmail.com (SM8UP534NU)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */ - Frameworks/libswiftMetal.dylib - - cdhash - - 4DS4OyuirMGDGTYScIf+85H1J2Y= - - requirement - identifier "com.apple.dt.runtime.swiftMetal" and anchor apple generic and certificate leaf[subject.CN] = "Mac Developer: tylermorgan210@gmail.com (SM8UP534NU)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */ - Frameworks/libswiftObjectiveC.dylib cdhash - C6Rb6gDJ6bhtkySrMgFJ+t9Siqw= + E/waPIAPDe4Idhxo1Ie9IYyTCu4= requirement identifier "com.apple.dt.runtime.swiftObjectiveC" and anchor apple generic and certificate leaf[subject.CN] = "Mac Developer: tylermorgan210@gmail.com (SM8UP534NU)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */ - Frameworks/libswiftQuartzCore.dylib - - cdhash - - 81nwZ5PtvFthFH2eEDN4EHquIJ8= - - requirement - identifier "com.apple.dt.runtime.swiftQuartzCore" and anchor apple generic and certificate leaf[subject.CN] = "Mac Developer: tylermorgan210@gmail.com (SM8UP534NU)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */ - Frameworks/libswiftXPC.dylib cdhash - b52JRCdgAzWAz6mv8aGBj7XB4rY= + hl7Di0qPjXuVKNXi0UBO9Bg46R4= requirement identifier "com.apple.dt.runtime.swiftXPC" and anchor apple generic and certificate leaf[subject.CN] = "Mac Developer: tylermorgan210@gmail.com (SM8UP534NU)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */ @@ -197,7 +148,7 @@ cdhash - 3uFC8e3XiXvDEfrnQ1sC4s2BRIY= + CWrktUR1DqA/82OJKbCWl8pfFTA= requirement identifier "com.apple.dt.runtime.swiftos" and anchor apple generic and certificate leaf[subject.CN] = "Mac Developer: tylermorgan210@gmail.com (SM8UP534NU)" and certificate 1[field.1.2.840.113635.100.6.2.1] /* exists */ @@ -206,105 +157,98 @@ hash2 - HZWCBEfHN/vYT5XH/pD15KmmHhOE6wTRlHW+p+G8uK8= + Yl6JWJAdRaC3du3UcIaVju0Qvf96mlSwwKW1vUSBX2M= Resources/Assets.car hash2 - tl63ovlvJsFYOkxK6oZhm3cmUFP8NPQY7QCz6wxlRks= + Nwjay4qu5yIx5ORTnP1LFtMSTtwc4ytteJORX33dZE8= Resources/Base.lproj/Main.storyboardc/20Z-7b-FQf-view-zCF-fv-Dwm.nib hash2 - 4ZZnmaTkWP06RfFlmh1/BRFLiUmTH+0he3La/RYo8VI= + VSeMTLLaeuaSV2ijUzfqCtac8hgT9TWp8nQ4AqRih5c= Resources/Base.lproj/Main.storyboardc/DSB-g8-MKz-view-tZ7-t3-3n5.nib hash2 - ig9+koP/aFWrCGYy/VbZdyG0qF4qAzW/ZPgUjbtqX8M= + QZ6FpgGCJCINxbjgFpg4645JQFpFwDqe6alHFQJgNlU= Resources/Base.lproj/Main.storyboardc/Info.plist hash2 - +0mSr5an2lVM0HNxMNfJozcPyMQzOYU+X8jjkUltdq4= + Mh0a/xweb2Ww8MZ101NY26pkRl/KCPSJw8nclwfqtOk= Resources/Base.lproj/Main.storyboardc/MainMenu.nib hash2 - HhNpmHH2XCIQT4plvIvc9Au2t6SBpSDSVlExHBSgmIk= - - - Resources/Base.lproj/Main.storyboardc/NSViewController-20Z-7b-FQf.nib - - hash2 - - pybO6Xr6MA9d+czo7YjeJasGtBj/KcWNLeS76czH2bM= + sjAf6Yu4ZgqhbHOq21vlyPNK+QQq2jyEE89GfJVPB6w= - Resources/Base.lproj/Main.storyboardc/NSViewController-DSB-g8-MKz.nib + Resources/Base.lproj/Main.storyboardc/NSWindowController-c2Q-3e-TR7.nib hash2 - J4gaIPzkBxsaGM2bOy8Ysv6NGw9fEN8rmn4gXrI2Ju8= + kffyu+wELEf0+BJeema2Rq+Kk2Q7gEz9WAe7EiFhhJw= - Resources/Base.lproj/Main.storyboardc/NSViewController-lRq-Sq-zZ6.nib + Resources/Base.lproj/Main.storyboardc/NSWindowController-smC-sj-ZbX.nib hash2 - Nf1cuu7m2Tva5Tcthi8FeX/cbsTFm3n9PvZB1oac/co= + nDHojjAdkkHSji5Dt322plohUuuKNX0wrO55HWNcqog= Resources/Base.lproj/Main.storyboardc/XfG-lQ-9wD-view-SH2-yM-fko.nib hash2 - WTr6RTLlkIUlW589c1VFuiVx3dQsoAC/8pKSieNuahg= + 2dQ34OEq0nTAGOfvZLvA0Q4FhnA43pdD4OxiO4bjVZw= Resources/Base.lproj/Main.storyboardc/authentication.nib hash2 - cuK0NgSV3wD6Liexx5d1NypVpiqR4ukYNPtG8JqxEXE= + VRctZQN+OomF6gaOuplzj6u1J2jXjPx0sdoZRs4m7CA= Resources/Base.lproj/Main.storyboardc/extensionRequest.nib hash2 - uT7fj6WtqF6IZhm26gaFsE51ik+71X22aA/hhA8Cu5A= + c3jHkRgBs5TQxV5+d+2yjHgrBnsiuW/5F69PNzXWAVI= Resources/Base.lproj/Main.storyboardc/gZa-NH-KiA-view-wv6-hf-89Z.nib hash2 - MF+vURrOM0ztZfNFT9zedVCNXAKFQuXVoxmPzYX8Pr0= + YNCoIXxzD3uR1jsnqrbXdZu/Cbj9PTjr87roXMg5AqU= Resources/Base.lproj/Main.storyboardc/lRq-Sq-zZ6-view-IOZ-KI-u6s.nib hash2 - 7saOXxvTCAdZIEln7h0FZ7E8MGToIvBSHkwlBmmF/bQ= + XB4A0zbYbtS0870pmomjswyA0JfuDoud3h7WmjyLFIY= Resources/Base.lproj/Main.storyboardc/lockoutWindow.nib hash2 - fMTmENymaZj3GfeK2rUSBfp33kfErwkBxPNc2ZcFNnE= + Ndqf1Y0bpw45b/RTi1ZhCrV/FZwYXEjTfSeBLpvET78= diff --git a/Installer/payload/Library/Preferences/com.github.cybertunnel.LoanShark.test.plist b/Installer/payload/Library/Preferences/com.github.cybertunnel.LoanShark.test.plist new file mode 100644 index 0000000..1d2a05c --- /dev/null +++ b/Installer/payload/Library/Preferences/com.github.cybertunnel.LoanShark.test.plist @@ -0,0 +1,40 @@ + + + + + authorizedGroupIDs + + + 1 + + 20 + + extensionOptions + + 1 Day + 3 Days + 5 Days + 7 Days + 1 Week + 2 Weeks + 3 Weeks + 1 Month + + jamfURL + myjamfserver.domain.com + lockoutMessage + Your loan period has expired. Please return to DNG Engineering or the manager you received the compter from. + logoffTimer + 60 + + sharedSecret + --- + sharedSecretAuth + + + + enableDebugging + + + + diff --git a/LoanShark.xcodeproj/project.pbxproj b/LoanShark.xcodeproj/project.pbxproj index fa73f89..a69fd93 100644 --- a/LoanShark.xcodeproj/project.pbxproj +++ b/LoanShark.xcodeproj/project.pbxproj @@ -8,28 +8,23 @@ /* Begin PBXBuildFile section */ 81239EDF226A68D700713960 /* ArgumentParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81239EDE226A68D700713960 /* ArgumentParser.swift */; }; - 8149B7622216137300243E13 /* StatusTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8149B7612216137300243E13 /* StatusTransformer.swift */; }; 815CDAFF225529DF0020A0D7 /* String_Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 815CDAFE225529DF0020A0D7 /* String_Extension.swift */; }; - 815E7FFC221CB11F009E3CA2 /* RemainingTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 815E7FFB221CB11F009E3CA2 /* RemainingTransformer.swift */; }; + 8185988823B2525E00BF1A0E /* LoanStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8185988723B2525E00BF1A0E /* LoanStatus.swift */; }; 81898DED224E9CB900A70807 /* LoginWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81898DEC224E9CB900A70807 /* LoginWindow.swift */; }; 81CAD2F92209D942003C5D32 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81CAD2F82209D942003C5D32 /* AppDelegate.swift */; }; - 81CAD2FB2209D942003C5D32 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81CAD2FA2209D942003C5D32 /* ViewController.swift */; }; 81CAD2FD2209D942003C5D32 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 81CAD2FC2209D942003C5D32 /* Assets.xcassets */; }; 81CAD3002209D942003C5D32 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81CAD2FE2209D942003C5D32 /* Main.storyboard */; }; 81CAD30C2209D942003C5D32 /* LoanSharkTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81CAD30B2209D942003C5D32 /* LoanSharkTests.swift */; }; 81CAD3172209D942003C5D32 /* LoanSharkUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81CAD3162209D942003C5D32 /* LoanSharkUITests.swift */; }; - 81CAD3292209D9F1003C5D32 /* ActionOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81CAD3282209D9F1003C5D32 /* ActionOptions.swift */; }; 81CAD32B220A0ABE003C5D32 /* Person.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81CAD32A220A0ABE003C5D32 /* Person.swift */; }; 81CAD32D220A0C68003C5D32 /* Date_Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81CAD32C220A0C68003C5D32 /* Date_Extension.swift */; }; 81CAD32F220A0C85003C5D32 /* Token.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81CAD32E220A0C85003C5D32 /* Token.swift */; }; 81CAD331220A0F9E003C5D32 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81CAD330220A0F9E003C5D32 /* Preferences.swift */; }; 81CAD333220A0FB2003C5D32 /* UserDefaults_Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81CAD332220A0FB2003C5D32 /* UserDefaults_Extension.swift */; }; - 81CAD335220A1379003C5D32 /* LoanPeriod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81CAD334220A1379003C5D32 /* LoanPeriod.swift */; }; - 81CAD337220A1409003C5D32 /* NotificationName_Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81CAD336220A1409003C5D32 /* NotificationName_Extension.swift */; }; + 81CAD335220A1379003C5D32 /* Loan.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81CAD334220A1379003C5D32 /* Loan.swift */; }; 81CAD339220A1B50003C5D32 /* LoanManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81CAD338220A1B50003C5D32 /* LoanManager.swift */; }; 81CAD33B220A1CB6003C5D32 /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81CAD33A220A1CB6003C5D32 /* Log.swift */; }; 81CAD341220A3DB0003C5D32 /* LoanerExpiredViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81CAD340220A3DB0003C5D32 /* LoanerExpiredViewController.swift */; }; - 81CAD343220A3ED4003C5D32 /* TimerTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81CAD342220A3ED4003C5D32 /* TimerTransformer.swift */; }; 81CAD345220B2AC3003C5D32 /* ActivationAuthentication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81CAD344220B2AC3003C5D32 /* ActivationAuthentication.swift */; }; 81CAD347220B3015003C5D32 /* LoanerConfigurationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81CAD346220B3015003C5D32 /* LoanerConfigurationViewController.swift */; }; 81CAD349220B4295003C5D32 /* AuthenticationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81CAD348220B4295003C5D32 /* AuthenticationViewController.swift */; }; @@ -60,13 +55,11 @@ /* Begin PBXFileReference section */ 81239EDE226A68D700713960 /* ArgumentParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArgumentParser.swift; sourceTree = ""; }; - 8149B7612216137300243E13 /* StatusTransformer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusTransformer.swift; sourceTree = ""; }; 815CDAFE225529DF0020A0D7 /* String_Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String_Extension.swift; sourceTree = ""; }; - 815E7FFB221CB11F009E3CA2 /* RemainingTransformer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemainingTransformer.swift; sourceTree = ""; }; + 8185988723B2525E00BF1A0E /* LoanStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoanStatus.swift; sourceTree = ""; }; 81898DEC224E9CB900A70807 /* LoginWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginWindow.swift; sourceTree = ""; }; 81CAD2F52209D942003C5D32 /* LoanShark.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LoanShark.app; sourceTree = BUILT_PRODUCTS_DIR; }; 81CAD2F82209D942003C5D32 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 81CAD2FA2209D942003C5D32 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 81CAD2FC2209D942003C5D32 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 81CAD2FF2209D942003C5D32 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 81CAD3012209D942003C5D32 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -77,18 +70,15 @@ 81CAD3122209D942003C5D32 /* LoanSharkUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LoanSharkUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 81CAD3162209D942003C5D32 /* LoanSharkUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoanSharkUITests.swift; sourceTree = ""; }; 81CAD3182209D942003C5D32 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 81CAD3282209D9F1003C5D32 /* ActionOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionOptions.swift; sourceTree = ""; }; 81CAD32A220A0ABE003C5D32 /* Person.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Person.swift; sourceTree = ""; }; 81CAD32C220A0C68003C5D32 /* Date_Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Date_Extension.swift; sourceTree = ""; }; 81CAD32E220A0C85003C5D32 /* Token.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Token.swift; sourceTree = ""; }; 81CAD330220A0F9E003C5D32 /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = ""; }; 81CAD332220A0FB2003C5D32 /* UserDefaults_Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaults_Extension.swift; sourceTree = ""; }; - 81CAD334220A1379003C5D32 /* LoanPeriod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoanPeriod.swift; sourceTree = ""; }; - 81CAD336220A1409003C5D32 /* NotificationName_Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationName_Extension.swift; sourceTree = ""; }; + 81CAD334220A1379003C5D32 /* Loan.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Loan.swift; sourceTree = ""; }; 81CAD338220A1B50003C5D32 /* LoanManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoanManager.swift; sourceTree = ""; }; 81CAD33A220A1CB6003C5D32 /* Log.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Log.swift; sourceTree = ""; }; 81CAD340220A3DB0003C5D32 /* LoanerExpiredViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoanerExpiredViewController.swift; sourceTree = ""; }; - 81CAD342220A3ED4003C5D32 /* TimerTransformer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimerTransformer.swift; sourceTree = ""; }; 81CAD344220B2AC3003C5D32 /* ActivationAuthentication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivationAuthentication.swift; sourceTree = ""; }; 81CAD346220B3015003C5D32 /* LoanerConfigurationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoanerConfigurationViewController.swift; sourceTree = ""; }; 81CAD348220B4295003C5D32 /* AuthenticationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationViewController.swift; sourceTree = ""; }; @@ -155,7 +145,6 @@ 81CAD3252209D99B003C5D32 /* Views */, 81CAD3242209D990003C5D32 /* Business Objects */, 81CAD2F82209D942003C5D32 /* AppDelegate.swift */, - 81CAD2FA2209D942003C5D32 /* ViewController.swift */, 81CAD2FC2209D942003C5D32 /* Assets.xcassets */, 81CAD2FE2209D942003C5D32 /* Main.storyboard */, 81CAD3012209D942003C5D32 /* Info.plist */, @@ -185,12 +174,11 @@ 81CAD3242209D990003C5D32 /* Business Objects */ = { isa = PBXGroup; children = ( - 81CAD3282209D9F1003C5D32 /* ActionOptions.swift */, + 8185988723B2525E00BF1A0E /* LoanStatus.swift */, 81CAD32A220A0ABE003C5D32 /* Person.swift */, 81CAD32C220A0C68003C5D32 /* Date_Extension.swift */, 81CAD32E220A0C85003C5D32 /* Token.swift */, - 81CAD334220A1379003C5D32 /* LoanPeriod.swift */, - 81CAD336220A1409003C5D32 /* NotificationName_Extension.swift */, + 81CAD334220A1379003C5D32 /* Loan.swift */, ); path = "Business Objects"; sourceTree = ""; @@ -217,9 +205,6 @@ 81CAD338220A1B50003C5D32 /* LoanManager.swift */, 81CAD33A220A1CB6003C5D32 /* Log.swift */, 81898DEC224E9CB900A70807 /* LoginWindow.swift */, - 81CAD342220A3ED4003C5D32 /* TimerTransformer.swift */, - 8149B7612216137300243E13 /* StatusTransformer.swift */, - 815E7FFB221CB11F009E3CA2 /* RemainingTransformer.swift */, 81CAD344220B2AC3003C5D32 /* ActivationAuthentication.swift */, 815CDAFE225529DF0020A0D7 /* String_Extension.swift */, 81239EDE226A68D700713960 /* ArgumentParser.swift */, @@ -313,11 +298,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 1010; - LastUpgradeCheck = 1010; + LastUpgradeCheck = 1120; ORGANIZATIONNAME = "Tyler Morgan"; TargetAttributes = { 81CAD2F42209D941003C5D32 = { CreatedOnToolsVersion = 10.1; + LastSwiftMigration = 1130; SystemCapabilities = { com.apple.HardenedRuntime = { enabled = 1; @@ -329,10 +315,12 @@ }; 81CAD3062209D942003C5D32 = { CreatedOnToolsVersion = 10.1; + LastSwiftMigration = 1130; TestTargetID = 81CAD2F42209D941003C5D32; }; 81CAD3112209D942003C5D32 = { CreatedOnToolsVersion = 10.1; + LastSwiftMigration = 1130; TestTargetID = 81CAD2F42209D941003C5D32; }; }; @@ -389,15 +377,13 @@ buildActionMask = 2147483647; files = ( 81CAD34B220B618D003C5D32 /* ExtensionRequestViewController.swift in Sources */, - 81CAD3292209D9F1003C5D32 /* ActionOptions.swift in Sources */, - 815E7FFC221CB11F009E3CA2 /* RemainingTransformer.swift in Sources */, 81CAD339220A1B50003C5D32 /* LoanManager.swift in Sources */, 815CDAFF225529DF0020A0D7 /* String_Extension.swift in Sources */, - 8149B7622216137300243E13 /* StatusTransformer.swift in Sources */, 81CAD350220B6D7C003C5D32 /* AgentMenu.swift in Sources */, 81CAD33B220A1CB6003C5D32 /* Log.swift in Sources */, 81CAD349220B4295003C5D32 /* AuthenticationViewController.swift in Sources */, 81CAD331220A0F9E003C5D32 /* Preferences.swift in Sources */, + 8185988823B2525E00BF1A0E /* LoanStatus.swift in Sources */, 81CAD353220B725D003C5D32 /* AgentMenuSegue.swift in Sources */, 81898DED224E9CB900A70807 /* LoginWindow.swift in Sources */, 81E486DA224BB6940001DE4B /* LockoutWindow.swift in Sources */, @@ -405,15 +391,12 @@ 81E486D8224BB5F20001DE4B /* LockoutWindowController.swift in Sources */, 81CAD333220A0FB2003C5D32 /* UserDefaults_Extension.swift in Sources */, 81CAD32D220A0C68003C5D32 /* Date_Extension.swift in Sources */, - 81CAD2FB2209D942003C5D32 /* ViewController.swift in Sources */, 81CAD32F220A0C85003C5D32 /* Token.swift in Sources */, 81CAD341220A3DB0003C5D32 /* LoanerExpiredViewController.swift in Sources */, - 81CAD343220A3ED4003C5D32 /* TimerTransformer.swift in Sources */, 81CAD345220B2AC3003C5D32 /* ActivationAuthentication.swift in Sources */, - 81CAD337220A1409003C5D32 /* NotificationName_Extension.swift in Sources */, 81239EDF226A68D700713960 /* ArgumentParser.swift in Sources */, 81CAD34D220B63DC003C5D32 /* ExtensionViewController.swift in Sources */, - 81CAD335220A1379003C5D32 /* LoanPeriod.swift in Sources */, + 81CAD335220A1379003C5D32 /* Loan.swift in Sources */, 81CAD32B220A0ABE003C5D32 /* Person.swift in Sources */, 81CAD2F92209D942003C5D32 /* AppDelegate.swift in Sources */, ); @@ -582,8 +565,10 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = LoanShark/LoanShark.entitlements; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 403; DEVELOPMENT_TEAM = 55JHL22EU7; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = LoanShark/Info.plist; @@ -594,7 +579,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.12; PRODUCT_BUNDLE_IDENTIFIER = com.github.cybertunnel.LoanShark; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -603,8 +588,10 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = LoanShark/LoanShark.entitlements; + CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 403; DEVELOPMENT_TEAM = 55JHL22EU7; ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = LoanShark/Info.plist; @@ -615,7 +602,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.12; PRODUCT_BUNDLE_IDENTIFIER = com.github.cybertunnel.LoanShark; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; }; name = Release; }; @@ -635,7 +622,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = com.github.cybertunnel.LoanSharkTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LoanShark.app/Contents/MacOS/LoanShark"; }; name = Debug; @@ -656,7 +643,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = com.github.cybertunnel.LoanSharkTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/LoanShark.app/Contents/MacOS/LoanShark"; }; name = Release; @@ -676,7 +663,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = com.github.cybertunnel.LoanSharkUITests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TEST_TARGET_NAME = LoanShark; }; name = Debug; @@ -696,7 +683,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = com.github.cybertunnel.LoanSharkUITests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TEST_TARGET_NAME = LoanShark; }; name = Release; diff --git a/LoanShark.xcodeproj/xcshareddata/xcschemes/LoanShark.xcscheme b/LoanShark.xcodeproj/xcshareddata/xcschemes/LoanShark.xcscheme index 2848fae..49c54fd 100644 --- a/LoanShark.xcodeproj/xcshareddata/xcschemes/LoanShark.xcscheme +++ b/LoanShark.xcodeproj/xcshareddata/xcschemes/LoanShark.xcscheme @@ -1,6 +1,6 @@ + + + + @@ -49,17 +58,6 @@ - - - - - - - - diff --git a/LoanShark/AppDelegate.swift b/LoanShark/AppDelegate.swift index 0550585..07193b8 100644 --- a/LoanShark/AppDelegate.swift +++ b/LoanShark/AppDelegate.swift @@ -14,16 +14,153 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele // MARK: Cocoa Binding Resources - @objc let loanerManager = LoanManager.sharedInstance - @objc let enableDebugging = Preferences.sharedInstance.enableDebugging + let loanerManager = LoanManager.sharedInstance + let enableDebugging = Preferences.sharedInstance.enableDebugging // Don't Use - private let dontUse: Any? = initialSetup() private var lockoutWindow: LockoutWindowController! private var storyboard: NSStoryboard { return NSStoryboard(name: "Main", bundle: nil) } + // MARK: Arguments + let arguements = [ + /// Sets the loaner period to expired + Argument( + name: "--set-expired", + description: "Set loaner period to expired.", + isBool: true, + callback: { (_) in + Log.write(.info, Log.Category.application, "Set expiration argument sent, setting loaner period to expired.") + print("Setting Loan Period to expired!") + LoanManager.sharedInstance.setExpired() + exit(0) + } + ), + + /// Extends the loaner period + Argument( + name: "--extend", + description: "Extend loaner by set number of days.", + isBool: false, + callback: { (value) in + Log.write(.info, Log.Category.application, "Loaner extension argument passed, attempting to extend loaner") + + guard let passcode = value["--passcode"] else { + Log.write(.fault, Log.Category.application, "--passcode was not passed, unable to authenticate.") + print("Missing --passcode argument.") + exit(1) + } + + guard let sharedSecret = Preferences.sharedInstance.sharedSecret else { + Log.write(.fault, Log.Category.application, "Shared secret not configured, please ensure this is configured before attempting to extend loaner period via. Command Line") + + print("Missing Shared Secret in preferences for --passcode or --extend to work properly.") + exit(1) + } + + if passcode.sha256().lowercased() == sharedSecret.lowercased() { + guard let length_string = value["--extend"] else { + Log.write(.error, Log.Category.application, "Extension amount was not provided!.") + exit(1) + } + + guard let length = Int(length_string) else { + Log.write(.error, Log.Category.application,"Unable to parse extension amount from provided \(length_string) length.") + exit(1) + } + do { + try LoanManager.sharedInstance.extend(extensionOf: length) + } + catch { + Log.write(.fault, Log.Category.application, "Error occurred while extending loan period.") + exit(1) + } + + print("Successfully extended the loaner by \(length_string) days!") + exit(0) + } else { + Log.write(.error, Log.Category.application, "Passcode provided does not match stored passcode, unable to properly authenticate.") + exit(1) + } + } + ), + + /// Passcode used for assignment, and extension + Argument( + name: "--passcode", + description: "Passcode to properly authenticate you.", + isBool: false, + callback: { _ in + return + } + ), + + // Gets the current status of the loan. + Argument( + name: "--status", + description: "Get the loaner period status", + isBool: true, + callback: { (_) in + Log.write(.info, Log.Category.application, "Requested to provide loaner period status") + print(LoanManager.sharedInstance.loanStatus.rawValue) + NSApp.terminate(self) + + } + ), + + /// Gets the current loanee details + Argument( + name: "--loanee-details", + description: "Get the loanee details", + isBool: true, + callback: { (_) in + Log.write(.info, Log.Category.application, "Requested to give loanee details, getting and providing loanee information") + print(LoanManager.sharedInstance.loanee?.description ?? "No Information to Provide") + NSApp.terminate(self) + } + ), + + /// DEBUG: Preferences + Argument( + name: "--prefs", + description: "Get the preferences LoanShark sees.", + isBool: true, + callback: { (_) in + Log.write(.info, Log.Category.application, "Requested to provide preference details, getting information and dumping it to standard out.") + + // Jamf URL + print("jamfURL:" + (Preferences.sharedInstance.jssURL ?? "Not Set")) + // Authorized Groups + if let authGroups = Preferences.sharedInstance.authorizedGroupIDs { + print("authorizedGroupIds:" + String(describing: authGroups)) + } + else { + print("authorizedGroupIds:Not Set") + } + // Extension Options + if let extOpt = Preferences.sharedInstance.extensionOptions { + print("extensionOptions:" + String(describing: extOpt)) + } + else { + print("extensionOptions:Not Set") + } + // Log Off Timer + print("logOffTimer:" + String(describing: Preferences.sharedInstance.logoffTimer)) + // Lockout Message + print("lockoutMessage:" + (Preferences.sharedInstance.lockoutMessage ?? "Not Set")) + // Debugging + print("enableDebugging:" + String(describing: Preferences.sharedInstance.enableDebugging)) + // Shared Secret + print("sharedSecret:" + (Preferences.sharedInstance.sharedSecret ?? "Not Set")) + // Shared Secret Auth + print("sharedSecretAuth:" + String(describing: Preferences.sharedInstance.sharedSecretAuth)) + // Jamf Cloud + print("jamfCloud:" + String(describing: Preferences.sharedInstance.jamfCloud)) + } + ) + ] + // MARK: IB Outlets @@ -41,122 +178,50 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele func applicationWillFinishLaunching(_ notification: Notification) { + // MARK: Argument Parsing Log.write(.debug, Log.Category.argumentParser, "Building argument parsing.") - // Set Loan Period to Expired argument - argParser.addArgument(name: "--set-expired", description: "Set loaner period to expired.", isBool: true) { (value) in - Log.write(.info, Log.Category.application, "Set expiration argument sent, setting loaner period to expired.") - print("Setting Loan Period to expired!") - self.loanerManager.setExpired() + for argument in self.arguements { + argParser.addArgument( + name: argument.name, + description: argument.description, + isBool: argument.isBool, + callback: argument.callback + ) } - - // Perform extension argument - // Requires --passcode parameter as well - argParser.addArgument(name: "--extend", description: "Extend loaner by set number of days.") { (value) in - Log.write(.info, Log.Category.application, "Loaner extension argument passed, attempting to extend loaner") - - guard let passcode = value["--passcode"] else { - Log.write(.fault, Log.Category.application, "--passcode was not passed, unable to authenticate.") - throw ArgumentError.missingValue("Missing --passcode") - } - - guard let sharedSecret = Preferences.sharedInstance.sharedSecret else { - Log.write(.fault, Log.Category.application, "Shared secret not configured, please ensure this is configured before attempting to extend loaner period via. Command Line") - throw ArgumentError.unsupportedArgument("Missing Shared Secret in preferences for --passcode or --extend to work properly.") - } - - if passcode.sha256() == sharedSecret { - Log.write(.info, Log.Category.application, "Provided passcode is correct, proceeding") - guard let daysRaw = value["--extend"] else { - Log.write(.fault, Log.Category.application, "Unable to get extension amount.") - throw ArgumentError.missingValue("--extend") - } - - guard let days = Int(daysRaw) else { - Log.write(.fault, Log.Category.application, "Unable to get number of days from provided input") - throw ArgumentError.invalidType(value: daysRaw, type: "Int", argument: "--extend") - } - - try self.loanerManager.extend(extensionOf: (days + 1)) - print("Successfully extended loaner by \(String(describing: days)). Total loaning period remaining is now \(self.loanerManager.loanPeriod?.remaining ?? 0) days.") - NSApp.terminate(self) - } - else { - print("Invalid passcode provided, please try again.") - Log.write(.error, Log.Category.application, "Passcode provided is invalid") - NSApp.terminate(self) - } - } - - // Authenticate using passcode - argParser.addArgument(name: "--passcode", description: "Passcode to properly authenticate you") { (value) in - - } - - // Get Loaner Status - argParser.addArgument(name: "--status", description: "Get the loaner period status", isBool: true) { (_) in - Log.write(.info, Log.Category.application, "Requested to provide loaner period status") - print(self.loanerManager.loanStatus.toString()) - NSApp.terminate(self) - } - - // Get Loanee Details - argParser.addArgument(name: "--loanee-details", description: "Get the loanee details", isBool: true) { (_) in - Log.write(.info, Log.Category.application, "Requested to give loanee details, getting and providing loanee information") - print(self.loanerManager.loanee?.description ?? "No Information to Provide") - NSApp.terminate(self) - } - - // DEBUG: Get Preferences - argParser.addArgument(name: "--prefs", description: "Get the preferences LoanShark sees", isBool: true) {(_) in - Log.write(.info, Log.Category.application, "Requested to provide preference details, getting information and dumping it to standard out.") - - // Jamf URL - print("jamfURL:" + (Preferences.sharedInstance.jssURL ?? "Not Set")) - // Authorized Groups - if let authGroups = Preferences.sharedInstance.authorizedGroupIDs { - print("authorizedGroupIds:" + String(describing: authGroups)) - } - else { - print("authorizedGroupIds:Not Set") - } - // Extension Options - if let extOpt = Preferences.sharedInstance.extensionOptions { - print("extensionOptions:" + String(describing: extOpt)) - } - else { - print("extensionOptions:Not Set") - } - // Log Off Timer - print("logOffTimer:" + String(describing: Preferences.sharedInstance.logoffTimer)) - // Lockout Message - print("lockoutMessage:" + (Preferences.sharedInstance.lockoutMessage ?? "Not Set")) - // Debugging - print("enableDebugging:" + String(describing: Preferences.sharedInstance.enableDebugging)) - // Shared Secret - print("sharedSecret:" + (Preferences.sharedInstance.sharedSecret ?? "Not Set")) - // Shared Secret Auth - print("sharedSecretAuth:" + String(describing: Preferences.sharedInstance.sharedSecretAuth)) - // Jamf Cloud - print("jamfCloud:" + String(describing: Preferences.sharedInstance.jamfCloud)) - } - } func applicationDidFinishLaunching(_ aNotification: Notification) { + // MARK: Agent Menu Log.write(.debug, Log.Category.application, "Building Agent Menu.") item.menu = agentMenu item.title = "LoanShark" + LoanManager.sharedInstance.addCallback { + DispatchQueue.main.async { + switch LoanManager.sharedInstance.loanStatus { + case .active: + self.item.image = NSImage(named: NSImage.statusAvailableName) + case .warning: + self.item.image = NSImage(named: NSImage.statusPartiallyAvailableName) + case .critical: + self.item.image = NSImage(named: NSImage.statusUnavailableName) + case .notSet: + self.item.image = NSImage(named: NSImage.statusNoneName) + default: + self.item.image = NSImage(named: NSImage.statusNoneName) + } + } + } Log.write(.debug, Log.Category.application, "Agent Menu built.") - + // MARK: Loaner Information Log.write(.info, Log.Category.application, "Checking loaner information") if let startDate = Preferences.sharedInstance.startDate, let endDate = Preferences.sharedInstance.endDate { Log.write(.debug, Log.Category.application, "Start Date: \(startDate.toString(format: "MM/dd/yyyy")) ; End DateL \(endDate.toString(format: "MM/dd/yyyy"))") - let period = LoanPeriod(startDate: startDate, endDate: endDate) + let period = Loan(startDate: startDate, endDate: endDate) Log.write(.debug, Log.Category.application, period.description) self.willChangeValue(forKey: "loanerManager") Log.write(.debug, Log.Category.application, "Application setting loaner period in loaner manager") @@ -188,62 +253,41 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele } Log.write(.info, Log.Category.application, "Enabling observer for notifications.") - NotificationCenter.default.addObserver(self, selector: #selector(self.loanPeriodChanged(_:)), name: NSNotification.Name.loanerPeriodChanged, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(self.loanPeriodSet(_:)), name: NSNotification.Name.loanerPeriodSet, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(self.loanPeriodExpired(_:)), name: NSNotification.Name.loanerPeriodExpired, object: nil) - self.loanerManager.startPeriodChecker() - if self.loanerManager.loanStatus == .notSet { + // TODO: Switch this out for loan manager's new mech + LoanManager.sharedInstance.addCallback { self.sendUserNotification() + + if LoanManager.sharedInstance.loanPeriod != nil { + if LoanManager.sharedInstance.loanPeriod?.remaining ?? 0 < 0 { + self.loanPeriodExpired() + } + } } self.argParser.parse() } - func applicationWillTerminate(_ aNotification: Notification) { - // Insert code here to tear down your application - } - - private static func initialSetup() { - - Log.write(.info, Log.Category.application, "Beginning initial setup.") - // Value Transformers for bindings - ValueTransformer.setValueTransformer(StatusTransformer(), forName: .statusTransformer) - ValueTransformer.setValueTransformer(TimerTransformer(), forName: .timerTransformer) - ValueTransformer.setValueTransformer(RemainingTransformer(), forName: .remainingTransformer) - Log.write(.info, Log.Category.application, "Finished initial setup.") - } - - @objc func loanPeriodChanged(_ aNotification: Notification) { - Log.write(.debug, Log.Category.application, "Application detected a loan period change.") - self.willChangeValue(forKey: "loanerManager") - self.didChangeValue(forKey: "loanerManager") - self.sendUserNotification() - } - - @objc func loanPeriodSet(_ aNotification: Notification) { - Log.write(.debug, Log.Category.application, "Application detected loaner period being set.") - self.willChangeValue(forKey: "loanerManager") - self.didChangeValue(forKey: "loanerManager") - } - @objc func loanPeriodExpired(_ aNotification: Notification) { + func loanPeriodExpired() { Log.write(.info, Log.Category.application, "Loan period expired, displaying lockout message") - if #available(OSX 10.13, *) { - guard let lockoutWC = NSStoryboard.main?.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(stringLiteral: "lockoutWindow")) as? LockoutWindowController else { - Log.write(.error, Log.Category.application, "Unable to get lockout window controller") - return - } - self.lockoutWindow = lockoutWC - } else { - guard let lockoutWC = self.storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(stringLiteral: "lockoutWindow")) as? LockoutWindowController else { - Log.write(.error, Log.Category.application, "Unable to get lockout window controller") - return + DispatchQueue.main.async { + if #available(OSX 10.13, *) { + guard let lockoutWC = NSStoryboard.main?.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(stringLiteral: "lockoutWindow")) as? LockoutWindowController else { + Log.write(.error, Log.Category.application, "Unable to get lockout window controller") + return + } + self.lockoutWindow = lockoutWC + } else { + guard let lockoutWC = self.storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(stringLiteral: "lockoutWindow")) as? LockoutWindowController else { + Log.write(.error, Log.Category.application, "Unable to get lockout window controller") + return + } + self.lockoutWindow = lockoutWC } - self.lockoutWindow = lockoutWC + + self.lockoutWindow.loadWindow() + self.lockoutWindow.showWindow(self) } - - self.lockoutWindow.loadWindow() - self.lockoutWindow.showWindow(self) } private func sendUserNotification() { diff --git a/LoanShark/Base.lproj/Main.storyboard b/LoanShark/Base.lproj/Main.storyboard index 2acc954..9d47c20 100644 --- a/LoanShark/Base.lproj/Main.storyboard +++ b/LoanShark/Base.lproj/Main.storyboard @@ -1,8 +1,8 @@ - + - + @@ -30,6 +30,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -45,45 +95,14 @@ - - - - NSIsNil - - - - - - StatusTransformer - - - - - - - NSIsNil - - - - - RemainingTransformer - - - - - - - NSIsNil - - - + @@ -93,69 +112,15 @@ - - - - NSIsNil - - - - - NSIsNil - - - - - - - - NSIsNil - - - - - NSIsNil - - - - - Loanee's Email Address - - - - - - - NSIsNil - - - - - NSIsNil - - - - - Loanee's Phone Number - - - - - - - NSIsNil - - - @@ -163,45 +128,12 @@ - - - - NSIsNil - - - - - NSIsNil - - - - - - - - NSIsNil - - - - - NSIsNil - - - - - - - - NSIsNil - - - @@ -210,73 +142,74 @@ - - - NSIsNotNil - - - + - - - NSIsNil - - - + - + + + + + + + + + + + + + + + + + + + @@ -312,12 +245,12 @@ - - + + - + @@ -325,16 +258,16 @@ - + - + - + - + @@ -348,19 +281,6 @@ - - - - NSNegateBoolean - - - - - - Username - - - @@ -372,19 +292,6 @@ NSAllRomanInputSourcesLocaleIdentifier - - - - - Password - - - - - NSNegateBoolean - - - @@ -400,15 +307,12 @@ - - - - + - + @@ -425,19 +329,6 @@ NSAllRomanInputSourcesLocaleIdentifier - - - - NSNegateBoolean - - - - - - Password - - - @@ -449,13 +340,6 @@ - - - - NSNegateBoolean - - - @@ -473,21 +357,13 @@ - + - + @@ -537,14 +404,22 @@ DQ - - + + + + + + + + + + - + @@ -619,7 +494,7 @@ DQ - + @@ -629,9 +504,6 @@ DQ - - - @@ -667,13 +539,6 @@ DQ - - - - - - - @@ -696,32 +561,15 @@ DQ - - - NSIsNotNil - - - + @@ -746,6 +594,9 @@ DQ + + + @@ -788,13 +639,6 @@ DQ - - - - Message that is displayed to the end user. - - - @@ -822,13 +666,6 @@ DQ - - - - TimerTransformer - - - @@ -840,13 +677,6 @@ DQ - - - - Contact Name - - - @@ -855,13 +685,6 @@ DQ - - - - Contact Phone Number - - - @@ -870,13 +693,6 @@ DQ - - - - Contact Email Address - - - @@ -930,16 +746,23 @@ DQ + + + + + + + - + - + - + @@ -961,11 +784,11 @@ DQ - + - + @@ -973,10 +796,10 @@ DQ - + - + @@ -984,7 +807,7 @@ DQ - + @@ -996,22 +819,33 @@ DQ - + - - - - - Period in Days - - - - + + + + + + + + + + + + + + + + + + + + @@ -1019,21 +853,23 @@ DQ + + - + - + - + @@ -1041,68 +877,36 @@ DQ - + - - - - - First Name - - - - + - - - - - Phone Number - - - - + - - - - - Email Address - - - - + - - - - - Last Name - - - @@ -1124,11 +928,11 @@ DQ - + - + @@ -1136,68 +940,36 @@ DQ - + - - - - - First Name - - - - + - - - - - Last Name - - - - + - - - - - Phone Number - - - - + - - - - - Email Address - - - @@ -1225,7 +997,7 @@ DQ @@ -1260,10 +1031,23 @@ DQ + + + + + + + + + + + + + - + @@ -1320,13 +1104,6 @@ DQ - - - - - - - @@ -1351,17 +1128,10 @@ DQ - - - - - - - @@ -1381,21 +1150,13 @@ DQ - + @@ -1429,6 +1190,12 @@ DQ + + + + + + @@ -1440,9 +1207,9 @@ DQ - - - + + + diff --git a/LoanShark/Business Objects/ActionOptions.swift b/LoanShark/Business Objects/ActionOptions.swift deleted file mode 100644 index 094a0af..0000000 --- a/LoanShark/Business Objects/ActionOptions.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// ActionOptions.swift -// LoanShark -// -// Created by Tyler Morgan on 2/5/19. -// Copyright © 2019 Tyler Morgan. All rights reserved. -// - -import Foundation - -/** - Extension options used to display to the user, and used to alert the program of a request change. - */ -struct ActionOptions { - static let oneDay = NSUserNotificationAction(identifier: "1Day", title: "1 Day") - static let threeDays = NSUserNotificationAction(identifier: "3Days", title: "3 Days") - static let sevenDays = NSUserNotificationAction(identifier: "7Days", title: "7 Days") - static let fourteenDays = NSUserNotificationAction(identifier: "14Days", title: "14 Days") - static let thirtyDays = NSUserNotificationAction(identifier: "30Days", title: "30 Days") -} diff --git a/LoanShark/Business Objects/Date_Extension.swift b/LoanShark/Business Objects/Date_Extension.swift index 497f134..fe1ee38 100644 --- a/LoanShark/Business Objects/Date_Extension.swift +++ b/LoanShark/Business Objects/Date_Extension.swift @@ -9,38 +9,79 @@ import Foundation extension Date { - /// Returns the amount of years from another date + + /** + Calculates the years between the current date and the date provided. + - parameter from: The current date difference from. + - Returns: The number of years difference from this date object and the date object provided as Int + */ func years(from date: Date) -> Int { return Calendar.current.dateComponents([.year], from: date, to: self).year ?? 0 } - /// Returns the amount of months from another date + + /** + Calculates the months between the current date and the date provided. + - parameter from: The current date difference from. + - Returns: The number of months difference from this date object and the date object provided as Int + */ func months(from date: Date) -> Int { return Calendar.current.dateComponents([.month], from: date, to: self).month ?? 0 } - /// Returns the amount of weeks from another date + + /** + Calculates the weeks between the current date and the date provided. + - parameter from: The current date difference from. + - Returns: The number of weeks difference from this date object and the date object provided as Int + */ func weeks(from date: Date) -> Int { return Calendar.current.dateComponents([.weekOfMonth], from: date, to: self).weekOfMonth ?? 0 } - /// Returns the amount of days from another date + + /** + Calculates the days between the current date and the date provided. + - parameter from: The current date difference from. + - Returns: The number of days difference from this date object and the date object provided as Int + */ func days(from date: Date) -> Int { return Calendar.current.dateComponents([.day], from: date, to: self).day ?? 0 } - /// Returns the amount of hours from another date + + /** + Calculates the hours between the current date and the date provided. + - parameter from: The current date difference from. + - Returns: The number of hours difference from this date object and the date object provided as Int + */ func hours(from date: Date) -> Int { return Calendar.current.dateComponents([.hour], from: date, to: self).hour ?? 0 } - /// Returns the amount of minutes from another date + + /** + Calculates the minutes between the current date and the date provided. + - parameter from: The current date difference from. + - Returns: The number of minutes difference from this date object and the date object provided as Int + */ func minutes(from date: Date) -> Int { return Calendar.current.dateComponents([.minute], from: date, to: self).minute ?? 0 } - /// Returns the amount of seconds from another date + + /** + Calculates the seconds between the current date and the date provided. + - parameter from: The current date difference from. + - Returns: The number of seconds difference from this date object and the date object provided as Int + */ func seconds(from date: Date) -> Int { return Calendar.current.dateComponents([.second], from: date, to: self).second ?? 0 } - /// Returns the amount of nanoseconds from another date + + /** + Calculates the nanoseconds between the current date and the date provided. + - parameter from: The current date difference from. + - Returns: The number of nanoseconds difference from this date object and the date object provided as Int + */ func nanoseconds(from date: Date) -> Int { return Calendar.current.dateComponents([.nanosecond], from: date, to: self).nanosecond ?? 0 } + /// Returns the a custom time interval description from another date func offset(from date: Date) -> String { if years(from: date) > 0 { return "\(years(from: date))y" } @@ -53,6 +94,12 @@ extension Date { if nanoseconds(from: date) > 0 { return "\(nanoseconds(from: date))ns" } return "" } + + /** + Turns the current date into a readable text using the provided format. + - parameter format: The date format which is wanted to be used. + - Returns: The current date object in a String form. + */ func toString(format: String) -> String { let formatter = DateFormatter() formatter.dateFormat = format diff --git a/LoanShark/Business Objects/LoanPeriod.swift b/LoanShark/Business Objects/Loan.swift similarity index 58% rename from LoanShark/Business Objects/LoanPeriod.swift rename to LoanShark/Business Objects/Loan.swift index 9479e3b..3c1ac2e 100644 --- a/LoanShark/Business Objects/LoanPeriod.swift +++ b/LoanShark/Business Objects/Loan.swift @@ -1,5 +1,5 @@ // -// LoanPeriod.swift +// Loan.swift // LoanShark // // Created by Tyler Morgan on 2/5/19. @@ -11,14 +11,19 @@ import Foundation /** Loan period object, this is used to determine the loaner period duration. */ -@objc class LoanPeriod: NSObject { +class Loan: NSObject { //MARK: Variables + + // The date which the loan started let start: Date + + // The date which the loan will expire let end: Date - @objc var remaining: Int { + // The remaining duration of the loan in days + var remaining: Int { get { return self.end.days(from: Date()) } @@ -26,6 +31,11 @@ import Foundation //MARK: Initializers + /** + - Parameters: + - startDate: The date which the loan will begin on. + - endDate: The date which the loan will expire on. + */ init (startDate start: Date, endDate end: Date) { self.start = start self.end = end diff --git a/LoanShark/Business Objects/LoanStatus.swift b/LoanShark/Business Objects/LoanStatus.swift new file mode 100644 index 0000000..be24a1f --- /dev/null +++ b/LoanShark/Business Objects/LoanStatus.swift @@ -0,0 +1,20 @@ +// +// LoanStatus.swift +// LoanShark +// +// Created by Tyler Morgan on 12/24/19. +// Copyright © 2019 Tyler Morgan. All rights reserved. +// + +import Foundation + +/** + Status for a loan period with a raw string value. + */ +enum LoanStatus: String { + case active = "Active" + case warning = "Warning" + case critical = "Critical" + case expired = "Expired" + case notSet = "Not Set" +} diff --git a/LoanShark/Business Objects/NotificationName_Extension.swift b/LoanShark/Business Objects/NotificationName_Extension.swift deleted file mode 100644 index 4b7a776..0000000 --- a/LoanShark/Business Objects/NotificationName_Extension.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// NotificationName_Extension.swift -// LoanShark -// -// Created by Tyler Morgan on 2/5/19. -// Copyright © 2019 Tyler Morgan. All rights reserved. -// - -import Foundation - -extension Notification.Name { - /// Notification for when loaner period is modified. - static let loanerPeriodChanged = Notification.Name(rawValue: "loanerPeriodChanged") - static let loanerPeriodSet = Notification.Name(rawValue: "loanerPeriodSet") - static let loanerPeriodExpired = Notification.Name(rawValue: "loanerPeriodExpired") -} diff --git a/LoanShark/Business Objects/Person.swift b/LoanShark/Business Objects/Person.swift index 5b09047..875da6d 100644 --- a/LoanShark/Business Objects/Person.swift +++ b/LoanShark/Business Objects/Person.swift @@ -10,11 +10,6 @@ import Foundation /** Object used while assigning device, and announcing who to contact. - parameters: - - first: First name of the person. - - last: Last name of the person. - - emailAddress: Email address of the person. - - phoneNumber: Preferred phone number of the person. */ class Person: NSObject, NSCoding { @@ -34,6 +29,13 @@ class Person: NSObject, NSCoding { } // MARK: Initializers + /** + - parameters: + - first: First name of the person. + - last: Last name of the person. + - emailAddress: Email address of the person. + - phoneNumber: Preferred phone number of the person. + */ init(first fname: String, last lname: String, emailAddress emailAddr: String, phoneNumber phNum: String) { self.first = fname self.last = lname diff --git a/LoanShark/Business Objects/Token.swift b/LoanShark/Business Objects/Token.swift index b345d3f..97f3308 100644 --- a/LoanShark/Business Objects/Token.swift +++ b/LoanShark/Business Objects/Token.swift @@ -11,21 +11,37 @@ import Foundation /** Token object for Jamf Pro API */ + class Token { // MARK: Enumerations enum TokenGenerationError: Error { case jsonParsingError(String) + case tokenExpired } // MARK: Variables - static var sharedInstance = Token() // Singleton + /** + Singleton + */ + static var sharedInstance = Token() + + /** + Token hash used to authenticate to the Jamf Pro API + */ + var token: String? - var token: String? // Token element for accessing Jamf Pro API + /** + When the token will expire in epoch + */ var expires: Double? // When the token will expire in Unix - var isExpired: Bool { // Checks if the token has expired + + /** + Checks if the token has expired + */ + var isExpired: Bool { get { let hoursRemaining = Date(timeIntervalSince1970: self.expires ?? 0.0).hours(from: Date()) if hoursRemaining >= 1 { @@ -36,13 +52,20 @@ class Token { } } } + + /** + The user who is authenticated. + */ var user: String? // User who is authenticated + // MARK: Functions + /** Sets the token object using the provided JSON. - parameters: - - json: JSON object provided in Dictionary format - throws: `TokenGenerationError.jsonParsingError` if the `json` parameter does not contain `token` element or `expires` element. + - parameters: + - json: JSON object provided in Dictionary format + - user: The user who is generating the token + - throws: An error of type TokenGenerationError.jsonParsingError if the json's parameter does not contain token element or expires element. */ func setToken(_ json: Dictionary , user: String) throws { guard let token = json["token"] as? String else { @@ -51,9 +74,9 @@ class Token { guard let expires = json["expires"] as? Double else { throw TokenGenerationError.jsonParsingError("Error while parsing expires field of json.") } + self.token = token self.expires = expires } - } diff --git a/LoanShark/Info.plist b/LoanShark/Info.plist index 58f2b91..9be353c 100644 --- a/LoanShark/Info.plist +++ b/LoanShark/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 0.3 CFBundleVersion - 231 + $(CURRENT_PROJECT_VERSION) LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) LSUIElement diff --git a/LoanShark/Menus/AgentMenu.swift b/LoanShark/Menus/AgentMenu.swift index 3a0764e..5af8167 100644 --- a/LoanShark/Menus/AgentMenu.swift +++ b/LoanShark/Menus/AgentMenu.swift @@ -10,10 +10,63 @@ import Cocoa class AgentMenu: NSMenu, NSUserNotificationCenterDelegate { - func startListening() { - Log.write(.debug, Log.Category.statusListener, "Listener has been started.") - //NotificationCenter.default.addObserver(self, selector: #selector(self.loanerPeriodDidChange(_:)), name: NSNotification.Name.loanerPeriodChanged, object: nil) - //NotificationCenter.default.addObserver(self, selector: #selector(self.loanerPeriodSet(_:)), name: NSNotification.Name.loanerPeriodSet, object: nil) - //NotificationCenter.default.addObserver(self, selector: #selector(self.loanerPeriodExpired(_:)), name: NSNotification.Name.loanerPeriodExpired, object: nil) + // MARK: Outlets + @IBOutlet weak var statusTitle: NSMenuItem! + @IBOutlet weak var remainingTitle: NSMenuItem! + @IBOutlet weak var requestTitle: NSMenuItem! + @IBOutlet weak var loaneeTitle: NSMenuItem! + @IBOutlet weak var loaneeMenu: NSMenu! + @IBOutlet weak var assignedUser: NSMenuItem! + @IBOutlet weak var assignedEmail: NSMenuItem! + @IBOutlet weak var assignedPhone: NSMenuItem! + @IBOutlet weak var techEmail: NSMenuItem! + @IBOutlet weak var techPhone: NSMenuItem! + @IBOutlet weak var techTitle: NSMenuItem! + @IBOutlet weak var techMenu: NSMenu! + @IBOutlet weak var adminMenu: NSMenu! + @IBOutlet weak var adminConfigure: NSMenuItem! + @IBOutlet weak var adminExtend: NSMenuItem! + @IBOutlet weak var debugMenu: NSMenuItem! + + // MARK: Functions + required init(coder: NSCoder) { + super.init(coder: coder) + LoanManager.sharedInstance.addCallback { + DispatchQueue.main.async { + + self.debugMenu.isHidden = !Preferences.sharedInstance.enableDebugging + + // Status + self.statusTitle.title = "Status: \(LoanManager.sharedInstance.loanStatus.rawValue)" + + // Loan period not set + if LoanManager.sharedInstance.loanPeriod == nil { + self.loaneeTitle.isHidden = true + self.techTitle.isHidden = true + self.remainingTitle.isHidden = true + self.requestTitle.isHidden = true + self.adminExtend.isHidden = true + self.adminConfigure.isHidden = false + } + // Loan period set + else { + + self.loaneeTitle.isHidden = false + self.techTitle.isHidden = false + self.remainingTitle.isHidden = false + self.requestTitle.isHidden = false + self.adminExtend.isHidden = false + self.adminConfigure.isHidden = true + + // Update Menu Text + self.remainingTitle.title = "Remaining: \(LoanManager.sharedInstance.loanPeriod?.remaining ?? 0)" + self.techEmail.title = LoanManager.sharedInstance.techEmail ?? "UNKNOWN" + self.techPhone.title = LoanManager.sharedInstance.techPhone ?? "UNKNOWN" + self.assignedUser.title = LoanManager.sharedInstance.loaneeName ?? "UNKNOWN" + self.assignedEmail.title = LoanManager.sharedInstance.loaneeEmail ?? "UNKNOWN" + self.assignedPhone.title = LoanManager.sharedInstance.loaneePhone ?? "UNKNOWN" + } + } + } } } diff --git a/LoanShark/Tools/ActivationAuthentication.swift b/LoanShark/Tools/ActivationAuthentication.swift index 77a17da..f9c539a 100644 --- a/LoanShark/Tools/ActivationAuthentication.swift +++ b/LoanShark/Tools/ActivationAuthentication.swift @@ -12,20 +12,16 @@ import Foundation Used to perform authentication against the Jamf Pro instance. */ class ActivationAuthentication { - /** - TODO: Use UAPI to grab LDAP groups the user is a part of, and grab from Preferences the groups authorized to administer the loaner. - /auth/current gets the Group IDs, but nothing else right now. - Asked #jss-api for help, waiting for response. - */ - // MARK: Variables private var accessGroups: Array ? + // MARK: Enumerations enum AuthenticationError: Error { case UnableToAuthenticate(String) case NoAccessGroups case NoSharedSecretStored + case UserDoesNotExist(String) } // MARK: Functions @@ -33,7 +29,6 @@ class ActivationAuthentication { /** Checks to see if the authenticated user has access to perform loaner management. - - Parameter user: The user who is being checked for permission as String. - returns: Bool */ func doesHaveAccess() throws -> Bool { @@ -129,6 +124,8 @@ class ActivationAuthentication { var authorized = false let task = URLSession.shared.dataTask(with: request) { data, response, error in guard let data = data, error == nil else { + authorized = false + running = false return } @@ -149,6 +146,12 @@ class ActivationAuthentication { running = false } } + else { + Log.write(.error, Log.Category.authenticator, "No response from web server.") + authorized = false + running = false + } + } task.resume() while running { @@ -157,6 +160,93 @@ class ActivationAuthentication { return authorized } + /** + Obtains information of the provided user using the Jamf Pro API + */ + func getUserDetails(user: String, apiUser: String, apiPassword: String) throws -> Person? { + Log.write(.info, Log.Category.authenticator, "Attempting to authenticate \(user) using the JPS") + + let host = try self.getURI() + Log.write(.debug, Log.Category.authenticator, "The server attempting to perform authentication to is \(host)") + + // Encodes login credentials to Base64 + let loginData = String(format: "%@:%@", apiUser, apiPassword).data(using: String.Encoding.utf8) + let base64LoginData = loginData?.base64EncodedString() + + // Creates the request + + let uri = host + "/JSSResource/users/name/\(user)" + + let url = URL(string: uri)! + var request = URLRequest(url: url) + request.httpMethod = "GET" + request.setValue("Basic \(base64LoginData!)", forHTTPHeaderField: "Authorization") + request.setValue("application/json", forHTTPHeaderField: "Accept") + + // Performs the request + var running = true + var userObj: Person? + let task = URLSession.shared.dataTask(with: request) { data, response, error in + guard let data = data, error == nil else { + running = false + return + } + + if let httpStatus = response as? HTTPURLResponse { + // Checks status code returned by the http server. + if httpStatus.statusCode == 200 { + Log.write(.info, Log.Category.authenticator, "\(user) has been successfully authenticated.") + do { + guard let jsonObj = try! JSONSerialization.jsonObject(with: data, options: []) as? [String:Any] else { + return + } + guard let userDetails = jsonObj["user"] as? [String:Any] else { + return + } + + guard let name = userDetails["full_name"] as? String else { + return + } + guard let email = userDetails["email"] as? String else { + return + } + guard let phone = userDetails["phone_number"] as? String else { + return + } + + var first = "" + var last = "" + if name.contains(",") { + first = String(name.split(separator: ",")[1]) + last = String(name.split(separator: ",")[0]) + } else { + first = String(name.split(separator: " ")[0]) + last = String(name.split(separator: " ")[1]) + } + + userObj = Person(first: first, last: last, emailAddress: email, phoneNumber: phone) + } + running = false + } + else { + Log.write(.error, Log.Category.authenticator, "Unable to authenticate \(user), recieved status code of \(httpStatus.statusCode)") + running = false + } + } + else { + Log.write(.error, Log.Category.authenticator, "No response from web server.") + running = false + } + + } + task.resume() + while running { + sleep(1) + } + + return userObj + } + /** Authenicates a user using a shared secret. - Parameters: @@ -170,7 +260,7 @@ class ActivationAuthentication { throw AuthenticationError.NoSharedSecretStored } Log.write(.debug, Log.Category.authenticator, "Hash provided: " + secret.sha256().uppercased()) - return sharedSecret == secret.sha256().uppercased() + return sharedSecret.uppercased() == secret.sha256().uppercased() } /** diff --git a/LoanShark/Tools/ArgumentParser.swift b/LoanShark/Tools/ArgumentParser.swift index 668f646..cbe50b8 100644 --- a/LoanShark/Tools/ArgumentParser.swift +++ b/LoanShark/Tools/ArgumentParser.swift @@ -17,6 +17,12 @@ enum ArgumentError: Error { case unsupportedArgument(String) } +struct Argument { + let name: String + let description: String + let isBool: Bool + let callback: ([String:String]) throws -> Void +} /** Parses the arguments passed to the application and stores those values and settings. */ @@ -116,6 +122,9 @@ class ArgumentParser { self.arguments.append(arg) } + /** + Prints the usage of the provided arguments. + */ private func printUsage() { for arg in self.arguments { print("\(arg.name ?? "") - \(arg.help ?? "")") diff --git a/LoanShark/Tools/LoanManager.swift b/LoanShark/Tools/LoanManager.swift index ef3f240..8b5258e 100644 --- a/LoanShark/Tools/LoanManager.swift +++ b/LoanShark/Tools/LoanManager.swift @@ -8,43 +8,28 @@ import Foundation -@objc class LoanManager: NSObject { +class LoanManager: NSObject { // MARK: Enumerations - - /** - Status of the loaner that the manager knows about. - */ - @objc enum Status: UInt { - case active, warning, critical, expired, notSet - func toString() -> String { - switch self { - case .active: - return "Active" - case .warning: - return "Warning" - case .critical: - return "Critical" - case .expired: - return "Expired" - case .notSet: - return "Not Set" - } - } - } - enum ExtensionError: Error { case LoanerPeriodIsNull } - - // MARK: Variables - + // MARK: Variables + private var callbacks: Array <()-> Void> = [] { + didSet { + if self.loanPeriod == nil { + for callback in self.callbacks { + callback() + } + } + } + } // Current status of the loaning period - @objc var loanStatus: Status { + var loanStatus: LoanStatus { get { Log.write(.info, Log.Category.loanManager, "Loan Status requested") /// Checks if a loan period has been set. @@ -69,16 +54,15 @@ import Foundation return .critical default: Log.write(.debug, Log.Category.loanManager, "Less than 0 days remaining on loaning period") - NotificationCenter.default.post(name: NSNotification.Name.loanerPeriodExpired, object: nil) return .expired } } } - @objc var loanee: Person? - @objc var tech: Person? + var loanee: Person? + var tech: Person? - @objc var loaneeName: String? { + var loaneeName: String? { get { guard let name = self.loanee?.name else { return nil @@ -87,7 +71,7 @@ import Foundation } } - @objc var loaneePhone: String? { + var loaneePhone: String? { get { guard let phone = self.loanee?.phoneNum else { return nil @@ -96,7 +80,7 @@ import Foundation } } - @objc var loaneeEmail: String? { + var loaneeEmail: String? { get { guard let email = self.loanee?.emailAddr else { return nil @@ -105,7 +89,7 @@ import Foundation } } - @objc var techEmail: String? { + var techEmail: String? { get { guard let email = self.tech?.emailAddr else { return nil @@ -114,7 +98,7 @@ import Foundation } } - @objc var techPhone: String? { + var techPhone: String? { get { guard let phone = self.tech?.phoneNum else { return nil @@ -123,7 +107,7 @@ import Foundation } } - @objc var loanPeriod: LoanPeriod? { + var loanPeriod: Loan? { willSet { self.willChangeValue(forKey: "loanPeriod") self.willChangeValue(forKey: "loanStatus") @@ -136,12 +120,52 @@ import Foundation static let sharedInstance = LoanManager() + // MARK: Functions + + override init() { + super.init() + self.startListener() + } - - // MARK: Functions - + /** + Add a function that will be called upon when the loan period is set, changed, or otherwise modified. + - parameter callback: Function that will be called upon + */ + func addCallback(_ callback: @escaping ()-> Void) { + self.callbacks.append(callback) + } + /** + Starts the loan period listener for changes to the loan period. + */ + private func startListener() { + // Start listening for loan period change + DispatchQueue.global(qos: .background).async { + + /// Previous loan period value + var previousLoanPeriod = self.loanPeriod + var delay = 1 + while true { + sleep(UInt32(delay)) + if previousLoanPeriod != self.loanPeriod { + if previousLoanPeriod == nil { + previousLoanPeriod = self.loanPeriod + + // Set delay to 30 minutes + delay = 1800 + for callback in self.callbacks { + callback() + } + } else if previousLoanPeriod?.remaining != self.loanPeriod?.remaining { + for callback in self.callbacks { + callback() + } + } + } + } + } + } /** Sets the period of the loaner. - Parameter length: How long the loaner period will be as Int @@ -161,12 +185,9 @@ import Foundation Log.write(.debug, Log.Category.loanManager, "Calculated an end date of " + String(describing: endDate)) Preferences.sharedInstance.endDate = endDate - self.loanPeriod = LoanPeriod(startDate: currentDate, endDate: endDate) + self.loanPeriod = Loan(startDate: currentDate, endDate: endDate) Log.write(.info, Log.Category.loanManager, "Successfully set loaning period ending on " + String(describing: endDate)) Log.write(.debug, Log.Category.loanManager, "Alerting whole application loaner period has been set.") - DispatchQueue.main.async { - NotificationCenter.default.post(name: NSNotification.Name.loanerPeriodSet, object: nil) - } } /** @@ -249,43 +270,10 @@ import Foundation guard let endDate = Calendar.current.date(byAdding: .day, value: totalDays, to: Date()) else { return } - let newPeriod = LoanPeriod(startDate: period.start, endDate: endDate) + let newPeriod = Loan(startDate: period.start, endDate: endDate) Preferences.sharedInstance.endDate = endDate self.loanPeriod = newPeriod - - DispatchQueue.main.async { - NotificationCenter.default.post(name: NSNotification.Name.loanerPeriodChanged, object: nil) - } - } - - /** - Checks every 30 minutes for a period change. - */ - func checkPeriod(_ previousValue: Int) -> Int { - Log.write(.debug, Log.Category.loanManager, "Checking period using previous value of \(previousValue.description)") - if previousValue != self.loanPeriod?.remaining ?? 0 { - DispatchQueue.main.async { - NotificationCenter.default.post(name: NSNotification.Name.loanerPeriodChanged, object: nil) - } - return self.loanPeriod?.remaining ?? 0 - } - else { - return previousValue - } - } - - /** - Starts checking the loaning period remaining and alerts the application of a change. - */ - func startPeriodChecker() { - DispatchQueue.global(qos: .background).async { - var currentRemaining = 0 - while true { - currentRemaining = self.checkPeriod(currentRemaining) - sleep(6000) - } - } } /** @@ -300,10 +288,6 @@ import Foundation let newDate = Calendar.current.date(byAdding: .day, value: -30, to: currDate) Preferences.sharedInstance.endDate = newDate - - DispatchQueue.main.async { - NotificationCenter.default.post(name: NSNotification.Name.loanerPeriodExpired, object: nil) - } } } } diff --git a/LoanShark/Tools/LoginWindow.swift b/LoanShark/Tools/LoginWindow.swift index 0c6aded..c25bd67 100644 --- a/LoanShark/Tools/LoginWindow.swift +++ b/LoanShark/Tools/LoginWindow.swift @@ -8,10 +8,16 @@ import Foundation +/** + Handles the AppleEvents for the LoginWindow actions. + */ class LoginWindow { // MARK: Functions + /** + Logs off the current user using an AppleEvent code. + */ static func logoff() { do { try self.sendEvent(eventCode: kAEReallyLogOut) diff --git a/LoanShark/Tools/Preferences.swift b/LoanShark/Tools/Preferences.swift index 36a4a98..faba02e 100644 --- a/LoanShark/Tools/Preferences.swift +++ b/LoanShark/Tools/Preferences.swift @@ -16,8 +16,10 @@ class Preferences { // MARK: Variables - static let sharedInstance = Preferences() // Singleton - internal let userDefaults: UserDefaults + /// Singleton + static let sharedInstance = Preferences() + + private let userDefaults: UserDefaults public var startDate: Date? { get { @@ -84,24 +86,6 @@ class Preferences { } } - public var runScriptOnChange: String? { - get { - return self.userDefaults.string(forKey: "scriptOnChange") - } - } - - public var runScriptOnSet: String? { - get { - return self.userDefaults.string(forKey: "scriptOnSet") - } - } - - public var runScriptOnExpire: String? { - get { - return self.userDefaults.string(forKey: "scriptOnExpire") - } - } - public var logoffTimer: Int { get { let timerValue = self.userDefaults.integer(forKey: "logoffTimer") @@ -162,6 +146,12 @@ class Preferences { } } + public var useGmail: Bool { + get { + return self.userDefaults.bool(forKey:"useGmail") + } + } + //MARK: Initializers init(nsUserDefaults: UserDefaults = UserDefaults.standard) { diff --git a/LoanShark/Tools/RemainingTransformer.swift b/LoanShark/Tools/RemainingTransformer.swift deleted file mode 100644 index 682d888..0000000 --- a/LoanShark/Tools/RemainingTransformer.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// RemainingTransformer.swift -// LoanShark -// -// Created by Tyler Morgan on 2/19/19. -// Copyright © 2019 Tyler Morgan. All rights reserved. -// - -import Cocoa - -class RemainingTransformer: ValueTransformer { - class func transformedValueClass(_ value: Any?) -> Any? { - return String.self - } - - override class func allowsReverseTransformation() -> Bool { - return false - } - - override func transformedValue(_ value: Any?) -> Any? { - return "Remaining: \(String(describing: value ?? 0))" - } -} - -extension NSValueTransformerName { - static let remainingTransformer = NSValueTransformerName(rawValue: "RemainingTransformer") -} diff --git a/LoanShark/Tools/StatusTransformer.swift b/LoanShark/Tools/StatusTransformer.swift deleted file mode 100644 index 8a1ecaa..0000000 --- a/LoanShark/Tools/StatusTransformer.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// StatusTransformer.swift -// LoanShark -// -// Created by Tyler Morgan on 2/14/19. -// Copyright © 2019 Tyler Morgan. All rights reserved. -// - -import Cocoa - -class StatusTransformer: ValueTransformer { - class func transformedValueClass(_ value: Any?) -> Any? { - return String.self - } - - override class func allowsReverseTransformation() -> Bool { - return false - } - - override func transformedValue(_ value: Any?) -> Any? { - if let statusInt = value as? UInt { - let status = LoanManager.Status.init(rawValue: statusInt) - return "Status: \(status!.toString())" - } else { - return "Status: Not Set" - } - } -} - -extension NSValueTransformerName { - static let statusTransformer = NSValueTransformerName(rawValue: "StatusTransformer") -} diff --git a/LoanShark/Tools/String_Extension.swift b/LoanShark/Tools/String_Extension.swift index 27d6bc4..72287b0 100644 --- a/LoanShark/Tools/String_Extension.swift +++ b/LoanShark/Tools/String_Extension.swift @@ -11,6 +11,10 @@ import CommonCrypto extension String { + /** + Convert current string to a SHA256 hash. + - returns: SHA256 hash as String + */ func sha256() -> String{ if let stringData = self.data(using: String.Encoding.utf8) { return hexStringFromData(input: digest(input: stringData as NSData)) diff --git a/LoanShark/Tools/TimerTransformer.swift b/LoanShark/Tools/TimerTransformer.swift deleted file mode 100644 index 14fb882..0000000 --- a/LoanShark/Tools/TimerTransformer.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// TimerTransformer.swift -// LoanShark -// -// Created by Tyler Morgan on 2/5/19. -// Copyright © 2019 Tyler Morgan. All rights reserved. -// - -import Cocoa - -class TimerTransformer: ValueTransformer { - class func transformedValueClass(_ value: Any?) -> Any? { - return String.self - } - - override class func allowsReverseTransformation() -> Bool { - return false - } - - override func transformedValue(_ value: Any?) -> Any? { - let timer = value as! String - let timerValue = Int(timer) ?? 0 - let hours = timerValue / 60 - let minutes = timerValue - (60 * hours) - if minutes < 10 { - return String(describing: hours) + ":0" + String(describing: minutes) - } - else { - return String(describing: hours) + ":" + String(describing: minutes) - } - } -} - -extension NSValueTransformerName { - static let timerTransformer = NSValueTransformerName(rawValue: "TimerTransformer") -} diff --git a/LoanShark/ViewController.swift b/LoanShark/ViewController.swift deleted file mode 100644 index 942d6cd..0000000 --- a/LoanShark/ViewController.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// ViewController.swift -// LoanShark -// -// Created by Tyler Morgan on 2/5/19. -// Copyright © 2019 Tyler Morgan. All rights reserved. -// - -import Cocoa - -class ViewController: NSViewController { - - override func viewDidLoad() { - super.viewDidLoad() - - // Do any additional setup after loading the view. - NotificationCenter.default.post(name: NSNotification.Name.loanerPeriodSet, object: nil) - } - - override var representedObject: Any? { - didSet { - // Update the view, if already loaded. - } - } - - -} - diff --git a/LoanShark/Views/AuthenticationViewController.swift b/LoanShark/Views/AuthenticationViewController.swift index e431456..e7907b9 100644 --- a/LoanShark/Views/AuthenticationViewController.swift +++ b/LoanShark/Views/AuthenticationViewController.swift @@ -10,42 +10,17 @@ import Cocoa class AuthenticationViewController: NSViewController { - // MARK: Cocoa Binding Resources - @objc var username: String? { - didSet { - self.checkRequirements() - } - } - @objc var password: String? { - didSet { - self.checkRequirements() - } - } - @objc var performingAuthorization: Bool = false { - willSet { - self.willChangeValue(forKey: "performingAuthorization") - } - didSet { - self.didChangeValue(forKey: "performingAuthorization") - } - } - - @objc var requirementsCompleted: Bool = false + // MARK: Outlets + @IBOutlet weak var usernameField: NSTextField! + @IBOutlet weak var passwordField: NSTextField! + @IBOutlet weak var passphraseField: NSTextField! + @IBOutlet weak var errorMessage: NSTextField! + @IBOutlet weak var jamfAuthView: NSView! + @IBOutlet weak var passphraseView: NSView! + @IBOutlet weak var authenticateButton: NSButton! + @IBOutlet weak var authenticationIndicator: NSProgressIndicator! - @objc var errorMessage: String? { - willSet { - self.willChangeValue(forKey: "errorMessage") - } - didSet { - self.didChangeValue(forKey: "errorMessage") - } - } - @objc var sharedSecret: String? { - didSet { - self.checkRequirements() - } - } - @objc var isSharedSecretEnabled: Bool { + var isSharedSecretEnabled: Bool { guard let _ = Preferences.sharedInstance.sharedSecret else { return false } @@ -60,6 +35,8 @@ class AuthenticationViewController: NSViewController { // MARK: Variables public var destination: String? + private var authenticator: ActivationAuthentication? + private var userObj: Person? // MARK: Functions @@ -67,11 +44,44 @@ class AuthenticationViewController: NSViewController { override func viewDidLoad() { super.viewDidLoad() // Do view setup here. + + if Preferences.sharedInstance.sharedSecretAuth { + self.jamfAuthView.isHidden = true + self.passphraseView.isHidden = false + } else { + self.jamfAuthView.isHidden = false + self.passphraseView.isHidden = true + } + } + + private func setEnabled(to enabled: Bool) { + + self.authenticationIndicator.isHidden = enabled + self.authenticationIndicator.startAnimation(self) + let jamfViews: Array = [ + self.usernameField, + self.passwordField + ] + + let passphraseViews: Array = [ + self.passphraseField + ] + + if Preferences.sharedInstance.sharedSecretAuth { + for view in passphraseViews { + view.isEnabled = enabled + } + } else { + for view in jamfViews { + view.isEnabled = enabled + } + } } @IBAction func performAuthorization(_ sender: NSButton) { DispatchQueue.main.async { - self.performingAuthorization = true + sender.isEnabled = false + self.setEnabled(to: false) } if self.isSharedSecretEnabled { @@ -79,23 +89,27 @@ class AuthenticationViewController: NSViewController { // Shared Secret Authentication Process let authenticator = ActivationAuthentication() do { - if try authenticator.authenticate(secret: self.sharedSecret ?? "") { + if try authenticator.authenticate(secret: self.passphraseField.stringValue) { DispatchQueue.main.async { self.performTransition() } } else { DispatchQueue.main.async { - self.errorMessage = "Sorry, you entered an invalid password." - self.performingAuthorization = false + self.errorMessage.stringValue = "Sorry, you entered an invalid password." + self.errorMessage.isHidden = false + sender.isEnabled = true + self.setEnabled(to: true) } } } catch ActivationAuthentication.AuthenticationError.NoSharedSecretStored { Log.write(.error, Log.Category.view, "No shared secret is stored.") DispatchQueue.main.async { - self.errorMessage = "There is no shared secret stored." - self.performingAuthorization = false + self.errorMessage.stringValue = "There is no shared secret stored." + self.errorMessage.isHidden = false + self.setEnabled(to: true) + sender.isEnabled = true } } catch { @@ -107,34 +121,59 @@ class AuthenticationViewController: NSViewController { DispatchQueue.global(qos: .userInitiated).async { // Jamf Pro API Authentication Method let authenticator = ActivationAuthentication() + var username = "" + var password = "" + DispatchQueue.main.sync { + username = self.usernameField.stringValue + password = self.passwordField.stringValue + } do { - - if try authenticator.authenticate(self.username ?? "", self.password ?? "") { + if try authenticator.authenticate(username, password) { let access = try authenticator.doesHaveAccess() if access { DispatchQueue.main.async { - self.performTransition() + Log.write(.debug, Log.Category.authenticator, "Attempting to perform transition.") + self.authenticator = authenticator + DispatchQueue.global(qos: .userInitiated).async { + do { + let results = try authenticator.getUserDetails(user: username, apiUser: username, apiPassword: password) + self.userObj = results + DispatchQueue.main.async { + self.performTransition() + } + } + catch { + DispatchQueue.main.async { + self.performTransition() + } + } + } } } else { DispatchQueue.main.async { - self.errorMessage = "Sorry, you do not have access to perform this action!" - self.performingAuthorization = false + self.errorMessage.stringValue = "Sorry, you do not have access to perform this action!" + self.errorMessage.isHidden = false + self.setEnabled(to: true) } } } else { DispatchQueue.main.async { - self.errorMessage = "Unable to authenticate \(self.username ?? ""), invalid username or password." - self.performingAuthorization = false + self.errorMessage.stringValue = "Unable to authenticate \(self.usernameField.stringValue), invalid username or password." + self.errorMessage.isHidden = false + self.setEnabled(to: true) + sender.isEnabled = true } } } catch ActivationAuthentication.AuthenticationError.UnableToAuthenticate(let message) { Log.write(.error, Log.Category.view, "Recieved \(message) from authentication attempt.") DispatchQueue.main.async { - self.errorMessage = message - self.performingAuthorization = false + self.errorMessage.stringValue = message + self.errorMessage.isHidden = false + sender.isEnabled = true + self.setEnabled(to: true) } } catch { @@ -148,28 +187,18 @@ class AuthenticationViewController: NSViewController { if self.isSharedSecretEnabled { // Non-Jamf Pro authentication check - if self.sharedSecret?.isEmpty ?? true { - self.willChangeValue(forKey: "requirementsCompleted") - self.requirementsCompleted = false - self.didChangeValue(forKey: "requirementsCompleted") - } - else { - self.willChangeValue(forKey: "requirementsCompleted") - self.requirementsCompleted = true - self.didChangeValue(forKey: "requirementsCompleted") + if !self.passphraseField.stringValue.isEmpty { + self.authenticateButton.isEnabled = true + } else { + self.authenticateButton.isEnabled = false } } else { // Jamf Pro authentication check - if self.username?.isEmpty ?? true || self.password?.isEmpty ?? true { - self.willChangeValue(forKey: "requirementsCompleted") - self.requirementsCompleted = false - self.didChangeValue(forKey: "requirementsCompleted") - } - else { - self.willChangeValue(forKey: "requirementsCompleted") - self.requirementsCompleted = true - self.didChangeValue(forKey: "requirementsCompleted") + if !self.usernameField.stringValue.isEmpty && !self.passwordField.stringValue.isEmpty { + self.authenticateButton.isEnabled = true + } else { + self.authenticateButton.isEnabled = false } } } @@ -187,4 +216,18 @@ class AuthenticationViewController: NSViewController { } } + override func prepare(for segue: NSStoryboardSegue, sender: Any?) { + if let userObj = self.userObj { + + if let dest = self.destination { + if dest == "configure" { + let destWC = segue.destinationController as! NSWindowController + (destWC.window?.contentViewController as! LoanerConfigurationViewController).userObj = userObj + } + } + } + + super.prepare(for: segue, sender: sender) + } + } diff --git a/LoanShark/Views/ExtensionRequestViewController.swift b/LoanShark/Views/ExtensionRequestViewController.swift index b134ec6..9e8127b 100644 --- a/LoanShark/Views/ExtensionRequestViewController.swift +++ b/LoanShark/Views/ExtensionRequestViewController.swift @@ -13,52 +13,60 @@ class ExtensionRequestViewController: NSViewController { // MARK: IBOutlets @IBOutlet weak var requestOptions: NSPopUpButton! - - /// Options for the user to select. - @objc var options = Preferences.sharedInstance.extensionOptions ?? ["None Set"] - @objc var justification: String? - - @objc var errMsg: String? { - willSet { - self.willChangeValue(forKey: "errMsg") - } - didSet { - self.didChangeValue(forKey: "errMsg") - } - } + @IBOutlet weak var justificationField: NSTextField! + @IBOutlet weak var requestButton: NSButton! + @IBOutlet weak var errorMessage: NSTextField! override func viewDidLoad() { super.viewDidLoad() + self.requestOptions.removeAllItems() + guard let options = Preferences.sharedInstance.extensionOptions else { + self.requestOptions.addItem(withTitle: "Not Set") + return + } + + self.requestOptions.addItems(withTitles: options) + // Do view setup here. } @IBAction func sendRequest(_ sender: NSButton) { - guard let justification = self.justification else { - self.errMsg = "Justification not provided." - return - } + let justification = self.justificationField.stringValue if justification.lengthOfBytes(using: .utf8) < 10 { - self.errMsg = "Justification is not valid, please enter a valid justification." + self.errorMessage.stringValue = "Justification is not valid, please enter a valid justification." + self.errorMessage.isHidden = false return } - let body = "Extension request is being made of \(self.requestOptions.titleOfSelectedItem ?? "UNKNOWN")" - let shareItems = [body] - - let service = NSSharingService(named: .composeEmail) - - guard let recipient = LoanManager.sharedInstance.tech?.emailAddr else { - self.errMsg = "Tech information is not set, unable to find who to request extension from." - return + if Preferences.sharedInstance.useGmail { + + let urlString = "https://mail.google.com/mail/u/0/?view=cm&fs=1&to=\(String(describing: LoanManager.sharedInstance.techEmail))&su=\("Extension Request - Current End Date of \(LoanManager.sharedInstance.loanPeriod?.end.toString(format: "MM/dd/yyyy") ?? "UNKNOWN")")&body=\("Extension request is being made of \(self.requestOptions.titleOfSelectedItem ?? "UNKNOWN")\n With justification of \(justification)")" + let url = URL(string: urlString) + NSWorkspace.shared.open(url!) + + self.view.window?.close() + } + else { + let body = "Extension request is being made of \(self.requestOptions.titleOfSelectedItem ?? "UNKNOWN")\n With justification of \(justification)" + let shareItems = [body] + + let service = NSSharingService(named: .composeEmail) + + + guard let recipient = LoanManager.sharedInstance.tech?.emailAddr else { + self.errorMessage.stringValue = "Tech information is not set, unable to find who to request extension from." + self.errorMessage.isHidden = false + return + } + + service?.recipients = [recipient] + service?.subject = "Extension Request - Current End Date of \(LoanManager.sharedInstance.loanPeriod?.end.toString(format: "MM/dd/yyyy") ?? "UNKNOWN")" + service?.perform(withItems: shareItems) + + self.view.window?.close() } - - service?.recipients = [recipient] - service?.subject = "Extension Request - Current End Date of \(LoanManager.sharedInstance.loanPeriod?.end.toString(format: "MM/dd/yyyy") ?? "UNKNOWN")" - service?.perform(withItems: shareItems) - - self.view.window?.close() } } diff --git a/LoanShark/Views/ExtensionViewController.swift b/LoanShark/Views/ExtensionViewController.swift index e8b75b2..dc80ec5 100644 --- a/LoanShark/Views/ExtensionViewController.swift +++ b/LoanShark/Views/ExtensionViewController.swift @@ -10,73 +10,60 @@ import Cocoa class ExtensionViewController: NSViewController { - @objc var extensionAmount: NSNumber? { - didSet { - self.checkRequirements() - } - } - @objc var extenderEmailAddr: String? { - didSet { - self.checkRequirements() - } - } - - @objc var requirementsMet: Bool = false { - willSet { - self.willChangeValue(forKey: "requirementsMet") - } - didSet { - self.didChangeValue(forKey: "requirementsMet") - } - } - - @objc var errMsg: String? { - willSet { - self.willChangeValue(forKey: "errMsg") - } - didSet { - self.didChangeValue(forKey: "errMsg") - } - } + // MARK: Outlets + @IBOutlet weak var extensionAmount: NSTextField! + @IBOutlet weak var extensionUser: NSTextField! + @IBOutlet weak var errorMessage: NSTextField! + @IBOutlet weak var extensionButton: NSButton! // MARK: Functions override func viewDidLoad() { super.viewDidLoad() + DispatchQueue.global(qos: .background).async { + while true { + DispatchQueue.main.async { + self.checkRequirements() + } + sleep(1) + } + } // Do view setup here. } private func checkRequirements() { - if self.extensionAmount == 0 || self.extensionAmount == nil || self.extenderEmailAddr?.isEmpty ?? true{ - self.requirementsMet = false + if self.extensionAmount.integerValue == 0 || self.extensionUser.stringValue.isEmpty { + self.extensionButton.isEnabled = false } else { - self.requirementsMet = true + self.extensionButton.isEnabled = true } } // MARK: IB Actions @IBAction func extend(_ sender: NSButton) { - guard let extendAmount = self.extensionAmount else { - self.errMsg = "Extension period is null." - return - } - - guard let extend = Int(exactly: extendAmount) else { - self.errMsg = "Error while converting extension." - return - } + sender.isEnabled = false + let extend = self.extensionAmount.integerValue if extend < 0 { - self.errMsg = "Extension amount is in the negative, must be positive." + self.errorMessage.stringValue = "Extension amount is in the negative, must be positive." + self.errorMessage.isHidden = false + sender.isEnabled = true + return + } else if extend == 0 { + self.errorMessage.stringValue = "Extension amount must be greater than 0." + self.errorMessage.isHidden = false + sender.isEnabled = true return } do { try LoanManager.sharedInstance.extend(extensionOf: extend) self.view.window?.close() } catch { - self.errMsg = "Error was thrown" + self.errorMessage.stringValue = "Error was thrown" + self.errorMessage.isHidden = false + sender.isEnabled = false return } } diff --git a/LoanShark/Views/LoanerConfigurationViewController.swift b/LoanShark/Views/LoanerConfigurationViewController.swift index bfdec83..ba49d13 100644 --- a/LoanShark/Views/LoanerConfigurationViewController.swift +++ b/LoanShark/Views/LoanerConfigurationViewController.swift @@ -10,72 +10,75 @@ import Cocoa class LoanerConfigurationViewController: NSViewController { - // MARK: Cocoa Binding Resources - @objc var userFirst: String? { - didSet { - self.checkRequirements() - } - } - @objc var userLast: String? { - didSet { - self.checkRequirements() - } - } - @objc var userPhone: String? { - didSet { - self.checkRequirements() - } - } - @objc var userEmail: String? { - didSet { - self.checkRequirements() - } - } - - @objc var techFirst: String? { - didSet { - self.checkRequirements() - } - } - @objc var techLast: String? { - didSet { - self.checkRequirements() - } - } - @objc var techPhone: String? { - didSet { - self.checkRequirements() - } - } - @objc var techEmail: String? { - didSet { - self.checkRequirements() - } - } + // MARK: Outlets + @IBOutlet weak var periodLength: NSTextField! + @IBOutlet weak var userFirst: NSTextField! + @IBOutlet weak var userLast: NSTextField! + @IBOutlet weak var userPhone: NSTextField! + @IBOutlet weak var userEmail: NSTextField! + @IBOutlet weak var techFirst: NSTextField! + @IBOutlet weak var techLast: NSTextField! + @IBOutlet weak var techPhone: NSTextField! + @IBOutlet weak var techEmail: NSTextField! + @IBOutlet weak var assignButton: NSButton! + @IBOutlet weak var lengthModifier: NSPopUpButton! - @objc var loanPeriod: NSNumber? { + // MARK: Variables + public var userObj: Person? { didSet { - self.checkRequirements() + guard let user = self.userObj else { + Log.write(.error, Log.Category.view, "User object not assigned!") + return + } + + self.techFirst.stringValue = user.first + self.techLast.stringValue = user.last + self.techEmail.stringValue = user.emailAddr + self.techPhone.stringValue = user.phoneNum } } - @objc var requiredCompleted: Bool = false - - override func viewDidLoad() { super.viewDidLoad() + // Do view setup here. + DispatchQueue.global(qos: .background).async { + while true { + DispatchQueue.main.async { + self.checkRequirements() + } + sleep(1) + } + } } @IBAction func assignDevice(_ sender: NSButton) { Log.write(.debug, Log.Category.view, "Recieved request to configure loaner") - let loanee = Person(first: self.userFirst ?? "", last: self.userLast ?? "", emailAddress: self.userEmail ?? "", phoneNumber: self.userPhone ?? "") - let tech = Person(first: self.techFirst ?? "", last: self.techLast ?? "", emailAddress: self.techEmail ?? "", phoneNumber: self.techPhone ?? "") + let loanee = Person(first: self.userFirst.stringValue, + last: self.userLast.stringValue, + emailAddress: self.userEmail.stringValue, + phoneNumber: self.userPhone.stringValue) + + let tech = Person(first: self.techFirst.stringValue, + last: self.techLast.stringValue, + emailAddress: self.techEmail.stringValue, + phoneNumber: self.techPhone.stringValue) - Log.write(.info, Log.Category.view, "Requested to provide loanee of " + loanee.description + " a loaner period of " + String(describing: self.loanPeriod) + " assigned by " + tech.description) + Log.write(.info, Log.Category.view, "Requested to provide loanee of " + loanee.description + " a loaner period of " + String(describing: self.periodLength.intValue) + " assigned by " + tech.description) LoanManager.sharedInstance.setLoanee(loanee) LoanManager.sharedInstance.setTech(tech) - LoanManager.sharedInstance.setPeriod(Int(truncating: self.loanPeriod ?? 0)) + var length = self.periodLength.integerValue + switch self.lengthModifier.titleOfSelectedItem { + case "Day(s)": + break + case "Week(s)": + length *= 7 + case "Month(s)": + length *= 30 + default: + break + } + LoanManager.sharedInstance.setPeriod(length) self.view.window?.close() } @@ -84,30 +87,18 @@ class LoanerConfigurationViewController: NSViewController { Checks to see if all the required items are filled and not empty and sets the `requiredCompleted` to true */ private func checkRequirements() { - if ( - self.userFirst?.isEmpty ?? true || - self.userLast?.isEmpty ?? true || - self.userPhone?.isEmpty ?? true || - self.userEmail?.isEmpty ?? true || - self.techFirst?.isEmpty ?? true || - self.techLast?.isEmpty ?? true || - self.techPhone?.isEmpty ?? true || - self.techEmail?.isEmpty ?? true || - self.loanPeriod == nil - ) - { - DispatchQueue.main.async { - self.willChangeValue(forKey: "requiredCompleted") - self.requiredCompleted = false - self.didChangeValue(forKey: "requiredCompleted") - } - } - else { - DispatchQueue.main.async { - self.willChangeValue(forKey: "requiredCompleted") - self.requiredCompleted = true - self.didChangeValue(forKey: "requiredCompleted") - } + if (self.techPhone.stringValue.isEmpty || + self.techFirst.stringValue.isEmpty || + self.techLast.stringValue.isEmpty || + self.techEmail.stringValue.isEmpty || + self.userFirst.stringValue.isEmpty || + self.userLast.stringValue.isEmpty || + self.userEmail.stringValue.isEmpty || + self.userPhone.stringValue.isEmpty || + self.periodLength.integerValue == 0) { + self.assignButton.isEnabled = false + } else { + self.assignButton.isEnabled = true } } diff --git a/LoanShark/Views/LoanerExpiredViewController.swift b/LoanShark/Views/LoanerExpiredViewController.swift index 80afc48..4524422 100644 --- a/LoanShark/Views/LoanerExpiredViewController.swift +++ b/LoanShark/Views/LoanerExpiredViewController.swift @@ -10,66 +10,35 @@ import Cocoa class LoanerExpiredViewController: NSViewController { + // MARK: Outlets + @IBOutlet weak var message: NSTextField! + @IBOutlet weak var timerText: NSTextField! + @IBOutlet weak var contactName: NSTextField! + @IBOutlet weak var contactPhone: NSTextField! + @IBOutlet weak var contactEmail: NSTextField! - // MARK: Variables - - /** - The timer value from preferences - */ - var timer = Preferences.sharedInstance.logoffTimer { - willSet { - self.willChangeValue(forKey: "timerString") - } + // MARK: Variables + private var timer = Preferences.sharedInstance.logoffTimer { didSet { - self.didChangeValue(forKey: "timerString") - } - } - - // MARK: Cocoa Binding Resources - - - /** - String that the UI uses to display to the user. - */ - @objc var timerString: String { - get { - return String(describing: self.timer) - } - } - - /** - The contact's full name pulled from the Preferences class. - */ - @objc var contactName: String? { - get { - return Preferences.sharedInstance.contactDetails?.name - } - } - - /** - The contact's phone number pulled from the Preferences class. - */ - @objc var contactPhone: String? { - get { - return Preferences.sharedInstance.contactDetails?.phoneNum - } - } - - /** - The contact's email address pulled from the Preferences class. - */ - @objc var contactEmail: String? { - get { - return Preferences.sharedInstance.contactDetails?.emailAddr - } - } - - /** - The lockout message that is displayed to the end user. This is pulled from the Preferences class. - */ - @objc var lockoutMessage: String? { - get { - return Preferences.sharedInstance.lockoutMessage + // Minutes + let minutes = floor(Double(self.timer) / Double(60)) + let seconds = (self.timer - Int(minutes) * 60) + + var timerString = "" + if minutes >= 10 { + timerString = "\(String(minutes))" + } else { + timerString = "0\(String(minutes)):" + } + + if seconds >= 10 { + timerString += String(seconds) + } else { + timerString += "0\(String(seconds))" + } + DispatchQueue.main.async { + self.timerText.stringValue = timerString + } } } @@ -81,6 +50,10 @@ class LoanerExpiredViewController: NSViewController { override func viewDidLoad() { super.viewDidLoad() // Do view setup here. + self.message.stringValue = Preferences.sharedInstance.lockoutMessage ?? "Please return this loaned device." + self.contactName.stringValue = LoanManager.sharedInstance.tech?.name ?? "Not Set" + self.contactPhone.stringValue = LoanManager.sharedInstance.techPhone ?? "Not Set" + contactEmail.stringValue = LoanManager.sharedInstance.techEmail ?? "Not Set" self.startTimerCountdown() } @@ -101,12 +74,13 @@ class LoanerExpiredViewController: NSViewController { - Note: Runs in the background and updates timer on main thread. */ private func startTimerCountdown () { - DispatchQueue(label: "TimerCountdown", qos: DispatchQoS.userInitiated, attributes: DispatchQueue.Attributes.concurrent, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.workItem, target: nil).async { - while true { + DispatchQueue.global(qos: .userInitiated).async { + while self.timer > 0 { sleep(1) DispatchQueue.main.async { self.timer -= 1 - if self.timer <= 0 { + + if self.timer < 0 { Log.write(.info, Log.Category.application, "Logging user off") LoginWindow.logoff() } diff --git a/README.md b/README.md index b2cca9b..6995ad5 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ -![Swift 4.0](https://img.shields.io/static/v1.svg?label=Swift&message=4.0&color=green&logo=swift) +![Swift 5.0](https://img.shields.io/static/v1.svg?label=Swift&message=5.0&color=green&logo=swift) ![macOS 10.12](https://img.shields.io/static/v1.svg?label=macOS&message=10.12&color=green&logo=apple) ![macOS 10.13](https://img.shields.io/static/v1.svg?label=macOS&message=10.13&color=green&logo=apple) ![macOS 10.14](https://img.shields.io/static/v1.svg?label=macOS&message=10.14&color=green&logo=apple) -![macOS 10.15](https://img.shields.io/static/v1.svg?label=macOS&message=10.15&color=yellow&logo=apple) +![macOS 10.15](https://img.shields.io/static/v1.svg?label=macOS&message=10.15&color=green&logo=apple) ![macOS Dark Mode](https://img.shields.io/static/v1.svg?label=Dark%20Mode&message=enabled&color=green&logo=apple) [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) -![Current LoanShark Version](https://img.shields.io/static/v1.svg?label=version&message=0.3&color=lightgrey) +![Current LoanShark Version](https://img.shields.io/static/v1.svg?label=version&message=1.0&color=lightgrey) # LoanShark![LoanShark](https://user-images.githubusercontent.com/23121750/55338309-71916300-546e-11e9-8517-b3d5cbd4ffbd.png) LoanShark's goal is to provide a simple, yet effective management to your loaner fleet. diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..9718182 --- /dev/null +++ b/TODO.md @@ -0,0 +1,28 @@ +# Things To Do + +## Target Objects + +### Views + +### Models +- Person + - First Name + - Last Name + - Phone Number + - Email Address +- Token + - token + - expires + - isExpired + + +### Controllers +- JamfAPI + - authorize + - uses token to get details + - getInfo(ofUser: String) --> Person + + + +### Support Views +