Compare commits

...

61 Commits

Author SHA1 Message Date
Carlosokumu
6dbe74d12b use single temporary value 2024-11-01 16:46:09 +03:00
Carlosokumu
332074375a wrap in devtools/admin 2024-11-01 16:44:54 +03:00
Carlosokumu
5e4a9e7567 Merge branch 'master' into pin-reset 2024-11-01 16:26:29 +03:00
Carlosokumu
eb2c73dce1 remove unused setadmin store 2024-11-01 11:51:50 +03:00
Carlosokumu
7e448f739a change fs store path to root 2024-11-01 09:35:48 +03:00
Carlosokumu
0014693ba8 remove guard pin option 2024-11-01 06:39:37 +03:00
Carlosokumu
2704069e74 Merge branch 'master' into pin-reset 2024-10-31 21:09:48 +03:00
Carlosokumu
7d1a04f089 remove from root 2024-10-31 21:01:24 +03:00
Carlosokumu
53fa6f64ce define structure of json 2024-10-31 21:01:01 +03:00
Carlosokumu
7fa38340dd add command to initialize a list of admin numbers 2024-10-31 21:00:41 +03:00
Carlosokumu
7aab3cff8c remove seed 2024-10-31 21:00:16 +03:00
Carlosokumu
299534ccf1 define seed as a command in the devtool 2024-10-31 20:59:51 +03:00
Carlosokumu
b2655b7f11 remove seed from executable 2024-10-31 20:59:11 +03:00
Carlosokumu
5abe9b78cc attach an admin store for the phone numbers 2024-10-31 20:11:26 +03:00
Carlosokumu
12825ae08a setup adminstore in the local handler service 2024-10-31 20:10:46 +03:00
Carlosokumu
ac0b4b2ed1 pass context 2024-10-31 20:08:30 +03:00
Carlosokumu
8fe8ff540b Merge branch 'master' into pin-reset 2024-10-31 16:38:28 +03:00
Carlosokumu
767a3cd64c remove pin guard menu option 2024-10-31 09:38:51 +03:00
Carlosokumu
c4078c5280 remove extra spaces 2024-10-31 09:21:46 +03:00
Carlosokumu
d434194021 catch incorrect pin entry 2024-10-30 23:21:15 +03:00
Carlosokumu
c6ca3f6be4 fix sink error 2024-10-30 22:32:38 +03:00
Carlosokumu
8093eae61a use 0 instead of 1 for back 2024-10-30 21:26:52 +03:00
Carlosokumu
833d52a558 remove print message 2024-10-30 21:26:11 +03:00
Carlosokumu
8262e14198 Merge branch 'master' into pin-reset 2024-10-30 21:10:12 +03:00
Carlosokumu
ea4c6d9314 check for phone number validity 2024-10-30 18:01:43 +03:00
Carlosokumu
7c823e07ca move to root node after on back 2024-10-30 18:01:20 +03:00
Carlosokumu
41585f831c move catch and load to next node 2024-10-30 18:00:38 +03:00
Carlosokumu
d93a26f9b0 remove function exec after HALT 2024-10-30 17:58:52 +03:00
Carlosokumu
cf523e30f8 update handler in test 2024-10-30 14:50:31 +03:00
Carlosokumu
888d3befe9 add actual pin reset functionality 2024-10-30 14:50:12 +03:00
Carlosokumu
017691a40c define structure for admin numbers 2024-10-30 14:41:14 +03:00
Carlosokumu
dc418771a7 attach an admin store for phone numbers 2024-10-30 14:33:48 +03:00
Carlosokumu
c2068db050 update handler functions 2024-10-30 14:33:22 +03:00
Carlosokumu
c42b1cd66b provide required handler functions and admin store 2024-10-30 14:32:01 +03:00
Carlosokumu
b404ae95fb setup an admin store based on fs 2024-10-30 14:30:38 +03:00
Carlosokumu
0a97f610a4 catch unregistred number 2024-10-29 22:23:22 +03:00
Carlosokumu
5a0563df94 group regex,check for valid number against the regex 2024-10-29 22:17:43 +03:00
Carlosokumu
7597b96dae remove catch for unregistered number 2024-10-29 22:16:34 +03:00
Carlosokumu
f37483e2f0 use _ for back navigation 2024-10-29 22:15:31 +03:00
Carlosokumu
d0ad6395b5 add check for unregistered phone numbers 2024-10-29 17:35:42 +03:00
Carlosokumu
106983a394 use explicit back to node 2024-10-29 17:35:01 +03:00
Carlosokumu
91b85af11a add reset unregistered number 2024-10-29 17:34:34 +03:00
Carlosokumu
534d756318 catch unregistred phone numbers 2024-10-29 17:18:39 +03:00
Carlosokumu
6998c30dd1 add node to handle unregistered phone numbers 2024-10-29 17:18:01 +03:00
Carlosokumu
449f90c95b add flag to catch unregistred numbers 2024-10-29 17:17:03 +03:00
Carlosokumu
e96c874300 repeat same node on invalid option input 2024-10-29 15:02:40 +03:00
Carlosokumu
b35460d3c1 Merge branch 'master' into pin-reset 2024-10-29 14:35:17 +03:00
Carlosokumu
124049c924 add admin number defination in env 2024-10-29 14:32:17 +03:00
Carlosokumu
5fd3eb3c29 set admin privilege flag 2024-10-29 14:28:58 +03:00
Carlosokumu
d83962c0ba load admin numbers defined in the .env 2024-10-29 14:26:24 +03:00
Carlosokumu
41da099933 remove the admin flag,setup an admin store 2024-10-29 13:24:13 +03:00
Carlosokumu
c9bb93ede6 create a simple admin store for phone numbers 2024-10-29 13:15:41 +03:00
Carlosokumu
ca13d9155c replace _ with explicit back node 2024-10-29 13:15:22 +03:00
Carlosokumu
e338ce0025 load and reload only after input 2024-10-29 13:14:49 +03:00
Carlosokumu
b97965193b add pin reset for others handling 2024-10-28 16:37:23 +03:00
Carlosokumu
aec0abb2b6 setup an admin flag 2024-10-28 16:34:33 +03:00
Carlosokumu
26073c8000 define handler functions required to reset others pin 2024-10-28 15:49:20 +03:00
Carlosokumu
e4c2f644f3 define a key to hold number during pin reset 2024-10-28 15:47:56 +03:00
Carlosokumu
3de46cef5e setup pin reset nodes 2024-10-28 15:45:08 +03:00
Carlosokumu
0cc0bdf9f7 add pin reset for others nodes 2024-10-28 15:19:35 +03:00
Carlosokumu
72d5c186dd add admin privilege flag 2024-10-28 15:18:40 +03:00
37 changed files with 396 additions and 34 deletions

View File

@@ -16,3 +16,7 @@ CREATE_ACCOUNT_URL=http://localhost:5003/api/v2/account/create
TRACK_STATUS_URL=https://custodial.sarafu.africa/api/track/ TRACK_STATUS_URL=https://custodial.sarafu.africa/api/track/
BALANCE_URL=https://custodial.sarafu.africa/api/account/status/ BALANCE_URL=https://custodial.sarafu.africa/api/account/status/
TRACK_URL=http://localhost:5003/api/v2/account/status TRACK_URL=http://localhost:5003/api/v2/account/status
#numbers with privileges to reset others pin
ADMIN_NUMBERS=254051722XXX,255012221XXX

View File

@@ -131,7 +131,7 @@ func main() {
os.Exit(1) os.Exit(1)
} }
lhs, err := handlers.NewLocalHandlerService(pfp, true, dbResource, cfg, rs) lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs)
lhs.SetDataStore(&userdataStore) lhs.SetDataStore(&userdataStore)
if err != nil { if err != nil {

View File

@@ -104,8 +104,9 @@ func main() {
os.Exit(1) os.Exit(1)
} }
lhs, err := handlers.NewLocalHandlerService(pfp, true, dbResource, cfg, rs) lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs)
lhs.SetDataStore(&userdataStore) lhs.SetDataStore(&userdataStore)
accountService := server.AccountService{} accountService := server.AccountService{}
hl, err := lhs.GetHandler(&accountService) hl, err := lhs.GetHandler(&accountService)

View File

@@ -92,13 +92,14 @@ func main() {
os.Exit(1) os.Exit(1)
} }
lhs, err := handlers.NewLocalHandlerService(pfp, true, dbResource, cfg, rs) lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs)
lhs.SetDataStore(&userdataStore) lhs.SetDataStore(&userdataStore)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, err.Error()) fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1) os.Exit(1)
} }
accountService := server.AccountService{} accountService := server.AccountService{}
hl, err := lhs.GetHandler(&accountService) hl, err := lhs.GetHandler(&accountService)
if err != nil { if err != nil {

View File

@@ -88,7 +88,7 @@ func main() {
os.Exit(1) os.Exit(1)
} }
lhs, err := handlers.NewLocalHandlerService(pfp, true, dbResource, cfg, rs) lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs)
lhs.SetDataStore(&userdatastore) lhs.SetDataStore(&userdatastore)
lhs.SetPersister(pe) lhs.SetPersister(pe)

View File

@@ -0,0 +1,7 @@
{
"admins": [
{
"phonenumber" : "<replace with any admin number to test with >"
}
]
}

View File

@@ -0,0 +1,47 @@
package commands
import (
"context"
"encoding/json"
"os"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/urdt/ussd/internal/utils"
)
var (
logg = logging.NewVanilla().WithDomain("adminstore")
)
type Admin struct {
PhoneNumber string `json:"phonenumber"`
}
type Config struct {
Admins []Admin `json:"admins"`
}
func Seed(ctx context.Context) error {
var config Config
adminstore, err := utils.NewAdminStore(ctx, "../admin_numbers")
store := adminstore.FsStore
if err != nil {
return err
}
defer store.Close()
data, err := os.ReadFile("admin_numbers.json")
if err != nil {
return err
}
if err := json.Unmarshal(data, &config); err != nil {
return err
}
for _, admin := range config.Admins {
err := store.Put(ctx, []byte(admin.PhoneNumber), []byte("1"))
if err != nil {
logg.Printf(logging.LVL_DEBUG, "Failed to insert admin number", admin.PhoneNumber)
return err
}
}
return nil
}

17
devtools/admin/main.go Normal file
View File

@@ -0,0 +1,17 @@
package main
import (
"context"
"log"
"git.grassecon.net/urdt/ussd/devtools/admin/commands"
)
func main() {
ctx := context.Background()
err := commands.Seed(ctx)
if err != nil {
log.Fatalf("Failed to initialize a list of admins with error %s", err)
}
}

View File

@@ -1,6 +1,8 @@
package handlers package handlers
import ( import (
"context"
"git.defalsify.org/vise.git/asm" "git.defalsify.org/vise.git/asm"
"git.defalsify.org/vise.git/db" "git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/engine" "git.defalsify.org/vise.git/engine"
@@ -8,6 +10,7 @@ import (
"git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/resource"
"git.grassecon.net/urdt/ussd/internal/handlers/server" "git.grassecon.net/urdt/ussd/internal/handlers/server"
"git.grassecon.net/urdt/ussd/internal/handlers/ussd" "git.grassecon.net/urdt/ussd/internal/handlers/ussd"
"git.grassecon.net/urdt/ussd/internal/utils"
) )
type HandlerService interface { type HandlerService interface {
@@ -28,20 +31,26 @@ type LocalHandlerService struct {
DbRs *resource.DbResource DbRs *resource.DbResource
Pe *persist.Persister Pe *persist.Persister
UserdataStore *db.Db UserdataStore *db.Db
AdminStore *utils.AdminStore
Cfg engine.Config Cfg engine.Config
Rs resource.Resource Rs resource.Resource
} }
func NewLocalHandlerService(fp string, debug bool, dbResource *resource.DbResource, cfg engine.Config, rs resource.Resource) (*LocalHandlerService, error) { func NewLocalHandlerService(ctx context.Context, fp string, debug bool, dbResource *resource.DbResource, cfg engine.Config, rs resource.Resource) (*LocalHandlerService, error) {
parser, err := getParser(fp, debug) parser, err := getParser(fp, debug)
if err != nil { if err != nil {
return nil, err return nil, err
} }
adminstore, err := utils.NewAdminStore(ctx, "admin_numbers")
if err != nil {
return nil, err
}
return &LocalHandlerService{ return &LocalHandlerService{
Parser: parser, Parser: parser,
DbRs: dbResource, DbRs: dbResource,
Cfg: cfg, AdminStore: adminstore,
Rs: rs, Cfg: cfg,
Rs: rs,
}, nil }, nil
} }
@@ -54,7 +63,7 @@ func (ls *LocalHandlerService) SetDataStore(db *db.Db) {
} }
func (ls *LocalHandlerService) GetHandler(accountService server.AccountServiceInterface) (*ussd.Handlers, error) { func (ls *LocalHandlerService) GetHandler(accountService server.AccountServiceInterface) (*ussd.Handlers, error) {
ussdHandlers, err := ussd.NewHandlers(ls.Parser, *ls.UserdataStore,accountService) ussdHandlers, err := ussd.NewHandlers(ls.Parser, *ls.UserdataStore, ls.AdminStore, accountService)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -98,6 +107,13 @@ func (ls *LocalHandlerService) GetHandler(accountService server.AccountServiceIn
ls.DbRs.AddLocalFunc("get_vouchers", ussdHandlers.GetVoucherList) ls.DbRs.AddLocalFunc("get_vouchers", ussdHandlers.GetVoucherList)
ls.DbRs.AddLocalFunc("view_voucher", ussdHandlers.ViewVoucher) ls.DbRs.AddLocalFunc("view_voucher", ussdHandlers.ViewVoucher)
ls.DbRs.AddLocalFunc("set_voucher", ussdHandlers.SetVoucher) ls.DbRs.AddLocalFunc("set_voucher", ussdHandlers.SetVoucher)
ls.DbRs.AddLocalFunc("reset_valid_pin", ussdHandlers.ResetValidPin)
ls.DbRs.AddLocalFunc("check_pin_mismatch", ussdHandlers.CheckPinMisMatch)
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)
return ussdHandlers, nil return ussdHandlers, nil
} }

View File

@@ -35,6 +35,12 @@ var (
errResponse *api.ErrResponse errResponse *api.ErrResponse
) )
// Define the regex patterns as constants
const (
phoneRegex = `(\(\d{3}\)\s?|\d{3}[-.\s]?)?\d{3}[-.\s]?\d{4}`
pinPattern = `^\d{4}$`
)
// FlagManager handles centralized flag management // FlagManager handles centralized flag management
type FlagManager struct { type FlagManager struct {
parser *asm.FlagParser parser *asm.FlagParser
@@ -63,12 +69,13 @@ type Handlers struct {
st *state.State st *state.State
ca cache.Memory ca cache.Memory
userdataStore utils.DataStore userdataStore utils.DataStore
adminstore *utils.AdminStore
flagManager *asm.FlagParser flagManager *asm.FlagParser
accountService server.AccountServiceInterface accountService server.AccountServiceInterface
prefixDb storage.PrefixDb prefixDb storage.PrefixDb
} }
func NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db, accountService server.AccountServiceInterface) (*Handlers, error) { func NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db, adminstore *utils.AdminStore, accountService server.AccountServiceInterface) (*Handlers, error) {
if userdataStore == nil { if userdataStore == nil {
return nil, fmt.Errorf("cannot create handler with nil userdata store") return nil, fmt.Errorf("cannot create handler with nil userdata store")
} }
@@ -81,21 +88,24 @@ func NewHandlers(appFlags *asm.FlagParser, userdataStore db.Db, accountService s
h := &Handlers{ h := &Handlers{
userdataStore: userDb, userdataStore: userDb,
flagManager: appFlags, flagManager: appFlags,
adminstore: adminstore,
accountService: accountService, accountService: accountService,
prefixDb: prefixDb, prefixDb: prefixDb,
} }
return h, nil return h, nil
} }
// Define the regex pattern as a constant
const pinPattern = `^\d{4}$`
// isValidPIN checks whether the given input is a 4 digit number // isValidPIN checks whether the given input is a 4 digit number
func isValidPIN(pin string) bool { func isValidPIN(pin string) bool {
match, _ := regexp.MatchString(pinPattern, pin) match, _ := regexp.MatchString(pinPattern, pin)
return match return match
} }
func isValidPhoneNumber(phonenumber string) bool {
match, _ := regexp.MatchString(phoneRegex, phonenumber)
return match
}
func (h *Handlers) WithPersister(pe *persist.Persister) *Handlers { func (h *Handlers) WithPersister(pe *persist.Persister) *Handlers {
if h.pe != nil { if h.pe != nil {
panic("persister already set") panic("persister already set")
@@ -106,13 +116,25 @@ func (h *Handlers) WithPersister(pe *persist.Persister) *Handlers {
func (h *Handlers) Init(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) Init(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var r resource.Result var r resource.Result
if h.pe == nil { if h.pe == nil {
logg.WarnCtxf(ctx, "handler init called before it is ready or more than once", "state", h.st, "cache", h.ca) logg.WarnCtxf(ctx, "handler init called before it is ready or more than once", "state", h.st, "cache", h.ca)
return r, nil return r, nil
} }
h.st = h.pe.GetState() h.st = h.pe.GetState()
h.ca = h.pe.GetMemory() h.ca = h.pe.GetMemory()
sessionId, _ := ctx.Value("SessionId").(string)
flag_admin_privilege, _ := h.flagManager.GetFlag("flag_admin_privilege")
isAdmin, _ := h.adminstore.IsAdmin(sessionId)
if isAdmin {
r.FlagSet = append(r.FlagSet, flag_admin_privilege)
} else {
r.FlagReset = append(r.FlagReset, flag_admin_privilege)
}
if h.st == nil || h.ca == nil { if h.st == nil || h.ca == nil {
logg.ErrorCtxf(ctx, "perister fail in handler", "state", h.st, "cache", h.ca) logg.ErrorCtxf(ctx, "perister fail in handler", "state", h.st, "cache", h.ca)
return r, fmt.Errorf("cannot get state and memory for handler") return r, fmt.Errorf("cannot get state and memory for handler")
@@ -203,6 +225,30 @@ func (h *Handlers) CreateAccount(ctx context.Context, sym string, input []byte)
return res, nil return res, nil
} }
func (h *Handlers) CheckPinMisMatch(ctx context.Context, sym string, input []byte) (resource.Result, error) {
res := resource.Result{}
flag_pin_mismatch, _ := h.flagManager.GetFlag("flag_pin_mismatch")
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
store := h.userdataStore
blockedNumber, err := store.ReadEntry(ctx, sessionId, utils.DATA_BLOCKED_NUMBER)
if err != nil {
return res, err
}
temporaryPin, err := store.ReadEntry(ctx, string(blockedNumber), utils.DATA_TEMPORARY_VALUE)
if err != nil {
return res, err
}
if bytes.Equal(temporaryPin, input) {
res.FlagReset = append(res.FlagReset, flag_pin_mismatch)
} else {
res.FlagSet = append(res.FlagSet, flag_pin_mismatch)
}
return res, nil
}
func (h *Handlers) VerifyNewPin(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) VerifyNewPin(ctx context.Context, sym string, input []byte) (resource.Result, error) {
res := resource.Result{} res := resource.Result{}
_, ok := ctx.Value("SessionId").(string) _, ok := ctx.Value("SessionId").(string)
@@ -234,7 +280,6 @@ func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byt
} }
flag_incorrect_pin, _ := h.flagManager.GetFlag("flag_incorrect_pin") flag_incorrect_pin, _ := h.flagManager.GetFlag("flag_incorrect_pin")
accountPIN := string(input) accountPIN := string(input)
// Validate that the PIN is a 4-digit number // Validate that the PIN is a 4-digit number
@@ -242,9 +287,7 @@ func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byt
res.FlagSet = append(res.FlagSet, flag_incorrect_pin) res.FlagSet = append(res.FlagSet, flag_incorrect_pin)
return res, nil return res, nil
} }
res.FlagReset = append(res.FlagReset, flag_incorrect_pin) res.FlagReset = append(res.FlagReset, flag_incorrect_pin)
store := h.userdataStore store := h.userdataStore
err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(accountPIN)) err = store.WriteEntry(ctx, sessionId, utils.DATA_TEMPORARY_VALUE, []byte(accountPIN))
if err != nil { if err != nil {
@@ -254,6 +297,29 @@ func (h *Handlers) SaveTemporaryPin(ctx context.Context, sym string, input []byt
return res, nil return res, nil
} }
func (h *Handlers) SaveOthersTemporaryPin(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result
var err error
store := h.userdataStore
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
temporaryPin := string(input)
blockedNumber, err := store.ReadEntry(ctx, sessionId, utils.DATA_BLOCKED_NUMBER)
if err != nil {
return res, err
}
err = store.WriteEntry(ctx, string(blockedNumber), utils.DATA_TEMPORARY_VALUE, []byte(temporaryPin))
if err != nil {
return res, err
}
return res, nil
}
func (h *Handlers) ConfirmPinChange(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) ConfirmPinChange(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
sessionId, ok := ctx.Value("SessionId").(string) sessionId, ok := ctx.Value("SessionId").(string)
@@ -298,7 +364,6 @@ func (h *Handlers) VerifyCreatePin(ctx context.Context, sym string, input []byte
if err != nil { if err != nil {
return res, err return res, err
} }
if bytes.Equal(input, temporaryPin) { if bytes.Equal(input, temporaryPin) {
res.FlagSet = []uint32{flag_valid_pin} res.FlagSet = []uint32{flag_valid_pin}
res.FlagReset = []uint32{flag_pin_mismatch} res.FlagReset = []uint32{flag_pin_mismatch}
@@ -511,6 +576,14 @@ func (h *Handlers) ResetAllowUpdate(ctx context.Context, sym string, input []byt
return res, nil return res, nil
} }
// ResetAllowUpdate resets the allowupdate flag that allows a user to update profile data.
func (h *Handlers) ResetValidPin(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result
flag_valid_pin, _ := h.flagManager.GetFlag("flag_valid_pin")
res.FlagReset = append(res.FlagReset, flag_valid_pin)
return res, nil
}
// ResetAccountAuthorized resets the account authorization flag after a successful PIN entry. // ResetAccountAuthorized resets the account authorization flag after a successful PIN entry.
func (h *Handlers) ResetAccountAuthorized(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) ResetAccountAuthorized(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
@@ -594,11 +667,13 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b
if !ok { if !ok {
return res, fmt.Errorf("missing session") return res, fmt.Errorf("missing session")
} }
store := h.userdataStore store := h.userdataStore
publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY) publicKey, err := store.ReadEntry(ctx, sessionId, utils.DATA_PUBLIC_KEY)
if err != nil { if err != nil {
return res, err return res, err
} }
okResponse, err = h.accountService.TrackAccountStatus(ctx, string(publicKey)) okResponse, err = h.accountService.TrackAccountStatus(ctx, string(publicKey))
if err != nil { if err != nil {
res.FlagSet = append(res.FlagSet, flag_api_error) res.FlagSet = append(res.FlagSet, flag_api_error)
@@ -655,7 +730,6 @@ func (h *Handlers) VerifyYob(ctx context.Context, sym string, input []byte) (res
var err error var err error
flag_incorrect_date_format, _ := h.flagManager.GetFlag("flag_incorrect_date_format") flag_incorrect_date_format, _ := h.flagManager.GetFlag("flag_incorrect_date_format")
date := string(input) date := string(input)
_, err = strconv.Atoi(date) _, err = strconv.Atoi(date)
if err != nil { if err != nil {
@@ -678,7 +752,6 @@ func (h *Handlers) ResetIncorrectYob(ctx context.Context, sym string, input []by
var res resource.Result var res resource.Result
flag_incorrect_date_format, _ := h.flagManager.GetFlag("flag_incorrect_date_format") flag_incorrect_date_format, _ := h.flagManager.GetFlag("flag_incorrect_date_format")
res.FlagReset = append(res.FlagReset, flag_incorrect_date_format) res.FlagReset = append(res.FlagReset, flag_incorrect_date_format)
return res, nil return res, nil
} }
@@ -761,6 +834,67 @@ func (h *Handlers) FetchCustodialBalances(ctx context.Context, sym string, input
return res, nil return res, nil
} }
func (h *Handlers) ResetOthersPin(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result
store := h.userdataStore
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
blockedPhonenumber, err := store.ReadEntry(ctx, sessionId, utils.DATA_BLOCKED_NUMBER)
if err != nil {
return res, err
}
temporaryPin, err := store.ReadEntry(ctx, string(blockedPhonenumber), utils.DATA_TEMPORARY_VALUE)
if err != nil {
return res, err
}
err = store.WriteEntry(ctx, string(blockedPhonenumber), utils.DATA_ACCOUNT_PIN, []byte(temporaryPin))
if err != nil {
return res, nil
}
return res, nil
}
func (h *Handlers) ResetUnregisteredNumber(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result
flag_unregistered_number, _ := h.flagManager.GetFlag("flag_unregistered_number")
res.FlagReset = append(res.FlagReset, flag_unregistered_number)
return res, nil
}
func (h *Handlers) ValidateBlockedNumber(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result
var err error
flag_unregistered_number, _ := h.flagManager.GetFlag("flag_unregistered_number")
store := h.userdataStore
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
blockedNumber := string(input)
_, err = store.ReadEntry(ctx, blockedNumber, utils.DATA_PUBLIC_KEY)
if !isValidPhoneNumber(blockedNumber) {
res.FlagSet = append(res.FlagSet, flag_unregistered_number)
return res, nil
}
if err != nil {
if db.IsNotFound(err) {
logg.Printf(logging.LVL_INFO, "Invalid or unregistered number")
res.FlagSet = append(res.FlagSet, flag_unregistered_number)
return res, nil
} else {
return res, err
}
}
err = store.WriteEntry(ctx, sessionId, utils.DATA_BLOCKED_NUMBER, []byte(blockedNumber))
if err != nil {
return res, nil
}
return res, nil
}
// ValidateRecipient validates that the given input is a valid phone number. // ValidateRecipient validates that the given input is a valid phone number.
func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result
@@ -932,6 +1066,22 @@ func (h *Handlers) GetRecipient(ctx context.Context, sym string, input []byte) (
return res, nil return res, nil
} }
// RetrieveBlockedNumber gets the current number during the pin reset for other's is in progress.
func (h *Handlers) RetrieveBlockedNumber(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
store := h.userdataStore
blockedNumber, _ := store.ReadEntry(ctx, sessionId, utils.DATA_BLOCKED_NUMBER)
res.Content = string(blockedNumber)
return res, nil
}
// GetSender returns the sessionId (phoneNumber) // GetSender returns the sessionId (phoneNumber)
func (h *Handlers) GetSender(ctx context.Context, sym string, input []byte) (resource.Result, error) { func (h *Handlers) GetSender(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result var res resource.Result

View File

@@ -42,7 +42,7 @@ func TestNewHandlers(t *testing.T) {
} }
t.Run("Valid UserDataStore", func(t *testing.T) { t.Run("Valid UserDataStore", func(t *testing.T) {
mockStore := &mocks.MockUserDataStore{} mockStore := &mocks.MockUserDataStore{}
handlers, err := NewHandlers(fm.parser, mockStore, &accountService) handlers, err := NewHandlers(fm.parser, mockStore, nil, &accountService)
if err != nil { if err != nil {
t.Fatalf("expected no error, got %v", err) t.Fatalf("expected no error, got %v", err)
} }
@@ -58,7 +58,7 @@ func TestNewHandlers(t *testing.T) {
t.Run("Nil UserDataStore", func(t *testing.T) { t.Run("Nil UserDataStore", func(t *testing.T) {
appFlags := &asm.FlagParser{} appFlags := &asm.FlagParser{}
handlers, err := NewHandlers(appFlags, nil, &accountService) handlers, err := NewHandlers(appFlags, nil, nil, &accountService)
if err == nil { if err == nil {
t.Fatal("expected an error, got none") t.Fatal("expected an error, got none")

View File

@@ -73,7 +73,7 @@ func TestEngine(sessionId string) (engine.Engine, func(), chan bool) {
os.Exit(1) os.Exit(1)
} }
lhs, err := handlers.NewLocalHandlerService(pfp, true, dbResource, cfg, rs) lhs, err := handlers.NewLocalHandlerService(ctx, pfp, true, dbResource, cfg, rs)
lhs.SetDataStore(&userDataStore) lhs.SetDataStore(&userDataStore)
lhs.SetPersister(pe) lhs.SetPersister(pe)

View File

@@ -0,0 +1,51 @@
package utils
import (
"context"
"git.defalsify.org/vise.git/db"
fsdb "git.defalsify.org/vise.git/db/fs"
"git.defalsify.org/vise.git/logging"
)
var (
logg = logging.NewVanilla().WithDomain("adminstore")
)
type AdminStore struct {
ctx context.Context
FsStore db.Db
}
func NewAdminStore(ctx context.Context, fileName string) (*AdminStore, error) {
fsStore, err := getFsStore(ctx, fileName)
if err != nil {
return nil, err
}
return &AdminStore{ctx: ctx, FsStore: fsStore}, nil
}
func getFsStore(ctx context.Context, connectStr string) (db.Db, error) {
fsStore := fsdb.NewFsDb()
err := fsStore.Connect(ctx, connectStr)
fsStore.SetPrefix(db.DATATYPE_USERDATA)
if err != nil {
return nil, err
}
return fsStore, nil
}
// Checks if the given sessionId is listed as an admin.
func (as *AdminStore) IsAdmin(sessionId string) (bool, error) {
_, err := as.FsStore.Get(as.ctx, []byte(sessionId))
if err != nil {
if db.IsNotFound(err) {
logg.Printf(logging.LVL_INFO, "Returning false because session id was not found")
return false, nil
} else {
return false, err
}
}
return true, nil
}

View File

@@ -26,6 +26,7 @@ const (
DATA_VOUCHER_LIST DATA_VOUCHER_LIST
DATA_ACTIVE_SYM DATA_ACTIVE_SYM
DATA_ACTIVE_BAL DATA_ACTIVE_BAL
DATA_BLOCKED_NUMBER
DATA_PUBLIC_KEY_REVERSE DATA_PUBLIC_KEY_REVERSE
DATA_ACTIVE_DECIMAL DATA_ACTIVE_DECIMAL
DATA_ACTIVE_ADDRESS DATA_ACTIVE_ADDRESS

View File

@@ -13,7 +13,7 @@
}, },
{ {
"input": "5", "input": "5",
"expectedContent": "PIN Management\n1:Change PIN\n2:Reset other's PIN\n3:Guard my PIN\n0:Back" "expectedContent": "PIN Management\n1:Change PIN\n2:Reset other's PIN\n0:Back"
}, },
{ {
"input": "1", "input": "1",

View File

@@ -0,0 +1 @@
Please confirm new PIN for:{{.retrieve_blocked_number}}

View File

@@ -0,0 +1,14 @@
CATCH pin_entry flag_incorrect_pin 1
RELOAD retrieve_blocked_number
MAP retrieve_blocked_number
CATCH invalid_others_pin flag_valid_pin 0
CATCH pin_reset_result flag_account_authorized 1
LOAD save_others_temporary_pin 6
RELOAD save_others_temporary_pin
MOUT back 0
HALT
INCMP _ 0
LOAD check_pin_mismatch 0
RELOAD check_pin_mismatch
CATCH others_pin_mismatch flag_pin_mismatch 1
INCMP pin_entry *

View File

@@ -3,5 +3,3 @@ MOUT back 0
HALT HALT
INCMP _ 0 INCMP _ 0
INCMP * pin_reset_success INCMP * pin_reset_success

View File

@@ -0,0 +1 @@
Enter other's phone number:

View File

@@ -0,0 +1,7 @@
CATCH no_admin_privilege flag_admin_privilege 0
LOAD reset_account_authorized 0
RELOAD reset_account_authorized
MOUT back 0
HALT
INCMP _ 0
INCMP enter_others_new_pin *

View File

@@ -0,0 +1 @@
Please enter new PIN for: {{.retrieve_blocked_number}}

View File

@@ -0,0 +1,12 @@
LOAD validate_blocked_number 6
RELOAD validate_blocked_number
CATCH unregistered_number flag_unregistered_number 1
LOAD retrieve_blocked_number 0
RELOAD retrieve_blocked_number
MAP retrieve_blocked_number
MOUT back 0
HALT
LOAD verify_new_pin 6
RELOAD verify_new_pin
INCMP _ 0
INCMP * confirm_others_new_pin

View File

@@ -1 +0,0 @@
Guard my PIN

View File

@@ -1 +0,0 @@
Linda PIN yangu

View File

@@ -0,0 +1 @@
The PIN you have entered is invalid.Please try a 4 digit number instead.

View File

@@ -0,0 +1,5 @@
MOUT retry 1
MOUT quit 9
HALT
INCMP enter_others_new_pin 1
INCMP quit 9

View File

@@ -0,0 +1 @@
You do not have privileges to perform this action

View File

@@ -0,0 +1,5 @@
MOUT quit 9
MOUT back 0
HALT
INCMP pin_management 0
INCMP quit 9

View File

@@ -0,0 +1 @@
The PIN you have entered is not a match

View File

@@ -0,0 +1,5 @@
MOUT retry 1
MOUT quit 9
HALT
INCMP _ 1
INCMP quit 9

View File

@@ -1,8 +1,8 @@
MOUT change_pin 1 MOUT change_pin 1
MOUT reset_pin 2 MOUT reset_pin 2
MOUT guard_pin 3
MOUT back 0 MOUT back 0
HALT HALT
INCMP _ 0 INCMP my_account 0
INCMP old_pin 1 INCMP old_pin 1
INCMP enter_other_number 2
INCMP . *

View File

@@ -0,0 +1 @@
PIN reset request for {{.retrieve_blocked_number}} was successful

View File

@@ -0,0 +1,8 @@
LOAD retrieve_blocked_number 0
MAP retrieve_blocked_number
LOAD reset_others_pin 6
MOUT back 0
MOUT quit 9
HALT
INCMP pin_management 0
INCMP quit 9

View File

@@ -6,5 +6,3 @@ MOUT quit 9
HALT HALT
INCMP main 0 INCMP main 0
INCMP quit 9 INCMP quit 9

View File

@@ -17,3 +17,5 @@ flag,flag_incorrect_date_format,23,this is set when the given year of birth is i
flag,flag_incorrect_voucher,24,this is set when the selected voucher is invalid flag,flag_incorrect_voucher,24,this is set when the selected voucher is invalid
flag,flag_api_call_error,25,this is set when communication to an external service fails flag,flag_api_call_error,25,this is set when communication to an external service fails
flag,flag_no_active_voucher,26,this is set when a user does not have an active voucher flag,flag_no_active_voucher,26,this is set when a user does not have an active voucher
flag,flag_admin_privilege,27,this is set when a user has admin privileges.
flag,flag_unregistered_number,28,this is set when an unregistered phonenumber tries to perform an action
1 flag flag_language_set 8 checks whether the user has set their prefered language
17 flag flag_incorrect_voucher 24 this is set when the selected voucher is invalid
18 flag flag_api_call_error 25 this is set when communication to an external service fails
19 flag flag_no_active_voucher 26 this is set when a user does not have an active voucher
20 flag flag_admin_privilege 27 this is set when a user has admin privileges.
21 flag flag_unregistered_number 28 this is set when an unregistered phonenumber tries to perform an action

View File

@@ -0,0 +1 @@
The number you have entered is either not registered with Sarafu or is invalid.

View File

@@ -0,0 +1,7 @@
LOAD reset_unregistered_number 0
RELOAD reset_unregistered_number
MOUT back 0
MOUT quit 9
HALT
INCMP ^ 0
INCMP quit 9