login-app: Use a pure-Go tty interface instead of curses
This commit is contained in:
parent
af53a37d33
commit
8ab758ac9a
8 changed files with 372 additions and 294 deletions
5
Makefile
5
Makefile
|
@ -1,10 +1,11 @@
|
||||||
tuto1: token-validator/token-validator server.iso
|
tuto1: token-validator/token-validator server.iso
|
||||||
|
|
||||||
login-app: pkg/login-app/build.yml pkg/login-app/Dockerfile pkg/login-app/cmd/login.go pkg/login-app/cmd/main.go pkg/login-app/cmd/windows.go
|
pkg/login-app: pkg/login-app/cmd/login.go pkg/login-app/cmd/dialog-checklogin.go pkg/login-app/cmd/cmd pkg/login-app/cmd/dialog-login.go pkg/login-app/cmd/login-app pkg/login-app/cmd/dialog-errmsg.go pkg/login-app/cmd/main.go pkg/login-app/cmd/dialog-reboot.go pkg/login-app/cmd/debug.log pkg/login-app/build.yml pkg/login-app/Dockerfile
|
||||||
linuxkit pkg build -org nemunaire pkg/login-app/
|
linuxkit pkg build -org nemunaire pkg/login-app/
|
||||||
#linuxkit pkg push -org nemunaire --sign=false pkg/login-app/
|
#linuxkit pkg push -org nemunaire --sign=false pkg/login-app/
|
||||||
|
touch pkg/login-app
|
||||||
|
|
||||||
login-initrd.img: login.yml login-app
|
login-initrd.img: login.yml pkg/login-app
|
||||||
linuxkit build -docker $<
|
linuxkit build -docker $<
|
||||||
|
|
||||||
token-validator/token-validator: token-validator/*.go
|
token-validator/token-validator: token-validator/*.go
|
||||||
|
|
|
@ -3,14 +3,14 @@ FROM golang:alpine as gobuild
|
||||||
ENV GOOS linux
|
ENV GOOS linux
|
||||||
ENV GOARCH amd64
|
ENV GOARCH amd64
|
||||||
|
|
||||||
RUN apk add --no-cache git pkgconfig ncurses-dev ncurses-static gcc libc-dev
|
RUN apk add --no-cache git gcc
|
||||||
|
|
||||||
WORKDIR /go/src/login-app
|
WORKDIR /go/src/login-app
|
||||||
|
|
||||||
ADD cmd ./
|
ADD cmd ./
|
||||||
|
|
||||||
RUN go get -d -v
|
RUN go get -d -v
|
||||||
RUN go build -v -tags netgo -ldflags '-w -extldflags "-static -lpanelw -lncursesw"'
|
RUN go build -v -tags netgo
|
||||||
|
|
||||||
|
|
||||||
FROM alpine
|
FROM alpine
|
||||||
|
@ -19,7 +19,6 @@ MAINTAINER Pierre-Olivier Mercier <nemunaire@nemunai.re>
|
||||||
EXPOSE 8081
|
EXPOSE 8081
|
||||||
|
|
||||||
COPY --from=gobuild /go/src/login-app/login-app /bin/login-app
|
COPY --from=gobuild /go/src/login-app/login-app /bin/login-app
|
||||||
COPY --from=gobuild /etc/terminfo/l/linux /etc/terminfo/l/linux
|
|
||||||
COPY --from=gobuild /usr/share/udhcpc/default.script /usr/share/udhcpc/default.script
|
COPY --from=gobuild /usr/share/udhcpc/default.script /usr/share/udhcpc/default.script
|
||||||
|
|
||||||
ENTRYPOINT ["/bin/login-app"]
|
ENTRYPOINT ["/bin/login-app"]
|
||||||
|
|
79
pkg/login-app/cmd/dialog-checklogin.go
Normal file
79
pkg/login-app/cmd/dialog-checklogin.go
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
ui "github.com/VladimirMarkelov/clui"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CheckDialog struct {
|
||||||
|
View *ui.Window
|
||||||
|
|
||||||
|
result int
|
||||||
|
beforeClose func(ui.Event)
|
||||||
|
onClose func()
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateCheckDialog(title, username, password string) *CheckDialog {
|
||||||
|
dlg := new(CheckDialog)
|
||||||
|
|
||||||
|
sWidth, sHeight := ui.ScreenSize()
|
||||||
|
wWidth, wHeight := 40, 5
|
||||||
|
dlg.View = ui.AddWindow(sWidth/2-wWidth/2, sHeight/2-wHeight/2, wWidth, wHeight, title)
|
||||||
|
ui.WindowManager().BeginUpdate()
|
||||||
|
defer ui.WindowManager().EndUpdate()
|
||||||
|
|
||||||
|
dlg.View.SetModal(true)
|
||||||
|
dlg.View.SetSizable(false)
|
||||||
|
dlg.View.SetTitleButtons(ui.ButtonDefault)
|
||||||
|
dlg.View.SetPack(ui.Vertical)
|
||||||
|
|
||||||
|
textfrm := ui.CreateFrame(dlg.View, 1, 1, ui.BorderNone, ui.Fixed)
|
||||||
|
textfrm.SetPaddings(1, 1)
|
||||||
|
textfrm.SetPack(ui.Vertical)
|
||||||
|
textfrm.SetGaps(2, 1)
|
||||||
|
ui.CreateLabel(textfrm, ui.AutoSize, ui.AutoSize, " Please wait", ui.Fixed)
|
||||||
|
|
||||||
|
progress := ui.CreateProgressBar(textfrm, ui.AutoSize, ui.AutoSize, 1)
|
||||||
|
progress.SetLimits(0, 100)
|
||||||
|
|
||||||
|
ui.CreateLabel(textfrm, ui.AutoSize, ui.AutoSize, "Connecting to login server...", ui.Fixed)
|
||||||
|
|
||||||
|
dlg.View.OnKeyDown(func(ev ui.Event, data interface{}) bool {
|
||||||
|
if ev.Key == 0 && ev.Msg == "login-complete" {
|
||||||
|
if dlg.beforeClose != nil {
|
||||||
|
dlg.beforeClose(ev)
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.WindowManager().DestroyWindow(dlg.View)
|
||||||
|
ui.WindowManager().BeginUpdate()
|
||||||
|
|
||||||
|
closeFunc := dlg.onClose
|
||||||
|
ui.WindowManager().EndUpdate()
|
||||||
|
if closeFunc != nil {
|
||||||
|
closeFunc()
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if ok, err := checkLogin(username, password); ok {
|
||||||
|
ui.PutEvent(ui.Event{Type: ui.EventKey, Msg: "login-complete"})
|
||||||
|
} else {
|
||||||
|
ui.PutEvent(ui.Event{Type: ui.EventKey, Msg: "login-complete", Err: err})
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for i := 0; i < 422; i += 1 {
|
||||||
|
progress.SetValue(int(math.Floor(math.Log(float64(i)*8)*16 - 30)))
|
||||||
|
time.Sleep(64 * time.Millisecond)
|
||||||
|
ui.PutEvent(ui.Event{Type: ui.EventRedraw})
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return dlg
|
||||||
|
}
|
85
pkg/login-app/cmd/dialog-errmsg.go
Normal file
85
pkg/login-app/cmd/dialog-errmsg.go
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
ui "github.com/VladimirMarkelov/clui"
|
||||||
|
term "github.com/nsf/termbox-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ErrMsgDialog struct {
|
||||||
|
View *ui.Window
|
||||||
|
|
||||||
|
result int
|
||||||
|
beforeClose func()
|
||||||
|
onClose func()
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateErrMsgDialog(title string, err error) *ErrMsgDialog {
|
||||||
|
dlg := new(ErrMsgDialog)
|
||||||
|
|
||||||
|
sWidth, sHeight := ui.ScreenSize()
|
||||||
|
wWidth, wHeight := 60, 10
|
||||||
|
dlg.View = ui.AddWindow(sWidth/2-wWidth/2, sHeight/2-wHeight/2, wWidth, wHeight, title)
|
||||||
|
ui.WindowManager().BeginUpdate()
|
||||||
|
defer ui.WindowManager().EndUpdate()
|
||||||
|
|
||||||
|
dlg.View.SetModal(true)
|
||||||
|
dlg.View.SetSizable(false)
|
||||||
|
dlg.View.SetTitleButtons(ui.ButtonDefault)
|
||||||
|
dlg.View.SetPack(ui.Vertical)
|
||||||
|
|
||||||
|
textfrm := ui.CreateFrame(dlg.View, 1, 1, ui.BorderNone, ui.Fixed)
|
||||||
|
textfrm.SetPaddings(1, 1)
|
||||||
|
textfrm.SetPack(ui.Vertical)
|
||||||
|
textfrm.SetGaps(2, 1)
|
||||||
|
|
||||||
|
lbl := ui.CreateLabel(textfrm, ui.AutoSize, ui.AutoSize, "An error occurs:", ui.Fixed)
|
||||||
|
lbl.SetTextColor(ui.ColorRedBold)
|
||||||
|
|
||||||
|
tv := ui.CreateTextView(textfrm, ui.AutoSize, 4, ui.Fixed)
|
||||||
|
tv.SetWordWrap(true)
|
||||||
|
tv.SetText([]string{err.Error()})
|
||||||
|
tv.SetTextColor(ui.ColorWhite)
|
||||||
|
tv.SetBackColor(ui.ColorBlack)
|
||||||
|
|
||||||
|
ui.CreateLabel(textfrm, ui.AutoSize, ui.AutoSize, "Please try again.", ui.Fixed)
|
||||||
|
|
||||||
|
btnOk := ui.CreateButton(textfrm, 20, 4, "Ok", 1)
|
||||||
|
|
||||||
|
btnOk.OnClick(func(ev ui.Event) {
|
||||||
|
if dlg.beforeClose != nil {
|
||||||
|
dlg.beforeClose()
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.WindowManager().DestroyWindow(dlg.View)
|
||||||
|
ui.WindowManager().BeginUpdate()
|
||||||
|
|
||||||
|
closeFunc := dlg.onClose
|
||||||
|
ui.WindowManager().EndUpdate()
|
||||||
|
if closeFunc != nil {
|
||||||
|
closeFunc()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
dlg.View.OnKeyDown(func(ev ui.Event, data interface{}) bool {
|
||||||
|
if ev.Key == term.KeyEnter {
|
||||||
|
if dlg.beforeClose != nil {
|
||||||
|
dlg.beforeClose()
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.WindowManager().DestroyWindow(dlg.View)
|
||||||
|
ui.WindowManager().BeginUpdate()
|
||||||
|
|
||||||
|
closeFunc := dlg.onClose
|
||||||
|
ui.WindowManager().EndUpdate()
|
||||||
|
if closeFunc != nil {
|
||||||
|
closeFunc()
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
ui.ActivateControl(dlg.View, btnOk)
|
||||||
|
|
||||||
|
return dlg
|
||||||
|
}
|
124
pkg/login-app/cmd/dialog-login.go
Normal file
124
pkg/login-app/cmd/dialog-login.go
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
ui "github.com/VladimirMarkelov/clui"
|
||||||
|
term "github.com/nsf/termbox-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
LoginOk = iota
|
||||||
|
LoginCanceled
|
||||||
|
LoginInvalid
|
||||||
|
)
|
||||||
|
|
||||||
|
type LoginDialog struct {
|
||||||
|
View *ui.Window
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
Action int
|
||||||
|
|
||||||
|
result int
|
||||||
|
beforeClose func()
|
||||||
|
onClose func()
|
||||||
|
onCheck func(string, string) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateLoginDialog(title string) *LoginDialog {
|
||||||
|
dlg := new(LoginDialog)
|
||||||
|
|
||||||
|
sWidth, sHeight := ui.ScreenSize()
|
||||||
|
wWidth, wHeight := 40, 15
|
||||||
|
dlg.View = ui.AddWindow(sWidth/2-wWidth/2, sHeight/2-wHeight/2, wWidth, wHeight, title)
|
||||||
|
ui.WindowManager().BeginUpdate()
|
||||||
|
defer ui.WindowManager().EndUpdate()
|
||||||
|
|
||||||
|
dlg.View.SetModal(true)
|
||||||
|
dlg.View.SetSizable(false)
|
||||||
|
dlg.View.SetTitleButtons(ui.ButtonDefault)
|
||||||
|
dlg.View.SetPack(ui.Vertical)
|
||||||
|
|
||||||
|
userfrm := ui.CreateFrame(dlg.View, 1, 1, ui.BorderNone, ui.Fixed)
|
||||||
|
userfrm.SetPaddings(1, 1)
|
||||||
|
userfrm.SetPack(ui.Horizontal)
|
||||||
|
userfrm.SetGaps(1, 0)
|
||||||
|
ui.CreateLabel(userfrm, ui.AutoSize, ui.AutoSize, " Login", ui.Fixed)
|
||||||
|
edUser := ui.CreateEditField(userfrm, 20, "", 1)
|
||||||
|
|
||||||
|
passfrm := ui.CreateFrame(dlg.View, 1, 1, ui.BorderNone, 1)
|
||||||
|
passfrm.SetPaddings(1, 1)
|
||||||
|
passfrm.SetPack(ui.Horizontal)
|
||||||
|
passfrm.SetGaps(1, 0)
|
||||||
|
ui.CreateLabel(passfrm, ui.AutoSize, ui.AutoSize, "Password", ui.Fixed)
|
||||||
|
edPass := ui.CreateEditField(passfrm, 20, "", 1)
|
||||||
|
edPass.SetPasswordMode(true)
|
||||||
|
|
||||||
|
filler := ui.CreateFrame(dlg.View, 1, 1, ui.BorderNone, 1)
|
||||||
|
filler.SetPack(ui.Horizontal)
|
||||||
|
lbRes := ui.CreateLabel(filler, ui.AutoSize, ui.AutoSize, "", 1)
|
||||||
|
|
||||||
|
blist := ui.CreateFrame(dlg.View, 1, 1, ui.BorderNone, ui.Fixed)
|
||||||
|
blist.SetPack(ui.Horizontal)
|
||||||
|
blist.SetPaddings(1, 1)
|
||||||
|
btnOk := ui.CreateButton(blist, 20, 4, "Authenticate me", 1)
|
||||||
|
|
||||||
|
btnOk.OnClick(func(ev ui.Event) {
|
||||||
|
if dlg.onCheck != nil && !dlg.onCheck(edUser.Title(), edPass.Title()) {
|
||||||
|
lbRes.SetTitle("Invalid username or password")
|
||||||
|
dlg.Action = LoginInvalid
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dlg.Action = LoginOk
|
||||||
|
if dlg.onCheck == nil {
|
||||||
|
dlg.Username = edUser.Title()
|
||||||
|
dlg.Password = edPass.Title()
|
||||||
|
}
|
||||||
|
|
||||||
|
if dlg.beforeClose != nil {
|
||||||
|
dlg.beforeClose()
|
||||||
|
}
|
||||||
|
ui.WindowManager().DestroyWindow(dlg.View)
|
||||||
|
ui.WindowManager().BeginUpdate()
|
||||||
|
|
||||||
|
closeFunc := dlg.onClose
|
||||||
|
ui.WindowManager().EndUpdate()
|
||||||
|
if closeFunc != nil {
|
||||||
|
closeFunc()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
dlg.View.OnKeyDown(func(ev ui.Event, data interface{}) bool {
|
||||||
|
if ev.Key == term.KeyEnter {
|
||||||
|
if edUser.Title() == "" {
|
||||||
|
ui.ActivateControl(dlg.View, edUser)
|
||||||
|
} else if edPass.Title() == "" {
|
||||||
|
ui.ActivateControl(dlg.View, edPass)
|
||||||
|
} else {
|
||||||
|
if dlg.beforeClose != nil {
|
||||||
|
dlg.beforeClose()
|
||||||
|
}
|
||||||
|
ui.WindowManager().DestroyWindow(dlg.View)
|
||||||
|
ui.WindowManager().BeginUpdate()
|
||||||
|
|
||||||
|
closeFunc := dlg.onClose
|
||||||
|
ui.WindowManager().EndUpdate()
|
||||||
|
if closeFunc != nil {
|
||||||
|
closeFunc()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}, nil)
|
||||||
|
|
||||||
|
edUser.OnChange(func(ev ui.Event) {
|
||||||
|
lbRes.SetTitle("")
|
||||||
|
})
|
||||||
|
edPass.OnChange(func(ev ui.Event) {
|
||||||
|
lbRes.SetTitle("")
|
||||||
|
})
|
||||||
|
|
||||||
|
ui.ActivateControl(dlg.View, edUser)
|
||||||
|
|
||||||
|
return dlg
|
||||||
|
}
|
50
pkg/login-app/cmd/dialog-reboot.go
Normal file
50
pkg/login-app/cmd/dialog-reboot.go
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
ui "github.com/VladimirMarkelov/clui"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RebootDialog struct {
|
||||||
|
View *ui.Window
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateRebootDialog(title, login string) *RebootDialog {
|
||||||
|
dlg := new(RebootDialog)
|
||||||
|
|
||||||
|
sWidth, sHeight := ui.ScreenSize()
|
||||||
|
wWidth, wHeight := 50, 10
|
||||||
|
dlg.View = ui.AddWindow(sWidth/2-wWidth/2, sHeight/2-wHeight/2, wWidth, wHeight, title)
|
||||||
|
ui.WindowManager().BeginUpdate()
|
||||||
|
defer ui.WindowManager().EndUpdate()
|
||||||
|
|
||||||
|
dlg.View.SetModal(true)
|
||||||
|
dlg.View.SetSizable(false)
|
||||||
|
dlg.View.SetTitleButtons(ui.ButtonDefault)
|
||||||
|
dlg.View.SetPack(ui.Vertical)
|
||||||
|
|
||||||
|
textfrm := ui.CreateFrame(dlg.View, 1, 1, ui.BorderNone, ui.Fixed)
|
||||||
|
textfrm.SetPaddings(1, 1)
|
||||||
|
textfrm.SetPack(ui.Vertical)
|
||||||
|
textfrm.SetGaps(2, 1)
|
||||||
|
ui.CreateLabel(textfrm, ui.AutoSize, ui.AutoSize, "You are now successfully logged in as:", ui.Fixed)
|
||||||
|
ui.CreateLabel(textfrm, ui.AutoSize, ui.AutoSize, login, ui.Fixed)
|
||||||
|
|
||||||
|
ui.CreateLabel(textfrm, ui.AutoSize, ui.AutoSize, "Your computer will automatically", ui.Fixed)
|
||||||
|
ui.CreateLabel(textfrm, ui.AutoSize, ui.AutoSize, "reboot in a few seconds...", ui.Fixed)
|
||||||
|
|
||||||
|
progress := ui.CreateProgressBar(textfrm, ui.AutoSize, ui.AutoSize, 1)
|
||||||
|
progress.SetLimits(0, 100)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for i := 0; i < 100; i += 1 {
|
||||||
|
progress.SetValue(i)
|
||||||
|
ui.PutEvent(ui.Event{Type: ui.EventRedraw})
|
||||||
|
time.Sleep(64 * time.Millisecond)
|
||||||
|
}
|
||||||
|
ui.WindowManager().DestroyWindow(dlg.View)
|
||||||
|
}()
|
||||||
|
|
||||||
|
return dlg
|
||||||
|
}
|
|
@ -1,58 +1,47 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
gc "github.com/rthornton128/goncurses"
|
"os"
|
||||||
|
|
||||||
|
ui "github.com/VladimirMarkelov/clui"
|
||||||
)
|
)
|
||||||
|
|
||||||
const URLLogin = "https://auth.adlin.nemunai.re/login"
|
const URLLogin = "https://auth.adlin.nemunai.re/login"
|
||||||
|
|
||||||
func goLogin(stdscr *gc.Window, in chan gc.Key) (string, string, bool) {
|
var logged = false
|
||||||
username, password := login(stdscr, in)
|
|
||||||
|
|
||||||
validator := make(chan bool)
|
func askLogin() (lgd *LoginDialog) {
|
||||||
validator_err := make(chan error)
|
lgd = CreateLoginDialog(" SRS AdLin - Login ")
|
||||||
go func(username, password string, progress chan bool, err chan error) {
|
|
||||||
st, errm := checkLogin(username, password)
|
|
||||||
progress <- st
|
|
||||||
err <- errm
|
|
||||||
}(username, password, validator, validator_err)
|
|
||||||
|
|
||||||
if connection(stdscr, in, validator, validator_err) {
|
lgd.beforeClose = func() {
|
||||||
e := <-validator_err
|
// Display next dialoag
|
||||||
return username, e.Error(), true
|
ckd := CreateCheckDialog(" SRS AdLin - Login ", lgd.Username, lgd.Password)
|
||||||
} else {
|
|
||||||
return goLogin(stdscr, in)
|
ckd.beforeClose = func(ev ui.Event) {
|
||||||
|
if ev.Err == nil {
|
||||||
|
logged = true
|
||||||
|
CreateRebootDialog(" SRS AdLin - Login", lgd.Username)
|
||||||
|
} else {
|
||||||
|
errd := CreateErrMsgDialog(" SRS AdLin - Login ", ev.Err)
|
||||||
|
errd.beforeClose = func() {
|
||||||
|
askLogin()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
stdscr, _ := gc.Init()
|
ui.InitLibrary()
|
||||||
defer gc.End()
|
defer ui.DeinitLibrary()
|
||||||
|
|
||||||
// Set main properties
|
askLogin()
|
||||||
gc.Cursor(0)
|
|
||||||
gc.StartColor()
|
|
||||||
gc.Raw(true)
|
|
||||||
gc.Echo(false)
|
|
||||||
stdscr.Keypad(true)
|
|
||||||
|
|
||||||
// Define colors
|
ui.MainLoop()
|
||||||
gc.InitPair(1, gc.C_WHITE, gc.C_BLUE)
|
|
||||||
gc.InitPair(2, gc.C_GREEN, gc.C_BLACK)
|
|
||||||
gc.InitPair(3, gc.C_CYAN, gc.C_BLACK)
|
|
||||||
gc.InitPair(4, gc.C_RED, gc.C_BLACK)
|
|
||||||
gc.InitPair(5, gc.C_BLACK, gc.C_WHITE)
|
|
||||||
|
|
||||||
// Register pressed key through channel
|
if !logged {
|
||||||
in := make(chan gc.Key)
|
os.Exit(1)
|
||||||
go func(w *gc.Window, ch chan<- gc.Key) {
|
|
||||||
for {
|
|
||||||
ch <- w.GetChar()
|
|
||||||
}
|
|
||||||
}(stdscr, in)
|
|
||||||
|
|
||||||
// Run!
|
|
||||||
if username, ip, ok := goLogin(stdscr, in); ok {
|
|
||||||
okreboot(stdscr, username, ip)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,249 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
gc "github.com/rthornton128/goncurses"
|
|
||||||
)
|
|
||||||
|
|
||||||
func login(stdscr *gc.Window, in chan gc.Key) (username, password string) {
|
|
||||||
gc.Cursor(1)
|
|
||||||
stdscr.Clear()
|
|
||||||
|
|
||||||
// Initialize the fields and Set field options
|
|
||||||
fields := make([]*gc.Field, 3)
|
|
||||||
fields[0], _ = gc.NewField(1, 28, 2, 12, 0, 0)
|
|
||||||
defer fields[0].Free()
|
|
||||||
fields[0].SetBackground(gc.ColorPair(5) | gc.A_UNDERLINE)
|
|
||||||
fields[0].SetOptionsOff(gc.FO_AUTOSKIP)
|
|
||||||
|
|
||||||
fields[1], _ = gc.NewField(1, 28, 4, 12, 0, 0)
|
|
||||||
defer fields[1].Free()
|
|
||||||
fields[1].SetBackground(gc.ColorPair(5) | gc.A_UNDERLINE)
|
|
||||||
fields[1].SetOptionsOff(gc.FO_PUBLIC)
|
|
||||||
fields[1].SetOptionsOff(gc.FO_AUTOSKIP)
|
|
||||||
|
|
||||||
fields[2], _ = gc.NewField(1, 11, 7, 18, 0, 0)
|
|
||||||
defer fields[2].Free()
|
|
||||||
fields[2].SetBuffer("< Connect >")
|
|
||||||
fields[2].SetBackground(gc.ColorPair(1))
|
|
||||||
fields[2].SetOptionsOff(gc.FO_EDIT)
|
|
||||||
fields[2].SetOptionsOff(gc.FO_AUTOSKIP)
|
|
||||||
|
|
||||||
// Create the form and post it
|
|
||||||
form, _ := gc.NewForm(fields)
|
|
||||||
defer form.Free()
|
|
||||||
|
|
||||||
// Create the window to be associated with the form
|
|
||||||
rows, cols := stdscr.MaxYX()
|
|
||||||
height, width := 14, 44
|
|
||||||
y, x := (rows-height)/2, (cols-width)/2
|
|
||||||
|
|
||||||
mainwin, _ := gc.NewWindow(height, width, y, x)
|
|
||||||
defer mainwin.Delete()
|
|
||||||
defer mainwin.Erase()
|
|
||||||
mainwin.Keypad(true)
|
|
||||||
|
|
||||||
// Set main window and sub window
|
|
||||||
form.SetWindow(mainwin)
|
|
||||||
form.SetSub(mainwin.Derived(8, 42, 3, 1))
|
|
||||||
|
|
||||||
// Print a border around the main window and print a title
|
|
||||||
mainwin.Box(0, 0)
|
|
||||||
|
|
||||||
y, x = mainwin.MaxYX()
|
|
||||||
title := "SRS ADLIN - Login"
|
|
||||||
mainwin.ColorOn(2)
|
|
||||||
mainwin.MovePrint(1, (x/2)-(len(title)/2), title)
|
|
||||||
mainwin.ColorOff(1)
|
|
||||||
mainwin.MoveAddChar(2, 0, gc.ACS_LTEE)
|
|
||||||
mainwin.HLine(2, 1, gc.ACS_HLINE, x-2)
|
|
||||||
mainwin.MoveAddChar(2, x-1, gc.ACS_RTEE)
|
|
||||||
stdscr.Refresh()
|
|
||||||
|
|
||||||
form.Post()
|
|
||||||
defer form.UnPost()
|
|
||||||
|
|
||||||
mainwin.MovePrint(5, 3, "Login:")
|
|
||||||
mainwin.MovePrint(7, 3, "Password:")
|
|
||||||
|
|
||||||
form.Driver(gc.REQ_FIRST_FIELD)
|
|
||||||
|
|
||||||
stdscr.Refresh()
|
|
||||||
mainwin.Refresh()
|
|
||||||
|
|
||||||
login:
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case ch := <-in:
|
|
||||||
switch ch {
|
|
||||||
case gc.KEY_DOWN, gc.KEY_TAB:
|
|
||||||
form.Driver(gc.REQ_NEXT_FIELD)
|
|
||||||
form.Driver(gc.REQ_END_LINE)
|
|
||||||
case gc.KEY_UP:
|
|
||||||
form.Driver(gc.REQ_PREV_FIELD)
|
|
||||||
form.Driver(gc.REQ_END_LINE)
|
|
||||||
case gc.KEY_BACKSPACE:
|
|
||||||
form.Driver(gc.REQ_CLR_FIELD)
|
|
||||||
case gc.KEY_RETURN:
|
|
||||||
form.Driver(gc.REQ_NEXT_FIELD)
|
|
||||||
form.Driver(gc.REQ_END_LINE)
|
|
||||||
if len(strings.TrimSpace(fields[0].Buffer())) > 0 && len(strings.TrimSpace(fields[1].Buffer())) > 0 {
|
|
||||||
break login
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
form.Driver(ch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mainwin.Refresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
username = strings.TrimSpace(fields[0].Buffer())
|
|
||||||
password = strings.TrimSpace(fields[1].Buffer())
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func connection(stdscr *gc.Window, in chan gc.Key, validator chan bool, validator_err chan error) (canContinue bool) {
|
|
||||||
gc.Cursor(0)
|
|
||||||
stdscr.Clear()
|
|
||||||
|
|
||||||
// Create the window to be associated with the form
|
|
||||||
rows, cols := stdscr.MaxYX()
|
|
||||||
height, width := 10, 60
|
|
||||||
y, x := (rows-height)/2, (cols-width)/2
|
|
||||||
|
|
||||||
mainwin, _ := gc.NewWindow(height, width, y, x)
|
|
||||||
defer mainwin.Delete()
|
|
||||||
mainwin.Keypad(true)
|
|
||||||
|
|
||||||
// Print a border around the main window and print a title
|
|
||||||
mainwin.Box(0, 0)
|
|
||||||
|
|
||||||
y, x = mainwin.MaxYX()
|
|
||||||
title := "SRS ADLIN - Login"
|
|
||||||
mainwin.ColorOn(2)
|
|
||||||
mainwin.MovePrint(1, (x/2)-(len(title)/2), title)
|
|
||||||
mainwin.ColorOff(2)
|
|
||||||
mainwin.MoveAddChar(2, 0, gc.ACS_LTEE)
|
|
||||||
mainwin.HLine(2, 1, gc.ACS_HLINE, x-2)
|
|
||||||
mainwin.MoveAddChar(2, x-1, gc.ACS_RTEE)
|
|
||||||
stdscr.Refresh()
|
|
||||||
|
|
||||||
mainwin.MovePrint(4, 4, " Please wait...")
|
|
||||||
mainwin.ColorOn(3)
|
|
||||||
mainwin.MovePrint(6, 2, "Connecting to login server...")
|
|
||||||
mainwin.ColorOff(3)
|
|
||||||
|
|
||||||
stdscr.Refresh()
|
|
||||||
mainwin.Refresh()
|
|
||||||
|
|
||||||
ticker := time.NewTicker(time.Millisecond * 150)
|
|
||||||
|
|
||||||
rotPos := 0
|
|
||||||
loginloop:
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case ch := <-in:
|
|
||||||
if gc.Char(ch) == gc.Char('r') {
|
|
||||||
break loginloop
|
|
||||||
}
|
|
||||||
case st := <-validator:
|
|
||||||
if st {
|
|
||||||
canContinue = true
|
|
||||||
break loginloop
|
|
||||||
} else {
|
|
||||||
e := <-validator_err
|
|
||||||
|
|
||||||
mainwin.ColorOn(4)
|
|
||||||
mainwin.MovePrint(4, 2, e.Error())
|
|
||||||
mainwin.ColorOff(4)
|
|
||||||
ticker.Stop()
|
|
||||||
|
|
||||||
mainwin.MovePrint(7, 2, " Press any key to retry ")
|
|
||||||
mainwin.Refresh()
|
|
||||||
<-in
|
|
||||||
|
|
||||||
break loginloop
|
|
||||||
}
|
|
||||||
case <-ticker.C:
|
|
||||||
switch rotPos += 1; rotPos {
|
|
||||||
case 0, 4:
|
|
||||||
mainwin.MovePrint(4, 4, "|")
|
|
||||||
case 1, 5:
|
|
||||||
mainwin.MovePrint(4, 4, "/")
|
|
||||||
case 2, 6:
|
|
||||||
mainwin.MovePrint(4, 4, "-")
|
|
||||||
case 3, 7:
|
|
||||||
mainwin.MovePrint(4, 4, "\\")
|
|
||||||
default:
|
|
||||||
mainwin.MovePrint(4, 4, "|")
|
|
||||||
rotPos = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mainwin.Refresh()
|
|
||||||
}
|
|
||||||
ticker.Stop()
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func okreboot(stdscr *gc.Window, login string, ip string) {
|
|
||||||
gc.Cursor(0)
|
|
||||||
stdscr.Clear()
|
|
||||||
|
|
||||||
// Create the window to be associated with the form
|
|
||||||
rows, cols := stdscr.MaxYX()
|
|
||||||
height, width := 14, 42
|
|
||||||
y, x := (rows-height)/2, (cols-width)/2
|
|
||||||
|
|
||||||
mainwin, _ := gc.NewWindow(height, width, y, x)
|
|
||||||
defer mainwin.Delete()
|
|
||||||
mainwin.Keypad(true)
|
|
||||||
|
|
||||||
// Print a border around the main window and print a title
|
|
||||||
mainwin.Box(0, 0)
|
|
||||||
|
|
||||||
y, x = mainwin.MaxYX()
|
|
||||||
title := "SRS ADLIN"
|
|
||||||
mainwin.ColorOn(2)
|
|
||||||
mainwin.MovePrint(1, (x/2)-(len(title)/2), title)
|
|
||||||
mainwin.ColorOff(2)
|
|
||||||
mainwin.MoveAddChar(2, 0, gc.ACS_LTEE)
|
|
||||||
mainwin.HLine(2, 1, gc.ACS_HLINE, x-2)
|
|
||||||
mainwin.MoveAddChar(2, x-1, gc.ACS_RTEE)
|
|
||||||
stdscr.Refresh()
|
|
||||||
|
|
||||||
mainwin.ColorOn(2)
|
|
||||||
mainwin.MovePrint(4, 2, "You are now successfully logged in as: ")
|
|
||||||
mainwin.ColorOff(2)
|
|
||||||
mainwin.ColorOn(3)
|
|
||||||
mainwin.MovePrint(5, (x/2)-(len(login)/2), login)
|
|
||||||
mainwin.ColorOff(3)
|
|
||||||
|
|
||||||
mainwin.MovePrint(8, 2, "Your computer will automatically")
|
|
||||||
mainwin.MovePrint(9, 2, "reboot in a few seconds...")
|
|
||||||
|
|
||||||
mainwin.MovePrint(11, 2, "|------------------------------------|")
|
|
||||||
|
|
||||||
stdscr.Refresh()
|
|
||||||
mainwin.Refresh()
|
|
||||||
|
|
||||||
ticker := time.NewTicker(time.Millisecond * 98)
|
|
||||||
|
|
||||||
pos := 0
|
|
||||||
rebootloop:
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ticker.C:
|
|
||||||
mainwin.MovePrint(11, 3+pos, "*")
|
|
||||||
pos += 1
|
|
||||||
if pos > 36 {
|
|
||||||
break rebootloop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mainwin.Refresh()
|
|
||||||
}
|
|
||||||
ticker.Stop()
|
|
||||||
}
|
|
Reference in a new issue