// -*- Mode: Go; indent-tabs-mode: t -*-

/*
 * Copyright (C) 2025 Canonical Ltd
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package assemblestate

type (
	// Fingerprint is the sha512 of a TLS certificate
	Fingerprint [64]byte

	// Proof is a piece of data signed by a device's private key.
	Proof []byte

	// DeviceToken is a cryptographically secure random device token (often
	// referred to as RDT) for a device, generated by the device itself.
	DeviceToken string
)

// Auth is a top-level message used in the assemble protocol. This message is
// used prior to any other communications to prove knowledge of a shared secret.
type Auth struct {
	// HMAC is calculated using sha512, using the shared assembly session secret
	// as the HMAC key. The hash is applied to the concatenated byte
	// representation of the following values:
	//   1. The fingerprint of the TLS certificate presented by this message's
	//      sender
	//   2. The device’s RDT value (must match the RDT field)
	// Failure to match this pattern will result in authentication being denied.
	HMAC []byte `json:"hmac"`

	// RDT is the random device token associated with the sender of this message.
	RDT DeviceToken `json:"rdt"`
}

// UnknownDevices is a top-level message used in the assemble protocol. This
// message is used to query another device for device identities.
type UnknownDevices struct {
	// Devices is the list of devices that the sender of this message would like
	// identifying information for.
	Devices []DeviceToken `json:"devices"`
}

// Devices is a top-level message used in the assemble protocol. This message is
// used in response to the [UnknownDevices] message.
type Devices struct {
	// Devices contains identifying information about the devices that the
	// sender of this message was queried for.
	Devices []Identity `json:"devices"`
}

// Identity carries the identifying information for a single device in the
// assembly session.
type Identity struct {
	// RDT is this device's random device token.
	RDT DeviceToken `json:"rdt"`

	// TODO: we're not using these yet, but we eventually will.

	// FP is the TLS certificate fingerprint used by this device.
	FP Fingerprint `json:"fp"`

	// SerialBundle is the bundle of assertions required to validate this
	// device's serial assertion, including the serial assertion itself.
	SerialBundle string `json:"serial-bundle"`

	// SerialProof is the HMAC that this device would use to authenticate
	// itself, signed by this device's private key. This signature can be
	// verified using the serial assertion.
	SerialProof Proof `json:"serial-proof"`
}

// Routes is a top-level message used in the assemble protocol. This message is
// used to spread information about topology of the cluster to other peers in
// the cluster.
type Routes struct {
	// Devices is the set of devices that are involved in the routes that this
	// message contains.
	//
	// TODO: once we start using this field to help with discovery, include
	// info about that here.
	Devices []DeviceToken `json:"devices"`

	// Addresses is the set of addresses that are involved in the routes that
	// this message contains.
	Addresses []string `json:"addresses"`

	// Routes contains triplets of indexes where every group of three
	// consecutive values represents one verified route in the cluster:
	//   - Routes[n]   = index into Devices slice (source device)
	//   - Routes[n+1] = index into Devices slice (destination device)
	//   - Routes[n+2] = index into Addresses slice (address to reach destination)
	//
	// For example, if Routes = [0, 1, 0, 2, 1, 1], this represents:
	//   - Route 1: Devices[0] can reach Devices[1] via Addresses[0]
	//   - Route 2: Devices[2] can reach Devices[1] via Addresses[1]
	Routes []int `json:"routes"`
}
