Session
This commit is contained in:
parent
b8a673fb0a
commit
a76c093d44
52
main.go
52
main.go
@ -51,6 +51,8 @@ func main() {// {{{
|
|||||||
static = http.FileServer(http.Dir("./static"))
|
static = http.FileServer(http.Dir("./static"))
|
||||||
http.HandleFunc("/css_updated", cssUpdateHandler)
|
http.HandleFunc("/css_updated", cssUpdateHandler)
|
||||||
http.HandleFunc("/session/create", sessionCreate)
|
http.HandleFunc("/session/create", sessionCreate)
|
||||||
|
http.HandleFunc("/session/retrieve", sessionRetrieve)
|
||||||
|
http.HandleFunc("/session/authenticate", sessionAuthenticate)
|
||||||
http.HandleFunc("/ws", websocketHandler)
|
http.HandleFunc("/ws", websocketHandler)
|
||||||
http.HandleFunc("/", staticHandler)
|
http.HandleFunc("/", staticHandler)
|
||||||
|
|
||||||
@ -68,12 +70,62 @@ func sessionCreate(w http.ResponseWriter, r *http.Request) {// {{{
|
|||||||
session, err := NewSession()
|
session, err := NewSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
responseError(w, err)
|
responseError(w, err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
responseData(w, map[string]interface{}{
|
responseData(w, map[string]interface{}{
|
||||||
"OK": true,
|
"OK": true,
|
||||||
"Session": session,
|
"Session": session,
|
||||||
})
|
})
|
||||||
}// }}}
|
}// }}}
|
||||||
|
func sessionRetrieve(w http.ResponseWriter, r *http.Request) {// {{{
|
||||||
|
var err error
|
||||||
|
var uuid string
|
||||||
|
|
||||||
|
if uuid, err = sessionUUID(r); err != nil {
|
||||||
|
responseError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
session := Session{ UUID: uuid }
|
||||||
|
if err = session.Retrieve(); err != nil {
|
||||||
|
responseError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
responseData(w, map[string]interface{}{
|
||||||
|
"OK": true,
|
||||||
|
"Session": session,
|
||||||
|
})
|
||||||
|
}// }}}
|
||||||
|
func sessionAuthenticate(w http.ResponseWriter, r *http.Request) {// {{{
|
||||||
|
var err error
|
||||||
|
var uuid string
|
||||||
|
|
||||||
|
if uuid, err = sessionUUID(r); err != nil {
|
||||||
|
responseError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
session := Session{
|
||||||
|
UUID: uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
req := struct{ Username string; Password string }{}
|
||||||
|
if err = request(r, &req); err != nil {
|
||||||
|
responseError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = session.Authenticate(req.Username, req.Password); err != nil {
|
||||||
|
responseError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
responseData(w, map[string]interface{}{
|
||||||
|
"OK": true,
|
||||||
|
"Session": session,
|
||||||
|
})
|
||||||
|
}// }}}
|
||||||
func websocketHandler(w http.ResponseWriter, r *http.Request) {// {{{
|
func websocketHandler(w http.ResponseWriter, r *http.Request) {// {{{
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -3,6 +3,8 @@ package main
|
|||||||
import (
|
import (
|
||||||
// Standard
|
// Standard
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -26,3 +28,18 @@ func responseData(w http.ResponseWriter, data interface{}) {
|
|||||||
w.Header().Add("Content-Type", "application/json")
|
w.Header().Add("Content-Type", "application/json")
|
||||||
w.Write(resJSON)
|
w.Write(resJSON)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func request(r *http.Request, data interface{}) (err error) {
|
||||||
|
body, _ := io.ReadAll(r.Body)
|
||||||
|
defer r.Body.Close()
|
||||||
|
err = json.Unmarshal(body, data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func sessionUUID(r *http.Request) (string, error) {
|
||||||
|
headers := r.Header["X-Session-Id"]
|
||||||
|
if len(headers) > 0 {
|
||||||
|
return headers[0], nil
|
||||||
|
}
|
||||||
|
return "", errors.New("Invalid session")
|
||||||
|
}
|
||||||
|
58
session.go
58
session.go
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
// Standard
|
// Standard
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -29,3 +30,60 @@ func NewSession() (session Session, err error) {
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (session *Session) Retrieve() (err error) {
|
||||||
|
var rows *sql.Rows
|
||||||
|
if rows, err = db.Query(`
|
||||||
|
SELECT
|
||||||
|
uuid, user_id, created
|
||||||
|
FROM public.session
|
||||||
|
WHERE
|
||||||
|
uuid = $1
|
||||||
|
`,
|
||||||
|
session.UUID,
|
||||||
|
); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
if rows.Next() {
|
||||||
|
rows.Scan(&session.UUID, &session.UserID, &session.Created)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (session *Session) Authenticate(username, password string) (err error) {
|
||||||
|
authenticated := false
|
||||||
|
|
||||||
|
var rows *sql.Rows
|
||||||
|
if rows, err = db.Query(`
|
||||||
|
SELECT id
|
||||||
|
FROM public.user
|
||||||
|
WHERE
|
||||||
|
username=$1 AND
|
||||||
|
password=$2
|
||||||
|
`,
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
if rows.Next() {
|
||||||
|
rows.Scan(&session.UserID)
|
||||||
|
authenticated = session.UserID > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if authenticated {
|
||||||
|
_, err = db.Exec("UPDATE public.session SET user_id=$1 WHERE uuid=$2", session.UserID, session.UUID)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = errors.New("Invalid authentication")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -16,8 +16,7 @@
|
|||||||
"preact/devtools": "/js/{{ .VERSION }}/lib/preact/devtools.mjs",
|
"preact/devtools": "/js/{{ .VERSION }}/lib/preact/devtools.mjs",
|
||||||
"@preact/signals-core": "/js/{{ .VERSION }}/lib/signals/signals-core.mjs",
|
"@preact/signals-core": "/js/{{ .VERSION }}/lib/signals/signals-core.mjs",
|
||||||
"preact/signals": "/js/{{ .VERSION }}/lib/signals/signals.mjs",
|
"preact/signals": "/js/{{ .VERSION }}/lib/signals/signals.mjs",
|
||||||
"htm": "/js/{{ .VERSION }}/lib/htm/htm.mjs"
|
"htm": "/js/{{ .VERSION }}/lib/htm/htm.mjs",
|
||||||
|
|
||||||
"session": "/js/{{ .VERSION }}/session.mjs"
|
"session": "/js/{{ .VERSION }}/session.mjs"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import 'preact/devtools'
|
|||||||
//import { signal } from 'preact/signals'
|
//import { signal } from 'preact/signals'
|
||||||
import { h, Component, render, createRef } from 'preact'
|
import { h, Component, render, createRef } from 'preact'
|
||||||
import htm from 'htm'
|
import htm from 'htm'
|
||||||
import Session from 'session'
|
import { Session } from 'session'
|
||||||
const html = htm.bind(h)
|
const html = htm.bind(h)
|
||||||
|
|
||||||
class App extends Component {
|
class App extends Component {
|
||||||
@ -15,10 +15,16 @@ class App extends Component {
|
|||||||
this.wsConnect()
|
this.wsConnect()
|
||||||
this.wsLoop()
|
this.wsLoop()
|
||||||
|
|
||||||
|
this.session = new Session(this)
|
||||||
|
this.session.initialize()
|
||||||
}//}}}
|
}//}}}
|
||||||
render() {//{{{
|
render() {//{{{
|
||||||
if(this.sessionID === null) {
|
if(!this.session.initialized) {
|
||||||
|
return false;
|
||||||
|
//return html`<div>Validating session</div>`
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!this.session.authenticated()) {
|
||||||
return html`<${Login} />`
|
return html`<${Login} />`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,8 +91,9 @@ class App extends Component {
|
|||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.sessionID !== null)
|
console.log(this.session)
|
||||||
headers['X-SESSION-ID'] = this.sessionID
|
if(this.session.UUID !== '')
|
||||||
|
headers['X-Session-Id'] = this.session.UUID
|
||||||
|
|
||||||
fetch(url, {
|
fetch(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@ -116,22 +123,6 @@ class App extends Component {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}//}}}
|
}//}}}
|
||||||
login(username, password) {//{{{
|
|
||||||
this.request('/session/create', {})
|
|
||||||
.then(res=>{
|
|
||||||
this.setSessionID(res.Session.UUID)
|
|
||||||
})
|
|
||||||
.catch(this.responseError)
|
|
||||||
}//}}}
|
|
||||||
|
|
||||||
getSessionID() {
|
|
||||||
return window.localStorage.getItem("sessionID")
|
|
||||||
}
|
|
||||||
setSessionID(uuid) {
|
|
||||||
console.log('wut')
|
|
||||||
this.sessionID = uuid
|
|
||||||
window.localStorage.setItem('sessionID', uuid)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Login extends Component {
|
class Login extends Component {
|
||||||
@ -152,7 +143,7 @@ class Login extends Component {
|
|||||||
login() {//{{{
|
login() {//{{{
|
||||||
let username = document.getElementById('username').value
|
let username = document.getElementById('username').value
|
||||||
let password = document.getElementById('password').value
|
let password = document.getElementById('password').value
|
||||||
window._app.current.login(username, password)
|
window._app.current.session.authenticate(username, password)
|
||||||
}//}}}
|
}//}}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
51
static/js/session.mjs
Normal file
51
static/js/session.mjs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
export class Session {
|
||||||
|
constructor(app) {
|
||||||
|
this.app = app
|
||||||
|
this.UUID = ''
|
||||||
|
this.initialized = false
|
||||||
|
this.UserID = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
initialize() {//{{{
|
||||||
|
// Retrieving the stored session UUID, if any.
|
||||||
|
// If one found, validate with server.
|
||||||
|
let uuid = window.localStorage.getItem("session.UUID")
|
||||||
|
if(uuid === null) {
|
||||||
|
this.create()
|
||||||
|
} else {
|
||||||
|
this.UUID = uuid
|
||||||
|
this.app.request('/session/retrieve', {})
|
||||||
|
.then(res=>{
|
||||||
|
this.UserID = res.Session.UserID
|
||||||
|
this.initialized = true
|
||||||
|
this.app.forceUpdate()
|
||||||
|
})
|
||||||
|
.catch(this.app.responseError)
|
||||||
|
}
|
||||||
|
}//}}}
|
||||||
|
create() {//{{{
|
||||||
|
this.app.request('/session/create', {})
|
||||||
|
.then(res=>{
|
||||||
|
this.UUID = res.Session.UUID
|
||||||
|
window.localStorage.setItem('session.UUID', this.UUID)
|
||||||
|
this.app.forceUpdate()
|
||||||
|
})
|
||||||
|
.catch(this.responseError)
|
||||||
|
}//}}}
|
||||||
|
authenticate(username, password) {//{{{
|
||||||
|
this.app.request('/session/authenticate', {
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
})
|
||||||
|
.then(res=>{
|
||||||
|
this.UserID = res.Session.UserID
|
||||||
|
this.app.forceUpdate()
|
||||||
|
})
|
||||||
|
.catch(this.app.responseError)
|
||||||
|
}//}}}
|
||||||
|
authenticated() {//{{{
|
||||||
|
return this.UserID != 0
|
||||||
|
}//}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// vim: foldmethod=marker
|
@ -1,12 +0,0 @@
|
|||||||
export class Session {
|
|
||||||
static createFromStorage() {
|
|
||||||
let session = new Session()
|
|
||||||
session.UUID
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.UUID = ''
|
|
||||||
this.authenticated = false
|
|
||||||
this.UserID = 0
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user