forked from teamhanko/hanko
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Server side sessions (teamhanko#1673)
* feat: add server side sessions * feat: add lastUsed & admin endpoint * feat: add session list to elements * fix: fix public session endpoint * chore: only store session info when enabled * build: update go mod * feat: add translations * test: fix tests * feat: change path * feat: return userID on session validation endpoint * feat: move all session endpoints to public router * fix: add missing translation * fix: add missing structs * chore: align session persister with other persisters * fix: use correct translation label * chore: add db validator to session model * feat: create server side session from cmd * fix: fix review findings
- Loading branch information
1 parent
6c85c11
commit b401e57
Showing
52 changed files
with
946 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package dto | ||
|
||
import ( | ||
"fmt" | ||
"github.com/gofrs/uuid" | ||
"github.com/mileusna/useragent" | ||
"github.com/teamhanko/hanko/backend/persistence/models" | ||
"time" | ||
) | ||
|
||
type SessionData struct { | ||
ID uuid.UUID `json:"id"` | ||
UserAgentRaw string `json:"user_agent_raw"` | ||
UserAgent string `json:"user_agent"` | ||
IpAddress string `json:"ip_address"` | ||
Current bool `json:"current"` | ||
CreatedAt time.Time `json:"created_at"` | ||
ExpiresAt *time.Time `json:"expires_at,omitempty"` | ||
LastUsed time.Time `json:"last_used"` | ||
} | ||
|
||
func FromSessionModel(model models.Session, current bool) SessionData { | ||
ua := useragent.Parse(model.UserAgent) | ||
return SessionData{ | ||
ID: model.ID, | ||
UserAgentRaw: model.UserAgent, | ||
UserAgent: fmt.Sprintf("%s (%s)", ua.OS, ua.Name), | ||
IpAddress: model.IpAddress, | ||
Current: current, | ||
CreatedAt: model.CreatedAt, | ||
ExpiresAt: model.ExpiresAt, | ||
LastUsed: model.LastUsed, | ||
} | ||
} | ||
|
||
type ValidateSessionResponse struct { | ||
IsValid bool `json:"is_valid"` | ||
ExpirationTime *time.Time `json:"expiration_time,omitempty"` | ||
UserID *uuid.UUID `json:"user_id,omitempty"` | ||
} | ||
|
||
type ValidateSessionRequest struct { | ||
SessionToken string `json:"session_token" validate:"required"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package profile | ||
|
||
import ( | ||
"fmt" | ||
"github.com/gofrs/uuid" | ||
"github.com/teamhanko/hanko/backend/flow_api/flow/shared" | ||
"github.com/teamhanko/hanko/backend/flowpilot" | ||
"github.com/teamhanko/hanko/backend/persistence/models" | ||
) | ||
|
||
type SessionDelete struct { | ||
shared.Action | ||
} | ||
|
||
func (a SessionDelete) GetName() flowpilot.ActionName { | ||
return shared.ActionSessionDelete | ||
} | ||
|
||
func (a SessionDelete) GetDescription() string { | ||
return "Delete a session." | ||
} | ||
|
||
func (a SessionDelete) Initialize(c flowpilot.InitializationContext) { | ||
deps := a.GetDeps(c) | ||
if !deps.Cfg.Session.ServerSide.Enabled { | ||
c.SuspendAction() | ||
} | ||
userModel, ok := c.Get("session_user").(*models.User) | ||
if !ok { | ||
c.SuspendAction() | ||
return | ||
} | ||
|
||
input := flowpilot.StringInput("session_id").Required(true).Hidden(true) | ||
|
||
currentSessionID := uuid.FromStringOrNil(c.Get("session_id").(string)) | ||
sessions, err := deps.Persister.GetSessionPersisterWithConnection(deps.Tx).ListActive(userModel.ID) | ||
if err != nil { | ||
c.SuspendAction() | ||
return | ||
} | ||
|
||
for _, session := range sessions { | ||
if session.ID != currentSessionID { | ||
input.AllowedValue(session.ID.String(), session.ID.String()) | ||
} | ||
} | ||
|
||
c.AddInputs(input) | ||
} | ||
|
||
func (a SessionDelete) Execute(c flowpilot.ExecutionContext) error { | ||
deps := a.GetDeps(c) | ||
|
||
sessionToBeDeleted := uuid.FromStringOrNil(c.Input().Get("session_id").String()) | ||
|
||
session, err := deps.Persister.GetSessionPersisterWithConnection(deps.Tx).Get(sessionToBeDeleted) | ||
if err != nil { | ||
return fmt.Errorf("failed to get session from db: %w", err) | ||
} | ||
|
||
if session != nil { | ||
err = deps.Persister.GetSessionPersisterWithConnection(deps.Tx).Delete(*session) | ||
} | ||
|
||
return c.Continue(shared.StateProfileInit) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package profile | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"github.com/gofrs/uuid" | ||
"github.com/teamhanko/hanko/backend/dto" | ||
"github.com/teamhanko/hanko/backend/flow_api/flow/shared" | ||
"github.com/teamhanko/hanko/backend/flowpilot" | ||
"github.com/teamhanko/hanko/backend/persistence/models" | ||
) | ||
|
||
type GetSessions struct { | ||
shared.Action | ||
} | ||
|
||
func (h GetSessions) Execute(c flowpilot.HookExecutionContext) error { | ||
deps := h.GetDeps(c) | ||
|
||
if !deps.Cfg.Session.ServerSide.Enabled { | ||
return nil | ||
} | ||
|
||
userModel, ok := c.Get("session_user").(*models.User) | ||
if !ok { | ||
return errors.New("no valid session") | ||
} | ||
|
||
activeSessions, err := deps.Persister.GetSessionPersisterWithConnection(deps.Tx).ListActive(userModel.ID) | ||
if err != nil { | ||
return fmt.Errorf("failed to get sessions from db: %w", err) | ||
} | ||
|
||
currentSessionID := uuid.FromStringOrNil(c.Get("session_id").(string)) | ||
|
||
sessionsDto := make([]dto.SessionData, len(activeSessions)) | ||
for i := range activeSessions { | ||
sessionsDto[i] = dto.FromSessionModel(activeSessions[i], activeSessions[i].ID == currentSessionID) | ||
} | ||
|
||
err = c.Payload().Set("sessions", sessionsDto) | ||
if err != nil { | ||
return fmt.Errorf("failed to set sessions payload: %w", err) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.