Compare commits

...

5 commits

Author SHA1 Message Date
384270f57b
fix: usb isd-r aid fallback 2025-04-01 18:39:43 +08:00
00ddf09287 fix: improve lpa string parsing (#181)
Reviewed-on: PeterCxy/OpenEUICC#181
Co-authored-by: septs <github@septs.pw>
Co-committed-by: septs <github@septs.pw>
2025-04-01 03:19:21 +02:00
3662f93760 fix: send terminal capabilities (#187)
fix 9eSIM v1 (G+D) on USB

Reviewed-on: PeterCxy/OpenEUICC#187
Co-authored-by: septs <github@septs.pw>
Co-committed-by: septs <github@septs.pw>
2025-04-01 03:18:45 +02:00
05abed117a fix: click sn copy (#186)
Reviewed-on: PeterCxy/OpenEUICC#186
Co-authored-by: septs <github@septs.pw>
Co-committed-by: septs <github@septs.pw>
2025-04-01 03:18:22 +02:00
92fbfc5229 chore: add more isd-r aids (#184)
Reviewed-on: PeterCxy/OpenEUICC#184
Co-authored-by: septs <github@septs.pw>
Co-committed-by: septs <github@septs.pw>
2025-04-01 03:18:02 +02:00
7 changed files with 45 additions and 24 deletions

View file

@ -55,7 +55,7 @@ open class DefaultEuiccChannelManager(
parseIsdrAidList(appContainer.preferenceRepository.isdrAidListFlow.first())
return isdrAidList.firstNotNullOfOrNull {
Log.i(TAG, "Opening channel, trying ISDR AID ${it.encodeHex()}")
Log.i(TAG, "Opening channel, trying ISD-R AID: ${it.encodeHex()}")
openFn(it)?.let { channel ->
if (channel.valid) {
@ -277,11 +277,11 @@ open class DefaultEuiccChannelManager(
)
try {
val channel = tryOpenChannelFirstValidAid {
euiccChannelFactory.tryOpenUsbEuiccChannel(
device,
iface,
it
)
try {
euiccChannelFactory.tryOpenUsbEuiccChannel(device, iface, it)
} catch (_: IllegalArgumentException) {
null
}
}
if (channel != null && channel.lpa.valid) {
usbChannel = channel

View file

@ -45,6 +45,15 @@ class UsbApduInterface(
e.printStackTrace()
throw e
}
// Send Terminal Capabilities
// Specs: ETSI TS 102 221 v15.0.0 - 11.1.19 TERMINAL CAPABILITY
val terminalCapabilities = buildCmd(
0x80.toByte(), 0xaa.toByte(), 0x00, 0x00,
"A9088100820101830107".decodeHex(),
le = null,
)
transmitApduByChannel(terminalCapabilities, 0)
}
override fun disconnect() {

View file

@ -104,7 +104,7 @@ class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker {
add(Item(R.string.euicc_info_eid, channel.lpa.eID, copiedToastResId = R.string.toast_eid_copied))
channel.tryParseEuiccVendorInfo()?.let { vendorInfo ->
vendorInfo.skuName?.let { add(Item(R.string.euicc_info_sku, it)) }
vendorInfo.serialNumber?.let { add(Item(R.string.euicc_info_sn, it)) }
vendorInfo.serialNumber?.let { add(Item(R.string.euicc_info_sn, it, copiedToastResId = R.string.toast_sn_copied)) }
vendorInfo.firmwareVersion?.let { add(Item(R.string.euicc_info_fw_ver, it)) }
vendorInfo.bootloaderVersion?.let { add(Item(R.string.euicc_info_bl_ver, it)) }
}

View file

@ -8,15 +8,15 @@ data class LPAString(
) {
companion object {
fun parse(input: String): LPAString {
val components = input.removePrefix("LPA:").split('$')
if (components.size < 2 || components[0] != "1") {
throw IllegalArgumentException("Invalid activation code format")
}
var token = input
if (token.startsWith("LPA:", ignoreCase = true)) token = token.drop(4)
val components = token.split('$').map { it.trim().ifBlank { null } }
require(components.getOrNull(0) == "1") { "Invalid AC_Format" }
return LPAString(
address = components[1].trim(),
matchingId = components.getOrNull(2)?.trim()?.ifBlank { null },
oid = components.getOrNull(3)?.trim()?.ifBlank { null },
confirmationCodeRequired = components.getOrNull(4)?.trim() == "1"
requireNotNull(components.getOrNull(1)) { "SM-DP+ is required" },
components.getOrNull(2),
components.getOrNull(3),
components.getOrNull(4) == "1"
)
}
}

View file

@ -45,11 +45,22 @@ const val EUICC_DEFAULT_ISDR_AID = "A0000005591010FFFFFFFF8900000100"
internal object PreferenceConstants {
val DEFAULT_AID_LIST = """
# One AID per line. Comment lines start with #.
# Refs: <https://euicc-manual.osmocom.org/docs/lpa/applet-id-oem/>
# eUICC standard
$EUICC_DEFAULT_ISDR_AID
# 5ber
# eSTK.me
A06573746B6D65FFFFFFFF4953442D52
# eSIM.me
A0000005591010000000008900000300
# 5ber.eSIM
A0000005591010FFFFFFFF8900050500
# Xesim
A0000005591010FFFFFFFF8900000177
""".trimIndent()
}
@ -97,8 +108,7 @@ class PreferenceFlowWrapper<T> private constructor(
defaultValue: T,
encoder: (T) -> T,
decoder: (T) -> T
) :
this(
) : this(
context,
key,
context.dataStore.data.map { it[key]?.let(decoder) ?: defaultValue },

View file

@ -36,6 +36,7 @@ fun formatFreeSpace(size: Int): String =
fun parseIsdrAidList(s: String): List<ByteArray> =
s.split('\n').map(String::trim).filter { !it.startsWith('#') }
.map(String::trim)
.filter(String::isNotEmpty)
.mapNotNull {
try {
it.decodeHex()

View file

@ -11,6 +11,7 @@
android:id="@+id/isdr_aid_list_editor"
android:layout_width="0dp"
android:layout_height="0dp"
android:fontFamily="monospace"
android:importantForAutofill="no"
android:inputType="textMultiLine"
android:gravity="top|start"