/* * Wiki - A wiki with editor * Copyright (c) 2021 Peter Stuifzand * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package main import ( "encoding/json" "errors" "fmt" "net/http" "os" "sync" "time" ) type Session struct { ID string LoggedIn bool Me string AuthorizationEndpoint string RedirectURI string State string NextURI string } func NewSession(w http.ResponseWriter, r *http.Request) (*Session, error) { sessionID, err := getSessionCookie(w, r) if err != nil { return nil, fmt.Errorf("getSessionCookie failed: %w", err) } session := &Session{ID: sessionID} err = loadSession(session) if err != nil { return nil, fmt.Errorf("loadSession failed: %w" , err) } return session, nil } func (sess *Session) Flush() error { return saveSession(sess) } var fileMutex sync.RWMutex func saveSession(sess *Session) error { filename := generateFilename(sess.ID) err := os.Mkdir("session", 0755) fileMutex.Lock() defer fileMutex.Unlock() f, err := os.Create(filename) if err != nil { return err } defer f.Close() err = json.NewEncoder(f).Encode(sess) return err } func loadSession(sess *Session) error { filename := generateFilename(sess.ID) err := os.Mkdir("session", 0755) fileMutex.RLock() defer fileMutex.RUnlock() f, err := os.Open(filename) if err != nil { if os.IsNotExist(err) { // add defaults to session? return nil } return fmt.Errorf("while opening file %s: %w", filename, err) } defer f.Close() err = json.NewDecoder(f).Decode(sess) if err != nil { return fmt.Errorf("while decoding json from file %s: %w", filename, err) } return nil } func generateFilename(id string) string { return fmt.Sprintf("session/%s.json", id) } func getSessionCookie(w http.ResponseWriter, r *http.Request) (string, error) { c, err := r.Cookie("session") var sessionVar string if err != nil && errors.Is(err, http.ErrNoCookie) { sessionVar = RandStringBytes(16) c = &http.Cookie{ Name: "session", Value: sessionVar, Expires: time.Now().Add(24 * time.Hour), Path: "/", } } else { sessionVar = c.Value c.Expires = time.Now().Add(24 * time.Hour) } http.SetCookie(w, c) return sessionVar, nil }