github.com/e154/smart-home@v0.17.2-0.20240311175135-e530a6e5cd45/system/mqtt_authenticator/mqtt_authenticator.go (about)

     1  // This file is part of the Smart Home
     2  // Program complex distribution https://github.com/e154/smart-home
     3  // Copyright (C) 2016-2023, Filippov Alex
     4  //
     5  // This library is free software: you can redistribute it and/or
     6  // modify it under the terms of the GNU Lesser General Public
     7  // License as published by the Free Software Foundation; either
     8  // version 3 of the License, or (at your option) any later version.
     9  //
    10  // This library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13  // Library General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public
    16  // License along with this library.  If not, see
    17  // <https://www.gnu.org/licenses/>.
    18  
    19  package mqtt_authenticator
    20  
    21  import (
    22  	"context"
    23  	"fmt"
    24  	"reflect"
    25  	"sync"
    26  	"time"
    27  
    28  	"github.com/pkg/errors"
    29  
    30  	"github.com/e154/smart-home/adaptors"
    31  	"github.com/e154/smart-home/common/apperr"
    32  	"github.com/e154/smart-home/common/logger"
    33  	m "github.com/e154/smart-home/models"
    34  	"github.com/e154/smart-home/system/cache"
    35  )
    36  
    37  var (
    38  	log = logger.MustGetLogger("mqtt_authenticator")
    39  )
    40  
    41  // MqttAuthenticator ...
    42  type MqttAuthenticator interface {
    43  	Authenticate(login string, pass interface{}) (err error)
    44  	//DEPRECATED
    45  	Register(fn func(login, password string) (err error)) (err error)
    46  	//DEPRECATED
    47  	Unregister(fn func(login, password string) (err error)) (err error)
    48  }
    49  
    50  // Authenticator ...
    51  type Authenticator struct {
    52  	adaptors  *adaptors.Adaptors
    53  	cache     cache.Cache
    54  	handlerMu *sync.Mutex
    55  	handlers  []reflect.Value
    56  }
    57  
    58  // NewAuthenticator ...
    59  func NewAuthenticator(adaptors *adaptors.Adaptors) MqttAuthenticator {
    60  	bm, _ := cache.NewCache("memory", `{"interval":60}`)
    61  	return &Authenticator{
    62  		adaptors:  adaptors,
    63  		cache:     bm,
    64  		handlerMu: &sync.Mutex{},
    65  	}
    66  }
    67  
    68  // Authenticate ...
    69  func (a *Authenticator) Authenticate(login string, pass interface{}) (err error) {
    70  
    71  	log.Infof("login: \"%v\", pass: \"%v\"", login, pass)
    72  
    73  	password, ok := pass.(string)
    74  	if !ok || password == "" {
    75  		err = apperr.ErrBadLoginOrPassword
    76  	}
    77  
    78  	var value interface{}
    79  	if value, err = a.cache.Get(context.Background(), login); value != nil {
    80  		if password == pass.(string) {
    81  			return
    82  		}
    83  	}
    84  
    85  	defer func() {
    86  		if err == nil {
    87  			_ = a.cache.Put(context.Background(), login, pass, 60*time.Second)
    88  		}
    89  	}()
    90  
    91  	for _, v := range a.handlers {
    92  		result := v.Call([]reflect.Value{reflect.ValueOf(login), reflect.ValueOf(pass)})
    93  		if result[0].Interface() != nil {
    94  			if err, ok = result[0].Interface().(error); !ok {
    95  				err = nil
    96  				return
    97  			}
    98  		} else {
    99  			err = nil
   100  			return
   101  		}
   102  	}
   103  
   104  	var user *m.User
   105  	if user, err = a.adaptors.User.GetByNickname(context.Background(), login); err != nil {
   106  		err = errors.Wrap(apperr.ErrUnauthorized, fmt.Sprintf("email %s", login))
   107  		return
   108  	} else if !user.CheckPass(password) {
   109  		err = apperr.ErrPassNotValid
   110  		return
   111  	} else if user.Status == "blocked" {
   112  		err = apperr.ErrAccountIsBlocked
   113  		return
   114  	}
   115  
   116  	return
   117  }
   118  
   119  // Register ...
   120  func (a *Authenticator) Register(fn func(login, password string) (err error)) (err error) {
   121  	if reflect.TypeOf(fn).Kind() != reflect.Func {
   122  		err = errors.Wrap(apperr.ErrInternal, fmt.Sprintf("%s is not a reflect.Func", reflect.TypeOf(fn)))
   123  	}
   124  
   125  	a.handlerMu.Lock()
   126  	defer a.handlerMu.Unlock()
   127  
   128  	rv := reflect.ValueOf(fn)
   129  
   130  	for _, v := range a.handlers {
   131  		if v == rv || v.Pointer() == rv.Pointer() {
   132  			return
   133  		}
   134  	}
   135  
   136  	a.handlers = append(a.handlers, rv)
   137  
   138  	log.Infof("register ...")
   139  
   140  	return
   141  }
   142  
   143  // Unregister ...
   144  func (a *Authenticator) Unregister(fn func(login, password string) (err error)) (err error) {
   145  	a.handlerMu.Lock()
   146  	defer a.handlerMu.Unlock()
   147  
   148  	rv := reflect.ValueOf(fn)
   149  
   150  	var indexesToDelete []int
   151  
   152  	for i, v := range a.handlers {
   153  		if v == rv || v.Pointer() == rv.Pointer() {
   154  			indexesToDelete = append(indexesToDelete, i)
   155  		}
   156  	}
   157  
   158  	for i := len(indexesToDelete) - 1; i >= 0; i-- {
   159  		index := indexesToDelete[i]
   160  		a.handlers = append(a.handlers[:index], a.handlers[index+1:]...)
   161  	}
   162  
   163  	log.Infof("unregister ...")
   164  
   165  	return
   166  }