summaryrefslogtreecommitdiff
path: root/client
diff options
context:
space:
mode:
Diffstat (limited to 'client')
-rw-r--r--client/application.go100
-rw-r--r--client/cmd_window.go8
-rw-r--r--client/command.go9
-rw-r--r--client/login_prompt.go96
-rw-r--r--client/ui.go8
5 files changed, 192 insertions, 29 deletions
diff --git a/client/application.go b/client/application.go
index d396f24..640abd6 100644
--- a/client/application.go
+++ b/client/application.go
@@ -145,37 +145,109 @@ func (a *application) GetInfo(id string, callback func(*proto.Object)) {
})
}
-func (a *application) auth(name string, authCallback func(success bool)) {
- callback := func(response proto.Command) {
+func (a *application) authAnon(as string, callback func(ok bool, uid string)) {
+ cb := func(response proto.Command) {
+ switch response.Kind {
+ case "you-are":
+ if len(response.Args) == 0 {
+ callback(false, "")
+ break
+ }
+ me := response.Args[0]
+ a.onAuth(me.Id)
+ if callback != nil {
+ callback(true, me.Id)
+ }
+ case "fail":
+ var uid string
+ if len(response.Args) != 0 {
+ if response.Args[0].Kind == "name-taken" &&
+ response.Args[0].Fields["anonymous"] == "no" {
+ uid = response.Args[0].Fields["id"]
+ } else {
+ a.cmdWindow.err(proto.Strfail(response.Args[0]))
+ }
+ }
+ if callback != nil {
+ callback(false, uid)
+ }
+ }
+ }
+ a.Request(proto.NewCmd("auth", "", proto.Object {
+ "anonymous", "", map[string]string {"": as},
+ }), cb)
+}
+
+func (a *application) authPassword(
+ uid string, password string, callback func(ok bool)) {
+ cb := func(response proto.Command) {
switch response.Kind {
case "you-are":
if len(response.Args) == 0 {
- authCallback(false)
+ callback(false)
break
}
me := response.Args[0]
- a.authenticated = true
- a.uid = me.Id
- a.cache.Watch(a.uid)
- a.onAuth()
- if authCallback != nil {
- authCallback(true)
+ a.onAuth(me.Id)
+ if callback != nil {
+ callback(true)
}
case "fail":
if len(response.Args) != 0 {
a.cmdWindow.err(proto.Strfail(response.Args[0]))
}
- if authCallback != nil {
- authCallback(false)
+ if callback != nil {
+ callback(false)
}
}
}
a.Request(proto.NewCmd("auth", "", proto.Object {
- "anonymous", "", map[string]string {"": name},
- }), callback)
+ "password", "", map[string]string {"": password, "id": uid},
+ }), cb)
+}
+
+func (a *application) setPassword(password string, callback func(ok bool)) {
+ cb := func(response proto.Command) {
+ switch response.Kind {
+ case "ok":
+ if callback != nil {
+ callback(true)
+ }
+ case "fail":
+ if len(response.Args) != 0 &&
+ response.Args[0].Kind == "password-required" {
+ lp := newLoginPrompt("")
+ lp.uid = a.uid
+ lp.customPrompt = "current password"
+ lp.callback = func(ok bool) {
+ if ok {
+ a.setPassword(password, callback)
+ } else {
+ if callback != nil {
+ callback(false)
+ }
+ }
+ }
+ a.pushPrompt(lp)
+ } else {
+ if len(response.Args) != 0 {
+ a.cmdWindow.err(proto.Strfail(response.Args[0]))
+ }
+ if callback != nil {
+ callback(false)
+ }
+ }
+ }
+ }
+ a.Request(proto.NewCmd("auth-update", a.uid, proto.Object {
+ "password", "", map[string]string {"": password},
+ }), cb)
}
-func (a *application) onAuth() {
+func (a *application) onAuth(uid string) {
+ a.authenticated = true
+ a.uid = uid
+ a.cache.Watch(uid)
a.Request(proto.NewCmd("channels", ""), func(response proto.Command) {
if response.Kind == "channels" {
previousChannels := make(channelList, len(a.channelList))
diff --git a/client/cmd_window.go b/client/cmd_window.go
index dccbaba..f849560 100644
--- a/client/cmd_window.go
+++ b/client/cmd_window.go
@@ -26,6 +26,7 @@ const (
logInfo = iota
logErr
logCmd
+ logWarn
)
func (m logMsg) Id() string {
@@ -39,6 +40,8 @@ func (m logMsg) Show(odd bool) {
style = &tui.Style {Bg: colorErr[odd], Fg: tui.White}
case logCmd:
style = &tui.Style {Bg: colorCmd[odd], Fg: tui.White}
+ case logWarn:
+ style = &tui.Style {Bg: colorDefault[odd], Fg: 229}
}
tui.Push("", tui.Box {
@@ -138,6 +141,11 @@ func (w *cmdWindow) info(f string, a ...any) {
w.Buf.Add(logMsg {lastIndex, fmt.Sprintf(f, a...), logInfo})
}
+func (w *cmdWindow) warn(f string, a ...any) {
+ lastIndex++
+ w.Buf.Add(logMsg {lastIndex, fmt.Sprintf(f, a...), logWarn})
+}
+
func (w *cmdWindow) err(f string, a ...any) {
lastIndex++
w.Buf.Add(logMsg {lastIndex, fmt.Sprintf(f, a...), logErr})
diff --git a/client/command.go b/client/command.go
index 5ceb45b..64f8cd8 100644
--- a/client/command.go
+++ b/client/command.go
@@ -179,9 +179,14 @@ func (a *application) doCommand(command string, args []string, text string) {
})
return
case "create":
- if a.authenticated {
- a.createChannel(text)
+ a.createChannel(text)
+ return
+ case "password":
+ if text == "" {
+ a.cmdWindow.err("password cannot be empty")
+ return
}
+ a.pushPrompt(&passwordChangePrompt {password: text})
return
case "debug":
a.goTo(debugWindowLocation{})
diff --git a/client/login_prompt.go b/client/login_prompt.go
index c19d987..ec5b36b 100644
--- a/client/login_prompt.go
+++ b/client/login_prompt.go
@@ -7,7 +7,11 @@ import (
type loginPrompt struct {
input tui.TextInput
+ uid string
username string
+ customPrompt string
+ waiting bool
+ callback func(ok bool)
}
func newLoginPrompt(completeName string) *loginPrompt {
@@ -21,28 +25,96 @@ func newLoginPrompt(completeName string) *loginPrompt {
}
func (p *loginPrompt) Input() *tui.TextInput {
- return &p.input
+ if !p.waiting {
+ return &p.input
+ } else {
+ return &tui.TextInput {}
+ }
}
func (p *loginPrompt) Send(text string) {
- if p.username != "" {
- return
- }
- p.username = text
- globalApp.auth(text, func(success bool) {
- if success {
+ if p.uid == "" {
+ p.username = text
+ globalApp.authAnon(text, func(success bool, uid string) {
+ if success {
+ globalApp.removePrompt(p)
+ globalApp.cmdWindow.warn(
+ "you have created a temporary account. " +
+ "set a password to keep it.",
+ )
+ } else if uid == "" {
+ p.username = ""
+ } else {
+ p.uid = uid
+ p.input.SetText("")
+ p.input.Private = true
+ }
+ })
+ } else {
+ p.input.SetText("")
+ p.waiting = true
+ globalApp.authPassword(p.uid, text, func(success bool) {
+ p.waiting = false
+ if !globalApp.authenticated {
+ p.uid = ""
+ p.input.SetText(p.username)
+ p.input.Private = false
+ return
+ }
globalApp.removePrompt(p)
+ if p.callback != nil {
+ p.callback(success)
+ }
+ })
+ }
+}
+
+func (p *loginPrompt) ShowStatusLine() {
+ tui.Text("[", nil)
+ tui.Text("login", &tui.Style {
+ Bg: tui.White, Fg: tui.Blue, Bold: true,
+ })
+ tui.Text("] ", nil)
+ if p.customPrompt == "" {
+ if p.uid == "" {
+ tui.Text("username", nil)
} else {
- p.username = ""
+ tui.Text("password", nil)
}
- })
+ } else {
+ tui.Text(p.customPrompt, nil)
+ }
+ tui.Text(":", nil)
}
-func (p *loginPrompt) ShowStatusLine() {
+type passwordChangePrompt struct {
+ input tui.TextInput
+ password string
+}
+
+func (p *passwordChangePrompt) Input() *tui.TextInput {
+ p.input.Private = true
+ return &p.input
+}
+
+func (p *passwordChangePrompt) Send(text string) {
+ if text != p.password {
+ globalApp.cmdWindow.err("passwords do not match")
+ } else {
+ globalApp.setPassword(text, func(ok bool) {
+ if ok {
+ globalApp.cmdWindow.info("password changed")
+ }
+ })
+ }
+ globalApp.removePrompt(p)
+}
+
+func (p *passwordChangePrompt) ShowStatusLine() {
tui.Text("[", nil)
tui.Text("login", &tui.Style {
Bg: tui.White, Fg: tui.Blue, Bold: true,
})
- tui.Text("]", nil)
- tui.Text(" username:", nil)
+ tui.Text("] ", nil)
+ tui.Text("confirm new password:", nil)
}
diff --git a/client/ui.go b/client/ui.go
index e5917fa..6ea9fa5 100644
--- a/client/ui.go
+++ b/client/ui.go
@@ -190,7 +190,13 @@ func (a *application) showWindow() {
Width: tui.Fill, Height: tui.Children, Dir: tui.Right,
})
a.showNickBox()
- prompt.Input().Show("input")
+ input := prompt.Input()
+ priv := input.Private
+ if strings.HasPrefix(input.Text(), "/") {
+ input.Private = strings.HasPrefix(input.Text(), "/password ")
+ }
+ input.Show("input")
+ input.Private = priv
tui.Pop()
tui.Pop()