Files
unibus/pkg/client/directory.go
T
agent 53f8a4a3d6 feat(mobile): reconstruir+ampliar binding gomobile para paridad con la web
El wrapper mobile/unibus.go se habia perdido del repo (solo quedaba compilado
en el .aar del 5 jun). Se reconstruye y amplia con:

- Wallet BIP39 determinista: NewMnemonic, ValidateMnemonic, DeriveAndSaveIdentity.
  Deriva la MISMA identidad que uniweb (web/src/wallet/derive.ts): PBKDF2-BIP39 ->
  HKDF-SHA256(info unibus-sign-v1 / unibus-kex-v1) -> Ed25519 + X25519. Test de
  paridad contra el vector de oro (mnemonica abandon...about -> sign_pub
  34302746...b3c8) garantiza misma cuenta web<->movil byte a byte.
- Selector de salas: Session.ListMyRooms() -> JSON [{id,subject,mode,role}].
- Nombres legibles: Session.Directory() + Client.Directory()/EndpointID() nuevos
  en pkg/client (GET /directory firmado).
- HasIdentity/SignPubAt para el onboarding.

Aditivo; build/vet/test del modulo verdes (incluido TestDeriveParityWithWeb).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 23:38:14 +02:00

51 lines
1.7 KiB
Go

package client
// This file exposes two read helpers the mobile binding needs but that the core
// client did not surface yet: the peer's own endpoint id, and the cluster member
// directory (endpoint id -> human handle). Both are additive and read-only.
// EndpointID returns this peer's stable endpoint id, base64url(sha256(signPub)),
// the value the bus stamps as the sender of every frame this peer publishes.
func (c *Client) EndpointID() string { return c.endpoint }
// DirectoryEntry maps a member's stable endpoint id to a human handle, as served
// by the control plane's GET /directory. A client uses it to render readable names
// instead of raw endpoint ids on incoming frames.
type DirectoryEntry struct {
SignPub string // 64-hex Ed25519 public key
Endpoint string // base64url-nopad, == EndpointID(signPub)
Handle string
Role string
}
type directoryMemberWire struct {
SignPub string `json:"sign_pub"`
Endpoint string `json:"endpoint"`
Handle string `json:"handle"`
Role string `json:"role"`
}
type directoryResp struct {
Members []directoryMemberWire `json:"members"`
}
// Directory fetches the cluster-wide member directory (endpoint id -> handle). Any
// active user may read it; the request is signed like every other control-plane
// call. Returns the active members only (the server filters to status=active).
func (c *Client) Directory() ([]DirectoryEntry, error) {
var resp directoryResp
if err := c.doJSON("GET", "/directory", nil, &resp); err != nil {
return nil, err
}
out := make([]DirectoryEntry, 0, len(resp.Members))
for _, m := range resp.Members {
out = append(out, DirectoryEntry{
SignPub: m.SignPub,
Endpoint: m.Endpoint,
Handle: m.Handle,
Role: m.Role,
})
}
return out, nil
}