mirror of
https://github.com/tinode/chat.git
synced 2026-06-06 20:18:25 +00:00
110 lines
3.2 KiB
Go
110 lines
3.2 KiB
Go
// Package tel is an incomplete implementation of SMS or voice credential validator.
|
|
package tel
|
|
|
|
import (
|
|
"github.com/nyaruka/phonenumbers"
|
|
"github.com/tinode/chat/server/store"
|
|
t "github.com/tinode/chat/server/store/types"
|
|
)
|
|
|
|
const validatorName = "tel"
|
|
|
|
// Empty placeholder struct.
|
|
type validator struct {
|
|
DebugResponse string `json:"debug_response"`
|
|
MaxRetries int `json:"max_retries"`
|
|
}
|
|
|
|
// Init is a noop.
|
|
func (v *validator) Init(jsonconf string) error {
|
|
// Implement: Parse config and initialize SMS service.
|
|
|
|
v.MaxRetries = 1000
|
|
v.DebugResponse = "123456"
|
|
|
|
return nil
|
|
}
|
|
|
|
// PreCheck validates the credential and parameters without sending an SMS or making the call.
|
|
// If credential is valid it's formatted and prefixed with a tag namespace.
|
|
func (*validator) PreCheck(cred string, params map[string]interface{}) (string, error) {
|
|
countryCode, ok := params["countryCode"].(string)
|
|
if !ok {
|
|
countryCode = "US"
|
|
}
|
|
|
|
// Libphonenumber is broken by design: Parse will try to extract the number from any text.
|
|
if phonenumbers.VALID_PHONE_NUMBER_PATTERN.MatchString(cred) {
|
|
if num, err := phonenumbers.Parse(cred, countryCode); err == nil {
|
|
// It's a phone number. Not checking the length because phone numbers cannot be that long.
|
|
if phonenumbers.IsValidNumber(num) {
|
|
return validatorName + ":" + phonenumbers.Format(num, phonenumbers.E164), nil
|
|
}
|
|
}
|
|
}
|
|
return "", t.ErrMalformed
|
|
}
|
|
|
|
// Request sends a request for confirmation to the user: makes a record in DB and nothing else.
|
|
func (*validator) Request(user t.Uid, cred, lang, resp string, tmpToken []byte) (bool, error) {
|
|
// TODO: actually send a validation SMS or make a call to the provided `cred` here.
|
|
return true, nil
|
|
}
|
|
|
|
// ResetSecret sends a message with instructions for resetting an authentication secret.
|
|
func (*validator) ResetSecret(cred, scheme, lang string, tmpToken []byte, params map[string]interface{}) error {
|
|
// TODO: send SMS with rest instructions.
|
|
return nil
|
|
}
|
|
|
|
// Check checks validity of user's response.
|
|
func (v *validator) Check(user t.Uid, resp string) (string, error) {
|
|
cred, err := store.Users.GetActiveCred(user, validatorName)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if cred == nil {
|
|
// Request to validate non-existent credential.
|
|
return "", t.ErrNotFound
|
|
}
|
|
|
|
if cred.Retries > v.MaxRetries {
|
|
return "", t.ErrPolicy
|
|
}
|
|
|
|
if resp == "" {
|
|
return "", t.ErrCredentials
|
|
}
|
|
|
|
// Comparing with dummy response too.
|
|
if cred.Resp == resp || v.DebugResponse == resp {
|
|
// Valid response, save confirmation.
|
|
return cred.Value, store.Users.ConfirmCred(user, validatorName)
|
|
}
|
|
|
|
// Invalid response, increment fail counter, ignore possible error.
|
|
store.Users.FailCred(user, validatorName)
|
|
|
|
return "", t.ErrCredentials
|
|
}
|
|
|
|
// Delete deletes user's records. Returns deleted credentials.
|
|
func (*validator) Delete(user t.Uid) error {
|
|
return store.Users.DelCred(user, validatorName, "")
|
|
}
|
|
|
|
// Remove or disable the given record
|
|
func (*validator) Remove(user t.Uid, value string) error {
|
|
return store.Users.DelCred(user, validatorName, value)
|
|
}
|
|
|
|
// Implement sending a text message
|
|
func (*validator) send(to, body string) error {
|
|
return nil
|
|
}
|
|
|
|
func init() {
|
|
store.RegisterValidator(validatorName, &validator{})
|
|
}
|