From df6ff8ff2bdc00cb9ef86fcc9977e07c0984db81 Mon Sep 17 00:00:00 2001 From: poyo Date: Tue, 13 Oct 2026 22:31:21 +0200 Subject: [PATCH] admin password hashing --- .gitignore | 3 ++- README.md | 11 ++++++++++- crypto.go | 20 ++++++++++++++++++++ env.go | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 8 +++++++- go.sum | 8 ++++++++ main.go | 13 +++++++++++++ 7 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 crypto.go create mode 100644 env.go diff --git a/.gitignore b/.gitignore index cf4c7eb..d32d550 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ content/* _dist/* -layout/* \ No newline at end of file +layout/* +.env \ No newline at end of file diff --git a/README.md b/README.md index 10a6c08..c8f26bd 100644 --- a/README.md +++ b/README.md @@ -14,4 +14,13 @@ tags: example,another example,lol # Cookies blah *blah* **blah** -``` \ No newline at end of file +``` + +## Configuration. +To set the admin password, run: + +```sh +go run . --set-password "PasswordHere_1234" +``` + +It will be saved to the `.env`. \ No newline at end of file diff --git a/crypto.go b/crypto.go new file mode 100644 index 0000000..6d8cc6c --- /dev/null +++ b/crypto.go @@ -0,0 +1,20 @@ +package main + +import ( + "log" + + "golang.org/x/crypto/bcrypt" +) + +func HashPassword(input []byte) []byte { + hash, err := bcrypt.GenerateFromPassword(input, 12) + if err != nil { + log.Fatal("Couldn't hash the password: " + err.Error()) + } + + return hash +} + +func ValidatePassword(hash []byte, password []byte) bool { + return bcrypt.CompareHashAndPassword(hash, password) == nil +} diff --git a/env.go b/env.go new file mode 100644 index 0000000..3690594 --- /dev/null +++ b/env.go @@ -0,0 +1,52 @@ +package main + +import ( + "log" + "os" + "strconv" + + "github.com/joho/godotenv" +) + +const ( + SECURE = "SECURE" + PASSWORD_HASH = "PASSWORD_HASH" +) + +type EnvVars struct { + PasswordHash []byte // hashed passwd of the admin/only user. + Secure bool // whether or not the frontend is served via HTTPs. +} + +func LoadEnv() EnvVars { + var env EnvVars + var err error + godotenv.Load() + + env.PasswordHash = []byte(os.Getenv(PASSWORD_HASH)) + secureVar, found := os.LookupEnv(SECURE) + if found { + env.Secure, err = strconv.ParseBool(secureVar) + if err != nil { + panic("Invalid HTTPS value: Should be either 'true' or 'false'") + } + } else { + env.Secure = false // assume false by default + } + + return env +} + +// reads and saves a single key to the .env +func SaveKeyToEnv(key string, value string) { + env, err := godotenv.Read(".env") + if err != nil && !os.IsNotExist(err) { + log.Fatal("Failed to read .env: " + err.Error()) + } + + env[key] = value + + if err := godotenv.Write(env, ".env"); err != nil { + log.Fatal(err) + } +} diff --git a/go.mod b/go.mod index 9152f36..d0d4d40 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,10 @@ module ssg go 1.27.1 -require github.com/gomarkdown/markdown v0.0.0-20260923180740-94fc73f6b1a3 +require ( + github.com/gomarkdown/markdown v0.0.0-20260923180740-94fc73f6b1a3 + github.com/joho/godotenv v1.5.1 + golang.org/x/crypto v0.58.0 +) + +require golang.org/x/sys v0.49.0 // indirect diff --git a/go.sum b/go.sum index 29bca07..8f4617f 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,10 @@ github.com/gomarkdown/markdown v0.0.0-20260923180740-94fc73f6b1a3 h1:tTy9EC3uLxFeMrYCOf+T4cS86imMT6kGMl7htiU907o= github.com/gomarkdown/markdown v0.0.0-20260923180740-94fc73f6b1a3/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= +golang.org/x/crypto v0.58.0 h1:COkYLr4k7nDI4r6QtMML2AfzeIswWHAJthLS6K/M/54= +golang.org/x/crypto v0.58.0/go.mod h1:Xh+kl5A+M0gMiWDytH2Hhr5Z7WbNCpv/eB/EFgfSk+w= +golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.49.0 h1:XbzkgYJHdqh/8m2Uu0W/dQv8nktxx4BFHp1M0gROTXA= +golang.org/x/sys v0.49.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= diff --git a/main.go b/main.go index 2344d9c..fc6dc1c 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,7 @@ package main import ( + "flag" "fmt" "log" "os" @@ -14,6 +15,18 @@ const OUTPUT_DIR = "./_dist" const UNTITLED_POST = "Untitled rambling." func main() { + newAdminPassword := flag.String("set-password", "", "Sets the admin password and hashes it into the .envz.") + flag.Parse() + + if *newAdminPassword != "" { + passwordHash := HashPassword([]byte(*newAdminPassword)) + + SaveKeyToEnv(PASSWORD_HASH, string(passwordHash)) + fmt.Printf("Hashed your password. '%s'. DO NOT SHARE IT.\n", passwordHash) + + os.Exit(0) + } + srcDir := EnsureDir(CONTENT_DIR, true) // distDir := EnsureDir(OUTPUT_DIR) ClearDir(OUTPUT_DIR) -- 2.51.2