@authon/react-native-wallet 0.5.1 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# @authon/react-native-wallet
|
|
2
2
|
|
|
3
|
+
## 0.5.2
|
|
4
|
+
|
|
5
|
+
- Signing, `accounts()`, `protect()` and `upgradeBackup()` fail with `NEEDS_RESTORE` when this device holds a share of an older generation than the server, instead of `ADDRESS_MISMATCH` (Swift and Kotlin). This happens when a backup was saved on the server but the device could not store its new share, or after another device upgraded the backup. `status()` already reports `needsRestore` in that case; `restore()` with the existing backup passkey brings the device back. Calling `protect()` again on a device already in that state no longer reports success. This detects the state on later calls; it does not make the server and device writes atomic. `revokeDevice()` skips the local share check, and the server's own device checks still apply (a device left behind by another device's upgrade is refused there).
|
|
6
|
+
|
|
3
7
|
## 0.5.1
|
|
4
8
|
|
|
5
9
|
- `AuthonWalletError` gains `reason`, `phase` and `clientAttemptId` (null when not reported). Android: when the passkey provider says it cannot validate the RP for this app (a DataError of the "RP ID cannot be validated" family), `protect()`, `upgradeBackup()` and `restore()` fail with `ORIGIN_NOT_ALLOWED`, `reason: 'PASSKEY_RP_VALIDATION_FAILED'`, `phase: 'passkey.create.rpValidation'` (or `passkey.get.rpValidation`) and `retryable: false` instead of `INTERNAL`. Other provider data errors stay `INTERNAL`. `phase` is set on Android Credential Manager failures and `clientAttemptId` (a random device-side ID) on those other than a cancel or a missing passkey; all three are null on iOS and from older natives. `diagnosticId` stays the server request ID only.
|
|
@@ -171,11 +171,18 @@ internal class WalletOps(private val ctx: WalletContext) {
|
|
|
171
171
|
|
|
172
172
|
private class Local(val record: DeviceRecord, val wallet: ServerWallet)
|
|
173
173
|
|
|
174
|
-
|
|
174
|
+
/**
|
|
175
|
+
* The local record for this user's wallet. With [currentShare] (every path that opens the device
|
|
176
|
+
* share) a share from an older generation is refused: the server rotated the shares (another
|
|
177
|
+
* device's upgrade, or a backup that committed before this device could save its new share), and
|
|
178
|
+
* combining the old share with the new company share would only fail later as ADDRESS_MISMATCH.
|
|
179
|
+
*/
|
|
180
|
+
private suspend fun requireLocal(session: String, currentShare: Boolean = true): Local {
|
|
175
181
|
val wallet = ctx.api.getMe(session)
|
|
176
182
|
if (wallet == null || wallet.status == "pending") throw walletError(WalletErrorCode.NOT_FOUND)
|
|
177
183
|
val record = ctx.store.get(recordKey(session))
|
|
178
184
|
if (record == null || record.walletId != wallet.id) throw walletError(WalletErrorCode.NEEDS_RESTORE)
|
|
185
|
+
if (currentShare && record.shareVersion != wallet.shareVersion) throw walletError(WalletErrorCode.NEEDS_RESTORE)
|
|
179
186
|
return Local(record, wallet)
|
|
180
187
|
}
|
|
181
188
|
|
|
@@ -527,7 +534,7 @@ internal class WalletOps(private val ctx: WalletContext) {
|
|
|
527
534
|
|
|
528
535
|
suspend fun revokeDevice(session: String, deviceId: String): Boolean {
|
|
529
536
|
if (deviceId.isEmpty()) throw walletError(WalletErrorCode.INVALID_REQUEST, "deviceId required")
|
|
530
|
-
val local = requireLocal(session)
|
|
537
|
+
val local = requireLocal(session, currentShare = false)
|
|
531
538
|
ctx.api.revokeDevice(session, deviceId, deviceProof(session, local.record))
|
|
532
539
|
if (local.record.deviceId == deviceId) ctx.store.delete(recordKey(session))
|
|
533
540
|
return true
|
|
@@ -261,11 +261,16 @@ struct WalletOps {
|
|
|
261
261
|
return try await status(session)
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
-
|
|
264
|
+
/// The local record for this user's wallet. With `currentShare` (every path that opens the device
|
|
265
|
+
/// share) a share from an older generation is refused: the server rotated the shares (another
|
|
266
|
+
/// device's upgrade, or a backup that committed before this device could save its new share), and
|
|
267
|
+
/// combining the old share with the new company share would only fail later as addressMismatch.
|
|
268
|
+
private func requireLocal(_ session: String, currentShare: Bool = true) async throws -> (record: DeviceRecord, wallet: ServerWallet) {
|
|
265
269
|
guard let wallet = try await ctx.api.getMe(session), wallet.status != "pending" else { throw WalletError(.notFound) }
|
|
266
270
|
guard let record = try ctx.store.get(try recordKey(session)), record.walletId == wallet.id else {
|
|
267
271
|
throw WalletError(.needsRestore)
|
|
268
272
|
}
|
|
273
|
+
if currentShare && record.shareVersion != wallet.shareVersion { throw WalletError(.needsRestore) }
|
|
269
274
|
return (record, wallet)
|
|
270
275
|
}
|
|
271
276
|
|
|
@@ -647,7 +652,7 @@ struct WalletOps {
|
|
|
647
652
|
/// Revokes a device with a request signed by this device's key.
|
|
648
653
|
func revokeDevice(_ session: String, deviceId: String) async throws {
|
|
649
654
|
guard !deviceId.isEmpty else { throw WalletError(.invalidRequest, "deviceId required") }
|
|
650
|
-
let (record, _) = try await requireLocal(session)
|
|
655
|
+
let (record, _) = try await requireLocal(session, currentShare: false)
|
|
651
656
|
try await ctx.api.revokeDevice(session, deviceId: deviceId, proof: try await deviceProof(session, record))
|
|
652
657
|
if record.deviceId == deviceId { try ctx.store.delete(try recordKey(session)) }
|
|
653
658
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@authon/react-native-wallet",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "Authon embedded wallet for React Native (Expo native module wrapping the Swift and Kotlin wallet SDKs)",
|
|
5
5
|
"main": "./build/index.js",
|
|
6
6
|
"types": "./build/index.d.ts",
|