twofactor.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. package user
  2. import (
  3. "bytes"
  4. "encoding/base64"
  5. "image/png"
  6. "github.com/ente-io/museum/pkg/utils/network"
  7. "github.com/ente-io/museum/ente"
  8. "github.com/ente-io/museum/pkg/utils/auth"
  9. "github.com/ente-io/museum/pkg/utils/crypto"
  10. "github.com/ente-io/museum/pkg/utils/time"
  11. "github.com/ente-io/stacktrace"
  12. "github.com/gin-gonic/gin"
  13. "github.com/pquerna/otp/totp"
  14. )
  15. // SetupTwoFactor generates a two factor secret and sends it to user to setup his authenticator app with
  16. func (c *UserController) SetupTwoFactor(userID int64) (ente.TwoFactorSecret, error) {
  17. user, err := c.UserRepo.Get(userID)
  18. if err != nil {
  19. return ente.TwoFactorSecret{}, stacktrace.Propagate(err, "")
  20. }
  21. if _, keyErr := c.UserRepo.GetKeyAttributes(userID); keyErr != nil {
  22. return ente.TwoFactorSecret{}, stacktrace.Propagate(keyErr, "User keys setup is not completed")
  23. }
  24. key, err := totp.Generate(totp.GenerateOpts{Issuer: TOTPIssuerORG, AccountName: user.Email})
  25. if err != nil {
  26. return ente.TwoFactorSecret{}, stacktrace.Propagate(err, "")
  27. }
  28. encryptedSecret, err := crypto.Encrypt(key.Secret(), c.SecretEncryptionKey)
  29. if err != nil {
  30. return ente.TwoFactorSecret{}, stacktrace.Propagate(err, "")
  31. }
  32. secretHash, err := crypto.GetHash(key.Secret(), c.HashingKey)
  33. if err != nil {
  34. return ente.TwoFactorSecret{}, stacktrace.Propagate(err, "")
  35. }
  36. err = c.TwoFactorRepo.SetTempTwoFactorSecret(userID, encryptedSecret, secretHash, time.Microseconds()+TwoFactorValidityDurationInMicroSeconds)
  37. if err != nil {
  38. return ente.TwoFactorSecret{}, stacktrace.Propagate(err, "")
  39. }
  40. buf := new(bytes.Buffer)
  41. img, err := key.Image(200, 200)
  42. if err != nil {
  43. return ente.TwoFactorSecret{}, stacktrace.Propagate(err, "")
  44. }
  45. err = png.Encode(buf, img)
  46. if err != nil {
  47. return ente.TwoFactorSecret{}, stacktrace.Propagate(err, "")
  48. }
  49. return ente.TwoFactorSecret{SecretCode: key.Secret(), QRCode: base64.StdEncoding.EncodeToString(buf.Bytes())}, nil
  50. }
  51. // EnableTwoFactor handles the two factor activation request after user has setup his two factor by validing a totp request
  52. func (c *UserController) EnableTwoFactor(userID int64, request ente.TwoFactorEnableRequest) error {
  53. encryptedSecrets, hashedSecrets, err := c.TwoFactorRepo.GetTempTwoFactorSecret(userID)
  54. if err != nil {
  55. return stacktrace.Propagate(err, "")
  56. }
  57. valid := false
  58. validSecret := ""
  59. var validEncryptedSecret ente.EncryptionResult
  60. var validSecretHash string
  61. for index, encryptedSecret := range encryptedSecrets {
  62. secret, err := crypto.Decrypt(encryptedSecret.Cipher, c.SecretEncryptionKey, encryptedSecret.Nonce)
  63. if err != nil {
  64. return stacktrace.Propagate(err, "")
  65. }
  66. valid = totp.Validate(request.Code, secret)
  67. if valid {
  68. validSecret = secret
  69. validEncryptedSecret = encryptedSecret
  70. validSecretHash = hashedSecrets[index]
  71. break
  72. }
  73. }
  74. if !valid {
  75. return stacktrace.Propagate(ente.ErrIncorrectTOTP, "")
  76. }
  77. err = c.UserRepo.SetTwoFactorSecret(userID, validEncryptedSecret, validSecretHash, request.EncryptedTwoFactorSecret, request.TwoFactorSecretDecryptionNonce)
  78. if err != nil {
  79. return stacktrace.Propagate(err, "")
  80. }
  81. err = c.TwoFactorRepo.UpdateTwoFactorStatus(userID, true)
  82. if err != nil {
  83. return stacktrace.Propagate(err, "")
  84. }
  85. secretHash, err := crypto.GetHash(validSecret, c.HashingKey)
  86. if err != nil {
  87. return stacktrace.Propagate(err, "")
  88. }
  89. err = c.TwoFactorRepo.RemoveTempTwoFactorSecret(secretHash)
  90. return stacktrace.Propagate(err, "")
  91. }
  92. // VerifyTwoFactor handles the two factor validation request
  93. func (c *UserController) VerifyTwoFactor(context *gin.Context, sessionID string, otp string) (ente.TwoFactorAuthorizationResponse, error) {
  94. userID, err := c.TwoFactorRepo.GetUserIDWithTwoFactorSession(sessionID)
  95. if err != nil {
  96. return ente.TwoFactorAuthorizationResponse{}, stacktrace.Propagate(err, "")
  97. }
  98. isTwoFactorEnabled, err := c.UserRepo.IsTwoFactorEnabled(userID)
  99. if err != nil {
  100. return ente.TwoFactorAuthorizationResponse{}, stacktrace.Propagate(err, "")
  101. }
  102. if !isTwoFactorEnabled {
  103. return ente.TwoFactorAuthorizationResponse{}, stacktrace.Propagate(ente.ErrBadRequest, "")
  104. }
  105. secret, err := c.TwoFactorRepo.GetTwoFactorSecret(userID)
  106. if err != nil {
  107. return ente.TwoFactorAuthorizationResponse{}, stacktrace.Propagate(err, "")
  108. }
  109. valid := totp.Validate(otp, secret)
  110. if !valid {
  111. return ente.TwoFactorAuthorizationResponse{}, stacktrace.Propagate(ente.ErrIncorrectTOTP, "")
  112. }
  113. response, err := c.GetKeyAttributeAndToken(context, userID)
  114. if err != nil {
  115. return ente.TwoFactorAuthorizationResponse{}, stacktrace.Propagate(err, "")
  116. }
  117. return response, nil
  118. }
  119. // DisableTwoFactor disables the two factor authentication for a user
  120. func (c *UserController) DisableTwoFactor(userID int64) error {
  121. err := c.TwoFactorRepo.UpdateTwoFactorStatus(userID, false)
  122. return stacktrace.Propagate(err, "")
  123. }
  124. // RecoverTwoFactor handles the two factor recovery request by sending the
  125. // recoveryKeyEncryptedTwoFactorSecret for the user to decrypt it and make twoFactor removal api call
  126. func (c *UserController) RecoverTwoFactor(sessionID string) (*ente.TwoFactorRecoveryResponse, error) {
  127. userID, err := c.TwoFactorRepo.GetUserIDWithTwoFactorSession(sessionID)
  128. if err != nil {
  129. return nil, stacktrace.Propagate(err, "")
  130. }
  131. response, err := c.TwoFactorRepo.GetRecoveryKeyEncryptedTwoFactorSecret(userID)
  132. if err != nil {
  133. return nil, stacktrace.Propagate(err, "")
  134. }
  135. return &response, nil
  136. }
  137. // RemoveTOTPTwoFactor handles two factor deactivation request if user lost his device
  138. // by authenticating him using his twoFactorsessionToken and twoFactor secret
  139. func (c *UserController) RemoveTOTPTwoFactor(context *gin.Context, sessionID string, secret string) (*ente.TwoFactorAuthorizationResponse, error) {
  140. userID, err := c.TwoFactorRepo.GetUserIDWithTwoFactorSession(sessionID)
  141. if err != nil {
  142. return nil, stacktrace.Propagate(err, "")
  143. }
  144. secretHash, err := crypto.GetHash(secret, c.HashingKey)
  145. if err != nil {
  146. return nil, stacktrace.Propagate(err, "")
  147. }
  148. exists, err := c.TwoFactorRepo.VerifyTwoFactorSecret(userID, secretHash)
  149. if err != nil {
  150. return nil, stacktrace.Propagate(err, "")
  151. }
  152. if !exists {
  153. return nil, stacktrace.Propagate(ente.ErrPermissionDenied, "")
  154. }
  155. err = c.TwoFactorRepo.UpdateTwoFactorStatus(userID, false)
  156. if err != nil {
  157. return nil, stacktrace.Propagate(err, "")
  158. }
  159. response, err := c.GetKeyAttributeAndToken(context, userID)
  160. if err != nil {
  161. return nil, stacktrace.Propagate(err, "")
  162. }
  163. return &response, nil
  164. }
  165. func (c *UserController) GetKeyAttributeAndToken(context *gin.Context, userID int64) (ente.TwoFactorAuthorizationResponse, error) {
  166. keyAttributes, err := c.UserRepo.GetKeyAttributes(userID)
  167. if err != nil {
  168. return ente.TwoFactorAuthorizationResponse{}, stacktrace.Propagate(err, "")
  169. }
  170. token, err := auth.GenerateURLSafeRandomString(TokenLength)
  171. if err != nil {
  172. return ente.TwoFactorAuthorizationResponse{}, stacktrace.Propagate(err, "")
  173. }
  174. encryptedToken, err := crypto.GetEncryptedToken(token, keyAttributes.PublicKey)
  175. if err != nil {
  176. return ente.TwoFactorAuthorizationResponse{}, stacktrace.Propagate(err, "")
  177. }
  178. err = c.UserAuthRepo.AddToken(userID, auth.GetApp(context),
  179. token, network.GetClientIP(context), context.Request.UserAgent())
  180. if err != nil {
  181. return ente.TwoFactorAuthorizationResponse{}, stacktrace.Propagate(err, "")
  182. }
  183. return ente.TwoFactorAuthorizationResponse{
  184. ID: userID,
  185. KeyAttributes: &keyAttributes,
  186. EncryptedToken: encryptedToken,
  187. }, nil
  188. }