feat: device list and revoke with the jti followed through refresh
GET /devices lists the caller's confirmed and used device sessions (PHP's
fields, device_name from the stored name or the user agent, is_current
for the session the request's token belongs to). DELETE /devices/{id}
marks the session revoked and blacklists the device token's jti for its
whole refresh window in one transaction. POST /refresh hands a used
session's jwt_jti over to the refreshed token (classes.HandOverDeviceJTI),
so a device that refreshed before the revoke is signed out too.
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
package classes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.golem15.com/golem15/summercms/modules/backpack"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// DeviceShortCodeAlphabet is the alphabet of device short codes (PHP's
|
||||
@@ -126,3 +128,17 @@ func DeviceDisplayName(stored *string, userAgent string) string {
|
||||
}
|
||||
return "Unknown Device"
|
||||
}
|
||||
|
||||
// HandOverDeviceJTI moves a used device session from the jti of a session
|
||||
// token to the jti of the token that refreshed it, and stamps its
|
||||
// last_activity_at, so revoking the device still reaches the token the
|
||||
// device holds now. POST /refresh calls it after a successful refresh;
|
||||
// empty values do nothing.
|
||||
func HandOverDeviceJTI(ctx context.Context, db *gorm.DB, oldJTI, newJTI string) error {
|
||||
if db == nil || oldJTI == "" || newJTI == "" || oldJTI == newJTI {
|
||||
return nil
|
||||
}
|
||||
return db.WithContext(ctx).Exec(`UPDATE golem15_user_device_auth_sessions
|
||||
SET jwt_jti = ?, last_activity_at = NOW(), updated_at = NOW()
|
||||
WHERE jwt_jti = ? AND status = 'used'`, newJTI, oldJTI).Error
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user