1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2025-01-05 17:40:26 +00:00

Drop fixed authorization

Important changes:
- UseFixedAuth is now UseAuth and toggles all kinds of authorization and
  registration
- UseRegistration is now AllowRegistration to better reflect the meaning
- LimitRegistration is now RegistrationLimit because it's not a boolean,
  it's a value (not "limit registration?", but "registration limit is
  ...")
- registered-users.json is now users.json, because all users are stored
  there
- user.AuthUsed is dropped in favor of new cfg.UseAuth which has the
  same meaning

I hope I have not forgotten anything.
This commit is contained in:
handlerug 2021-07-02 15:20:03 +07:00
parent e6265c9ad9
commit b87583ef28
No known key found for this signature in database
GPG Key ID: 38009F0605051491
19 changed files with 211 additions and 335 deletions

View File

@ -11,7 +11,7 @@ HTTPPort = 8080
URL = https://wiki
[Authorization]
UseFixedAuth = true
UseAuth = true
UseRegistration = true
LimitRegistration = 10
AllowRegistration = true
RegistrationLimit = 10

View File

@ -11,7 +11,7 @@ HTTPPort = 1737
URL = http://localhost:1737
[Authorization]
UseFixedAuth = true
UseAuth = true
UseRegistration = true
LimitRegistration = 3
AllowRegistration = true
RegistrationLimit = 3

View File

@ -26,9 +26,9 @@ var (
URL string
GeminiCertificatePath string
UseFixedAuth bool
UseRegistration bool
LimitRegistration int
UseAuth bool
AllowRegistration bool
RegistrationLimit uint64
CommonScripts []string
ViewScripts []string
@ -79,9 +79,9 @@ type CustomScripts struct {
// Authorization is a section of Config that has fields related to
// authorization and authentication.
type Authorization struct {
UseFixedAuth bool
UseRegistration bool
LimitRegistration uint64 `comment:"This field controls the maximum amount of allowed registrations."`
UseAuth bool
AllowRegistration bool
RegistrationLimit uint64 `comment:"This field controls the maximum amount of allowed registrations."`
}
// ReadConfigFile reads a config on the given path and stores the
@ -101,9 +101,9 @@ func ReadConfigFile(path string) error {
GeminiCertificatePath: "",
},
Authorization: Authorization{
UseFixedAuth: false,
UseRegistration: false,
LimitRegistration: 0,
UseAuth: false,
AllowRegistration: false,
RegistrationLimit: 0,
},
CustomScripts: CustomScripts{
CommonScripts: []string{},
@ -164,9 +164,9 @@ func ReadConfigFile(path string) error {
HTTPPort = strconv.FormatUint(cfg.HTTPPort, 10)
URL = cfg.URL
GeminiCertificatePath = cfg.GeminiCertificatePath
UseFixedAuth = cfg.UseFixedAuth
UseRegistration = cfg.UseRegistration
LimitRegistration = int(cfg.LimitRegistration)
UseAuth = cfg.UseAuth
AllowRegistration = cfg.AllowRegistration
RegistrationLimit = cfg.RegistrationLimit
CommonScripts = cfg.CommonScripts
ViewScripts = cfg.ViewScripts
EditScripts = cfg.EditScripts

View File

@ -9,13 +9,12 @@ import (
)
var paths struct {
gitRepo string
cacheDir string
staticFiles string
configPath string
tokensJSON string
registrationCredentialsJSON string
fixedCredentialsJSON string
gitRepo string
cacheDir string
staticFiles string
configPath string
tokensJSON string
userCredentialsJSON string
}
// HyphaeDir returns the path to hyphae storage.
@ -36,12 +35,8 @@ func ConfigPath() string { return paths.configPath }
// TokensJSON returns the path to the JSON user tokens storage.
func TokensJSON() string { return paths.tokensJSON }
// RegistrationCredentialsJSON returns the path to the JSON registration
// credentials storage.
func RegistrationCredentialsJSON() string { return paths.registrationCredentialsJSON }
// FixedCredentialsJSON returns the path to the JSON fixed credentials storage.
func FixedCredentialsJSON() string { return paths.fixedCredentialsJSON }
// UserCredentialsJSON returns the path to the JSON user credentials storage.
func UserCredentialsJSON() string { return paths.userCredentialsJSON }
// PrepareWikiRoot ensures all needed directories and files exist and have
// correct permissions.
@ -66,10 +61,9 @@ func PrepareWikiRoot() error {
}
paths.configPath = filepath.Join(cfg.WikiDir, "config.ini")
paths.userCredentialsJSON = filepath.Join(cfg.WikiDir, "users.json")
paths.tokensJSON = filepath.Join(paths.cacheDir, "tokens.json")
paths.fixedCredentialsJSON = filepath.Join(cfg.WikiDir, "fixed-users.json")
paths.registrationCredentialsJSON = filepath.Join(cfg.WikiDir, "registered-users.json")
return nil
}

View File

@ -1,24 +0,0 @@
[
{
"name": "admin",
"password": "mycorrhiza",
"group": "admin"
},
{
"name": "weird_fish",
"password": "DeepestOcean",
"group": "moderator"
},
{
"name": "king_of_limbs",
"password": "ambush",
"group": "trusted"
},
{
"name": "paranoid_android",
"password": "ok computer",
"group": "editor"
}
]

View File

@ -2,8 +2,7 @@ package user
import (
"encoding/json"
"golang.org/x/crypto/bcrypt"
"io/ioutil"
"errors"
"log"
"os"
@ -12,64 +11,25 @@ import (
"github.com/bouncepaw/mycorrhiza/util"
)
// InitUserDatabase checks the configuration for auth methods and loads users
// if necessary. Call it during initialization.
// InitUserDatabase loads users, if necessary. Call it during initialization.
func InitUserDatabase() {
AuthUsed = cfg.UseFixedAuth || cfg.UseRegistration
if AuthUsed {
ReadUsersFromFilesystem()
}
ReadUsersFromFilesystem()
}
// ReadUsersFromFilesystem reads all user information from filesystem and stores it internally.
// ReadUsersFromFilesystem reads all user information from filesystem and
// stores it internally.
func ReadUsersFromFilesystem() {
if cfg.UseFixedAuth {
// This one will be removed.
rememberUsers(usersFromFixedCredentials())
}
// And this one will be renamed to just "users" in the future.
rememberUsers(usersFromRegistrationCredentials())
// Migrate fixed users to registered
tryToMigrate()
readTokensToUsers()
}
func tryToMigrate() {
// Fixed authorization should be removed by the next release (1.13).
// So let's try to help fixed users and migrate them over!
migrated := 0
for user := range YieldUsers() {
if user.Source == SourceFixed {
hashedPasswd, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost)
if err != nil {
log.Fatal("Failed to migrate fixed users:", err)
}
user.Password = ""
user.HashedPassword = string(hashedPasswd)
user.Source = SourceRegistration
migrated++
}
}
if migrated > 0 {
if err := dumpRegistrationCredentials(); err != nil {
log.Fatal("Failed to migrate fixed users:", err)
}
log.Printf("Migrated %d users", migrated)
if cfg.UseAuth {
rememberUsers(usersFromFile())
readTokensToUsers()
}
}
func usersFromFile(path string, source UserSource) (users []*User) {
contents, err := ioutil.ReadFile(path)
if os.IsNotExist(err) {
return
func usersFromFile() []*User {
var users []*User
contents, err := os.ReadFile(files.UserCredentialsJSON())
if errors.Is(err, os.ErrNotExist) {
return users
}
if err != nil {
log.Fatal(err)
@ -80,20 +40,8 @@ func usersFromFile(path string, source UserSource) (users []*User) {
}
for _, u := range users {
u.Name = util.CanonicalName(u.Name)
u.Source = source
}
return users
}
func usersFromFixedCredentials() []*User {
users := usersFromFile(files.FixedCredentialsJSON(), SourceFixed)
log.Println("Found", len(users), "fixed users")
return users
}
func usersFromRegistrationCredentials() []*User {
users := usersFromFile(files.RegistrationCredentialsJSON(), SourceRegistration)
log.Println("Found", len(users), "registered users")
log.Println("Found", len(users), "users")
return users
}
@ -104,7 +52,7 @@ func rememberUsers(userList []*User) {
}
func readTokensToUsers() {
contents, err := ioutil.ReadFile(files.TokensJSON())
contents, err := os.ReadFile(files.TokensJSON())
if os.IsNotExist(err) {
return
}
@ -119,37 +67,36 @@ func readTokensToUsers() {
}
for token, username := range tmp {
commenceSession(username, token)
tokens.Store(token, username)
// commenceSession(username, token)
}
log.Println("Found", len(tmp), "active sessions")
}
func SaveUserDatabase() error {
return dumpRegistrationCredentials()
return dumpUserCredentials()
}
func dumpRegistrationCredentials() error {
tmp := []*User{}
func dumpUserCredentials() error {
userList := []*User{}
// TODO: lock the map during saving to prevent corruption
for u := range YieldUsers() {
if u.Source != SourceRegistration {
continue
}
copiedUser := u
copiedUser.Password = ""
tmp = append(tmp, copiedUser)
userList = append(userList, u)
}
blob, err := json.MarshalIndent(tmp, "", "\t")
blob, err := json.MarshalIndent(userList, "", "\t")
if err != nil {
log.Println(err)
return err
}
err = ioutil.WriteFile(files.RegistrationCredentialsJSON(), blob, 0644)
err = os.WriteFile(files.UserCredentialsJSON(), blob, 0666)
if err != nil {
log.Println(err)
return err
}
return nil
}
@ -166,7 +113,7 @@ func dumpTokens() {
blob, err := json.MarshalIndent(tmp, "", "\t")
if err != nil {
log.Println(err)
} else {
ioutil.WriteFile(files.TokensJSON(), blob, 0644)
return
}
os.WriteFile(files.TokensJSON(), blob, 0666)
}

View File

@ -1,11 +1,9 @@
package user
import (
"errors"
"fmt"
"log"
"net/http"
"strconv"
"time"
"github.com/bouncepaw/mycorrhiza/cfg"
@ -41,13 +39,12 @@ func Register(username, password string) error {
username = util.CanonicalName(username)
log.Println("Attempt to register user", username)
switch {
case CountRegistered() >= cfg.LimitRegistration && cfg.LimitRegistration > 0:
i := strconv.Itoa(cfg.LimitRegistration)
log.Println("Limit reached: " + i)
return errors.New("Reached the limit of registered users: " + i)
case cfg.RegistrationLimit > 0 && Count() >= cfg.RegistrationLimit:
log.Printf("Limit reached: %d", cfg.RegistrationLimit)
return fmt.Errorf("Reached the limit of registered users: %d", cfg.RegistrationLimit)
case HasUsername(username):
log.Println("Username taken")
return errors.New("Username " + username + " is taken already.")
return fmt.Errorf("Username \"%s\" is taken already.", username)
case !util.IsPossibleUsername(username):
log.Println("Illegal username:", username)
return fmt.Errorf("Illegal username \"%s\".", username)
@ -57,14 +54,13 @@ func Register(username, password string) error {
return err
}
u := User{
Name: username,
Group: "editor",
HashedPassword: string(hash),
RegisteredAt: time.Now(),
Source: SourceRegistration,
Name: username,
Group: "editor",
Password: string(hash),
RegisteredAt: time.Now(),
}
users.Store(username, &u)
err = dumpRegistrationCredentials()
err = SaveUserDatabase()
if err != nil {
return err
}

View File

@ -4,29 +4,17 @@ import (
"sync"
"time"
"github.com/bouncepaw/mycorrhiza/cfg"
"golang.org/x/crypto/bcrypt"
)
// 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"` // for fixed
HashedPassword string `json:"hashed_password"` // for registered
RegisteredAt time.Time `json:"registered_on"`
Source UserSource `json:"-"`
Name string `json:"name"`
Group string `json:"group"`
Password string `json:"hashed_password"`
RegisteredAt time.Time `json:"registered_on"`
sync.RWMutex
// A note about why HashedPassword is string and not []byte. The reason is
@ -86,7 +74,7 @@ func EmptyUser() *User {
}
func (user *User) CanProceed(route string) bool {
if !AuthUsed {
if !cfg.UseAuth {
return true
}
@ -105,12 +93,6 @@ func (user *User) isCorrectPassword(password string) bool {
user.RLock()
defer user.RUnlock()
switch user.Source {
case SourceFixed:
return password == user.Password
case SourceRegistration:
err := bcrypt.CompareHashAndPassword([]byte(user.HashedPassword), []byte(password))
return err == nil
}
return false
err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
return err == nil
}

View File

@ -1,10 +1,7 @@
package user
import (
"sync"
)
import "sync"
var AuthUsed bool
var users sync.Map
var tokens sync.Map
@ -21,28 +18,16 @@ func YieldUsers() chan *User {
}
func ListUsersWithGroup(group string) []string {
usersWithTheGroup := []string{}
filtered := []string{}
for u := range YieldUsers() {
if u.Group == group {
usersWithTheGroup = append(usersWithTheGroup, u.Name)
filtered = append(filtered, u.Name)
}
}
return usersWithTheGroup
return filtered
}
func CountRegistered() int {
i := 0
users.Range(func(k, v interface{}) bool {
if v.(*User).Source == SourceRegistration {
i++
}
return true
})
return i
}
func Count() int {
i := 0
func Count() (i uint64) {
users.Range(func(k, v interface{}) bool {
i++
return true

View File

@ -1,12 +1,11 @@
{% import "net/http" %}
{% import "github.com/bouncepaw/mycorrhiza/user" %}
{% import "github.com/bouncepaw/mycorrhiza/cfg" %}
{% func RegisterHTML(rq *http.Request) %}
<div class="layout">
<main class="main-width">
<section>
{% if cfg.UseRegistration %}
{% if cfg.AllowRegistration %}
<form class="modal" method="post" action="/register?{%s rq.URL.RawQuery %}" id="register-form" enctype="multipart/form-data" autocomplete="off">
<fieldset class="modal__fieldset">
<legend class="modal__title">Register on {%s cfg.WikiName %}</legend>
@ -24,11 +23,11 @@
<a class="btn btn_weak" href="/{%s rq.URL.RawQuery %}">Cancel</a>
</fieldset>
</form>
{% elseif cfg.UseFixedAuth %}
<p>Administrators have forbidden registration for this wiki. Administrators can make an account for you by hand; contact them.</p>
{% elseif cfg.UseAuth %}
<p>Registrations are currently closed. Administrators can make an account for you by hand; contact them.</p>
<p><a href="/{%s rq.URL.RawQuery %}">← Go back</a></p>
{% else %}
<p>Administrators of this wiki have not configured any authorization method. You can make edits anonymously.</p>
<p>Authentication is disabled. You can make edits anonymously.</p>
<p><a href="/{%s rq.URL.RawQuery %}">← Go back</a></p>
{% endif %}
</section>
@ -40,7 +39,7 @@
<div class="layout">
<main class="main-width">
<section>
{% if user.AuthUsed %}
{% if cfg.UseAuth %}
<form class="modal" method="post" action="/login-data" id="login-form" enctype="multipart/form-data" autocomplete="on">
<fieldset class="modal__fieldset">
<legend class="modal__title">Log in to {%s cfg.WikiName %}</legend>
@ -57,7 +56,7 @@
</fieldset>
</form>
{% else %}
<p>Administrators of this wiki have not configured any authorization method. You can make edits anonymously.</p>
<p>Authentication is disabled. You can make edits anonymously.</p>
<p><a class="modal__cancel" href="/">← Go home</a></p>
{% endif %}
</section>

View File

@ -8,46 +8,43 @@ package views
import "net/http"
//line views/auth.qtpl:2
import "github.com/bouncepaw/mycorrhiza/user"
//line views/auth.qtpl:3
import "github.com/bouncepaw/mycorrhiza/cfg"
//line views/auth.qtpl:5
//line views/auth.qtpl:4
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
//line views/auth.qtpl:5
//line views/auth.qtpl:4
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
//line views/auth.qtpl:5
//line views/auth.qtpl:4
func StreamRegisterHTML(qw422016 *qt422016.Writer, rq *http.Request) {
//line views/auth.qtpl:5
//line views/auth.qtpl:4
qw422016.N().S(`
<div class="layout">
<main class="main-width">
<section>
`)
//line views/auth.qtpl:9
if cfg.UseRegistration {
//line views/auth.qtpl:9
//line views/auth.qtpl:8
if cfg.AllowRegistration {
//line views/auth.qtpl:8
qw422016.N().S(`
<form class="modal" method="post" action="/register?`)
//line views/auth.qtpl:10
//line views/auth.qtpl:9
qw422016.E().S(rq.URL.RawQuery)
//line views/auth.qtpl:10
//line views/auth.qtpl:9
qw422016.N().S(`" id="register-form" enctype="multipart/form-data" autocomplete="off">
<fieldset class="modal__fieldset">
<legend class="modal__title">Register on `)
//line views/auth.qtpl:12
//line views/auth.qtpl:11
qw422016.E().S(cfg.WikiName)
//line views/auth.qtpl:12
//line views/auth.qtpl:11
qw422016.N().S(`</legend>
<label for="register-form__username">Username</label>
@ -61,90 +58,90 @@ func StreamRegisterHTML(qw422016 *qt422016.Writer, rq *http.Request) {
<p>By submitting this form you give this wiki a permission to store cookies in your browser. It lets the engine associate your edits with you. You will stay logged in until you log out.</p>
<input class="btn" type="submit" value="Register">
<a class="btn btn_weak" href="/`)
//line views/auth.qtpl:24
//line views/auth.qtpl:23
qw422016.E().S(rq.URL.RawQuery)
//line views/auth.qtpl:24
//line views/auth.qtpl:23
qw422016.N().S(`">Cancel</a>
</fieldset>
</form>
`)
//line views/auth.qtpl:27
} else if cfg.UseFixedAuth {
//line views/auth.qtpl:27
//line views/auth.qtpl:26
} else if cfg.UseAuth {
//line views/auth.qtpl:26
qw422016.N().S(`
<p>Administrators have forbidden registration for this wiki. Administrators can make an account for you by hand; contact them.</p>
<p>Registrations are currently closed. Administrators can make an account for you by hand; contact them.</p>
<p><a href="/`)
//line views/auth.qtpl:29
//line views/auth.qtpl:28
qw422016.E().S(rq.URL.RawQuery)
//line views/auth.qtpl:29
//line views/auth.qtpl:28
qw422016.N().S(`"> Go back</a></p>
`)
//line views/auth.qtpl:30
//line views/auth.qtpl:29
} else {
//line views/auth.qtpl:30
//line views/auth.qtpl:29
qw422016.N().S(`
<p>Administrators of this wiki have not configured any authorization method. You can make edits anonymously.</p>
<p>Authentication is disabled. You can make edits anonymously.</p>
<p><a href="/`)
//line views/auth.qtpl:32
//line views/auth.qtpl:31
qw422016.E().S(rq.URL.RawQuery)
//line views/auth.qtpl:32
//line views/auth.qtpl:31
qw422016.N().S(`"> Go back</a></p>
`)
//line views/auth.qtpl:33
//line views/auth.qtpl:32
}
//line views/auth.qtpl:33
//line views/auth.qtpl:32
qw422016.N().S(`
</section>
</main>
</div>
`)
//line views/auth.qtpl:37
//line views/auth.qtpl:36
}
//line views/auth.qtpl:37
//line views/auth.qtpl:36
func WriteRegisterHTML(qq422016 qtio422016.Writer, rq *http.Request) {
//line views/auth.qtpl:37
//line views/auth.qtpl:36
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/auth.qtpl:37
//line views/auth.qtpl:36
StreamRegisterHTML(qw422016, rq)
//line views/auth.qtpl:37
//line views/auth.qtpl:36
qt422016.ReleaseWriter(qw422016)
//line views/auth.qtpl:37
//line views/auth.qtpl:36
}
//line views/auth.qtpl:37
//line views/auth.qtpl:36
func RegisterHTML(rq *http.Request) string {
//line views/auth.qtpl:37
//line views/auth.qtpl:36
qb422016 := qt422016.AcquireByteBuffer()
//line views/auth.qtpl:37
//line views/auth.qtpl:36
WriteRegisterHTML(qb422016, rq)
//line views/auth.qtpl:37
//line views/auth.qtpl:36
qs422016 := string(qb422016.B)
//line views/auth.qtpl:37
//line views/auth.qtpl:36
qt422016.ReleaseByteBuffer(qb422016)
//line views/auth.qtpl:37
//line views/auth.qtpl:36
return qs422016
//line views/auth.qtpl:37
//line views/auth.qtpl:36
}
//line views/auth.qtpl:39
//line views/auth.qtpl:38
func StreamLoginHTML(qw422016 *qt422016.Writer) {
//line views/auth.qtpl:39
//line views/auth.qtpl:38
qw422016.N().S(`
<div class="layout">
<main class="main-width">
<section>
`)
//line views/auth.qtpl:43
if user.AuthUsed {
//line views/auth.qtpl:43
//line views/auth.qtpl:42
if cfg.UseAuth {
//line views/auth.qtpl:42
qw422016.N().S(`
<form class="modal" method="post" action="/login-data" id="login-form" enctype="multipart/form-data" autocomplete="on">
<fieldset class="modal__fieldset">
<legend class="modal__title">Log in to `)
//line views/auth.qtpl:46
//line views/auth.qtpl:45
qw422016.E().S(cfg.WikiName)
//line views/auth.qtpl:46
//line views/auth.qtpl:45
qw422016.N().S(`</legend>
<label for="login-form__username">Username</label>
<br>
@ -159,177 +156,177 @@ func StreamLoginHTML(qw422016 *qt422016.Writer) {
</fieldset>
</form>
`)
//line views/auth.qtpl:59
//line views/auth.qtpl:58
} else {
//line views/auth.qtpl:59
//line views/auth.qtpl:58
qw422016.N().S(`
<p>Administrators of this wiki have not configured any authorization method. You can make edits anonymously.</p>
<p>Authentication is disabled. You can make edits anonymously.</p>
<p><a class="modal__cancel" href="/"> Go home</a></p>
`)
//line views/auth.qtpl:62
//line views/auth.qtpl:61
}
//line views/auth.qtpl:62
//line views/auth.qtpl:61
qw422016.N().S(`
</section>
</main>
</div>
`)
//line views/auth.qtpl:66
//line views/auth.qtpl:65
}
//line views/auth.qtpl:66
//line views/auth.qtpl:65
func WriteLoginHTML(qq422016 qtio422016.Writer) {
//line views/auth.qtpl:66
//line views/auth.qtpl:65
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/auth.qtpl:66
//line views/auth.qtpl:65
StreamLoginHTML(qw422016)
//line views/auth.qtpl:66
//line views/auth.qtpl:65
qt422016.ReleaseWriter(qw422016)
//line views/auth.qtpl:66
//line views/auth.qtpl:65
}
//line views/auth.qtpl:66
//line views/auth.qtpl:65
func LoginHTML() string {
//line views/auth.qtpl:66
//line views/auth.qtpl:65
qb422016 := qt422016.AcquireByteBuffer()
//line views/auth.qtpl:66
//line views/auth.qtpl:65
WriteLoginHTML(qb422016)
//line views/auth.qtpl:66
//line views/auth.qtpl:65
qs422016 := string(qb422016.B)
//line views/auth.qtpl:66
//line views/auth.qtpl:65
qt422016.ReleaseByteBuffer(qb422016)
//line views/auth.qtpl:66
//line views/auth.qtpl:65
return qs422016
//line views/auth.qtpl:66
//line views/auth.qtpl:65
}
//line views/auth.qtpl:68
//line views/auth.qtpl:67
func StreamLoginErrorHTML(qw422016 *qt422016.Writer, err string) {
//line views/auth.qtpl:68
//line views/auth.qtpl:67
qw422016.N().S(`
<div class="layout">
<main class="main-width">
<section>
`)
//line views/auth.qtpl:72
//line views/auth.qtpl:71
switch err {
//line views/auth.qtpl:73
//line views/auth.qtpl:72
case "unknown username":
//line views/auth.qtpl:73
//line views/auth.qtpl:72
qw422016.N().S(`
<p class="error">Unknown username.</p>
`)
//line views/auth.qtpl:75
//line views/auth.qtpl:74
case "wrong password":
//line views/auth.qtpl:75
//line views/auth.qtpl:74
qw422016.N().S(`
<p class="error">Wrong password.</p>
`)
//line views/auth.qtpl:77
//line views/auth.qtpl:76
default:
//line views/auth.qtpl:77
//line views/auth.qtpl:76
qw422016.N().S(`
<p class="error">`)
//line views/auth.qtpl:78
//line views/auth.qtpl:77
qw422016.E().S(err)
//line views/auth.qtpl:78
//line views/auth.qtpl:77
qw422016.N().S(`</p>
`)
//line views/auth.qtpl:79
//line views/auth.qtpl:78
}
//line views/auth.qtpl:79
//line views/auth.qtpl:78
qw422016.N().S(`
<p><a href="/login"> Try again</a></p>
</section>
</main>
</div>
`)
//line views/auth.qtpl:84
//line views/auth.qtpl:83
}
//line views/auth.qtpl:84
//line views/auth.qtpl:83
func WriteLoginErrorHTML(qq422016 qtio422016.Writer, err string) {
//line views/auth.qtpl:84
//line views/auth.qtpl:83
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/auth.qtpl:84
//line views/auth.qtpl:83
StreamLoginErrorHTML(qw422016, err)
//line views/auth.qtpl:84
//line views/auth.qtpl:83
qt422016.ReleaseWriter(qw422016)
//line views/auth.qtpl:84
//line views/auth.qtpl:83
}
//line views/auth.qtpl:84
//line views/auth.qtpl:83
func LoginErrorHTML(err string) string {
//line views/auth.qtpl:84
//line views/auth.qtpl:83
qb422016 := qt422016.AcquireByteBuffer()
//line views/auth.qtpl:84
//line views/auth.qtpl:83
WriteLoginErrorHTML(qb422016, err)
//line views/auth.qtpl:84
//line views/auth.qtpl:83
qs422016 := string(qb422016.B)
//line views/auth.qtpl:84
//line views/auth.qtpl:83
qt422016.ReleaseByteBuffer(qb422016)
//line views/auth.qtpl:84
//line views/auth.qtpl:83
return qs422016
//line views/auth.qtpl:84
//line views/auth.qtpl:83
}
//line views/auth.qtpl:86
//line views/auth.qtpl:85
func StreamLogoutHTML(qw422016 *qt422016.Writer, can bool) {
//line views/auth.qtpl:86
//line views/auth.qtpl:85
qw422016.N().S(`
<div class="layout">
<main class="main-width">
<section>
`)
//line views/auth.qtpl:90
//line views/auth.qtpl:89
if can {
//line views/auth.qtpl:90
//line views/auth.qtpl:89
qw422016.N().S(`
<h1>Log out?</h1>
<p><a href="/logout-confirm"><strong>Confirm</strong></a></p>
<p><a href="/">Cancel</a></p>
`)
//line views/auth.qtpl:94
//line views/auth.qtpl:93
} else {
//line views/auth.qtpl:94
//line views/auth.qtpl:93
qw422016.N().S(`
<p>You cannot log out because you are not logged in.</p>
<p><a href="/login">Login</a></p>
<p><a href="/login"> Home</a></p>
`)
//line views/auth.qtpl:98
//line views/auth.qtpl:97
}
//line views/auth.qtpl:98
//line views/auth.qtpl:97
qw422016.N().S(`
</section>
</main>
</div>
`)
//line views/auth.qtpl:102
//line views/auth.qtpl:101
}
//line views/auth.qtpl:102
//line views/auth.qtpl:101
func WriteLogoutHTML(qq422016 qtio422016.Writer, can bool) {
//line views/auth.qtpl:102
//line views/auth.qtpl:101
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/auth.qtpl:102
//line views/auth.qtpl:101
StreamLogoutHTML(qw422016, can)
//line views/auth.qtpl:102
//line views/auth.qtpl:101
qt422016.ReleaseWriter(qw422016)
//line views/auth.qtpl:102
//line views/auth.qtpl:101
}
//line views/auth.qtpl:102
//line views/auth.qtpl:101
func LogoutHTML(can bool) string {
//line views/auth.qtpl:102
//line views/auth.qtpl:101
qb422016 := qt422016.AcquireByteBuffer()
//line views/auth.qtpl:102
//line views/auth.qtpl:101
WriteLogoutHTML(qb422016, can)
//line views/auth.qtpl:102
//line views/auth.qtpl:101
qs422016 := string(qb422016.B)
//line views/auth.qtpl:102
//line views/auth.qtpl:101
qt422016.ReleaseByteBuffer(qb422016)
//line views/auth.qtpl:102
//line views/auth.qtpl:101
return qs422016
//line views/auth.qtpl:102
//line views/auth.qtpl:101
}

View File

@ -9,11 +9,11 @@
{% func nonExistentHyphaNotice(h *hyphae.Hypha, u *user.User) %}
<section class="non-existent-hypha">
<h2 class="non-existent-hypha__title">This hypha does not exist</h2>
{% if user.AuthUsed && u.Group == "anon" %}
{% if cfg.UseAuth && u.Group == "anon" %}
<p>You are not authorized to create new hyphae. Here is what you can do:</p>
<ul>
<li><a href="/login">Log in to your account, if you have one</a></li>
{% if cfg.UseRegistration %}<li><a href="/register">Register a new account</a></li>{% endif %}
{% if cfg.AllowRegistration %}<li><a href="/register">Register a new account</a></li>{% endif %}
</ul>
{% else %}

View File

@ -43,7 +43,7 @@ func streamnonExistentHyphaNotice(qw422016 *qt422016.Writer, h *hyphae.Hypha, u
<h2 class="non-existent-hypha__title">This hypha does not exist</h2>
`)
//line views/hypha.qtpl:12
if user.AuthUsed && u.Group == "anon" {
if cfg.UseAuth && u.Group == "anon" {
//line views/hypha.qtpl:12
qw422016.N().S(`
<p>You are not authorized to create new hyphae. Here is what you can do:</p>
@ -51,7 +51,7 @@ func streamnonExistentHyphaNotice(qw422016 *qt422016.Writer, h *hyphae.Hypha, u
<li><a href="/login">Log in to your account, if you have one</a></li>
`)
//line views/hypha.qtpl:16
if cfg.UseRegistration {
if cfg.AllowRegistration {
//line views/hypha.qtpl:16
qw422016.N().S(`<li><a href="/register">Register a new account</a></li>`)
//line views/hypha.qtpl:16

View File

@ -48,7 +48,7 @@ var navEntries = []navEntry{
{% endfunc %}
{% func UserMenuHTML(u *user.User) %}
{% if user.AuthUsed %}
{% if cfg.UseAuth %}
<li class="header-links__entry header-links__entry_user">
{% if u.Group == "anon" %}
<a href="/login" class="header-links__link">Login</a>
@ -57,7 +57,7 @@ var navEntries = []navEntry{
{% endif %}
</li>
{% endif %}
{% if user.AuthUsed && cfg.UseRegistration && u.Group == "anon" %}
{% if cfg.UseAuth && cfg.AllowRegistration && u.Group == "anon" %}
<li class="header-links__entry header-links__entry_register">
<a href="/register" class="header-links__link">Register</a>
</li>

View File

@ -150,7 +150,7 @@ func StreamUserMenuHTML(qw422016 *qt422016.Writer, u *user.User) {
qw422016.N().S(`
`)
//line views/nav.qtpl:51
if user.AuthUsed {
if cfg.UseAuth {
//line views/nav.qtpl:51
qw422016.N().S(`
<li class="header-links__entry header-links__entry_user">
@ -191,7 +191,7 @@ func StreamUserMenuHTML(qw422016 *qt422016.Writer, u *user.User) {
qw422016.N().S(`
`)
//line views/nav.qtpl:60
if user.AuthUsed && cfg.UseRegistration && u.Group == "anon" {
if cfg.UseAuth && cfg.AllowRegistration && u.Group == "anon" {
//line views/nav.qtpl:60
qw422016.N().S(`
<li class="header-links__entry header-links__entry_register">

View File

@ -113,8 +113,8 @@ for u := range user.YieldUsers() {
<h1>About {%s cfg.WikiName %}</h1>
<ul>
<li><b><a href="https://mycorrhiza.lesarbr.es">Mycorrhiza Wiki</a> version:</b> 1.3.0</li>
{%- if user.AuthUsed -%}
<li><b>User count:</b> {%d user.Count() %}</li>
{%- if cfg.UseAuth -%}
<li><b>User count:</b> {%dul user.Count() %}</li>
<li><b>Home page:</b> <a href="/">{%s cfg.HomeHypha %}</a></li>
<li><b>Administrators:</b> {%- for i, username := range user.ListUsersWithGroup("admin") -%}
{%- if i > 0 -%}<span aria-hidden="true">, </span>

View File

@ -376,11 +376,11 @@ func StreamAboutHTML(qw422016 *qt422016.Writer) {
<li><b><a href="https://mycorrhiza.lesarbr.es">Mycorrhiza Wiki</a> version:</b> 1.3.0</li>
`)
//line views/stuff.qtpl:116
if user.AuthUsed {
if cfg.UseAuth {
//line views/stuff.qtpl:116
qw422016.N().S(` <li><b>User count:</b> `)
//line views/stuff.qtpl:117
qw422016.N().D(user.Count())
qw422016.N().DUL(user.Count())
//line views/stuff.qtpl:117
qw422016.N().S(`</li>
<li><b>Home page:</b> <a href="/">`)

View File

@ -17,7 +17,7 @@ import (
// initAdmin sets up /admin routes if auth is used. Call it after you have decided if you want to use auth.
func initAdmin() {
if user.AuthUsed {
if cfg.UseAuth {
http.HandleFunc("/admin/", handlerAdmin)
http.HandleFunc("/admin/shutdown/", handlerAdminShutdown)
http.HandleFunc("/admin/reindex-users/", handlerAdminReindexUsers)

View File

@ -14,10 +14,10 @@ import (
)
func initAuth() {
if !user.AuthUsed {
if !cfg.UseAuth {
return
}
if cfg.UseRegistration {
if cfg.AllowRegistration {
http.HandleFunc("/register", handlerRegister)
}
http.HandleFunc("/login", handlerLogin)
@ -29,7 +29,7 @@ func initAuth() {
// handlerRegister both displays the register form (GET) and registers users (POST).
func handlerRegister(w http.ResponseWriter, rq *http.Request) {
util.PrepareRq(rq)
if !cfg.UseRegistration {
if !cfg.AllowRegistration {
w.WriteHeader(http.StatusForbidden)
}
if rq.Method == http.MethodGet {
@ -97,7 +97,7 @@ func handlerLogoutConfirm(w http.ResponseWriter, rq *http.Request) {
func handlerLogin(w http.ResponseWriter, rq *http.Request) {
util.PrepareRq(rq)
w.Header().Set("Content-Type", "text/html;charset=utf-8")
if user.AuthUsed {
if cfg.UseAuth {
w.WriteHeader(http.StatusOK)
} else {
w.WriteHeader(http.StatusForbidden)