Add --adduser flag to add users manually as a site operator.

このコミットが含まれているのは:
Christian Heller 2016-02-12 23:51:15 +01:00
コミット fbec273fb9
3個のファイルの変更63行の追加24行の削除

ファイルの表示

@ -10,18 +10,20 @@ space.
## Features (or lack thereof)
- users may register accounts mapped to individual twtxt feeds they may write to
- user accounts may be registered, mapped to individual twtxt feeds they can
write to
- no sessions, no cookies: few POST-writable resources (feeds, account data)
expect user credential parameters, which to store between requests is up to
the user / browser
expect user credential parameters, which to store between requests if desired
is up to the user / browser
- account registration may be open to the public, or closed (with the site
operator adding new accounts manually)
- users may register e-mail addresses and optional security questions to allow
for password reset (if enabled by site operator)
- account registration may be closed or open to the public
- HTTPS / TLS support (if paths to key and certificate files are provided)
## Online demo
A demo instance with frequent downtimes can be tested at
A demo instance with frequent downtimes and open sign-up can be tested at
http://test.plomlompom.com:8000 (don't expect any of its feeds' URLs to be
stable; it's just for testing, and data frequently gets deleted).
@ -76,10 +78,12 @@ This is [a common privilege problem](http://stackoverflow.com/q/413807) and
sudo setcap 'cap_net_bind_service=+ep' $GOPATH/bin/htwtxt
### Public sign-up
### Public or closed sign-up
By default, sign up / account creation is not open to the public. The `--signup`
flag must be set explicitely to change that.
By default, sign up / account creation is not open to the web-browsing public.
The `--signup` flag must be set explicitely to change that. Alternatively, new
accounts can be added by starting the program with the `--adduser` flag,
followed by an argument of the form `NAME:PASSWORD`.
### Set site owner contact info

ファイルの表示

@ -170,7 +170,7 @@ func signUpHandler(w http.ResponseWriter, r *http.Request) {
return
}
name := r.FormValue("name")
if "" == name || !onlyLegalRunes(name) || len(name) > 140 {
if !nameIsLegal(name) {
execTemplate(w, "error.html", "Illegal name.")
return
}

65
main.go
ファイルの表示

@ -117,19 +117,31 @@ func login(w http.ResponseWriter, r *http.Request) (string, error) {
return name, nil
}
func nameIsLegal(name string) bool {
return !("" == name || !onlyLegalRunes(name) || len(name) > 140)
}
func passwordIsLegal(password string) bool {
return !("" == password)
}
func hashFromPw(pw string) string {
hash, err := bcrypt.GenerateFromPassword([]byte(pw), bcrypt.DefaultCost)
if err != nil {
log.Fatal("Can't generate hash", err)
}
return string(hash)
}
func newPassword(w http.ResponseWriter, r *http.Request) (string, error) {
pw := r.FormValue("new_password")
pw2 := r.FormValue("new_password2")
if 0 != strings.Compare(pw, pw2) {
return "", errors.New("Password values did not match")
} else if "" == pw {
} else if !passwordIsLegal(pw) {
return "", errors.New("Illegal password.")
}
hash, err := bcrypt.GenerateFromPassword([]byte(pw), bcrypt.DefaultCost)
if err != nil {
log.Fatal("Can't generate password hash", err)
}
return string(hash), nil
return hashFromPw(pw), nil
}
func newMailAddress(w http.ResponseWriter, r *http.Request) (string, error) {
@ -152,12 +164,7 @@ func newSecurityQuestion(w http.ResponseWriter, r *http.Request) (string,
} else if "" == secanswer {
return "", "", errors.New("Illegal security question answer.")
}
hash, err := bcrypt.GenerateFromPassword([]byte(secanswer),
bcrypt.DefaultCost)
if err != nil {
log.Fatal("Can't generate security question answer hash", err)
}
return secquestion, string(hash), nil
return secquestion, hashFromPw(secanswer), nil
}
func changeLoginField(w http.ResponseWriter, r *http.Request,
@ -203,11 +210,14 @@ func nameMyself(ssl bool, port int) string {
return "http" + s + "://" + ip + ":" + strconv.Itoa(port)
}
func readOptions() (string, int, string, int) {
func readOptions() (string, int, string, int, string) {
var mailpw string
var mailport int
var mailserver string
var port int
var newLogin string
flag.StringVar(&newLogin, "adduser", "", "instead of starting as "+
"server, add user with login NAME:PASSWORD")
flag.IntVar(&port, "port", 8000, "port to serve")
flag.StringVar(&keyPath, "key", "", "SSL key file")
flag.StringVar(&certPath, "cert", "", "SSL certificate file")
@ -244,13 +254,38 @@ func readOptions() (string, int, string, int) {
mailpw = string(bytePassword)
fmt.Println("")
}
return mailserver, mailport, mailpw, port
return mailserver, mailport, mailpw, port, newLogin
}
func addUser(login string) {
fields := strings.Split(login, ":")
if len(fields) != 2 {
log.Fatal("Malformed adduser string, must be NAME:PASSWORD")
}
name := fields[0]
password := fields[1]
if !nameIsLegal(name) {
log.Fatal("Malformed adduser NAME argument.")
}
if !passwordIsLegal(password) {
log.Fatal("Malformed adduser PASSWORD argument.")
}
if _, err := getFromFileEntryFor(loginsPath, name, 5); err == nil {
log.Fatal("Username already taken.")
}
hash := hashFromPw(password)
appendToFile(loginsPath, name+"\t"+hash+"\t\t\t")
fmt.Println("Added user.")
}
func main() {
var err error
mailserver, mailport, mailpw, port := readOptions()
mailserver, mailport, mailpw, port, newLogin := readOptions()
initFilesAndDirs()
if "" != newLogin {
addUser(newLogin)
return
}
myself = nameMyself("" != keyPath, port)
templ, err = template.New("main").ParseGlob(templPath + "/*.html")
if err != nil {