From 61aa1be730fa6c5739c0457930f1e03eba5ae455 Mon Sep 17 00:00:00 2001 From: cheddar Date: Thu, 20 Feb 2025 20:45:49 -0500 Subject: [PATCH] Reog and implement sqlite --- go.mod | 1 + go.sum | 2 + keydirectory/in_memory_directory.go | 45 ++++++++++ keydirectory/key_ids.go | 15 ++++ keydirectory/keyentry.go | 28 +++++- keydirectory/sqlite.go | 110 ++++++++++++++++++++++++ main.go | 28 +++++- sqlite_directory/create_directory.go | 11 --- sqlite_directory/in_memory_directory.go | 59 ------------- 9 files changed, 223 insertions(+), 76 deletions(-) create mode 100644 keydirectory/in_memory_directory.go create mode 100644 keydirectory/key_ids.go create mode 100644 keydirectory/sqlite.go delete mode 100644 sqlite_directory/create_directory.go delete mode 100644 sqlite_directory/in_memory_directory.go diff --git a/go.mod b/go.mod index d20d041..d7a74ce 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.23.4 require ( github.com/common-fate/httpsig v0.2.1 github.com/google/uuid v1.6.0 + github.com/mattn/go-sqlite3 v1.14.24 github.com/opencontainers/go-digest v1.0.0 golang.org/x/crypto v0.33.0 ) diff --git a/go.sum b/go.sum index 9aae5ae..360ff9f 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM= +github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= diff --git a/keydirectory/in_memory_directory.go b/keydirectory/in_memory_directory.go new file mode 100644 index 0000000..d2851b8 --- /dev/null +++ b/keydirectory/in_memory_directory.go @@ -0,0 +1,45 @@ +package keydirectory + +import ( + "context" + "crypto" + "errors" + + "github.com/common-fate/httpsig/verifier" +) + +type inMemoryDirectory struct { + records map[string]keyEntry +} + +func CreateMemoryDirectory() inMemoryDirectory { + return inMemoryDirectory{ + records: map[string]keyEntry{}, + } +} + +func (dir inMemoryDirectory) GetKey(ctx context.Context, keyId string, _ string) (verifier.Algorithm, error) { + entry, ok := dir.records[keyId] + + if !ok { + return nil, errors.New("key not found in directory") + } + + return entry.toAlg() +} + +func (dir inMemoryDirectory) RegisterKey(key crypto.PublicKey, alg string, userId string) (string, error) { + keyId, err := generateKeyId() + + if err != nil { + return "", err + } + + dir.records[keyId] = keyEntry{ + Alg: alg, + PublicKey: key, + UserId: userId, + } + + return keyId, nil +} diff --git a/keydirectory/key_ids.go b/keydirectory/key_ids.go new file mode 100644 index 0000000..80d39af --- /dev/null +++ b/keydirectory/key_ids.go @@ -0,0 +1,15 @@ +package keydirectory + +import "github.com/google/uuid" + +func generateKeyId() (string, error) { + uuid, err := uuid.NewRandom() + + if err != nil { + return "", err + } + + keyId := uuid.String() + + return keyId, nil +} diff --git a/keydirectory/keyentry.go b/keydirectory/keyentry.go index c23e573..a3efaa0 100644 --- a/keydirectory/keyentry.go +++ b/keydirectory/keyentry.go @@ -1,9 +1,33 @@ package keydirectory -import "crypto" +import ( + "crypto" + "crypto/ed25519" + "fmt" -type KeyEntry struct { + "github.com/common-fate/httpsig/alg_ed25519" + "github.com/common-fate/httpsig/verifier" +) + +type keyEntry struct { Alg string PublicKey crypto.PublicKey UserId string } + +func (k keyEntry) toAlg() (verifier.Algorithm, error) { + var alg verifier.Algorithm + var err error + + switch k.Alg { + case "ed25519": + alg = alg_ed25519.Ed25519{ + PublicKey: k.PublicKey.(ed25519.PublicKey), + Attrs: k.UserId, + } + default: + err = fmt.Errorf("unknown algoritm: %s", k.Alg) + } + + return alg, err +} diff --git a/keydirectory/sqlite.go b/keydirectory/sqlite.go new file mode 100644 index 0000000..b64044f --- /dev/null +++ b/keydirectory/sqlite.go @@ -0,0 +1,110 @@ +package keydirectory + +import ( + "context" + "crypto" + "crypto/ed25519" + "database/sql" + "fmt" + + "github.com/common-fate/httpsig/verifier" + _ "github.com/mattn/go-sqlite3" +) + +type dbWrapper struct { + db *sql.DB +} + +func InitSqlite(dbPath string) (*dbWrapper, error) { + db, err := sql.Open("sqlite3", dbPath) + + if err != nil { + return &dbWrapper{}, err + } + + createStmt := ` + create table + if not exists + keys(keyId text not null primary key, userId text, alg text, publicKey blob) + ` + + _, err = db.Exec(createStmt) + + if err != nil { + return &dbWrapper{}, err + } + + return &dbWrapper{db}, nil +} + +func (dir *dbWrapper) GetKey(ctx context.Context, keyId string, _ string) (verifier.Algorithm, error) { + db := dir.db + + query := "select userId, alg, publicKey from keys where keyId = ?" + + stmt, err := db.Prepare(query) + + if err != nil { + return nil, err + } + + defer stmt.Close() + + var userId string + var alg string + var keyBytes []byte + + row := stmt.QueryRow(keyId) + + err = row.Scan(&userId, &alg, &keyBytes) + + if err != nil { + return nil, err + } + + var publicKey crypto.PublicKey + + switch alg { + case "ed25519": + publicKey = ed25519.PublicKey(keyBytes) + default: + return nil, fmt.Errorf("unknown algorithm: %s", alg) + } + + keyEntry := keyEntry{ + Alg: alg, + UserId: userId, + PublicKey: publicKey, + } + + return keyEntry.toAlg() +} + +func (dir *dbWrapper) RegisterKey(key crypto.PublicKey, alg string, userId string) (string, error) { + db := dir.db + + keyId, err := generateKeyId() + + if err != nil { + return "", err + } + + stmt := "insert into keys(keyId, userId, alg, publicKey) values (?, ?, ?, ?)" + + var keyBytes []byte + + switch alg { + case "ed25519": + keyBytes = []byte(key.(ed25519.PublicKey)) + default: + return "", fmt.Errorf("unknown algorithm: %s", alg) + } + + _, err = db.Exec(stmt, keyId, userId, alg, keyBytes) + + if err != nil { + return "", err + } + + return keyId, nil +} diff --git a/main.go b/main.go index 1a48c66..dba520a 100644 --- a/main.go +++ b/main.go @@ -12,8 +12,8 @@ import ( "os" "crispbyte.dev/sig-auth/client" + "crispbyte.dev/sig-auth/keydirectory" "crispbyte.dev/sig-auth/server" - "crispbyte.dev/sig-auth/sqlite_directory" "github.com/opencontainers/go-digest" "golang.org/x/crypto/ssh" ) @@ -31,6 +31,10 @@ func main() { simulateCaddy := flag.Bool("caddy", false, "Simulate caddy reverse proxy") + useTempDb := flag.Bool("temp-db", false, "Use a temporary in-memory database") + + dbPath := flag.String("db", "", "Path to the sqlite database file") + flag.Parse() if *useClient { @@ -48,7 +52,12 @@ func main() { registerKey(*keyPath, *user) } else { - runServer(*simulateCaddy) + if !*useTempDb && *dbPath == "" { + flag.PrintDefaults() + return + } + + runServer(*simulateCaddy, *useTempDb, *dbPath) } } @@ -105,8 +114,19 @@ func runClient(keyFile string, keyId string, simulateCaddy bool) { fmt.Println(string(out[:])) } -func runServer(simulateCaddy bool) { - keyDir := sqlite_directory.CreateDirectory() +func runServer(simulateCaddy bool, useTempDb bool, dbPath string) { + var keyDir keydirectory.RegistrationDirectory + + if useTempDb { + keyDir = keydirectory.CreateMemoryDirectory() + } else { + var err error + keyDir, err = keydirectory.InitSqlite(dbPath) + + if err != nil { + log.Fatal(err) + } + } server.Start(simulateCaddy, keyDir) } diff --git a/sqlite_directory/create_directory.go b/sqlite_directory/create_directory.go deleted file mode 100644 index 06414d8..0000000 --- a/sqlite_directory/create_directory.go +++ /dev/null @@ -1,11 +0,0 @@ -package sqlite_directory - -import ( - "crispbyte.dev/sig-auth/keydirectory" -) - -func CreateDirectory() InMemoryDirectory { - return InMemoryDirectory{ - records: map[string]keydirectory.KeyEntry{}, - } -} diff --git a/sqlite_directory/in_memory_directory.go b/sqlite_directory/in_memory_directory.go deleted file mode 100644 index 0b8f625..0000000 --- a/sqlite_directory/in_memory_directory.go +++ /dev/null @@ -1,59 +0,0 @@ -package sqlite_directory - -import ( - "context" - "crypto" - "crypto/ed25519" - "errors" - "fmt" - - "github.com/common-fate/httpsig/alg_ed25519" - "github.com/common-fate/httpsig/verifier" - "github.com/google/uuid" - - "crispbyte.dev/sig-auth/keydirectory" -) - -type InMemoryDirectory struct { - records map[string]keydirectory.KeyEntry -} - -func (dir InMemoryDirectory) GetKey(ctx context.Context, keyId string, _ string) (verifier.Algorithm, error) { - entry, ok := dir.records[keyId] - - if !ok { - return nil, errors.New("key not found in directory") - } - - var alg verifier.Algorithm - var err error - - switch entry.Alg { - case "ed25519": - alg = alg_ed25519.Ed25519{ - PublicKey: entry.PublicKey.(ed25519.PublicKey), - Attrs: entry.UserId, - } - default: - err = fmt.Errorf("unknown algoritm: %s", entry.Alg) - } - - return alg, err -} - -func (dir InMemoryDirectory) RegisterKey(key crypto.PublicKey, alg string, userId string) (string, error) { - uuid, err := uuid.NewRandom() - keyId := uuid.String() - - if err != nil { - return "", err - } - - dir.records[keyId] = keydirectory.KeyEntry{ - Alg: alg, - PublicKey: key, - UserId: userId, - } - - return keyId, nil -}