Version handling from file

This commit is contained in:
Magnus Åhall 2023-12-28 07:47:23 +01:00
parent ac58fa0fc8
commit 392aff5956
4 changed files with 148 additions and 115 deletions

24
README.md Normal file
View File

@ -0,0 +1,24 @@
Create a configuration file `$HOME/.config/notes.yaml` with the following content:
```yaml
websocket:
domains:
- notes.com
database:
host: 127.0.0.1
port: 5432
name: notes.com
username: notes
password: SomePassword
application:
directories:
static: /usr/local/share/notes
upload: /usr/local/lib/notes/upload
session:
daysvalid: 31
```
Create an empty database.

4
db.go
View File

@ -6,7 +6,6 @@ import (
_ "github.com/lib/pq" _ "github.com/lib/pq"
// Standard // Standard
"embed"
"errors" "errors"
"fmt" "fmt"
"log" "log"
@ -16,9 +15,6 @@ import (
var ( var (
dbConn string dbConn string
db *sqlx.DB db *sqlx.DB
//go:embed sql/*
embedded embed.FS
) )
func dbInit() (err error) {// {{{ func dbInit() (err error) {// {{{

234
main.go
View File

@ -3,8 +3,8 @@ package main
import ( import (
// Standard // Standard
"crypto/md5" "crypto/md5"
"embed"
"encoding/hex" "encoding/hex"
"path/filepath"
"flag" "flag"
"fmt" "fmt"
"html/template" "html/template"
@ -13,41 +13,45 @@ import (
"net/http" "net/http"
"os" "os"
"path" "path"
"path/filepath"
"regexp" "regexp"
"strings"
"strconv" "strconv"
"strings"
"time" "time"
_ "embed"
) )
const VERSION = "v13"; const LISTEN_HOST = "0.0.0.0"
const LISTEN_HOST = "0.0.0.0";
const DB_SCHEMA = 13 const DB_SCHEMA = 13
var ( var (
flagPort int flagPort int
flagVersion bool flagVersion bool
flagConfig string
connectionManager ConnectionManager connectionManager ConnectionManager
static http.Handler static http.Handler
config Config config Config
VERSION string
//go:embed version sql/*
embedded embed.FS
) )
func init() {// {{{ func init() { // {{{
flag.IntVar( version, _ := embedded.ReadFile("version")
&flagPort, VERSION = strings.TrimSpace(string(version))
"port",
1371,
"TCP port to listen on",
)
flag.BoolVar(&flagVersion, "version", false, "Shows Notes version and exists")
configFilename := os.Getenv("HOME") + "/.config/notes.yaml"
flag.IntVar(&flagPort, "port", 1371, "TCP port to listen on")
flag.BoolVar(&flagVersion, "version", false, "Shows Notes version and exists")
flag.StringVar(&flagConfig, "config", configFilename, "Filename of configuration file")
flag.Parse() flag.Parse()
if false { if false {
time.Sleep(time.Second*1) time.Sleep(time.Second * 1)
} }
}// }}} } // }}}
func main() {// {{{ func main() { // {{{
var err error var err error
if flagVersion { if flagVersion {
@ -57,7 +61,7 @@ func main() {// {{{
log.Printf("\x1b[32mNotes\x1b[0m %s\n", VERSION) log.Printf("\x1b[32mNotes\x1b[0m %s\n", VERSION)
config, err = ConfigRead(os.Getenv("HOME")+"/.config/notes.yaml") config, err = ConfigRead(flagConfig)
if err != nil { if err != nil {
fmt.Printf("%s\n", err) fmt.Printf("%s\n", err)
os.Exit(1) os.Exit(1)
@ -72,23 +76,23 @@ func main() {// {{{
go connectionManager.BroadcastLoop() go connectionManager.BroadcastLoop()
static = http.FileServer(http.Dir(config.Application.Directories.Static)) static = http.FileServer(http.Dir(config.Application.Directories.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/retrieve", sessionRetrieve)
http.HandleFunc("/session/authenticate", sessionAuthenticate) http.HandleFunc("/session/authenticate", sessionAuthenticate)
http.HandleFunc("/user/password", userPassword) http.HandleFunc("/user/password", userPassword)
http.HandleFunc("/node/tree", nodeTree) http.HandleFunc("/node/tree", nodeTree)
http.HandleFunc("/node/retrieve", nodeRetrieve) http.HandleFunc("/node/retrieve", nodeRetrieve)
http.HandleFunc("/node/create", nodeCreate) http.HandleFunc("/node/create", nodeCreate)
http.HandleFunc("/node/update", nodeUpdate) http.HandleFunc("/node/update", nodeUpdate)
http.HandleFunc("/node/rename", nodeRename) http.HandleFunc("/node/rename", nodeRename)
http.HandleFunc("/node/delete", nodeDelete) http.HandleFunc("/node/delete", nodeDelete)
http.HandleFunc("/node/upload", nodeUpload) http.HandleFunc("/node/upload", nodeUpload)
http.HandleFunc("/node/download", nodeDownload) http.HandleFunc("/node/download", nodeDownload)
http.HandleFunc("/node/search", nodeSearch) http.HandleFunc("/node/search", nodeSearch)
http.HandleFunc("/key/retrieve", keyRetrieve) http.HandleFunc("/key/retrieve", keyRetrieve)
http.HandleFunc("/key/create", keyCreate) http.HandleFunc("/key/create", keyCreate)
http.HandleFunc("/key/counter", keyCounter) http.HandleFunc("/key/counter", keyCounter)
http.HandleFunc("/ws", websocketHandler) http.HandleFunc("/ws", websocketHandler)
http.HandleFunc("/", staticHandler) http.HandleFunc("/", staticHandler)
@ -96,13 +100,17 @@ func main() {// {{{
log.Printf("\x1b[32mNotes\x1b[0m Listening on %s\n", listen) log.Printf("\x1b[32mNotes\x1b[0m Listening on %s\n", listen)
log.Printf("\x1b[32mNotes\x1b[0m Answer for domains %s\n", strings.Join(config.Websocket.Domains, ", ")) log.Printf("\x1b[32mNotes\x1b[0m Answer for domains %s\n", strings.Join(config.Websocket.Domains, ", "))
http.ListenAndServe(listen, nil) http.ListenAndServe(listen, nil)
}// }}} } // }}}
func cssUpdateHandler(w http.ResponseWriter, r *http.Request) {// {{{ func cssUpdateHandler(w http.ResponseWriter, r *http.Request) { // {{{
log.Println("[BROADCAST] CSS updated") log.Println("[BROADCAST] CSS updated")
connectionManager.Broadcast(struct{ Ok bool; ID string; Op string }{ Ok: true, Op: "css_reload" }) connectionManager.Broadcast(struct {
}// }}} Ok bool
func websocketHandler(w http.ResponseWriter, r *http.Request) {// {{{ ID string
Op string
}{Ok: true, Op: "css_reload"})
} // }}}
func websocketHandler(w http.ResponseWriter, r *http.Request) { // {{{
var err error var err error
_, err = connectionManager.NewConnection(w, r) _, err = connectionManager.NewConnection(w, r)
@ -110,9 +118,9 @@ func websocketHandler(w http.ResponseWriter, r *http.Request) {// {{{
log.Printf("[Connection] %s\n", err) log.Printf("[Connection] %s\n", err)
return return
} }
}// }}} } // }}}
func staticHandler(w http.ResponseWriter, r *http.Request) {// {{{ func staticHandler(w http.ResponseWriter, r *http.Request) { // {{{
data := struct{ data := struct {
VERSION string VERSION string
}{ }{
VERSION: VERSION, VERSION: VERSION,
@ -149,9 +157,9 @@ func staticHandler(w http.ResponseWriter, r *http.Request) {// {{{
if err = tmpl.Execute(w, data); err != nil { if err = tmpl.Execute(w, data); err != nil {
w.Write([]byte(err.Error())) w.Write([]byte(err.Error()))
} }
}// }}} } // }}}
func sessionCreate(w http.ResponseWriter, r *http.Request) {// {{{ func sessionCreate(w http.ResponseWriter, r *http.Request) { // {{{
log.Println("/session/create") log.Println("/session/create")
session, err := CreateSession() session, err := CreateSession()
if err != nil { if err != nil {
@ -159,11 +167,11 @@ func sessionCreate(w http.ResponseWriter, r *http.Request) {// {{{
return 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) {// {{{ func sessionRetrieve(w http.ResponseWriter, r *http.Request) { // {{{
log.Println("/session/retrieve") log.Println("/session/retrieve")
var err error var err error
var found bool var found bool
@ -175,12 +183,12 @@ func sessionRetrieve(w http.ResponseWriter, r *http.Request) {// {{{
} }
responseData(w, map[string]interface{}{ responseData(w, map[string]interface{}{
"OK": true, "OK": true,
"Valid": found, "Valid": found,
"Session": session, "Session": session,
}) })
}// }}} } // }}}
func sessionAuthenticate(w http.ResponseWriter, r *http.Request) {// {{{ func sessionAuthenticate(w http.ResponseWriter, r *http.Request) { // {{{
log.Println("/session/authenticate") log.Println("/session/authenticate")
var err error var err error
var session Session var session Session
@ -192,7 +200,10 @@ func sessionAuthenticate(w http.ResponseWriter, r *http.Request) {// {{{
return return
} }
req := struct{ Username string; Password string }{} req := struct {
Username string
Password string
}{}
if err = parseRequest(r, &req); err != nil { if err = parseRequest(r, &req); err != nil {
responseError(w, err) responseError(w, err)
return return
@ -204,13 +215,13 @@ func sessionAuthenticate(w http.ResponseWriter, r *http.Request) {// {{{
} }
responseData(w, map[string]interface{}{ responseData(w, map[string]interface{}{
"OK": true, "OK": true,
"Authenticated": authenticated, "Authenticated": authenticated,
"Session": session, "Session": session,
}) })
}// }}} } // }}}
func userPassword(w http.ResponseWriter, r *http.Request) {// {{{ func userPassword(w http.ResponseWriter, r *http.Request) { // {{{
var err error var err error
var ok bool var ok bool
var session Session var session Session
@ -222,7 +233,7 @@ func userPassword(w http.ResponseWriter, r *http.Request) {// {{{
req := struct { req := struct {
CurrentPassword string CurrentPassword string
NewPassword string NewPassword string
}{} }{}
if err = parseRequest(r, &req); err != nil { if err = parseRequest(r, &req); err != nil {
responseError(w, err) responseError(w, err)
@ -236,12 +247,12 @@ func userPassword(w http.ResponseWriter, r *http.Request) {// {{{
} }
responseData(w, map[string]interface{}{ responseData(w, map[string]interface{}{
"OK": true, "OK": true,
"CurrentPasswordOK": ok, "CurrentPasswordOK": ok,
}) })
}// }}} } // }}}
func nodeTree(w http.ResponseWriter, r *http.Request) {// {{{ func nodeTree(w http.ResponseWriter, r *http.Request) { // {{{
var err error var err error
var session Session var session Session
@ -250,7 +261,7 @@ func nodeTree(w http.ResponseWriter, r *http.Request) {// {{{
return return
} }
req := struct { StartNodeID int }{} req := struct{ StartNodeID int }{}
if err = parseRequest(r, &req); err != nil { if err = parseRequest(r, &req); err != nil {
responseError(w, err) responseError(w, err)
return return
@ -263,11 +274,11 @@ func nodeTree(w http.ResponseWriter, r *http.Request) {// {{{
} }
responseData(w, map[string]interface{}{ responseData(w, map[string]interface{}{
"OK": true, "OK": true,
"Nodes": nodes, "Nodes": nodes,
}) })
}// }}} } // }}}
func nodeRetrieve(w http.ResponseWriter, r *http.Request) {// {{{ func nodeRetrieve(w http.ResponseWriter, r *http.Request) { // {{{
log.Println("/node/retrieve") log.Println("/node/retrieve")
var err error var err error
var session Session var session Session
@ -277,7 +288,7 @@ func nodeRetrieve(w http.ResponseWriter, r *http.Request) {// {{{
return return
} }
req := struct { ID int }{} req := struct{ ID int }{}
if err = parseRequest(r, &req); err != nil { if err = parseRequest(r, &req); err != nil {
responseError(w, err) responseError(w, err)
return return
@ -290,11 +301,11 @@ func nodeRetrieve(w http.ResponseWriter, r *http.Request) {// {{{
} }
responseData(w, map[string]interface{}{ responseData(w, map[string]interface{}{
"OK": true, "OK": true,
"Node": node, "Node": node,
}) })
}// }}} } // }}}
func nodeCreate(w http.ResponseWriter, r *http.Request) {// {{{ func nodeCreate(w http.ResponseWriter, r *http.Request) { // {{{
log.Println("/node/create") log.Println("/node/create")
var err error var err error
var session Session var session Session
@ -305,7 +316,7 @@ func nodeCreate(w http.ResponseWriter, r *http.Request) {// {{{
} }
req := struct { req := struct {
Name string Name string
ParentID int ParentID int
}{} }{}
if err = parseRequest(r, &req); err != nil { if err = parseRequest(r, &req); err != nil {
@ -320,11 +331,11 @@ func nodeCreate(w http.ResponseWriter, r *http.Request) {// {{{
} }
responseData(w, map[string]interface{}{ responseData(w, map[string]interface{}{
"OK": true, "OK": true,
"Node": node, "Node": node,
}) })
}// }}} } // }}}
func nodeUpdate(w http.ResponseWriter, r *http.Request) {// {{{ func nodeUpdate(w http.ResponseWriter, r *http.Request) { // {{{
log.Println("/node/update") log.Println("/node/update")
var err error var err error
var session Session var session Session
@ -335,8 +346,8 @@ func nodeUpdate(w http.ResponseWriter, r *http.Request) {// {{{
} }
req := struct { req := struct {
NodeID int NodeID int
Content string Content string
CryptoKeyID int CryptoKeyID int
}{} }{}
if err = parseRequest(r, &req); err != nil { if err = parseRequest(r, &req); err != nil {
@ -353,8 +364,8 @@ func nodeUpdate(w http.ResponseWriter, r *http.Request) {// {{{
responseData(w, map[string]interface{}{ responseData(w, map[string]interface{}{
"OK": true, "OK": true,
}) })
}// }}} } // }}}
func nodeRename(w http.ResponseWriter, r *http.Request) {// {{{ func nodeRename(w http.ResponseWriter, r *http.Request) { // {{{
var err error var err error
var session Session var session Session
@ -365,7 +376,7 @@ func nodeRename(w http.ResponseWriter, r *http.Request) {// {{{
req := struct { req := struct {
NodeID int NodeID int
Name string Name string
}{} }{}
if err = parseRequest(r, &req); err != nil { if err = parseRequest(r, &req); err != nil {
responseError(w, err) responseError(w, err)
@ -381,8 +392,8 @@ func nodeRename(w http.ResponseWriter, r *http.Request) {// {{{
responseData(w, map[string]interface{}{ responseData(w, map[string]interface{}{
"OK": true, "OK": true,
}) })
}// }}} } // }}}
func nodeDelete(w http.ResponseWriter, r *http.Request) {// {{{ func nodeDelete(w http.ResponseWriter, r *http.Request) { // {{{
var err error var err error
var session Session var session Session
@ -408,8 +419,8 @@ func nodeDelete(w http.ResponseWriter, r *http.Request) {// {{{
responseData(w, map[string]interface{}{ responseData(w, map[string]interface{}{
"OK": true, "OK": true,
}) })
}// }}} } // }}}
func nodeUpload(w http.ResponseWriter, r *http.Request) {// {{{ func nodeUpload(w http.ResponseWriter, r *http.Request) { // {{{
log.Println("/node/upload") log.Println("/node/upload")
var err error var err error
var session Session var session Session
@ -444,18 +455,17 @@ func nodeUpload(w http.ResponseWriter, r *http.Request) {// {{{
md5sumBytes := md5.Sum(fileBytes) md5sumBytes := md5.Sum(fileBytes)
md5sum := hex.EncodeToString(md5sumBytes[:]) md5sum := hex.EncodeToString(md5sumBytes[:])
var nodeID int var nodeID int
if nodeID, err = strconv.Atoi(r.PostFormValue("NodeID")); err != nil { if nodeID, err = strconv.Atoi(r.PostFormValue("NodeID")); err != nil {
responseError(w, err) responseError(w, err)
return return
} }
nodeFile := File{ nodeFile := File{
NodeID: nodeID, NodeID: nodeID,
Filename: handler.Filename, Filename: handler.Filename,
Size: handler.Size, Size: handler.Size,
MIME: handler.Header.Get("Content-Type"), MIME: handler.Header.Get("Content-Type"),
MD5: md5sum, MD5: md5sum,
} }
if err = session.AddFile(&nodeFile); err != nil { if err = session.AddFile(&nodeFile); err != nil {
responseError(w, err) responseError(w, err)
@ -490,11 +500,11 @@ func nodeUpload(w http.ResponseWriter, r *http.Request) {// {{{
} }
responseData(w, map[string]interface{}{ responseData(w, map[string]interface{}{
"OK": true, "OK": true,
"File": nodeFile, "File": nodeFile,
}) })
}// }}} } // }}}
func nodeDownload(w http.ResponseWriter, r *http.Request) {// {{{ func nodeDownload(w http.ResponseWriter, r *http.Request) { // {{{
log.Println("/node/download") log.Println("/node/download")
var err error var err error
var session Session var session Session
@ -524,7 +534,7 @@ func nodeDownload(w http.ResponseWriter, r *http.Request) {// {{{
responseError(w, fmt.Errorf("File not found")) responseError(w, fmt.Errorf("File not found"))
return return
} }
var file *os.File var file *os.File
fname := filepath.Join( fname := filepath.Join(
config.Application.Directories.Upload, config.Application.Directories.Upload,
@ -560,8 +570,8 @@ func nodeDownload(w http.ResponseWriter, r *http.Request) {// {{{
} }
} }
}// }}} } // }}}
func nodeFiles(w http.ResponseWriter, r *http.Request) {// {{{ func nodeFiles(w http.ResponseWriter, r *http.Request) { // {{{
var err error var err error
var session Session var session Session
var files []File var files []File
@ -586,11 +596,11 @@ func nodeFiles(w http.ResponseWriter, r *http.Request) {// {{{
} }
responseData(w, map[string]interface{}{ responseData(w, map[string]interface{}{
"OK": true, "OK": true,
"Files": files, "Files": files,
}) })
}// }}} } // }}}
func nodeSearch(w http.ResponseWriter, r *http.Request) {// {{{ func nodeSearch(w http.ResponseWriter, r *http.Request) { // {{{
log.Println("/node/search") log.Println("/node/search")
var err error var err error
var session Session var session Session
@ -616,12 +626,12 @@ func nodeSearch(w http.ResponseWriter, r *http.Request) {// {{{
} }
responseData(w, map[string]interface{}{ responseData(w, map[string]interface{}{
"OK": true, "OK": true,
"Nodes": nodes, "Nodes": nodes,
}) })
}// }}} } // }}}
func keyRetrieve(w http.ResponseWriter, r *http.Request) {// {{{ func keyRetrieve(w http.ResponseWriter, r *http.Request) { // {{{
log.Println("/key/retrieve") log.Println("/key/retrieve")
var err error var err error
var session Session var session Session
@ -638,11 +648,11 @@ func keyRetrieve(w http.ResponseWriter, r *http.Request) {// {{{
} }
responseData(w, map[string]interface{}{ responseData(w, map[string]interface{}{
"OK": true, "OK": true,
"Keys": keys, "Keys": keys,
}) })
}// }}} } // }}}
func keyCreate(w http.ResponseWriter, r *http.Request) {// {{{ func keyCreate(w http.ResponseWriter, r *http.Request) { // {{{
log.Println("/key/create") log.Println("/key/create")
var err error var err error
var session Session var session Session
@ -654,7 +664,7 @@ func keyCreate(w http.ResponseWriter, r *http.Request) {// {{{
req := struct { req := struct {
Description string Description string
Key string Key string
}{} }{}
if err = parseRequest(r, &req); err != nil { if err = parseRequest(r, &req); err != nil {
responseError(w, err) responseError(w, err)
@ -668,11 +678,11 @@ func keyCreate(w http.ResponseWriter, r *http.Request) {// {{{
} }
responseData(w, map[string]interface{}{ responseData(w, map[string]interface{}{
"OK": true, "OK": true,
"Key": key, "Key": key,
}) })
}// }}} } // }}}
func keyCounter(w http.ResponseWriter, r *http.Request) {// {{{ func keyCounter(w http.ResponseWriter, r *http.Request) { // {{{
log.Println("/key/counter") log.Println("/key/counter")
var err error var err error
var session Session var session Session
@ -693,9 +703,9 @@ func keyCounter(w http.ResponseWriter, r *http.Request) {// {{{
// Javascript uses int32, thus getting a string counter for Javascript BigInt to parse. // Javascript uses int32, thus getting a string counter for Javascript BigInt to parse.
"Counter": strconv.FormatInt(counter, 10), "Counter": strconv.FormatInt(counter, 10),
}) })
}// }}} } // }}}
func newTemplate(requestPath string) (tmpl *template.Template, err error) {// {{{ func newTemplate(requestPath string) (tmpl *template.Template, err error) { // {{{
// Append index.html if needed for further reading of the file // Append index.html if needed for further reading of the file
p := requestPath p := requestPath
if p[len(p)-1] == '/' { if p[len(p)-1] == '/' {
@ -704,9 +714,11 @@ func newTemplate(requestPath string) (tmpl *template.Template, err error) {// {{
p = config.Application.Directories.Static + p p = config.Application.Directories.Static + p
base := path.Base(p) base := path.Base(p)
if tmpl, err = template.New(base).ParseFiles(p); err != nil { return } if tmpl, err = template.New(base).ParseFiles(p); err != nil {
return
}
return return
}// }}} } // }}}
// vim: foldmethod=marker // vim: foldmethod=marker

1
version Normal file
View File

@ -0,0 +1 @@
v14