Compare commits

..

No commits in common. "6cb4833dbd81696e8564b4f34a4a46183d798f6a" and "48e07c15d43c5c3b59e004476b864bdc3b7cea93" have entirely different histories.

8 changed files with 120 additions and 213 deletions

View File

@ -1,36 +0,0 @@
# Run from scratch
## Database
Create an empty database. The configured user needs to be able to create and alter stuff.
## Configuration
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
```
## User
Create a user by running
```
notes --createuser
```

1
TODO
View File

@ -4,6 +4,7 @@
- per file
- when deleting node and child nodes
* Move node
* Tree titles should be user-select none
Long term

4
db.go
View File

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

245
main.go
View File

@ -3,8 +3,8 @@ package main
import (
// Standard
"crypto/md5"
"embed"
"encoding/hex"
"path/filepath"
"flag"
"fmt"
"html/template"
@ -13,47 +13,41 @@ import (
"net/http"
"os"
"path"
"path/filepath"
"regexp"
"strconv"
"strings"
"strconv"
"time"
_ "embed"
)
const LISTEN_HOST = "0.0.0.0"
const VERSION = "v13";
const LISTEN_HOST = "0.0.0.0";
const DB_SCHEMA = 13
var (
flagPort int
flagVersion bool
flagCreateUser bool
flagConfig string
flagPort int
flagVersion bool
connectionManager ConnectionManager
static http.Handler
config Config
VERSION string
//go:embed version sql/*
embedded embed.FS
static http.Handler
config Config
)
func init() { // {{{
version, _ := embedded.ReadFile("version")
VERSION = strings.TrimSpace(string(version))
configFilename := os.Getenv("HOME") + "/.config/notes.yaml"
flag.IntVar(&flagPort, "port", 1371, "TCP port to listen on")
func init() {// {{{
flag.IntVar(
&flagPort,
"port",
1371,
"TCP port to listen on",
)
flag.BoolVar(&flagVersion, "version", false, "Shows Notes version and exists")
flag.BoolVar(&flagCreateUser, "createuser", false, "Create a user and exit")
flag.StringVar(&flagConfig, "config", configFilename, "Filename of configuration file")
flag.Parse()
if false {
time.Sleep(time.Second * 1)
time.Sleep(time.Second*1)
}
} // }}}
func main() { // {{{
}// }}}
func main() {// {{{
var err error
if flagVersion {
@ -63,7 +57,7 @@ func main() { // {{{
log.Printf("\x1b[32mNotes\x1b[0m %s\n", VERSION)
config, err = ConfigRead(flagConfig)
config, err = ConfigRead(os.Getenv("HOME")+"/.config/notes.yaml")
if err != nil {
fmt.Printf("%s\n", err)
os.Exit(1)
@ -74,36 +68,27 @@ func main() { // {{{
os.Exit(1)
}
if flagCreateUser {
err = createUser()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
os.Exit(0)
}
connectionManager = NewConnectionManager()
go connectionManager.BroadcastLoop()
static = http.FileServer(http.Dir(config.Application.Directories.Static))
http.HandleFunc("/css_updated", cssUpdateHandler)
http.HandleFunc("/session/create", sessionCreate)
http.HandleFunc("/session/retrieve", sessionRetrieve)
http.HandleFunc("/css_updated", cssUpdateHandler)
http.HandleFunc("/session/create", sessionCreate)
http.HandleFunc("/session/retrieve", sessionRetrieve)
http.HandleFunc("/session/authenticate", sessionAuthenticate)
http.HandleFunc("/user/password", userPassword)
http.HandleFunc("/node/tree", nodeTree)
http.HandleFunc("/node/retrieve", nodeRetrieve)
http.HandleFunc("/node/create", nodeCreate)
http.HandleFunc("/node/update", nodeUpdate)
http.HandleFunc("/node/rename", nodeRename)
http.HandleFunc("/node/delete", nodeDelete)
http.HandleFunc("/node/upload", nodeUpload)
http.HandleFunc("/node/download", nodeDownload)
http.HandleFunc("/node/search", nodeSearch)
http.HandleFunc("/key/retrieve", keyRetrieve)
http.HandleFunc("/key/create", keyCreate)
http.HandleFunc("/key/counter", keyCounter)
http.HandleFunc("/user/password", userPassword)
http.HandleFunc("/node/tree", nodeTree)
http.HandleFunc("/node/retrieve", nodeRetrieve)
http.HandleFunc("/node/create", nodeCreate)
http.HandleFunc("/node/update", nodeUpdate)
http.HandleFunc("/node/rename", nodeRename)
http.HandleFunc("/node/delete", nodeDelete)
http.HandleFunc("/node/upload", nodeUpload)
http.HandleFunc("/node/download", nodeDownload)
http.HandleFunc("/node/search", nodeSearch)
http.HandleFunc("/key/retrieve", keyRetrieve)
http.HandleFunc("/key/create", keyCreate)
http.HandleFunc("/key/counter", keyCounter)
http.HandleFunc("/ws", websocketHandler)
http.HandleFunc("/", staticHandler)
@ -111,17 +96,13 @@ func main() { // {{{
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, ", "))
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")
connectionManager.Broadcast(struct {
Ok bool
ID string
Op string
}{Ok: true, Op: "css_reload"})
} // }}}
func websocketHandler(w http.ResponseWriter, r *http.Request) { // {{{
connectionManager.Broadcast(struct{ Ok bool; ID string; Op string }{ Ok: true, Op: "css_reload" })
}// }}}
func websocketHandler(w http.ResponseWriter, r *http.Request) {// {{{
var err error
_, err = connectionManager.NewConnection(w, r)
@ -129,9 +110,9 @@ func websocketHandler(w http.ResponseWriter, r *http.Request) { // {{{
log.Printf("[Connection] %s\n", err)
return
}
} // }}}
func staticHandler(w http.ResponseWriter, r *http.Request) { // {{{
data := struct {
}// }}}
func staticHandler(w http.ResponseWriter, r *http.Request) {// {{{
data := struct{
VERSION string
}{
VERSION: VERSION,
@ -168,9 +149,9 @@ func staticHandler(w http.ResponseWriter, r *http.Request) { // {{{
if err = tmpl.Execute(w, data); err != nil {
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")
session, err := CreateSession()
if err != nil {
@ -178,11 +159,11 @@ func sessionCreate(w http.ResponseWriter, r *http.Request) { // {{{
return
}
responseData(w, map[string]interface{}{
"OK": true,
"OK": true,
"Session": session,
})
} // }}}
func sessionRetrieve(w http.ResponseWriter, r *http.Request) { // {{{
}// }}}
func sessionRetrieve(w http.ResponseWriter, r *http.Request) {// {{{
log.Println("/session/retrieve")
var err error
var found bool
@ -194,12 +175,12 @@ func sessionRetrieve(w http.ResponseWriter, r *http.Request) { // {{{
}
responseData(w, map[string]interface{}{
"OK": true,
"Valid": found,
"OK": true,
"Valid": found,
"Session": session,
})
} // }}}
func sessionAuthenticate(w http.ResponseWriter, r *http.Request) { // {{{
}// }}}
func sessionAuthenticate(w http.ResponseWriter, r *http.Request) {// {{{
log.Println("/session/authenticate")
var err error
var session Session
@ -211,10 +192,7 @@ func sessionAuthenticate(w http.ResponseWriter, r *http.Request) { // {{{
return
}
req := struct {
Username string
Password string
}{}
req := struct{ Username string; Password string }{}
if err = parseRequest(r, &req); err != nil {
responseError(w, err)
return
@ -226,13 +204,13 @@ func sessionAuthenticate(w http.ResponseWriter, r *http.Request) { // {{{
}
responseData(w, map[string]interface{}{
"OK": true,
"OK": true,
"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 ok bool
var session Session
@ -244,7 +222,7 @@ func userPassword(w http.ResponseWriter, r *http.Request) { // {{{
req := struct {
CurrentPassword string
NewPassword string
NewPassword string
}{}
if err = parseRequest(r, &req); err != nil {
responseError(w, err)
@ -258,12 +236,12 @@ func userPassword(w http.ResponseWriter, r *http.Request) { // {{{
}
responseData(w, map[string]interface{}{
"OK": true,
"OK": true,
"CurrentPasswordOK": ok,
})
} // }}}
}// }}}
func nodeTree(w http.ResponseWriter, r *http.Request) { // {{{
func nodeTree(w http.ResponseWriter, r *http.Request) {// {{{
var err error
var session Session
@ -272,7 +250,7 @@ func nodeTree(w http.ResponseWriter, r *http.Request) { // {{{
return
}
req := struct{ StartNodeID int }{}
req := struct { StartNodeID int }{}
if err = parseRequest(r, &req); err != nil {
responseError(w, err)
return
@ -285,11 +263,11 @@ func nodeTree(w http.ResponseWriter, r *http.Request) { // {{{
}
responseData(w, map[string]interface{}{
"OK": true,
"OK": true,
"Nodes": nodes,
})
} // }}}
func nodeRetrieve(w http.ResponseWriter, r *http.Request) { // {{{
}// }}}
func nodeRetrieve(w http.ResponseWriter, r *http.Request) {// {{{
log.Println("/node/retrieve")
var err error
var session Session
@ -299,7 +277,7 @@ func nodeRetrieve(w http.ResponseWriter, r *http.Request) { // {{{
return
}
req := struct{ ID int }{}
req := struct { ID int }{}
if err = parseRequest(r, &req); err != nil {
responseError(w, err)
return
@ -312,11 +290,11 @@ func nodeRetrieve(w http.ResponseWriter, r *http.Request) { // {{{
}
responseData(w, map[string]interface{}{
"OK": true,
"OK": true,
"Node": node,
})
} // }}}
func nodeCreate(w http.ResponseWriter, r *http.Request) { // {{{
}// }}}
func nodeCreate(w http.ResponseWriter, r *http.Request) {// {{{
log.Println("/node/create")
var err error
var session Session
@ -327,7 +305,7 @@ func nodeCreate(w http.ResponseWriter, r *http.Request) { // {{{
}
req := struct {
Name string
Name string
ParentID int
}{}
if err = parseRequest(r, &req); err != nil {
@ -342,11 +320,11 @@ func nodeCreate(w http.ResponseWriter, r *http.Request) { // {{{
}
responseData(w, map[string]interface{}{
"OK": true,
"OK": true,
"Node": node,
})
} // }}}
func nodeUpdate(w http.ResponseWriter, r *http.Request) { // {{{
}// }}}
func nodeUpdate(w http.ResponseWriter, r *http.Request) {// {{{
log.Println("/node/update")
var err error
var session Session
@ -357,8 +335,8 @@ func nodeUpdate(w http.ResponseWriter, r *http.Request) { // {{{
}
req := struct {
NodeID int
Content string
NodeID int
Content string
CryptoKeyID int
}{}
if err = parseRequest(r, &req); err != nil {
@ -375,8 +353,8 @@ func nodeUpdate(w http.ResponseWriter, r *http.Request) { // {{{
responseData(w, map[string]interface{}{
"OK": true,
})
} // }}}
func nodeRename(w http.ResponseWriter, r *http.Request) { // {{{
}// }}}
func nodeRename(w http.ResponseWriter, r *http.Request) {// {{{
var err error
var session Session
@ -387,7 +365,7 @@ func nodeRename(w http.ResponseWriter, r *http.Request) { // {{{
req := struct {
NodeID int
Name string
Name string
}{}
if err = parseRequest(r, &req); err != nil {
responseError(w, err)
@ -403,8 +381,8 @@ func nodeRename(w http.ResponseWriter, r *http.Request) { // {{{
responseData(w, map[string]interface{}{
"OK": true,
})
} // }}}
func nodeDelete(w http.ResponseWriter, r *http.Request) { // {{{
}// }}}
func nodeDelete(w http.ResponseWriter, r *http.Request) {// {{{
var err error
var session Session
@ -430,8 +408,8 @@ func nodeDelete(w http.ResponseWriter, r *http.Request) { // {{{
responseData(w, map[string]interface{}{
"OK": true,
})
} // }}}
func nodeUpload(w http.ResponseWriter, r *http.Request) { // {{{
}// }}}
func nodeUpload(w http.ResponseWriter, r *http.Request) {// {{{
log.Println("/node/upload")
var err error
var session Session
@ -466,17 +444,18 @@ func nodeUpload(w http.ResponseWriter, r *http.Request) { // {{{
md5sumBytes := md5.Sum(fileBytes)
md5sum := hex.EncodeToString(md5sumBytes[:])
var nodeID int
if nodeID, err = strconv.Atoi(r.PostFormValue("NodeID")); err != nil {
responseError(w, err)
return
}
nodeFile := File{
NodeID: nodeID,
NodeID: nodeID,
Filename: handler.Filename,
Size: handler.Size,
MIME: handler.Header.Get("Content-Type"),
MD5: md5sum,
Size: handler.Size,
MIME: handler.Header.Get("Content-Type"),
MD5: md5sum,
}
if err = session.AddFile(&nodeFile); err != nil {
responseError(w, err)
@ -511,11 +490,11 @@ func nodeUpload(w http.ResponseWriter, r *http.Request) { // {{{
}
responseData(w, map[string]interface{}{
"OK": true,
"OK": true,
"File": nodeFile,
})
} // }}}
func nodeDownload(w http.ResponseWriter, r *http.Request) { // {{{
}// }}}
func nodeDownload(w http.ResponseWriter, r *http.Request) {// {{{
log.Println("/node/download")
var err error
var session Session
@ -581,8 +560,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 session Session
var files []File
@ -607,11 +586,11 @@ func nodeFiles(w http.ResponseWriter, r *http.Request) { // {{{
}
responseData(w, map[string]interface{}{
"OK": true,
"OK": true,
"Files": files,
})
} // }}}
func nodeSearch(w http.ResponseWriter, r *http.Request) { // {{{
}// }}}
func nodeSearch(w http.ResponseWriter, r *http.Request) {// {{{
log.Println("/node/search")
var err error
var session Session
@ -637,12 +616,12 @@ func nodeSearch(w http.ResponseWriter, r *http.Request) { // {{{
}
responseData(w, map[string]interface{}{
"OK": true,
"OK": true,
"Nodes": nodes,
})
} // }}}
}// }}}
func keyRetrieve(w http.ResponseWriter, r *http.Request) { // {{{
func keyRetrieve(w http.ResponseWriter, r *http.Request) {// {{{
log.Println("/key/retrieve")
var err error
var session Session
@ -659,11 +638,11 @@ func keyRetrieve(w http.ResponseWriter, r *http.Request) { // {{{
}
responseData(w, map[string]interface{}{
"OK": true,
"OK": true,
"Keys": keys,
})
} // }}}
func keyCreate(w http.ResponseWriter, r *http.Request) { // {{{
}// }}}
func keyCreate(w http.ResponseWriter, r *http.Request) {// {{{
log.Println("/key/create")
var err error
var session Session
@ -675,7 +654,7 @@ func keyCreate(w http.ResponseWriter, r *http.Request) { // {{{
req := struct {
Description string
Key string
Key string
}{}
if err = parseRequest(r, &req); err != nil {
responseError(w, err)
@ -689,11 +668,11 @@ func keyCreate(w http.ResponseWriter, r *http.Request) { // {{{
}
responseData(w, map[string]interface{}{
"OK": true,
"OK": true,
"Key": key,
})
} // }}}
func keyCounter(w http.ResponseWriter, r *http.Request) { // {{{
}// }}}
func keyCounter(w http.ResponseWriter, r *http.Request) {// {{{
log.Println("/key/counter")
var err error
var session Session
@ -714,9 +693,9 @@ func keyCounter(w http.ResponseWriter, r *http.Request) { // {{{
// Javascript uses int32, thus getting a string counter for Javascript BigInt to parse.
"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
p := requestPath
if p[len(p)-1] == '/' {
@ -725,11 +704,9 @@ func newTemplate(requestPath string) (tmpl *template.Template, err error) { // {
p = config.Application.Directories.Static + 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
} // }}}
}// }}}
// vim: foldmethod=marker

View File

@ -205,7 +205,6 @@ header .menu {
#tree .node .name {
white-space: nowrap;
cursor: pointer;
user-select: none;
}
#tree .node .name:hover {
color: #ecbf00;

View File

@ -232,7 +232,6 @@ header {
.name {
white-space: nowrap;
cursor: pointer;
user-select: none;
&:hover {
color: @accent_2;

42
user.go
View File

@ -3,7 +3,6 @@ package main
import (
// Standard
"database/sql"
"fmt"
)
func (session Session) UpdatePassword(currPass, newPass string) (ok bool, err error) {
@ -25,9 +24,9 @@ func (session Session) UpdatePassword(currPass, newPass string) (ok bool, err er
password=password_hash(SUBSTRING(password FROM 1 FOR 32), $3::bytea)
RETURNING id
`,
newPass,
session.UserID,
currPass,
newPass,
session.UserID,
currPass,
)
if rowsAffected, err = result.RowsAffected(); err != nil {
@ -36,38 +35,3 @@ func (session Session) UpdatePassword(currPass, newPass string) (ok bool, err er
return rowsAffected > 0, nil
}
func createUser() (err error) {
var username, password string
fmt.Printf("Username: ")
fmt.Scanln(&username)
fmt.Printf("Password: ")
fmt.Scanln(&password)
err = CreateDbUser(username, password)
return
}
func CreateDbUser(username string, password string) (err error) {
var result sql.Result
result, err = db.Exec(`
INSERT INTO public.user(username, password)
VALUES(
$1,
password_hash(
/* salt in hex */
ENCODE(gen_random_bytes(16), 'hex'),
/* password */
$2::bytea
)
)
`,
username,
password,
)
_, err = result.RowsAffected()
return
}

View File

@ -1 +0,0 @@
v14