Skip to content

Commit 6e599a4

Browse files
committed
Add starting table component and refactor
1 parent 703081c commit 6e599a4

File tree

6 files changed

+169
-69
lines changed

6 files changed

+169
-69
lines changed

cmd/bisturi/main.go

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,4 @@ func main() {
1212
if _, err := p.Run(); err != nil {
1313
log.Fatal("Error running program:", err)
1414
}
15-
16-
// // SYS_SOCKET syscall
17-
// rs, err := sockets.NewRawSocket(protocol)
18-
// if err != nil {
19-
// log.Fatalf("Failed to open raw socket: %v", err)
20-
// }
21-
// defer rs.Close()
22-
23-
// // bind the socket to the network interface
24-
// rs.Bind(*networkInterface)
25-
// if err != nil {
26-
// log.Fatalf("Failed to bind socket: %v", err)
27-
// }
28-
// log.Printf("listening for %s packets on interface: %s\n", protocol, networkInterface.Name)
29-
30-
// // SYS_RECVFROM syscall
31-
// rs.ReadPackets()
3215
}

protocols/eth.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,5 @@ func EthFrameFromBytes(raw []byte) (*EthernetFrame, error) {
4343
func (f *EthernetFrame) Info() string {
4444
etv := etherTypesValues[f.etherType]
4545

46-
return fmt.Sprintf("%s Ethernet Frame from MAC %s to MAC %s", f.sourceMAC, f.destinationMAC, etv)
46+
return fmt.Sprintf("%s Ethernet Frame from MAC %s to MAC %s", etv, f.sourceMAC, f.destinationMAC)
4747
}

tui/models/bisturi_model.go

Lines changed: 88 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ package tui
33
import (
44
"fmt"
55
"net"
6+
"strings"
67

8+
"github.com/NamelessOne91/bisturi/sockets"
79
"github.com/charmbracelet/bubbles/spinner"
810
tea "github.com/charmbracelet/bubbletea"
911
"github.com/charmbracelet/lipgloss"
@@ -12,25 +14,23 @@ import (
1214
type step uint8
1315

1416
const (
15-
setupStep step = iota
16-
ifaceStep
17-
protoStep
18-
doneStep
17+
retrieveIfaces step = iota
18+
selectIface
19+
selectProtocol
20+
receivePackets
1921
)
2022

21-
type errMsg struct {
22-
err error
23-
}
24-
25-
func (e errMsg) Error() string { return e.err.Error() }
23+
type errMsg error
2624

2725
type bisturiModel struct {
2826
step step
29-
startMenu startMenuModel
3027
spinner spinner.Model
31-
selectedInterface *net.Interface
28+
startMenu startMenuModel
29+
packetsTable packetsTablemodel
30+
selectedInterface net.Interface
3231
selectedProtocol string
3332
selectedEthType uint16
33+
rawSocket *sockets.RawSocket
3434
err error
3535
}
3636

@@ -39,74 +39,118 @@ func NewBisturiModel() *bisturiModel {
3939
s.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("#00cc99"))
4040

4141
return &bisturiModel{
42-
step: setupStep,
43-
spinner: s,
44-
startMenu: startMenuModel{},
42+
step: retrieveIfaces,
43+
spinner: s,
4544
}
4645
}
4746

4847
func (m bisturiModel) Init() tea.Cmd {
49-
return tea.Sequence(m.spinner.Tick, fetchInterfaces())
48+
return tea.Batch(m.spinner.Tick, fetchInterfaces())
5049
}
5150

52-
func (m *bisturiModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
53-
var cmd tea.Cmd
51+
func (m bisturiModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
52+
switch m.step {
53+
case retrieveIfaces:
54+
return m.updateLoading(msg)
55+
case selectIface, selectProtocol:
56+
return m.updateStartMenuSelection(msg)
57+
case receivePackets:
58+
return m.updateReceivingPacket(msg)
59+
default:
60+
return m, nil
61+
}
62+
}
5463

64+
func (m *bisturiModel) updateLoading(msg tea.Msg) (tea.Model, tea.Cmd) {
5565
switch msg := msg.(type) {
5666
case errMsg:
57-
m.err = msg.err
67+
m.err = msg
5868
return m, tea.Quit
5969

6070
case networkInterfacesMsg:
6171
m.startMenu = newStartMenuModel(msg)
62-
m.step = ifaceStep
72+
m.step = selectIface
73+
6374
return m, nil
6475

65-
case selectedInterfaceMsg:
76+
case tea.KeyMsg:
77+
switch msg.String() {
78+
case "q", "esc", "ctrl+c":
79+
return m, tea.Quit
80+
}
81+
}
82+
var cmd tea.Cmd
83+
m.spinner, cmd = m.spinner.Update(msg)
84+
return m, cmd
85+
}
86+
87+
func (m *bisturiModel) updateStartMenuSelection(msg tea.Msg) (tea.Model, tea.Cmd) {
88+
var cmd tea.Cmd
89+
90+
m.startMenu, cmd = m.startMenu.Update(msg)
91+
92+
switch msg := msg.(type) {
93+
case selectedIfaceItemMsg:
6694
iface, err := net.InterfaceByName(msg.name)
6795
if err != nil {
68-
return m, func() tea.Msg {
69-
return errMsg{err: err}
70-
}
96+
m.err = err
97+
return m, tea.Quit
7198
}
72-
m.selectedInterface = iface
73-
m.step = protoStep
74-
m.startMenu.step = protoStep
75-
return m, nil
99+
m.selectedInterface = *iface
100+
m.step = selectProtocol
76101

77-
case selectedProtocolMsg:
78-
m.selectedProtocol = msg.protocol
79-
m.selectedEthType = msg.ethTytpe
80-
m.step = doneStep
81102
return m, nil
82103

83-
case tea.KeyMsg:
84-
switch msg.String() {
85-
case "q", "esc", "ctrl+c":
104+
case selectedProtocolItemMsg:
105+
// SYS_SOCKET syscall
106+
rs, err := sockets.NewRawSocket(msg.name, msg.ethType)
107+
if err != nil {
108+
return m, tea.Quit
109+
}
110+
// bind the socket to the network interface
111+
err = rs.Bind(m.selectedInterface)
112+
if err != nil {
113+
m.err = err
86114
return m, tea.Quit
87115
}
116+
m.selectedProtocol = msg.name
117+
m.selectedEthType = msg.ethType
118+
m.rawSocket = rs
119+
m.step = receivePackets
120+
m.packetsTable = newPacketsTable()
88121

89-
case spinner.TickMsg:
90-
m.spinner, cmd = m.spinner.Update(msg)
91-
return m, cmd
122+
return m, nil
92123
}
124+
return m, cmd
125+
}
126+
127+
func (m *bisturiModel) updateReceivingPacket(msg tea.Msg) (tea.Model, tea.Cmd) {
128+
var cmd tea.Cmd
129+
130+
m.packetsTable, cmd = m.packetsTable.Update(msg)
93131

94-
m.startMenu, cmd = m.startMenu.Update(msg)
95132
return m, cmd
96133
}
97134

98135
func (m bisturiModel) View() string {
99136
if m.err != nil {
137+
if m.rawSocket != nil {
138+
m.rawSocket.Close()
139+
}
100140
return fmt.Sprintf("Error: %s\n", m.err)
101141
}
102142

143+
sb := strings.Builder{}
103144
switch m.step {
104-
case ifaceStep, protoStep:
105-
return m.startMenu.View()
106-
case doneStep:
107-
return fmt.Sprintf("Receiving packet on %s - %s\n", m.selectedInterface.Name, m.selectedProtocol)
145+
case retrieveIfaces:
146+
sb.WriteString(fmt.Sprintf("\n\n %s Retrieving network interfaces...\n\n", m.spinner.View()))
147+
case selectIface, selectProtocol:
148+
sb.WriteString(m.startMenu.View())
149+
case receivePackets:
150+
sb.WriteString(fmt.Sprintf("Receiving %s packets on %s ...\n", m.selectedProtocol, m.selectedInterface.Name))
151+
sb.WriteString(m.packetsTable.View())
108152
default:
109-
return fmt.Sprintf("\n\n %s Retrieving network interfaces...\n\n", m.spinner.View())
153+
sb.WriteString("The program is in an unkowqn state\n")
110154
}
111-
155+
return sb.String()
112156
}

tui/models/interfaces_list.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ func fetchInterfaces() tea.Cmd {
8383
return func() tea.Msg {
8484
ifaces, err := net.Interfaces()
8585
if err != nil {
86-
return errMsg{err: err}
86+
return errMsg(err)
8787
}
8888
return networkInterfacesMsg(ifaces)
8989
}

tui/models/packets_table.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package tui
2+
3+
import (
4+
"strings"
5+
6+
"github.com/NamelessOne91/bisturi/protocols"
7+
tea "github.com/charmbracelet/bubbletea"
8+
"github.com/charmbracelet/lipgloss"
9+
"github.com/evertras/bubble-table/table"
10+
)
11+
12+
const (
13+
columnKeyProtocol = "protocol"
14+
columnKeyInterface = "interface"
15+
columnKeyInfo = "info"
16+
)
17+
18+
type packetsTablemodel struct {
19+
table table.Model
20+
cachedRows []table.Row
21+
packetsChan <-chan protocols.IPPacket
22+
}
23+
24+
func newPacketsTable() packetsTablemodel {
25+
rows := make([]table.Row, 0, 20)
26+
27+
return packetsTablemodel{
28+
cachedRows: rows,
29+
table: table.New([]table.Column{
30+
table.NewColumn(columnKeyInterface, "Interface", 20),
31+
table.NewColumn(columnKeyProtocol, "Protocol", 20),
32+
table.NewColumn(columnKeyProtocol, "Info", 50),
33+
}).
34+
WithRows(rows).
35+
WithBaseStyle(lipgloss.NewStyle().
36+
BorderForeground(lipgloss.Color("#00cc99")).
37+
Foreground(lipgloss.Color("#00cc99")).
38+
Align(lipgloss.Center),
39+
),
40+
}
41+
}
42+
43+
func (m packetsTablemodel) Init() tea.Cmd {
44+
return nil
45+
}
46+
47+
func (m packetsTablemodel) Update(msg tea.Msg) (packetsTablemodel, tea.Cmd) {
48+
var (
49+
cmd tea.Cmd
50+
cmds []tea.Cmd
51+
)
52+
53+
m.table, cmd = m.table.Update(msg)
54+
cmds = append(cmds, cmd)
55+
56+
switch msg := msg.(type) {
57+
case tea.KeyMsg:
58+
switch msg.String() {
59+
case "ctrl+c", "esc", "q":
60+
cmds = append(cmds, tea.Quit)
61+
}
62+
}
63+
64+
return m, tea.Batch(cmds...)
65+
}
66+
67+
func (m packetsTablemodel) View() string {
68+
sb := strings.Builder{}
69+
70+
sb.WriteString(m.table.View())
71+
72+
return sb.String()
73+
}

tui/models/start_menu.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func newStartMenuModel(interfaces []net.Interface) startMenuModel {
3030
plm := newProtocolsListModel(listWidth, listHeight)
3131

3232
return startMenuModel{
33-
step: ifaceStep,
33+
step: selectIface,
3434
ifaceList: il,
3535
protoList: plm,
3636
}
@@ -42,10 +42,10 @@ func (m startMenuModel) Init() tea.Cmd {
4242

4343
func (m startMenuModel) Update(msg tea.Msg) (startMenuModel, tea.Cmd) {
4444
switch m.step {
45-
case ifaceStep:
45+
case selectIface:
4646
model, cmd := m.ifaceList.Update(msg)
4747
if i, ok := msg.(selectedIfaceItemMsg); ok {
48-
m.step = protoStep
48+
m.step = selectProtocol
4949
return m, func() tea.Msg {
5050
return selectedInterfaceMsg{
5151
name: i.name,
@@ -55,7 +55,7 @@ func (m startMenuModel) Update(msg tea.Msg) (startMenuModel, tea.Cmd) {
5555
m.ifaceList = model
5656
return m, cmd
5757

58-
case protoStep:
58+
case selectProtocol:
5959
model, cmd := m.protoList.Update(msg)
6060
if p, ok := msg.(selectedProtocolItemMsg); ok {
6161
return m, func() tea.Msg {
@@ -74,9 +74,9 @@ func (m startMenuModel) Update(msg tea.Msg) (startMenuModel, tea.Cmd) {
7474
func (m startMenuModel) View() string {
7575
var s string
7676
switch m.step {
77-
case ifaceStep:
77+
case selectIface:
7878
s = m.ifaceList.l.View()
79-
case protoStep:
79+
case selectProtocol:
8080
s = m.protoList.l.View()
8181
default:
8282
return "Unkown step"

0 commit comments

Comments
 (0)