This repository has been archived on 2026-03-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
oubliette/internal/shell/banking/screen_menu.go
Torjus Håkestad 8ff029fcb7 feat: add Banking TUI shell using bubbletea
Add an 80s-style green-on-black bank terminal shell ("banking") using
charmbracelet/bubbletea for full-screen TUI rendering over SSH.

Screens: login, main menu, account summary, account detail with
transactions, wire transfer wizard (6-step form capturing routing
number, destination, beneficiary, amount, memo, auth code), transaction
history with pagination, secure messages with breadcrumb content (fake
internal IPs, vault codes), change PIN, and hidden admin access (99)
that locks after 3 failed attempts with COBOL-style error output.

All key actions (login, navigation, wire transfers, admin attempts) are
logged to the session store. Wire transfer data is the honeypot gold.

Configurable via [shell.banking] in TOML: bank_name, terminal_id, region.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 23:17:12 +01:00

81 lines
1.6 KiB
Go

package banking
import (
"fmt"
"strings"
tea "github.com/charmbracelet/bubbletea"
)
type menuModel struct {
choice string
unread int
bankName string
}
func newMenuModel(bankName string, unreadCount int) menuModel {
return menuModel{bankName: bankName, unread: unreadCount}
}
func (m menuModel) Update(msg tea.Msg) (menuModel, tea.Cmd) {
keyMsg, ok := msg.(tea.KeyMsg)
if !ok {
return m, nil
}
switch keyMsg.Type {
case tea.KeyEnter:
return m, nil
case tea.KeyBackspace:
if len(m.choice) > 0 {
m.choice = m.choice[:len(m.choice)-1]
}
default:
ch := keyMsg.String()
if len(ch) == 1 && ch[0] >= 32 && ch[0] < 127 {
if len(m.choice) < 10 {
m.choice += ch
}
}
}
return m, nil
}
func (m menuModel) View() string {
var b strings.Builder
b.WriteString("\n")
b.WriteString(centerText("MAIN MENU"))
b.WriteString("\n\n")
b.WriteString(thinDivider())
b.WriteString("\n\n")
items := []struct {
num string
desc string
}{
{"1", "ACCOUNT SUMMARY"},
{"2", "ACCOUNT DETAIL / TRANSACTIONS"},
{"3", "WIRE TRANSFER"},
{"4", "TRANSACTION HISTORY"},
{"5", fmt.Sprintf("SECURE MESSAGES (%d UNREAD)", m.unread)},
{"6", "CHANGE PIN"},
{"7", "LOGOUT"},
}
for _, item := range items {
b.WriteString(baseStyle.Render(fmt.Sprintf(" [%s] %s", item.num, item.desc)))
b.WriteString("\n")
}
b.WriteString("\n")
b.WriteString(thinDivider())
b.WriteString("\n\n")
b.WriteString(titleStyle.Render(" ENTER SELECTION: "))
b.WriteString(inputStyle.Render(m.choice))
b.WriteString(inputStyle.Render("_"))
b.WriteString("\n")
return b.String()
}