Skip to content

Commit

Permalink
Fixed (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
joeldavidw authored Jun 15, 2024
1 parent a5c1bfd commit 4a9fc83
Show file tree
Hide file tree
Showing 11 changed files with 91 additions and 46 deletions.
14 changes: 10 additions & 4 deletions Chronos/App/MainAppView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,15 @@ struct MainAppView: View {
@Environment(\.scenePhase) private var scenePhase
@EnvironmentObject var loginStatus: LoginStatus

@Query var chronosCryptos: [ChronosCrypto]
private let stateService = Container.shared.stateService()

let stateService = Container.shared.stateService()
@Query(sort: \Vault.createdAt) private var vaults: [Vault]

private var filteredVault: [Vault] {
return vaults.compactMap { vault in
vault.vaultId == stateService.getVaultId() ? vault : nil
}
}

var body: some View {
ZStack {
Expand All @@ -34,12 +40,12 @@ struct MainAppView: View {
}
}
.onAppear {
if chronosCryptos.isEmpty {
if filteredVault.isEmpty {
stateService.resetAllStates()
loginStatus.loggedIn = false
}
}
.onChange(of: chronosCryptos) { _, newValue in
.onChange(of: filteredVault) { _, newValue in
if newValue.isEmpty {
stateService.resetAllStates()
loginStatus.loggedIn = false
Expand Down
1 change: 0 additions & 1 deletion Chronos/App/Onboarding/BiometricsSetupView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ struct BiometricsSetupView: View {
activateBiometricsAuth()

loginStatus.loggedIn = true

stateBiometricsAuth = true
stateOnboardingCompleted = true
} label: {
Expand Down
7 changes: 3 additions & 4 deletions Chronos/App/Onboarding/PasswordSetupView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct PasswordSetupView: View {

let cryptoService = Container.shared.cryptoService()
let stateService = Container.shared.stateService()
let vaultService = Container.shared.vaultService()

var body: some View {
ScrollView {
Expand Down Expand Up @@ -102,13 +103,11 @@ extension PasswordSetupView {
func generateAndEncryptMasterKey() async {
stateService.masterKey = try! cryptoService.generateRandomMasterKey()

let vault = Vault(vaultId: UUID(), createdAt: Date(), chronosCryptos: [], encryptedTokens: [])
modelContext.insert(vault)
try? modelContext.save()
let chronosCrypto = await cryptoService.wrapMasterKeyWithUserPassword(password: Array(password.utf8))

let vault = vaultService.createVault(chronosCrypto: chronosCrypto)!
stateService.setVaultId(vaultId: vault.vaultId!)

await cryptoService.wrapMasterKeyWithUserPassword(password: Array(password.utf8))
nextBtnPressed = true
}
}
Expand Down
5 changes: 2 additions & 3 deletions Chronos/App/Tabs/Tokens/AddToken/AddManualTokenView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import Factory
import SwiftUI

struct AddManualTokenView: View {
@Environment(\.modelContext) private var modelContext
@Environment(\.dismiss) var dismiss
@Environment(\.colorScheme) var colorScheme

Expand All @@ -18,6 +17,7 @@ struct AddManualTokenView: View {
@State private var period: Int = 30

let cryptoService = Container.shared.cryptoService()
let vaultService = Container.shared.vaultService()

let parentDismiss: DismissAction

Expand Down Expand Up @@ -127,8 +127,7 @@ struct AddManualTokenView: View {
newToken.period = period

let newEncToken = cryptoService.encryptToken(token: newToken)
modelContext.insert(newEncToken)
try? modelContext.save()
vaultService.insertEncryptedToken(newEncToken)

parentDismiss()
dismiss()
Expand Down
11 changes: 2 additions & 9 deletions Chronos/App/Tabs/Tokens/AddToken/AddTokenView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ import Factory
import SwiftUI

struct AddTokenView: View {
@Environment(\.modelContext) private var modelContext

@Environment(\.dismiss) var dismiss
@State private var unableToAccessCamera = false
@State private var showTokenManualAddSheet = false

let cryptoService = Container.shared.cryptoService()
let otpService = Container.shared.otpService()
let vaultService = Container.shared.vaultService()

var body: some View {
VStack {
Expand Down Expand Up @@ -94,10 +93,8 @@ struct AddTokenView: View {

do {
let newToken = try otpService.parseOtpAuthUrl(otpAuthStr: otpAuthStr)

let newEncToken = cryptoService.encryptToken(token: newToken)
modelContext.insert(newEncToken)
try modelContext.save()
vaultService.insertEncryptedToken(newEncToken)

dismiss()

Expand All @@ -122,7 +119,3 @@ struct AddTokenView: View {
}
}
}

#Preview {
AddTokenView()
}
14 changes: 7 additions & 7 deletions Chronos/App/Tabs/Tokens/TokensTab.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ struct TokenPair: Identifiable {
}

struct TokensTab: View {
@Query(sort: \EncryptedToken.createdAt) private var encryptedTokens: [EncryptedToken]
@Query(sort: \Vault.createdAt) private var vaults: [Vault]

@State private var showTokenAddSheet = false
@State private var showTokenUpdateSheet = false
Expand All @@ -25,14 +25,14 @@ struct TokensTab: View {

private var tokenPairs: [TokenPair] {
let vaultId = stateService.getVaultId()
let vault = vaults.filter { $0.vaultId == vaultId }

return encryptedTokens.filter { $0.vault?.vaultId == vaultId }
.compactMap { encToken in
guard let decryptedToken = cryptoService.decryptToken(encryptedToken: encToken) else {
return nil
}
return TokenPair(id: encToken.id, token: decryptedToken, encToken: encToken)
return vault.first!.encryptedTokens!.compactMap { encToken in
guard let decryptedToken = cryptoService.decryptToken(encryptedToken: encToken) else {
return nil
}
return TokenPair(id: encToken.id, token: decryptedToken, encToken: encToken)
}
}

var body: some View {
Expand Down
3 changes: 1 addition & 2 deletions Chronos/Database/ChronosCrypto.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ class ChronosCrypto {
var passwordParams: PasswordParams?
var kdfParams: KdfParams?

init(vault: Vault, key: [UInt8]? = nil, keyParams: KeyParams? = nil, passwordParams: PasswordParams? = nil, kdfParams: KdfParams? = nil) {
self.vault = vault
init(key: [UInt8], keyParams: KeyParams, passwordParams: PasswordParams, kdfParams: KdfParams) {
self.key = key
self.keyParams = keyParams
self.passwordParams = passwordParams
Expand Down
3 changes: 1 addition & 2 deletions Chronos/Database/EncryptedToken.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ class EncryptedToken {
var authenticationTag: [UInt8]?
var createdAt: Date?

init(vault: Vault, encryptedTokenCiper: [UInt8]? = nil, iv: [UInt8]? = nil, authenticationTag: [UInt8]? = nil, createdAt: Date? = nil) {
self.vault = vault
init(encryptedTokenCiper: [UInt8], iv: [UInt8], authenticationTag: [UInt8], createdAt: Date) {
self.encryptedTokenCiper = encryptedTokenCiper
self.iv = iv
self.authenticationTag = authenticationTag
Expand Down
12 changes: 5 additions & 7 deletions Chronos/Database/Vault.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,14 @@ class Vault {
var vaultId: UUID?
var createdAt: Date?

@Relationship(deleteRule: .cascade, inverse: \ChronosCrypto.vault)
var chronosCryptos: [ChronosCrypto]?
@Relationship(deleteRule: .cascade)
var chronosCryptos: [ChronosCrypto]? = []

@Relationship(deleteRule: .cascade, inverse: \EncryptedToken.vault)
var encryptedTokens: [EncryptedToken]?
@Relationship(deleteRule: .cascade)
var encryptedTokens: [EncryptedToken]? = []

init(vaultId: UUID? = nil, createdAt: Date? = nil, chronosCryptos: [ChronosCrypto]? = nil, encryptedTokens: [EncryptedToken]? = nil) {
init(vaultId: UUID, createdAt: Date) {
self.vaultId = vaultId
self.createdAt = createdAt
self.chronosCryptos = chronosCryptos
self.encryptedTokens = encryptedTokens
}
}
11 changes: 4 additions & 7 deletions Chronos/Services/CryptoService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class CryptoService {
// scrypt paramaters - n: 2^17, r: 8, p: 1
private let kdfParams = KdfParams(type: 0, n: 1 << 17, r: 8, p: 1)

func wrapMasterKeyWithUserPassword(password: [UInt8]) async {
func wrapMasterKeyWithUserPassword(password: [UInt8]) async -> ChronosCrypto {
let passwordSalt = try! generateRandomSaltHexString()
let passwordParams = PasswordParams(salt: passwordSalt)

Expand All @@ -33,12 +33,9 @@ public class CryptoService {

let keyParams = KeyParams(iv: iv, tag: encrypt.authenticationTag)

let newPasswordCrypto = ChronosCrypto(vault: vaultService.getVault()!, key: encrypt.cipherText, keyParams: keyParams, passwordParams: passwordParams, kdfParams: kdfParams)
let newPasswordCrypto = ChronosCrypto(key: encrypt.cipherText, keyParams: keyParams, passwordParams: passwordParams, kdfParams: kdfParams)

let context = ModelContext(swiftDataService.getModelContainer())

context.insert(newPasswordCrypto)
try context.save()
return newPasswordCrypto
} catch {
fatalError(error.localizedDescription)
}
Expand Down Expand Up @@ -102,7 +99,7 @@ extension CryptoService {
let tokenJson = try JSONEncoder().encode(token)
let encrypt = try AEADXChaCha20Poly1305.encrypt(Array(tokenJson), key: Array(stateService.masterKey), iv: iv, authenticationHeader: header)

return EncryptedToken(vault: vaultService.getVault()!, encryptedTokenCiper: encrypt.cipherText, iv: iv, authenticationTag: encrypt.authenticationTag, createdAt: Date())
return EncryptedToken(encryptedTokenCiper: encrypt.cipherText, iv: iv, authenticationTag: encrypt.authenticationTag, createdAt: Date())
} catch {
fatalError(error.localizedDescription)
}
Expand Down
56 changes: 56 additions & 0 deletions Chronos/Services/VaultService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,26 @@ public class VaultService {
private let stateService = Container.shared.stateService()
private let swiftDataService = Container.shared.swiftDataService()

func createVault(chronosCrypto: ChronosCrypto) -> Vault? {
let context = ModelContext(swiftDataService.getModelContainer())

let vault = Vault(vaultId: UUID(), createdAt: Date())

vault.chronosCryptos = [chronosCrypto]

context.insert(vault)

do {
try context.save()
logger.info("Successfully saved vault")

return vault
} catch {
logger.error("Failed to save context: \(error.localizedDescription)")
return nil
}
}

// TODO(joeldavidw): Selects first vault for now. Selection page should be shown if there are more than one vault.
func getFirstVault(isRestore: Bool) -> Vault? {
let context = ModelContext(swiftDataService.getModelContainer(isRestore: isRestore))
Expand Down Expand Up @@ -44,3 +64,39 @@ public class VaultService {
return vaultArr.first
}
}

extension VaultService {
func insertEncryptedToken(_ encryptedToken: EncryptedToken) {
let context = ModelContext(swiftDataService.getModelContainer())

let vault = getVault()!

vault.encryptedTokens?.append(encryptedToken)

context.insert(vault)

do {
try context.save()
logger.info("Successfully saved vault")
} catch {
logger.error("Failed to save context: \(error.localizedDescription)")
}
}

func deleteEncryptedToken(_ encryptedToken: EncryptedToken) {
let context = ModelContext(swiftDataService.getModelContainer())

var vault = getVault()!

vault.encryptedTokens?.append(encryptedToken)

context.insert(vault)

do {
try context.save()
logger.info("Successfully saved vault")
} catch {
logger.error("Failed to save context: \(error.localizedDescription)")
}
}
}

0 comments on commit 4a9fc83

Please sign in to comment.