Mobileprovision.swift 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. //
  2. // MobileProvision.swift
  3. // Fluux.io
  4. //
  5. // Created by Mickaël Rémond on 03/11/2018.
  6. // Copyright © 2018 ProcessOne.
  7. // Distributed under Apache License v2
  8. //
  9. import Foundation
  10. /* Decode mobileprovision plist file
  11. Usage:
  12. 1. To get mobileprovision data as embedded in your app:
  13. MobileProvision.read()
  14. 2. To get mobile provision data from a file on disk:
  15. MobileProvision.read(from: "my.mobileprovision")
  16. */
  17. struct MobileProvision: Decodable {
  18. var name: String
  19. var appIDName: String
  20. var platform: [String]
  21. var isXcodeManaged: Bool? = false
  22. var creationDate: Date
  23. var expirationDate: Date
  24. var entitlements: Entitlements
  25. private enum CodingKeys : String, CodingKey {
  26. case name = "Name"
  27. case appIDName = "AppIDName"
  28. case platform = "Platform"
  29. case isXcodeManaged = "IsXcodeManaged"
  30. case creationDate = "CreationDate"
  31. case expirationDate = "ExpirationDate"
  32. case entitlements = "Entitlements"
  33. }
  34. // Sublevel: decode entitlements informations
  35. struct Entitlements: Decodable {
  36. let keychainAccessGroups: [String]
  37. let getTaskAllow: Bool
  38. let apsEnvironment: Environment
  39. private enum CodingKeys: String, CodingKey {
  40. case keychainAccessGroups = "keychain-access-groups"
  41. case getTaskAllow = "get-task-allow"
  42. case apsEnvironment = "aps-environment"
  43. }
  44. enum Environment: String, Decodable {
  45. case development, production, disabled
  46. }
  47. init(keychainAccessGroups: Array<String>, getTaskAllow: Bool, apsEnvironment: Environment) {
  48. self.keychainAccessGroups = keychainAccessGroups
  49. self.getTaskAllow = getTaskAllow
  50. self.apsEnvironment = apsEnvironment
  51. }
  52. init(from decoder: Decoder) throws {
  53. let container = try decoder.container(keyedBy: CodingKeys.self)
  54. let keychainAccessGroups: [String] = (try? container.decode([String].self, forKey: .keychainAccessGroups)) ?? []
  55. let getTaskAllow: Bool = (try? container.decode(Bool.self, forKey: .getTaskAllow)) ?? false
  56. let apsEnvironment: Environment = (try? container.decode(Environment.self, forKey: .apsEnvironment)) ?? .disabled
  57. self.init(keychainAccessGroups: keychainAccessGroups, getTaskAllow: getTaskAllow, apsEnvironment: apsEnvironment)
  58. }
  59. }
  60. }
  61. // Factory methods
  62. extension MobileProvision {
  63. // Read mobileprovision file embedded in app.
  64. static func read() -> MobileProvision? {
  65. let profilePath: String? = Bundle.main.path(forResource: "embedded", ofType: "mobileprovision")
  66. guard let path = profilePath else { return nil }
  67. return read(from: path)
  68. }
  69. // Read a .mobileprovision file on disk
  70. static func read(from profilePath: String) -> MobileProvision? {
  71. guard let plistDataString = try? NSString.init(contentsOfFile: profilePath,
  72. encoding: String.Encoding.isoLatin1.rawValue) else { return nil }
  73. // Skip binary part at the start of the mobile provisionning profile
  74. let scanner = Scanner(string: plistDataString as String)
  75. guard scanner.scanUpTo("<plist", into: nil) != false else { return nil }
  76. // ... and extract plist until end of plist payload (skip the end binary part.
  77. var extractedPlist: NSString?
  78. guard scanner.scanUpTo("</plist>", into: &extractedPlist) != false else { return nil }
  79. guard let plist = extractedPlist?.appending("</plist>").data(using: .isoLatin1) else { return nil }
  80. let decoder = PropertyListDecoder()
  81. do {
  82. let provision = try decoder.decode(MobileProvision.self, from: plist)
  83. return provision
  84. } catch {
  85. // TODO: log / handle error
  86. return nil
  87. }
  88. }
  89. }