Mobileprovision.swift 3.8 KB

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