1package tui
2
3import (
4 "strings"
5
6 tea "charm.land/bubbletea/v2"
7 "charm.land/lipgloss/v2"
8 "github.com/floatpane/matcha/config"
9 "github.com/floatpane/matcha/internal/passwordstrength"
10)
11
12func (m *Settings) updateEncryption(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) {
13 isEnabled := config.IsSecureModeEnabled()
14
15 if isEnabled {
16 if m.confirmingDisable {
17 switch msg.String() {
18 case "y", "Y":
19 m.confirmingDisable = false
20 cfg := m.cfg
21 return m, func() tea.Msg {
22 err := config.DisableSecureMode(cfg)
23 return SecureModeDisabledMsg{Err: err}
24 }
25 case "n", "N", "esc":
26 m.confirmingDisable = false
27 return m, nil
28 }
29 return m, nil
30 }
31 if msg.String() == keyEnter {
32 m.confirmingDisable = true
33 }
34 return m, nil
35 }
36
37 switch msg.String() {
38 case "esc":
39 // Clear inputs and return to menu
40 m.encPasswordInput.SetValue("")
41 m.encConfirmInput.SetValue("")
42 m.encPasswordStrength = ""
43 m.encPasswordInput.Blur()
44 m.encConfirmInput.Blur()
45 m.encError = ""
46 m.activePane = PaneMenu
47 return m, nil
48 case "tab", keyShiftTab, keyDown, "up":
49 if msg.String() == keyShiftTab || msg.String() == "up" {
50 m.encFocusIndex--
51 if m.encFocusIndex < 0 {
52 m.encFocusIndex = 2
53 }
54 } else {
55 m.encFocusIndex++
56 if m.encFocusIndex > 2 {
57 m.encFocusIndex = 0
58 }
59 }
60 m.encPasswordInput.Blur()
61 m.encConfirmInput.Blur()
62 var cmds []tea.Cmd
63 if m.encFocusIndex == 0 {
64 cmds = append(cmds, m.encPasswordInput.Focus())
65 }
66 if m.encFocusIndex == 1 {
67 cmds = append(cmds, m.encConfirmInput.Focus())
68 }
69 return m, tea.Batch(cmds...)
70 case keyEnter:
71 switch m.encFocusIndex {
72 case 0:
73 m.encFocusIndex = 1
74 m.encPasswordInput.Blur()
75 return m, m.encConfirmInput.Focus()
76 case 1:
77 m.encFocusIndex = 2
78 m.encConfirmInput.Blur()
79 return m, nil
80 case 2:
81 password := m.encPasswordInput.Value()
82 confirm := m.encConfirmInput.Value()
83 if password == "" {
84 m.encError = t("settings_encryption.error_empty")
85 return m, nil
86 }
87 if password != confirm {
88 m.encError = t("settings_encryption.error_mismatch")
89 return m, nil
90 }
91 m.encEnabling = true
92 m.encError = ""
93 cfg := m.cfg
94 return m, func() tea.Msg {
95 err := config.EnableSecureMode(password, cfg)
96 return SecureModeEnabledMsg{Err: err}
97 }
98 }
99 default:
100 // Forward input to focused textinput
101 var cmd tea.Cmd
102 switch m.encFocusIndex {
103 case 0:
104 before := m.encPasswordInput.Value()
105 m.encPasswordInput, cmd = m.encPasswordInput.Update(msg)
106 if m.encPasswordInput.Value() != before {
107 m.handlePasswordChanged()
108 }
109 case 1:
110 m.encConfirmInput, cmd = m.encConfirmInput.Update(msg)
111 }
112 return m, cmd
113 }
114 return m, nil
115}
116
117func (m *Settings) viewEncryption() string {
118 var b strings.Builder
119 isEnabled := config.IsSecureModeEnabled()
120
121 b.WriteString(titleStyle.Render(t("settings_encryption.title")) + "\n\n")
122
123 if isEnabled {
124 if m.confirmingDisable {
125 dialog := DialogBoxStyle.Render(
126 lipgloss.JoinVertical(lipgloss.Center,
127 dangerStyle.Render(t("settings_encryption.disable_confirm")),
128 accountEmailStyle.Render(t("settings_encryption.disable_warning")),
129 HelpStyle.Render("\n(y/n)"),
130 ),
131 )
132 b.WriteString(dialog + "\n")
133 } else {
134 b.WriteString(settingsFocusedStyle.Render(" "+t("settings_encryption.enabled")) + "\n\n")
135 b.WriteString(accountEmailStyle.Render(" "+t("settings_encryption.disable_button")) + "\n\n")
136 b.WriteString(helpStyle.Render("enter: disable"))
137 }
138 } else {
139 b.WriteString(accountEmailStyle.Render(t("settings_encryption.disabled")) + "\n\n")
140
141 if m.encFocusIndex == 0 {
142 b.WriteString(settingsFocusedStyle.Render(t("settings_encryption.password_label") + "\n"))
143 } else {
144 b.WriteString(settingsBlurredStyle.Render(t("settings_encryption.password_label") + "\n"))
145 }
146 b.WriteString(m.encPasswordInput.View() + "\n\n")
147 if m.encPasswordStrength != "" {
148 b.WriteString(" " + m.renderPasswordStrength() + "\n\n")
149 }
150
151 if m.encFocusIndex == 1 {
152 b.WriteString(settingsFocusedStyle.Render(t("settings_encryption.confirm_label") + "\n"))
153 } else {
154 b.WriteString(settingsBlurredStyle.Render(t("settings_encryption.confirm_label") + "\n"))
155 }
156 b.WriteString(m.encConfirmInput.View() + "\n")
157 if status := m.renderPasswordMatch(); status != "" {
158 b.WriteString(" " + status + "\n")
159 }
160 b.WriteString("\n")
161
162 saveBtn := "[ " + t("settings_encryption.enable_button") + " ]"
163 if m.encFocusIndex == 2 {
164 b.WriteString(settingsFocusedStyle.Render(saveBtn) + "\n")
165 } else {
166 b.WriteString(settingsBlurredStyle.Render(saveBtn) + "\n")
167 }
168
169 if m.encEnabling {
170 b.WriteString("\n" + accountEmailStyle.Render(" "+t("settings_encryption.encrypting")) + "\n")
171 }
172
173 b.WriteString("\n" + helpStyle.Render(t("settings_encryption.help")))
174 }
175
176 if m.encError != "" {
177 b.WriteString("\n" + dangerStyle.Render(" "+m.encError) + "\n")
178 }
179
180 return b.String()
181}
182
183func (m *Settings) renderPasswordMatch() string {
184 password := m.encPasswordInput.Value()
185 confirm := m.encConfirmInput.Value()
186 if confirm == "" {
187 return ""
188 }
189 if password == confirm {
190 return successStyle.Render(t("settings_encryption.passwords_match"))
191 }
192 return dangerStyle.Render(t("settings_encryption.passwords_do_not_match"))
193}
194
195func (m *Settings) handlePasswordChanged() {
196 password := m.encPasswordInput.Value()
197 if password == "" {
198 m.encPasswordStrength = ""
199 return
200 }
201 m.encPasswordStrength = m.passwordMeter.Strength(password)
202}
203
204func (m *Settings) renderPasswordStrength() string {
205 switch m.encPasswordStrength {
206 case passwordstrength.Strong:
207 return successStyle.Render(t("settings_encryption.strength_label") + " " + t("settings_encryption.strength_strong"))
208 case passwordstrength.Medium:
209 return settingsFocusedStyle.Render(t("settings_encryption.strength_label") + " " + t("settings_encryption.strength_medium"))
210 case passwordstrength.Weak:
211 return dangerStyle.Render(t("settings_encryption.strength_label") + " " + t("settings_encryption.strength_weak"))
212 }
213 return dangerStyle.Render(t("settings_encryption.strength_label") + " " + t("settings_encryption.strength_weak"))
214}