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:
parent
e6265c9ad9
commit
b87583ef28
@ -11,7 +11,7 @@ HTTPPort = 8080
|
||||
URL = https://wiki
|
||||
|
||||
[Authorization]
|
||||
UseFixedAuth = true
|
||||
UseAuth = true
|
||||
|
||||
UseRegistration = true
|
||||
LimitRegistration = 10
|
||||
AllowRegistration = true
|
||||
RegistrationLimit = 10
|
||||
|
@ -11,7 +11,7 @@ HTTPPort = 1737
|
||||
URL = http://localhost:1737
|
||||
|
||||
[Authorization]
|
||||
UseFixedAuth = true
|
||||
UseAuth = true
|
||||
|
||||
UseRegistration = true
|
||||
LimitRegistration = 3
|
||||
AllowRegistration = true
|
||||
RegistrationLimit = 3
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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"
|
||||
}
|
||||
]
|
||||
|
||||
|
109
user/files.go
109
user/files.go
@ -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)
|
||||
}
|
||||
|
22
user/net.go
22
user/net.go
@ -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
|
||||
}
|
||||
|
34
user/user.go
34
user/user.go
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 %}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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">
|
||||
|
@ -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>
|
||||
|
@ -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="/">`)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user