Encrypt profiles stored to iCloud (#436)

Going forward, persist profiles encrypted to the CloudKit container.
Conversely, read from the encrypted field if any, falling back to the
plain JSON field.

WARNING: the change is NOT backward compatible, as it would defeat the
purpose. That is, once the profile is stored encrypted, the old plain
profile is erased and its content won't be readable by older versions of
the app.
This commit is contained in:
Davide De Rosa 2023-12-17 23:31:08 +01:00 committed by GitHub
parent 526ed49472
commit 38b06b6bb5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 12 additions and 7 deletions

View File

@ -7,9 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased ## Unreleased
- Upgrade OpenSSL to 3.2.0. [tunnelkit#336](https://github.com/passepartoutvpn/tunnelkit/issues/336) ### Added
- WireGuard: Show data count. [#312](https://github.com/passepartoutvpn/passepartout-apple/issues/312) - WireGuard: Show data count. [#312](https://github.com/passepartoutvpn/passepartout-apple/issues/312)
### Changed
- Upgrade OpenSSL to 3.2.0. [tunnelkit#336](https://github.com/passepartoutvpn/tunnelkit/issues/336)
- Encrypt profiles stored to iCloud. [#436](https://github.com/passepartoutvpn/passepartout-apple/pull/436)
## 2.2.1 (2023-10-14) ## 2.2.1 (2023-10-14)
### Fixed ### Fixed

View File

@ -17,6 +17,7 @@ extension CDProfile {
} }
@NSManaged var json: Data? @NSManaged var json: Data?
@NSManaged var encryptedJSON: Data?
@NSManaged var name: String? @NSManaged var name: String?
@NSManaged var providerName: String? @NSManaged var providerName: String?
@NSManaged var uuid: UUID? @NSManaged var uuid: UUID?

View File

@ -1,13 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="20086" systemVersion="21E230" minimumToolsVersion="Automatic" sourceLanguage="Swift" usedWithCloudKit="YES" userDefinedModelVersionIdentifier="1.0"> <model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="21754" systemVersion="22E252" minimumToolsVersion="Automatic" sourceLanguage="Swift" usedWithCloudKit="YES" userDefinedModelVersionIdentifier="1.0">
<entity name="CDProfile" representedClassName="CDProfile" syncable="YES"> <entity name="CDProfile" representedClassName="CDProfile" syncable="YES">
<attribute name="encryptedJSON" optional="YES" attributeType="Binary" allowsCloudEncryption="YES"/>
<attribute name="json" optional="YES" attributeType="Binary"/> <attribute name="json" optional="YES" attributeType="Binary"/>
<attribute name="lastUpdate" optional="YES" attributeType="Date" usesScalarValueType="NO"/> <attribute name="lastUpdate" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="name" optional="YES" attributeType="String"/> <attribute name="name" optional="YES" attributeType="String"/>
<attribute name="providerName" optional="YES" attributeType="String"/> <attribute name="providerName" optional="YES" attributeType="String"/>
<attribute name="uuid" optional="YES" attributeType="UUID" usesScalarValueType="NO"/> <attribute name="uuid" optional="YES" attributeType="UUID" usesScalarValueType="NO"/>
</entity> </entity>
<elements>
<element name="CDProfile" positionX="-63" positionY="-18" width="128" height="104"/>
</elements>
</model> </model>

View File

@ -38,7 +38,7 @@ struct ProfileMapper: DTOMapper, ModelMapper {
func toDTO(_ ws: Profile) throws -> CDProfile { func toDTO(_ ws: Profile) throws -> CDProfile {
let profile = ProfileHeaderMapper(context).toDTO(ws) let profile = ProfileHeaderMapper(context).toDTO(ws)
do { do {
profile.json = try JSONEncoder().encode(ws) profile.encryptedJSON = try JSONEncoder().encode(ws)
} catch { } catch {
assertionFailure("Unable to encode profile: \(error)") assertionFailure("Unable to encode profile: \(error)")
throw error throw error
@ -47,7 +47,7 @@ struct ProfileMapper: DTOMapper, ModelMapper {
} }
static func toModel(_ dto: CDProfile) throws -> Profile? { static func toModel(_ dto: CDProfile) throws -> Profile? {
guard let json = dto.json else { guard let json = dto.encryptedJSON ?? dto.json else {
Utils.assertCoreDataDecodingFailed() Utils.assertCoreDataDecodingFailed()
return nil return nil
} }