GoLang實現google authenticator的CLI工具

來源:互聯網
上載者:User

兩步認證在很多驗證中都要使用。如果在手機用戶端上,如果使用電腦,每次都要拿出手機,手動輸入。還要擔心會過時。效率不是很高。

我現在的處理方式以下方式:

  • MAC上alfred workflow支援
  • Chrom擴充支援
  • 手機用戶端
  • CLI記錄工具

今天主要介紹CLI工具,我現在在golang,找一些練手的項目.

先上代碼

package mainimport (    "fmt"    "os"    "log"    "sort"    "github.com/urfave/cli"    "gopkg.in/ini.v1"    "crypto/hmac"    "crypto/sha1"    "strings"    "encoding/base32"    "time"    "github.com/atotto/clipboard"    "strconv")func 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 toUint32(bytes []byte) uint32 {    return (uint32(bytes[0]) << 24) + (uint32(bytes[1]) << 16) +        (uint32(bytes[2]) << 8) + uint32(bytes[3])}func oneTimePassword(key []byte, value []byte) uint32 {    // sign the value using HMAC-SHA1    hmacSha1 := hmac.New(sha1.New, key)    hmacSha1.Write(value)    hash := hmacSha1.Sum(nil)        offset := hash[len(hash)-1] & 0x0F    // get a 32-bit (4-byte) chunk from the hash starting at offset    hashParts := hash[offset : offset+4]    // ignore the most significant bit as per RFC 4226    hashParts[0] = hashParts[0] & 0x7F    number := toUint32(hashParts)    // size to 6 digits    // one million is the first number with 7 digits so the remainder    // of the division will always return < 7 digits    pwd := number % 1000000    return pwd}func Cli() {    app := cli.NewApp()    app.Name = "Google Authentiator CLI"    app.Usage = "Create, List, Delete, Copy your GA"    app.Version = "0.0.1"    app.Commands = []cli.Command {        {            Name: "list",            Aliases: []string{"l"},            Usage: "list | l",            Description: "list all item",            Category: "Show",            Action: func(c *cli.Context) error {                list()                return nil            },        },        {            Name: "show",            Aliases: []string{"s"},            Usage: "show | s github.com",            Description: "show all item",            Category: "Show",            Action: func(c *cli.Context) error {                item := c.Args().First()                show(item)                return nil            },        },        {            Name: "copy",            Aliases: []string{"c"},            Usage: "copy | c github.com",            UsageText: "copy ga to Clipboard",            Category: "Show",            Action: func(c *cli.Context) error {                item := c.Args().First()                copy(item)                return nil            },        },        {            Name: "create",            Aliases: []string{"r"},            Usage: "create| r github.com xxxxxxxxxx",            UsageText: "create a new ga Secrete item",            Category: "Store",            Action: func(c *cli.Context) error {                item := c.Args().First()                secret := c.Args()[1]                create(item, secret)                return nil            },        },        {            Name: "modify",            Aliases: []string{"m"},            Usage: "modify | m github.com xxxxxxxxx",            UsageText: "Modify One item Secrete",            Category: "Store",            Action: func(c *cli.Context) error {                item := c.Args().First()                secret := c.Args()[1]                modify(item, secret)                return nil            },        },        {            Name: "delete",            Aliases: []string{"d"},            Usage: "delete | d github.com",            UsageText: "Delete One item Secrete",            Category: "Store",            Action: func(c *cli.Context) error {                delete(c.Args().First())                return nil            },        },    }    app.Action = func(c *cli.Context) error {        fmt.Println("you can use list")        return nil    }    sort.Sort(cli.FlagsByName(app.Flags))    cli.HelpFlag = cli.BoolFlag {        Name: "help, h",        Usage: "Help!Help!",    }    cli.VersionFlag = cli.BoolFlag {        Name: "print-version, v",        Usage: "print version",    }    err := app.Run(os.Args)    if err != nil {        log.Fatal(err)    }}func create(item, secret string) error {    file,er:=os.Open("/tmp/myga.ini")    if er != nil {        file, _ = os.Create("/tmp/myga.ini")    }    file.Close()    cfg, err := ini.Load("/tmp/myga.ini")    if err != nil {        panic(err)    }    if _, err := cfg.GetSection(item); err == nil {        fmt.Println(item + " is Exist!!!!")        os.Exit(1)    }    cfg.NewSection(item)    cfg.Section(item).Key("secret").SetValue(secret)    cfg.SaveTo("/tmp/myga.ini")    return nil}func show(item string) error {    file,er:=os.Open("/tmp/myga.ini")    if er!=nil && os.IsNotExist(er){        fmt.Println("no data!!!")        os.Exit(1)    }    file.Close()    cfg, err := ini.Load("/tmp/myga.ini")    if err != nil {        panic(err)    }    section, err := cfg.GetSection(item)    if err != nil {        panic(err)    }    key, err := section.GetKey("secret")    if err != nil {        panic(err)    }    inputNoSpaces := strings.Replace(key.String(), " ", "", -1)    inputNoSpacesUpper := strings.ToUpper(inputNoSpaces)    keyS, erro := base32.StdEncoding.DecodeString(inputNoSpacesUpper)    if erro != nil {        fmt.Fprintln(os.Stderr, err.Error())        os.Exit(1)    }    // generate a one-time password using the time at 30-second intervals    epochSeconds := time.Now().Unix()    pwd := oneTimePassword(keyS, toBytes(epochSeconds/30))    secondsRemaining := 30 - (epochSeconds % 30)    fmt.Printf("%06d (%d second(s) remaining)\n", pwd, secondsRemaining)    return nil}func copy(item string) error {    file,er:=os.Open("/tmp/myga.ini")    if er!=nil && os.IsNotExist(er){        fmt.Println("no data!!!")        os.Exit(1)    }    file.Close()    cfg, err := ini.Load("/tmp/myga.ini")    if err != nil {        panic(err)    }    section, err := cfg.GetSection(item)    if err != nil {        panic(err)    }    key, err := section.GetKey("secret")    if err != nil {        panic(err)    }    inputNoSpaces := strings.Replace(key.String(), " ", "", -1)    inputNoSpacesUpper := strings.ToUpper(inputNoSpaces)    keyS, erro := base32.StdEncoding.DecodeString(inputNoSpacesUpper)    if erro != nil {        fmt.Fprintln(os.Stderr, err.Error())        os.Exit(1)    }    // generate a one-time password using the time at 30-second intervals    epochSeconds := time.Now().Unix()    pwd := oneTimePassword(keyS, toBytes(epochSeconds/30))    secondsRemaining := 30 - (epochSeconds % 30)    clipStr := strconv.Itoa(int(pwd))    clipboard.WriteAll(clipStr)    fmt.Printf("%06d (%d second(s) remaining)\n", pwd, secondsRemaining)    return nil}func list() error {    file,er:=os.Open("/tmp/myga.ini")    if er!=nil && os.IsNotExist(er){        fmt.Println("no data!!!")        os.Exit(1)    }    file.Close()    cfg, err := ini.Load("/tmp/myga.ini")    if err != nil {        panic(err)    }    sections := cfg.Sections()    for _,v := range sections {        fmt.Println(v.Name())    }    return nil}func delete(item string) error {    file,er:=os.Open("/tmp/myga.ini")    if er!=nil && os.IsNotExist(er){        file, _ = os.Create("/tmp/myga.ini")    }    file.Close()    cfg, err := ini.Load("/tmp/myga.ini")    if err != nil {        panic(err)    }    if _, err := cfg.GetSection(item); err != nil {        fmt.Println(item + " is not Exist!!!!")        os.Exit(1)    }    cfg.DeleteSection(item)    cfg.SaveTo("/tmp/myga.ini")    fmt.Println("ok!!!")    return nil}func modify(item string, secret string) error {    file,er:=os.Open("/tmp/myga.ini")    if er!=nil && os.IsNotExist(er){        file, _ = os.Create("/tmp/myga.ini")    }    file.Close()    cfg, err := ini.Load("/tmp/myga.ini")    if err != nil {        panic(err)    }    if _, err := cfg.GetSection(item); err != nil {        fmt.Println(item + " is not Exist!!!!")        os.Exit(1)    }    cfg.Section(item).Key("secret").SetValue(secret)    cfg.SaveTo("/tmp/myga.ini")    return nil}func main() {    Cli()}

上面實現的功能有

  • ga的建立,更新,刪除,資料都是儲存在本地的
  • 顯示所有條目
  • 顯示驗證碼,複製驗證碼到黏貼板上

後續介紹其他的方式以及ga的工作原理。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.