@@ -51,6 +51,7 @@ const (
51
51
CacheExpirationMax = 7 * 24 * 3600 * time .Second // 7 days
52
52
CacheExpirationMin = 3 * 24 * 3600 * time .Second // 3 days
53
53
DefaultPeerLoginExpiration = 24 * time .Hour
54
+ DefaultPeerInactivityExpiration = 10 * time .Minute
54
55
emptyUserID = "empty user ID in claims"
55
56
errorGettingDomainAccIDFmt = "error getting account ID by private domain: %v"
56
57
)
@@ -181,6 +182,8 @@ type DefaultAccountManager struct {
181
182
dnsDomain string
182
183
peerLoginExpiry Scheduler
183
184
185
+ peerInactivityExpiry Scheduler
186
+
184
187
// userDeleteFromIDPEnabled allows to delete user from IDP when user is deleted from account
185
188
userDeleteFromIDPEnabled bool
186
189
@@ -198,6 +201,13 @@ type Settings struct {
198
201
// Applies to all peers that have Peer.LoginExpirationEnabled set to true.
199
202
PeerLoginExpiration time.Duration
200
203
204
+ // PeerInactivityExpirationEnabled globally enables or disables peer inactivity expiration
205
+ PeerInactivityExpirationEnabled bool
206
+
207
+ // PeerInactivityExpiration is a setting that indicates when peer inactivity expires.
208
+ // Applies to all peers that have Peer.PeerInactivityExpirationEnabled set to true.
209
+ PeerInactivityExpiration time.Duration
210
+
201
211
// RegularUsersViewBlocked allows to block regular users from viewing even their own peers and some UI elements
202
212
RegularUsersViewBlocked bool
203
213
@@ -228,6 +238,9 @@ func (s *Settings) Copy() *Settings {
228
238
GroupsPropagationEnabled : s .GroupsPropagationEnabled ,
229
239
JWTAllowGroups : s .JWTAllowGroups ,
230
240
RegularUsersViewBlocked : s .RegularUsersViewBlocked ,
241
+
242
+ PeerInactivityExpirationEnabled : s .PeerInactivityExpirationEnabled ,
243
+ PeerInactivityExpiration : s .PeerInactivityExpiration ,
231
244
}
232
245
if s .Extra != nil {
233
246
settings .Extra = s .Extra .Copy ()
@@ -609,6 +622,60 @@ func (a *Account) GetPeersWithExpiration() []*nbpeer.Peer {
609
622
return peers
610
623
}
611
624
625
+ // GetInactivePeers returns peers that have been expired by inactivity
626
+ func (a * Account ) GetInactivePeers () []* nbpeer.Peer {
627
+ var peers []* nbpeer.Peer
628
+ for _ , inactivePeer := range a .GetPeersWithInactivity () {
629
+ inactive , _ := inactivePeer .SessionExpired (a .Settings .PeerInactivityExpiration )
630
+ if inactive {
631
+ peers = append (peers , inactivePeer )
632
+ }
633
+ }
634
+ return peers
635
+ }
636
+
637
+ // GetNextInactivePeerExpiration returns the minimum duration in which the next peer of the account will expire if it was found.
638
+ // If there is no peer that expires this function returns false and a duration of 0.
639
+ // This function only considers peers that haven't been expired yet and that are not connected.
640
+ func (a * Account ) GetNextInactivePeerExpiration () (time.Duration , bool ) {
641
+ peersWithExpiry := a .GetPeersWithInactivity ()
642
+ if len (peersWithExpiry ) == 0 {
643
+ return 0 , false
644
+ }
645
+ var nextExpiry * time.Duration
646
+ for _ , peer := range peersWithExpiry {
647
+ if peer .Status .LoginExpired || peer .Status .Connected {
648
+ continue
649
+ }
650
+ _ , duration := peer .SessionExpired (a .Settings .PeerInactivityExpiration )
651
+ if nextExpiry == nil || duration < * nextExpiry {
652
+ // if expiration is below 1s return 1s duration
653
+ // this avoids issues with ticker that can't be set to < 0
654
+ if duration < time .Second {
655
+ return time .Second , true
656
+ }
657
+ nextExpiry = & duration
658
+ }
659
+ }
660
+
661
+ if nextExpiry == nil {
662
+ return 0 , false
663
+ }
664
+
665
+ return * nextExpiry , true
666
+ }
667
+
668
+ // GetPeersWithInactivity eturns a list of peers that have Peer.InactivityExpirationEnabled set to true and that were added by a user
669
+ func (a * Account ) GetPeersWithInactivity () []* nbpeer.Peer {
670
+ peers := make ([]* nbpeer.Peer , 0 )
671
+ for _ , peer := range a .Peers {
672
+ if peer .InactivityExpirationEnabled && peer .AddedWithSSOLogin () {
673
+ peers = append (peers , peer )
674
+ }
675
+ }
676
+ return peers
677
+ }
678
+
612
679
// GetPeers returns a list of all Account peers
613
680
func (a * Account ) GetPeers () []* nbpeer.Peer {
614
681
var peers []* nbpeer.Peer
@@ -975,6 +1042,7 @@ func BuildManager(
975
1042
dnsDomain : dnsDomain ,
976
1043
eventStore : eventStore ,
977
1044
peerLoginExpiry : NewDefaultScheduler (),
1045
+ peerInactivityExpiry : NewDefaultScheduler (),
978
1046
userDeleteFromIDPEnabled : userDeleteFromIDPEnabled ,
979
1047
integratedPeerValidator : integratedPeerValidator ,
980
1048
metrics : metrics ,
@@ -1103,6 +1171,11 @@ func (am *DefaultAccountManager) UpdateAccountSettings(ctx context.Context, acco
1103
1171
am .checkAndSchedulePeerLoginExpiration (ctx , account )
1104
1172
}
1105
1173
1174
+ err = am .handleInactivityExpirationSettings (ctx , account , oldSettings , newSettings , userID , accountID )
1175
+ if err != nil {
1176
+ return nil , err
1177
+ }
1178
+
1106
1179
updatedAccount := account .UpdateSettings (newSettings )
1107
1180
1108
1181
err = am .Store .SaveAccount (ctx , account )
@@ -1113,6 +1186,26 @@ func (am *DefaultAccountManager) UpdateAccountSettings(ctx context.Context, acco
1113
1186
return updatedAccount , nil
1114
1187
}
1115
1188
1189
+ func (am * DefaultAccountManager ) handleInactivityExpirationSettings (ctx context.Context , account * Account , oldSettings , newSettings * Settings , userID , accountID string ) error {
1190
+ if oldSettings .PeerInactivityExpirationEnabled != newSettings .PeerInactivityExpirationEnabled {
1191
+ event := activity .AccountPeerInactivityExpirationEnabled
1192
+ if ! newSettings .PeerInactivityExpirationEnabled {
1193
+ event = activity .AccountPeerInactivityExpirationDisabled
1194
+ am .peerInactivityExpiry .Cancel (ctx , []string {accountID })
1195
+ } else {
1196
+ am .checkAndSchedulePeerInactivityExpiration (ctx , account )
1197
+ }
1198
+ am .StoreEvent (ctx , userID , accountID , accountID , event , nil )
1199
+ }
1200
+
1201
+ if oldSettings .PeerInactivityExpiration != newSettings .PeerInactivityExpiration {
1202
+ am .StoreEvent (ctx , userID , accountID , accountID , activity .AccountPeerInactivityExpirationDurationUpdated , nil )
1203
+ am .checkAndSchedulePeerInactivityExpiration (ctx , account )
1204
+ }
1205
+
1206
+ return nil
1207
+ }
1208
+
1116
1209
func (am * DefaultAccountManager ) peerLoginExpirationJob (ctx context.Context , accountID string ) func () (time.Duration , bool ) {
1117
1210
return func () (time.Duration , bool ) {
1118
1211
unlock := am .Store .AcquireWriteLockByUID (ctx , accountID )
@@ -1148,6 +1241,43 @@ func (am *DefaultAccountManager) checkAndSchedulePeerLoginExpiration(ctx context
1148
1241
}
1149
1242
}
1150
1243
1244
+ // peerInactivityExpirationJob marks login expired for all inactive peers and returns the minimum duration in which the next peer of the account will expire by inactivity if found
1245
+ func (am * DefaultAccountManager ) peerInactivityExpirationJob (ctx context.Context , accountID string ) func () (time.Duration , bool ) {
1246
+ return func () (time.Duration , bool ) {
1247
+ unlock := am .Store .AcquireWriteLockByUID (ctx , accountID )
1248
+ defer unlock ()
1249
+
1250
+ account , err := am .Store .GetAccount (ctx , accountID )
1251
+ if err != nil {
1252
+ log .Errorf ("failed getting account %s expiring peers" , account .Id )
1253
+ return account .GetNextInactivePeerExpiration ()
1254
+ }
1255
+
1256
+ expiredPeers := account .GetInactivePeers ()
1257
+ var peerIDs []string
1258
+ for _ , peer := range expiredPeers {
1259
+ peerIDs = append (peerIDs , peer .ID )
1260
+ }
1261
+
1262
+ log .Debugf ("discovered %d peers to expire for account %s" , len (peerIDs ), account .Id )
1263
+
1264
+ if err := am .expireAndUpdatePeers (ctx , account , expiredPeers ); err != nil {
1265
+ log .Errorf ("failed updating account peers while expiring peers for account %s" , account .Id )
1266
+ return account .GetNextInactivePeerExpiration ()
1267
+ }
1268
+
1269
+ return account .GetNextInactivePeerExpiration ()
1270
+ }
1271
+ }
1272
+
1273
+ // checkAndSchedulePeerInactivityExpiration periodically checks for inactive peers to end their sessions
1274
+ func (am * DefaultAccountManager ) checkAndSchedulePeerInactivityExpiration (ctx context.Context , account * Account ) {
1275
+ am .peerInactivityExpiry .Cancel (ctx , []string {account .Id })
1276
+ if nextRun , ok := account .GetNextInactivePeerExpiration (); ok {
1277
+ go am .peerInactivityExpiry .Schedule (ctx , nextRun , account .Id , am .peerInactivityExpirationJob (ctx , account .Id ))
1278
+ }
1279
+ }
1280
+
1151
1281
// newAccount creates a new Account with a generated ID and generated default setup keys.
1152
1282
// If ID is already in use (due to collision) we try one more time before returning error
1153
1283
func (am * DefaultAccountManager ) newAccount (ctx context.Context , userID , domain string ) (* Account , error ) {
@@ -2412,6 +2542,9 @@ func newAccountWithId(ctx context.Context, accountID, userID, domain string) *Ac
2412
2542
PeerLoginExpiration : DefaultPeerLoginExpiration ,
2413
2543
GroupsPropagationEnabled : true ,
2414
2544
RegularUsersViewBlocked : true ,
2545
+
2546
+ PeerInactivityExpirationEnabled : false ,
2547
+ PeerInactivityExpiration : DefaultPeerInactivityExpiration ,
2415
2548
},
2416
2549
}
2417
2550
0 commit comments