idp login/logout routes (#761)

This commit is contained in:
ed 2025-09-05 18:44:30 +00:00
parent c2be664e96
commit 09f22993be
9 changed files with 68 additions and 10 deletions

View file

@ -1942,6 +1942,10 @@ you can disable the built-in password-based login system, and instead replace it
* the regular config-defined users will be used as a fallback for requests which don't include a valid (trusted) IdP username header
* `--auth-ord` configured auth precedence, for example to allow overriding the IdP with a copyparty password
* the login/logout links/buttons can be replaced with links to your IdP with `--idp-login` and `--idp-logout` , for example `--idp-login /idp/login/?redir={dst}` will expand `{dst}` to the page the user was on when clicking Login
* if your IdP-server is slow, consider `--idp-cookie` and let requests with the cookie `cppws` bypass the IdP; experimental sessions-based feature added for a party
some popular identity providers are [Authelia](https://www.authelia.com/) (config-file based) and [authentik](https://goauthentik.io/) (GUI-based, more complex)

View file

@ -897,6 +897,11 @@ def get_sects():
middleware and not by clients! and, as an extra precaution,
send a header named '\033[36mfinalmasterspark\033[0m' (a secret keyword)
and then \033[36m--idp-h-key finalmasterspark\033[0m to require that
the login/logout links/buttons can be replaced with links
going to your IdP's UI; \033[36m--idp-login /login/?redir={dst}\033[0m
will expand \033[36m{dst}\033[0m to the URL of the current page, so
the IdP can redirect the user back to where they were
"""
),
],
@ -1303,6 +1308,9 @@ def add_auth(ap):
ap2.add_argument("--idp-store", metavar="N", type=int, default=1, help="how to use \033[33m--idp-db\033[0m; [\033[32m0\033[0m] = entirely disable, [\033[32m1\033[0m] = write-only (effectively disabled), [\033[32m2\033[0m] = remember users, [\033[32m3\033[0m] = remember users and groups.\nNOTE: Will remember and restore the IdP-volumes of all users for all eternity if set to 2 or 3, even when user is deleted from your IdP")
ap2.add_argument("--idp-adm", metavar="U,U", type=u, default="", help="comma-separated list of users allowed to use /?idp (the cache management UI)")
ap2.add_argument("--idp-cookie", metavar="S", type=int, default=0, help="generate a session-token for IdP users which is written to cookie \033[33mcppws\033[0m (or \033[33mcppwd\033[0m if plaintext), to reduce the load on the IdP server, lifetime \033[33mS\033[0m seconds.\n └─note: The expiration time is a client hint only; the actual lifetime of the session-token is infinite (until next restart with \033[33m--ses-db\033[0m wiped)")
ap2.add_argument("--idp-login", metavar="L", type=u, default="", help="replace all login-buttons with a link to URL \033[33mL\033[0m (unless \033[32mpw\033[0m is in \033[33m--auth-ord\033[0m then both will be shown); [\033[32m{dst}\033[0m] expands to url of current page")
ap2.add_argument("--idp-login-t", metavar="T", type=u, default="Login with SSO", help="the label/text for the idp-login button")
ap2.add_argument("--idp-logout", metavar="L", type=u, default="", help="replace all logout-buttons with a link to URL \033[33mL\033[0m")
ap2.add_argument("--auth-ord", metavar="TXT", type=u, default="idp,ipu", help="controls auth precedence; examples: [\033[32mpw,idp,ipu\033[0m], [\033[32mipu,pw,idp\033[0m], see --help-auth-ord")
ap2.add_argument("--no-bauth", action="store_true", help="disable basic-authentication support; do not accept passwords from the 'Authenticate' header at all. NOTE: This breaks support for the android app")
ap2.add_argument("--bauth-last", action="store_true", help="keeps basic-authentication enabled, but only as a last-resort; if a cookie is also provided then the cookie wins")
@ -1317,7 +1325,7 @@ def add_auth(ap):
ap2.add_argument("--ao-idp-before-pw", type=u, default="", help=argparse.SUPPRESS)
ap2.add_argument("--ao-h-before-hm", type=u, default="", help=argparse.SUPPRESS)
ap2.add_argument("--ao-ipu-wins", type=u, default="", help=argparse.SUPPRESS)
ap2.add_argument("--ao-has-pw", type=u, default="", help=argparse.SUPPRESS)
ap2.add_argument("--ao-have-pw", type=u, default="", help=argparse.SUPPRESS)
def add_chpw(ap):

View file

@ -2808,6 +2808,7 @@ class AuthSrv(object):
js_htm = {
"SPINNER": self.args.spinner,
"s_name": self.args.bname,
"idp_login": self.args.idp_login,
"have_up2k_idx": "e2d" in vf,
"have_acode": not self.args.no_acode,
"have_c2flac": self.args.allow_flac,
@ -2879,7 +2880,7 @@ class AuthSrv(object):
self.args.ao_idp_before_pw = min(h, hm) < pw
self.args.ao_h_before_hm = h < hm
self.args.ao_ipu_wins = ipu == 0
self.args.ao_have_pw = pw < 99
self.args.ao_have_pw = pw < 99 or not self.args.have_idp_hdrs
def load_idp_db(self, quiet=False) -> None:
# mutex me

View file

@ -690,7 +690,7 @@ class HttpCli(object):
if idp_usr in self.asrv.vfs.aread:
self.pw = ""
self.uname = idp_usr
if self.args.ao_have_pw:
if self.args.ao_have_pw or self.args.idp_logout:
self.html_head += "<script>var is_idp=1</script>\n"
else:
self.html_head += "<script>var is_idp=2</script>\n"
@ -3051,7 +3051,7 @@ class HttpCli(object):
self.asrv.forget_session(self.conn.hsrv.broker, self.uname)
self.get_pwd_cookie("x")
dst = self.args.SRS + "?h"
dst = self.args.idp_logout or (self.args.SRS + "?h")
h2 = '<a href="' + dst + '">continue</a>'
html = self.j2s("msg", h1="ok bye", h2=h2, redir=dst)
self.reply(html.encode("utf-8"))

View file

@ -114,6 +114,7 @@ var Ls = {
"gou": 'parent folder">up',
"gon": 'next folder">next',
"logout": "Logout ",
"login": "Login",
"access": " access",
"ot_close": "close submenu",
"ot_search": "search for files by attributes, path / name, music tags, or any combination of those$N$N&lt;code&gt;foo bar&lt;/code&gt; = must contain both «foo» and «bar»,$N&lt;code&gt;foo -bar&lt;/code&gt; = must contain «foo» but not «bar»,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = start with «yana» and be an «opus» file$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = contain exactly «try unite»$N$Nthe date format is iso-8601, like$N&lt;code&gt;2009-12-31&lt;/code&gt; or &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
@ -745,6 +746,7 @@ var Ls = {
"gou": 'naviger ett nivå opp">opp',
"gon": 'naviger til mappen etter denne">neste',
"logout": "Logg ut ",
"login": "Logg inn",
"access": " tilgang",
"ot_close": "lukk verktøy",
"ot_search": "søk etter filer ved å angi filnavn, mappenavn, tid, størrelse, eller metadata som sangtittel / artist / osv.$N$N&lt;code&gt;foo bar&lt;/code&gt; = inneholder både «foo» og «bar»,$N&lt;code&gt;foo -bar&lt;/code&gt; = inneholder «foo» men ikke «bar»,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = starter med «yana», filtype «opus»$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = «try unite» eksakt$N$Ndatoformat er iso-8601, så f.eks.$N&lt;code&gt;2009-12-31&lt;/code&gt; eller &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
@ -1375,6 +1377,7 @@ var Ls = {
"gou": '顶部">up',
"gon": '下一项">next',
"logout": " 登出",
"login": "登录", //m
"access": " 访问",
"ot_close": "关闭子菜单",
"ot_search": "按属性、路径/名称、音乐标签或上述内容的任意组合搜索文件$N$N&lt;code&gt;foo bar&lt;/code&gt; = 必须包含 «foo» 和 «bar»,$N&lt;code&gt;foo -bar&lt;/code&gt; = 包含 «foo» 而不包含 «bar»,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = 以 «yama» 为开头的 «opus» 文件$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = 正好包含 «try unite»$N$N时间格式为 iso-8601, 比如:$N&lt;code&gt;2009-12-31&lt;/code&gt; or &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
@ -2009,6 +2012,7 @@ var Ls = {
"gou": 'nadřazená složka">nahoru',
"gon": 'následující složka">následující',
"logout": "Odhlásit ",
"login": "Přihlásit se", //m
"access": " přístup",
"ot_close": "zavřít podnabídku",
"ot_search": "hledat soubory podle atributů, cesty / názvu, hudebních tagů nebo jejich kombinace$N$N&lt;code&gt;foo bar&lt;/code&gt; = musí obsahovat jak «foo» tak «bar»,$N&lt;code&gt;foo -bar&lt;/code&gt; = musí obsahovat «foo» ale ne «bar»,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = začíná na «yana» a je to «opus» soubor$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = obsahuje přesně «try unite»$N$Nformát data je iso-8601, jako$N&lt;code&gt;2009-12-31&lt;/code&gt; nebo &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
@ -2639,6 +2643,7 @@ var Ls = {
"gou": 'zum übergeordneter Ordner springen">hoch',
"gon": 'zum nächsten Ordner springen">nächst.',
"logout": "Abmelden ",
"login": "Anmelden", //m
"access": " Zugriff",
"ot_close": "Submenu schliessen",
"ot_search": "Dateien nach Attributen, Pfad/Name, Musiktags oder beliebiger Kombination suchen$N$N&lt;code&gt;foo bar&lt;/code&gt; = muss «foo» und «bar» enthalten,$N&lt;code&gt;foo -bar&lt;/code&gt; = muss «foo» aber nicht «bar» enthalten,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = beginnt mit «yana» und ist «opus»-Datei$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = genau «try unite» enthalten$N$NDatumsformat ist iso-8601, z.B.$N&lt;code&gt;2009-12-31&lt;/code&gt; oder &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
@ -3269,6 +3274,7 @@ var Ls = {
"gou": 'ylempi hakemisto">ylös',
"gon": 'seuraava hakemisto">seur',
"logout": "Kirjaudu ulos ",
"login": "Kirjaudu sisään", //m
"access": " -oikeudet",
"ot_close": "sulje alavalikko",
"ot_search": "etsi tiedostoja ominaisuuksien, tiedostopolun tai -nimen, musiikkitägien tai näiden yhdistelmän perusteella$N$N&lt;code&gt;foo bar&lt;/code&gt; = täytyy sisältää sekä «foo» että «bar»,$N&lt;code&gt;foo -bar&lt;/code&gt; = täytyy sisältää «foo» mutta ei «bar»,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = alkaa «yana» ja on «opus»-tiedosto$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = sisältää täsmälleen «try unite»$N$Npäivämäärän muoto on iso-8601, kuten$N&lt;code&gt;2009-12-31&lt;/code&gt; tai &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
@ -3899,6 +3905,7 @@ var Ls = {
"gou": 'dossier parent">haut',
"gon": 'dossier suivant">suivant',
"logout": "Déconnexion ",
"login": "Se connecter", //m
"access": " accès",
"ot_close": "fermer le sous-menu",
"ot_search": "chercher des fichiers par leurs attributs, chemin / nom, tag musicaux, ou nimporte quelle combinaison de ces options$N$N&lt;code&gt;foo bar&lt;/code&gt; = doit contenir à la fois «foo» et «bar»,$N&lt;code&gt;foo -bar&lt;/code&gt; = doit contenir «foo» mais pas «bar»,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = commence par «yana» et est un fichier «opus»$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = contient exactement «try unite»$N$Nle format de date est iso-8601, comme$N&lt;code&gt;2009-12-31&lt;/code&gt; ou &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
@ -4529,6 +4536,7 @@ var Ls = {
"gou": 'γονικός φάκελος">πάνω',
"gon": 'επόμενος φάκελος">επόμενο',
"logout": "Αποσύνδεση ",
"login": "Σύνδεση", //m
"access": " πρόσβαση",
"ot_close": "κλείσιμο υπομενού",
"ot_search": "αναζήτηση αρχείων με βάση χαρακτηριστικά, διαδρομή / όνομα, μουσικά tags ή οποιονδήποτε συνδυασμό$N$N&lt;code&gt;foo bar&lt;/code&gt; = πρέπει να περιέχει και τα «foo» και «bar»,$N&lt;code&gt;foo -bar&lt;/code&gt; = πρέπει να περιέχει το «foo» αλλά όχι το «bar»,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = να ξεκινά με «yana» και να είναι αρχείο «opus»$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = να περιέχει ακριβώς «try unite»$N$Nη μορφή ημερομηνίας είναι iso-8601, όπως$N&lt;code&gt;2009-12-31&lt;/code&gt; ή &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
@ -5159,6 +5167,7 @@ var Ls = {
"gou": 'cartella genitore">su',
"gon": 'prossima cartella">succ',
"logout": "Logout ",
"login": "Accedi", //m
"access": " accesso",
"ot_close": "chiudi sottomenu",
"ot_search": "cerca file per attributi, percorso / nome, tag musicali, o qualsiasi combinazione di questi$N$N&lt;code&gt;foo bar&lt;/code&gt; = deve contenere sia «foo» che «bar»,$N&lt;code&gt;foo -bar&lt;/code&gt; = deve contenere «foo» ma non «bar»,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = inizia con «yana» ed è un file «opus»$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = contiene esattamente «try unite»$N$Nil formato data è iso-8601, come$N&lt;code&gt;2009-12-31&lt;/code&gt; o &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
@ -5789,6 +5798,7 @@ var Ls = {
"gou": '상위 폴더">위로',
"gon": '다음 폴더">다음',
"logout": "로그아웃 ",
"login": "로그인", //m
"access": " 액세스",
"ot_close": "하위 메뉴 닫기",
"ot_search": "속성, 경로/이름, 음악 태그 또는 이들의 조합으로 파일을 검색합니다.$N$N&lt;code&gt;foo bar&lt;/code&gt; = «foo»와 «bar»를 모두 포함해야 함,$N&lt;code&gt;foo -bar&lt;/code&gt; = «foo»는 포함하지만 «bar»는 포함하지 않아야 함,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = «yana»로 시작하고 «opus» 파일이어야 함$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = 정확히 «try unite»를 포함해야 함$N$N날짜 형식은 ISO-8601입니다. 예:$N&lt;code&gt;2009-12-31&lt;/code&gt; 또는 &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
@ -6419,6 +6429,7 @@ var Ls = {
"gou": 'Bovenligende map">Omhoog',
"gon": 'Volgende map">Volgende',
"logout": "Uitloggen ",
"login": "Inloggen", //m
"access": " Toegang",
"ot_close": "Sluit onder-menu",
"ot_search": "Zoek voor bestanden bij attributes, pad / naam, muziek tags, of elk andere combinatie tussen$N$N&lt;code&gt;foo bar&lt;/code&gt; = moet beide «foo» en «bar» bevatten,$N&lt;code&gt;foo -bar&lt;/code&gt; = moet «foo» bevatten maar geen «bar»,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = start met «yana» en moet een «opus» bestand zijn$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = moet precies «try unite» bevatten$N$Nde datum formaat is iso-8601, zoals$N&lt;code&gt;2009-12-31&lt;/code&gt; of &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
@ -7050,6 +7061,7 @@ var Ls = {
"gou": 'navigér eitt nivå opp">opp',
"gon": 'navigér åt mappa etter den her">neste',
"logout": "Logg ut ",
"login": "Logg inn",
"access": " åtgang",
"ot_close": "lukk reiskap",
"ot_search": "søk etter filer ved å angje filnamn, mappenamn, tid, storleik, eller metadata som songtittel / artist / osv.$N$N&lt;code&gt;foo bar&lt;/code&gt; = inneheld båe «foo» og «bar»,$N&lt;code&gt;foo -bar&lt;/code&gt; = innehold «foo» men ikkje «bar»,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = startar med «yana», filtype «opus»$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = «try unite» eksakt$N$Ndatoformat er iso-8601, så f.eks.$N&lt;code&gt;2009-12-31&lt;/code&gt; eller &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
@ -7679,6 +7691,7 @@ var Ls = {
"gou": 'nadrzędny folder">w górę',
"gon": 'następny folder">następny',
"logout": "Wyloguj ",
"login": "Zaloguj się", //m
"access": " dostęp",
"ot_close": "zamknij pod-menu",
"ot_search": "szukaj plików po atrybutach, ścieżce / nazwie, tagach muzyki, bądź dowolnej ich kombinacji$N$N&lt;code&gt;foo bar&lt;/code&gt; = musi zawierać «foo» oraz «bar»,$N&lt;code&gt;foo -bar&lt;/code&gt; = musi zawierać «foo», lecz nie «bar»,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = musi zaczynać się od «yana» i być plikiem «opus»$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = zawierać dokładnie «try unite»$N$Nformatem daty jest iso-8601, czyli$N&lt;code&gt;2009-12-31&lt;/code&gt; lub &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
@ -8307,6 +8320,7 @@ var Ls = {
"gou": 'pasta pai">acima',
"gon": 'próxima pasta">próximo',
"logout": "Sair ",
"login": "Fazer login",
"access": " acesso",
"ot_close": "fechar submenu",
"ot_search": "procurar arquivos por atributos, caminho / nome, tags de música ou qualquer combinação deles$N$N&lt;code&gt;foo bar&lt;/code&gt; = deve conter ambos «foo» e «bar»,$N&lt;code&gt;foo -bar&lt;/code&gt; = deve conter «foo» mas não «bar»,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = começar com «yana» e ser um arquivo «opus»$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = conter exatamente «try unite»$N$No formato de data é iso-8601, como$N&lt;code&gt;2009-12-31&lt;/code&gt; ou &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
@ -8937,6 +8951,7 @@ var Ls = {
"gou": 'родительская папка">вверх',
"gon": 'следующая папка">след',
"logout": "Выйти ",
"login": "Войти", //m
"access": " доступ",
"ot_close": "закрыть подменю",
"ot_search": "искать файлы по атрибутам, пути / имени, музыкальным тегам или любой другой комбинации из следующих конструкций$N$N&lt;code&gt;foo bar&lt;/code&gt; = обязано содержать «foo» И «bar»,$N&lt;code&gt;foo -bar&lt;/code&gt; = обязано содержать «foo», но не «bar»,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = начинается с «yana» и имеет расширение «opus»$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = содержит именно «try unite»$N$Nформат времени задаётся по стандарту iso-8601, например$N&lt;code&gt;2009-12-31&lt;/code&gt; или &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
@ -9567,6 +9582,7 @@ var Ls = {
"gou": 'carpeta de nivel superior">subir',
"gon": 'siguiente carpeta">siguiente',
"logout": "Cerrar sesión ",
"login": "Iniciar sesión", //m
"access": " acceso",
"ot_close": "cerrar submenú",
"ot_search": "buscar archivos por atributos, ruta / nombre, etiquetas de música, o cualquier combinación$N$N&lt;code&gt;foo bar&lt;/code&gt; = debe contener «foo» y «bar»,$N&lt;code&gt;foo -bar&lt;/code&gt; = debe contener «foo» pero no «bar»,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = empieza con «yana» y es un archivo «opus»$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = contiene exactamente «try unite»$N$Nel formato de fecha es iso-8601, como$N&lt;code&gt;2009-12-31&lt;/code&gt; o &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
@ -10196,6 +10212,7 @@ var Ls = {
"gou": 'överordnad mapp">upp',
"gon": 'nästa mapp">nästa',
"logout": "Logga ut ",
"login": "Logga in", //m
"access": "-rättighet",
"ot_close": "stäng undermeny",
"ot_search": "sök efter filer via attribut, sökväg / namn, musiktaggar, eller någon kombination av dessa$N$N&lt;code&gt;foo bar&lt;/code&gt; = måste innehålla både «foo» och «bar»,$N&lt;code&gt;foo -bar&lt;/code&gt; = måste innehålla «foo» men inte «bar»,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = måste börja med «yana» och vara en «opus»-fil$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = måste innehålla exakt «try unite»$N$Ndatumformatet är iso-8601, t.ex.$N&lt;code&gt;2009-12-31&lt;/code&gt; eller &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
@ -10826,6 +10843,7 @@ var Ls = {
"gou": 'батьківська папка">вгору',
"gon": 'наступна папка">далі',
"logout": "Вийти ",
"login": "увійти", //m
"access": " доступ",
"ot_close": "закрити підменю",
"ot_search": "пошук файлів за атрибутами, шляхом / іменем, музичними тегами, або будь-якою комбінацією$N$N&lt;code&gt;foo bar&lt;/code&gt; = має містити «foo» і «bar»,$N&lt;code&gt;foo -bar&lt;/code&gt; = має містити «foo», але не «bar»,$N&lt;code&gt;^yana .opus$&lt;/code&gt; = починатися з «yana» і бути файлом «opus»$N&lt;code&gt;&quot;try unite&quot;&lt;/code&gt; = містити точно «try unite»$N$Nформат дати - iso-8601, наприклад$N&lt;code&gt;2009-12-31&lt;/code&gt; або &lt;code&gt;2020-09-12 23:30:00&lt;/code&gt;",
@ -18289,10 +18307,14 @@ function apply_perms(res) {
axs += '-Only';
}
var dst = "?h";
if (idp_login && acct == "*")
dst = idp_login.replace(/\{dst\}/g, get_evpath());
ebi('acc_info').innerHTML = '<span id="srv_info2"><span>' + srvinf +
'</span></span><span' + aclass + axs + L.access + '</span>' + (acct != '*' ?
'<form id="flogout" method="post" enctype="multipart/form-data"><input type="hidden" name="act" value="logout" /><input id="blogout" type="submit" value="' + (window.is_idp ? '' : L.logout) + acct + '"></form>' :
'<a href="?h">Login</a>');
'<form id="flogout" method="post" enctype="multipart/form-data"><input type="hidden" name="act" value="logout" /><input id="blogout" type="submit" value="' + L.logout + acct + '"></form>' :
'<a href="' + dst + '">' + L.login + '</a>');
var o = QSA('#ops>a[data-perm]');
for (var a = 0; a < o.length; a++) {

View file

@ -38,6 +38,7 @@ a {
td a {
margin: 0;
}
#wb,
#w {
color: #fff;
background: #940;

View file

@ -21,7 +21,11 @@
{%- if this.uname == '*' %}
<p id="b">howdy stranger &nbsp; <small>(you're not logged in)</small></p>
{%- else %}
{%- if this.args.idp_logout %}
<a id="c" href="{{ this.args.idp_logout }}" class="logout">logout</a>
{%- else %}
<a id="c" href="{{ r }}/?pw=x" class="logout">logout</a>
{%- endif %}
<p><span id="m">welcome back,</span> <strong id="un">{{ this.uname|e }}</strong></p>
{%- endif %}
{%- endif %}
@ -118,6 +122,13 @@
{%- else %}
<h1 id="l">login for more:</h1>
<div>
{%- if this.args.idp_login %}
<ul><li>
<a href="{{ this.args.idp_login | replace("{dst}",r+"/"+qvpath) }}">{{ this.args.idp_login_t }}</a>
{%- if this.args.ao_have_pw %}or alternatively:{%- endif %}
</li></ul>
{%- endif %}
{%- if this.args.ao_have_pw %}
<form id="lf" method="post" enctype="multipart/form-data" action="{{ r }}/{{ qvpath }}">
<input type="hidden" id="la" name="act" value="login" />
{%- if this.args.usernames %}
@ -135,11 +146,16 @@
<a id="w" href="{{ ahttps }}">switch to https</a>
{%- endif %}
</form>
{%- endif %}
</div>
{%- endif %}
<h1 id="cc">other stuff:</h1>
<ul>
{%- if ahttps %}
<li><a id="wb" href="{{ ahttps }}">switch to https</a></li>
{%- endif %}
{%- if this.uname in this.args.idp_adm_set %}
<li><a id="ag" href="{{ r }}/?idp">view idp cache</a></li>
{%- endif %}
@ -169,7 +185,7 @@
<li><a id="af" href="{{ r }}/?ru">show recent uploads</a></li>
<li><a id="k" href="{{ r }}/?reset" class="r" onclick="localStorage.clear();return true">reset client settings</a></li>
{%- if this.uname != '*' %}
{%- if this.uname != '*' and not in_shr %}
<li><form method="post" enctype="multipart/form-data">
<input type="hidden" name="act" value="logout" />
<input type="submit" id="lo" value="logout “{{ this.uname|e }}” everywhere" />

View file

@ -814,6 +814,8 @@ if (window.langmod)
var d = Ls[sread("cpp_lang", Object.keys(Ls)) || lang] ||
Ls.eng || Ls.nor || Ls.chi;
d.wb = d.w;
for (var k in (d || {})) {
var f = k.slice(-1),
i = k.slice(0, -1),
@ -844,14 +846,16 @@ catch (ex) { }
tt.init();
var o = QS('input[name="uname"]') || QS('input[name="cppwd"]');
if (!MOBILE && !ebi('c') && o.offsetTop + o.offsetHeight < window.innerHeight)
if (o && !MOBILE && !ebi('c') && o.offsetTop + o.offsetHeight < window.innerHeight)
o.focus();
o = ebi('u');
if (o && /[0-9]+$/.exec(o.innerHTML))
o.innerHTML = shumantime(o.innerHTML);
ebi('uhash').value = '' + location.hash;
o = ebi('uhash')
if (o)
o.value = '' + location.hash;
if (/\&re=/.test('' + location))
ebi('a').className = 'af g';

View file

@ -164,7 +164,7 @@ class Cfg(Namespace):
ex = "ctl_re db_act forget_ip idp_cookie idp_store k304 loris no304 nosubtle qr_pin qr_wait re_maxage rproxy rsp_jtr rsp_slp s_wr_slp snap_wri theme themes turbo u2ow zipmaxn zipmaxs"
ka.update(**{k: 0 for k in ex.split()})
ex = "ah_alg bname chdir chmod_f chpw_db doctitle df exit favico ipa html_head lg_sba lg_sbf log_fk md_sba md_sbf name og_desc og_site og_th og_title og_title_a og_title_v og_title_i shr tcolor textfiles txt_eol unlist vname xff_src zipmaxt R RS SR"
ex = "ah_alg bname chdir chmod_f chpw_db doctitle df exit favico ipa html_head idp_login idp_logout lg_sba lg_sbf log_fk md_sba md_sbf name og_desc og_site og_th og_title og_title_a og_title_v og_title_i shr tcolor textfiles txt_eol unlist vname xff_src zipmaxt R RS SR"
ka.update(**{k: "" for k in ex.split()})
ex = "ban_403 ban_404 ban_422 ban_pw ban_pwc ban_url spinner"
@ -289,6 +289,7 @@ class VHttpSrv(object):
self.broker = NullBroker(args, asrv)
self.prism = None
self.ipr = None
self.bans = {}
self.tdls = self.dls = {}
self.tdli = self.dli = {}
@ -344,6 +345,7 @@ class VHttpConn(object):
Ctor = VHttpSrvUp2k if use_up2k else VHttpSrv
self.hsrv = Ctor(args, asrv, log)
self.ico = Ico(args)
self.ipr = None
self.ipa_nm = None
self.lf_url = None
self.log_func = log