Add the ability to manage .htpasswd from widdler.

This commit is contained in:
Aaron Bieber 2021-05-20 06:47:38 -06:00
parent 2cfd965467
commit 0c90ee2be7
3 changed files with 85 additions and 33 deletions

View File

@ -26,11 +26,11 @@ go get -u suah.dev/widdler
```
mkdir wiki
cd wiki
# OpenBSD:
htpasswd .htpasswd youruser
# or on Linux/macOS
# htpasswd -c -B youruser
widdler
# Generate a .htpasswd file:
widdler -gen
Username: qbit
Passwd: ******
./widdler
```
Now open your browser to [http://localhost:8080](http://localhost:8080).

2
go.sum
View File

@ -7,9 +7,9 @@ golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
suah.dev/protect v1.0.0 h1:X8pzDvDIZIiugmkmr6DES6JFO1XUdJWi34Ffmk6CMZY=

106
main.go
View File

@ -19,6 +19,7 @@ import (
"time"
"golang.org/x/crypto/bcrypt"
"golang.org/x/crypto/ssh/terminal"
"golang.org/x/net/webdav"
"suah.dev/protect"
)
@ -60,6 +61,7 @@ var (
auth bool
davDir string
fullListen string
genHtpass bool
handlers map[string]userHandlers
listen string
passPath string
@ -82,6 +84,7 @@ func init() {
flag.StringVar(&tlsKey, "tlskey", "", "TLS key.")
flag.StringVar(&passPath, "htpass", fmt.Sprintf("%s/.htpasswd", dir), "Path to .htpasswd file..")
flag.BoolVar(&auth, "auth", true, "Enable HTTP Basic Authentication.")
flag.BoolVar(&genHtpass, "gen", false, "Generate a .htpasswd file or add a new entry to an existing file.")
flag.Parse()
// These are OpenBSD specific protections used to prevent unnecessary file access.
@ -96,33 +99,6 @@ func init() {
log.Fatalln(err)
}
_, fErr := os.Stat(passPath)
if os.IsNotExist(fErr) {
if auth {
fmt.Println("No .htpasswd file found!")
os.Exit(1)
}
} else {
p, err := os.Open(passPath)
if err != nil {
log.Fatal(err)
}
defer p.Close()
ht := csv.NewReader(p)
ht.Comma = ':'
ht.Comment = '#'
ht.TrimLeadingSpace = true
entries, err := ht.ReadAll()
if err != nil {
log.Fatal(err)
}
for _, parts := range entries {
users[parts[0]] = parts[1]
}
}
}
func authenticate(user string, pass string) bool {
@ -164,7 +140,83 @@ func createEmpty(path string) error {
return nil
}
func prompt(prompt string, secure bool) (string, error) {
var input string
fmt.Print(prompt)
if secure {
b, err := terminal.ReadPassword(int(os.Stdin.Fd()))
if err != nil {
return "", err
}
input = string(b)
} else {
fmt.Scanln(&input)
}
return input, nil
}
func main() {
if genHtpass {
user, err := prompt("Username: ", false)
if err != nil {
log.Fatalln(err)
}
pass, err := prompt("Password: ", true)
if err != nil {
log.Fatalln(err)
}
hash, err := bcrypt.GenerateFromPassword([]byte(pass), 11)
if err != nil {
log.Fatalln(err)
}
f, err := os.OpenFile(passPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
log.Fatalln(err)
}
defer f.Close()
if _, err := f.WriteString(fmt.Sprintf("%s:%s\n", user, hash)); err != nil {
log.Fatalln(err)
}
fmt.Printf("Added %q to %q\n", user, passPath)
os.Exit(0)
}
_, fErr := os.Stat(passPath)
if os.IsNotExist(fErr) {
if auth {
fmt.Println("No .htpasswd file found!")
os.Exit(1)
}
} else {
p, err := os.Open(passPath)
if err != nil {
log.Fatal(err)
}
defer p.Close()
ht := csv.NewReader(p)
ht.Comma = ':'
ht.Comment = '#'
ht.TrimLeadingSpace = true
entries, err := ht.ReadAll()
if err != nil {
log.Fatal(err)
}
for _, parts := range entries {
users[parts[0]] = parts[1]
}
}
if auth {
for u := range users {
uPath := path.Join(davDir, u)