Compare commits
2 commits
002c90ba11
...
35be370c16
| Author | SHA1 | Date | |
|---|---|---|---|
| 35be370c16 | |||
| f60a2a5dd6 |
12 changed files with 54 additions and 19 deletions
|
|
@ -24,7 +24,18 @@ class UsbApduInterface(
|
|||
// ATR parser
|
||||
// Specs: ISO/IEC 7816-3:2006 8.2 Answer-to-Reset
|
||||
// See also: https://en.wikipedia.org/wiki/Answer_to_reset
|
||||
class ParsedAtr private constructor(val ts: Byte?, val t0: Byte?, val ta1: Byte?, val tb1: Byte?, val tc1: Byte?, val td1: Byte?, val ta2: Byte?, val tb2: Byte?, val tc2: Byte?, val td2: Byte?) {
|
||||
class ParsedAtr private constructor(
|
||||
val ts: Byte?,
|
||||
val t0: Byte?,
|
||||
val ta1: Byte?,
|
||||
val tb1: Byte?,
|
||||
val tc1: Byte?,
|
||||
val td1: Byte?,
|
||||
val ta2: Byte?,
|
||||
val tb2: Byte?,
|
||||
val tc2: Byte?,
|
||||
val td2: Byte?
|
||||
) {
|
||||
companion object {
|
||||
fun parse(atr: ByteArray): ParsedAtr {
|
||||
val ts = atr[0]
|
||||
|
|
@ -49,8 +60,9 @@ class UsbApduInterface(
|
|||
}
|
||||
}
|
||||
|
||||
return ParsedAtr(ts=ts, t0=t0, ta1=tx1[0], tb1=tx1[1], tc1=tx1[2], td1=tx1[3],
|
||||
ta2=tx2[0], tb2=tx2[1], tc2=tx2[2], td2=tx2[3],
|
||||
return ParsedAtr(
|
||||
ts = ts, t0 = t0, ta1 = tx1[0], tb1 = tx1[1], tc1 = tx1[2], td1 = tx1[3],
|
||||
ta2 = tx2[0], tb2 = tx2[1], tc2 = tx2[2], td2 = tx2[3],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -59,7 +71,7 @@ class UsbApduInterface(
|
|||
override fun connect() {
|
||||
ccidCtx.connect()
|
||||
|
||||
if (ccidCtx.transceiver.useTpdu) {
|
||||
if (ccidCtx.useTpdu) {
|
||||
// Send parameter selection
|
||||
// Specs: USB-CCID 3.2.1 TPDU level of exchange
|
||||
val parsedAtr = ParsedAtr.parse(atr!!)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import android.hardware.usb.UsbInterface
|
|||
import android.hardware.usb.UsbManager
|
||||
import im.angry.openeuicc.util.preferenceRepository
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
/**
|
||||
* A wrapper over an usb device + interface, manages the lifecycle independent
|
||||
|
|
@ -20,7 +22,8 @@ class UsbCcidContext private constructor(
|
|||
private val conn: UsbDeviceConnection,
|
||||
private val bulkIn: UsbEndpoint,
|
||||
private val bulkOut: UsbEndpoint,
|
||||
val verboseLoggingFlow: Flow<Boolean>
|
||||
val verboseLoggingFlow: Flow<Boolean>,
|
||||
val useTpdu: Boolean
|
||||
) {
|
||||
companion object {
|
||||
fun createFromUsbDevice(
|
||||
|
|
@ -33,11 +36,16 @@ class UsbCcidContext private constructor(
|
|||
val conn = context.getSystemService(UsbManager::class.java).openDevice(usbDevice)
|
||||
?: return@runCatching null
|
||||
if (!conn.claimInterface(usbInterface, true)) return@runCatching null
|
||||
|
||||
val forceTpduMode = runBlocking { context.preferenceRepository.forceTpduModeFlow.first() }
|
||||
val useTpdu = forceTpduMode || isKnownTpduReader(usbDevice.vendorId, usbDevice.productId)
|
||||
|
||||
UsbCcidContext(
|
||||
conn,
|
||||
bulkIn,
|
||||
bulkOut,
|
||||
context.preferenceRepository.verboseLoggingFlow
|
||||
context.preferenceRepository.verboseLoggingFlow,
|
||||
useTpdu
|
||||
)
|
||||
}.getOrNull()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,10 +84,6 @@ data class UsbCcidDescription(
|
|||
|
||||
private fun hasFeature(feature: Int) = (dwFeatures and feature) != 0
|
||||
|
||||
private fun hasTpduLevel() = hasFeature(FEATURE_EXCHANGE_LEVEL_TPDU)
|
||||
private fun hasShortApduLevel() = hasFeature(FEATURE_EXCHANGE_LEVEL_SHORT_APDU)
|
||||
private fun hasExtendedApduLevel() = hasFeature(FEATURE_EXCHANGE_LEVEL_EXTENDED_APDU)
|
||||
|
||||
val voltages: List<Voltage>
|
||||
get() {
|
||||
if (hasFeature(FEATURE_AUTOMATIC_VOLTAGE)) return listOf(Voltage.AUTO)
|
||||
|
|
@ -99,7 +95,4 @@ data class UsbCcidDescription(
|
|||
|
||||
val hasT0Protocol: Boolean
|
||||
get() = (dwProtocols and MASK_T0_PROTO) != 0
|
||||
|
||||
val useTpdu: Boolean
|
||||
get() = hasTpduLevel() && !hasShortApduLevel() && !hasExtendedApduLevel()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,12 +143,6 @@ class UsbCcidTransceiver(
|
|||
|
||||
val hasAutomaticPps = usbCcidDescription.hasAutomaticPps
|
||||
|
||||
/**
|
||||
* True if this reader only supports TPDU exchange level (no APDU bits advertised).
|
||||
* These readers require PPS + SetParameters handshake during connect().
|
||||
*/
|
||||
val useTpdu = usbCcidDescription.useTpdu
|
||||
|
||||
private val inputBuffer = ByteArray(usbBulkIn.maxPacketSize)
|
||||
|
||||
private var currentSequenceNumber: Byte = 0
|
||||
|
|
|
|||
|
|
@ -25,3 +25,12 @@ val Iterable<UsbEndpoint>.bulkPair: Pair<UsbEndpoint?, UsbEndpoint?>
|
|||
endpoints.find { it.direction == UsbConstants.USB_DIR_OUT },
|
||||
)
|
||||
}
|
||||
|
||||
val KNOWN_TPDU_READERS: Set<Pair<Int, Int>> = setOf(
|
||||
// USB vendor ID + product ID pairs that require TPDU mode
|
||||
// Realtek RTS5169 from <https://gitea.angry.im/PeterCxy/OpenEUICC/issues/37>
|
||||
Pair(0x0bda, 0x0169)
|
||||
)
|
||||
|
||||
fun isKnownTpduReader(vendorId: Int, productId: Int): Boolean =
|
||||
KNOWN_TPDU_READERS.contains(Pair(vendorId, productId))
|
||||
|
|
|
|||
|
|
@ -71,6 +71,9 @@ open class SettingsFragment : PreferenceFragmentCompat(), OpenEuiccContextMarker
|
|||
requirePreference<CheckBoxPreference>("pref_advanced_verbose_logging")
|
||||
.bindBooleanFlow(preferenceRepository.verboseLoggingFlow)
|
||||
|
||||
requirePreference<CheckBoxPreference>("pref_advanced_force_tpdu_mode")
|
||||
.bindBooleanFlow(preferenceRepository.forceTpduModeFlow)
|
||||
|
||||
requirePreference<CheckBoxPreference>("pref_developer_unfiltered_profile_list")
|
||||
.bindBooleanFlow(preferenceRepository.unfilteredProfileListFlow)
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ internal object PreferenceKeys {
|
|||
// ---- Advanced ----
|
||||
val DISABLE_SAFEGUARD_REMOVABLE_ESIM = booleanPreferencesKey("disable_safeguard_removable_esim")
|
||||
val VERBOSE_LOGGING = booleanPreferencesKey("verbose_logging")
|
||||
val FORCE_TPDU_MODE = booleanPreferencesKey("force_tpdu_mode")
|
||||
|
||||
// ---- Developer Options ----
|
||||
val DEVELOPER_OPTIONS_ENABLED = booleanPreferencesKey("developer_options_enabled")
|
||||
|
|
@ -87,6 +88,7 @@ open class PreferenceRepository(private val context: Context) {
|
|||
// ---- Advanced ----
|
||||
val disableSafeguardFlow = bindFlow(PreferenceKeys.DISABLE_SAFEGUARD_REMOVABLE_ESIM, false)
|
||||
val verboseLoggingFlow = bindFlow(PreferenceKeys.VERBOSE_LOGGING, false)
|
||||
val forceTpduModeFlow = bindFlow(PreferenceKeys.FORCE_TPDU_MODE, false)
|
||||
|
||||
// ---- Developer Options ----
|
||||
val refreshAfterSwitchFlow = bindFlow(PreferenceKeys.REFRESH_AFTER_SWITCH, true)
|
||||
|
|
|
|||
|
|
@ -172,6 +172,8 @@
|
|||
<string name="pref_advanced_disable_safeguard_removable_esim_desc">デフォルトでは、このアプリでデバイスに挿入されたリムーバブル eSIM の有効なプロファイルを無効化することを防いでいます。なぜなのかというと<i>時々</i>アクセスができなくなるからです。\nこのチェックボックスを ON にすることで、この保護機能を<i>解除</i>します。</string>
|
||||
<string name="pref_advanced_verbose_logging">詳細ログ</string>
|
||||
<string name="pref_advanced_verbose_logging_desc">詳細ログを有効化します。これには個人的な情報が含まれている可能性があります。この機能を ON にした後は、信頼できるユーザーとのみログを共有してください。</string>
|
||||
<string name="pref_advanced_force_tpdu_mode">USBリーダーでTPDUモードを強制</string>
|
||||
<string name="pref_advanced_force_tpdu_mode_desc">すべてのUSB CCIDリーダーでTPDUモードを強制します。TPDUのみで動作するUSBリーダーがある場合にのみ有効にしてください。</string>
|
||||
<string name="pref_advanced_language">言語</string>
|
||||
<string name="pref_advanced_language_desc">アプリの言語を設定します。</string>
|
||||
<string name="pref_advanced_logs">ログ</string>
|
||||
|
|
|
|||
|
|
@ -80,6 +80,8 @@
|
|||
<string name="pref_advanced_disable_safeguard_removable_esim_desc">默认情况下,此应用程序会阻止您禁用可插拔 eSIM 中已启用的配置文件。\n因为这样做 <i>有时</i> 会使其无法访问。\n勾选此框以 <i>移除</i> 此保护措施。</string>
|
||||
<string name="pref_advanced_verbose_logging">记录详细日志</string>
|
||||
<string name="pref_advanced_verbose_logging_desc">详细日志中包含敏感信息,开启此功能后请仅与你信任的人共享你的日志。</string>
|
||||
<string name="pref_advanced_force_tpdu_mode">强制 USB 读卡器使用 TPDU 模式</string>
|
||||
<string name="pref_advanced_force_tpdu_mode_desc">强制所有 USB CCID 读卡器使用 TPDU 模式。仅在您的 USB 读卡器仅支持 TPDU 模式时启用。</string>
|
||||
<string name="pref_advanced_logs">日志</string>
|
||||
<string name="pref_advanced_logs_desc">查看应用程序的最新调试日志</string>
|
||||
<string name="pref_developer_isdr_aid_list_desc">某些品牌的可移除 eSIM 可能会使用自己的非标准 ISD-R AID,导致第三方应用无法访问。此 App 可以尝试使用此列表中添加的非标准 AID,但不能保证它们一定有效。</string>
|
||||
|
|
|
|||
|
|
@ -76,6 +76,8 @@
|
|||
<string name="pref_notifications_switch">切換</string>
|
||||
<string name="pref_advanced_verbose_logging">記錄詳細日誌</string>
|
||||
<string name="pref_advanced_verbose_logging_desc">詳細日誌中包含敏感資訊,開啟此功能後請僅與你信任的人共享你的日誌。</string>
|
||||
<string name="pref_advanced_force_tpdu_mode">強制 USB 讀卡機使用 TPDU 模式</string>
|
||||
<string name="pref_advanced_force_tpdu_mode_desc">強制所有 USB CCID 讀卡機使用 TPDU 模式。僅在您的 USB 讀卡機僅支援 TPDU 模式時啟用。</string>
|
||||
<string name="pref_advanced_logs">日誌</string>
|
||||
<string name="pref_advanced_logs_desc">檢視應用程式的最新除錯日誌</string>
|
||||
<string name="pref_notifications_switch_desc">傳送 <i>切換</i> 設定檔的通知\n注意,這個狀態的通知不一定有用。</string>
|
||||
|
|
|
|||
|
|
@ -208,6 +208,8 @@
|
|||
<string name="pref_advanced_disable_safeguard_removable_esim_desc">By default, this app prevents you from disabling the active profile on a removable eSIM inserted in the device, because doing so may <i>sometimes</i> render it inaccessible.\nCheck this box to <i>remove</i> this safeguard.</string>
|
||||
<string name="pref_advanced_verbose_logging">Verbose Logging</string>
|
||||
<string name="pref_advanced_verbose_logging_desc">Enable verbose logs, which may contain sensitive information. Only share your logs with someone you trust after turning this on.</string>
|
||||
<string name="pref_advanced_force_tpdu_mode">Force TPDU Mode for USB Readers</string>
|
||||
<string name="pref_advanced_force_tpdu_mode_desc">Force TPDU mode for all USB CCID readers. Only enable if you have a USB reader that only works under TPDU.</string>
|
||||
<string name="pref_advanced_language">Language</string>
|
||||
<string name="pref_advanced_language_desc">Select app language</string>
|
||||
<string name="pref_advanced_logs">Logs</string>
|
||||
|
|
|
|||
|
|
@ -37,6 +37,12 @@
|
|||
app:summary="@string/pref_advanced_verbose_logging_desc"
|
||||
app:title="@string/pref_advanced_verbose_logging" />
|
||||
|
||||
<CheckBoxPreference
|
||||
app:iconSpaceReserved="false"
|
||||
app:key="pref_advanced_force_tpdu_mode"
|
||||
app:summary="@string/pref_advanced_force_tpdu_mode_desc"
|
||||
app:title="@string/pref_advanced_force_tpdu_mode" />
|
||||
|
||||
<Preference
|
||||
app:iconSpaceReserved="false"
|
||||
app:isPreferenceVisible="false"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue