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 }