3 Commits

Author SHA1 Message Date
gawells 22c4666fa7 update session stores to decide TTLs 2026-06-09 12:31:27 -04:00
gawells e41a81c487 get a cropped square to exist 2026-06-08 21:36:10 -04:00
gawells 600c3abf20 make new photo pop up in box before changing 2026-06-08 21:09:12 -04:00
6 changed files with 118 additions and 40 deletions
+26 -2
View File
@@ -101,6 +101,11 @@
<button id="final_change_password_button">Change Password</button> <button id="final_change_password_button">Change Password</button>
</div> </div>
<div id="resize_photo_dialouge" class="card static_center hidden">
<div id="resize_photo_box"></div>
<img id="new_profile_image" alt="new-profile-image" />
</div>
<img id="logo_image" alt="logo" src="/logo" /> <img id="logo_image" alt="logo" src="/logo" />
<div id="main_content"> <div id="main_content">
<div class="cards"> <div class="cards">
@@ -190,6 +195,25 @@
fileInput.value = ""; fileInput.value = "";
return; return;
} }
document
.getElementById("resize_photo_dialouge")
.classList.remove("hidden");
var image = URL.createObjectURL(file);
const bitmap = await createImageBitmap(file);
var new_profile_image = document.getElementById("new_profile_image");
new_profile_image.src = image;
var resize_photo_box = document.getElementById("resize_photo_box");
resize_photo_box.style.setProperty("--img-width", bitmap.width + "px");
resize_photo_box.style.setProperty(
"--img-height",
bitmap.height + "px",
);
return;
const formData = new FormData(); const formData = new FormData();
formData.append("photo", file); formData.append("photo", file);
formData.append( formData.append(
@@ -211,8 +235,8 @@
URL.revokeObjectURL(currentPreviewURL); URL.revokeObjectURL(currentPreviewURL);
} }
img.src = URL.createObjectURL(file); img.src = image;
currentPreviewURL = img.src; currentPreviewURL = image;
}); });
</script> </script>
+19 -20
View File
@@ -7,7 +7,6 @@ import (
"astraltech.xyz/accountmanager/src/logging" "astraltech.xyz/accountmanager/src/logging"
"astraltech.xyz/accountmanager/src/store" "astraltech.xyz/accountmanager/src/store"
"astraltech.xyz/accountmanager/src/worker"
) )
const SessionCookieName = "session_token" const SessionCookieName = "session_token"
@@ -39,10 +38,10 @@ func (manager *SessionManager) SetStoreType(storeType StoreType, params ...any)
case InMemory: case InMemory:
{ {
manager.store = store.NewMemoryStore[*SessionData]() manager.store = store.NewMemoryStore[*SessionData]()
worker.CreateWorker(time.Minute*5, func() { // worker.CreateWorker(time.Minute*5, func() {
inMemStore, _ := manager.store.(*store.MemoryStore[*SessionData]) // inMemStore, _ := manager.store.(*store.MemoryStore[*SessionData])
cleanupInMemoryStore(inMemStore) // cleanupInMemoryStore(inMemStore)
}) // })
break break
} }
case Redis: case Redis:
@@ -70,7 +69,7 @@ func (manager *SessionManager) CreateSession(userID string) (cookie *http.Cookie
CSRFToken: CSRFToken, CSRFToken: CSRFToken,
ExpiresAt: time.Now().Add(time.Hour), ExpiresAt: time.Now().Add(time.Hour),
} }
err = manager.store.Create(token, &newSessionData) err = manager.store.CreateExpiring(token, &newSessionData, time.Hour)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -110,22 +109,22 @@ func (manager *SessionManager) GetSession(r *http.Request) (*SessionData, error)
return data, nil return data, nil
} }
func cleanupInMemoryStore(m *store.MemoryStore[*SessionData]) { // func cleanupInMemoryStore(m *store.MemoryStore[*SessionData]) {
logging.Debug("Cleaning up memory store sessions") // logging.Debug("Cleaning up memory store sessions")
now := time.Now() // now := time.Now()
m.Lock.Lock() // m.Lock.Lock()
defer m.Lock.Unlock() // defer m.Lock.Unlock()
deleted := 0 // deleted := 0
for id, session := range m.Sessions { // for id, session := range m.Sessions {
if now.After(session.ExpiresAt) { // if now.After(session.ExpiresAt) {
delete(m.Sessions, id) // delete(m.Sessions, id)
deleted = deleted + 1 // deleted = deleted + 1
} // }
} // }
logging.Infof("Cleaned up %d stale sessions", deleted) // logging.Infof("Cleaned up %d stale sessions", deleted)
} // }
func (manager *SessionManager) DeleteSession(sessionId string) error { func (manager *SessionManager) DeleteSession(sessionId string) error {
return manager.store.Delete(sessionId) return manager.store.Delete(sessionId)
+5
View File
@@ -1,9 +1,14 @@
package store package store
import (
"time"
)
// A simple key value store that can either just be single instance in memory or a redis server (for now) // A simple key value store that can either just be single instance in memory or a redis server (for now)
type KeyValueStore[Value any] interface { type KeyValueStore[Value any] interface {
Create(key string, value Value) error Create(key string, value Value) error
CreateExpiring(key string, value Value, ttl time.Duration) error
Get(key string) (Value, error) Get(key string) (Value, error)
Update(key string, session Value) error Update(key string, session Value) error
Delete(key string) error Delete(key string) error
+32 -15
View File
@@ -2,60 +2,77 @@ package store
import ( import (
"sync" "sync"
"time"
"astraltech.xyz/accountmanager/src/logging" "astraltech.xyz/accountmanager/src/logging"
) )
type ValueEntry[Value any] struct {
value Value
expiry time.Time
}
type MemoryStore[Value any] struct { type MemoryStore[Value any] struct {
Sessions map[string]Value Keys map[string]ValueEntry[Value]
Lock sync.RWMutex
Lock sync.RWMutex
} }
func NewMemoryStore[Value any]() *MemoryStore[Value] { func NewMemoryStore[Value any]() *MemoryStore[Value] {
logging.Debug("Creating new in memory session store") logging.Debug("Creating new in memory session store")
store := &MemoryStore[Value]{ store := &MemoryStore[Value]{
Sessions: make(map[string]Value), Keys: make(map[string]ValueEntry[Value]),
} }
return store return store
} }
func (m *MemoryStore[Value]) Create(key string, session Value) (err error) { func (m *MemoryStore[Value]) CreateExpiring(key string, value Value, duration time.Duration) error {
hashedkey := HashKey(key) hashedkey := HashKey(key)
m.Lock.Lock() m.Lock.Lock()
defer m.Lock.Unlock() defer m.Lock.Unlock()
_, exist := m.Sessions[hashedkey] _, exist := m.Keys[hashedkey]
if exist { if exist {
return ErrKeyAlreadyExists return ErrKeyAlreadyExists
} }
m.Sessions[hashedkey] = session m.Keys[hashedkey] = ValueEntry[Value]{
value: value,
expiry: time.Now().Add(duration),
}
return nil return nil
} }
func (m *MemoryStore[Value]) Create(key string, session Value) error {
return m.CreateExpiring(key, session, 0)
}
func (m *MemoryStore[Value]) Get(key string) (Value, error) { func (m *MemoryStore[Value]) Get(key string) (Value, error) {
var data Value var data ValueEntry[Value]
m.Lock.RLock() m.Lock.RLock()
hashedkey := HashKey(key) hashedkey := HashKey(key)
data, exists := m.Sessions[hashedkey] data, exists := m.Keys[hashedkey]
m.Lock.RUnlock() m.Lock.RUnlock()
if exists == false { if exists == false {
return data, ErrKeyNotFound return data.value, ErrKeyNotFound
} }
return data, nil return data.value, nil
} }
func (m *MemoryStore[Value]) Update(sessionID string, session Value) error { func (m *MemoryStore[Value]) Update(sessionID string, value Value) error {
hashedkey := HashKey(sessionID) hashedkey := HashKey(sessionID)
m.Lock.Lock() m.Lock.Lock()
defer m.Lock.Unlock() defer m.Lock.Unlock()
_, exist := m.Sessions[hashedkey] current_key, exist := m.Keys[hashedkey]
if !exist { if !exist {
return ErrKeyNotFound return ErrKeyNotFound
} }
m.Sessions[hashedkey] = session m.Keys[hashedkey] = ValueEntry[Value]{
value: value,
expiry: current_key.expiry,
}
return nil return nil
} }
@@ -64,10 +81,10 @@ func (m *MemoryStore[Value]) Delete(sessionID string) error {
m.Lock.Lock() m.Lock.Lock()
defer m.Lock.Unlock() defer m.Lock.Unlock()
_, exist := m.Sessions[hashedkey] _, exist := m.Keys[hashedkey]
if !exist { if !exist {
return ErrKeyNotFound return ErrKeyNotFound
} }
delete(m.Sessions, hashedkey) delete(m.Keys, hashedkey)
return nil return nil
} }
+5 -3
View File
@@ -43,8 +43,7 @@ func NewRedisStore[Value any](redis_server string, prefix string) *RedisStore[Va
} }
return store return store
} }
func (m *RedisStore[Value]) CreateExpiring(key string, value Value, ttl time.Duration) error {
func (m *RedisStore[Value]) Create(key string, value Value) (err error) {
hashedSession := m.RedisHash(key) hashedSession := m.RedisHash(key)
data, err := json.Marshal(value) data, err := json.Marshal(value)
@@ -52,7 +51,7 @@ func (m *RedisStore[Value]) Create(key string, value Value) (err error) {
return ErrKeyBackend return ErrKeyBackend
} }
created, err := m.client.SetNX(m.ctx, hashedSession, data, time.Hour).Result() created, err := m.client.SetNX(m.ctx, hashedSession, data, ttl).Result()
if err != nil { if err != nil {
logging.Error(err.Error()) logging.Error(err.Error())
return ErrKeyBackend return ErrKeyBackend
@@ -63,6 +62,9 @@ func (m *RedisStore[Value]) Create(key string, value Value) (err error) {
} }
return nil return nil
} }
func (m *RedisStore[Value]) Create(key string, value Value) error {
return m.CreateExpiring(key, value, 0)
}
func (m *RedisStore[Value]) Get(sessionID string) (Value, error) { func (m *RedisStore[Value]) Get(sessionID string) (Value, error) {
hashed := m.RedisHash(sessionID) hashed := m.RedisHash(sessionID)
var session_data Value var session_data Value
+31
View File
@@ -116,6 +116,10 @@
position: fixed; position: fixed;
} }
#resize_photo_dialouge {
z-index: 10000;
}
#change_password_dialogue input { #change_password_dialogue input {
width: 350px; width: 350px;
} }
@@ -149,3 +153,30 @@
border-style: solid; border-style: solid;
color: var(--text-main); color: var(--text-main);
} }
#resize_photo_box {
background-color: black;
position: absolute;
opacity: 40%;
width: var(--img-width);
height: var(--img-height);
--percent: 0.5;
--smalled-dim: min(var(--img-width), var(--img-height));
--smaller-pixel: calc((0.5 - (var(--percent)) / 2) * var(--smalled-dim));
--larger-pixel: calc((0.5 + (var(--percent)) / 2) * var(--smalled-dim));
clip-path: polygon(
0% 0%,
0% 100%,
var(--smaller-pixel) 100%,
var(--smaller-pixel) var(--smaller-pixel),
var(--larger-pixel) var(--smaller-pixel),
var(--larger-pixel) var(--larger-pixel),
var(--smaller-pixel) var(--larger-pixel),
var(--smaller-pixel) 100%,
100% 100%,
100% 0%
);
}