diff --git a/src/cmd/collerd/README.md b/src/cmd/collerd/README.md index ca8674d..4ad8b1e 100644 --- a/src/cmd/collerd/README.md +++ b/src/cmd/collerd/README.md @@ -20,6 +20,8 @@ The file format is **JSON**: * **database_dsn** (string): Connection string for the database (default "collerd.db") * **node_id** (int): Number between 0 and 1023 to define the node generating identifiers (see [snowflake](https://github.com/bwmarrin/snowflake)) * **encryption_key_length** (int): Number of characters for generated encryption key (default 16) +* **allow_client_encryption_key** (bool): Allow encryption key provided by the client on the web UI +* **allow_no_encryption** (bool): Allow notes without encryption * **expiration_interval** (int): Number of seconds to wait between two expiration runs * **listen_address** (string): Address to listen for the web server (default "0.0.0.0") * **listen_port** (int): Port to listen for the web server (default 8080) diff --git a/src/server/config.go b/src/server/config.go index f2a6a6b..ea5e5d2 100644 --- a/src/server/config.go +++ b/src/server/config.go @@ -7,28 +7,30 @@ import ( ) type Config struct { - Title string `json:"title"` - DatabaseType string `json:"database_type"` - DatabaseDsn string `json:"database_dsn"` - NodeID int64 `json:"node_id"` - EncryptionKeyLength int `json:"encryption_key_length"` - ExpirationInterval int `json:"expiration_interval"` - ListenAddress string `json:"listen_address"` - ListenPort int `json:"listen_port"` - Expirations []int `json:"expirations"` - Expiration int `json:"expiration"` - MaxUploadSize int64 `json:"max_upload_size"` - ShowVersion bool `json:"show_version"` - EnableMetrics bool `json:"enable_metrics"` - PrometheusRoute string `json:"prometheus_route"` - PrometheusNotesMetric string `json:"prometheus_notes_metric"` - ObservationInterval int `json:"observation_internal"` - Languages []string `json:"languages"` - Language string `json:"language"` - EnableUploadFileButton bool `json:"enable_upload_file_button"` - TLSCertFile string `json:"tls_cert_file"` - TLSKeyFile string `json:"tls_key_file"` - BootstrapDirectory string `json:"bootstrap_directory"` + Title string `json:"title"` + DatabaseType string `json:"database_type"` + DatabaseDsn string `json:"database_dsn"` + NodeID int64 `json:"node_id"` + EncryptionKeyLength int `json:"encryption_key_length"` + AllowClientEncryptionKey bool `json:"allow_client_encryption_key"` + AllowNoEncryption bool `json:"allow_no_encryption"` + ExpirationInterval int `json:"expiration_interval"` + ListenAddress string `json:"listen_address"` + ListenPort int `json:"listen_port"` + Expirations []int `json:"expirations"` + Expiration int `json:"expiration"` + MaxUploadSize int64 `json:"max_upload_size"` + ShowVersion bool `json:"show_version"` + EnableMetrics bool `json:"enable_metrics"` + PrometheusRoute string `json:"prometheus_route"` + PrometheusNotesMetric string `json:"prometheus_notes_metric"` + ObservationInterval int `json:"observation_internal"` + Languages []string `json:"languages"` + Language string `json:"language"` + EnableUploadFileButton bool `json:"enable_upload_file_button"` + TLSCertFile string `json:"tls_cert_file"` + TLSKeyFile string `json:"tls_key_file"` + BootstrapDirectory string `json:"bootstrap_directory"` } func NewConfig() *Config { diff --git a/src/server/handlers_api.go b/src/server/handlers_api.go index 47bc512..51852c3 100644 --- a/src/server/handlers_api.go +++ b/src/server/handlers_api.go @@ -16,9 +16,11 @@ func HealthHandler(w http.ResponseWriter, r *http.Request) { } type CreateNoteHandler struct { - logger *slog.Logger - db *Database - maxUploadSize int64 + logger *slog.Logger + db *Database + maxUploadSize int64 + allowClientEncryptionKey bool + allowNoEncryption bool } type CreateNotePayload struct { @@ -47,6 +49,16 @@ func (h *CreateNoteHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } + if !h.allowNoEncryption && !body.Encrypted { + WriteError(w, "could not create note", fmt.Errorf("encryption is mandatory")) + return + } + + if !h.allowClientEncryptionKey && body.EncryptionKey != "" { + WriteError(w, "could not create note", fmt.Errorf("client encryption key is not allowed")) + return + } + content, err := internal.Decode(body.Content) if err != nil { diff --git a/src/server/handlers_web.go b/src/server/handlers_web.go index 896169e..813929a 100644 --- a/src/server/handlers_web.go +++ b/src/server/handlers_web.go @@ -17,16 +17,18 @@ import ( ) type PageData struct { - Title string - Version string - Expirations []int - Expiration int - Languages []string - Err error - URL string - Note *Note - EnableUploadFileButton bool - BootstrapDirectory string + Title string + Version string + Expirations []int + Expiration int + Languages []string + Err error + URL string + Note *Note + EnableUploadFileButton bool + AllowClientEncryptionKey bool + AllowNoEncryption bool + BootstrapDirectory string } type HomeHandler struct { @@ -115,7 +117,17 @@ func (h *CreateNoteWithFormHandler) ServeHTTP(w http.ResponseWriter, r *http.Req deleteAfterRead := r.FormValue("delete-after-read") language := r.FormValue("language") - if encryptionKey == "" && noEncryption == "" { + if !h.PageData.AllowNoEncryption && noEncryption != "" { + h.PageData.Err = fmt.Errorf("encryption is mandatory") + h.Templates.ExecuteTemplate(w, templateName, h.PageData) + } + + if !h.PageData.AllowClientEncryptionKey && encryptionKey != "" { + h.PageData.Err = fmt.Errorf("client encryption key is not allowed") + h.Templates.ExecuteTemplate(w, templateName, h.PageData) + } + + if !h.PageData.AllowClientEncryptionKey && encryptionKey == "" && noEncryption == "" { h.logger.Debug("generating encryption key") encryptionKey = internal.GenerateChars(encryptionKeyLength) } diff --git a/src/server/server.go b/src/server/server.go index 85e494c..87b8aec 100644 --- a/src/server/server.go +++ b/src/server/server.go @@ -99,9 +99,26 @@ func (s *Server) Start() error { } // API - r.Path("/api/note").Handler(&CreateNoteHandler{logger: s.logger, db: s.db, maxUploadSize: s.config.MaxUploadSize}).Methods("POST") - r.Path("/{id:[a-zA-Z0-9]+}/{encryptionKey:[a-zA-Z0-9]+}").Handler(&GetEncryptedNoteHandler{logger: s.logger, db: s.db}).Methods("GET") - r.Path("/{id:[a-zA-Z0-9]+}").Handler(&GetNoteHandler{logger: s.logger, db: s.db}).Methods("GET") + createNoteHandler := &CreateNoteHandler{ + logger: s.logger, + db: s.db, + maxUploadSize: s.config.MaxUploadSize, + allowClientEncryptionKey: s.config.AllowClientEncryptionKey, + allowNoEncryption: s.config.AllowNoEncryption, + } + r.Path("/api/note").Handler(createNoteHandler).Methods("POST") + + getEncryptedNoteHandler := &GetEncryptedNoteHandler{ + logger: s.logger, + db: s.db, + } + r.Path("/{id:[a-zA-Z0-9]+}/{encryptionKey:[a-zA-Z0-9]+}").Handler(getEncryptedNoteHandler).Methods("GET") + + getNoteHandler := &GetNoteHandler{ + logger: s.logger, + db: s.db, + } + r.Path("/{id:[a-zA-Z0-9]+}").Handler(getNoteHandler).Methods("GET") // Web pages funcs := template.FuncMap{ @@ -111,22 +128,25 @@ func (s *Server) Start() error { "string": func(b []byte) string { return string(b) }, } p := PageData{ - Title: s.config.Title, - Expirations: s.config.Expirations, - Expiration: s.config.Expiration, - Languages: s.config.Languages, - BootstrapDirectory: s.config.BootstrapDirectory, + Title: s.config.Title, + Expirations: s.config.Expirations, + Expiration: s.config.Expiration, + Languages: s.config.Languages, + BootstrapDirectory: s.config.BootstrapDirectory, + EnableUploadFileButton: s.config.EnableUploadFileButton, + AllowClientEncryptionKey: s.config.AllowClientEncryptionKey, + AllowNoEncryption: s.config.AllowNoEncryption, } if s.config.ShowVersion { p.Version = s.version } - p.EnableUploadFileButton = s.config.EnableUploadFileButton templates, err := template.New("templates").Funcs(funcs).ParseFS(templatesFS, "templates/*.html") if err != nil { return err } + createNoteWithFormHandler := &CreateNoteWithFormHandler{ Templates: templates, PageData: p, @@ -142,7 +162,12 @@ func (s *Server) Start() error { logger: s.logger, } r.Path("/clients.html").Handler(clientsHandler).Methods("GET") - r.Path("/clients/{os:[a-z]+}-{arch:[a-z0-9]+}/{clientName:[a-z]+}").Handler(&ClientHandler{logger: s.logger, version: p.Version}).Methods("GET") + + clientHandler := &ClientHandler{ + logger: s.logger, + version: p.Version, + } + r.Path("/clients/{os:[a-z]+}-{arch:[a-z0-9]+}/{clientName:[a-z]+}").Handler(clientHandler).Methods("GET") encryptedWebNoteHandler := &GetEncryptedWebNoteHandler{ Templates: templates, diff --git a/src/server/templates/index.html b/src/server/templates/index.html index f7319e9..a6363c1 100644 --- a/src/server/templates/index.html +++ b/src/server/templates/index.html @@ -13,6 +13,7 @@
+ {{if .AllowClientEncryptionKey}}
@@ -21,11 +22,14 @@ title="Letters and numbers with length from 16 to 256" class="form-control" id="encryption-key" name="encryption-key">
+ {{end}} + {{if .AllowNoEncryption}}
+ {{end}}
@@ -40,7 +44,8 @@