implement full request flow

This commit is contained in:
Jared Allard 2025-03-06 21:33:46 -08:00
parent cb20155b1e
commit affa5919f7
Signed by: jaredallard
SSH key fingerprint: SHA256:wyRyyv28jBYw8Yp/oABNPUYvbGd6hyZj23XVXEm5G/U
7 changed files with 214 additions and 60 deletions

View file

@ -29,10 +29,12 @@ import (
func newNewCommand() *cobra.Command {
// TODO(jaredallard): Support setting the name of the machine.
return &cobra.Command{
Use: "new",
Use: "new <machineName>",
Short: "Create a new machine",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, _ []string) error {
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
name := args[0] // Checked by [cobra.ExactArgs] above.
db, err := db.New(cmd.Context())
if err != nil {
return fmt.Errorf("failed to open DB: %w", err)
@ -54,7 +56,7 @@ func newNewCommand() *cobra.Command {
return err
}
if err := db.Machine.Create().
if err := db.Machine.Create().SetName(name).
SetID(fprint).SetPublicKey(m.PublicKey).
Exec(cmd.Context()); err != nil {
return fmt.Errorf("failed to write to DB: %w", err)

View file

@ -21,7 +21,9 @@ import (
"bytes"
"crypto/ed25519"
"fmt"
"io"
"os"
"strings"
"text/tabwriter"
pbgrpcv1 "git.rgst.io/homelab/klefki/internal/server/grpc/generated/go/rgst/klefki/v1"
@ -33,6 +35,21 @@ import (
"github.com/spf13/cobra"
)
// nopWriteCloser is a no-op [io.WriteCloser]
type nopWriteCloser struct {
io.Writer
}
// Close implements [io.Closer]
func (nwc nopWriteCloser) Close() error {
return nil
}
// newNopWriteCloser creates a new nopWriteCloser
func newNopWriteCloser(w io.Writer) *nopWriteCloser {
return &nopWriteCloser{w}
}
// newRequestsCommand creates a requests [cobra.Command]
func newRequestsCommand() *cobra.Command {
cmd := &cobra.Command{
@ -40,18 +57,19 @@ func newRequestsCommand() *cobra.Command {
Short: "Make requests to a klefki server",
}
cmd.AddCommand(
newGetKeyRequestCommand(),
newGetKeyCommand(),
newListSessionsCommand(),
newSubmitKeyCommand(),
)
flags := cmd.Flags()
flags.String("hostname", "127.0.0.1:5300", "hostname of the klefki server to connect to")
return cmd
}
// newGetKeyRequestCommand creates a getkeyrequest [cobra.Command]
func newGetKeyRequestCommand() *cobra.Command {
// newGetKeyCommand creates a getkeyrequest [cobra.Command]
func newGetKeyCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "getkeyrequest",
Use: "getkey",
Short: "Get the passphrase for the given machine",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, _ []string) error {
@ -84,11 +102,17 @@ func newGetKeyRequestCommand() *cobra.Command {
if err != nil {
return err
}
defer kcclose() //nolint:errcheck // Why: Best effort
defer kcclose() //nolint:errcheck // Why: Btiest effort
tsResp, err := kc.GetTime(cmd.Context(), &pbgrpcv1.GetTimeRequest{})
if err != nil {
return fmt.Errorf("failed to connect to server to get time: %w", err)
}
req := &pbgrpcv1.GetKeyRequest{}
req.SetMachineId(machineID)
req.SetNonce(uuid.New().String())
req.SetSignedAt(tsResp.GetTime())
req.SetSignature(ed25519.Sign(pk, []byte(req.GetNonce())))
resp, err := kc.GetKey(cmd.Context(), req)
@ -125,7 +149,7 @@ func newListSessionsCommand() *cobra.Command {
Short: "Return a list of all machines waiting for a key to be provided",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, _ []string) error {
kc, kcclose, err := client.Dial(cmd.Flag("hostname").Value.String())
kc, kcclose, err := client.Dial(cmd.Parent().Flag("hostname").Value.String())
if err != nil {
return err
}
@ -143,11 +167,74 @@ func newListSessionsCommand() *cobra.Command {
}
tw := tabwriter.NewWriter(os.Stdout, 2, 2, 2, ' ', 0)
fmt.Fprint(tw, "FINGERPRINT\n")
fmt.Fprint(tw, "FINGERPRINT\tLAST ASKED\n")
for _, m := range machines {
fmt.Fprintf(tw, "%s\n", m.GetId())
fmt.Fprintf(tw, "%s\t%s\n", m.GetId(), m.GetLastAsked())
}
return tw.Flush()
},
}
}
// newSubmitKeyCommand creates a submitekey [cobra.Command]
func newSubmitKeyCommand() *cobra.Command {
return &cobra.Command{
Use: "submitkey <machineID> <passphrase>",
Short: "Submit a passphrase to a given machine by its ID",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
machineID := args[0]
// TODO(jaredallard): don't expect to be passed
passphrase := args[1]
kc, kcclose, err := client.Dial(cmd.Parent().Flag("hostname").Value.String())
if err != nil {
return err
}
defer kcclose() //nolint:errcheck // Why: Best effort
resp, err := kc.ListSessions(cmd.Context(), &pbgrpcv1.ListSessionsRequest{})
if err != nil {
return fmt.Errorf("failed to get key from server: %w", err)
}
machines := resp.GetMachines()
var machine *pbgrpcv1.Machine
for _, m := range machines {
if m.GetId() == machineID {
machine = m
break
}
}
if machine == nil {
return fmt.Errorf("no sessions found for %q", machineID)
}
pubKey, err := sign.PublicKeyFromBytes(machine.GetPublicKey())
if err != nil {
return fmt.Errorf("failed to convert machine's public key to encryption public key: %w", err)
}
enc, err := sign.NewEncryptor(nil, 1024)
if err != nil {
return fmt.Errorf("failed to create decryptor: %w", err)
}
if err := enc.AddRecipient(pubKey); err != nil {
return fmt.Errorf("failed to set private key on decryptor: %w", err)
}
var buf bytes.Buffer
if err := enc.Encrypt(strings.NewReader(passphrase), newNopWriteCloser(&buf)); err != nil {
return fmt.Errorf("failed to decrypt session ID: %w", err)
}
req := &pbgrpcv1.SubmitKeyRequest{}
req.SetEncKey(buf.Bytes())
req.SetMachineId(machineID)
_, err = kc.SubmitKey(cmd.Context(), req)
return err
},
}
}

View file

@ -13,7 +13,7 @@ var (
{Name: "id", Type: field.TypeString},
{Name: "name", Type: field.TypeString, Unique: true},
{Name: "public_key", Type: field.TypeBytes},
{Name: "created_at", Type: field.TypeString, Default: "2025-03-01T23:41:53Z"},
{Name: "created_at", Type: field.TypeString, Default: "2025-03-07T05:15:58Z"},
}
// MachinesTable holds the schema information for the "machines" table.
MachinesTable = &schema.Table{

View file

@ -7,11 +7,12 @@
package v1
import (
reflect "reflect"
unsafe "unsafe"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
_ "google.golang.org/protobuf/types/gofeaturespb"
reflect "reflect"
unsafe "unsafe"
)
const (
@ -444,6 +445,7 @@ type Machine struct {
state protoimpl.MessageState `protogen:"opaque.v1"`
xxx_hidden_Id *string `protobuf:"bytes,1,opt,name=id"`
xxx_hidden_PublicKey []byte `protobuf:"bytes,2,opt,name=public_key,json=publicKey"`
xxx_hidden_LastAsked *string `protobuf:"bytes,3,opt,name=last_asked,json=lastAsked"`
XXX_raceDetectHookData protoimpl.RaceDetectHookData
XXX_presence [1]uint32
unknownFields protoimpl.UnknownFields
@ -492,9 +494,19 @@ func (x *Machine) GetPublicKey() []byte {
return nil
}
func (x *Machine) GetLastAsked() string {
if x != nil {
if x.xxx_hidden_LastAsked != nil {
return *x.xxx_hidden_LastAsked
}
return ""
}
return ""
}
func (x *Machine) SetId(v string) {
x.xxx_hidden_Id = &v
protoimpl.X.SetPresent(&(x.XXX_presence[0]), 0, 2)
protoimpl.X.SetPresent(&(x.XXX_presence[0]), 0, 3)
}
func (x *Machine) SetPublicKey(v []byte) {
@ -502,7 +514,12 @@ func (x *Machine) SetPublicKey(v []byte) {
v = []byte{}
}
x.xxx_hidden_PublicKey = v
protoimpl.X.SetPresent(&(x.XXX_presence[0]), 1, 2)
protoimpl.X.SetPresent(&(x.XXX_presence[0]), 1, 3)
}
func (x *Machine) SetLastAsked(v string) {
x.xxx_hidden_LastAsked = &v
protoimpl.X.SetPresent(&(x.XXX_presence[0]), 2, 3)
}
func (x *Machine) HasId() bool {
@ -519,6 +536,13 @@ func (x *Machine) HasPublicKey() bool {
return protoimpl.X.Present(&(x.XXX_presence[0]), 1)
}
func (x *Machine) HasLastAsked() bool {
if x == nil {
return false
}
return protoimpl.X.Present(&(x.XXX_presence[0]), 2)
}
func (x *Machine) ClearId() {
protoimpl.X.ClearPresent(&(x.XXX_presence[0]), 0)
x.xxx_hidden_Id = nil
@ -529,11 +553,17 @@ func (x *Machine) ClearPublicKey() {
x.xxx_hidden_PublicKey = nil
}
func (x *Machine) ClearLastAsked() {
protoimpl.X.ClearPresent(&(x.XXX_presence[0]), 2)
x.xxx_hidden_LastAsked = nil
}
type Machine_builder struct {
_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
Id *string
PublicKey []byte
LastAsked *string
}
func (b0 Machine_builder) Build() *Machine {
@ -541,13 +571,17 @@ func (b0 Machine_builder) Build() *Machine {
b, x := &b0, m0
_, _ = b, x
if b.Id != nil {
protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 0, 2)
protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 0, 3)
x.xxx_hidden_Id = b.Id
}
if b.PublicKey != nil {
protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 1, 2)
protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 1, 3)
x.xxx_hidden_PublicKey = b.PublicKey
}
if b.LastAsked != nil {
protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 2, 3)
x.xxx_hidden_LastAsked = b.LastAsked
}
return m0
}
@ -787,48 +821,50 @@ var file_rgst_klefki_v1_kelfki_proto_rawDesc = string([]byte{
0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x17, 0x0a, 0x07,
0x65, 0x6e, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x65,
0x6e, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x15, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x73,
0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x38, 0x0a, 0x07,
0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x57, 0x0a, 0x07,
0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69,
0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62,
0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x4b, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65,
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33,
0x0a, 0x08, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
0x32, 0x17, 0x2e, 0x72, 0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e, 0x76,
0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x08, 0x6d, 0x61, 0x63, 0x68, 0x69,
0x6e, 0x65, 0x73, 0x22, 0x4a, 0x0a, 0x10, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4b, 0x65, 0x79,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69,
0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x61, 0x63,
0x68, 0x69, 0x6e, 0x65, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x6e, 0x63, 0x5f, 0x6b, 0x65,
0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x65, 0x6e, 0x63, 0x4b, 0x65, 0x79, 0x22,
0x13, 0x0a, 0x11, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x32, 0xd1, 0x02, 0x0a, 0x0d, 0x4b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x53,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4a, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x54, 0x69, 0x6d,
0x65, 0x12, 0x1e, 0x2e, 0x72, 0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e,
0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x1f, 0x2e, 0x72, 0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e,
0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x12, 0x47, 0x0a, 0x06, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x2e, 0x72,
0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65,
0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x72, 0x67,
0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x61,
0x73, 0x6b, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x61, 0x73, 0x74,
0x41, 0x73, 0x6b, 0x65, 0x64, 0x22, 0x4b, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x73,
0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a,
0x08, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x17, 0x2e, 0x72, 0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e, 0x76, 0x31,
0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x08, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e,
0x65, 0x73, 0x22, 0x4a, 0x0a, 0x10, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e,
0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68,
0x69, 0x6e, 0x65, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x6e, 0x63, 0x5f, 0x6b, 0x65, 0x79,
0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x65, 0x6e, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x13,
0x0a, 0x11, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x32, 0xd1, 0x02, 0x0a, 0x0d, 0x4b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x53, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4a, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65,
0x12, 0x1e, 0x2e, 0x72, 0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e, 0x76,
0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x1f, 0x2e, 0x72, 0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e, 0x76,
0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x12, 0x47, 0x0a, 0x06, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x2e, 0x72, 0x67,
0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74,
0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x59, 0x0a, 0x0c, 0x4c,
0x69, 0x73, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x23, 0x2e, 0x72, 0x67,
0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73,
0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x24, 0x2e, 0x72, 0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e, 0x76,
0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74,
0x4b, 0x65, 0x79, 0x12, 0x20, 0x2e, 0x72, 0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b,
0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x72, 0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65,
0x66, 0x6b, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4b, 0x65, 0x79,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3f, 0x5a, 0x35, 0x67, 0x69, 0x74, 0x2e,
0x72, 0x67, 0x73, 0x74, 0x2e, 0x69, 0x6f, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2f,
0x67, 0x6f, 0x2f, 0x72, 0x67, 0x73, 0x74, 0x2f, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2f, 0x76,
0x31, 0x92, 0x03, 0x05, 0xd2, 0x3e, 0x02, 0x10, 0x03, 0x62, 0x08, 0x65, 0x64, 0x69, 0x74, 0x69,
0x6f, 0x6e, 0x73, 0x70, 0xe8, 0x07,
0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x72, 0x67, 0x73,
0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4b,
0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x59, 0x0a, 0x0c, 0x4c, 0x69,
0x73, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x23, 0x2e, 0x72, 0x67, 0x73,
0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74,
0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x24, 0x2e, 0x72, 0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e, 0x76, 0x31,
0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4b,
0x65, 0x79, 0x12, 0x20, 0x2e, 0x72, 0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69,
0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x72, 0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66,
0x6b, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3f, 0x5a, 0x35, 0x67, 0x69, 0x74, 0x2e, 0x72,
0x67, 0x73, 0x74, 0x2e, 0x69, 0x6f, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f,
0x67, 0x72, 0x70, 0x63, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2f, 0x67,
0x6f, 0x2f, 0x72, 0x67, 0x73, 0x74, 0x2f, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2f, 0x76, 0x31,
0x92, 0x03, 0x05, 0xd2, 0x3e, 0x02, 0x10, 0x03, 0x62, 0x08, 0x65, 0x64, 0x69, 0x74, 0x69, 0x6f,
0x6e, 0x73, 0x70, 0xe8, 0x07,
})
var file_rgst_klefki_v1_kelfki_proto_msgTypes = make([]protoimpl.MessageInfo, 9)

View file

@ -8,6 +8,7 @@ package v1
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"

View file

@ -28,6 +28,7 @@ message ListSessionsRequest {}
message Machine {
string id = 1;
bytes public_key = 2;
string last_asked = 3;
}
message ListSessionsResponse {

View file

@ -84,6 +84,8 @@ func (s *Server) Run(ctx context.Context) error {
return fmt.Errorf("failed to open DB: %w", err)
}
// TODO(jaredallard): Clean up expired sessions after X time period.
s.gs = grpc.NewServer()
pbgrpcv1.RegisterKlefkiServiceServer(s.gs, s)
reflection.Register(s.gs)
@ -100,10 +102,21 @@ func (s *Server) Run(ctx context.Context) error {
// GetTime implements the GetTime RPC
func (s *Server) GetTime(_ context.Context, req *pbgrpcv1.GetTimeRequest) (*pbgrpcv1.GetTimeResponse, error) {
resp := &pbgrpcv1.GetTimeResponse{}
resp.SetTime(time.Now().UTC().Format(time.RFC3339Nano))
resp.SetTime(time.Now().Format(time.RFC3339Nano))
return resp, nil
}
// SubmitKey implements the SubmitKey RPC
func (s *Server) SubmitKey(ctx context.Context, req *pbgrpcv1.SubmitKeyRequest) (*pbgrpcv1.SubmitKeyResponse, error) {
machineID := req.GetMachineId()
if _, ok := s.ses[machineID]; !ok {
return nil, fmt.Errorf("failed to find machine ID %q", machineID)
}
s.ses[machineID].EncKey = req.GetEncKey()
return &pbgrpcv1.SubmitKeyResponse{}, nil
}
// GetKey implements the GetKey RPC
func (s *Server) GetKey(ctx context.Context, req *pbgrpcv1.GetKeyRequest) (*pbgrpcv1.GetKeyResponse, error) {
resp := &pbgrpcv1.GetKeyResponse{}
@ -113,6 +126,7 @@ func (s *Server) GetKey(ctx context.Context, req *pbgrpcv1.GetKeyRequest) (*pbgr
if err != nil || ts.IsZero() {
return nil, fmt.Errorf("failed to parsed signed at %q: %w", req.GetSignedAt(), err)
}
ts = ts.UTC() // Always operate with UTC time.
sig := req.GetSignature()
machine, err := s.db.Machine.Get(ctx, req.GetMachineId())
@ -138,11 +152,21 @@ func (s *Server) GetKey(ctx context.Context, req *pbgrpcv1.GetKeyRequest) (*pbgr
return nil, fmt.Errorf("failed to add instance public key to encryptor: %w", err)
}
// Track the last time the machine asked for a key. This is what backs
// the sessions api
if _, ok := s.ses[machine.ID]; !ok {
s.ses[machine.ID] = &Session{}
}
s.ses[machine.ID].LastAsked = time.Now()
if len(s.ses[machine.ID].EncKey) == 0 {
return nil, fmt.Errorf("key not available")
}
resp.SetEncKey(s.ses[machine.ID].EncKey)
// Reset the session
delete(s.ses, machine.ID)
return resp, nil
}
@ -157,7 +181,10 @@ func (s *Server) ListSessions(ctx context.Context, _ *pbgrpcv1.ListSessionsReque
return nil, fmt.Errorf("failed to get machine %q: %w", machineID, err)
}
grpcMachines = append(grpcMachines, machines.GRPCMachine(machine))
// If the machine asked recently, return it
gMachine := machines.GRPCMachine(machine)
gMachine.SetLastAsked(s.ses[machineID].LastAsked.Format(time.RFC3339Nano))
grpcMachines = append(grpcMachines, gMachine)
}
resp.SetMachines(grpcMachines)