diff options
author | Peter Smit <peter@smitmail.eu> | 2015-01-02 15:38:11 +0200 |
---|---|---|
committer | Peter Smit <peter@smitmail.eu> | 2015-01-02 15:38:11 +0200 |
commit | 6251626de45a2310b3532176c0fc12c52dbd6e32 (patch) | |
tree | d8da1f5ec9aa6255700d22eae077dfd5ccb294a8 /models | |
parent | 9b0858b1ad96455c0660d6311fedc6fb752a928f (diff) | |
download | gitea-6251626de45a2310b3532176c0fc12c52dbd6e32.tar.gz gitea-6251626de45a2310b3532176c0fc12c52dbd6e32.zip |
Implement #798 Flexible ssh-key input
It is now possible to input ssh keys in a number of formats: openssh, SSH2 or just the base64 encoded key.
Diffstat (limited to 'models')
-rw-r--r-- | models/publickey.go | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/models/publickey.go b/models/publickey.go index ba15ca4553..566814e841 100644 --- a/models/publickey.go +++ b/models/publickey.go @@ -6,6 +6,8 @@ package models import ( "bufio" + "encoding/base64" + "encoding/binary" "errors" "fmt" "io" @@ -111,6 +113,85 @@ var ( } ) +func extractTypeFromBase64Key(key string) (string, error) { + b, err := base64.StdEncoding.DecodeString(key) + if err != nil || len(b) < 4 { + return "", errors.New("Invalid key format") + } + + keyLength := int(binary.BigEndian.Uint32(b)) + + if len(b) < 4+keyLength { + return "", errors.New("Invalid key format") + } + + return string(b[4 : 4+keyLength]), nil +} + +// Parse any key string in openssh or ssh2 format to clean openssh string (rfc4253) +func ParseKeyString(content string) (string, error) { + + // Transform all legal line endings to a single "\n" + s := strings.Replace(strings.Replace(strings.TrimSpace(content), "\r\n", "\n", -1), "\r", "\n", -1) + + lines := strings.Split(s, "\n") + + var keyType, keyContent, keyComment string + + if len(lines) == 1 { + // Parse openssh format + parts := strings.Fields(lines[0]) + switch len(parts) { + case 0: + return "", errors.New("Empty key") + case 1: + keyContent = parts[0] + case 2: + keyType = parts[0] + keyContent = parts[1] + default: + keyType = parts[0] + keyContent = parts[1] + keyComment = parts[2] + } + + // If keyType is not given, extract it from content. If given, validate it + if len(keyType) == 0 { + if t, err := extractTypeFromBase64Key(keyContent); err == nil { + keyType = t + } else { + return "", err + } + } else { + if t, err := extractTypeFromBase64Key(keyContent); err != nil || keyType != t { + return "", err + } + } + } else { + // Parse SSH2 file format. + continuationLine := false + + for _, line := range lines { + // Skip lines that: + // 1) are a continuation of the previous line, + // 2) contain ":" as that are comment lines + // 3) contain "-" as that are begin and end tags + if continuationLine || strings.ContainsAny(line, ":-") { + continuationLine = strings.HasSuffix(line, "\\") + } else { + keyContent = keyContent + line + } + } + + if t, err := extractTypeFromBase64Key(keyContent); err == nil { + keyType = t + } else { + return "", err + } + } + return keyType + " " + keyContent + " " + keyComment, nil +} + // CheckPublicKeyString checks if the given public key string is recognized by SSH. func CheckPublicKeyString(content string) (bool, error) { content = strings.TrimRight(content, "\n\r") |