mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-03-22 16:45:08 +00:00
fix: one-time-access-token route should get user ID from URL only (#1358)
This commit is contained in:
committed by
GitHub
parent
e0fc4cc01b
commit
27ca713cd4
@@ -139,6 +139,20 @@ func (e *TooManyRequestsError) Error() string {
|
|||||||
}
|
}
|
||||||
func (e *TooManyRequestsError) HttpStatusCode() int { return http.StatusTooManyRequests }
|
func (e *TooManyRequestsError) HttpStatusCode() int { return http.StatusTooManyRequests }
|
||||||
|
|
||||||
|
type UserIdNotProvidedError struct{}
|
||||||
|
|
||||||
|
func (e *UserIdNotProvidedError) Error() string {
|
||||||
|
return "User id not provided"
|
||||||
|
}
|
||||||
|
func (e *UserIdNotProvidedError) HttpStatusCode() int { return http.StatusBadRequest }
|
||||||
|
|
||||||
|
type UserNotFoundError struct{}
|
||||||
|
|
||||||
|
func (e *UserNotFoundError) Error() string {
|
||||||
|
return "User not found"
|
||||||
|
}
|
||||||
|
func (e *UserNotFoundError) HttpStatusCode() int { return http.StatusNotFound }
|
||||||
|
|
||||||
type ClientIdOrSecretNotProvidedError struct{}
|
type ClientIdOrSecretNotProvidedError struct{}
|
||||||
|
|
||||||
func (e *ClientIdOrSecretNotProvidedError) Error() string {
|
func (e *ClientIdOrSecretNotProvidedError) Error() string {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/pocket-id/pocket-id/backend/internal/common"
|
||||||
"github.com/pocket-id/pocket-id/backend/internal/utils/cookie"
|
"github.com/pocket-id/pocket-id/backend/internal/utils/cookie"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -322,22 +323,34 @@ func (uc *UserController) updateCurrentUserProfilePictureHandler(c *gin.Context)
|
|||||||
|
|
||||||
func (uc *UserController) createOneTimeAccessTokenHandler(c *gin.Context, own bool) {
|
func (uc *UserController) createOneTimeAccessTokenHandler(c *gin.Context, own bool) {
|
||||||
var input dto.OneTimeAccessTokenCreateDto
|
var input dto.OneTimeAccessTokenCreateDto
|
||||||
if err := c.ShouldBindJSON(&input); err != nil {
|
err := c.ShouldBindJSON(&input)
|
||||||
|
if err != nil {
|
||||||
_ = c.Error(err)
|
_ = c.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var ttl time.Duration
|
var (
|
||||||
|
userID string
|
||||||
|
ttl time.Duration
|
||||||
|
)
|
||||||
if own {
|
if own {
|
||||||
input.UserID = c.GetString("userID")
|
// Get user ID from context and force the default TTL
|
||||||
|
userID = c.GetString("userID")
|
||||||
ttl = defaultOneTimeAccessTokenDuration
|
ttl = defaultOneTimeAccessTokenDuration
|
||||||
} else {
|
} else {
|
||||||
|
// Get user ID from URL parameter, and optional TTL from body
|
||||||
|
userID = c.Param("id")
|
||||||
ttl = input.TTL.Duration
|
ttl = input.TTL.Duration
|
||||||
if ttl <= 0 {
|
if ttl <= 0 {
|
||||||
ttl = defaultOneTimeAccessTokenDuration
|
ttl = defaultOneTimeAccessTokenDuration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
token, err := uc.oneTimeAccessService.CreateOneTimeAccessToken(c.Request.Context(), input.UserID, ttl)
|
if userID == "" {
|
||||||
|
_ = c.Error(&common.UserIdNotProvidedError{})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := uc.oneTimeAccessService.CreateOneTimeAccessToken(c.Request.Context(), userID, ttl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = c.Error(err)
|
_ = c.Error(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ package dto
|
|||||||
import "github.com/pocket-id/pocket-id/backend/internal/utils"
|
import "github.com/pocket-id/pocket-id/backend/internal/utils"
|
||||||
|
|
||||||
type OneTimeAccessTokenCreateDto struct {
|
type OneTimeAccessTokenCreateDto struct {
|
||||||
UserID string `json:"userId"`
|
TTL utils.JSONDuration `json:"ttl" binding:"ttl"`
|
||||||
TTL utils.JSONDuration `json:"ttl" binding:"ttl"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type OneTimeAccessEmailAsUnauthenticatedUserDto struct {
|
type OneTimeAccessEmailAsUnauthenticatedUserDto struct {
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ func (s *OneTimeAccessService) requestOneTimeAccessEmailInternal(ctx context.Con
|
|||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
user, err := s.userService.GetUser(ctx, userID)
|
user, err := s.userService.getUserInternal(ctx, userID, tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -131,8 +131,32 @@ func (s *OneTimeAccessService) requestOneTimeAccessEmailInternal(ctx context.Con
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *OneTimeAccessService) CreateOneTimeAccessToken(ctx context.Context, userID string, ttl time.Duration) (token string, err error) {
|
func (s *OneTimeAccessService) CreateOneTimeAccessToken(ctx context.Context, userID string, ttl time.Duration) (token string, err error) {
|
||||||
token, _, err = s.createOneTimeAccessTokenInternal(ctx, userID, ttl, false, s.db)
|
tx := s.db.Begin()
|
||||||
return token, err
|
defer func() {
|
||||||
|
tx.Rollback()
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Load the user to ensure it exists
|
||||||
|
_, err = s.userService.getUserInternal(ctx, userID, tx)
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return "", &common.UserNotFoundError{}
|
||||||
|
} else if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the one-time access token
|
||||||
|
token, _, err = s.createOneTimeAccessTokenInternal(ctx, userID, ttl, false, tx)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commit
|
||||||
|
err = tx.Commit().Error
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return token, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *OneTimeAccessService) createOneTimeAccessTokenInternal(ctx context.Context, userID string, ttl time.Duration, withDeviceToken bool, tx *gorm.DB) (token string, deviceToken *string, err error) {
|
func (s *OneTimeAccessService) createOneTimeAccessTokenInternal(ctx context.Context, userID string, ttl time.Duration, withDeviceToken bool, tx *gorm.DB) (token string, deviceToken *string, err error) {
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ export default class UserService extends APIService {
|
|||||||
};
|
};
|
||||||
|
|
||||||
createOneTimeAccessToken = async (userId: string = 'me', ttl?: string | number) => {
|
createOneTimeAccessToken = async (userId: string = 'me', ttl?: string | number) => {
|
||||||
const res = await this.api.post(`/users/${userId}/one-time-access-token`, { userId, ttl });
|
const res = await this.api.post(`/users/${userId}/one-time-access-token`, { ttl });
|
||||||
return res.data.token;
|
return res.data.token;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user