diff --git a/go.mod b/go.mod
index 060d073..6f4d76d 100644
--- a/go.mod
+++ b/go.mod
@@ -5,8 +5,11 @@ go 1.14
require (
git.sr.ht/~adnano/go-gemini v0.1.13
github.com/adrg/xdg v0.2.2
- github.com/go-ini/ini v1.62.0 // indirect
+ github.com/go-ini/ini v1.62.0
github.com/gorilla/feeds v1.1.1
github.com/kr/pretty v0.2.1 // indirect
+ github.com/smartystreets/goconvey v1.6.4 // indirect
github.com/valyala/quicktemplate v1.6.3
+ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
+ gopkg.in/ini.v1 v1.62.0 // indirect
)
diff --git a/go.sum b/go.sum
index 544a723..5c4b13d 100644
--- a/go.sum
+++ b/go.sum
@@ -7,8 +7,12 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-ini/ini v1.62.0 h1:7VJT/ZXjzqSrvtraFp4ONq80hTcRQth1c9ZnQ3uNQvU=
github.com/go-ini/ini v1.62.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/feeds v1.1.1 h1:HwKXxqzcRNg9to+BbvJog4+f3s/xzvtZXICcQGutYfY=
github.com/gorilla/feeds v1.1.1/go.mod h1:Nk0jZrvPFZX1OBe5NPiddPw7CfwF6Q9eqzaBbaightA=
+github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.11.0/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
@@ -18,6 +22,10 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@@ -27,13 +35,18 @@ github.com/valyala/fasthttp v1.16.0/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl
github.com/valyala/quicktemplate v1.6.3 h1:O7EuMwuH7Q94U2CXD6sOX8AYHqQqWtmIk690IhmpkKA=
github.com/valyala/quicktemplate v1.6.3/go.mod h1:fwPzK2fHuYEODzJ9pkw0ipCPNHZ2tD5KW4lOuSdPKzY=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
+gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/http_auth.go b/http_auth.go
index 9981520..52f6260 100644
--- a/http_auth.go
+++ b/http_auth.go
@@ -1,6 +1,7 @@
package main
import (
+ "io"
"log"
"net/http"
@@ -10,12 +11,34 @@ import (
)
func init() {
+ http.HandleFunc("/register", handlerRegister)
http.HandleFunc("/login", handlerLogin)
http.HandleFunc("/login-data", handlerLoginData)
http.HandleFunc("/logout", handlerLogout)
http.HandleFunc("/logout-confirm", handlerLogoutConfirm)
}
+func handlerRegister(w http.ResponseWriter, rq *http.Request) {
+ log.Println(rq.URL)
+ if util.UseRegistration {
+ w.WriteHeader(http.StatusOK)
+ } else {
+ w.WriteHeader(http.StatusForbidden)
+ }
+ if rq.Method == http.MethodGet {
+ io.WriteString(
+ w,
+ base(
+ "Register",
+ views.RegisterHTML(rq),
+ user.FromRequest(rq),
+ ),
+ )
+ } else if rq.Method == http.MethodPost {
+ io.WriteString(w, "Not implemented")
+ }
+}
+
func handlerLogout(w http.ResponseWriter, rq *http.Request) {
var (
u = user.FromRequest(rq)
diff --git a/user/files.go b/user/files.go
index a4fa7a0..721b82c 100644
--- a/user/files.go
+++ b/user/files.go
@@ -4,8 +4,8 @@ import (
"encoding/json"
"io/ioutil"
"log"
- "strings"
"os"
+ "strings"
"github.com/adrg/xdg"
"github.com/bouncepaw/mycorrhiza/util"
@@ -27,6 +27,9 @@ func usersFromFixedCredentials() []*User {
if err != nil {
log.Fatal(err)
}
+ for _, u := range users {
+ u.Source = SourceFixed
+ }
log.Println("Found", len(users), "fixed users")
return users
}
diff --git a/user/user.go b/user/user.go
index e126d76..efce8a2 100644
--- a/user/user.go
+++ b/user/user.go
@@ -1,15 +1,29 @@
package user
import (
+ "golang.org/x/crypto/bcrypt"
"sync"
)
+// UserSource shows where is the user data gotten from.
+type UserSource int
+
+const (
+ SourceUnknown UserSource = iota
+ // SourceFixed is used with users that are predefined using fixed auth
+ SourceFixed
+ // SourceRegistration is used with users that are registered through the register form
+ SourceRegistration
+)
+
// User is a user.
type User struct {
// Name is a username. It must follow hypha naming rules.
- Name string `json:"name"`
- Group string `json:"group"`
- Password string `json:"password"`
+ Name string `json:"name"`
+ Group string `json:"group"`
+ Password string `json:"password"` // for fixed
+ HashedPassword string `json:"hashed_password"` // for registered
+ Source UserSource `json:"-"`
sync.RWMutex
}
@@ -67,5 +81,12 @@ func (user *User) isCorrectPassword(password string) bool {
user.RLock()
defer user.RUnlock()
- return password == user.Password
+ switch user.Source {
+ case SourceFixed:
+ return password == user.Password
+ case SourceRegistration:
+ err := bcrypt.CompareHashAndPassword([]byte(user.HashedPassword), []byte(password))
+ return err == nil
+ }
+ return false
}
diff --git a/views/auth.qtpl b/views/auth.qtpl
index f3f257a..2cf72ae 100644
--- a/views/auth.qtpl
+++ b/views/auth.qtpl
@@ -1,6 +1,41 @@
+{% import "net/http" %}
{% import "github.com/bouncepaw/mycorrhiza/user" %}
{% import "github.com/bouncepaw/mycorrhiza/util" %}
+{% func RegisterHTML(rq *http.Request) %}
+
+
+
+ {% if util.UseRegistration %}
+
+ {% elseif util.UseFixedAuth %}
+ Administrators have forbidden registration for this wiki. Administrators can make an account for you by hand; contact them.
+ ← Go back
+ {% else %}
+ Administrators of this wiki have not configured any authorization method. You can make edits anonymously.
+ ← Go back
+ {% endif %}
+
+
+
+{% endfunc %}
+
{% func LoginHTML() %}
diff --git a/views/auth.qtpl.go b/views/auth.qtpl.go
index 74d83b1..02b7743 100644
--- a/views/auth.qtpl.go
+++ b/views/auth.qtpl.go
@@ -5,42 +5,142 @@
package views
//line views/auth.qtpl:1
-import "github.com/bouncepaw/mycorrhiza/user"
+import "net/http"
//line views/auth.qtpl:2
+import "github.com/bouncepaw/mycorrhiza/user"
+
+//line views/auth.qtpl:3
import "github.com/bouncepaw/mycorrhiza/util"
-//line views/auth.qtpl:4
+//line views/auth.qtpl:5
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
-//line views/auth.qtpl:4
+//line views/auth.qtpl:5
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
-//line views/auth.qtpl:4
-func StreamLoginHTML(qw422016 *qt422016.Writer) {
-//line views/auth.qtpl:4
+//line views/auth.qtpl:5
+func StreamRegisterHTML(qw422016 *qt422016.Writer, rq *http.Request) {
+//line views/auth.qtpl:5
qw422016.N().S(`
`)
-//line views/auth.qtpl:8
+//line views/auth.qtpl:9
+ if util.UseRegistration {
+//line views/auth.qtpl:9
+ qw422016.N().S(`
+
+ `)
+//line views/auth.qtpl:27
+ } else if util.UseFixedAuth {
+//line views/auth.qtpl:27
+ qw422016.N().S(`
+ Administrators have forbidden registration for this wiki. Administrators can make an account for you by hand; contact them.
+ ← Go back
+ `)
+//line views/auth.qtpl:30
+ } else {
+//line views/auth.qtpl:30
+ qw422016.N().S(`
+ Administrators of this wiki have not configured any authorization method. You can make edits anonymously.
+ ← Go back
+ `)
+//line views/auth.qtpl:33
+ }
+//line views/auth.qtpl:33
+ qw422016.N().S(`
+
+
+
+`)
+//line views/auth.qtpl:37
+}
+
+//line views/auth.qtpl:37
+func WriteRegisterHTML(qq422016 qtio422016.Writer, rq *http.Request) {
+//line views/auth.qtpl:37
+ qw422016 := qt422016.AcquireWriter(qq422016)
+//line views/auth.qtpl:37
+ StreamRegisterHTML(qw422016, rq)
+//line views/auth.qtpl:37
+ qt422016.ReleaseWriter(qw422016)
+//line views/auth.qtpl:37
+}
+
+//line views/auth.qtpl:37
+func RegisterHTML(rq *http.Request) string {
+//line views/auth.qtpl:37
+ qb422016 := qt422016.AcquireByteBuffer()
+//line views/auth.qtpl:37
+ WriteRegisterHTML(qb422016, rq)
+//line views/auth.qtpl:37
+ qs422016 := string(qb422016.B)
+//line views/auth.qtpl:37
+ qt422016.ReleaseByteBuffer(qb422016)
+//line views/auth.qtpl:37
+ return qs422016
+//line views/auth.qtpl:37
+}
+
+//line views/auth.qtpl:39
+func StreamLoginHTML(qw422016 *qt422016.Writer) {
+//line views/auth.qtpl:39
+ qw422016.N().S(`
+
+
+
+ `)
+//line views/auth.qtpl:43
if user.AuthUsed {
-//line views/auth.qtpl:8
+//line views/auth.qtpl:43
qw422016.N().S(`
`)
-//line views/auth.qtpl:25
+//line views/auth.qtpl:60
} else {
-//line views/auth.qtpl:25
+//line views/auth.qtpl:60
qw422016.N().S(`
Administrators of this wiki have not configured any authorization method. You can make edits anonymously.
← Go home
`)
-//line views/auth.qtpl:28
+//line views/auth.qtpl:63
}
-//line views/auth.qtpl:28
+//line views/auth.qtpl:63
qw422016.N().S(`
`)
-//line views/auth.qtpl:32
+//line views/auth.qtpl:67
}
-//line views/auth.qtpl:32
+//line views/auth.qtpl:67
func WriteLoginHTML(qq422016 qtio422016.Writer) {
-//line views/auth.qtpl:32
+//line views/auth.qtpl:67
qw422016 := qt422016.AcquireWriter(qq422016)
-//line views/auth.qtpl:32
+//line views/auth.qtpl:67
StreamLoginHTML(qw422016)
-//line views/auth.qtpl:32
+//line views/auth.qtpl:67
qt422016.ReleaseWriter(qw422016)
-//line views/auth.qtpl:32
+//line views/auth.qtpl:67
}
-//line views/auth.qtpl:32
+//line views/auth.qtpl:67
func LoginHTML() string {
-//line views/auth.qtpl:32
+//line views/auth.qtpl:67
qb422016 := qt422016.AcquireByteBuffer()
-//line views/auth.qtpl:32
+//line views/auth.qtpl:67
WriteLoginHTML(qb422016)
-//line views/auth.qtpl:32
+//line views/auth.qtpl:67
qs422016 := string(qb422016.B)
-//line views/auth.qtpl:32
+//line views/auth.qtpl:67
qt422016.ReleaseByteBuffer(qb422016)
-//line views/auth.qtpl:32
+//line views/auth.qtpl:67
return qs422016
-//line views/auth.qtpl:32
+//line views/auth.qtpl:67
}
-//line views/auth.qtpl:34
+//line views/auth.qtpl:69
func StreamLoginErrorHTML(qw422016 *qt422016.Writer, err string) {
-//line views/auth.qtpl:34
+//line views/auth.qtpl:69
qw422016.N().S(`
`)
-//line views/auth.qtpl:38
+//line views/auth.qtpl:73
switch err {
-//line views/auth.qtpl:39
+//line views/auth.qtpl:74
case "unknown username":
-//line views/auth.qtpl:39
+//line views/auth.qtpl:74
qw422016.N().S(`
Unknown username.
`)
-//line views/auth.qtpl:41
+//line views/auth.qtpl:76
case "wrong password":
-//line views/auth.qtpl:41
+//line views/auth.qtpl:76
qw422016.N().S(`
Wrong password.
`)
-//line views/auth.qtpl:43
+//line views/auth.qtpl:78
default:
-//line views/auth.qtpl:43
+//line views/auth.qtpl:78
qw422016.N().S(`
`)
-//line views/auth.qtpl:44
+//line views/auth.qtpl:79
qw422016.E().S(err)
-//line views/auth.qtpl:44
+//line views/auth.qtpl:79
qw422016.N().S(`
`)
-//line views/auth.qtpl:45
+//line views/auth.qtpl:80
}
-//line views/auth.qtpl:45
+//line views/auth.qtpl:80
qw422016.N().S(`
← Try again
`)
-//line views/auth.qtpl:50
+//line views/auth.qtpl:85
}
-//line views/auth.qtpl:50
+//line views/auth.qtpl:85
func WriteLoginErrorHTML(qq422016 qtio422016.Writer, err string) {
-//line views/auth.qtpl:50
+//line views/auth.qtpl:85
qw422016 := qt422016.AcquireWriter(qq422016)
-//line views/auth.qtpl:50
+//line views/auth.qtpl:85
StreamLoginErrorHTML(qw422016, err)
-//line views/auth.qtpl:50
+//line views/auth.qtpl:85
qt422016.ReleaseWriter(qw422016)
-//line views/auth.qtpl:50
+//line views/auth.qtpl:85
}
-//line views/auth.qtpl:50
+//line views/auth.qtpl:85
func LoginErrorHTML(err string) string {
-//line views/auth.qtpl:50
+//line views/auth.qtpl:85
qb422016 := qt422016.AcquireByteBuffer()
-//line views/auth.qtpl:50
+//line views/auth.qtpl:85
WriteLoginErrorHTML(qb422016, err)
-//line views/auth.qtpl:50
+//line views/auth.qtpl:85
qs422016 := string(qb422016.B)
-//line views/auth.qtpl:50
+//line views/auth.qtpl:85
qt422016.ReleaseByteBuffer(qb422016)
-//line views/auth.qtpl:50
+//line views/auth.qtpl:85
return qs422016
-//line views/auth.qtpl:50
+//line views/auth.qtpl:85
}
-//line views/auth.qtpl:52
+//line views/auth.qtpl:87
func StreamLogoutHTML(qw422016 *qt422016.Writer, can bool) {
-//line views/auth.qtpl:52
+//line views/auth.qtpl:87
qw422016.N().S(`
`)
-//line views/auth.qtpl:56
+//line views/auth.qtpl:91
if can {
-//line views/auth.qtpl:56
+//line views/auth.qtpl:91
qw422016.N().S(`
Log out?
Confirm
Cancel
`)
-//line views/auth.qtpl:60
+//line views/auth.qtpl:95
} else {
-//line views/auth.qtpl:60
+//line views/auth.qtpl:95
qw422016.N().S(`
You cannot log out because you are not logged in.
Login
← Home
`)
-//line views/auth.qtpl:64
+//line views/auth.qtpl:99
}
-//line views/auth.qtpl:64
+//line views/auth.qtpl:99
qw422016.N().S(`
`)
-//line views/auth.qtpl:68
+//line views/auth.qtpl:103
}
-//line views/auth.qtpl:68
+//line views/auth.qtpl:103
func WriteLogoutHTML(qq422016 qtio422016.Writer, can bool) {
-//line views/auth.qtpl:68
+//line views/auth.qtpl:103
qw422016 := qt422016.AcquireWriter(qq422016)
-//line views/auth.qtpl:68
+//line views/auth.qtpl:103
StreamLogoutHTML(qw422016, can)
-//line views/auth.qtpl:68
+//line views/auth.qtpl:103
qt422016.ReleaseWriter(qw422016)
-//line views/auth.qtpl:68
+//line views/auth.qtpl:103
}
-//line views/auth.qtpl:68
+//line views/auth.qtpl:103
func LogoutHTML(can bool) string {
-//line views/auth.qtpl:68
+//line views/auth.qtpl:103
qb422016 := qt422016.AcquireByteBuffer()
-//line views/auth.qtpl:68
+//line views/auth.qtpl:103
WriteLogoutHTML(qb422016, can)
-//line views/auth.qtpl:68
+//line views/auth.qtpl:103
qs422016 := string(qb422016.B)
-//line views/auth.qtpl:68
+//line views/auth.qtpl:103
qt422016.ReleaseByteBuffer(qb422016)
-//line views/auth.qtpl:68
+//line views/auth.qtpl:103
return qs422016
-//line views/auth.qtpl:68
+//line views/auth.qtpl:103
}