diff --git a/README.md b/README.md deleted file mode 100644 index 9de30de..0000000 --- a/README.md +++ /dev/null @@ -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 -``` diff --git a/TODO b/TODO index fa84dd8..e28d5fb 100644 --- a/TODO +++ b/TODO @@ -4,6 +4,7 @@ - per file - when deleting node and child nodes * Move node +* Tree titles should be user-select none Long term diff --git a/db.go b/db.go index 65e189f..f8df736 100644 --- a/db.go +++ b/db.go @@ -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) {// {{{ diff --git a/main.go b/main.go index 75e8a43..8ea96d4 100644 --- a/main.go +++ b/main.go @@ -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 @@ -545,7 +524,7 @@ func nodeDownload(w http.ResponseWriter, r *http.Request) { // {{{ responseError(w, fmt.Errorf("File not found")) return } - + var file *os.File fname := filepath.Join( config.Application.Directories.Upload, @@ -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 diff --git a/static/css/main.css b/static/css/main.css index 25b2239..552928f 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -205,7 +205,6 @@ header .menu { #tree .node .name { white-space: nowrap; cursor: pointer; - user-select: none; } #tree .node .name:hover { color: #ecbf00; diff --git a/static/less/main.less b/static/less/main.less index d1da164..c885ec8 100644 --- a/static/less/main.less +++ b/static/less/main.less @@ -232,7 +232,6 @@ header { .name { white-space: nowrap; cursor: pointer; - user-select: none; &:hover { color: @accent_2; diff --git a/user.go b/user.go index c195b90..0d9b4ee 100644 --- a/user.go +++ b/user.go @@ -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 -} diff --git a/version b/version deleted file mode 100644 index 958b5a3..0000000 --- a/version +++ /dev/null @@ -1 +0,0 @@ -v14