Skip to content

Instantly share code, notes, and snippets.

@rsahara
Created March 12, 2020 09:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rsahara/bdd623186eda01e4d18cb17bcd61caef to your computer and use it in GitHub Desktop.
Save rsahara/bdd623186eda01e4d18cb17bcd61caef to your computer and use it in GitHub Desktop.
Test iOS backups
enum RunoTest {
static func execute() {
print("keychain[mofu] = \(describeValueInKeychain(account: "mofu"))")
print("keychain[mofu-device-only] = \(describeValueInKeychain(account: "mofu-device-only"))")
print("document[mofu] = \(describeValueInDocumentDirectory(filename: "mofu"))")
print("document[mofu-excluded] = \(describeValueInDocumentDirectory(filename: "mofu-excluded"))")
print("caches[mofu] = \(describeValueInCachesDirectory(filename: "mofu"))")
print("caches[mofu-excluded] = \(describeValueInCachesDirectory(filename: "mofu-excluded"))")
let value = DateFormatter.localizedString(from: Date(), dateStyle: .medium, timeStyle: .medium)
print("writing value: \(value)")
setToKeychain(account: "mofu", accessibility: kSecAttrAccessibleAlways, value: value)
setToKeychain(account: "mofu-device-only", accessibility: kSecAttrAccessibleWhenUnlockedThisDeviceOnly, value: value)
writeToDocumentDirectory(filename: "mofu", value: value)
writeToDocumentDirectory(filename: "mofu-excluded", value: value, excludeFromBackup: true)
writeToCachesDirectory(filename: "mofu", value: value)
writeToCachesDirectory(filename: "mofu-excluded", value: value, excludeFromBackup: true)
}
static let keychainService = "RunoTest"
static let documentDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
static let cachesDirectoryURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
}
extension RunoTest {
private static func setToKeychain(account: String, accessibility: CFString, value: String) {
let valueData = value.data(using: .utf8)!
let updateResultCode = SecItemUpdate([
kSecClass: kSecClassGenericPassword,
kSecAttrService: keychainService,
kSecAttrAccount: account,
] as CFDictionary, [
kSecAttrAccessible: accessibility,
kSecValueData: valueData,
] as CFDictionary)
switch updateResultCode {
case errSecSuccess: break
case errSecItemNotFound:
let addResultCode = SecItemAdd([
kSecClass: kSecClassGenericPassword,
kSecAttrService: keychainService,
kSecAttrAccount: account,
kSecAttrAccessible: accessibility,
kSecValueData: valueData,
] as CFDictionary, nil)
guard addResultCode == errSecSuccess else {
fatalError("\(addResultCode)")
}
default:
fatalError("\(updateResultCode)")
}
}
private static func describeValueInKeychain(account: String) -> String {
var result: CFTypeRef? = nil
let resultCode = SecItemCopyMatching([
kSecClass: kSecClassGenericPassword,
kSecAttrService: keychainService,
kSecAttrAccount: account,
kSecReturnData: true,
] as NSDictionary, &result)
switch resultCode {
case errSecSuccess: return String(bytes: result! as! Data, encoding: .utf8)!
case errSecItemNotFound: return "(error: not found)"
default: return "(error: \(resultCode))"
}
}
private static func writeToDocumentDirectory(filename: String, value: String, excludeFromBackup: Bool = false) {
let url = documentDirectoryURL.appendingPathComponent(filename)
writeToFile(url: url, value: value)
if excludeFromBackup {
setResourceValues(url: url, excludedFromBackup: true)
}
}
private static func describeValueInDocumentDirectory(filename: String) -> String {
describeValueInFile(url: documentDirectoryURL.appendingPathComponent(filename))
}
private static func writeToCachesDirectory(filename: String, value: String, excludeFromBackup: Bool = false) {
let url = cachesDirectoryURL.appendingPathComponent(filename)
writeToFile(url: url, value: value)
if excludeFromBackup {
setResourceValues(url: url, excludedFromBackup: true)
}
}
private static func describeValueInCachesDirectory(filename: String) -> String {
describeValueInFile(url: cachesDirectoryURL.appendingPathComponent(filename))
}
private static func writeToFile(url: URL, value: String) {
do {
try value.write(
to: url,
atomically: false,
encoding: .utf8
)
}
catch {
fatalError("\(error.localizedDescription)")
}
}
private static func describeValueInFile(url: URL) -> String {
do {
return try String(
contentsOf: url,
encoding: .utf8
)
}
catch {
return "(error: \(error.localizedDescription))"
}
}
private static func setResourceValues(url: URL, excludedFromBackup: Bool) {
var resourceURL = url
var resourceValues = URLResourceValues()
resourceValues.isExcludedFromBackup = excludedFromBackup
do {
try resourceURL.setResourceValues(resourceValues)
}
catch {
fatalError("\(error)")
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment