Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[server] Encrich admin api response #4148

Merged
merged 3 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions server/cmd/museum/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,7 @@ func main() {
QueueRepo: queueRepo,
UserRepo: userRepo,
CollectionRepo: collectionRepo,
AuthenticatorRepo: authRepo,
UserAuthRepo: userAuthRepo,
UserController: userController,
FamilyController: familyController,
Expand Down
8 changes: 8 additions & 0 deletions server/ente/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ type LogoutSessionReq struct {
UserID int64 `json:"userID" binding:"required"`
}

type TokenInfo struct {
CreationTime int64 `json:"creationTime"`
LastUsedTime int64 `json:"lastUsedTime"`
UA string `json:"ua"`
IsDeleted bool `json:"isDeleted"`
App App `json:"app"`
}

func (a AdminOttReq) Validate() error {
if !a.App.IsValid() {
return errors.New("invalid app")
Expand Down
7 changes: 4 additions & 3 deletions server/ente/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,10 @@ type TwoFactorRemovalRequest struct {

type ProfileData struct {
// CanDisableEmailMFA is used to decide if client should show disable email MFA option
CanDisableEmailMFA bool `json:"canDisableEmailMFA"`
IsEmailMFAEnabled bool `json:"isEmailMFAEnabled"`
IsTwoFactorEnabled bool `json:"isTwoFactorEnabled"`
CanDisableEmailMFA bool `json:"canDisableEmailMFA"`
IsEmailMFAEnabled bool `json:"isEmailMFAEnabled"`
IsTwoFactorEnabled bool `json:"isTwoFactorEnabled"`
PasskeyCount int64 `json:"passkeyCount"`
}

type Session struct {
Expand Down
12 changes: 11 additions & 1 deletion server/pkg/api/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"github.com/ente-io/museum/pkg/controller/remotestore"
"github.com/ente-io/museum/pkg/repo/authenticator"
"net/http"
"strconv"
"strings"
Expand Down Expand Up @@ -39,6 +40,7 @@ type AdminHandler struct {
QueueRepo *repo.QueueRepository
UserRepo *repo.UserRepository
CollectionRepo *repo.CollectionRepository
AuthenticatorRepo *authenticator.Repository
UserAuthRepo *repo.UserAuthRepository
FileRepo *repo.FileRepository
BillingRepo *repo.BillingRepository
Expand Down Expand Up @@ -113,7 +115,7 @@ func (h *AdminHandler) GetUsers(c *gin.Context) {
}

func (h *AdminHandler) GetUser(c *gin.Context) {
e := c.Query("email")
e := strings.ToLower(strings.TrimSpace(c.Query("email")))
if e == "" {
id, err := strconv.ParseInt(c.Query("id"), 10, 64)
if err != nil {
Expand Down Expand Up @@ -571,6 +573,14 @@ func (h *AdminHandler) attachSubscription(ctx *gin.Context, userID int64, respon
if err == nil {
response["details"] = details
}
tokenInfos, err := h.UserAuthRepo.GetUserTokenInfo(userID)
if err == nil {
response["tokens"] = tokenInfos
}
authEntryCount, err := h.AuthenticatorRepo.GetAuthCodeCount(ctx, userID)
if err == nil {
response["authCodes"] = authEntryCount
}
}

func (h *AdminHandler) ClearOrphanObjects(c *gin.Context) {
Expand Down
10 changes: 8 additions & 2 deletions server/pkg/controller/user/user_details.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"github.com/ente-io/museum/ente"
"github.com/ente-io/museum/ente/details"
bonus "github.com/ente-io/museum/ente/storagebonus"
"github.com/ente-io/museum/pkg/utils/recover"
"github.com/ente-io/museum/pkg/utils/time"
"github.com/ente-io/stacktrace"
"github.com/gin-gonic/gin"
Expand All @@ -27,6 +26,7 @@ func (c *UserController) GetDetailsV2(ctx *gin.Context, userID int64, fetchMemor
var familyData *ente.FamilyMemberResponse
var subscription *ente.Subscription
var canDisableEmailMFA bool
var passkeyCount int64
var fileCount, sharedCollectionCount, usage int64
var bonus *bonus.ActiveStorageBonus
g.Go(func() error {
Expand Down Expand Up @@ -69,7 +69,12 @@ func (c *UserController) GetDetailsV2(ctx *gin.Context, userID int64, fetchMemor
return nil
})
g.Go(func() error {
return recover.Int64ToInt64RecoverWrapper(userID, c.FileRepo.GetUsage, &usage)
cnt, err := c.PasskeyRepo.GetPasskeyCount(userID)
if err != nil {
return stacktrace.Propagate(err, "")
}
passkeyCount = cnt
return nil
})

if fetchMemoryCount {
Expand Down Expand Up @@ -111,6 +116,7 @@ func (c *UserController) GetDetailsV2(ctx *gin.Context, userID int64, fetchMemor
CanDisableEmailMFA: canDisableEmailMFA,
IsEmailMFAEnabled: *user.IsEmailMFAEnabled,
IsTwoFactorEnabled: *user.IsTwoFactorEnabled,
PasskeyCount: passkeyCount,
},
BonusData: bonus,
}
Expand Down
10 changes: 10 additions & 0 deletions server/pkg/repo/authenticator/entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,16 @@ func (r *Repository) Update(ctx context.Context, userID int64, req model.UpdateE
return nil
}

// GetAuthCodeCount returns the count of the authenticator entries for the given user
func (r *Repository) GetAuthCodeCount(ctx context.Context, userID int64) (int64, error) {
var count int64
err := r.DB.QueryRowContext(ctx, `SELECT count(*) FROM authenticator_entity WHERE user_id = $1 and is_deleted = FALSE`, userID).Scan(&count)
if err != nil {
return 0, stacktrace.Propagate(err, "failed to get auth code count")
}
return count, nil
}

// GetDiff returns the &{[]ente.TotpEntity} which have been added or
// modified after the given sinceTime
func (r *Repository) GetDiff(ctx context.Context, userID int64, sinceTime int64, limit int16) ([]model.Entity, error) {
Expand Down
5 changes: 5 additions & 0 deletions server/pkg/repo/passkey/passkey.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ func NewRepository(
return
}

func (r *Repository) GetPasskeyCount(userID int64) (count int64, err error) {
err = r.DB.QueryRow(`SELECT COUNT(*) FROM passkeys WHERE user_id = $1 AND deleted_at IS NULL`, userID).Scan(&count)
return
}

func (r *Repository) GetUserPasskeys(userID int64) (passkeys []ente.Passkey, err error) {
rows, err := r.DB.Query(`
SELECT id, user_id, friendly_name, created_at
Expand Down
18 changes: 18 additions & 0 deletions server/pkg/repo/userauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,24 @@ func (repo *UserAuthRepository) GetTokenCreationTime(token string) (int64, error
return result, nil
}

func (repo *UserAuthRepository) GetUserTokenInfo(userID int64) ([]ente.TokenInfo, error) {
rows, err := repo.DB.Query(`SELECT creation_time, last_used_at, user_agent, is_deleted, app FROM tokens WHERE user_id = $1 AND is_deleted = false`, userID)
if err != nil {
return nil, stacktrace.Propagate(err, "")
}
defer rows.Close()
tokenInfos := make([]ente.TokenInfo, 0)
for rows.Next() {
var tokenInfo ente.TokenInfo
err := rows.Scan(&tokenInfo.CreationTime, &tokenInfo.LastUsedTime, &tokenInfo.UA, &tokenInfo.IsDeleted, &tokenInfo.App)
if err != nil {
return nil, stacktrace.Propagate(err, "")
}
tokenInfos = append(tokenInfos, tokenInfo)
}
return tokenInfos, nil
}

// GetValidOTTs returns the list of OTTs that haven't expired for a given user
func (repo *UserAuthRepository) GetValidOTTs(emailHash string, app ente.App) ([]string, error) {
rows, err := repo.DB.Query(`SELECT ott FROM otts WHERE email_hash = $1 AND app = $2 AND expiration_time > $3`,
Expand Down
Loading