[#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
No known key found for this signature in database
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.
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
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) {
r.HandleFunc("/create", a.handleCreate)
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) {

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 -->
<b-card
v-if="mode == 'create' && !secretId"
v-if="mode == 'create' && !secretId && canWrite"
border-variant="primary"
header-bg-variant="primary"
header-text-variant="white"
@ -110,6 +110,20 @@
</b-button>
</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 -->
<b-card
v-if="mode == 'create' && secretId"
@ -240,6 +254,7 @@ export default {
data() {
return {
canWrite: null,
copyToClipboardSuccess: false,
customize: {},
darkTheme: false,
@ -255,6 +270,23 @@ export default {
},
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() {
navigator.clipboard.writeText(this.secretUrl)
.then(() => {
@ -374,6 +406,7 @@ export default {
// Trigger initialization functions
mounted() {
this.checkWriteAccess()
this.customize = window.OTSCustomize
this.darkTheme = window.getTheme() === 'dark'
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-something-went-wrong": "Irgendwas ging schief. Entschuldigung&hellip;",
"btn-create-secret": "Secret erstellen!",
@ -20,8 +21,10 @@
"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&hellip;",
"title-new-secret": "Erstelle ein neues Secret",
"title-reading-secret": "Secret auslesen&hellip;",
"title-secret-create-disabled": "Erstellen von Secrets deaktiviert…",
"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-something-went-wrong": "Something went wrong. I'm very sorry about this&hellip;",
"btn-create-secret": "Create the secret!",
@ -20,8 +21,10 @@
"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&hellip;",
"title-new-secret": "Create a new secret",
"title-reading-secret": "Reading your secret&hellip;",
"title-secret-create-disabled": "Secret creation disabled…",
"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-something-went-wrong": "Algo ha salido mal. Lo sentimos mucho&hellip;",
"btn-create-secret": "¡Crea el secreto!",
@ -20,8 +21,10 @@
"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": "En este caso, la creación de nuevos secretos está desactivada.",
"title-explanation": "Así es como funciona&hellip;",
"title-new-secret": "Crea un nuevo secreto",
"title-reading-secret": "Obteniendo tu secreto&hellip;",
"title-secret-create-disabled": "Creación secreta desactivada...",
"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-something-went-wrong": "Un problème est survenu. Nous en sommes désolés&hellip;",
"btn-create-secret": "Créer le secret!",
@ -20,8 +21,10 @@
"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:",
"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-new-secret": "Créer un nouveau secret",
"title-reading-secret": "Lecture du secret&hellip;",
"title-secret-create-disabled": "Création secrète désactivée...",
"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-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!",
@ -20,8 +21,10 @@
"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ē:",
"text-secret-create-disabled": "Šajā gadījumā jaunu noslēpumu izveide ir atspējota.",
"title-explanation": "Tā tas strādā&hellip;",
"title-new-secret": "Šifrēt ziņu",
"title-reading-secret": "Atver ziņu&hellip;",
"title-secret-create-disabled": "Slepena izveide atspējota...",
"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-something-went-wrong": "Er ging iets verkeerd, sorry&hellip;",
"btn-create-secret": "Nieuwe vertrouwelijke info aanmaken!",
@ -20,8 +21,10 @@
"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:",
"text-secret-create-disabled": "Het aanmaken van nieuwe geheimen is in dit geval uitgeschakeld.",
"title-explanation": "Dit is hoe het werkt&hellip;",
"title-new-secret": "Nieuwe vertrouwelijke info opslaan",
"title-reading-secret": "Vertrouwelijke info lezen&hellip;",
"title-secret-create-disabled": "Geheime creatie uitgeschakeld...",
"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-something-went-wrong": "Desculpe, algo deu errado…",
"btn-create-secret": "Criar segredo!",
@ -20,8 +21,10 @@
"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:",
"text-secret-create-disabled": "A criação de novos segredos é desativada nesse caso.",
"title-explanation": "É assim como funciona…",
"title-new-secret": "Criar um novo segredo",
"title-reading-secret": "Lendo seu segredo…",
"title-secret-create-disabled": "Criação secreta desativada...",
"title-secret-created": "Segredo criado!"
}

View File

@ -1,4 +1,5 @@
{
"__lang": "ru",
"alert-secret-not-found": "Секрет недоступен&hellip; - Помните, он может быть скомпрометирован. Возможно кто-то другой уже открыл вашу ссылку.",
"alert-something-went-wrong": "Что-то пошло не так. Приносим свои извинения&hellip;",
"btn-create-secret": "Создать секрет!",
@ -20,8 +21,10 @@
"text-powered-by": "Powered by",
"text-pre-reveal-hint": "Чтобы раскрыть секрет, нажмите эту кнопку, но имейте в виду, что это приведет к уничтожению секрета. Вы можете просмотреть его только один раз!",
"text-pre-url": "Ваш секрет создан и сохранён, его URL:",
"text-secret-create-disabled": "Создание новых секретов в этом случае отключено.",
"title-explanation": "Как это работает&hellip;",
"title-new-secret": "Создать новый секрет",
"title-reading-secret": "Читаем ваш секрет&hellip;",
"title-secret-create-disabled": "Секретное создание отключено...",
"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-something-went-wrong": "Något gick fel. Jag ber om ursäkt för detta!&hellip;",
"btn-create-secret": "Skapa hemliget!",
@ -20,8 +21,10 @@
"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:",
"text-secret-create-disabled": "Skapandet av nya hemligheter blockeras i detta fall.",
"title-explanation": "Såhär fungerar det&hellip;",
"title-new-secret": "Skapa ny hemlighet",
"title-reading-secret": "Läs din hemlighet&hellip;",
"title-secret-create-disabled": "Hemlig skapelse avaktiverad...",
"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-something-went-wrong": "Bir şeyler ters gitti. Bunun için çok üzgünüm…",
"btn-create-secret": "Sır oluştur!",
@ -20,8 +21,10 @@
"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:",
"text-secret-create-disabled": "Bu durumda yeni gizli dizilerin oluşturulması devre dışı bırakılır.",
"title-explanation": "Bu sekilde çalışır…",
"title-new-secret": "Yeni sır oluştur",
"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!"
}