grim/hgkeeper

ebc5f568d629
Add a note about downloads and pgp verification to the readme
package access
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"sync"
log "github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh"
)
const (
keysDir = "keys"
)
var (
usernames map[string]string
keys map[string]ssh.PublicKey
keysLock sync.Mutex
)
func refreshKeys() error {
keysLock.Lock()
defer keysLock.Unlock()
keys = map[string]ssh.PublicKey{}
usernames = map[string]string{}
keysPath := filepath.Join(AdminRepoPath(), keysDir)
if _, err := os.Stat(keysPath); err != nil {
if os.IsNotExist(err) {
log.Error("keys directory not found, no one will be to access hgkeeper")
return nil
}
}
entries, err := ioutil.ReadDir(keysPath)
if err != nil {
return err
}
for _, entry := range entries {
if entry.Mode().IsRegular() {
filename := filepath.Join(keysPath, entry.Name())
loadSshKey(filename, entry.Name())
}
}
return nil
}
func loadSshKey(filename, username string) {
buffer, err := ioutil.ReadFile(filename)
if err != nil {
log.Warnf("failed to read keyfile for user %s: %v", username, err)
return
}
counter := 0
// iterate through the file reading one ssh public key at a time
for len(buffer) > 0 {
var pubkey ssh.PublicKey
pubkey, _, _, buffer, err = ssh.ParseAuthorizedKey(buffer)
if err != nil {
if !strings.HasSuffix(err.Error(), "ssh: no key found") {
log.Warnf("failed to parse key file for user %s: %v", username, err)
}
continue
}
fingerprint := ssh.FingerprintSHA256(pubkey)
if duppedname, found := usernames[fingerprint]; found {
log.Warnf(
"duplicate key found for user %s. existing key was for %s.",
username,
duppedname,
)
}
usernames[fingerprint] = username
keys[fingerprint] = pubkey
counter++
}
log.Infof("loaded %d keys for user %q", counter, username)
}
// UsernameFromFingerprint looks up a username from an SSH key's fingerprint
// and returns the username if found, or err if not found.
func UsernameFromFingerprint(fingerprint string) (string, error) {
keysLock.Lock()
defer keysLock.Unlock()
username, found := usernames[fingerprint]
if !found {
return "", fmt.Errorf("user not found")
}
return username, nil
}
func UsernameFromPubkey(pubkey ssh.PublicKey) (string, error) {
return UsernameFromFingerprint(ssh.FingerprintSHA256(pubkey))
}
func PubkeyFromFingerprint(fingerprint string) (string, error) {
pubkey, found := keys[fingerprint]
if !found {
return "", fmt.Errorf("PubKey not found")
}
str := string(ssh.MarshalAuthorizedKey(pubkey))
return str, nil
}