support encryption
This commit is contained in:
parent
db95258d63
commit
eb74b6ea15
13 changed files with 463 additions and 53 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -49,4 +49,5 @@ CHANGELOG.md
|
|||
## <<Stencil::Block(custom)>>
|
||||
data/
|
||||
!data/.gitkeep
|
||||
*.key
|
||||
## <</Stencil::Block>>
|
||||
|
|
|
@ -27,11 +27,7 @@ import (
|
|||
)
|
||||
|
||||
func main() {
|
||||
exitCode := 0
|
||||
defer func() { os.Exit(exitCode) }()
|
||||
|
||||
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill)
|
||||
defer cancel()
|
||||
|
||||
rootCmd := &cobra.Command{
|
||||
Use: "klefkictl",
|
||||
|
@ -41,9 +37,12 @@ func main() {
|
|||
newNewCommand(),
|
||||
newListCommand(),
|
||||
newDeleteCommand(),
|
||||
newRequestsCommand(),
|
||||
)
|
||||
if err := rootCmd.ExecuteContext(ctx); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
exitCode = 1
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
cancel()
|
||||
}
|
||||
|
|
124
cmd/klefkictl/klefkictl_requests.go
Normal file
124
cmd/klefkictl/klefkictl_requests.go
Normal file
|
@ -0,0 +1,124 @@
|
|||
// Copyright (C) 2025 klefki contributors
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ed25519"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
pbgrpcv1 "git.rgst.io/homelab/klefki/internal/server/grpc/generated/go/rgst/klefki/v1"
|
||||
|
||||
"git.rgst.io/homelab/klefki/internal/machines"
|
||||
"git.rgst.io/homelab/sigtool/v3/sign"
|
||||
"github.com/spf13/cobra"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
)
|
||||
|
||||
// newRequestsCommand creates a requests [cobra.Command]
|
||||
func newRequestsCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "requests",
|
||||
Short: "Make requests to a klefki server",
|
||||
}
|
||||
cmd.AddCommand(newGetKeyRequestCommand())
|
||||
return cmd
|
||||
}
|
||||
|
||||
// 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}
|
||||
}
|
||||
|
||||
// newGetKeyRequestCommand creates a getkeyrequest [cobra.Command]
|
||||
func newGetKeyRequestCommand() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "getkeyrequest",
|
||||
Short: "Get the passphrase for the given machine",
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
privKeyPath := cmd.Flag("priv-key").Value.String()
|
||||
|
||||
privKeyByt, err := os.ReadFile(privKeyPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pk, err := machines.DecodePrivateKey(privKeyByt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
machineID, err := machines.Fingerprint(pk.Public().(ed25519.PublicKey))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get fingerprint for key: %w", err)
|
||||
}
|
||||
|
||||
spk, err := sign.PrivateKeyFromBytes(pk)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create private key for decryption: %w", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Sending GetKeyRequest: machine_id=%s\n", machineID)
|
||||
|
||||
// TODO(jaredallard): Make a client
|
||||
conn, err := grpc.NewClient("127.0.0.1:5300", grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect to klefki server: %w", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
client := pbgrpcv1.NewKlefkiServiceClient(conn)
|
||||
|
||||
req := &pbgrpcv1.GetKeyRequest{}
|
||||
req.SetMachineId(machineID)
|
||||
req.SetNonce("FIXME")
|
||||
req.SetSignature(ed25519.Sign(pk, []byte(req.GetNonce())))
|
||||
|
||||
resp, err := client.GetKey(cmd.Context(), req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get key from server: %w", err)
|
||||
}
|
||||
|
||||
dec, err := sign.NewDecryptor(bytes.NewReader(resp.GetKey()))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create decryptor: %w", err)
|
||||
}
|
||||
if err := dec.SetPrivateKey(spk, nil); err != nil {
|
||||
return fmt.Errorf("failed to set private key on decryptor: %w", err)
|
||||
}
|
||||
return dec.Decrypt(os.Stdout)
|
||||
},
|
||||
}
|
||||
flags := cmd.Flags()
|
||||
flags.String("priv-key", "", "path to private key")
|
||||
return cmd
|
||||
}
|
|
@ -39,11 +39,14 @@ disk.
|
|||
|
||||
### Security
|
||||
|
||||
- Pass-phrases are encrypted using to public key of the authenticated
|
||||
machine to prevent the pass-phrase from ever being send unencrypted or
|
||||
being able to decrypted the key.
|
||||
- Pass-phrases are encrypted to public key of the authenticated machine
|
||||
to prevent the pass-phrase from ever being sent unencrypted or being
|
||||
able to decrypted the key.
|
||||
- Machine IDs are derived from the authenticated machine, through a
|
||||
signature check (public keys are stored on the server side).
|
||||
- This technically is vulnerable to replay attacks. However, the
|
||||
returned data is encrypted to the key holder. An attacker replaying
|
||||
this would get encrypted data only.
|
||||
|
||||
### Flow
|
||||
|
||||
|
|
13
go.mod
13
go.mod
|
@ -1,11 +1,10 @@
|
|||
module git.rgst.io/homelab/klefki
|
||||
|
||||
go 1.23.0
|
||||
|
||||
toolchain go1.24.0
|
||||
go 1.24
|
||||
|
||||
require (
|
||||
entgo.io/ent v0.14.3
|
||||
git.rgst.io/homelab/sigtool/v3 v3.2.3-jaredallard.2
|
||||
github.com/ncruces/go-sqlite3 v0.24.0
|
||||
github.com/spf13/cobra v1.9.1
|
||||
google.golang.org/grpc v1.70.0
|
||||
|
@ -17,6 +16,7 @@ require (
|
|||
github.com/agext/levenshtein v1.2.3 // indirect
|
||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
||||
github.com/bmatcuk/doublestar v1.3.4 // indirect
|
||||
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a // indirect
|
||||
github.com/go-openapi/inflect v0.21.0 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
|
@ -26,11 +26,17 @@ require (
|
|||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||
github.com/ncruces/julianday v1.0.0 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/opencoff/go-fio v0.5.13 // indirect
|
||||
github.com/opencoff/go-mmap v0.1.5 // indirect
|
||||
github.com/pkg/xattr v0.4.10 // indirect
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
||||
github.com/puzpuzpuz/xsync/v3 v3.5.1 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/tetratelabs/wazero v1.9.0 // indirect
|
||||
github.com/zclconf/go-cty v1.16.2 // indirect
|
||||
github.com/zclconf/go-cty-yaml v1.1.0 // indirect
|
||||
golang.org/x/crypto v0.35.0 // indirect
|
||||
golang.org/x/mod v0.23.0 // indirect
|
||||
golang.org/x/net v0.35.0 // indirect
|
||||
golang.org/x/sync v0.11.0 // indirect
|
||||
|
@ -38,6 +44,7 @@ require (
|
|||
golang.org/x/text v0.22.0 // indirect
|
||||
golang.org/x/tools v0.30.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
||||
tool entgo.io/ent/cmd/ent
|
||||
|
|
26
go.sum
generated
26
go.sum
generated
|
@ -2,6 +2,8 @@ ariga.io/atlas v0.31.1-0.20250212144724-069be8033e83 h1:nX4HXncwIdvQ8/8sIUIf1nyC
|
|||
ariga.io/atlas v0.31.1-0.20250212144724-069be8033e83/go.mod h1:Oe1xWPuu5q9LzyrWfbZmEZxFYeu4BHTyzfjeW2aZp/w=
|
||||
entgo.io/ent v0.14.3 h1:wokAV/kIlH9TeklJWGGS7AYJdVckr0DloWjIcO9iIIQ=
|
||||
entgo.io/ent v0.14.3/go.mod h1:aDPE/OziPEu8+OWbzy4UlvWmD2/kbRuWfK2A40hcxJM=
|
||||
git.rgst.io/homelab/sigtool/v3 v3.2.3-jaredallard.2 h1:uZBtO7FkSvLoR9lgw36StTihkLKh8Rcc9QiAZW+z6gA=
|
||||
git.rgst.io/homelab/sigtool/v3 v3.2.3-jaredallard.2/go.mod h1:0krgyBHYyZgmdfc9yzP+QVHlEvw+6bKKrSyt8a7A8oE=
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
|
||||
github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
|
||||
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
|
||||
|
@ -13,6 +15,8 @@ github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9
|
|||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a h1:saTgr5tMLFnmy/yg3qDTft4rE5DY2uJ/cCxCe3q0XTU=
|
||||
github.com/dchest/bcrypt_pbkdf v0.0.0-20150205184540-83f37f9c154a/go.mod h1:Bw9BbhOJVNR+t0jCqx2GC6zv0TGBsShs56Y3gfSCvl0=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
|
@ -44,8 +48,18 @@ github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt
|
|||
github.com/ncruces/julianday v1.0.0/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/opencoff/go-fio v0.5.13 h1:j0vcntRgk475Lw27FOZ35Vw0U7zEY6UFCDfXKynXisY=
|
||||
github.com/opencoff/go-fio v0.5.13/go.mod h1:mehrXmBVDrLdmPrzeuihR1Fv9SnAo+P+riSQybhOg3k=
|
||||
github.com/opencoff/go-mmap v0.1.5 h1:RKPtevC4mOW5bi9skBPPo4nFTIH4lVWAL20Tff+FjLg=
|
||||
github.com/opencoff/go-mmap v0.1.5/go.mod h1:y/6Jk/tDUc00k3oSQpiJX++20Nw7xFSlc5kLkhGnRXw=
|
||||
github.com/pkg/xattr v0.4.10 h1:Qe0mtiNFHQZ296vRgUjRCoPHPqH7VdTOrZx3g0T+pGA=
|
||||
github.com/pkg/xattr v0.4.10/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg=
|
||||
github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
|
@ -53,8 +67,8 @@ github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
|||
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
|
||||
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
|
||||
github.com/zclconf/go-cty v1.16.2 h1:LAJSwc3v81IRBZyUVQDUdZ7hs3SYs9jv0eZJDWHD/70=
|
||||
|
@ -73,14 +87,19 @@ go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiy
|
|||
go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ=
|
||||
go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM=
|
||||
go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
|
||||
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
|
||||
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
|
||||
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
|
||||
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
|
||||
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
|
||||
|
@ -91,6 +110,9 @@ google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ=
|
|||
google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
2
internal/db/ent/migrate/schema.go
generated
2
internal/db/ent/migrate/schema.go
generated
|
@ -12,7 +12,7 @@ var (
|
|||
MachinesColumns = []*schema.Column{
|
||||
{Name: "id", Type: field.TypeString},
|
||||
{Name: "public_key", Type: field.TypeBytes},
|
||||
{Name: "created_at", Type: field.TypeString, Default: "2025-02-23T06:06:02Z"},
|
||||
{Name: "created_at", Type: field.TypeString, Default: "2025-03-01T18:10:35Z"},
|
||||
}
|
||||
// MachinesTable holds the schema information for the "machines" table.
|
||||
MachinesTable = &schema.Table{
|
||||
|
|
4
internal/db/ent/runtime/runtime.go
generated
4
internal/db/ent/runtime/runtime.go
generated
|
@ -5,6 +5,6 @@ package runtime
|
|||
// The schema-stitching logic is generated in git.rgst.io/homelab/klefki/internal/db/ent/runtime.go
|
||||
|
||||
const (
|
||||
Version = "v0.14.2" // Version of ent codegen.
|
||||
Sum = "h1:ywld/j2Rx4EmnIKs8eZ29cbFA1zpB+DA9TLL5l3rlq0=" // Sum of ent codegen.
|
||||
Version = "v0.14.3" // Version of ent codegen.
|
||||
Sum = "h1:wokAV/kIlH9TeklJWGGS7AYJdVckr0DloWjIcO9iIIQ=" // Sum of ent codegen.
|
||||
)
|
||||
|
|
|
@ -29,8 +29,8 @@ import (
|
|||
"git.rgst.io/homelab/klefki/internal/db/ent"
|
||||
)
|
||||
|
||||
// getFingerprint returns a fingerprint of the key.
|
||||
func getFingerprint(pub ed25519.PublicKey) (string, error) {
|
||||
// Fingerprint returns a fingerprint of the provided key.
|
||||
func Fingerprint(pub ed25519.PublicKey) (string, error) {
|
||||
hasher := sha256.New()
|
||||
if _, err := hasher.Write(pub); err != nil {
|
||||
return "", fmt.Errorf("failed to hash provided public key: %w", err)
|
||||
|
@ -73,7 +73,7 @@ func (m *Machine) Fingerprint() (string, error) {
|
|||
if m.fingerprint != "" {
|
||||
return // NOOP if already set.
|
||||
}
|
||||
m.fingerprint, err = getFingerprint(m.PublicKey)
|
||||
m.fingerprint, err = Fingerprint(m.PublicKey)
|
||||
})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to calculate fingerprint: %w", err)
|
||||
|
@ -121,3 +121,36 @@ func NewMachine() (*Machine, error) {
|
|||
|
||||
return &Machine{PublicKey: pub, PrivateKey: priv}, nil
|
||||
}
|
||||
|
||||
// DecodePrivateKey decodes a private key that was encoded by
|
||||
// [Machine.EncodePrivateKey].
|
||||
func DecodePrivateKey(data []byte) (ed25519.PrivateKey, error) {
|
||||
b, _ := pem.Decode(data)
|
||||
if b == nil {
|
||||
return nil, fmt.Errorf("failed to parse private key as PEM encoded data")
|
||||
}
|
||||
if b.Type != "ED25519 PRIVATE KEY" {
|
||||
return nil, fmt.Errorf("expected type \"ED25519 PRIVATE KEY\", got %s", b.Type)
|
||||
}
|
||||
|
||||
k, err := x509.ParsePKCS8PrivateKey(b.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pk, ok := k.(ed25519.PrivateKey)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("expected ed25519.PrivateKey, got %T", k)
|
||||
}
|
||||
return pk, nil
|
||||
}
|
||||
|
||||
// Verify takes the provided pubKey and determines if the provided
|
||||
// signature was made by it, for the nonce. A nil error is success.
|
||||
func Verify(pubKey ed25519.PublicKey, sig []byte, nonce string) error {
|
||||
if ed25519.Verify(pubKey, []byte(nonce), sig) {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("invalid signature")
|
||||
}
|
||||
|
|
50
internal/server/auth.go
Normal file
50
internal/server/auth.go
Normal file
|
@ -0,0 +1,50 @@
|
|||
// Copyright (C) 2025 klefki contributors
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0
|
||||
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ed25519"
|
||||
|
||||
pbgrpcv1 "git.rgst.io/homelab/klefki/internal/server/grpc/generated/go/rgst/klefki/v1"
|
||||
)
|
||||
|
||||
// AuthChallenge is an authentication challenge.
|
||||
type AuthChallenge struct {
|
||||
// MachineID is the ID of the machine that sent this request
|
||||
// (fingerprint).
|
||||
MachineID string `json:"machine_id"`
|
||||
|
||||
// Signature is an ED25519 signature of the provided message.
|
||||
Signature []byte `json:"signature"`
|
||||
|
||||
// Nonce is a randomly generated string that corresponds to the
|
||||
// provided signature.
|
||||
Nonce string `json:"nonce"`
|
||||
}
|
||||
|
||||
// ValidateAuth determines if the auth presented is valid or not.
|
||||
func (s *Server) ValidateAuth(ctx context.Context, req *pbgrpcv1.GetKeyRequest) bool {
|
||||
// Get the public key for this node.
|
||||
m, err := s.db.Machine.Get(ctx, req.GetMachineId())
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return ed25519.Verify(m.PublicKey, []byte(req.GetNonce()), req.GetSignature())
|
||||
}
|
|
@ -23,9 +23,14 @@ const (
|
|||
)
|
||||
|
||||
type GetKeyRequest struct {
|
||||
state protoimpl.MessageState `protogen:"opaque.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
state protoimpl.MessageState `protogen:"opaque.v1"`
|
||||
xxx_hidden_MachineId *string `protobuf:"bytes,1,opt,name=machine_id,json=machineId"`
|
||||
xxx_hidden_Signature []byte `protobuf:"bytes,2,opt,name=signature"`
|
||||
xxx_hidden_Nonce *string `protobuf:"bytes,3,opt,name=nonce"`
|
||||
XXX_raceDetectHookData protoimpl.RaceDetectHookData
|
||||
XXX_presence [1]uint32
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *GetKeyRequest) Reset() {
|
||||
|
@ -53,21 +58,117 @@ func (x *GetKeyRequest) ProtoReflect() protoreflect.Message {
|
|||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
func (x *GetKeyRequest) GetMachineId() string {
|
||||
if x != nil {
|
||||
if x.xxx_hidden_MachineId != nil {
|
||||
return *x.xxx_hidden_MachineId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GetKeyRequest) GetSignature() []byte {
|
||||
if x != nil {
|
||||
return x.xxx_hidden_Signature
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *GetKeyRequest) GetNonce() string {
|
||||
if x != nil {
|
||||
if x.xxx_hidden_Nonce != nil {
|
||||
return *x.xxx_hidden_Nonce
|
||||
}
|
||||
return ""
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GetKeyRequest) SetMachineId(v string) {
|
||||
x.xxx_hidden_MachineId = &v
|
||||
protoimpl.X.SetPresent(&(x.XXX_presence[0]), 0, 3)
|
||||
}
|
||||
|
||||
func (x *GetKeyRequest) SetSignature(v []byte) {
|
||||
if v == nil {
|
||||
v = []byte{}
|
||||
}
|
||||
x.xxx_hidden_Signature = v
|
||||
protoimpl.X.SetPresent(&(x.XXX_presence[0]), 1, 3)
|
||||
}
|
||||
|
||||
func (x *GetKeyRequest) SetNonce(v string) {
|
||||
x.xxx_hidden_Nonce = &v
|
||||
protoimpl.X.SetPresent(&(x.XXX_presence[0]), 2, 3)
|
||||
}
|
||||
|
||||
func (x *GetKeyRequest) HasMachineId() bool {
|
||||
if x == nil {
|
||||
return false
|
||||
}
|
||||
return protoimpl.X.Present(&(x.XXX_presence[0]), 0)
|
||||
}
|
||||
|
||||
func (x *GetKeyRequest) HasSignature() bool {
|
||||
if x == nil {
|
||||
return false
|
||||
}
|
||||
return protoimpl.X.Present(&(x.XXX_presence[0]), 1)
|
||||
}
|
||||
|
||||
func (x *GetKeyRequest) HasNonce() bool {
|
||||
if x == nil {
|
||||
return false
|
||||
}
|
||||
return protoimpl.X.Present(&(x.XXX_presence[0]), 2)
|
||||
}
|
||||
|
||||
func (x *GetKeyRequest) ClearMachineId() {
|
||||
protoimpl.X.ClearPresent(&(x.XXX_presence[0]), 0)
|
||||
x.xxx_hidden_MachineId = nil
|
||||
}
|
||||
|
||||
func (x *GetKeyRequest) ClearSignature() {
|
||||
protoimpl.X.ClearPresent(&(x.XXX_presence[0]), 1)
|
||||
x.xxx_hidden_Signature = nil
|
||||
}
|
||||
|
||||
func (x *GetKeyRequest) ClearNonce() {
|
||||
protoimpl.X.ClearPresent(&(x.XXX_presence[0]), 2)
|
||||
x.xxx_hidden_Nonce = nil
|
||||
}
|
||||
|
||||
type GetKeyRequest_builder struct {
|
||||
_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
|
||||
|
||||
MachineId *string
|
||||
Signature []byte
|
||||
Nonce *string
|
||||
}
|
||||
|
||||
func (b0 GetKeyRequest_builder) Build() *GetKeyRequest {
|
||||
m0 := &GetKeyRequest{}
|
||||
b, x := &b0, m0
|
||||
_, _ = b, x
|
||||
if b.MachineId != nil {
|
||||
protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 0, 3)
|
||||
x.xxx_hidden_MachineId = b.MachineId
|
||||
}
|
||||
if b.Signature != nil {
|
||||
protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 1, 3)
|
||||
x.xxx_hidden_Signature = b.Signature
|
||||
}
|
||||
if b.Nonce != nil {
|
||||
protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 2, 3)
|
||||
x.xxx_hidden_Nonce = b.Nonce
|
||||
}
|
||||
return m0
|
||||
}
|
||||
|
||||
type GetKeyResponse struct {
|
||||
state protoimpl.MessageState `protogen:"opaque.v1"`
|
||||
xxx_hidden_Key *string `protobuf:"bytes,1,opt,name=key"`
|
||||
xxx_hidden_Key []byte `protobuf:"bytes,1,opt,name=key"`
|
||||
XXX_raceDetectHookData protoimpl.RaceDetectHookData
|
||||
XXX_presence [1]uint32
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
@ -99,18 +200,18 @@ func (x *GetKeyResponse) ProtoReflect() protoreflect.Message {
|
|||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
func (x *GetKeyResponse) GetKey() string {
|
||||
func (x *GetKeyResponse) GetKey() []byte {
|
||||
if x != nil {
|
||||
if x.xxx_hidden_Key != nil {
|
||||
return *x.xxx_hidden_Key
|
||||
}
|
||||
return ""
|
||||
return x.xxx_hidden_Key
|
||||
}
|
||||
return ""
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *GetKeyResponse) SetKey(v string) {
|
||||
x.xxx_hidden_Key = &v
|
||||
func (x *GetKeyResponse) SetKey(v []byte) {
|
||||
if v == nil {
|
||||
v = []byte{}
|
||||
}
|
||||
x.xxx_hidden_Key = v
|
||||
protoimpl.X.SetPresent(&(x.XXX_presence[0]), 0, 1)
|
||||
}
|
||||
|
||||
|
@ -129,7 +230,7 @@ func (x *GetKeyResponse) ClearKey() {
|
|||
type GetKeyResponse_builder struct {
|
||||
_ [0]func() // Prevents comparability and use of unkeyed literals for the builder.
|
||||
|
||||
Key *string
|
||||
Key []byte
|
||||
}
|
||||
|
||||
func (b0 GetKeyResponse_builder) Build() *GetKeyResponse {
|
||||
|
@ -151,20 +252,25 @@ var file_rgst_klefki_v1_kelfki_proto_rawDesc = string([]byte{
|
|||
0x67, 0x73, 0x74, 0x2e, 0x6b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x2e, 0x76, 0x31, 0x1a, 0x21, 0x67,
|
||||
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x67,
|
||||
0x6f, 0x5f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x22, 0x0f, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x22, 0x22, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x03, 0x6b, 0x65, 0x79, 0x32, 0x58, 0x0a, 0x0d, 0x4b, 0x6c, 0x65, 0x66, 0x6b, 0x69, 0x53,
|
||||
0x65, 0x72, 0x76, 0x69, 0x63, 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, 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, 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,
|
||||
0x22, 0x62, 0x0a, 0x0d, 0x47, 0x65, 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, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x14,
|
||||
0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6e,
|
||||
0x6f, 0x6e, 0x63, 0x65, 0x22, 0x22, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x32, 0x58, 0x0a, 0x0d, 0x4b, 0x6c, 0x65, 0x66,
|
||||
0x6b, 0x69, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 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, 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, 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, 2)
|
||||
|
|
|
@ -7,10 +7,14 @@ import "google/protobuf/go_features.proto";
|
|||
option features.(pb.go).api_level = API_OPAQUE;
|
||||
option go_package = "git.rgst.io/internal/grpc/generated/go/rgst/klefki/v1";
|
||||
|
||||
message GetKeyRequest {}
|
||||
message GetKeyRequest {
|
||||
string machine_id = 1;
|
||||
bytes signature = 2;
|
||||
string nonce = 3;
|
||||
}
|
||||
|
||||
message GetKeyResponse {
|
||||
string key = 1;
|
||||
bytes key = 1;
|
||||
}
|
||||
|
||||
service KlefkiService {
|
||||
|
|
|
@ -19,23 +19,52 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"git.rgst.io/homelab/klefki/internal/db"
|
||||
"git.rgst.io/homelab/klefki/internal/db/ent"
|
||||
"git.rgst.io/homelab/klefki/internal/machines"
|
||||
pbgrpcv1 "git.rgst.io/homelab/klefki/internal/server/grpc/generated/go/rgst/klefki/v1"
|
||||
"git.rgst.io/homelab/sigtool/v3/sign"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/reflection"
|
||||
)
|
||||
|
||||
// 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}
|
||||
}
|
||||
|
||||
// Server is a Klefki gRPC server
|
||||
type Server struct {
|
||||
gs *grpc.Server
|
||||
db *ent.Client
|
||||
pbgrpcv1.UnimplementedKlefkiServiceServer
|
||||
}
|
||||
|
||||
// Run starts the server
|
||||
func (s *Server) Run(_ context.Context) error {
|
||||
func (s *Server) Run(ctx context.Context) error {
|
||||
var err error
|
||||
s.db, err = db.New(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open DB: %w", err)
|
||||
}
|
||||
|
||||
s.gs = grpc.NewServer()
|
||||
pbgrpcv1.RegisterKlefkiServiceServer(s.gs, s)
|
||||
reflection.Register(s.gs)
|
||||
|
@ -50,9 +79,42 @@ func (s *Server) Run(_ context.Context) error {
|
|||
}
|
||||
|
||||
// GetKey implements the GetKey request
|
||||
func (s *Server) GetKey(_ context.Context, _ *pbgrpcv1.GetKeyRequest) (*pbgrpcv1.GetKeyResponse, error) {
|
||||
func (s *Server) GetKey(ctx context.Context, req *pbgrpcv1.GetKeyRequest) (*pbgrpcv1.GetKeyResponse, error) {
|
||||
resp := &pbgrpcv1.GetKeyResponse{}
|
||||
resp.SetKey("hello-world")
|
||||
|
||||
nonce := req.GetNonce()
|
||||
sig := req.GetSignature()
|
||||
|
||||
machine, err := s.db.Machine.Get(ctx, req.GetMachineId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := machines.Verify(machine.PublicKey, sig, nonce); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
spubk, err := sign.PublicKeyFromBytes(machine.PublicKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create pub key for encryption: %w", err)
|
||||
}
|
||||
|
||||
enc, err := sign.NewEncryptor(nil, 1024)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create encryptor instance: %w", err)
|
||||
}
|
||||
|
||||
if err := enc.AddRecipient(spubk); err != nil {
|
||||
return nil, fmt.Errorf("failed to add instance public key to encryptor: %w", err)
|
||||
}
|
||||
|
||||
// TODO(jaredallard): Wait for input here.
|
||||
var buf bytes.Buffer
|
||||
if err := enc.Encrypt(strings.NewReader("hello world"), newNopWriteCloser(&buf)); err != nil {
|
||||
return nil, fmt.Errorf("failed to encrypt passphrase: %w", err)
|
||||
}
|
||||
|
||||
resp.SetKey(buf.Bytes())
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
|
@ -63,7 +125,6 @@ func (s *Server) Close(_ context.Context) error {
|
|||
}
|
||||
|
||||
fmt.Println("shutting down server")
|
||||
|
||||
s.gs.GracefulStop()
|
||||
return nil
|
||||
return s.db.Close()
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue