From d83fd7d82f2e3904122eb267cef33f775042b13e Mon Sep 17 00:00:00 2001 From: Bruno Michel Date: Wed, 24 Jan 2024 15:01:12 +0100 Subject: [PATCH] Fix last-activity when OAuth clients are deleted The last-activity is guessed from the web sessions and the OAuth clients. But OAuth clients can be revoked/deleted, which can lose the information. For example, if a Cozy instance has only been used with the flagship app, and the flagship app is revoked, the last-activity would be really wrong. We fix that by keeping a date on the instance for the last activity for deleted OAuth clients. --- model/instance/instance.go | 4 ++++ model/oauth/client.go | 24 ++++++++++++++++++++++++ web/instances/instances.go | 3 +++ 3 files changed, 31 insertions(+) diff --git a/model/instance/instance.go b/model/instance/instance.go index 539eabc1cb3..0d65a9af2b3 100644 --- a/model/instance/instance.go +++ b/model/instance/instance.go @@ -108,6 +108,10 @@ type Instance struct { // FeatureSets is a list of feature sets from the manager FeatureSets []string `json:"feature_sets,omitempty"` + // LastActivityFromDeletedOAuthClients is the date of the last activity for + // OAuth clients that have been deleted + LastActivityFromDeletedOAuthClients *time.Time `json:"last_activity_from_deleted_oauth_clients,omitempty"` + vfs vfs.VFS contextualDomain string } diff --git a/model/oauth/client.go b/model/oauth/client.go index 96619bb0414..050d59b6112 100644 --- a/model/oauth/client.go +++ b/model/oauth/client.go @@ -25,6 +25,7 @@ import ( "github.com/cozy/cozy-stack/pkg/couchdb/mango" "github.com/cozy/cozy-stack/pkg/crypto" "github.com/cozy/cozy-stack/pkg/metadata" + "github.com/cozy/cozy-stack/pkg/prefixer" "github.com/cozy/cozy-stack/pkg/registry" jwt "github.com/golang-jwt/jwt/v5" @@ -648,6 +649,29 @@ func (c *Client) Delete(i *instance.Instance) *ClientRegistrationError { Error: "internal_server_error", } } + + var last *time.Time + if at, ok := c.LastRefreshedAt.(string); ok { + if t, err := time.Parse(time.RFC3339Nano, at); err == nil { + last = &t + } + } + if at, ok := c.SynchronizedAt.(string); ok { + if t, err := time.Parse(time.RFC3339Nano, at); err == nil { + if last == nil || last.Before(t) { + last = &t + } + } + } + if last != nil { + if i.LastActivityFromDeletedOAuthClients == nil || i.LastActivityFromDeletedOAuthClients.Before(*last) { + i.LastActivityFromDeletedOAuthClients = last + if err := couchdb.UpdateDoc(prefixer.GlobalPrefixer, i); err != nil { + i.Logger().Warnf("Cannot update last activity for %q: %s", i.Domain, err) + } + } + } + return nil } diff --git a/web/instances/instances.go b/web/instances/instances.go index 3cddb2f52af..a637efaaa0d 100644 --- a/web/instances/instances.go +++ b/web/instances/instances.go @@ -473,6 +473,9 @@ func lastActivity(c echo.Context) error { return jsonapi.NotFound(err) } last := time.Date(2018, time.January, 1, 0, 0, 0, 0, time.UTC) + if inst.LastActivityFromDeletedOAuthClients != nil { + last = *inst.LastActivityFromDeletedOAuthClients + } err = couchdb.ForeachDocs(inst, consts.SessionsLogins, func(_ string, data json.RawMessage) error { var entry session.LoginEntry