109 lines
		
	
	
		
			2.2 KiB
		
	
	
	
		
			Go
		
	
	
			
		
		
	
	
			109 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 implementation 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.Store, 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) //nolint:govet
 | |
| 
 | |
| 		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 connection.
 | |
| 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
 | |
| 	}
 | |
| 	defer resp.Body.Close()
 | |
| 
 | |
| 	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
 | |
| }
 |