Mobileprovision.swift 3.8 KB

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