diff --git a/pkg/routes/api/v1/user_caldav_token.go b/pkg/routes/api/v1/user_caldav_token.go
new file mode 100644
index 00000000..adf76a47
--- /dev/null
+++ b/pkg/routes/api/v1/user_caldav_token.go
@@ -0,0 +1,112 @@
+// Vikunja is a to-do list application to facilitate your life.
+// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public Licensee as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public Licensee for more details.
+//
+// You should have received a copy of the GNU Affero General Public Licensee
+// along with this program. If not, see .
+
+package v1
+
+import (
+ "net/http"
+ "strconv"
+
+ "code.vikunja.io/api/pkg/models"
+
+ "code.vikunja.io/api/pkg/user"
+ "code.vikunja.io/web/handler"
+ "github.com/labstack/echo/v4"
+)
+
+// GenerateCaldavToken is the handler to create a caldav token
+// @Summary Generate a caldav token
+// @Description Generates a caldav token which can be used for the caldav api. It is not possible to see the token again after it was generated.
+// @tags user
+// @Accept json
+// @Produce json
+// @Security JWTKeyAuth
+// @Success 200 {object} user.Token
+// @Failure 400 {object} web.HTTPError "Something's invalid."
+// @Failure 404 {object} web.HTTPError "User does not exist."
+// @Failure 500 {object} models.Message "Internal server error."
+// @Router /user/settings/token/caldav [put]
+func GenerateCaldavToken(c echo.Context) (err error) {
+
+ u, err := user.GetCurrentUser(c)
+ if err != nil {
+ return handler.HandleHTTPError(err, c)
+ }
+
+ token, err := user.GenerateNewCaldavToken(u)
+ if err != nil {
+ return handler.HandleHTTPError(err, c)
+ }
+
+ return c.JSON(http.StatusCreated, token)
+}
+
+// GetCaldavTokens is the handler to return a list of all caldav tokens for the current user
+// @Summary Returns the caldav tokens for the current user
+// @Description Return the IDs and created dates of all caldav tokens for the current user.
+// @tags user
+// @Accept json
+// @Produce json
+// @Security JWTKeyAuth
+// @Success 200 {array} user.Token
+// @Failure 400 {object} web.HTTPError "Something's invalid."
+// @Failure 404 {object} web.HTTPError "User does not exist."
+// @Failure 500 {object} models.Message "Internal server error."
+// @Router /user/settings/token/caldav [get]
+func GetCaldavTokens(c echo.Context) error {
+ u, err := user.GetCurrentUser(c)
+ if err != nil {
+ return handler.HandleHTTPError(err, c)
+ }
+
+ tokens, err := user.GetCaldavTokens(u)
+ if err != nil {
+ return handler.HandleHTTPError(err, c)
+ }
+
+ return c.JSON(http.StatusCreated, tokens)
+}
+
+// DeleteCaldavToken is the handler to delete a caldv token
+// @Summary Delete a caldav token by id
+// @tags user
+// @Accept json
+// @Produce json
+// @Security JWTKeyAuth
+// @Param id path int true "Token ID"
+// @Success 200 {object} models.Message
+// @Failure 400 {object} web.HTTPError "Something's invalid."
+// @Failure 404 {object} web.HTTPError "User does not exist."
+// @Failure 500 {object} models.Message "Internal server error."
+// @Router /user/settings/token/caldav/{id} [get]
+func DeleteCaldavToken(c echo.Context) error {
+ u, err := user.GetCurrentUser(c)
+ if err != nil {
+ return handler.HandleHTTPError(err, c)
+ }
+
+ id, err := strconv.ParseInt(c.Param("id"), 10, 64)
+ if err != nil {
+ return handler.HandleHTTPError(err, c)
+ }
+
+ err = user.DeleteCaldavTokenByID(u, id)
+ if err != nil {
+ return handler.HandleHTTPError(err, c)
+ }
+
+ return c.JSON(http.StatusOK, &models.Message{Message: "The token was deleted successfully."})
+}
diff --git a/pkg/routes/caldav/auth.go b/pkg/routes/caldav/auth.go
new file mode 100644
index 00000000..8b9a9d4e
--- /dev/null
+++ b/pkg/routes/caldav/auth.go
@@ -0,0 +1,70 @@
+// Vikunja is a to-do list application to facilitate your life.
+// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public Licensee as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public Licensee for more details.
+//
+// You should have received a copy of the GNU Affero General Public Licensee
+// along with this program. If not, see .
+
+package caldav
+
+import (
+ "errors"
+
+ "code.vikunja.io/api/pkg/db"
+ "code.vikunja.io/api/pkg/log"
+ "code.vikunja.io/api/pkg/user"
+
+ "github.com/labstack/echo/v4"
+ "golang.org/x/crypto/bcrypt"
+)
+
+func BasicAuth(username, password string, c echo.Context) (bool, error) {
+ creds := &user.Login{
+ Username: username,
+ Password: password,
+ }
+ s := db.NewSession()
+ defer s.Close()
+ u, err := user.CheckUserCredentials(s, creds)
+ if err != nil && !user.IsErrWrongUsernameOrPassword(err) {
+ log.Errorf("Error during basic auth for caldav: %v", err)
+ return false, nil
+ }
+
+ if err == nil {
+ c.Set("userBasicAuth", u)
+ return true, nil
+ }
+
+ tokens, err := user.GetCaldavTokens(u)
+ if err != nil {
+ log.Errorf("Error while getting tokens for caldav auth: %v", err)
+ return false, nil
+ }
+
+ // Looping over all tokens until we find one that matches
+ for _, token := range tokens {
+ err = bcrypt.CompareHashAndPassword([]byte(token.Token), []byte(password))
+ if err != nil {
+ if errors.Is(err, bcrypt.ErrMismatchedHashAndPassword) {
+ continue
+ }
+ log.Errorf("Error while verifying tokens for caldav auth: %v", err)
+ return false, nil
+ }
+
+ c.Set("userBasicAuth", u)
+ return true, nil
+ }
+
+ return false, nil
+}
diff --git a/pkg/routes/routes.go b/pkg/routes/routes.go
index 46b6c88d..d5f79a8c 100644
--- a/pkg/routes/routes.go
+++ b/pkg/routes/routes.go
@@ -75,7 +75,6 @@ import (
apiv1 "code.vikunja.io/api/pkg/routes/api/v1"
"code.vikunja.io/api/pkg/routes/caldav"
_ "code.vikunja.io/api/pkg/swagger" // To generate swagger docs
- "code.vikunja.io/api/pkg/user"
"code.vikunja.io/api/pkg/version"
"code.vikunja.io/web"
"code.vikunja.io/web/handler"
@@ -194,7 +193,7 @@ func RegisterRoutes(e *echo.Echo) {
if config.ServiceEnableCaldav.GetBool() {
// Caldav routes
wkg := e.Group("/.well-known")
- wkg.Use(middleware.BasicAuth(caldavBasicAuth))
+ wkg.Use(middleware.BasicAuth(caldav.BasicAuth))
wkg.Any("/caldav", caldav.PrincipalHandler)
wkg.Any("/caldav/", caldav.PrincipalHandler)
c := e.Group("/dav")
@@ -323,6 +322,9 @@ func registerAPIRoutes(a *echo.Group) {
u.POST("/export/request", apiv1.RequestUserDataExport)
u.POST("/export/download", apiv1.DownloadUserDataExport)
u.GET("/timezones", apiv1.GetAvailableTimezones)
+ u.PUT("/settings/token/caldav", apiv1.GenerateCaldavToken)
+ u.GET("/settings/token/caldav", apiv1.GetCaldavTokens)
+ u.DELETE("/settings/token/caldav/:id", apiv1.DeleteCaldavToken)
if config.ServiceEnableTotp.GetBool() {
u.GET("/settings/totp", apiv1.UserTOTP)
@@ -663,7 +665,7 @@ func registerMigrations(m *echo.Group) {
func registerCalDavRoutes(c *echo.Group) {
// Basic auth middleware
- c.Use(middleware.BasicAuth(caldavBasicAuth))
+ c.Use(middleware.BasicAuth(caldav.BasicAuth))
// THIS is the entry point for caldav clients, otherwise lists will show up double
c.Any("", caldav.EntryHandler)
@@ -675,26 +677,3 @@ func registerCalDavRoutes(c *echo.Group) {
c.Any("/lists/:list/", caldav.ListHandler)
c.Any("/lists/:list/:task", caldav.TaskHandler) // Mostly used for editing
}
-
-func caldavBasicAuth(username, password string, c echo.Context) (bool, error) {
- creds := &user.Login{
- Username: username,
- Password: password,
- }
- s := db.NewSession()
- defer s.Close()
- u, err := user.CheckUserCredentials(s, creds)
- if err != nil {
- _ = s.Rollback()
- log.Errorf("Error during basic auth for caldav: %v", err)
- return false, nil
- }
-
- if err := s.Commit(); err != nil {
- return false, err
- }
-
- // Save the user in echo context for later use
- c.Set("userBasicAuth", u)
- return true, nil
-}
diff --git a/pkg/swagger/docs.go b/pkg/swagger/docs.go
index 5b2b39e2..f45fdfeb 100644
--- a/pkg/swagger/docs.go
+++ b/pkg/swagger/docs.go
@@ -7026,6 +7026,153 @@ var doc = `{
}
}
},
+ "/user/settings/token/caldav": {
+ "get": {
+ "security": [
+ {
+ "JWTKeyAuth": []
+ }
+ ],
+ "description": "Return the IDs and created dates of all caldav tokens for the current user.",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "user"
+ ],
+ "summary": "Returns the caldav tokens for the current user",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/user.Token"
+ }
+ }
+ },
+ "400": {
+ "description": "Something's invalid.",
+ "schema": {
+ "$ref": "#/definitions/web.HTTPError"
+ }
+ },
+ "404": {
+ "description": "User does not exist.",
+ "schema": {
+ "$ref": "#/definitions/web.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal server error.",
+ "schema": {
+ "$ref": "#/definitions/models.Message"
+ }
+ }
+ }
+ },
+ "put": {
+ "security": [
+ {
+ "JWTKeyAuth": []
+ }
+ ],
+ "description": "Generates a caldav token which can be used for the caldav api. It is not possible to see the token again after it was generated.",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "user"
+ ],
+ "summary": "Generate a caldav token",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/user.Token"
+ }
+ },
+ "400": {
+ "description": "Something's invalid.",
+ "schema": {
+ "$ref": "#/definitions/web.HTTPError"
+ }
+ },
+ "404": {
+ "description": "User does not exist.",
+ "schema": {
+ "$ref": "#/definitions/web.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal server error.",
+ "schema": {
+ "$ref": "#/definitions/models.Message"
+ }
+ }
+ }
+ }
+ },
+ "/user/settings/token/caldav/{id}": {
+ "get": {
+ "security": [
+ {
+ "JWTKeyAuth": []
+ }
+ ],
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "user"
+ ],
+ "summary": "Delete a caldav token by id",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "Token ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/models.Message"
+ }
+ },
+ "400": {
+ "description": "Something's invalid.",
+ "schema": {
+ "$ref": "#/definitions/web.HTTPError"
+ }
+ },
+ "404": {
+ "description": "User does not exist.",
+ "schema": {
+ "$ref": "#/definitions/web.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal server error.",
+ "schema": {
+ "$ref": "#/definitions/models.Message"
+ }
+ }
+ }
+ }
+ },
"/user/settings/totp": {
"get": {
"security": [
@@ -8918,6 +9065,20 @@ var doc = `{
}
}
},
+ "user.Token": {
+ "type": "object",
+ "properties": {
+ "created": {
+ "type": "string"
+ },
+ "id": {
+ "type": "integer"
+ },
+ "token": {
+ "type": "string"
+ }
+ }
+ },
"user.User": {
"type": "object",
"properties": {
diff --git a/pkg/swagger/swagger.json b/pkg/swagger/swagger.json
index 72a59730..d37a426c 100644
--- a/pkg/swagger/swagger.json
+++ b/pkg/swagger/swagger.json
@@ -7010,6 +7010,153 @@
}
}
},
+ "/user/settings/token/caldav": {
+ "get": {
+ "security": [
+ {
+ "JWTKeyAuth": []
+ }
+ ],
+ "description": "Return the IDs and created dates of all caldav tokens for the current user.",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "user"
+ ],
+ "summary": "Returns the caldav tokens for the current user",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/user.Token"
+ }
+ }
+ },
+ "400": {
+ "description": "Something's invalid.",
+ "schema": {
+ "$ref": "#/definitions/web.HTTPError"
+ }
+ },
+ "404": {
+ "description": "User does not exist.",
+ "schema": {
+ "$ref": "#/definitions/web.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal server error.",
+ "schema": {
+ "$ref": "#/definitions/models.Message"
+ }
+ }
+ }
+ },
+ "put": {
+ "security": [
+ {
+ "JWTKeyAuth": []
+ }
+ ],
+ "description": "Generates a caldav token which can be used for the caldav api. It is not possible to see the token again after it was generated.",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "user"
+ ],
+ "summary": "Generate a caldav token",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/user.Token"
+ }
+ },
+ "400": {
+ "description": "Something's invalid.",
+ "schema": {
+ "$ref": "#/definitions/web.HTTPError"
+ }
+ },
+ "404": {
+ "description": "User does not exist.",
+ "schema": {
+ "$ref": "#/definitions/web.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal server error.",
+ "schema": {
+ "$ref": "#/definitions/models.Message"
+ }
+ }
+ }
+ }
+ },
+ "/user/settings/token/caldav/{id}": {
+ "get": {
+ "security": [
+ {
+ "JWTKeyAuth": []
+ }
+ ],
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "user"
+ ],
+ "summary": "Delete a caldav token by id",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "Token ID",
+ "name": "id",
+ "in": "path",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "$ref": "#/definitions/models.Message"
+ }
+ },
+ "400": {
+ "description": "Something's invalid.",
+ "schema": {
+ "$ref": "#/definitions/web.HTTPError"
+ }
+ },
+ "404": {
+ "description": "User does not exist.",
+ "schema": {
+ "$ref": "#/definitions/web.HTTPError"
+ }
+ },
+ "500": {
+ "description": "Internal server error.",
+ "schema": {
+ "$ref": "#/definitions/models.Message"
+ }
+ }
+ }
+ }
+ },
"/user/settings/totp": {
"get": {
"security": [
@@ -8902,6 +9049,20 @@
}
}
},
+ "user.Token": {
+ "type": "object",
+ "properties": {
+ "created": {
+ "type": "string"
+ },
+ "id": {
+ "type": "integer"
+ },
+ "token": {
+ "type": "string"
+ }
+ }
+ },
"user.User": {
"type": "object",
"properties": {
diff --git a/pkg/swagger/swagger.yaml b/pkg/swagger/swagger.yaml
index adb7e0d5..8df979f8 100644
--- a/pkg/swagger/swagger.yaml
+++ b/pkg/swagger/swagger.yaml
@@ -1210,6 +1210,15 @@ definitions:
passcode:
type: string
type: object
+ user.Token:
+ properties:
+ created:
+ type: string
+ id:
+ type: integer
+ token:
+ type: string
+ type: object
user.User:
properties:
created:
@@ -6079,6 +6088,101 @@ paths:
summary: Change general user settings of the current user.
tags:
- user
+ /user/settings/token/caldav:
+ get:
+ consumes:
+ - application/json
+ description: Return the IDs and created dates of all caldav tokens for the current
+ user.
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ items:
+ $ref: '#/definitions/user.Token'
+ type: array
+ "400":
+ description: Something's invalid.
+ schema:
+ $ref: '#/definitions/web.HTTPError'
+ "404":
+ description: User does not exist.
+ schema:
+ $ref: '#/definitions/web.HTTPError'
+ "500":
+ description: Internal server error.
+ schema:
+ $ref: '#/definitions/models.Message'
+ security:
+ - JWTKeyAuth: []
+ summary: Returns the caldav tokens for the current user
+ tags:
+ - user
+ put:
+ consumes:
+ - application/json
+ description: Generates a caldav token which can be used for the caldav api.
+ It is not possible to see the token again after it was generated.
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/user.Token'
+ "400":
+ description: Something's invalid.
+ schema:
+ $ref: '#/definitions/web.HTTPError'
+ "404":
+ description: User does not exist.
+ schema:
+ $ref: '#/definitions/web.HTTPError'
+ "500":
+ description: Internal server error.
+ schema:
+ $ref: '#/definitions/models.Message'
+ security:
+ - JWTKeyAuth: []
+ summary: Generate a caldav token
+ tags:
+ - user
+ /user/settings/token/caldav/{id}:
+ get:
+ consumes:
+ - application/json
+ parameters:
+ - description: Token ID
+ in: path
+ name: id
+ required: true
+ type: integer
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ $ref: '#/definitions/models.Message'
+ "400":
+ description: Something's invalid.
+ schema:
+ $ref: '#/definitions/web.HTTPError'
+ "404":
+ description: User does not exist.
+ schema:
+ $ref: '#/definitions/web.HTTPError'
+ "500":
+ description: Internal server error.
+ schema:
+ $ref: '#/definitions/models.Message'
+ security:
+ - JWTKeyAuth: []
+ summary: Delete a caldav token by id
+ tags:
+ - user
/user/settings/totp:
get:
consumes:
diff --git a/pkg/user/caldav_token.go b/pkg/user/caldav_token.go
new file mode 100644
index 00000000..4943773e
--- /dev/null
+++ b/pkg/user/caldav_token.go
@@ -0,0 +1,40 @@
+// Vikunja is a to-do list application to facilitate your life.
+// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public Licensee as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public Licensee for more details.
+//
+// You should have received a copy of the GNU Affero General Public Licensee
+// along with this program. If not, see .
+
+package user
+
+import "code.vikunja.io/api/pkg/db"
+
+func GenerateNewCaldavToken(u *User) (token *Token, err error) {
+ s := db.NewSession()
+ defer s.Close()
+
+ return generateHashedToken(s, u, TokenCaldavAuth)
+}
+
+func GetCaldavTokens(u *User) (tokens []*Token, err error) {
+ s := db.NewSession()
+ defer s.Close()
+
+ return getTokensForKind(s, u, TokenCaldavAuth)
+}
+
+func DeleteCaldavTokenByID(u *User, id int64) error {
+ s := db.NewSession()
+ defer s.Close()
+
+ return removeTokenByID(s, u, TokenCaldavAuth, id)
+}
diff --git a/pkg/user/delete.go b/pkg/user/delete.go
index c54160de..3e172720 100644
--- a/pkg/user/delete.go
+++ b/pkg/user/delete.go
@@ -87,7 +87,7 @@ func notifyUsersScheduledForDeletion() {
// RequestDeletion creates a user deletion confirm token and sends a notification to the user
func RequestDeletion(s *xorm.Session, user *User) (err error) {
- token, err := generateNewToken(s, user, TokenAccountDeletion)
+ token, err := generateToken(s, user, TokenAccountDeletion)
if err != nil {
return err
}
diff --git a/pkg/user/token.go b/pkg/user/token.go
index 076df953..dfdb6dc6 100644
--- a/pkg/user/token.go
+++ b/pkg/user/token.go
@@ -34,17 +34,19 @@ const (
TokenPasswordReset
TokenEmailConfirm
TokenAccountDeletion
+ TokenCaldavAuth
tokenSize = 64
)
// Token is a token a user can use to do things like verify their email or resetting their password
type Token struct {
- ID int64 `xorm:"bigint autoincr not null unique pk"`
- UserID int64 `xorm:"not null"`
- Token string `xorm:"varchar(450) not null index"`
- Kind TokenKind `xorm:"not null"`
- Created time.Time `xorm:"created not null"`
+ ID int64 `xorm:"bigint autoincr not null unique pk" json:"id"`
+ UserID int64 `xorm:"not null" json:"-"`
+ Token string `xorm:"varchar(450) not null index" json:"-"`
+ ClearTextToken string `xorm:"-" json:"token"`
+ Kind TokenKind `xorm:"not null" json:"-"`
+ Created time.Time `xorm:"created not null" json:"created"`
}
// TableName returns the real table name for user tokens
@@ -52,12 +54,28 @@ func (t *Token) TableName() string {
return "user_tokens"
}
-func generateNewToken(s *xorm.Session, u *User, kind TokenKind) (token *Token, err error) {
- token = &Token{
+func genToken(u *User, kind TokenKind) *Token {
+ return &Token{
UserID: u.ID,
Kind: kind,
Token: utils.MakeRandomString(tokenSize),
}
+}
+
+func generateToken(s *xorm.Session, u *User, kind TokenKind) (token *Token, err error) {
+ token = genToken(u, kind)
+
+ _, err = s.Insert(token)
+ return
+}
+
+func generateHashedToken(s *xorm.Session, u *User, kind TokenKind) (token *Token, err error) {
+ token = genToken(u, kind)
+ token.ClearTextToken = token.Token
+ token.Token, err = HashPassword(token.ClearTextToken)
+ if err != nil {
+ return nil, err
+ }
_, err = s.Insert(token)
return
@@ -74,12 +92,26 @@ func getToken(s *xorm.Session, token string, kind TokenKind) (t *Token, err erro
return
}
+func getTokensForKind(s *xorm.Session, u *User, kind TokenKind) (tokens []*Token, err error) {
+ tokens = []*Token{}
+
+ err = s.Where("kind = ? AND user_id = ?", kind, u.ID).
+ Find(&tokens)
+ return
+}
+
func removeTokens(s *xorm.Session, u *User, kind TokenKind) (err error) {
_, err = s.Where("user_id = ? AND kind = ?", u.ID, kind).
Delete(&Token{})
return
}
+func removeTokenByID(s *xorm.Session, u *User, kind TokenKind, id int64) (err error) {
+ _, err = s.Where("id = ? AND user_id = ? AND kind = ?", id, u.ID, kind).
+ Delete(&Token{})
+ return
+}
+
// RegisterTokenCleanupCron registers a cron function to clean up all password reset tokens older than 24 hours
func RegisterTokenCleanupCron() {
const logPrefix = "[User Token Cleanup Cron] "
diff --git a/pkg/user/update_email.go b/pkg/user/update_email.go
index 6b4b35d9..f1572ec1 100644
--- a/pkg/user/update_email.go
+++ b/pkg/user/update_email.go
@@ -63,7 +63,7 @@ func UpdateEmail(s *xorm.Session, update *EmailUpdate) (err error) {
}
update.User.Status = StatusEmailConfirmationRequired
- token, err := generateNewToken(s, update.User, TokenEmailConfirm)
+ token, err := generateToken(s, update.User, TokenEmailConfirm)
if err != nil {
return
}
diff --git a/pkg/user/user.go b/pkg/user/user.go
index 1a7c31bf..7be296e9 100644
--- a/pkg/user/user.go
+++ b/pkg/user/user.go
@@ -324,7 +324,7 @@ func CheckUserCredentials(s *xorm.Session, u *Login) (*User, error) {
if IsErrWrongUsernameOrPassword(err) {
handleFailedPassword(user)
}
- return nil, err
+ return user, err
}
return user, nil
diff --git a/pkg/user/user_create.go b/pkg/user/user_create.go
index 1ccecdaf..213e9cee 100644
--- a/pkg/user/user_create.go
+++ b/pkg/user/user_create.go
@@ -81,7 +81,7 @@ func CreateUser(s *xorm.Session, user *User) (newUser *User, err error) {
}
user.Status = StatusEmailConfirmationRequired
- token, err := generateNewToken(s, user, TokenEmailConfirm)
+ token, err := generateToken(s, user, TokenEmailConfirm)
if err != nil {
return nil, err
}
diff --git a/pkg/user/user_password_reset.go b/pkg/user/user_password_reset.go
index 277d0bb7..0fc3290b 100644
--- a/pkg/user/user_password_reset.go
+++ b/pkg/user/user_password_reset.go
@@ -112,7 +112,7 @@ func RequestUserPasswordResetTokenByEmail(s *xorm.Session, tr *PasswordTokenRequ
// RequestUserPasswordResetToken sends a user a password reset email.
func RequestUserPasswordResetToken(s *xorm.Session, user *User) (err error) {
- token, err := generateNewToken(s, user, TokenPasswordReset)
+ token, err := generateToken(s, user, TokenPasswordReset)
if err != nil {
return
}