package com.vtence.molecule.session; import java.time.Clock; import java.time.Instant; public class CookieSessionStore implements SessionStore { private final SessionIdentifierPolicy identifierPolicy; private final SessionEncoder encoder; private Clock clock = Clock.systemDefaultZone(); private boolean renew; private int idleTimeout; private int timeToLive; public static CookieSessionStore secure(String key, String... oldKeys) { SecureSessionEncoder secureEncoder = new SecureSessionEncoder(key); secureEncoder.acceptAlternateKeys(oldKeys); return new CookieSessionStore(new SecureIdentifierPolicy(), secureEncoder); } public CookieSessionStore(SessionIdentifierPolicy policy, SessionEncoder encoder) { this.identifierPolicy = policy; this.encoder = encoder; } public CookieSessionStore renewIds() { this.renew = true; return this; } public CookieSessionStore idleTimeout(int seconds) { this.idleTimeout = seconds; return this; } public CookieSessionStore timeToLive(int seconds) { this.timeToLive = seconds; return this; } public CookieSessionStore usingClock(Clock clock) { this.clock = clock; return this; } public Session load(String id) throws Exception { Session session = encoder.decode(id); if (session == null || !validate(session)) return null; else return session; } public String save(Session data) throws Exception { String sid = sessionId(data); Session session = makeSession(data, sid); Instant now = now(); session.updatedAt(now); if (!sid.equals(data.id())) { session.createdAt(now); } return encoder.encode(session); } public void destroy(String sid) { // nothing to do, it's stored on the client } private boolean validate(Session session) { if (expired(session) || stale(session) || dead(session)) session.invalidate(); return !session.invalid(); } private boolean expired(Session session) { return session.expires() && session.expired(now()); } private boolean stale(Session session) { return !session.expires() && idleTimeout > 0 && !now().isBefore(staleTime(session)); } private boolean dead(Session session) { return timeToLive > 0 && !now().isBefore(endOfLifeTime(session)); } private Instant staleTime(Session session) { return session.updatedAt().plusSeconds(idleTimeout); } private Instant endOfLifeTime(Session session) { return session.updatedAt().plusSeconds(timeToLive); } private Instant now() { return clock.instant(); } private String sessionId(Session data) { return data.fresh() || renew ? identifierPolicy.generateId(data) : data.id(); } private Session makeSession(Session data, String sid) { Session session = new Session(sid); session.merge(data); session.maxAge(data.maxAge()); session.updatedAt(data.updatedAt()); session.createdAt(data.createdAt()); return session; } }