Adjust variable naming
This commit is contained in:
parent
c3334faa9e
commit
78056d8b48
10 changed files with 45 additions and 41 deletions
14
auth/auth.go
14
auth/auth.go
|
@ -25,15 +25,15 @@ func Register(w http.ResponseWriter, r *http.Request) {
|
||||||
if ok {
|
if ok {
|
||||||
email = strings.TrimSpace(email)
|
email = strings.TrimSpace(email)
|
||||||
password = strings.TrimSpace(password)
|
password = strings.TrimSpace(password)
|
||||||
if !(validEmail(email) && validPass(password) && !storage.Data.EmailExists(email)) {
|
if !(validEmail(email) && validPass(password) && !storage.Data.Taken(email)) {
|
||||||
slog.Debug("Outcome",
|
slog.Debug("outcome",
|
||||||
"email", validEmail(email),
|
"email", validEmail(email),
|
||||||
"pass", validPass(password),
|
"pass", validPass(password),
|
||||||
"taken", !storage.Data.EmailExists(email))
|
"taken", !storage.Data.Taken(email))
|
||||||
http.Error(w, "invalid auth credentials", http.StatusBadRequest)
|
http.Error(w, "invalid auth credentials", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err := storage.Data.AddUser(email, password)
|
err := storage.Data.Add(email, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("error adding a new user", "error", err)
|
slog.Error("error adding a new user", "error", err)
|
||||||
http.Error(w, "error adding a new user", http.StatusInternalServerError)
|
http.Error(w, "error adding a new user", http.StatusInternalServerError)
|
||||||
|
@ -57,18 +57,18 @@ func Login(w http.ResponseWriter, r *http.Request) {
|
||||||
email = strings.TrimSpace(email)
|
email = strings.TrimSpace(email)
|
||||||
password = strings.TrimSpace(password)
|
password = strings.TrimSpace(password)
|
||||||
user, ok := storage.Data.ByEmail(email)
|
user, ok := storage.Data.ByEmail(email)
|
||||||
if !ok || !user.PasswordFits(password) {
|
if !ok || !user.Fits(password) {
|
||||||
w.Header().Set("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`)
|
w.Header().Set("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`)
|
||||||
http.Error(w, "you did something wrong", http.StatusUnauthorized)
|
http.Error(w, "you did something wrong", http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := CreateJWT(user)
|
token, err := Create(user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "error creating jwt", http.StatusInternalServerError)
|
http.Error(w, "error creating jwt", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.Write([]byte(s))
|
w.Write([]byte(token))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
22
auth/jwt.go
22
auth/jwt.go
|
@ -18,7 +18,7 @@ import (
|
||||||
|
|
||||||
var key *rsa.PrivateKey
|
var key *rsa.PrivateKey
|
||||||
|
|
||||||
// LoadKey attempts to load a private key from KeyFile.
|
// LoadKey attempts to load a private RS256 key from file.
|
||||||
// If the file does not exist, it generates a new key (and saves it)
|
// If the file does not exist, it generates a new key (and saves it)
|
||||||
func MustLoadKey() {
|
func MustLoadKey() {
|
||||||
// If the key doesn't exist, create it
|
// If the key doesn't exist, create it
|
||||||
|
@ -58,14 +58,15 @@ func MustLoadKey() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PublicKey returns our public key as PEM block over http
|
// ServePublicKey returns our public key as PEM block over HTTP
|
||||||
func PublicKey(w http.ResponseWriter, r *http.Request) {
|
func ServePublicKey(w http.ResponseWriter, r *http.Request) {
|
||||||
key_marshalled := x509.MarshalPKCS1PublicKey(&key.PublicKey)
|
key_marshalled := x509.MarshalPKCS1PublicKey(&key.PublicKey)
|
||||||
block := pem.Block{Bytes: key_marshalled, Type: "RSA PUBLIC KEY"}
|
block := pem.Block{Bytes: key_marshalled, Type: "RSA PUBLIC KEY"}
|
||||||
pem.Encode(w, &block)
|
pem.Encode(w, &block)
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateJWT(user storage.User) (string, error) {
|
// Create creates a JSON Web Token that expires after a week
|
||||||
|
func Create(user storage.User) (token string, err error) {
|
||||||
t := jwt.NewWithClaims(jwt.SigningMethodRS256,
|
t := jwt.NewWithClaims(jwt.SigningMethodRS256,
|
||||||
jwt.MapClaims{
|
jwt.MapClaims{
|
||||||
"iss": "pye",
|
"iss": "pye",
|
||||||
|
@ -74,17 +75,17 @@ func CreateJWT(user storage.User) (string, error) {
|
||||||
"iat": time.Now().Unix(),
|
"iat": time.Now().Unix(),
|
||||||
"exp": time.Now().Add(time.Hour * 24 * 7).Unix(),
|
"exp": time.Now().Add(time.Hour * 24 * 7).Unix(),
|
||||||
})
|
})
|
||||||
s, err := t.SignedString(key)
|
token, err = t.SignedString(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("error creating JWT", "error", err)
|
slog.Error("error creating JWT", "error", err)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return s, nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifyToken receives a JWT and PEM-encoded public key,
|
// Verify receives a JWT and PEM-encoded public key,
|
||||||
// then returns whether the token is valid
|
// then returns whether the token is valid
|
||||||
func VerifyJWT(token string, publicKey []byte) (*jwt.Token, error) {
|
func Verify(token string, publicKey []byte) (*jwt.Token, error) {
|
||||||
t, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
|
t, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
|
||||||
key, err := jwt.ParseRSAPublicKeyFromPEM(publicKey)
|
key, err := jwt.ParseRSAPublicKeyFromPEM(publicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -98,8 +99,9 @@ func VerifyJWT(token string, publicKey []byte) (*jwt.Token, error) {
|
||||||
return t, err
|
return t, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func VerifyLocalJWT(token string) (*jwt.Token, error) {
|
// VerifyLocal calls Verify with public key set to current local one
|
||||||
|
func VerifyLocal(token string) (*jwt.Token, error) {
|
||||||
key_marshalled := x509.MarshalPKCS1PublicKey(&key.PublicKey)
|
key_marshalled := x509.MarshalPKCS1PublicKey(&key.PublicKey)
|
||||||
block := pem.Block{Bytes: key_marshalled, Type: "RSA PUBLIC KEY"}
|
block := pem.Block{Bytes: key_marshalled, Type: "RSA PUBLIC KEY"}
|
||||||
return VerifyJWT(token, pem.EncodeToMemory(&block))
|
return Verify(token, pem.EncodeToMemory(&block))
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,14 +25,14 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func initConfig() {
|
func initConfig() {
|
||||||
logging.LogInit(*debugMode)
|
logging.Load(*debugMode)
|
||||||
config.MustLoadConfig(cfgFile)
|
config.MustLoad(cfgFile)
|
||||||
if cfgDb != "" {
|
if cfgDb != "" {
|
||||||
config.Cfg.SQLiteFile = cfgDb
|
config.Cfg.SQLiteFile = cfgDb
|
||||||
}
|
}
|
||||||
|
|
||||||
auth.MustLoadKey()
|
auth.MustLoadKey()
|
||||||
storage.Data = sqlite.MustLoadSQLite(config.Cfg.SQLiteFile)
|
storage.Data = sqlite.MustLoad(config.Cfg.SQLiteFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
@ -35,7 +35,7 @@ func serveAuth(cmd *cobra.Command, args []string) {
|
||||||
r.Use(middleware.RealIP)
|
r.Use(middleware.RealIP)
|
||||||
r.Use(middleware.Logger, middleware.CleanPath, middleware.StripSlashes)
|
r.Use(middleware.Logger, middleware.CleanPath, middleware.StripSlashes)
|
||||||
|
|
||||||
r.Get("/pem", auth.PublicKey)
|
r.Get("/pem", auth.ServePublicKey)
|
||||||
r.Post("/register", auth.Register)
|
r.Post("/register", auth.Register)
|
||||||
r.Post("/login", auth.Login)
|
r.Post("/login", auth.Login)
|
||||||
|
|
||||||
|
|
|
@ -41,14 +41,14 @@ func verifyFunc(cmd *cobra.Command, args []string) {
|
||||||
var err error
|
var err error
|
||||||
if verifyFile == "" {
|
if verifyFile == "" {
|
||||||
fmt.Println("No PEM file supplied, assuming local")
|
fmt.Println("No PEM file supplied, assuming local")
|
||||||
t, err = auth.VerifyLocalJWT(verifyToken)
|
t, err = auth.VerifyLocal(verifyToken)
|
||||||
} else {
|
} else {
|
||||||
key, err_k := os.ReadFile(verifyFile)
|
key, err_k := os.ReadFile(verifyFile)
|
||||||
if err_k != nil {
|
if err_k != nil {
|
||||||
slog.Error("error reading file", "error", err, "file", verifyFile)
|
slog.Error("error reading file", "error", err, "file", verifyFile)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t, err = auth.VerifyJWT(verifyToken, key)
|
t, err = auth.Verify(verifyToken, key)
|
||||||
}
|
}
|
||||||
slog.Debug("result", "token", t, "error", err, "ok", err == nil)
|
slog.Debug("result", "token", t, "error", err, "ok", err == nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
|
@ -27,7 +27,7 @@ var (
|
||||||
Cfg Config
|
Cfg Config
|
||||||
)
|
)
|
||||||
|
|
||||||
func LoadConfig(filename string) error {
|
func Load(filename string) error {
|
||||||
data, err := os.ReadFile(filename)
|
data, err := os.ReadFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -42,8 +42,8 @@ func LoadConfig(filename string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func MustLoadConfig(filename string) {
|
func MustLoad(filename string) {
|
||||||
err := LoadConfig(filename)
|
err := Load(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)
|
||||||
|
|
|
@ -10,8 +10,8 @@ import (
|
||||||
"github.com/go-chi/chi/middleware"
|
"github.com/go-chi/chi/middleware"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LogInit makes slog output to both os.Stdout and a file if needed, and sets slog.LevelDebug if enabled.
|
// Load makes slog output to both os.Stdout and a file if needed, and sets slog.LevelDebug if enabled.
|
||||||
func LogInit(debugMode bool) {
|
func Load(debugMode bool) {
|
||||||
var w io.Writer
|
var w io.Writer
|
||||||
if config.Cfg.LogToFile {
|
if config.Cfg.LogToFile {
|
||||||
f, err := os.OpenFile(config.Cfg.LogFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
f, err := os.OpenFile(config.Cfg.LogFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||||
|
|
|
@ -23,8 +23,8 @@ type SQLiteStorage struct {
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s SQLiteStorage) AddUser(email, password string) error {
|
func (s SQLiteStorage) Add(email, password string) error {
|
||||||
user, err := storage.NewUser(email, password)
|
user, err := storage.New(email, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -53,12 +53,12 @@ func (s SQLiteStorage) ByEmail(email string) (storage.User, bool) {
|
||||||
return user, err == nil
|
return user, err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s SQLiteStorage) EmailExists(email string) bool {
|
func (s SQLiteStorage) Taken(email string) bool {
|
||||||
_, ok := s.ByEmail(email)
|
_, ok := s.ByEmail(email)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func MustLoadSQLite(dataFile string) SQLiteStorage {
|
func MustLoad(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.Debug("created sqlite3 database file", "file", dataFile)
|
slog.Debug("created sqlite3 database file", "file", dataFile)
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package storage
|
package storage
|
||||||
|
|
||||||
// Storage is an arbitrary storage interface
|
// Storage is an interface for arbitrary storage
|
||||||
type Storage interface {
|
type Storage interface {
|
||||||
AddUser(email, password string) error
|
Add(email, password string) error // Add inserts a user into data
|
||||||
ById(uuid string) (User, bool)
|
ById(uuid string) (User, bool) // ById retrieves a user by their UUID
|
||||||
ByEmail(uuid string) (User, bool)
|
ByEmail(email string) (User, bool) // ByEmail retrieves a user by their email
|
||||||
EmailExists(email string) bool
|
Taken(email string) bool // Taken checks whether an email is taken
|
||||||
}
|
}
|
||||||
|
|
||||||
// Data stores active information for the app
|
// Data stores active information for the app.
|
||||||
// It should be populated at app startup
|
// It should be populated on startup
|
||||||
var Data Storage
|
var Data Storage
|
||||||
|
|
|
@ -13,12 +13,14 @@ type User struct {
|
||||||
Hash []byte // bcrypt hash of password
|
Hash []byte // bcrypt hash of password
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u User) PasswordFits(password string) bool {
|
// Fits checks whether the password is correct
|
||||||
|
func (u User) Fits(password string) bool {
|
||||||
err := bcrypt.CompareHashAndPassword(u.Hash, []byte(password))
|
err := bcrypt.CompareHashAndPassword(u.Hash, []byte(password))
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUser(email, password string) (User, error) {
|
// New Creates a new User
|
||||||
|
func New(email, password string) (User, error) {
|
||||||
hash, err := bcrypt.GenerateFromPassword([]byte(password), 14)
|
hash, err := bcrypt.GenerateFromPassword([]byte(password), 14)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("error creating a new user", "error", err)
|
slog.Error("error creating a new user", "error", err)
|
||||||
|
|
Loading…
Reference in a new issue