[#148] Make secret optional when files are attached (#150)

This commit is contained in:
Knut Ahlers 2023-11-20 15:52:06 +01:00 committed by GitHub
parent 62d2897e44
commit 8d29e5f6ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 56 additions and 26 deletions

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"bytes"
"fmt" "fmt"
"io" "io"
"mime" "mime"
@ -37,6 +38,7 @@ func init() {
createCmd.Flags().StringSliceP("header", "H", nil, "Headers to include in the request (i.e. 'Authorization: Token ...')") createCmd.Flags().StringSliceP("header", "H", nil, "Headers to include in the request (i.e. 'Authorization: Token ...')")
createCmd.Flags().String("instance", "https://ots.fyi/", "Instance to create the secret with") createCmd.Flags().String("instance", "https://ots.fyi/", "Instance to create the secret with")
createCmd.Flags().StringSliceP("file", "f", nil, "File(s) to attach to the secret") createCmd.Flags().StringSliceP("file", "f", nil, "File(s) to attach to the secret")
createCmd.Flags().Bool("no-text", false, "Disable secret read (create a secret with only files)")
createCmd.Flags().String("secret-from", "-", `File to read the secret content from ("-" for STDIN)`) createCmd.Flags().String("secret-from", "-", `File to read the secret content from ("-" for STDIN)`)
createCmd.Flags().StringP("user", "u", "", "Username / Password for basic auth, specified as 'user:pass'") createCmd.Flags().StringP("user", "u", "", "Username / Password for basic auth, specified as 'user:pass'")
rootCmd.AddCommand(createCmd) rootCmd.AddCommand(createCmd)
@ -51,29 +53,10 @@ func createRunE(cmd *cobra.Command, _ []string) (err error) {
// Read the secret content // Read the secret content
logrus.Info("reading secret content...") logrus.Info("reading secret content...")
secretSourceName, err := cmd.Flags().GetString("secret-from") if secret.Secret, err = getSecretContent(cmd); err != nil {
if err != nil { return fmt.Errorf("getting secret content: %w", err)
return fmt.Errorf("getting secret-from flag: %w", err)
} }
var secretSource io.Reader
if secretSourceName == "-" {
secretSource = os.Stdin
} else {
f, err := os.Open(secretSourceName) //#nosec:G304 // Opening user specified file is intended
if err != nil {
return fmt.Errorf("opening secret-from file: %w", err)
}
defer f.Close() //nolint:errcheck // The file will be force-closed by program exit
secretSource = f
}
secretContent, err := io.ReadAll(secretSource)
if err != nil {
return fmt.Errorf("reading secret content: %w", err)
}
secret.Secret = string(secretContent)
// Attach any file given // Attach any file given
files, err := cmd.Flags().GetStringSlice("file") files, err := cmd.Flags().GetStringSlice("file")
if err != nil { if err != nil {
@ -93,6 +76,10 @@ func createRunE(cmd *cobra.Command, _ []string) (err error) {
}) })
} }
if secret.Secret == "" && secret.Attachments == nil {
return fmt.Errorf("secret has no content and no attachments")
}
// Get flags for creation // Get flags for creation
logrus.Info("creating the secret...") logrus.Info("creating the secret...")
instanceURL, err := cmd.Flags().GetString("instance") instanceURL, err := cmd.Flags().GetString("instance")
@ -158,6 +145,42 @@ func constructHTTPClient(cmd *cobra.Command) (*http.Client, error) {
return &http.Client{Transport: t}, nil return &http.Client{Transport: t}, nil
} }
func getSecretContent(cmd *cobra.Command) (string, error) {
secretSourceName, err := cmd.Flags().GetString("secret-from")
if err != nil {
return "", fmt.Errorf("getting secret-from flag: %w", err)
}
noSecret, err := cmd.Flags().GetBool("no-text")
if err != nil {
return "", fmt.Errorf("getting no-text flag: %w", err)
}
var secretSource io.Reader
switch {
case noSecret:
secretSource = bytes.NewReader(nil)
case secretSourceName == "-":
secretSource = os.Stdin
default:
f, err := os.Open(secretSourceName) //#nosec:G304 // Opening user specified file is intended
if err != nil {
return "", fmt.Errorf("opening secret-from file: %w", err)
}
defer f.Close() //nolint:errcheck // The file will be force-closed by program exit
secretSource = f
}
secretContent, err := io.ReadAll(secretSource)
if err != nil {
return "", fmt.Errorf("reading secret content: %w", err)
}
return strings.TrimSpace(string(secretContent)), nil
}
func (a authRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) { func (a authRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
if a.user != "" { if a.user != "" {
r.SetBasicAuth(a.user, a.pass) r.SetBasicAuth(a.user, a.pass)

View File

@ -72,7 +72,7 @@
<button <button
type="submit" type="submit"
class="btn btn-success" class="btn btn-success"
:disabled="secret.trim().length < 1 || maxFileSizeExceeded || invalidFilesSelected || createRunning" :disabled="!canCreate"
> >
<template v-if="!createRunning"> <template v-if="!createRunning">
{{ $t('btn-create-secret') }} {{ $t('btn-create-secret') }}
@ -148,6 +148,10 @@ const passwordLength = 20
export default { export default {
computed: { computed: {
canCreate() {
return (this.secret.trim().length > 0 || this.selectedFileMeta.length > 0) && !this.maxFileSizeExceeded && !this.invalidFilesSelected
},
expiryChoices() { expiryChoices() {
const choices = [{ text: this.$t('expire-default'), value: null }] const choices = [{ text: this.$t('expire-default'), value: null }]
for (const choice of this.$root.customize.expiryChoices || defaultExpiryChoices) { for (const choice of this.$root.customize.expiryChoices || defaultExpiryChoices) {
@ -243,7 +247,7 @@ export default {
// createSecret executes the secret creation after encrypting the secret // createSecret executes the secret creation after encrypting the secret
createSecret() { createSecret() {
if (this.secret.trim().length < 1 || this.maxFileSizeExceeded || this.invalidFilesSelected) { if (!this.canCreate) {
return false return false
} }

View File

@ -6,7 +6,7 @@
v-html="$t('title-reading-secret')" v-html="$t('title-reading-secret')"
/> />
<div class="card-body"> <div class="card-body">
<template v-if="!secret"> <template v-if="!secret && files.length === 0">
<p v-html="$t('text-pre-reveal-hint')" /> <p v-html="$t('text-pre-reveal-hint')" />
<button <button
class="btn btn-success" class="btn btn-success"
@ -23,7 +23,10 @@
</button> </button>
</template> </template>
<template v-else> <template v-else>
<div class="input-group mb-3"> <div
v-if="secret"
class="input-group mb-3"
>
<textarea <textarea
class="form-control" class="form-control"
readonly readonly
@ -47,7 +50,6 @@
</div> </div>
</div> </div>
</div> </div>
<p v-html="$t('text-hint-burned')" />
<template v-if="files.length > 0"> <template v-if="files.length > 0">
<p v-html="$t('text-attached-files')" /> <p v-html="$t('text-attached-files')" />
<ul> <ul>
@ -64,6 +66,7 @@
</li> </li>
</ul> </ul>
</template> </template>
<p v-html="$t('text-hint-burned')" />
</template> </template>
</div> </div>
</div> </div>