Skip to content

Commit

Permalink
Merge pull request #67 from johannes-schliephake/develop
Browse files Browse the repository at this point in the history
v2.0
  • Loading branch information
johannes-schliephake authored May 4, 2021
2 parents 0e1b3fb + 4e4c71d commit cf8a77d
Show file tree
Hide file tree
Showing 158 changed files with 2,298 additions and 511 deletions.
2 changes: 2 additions & 0 deletions App/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>ITSAppUsesNonExemptEncryption</key>
<true/>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
Expand Down
168 changes: 147 additions & 21 deletions Passwords.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"object": {
"pins": [
{
"package": "Sodium",
"repositoryURL": "https://github.com/jedisct1/swift-sodium.git",
"state": {
"branch": null,
"revision": "4f9164a0a2c9a6a7ff53a2833d54a5c79c957342",
"version": "0.9.1"
}
}
]
},
"version": 1
}
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@

![](https://raw.githubusercontent.com/johannes-schliephake/nextcloud-passwords-ios/main/AppIcon@1x.png)

An iOS client for the [Nextcloud Passwords](https://git.mdns.eu/nextcloud/passwords) app.
Available on the [App Store](https://apps.apple.com/app/id1546212226).
An iOS client for the [Nextcloud Passwords](https://git.mdns.eu/nextcloud/passwords) app. Available on the [App Store](https://apps.apple.com/app/id1546212226).

This app allows you to view, create, edit and delete the passwords and folders on your Nextcloud server. It offers a variety of filtering and sorting options.
This app allows you to view, create, edit and delete passwords and folders on your Nextcloud server. It offers a variety of filtering and sorting options. End-to-end/client-side encryption and encrypted offline storage make sure your data is secure.

A Password AutoFill provider is integrated into the app for seamless login experiences. You can enable this feature in iOS's Settings app.

Expand Down
17 changes: 12 additions & 5 deletions Shared/Configuration.swift
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
import Foundation


struct Configuration {
enum Configuration {

static let defaults: [String: Any] = [
"automaticallyGeneratePasswords": true,
"storeOffline": true
]

static let shortVersionString = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String // swiftlint:disable:this force_cast
static let appService = Bundle.main.object(forInfoDictionaryKey: "AppService") as! String // swiftlint:disable:this force_cast
static let appGroup = Bundle.main.object(forInfoDictionaryKey: "AppGroup") as! String // swiftlint:disable:this force_cast
static let appKeychain = Bundle.main.object(forInfoDictionaryKey: "AppKeychain") as! String // swiftlint:disable:this force_cast
static let clientName = "\(Bundle.main.infoDictionary?["CFBundleName"] as! String) (iOS)" // swiftlint:disable:this force_cast
static let clientName = "\(Bundle.main.infoDictionary?["CFBundleName"] as! String) (iOS\(appService.hasSuffix("debug") ? ", Debug" : ""))" // swiftlint:disable:this force_cast
static let isTestEnvironment = ProcessInfo.processInfo.environment["TEST"] == "true"
static let userDefaults = UserDefaults(suiteName: Configuration.appGroup)!

private init() {}
static let userDefaults: UserDefaults = {
let userDefaults = UserDefaults(suiteName: Configuration.appGroup)!
userDefaults.register(defaults: defaults)
return userDefaults
}()

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import CryptoKit
import WebKit
import Combine

Expand All @@ -24,11 +23,10 @@ final class AuthenticationChallengeController: NSObject, ObservableObject {
super.init()

acceptedCertificateHash = Keychain.default.load(key: "acceptedCertificateHash")
CredentialsController.default.$credentials.sink(receiveValue: clearAcceptedCertificateHash).store(in: &subscriptions)
}

func clearAcceptedCertificateHash(credentials: Credentials? = nil) {
guard credentials == nil else {
func clearAcceptedCertificateHash(session: Session? = nil) {
guard session == nil else {
return
}
acceptedCertificateHash = nil
Expand All @@ -43,7 +41,7 @@ final class AuthenticationChallengeController: NSObject, ObservableObject {
}

func deny(certificateHash: String) {
CredentialsController.default.logout()
SessionController.default.logout()

let deniedCertificateConfirmationRequests = certificateConfirmationRequests.filter { $0.hash == certificateHash }
certificateConfirmationRequests.removeAll { deniedCertificateConfirmationRequests.contains($0) }
Expand All @@ -65,7 +63,7 @@ final class AuthenticationChallengeController: NSObject, ObservableObject {
return
}
let certificateData = SecCertificateCopyData(certificate) as Data
let certificateHash = SHA256.hash(data: certificateData).map { String(format: "%02X", $0) }.joined(separator: ":")
let certificateHash = Crypto.SHA256.hash(certificateData, humanReadable: true)

/// Check certificate hash against accepted hash
if certificateHash == acceptedCertificateHash {
Expand All @@ -79,7 +77,10 @@ final class AuthenticationChallengeController: NSObject, ObservableObject {
}, deny: {
completionHandler(.performDefaultHandling, nil)
})
certificateConfirmationRequests.append(certificateConfirmationRequest)
DispatchQueue.main.async {
[self] in
certificateConfirmationRequests.append(certificateConfirmationRequest)
}
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ final class BiometricAuthenticationController: ObservableObject {
private let semaphore = DispatchSemaphore(value: 1)

init() {
NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification).sink(receiveValue: unlockApp).store(in: &subscriptions)
NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification).sink(receiveValue: lockApp).store(in: &subscriptions)
NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification)
.sink(receiveValue: unlockApp)
.store(in: &subscriptions)
NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)
.sink(receiveValue: lockApp)
.store(in: &subscriptions)
}

private init(isUnlocked: Bool) {
Expand All @@ -34,7 +38,7 @@ final class BiometricAuthenticationController: ObservableObject {
let context = LAContext()
let policy = LAPolicy.deviceOwnerAuthentication
var error: NSError?
guard CredentialsController.default.credentials != nil,
guard SessionController.default.session != nil,
context.canEvaluatePolicy(policy, error: &error) else {
DispatchQueue.main.async {
isUnlocked = true
Expand Down
48 changes: 0 additions & 48 deletions Shared/Controllers/Global/CredentialsController.swift

This file was deleted.

Loading

0 comments on commit cf8a77d

Please sign in to comment.