Skip to content
This repository was archived by the owner on Sep 9, 2022. It is now read-only.

Commit 9fe4010

Browse files
committed
add secman auth refresh command functions in pkg/auth/refresh
1 parent 53dd4cf commit 9fe4010

File tree

1 file changed

+241
-0
lines changed

1 file changed

+241
-0
lines changed

pkg/auth/refresh/refresh.go

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
package refresh
2+
3+
import (
4+
"os"
5+
"fmt"
6+
"strings"
7+
8+
"github.com/abdfnx/gosh"
9+
"github.com/charmbracelet/lipgloss"
10+
"github.com/scmn-dev/secman/constants"
11+
tea "github.com/charmbracelet/bubbletea"
12+
"github.com/charmbracelet/bubbles/spinner"
13+
"github.com/charmbracelet/bubbles/textinput"
14+
"github.com/scmn-dev/secman/internal/config"
15+
"github.com/scmn-dev/secman/internal/shared"
16+
)
17+
18+
const (
19+
textInput shared.Index = iota
20+
okButton
21+
cancelButton
22+
)
23+
24+
var user = config.Config("config.user")
25+
26+
type model struct {
27+
styles shared.Styles
28+
state shared.State
29+
ms string
30+
index shared.Index
31+
message string
32+
input textinput.Model
33+
spinner spinner.Model
34+
}
35+
36+
func (m *model) updateFocus() {
37+
if m.index == textInput && !m.input.Focused() {
38+
m.input.Focus()
39+
m.input.Prompt = m.styles.FocusedPrompt.String()
40+
} else if m.index != textInput && m.input.Focused() {
41+
m.input.Blur()
42+
m.input.Prompt = m.styles.Prompt.String()
43+
}
44+
}
45+
46+
func (m *model) indexForward() {
47+
m.index++
48+
if m.index > cancelButton {
49+
m.index = textInput
50+
}
51+
52+
m.updateFocus()
53+
}
54+
55+
func (m *model) indexBackward() {
56+
m.index--
57+
if m.index < textInput {
58+
m.index = cancelButton
59+
}
60+
61+
m.updateFocus()
62+
}
63+
64+
func Refresh() model {
65+
st := shared.DefaultStyles()
66+
t := textinput.NewModel()
67+
68+
t.CursorStyle = st.Cursor
69+
t.Placeholder = "Your Master Password"
70+
t.Prompt = st.FocusedPrompt.String()
71+
t.CharLimit = 50
72+
t.EchoMode = textinput.EchoPassword
73+
t.EchoCharacter = '•'
74+
t.Focus()
75+
76+
return model{
77+
styles: st,
78+
state: shared.Ready,
79+
ms: "",
80+
index: textInput,
81+
message: "",
82+
input: t,
83+
spinner: shared.NewSpinner(),
84+
}
85+
}
86+
87+
func (m model) Init() tea.Cmd {
88+
return textinput.Blink
89+
}
90+
91+
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
92+
switch msg := msg.(type) {
93+
case tea.KeyMsg:
94+
switch msg.Type {
95+
case tea.KeyCtrlC:
96+
return m, tea.Quit
97+
98+
default:
99+
if m.state == shared.Loading {
100+
return m, nil
101+
}
102+
103+
switch msg.String() {
104+
case "tab":
105+
m.indexForward()
106+
107+
case "shift+tab":
108+
m.indexBackward()
109+
110+
case "l", "k", "right":
111+
if m.index != textInput {
112+
m.indexForward()
113+
}
114+
115+
case "h", "j", "left":
116+
if m.index != textInput {
117+
m.indexBackward()
118+
}
119+
120+
case "up", "down":
121+
if m.index == textInput {
122+
m.indexForward()
123+
} else {
124+
m.index = textInput
125+
m.updateFocus()
126+
}
127+
128+
case "enter":
129+
switch m.index {
130+
case textInput:
131+
fallthrough
132+
133+
case okButton:
134+
m.state = shared.Loading
135+
m.message = ""
136+
m.ms = strings.TrimSpace(m.input.Value())
137+
138+
return m, tea.Batch(
139+
smr(m),
140+
spinner.Tick,
141+
)
142+
143+
case cancelButton:
144+
return m, tea.Quit
145+
}
146+
}
147+
148+
if m.index == textInput {
149+
var cmd tea.Cmd
150+
m.input, cmd = m.input.Update(msg)
151+
152+
return m, cmd
153+
}
154+
155+
return m, nil
156+
}
157+
158+
case shared.ErrorMsg:
159+
m.state = shared.Ready
160+
m.message = m.styles.Error.Render("Invalid master password. or if you don't have an account, please create one using the command ") + m.styles.Subtle.Render("`secman auth create`")
161+
162+
return m, nil
163+
164+
case shared.SuccessMsg:
165+
m.state = shared.Ready
166+
m.message = m.styles.Wrap.Render(m.styles.Success.Render("🔗 Refreshed"))
167+
168+
return m, nil
169+
170+
case shared.Message:
171+
m.state = shared.Ready
172+
head := m.styles.Error.Render("Oh, what? There was a curious error we were not expecting.\n")
173+
body := m.styles.Subtle.Render(msg.Error())
174+
m.message = m.styles.Wrap.Render(head + body)
175+
176+
return m, nil
177+
178+
case spinner.TickMsg:
179+
var cmd tea.Cmd
180+
m.spinner, cmd = m.spinner.Update(msg)
181+
182+
return m, cmd
183+
184+
default:
185+
var cmd tea.Cmd
186+
m.input, cmd = m.input.Update(msg)
187+
188+
return m, cmd
189+
}
190+
}
191+
192+
func (m model) View() string {
193+
if user == "" {
194+
fmt.Println(lipgloss.NewStyle().Padding(0, 2).SetString(constants.Logo("Secman Auth") + m.styles.Error.Render("\n\nYou are not logged in. Please use ") + m.styles.Subtle.Render("`secman auth`") + m.styles.Error.Render(" command to login.")))
195+
196+
os.Exit(0)
197+
198+
return ""
199+
} else {
200+
s := "\n\nPlease enter your Master Password\n\n"
201+
s += m.input.View() + "\n\n"
202+
203+
if m.state == shared.Loading {
204+
s += spinnerView(m)
205+
} else {
206+
s += shared.OKButton(m.index == 1, true, "Yes")
207+
s += " " + shared.CancelButton(m.index == 2, false, "Exit")
208+
209+
if m.message != "" {
210+
fmt.Println(lipgloss.NewStyle().Padding(0, 2).SetString(m.message).String())
211+
os.Exit(0)
212+
}
213+
}
214+
215+
return lipgloss.NewStyle().Padding(0, 2).SetString(constants.Logo("Secman Auth") + s).String()
216+
}
217+
}
218+
219+
func spinnerView(m model) string {
220+
return m.spinner.View() + "🔗 Refreshing..."
221+
}
222+
223+
func smr(m model) tea.Cmd {
224+
return func() tea.Msg {
225+
err, out, _ := gosh.RunOutput("sc auth -e " + user + " -m " + m.ms)
226+
227+
if err != nil {
228+
return shared.Message{err}
229+
}
230+
231+
out = strings.TrimSuffix(out, "\n")
232+
233+
if strings.Contains(out, "401") {
234+
return shared.ErrorMsg{}
235+
} else if strings.Contains(out, "406") {
236+
return shared.SuccessMsg{}
237+
}
238+
239+
return shared.SetMsg(out)
240+
}
241+
}

0 commit comments

Comments
 (0)