108 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			108 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Go
		
	
	
	
package auth
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/json"
 | 
						|
	"net/http"
 | 
						|
	"net/url"
 | 
						|
	"os"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"github.com/filebrowser/filebrowser/v2/settings"
 | 
						|
	"github.com/filebrowser/filebrowser/v2/users"
 | 
						|
)
 | 
						|
 | 
						|
// MethodJSONAuth is used to identify json auth.
 | 
						|
const MethodJSONAuth settings.AuthMethod = "json"
 | 
						|
 | 
						|
type jsonCred struct {
 | 
						|
	Password  string `json:"password"`
 | 
						|
	Username  string `json:"username"`
 | 
						|
	ReCaptcha string `json:"recaptcha"`
 | 
						|
}
 | 
						|
 | 
						|
// JSONAuth is a json implementaion of an Auther.
 | 
						|
type JSONAuth struct {
 | 
						|
	ReCaptcha *ReCaptcha `json:"recaptcha" yaml:"recaptcha"`
 | 
						|
}
 | 
						|
 | 
						|
// Auth authenticates the user via a json in content body.
 | 
						|
func (a JSONAuth) Auth(r *http.Request, sto *users.Storage, root string) (*users.User, error) {
 | 
						|
	var cred jsonCred
 | 
						|
 | 
						|
	if r.Body == nil {
 | 
						|
		return nil, os.ErrPermission
 | 
						|
	}
 | 
						|
 | 
						|
	err := json.NewDecoder(r.Body).Decode(&cred)
 | 
						|
	if err != nil {
 | 
						|
		return nil, os.ErrPermission
 | 
						|
	}
 | 
						|
 | 
						|
	// If ReCaptcha is enabled, check the code.
 | 
						|
	if a.ReCaptcha != nil && len(a.ReCaptcha.Secret) > 0 {
 | 
						|
		ok, err := a.ReCaptcha.Ok(cred.ReCaptcha)
 | 
						|
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		if !ok {
 | 
						|
			return nil, os.ErrPermission
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	u, err := sto.Get(root, cred.Username)
 | 
						|
	if err != nil || !users.CheckPwd(cred.Password, u.Password) {
 | 
						|
		return nil, os.ErrPermission
 | 
						|
	}
 | 
						|
 | 
						|
	return u, nil
 | 
						|
}
 | 
						|
 | 
						|
// LoginPage tells that json auth doesn't require a login page.
 | 
						|
func (a JSONAuth) LoginPage() bool {
 | 
						|
	return true
 | 
						|
}
 | 
						|
 | 
						|
const reCaptchaAPI = "/recaptcha/api/siteverify"
 | 
						|
 | 
						|
// ReCaptcha identifies a recaptcha conenction.
 | 
						|
type ReCaptcha struct {
 | 
						|
	Host   string `json:"host"`
 | 
						|
	Key    string `json:"key"`
 | 
						|
	Secret string `json:"secret"`
 | 
						|
}
 | 
						|
 | 
						|
// Ok checks if a reCaptcha responde is correct.
 | 
						|
func (r *ReCaptcha) Ok(response string) (bool, error) {
 | 
						|
	body := url.Values{}
 | 
						|
	body.Set("secret", r.Secret)
 | 
						|
	body.Add("response", response)
 | 
						|
 | 
						|
	client := &http.Client{}
 | 
						|
 | 
						|
	resp, err := client.Post(
 | 
						|
		r.Host+reCaptchaAPI,
 | 
						|
		"application/x-www-form-urlencoded",
 | 
						|
		strings.NewReader(body.Encode()),
 | 
						|
	)
 | 
						|
	if err != nil {
 | 
						|
		return false, err
 | 
						|
	}
 | 
						|
 | 
						|
	if resp.StatusCode != http.StatusOK {
 | 
						|
		return false, nil
 | 
						|
	}
 | 
						|
 | 
						|
	var data struct {
 | 
						|
		Success bool `json:"success"`
 | 
						|
	}
 | 
						|
 | 
						|
	err = json.NewDecoder(resp.Body).Decode(&data)
 | 
						|
	if err != nil {
 | 
						|
		return false, err
 | 
						|
	}
 | 
						|
 | 
						|
	return data.Success, nil
 | 
						|
}
 |