Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
6321b27
[Autofill] Add extraction
OffRange Aug 7, 2025
6c89108
[Autofill] Add inline suggestions
OffRange Aug 8, 2025
1ffef0c
[Autofill] Add menu suggestions for API<30
OffRange Aug 9, 2025
a6c6a44
[Autofill] Refactor Identifier to Credentials
OffRange Aug 9, 2025
fee7f52
[Autofill] Fix password credential type
OffRange Aug 10, 2025
e4eb0e7
[Autofill] Add compatibility support
OffRange Aug 10, 2025
df88f8f
[Autofill] Fix extraction for compatibility browsers
OffRange Aug 10, 2025
2b31857
[Autofill] Implement basic save request logic
OffRange Aug 10, 2025
6667ec0
[Autofill] Fix unintended one shot
OffRange Aug 18, 2025
e44179f
[Core] Move docs
OffRange Aug 21, 2025
412e01e
[Autofill] Add filling feature prove-of-concept
OffRange Aug 23, 2025
37d3c69
[Core] Rename local composition file
OffRange Aug 24, 2025
5a2267f
[Core] Inject Session instead of AesKey
OffRange Aug 25, 2025
ad95d55
[Autofill] Make Icon API Q+
OffRange Aug 26, 2025
07f0274
[Core] Refactor biometric authentication logic
OffRange Aug 26, 2025
064ae48
[Autofill] Implement suggestion
OffRange Aug 26, 2025
3773c55
[Biometrics] Make title dynamic
OffRange Aug 26, 2025
9c7b3d9
[Biometrics] Handle failure callback
OffRange Aug 26, 2025
e2578a5
[Autofill] Fix issue during configuration changes
OffRange Aug 26, 2025
75cf552
[Biometrics] Add request reason
OffRange Aug 26, 2025
1ab640b
[Autofill] Add show ui event
OffRange Aug 26, 2025
967fd5d
[REBASE] rebase main branch refactoring
OffRange Aug 27, 2025
acb8bd2
[Autofill] Fix Validator
OffRange Aug 27, 2025
85003d1
[Autofill] Implement data to save extraction
OffRange Aug 28, 2025
27e56d5
[Autofill] Migrate to default RequestData class
OffRange Aug 28, 2025
f86d384
[Autofill] Generalize autofill extraction
OffRange Aug 30, 2025
1d99c99
[Autofill] Refactor ui show up
OffRange Aug 30, 2025
abdb8aa
[Dashboard] Fix onItemClick
OffRange Sep 5, 2025
96aed01
[Dashboard] Fix syntax
OffRange Sep 5, 2025
a93e602
[Autofill] Cleanup
OffRange Sep 5, 2025
875d852
[Autofill] Implement saving feature
OffRange Sep 6, 2025
47b2df8
[Autofill] Add todo
OffRange Sep 11, 2025
ac42194
[Auth] Add opt-out for auto biometric prompt
OffRange Sep 11, 2025
3a7ec3f
[Autofill] Add unlock with password support
OffRange Sep 12, 2025
3d16fdf
[Autofill] Refactor ui state handling
OffRange Sep 14, 2025
4669834
[Automation] Reduce generated code for better maintainability
OffRange Sep 16, 2025
07f7601
[Util] Move Result to separate module
OffRange Sep 16, 2025
2abd5ae
[Core Item] Create Item module
OffRange Sep 16, 2025
66c3ec1
[Core Item] Create SecretData type
OffRange Sep 17, 2025
f5e484d
[Core Item] Implement basic room entities
OffRange Sep 17, 2025
864bbdd
[Core Item] Implement domain models
OffRange Sep 17, 2025
643caa5
[Core Item] Implement DAOs
OffRange Sep 17, 2025
6b06321
[Core Item] Implement repositories
OffRange Sep 17, 2025
43d1545
[Core Item] Implement upsert use-case
OffRange Sep 17, 2025
8832f77
[Core Item] Add password string res
OffRange Sep 17, 2025
0ae05b0
[Core Item] Add room db
OffRange Sep 17, 2025
fd275eb
[App] Add SecretData cryptographic extensions
OffRange Sep 17, 2025
8a432ba
[App] Migrate to new item module
OffRange Sep 17, 2025
f8ebaab
[Dependencies] Dump ksp version
OffRange Sep 17, 2025
7a2bf13
[Auth] Fix creating access
OffRange Sep 17, 2025
9b82122
[Core] Add chip text field
OffRange Sep 19, 2025
11675a2
[Core] Add chip supporting group
OffRange Sep 20, 2025
a6d24ef
[Core Util] Add registrable domain resolver
OffRange Sep 20, 2025
e63ad93
[Core] Lookup actual eTLD+1 during TOTP request
OffRange Sep 20, 2025
410ab61
[Core Item] Move entire item upsert logic into repository
OffRange Sep 21, 2025
4397680
[Core Item] Allow nullable eTLD1
OffRange Sep 22, 2025
932767c
[Item] Make Upsert class explicit for password
OffRange Sep 22, 2025
9527376
[Item] Migrate password creation
OffRange Sep 23, 2025
cd28a7b
[Core Item] Make domains a set
OffRange Sep 24, 2025
bc6dbb6
[Item] Dont allow the same domain value
OffRange Sep 24, 2025
ce74765
[Core Item] Implement dao for domains
OffRange Sep 24, 2025
3ea498e
[Item] Support totp issuer again
OffRange Sep 25, 2025
0cdc15f
[Item] Support domain viewing again
OffRange Sep 25, 2025
64eeb14
[Item] Rename website to domain
OffRange Sep 25, 2025
e1d6bcc
[Item] Implement domain modification again
OffRange Sep 25, 2025
30b5ab7
[Item] Add spacing
OffRange Sep 25, 2025
eef8929
[Autofill] Use etld1 for suggestions
OffRange Sep 25, 2025
28996d2
[Autofill] Implement association option
OffRange Sep 28, 2025
a063af5
[Autofill] Return early
OffRange Oct 1, 2025
8fdb47f
[Autofill] Resolve TODO
OffRange Oct 1, 2025
ad7d46d
[Autofill] Resolve TODO - support field types
OffRange Oct 1, 2025
3a69e38
[Autofill] Fix not focused issue
OffRange Oct 1, 2025
1c888d6
[Strings] Refactor login identifier
OffRange Oct 1, 2025
ca7cab6
[Autofill] Only allow autofill when access is available
OffRange Oct 2, 2025
f77dd92
[Autofill] Add manual flag support
OffRange Oct 2, 2025
02ab5f7
[Autofill] Add suspicion waring
OffRange Oct 3, 2025
8035bcf
[Autofill] Introduce per-field urls
OffRange Oct 4, 2025
a1470c8
[Autofill] Remove unused code
OffRange Oct 4, 2025
2a2a16d
[Autofill] Check DALs when suspicious
OffRange Oct 5, 2025
4fe1df5
[Autofill] Only check DAL when suspicion should be handled
OffRange Oct 6, 2025
c698211
[Autofill] Handle exception
OffRange Oct 6, 2025
68b32f6
[Autofill] Resolve TODO
OffRange Oct 6, 2025
57b38ea
[Autofill] Remove url set
OffRange Oct 6, 2025
2aebf5b
[Item Create] Support urls when creating from raw
OffRange Oct 6, 2025
44a9b6e
[Autofill] Add TODO
OffRange Oct 7, 2025
6704ee5
[Autofill] Merge redundant functions
OffRange Oct 12, 2025
f56b0a9
[Core Item] Add totp requirement flag
OffRange Oct 12, 2025
fe8f139
[Autofill] Support autofill for TOTP
OffRange Oct 12, 2025
96cf09e
Merge branch 'v2' into feat/v2/autofill
OffRange Oct 16, 2025
6dd90e4
Fix package typo
OffRange Oct 16, 2025
9a01f04
Fix tests
OffRange Oct 16, 2025
dc0dc5e
Fix R8 issues
OffRange Oct 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 5 additions & 17 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget

plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.androidx.room)
alias(libs.plugins.kotlin.parcelize)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
Expand Down Expand Up @@ -64,11 +63,13 @@ android {

kotlin {
compilerOptions {
freeCompilerArgs.add("-Xcontext-parameters")
jvmTarget = JvmTarget.JVM_17
}
}

dependencies {
implementation(libs.okhttp)

// Koin DI
implementation(project.dependencies.platform(libs.koin.bom))
Expand All @@ -77,14 +78,7 @@ dependencies {
implementation(libs.koin.annotations)
ksp(libs.koin.ksp.compiler)

// Room
implementation(libs.androidx.room.runtime)
implementation(libs.androidx.room.ktx)
ksp(libs.androidx.room.compiler)

// Automation
implementation(projects.automation)
ksp(projects.automationProcessor)
implementation(projects.core.item)

// Datastore
implementation(libs.androidx.datastore)
Expand All @@ -96,6 +90,8 @@ dependencies {
implementation(libs.offrange.passgen)
implementation(libs.argon2kt)

implementation(libs.androidx.autofill)

// Use GMS ML Kit for barcode scanning on the Play Store to minimize app size; use ZXing for F-Droid builds.
"playStoreImplementation"(libs.gms.mlkit.barcode.scanning)
"fdroidImplementation"(libs.zxing.barcode.scanning)
Expand Down Expand Up @@ -153,12 +149,4 @@ protobuf {
composeCompiler {
reportsDestination = layout.buildDirectory.dir("compose_compiler")
metricsDestination = layout.buildDirectory.dir("compose_compiler")
}

room {
schemaDirectory("$projectDir/schemas")
}

ksp {
arg("automation.packageName", "de.davis.keygo.generated")
}
18 changes: 18 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,24 @@
android:scheme="otpauth" />
</intent-filter>
</activity>

<service
android:name=".autofill.presentation.KeyGoAutofillService"
android:exported="true"
android:permission="android.permission.BIND_AUTOFILL_SERVICE">
<meta-data
android:name="android.autofill"
android:resource="@xml/keygo_autofill_service" />
<intent-filter>
<action android:name="android.service.autofill.AutofillService" />
</intent-filter>
</service>

<activity
android:name=".autofill.presentation.activity.AutofillActivity"
android:excludeFromRecents="true"
android:exported="false"
android:theme="@style/Theme.KeyGo.Auth.Transparent" />
</application>

</manifest>
12 changes: 11 additions & 1 deletion app/src/main/kotlin/de/davis/keygo/app/KeyGoApplication.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
package de.davis.keygo.app

import android.app.Application
import de.davis.keygo.app.di.init
import org.koin.core.context.startKoin

class KeyGoApplication : Application()
class KeyGoApplication : Application() {

override fun onCreate() {
super.onCreate()
startKoin {
init(this@KeyGoApplication)
}
}
}
8 changes: 6 additions & 2 deletions app/src/main/kotlin/de/davis/keygo/app/di/Koin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package de.davis.keygo.app.di

import android.content.Context
import de.davis.keygo.auth.di.AuthModule
import de.davis.keygo.core.data.local.datasource.KeyGoDatabase
import de.davis.keygo.autofill.di.AutofillModule
import de.davis.keygo.core.di.CoreModule
import de.davis.keygo.core.item.data.local.datasource.ItemDatabase
import de.davis.keygo.core.util.di.CoreUtilModule
import de.davis.keygo.dashboard.di.DashboardModule
import de.davis.keygo.item.di.ItemModule
import de.davis.keygo.migration.create_access.di.MigrationCreateAccessModule
Expand All @@ -17,12 +19,14 @@ fun KoinApplication.init(androidContext: Context) {

// modules
modules(
KeyGoDatabase.koinModule,
ItemDatabase.koinModule,
CoreModule.module,
CoreUtilModule.module,
AuthModule.module,
DashboardModule.module,
ItemModule.module,
TotpModule.module,
AutofillModule.module,

MigrationCreateAccessModule.module
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package de.davis.keygo.auth.data.repository
import com.lambdapioneer.argon2kt.Argon2Kt
import com.lambdapioneer.argon2kt.Argon2Mode
import com.lambdapioneer.argon2kt.Argon2Version
import de.davis.keygo.auth.domain.model.CryptographyError
import de.davis.keygo.auth.domain.repository.KeyDerivationRepository
import de.davis.keygo.core.domain.Result
import de.davis.keygo.core.identity.common.domain.model.CryptographyError
import de.davis.keygo.core.util.Result
import org.koin.core.annotation.Single

@Single
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package de.davis.keygo.auth.data.repository

import androidx.datastore.core.DataStore
import de.davis.keygo.auth.data.local.model.ProtoPasswordKeyData
import de.davis.keygo.auth.data.mapper.toDomain
import de.davis.keygo.auth.data.mapper.toProto
import de.davis.keygo.auth.domain.model.PasswordWrappedKeyData
import de.davis.keygo.core.di.annotation.PasswordQualifier
import de.davis.keygo.core.identity.common.data.repository.DefaultWrappedKeyRepository
import de.davis.keygo.core.identity.common.domain.repository.WrappedKeyRepository
import org.koin.core.annotation.Single

@Suppress("FunctionName")
@Single(binds = [WrappedKeyRepository::class])
@PasswordQualifier
fun PasswordWrappedKeyRepositoryImpl(@PasswordQualifier dataStore: DataStore<ProtoPasswordKeyData>) =
DefaultWrappedKeyRepository(
dataStore = dataStore,
toDomain = ProtoPasswordKeyData::toDomain,
toProto = PasswordWrappedKeyData::toProto,
defaultInstance = ProtoPasswordKeyData::getDefaultInstance
)
15 changes: 0 additions & 15 deletions app/src/main/kotlin/de/davis/keygo/auth/di/AuthModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ package de.davis.keygo.auth.di
import android.content.Context
import androidx.datastore.dataStore
import com.lambdapioneer.argon2kt.Argon2Kt
import de.davis.keygo.auth.data.local.model.ProtoBiometricKeyData
import de.davis.keygo.auth.data.local.model.ProtoPasswordKeyData
import de.davis.keygo.auth.di.annotation.BiometricQualifier
import de.davis.keygo.core.di.DefaultProtoSerializer
import de.davis.keygo.core.di.annotation.PasswordQualifier
import org.koin.core.annotation.ComponentScan
Expand All @@ -24,24 +22,11 @@ object AuthModule {
)
)

private val Context.protoBiometricKeyDataStore by dataStore(
"biometric_key_data.pb",
DefaultProtoSerializer(
defaultInstance = ProtoBiometricKeyData.getDefaultInstance(),
parser = ProtoBiometricKeyData.parser()
)
)

@Single
internal fun provideArgon2Kt() = Argon2Kt()

@Single
@PasswordQualifier
internal fun provideProtoPasswordKeyDataStore(context: Context) =
context.protoPasswordKeyDataStore

@Single
@BiometricQualifier
internal fun provideProtoBiometricKeyDataStore(context: Context) =
context.protoBiometricKeyDataStore
}

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package de.davis.keygo.auth.domain.repository

import de.davis.keygo.auth.domain.model.CryptographyError
import de.davis.keygo.core.domain.Result
import de.davis.keygo.core.identity.common.domain.model.CryptographyError
import de.davis.keygo.core.util.Result

interface KeyDerivationRepository {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,6 @@
package de.davis.keygo.auth.domain.repository

import androidx.datastore.core.DataStore
import de.davis.keygo.auth.data.local.model.ProtoPasswordKeyData
import de.davis.keygo.auth.data.mapper.toDomain
import de.davis.keygo.auth.data.mapper.toProto
import de.davis.keygo.auth.data.repository.DefaultWrappedKeyRepository
import de.davis.keygo.auth.domain.model.PasswordWrappedKeyData
import de.davis.keygo.core.di.annotation.PasswordQualifier
import org.koin.core.annotation.Single
import de.davis.keygo.core.identity.common.domain.repository.WrappedKeyRepository

typealias PasswordWrappedKeyRepository = WrappedKeyRepository<PasswordWrappedKeyData>

@Suppress("FunctionName")
@Single(binds = [WrappedKeyRepository::class])
@PasswordQualifier
fun PasswordWrappedKeyRepositoryImpl(@PasswordQualifier dataStore: DataStore<ProtoPasswordKeyData>) =
DefaultWrappedKeyRepository(
dataStore = dataStore,
toDomain = ProtoPasswordKeyData::toDomain,
toProto = PasswordWrappedKeyData::toProto,
defaultInstance = ProtoPasswordKeyData::getDefaultInstance
)
typealias PasswordWrappedKeyRepository = WrappedKeyRepository<PasswordWrappedKeyData>
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
package de.davis.keygo.auth.domain.usecase

import de.davis.keygo.auth.data.repository.BiometricWrappedKeyRepository
import de.davis.keygo.auth.di.annotation.BiometricQualifier
import de.davis.keygo.auth.domain.factory.CipherFactory
import de.davis.keygo.auth.domain.model.BiometricWrappedKeyData
import de.davis.keygo.auth.domain.model.CryptographicMode
import de.davis.keygo.auth.domain.model.CryptographyError
import de.davis.keygo.auth.domain.model.PasswordWrappedKeyData
import de.davis.keygo.auth.domain.repository.DeviceInfoRepository
import de.davis.keygo.auth.domain.repository.KeyDerivationRepository
import de.davis.keygo.auth.domain.repository.PasswordWrappedKeyRepository
import de.davis.keygo.core.di.annotation.BiometricQualifier
import de.davis.keygo.core.di.annotation.PasswordQualifier
import de.davis.keygo.core.domain.Result
import de.davis.keygo.core.domain.Session
import de.davis.keygo.core.domain.asUnitResult
import de.davis.keygo.core.domain.model.crypto.asAesKey
import de.davis.keygo.core.domain.onSuccess
import de.davis.keygo.core.domain.zip
import de.davis.keygo.core.identity.common.domain.CipherFactory
import de.davis.keygo.core.identity.common.domain.model.BiometricWrappedKeyData
import de.davis.keygo.core.identity.common.domain.model.CryptographicMode
import de.davis.keygo.core.identity.common.domain.model.CryptographyError
import de.davis.keygo.core.identity.common.domain.repository.BiometricWrappedKeyRepository
import de.davis.keygo.core.util.Result
import de.davis.keygo.core.util.asUnitResult
import de.davis.keygo.core.util.onSuccess
import de.davis.keygo.core.util.zip
import org.koin.core.annotation.Single
import java.security.SecureRandom
import javax.crypto.Cipher
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
package de.davis.keygo.auth.domain.usecase

import de.davis.keygo.auth.domain.factory.CipherFactory
import de.davis.keygo.auth.domain.model.CryptographicMode
import de.davis.keygo.auth.domain.model.CryptographyError
import de.davis.keygo.auth.domain.repository.DeviceInfoRepository
import de.davis.keygo.auth.domain.repository.KeyDerivationRepository
import de.davis.keygo.auth.domain.repository.PasswordWrappedKeyRepository
import de.davis.keygo.core.di.annotation.PasswordQualifier
import de.davis.keygo.core.domain.Result
import de.davis.keygo.core.domain.Session
import de.davis.keygo.core.domain.asResult
import de.davis.keygo.core.domain.asUnitResult
import de.davis.keygo.core.domain.model.crypto.asAesKey
import de.davis.keygo.core.domain.onSuccess
import de.davis.keygo.core.domain.zip
import de.davis.keygo.core.identity.common.domain.CipherFactory
import de.davis.keygo.core.identity.common.domain.model.CryptographicMode
import de.davis.keygo.core.identity.common.domain.model.CryptographyError
import de.davis.keygo.core.util.Result
import de.davis.keygo.core.util.asResult
import de.davis.keygo.core.util.asUnitResult
import de.davis.keygo.core.util.onSuccess
import de.davis.keygo.core.util.zip
import org.koin.core.annotation.Single

@Single
Expand Down
28 changes: 15 additions & 13 deletions app/src/main/kotlin/de/davis/keygo/auth/presentation/AuthScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package de.davis.keygo.auth.presentation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import de.davis.keygo.auth.presentation.model.AuthUIEvent
import de.davis.keygo.core.identity.biometric.presentation.BiometricPromptSupport
import de.davis.keygo.core.identity.biometric.presentation.LocalBiometricManager
import de.davis.keygo.core.identity.biometric.presentation.model.BiometricRequest
import de.davis.keygo.core.presentation.ObserveAsEvents
import org.koin.androidx.compose.koinViewModel

Expand All @@ -16,18 +18,18 @@ fun AuthScreen(onSuccess: () -> Unit) {
onSuccess()
}

BiometricAuthHandler(
flow = viewModel.biometricRequests,
onAuthenticationSucceeded = {
viewModel.onEvent(AuthUIEvent.BiometricSuccess(it))
},
onAuthenticationError = { _, _ ->
viewModel.onEvent(AuthUIEvent.BiometricError)
},
onAuthenticationFailed = {
viewModel.onEvent(AuthUIEvent.BiometricFailure)
BiometricPromptSupport {
val biometricManager = LocalBiometricManager.current

ObserveAsEvents(viewModel.biometricRequests) {
when (it) {
is BiometricRequest.Class3 -> {
val result = biometricManager.authenticate(it)
viewModel.onBiometricResult(result)
}
}
}
)

AuthContent(state = state, onEvent = viewModel::onEvent)
AuthContent(state = state, onEvent = viewModel::onEvent)
}
}
Loading