Skip to content

Commit

Permalink
v2.7.3
Browse files Browse the repository at this point in the history
  • Loading branch information
johannes-schliephake committed Jul 25, 2024
2 parents 6421a43 + 784fba8 commit c61b37f
Show file tree
Hide file tree
Showing 234 changed files with 4,399 additions and 948 deletions.
9 changes: 4 additions & 5 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ opt_in_rules:
- toggle_bool
- unneeded_parentheses_in_closure_argument
- unowned_variable_capture
- unused_capture_list
- yoda_condition

custom_rules:
Expand All @@ -59,11 +58,11 @@ custom_rules:
regex: '\b(Swift\s*\.\s*)?print\b'
message: 'Prints should be removed'
severity: warning
view_model_state_access:
state_access:
included: '.*\.swift'
name: 'ViewModel State Access'
regex: '\bviewModel\s*\.\s*state'
message: 'ViewModel state should be accessed via subscript'
name: 'State Access'
regex: '\b[a-zA-Z0-9]*(?i)(viewModel|useCase)(?-i)\s*\.\s*state'
message: 'State should be accessed via subscript'
severity: warning
test_naming:
included: '.*Tests\.swift'
Expand Down
2 changes: 1 addition & 1 deletion App/PasswordsApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Factory

init() {
_ = resolve(\.logger)
_ = resolve(\.windowSizeService)
_ = resolve(\.windowSizeDataSource)
}

// MARK: Views
Expand Down
11 changes: 11 additions & 0 deletions App/uk.lproj/InfoPlist.strings
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* Name of the app */
"CFBundleDisplayName" = "Паролі";

/* Shown when user is asked for Camera permissions for scanning an OTP QR code, same as "_scanQrCode" in Localizable.strings and "NSCameraUsageDescription" in Provider/InfoPlist.strings and "NSCameraUsageDescription" in Extension/InfoPlist.strings */
"NSCameraUsageDescription" = "Сканувати QR-код";

/* Shown when user is asked for Face ID permissions, same as "_unlockApp" in Localizable.strings and "NSFaceIDUsageDescription" in Provider/InfoPlist.strings and "NSFaceIDUsageDescription" in Extension/InfoPlist.strings */
"NSFaceIDUsageDescription" = "Розблокувати додаток";

/* Shown when user is asked for photo library permissions, same as "_shareQrCode" in Localizable.strings and "NSPhotoLibraryAddUsageDescription" in Provider/InfoPlist.strings and "NSPhotoLibraryAddUsageDescription" in Extension/InfoPlist.strings */
"NSPhotoLibraryAddUsageDescription" = "Поширити QR-код";
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## [v2.7.3] - 2024-07-25
- Ukrainian translation (Thanks Markevych Dmytro!)
- Upgraded more parts of the app to new architecture
- Bugfixes and optimizations

## [v2.7.2] - 2024-06-06
- Button for clearing E2E password
- Bugfixes and optimizations
Expand Down
2 changes: 1 addition & 1 deletion Extension/ExtensionViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class ExtensionViewController: UIViewController {

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
_ = resolve(\.logger)
_ = resolve(\.windowSizeService)
_ = resolve(\.windowSizeDataSource)

super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
Expand Down
11 changes: 11 additions & 0 deletions Extension/uk.lproj/InfoPlist.strings
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

/* Shown when user is asked for Camera permissions for scanning an OTP QR code, same as "_scanQrCode" in Localizable.strings and "NSCameraUsageDescription" in App/InfoPlist.strings and "NSCameraUsageDescription" in Provider/InfoPlist.strings */
"NSCameraUsageDescription" = "Сканувати QR-код";

/* Shown when user is asked for photo library permissions, same as "_shareQrCode" in Localizable.strings and "NSPhotoLibraryAddUsageDescription" in App/InfoPlist.strings and "NSPhotoLibraryAddUsageDescription" in Provider/InfoPlist.strings */
"NSPhotoLibraryAddUsageDescription" = "Поширити QR-код";

/* Shown when user is asked for Face ID permissions, same as "_unlockApp" in Localizable.strings and "NSFaceIDUsageDescription" in App/InfoPlist.strings and "NSFaceIDUsageDescription" in Provider/InfoPlist.strings */
"NSFaceIDUsageDescription" = "Розблокувати додаток";
/* Name of the action button in Safari's share sheet */
"CFBundleDisplayName" = "Вставити одноразовий пароль";
992 changes: 863 additions & 129 deletions Passwords.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"originHash" : "8177ebc26b2667e9d46b7db5ce0d13f73ff96c0e046c1423700c1812fbb149a4",
"originHash" : "dc6dc453aff4c1686fe3d3f715279c9740fcc90fe3907cfc8b63a0d90e6733bd",
"pins" : [
{
"identity" : "anyasyncsequence",
Expand All @@ -10,6 +10,15 @@
"version" : "1.0.2"
}
},
{
"identity" : "combine-schedulers",
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/combine-schedulers",
"state" : {
"revision" : "9dc9cbe4bc45c65164fa653a563d8d8db61b09bb",
"version" : "1.0.0"
}
},
{
"identity" : "cwlcatchexception",
"kind" : "remoteSourceControl",
Expand Down Expand Up @@ -46,6 +55,15 @@
"version" : "13.3.0"
}
},
{
"identity" : "swift-concurrency-extras",
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/swift-concurrency-extras",
"state" : {
"revision" : "bb5059bde9022d69ac516803f4f227d8ac967f71",
"version" : "1.1.0"
}
},
{
"identity" : "swift-sodium",
"kind" : "remoteSourceControl",
Expand All @@ -54,6 +72,15 @@
"branch" : "master",
"revision" : "0d3021d0f81ac4be8600fecc19630b831def1b5b"
}
},
{
"identity" : "xctest-dynamic-overlay",
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/xctest-dynamic-overlay",
"state" : {
"revision" : "6f30bdba373bbd7fbfe241dddd732651f2fbd1e2",
"version" : "1.1.2"
}
}
],
"version" : 3
Expand Down
2 changes: 1 addition & 1 deletion Provider/ProviderViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ final class ProviderViewController: ASCredentialProviderViewController {

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
_ = resolve(\.logger)
_ = resolve(\.windowSizeService)
_ = resolve(\.windowSizeDataSource)

super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
Expand Down
8 changes: 8 additions & 0 deletions Provider/uk.lproj/InfoPlist.strings
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

/* Shown when user is asked for photo library permissions, same as "_shareQrCode" in Localizable.strings and "NSPhotoLibraryAddUsageDescription" in App/InfoPlist.strings and "NSPhotoLibraryAddUsageDescription" in Extension/InfoPlist.strings */
"NSPhotoLibraryAddUsageDescription" = "Поширити QR-код";
/* Shown when user is asked for Camera permissions for scanning an OTP QR code, same as "_scanQrCode" in Localizable.strings and "NSCameraUsageDescription" in App/InfoPlist.strings and "NSCameraUsageDescription" in Extension/InfoPlist.strings */
"NSCameraUsageDescription" = "Сканувати QR-код";

/* Shown when user is asked for Face ID permissions, same as "_unlockApp" in Localizable.strings and "NSFaceIDUsageDescription" in App/InfoPlist.strings and "NSFaceIDUsageDescription" in Extension/InfoPlist.strings */
"NSFaceIDUsageDescription" = "Розблокувати додаток";
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ You can install beta builds by joining the [TestFlight](https://testflight.apple
- Norwegian: [Allan Nordhøy](https://github.com/comradekingu)
- Catalan: [Maite Guix](https://hosted.weblate.org/user/maite.guix)
- Swedish: [Anders Johansson](https://github.com/tellustheguru)
- Ukrainian: [Markevych Dmytro](https://github.com/Hotr1pak)

Everybody is welcome to contribute translations via [Weblate](https://hosted.weblate.org/engage/nextcloud-passwords-ios)!

Expand Down
2 changes: 2 additions & 0 deletions Shared/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ protocol Configurating {
static var nonUpdatingJsonEncoder: JSONEncoder { get }
static var updatingJsonEncoder: JSONEncoder { get }
static var propertyListDecoder: PropertyListDecoder { get }
static var preferredLanguage: String? { get }

}

Expand Down Expand Up @@ -66,5 +67,6 @@ enum Configuration: Configurating {
return encoder
}()
static let propertyListDecoder = PropertyListDecoder()
static let preferredLanguage = NSLocale.preferredLanguages.first

}
49 changes: 49 additions & 0 deletions Shared/Container+Registrations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import Factory
import CoreImage
import AVFoundation
import StoreKit
import CombineSchedulers
import WebKit


extension Container {
Expand All @@ -22,6 +24,9 @@ extension Container {
var globalAlertsViewModelType: Factory<any GlobalAlertsViewModelProtocol.Type> {
self { GlobalAlertsViewModel.self }
}
var loginFlowViewModelType: Factory<any LoginFlowViewModelProtocol.Type> {
self { LoginFlowViewModel.self }
}
var logViewModelType: Factory<any LogViewModelProtocol.Type> {
self { LogViewModel.self }
}
Expand All @@ -31,13 +36,40 @@ extension Container {
var selectTagsViewModelType: Factory<any SelectTagsViewModelProtocol.Type> {
self { SelectTagsViewModel.self }
}
var serverSetupViewModelType: Factory<any ServerSetupViewModelProtocol.Type> {
self { ServerSetupViewModel.self }
}
var settingsViewModelType: Factory<any SettingsViewModelProtocol.Type> {
self { SettingsViewModel.self }
}
var shareOTPViewModelType: Factory<any ShareOTPViewModelProtocol.Type> {
self { ShareOTPViewModel.self }
}

// MARK: UseCases
var checkLoginGrantUseCase: Factory<any CheckLoginGrantUseCaseProtocol> {
self { CheckLoginGrantUseCase() }
}
var checkTrustUseCase: Factory<any CheckTrustUseCaseProtocol> {
self { CheckTrustUseCase() }
}
var folderLabelUseCase: Factory<any FolderLabelUseCaseProtocol> {
self { FolderLabelUseCase() }
}
var initiateLoginUseCase: Factory<any InitiateLoginUseCaseProtocol> {
self { InitiateLoginUseCase() }
}
var loginPollUseCase: Factory<any LoginPollUseCaseProtocol> {
self { LoginPollUseCase() }
}
var loginUrlUseCase: Factory<any LoginUrlUseCaseProtocol> {
self { LoginUrlUseCase() }
}
var managedConfigurationUseCase: Factory<any ManagedConfigurationUseCaseProtocol> {
self { ManagedConfigurationUseCase() }
.cached
}

// MARK: Services
var folderValidationService: Factory<any FolderValidationServiceProtocol> {
self { FolderValidationService() }
Expand Down Expand Up @@ -116,6 +148,14 @@ extension Container {
self { ProductsRepository() }
.cached
}
var windowSizeDataSource: Factory<any WindowSizeDataSourceProtocol> {
self { WindowSizeDataSource() }
.cached
}
var windowSizeRepository: Factory<any WindowSizeRepositoryProtocol> {
self { WindowSizeRepository() }
.cached
}

// MARK: Helpers
var logger: Factory<any Logging> {
Expand All @@ -127,6 +167,9 @@ extension Container {
var appStoreType: Factory<any AppStore.Type> {
self { StoreKit.AppStore.self }
}
var nonPersistentWebDataStore: Factory<any WebDataStore> {
self { WKWebsiteDataStore.nonPersistent() }
}
var pasteboard: Factory<any Pasteboard> {
self { UIPasteboard.general }
}
Expand All @@ -136,6 +179,9 @@ extension Container {
var qrCodeGenerator: Factory<(any QRCodeGenerating)?> {
self { CIFilter(name: "CIQRCodeGenerator") }
}
var systemNotifications: Factory <any Notifications> {
self { NotificationCenter.default }
}
var transactionType: Factory<any Transaction.Type> {
self { StoreKit.Transaction.self }
}
Expand All @@ -156,6 +202,9 @@ extension Container {
var currentDate: Factory<Date> {
self { .init() }
}
var userInitiatedScheduler: Factory<AnySchedulerOf<DispatchQueue>> {
self { DispatchQueue(qos: .userInitiated).eraseToAnyScheduler() }
}

// TODO: remove
var entriesController: Factory<EntriesController> {
Expand Down
32 changes: 22 additions & 10 deletions Shared/Controllers/Global/AuthenticationChallengeController.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import WebKit
import Foundation
import Factory
import Combine


final class AuthenticationChallengeController: NSObject, ObservableObject {
Expand Down Expand Up @@ -45,20 +46,19 @@ final class AuthenticationChallengeController: NSObject, ObservableObject {
deniedCertificateConfirmationRequests.forEach { $0.deny() }
}

private func handler(didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
DispatchQueue.global(qos: .userInitiated).async {
[weak self] in
private func checkTrust(_ trust: SecTrust?, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
DispatchQueue.global(qos: .userInitiated).async { [weak self] in

/// Check certificate and calculate SHA-256 if invalid
guard let serverTrust = challenge.protectionSpace.serverTrust else {
guard let trust else {
completionHandler(.performDefaultHandling, nil)
return
}
if SecTrustEvaluateWithError(serverTrust, nil) {
if SecTrustEvaluateWithError(trust, nil) {
completionHandler(.performDefaultHandling, nil)
return
}
guard let certificateChain = SecTrustCopyCertificateChain(serverTrust) as? [SecCertificate],
guard let certificateChain = SecTrustCopyCertificateChain(trust) as? [SecCertificate],
let certificate = certificateChain.first else {
completionHandler(.performDefaultHandling, nil)
return
Expand All @@ -68,13 +68,13 @@ final class AuthenticationChallengeController: NSObject, ObservableObject {

/// Check certificate hash against accepted hash
if certificateHash == self?.acceptedCertificateHash {
completionHandler(.useCredential, URLCredential(trust: serverTrust))
completionHandler(.useCredential, .init(trust: trust))
return
}

/// Add data needed for certificate confirmation
let certificateConfirmationRequest = CertificateConfirmationRequest(hash: certificateHash, accept: {
completionHandler(.useCredential, URLCredential(trust: serverTrust))
completionHandler(.useCredential, .init(trust: trust))
}, deny: {
completionHandler(.performDefaultHandling, nil)
})
Expand All @@ -84,6 +84,18 @@ final class AuthenticationChallengeController: NSObject, ObservableObject {
}
}

func checkTrust(_ trust: SecTrust?) -> AnyPublisher<Bool, Never> {
Just(trust)
.flatMap { [weak self] trust in
Future { promise in
self?.checkTrust(trust) { disposition, _ in
promise(.success(disposition == .useCredential))
}
}
}
.eraseToAnyPublisher()
}

}


Expand All @@ -108,7 +120,7 @@ extension AuthenticationChallengeController {
extension AuthenticationChallengeController: URLSessionDelegate {

func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
handler(didReceive: challenge, completionHandler: completionHandler)
checkTrust(challenge.protectionSpace.serverTrust, completionHandler: completionHandler)
}

}
Expand All @@ -117,7 +129,7 @@ extension AuthenticationChallengeController: URLSessionDelegate {
extension AuthenticationChallengeController: WKNavigationDelegate {

func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
handler(didReceive: challenge, completionHandler: completionHandler)
checkTrust(challenge.protectionSpace.serverTrust, completionHandler: completionHandler)
}

}
2 changes: 1 addition & 1 deletion Shared/Controllers/Global/SessionController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ final class SessionController: ObservableObject {
CloseSessionRequest(session: session).send { _ in promise(.success(())) }
session.invalidate(reason: .logout)
}
.flatMap {
.flatMapLatest {
DeleteAppPasswordOCSRequest(session: session).publisher
.replaceError(with: ())
}
Expand Down
2 changes: 1 addition & 1 deletion Shared/Controllers/Local/EditPasswordController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ final class EditPasswordController: ObservableObject {
}
password.updated = Date()

let hash = Crypto.SHA1.hash(passwordPassword.data(using: .utf8)!)
let hash = Crypto.SHA1.hash(.init(passwordPassword.utf8))
password.hash = String(hash.prefix(SettingsController.default.userPasswordSecurityHash))

password.password = passwordPassword
Expand Down
Loading

0 comments on commit c61b37f

Please sign in to comment.