[#92] Add detection for write-disabled instances

to deactivate secret creation for non-logged-in users

Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
Knut Ahlers 2023-06-15 18:49:10 +02:00
parent f5aebbb99a
commit 805a005ed5
Signed by: luzifer
GPG key ID: D91C3E91E4CAD6F5
14 changed files with 108 additions and 1 deletions

View file

@ -71,6 +71,8 @@ To override the styling of the application have a look at the [`src/style.scss`]
After modifying files in the `overlayFSPath` make sure to restart the application as otherwise the file integrity hashes are no longer matching and your resources will be blocked by the browsers. After modifying files in the `overlayFSPath` make sure to restart the application as otherwise the file integrity hashes are no longer matching and your resources will be blocked by the browsers.
If you want to disable secret creation for users not logged into your company SSO you can apply an ACL on the `/api/create` and `/api/isWritable` endpoints to allow access to them only for logged in users. This will also disable the secret-creation interface for all not having access to the `/api/isWritable` endpoint.
## Creating secrets through CLI / scripts ## Creating secrets through CLI / scripts
As `ots` is designed to never let the server know the secret you are sharing you should not just send the plain secret to it though it is possible. As `ots` is designed to never let the server know the secret you are sharing you should not just send the plain secret to it though it is possible.

1
api.go
View file

@ -36,6 +36,7 @@ func newAPI(s storage) *apiServer {
func (a apiServer) Register(r *mux.Router) { func (a apiServer) Register(r *mux.Router) {
r.HandleFunc("/create", a.handleCreate) r.HandleFunc("/create", a.handleCreate)
r.HandleFunc("/get/{id}", a.handleRead) r.HandleFunc("/get/{id}", a.handleRead)
r.HandleFunc("/isWritable", func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusNoContent) })
} }
func (a apiServer) handleCreate(res http.ResponseWriter, r *http.Request) { func (a apiServer) handleCreate(res http.ResponseWriter, r *http.Request) {

41
ci/autotranslate.sh Normal file
View file

@ -0,0 +1,41 @@
#!/usr/bin/env bash
set -euo pipefail
function log() {
echo "[$(date +%H:%M:%S)] $@" >&2
}
translation_keys=($(
jq -r '. | keys | .[]' src/langs/en.json
))
for lang_file in src/langs/*.json; do
lang=$(echo ${lang_file} | sed -E 's@.*/([^\/\.]*)\.json@\1@')
log "Processing ${lang}..."
target_lang=$(jq -r ".__lang" ${lang_file} | grep -v null || echo "")
[[ -n $target_lang ]] || {
log " + Missing '__lang' key, cannot translate."
continue
}
for tk in "${translation_keys[@]}"; do
[[ $(jq -r ".[\"${tk}\"]" ${lang_file}) == null ]] || continue
log " + Missing '${tk}', fetching..."
source_str=$(jq -r ".[\"${tk}\"]" src/langs/en.json)
translation="$(
curl -sSf -X POST "${DEEPL_API_ENDPOINT}" \
-H "Authorization: DeepL-Auth-Key ${DEEPL_API_KEY}" \
-F "text=${source_str}" \
-F "target_lang=${target_lang}" |
jq -r '.translations[0].text'
)"
jq -S --arg t "${translation}" ".[\"${tk}\"]=\$t" ${lang_file} >${lang_file}.tmp
mv ${lang_file}.tmp ${lang_file}
done
done

View file

@ -84,7 +84,7 @@
<!-- Creation dialog --> <!-- Creation dialog -->
<b-card <b-card
v-if="mode == 'create' && !secretId" v-if="mode == 'create' && !secretId && canWrite"
border-variant="primary" border-variant="primary"
header-bg-variant="primary" header-bg-variant="primary"
header-text-variant="white" header-text-variant="white"
@ -110,6 +110,20 @@
</b-button> </b-button>
</b-card> </b-card>
<!-- Creation disabled -->
<b-card
v-if="mode == 'create' && !secretId && canWrite === false"
border-variant="info"
header-bg-variant="info"
header-text-variant="white"
>
<span
slot="header"
v-html="$t('title-secret-create-disabled')"
/>
<p v-html="$t('text-secret-create-disabled')" />
</b-card>
<!-- Secret created, show secret URL --> <!-- Secret created, show secret URL -->
<b-card <b-card
v-if="mode == 'create' && secretId" v-if="mode == 'create' && secretId"
@ -240,6 +254,7 @@ export default {
data() { data() {
return { return {
canWrite: null,
copyToClipboardSuccess: false, copyToClipboardSuccess: false,
customize: {}, customize: {},
darkTheme: false, darkTheme: false,
@ -255,6 +270,23 @@ export default {
}, },
methods: { methods: {
checkWriteAccess() {
fetch('api/isWritable', {
credentials: 'same-origin',
method: 'GET',
redirect: 'error',
})
.then(resp => {
if (resp.status !== 204) {
throw new Error(`unexpected status: ${resp.status}`)
}
this.canWrite = true
})
.catch(() => {
this.canWrite = false
})
},
copySecretUrl() { copySecretUrl() {
navigator.clipboard.writeText(this.secretUrl) navigator.clipboard.writeText(this.secretUrl)
.then(() => { .then(() => {
@ -374,6 +406,7 @@ export default {
// Trigger initialization functions // Trigger initialization functions
mounted() { mounted() {
this.checkWriteAccess()
this.customize = window.OTSCustomize this.customize = window.OTSCustomize
this.darkTheme = window.getTheme() === 'dark' this.darkTheme = window.getTheme() === 'dark'
window.onhashchange = this.hashLoad window.onhashchange = this.hashLoad

View file

@ -1,4 +1,5 @@
{ {
"__lang": "de",
"alert-secret-not-found": "Das ist nicht das Secret, was du suchst&hellip; - 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-secret-not-found": "Das ist nicht das Secret, was du suchst&hellip; - 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&hellip;", "alert-something-went-wrong": "Irgendwas ging schief. Entschuldigung&hellip;",
"btn-create-secret": "Secret erstellen!", "btn-create-secret": "Secret erstellen!",
@ -20,8 +21,10 @@
"text-powered-by": "Läuft mit", "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-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-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&hellip;", "title-explanation": "So funktioniert es&hellip;",
"title-new-secret": "Erstelle ein neues Secret", "title-new-secret": "Erstelle ein neues Secret",
"title-reading-secret": "Secret auslesen&hellip;", "title-reading-secret": "Secret auslesen&hellip;",
"title-secret-create-disabled": "Erstellen von Secrets deaktiviert…",
"title-secret-created": "Secret erstellt!" "title-secret-created": "Secret erstellt!"
} }

View file

@ -1,4 +1,5 @@
{ {
"__lang": "en",
"alert-secret-not-found": "This is not the secret you are looking for&hellip; - If you expected the secret to be here it might be compromised as someone else might have opened the link already.", "alert-secret-not-found": "This is not the secret you are looking for&hellip; - 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&hellip;", "alert-something-went-wrong": "Something went wrong. I'm very sorry about this&hellip;",
"btn-create-secret": "Create the secret!", "btn-create-secret": "Create the secret!",
@ -20,8 +21,10 @@
"text-powered-by": "Powered by", "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-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-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&hellip;", "title-explanation": "This is how it works&hellip;",
"title-new-secret": "Create a new secret", "title-new-secret": "Create a new secret",
"title-reading-secret": "Reading your secret&hellip;", "title-reading-secret": "Reading your secret&hellip;",
"title-secret-create-disabled": "Secret creation disabled…",
"title-secret-created": "Secret created!" "title-secret-created": "Secret created!"
} }

View file

@ -1,4 +1,5 @@
{ {
"__lang": "es",
"alert-secret-not-found": "Este no es el secreto que buscas&hellip; - 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-secret-not-found": "Este no es el secreto que buscas&hellip; - 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&hellip;", "alert-something-went-wrong": "Algo ha salido mal. Lo sentimos mucho&hellip;",
"btn-create-secret": "¡Crea el secreto!", "btn-create-secret": "¡Crea el secreto!",
@ -20,8 +21,10 @@
"text-powered-by": "Funciona con", "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-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-pre-url": "Tu secreto ha sido creado y almacenado en el siguiente enlace:",
"text-secret-create-disabled": "En este caso, la creación de nuevos secretos está desactivada.",
"title-explanation": "Así es como funciona&hellip;", "title-explanation": "Así es como funciona&hellip;",
"title-new-secret": "Crea un nuevo secreto", "title-new-secret": "Crea un nuevo secreto",
"title-reading-secret": "Obteniendo tu secreto&hellip;", "title-reading-secret": "Obteniendo tu secreto&hellip;",
"title-secret-create-disabled": "Creación secreta desactivada...",
"title-secret-created": "¡Secreto creado!" "title-secret-created": "¡Secreto creado!"
} }

View file

@ -1,4 +1,5 @@
{ {
"__lang": "fr",
"alert-secret-not-found": "Ce secret n'est pas celui que vous cherchez&hellip; - Si vous comptiez trouvez ce secret ici, il a pu être compromis car quelqu'un a probablement déjà ouvert le lien.", "alert-secret-not-found": "Ce secret n'est pas celui que vous cherchez&hellip; - Si vous comptiez trouvez ce secret ici, il a pu être compromis car quelqu'un a probablement déjà ouvert le lien.",
"alert-something-went-wrong": "Un problème est survenu. Nous en sommes désolés&hellip;", "alert-something-went-wrong": "Un problème est survenu. Nous en sommes désolés&hellip;",
"btn-create-secret": "Créer le secret!", "btn-create-secret": "Créer le secret!",
@ -20,8 +21,10 @@
"text-powered-by": "Propulsé par", "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-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:", "text-pre-url": "Votre secret a été créé et stocké à cette URL:",
"text-secret-create-disabled": "La création de nouveaux secrets est désactivée dans ce cas.",
"title-explanation": "Voici comment ça fonctionne&hellip;", "title-explanation": "Voici comment ça fonctionne&hellip;",
"title-new-secret": "Créer un nouveau secret", "title-new-secret": "Créer un nouveau secret",
"title-reading-secret": "Lecture du secret&hellip;", "title-reading-secret": "Lecture du secret&hellip;",
"title-secret-create-disabled": "Création secrète désactivée...",
"title-secret-created": "Secret créé!" "title-secret-created": "Secret créé!"
} }

View file

@ -1,4 +1,5 @@
{ {
"__lang": "lv",
"alert-secret-not-found": "<strong>Ziņa nav atrasta!</strong>&hellip; - Ja ievadītā saite ir pareiza, tad ir beidzies ziņas glabāšanas laiks, vai arī tā jau vienreiz ir atvērta.", "alert-secret-not-found": "<strong>Ziņa nav atrasta!</strong>&hellip; - Ja ievadītā saite ir pareiza, tad ir beidzies ziņas glabāšanas laiks, vai arī tā jau vienreiz ir atvērta.",
"alert-something-went-wrong": "Neparedzēta sistēmas kļūda. Atvainojiet par sagādātajām neērtībām&hellip;", "alert-something-went-wrong": "Neparedzēta sistēmas kļūda. Atvainojiet par sagādātajām neērtībām&hellip;",
"btn-create-secret": "Šifrēt ziņu!", "btn-create-secret": "Šifrēt ziņu!",
@ -20,8 +21,10 @@
"text-powered-by": "Darbina", "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-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ē:", "text-pre-url": "Ziņa ir nošifrēta un ir atverama šajā adresē:",
"text-secret-create-disabled": "Šajā gadījumā jaunu noslēpumu izveide ir atspējota.",
"title-explanation": "Tā tas strādā&hellip;", "title-explanation": "Tā tas strādā&hellip;",
"title-new-secret": "Šifrēt ziņu", "title-new-secret": "Šifrēt ziņu",
"title-reading-secret": "Atver ziņu&hellip;", "title-reading-secret": "Atver ziņu&hellip;",
"title-secret-create-disabled": "Slepena izveide atspējota...",
"title-secret-created": "Ziņa nošifrēta!" "title-secret-created": "Ziņa nošifrēta!"
} }

View file

@ -1,4 +1,5 @@
{ {
"__lang": "nl",
"alert-secret-not-found": "De gegevens die je zocht bestaan niet (meer)&hellip; - Als je hier informatie verwachtte dan is de link mogelijk al door iemand anders bekeken!", "alert-secret-not-found": "De gegevens die je zocht bestaan niet (meer)&hellip; - Als je hier informatie verwachtte dan is de link mogelijk al door iemand anders bekeken!",
"alert-something-went-wrong": "Er ging iets verkeerd, sorry&hellip;", "alert-something-went-wrong": "Er ging iets verkeerd, sorry&hellip;",
"btn-create-secret": "Nieuwe vertrouwelijke info aanmaken!", "btn-create-secret": "Nieuwe vertrouwelijke info aanmaken!",
@ -20,8 +21,10 @@
"text-powered-by": "Mogelijk gemaakt door", "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-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:", "text-pre-url": "Je vertrouwelijke informatie kan opgevraagd worden via deze URL:",
"text-secret-create-disabled": "Het aanmaken van nieuwe geheimen is in dit geval uitgeschakeld.",
"title-explanation": "Dit is hoe het werkt&hellip;", "title-explanation": "Dit is hoe het werkt&hellip;",
"title-new-secret": "Nieuwe vertrouwelijke info opslaan", "title-new-secret": "Nieuwe vertrouwelijke info opslaan",
"title-reading-secret": "Vertrouwelijke info lezen&hellip;", "title-reading-secret": "Vertrouwelijke info lezen&hellip;",
"title-secret-create-disabled": "Geheime creatie uitgeschakeld...",
"title-secret-created": "Vertrouwelijke info opgeslaan!" "title-secret-created": "Vertrouwelijke info opgeslaan!"
} }

View file

@ -1,4 +1,5 @@
{ {
"__lang": "PT-BR",
"alert-secret-not-found": "Esta não é o segredo que você está procurando… - Se você esperava que o segredo estaria aqui, ele pode ter sido comprometido por alguém que já acessou o link.", "alert-secret-not-found": "Esta não é o segredo que você está procurando… - Se você esperava que o segredo estaria aqui, ele pode ter sido comprometido por alguém que já acessou o link.",
"alert-something-went-wrong": "Desculpe, algo deu errado…", "alert-something-went-wrong": "Desculpe, algo deu errado…",
"btn-create-secret": "Criar segredo!", "btn-create-secret": "Criar segredo!",
@ -20,8 +21,10 @@
"text-powered-by": "Powered by", "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-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:", "text-pre-url": "Seu segredo foi criado e armazenado na seguinte URL:",
"text-secret-create-disabled": "A criação de novos segredos é desativada nesse caso.",
"title-explanation": "É assim como funciona…", "title-explanation": "É assim como funciona…",
"title-new-secret": "Criar um novo segredo", "title-new-secret": "Criar um novo segredo",
"title-reading-secret": "Lendo seu segredo…", "title-reading-secret": "Lendo seu segredo…",
"title-secret-create-disabled": "Criação secreta desativada...",
"title-secret-created": "Segredo criado!" "title-secret-created": "Segredo criado!"
} }

View file

@ -1,4 +1,5 @@
{ {
"__lang": "ru",
"alert-secret-not-found": "Секрет недоступен&hellip; - Помните, он может быть скомпрометирован. Возможно кто-то другой уже открыл вашу ссылку.", "alert-secret-not-found": "Секрет недоступен&hellip; - Помните, он может быть скомпрометирован. Возможно кто-то другой уже открыл вашу ссылку.",
"alert-something-went-wrong": "Что-то пошло не так. Приносим свои извинения&hellip;", "alert-something-went-wrong": "Что-то пошло не так. Приносим свои извинения&hellip;",
"btn-create-secret": "Создать секрет!", "btn-create-secret": "Создать секрет!",
@ -20,8 +21,10 @@
"text-powered-by": "Powered by", "text-powered-by": "Powered by",
"text-pre-reveal-hint": "Чтобы раскрыть секрет, нажмите эту кнопку, но имейте в виду, что это приведет к уничтожению секрета. Вы можете просмотреть его только один раз!", "text-pre-reveal-hint": "Чтобы раскрыть секрет, нажмите эту кнопку, но имейте в виду, что это приведет к уничтожению секрета. Вы можете просмотреть его только один раз!",
"text-pre-url": "Ваш секрет создан и сохранён, его URL:", "text-pre-url": "Ваш секрет создан и сохранён, его URL:",
"text-secret-create-disabled": "Создание новых секретов в этом случае отключено.",
"title-explanation": "Как это работает&hellip;", "title-explanation": "Как это работает&hellip;",
"title-new-secret": "Создать новый секрет", "title-new-secret": "Создать новый секрет",
"title-reading-secret": "Читаем ваш секрет&hellip;", "title-reading-secret": "Читаем ваш секрет&hellip;",
"title-secret-create-disabled": "Секретное создание отключено...",
"title-secret-created": "Секрет создан!" "title-secret-created": "Секрет создан!"
} }

View file

@ -1,4 +1,5 @@
{ {
"__lang": "sv",
"alert-secret-not-found": "Hemlighet hittades inte&hellip; - Om du förväntade dig att hemligheten skulle finnas här kan den vara röjd då någon annan kan ha öppnat denna länk tidigare.", "alert-secret-not-found": "Hemlighet hittades inte&hellip; - Om du förväntade dig att hemligheten skulle finnas här kan den vara röjd då någon annan kan ha öppnat denna länk tidigare.",
"alert-something-went-wrong": "Något gick fel. Jag ber om ursäkt för detta!&hellip;", "alert-something-went-wrong": "Något gick fel. Jag ber om ursäkt för detta!&hellip;",
"btn-create-secret": "Skapa hemliget!", "btn-create-secret": "Skapa hemliget!",
@ -20,8 +21,10 @@
"text-powered-by": "Drivs av", "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-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:", "text-pre-url": "Din hemlighet har skapats och lagrats med denna URL:",
"text-secret-create-disabled": "Skapandet av nya hemligheter blockeras i detta fall.",
"title-explanation": "Såhär fungerar det&hellip;", "title-explanation": "Såhär fungerar det&hellip;",
"title-new-secret": "Skapa ny hemlighet", "title-new-secret": "Skapa ny hemlighet",
"title-reading-secret": "Läs din hemlighet&hellip;", "title-reading-secret": "Läs din hemlighet&hellip;",
"title-secret-create-disabled": "Hemlig skapelse avaktiverad...",
"title-secret-created": "Hemlighet skapad!" "title-secret-created": "Hemlighet skapad!"
} }

View file

@ -1,4 +1,5 @@
{ {
"__lang": "tr",
"alert-secret-not-found": "Aradığınız sır bu değil… - Sırrın burada olmasını bekliyorsanız, bu link başkası tarafından açılmış ve sırrınız tehlikede olabilir.", "alert-secret-not-found": "Aradığınız sır bu değil… - Sırrın burada olmasını bekliyorsanız, bu link başkası tarafından açılmış ve sırrınız tehlikede olabilir.",
"alert-something-went-wrong": "Bir şeyler ters gitti. Bunun için çok üzgünüm…", "alert-something-went-wrong": "Bir şeyler ters gitti. Bunun için çok üzgünüm…",
"btn-create-secret": "Sır oluştur!", "btn-create-secret": "Sır oluştur!",
@ -20,8 +21,10 @@
"text-powered-by": "Tarafından desteklenmektedir", "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-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:", "text-pre-url": "Sırrınız oluşturuldu ve bu link kullanılarak kaydedildi:",
"text-secret-create-disabled": "Bu durumda yeni gizli dizilerin oluşturulması devre dışı bırakılır.",
"title-explanation": "Bu sekilde çalışır…", "title-explanation": "Bu sekilde çalışır…",
"title-new-secret": "Yeni sır oluştur", "title-new-secret": "Yeni sır oluştur",
"title-reading-secret": "Sırrınız okunuyor…", "title-reading-secret": "Sırrınız okunuyor…",
"title-secret-create-disabled": "Gizli yaratım devre dışı bırakıldı...",
"title-secret-created": "Sır oluşturuldu!" "title-secret-created": "Sır oluşturuldu!"
} }