aboutsummaryrefslogblamecommitdiff
path: root/invite.go
blob: d078642d0a78aa487a5642dbcac32601e0379f41 (plain) (tree)















































































































































                                                                                                                                    
package main

import (
	"fmt"
	"html/template"
	"net/http"
	"regexp"
	"strings"

	"github.com/go-ldap/ldap/v3"
)

func checkInviterLogin(w http.ResponseWriter, r *http.Request) *LoginStatus {
	login := checkLogin(w, r)
	if login == nil {
		return nil
	}

	if !login.CanInvite {
		http.Error(w, "Not authorized to invite new users.", http.StatusUnauthorized)
		return nil
	}

	return login
}

type NewAccountData struct {
	Username    string
	DisplayName string
	GivenName   string
	Surname     string

	ErrorUsernameTaken    bool
	ErrorInvalidUsername  bool
	ErrorPasswordTooShort bool
	ErrorPasswordMismatch bool
	ErrorMessage          string
	WarningMessage        string
	Success               bool
}

func handleInviteNewAccount(w http.ResponseWriter, r *http.Request) {
	templateInviteNewAccount := template.Must(template.ParseFiles("templates/layout.html", "templates/invite_new_account.html"))

	login := checkInviterLogin(w, r)
	if login == nil {
		return
	}

	data := &NewAccountData{}

	if r.Method == "POST" {
		r.ParseForm()

		data.Username = strings.TrimSpace(strings.Join(r.Form["username"], ""))
		data.DisplayName = strings.TrimSpace(strings.Join(r.Form["displayname"], ""))
		data.GivenName = strings.TrimSpace(strings.Join(r.Form["givenname"], ""))
		data.Surname = strings.TrimSpace(strings.Join(r.Form["surname"], ""))

		password1 := strings.Join(r.Form["password"], "")
		password2 := strings.Join(r.Form["password2"], "")

		tryCreateAccount(login.conn, data, password1, password2)
	}

	templateInviteNewAccount.Execute(w, data)
}

func tryCreateAccount(l *ldap.Conn, data *NewAccountData, pass1 string, pass2 string) {
	// Check if username is correct
	if match, err := regexp.MatchString("^[a-zA-Z0-9._-]+$", data.Username); !(err == nil && match) {
		data.ErrorInvalidUsername = true
	}

	// Check if user exists
	userDn := config.UserNameAttr + "=" + data.Username + "," + config.UserBaseDN
	searchRq := ldap.NewSearchRequest(
		userDn,
		ldap.ScopeBaseObject, ldap.NeverDerefAliases, 0, 0, false,
		"(objectclass=*)",
		[]string{"dn"},
		nil)

	sr, err := l.Search(searchRq)
	if err != nil {
		data.ErrorMessage = err.Error()
		return
	}

	if len(sr.Entries) > 0 {
		data.ErrorUsernameTaken = true
		return
	}

	// Check that password is long enough
	if len(pass1) < 8 {
		data.ErrorPasswordTooShort = true
		return
	}

	if pass1 != pass2 {
		data.ErrorPasswordMismatch = true
		return
	}

	// Actually create user
	req := ldap.NewAddRequest(userDn, nil)
	req.Attribute("objectclass", []string{"inetOrgPerson", "organizationalPerson", "person", "top"})
	req.Attribute("structuralobjectclass", []string{"inetOrgPerson"})
	req.Attribute("userpassword", []string{SSHAEncode([]byte(pass1))})
	if len(data.DisplayName) > 0 {
		req.Attribute("displayname", []string{data.DisplayName})
	}
	if len(data.GivenName) > 0 {
		req.Attribute("givenname", []string{data.GivenName})
	}
	if len(data.Surname) > 0 {
		req.Attribute("sn", []string{data.Surname})
	}
	if len(config.InvitedMailFormat) > 0 {
		email := strings.ReplaceAll(config.InvitedMailFormat, "{}", data.Username)
		req.Attribute("mail", []string{email})
	}

	err = l.Add(req)
	if err != nil {
		data.ErrorMessage = err.Error()
		return
	}

	for _, group := range config.InvitedAutoGroups {
		req := ldap.NewModifyRequest(group, nil)
		req.Add("member", []string{userDn})
		err = l.Modify(req)
		if err != nil {
			data.WarningMessage += fmt.Sprintf("Cannot add to %s: %s\n", group, err.Error())
		}
	}

	data.Success = true
}

func handleInviteSendCode(w http.ResponseWriter, r *http.Request) {
}