KeychainAccessTests.swift 62 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398
  1. //
  2. // KeychainAccessTests.swift
  3. // KeychainAccessTests
  4. //
  5. // Created by kishikawa katsumi on 2014/12/24.
  6. // Copyright (c) 2014 kishikawa katsumi. All rights reserved.
  7. //
  8. import Foundation
  9. import XCTest
  10. import KeychainAccess
  11. class KeychainAccessTests: XCTestCase {
  12. override func setUp() {
  13. super.setUp()
  14. do { try Keychain(service: "Twitter", accessGroup: "12ABCD3E4F.shared").removeAll() } catch {}
  15. do { try Keychain(service: "Twitter").removeAll() } catch {}
  16. do { try Keychain(server: NSURL(string: "https://example.com")!, protocolType: .HTTPS).removeAll() } catch {}
  17. do { try Keychain(server: NSURL(string: "https://example.com:443")!, protocolType: .HTTPS).removeAll() } catch {}
  18. do { try Keychain().removeAll() } catch {}
  19. }
  20. override func tearDown() {
  21. super.tearDown()
  22. }
  23. // MARK:
  24. func testGenericPassword() {
  25. do {
  26. // Add Keychain items
  27. let keychain = Keychain(service: "Twitter")
  28. do { try keychain.set("kishikawa_katsumi", key: "username") } catch {}
  29. do { try keychain.set("password_1234", key: "password") } catch {}
  30. let username = try! keychain.get("username")
  31. XCTAssertEqual(username, "kishikawa_katsumi")
  32. let password = try! keychain.get("password")
  33. XCTAssertEqual(password, "password_1234")
  34. }
  35. do {
  36. // Update Keychain items
  37. let keychain = Keychain(service: "Twitter")
  38. do { try keychain.set("katsumi_kishikawa", key: "username") } catch {}
  39. do { try keychain.set("1234_password", key: "password") } catch {}
  40. let username = try! keychain.get("username")
  41. XCTAssertEqual(username, "katsumi_kishikawa")
  42. let password = try! keychain.get("password")
  43. XCTAssertEqual(password, "1234_password")
  44. }
  45. do {
  46. // Remove Keychain items
  47. let keychain = Keychain(service: "Twitter")
  48. do { try keychain.remove("username") } catch {}
  49. do { try keychain.remove("password") } catch {}
  50. XCTAssertNil(try! keychain.get("username"))
  51. XCTAssertNil(try! keychain.get("password"))
  52. }
  53. }
  54. func testGenericPasswordSubscripting() {
  55. do {
  56. // Add Keychain items
  57. let keychain = Keychain(service: "Twitter", accessGroup: "12ABCD3E4F.shared")
  58. keychain["username"] = "kishikawa_katsumi"
  59. keychain["password"] = "password_1234"
  60. let username = keychain["username"]
  61. XCTAssertEqual(username, "kishikawa_katsumi")
  62. let password = keychain["password"]
  63. XCTAssertEqual(password, "password_1234")
  64. }
  65. do {
  66. // Update Keychain items
  67. let keychain = Keychain(service: "Twitter", accessGroup: "12ABCD3E4F.shared")
  68. keychain["username"] = "katsumi_kishikawa"
  69. keychain["password"] = "1234_password"
  70. let username = keychain["username"]
  71. XCTAssertEqual(username, "katsumi_kishikawa")
  72. let password = keychain["password"]
  73. XCTAssertEqual(password, "1234_password")
  74. }
  75. do {
  76. // Remove Keychain items
  77. let keychain = Keychain(service: "Twitter", accessGroup: "12ABCD3E4F.shared")
  78. keychain["username"] = nil
  79. keychain["password"] = nil
  80. XCTAssertNil(keychain["username"])
  81. XCTAssertNil(keychain["password"])
  82. }
  83. }
  84. // MARK:
  85. func testInternetPassword() {
  86. do {
  87. // Add Keychain items
  88. let keychain = Keychain(server: NSURL(string: "https://kishikawakatsumi.com")!, protocolType: .HTTPS)
  89. do { try keychain.set("kishikawa_katsumi", key: "username") } catch {}
  90. do { try keychain.set("password_1234", key: "password") } catch {}
  91. let username = try! keychain.get("username")
  92. XCTAssertEqual(username, "kishikawa_katsumi")
  93. let password = try! keychain.get("password")
  94. XCTAssertEqual(password, "password_1234")
  95. }
  96. do {
  97. // Update Keychain items
  98. let keychain = Keychain(server: NSURL(string: "https://kishikawakatsumi.com")!, protocolType: .HTTPS)
  99. do { try keychain.set("katsumi_kishikawa", key: "username") } catch {}
  100. do { try keychain.set("1234_password", key: "password") } catch {}
  101. let username = try! keychain.get("username")
  102. XCTAssertEqual(username, "katsumi_kishikawa")
  103. let password = try! keychain.get("password")
  104. XCTAssertEqual(password, "1234_password")
  105. }
  106. do {
  107. // Remove Keychain items
  108. let keychain = Keychain(server: NSURL(string: "https://kishikawakatsumi.com")!, protocolType: .HTTPS)
  109. do { try keychain.remove("username") } catch {}
  110. do { try keychain.remove("password") } catch {}
  111. XCTAssertNil(try! keychain.get("username"))
  112. XCTAssertNil(try! keychain.get("password"))
  113. }
  114. }
  115. func testInternetPasswordSubscripting() {
  116. do {
  117. // Add Keychain items
  118. let keychain = Keychain(server: NSURL(string: "https://kishikawakatsumi.com")!, protocolType: .HTTPS)
  119. keychain["username"] = "kishikawa_katsumi"
  120. keychain["password"] = "password_1234"
  121. let username = keychain["username"]
  122. XCTAssertEqual(username, "kishikawa_katsumi")
  123. let password = keychain["password"]
  124. XCTAssertEqual(password, "password_1234")
  125. }
  126. do {
  127. // Update Keychain items
  128. let keychain = Keychain(server: NSURL(string: "https://kishikawakatsumi.com")!, protocolType: .HTTPS)
  129. keychain["username"] = "katsumi_kishikawa"
  130. keychain["password"] = "1234_password"
  131. let username = keychain["username"]
  132. XCTAssertEqual(username, "katsumi_kishikawa")
  133. let password = keychain["password"]
  134. XCTAssertEqual(password, "1234_password")
  135. }
  136. do {
  137. // Remove Keychain items
  138. let keychain = Keychain(server: NSURL(string: "https://kishikawakatsumi.com")!, protocolType: .HTTPS)
  139. keychain["username"] = nil
  140. keychain["password"] = nil
  141. XCTAssertNil(keychain["username"])
  142. XCTAssertNil(keychain["password"])
  143. }
  144. }
  145. // MARK:
  146. func testDefaultInitializer() {
  147. let keychain = Keychain()
  148. XCTAssertEqual(keychain.service, "")
  149. XCTAssertNil(keychain.accessGroup)
  150. }
  151. func testInitializerWithService() {
  152. let keychain = Keychain(service: "com.example.github-token")
  153. XCTAssertEqual(keychain.service, "com.example.github-token")
  154. XCTAssertNil(keychain.accessGroup)
  155. }
  156. func testInitializerWithAccessGroup() {
  157. let keychain = Keychain(accessGroup: "12ABCD3E4F.shared")
  158. XCTAssertEqual(keychain.service, "")
  159. XCTAssertEqual(keychain.accessGroup, "12ABCD3E4F.shared")
  160. }
  161. func testInitializerWithServiceAndAccessGroup() {
  162. let keychain = Keychain(service: "com.example.github-token", accessGroup: "12ABCD3E4F.shared")
  163. XCTAssertEqual(keychain.service, "com.example.github-token")
  164. XCTAssertEqual(keychain.accessGroup, "12ABCD3E4F.shared")
  165. }
  166. func testInitializerWithServer() {
  167. let server = "https://kishikawakatsumi.com"
  168. let URL = NSURL(string: server)!
  169. do {
  170. let keychain = Keychain(server: server, protocolType: .HTTPS)
  171. XCTAssertEqual(keychain.server, URL)
  172. XCTAssertEqual(keychain.protocolType, ProtocolType.HTTPS)
  173. XCTAssertEqual(keychain.authenticationType, AuthenticationType.Default)
  174. }
  175. do {
  176. let keychain = Keychain(server: URL, protocolType: .HTTPS)
  177. XCTAssertEqual(keychain.server, URL)
  178. XCTAssertEqual(keychain.protocolType, ProtocolType.HTTPS)
  179. XCTAssertEqual(keychain.authenticationType, AuthenticationType.Default)
  180. }
  181. }
  182. func testInitializerWithServerAndAuthenticationType() {
  183. let server = "https://kishikawakatsumi.com"
  184. let URL = NSURL(string: server)!
  185. do {
  186. let keychain = Keychain(server: server, protocolType: .HTTPS, authenticationType: .HTMLForm)
  187. XCTAssertEqual(keychain.server, URL)
  188. XCTAssertEqual(keychain.protocolType, ProtocolType.HTTPS)
  189. XCTAssertEqual(keychain.authenticationType, AuthenticationType.HTMLForm)
  190. }
  191. do {
  192. let keychain = Keychain(server: URL, protocolType: .HTTPS, authenticationType: .HTMLForm)
  193. XCTAssertEqual(keychain.server, URL)
  194. XCTAssertEqual(keychain.protocolType, ProtocolType.HTTPS)
  195. XCTAssertEqual(keychain.authenticationType, AuthenticationType.HTMLForm)
  196. }
  197. }
  198. // MARK:
  199. func testContains() {
  200. let keychain = Keychain(service: "Twitter")
  201. XCTAssertFalse(try! keychain.contains("username"), "not stored username")
  202. XCTAssertFalse(try! keychain.contains("password"), "not stored password")
  203. do { try keychain.set("kishikawakatsumi", key: "username") } catch {}
  204. XCTAssertTrue(try! keychain.contains("username"), "stored username")
  205. XCTAssertFalse(try! keychain.contains("password"), "not stored password")
  206. do { try keychain.set("password1234", key: "password") } catch {}
  207. XCTAssertTrue(try! keychain.contains("username"), "stored username")
  208. XCTAssertTrue(try! keychain.contains("password"), "stored password")
  209. }
  210. // MARK:
  211. func testSetString() {
  212. let keychain = Keychain(service: "Twitter")
  213. XCTAssertNil(try! keychain.get("username"), "not stored username")
  214. XCTAssertNil(try! keychain.get("password"), "not stored password")
  215. do { try keychain.set("kishikawakatsumi", key: "username") } catch {}
  216. XCTAssertEqual(try! keychain.get("username"), "kishikawakatsumi", "stored username")
  217. XCTAssertNil(try! keychain.get("password"), "not stored password")
  218. do { try keychain.set("password1234", key: "password") } catch {}
  219. XCTAssertEqual(try! keychain.get("username"), "kishikawakatsumi", "stored username")
  220. XCTAssertEqual(try! keychain.get("password"), "password1234", "stored password")
  221. }
  222. func testSetStringWithLabel() {
  223. let keychain = Keychain(service: "Twitter")
  224. .label("Twitter Account")
  225. XCTAssertNil(keychain["kishikawakatsumi"], "not stored password")
  226. do {
  227. let label = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
  228. return attributes?.label
  229. }
  230. XCTAssertNil(label)
  231. } catch {
  232. XCTFail("error occurred")
  233. }
  234. keychain["kishikawakatsumi"] = "password1234"
  235. XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
  236. do {
  237. let label = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
  238. return attributes?.label
  239. }
  240. XCTAssertEqual(label, "Twitter Account")
  241. } catch {
  242. XCTFail("error occurred")
  243. }
  244. }
  245. func testSetStringWithComment() {
  246. let keychain = Keychain(service: "Twitter")
  247. .comment("Kishikawa Katsumi")
  248. XCTAssertNil(keychain["kishikawakatsumi"], "not stored password")
  249. do {
  250. let comment = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
  251. return attributes?.comment
  252. }
  253. XCTAssertNil(comment)
  254. } catch {
  255. XCTFail("error occurred")
  256. }
  257. keychain["kishikawakatsumi"] = "password1234"
  258. XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
  259. do {
  260. let comment = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
  261. return attributes?.comment
  262. }
  263. XCTAssertEqual(comment, "Kishikawa Katsumi")
  264. } catch {
  265. XCTFail("error occurred")
  266. }
  267. }
  268. func testSetStringWithLabelAndComment() {
  269. let keychain = Keychain(service: "Twitter")
  270. .label("Twitter Account")
  271. .comment("Kishikawa Katsumi")
  272. XCTAssertNil(keychain["kishikawakatsumi"], "not stored password")
  273. do {
  274. let label = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
  275. return attributes?.label
  276. }
  277. XCTAssertNil(label)
  278. let comment = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
  279. return attributes?.comment
  280. }
  281. XCTAssertNil(comment)
  282. } catch {
  283. XCTFail("error occurred")
  284. }
  285. keychain["kishikawakatsumi"] = "password1234"
  286. XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
  287. do {
  288. let label = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
  289. return attributes?.label
  290. }
  291. XCTAssertEqual(label, "Twitter Account")
  292. let comment = try keychain.get("kishikawakatsumi") { (attributes) -> String? in
  293. return attributes?.comment
  294. }
  295. XCTAssertEqual(comment, "Kishikawa Katsumi")
  296. } catch {
  297. XCTFail("error occurred")
  298. }
  299. }
  300. func testSetData() {
  301. let JSONObject = ["username": "kishikawakatsumi", "password": "password1234"]
  302. let JSONData = try! NSJSONSerialization.dataWithJSONObject(JSONObject, options: [])
  303. let keychain = Keychain(service: "Twitter")
  304. XCTAssertNil(try! keychain.getData("JSONData"), "not stored JSON data")
  305. do { try keychain.set(JSONData, key: "JSONData") } catch {}
  306. XCTAssertEqual(try! keychain.getData("JSONData"), JSONData, "stored JSON data")
  307. }
  308. func testStringConversionError() {
  309. let keychain = Keychain(service: "Twitter")
  310. let length = 256
  311. let data = NSMutableData(length: length)!
  312. SecRandomCopyBytes(kSecRandomDefault, length, UnsafeMutablePointer<UInt8>(data.mutableBytes))
  313. do {
  314. try keychain.set(data, key: "RandomData")
  315. let _ = try keychain.getString("RandomData")
  316. } catch let error as NSError {
  317. XCTAssertEqual(error.domain, KeychainAccessErrorDomain)
  318. XCTAssertEqual(error.code, Int(Status.ConversionError.rawValue))
  319. }
  320. }
  321. func testGetPersistentRef() {
  322. let keychain = Keychain(service: "Twitter")
  323. XCTAssertNil(keychain["kishikawakatsumi"], "not stored password")
  324. do {
  325. let persistentRef = try keychain.get("kishikawakatsumi") { $0?.persistentRef }
  326. XCTAssertNil(persistentRef)
  327. } catch {
  328. XCTFail("error occurred")
  329. }
  330. keychain["kishikawakatsumi"] = "password1234"
  331. XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
  332. do {
  333. let persistentRef = try keychain.get("kishikawakatsumi") { $0?.persistentRef }
  334. XCTAssertNotNil(persistentRef)
  335. } catch {
  336. XCTFail("error occurred")
  337. }
  338. }
  339. #if os(iOS) || os(tvOS)
  340. func testSetAttributes() {
  341. do {
  342. var attributes = [String: AnyObject]()
  343. attributes[String(kSecAttrDescription)] = "Description Test"
  344. attributes[String(kSecAttrComment)] = "Comment Test"
  345. attributes[String(kSecAttrCreator)] = "Creator Test"
  346. attributes[String(kSecAttrType)] = "Type Test"
  347. attributes[String(kSecAttrLabel)] = "Label Test"
  348. attributes[String(kSecAttrIsInvisible)] = true
  349. attributes[String(kSecAttrIsNegative)] = true
  350. let keychain = Keychain(service: "Twitter")
  351. .attributes(attributes)
  352. .accessibility(.WhenPasscodeSetThisDeviceOnly, authenticationPolicy: .UserPresence)
  353. XCTAssertNil(keychain["kishikawakatsumi"], "not stored password")
  354. do {
  355. let attributes = try keychain.get("kishikawakatsumi") { $0 }
  356. XCTAssertNil(attributes)
  357. } catch {
  358. XCTFail("error occurred")
  359. }
  360. keychain["kishikawakatsumi"] = "password1234"
  361. XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
  362. do {
  363. let attributes = try keychain.get("kishikawakatsumi") { $0 }
  364. XCTAssertEqual(attributes?.`class`, ItemClass.GenericPassword.rawValue)
  365. XCTAssertEqual(attributes?.data, "password1234".dataUsingEncoding(NSUTF8StringEncoding))
  366. XCTAssertNil(attributes?.ref)
  367. XCTAssertNotNil(attributes?.persistentRef)
  368. XCTAssertEqual(attributes?.accessible, Accessibility.WhenPasscodeSetThisDeviceOnly.rawValue)
  369. XCTAssertNotNil(attributes?.accessControl)
  370. XCTAssertEqual(attributes?.accessGroup, "")
  371. XCTAssertNotNil(attributes?.synchronizable)
  372. XCTAssertNotNil(attributes?.creationDate)
  373. XCTAssertNotNil(attributes?.modificationDate)
  374. XCTAssertEqual(attributes?.attributeDescription, "Description Test")
  375. XCTAssertEqual(attributes?.comment, "Comment Test")
  376. XCTAssertEqual(attributes?.creator, "Creator Test")
  377. XCTAssertEqual(attributes?.type, "Type Test")
  378. XCTAssertEqual(attributes?.label, "Label Test")
  379. XCTAssertEqual(attributes?.isInvisible, true)
  380. XCTAssertEqual(attributes?.isNegative, true)
  381. XCTAssertEqual(attributes?.account, "kishikawakatsumi")
  382. XCTAssertEqual(attributes?.service, "Twitter")
  383. XCTAssertNil(attributes?.generic)
  384. XCTAssertNil(attributes?.securityDomain)
  385. XCTAssertNil(attributes?.server)
  386. XCTAssertNil(attributes?.`protocol`)
  387. XCTAssertNil(attributes?.authenticationType)
  388. XCTAssertNil(attributes?.port)
  389. XCTAssertNil(attributes?.path)
  390. XCTAssertEqual(attributes![String(kSecClass)] as? String, ItemClass.GenericPassword.rawValue)
  391. XCTAssertEqual(attributes![String(kSecValueData)] as? NSData, "password1234".dataUsingEncoding(NSUTF8StringEncoding))
  392. } catch {
  393. XCTFail("error occurred")
  394. }
  395. }
  396. do {
  397. var attributes = [String: AnyObject]()
  398. attributes[String(kSecAttrDescription)] = "Description Test"
  399. attributes[String(kSecAttrComment)] = "Comment Test"
  400. attributes[String(kSecAttrCreator)] = "Creator Test"
  401. attributes[String(kSecAttrType)] = "Type Test"
  402. attributes[String(kSecAttrLabel)] = "Label Test"
  403. attributes[String(kSecAttrIsInvisible)] = true
  404. attributes[String(kSecAttrIsNegative)] = true
  405. attributes[String(kSecAttrSecurityDomain)] = "securitydomain"
  406. let keychain = Keychain(server: NSURL(string: "https://example.com:443/api/login/")!, protocolType: .HTTPS)
  407. .attributes(attributes)
  408. XCTAssertNil(keychain["kishikawakatsumi"], "not stored password")
  409. do {
  410. let attributes = try keychain.get("kishikawakatsumi") { $0 }
  411. XCTAssertNil(attributes)
  412. } catch {
  413. XCTFail("error occurred")
  414. }
  415. do {
  416. keychain["kishikawakatsumi"] = "password1234"
  417. XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
  418. let attributes = try keychain.get("kishikawakatsumi") { $0 }
  419. XCTAssertEqual(attributes?.`class`, ItemClass.InternetPassword.rawValue)
  420. XCTAssertEqual(attributes?.data, "password1234".dataUsingEncoding(NSUTF8StringEncoding))
  421. XCTAssertNil(attributes?.ref)
  422. XCTAssertNotNil(attributes?.persistentRef)
  423. XCTAssertEqual(attributes?.accessible, Accessibility.AfterFirstUnlock.rawValue)
  424. if #available(iOS 9.0, *) {
  425. XCTAssertNil(attributes?.accessControl)
  426. } else {
  427. XCTAssertNotNil(attributes?.accessControl)
  428. }
  429. XCTAssertEqual(attributes?.accessGroup, "")
  430. XCTAssertNotNil(attributes?.synchronizable)
  431. XCTAssertNotNil(attributes?.creationDate)
  432. XCTAssertNotNil(attributes?.modificationDate)
  433. XCTAssertEqual(attributes?.attributeDescription, "Description Test")
  434. XCTAssertEqual(attributes?.comment, "Comment Test")
  435. XCTAssertEqual(attributes?.creator, "Creator Test")
  436. XCTAssertEqual(attributes?.type, "Type Test")
  437. XCTAssertEqual(attributes?.label, "Label Test")
  438. XCTAssertEqual(attributes?.isInvisible, true)
  439. XCTAssertEqual(attributes?.isNegative, true)
  440. XCTAssertEqual(attributes?.account, "kishikawakatsumi")
  441. XCTAssertNil(attributes?.service)
  442. XCTAssertNil(attributes?.generic)
  443. XCTAssertEqual(attributes?.securityDomain, "securitydomain")
  444. XCTAssertEqual(attributes?.server, "example.com")
  445. XCTAssertEqual(attributes?.`protocol`, ProtocolType.HTTPS.rawValue)
  446. XCTAssertEqual(attributes?.authenticationType, AuthenticationType.Default.rawValue)
  447. XCTAssertEqual(attributes?.port, 443)
  448. XCTAssertEqual(attributes?.path, "")
  449. } catch {
  450. XCTFail("error occurred")
  451. }
  452. do {
  453. let keychain = Keychain(server: NSURL(string: "https://example.com:443/api/login/")!, protocolType: .HTTPS)
  454. XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "stored password")
  455. keychain["kishikawakatsumi"] = "1234password"
  456. XCTAssertEqual(keychain["kishikawakatsumi"], "1234password", "updated password")
  457. let attributes = try keychain.get("kishikawakatsumi") { $0 }
  458. XCTAssertEqual(attributes?.`class`, ItemClass.InternetPassword.rawValue)
  459. XCTAssertEqual(attributes?.data, "1234password".dataUsingEncoding(NSUTF8StringEncoding))
  460. XCTAssertNil(attributes?.ref)
  461. XCTAssertNotNil(attributes?.persistentRef)
  462. XCTAssertEqual(attributes?.accessible, Accessibility.AfterFirstUnlock.rawValue)
  463. if #available(iOS 9.0, *) {
  464. XCTAssertNil(attributes?.accessControl)
  465. } else {
  466. XCTAssertNotNil(attributes?.accessControl)
  467. }
  468. XCTAssertEqual(attributes?.accessGroup, "")
  469. XCTAssertNotNil(attributes?.synchronizable)
  470. XCTAssertNotNil(attributes?.creationDate)
  471. XCTAssertNotNil(attributes?.modificationDate)
  472. XCTAssertEqual(attributes?.attributeDescription, "Description Test")
  473. XCTAssertEqual(attributes?.comment, "Comment Test")
  474. XCTAssertEqual(attributes?.creator, "Creator Test")
  475. XCTAssertEqual(attributes?.type, "Type Test")
  476. XCTAssertEqual(attributes?.label, "Label Test")
  477. XCTAssertEqual(attributes?.isInvisible, true)
  478. XCTAssertEqual(attributes?.isNegative, true)
  479. XCTAssertEqual(attributes?.account, "kishikawakatsumi")
  480. XCTAssertNil(attributes?.service)
  481. XCTAssertNil(attributes?.generic)
  482. XCTAssertEqual(attributes?.securityDomain, "securitydomain")
  483. XCTAssertEqual(attributes?.server, "example.com")
  484. XCTAssertEqual(attributes?.`protocol`, ProtocolType.HTTPS.rawValue)
  485. XCTAssertEqual(attributes?.authenticationType, AuthenticationType.Default.rawValue)
  486. XCTAssertEqual(attributes?.port, 443)
  487. XCTAssertEqual(attributes?.path, "")
  488. } catch {
  489. XCTFail("error occurred")
  490. }
  491. do {
  492. let keychain = Keychain(server: NSURL(string: "https://example.com:443/api/login/")!, protocolType: .HTTPS)
  493. .attributes([String(kSecAttrDescription): "Updated Description"])
  494. XCTAssertEqual(keychain["kishikawakatsumi"], "1234password", "stored password")
  495. keychain["kishikawakatsumi"] = "password1234"
  496. XCTAssertEqual(keychain["kishikawakatsumi"], "password1234", "updated password")
  497. let attributes = keychain[attributes: "kishikawakatsumi"]
  498. XCTAssertEqual(attributes?.`class`, ItemClass.InternetPassword.rawValue)
  499. XCTAssertEqual(attributes?.data, "password1234".dataUsingEncoding(NSUTF8StringEncoding))
  500. XCTAssertNil(attributes?.ref)
  501. XCTAssertNotNil(attributes?.persistentRef)
  502. XCTAssertEqual(attributes?.accessible, Accessibility.AfterFirstUnlock.rawValue)
  503. if #available(iOS 9.0, *) {
  504. XCTAssertNil(attributes?.accessControl)
  505. } else {
  506. XCTAssertNotNil(attributes?.accessControl)
  507. }
  508. XCTAssertEqual(attributes?.accessGroup, "")
  509. XCTAssertNotNil(attributes?.synchronizable)
  510. XCTAssertNotNil(attributes?.creationDate)
  511. XCTAssertNotNil(attributes?.modificationDate)
  512. XCTAssertEqual(attributes?.attributeDescription, "Updated Description")
  513. XCTAssertEqual(attributes?.comment, "Comment Test")
  514. XCTAssertEqual(attributes?.creator, "Creator Test")
  515. XCTAssertEqual(attributes?.type, "Type Test")
  516. XCTAssertEqual(attributes?.label, "Label Test")
  517. XCTAssertEqual(attributes?.isInvisible, true)
  518. XCTAssertEqual(attributes?.isNegative, true)
  519. XCTAssertEqual(attributes?.account, "kishikawakatsumi")
  520. XCTAssertNil(attributes?.service)
  521. XCTAssertNil(attributes?.generic)
  522. XCTAssertEqual(attributes?.securityDomain, "securitydomain")
  523. XCTAssertEqual(attributes?.server, "example.com")
  524. XCTAssertEqual(attributes?.`protocol`, ProtocolType.HTTPS.rawValue)
  525. XCTAssertEqual(attributes?.authenticationType, AuthenticationType.Default.rawValue)
  526. XCTAssertEqual(attributes?.port, 443)
  527. XCTAssertEqual(attributes?.path, "")
  528. }
  529. }
  530. }
  531. #endif
  532. func testRemoveString() {
  533. let keychain = Keychain(service: "Twitter")
  534. XCTAssertNil(try! keychain.get("username"), "not stored username")
  535. XCTAssertNil(try! keychain.get("password"), "not stored password")
  536. do { try keychain.set("kishikawakatsumi", key: "username") } catch {}
  537. XCTAssertEqual(try! keychain.get("username"), "kishikawakatsumi", "stored username")
  538. do { try keychain.set("password1234", key: "password") } catch {}
  539. XCTAssertEqual(try! keychain.get("password"), "password1234", "stored password")
  540. do { try keychain.remove("username") } catch {}
  541. XCTAssertNil(try! keychain.get("username"), "removed username")
  542. XCTAssertEqual(try! keychain.get("password"), "password1234", "left password")
  543. do { try keychain.remove("password") } catch {}
  544. XCTAssertNil(try! keychain.get("username"), "removed username")
  545. XCTAssertNil(try! keychain.get("password"), "removed password")
  546. }
  547. func testRemoveData() {
  548. let JSONObject = ["username": "kishikawakatsumi", "password": "password1234"]
  549. let JSONData = try! NSJSONSerialization.dataWithJSONObject(JSONObject, options: [])
  550. let keychain = Keychain(service: "Twitter")
  551. XCTAssertNil(try! keychain.getData("JSONData"), "not stored JSON data")
  552. do { try keychain.set(JSONData, key: "JSONData") } catch {}
  553. XCTAssertEqual(try! keychain.getData("JSONData"), JSONData, "stored JSON data")
  554. do { try keychain.remove("JSONData") } catch {}
  555. XCTAssertNil(try! keychain.getData("JSONData"), "removed JSON data")
  556. }
  557. // MARK:
  558. func testSubscripting() {
  559. let keychain = Keychain(service: "Twitter")
  560. XCTAssertNil(keychain["username"], "not stored username")
  561. XCTAssertNil(keychain["password"], "not stored password")
  562. XCTAssertNil(keychain[string: "username"], "not stored username")
  563. XCTAssertNil(keychain[string: "password"], "not stored password")
  564. keychain["username"] = "kishikawakatsumi"
  565. XCTAssertEqual(keychain["username"], "kishikawakatsumi", "stored username")
  566. XCTAssertEqual(keychain[string: "username"], "kishikawakatsumi", "stored username")
  567. keychain["password"] = "password1234"
  568. XCTAssertEqual(keychain["password"], "password1234", "stored password")
  569. XCTAssertEqual(keychain[string: "password"], "password1234", "stored password")
  570. keychain[string: "username"] = nil
  571. XCTAssertNil(keychain["username"], "removed username")
  572. XCTAssertEqual(keychain["password"], "password1234", "left password")
  573. XCTAssertNil(keychain[string: "username"], "removed username")
  574. XCTAssertEqual(keychain[string: "password"], "password1234", "left password")
  575. keychain[string: "password"] = nil
  576. XCTAssertNil(keychain["username"], "removed username")
  577. XCTAssertNil(keychain["password"], "removed password")
  578. XCTAssertNil(keychain[string: "username"], "removed username")
  579. XCTAssertNil(keychain[string: "password"], "removed password")
  580. let JSONObject = ["username": "kishikawakatsumi", "password": "password1234"]
  581. let JSONData = try! NSJSONSerialization.dataWithJSONObject(JSONObject, options: [])
  582. XCTAssertNil(keychain[data:"JSONData"], "not stored JSON data")
  583. keychain[data: "JSONData"] = JSONData
  584. XCTAssertEqual(keychain[data: "JSONData"], JSONData, "stored JSON data")
  585. keychain[data: "JSONData"] = nil
  586. XCTAssertNil(keychain[data:"JSONData"], "removed JSON data")
  587. }
  588. // MARK:
  589. #if os(iOS)
  590. func testErrorHandling() {
  591. do {
  592. let keychain = Keychain(service: "Twitter", accessGroup: "12ABCD3E4F.shared")
  593. try keychain.removeAll()
  594. XCTAssertTrue(true, "no error occurred")
  595. } catch {
  596. XCTFail("error occurred")
  597. }
  598. do {
  599. let keychain = Keychain(service: "Twitter")
  600. try keychain.removeAll()
  601. XCTAssertTrue(true, "no error occurred")
  602. } catch {
  603. XCTFail("error occurred")
  604. }
  605. do {
  606. let keychain = Keychain(server: NSURL(string: "https://kishikawakatsumi.com")!, protocolType: .HTTPS)
  607. try keychain.removeAll()
  608. XCTAssertTrue(true, "no error occurred")
  609. } catch {
  610. XCTFail("error occurred")
  611. }
  612. do {
  613. let keychain = Keychain()
  614. try keychain.removeAll()
  615. XCTAssertTrue(true, "no error occurred")
  616. } catch {
  617. XCTFail("error occurred")
  618. }
  619. do {
  620. // Add Keychain items
  621. let keychain = Keychain(service: "Twitter")
  622. do {
  623. try keychain.set("kishikawa_katsumi", key: "username")
  624. XCTAssertTrue(true, "no error occurred")
  625. } catch {
  626. XCTFail("error occurred")
  627. }
  628. do {
  629. try keychain.set("password_1234", key: "password")
  630. XCTAssertTrue(true, "no error occurred")
  631. } catch {
  632. XCTFail("error occurred")
  633. }
  634. do {
  635. let username = try keychain.get("username")
  636. XCTAssertEqual(username, "kishikawa_katsumi")
  637. } catch {
  638. XCTFail("error occurred")
  639. }
  640. do {
  641. let password = try keychain.get("password")
  642. XCTAssertEqual(password, "password_1234")
  643. } catch {
  644. XCTFail("error occurred")
  645. }
  646. }
  647. do {
  648. // Update Keychain items
  649. let keychain = Keychain(service: "Twitter")
  650. do {
  651. try keychain.set("katsumi_kishikawa", key: "username")
  652. XCTAssertTrue(true, "no error occurred")
  653. } catch {
  654. XCTFail("error occurred")
  655. }
  656. do {
  657. try keychain.set("1234_password", key: "password")
  658. XCTAssertTrue(true, "no error occurred")
  659. } catch {
  660. XCTFail("error occurred")
  661. }
  662. do {
  663. let username = try keychain.get("username")
  664. XCTAssertEqual(username, "katsumi_kishikawa")
  665. } catch {
  666. XCTFail("error occurred")
  667. }
  668. do {
  669. let password = try keychain.get("password")
  670. XCTAssertEqual(password, "1234_password")
  671. } catch {
  672. XCTFail("error occurred")
  673. }
  674. }
  675. do {
  676. // Remove Keychain items
  677. let keychain = Keychain(service: "Twitter")
  678. do {
  679. try keychain.remove("username")
  680. XCTAssertNil(try! keychain.get("username"))
  681. } catch {
  682. XCTFail("error occurred")
  683. }
  684. do {
  685. try keychain.remove("password")
  686. XCTAssertNil(try! keychain.get("username"))
  687. } catch {
  688. XCTFail("error occurred")
  689. }
  690. }
  691. }
  692. #endif
  693. // MARK:
  694. func testSetStringWithCustomService() {
  695. let username_1 = "kishikawakatsumi"
  696. let password_1 = "password1234"
  697. let username_2 = "kishikawa_katsumi"
  698. let password_2 = "password_1234"
  699. let username_3 = "k_katsumi"
  700. let password_3 = "12341234"
  701. let service_1 = ""
  702. let service_2 = "com.kishikawakatsumi.KeychainAccess"
  703. let service_3 = "example.com"
  704. do { try Keychain().removeAll() } catch {}
  705. do { try Keychain(service: service_1).removeAll() } catch {}
  706. do { try Keychain(service: service_2).removeAll() } catch {}
  707. do { try Keychain(service: service_3).removeAll() } catch {}
  708. XCTAssertNil(try! Keychain().get("username"), "not stored username")
  709. XCTAssertNil(try! Keychain().get("password"), "not stored password")
  710. XCTAssertNil(try! Keychain(service: service_1).get("username"), "not stored username")
  711. XCTAssertNil(try! Keychain(service: service_1).get("password"), "not stored password")
  712. XCTAssertNil(try! Keychain(service: service_2).get("username"), "not stored username")
  713. XCTAssertNil(try! Keychain(service: service_2).get("password"), "not stored password")
  714. XCTAssertNil(try! Keychain(service: service_3).get("username"), "not stored username")
  715. XCTAssertNil(try! Keychain(service: service_3).get("password"), "not stored password")
  716. do { try Keychain().set(username_1, key: "username") } catch {}
  717. XCTAssertEqual(try! Keychain().get("username"), username_1, "stored username")
  718. XCTAssertEqual(try! Keychain(service: service_1).get("username"), username_1, "stored username")
  719. XCTAssertNil(try! Keychain(service: service_2).get("username"), "not stored username")
  720. XCTAssertNil(try! Keychain(service: service_3).get("username"), "not stored username")
  721. do { try Keychain(service: service_1).set(username_1, key: "username") } catch {}
  722. XCTAssertEqual(try! Keychain().get("username"), username_1, "stored username")
  723. XCTAssertEqual(try! Keychain(service: service_1).get("username"), username_1, "stored username")
  724. XCTAssertNil(try! Keychain(service: service_2).get("username"), "not stored username")
  725. XCTAssertNil(try! Keychain(service: service_3).get("username"), "not stored username")
  726. do { try Keychain(service: service_2).set(username_2, key: "username") } catch {}
  727. XCTAssertEqual(try! Keychain().get("username"), username_1, "stored username")
  728. XCTAssertEqual(try! Keychain(service: service_1).get("username"), username_1, "stored username")
  729. XCTAssertEqual(try! Keychain(service: service_2).get("username"), username_2, "stored username")
  730. XCTAssertNil(try! Keychain(service: service_3).get("username"), "not stored username")
  731. do { try Keychain(service: service_3).set(username_3, key: "username") } catch {}
  732. XCTAssertEqual(try! Keychain().get("username"), username_1, "stored username")
  733. XCTAssertEqual(try! Keychain(service: service_1).get("username"), username_1, "stored username")
  734. XCTAssertEqual(try! Keychain(service: service_2).get("username"), username_2, "stored username")
  735. XCTAssertEqual(try! Keychain(service: service_3).get("username"), username_3, "stored username")
  736. do { try Keychain().set(password_1, key: "password") } catch {}
  737. XCTAssertEqual(try! Keychain().get("password"), password_1, "stored password")
  738. XCTAssertEqual(try! Keychain(service: service_1).get("password"), password_1, "stored password")
  739. XCTAssertNil(try! Keychain(service: service_2).get("password"), "not stored password")
  740. XCTAssertNil(try! Keychain(service: service_3).get("password"), "not stored password")
  741. do { try Keychain(service: service_1).set(password_1, key: "password") } catch {}
  742. XCTAssertEqual(try! Keychain().get("password"), password_1, "stored password")
  743. XCTAssertEqual(try! Keychain(service: service_1).get("password"), password_1, "stored password")
  744. XCTAssertNil(try! Keychain(service: service_2).get("password"), "not stored password")
  745. XCTAssertNil(try! Keychain(service: service_3).get("password"), "not stored password")
  746. do { try Keychain(service: service_2).set(password_2, key: "password") } catch {}
  747. XCTAssertEqual(try! Keychain().get("password"), password_1, "stored password")
  748. XCTAssertEqual(try! Keychain(service: service_1).get("password"), password_1, "stored password")
  749. XCTAssertEqual(try! Keychain(service: service_2).get("password"), password_2, "stored password")
  750. XCTAssertNil(try! Keychain(service: service_3).get("password"), "not stored password")
  751. do { try Keychain(service: service_3).set(password_3, key: "password") } catch {}
  752. XCTAssertEqual(try! Keychain().get("password"), password_1, "stored password")
  753. XCTAssertEqual(try! Keychain(service: service_1).get("password"), password_1, "stored password")
  754. XCTAssertEqual(try! Keychain(service: service_2).get("password"), password_2, "stored password")
  755. XCTAssertEqual(try! Keychain(service: service_3).get("password"), password_3, "stored password")
  756. do { try Keychain().remove("username") } catch {}
  757. XCTAssertNil(try! Keychain().get("username"), "removed username")
  758. XCTAssertNil(try! Keychain(service: service_1).get("username"), "removed username")
  759. XCTAssertEqual(try! Keychain(service: service_2).get("username"), username_2, "left username")
  760. XCTAssertEqual(try! Keychain(service: service_3).get("username"), username_3, "left username")
  761. do { try Keychain(service: service_1).remove("username") } catch {}
  762. XCTAssertNil(try! Keychain().get("username"), "removed username")
  763. XCTAssertNil(try! Keychain(service: service_1).get("username"), "removed username")
  764. XCTAssertEqual(try! Keychain(service: service_2).get("username"), username_2, "left username")
  765. XCTAssertEqual(try! Keychain(service: service_3).get("username"), username_3, "left username")
  766. do { try Keychain(service: service_2).remove("username") } catch {}
  767. XCTAssertNil(try! Keychain().get("username"), "removed username")
  768. XCTAssertNil(try! Keychain(service: service_1).get("username"), "removed username")
  769. XCTAssertNil(try! Keychain(service: service_2).get("username"), "removed username")
  770. XCTAssertEqual(try! Keychain(service: service_3).get("username"), username_3, "left username")
  771. do { try Keychain(service: service_3).remove("username") } catch {}
  772. XCTAssertNil(try! Keychain().get("username"), "removed username")
  773. XCTAssertNil(try! Keychain(service: service_1).get("username"), "removed username")
  774. XCTAssertNil(try! Keychain(service: service_2).get("username"), "removed username")
  775. XCTAssertNil(try! Keychain(service: service_3).get("username"), "removed username")
  776. do { try Keychain().remove("password") } catch {}
  777. XCTAssertNil(try! Keychain().get("password"), "removed password")
  778. XCTAssertNil(try! Keychain(service: service_1).get("password"), "removed password")
  779. XCTAssertEqual(try! Keychain(service: service_2).get("password"), password_2, "left password")
  780. XCTAssertEqual(try! Keychain(service: service_3).get("password"), password_3, "left password")
  781. do { try Keychain(service: service_1).remove("password") } catch {}
  782. XCTAssertNil(try! Keychain().get("password"), "removed password")
  783. XCTAssertNil(try! Keychain(service: service_1).get("password"), "removed password")
  784. XCTAssertEqual(try! Keychain(service: service_2).get("password"), password_2, "left password")
  785. XCTAssertEqual(try! Keychain(service: service_3).get("password"), password_3, "left password")
  786. do { try Keychain(service: service_2).remove("password") } catch {}
  787. XCTAssertNil(try! Keychain().get("password"), "removed password")
  788. XCTAssertNil(try! Keychain(service: service_1).get("password"), "removed password")
  789. XCTAssertNil(try! Keychain(service: service_2).get("password"), "removed password")
  790. XCTAssertEqual(try! Keychain(service: service_3).get("password"), password_3, "left password")
  791. do { try Keychain(service: service_3).remove("password") } catch {}
  792. XCTAssertNil(try! Keychain().get("password"), "removed password")
  793. XCTAssertNil(try! Keychain(service: service_2).get("password"), "removed password")
  794. XCTAssertNil(try! Keychain(service: service_2).get("password"), "removed password")
  795. XCTAssertNil(try! Keychain(service: service_2).get("password"), "removed password")
  796. }
  797. // MARK:
  798. func testProperties() {
  799. guard #available(OSX 10.10, *) else {
  800. return
  801. }
  802. let keychain = Keychain()
  803. XCTAssertEqual(keychain.synchronizable, false)
  804. XCTAssertEqual(keychain.synchronizable(true).synchronizable, true)
  805. XCTAssertEqual(keychain.synchronizable(false).synchronizable, false)
  806. XCTAssertEqual(keychain.accessibility(.AfterFirstUnlock).accessibility, Accessibility.AfterFirstUnlock)
  807. XCTAssertEqual(keychain.accessibility(.WhenPasscodeSetThisDeviceOnly, authenticationPolicy: .UserPresence).accessibility, Accessibility.WhenPasscodeSetThisDeviceOnly)
  808. XCTAssertEqual(keychain.accessibility(.WhenPasscodeSetThisDeviceOnly, authenticationPolicy: .UserPresence).authenticationPolicy, AuthenticationPolicy.UserPresence)
  809. XCTAssertNil(keychain.label)
  810. XCTAssertEqual(keychain.label("Label").label, "Label")
  811. XCTAssertNil(keychain.comment)
  812. XCTAssertEqual(keychain.comment("Comment").comment, "Comment")
  813. XCTAssertEqual(keychain.authenticationPrompt("Prompt").authenticationPrompt, "Prompt")
  814. }
  815. // MARK:
  816. #if os(iOS)
  817. func testAllKeys() {
  818. do {
  819. let keychain = Keychain()
  820. keychain["key1"] = "value1"
  821. keychain["key2"] = "value2"
  822. keychain["key3"] = "value3"
  823. let allKeys = keychain.allKeys()
  824. XCTAssertEqual(allKeys.count, 3)
  825. XCTAssertEqual(allKeys.sort(), ["key1", "key2", "key3"])
  826. let allItems = keychain.allItems()
  827. XCTAssertEqual(allItems.count, 3)
  828. let sortedItems = allItems.sort { (item1, item2) -> Bool in
  829. let value1 = item1["value"] as! String
  830. let value2 = item2["value"] as! String
  831. return value1.compare(value2) == NSComparisonResult.OrderedAscending || value1.compare(value2) == NSComparisonResult.OrderedSame
  832. }
  833. XCTAssertEqual(sortedItems[0]["accessGroup"] as? String, "")
  834. XCTAssertEqual(sortedItems[0]["synchronizable"] as? String, "false")
  835. XCTAssertEqual(sortedItems[0]["service"] as? String, "")
  836. XCTAssertEqual(sortedItems[0]["value"] as? String, "value1")
  837. XCTAssertEqual(sortedItems[0]["key"] as? String, "key1")
  838. XCTAssertEqual(sortedItems[0]["class"] as? String, "GenericPassword")
  839. XCTAssertEqual(sortedItems[0]["accessibility"] as? String, "AfterFirstUnlock")
  840. XCTAssertEqual(sortedItems[1]["accessGroup"] as? String, "")
  841. XCTAssertEqual(sortedItems[1]["synchronizable"] as? String, "false")
  842. XCTAssertEqual(sortedItems[1]["service"] as? String, "")
  843. XCTAssertEqual(sortedItems[1]["value"] as? String, "value2")
  844. XCTAssertEqual(sortedItems[1]["key"] as? String, "key2")
  845. XCTAssertEqual(sortedItems[1]["class"] as? String, "GenericPassword")
  846. XCTAssertEqual(sortedItems[1]["accessibility"] as? String, "AfterFirstUnlock")
  847. XCTAssertEqual(sortedItems[2]["accessGroup"] as? String, "")
  848. XCTAssertEqual(sortedItems[2]["synchronizable"] as? String, "false")
  849. XCTAssertEqual(sortedItems[2]["service"] as? String, "")
  850. XCTAssertEqual(sortedItems[2]["value"] as? String, "value3")
  851. XCTAssertEqual(sortedItems[2]["key"] as? String, "key3")
  852. XCTAssertEqual(sortedItems[2]["class"] as? String, "GenericPassword")
  853. XCTAssertEqual(sortedItems[2]["accessibility"] as? String, "AfterFirstUnlock")
  854. }
  855. do {
  856. let keychain = Keychain(service: "service1")
  857. try! keychain
  858. .synchronizable(true)
  859. .accessibility(.WhenUnlockedThisDeviceOnly)
  860. .set("service1_value1", key: "service1_key1")
  861. try! keychain
  862. .synchronizable(false)
  863. .accessibility(.AfterFirstUnlockThisDeviceOnly)
  864. .set("service1_value2", key: "service1_key2")
  865. let allKeys = keychain.allKeys()
  866. XCTAssertEqual(allKeys.count, 2)
  867. XCTAssertEqual(allKeys.sort(), ["service1_key1", "service1_key2"])
  868. let allItems = keychain.allItems()
  869. XCTAssertEqual(allItems.count, 2)
  870. let sortedItems = allItems.sort { (item1, item2) -> Bool in
  871. let value1 = item1["value"] as! String
  872. let value2 = item2["value"] as! String
  873. return value1.compare(value2) == NSComparisonResult.OrderedAscending || value1.compare(value2) == NSComparisonResult.OrderedSame
  874. }
  875. XCTAssertEqual(sortedItems[0]["accessGroup"] as? String, "")
  876. XCTAssertEqual(sortedItems[0]["synchronizable"] as? String, "true")
  877. XCTAssertEqual(sortedItems[0]["service"] as? String, "service1")
  878. XCTAssertEqual(sortedItems[0]["value"] as? String, "service1_value1")
  879. XCTAssertEqual(sortedItems[0]["key"] as? String, "service1_key1")
  880. XCTAssertEqual(sortedItems[0]["class"] as? String, "GenericPassword")
  881. XCTAssertEqual(sortedItems[0]["accessibility"] as? String, "WhenUnlockedThisDeviceOnly")
  882. XCTAssertEqual(sortedItems[1]["accessGroup"] as? String, "")
  883. XCTAssertEqual(sortedItems[1]["synchronizable"] as? String, "false")
  884. XCTAssertEqual(sortedItems[1]["service"] as? String, "service1")
  885. XCTAssertEqual(sortedItems[1]["value"] as? String, "service1_value2")
  886. XCTAssertEqual(sortedItems[1]["key"] as? String, "service1_key2")
  887. XCTAssertEqual(sortedItems[1]["class"] as? String, "GenericPassword")
  888. XCTAssertEqual(sortedItems[1]["accessibility"] as? String, "AfterFirstUnlockThisDeviceOnly")
  889. }
  890. do {
  891. let keychain = Keychain(server: "https://google.com", protocolType: .HTTPS)
  892. try! keychain
  893. .synchronizable(false)
  894. .accessibility(.AlwaysThisDeviceOnly)
  895. .set("google.com_value1", key: "google.com_key1")
  896. try! keychain
  897. .synchronizable(true)
  898. .accessibility(.Always)
  899. .set("google.com_value2", key: "google.com_key2")
  900. let allKeys = keychain.allKeys()
  901. XCTAssertEqual(allKeys.count, 2)
  902. XCTAssertEqual(allKeys.sort(), ["google.com_key1", "google.com_key2"])
  903. let allItems = keychain.allItems()
  904. XCTAssertEqual(allItems.count, 2)
  905. let sortedItems = allItems.sort { (item1, item2) -> Bool in
  906. let value1 = item1["value"] as! String
  907. let value2 = item2["value"] as! String
  908. return value1.compare(value2) == NSComparisonResult.OrderedAscending || value1.compare(value2) == NSComparisonResult.OrderedSame
  909. }
  910. XCTAssertEqual(sortedItems[0]["synchronizable"] as? String, "false")
  911. XCTAssertEqual(sortedItems[0]["value"] as? String, "google.com_value1")
  912. XCTAssertEqual(sortedItems[0]["key"] as? String, "google.com_key1")
  913. XCTAssertEqual(sortedItems[0]["server"] as? String, "google.com")
  914. XCTAssertEqual(sortedItems[0]["class"] as? String, "InternetPassword")
  915. XCTAssertEqual(sortedItems[0]["authenticationType"] as? String, "Default")
  916. XCTAssertEqual(sortedItems[0]["protocol"] as? String, "HTTPS")
  917. XCTAssertEqual(sortedItems[0]["accessibility"] as? String, "AlwaysThisDeviceOnly")
  918. XCTAssertEqual(sortedItems[1]["synchronizable"] as? String, "true")
  919. XCTAssertEqual(sortedItems[1]["value"] as? String, "google.com_value2")
  920. XCTAssertEqual(sortedItems[1]["key"] as? String, "google.com_key2")
  921. XCTAssertEqual(sortedItems[1]["server"] as? String, "google.com")
  922. XCTAssertEqual(sortedItems[1]["class"] as? String, "InternetPassword")
  923. XCTAssertEqual(sortedItems[1]["authenticationType"] as? String, "Default")
  924. XCTAssertEqual(sortedItems[1]["protocol"] as? String, "HTTPS")
  925. XCTAssertEqual(sortedItems[1]["accessibility"] as? String, "Always")
  926. }
  927. do {
  928. let allKeys = Keychain.allKeys(.GenericPassword)
  929. XCTAssertEqual(allKeys.count, 5)
  930. let sortedKeys = allKeys.sort { (key1, key2) -> Bool in
  931. return key1.1.compare(key2.1) == NSComparisonResult.OrderedAscending || key1.1.compare(key2.1) == NSComparisonResult.OrderedSame
  932. }
  933. XCTAssertEqual(sortedKeys[0].0, "")
  934. XCTAssertEqual(sortedKeys[0].1, "key1")
  935. XCTAssertEqual(sortedKeys[1].0, "")
  936. XCTAssertEqual(sortedKeys[1].1, "key2")
  937. XCTAssertEqual(sortedKeys[2].0, "")
  938. XCTAssertEqual(sortedKeys[2].1, "key3")
  939. XCTAssertEqual(sortedKeys[3].0, "service1")
  940. XCTAssertEqual(sortedKeys[3].1, "service1_key1")
  941. XCTAssertEqual(sortedKeys[4].0, "service1")
  942. XCTAssertEqual(sortedKeys[4].1, "service1_key2")
  943. }
  944. do {
  945. let allKeys = Keychain.allKeys(.InternetPassword)
  946. XCTAssertEqual(allKeys.count, 2)
  947. let sortedKeys = allKeys.sort { (key1, key2) -> Bool in
  948. return key1.1.compare(key2.1) == NSComparisonResult.OrderedAscending || key1.1.compare(key2.1) == NSComparisonResult.OrderedSame
  949. }
  950. XCTAssertEqual(sortedKeys[0].0, "google.com")
  951. XCTAssertEqual(sortedKeys[0].1, "google.com_key1")
  952. XCTAssertEqual(sortedKeys[1].0, "google.com")
  953. XCTAssertEqual(sortedKeys[1].1, "google.com_key2")
  954. }
  955. }
  956. func testDescription() {
  957. do {
  958. let keychain = Keychain()
  959. XCTAssertEqual(keychain.description, "[]")
  960. XCTAssertEqual(keychain.debugDescription, "[]")
  961. }
  962. }
  963. #endif
  964. // MARK:
  965. func testAuthenticationPolicy() {
  966. guard #available(iOS 9.0, OSX 10.11, *) else {
  967. return
  968. }
  969. do {
  970. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  971. let policy: AuthenticationPolicy = [.UserPresence]
  972. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  973. var error: Unmanaged<CFError>?
  974. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  975. XCTAssertNil(error)
  976. XCTAssertNotNil(accessControl)
  977. }
  978. #if os(iOS)
  979. do {
  980. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  981. let policy: AuthenticationPolicy = [.UserPresence, .ApplicationPassword]
  982. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  983. var error: Unmanaged<CFError>?
  984. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  985. XCTAssertNil(error)
  986. XCTAssertNotNil(accessControl)
  987. }
  988. do {
  989. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  990. let policy: AuthenticationPolicy = [.UserPresence, .ApplicationPassword, .PrivateKeyUsage]
  991. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  992. var error: Unmanaged<CFError>?
  993. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  994. XCTAssertNil(error)
  995. XCTAssertNotNil(accessControl)
  996. }
  997. do {
  998. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  999. let policy: AuthenticationPolicy = [.ApplicationPassword]
  1000. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1001. var error: Unmanaged<CFError>?
  1002. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1003. XCTAssertNil(error)
  1004. XCTAssertNotNil(accessControl)
  1005. }
  1006. do {
  1007. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1008. let policy: AuthenticationPolicy = [.ApplicationPassword, .PrivateKeyUsage]
  1009. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1010. var error: Unmanaged<CFError>?
  1011. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1012. XCTAssertNil(error)
  1013. XCTAssertNotNil(accessControl)
  1014. }
  1015. do {
  1016. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1017. let policy: AuthenticationPolicy = [.PrivateKeyUsage]
  1018. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1019. var error: Unmanaged<CFError>?
  1020. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1021. XCTAssertNil(error)
  1022. XCTAssertNotNil(accessControl)
  1023. }
  1024. do {
  1025. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1026. let policy: AuthenticationPolicy = [.TouchIDAny]
  1027. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1028. var error: Unmanaged<CFError>?
  1029. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1030. XCTAssertNil(error)
  1031. XCTAssertNotNil(accessControl)
  1032. }
  1033. do {
  1034. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1035. let policy: AuthenticationPolicy = [.TouchIDAny, .DevicePasscode]
  1036. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1037. var error: Unmanaged<CFError>?
  1038. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1039. XCTAssertNil(error)
  1040. XCTAssertNotNil(accessControl)
  1041. }
  1042. do {
  1043. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1044. let policy: AuthenticationPolicy = [.TouchIDAny, .ApplicationPassword]
  1045. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1046. var error: Unmanaged<CFError>?
  1047. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1048. XCTAssertNil(error)
  1049. XCTAssertNotNil(accessControl)
  1050. }
  1051. do {
  1052. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1053. let policy: AuthenticationPolicy = [.TouchIDAny, .ApplicationPassword, .PrivateKeyUsage]
  1054. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1055. var error: Unmanaged<CFError>?
  1056. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1057. XCTAssertNil(error)
  1058. XCTAssertNotNil(accessControl)
  1059. }
  1060. do {
  1061. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1062. let policy: AuthenticationPolicy = [.TouchIDCurrentSet]
  1063. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1064. var error: Unmanaged<CFError>?
  1065. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1066. XCTAssertNil(error)
  1067. XCTAssertNotNil(accessControl)
  1068. }
  1069. do {
  1070. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1071. let policy: AuthenticationPolicy = [.TouchIDCurrentSet, .DevicePasscode]
  1072. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1073. var error: Unmanaged<CFError>?
  1074. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1075. XCTAssertNil(error)
  1076. XCTAssertNotNil(accessControl)
  1077. }
  1078. do {
  1079. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1080. let policy: AuthenticationPolicy = [.TouchIDCurrentSet, .ApplicationPassword]
  1081. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1082. var error: Unmanaged<CFError>?
  1083. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1084. XCTAssertNil(error)
  1085. XCTAssertNotNil(accessControl)
  1086. }
  1087. do {
  1088. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1089. let policy: AuthenticationPolicy = [.TouchIDCurrentSet, .ApplicationPassword, .PrivateKeyUsage]
  1090. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1091. var error: Unmanaged<CFError>?
  1092. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1093. XCTAssertNil(error)
  1094. XCTAssertNotNil(accessControl)
  1095. }
  1096. do {
  1097. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1098. let policy: AuthenticationPolicy = [.TouchIDAny, .Or, .DevicePasscode]
  1099. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1100. var error: Unmanaged<CFError>?
  1101. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1102. XCTAssertNil(error)
  1103. XCTAssertNotNil(accessControl)
  1104. }
  1105. do {
  1106. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1107. let policy: AuthenticationPolicy = [.TouchIDAny, .And, .DevicePasscode]
  1108. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1109. var error: Unmanaged<CFError>?
  1110. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1111. XCTAssertNil(error)
  1112. XCTAssertNotNil(accessControl)
  1113. }
  1114. #endif
  1115. #if os(OSX)
  1116. do {
  1117. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1118. let policy: AuthenticationPolicy = [.UserPresence]
  1119. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1120. var error: Unmanaged<CFError>?
  1121. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1122. XCTAssertNil(error)
  1123. XCTAssertNotNil(accessControl)
  1124. }
  1125. do {
  1126. let accessibility: Accessibility = .WhenPasscodeSetThisDeviceOnly
  1127. let policy: AuthenticationPolicy = [.DevicePasscode]
  1128. let flags = SecAccessControlCreateFlags(rawValue: policy.rawValue)
  1129. var error: Unmanaged<CFError>?
  1130. let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, accessibility.rawValue, flags, &error)
  1131. XCTAssertNil(error)
  1132. XCTAssertNotNil(accessControl)
  1133. }
  1134. #endif
  1135. }
  1136. }