Merge branch 'master' into lash/purify-max

This commit is contained in:
lash 2025-01-09 13:48:39 +00:00
commit bcf1965a6c
19 changed files with 324 additions and 108 deletions

View File

@ -75,7 +75,7 @@ func main() {
if connStr != "" {
connStr = config.DbConn
}
connData, err := storage.ToConnData(config.DbConn)
connData, err := storage.ToConnData(connStr)
if err != nil {
fmt.Fprintf(os.Stderr, "connstr err: %v", err)
os.Exit(1)

View File

@ -62,7 +62,7 @@ func main() {
if connStr != "" {
connStr = config.DbConn
}
connData, err := storage.ToConnData(config.DbConn)
connData, err := storage.ToConnData(connStr)
if err != nil {
fmt.Fprintf(os.Stderr, "connstr err: %v", err)
os.Exit(1)

View File

@ -55,7 +55,7 @@ func main() {
if connStr != "" {
connStr = config.DbConn
}
connData, err := storage.ToConnData(config.DbConn)
connData, err := storage.ToConnData(connStr)
if err != nil {
fmt.Fprintf(os.Stderr, "connstr err: %v", err)
os.Exit(1)

View File

@ -37,7 +37,7 @@ func main() {
config.LoadConfig()
var connStr string
var dbDir string
var authConnStr string
var resourceDir string
var size uint
var engineDebug bool
@ -45,6 +45,7 @@ func main() {
var host string
var port uint
flag.StringVar(&connStr, "c", "", "connection string")
flag.StringVar(&authConnStr, "authdb", "", "auth connection string")
flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir")
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
flag.UintVar(&size, "s", 160, "max size of output")
@ -52,14 +53,22 @@ func main() {
flag.UintVar(&port, "p", 7122, "socket port")
flag.Parse()
if connStr != "" {
if connStr == "" {
connStr = config.DbConn
}
connData, err := storage.ToConnData(config.DbConn)
if authConnStr == "" {
authConnStr = connStr
}
connData, err := storage.ToConnData(connStr)
if err != nil {
fmt.Fprintf(os.Stderr, "connstr err: %v", err)
os.Exit(1)
}
authConnData, err := storage.ToConnData(authConnStr)
if err != nil {
fmt.Fprintf(os.Stderr, "auth connstr err: %v", err)
os.Exit(1)
}
sshKeyFile := flag.Arg(0)
_, err = os.Stat(sshKeyFile)
@ -75,7 +84,7 @@ func main() {
logg.WarnCtxf(ctx, "!!!!! Do not expose to internet and only use with tunnel!")
logg.WarnCtxf(ctx, "!!!!! (See ssh -L <...>)")
logg.Infof("start command", "dbdir", dbDir, "resourcedir", resourceDir, "outputsize", size, "keyfile", sshKeyFile, "host", host, "port", port)
logg.Infof("start command", "conn", connData, "authconn", authConnData, "resourcedir", resourceDir, "outputsize", size, "keyfile", sshKeyFile, "host", host, "port", port)
pfp := path.Join(scriptDir, "pp.csv")
@ -91,7 +100,7 @@ func main() {
cfg.EngineDebug = true
}
authKeyStore, err := ssh.NewSshKeyStore(ctx, dbDir)
authKeyStore, err := ssh.NewSshKeyStore(ctx, authConnData.String())
if err != nil {
fmt.Fprintf(os.Stderr, "keystore file open error: %v", err)
os.Exit(1)

View File

@ -55,6 +55,8 @@ const (
DATA_ACTIVE_DECIMAL
// EVM address of the currently active voucher
DATA_ACTIVE_ADDRESS
//Holds count of the number of incorrect PIN attempts
DATA_INCORRECT_PIN_ATTEMPTS
)
const (

View File

@ -6,9 +6,13 @@ import (
"golang.org/x/crypto/bcrypt"
)
// Define the regex pattern as a constant
const (
// Define the regex pattern as a constant
pinPattern = `^\d{4}$`
//Allowed incorrect PIN attempts
AllowedPINAttempts = uint8(3)
)
// checks whether the given input is a 4 digit number

View File

@ -9,7 +9,7 @@ import (
"git.grassecon.net/urdt/ussd/request"
"git.grassecon.net/urdt/ussd/errors"
"git.grassecon.net/urdt/ussd/internal/handlers/ussd"
"git.grassecon.net/urdt/ussd/internal/handlers/application"
"git.grassecon.net/urdt/ussd/internal/storage"
)
@ -21,11 +21,11 @@ type BaseSessionHandler struct {
cfgTemplate engine.Config
rp request.RequestParser
rs resource.Resource
hn *ussd.Handlers
hn *application.Handlers
provider storage.StorageProvider
}
func NewBaseSessionHandler(cfg engine.Config, rs resource.Resource, stateDb db.Db, userdataDb db.Db, rp request.RequestParser, hn *ussd.Handlers) *BaseSessionHandler {
func NewBaseSessionHandler(cfg engine.Config, rs resource.Resource, stateDb db.Db, userdataDb db.Db, rp request.RequestParser, hn *application.Handlers) *BaseSessionHandler {
return &BaseSessionHandler{
cfgTemplate: cfg,
rs: rs,
@ -110,6 +110,10 @@ func(f *BaseSessionHandler) GetConfig() engine.Config {
return f.cfgTemplate
}
<<<<<<< HEAD:handlers/base.go
func(f *BaseSessionHandler) GetRequestParser() request.RequestParser {
=======
func (f *BaseSessionHandler) GetRequestParser() RequestParser {
>>>>>>> master:internal/handlers/base.go
return f.rp
}

View File

@ -10,13 +10,13 @@ import (
"git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/urdt/ussd/internal/handlers/ussd"
"git.grassecon.net/urdt/ussd/internal/handlers/application"
"git.grassecon.net/urdt/ussd/internal/utils"
"git.grassecon.net/urdt/ussd/remote"
)
type HandlerService interface {
GetHandler() (*ussd.Handlers, error)
GetHandler() (*application.Handlers, error)
}
func getParser(fp string, debug bool) (*asm.FlagParser, error) {
@ -64,72 +64,73 @@ func (ls *LocalHandlerService) SetDataStore(db *db.Db) {
ls.UserdataStore = db
}
func (ls *LocalHandlerService) GetHandler(accountService remote.AccountServiceInterface) (*ussd.Handlers, error) {
func (ls *LocalHandlerService) GetHandler(accountService remote.AccountServiceInterface) (*application.Handlers, error) {
replaceSeparatorFunc := func(input string) string {
return strings.ReplaceAll(input, ":", ls.Cfg.MenuSeparator)
}
ussdHandlers, err := ussd.NewHandlers(ls.Parser, *ls.UserdataStore, ls.AdminStore, accountService, replaceSeparatorFunc)
appHandlers, err := application.NewHandlers(ls.Parser, *ls.UserdataStore, ls.AdminStore, accountService, replaceSeparatorFunc)
if err != nil {
return nil, err
}
ussdHandlers = ussdHandlers.WithPersister(ls.Pe)
ls.DbRs.AddLocalFunc("set_language", ussdHandlers.SetLanguage)
ls.DbRs.AddLocalFunc("create_account", ussdHandlers.CreateAccount)
ls.DbRs.AddLocalFunc("save_temporary_pin", ussdHandlers.SaveTemporaryPin)
ls.DbRs.AddLocalFunc("verify_create_pin", ussdHandlers.VerifyCreatePin)
ls.DbRs.AddLocalFunc("check_identifier", ussdHandlers.CheckIdentifier)
ls.DbRs.AddLocalFunc("check_account_status", ussdHandlers.CheckAccountStatus)
ls.DbRs.AddLocalFunc("authorize_account", ussdHandlers.Authorize)
ls.DbRs.AddLocalFunc("quit", ussdHandlers.Quit)
ls.DbRs.AddLocalFunc("check_balance", ussdHandlers.CheckBalance)
ls.DbRs.AddLocalFunc("validate_recipient", ussdHandlers.ValidateRecipient)
ls.DbRs.AddLocalFunc("transaction_reset", ussdHandlers.TransactionReset)
ls.DbRs.AddLocalFunc("invite_valid_recipient", ussdHandlers.InviteValidRecipient)
ls.DbRs.AddLocalFunc("max_amount", ussdHandlers.MaxAmount)
ls.DbRs.AddLocalFunc("validate_amount", ussdHandlers.ValidateAmount)
ls.DbRs.AddLocalFunc("reset_transaction_amount", ussdHandlers.ResetTransactionAmount)
ls.DbRs.AddLocalFunc("get_recipient", ussdHandlers.GetRecipient)
ls.DbRs.AddLocalFunc("get_sender", ussdHandlers.GetSender)
ls.DbRs.AddLocalFunc("get_amount", ussdHandlers.GetAmount)
ls.DbRs.AddLocalFunc("reset_incorrect", ussdHandlers.ResetIncorrectPin)
ls.DbRs.AddLocalFunc("save_firstname", ussdHandlers.SaveFirstname)
ls.DbRs.AddLocalFunc("save_familyname", ussdHandlers.SaveFamilyname)
ls.DbRs.AddLocalFunc("save_gender", ussdHandlers.SaveGender)
ls.DbRs.AddLocalFunc("save_location", ussdHandlers.SaveLocation)
ls.DbRs.AddLocalFunc("save_yob", ussdHandlers.SaveYob)
ls.DbRs.AddLocalFunc("save_offerings", ussdHandlers.SaveOfferings)
ls.DbRs.AddLocalFunc("reset_account_authorized", ussdHandlers.ResetAccountAuthorized)
ls.DbRs.AddLocalFunc("reset_allow_update", ussdHandlers.ResetAllowUpdate)
ls.DbRs.AddLocalFunc("get_profile_info", ussdHandlers.GetProfileInfo)
ls.DbRs.AddLocalFunc("verify_yob", ussdHandlers.VerifyYob)
ls.DbRs.AddLocalFunc("reset_incorrect_date_format", ussdHandlers.ResetIncorrectYob)
ls.DbRs.AddLocalFunc("initiate_transaction", ussdHandlers.InitiateTransaction)
ls.DbRs.AddLocalFunc("verify_new_pin", ussdHandlers.VerifyNewPin)
ls.DbRs.AddLocalFunc("confirm_pin_change", ussdHandlers.ConfirmPinChange)
ls.DbRs.AddLocalFunc("quit_with_help", ussdHandlers.QuitWithHelp)
ls.DbRs.AddLocalFunc("fetch_community_balance", ussdHandlers.FetchCommunityBalance)
ls.DbRs.AddLocalFunc("set_default_voucher", ussdHandlers.SetDefaultVoucher)
ls.DbRs.AddLocalFunc("check_vouchers", ussdHandlers.CheckVouchers)
ls.DbRs.AddLocalFunc("get_vouchers", ussdHandlers.GetVoucherList)
ls.DbRs.AddLocalFunc("view_voucher", ussdHandlers.ViewVoucher)
ls.DbRs.AddLocalFunc("set_voucher", ussdHandlers.SetVoucher)
ls.DbRs.AddLocalFunc("get_voucher_details", ussdHandlers.GetVoucherDetails)
ls.DbRs.AddLocalFunc("reset_valid_pin", ussdHandlers.ResetValidPin)
ls.DbRs.AddLocalFunc("check_pin_mismatch", ussdHandlers.CheckBlockedNumPinMisMatch)
ls.DbRs.AddLocalFunc("validate_blocked_number", ussdHandlers.ValidateBlockedNumber)
ls.DbRs.AddLocalFunc("retrieve_blocked_number", ussdHandlers.RetrieveBlockedNumber)
ls.DbRs.AddLocalFunc("reset_unregistered_number", ussdHandlers.ResetUnregisteredNumber)
ls.DbRs.AddLocalFunc("reset_others_pin", ussdHandlers.ResetOthersPin)
ls.DbRs.AddLocalFunc("save_others_temporary_pin", ussdHandlers.SaveOthersTemporaryPin)
ls.DbRs.AddLocalFunc("get_current_profile_info", ussdHandlers.GetCurrentProfileInfo)
ls.DbRs.AddLocalFunc("check_transactions", ussdHandlers.CheckTransactions)
ls.DbRs.AddLocalFunc("get_transactions", ussdHandlers.GetTransactionsList)
ls.DbRs.AddLocalFunc("view_statement", ussdHandlers.ViewTransactionStatement)
ls.DbRs.AddLocalFunc("update_all_profile_items", ussdHandlers.UpdateAllProfileItems)
ls.DbRs.AddLocalFunc("set_back", ussdHandlers.SetBack)
appHandlers = appHandlers.WithPersister(ls.Pe)
ls.DbRs.AddLocalFunc("set_language", appHandlers.SetLanguage)
ls.DbRs.AddLocalFunc("create_account", appHandlers.CreateAccount)
ls.DbRs.AddLocalFunc("save_temporary_pin", appHandlers.SaveTemporaryPin)
ls.DbRs.AddLocalFunc("verify_create_pin", appHandlers.VerifyCreatePin)
ls.DbRs.AddLocalFunc("check_identifier", appHandlers.CheckIdentifier)
ls.DbRs.AddLocalFunc("check_account_status", appHandlers.CheckAccountStatus)
ls.DbRs.AddLocalFunc("authorize_account", appHandlers.Authorize)
ls.DbRs.AddLocalFunc("quit", appHandlers.Quit)
ls.DbRs.AddLocalFunc("check_balance", appHandlers.CheckBalance)
ls.DbRs.AddLocalFunc("validate_recipient", appHandlers.ValidateRecipient)
ls.DbRs.AddLocalFunc("transaction_reset", appHandlers.TransactionReset)
ls.DbRs.AddLocalFunc("invite_valid_recipient", appHandlers.InviteValidRecipient)
ls.DbRs.AddLocalFunc("max_amount", appHandlers.MaxAmount)
ls.DbRs.AddLocalFunc("validate_amount", appHandlers.ValidateAmount)
ls.DbRs.AddLocalFunc("reset_transaction_amount", appHandlers.ResetTransactionAmount)
ls.DbRs.AddLocalFunc("get_recipient", appHandlers.GetRecipient)
ls.DbRs.AddLocalFunc("get_sender", appHandlers.GetSender)
ls.DbRs.AddLocalFunc("get_amount", appHandlers.GetAmount)
ls.DbRs.AddLocalFunc("reset_incorrect", appHandlers.ResetIncorrectPin)
ls.DbRs.AddLocalFunc("save_firstname", appHandlers.SaveFirstname)
ls.DbRs.AddLocalFunc("save_familyname", appHandlers.SaveFamilyname)
ls.DbRs.AddLocalFunc("save_gender", appHandlers.SaveGender)
ls.DbRs.AddLocalFunc("save_location", appHandlers.SaveLocation)
ls.DbRs.AddLocalFunc("save_yob", appHandlers.SaveYob)
ls.DbRs.AddLocalFunc("save_offerings", appHandlers.SaveOfferings)
ls.DbRs.AddLocalFunc("reset_account_authorized", appHandlers.ResetAccountAuthorized)
ls.DbRs.AddLocalFunc("reset_allow_update", appHandlers.ResetAllowUpdate)
ls.DbRs.AddLocalFunc("get_profile_info", appHandlers.GetProfileInfo)
ls.DbRs.AddLocalFunc("verify_yob", appHandlers.VerifyYob)
ls.DbRs.AddLocalFunc("reset_incorrect_date_format", appHandlers.ResetIncorrectYob)
ls.DbRs.AddLocalFunc("initiate_transaction", appHandlers.InitiateTransaction)
ls.DbRs.AddLocalFunc("verify_new_pin", appHandlers.VerifyNewPin)
ls.DbRs.AddLocalFunc("confirm_pin_change", appHandlers.ConfirmPinChange)
ls.DbRs.AddLocalFunc("quit_with_help", appHandlers.QuitWithHelp)
ls.DbRs.AddLocalFunc("fetch_community_balance", appHandlers.FetchCommunityBalance)
ls.DbRs.AddLocalFunc("set_default_voucher", appHandlers.SetDefaultVoucher)
ls.DbRs.AddLocalFunc("check_vouchers", appHandlers.CheckVouchers)
ls.DbRs.AddLocalFunc("get_vouchers", appHandlers.GetVoucherList)
ls.DbRs.AddLocalFunc("view_voucher", appHandlers.ViewVoucher)
ls.DbRs.AddLocalFunc("set_voucher", appHandlers.SetVoucher)
ls.DbRs.AddLocalFunc("get_voucher_details", appHandlers.GetVoucherDetails)
ls.DbRs.AddLocalFunc("reset_valid_pin", appHandlers.ResetValidPin)
ls.DbRs.AddLocalFunc("check_pin_mismatch", appHandlers.CheckBlockedNumPinMisMatch)
ls.DbRs.AddLocalFunc("validate_blocked_number", appHandlers.ValidateBlockedNumber)
ls.DbRs.AddLocalFunc("retrieve_blocked_number", appHandlers.RetrieveBlockedNumber)
ls.DbRs.AddLocalFunc("reset_unregistered_number", appHandlers.ResetUnregisteredNumber)
ls.DbRs.AddLocalFunc("reset_others_pin", appHandlers.ResetOthersPin)
ls.DbRs.AddLocalFunc("save_others_temporary_pin", appHandlers.SaveOthersTemporaryPin)
ls.DbRs.AddLocalFunc("get_current_profile_info", appHandlers.GetCurrentProfileInfo)
ls.DbRs.AddLocalFunc("check_transactions", appHandlers.CheckTransactions)
ls.DbRs.AddLocalFunc("get_transactions", appHandlers.GetTransactionsList)
ls.DbRs.AddLocalFunc("view_statement", appHandlers.ViewTransactionStatement)
ls.DbRs.AddLocalFunc("update_all_profile_items", appHandlers.UpdateAllProfileItems)
ls.DbRs.AddLocalFunc("set_back", appHandlers.SetBack)
ls.DbRs.AddLocalFunc("show_blocked_account", appHandlers.ShowBlockedAccount)
return ussdHandlers, nil
return appHandlers, nil
}
// TODO: enable setting of sessionId on engine init time

View File

@ -1,4 +1,4 @@
package ussd
package application
import (
"bytes"
@ -734,11 +734,23 @@ func (h *Handlers) Authorize(ctx context.Context, sym string, input []byte) (res
if h.st.MatchFlag(flag_account_authorized, false) {
res.FlagReset = append(res.FlagReset, flag_incorrect_pin)
res.FlagSet = append(res.FlagSet, flag_allow_update, flag_account_authorized)
err := h.resetIncorrectPINAttempts(ctx, sessionId)
if err != nil {
return res, err
}
} else {
res.FlagSet = append(res.FlagSet, flag_allow_update)
res.FlagReset = append(res.FlagReset, flag_account_authorized)
err := h.resetIncorrectPINAttempts(ctx, sessionId)
if err != nil {
return res, err
}
}
} else {
err := h.incrementIncorrectPINAttempts(ctx, sessionId)
if err != nil {
return res, err
}
res.FlagSet = append(res.FlagSet, flag_incorrect_pin)
res.FlagReset = append(res.FlagReset, flag_account_authorized)
return res, nil
@ -752,8 +764,34 @@ func (h *Handlers) Authorize(ctx context.Context, sym string, input []byte) (res
// ResetIncorrectPin resets the incorrect pin flag after a new PIN attempt.
func (h *Handlers) ResetIncorrectPin(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result
store := h.userdataStore
flag_incorrect_pin, _ := h.flagManager.GetFlag("flag_incorrect_pin")
flag_account_blocked, _ := h.flagManager.GetFlag("flag_account_blocked")
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
res.FlagReset = append(res.FlagReset, flag_incorrect_pin)
currentWrongPinAttempts, err := store.ReadEntry(ctx, sessionId, common.DATA_INCORRECT_PIN_ATTEMPTS)
if err != nil {
if !db.IsNotFound(err) {
return res, err
}
}
pinAttemptsValue, _ := strconv.ParseUint(string(currentWrongPinAttempts), 0, 64)
remainingPINAttempts := common.AllowedPINAttempts - uint8(pinAttemptsValue)
if remainingPINAttempts == 0 {
res.FlagSet = append(res.FlagSet, flag_account_blocked)
return res, nil
}
if remainingPINAttempts < common.AllowedPINAttempts {
res.Content = strconv.Itoa(int(remainingPINAttempts))
}
return res, nil
}
@ -840,6 +878,16 @@ func (h *Handlers) QuitWithHelp(ctx context.Context, sym string, input []byte) (
return res, nil
}
// ShowBlockedAccount displays a message after an account has been blocked and how to reach support.
func (h *Handlers) ShowBlockedAccount(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result
code := codeFromCtx(ctx)
l := gotext.NewLocale(translationDir, code)
l.AddDomain("default")
res.Content = l.Get("Your account has been locked. For help on how to unblock your account, contact support at: 0757628885")
return res, nil
}
// VerifyYob verifies the length of the given input.
func (h *Handlers) VerifyYob(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result
@ -2075,3 +2123,53 @@ func (h *Handlers) UpdateAllProfileItems(ctx context.Context, sym string, input
}
return res, nil
}
// incrementIncorrectPINAttempts keeps track of the number of incorrect PIN attempts
func (h *Handlers) incrementIncorrectPINAttempts(ctx context.Context, sessionId string) error {
var pinAttemptsCount uint8
store := h.userdataStore
currentWrongPinAttempts, err := store.ReadEntry(ctx, sessionId, common.DATA_INCORRECT_PIN_ATTEMPTS)
if err != nil {
if db.IsNotFound(err) {
//First time Wrong PIN attempt: initialize with a count of 1
pinAttemptsCount = 1
err = store.WriteEntry(ctx, sessionId, common.DATA_INCORRECT_PIN_ATTEMPTS, []byte(strconv.Itoa(int(pinAttemptsCount))))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write incorrect PIN attempts ", "key", common.DATA_INCORRECT_PIN_ATTEMPTS, "value", currentWrongPinAttempts, "error", err)
return err
}
return nil
}
}
pinAttemptsValue, _ := strconv.ParseUint(string(currentWrongPinAttempts), 0, 64)
pinAttemptsCount = uint8(pinAttemptsValue) + 1
err = store.WriteEntry(ctx, sessionId, common.DATA_INCORRECT_PIN_ATTEMPTS, []byte(strconv.Itoa(int(pinAttemptsCount))))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write incorrect PIN attempts ", "key", common.DATA_INCORRECT_PIN_ATTEMPTS, "value", pinAttemptsCount, "error", err)
return err
}
return nil
}
// resetIncorrectPINAttempts resets the number of incorrect PIN attempts after a correct PIN entry
func (h *Handlers) resetIncorrectPINAttempts(ctx context.Context, sessionId string) error {
store := h.userdataStore
currentWrongPinAttempts, err := store.ReadEntry(ctx, sessionId, common.DATA_INCORRECT_PIN_ATTEMPTS)
if err != nil {
if db.IsNotFound(err) {
return nil
}
return err
}
currentWrongPinAttemptsCount, _ := strconv.ParseUint(string(currentWrongPinAttempts), 0, 64)
if currentWrongPinAttemptsCount <= uint64(common.AllowedPINAttempts) {
err = store.WriteEntry(ctx, sessionId, common.DATA_INCORRECT_PIN_ATTEMPTS, []byte(string("0")))
if err != nil {
logg.ErrorCtxf(ctx, "failed to reset incorrect PIN attempts ", "key", common.DATA_INCORRECT_PIN_ATTEMPTS, "value", common.AllowedPINAttempts, "error", err)
return err
}
}
return nil
}

View File

@ -1,10 +1,11 @@
package ussd
package application
import (
"context"
"fmt"
"log"
"path"
"strconv"
"strings"
"testing"
@ -907,37 +908,79 @@ func TestResetAccountAuthorized(t *testing.T) {
}
func TestIncorrectPinReset(t *testing.T) {
sessionId := "session123"
ctx, store := InitializeTestStore(t)
fm, err := NewFlagManager(flagsPath)
if err != nil {
log.Fatal(err)
}
flag_incorrect_pin, _ := fm.parser.GetFlag("flag_incorrect_pin")
flag_account_blocked, _ := fm.parser.GetFlag("flag_account_blocked")
ctx = context.WithValue(ctx, "SessionId", sessionId)
// Define test cases
tests := []struct {
name string
input []byte
attempts uint8
expectedResult resource.Result
}{
{
name: "Test incorrect pin reset",
name: "Test when incorrect PIN attempts is 2",
input: []byte(""),
expectedResult: resource.Result{
FlagReset: []uint32{flag_incorrect_pin},
Content: "1", //Expected remaining PIN attempts
},
attempts: 2,
},
{
name: "Test incorrect pin reset when incorrect PIN attempts is 1",
input: []byte(""),
expectedResult: resource.Result{
FlagReset: []uint32{flag_incorrect_pin},
Content: "2", //Expected remaining PIN attempts
},
attempts: 1,
},
{
name: "Test incorrect pin reset when incorrect PIN attempts is 1",
input: []byte(""),
expectedResult: resource.Result{
FlagReset: []uint32{flag_incorrect_pin},
Content: "2", //Expected remaining PIN attempts
},
attempts: 1,
},
{
name: "Test incorrect pin reset when incorrect PIN attempts is 3(account expected to be blocked)",
input: []byte(""),
expectedResult: resource.Result{
FlagReset: []uint32{flag_incorrect_pin},
FlagSet: []uint32{flag_account_blocked},
},
attempts: 3,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := store.WriteEntry(ctx, sessionId, common.DATA_INCORRECT_PIN_ATTEMPTS, []byte(strconv.Itoa(int(tt.attempts)))); err != nil {
t.Fatal(err)
}
// Create the Handlers instance with the mock flag manager
h := &Handlers{
flagManager: fm.parser,
userdataStore: store,
}
// Call the method
res, err := h.ResetIncorrectPin(context.Background(), "reset_incorrect_pin", tt.input)
res, err := h.ResetIncorrectPin(ctx, "reset_incorrect_pin", tt.input)
if err != nil {
t.Error(err)
}
@ -2190,3 +2233,55 @@ func TestGetVoucherDetails(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, expectedResult, res)
}
func TestCountIncorrectPINAttempts(t *testing.T) {
ctx, store := InitializeTestStore(t)
sessionId := "session123"
ctx = context.WithValue(ctx, "SessionId", sessionId)
attempts := uint8(2)
h := &Handlers{
userdataStore: store,
}
err := store.WriteEntry(ctx, sessionId, common.DATA_INCORRECT_PIN_ATTEMPTS, []byte(strconv.Itoa(int(attempts))))
if err != nil {
t.Logf(err.Error())
}
err = h.incrementIncorrectPINAttempts(ctx, sessionId)
if err != nil {
t.Logf(err.Error())
}
attemptsAfterCount, err := store.ReadEntry(ctx, sessionId, common.DATA_INCORRECT_PIN_ATTEMPTS)
if err != nil {
t.Logf(err.Error())
}
pinAttemptsValue, _ := strconv.ParseUint(string(attemptsAfterCount), 0, 64)
pinAttemptsCount := uint8(pinAttemptsValue)
expectedAttempts := attempts + 1
assert.Equal(t, pinAttemptsCount, expectedAttempts)
}
func TestResetIncorrectPINAttempts(t *testing.T) {
ctx, store := InitializeTestStore(t)
sessionId := "session123"
ctx = context.WithValue(ctx, "SessionId", sessionId)
err := store.WriteEntry(ctx, sessionId, common.DATA_INCORRECT_PIN_ATTEMPTS, []byte(string("2")))
if err != nil {
t.Logf(err.Error())
}
h := &Handlers{
userdataStore: store,
}
h.resetIncorrectPINAttempts(ctx, sessionId)
incorrectAttempts, err := store.ReadEntry(ctx, sessionId, common.DATA_INCORRECT_PIN_ATTEMPTS)
if err != nil {
t.Logf(err.Error())
}
assert.Equal(t, "0", string(incorrectAttempts))
}

View File

@ -41,6 +41,7 @@ func NewAuther(ctx context.Context, keyStore *SshKeyStore) *auther {
}
func(a *auther) Check(conn ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) {
logg.TraceCtxf(a.Ctx, "looking for publickey", "pubkey", fmt.Sprintf("%x", pubKey))
va, err := a.keyStore.Get(a.Ctx, pubKey)
if err != nil {
return nil, err
@ -203,6 +204,7 @@ func(s *SshRunner) GetEngine(sessionId string) (engine.Engine, func(), error) {
// adapted example from crypto/ssh package, NewServerConn doc
func(s *SshRunner) Run(ctx context.Context, keyStore *SshKeyStore) {
s.Ctx = ctx
running := true
// TODO: waitgroup should probably not be global

View File

@ -54,7 +54,7 @@
},
{
"input": "1235",
"expectedContent": "Incorrect PIN\n1:Retry\n9:Quit"
"expectedContent": "Incorrect PIN. You have: 2 remaining attempt(s).\n1:Retry\n9:Quit"
},
{
"input": "1",
@ -95,7 +95,7 @@
},
{
"input": "1235",
"expectedContent": "Incorrect PIN\n1:Retry\n9:Quit"
"expectedContent": "Incorrect PIN. You have: 2 remaining attempt(s).\n1:Retry\n9:Quit"
},
{
"input": "1",
@ -108,7 +108,6 @@
{
"input": "0",
"expectedContent": "Balances:\n1:My balance\n2:Community balance\n0:Back"
},
{
"input": "0",
@ -141,7 +140,7 @@
},
{
"input": "1235",
"expectedContent": "Incorrect PIN\n1:Retry\n9:Quit"
"expectedContent": "Incorrect PIN. You have: 2 remaining attempt(s).\n1:Retry\n9:Quit"
},
{
"input": "1",
@ -154,7 +153,6 @@
{
"input": "0",
"expectedContent": "Balances:\n1:My balance\n2:Community balance\n0:Back"
},
{
"input": "0",
@ -258,7 +256,6 @@
"input": "0",
"expectedContent": "{balance}\n\n1:Send\n2:My Vouchers\n3:My Account\n4:Help\n9:Quit"
}
]
},
{
@ -444,9 +441,3 @@
}
]
}

View File

@ -0,0 +1,2 @@
LOAD show_blocked_account 0
HALT

View File

@ -1 +1 @@
Incorrect PIN
Incorrect PIN. You have: {{.reset_incorrect}} remaining attempt(s).

View File

@ -1,5 +1,7 @@
LOAD reset_incorrect 0
RELOAD reset_incorrect
MAP reset_incorrect
CATCH blocked_account flag_account_blocked 1
MOUT retry 1
MOUT quit 9
HALT

View File

@ -1 +1 @@
PIN ulioeka sio sahihi
PIN ulioeka sio sahihi, una majaribio: {{.reset_incorrect}} yaliyobaki

View File

@ -10,6 +10,9 @@ msgstr "Asante kwa kutumia huduma ya Sarafu. Kwaheri!"
msgid "For more help, please call: 0757628885"
msgstr "Kwa usaidizi zaidi, piga: 0757628885"
msgid "Your account has been locked. For help on how to unblock your account, contact support at: 0757628885"
msgstr "Akaunti yako imefungwa. Kwa usaidizi wa jinsi ya kufungua akaunti yako, wasiliana na usaidizi kwa: 0757628885"
msgid "Balance: %s\n"
msgstr "Salio: %s\n"

View File

@ -28,3 +28,5 @@ flag,flag_gender_set,34,this is set when the gender of the profile is set
flag,flag_location_set,35,this is set when the location of the profile is set
flag,flag_offerings_set,36,this is set when the offerings of the profile is set
flag,flag_back_set,37,this is set when it is a back navigation
flag,flag_account_blocked,38,this is set when an account has been blocked after the allowed incorrect PIN attempts have been exceeded

1 flag flag_language_set 8 checks whether the user has set their prefered language
28 flag flag_location_set 35 this is set when the location of the profile is set
29 flag flag_offerings_set 36 this is set when the offerings of the profile is set
30 flag flag_back_set 37 this is set when it is a back navigation
31 flag flag_account_blocked 38 this is set when an account has been blocked after the allowed incorrect PIN attempts have been exceeded
32

View File

@ -1,3 +1,4 @@
CATCH blocked_account flag_account_blocked 1
CATCH select_language flag_language_set 0
CATCH terms flag_account_created 0
LOAD check_account_status 0