Verifies downloaded app’s permissions match source

Renames source JSON permissions key to “appPermissions” in order to preserve backwards compatibility, since we’ve changed the schema for permissions.
This commit is contained in:
Riley Testut
2023-05-12 18:26:24 -05:00
committed by Magesh K
parent f884d72a8b
commit ee410605e8
16 changed files with 452 additions and 127 deletions

View File

@@ -9,6 +9,7 @@
import CoreData
import UIKit
import AltSign
public extension ALTAppPermissionType
{
var localizedShortName: String? {
@@ -71,15 +72,29 @@ public extension ALTAppPermissionType
}
}
@objc(AppPermission)
@objc(AppPermission) @dynamicMemberLookup
public class AppPermission: NSManagedObject, Decodable, Fetchable
{
/* Properties */
@NSManaged public var type: ALTAppPermissionType
@NSManaged public var usageDescription: String
@NSManaged public var usageDescription: String?
@nonobjc public var permission: any ALTAppPermission {
switch self.type
{
case .entitlement: return ALTEntitlement(rawValue: self._permission)
case .privacy: return ALTAppPrivacyPermission(rawValue: self._permission)
case .backgroundMode: return ALTAppBackgroundMode(rawValue: self._permission)
default: return UnknownAppPermission(rawValue: self._permission)
}
}
@NSManaged @objc(permission) private var _permission: String
// Set by StoreApp.
@NSManaged public var appBundleID: String?
/* Relationships */
@NSManaged public private(set) var app: StoreApp!
@NSManaged public internal(set) var app: StoreApp?
private override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?)
{
@@ -88,7 +103,10 @@ public class AppPermission: NSManagedObject, Decodable, Fetchable
private enum CodingKeys: String, CodingKey
{
case type
case entitlement
case privacyType = "privacy"
case backgroundMode = "background"
case usageDescription
}
@@ -101,10 +119,33 @@ public class AppPermission: NSManagedObject, Decodable, Fetchable
do
{
let container = try decoder.container(keyedBy: CodingKeys.self)
self.usageDescription = try container.decode(String.self, forKey: .usageDescription)
let rawType = try container.decode(String.self, forKey: .type)
self.type = ALTAppPermissionType(rawValue: rawType)
self.usageDescription = try container.decodeIfPresent(String.self, forKey: .usageDescription)
if let entitlement = try container.decodeIfPresent(String.self, forKey: .entitlement)
{
self._permission = entitlement
self.type = .entitlement
}
else if let privacyType = try container.decodeIfPresent(String.self, forKey: .privacyType)
{
self._permission = privacyType
self.type = .privacy
}
else if let backgroundMode = try container.decodeIfPresent(String.self, forKey: .backgroundMode)
{
self._permission = backgroundMode
self.type = .backgroundMode
}
else
{
self._permission = ""
self.type = .unknown
// We don't want to save any unknown permissions, but can't throw error
// without making the entire decoding fail, so just delete self instead.
context.delete(self)
}
}
catch
{
@@ -125,3 +166,14 @@ public extension AppPermission
return NSFetchRequest<AppPermission>(entityName: "AppPermission")
}
}
// @dynamicMemberLookup
public extension AppPermission
{
// Convenience for accessing .permission properties.
subscript<T>(dynamicMember keyPath: KeyPath<any ALTAppPermission, T>) -> T {
get {
return self.permission[keyPath: keyPath]
}
}
}