mirror of
https://github.com/tailscale/tailscale.git
synced 2026-09-15 15:29:33 -04:00
This patch pulls the printing and JSON-encoding out of feature/tailnetlock/tslockjsonv1 into their callers, so that this package only handles type conversions. In cmd/tailscale/cli/tailnet-lock.go, it extracts the printTailnetLockStatus function from runTailnetLockStatus to mirror printTailnetLockLog and runTailnetLockLog. Updates #17613 Signed-off-by: Simon Law <sfllaw@tailscale.com>
100 lines
2.9 KiB
Go
100 lines
2.9 KiB
Go
// Copyright (c) Tailscale Inc & contributors
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
//go:build !ts_omit_tailnetlock
|
|
|
|
package tslockjsonv1
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/base64"
|
|
"fmt"
|
|
|
|
"tailscale.com/cmd/tailscale/jsonoutput"
|
|
"tailscale.com/cmd/tailscale/tslockjsonv1"
|
|
"tailscale.com/ipn/ipnstate"
|
|
"tailscale.com/tka"
|
|
)
|
|
|
|
// LogResponse returns the stored TKA state as a JSON object to the CLI,
|
|
// in a stable "v1" format.
|
|
//
|
|
// This format includes:
|
|
//
|
|
// - the AUM hash as a base32-encoded string
|
|
// - the raw AUM as base64-encoded bytes
|
|
// - the expanded AUM, which prints named fields for consumption by other tools
|
|
func LogResponse(updates []ipnstate.NetworkLockUpdate) (tslockjsonv1.LogResponse, error) {
|
|
var zero tslockjsonv1.LogResponse
|
|
resp := tslockjsonv1.LogResponse{
|
|
ResponseEnvelope: jsonoutput.ResponseEnvelope{
|
|
SchemaVersion: "1",
|
|
},
|
|
Messages: make([]tslockjsonv1.LogMessage, len(updates)),
|
|
}
|
|
|
|
for i, update := range updates {
|
|
var aum tka.AUM
|
|
if err := aum.Unserialize(update.Raw); err != nil {
|
|
return zero, fmt.Errorf("decoding: %w", err)
|
|
}
|
|
|
|
h := aum.Hash()
|
|
|
|
if !bytes.Equal(h[:], update.Hash[:]) {
|
|
return zero, fmt.Errorf("incorrect AUM hash: got %v, want %v", h, update)
|
|
}
|
|
|
|
resp.Messages[i] = logMessage(aum, update)
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
// logMessage converts a [tka.AUM] and [ipnstate.TailnetLockUpdate]
|
|
// the JSON output returned by the CLI, in a stable "v1" format.
|
|
func logMessage(aum tka.AUM, update ipnstate.TailnetLockUpdate) tslockjsonv1.LogMessage {
|
|
expandedAUM := tslockjsonv1.AUM{}
|
|
expandedAUM.MessageKind = aum.MessageKind.String()
|
|
if len(aum.PrevAUMHash) > 0 {
|
|
expandedAUM.PrevAUMHash = aum.PrevAUMHash.String()
|
|
}
|
|
if key := aum.Key; key != nil {
|
|
expandedAUM.Key = tkaKey(key)
|
|
}
|
|
if keyID := aum.KeyID; keyID != nil {
|
|
expandedAUM.KeyID = fmt.Sprintf("tlpub:%x", keyID)
|
|
}
|
|
if state := aum.State; state != nil {
|
|
expandedState := tslockjsonv1.TKAState{}
|
|
if h := state.LastAUMHash; h != nil {
|
|
expandedState.LastAUMHash = h.String()
|
|
}
|
|
for _, secret := range state.DisablementValues {
|
|
expandedState.DisablementValues = append(expandedState.DisablementValues, fmt.Sprintf("%x", secret))
|
|
}
|
|
for _, key := range state.Keys {
|
|
expandedState.Keys = append(expandedState.Keys, tkaKey(&key))
|
|
}
|
|
expandedState.StateID1 = state.StateID1
|
|
expandedState.StateID2 = state.StateID2
|
|
expandedAUM.State = expandedState
|
|
}
|
|
if votes := aum.Votes; votes != nil {
|
|
expandedAUM.Votes = *votes
|
|
}
|
|
expandedAUM.Meta = aum.Meta
|
|
for _, signature := range aum.Signatures {
|
|
expandedAUM.Signatures = append(expandedAUM.Signatures, tslockjsonv1.Signature{
|
|
KeyID: fmt.Sprintf("tlpub:%x", signature.KeyID),
|
|
Signature: base64.URLEncoding.EncodeToString(signature.Signature),
|
|
})
|
|
}
|
|
|
|
return tslockjsonv1.LogMessage{
|
|
Hash: aum.Hash().String(),
|
|
AUM: expandedAUM,
|
|
Raw: base64.URLEncoding.EncodeToString(update.Raw),
|
|
}
|
|
}
|