forked from jriou/coller
feat: Disable levels of encryptions by default
- Add `allow_client_encryption_key` option to allow encryption key provided by the client on the web UI (false by default) - Add `allow_no_encryption` option to allow notes without encryption (disabled by default) Signed-off-by: Julien Riou <julien@riou.xyz>
This commit is contained in:
parent
75bdab55df
commit
61ca30690b
6 changed files with 105 additions and 47 deletions
|
@ -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)
|
||||
|
|
|
@ -12,6 +12,8 @@ type Config struct {
|
|||
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"`
|
||||
|
|
|
@ -19,6 +19,8 @@ type CreateNoteHandler struct {
|
|||
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 {
|
||||
|
|
|
@ -26,6 +26,8 @@ type PageData struct {
|
|||
URL string
|
||||
Note *Note
|
||||
EnableUploadFileButton bool
|
||||
AllowClientEncryptionKey bool
|
||||
AllowNoEncryption bool
|
||||
BootstrapDirectory string
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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{
|
||||
|
@ -116,17 +133,20 @@ func (s *Server) Start() error {
|
|||
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,
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
</div>
|
||||
<div class="container text-center justify-content-center w-75 mb-4">
|
||||
<div class="row align-items-center">
|
||||
{{if .AllowClientEncryptionKey}}
|
||||
<div class="col-1">
|
||||
<label class="col-form-label col-form-label-sm" for="encryption-key">Encryption key</label>
|
||||
</div>
|
||||
|
@ -21,11 +22,14 @@
|
|||
title="Letters and numbers with length from 16 to 256" class="form-control" id="encryption-key"
|
||||
name="encryption-key">
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .AllowNoEncryption}}
|
||||
<div class="col-1">
|
||||
<input type="checkbox" class="form-check-input" for="no-encryption-key" id="no-encryption-key"
|
||||
value="no-encryption-key" name="no-encryption-key">
|
||||
<label class="col-form-label col-form-label-sm" for="no-encryption-key">No encryption</label>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="col-1">
|
||||
<input type="checkbox" class="form-check-input" for="delete-after-read" id="delete-after-read"
|
||||
value="delete-after-read" name="delete-after-read">
|
||||
|
@ -40,7 +44,8 @@
|
|||
<select class="form-select" aria-label="Expiration" id="expiration" name="expiration">
|
||||
<option disabled>Expiration</option>
|
||||
{{range $exp := .Expirations}}
|
||||
<option {{ if eq $exp $.Expiration }}selected="selected"{{end}} value="{{$exp}}">{{HumanDuration $exp}}</option>
|
||||
<option {{ if eq $exp $.Expiration }}selected="selected" {{end}} value="{{$exp}}">
|
||||
{{HumanDuration $exp}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</div>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue