Sfoglia il codice sorgente

Add app expiration display

Jon Fawcett 5 anni fa
parent
commit
ed11f4ab6a

+ 4 - 0
LoopFollow.xcodeproj/project.pbxproj

@@ -142,6 +142,7 @@
 		FC7CE58E248ABEF2001F83B8 /* alarm-notification.m4a in Resources */ = {isa = PBXBuildFile; fileRef = FC7CE58C248ABEF1001F83B8 /* alarm-notification.m4a */; };
 		FC7CE59C248D33A9001F83B8 /* dragbar.png in Resources */ = {isa = PBXBuildFile; fileRef = FC7CE59B248D33A9001F83B8 /* dragbar.png */; };
 		FC7CE59F248D8D23001F83B8 /* SnoozeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC7CE59E248D8D23001F83B8 /* SnoozeViewController.swift */; };
+		FC8589BF252B54F500C8FC73 /* Mobileprovision.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC8589BE252B54F500C8FC73 /* Mobileprovision.swift */; };
 		FC9788182485969B00A7906C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC9788172485969B00A7906C /* AppDelegate.swift */; };
 		FC97881A2485969B00A7906C /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC9788192485969B00A7906C /* SceneDelegate.swift */; };
 		FC97881C2485969B00A7906C /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC97881B2485969B00A7906C /* MainViewController.swift */; };
@@ -306,6 +307,7 @@
 		FC7CE58C248ABEF1001F83B8 /* alarm-notification.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = "alarm-notification.m4a"; sourceTree = "<group>"; };
 		FC7CE59B248D33A9001F83B8 /* dragbar.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = dragbar.png; sourceTree = "<group>"; };
 		FC7CE59E248D8D23001F83B8 /* SnoozeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SnoozeViewController.swift; sourceTree = "<group>"; };
+		FC8589BE252B54F500C8FC73 /* Mobileprovision.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mobileprovision.swift; sourceTree = "<group>"; };
 		FC8DEEE62485D1ED0075863F /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		FC9788142485969B00A7906C /* Loop Follow.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Loop Follow.app"; sourceTree = BUILT_PRODUCTS_DIR; };
 		FC9788172485969B00A7906C /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
@@ -597,6 +599,7 @@
 				FCEF87AA24A1417900AE6FA0 /* bgUnits.swift */,
 				FC1BDD2E24A232A3001B652C /* DataStructs.swift */,
 				FCD2A27C24C9D044009F7B7B /* Globals.swift */,
+				FC8589BE252B54F500C8FC73 /* Mobileprovision.swift */,
 			);
 			path = helpers;
 			sourceTree = "<group>";
@@ -870,6 +873,7 @@
 				FC1BDD3224A2585C001B652C /* DataStructs.swift in Sources */,
 				FCC6886524898EEE00A0279D /* UserDefaults.swift in Sources */,
 				FC16A97F249969E2003D6245 /* Graphs.swift in Sources */,
+				FC8589BF252B54F500C8FC73 /* Mobileprovision.swift in Sources */,
 				DD152D3B24C01B2300361FA2 /* InfoDisplaySettingsViewController.swift in Sources */,
 				DDCF979C24C14EFB002C9752 /* DebugSettingsViewController.swift in Sources */,
 				FC97881C2485969B00A7906C /* MainViewController.swift in Sources */,

+ 7 - 1
LoopFollow/ViewControllers/SettingsViewController.swift

@@ -41,7 +41,10 @@ class SettingsViewController: FormViewController {
             overrideUserInterfaceStyle = .dark
         }
     
-        
+        var expiration: Date = Date()
+        if let provision = MobileProvision.read() {
+            expiration = provision.expirationDate
+        }
                         
         form
         +++ Section(header: "Nightscout Settings", footer: "Changing Nightscout settings requires an app restart.")
@@ -185,9 +188,12 @@ class SettingsViewController: FormViewController {
             
         }
     
+            +++ Section(header: "App Expiration", footer: String(expiration.description))
+    
         showHideNSDetails()
       
     }
     
     
+
 }

+ 106 - 0
LoopFollow/helpers/Mobileprovision.swift

@@ -0,0 +1,106 @@
+//
+//  MobileProvision.swift
+//  Fluux.io
+//
+//  Created by Mickaël Rémond on 03/11/2018.
+//  Copyright © 2018 ProcessOne.
+//  Distributed under Apache License v2
+//
+import Foundation
+
+/* Decode mobileprovision plist file
+ Usage:
+ 
+ 1. To get mobileprovision data as embedded in your app:
+ MobileProvision.read()
+ 2. To get mobile provision data from a file on disk:
+ 
+ MobileProvision.read(from: "my.mobileprovision")
+ 
+*/
+
+struct MobileProvision: Decodable {
+    var name: String
+    var appIDName: String
+    var platform: [String]
+    var isXcodeManaged: Bool? = false
+    var creationDate: Date
+    var expirationDate: Date
+    var entitlements: Entitlements
+    
+    private enum CodingKeys : String, CodingKey {
+        case name = "Name"
+        case appIDName = "AppIDName"
+        case platform = "Platform"
+        case isXcodeManaged = "IsXcodeManaged"
+        case creationDate = "CreationDate"
+        case expirationDate = "ExpirationDate"
+        case entitlements = "Entitlements"
+    }
+    
+    // Sublevel: decode entitlements informations
+    struct Entitlements: Decodable {
+        let keychainAccessGroups: [String]
+        let getTaskAllow: Bool
+        let apsEnvironment: Environment
+        
+        private enum CodingKeys: String, CodingKey {
+            case keychainAccessGroups = "keychain-access-groups"
+            case getTaskAllow = "get-task-allow"
+            case apsEnvironment = "aps-environment"
+        }
+        
+        enum Environment: String, Decodable {
+            case development, production, disabled
+        }
+        
+        init(keychainAccessGroups: Array<String>, getTaskAllow: Bool, apsEnvironment: Environment) {
+            self.keychainAccessGroups = keychainAccessGroups
+            self.getTaskAllow = getTaskAllow
+            self.apsEnvironment = apsEnvironment
+        }
+        
+        init(from decoder: Decoder) throws {
+            let container = try decoder.container(keyedBy: CodingKeys.self)
+            let keychainAccessGroups: [String] = (try? container.decode([String].self, forKey: .keychainAccessGroups)) ?? []
+            let getTaskAllow: Bool = (try? container.decode(Bool.self, forKey: .getTaskAllow)) ?? false
+            let apsEnvironment: Environment = (try? container.decode(Environment.self, forKey: .apsEnvironment)) ?? .disabled
+            
+            self.init(keychainAccessGroups: keychainAccessGroups, getTaskAllow: getTaskAllow, apsEnvironment: apsEnvironment)
+        }
+    }
+}
+
+// Factory methods
+extension MobileProvision {
+    // Read mobileprovision file embedded in app.
+    static func read() -> MobileProvision? {
+        let profilePath: String? = Bundle.main.path(forResource: "embedded", ofType: "mobileprovision")
+        guard let path = profilePath else { return nil }
+        return read(from: path)
+    }
+
+    // Read a .mobileprovision file on disk
+    static func read(from profilePath: String) -> MobileProvision? {
+        guard let plistDataString = try? NSString.init(contentsOfFile: profilePath,
+                                                       encoding: String.Encoding.isoLatin1.rawValue) else { return nil }
+                
+        // Skip binary part at the start of the mobile provisionning profile
+        let scanner = Scanner(string: plistDataString as String)
+        guard scanner.scanUpTo("<plist", into: nil) != false else { return nil }
+        
+        // ... and extract plist until end of plist payload (skip the end binary part.
+        var extractedPlist: NSString?
+        guard scanner.scanUpTo("</plist>", into: &extractedPlist) != false else { return nil }
+        
+        guard let plist = extractedPlist?.appending("</plist>").data(using: .isoLatin1) else { return nil }
+        let decoder = PropertyListDecoder()
+        do {
+            let provision = try decoder.decode(MobileProvision.self, from: plist)
+            return provision
+        } catch {
+            // TODO: log / handle error
+            return nil
+        }
+    }
+}