Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
0624288
feat: new security system (phase 1)
HashEngineering Dec 19, 2025
5ab1962
feat: new security system (phase 2)
HashEngineering Dec 20, 2025
4cf7737
feat: add fallback testing
HashEngineering Dec 20, 2025
f1f0591
fix: add propagate context
HashEngineering Dec 21, 2025
a967b50
feat: add add security status and track
HashEngineering Dec 23, 2025
7f30bdb
feat: add add security status and track
HashEngineering Dec 23, 2025
1b20d3d
feat: add add security status and track
HashEngineering Dec 23, 2025
57963fd
feat: add another test failure mode
HashEngineering Dec 23, 2025
c9a3d5f
feat: new security system phase 3, recovery
HashEngineering Dec 23, 2025
a794696
feat: remove obsolete files
HashEngineering Dec 24, 2025
dd2f403
feat: notify user of lost password/PIN
HashEngineering Dec 30, 2025
110be64
feat: other updates
HashEngineering Dec 30, 2025
fd21786
feat: update dialogs with new components
HashEngineering Dec 30, 2025
47403ba
feat: restore migration step
HashEngineering Jan 5, 2026
86efb03
feat: prevent crashes
HashEngineering Jan 6, 2026
9c73707
fixes: minor fixes
HashEngineering Jan 8, 2026
e38b795
fix: minor fixes
HashEngineering Jan 9, 2026
d3b0dd6
docs: add QA test protocol
HashEngineering Jan 9, 2026
8e61189
Merge branch 'master' of https://github.com/dashevo/dash-wallet into …
HashEngineering Jan 9, 2026
61e1f54
fix: remove debug UI elements
HashEngineering Jan 12, 2026
a8168a6
fix: remove password dumps in debug mode
HashEngineering Jan 12, 2026
06c8fe5
fix: only set healthy status if encryption is true
HashEngineering Jan 12, 2026
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
915 changes: 915 additions & 0 deletions .claude/agents/DEVELOPMENT-PATTERNS.md

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ buildscript {
kotlin_version = '2.1.0'
coroutinesVersion = '1.6.4'
ok_http_version = '4.12.0'
dashjVersion = '21.1.13'
dashjVersion = '21.1.14-SNAPSHOT'
dppVersion = "2.0.2"
hiltVersion = '2.53'
hiltCompilerVersion = '1.2.0'
Expand Down Expand Up @@ -76,5 +76,9 @@ allprojects {
mavenCentral()
maven { url 'https://jitpack.io' }
maven { url 'https://s01.oss.sonatype.org/content/repositories/snapshots/' }
maven {
name 'Central Portal Snapshots'
url 'https://central.sonatype.com/repository/maven-snapshots/'
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2025 Dash Core Group.
*
* 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/>.
*/

package org.dash.wallet.common.data

enum class SecuritySystemStatus(
val value: Int,
val isHealthy: Boolean,
val hasFallback: Boolean
) {
DEAD(0, false, false),
FALLBACKS(2, false, true),
HEALTHY(1, true, false),
HEALTHY_WITH_FALLBACKS(3, true, true);
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ data class BlockchainState(var bestChainDate: Date?,
}

enum class Impediment {
STORAGE, NETWORK
STORAGE, NETWORK, SECURITY
}

fun syncFailed(): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@
package org.dash.wallet.common.services

import androidx.fragment.app.FragmentActivity
import kotlinx.coroutines.flow.Flow
import org.bitcoinj.core.Address
import org.dash.wallet.common.data.SecuritySystemStatus

interface AuthenticationManager {
fun authenticate(activity: FragmentActivity, pinOnly: Boolean = false, callback: (String?) -> Unit)
suspend fun authenticate(activity: FragmentActivity, pinOnly: Boolean = false): String?
suspend fun signMessage(address: Address, message: String): String
fun getHealth(): SecuritySystemStatus
fun observeHealth(): Flow<SecuritySystemStatus>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
/*
* Copyright 2025 Dash Core Group.
*
* 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/>.
*/

package org.dash.wallet.common.ui.components

import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import org.dash.wallet.common.R

data class FeatureItem(
val heading: String,
val text: String? = null,
val icon: ImageVector? = null,
val number: String? = null
)

@Composable
fun FeatureItemNumber(
number: String,
modifier: Modifier = Modifier
) {
Box(
modifier = modifier
.size(24.dp)
.background(
color = MyTheme.Colors.dashBlue,
shape = RoundedCornerShape(8.dp)
),
contentAlignment = Alignment.Center
) {
Text(
text = number,
fontSize = 14.sp,
color = Color.White,
textAlign = TextAlign.Center
)
}
}

@Composable
fun FeatureSingleItem(
heading: String,
text: String? = null,
modifier: Modifier = Modifier,
icon: ImageVector? = null,
number: String? = null
) {
Row(
modifier = modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalAlignment = Alignment.Top
) {
Box(
modifier = Modifier
.size(40.dp)
.padding(top = 10.dp),
contentAlignment = Alignment.TopCenter
) {
when {
number != null -> {
FeatureItemNumber(number = number)
}
icon != null -> {
Icon(
imageVector = icon,
contentDescription = null,
modifier = Modifier.size(20.dp),
tint = MyTheme.Colors.gray300
)
}
else -> {
Box(
modifier = Modifier
.size(20.dp)
.border(
width = 2.5.dp,
color = MyTheme.Colors.gray300,
shape = RoundedCornerShape(5.dp)
)
)
}
}
}

Column(
modifier = Modifier
.weight(1f)
.padding(top = 10.dp),
verticalArrangement = Arrangement.spacedBy(2.dp)
) {
Text(
text = heading,
style = MyTheme.Typography.TitleSmallMedium,
color = MyTheme.Colors.textPrimary
)
if (text != null) {
Text(
text = text,
style = MyTheme.Typography.BodyMedium,
color = MyTheme.Colors.textSecondary
)
}
}
}
}

@Composable
fun FeatureList(
items: List<FeatureItem>,
modifier: Modifier = Modifier
) {
Column(
modifier = modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
items.forEach { item ->
FeatureSingleItem(
heading = item.heading,
text = item.text,
icon = item.icon,
number = item.number
)
}
}
}

@Preview(showBackground = true)
@Composable
private fun FeatureSingleItemPreview() {
Box(
modifier = Modifier
.fillMaxWidth()
.background(Color.White)
.padding(20.dp)
) {
FeatureSingleItem(
heading = "heading",
text = "text"
)
}
}

@Preview(showBackground = true)
@Composable
private fun FeatureListPreview() {
Box(
modifier = Modifier
.fillMaxWidth()
.background(Color.White)
.padding(20.dp)
) {
FeatureList(
items = listOf(
FeatureItem("heading", "text"),
FeatureItem("heading", "text"),
FeatureItem("heading", "text"),
FeatureItem("heading", "text")
)
)
}
}

@Preview(showBackground = true)
@Composable
private fun FeatureListWithIconsPreview() {
Box(
modifier = Modifier
.fillMaxWidth()
.background(Color.White)
.padding(20.dp)
) {
FeatureList(
items = listOf(
FeatureItem(
"Enhanced Security",
"Your wallet will use the latest encryption technology",
ImageVector.vectorResource(R.drawable.ic_preview)
),
FeatureItem(
"Biometric Support",
"Unlock your wallet with fingerprint or face recognition",
ImageVector.vectorResource(R.drawable.ic_preview)
),
FeatureItem(
"PIN Protection",
"Set a secure PIN to protect your funds",
ImageVector.vectorResource(R.drawable.ic_preview)
),
FeatureItem(
"Recovery Options",
"Multiple ways to recover your wallet if needed",
ImageVector.vectorResource(R.drawable.ic_preview)
)
)
)
}
}

@Preview(showBackground = true)
@Composable
private fun FeatureListWithNumbersPreview() {
Box(
modifier = Modifier
.fillMaxWidth()
.background(Color.White)
.padding(20.dp)
) {
FeatureList(
items = listOf(
FeatureItem(
heading = "Create a secure PIN",
text = "Choose a 6-digit PIN that you'll use to unlock your wallet",
number = "1"
),
FeatureItem(
heading = "Write down your recovery phrase",
text = "Save your 12-word recovery phrase in a safe place",
number = "2"
),
FeatureItem(
heading = "Enable biometric authentication",
text = "Use fingerprint or face recognition for quick access",
number = "3"
),
FeatureItem(
heading = "Start using your wallet",
text = "You're all set! Begin sending and receiving Dash",
number = "4"
)
)
)
}
}
Loading