[client] Let a logged-out profile deserialize again (review item 2)

ConfigFromJSON refused a document with no WireGuard or SSH key. A config
legitimately has none between a logout and the next login: mobile
LogoutProfile clears both in place and writes the profile back, so the peer
re-registers on the next login instead of returning as itself.

So the refusal broke the mobile flows it was meant to protect. On iOS and
tvOS the stored JSON of a logged-out profile stopped loading through
Client.SetConfigFromJSON and Auth.SetConfigFromJSON, and copyConfig — which
round-trips a Config through JSON to take an in-memory copy before applying
the MDM overlay — failed on the same document. Where the old code silently
minted a key, this returned an error, which is worse for logout and profile
switching alike: neither is asking to connect.

The deserializer now stays out of the identity question in both directions:
it does not generate one (a read cannot hand back keys nothing will write
down) and does not refuse one that is absent. Whoever goes on to connect is
where an absent identity has to be answered — and it already is, by the
login path that provisions and persists.

ErrConfigWithoutIdentity goes with it; nothing else used it.
This commit is contained in:
riccardom
2026-09-11 14:53:04 +02:00
parent 222ad91c4d
commit 07dc9cb1c8
4 changed files with 32 additions and 52 deletions
+5 -6
View File
@@ -130,13 +130,12 @@ func NewClient(cfgFile, stateFile, cacheDir, logFilePath, deviceName string, osV
// SetConfigFromJSON stores the JSON config that later loads resolve instead of the config file (tvOS).
func (c *Client) SetConfigFromJSON(jsonStr string) error {
// Parsed only to reject a bad document early; the JSON itself is what is
// stored, and every load re-parses it. Not only a parse error any more: a
// document with no peer identity is refused too, because Run() would
// otherwise connect as a peer whose key this SDK has no way to hand back
// to the caller's store.
// Parsed only to reject an unreadable document early; the JSON itself is
// what is stored, and every load re-parses it. A document carrying no peer
// identity is readable and accepted: that is a logged-out profile, and the
// login that follows provisions the keys.
if _, err := profilemanager.ConfigFromJSON(jsonStr); err != nil {
log.Errorf("SetConfigFromJSON: failed to load config JSON: %v", err)
log.Errorf("SetConfigFromJSON: failed to parse config JSON: %v", err)
return err
}
c.preloadedConfigJSON.Store(&jsonStr)