started login system

This commit is contained in:
drevil 2023-06-13 23:49:34 -04:00
parent bd6fbb2bce
commit c0d546b167
5 changed files with 163 additions and 26 deletions

3
.gitignore vendored
View File

@ -1,3 +1,4 @@
comics
db.sqlite
media
media
secret.key

View File

@ -17,10 +17,10 @@ import (
_ "github.com/mattn/go-sqlite3"
)
var errlog *log.Logger = nil
var db *sql.DB = nil
var errlog *log.Logger = nil
var db *sql.DB = nil
var options Options = Options{}
var options Options = Options{}
var NoSuchComicErr Err = Err{msg: "no such comic found"}
@ -45,25 +45,27 @@ type Options struct {
ImagePath string
RunManager bool
UploadSize int64
SiteURL string
SiteURL string
SecretPath string
}
type Comic struct {
ID int
DateTime string
Title string
Image string
Description string
Tags string
ID int
DateTime string
Title string
Image string
Description string
Tags string
}
type Context struct {
Comics []struct{
No int
Title string
Date string
Image string
}
No int
Title string
Date string
Image string
}
Comic *Comic
Current int
Previous int
@ -83,7 +85,7 @@ type Err struct {
func (o * Options) Parse() error {
flag.StringVar(&o.DBPath, "d", "./db.sqlite", "Sets path to database file")
flag.StringVar(&o.MediaPath, "m", "./media/", "Sets path to media directory")
flag.StringVar(&o.TemplatesPath, "t", "./templates/", "Sets path to templates directory")
flag.StringVar(&o.TemplatesPath, "t", "./templates/", "Sets path to templates directory")
flag.StringVar(&o.Address, "a", "127.0.0.1", "Defines the address the web server will listen to")
flag.IntVar(&o.Port, "p", 8080, "Defines the port the web server will listen to")
flag.BoolVar(&o.Publish, "u", false, "Creates new commics. Needs both -i and -l")
@ -92,7 +94,8 @@ func (o * Options) Parse() error {
flag.BoolVar(&o.RunManager, "r", false, "Runs the content manager instead of the site")
flag.Int64Var(&o.UploadSize, "z", 10, "Max upload size for posts")
flag.StringVar(&o.SiteURL, "0", "https://comics.blackram.works", "URL of the site once deployed")
flag.StringVar(&o.SecretPath, "s", "./secret.key", "Sets path to secret key file")
flag.Parse()
if _, err := os.Stat(o.TemplatesPath); errors.Is(err, os.ErrNotExist) {
@ -100,12 +103,11 @@ func (o * Options) Parse() error {
}
if _, err := os.Stat(o.MediaPath); errors.Is(err, os.ErrNotExist) {
err := os.Mkdir(o.MediaPath, os.ModePerm)
err := os.Mkdir(o.MediaPath, os.ModePerm)
if err != nil {
log.Fatal(err)
}
}
return nil
}
@ -375,6 +377,10 @@ func returnError(w http.ResponseWriter, r * http.Request, status int) {
err = t.Execute(w, &c)
}
func return401(w http.ResponseWriter, r * http.Request) {
returnError(w, r, http.StatusUnauthorized)
}
func return404(w http.ResponseWriter, r * http.Request) {
returnError(w, r, http.StatusNotFound)
}

5
go.mod
View File

@ -3,3 +3,8 @@ module tildegit.com/drevil/comics
go 1.19
require github.com/mattn/go-sqlite3 v1.14.16
require (
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
golang.org/x/crypto v0.10.0 // indirect
)

4
go.sum
View File

@ -1,2 +1,6 @@
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=

View File

@ -11,16 +11,75 @@ import (
"strings"
"net/http"
"math/rand"
"database/sql"
"path/filepath"
"github.com/golang-jwt/jwt"
"golang.org/x/crypto/bcrypt"
)
var seededRand *rand.Rand = nil
var secretKey string = ""
const authSquema string = `
CREATE TABLE IF NOT EXISTS user (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
name CHAR(20),
password CHAR(100)
);`
type User struct {
ID int
Name string
Password string
}
type ConfirmContext struct {
Action string
Message string
OnYes string
OnNo string
Action string
Message string
OnYes string
OnNo string
}
func (u *User) readRow(db * sql.Rows) error {
return db.Scan(&u.ID, &u.Name, &u.Password)
}
func generateToken(username string) (string, error) {
token := jwt.New(jwt.SigningMethodEdDSA)
claims := token.Claims.(jwt.MapClaims)
claims["exp"] = time.Now().Add(10 * time.Minute)
claims["authorized"] = true
claims["user"] = username
tokenString, err := token.SignedString(secretKey)
if err != nil {
return "Signing Error", err
}
return tokenString, nil
}
func getAllUsers() ([]User, error) {
rows, err := db.Query("SELECT * FROM user ORDER BY id ASC")
if err != nil {
return nil, err
}
defer rows.Close()
users := []User{}
for rows.Next() {
u := User{}
err := u.readRow(rows)
if err != nil {
return users, err
}
users = append(users, u)
}
return users, nil
}
func randomString(length int) string {
@ -34,7 +93,7 @@ func randomString(length int) string {
func managerIndexView(w http.ResponseWriter, r * http.Request) {
var err error
defer func() {
if err != nil {
errlog.Println(err)
@ -167,12 +226,74 @@ func managerPublishView(w http.ResponseWriter, r * http.Request) {
http.Redirect(w, r, "/", http.StatusSeeOther)
}
func loginView(w http.ResponseWriter, r * http.Request) {
if r.Method != "POST" {
return404(w, r)
return
}
username := r.FormValue("username")
password := r.FormValue("password")
if username == "" || password == "" {
return404(w, r)
return
}
if len(username) >= 20 {
username = username[:20]
}
if len(password) >= 100 {
password = password[:100]
}
users, _ := getAllUsers()
var user *User = nil
for i, u := range(users) {
if u.Name == username {
user = &users[i]
break
}
}
if user == nil {
return401(w, r)
return
}
if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil {
return401(w, r)
return
}
http.Redirect(w, r, "/", http.StatusSeeOther)
}
func managerEditView(w http.ResponseWriter, r * http.Request) {
}
func startManager(address string, port int, dbPath string, mediaPath string) error {
_, err := db.Exec(authSquema)
if err != nil {
log.Fatal(err)
}
seededRand = rand.New(rand.NewSource(time.Now().UnixNano()))
_, err = os.Stat(options.SecretPath)
if os.IsNotExist(err) {
secretKey = randomString(100)
err = os.WriteFile(options.SecretPath, []byte(secretKey), 0600)
if err != nil {
log.Fatal(fmt.Sprintf("failed to create random key: %s", err))
}
} else {
s, err := os.ReadFile(options.SecretPath)
secretKey = string(s)
if err != nil {
log.Fatal(fmt.Sprintf("failed to read random key: %s", err))
}
}
http.HandleFunc("/", managerIndexView)
http.HandleFunc("/edit/", managerEditView)
http.HandleFunc("/remove/", managerRemoveView)