1package tui
2
3import (
4 "fmt"
5 "strings"
6
7 tea "charm.land/bubbletea/v2"
8 "github.com/floatpane/matcha/config"
9)
10
11const cryptoConfigMaxFocus = 9
12
13func (m *Settings) updateSMIMEConfig(msg tea.KeyPressMsg) (*Settings, tea.Cmd) {
14 var cmds []tea.Cmd
15
16 key := msg.Key()
17 isEnter := key.Code == tea.KeyEnter || key.Code == tea.KeyReturn || key.Code == tea.KeyKpEnter
18 isSpace := key.Code == tea.KeySpace
19
20 setFocus := func(next int) tea.Cmd {
21 m.cryptoFocusIndex = next
22 m.smimeCertInput.Blur()
23 m.smimeKeyInput.Blur()
24 m.pgpPublicKeyInput.Blur()
25 m.pgpPrivateKeyInput.Blur()
26 m.pgpPINInput.Blur()
27
28 switch m.cryptoFocusIndex {
29 case 0:
30 return m.smimeCertInput.Focus()
31 case 1:
32 return m.smimeKeyInput.Focus()
33 case 3:
34 return m.pgpPublicKeyInput.Focus()
35 case 4:
36 return m.pgpPrivateKeyInput.Focus()
37 case 6:
38 return m.pgpPINInput.Focus()
39 }
40 return nil
41 }
42
43 switch msg.String() {
44 case "esc":
45 m.isCryptoConfig = false
46 return m, nil
47 case "tab", keyShiftTab, "up", keyDown:
48 if msg.String() == keyShiftTab || msg.String() == "up" {
49 m.cryptoFocusIndex--
50 if m.cryptoFocusIndex < 0 {
51 m.cryptoFocusIndex = cryptoConfigMaxFocus
52 }
53 } else {
54 m.cryptoFocusIndex++
55 if m.cryptoFocusIndex > cryptoConfigMaxFocus {
56 m.cryptoFocusIndex = 0
57 }
58 }
59 if m.cryptoFocusIndex == 6 && m.pgpKeySource != keyYubikey {
60 if msg.String() == keyShiftTab || msg.String() == "up" {
61 m.cryptoFocusIndex = 5
62 } else {
63 m.cryptoFocusIndex = 7
64 }
65 }
66 cmds = append(cmds, setFocus(m.cryptoFocusIndex))
67 return m, tea.Batch(cmds...)
68 }
69
70 if isEnter {
71 switch m.cryptoFocusIndex {
72 case 8: // Save
73 m.cfg.Accounts[m.editingAccountIdx].SMIMECert = m.smimeCertInput.Value()
74 m.cfg.Accounts[m.editingAccountIdx].SMIMEKey = m.smimeKeyInput.Value()
75 m.cfg.Accounts[m.editingAccountIdx].PGPPublicKey = m.pgpPublicKeyInput.Value()
76 m.cfg.Accounts[m.editingAccountIdx].PGPPrivateKey = m.pgpPrivateKeyInput.Value()
77 m.cfg.Accounts[m.editingAccountIdx].PGPKeySource = m.pgpKeySource
78 m.cfg.Accounts[m.editingAccountIdx].PGPPIN = m.pgpPINInput.Value()
79 _ = config.SaveConfig(m.cfg)
80 m.isCryptoConfig = false
81 return m, nil
82 case 9: // Cancel
83 m.isCryptoConfig = false
84 return m, nil
85 default:
86 // advance to next
87 next := m.cryptoFocusIndex + 1
88 if next == 6 && m.pgpKeySource != keyYubikey {
89 next = 7
90 }
91 cmds = append(cmds, setFocus(next))
92 return m, tea.Batch(cmds...)
93 }
94 }
95
96 if isSpace {
97 switch m.cryptoFocusIndex {
98 case 2:
99 m.cfg.Accounts[m.editingAccountIdx].SMIMESignByDefault = !m.cfg.Accounts[m.editingAccountIdx].SMIMESignByDefault
100 return m, nil
101 case 5:
102 if m.pgpKeySource == "file" {
103 m.pgpKeySource = keyYubikey
104 } else {
105 m.pgpKeySource = "file"
106 }
107 return m, nil
108 case 7:
109 m.cfg.Accounts[m.editingAccountIdx].PGPSignByDefault = !m.cfg.Accounts[m.editingAccountIdx].PGPSignByDefault
110 return m, nil
111 }
112 }
113
114 return m, tea.Batch(cmds...)
115}
116
117func (m *Settings) viewSMIMEConfig() string {
118 var b strings.Builder
119 account := m.cfg.Accounts[m.editingAccountIdx]
120 b.WriteString(titleStyle.Render(fmt.Sprintf("Crypto Config: %s", account.FetchEmail)) + "\n\n")
121
122 renderField := func(index int, label, content string) {
123 if m.cryptoFocusIndex == index {
124 b.WriteString(m.contentFocusStyle().Render(label) + "\n")
125 } else {
126 b.WriteString(settingsBlurredStyle.Render(label) + "\n")
127 }
128 b.WriteString(content + "\n\n")
129 }
130
131 // S/MIME
132 b.WriteString(settingsFocusedStyle.Render("S/MIME") + "\n")
133 renderField(0, "Certificate (PEM) Path:", m.smimeCertInput.View())
134 renderField(1, "Private Key (PEM) Path:", m.smimeKeyInput.View())
135 smimeSign := "OFF"
136 if account.SMIMESignByDefault {
137 smimeSign = "ON"
138 }
139 renderField(2, "Sign By Default:", smimeSign)
140
141 // PGP
142 b.WriteString(settingsFocusedStyle.Render("PGP") + "\n")
143 renderField(3, "Public Key Path:", m.pgpPublicKeyInput.View())
144 renderField(4, "Private Key Path:", m.pgpPrivateKeyInput.View())
145
146 keySource := "File"
147 if m.pgpKeySource == keyYubikey {
148 keySource = "YubiKey"
149 }
150 renderField(5, "Key Source:", keySource)
151
152 if m.pgpKeySource == keyYubikey {
153 renderField(6, "YubiKey PIN:", m.pgpPINInput.View())
154 }
155
156 pgpSign := "OFF"
157 if account.PGPSignByDefault {
158 pgpSign = "ON"
159 }
160 renderField(7, "Sign By Default:", pgpSign)
161
162 saveBtn := "[ Save ]"
163 cancelBtn := "[ Cancel ]"
164 if m.cryptoFocusIndex == 8 {
165 saveBtn = m.contentFocusStyle().Render(saveBtn)
166 } else {
167 saveBtn = settingsBlurredStyle.Render(saveBtn)
168 }
169 if m.cryptoFocusIndex == 9 {
170 cancelBtn = m.contentFocusStyle().Render(cancelBtn)
171 } else {
172 cancelBtn = settingsBlurredStyle.Render(cancelBtn)
173 }
174
175 b.WriteString(saveBtn + " " + cancelBtn + "\n\n")
176 b.WriteString(helpStyle.Render("tab: next • enter: next/save • space: toggle • esc: cancel"))
177
178 return b.String()
179}