Skip to content

Commit

Permalink
chore: Merge branch 'master' into more-macos
Browse files Browse the repository at this point in the history
  • Loading branch information
adrien-coye committed Jan 23, 2024
2 parents 5febafe + 162b153 commit ca38968
Show file tree
Hide file tree
Showing 27 changed files with 498 additions and 403 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ jobs:
- name: Checkout
uses: actions/checkout@v2
- name: Build
run: swift build
run: xcodebuild -scheme InfomaniakCore build -destination "platform=iOS Simulator,name=iPhone 13,OS=latest"
- name: Test
run: swift test
run: xcodebuild -scheme InfomaniakCore test -destination "platform=iOS Simulator,name=iPhone 13,OS=latest"

build_and_test_macOS:
name: Build and Test project on macOS
Expand Down
15 changes: 15 additions & 0 deletions .sonarcloud.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
## Path to sources
sonar.sources=Sources
# sonar.exclusions=
# sonar.inclusions=

## Path to tests
sonar.tests=Tests
# sonar.test.exclusions=
# sonar.test.inclusions=

## Source encoding
# sonar.sourceEncoding=

# Exclusions for copy-paste detection
# sonar.cpd.exclusions=
43 changes: 26 additions & 17 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -5,71 +5,80 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/Alamofire/Alamofire",
"state" : {
"revision" : "bc268c28fb170f494de9e9927c371b8342979ece",
"version" : "5.7.1"
"revision" : "3dc6a42c7727c49bf26508e29b0a0b35f9c7e1ad",
"version" : "5.8.1"
}
},
{
"identity" : "cocoalumberjack",
"kind" : "remoteSourceControl",
"location" : "https://github.com/CocoaLumberjack/CocoaLumberjack.git",
"location" : "https://github.com/CocoaLumberjack/CocoaLumberjack",
"state" : {
"revision" : "0188d31089b5881a269e01777be74c7316924346",
"version" : "3.8.0"
"revision" : "363ed23d19a931809ea834a7d722da830353806a",
"version" : "3.8.2"
}
},
{
"identity" : "ios-dependency-injection",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Infomaniak/ios-dependency-injection",
"state" : {
"revision" : "41a99aeb652d5294355129bfa70d1ea8c17b9980",
"version" : "1.1.10"
"revision" : "8dc9e67e6d3d9f4f5bd02d693a7ce1f93b125bcd",
"version" : "2.0.1"
}
},
{
"identity" : "ios-login",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Infomaniak/ios-login",
"state" : {
"revision" : "904c1ac39b4db56212302b464a0b2e023d9b5791",
"version" : "6.0.0"
}
},
{
"identity" : "realm-core",
"kind" : "remoteSourceControl",
"location" : "https://github.com/realm/realm-core.git",
"state" : {
"revision" : "f1434caadda443b4ed2261b91ea4f43ab1ee2aa5",
"version" : "13.15.1"
"revision" : "7227d6a447821c28895daa099b6c7cd4c99d461b",
"version" : "13.25.1"
}
},
{
"identity" : "realm-swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/realm/realm-swift",
"state" : {
"revision" : "b287dc102036ff425bd8a88483f0a5596871f05e",
"version" : "10.41.0"
"revision" : "836cc4b8619886f979f8961c3f592a82b0741591",
"version" : "10.45.3"
}
},
{
"identity" : "sentry-cocoa",
"kind" : "remoteSourceControl",
"location" : "https://github.com/getsentry/sentry-cocoa",
"state" : {
"revision" : "e46936ed191c0112cd3276e1c10c0bb7f865268e",
"version" : "8.9.1"
"revision" : "3b9a8e69ca296bd8cd0e317ad7a448e5daf4a342",
"version" : "8.18.0"
}
},
{
"identity" : "swift-log",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-log.git",
"state" : {
"revision" : "32e8d724467f8fe623624570367e3d50c5638e46",
"version" : "1.5.2"
"revision" : "532d8b529501fb73a2455b179e0bbb6d49b652ed",
"version" : "1.5.3"
}
},
{
"identity" : "zipfoundation",
"kind" : "remoteSourceControl",
"location" : "https://github.com/weichsel/ZIPFoundation.git",
"state" : {
"revision" : "43ec568034b3731101dbf7670765d671c30f54f3",
"version" : "0.9.16"
"revision" : "a3f5c2bae0f04b0bce9ef3c4ba6bd1031a0564c4",
"version" : "0.9.17"
}
}
],
Expand Down
12 changes: 7 additions & 5 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ let package = Package(
)
],
dependencies: [
.package(url: "https://github.com/Infomaniak/ios-dependency-injection", .upToNextMajor(from: "1.1.10")),
.package(url: "https://github.com/Alamofire/Alamofire", .upToNextMajor(from: "5.2.2")),
.package(url: "https://github.com/getsentry/sentry-cocoa", .upToNextMajor(from: "8.3.1")),
.package(url: "https://github.com/realm/realm-swift", .upToNextMajor(from: "10.0.0")),
.package(url: "https://github.com/CocoaLumberjack/CocoaLumberjack", .upToNextMajor(from: "3.7.0")),
.package(url: "https://github.com/Infomaniak/ios-dependency-injection", .upToNextMajor(from: "2.0.0")),
.package(url: "https://github.com/Infomaniak/ios-login", .upToNextMajor(from: "6.0.0")),
.package(url: "https://github.com/Alamofire/Alamofire", .upToNextMajor(from: "5.8.0")),
.package(url: "https://github.com/getsentry/sentry-cocoa", .upToNextMajor(from: "8.18.0")),
.package(url: "https://github.com/realm/realm-swift", .upToNextMajor(from: "10.45.0")),
.package(url: "https://github.com/CocoaLumberjack/CocoaLumberjack", .upToNextMajor(from: "3.8.0")),
.package(url: "https://github.com/weichsel/ZIPFoundation.git", .upToNextMajor(from: "0.9.0"))
],
targets: [
Expand All @@ -29,6 +30,7 @@ let package = Package(
dependencies: [
"Alamofire",
.product(name: "InfomaniakDI", package: "ios-dependency-injection"),
.product(name: "InfomaniakLogin", package: "ios-login"),
.product(name: "Sentry", package: "sentry-cocoa"),
.product(name: "RealmSwift", package: "realm-swift"),
.product(name: "CocoaLumberjackSwift", package: "CocoaLumberjack"),
Expand Down
1 change: 1 addition & 0 deletions Sources/InfomaniakCore/Account/Account.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/

import Foundation
import InfomaniakLogin

public protocol AccountUpdateDelegate {
func didUpdateCurrentAccount(_ account: Account)
Expand Down
90 changes: 58 additions & 32 deletions Sources/InfomaniakCore/Account/KeychainHelper.swift
Original file line number Diff line number Diff line change
@@ -1,43 +1,44 @@
/*
Infomaniak Core - iOS
Copyright (C) 2023 Infomaniak Network SA
This program 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.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/

import CocoaLumberjackSwift
import Foundation
import InfomaniakLogin
import Sentry

public class KeychainHelper {
let accessGroup: String
let tag = "ch.infomaniak.token".data(using: .utf8)!
let keychainQueue = DispatchQueue(label: "com.infomaniak.keychain")

let lockedKey = "isLockedKey"
let lockedValue = "locked".data(using: .utf8)!
var accessibilityValueWritten = false

public init(accessGroup: String) {
self.accessGroup = accessGroup
}

public var isKeychainAccessible: Bool {
if !accessibilityValueWritten {
initKeychainAccessibility()
}

let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: lockedKey,
Expand All @@ -47,13 +48,13 @@ public class KeychainHelper {
kSecReturnRef as String: kCFBooleanTrue as Any,
kSecMatchLimit as String: kSecMatchLimitAll
]

var result: AnyObject?

let resultCode = withUnsafeMutablePointer(to: &result) {
SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0))
}

if resultCode == noErr, let array = result as? [[String: Any]] {
for item in array {
if let value = item[kSecValueData as String] as? Data {
Expand All @@ -66,7 +67,7 @@ public class KeychainHelper {
return false
}
}

func initKeychainAccessibility() {
accessibilityValueWritten = true
let queryAdd: [String: Any] = [
Expand All @@ -81,7 +82,7 @@ public class KeychainHelper {
"[Keychain] Successfully init KeychainHelper ? \(resultCode == noErr || resultCode == errSecDuplicateItem), \(resultCode)"
)
}

public func deleteToken(for userId: Int) {
keychainQueue.sync {
let queryDelete: [String: Any] = [
Expand All @@ -93,7 +94,7 @@ public class KeychainHelper {
DDLogInfo("Successfully deleted token ? \(resultCode == noErr)")
}
}

public func deleteAllTokens() {
keychainQueue.sync {
let queryDelete: [String: Any] = [
Expand All @@ -104,27 +105,38 @@ public class KeychainHelper {
DDLogInfo("Successfully deleted all tokens ? \(resultCode == noErr)")
}
}

public func storeToken(_ token: ApiToken) {
var resultCode: OSStatus = noErr

let tokenData = try! JSONEncoder().encode(token)

if let savedToken = getSavedToken(for: token.userId) {
keychainQueue.sync {
let queryUpdate: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: "\(token.userId)"
]

let attributes: [String: Any] = [
kSecValueData as String: tokenData
]

// Save token only if it's more recent
if savedToken.expirationDate <= token.expirationDate {
let queryUpdate: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: "\(token.userId)"
]

let attributes: [String: Any] = [
kSecValueData as String: tokenData
]
if let savedTokenExpirationDate = savedToken.expirationDate,
let newTokenExpirationDate = token.expirationDate,
savedTokenExpirationDate <= newTokenExpirationDate {
resultCode = SecItemUpdate(queryUpdate as CFDictionary, attributes as CFDictionary)
DDLogInfo("Successfully updated token ? \(resultCode == noErr)")
SentrySDK.addBreadcrumb(token.generateBreadcrumb(level: .info, message: "Successfully updated token"))
} else if savedToken.expirationDate == nil || token.expirationDate == nil {
// Or if one of them is now an infinite refresh token
resultCode = SecItemUpdate(queryUpdate as CFDictionary, attributes as CFDictionary)
DDLogInfo("Successfully updated unlimited token ? \(resultCode == noErr)")
SentrySDK.addBreadcrumb(token.generateBreadcrumb(
level: .info,
message: "Successfully updated unlimited token"
))
}
}
} else {
Expand All @@ -149,7 +161,7 @@ public class KeychainHelper {
.generateBreadcrumb(level: .error, message: "Failed saving token", keychainError: resultCode))
}
}

public func getSavedToken(for userId: Int) -> ApiToken? {
var savedToken: ApiToken?
keychainQueue.sync {
Expand All @@ -164,11 +176,11 @@ public class KeychainHelper {
kSecMatchLimit as String: kSecMatchLimitOne
]
var result: AnyObject?

let resultCode = withUnsafeMutablePointer(to: &result) {
SecItemCopyMatching(queryFindOne as CFDictionary, UnsafeMutablePointer($0))
}

let jsonDecoder = JSONDecoder()
if resultCode == noErr,
let keychainItem = result as? [String: Any],
Expand All @@ -179,7 +191,7 @@ public class KeychainHelper {
}
return savedToken
}

public func loadTokens() -> [ApiToken] {
var values = [ApiToken]()
keychainQueue.sync {
Expand All @@ -192,14 +204,14 @@ public class KeychainHelper {
kSecReturnRef as String: kCFBooleanTrue as Any,
kSecMatchLimit as String: kSecMatchLimitAll
]

var result: AnyObject?

let resultCode = withUnsafeMutablePointer(to: &result) {
SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0))
}
DDLogInfo("Successfully loaded tokens ? \(resultCode == noErr)")

guard resultCode == noErr else {
let crumb = Breadcrumb(level: .error, category: "Token")
crumb.type = "error"
Expand All @@ -208,7 +220,7 @@ public class KeychainHelper {
SentrySDK.addBreadcrumb(crumb)
return
}

if let array = result as? [[String: Any]] {
let jsonDecoder = JSONDecoder()
for item in array {
Expand All @@ -226,3 +238,17 @@ public class KeychainHelper {
return values
}
}

public extension ApiToken {
func generateBreadcrumb(level: SentryLevel, message: String, keychainError: OSStatus = noErr) -> Breadcrumb {
let crumb = Breadcrumb(level: level, category: "Token")
crumb.type = level == .info ? "info" : "error"
crumb.message = message
crumb.data = ["User id": userId,
"Expiration date": expirationDate?.timeIntervalSince1970 ?? "infinite",
"Access Token": truncatedAccessToken,
"Refresh Token": truncatedRefreshToken,
"Keychain error code": keychainError]
return crumb
}
}
Loading

0 comments on commit ca38968

Please sign in to comment.