Skip to content

Commit bc66a44

Browse files
committed
Move TestCertStore to separate file
1 parent 42d883e commit bc66a44

File tree

2 files changed

+96
-80
lines changed

2 files changed

+96
-80
lines changed

lib/src/test/java/at/bitfire/cert4android/CustomCertManagerTest.kt

Lines changed: 0 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -128,84 +128,4 @@ class CustomCertManagerTest {
128128
}
129129
}
130130

131-
132-
class TestCertStore(): CertStore {
133-
134-
private val logger
135-
get() = Logger.getLogger(javaClass.name)
136-
137-
/** custom TrustStore (simple map) */
138-
@VisibleForTesting
139-
internal val userKeyStore = mutableMapOf<String, X509Certificate>()
140-
141-
/** in-memory store for untrusted certs */
142-
@VisibleForTesting
143-
internal var untrustedCerts = HashSet<X509Certificate>()
144-
145-
@Synchronized
146-
override fun clearUserDecisions() {
147-
logger.info("Clearing user-(dis)trusted certificates")
148-
149-
for (alias in userKeyStore.keys)
150-
userKeyStore.remove(alias)
151-
152-
// clear untrusted certs
153-
untrustedCerts.clear()
154-
}
155-
156-
/**
157-
* Determines whether a certificate chain is trusted.
158-
*/
159-
override fun isTrusted(chain: Array<X509Certificate>, authType: String, trustSystemCerts: Boolean, appInForeground: StateFlow<Boolean>?): Boolean {
160-
if (chain.isEmpty())
161-
throw IllegalArgumentException("Certificate chain must not be empty")
162-
val cert = chain[0]
163-
164-
synchronized(this) {
165-
// explicitly accepted by user?
166-
if (isTrustedByUser(cert))
167-
return true
168-
169-
// explicitly rejected by user?
170-
if (untrustedCerts.contains(cert))
171-
return false
172-
173-
// trusted by system? (if applicable)
174-
if (trustSystemCerts)
175-
return true // system trusts all certificates
176-
}
177-
logger.log(Level.INFO, "Certificate not known and running in non-interactive mode, rejecting")
178-
return false
179-
}
180-
181-
/**
182-
* Determines whether a certificate has been explicitly accepted by the user. In this case,
183-
* we can ignore an invalid host name for that certificate.
184-
*/
185-
@Synchronized
186-
override fun isTrustedByUser(cert: X509Certificate): Boolean =
187-
userKeyStore.containsValue(cert)
188-
189-
@Synchronized
190-
override fun setTrustedByUser(cert: X509Certificate) {
191-
val alias = CertUtils.getTag(cert)
192-
logger.info("Trusted by user: ${cert.subjectDN.name} ($alias)")
193-
userKeyStore[alias] = cert
194-
untrustedCerts -= cert
195-
}
196-
197-
@Synchronized
198-
override fun setUntrustedByUser(cert: X509Certificate) {
199-
logger.info("Distrusted by user: ${cert.subjectDN.name}")
200-
201-
// find certificate
202-
val alias = userKeyStore.entries.find { it.value == cert }?.key
203-
if (alias != null)
204-
// and delete, if applicable
205-
userKeyStore.remove(alias)
206-
untrustedCerts += cert
207-
}
208-
209-
}
210-
211131
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
7+
*
8+
* SPDX-License-Identifier: MPL-2.0
9+
*/
10+
11+
package at.bitfire.cert4android
12+
13+
import androidx.annotation.VisibleForTesting
14+
import kotlinx.coroutines.flow.StateFlow
15+
import java.security.cert.X509Certificate
16+
import java.util.logging.Level
17+
import java.util.logging.Logger
18+
19+
class TestCertStore(): CertStore {
20+
21+
private val logger
22+
get() = Logger.getLogger(javaClass.name)
23+
24+
/** custom TrustStore (simple map) */
25+
@VisibleForTesting
26+
internal val userKeyStore = mutableMapOf<String, X509Certificate>()
27+
28+
/** in-memory store for untrusted certs */
29+
@VisibleForTesting
30+
internal var untrustedCerts = HashSet<X509Certificate>()
31+
32+
@Synchronized
33+
override fun clearUserDecisions() {
34+
logger.info("Clearing user-(dis)trusted certificates")
35+
36+
for (alias in userKeyStore.keys)
37+
userKeyStore.remove(alias)
38+
39+
// clear untrusted certs
40+
untrustedCerts.clear()
41+
}
42+
43+
/**
44+
* Determines whether a certificate chain is trusted.
45+
*/
46+
override fun isTrusted(chain: Array<X509Certificate>, authType: String, trustSystemCerts: Boolean, appInForeground: StateFlow<Boolean>?): Boolean {
47+
if (chain.isEmpty())
48+
throw IllegalArgumentException("Certificate chain must not be empty")
49+
val cert = chain[0]
50+
51+
synchronized(this) {
52+
// explicitly accepted by user?
53+
if (isTrustedByUser(cert))
54+
return true
55+
56+
// explicitly rejected by user?
57+
if (untrustedCerts.contains(cert))
58+
return false
59+
60+
// trusted by system? (if applicable)
61+
if (trustSystemCerts)
62+
return true // system trusts all certificates
63+
}
64+
logger.log(Level.INFO, "Certificate not known and running in non-interactive mode, rejecting")
65+
return false
66+
}
67+
68+
/**
69+
* Determines whether a certificate has been explicitly accepted by the user. In this case,
70+
* we can ignore an invalid host name for that certificate.
71+
*/
72+
@Synchronized
73+
override fun isTrustedByUser(cert: X509Certificate): Boolean =
74+
userKeyStore.containsValue(cert)
75+
76+
@Synchronized
77+
override fun setTrustedByUser(cert: X509Certificate) {
78+
val alias = CertUtils.getTag(cert)
79+
logger.info("Trusted by user: ${cert.subjectDN.name} ($alias)")
80+
userKeyStore[alias] = cert
81+
untrustedCerts -= cert
82+
}
83+
84+
@Synchronized
85+
override fun setUntrustedByUser(cert: X509Certificate) {
86+
logger.info("Distrusted by user: ${cert.subjectDN.name}")
87+
88+
// find certificate
89+
val alias = userKeyStore.entries.find { it.value == cert }?.key
90+
if (alias != null)
91+
// and delete, if applicable
92+
userKeyStore.remove(alias)
93+
untrustedCerts += cert
94+
}
95+
96+
}

0 commit comments

Comments
 (0)