Migrate host configurations

This commit is contained in:
Davide De Rosa 2018-10-25 18:53:51 +02:00
parent 542a3e3721
commit d087acd512
5 changed files with 184 additions and 1 deletions

View File

@ -48,6 +48,9 @@
0E8D97E521389277006FB4A0 /* pia.json in Resources */ = {isa = PBXBuildFile; fileRef = 0E8D97E421389276006FB4A0 /* pia.json */; };
0EAAD71920E6669A0088754A /* GroupConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDE8DED20C93E4C004C739C /* GroupConstants.swift */; };
0EB60FDA2111136E00AD27F3 /* UITextView+Search.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB60FD92111136E00AD27F3 /* UITextView+Search.swift */; };
0EBBE8F221822B4D00106008 /* ConnectionServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBBE8F021822B4D00106008 /* ConnectionServiceTests.swift */; };
0EBBE8F321822B4D00106008 /* ConnectionService.json in Resources */ = {isa = PBXBuildFile; fileRef = 0EBBE8F121822B4D00106008 /* ConnectionService.json */; };
0EBBE8F52182361800106008 /* ConnectionService+Migration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBBE8F42182361700106008 /* ConnectionService+Migration.swift */; };
0EBE3A79213C4E5500BFA2F5 /* OrganizerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBE3A78213C4E5400BFA2F5 /* OrganizerViewController.swift */; };
0EBE3A84213C6ADE00BFA2F5 /* InfrastructureFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBE3A83213C6ADE00BFA2F5 /* InfrastructureFactory.swift */; };
0EBE3A90213C6F4000BFA2F5 /* TrustPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBE3A8F213C6F4000BFA2F5 /* TrustPolicy.swift */; };
@ -165,6 +168,9 @@
0E8D97E121388B52006FB4A0 /* InfrastructurePreset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfrastructurePreset.swift; sourceTree = "<group>"; };
0E8D97E421389276006FB4A0 /* pia.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = pia.json; sourceTree = "<group>"; };
0EB60FD92111136E00AD27F3 /* UITextView+Search.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextView+Search.swift"; sourceTree = "<group>"; };
0EBBE8F021822B4D00106008 /* ConnectionServiceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConnectionServiceTests.swift; sourceTree = "<group>"; };
0EBBE8F121822B4D00106008 /* ConnectionService.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = ConnectionService.json; sourceTree = "<group>"; };
0EBBE8F42182361700106008 /* ConnectionService+Migration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ConnectionService+Migration.swift"; sourceTree = "<group>"; };
0EBE3A78213C4E5400BFA2F5 /* OrganizerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OrganizerViewController.swift; sourceTree = "<group>"; };
0EBE3A83213C6ADE00BFA2F5 /* InfrastructureFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfrastructureFactory.swift; sourceTree = "<group>"; };
0EBE3A8F213C6F4000BFA2F5 /* TrustPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrustPolicy.swift; sourceTree = "<group>"; };
@ -324,10 +330,12 @@
0E57F64F20C83FC7008323CF /* PassepartoutTests-iOS */ = {
isa = PBXGroup;
children = (
0EBBE8F121822B4D00106008 /* ConnectionService.json */,
0ED38AE2213F517D0004D387 /* pia-hungary.ovpn */,
0E57F65220C83FC7008323CF /* Info.plist */,
0EBBE8F021822B4D00106008 /* ConnectionServiceTests.swift */,
0ED38AE0213F51370004D387 /* FileConfigurationTests.swift */,
0ED31C2620CF257C0027975F /* InfrastructureTests.swift */,
0E57F65220C83FC7008323CF /* Info.plist */,
);
path = "PassepartoutTests-iOS";
sourceTree = "<group>";
@ -377,6 +385,7 @@
0EBE3A9E213DC1A100BFA2F5 /* ConnectionProfile.swift */,
0EBE3AAB213DEB8800BFA2F5 /* ConnectionProfileHolder.swift */,
0EBE3A9F213DC1A100BFA2F5 /* ConnectionService.swift */,
0EBBE8F42182361700106008 /* ConnectionService+Migration.swift */,
0EDE8DE620C93945004C739C /* Credentials.swift */,
0EC7F20420E24308004EA58E /* DebugLog.swift */,
0ED38AE621404F100004D387 /* EndpointDataSource.swift */,
@ -654,6 +663,7 @@
buildActionMask = 2147483647;
files = (
0ED38AE3213F517D0004D387 /* pia-hungary.ovpn in Resources */,
0EBBE8F321822B4D00106008 /* ConnectionService.json in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -816,6 +826,7 @@
0E1066C920E0F84A004F98B7 /* Cells.swift in Sources */,
0EBE3AA6213DC1B000BFA2F5 /* ProviderConnectionProfile.swift in Sources */,
0E3DA371215CB5BF00B40FC9 /* VersionViewController.swift in Sources */,
0EBBE8F52182361800106008 /* ConnectionService+Migration.swift in Sources */,
0E39BCF3214DA9310035E9DE /* AppConstants.swift in Sources */,
0E05C5D620D1645F006EE732 /* SwiftGen+Storyboards.swift in Sources */,
0E2B494220FD16540094784C /* TransientStore.swift in Sources */,
@ -866,6 +877,7 @@
files = (
0ED38AE1213F51370004D387 /* FileConfigurationTests.swift in Sources */,
0ED31C2720CF257C0027975F /* InfrastructureTests.swift in Sources */,
0EBBE8F221822B4D00106008 /* ConnectionServiceTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -35,4 +35,6 @@ enum ApplicationError: Error {
case emptyRemotes
case unsupportedConfiguration(option: String)
case migration
}

View File

@ -0,0 +1,107 @@
//
// ConnectionService+Migration.swift
// Passepartout
//
// Created by Davide De Rosa on 10/25/18.
// Copyright (c) 2018 Davide De Rosa. All rights reserved.
//
// https://github.com/keeshux
//
// This file is part of Passepartout.
//
// Passepartout is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Passepartout is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
//
import Foundation
import SwiftyBeaver
private let log = SwiftyBeaver.self
extension ConnectionService {
static func migrateJSON(at from: URL, to: URL) {
do {
let newData = try migrateJSON(at: from)
try newData.write(to: to)
} catch let e {
log.warning("Could not migrate service: \(e)")
}
}
static func migrateJSON(at from: URL) throws -> Data {
let data = try Data(contentsOf: from)
guard var json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
throw ApplicationError.migration
}
// replace migration logic here
try migrateToWrappedSessionConfiguration(&json)
return try JSONSerialization.data(withJSONObject: json, options: [])
}
private static func migrateToWrappedSessionConfiguration(_ json: inout [String: Any]) throws {
guard let profiles = json["profiles"] as? [[String: Any]] else {
throw ApplicationError.migration
}
var newProfiles: [[String: Any]] = []
for var container in profiles {
guard var hostProfile = container["host"] as? [String: Any] else {
newProfiles.append(container)
continue
}
guard var parameters = hostProfile["parameters"] as? [String: Any] else {
throw ApplicationError.migration
}
guard parameters["sessionConfiguration"] == nil else {
newProfiles.append(container)
continue
}
migrateSessionConfiguration(in: &parameters)
hostProfile["parameters"] = parameters
container["host"] = hostProfile
newProfiles.append(container)
}
json["profiles"] = newProfiles
}
private static func migrateSessionConfiguration(in map: inout [String: Any]) {
let scKeys = [
"cipher",
"digest",
"ca",
"clientCertificate",
"clientKey",
"compressionFraming",
"tlsWrap",
// "keepAliveSeconds", // renamed
// "renegotiatesAfterSeconds", // renamed
"usesPIAPatches"
]
var sessionConfiguration: [String: Any] = [:]
for key in scKeys {
guard let value = map[key] else {
continue
}
sessionConfiguration[key] = value
map.removeValue(forKey: key)
}
if let value = map["keepAliveSeconds"] {
sessionConfiguration["keepAliveInterval"] = value
}
if let value = map["renegotiatesAfterSeconds"] {
sessionConfiguration["renegotiatesAfter"] = value
}
map["sessionConfiguration"] = sessionConfiguration
}
}

View File

@ -0,0 +1 @@
{"appGroup":"group.com.algoritmico.Passepartout","activeProfileId":"host.edu","tunnelConfiguration":{"endpointProtocols":["UDP:1194"],"compressionFraming":0,"digest":"SHA1","ca":"","lastErrorKey":"LastVPNError","debugLogFormat":"$DHH:mm:ss$d - $M","usesPIAPatches":false,"cipher":"AES-128-CBC","prefersResolvedAddresses":false,"shouldDebug":true,"mtu":1250,"debugLogKey":"LastVPNLog"},"preferences":{"trustPolicy":"ignore","trustsMobileNetwork":false,"disconnectsOnSleep":false,"trustedWifis":{},"resolvesHostname":true},"profiles":[{"provider":{"username":"p0000000","id":"provider.PIA","poolId":"ca-vancouver","name":"PIA","presetId":"recommended"}},{"host":{"username":"","title":"edu","hostname":"1.2.4.5","parameters":{"endpointProtocols":["UDP:1194","TCP:1194","TCP:443"],"compressionFraming":1,"digest":"SHA256","ca":"bogus+ca","clientCertificate":"bogus+client","usesPIAPatches":false,"tlsWrap":{"key":{"dir":1,"data":"bogus+static+key"},"strategy":"auth"},"cipher":"AES-256-CBC","prefersResolvedAddresses":false,"clientKey":"bogus+key","mtu":1500,"shouldDebug":false}}},{"host":{"username":"","title":"vps-udp-tc","hostname":"8.8.4.4","parameters":{"shouldDebug":false,"endpointProtocols":["UDP:1198"],"compressionFraming":1,"digest":"SHA512","ca":"bogus+ca","renegotiatesAfterSeconds":0,"usesPIAPatches":false,"tlsWrap":{"key":{"dir":1,"data":"bogus+static+key"},"strategy":"crypt"},"cipher":"AES-192-CBC","prefersResolvedAddresses":false,"clientKey":"bogus+key","mtu":1500,"keepAliveSeconds":25}}}]}

View File

@ -0,0 +1,61 @@
//
// ConnectionServiceTests.swift
// PassepartoutTests-iOS
//
// Created by Davide De Rosa on 10/25/18.
// Copyright (c) 2018 Davide De Rosa. All rights reserved.
//
// https://github.com/keeshux
//
// This file is part of Passepartout.
//
// Passepartout is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Passepartout is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
//
import XCTest
import TunnelKit
@testable import Passepartout_iOS
class ConnectionServiceTests: XCTestCase {
let url = Bundle(for: ConnectionServiceTests.self).url(forResource: "ConnectionService", withExtension: "json")!
override func setUp() {
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
func testParse() {
let jsonData = try! Data(contentsOf: url)
XCTAssertNoThrow(try JSONSerialization.jsonObject(with: jsonData, options: []))
}
func testMigrate() {
let migrated = try! ConnectionService.migrateJSON(at: url)
let json = String(data: migrated, encoding: .utf8)!
print(json)
let service = try! JSONDecoder().decode(ConnectionService.self, from: migrated)
guard let activeProfile = service.activeProfile as? HostConnectionProfile else {
XCTFail()
return
}
XCTAssert(activeProfile.id == "host.edu")
XCTAssert(activeProfile.hostname == "1.2.4.5")
XCTAssert(activeProfile.parameters.sessionConfiguration.cipher == .aes256cbc)
XCTAssert(activeProfile.parameters.sessionConfiguration.ca.pem == "bogus+ca")
}
}