[Refactor] unexport config.Config var & move login tasks to task module (#288)
Unexport generateToken() move CreateLogin into task Create func config.SetDefaultLogin() Unexport loadConfig() & saveConfig unexport config var make SetDefaultLogin() case insensitive update func descriptions move FindSSHKey to task module Reviewed-on: https://gitea.com/gitea/tea/pulls/288 Reviewed-by: Norwin <noerw@noreply.gitea.io> Reviewed-by: Andrew Thornton <art27@cantab.net> Co-Authored-By: 6543 <6543@obermui.de> Co-Committed-By: 6543 <6543@obermui.de>
This commit is contained in:
parent
eeb9cbafe7
commit
c063329e9a
|
@ -39,10 +39,6 @@ func runLogins(ctx *cli.Context) error {
|
|||
}
|
||||
|
||||
func runLoginDetail(name string) error {
|
||||
if err := config.LoadConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
l := config.GetLoginByName(name)
|
||||
if l == nil {
|
||||
fmt.Printf("Login '%s' do not exist\n\n", name)
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
package login
|
||||
|
||||
import (
|
||||
"code.gitea.io/tea/modules/config"
|
||||
"code.gitea.io/tea/modules/interact"
|
||||
"code.gitea.io/tea/modules/task"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
@ -70,7 +70,7 @@ func runLoginAdd(ctx *cli.Context) error {
|
|||
}
|
||||
|
||||
// else use args to add login
|
||||
return config.AddLogin(
|
||||
return task.CreateLogin(
|
||||
ctx.String("name"),
|
||||
ctx.String("token"),
|
||||
ctx.String("user"),
|
||||
|
|
|
@ -24,9 +24,6 @@ var CmdLoginSetDefault = cli.Command{
|
|||
}
|
||||
|
||||
func runLoginSetDefault(ctx *cli.Context) error {
|
||||
if err := config.LoadConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
if ctx.Args().Len() == 0 {
|
||||
l, err := config.GetDefaultLogin()
|
||||
if err != nil {
|
||||
|
@ -35,18 +32,7 @@ func runLoginSetDefault(ctx *cli.Context) error {
|
|||
fmt.Printf("Default Login: %s\n", l.Name)
|
||||
return nil
|
||||
}
|
||||
loginExist := false
|
||||
for i := range config.Config.Logins {
|
||||
config.Config.Logins[i].Default = false
|
||||
if config.Config.Logins[i].Name == ctx.Args().First() {
|
||||
config.Config.Logins[i].Default = true
|
||||
loginExist = true
|
||||
}
|
||||
}
|
||||
|
||||
if !loginExist {
|
||||
return fmt.Errorf("login '%s' not found", ctx.Args().First())
|
||||
}
|
||||
|
||||
return config.SaveConfig()
|
||||
name := ctx.Args().First()
|
||||
return config.SetDefaultLogin(name)
|
||||
}
|
||||
|
|
|
@ -21,6 +21,6 @@ var CmdLoginEdit = cli.Command{
|
|||
Flags: []cli.Flag{&flags.OutputFlag},
|
||||
}
|
||||
|
||||
func runLoginEdit(ctx *cli.Context) error {
|
||||
func runLoginEdit(_ *cli.Context) error {
|
||||
return open.Start(config.GetConfigPath())
|
||||
}
|
||||
|
|
|
@ -25,12 +25,12 @@ var CmdLoginList = cli.Command{
|
|||
}
|
||||
|
||||
// RunLoginList list all logins
|
||||
func RunLoginList(ctx *cli.Context) error {
|
||||
err := config.LoadConfig()
|
||||
func RunLoginList(_ *cli.Context) error {
|
||||
logins, err := config.GetLogins()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
print.LoginsList(config.Config.Logins, flags.GlobalOutputValue)
|
||||
print.LoginsList(logins, flags.GlobalOutputValue)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ var CmdLogout = cli.Command{
|
|||
}
|
||||
|
||||
func runLogout(ctx *cli.Context) error {
|
||||
err := config.LoadConfig()
|
||||
logins, err := config.GetLogins()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -40,8 +40,8 @@ func runLogout(ctx *cli.Context) error {
|
|||
name = ctx.String("name")
|
||||
} else if len(ctx.Args().First()) != 0 {
|
||||
name = ctx.Args().First()
|
||||
} else if len(config.Config.Logins) == 1 {
|
||||
name = config.Config.Logins[0].Name
|
||||
} else if len(logins) == 1 {
|
||||
name = logins[0].Name
|
||||
} else {
|
||||
return errors.New("Please specify a login name")
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ import (
|
|||
// the remotes of the .git repo specified in repoFlag or $PWD, and using overrides from
|
||||
// command flags. If a local git repo can't be found, repo slug values are unset.
|
||||
func InitCommand(repoFlag, loginFlag, remoteFlag string) (login *Login, owner string, reponame string) {
|
||||
err := LoadConfig()
|
||||
err := loadConfig()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ func InitCommand(repoFlag, loginFlag, remoteFlag string) (login *Login, owner st
|
|||
return
|
||||
}
|
||||
|
||||
// discovers login & repo slug from the default branch remote of the given local repo
|
||||
// contextFromLocalRepo discovers login & repo slug from the default branch remote of the given local repo
|
||||
func contextFromLocalRepo(repoValue, remoteValue string) (*Login, string, error) {
|
||||
repo, err := git.RepoFromPath(repoValue)
|
||||
if err != nil {
|
||||
|
@ -106,7 +106,7 @@ func contextFromLocalRepo(repoValue, remoteValue string) (*Login, string, error)
|
|||
return nil, "", errors.New("Remote " + remoteValue + " not found in this Git repository")
|
||||
}
|
||||
|
||||
for _, l := range Config.Logins {
|
||||
for _, l := range config.Logins {
|
||||
for _, u := range remoteConfig.URLs {
|
||||
p, err := git.ParseURL(strings.TrimSpace(u))
|
||||
if err != nil {
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"io/ioutil"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"code.gitea.io/tea/modules/utils"
|
||||
|
||||
|
@ -22,8 +23,9 @@ type LocalConfig struct {
|
|||
}
|
||||
|
||||
var (
|
||||
// Config contain if loaded local tea config
|
||||
Config LocalConfig
|
||||
// config contain if loaded local tea config
|
||||
config LocalConfig
|
||||
loadConfigOnce sync.Once
|
||||
)
|
||||
|
||||
// GetConfigPath return path to tea config file
|
||||
|
@ -53,29 +55,30 @@ func GetConfigPath() string {
|
|||
return configFilePath
|
||||
}
|
||||
|
||||
// LoadConfig load config into global Config var
|
||||
func LoadConfig() error {
|
||||
ymlPath := GetConfigPath()
|
||||
exist, _ := utils.FileExist(ymlPath)
|
||||
if exist {
|
||||
bs, err := ioutil.ReadFile(ymlPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to read config file: %s", ymlPath)
|
||||
}
|
||||
// loadConfig load config from file
|
||||
func loadConfig() (err error) {
|
||||
loadConfigOnce.Do(func() {
|
||||
ymlPath := GetConfigPath()
|
||||
exist, _ := utils.FileExist(ymlPath)
|
||||
if exist {
|
||||
bs, err := ioutil.ReadFile(ymlPath)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Failed to read config file: %s", ymlPath)
|
||||
}
|
||||
|
||||
err = yaml.Unmarshal(bs, &Config)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to parse contents of config file: %s", ymlPath)
|
||||
err = yaml.Unmarshal(bs, &config)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Failed to parse contents of config file: %s", ymlPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// SaveConfig save config from global Config var into config file
|
||||
func SaveConfig() error {
|
||||
// saveConfig save config to file
|
||||
func saveConfig() error {
|
||||
ymlPath := GetConfigPath()
|
||||
bs, err := yaml.Marshal(Config)
|
||||
bs, err := yaml.Marshal(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -6,21 +6,15 @@ package config
|
|||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/tea/modules/utils"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// Login represents a login to a gitea server, you even could add multiple logins for one gitea server
|
||||
|
@ -39,55 +33,88 @@ type Login struct {
|
|||
Created int64 `yaml:"created"`
|
||||
}
|
||||
|
||||
// GetLogins return all login available by config
|
||||
func GetLogins() ([]Login, error) {
|
||||
if err := loadConfig(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return config.Logins, nil
|
||||
}
|
||||
|
||||
// GetDefaultLogin return the default login
|
||||
func GetDefaultLogin() (*Login, error) {
|
||||
if len(Config.Logins) == 0 {
|
||||
if err := loadConfig(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(config.Logins) == 0 {
|
||||
return nil, errors.New("No available login")
|
||||
}
|
||||
for _, l := range Config.Logins {
|
||||
for _, l := range config.Logins {
|
||||
if l.Default {
|
||||
return &l, nil
|
||||
}
|
||||
}
|
||||
|
||||
return &Config.Logins[0], nil
|
||||
return &config.Logins[0], nil
|
||||
}
|
||||
|
||||
// GetLoginByName get login by name
|
||||
// SetDefaultLogin set the default login by name (case insensitive)
|
||||
func SetDefaultLogin(name string) error {
|
||||
if err := loadConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
loginExist := false
|
||||
for i := range config.Logins {
|
||||
config.Logins[i].Default = false
|
||||
if strings.ToLower(config.Logins[i].Name) == strings.ToLower(name) {
|
||||
config.Logins[i].Default = true
|
||||
loginExist = true
|
||||
}
|
||||
}
|
||||
|
||||
if !loginExist {
|
||||
return fmt.Errorf("login '%s' not found", name)
|
||||
}
|
||||
|
||||
return saveConfig()
|
||||
}
|
||||
|
||||
// GetLoginByName get login by name (case insensitive)
|
||||
func GetLoginByName(name string) *Login {
|
||||
for _, l := range Config.Logins {
|
||||
if l.Name == name {
|
||||
err := loadConfig()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, l := range config.Logins {
|
||||
if strings.ToLower(l.Name) == strings.ToLower(name) {
|
||||
return &l
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GenerateLoginName generates a name string based on instance URL & adds username if the result is not unique
|
||||
func GenerateLoginName(url, user string) (string, error) {
|
||||
parsedURL, err := utils.NormalizeURL(url)
|
||||
// GetLoginByToken get login by token
|
||||
func GetLoginByToken(token string) *Login {
|
||||
err := loadConfig()
|
||||
if err != nil {
|
||||
return "", err
|
||||
log.Fatal(err)
|
||||
}
|
||||
name := parsedURL.Host
|
||||
|
||||
// append user name if login name already exists
|
||||
if len(user) != 0 {
|
||||
for _, l := range Config.Logins {
|
||||
if l.Name == name {
|
||||
name += "_" + user
|
||||
break
|
||||
}
|
||||
for _, l := range config.Logins {
|
||||
if l.Token == token {
|
||||
return &l
|
||||
}
|
||||
}
|
||||
|
||||
return name, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteLogin delete a login by name
|
||||
// DeleteLogin delete a login by name from config
|
||||
func DeleteLogin(name string) error {
|
||||
var idx = -1
|
||||
for i, l := range Config.Logins {
|
||||
for i, l := range config.Logins {
|
||||
if l.Name == name {
|
||||
idx = i
|
||||
break
|
||||
|
@ -97,9 +124,22 @@ func DeleteLogin(name string) error {
|
|||
return fmt.Errorf("can not delete login '%s', does not exist", name)
|
||||
}
|
||||
|
||||
Config.Logins = append(Config.Logins[:idx], Config.Logins[idx+1:]...)
|
||||
config.Logins = append(config.Logins[:idx], config.Logins[idx+1:]...)
|
||||
|
||||
return SaveConfig()
|
||||
return saveConfig()
|
||||
}
|
||||
|
||||
// AddLogin save a login to config
|
||||
func AddLogin(login *Login) error {
|
||||
if err := loadConfig(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// save login to global var
|
||||
config.Logins = append(config.Logins, *login)
|
||||
|
||||
// save login to config file
|
||||
return saveConfig()
|
||||
}
|
||||
|
||||
// Client returns a client to operate Gitea API
|
||||
|
@ -138,65 +178,3 @@ func (l *Login) GetSSHHost() string {
|
|||
|
||||
return u.Hostname()
|
||||
}
|
||||
|
||||
// FindSSHKey retrieves the ssh keys registered in gitea, and tries to find
|
||||
// a matching private key in ~/.ssh/. If no match is found, path is empty.
|
||||
func (l *Login) FindSSHKey() (string, error) {
|
||||
// get keys registered on gitea instance
|
||||
keys, _, err := l.Client().ListMyPublicKeys(gitea.ListPublicKeysOptions{})
|
||||
if err != nil || len(keys) == 0 {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// enumerate ~/.ssh/*.pub files
|
||||
glob, err := utils.AbsPathWithExpansion("~/.ssh/*.pub")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
localPubkeyPaths, err := filepath.Glob(glob)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// parse each local key with present privkey & compare fingerprints to online keys
|
||||
for _, pubkeyPath := range localPubkeyPaths {
|
||||
var pubkeyFile []byte
|
||||
pubkeyFile, err = ioutil.ReadFile(pubkeyPath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
fields := strings.Split(string(pubkeyFile), " ")
|
||||
if len(fields) < 2 { // first word is key type, second word is key material
|
||||
continue
|
||||
}
|
||||
|
||||
var keymaterial []byte
|
||||
keymaterial, err = base64.StdEncoding.DecodeString(fields[1])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
var pubkey ssh.PublicKey
|
||||
pubkey, err = ssh.ParsePublicKey(keymaterial)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
privkeyPath := strings.TrimSuffix(pubkeyPath, ".pub")
|
||||
var exists bool
|
||||
exists, err = utils.FileExist(privkeyPath)
|
||||
if err != nil || !exists {
|
||||
continue
|
||||
}
|
||||
|
||||
// if pubkey fingerprints match, return path to corresponding privkey.
|
||||
fingerprint := ssh.FingerprintSHA256(pubkey)
|
||||
for _, key := range keys {
|
||||
if fingerprint == key.Fingerprint {
|
||||
return privkeyPath, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/tea/modules/config"
|
||||
"code.gitea.io/tea/modules/task"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
)
|
||||
|
@ -28,7 +28,7 @@ func CreateLogin() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
name, err := config.GenerateLoginName(giteaURL, "")
|
||||
name, err := task.GenerateLoginName(giteaURL, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -87,5 +87,5 @@ func CreateLogin() error {
|
|||
}
|
||||
}
|
||||
|
||||
return config.AddLogin(name, token, user, passwd, sshKey, giteaURL, insecure)
|
||||
return task.CreateLogin(name, token, user, passwd, sshKey, giteaURL, insecure)
|
||||
}
|
||||
|
|
|
@ -2,42 +2,35 @@
|
|||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package config
|
||||
package task
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/tea/modules/config"
|
||||
"code.gitea.io/tea/modules/utils"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
)
|
||||
|
||||
// AddLogin add login to config ( global var & file)
|
||||
func AddLogin(name, token, user, passwd, sshKey, giteaURL string, insecure bool) error {
|
||||
// CreateLogin create a login to be stored in config
|
||||
func CreateLogin(name, token, user, passwd, sshKey, giteaURL string, insecure bool) error {
|
||||
// checks ...
|
||||
// ... if we have a url
|
||||
if len(giteaURL) == 0 {
|
||||
log.Fatal("You have to input Gitea server URL")
|
||||
}
|
||||
|
||||
err := LoadConfig()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
// ... if there already exist a login with same name
|
||||
if login := config.GetLoginByName(name); login != nil {
|
||||
return fmt.Errorf("login name '%s' has already been used", login.Name)
|
||||
}
|
||||
|
||||
for _, l := range Config.Logins {
|
||||
// ... if there already exist a login with same name
|
||||
if strings.ToLower(l.Name) == strings.ToLower(name) {
|
||||
return fmt.Errorf("login name '%s' has already been used", l.Name)
|
||||
}
|
||||
// ... if we already use this token
|
||||
if l.Token == token {
|
||||
return fmt.Errorf("token already been used, delete login '%s' first", l.Name)
|
||||
}
|
||||
// ... if we already use this token
|
||||
if login := config.GetLoginByToken(token); login != nil {
|
||||
return fmt.Errorf("token already been used, delete login '%s' first", login.Name)
|
||||
}
|
||||
|
||||
// .. if we have enough information to authenticate
|
||||
|
@ -55,7 +48,7 @@ func AddLogin(name, token, user, passwd, sshKey, giteaURL string, insecure bool)
|
|||
log.Fatal("Unable to parse URL", err)
|
||||
}
|
||||
|
||||
login := Login{
|
||||
login := config.Login{
|
||||
Name: name,
|
||||
URL: serverURL.String(),
|
||||
Token: token,
|
||||
|
@ -64,15 +57,17 @@ func AddLogin(name, token, user, passwd, sshKey, giteaURL string, insecure bool)
|
|||
Created: time.Now().Unix(),
|
||||
}
|
||||
|
||||
client := login.Client()
|
||||
|
||||
if len(token) == 0 {
|
||||
login.Token, err = GenerateToken(login.Client(), user, passwd)
|
||||
login.Token, err = generateToken(client, user, passwd)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify if authentication works and get user info
|
||||
u, _, err := login.Client().GetMyUserInfo()
|
||||
u, _, err := client.GetMyUserInfo()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -90,17 +85,13 @@ func AddLogin(name, token, user, passwd, sshKey, giteaURL string, insecure bool)
|
|||
login.SSHHost = serverURL.Hostname()
|
||||
|
||||
if len(sshKey) == 0 {
|
||||
login.SSHKey, err = login.FindSSHKey()
|
||||
login.SSHKey, err = findSSHKey(client)
|
||||
if err != nil {
|
||||
fmt.Printf("Warning: problem while finding a SSH key: %s\n", err)
|
||||
}
|
||||
}
|
||||
|
||||
// save login to global var
|
||||
Config.Logins = append(Config.Logins, login)
|
||||
|
||||
// save login to config file
|
||||
err = SaveConfig()
|
||||
err = config.AddLogin(&login)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -110,8 +101,8 @@ func AddLogin(name, token, user, passwd, sshKey, giteaURL string, insecure bool)
|
|||
return nil
|
||||
}
|
||||
|
||||
// GenerateToken creates a new token when given BasicAuth credentials
|
||||
func GenerateToken(client *gitea.Client, user, pass string) (string, error) {
|
||||
// generateToken creates a new token when given BasicAuth credentials
|
||||
func generateToken(client *gitea.Client, user, pass string) (string, error) {
|
||||
gitea.SetBasicAuth(user, pass)(client)
|
||||
|
||||
host, _ := os.Hostname()
|
||||
|
@ -131,3 +122,21 @@ func GenerateToken(client *gitea.Client, user, pass string) (string, error) {
|
|||
t, _, err := client.CreateAccessToken(gitea.CreateAccessTokenOption{Name: tokenName})
|
||||
return t.Token, err
|
||||
}
|
||||
|
||||
// GenerateLoginName generates a name string based on instance URL & adds username if the result is not unique
|
||||
func GenerateLoginName(url, user string) (string, error) {
|
||||
parsedURL, err := utils.NormalizeURL(url)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
name := parsedURL.Host
|
||||
|
||||
// append user name if login name already exists
|
||||
if len(user) != 0 {
|
||||
if login := config.GetLoginByName(name); login != nil {
|
||||
return name + "_" + user, nil
|
||||
}
|
||||
}
|
||||
|
||||
return name, nil
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package task
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/tea/modules/utils"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
// findSSHKey retrieves the ssh keys registered in gitea, and tries to find
|
||||
// a matching private key in ~/.ssh/. If no match is found, path is empty.
|
||||
func findSSHKey(client *gitea.Client) (string, error) {
|
||||
// get keys registered on gitea instance
|
||||
keys, _, err := client.ListMyPublicKeys(gitea.ListPublicKeysOptions{})
|
||||
if err != nil || len(keys) == 0 {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// enumerate ~/.ssh/*.pub files
|
||||
glob, err := utils.AbsPathWithExpansion("~/.ssh/*.pub")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
localPubkeyPaths, err := filepath.Glob(glob)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// parse each local key with present privkey & compare fingerprints to online keys
|
||||
for _, pubkeyPath := range localPubkeyPaths {
|
||||
var pubkeyFile []byte
|
||||
pubkeyFile, err = ioutil.ReadFile(pubkeyPath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
fields := strings.Split(string(pubkeyFile), " ")
|
||||
if len(fields) < 2 { // first word is key type, second word is key material
|
||||
continue
|
||||
}
|
||||
|
||||
var keymaterial []byte
|
||||
keymaterial, err = base64.StdEncoding.DecodeString(fields[1])
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
var pubkey ssh.PublicKey
|
||||
pubkey, err = ssh.ParsePublicKey(keymaterial)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
privkeyPath := strings.TrimSuffix(pubkeyPath, ".pub")
|
||||
var exists bool
|
||||
exists, err = utils.FileExist(privkeyPath)
|
||||
if err != nil || !exists {
|
||||
continue
|
||||
}
|
||||
|
||||
// if pubkey fingerprints match, return path to corresponding privkey.
|
||||
fingerprint := ssh.FingerprintSHA256(pubkey)
|
||||
for _, key := range keys {
|
||||
if fingerprint == key.Fingerprint {
|
||||
return privkeyPath, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "", err
|
||||
}
|
Loading…
Reference in New Issue