Compare commits

...

10 Commits

Author SHA1 Message Date
lash
1b712dbbb7 Instantiate config in main, add outputsize param 2024-09-05 04:11:20 +01:00
lash
3c6585e387 Add missing user db create 2024-09-05 04:07:45 +01:00
lash
7fc235c84c Draft example of dev-0.1.0 refactor 2024-09-05 03:29:44 +01:00
Carlosokumu
220c5b2081 remove commented code 2024-09-04 20:22:25 +03:00
Carlosokumu
2fc8a0e5a7 use fsDb for the resources 2024-09-04 19:57:08 +03:00
alfred-mk
8ffc5d67cc Removed mutex 2024-09-04 12:01:51 +03:00
alfred-mk
2d7b6bd125 Removed unused code 2024-09-03 22:28:48 +03:00
alfred-mk
5105e902f1 Process flags once and make them available across functions 2024-09-03 19:06:37 +03:00
Carlosokumu
19b2fa65fa Merge remote-tracking branch 'refs/remotes/origin/wip-flag-migration' into wip-flag-migration 2024-09-03 18:00:06 +03:00
Carlosokumu
ee4db50e00 remove unused code 2024-09-03 17:59:03 +03:00
6 changed files with 339 additions and 398 deletions

View File

@@ -10,160 +10,165 @@ import (
"path"
"strconv"
"git.defalsify.org/vise.git/cache"
fsdb "git.defalsify.org/vise.git/db/fs"
gdbmdb "git.defalsify.org/vise.git/db/gdbm"
"git.defalsify.org/vise.git/engine"
"git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/resource"
"git.defalsify.org/vise.git/state"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/urdt/ussd/internal/handlers/ussd"
)
var (
scriptDir = path.Join("services", "registration")
logg = logging.NewVanilla()
flags *FlagParser
)
func getFlags(fp string, debug bool) error {
Flags = NewFlagParser().WithDebug()
flags, err := Flags.Load(fp)
if err != nil {
return err
}
}
func getHandler(appFlags *asm.FlagParser, rs *resource.DbResource, pe *persist.Persister, userdataStore db.Db) (*ussd.Handlers, error) {
ussdHandlers, err := ussd.NewHandlers(appFlags pr.GetState(), dataStore)
if err != nil {
return nil, err
}
rs.AddLocalFunc("select_language", ussdHandlers.SetLanguage)
rs.AddLocalFunc("create_account", ussdHandlers.CreateAccount)
rs.AddLocalFunc("save_pin", ussdHandlers.SavePin)
rs.AddLocalFunc("verify_pin", ussdHandlers.VerifyPin)
rs.AddLocalFunc("check_identifier", ussdHandlers.CheckIdentifier)
rs.AddLocalFunc("check_account_status", ussdHandlers.CheckAccountStatus)
rs.AddLocalFunc("authorize_account", ussdHandlers.Authorize)
rs.AddLocalFunc("quit", ussdHandlers.Quit)
rs.AddLocalFunc("check_balance", ussdHandlers.CheckBalance)
rs.AddLocalFunc("validate_recipient", ussdHandlers.ValidateRecipient)
rs.AddLocalFunc("transaction_reset", ussdHandlers.TransactionReset)
rs.AddLocalFunc("max_amount", ussdHandlers.MaxAmount)
rs.AddLocalFunc("validate_amount", ussdHandlers.ValidateAmount)
rs.AddLocalFunc("reset_transaction_amount", ussdHandlers.ResetTransactionAmount)
rs.AddLocalFunc("get_recipient", ussdHandlers.GetRecipient)
rs.AddLocalFunc("get_sender", ussdHandlers.GetSender)
rs.AddLocalFunc("get_amount", ussdHandlers.GetAmount)
rs.AddLocalFunc("reset_incorrect", ussdHandlers.ResetIncorrectPin)
rs.AddLocalFunc("save_firstname", ussdHandlers.SaveFirstname)
rs.AddLocalFunc("save_familyname", ussdHandlers.SaveFamilyname)
rs.AddLocalFunc("save_gender", ussdHandlers.SaveGender)
rs.AddLocalFunc("save_location", ussdHandlers.SaveLocation)
rs.AddLocalFunc("save_yob", ussdHandlers.SaveYob)
rs.AddLocalFunc("save_offerings", ussdHandlers.SaveOfferings)
rs.AddLocalFunc("quit_with_balance", ussdHandlers.QuitWithBalance)
rs.AddLocalFunc("reset_account_authorized", ussdHandlers.ResetAccountAuthorized)
rs.AddLocalFunc("reset_allow_update", ussdHandlers.ResetAllowUpdate)
rs.AddLocalFunc("get_profile_info", ussdHandlers.GetProfileInfo)
rs.AddLocalFunc("verify_yob", ussdHandlers.VerifyYob)
rs.AddLocalFunc("reset_incorrect_date_format", ussdHandlers.ResetIncorrectYob)
rs.AddLocalFunc("set_reset_single_edit", ussdHandlers.SetResetSingleEdit)
rs.AddLocalFunc("initiate_transaction", ussdHandlers.InitiateTransaction)
return ussdHandlers, nil
}
func getPersister(dbDir string) (*persist.Persister, error) {
err = os.MkdirAll(dp, 0700)
if err != nil {
return nil, fmt.Errorf("state dir create exited with error: %v\n", err)
}
store := gdbmdb.NewGdbmDb()
storeFile := path.Join(dbDir, "states.gdbm")
store.Connect(ctx, storeFile)
pr := persist.NewPersister(store)
return pr
}
func getUserdataDb(dbDir string) {
store := gdbmdb.NewGdbmDb()
storeFile := path.Join(dbDir, "userdata.gdbm")
store.Connect(ctx, storeFile)
return store
}
func getResource(resourceDir string) (resource.Resource, error) {
store := fsdb.NewFsDb()
err = store.Connect(ctx, resourceDir)
if err != nil {
return err
}
rfs := resource.NewDbResource(store)
}
func getEngine(cfg Config, rs resource.Resource, pr *persister.Persister) {
en := engine.NewEngine(cfg, rfs)
en = en.WithPersister(pr)
return en
}
func main() {
var dir string
var dbDir string
var resourceDir string
var root string
var size uint
var sessionId string
flag.StringVar(&dir, "d", ".", "resource dir to read from")
flag.UintVar(&size, "s", 0, "max size of output")
flag.StringVar(&dbDir, "dbdir", ".state", "database dir to read from")
flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir")
flag.UintVar(&size, "s", 160, "max size of output")
flag.StringVar(&root, "root", "root", "entry point symbol")
flag.StringVar(&sessionId, "session-id", "default", "session id")
flag.Parse()
fmt.Fprintf(os.Stderr, "starting session at symbol '%s' using resource dir: %s\n", root, dir)
logg.Infof("starting session", "symbol", root, "dbdir", dbDir, "sessionid", sessionId, "outsize", size)
ctx := context.Background()
st := state.NewState(16)
st.UseDebug()
pfp := path.Join(scriptDir, "pp.csv")
file, err := os.Open(pfp)
fl, err := getFlags()
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to open CSV file: %v\n", err)
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
defer file.Close()
reader := csv.NewReader(file)
// Iterate through the CSV records and register the flags
for {
record, err := reader.Read()
if err != nil {
if err == io.EOF {
break
}
fmt.Fprintf(os.Stderr, "Error reading CSV file: %v\n", err)
os.Exit(1)
}
// Ensure the record starts with "flag" and has at least 3 columns
if len(record) < 3 || record[0] != "flag" {
continue
}
flagName := record[1]
flagValue, err := strconv.Atoi(record[2])
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to convert flag value %s to integer: %v\n", record[2], err)
continue
}
// Register the flag
state.FlagDebugger.Register(uint32(flagValue), flagName)
rs, err := getResource(resourceDir)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
pr, err := getDataPersister(dbDir)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
store, err := getUserdataDb(dataDir)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
hn, err := getHandlers(fl, rs, pr, store)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
rfs := resource.NewFsResource(scriptDir)
ca := cache.NewCache()
cfg := engine.Config{
Root: "root",
Root: sym,
SessionId: sessionId,
OutputSize: size,
FlagCount: uint32(16),
}
dp := path.Join(scriptDir, ".state")
err = os.MkdirAll(dp, 0700)
if err != nil {
fmt.Fprintf(os.Stderr, "state dir create exited with error: %v\n", err)
os.Exit(1)
}
pr := persist.NewFsPersister(dp)
en, err := engine.NewPersistedEngine(ctx, cfg, pr, rfs)
if err != nil {
pr = pr.WithContent(&st, ca)
err = pr.Save(cfg.SessionId)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to save state with error: %v\n", err)
}
en, err = engine.NewPersistedEngine(ctx, cfg, pr, rfs)
if err != nil {
fmt.Fprintf(os.Stderr, "engine create exited with error: %v\n", err)
os.Exit(1)
}
}
fp := path.Join(dp, sessionId)
ussdHandlers, err := ussd.NewHandlers(fp, &st,sessionId)
if err != nil {
fmt.Fprintf(os.Stderr, "handler setup failed with error: %v\n", err)
}
rfs.AddLocalFunc("select_language", ussdHandlers.SetLanguage)
rfs.AddLocalFunc("create_account", ussdHandlers.CreateAccount)
rfs.AddLocalFunc("save_pin", ussdHandlers.SavePin)
rfs.AddLocalFunc("verify_pin", ussdHandlers.VerifyPin)
rfs.AddLocalFunc("check_identifier", ussdHandlers.CheckIdentifier)
rfs.AddLocalFunc("check_account_status", ussdHandlers.CheckAccountStatus)
rfs.AddLocalFunc("authorize_account", ussdHandlers.Authorize)
rfs.AddLocalFunc("quit", ussdHandlers.Quit)
rfs.AddLocalFunc("check_balance", ussdHandlers.CheckBalance)
rfs.AddLocalFunc("validate_recipient", ussdHandlers.ValidateRecipient)
rfs.AddLocalFunc("transaction_reset", ussdHandlers.TransactionReset)
rfs.AddLocalFunc("max_amount", ussdHandlers.MaxAmount)
rfs.AddLocalFunc("validate_amount", ussdHandlers.ValidateAmount)
rfs.AddLocalFunc("reset_transaction_amount", ussdHandlers.ResetTransactionAmount)
rfs.AddLocalFunc("get_recipient", ussdHandlers.GetRecipient)
rfs.AddLocalFunc("get_sender", ussdHandlers.GetSender)
rfs.AddLocalFunc("get_amount", ussdHandlers.GetAmount)
rfs.AddLocalFunc("reset_incorrect", ussdHandlers.ResetIncorrectPin)
rfs.AddLocalFunc("save_firstname", ussdHandlers.SaveFirstname)
rfs.AddLocalFunc("save_familyname", ussdHandlers.SaveFamilyname)
rfs.AddLocalFunc("save_gender", ussdHandlers.SaveGender)
rfs.AddLocalFunc("save_location", ussdHandlers.SaveLocation)
rfs.AddLocalFunc("save_yob", ussdHandlers.SaveYob)
rfs.AddLocalFunc("save_offerings", ussdHandlers.SaveOfferings)
rfs.AddLocalFunc("quit_with_balance", ussdHandlers.QuitWithBalance)
rfs.AddLocalFunc("reset_account_authorized", ussdHandlers.ResetAccountAuthorized)
rfs.AddLocalFunc("reset_allow_update", ussdHandlers.ResetAllowUpdate)
rfs.AddLocalFunc("get_profile_info", ussdHandlers.GetProfileInfo)
rfs.AddLocalFunc("verify_yob", ussdHandlers.VerifyYob)
rfs.AddLocalFunc("reset_incorrect_date_format", ussdHandlers.ResetIncorrectYob)
rfs.AddLocalFunc("set_reset_single_edit", ussdHandlers.SetResetSingleEdit)
rfs.AddLocalFunc("initiate_transaction", ussdHandlers.InitiateTransaction)
cont, err := en.Init(ctx)
en.SetDebugger(engine.NewSimpleDebug(nil))
en := getEngine(cfg, rs, pr)
_, err = en.Init(ctx)
if err != nil {
fmt.Fprintf(os.Stderr, "engine init exited with error: %v\n", err)
os.Exit(1)
}
if !cont {
_, err = en.WriteResult(ctx, os.Stdout)
if err != nil {
fmt.Fprintf(os.Stderr, "dead init write error: %v\n", err)
os.Exit(1)
}
err = en.Finish()
if err != nil {
fmt.Fprintf(os.Stderr, "engine finish error: %v\n", err)
os.Exit(1)
}
os.Stdout.Write([]byte{0x0a})
os.Exit(0)
}
err = engine.Loop(ctx, en, os.Stdin, os.Stdout)
if err != nil {
fmt.Fprintf(os.Stderr, "loop exited with error: %v\n", err)

Submodule go-vise updated: 1f47a674d9...326bdb5018

View File

@@ -11,10 +11,13 @@ import (
"strings"
"git.defalsify.org/vise.git/asm"
"git.defalsify.org/vise.git/engine"
"git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/lang"
"git.defalsify.org/vise.git/resource"
"git.defalsify.org/vise.git/state"
"git.defalsify.org/vise.git/cache"
"git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/urdt/ussd/internal/handlers/server"
"git.grassecon.net/urdt/ussd/internal/utils"
"github.com/graygnuorg/go-gdbm"
@@ -22,9 +25,9 @@ import (
)
var (
logg = logging.NewVanilla().WithDomain("urdt_ussdhandler")
scriptDir = path.Join("services", "registration")
translationDir = path.Join(scriptDir, "locale")
//dbFile = path.Join(scriptDir, "userdata.gdbm")
)
const (
@@ -44,49 +47,29 @@ const (
AccountCreated = "ACCOUNTCREATED"
)
func toBytes(s string) []byte {
return []byte(s)
}
type FSData struct {
Path string
St *state.State
}
type FlagParserInterface interface {
GetFlag(key string) (uint32, error)
}
type Handlers struct {
fs *FSData
db *gdbm.Database
parser FlagParserInterface
accountFileHandler utils.AccountFileHandlerInterface
st *state.State
ca cache.Memory
userdataStore db.Db
flagManager *asm.FlagParser
accountFileHandler *utils.AccountFileHandler
accountService server.AccountServiceInterface
}
func NewHandlers(dir string, st *state.State, sessionId string) (*Handlers, error) {
filename := path.Join(scriptDir, sessionId+"_userdata.gdbm")
db, err := gdbm.Open(filename, gdbm.ModeWrcreat)
if err != nil {
panic(err)
}
pfp := path.Join(scriptDir, "pp.csv")
parser := asm.NewFlagParser()
_, err = parser.Load(pfp)
if err != nil {
return nil, err
}
return &Handlers{
db: db,
fs: &FSData{
Path: dir,
St: st,
},
parser: parser,
accountFileHandler: utils.NewAccountFileHandler(dir + "_data"),
func NewHandlers(appFlags *asm.FlagParser, pe *persist.Persister, userdataStore db.Db) (*Handlers, error) {
h := &Handlers{
st: pe.GetState(),
ca: pe.GetMemory(),
userdataStore: userdataStore,
flagManager: appFlags,
accountFileHandler: utils.NewAccountFileHandler(userdataStore),
accountService: &server.AccountService{},
}, nil
}
if h.st == nil || h.ca == nil || h.userdataStore == nil || h.flagManager == nil {
logg.Errorf("have nil for essential value in handler", "state", h.st, "cache", h.ca, "store", h.userdataStore, "flags", h.flagManager)
return nil, fmt.Errorf("have nil for essential value")
}
return h, nil
}
// Define the regex pattern as a constant
@@ -98,29 +81,10 @@ func isValidPIN(pin string) bool {
return match
}
func (h *Handlers) PreloadFlags(flagKeys []string) (map[string]uint32, error) {
flags := make(map[string]uint32)
for _, key := range flagKeys {
flag, err := h.parser.GetFlag(key)
if err != nil {
return nil, err
}
flags[key] = flag
}
return flags, nil
}
// SetLanguage sets the language across the menu
func (h *Handlers) SetLanguage(ctx context.Context, sym string, input []byte) (resource.Result, error) {
res := resource.Result{}
// Preload the required flag
flagKeys := []string{"flag_language_set"}
flags, err := h.PreloadFlags(flagKeys)
if err != nil {
return res, err
}
inputStr := string(input)
switch inputStr {
case "0":
@@ -132,71 +96,83 @@ func (h *Handlers) SetLanguage(ctx context.Context, sym string, input []byte) (r
default:
}
res.FlagSet = append(res.FlagSet, flags["flag_language_set"])
languageSetFlag, err := h.flagManager.GetFlag("flag_language_set")
if err != nil {
return res, err
}
res.FlagSet = append(res.FlagSet, languageSetFlag)
return res, nil
}
func (h *Handlers) createAccountNoExist(ctx context.Context, sessionId string, res *resource.Result) error {
accountResp, err := h.accountService.CreateAccount()
if err != nil {
flag_account_creation_failed, _ := h.flagManager.GetFlag("flag_account_creation_failed")
res.FlagSet = append(res.FlagSet, flag_account_creation_failed)
return err
}
// data := map[string]string{
// TrackingIdKey: accountResp.Result.TrackingId,
// PublicKeyKey: accountResp.Result.PublicKey,
// CustodialIdKey: accountResp.Result.CustodialId.String(),
// }
data := map[utils.DataTyp]string{
utils.DATA_TRACKING_ID: accountResp.Result.TrackingId,
utils.DATA_PUBLIC_KEY: accountResp.Result.PublicKey,
utils.DATA_CUSTODIAL_ID: accountResp.Result.CustodialId.String(),
}
for key, value := range data {
err := utils.WriteEntry(ctx, h.userdataStore, sessionId, key, []byte(value))
if err != nil {
return err
}
}
// NOTE: this is covered by the flag, no?
//key := []byte(AccountCreated)
//value := []byte("1")
//h.db.Store(key, value, true)
flag_account_created, _ := h.flagManager.GetFlag("flag_account_created")
res.FlagSet = append(res.FlagSet, flag_account_created)
return err
}
// CreateAccount checks if any account exists on the JSON data file, and if not
// creates an account on the API,
// sets the default values and flags
func (h *Handlers) CreateAccount(ctx context.Context, sym string, input []byte) (resource.Result, error) {
res := resource.Result{}
// Preload the required flags
flagKeys := []string{"flag_account_created", "flag_account_creation_failed"}
flags, err := h.PreloadFlags(flagKeys)
if err != nil {
return res, err
var err error
var res resource.Result
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
_, err = h.db.Fetch([]byte(AccountCreated))
if err != nil {
if errors.Is(err, gdbm.ErrItemNotFound) {
accountResp, err := h.accountService.CreateAccount()
if err != nil {
res.FlagSet = append(res.FlagSet, flags["flag_account_creation_failed"])
return res, err
}
data := map[string]string{
TrackingIdKey: accountResp.Result.TrackingId,
PublicKeyKey: accountResp.Result.PublicKey,
CustodialIdKey: accountResp.Result.CustodialId.String(),
}
for key, value := range data {
err := h.db.Store(toBytes(key), toBytes(value), true)
if err != nil {
return res, err
}
}
key := []byte(AccountCreated)
value := []byte("1")
h.db.Store(key, value, true)
res.FlagSet = append(res.FlagSet, flags["flag_account_created"])
return res, err
} else {
return res, err
_, err = utils.ReadEntry(ctx, h.userdataStore, sessionId, utils.DATA_ACCOUNT_CREATED)
if err != nil {
if db.IsNotFound(err) {
err = h.createAccountNoExist(ctx, sessionId, &res)
}
} else {
return res, nil
}
return res, err
}
// SavePin persists the user's PIN choice into the filesystem
func (h *Handlers) SavePin(ctx context.Context, sym string, input []byte) (resource.Result, error) {
res := resource.Result{}
flagKeys := []string{"flag_incorrect_pin"}
flags, err := h.PreloadFlags(flagKeys)
if err != nil {
return res, err
}
flag_incorrect_pin, _ := h.flagManager.GetFlag("flag_incorrect_pin")
accountPIN := string(input)
// Validate that the PIN is a 4-digit number
if !isValidPIN(accountPIN) {
res.FlagSet = append(res.FlagSet, flags["flag_incorrect_pin"])
res.FlagSet = append(res.FlagSet, flag_incorrect_pin)
return res, nil
}
res.FlagReset = append(res.FlagReset, flags["flag_incorrect_pin"])
res.FlagReset = append(res.FlagReset, flag_incorrect_pin)
key := []byte(AccountPin)
value := []byte(accountPIN)
@@ -210,25 +186,21 @@ func (h *Handlers) SetResetSingleEdit(ctx context.Context, sym string, input []b
res := resource.Result{}
menuOption := string(input)
// Preload the required flags
flagKeys := []string{"flag_allow_update", "flag_single_edit"}
flags, err := h.PreloadFlags(flagKeys)
if err != nil {
return res, err
}
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
flag_single_edit, _ := h.flagManager.GetFlag("flag_single_edit")
switch menuOption {
case "2":
res.FlagReset = append(res.FlagReset, flags["flag_allow_update"])
res.FlagSet = append(res.FlagSet, flags["flag_single_edit"])
res.FlagReset = append(res.FlagReset, flag_allow_update)
res.FlagSet = append(res.FlagSet, flag_single_edit)
case "3":
res.FlagReset = append(res.FlagReset, flags["flag_allow_update"])
res.FlagSet = append(res.FlagSet, flags["flag_single_edit"])
res.FlagReset = append(res.FlagReset, flag_allow_update)
res.FlagSet = append(res.FlagSet, flag_single_edit)
case "4":
res.FlagReset = append(res.FlagReset, flags["flag_allow_update"])
res.FlagSet = append(res.FlagSet, flags["flag_single_edit"])
res.FlagReset = append(res.FlagReset, flag_allow_update)
res.FlagSet = append(res.FlagSet, flag_single_edit)
default:
res.FlagReset = append(res.FlagReset, flags["flag_single_edit"])
res.FlagReset = append(res.FlagReset, flag_single_edit)
}
return res, nil
@@ -240,23 +212,20 @@ func (h *Handlers) SetResetSingleEdit(ctx context.Context, sym string, input []b
func (h *Handlers) VerifyPin(ctx context.Context, sym string, input []byte) (resource.Result, error) {
res := resource.Result{}
// Preload the required flags
flagKeys := []string{"flag_valid_pin", "flag_pin_mismatch", "flag_pin_set"}
flags, err := h.PreloadFlags(flagKeys)
if err != nil {
return res, err
}
flag_valid_pin, _ := h.flagManager.GetFlag("flag_valid_pin")
flag_pin_mismatch, _ := h.flagManager.GetFlag("flag_pin_mismatch")
flag_pin_set, _ := h.flagManager.GetFlag("flag_pin_set")
AccountPin, err := h.db.Fetch([]byte(AccountPin))
if err != nil {
return res, err
}
if bytes.Equal(input, AccountPin) {
res.FlagSet = []uint32{flags["flag_valid_pin"]}
res.FlagReset = []uint32{flags["flag_pin_mismatch"]}
res.FlagSet = append(res.FlagSet, flags["flag_pin_set"])
res.FlagSet = []uint32{flag_valid_pin}
res.FlagReset = []uint32{flag_pin_mismatch}
res.FlagSet = append(res.FlagSet, flag_pin_set)
} else {
res.FlagSet = []uint32{flags["flag_pin_mismatch"]}
res.FlagSet = []uint32{flag_pin_mismatch}
}
return res, nil
@@ -265,7 +234,6 @@ func (h *Handlers) VerifyPin(ctx context.Context, sym string, input []byte) (res
// codeFromCtx retrieves language codes from the context that can be used for handling translations
func codeFromCtx(ctx context.Context) string {
var code string
engine.Logg.DebugCtxf(ctx, "in msg", "ctx", ctx, "val", code)
if ctx.Value("Language") != nil {
lang := ctx.Value("Language").(lang.Language)
code = lang.Code
@@ -363,14 +331,9 @@ func (h *Handlers) SaveOfferings(ctx context.Context, sym string, input []byte)
func (h *Handlers) ResetAllowUpdate(ctx context.Context, sym string, input []byte) (resource.Result, error) {
res := resource.Result{}
// Preload the required flag
flagKeys := []string{"flag_allow_update"}
flags, err := h.PreloadFlags(flagKeys)
if err != nil {
return res, err
}
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
res.FlagReset = append(res.FlagReset, flags["flag_allow_update"])
res.FlagReset = append(res.FlagReset, flag_allow_update)
return res, nil
}
@@ -378,14 +341,9 @@ func (h *Handlers) ResetAllowUpdate(ctx context.Context, sym string, input []byt
func (h *Handlers) ResetAccountAuthorized(ctx context.Context, sym string, input []byte) (resource.Result, error) {
res := resource.Result{}
// Preload the required flags
flagKeys := []string{"flag_account_authorized"}
flags, err := h.PreloadFlags(flagKeys)
if err != nil {
return res, err
}
flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized")
res.FlagReset = append(res.FlagReset, flags["flag_account_authorized"])
res.FlagReset = append(res.FlagReset, flag_account_authorized)
return res, nil
}
@@ -404,26 +362,25 @@ func (h *Handlers) CheckIdentifier(ctx context.Context, sym string, input []byte
// It sets the required flags that control the flow.
func (h *Handlers) Authorize(ctx context.Context, sym string, input []byte) (resource.Result, error) {
res := resource.Result{}
// Preload the required flags
flagKeys := []string{"flag_incorrect_pin", "flag_account_authorized", "flag_allow_update"}
flags, err := h.PreloadFlags(flagKeys)
if err != nil {
return res, err
}
flag_incorrect_pin, _ := h.flagManager.GetFlag("flag_incorrect_pin")
flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized")
flag_allow_update, _ := h.flagManager.GetFlag("flag_allow_update")
storedpin, err := h.db.Fetch([]byte(AccountPin))
if err == nil {
if len(input) == 4 {
if bytes.Equal(input, storedpin) {
if h.fs.St.MatchFlag(flags["flag_account_authorized"], false) {
res.FlagReset = append(res.FlagReset, flags["flag_incorrect_pin"])
res.FlagSet = append(res.FlagSet, flags["flag_allow_update"], flags["flag_account_authorized"])
if h.fs.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)
} else {
res.FlagSet = append(res.FlagSet, flags["flag_allow_update"])
res.FlagReset = append(res.FlagReset, flags["flag_account_authorized"])
res.FlagSet = append(res.FlagSet, flag_allow_update)
res.FlagReset = append(res.FlagReset, flag_account_authorized)
}
} else {
res.FlagSet = append(res.FlagSet, flags["flag_incorrect_pin"])
res.FlagReset = append(res.FlagReset, flags["flag_account_authorized"])
res.FlagSet = append(res.FlagSet, flag_incorrect_pin)
res.FlagReset = append(res.FlagReset, flag_account_authorized)
return res, nil
}
}
@@ -439,14 +396,9 @@ func (h *Handlers) Authorize(ctx context.Context, sym string, input []byte) (res
func (h *Handlers) ResetIncorrectPin(ctx context.Context, sym string, input []byte) (resource.Result, error) {
res := resource.Result{}
// Preload the required flag
flagKeys := []string{"flag_incorrect_pin"}
flags, err := h.PreloadFlags(flagKeys)
if err != nil {
return res, err
}
flag_incorrect_pin, _ := h.flagManager.GetFlag("flag_incorrect_pin")
res.FlagReset = append(res.FlagReset, flags["flag_incorrect_pin"])
res.FlagReset = append(res.FlagReset, flag_incorrect_pin)
return res, nil
}
@@ -455,12 +407,9 @@ func (h *Handlers) ResetIncorrectPin(ctx context.Context, sym string, input []by
func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []byte) (resource.Result, error) {
res := resource.Result{}
// Preload the required flags
flagKeys := []string{"flag_account_success", "flag_account_pending"}
flags, err := h.PreloadFlags(flagKeys)
if err != nil {
return res, err
}
flag_account_success, _ := h.flagManager.GetFlag("flag_account_success")
flag_account_pending, _ := h.flagManager.GetFlag("flag_account_pending")
trackingId, err := h.db.Fetch([]byte(TrackingIdKey))
if err != nil {
@@ -475,22 +424,22 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b
}
err = h.db.Store(toBytes(AccountStatus), toBytes(status), true)
err = h.db.Store([]byte(AccountStatus), []byte(status), true)
if err != nil {
return res, nil
}
err = h.db.Store(toBytes(TrackingIdKey), toBytes(status), true)
err = h.db.Store([]byte(TrackingIdKey), []byte(status), true)
if err != nil {
return res, nil
}
if status == "SUCCESS" {
res.FlagSet = append(res.FlagSet, flags["flag_account_success"])
res.FlagReset = append(res.FlagReset, flags["flag_account_pending"])
res.FlagSet = append(res.FlagSet, flag_account_success)
res.FlagReset = append(res.FlagReset, flag_account_pending)
} else {
res.FlagReset = append(res.FlagReset, flags["flag_account_success"])
res.FlagSet = append(res.FlagSet, flags["flag_account_pending"])
res.FlagReset = append(res.FlagReset, flag_account_success)
res.FlagSet = append(res.FlagSet, flag_account_pending)
}
return res, nil
}
@@ -499,19 +448,14 @@ func (h *Handlers) CheckAccountStatus(ctx context.Context, sym string, input []b
func (h *Handlers) Quit(ctx context.Context, sym string, input []byte) (resource.Result, error) {
res := resource.Result{}
// Preload the required flags
flagKeys := []string{"flag_account_authorized"}
flags, err := h.PreloadFlags(flagKeys)
if err != nil {
return res, err
}
flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized")
code := codeFromCtx(ctx)
l := gotext.NewLocale(translationDir, code)
l.AddDomain("default")
res.Content = l.Get("Thank you for using Sarafu. Goodbye!")
res.FlagReset = append(res.FlagReset, flags["flag_account_authorized"])
res.FlagReset = append(res.FlagReset, flag_account_authorized)
return res, nil
}
@@ -519,25 +463,20 @@ func (h *Handlers) Quit(ctx context.Context, sym string, input []byte) (resource
func (h *Handlers) VerifyYob(ctx context.Context, sym string, input []byte) (resource.Result, error) {
res := resource.Result{}
// Preload the required flag
flagKeys := []string{"flag_incorrect_date_format"}
flags, err := h.PreloadFlags(flagKeys)
if err != nil {
return res, err
}
flag_incorrect_date_format, _ := h.flagManager.GetFlag("flag_incorrect_date_format")
date := string(input)
_, err = strconv.Atoi(date)
_, err := strconv.Atoi(date)
if err != nil {
// If conversion fails, input is not numeric
res.FlagSet = append(res.FlagSet, flags["flag_incorrect_date_format"])
res.FlagSet = append(res.FlagSet, flag_incorrect_date_format)
return res, nil
}
if len(date) == 4 {
res.FlagReset = append(res.FlagReset, flags["flag_incorrect_date_format"])
res.FlagReset = append(res.FlagReset, flag_incorrect_date_format)
} else {
res.FlagSet = append(res.FlagSet, flags["flag_incorrect_date_format"])
res.FlagSet = append(res.FlagSet, flag_incorrect_date_format)
}
return res, nil
@@ -547,14 +486,9 @@ func (h *Handlers) VerifyYob(ctx context.Context, sym string, input []byte) (res
func (h *Handlers) ResetIncorrectYob(ctx context.Context, sym string, input []byte) (resource.Result, error) {
res := resource.Result{}
// Preload the required flags
flagKeys := []string{"flag_incorrect_date_format"}
flags, err := h.PreloadFlags(flagKeys)
if err != nil {
return res, err
}
flag_incorrect_date_format, _ := h.flagManager.GetFlag("flag_incorrect_date_format")
res.FlagReset = append(res.FlagReset, flags["flag_incorrect_date_format"])
res.FlagReset = append(res.FlagReset, flag_incorrect_date_format)
return res, nil
}
@@ -582,16 +516,12 @@ func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []by
res := resource.Result{}
recipient := string(input)
flagKeys := []string{"flag_invalid_recipient"}
flags, err := h.PreloadFlags(flagKeys)
if err != nil {
return res, err
}
flag_invalid_recipient, _ := h.flagManager.GetFlag("flag_invalid_recipient")
if recipient != "0" {
// mimic invalid number check
if recipient == "000" {
res.FlagSet = append(res.FlagSet, flags["flag_invalid_recipient"])
res.FlagSet = append(res.FlagSet, flag_invalid_recipient)
res.Content = recipient
return res, nil
@@ -612,14 +542,10 @@ func (h *Handlers) ValidateRecipient(ctx context.Context, sym string, input []by
func (h *Handlers) TransactionReset(ctx context.Context, sym string, input []byte) (resource.Result, error) {
res := resource.Result{}
// Preload the required flags
flagKeys := []string{"flag_invalid_recipient", "flag_invalid_recipient_with_invite"}
flags, err := h.PreloadFlags(flagKeys)
if err != nil {
return res, err
}
flag_invalid_recipient, _ := h.flagManager.GetFlag("flag_invalid_recipient")
flag_invalid_recipient_with_invite, _ := h.flagManager.GetFlag("flag_invalid_recipient_with_invite")
err = h.db.Delete([]byte(Amount))
err := h.db.Delete([]byte(Amount))
if err != nil && !errors.Is(err, gdbm.ErrItemNotFound) {
return res, err
}
@@ -628,7 +554,7 @@ func (h *Handlers) TransactionReset(ctx context.Context, sym string, input []byt
return res, err
}
res.FlagReset = append(res.FlagReset, flags["flag_invalid_recipient"], flags["flag_invalid_recipient_with_invite"])
res.FlagReset = append(res.FlagReset, flag_invalid_recipient, flag_invalid_recipient_with_invite)
return res, nil
}
@@ -637,19 +563,14 @@ func (h *Handlers) TransactionReset(ctx context.Context, sym string, input []byt
func (h *Handlers) ResetTransactionAmount(ctx context.Context, sym string, input []byte) (resource.Result, error) {
res := resource.Result{}
// Preload the required flag
flagKeys := []string{"flag_invalid_amount"}
flags, err := h.PreloadFlags(flagKeys)
if err != nil {
return res, err
}
flag_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount")
err = h.db.Delete([]byte(Amount))
err := h.db.Delete([]byte(Amount))
if err != nil && !errors.Is(err, gdbm.ErrItemNotFound) {
return res, err
}
res.FlagReset = append(res.FlagReset, flags["flag_invalid_amount"])
res.FlagReset = append(res.FlagReset, flag_invalid_amount)
return res, nil
}
@@ -677,12 +598,8 @@ func (h *Handlers) MaxAmount(ctx context.Context, sym string, input []byte) (res
// it is not more than the current balance.
func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte) (resource.Result, error) {
res := resource.Result{}
// Preload the required flag
flagKeys := []string{"flag_invalid_amount"}
flags, err := h.PreloadFlags(flagKeys)
if err != nil {
return res, err
}
flag_invalid_amount, _ := h.flagManager.GetFlag("flag_invalid_amount")
amountStr := string(input)
publicKey, err := h.db.Fetch([]byte(PublicKeyKey))
@@ -712,20 +629,20 @@ func (h *Handlers) ValidateAmount(ctx context.Context, sym string, input []byte)
re := regexp.MustCompile(`^(\d+(\.\d+)?)\s*(?:CELO)?$`)
matches := re.FindStringSubmatch(strings.TrimSpace(amountStr))
if len(matches) < 2 {
res.FlagSet = append(res.FlagSet, flags["flag_invalid_amount"])
res.FlagSet = append(res.FlagSet, flag_invalid_amount)
res.Content = amountStr
return res, nil
}
inputAmount, err := strconv.ParseFloat(matches[1], 64)
if err != nil {
res.FlagSet = append(res.FlagSet, flags["flag_invalid_amount"])
res.FlagSet = append(res.FlagSet, flag_invalid_amount)
res.Content = amountStr
return res, nil
}
if inputAmount > balanceValue {
res.FlagSet = append(res.FlagSet, flags["flag_invalid_amount"])
res.FlagSet = append(res.FlagSet, flag_invalid_amount)
res.Content = amountStr
return res, nil
}
@@ -755,11 +672,9 @@ func (h *Handlers) GetRecipient(ctx context.Context, sym string, input []byte) (
return res, nil
}
// GetSender retrieves the public key from a JSON data file.
// GetSender retrieves the public key from the Gdbm Db
func (h *Handlers) GetSender(ctx context.Context, sym string, input []byte) (resource.Result, error) {
res := resource.Result{}
//accountData, err := h.accountFileHandler.ReadAccountData()
publicKey, err := h.db.Fetch([]byte(PublicKeyKey))
if err != nil {
return res, err
@@ -770,7 +685,7 @@ func (h *Handlers) GetSender(ctx context.Context, sym string, input []byte) (res
return res, nil
}
// GetAmount retrieves the amount from a JSON data file.
// GetAmount retrieves the amount from teh Gdbm Db
func (h *Handlers) GetAmount(ctx context.Context, sym string, input []byte) (resource.Result, error) {
res := resource.Result{}
amount, err := h.db.Fetch([]byte(Amount))
@@ -787,12 +702,7 @@ func (h *Handlers) GetAmount(ctx context.Context, sym string, input []byte) (res
func (h *Handlers) QuitWithBalance(ctx context.Context, sym string, input []byte) (resource.Result, error) {
res := resource.Result{}
// Preload the required flag
flagKeys := []string{"flag_account_authorized"}
flags, err := h.PreloadFlags(flagKeys)
if err != nil {
return res, err
}
flag_account_authorized, _ := h.flagManager.GetFlag("flag_account_authorized")
code := codeFromCtx(ctx)
l := gotext.NewLocale(translationDir, code)
@@ -806,7 +716,7 @@ func (h *Handlers) QuitWithBalance(ctx context.Context, sym string, input []byte
return res, nil
}
res.Content = l.Get("Your account balance is %s", balance)
res.FlagReset = append(res.FlagReset, flags["flag_account_authorized"])
res.FlagReset = append(res.FlagReset, flag_account_authorized)
return res, nil
}
@@ -835,10 +745,9 @@ func (h *Handlers) InitiateTransaction(ctx context.Context, sym string, input []
res.Content = l.Get("Your request has been sent. %s will receive %s from %s.", string(recipient), string(amount), string(publicKey))
account_authorized_flag, err := h.parser.GetFlag("flag_account_authorized")
account_authorized_flag, err := h.flagManager.GetFlag("flag_account_authorized")
if err != nil {
return res, nil
return res, err
}
res.FlagReset = append(res.FlagReset, account_authorized_flag)

View File

@@ -1,25 +1,25 @@
package utils
import (
"context"
"encoding/json"
"os"
"git.defalsify.org/vise.git/db"
)
type AccountFileHandler struct {
FilePath string
store db.Db
}
func NewAccountFileHandler(path string) *AccountFileHandler {
return &AccountFileHandler{FilePath: path}
}
func (afh *AccountFileHandler) ReadAccountData() (map[string]string, error) {
jsonData, err := os.ReadFile(afh.FilePath)
if err != nil {
return nil, err
func NewAccountFileHandler(store db.Db) *AccountFileHandler {
return &AccountFileHandler{
store: store,
}
}
func (afh *AccountFileHandler) ReadAccountData(ctx context.Context, sessionId string) (map[string]string, error) {
var accountData map[string]string
jsonData, err := ReadEntry(ctx, afh.store, sessionId, DATA_ACCOUNT)
err = json.Unmarshal(jsonData, &accountData)
if err != nil {
return nil, err
@@ -28,19 +28,10 @@ func (afh *AccountFileHandler) ReadAccountData() (map[string]string, error) {
return accountData, nil
}
func (afh *AccountFileHandler) WriteAccountData(accountData map[string]string) error {
jsonData, err := json.Marshal(accountData)
func (afh *AccountFileHandler) WriteAccountData(ctx context.Context, sessionId string, accountData map[string]string) error {
b, err := json.Marshal(accountData)
if err != nil {
return err
}
return os.WriteFile(afh.FilePath, jsonData, 0644)
}
func (afh *AccountFileHandler) EnsureFileExists() error {
f, err := os.OpenFile(afh.FilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
return f.Close()
return WriteEntry(ctx, afh.store, sessionId, DATA_ACCOUNT, b)
}

48
internal/utils/db.go Normal file
View File

@@ -0,0 +1,48 @@
package utils
import (
"context"
"encoding/binary"
"git.defalsify.org/vise.git/db"
)
type DataTyp uint16
const (
DATA_ACCOUNT DataTyp = iota
DATA_ACCOUNT_CREATED
DATA_TRACKING_ID
DATA_PUBLIC_KEY
DATA_CUSTODIAL_ID
)
func typToBytes(typ DataTyp) []byte {
var b []byte
binary.BigEndian.PutUint16(b, uint16(typ))
return b
}
func packKey(typ DataTyp, data []byte) []byte {
v := typToBytes(typ)
return append(v, data...)
}
func ReadEntry(ctx context.Context, store db.Db, sessionId string, typ DataTyp) ([]byte, error) {
store.SetPrefix(db.DATATYPE_USERDATA)
store.SetSession(sessionId)
k := packKey(typ, []byte(sessionId))
b, err := store.Get(ctx, k)
if err != nil {
return nil, err
}
return b, nil
}
func WriteEntry(ctx context.Context, store db.Db, sessionId string, typ DataTyp, value []byte) error {
store.SetPrefix(db.DATATYPE_USERDATA)
store.SetSession(sessionId)
k := packKey(typ, []byte(sessionId))
return store.Put(ctx, k, value)
}

View File

@@ -1,13 +1 @@
package utils
type AccountFileHandlerInterface interface {
EnsureFileExists() error
ReadAccountData() (map[string]string, error)
WriteAccountData(data map[string]string) error
}