publickey.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. // Copyright 2014 The Gogs Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package models
  5. import (
  6. "bufio"
  7. "fmt"
  8. "io"
  9. "os"
  10. "os/exec"
  11. "path/filepath"
  12. "strings"
  13. "sync"
  14. "time"
  15. "github.com/Unknwon/com"
  16. )
  17. var (
  18. sshOpLocker = sync.Mutex{}
  19. //publicKeyRootPath string
  20. sshPath string
  21. appPath string
  22. // "### autogenerated by gitgos, DO NOT EDIT\n"
  23. tmplPublicKey = "command=\"%s serv key-%d\",no-port-forwarding," +
  24. "no-X11-forwarding,no-agent-forwarding,no-pty %s\n"
  25. )
  26. func exePath() (string, error) {
  27. file, err := exec.LookPath(os.Args[0])
  28. if err != nil {
  29. return "", err
  30. }
  31. return filepath.Abs(file)
  32. }
  33. func homeDir() string {
  34. home, err := com.HomeDir()
  35. if err != nil {
  36. return "/"
  37. }
  38. return home
  39. }
  40. func init() {
  41. var err error
  42. appPath, err = exePath()
  43. if err != nil {
  44. println(err.Error())
  45. os.Exit(2)
  46. }
  47. sshPath = filepath.Join(homeDir(), ".ssh")
  48. }
  49. type PublicKey struct {
  50. Id int64
  51. OwnerId int64 `xorm:"index"`
  52. Name string `xorm:"unique not null"`
  53. Content string `xorm:"text not null"`
  54. Created time.Time `xorm:"created"`
  55. Updated time.Time `xorm:"updated"`
  56. }
  57. func GenAuthorizedKey(keyId int64, key string) string {
  58. return fmt.Sprintf(tmplPublicKey, appPath, keyId, key)
  59. }
  60. func AddPublicKey(key *PublicKey) error {
  61. _, err := orm.Insert(key)
  62. if err != nil {
  63. return err
  64. }
  65. err = SaveAuthorizedKeyFile(key)
  66. if err != nil {
  67. _, err2 := orm.Delete(key)
  68. if err2 != nil {
  69. // TODO: log the error
  70. }
  71. return err
  72. }
  73. return nil
  74. }
  75. // DeletePublicKey deletes SSH key information both in database and authorized_keys file.
  76. func DeletePublicKey(key *PublicKey) (err error) {
  77. if _, err = orm.Delete(key); err != nil {
  78. return err
  79. }
  80. sshOpLocker.Lock()
  81. defer sshOpLocker.Unlock()
  82. p := filepath.Join(sshPath, "authorized_keys")
  83. tmpP := filepath.Join(sshPath, "authorized_keys.tmp")
  84. fr, err := os.Open(p)
  85. if err != nil {
  86. return err
  87. }
  88. defer fr.Close()
  89. fw, err := os.Create(tmpP)
  90. if err != nil {
  91. return err
  92. }
  93. defer fw.Close()
  94. buf := bufio.NewReader(fr)
  95. for {
  96. line, errRead := buf.ReadString('\n')
  97. line = strings.TrimSpace(line)
  98. if errRead != nil {
  99. if errRead != io.EOF {
  100. return errRead
  101. }
  102. // Reached end of file, if nothing to read then break,
  103. // otherwise handle the last line.
  104. if len(line) == 0 {
  105. break
  106. }
  107. }
  108. // Found the line and copy rest of file.
  109. if strings.Contains(line, key.Content) {
  110. if _, err = io.Copy(fw, fr); err != nil {
  111. return err
  112. }
  113. break
  114. }
  115. // Still finding the line, copy the line that currently read.
  116. if _, err = fw.WriteString(line + "\n"); err != nil {
  117. return err
  118. }
  119. if errRead == io.EOF {
  120. break
  121. }
  122. }
  123. if err = os.Remove(p); err != nil {
  124. return err
  125. }
  126. return os.Rename(tmpP, p)
  127. }
  128. func ListPublicKey(userId int64) ([]PublicKey, error) {
  129. keys := make([]PublicKey, 0)
  130. err := orm.Find(&keys, &PublicKey{OwnerId: userId})
  131. return keys, err
  132. }
  133. func SaveAuthorizedKeyFile(key *PublicKey) error {
  134. sshOpLocker.Lock()
  135. defer sshOpLocker.Unlock()
  136. p := filepath.Join(sshPath, "authorized_keys")
  137. f, err := os.OpenFile(p, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
  138. if err != nil {
  139. return err
  140. }
  141. defer f.Close()
  142. //os.Chmod(p, 0600)
  143. _, err = f.WriteString(GenAuthorizedKey(key.Id, key.Content))
  144. return err
  145. }