Compare commits

..

60 Commits

Author SHA1 Message Date
alfred-mk
1e8d5b1b83 Remove left over code comment 2025-02-06 16:42:39 +03:00
alfred-mk
628a57ea10 Only clear the temporary data once at main.vis 2025-02-06 16:42:07 +03:00
alfred-mk
a37908323f Remove early LOAD statement 2025-02-06 16:32:03 +03:00
lash
9c27be3a9d Update sarafu-api dep 2025-02-06 12:24:35 +00:00
b95452ae5f Merge pull request 'clear-temporary-valua-after-use' (#21) from clear-temporary-valua-after-use into master
Reviewed-on: #21
2025-02-06 13:18:41 +01:00
Carlosokumu
6b3b8ffabe add alias request and resolve logs 2025-02-06 14:57:29 +03:00
alfred-mk
6647416115 Return an error if the temporary value is empty 2025-02-06 14:38:11 +03:00
alfred-mk
4155b267ee Clear the temporary value after use 2025-02-06 14:23:42 +03:00
0f2d6def23 Merge pull request 'lash/custom-engin' (#20) from lash/custom-engin into master
Some checks failed
release / docker (push) Has been cancelled
Reviewed-on: #20
2025-02-06 11:11:48 +01:00
lash
c13768d782 Remove custom engine 2025-02-05 17:56:08 +00:00
lash
af4b075df3 Add reset on empty to ssh 2025-02-05 17:45:31 +00:00
lash
1d7027905d Use simplified reset on empty input solution 2025-02-05 17:44:29 +00:00
lash
6c77d04284 Merge branch 'lash/async-inputs' into lash/custom-engin 2025-02-05 16:27:10 +00:00
lash
12acd508b1 Allow empty input in async cmd 2025-02-05 16:26:17 +00:00
alfred-mk
f88e253486 Call the engine Reset 2025-02-05 19:16:25 +03:00
alfred-mk
68597ea7cc Return the Sarafu Engine in GetEngine 2025-02-05 19:08:36 +03:00
alfred-mk
3d9eeddab8 Remove the Move to top node on empty input test case 2025-02-05 19:07:35 +03:00
alfred-mk
df58f69032 Remove input length check on menuhandler Init 2025-02-05 19:02:23 +03:00
lash
fdde1bb979 Add missing services import in ssh 2025-02-05 10:28:20 +00:00
lash
23cadc6178 Reinstate loading handlerfuncs in cmd, ssh clients 2025-02-05 10:21:21 +00:00
1918ea37d5 Merge pull request 'Bug fixes and menu improvement' (#19) from minor-bug-fixes into master
Reviewed-on: #19
Reviewed-by: lash <accounts-grassrootseconomics@holbrook.no>
2025-02-04 14:36:20 +01:00
lash
422b651097 Add missing file 2025-02-04 13:33:44 +00:00
lash
861d04dbfd WIP Implement custom engine 2025-02-04 13:25:17 +00:00
Carlosokumu
f7873bfef7 add mock state to failing tests 2025-02-04 10:16:12 +03:00
Carlosokumu
815e3b2a25 remove unused handler 2025-02-04 09:46:33 +03:00
Carlosokumu
f9a9a9b4a6 preload all common functions 2025-02-04 08:44:10 +03:00
Carlosokumu
04429ab74c fix: wrong pin count by load and reload handlers 2025-02-04 08:43:55 +03:00
Carlosokumu
d3f1a14e71 replace back with retry option 2025-02-04 08:41:55 +03:00
Carlosokumu
5722d4f8dd reset flags on back navigation,process only numeric pin entries 2025-02-04 08:41:06 +03:00
carlos
cad18c9e64 Merge pull request 'use the latest changes from grassrootseconomics/visedriver-africastalking' (#17) from update-dependency into master
Some checks failed
release / docker (push) Has been cancelled
Reviewed-on: #17
2025-01-29 09:18:49 +01:00
alfred-mk
fbff584bb4 use the latest changes from grassrootseconomics/visedriver-africastalking 2025-01-29 10:14:01 +03:00
d2f75c693a Merge pull request 'alias-fqdn' (#9) from alias-fqdn into master
Reviewed-on: #9
2025-01-25 13:46:29 +01:00
Carlosokumu
363c35efed update test data file 2025-01-25 09:55:39 +03:00
carlos
0f361a065b Merge branch 'master' into alias-fqdn 2025-01-24 13:08:29 +01:00
lash
4d1045a9f9 Adapt override to non-pointer values 2025-01-24 15:03:47 +03:00
lash
f3a6485bb3 Avoid overwrite of env configs 2025-01-24 15:02:31 +03:00
Carlosokumu
cd37adc288 update test 2025-01-24 15:02:30 +03:00
Carlosokumu
6f0994d692 feat: show alias as part of the profile information 2025-01-24 15:02:30 +03:00
lash
fbaba15776 Adapt override to non-pointer values 2025-01-24 10:15:37 +00:00
lash
9a094f440f Avoid overwrite of env configs 2025-01-24 08:47:23 +00:00
carlos
6c77ff58ab Merge branch 'master' into alias-fqdn 2025-01-24 09:44:50 +01:00
Carlosokumu
c8ddafcf66 run go mod tidy 2025-01-24 11:41:25 +03:00
Carlosokumu
5f1a659789 request alias on initial profile setup 2025-01-24 11:41:00 +03:00
Carlosokumu
0d4be0f7fc return nil when error is key not found 2025-01-24 10:12:28 +03:00
Carlosokumu
b6161da749 fix failing test 2025-01-24 09:32:21 +03:00
f1c4d5f1f9 docker: change bin name -> sarafu-at 2025-01-24 09:26:00 +03:00
73b876dbdd ci/cd: add Dockerfile and GH builds 2025-01-24 09:25:09 +03:00
Carlosokumu
18e865ba26 set UseApi and storageservice to HttpAccountService 2025-01-24 07:59:33 +03:00
Carlosokumu
d7c909f028 update sarafu-api dep 2025-01-24 07:58:03 +03:00
Carlosokumu
908a52cda6 Merge branch 'master' into alias-fqdn 2025-01-24 07:41:33 +03:00
carlos
526dc822fb Merge pull request 'remove unused New conn argument' (#14) from fix-remote-new-args into master
Reviewed-on: #14
2025-01-23 09:29:25 +01:00
Carlosokumu
ec6b078de3 fix: import config and model packages 2025-01-21 15:23:21 +03:00
Carlosokumu
0b4fde9d1e Merge branch 'master' into alias-fqdn 2025-01-21 12:53:50 +03:00
Carlosokumu
66be350ad1 remove accountservice implementation check 2025-01-21 12:48:17 +03:00
Carlosokumu
1e69f2167a Merge branch 'master' into alias-fqdn 2025-01-20 12:32:29 +03:00
Carlosokumu
f435046385 Merge branch 'master' into alias-fqdn 2025-01-18 08:01:58 +03:00
Carlosokumu
efaf0ab22e feat: construct an account alias 2025-01-18 07:53:42 +03:00
Carlosokumu
e29bcb5b27 define and parse alias search domains 2025-01-18 07:52:08 +03:00
Carlosokumu
cdb22f8cbb add key for the account alias 2025-01-18 07:50:55 +03:00
Carlosokumu
6aa4bd8906 add alias search domains 2025-01-17 15:02:58 +03:00
38 changed files with 484 additions and 206 deletions

16
.dockerignore Normal file
View File

@@ -0,0 +1,16 @@
/**
!/args
!/cmd/africastalking
!/cmd/ssh
!/config
!/debug
!/handlers
!/internal
!/profile
!/services
!/ssh
!/store
!/LICENSE
!/README.md
!/go.*
!/.env.example

View File

@@ -18,3 +18,6 @@ DATA_URL_BASE=http://localhost:5006
#Language
DEFAULT_LANGUAGE=eng
LANGUAGES=eng, swa
#Alias search domains
ALIAS_SEARCH_DOMAINS=sarafu.local, sarafu.eth

56
.github/workflows/docker.yaml vendored Normal file
View File

@@ -0,0 +1,56 @@
name: release
on:
push:
tags:
- "v*"
jobs:
docker:
runs-on: ubuntu-latest
steps:
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Check out repo
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Cache Docker layers
uses: actions/cache@v3
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Login to GHCR Docker registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set outputs
run: |
echo "RELEASE_TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV \
&& echo "RELEASE_SHORT_COMMIT=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
- name: Build and push image
uses: docker/build-push-action@v2
with:
context: ./
file: ./Dockerfile
platforms: linux/amd64
push: true
build-args: |
BUILD=${{ env.RELEASE_SHORT_COMMIT }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache
tags: |
ghcr.io/grassrootseconomics/sarafu-vise:latest
ghcr.io/grassrootseconomics/sarafu-vise:${{ env.RELEASE_TAG }}

50
Dockerfile Normal file
View File

@@ -0,0 +1,50 @@
FROM golang:1.23.4-bookworm AS build
ENV CGO_ENABLED=1
ARG BUILDPLATFORM
ARG TARGETPLATFORM
ARG BUILD=dev
WORKDIR /build
RUN apt-get update && apt-get install -y --no-install-recommends \
libgdbm-dev \
git \
&& rm -rf /var/lib/apt/lists/*
RUN git clone https://git.defalsify.org/vise.git go-vise
COPY . ./sarafu-vise
WORKDIR /build/sarafu-vise/services/registration
RUN echo "Compiling go-vise files"
RUN make VISE_PATH=/build/go-vise -B
WORKDIR /build/sarafu-vise
RUN echo "Building on $BUILDPLATFORM, building for $TARGETPLATFORM"
RUN go mod download
RUN go build -tags logtrace,online -o sarafu-at -ldflags="-X main.build=${BUILD} -s -w" cmd/africastalking/main.go
RUN go build -tags logtrace,online -o sarafu-ssh -ldflags="-X main.build=${BUILD} -s -w" cmd/ssh/main.go
FROM debian:bookworm-slim
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
libgdbm-dev \
ca-certificates \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /service
COPY --from=build /build/sarafu-vise/sarafu-at .
COPY --from=build /build/sarafu-vise/sarafu-ssh .
COPY --from=build /build/sarafu-vise/LICENSE .
COPY --from=build /build/sarafu-vise/README.md .
COPY --from=build /build/sarafu-vise/services ./services
COPY --from=build /build/sarafu-vise/.env.example .
RUN mv .env.example .env
EXPOSE 7123
EXPOSE 7122
CMD ["./sarafu-at"]

View File

@@ -44,14 +44,12 @@ func main() {
var err error
var gettextDir string
var langs args.LangVar
var resourceDir string
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
flag.StringVar(override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
flag.StringVar(override.UserConn, "userdata", "?", "userdata store connection string")
flag.StringVar(override.ResourceConn, "resource", "?", "resource data directory")
flag.StringVar(&resourceDir, "resource-dir", "", "resource data directory. If set, overrides --resource to create a non-binary fsdb for the given path.")
flag.StringVar(override.StateConn, "state", "?", "state store connection string")
flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
flag.StringVar(&override.UserConn, "userdata", "?", "userdata store connection string")
flag.StringVar(&override.ResourceConn, "resource", "?", "resource data directory")
flag.StringVar(&override.StateConn, "state", "?", "state store connection string")
flag.UintVar(&size, "s", 160, "max size of output")
flag.StringVar(&host, "h", config.Host(), "http host")
flag.UintVar(&port, "p", config.Port(), "http port")
@@ -59,10 +57,6 @@ func main() {
flag.Var(&langs, "language", "add symbol resolution for language")
flag.Parse()
if resourceDir != "" {
*override.ResourceConn = resourceDir
override.ResourceConnMode = storage.DBMODE_TEXT
}
config.Apply(override)
conns, err := config.GetConns()
if err != nil {
@@ -87,6 +81,7 @@ func main() {
OutputSize: uint32(size),
FlagCount: uint32(128),
MenuSeparator: menuSeparator,
ResetOnEmptyInput: true,
}
if engineDebug {
@@ -139,6 +134,7 @@ func main() {
rp := &at.ATRequestParser{}
bsh := request.NewBaseRequestHandler(cfg, rs, stateStore, userdataStore, rp, hl)
bsh = bsh.WithEngineFunc(lhs.GetEngine)
sh := at.NewATRequestHandler(bsh)
mux := http.NewServeMux()

View File

@@ -1,12 +1,15 @@
package main
import (
"bufio"
"context"
"flag"
"fmt"
"io"
"os"
"os/signal"
"path"
"strings"
"syscall"
"git.defalsify.org/vise.git/engine"
@@ -53,14 +56,12 @@ func main() {
var err error
var gettextDir string
var langs args.LangVar
var resourceDir string
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
flag.StringVar(override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
flag.StringVar(override.ResourceConn, "resource", "?", "resource data directory")
flag.StringVar(&resourceDir, "resource-dir", "", "resource data directory. If set, overrides --resource to create a non-binary fsdb for the given path.")
flag.StringVar(override.UserConn, "userdata", "?", "userdata store connection string")
flag.StringVar(override.StateConn, "state", "?", "state store connection string")
flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
flag.StringVar(&override.ResourceConn, "resource", "?", "resource data directory")
flag.StringVar(&override.UserConn, "userdata", "?", "userdata store connection string")
flag.StringVar(&override.StateConn, "state", "?", "state store connection string")
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
flag.UintVar(&size, "s", 160, "max size of output")
@@ -70,10 +71,6 @@ func main() {
flag.Var(&langs, "language", "add symbol resolution for language")
flag.Parse()
if resourceDir != "" {
*override.ResourceConn = resourceDir
override.ResourceConnMode = storage.DBMODE_TEXT
}
config.Apply(override)
conns, err := config.GetConns()
if err != nil {
@@ -99,6 +96,7 @@ func main() {
OutputSize: uint32(size),
FlagCount: uint32(128),
MenuSeparator: menuSeparator,
ResetOnEmptyInput: true,
}
if engineDebug {
@@ -133,7 +131,6 @@ func main() {
lhs.SetDataStore(&userdataStore)
accountService := services.New(ctx, menuStorageService)
hl, err := lhs.GetHandler(accountService)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
@@ -151,6 +148,8 @@ func main() {
sessionId: sessionId,
}
sh := request.NewBaseRequestHandler(cfg, rs, stateStore, userdataStore, rp, hl)
sh = sh.WithEngineFunc(lhs.GetEngine)
cfg.SessionId = sessionId
rqs := request.RequestSession{
Ctx: ctx,
@@ -190,11 +189,19 @@ func main() {
os.Exit(1)
}
fmt.Println("")
_, err = fmt.Scanln(&rqs.Input)
in := bufio.NewReader(os.Stdin)
s, err := in.ReadString('\n')
if err != nil {
if err == io.EOF {
logg.DebugCtxf(ctx, "have EOF, bailing")
break
}
logg.ErrorCtxf(ctx, "error in input", "err", err)
fmt.Errorf("error in input: %v", err)
os.Exit(1)
}
rqs.Input = []byte{}
s = strings.TrimSpace(s)
rqs.Input = []byte(s)
}
}

View File

@@ -43,13 +43,11 @@ func main() {
var err error
var gettextDir string
var langs args.LangVar
var resourceDir string
flag.StringVar(override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
flag.StringVar(override.UserConn, "userdata", "?", "userdata store connection string")
flag.StringVar(override.ResourceConn, "resource", "?", "resource data directory")
flag.StringVar(&resourceDir, "resource-dir", "", "resource data directory. If set, overrides --resource to create a non-binary fsdb for the given path.")
flag.StringVar(override.StateConn, "state", "?", "state store connection string")
flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
flag.StringVar(&override.UserConn, "userdata", "?", "userdata store connection string")
flag.StringVar(&override.ResourceConn, "resource", "?", "resource data directory")
flag.StringVar(&override.StateConn, "state", "?", "state store connection string")
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
flag.UintVar(&size, "s", 160, "max size of output")
@@ -59,10 +57,6 @@ func main() {
flag.Var(&langs, "language", "add symbol resolution for language")
flag.Parse()
if resourceDir != "" {
*override.ResourceConn = resourceDir
override.ResourceConnMode = storage.DBMODE_TEXT
}
config.Apply(override)
conns, err := config.GetConns()
if err != nil {
@@ -88,6 +82,7 @@ func main() {
OutputSize: uint32(size),
FlagCount: uint32(128),
MenuSeparator: menuSeparator,
ResetOnEmptyInput: true,
}
if engineDebug {
@@ -139,6 +134,7 @@ func main() {
rp := &httprequest.DefaultRequestParser{}
bsh := request.NewBaseRequestHandler(cfg, rs, stateStore, userdataStore, rp, hl)
bsh = bsh.WithEngineFunc(lhs.GetEngine)
sh := httprequest.NewHTTPRequestHandler(bsh)
s := &http.Server{
Addr: fmt.Sprintf("%s:%s", host, strconv.Itoa(int(port))),

View File

@@ -38,10 +38,10 @@ func main() {
var langs args.LangVar
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
flag.StringVar(override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
flag.StringVar(override.ResourceConn, "resource", "?", "resource data directory")
flag.StringVar(override.UserConn, "userdata", "?", "userdata store connection string")
flag.StringVar(override.StateConn, "state", "?", "state store connection string")
flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
flag.StringVar(&override.ResourceConn, "resource", "?", "resource data directory")
flag.StringVar(&override.UserConn, "userdata", "?", "userdata store connection string")
flag.StringVar(&override.StateConn, "state", "?", "state store connection string")
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
flag.UintVar(&size, "s", 160, "max size of output")
flag.StringVar(&gettextDir, "gettext", "", "use gettext translations from given directory")
@@ -79,6 +79,8 @@ func main() {
OutputSize: uint32(size),
FlagCount: uint32(128),
MenuSeparator: menuSeparator,
EngineDebug: engineDebug,
ResetOnEmptyInput: true,
}
menuStorageService := storage.NewMenuStorageService(conns)
@@ -124,17 +126,12 @@ func main() {
}
accountService := services.New(ctx, menuStorageService)
hl, err := lhs.GetHandler(accountService)
_, err = lhs.GetHandler(accountService)
if err != nil {
fmt.Fprintf(os.Stderr, "get accounts service handler: %v\n", err)
os.Exit(1)
}
en := lhs.GetEngine()
en = en.WithFirst(hl.Init)
if engineDebug {
en = en.WithDebug(nil)
fmt.Fprintf(os.Stderr, "get accounts service handler: %v\n", err)
os.Exit(1)
}
en := lhs.GetEngine(cfg, rs, pe)
cint := make(chan os.Signal)
cterm := make(chan os.Signal)

View File

@@ -38,10 +38,11 @@ func main() {
var stateDebug bool
var host string
var port uint
flag.StringVar(override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
flag.StringVar(override.ResourceConn, "resource", "?", "resource connection string")
flag.StringVar(override.UserConn, "userdata", "?", "userdata store connection string")
flag.StringVar(override.StateConn, "state", "?", "state store connection string")
flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
flag.StringVar(&override.ResourceConn, "resource", "?", "resource connection string")
flag.StringVar(&override.UserConn, "userdata", "?", "userdata store connection string")
flag.StringVar(&override.StateConn, "state", "?", "state store connection string")
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
flag.UintVar(&size, "s", 160, "max size of output")
flag.StringVar(&host, "h", config.HostSSH(), "socket host")
@@ -83,6 +84,7 @@ func main() {
Root: "root",
OutputSize: uint32(size),
FlagCount: uint32(128),
ResetOnEmptyInput: true,
}
if stateDebug {
cfg.StateDebug = true

View File

@@ -6,17 +6,9 @@ import (
)
func NewOverride() *viseconfig.Override {
var a string
var b string
var c string
var d string
o := &viseconfig.Override{
DbConn: &a,
StateConn: &b,
StateConnMode: storage.DBMODE_TEXT,
ResourceConn: &c,
ResourceConnMode: storage.DBMODE_TEXT,
UserConn: &d,
UserConnMode: storage.DBMODE_BINARY,
}
return o

View File

@@ -1,6 +1,8 @@
package config
import (
"strings"
apiconfig "git.grassecon.net/grassrootseconomics/sarafu-api/config"
viseconfig "git.grassecon.net/grassrootseconomics/visedriver/config"
"git.grassecon.net/grassrootseconomics/visedriver/env"
@@ -23,7 +25,8 @@ const (
defaultSSHHost string = "127.0.0.1"
defaultSSHPort uint = 7122
defaultHTTPHost string = "127.0.0.1"
defaultHTTPPort uint = 7123
defaultHTTPPort uint = 7123
defaultDomain = "sarafu.local"
)
func LoadConfig() error {
@@ -39,6 +42,17 @@ func LoadConfig() error {
return nil
}
func SearchDomains() []string {
var ParsedDomains []string
SearchDomains := env.GetEnv("ALIAS_SEARCH_DOMAINS", defaultDomain)
SearchDomainList := strings.Split(env.GetEnv("ALIAS_SEARCH_DOMAINS", SearchDomains), ",")
for _, domain := range SearchDomainList {
ParsedDomains = append(ParsedDomains, strings.ReplaceAll(domain, " ", ""))
}
return ParsedDomains
}
func Language() string {
return viseconfig.DefaultLanguage
}

View File

@@ -25,21 +25,15 @@ func main() {
override := config.NewOverride()
var sessionId string
var resourceDir string
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
flag.StringVar(override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
flag.StringVar(override.ResourceConn, "resource", "?", "resource data directory")
flag.StringVar(&resourceDir, "resource-dir", "", "resource data directory. If set, overrides --resource to create a non-binary fsdb for the given path.")
flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
flag.StringVar(&override.ResourceConn, "resource", "?", "resource data directory")
flag.StringVar(override.UserConn, "userdata", "?", "userdata store connection string")
flag.StringVar(override.StateConn, "state", "?", "state store connection string")
flag.StringVar(&override.UserConn, "userdata", "?", "userdata store connection string")
flag.StringVar(&override.StateConn, "state", "?", "state store connection string")
flag.Parse()
if resourceDir != "" {
*override.ResourceConn = resourceDir
override.ResourceConnMode = storage.DBMODE_TEXT
}
config.Apply(override)
conns, err := config.GetConns()
if err != nil {

View File

@@ -38,21 +38,15 @@ func main() {
var engineDebug bool
var err error
var first bool
var resourceDir string
flag.StringVar(&sessionId, "session-id", "075xx2123", "session id")
flag.StringVar(override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
flag.StringVar(override.ResourceConn, "resource", "?", "resource data directory")
flag.StringVar(&resourceDir, "resource-dir", "", "resource data directory. If set, overrides --resource to create a non-binary fsdb for the given path.")
flag.StringVar(override.UserConn, "userdata", "?", "userdata store connection string")
flag.StringVar(override.StateConn, "state", "?", "state store connection string")
flag.StringVar(&override.DbConn, "c", "?", "default connection string (replaces all unspecified strings)")
flag.StringVar(&override.ResourceConn, "resource", "?", "resource data directory")
flag.StringVar(&override.UserConn, "userdata", "?", "userdata store connection string")
flag.StringVar(&override.StateConn, "state", "?", "state store connection string")
flag.BoolVar(&engineDebug, "d", false, "use engine debug output")
flag.Parse()
if resourceDir != "" {
*override.ResourceConn = resourceDir
override.ResourceConnMode = storage.DBMODE_TEXT
}
config.Apply(override)
conns, err := config.GetConns()
if err != nil {

8
go.mod
View File

@@ -3,11 +3,11 @@ module git.grassecon.net/grassrootseconomics/sarafu-vise
go 1.23.4
require (
git.defalsify.org/vise.git v0.2.3-0.20250120121301-10739fb4a8c9
git.defalsify.org/vise.git v0.2.3-0.20250205173834-d1f6647211ac
git.grassecon.net/grassrootseconomics/common v0.0.0-20250121134736-ba8cbbccea7d
git.grassecon.net/grassrootseconomics/sarafu-api v0.0.0-20250121135150-e0b539809805
git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250122123424-6749c632b0a2
git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250121135340-ca97e23e8c84
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250206112944-31eb30de0f69
git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.1.0.20250204132347-1eb0b1555244
git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694
github.com/alecthomas/assert/v2 v2.2.2
github.com/gofrs/uuid v4.4.0+incompatible
github.com/grassrootseconomics/ussd-data-service v1.2.0-beta

16
go.sum
View File

@@ -1,13 +1,13 @@
git.defalsify.org/vise.git v0.2.3-0.20250120121301-10739fb4a8c9 h1:sPcqXQcywxA8W3W+9qQncLPmsrgqTIlec7vmD4/7vyA=
git.defalsify.org/vise.git v0.2.3-0.20250120121301-10739fb4a8c9/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck=
git.defalsify.org/vise.git v0.2.3-0.20250205173834-d1f6647211ac h1:f/E0ZTclVfMEnD/3Alrzzbg+dOm138zGydV42jT0JPw=
git.defalsify.org/vise.git v0.2.3-0.20250205173834-d1f6647211ac/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck=
git.grassecon.net/grassrootseconomics/common v0.0.0-20250121134736-ba8cbbccea7d h1:5mzLas+jxTUtusOKx4XvU+n2QvrV/mH17MnJRy46siQ=
git.grassecon.net/grassrootseconomics/common v0.0.0-20250121134736-ba8cbbccea7d/go.mod h1:wgQJZGIS6QuNLHqDhcsvehsbn5PvgV7aziRebMnJi60=
git.grassecon.net/grassrootseconomics/sarafu-api v0.0.0-20250121135150-e0b539809805 h1:deGnqf4YCsbxhXgjFEjYjTUCvciLEmI26T9IysRsQXY=
git.grassecon.net/grassrootseconomics/sarafu-api v0.0.0-20250121135150-e0b539809805/go.mod h1:9bc3d//Qqm11hz7GYRdQc1Uan+0GJIOpvRBbv8cHMu8=
git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250122123424-6749c632b0a2 h1:ON77G5K0JNuwPb5JT/hRfF6G6+xstlBQgEIEzWydnhg=
git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250122123424-6749c632b0a2/go.mod h1:pjKp9L/ZsWW3kMB0UoIl1yv9TBIuU33mn9Aghxp7vGk=
git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250121135340-ca97e23e8c84 h1:VoBmqsjlRdz+IPbtKsAkc1IrMepjR+QlesZT31Jokrk=
git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250121135340-ca97e23e8c84/go.mod h1:DpibtYpnT3nG4Kn556hRAkdu4+CtiI/6MbnQHal51mQ=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250206112944-31eb30de0f69 h1:cbBpm9uNJak58MpFpNXJuvgCmz+A8kquXr9har4expg=
git.grassecon.net/grassrootseconomics/sarafu-api v0.9.0-beta.1.0.20250206112944-31eb30de0f69/go.mod h1:gOn89ipaDcDvmQXRMQYKUqcw/sJcwVOPVt2eC6Geip8=
git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.1.0.20250204132347-1eb0b1555244 h1:BXotWSKg04U97sf/xeWJuUTSVgKk2aEK+5BtBrnafXQ=
git.grassecon.net/grassrootseconomics/visedriver v0.9.0-beta.1.0.20250204132347-1eb0b1555244/go.mod h1:6B6ByxXOiRY0NR7K02Bf3fEu7z+2c/6q8PFVNjC5G8w=
git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694 h1:DjJlBSz0S13acft5XZDWk7ZYnzElym0xLMYEVgyNJ+E=
git.grassecon.net/grassrootseconomics/visedriver-africastalking v0.0.0-20250129070628-5a539172c694/go.mod h1:DpibtYpnT3nG4Kn556hRAkdu4+CtiI/6MbnQHal51mQ=
github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk=
github.com/alecthomas/assert/v2 v2.2.2/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ=
github.com/alecthomas/participle/v2 v2.0.0 h1:Fgrq+MbuSsJwIkw3fEj9h75vDP0Er5JzepJ0/HNHv0g=

View File

@@ -23,7 +23,9 @@ import (
"git.grassecon.net/grassrootseconomics/common/person"
"git.grassecon.net/grassrootseconomics/common/phone"
"git.grassecon.net/grassrootseconomics/common/pin"
"git.grassecon.net/grassrootseconomics/sarafu-api/models"
"git.grassecon.net/grassrootseconomics/sarafu-api/remote"
"git.grassecon.net/grassrootseconomics/sarafu-vise/config"
"git.grassecon.net/grassrootseconomics/sarafu-vise/profile"
"git.grassecon.net/grassrootseconomics/sarafu-vise/store"
storedb "git.grassecon.net/grassrootseconomics/sarafu-vise/store/db"
@@ -123,12 +125,6 @@ func (h *MenuHandlers) Init(ctx context.Context, sym string, input []byte) (reso
h.st = h.pe.GetState()
h.ca = h.pe.GetMemory()
if len(input) == 0 {
// move to the top node
h.st.Code = []byte{}
}
sessionId, ok := ctx.Value("SessionId").(string)
if ok {
ctx = context.WithValue(ctx, "SessionId", sessionId)
@@ -324,12 +320,16 @@ func (h *MenuHandlers) VerifyNewPin(ctx context.Context, sym string, input []byt
return res, fmt.Errorf("missing session")
}
flag_valid_pin, _ := h.flagManager.GetFlag("flag_valid_pin")
pinInput := string(input)
// Validate that the PIN is a 4-digit number.
if pin.IsValidPIN(pinInput) {
res.FlagSet = append(res.FlagSet, flag_valid_pin)
if !h.st.Back() {
pinInput := string(input)
// Validate that the PIN is a 4-digit number.
if pin.IsValidPIN(pinInput) {
res.FlagSet = append(res.FlagSet, flag_valid_pin)
} else {
res.FlagReset = append(res.FlagReset, flag_valid_pin)
}
} else {
res.FlagReset = append(res.FlagReset, flag_valid_pin)
res.FlagSet = append(res.FlagSet, flag_valid_pin)
}
return res, nil
@@ -418,6 +418,11 @@ func (h *MenuHandlers) CheckBlockedNumPinMisMatch(ctx context.Context, sym strin
if !ok {
return res, fmt.Errorf("missing session")
}
if h.st.Back() {
res.FlagReset = append(res.FlagReset, flag_pin_mismatch)
return res, nil
}
// Get blocked number from storage.
store := h.userdataStore
blockedNumber, err := store.ReadEntry(ctx, sessionId, storedb.DATA_BLOCKED_NUMBER)
@@ -431,6 +436,11 @@ func (h *MenuHandlers) CheckBlockedNumPinMisMatch(ctx context.Context, sym strin
logg.ErrorCtxf(ctx, "failed to read hashedTemporaryPin entry with", "key", storedb.DATA_TEMPORARY_VALUE, "error", err)
return res, err
}
if len(hashedTemporaryPin) == 0 {
logg.ErrorCtxf(ctx, "hashedTemporaryPin is empty", "key", storedb.DATA_TEMPORARY_VALUE)
return res, fmt.Errorf("Data error encountered")
}
if pin.VerifyPIN(string(hashedTemporaryPin), string(input)) {
res.FlagReset = append(res.FlagReset, flag_pin_mismatch)
} else {
@@ -448,12 +458,21 @@ func (h *MenuHandlers) ConfirmPinChange(ctx context.Context, sym string, input [
}
flag_pin_mismatch, _ := h.flagManager.GetFlag("flag_pin_mismatch")
if h.st.Back() {
res.FlagReset = append(res.FlagReset, flag_pin_mismatch)
return res, nil
}
store := h.userdataStore
hashedTemporaryPin, err := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE)
if err != nil {
logg.ErrorCtxf(ctx, "failed to read hashedTemporaryPin entry with", "key", storedb.DATA_TEMPORARY_VALUE, "error", err)
return res, err
}
if len(hashedTemporaryPin) == 0 {
logg.ErrorCtxf(ctx, "hashedTemporaryPin is empty", "key", storedb.DATA_TEMPORARY_VALUE)
return res, fmt.Errorf("Data error encountered")
}
if pin.VerifyPIN(string(hashedTemporaryPin), string(input)) {
res.FlagReset = append(res.FlagReset, flag_pin_mismatch)
@@ -488,13 +507,17 @@ func (h *MenuHandlers) ResetOthersPin(ctx context.Context, sym string, input []b
logg.ErrorCtxf(ctx, "failed to read blockedPhonenumber entry with", "key", storedb.DATA_BLOCKED_NUMBER, "error", err)
return res, err
}
hashedTmporaryPin, err := store.ReadEntry(ctx, string(blockedPhonenumber), storedb.DATA_TEMPORARY_VALUE)
hashedTemporaryPin, err := store.ReadEntry(ctx, string(blockedPhonenumber), storedb.DATA_TEMPORARY_VALUE)
if err != nil {
logg.ErrorCtxf(ctx, "failed to read hashedTmporaryPin entry with", "key", storedb.DATA_TEMPORARY_VALUE, "error", err)
return res, err
}
if len(hashedTemporaryPin) == 0 {
logg.ErrorCtxf(ctx, "hashedTemporaryPin is empty", "key", storedb.DATA_TEMPORARY_VALUE)
return res, fmt.Errorf("Data error encountered")
}
err = store.WriteEntry(ctx, string(blockedPhonenumber), storedb.DATA_ACCOUNT_PIN, []byte(hashedTmporaryPin))
err = store.WriteEntry(ctx, string(blockedPhonenumber), storedb.DATA_ACCOUNT_PIN, []byte(hashedTemporaryPin))
if err != nil {
return res, err
}
@@ -579,6 +602,11 @@ func (h *MenuHandlers) ValidateBlockedNumber(ctx context.Context, sym string, in
if !ok {
return res, fmt.Errorf("missing session")
}
if h.st.Back() {
res.FlagReset = append(res.FlagReset, flag_unregistered_number)
return res, nil
}
blockedNumber := string(input)
_, err = store.ReadEntry(ctx, blockedNumber, storedb.DATA_PUBLIC_KEY)
if !phone.IsValidPhoneNumber(blockedNumber) {
@@ -622,6 +650,11 @@ func (h *MenuHandlers) VerifyCreatePin(ctx context.Context, sym string, input []
logg.ErrorCtxf(ctx, "failed to read hashedTemporaryPin entry with", "key", storedb.DATA_TEMPORARY_VALUE, "error", err)
return res, err
}
if len(hashedTemporaryPin) == 0 {
logg.ErrorCtxf(ctx, "hashedTemporaryPin is empty", "key", storedb.DATA_TEMPORARY_VALUE)
return res, fmt.Errorf("Data error encountered")
}
if pin.VerifyPIN(string(hashedTemporaryPin), string(input)) {
res.FlagSet = []uint32{flag_valid_pin}
res.FlagReset = []uint32{flag_pin_mismatch}
@@ -657,11 +690,19 @@ func (h *MenuHandlers) SaveFirstname(ctx context.Context, sym string, input []by
firstNameSet := h.st.MatchFlag(flag_firstname_set, true)
if allowUpdate {
temporaryFirstName, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE)
if len(temporaryFirstName) == 0 {
logg.ErrorCtxf(ctx, "temporaryFirstName is empty", "key", storedb.DATA_TEMPORARY_VALUE)
return res, fmt.Errorf("Data error encountered")
}
err = store.WriteEntry(ctx, sessionId, storedb.DATA_FIRST_NAME, []byte(temporaryFirstName))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write firstName entry with", "key", storedb.DATA_FIRST_NAME, "value", temporaryFirstName, "error", err)
return res, err
}
err := h.constructAccountAlias(ctx)
if err != nil {
return res, err
}
res.FlagSet = append(res.FlagSet, flag_firstname_set)
} else {
if firstNameSet {
@@ -697,6 +738,10 @@ func (h *MenuHandlers) SaveFamilyname(ctx context.Context, sym string, input []b
if allowUpdate {
temporaryFamilyName, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE)
if len(temporaryFamilyName) == 0 {
logg.ErrorCtxf(ctx, "temporaryFamilyName is empty", "key", storedb.DATA_TEMPORARY_VALUE)
return res, fmt.Errorf("Data error encountered")
}
err = store.WriteEntry(ctx, sessionId, storedb.DATA_FAMILY_NAME, []byte(temporaryFamilyName))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write familyName entry with", "key", storedb.DATA_FAMILY_NAME, "value", temporaryFamilyName, "error", err)
@@ -767,6 +812,10 @@ func (h *MenuHandlers) SaveYob(ctx context.Context, sym string, input []byte) (r
if allowUpdate {
temporaryYob, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE)
if len(temporaryYob) == 0 {
logg.ErrorCtxf(ctx, "temporaryYob is empty", "key", storedb.DATA_TEMPORARY_VALUE)
return res, fmt.Errorf("Data error encountered")
}
err = store.WriteEntry(ctx, sessionId, storedb.DATA_YOB, []byte(temporaryYob))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write yob entry with", "key", storedb.DATA_TEMPORARY_VALUE, "value", temporaryYob, "error", err)
@@ -806,6 +855,10 @@ func (h *MenuHandlers) SaveLocation(ctx context.Context, sym string, input []byt
if allowUpdate {
temporaryLocation, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE)
if len(temporaryLocation) == 0 {
logg.ErrorCtxf(ctx, "temporaryLocation is empty", "key", storedb.DATA_TEMPORARY_VALUE)
return res, fmt.Errorf("Data error encountered")
}
err = store.WriteEntry(ctx, sessionId, storedb.DATA_LOCATION, []byte(temporaryLocation))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write location entry with", "key", storedb.DATA_LOCATION, "value", temporaryLocation, "error", err)
@@ -847,6 +900,10 @@ func (h *MenuHandlers) SaveGender(ctx context.Context, sym string, input []byte)
if allowUpdate {
temporaryGender, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE)
if len(temporaryGender) == 0 {
logg.ErrorCtxf(ctx, "temporaryGender is empty", "key", storedb.DATA_TEMPORARY_VALUE)
return res, fmt.Errorf("Data error encountered")
}
err = store.WriteEntry(ctx, sessionId, storedb.DATA_GENDER, []byte(temporaryGender))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write gender entry with", "key", storedb.DATA_GENDER, "value", gender, "error", err)
@@ -888,6 +945,10 @@ func (h *MenuHandlers) SaveOfferings(ctx context.Context, sym string, input []by
if allowUpdate {
temporaryOfferings, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE)
if len(temporaryOfferings) == 0 {
logg.ErrorCtxf(ctx, "temporaryOfferings is empty", "key", storedb.DATA_TEMPORARY_VALUE)
return res, fmt.Errorf("Data error encountered")
}
err = store.WriteEntry(ctx, sessionId, storedb.DATA_OFFERINGS, []byte(temporaryOfferings))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write offerings entry with", "key", storedb.DATA_TEMPORARY_VALUE, "value", offerings, "error", err)
@@ -1076,6 +1137,11 @@ func (h *MenuHandlers) GetProfileInfo(ctx context.Context, sym string, input []b
gender := getEntryOrDefault(store.ReadEntry(ctx, sessionId, storedb.DATA_GENDER))
location := getEntryOrDefault(store.ReadEntry(ctx, sessionId, storedb.DATA_LOCATION))
offerings := getEntryOrDefault(store.ReadEntry(ctx, sessionId, storedb.DATA_OFFERINGS))
alias := getEntryOrDefault(store.ReadEntry(ctx, sessionId, storedb.DATA_ACCOUNT_ALIAS))
if alias != defaultValue {
alias = strings.Split(alias, ".")[0]
}
// Construct the full name
name := person.ConstructName(firstName, familyName, defaultValue)
@@ -1092,18 +1158,18 @@ func (h *MenuHandlers) GetProfileInfo(ctx context.Context, sym string, input []b
switch language.Code {
case "eng":
res.Content = fmt.Sprintf(
"Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n",
name, gender, age, location, offerings,
"Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\nYour alias: %s\n",
name, gender, age, location, offerings, alias,
)
case "swa":
res.Content = fmt.Sprintf(
"Jina: %s\nJinsia: %s\nUmri: %s\nEneo: %s\nUnauza: %s\n",
name, gender, age, location, offerings,
"Jina: %s\nJinsia: %s\nUmri: %s\nEneo: %s\nUnauza: %s\nLakabu yako: %s\n",
name, gender, age, location, offerings, alias,
)
default:
res.Content = fmt.Sprintf(
"Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n",
name, gender, age, location, offerings,
"Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\nYour alias: %s\n",
name, gender, age, location, offerings, alias,
)
}
@@ -1159,6 +1225,10 @@ func (h *MenuHandlers) UpdateAllProfileItems(ctx context.Context, sym string, in
if err != nil {
return res, err
}
err = h.constructAccountAlias(ctx)
if err != nil {
return res, err
}
return res, nil
}
@@ -1204,7 +1274,9 @@ func (h *MenuHandlers) Authorize(ctx context.Context, sym string, input []byte)
logg.ErrorCtxf(ctx, "failed to read AccountPin entry with", "key", storedb.DATA_ACCOUNT_PIN, "error", err)
return res, err
}
if len(input) == 4 {
str := string(input)
_, err = strconv.Atoi(str)
if len(input) == 4 && err == nil {
if pin.VerifyPIN(string(AccountPin), string(input)) {
if h.st.MatchFlag(flag_account_authorized, false) {
res.FlagReset = append(res.FlagReset, flag_incorrect_pin)
@@ -1222,7 +1294,7 @@ func (h *MenuHandlers) Authorize(ctx context.Context, sym string, input []byte)
}
}
} else {
err := h.incrementIncorrectPINAttempts(ctx, sessionId)
err = h.incrementIncorrectPINAttempts(ctx, sessionId)
if err != nil {
return res, err
}
@@ -1239,11 +1311,13 @@ func (h *MenuHandlers) Authorize(ctx context.Context, sym string, input []byte)
// Setback sets the flag_back_set flag when the navigation is back.
func (h *MenuHandlers) SetBack(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result
flag_back_set, _ := h.flagManager.GetFlag("flag_back_set")
//TODO:
//Add check if the navigation is lateral nav instead of checking the input.
if string(input) == "0" {
flag_back_set, _ := h.flagManager.GetFlag("flag_back_set")
res.FlagSet = append(res.FlagSet, flag_back_set)
} else {
res.FlagReset = append(res.FlagReset, flag_back_set)
}
return res, nil
}
@@ -1399,16 +1473,16 @@ func (h *MenuHandlers) FetchCommunityBalance(ctx context.Context, sym string, in
// TODO: split up functino
func (h *MenuHandlers) ValidateRecipient(ctx context.Context, sym string, input []byte) (resource.Result, error) {
var res resource.Result
var AliasAddressResult string
var AliasAddress *models.AliasAddress
store := h.userdataStore
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return res, fmt.Errorf("missing session")
}
flag_invalid_recipient, _ := h.flagManager.GetFlag("flag_invalid_recipient")
flag_invalid_recipient_with_invite, _ := h.flagManager.GetFlag("flag_invalid_recipient_with_invite")
flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error")
recipient := string(input)
@@ -1468,21 +1542,36 @@ func (h *MenuHandlers) ValidateRecipient(ctx context.Context, sym string, input
}
case "alias":
// Call the API to validate and retrieve the address for the alias
r, aliasErr := h.accountService.CheckAliasAddress(ctx, recipient)
if aliasErr != nil {
res.FlagSet = append(res.FlagSet, flag_api_error)
res.Content = recipient
logg.ErrorCtxf(ctx, "failed on CheckAliasAddress", "error", aliasErr)
return res, err
if strings.Contains(recipient, ".") {
AliasAddress, err = h.accountService.CheckAliasAddress(ctx, recipient)
if err == nil {
AliasAddressResult = AliasAddress.Address
} else {
logg.ErrorCtxf(ctx, "failed to resolve alias", "alias", recipient, "error_alias_check", err)
}
} else {
//Perform a search for each search domain,break on first match
for _, domain := range config.SearchDomains() {
fqdn := fmt.Sprintf("%s.%s", recipient, domain)
AliasAddress, err = h.accountService.CheckAliasAddress(ctx, fqdn)
if err == nil {
AliasAddressResult = AliasAddress.Address
continue
} else {
logg.ErrorCtxf(ctx, "failed to resolve alias", "alias", recipient, "error_alias_check", err)
}
}
}
// Alias validation succeeded, save the Ethereum address
err = store.WriteEntry(ctx, sessionId, storedb.DATA_RECIPIENT, []byte(r.Address))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write recipient entry with", "key", storedb.DATA_RECIPIENT, "value", r.Address, "error", err)
return res, err
if AliasAddressResult == "" {
res.Content = recipient
res.FlagSet = append(res.FlagSet, flag_invalid_recipient)
return res, nil
} else {
err = store.WriteEntry(ctx, sessionId, storedb.DATA_RECIPIENT, []byte(AliasAddressResult))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write recipient entry with", "key", storedb.DATA_RECIPIENT, "value", AliasAddressResult, "error", err)
return res, err
}
}
}
}
@@ -1534,6 +1623,10 @@ func (h *MenuHandlers) InviteValidRecipient(ctx context.Context, sym string, inp
l.AddDomain("default")
recipient, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE)
if len(recipient) == 0 {
logg.ErrorCtxf(ctx, "recipient is empty", "key", storedb.DATA_TEMPORARY_VALUE)
return res, fmt.Errorf("Data error encountered")
}
// TODO
// send an invitation SMS
@@ -1652,6 +1745,10 @@ func (h *MenuHandlers) GetRecipient(ctx context.Context, sym string, input []byt
}
store := h.userdataStore
recipient, _ := store.ReadEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE)
if len(recipient) == 0 {
logg.ErrorCtxf(ctx, "recipient is empty", "key", storedb.DATA_TEMPORARY_VALUE)
return res, fmt.Errorf("Data error encountered")
}
res.Content = string(recipient)
@@ -2015,7 +2112,6 @@ func (h *MenuHandlers) GetVoucherDetails(ctx context.Context, sym string, input
if !ok {
return res, fmt.Errorf("missing session")
}
flag_api_error, _ := h.flagManager.GetFlag("flag_api_call_error")
// get the active address
@@ -2242,3 +2338,64 @@ func (h *MenuHandlers) persistLanguageCode(ctx context.Context, code string) err
}
return h.persistInitialLanguageCode(ctx, sessionId, code)
}
func (h *MenuHandlers) constructAccountAlias(ctx context.Context) error {
var alias string
store := h.userdataStore
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
return fmt.Errorf("missing session")
}
firstName, err := store.ReadEntry(ctx, sessionId, storedb.DATA_FIRST_NAME)
if err != nil {
if db.IsNotFound(err) {
return nil
}
return err
}
familyName, err := store.ReadEntry(ctx, sessionId, storedb.DATA_FAMILY_NAME)
if err != nil {
if db.IsNotFound(err) {
return nil
}
return err
}
pubKey, err := store.ReadEntry(ctx, sessionId, storedb.DATA_PUBLIC_KEY)
if err != nil {
if db.IsNotFound(err) {
return nil
}
return err
}
aliasInput := fmt.Sprintf("%s%s", firstName, familyName)
aliasResult, err := h.accountService.RequestAlias(ctx, string(pubKey), aliasInput)
if err != nil {
logg.ErrorCtxf(ctx, "failed to retrieve alias", "alias", aliasInput, "error_alias_request", err)
return fmt.Errorf("Failed to retrieve alias: %s", err.Error())
}
alias = aliasResult.Alias
//Store the alias
err = store.WriteEntry(ctx, sessionId, storedb.DATA_ACCOUNT_ALIAS, []byte(alias))
if err != nil {
logg.ErrorCtxf(ctx, "failed to write account alias", "key", storedb.DATA_ACCOUNT_ALIAS, "value", alias, "error", err)
return err
}
return nil
}
func (h *MenuHandlers) ClearTemporaryValue(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")
}
userStore := h.userdataStore
// clear the temporary value at the start
err := userStore.WriteEntry(ctx, sessionId, storedb.DATA_TEMPORARY_VALUE, []byte(""))
if err != nil {
logg.ErrorCtxf(ctx, "failed to clear DATA_TEMPORARY_VALUE entry with", "key", storedb.DATA_TEMPORARY_VALUE, "value", "empty", "error", err)
return res, err
}
return res, nil
}

View File

@@ -175,20 +175,6 @@ func TestInit(t *testing.T) {
input: []byte("1"),
expectedResult: resource.Result{},
},
{
name: "Move to top node on empty input",
setup: func() (*MenuHandlers, context.Context) {
pe := persist.NewPersister(testStore).WithSession(sessionId).WithContent(st, ca)
h := &MenuHandlers{
flagManager: fm,
pe: pe,
}
st.Code = []byte("some pending bytecode")
return h, context.WithValue(ctx, "SessionId", sessionId)
},
input: []byte(""),
expectedResult: resource.Result{},
},
}
for _, tt := range tests {
@@ -1679,7 +1665,7 @@ func TestValidateRecipient(t *testing.T) {
},
{
name: "Test with alias recepient",
input: []byte("alias123"),
input: []byte("alias123.sarafu.local"),
expectedResult: resource.Result{},
},
}
@@ -1797,37 +1783,37 @@ func TestGetProfile(t *testing.T) {
}{
{
name: "Test with full profile information in eng",
keys: []storedb.DataTyp{storedb.DATA_FAMILY_NAME, storedb.DATA_FIRST_NAME, storedb.DATA_GENDER, storedb.DATA_OFFERINGS, storedb.DATA_LOCATION, storedb.DATA_YOB},
profileInfo: []string{"Doee", "John", "Male", "Bananas", "Kilifi", "1976"},
keys: []storedb.DataTyp{storedb.DATA_FAMILY_NAME, storedb.DATA_FIRST_NAME, storedb.DATA_GENDER, storedb.DATA_OFFERINGS, storedb.DATA_LOCATION, storedb.DATA_YOB, storedb.DATA_ACCOUNT_ALIAS},
profileInfo: []string{"Doee", "John", "Male", "Bananas", "Kilifi", "1976", "DoeJohn"},
languageCode: "eng",
result: resource.Result{
Content: fmt.Sprintf(
"Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n",
"John Doee", "Male", "49", "Kilifi", "Bananas",
"Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\nYour alias: %s\n",
"John Doee", "Male", "49", "Kilifi", "Bananas", "DoeJohn",
),
},
},
{
name: "Test with with profile information in swa",
keys: []storedb.DataTyp{storedb.DATA_FAMILY_NAME, storedb.DATA_FIRST_NAME, storedb.DATA_GENDER, storedb.DATA_OFFERINGS, storedb.DATA_LOCATION, storedb.DATA_YOB},
profileInfo: []string{"Doee", "John", "Male", "Bananas", "Kilifi", "1976"},
keys: []storedb.DataTyp{storedb.DATA_FAMILY_NAME, storedb.DATA_FIRST_NAME, storedb.DATA_GENDER, storedb.DATA_OFFERINGS, storedb.DATA_LOCATION, storedb.DATA_YOB, storedb.DATA_ACCOUNT_ALIAS},
profileInfo: []string{"Doee", "John", "Male", "Bananas", "Kilifi", "1976", "DoeJohn"},
languageCode: "swa",
result: resource.Result{
Content: fmt.Sprintf(
"Jina: %s\nJinsia: %s\nUmri: %s\nEneo: %s\nUnauza: %s\n",
"John Doee", "Male", "49", "Kilifi", "Bananas",
"Jina: %s\nJinsia: %s\nUmri: %s\nEneo: %s\nUnauza: %s\nLakabu yako: %s\n",
"John Doee", "Male", "49", "Kilifi", "Bananas", "DoeJohn",
),
},
},
{
name: "Test with with profile information with language that is not yet supported",
keys: []storedb.DataTyp{storedb.DATA_FAMILY_NAME, storedb.DATA_FIRST_NAME, storedb.DATA_GENDER, storedb.DATA_OFFERINGS, storedb.DATA_LOCATION, storedb.DATA_YOB},
profileInfo: []string{"Doee", "John", "Male", "Bananas", "Kilifi", "1976"},
keys: []storedb.DataTyp{storedb.DATA_FAMILY_NAME, storedb.DATA_FIRST_NAME, storedb.DATA_GENDER, storedb.DATA_OFFERINGS, storedb.DATA_LOCATION, storedb.DATA_YOB, storedb.DATA_ACCOUNT_ALIAS},
profileInfo: []string{"Doee", "John", "Male", "Bananas", "Kilifi", "1976", "DoeJohn"},
languageCode: "nor",
result: resource.Result{
Content: fmt.Sprintf(
"Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\n",
"John Doee", "Male", "49", "Kilifi", "Bananas",
"Name: %s\nGender: %s\nAge: %s\nLocation: %s\nYou provide: %s\nYour alias: %s\n",
"John Doee", "Male", "49", "Kilifi", "Bananas", "DoeJohn",
),
},
},
@@ -1857,12 +1843,14 @@ func TestVerifyNewPin(t *testing.T) {
sessionId := "session123"
fm, _ := NewFlagManager(flagsPath)
mockState := state.NewState(16)
flag_valid_pin, _ := fm.GetFlag("flag_valid_pin")
mockAccountService := new(mocks.MockAccountService)
h := &MenuHandlers{
flagManager: fm,
accountService: mockAccountService,
st: mockState,
}
ctx := context.WithValue(context.Background(), "SessionId", sessionId)
@@ -1900,6 +1888,7 @@ func TestVerifyNewPin(t *testing.T) {
func TestConfirmPin(t *testing.T) {
sessionId := "session123"
mockState := state.NewState(16)
ctx, store := InitializeTestStore(t)
ctx = context.WithValue(ctx, "SessionId", sessionId)
@@ -1910,6 +1899,7 @@ func TestConfirmPin(t *testing.T) {
userdataStore: store,
flagManager: fm,
accountService: mockAccountService,
st: mockState,
}
tests := []struct {

View File

@@ -6,6 +6,7 @@ import (
"git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/engine"
"git.defalsify.org/vise.git/logging"
"git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/resource"
@@ -13,6 +14,10 @@ import (
"git.grassecon.net/grassrootseconomics/sarafu-vise/handlers/application"
)
var (
logg = logging.NewVanilla().WithDomain("sarafu-vise.engine")
)
type HandlerService interface {
GetHandler() (*application.MenuHandlers, error)
}
@@ -24,6 +29,7 @@ type LocalHandlerService struct {
UserdataStore *db.Db
Cfg engine.Config
Rs resource.Resource
first resource.EntryFunc
}
func NewLocalHandlerService(ctx context.Context, fp string, debug bool, dbResource *resource.DbResource, cfg engine.Config, rs resource.Resource) (*LocalHandlerService, error) {
@@ -118,13 +124,20 @@ func (ls *LocalHandlerService) GetHandler(accountService remote.AccountService)
ls.DbRs.AddLocalFunc("update_all_profile_items", appHandlers.UpdateAllProfileItems)
ls.DbRs.AddLocalFunc("set_back", appHandlers.SetBack)
ls.DbRs.AddLocalFunc("show_blocked_account", appHandlers.ShowBlockedAccount)
ls.DbRs.AddLocalFunc("clear_temporary_value", appHandlers.ClearTemporaryValue)
ls.first = appHandlers.Init
return appHandlers, nil
}
// TODO: enable setting of sessionId on engine init time
func (ls *LocalHandlerService) GetEngine() *engine.DefaultEngine {
en := engine.NewEngine(ls.Cfg, ls.Rs)
en = en.WithPersister(ls.Pe)
func (ls *LocalHandlerService) GetEngine(cfg engine.Config, rs resource.Resource, pr *persist.Persister) engine.Engine {
en := engine.NewEngine(cfg, rs)
if ls.first != nil {
en = en.WithFirst(ls.first)
}
en = en.WithPersister(pr)
if cfg.EngineDebug {
en = en.WithDebug(nil)
}
return en
}

View File

@@ -427,7 +427,7 @@
},
{
"input": "1234",
"expectedContent": "My profile:\nName: foo bar\nGender: male\nAge: 80\nLocation: Kilifi\nYou provide: Bananas\n\n0:Back\n9:Quit"
"expectedContent": "My profile:\nName: foo bar\nGender: male\nAge: 80\nLocation: Kilifi\nYou provide: Bananas\nYour alias: \n\n0:Back\n9:Quit"
},
{
"input": "0",

View File

@@ -8,7 +8,7 @@ RELOAD save_others_temporary_pin
MOUT back 0
HALT
INCMP _ 0
LOAD check_pin_mismatch 0
LOAD check_pin_mismatch 6
RELOAD check_pin_mismatch
CATCH others_pin_mismatch flag_pin_mismatch 1
INCMP pin_entry *

View File

@@ -1,5 +1,7 @@
CATCH invalid_pin flag_valid_pin 0
LOAD confirm_pin_change 0
MOUT back 0
HALT
INCMP _ 0
RELOAD confirm_pin_change
CATCH pin_reset_mismatch flag_pin_mismatch 1
INCMP * pin_reset_success

View File

@@ -4,4 +4,7 @@ RELOAD reset_account_authorized
MOUT back 0
HALT
INCMP _ 0
LOAD validate_blocked_number 6
RELOAD validate_blocked_number
CATCH unregistered_number flag_unregistered_number 1
INCMP enter_others_new_pin *

View File

@@ -1,6 +1,3 @@
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

View File

@@ -1,3 +1,5 @@
LOAD clear_temporary_value 2
RELOAD clear_temporary_value
LOAD set_default_voucher 8
RELOAD set_default_voucher
LOAD check_vouchers 10

View File

@@ -1,13 +1,7 @@
LOAD authorize_account 12
RELOAD authorize_account
CATCH incorrect_pin flag_incorrect_pin 1
CATCH old_pin flag_allow_update 0
MOUT back 0
HALT
INCMP _ 0
LOAD save_temporary_pin 6
LOAD verify_new_pin 0
RELOAD save_temporary_pin
RELOAD verify_new_pin
CATCH invalid_pin flag_valid_pin 0
INCMP * confirm_pin_change

View File

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

View File

@@ -1,7 +1,7 @@
LOAD reset_allow_update 0
RELOAD reset_incorrect
MOUT back 0
HALT
RELOAD reset_allow_update
INCMP _ 0
RELOAD authorize_account
CATCH incorrect_pin flag_incorrect_pin 1
INCMP new_pin *

View File

@@ -1,8 +1,14 @@
LOAD set_back 6
LOAD authorize_account 5
LOAD reset_allow_update 4
LOAD verify_new_pin 2
LOAD save_temporary_pin 1
LOAD reset_incorrect 0
MOUT change_pin 1
MOUT reset_pin 2
MOUT back 0
HALT
INCMP my_account 0
INCMP _ 0
INCMP old_pin 1
INCMP enter_other_number 2
INCMP . *

View File

@@ -1,6 +1,6 @@
MOUT retry 1
MOUT quit 9
HALT
INCMP confirm_pin_change 1
INCMP _ 1
INCMP quit 9

View File

@@ -4,5 +4,5 @@ LOAD reset_others_pin 6
MOUT back 0
MOUT quit 9
HALT
INCMP pin_management 0
INCMP ^ 0
INCMP quit 9

View File

@@ -1,6 +1,3 @@
LOAD confirm_pin_change 0
RELOAD confirm_pin_change
CATCH pin_reset_mismatch flag_pin_mismatch 1
MOUT back 0
MOUT quit 9
HALT

View File

@@ -1,7 +1,8 @@
LOAD reset_unregistered_number 0
RELOAD reset_unregistered_number
MOUT back 0
MOUT retry 1
MOUT quit 9
HALT
INCMP ^ 0
INCMP _ 1
INCMP quit 9
INCMP . *

View File

@@ -12,5 +12,8 @@ import (
)
func New(ctx context.Context, storageService storage.StorageService) remote.AccountService {
return &httpremote.HTTPAccountService{}
return &httpremote.HTTPAccountService{
SS: storageService,
UseApi: false,
}
}

View File

@@ -177,20 +177,14 @@ func (s *SshRunner) GetEngine(sessionId string) (engine.Engine, func(), error) {
return nil, nil, err
}
// TODO: clear up why pointer here and by-value other cmds
accountService := services.New(ctx, menuStorageService)
hl, err := lhs.GetHandler(accountService)
if err != nil {
return nil, nil, err
}
en := lhs.GetEngine()
en = en.WithFirst(hl.Init)
if s.Debug {
en = en.WithDebug(nil)
}
// TODO: this is getting very hacky!
accountService := services.New(ctx, menuStorageService)
_, err = lhs.GetHandler(accountService)
if err != nil {
fmt.Fprintf(os.Stderr, "get accounts service handler: %v\n", err)
os.Exit(1)
}
en := lhs.GetEngine(lhs.Cfg, rs, pe)
closer := func() {
err := menuStorageService.Close(ctx)
if err != nil {

View File

@@ -61,6 +61,8 @@ const (
DATA_SELECTED_LANGUAGE_CODE
//ISO 639 code for the language initially selected.
DATA_INITIAL_LANGUAGE_CODE
//Fully qualified account alias string
DATA_ACCOUNT_ALIAS
)
const (

View File

@@ -137,14 +137,14 @@ func TestEngine(sessionId string) (engine.Engine, func(), chan bool) {
panic("Unknown account service type")
}
hl, err := lhs.GetHandler(testtag.AccountService)
// TODO: triggers withfirst assignment
_, err = lhs.GetHandler(testtag.AccountService)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(1)
}
en := lhs.GetEngine()
en = en.WithFirst(hl.Init)
en := lhs.GetEngine(lhs.Cfg, rs, pe)
cleanFn := func() {
err := en.Finish(ctx)
if err != nil {

View File

@@ -16,10 +16,10 @@ func init() {
if err != nil {
panic(err)
}
override.StateConn = &stateDir
override.StateConn = stateDir
userDir, err := os.MkdirTemp("", "sarafu-vise-menutraversal-fs-user-")
if err != nil {
panic(err)
}
override.UserConn = &userDir
override.UserConn = userDir
}

View File

@@ -21,7 +21,7 @@ func init() {
if err != nil {
panic(err)
}
override.StateConn = &stateDir
override.StateConn = stateDir
userDir, err := os.MkdirTemp("", "sarafu-vise-menutraversal-gdbm-user-")
if err != nil {
panic(err)
@@ -30,5 +30,5 @@ func init() {
if err != nil {
panic(err)
}
override.UserConn = &userDir
override.UserConn = userDir
}