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 }