diff --git a/History.md b/History.md
index 46b9956..f41a95f 100644
--- a/History.md
+++ b/History.md
@@ -143,7 +143,7 @@
* Only mention tool name in footer (#71)
* Replace redis client, move expiry into creation interface
-With this release an old migration was removed and in case you are still using the `REDIS_EXPIRY` environment variable you need to switch to `SECRET_EXPIRY`. Also with the new redis client you might need to adjust the username in your `REDIS_URL` to a proper ACL username (or enable legacy auth in Redis) - see the README for the `REDIS_URL` format.
+With this release an old migration was removed and in case you are still using the `REDIS_EXPIRY` environment variable you need to switch to `MAX_SECRET_EXPIRY`. Also with the new redis client you might need to adjust the username in your `REDIS_URL` to a proper ACL username (or enable legacy auth in Redis) - see the README for the `REDIS_URL` format.
# 1.0.0 / 2023-04-14
diff --git a/README.md b/README.md
index 1db58f8..212b68b 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@ For a better setup you can choose the backend which is used to store the secrets
(pre Redis v6 use `auth` as user, afterwards use a user available in your ACLs)
- `REDIS_KEY` - Key prefix to store the keys under (Default `io.luzifer.ots`)
- Common options
- - `SECRET_EXPIRY` - Expiry of the keys in seconds (Default `0` = no expiry)
+ - `MAX_SECRET_EXPIRY` - Expiry of the keys in seconds (Default `0` = no expiry)
### Customization
diff --git a/api.go b/api.go
index 82de183..24ff2bd 100644
--- a/api.go
+++ b/api.go
@@ -62,13 +62,17 @@ func (a apiServer) handleCreate(res http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(res, r.Body, cust.MaxSecretSize*2) //nolint:gomnd
}
+ if cfg.DefaultSecretExpiry == 0 && cfg.MaxSecretExpiry > 0 {
+ cfg.DefaultSecretExpiry = cfg.MaxSecretExpiry
+ }
+
var (
- expiry = cfg.SecretExpiry
+ expiry = cfg.DefaultSecretExpiry
secret string
)
if !cust.DisableExpiryOverride {
- if ev, err := strconv.ParseInt(r.URL.Query().Get("expire"), 10, 64); err == nil && (ev < expiry || cfg.SecretExpiry == 0) {
+ if ev, err := strconv.ParseInt(r.URL.Query().Get("expire"), 10, 64); err == nil && (ev <= cfg.MaxSecretExpiry || cfg.MaxSecretExpiry == 0) {
expiry = ev
}
}
diff --git a/docker-compose.yml b/docker-compose.yml
index 048dca3..87e4140 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -10,7 +10,7 @@ services:
# See README for details
REDIS_URL: redis://redis:6379/0
# 168h = 1w
- SECRET_EXPIRY: "604800"
+ MAX_SECRET_EXPIRY: "604800"
# "mem" or "redis" (See README)
STORAGE_TYPE: redis
depends_on:
diff --git a/docs/k8s_example.yml b/docs/k8s_example.yml
index 78905ad..e221c31 100644
--- a/docs/k8s_example.yml
+++ b/docs/k8s_example.yml
@@ -118,7 +118,7 @@ spec:
value: tcp://ots-redis:6379
- name: REDIS_KEY
value: ots
- - name: SECRET_EXPIRY
+ - name: MAX_SECRET_EXPIRY
value: "172800"
volumeMounts:
- mountPath: /custom
diff --git a/frontend/index.html b/frontend/index.html
index 8e9e77a..3ded167 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -47,6 +47,8 @@
// Template variable from Golang process
const maxSecretExpire = {{ .MaxSecretExpiry }}
+ const defaultSecretExpire = {{ .DefaultSecretExpiry }}
+
const version = "{{ .Version }}"
window.OTSCustomize = JSON.parse('{{ .Customize.ToJSON }}')
window.useFormalLanguage = {{ .Customize.UseFormalLanguage | mustToJson }}
diff --git a/i18n.yaml b/i18n.yaml
index 1bed2a3..f9ba80c 100644
--- a/i18n.yaml
+++ b/i18n.yaml
@@ -12,7 +12,7 @@ reference:
btn-reveal-secret: Show me the secret!
btn-reveal-secret-processing: Secret is being decrypted…
btn-show-explanation: How does this work?
- expire-default: Default Expiry
+ expire-default: Default Expiry ({duration})
expire-n-days: '{n} day | {n} days'
expire-n-hours: '{n} hour | {n} hours'
expire-n-minutes: '{n} minute | {n} minutes'
@@ -35,6 +35,7 @@ reference:
text-invalid-files-selected: At least one of the selected files is not allowed as an attachment.
text-max-filesize: 'Maximum size: {maxSize}'
text-max-filesize-exceeded: 'The file(s) you chose are too big to attach: {curSize} / {maxSize}'
+ text-never: never
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:'
@@ -57,7 +58,7 @@ translations:
btn-reveal-secret: Mostra'm el secret!
btn-reveal-secret-processing: El secret s'està desxifrant...
btn-show-explanation: Com funciona?
- expire-default: Caducitat predeterminada
+ expire-default: Caducitat predeterminada ({duration})
expire-n-days: '{n} dia | {n} dies'
expire-n-hours: '{n} hora | {n} hores'
expire-n-minutes: '{n} minut | {n} minuts'
@@ -79,6 +80,7 @@ translations:
text-hint-burned: Atenció: Només veuràs això una vegada. Quan recarregues la pàgina, el secret desapareixerà, així que copia'l ja…
text-max-filesize: 'Mida màxima: {maxSize}'
text-max-filesize-exceeded: 'Els arxius seleccionats són massa grans per adjuntar-los: {curSize} / {maxSize}'
+ text-never: Mai
text-powered-by: Funciona amb
text-pre-reveal-hint: Per a mostrar el secret prem aquest botó, però tingues en compte que en fer-ho es destruirà. Només pots veure'l una vegada!
text-pre-url: 'El teu secret ha sigut creat i emmagatzemat en el següent enllaç:'
@@ -101,7 +103,7 @@ translations:
btn-reveal-secret: Zeig mir das Secret!
btn-reveal-secret-processing: Secret wird entschlüsselt…
btn-show-explanation: Wie funktioniert das?
- expire-default: Server-Standard
+ expire-default: Server-Standard ({duration})
expire-n-days: '{n} Tag | {n} Tage'
expire-n-hours: '{n} Stunde | {n} Stunden'
expire-n-minutes: '{n} Minute | {n} Minuten'
@@ -124,6 +126,7 @@ translations:
text-invalid-files-selected: Mindestens eine der ausgewählten Dateien ist nicht als Anhang erlaubt.
text-max-filesize: 'Maximale Größe: {maxSize}'
text-max-filesize-exceeded: 'Die ausgewählten Dateien übersteigen die maximale Größe: {curSize} / {maxSize}'
+ text-never: Nie
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:'
@@ -163,7 +166,7 @@ translations:
btn-reveal-secret: ¡Muéstrame el secreto!
btn-reveal-secret-processing: El secreto se está descifrando...
btn-show-explanation: ¿Cómo funciona?
- expire-default: Caducidad predeterminada
+ expire-default: Caducidad predeterminada ({duration})
expire-n-days: '{n} día | {n} días'
expire-n-hours: '{n} hora | {n} horas'
expire-n-minutes: '{n} minuto | {n} minutos'
@@ -185,6 +188,7 @@ translations:
text-hint-burned: Atención: Solo verás esto una vez. En cuanto recargues la página, el secreto desaparecerá, así que cópialo ya…
text-max-filesize: 'Tamaño máximo: {maxSize}'
text-max-filesize-exceeded: 'Los archivos seleccionados son demasiado grandes para adjuntarlos: {curSize} / {maxSize}'
+ text-never: Nunca
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:'
@@ -219,6 +223,7 @@ translations:
label-secret-data: 'Données secrètes:'
text-burn-hint: Attention de ne pas ouvrir cette URL vous-même, cela détruirait le secret. Fournissez-la à quelqu'un d'autre!
text-hint-burned: Attention: Vous ne pouvez consulter ce contenu qu'une fois. Le secret sera détruit dès que vous rechargez la page, donc copiez le maintenant…
+ text-never: Jamais
text-powered-by: Propulsé par
text-pre-reveal-hint: Pour afficher le secret, cliquez sur ce bouton, mais soyez conscient que cela le détruira. Vous ne pouvez l'afficher qu'une fois!
text-pre-url: 'Votre secret a été créé et stocké à cette URL:'
@@ -253,6 +258,7 @@ translations:
label-secret-data: 'Ziņa:'
text-burn-hint: Lūdzu atceries neatvērt saiti pats, jo tad ziņa tiks dzēsta. Nodod saiti ziņas saņēmējam!
text-hint-burned: Uzmanību: Ziņa tiek parādīta tikai vienu reizi. Līdzko lapa tiks pārlādēta, ziņa būs neatgriezeniski zaudēta, tāpēc nepieciešamības gadījumā nokopē to tagad…
+ text-never: Nekad
text-powered-by: Darbina
text-pre-reveal-hint: Lai parādītu ziņu nospied šo pogu, bet rēķinies ar to, ka pēc apskates ziņa vairs nebūs pieejama. To var atvērt tikai vienreiz!
text-pre-url: 'Ziņa ir nošifrēta un ir atverama šajā adresē:'
@@ -274,7 +280,7 @@ translations:
btn-reveal-secret: Toon mij de vertrouwelijke info!
btn-reveal-secret-processing: Vertrouwelijke info wordt ontsleuteld...
btn-show-explanation: Hoe werkt dit?
- expire-default: Standaard termijn
+ expire-default: Standaard termijn ({duration})
expire-n-days: '{n} dag | {n} dagen'
expire-n-hours: '{n} uur | {n} uur'
expire-n-minutes: '{n} minuut | {n} minuten'
@@ -296,6 +302,7 @@ translations:
text-hint-burned: Opgelet: Je ziet deze informatie alleen nu. Je kan het niet meer opnieuw opvragen als je de pagina verlaat.
text-max-filesize: 'Maximum grootte: {maxSize}'
text-max-filesize-exceeded: 'De bestanden die je toevoegde zijn te groot: {curSize} / {maxSize}'
+ text-never: Nooit
text-powered-by: Mogelijk gemaakt door
text-pre-reveal-hint: 'Gebruik deze knop om de vertrouwelijke info op te halen. Let op: Je kan dit slechts eenmaal doen!'
text-pre-url: 'Je vertrouwelijke informatie kan opgevraagd worden via deze URL:'
@@ -318,7 +325,7 @@ translations:
btn-reveal-secret: Pokaż mi sekret!
btn-reveal-secret-processing: Sekret jest odszyfrowywany...
btn-show-explanation: Jak to działa?
- expire-default: Domyślne wygasanie
+ expire-default: Domyślne wygasanie ({duration})
expire-n-days: '{n} dzień | {n} dni'
expire-n-hours: '{n} godzina | {n} godzin(y)'
expire-n-minutes: '{n} minuta | {n} minut(y)'
@@ -341,6 +348,7 @@ translations:
text-invalid-files-selected: Co najmniej jeden z załączonych plików nie jest dopuszczalny jako załącznik.
text-max-filesize: 'Maksymalny rozmiar: {maxSize}'
text-max-filesize-exceeded: 'Wybrane załączniki przekraczają maksymalny rozmiar: {curSize} / {maxSize}'
+ text-never: Nigdy
text-powered-by: Obsługiwane przez
text-pre-reveal-hint: Aby odsłonić sekret, naciśnij ten przycisk, jednak wiedz, że to zniszczy sekret. Możesz go zobaczyć tylko raz!
text-pre-url: 'Twój sekret został stworzony i zachowany pod tym adresem URL:'
@@ -375,6 +383,7 @@ translations:
label-secret-data: 'Informação secreta:'
text-burn-hint: Importante você lembrar de não acessar esta URL, pois isto irá indisponibilizar o segredo. Apenas encaminhe para outra pessoa!
text-hint-burned: 'Atenção: Você está vendo esta informação apenas uma vez. Logo que você recarregar a página o segredo ficará indisponível. É recomendado que você copie a informação agora…'
+ text-never: Nunca
text-powered-by: Powered by
text-pre-reveal-hint: Para revelar o segredo clique neste botão, mas lembre-se que esta ação vai destruir o segredo. Você só pode ver uma única vez!
text-pre-url: 'Seu segredo foi criado e armazenado na seguinte URL:'
@@ -397,7 +406,7 @@ translations:
btn-reveal-secret: Показать секрет!
btn-reveal-secret-processing: Секрет декодируется ...
btn-show-explanation: Как это работает?
- expire-default: Значение по умолчанию до исчезновения
+ expire-default: Значение по умолчанию до исчезновения ({duration})
expire-n-days: '{n} день | {n} дней'
expire-n-hours: '{n} час | {n} часов'
expire-n-minutes: '{n} минут | {n} минут'
@@ -419,6 +428,7 @@ translations:
text-hint-burned: Внимание: Секрет будет показан только один раз. Как только вы перезагрузите страницу, секрет исчезнет, скопируйте его незамедлительно…
text-max-filesize: 'Максимальный размер: {maxSize}'
text-max-filesize-exceeded: 'Ваш файл(ы) слишком большой для прикрепления к секрету: {curSize} / {maxSize}'
+ text-never: Никогда
text-powered-by: Основан
text-pre-reveal-hint: Чтобы раскрыть секрет, нажмите эту кнопку, но имейте в виду, что это приведет к уничтожению секрета. Вы можете просмотреть его только один раз!
text-pre-url: 'Ваш секрет создан и сохранён, его URL:'
@@ -440,7 +450,7 @@ translations:
btn-reveal-secret: Visa mig hemligheten!
btn-reveal-secret-processing: Hemlighet håller på att dekrypteras..
btn-show-explanation: Hur fungerar detta?
- expire-default: Standard utgångstid
+ expire-default: Standard utgångstid ({duration})
expire-n-days: '{n} dag | {n} dagar'
expire-n-hours: '{n} timme | {n} timmar'
expire-n-minutes: '{n} minut | {n} minuter'
@@ -462,6 +472,7 @@ translations:
text-hint-burned: Observera: Du kan endast se denna sida en gång. Så fort du laddar om sidan kommer hemligheten att försvinna så kopiera den nu…
text-max-filesize: 'Maximal storlek: {maxSize}'
text-max-filesize-exceeded: 'Filerna du valt är för stora för att kunna bifogas: {curSize} / {maxSize}'
+ text-never: Aldrig
text-powered-by: Drivs av
text-pre-reveal-hint: För att visa hemligheten klicka på denna knapp. Var medveten om att när du gör det kommer hemligheten att förbrukas, du kan endast se den en gång!
text-pre-url: 'Din hemlighet har skapats och lagrats med denna URL:'
@@ -496,6 +507,7 @@ translations:
label-secret-data: 'Sır bilgisi:'
text-burn-hint: Lütfen linki kendiniz acmayın, bu sırrın silinmesine neden olur. Linki sadece alıcıya gönderin!
text-hint-burned: 'Dikkat: Bunu sadece bir kez göreceksiniz. Sayfayı güncellediğinizde yada kapattiğınızda sır kaybolacaktır, belkide şimdi sırrı kopyalamanız akıllıca olacaktır…'
+ text-never: Asla
text-powered-by: Tarafından desteklenmektedir
text-pre-reveal-hint: Sırrı görmek için bu düğmeye tıklayın, ama bunu yaptıktan sonra sırrın silineceğini unutmayın. Bunu sadece bir kez görebilirsin!
text-pre-url: 'Sırrınız oluşturuldu ve bu link kullanılarak kaydedildi:'
@@ -517,7 +529,7 @@ translations:
btn-reveal-secret: Показати мені секрет!
btn-reveal-secret-processing: Секрет розшифровується…
btn-show-explanation: Як це працює?
- expire-default: Термін дії за замовчуванням
+ expire-default: Термін дії за замовчуванням ({duration})
expire-n-days: '{n} день | {n} днів'
expire-n-hours: '{n} година | {n} годин'
expire-n-minutes: '{n} хвилина | {n} хвилин'
@@ -539,6 +551,7 @@ translations:
text-hint-burned: Увага: Ви бачите це лише раз. Щойно ви перезавантажите сторінку, секрет зникне, тому, можливо, скопіюйте його зараз…
text-max-filesize: 'Максимальний розмір: {maxSize}'
text-max-filesize-exceeded: 'Вибрані вами файли завеликі, щоб вкласти: {curSize} / {maxSize}'
+ text-never: Ніколи
text-powered-by: Powered by
text-pre-reveal-hint: Щоб розкрити секрет, натисніть цю кнопку, але майте на увазі, що це знищить секрет. Ви можете переглянути його лише один раз!
text-pre-url: 'Ваш секрет було створено та збережено за допомогою цієї URL-адреси:'
@@ -560,7 +573,7 @@ translations:
btn-reveal-secret: 向我展示机密
btn-reveal-secret-processing: 机密正在解密中…
btn-show-explanation: 它如何运作?
- expire-default: 默认过期时间
+ expire-default: 默认过期时间 ({duration})
expire-n-days: '{n} 天 | {n} 天'
expire-n-hours: '{n} 小时 | {n} 小时'
expire-n-minutes: '{n} 分钟 | {n} 分钟'
@@ -583,6 +596,7 @@ translations:
text-invalid-files-selected: 选中了至少一个不允许被作为附件的文件。
text-max-filesize: 附加文件大小上限:{maxSize}
text-max-filesize-exceeded: 您选择的文件过大,无法附加:{curSize} / {maxSize}
+ text-never: 绝不
text-powered-by: Powered by
text-pre-reveal-hint: 点击按钮即可查看机密,但请注意该操作会立即销毁机密,而且您也只能查看一次!
text-pre-url: 您的机密已创建,访问链接如下:
diff --git a/main.go b/main.go
index 404d34d..e92634b 100644
--- a/main.go
+++ b/main.go
@@ -27,12 +27,13 @@ const scriptNonceSize = 32
var (
cfg struct {
- Customize string `flag:"customize" default:"" description:"Customize-File to load"`
- Listen string `flag:"listen" default:":3000" description:"IP/Port to listen on"`
- LogLevel string `flag:"log-level" default:"info" description:"Set log level (debug, info, warning, error)"`
- SecretExpiry int64 `flag:"secret-expiry" default:"0" description:"Maximum expiry of the stored secrets in seconds"`
- StorageType string `flag:"storage-type" default:"mem" description:"Storage to use for putting secrets to" validate:"nonzero"`
- VersionAndExit bool `flag:"version" default:"false" description:"Print version information and exit"`
+ Customize string `flag:"customize" default:"" description:"Customize-File to load"`
+ Listen string `flag:"listen" default:":3000" description:"IP/Port to listen on"`
+ LogLevel string `flag:"log-level" default:"info" description:"Set log level (debug, info, warning, error)"`
+ MaxSecretExpiry int64 `flag:"max-secret-expiry" default:"0" description:"Maximum expiry of the stored secrets in seconds"`
+ DefaultSecretExpiry int64 `flag:"default-secret-expiry" default:"0" description:"Default expiry of the stored secrets in seconds"`
+ StorageType string `flag:"storage-type" default:"mem" description:"Storage to use for putting secrets to" validate:"nonzero"`
+ VersionAndExit bool `flag:"version" default:"false" description:"Print version information and exit"`
}
assets file_helpers.FSStack
@@ -154,8 +155,9 @@ func main() {
// Start server
logrus.WithFields(logrus.Fields{
- "secret_expiry": time.Duration(cfg.SecretExpiry) * time.Second,
- "version": version,
+ "max_secret_expiry": time.Duration(cfg.MaxSecretExpiry) * time.Second,
+ "default_secret_expiry": time.Duration(cfg.DefaultSecretExpiry) * time.Second,
+ "version": version,
}).Info("ots started")
if err = server.ListenAndServe(); err != nil {
@@ -209,15 +211,17 @@ func handleIndex(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("X-Content-Type-Options", "nosniff")
if err := indexTpl.Execute(w, struct {
- Customize customization.Customize
- InlineContentNonce string
- MaxSecretExpiry int64
- Version string
+ Customize customization.Customize
+ InlineContentNonce string
+ MaxSecretExpiry int64
+ DefaultSecretExpiry int64
+ Version string
}{
- Customize: cust,
- InlineContentNonce: inlineContentNonceStr,
- MaxSecretExpiry: cfg.SecretExpiry,
- Version: version,
+ Customize: cust,
+ InlineContentNonce: inlineContentNonceStr,
+ MaxSecretExpiry: cfg.MaxSecretExpiry,
+ DefaultSecretExpiry: cfg.DefaultSecretExpiry,
+ Version: version,
}); err != nil {
http.Error(w, errors.Wrap(err, "executing template").Error(), http.StatusInternalServerError)
return
diff --git a/src/components/create.vue b/src/components/create.vue
index 1ed40c6..c9af529 100644
--- a/src/components/create.vue
+++ b/src/components/create.vue
@@ -114,6 +114,14 @@