Improve initial loading
This commit is contained in:
parent
1f50b8621e
commit
acab4bc68b
8 changed files with 47 additions and 44 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,4 +1,3 @@
|
||||||
pye
|
pye
|
||||||
private.key
|
private.key
|
||||||
dev-data.db
|
|
||||||
data.db
|
data.db
|
2
Makefile
2
Makefile
|
@ -5,4 +5,4 @@ run:
|
||||||
go build && ./pye serve
|
go build && ./pye serve
|
||||||
|
|
||||||
dev:
|
dev:
|
||||||
go build && ./pye serve --db dev-data.db --debug
|
go build && ./pye serve --debug
|
32
README.md
32
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,
|
This should be done by **October 17th 2024**. Or, at the very least,
|
||||||
in a state that proves I am competent Go developer.
|
in a state that proves I am competent Go developer.
|
||||||
|
|
||||||
## Commands
|
## Usage
|
||||||
|
|
||||||
## JWT server
|
```
|
||||||
|
Usage:
|
||||||
|
pye [command]
|
||||||
|
|
||||||
Serve a simple JWT auth system
|
Available Commands:
|
||||||
**Usage**: `pye serve [--config] [--port] [--db]`
|
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
|
Flags:
|
||||||
* `POST /login` - get a JWT token by Basic Auth
|
-c, --config string config file (default "config.json")
|
||||||
* `GET /pem` - get PEM-encoded public RS256 key
|
--db string database to use
|
||||||
* Data and RS256 key persistently stored in an SQLite database and a PEM file
|
-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
|
## Technologies used
|
||||||
**Usage**: `pye verify <jwt> <pem_file>`
|
|
||||||
|
* **Storage** - [SQLite](https://github.com/mattn/go-sqlite3) and a PEM file
|
||||||
|
* **CLI management** - [Cobra](https://cobra.dev/)
|
|
@ -42,7 +42,7 @@ func MustLoadKey() {
|
||||||
slog.Error("error closing file", "error", err)
|
slog.Error("error closing file", "error", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
slog.Info("generated new key", "file", config.Cfg.KeyFile)
|
slog.Debug("generated new key", "file", config.Cfg.KeyFile)
|
||||||
} else {
|
} else {
|
||||||
km, err := os.ReadFile(config.Cfg.KeyFile)
|
km, err := os.ReadFile(config.Cfg.KeyFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -54,14 +54,10 @@ func MustLoadKey() {
|
||||||
slog.Error("error parsing key", "error", err)
|
slog.Error("error parsing key", "error", err)
|
||||||
os.Exit(1)
|
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
|
// PublicKey returns our public key as PEM block over http
|
||||||
func PublicKey(w http.ResponseWriter, r *http.Request) {
|
func PublicKey(w http.ResponseWriter, r *http.Request) {
|
||||||
key_marshalled := x509.MarshalPKCS1PublicKey(&key.PublicKey)
|
key_marshalled := x509.MarshalPKCS1PublicKey(&key.PublicKey)
|
||||||
|
|
13
cmd/root.go
13
cmd/root.go
|
@ -2,9 +2,9 @@ package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"git.a71.su/Andrew71/pye/auth"
|
||||||
"git.a71.su/Andrew71/pye/config"
|
"git.a71.su/Andrew71/pye/config"
|
||||||
"git.a71.su/Andrew71/pye/logging"
|
"git.a71.su/Andrew71/pye/logging"
|
||||||
"git.a71.su/Andrew71/pye/storage"
|
"git.a71.su/Andrew71/pye/storage"
|
||||||
|
@ -26,22 +26,19 @@ var (
|
||||||
|
|
||||||
func initConfig() {
|
func initConfig() {
|
||||||
logging.LogInit(*debugMode)
|
logging.LogInit(*debugMode)
|
||||||
if cfgFile != "" {
|
config.MustLoadConfig(cfgFile)
|
||||||
err := config.LoadConfig(cfgFile)
|
|
||||||
if err != nil {
|
|
||||||
slog.Error("error loading custom config", "error", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if cfgDb != "" {
|
if cfgDb != "" {
|
||||||
config.Cfg.SQLiteFile = cfgDb
|
config.Cfg.SQLiteFile = cfgDb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auth.MustLoadKey()
|
||||||
storage.Data = sqlite.MustLoadSQLite(config.Cfg.SQLiteFile)
|
storage.Data = sqlite.MustLoadSQLite(config.Cfg.SQLiteFile)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
cobra.OnInitialize(initConfig)
|
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")
|
rootCmd.PersistentFlags().StringVar(&cfgDb, "db", "", "database to use")
|
||||||
debugMode = rootCmd.PersistentFlags().BoolP("debug", "d", false, "enable debug mode")
|
debugMode = rootCmd.PersistentFlags().BoolP("debug", "d", false, "enable debug mode")
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,19 +18,19 @@ var (
|
||||||
func init() {
|
func init() {
|
||||||
verifyCmd.Flags().StringVarP(&verifyToken, "token", "t", "", "token to verify")
|
verifyCmd.Flags().StringVarP(&verifyToken, "token", "t", "", "token to verify")
|
||||||
verifyCmd.MarkFlagRequired("token")
|
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)
|
rootCmd.AddCommand(verifyCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
var verifyCmd = &cobra.Command{
|
var verifyCmd = &cobra.Command{
|
||||||
Use: "verify",
|
Use: "verify",
|
||||||
Short: "Verify a JWT token",
|
Short: "Verify a JWT token",
|
||||||
Long: `Pass a JWT token and a path to PEM-encoded file with a public key
|
Long: `Pass a JWT token (and optionally a path to a PEM-formatted file with the public key)
|
||||||
to verify whether it is legit.`,
|
to verify whether it is valid.`,
|
||||||
Run: verifyFunc,
|
Run: verifyFunc,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Better name.
|
// TODO: Needs a better name?
|
||||||
func verifyFunc(cmd *cobra.Command, args []string) {
|
func verifyFunc(cmd *cobra.Command, args []string) {
|
||||||
if verifyToken == "" {
|
if verifyToken == "" {
|
||||||
fmt.Println("Empty token supplied!")
|
fmt.Println("Empty token supplied!")
|
||||||
|
@ -50,5 +50,10 @@ func verifyFunc(cmd *cobra.Command, args []string) {
|
||||||
}
|
}
|
||||||
t, err = auth.VerifyJWT(verifyToken, key)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,18 +38,14 @@ func LoadConfig(filename string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
Cfg = temp_config
|
Cfg = temp_config
|
||||||
slog.Info("Loaded config", "file", filename)
|
slog.Debug("Loaded config", "file", filename)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func MustLoadConfig() {
|
func MustLoadConfig(filename string) {
|
||||||
err := LoadConfig(DefaultLocation)
|
err := LoadConfig(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("error initially loading config", "error", err)
|
slog.Error("error initially loading config", "error", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
|
||||||
MustLoadConfig()
|
|
||||||
}
|
|
||||||
|
|
|
@ -61,7 +61,7 @@ func (s SQLiteStorage) EmailExists(email string) bool {
|
||||||
func MustLoadSQLite(dataFile string) SQLiteStorage {
|
func MustLoadSQLite(dataFile string) SQLiteStorage {
|
||||||
if _, err := os.Stat(dataFile); errors.Is(err, os.ErrNotExist) {
|
if _, err := os.Stat(dataFile); errors.Is(err, os.ErrNotExist) {
|
||||||
os.Create(dataFile)
|
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)
|
db, err := sql.Open("sqlite3", dataFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -72,13 +72,13 @@ func MustLoadSQLite(dataFile string) SQLiteStorage {
|
||||||
statement, err := db.Prepare(create)
|
statement, err := db.Prepare(create)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err.Error() != "table \"users\" already exists" {
|
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)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
statement.Exec()
|
statement.Exec()
|
||||||
}
|
}
|
||||||
|
|
||||||
slog.Info("loaded database", "file", dataFile)
|
slog.Debug("loaded database", "file", dataFile)
|
||||||
return SQLiteStorage{db}
|
return SQLiteStorage{db}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue