implement full request flow
This commit is contained in:
parent
cb20155b1e
commit
affa5919f7
7 changed files with 214 additions and 60 deletions
|
@ -29,10 +29,12 @@ import (
|
||||||
func newNewCommand() *cobra.Command {
|
func newNewCommand() *cobra.Command {
|
||||||
// TODO(jaredallard): Support setting the name of the machine.
|
// TODO(jaredallard): Support setting the name of the machine.
|
||||||
return &cobra.Command{
|
return &cobra.Command{
|
||||||
Use: "new",
|
Use: "new <machineName>",
|
||||||
Short: "Create a new machine",
|
Short: "Create a new machine",
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.ExactArgs(1),
|
||||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
name := args[0] // Checked by [cobra.ExactArgs] above.
|
||||||
|
|
||||||
db, err := db.New(cmd.Context())
|
db, err := db.New(cmd.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to open DB: %w", err)
|
return fmt.Errorf("failed to open DB: %w", err)
|
||||||
|
@ -54,7 +56,7 @@ func newNewCommand() *cobra.Command {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := db.Machine.Create().
|
if err := db.Machine.Create().SetName(name).
|
||||||
SetID(fprint).SetPublicKey(m.PublicKey).
|
SetID(fprint).SetPublicKey(m.PublicKey).
|
||||||
Exec(cmd.Context()); err != nil {
|
Exec(cmd.Context()); err != nil {
|
||||||
return fmt.Errorf("failed to write to DB: %w", err)
|
return fmt.Errorf("failed to write to DB: %w", err)
|
||||||
|
|
|
@ -21,7 +21,9 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
|
||||||
pbgrpcv1 "git.rgst.io/homelab/klefki/internal/server/grpc/generated/go/rgst/klefki/v1"
|
pbgrpcv1 "git.rgst.io/homelab/klefki/internal/server/grpc/generated/go/rgst/klefki/v1"
|
||||||
|
@ -33,6 +35,21 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"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]
|
// newRequestsCommand creates a requests [cobra.Command]
|
||||||
func newRequestsCommand() *cobra.Command {
|
func newRequestsCommand() *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
|
@ -40,18 +57,19 @@ func newRequestsCommand() *cobra.Command {
|
||||||
Short: "Make requests to a klefki server",
|
Short: "Make requests to a klefki server",
|
||||||
}
|
}
|
||||||
cmd.AddCommand(
|
cmd.AddCommand(
|
||||||
newGetKeyRequestCommand(),
|
newGetKeyCommand(),
|
||||||
newListSessionsCommand(),
|
newListSessionsCommand(),
|
||||||
|
newSubmitKeyCommand(),
|
||||||
)
|
)
|
||||||
flags := cmd.Flags()
|
flags := cmd.Flags()
|
||||||
flags.String("hostname", "127.0.0.1:5300", "hostname of the klefki server to connect to")
|
flags.String("hostname", "127.0.0.1:5300", "hostname of the klefki server to connect to")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// newGetKeyRequestCommand creates a getkeyrequest [cobra.Command]
|
// newGetKeyCommand creates a getkeyrequest [cobra.Command]
|
||||||
func newGetKeyRequestCommand() *cobra.Command {
|
func newGetKeyCommand() *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "getkeyrequest",
|
Use: "getkey",
|
||||||
Short: "Get the passphrase for the given machine",
|
Short: "Get the passphrase for the given machine",
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||||
|
@ -84,11 +102,17 @@ func newGetKeyRequestCommand() *cobra.Command {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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 := &pbgrpcv1.GetKeyRequest{}
|
||||||
req.SetMachineId(machineID)
|
req.SetMachineId(machineID)
|
||||||
req.SetNonce(uuid.New().String())
|
req.SetNonce(uuid.New().String())
|
||||||
|
req.SetSignedAt(tsResp.GetTime())
|
||||||
req.SetSignature(ed25519.Sign(pk, []byte(req.GetNonce())))
|
req.SetSignature(ed25519.Sign(pk, []byte(req.GetNonce())))
|
||||||
|
|
||||||
resp, err := kc.GetKey(cmd.Context(), req)
|
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",
|
Short: "Return a list of all machines waiting for a key to be provided",
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -143,11 +167,74 @@ func newListSessionsCommand() *cobra.Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
tw := tabwriter.NewWriter(os.Stdout, 2, 2, 2, ' ', 0)
|
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 {
|
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()
|
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
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
2
internal/db/ent/migrate/schema.go
generated
2
internal/db/ent/migrate/schema.go
generated
|
@ -13,7 +13,7 @@ var (
|
||||||
{Name: "id", Type: field.TypeString},
|
{Name: "id", Type: field.TypeString},
|
||||||
{Name: "name", Type: field.TypeString, Unique: true},
|
{Name: "name", Type: field.TypeString, Unique: true},
|
||||||
{Name: "public_key", Type: field.TypeBytes},
|
{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 holds the schema information for the "machines" table.
|
||||||
MachinesTable = &schema.Table{
|
MachinesTable = &schema.Table{
|
||||||
|
|
|
@ -7,11 +7,12 @@
|
||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
reflect "reflect"
|
||||||
|
unsafe "unsafe"
|
||||||
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
_ "google.golang.org/protobuf/types/gofeaturespb"
|
_ "google.golang.org/protobuf/types/gofeaturespb"
|
||||||
reflect "reflect"
|
|
||||||
unsafe "unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -444,6 +445,7 @@ type Machine struct {
|
||||||
state protoimpl.MessageState `protogen:"opaque.v1"`
|
state protoimpl.MessageState `protogen:"opaque.v1"`
|
||||||
xxx_hidden_Id *string `protobuf:"bytes,1,opt,name=id"`
|
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_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_raceDetectHookData protoimpl.RaceDetectHookData
|
||||||
XXX_presence [1]uint32
|
XXX_presence [1]uint32
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
@ -492,9 +494,19 @@ func (x *Machine) GetPublicKey() []byte {
|
||||||
return nil
|
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) {
|
func (x *Machine) SetId(v string) {
|
||||||
x.xxx_hidden_Id = &v
|
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) {
|
func (x *Machine) SetPublicKey(v []byte) {
|
||||||
|
@ -502,7 +514,12 @@ func (x *Machine) SetPublicKey(v []byte) {
|
||||||
v = []byte{}
|
v = []byte{}
|
||||||
}
|
}
|
||||||
x.xxx_hidden_PublicKey = v
|
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 {
|
func (x *Machine) HasId() bool {
|
||||||
|
@ -519,6 +536,13 @@ func (x *Machine) HasPublicKey() bool {
|
||||||
return protoimpl.X.Present(&(x.XXX_presence[0]), 1)
|
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() {
|
func (x *Machine) ClearId() {
|
||||||
protoimpl.X.ClearPresent(&(x.XXX_presence[0]), 0)
|
protoimpl.X.ClearPresent(&(x.XXX_presence[0]), 0)
|
||||||
x.xxx_hidden_Id = nil
|
x.xxx_hidden_Id = nil
|
||||||
|
@ -529,11 +553,17 @@ func (x *Machine) ClearPublicKey() {
|
||||||
x.xxx_hidden_PublicKey = nil
|
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 {
|
type Machine_builder struct {
|
||||||
_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
|
_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
|
||||||
|
|
||||||
Id *string
|
Id *string
|
||||||
PublicKey []byte
|
PublicKey []byte
|
||||||
|
LastAsked *string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b0 Machine_builder) Build() *Machine {
|
func (b0 Machine_builder) Build() *Machine {
|
||||||
|
@ -541,13 +571,17 @@ func (b0 Machine_builder) Build() *Machine {
|
||||||
b, x := &b0, m0
|
b, x := &b0, m0
|
||||||
_, _ = b, x
|
_, _ = b, x
|
||||||
if b.Id != nil {
|
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
|
x.xxx_hidden_Id = b.Id
|
||||||
}
|
}
|
||||||
if b.PublicKey != nil {
|
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
|
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
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
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,
|
0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x61,
|
||||||
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33,
|
0x73, 0x6b, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6c, 0x61, 0x73, 0x74,
|
||||||
0x0a, 0x08, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
|
0x41, 0x73, 0x6b, 0x65, 0x64, 0x22, 0x4b, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x73,
|
||||||
0x32, 0x17, 0x2e, 0x72, 0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e, 0x76,
|
0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a,
|
||||||
0x31, 0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x08, 0x6d, 0x61, 0x63, 0x68, 0x69,
|
0x08, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||||
0x6e, 0x65, 0x73, 0x22, 0x4a, 0x0a, 0x10, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4b, 0x65, 0x79,
|
0x17, 0x2e, 0x72, 0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e, 0x76, 0x31,
|
||||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69,
|
0x2e, 0x4d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x52, 0x08, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e,
|
||||||
0x6e, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x61, 0x63,
|
0x65, 0x73, 0x22, 0x4a, 0x0a, 0x10, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x52,
|
||||||
0x68, 0x69, 0x6e, 0x65, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x6e, 0x63, 0x5f, 0x6b, 0x65,
|
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e,
|
||||||
0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x65, 0x6e, 0x63, 0x4b, 0x65, 0x79, 0x22,
|
0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x61, 0x63, 0x68,
|
||||||
0x13, 0x0a, 0x11, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70,
|
0x69, 0x6e, 0x65, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x65, 0x6e, 0x63, 0x5f, 0x6b, 0x65, 0x79,
|
||||||
0x6f, 0x6e, 0x73, 0x65, 0x32, 0xd1, 0x02, 0x0a, 0x0d, 0x4b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x53,
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x65, 0x6e, 0x63, 0x4b, 0x65, 0x79, 0x22, 0x13,
|
||||||
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4a, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x54, 0x69, 0x6d,
|
0x0a, 0x11, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||||
0x65, 0x12, 0x1e, 0x2e, 0x72, 0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e,
|
0x6e, 0x73, 0x65, 0x32, 0xd1, 0x02, 0x0a, 0x0d, 0x4b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x53, 0x65,
|
||||||
0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4a, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65,
|
||||||
0x74, 0x1a, 0x1f, 0x2e, 0x72, 0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e,
|
0x12, 0x1e, 0x2e, 0x72, 0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e, 0x76,
|
||||||
0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||||
0x73, 0x65, 0x12, 0x47, 0x0a, 0x06, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x2e, 0x72,
|
0x1a, 0x1f, 0x2e, 0x72, 0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e, 0x76,
|
||||||
0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65,
|
0x31, 0x2e, 0x47, 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||||
0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x72, 0x67,
|
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,
|
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,
|
0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x72, 0x67, 0x73,
|
||||||
0x69, 0x73, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x23, 0x2e, 0x72, 0x67,
|
0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4b,
|
||||||
0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73,
|
0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x59, 0x0a, 0x0c, 0x4c, 0x69,
|
||||||
0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
0x73, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x23, 0x2e, 0x72, 0x67, 0x73,
|
||||||
0x1a, 0x24, 0x2e, 0x72, 0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e, 0x76,
|
0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74,
|
||||||
0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65,
|
0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74,
|
0x24, 0x2e, 0x72, 0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e, 0x76, 0x31,
|
||||||
0x4b, 0x65, 0x79, 0x12, 0x20, 0x2e, 0x72, 0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b,
|
0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73,
|
||||||
0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65,
|
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4b,
|
||||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x72, 0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65,
|
0x65, 0x79, 0x12, 0x20, 0x2e, 0x72, 0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69,
|
||||||
0x66, 0x6b, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4b, 0x65, 0x79,
|
0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71,
|
||||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3f, 0x5a, 0x35, 0x67, 0x69, 0x74, 0x2e,
|
0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x72, 0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66,
|
||||||
0x72, 0x67, 0x73, 0x74, 0x2e, 0x69, 0x6f, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
|
0x6b, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x4b, 0x65, 0x79, 0x52,
|
||||||
0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2f,
|
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x3f, 0x5a, 0x35, 0x67, 0x69, 0x74, 0x2e, 0x72,
|
||||||
0x67, 0x6f, 0x2f, 0x72, 0x67, 0x73, 0x74, 0x2f, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2f, 0x76,
|
0x67, 0x73, 0x74, 0x2e, 0x69, 0x6f, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f,
|
||||||
0x31, 0x92, 0x03, 0x05, 0xd2, 0x3e, 0x02, 0x10, 0x03, 0x62, 0x08, 0x65, 0x64, 0x69, 0x74, 0x69,
|
0x67, 0x72, 0x70, 0x63, 0x2f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x2f, 0x67,
|
||||||
0x6f, 0x6e, 0x73, 0x70, 0xe8, 0x07,
|
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)
|
var file_rgst_klefki_v1_kelfki_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
|
||||||
|
|
|
@ -8,6 +8,7 @@ package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
context "context"
|
context "context"
|
||||||
|
|
||||||
grpc "google.golang.org/grpc"
|
grpc "google.golang.org/grpc"
|
||||||
codes "google.golang.org/grpc/codes"
|
codes "google.golang.org/grpc/codes"
|
||||||
status "google.golang.org/grpc/status"
|
status "google.golang.org/grpc/status"
|
||||||
|
|
|
@ -28,6 +28,7 @@ message ListSessionsRequest {}
|
||||||
message Machine {
|
message Machine {
|
||||||
string id = 1;
|
string id = 1;
|
||||||
bytes public_key = 2;
|
bytes public_key = 2;
|
||||||
|
string last_asked = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ListSessionsResponse {
|
message ListSessionsResponse {
|
||||||
|
|
|
@ -84,6 +84,8 @@ func (s *Server) Run(ctx context.Context) error {
|
||||||
return fmt.Errorf("failed to open DB: %w", err)
|
return fmt.Errorf("failed to open DB: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(jaredallard): Clean up expired sessions after X time period.
|
||||||
|
|
||||||
s.gs = grpc.NewServer()
|
s.gs = grpc.NewServer()
|
||||||
pbgrpcv1.RegisterKlefkiServiceServer(s.gs, s)
|
pbgrpcv1.RegisterKlefkiServiceServer(s.gs, s)
|
||||||
reflection.Register(s.gs)
|
reflection.Register(s.gs)
|
||||||
|
@ -100,10 +102,21 @@ func (s *Server) Run(ctx context.Context) error {
|
||||||
// GetTime implements the GetTime RPC
|
// GetTime implements the GetTime RPC
|
||||||
func (s *Server) GetTime(_ context.Context, req *pbgrpcv1.GetTimeRequest) (*pbgrpcv1.GetTimeResponse, error) {
|
func (s *Server) GetTime(_ context.Context, req *pbgrpcv1.GetTimeRequest) (*pbgrpcv1.GetTimeResponse, error) {
|
||||||
resp := &pbgrpcv1.GetTimeResponse{}
|
resp := &pbgrpcv1.GetTimeResponse{}
|
||||||
resp.SetTime(time.Now().UTC().Format(time.RFC3339Nano))
|
resp.SetTime(time.Now().Format(time.RFC3339Nano))
|
||||||
return resp, nil
|
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
|
// GetKey implements the GetKey RPC
|
||||||
func (s *Server) GetKey(ctx context.Context, req *pbgrpcv1.GetKeyRequest) (*pbgrpcv1.GetKeyResponse, error) {
|
func (s *Server) GetKey(ctx context.Context, req *pbgrpcv1.GetKeyRequest) (*pbgrpcv1.GetKeyResponse, error) {
|
||||||
resp := &pbgrpcv1.GetKeyResponse{}
|
resp := &pbgrpcv1.GetKeyResponse{}
|
||||||
|
@ -113,6 +126,7 @@ func (s *Server) GetKey(ctx context.Context, req *pbgrpcv1.GetKeyRequest) (*pbgr
|
||||||
if err != nil || ts.IsZero() {
|
if err != nil || ts.IsZero() {
|
||||||
return nil, fmt.Errorf("failed to parsed signed at %q: %w", req.GetSignedAt(), err)
|
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()
|
sig := req.GetSignature()
|
||||||
|
|
||||||
machine, err := s.db.Machine.Get(ctx, req.GetMachineId())
|
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)
|
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 {
|
if len(s.ses[machine.ID].EncKey) == 0 {
|
||||||
return nil, fmt.Errorf("key not available")
|
return nil, fmt.Errorf("key not available")
|
||||||
}
|
}
|
||||||
|
|
||||||
resp.SetEncKey(s.ses[machine.ID].EncKey)
|
resp.SetEncKey(s.ses[machine.ID].EncKey)
|
||||||
|
|
||||||
|
// Reset the session
|
||||||
|
delete(s.ses, machine.ID)
|
||||||
|
|
||||||
return resp, nil
|
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)
|
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)
|
resp.SetMachines(grpcMachines)
|
||||||
|
|
Loading…
Add table
Reference in a new issue