mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 13:51:35 +01:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									9b0858b1ad
								
							
						
					
					
						commit
						6251626de4
					
				| @ -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") | ||||
|  | ||||
| @ -325,10 +325,15 @@ func SettingsSSHKeysPost(ctx *middleware.Context, form auth.AddSSHKeyForm) { | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		// Remove newline characters from form.KeyContent | ||||
| 		cleanContent := strings.Replace(form.Content, "\n", "", -1) | ||||
| 		// Parse openssh style string from form content | ||||
| 		content, err := models.ParseKeyString(form.Content) | ||||
| 		if err != nil { | ||||
| 			ctx.Flash.Error(ctx.Tr("form.invalid_ssh_key", err.Error())) | ||||
| 			ctx.Redirect(setting.AppSubUrl + "/user/settings/ssh") | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		if ok, err := models.CheckPublicKeyString(cleanContent); !ok { | ||||
| 		if ok, err := models.CheckPublicKeyString(content); !ok { | ||||
| 			if err == models.ErrKeyUnableVerify { | ||||
| 				ctx.Flash.Info(ctx.Tr("form.unable_verify_ssh_key")) | ||||
| 			} else { | ||||
| @ -341,7 +346,7 @@ func SettingsSSHKeysPost(ctx *middleware.Context, form auth.AddSSHKeyForm) { | ||||
| 		k := &models.PublicKey{ | ||||
| 			OwnerId: ctx.User.Id, | ||||
| 			Name:    form.SSHTitle, | ||||
| 			Content: cleanContent, | ||||
| 			Content: content, | ||||
| 		} | ||||
| 		if err := models.AddPublicKey(k); err != nil { | ||||
| 			if err == models.ErrKeyAlreadyExist { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user