@dotrino/identity 0.110.0 → 0.110.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotrino/identity",
3
- "version": "0.110.0",
3
+ "version": "0.110.2",
4
4
  "description": "Identidad y rating de usuarios compartidos entre apps de Dotrino (vault iframe + postMessage)",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/vault/core.js CHANGED
@@ -1124,12 +1124,11 @@ export async function createIdentityCore ({ kv: hostKv, peers, makeSync = null,
1124
1124
  if (keyStore?.importPair) {
1125
1125
  // DENTRO DE UNA APP NATIVA: la llave que entrega la bóveda la guarda la app (cifrada
1126
1126
  // con una llave del chip) y firma ella. Van las dos mitades juntas, bajo un mismo id.
1127
- if (!entrada.keys.enc || !entrada.encPublickey) {
1128
- throw Object.assign(new Error('this login has no encryption key: the phone needs both'), { code: 'native-import-needs-enc' })
1129
- }
1127
+ // Si la bóveda no entrega llave de cifrado, la app estrena una (como hace el navegador).
1128
+ const traeEnc = !!(entrada.keys.enc && entrada.encPublickey)
1130
1129
  await keyStore.importPair({
1131
1130
  sign: { name: _scoped(KEY_STORAGE), privateJwk: sinTopes(entrada.keys.sign), publickey: entrada.publickey },
1132
- enc: { name: _scoped(ENC_KEY_STORAGE), privateJwk: sinTopes(entrada.keys.enc), publickey: entrada.encPublickey }
1131
+ enc: { name: _scoped(ENC_KEY_STORAGE), privateJwk: traeEnc ? sinTopes(entrada.keys.enc) : null, publickey: traeEnc ? entrada.encPublickey : null }
1133
1132
  })
1134
1133
  kv.removeItem(KEY_STORAGE); kv.removeItem(ENC_KEY_STORAGE)
1135
1134
  } else {
@@ -83,15 +83,16 @@ export function withExternalKeys (keyStore, bridge) {
83
83
  * puede meter en el chip, así que la app la guarda cifrada con una llave del chip y firma
84
84
  * ella. Desde aquí es una llave externa más: la página no se queda con la privada.
85
85
  * `sign` y `enc`: `{ name, privateJwk, publickey }`, con la pública TAL CUAL la escribe el
86
- * acta (es la cadena con la que esa llave es miembro).
86
+ * acta (es la cadena con la que esa llave es miembro). Si la bóveda no entrega la de
87
+ * cifrado (`enc.privateJwk` nulo), la app estrena una y devuelve su pública.
87
88
  */
88
89
  async importPair ({ sign, enc }) {
89
- const k = await bridge.call('import', {
90
- sign: sign.privateJwk, enc: enc.privateJwk, publickey: sign.publickey, encPub: enc.publickey
91
- })
92
- if (!k?.kid) throw Object.assign(new Error('the phone did not keep the key'), { code: 'native-no-key' })
90
+ const params = { sign: sign.privateJwk, publickey: sign.publickey }
91
+ if (enc.privateJwk) { params.enc = enc.privateJwk; params.encPub = enc.publickey }
92
+ const k = await bridge.call('import', params)
93
+ if (!k?.kid || !k.encPub) throw Object.assign(new Error('the phone did not keep the key'), { code: 'native-no-key' })
93
94
  await keyStore.set(sign.name, { external: k.kid, kind: 'sign', publicJwk: JSON.parse(sign.publickey) })
94
- await keyStore.set(enc.name, { external: k.kid, kind: 'enc', publicJwk: JSON.parse(enc.publickey) })
95
+ await keyStore.set(enc.name, { external: k.kid, kind: 'enc', publicJwk: JSON.parse(enc.publickey || k.encPub) })
95
96
  },
96
97
  async create (kind, name) {
97
98
  // Las dos mitades del perfil van bajo la MISMA llave del chip: si la otra ya nació
package/vault/vault.js CHANGED
@@ -531,8 +531,14 @@ import { useBackend as usePeerBackend } from './peerStore.js'
531
531
  // dato que la aplicación no puede falsificar —el navegador lo garantiza— y de él
532
532
  // depende a quién se le concedió qué.
533
533
  const result = await handler({ ...(params || {}), __origin: event.origin })
534
+ // DENTRO DE LA APP, lo guardado viaja a la app por una cola (`nativeStore.js`). Quien
535
+ // llama suele NAVEGAR en cuanto recibe la respuesta (entrar con contraseña vuelve a
536
+ // donde estaba; cambiar de perfil recarga), y eso destruye este iframe con la cola a
537
+ // medias: la cuenta quedaba en Pedidos y no en la lista de perfiles (2026-10-12).
538
+ if (native) await native.flush()
534
539
  reply({ result })
535
540
  } catch (e) {
541
+ if (native) await native.flush()
536
542
  // `code` (y su `detail`) CRUZAN. Sin ellos, al otro lado solo llegaba la frase, y una
537
543
  // app que quiere reaccionar a un rechazo concreto —«esa bóveda ya está en otra cuenta
538
544
  // de este aparato»— no tenía más remedio que emparejarla por su texto: se traduce o se