Add encryption experiments

This commit is contained in:
Andrew71 2024-10-11 23:57:57 +03:00
parent bf5acf23b0
commit 94851e6104
10 changed files with 200 additions and 25 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
pye-auth
key

5
Makefile Normal file
View file

@ -0,0 +1,5 @@
build:
go build
run:
go build && ./pye-auth

View file

@ -1,3 +1,33 @@
# PYE
# PYE Auth
**Mission**: Science compels us to create a microservice!
This is the repository for my **JWT auth microservice assignment**
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 shape that proves I am somewhat competent.
## Course of action
How I currently see this going
1. Make an HTTP Basic Auth -> JWT -> Open key API
2. Create simple frontend (really stretching the definition) to test it
3. Ask myself and others - "Is this a microservice?"
If the answer is yes, rejoice.
If the answer is no, rejoice for a different reason.
4. Once it's technically solid-ish, polish ever-so-slightly
## "Technology stack"
The technology I *intend* on using
1. **Data storage - SQLite**.
Definitely want to avoid a full-sized DB because they're oversized for most
projects. To be honest, even **JSON** would do for this.
In fact, this might just be the way to go for the proof-of-concept, hm...
2. **Frontend - template/html module**. Duh, I am anti-bloat.
3. **HTTP routing - Chi**.
I'd use `net/http`, but a deadline of 1 week means speed is everything.

35
auth.go
View file

@ -1,6 +1,7 @@
package main
import (
"log/slog"
"net/http"
"net/mail"
"strings"
@ -13,9 +14,9 @@ func ValidEmail(email string) bool {
func ValidPass(pass string) bool {
return len(pass) >= 8 // TODO: Obviously, we *might* want something more sophisticated here
}
func TakenEmail(email string) bool {
// TODO: Implement
return false
func EmailTaken(email string) bool {
// TODO: Implement properly
return EmailExists(email)
}
func Register(w http.ResponseWriter, r *http.Request) {
email, password, ok := r.BasicAuth()
@ -23,10 +24,36 @@ func Register(w http.ResponseWriter, r *http.Request) {
if !ok {
email = strings.TrimSpace(email)
password = strings.TrimSpace(password)
if !(ValidEmail(email) || ValidPass(password) || TakenEmail(email)) {
if !(ValidEmail(email) || ValidPass(password) || EmailTaken(email)) {
// TODO: Provide descriptive error and check if 400 is best code?
http.Error(w, "Invalid auth credentials", http.StatusBadRequest)
return
}
user, err := NewUser(email, password)
if err != nil {
slog.Error("Error creating a new user", "error", err)
}
AddUser(user)
}
// No email and password was provided
w.Header().Set("WWW-Authenticate", `Basic realm="restricted", charset="UTF-8"`)
http.Error(w, "This API requires authorization", http.StatusUnauthorized)
}
func Login(w http.ResponseWriter, r *http.Request) {
email, password, ok := r.BasicAuth()
if !ok {
email = strings.TrimSpace(email)
password = strings.TrimSpace(password)
user, ok := ByEmail(email)
if !ok || !user.PasswordFits(password) {
http.Error(w, "You did something wrong", http.StatusUnauthorized)
return
}
w.WriteHeader(http.StatusOK)
}
// No email and password was provided

1
go.mod
View file

@ -3,6 +3,7 @@ module pye-auth
go 1.22
require (
github.com/golang-jwt/jwt/v5 v5.2.1
github.com/google/uuid v1.6.0
golang.org/x/crypto v0.28.0
)

2
go.sum
View file

@ -1,3 +1,5 @@
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
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=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=

44
jwt.go Normal file
View file

@ -0,0 +1,44 @@
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"log/slog"
// "github.com/golang-jwt/jwt/v5"
)
// var (
// key *ecdsa.PrivateKey
// t *jwt.Token
// s string
// key string
// )
func CreateKey() {
// TODO: Is this a secure key?
k, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
if err != nil {
slog.Error("Error generating key", "error", err)
}
km, _ := x509.MarshalECPrivateKey(k)
slog.Info("Key", "key", km)
}
// func CreateJWT(usr User) string {
// t := jwt.NewWithClaims(jwt.SigningMethodES256,
// jwt.MapClaims{
// "iss": "my-auth-server",
// "sub": "john",
// "foo": 2,
// })
// s, err := t.SignedString(key)
// if err != nil {
// slog.Error("Error creating JWT", "error", err)
// // TODO: Something
// }
// return s
// }

37
main.go
View file

@ -2,31 +2,34 @@ package main
import (
"fmt"
"net/http"
// "net/http"
)
func main() {
fmt.Println("Test")
router := http.NewServeMux()
CreateKey()
router.HandleFunc("POST /todos", func(w http.ResponseWriter, r *http.Request) {
fmt.Println("create a todo")
})
// router := http.NewServeMux()
router.HandleFunc("GET /todos", func(w http.ResponseWriter, r *http.Request) {
fmt.Println("get all todos")
})
// router.HandleFunc("POST /todos", func(w http.ResponseWriter, r *http.Request) {
// fmt.Println("create a todo")
// })
router.HandleFunc("PATCH /todos/{id}", func(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
fmt.Println("update a todo by id", id)
})
// // router.HandleFunc("GET /public-key", func(w http.ResponseWriter, r *http.Request) {
// // w.WriteHeader(http.StatusOK)
// // w.Write()
// // })
router.HandleFunc("DELETE /todos/{id}", func(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
fmt.Println("delete a todo by id", id)
})
// router.HandleFunc("PATCH /todos/{id}", func(w http.ResponseWriter, r *http.Request) {
// id := r.PathValue("id")
// fmt.Println("update a todo by id", id)
// })
http.ListenAndServe(":7102", router)
// router.HandleFunc("DELETE /todos/{id}", func(w http.ResponseWriter, r *http.Request) {
// id := r.PathValue("id")
// fmt.Println("delete a todo by id", id)
// })
// http.ListenAndServe(":7102", router)
}

60
pseudo_db.go Normal file
View file

@ -0,0 +1,60 @@
package main
import (
"encoding/json"
"log"
"os"
)
// So SQLite seems to hate my Mac.
// And I'd rather deal with something easily tinker-able in PoC stage
// So.................
// JSON.
//
// TODO: Kill this, preferably with fire.
func ReadUsers() []User {
data, err := os.ReadFile("./data.json")
if err != nil {
log.Fatal(err)
}
var users []User
err = json.Unmarshal(data, &users)
if err != nil {
log.Fatal(err)
}
return users
}
func AddUser(user User) {
users := ReadUsers()
users = append(users, user)
data, err := json.Marshal(users)
if err != nil {
log.Fatal(err)
}
err = os.WriteFile("./data.json", data, 0644)
if err != nil {
log.Fatal(err)
}
}
func EmailExists(email string) bool {
users := ReadUsers()
for i := 0; i < len(users); i++ {
if users[i].email == email {
return true
}
}
return false
}
func UserByEmail(email string) (User, bool) {
users := ReadUsers()
for i := 0; i < len(users); i++ {
if users[i].email == email {
return users[i], true
}
}
return User{}, false
}

View file

@ -24,6 +24,7 @@ func NewUser(email, password string) (User, error) {
return User{uuid.New(), email, hash}, nil
}
func CreateUser(User) {
// TODO: Implement
func ByEmail(email string) (User, bool) {
return UserByEmail(email)
}