diff --git a/.gitignore b/.gitignore index efd9b43..ec723ee 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ pye private.key -dev-data.db data.db \ No newline at end of file diff --git a/Makefile b/Makefile index 926f532..92c01d7 100644 --- a/Makefile +++ b/Makefile @@ -5,4 +5,4 @@ run: go build && ./pye serve dev: - go build && ./pye serve --db dev-data.db --debug \ No newline at end of file + go build && ./pye serve --debug \ No newline at end of file diff --git a/README.md b/README.md index 2dd4fa7..8e8ee9b 100644 --- a/README.md +++ b/README.md @@ -9,19 +9,29 @@ with(out) blazingly fast cloud-native web3 memory-safe blockchain reactive AI This should be done by **October 17th 2024**. Or, at the very least, in a state that proves I am competent Go developer. -## Commands +## Usage -## JWT server +``` +Usage: + pye [command] -Serve a simple JWT auth system -**Usage**: `pye serve [--config] [--port] [--db]` +Available Commands: + completion Generate the autocompletion script for the specified shell + find Find a user + help Help about any command + serve Start JWT service + verify Verify a JWT token -* `POST /register` - register a user with Basic Auth -* `POST /login` - get a JWT token by Basic Auth -* `GET /pem` - get PEM-encoded public RS256 key -* Data and RS256 key persistently stored in an SQLite database and a PEM file +Flags: + -c, --config string config file (default "config.json") + --db string database to use + -d, --debug enable debug mode + -h, --help help for pye -## JWT verification +Use "pye [command] --help" for more information about a command. +``` -Verify a JWT with a public key from a PEM file -**Usage**: `pye verify ` \ No newline at end of file +## Technologies used + +* **Storage** - [SQLite](https://github.com/mattn/go-sqlite3) and a PEM file +* **CLI management** - [Cobra](https://cobra.dev/) \ No newline at end of file diff --git a/auth/jwt.go b/auth/jwt.go index 1917720..c9210af 100644 --- a/auth/jwt.go +++ b/auth/jwt.go @@ -42,7 +42,7 @@ func MustLoadKey() { slog.Error("error closing file", "error", err) os.Exit(1) } - slog.Info("generated new key", "file", config.Cfg.KeyFile) + slog.Debug("generated new key", "file", config.Cfg.KeyFile) } else { km, err := os.ReadFile(config.Cfg.KeyFile) if err != nil { @@ -54,14 +54,10 @@ func MustLoadKey() { slog.Error("error parsing key", "error", err) os.Exit(1) } - slog.Info("loaded private key", "file", config.Cfg.KeyFile) + slog.Debug("loaded private key", "file", config.Cfg.KeyFile) } } -func init() { - MustLoadKey() -} - // PublicKey returns our public key as PEM block over http func PublicKey(w http.ResponseWriter, r *http.Request) { key_marshalled := x509.MarshalPKCS1PublicKey(&key.PublicKey) @@ -106,4 +102,4 @@ func VerifyLocalJWT(token string) (*jwt.Token, error) { key_marshalled := x509.MarshalPKCS1PublicKey(&key.PublicKey) block := pem.Block{Bytes: key_marshalled, Type: "RSA PUBLIC KEY"} return VerifyJWT(token, pem.EncodeToMemory(&block)) -} \ No newline at end of file +} diff --git a/cmd/root.go b/cmd/root.go index 58a75c5..62b3242 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -2,9 +2,9 @@ package cmd import ( "fmt" - "log/slog" "os" + "git.a71.su/Andrew71/pye/auth" "git.a71.su/Andrew71/pye/config" "git.a71.su/Andrew71/pye/logging" "git.a71.su/Andrew71/pye/storage" @@ -26,22 +26,19 @@ var ( func initConfig() { logging.LogInit(*debugMode) - if cfgFile != "" { - err := config.LoadConfig(cfgFile) - if err != nil { - slog.Error("error loading custom config", "error", err) - } - } + config.MustLoadConfig(cfgFile) if cfgDb != "" { config.Cfg.SQLiteFile = cfgDb } + auth.MustLoadKey() storage.Data = sqlite.MustLoadSQLite(config.Cfg.SQLiteFile) + } func init() { cobra.OnInitialize(initConfig) - rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "config.json", "config file") + rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "config.json", "config file") rootCmd.PersistentFlags().StringVar(&cfgDb, "db", "", "database to use") debugMode = rootCmd.PersistentFlags().BoolP("debug", "d", false, "enable debug mode") } diff --git a/cmd/verify.go b/cmd/verify.go index 9b38c16..0071f6e 100644 --- a/cmd/verify.go +++ b/cmd/verify.go @@ -18,19 +18,19 @@ var ( func init() { verifyCmd.Flags().StringVarP(&verifyToken, "token", "t", "", "token to verify") verifyCmd.MarkFlagRequired("token") - verifyCmd.Flags().StringVarP(&verifyFile, "file", "f", "", "file to use") + verifyCmd.Flags().StringVarP(&verifyFile, "file", "f", "", "PEM file to use") rootCmd.AddCommand(verifyCmd) } var verifyCmd = &cobra.Command{ Use: "verify", Short: "Verify a JWT token", - Long: `Pass a JWT token and a path to PEM-encoded file with a public key - to verify whether it is legit.`, + Long: `Pass a JWT token (and optionally a path to a PEM-formatted file with the public key) + to verify whether it is valid.`, Run: verifyFunc, } -// TODO: Better name. +// TODO: Needs a better name? func verifyFunc(cmd *cobra.Command, args []string) { if verifyToken == "" { fmt.Println("Empty token supplied!") @@ -50,5 +50,10 @@ func verifyFunc(cmd *cobra.Command, args []string) { } t, err = auth.VerifyJWT(verifyToken, key) } - slog.Info("result", "token", t, "error", err, "ok", err == nil) + slog.Debug("result", "token", t, "error", err, "ok", err == nil) + if err == nil { + fmt.Println("Token valid!") + } else { + fmt.Println("Token invalid!", err) + } } diff --git a/config/config.go b/config/config.go index a5a8957..6a7dae7 100644 --- a/config/config.go +++ b/config/config.go @@ -38,18 +38,14 @@ func LoadConfig(filename string) error { return err } Cfg = temp_config - slog.Info("Loaded config", "file", filename) + slog.Debug("Loaded config", "file", filename) return nil } -func MustLoadConfig() { - err := LoadConfig(DefaultLocation) +func MustLoadConfig(filename string) { + err := LoadConfig(filename) if err != nil { slog.Error("error initially loading config", "error", err) os.Exit(1) } -} - -func init() { - MustLoadConfig() -} +} \ No newline at end of file diff --git a/storage/sqlite/sqlite.go b/storage/sqlite/sqlite.go index d33d8c1..9844c69 100644 --- a/storage/sqlite/sqlite.go +++ b/storage/sqlite/sqlite.go @@ -61,7 +61,7 @@ func (s SQLiteStorage) EmailExists(email string) bool { func MustLoadSQLite(dataFile string) SQLiteStorage { if _, err := os.Stat(dataFile); errors.Is(err, os.ErrNotExist) { os.Create(dataFile) - slog.Info("created sqlite3 database file", "file", dataFile) + slog.Debug("created sqlite3 database file", "file", dataFile) } db, err := sql.Open("sqlite3", dataFile) if err != nil { @@ -72,13 +72,13 @@ func MustLoadSQLite(dataFile string) SQLiteStorage { statement, err := db.Prepare(create) if err != nil { if err.Error() != "table \"users\" already exists" { - slog.Info("error initialising sqlite3 database table", "error", err) + slog.Error("error initialising sqlite3 database table", "error", err) os.Exit(1) } } else { statement.Exec() } - slog.Info("loaded database", "file", dataFile) + slog.Debug("loaded database", "file", dataFile) return SQLiteStorage{db} }