SafeTests.swift 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. // _____ _
  2. // |_ _| |_ _ _ ___ ___ _ __ __ _
  3. // | | | ' \| '_/ -_) -_) ' \/ _` |_
  4. // |_| |_||_|_| \___\___|_|_|_\__,_(_)
  5. //
  6. // Threema iOS Client
  7. // Copyright (c) 2018-2020 Threema GmbH
  8. //
  9. // This program is free software: you can redistribute it and/or modify
  10. // it under the terms of the GNU Affero General Public License, version 3,
  11. // as published by the Free Software Foundation.
  12. //
  13. // This program is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. // GNU Affero General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Affero General Public License
  19. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. import XCTest
  21. //import ThreemaFramework
  22. @testable import Threema
  23. class SafeTests: XCTestCase {
  24. override func setUp() {
  25. super.setUp()
  26. // necessary for ValidationLogger
  27. AppGroup.setGroupId("group.ch.threema") //THREEMA_GROUP_IDENTIFIER @"group.ch.threema"
  28. }
  29. override func tearDown() {
  30. super.tearDown()
  31. }
  32. func testSafeSha1() {
  33. let safeStore = SafeStore(safeConfigManager: SafeConfigManager(), serverApiConnector: ServerAPIConnector())
  34. let sha1a = safeStore.sha1(data: Data([1]))
  35. let sha1b = safeStore.sha1(data: Data([1]))
  36. XCTAssertTrue(sha1a == sha1b)
  37. }
  38. func testSafeJsonParserCreate() -> Void {
  39. let parser = SafeJsonParser()
  40. let safeBackupData = parser.getSafeBackupData()
  41. let json = parser.getJsonAsString(from: safeBackupData)
  42. XCTAssertNotNil(json)
  43. XCTAssertEqual(json, "{\"info\":{\"version\":1,\"device\":\"ios\"}}")
  44. }
  45. func testSafeJsonParserUser() -> Void {
  46. let user = SafeJsonParser.SafeBackupData.User(privatekey: "key123")
  47. user.nickname = "nicki"
  48. user.profilePic = "pic source"
  49. user.profilePicRelease = ["ECHOECHO", "TEST1234"]
  50. user.links = [SafeJsonParser.SafeBackupData.User.Link (type: "email", value: "a@a.a")]
  51. let parser = SafeJsonParser()
  52. var safeBackupData = parser.getSafeBackupData()
  53. safeBackupData.user = user
  54. let json = parser.getJsonAsString(from: safeBackupData)
  55. XCTAssertNotNil(json)
  56. XCTAssertNotNil(json?.range(of: "\"privatekey\":\"key123\""))
  57. XCTAssertNotNil(json?.range(of: "\"nickname\":\"nicki\""))
  58. XCTAssertNotNil(json?.range(of: "\"profilePic\":\"pic source\""))
  59. XCTAssertNotNil(json?.range(of: "\"profilePicRelease\":[\"ECHOECHO\",\"TEST1234\"]"))
  60. XCTAssertNotNil(json?.range(of: "{\"links\":[{"))
  61. XCTAssertNotNil(json?.range(of: "\"type\":\"email\""))
  62. XCTAssertNotNil(json?.range(of: "\"value\":\"a@a.a\""))
  63. XCTAssertNotNil(json?.range(of: "}]"))
  64. }
  65. func testSafeJsonParserLoad() -> Void {
  66. let json = "{\"info\":{\"version\":1,\"device\":\"ios\"},\"user\":{\"links\":[{\"type\":\"email\",\"name\":\"privat\",\"value\":\"a@a.a\"}],\"nickname\":\"nicki\",\"privatekey\":\"key123\",\"profilePic\":\"pic source\",\"profilePicRelease\":[\"ECHOECHO\",\"TEST1234\"]}}"
  67. let parser = SafeJsonParser()
  68. let safeBackupData = try! parser.getSafeBackupData(from: json.data(using: .utf8)!)
  69. XCTAssertNotNil(safeBackupData)
  70. XCTAssertEqual(safeBackupData.user?.nickname, "nicki")
  71. }
  72. func testSafeStoreCreateKey() -> Void {
  73. let store = SafeStore(safeConfigManager: SafeConfigManager(), serverApiConnector: ServerAPIConnector())
  74. let result = store.createKey(identity: "ECHOECHO", password: "shootdeathstar")
  75. XCTAssertEqual(hexString(data: result!),
  76. "066384d3695fbbd9f31a7d533900fd0cd8d1373beb6a28678522d2a49980c9c351c3d8d752fb6e1fd3199ead7f0895d6e3893ff691f2a5ee1976ed0897fc2f66")
  77. }
  78. func testSafeStoreGetBackupIdAndGetEncrptionKey() -> Void {
  79. let store = SafeStore(safeConfigManager: SafeConfigManager(), serverApiConnector: ServerAPIConnector())
  80. let key = store.createKey(identity: "ECHOECHO", password: "shootdeathstar")
  81. let backupId = store.getBackupId(key: key!)
  82. let encryptionKey = store.getEncryptionKey(key: key!)
  83. XCTAssertNotNil(backupId)
  84. XCTAssertNotNil(encryptionKey)
  85. XCTAssertEqual(32, backupId?.count)
  86. XCTAssertEqual(32, encryptionKey?.count)
  87. XCTAssertFalse(backupId!.elementsEqual(encryptionKey!))
  88. }
  89. private func hexString(data: [UInt8]) -> String {
  90. return data.map { String(format: "%02hhx", $0) }.joined(separator: "")
  91. }
  92. func testSafeStoreBackupDataEncryptDecrypt() {
  93. let user = SafeJsonParser.SafeBackupData.User(privatekey: "key123")
  94. user.nickname = "nicki"
  95. let parser = SafeJsonParser()
  96. var dataIn = parser.getSafeBackupData()
  97. dataIn.user = user;
  98. let store = SafeStore(safeConfigManager: SafeConfigManager(), serverApiConnector: ServerAPIConnector())
  99. let key = store.createKey(identity: "ECHOECHO", password: "shootdeathstar")
  100. let encryptedData = try! store.encryptBackupData(key: key!, data: parser.getJsonAsBytes(from: dataIn)!)
  101. let decryptedData = try! store.decryptBackupData(key: key!, data: encryptedData)
  102. let dataOut = try! parser.getSafeBackupData(from: Data(decryptedData))
  103. XCTAssertNotNil(dataOut.user)
  104. XCTAssertEqual("key123", dataOut.user?.privatekey)
  105. XCTAssertEqual("nicki", dataOut.user?.nickname)
  106. }
  107. func testSafeManagerIsPasswordBad() {
  108. let passwordTests = [
  109. ["", true],
  110. ["1", true],
  111. ["a", true],
  112. ["aaaaaaaa", true],
  113. ["11111111", true],
  114. ["1111111w", false],
  115. ["83497585", true],
  116. ["123456789012345", true],
  117. ["1234567890123456", false],
  118. ["7777777777777777", true],
  119. ["834975 8", false],
  120. ["83497 8", true],
  121. [" ", true],
  122. ["0000000000d", true],
  123. ["ronaldo7", true],
  124. ["Zzzzzzz1", true]
  125. ]
  126. let safeConfigManager = SafeConfigManager()
  127. let safeStore = SafeStore(safeConfigManager: safeConfigManager, serverApiConnector: ServerAPIConnector())
  128. let safeManager: SafeManager = SafeManager(safeConfigManager: safeConfigManager, safeStore: safeStore, safeApiService: SafeApiService())
  129. for passwordTest in passwordTests {
  130. let isBad = safeManager.isPasswordBad(password: passwordTest[0] as! String)
  131. if passwordTest[1] as! Bool {
  132. XCTAssert(isBad, "\(passwordTest[0]) isBad:\(isBad)")
  133. } else {
  134. XCTAssertFalse(isBad, "\(passwordTest[0]) isBad:\(isBad)")
  135. }
  136. }
  137. }
  138. func testSafeManagerIsPasswordPatternValid() {
  139. let passwordTests = [
  140. ["", false],
  141. ["12345678aA", true],
  142. ["123456789aA", true],
  143. ["1234567aA", false],
  144. ["12345678aa", false],
  145. ]
  146. // Password min. length 10 with min. one lowercase and one uppercase character
  147. let regExPattern: String = "(?=(.*[0-9]))(?=.*[a-z])(?=(.*[A-Z]))(?=(.*)).{10,}"
  148. for passwordTest in passwordTests {
  149. let result = try? SafeManager.isPasswordPatternValid(password: passwordTest[0] as! String, regExPattern: regExPattern)
  150. XCTAssertEqual(result, passwordTest[1] as! Bool)
  151. }
  152. }
  153. /*
  154. func testApi() {
  155. let asyncDone = expectation(description: "async func")
  156. var identity: String?
  157. let api = ServerAPIConnector()
  158. api.fetchBulkIdentityInfo(["ECHOECHO"], onCompletion: { (identities, publicKeys, featureLevels, featureMasks, states, types) in
  159. if let identities = identities as? [String] {
  160. print(identities.count)
  161. identity = identities[0] as String
  162. }
  163. asyncDone.fulfill()
  164. }) { (error) in
  165. print(error)
  166. asyncDone.fulfill()
  167. }
  168. wait(for: [asyncDone], timeout: 10)
  169. XCTAssertEqual("ECHOECHO", identity)
  170. }
  171. */
  172. func testSafeSeverToDisplay() {
  173. let store = SafeStore(safeConfigManager: SafeConfigManagerMock(server: nil), serverApiConnector: ServerAPIConnector())
  174. let result = store.getSafeServerToDisplay()
  175. XCTAssertNotNil(result)
  176. }
  177. func testSafeServerUrlDefault() {
  178. let store = SafeStore(safeConfigManager: SafeConfigManagerMock(server: nil), serverApiConnector: ServerAPIConnector())
  179. let key = store.createKey(identity: "ECHOECHO", password: "shootdeathstar")!
  180. let url = store.getSafeServer(key: key)
  181. XCTAssertNotNil(url)
  182. XCTAssertEqual(url?.absoluteString, "https://safe-06.threema.ch")
  183. XCTAssertEqual(url?.appendingPathComponent("backups/\(SafeStore.dataToHexString(store.getBackupId(key: key)!))").absoluteString, "https://safe-06.threema.ch/backups/066384d3695fbbd9f31a7d533900fd0cd8d1373beb6a28678522d2a49980c9c3")
  184. }
  185. func testSafeServerUrlCustom() {
  186. let store = SafeStore(safeConfigManager: SafeConfigManagerMock(server: "http://test.com"), serverApiConnector: ServerAPIConnector())
  187. let key = store.createKey(identity: "ECHOECHO", password: "shootdeathstar")!
  188. let url = store.getSafeServer(key: key)
  189. XCTAssertNotNil(url)
  190. XCTAssertEqual(url?.absoluteString, "http://test.com")
  191. XCTAssertEqual(url?.appendingPathComponent("backups/\(SafeStore.dataToHexString(store.getBackupId(key: key)!))").absoluteString, "http://test.com/backups/066384d3695fbbd9f31a7d533900fd0cd8d1373beb6a28678522d2a49980c9c3")
  192. }
  193. func testComposeSafeServerAuth() {
  194. let serverUrlTests = [
  195. [nil, nil, nil, nil],
  196. ["https://example.com/", nil, nil, "https://example.com/"],
  197. ["https://example.com/", "test.tester@app.com", nil, "https://test.tester%40app.com:@example.com/"],
  198. ["https://example.com/", "test.tester@app.com", "passphrase", "https://test.tester%40app.com:passphrase@example.com/"],
  199. ["https://example.com", "test.tester@app.com", "püssiKösch", "https://test.tester%40app.com:p%C3%BCssiK%C3%B6sch@example.com"],
  200. ["example.com", "test.tester@app.com", "püssiKösch", "https://test.tester%40app.com:p%C3%BCssiK%C3%B6sch@example.com"],
  201. ["https://example.com/", nil, "passphrase", "https://:passphrase@example.com/"],
  202. ["HTTPS://example.com", nil, nil, "HTTPS://example.com"],
  203. ["HTtPS://example.com", nil, nil, "HTtPS://example.com"],
  204. ["http://example.com", nil, nil, nil],
  205. ["https://exämple.com", nil, nil, nil],
  206. ]
  207. let store = SafeStore(safeConfigManager: SafeConfigManager(), serverApiConnector: ServerAPIConnector())
  208. for serverUrlTest in serverUrlTests {
  209. let url = store.composeSafeServerAuth(server: serverUrlTest[0], user: serverUrlTest[1], password: serverUrlTest[2])
  210. if serverUrlTest[3] != nil {
  211. XCTAssertNotNil(url)
  212. XCTAssertEqual(url?.absoluteString, serverUrlTest[3])
  213. } else {
  214. XCTAssertNil(url)
  215. }
  216. }
  217. }
  218. func testExtractSafeServerAuth() {
  219. let serverUrlTests = [
  220. ["https://example.com/", nil, nil, "https://example.com/"],
  221. ["https://test.tester%40app.com:@example.com/", "test.tester@app.com", "", "https://example.com/"],
  222. ["https://test.tester%40app.com:passphrase@example.com/", "test.tester@app.com", "passphrase", "https://example.com/"],
  223. ["https://test.tester%40app.com:p%C3%BCssiK%C3%B6sch@example.com", "test.tester@app.com", "püssiKösch", "https://example.com"],
  224. ["https://:passphrase@example.com/", "", "passphrase", "https://example.com/"],
  225. ["https://passphrase@example.com/", "passphrase", nil, "https://example.com/"],
  226. ["HTTPS://example.com", nil, nil, "HTTPS://example.com"],
  227. ["HTtPS://example.com", nil, nil, "HTtPS://example.com"],
  228. ["http://example.com", nil, nil, "http://example.com"],
  229. ]
  230. let store = SafeStore(safeConfigManager: SafeConfigManager(), serverApiConnector: ServerAPIConnector())
  231. for serverUrlTest in serverUrlTests {
  232. let safeServerAuth = store.extractSafeServerAuth(server: URL(string: serverUrlTest[0]!)!)
  233. XCTAssertEqual(serverUrlTest[1], safeServerAuth.user)
  234. XCTAssertEqual(serverUrlTest[2], safeServerAuth.password)
  235. XCTAssertEqual(URL(string: serverUrlTest[3]!)!, safeServerAuth.server)
  236. }
  237. }
  238. }