2020-06-25 01:20:58 +02:00
|
|
|
package session
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"io/ioutil"
|
|
|
|
"path"
|
2020-06-29 11:10:24 +02:00
|
|
|
"sync"
|
2020-06-25 01:20:58 +02:00
|
|
|
"time"
|
|
|
|
|
|
|
|
gc "github.com/patrickmn/go-cache"
|
|
|
|
"github.com/photoprism/photoprism/internal/entity"
|
|
|
|
)
|
|
|
|
|
2021-04-30 10:07:20 +02:00
|
|
|
const cacheFileName = "sessions.json"
|
|
|
|
|
2020-06-29 11:10:24 +02:00
|
|
|
var fileMutex sync.RWMutex
|
|
|
|
|
2020-06-25 01:20:58 +02:00
|
|
|
// New returns a new session store with an optional cachePath.
|
|
|
|
func New(expiration time.Duration, cachePath string) *Session {
|
|
|
|
s := &Session{}
|
|
|
|
|
|
|
|
cleanupInterval := 15 * time.Minute
|
|
|
|
|
|
|
|
if cachePath != "" {
|
2020-06-29 11:10:24 +02:00
|
|
|
fileMutex.RLock()
|
|
|
|
defer fileMutex.RUnlock()
|
|
|
|
|
2020-06-25 01:20:58 +02:00
|
|
|
var savedItems map[string]Saved
|
|
|
|
|
|
|
|
items := make(map[string]gc.Item)
|
2021-04-30 10:07:20 +02:00
|
|
|
s.cacheFile = path.Join(cachePath, cacheFileName)
|
2020-06-25 01:20:58 +02:00
|
|
|
|
|
|
|
if cached, err := ioutil.ReadFile(s.cacheFile); err != nil {
|
2021-04-30 10:07:20 +02:00
|
|
|
log.Debugf("session: %s", err)
|
2020-06-25 01:20:58 +02:00
|
|
|
} else if err := json.Unmarshal(cached, &savedItems); err != nil {
|
|
|
|
log.Errorf("session: %s", err)
|
|
|
|
} else {
|
|
|
|
for key, saved := range savedItems {
|
2020-10-03 13:50:30 +02:00
|
|
|
user := entity.FindUserByUID(saved.User)
|
2020-06-25 01:20:58 +02:00
|
|
|
|
|
|
|
if user == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
var tokens []string
|
|
|
|
var shared []string
|
|
|
|
|
|
|
|
for _, token := range saved.Tokens {
|
2020-06-26 12:16:13 +02:00
|
|
|
links := entity.FindValidLinks(token, "")
|
2020-06-25 01:20:58 +02:00
|
|
|
|
|
|
|
if len(links) > 0 {
|
|
|
|
for _, link := range links {
|
|
|
|
shared = append(shared, link.LinkUID)
|
|
|
|
}
|
2020-06-26 12:16:13 +02:00
|
|
|
|
2020-06-25 01:20:58 +02:00
|
|
|
tokens = append(tokens, token)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-25 14:54:04 +02:00
|
|
|
data := Data{User: *user, Tokens: tokens, Shares: shared}
|
2020-06-25 01:20:58 +02:00
|
|
|
items[key] = gc.Item{Expiration: saved.Expiration, Object: data}
|
|
|
|
}
|
|
|
|
|
|
|
|
s.cache = gc.NewFrom(expiration, cleanupInterval, items)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.cache == nil {
|
|
|
|
s.cache = gc.New(expiration, cleanupInterval)
|
|
|
|
}
|
|
|
|
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
2021-04-30 10:07:20 +02:00
|
|
|
// Save stores all sessions in a JSON file.
|
2020-06-25 01:20:58 +02:00
|
|
|
func (s *Session) Save() error {
|
|
|
|
if s.cacheFile == "" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-06-29 11:10:24 +02:00
|
|
|
fileMutex.Lock()
|
|
|
|
defer fileMutex.Unlock()
|
|
|
|
|
2020-06-25 01:20:58 +02:00
|
|
|
items := s.cache.Items()
|
|
|
|
savedItems := make(map[string]Saved, len(items))
|
|
|
|
|
|
|
|
for key, item := range items {
|
2020-06-25 14:54:04 +02:00
|
|
|
saved := item.Object.(Data).Saved()
|
2020-06-25 01:20:58 +02:00
|
|
|
saved.Expiration = item.Expiration
|
|
|
|
savedItems[key] = saved
|
|
|
|
}
|
|
|
|
|
|
|
|
if serialized, err := json.MarshalIndent(savedItems, "", " "); err != nil {
|
|
|
|
return err
|
|
|
|
} else if err = ioutil.WriteFile(s.cacheFile, serialized, 0600); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|