Use fingerprint to check instead content for public key (#911)
* use fingerprint to check instead content for public key * add fingerprint field for ErrKeyAlreadyExist
This commit is contained in:
		
							parent
							
								
									55ae78208e
								
							
						
					
					
						commit
						7eb8daffa3
					
				| 
						 | 
					@ -214,6 +214,7 @@ func (err ErrKeyNotExist) Error() string {
 | 
				
			||||||
// ErrKeyAlreadyExist represents a "KeyAlreadyExist" kind of error.
 | 
					// ErrKeyAlreadyExist represents a "KeyAlreadyExist" kind of error.
 | 
				
			||||||
type ErrKeyAlreadyExist struct {
 | 
					type ErrKeyAlreadyExist struct {
 | 
				
			||||||
	OwnerID     int64
 | 
						OwnerID     int64
 | 
				
			||||||
 | 
						Fingerprint string
 | 
				
			||||||
	Content     string
 | 
						Content     string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -224,7 +225,8 @@ func IsErrKeyAlreadyExist(err error) bool {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (err ErrKeyAlreadyExist) Error() string {
 | 
					func (err ErrKeyAlreadyExist) Error() string {
 | 
				
			||||||
	return fmt.Sprintf("public key already exists [owner_id: %d, content: %s]", err.OwnerID, err.Content)
 | 
						return fmt.Sprintf("public key already exists [owner_id: %d, finter_print: %s, content: %s]",
 | 
				
			||||||
 | 
							err.OwnerID, err.Fingerprint, err.Content)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ErrKeyNameAlreadyUsed represents a "KeyNameAlreadyUsed" kind of error.
 | 
					// ErrKeyNameAlreadyUsed represents a "KeyNameAlreadyUsed" kind of error.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -354,41 +354,50 @@ func appendAuthorizedKeysToFile(keys ...*PublicKey) error {
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// checkKeyContent only checks if key content has been used as public key,
 | 
					// checkKeyFingerprint only checks if key fingerprint has been used as public key,
 | 
				
			||||||
// it is OK to use same key as deploy key for multiple repositories/users.
 | 
					// it is OK to use same key as deploy key for multiple repositories/users.
 | 
				
			||||||
func checkKeyContent(content string) error {
 | 
					func checkKeyFingerprint(e Engine, fingerprint string) error {
 | 
				
			||||||
	has, err := x.Get(&PublicKey{
 | 
						has, err := e.Get(&PublicKey{
 | 
				
			||||||
		Content: content,
 | 
							Fingerprint: fingerprint,
 | 
				
			||||||
		Type:        KeyTypeUser,
 | 
							Type:        KeyTypeUser,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	} else if has {
 | 
						} else if has {
 | 
				
			||||||
		return ErrKeyAlreadyExist{0, content}
 | 
							return ErrKeyAlreadyExist{0, fingerprint, ""}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func addKey(e Engine, key *PublicKey) (err error) {
 | 
					func calcFingerprint(publicKeyContent string) (string, error) {
 | 
				
			||||||
	// Calculate fingerprint.
 | 
						// Calculate fingerprint.
 | 
				
			||||||
	tmpPath := strings.Replace(path.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond()),
 | 
						tmpPath := strings.Replace(path.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond()),
 | 
				
			||||||
		"id_rsa.pub"), "\\", "/", -1)
 | 
							"id_rsa.pub"), "\\", "/", -1)
 | 
				
			||||||
	dir := path.Dir(tmpPath)
 | 
						dir := path.Dir(tmpPath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := os.MkdirAll(dir, os.ModePerm); err != nil {
 | 
						if err := os.MkdirAll(dir, os.ModePerm); err != nil {
 | 
				
			||||||
		return fmt.Errorf("Failed to create dir %s: %v", dir, err)
 | 
							return "", fmt.Errorf("Failed to create dir %s: %v", dir, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err = ioutil.WriteFile(tmpPath, []byte(key.Content), 0644); err != nil {
 | 
						if err := ioutil.WriteFile(tmpPath, []byte(publicKeyContent), 0644); err != nil {
 | 
				
			||||||
		return err
 | 
							return "", err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	stdout, stderr, err := process.GetManager().Exec("AddPublicKey", "ssh-keygen", "-lf", tmpPath)
 | 
						stdout, stderr, err := process.GetManager().Exec("AddPublicKey", "ssh-keygen", "-lf", tmpPath)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return fmt.Errorf("'ssh-keygen -lf %s' failed with error '%s': %s", tmpPath, err, stderr)
 | 
							return "", fmt.Errorf("'ssh-keygen -lf %s' failed with error '%s': %s", tmpPath, err, stderr)
 | 
				
			||||||
	} else if len(stdout) < 2 {
 | 
						} else if len(stdout) < 2 {
 | 
				
			||||||
		return errors.New("not enough output for calculating fingerprint: " + stdout)
 | 
							return "", errors.New("not enough output for calculating fingerprint: " + stdout)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return strings.Split(stdout, " ")[1], nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func addKey(e Engine, key *PublicKey) (err error) {
 | 
				
			||||||
 | 
						if len(key.Fingerprint) <= 0 {
 | 
				
			||||||
 | 
							key.Fingerprint, err = calcFingerprint(key.Content)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	key.Fingerprint = strings.Split(stdout, " ")[1]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Save SSH key.
 | 
						// Save SSH key.
 | 
				
			||||||
	if _, err = e.Insert(key); err != nil {
 | 
						if _, err = e.Insert(key); err != nil {
 | 
				
			||||||
| 
						 | 
					@ -405,7 +414,13 @@ func addKey(e Engine, key *PublicKey) (err error) {
 | 
				
			||||||
// AddPublicKey adds new public key to database and authorized_keys file.
 | 
					// AddPublicKey adds new public key to database and authorized_keys file.
 | 
				
			||||||
func AddPublicKey(ownerID int64, name, content string) (*PublicKey, error) {
 | 
					func AddPublicKey(ownerID int64, name, content string) (*PublicKey, error) {
 | 
				
			||||||
	log.Trace(content)
 | 
						log.Trace(content)
 | 
				
			||||||
	if err := checkKeyContent(content); err != nil {
 | 
					
 | 
				
			||||||
 | 
						fingerprint, err := calcFingerprint(content)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err := checkKeyFingerprint(x, fingerprint); err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -428,6 +443,7 @@ func AddPublicKey(ownerID int64, name, content string) (*PublicKey, error) {
 | 
				
			||||||
	key := &PublicKey{
 | 
						key := &PublicKey{
 | 
				
			||||||
		OwnerID:     ownerID,
 | 
							OwnerID:     ownerID,
 | 
				
			||||||
		Name:        name,
 | 
							Name:        name,
 | 
				
			||||||
 | 
							Fingerprint: fingerprint,
 | 
				
			||||||
		Content:     content,
 | 
							Content:     content,
 | 
				
			||||||
		Mode:        AccessModeWrite,
 | 
							Mode:        AccessModeWrite,
 | 
				
			||||||
		Type:        KeyTypeUser,
 | 
							Type:        KeyTypeUser,
 | 
				
			||||||
| 
						 | 
					@ -665,12 +681,13 @@ func HasDeployKey(keyID, repoID int64) bool {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// AddDeployKey add new deploy key to database and authorized_keys file.
 | 
					// AddDeployKey add new deploy key to database and authorized_keys file.
 | 
				
			||||||
func AddDeployKey(repoID int64, name, content string) (*DeployKey, error) {
 | 
					func AddDeployKey(repoID int64, name, content string) (*DeployKey, error) {
 | 
				
			||||||
	if err := checkKeyContent(content); err != nil {
 | 
						fingerprint, err := calcFingerprint(content)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pkey := &PublicKey{
 | 
						pkey := &PublicKey{
 | 
				
			||||||
		Content: content,
 | 
							Fingerprint: fingerprint,
 | 
				
			||||||
		Mode:        AccessModeRead,
 | 
							Mode:        AccessModeRead,
 | 
				
			||||||
		Type:        KeyTypeDeploy,
 | 
							Type:        KeyTypeDeploy,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -687,6 +704,8 @@ func AddDeployKey(repoID int64, name, content string) (*DeployKey, error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// First time use this deploy key.
 | 
						// First time use this deploy key.
 | 
				
			||||||
	if !has {
 | 
						if !has {
 | 
				
			||||||
 | 
							pkey.Content = content
 | 
				
			||||||
 | 
							pkey.Name = name
 | 
				
			||||||
		if err = addKey(sess, pkey); err != nil {
 | 
							if err = addKey(sess, pkey); err != nil {
 | 
				
			||||||
			return nil, fmt.Errorf("addKey: %v", err)
 | 
								return nil, fmt.Errorf("addKey: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue