diff --git a/README.md b/README.md index c51cd24..7e7c767 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,20 @@ overlayFSPath: /path/to/ots-customization # Languages not having a formal version will still display the normal # translations in the respective language. useFormalLanguage: false + +# Define which file types are selectable by the user when uploading +# files to attach. This fuels the `accept` attribute of the file +# select and requires the same format. Pay attention this is not +# suited as a security measure as this is purely a frontend +# implementation and can be circumvented. +# https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#accept +acceptedFileTypes: '' + +# Disable the file attachment functionality alltogether +disableFileAttachment: false + +# Define how big all attachments might be in bytes +maxAttachmentSizeTotal: 0 ``` To override the styling of the application have a look at the [`src/style.scss`](./src/style.scss) file how the theme of the application is built and present the compiled `app.css` in the `overlayFSPath`. diff --git a/customize.go b/customize.go index 4797fe5..bf808c5 100644 --- a/customize.go +++ b/customize.go @@ -12,16 +12,22 @@ import ( type ( customize struct { - AppIcon string `json:"appIcon,omitempty" yaml:"appIcon"` - AppTitle string `json:"appTitle,omitempty" yaml:"appTitle"` - DisableAppTitle bool `json:"disableAppTitle,omitempty" yaml:"disableAppTitle"` + AppIcon string `json:"appIcon,omitempty" yaml:"appIcon"` + AppTitle string `json:"appTitle,omitempty" yaml:"appTitle"` + DisableAppTitle bool `json:"disableAppTitle,omitempty" yaml:"disableAppTitle"` + DisablePoweredBy bool `json:"disablePoweredBy,omitempty" yaml:"disablePoweredBy"` + DisableQRSupport bool `json:"disableQRSupport,omitempty" yaml:"disableQRSupport"` + DisableThemeSwitcher bool `json:"disableThemeSwitcher,omitempty" yaml:"disableThemeSwitcher"` + DisableExpiryOverride bool `json:"disableExpiryOverride,omitempty" yaml:"disableExpiryOverride"` - DisablePoweredBy bool `json:"disablePoweredBy,omitempty" yaml:"disablePoweredBy"` - DisableQRSupport bool `json:"disableQRSupport,omitempty" yaml:"disableQRSupport"` - DisableThemeSwitcher bool `json:"disableThemeSwitcher,omitempty" yaml:"disableThemeSwitcher"` ExpiryChoices []int64 `json:"expiryChoices,omitempty" yaml:"expiryChoices"` - OverlayFSPath string `json:"-" yaml:"overlayFSPath"` - UseFormalLanguage bool `json:"-" yaml:"useFormalLanguage"` + + AcceptedFileTypes string `json:"acceptedFileTypes" yaml:"acceptedFileTypes"` + DisableFileAttachment bool `json:"disableFileAttachment" yaml:"disableFileAttachment"` + MaxAttachmentSizeTotal int64 `json:"maxAttachmentSizeTotal" yaml:"maxAttachmentSizeTotal"` + + OverlayFSPath string `json:"-" yaml:"overlayFSPath"` + UseFormalLanguage bool `json:"-" yaml:"useFormalLanguage"` } ) diff --git a/i18n.yaml b/i18n.yaml index 7dc24f4..51bf315 100644 --- a/i18n.yaml +++ b/i18n.yaml @@ -28,6 +28,7 @@ reference: text-burn-hint: Please remember not to go to this URL yourself as that would destroy the secret. Just pass it to someone else! text-burn-time: 'If not viewed before, this secret will automatically be deleted:' text-hint-burned: Attention: You're only seeing this once. As soon as you reload the page the secret will be gone so maybe copy it now… + text-max-filesize-exceeded: The file(s) you chose are too big to attach. text-powered-by: Powered by text-pre-reveal-hint: To reveal the secret click this button but be aware doing so will destroy the secret. You can only view it once! text-pre-url: 'Your secret was created and stored using this URL:' diff --git a/src/components/create.vue b/src/components/create.vue index 22d5161..db9ded2 100644 --- a/src/components/create.vue +++ b/src/components/create.vue @@ -38,7 +38,10 @@ rows="5" /> -
+
+
+ {{ $t('text-max-filesize-exceeded') }} +
@@ -133,6 +144,10 @@ export default { return choices }, + + maxFileSizeExceeded() { + return this.$root.customize.maxAttachmentSizeTotal !== 0 && this.fileSize > this.$root.customize.maxAttachmentSizeTotal + }, }, created() { @@ -142,6 +157,7 @@ export default { data() { return { canWrite: null, + fileSize: 0, secret: '', securePassword: null, selectedExpiry: null, @@ -168,7 +184,7 @@ export default { // createSecret executes the secret creation after encrypting the secret createSecret() { - if (this.secret.trim().length < 1) { + if (this.secret.trim().length < 1 || this.maxFileSizeExceeded) { return false } @@ -227,6 +243,15 @@ export default { return false }, + + updateFileSize() { + let cumSize = 0 + for (const f of [...this.$refs.createSecretFiles.files]) { + cumSize += f.size + } + + this.fileSize = cumSize + }, }, name: 'AppCreate', diff --git a/src/langs/langs.js b/src/langs/langs.js index 662565b..069eee0 100644 --- a/src/langs/langs.js +++ b/src/langs/langs.js @@ -10,7 +10,7 @@ export default { JSON.parse('{"alert-secret-not-found":"Das ist nicht das Secret, was du suchst\u0026hellip; - Falls du diesen Link noch nicht selbst geöffnet hast, könnte das Secret kompromittiert sein, da jemand anderes den Link geöffnet haben könnte.","alert-something-went-wrong":"Irgendwas ging schief. Entschuldigung\u0026hellip;","btn-create-secret":"Secret erstellen!","btn-new-secret":"Neues Secret","btn-reveal-secret":"Zeig mir das Secret!","btn-show-explanation":"Wie funktioniert das?","expire-default":"Server-Standard","expire-n-days":"{n} Tag | {n} Tage","expire-n-hours":"{n} Stunde | {n} Stunden","expire-n-minutes":"{n} Minute | {n} Minuten","expire-n-seconds":"{n} Sekunde | {n} Sekunden","items-explanation":["Du gibst ein Secret auf dieser Seite ein","Dein Browser verschlüsselt das Secret mit einem generierten Passwort","Nur das verschlüsselte Secret wird an den Server geschickt (das Passwort oder das Secret im Klartext werden niemals übertragen!)","Der Server speichert das verschlüsselte Secret für eine Weile","Du gibst die angezeigte URL, welche die ID und das Passwort des Secrets enthält, an den Empfänger","Der Empfänger kann das Secret einmalig abrufen: Funktioniert das nicht, könnte jemand anderes es abgerufen haben!","Wenn das verschlüsselte Secret das erste Mal abgerufen wurde, wird es automatisch vom Server gelöscht"],"label-expiry":"Ablauf in:","label-secret-data":"Inhalt des Secrets:","text-burn-hint":"Bitte rufe die URL nicht selbst auf, da das Secret dadurch zerstört würde. Gib sie einfach weiter!","text-burn-time":"Wenn es vorher nicht eingesehen wurde, wird dieses Secret automatisch gelöscht:","text-hint-burned":"\u003cstrong\u003eAchtung:\u003c/strong\u003e Du kannst das nur einmal ansehen! Sobald du die Seite neu lädst, ist das Secret verschwunden, also besser direkt kopieren und sicher abspeichern\u0026hellip;","text-powered-by":"Läuft mit","text-pre-reveal-hint":"Um das Secret anzuzeigen klicke diesen Button aber denk dran, dass das Secret nur einmal angezeigt und dabei gelöscht wird.","text-pre-url":"Dein Secret wurde angelegt und unter folgender URL gespeichert:","text-secret-create-disabled":"Auf dieser Instanz wurde das Erstellen neuer Secrets deaktiviert.","title-explanation":"So funktioniert es\u0026hellip;","title-new-secret":"Erstelle ein neues Secret","title-reading-secret":"Secret auslesen\u0026hellip;","title-secret-create-disabled":"Erstellen von Secrets deaktiviert…","title-secret-created":"Secret erstellt!"}'), ), - 'en': JSON.parse('{"alert-secret-not-found":"This is not the secret you are looking for\u0026hellip; - If you expected the secret to be here it might be compromised as someone else might have opened the link already.","alert-something-went-wrong":"Something went wrong. I\'m very sorry about this\u0026hellip;","btn-create-secret":"Create the secret!","btn-new-secret":"New Secret","btn-reveal-secret":"Show me the secret!","btn-show-explanation":"How does this work?","expire-default":"Default Expiry","expire-n-days":"{n} day | {n} days","expire-n-hours":"{n} hour | {n} hours","expire-n-minutes":"{n} minute | {n} minutes","expire-n-seconds":"{n} second | {n} seconds","items-explanation":["You enter a secret into the field on this page","Your browser encrypts the secret using a generated password","Only the encrypted secret is sent to the server (neither the plain secret nor the password are ever sent!)","The server stores the encrypted secret for a certain time","You pass the displayed URL containing the ID and the decryption password to the recipient","The recipient can view the secret exactly once: If they can\'t, the secret might have been viewed by someone else!","After the encrypted secret has been retrieved once, it is deleted from the server"],"label-expiry":"Expire in:","label-secret-data":"Secret data:","label-secret-files":"Files to attach:","text-attached-files":"The sender attached files to the secret. Click to download them but make sure you trust the sender when using them:","text-burn-hint":"Please remember not to go to this URL yourself as that would destroy the secret. Just pass it to someone else!","text-burn-time":"If not viewed before, this secret will automatically be deleted:","text-hint-burned":"\u003cstrong\u003eAttention:\u003c/strong\u003e You\'re only seeing this once. As soon as you reload the page the secret will be gone so maybe copy it now\u0026hellip;","text-powered-by":"Powered by","text-pre-reveal-hint":"To reveal the secret click this button but be aware doing so will destroy the secret. You can only view it once!","text-pre-url":"Your secret was created and stored using this URL:","text-secret-create-disabled":"The creation of new secrets is disabled in this instance.","title-explanation":"This is how it works\u0026hellip;","title-new-secret":"Create a new secret","title-reading-secret":"Reading your secret\u0026hellip;","title-secret-create-disabled":"Secret creation disabled…","title-secret-created":"Secret created!"}'), + 'en': JSON.parse('{"alert-secret-not-found":"This is not the secret you are looking for\u0026hellip; - If you expected the secret to be here it might be compromised as someone else might have opened the link already.","alert-something-went-wrong":"Something went wrong. I\'m very sorry about this\u0026hellip;","btn-create-secret":"Create the secret!","btn-new-secret":"New Secret","btn-reveal-secret":"Show me the secret!","btn-show-explanation":"How does this work?","expire-default":"Default Expiry","expire-n-days":"{n} day | {n} days","expire-n-hours":"{n} hour | {n} hours","expire-n-minutes":"{n} minute | {n} minutes","expire-n-seconds":"{n} second | {n} seconds","items-explanation":["You enter a secret into the field on this page","Your browser encrypts the secret using a generated password","Only the encrypted secret is sent to the server (neither the plain secret nor the password are ever sent!)","The server stores the encrypted secret for a certain time","You pass the displayed URL containing the ID and the decryption password to the recipient","The recipient can view the secret exactly once: If they can\'t, the secret might have been viewed by someone else!","After the encrypted secret has been retrieved once, it is deleted from the server"],"label-expiry":"Expire in:","label-secret-data":"Secret data:","label-secret-files":"Files to attach:","text-attached-files":"The sender attached files to the secret. Click to download them but make sure you trust the sender when using them:","text-burn-hint":"Please remember not to go to this URL yourself as that would destroy the secret. Just pass it to someone else!","text-burn-time":"If not viewed before, this secret will automatically be deleted:","text-hint-burned":"\u003cstrong\u003eAttention:\u003c/strong\u003e You\'re only seeing this once. As soon as you reload the page the secret will be gone so maybe copy it now\u0026hellip;","text-max-filesize-exceeded":"The file(s) you chose are too big to attach.","text-powered-by":"Powered by","text-pre-reveal-hint":"To reveal the secret click this button but be aware doing so will destroy the secret. You can only view it once!","text-pre-url":"Your secret was created and stored using this URL:","text-secret-create-disabled":"The creation of new secrets is disabled in this instance.","title-explanation":"This is how it works\u0026hellip;","title-new-secret":"Create a new secret","title-reading-secret":"Reading your secret\u0026hellip;","title-secret-create-disabled":"Secret creation disabled…","title-secret-created":"Secret created!"}'), 'es': JSON.parse('{"alert-secret-not-found":"Este no es el secreto que buscas\u0026hellip; - Si esperabas que el secreto estuviera aquí, es posible que se haya visto comprometido, ya que otra persona podría haber abierto el enlace en tu lugar.","alert-something-went-wrong":"Algo ha salido mal. Lo sentimos mucho\u0026hellip;","btn-create-secret":"¡Crea el secreto!","btn-new-secret":"Nuevo secreto","btn-reveal-secret":"¡Muéstrame el secreto!","btn-show-explanation":"¿Cómo funciona?","expire-default":"Caducidad predeterminada","expire-n-days":"{n} día | {n} días","expire-n-hours":"{n} hora | {n} horas","expire-n-minutes":"{n} minuto | {n} minutos","expire-n-seconds":"{n} segundo | {n} segundos","items-explanation":["Introduce un secreto en el formulario que hay en esta página","Tu navegador cifra el secreto utilizando una contraseña generada","Únicamente se envía al servidor el secreto cifrado (¡nunca se envían ni el secreto sin cifrar ni la contraseña!)","El servidor almacena el secreto cifrado durante un tiempo limitado","Envía al destinatario el enlace mostrado, que contiene el identificador del secreto y la contraseña de descifrado","El destinatario puede ver el secreto una sola vez: si no puede, ¡el secreto podría haber sido visto por otra persona!","Cuando se ha obtenido por primera y única vez el secreto cifrado, se elimina del servidor"],"label-expiry":"Caduca en:","label-secret-data":"Información secreta:","text-burn-hint":"Por favor, recuerda no acceder a este enlace tú mismo, ya que esto destruiría el secreto. ¡Solo tienes que pasárselo a otra persona!","text-burn-time":"Si no se muestra antes, este secreto se eliminará automáticamente:","text-hint-burned":"\u003cstrong\u003eAtención:\u003c/strong\u003e Solo verás esto una vez. En cuanto recargues la página, el secreto desaparecerá, así que cópialo ya\u0026hellip;","text-powered-by":"Funciona con","text-pre-reveal-hint":"Para mostrar el secreto pulsa este botón, pero ten en cuenta que al hacerlo se destruirá. ¡Solo puedes verlo una vez!","text-pre-url":"Tu secreto ha sido creado y almacenado en el siguiente enlace:","text-secret-create-disabled":"La creación de nuevos secretos está desactivada en esta instancia.","title-explanation":"Así es como funciona\u0026hellip;","title-new-secret":"Crea un nuevo secreto","title-reading-secret":"Obteniendo tu secreto\u0026hellip;","title-secret-create-disabled":"Creación de secretos desactivada...","title-secret-created":"¡Secreto creado!"}'),