Refactor everything again

This commit is contained in:
Andrew-71 2024-10-13 21:03:44 +03:00
parent 7fdb0bf0f4
commit 96c369e4b1
14 changed files with 72 additions and 53 deletions

View file

@ -1,14 +1,11 @@
# Auth microservice
# Pye Auth
**Mission**: Science compels us to create a microservice!
This is the repository for my **JWT auth microservice assignment**
This is the repository for my **JWT authentication microservice**
with(out) blazingly fast cloud-native web3 memory-safe blockchain reactive AI
(insert a dozen more buzzwords of your choosing) technologies.
This should be done by **October 17th 2024**. Or, at the very least,
in a state that proves I am competent Go developer.
## Usage
```
@ -33,6 +30,7 @@ Use "pye [command] --help" for more information about a command.
## Technologies used
* **Storage** - [SQLite](https://github.com/mattn/go-sqlite3) and a PEM file
* **Storage** - [SQLite](https://github.com/mattn/go-sqlite3) and a
[PEM](https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail) file
* **HTTP routing** - [Chi](https://go-chi.io), just for logging...
* **CLI management** - [Cobra](https://cobra.dev/)

View file

@ -1,9 +1,10 @@
package cmd
package app
import (
"fmt"
"git.a71.su/Andrew71/pye/storage"
"git.a71.su/Andrew71/pye/internal/models/user"
"git.a71.su/Andrew71/pye/internal/storage"
"github.com/spf13/cobra"
)
@ -20,7 +21,7 @@ var findUserCmd = &cobra.Command{
}
func findUser(cmd *cobra.Command, args []string) {
var user storage.User
var user user.User
var ok bool
if args[0] == "email" {
user, ok = storage.Data.ByEmail(args[1])

View file

@ -1,21 +1,21 @@
package cmd
package app
import (
"fmt"
"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"
"git.a71.su/Andrew71/pye/storage/sqlite"
"git.a71.su/Andrew71/pye/internal/auth"
"git.a71.su/Andrew71/pye/internal/config"
"git.a71.su/Andrew71/pye/internal/logging"
"git.a71.su/Andrew71/pye/internal/storage"
"git.a71.su/Andrew71/pye/internal/storage/sqlite"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
Use: "pye",
Short: "Pye is a simple JWT system",
Long: `A bare-bones authentication system built by Andrew71 as an assignment`,
Long: `A bare-bones authentication system with RS256`,
}
var (

View file

@ -1,12 +1,12 @@
package cmd
package app
import (
"log/slog"
"net/http"
"strconv"
"git.a71.su/Andrew71/pye/auth"
"git.a71.su/Andrew71/pye/config"
"git.a71.su/Andrew71/pye/internal/auth"
"git.a71.su/Andrew71/pye/internal/config"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"github.com/spf13/cobra"

View file

@ -1,11 +1,11 @@
package cmd
package app
import (
"fmt"
"log/slog"
"os"
"git.a71.su/Andrew71/pye/auth"
"git.a71.su/Andrew71/pye/internal/auth"
"github.com/golang-jwt/jwt/v5"
"github.com/spf13/cobra"
)

View file

@ -1,12 +1,13 @@
package auth
import (
"errors"
"log/slog"
"net/http"
"net/mail"
"strings"
"git.a71.su/Andrew71/pye/storage"
"git.a71.su/Andrew71/pye/internal/storage"
)
func validEmail(email string) bool {
@ -25,7 +26,7 @@ func Register(w http.ResponseWriter, r *http.Request) {
if ok {
email = strings.TrimSpace(email)
password = strings.TrimSpace(password)
if !(validEmail(email) && validPass(password) && !storage.Data.Taken(email)) {
if !(validEmail(email) && validPass(password)) {
slog.Debug("outcome",
"valid_email", validEmail(email),
"valid_pass", validPass(password),
@ -35,12 +36,15 @@ func Register(w http.ResponseWriter, r *http.Request) {
}
err := storage.Data.Add(email, password)
if err != nil {
slog.Error("error adding a new user", "error", err)
http.Error(w, "error adding a new user", http.StatusInternalServerError)
if errors.Is(err, storage.ErrExist) {
http.Error(w, "invalid auth credentials", http.StatusBadRequest)
} else {
http.Error(w, "error adding a new user", http.StatusInternalServerError)
}
return
}
w.WriteHeader(http.StatusCreated)
w.Write([]byte("User created"))
w.Write([]byte("user created"))
return
}

View file

@ -11,8 +11,8 @@ import (
"os"
"time"
"git.a71.su/Andrew71/pye/config"
"git.a71.su/Andrew71/pye/storage"
"git.a71.su/Andrew71/pye/internal/config"
"git.a71.su/Andrew71/pye/internal/models/user"
"github.com/golang-jwt/jwt/v5"
)
@ -66,7 +66,7 @@ func ServePublicKey(w http.ResponseWriter, r *http.Request) {
}
// Create creates a JSON Web Token that expires after a week
func Create(user storage.User) (token string, err error) {
func Create(user user.User) (token string, err error) {
t := jwt.NewWithClaims(jwt.SigningMethodRS256,
jwt.MapClaims{
"iss": "pye",

View file

@ -6,7 +6,7 @@ import (
"log/slog"
"os"
"git.a71.su/Andrew71/pye/config"
"git.a71.su/Andrew71/pye/internal/config"
"github.com/go-chi/chi/middleware"
)

View file

@ -1,4 +1,4 @@
package storage
package user
import (
"log/slog"

View file

@ -3,11 +3,13 @@ package sqlite
import (
"database/sql"
"errors"
"fmt"
"log/slog"
"os"
"git.a71.su/Andrew71/pye/storage"
_ "github.com/mattn/go-sqlite3"
"git.a71.su/Andrew71/pye/internal/models/user"
"git.a71.su/Andrew71/pye/internal/storage"
sqlite "github.com/mattn/go-sqlite3"
)
const create string = `
@ -24,30 +26,36 @@ type SQLiteStorage struct {
}
func (s SQLiteStorage) Add(email, password string) error {
user, err := storage.New(email, password)
user, err := user.New(email, password)
if err != nil {
return err
}
_, err = s.db.Exec("insert into users (uuid, email, password) values ($1, $2, $3)",
user.Uuid.String(), user.Email, user.Hash)
if err != nil {
e, ok := err.(sqlite.Error)
if ok && errors.Is(e.ExtendedCode, sqlite.ErrConstraintUnique) {
// Return a standard error if the user already exists
slog.Info("can't add user because email already taken", "user", user)
return fmt.Errorf("%w (%s)", storage.ErrExist, user.Email)
}
slog.Error("error adding user to database", "error", err, "user", user)
return err
}
return nil
}
func (s SQLiteStorage) ById(uuid string) (storage.User, bool) {
func (s SQLiteStorage) ById(uuid string) (user.User, bool) {
row := s.db.QueryRow("select * from users where uuid = $1", uuid)
user := storage.User{}
user := user.User{}
err := row.Scan(&user.Uuid, &user.Email, &user.Hash)
return user, err == nil
}
func (s SQLiteStorage) ByEmail(email string) (storage.User, bool) {
func (s SQLiteStorage) ByEmail(email string) (user.User, bool) {
row := s.db.QueryRow("select * from users where email = $1", email)
user := storage.User{}
user := user.User{}
err := row.Scan(&user.Uuid, &user.Email, &user.Hash)
return user, err == nil

View file

@ -0,0 +1,21 @@
package storage
import (
"errors"
"git.a71.su/Andrew71/pye/internal/models/user"
)
var ErrExist = errors.New("user already exists")
// Storage is an interface for arbitrary storage
type Storage interface {
Add(email, password string) error // Add inserts a user into data
ById(uuid string) (user.User, bool) // ById retrieves a user by their UUID
ByEmail(email string) (user.User, bool) // ByEmail retrieves a user by their email
Taken(email string) bool // Taken checks whether an email is taken
}
// Data stores active information for the app.
// It should be populated on startup
var Data Storage

View file

@ -1,7 +1,7 @@
package main
import "git.a71.su/Andrew71/pye/cmd"
import "git.a71.su/Andrew71/pye/internal/app"
func main() {
cmd.Execute()
app.Execute()
}

View file

@ -1,13 +0,0 @@
package storage
// Storage is an interface for arbitrary storage
type Storage interface {
Add(email, password string) error // Add inserts a user into data
ById(uuid string) (User, bool) // ById retrieves a user by their UUID
ByEmail(email string) (User, bool) // ByEmail retrieves a user by their email
Taken(email string) bool // Taken checks whether an email is taken
}
// Data stores active information for the app.
// It should be populated on startup
var Data Storage