forked from jriou/coller
feat: Rename password by encryption key
Signed-off-by: Julien Riou <julien@riou.xyz>
This commit is contained in:
parent
634326190c
commit
8e1dd686d3
16 changed files with 118 additions and 117 deletions
|
@ -22,17 +22,17 @@ Create from file:
|
|||
coller -file filename.txt
|
||||
```
|
||||
|
||||
Provide password for encryption:
|
||||
Provide encryption key:
|
||||
|
||||
```
|
||||
coller -ask-password
|
||||
coller -password PASSWORD
|
||||
coller -ask-encryption-key
|
||||
coller -encryption-key ENCRYPTION_KEY
|
||||
```
|
||||
|
||||
Create public note:
|
||||
Create a note in cleartext:
|
||||
|
||||
```
|
||||
coller -no-password
|
||||
coller -no-encryption
|
||||
```
|
||||
|
||||
Return the copier command to use client-side decryption instead of the URL:
|
||||
|
|
|
@ -64,10 +64,10 @@ func handleMain() int {
|
|||
configFile := flag.String("config", filepath.Join(homeDir, ".config", AppName+".json"), "Configuration file")
|
||||
reconfigure := flag.Bool("reconfigure", false, "Re-create configuration file")
|
||||
url := flag.String("url", "", "URL of the coller API")
|
||||
password := flag.String("password", os.Getenv("COLLER_PASSWORD"), "Password to encrypt the note")
|
||||
askPassword := flag.Bool("ask-password", false, "Read password from input")
|
||||
noPassword := flag.Bool("no-password", false, "Allow notes without password")
|
||||
passwordLength := flag.Int("password-length", 16, "Length of the auto-generated password")
|
||||
encryptionKey := flag.String("encryption-key", os.Getenv("COLLER_ENCRYPTION_KEY"), "Key to encrypt the note")
|
||||
askEncryptionKey := flag.Bool("ask-encryption-key", false, "Read encryption key from input")
|
||||
noEncryption := flag.Bool("no-encryption", false, "Allow notes without encryption key")
|
||||
encryptionKeyLength := flag.Int("encryption-key-length", 16, "Length of the auto-generated encryption key")
|
||||
flag.StringVar(&fileName, "file", "", "Read content of the note from a file")
|
||||
expiration := flag.Int("expiration", 0, "Number of seconds before expiration")
|
||||
deleteAfterRead := flag.Bool("delete-after-read", false, "Delete the note after the first read")
|
||||
|
@ -140,22 +140,22 @@ func handleMain() int {
|
|||
content = clipboard.Read(clipboard.FmtText)
|
||||
}
|
||||
|
||||
if *askPassword {
|
||||
fmt.Print("Password: ")
|
||||
if *askEncryptionKey {
|
||||
fmt.Print("Encryption key: ")
|
||||
p, err := term.ReadPassword(int(syscall.Stdin))
|
||||
if err != nil {
|
||||
return internal.ReturnError(logger, "could not read password", err)
|
||||
return internal.ReturnError(logger, "could not read encryption key", err)
|
||||
}
|
||||
*password = string(p)
|
||||
*encryptionKey = string(p)
|
||||
fmt.Print("\n")
|
||||
}
|
||||
|
||||
if !*noPassword && *password == "" {
|
||||
logger.Debug("generating random password")
|
||||
if *passwordLength < internal.MIN_PASSWORD_LENGTH || *passwordLength > internal.MAX_PASSWORD_LENGTH {
|
||||
return internal.ReturnError(logger, "invalid password length for auto-generated password", fmt.Errorf("password length must be between %d and %d", internal.MIN_PASSWORD_LENGTH, internal.MAX_PASSWORD_LENGTH))
|
||||
if !*noEncryption && *encryptionKey == "" {
|
||||
logger.Debug("generating random encryption key")
|
||||
if *encryptionKeyLength < internal.MIN_ENCRYPTION_KEY_LENGTH || *encryptionKeyLength > internal.MAX_ENCRYPTION_KEY_LENGTH {
|
||||
return internal.ReturnError(logger, "invalid length of auto-generated encryption key", fmt.Errorf("encryption key length must be between %d and %d", internal.MIN_ENCRYPTION_KEY_LENGTH, internal.MAX_ENCRYPTION_KEY_LENGTH))
|
||||
}
|
||||
*password = internal.GenerateChars(*passwordLength)
|
||||
*encryptionKey = internal.GenerateChars(*encryptionKeyLength)
|
||||
}
|
||||
|
||||
if len(content) == 0 {
|
||||
|
@ -173,13 +173,13 @@ func handleMain() int {
|
|||
p.Language = *language
|
||||
}
|
||||
|
||||
if *password != "" {
|
||||
logger.Debug("validating password")
|
||||
if err = internal.ValidatePassword(*password); err != nil {
|
||||
return internal.ReturnError(logger, "invalid password", nil)
|
||||
if *encryptionKey != "" {
|
||||
logger.Debug("validating encryption key")
|
||||
if err = internal.ValidateEncryptionKey(*encryptionKey); err != nil {
|
||||
return internal.ReturnError(logger, "invalid encryption key", nil)
|
||||
}
|
||||
logger.Debug("encrypting content")
|
||||
content, err = internal.Encrypt(content, *password)
|
||||
content, err = internal.Encrypt(content, *encryptionKey)
|
||||
if err != nil {
|
||||
return internal.ReturnError(logger, "could not encrypt note", err)
|
||||
}
|
||||
|
@ -242,21 +242,21 @@ func handleMain() int {
|
|||
logger.Debug("finding note location")
|
||||
var location string
|
||||
noteURL := *url + "/" + jsonBody.ID
|
||||
if *password != "" {
|
||||
if *encryptionKey != "" {
|
||||
if *copier {
|
||||
location = fmt.Sprintf("copier -password %s %s", *password, noteURL)
|
||||
location = fmt.Sprintf("copier -encryption-key %s %s", *encryptionKey, noteURL)
|
||||
} else {
|
||||
if *html {
|
||||
location = fmt.Sprintf("%s/%s.html", noteURL, *password)
|
||||
location = fmt.Sprintf("%s/%s.html", noteURL, *encryptionKey)
|
||||
} else {
|
||||
location = fmt.Sprintf("%s/%s", noteURL, *password)
|
||||
location = fmt.Sprintf("%s/%s", noteURL, *encryptionKey)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if *html {
|
||||
location = fmt.Sprintf("%s.html", noteURL)
|
||||
} else {
|
||||
location = fmt.Sprintf("%s", noteURL)
|
||||
location = noteURL
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ The file format is **JSON**:
|
|||
* **database_type** (string): Type of the database (default "sqlite", "postgres" also supported)
|
||||
* **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))
|
||||
* **password_length** (int): Number of characters for generated passwords (default 16)
|
||||
* **encryption_key_length** (int): Number of characters for generated encryption key (default 16)
|
||||
* **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)
|
||||
|
@ -52,7 +52,7 @@ Create a note.
|
|||
|
||||
Body (JSON):
|
||||
* **content** (string): base64 encoded content (required)
|
||||
* **password** (string): use server-side encryption with this password
|
||||
* **encryption_key** (string): use server-side encryption with this encryption key
|
||||
* **encrypted** (bool): true if the content has been encrypted by the client
|
||||
* **expiration** (int): lifetime of the note in seconds (must be supported by the server)
|
||||
* **delete_after_read** (bool): delete the note after the first read
|
||||
|
@ -62,12 +62,12 @@ Response (JSON):
|
|||
* **id** (string): ID of the note
|
||||
|
||||
|
||||
### GET /\<id\>/\<password\>
|
||||
### GET /\<id\>/\<encryptionKey\>
|
||||
|
||||
> [!WARNING]
|
||||
> Potential password leak
|
||||
> Potential encryption key leak
|
||||
|
||||
Return content of a note encrypted by the given password.
|
||||
Return content of a note encrypted by the given encryption key.
|
||||
|
||||
### GET /\<id\>
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ func handleMain() int {
|
|||
return internal.ReturnError(logger, "could not create server", err)
|
||||
}
|
||||
|
||||
srv.SetPasswordLength(config.PasswordLength)
|
||||
srv.SetEncryptionKeyLength(config.EncryptionKeyLength)
|
||||
|
||||
if config.EnableMetrics {
|
||||
reg := prometheus.NewRegistry()
|
||||
|
|
|
@ -11,6 +11,6 @@ copier -help
|
|||
# Examples
|
||||
|
||||
```
|
||||
copier -password PASSWORD URL
|
||||
copier -ask-password URL
|
||||
copier -encryption-key ENCRYPTION_KEY URL
|
||||
copier -ask-encryption-key URL
|
||||
```
|
|
@ -9,8 +9,9 @@ import (
|
|||
"os"
|
||||
"syscall"
|
||||
|
||||
"git.riou.xyz/jriou/coller/internal"
|
||||
"golang.org/x/term"
|
||||
|
||||
"git.riou.xyz/jriou/coller/internal"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -28,8 +29,8 @@ func handleMain() int {
|
|||
quiet := flag.Bool("quiet", false, "Log errors only")
|
||||
verbose := flag.Bool("verbose", false, "Print more logs")
|
||||
debug := flag.Bool("debug", false, "Print even more logs")
|
||||
password := flag.String("password", os.Getenv("COLLER_PASSWORD"), "Password to decrypt the note")
|
||||
askPassword := flag.Bool("ask-password", false, "Read password from input")
|
||||
encryptionKey := flag.String("encryption-key", os.Getenv("COLLER_ENCRYPTION_KEY"), "Key to decrypt the note")
|
||||
askEncryptionKey := flag.Bool("ask-encryption-key", false, "Read encryption key from input")
|
||||
fileName := flag.String("file", "", "Write content of the note to a file")
|
||||
bearer := flag.String("bearer", os.Getenv("COLLER_BEARER"), "Bearer token")
|
||||
askBearer := flag.Bool("ask-bearer", false, "Read bearer token from input")
|
||||
|
@ -60,13 +61,13 @@ func handleMain() int {
|
|||
}
|
||||
logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: level}))
|
||||
|
||||
if *askPassword {
|
||||
fmt.Print("Password: ")
|
||||
if *askEncryptionKey {
|
||||
fmt.Print("Encryption key: ")
|
||||
p, err := term.ReadPassword(int(syscall.Stdin))
|
||||
if err != nil {
|
||||
return internal.ReturnError(logger, "could not read password", err)
|
||||
return internal.ReturnError(logger, "could not read encryption key", err)
|
||||
}
|
||||
*password = string(p)
|
||||
*encryptionKey = string(p)
|
||||
fmt.Print("\n")
|
||||
}
|
||||
|
||||
|
@ -102,11 +103,11 @@ func handleMain() int {
|
|||
}
|
||||
|
||||
var content []byte
|
||||
if *password != "" {
|
||||
if *encryptionKey != "" {
|
||||
logger.Debug("decrypting note")
|
||||
content, err = internal.Decrypt(body, *password)
|
||||
content, err = internal.Decrypt(body, *encryptionKey)
|
||||
if err != nil {
|
||||
return internal.ReturnError(logger, "could not decrypt paste", err)
|
||||
return internal.ReturnError(logger, "could not decrypt note", err)
|
||||
}
|
||||
} else {
|
||||
content = body
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue