[#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:
parent
f5aebbb99a
commit
805a005ed5
14 changed files with 108 additions and 1 deletions
|
@ -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
1
api.go
|
@ -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
41
ci/autotranslate.sh
Normal 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
|
35
src/app.vue
35
src/app.vue
|
@ -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
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"__lang": "de",
|
||||
"alert-secret-not-found": "Das ist nicht das Secret, was du suchst… - 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…",
|
||||
"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…",
|
||||
"title-new-secret": "Erstelle ein neues Secret",
|
||||
"title-reading-secret": "Secret auslesen…",
|
||||
"title-secret-create-disabled": "Erstellen von Secrets deaktiviert…",
|
||||
"title-secret-created": "Secret erstellt!"
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"__lang": "en",
|
||||
"alert-secret-not-found": "This is not the secret you are looking for… - 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…",
|
||||
"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…",
|
||||
"title-new-secret": "Create a new secret",
|
||||
"title-reading-secret": "Reading your secret…",
|
||||
"title-secret-create-disabled": "Secret creation disabled…",
|
||||
"title-secret-created": "Secret created!"
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"__lang": "es",
|
||||
"alert-secret-not-found": "Este no es el secreto que buscas… - 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…",
|
||||
"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…",
|
||||
"title-new-secret": "Crea un nuevo secreto",
|
||||
"title-reading-secret": "Obteniendo tu secreto…",
|
||||
"title-secret-create-disabled": "Creación secreta desactivada...",
|
||||
"title-secret-created": "¡Secreto creado!"
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"__lang": "fr",
|
||||
"alert-secret-not-found": "Ce secret n'est pas celui que vous cherchez… - 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…",
|
||||
"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…",
|
||||
"title-new-secret": "Créer un nouveau secret",
|
||||
"title-reading-secret": "Lecture du secret…",
|
||||
"title-secret-create-disabled": "Création secrète désactivée...",
|
||||
"title-secret-created": "Secret créé!"
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"__lang": "lv",
|
||||
"alert-secret-not-found": "<strong>Ziņa nav atrasta!</strong>… - 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…",
|
||||
"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ā…",
|
||||
"title-new-secret": "Šifrēt ziņu",
|
||||
"title-reading-secret": "Atver ziņu…",
|
||||
"title-secret-create-disabled": "Slepena izveide atspējota...",
|
||||
"title-secret-created": "Ziņa nošifrēta!"
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"__lang": "nl",
|
||||
"alert-secret-not-found": "De gegevens die je zocht bestaan niet (meer)… - Als je hier informatie verwachtte dan is de link mogelijk al door iemand anders bekeken!",
|
||||
"alert-something-went-wrong": "Er ging iets verkeerd, sorry…",
|
||||
"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…",
|
||||
"title-new-secret": "Nieuwe vertrouwelijke info opslaan",
|
||||
"title-reading-secret": "Vertrouwelijke info lezen…",
|
||||
"title-secret-create-disabled": "Geheime creatie uitgeschakeld...",
|
||||
"title-secret-created": "Vertrouwelijke info opgeslaan!"
|
||||
}
|
||||
|
|
|
@ -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!"
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"__lang": "ru",
|
||||
"alert-secret-not-found": "Секрет недоступен… - Помните, он может быть скомпрометирован. Возможно кто-то другой уже открыл вашу ссылку.",
|
||||
"alert-something-went-wrong": "Что-то пошло не так. Приносим свои извинения…",
|
||||
"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": "Как это работает…",
|
||||
"title-new-secret": "Создать новый секрет",
|
||||
"title-reading-secret": "Читаем ваш секрет…",
|
||||
"title-secret-create-disabled": "Секретное создание отключено...",
|
||||
"title-secret-created": "Секрет создан!"
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"__lang": "sv",
|
||||
"alert-secret-not-found": "Hemlighet hittades inte… - 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!…",
|
||||
"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…",
|
||||
"title-new-secret": "Skapa ny hemlighet",
|
||||
"title-reading-secret": "Läs din hemlighet…",
|
||||
"title-secret-create-disabled": "Hemlig skapelse avaktiverad...",
|
||||
"title-secret-created": "Hemlighet skapad!"
|
||||
}
|
||||
|
|
|
@ -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!"
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue