53f8a4a3d6
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>
51 lines
1.7 KiB
Go
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
|
|
}
|