package main
import (
"fmt"
"github.com/ThomasRooney/gexpect"
)
func main() {
child, err := gexpect.Spawn(fmt.Sprintf("/usr/local/opt/mysql-client/bin/mysql -h 127.0.0.1 -u %s -p", "root"))
if err != nil {
panic(err)
}
child.Expect("Enter password")
child.SendLine("123123\n")
child.Expect("mysql>")
fmt.Printf("mysql>")
child.Interact()
fmt.Printf("Done \n")
child.Close()
}
Created
September 5, 2019 09:58
-
-
Save sh7ning/1139d1a62c362528212a00d9e7b61589 to your computer and use it in GitHub Desktop.
auto-login-mysql.go
Author
sh7ning
commented
Sep 6, 2019
package main
import (
"context"
"flag"
"fmt"
"io"
"jumpserver/gauth"
"os"
"os/exec"
"os/signal"
"strings"
"github.com/creack/pty"
"github.com/joho/godotenv"
"golang.org/x/crypto/ssh/terminal"
)
var (
ptmx *os.File
err error
cmd *exec.Cmd
)
func main() {
envFile := flag.String("c", ".env", ".env file")
flag.Parse()
loadEnv(*envFile)
mfaCode := get2fa()
c := ""
//c = fmt.Sprintf("/usr/bin/ssh yadou")
//c = fmt.Sprintf("/usr/bin/php -a")
c = fmt.Sprintf("/usr/bin/ssh %s -p %s", os.Getenv("JUMPSERVER_DSN"), os.Getenv("JUMPSERVER_PORT"))
warn("process cmd: %s", c)
cmd = exec.Command("sh", "-c", c)
ptmx, err = pty.Start(cmd)
if err != nil {
panic(err)
}
// Make sure to close the pty at the end.
defer func() {
err := ptmx.Close()
if err != nil {
panic(err)
}
}() // Best effort.
//interact()
//os.Exit(0)
login(mfaCode)
interact()
}
func login(mfaCode string) {
for {
chunk := make([]byte, 1024)
n, err := ptmx.Read(chunk)
if err != nil && err != io.EOF {
panic(err)
}
if n != 0 {
output := string(chunk[:n])
fmt.Print(output)
if strings.Contains(output, "Are you sure you want to continue connecting (yes/no)?") {
fmt.Print(output)
send("yes\n")
}
if !strings.Contains(output, "yes") {
if strings.Contains(output, "password:") {
send(os.Getenv("JUMPSERVER_PASSWORD") + "\n")
}
}
if strings.Contains(output, "[MFA auth]:") {
send(mfaCode + "\n")
}
if strings.Contains(output, "Opt>") {
break
}
if strings.Contains(output, "data]#") {
break
}
if strings.Contains(output, "Permission denied") {
panic("login failed...")
}
}
}
}
func interact() {
fd := int(os.Stdin.Fd())
state, err := terminal.MakeRaw(fd)
if err != nil {
panic("setting stdin to raw:" + err.Error())
}
isCmdRunning := true
ctx, cancel := context.WithCancel(context.Background())
go func() {
_ = cmd.Wait()
isCmdRunning = false
if err := terminal.Restore(0, state); err != nil {
fmt.Println("warning, failed to restore terminal:", err)
}
fmt.Println("")
cancel()
//fmt.Println("wait done")
}()
go func() {
for {
chunk := make([]byte, 1024)
n, err := ptmx.Read(chunk)
if err != nil && err != io.EOF {
panic(err)
}
if n != 0 {
output := string(chunk[:n])
fmt.Print(output)
}
}
}()
//go io.Copy(os.Stdout, ptmx)
go io.Copy(ptmx, os.Stdin)
//go func() {
//
// in := bufio.NewReader(os.Stdin)
// for {
// r, _, err := in.ReadRune()
// if err != nil {
// fmt.Println("stdin:", err)
// break
// }
// //fmt.Printf("key: %#v", r)
// send(string(r))
// //fmt.Printf("read rune %q\r\n", r)
// }
//}()
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, os.Kill)
for {
select {
case <-ctx.Done():
return
case <-c:
if !isCmdRunning {
fmt.Printf("%#v", cmd.ProcessState.Exited())
//fmt.Println("sign break")
return
}
//fmt.Println("sign")
}
}
}
func get2fa() string {
secret := os.Getenv("JUMPSERVER_SECRET")
if secret == "" {
panic("empty secret")
}
code, err := gauth.NewGoogleAuth().GetCode(secret)
if err != nil {
panic(err)
}
return code
}
func send(cmd string) {
_, err := ptmx.Write([]byte(cmd))
if err != nil {
panic(err)
}
}
func warn(format string, v ...interface{}) {
fmt.Printf("\033[33m[Warn] "+format+"\033[0m\n", v...)
}
func loadEnv(file string) {
err := godotenv.Load(file)
if err != nil {
warn("Error loading .env file: %s", file)
}
}
package gauth
import (
"bytes"
"crypto/hmac"
"crypto/sha1"
"encoding/base32"
"encoding/binary"
"fmt"
"strings"
"time"
)
type GoogleAuth struct {
}
func NewGoogleAuth() *GoogleAuth {
return &GoogleAuth{}
}
func (googleAuth *GoogleAuth) un() int64 {
return time.Now().UnixNano() / 1000 / 30
}
func (googleAuth *GoogleAuth) hmacSha1(key, data []byte) []byte {
h := hmac.New(sha1.New, key)
if total := len(data); total > 0 {
h.Write(data)
}
return h.Sum(nil)
}
func (googleAuth *GoogleAuth) base32encode(src []byte) string {
return base32.StdEncoding.EncodeToString(src)
}
func (googleAuth *GoogleAuth) base32decode(s string) ([]byte, error) {
return base32.StdEncoding.DecodeString(s)
}
func (googleAuth *GoogleAuth) toBytes(value int64) []byte {
var result []byte
mask := int64(0xFF)
shifts := [8]uint16{56, 48, 40, 32, 24, 16, 8, 0}
for _, shift := range shifts {
result = append(result, byte((value>>shift)&mask))
}
return result
}
func (googleAuth *GoogleAuth) toUint32(bts []byte) uint32 {
return (uint32(bts[0]) << 24) + (uint32(bts[1]) << 16) +
(uint32(bts[2]) << 8) + uint32(bts[3])
}
func (googleAuth *GoogleAuth) oneTimePassword(key []byte, data []byte) uint32 {
hash := googleAuth.hmacSha1(key, data)
offset := hash[len(hash)-1] & 0x0F
hashParts := hash[offset : offset+4]
hashParts[0] = hashParts[0] & 0x7F
number := googleAuth.toUint32(hashParts)
return number % 1000000
}
func (googleAuth *GoogleAuth) GetSecret() string {
var buf bytes.Buffer
binary.Write(&buf, binary.BigEndian, googleAuth.un())
return strings.ToUpper(googleAuth.base32encode(googleAuth.hmacSha1(buf.Bytes(), nil)))
}
func (googleAuth *GoogleAuth) GetCode(secret string) (string, error) {
secretUpper := strings.ToUpper(secret)
secretKey, err := googleAuth.base32decode(secretUpper)
if err != nil {
return "", err
}
number := googleAuth.oneTimePassword(secretKey, googleAuth.toBytes(time.Now().Unix()/30))
return fmt.Sprintf("%06d", number), nil
}
func (googleAuth *GoogleAuth) GetQrcode(user, secret string) string {
return fmt.Sprintf("otpauth://totp/%s?secret=%s", user, secret)
}
func (googleAuth *GoogleAuth) GetQrcodeUrl(user, secret string) string {
qrcode := googleAuth.GetQrcode(user, secret)
return fmt.Sprintf("http://www.google.com/chart?chs=200x200&chld=M%%7C0&cht=qr&chl=%s", qrcode)
}
func (googleAuth *GoogleAuth) VerifyCode(secret, code string) (bool, error) {
_code, err := googleAuth.GetCode(secret)
fmt.Println(_code, code, err)
if err != nil {
return false, err
}
return _code == code, nil
}
ssh 有个小bug...跳板机不能展示出有权限的服务器列表....
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment