func addKey(e Engine, key *PublicKey) (err error) { // Calculate fingerprint. tmpPath := strings.Replace(path.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond()), "id_rsa.pub"), "\\", "/", -1) os.MkdirAll(path.Dir(tmpPath), os.ModePerm) if err = ioutil.WriteFile(tmpPath, []byte(key.Content), 0644); err != nil { return err } stdout, stderr, err := process.Exec("AddPublicKey", "ssh-keygen", "-lf", tmpPath) if err != nil { return fmt.Errorf("'ssh-keygen -lf %s' failed with error '%s': %s", tmpPath, err, stderr) } else if len(stdout) < 2 { return errors.New("not enough output for calculating fingerprint: " + stdout) } key.Fingerprint = strings.Split(stdout, " ")[1] // Save SSH key. if _, err = e.Insert(key); err != nil { return err } // Don't need to rewrite this file if builtin SSH server is enabled. if setting.SSH.StartBuiltinServer { return nil } return saveAuthorizedKeyFile(key) }
// SSHKeyGenParsePublicKey extracts key type and length using ssh-keygen. func SSHKeyGenParsePublicKey(key string) (string, int, error) { // The ssh-keygen in Windows does not print key type, so no need go further. if setting.IsWindows { return "", 0, nil } tmpName, err := writeTmpKeyFile(key) if err != nil { return "", 0, fmt.Errorf("writeTmpKeyFile: %v", err) } defer os.Remove(tmpName) stdout, stderr, err := process.Exec("SSHKeyGenParsePublicKey", setting.SSH.KeygenPath, "-lf", tmpName) if err != nil { return "", 0, fmt.Errorf("Fail to parse public key: %s - %s", err, stderr) } if strings.Contains(stdout, "is not a public key file") { return "", 0, ErrKeyUnableVerify{stdout} } fields := strings.Split(stdout, " ") if len(fields) < 4 { return "", 0, fmt.Errorf("Invalid public key line: %s", stdout) } keyType := strings.Trim(fields[len(fields)-1], "()\r\n") return strings.ToLower(keyType), com.StrTo(fields[0]).MustInt(), nil }