auth.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. package auth
  2. import (
  3. "crypto/rand"
  4. "crypto/sha256"
  5. "encoding/base64"
  6. "encoding/hex"
  7. "encoding/json"
  8. "fmt"
  9. "goseg/config"
  10. "goseg/structs"
  11. "net"
  12. "net/http"
  13. "strings"
  14. "sync"
  15. "time"
  16. "github.com/gorilla/websocket"
  17. "golang.org/x/crypto/nacl/secretbox"
  18. )
  19. var (
  20. // maps a websocket conn to a tokenid
  21. // tokenid's can be referenced from the global conf
  22. AuthenticatedClients = struct {
  23. Conns map[*websocket.Conn]string
  24. sync.Mutex
  25. }{
  26. Conns: make(map[*websocket.Conn]string),
  27. }
  28. UnauthClients = struct {
  29. Conns map[*websocket.Conn]string
  30. sync.Mutex
  31. }{
  32. Conns: make(map[*websocket.Conn]string),
  33. }
  34. )
  35. // check if websocket session is in the auth map
  36. func WsIsAuthenticated(conn *websocket.Conn) bool {
  37. AuthenticatedClients.Lock()
  38. _, exists := AuthenticatedClients.Conns[conn]
  39. AuthenticatedClients.Unlock()
  40. return exists
  41. }
  42. // // CheckToken checks the validity of the token.
  43. // func CheckToken(token string, conn *websocket.Conn, setup bool) (bool, string, error) {
  44. // if token == "" {
  45. // authStatus := false
  46. // if setup {
  47. // authStatus = true
  48. // }
  49. // newToken, err := CreateToken(conn, setup)
  50. // if err != nil {
  51. // return false, "", err
  52. // }
  53. // return authStatus, newToken["token"], nil
  54. // }
  55. // return false, "", nil
  56. // }
  57. // CreateToken creates a new session token.
  58. func CreateToken(conn *websocket.Conn, r *http.Request, setup bool) (map[string]string, error) {
  59. // extract conn info
  60. var ip string
  61. if forwarded := r.Header.Get("X-Forwarded-For"); forwarded != "" {
  62. ip = strings.Split(forwarded, ",")[0]
  63. } else {
  64. ip, _, _ = net.SplitHostPort(r.RemoteAddr)
  65. }
  66. userAgent := r.Header.Get("User-Agent")
  67. conf := config.Conf()
  68. now := time.Now().Format("2006-01-02_15:04:05")
  69. // generate random strings for id, secret, and padding
  70. id := config.RandString(32)
  71. secret := config.RandString(128)
  72. padding := config.RandString(32)
  73. contents := map[string]string{
  74. "id": id,
  75. "ip": ip,
  76. "user_agent": userAgent,
  77. "secret": secret,
  78. "padding": padding,
  79. "authorized": fmt.Sprintf("%v", setup),
  80. "created": now,
  81. }
  82. // encrypt the contents
  83. key := conf.KeyFile
  84. encryptedText, err := KeyfileEncrypt(contents, key)
  85. if err != nil {
  86. return nil, fmt.Errorf("failed to encrypt token: %v", err)
  87. }
  88. hashed := sha256.Sum256([]byte(encryptedText))
  89. hash := hex.EncodeToString(hashed[:])
  90. // Update sessions in the system's configuration
  91. AddSession(id, hash, now, setup)
  92. return map[string]string{
  93. "id": id,
  94. "token": encryptedText,
  95. }, nil
  96. }
  97. // take session details and add to SysConfig
  98. func AddSession(tokenID string, hash string, created string, authorized bool) error {
  99. session := structs.SessionInfo{
  100. Hash: hash,
  101. Created: created,
  102. }
  103. if authorized {
  104. update := map[string]interface{}{
  105. "Sessions": map[string]interface{}{
  106. "Authorized": map[string]string{
  107. "Hash": session.Hash,
  108. "Created": session.Created,
  109. },
  110. },
  111. }
  112. if err := config.UpdateConf(update); err != nil {
  113. return fmt.Errorf("Error adding session: %v", err)
  114. }
  115. if err := config.RemoveSession(tokenID, false); err != nil {
  116. return fmt.Errorf("Error removing session: %v", err)
  117. }
  118. } else {
  119. update := map[string]interface{}{
  120. "Sessions": map[string]interface{}{
  121. "Unauthorized": map[string]string{
  122. "Hash": session.Hash,
  123. "Created": session.Created,
  124. },
  125. },
  126. }
  127. if err := config.UpdateConf(update); err != nil {
  128. return fmt.Errorf("Error adding session: %v", err)
  129. }
  130. if err := config.RemoveSession(tokenID, true); err != nil {
  131. return fmt.Errorf("Error removing session: %v", err)
  132. }
  133. }
  134. return nil
  135. }
  136. // encrypt the contents using stored keyfile val
  137. func KeyfileEncrypt(contents map[string]string, key string) (string, error) {
  138. contentBytes, err := json.Marshal(contents)
  139. if err != nil {
  140. return "", err
  141. }
  142. // convert key to bytes
  143. keyBytes := []byte(key)
  144. if len(keyBytes) != 32 {
  145. return "", fmt.Errorf("key must be 32 bytes in length")
  146. }
  147. var keyArray [32]byte
  148. copy(keyArray[:], keyBytes)
  149. // generate nonce
  150. var nonce [24]byte
  151. if _, err := rand.Read(nonce[:]); err != nil {
  152. return "", err
  153. }
  154. // encrypt contents
  155. encrypted := secretbox.Seal(nonce[:], contentBytes, &nonce, &keyArray)
  156. return base64.URLEncoding.EncodeToString(encrypted), nil
  157. }
  158. // decrypt routine
  159. func KeyfileDecrypt(encryptedText string, key string) (map[string]string, error) {
  160. // get bytes
  161. keyBytes := []byte(key)
  162. var keyArray [32]byte
  163. copy(keyArray[:], keyBytes)
  164. encryptedBytes, err := base64.URLEncoding.DecodeString(encryptedText)
  165. if err != nil {
  166. return nil, err
  167. }
  168. // get nonce
  169. var nonce [24]byte
  170. copy(nonce[:], encryptedBytes[:24])
  171. // attempt decrypt
  172. decrypted, ok := secretbox.Open(nil, encryptedBytes[24:], &nonce, &keyArray)
  173. if !ok {
  174. return nil, fmt.Errorf("Decryption failed")
  175. }
  176. var contents map[string]string
  177. if err := json.Unmarshal(decrypted, &contents); err != nil {
  178. return nil, err
  179. }
  180. return contents, nil
  181. }
  182. // salted sha256
  183. func Hasher(password string) string {
  184. conf := config.Conf()
  185. salt := conf.Salt
  186. toHash := salt + password
  187. res := sha256.Sum256([]byte(toHash))
  188. return hex.EncodeToString(res[:])
  189. }
  190. // check if pw matches sysconfig
  191. func AuthenticateLogin(password string) bool {
  192. conf := config.Conf()
  193. if Hasher(password) == conf.PwHash {
  194. return true
  195. } else {
  196. return false
  197. }
  198. }