Przeglądaj źródła

Merge pull request #1629 from karthikkasturi/shlink

Added shlink integration
El RIDO 11 miesięcy temu
rodzic
commit
5cc66bb29b

+ 1 - 0
CHANGELOG.md

@@ -5,6 +5,7 @@
 * FIXED: Allow pasting a password for decrypting a paste (#1620)
 * FIXED: Allow copying the shortened link after using a URL shortener (#1624)
 * ADDED: Auto shorten URLs with config option `shortenbydefault` (#1627)
+* ADDED: Added `shortenviashlink` endpoint with an `shlink` configuration section 
 
 ## 2.0.0 (2025-07-28)
 * ADDED: Error logging in database and filesystem backend (#1554)

+ 1 - 0
CREDITS.md

@@ -6,6 +6,7 @@
 * rugk - security review, doc improvment, JS refactoring & various other stuff
 * R4SAS - python client, compression, blob URI to support larger attachments
 * Mikhail Romanov - UI improvements, theme switching, clipboard support, multi-file upload, bugfixes, code refactoring
+* karthikkasturi - shlink proxy and url shortening bugfixes
 
 ## Past contributions
 

+ 11 - 0
cfg/conf.sample.php

@@ -274,6 +274,17 @@ dir = PATH "data"
 ;version = "latest"
 ;bucket = "my-bucket"
 
+;[shlink]
+; - Shlink requires you to make a post call with a generated API key.
+;   use this section to setup the API key and URL. In order to use this section,
+;   "urlshortener" needs to point to the base URL of your PrivateBin
+;   instance with "?shortenviashlink&link=" appended. For example:
+;   urlshortener = "${basepath}?shortenviashlink&link="
+;   This URL will in turn call YOURLS on the server side, using the URL from
+;   "apiurl" and the API Key from the "apikey" parameters below.
+; apiurl = "https://shlink.example.com/rest/v3/short-urls"
+; apikey = "your_api_key"
+
 ;[yourls]
 ; When using YOURLS as a "urlshortener" config item:
 ; - By default, "urlshortener" will point to the YOURLS API URL, with or without

+ 3 - 2
i18n/ar.json

@@ -214,8 +214,9 @@
     "Save document": "احفظ اللصق",
     "Your IP is not authorized to create documents.": "عنوان IP الخاص بك غير مصرح له بإنشاء لصُق.",
     "Trying to shorten a URL that isn't pointing at our instance.": "محاولة تقصير عنوان URL لا يشير إلى خادمنا.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "خطأ في الاتصال بـ YOURLS. ربما تكون هناك مشكلة في التضبيط، مثل \"apiurl\" أو \"التوقيع\" الخاطئ أو المفقود.",
-    "Error parsing YOURLS response.": "خطأ في تحليل استجابة YOURLS.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "خطأ في الاتصال بـ YOURLS. ربما تكون هناك مشكلة في التضبيط، مثل \"apiurl\" أو \"التوقيع\" الخاطئ أو المفقود.",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "خطأ في تحليل استجابة YOURLS.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "يمكن عرض هذه الرسالة السرية مرة واحدة فقط. هل ترغب في رؤيتها الآن؟",
     "Yes, see it": "نعم، دعني اراها",
     "Dark Mode": "الوضع الداكن",

+ 3 - 2
i18n/bg.json

@@ -214,8 +214,9 @@
     "Save document": "Save document",
     "Your IP is not authorized to create documents.": "Your IP is not authorized to create documents.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
-    "Error parsing YOURLS response.": "Error parsing YOURLS response.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?",
     "Yes, see it": "Yes, see it",
     "Dark Mode": "Dark Mode",

+ 3 - 2
i18n/ca.json

@@ -214,8 +214,9 @@
     "Save document": "Save document",
     "Your IP is not authorized to create documents.": "La teva IP no està autoritzada a crear notes.",
     "Trying to shorten a URL that isn't pointing at our instance.": "S'està intentant escurçar un URL que no apunta a la nostra instància.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error en la crida a YOURLS. Probablement és un problema de configuració, com ara \"apiurl\" o \"signature\" incorrectes o que falten.",
-    "Error parsing YOURLS response.": "Error parsing YOURLS response.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Error en la crida a YOURLS. Probablement és un problema de configuració, com ara \"apiurl\" o \"signature\" incorrectes o que falten.",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "Aquest missatge secret sols es pot veure una vegada. Vols obrir-ho ara?",
     "Yes, see it": "Yes, see it",
     "Dark Mode": "Dark Mode",

+ 3 - 2
i18n/co.json

@@ -214,8 +214,9 @@
     "Save document": "Arregistrà u ducumentu",
     "Your IP is not authorized to create documents.": "U vostru indirizzu IP ùn hè micca auturizatu à creà ducumenti.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Pruvate d’ammuzzà un indirizzu web chì ùn punta micca versu a vostra instanza.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Sbagliu à a chjama di YOURLS. Seria forse una cunfigurazione gattiva, tale una « apiurl » o « signature » falsa o assente.",
-    "Error parsing YOURLS response.": "Sbagliu durante l’analisa di a risposta di YOURLS.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Sbagliu à a chjama di YOURLS. Seria forse una cunfigurazione gattiva, tale una « apiurl » o « signature » falsa o assente.",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Sbagliu durante l’analisa di a risposta di YOURLS.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "Stu messaghju secretu pò esse affissatu solu una volta. Vulete fighjallu subitu ?",
     "Yes, see it": "Iè, fighjallu",
     "Dark Mode": "Modu scuru",

+ 3 - 2
i18n/cs.json

@@ -214,8 +214,9 @@
     "Save document": "Uložit příspěvek",
     "Your IP is not authorized to create documents.": "Vaše IP adresa nemá oprávnění k vytváření příspěvků.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Pokus o zkrácení URL, které neodkazuje na naši instanci.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Chyba volání YOURLS. Pravděpodobně chyba konfigurace, např. nesprávné či chybějící „apiurl“ nebo „signature“.",
-    "Error parsing YOURLS response.": "Chyba čtení odpovědi YOURLS.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Chyba volání YOURLS. Pravděpodobně chyba konfigurace, např. nesprávné či chybějící „apiurl“ nebo „signature“.",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Chyba čtení odpovědi YOURLS.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "Tuto tajnou zprávu lze zobrazit pouze jednou. Chcete si ji prohlédnout teď?",
     "Yes, see it": "Ano, zobrazit",
     "Dark Mode": "Tmavý režim",

+ 3 - 2
i18n/de.json

@@ -214,8 +214,9 @@
     "Save document": "Dokument speichern",
     "Your IP is not authorized to create documents.": "Deine IP ist nicht berechtigt, Texte zu erstellen.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Versuch eine URL zu verkürzen, die nicht auf unsere Instanz zeigt.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Fehler beim Aufruf von YOURLS. Wahrscheinlich ein Konfigurationsproblem, wie eine falsche oder fehlende \"apiurl\" oder \"signature\".",
-    "Error parsing YOURLS response.": "Fehler beim Verarbeiten der YOURLS-Antwort.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Fehler beim Aufruf von YOURLS. Wahrscheinlich ein Konfigurationsproblem, wie eine falsche oder fehlende \"apiurl\" oder \"signature\".",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Fehler beim Verarbeiten der YOURLS-Antwort.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "Texte des \"Einmal\"-Typs können nach dem Öffnen nur einmal angezeigt werden. Möchtest Du ihn jetzt einsehen?",
     "Yes, see it": "Ja, jetzt einsehen",
     "Dark Mode": "Nachtmodus",

+ 3 - 2
i18n/el.json

@@ -214,8 +214,9 @@
     "Save document": "Αποθήκευση επικόλλησης",
     "Your IP is not authorized to create documents.": "Η IP σας δεν επιτρέπεται να δημιουργεί επικολλήσεις.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Έγινε προσπάθεια συντόμευσης ενός URL που δε δείχνει προς τη δική μας υπηρεσία.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Σφάλμα κατά την κλήση YOURLS. Πιθανώς ένα ζήτημα διαμόρφωσης, όπως λάθος ή λείπει \"apiurl\" ή \"υπογραφή\".",
-    "Error parsing YOURLS response.": "Σφάλμα ανάλυσης της απόκρισης YOURLS.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Σφάλμα κατά την κλήση YOURLS. Πιθανώς ένα ζήτημα διαμόρφωσης, όπως λάθος ή λείπει \"apiurl\" ή \"υπογραφή\".",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Σφάλμα ανάλυσης της απόκρισης YOURLS.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "Αυτό το μυστικό μήνυμα μπορεί να εμφανιστεί μόνο μία φορά. Θα θέλατε να το δείτε τώρα;",
     "Yes, see it": "Ναι, δείτε το",
     "Dark Mode": "Σκοτεινό Θέμα",

+ 3 - 2
i18n/en.json

@@ -214,8 +214,9 @@
     "Save document": "Save document",
     "Your IP is not authorized to create documents.": "Your IP is not authorized to create documents.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
-    "Error parsing YOURLS response.": "Error parsing YOURLS response.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?",
     "Yes, see it": "Yes, see it",
     "Dark Mode": "Dark Mode",

+ 3 - 2
i18n/es.json

@@ -214,8 +214,9 @@
     "Save document": "Guardar documento",
     "Your IP is not authorized to create documents.": "Tu IP no está autorizada para crear contenido.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Intentando acortar una URL que no apunta a nuestra instancia.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error llamando a YOURLS. Probablemente un problema de configuración, como error o falta \"apiurl\" o \"signature\".",
-    "Error parsing YOURLS response.": "Error al analizar la respuesta de YOURLS.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Error llamando a YOURLS. Probablemente un problema de configuración, como error o falta \"apiurl\" o \"signature\".",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Error al analizar la respuesta de YOURLS.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "Este mensaje secreto sólo se puede mostrar una vez. ¿Quieres verlo ahora?",
     "Yes, see it": "Sí, verlo",
     "Dark Mode": "Modo nocturno",

+ 3 - 2
i18n/et.json

@@ -214,8 +214,9 @@
     "Save document": "Salvesta kleebe",
     "Your IP is not authorized to create documents.": "Su IP-l ei ole lubatud kleepeid luua.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Püüame lühendada URL-i, mis ei viita meie instantsile.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Viga YOURLS-i kutsumisel. Tõenäoliselt konfiguratsiooniprobleem, näiteks vale või puuduv \"apiurl\" või \"signature\".",
-    "Error parsing YOURLS response.": "Viga YOURLS vastuse parsimisel.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Viga YOURLS-i kutsumisel. Tõenäoliselt konfiguratsiooniprobleem, näiteks vale või puuduv \"apiurl\" või \"signature\".",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Viga YOURLS vastuse parsimisel.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "Seda turvalist sõnumit saab kuvada vaid ühe korra. \nKas soovid seda näha nüüd?",
     "Yes, see it": "Jah, vaata seda",
     "Dark Mode": "Tume režiim",

+ 3 - 2
i18n/fi.json

@@ -214,8 +214,9 @@
     "Save document": "Tallenna asiakirja",
     "Your IP is not authorized to create documents.": "IP:llesi ei ole annettu oikeutta luoda pasteja.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Yritetään lyhentää URL-osoite, joka ei osoita meidän instanssiiin.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Virhe kutsuttaessa YOURLS. Luultavasti asetusongelma kuten väärä tai puuttuuva \"apiurl\" tai \"signature\".",
-    "Error parsing YOURLS response.": "Virhe jäsennettäessä YOURLS-vastausta.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Virhe kutsuttaessa YOURLS. Luultavasti asetusongelma kuten väärä tai puuttuuva \"apiurl\" tai \"signature\".",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Virhe jäsennettäessä YOURLS-vastausta.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "Tämä salainen viesti voidaan näyttää vain kerran. Haluatko nähdä sen nyt?",
     "Yes, see it": "Kyllä, näet sen",
     "Dark Mode": "Tumma tila",

+ 3 - 2
i18n/fr.json

@@ -214,8 +214,9 @@
     "Save document": "Sauver le document",
     "Your IP is not authorized to create documents.": "Votre adresse IP n'est pas autorisée à créer des documents.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Tentative de raccourcir une URL qui ne pointe pas vers notre instance.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Erreur lors de l'appel de YOURLS. Peut-être un problème de configuration, comme \"apiurl\" ou \"signature\" manquant.",
-    "Error parsing YOURLS response.": "Erreur d'analyse de la réponse YOURLS.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Erreur lors de l'appel de YOURLS. Peut-être un problème de configuration, comme \"apiurl\" ou \"signature\" manquant.",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Erreur d'analyse de la réponse YOURLS.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "Les documents de type \"Effacer après la lecture\" ne peuvent être affichés qu'une seule fois. Voulez-vous le voir maintenant ?",
     "Yes, see it": "Oui, le voir",
     "Dark Mode": "Mode Sombre",

+ 3 - 2
i18n/he.json

@@ -214,8 +214,9 @@
     "Save document": "שמור הדבקה",
     "Your IP is not authorized to create documents.": "ה-IP שלך אינו מורשה ליצור הדבקות.",
     "Trying to shorten a URL that isn't pointing at our instance.": "מנסים לקצר כתובת URL שאינה מצביעה על המערכת שלנו.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "שגיאה בעת קריאה ל-YOURLS. כנראה מדובר בבעיה בהגדרות, כמו \"apiurl\" או \"signature\" שגויים או חסרים.",
-    "Error parsing YOURLS response.": "שגיאה בניתוח התגובה מ-YOURLS.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "שגיאה בעת קריאה ל-YOURLS. כנראה מדובר בבעיה בהגדרות, כמו \"apiurl\" או \"signature\" שגויים או חסרים.",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "שגיאה בניתוח התגובה מ-YOURLS.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "ההודעה הסודית הזו יכולה להוצג רק פעם אחת. האם תרצה לראות אותה עכשיו?",
     "Yes, see it": "כן, ראה אותה",
     "Dark Mode": "מצב כהה",

+ 3 - 2
i18n/hi.json

@@ -214,8 +214,9 @@
     "Save document": "Save document",
     "Your IP is not authorized to create documents.": "Your IP is not authorized to create documents.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
-    "Error parsing YOURLS response.": "Error parsing YOURLS response.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?",
     "Yes, see it": "Yes, see it",
     "Dark Mode": "Dark Mode",

+ 3 - 2
i18n/hu.json

@@ -214,8 +214,9 @@
     "Save document": "Save document",
     "Your IP is not authorized to create documents.": "Your IP is not authorized to create documents.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
-    "Error parsing YOURLS response.": "Error parsing YOURLS response.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?",
     "Yes, see it": "Yes, see it",
     "Dark Mode": "Sötét mód",

+ 3 - 2
i18n/id.json

@@ -214,8 +214,9 @@
     "Save document": "Simpan document",
     "Your IP is not authorized to create documents.": "Your IP is not authorized to create documents.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
-    "Error parsing YOURLS response.": "Error parsing YOURLS response.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?",
     "Yes, see it": "Yes, see it",
     "Dark Mode": "Mode Gelap",

+ 3 - 2
i18n/it.json

@@ -214,8 +214,9 @@
     "Save document": "Salva il messagio",
     "Your IP is not authorized to create documents.": "Il tuo IP non è autorizzato a creare dei messaggi.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Tantativo in corso di accorciare un URL che non punta alla nostra istanza.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Errore nella chiamata a YOURLS. Probabilmente un problema di configurazione, come un \"apiurl\" o una \"signature\" sbagliati o mancanti.",
-    "Error parsing YOURLS response.": "Errore nell'analizzare la risposta YOURLS.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Errore nella chiamata a YOURLS. Probabilmente un problema di configurazione, come un \"apiurl\" o una \"signature\" sbagliati o mancanti.",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Errore nell'analizzare la risposta YOURLS.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "Questo messaggio di tipo Distruggi-dopo-lettura può essere visualizzato solo una volta. Vuoi vederlo ora?",
     "Yes, see it": "Sì, visualizzalo",
     "Dark Mode": "Tema Scuro",

+ 3 - 2
i18n/ja.json

@@ -214,8 +214,9 @@
     "Save document": "ペーストを保存",
     "Your IP is not authorized to create documents.": "あなたのIPアドレスにはペーストを作成する権限がありません。",
     "Trying to shorten a URL that isn't pointing at our instance.": "このインスタンスを指していないURLを短縮しようとしています。",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "YOURLSの呼び出し中にエラーが発生しました。\"apiurl\"または\"signature\"等の設定に問題がある可能性があります。",
-    "Error parsing YOURLS response.": "YOURLSレスポンスの解析中にエラーが発生しました。",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "YOURLSの呼び出し中にエラーが発生しました。\"apiurl\"または\"signature\"等の設定に問題がある可能性があります。",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "YOURLSレスポンスの解析中にエラーが発生しました。",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?",
     "Yes, see it": "はい、使用します",
     "Dark Mode": "ダークモード",

+ 3 - 2
i18n/jbo.json

@@ -214,8 +214,9 @@
     "Save document": "rejgau fukpi",
     "Your IP is not authorized to create documents.": "Your IP is not authorized to create documents.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
-    "Error parsing YOURLS response.": "Error parsing YOURLS response.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?",
     "Yes, see it": "Yes, see it",
     "Dark Mode": "Dark Mode",

+ 3 - 2
i18n/ko.json

@@ -214,8 +214,9 @@
     "Save document": "Save document",
     "Your IP is not authorized to create documents.": "Your IP is not authorized to create documents.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
-    "Error parsing YOURLS response.": "Error parsing YOURLS response.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?",
     "Yes, see it": "Yes, see it",
     "Dark Mode": "Dark Mode",

+ 3 - 2
i18n/ku.json

@@ -214,8 +214,9 @@
     "Save document": "Save document",
     "Your IP is not authorized to create documents.": "Your IP is not authorized to create documents.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
-    "Error parsing YOURLS response.": "Error parsing YOURLS response.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?",
     "Yes, see it": "Yes, see it",
     "Dark Mode": "جۆری ڕەش",

+ 3 - 2
i18n/la.json

@@ -214,8 +214,9 @@
     "Save document": "Save document",
     "Your IP is not authorized to create documents.": "Your IP is not authorized to create documents.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
-    "Error parsing YOURLS response.": "Error parsing YOURLS response.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?",
     "Yes, see it": "Yes, see it",
     "Dark Mode": "Dark Mode",

+ 3 - 2
i18n/lt.json

@@ -214,8 +214,9 @@
     "Save document": "Įrašyti įdėjimą",
     "Your IP is not authorized to create documents.": "Jūsų IP adresas neturi įgaliojimų kurti įdėjimų.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Bandoma sutrumpinti URL adresą, kuris nenurodo į mūsų egzempliorių.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Klaida iškviečiant YOURLS. Tikriausiai, konfigūracijos klaida, pavyzdžiui, neteisingi „apiurl“ ar „signature“, arba jų nėra.",
-    "Error parsing YOURLS response.": "Klaida nagrinėjant YOURLS atsaką.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Klaida iškviečiant YOURLS. Tikriausiai, konfigūracijos klaida, pavyzdžiui, neteisingi „apiurl“ ar „signature“, arba jų nėra.",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Klaida nagrinėjant YOURLS atsaką.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "Ši slapta žinutė gali būti parodyta tik vieną kartą. Ar norėtumėte ją dabar pamatyti?",
     "Yes, see it": "Taip, pamatyti",
     "Dark Mode": "Tamsi veiksena",

+ 3 - 2
i18n/nl.json

@@ -214,8 +214,9 @@
     "Save document": "Document opslaan",
     "Your IP is not authorized to create documents.": "Je IP-adres is niet gemachtigd om documenten te maken.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Proberen om een URL te verkorten dat niet naar ons systeem wijst.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Foutmelding ophalen YOURLS. Waarschijnlijk een configuratiefout, zoals een verkeerde of missende \"apiurl\" of \"signature\".",
-    "Error parsing YOURLS response.": "Foutmelding bij parsen van YOURLS respons.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Foutmelding ophalen YOURLS. Waarschijnlijk een configuratiefout, zoals een verkeerde of missende \"apiurl\" of \"signature\".",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Foutmelding bij parsen van YOURLS respons.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "Dit geheime bericht kan maar één keer worden weergegeven. Wil je het nu zien?",
     "Yes, see it": "Ja, tonen",
     "Dark Mode": "Donkere modus",

+ 3 - 2
i18n/no.json

@@ -214,8 +214,9 @@
     "Save document": "Lagre utklipp",
     "Your IP is not authorized to create documents.": "Din IP er ikke autorisert til å opprette dokumenter.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Prøver å forkorte en URL som ikke peker i vår instans.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Feil ved å besøke YOURLS. Sannsynligvis et konfigurasjonsproblem, eksempelvis feil eller mangler, med \"apiurl\" eller \"signatur\".",
-    "Error parsing YOURLS response.": "Feil ved analyse av YOURLS svar.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Feil ved å besøke YOURLS. Sannsynligvis et konfigurasjonsproblem, eksempelvis feil eller mangler, med \"apiurl\" eller \"signatur\".",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Feil ved analyse av YOURLS svar.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "Denne hemmelige meldingen kan bare vises én gang. Vil du se den nå?",
     "Yes, see it": "Ja, se det",
     "Dark Mode": "Mørk modus",

+ 3 - 2
i18n/oc.json

@@ -214,8 +214,9 @@
     "Save document": "Enregistrar lo tèxt",
     "Your IP is not authorized to create documents.": "Vòstra adreça IP a pas l’autorizacion de crear de tèxtes.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Ensag d’abracar una URL que mena pas a nòstra instància.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error en cridant YOURLS. Es probablament un problèma de configuracion, quicòm coma « apirul » o « signature » marrit o absent.",
-    "Error parsing YOURLS response.": "Error d'analisi de la responsa YOURLS.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Error en cridant YOURLS. Es probablament un problèma de configuracion, quicòm coma « apirul » o « signature » marrit o absent.",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Error d'analisi de la responsa YOURLS.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "Aqueste messatge secrèt se pòt pas qu'afichar un còp. Lo volètz veire ara ?",
     "Yes, see it": "Òc, afichatz-lo",
     "Dark Mode": "Mòde escur",

+ 3 - 2
i18n/pl.json

@@ -214,8 +214,9 @@
     "Save document": "Zapisz dokument",
     "Your IP is not authorized to create documents.": "Twój adres IP nie jest autoryzowany do tworzenia dokumentów.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Próba skrócenia adresu URL wskazującego na inną instancję.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Błąd wywoływania YOURLS. Możliwy błąd konfiguracji, taki jak błędne lub brakujące \"apiurl\" lub \"signature\".",
-    "Error parsing YOURLS response.": "Błąd przetwarzania odpowiedzi YOURLS.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Błąd wywoływania YOURLS. Możliwy błąd konfiguracji, taki jak błędne lub brakujące \"apiurl\" lub \"signature\".",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Błąd przetwarzania odpowiedzi YOURLS.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "Tę tajną wiadomość możesz zobaczyć tylko jeden raz. Czy chcesz to zrobić teraz?",
     "Yes, see it": "Tak, pokaż",
     "Dark Mode": "Ciemny motyw",

+ 3 - 2
i18n/pt.json

@@ -214,8 +214,9 @@
     "Save document": "Salvar cópia",
     "Your IP is not authorized to create documents.": "Seu IP não está autorizado a criar cópias.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Tentando encurtar uma URL que não aponta para a nossa instância.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Erro ao chamar YOURLS. Provavelmente um problema de configuração, como errado ou faltando \"apiurl\" ou \"signature\".",
-    "Error parsing YOURLS response.": "Erro ao analisar a resposta do YOURLS.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Erro ao chamar YOURLS. Provavelmente um problema de configuração, como errado ou faltando \"apiurl\" ou \"signature\".",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Erro ao analisar a resposta do YOURLS.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "Esta mensagem secreta só pode ser exibida uma vez. Gostaria de vê-la agora?",
     "Yes, see it": "Sim, veja",
     "Dark Mode": "Modo Noturno",

+ 3 - 2
i18n/ro.json

@@ -214,8 +214,9 @@
     "Save document": "Salvați document-ul",
     "Your IP is not authorized to create documents.": "Adresa dvs. IP nu este autorizată să creeze document-uri.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Încercarea de a scurta un URL care nu direcționează spre instanța noastră.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Eroare la apelarea YOURLS. Probabil o problemă de configurare, cum ar fi \"apiurl\" sau \"signature\" greșite sau lipsă.",
-    "Error parsing YOURLS response.": "Eroare la analizarea răspunsului YOURLS.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Eroare la apelarea YOURLS. Probabil o problemă de configurare, cum ar fi \"apiurl\" sau \"signature\" greșite sau lipsă.",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Eroare la analizarea răspunsului YOURLS.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "Acest mesaj secret poate fi afișat o singură dată. Doriți să îl vedeți acum?",
     "Yes, see it": "Da, vezi",
     "Dark Mode": "Mod întunecat",

+ 3 - 2
i18n/ru.json

@@ -214,8 +214,9 @@
     "Save document": "Сохранить запись",
     "Your IP is not authorized to create documents.": "Вашему IP адресу не разрешено создавать записи.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Попытка сократить URL, который указывает не на наш сервер.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Ошибка обращения к YOURLS. Возможно в конфигурации допущена ошибка, например неверный или отсутствующий параметр \"apiurl\" или \"signature\".",
-    "Error parsing YOURLS response.": "Ошибка разбора ответа от YOURLS.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Ошибка обращения к YOURLS. Возможно в конфигурации допущена ошибка, например неверный или отсутствующий параметр \"apiurl\" или \"signature\".",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Ошибка разбора ответа от YOURLS.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "Записи, удаляемые после прочтения, могут быть отображены после загрузки только один раз. Вы хотите открыть её сейчас?",
     "Yes, see it": "Да, загрузить",
     "Dark Mode": "Тёмная",

+ 3 - 2
i18n/sk.json

@@ -214,8 +214,9 @@
     "Save document": "Uložiť príspevok",
     "Your IP is not authorized to create documents.": "Vaša IP adresa nie je oprávnená vytvárať príspevky.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Pokúšate sa skrátiť adresu URL, ktorá neukazuje na túto inštanciu.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
-    "Error parsing YOURLS response.": "Error parsing YOURLS response.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?",
     "Yes, see it": "Áno, zobraziť",
     "Dark Mode": "Tmavý Režim",

+ 3 - 2
i18n/sl.json

@@ -214,8 +214,9 @@
     "Save document": "Save document",
     "Your IP is not authorized to create documents.": "Your IP is not authorized to create documents.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
-    "Error parsing YOURLS response.": "Error parsing YOURLS response.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?",
     "Yes, see it": "Yes, see it",
     "Dark Mode": "Temni način",

+ 3 - 2
i18n/sv.json

@@ -214,8 +214,9 @@
     "Save document": "Save document",
     "Your IP is not authorized to create documents.": "Your IP is not authorized to create documents.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
-    "Error parsing YOURLS response.": "Error parsing YOURLS response.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?",
     "Yes, see it": "Yes, see it",
     "Dark Mode": "Mörkt Läge",

+ 3 - 2
i18n/th.json

@@ -214,8 +214,9 @@
     "Save document": "ดาวน์โหลดข้อมูลการฝากโค้ด",
     "Your IP is not authorized to create documents.": "IP ของคุณไม่ได้รับอนุญาตให้สร้างการฝากโค้ด",
     "Trying to shorten a URL that isn't pointing at our instance.": "กำลังพยายามใช้เครื่องมือสร้างลิงก์ย่อ ที่ไม่ได้ชี้ไปที่อินสแตนซ์ของเรา",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "เกิดข้อผิดพลาดในการเรียก YOURLS อาจเป็นปัญหามาจากการกำหนดค่า เช่น \"apiurl\" หรือ \"signature\" ไม่ถูกต้องหรือขาดหายไป",
-    "Error parsing YOURLS response.": "เกิดข้อผิดพลาดในการแยกวิเคราะห์การตอบสนองของ YOURLS",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "เกิดข้อผิดพลาดในการเรียก YOURLS อาจเป็นปัญหามาจากการกำหนดค่า เช่น \"apiurl\" หรือ \"signature\" ไม่ถูกต้องหรือขาดหายไป",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "เกิดข้อผิดพลาดในการแยกวิเคราะห์การตอบสนองของ YOURLS",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "ข้อความลับนี้จะแสดงได้เพียงครั้งเดียวเท่านั้น คุณต้องการดูข้อความนี้ตอนนี้เลยใช่หรือไม่",
     "Yes, see it": "ใช่ ดูเลย",
     "Dark Mode": "โหมดสีเข้ม",

+ 3 - 2
i18n/tr.json

@@ -214,8 +214,9 @@
     "Save document": "Yazıyı kaydet",
     "Your IP is not authorized to create documents.": "IP adresinizin yazı oluşturmaya yetkisi yoktur.",
     "Trying to shorten a URL that isn't pointing at our instance.": "URL'yi kısaltmaya çalışırken, bizim sunucumuza işaret etmeyen bir URL kullanıyorsunuz.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "YOURLS çağrısı başarısız oldu. Muhtemelen \"apiurl\" veya \"signature\" gibi yanlış veya eksik yapılandırma hatası.",
-    "Error parsing YOURLS response.": "YOURLS yanıtı ayrıştırılamadı.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "YOURLS çağrısı başarısız oldu. Muhtemelen \"apiurl\" veya \"signature\" gibi yanlış veya eksik yapılandırma hatası.",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "YOURLS yanıtı ayrıştırılamadı.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "Bu gizli mesaj yalnızca bir kez görüntülenebilir. Şimdi görmek ister misiniz?",
     "Yes, see it": "Evet, gör",
     "Dark Mode": "Koyu Mod",

+ 3 - 2
i18n/uk.json

@@ -214,8 +214,9 @@
     "Save document": "Зберегти вставку",
     "Your IP is not authorized to create documents.": "Вашому IP не дозволено створювати вставки.",
     "Trying to shorten a URL that isn't pointing at our instance.": "Спроба скоротити URL, який не вказує на наш екземпляр.",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Помилка виклику YOURLS. Ймовірно проблема з налаштуванням, наприклад \"apiurl\" чи \"signature\".",
-    "Error parsing YOURLS response.": "Помилка розбору відповіді YOURLS.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Помилка виклику YOURLS. Ймовірно проблема з налаштуванням, наприклад \"apiurl\" чи \"signature\".",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Помилка розбору відповіді YOURLS.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "Це таємне повідомлення можна надіслати лише один раз. Хочете переглянути його зараз?",
     "Yes, see it": "Так, побачити",
     "Dark Mode": "Темний режим",

+ 3 - 2
i18n/zh.json

@@ -214,8 +214,9 @@
     "Save document": "保存内容",
     "Your IP is not authorized to create documents.": "您的 IP 无权创建粘贴。",
     "Trying to shorten a URL that isn't pointing at our instance.": "尝试缩短一个不指向我们实例的URL。",
-    "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "调用 YOURLS 时出错。可能是配置问题,例如“apiurl”或“signature”错误或缺失。",
-    "Error parsing YOURLS response.": "解析 YOURLS 响应时出错。",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "调用 YOURLS 时出错。可能是配置问题,例如“apiurl”或“signature”错误或缺失。",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "解析 YOURLS 响应时出错。",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
     "This secret message can only be displayed once. Would you like to see it now?": "读取粘贴后只能在加载时显示一次。您想现在打开吗?",
     "Yes, see it": "是的,加载它",
     "Dark Mode": "夜间模式",

+ 4 - 0
lib/Configuration.php

@@ -107,6 +107,10 @@ class Configuration
             'signature' => '',
             'apiurl'    => '',
         ),
+        'shlink' => array(
+            'apikey'    => '',
+            'apiurl'    => '',
+        ),
         // update this array when adding/changing/removing js files
         'sri' => array(
             'js/base-x-5.0.1.js'     => 'sha512-FmhlnjIxQyxkkxQmzf0l6IRGsGbgyCdgqPxypFsEtHMF1naRqaLLo6mcyN5rEaT16nKx1PeJ4g7+07D6gnk/Tg==',

+ 19 - 9
lib/Controller.php

@@ -14,6 +14,9 @@ namespace PrivateBin;
 use Exception;
 use PrivateBin\Persistence\ServerSalt;
 use PrivateBin\Persistence\TrafficLimiter;
+use PrivateBin\Proxy\AbstractProxy;
+use PrivateBin\Proxy\ShlinkProxy;
+use PrivateBin\Proxy\YourlsProxy;
 
 /**
  * Controller
@@ -149,7 +152,10 @@ class Controller
                 $this->_jsonld($this->_request->getParam('jsonld'));
                 return;
             case 'yourlsproxy':
-                $this->_yourlsproxy($this->_request->getParam('link'));
+                $this->_shortenerproxy(new YourlsProxy($this->_conf, $this->_request->getParam('link')));
+                break;
+            case 'shlinkproxy':
+                $this->_shortenerproxy(new ShlinkProxy($this->_conf, $this->_request->getParam('link')));
                 break;
         }
 
@@ -451,7 +457,12 @@ class Controller
         $page->assign('NAME', $this->_conf->getKey('name'));
         if ($this->_request->getOperation() === 'yourlsproxy') {
             $page->assign('SHORTURL', $this->_status);
-            $page->draw('yourlsproxy');
+            $page->draw('shortenerproxy');
+            return;
+        }
+        if ($this->_request->getOperation() === 'shlinkproxy') {
+            $page->assign('SHORTURL', $this->_status);
+            $page->draw('shortenerproxy');
             return;
         }
         $page->assign('BASEPATH', I18n::_($this->_conf->getKey('basepath')));
@@ -528,18 +539,17 @@ class Controller
     }
 
     /**
-     * proxies link to YOURLS, updates status or error with response
+     * Proxies a link using the specified proxy class, and updates the status or error with the response.
      *
      * @access private
-     * @param string $link
+     * @param AbstractProxy $proxy The instance of the proxy class.
      */
-    private function _yourlsproxy($link)
+    private function _shortenerproxy(AbstractProxy $proxy)
     {
-        $yourls = new YourlsProxy($this->_conf, $link);
-        if ($yourls->isError()) {
-            $this->_error = $yourls->getError();
+        if ($proxy->isError()) {
+            $this->_error = $proxy->getError();
         } else {
-            $this->_status = $yourls->getUrl();
+            $this->_status = $proxy->getUrl();
         }
     }
 

+ 165 - 0
lib/Proxy/AbstractProxy.php

@@ -0,0 +1,165 @@
+<?php declare(strict_types=1);
+/**
+ * PrivateBin
+ *
+ * a zero-knowledge paste bin
+ *
+ * @link      https://github.com/PrivateBin/PrivateBin
+ * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
+ * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
+ */
+
+namespace PrivateBin\Proxy;
+
+use Exception;
+use PrivateBin\Configuration;
+use PrivateBin\Json;
+
+/**
+ * AbstractProxy
+ *
+ * Forwards a URL for shortening and stores the result.
+ */
+abstract class AbstractProxy
+{
+    /**
+     * error message
+     *
+     * @access private
+     * @var    string
+     */
+    private $_error = '';
+
+    /**
+     * shortened URL
+     *
+     * @access private
+     * @var    string
+     */
+    private $_url = '';
+
+    /**
+     * constructor
+     *
+     * initializes and runs the proxy class
+     *
+     * @access public
+     * @param Configuration $conf
+     * @param string $link
+     */
+    public function __construct(Configuration $conf, string $link)
+    {
+        if (!str_starts_with($link, $conf->getKey('basepath') . '?')) {
+            $this->_error = 'Trying to shorten a URL that isn\'t pointing at our instance.';
+            return;
+        }
+
+        $proxyUrl = $this->_getProxyUrl($conf);
+
+        if (empty($proxyUrl)) {
+            $this->_error = 'Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.';
+            $this->logErrorWithClassName($this->_error);
+            return;
+        }
+
+        $data = file_get_contents($proxyUrl, false,
+            stream_context_create(
+                array(
+                    'http' => $this->_getProxyPayload($conf, $link),
+                )
+            )
+        );
+
+        if ($data === false) {
+            $http_response_header = $http_response_header ?? array();
+            $statusCode           = '';
+            if (!empty($http_response_header) && preg_match('/HTTP\/\d+\.\d+\s+(\d+)/', $http_response_header[0], $matches)) {
+                $statusCode = $matches[1];
+            }
+            $this->_error = 'Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.';
+            $this->logErrorWithClassName($this->_error . ' Status code: ' . $statusCode);
+            return;
+        }
+
+        try {
+            $jsonData = Json::decode($data);
+        } catch (Exception $e) {
+            $this->_error = 'Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.';
+            $this->logErrorWithClassName('Error calling proxy: ' . $e->getMessage());
+            return;
+        }
+
+        $url = $this->_extractShortUrl($jsonData);
+
+        if ($url === null || empty($url)) {
+            $this->_error = 'Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.';
+            $this->logErrorWithClassName('Error calling proxy: ' . $data);
+        } else {
+            $this->_url = $url;
+        }
+    }
+
+    private function logErrorWithClassName(string $error)
+    {
+        error_log('[' . get_class($this) . '] ' . $error);
+    }
+
+    /**
+     * Returns the (untranslated) error message
+     *
+     * @access public
+     * @return string
+     */
+    public function getError()
+    {
+        return $this->_error;
+    }
+
+    /**
+     * Returns the shortened URL
+     *
+     * @access public
+     * @return string
+     */
+    public function getUrl()
+    {
+        return $this->_url;
+    }
+
+    /**
+     * Returns true if any error has occurred
+     *
+     * @access public
+     * @return bool
+     */
+    public function isError()
+    {
+        return !empty($this->_error);
+    }
+
+    /**
+     * Abstract method to get the payload to send to the URL shortener
+     *
+     * @access protected
+     * @param Configuration $conf
+     * @param string $link
+     * @return array
+     */
+    abstract protected function _getProxyPayload(Configuration $conf, string $link): array;
+
+    /**
+     * Abstract method to extract the shortUrl from the response
+     *
+     * @param array $data
+     * @return ?string
+     */
+    abstract protected function _extractShortUrl(array $data): ?string;
+
+    /**
+     * Abstract method to get the proxy URL
+     *
+     * @param Configuration $conf
+     * @return string
+     */
+    abstract protected function _getProxyUrl(Configuration $conf): string;
+}

+ 75 - 0
lib/Proxy/ShlinkProxy.php

@@ -0,0 +1,75 @@
+<?php declare(strict_types=1);
+/**
+ * PrivateBin
+ *
+ * a zero-knowledge paste bin
+ *
+ * @link      https://github.com/PrivateBin/PrivateBin
+ * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
+ * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
+ */
+
+namespace PrivateBin\Proxy;
+
+use PrivateBin\Configuration;
+use PrivateBin\Json;
+
+/**
+ * ShlinkProxy
+ *
+ * Forwards a URL for shortening to shlink and stores the result.
+ */
+class ShlinkProxy extends AbstractProxy
+{
+    /**
+     * Overrides the abstract parent function to get the proxy URL.
+     *
+     * @param Configuration $conf
+     * @return string
+     */
+    protected function _getProxyUrl(Configuration $conf): string
+    {
+        return $conf->getKey('apiurl', 'shlink');
+    }
+
+    /**
+     * Overrides the abstract parent function to get contents from Shlink API.
+     *
+     * @access protected
+     * @param Configuration $conf
+     * @param string $link
+     * @return array
+     */
+    protected function _getProxyPayload(Configuration $conf, string $link): array
+    {
+        $shlink_api_key = $conf->getKey('apikey', 'shlink');
+
+        $body = array(
+            'longUrl' => $link,
+        );
+
+        return array(
+            'method'  => 'POST',
+            'header'  => "Content-Type: application/json\r\n" .
+                         'X-Api-Key: ' . $shlink_api_key . "\r\n",
+            'content' => Json::encode($body),
+        );
+    }
+
+    /**
+     * Extracts the short URL from the shlink API response.
+     *
+     * @access protected
+     * @param array $data
+     * @return ?string
+     */
+    protected function _extractShortUrl(array $data): ?string
+    {
+        if (
+            array_key_exists('shortUrl', $data)
+        ) {
+            return $data['shortUrl'];
+        }
+        return null;
+    }
+}

+ 77 - 0
lib/Proxy/YourlsProxy.php

@@ -0,0 +1,77 @@
+<?php declare(strict_types=1);
+/**
+ * PrivateBin
+ *
+ * a zero-knowledge paste bin
+ *
+ * @link      https://github.com/PrivateBin/PrivateBin
+ * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
+ * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
+ */
+
+namespace PrivateBin\Proxy;
+
+use PrivateBin\Configuration;
+
+/**
+ * YourlsProxy
+ *
+ * Forwards a URL for shortening to YOURLS (your own URL shortener) and stores
+ * the result.
+ */
+class YourlsProxy extends AbstractProxy
+{
+    /**
+     * Overrides the abstract parent function to get the proxy URL.
+     *
+     * @param Configuration $conf
+     * @return string
+     */
+    protected function _getProxyUrl(Configuration $conf): string
+    {
+        return $conf->getKey('apiurl', 'yourls');
+    }
+
+    /**
+     * Overrides the abstract parent function to get contents from YOURLS API.
+     *
+     * @access protected
+     * @param Configuration $conf
+     * @param string $link
+     * @return array
+     */
+    protected function _getProxyPayload(Configuration $conf, string $link): array
+    {
+        return array(
+            'method'  => 'POST',
+            'header'  => "Content-Type: application/x-www-form-urlencoded\r\n",
+            'content' => http_build_query(
+                array(
+                    'signature' => $conf->getKey('signature', 'yourls'),
+                    'format'    => 'json',
+                    'action'    => 'shorturl',
+                    'url'       => $link,
+                )
+            ),
+        );
+    }
+
+    /**
+     * Extracts the short URL from the YOURLS API response.
+     *
+     * @access protected
+     * @param array $data
+     * @return ?string
+     */
+    protected function _extractShortUrl(array $data): ?string
+    {
+        if (
+            array_key_exists('statusCode', $data) &&
+            $data['statusCode'] == 200 &&
+            array_key_exists('shorturl', $data)
+        ) {
+            return $data['shorturl'];
+        }
+        return null;
+    }
+}

+ 4 - 0
lib/Request.php

@@ -124,6 +124,7 @@ class Request
                     'link'             => FILTER_SANITIZE_URL,
                     'pasteid'          => FILTER_SANITIZE_SPECIAL_CHARS,
                     'shortenviayourls' => FILTER_SANITIZE_SPECIAL_CHARS,
+                    'shortenviashlink' => FILTER_SANITIZE_SPECIAL_CHARS,
                 ), false);
         }
         if (
@@ -149,6 +150,9 @@ class Request
             if (str_contains($this->getRequestUri(), '/shortenviayourls') || array_key_exists('shortenviayourls', $this->_params)) {
                 $this->_operation = 'yourlsproxy';
             }
+            if (str_contains($this->getRequestUri(), '/shortenviashlink') || array_key_exists('shortenviashlink', $this->_params)) {
+                $this->_operation = 'shlinkproxy';
+            }
         }
     }
 

+ 0 - 131
lib/YourlsProxy.php

@@ -1,131 +0,0 @@
-<?php declare(strict_types=1);
-/**
- * PrivateBin
- *
- * a zero-knowledge paste bin
- *
- * @link      https://github.com/PrivateBin/PrivateBin
- * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
- * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
- */
-
-namespace PrivateBin;
-
-use Exception;
-
-/**
- * YourlsProxy
- *
- * Forwards a URL for shortening to YOURLS (your own URL shortener) and stores
- * the result.
- */
-class YourlsProxy
-{
-    /**
-     * error message
-     *
-     * @access private
-     * @var    string
-     */
-    private $_error = '';
-
-    /**
-     * shortened URL
-     *
-     * @access private
-     * @var    string
-     */
-    private $_url = '';
-
-    /**
-     * constructor
-     *
-     * initializes and runs PrivateBin
-     *
-     * @access public
-     * @param string $link
-     */
-    public function __construct(Configuration $conf, $link)
-    {
-        if (!str_starts_with($link, $conf->getKey('basepath') . '?')) {
-            $this->_error = 'Trying to shorten a URL that isn\'t pointing at our instance.';
-            return;
-        }
-
-        $yourls_api_url = $conf->getKey('apiurl', 'yourls');
-        if (empty($yourls_api_url)) {
-            $this->_error = 'Error calling YOURLS. Probably a configuration issue, like wrong or missing "apiurl" or "signature".';
-            return;
-        }
-
-        $data = file_get_contents(
-            $yourls_api_url, false, stream_context_create(
-                array(
-                    'http' => array(
-                        'method'  => 'POST',
-                        'header'  => "Content-Type: application/x-www-form-urlencoded\r\n",
-                        'content' => http_build_query(
-                            array(
-                                'signature' => $conf->getKey('signature', 'yourls'),
-                                'format'    => 'json',
-                                'action'    => 'shorturl',
-                                'url'       => $link,
-                            )
-                        ),
-                    ),
-                )
-            )
-        );
-        try {
-            $data = Json::decode($data);
-        } catch (Exception $e) {
-            $this->_error = 'Error calling YOURLS. Probably a configuration issue, like wrong or missing "apiurl" or "signature".';
-            error_log('Error calling YOURLS: ' . $e->getMessage());
-            return;
-        }
-
-        if (
-            !is_null($data) &&
-            array_key_exists('statusCode', $data) &&
-            $data['statusCode'] == 200 &&
-            array_key_exists('shorturl', $data)
-        ) {
-            $this->_url = $data['shorturl'];
-        } else {
-            $this->_error = 'Error parsing YOURLS response.';
-        }
-    }
-
-    /**
-     * Returns the (untranslated) error message
-     *
-     * @access public
-     * @return string
-     */
-    public function getError()
-    {
-        return $this->_error;
-    }
-
-    /**
-     * Returns the shortened URL
-     *
-     * @access public
-     * @return string
-     */
-    public function getUrl()
-    {
-        return $this->_url;
-    }
-
-    /**
-     * Returns true if any error has occurred
-     *
-     * @access public
-     * @return bool
-     */
-    public function isError()
-    {
-        return !empty($this->_error);
-    }
-}

+ 0 - 0
tpl/yourlsproxy.php → tpl/shortenerproxy.php


+ 109 - 1
tst/JsonApiTest.php

@@ -313,6 +313,88 @@ class JsonApiTest extends TestCase
         $this->assertStringContainsString('id="pasteurl" href="https://example.com/1"', $content, "'{$baseUri}' outputs shortened URL correctly");
     }
 
+    /**
+     * @runInSeparateProcess
+     * @dataProvider baseShlinkUriProvider
+     */
+    public function testShortenViaShlink($baseUri)
+    {
+        $mock_shlink_service                = $this->_path . DIRECTORY_SEPARATOR . 'shlink.json';
+        $options                            = parse_ini_file(CONF, true);
+        $options['main']['basepath']        = 'https://example.com/path'; // missing slash gets added by Configuration constructor
+        $options['main']['urlshortener']    = 'https://example.com' . $baseUri . 'link=';
+        $options['shlink']['apiurl']        = $mock_shlink_service;
+        Helper::createIniFile(CONF, $options);
+
+        // the real service answer is more complex, but we only look for the shorturl & statusCode
+        file_put_contents($mock_shlink_service, '{"shortUrl":"https:\/\/example.com\/1"}');
+
+        $_SERVER['REQUEST_URI'] = $baseUri . 'link=https%3A%2F%2Fexample.com%2Fpath%2F%3Ffoo%23bar';
+        $_GET['link']           = 'https://example.com/path/?foo#bar';
+        if (str_contains($baseUri, '?shortenviashlink')) {
+            $_GET['shortenviashlink'] = null;
+        }
+        ob_start();
+        new Controller;
+        $content = ob_get_contents();
+        ob_end_clean();
+        $this->assertStringContainsString('id="pasteurl" href="https://example.com/1"', $content, "'{$baseUri}' outputs shortened URL correctly");
+    }
+
+    /**
+     * @runInSeparateProcess
+     * @dataProvider baseShlinkUriProvider
+     */
+    public function testShortenViaShlinkFailureHttp($baseUri)
+    {
+        $mock_shlink_service                = 'https://httpbin.org/status/403';
+        $options                            = parse_ini_file(CONF, true);
+        $options['main']['basepath']        = 'https://example.com/path'; // missing slash gets added by Configuration constructor
+        $options['main']['urlshortener']    = 'https://example.com' . $baseUri . 'link=';
+        $options['shlink']['apiurl']        = $mock_shlink_service;
+        Helper::createIniFile(CONF, $options);
+
+        $_SERVER['REQUEST_URI'] = $baseUri . 'link=https%3A%2F%2Fexample.com%2Fpath%2F%3Ffoo%23bar';
+        $_GET['link']           = 'https://example.com/path/?foo#bar';
+        if (str_contains($baseUri, '?shortenviashlink')) {
+            $_GET['shortenviashlink'] = null;
+        }
+        ob_start();
+        // Use @ to ignore the http warning for the 403. It will be handled appropriately by AbstractProxy
+        @new Controller;
+        $content = ob_get_contents();
+        ob_end_clean();
+        $this->assertStringContainsString('Proxy error: Bad response.', $content, 'outputs error correctly');
+    }
+
+    /**
+     * @runInSeparateProcess
+     * @dataProvider baseShlinkUriProvider
+     */
+    public function testShortenViaShlinkSuccessButMissingShortUrl($baseUri)
+    {
+        $mock_shlink_service                = $this->_path . DIRECTORY_SEPARATOR . 'shlink.json';
+        $options                            = parse_ini_file(CONF, true);
+        $options['main']['basepath']        = 'https://example.com/path'; // missing slash gets added by Configuration constructor
+        $options['main']['urlshortener']    = 'https://example.com' . $baseUri . 'link=';
+        $options['shlink']['apiurl']        = $mock_shlink_service;
+        Helper::createIniFile(CONF, $options);
+
+        // Ideally, this should never happen, just in case "shortUrl" is somehow missing in the 200 response
+        file_put_contents($mock_shlink_service, '{}');
+
+        $_SERVER['REQUEST_URI'] = $baseUri . 'link=https%3A%2F%2Fexample.com%2Fpath%2F%3Ffoo%23bar';
+        $_GET['link']           = 'https://example.com/path/?foo#bar';
+        if (str_contains($baseUri, '?shortenviashlink')) {
+            $_GET['shortenviashlink'] = null;
+        }
+        ob_start();
+        new Controller;
+        $content = ob_get_contents();
+        ob_end_clean();
+        $this->assertStringContainsString('Proxy error: Error parsing proxy response.', $content, 'outputs error correctly');
+    }
+
     public function baseUriProvider()
     {
         return array(
@@ -322,6 +404,15 @@ class JsonApiTest extends TestCase
         );
     }
 
+    public function baseShlinkUriProvider()
+    {
+        return array(
+            array('/path/shortenviashlink?'),
+            array('/path/index.php/shortenviashlink?'),
+            array('/path?shortenviashlink&'),
+        );
+    }
+
     /**
      * @runInSeparateProcess
      */
@@ -336,6 +427,23 @@ class JsonApiTest extends TestCase
         new Controller;
         $content = ob_get_contents();
         ob_end_clean();
-        $this->assertStringContainsString('Error calling YOURLS.', $content, 'outputs error correctly');
+        $this->assertStringContainsString('Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.', $content, 'outputs error correctly');
+    }
+
+    /**
+     * @runInSeparateProcess
+     */
+    public function testShortenViaShlinkFailure()
+    {
+        $options                            = parse_ini_file(CONF, true);
+        $options['main']['basepath']        = 'https://example.com/path'; // missing slash gets added by Configuration constructor
+        Helper::createIniFile(CONF, $options);
+        $_SERVER['REQUEST_URI'] = '/path/shortenviashlink?link=https%3A%2F%2Fexample.com%2Fpath%2F%3Ffoo%23bar';
+        $_GET['link']           = 'https://example.com/path/?foo#bar';
+        ob_start();
+        new Controller;
+        $content = ob_get_contents();
+        ob_end_clean();
+        $this->assertStringContainsString('Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.', $content, 'outputs error correctly');
     }
 }

+ 2 - 2
tst/ViewTest.php

@@ -106,8 +106,8 @@ class ViewTest extends TestCase
                 $content,
                 $template . ': outputs error correctly'
             );
-            if ($template === 'yourlsproxy') {
-                // yourlsproxy template only displays error message
+            if ($template === 'shortenerproxy') {
+                // shortenerproxy template only displays error message
                 continue;
             }
             $this->assertMatchesRegularExpression(

+ 3 - 3
tst/YourlsProxyTest.php

@@ -2,7 +2,7 @@
 
 use PHPUnit\Framework\TestCase;
 use PrivateBin\Configuration;
-use PrivateBin\YourlsProxy;
+use PrivateBin\Proxy\YourlsProxy;
 
 class YourlsProxyTest extends TestCase
 {
@@ -68,7 +68,7 @@ class YourlsProxyTest extends TestCase
 
         $yourls = new YourlsProxy($this->_conf, 'https://example.com/?foo#bar');
         $this->assertTrue($yourls->isError());
-        $this->assertEquals($yourls->getError(), 'Error parsing YOURLS response.');
+        $this->assertEquals($yourls->getError(), 'Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.');
     }
 
     public function testServerError()
@@ -78,6 +78,6 @@ class YourlsProxyTest extends TestCase
 
         $yourls = new YourlsProxy($this->_conf, 'https://example.com/?foo#bar');
         $this->assertTrue($yourls->isError());
-        $this->assertEquals($yourls->getError(), 'Error calling YOURLS. Probably a configuration issue, like wrong or missing "apiurl" or "signature".');
+        $this->assertEquals($yourls->getError(), 'Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.');
     }
 }

+ 3 - 1
vendor/composer/autoload_classmap.php

@@ -85,11 +85,13 @@ return array(
     'PrivateBin\\Persistence\\PurgeLimiter' => $baseDir . '/lib/Persistence/PurgeLimiter.php',
     'PrivateBin\\Persistence\\ServerSalt' => $baseDir . '/lib/Persistence/ServerSalt.php',
     'PrivateBin\\Persistence\\TrafficLimiter' => $baseDir . '/lib/Persistence/TrafficLimiter.php',
+    'PrivateBin\\Proxy\\AbstractProxy' => $baseDir . '/lib/Proxy/AbstractProxy.php',
+    'PrivateBin\\Proxy\\ShlinkProxy' => $baseDir . '/lib/Proxy/ShlinkProxy.php',
+    'PrivateBin\\Proxy\\YourlsProxy' => $baseDir . '/lib/Proxy/YourlsProxy.php',
     'PrivateBin\\Request' => $baseDir . '/lib/Request.php',
     'PrivateBin\\TemplateSwitcher' => $baseDir . '/lib/TemplateSwitcher.php',
     'PrivateBin\\View' => $baseDir . '/lib/View.php',
     'PrivateBin\\Vizhash16x16' => $baseDir . '/lib/Vizhash16x16.php',
-    'PrivateBin\\YourlsProxy' => $baseDir . '/lib/YourlsProxy.php',
     'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
     'Symfony\\Polyfill\\Php80\\Php80' => $vendorDir . '/symfony/polyfill-php80/Php80.php',
     'Symfony\\Polyfill\\Php80\\PhpToken' => $vendorDir . '/symfony/polyfill-php80/PhpToken.php',

+ 3 - 1
vendor/composer/autoload_static.php

@@ -133,11 +133,13 @@ class ComposerStaticInitDontChange
         'PrivateBin\\Persistence\\PurgeLimiter' => __DIR__ . '/../..' . '/lib/Persistence/PurgeLimiter.php',
         'PrivateBin\\Persistence\\ServerSalt' => __DIR__ . '/../..' . '/lib/Persistence/ServerSalt.php',
         'PrivateBin\\Persistence\\TrafficLimiter' => __DIR__ . '/../..' . '/lib/Persistence/TrafficLimiter.php',
+        'PrivateBin\\Proxy\\AbstractProxy' => __DIR__ . '/../..' . '/lib/Proxy/AbstractProxy.php',
+        'PrivateBin\\Proxy\\ShlinkProxy' => __DIR__ . '/../..' . '/lib/Proxy/ShlinkProxy.php',
+        'PrivateBin\\Proxy\\YourlsProxy' => __DIR__ . '/../..' . '/lib/Proxy/YourlsProxy.php',
         'PrivateBin\\Request' => __DIR__ . '/../..' . '/lib/Request.php',
         'PrivateBin\\TemplateSwitcher' => __DIR__ . '/../..' . '/lib/TemplateSwitcher.php',
         'PrivateBin\\View' => __DIR__ . '/../..' . '/lib/View.php',
         'PrivateBin\\Vizhash16x16' => __DIR__ . '/../..' . '/lib/Vizhash16x16.php',
-        'PrivateBin\\YourlsProxy' => __DIR__ . '/../..' . '/lib/YourlsProxy.php',
         'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php',
         'Symfony\\Polyfill\\Php80\\Php80' => __DIR__ . '/..' . '/symfony/polyfill-php80/Php80.php',
         'Symfony\\Polyfill\\Php80\\PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/PhpToken.php',