From f30bdaad1e5cf5b3aae7b9efacbad80715cd4413 Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Wed, 27 Dec 2023 11:57:34 +0100 Subject: [PATCH 01/31] translate: Updates for file locale/en/LC_MESSAGES/django.po in it (#7998) Translate locale/en/LC_MESSAGES/django.po in it 100% translated source file: 'locale/en/LC_MESSAGES/django.po' on 'it'. Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com> --- locale/it/LC_MESSAGES/django.po | 2919 +++++++++++++++++++++++++++++++ 1 file changed, 2919 insertions(+) create mode 100644 locale/it/LC_MESSAGES/django.po diff --git a/locale/it/LC_MESSAGES/django.po b/locale/it/LC_MESSAGES/django.po new file mode 100644 index 000000000..3f39ddb2e --- /dev/null +++ b/locale/it/LC_MESSAGES/django.po @@ -0,0 +1,2919 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +# Translators: +# Dario Rigolin, 2022 +# aoor9, 2023 +# Marco Realacci, 2023 +# Matteo Piccina , 2023 +# Kowalski Dragon , 2023 +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-12-06 16:55+0000\n" +"PO-Revision-Date: 2022-09-26 16:47+0000\n" +"Last-Translator: Kowalski Dragon , 2023\n" +"Language-Team: Italian (https://app.transifex.com/authentik/teams/119923/it/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: it\n" +"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n" + +#: authentik/admin/api/tasks.py:127 +#, python-format +msgid "Successfully re-scheduled Task %(name)s!" +msgstr "Operazione ri-pianificata con successo%(name)s!" + +#: authentik/api/schema.py:25 +msgid "Generic API Error" +msgstr "Errore API generico" + +#: authentik/api/schema.py:33 +msgid "Validation Error" +msgstr "Errore di validazione" + +#: authentik/blueprints/api.py:43 +msgid "Blueprint file does not exist" +msgstr "File del modello inesistente" + +#: authentik/blueprints/api.py:54 +#, python-format +msgid "Failed to validate blueprint: %(logs)s" +msgstr "Validazione del modello fallita: %(logs)s" + +#: authentik/blueprints/api.py:59 +msgid "Either path or content must be set." +msgstr "È necessario impostare il percorso o il contenuto." + +#: authentik/blueprints/models.py:30 +msgid "Managed by authentik" +msgstr "Gestito da authentik" + +#: authentik/blueprints/models.py:32 +msgid "" +"Objects that are managed by authentik. These objects are created and updated" +" automatically. This flag only indicates that an object can be overwritten " +"by migrations. You can still modify the objects via the API, but expect " +"changes to be overwritten in a later update." +msgstr "" +"Oggetti gestiti da authentik. Questi oggetti sono creati e aggiornati " +"automaticamente. Questo controllo indica solo che un oggetto può essere " +"sovrascritto dalle migrazioni. Puoi ancora modificare gli oggetti tramite " +"l'API, ma aspettati che le modifiche vengano sovrascritte in un " +"aggiornamento successivo." + +#: authentik/blueprints/models.py:112 +msgid "Blueprint Instance" +msgstr "Istanza del modello" + +#: authentik/blueprints/models.py:113 +msgid "Blueprint Instances" +msgstr "Istanze dei modelli" + +#: authentik/blueprints/v1/exporter.py:62 +#, python-format +msgid "authentik Export - %(date)s" +msgstr "Esportazione authentik - %(date)s" + +#: authentik/blueprints/v1/tasks.py:150 authentik/crypto/tasks.py:93 +#, python-format +msgid "Successfully imported %(count)d files." +msgstr "Importato con successo %(count)d file." + +#: authentik/core/api/providers.py:120 +msgid "SAML Provider from Metadata" +msgstr "Provider SAML dai Metadati" + +#: authentik/core/api/providers.py:121 +msgid "Create a SAML Provider by importing its Metadata." +msgstr "Crea un SAML Provider importando i sui Metadati." + +#: authentik/core/api/users.py:156 +msgid "No leading or trailing slashes allowed." +msgstr "Non sono consentite barre oblique iniziali o finali." + +#: authentik/core/api/users.py:159 +msgid "No empty segments in user path allowed." +msgstr "Non sono consentiti segmenti vuoti nel percorso utente." + +#: authentik/core/models.py:86 +msgid "name" +msgstr "nome" + +#: authentik/core/models.py:88 +msgid "Users added to this group will be superusers." +msgstr "Utenti aggiunti a questo gruppo saranno superutenti." + +#: authentik/core/models.py:162 +msgid "Group" +msgstr "Gruppo" + +#: authentik/core/models.py:163 +msgid "Groups" +msgstr "Gruppi" + +#: authentik/core/models.py:178 +msgid "User's display name." +msgstr "Nome visualizzato dell'utente." + +#: authentik/core/models.py:274 authentik/providers/oauth2/models.py:295 +msgid "User" +msgstr "Utente" + +#: authentik/core/models.py:275 +msgid "Users" +msgstr "Utenti" + +#: authentik/core/models.py:277 +#: authentik/stages/email/templates/email/password_reset.html:28 +msgid "Reset Password" +msgstr "Reimposta Password" + +#: authentik/core/models.py:278 +msgid "Can impersonate other users" +msgstr "Può impersonare altri utenti" + +#: authentik/core/models.py:279 authentik/rbac/models.py:54 +msgid "Can assign permissions to users" +msgstr "Può assegnare permessi a utenti" + +#: authentik/core/models.py:280 authentik/rbac/models.py:55 +msgid "Can unassign permissions from users" +msgstr "Può rimuovere permessi da utenti" + +#: authentik/core/models.py:294 +msgid "" +"Flow used for authentication when the associated application is accessed by " +"an un-authenticated user." +msgstr "" +"Flusso usato per l'autenticazione quando un utente non autenticato accede " +"all'applicazione associata." + +#: authentik/core/models.py:304 +msgid "Flow used when authorizing this provider." +msgstr "Flusso utilizzato durante l'autorizzazione di questo provider." + +#: authentik/core/models.py:316 +msgid "" +"Accessed from applications; optional backchannel providers for protocols " +"like LDAP and SCIM." +msgstr "" +"Accessibile dalle applicazioni; fornitori di backchannel opzionali per " +"protocolli come LDAP e SCIM." + +#: authentik/core/models.py:371 +msgid "Application's display Name." +msgstr "Nome visualizzato dell'applicazione." + +#: authentik/core/models.py:372 +msgid "Internal application name, used in URLs." +msgstr "Nome interno dell'applicazione, utilizzato negli URL." + +#: authentik/core/models.py:384 +msgid "Open launch URL in a new browser tab or window." +msgstr "Apri l'URL di avvio in una nuova scheda o finestra del browser." + +#: authentik/core/models.py:448 +msgid "Application" +msgstr "Applicazione" + +#: authentik/core/models.py:449 +msgid "Applications" +msgstr "Applicazioni" + +#: authentik/core/models.py:455 +msgid "Use the source-specific identifier" +msgstr "Utilizzare l'identificatore specifico della fonte" + +#: authentik/core/models.py:457 +msgid "" +"Link to a user with identical email address. Can have security implications " +"when a source doesn't validate email addresses." +msgstr "" +"Collegamento a un utente con indirizzo email identico. Può avere " +"implicazioni sulla sicurezza quando una fonte non convalida gli indirizzi " +"e-mail." + +#: authentik/core/models.py:461 +msgid "" +"Use the user's email address, but deny enrollment when the email address " +"already exists." +msgstr "" +"Usa l'indirizzo e-mail dell'utente, ma nega l'iscrizione quando l'indirizzo " +"e-mail esiste già." + +#: authentik/core/models.py:464 +msgid "" +"Link to a user with identical username. Can have security implications when " +"a username is used with another source." +msgstr "" +"Collegamento a un utente con nome utente identico. Può avere implicazioni " +"sulla sicurezza quando un nome utente viene utilizzato con un'altra fonte." + +#: authentik/core/models.py:468 +msgid "" +"Use the user's username, but deny enrollment when the username already " +"exists." +msgstr "" +"Utilizza il nome utente dell'utente, ma nega l'iscrizione quando il nome " +"utente esiste già." + +#: authentik/core/models.py:475 +msgid "Source's display Name." +msgstr "Nome visualizzato della sorgente." + +#: authentik/core/models.py:476 +msgid "Internal source name, used in URLs." +msgstr "Nome interno della sorgente, utilizzato negli URL." + +#: authentik/core/models.py:495 +msgid "Flow to use when authenticating existing users." +msgstr "Flusso da usare per autenticare utenti esistenti." + +#: authentik/core/models.py:504 +msgid "Flow to use when enrolling new users." +msgstr "Flusso da usare per iscrivere nuovi utenti." + +#: authentik/core/models.py:512 +msgid "" +"How the source determines if an existing user should be authenticated or a " +"new user enrolled." +msgstr "" +"Modalità in cui la fonte determina se un utente esistente deve essere " +"autenticato o un nuovo utente registrato." + +#: authentik/core/models.py:684 +msgid "Token" +msgstr "Token" + +#: authentik/core/models.py:685 +msgid "Tokens" +msgstr "Tokens" + +#: authentik/core/models.py:690 +msgid "View token's key" +msgstr "Visualizza la chiave token" + +#: authentik/core/models.py:726 +msgid "Property Mapping" +msgstr "Mappatura della proprietà" + +#: authentik/core/models.py:727 +msgid "Property Mappings" +msgstr "Mappatura delle proprietà" + +#: authentik/core/models.py:762 +msgid "Authenticated Session" +msgstr "Sessione Autenticata" + +#: authentik/core/models.py:763 +msgid "Authenticated Sessions" +msgstr "Sessioni Autenticate" + +#: authentik/core/sources/flow_manager.py:190 +#, python-format +msgid "" +"Request to authenticate with %(source)s has been denied. Please authenticate" +" with the source you've previously signed up with." +msgstr "" +"La richiesta di autenticazione con %(source)s è stata negata. Autenticati " +"con la fonte con cui ti sei registrato in precedenza." + +#: authentik/core/sources/flow_manager.py:242 +msgid "Configured flow does not exist." +msgstr "Flusso configurato inesistente." + +#: authentik/core/sources/flow_manager.py:272 +#: authentik/core/sources/flow_manager.py:324 +#, python-format +msgid "Successfully authenticated with %(source)s!" +msgstr "Autenticazione riuscita con %(source)s!" + +#: authentik/core/sources/flow_manager.py:296 +#, python-format +msgid "Successfully linked %(source)s!" +msgstr "%(source)s collegato con successo!" + +#: authentik/core/sources/flow_manager.py:315 +msgid "Source is not configured for enrollment." +msgstr "La sorgente non è configurata per la registrazione." + +#: authentik/core/templates/if/end_session.html:7 +msgid "End session" +msgstr "Fine sessione" + +#: authentik/core/templates/if/end_session.html:11 +#, python-format +msgid "" +"\n" +"You've logged out of %(application)s.\n" +msgstr "" +"\n" +"Sei disconnesso da %(application)s.\n" + +#: authentik/core/templates/if/end_session.html:19 +#, python-format +msgid "" +"\n" +" You've logged out of %(application)s. You can go back to the overview to launch another application, or log out of your %(branding_title)s account.\n" +" " +msgstr "" +"\n" +" Hai effettuato il logout da %(application)s. Puoi tornare alla panoramica per avviare un'altra applicazione o effettuare il logout dal tuo account %(branding_title)s." + +#: authentik/core/templates/if/end_session.html:25 +msgid "Go back to overview" +msgstr "Torna alla panoramica" + +#: authentik/core/templates/if/end_session.html:29 +#, python-format +msgid "" +"\n" +" Log out of %(branding_title)s\n" +" " +msgstr "" +"\n" +" Esci da %(branding_title)s\n" +" " + +#: authentik/core/templates/if/end_session.html:36 +#, python-format +msgid "" +"\n" +" Log back into %(application)s\n" +" " +msgstr "" +"\n" +" Accedi di nuovo a %(application)s\n" +" " + +#: authentik/core/templates/if/error.html:18 +msgid "Go home" +msgstr "Vai alla pagina iniziale" + +#: authentik/core/templates/login/base_full.html:89 +msgid "Powered by authentik" +msgstr "Gestito da authentik" + +#: authentik/core/views/apps.py:53 +#: authentik/providers/oauth2/views/authorize.py:393 +#: authentik/providers/oauth2/views/device_init.py:70 +#: authentik/providers/saml/views/sso.py:70 +#, python-format +msgid "You're about to sign into %(application)s." +msgstr "Stai per accedere a %(application)s" + +#: authentik/crypto/api.py:179 +msgid "Subject-alt name" +msgstr "Nome alternativo del soggetto" + +#: authentik/crypto/models.py:30 +msgid "PEM-encoded Certificate data" +msgstr "Dati del certificato in codifica PEM" + +#: authentik/crypto/models.py:33 +msgid "" +"Optional Private Key. If this is set, you can use this keypair for " +"encryption." +msgstr "" +"Chiave privata facoltativa. Se è impostato, puoi utilizzare questa coppia di" +" chiavi per la crittografia." + +#: authentik/crypto/models.py:101 +msgid "Certificate-Key Pair" +msgstr "Coppia certificato-chiave" + +#: authentik/crypto/models.py:102 +msgid "Certificate-Key Pairs" +msgstr "Coppie certificato-chiave" + +#: authentik/enterprise/models.py:183 +msgid "License" +msgstr "Licenza" + +#: authentik/enterprise/models.py:184 +msgid "Licenses" +msgstr "Licenze" + +#: authentik/enterprise/models.py:206 +msgid "License Usage" +msgstr "Utilizzo della licenza" + +#: authentik/enterprise/models.py:207 +msgid "License Usage Records" +msgstr "Registri sull'utilizzo della licenza" + +#: authentik/events/models.py:291 +msgid "Event" +msgstr "Evento" + +#: authentik/events/models.py:292 +msgid "Events" +msgstr "Eventi" + +#: authentik/events/models.py:298 +msgid "authentik inbuilt notifications" +msgstr "notifiche integrate authentik" + +#: authentik/events/models.py:299 +msgid "Generic Webhook" +msgstr "Webhook generico" + +#: authentik/events/models.py:300 +msgid "Slack Webhook (Slack/Discord)" +msgstr "Slack Webhook (Slack/Discord)" + +#: authentik/events/models.py:301 +msgid "Email" +msgstr "Email" + +#: authentik/events/models.py:319 +msgid "" +"Only send notification once, for example when sending a webhook into a chat " +"channel." +msgstr "" +"Invia una notifica solo una volta, ad esempio quando invii un webhook in un " +"canale di chat." + +#: authentik/events/models.py:384 +msgid "Severity" +msgstr "Gravità" + +#: authentik/events/models.py:389 +msgid "Dispatched for user" +msgstr "Inviato per l'utente" + +#: authentik/events/models.py:398 +msgid "Event user" +msgstr "Evento utente" + +#: authentik/events/models.py:492 +msgid "Notification Transport" +msgstr "Trasporto Notifica" + +#: authentik/events/models.py:493 +msgid "Notification Transports" +msgstr "Trasporti notifica" + +#: authentik/events/models.py:499 +msgid "Notice" +msgstr "Avviso" + +#: authentik/events/models.py:500 +msgid "Warning" +msgstr "Avvertimento" + +#: authentik/events/models.py:501 +msgid "Alert" +msgstr "Allarme" + +#: authentik/events/models.py:526 +msgid "Notification" +msgstr "Notifica" + +#: authentik/events/models.py:527 +msgid "Notifications" +msgstr "Notifiche" + +#: authentik/events/models.py:537 +msgid "" +"Select which transports should be used to notify the user. If none are " +"selected, the notification will only be shown in the authentik UI." +msgstr "" +"Selezionare quali trasporti devono essere utilizzati per notificare " +"l'utente. Se non ne viene selezionato nessuno, la notifica verrà mostrata " +"solo nell'interfaccia utente authentik." + +#: authentik/events/models.py:545 +msgid "Controls which severity level the created notifications will have." +msgstr "Controlla quale livello di gravità avranno le notifiche create." + +#: authentik/events/models.py:550 +msgid "" +"Define which group of users this notification should be sent and shown to. " +"If left empty, Notification won't ben sent." +msgstr "" +"Definisci a quale gruppo di utenti deve essere inviata e mostrata questa " +"notifica. Se lasciato vuoto, la notifica non verrà inviata." + +#: authentik/events/models.py:568 +msgid "Notification Rule" +msgstr "Regola di notifica" + +#: authentik/events/models.py:569 +msgid "Notification Rules" +msgstr "Regole di notifica" + +#: authentik/events/models.py:589 +msgid "Webhook Mapping" +msgstr "Mappatura Webhook" + +#: authentik/events/models.py:590 +msgid "Webhook Mappings" +msgstr "Mappature Webhook" + +#: authentik/events/monitored_tasks.py:205 +msgid "Task has not been run yet." +msgstr "L'attività non è stata ancora eseguita." + +#: authentik/flows/api/flows.py:295 +#, python-format +msgid "Flow not applicable to current user/request: %(messages)s" +msgstr "Flusso non applicabile all'utente/richiesta corrente: %(messages)s" + +#: authentik/flows/api/flows_diagram.py:68 +#: authentik/flows/api/flows_diagram.py:94 +#, python-format +msgid "Policy (%(type)s)" +msgstr "Criterio (%(type)s)" + +#: authentik/flows/api/flows_diagram.py:71 +#, python-format +msgid "Binding %(order)d" +msgstr "Associazione %(order)d" + +#: authentik/flows/api/flows_diagram.py:118 +msgid "Policy passed" +msgstr "Criterio approvato" + +#: authentik/flows/api/flows_diagram.py:122 +#, python-format +msgid "Stage (%(type)s)" +msgstr "Fase (%(type)s)" + +#: authentik/flows/api/flows_diagram.py:146 +#: authentik/flows/api/flows_diagram.py:206 +msgid "Policy denied" +msgstr "Criterio negato" + +#: authentik/flows/api/flows_diagram.py:156 +#: authentik/flows/api/flows_diagram.py:168 +#: authentik/flows/api/flows_diagram.py:205 +#: authentik/flows/api/flows_diagram.py:227 +msgid "End of the flow" +msgstr "Fine del flusso" + +#: authentik/flows/api/flows_diagram.py:169 +msgid "Requirement not fulfilled" +msgstr "Requisito non soddisfatto" + +#: authentik/flows/api/flows_diagram.py:177 +msgid "Flow authentication requirement" +msgstr "Requisito di autenticazione del flusso" + +#: authentik/flows/api/flows_diagram.py:183 +msgid "Requirement fulfilled" +msgstr "Requisito soddisfatto" + +#: authentik/flows/api/flows_diagram.py:196 +msgid "Pre-flow policies" +msgstr "Politiche pre-flusso" + +#: authentik/flows/api/flows_diagram.py:214 authentik/flows/models.py:193 +msgid "Flow" +msgstr "Flusso" + +#: authentik/flows/exceptions.py:19 +msgid "Flow does not apply to current user." +msgstr "Il flusso non si applica all'utente corrente." + +#: authentik/flows/models.py:114 +#, python-format +msgid "Dynamic In-memory stage: %(doc)s" +msgstr "Fase dinamica in memoria: %(doc)s" + +#: authentik/flows/models.py:129 +msgid "Visible in the URL." +msgstr "Visibile nell'URL." + +#: authentik/flows/models.py:131 +msgid "Shown as the Title in Flow pages." +msgstr "Mostrato come Titolo nelle pagine Flusso" + +#: authentik/flows/models.py:138 +msgid "" +"Decides what this Flow is used for. For example, the Authentication flow is " +"redirect to when an un-authenticated user visits authentik." +msgstr "" +"Decide cosa viene utilizzato questo Flusso. Ad esempio, il flusso di " +"autenticazione viene reindirizzato quando un utente non autenticato visita " +"authentik." + +#: authentik/flows/models.py:147 +msgid "Background shown during execution" +msgstr "Sfondo mostrato durante l'esecuzione" + +#: authentik/flows/models.py:154 +msgid "" +"Enable compatibility mode, increases compatibility with password managers on" +" mobile devices." +msgstr "" +"Abilita compatibilità, incrementa la compatibilità con i gestori password su" +" dispositivi mobile." + +#: authentik/flows/models.py:162 +msgid "Configure what should happen when a flow denies access to a user." +msgstr "" +"Configura cosa può accadere quando un flusso nega l'accesso ad un utente." + +#: authentik/flows/models.py:168 +msgid "Required level of authentication and authorization to access a flow." +msgstr "" +"Livello richiesto di autenticazione e autorizzazione per accedere a un " +"flusso." + +#: authentik/flows/models.py:194 +msgid "Flows" +msgstr "Flussi" + +#: authentik/flows/models.py:197 +msgid "Can export a Flow" +msgstr "Può esportare un flusso" + +#: authentik/flows/models.py:198 +msgid "Can inspect a Flow's execution" +msgstr "Può ispezionare l'esecuzione di un flusso" + +#: authentik/flows/models.py:199 +msgid "View Flow's cache metrics" +msgstr "Visualizza le metriche della cache del flusso" + +#: authentik/flows/models.py:200 +msgid "Clear Flow's cache metrics" +msgstr "Cancella le metriche della cache del flusso" + +#: authentik/flows/models.py:216 +msgid "Evaluate policies during the Flow planning process." +msgstr "" +"Valutare le politiche durante il processo di pianificazione del flusso." + +#: authentik/flows/models.py:220 +msgid "Evaluate policies when the Stage is present to the user." +msgstr "Valutare le policy quando lo stage è presente all'utente." + +#: authentik/flows/models.py:227 +msgid "" +"Configure how the flow executor should handle an invalid response to a " +"challenge. RETRY returns the error message and a similar challenge to the " +"executor. RESTART restarts the flow from the beginning, and " +"RESTART_WITH_CONTEXT restarts the flow while keeping the current context." +msgstr "" +"Specifica come l'esecutore del flow dovrebbe gestire un riscontro negativo " +"di una verifica. RETRY restituisce il messaggio di errore e una verifica " +"simile all'esecutore. RESTART riavvia il flusso da capo, e " +"RESTART_WITH_CONTEXT lo riavvia mantenendo lo stato attuale." + +#: authentik/flows/models.py:250 +msgid "Flow Stage Binding" +msgstr "Associazione della fase del flusso" + +#: authentik/flows/models.py:251 +msgid "Flow Stage Bindings" +msgstr "Associazioni della fase del flusso" + +#: authentik/flows/models.py:266 +msgid "" +"Flow used by an authenticated user to configure this Stage. If empty, user " +"will not be able to configure this stage." +msgstr "" +"Flusso utilizzato da un utente autenticato per configurare questa fase. Se " +"vuoto, l'utente non sarà in grado di configurare questa fase." + +#: authentik/flows/models.py:306 +msgid "Flow Token" +msgstr "Token del flusso" + +#: authentik/flows/models.py:307 +msgid "Flow Tokens" +msgstr "Tokens del flusso" + +#: authentik/lib/utils/time.py:27 +#, python-format +msgid "%(value)s is not in the correct format of 'hours=3;minutes=1'." +msgstr "%(value)s non è nel formato corretto di 'hours=3;minutes=1'." + +#: authentik/lib/validators.py:16 +#, python-brace-format +msgid "The fields {field_names} must be used together." +msgstr "I campi {field_names} devono essere utilizzati insieme." + +#: authentik/outposts/api/service_connections.py:127 +msgid "" +"You can only use an empty kubeconfig when connecting to a local cluster." +msgstr "" +"Puoi usare sono un kubeconfig vuoto durante la connessione ad un cluster " +"locale." + +#: authentik/outposts/api/service_connections.py:135 +msgid "Invalid kubeconfig" +msgstr "Kubeconfig invalida" + +#: authentik/outposts/models.py:122 +msgid "" +"If enabled, use the local connection. Required Docker socket/Kubernetes " +"Integration" +msgstr "" +"Se abilitato, utilizzare la connessione locale. Socket Docker/Integrazione " +"Kubernetes richiesto" + +#: authentik/outposts/models.py:152 +msgid "Outpost Service-Connection" +msgstr "Connessione al servizio Outpost" + +#: authentik/outposts/models.py:153 +msgid "Outpost Service-Connections" +msgstr "Connessioni al servizii Outpost" + +#: authentik/outposts/models.py:161 +msgid "" +"Can be in the format of 'unix://' when connecting to a local docker " +"daemon, or 'https://:2376' when connecting to a remote system." +msgstr "" +"Può essere nel formato 'unix://' quando si connette a un demone Docker" +" locale, o 'https://:2376' quando si connette a un sistema remoto." + +#: authentik/outposts/models.py:173 +msgid "" +"CA which the endpoint's Certificate is verified against. Can be left empty " +"for no validation." +msgstr "" +"CA contro cui viene verificato il certificato del punto finale. Può essere " +"lasciato vuoto per nessuna validazione." + +#: authentik/outposts/models.py:185 +msgid "" +"Certificate/Key used for authentication. Can be left empty for no " +"authentication." +msgstr "" +"Certificato/Chiave utilizzata per l'autenticazione. Può essere lasciato " +"vuoto per nessuna autenticazione." + +#: authentik/outposts/models.py:203 +msgid "Docker Service-Connection" +msgstr "Connessione al servizio Docker" + +#: authentik/outposts/models.py:204 +msgid "Docker Service-Connections" +msgstr "Connessioni al servizi Docker" + +#: authentik/outposts/models.py:212 +msgid "" +"Paste your kubeconfig here. authentik will automatically use the currently " +"selected context." +msgstr "" +"Incolla il tuo kubeconfig qui. authentik utilizzerà automaticamente il " +"contesto attualmente selezionato." + +#: authentik/outposts/models.py:218 +msgid "Verify SSL Certificates of the Kubernetes API endpoint" +msgstr "Verifica i certificati SSL del punto di accesso API di Kubernetes." + +#: authentik/outposts/models.py:235 +msgid "Kubernetes Service-Connection" +msgstr "Connessione al servizio Kubernetes" + +#: authentik/outposts/models.py:236 +msgid "Kubernetes Service-Connections" +msgstr "Connessione ai servizi Kubernetes" + +#: authentik/outposts/models.py:252 +msgid "" +"Select Service-Connection authentik should use to manage this outpost. Leave" +" empty if authentik should not handle the deployment." +msgstr "" +"Seleziona il servizio di connessione che authentik dovrebbe utilizzare per " +"gestire questo outpost. Lascia vuoto se authentik non deve gestire la " +"distribuzione." + +#: authentik/outposts/models.py:419 +msgid "Outpost" +msgstr "Outpost" + +#: authentik/outposts/models.py:420 +msgid "Outposts" +msgstr "Outposts" + +#: authentik/policies/denied.py:24 +msgid "Access denied" +msgstr "Accesso negato" + +#: authentik/policies/dummy/models.py:44 +msgid "Dummy Policy" +msgstr "Criterio fittizio" + +#: authentik/policies/dummy/models.py:45 +msgid "Dummy Policies" +msgstr "Politiche fittizie" + +#: authentik/policies/event_matcher/api.py:20 +#: authentik/policies/event_matcher/models.py:56 +msgid "" +"Match events created by selected application. When left empty, all " +"applications are matched." +msgstr "" +"Eventi di corrispondenza creati dall'applicazione selezionata. Quando " +"lasciato vuoto, tutte le applicazioni vengono corrisposte." + +#: authentik/policies/event_matcher/api.py:29 +#: authentik/policies/event_matcher/models.py:64 +msgid "" +"Match events created by selected model. When left empty, all models are " +"matched. When an app is selected, all the application's models are matched." +msgstr "" +"Eventi di corrispondenza creati dal modello selezionato. Quando lasciato " +"vuoto, tutti i modelli vengono abbinati. Quando viene selezionata un'app, " +"vengono abbinati tutti i modelli dell'applicazione." + +#: authentik/policies/event_matcher/api.py:42 +msgid "At least one criteria must be set." +msgstr "Deve essere impostato almeno un criterio." + +#: authentik/policies/event_matcher/models.py:48 +msgid "" +"Match created events with this action type. When left empty, all action " +"types will be matched." +msgstr "" +"Corrispondere gli eventi creati con questo tipo di azione. Quando lasciato " +"vuoto, tutti i tipi di azione saranno corrisposti." + +#: authentik/policies/event_matcher/models.py:73 +msgid "" +"Matches Event's Client IP (strict matching, for network matching use an " +"Expression Policy)" +msgstr "" +"Corrisponde all'IP del client dell'evento (corrispondenza rigorosa, per la " +"corrispondenza di rete utilizzare una criterio di espressione)" + +#: authentik/policies/event_matcher/models.py:143 +msgid "Event Matcher Policy" +msgstr "Criterio Corrispondenza Evento" + +#: authentik/policies/event_matcher/models.py:144 +msgid "Event Matcher Policies" +msgstr "Criteri Corrispondenza Evento" + +#: authentik/policies/expiry/models.py:45 +#, python-format +msgid "Password expired %(days)d days ago. Please update your password." +msgstr "" +"Password scaduta %(days)d giorni fa. Si prega di aggiornare la password." + +#: authentik/policies/expiry/models.py:49 +msgid "Password has expired." +msgstr "Password scaduta" + +#: authentik/policies/expiry/models.py:53 +msgid "Password Expiry Policy" +msgstr "Criterio di scadenza della password" + +#: authentik/policies/expiry/models.py:54 +msgid "Password Expiry Policies" +msgstr "Politiche di scadenza della password" + +#: authentik/policies/expression/models.py:40 +msgid "Expression Policy" +msgstr "Criterio di Espressione" + +#: authentik/policies/expression/models.py:41 +msgid "Expression Policies" +msgstr "Criteri di espressione" + +#: authentik/policies/models.py:22 +msgid "all, all policies must pass" +msgstr "tutte, tutti i criteri devono passare" + +#: authentik/policies/models.py:23 +msgid "any, any policy must pass" +msgstr "qualsiasi, qualsiasi criterio deve passare" + +#: authentik/policies/models.py:46 +msgid "Policy Binding Model" +msgstr "Modello Associazione Criterio" + +#: authentik/policies/models.py:47 +msgid "Policy Binding Models" +msgstr "Modelli Associazione Criterio" + +#: authentik/policies/models.py:86 +msgid "Negates the outcome of the policy. Messages are unaffected." +msgstr "Nega il risultato del criterio. I messaggi non sono influenzati." + +#: authentik/policies/models.py:89 +msgid "Timeout after which Policy execution is terminated." +msgstr "Timeout dopo il quale l'esecuzione del Criterio viene terminato." + +#: authentik/policies/models.py:92 +msgid "Result if the Policy execution fails." +msgstr "Risultato se l'esecuzione della Policy fallisce." + +#: authentik/policies/models.py:145 +msgid "Policy Binding" +msgstr "Associazione criterio" + +#: authentik/policies/models.py:146 +msgid "Policy Bindings" +msgstr "Associazioni criterio" + +#: authentik/policies/models.py:167 +msgid "" +"When this option is enabled, all executions of this policy will be logged. " +"By default, only execution errors are logged." +msgstr "" +"Quando questa opzione è abilitata, tutte le esecuzioni di questo criterio " +"verranno registrate. Per impostazione predefinita, vengono registrati solo " +"gli errori di esecuzione." + +#: authentik/policies/models.py:189 +msgid "Policy" +msgstr "Criterio" + +#: authentik/policies/models.py:190 +msgid "Policies" +msgstr "Politiche" + +#: authentik/policies/models.py:193 +msgid "View Policy's cache metrics" +msgstr "Visualizza le metriche della cache della Policy" + +#: authentik/policies/models.py:194 +msgid "Clear Policy's cache metrics" +msgstr "Cancellare le metriche della cache della Policy" + +#: authentik/policies/password/models.py:27 +msgid "Field key to check, field keys defined in Prompt stages are available." +msgstr "" +"Chiave di campo da verificare, sono disponibili le chiavi di campo definite " +"nelle fasi Richiesta." + +#: authentik/policies/password/models.py:44 +msgid "How many times the password hash is allowed to be on haveibeenpwned" +msgstr "" +"Quante volte l'hash della password è consentito essere su haveibeenpwned" + +#: authentik/policies/password/models.py:49 +msgid "" +"If the zxcvbn score is equal or less than this value, the policy will fail." +msgstr "" +"Se il punteggio zxcvbn è inferiore o uguale a questo valore, il criterio non" +" verrà soddisfatto." + +#: authentik/policies/password/models.py:72 +msgid "Password not set in context" +msgstr "Password non impostata nel contesto" + +#: authentik/policies/password/models.py:134 +#, python-format +msgid "Password exists on %(count)d online lists." +msgstr "Password esistente in %(count)d lite online." + +#: authentik/policies/password/models.py:154 +msgid "Password is too weak." +msgstr "Password troppo deblole" + +#: authentik/policies/password/models.py:162 +msgid "Password Policy" +msgstr "Criterio della password" + +#: authentik/policies/password/models.py:163 +msgid "Password Policies" +msgstr "Politiche delle password" + +#: authentik/policies/reputation/api.py:18 +msgid "Either IP or Username must be checked" +msgstr "È necessario controllare l'IP o il nome utente" + +#: authentik/policies/reputation/models.py:67 +msgid "Reputation Policy" +msgstr "Criterio Reputazione" + +#: authentik/policies/reputation/models.py:68 +msgid "Reputation Policies" +msgstr "Politiche della reputazione" + +#: authentik/policies/reputation/models.py:95 +msgid "Reputation Score" +msgstr "Punteggio di reputazione" + +#: authentik/policies/reputation/models.py:96 +msgid "Reputation Scores" +msgstr "Punteggi di reputazione" + +#: authentik/policies/templates/policies/denied.html:7 +#: authentik/policies/templates/policies/denied.html:11 +msgid "Permission denied" +msgstr "Permesso negato" + +#: authentik/policies/templates/policies/denied.html:21 +msgid "User's avatar" +msgstr "Avatar utente" + +#: authentik/policies/templates/policies/denied.html:25 +msgid "Not you?" +msgstr "Non sei tu?" + +#: authentik/policies/templates/policies/denied.html:33 +msgid "Request has been denied." +msgstr "La richiesta è stata negata." + +#: authentik/policies/templates/policies/denied.html:44 +msgid "Messages:" +msgstr "Messaggi:" + +#: authentik/policies/templates/policies/denied.html:54 +msgid "Explanation:" +msgstr "Spiegazione:" + +#: authentik/policies/templates/policies/denied.html:58 +#, python-format +msgid "" +"\n" +" Policy binding '%(name)s' returned result '%(result)s'\n" +" " +msgstr "" +"\n" +" L'associazione criterio '%(name)s' ha restituito '%(result)s'\n" +" " + +#: authentik/policies/views.py:68 +msgid "Failed to resolve application" +msgstr "Impossibile risolvere l'applicazione" + +#: authentik/providers/ldap/models.py:25 +msgid "DN under which objects are accessible." +msgstr "DN sotto il quale gli oggetti sono accessibili." + +#: authentik/providers/ldap/models.py:34 +msgid "" +"Users in this group can do search queries. If not set, every user can " +"execute search queries." +msgstr "" +"Gli utenti di questo gruppo possono scrivere query di ricerca. Se non " +"specificato, qualsiasi utente può eseguirle." + +#: authentik/providers/ldap/models.py:53 +msgid "" +"The start for uidNumbers, this number is added to the user.pk to make sure " +"that the numbers aren't too low for POSIX users. Default is 2000 to ensure " +"that we don't collide with local users uidNumber" +msgstr "" +"Il numero di partenza per uidNumbers, questo numero viene aggiunto a user.pk" +" per assicurarsi che i numeri non siano troppo bassi per gli utenti POSIX. " +"Il valore predefinito è 2000 per garantire che non ci siano collisioni con " +"gli uidNumber degli utenti locali." + +#: authentik/providers/ldap/models.py:62 +msgid "" +"The start for gidNumbers, this number is added to a number generated from " +"the group.pk to make sure that the numbers aren't too low for POSIX groups. " +"Default is 4000 to ensure that we don't collide with local groups or users " +"primary groups gidNumber" +msgstr "" +"Il punto di partenza per gidNumbers, questo numero viene aggiunto a un " +"numero generato dal group.pk per assicurarsi che i numeri non siano troppo " +"bassi per i gruppi POSIX. Il valore predefinito è 4000 per garantire che non" +" ci siano collisioni con gruppi locali o gruppi primari di utenti gidNumber." + +#: authentik/providers/ldap/models.py:76 +#: authentik/providers/radius/models.py:34 +msgid "" +"When enabled, code-based multi-factor authentication can be used by " +"appending a semicolon and the TOTP code to the password. This should only be" +" enabled if all users that will bind to this provider have a TOTP device " +"configured, as otherwise a password may incorrectly be rejected if it " +"contains a semicolon." +msgstr "" +"Quando abilitato, l'autenticazione a più fattori basata su codice può essere" +" utilizzata aggiungendo un punto e virgola e il codice TOTP alla password. " +"Ciò dovrebbe essere abilitato solo se tutti gli utenti che si assoceranno a " +"questo provider hanno un dispositivo TOTP configurato, poiché altrimenti una" +" password potrebbe essere erroneamente rifiutata se contiene un punto e " +"virgola." + +#: authentik/providers/ldap/models.py:108 +msgid "LDAP Provider" +msgstr "Provider LDAP" + +#: authentik/providers/ldap/models.py:109 +msgid "LDAP Providers" +msgstr "Providers LDAP" + +#: authentik/providers/oauth2/id_token.py:27 +msgid "Based on the Hashed User ID" +msgstr "Basato sull'ID utente hashato" + +#: authentik/providers/oauth2/id_token.py:28 +msgid "Based on user ID" +msgstr "Basato sull' ID utente" + +#: authentik/providers/oauth2/id_token.py:29 +msgid "Based on user UUID" +msgstr "Basato sull' UUID utente" + +#: authentik/providers/oauth2/id_token.py:30 +msgid "Based on the username" +msgstr "Basato sull'username" + +#: authentik/providers/oauth2/id_token.py:33 +msgid "Based on the User's Email. This is recommended over the UPN method." +msgstr "Basato sull'email dell'utente. Consigliato per il metodo UPN." + +#: authentik/providers/oauth2/id_token.py:38 +msgid "" +"Based on the User's UPN, only works if user has a 'upn' attribute set. Use " +"this method only if you have different UPN and Mail domains." +msgstr "" +"Basato sull'UPN dell'utente, funziona solo se l'utente ha un attributo 'upn'" +" impostato. Utilizza questo metodo solo se hai domini UPN e Mail diversi." + +#: authentik/providers/oauth2/models.py:43 +msgid "Confidential" +msgstr "Confidenziale" + +#: authentik/providers/oauth2/models.py:44 +msgid "Public" +msgstr "Pubblico" + +#: authentik/providers/oauth2/models.py:66 +msgid "Same identifier is used for all providers" +msgstr "Stesso identificatore usato su tutti i providers" + +#: authentik/providers/oauth2/models.py:68 +msgid "Each provider has a different issuer, based on the application slug." +msgstr "" +"Ogni provider ha un issuer differente, basato sullo slug dell'applicazione." + +#: authentik/providers/oauth2/models.py:75 +msgid "code (Authorization Code Flow)" +msgstr "code (Flusso di autorizzazione del codice)" + +#: authentik/providers/oauth2/models.py:76 +msgid "id_token (Implicit Flow)" +msgstr "id_token (Flusso Implicito)" + +#: authentik/providers/oauth2/models.py:77 +msgid "id_token token (Implicit Flow)" +msgstr "id_token token (Flusso Implicito)" + +#: authentik/providers/oauth2/models.py:78 +msgid "code token (Hybrid Flow)" +msgstr "code token (Flusso Ibrido)" + +#: authentik/providers/oauth2/models.py:79 +msgid "code id_token (Hybrid Flow)" +msgstr "code id_token (Flusso Ibrido)" + +#: authentik/providers/oauth2/models.py:80 +msgid "code id_token token (Hybrid Flow)" +msgstr "code id_token token (Flusso Ibrido)" + +#: authentik/providers/oauth2/models.py:86 +msgid "HS256 (Symmetric Encryption)" +msgstr "HS256 (Crittografia Simmetrica)" + +#: authentik/providers/oauth2/models.py:87 +msgid "RS256 (Asymmetric Encryption)" +msgstr "RS256 (Crittografia Asimmetrica)" + +#: authentik/providers/oauth2/models.py:88 +msgid "ES256 (Asymmetric Encryption)" +msgstr "ES256 (Crittografia Asimmetrica)" + +#: authentik/providers/oauth2/models.py:94 +msgid "Scope used by the client" +msgstr "Scope usato dall'utente" + +#: authentik/providers/oauth2/models.py:98 +msgid "" +"Description shown to the user when consenting. If left empty, the user won't" +" be informed." +msgstr "" +"Descrizione mostrata all'utente durante il consenso. Se lasciato vuoto, " +"l'utente non verrà informato." + +#: authentik/providers/oauth2/models.py:117 +msgid "Scope Mapping" +msgstr "Mappatura dell'ambito" + +#: authentik/providers/oauth2/models.py:118 +msgid "Scope Mappings" +msgstr "Mappature degli ambiti" + +#: authentik/providers/oauth2/models.py:128 +msgid "Client Type" +msgstr "Tipo Client" + +#: authentik/providers/oauth2/models.py:130 +msgid "" +"Confidential clients are capable of maintaining the confidentiality of their" +" credentials. Public clients are incapable" +msgstr "" +"I clienti confidenziali sono in grado di mantenere la riservatezza delle " +"loro credenziali. I clienti pubblici sono incapaci." + +#: authentik/providers/oauth2/models.py:137 +msgid "Client ID" +msgstr "Client ID" + +#: authentik/providers/oauth2/models.py:143 +msgid "Client Secret" +msgstr "Client Secret" + +#: authentik/providers/oauth2/models.py:149 +msgid "Redirect URIs" +msgstr "URL di reindirizzamento" + +#: authentik/providers/oauth2/models.py:150 +msgid "Enter each URI on a new line." +msgstr "Inserisci ogni URI su una nuova riga." + +#: authentik/providers/oauth2/models.py:155 +msgid "Include claims in id_token" +msgstr "Includere le richieste in id_token" + +#: authentik/providers/oauth2/models.py:157 +msgid "" +"Include User claims from scopes in the id_token, for applications that don't" +" access the userinfo endpoint." +msgstr "" +"Includere le richieste dell'utente dagli ambiti nell'id_token, per le " +"applicazioni che non accedono al punto di accesso userinfo." + +#: authentik/providers/oauth2/models.py:166 +msgid "" +"Access codes not valid on or after current time + this value (Format: " +"hours=1;minutes=2;seconds=3)." +msgstr "" +"Codici di accesso non validi a partire dall'ora corrente + questo valore " +"(Format: hours=1;minutes=2;seconds=3)." + +#: authentik/providers/oauth2/models.py:174 +#: authentik/providers/oauth2/models.py:182 +msgid "" +"Tokens not valid on or after current time + this value (Format: " +"hours=1;minutes=2;seconds=3)." +msgstr "" +"Tokens non validi a partire dall'ora corrente + questo valore (Format: " +"hours=1;minutes=2;seconds=3)." + +#: authentik/providers/oauth2/models.py:191 +msgid "" +"Configure what data should be used as unique User Identifier. For most " +"cases, the default should be fine." +msgstr "" +"Configurare quale dato dovrebbe essere utilizzato come identificatore " +"univoco dell'utente. Per la maggior parte dei casi, il valore predefinito " +"dovrebbe essere sufficiente." + +#: authentik/providers/oauth2/models.py:198 +msgid "Configure how the issuer field of the ID Token should be filled." +msgstr "" +"Configurare come il campo emittente dell'ID Token dovrebbe essere compilato." + +#: authentik/providers/oauth2/models.py:203 +msgid "Signing Key" +msgstr "Chiave di firma" + +#: authentik/providers/oauth2/models.py:207 +msgid "" +"Key used to sign the tokens. Only required when JWT Algorithm is set to " +"RS256." +msgstr "" +"Chiave utilizzata per firmare i token. Richiesta solo quando l'algoritmo JWT" +" è impostato su RS256." + +#: authentik/providers/oauth2/models.py:214 +msgid "" +"Any JWT signed by the JWK of the selected source can be used to " +"authenticate." +msgstr "" +"Ogni JWT firmata dal JWK della sorgente selezionata può essere utilizzata " +"per l'autenticazione." + +#: authentik/providers/oauth2/models.py:287 +msgid "OAuth2/OpenID Provider" +msgstr "Fornitore OAuth2/OpenID" + +#: authentik/providers/oauth2/models.py:288 +msgid "OAuth2/OpenID Providers" +msgstr "Fornitori OAuth2/OpenID" + +#: authentik/providers/oauth2/models.py:297 +#: authentik/providers/oauth2/models.py:429 +msgid "Scopes" +msgstr "Scopes" + +#: authentik/providers/oauth2/models.py:316 +msgid "Code" +msgstr "Codice" + +#: authentik/providers/oauth2/models.py:317 +msgid "Nonce" +msgstr "Nonce" + +#: authentik/providers/oauth2/models.py:318 +msgid "Code Challenge" +msgstr "Verifica del codice" + +#: authentik/providers/oauth2/models.py:320 +msgid "Code Challenge Method" +msgstr "Metodo di verifica del codice" + +#: authentik/providers/oauth2/models.py:340 +msgid "Authorization Code" +msgstr "Codice di autorizzazione" + +#: authentik/providers/oauth2/models.py:341 +msgid "Authorization Codes" +msgstr "Codici di autorizzazione" + +#: authentik/providers/oauth2/models.py:383 +msgid "OAuth2 Access Token" +msgstr "Token di accesso OAuth2" + +#: authentik/providers/oauth2/models.py:384 +msgid "OAuth2 Access Tokens" +msgstr "Tokens di accesso OAuth2" + +#: authentik/providers/oauth2/models.py:394 +msgid "ID Token" +msgstr "ID Token" + +#: authentik/providers/oauth2/models.py:413 +msgid "OAuth2 Refresh Token" +msgstr "Token di aggiornamento OAuth2" + +#: authentik/providers/oauth2/models.py:414 +msgid "OAuth2 Refresh Tokens" +msgstr "Tokens di aggiornamento OAuth2" + +#: authentik/providers/oauth2/models.py:441 +msgid "Device Token" +msgstr "Token Dispositivo" + +#: authentik/providers/oauth2/models.py:442 +msgid "Device Tokens" +msgstr "Token Dispositivi" + +#: authentik/providers/oauth2/views/authorize.py:448 +#: authentik/providers/saml/views/flows.py:87 +#, python-format +msgid "Redirecting to %(app)s..." +msgstr "Reindirizzamento a %(app)s..." + +#: authentik/providers/oauth2/views/device_init.py:151 +msgid "Invalid code" +msgstr "Codice non valido" + +#: authentik/providers/oauth2/views/userinfo.py:55 +#: authentik/providers/oauth2/views/userinfo.py:56 +msgid "GitHub Compatibility: Access your User Information" +msgstr "Compatibilità GitHub: Accesso alle tue informazioni utente" + +#: authentik/providers/oauth2/views/userinfo.py:57 +msgid "GitHub Compatibility: Access you Email addresses" +msgstr "Compatibilità GitHub: Accesso ai tuoi indirizzi email" + +#: authentik/providers/oauth2/views/userinfo.py:58 +msgid "GitHub Compatibility: Access your Groups" +msgstr "Compatibilità GitHub: Accesso ai tuoi gruppi" + +#: authentik/providers/oauth2/views/userinfo.py:59 +msgid "authentik API Access on behalf of your user" +msgstr "authentik Accesso API per conto del tuo utente" + +#: authentik/providers/proxy/api.py:52 +msgid "User and password attributes must be set when basic auth is enabled." +msgstr "" +"Gli attributi utente e password devono essere impostati quando " +"l'autenticazione di base è abilitata." + +#: authentik/providers/proxy/api.py:63 +msgid "Internal host cannot be empty when forward auth is disabled." +msgstr "" +"L'host interno non può essere vuoto quando l'autenticazione inoltrata è " +"disabilitata." + +#: authentik/providers/proxy/models.py:54 +msgid "Validate SSL Certificates of upstream servers" +msgstr "Convalida dei certificati SSL dei server upstream" + +#: authentik/providers/proxy/models.py:55 +msgid "Internal host SSL Validation" +msgstr "Validazione SSL dell'host interno" + +#: authentik/providers/proxy/models.py:61 +msgid "" +"Enable support for forwardAuth in traefik and nginx auth_request. Exclusive " +"with internal_host." +msgstr "" +"Abilita il supporto per forwardAuth in traefik e nginx auth_request. " +"Esclusivo con internal_host." + +#: authentik/providers/proxy/models.py:70 +msgid "" +"Regular expressions for which authentication is not required. Each new line " +"is interpreted as a new Regular Expression." +msgstr "" +"Espressioni regolari per le quali non è richiesta l'autenticazione. Ogni " +"nuova riga viene interpretata come una nuova espressione regolare." + +#: authentik/providers/proxy/models.py:78 +msgid "" +"When enabled, this provider will intercept the authorization header and " +"authenticate requests based on its value." +msgstr "" +"Quando abilitato, questo provider intercetterà l'intestazione di " +"autorizzazione e autenticherà le richieste in base al suo valore." + +#: authentik/providers/proxy/models.py:84 +msgid "Set HTTP-Basic Authentication" +msgstr "Imposta Autenticazione HTTP-Basic" + +#: authentik/providers/proxy/models.py:86 +msgid "" +"Set a custom HTTP-Basic Authentication header based on values from " +"authentik." +msgstr "" +"Imposta un header personalizzato HTTP-Basic Authentication basato su " +"parametri provenienti da authentik." + +#: authentik/providers/proxy/models.py:91 +msgid "HTTP-Basic Username Key" +msgstr "Chiave Username HTTP-Basic" + +#: authentik/providers/proxy/models.py:93 +msgid "" +"User/Group Attribute used for the user part of the HTTP-Basic Header. If not" +" set, the user's Email address is used." +msgstr "" +"User/Group Attributo utilizzato per la parte utente dell'intestazione HTTP-" +"Basic. Se non impostato, viene utilizzato l'indirizzo email dell'utente." + +#: authentik/providers/proxy/models.py:99 +msgid "HTTP-Basic Password Key" +msgstr "Chiave Password HTTP-Basic" + +#: authentik/providers/proxy/models.py:100 +msgid "" +"User/Group Attribute used for the password part of the HTTP-Basic Header." +msgstr "" +"Attributo utente/gruppo utilizzato per la parte relativa alla password " +"dell'intestazione HTTP-Basic." + +#: authentik/providers/proxy/models.py:154 +msgid "Proxy Provider" +msgstr "Provider Proxy" + +#: authentik/providers/proxy/models.py:155 +msgid "Proxy Providers" +msgstr "Providers Proxy" + +#: authentik/providers/radius/models.py:18 +msgid "Shared secret between clients and server to hash packets." +msgstr "Segreto condiviso tra client e server per hashare i pacchetti." + +#: authentik/providers/radius/models.py:24 +msgid "" +"List of CIDRs (comma-separated) that clients can connect from. A more " +"specific CIDR will match before a looser one. Clients connecting from a non-" +"specified CIDR will be dropped." +msgstr "" +"Elenco di CIDR (separati da virgola) da cui i client possono connettersi. Un" +" CIDR più specifico corrisponderà prima di uno più generico. I client che si" +" connettono da un CIDR non specificato verranno eliminati." + +#: authentik/providers/radius/models.py:60 +msgid "Radius Provider" +msgstr "Provider Radius" + +#: authentik/providers/radius/models.py:61 +msgid "Radius Providers" +msgstr "Providers Radius" + +#: authentik/providers/saml/api/providers.py:258 +msgid "Invalid XML Syntax" +msgstr "Sintassi XML non valida" + +#: authentik/providers/saml/api/providers.py:268 +#, python-format +msgid "Failed to import Metadata: %(message)s" +msgstr "Impossibile importare i metadati: %(message)s" + +#: authentik/providers/saml/models.py:38 +msgid "ACS URL" +msgstr "URL ACS" + +#: authentik/providers/saml/models.py:43 +msgid "" +"Value of the audience restriction field of the assertion. When left empty, " +"no audience restriction will be added." +msgstr "" +"Valore del campo di limitazione del pubblico dell'asserzione. Se lasciato " +"vuoto, non verrà aggiunta alcuna restrizione sul pubblico." + +#: authentik/providers/saml/models.py:47 +msgid "Also known as EntityID" +msgstr "Conosciuto anche come EntityID" + +#: authentik/providers/saml/models.py:51 +msgid "Service Provider Binding" +msgstr "Associazione fornitore di servizi" + +#: authentik/providers/saml/models.py:53 +msgid "" +"This determines how authentik sends the response back to the Service " +"Provider." +msgstr "" +"Ciò determina il modo in cui authentik invia la risposta al fornitore di " +"servizi." + +#: authentik/providers/saml/models.py:63 +msgid "NameID Property Mapping" +msgstr "Mappatura proprietà NameID" + +#: authentik/providers/saml/models.py:65 +msgid "" +"Configure how the NameID value will be created. When left empty, the " +"NameIDPolicy of the incoming request will be considered" +msgstr "" +"Configura il modo in cui verrà creato il valore NameID. Se lasciato vuoto, " +"verrà considerato il NameIDPolicy della richiesta in arrivo" + +#: authentik/providers/saml/models.py:74 +msgid "" +"Assertion valid not before current time + this value (Format: " +"hours=-1;minutes=-2;seconds=-3)." +msgstr "" +"L'asserzione non è valida prima dell'ora corrente + questo valore (Formato: " +"hours=-1;minutes=-2;seconds=-3)." + +#: authentik/providers/saml/models.py:82 +msgid "" +"Assertion not valid on or after current time + this value (Format: " +"hours=1;minutes=2;seconds=3)." +msgstr "" +"Asserzione non valida a partire dall'ora corrente + questo valore (Formato: " +"hours=1;minutes=2;seconds=3)." + +#: authentik/providers/saml/models.py:91 +msgid "" +"Session not valid on or after current time + this value (Format: " +"hours=1;minutes=2;seconds=3)." +msgstr "" +"Sessione non valida a partire dall'ora corrente + questo valore (Format: " +"hours=1;minutes=2;seconds=3)." + +#: authentik/providers/saml/models.py:99 authentik/sources/saml/models.py:150 +msgid "SHA1" +msgstr "SHA1" + +#: authentik/providers/saml/models.py:100 authentik/sources/saml/models.py:151 +msgid "SHA256" +msgstr "SHA256" + +#: authentik/providers/saml/models.py:101 authentik/sources/saml/models.py:152 +msgid "SHA384" +msgstr "SHA384" + +#: authentik/providers/saml/models.py:102 authentik/sources/saml/models.py:153 +msgid "SHA512" +msgstr "SHA512" + +#: authentik/providers/saml/models.py:109 authentik/sources/saml/models.py:160 +msgid "RSA-SHA1" +msgstr "RSA-SHA1" + +#: authentik/providers/saml/models.py:110 authentik/sources/saml/models.py:161 +msgid "RSA-SHA256" +msgstr "RSA-SHA256" + +#: authentik/providers/saml/models.py:111 authentik/sources/saml/models.py:162 +msgid "RSA-SHA384" +msgstr "RSA-SHA384" + +#: authentik/providers/saml/models.py:112 authentik/sources/saml/models.py:163 +msgid "RSA-SHA512" +msgstr "RSA-SHA512" + +#: authentik/providers/saml/models.py:113 authentik/sources/saml/models.py:164 +msgid "DSA-SHA1" +msgstr "DSA-SHA1" + +#: authentik/providers/saml/models.py:124 authentik/sources/saml/models.py:130 +msgid "" +"When selected, incoming assertion's Signatures will be validated against " +"this certificate. To allow unsigned Requests, leave on default." +msgstr "" +"Quando selezionato, le Firme delle asserzioni in arrivo verranno validate " +"con questo certificato. Per consentire Richieste non firmate, lasciare su " +"impostazione predefinita." + +#: authentik/providers/saml/models.py:128 authentik/sources/saml/models.py:134 +msgid "Verification Certificate" +msgstr "Certificato di Verifica" + +#: authentik/providers/saml/models.py:136 +msgid "Keypair used to sign outgoing Responses going to the Service Provider." +msgstr "" +"Coppia di chiavi utilizzato per firmare le Risposte in uscita inviate al " +"Service Provider." + +#: authentik/providers/saml/models.py:138 authentik/sources/saml/models.py:144 +msgid "Signing Keypair" +msgstr "Coppia di chiavi di firma" + +#: authentik/providers/saml/models.py:142 +msgid "Default relay_state value for IDP-initiated logins" +msgstr "Valore predefinito di relay_state per i login inizializzati da IDP" + +#: authentik/providers/saml/models.py:171 +msgid "SAML Provider" +msgstr "Provider SAML" + +#: authentik/providers/saml/models.py:172 +msgid "SAML Providers" +msgstr "Providers SAML" + +#: authentik/providers/saml/models.py:196 +msgid "SAML Property Mapping" +msgstr "Mappatura Proprietà SAML" + +#: authentik/providers/saml/models.py:197 +msgid "SAML Property Mappings" +msgstr "Mappature Proprietà SAML" + +#: authentik/providers/scim/models.py:20 +msgid "Base URL to SCIM requests, usually ends in /v2" +msgstr "URL di base per le richieste SCIM, di solito termina con /v2" + +#: authentik/providers/scim/models.py:21 +msgid "Authentication token" +msgstr "Token di autenticazione" + +#: authentik/providers/scim/models.py:27 authentik/sources/ldap/models.py:98 +msgid "Property mappings used for group creation/updating." +msgstr "" +"Mapping delle proprietà utilizzate per la creazione/aggiornamento dei " +"gruppi." + +#: authentik/providers/scim/models.py:60 +msgid "SCIM Provider" +msgstr "Privider SCIM" + +#: authentik/providers/scim/models.py:61 +msgid "SCIM Providers" +msgstr "Providers SCIM" + +#: authentik/providers/scim/models.py:81 +msgid "SCIM Mapping" +msgstr "Mappatura SCIM" + +#: authentik/providers/scim/models.py:82 +msgid "SCIM Mappings" +msgstr "Mappature SCIM" + +#: authentik/providers/scim/tasks.py:52 +msgid "Starting full SCIM sync" +msgstr "Iniziando la sincronizzazione completa SCIM" + +#: authentik/providers/scim/tasks.py:59 +#, python-format +msgid "Syncing page %(page)d of users" +msgstr "Sincronizzando pagina %(page)d degli utenti" + +#: authentik/providers/scim/tasks.py:63 +#, python-format +msgid "Syncing page %(page)d of groups" +msgstr "Sincronizzando pagina %(page)d dei gruppi" + +#: authentik/providers/scim/tasks.py:92 +#, python-format +msgid "Failed to sync user %(user_name)s due to remote error: %(error)s" +msgstr "" +"Impossibile sincronizzare l'utente %(user_name)s a causa di un errore " +"remoto: %(error)s" + +#: authentik/providers/scim/tasks.py:103 authentik/providers/scim/tasks.py:144 +#, python-format +msgid "Stopping sync due to error: %(error)s" +msgstr "Arresto della sincronizzazione a causa di un errore: %(error)s" + +#: authentik/providers/scim/tasks.py:133 +#, python-format +msgid "Failed to sync group %(group_name)s due to remote error: %(error)s" +msgstr "" +"Impossibile sincronizzare il gruppo %(group_name)s a causa di un errore " +"remoto: %(error)s" + +#: authentik/rbac/models.py:51 +msgid "Role" +msgstr "Ruolo" + +#: authentik/rbac/models.py:52 +msgid "Roles" +msgstr "Ruoli" + +#: authentik/rbac/models.py:66 +msgid "System permission" +msgstr "Autorizzazione di sistema" + +#: authentik/rbac/models.py:67 +msgid "System permissions" +msgstr "Autorizzazioni di sistema" + +#: authentik/rbac/models.py:69 +msgid "Can view system info" +msgstr "Può visualizzare le informazioni di sistema" + +#: authentik/rbac/models.py:70 +msgid "Can view system tasks" +msgstr "Possono visualizzare le attività di sistema" + +#: authentik/rbac/models.py:71 +msgid "Can run system tasks" +msgstr "Può eseguire attività di sistema" + +#: authentik/rbac/models.py:72 +msgid "Can access admin interface" +msgstr "Può accedere all'interfaccia di amministrazione" + +#: authentik/recovery/management/commands/create_admin_group.py:11 +msgid "Create admin group if the default group gets deleted." +msgstr "" +"Crea un gruppo di amministratori se il gruppo predefinito viene eliminato." + +#: authentik/recovery/management/commands/create_recovery_key.py:17 +msgid "Create a Key which can be used to restore access to authentik." +msgstr "" +"Crea una chiave che può essere utilizzata per ripristinare l'accesso ad " +"authentik." + +#: authentik/recovery/views.py:24 +msgid "Used recovery-link to authenticate." +msgstr "Utilizzato il link di recupero per autenticarsi." + +#: authentik/sources/ldap/models.py:41 +msgid "Server URI" +msgstr "URI Server" + +#: authentik/sources/ldap/models.py:50 +msgid "" +"Optionally verify the LDAP Server's Certificate against the CA Chain in this" +" keypair." +msgstr "" +"Opzionalmente verificare il Certificato del Server LDAP rispetto alla Catena" +" CA in questa coppia di chiavi." + +#: authentik/sources/ldap/models.py:59 +msgid "" +"Client certificate to authenticate against the LDAP Server's Certificate." +msgstr "" +"Certificato del client per autenticarsi con il certificato del server LDAP." + +#: authentik/sources/ldap/models.py:62 +msgid "Bind CN" +msgstr "Associa CN" + +#: authentik/sources/ldap/models.py:64 +msgid "Enable Start TLS" +msgstr "Abilita Start TLS" + +#: authentik/sources/ldap/models.py:65 +msgid "Use Server URI for SNI verification" +msgstr "Usa l'URI del server per la verifica SNI" + +#: authentik/sources/ldap/models.py:67 +msgid "Base DN" +msgstr "Base DN" + +#: authentik/sources/ldap/models.py:69 +msgid "Prepended to Base DN for User-queries." +msgstr "Anteposto al DN di base per le query dell'utente." + +#: authentik/sources/ldap/models.py:70 +msgid "Addition User DN" +msgstr "Aggiunta User DN" + +#: authentik/sources/ldap/models.py:74 +msgid "Prepended to Base DN for Group-queries." +msgstr "Anteposto al DN di base per le query di gruppo." + +#: authentik/sources/ldap/models.py:75 +msgid "Addition Group DN" +msgstr "Gruppo di aggiunta DN" + +#: authentik/sources/ldap/models.py:81 +msgid "Consider Objects matching this filter to be Users." +msgstr "Considerare gli oggetti corrispondenti a questo filtro come Utenti." + +#: authentik/sources/ldap/models.py:84 +msgid "Field which contains members of a group." +msgstr "Campo che contiene i membri di un gruppo." + +#: authentik/sources/ldap/models.py:88 +msgid "Consider Objects matching this filter to be Groups." +msgstr "Considera gli oggetti corrispondenti a questo filtro come Gruppi." + +#: authentik/sources/ldap/models.py:91 +msgid "Field which contains a unique Identifier." +msgstr "Campo che contiene un identificatore unico." + +#: authentik/sources/ldap/models.py:105 +msgid "" +"When a user changes their password, sync it back to LDAP. This can only be " +"enabled on a single LDAP source." +msgstr "" +"Quando un utente cambia la propria password, sincronizzala con LDAP. Questo " +"può essere abilitato solo su una singola origine LDAP." + +#: authentik/sources/ldap/models.py:248 +msgid "LDAP Source" +msgstr "Sorgente LDAP" + +#: authentik/sources/ldap/models.py:249 +msgid "LDAP Sources" +msgstr "Sorgenti LDAP" + +#: authentik/sources/ldap/models.py:271 +msgid "LDAP Property Mapping" +msgstr "Mappatura proprietà LDAP" + +#: authentik/sources/ldap/models.py:272 +msgid "LDAP Property Mappings" +msgstr "Mappatura proprietà LDAP" + +#: authentik/sources/ldap/signals.py:52 +msgid "Password does not match Active Directory Complexity." +msgstr "La password non soddisfa la complessità Active Directory." + +#: authentik/sources/oauth/clients/oauth2.py:68 +msgid "No token received." +msgstr "Nessun token ricevuto." + +#: authentik/sources/oauth/models.py:24 +msgid "Request Token URL" +msgstr "URL di Richiesta Token" + +#: authentik/sources/oauth/models.py:26 +msgid "" +"URL used to request the initial token. This URL is only required for OAuth " +"1." +msgstr "" +"URL utilizzato per richiedere il token iniziale. Questo URL è richiesto solo" +" per OAuth 1." + +#: authentik/sources/oauth/models.py:32 +msgid "Authorization URL" +msgstr "Authorization URL" + +#: authentik/sources/oauth/models.py:33 +msgid "URL the user is redirect to to conest the flow." +msgstr "URL a cui l'utente viene reindirizzato per concludere il flusso." + +#: authentik/sources/oauth/models.py:38 +msgid "Access Token URL" +msgstr "URL del token di accesso" + +#: authentik/sources/oauth/models.py:39 +msgid "URL used by authentik to retrieve tokens." +msgstr "URL utilizzato da authentik per recuperare i token." + +#: authentik/sources/oauth/models.py:44 +msgid "Profile URL" +msgstr "URL Profilo" + +#: authentik/sources/oauth/models.py:45 +msgid "URL used by authentik to get user information." +msgstr "URL utilizzato da authentik per ottenere le informazioni dell'utente." + +#: authentik/sources/oauth/models.py:48 +msgid "Additional Scopes" +msgstr "Ambiti aggiuntivi" + +#: authentik/sources/oauth/models.py:107 +msgid "OAuth Source" +msgstr "Sorgente OAuth" + +#: authentik/sources/oauth/models.py:108 +msgid "OAuth Sources" +msgstr "Sorgenti OAuth" + +#: authentik/sources/oauth/models.py:116 +msgid "GitHub OAuth Source" +msgstr "Sorgente OAuth di GitHub" + +#: authentik/sources/oauth/models.py:117 +msgid "GitHub OAuth Sources" +msgstr "Sorgenti OAuth di GitHub" + +#: authentik/sources/oauth/models.py:125 +msgid "Twitch OAuth Source" +msgstr "Sorgente OAuth di Twitch" + +#: authentik/sources/oauth/models.py:126 +msgid "Twitch OAuth Sources" +msgstr "Sorgenti OAuth di Twitch" + +#: authentik/sources/oauth/models.py:134 +msgid "Mailcow OAuth Source" +msgstr "Sorgente OAuth di Mailcow" + +#: authentik/sources/oauth/models.py:135 +msgid "Mailcow OAuth Sources" +msgstr "Sorgenti OAuth di Mailcow" + +#: authentik/sources/oauth/models.py:143 +msgid "Twitter OAuth Source" +msgstr "Sorgente OAuth di Twitter" + +#: authentik/sources/oauth/models.py:144 +msgid "Twitter OAuth Sources" +msgstr "Sorgenti OAuth di Twitter" + +#: authentik/sources/oauth/models.py:152 +msgid "Facebook OAuth Source" +msgstr "Sorgente OAuth di Facebook" + +#: authentik/sources/oauth/models.py:153 +msgid "Facebook OAuth Sources" +msgstr "Sorgenti OAuth di Facebook" + +#: authentik/sources/oauth/models.py:161 +msgid "Discord OAuth Source" +msgstr "Sorgente OAuth di Discord" + +#: authentik/sources/oauth/models.py:162 +msgid "Discord OAuth Sources" +msgstr "Sorgenti OAuth di Discord" + +#: authentik/sources/oauth/models.py:170 +msgid "Patreon OAuth Source" +msgstr "Sorgente OAuth di Patreon" + +#: authentik/sources/oauth/models.py:171 +msgid "Patreon OAuth Sources" +msgstr "Sorgenti OAuth di Patreon" + +#: authentik/sources/oauth/models.py:179 +msgid "Google OAuth Source" +msgstr "Sorgente OAuth di Google" + +#: authentik/sources/oauth/models.py:180 +msgid "Google OAuth Sources" +msgstr "Sorgenti OAuth di Google" + +#: authentik/sources/oauth/models.py:188 +msgid "Azure AD OAuth Source" +msgstr "Sorgente OAuth di Azure AD" + +#: authentik/sources/oauth/models.py:189 +msgid "Azure AD OAuth Sources" +msgstr "Sorgenti OAuth di Azure AD" + +#: authentik/sources/oauth/models.py:197 +msgid "OpenID OAuth Source" +msgstr "Sorgente OAuth di OpenID" + +#: authentik/sources/oauth/models.py:198 +msgid "OpenID OAuth Sources" +msgstr "Sorgenti OAuth di OpenID" + +#: authentik/sources/oauth/models.py:206 +msgid "Apple OAuth Source" +msgstr "Sorgente OAuth di Apple" + +#: authentik/sources/oauth/models.py:207 +msgid "Apple OAuth Sources" +msgstr "Sorgenti OAuth di Apple" + +#: authentik/sources/oauth/models.py:215 +msgid "Okta OAuth Source" +msgstr "Sorgente OAuth di Okta" + +#: authentik/sources/oauth/models.py:216 +msgid "Okta OAuth Sources" +msgstr "Sorgenti OAuth di Okta" + +#: authentik/sources/oauth/models.py:224 +msgid "Reddit OAuth Source" +msgstr "Sorgente OAuth di Reddit" + +#: authentik/sources/oauth/models.py:225 +msgid "Reddit OAuth Sources" +msgstr "Sorgenti OAuth di Reddit" + +#: authentik/sources/oauth/models.py:247 +msgid "User OAuth Source Connection" +msgstr "Connessione origine OAuth utente" + +#: authentik/sources/oauth/models.py:248 +msgid "User OAuth Source Connections" +msgstr "Connessioni origine OAuth utente" + +#: authentik/sources/oauth/views/callback.py:100 +#, python-format +msgid "Authentication failed: %(reason)s" +msgstr "Autenticazione fallita: %(reason)s" + +#: authentik/sources/plex/models.py:37 +msgid "Client identifier used to talk to Plex." +msgstr "Identificatore client utilizzato per comunicare con Plex." + +#: authentik/sources/plex/models.py:44 +msgid "" +"Which servers a user has to be a member of to be granted access. Empty list " +"allows every server." +msgstr "" +"Quali server un utente deve essere membro per ottenere l'accesso. Una lista " +"vuota consente ogni server." + +#: authentik/sources/plex/models.py:50 +msgid "Allow friends to authenticate, even if you don't share a server." +msgstr "" +"Consenti agli amici di autenticarsi, anche se non condividi un server." + +#: authentik/sources/plex/models.py:52 +msgid "Plex token used to check friends" +msgstr "Plex token utilizzato per controllare gli amici" + +#: authentik/sources/plex/models.py:95 +msgid "Plex Source" +msgstr "Sorgente Plex" + +#: authentik/sources/plex/models.py:96 +msgid "Plex Sources" +msgstr "Sorgenti Plex" + +#: authentik/sources/plex/models.py:112 +msgid "User Plex Source Connection" +msgstr "Connessione sorgente Plex utente" + +#: authentik/sources/plex/models.py:113 +msgid "User Plex Source Connections" +msgstr "Connessioni sorgente Plex utente" + +#: authentik/sources/saml/models.py:40 +msgid "Redirect Binding" +msgstr "Associazione reindirizzamento" + +#: authentik/sources/saml/models.py:41 +msgid "POST Binding" +msgstr "Associazione POST" + +#: authentik/sources/saml/models.py:42 +msgid "POST Binding with auto-confirmation" +msgstr "Associazione POST con auto-conferma" + +#: authentik/sources/saml/models.py:70 +msgid "Flow used before authentication." +msgstr "Flusso da usare prima dell'autenticazione." + +#: authentik/sources/saml/models.py:77 +msgid "Issuer" +msgstr "Emittente" + +#: authentik/sources/saml/models.py:78 +msgid "Also known as Entity ID. Defaults the Metadata URL." +msgstr "Anche conosciuto come ID entità. Predefinisce l'URL dei metadati." + +#: authentik/sources/saml/models.py:82 +msgid "SSO URL" +msgstr "URL SSO" + +#: authentik/sources/saml/models.py:83 +msgid "URL that the initial Login request is sent to." +msgstr "URL a cui viene inviata la richiesta di accesso iniziale." + +#: authentik/sources/saml/models.py:89 +msgid "SLO URL" +msgstr "URL SLO" + +#: authentik/sources/saml/models.py:90 +msgid "Optional URL if your IDP supports Single-Logout." +msgstr "URL opzionale se il tuo IDP supporta il Single-Logout." + +#: authentik/sources/saml/models.py:96 +msgid "" +"Allows authentication flows initiated by the IdP. This can be a security " +"risk, as no validation of the request ID is done." +msgstr "" +"Consente i flussi di autenticazione avviati dall'IdP. Questo può " +"rappresentare un rischio per la sicurezza, poiché non viene eseguita alcuna " +"convalida dell'ID richiesta." + +#: authentik/sources/saml/models.py:104 +msgid "" +"NameID Policy sent to the IdP. Can be unset, in which case no Policy is " +"sent." +msgstr "" +"Criterio NameID inviata all'IdP. Può essere disattivato, nel qual caso non " +"verrà inviata alcun criterio." + +#: authentik/sources/saml/models.py:115 +msgid "Delete temporary users after" +msgstr "Elimina gli utenti temporanei dopo" + +#: authentik/sources/saml/models.py:118 +msgid "" +"Time offset when temporary users should be deleted. This only applies if " +"your IDP uses the NameID Format 'transient', and the user doesn't log out " +"manually. (Format: hours=1;minutes=2;seconds=3)." +msgstr "" +"Offset di tempo quando gli utenti temporanei dovrebbero essere eliminati. " +"Questo si applica solo se il tuo IDP utilizza il formato NameID 'transient' " +"e l'utente non effettua il logout manualmente. (Formato: " +"hours=1;minutes=2;seconds=3)." + +#: authentik/sources/saml/models.py:142 +msgid "" +"Keypair used to sign outgoing Responses going to the Identity Provider." +msgstr "" +"Coppia di chiavi utilizzata per firmare le Risposte in uscita inviate " +"all'Identity Provider." + +#: authentik/sources/saml/models.py:226 +msgid "SAML Source" +msgstr "Sorgente SAML" + +#: authentik/sources/saml/models.py:227 +msgid "SAML Sources" +msgstr "Sorgenti SAML" + +#: authentik/sources/saml/models.py:242 +msgid "User SAML Source Connection" +msgstr "User SAML Source Connection" + +#: authentik/sources/saml/models.py:243 +msgid "User SAML Source Connections" +msgstr "User SAML Source Connections" + +#: authentik/stages/authenticator_duo/models.py:79 +msgid "Duo Authenticator Setup Stage" +msgstr "Fase di configurazione dell'autenticatore Duo" + +#: authentik/stages/authenticator_duo/models.py:80 +msgid "Duo Authenticator Setup Stages" +msgstr "Fasi di configurazione dell'autenticatore Duo" + +#: authentik/stages/authenticator_duo/models.py:103 +msgid "Duo Device" +msgstr "Dispositivo Duo" + +#: authentik/stages/authenticator_duo/models.py:104 +msgid "Duo Devices" +msgstr "Dispositivi Duo" + +#: authentik/stages/authenticator_sms/models.py:57 +msgid "" +"When enabled, the Phone number is only used during enrollment to verify the " +"users authenticity. Only a hash of the phone number is saved to ensure it is" +" not reused in the future." +msgstr "" +"Quando abilitato, il numero di telefono viene utilizzato solo durante " +"l'iscrizione per verificare l'autenticità degli utenti. Viene salvato solo " +"un hash del numero di telefono per garantire che non venga riutilizzato in " +"futuro." + +#: authentik/stages/authenticator_sms/models.py:68 +msgid "Optionally modify the payload being sent to custom providers." +msgstr "" +"Opzionalmente modifica il payload che viene inviato ai fornitori " +"personalizzati." + +#: authentik/stages/authenticator_sms/models.py:81 +#, python-format +msgid "Use this code to authenticate in authentik: %(token)s" +msgstr "Usa questo codice per accedere in authentik: %(token)s" + +#: authentik/stages/authenticator_sms/models.py:180 +msgid "SMS Authenticator Setup Stage" +msgstr "Fase di configurazione dell'autenticatore SMS" + +#: authentik/stages/authenticator_sms/models.py:181 +msgid "SMS Authenticator Setup Stages" +msgstr "Fasi di configurazione dell'autenticatore SMS" + +#: authentik/stages/authenticator_sms/models.py:226 +msgid "SMS Device" +msgstr "Dispositivo SMS" + +#: authentik/stages/authenticator_sms/models.py:227 +msgid "SMS Devices" +msgstr "Dispositivi SMS" + +#: authentik/stages/authenticator_sms/stage.py:57 +#: authentik/stages/authenticator_totp/stage.py:41 +#: authentik/stages/authenticator_totp/stage.py:44 +msgid "Code does not match" +msgstr "Il codice non corrisponde" + +#: authentik/stages/authenticator_sms/stage.py:73 +msgid "Invalid phone number" +msgstr "Numero di telefono non valido" + +#: authentik/stages/authenticator_static/models.py:52 +msgid "Static Authenticator Stage" +msgstr "Fase di configurazione dell'autenticatore statico" + +#: authentik/stages/authenticator_static/models.py:53 +msgid "Static Authenticator Stages" +msgstr "Fasi di configurazione dell'autenticatore statico" + +#: authentik/stages/authenticator_static/models.py:98 +msgid "Static Device" +msgstr "Dispositivo statico" + +#: authentik/stages/authenticator_static/models.py:99 +msgid "Static Devices" +msgstr "Dispositivi statici" + +#: authentik/stages/authenticator_static/models.py:129 +msgid "Static Token" +msgstr "Token statico" + +#: authentik/stages/authenticator_static/models.py:130 +msgid "Static Tokens" +msgstr "Token statici" + +#: authentik/stages/authenticator_totp/models.py:25 +msgid "6 digits, widely compatible" +msgstr "6 cifre, molto compatibile" + +#: authentik/stages/authenticator_totp/models.py:26 +msgid "8 digits, not compatible with apps like Google Authenticator" +msgstr "8 cifre, non compatibile con app quali Google Authenticator" + +#: authentik/stages/authenticator_totp/models.py:62 +msgid "TOTP Authenticator Setup Stage" +msgstr "Fase di configurazione dell'autenticatore TOTP" + +#: authentik/stages/authenticator_totp/models.py:63 +msgid "TOTP Authenticator Setup Stages" +msgstr "Fasi di configurazione dell'autenticatore TOTP" + +#: authentik/stages/authenticator_totp/models.py:244 +msgid "TOTP Device" +msgstr "Dispositivo TOTP" + +#: authentik/stages/authenticator_totp/models.py:245 +msgid "TOTP Devices" +msgstr "Dispositivi TOTP" + +#: authentik/stages/authenticator_validate/challenge.py:131 +msgid "Invalid Token" +msgstr "Token invalido" + +#: authentik/stages/authenticator_validate/models.py:18 +msgid "Static" +msgstr "Statico" + +#: authentik/stages/authenticator_validate/models.py:19 +msgid "TOTP" +msgstr "TOTP" + +#: authentik/stages/authenticator_validate/models.py:20 +msgid "WebAuthn" +msgstr "WebAuthn" + +#: authentik/stages/authenticator_validate/models.py:21 +msgid "Duo" +msgstr "Duo" + +#: authentik/stages/authenticator_validate/models.py:22 +msgid "SMS" +msgstr "SMS" + +#: authentik/stages/authenticator_validate/models.py:49 +msgid "" +"Stages used to configure Authenticator when user doesn't have any compatible" +" devices. After this configuration Stage passes, the user is not prompted " +"again." +msgstr "" +"Fasi utilizzate per configurare l'Autenticatore quando l'utente non dispone " +"di dispositivi compatibili. Dopo il superamento di questa configurazione, " +"all'utente non verrà più richiesto." + +#: authentik/stages/authenticator_validate/models.py:56 +msgid "Device classes which can be used to authenticate" +msgstr "" +"Classi di dispositivi che possono essere utilizzate per l'autenticazione" + +#: authentik/stages/authenticator_validate/models.py:64 +msgid "" +"If any of the user's device has been used within this threshold, this stage " +"will be skipped" +msgstr "" +"Se uno qualsiasi dei dispositivi dell'utente è stato utilizzato entro questa" +" soglia, questa fase verrà saltata." + +#: authentik/stages/authenticator_validate/models.py:70 +msgid "Enforce user verification for WebAuthn devices." +msgstr "Rafforza la verifica utente per dispositivi WebAuthn." + +#: authentik/stages/authenticator_validate/models.py:92 +msgid "Authenticator Validation Stage" +msgstr "Fase di convalida dell'autenticatore" + +#: authentik/stages/authenticator_validate/models.py:93 +msgid "Authenticator Validation Stages" +msgstr "Fasi di convalida dell'autenticatore" + +#: authentik/stages/authenticator_webauthn/models.py:112 +msgid "WebAuthn Authenticator Setup Stage" +msgstr "Fase di configurazione dell'autenticatore WebAuthn" + +#: authentik/stages/authenticator_webauthn/models.py:113 +msgid "WebAuthn Authenticator Setup Stages" +msgstr "Fasi di configurazione dell'autenticatore WebAuthn" + +#: authentik/stages/authenticator_webauthn/models.py:151 +msgid "WebAuthn Device" +msgstr "Dispositivo WebAuthn" + +#: authentik/stages/authenticator_webauthn/models.py:152 +msgid "WebAuthn Devices" +msgstr "Dispositivi WebAuthn" + +#: authentik/stages/captcha/models.py:14 +msgid "Public key, acquired your captcha Provider." +msgstr "Chiave pubblica, acquisito il tuo provider di captcha." + +#: authentik/stages/captcha/models.py:15 +msgid "Private key, acquired your captcha Provider." +msgstr "Chiave privata, acquisito il tuo fornitore di captcha." + +#: authentik/stages/captcha/models.py:37 +msgid "Captcha Stage" +msgstr "Fase Captcha" + +#: authentik/stages/captcha/models.py:38 +msgid "Captcha Stages" +msgstr "Fasi Captcha" + +#: authentik/stages/consent/models.py:30 +msgid "" +"Offset after which consent expires. (Format: hours=1;minutes=2;seconds=3)." +msgstr "" +"Compensazione dopo la quale il consenso scade. (Formato: " +"ore=1;minuti=2;secondi=3)." + +#: authentik/stages/consent/models.py:50 +msgid "Consent Stage" +msgstr "Fase consenso" + +#: authentik/stages/consent/models.py:51 +msgid "Consent Stages" +msgstr "Fasi consenso" + +#: authentik/stages/consent/models.py:72 +msgid "User Consent" +msgstr "Consenso utente" + +#: authentik/stages/consent/models.py:73 +msgid "User Consents" +msgstr "Consensi utente" + +#: authentik/stages/deny/models.py:32 +msgid "Deny Stage" +msgstr "Fase di negazione" + +#: authentik/stages/deny/models.py:33 +msgid "Deny Stages" +msgstr "Fasi di negazione" + +#: authentik/stages/dummy/models.py:34 +msgid "Dummy Stage" +msgstr "Fase fittizia" + +#: authentik/stages/dummy/models.py:35 +msgid "Dummy Stages" +msgstr "Fasi fittizie" + +#: authentik/stages/email/models.py:26 +msgid "Password Reset" +msgstr "Ripristino password" + +#: authentik/stages/email/models.py:30 +msgid "Account Confirmation" +msgstr "Conferma dell'account" + +#: authentik/stages/email/models.py:59 +msgid "" +"When enabled, global Email connection settings will be used and connection " +"settings below will be ignored." +msgstr "" +"Se abilitato, verranno utilizzate le impostazioni di connessione e-mail " +"globali e le impostazioni di connessione riportate di seguito verranno " +"ignorate." + +#: authentik/stages/email/models.py:74 +msgid "Activate users upon completion of stage." +msgstr "Attiva gli utenti al completamento della fase." + +#: authentik/stages/email/models.py:78 +msgid "Time in minutes the token sent is valid." +msgstr "Tempo in minuti in cui il token inviato è valido." + +#: authentik/stages/email/models.py:132 +msgid "Email Stage" +msgstr "Fase email" + +#: authentik/stages/email/models.py:133 +msgid "Email Stages" +msgstr "Fasi Email" + +#: authentik/stages/email/stage.py:126 +msgid "Exception occurred while rendering E-mail template" +msgstr "" +"Eccezione verificatasi durante la visualizzazione del modello di posta " +"elettronica" + +#: authentik/stages/email/stage.py:140 +msgid "Successfully verified Email." +msgstr "Email verificato con successo." + +#: authentik/stages/email/stage.py:147 authentik/stages/email/stage.py:173 +msgid "No pending user." +msgstr "Nessun utente in attesa." + +#: authentik/stages/email/stage.py:163 +msgid "Email sent." +msgstr "Email inviata." + +#: authentik/stages/email/stage.py:176 +msgid "Email Successfully sent." +msgstr "Email inviata con successo." + +#: authentik/stages/email/templates/email/account_confirmation.html:10 +msgid "Welcome!" +msgstr "Benvenuto!" + +#: authentik/stages/email/templates/email/account_confirmation.html:19 +msgid "" +"We're excited to have you get started. First, you need to confirm your " +"account. Just press the button below." +msgstr "" +"Siamo entusiasti che tu inizi. Per prima cosa devi confermare il tuo " +"account. Basta premere il pulsante qui sotto." + +#: authentik/stages/email/templates/email/account_confirmation.html:24 +msgid "Confirm Account" +msgstr "Conferma Account" + +#: authentik/stages/email/templates/email/account_confirmation.html:36 +#, python-format +msgid "" +"\n" +" If that doesn't work, copy and paste the following link in your browser: %(url)s\n" +" " +msgstr "" +"\n" +" Se questo non funziona, copia ed incolla il seguente link nel tuo browser: %(url)s\n" +" " + +#: authentik/stages/email/templates/email/event_notification.html:46 +#, python-format +msgid "" +"\n" +" This email was sent from the notification transport %(name)s.\n" +" " +msgstr "" +"\n" +" Questa email è stata inviata dal trasporto di notifica %(name)s." + +#: authentik/stages/email/templates/email/password_reset.html:10 +#, python-format +msgid "" +"\n" +" Hi %(username)s,\n" +" " +msgstr "" +"\n" +" Ciao %(username)s,\n" +" " + +#: authentik/stages/email/templates/email/password_reset.html:21 +msgid "" +"\n" +" You recently requested to change your password for your authentik account. Use the button below to set a new password.\n" +" " +msgstr "" +"\n" +" Hai recentemente richiesto di cambiare la tua password per il tuo account authentik. Utilizza il pulsante qui sotto per impostare una nuova password." + +#: authentik/stages/email/templates/email/password_reset.html:39 +#, python-format +msgid "" +"\n" +" If you did not request a password change, please ignore this Email. The link above is valid for %(expires)s.\n" +" " +msgstr "" +"\n" +" Se non hai richiesto una modifica della password, ignora questa email. Il link sopra è valido \n" +"per %(expires)s." + +#: authentik/stages/email/templates/email/setup.html:9 +msgid "authentik Test-Email" +msgstr "e-mail di prova di authentik" + +#: authentik/stages/email/templates/email/setup.html:17 +msgid "" +"\n" +" This is a test email to inform you, that you've successfully configured authentik emails.\n" +" " +msgstr "" +"\n" +" Questa è un'e-mail di prova per informarti che hai configurato correttamente le e-mail di authentik.\n" +" " + +#: authentik/stages/identification/api.py:20 +msgid "When no user fields are selected, at least one source must be selected" +msgstr "" +"Quando non viene selezionato alcun campo utente, è necessario selezionare " +"almeno una sorgente" + +#: authentik/stages/identification/models.py:29 +msgid "" +"Fields of the user object to match against. (Hold shift to select multiple " +"options)" +msgstr "" +"Campi dell'oggetto utente da confrontare. (Mantieni premuto il tasto Maiusc " +"per selezionare più opzioni)" + +#: authentik/stages/identification/models.py:47 +msgid "When enabled, user fields are matched regardless of their casing." +msgstr "" +"Quando abilitato, i campi utente vengono abbinati indipendentemente dalla " +"loro capitalizzazione." + +#: authentik/stages/identification/models.py:52 +msgid "" +"When a valid username/email has been entered, and this option is enabled, " +"the user's username and avatar will be shown. Otherwise, the text that the " +"user entered will be shown" +msgstr "" +"Quando viene inserito un nome utente/email valido e questa opzione è " +"abilitata, verranno mostrati il nome utente e l'avatar dell'utente. " +"Altrimenti, verrà mostrato il testo inserito dall'utente." + +#: authentik/stages/identification/models.py:60 +msgid "" +"When enabled, the stage will succeed and continue even when incorrect user " +"info is entered." +msgstr "" +"Quando abilitato, la fase avrà successo e continuerà anche quando vengono " +"inserite informazioni utente errate." + +#: authentik/stages/identification/models.py:72 +msgid "Optional enrollment flow, which is linked at the bottom of the page." +msgstr "Flusso di iscrizione opzionale, che è collegato in fondo alla pagina." + +#: authentik/stages/identification/models.py:81 +msgid "Optional recovery flow, which is linked at the bottom of the page." +msgstr "" +"Flusso di recupero opzionale, mostrato nella parte sottostante della pagina." + +#: authentik/stages/identification/models.py:90 +msgid "Optional passwordless flow, which is linked at the bottom of the page." +msgstr "" +"Flusso passwordless opzionale, mostrato nella parte sottostante della " +"pagina." + +#: authentik/stages/identification/models.py:94 +msgid "Specify which sources should be shown." +msgstr "Specifica quali sorgenti devono essere mostrati." + +#: authentik/stages/identification/models.py:115 +msgid "Identification Stage" +msgstr "Fase di identificazione" + +#: authentik/stages/identification/models.py:116 +msgid "Identification Stages" +msgstr "Fasi di identificazione" + +#: authentik/stages/identification/stage.py:188 +msgid "Log in" +msgstr "Accedi" + +#: authentik/stages/identification/stage.py:189 +msgid "Continue" +msgstr "Continua" + +#: authentik/stages/invitation/models.py:21 +msgid "" +"If this flag is set, this Stage will jump to the next Stage when no " +"Invitation is given. By default this Stage will cancel the Flow when no " +"invitation is given." +msgstr "" +"Se questo flag è impostato, questa fase passerà alla fase successiva quando " +"non viene dato alcun invito. Per impostazione predefinita, questa fase " +"annullerà il flusso quando non viene fornito alcun invito." + +#: authentik/stages/invitation/models.py:44 +msgid "Invitation Stage" +msgstr "Fase di invito" + +#: authentik/stages/invitation/models.py:45 +msgid "Invitation Stages" +msgstr "Fasi di invito" + +#: authentik/stages/invitation/models.py:60 +msgid "When set, only the configured flow can use this invitation." +msgstr "Quando impostato, solo il flusso configurato può usare questo invito." + +#: authentik/stages/invitation/models.py:64 +msgid "When enabled, the invitation will be deleted after usage." +msgstr "Se abilitato, l'invito verrà eliminato dopo l'utilizzo." + +#: authentik/stages/invitation/models.py:71 +msgid "Optional fixed data to enforce on user enrollment." +msgstr "Dati fissi facoltativi da applicare alla registrazione dell'utente." + +#: authentik/stages/invitation/models.py:84 +msgid "Invitation" +msgstr "Invito" + +#: authentik/stages/invitation/models.py:85 +msgid "Invitations" +msgstr "Inviti" + +#: authentik/stages/invitation/stage.py:62 +msgid "Invalid invite/invite not found" +msgstr "Invito non disponibile" + +#: authentik/stages/password/models.py:20 +msgid "User database + standard password" +msgstr "Database utente + password standard" + +#: authentik/stages/password/models.py:24 +msgid "User database + app passwords" +msgstr "Database utente + password app" + +#: authentik/stages/password/models.py:28 +msgid "User database + LDAP password" +msgstr "Database utenti + password LDAP" + +#: authentik/stages/password/models.py:38 +msgid "Selection of backends to test the password against." +msgstr "Selezione di backend su cui testare la password." + +#: authentik/stages/password/models.py:43 +msgid "" +"How many attempts a user has before the flow is canceled. To lock the user " +"out, use a reputation policy and a user_write stage." +msgstr "" +"Quanti tentativi ha un utente prima che il flusso venga annullato. Per " +"escludere l'utente, utilizzare un criterio di reputazione e una fase " +"user_write." + +#: authentik/stages/password/models.py:75 +msgid "Password Stage" +msgstr "Fase della password" + +#: authentik/stages/password/models.py:76 +msgid "Password Stages" +msgstr "Fasi della password" + +#: authentik/stages/password/stage.py:124 +msgid "Invalid password" +msgstr "Password invalida" + +#: authentik/stages/prompt/models.py:43 +msgid "Text: Simple Text input" +msgstr "Testo: Input di testo semplice" + +#: authentik/stages/prompt/models.py:45 +msgid "Text area: Multiline Text Input." +msgstr "Area di testo: Input di testo multilinea." + +#: authentik/stages/prompt/models.py:48 +msgid "Text (read-only): Simple Text input, but cannot be edited." +msgstr "Testo (sola lettura): Input di testo semplice, ma non modificabile." + +#: authentik/stages/prompt/models.py:52 +msgid "Text area (read-only): Multiline Text input, but cannot be edited." +msgstr "" +"Area di testo (sola lettura): Input di testo su più righe, ma non può essere" +" modificato." + +#: authentik/stages/prompt/models.py:58 +msgid "" +"Username: Same as Text input, but checks for and prevents duplicate " +"usernames." +msgstr "" +"Nome utente: Uguale all'input di testo, ma controlla e impedisce i nomi " +"utente duplicati." + +#: authentik/stages/prompt/models.py:60 +msgid "Email: Text field with Email type." +msgstr "E-mail: Campo di testo con il tipo di e-mail." + +#: authentik/stages/prompt/models.py:64 +msgid "" +"Password: Masked input, multiple inputs of this type on the same prompt need" +" to be identical." +msgstr "" +"Password: Input mascherato, più input di questo tipo sullo stesso prompt " +"devono essere identici." + +#: authentik/stages/prompt/models.py:71 +msgid "Fixed choice field rendered as a group of radio buttons." +msgstr "Campo a scelta fissa mostrato come gruppo di pulsanti radio." + +#: authentik/stages/prompt/models.py:73 +msgid "Fixed choice field rendered as a dropdown." +msgstr "Campo a scelta fissa mostrato come menu a discesa." + +#: authentik/stages/prompt/models.py:80 +msgid "" +"File: File upload for arbitrary files. File content will be available in " +"flow context as data-URI" +msgstr "" +"File: Caricamento di file per file arbitrari. Il contenuto del file sarà " +"disponibile nel contesto del flusso come dati-URI" + +#: authentik/stages/prompt/models.py:85 +msgid "Separator: Static Separator Line" +msgstr "Separatore: Linea di separazione statica" + +#: authentik/stages/prompt/models.py:86 +msgid "Hidden: Hidden field, can be used to insert data into form." +msgstr "" +"Nascosto: Campo nascosto, può essere utilizzato per inserire dati nel " +"modulo." + +#: authentik/stages/prompt/models.py:87 +msgid "Static: Static value, displayed as-is." +msgstr "Statico: Valore statico, visualizzato così com'è." + +#: authentik/stages/prompt/models.py:89 +msgid "authentik: Selection of locales authentik supports" +msgstr "" +"authentik: Selezione delle impostazioni locali supportate da authentik" + +#: authentik/stages/prompt/models.py:116 +msgid "Name of the form field, also used to store the value" +msgstr "Nome del campo del modulo, utilizzato anche per memorizzare il valore" + +#: authentik/stages/prompt/models.py:124 +msgid "" +"Optionally provide a short hint that describes the expected input value. " +"When creating a fixed choice field, enable interpreting as expression and " +"return a list to return multiple choices." +msgstr "" +"Opzionalmente fornire un breve suggerimento che descrive il valore di input " +"previsto. Quando si crea un campo di scelta fissa, abilitare " +"l'interpretazione come espressione e restituire una lista per restituire " +"scelte multiple." + +#: authentik/stages/prompt/models.py:132 +msgid "" +"Optionally pre-fill the input with an initial value. When creating a fixed " +"choice field, enable interpreting as expression and return a list to return " +"multiple default choices." +msgstr "" +"Opzionalmente precompila l'input con un valore iniziale. Quando si crea un " +"campo di scelta fissa, abilita l'interpretazione come espressione e " +"restituisci una lista per restituire più scelte predefinite." + +#: authentik/stages/prompt/models.py:321 +msgid "Prompt" +msgstr "Richiesta" + +#: authentik/stages/prompt/models.py:322 +msgid "Prompts" +msgstr "Richieste" + +#: authentik/stages/prompt/models.py:349 +msgid "Prompt Stage" +msgstr "Fase Richiesta" + +#: authentik/stages/prompt/models.py:350 +msgid "Prompt Stages" +msgstr "Fasi Richiesta" + +#: authentik/stages/prompt/stage.py:108 +msgid "Passwords don't match." +msgstr "Le password non corrispondono." + +#: authentik/stages/user_delete/models.py:31 +msgid "User Delete Stage" +msgstr "Fase di cancellazione dell'utente" + +#: authentik/stages/user_delete/models.py:32 +msgid "User Delete Stages" +msgstr "Fasi di cancellazione dell'utente" + +#: authentik/stages/user_delete/stage.py:18 +msgid "No Pending User." +msgstr "Nessun utente in attesa." + +#: authentik/stages/user_login/models.py:19 +msgid "" +"Determines how long a session lasts. Default of 0 means that the sessions " +"lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)" +msgstr "" +"Determina quanto può durare una sessione. Se impostato a 0, la sessione " +"durerà fino alla chiusura del browser. (Formato: " +"hours=-1;minutes=-2;seconds=-3)" + +#: authentik/stages/user_login/models.py:25 +msgid "Terminate all other sessions of the user logging in." +msgstr "Termina tutte le altre sessioni dell'utente che accede." + +#: authentik/stages/user_login/models.py:31 +msgid "" +"Offset the session will be extended by when the user picks the remember me " +"option. Default of 0 means that the remember me option will not be shown. " +"(Format: hours=-1;minutes=-2;seconds=-3)" +msgstr "" +"Offset la sessione verrà estesa quando l'utente seleziona l'opzione " +"ricordami. Il valore predefinito di 0 significa che l'opzione ricordami non " +"verrà mostrata. (Formato: hours=-1;minutes=-2;seconds=-3)" + +#: authentik/stages/user_login/models.py:54 +msgid "User Login Stage" +msgstr "Fase di accesso utente" + +#: authentik/stages/user_login/models.py:55 +msgid "User Login Stages" +msgstr "Fasi di accesso utente" + +#: authentik/stages/user_login/stage.py:57 +msgid "No Pending user to login." +msgstr "Nessun utente in attesa di accesso." + +#: authentik/stages/user_login/stage.py:90 +msgid "Successfully logged in!" +msgstr "Accesso effettuato!" + +#: authentik/stages/user_logout/models.py:30 +msgid "User Logout Stage" +msgstr "Fase di disconnessione dell'utente" + +#: authentik/stages/user_logout/models.py:31 +msgid "User Logout Stages" +msgstr "Fasi di disconnessione dell'utente" + +#: authentik/stages/user_write/models.py:31 +msgid "When set, newly created users are inactive and cannot login." +msgstr "Se specificato, i nuovi utenti sono inattivi e non possono accedere." + +#: authentik/stages/user_write/models.py:39 +msgid "Optionally add newly created users to this group." +msgstr "Opzionalmente, aggiungi gli utenti appena creati a questo gruppo." + +#: authentik/stages/user_write/models.py:68 +msgid "User Write Stage" +msgstr "Fase di scrittura dell'utente" + +#: authentik/stages/user_write/models.py:69 +msgid "User Write Stages" +msgstr "Fasi di scrittura dell'utente" + +#: authentik/stages/user_write/stage.py:141 +msgid "No Pending data." +msgstr "Nessun dato in attesa." + +#: authentik/stages/user_write/stage.py:147 +msgid "No user found and can't create new user." +msgstr "Nessun utente trovato e impossibile creare un nuovo utente." + +#: authentik/stages/user_write/stage.py:164 +#: authentik/stages/user_write/stage.py:178 +msgid "Failed to update user. Please try again later." +msgstr "Impossibile aggiornare l'utente. Per favore riprova più tardi." + +#: authentik/tenants/models.py:23 +msgid "" +"Domain that activates this tenant. Can be a superset, i.e. `a.b` for `aa.b` " +"and `ba.b`" +msgstr "" +"Dominio che attiva questo tenant. Può essere un superset, ad esempio `a.b` " +"per `aa.b` e `ba.b`" + +#: authentik/tenants/models.py:58 +msgid "" +"Events will be deleted after this duration.(Format: " +"weeks=3;days=2;hours=3,seconds=2)." +msgstr "" +"Gli eventi saranno cancellati dopo questa durata. (Formato: " +"weeks=3;days=2;hours=3,seconds=2)." + +#: authentik/tenants/models.py:67 +msgid "Web Certificate used by the authentik Core webserver." +msgstr "Certificato Web utilizzato dal server Web authentik Core." + +#: authentik/tenants/models.py:93 +msgid "Tenant" +msgstr "Tenant" + +#: authentik/tenants/models.py:94 +msgid "Tenants" +msgstr "Tenants" From fade781d9665103ab3913d05665751a9c255268c Mon Sep 17 00:00:00 2001 From: "authentik-automation[bot]" <135050075+authentik-automation[bot]@users.noreply.github.com> Date: Wed, 27 Dec 2023 17:58:12 +0100 Subject: [PATCH 02/31] core: compile backend translations (#8000) Signed-off-by: GitHub Co-authored-by: authentik-automation[bot] --- locale/it/LC_MESSAGES/django.mo | Bin 0 -> 65637 bytes locale/zh_CN/LC_MESSAGES/django.mo | Bin 56897 -> 59051 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 locale/it/LC_MESSAGES/django.mo diff --git a/locale/it/LC_MESSAGES/django.mo b/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..10aefe661d97607fa3c15d902632ac4b8df19a31 GIT binary patch literal 65637 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 delta 12222 zcmZwN2YgRw-^cNjCJ{+Qh}cBzJ!0=Ys!FY*h`oZEvFYDz)oKY*>o#jt&A(BzRMo6e zRFxJjMQN2P)p>uu|Lf;@yq?!{UiYu>Yn^kh^SiEd5_#S0KMy{*H`w=WOvpTsqxcJ+ zmkX0KdfqL{C-bS*^ZJzXye^o8lkhl}!)B$O6LA^!9XJEqmhrqeyn*d8IKlIVV<&8l z7qBoEE9-eRJz(_*;pMnU>N?08So)?$6)Rng}t#O4#Qad0*l}+WbR&u^6tER zsCqdJ#Rga#o8V}if#tZr7goXZvd~Zsn_^3h!DW~U{TPWyP!m0e>F_>w!N0H*CRX%3 zC2cQe#;d67{)TxmT_rc+Qm72o!#v#I>qbF0oQS&NJk-qBp)Rxsb)mDU3*AO#D5A3G zu^L_sYGQS;9wy>jxEytU(JC$@wNUqIjyk_P`gEgy)-et>fp;-CuEIq81m|FURks9w zOi%qF#^M>&jc#HK{1d~mX*D;#Eh>XOu`v$D!nmgz`46G+Jq^0xZPbOHpe7Q%pXZgOu!e@T z_%+tW?~!YGg=%|V0`|lTI3Ek)=cw_IP^tbKHNh#|Js19k5tyBe>B$S=Ygh*7;WX5P z#rs$=&8#Hy#(33GDeaHS!~|3(=3{nTk2&x#w!v$tC#qE6U9chQhOMmL8H1_!M=j|f zjKf)|3Hmlr&+}3gU~H9|vG4&Ox2`9_mR}S$zxUqrMOI`d-71 z_y9X&vxaU-HX`Tyy!{mTc6i58H~s^)HrX0^9vj$u8AEXjX2I#G46Q&t!A?wrpP({w z3r;c}uY<{(wa= z!%JKgt6*20iN)|f>H%^z@dBH?73%eChg#Bp7{UELAB9MqhIud*3*Zjq&GRm!GL-pc zw-gO9o_aq_#u?ZXgZO%BV!crrn~i$%`KY&G9cqv5LQVWf^lA5JYUXCt5S7~YRv(CA z)F)Yey7ezb?ecAy70;S?kT=&0dPNKCc{Pyz>FvWrwKsQfO=r}7`ZQ;l)?^$F9WVuz z%KOMed-eF5EW>xOFP3TPcK;&O6YM}uU+M&J!p`+Zaj^`k2iVo;kc4tZFwAhO@QWYpf+i`q-Uue#SPFX{nnqc&X| z)WlxL^f<;xK^LBenqjI9Sc#dbZ^1Em1czchw)hs@iJC}KTQ~7RsPR**z6d)}-;8?w zqT7*O?2qkHU!!pFb)Zn5LQiBrcndKr-bSsZMk^E5&8C>0dM7N5Bh6*je-xGSOQLpn6E*Py$OHSl;uMtP%BT}xLZvDZHIZag%4VQ4w9x8nFcbCd7>mcuZ&8`} z6?L6(9$(jq$H*Y=gS?queRkwNZPRxsXaY^imnP5|Sw?RNmc}Ef8$ChYD6+F#`*?d~rzC-n!I3!}Qb zCohKD-IXvKc0fI0GU@@QV>B*7ZLSUGUTZ&rTI$PK3^Vi~|FtPpqo9u)b-k7820K-{V)=5Zh`|)7aDK%+2%^rp4g6W;3=$+P5Zix&Ou#wE$YEO!Gh>J zYXhF3);Ox4n@9oF9w>`Cp&3SEA}WEpoE#AT^_zUL6Vgud8UPi5PJJfl7un4}1%IGF6grA|7 z?k8M~|6o?V|BD7$iZBQD-Kf-Gz$kox>G5CGh0+gpYgYj?Q15`nu|KN+JVFEZS%)jbTQ9?z?w8y3PuEQy(LI_foA zYHmY)KaOE3yo#kU{YY1@iP}4_qn395Nb;Yb!c7|TVfZN45lf&ZHU%r-dDOUw(JoV^ zP#GzQTB6#R5u0HQc0n!8P-~xTrdt16)Kcv6QP8IO3bp2sts`cPtCvO%Y=XLAAJmOT zq2BN5sPoU5KchBhy0LCzrBE5Fj*YPel6`Lx>H&Sx<6Me6VM!W#U?R@3`Y)&($MIER z|9GV_8!pF+xEr+;4^Vp{l#KGmc~Pj$jYhpan^76wh05d=jMn?_jdwT5fHZh{t)757 zu`co{@S5Nz+==Cb_$_yW`<-y{M9b&+}~S7K?Ap82%f|KJmFW^fqH{!?oThvQ5P;a-R0ZY%s0r*xW#Ah6a!|<4RjOiT48x(QH6MdXI0LmbkFh(ZdB^SkzNm?h zK=r3$46ZhJp6`^{<6yX0RdY@?gb48|CojarIT=7BlnUpKfygS>x{*U`?ElY$NYW)Pr=K>+FvisgFgSKMR%NR38Q1c#XLY^#wbKP4FTv$Ncl$g$|n+ z%$w$KSdVd`sqT7>Q4?rm_CkGYcA70r6sg7)Uf3*@b^_L569j`gofp%@*FP-`^AoQ%pu zDrUmf=5B09{S@j63;)Mi-mGIb!(jS5pf+J=(}&t)OC|UBKCq7Mn1lKSY=pmHF08!N zy=JeXZkUWp=>&5wDl=^Nnl zB5IR#McuHEIRau!{s?Q}dF+5OtK7r~pfa%l^#GrvCUD-og?fNLR{2~Z?0uKQ zSkw(lVtIT8wJ9f~ZnzZ-;3@2nzhZmrvfABv59)?Lp!U*Fm>&Pd1Wdoi{S>T?#i@7q zQP5hwV=lwM8kzg8{e*c1voiiCGjy%nGr6$}?UivD4#7%z8(+lub#7^rP}d)7`o>de zLBmXZ1+QW?Ed2rhSipYR4`bK6%{U%QP+x+Y$Z@QQ-(gYA{-L`;JyZsoTfG}*p*|3` z6mPnApSQpoR-;n4%XN4M%+Ia;YYeCVIyS?**Z`|;aE?b!=ri+M)C3-zX*arh4zmQN z)%#yFP~err%$(31wbs3GAWpwJRF&K*lP6MgE~Zv#%4Uzs;iCp<)@{;3(f%}q4Q%xhLK8>2pCiRMVWPCW&cnPJ=A z-a50L{HLd3)DHKWOhv8feAMp!1~Xvhoz6n2{z|CbJ`VMyJFz0(#B!MHBlinNb8`Y# zr+q6<#`~Cx$-CORUpyjryVSjE_Cb9S$6zGR!@{`S`j44cP#L^${$+-zw8)vsSB9Q4 zd)%Ae6{}L8iCUzi7>$=P4)3B~+=#ude>^fdF9o%`?wWt2&WqmXehlU@i=Z|~0&2}# z>2F&qw5K5!yP~E#95sPSW~#NXGk2JWFbCt#pvK=t{ZRM^mGh$eU5?wL)@Ul~ehX0d zS+?K4tsAUkw{;vePhk-TUPj#@G-sQOF%#`;%soB| zn%Qad8Y*=UFbabXxC=+4QeO-MGdDMwyUio0>zzkU_$GG8-%-1+<3aZUdDrx~{ZfY)X9|Y9ilbE&K%wV42Tc`>Uvlbi;TYf^nFF`gU(c-R~&Ia)0jz zg$ei+b>lHdT#DwR1}-vpqHcW7yoQCT|Afjw=A*8^9x8Lqu@DYHZO#R#J+TdS-VqG^ zZRI`%osj;RvkZn%Z;A2P)*Oji;|1pXs3+QjY4C`73iTRZ!0PB7cbTezy3aV&gDpKy z{vT4I=6S8(>;ySs9yQF?-) z(tZW?0Iy$ie=J&rdR?Dl6|C~LzNoDKPzp_GxP$7baM{gxASP13gf+3!7597ba8ybc zm>;3`&_&dq`3G}hj&IzOR>HE>n_+gGfO&8c7Ucfk9tt|)I_f?B2jemOw=RWMkp~PM z<@m3jPDfow;J=w);4QI1zhe!eB*91Xe~xJCX&LwI$U?zalt#T8QAAEU6Yvsk&yMdY zyiC0%ro|MZE-~H)yog(@+@AIVb_2FS;BRSP(3XX^+57~{Mhi?()O>l7s08t^|XEwLz~|J zuGTgao7(uuAo5?H20s6R@3qFvB5Dx9s&E`&@I`{}RN(J#U*kW-QQF?M3sLo+P!4&n zo{6X2Lj8)hU1Q8%;s@d~ZP$oCTK{7QI?LWdNaL0C9rytHg(t zw^@5S2FFp(XcwMK-=D-DB9gW<^i8p`k7*lYWqsH}iAPp%PI)46j(S0@|061yiT8=d zH0o3OHlZUE^-aWGLdPzL_bK(;#4VyUv6Ilz2>(NzB9e*Mh#|BuL>(Wi9e*Oa5#xf$ zzkbMEAbQZb4#Rkwlaz~6E<@a>97b%Vyq?fej4`WS(W_2hE@Cb*hPJ5~MSmL%CidI7 z(UfB;4<%MuTj2W>M`fBd9Ar>!Vl$y*J+35{5D%;^6o(T}i5%RhG7cql_=zCe76)qo z`=1KdA57mjlm`>(==K$$;8!OdpGl5XqCDkxxY63)pgfy$4CC@reuwf7LO(e#6FM?b z*Kr+RV4RLply?&?txs+5sh?P*?|(n*n4%tzwN_t)uM;r3df2`vGe!$pgM=c6pS^Z=n|1@NzVYM|5#QMbd#7FeiCUlIq{`0tsdNZppr`*NL ze`5kMmbM~9G0H1(BJRYWa3tQufANiH-~S{UbbN$MiCG(sl|HiR#vV3A@t%n$`2!c}2<4U$n9R-LV6*)3|{FA^0PHO53l*bT`D?OIr`h zh3VHZhx!6n4E$+h7WLLdR_kv_pZ=ktn;fxm;woe65cky8oWfNaZ(x6-1?Byy;|kG$ zm}hmh^(Jl+|Ijwg+RI`#ZaSLw?1YY&iD9%?2-Nrp(I0K)c*-{@FVoa2F=&NdXq*jr zfMHh7VSTDsAU8H zz%K`b>Eoew3 zbUY#YP<{);iDASd>!TPra#R1!+FD!NTAV|?L`0Cg@90k?8rrx*G9v!}Is9=6`+`#H zm5cE|E_*RNC2ft_DKFJr=+9NFN*e#v2Bky%XBzi=!9U>TIcfY+tsbXIiEN+8U#@*@ zRLYh{u_@hq=kibO{bQJa+`ynTu|0YYPwL*&Yn9wJIjMWRtNAw!8x)jMcSPeT>uvo? z>*n!2{O^s(8?^Gy$Vh*g$r(faOWyuBEWGQmHjmm*VkAB^{3KR75XW$>}A s{^7?Sg!(6(?i>`NyQSngTf|@JY>goQtS|aR_^W+0ImDmwyM-bD1Hq)$ From e171e5082104113ba391f16d395b9ff1efe4bbc1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Dec 2023 14:20:36 +0100 Subject: [PATCH 03/31] website: bump react-tooltip from 5.25.0 to 5.25.1 in /website (#8007) Bumps [react-tooltip](https://github.com/ReactTooltip/react-tooltip) from 5.25.0 to 5.25.1. - [Release notes](https://github.com/ReactTooltip/react-tooltip/releases) - [Changelog](https://github.com/ReactTooltip/react-tooltip/blob/master/CHANGELOG.md) - [Commits](https://github.com/ReactTooltip/react-tooltip/compare/v5.25.0...v5.25.1) --- updated-dependencies: - dependency-name: react-tooltip dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- website/package-lock.json | 8 ++++---- website/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/website/package-lock.json b/website/package-lock.json index 5a0562f33..097357958 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -26,7 +26,7 @@ "react-dom": "^18.2.0", "react-feather": "^2.0.10", "react-toggle": "^4.1.3", - "react-tooltip": "^5.25.0", + "react-tooltip": "^5.25.1", "remark-github": "^12.0.0" }, "devDependencies": { @@ -14365,9 +14365,9 @@ } }, "node_modules/react-tooltip": { - "version": "5.25.0", - "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.25.0.tgz", - "integrity": "sha512-/eGhmlwbHlJrVoUe75fb58rJfAy9aZnTvQAK9ZUPM0n9mmBGpEk13vDPiQVCeUuax+fBej+7JPsUXlhzaySc7w==", + "version": "5.25.1", + "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.25.1.tgz", + "integrity": "sha512-GDD0hrfbwGr2C6zEzVzzDzXSKeHM55cRFZQv2/EFmiFKVxWZk8hzOO5FNcwCpPyqVxQKUtYckReU5bXMd63alQ==", "dependencies": { "@floating-ui/dom": "^1.0.0", "classnames": "^2.3.0" diff --git a/website/package.json b/website/package.json index 418f9e87f..1b087d394 100644 --- a/website/package.json +++ b/website/package.json @@ -32,7 +32,7 @@ "react-dom": "^18.2.0", "react-feather": "^2.0.10", "react-toggle": "^4.1.3", - "react-tooltip": "^5.25.0", + "react-tooltip": "^5.25.1", "react": "^18.2.0", "remark-github": "^12.0.0" }, From 4b115e18fb062b39deef345e1a6387203541fb49 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Dec 2023 14:20:47 +0100 Subject: [PATCH 04/31] core: bump github.com/prometheus/client_golang from 1.17.0 to 1.18.0 (#8006) Bumps [github.com/prometheus/client_golang](https://github.com/prometheus/client_golang) from 1.17.0 to 1.18.0. - [Release notes](https://github.com/prometheus/client_golang/releases) - [Changelog](https://github.com/prometheus/client_golang/blob/v1.18.0/CHANGELOG.md) - [Commits](https://github.com/prometheus/client_golang/compare/v1.17.0...v1.18.0) --- updated-dependencies: - dependency-name: github.com/prometheus/client_golang dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 10 +++++----- go.sum | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index b3e4c8e8e..ef795099e 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 github.com/nmcclain/asn1-ber v0.0.0-20170104154839-2661553a0484 github.com/pires/go-proxyproto v0.7.0 - github.com/prometheus/client_golang v1.17.0 + github.com/prometheus/client_golang v1.18.0 github.com/redis/go-redis/v9 v9.3.1 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.0 @@ -60,14 +60,14 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pquerna/cachecontrol v0.0.0-20201205024021-ac21108117ac // indirect - github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect - github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.11.1 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.45.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect github.com/spf13/pflag v1.0.5 // indirect go.mongodb.org/mongo-driver v1.13.1 // indirect go.opentelemetry.io/otel v1.17.0 // indirect diff --git a/go.sum b/go.sum index 34c933ba3..e5b7ade11 100644 --- a/go.sum +++ b/go.sum @@ -223,8 +223,8 @@ github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -247,15 +247,15 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pquerna/cachecontrol v0.0.0-20201205024021-ac21108117ac h1:jWKYCNlX4J5s8M0nHYkh7Y7c9gRVDEb3mq51j5J0F5M= github.com/pquerna/cachecontrol v0.0.0-20201205024021-ac21108117ac/go.mod h1:hoLfEwdY11HjRfKFH6KqnPsfxlo3BP6bJehpDv8t6sQ= -github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= -github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= +github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM= -github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= -github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= -github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= +github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/redis/go-redis/v9 v9.3.1 h1:KqdY8U+3X6z+iACvumCNxnoluToB+9Me+TvyFa21Mds= github.com/redis/go-redis/v9 v9.3.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= From 64ca5d42be0ec967b00ec7c3c7fced16311e0db8 Mon Sep 17 00:00:00 2001 From: Marc 'risson' Schmitt Date: Thu, 28 Dec 2023 14:21:08 +0100 Subject: [PATCH 05/31] outposts/ldap: allow overriding gidNumber for a user (#8003) Signed-off-by: Marc 'risson' Schmitt --- internal/outpost/ldap/entries.go | 5 +++-- internal/outpost/ldap/group/group.go | 5 +++-- internal/outpost/ldap/server/base.go | 6 ++++-- internal/outpost/ldap/utils.go | 14 ++++++++++++-- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/internal/outpost/ldap/entries.go b/internal/outpost/ldap/entries.go index 2236a9964..d0f4abcf6 100644 --- a/internal/outpost/ldap/entries.go +++ b/internal/outpost/ldap/entries.go @@ -6,6 +6,7 @@ import ( "strings" "beryju.io/ldap" + "goauthentik.io/api/v3" "goauthentik.io/internal/outpost/ldap/constants" "goauthentik.io/internal/outpost/ldap/utils" @@ -49,8 +50,8 @@ func (pi *ProviderInstance) UserEntry(u api.User) *ldap.Entry { constants.OCPosixAccount, constants.OCAKUser, }, - "uidNumber": {pi.GetUidNumber(u)}, - "gidNumber": {pi.GetUidNumber(u)}, + "uidNumber": {pi.GetUserUidNumber(u)}, + "gidNumber": {pi.GetUserGidNumber(u)}, "homeDirectory": {fmt.Sprintf("/home/%s", u.Username)}, "sn": {u.Name}, }) diff --git a/internal/outpost/ldap/group/group.go b/internal/outpost/ldap/group/group.go index abfdf987f..21fd39b05 100644 --- a/internal/outpost/ldap/group/group.go +++ b/internal/outpost/ldap/group/group.go @@ -4,6 +4,7 @@ import ( "strconv" "beryju.io/ldap" + "goauthentik.io/api/v3" "goauthentik.io/internal/outpost/ldap/constants" "goauthentik.io/internal/outpost/ldap/server" @@ -50,7 +51,7 @@ func FromAPIGroup(g api.Group, si server.LDAPServerInstance) *LDAPGroup { DN: si.GetGroupDN(g.Name), CN: g.Name, Uid: string(g.Pk), - GidNumber: si.GetGidNumber(g), + GidNumber: si.GetGroupGidNumber(g), Member: si.UsersForGroup(g), IsVirtualGroup: false, IsSuperuser: *g.IsSuperuser, @@ -63,7 +64,7 @@ func FromAPIUser(u api.User, si server.LDAPServerInstance) *LDAPGroup { DN: si.GetVirtualGroupDN(u.Username), CN: u.Username, Uid: u.Uid, - GidNumber: si.GetUidNumber(u), + GidNumber: si.GetUserGidNumber(u), Member: []string{si.GetUserDN(u.Username)}, IsVirtualGroup: true, IsSuperuser: false, diff --git a/internal/outpost/ldap/server/base.go b/internal/outpost/ldap/server/base.go index ff6649a03..2983e3afc 100644 --- a/internal/outpost/ldap/server/base.go +++ b/internal/outpost/ldap/server/base.go @@ -3,6 +3,7 @@ package server import ( "beryju.io/ldap" "github.com/go-openapi/strfmt" + "goauthentik.io/api/v3" "goauthentik.io/internal/outpost/ldap/flags" ) @@ -28,8 +29,9 @@ type LDAPServerInstance interface { GetGroupDN(string) string GetVirtualGroupDN(string) string - GetUidNumber(api.User) string - GetGidNumber(api.Group) string + GetUserUidNumber(api.User) string + GetUserGidNumber(api.User) string + GetGroupGidNumber(api.Group) string UsersForGroup(api.Group) []string diff --git a/internal/outpost/ldap/utils.go b/internal/outpost/ldap/utils.go index 6dbf0723b..22c44fe90 100644 --- a/internal/outpost/ldap/utils.go +++ b/internal/outpost/ldap/utils.go @@ -35,7 +35,7 @@ func (pi *ProviderInstance) GetVirtualGroupDN(group string) string { return fmt.Sprintf("cn=%s,%s", group, pi.VirtualGroupDN) } -func (pi *ProviderInstance) GetUidNumber(user api.User) string { +func (pi *ProviderInstance) GetUserUidNumber(user api.User) string { uidNumber, ok := user.GetAttributes()["uidNumber"].(string) if ok { @@ -45,7 +45,17 @@ func (pi *ProviderInstance) GetUidNumber(user api.User) string { return strconv.FormatInt(int64(pi.uidStartNumber+user.Pk), 10) } -func (pi *ProviderInstance) GetGidNumber(group api.Group) string { +func (pi *ProviderInstance) GetUserGidNumber(user api.User) string { + gidNumber, ok := user.GetAttributes()["gidNumber"].(string) + + if ok { + return gidNumber + } + + return pi.GetUserUidNumber(user) +} + +func (pi *ProviderInstance) GetGroupGidNumber(group api.Group) string { gidNumber, ok := group.GetAttributes()["gidNumber"].(string) if ok { From cca556f7661033014aefb60fadb8ebc9e8e5d731 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 29 Dec 2023 11:31:04 +0100 Subject: [PATCH 06/31] core: bump github.com/go-openapi/strfmt from 0.21.10 to 0.22.0 (#8012) Bumps [github.com/go-openapi/strfmt](https://github.com/go-openapi/strfmt) from 0.21.10 to 0.22.0. - [Commits](https://github.com/go-openapi/strfmt/compare/v0.21.10...v0.22.0) --- updated-dependencies: - dependency-name: github.com/go-openapi/strfmt dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ef795099e..52f4ac7c5 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1 github.com/go-ldap/ldap/v3 v3.4.6 github.com/go-openapi/runtime v0.26.2 - github.com/go-openapi/strfmt v0.21.10 + github.com/go-openapi/strfmt v0.22.0 github.com/golang-jwt/jwt v3.2.2+incompatible github.com/google/uuid v1.5.0 github.com/gorilla/handlers v1.5.2 diff --git a/go.sum b/go.sum index e5b7ade11..e181e30db 100644 --- a/go.sum +++ b/go.sum @@ -116,8 +116,8 @@ github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6 github.com/go-openapi/spec v0.20.11 h1:J/TzFDLTt4Rcl/l1PmyErvkqlJDncGvPTMnCI39I4gY= github.com/go-openapi/spec v0.20.11/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= -github.com/go-openapi/strfmt v0.21.10 h1:JIsly3KXZB/Qf4UzvzJpg4OELH/0ASDQsyk//TTBDDk= -github.com/go-openapi/strfmt v0.21.10/go.mod h1:vNDMwbilnl7xKiO/Ve/8H8Bb2JIInBnH+lqiw6QWgis= +github.com/go-openapi/strfmt v0.22.0 h1:Ew9PnEYc246TwrEspvBdDHS4BVKXy/AOVsfqGDgAcaI= +github.com/go-openapi/strfmt v0.22.0/go.mod h1:HzJ9kokGIju3/K6ap8jL+OlGAbjpSv27135Yr9OivU4= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= From 6cd4c206aadd3c2d7a96a02208bf8521f8111aea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 29 Dec 2023 11:31:17 +0100 Subject: [PATCH 07/31] website: bump @types/react from 18.2.45 to 18.2.46 in /website (#8011) Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 18.2.45 to 18.2.46. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react) --- updated-dependencies: - dependency-name: "@types/react" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- website/package-lock.json | 8 ++++---- website/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/website/package-lock.json b/website/package-lock.json index 097357958..4e7d1a5a8 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -33,7 +33,7 @@ "@docusaurus/module-type-aliases": "3.0.1", "@docusaurus/tsconfig": "3.0.1", "@docusaurus/types": "3.0.1", - "@types/react": "^18.2.45", + "@types/react": "^18.2.46", "prettier": "3.1.1", "typescript": "~5.3.3" }, @@ -4373,9 +4373,9 @@ "integrity": "sha512-+0autS93xyXizIYiyL02FCY8N+KkKPhILhcUSA276HxzreZ16kl+cmwvV2qAM/PuCCwPXzOXOWhiPcw20uSFcA==" }, "node_modules/@types/react": { - "version": "18.2.45", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.45.tgz", - "integrity": "sha512-TtAxCNrlrBp8GoeEp1npd5g+d/OejJHFxS3OWmrPBMFaVQMSN0OFySozJio5BHxTuTeug00AVXVAjfDSfk+lUg==", + "version": "18.2.46", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.46.tgz", + "integrity": "sha512-nNCvVBcZlvX4NU1nRRNV/mFl1nNRuTuslAJglQsq+8ldXe5Xv0Wd2f7WTE3jOxhLH2BFfiZGC6GCp+kHQbgG+w==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", diff --git a/website/package.json b/website/package.json index 1b087d394..5e8dca12e 100644 --- a/website/package.json +++ b/website/package.json @@ -52,7 +52,7 @@ "@docusaurus/module-type-aliases": "3.0.1", "@docusaurus/tsconfig": "3.0.1", "@docusaurus/types": "3.0.1", - "@types/react": "^18.2.45", + "@types/react": "^18.2.46", "prettier": "3.1.1", "typescript": "~5.3.3" }, From 0cf4acf31eaf11bfcbd2d3247050fb36dfbb09fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 29 Dec 2023 11:31:32 +0100 Subject: [PATCH 08/31] web: bump the wdio group in /tests/wdio with 1 update (#8008) Bumps the wdio group in /tests/wdio with 1 update: [@wdio/cli](https://github.com/webdriverio/webdriverio/tree/HEAD/packages/wdio-cli). Updates `@wdio/cli` from 8.27.0 to 8.27.1 - [Release notes](https://github.com/webdriverio/webdriverio/releases) - [Changelog](https://github.com/webdriverio/webdriverio/blob/main/CHANGELOG.md) - [Commits](https://github.com/webdriverio/webdriverio/commits/v8.27.1/packages/wdio-cli) --- updated-dependencies: - dependency-name: "@wdio/cli" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: wdio ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tests/wdio/package-lock.json | 8 ++++---- tests/wdio/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/wdio/package-lock.json b/tests/wdio/package-lock.json index c9ce79620..486739f5c 100644 --- a/tests/wdio/package-lock.json +++ b/tests/wdio/package-lock.json @@ -9,7 +9,7 @@ "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@typescript-eslint/eslint-plugin": "^6.16.0", "@typescript-eslint/parser": "^6.16.0", - "@wdio/cli": "^8.27.0", + "@wdio/cli": "^8.27.1", "@wdio/local-runner": "^8.27.0", "@wdio/mocha-framework": "^8.27.0", "@wdio/spec-reporter": "^8.27.0", @@ -1166,9 +1166,9 @@ "dev": true }, "node_modules/@wdio/cli": { - "version": "8.27.0", - "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.27.0.tgz", - "integrity": "sha512-wdNYNvu52XxOqNHqDMGAtexBz+MM0RE2Z5U5ljyllbP3ed5vcvvK9vswURtI4cFGoqobVeoC7wif3VeD3aN+aQ==", + "version": "8.27.1", + "resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.27.1.tgz", + "integrity": "sha512-RY9o4h0iN6UGpU31X5c9mu/TK2FlHtKtDaRJYunm5ycZvGahQcN+naYpea1ftDr4IpI2gGGlHxvEeHkJF7urDQ==", "dev": true, "dependencies": { "@types/node": "^20.1.1", diff --git a/tests/wdio/package.json b/tests/wdio/package.json index eeb0c124e..9e0cc07b2 100644 --- a/tests/wdio/package.json +++ b/tests/wdio/package.json @@ -6,7 +6,7 @@ "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@typescript-eslint/eslint-plugin": "^6.16.0", "@typescript-eslint/parser": "^6.16.0", - "@wdio/cli": "^8.27.0", + "@wdio/cli": "^8.27.1", "@wdio/local-runner": "^8.27.0", "@wdio/mocha-framework": "^8.27.0", "@wdio/spec-reporter": "^8.27.0", From 4c24be60ae5f1eb33964bdfd42125bf4a997bed8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 29 Dec 2023 11:31:41 +0100 Subject: [PATCH 09/31] web: bump core-js from 3.34.0 to 3.35.0 in /web (#8010) Bumps [core-js](https://github.com/zloirock/core-js/tree/HEAD/packages/core-js) from 3.34.0 to 3.35.0. - [Release notes](https://github.com/zloirock/core-js/releases) - [Changelog](https://github.com/zloirock/core-js/blob/master/CHANGELOG.md) - [Commits](https://github.com/zloirock/core-js/commits/v3.35.0/packages/core-js) --- updated-dependencies: - dependency-name: core-js dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- web/package-lock.json | 8 ++++---- web/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 8caa84294..435b7abdc 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -32,7 +32,7 @@ "chartjs-adapter-moment": "^1.0.1", "codemirror": "^6.0.1", "construct-style-sheets-polyfill": "^3.1.0", - "core-js": "^3.34.0", + "core-js": "^3.35.0", "country-flag-icons": "^1.5.9", "fuse.js": "^7.0.0", "lit": "^2.8.0", @@ -9196,9 +9196,9 @@ "dev": true }, "node_modules/core-js": { - "version": "3.34.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.34.0.tgz", - "integrity": "sha512-aDdvlDder8QmY91H88GzNi9EtQi2TjvQhpCX6B1v/dAZHU1AuLgHvRh54RiOerpEhEW46Tkf+vgAViB/CWC0ag==", + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.35.0.tgz", + "integrity": "sha512-ntakECeqg81KqMueeGJ79Q5ZgQNR+6eaE8sxGCx62zMbAIj65q+uYvatToew3m6eAGdU4gNZwpZ34NMe4GYswg==", "hasInstallScript": true, "funding": { "type": "opencollective", diff --git a/web/package.json b/web/package.json index 4d7002840..e73b6ea64 100644 --- a/web/package.json +++ b/web/package.json @@ -57,7 +57,7 @@ "chartjs-adapter-moment": "^1.0.1", "codemirror": "^6.0.1", "construct-style-sheets-polyfill": "^3.1.0", - "core-js": "^3.34.0", + "core-js": "^3.35.0", "country-flag-icons": "^1.5.9", "fuse.js": "^7.0.0", "lit": "^2.8.0", From 0e1646ca1b651b7b0eeca02a62afa7620d9d690f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 29 Dec 2023 11:31:52 +0100 Subject: [PATCH 10/31] web: bump vite-tsconfig-paths from 4.2.2 to 4.2.3 in /web (#8009) Bumps [vite-tsconfig-paths](https://github.com/aleclarson/vite-tsconfig-paths) from 4.2.2 to 4.2.3. - [Release notes](https://github.com/aleclarson/vite-tsconfig-paths/releases) - [Commits](https://github.com/aleclarson/vite-tsconfig-paths/compare/v4.2.2...v4.2.3) --- updated-dependencies: - dependency-name: vite-tsconfig-paths dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- web/package-lock.json | 8 ++++---- web/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 435b7abdc..59c543660 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -101,7 +101,7 @@ "tslib": "^2.6.2", "turnstile-types": "^1.2.0", "typescript": "^5.3.3", - "vite-tsconfig-paths": "^4.2.2" + "vite-tsconfig-paths": "^4.2.3" }, "engines": { "node": ">=20" @@ -18353,9 +18353,9 @@ } }, "node_modules/vite-tsconfig-paths": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-4.2.2.tgz", - "integrity": "sha512-dq0FjyxHHDnp0uS3P12WEOX2W7NeuLzX9AWP38D7Zw2CTbFErapwQVlCiT5DMJcVWKQ1MMdTe92PZl/rBQ7qcw==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-4.2.3.tgz", + "integrity": "sha512-xVsA2xe6QSlzBujtWF8q2NYexh7PAUYfzJ4C8Axpe/7d2pcERYxuxGgph9F4f0iQO36g5tyGq6eBUYIssdUrVw==", "dev": true, "dependencies": { "debug": "^4.1.1", diff --git a/web/package.json b/web/package.json index e73b6ea64..f84bf97a8 100644 --- a/web/package.json +++ b/web/package.json @@ -126,7 +126,7 @@ "tslib": "^2.6.2", "turnstile-types": "^1.2.0", "typescript": "^5.3.3", - "vite-tsconfig-paths": "^4.2.2" + "vite-tsconfig-paths": "^4.2.3" }, "optionalDependencies": { "@esbuild/darwin-arm64": "^0.19.10", From 1c3cce1f899e08c910b313da1af7f5427ffad380 Mon Sep 17 00:00:00 2001 From: Jens L Date: Sat, 30 Dec 2023 15:18:21 +0100 Subject: [PATCH 11/31] outposts: fix Outpost reconcile not re-assigning managed attribute (#8014) * outposts: fix Outpost reconcile not re-assigning managed attribute Signed-off-by: Jens Langhammer * rework reconcile to find both name and managed outpost Signed-off-by: Jens Langhammer --------- Signed-off-by: Jens Langhammer --- authentik/blueprints/apps.py | 2 +- authentik/outposts/api/outposts.py | 12 +++++++++- authentik/outposts/apps.py | 7 +++++- authentik/outposts/tests/test_api.py | 35 ++++++++++++++++++++++++++-- 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/authentik/blueprints/apps.py b/authentik/blueprints/apps.py index 90df91c00..aba14d552 100644 --- a/authentik/blueprints/apps.py +++ b/authentik/blueprints/apps.py @@ -40,7 +40,7 @@ class ManagedAppConfig(AppConfig): meth() self._logger.debug("Successfully reconciled", name=name) except (DatabaseError, ProgrammingError, InternalError) as exc: - self._logger.debug("Failed to run reconcile", name=name, exc=exc) + self._logger.warning("Failed to run reconcile", name=name, exc=exc) class AuthentikBlueprintsConfig(ManagedAppConfig): diff --git a/authentik/outposts/api/outposts.py b/authentik/outposts/api/outposts.py index 4e9925029..6332c31a8 100644 --- a/authentik/outposts/api/outposts.py +++ b/authentik/outposts/api/outposts.py @@ -18,7 +18,7 @@ from authentik.core.api.used_by import UsedByMixin from authentik.core.api.utils import JSONDictField, PassiveSerializer from authentik.core.models import Provider from authentik.outposts.api.service_connections import ServiceConnectionSerializer -from authentik.outposts.apps import MANAGED_OUTPOST +from authentik.outposts.apps import MANAGED_OUTPOST, MANAGED_OUTPOST_NAME from authentik.outposts.models import ( Outpost, OutpostConfig, @@ -47,6 +47,16 @@ class OutpostSerializer(ModelSerializer): source="service_connection", read_only=True ) + def validate_name(self, name: str) -> str: + """Validate name (especially for embedded outpost)""" + if not self.instance: + return name + if self.instance.managed == MANAGED_OUTPOST: + raise ValidationError("Embedded outpost's name cannot be changed") + if self.instance.name == MANAGED_OUTPOST_NAME: + self.instance.managed = MANAGED_OUTPOST + return name + def validate_providers(self, providers: list[Provider]) -> list[Provider]: """Check that all providers match the type of the outpost""" type_map = { diff --git a/authentik/outposts/apps.py b/authentik/outposts/apps.py index 6898a170a..08d1080ee 100644 --- a/authentik/outposts/apps.py +++ b/authentik/outposts/apps.py @@ -15,6 +15,7 @@ GAUGE_OUTPOSTS_LAST_UPDATE = Gauge( ["outpost", "uid", "version"], ) MANAGED_OUTPOST = "goauthentik.io/outposts/embedded" +MANAGED_OUTPOST_NAME = "authentik Embedded Outpost" class AuthentikOutpostConfig(ManagedAppConfig): @@ -39,10 +40,14 @@ class AuthentikOutpostConfig(ManagedAppConfig): OutpostType, ) + if outpost := Outpost.objects.filter(name=MANAGED_OUTPOST_NAME, managed="").first(): + outpost.managed = MANAGED_OUTPOST + outpost.save() + return outpost, updated = Outpost.objects.update_or_create( defaults={ - "name": "authentik Embedded Outpost", "type": OutpostType.PROXY, + "name": MANAGED_OUTPOST_NAME, }, managed=MANAGED_OUTPOST, ) diff --git a/authentik/outposts/tests/test_api.py b/authentik/outposts/tests/test_api.py index 5e6fb385e..3edaeb78e 100644 --- a/authentik/outposts/tests/test_api.py +++ b/authentik/outposts/tests/test_api.py @@ -2,11 +2,13 @@ from django.urls import reverse from rest_framework.test import APITestCase +from authentik.blueprints.tests import reconcile_app from authentik.core.models import PropertyMapping from authentik.core.tests.utils import create_test_admin_user, create_test_flow from authentik.lib.generators import generate_id from authentik.outposts.api.outposts import OutpostSerializer -from authentik.outposts.models import OutpostType, default_outpost_config +from authentik.outposts.apps import MANAGED_OUTPOST +from authentik.outposts.models import Outpost, OutpostType, default_outpost_config from authentik.providers.ldap.models import LDAPProvider from authentik.providers.proxy.models import ProxyProvider @@ -22,7 +24,36 @@ class TestOutpostServiceConnectionsAPI(APITestCase): self.user = create_test_admin_user() self.client.force_login(self.user) - def test_outpost_validaton(self): + @reconcile_app("authentik_outposts") + def test_managed_name_change(self): + """Test name change for embedded outpost""" + embedded_outpost = Outpost.objects.filter(managed=MANAGED_OUTPOST).first() + self.assertIsNotNone(embedded_outpost) + response = self.client.patch( + reverse("authentik_api:outpost-detail", kwargs={"pk": embedded_outpost.pk}), + {"name": "foo"}, + ) + self.assertEqual(response.status_code, 400) + self.assertJSONEqual( + response.content, {"name": ["Embedded outpost's name cannot be changed"]} + ) + + @reconcile_app("authentik_outposts") + def test_managed_without_managed(self): + """Test name change for embedded outpost""" + embedded_outpost = Outpost.objects.filter(managed=MANAGED_OUTPOST).first() + self.assertIsNotNone(embedded_outpost) + embedded_outpost.managed = "" + embedded_outpost.save() + response = self.client.patch( + reverse("authentik_api:outpost-detail", kwargs={"pk": embedded_outpost.pk}), + {"name": "foo"}, + ) + self.assertEqual(response.status_code, 200) + embedded_outpost.refresh_from_db() + self.assertEqual(embedded_outpost.managed, MANAGED_OUTPOST) + + def test_outpost_validation(self): """Test Outpost validation""" valid = OutpostSerializer( data={ From 255f217c26f105ec54b40d32c29067c7bc5d0d77 Mon Sep 17 00:00:00 2001 From: Gabriel Simmer Date: Sat, 30 Dec 2023 15:20:29 +0000 Subject: [PATCH 12/31] website/integrations: Add custom Group/Role mapping documentation for Grafana (#7453) * Add custom Group/Role mapping documentation for Grafana * Correct anchor link to role-mappings * Indentation * Update website/integrations/services/grafana/index.mdx Co-authored-by: Tana M Berry Signed-off-by: Gabriel Simmer --------- Signed-off-by: Gabriel Simmer Co-authored-by: Tana M Berry --- .../integrations/services/grafana/index.mdx | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/website/integrations/services/grafana/index.mdx b/website/integrations/services/grafana/index.mdx index a79730ea0..2de91535a 100644 --- a/website/integrations/services/grafana/index.mdx +++ b/website/integrations/services/grafana/index.mdx @@ -24,6 +24,16 @@ Create an application in authentik. Create an OAuth2/OpenID provider with the fo - Signing Key: Select any available key - Redirect URIs: `https://grafana.company/login/generic_oauth` +Additionally, because Grafana has its own concept of groups, we need to create a custom Scope Mapping to ensure Grafana can read the user's groups assigned within authentik. It should contain the following expression: + +```json +return { + "info": { "groups": [group.name for group in request.user.ak_groups.all()] }, +} +``` + +This ensures that groups are available under `info.groups[]`, which can be used later in [Role Mapping](#role-mappings). + Note the Client ID and Client Secret values. Create an application, using the provider you've created above. Note the slug of the application you've created. ## Terraform provider @@ -46,6 +56,16 @@ data "authentik_scope_mapping" "scope-openid" { name = "authentik default OAuth Mapping: OpenID 'openid'" } +resource "authentik_scope_mapping" "scope-grafana-roles" { + name = "Grafana Groups" + scope_name = "grafana-groups" + expression = < @@ -138,7 +159,7 @@ auth_url = https://authentik.company/application/o/authorize/ token_url = https://authentik.company/application/o/token/ api_url = https://authentik.company/application/o/userinfo/ # Optionally map user groups to Grafana roles -role_attribute_path = contains(groups[*], 'Grafana Admins') && 'Admin' || contains(groups[*], 'Grafana Editors') && 'Editor' || 'Viewer' +role_attribute_path = contains(info.groups[*], 'Grafana Admins') && 'Admin' || contains(info.groups[*], 'Grafana Editors') && 'Editor' || 'Viewer' ``` @@ -160,7 +181,7 @@ grafana.ini: token_url: "https://authentik.company/application/o/token/" api_url: "https://authentik.company/application/o/userinfo/" # Optionally map user groups to Grafana roles - role_attribute_path: contains(groups[*], 'Grafana Admins') && 'Admin' || contains(groups[*], 'Grafana Editors') && 'Editor' || 'Viewer' + role_attribute_path: contains(info.groups[*], 'Grafana Admins') && 'Admin' || contains(info.groups[*], 'Grafana Editors') && 'Editor' || 'Viewer' ``` :::note @@ -178,8 +199,8 @@ In the example shown above, one of the specified group names is "Grafana Admins" If the user is not a member of the "Grafana Admins" group, it moves on to see if the user is a member of the "Grafana Editors" group. If they are, they are granted the "Editor" role. Finally, if the user is not found to be a member of either of these groups, it fails back to granting the "Viewer" role. ```text -contains(groups[*], 'Grafana Admins') && 'Admin' || contains(groups[*], 'Grafana Editors') && 'Editor' || 'Viewer' -^ attribute to search ^ group to search for ^ role to grant ^ or grant "Viewer" role. +contains(info.groups[*], 'Grafana Admins') && 'Admin' || contains(info.groups[*], 'Grafana Editors') && 'Editor' || 'Viewer' + ^ attribute ^ group to search for^ role to grant ^ or grant "Viewer" role. ``` For more information on group/role mappings, see [Grafana's docs](https://grafana.com/docs/grafana/latest/auth/generic-oauth/#role-mapping). From 1ea3dae5ac5eee5432f45c2a846ce13378932554 Mon Sep 17 00:00:00 2001 From: Jens L Date: Sat, 30 Dec 2023 16:36:43 +0100 Subject: [PATCH 13/31] providers/proxy: use access token (#8022) Signed-off-by: Jens Langhammer --- .../outpost/proxyv2/application/oauth_callback.go | 13 ++++--------- internal/outpost/proxyv2/application/session.go | 2 +- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/internal/outpost/proxyv2/application/oauth_callback.go b/internal/outpost/proxyv2/application/oauth_callback.go index eef418a84..13f28e67a 100644 --- a/internal/outpost/proxyv2/application/oauth_callback.go +++ b/internal/outpost/proxyv2/application/oauth_callback.go @@ -31,16 +31,11 @@ func (a *Application) redeemCallback(savedState string, u *url.URL, c context.Co return nil, err } - // Extract the ID Token from OAuth2 token. - rawIDToken, ok := oauth2Token.Extra("id_token").(string) - if !ok { - return nil, fmt.Errorf("missing id_token") - } - - a.log.WithField("id_token", rawIDToken).Trace("id_token") + jwt := oauth2Token.AccessToken + a.log.WithField("jwt", jwt).Trace("access_token") // Parse and verify ID Token payload. - idToken, err := a.tokenVerifier.Verify(ctx, rawIDToken) + idToken, err := a.tokenVerifier.Verify(ctx, jwt) if err != nil { return nil, err } @@ -53,6 +48,6 @@ func (a *Application) redeemCallback(savedState string, u *url.URL, c context.Co if claims.Proxy == nil { claims.Proxy = &ProxyClaims{} } - claims.RawToken = rawIDToken + claims.RawToken = jwt return claims, nil } diff --git a/internal/outpost/proxyv2/application/session.go b/internal/outpost/proxyv2/application/session.go index 5ffa77b04..468baf4d9 100644 --- a/internal/outpost/proxyv2/application/session.go +++ b/internal/outpost/proxyv2/application/session.go @@ -62,7 +62,7 @@ func (a *Application) getStore(p api.ProxyOutpostConfig, externalHost *url.URL) // https://github.com/markbates/goth/commit/7276be0fdf719ddff753f3574ef0f967e4a5a5f7 // set the maxLength of the cookies stored on the disk to a larger number to prevent issues with: // securecookie: the value is too long - // when using OpenID Connect , since this can contain a large amount of extra information in the id_token + // when using OpenID Connect, since this can contain a large amount of extra information in the id_token // Note, when using the FilesystemStore only the session.ID is written to a browser cookie, so this is explicit for the storage on disk cs.MaxLength(math.MaxInt) From a365ec81f3d44247279105b97ef3062ef1d5beb4 Mon Sep 17 00:00:00 2001 From: Jens L Date: Sat, 30 Dec 2023 21:32:30 +0100 Subject: [PATCH 14/31] outposts: disable deployment and secret reconciler for embedded outpost in code instead of in config (#8021) Signed-off-by: Jens Langhammer --- authentik/outposts/api/outposts.py | 2 +- authentik/outposts/apps.py | 7 ------- authentik/outposts/controllers/k8s/deployment.py | 4 ++++ authentik/outposts/controllers/k8s/secret.py | 4 ++++ authentik/outposts/controllers/k8s/service_monitor.py | 5 ++++- 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/authentik/outposts/api/outposts.py b/authentik/outposts/api/outposts.py index 6332c31a8..6219d68ea 100644 --- a/authentik/outposts/api/outposts.py +++ b/authentik/outposts/api/outposts.py @@ -51,7 +51,7 @@ class OutpostSerializer(ModelSerializer): """Validate name (especially for embedded outpost)""" if not self.instance: return name - if self.instance.managed == MANAGED_OUTPOST: + if self.instance.managed == MANAGED_OUTPOST and name != MANAGED_OUTPOST_NAME: raise ValidationError("Embedded outpost's name cannot be changed") if self.instance.name == MANAGED_OUTPOST_NAME: self.instance.managed = MANAGED_OUTPOST diff --git a/authentik/outposts/apps.py b/authentik/outposts/apps.py index 08d1080ee..b0a6298c7 100644 --- a/authentik/outposts/apps.py +++ b/authentik/outposts/apps.py @@ -36,7 +36,6 @@ class AuthentikOutpostConfig(ManagedAppConfig): DockerServiceConnection, KubernetesServiceConnection, Outpost, - OutpostConfig, OutpostType, ) @@ -56,10 +55,4 @@ class AuthentikOutpostConfig(ManagedAppConfig): outpost.service_connection = KubernetesServiceConnection.objects.first() elif DockerServiceConnection.objects.exists(): outpost.service_connection = DockerServiceConnection.objects.first() - outpost.config = OutpostConfig( - kubernetes_disabled_components=[ - "deployment", - "secret", - ] - ) outpost.save() diff --git a/authentik/outposts/controllers/k8s/deployment.py b/authentik/outposts/controllers/k8s/deployment.py index 4aa10e7f7..e06d97139 100644 --- a/authentik/outposts/controllers/k8s/deployment.py +++ b/authentik/outposts/controllers/k8s/deployment.py @@ -43,6 +43,10 @@ class DeploymentReconciler(KubernetesObjectReconciler[V1Deployment]): self.api = AppsV1Api(controller.client) self.outpost = self.controller.outpost + @property + def noop(self) -> bool: + return self.is_embedded + @staticmethod def reconciler_name() -> str: return "deployment" diff --git a/authentik/outposts/controllers/k8s/secret.py b/authentik/outposts/controllers/k8s/secret.py index 8a2293404..ddc3643c6 100644 --- a/authentik/outposts/controllers/k8s/secret.py +++ b/authentik/outposts/controllers/k8s/secret.py @@ -24,6 +24,10 @@ class SecretReconciler(KubernetesObjectReconciler[V1Secret]): super().__init__(controller) self.api = CoreV1Api(controller.client) + @property + def noop(self) -> bool: + return self.is_embedded + @staticmethod def reconciler_name() -> str: return "secret" diff --git a/authentik/outposts/controllers/k8s/service_monitor.py b/authentik/outposts/controllers/k8s/service_monitor.py index 4e58c119a..8e00f9c50 100644 --- a/authentik/outposts/controllers/k8s/service_monitor.py +++ b/authentik/outposts/controllers/k8s/service_monitor.py @@ -77,7 +77,10 @@ class PrometheusServiceMonitorReconciler(KubernetesObjectReconciler[PrometheusSe @property def noop(self) -> bool: - return (not self._crd_exists()) or (self.is_embedded) + if not self._crd_exists(): + self.logger.debug("CRD doesn't exist") + return True + return self.is_embedded def _crd_exists(self) -> bool: """Check if the Prometheus ServiceMonitor exists""" From 240cf6dd941664deedc62326263854992b2e721d Mon Sep 17 00:00:00 2001 From: Jens L Date: Sat, 30 Dec 2023 21:33:14 +0100 Subject: [PATCH 15/31] enterprise/providers: Add RAC [AUTH-15] (#7291) * add basic guacamole Signed-off-by: Jens Langhammer * make everything mostly work Signed-off-by: Jens Langhammer * add rac build to CI Signed-off-by: Jens Langhammer * fix resize, fix web lint, sendSize correctly Signed-off-by: Jens Langhammer * pre-send connection from client, format Signed-off-by: Jens Langhammer * improve throughput Signed-off-by: Jens Langhammer * cleanup Signed-off-by: Jens Langhammer * rework TokenOutpostConsumer into middleware Signed-off-by: Jens Langhammer * fix some layout issues Signed-off-by: Jens Langhammer * add outpost controllers Signed-off-by: Jens Langhammer * start testing audio things Signed-off-by: Jens Langhammer * fix a bunch of things Signed-off-by: Jens Langhammer * add deps Signed-off-by: Jens Langhammer * fix to work with outpost group Signed-off-by: Jens Langhammer * add simple loadbalancing Signed-off-by: Jens Langhammer * add simple reconnect Signed-off-by: Jens Langhammer * show reconnecting text Signed-off-by: Jens Langhammer * fix error when checking ports Signed-off-by: Jens Langhammer * move to providers Signed-off-by: Jens Langhammer * add flow check to interface Signed-off-by: Jens Langhammer * fix go lint Signed-off-by: Jens Langhammer * fix rac app label Signed-off-by: Jens Langhammer * fix audio Signed-off-by: Jens Langhammer * add logging Signed-off-by: Jens Langhammer * cleanup Signed-off-by: Jens Langhammer * allow overriding all settings Signed-off-by: Jens Langhammer * fix duplicate keyboard, debug high DPI Signed-off-by: Jens Langhammer * re-add deps Signed-off-by: Jens Langhammer * fix lint Signed-off-by: Jens Langhammer * fix missing __init__.py breaking model loading I love python Signed-off-by: Jens Langhammer * fix tests Signed-off-by: Jens Langhammer * bump successful ws connection to info Signed-off-by: Jens Langhammer * hide cursor since guac draws that Signed-off-by: Jens Langhammer * add clipboard support (bidirectional) Signed-off-by: Jens Langhammer * make codespell not want to break the code Signed-off-by: Jens Langhammer * run pr comment in separate task Signed-off-by: Jens Langhammer * start endpoint and property mapping stuff Signed-off-by: Jens Langhammer * more endpoint things Signed-off-by: Jens Langhammer * unrelated: fix event model_pk filtering with ints Signed-off-by: Jens Langhammer * unrelated: improve event display for changelog Signed-off-by: Jens Langhammer * rebuild endpoint stuff again Signed-off-by: Jens Langhammer * idk special url Signed-off-by: Jens Langhammer * more stuff, connect token with session Signed-off-by: Jens Langhammer * add disconnect Signed-off-by: Jens Langhammer * rework disconnect cleanly disconnect from guacd instead of just letting the connection timeout Signed-off-by: Jens Langhammer * clear cache when creating outpost Signed-off-by: Jens Langhammer * support host:port and fix protocol Signed-off-by: Jens Langhammer * center smaller viewport Signed-off-by: Jens Langhammer * rework connection to wait more and stop after some time Signed-off-by: Jens Langhammer * add policy control to endpoints Signed-off-by: Jens Langhammer * remove provider protocol Signed-off-by: Jens Langhammer * don't switch to different outpost connection when already chosen Signed-off-by: Jens Langhammer * start using property mappings, add static settings Signed-off-by: Jens Langhammer * add some RAC mapping settings Signed-off-by: Jens Langhammer * fix lint Signed-off-by: Jens Langhammer * start adding tests Signed-off-by: Jens Langhammer * add tests for event changes Signed-off-by: Jens Langhammer * add tests and fix issues found by said tests Signed-off-by: Jens Langhammer * add preview banner, move endpoints to main page Signed-off-by: Jens Langhammer * add locale Signed-off-by: Jens Langhammer * auto-select endpoint if only one is available Signed-off-by: Jens Langhammer * backport https://github.com/goauthentik/authentik/pull/7831 to rac Signed-off-by: Jens Langhammer * dont select property mappings on endpoints Signed-off-by: Jens Langhammer * make table modal only load when opened Signed-off-by: Jens Langhammer * only auto-redirect when open Signed-off-by: Jens Langhammer * fix web deps Signed-off-by: Jens Langhammer * check for token expiry and terminate session Signed-off-by: Jens Langhammer * re-add endpoint name to title Signed-off-by: Jens Langhammer * disconnect connection when token is manually deleted Signed-off-by: Jens Langhammer * add initial RAC docs Signed-off-by: Jens Langhammer * add connection expiry setting to provider Signed-off-by: Jens Langhammer * fix flaky tests Signed-off-by: Jens Langhammer --------- Signed-off-by: Jens Langhammer --- .dockerignore | 1 + .github/codespell-words.txt | 1 + .github/workflows/ci-main.yml | 29 +- .github/workflows/ci-outpost.yml | 2 + .github/workflows/release-publish.yml | 1 + Makefile | 2 +- authentik/core/channels.py | 21 +- authentik/core/views/interface.py | 1 + authentik/enterprise/policy.py | 10 +- authentik/enterprise/providers/__init__.py | 0 .../enterprise/providers/rac/__init__.py | 0 .../enterprise/providers/rac/api/__init__.py | 0 .../enterprise/providers/rac/api/endpoints.py | 133 ++ .../providers/rac/api/property_mappings.py | 35 + .../enterprise/providers/rac/api/providers.py | 31 + authentik/enterprise/providers/rac/apps.py | 17 + .../providers/rac/consumer_client.py | 163 +++ .../providers/rac/consumer_outpost.py | 48 + .../providers/rac/controllers/__init__.py | 0 .../providers/rac/controllers/docker.py | 11 + .../providers/rac/controllers/kubernetes.py | 13 + .../providers/rac/migrations/0001_initial.py | 164 +++ .../providers/rac/migrations/__init__.py | 0 authentik/enterprise/providers/rac/models.py | 191 +++ authentik/enterprise/providers/rac/signals.py | 54 + .../providers/rac/templates/if/rac.html | 18 + .../providers/rac/tests/__init__.py | 0 .../providers/rac/tests/test_endpoints_api.py | 168 +++ .../providers/rac/tests/test_models.py | 144 ++ .../providers/rac/tests/test_views.py | 132 ++ authentik/enterprise/providers/rac/urls.py | 47 + authentik/enterprise/providers/rac/views.py | 115 ++ authentik/enterprise/settings.py | 4 + authentik/events/api/events.py | 8 +- authentik/events/tests/test_api.py | 23 + authentik/outposts/api/outposts.py | 2 + authentik/outposts/consumer.py | 43 +- authentik/outposts/controllers/k8s/utils.py | 6 +- authentik/outposts/controllers/kubernetes.py | 25 +- .../migrations/0021_alter_outpost_type.py | 25 + authentik/outposts/models.py | 5 +- authentik/outposts/tasks.py | 7 + authentik/outposts/tests/test_ws.py | 6 +- authentik/outposts/urls.py | 6 +- blueprints/schema.json | 239 +++- blueprints/system/providers-rac.yaml | 32 + cmd/rac/main.go | 93 ++ go.mod | 1 + go.sum | 8 + internal/outpost/ak/api.go | 6 +- internal/outpost/ak/api_ws.go | 31 +- internal/outpost/rac/connection/connection.go | 124 ++ internal/outpost/rac/connection/mirror.go | 103 ++ internal/outpost/rac/guacd.go | 26 + internal/outpost/rac/metrics/metrics.go | 28 + internal/outpost/rac/rac.go | 126 ++ internal/web/static.go | 5 + rac.Dockerfile | 38 + schema.yml | 1232 ++++++++++++++++- web/package-lock.json | 13 + web/package.json | 2 + web/rollup.config.mjs | 17 + web/src/admin/outposts/OutpostForm.ts | 16 +- web/src/admin/outposts/OutpostListPage.ts | 2 + .../PropertyMappingListPage.ts | 1 + .../PropertyMappingRACForm.ts | 195 +++ .../PropertyMappingWizard.ts | 1 + web/src/admin/providers/ProviderListPage.ts | 1 + web/src/admin/providers/ProviderViewPage.ts | 5 + web/src/admin/providers/rac/EndpointForm.ts | 146 ++ web/src/admin/providers/rac/EndpointList.ts | 142 ++ .../admin/providers/rac/RACProviderForm.ts | 158 +++ .../providers/rac/RACProviderViewPage.ts | 181 +++ web/src/components/events/ObjectChangelog.ts | 8 +- web/src/elements/LoadingOverlay.ts | 6 +- web/src/elements/table/Table.ts | 29 +- web/src/elements/table/TableModal.ts | 20 +- web/src/enterprise/rac/index.ts | 324 +++++ .../RACLaunchEndpointModal.ts | 71 + web/src/user/LibraryApplication/index.ts | 25 +- .../user/LibraryPage/LibraryPageImpl.utils.ts | 8 +- web/xliff/de.xlf | 120 ++ web/xliff/en.xlf | 120 ++ web/xliff/es.xlf | 120 ++ web/xliff/fr.xlf | 186 ++- web/xliff/pl.xlf | 120 ++ web/xliff/pseudo-LOCALE.xlf | 120 ++ web/xliff/tr.xlf | 120 ++ web/xliff/zh-Hans.xlf | 168 ++- web/xliff/zh-Hant.xlf | 120 ++ web/xliff/zh_TW.xlf | 120 ++ website/docs/outposts/index.mdx | 1 + website/docs/providers/rac/index.md | 47 + website/docs/providers/radius/index.md | 4 - website/sidebars.js | 1 + 95 files changed, 6398 insertions(+), 144 deletions(-) create mode 100644 authentik/enterprise/providers/__init__.py create mode 100644 authentik/enterprise/providers/rac/__init__.py create mode 100644 authentik/enterprise/providers/rac/api/__init__.py create mode 100644 authentik/enterprise/providers/rac/api/endpoints.py create mode 100644 authentik/enterprise/providers/rac/api/property_mappings.py create mode 100644 authentik/enterprise/providers/rac/api/providers.py create mode 100644 authentik/enterprise/providers/rac/apps.py create mode 100644 authentik/enterprise/providers/rac/consumer_client.py create mode 100644 authentik/enterprise/providers/rac/consumer_outpost.py create mode 100644 authentik/enterprise/providers/rac/controllers/__init__.py create mode 100644 authentik/enterprise/providers/rac/controllers/docker.py create mode 100644 authentik/enterprise/providers/rac/controllers/kubernetes.py create mode 100644 authentik/enterprise/providers/rac/migrations/0001_initial.py create mode 100644 authentik/enterprise/providers/rac/migrations/__init__.py create mode 100644 authentik/enterprise/providers/rac/models.py create mode 100644 authentik/enterprise/providers/rac/signals.py create mode 100644 authentik/enterprise/providers/rac/templates/if/rac.html create mode 100644 authentik/enterprise/providers/rac/tests/__init__.py create mode 100644 authentik/enterprise/providers/rac/tests/test_endpoints_api.py create mode 100644 authentik/enterprise/providers/rac/tests/test_models.py create mode 100644 authentik/enterprise/providers/rac/tests/test_views.py create mode 100644 authentik/enterprise/providers/rac/urls.py create mode 100644 authentik/enterprise/providers/rac/views.py create mode 100644 authentik/outposts/migrations/0021_alter_outpost_type.py create mode 100644 blueprints/system/providers-rac.yaml create mode 100644 cmd/rac/main.go create mode 100644 internal/outpost/rac/connection/connection.go create mode 100644 internal/outpost/rac/connection/mirror.go create mode 100644 internal/outpost/rac/guacd.go create mode 100644 internal/outpost/rac/metrics/metrics.go create mode 100644 internal/outpost/rac/rac.go create mode 100644 rac.Dockerfile create mode 100644 web/src/admin/property-mappings/PropertyMappingRACForm.ts create mode 100644 web/src/admin/providers/rac/EndpointForm.ts create mode 100644 web/src/admin/providers/rac/EndpointList.ts create mode 100644 web/src/admin/providers/rac/RACProviderForm.ts create mode 100644 web/src/admin/providers/rac/RACProviderViewPage.ts create mode 100644 web/src/enterprise/rac/index.ts create mode 100644 web/src/user/LibraryApplication/RACLaunchEndpointModal.ts create mode 100644 website/docs/providers/rac/index.md diff --git a/.dockerignore b/.dockerignore index 352faf761..8d20d66d6 100644 --- a/.dockerignore +++ b/.dockerignore @@ -9,3 +9,4 @@ blueprints/local .git !gen-ts-api/node_modules !gen-ts-api/dist/** +!gen-go-api/ diff --git a/.github/codespell-words.txt b/.github/codespell-words.txt index 71f2f1c2c..29fb24832 100644 --- a/.github/codespell-words.txt +++ b/.github/codespell-words.txt @@ -2,3 +2,4 @@ keypair keypairs hass warmup +ontext diff --git a/.github/workflows/ci-main.yml b/.github/workflows/ci-main.yml index 282543d96..71bfc0d7a 100644 --- a/.github/workflows/ci-main.yml +++ b/.github/workflows/ci-main.yml @@ -249,12 +249,6 @@ jobs: VERSION_FAMILY=${{ steps.ev.outputs.versionFamily }} cache-from: type=gha cache-to: type=gha,mode=max - - name: Comment on PR - if: github.event_name == 'pull_request' - continue-on-error: true - uses: ./.github/actions/comment-pr-instructions - with: - tag: gh-${{ steps.ev.outputs.branchNameContainer }}-${{ steps.ev.outputs.timestamp }}-${{ steps.ev.outputs.shortHash }} build-arm64: needs: ci-core-mark runs-on: ubuntu-latest @@ -303,3 +297,26 @@ jobs: platforms: linux/arm64 cache-from: type=gha cache-to: type=gha,mode=max + pr-comment: + needs: + - build + - build-arm64 + runs-on: ubuntu-latest + if: ${{ github.event_name == 'pull_request' }} + permissions: + # Needed to write comments on PRs + pull-requests: write + timeout-minutes: 120 + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + - name: prepare variables + uses: ./.github/actions/docker-push-variables + id: ev + env: + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + - name: Comment on PR + uses: ./.github/actions/comment-pr-instructions + with: + tag: gh-${{ steps.ev.outputs.branchNameContainer }}-${{ steps.ev.outputs.timestamp }}-${{ steps.ev.outputs.shortHash }} diff --git a/.github/workflows/ci-outpost.yml b/.github/workflows/ci-outpost.yml index 196fa0b3b..35c83ac86 100644 --- a/.github/workflows/ci-outpost.yml +++ b/.github/workflows/ci-outpost.yml @@ -65,6 +65,7 @@ jobs: - proxy - ldap - radius + - rac runs-on: ubuntu-latest permissions: # Needed to upload contianer images to ghcr.io @@ -119,6 +120,7 @@ jobs: - proxy - ldap - radius + - rac goos: [linux] goarch: [amd64, arm64] steps: diff --git a/.github/workflows/release-publish.yml b/.github/workflows/release-publish.yml index c3c6a0d48..c002ab8a5 100644 --- a/.github/workflows/release-publish.yml +++ b/.github/workflows/release-publish.yml @@ -65,6 +65,7 @@ jobs: - proxy - ldap - radius + - rac steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 diff --git a/Makefile b/Makefile index a91ca7464..93092a779 100644 --- a/Makefile +++ b/Makefile @@ -58,7 +58,7 @@ test: ## Run the server tests and produce a coverage report (locally) lint-fix: ## Lint and automatically fix errors in the python source code. Reports spelling errors. isort $(PY_SOURCES) black $(PY_SOURCES) - ruff $(PY_SOURCES) + ruff --fix $(PY_SOURCES) codespell -w $(CODESPELL_ARGS) lint: ## Lint the python and golang sources diff --git a/authentik/core/channels.py b/authentik/core/channels.py index 00f213efc..722e9e03f 100644 --- a/authentik/core/channels.py +++ b/authentik/core/channels.py @@ -1,22 +1,29 @@ """Channels base classes""" +from channels.db import database_sync_to_async from channels.exceptions import DenyConnection -from channels.generic.websocket import JsonWebsocketConsumer from rest_framework.exceptions import AuthenticationFailed from structlog.stdlib import get_logger from authentik.api.authentication import bearer_auth -from authentik.core.models import User LOGGER = get_logger() -class AuthJsonConsumer(JsonWebsocketConsumer): +class TokenOutpostMiddleware: """Authorize a client with a token""" - user: User + def __init__(self, inner): + self.inner = inner - def connect(self): - headers = dict(self.scope["headers"]) + async def __call__(self, scope, receive, send): + scope = dict(scope) + await self.auth(scope) + return await self.inner(scope, receive, send) + + @database_sync_to_async + def auth(self, scope): + """Authenticate request from header""" + headers = dict(scope["headers"]) if b"authorization" not in headers: LOGGER.warning("WS Request without authorization header") raise DenyConnection() @@ -32,4 +39,4 @@ class AuthJsonConsumer(JsonWebsocketConsumer): LOGGER.warning("Failed to authenticate", exc=exc) raise DenyConnection() - self.user = user + scope["user"] = user diff --git a/authentik/core/views/interface.py b/authentik/core/views/interface.py index 82f09752c..c71bddbaf 100644 --- a/authentik/core/views/interface.py +++ b/authentik/core/views/interface.py @@ -22,6 +22,7 @@ class InterfaceView(TemplateView): kwargs["version_family"] = f"{LOCAL_VERSION.major}.{LOCAL_VERSION.minor}" kwargs["version_subdomain"] = f"version-{LOCAL_VERSION.major}-{LOCAL_VERSION.minor}" kwargs["build"] = get_build_hash() + kwargs["url_kwargs"] = self.kwargs return super().get_context_data(**kwargs) diff --git a/authentik/enterprise/policy.py b/authentik/enterprise/policy.py index 0c714322a..20bf438a0 100644 --- a/authentik/enterprise/policy.py +++ b/authentik/enterprise/policy.py @@ -1,6 +1,8 @@ """Enterprise license policies""" from typing import Optional +from django.utils.translation import gettext_lazy as _ + from authentik.core.models import User, UserTypes from authentik.enterprise.models import LicenseKey from authentik.policies.types import PolicyRequest, PolicyResult @@ -13,10 +15,10 @@ class EnterprisePolicyAccessView(PolicyAccessView): def check_license(self): """Check license""" if not LicenseKey.get_total().is_valid(): - return False + return PolicyResult(False, _("Enterprise required to access this feature.")) if self.request.user.type != UserTypes.INTERNAL: - return False - return True + return PolicyResult(False, _("Feature only accessible for internal users.")) + return PolicyResult(True) def user_has_access(self, user: Optional[User] = None) -> PolicyResult: user = user or self.request.user @@ -24,7 +26,7 @@ class EnterprisePolicyAccessView(PolicyAccessView): request.http_request = self.request result = super().user_has_access(user) enterprise_result = self.check_license() - if not enterprise_result: + if not enterprise_result.passing: return enterprise_result return result diff --git a/authentik/enterprise/providers/__init__.py b/authentik/enterprise/providers/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/authentik/enterprise/providers/rac/__init__.py b/authentik/enterprise/providers/rac/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/authentik/enterprise/providers/rac/api/__init__.py b/authentik/enterprise/providers/rac/api/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/authentik/enterprise/providers/rac/api/endpoints.py b/authentik/enterprise/providers/rac/api/endpoints.py new file mode 100644 index 000000000..b0b0239c5 --- /dev/null +++ b/authentik/enterprise/providers/rac/api/endpoints.py @@ -0,0 +1,133 @@ +"""RAC Provider API Views""" +from typing import Optional + +from django.core.cache import cache +from django.db.models import QuerySet +from django.urls import reverse +from drf_spectacular.types import OpenApiTypes +from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema +from rest_framework.fields import SerializerMethodField +from rest_framework.request import Request +from rest_framework.response import Response +from rest_framework.serializers import ModelSerializer +from rest_framework.viewsets import ModelViewSet +from structlog.stdlib import get_logger + +from authentik.core.api.used_by import UsedByMixin +from authentik.core.models import Provider +from authentik.enterprise.providers.rac.api.providers import RACProviderSerializer +from authentik.enterprise.providers.rac.models import Endpoint +from authentik.policies.engine import PolicyEngine +from authentik.rbac.filters import ObjectFilter + +LOGGER = get_logger() + + +def user_endpoint_cache_key(user_pk: str) -> str: + """Cache key where endpoint list for user is saved""" + return f"goauthentik.io/providers/rac/endpoint_access/{user_pk}" + + +class EndpointSerializer(ModelSerializer): + """Endpoint Serializer""" + + provider_obj = RACProviderSerializer(source="provider", read_only=True) + launch_url = SerializerMethodField() + + def get_launch_url(self, endpoint: Endpoint) -> Optional[str]: + """Build actual launch URL (the provider itself does not have one, just + individual endpoints)""" + try: + # pylint: disable=no-member + return reverse( + "authentik_providers_rac:start", + kwargs={"app": endpoint.provider.application.slug, "endpoint": endpoint.pk}, + ) + except Provider.application.RelatedObjectDoesNotExist: + return None + + class Meta: + model = Endpoint + fields = [ + "pk", + "name", + "provider", + "provider_obj", + "protocol", + "host", + "settings", + "property_mappings", + "auth_mode", + "launch_url", + ] + + +class EndpointViewSet(UsedByMixin, ModelViewSet): + """Endpoint Viewset""" + + queryset = Endpoint.objects.all() + serializer_class = EndpointSerializer + filterset_fields = ["name", "provider"] + search_fields = ["name", "protocol"] + ordering = ["name", "protocol"] + + def _filter_queryset_for_list(self, queryset: QuerySet) -> QuerySet: + """Custom filter_queryset method which ignores guardian, but still supports sorting""" + for backend in list(self.filter_backends): + if backend == ObjectFilter: + continue + queryset = backend().filter_queryset(self.request, queryset, self) + return queryset + + def _get_allowed_endpoints(self, queryset: QuerySet) -> list[Endpoint]: + endpoints = [] + for endpoint in queryset: + engine = PolicyEngine(endpoint, self.request.user, self.request) + engine.build() + if engine.passing: + endpoints.append(endpoint) + return endpoints + + @extend_schema( + parameters=[ + OpenApiParameter( + "search", + OpenApiTypes.STR, + ), + OpenApiParameter( + name="superuser_full_list", + location=OpenApiParameter.QUERY, + type=OpenApiTypes.BOOL, + ), + ], + responses={ + 200: EndpointSerializer(many=True), + 400: OpenApiResponse(description="Bad request"), + }, + ) + def list(self, request: Request, *args, **kwargs) -> Response: + """List accessible endpoints""" + should_cache = request.GET.get("search", "") == "" + + superuser_full_list = str(request.GET.get("superuser_full_list", "false")).lower() == "true" + if superuser_full_list and request.user.is_superuser: + return super().list(request) + + queryset = self._filter_queryset_for_list(self.get_queryset()) + self.paginate_queryset(queryset) + + allowed_endpoints = [] + if not should_cache: + allowed_endpoints = self._get_allowed_endpoints(queryset) + if should_cache: + allowed_endpoints = cache.get(user_endpoint_cache_key(self.request.user.pk)) + if not allowed_endpoints: + LOGGER.debug("Caching allowed endpoint list") + allowed_endpoints = self._get_allowed_endpoints(queryset) + cache.set( + user_endpoint_cache_key(self.request.user.pk), + allowed_endpoints, + timeout=86400, + ) + serializer = self.get_serializer(allowed_endpoints, many=True) + return self.get_paginated_response(serializer.data) diff --git a/authentik/enterprise/providers/rac/api/property_mappings.py b/authentik/enterprise/providers/rac/api/property_mappings.py new file mode 100644 index 000000000..35daec95c --- /dev/null +++ b/authentik/enterprise/providers/rac/api/property_mappings.py @@ -0,0 +1,35 @@ +"""RAC Provider API Views""" +from rest_framework.fields import CharField +from rest_framework.viewsets import ModelViewSet + +from authentik.core.api.propertymappings import PropertyMappingSerializer +from authentik.core.api.used_by import UsedByMixin +from authentik.core.api.utils import JSONDictField +from authentik.enterprise.providers.rac.models import RACPropertyMapping + + +class RACPropertyMappingSerializer(PropertyMappingSerializer): + """RACPropertyMapping Serializer""" + + static_settings = JSONDictField() + expression = CharField(allow_blank=True, required=False) + + def validate_expression(self, expression: str) -> str: + """Test Syntax""" + if expression == "": + return expression + return super().validate_expression(expression) + + class Meta: + model = RACPropertyMapping + fields = PropertyMappingSerializer.Meta.fields + ["static_settings"] + + +class RACPropertyMappingViewSet(UsedByMixin, ModelViewSet): + """RACPropertyMapping Viewset""" + + queryset = RACPropertyMapping.objects.all() + serializer_class = RACPropertyMappingSerializer + search_fields = ["name"] + ordering = ["name"] + filterset_fields = ["name", "managed"] diff --git a/authentik/enterprise/providers/rac/api/providers.py b/authentik/enterprise/providers/rac/api/providers.py new file mode 100644 index 000000000..6dd4f9f82 --- /dev/null +++ b/authentik/enterprise/providers/rac/api/providers.py @@ -0,0 +1,31 @@ +"""RAC Provider API Views""" +from rest_framework.fields import CharField, ListField +from rest_framework.viewsets import ModelViewSet + +from authentik.core.api.providers import ProviderSerializer +from authentik.core.api.used_by import UsedByMixin +from authentik.enterprise.providers.rac.models import RACProvider + + +class RACProviderSerializer(ProviderSerializer): + """RACProvider Serializer""" + + outpost_set = ListField(child=CharField(), read_only=True, source="outpost_set.all") + + class Meta: + model = RACProvider + fields = ProviderSerializer.Meta.fields + ["settings", "outpost_set", "connection_expiry"] + extra_kwargs = ProviderSerializer.Meta.extra_kwargs + + +class RACProviderViewSet(UsedByMixin, ModelViewSet): + """RACProvider Viewset""" + + queryset = RACProvider.objects.all() + serializer_class = RACProviderSerializer + filterset_fields = { + "application": ["isnull"], + "name": ["iexact"], + } + search_fields = ["name"] + ordering = ["name"] diff --git a/authentik/enterprise/providers/rac/apps.py b/authentik/enterprise/providers/rac/apps.py new file mode 100644 index 000000000..973159bb9 --- /dev/null +++ b/authentik/enterprise/providers/rac/apps.py @@ -0,0 +1,17 @@ +"""RAC app config""" +from authentik.blueprints.apps import ManagedAppConfig + + +class AuthentikEnterpriseProviderRAC(ManagedAppConfig): + """authentik enterprise rac app config""" + + name = "authentik.enterprise.providers.rac" + label = "authentik_providers_rac" + verbose_name = "authentik Enterprise.Providers.RAC" + default = True + mountpoint = "" + ws_mountpoint = "authentik.enterprise.providers.rac.urls" + + def reconcile_load_rac_signals(self): + """Load rac signals""" + self.import_module("authentik.enterprise.providers.rac.signals") diff --git a/authentik/enterprise/providers/rac/consumer_client.py b/authentik/enterprise/providers/rac/consumer_client.py new file mode 100644 index 000000000..57fef7d74 --- /dev/null +++ b/authentik/enterprise/providers/rac/consumer_client.py @@ -0,0 +1,163 @@ +"""RAC Client consumer""" +from asgiref.sync import async_to_sync +from channels.db import database_sync_to_async +from channels.exceptions import ChannelFull, DenyConnection +from channels.generic.websocket import AsyncWebsocketConsumer +from django.http.request import QueryDict +from structlog.stdlib import BoundLogger, get_logger + +from authentik.enterprise.providers.rac.models import ConnectionToken, RACProvider +from authentik.outposts.consumer import OUTPOST_GROUP_INSTANCE +from authentik.outposts.models import Outpost, OutpostState, OutpostType + +# Global broadcast group, which messages are sent to when the outpost connects back +# to authentik for a specific connection +# The `RACClientConsumer` consumer adds itself to this group on connection, +# and removes itself once it has been assigned a specific outpost channel +RAC_CLIENT_GROUP = "group_enterprise_rac_client" +# A group for all connections in a given authentik session ID +# A disconnect message is sent to this group when the session expires/is deleted +RAC_CLIENT_GROUP_SESSION = "group_enterprise_rac_client_%(session)s" +# A group for all connections with a specific token, which in almost all cases +# is just one connection, however this is used to disconnect the connection +# when the token is deleted +RAC_CLIENT_GROUP_TOKEN = "group_enterprise_rac_token_%(token)s" # nosec + +# Step 1: Client connects to this websocket endpoint +# Step 2: We prepare all the connection args for Guac +# Step 3: Send a websocket message to a single outpost that has this provider assigned +# (Currently sending to all of them) +# (Should probably do different load balancing algorithms) +# Step 4: Outpost creates a websocket connection back to authentik +# with /ws/outpost_rac// +# Step 5: This consumer transfers data between the two channels + + +class RACClientConsumer(AsyncWebsocketConsumer): + """RAC client consumer the browser connects to""" + + dest_channel_id: str = "" + provider: RACProvider + token: ConnectionToken + logger: BoundLogger + + async def connect(self): + await self.accept("guacamole") + await self.channel_layer.group_add(RAC_CLIENT_GROUP, self.channel_name) + await self.channel_layer.group_add( + RAC_CLIENT_GROUP_SESSION % {"session": self.scope["session"].session_key}, + self.channel_name, + ) + await self.init_outpost_connection() + + async def disconnect(self, code): + self.logger.debug("Disconnecting") + # Tell the outpost we're disconnecting + await self.channel_layer.send( + self.dest_channel_id, + { + "type": "event.disconnect", + }, + ) + + @database_sync_to_async + def init_outpost_connection(self): + """Initialize guac connection settings""" + self.token = ConnectionToken.filter_not_expired( + token=self.scope["url_route"]["kwargs"]["token"] + ).first() + if not self.token: + raise DenyConnection() + self.provider = self.token.provider + params = self.token.get_settings() + self.logger = get_logger().bind( + endpoint=self.token.endpoint.name, user=self.scope["user"].username + ) + msg = { + "type": "event.provider.specific", + "sub_type": "init_connection", + "dest_channel_id": self.channel_name, + "params": params, + "protocol": self.token.endpoint.protocol, + } + query = QueryDict(self.scope["query_string"].decode()) + for key in ["screen_width", "screen_height", "screen_dpi", "audio"]: + value = query.get(key, None) + if not value: + continue + msg[key] = str(value) + outposts = Outpost.objects.filter( + type=OutpostType.RAC, + providers__in=[self.provider], + ) + if not outposts.exists(): + self.logger.warning("Provider has no outpost") + raise DenyConnection() + for outpost in outposts: + # Sort all states for the outpost by connection count + states = sorted( + OutpostState.for_outpost(outpost), + key=lambda state: int(state.args.get("active_connections", 0)), + ) + if len(states) < 1: + continue + self.logger.debug("Sending out connection broadcast") + async_to_sync(self.channel_layer.group_send)( + OUTPOST_GROUP_INSTANCE % {"outpost_pk": str(outpost.pk), "instance": states[0].uid}, + msg, + ) + + async def receive(self, text_data=None, bytes_data=None): + """Mirror data received from client to the dest_channel_id + which is the channel talking to guacd""" + if self.dest_channel_id == "": + return + if self.token.is_expired: + await self.event_disconnect({"reason": "token_expiry"}) + return + try: + await self.channel_layer.send( + self.dest_channel_id, + { + "type": "event.send", + "text_data": text_data, + "bytes_data": bytes_data, + }, + ) + except ChannelFull: + pass + + async def event_outpost_connected(self, event: dict): + """Handle event broadcasted from outpost consumer, and check if they + created a connection for us""" + outpost_channel = event.get("outpost_channel") + if event.get("client_channel") != self.channel_name: + return + if self.dest_channel_id != "": + # We've already selected an outpost channel, so tell the other channel to disconnect + # This should never happen since we remove ourselves from the broadcast group + await self.channel_layer.send( + outpost_channel, + { + "type": "event.disconnect", + }, + ) + return + self.logger.debug("Connected to a single outpost instance") + self.dest_channel_id = outpost_channel + # Since we have a specific outpost channel now, we can remove + # ourselves from the global broadcast group + await self.channel_layer.group_discard(RAC_CLIENT_GROUP, self.channel_name) + + async def event_send(self, event: dict): + """Handler called by outpost websocket that sends data to this specific + client connection""" + if self.token.is_expired: + await self.event_disconnect({"reason": "token_expiry"}) + return + await self.send(text_data=event.get("text_data"), bytes_data=event.get("bytes_data")) + + async def event_disconnect(self, event: dict): + """Disconnect when the session ends""" + self.logger.info("Disconnecting RAC connection", reason=event.get("reason")) + await self.close() diff --git a/authentik/enterprise/providers/rac/consumer_outpost.py b/authentik/enterprise/providers/rac/consumer_outpost.py new file mode 100644 index 000000000..8fa42d859 --- /dev/null +++ b/authentik/enterprise/providers/rac/consumer_outpost.py @@ -0,0 +1,48 @@ +"""RAC consumer""" +from channels.exceptions import ChannelFull +from channels.generic.websocket import AsyncWebsocketConsumer + +from authentik.enterprise.providers.rac.consumer_client import RAC_CLIENT_GROUP + + +class RACOutpostConsumer(AsyncWebsocketConsumer): + """Consumer the outpost connects to, to send specific data back to a client connection""" + + dest_channel_id: str + + async def connect(self): + self.dest_channel_id = self.scope["url_route"]["kwargs"]["channel"] + await self.accept() + await self.channel_layer.group_send( + RAC_CLIENT_GROUP, + { + "type": "event.outpost.connected", + "outpost_channel": self.channel_name, + "client_channel": self.dest_channel_id, + }, + ) + + async def receive(self, text_data=None, bytes_data=None): + """Mirror data received from guacd running in the outpost + to the dest_channel_id which is the channel talking to the browser""" + try: + await self.channel_layer.send( + self.dest_channel_id, + { + "type": "event.send", + "text_data": text_data, + "bytes_data": bytes_data, + }, + ) + except ChannelFull: + pass + + async def event_send(self, event: dict): + """Handler called by client websocket that sends data to this specific + outpost connection""" + await self.send(text_data=event.get("text_data"), bytes_data=event.get("bytes_data")) + + async def event_disconnect(self, event: dict): + """Tell outpost we're about to disconnect""" + await self.send(text_data="0.authentik.disconnect") + await self.close() diff --git a/authentik/enterprise/providers/rac/controllers/__init__.py b/authentik/enterprise/providers/rac/controllers/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/authentik/enterprise/providers/rac/controllers/docker.py b/authentik/enterprise/providers/rac/controllers/docker.py new file mode 100644 index 000000000..8dac04d06 --- /dev/null +++ b/authentik/enterprise/providers/rac/controllers/docker.py @@ -0,0 +1,11 @@ +"""RAC Provider Docker Controller""" +from authentik.outposts.controllers.docker import DockerController +from authentik.outposts.models import DockerServiceConnection, Outpost + + +class RACDockerController(DockerController): + """RAC Provider Docker Controller""" + + def __init__(self, outpost: Outpost, connection: DockerServiceConnection): + super().__init__(outpost, connection) + self.deployment_ports = [] diff --git a/authentik/enterprise/providers/rac/controllers/kubernetes.py b/authentik/enterprise/providers/rac/controllers/kubernetes.py new file mode 100644 index 000000000..f7768735e --- /dev/null +++ b/authentik/enterprise/providers/rac/controllers/kubernetes.py @@ -0,0 +1,13 @@ +"""RAC Provider Kubernetes Controller""" +from authentik.outposts.controllers.k8s.service import ServiceReconciler +from authentik.outposts.controllers.kubernetes import KubernetesController +from authentik.outposts.models import KubernetesServiceConnection, Outpost + + +class RACKubernetesController(KubernetesController): + """RAC Provider Kubernetes Controller""" + + def __init__(self, outpost: Outpost, connection: KubernetesServiceConnection): + super().__init__(outpost, connection) + self.deployment_ports = [] + del self.reconcilers[ServiceReconciler.reconciler_name()] diff --git a/authentik/enterprise/providers/rac/migrations/0001_initial.py b/authentik/enterprise/providers/rac/migrations/0001_initial.py new file mode 100644 index 000000000..ef8702886 --- /dev/null +++ b/authentik/enterprise/providers/rac/migrations/0001_initial.py @@ -0,0 +1,164 @@ +# Generated by Django 4.2.8 on 2023-12-29 15:58 + +import uuid + +import django.db.models.deletion +from django.db import migrations, models + +import authentik.core.models +import authentik.lib.utils.time + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + ("authentik_policies", "0011_policybinding_failure_result_and_more"), + ("authentik_core", "0032_group_roles"), + ] + + operations = [ + migrations.CreateModel( + name="RACPropertyMapping", + fields=[ + ( + "propertymapping_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="authentik_core.propertymapping", + ), + ), + ("static_settings", models.JSONField(default=dict)), + ], + options={ + "verbose_name": "RAC Property Mapping", + "verbose_name_plural": "RAC Property Mappings", + }, + bases=("authentik_core.propertymapping",), + ), + migrations.CreateModel( + name="RACProvider", + fields=[ + ( + "provider_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="authentik_core.provider", + ), + ), + ("settings", models.JSONField(default=dict)), + ( + "auth_mode", + models.TextField( + choices=[("static", "Static"), ("prompt", "Prompt")], default="prompt" + ), + ), + ( + "connection_expiry", + models.TextField( + default="hours=8", + help_text="Determines how long a session lasts. Default of 0 means that the sessions lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)", + validators=[authentik.lib.utils.time.timedelta_string_validator], + ), + ), + ], + options={ + "verbose_name": "RAC Provider", + "verbose_name_plural": "RAC Providers", + }, + bases=("authentik_core.provider",), + ), + migrations.CreateModel( + name="Endpoint", + fields=[ + ( + "policybindingmodel_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="authentik_policies.policybindingmodel", + ), + ), + ("name", models.TextField()), + ("host", models.TextField()), + ( + "protocol", + models.TextField(choices=[("rdp", "Rdp"), ("vnc", "Vnc"), ("ssh", "Ssh")]), + ), + ("settings", models.JSONField(default=dict)), + ( + "auth_mode", + models.TextField(choices=[("static", "Static"), ("prompt", "Prompt")]), + ), + ( + "property_mappings", + models.ManyToManyField( + blank=True, default=None, to="authentik_core.propertymapping" + ), + ), + ( + "provider", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="authentik_providers_rac.racprovider", + ), + ), + ], + options={ + "verbose_name": "RAC Endpoint", + "verbose_name_plural": "RAC Endpoints", + }, + bases=("authentik_policies.policybindingmodel", models.Model), + ), + migrations.CreateModel( + name="ConnectionToken", + fields=[ + ( + "expires", + models.DateTimeField(default=authentik.core.models.default_token_duration), + ), + ("expiring", models.BooleanField(default=True)), + ( + "connection_token_uuid", + models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False), + ), + ("token", models.TextField(default=authentik.core.models.default_token_key)), + ("settings", models.JSONField(default=dict)), + ( + "endpoint", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="authentik_providers_rac.endpoint", + ), + ), + ( + "provider", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="authentik_providers_rac.racprovider", + ), + ), + ( + "session", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="authentik_core.authenticatedsession", + ), + ), + ], + options={ + "abstract": False, + }, + ), + ] diff --git a/authentik/enterprise/providers/rac/migrations/__init__.py b/authentik/enterprise/providers/rac/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/authentik/enterprise/providers/rac/models.py b/authentik/enterprise/providers/rac/models.py new file mode 100644 index 000000000..d79bbd54c --- /dev/null +++ b/authentik/enterprise/providers/rac/models.py @@ -0,0 +1,191 @@ +"""RAC Models""" +from typing import Optional +from uuid import uuid4 + +from deepmerge import always_merger +from django.db import models +from django.db.models import QuerySet +from django.utils.translation import gettext as _ +from rest_framework.serializers import Serializer +from structlog.stdlib import get_logger + +from authentik.core.exceptions import PropertyMappingExpressionException +from authentik.core.models import ExpiringModel, PropertyMapping, Provider, default_token_key +from authentik.events.models import Event, EventAction +from authentik.lib.models import SerializerModel +from authentik.lib.utils.time import timedelta_string_validator +from authentik.policies.models import PolicyBindingModel + +LOGGER = get_logger() + + +class Protocols(models.TextChoices): + """Supported protocols""" + + RDP = "rdp" + VNC = "vnc" + SSH = "ssh" + + +class AuthenticationMode(models.TextChoices): + """Authentication modes""" + + STATIC = "static" + PROMPT = "prompt" + + +class RACProvider(Provider): + """Remotely access computers/servers""" + + settings = models.JSONField(default=dict) + auth_mode = models.TextField( + choices=AuthenticationMode.choices, default=AuthenticationMode.PROMPT + ) + connection_expiry = models.TextField( + default="hours=8", + validators=[timedelta_string_validator], + help_text=_( + "Determines how long a session lasts. Default of 0 means " + "that the sessions lasts until the browser is closed. " + "(Format: hours=-1;minutes=-2;seconds=-3)" + ), + ) + + @property + def launch_url(self) -> Optional[str]: + """URL to this provider and initiate authorization for the user. + Can return None for providers that are not URL-based""" + return "goauthentik.io://providers/rac/launch" + + @property + def component(self) -> str: + return "ak-provider-rac-form" + + @property + def serializer(self) -> type[Serializer]: + from authentik.enterprise.providers.rac.api.providers import RACProviderSerializer + + return RACProviderSerializer + + class Meta: + verbose_name = _("RAC Provider") + verbose_name_plural = _("RAC Providers") + + +class Endpoint(SerializerModel, PolicyBindingModel): + """Remote-accessible endpoint""" + + name = models.TextField() + host = models.TextField() + protocol = models.TextField(choices=Protocols.choices) + settings = models.JSONField(default=dict) + auth_mode = models.TextField(choices=AuthenticationMode.choices) + provider = models.ForeignKey("RACProvider", on_delete=models.CASCADE) + + property_mappings = models.ManyToManyField( + "authentik_core.PropertyMapping", default=None, blank=True + ) + + @property + def serializer(self) -> type[Serializer]: + from authentik.enterprise.providers.rac.api.endpoints import EndpointSerializer + + return EndpointSerializer + + def __str__(self): + return f"RAC Endpoint {self.name}" + + class Meta: + verbose_name = _("RAC Endpoint") + verbose_name_plural = _("RAC Endpoints") + + +class RACPropertyMapping(PropertyMapping): + """Configure settings for remote access endpoints.""" + + static_settings = models.JSONField(default=dict) + + @property + def component(self) -> str: + return "ak-property-mapping-rac-form" + + @property + def serializer(self) -> type[Serializer]: + from authentik.enterprise.providers.rac.api.property_mappings import ( + RACPropertyMappingSerializer, + ) + + return RACPropertyMappingSerializer + + class Meta: + verbose_name = _("RAC Property Mapping") + verbose_name_plural = _("RAC Property Mappings") + + +class ConnectionToken(ExpiringModel): + """Token for a single connection to a specified endpoint""" + + connection_token_uuid = models.UUIDField(default=uuid4, primary_key=True) + provider = models.ForeignKey(RACProvider, on_delete=models.CASCADE) + endpoint = models.ForeignKey(Endpoint, on_delete=models.CASCADE) + token = models.TextField(default=default_token_key) + settings = models.JSONField(default=dict) + session = models.ForeignKey("authentik_core.AuthenticatedSession", on_delete=models.CASCADE) + + def get_settings(self) -> dict: + """Get settings""" + default_settings = {} + if ":" in self.endpoint.host: + host, _, port = self.endpoint.host.partition(":") + default_settings["hostname"] = host + default_settings["port"] = str(port) + else: + default_settings["hostname"] = self.endpoint.host + default_settings["client-name"] = "authentik" + # default_settings["enable-drive"] = "true" + # default_settings["drive-name"] = "authentik" + settings = {} + always_merger.merge(settings, default_settings) + always_merger.merge(settings, self.endpoint.provider.settings) + always_merger.merge(settings, self.endpoint.settings) + always_merger.merge(settings, self.settings) + + def mapping_evaluator(mappings: QuerySet): + for mapping in mappings: + mapping: RACPropertyMapping + if len(mapping.static_settings) > 0: + always_merger.merge(settings, mapping.static_settings) + continue + try: + mapping_settings = mapping.evaluate( + self.session.user, None, endpoint=self.endpoint, provider=self.provider + ) + always_merger.merge(settings, mapping_settings) + except PropertyMappingExpressionException as exc: + Event.new( + EventAction.CONFIGURATION_ERROR, + message=f"Failed to evaluate property-mapping: '{mapping.name}'", + provider=self.provider, + mapping=mapping, + ).set_user(self.session.user).save() + LOGGER.warning("Failed to evaluate property mapping", exc=exc) + + mapping_evaluator( + RACPropertyMapping.objects.filter(provider__in=[self.provider]).order_by("name") + ) + mapping_evaluator( + RACPropertyMapping.objects.filter(endpoint__in=[self.endpoint]).order_by("name") + ) + + settings["drive-path"] = f"/tmp/connection/{self.token}" # nosec + settings["create-drive-path"] = "true" + # Ensure all values of the settings dict are strings + for key, value in settings.items(): + if isinstance(value, str): + continue + # Special case for bools + if isinstance(value, bool): + settings[key] = str(value).lower() + continue + settings[key] = str(value) + return settings diff --git a/authentik/enterprise/providers/rac/signals.py b/authentik/enterprise/providers/rac/signals.py new file mode 100644 index 000000000..21f727690 --- /dev/null +++ b/authentik/enterprise/providers/rac/signals.py @@ -0,0 +1,54 @@ +"""RAC Signals""" +from asgiref.sync import async_to_sync +from channels.layers import get_channel_layer +from django.contrib.auth.signals import user_logged_out +from django.core.cache import cache +from django.db.models import Model +from django.db.models.signals import post_save, pre_delete +from django.dispatch import receiver +from django.http import HttpRequest + +from authentik.core.models import User +from authentik.enterprise.providers.rac.api.endpoints import user_endpoint_cache_key +from authentik.enterprise.providers.rac.consumer_client import ( + RAC_CLIENT_GROUP_SESSION, + RAC_CLIENT_GROUP_TOKEN, +) +from authentik.enterprise.providers.rac.models import ConnectionToken, Endpoint + + +@receiver(user_logged_out) +def user_logged_out_session(sender, request: HttpRequest, user: User, **_): + """Disconnect any open RAC connections""" + layer = get_channel_layer() + async_to_sync(layer.group_send)( + RAC_CLIENT_GROUP_SESSION + % { + "session": request.session.session_key, + }, + {"type": "event.disconnect", "reason": "session_logout"}, + ) + + +@receiver(pre_delete, sender=ConnectionToken) +def pre_delete_connection_token_disconnect(sender, instance: ConnectionToken, **_): + """Disconnect session when connection token is deleted""" + layer = get_channel_layer() + async_to_sync(layer.group_send)( + RAC_CLIENT_GROUP_TOKEN + % { + "token": instance.token, + }, + {"type": "event.disconnect", "reason": "token_delete"}, + ) + + +@receiver(post_save, sender=Endpoint) +def post_save_application(sender: type[Model], instance, created: bool, **_): + """Clear user's application cache upon application creation""" + if not created: # pragma: no cover + return + + # Delete user endpoint cache + keys = cache.keys(user_endpoint_cache_key("*")) + cache.delete_many(keys) diff --git a/authentik/enterprise/providers/rac/templates/if/rac.html b/authentik/enterprise/providers/rac/templates/if/rac.html new file mode 100644 index 000000000..1d1a03398 --- /dev/null +++ b/authentik/enterprise/providers/rac/templates/if/rac.html @@ -0,0 +1,18 @@ +{% extends "base/skeleton.html" %} + +{% load static %} + +{% block head %} + + + + + +{% include "base/header_js.html" %} +{% endblock %} + +{% block body %} + + + +{% endblock %} diff --git a/authentik/enterprise/providers/rac/tests/__init__.py b/authentik/enterprise/providers/rac/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/authentik/enterprise/providers/rac/tests/test_endpoints_api.py b/authentik/enterprise/providers/rac/tests/test_endpoints_api.py new file mode 100644 index 000000000..0a659bccd --- /dev/null +++ b/authentik/enterprise/providers/rac/tests/test_endpoints_api.py @@ -0,0 +1,168 @@ +"""Test Endpoints API""" + +from django.urls import reverse +from rest_framework.test import APITestCase + +from authentik.core.models import Application +from authentik.core.tests.utils import create_test_admin_user +from authentik.enterprise.providers.rac.models import Endpoint, Protocols, RACProvider +from authentik.lib.generators import generate_id +from authentik.policies.dummy.models import DummyPolicy +from authentik.policies.models import PolicyBinding + + +class TestEndpointsAPI(APITestCase): + """Test endpoints API""" + + def setUp(self) -> None: + self.user = create_test_admin_user() + self.provider = RACProvider.objects.create( + name=generate_id(), + ) + self.app = Application.objects.create( + name=generate_id(), + slug=generate_id(), + provider=self.provider, + ) + self.allowed = Endpoint.objects.create( + name=f"a-{generate_id()}", + host=generate_id(), + protocol=Protocols.RDP, + provider=self.provider, + ) + self.denied = Endpoint.objects.create( + name=f"b-{generate_id()}", + host=generate_id(), + protocol=Protocols.RDP, + provider=self.provider, + ) + PolicyBinding.objects.create( + target=self.denied, + policy=DummyPolicy.objects.create(name="deny", result=False, wait_min=1, wait_max=2), + order=0, + ) + + def test_list(self): + """Test list operation without superuser_full_list""" + self.client.force_login(self.user) + response = self.client.get(reverse("authentik_api:endpoint-list")) + self.assertJSONEqual( + response.content.decode(), + { + "pagination": { + "next": 0, + "previous": 0, + "count": 2, + "current": 1, + "total_pages": 1, + "start_index": 1, + "end_index": 2, + }, + "results": [ + { + "pk": str(self.allowed.pk), + "name": self.allowed.name, + "provider": self.provider.pk, + "provider_obj": { + "pk": self.provider.pk, + "name": self.provider.name, + "authentication_flow": None, + "authorization_flow": None, + "property_mappings": [], + "connection_expiry": "hours=8", + "component": "ak-provider-rac-form", + "assigned_application_slug": self.app.slug, + "assigned_application_name": self.app.name, + "verbose_name": "RAC Provider", + "verbose_name_plural": "RAC Providers", + "meta_model_name": "authentik_providers_rac.racprovider", + "settings": {}, + "outpost_set": [], + }, + "protocol": "rdp", + "host": self.allowed.host, + "settings": {}, + "property_mappings": [], + "auth_mode": "", + "launch_url": f"/application/rac/{self.app.slug}/{str(self.allowed.pk)}/", + }, + ], + }, + ) + + def test_list_superuser_full_list(self): + """Test list operation with superuser_full_list""" + self.client.force_login(self.user) + response = self.client.get( + reverse("authentik_api:endpoint-list") + "?superuser_full_list=true" + ) + self.assertJSONEqual( + response.content.decode(), + { + "pagination": { + "next": 0, + "previous": 0, + "count": 2, + "current": 1, + "total_pages": 1, + "start_index": 1, + "end_index": 2, + }, + "results": [ + { + "pk": str(self.allowed.pk), + "name": self.allowed.name, + "provider": self.provider.pk, + "provider_obj": { + "pk": self.provider.pk, + "name": self.provider.name, + "authentication_flow": None, + "authorization_flow": None, + "property_mappings": [], + "component": "ak-provider-rac-form", + "assigned_application_slug": self.app.slug, + "assigned_application_name": self.app.name, + "connection_expiry": "hours=8", + "verbose_name": "RAC Provider", + "verbose_name_plural": "RAC Providers", + "meta_model_name": "authentik_providers_rac.racprovider", + "settings": {}, + "outpost_set": [], + }, + "protocol": "rdp", + "host": self.allowed.host, + "settings": {}, + "property_mappings": [], + "auth_mode": "", + "launch_url": f"/application/rac/{self.app.slug}/{str(self.allowed.pk)}/", + }, + { + "pk": str(self.denied.pk), + "name": self.denied.name, + "provider": self.provider.pk, + "provider_obj": { + "pk": self.provider.pk, + "name": self.provider.name, + "authentication_flow": None, + "authorization_flow": None, + "property_mappings": [], + "component": "ak-provider-rac-form", + "assigned_application_slug": self.app.slug, + "assigned_application_name": self.app.name, + "connection_expiry": "hours=8", + "verbose_name": "RAC Provider", + "verbose_name_plural": "RAC Providers", + "meta_model_name": "authentik_providers_rac.racprovider", + "settings": {}, + "outpost_set": [], + }, + "protocol": "rdp", + "host": self.denied.host, + "settings": {}, + "property_mappings": [], + "auth_mode": "", + "launch_url": f"/application/rac/{self.app.slug}/{str(self.denied.pk)}/", + }, + ], + }, + ) diff --git a/authentik/enterprise/providers/rac/tests/test_models.py b/authentik/enterprise/providers/rac/tests/test_models.py new file mode 100644 index 000000000..48218f41b --- /dev/null +++ b/authentik/enterprise/providers/rac/tests/test_models.py @@ -0,0 +1,144 @@ +"""Test RAC Models""" +from django.test import TransactionTestCase + +from authentik.core.models import Application, AuthenticatedSession +from authentik.core.tests.utils import create_test_admin_user +from authentik.enterprise.providers.rac.models import ( + ConnectionToken, + Endpoint, + Protocols, + RACPropertyMapping, + RACProvider, +) +from authentik.lib.generators import generate_id + + +class TestModels(TransactionTestCase): + """Test RAC Models""" + + def setUp(self): + self.user = create_test_admin_user() + self.provider = RACProvider.objects.create( + name=generate_id(), + ) + self.app = Application.objects.create( + name=generate_id(), + slug=generate_id(), + provider=self.provider, + ) + self.endpoint = Endpoint.objects.create( + name=generate_id(), + host=f"{generate_id()}:1324", + protocol=Protocols.RDP, + provider=self.provider, + ) + + def test_settings_merge(self): + """Test settings merge""" + token = ConnectionToken.objects.create( + provider=self.provider, + endpoint=self.endpoint, + session=AuthenticatedSession.objects.create( + user=self.user, + session_key=generate_id(), + ), + ) + path = f"/tmp/connection/{token.token}" # nosec + self.assertEqual( + token.get_settings(), + { + "hostname": self.endpoint.host.split(":")[0], + "port": "1324", + "client-name": "authentik", + "drive-path": path, + "create-drive-path": "true", + }, + ) + # Set settings in provider + self.provider.settings = {"level": "provider"} + self.provider.save() + self.assertEqual( + token.get_settings(), + { + "hostname": self.endpoint.host.split(":")[0], + "port": "1324", + "client-name": "authentik", + "drive-path": path, + "create-drive-path": "true", + "level": "provider", + }, + ) + # Set settings in endpoint + self.endpoint.settings = { + "level": "endpoint", + } + self.endpoint.save() + self.assertEqual( + token.get_settings(), + { + "hostname": self.endpoint.host.split(":")[0], + "port": "1324", + "client-name": "authentik", + "drive-path": path, + "create-drive-path": "true", + "level": "endpoint", + }, + ) + # Set settings in token + token.settings = { + "level": "token", + } + token.save() + self.assertEqual( + token.get_settings(), + { + "hostname": self.endpoint.host.split(":")[0], + "port": "1324", + "client-name": "authentik", + "drive-path": path, + "create-drive-path": "true", + "level": "token", + }, + ) + # Set settings in property mapping (provider) + mapping = RACPropertyMapping.objects.create( + name=generate_id(), + expression="""return { + "level": "property_mapping_provider" + }""", + ) + self.provider.property_mappings.add(mapping) + self.assertEqual( + token.get_settings(), + { + "hostname": self.endpoint.host.split(":")[0], + "port": "1324", + "client-name": "authentik", + "drive-path": path, + "create-drive-path": "true", + "level": "property_mapping_provider", + }, + ) + # Set settings in property mapping (endpoint) + mapping = RACPropertyMapping.objects.create( + name=generate_id(), + static_settings={ + "level": "property_mapping_endpoint", + "foo": True, + "bar": 6, + }, + ) + self.endpoint.property_mappings.add(mapping) + self.assertEqual( + token.get_settings(), + { + "hostname": self.endpoint.host.split(":")[0], + "port": "1324", + "client-name": "authentik", + "drive-path": path, + "create-drive-path": "true", + "level": "property_mapping_endpoint", + "foo": "true", + "bar": "6", + }, + ) diff --git a/authentik/enterprise/providers/rac/tests/test_views.py b/authentik/enterprise/providers/rac/tests/test_views.py new file mode 100644 index 000000000..e2fb14a11 --- /dev/null +++ b/authentik/enterprise/providers/rac/tests/test_views.py @@ -0,0 +1,132 @@ +"""RAC Views tests""" +from datetime import timedelta +from json import loads +from time import mktime +from unittest.mock import MagicMock, patch + +from django.urls import reverse +from django.utils.timezone import now +from rest_framework.test import APITestCase + +from authentik.core.models import Application +from authentik.core.tests.utils import create_test_admin_user, create_test_flow +from authentik.enterprise.models import License, LicenseKey +from authentik.enterprise.providers.rac.models import Endpoint, Protocols, RACProvider +from authentik.lib.generators import generate_id +from authentik.policies.denied import AccessDeniedResponse +from authentik.policies.dummy.models import DummyPolicy +from authentik.policies.models import PolicyBinding + + +class TestRACViews(APITestCase): + """RAC Views tests""" + + def setUp(self): + self.user = create_test_admin_user() + self.flow = create_test_flow() + self.provider = RACProvider.objects.create(name=generate_id(), authorization_flow=self.flow) + self.app = Application.objects.create( + name=generate_id(), + slug=generate_id(), + provider=self.provider, + ) + self.endpoint = Endpoint.objects.create( + name=generate_id(), + host=f"{generate_id()}:1324", + protocol=Protocols.RDP, + provider=self.provider, + ) + + @patch( + "authentik.enterprise.models.LicenseKey.validate", + MagicMock( + return_value=LicenseKey( + aud="", + exp=int(mktime((now() + timedelta(days=3000)).timetuple())), + name=generate_id(), + internal_users=100, + external_users=100, + ) + ), + ) + def test_no_policy(self): + """Test request""" + License.objects.create(key=generate_id()) + self.client.force_login(self.user) + response = self.client.get( + reverse( + "authentik_providers_rac:start", + kwargs={"app": self.app.slug, "endpoint": str(self.endpoint.pk)}, + ) + ) + self.assertEqual(response.status_code, 302) + flow_response = self.client.get( + reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}) + ) + body = loads(flow_response.content) + next_url = body["to"] + final_response = self.client.get(next_url) + self.assertEqual(final_response.status_code, 200) + + @patch( + "authentik.enterprise.models.LicenseKey.validate", + MagicMock( + return_value=LicenseKey( + aud="", + exp=int(mktime((now() + timedelta(days=3000)).timetuple())), + name=generate_id(), + internal_users=100, + external_users=100, + ) + ), + ) + def test_app_deny(self): + """Test request (deny on app level)""" + PolicyBinding.objects.create( + target=self.app, + policy=DummyPolicy.objects.create(name="deny", result=False, wait_min=1, wait_max=2), + order=0, + ) + License.objects.create(key=generate_id()) + self.client.force_login(self.user) + response = self.client.get( + reverse( + "authentik_providers_rac:start", + kwargs={"app": self.app.slug, "endpoint": str(self.endpoint.pk)}, + ) + ) + self.assertIsInstance(response, AccessDeniedResponse) + + @patch( + "authentik.enterprise.models.LicenseKey.validate", + MagicMock( + return_value=LicenseKey( + aud="", + exp=int(mktime((now() + timedelta(days=3000)).timetuple())), + name=generate_id(), + internal_users=100, + external_users=100, + ) + ), + ) + def test_endpoint_deny(self): + """Test request (deny on endpoint level)""" + PolicyBinding.objects.create( + target=self.endpoint, + policy=DummyPolicy.objects.create(name="deny", result=False, wait_min=1, wait_max=2), + order=0, + ) + License.objects.create(key=generate_id()) + self.client.force_login(self.user) + response = self.client.get( + reverse( + "authentik_providers_rac:start", + kwargs={"app": self.app.slug, "endpoint": str(self.endpoint.pk)}, + ) + ) + self.assertEqual(response.status_code, 302) + flow_response = self.client.get( + reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}) + ) + body = loads(flow_response.content) + self.assertEqual(body["component"], "ak-stage-access-denied") diff --git a/authentik/enterprise/providers/rac/urls.py b/authentik/enterprise/providers/rac/urls.py new file mode 100644 index 000000000..383619a3a --- /dev/null +++ b/authentik/enterprise/providers/rac/urls.py @@ -0,0 +1,47 @@ +"""rac urls""" +from channels.auth import AuthMiddleware +from channels.sessions import CookieMiddleware +from django.urls import path +from django.views.decorators.csrf import ensure_csrf_cookie + +from authentik.core.channels import TokenOutpostMiddleware +from authentik.enterprise.providers.rac.api.endpoints import EndpointViewSet +from authentik.enterprise.providers.rac.api.property_mappings import RACPropertyMappingViewSet +from authentik.enterprise.providers.rac.api.providers import RACProviderViewSet +from authentik.enterprise.providers.rac.consumer_client import RACClientConsumer +from authentik.enterprise.providers.rac.consumer_outpost import RACOutpostConsumer +from authentik.enterprise.providers.rac.views import RACInterface, RACStartView +from authentik.root.asgi_middleware import SessionMiddleware +from authentik.root.middleware import ChannelsLoggingMiddleware + +urlpatterns = [ + path( + "application/rac///", + ensure_csrf_cookie(RACStartView.as_view()), + name="start", + ), + path( + "if/rac//", + ensure_csrf_cookie(RACInterface.as_view()), + name="if-rac", + ), +] + +websocket_urlpatterns = [ + path( + "ws/rac//", + ChannelsLoggingMiddleware( + CookieMiddleware(SessionMiddleware(AuthMiddleware(RACClientConsumer.as_asgi()))) + ), + ), + path( + "ws/outpost_rac//", + ChannelsLoggingMiddleware(TokenOutpostMiddleware(RACOutpostConsumer.as_asgi())), + ), +] + +api_urlpatterns = [ + ("providers/rac", RACProviderViewSet), + ("propertymappings/rac", RACPropertyMappingViewSet), + ("rac/endpoints", EndpointViewSet), +] diff --git a/authentik/enterprise/providers/rac/views.py b/authentik/enterprise/providers/rac/views.py new file mode 100644 index 000000000..31a25c721 --- /dev/null +++ b/authentik/enterprise/providers/rac/views.py @@ -0,0 +1,115 @@ +"""RAC Views""" +from typing import Any + +from django.http import Http404, HttpRequest, HttpResponse +from django.shortcuts import get_object_or_404, redirect +from django.urls import reverse +from django.utils.timezone import now + +from authentik.core.models import Application, AuthenticatedSession +from authentik.core.views.interface import InterfaceView +from authentik.enterprise.policy import EnterprisePolicyAccessView +from authentik.enterprise.providers.rac.models import ConnectionToken, Endpoint, RACProvider +from authentik.flows.challenge import RedirectChallenge +from authentik.flows.exceptions import FlowNonApplicableException +from authentik.flows.models import in_memory_stage +from authentik.flows.planner import FlowPlanner +from authentik.flows.stage import RedirectStage +from authentik.flows.views.executor import SESSION_KEY_PLAN +from authentik.lib.utils.time import timedelta_from_string +from authentik.lib.utils.urls import redirect_with_qs +from authentik.policies.engine import PolicyEngine + + +class RACStartView(EnterprisePolicyAccessView): + """Start a RAC connection by checking access and creating a connection token""" + + endpoint: Endpoint + + def resolve_provider_application(self): + self.application = get_object_or_404(Application, slug=self.kwargs["app"]) + # Endpoint permissions are validated in the RACFinalStage below + self.endpoint = get_object_or_404(Endpoint, pk=self.kwargs["endpoint"]) + self.provider = RACProvider.objects.get(application=self.application) + + def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse: + """Start flow planner for RAC provider""" + planner = FlowPlanner(self.provider.authorization_flow) + planner.allow_empty_flows = True + try: + plan = planner.plan(self.request) + except FlowNonApplicableException: + raise Http404 + plan.insert_stage( + in_memory_stage( + RACFinalStage, + endpoint=self.endpoint, + provider=self.provider, + ) + ) + request.session[SESSION_KEY_PLAN] = plan + return redirect_with_qs( + "authentik_core:if-flow", + request.GET, + flow_slug=self.provider.authorization_flow.slug, + ) + + +class RACInterface(InterfaceView): + """Start RAC connection""" + + template_name = "if/rac.html" + token: ConnectionToken + + def dispatch(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: + # Early sanity check to ensure token still exists + token = ConnectionToken.filter_not_expired(token=self.kwargs["token"]).first() + if not token: + return redirect("authentik_core:if-user") + self.token = token + return super().dispatch(request, *args, **kwargs) + + def get_context_data(self, **kwargs: Any) -> dict[str, Any]: + kwargs["token"] = self.token + return super().get_context_data(**kwargs) + + +class RACFinalStage(RedirectStage): + """RAC Connection final stage, set the connection token in the stage""" + + def dispatch(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: + endpoint: Endpoint = self.executor.current_stage.endpoint + engine = PolicyEngine(endpoint, self.request.user, self.request) + engine.use_cache = False + engine.build() + passing = engine.result + if not passing.passing: + return self.executor.stage_invalid(", ".join(passing.messages)) + return super().dispatch(request, *args, **kwargs) + + def get_challenge(self, *args, **kwargs) -> RedirectChallenge: + endpoint: Endpoint = self.executor.current_stage.endpoint + provider: RACProvider = self.executor.current_stage.provider + token = ConnectionToken.objects.create( + provider=provider, + endpoint=endpoint, + settings=self.executor.plan.context.get("connection_settings", {}), + session=AuthenticatedSession.objects.filter( + session_key=self.request.session.session_key + ).first(), + expires=now() + timedelta_from_string(provider.connection_expiry), + expiring=True, + ) + setattr( + self.executor.current_stage, + "destination", + self.request.build_absolute_uri( + reverse( + "authentik_providers_rac:if-rac", + kwargs={ + "token": str(token.token), + }, + ) + ), + ) + return super().get_challenge(*args, **kwargs) diff --git a/authentik/enterprise/settings.py b/authentik/enterprise/settings.py index 87aaea71b..f83a327dc 100644 --- a/authentik/enterprise/settings.py +++ b/authentik/enterprise/settings.py @@ -10,3 +10,7 @@ CELERY_BEAT_SCHEDULE = { "options": {"queue": "authentik_scheduled"}, } } + +INSTALLED_APPS = [ + "authentik.enterprise.providers.rac", +] diff --git a/authentik/events/api/events.py b/authentik/events/api/events.py index d2e89ae5b..18b60be2c 100644 --- a/authentik/events/api/events.py +++ b/authentik/events/api/events.py @@ -6,6 +6,7 @@ import django_filters from django.db.models.aggregates import Count from django.db.models.fields.json import KeyTextTransform, KeyTransform from django.db.models.functions import ExtractDay, ExtractHour +from django.db.models.query_utils import Q from drf_spectacular.types import OpenApiTypes from drf_spectacular.utils import OpenApiParameter, extend_schema from guardian.shortcuts import get_objects_for_user @@ -87,7 +88,12 @@ class EventsFilter(django_filters.FilterSet): we need to remove the dashes that a client may send. We can't use a UUIDField for this, as some models might not have a UUID PK""" value = str(value).replace("-", "") - return queryset.filter(context__model__pk=value) + query = Q(context__model__pk=value) + try: + query |= Q(context__model__pk=int(value)) + except ValueError: + pass + return queryset.filter(query) class Meta: model = Event diff --git a/authentik/events/tests/test_api.py b/authentik/events/tests/test_api.py index 1225d0665..98df7bc69 100644 --- a/authentik/events/tests/test_api.py +++ b/authentik/events/tests/test_api.py @@ -1,4 +1,5 @@ """Event API tests""" +from json import loads from django.urls import reverse from rest_framework.test import APITestCase @@ -11,6 +12,9 @@ from authentik.events.models import ( NotificationSeverity, TransportMode, ) +from authentik.events.utils import model_to_dict +from authentik.lib.generators import generate_id +from authentik.providers.oauth2.models import OAuth2Provider class TestEventsAPI(APITestCase): @@ -20,6 +24,25 @@ class TestEventsAPI(APITestCase): self.user = create_test_admin_user() self.client.force_login(self.user) + def test_filter_model_pk_int(self): + """Test event list with context_model_pk and integer PKs""" + provider = OAuth2Provider.objects.create( + name=generate_id(), + ) + event = Event.new(EventAction.MODEL_CREATED, model=model_to_dict(provider)) + event.save() + response = self.client.get( + reverse("authentik_api:event-list"), + data={ + "context_model_pk": provider.pk, + "context_model_app": "authentik_providers_oauth2", + "context_model_name": "oauth2provider", + }, + ) + self.assertEqual(response.status_code, 200) + body = loads(response.content) + self.assertEqual(body["pagination"]["count"], 1) + def test_top_n(self): """Test top_per_user""" event = Event.new(EventAction.AUTHORIZE_APPLICATION) diff --git a/authentik/outposts/api/outposts.py b/authentik/outposts/api/outposts.py index 6219d68ea..182ec4dbf 100644 --- a/authentik/outposts/api/outposts.py +++ b/authentik/outposts/api/outposts.py @@ -17,6 +17,7 @@ from authentik.core.api.providers import ProviderSerializer from authentik.core.api.used_by import UsedByMixin from authentik.core.api.utils import JSONDictField, PassiveSerializer from authentik.core.models import Provider +from authentik.enterprise.providers.rac.models import RACProvider from authentik.outposts.api.service_connections import ServiceConnectionSerializer from authentik.outposts.apps import MANAGED_OUTPOST, MANAGED_OUTPOST_NAME from authentik.outposts.models import ( @@ -63,6 +64,7 @@ class OutpostSerializer(ModelSerializer): OutpostType.LDAP: LDAPProvider, OutpostType.PROXY: ProxyProvider, OutpostType.RADIUS: RadiusProvider, + OutpostType.RAC: RACProvider, None: Provider, } for provider in providers: diff --git a/authentik/outposts/consumer.py b/authentik/outposts/consumer.py index dda3feed0..6ed2926b8 100644 --- a/authentik/outposts/consumer.py +++ b/authentik/outposts/consumer.py @@ -6,16 +6,18 @@ from typing import Any, Optional from asgiref.sync import async_to_sync from channels.exceptions import DenyConnection +from channels.generic.websocket import JsonWebsocketConsumer from dacite.core import from_dict from dacite.data import Data +from django.http.request import QueryDict from guardian.shortcuts import get_objects_for_user from structlog.stdlib import BoundLogger, get_logger -from authentik.core.channels import AuthJsonConsumer from authentik.outposts.apps import GAUGE_OUTPOSTS_CONNECTED, GAUGE_OUTPOSTS_LAST_UPDATE from authentik.outposts.models import OUTPOST_HELLO_INTERVAL, Outpost, OutpostState OUTPOST_GROUP = "group_outpost_%(outpost_pk)s" +OUTPOST_GROUP_INSTANCE = "group_outpost_%(outpost_pk)s_%(instance)s" class WebsocketMessageInstruction(IntEnum): @@ -42,25 +44,23 @@ class WebsocketMessage: args: dict[str, Any] = field(default_factory=dict) -class OutpostConsumer(AuthJsonConsumer): +class OutpostConsumer(JsonWebsocketConsumer): """Handler for Outposts that connect over websockets for health checks and live updates""" outpost: Optional[Outpost] = None logger: BoundLogger - last_uid: Optional[str] = None + instance_uid: Optional[str] = None def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.logger = get_logger() def connect(self): - super().connect() uuid = self.scope["url_route"]["kwargs"]["pk"] + user = self.scope["user"] outpost = ( - get_objects_for_user(self.user, "authentik_outposts.view_outpost") - .filter(pk=uuid) - .first() + get_objects_for_user(user, "authentik_outposts.view_outpost").filter(pk=uuid).first() ) if not outpost: raise DenyConnection() @@ -71,13 +71,19 @@ class OutpostConsumer(AuthJsonConsumer): self.logger.warning("runtime error during accept", exc=exc) raise DenyConnection() self.outpost = outpost - self.last_uid = self.channel_name + query = QueryDict(self.scope["query_string"].decode()) + self.instance_uid = query.get("instance_uuid", self.channel_name) async_to_sync(self.channel_layer.group_add)( OUTPOST_GROUP % {"outpost_pk": str(self.outpost.pk)}, self.channel_name ) + async_to_sync(self.channel_layer.group_add)( + OUTPOST_GROUP_INSTANCE + % {"outpost_pk": str(self.outpost.pk), "instance": self.instance_uid}, + self.channel_name, + ) GAUGE_OUTPOSTS_CONNECTED.labels( outpost=self.outpost.name, - uid=self.last_uid, + uid=self.instance_uid, expected=self.outpost.config.kubernetes_replicas, ).inc() @@ -86,34 +92,37 @@ class OutpostConsumer(AuthJsonConsumer): async_to_sync(self.channel_layer.group_discard)( OUTPOST_GROUP % {"outpost_pk": str(self.outpost.pk)}, self.channel_name ) - if self.outpost and self.last_uid: + if self.instance_uid: + async_to_sync(self.channel_layer.group_discard)( + OUTPOST_GROUP_INSTANCE + % {"outpost_pk": str(self.outpost.pk), "instance": self.instance_uid}, + self.channel_name, + ) + if self.outpost and self.instance_uid: GAUGE_OUTPOSTS_CONNECTED.labels( outpost=self.outpost.name, - uid=self.last_uid, + uid=self.instance_uid, expected=self.outpost.config.kubernetes_replicas, ).dec() def receive_json(self, content: Data, **kwargs): msg = from_dict(WebsocketMessage, content) - uid = msg.args.get("uuid", self.channel_name) - self.last_uid = uid - if not self.outpost: raise DenyConnection() - state = OutpostState.for_instance_uid(self.outpost, uid) + state = OutpostState.for_instance_uid(self.outpost, self.instance_uid) state.last_seen = datetime.now() state.hostname = msg.args.pop("hostname", "") if msg.instruction == WebsocketMessageInstruction.HELLO: state.version = msg.args.pop("version", None) state.build_hash = msg.args.pop("buildHash", "") - state.args = msg.args + state.args.update(msg.args) elif msg.instruction == WebsocketMessageInstruction.ACK: return GAUGE_OUTPOSTS_LAST_UPDATE.labels( outpost=self.outpost.name, - uid=self.last_uid or "", + uid=self.instance_uid or "", version=state.version or "", ).set_to_current_time() state.save(timeout=OUTPOST_HELLO_INTERVAL * 1.5) diff --git a/authentik/outposts/controllers/k8s/utils.py b/authentik/outposts/controllers/k8s/utils.py index d1f01811f..e9c83f975 100644 --- a/authentik/outposts/controllers/k8s/utils.py +++ b/authentik/outposts/controllers/k8s/utils.py @@ -1,5 +1,6 @@ """k8s utils""" from pathlib import Path +from typing import Optional from kubernetes.client.models.v1_container_port import V1ContainerPort from kubernetes.client.models.v1_service_port import V1ServicePort @@ -37,9 +38,12 @@ def compare_port( def compare_ports( - current: list[V1ServicePort | V1ContainerPort], reference: list[V1ServicePort | V1ContainerPort] + current: Optional[list[V1ServicePort | V1ContainerPort]], + reference: Optional[list[V1ServicePort | V1ContainerPort]], ): """Compare ports of a list""" + if not current or not reference: + raise NeedsRecreate() if len(current) != len(reference): raise NeedsRecreate() for port in reference: diff --git a/authentik/outposts/controllers/kubernetes.py b/authentik/outposts/controllers/kubernetes.py index e3a943e2c..e3b358078 100644 --- a/authentik/outposts/controllers/kubernetes.py +++ b/authentik/outposts/controllers/kubernetes.py @@ -81,7 +81,10 @@ class KubernetesController(BaseController): def up(self): try: for reconcile_key in self.reconcile_order: - reconciler = self.reconcilers[reconcile_key](self) + reconciler_cls = self.reconcilers.get(reconcile_key) + if not reconciler_cls: + continue + reconciler = reconciler_cls(self) reconciler.up() except (OpenApiException, HTTPError, ServiceConnectionInvalid) as exc: @@ -95,7 +98,10 @@ class KubernetesController(BaseController): all_logs += [f"{reconcile_key.title()}: Disabled"] continue with capture_logs() as logs: - reconciler = self.reconcilers[reconcile_key](self) + reconciler_cls = self.reconcilers.get(reconcile_key) + if not reconciler_cls: + continue + reconciler = reconciler_cls(self) reconciler.up() all_logs += [f"{reconcile_key.title()}: {x['event']}" for x in logs] return all_logs @@ -105,7 +111,10 @@ class KubernetesController(BaseController): def down(self): try: for reconcile_key in self.reconcile_order: - reconciler = self.reconcilers[reconcile_key](self) + reconciler_cls = self.reconcilers.get(reconcile_key) + if not reconciler_cls: + continue + reconciler = reconciler_cls(self) self.logger.debug("Tearing down object", name=reconcile_key) reconciler.down() @@ -120,7 +129,10 @@ class KubernetesController(BaseController): all_logs += [f"{reconcile_key.title()}: Disabled"] continue with capture_logs() as logs: - reconciler = self.reconcilers[reconcile_key](self) + reconciler_cls = self.reconcilers.get(reconcile_key) + if not reconciler_cls: + continue + reconciler = reconciler_cls(self) reconciler.down() all_logs += [f"{reconcile_key.title()}: {x['event']}" for x in logs] return all_logs @@ -130,7 +142,10 @@ class KubernetesController(BaseController): def get_static_deployment(self) -> str: documents = [] for reconcile_key in self.reconcile_order: - reconciler = self.reconcilers[reconcile_key](self) + reconciler_cls = self.reconcilers.get(reconcile_key) + if not reconciler_cls: + continue + reconciler = reconciler_cls(self) if reconciler.noop: continue documents.append(reconciler.get_reference_object().to_dict()) diff --git a/authentik/outposts/migrations/0021_alter_outpost_type.py b/authentik/outposts/migrations/0021_alter_outpost_type.py new file mode 100644 index 000000000..52fcf1fd5 --- /dev/null +++ b/authentik/outposts/migrations/0021_alter_outpost_type.py @@ -0,0 +1,25 @@ +# Generated by Django 4.2.6 on 2023-10-14 19:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("authentik_outposts", "0020_alter_outpost_type"), + ] + + operations = [ + migrations.AlterField( + model_name="outpost", + name="type", + field=models.TextField( + choices=[ + ("proxy", "Proxy"), + ("ldap", "Ldap"), + ("radius", "Radius"), + ("rac", "Rac"), + ], + default="proxy", + ), + ), + ] diff --git a/authentik/outposts/models.py b/authentik/outposts/models.py index 14f896c35..bcaeda8b8 100644 --- a/authentik/outposts/models.py +++ b/authentik/outposts/models.py @@ -90,11 +90,12 @@ class OutpostModel(Model): class OutpostType(models.TextChoices): - """Outpost types, currently only the reverse proxy is available""" + """Outpost types""" PROXY = "proxy" LDAP = "ldap" RADIUS = "radius" + RAC = "rac" def default_outpost_config(host: Optional[str] = None): @@ -459,7 +460,7 @@ class OutpostState: def for_instance_uid(outpost: Outpost, uid: str) -> "OutpostState": """Get state for a single instance""" key = f"{outpost.state_cache_prefix}/{uid}" - default_data = {"uid": uid, "channel_ids": []} + default_data = {"uid": uid} data = cache.get(key, default_data) if isinstance(data, str): cache.delete(key) diff --git a/authentik/outposts/tasks.py b/authentik/outposts/tasks.py index b6b3a9bab..0d4e54a3a 100644 --- a/authentik/outposts/tasks.py +++ b/authentik/outposts/tasks.py @@ -17,6 +17,8 @@ from kubernetes.config.kube_config import KUBE_CONFIG_DEFAULT_LOCATION from structlog.stdlib import get_logger from yaml import safe_load +from authentik.enterprise.providers.rac.controllers.docker import RACDockerController +from authentik.enterprise.providers.rac.controllers.kubernetes import RACKubernetesController from authentik.events.monitored_tasks import ( MonitoredTask, TaskResult, @@ -71,6 +73,11 @@ def controller_for_outpost(outpost: Outpost) -> Optional[type[BaseController]]: return RadiusDockerController if isinstance(service_connection, KubernetesServiceConnection): return RadiusKubernetesController + if outpost.type == OutpostType.RAC: + if isinstance(service_connection, DockerServiceConnection): + return RACDockerController + if isinstance(service_connection, KubernetesServiceConnection): + return RACKubernetesController return None diff --git a/authentik/outposts/tests/test_ws.py b/authentik/outposts/tests/test_ws.py index b8fcba925..ec3d543a3 100644 --- a/authentik/outposts/tests/test_ws.py +++ b/authentik/outposts/tests/test_ws.py @@ -1,6 +1,7 @@ """Websocket tests""" from dataclasses import asdict +from channels.exceptions import DenyConnection from channels.routing import URLRouter from channels.testing import WebsocketCommunicator from django.test import TransactionTestCase @@ -35,8 +36,9 @@ class TestOutpostWS(TransactionTestCase): communicator = WebsocketCommunicator( URLRouter(websocket.websocket_urlpatterns), f"/ws/outpost/{self.outpost.pk}/" ) - connected, _ = await communicator.connect() - self.assertFalse(connected) + with self.assertRaises(DenyConnection): + connected, _ = await communicator.connect() + self.assertFalse(connected) async def test_auth_valid(self): """Test auth with token""" diff --git a/authentik/outposts/urls.py b/authentik/outposts/urls.py index cd7ba3bf8..9d28a01eb 100644 --- a/authentik/outposts/urls.py +++ b/authentik/outposts/urls.py @@ -1,6 +1,7 @@ """Outpost Websocket URLS""" from django.urls import path +from authentik.core.channels import TokenOutpostMiddleware from authentik.outposts.api.outposts import OutpostViewSet from authentik.outposts.api.service_connections import ( DockerServiceConnectionViewSet, @@ -11,7 +12,10 @@ from authentik.outposts.consumer import OutpostConsumer from authentik.root.middleware import ChannelsLoggingMiddleware websocket_urlpatterns = [ - path("ws/outpost//", ChannelsLoggingMiddleware(OutpostConsumer.as_asgi())), + path( + "ws/outpost//", + ChannelsLoggingMiddleware(TokenOutpostMiddleware(OutpostConsumer.as_asgi())), + ), ] api_urlpatterns = [ diff --git a/blueprints/schema.json b/blueprints/schema.json index 523f6e10d..07d9cd227 100644 --- a/blueprints/schema.json +++ b/blueprints/schema.json @@ -2779,6 +2779,117 @@ } } }, + { + "type": "object", + "required": [ + "model", + "identifiers" + ], + "properties": { + "model": { + "const": "authentik_providers_rac.racprovider" + }, + "id": { + "type": "string" + }, + "state": { + "type": "string", + "enum": [ + "absent", + "present", + "created", + "must_created" + ], + "default": "present" + }, + "conditions": { + "type": "array", + "items": { + "type": "boolean" + } + }, + "attrs": { + "$ref": "#/$defs/model_authentik_providers_rac.racprovider" + }, + "identifiers": { + "$ref": "#/$defs/model_authentik_providers_rac.racprovider" + } + } + }, + { + "type": "object", + "required": [ + "model", + "identifiers" + ], + "properties": { + "model": { + "const": "authentik_providers_rac.endpoint" + }, + "id": { + "type": "string" + }, + "state": { + "type": "string", + "enum": [ + "absent", + "present", + "created", + "must_created" + ], + "default": "present" + }, + "conditions": { + "type": "array", + "items": { + "type": "boolean" + } + }, + "attrs": { + "$ref": "#/$defs/model_authentik_providers_rac.endpoint" + }, + "identifiers": { + "$ref": "#/$defs/model_authentik_providers_rac.endpoint" + } + } + }, + { + "type": "object", + "required": [ + "model", + "identifiers" + ], + "properties": { + "model": { + "const": "authentik_providers_rac.racpropertymapping" + }, + "id": { + "type": "string" + }, + "state": { + "type": "string", + "enum": [ + "absent", + "present", + "created", + "must_created" + ], + "default": "present" + }, + "conditions": { + "type": "array", + "items": { + "type": "boolean" + } + }, + "attrs": { + "$ref": "#/$defs/model_authentik_providers_rac.racpropertymapping" + }, + "identifiers": { + "$ref": "#/$defs/model_authentik_providers_rac.racpropertymapping" + } + } + }, { "type": "object", "required": [ @@ -3296,7 +3407,8 @@ "enum": [ "proxy", "ldap", - "radius" + "radius", + "rac" ], "title": "Type" }, @@ -3476,7 +3588,8 @@ "authentik.tenants", "authentik.blueprints", "authentik.core", - "authentik.enterprise" + "authentik.enterprise", + "authentik.enterprise.providers.rac" ], "title": "App", "description": "Match events created by selected application. When left empty, all applications are matched." @@ -3561,7 +3674,10 @@ "authentik_core.user", "authentik_core.application", "authentik_core.token", - "authentik_enterprise.license" + "authentik_enterprise.license", + "authentik_providers_rac.racprovider", + "authentik_providers_rac.endpoint", + "authentik_providers_rac.racpropertymapping" ], "title": "Model", "description": "Match events created by selected model. When left empty, all models are matched. When an app is selected, all the application's models are matched." @@ -8758,6 +8874,123 @@ }, "required": [] }, + "model_authentik_providers_rac.racprovider": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "title": "Name" + }, + "authentication_flow": { + "type": "integer", + "title": "Authentication flow", + "description": "Flow used for authentication when the associated application is accessed by an un-authenticated user." + }, + "authorization_flow": { + "type": "integer", + "title": "Authorization flow", + "description": "Flow used when authorizing this provider." + }, + "property_mappings": { + "type": "array", + "items": { + "type": "integer" + }, + "title": "Property mappings" + }, + "settings": { + "type": "object", + "additionalProperties": true, + "title": "Settings" + }, + "connection_expiry": { + "type": "string", + "minLength": 1, + "title": "Connection expiry", + "description": "Determines how long a session lasts. Default of 0 means that the sessions lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)" + } + }, + "required": [] + }, + "model_authentik_providers_rac.endpoint": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "title": "Name" + }, + "provider": { + "type": "integer", + "title": "Provider" + }, + "protocol": { + "type": "string", + "enum": [ + "rdp", + "vnc", + "ssh" + ], + "title": "Protocol" + }, + "host": { + "type": "string", + "minLength": 1, + "title": "Host" + }, + "settings": { + "type": "object", + "additionalProperties": true, + "title": "Settings" + }, + "property_mappings": { + "type": "array", + "items": { + "type": "integer" + }, + "title": "Property mappings" + }, + "auth_mode": { + "type": "string", + "enum": [ + "static", + "prompt" + ], + "title": "Auth mode" + } + }, + "required": [] + }, + "model_authentik_providers_rac.racpropertymapping": { + "type": "object", + "properties": { + "managed": { + "type": [ + "string", + "null" + ], + "minLength": 1, + "title": "Managed by authentik", + "description": "Objects that are managed by authentik. These objects are created and updated automatically. This flag only indicates that an object can be overwritten by migrations. You can still modify the objects via the API, but expect changes to be overwritten in a later update." + }, + "name": { + "type": "string", + "minLength": 1, + "title": "Name" + }, + "expression": { + "type": "string", + "title": "Expression" + }, + "static_settings": { + "type": "object", + "additionalProperties": true, + "title": "Static settings" + } + }, + "required": [] + }, "model_authentik_blueprints.metaapplyblueprint": { "type": "object", "properties": { diff --git a/blueprints/system/providers-rac.yaml b/blueprints/system/providers-rac.yaml new file mode 100644 index 000000000..63a568673 --- /dev/null +++ b/blueprints/system/providers-rac.yaml @@ -0,0 +1,32 @@ +version: 1 +metadata: + labels: + blueprints.goauthentik.io/system: "true" + name: System - RAC Provider - Mappings +entries: + - identifiers: + managed: goauthentik.io/providers/rac/rdp-default + model: authentik_providers_rac.racpropertymapping + attrs: + name: "authentik default RAC Mapping: RDP Default settings" + static_settings: + resize-method: "display-update" + enable-wallpaper: "true" + enable-font-smoothing: "true" + - identifiers: + managed: goauthentik.io/providers/rac/rdp-high-fidelity + model: authentik_providers_rac.racpropertymapping + attrs: + name: "authentik default RAC Mapping: RDP High Fidelity" + static_settings: + enable-theming: "true" + enable-full-window-drag: "true" + enable-desktop-composition: "true" + enable-menu-animations: "true" + - identifiers: + managed: goauthentik.io/providers/rac/ssh-default + model: authentik_providers_rac.racpropertymapping + attrs: + name: "authentik default RAC Mapping: SSH Default settings" + static_settings: + terminal-type: "xterm-256color" diff --git a/cmd/rac/main.go b/cmd/rac/main.go new file mode 100644 index 000000000..947ad14dd --- /dev/null +++ b/cmd/rac/main.go @@ -0,0 +1,93 @@ +package main + +import ( + "fmt" + "net/url" + "os" + + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + + "goauthentik.io/internal/common" + "goauthentik.io/internal/debug" + "goauthentik.io/internal/outpost/ak" + "goauthentik.io/internal/outpost/ak/healthcheck" + "goauthentik.io/internal/outpost/rac" +) + +const helpMessage = `authentik RAC + +Required environment variables: +- AUTHENTIK_HOST: URL to connect to (format "http://authentik.company") +- AUTHENTIK_TOKEN: Token to authenticate with +- AUTHENTIK_INSECURE: Skip SSL Certificate verification` + +var rootCmd = &cobra.Command{ + Long: helpMessage, + PersistentPreRun: func(cmd *cobra.Command, args []string) { + log.SetLevel(log.DebugLevel) + log.SetFormatter(&log.JSONFormatter{ + FieldMap: log.FieldMap{ + log.FieldKeyMsg: "event", + log.FieldKeyTime: "timestamp", + }, + DisableHTMLEscape: true, + }) + }, + Run: func(cmd *cobra.Command, args []string) { + debug.EnableDebugServer() + akURL, found := os.LookupEnv("AUTHENTIK_HOST") + if !found { + fmt.Println("env AUTHENTIK_HOST not set!") + fmt.Println(helpMessage) + os.Exit(1) + } + akToken, found := os.LookupEnv("AUTHENTIK_TOKEN") + if !found { + fmt.Println("env AUTHENTIK_TOKEN not set!") + fmt.Println(helpMessage) + os.Exit(1) + } + + akURLActual, err := url.Parse(akURL) + if err != nil { + fmt.Println(err) + fmt.Println(helpMessage) + os.Exit(1) + } + + ex := common.Init() + defer common.Defer() + go func() { + for { + <-ex + os.Exit(0) + } + }() + + ac := ak.NewAPIController(*akURLActual, akToken) + if ac == nil { + os.Exit(1) + } + defer ac.Shutdown() + + ac.Server = rac.NewServer(ac) + + err = ac.Start() + if err != nil { + log.WithError(err).Panic("Failed to run server") + } + + for { + <-ex + } + }, +} + +func main() { + rootCmd.AddCommand(healthcheck.Command) + err := rootCmd.Execute() + if err != nil { + os.Exit(1) + } +} diff --git a/go.mod b/go.mod index 52f4ac7c5..269d4c295 100644 --- a/go.mod +++ b/go.mod @@ -27,6 +27,7 @@ require ( github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.4 + github.com/wwt/guac v1.3.2 goauthentik.io/api/v3 v3.2023105.2 golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab golang.org/x/oauth2 v0.15.0 diff --git a/go.sum b/go.sum index e181e30db..d9acde526 100644 --- a/go.sum +++ b/go.sum @@ -195,6 +195,7 @@ github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kX github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY= github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ= +github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -210,6 +211,7 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -262,6 +264,7 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= @@ -269,8 +272,10 @@ github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyh github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -281,6 +286,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/wwt/guac v1.3.2 h1:sH6OFGa/1tBs7ieWBVlZe7t6F5JAOWBry/tqQL/Vup4= +github.com/wwt/guac v1.3.2/go.mod h1:eKm+NrnK7A88l4UBEcYNpZQGMpZRryYKoz4D/0/n1C0= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= @@ -414,6 +421,7 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/internal/outpost/ak/api.go b/internal/outpost/ak/api.go index 34a30cbea..1f744010a 100644 --- a/internal/outpost/ak/api.go +++ b/internal/outpost/ak/api.go @@ -159,8 +159,8 @@ func (a *APIController) AddRefreshHandler(handler func()) { a.refreshHandlers = append(a.refreshHandlers, handler) } -func (a *APIController) AddWSHandler(handler WSHandler) { - a.wsHandlers = append(a.wsHandlers, handler) +func (a *APIController) Token() string { + return a.token } func (a *APIController) OnRefresh() error { @@ -182,7 +182,7 @@ func (a *APIController) OnRefresh() error { return err } -func (a *APIController) getWebsocketArgs() map[string]interface{} { +func (a *APIController) getWebsocketPingArgs() map[string]interface{} { args := map[string]interface{}{ "version": constants.VERSION, "buildHash": constants.BUILD("tagged"), diff --git a/internal/outpost/ak/api_ws.go b/internal/outpost/ak/api_ws.go index 24c5099f4..c48cebba3 100644 --- a/internal/outpost/ak/api_ws.go +++ b/internal/outpost/ak/api_ws.go @@ -18,6 +18,8 @@ import ( func (ac *APIController) initWS(akURL url.URL, outpostUUID string) error { pathTemplate := "%s://%s/ws/outpost/%s/?%s" + query := akURL.Query() + query.Set("instance_uuid", ac.instanceUUID.String()) scheme := strings.ReplaceAll(akURL.Scheme, "http", "ws") authHeader := fmt.Sprintf("Bearer %s", ac.token) @@ -45,7 +47,7 @@ func (ac *APIController) initWS(akURL url.URL, outpostUUID string) error { // Send hello message with our version msg := websocketMessage{ Instruction: WebsocketInstructionHello, - Args: ac.getWebsocketArgs(), + Args: ac.getWebsocketPingArgs(), } err = ws.WriteJSON(msg) if err != nil { @@ -53,7 +55,7 @@ func (ac *APIController) initWS(akURL url.URL, outpostUUID string) error { return err } ac.lastWsReconnect = time.Now() - ac.logger.WithField("logger", "authentik.outpost.ak-ws").WithField("outpost", outpostUUID).Debug("Successfully connected websocket") + ac.logger.WithField("logger", "authentik.outpost.ak-ws").WithField("outpost", outpostUUID).Info("Successfully connected websocket") return nil } @@ -157,23 +159,19 @@ func (ac *APIController) startWSHandler() { func (ac *APIController) startWSHealth() { ticker := time.NewTicker(time.Second * 10) for ; true; <-ticker.C { - aliveMsg := websocketMessage{ - Instruction: WebsocketInstructionHello, - Args: ac.getWebsocketArgs(), - } if ac.wsConn == nil { go ac.reconnectWS() time.Sleep(time.Second * 5) continue } - err := ac.wsConn.WriteJSON(aliveMsg) - ac.logger.WithField("loop", "ws-health").Trace("hello'd") + err := ac.SendWSHello(map[string]interface{}{}) if err != nil { ac.logger.WithField("loop", "ws-health").WithError(err).Warning("ws write error") go ac.reconnectWS() time.Sleep(time.Second * 5) continue } else { + ac.logger.WithField("loop", "ws-health").Trace("hello'd") ConnectionStatus.With(prometheus.Labels{ "outpost_name": ac.Outpost.Name, "outpost_type": ac.Server.Type(), @@ -202,3 +200,20 @@ func (ac *APIController) startIntervalUpdater() { } } } + +func (a *APIController) AddWSHandler(handler WSHandler) { + a.wsHandlers = append(a.wsHandlers, handler) +} + +func (a *APIController) SendWSHello(args map[string]interface{}) error { + allArgs := a.getWebsocketPingArgs() + for key, value := range args { + allArgs[key] = value + } + aliveMsg := websocketMessage{ + Instruction: WebsocketInstructionHello, + Args: allArgs, + } + err := a.wsConn.WriteJSON(aliveMsg) + return err +} diff --git a/internal/outpost/rac/connection/connection.go b/internal/outpost/rac/connection/connection.go new file mode 100644 index 000000000..53ca9ecb0 --- /dev/null +++ b/internal/outpost/rac/connection/connection.go @@ -0,0 +1,124 @@ +package connection + +import ( + "context" + "crypto/tls" + "fmt" + "net" + "net/http" + "strings" + "time" + + "github.com/gorilla/websocket" + log "github.com/sirupsen/logrus" + "github.com/wwt/guac" + "goauthentik.io/internal/config" + "goauthentik.io/internal/constants" + "goauthentik.io/internal/outpost/ak" +) + +const guacAddr = "0.0.0.0:4822" + +type Connection struct { + log *log.Entry + st *guac.SimpleTunnel + ac *ak.APIController + ws *websocket.Conn + ctx context.Context + ctxCancel context.CancelFunc + OnError func(error) + closing bool +} + +func NewConnection(ac *ak.APIController, forChannel string, cfg *guac.Config) (*Connection, error) { + ctx, canc := context.WithCancel(context.Background()) + c := &Connection{ + ac: ac, + log: log.WithField("connection", forChannel), + ctx: ctx, + ctxCancel: canc, + OnError: func(err error) {}, + closing: false, + } + err := c.initGuac(cfg) + if err != nil { + return nil, err + } + err = c.initSocket(forChannel) + if err != nil { + _ = c.st.Close() + return nil, err + } + c.initMirror() + return c, nil +} + +func (c *Connection) initSocket(forChannel string) error { + pathTemplate := "%s://%s/ws/outpost_rac/%s/" + scheme := strings.ReplaceAll(c.ac.Client.GetConfig().Scheme, "http", "ws") + + authHeader := fmt.Sprintf("Bearer %s", c.ac.Token()) + + header := http.Header{ + "Authorization": []string{authHeader}, + "User-Agent": []string{constants.OutpostUserAgent()}, + } + + dialer := websocket.Dialer{ + Proxy: http.ProxyFromEnvironment, + HandshakeTimeout: 10 * time.Second, + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: config.Get().AuthentikInsecure, + }, + } + + url := fmt.Sprintf(pathTemplate, scheme, c.ac.Client.GetConfig().Host, forChannel) + ws, _, err := dialer.Dial(url, header) + if err != nil { + c.log.WithError(err).Warning("failed to connect websocket") + return err + } + c.ws = ws + return nil +} + +func (c *Connection) initGuac(cfg *guac.Config) error { + addr, err := net.ResolveTCPAddr("tcp", guacAddr) + if err != nil { + return err + } + + conn, err := net.DialTCP("tcp", nil, addr) + if err != nil { + return err + } + + stream := guac.NewStream(conn, guac.SocketTimeout) + + err = stream.Handshake(cfg) + if err != nil { + return err + } + st := guac.NewSimpleTunnel(stream) + c.st = st + return nil +} + +func (c *Connection) initMirror() { + go c.wsToGuacd() + go c.guacdToWs() +} + +func (c *Connection) onError(err error) { + if c.closing { + return + } + c.closing = true + e := c.st.Close() + if e != nil { + c.log.WithError(e).Warning("failed to close guacd connection") + } + c.log.WithError(err).Info("removing connection") + c.ctxCancel() + c.OnError(err) +} diff --git a/internal/outpost/rac/connection/mirror.go b/internal/outpost/rac/connection/mirror.go new file mode 100644 index 000000000..7475c6efc --- /dev/null +++ b/internal/outpost/rac/connection/mirror.go @@ -0,0 +1,103 @@ +package connection + +import ( + "bytes" + "fmt" + + "github.com/gorilla/websocket" + "github.com/wwt/guac" +) + +var ( + internalOpcodeIns = []byte(fmt.Sprint(len(guac.InternalDataOpcode), ".", guac.InternalDataOpcode)) + authentikOpcode = []byte("0.authentik.") +) + +// MessageReader wraps a websocket connection and only permits Reading +type MessageReader interface { + // ReadMessage should return a single complete message to send to guac + ReadMessage() (int, []byte, error) +} + +func (c *Connection) wsToGuacd() { + w := c.st.AcquireWriter() + for { + select { + default: + _, data, e := c.ws.ReadMessage() + if e != nil { + c.log.WithError(e).Trace("Error reading message from ws") + c.onError(e) + return + } + if bytes.HasPrefix(data, internalOpcodeIns) { + if bytes.HasPrefix(data, authentikOpcode) { + switch string(bytes.Replace(data, authentikOpcode, []byte{}, 1)) { + case "disconnect": + _, e := w.Write([]byte(guac.NewInstruction("disconnect").String())) + c.onError(e) + return + } + } + // messages starting with the InternalDataOpcode are never sent to guacd + continue + } + + if _, e = w.Write(data); e != nil { + c.log.WithError(e).Trace("Failed writing to guacd") + c.onError(e) + return + } + case <-c.ctx.Done(): + return + } + } +} + +// MessageWriter wraps a websocket connection and only permits Writing +type MessageWriter interface { + // WriteMessage writes one or more complete guac commands to the websocket + WriteMessage(int, []byte) error +} + +func (c *Connection) guacdToWs() { + r := c.st.AcquireReader() + buf := bytes.NewBuffer(make([]byte, 0, guac.MaxGuacMessage*2)) + for { + select { + default: + ins, e := r.ReadSome() + if e != nil { + c.log.WithError(e).Trace("Error reading from guacd") + c.onError(e) + return + } + + if bytes.HasPrefix(ins, internalOpcodeIns) { + // messages starting with the InternalDataOpcode are never sent to the websocket + continue + } + + if _, e = buf.Write(ins); e != nil { + c.log.WithError(e).Trace("Failed to buffer guacd to ws") + c.onError(e) + return + } + + // if the buffer has more data in it or we've reached the max buffer size, send the data and reset + if !r.Available() || buf.Len() >= guac.MaxGuacMessage { + if e = c.ws.WriteMessage(1, buf.Bytes()); e != nil { + if e == websocket.ErrCloseSent { + return + } + c.log.WithError(e).Trace("Failed sending message to ws") + c.onError(e) + return + } + buf.Reset() + } + case <-c.ctx.Done(): + return + } + } +} diff --git a/internal/outpost/rac/guacd.go b/internal/outpost/rac/guacd.go new file mode 100644 index 000000000..3ae0c4f3f --- /dev/null +++ b/internal/outpost/rac/guacd.go @@ -0,0 +1,26 @@ +package rac + +import ( + "os" + "os/exec" + "strings" + + log "github.com/sirupsen/logrus" + "goauthentik.io/internal/outpost/ak" +) + +const ( + guacdPath = "/opt/guacamole/sbin/guacd" + guacdDefaultArgs = " -b 0.0.0.0 -f" +) + +func (rs *RACServer) startGuac() error { + guacdArgs := strings.Split(guacdDefaultArgs, " ") + guacdArgs = append(guacdArgs, "-L", rs.ac.Outpost.Config[ak.ConfigLogLevel].(string)) + rs.guacd = exec.Command(guacdPath, guacdArgs...) + rs.guacd.Env = os.Environ() + rs.guacd.Stdout = rs.log.WithField("logger", "authentik.outpost.rac.guacd").WriterLevel(log.InfoLevel) + rs.guacd.Stderr = rs.log.WithField("logger", "authentik.outpost.rac.guacd").WriterLevel(log.InfoLevel) + rs.log.Info("starting guacd") + return rs.guacd.Start() +} diff --git a/internal/outpost/rac/metrics/metrics.go b/internal/outpost/rac/metrics/metrics.go new file mode 100644 index 000000000..0a3e6b45d --- /dev/null +++ b/internal/outpost/rac/metrics/metrics.go @@ -0,0 +1,28 @@ +package metrics + +import ( + "net/http" + + log "github.com/sirupsen/logrus" + "goauthentik.io/internal/config" + "goauthentik.io/internal/utils/sentry" + + "github.com/gorilla/mux" + "github.com/prometheus/client_golang/prometheus/promhttp" +) + +func RunServer() { + m := mux.NewRouter() + l := log.WithField("logger", "authentik.outpost.metrics") + m.Use(sentry.SentryNoSampleMiddleware) + m.HandleFunc("/outpost.goauthentik.io/ping", func(rw http.ResponseWriter, r *http.Request) { + rw.WriteHeader(204) + }) + m.Path("/metrics").Handler(promhttp.Handler()) + listen := config.Get().Listen.Metrics + l.WithField("listen", listen).Info("Starting Metrics server") + err := http.ListenAndServe(listen, m) + if err != nil { + l.WithError(err).Warning("Failed to start metrics listener") + } +} diff --git a/internal/outpost/rac/rac.go b/internal/outpost/rac/rac.go new file mode 100644 index 000000000..1e9920305 --- /dev/null +++ b/internal/outpost/rac/rac.go @@ -0,0 +1,126 @@ +package rac + +import ( + "context" + "os/exec" + "strconv" + "sync" + + "github.com/mitchellh/mapstructure" + log "github.com/sirupsen/logrus" + "github.com/wwt/guac" + + "goauthentik.io/internal/outpost/ak" + "goauthentik.io/internal/outpost/rac/connection" + "goauthentik.io/internal/outpost/rac/metrics" +) + +type RACServer struct { + log *log.Entry + ac *ak.APIController + guacd *exec.Cmd + connm sync.RWMutex + conns map[string]connection.Connection +} + +func NewServer(ac *ak.APIController) *RACServer { + rs := &RACServer{ + log: log.WithField("logger", "authentik.outpost.rac"), + ac: ac, + connm: sync.RWMutex{}, + conns: map[string]connection.Connection{}, + } + ac.AddWSHandler(rs.wsHandler) + return rs +} + +type WSMessage struct { + ConnID string `mapstructure:"conn_id"` + DestChannelID string `mapstructure:"dest_channel_id"` + Params map[string]string `mapstructure:"params"` + Protocol string `mapstructure:"protocol"` + OptimalScreenWidth string `mapstructure:"screen_width"` + OptimalScreenHeight string `mapstructure:"screen_height"` + OptimalScreenDPI string `mapstructure:"screen_dpi"` +} + +func parseIntOrZero(input string) int { + x, err := strconv.Atoi(input) + if err != nil { + return 0 + } + return x +} + +func (rs *RACServer) wsHandler(ctx context.Context, args map[string]interface{}) { + wsm := WSMessage{} + err := mapstructure.Decode(args, &wsm) + if err != nil { + rs.log.WithError(err).Warning("invalid ws message") + return + } + config := guac.NewGuacamoleConfiguration() + config.Protocol = wsm.Protocol + config.Parameters = wsm.Params + config.OptimalScreenWidth = parseIntOrZero(wsm.OptimalScreenWidth) + config.OptimalScreenHeight = parseIntOrZero(wsm.OptimalScreenHeight) + config.OptimalResolution = parseIntOrZero(wsm.OptimalScreenDPI) + config.AudioMimetypes = []string{ + "audio/L8", + "audio/L16", + } + cc, err := connection.NewConnection(rs.ac, wsm.DestChannelID, config) + if err != nil { + rs.log.WithError(err).Warning("failed to setup connection") + return + } + cc.OnError = func(err error) { + rs.connm.Lock() + delete(rs.conns, wsm.ConnID) + _ = rs.ac.SendWSHello(map[string]interface{}{ + "active_connections": len(rs.conns), + }) + rs.connm.Unlock() + } + rs.connm.Lock() + rs.conns[wsm.ConnID] = *cc + _ = rs.ac.SendWSHello(map[string]interface{}{ + "active_connections": len(rs.conns), + }) + rs.connm.Unlock() +} + +func (rs *RACServer) Start() error { + wg := sync.WaitGroup{} + wg.Add(2) + go func() { + defer wg.Done() + metrics.RunServer() + }() + go func() { + defer wg.Done() + err := rs.startGuac() + if err != nil { + panic(err) + } + }() + wg.Wait() + return nil +} + +func (rs *RACServer) Stop() error { + if rs.guacd != nil { + return rs.guacd.Process.Kill() + } + return nil +} + +func (rs *RACServer) TimerFlowCacheExpiry(context.Context) {} + +func (rs *RACServer) Type() string { + return "rac" +} + +func (rs *RACServer) Refresh() error { + return nil +} diff --git a/internal/web/static.go b/internal/web/static.go index c4f6dbcf4..8e0e3d0dd 100644 --- a/internal/web/static.go +++ b/internal/web/static.go @@ -34,6 +34,11 @@ func (ws *WebServer) configureStatic() { }) indexLessRouter.PathPrefix("/if/admin/assets").Handler(http.StripPrefix("/if/admin", distFs)) indexLessRouter.PathPrefix("/if/user/assets").Handler(http.StripPrefix("/if/user", distFs)) + indexLessRouter.PathPrefix("/if/rac/{app_slug}/assets").HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + + web.DisableIndex(http.StripPrefix(fmt.Sprintf("/if/rac/%s", vars["app_slug"]), distFs)).ServeHTTP(rw, r) + }) indexLessRouter.PathPrefix("/media/").Handler(http.StripPrefix("/media", fs)) diff --git a/rac.Dockerfile b/rac.Dockerfile new file mode 100644 index 000000000..ecfd86688 --- /dev/null +++ b/rac.Dockerfile @@ -0,0 +1,38 @@ +# syntax=docker/dockerfile:1 + +# Stage 1: Build +FROM docker.io/golang:1.21.3-bookworm AS builder + +WORKDIR /go/src/goauthentik.io + +RUN --mount=type=bind,target=/go/src/goauthentik.io/go.mod,src=./go.mod \ + --mount=type=bind,target=/go/src/goauthentik.io/go.sum,src=./go.sum \ + --mount=type=bind,target=/go/src/goauthentik.io/gen-go-api,src=./gen-go-api \ + --mount=type=cache,target=/go/pkg/mod \ + go mod download + +ENV CGO_ENABLED=0 +COPY . . +RUN --mount=type=cache,sharing=locked,target=/go/pkg/mod \ + --mount=type=cache,id=go-build-$TARGETARCH$TARGETVARIANT,sharing=locked,target=/root/.cache/go-build \ + go build -o /go/rac ./cmd/rac + +# Stage 2: Run +FROM ghcr.io/beryju/guacd:1.5.3 + +ARG GIT_BUILD_HASH +ENV GIT_BUILD_HASH=$GIT_BUILD_HASH + +LABEL org.opencontainers.image.url https://goauthentik.io +LABEL org.opencontainers.image.description goauthentik.io RAC outpost, see https://goauthentik.io for more info. +LABEL org.opencontainers.image.source https://github.com/goauthentik/authentik +LABEL org.opencontainers.image.version ${VERSION} +LABEL org.opencontainers.image.revision ${GIT_BUILD_HASH} + +COPY --from=builder /go/rac / + +HEALTHCHECK --interval=5s --retries=20 --start-period=3s CMD [ "/rac", "healthcheck" ] + +USER 1000 + +ENTRYPOINT ["/rac"] diff --git a/schema.yml b/schema.yml index d63b0c135..0ea6e8ee0 100644 --- a/schema.yml +++ b/schema.yml @@ -13953,6 +13953,279 @@ paths: schema: $ref: '#/components/schemas/GenericError' description: '' + /propertymappings/rac/: + get: + operationId: propertymappings_rac_list + description: RACPropertyMapping Viewset + parameters: + - in: query + name: managed + schema: + type: string + - in: query + name: name + schema: + type: string + - name: ordering + required: false + in: query + description: Which field to use when ordering the results. + schema: + type: string + - name: page + required: false + in: query + description: A page number within the paginated result set. + schema: + type: integer + - name: page_size + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - name: search + required: false + in: query + description: A search term. + schema: + type: string + tags: + - propertymappings + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PaginatedRACPropertyMappingList' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + post: + operationId: propertymappings_rac_create + description: RACPropertyMapping Viewset + tags: + - propertymappings + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/RACPropertyMappingRequest' + required: true + security: + - authentik: [] + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/RACPropertyMapping' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + /propertymappings/rac/{pm_uuid}/: + get: + operationId: propertymappings_rac_retrieve + description: RACPropertyMapping Viewset + parameters: + - in: path + name: pm_uuid + schema: + type: string + format: uuid + description: A UUID string identifying this RAC Property Mapping. + required: true + tags: + - propertymappings + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/RACPropertyMapping' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + put: + operationId: propertymappings_rac_update + description: RACPropertyMapping Viewset + parameters: + - in: path + name: pm_uuid + schema: + type: string + format: uuid + description: A UUID string identifying this RAC Property Mapping. + required: true + tags: + - propertymappings + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/RACPropertyMappingRequest' + required: true + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/RACPropertyMapping' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + patch: + operationId: propertymappings_rac_partial_update + description: RACPropertyMapping Viewset + parameters: + - in: path + name: pm_uuid + schema: + type: string + format: uuid + description: A UUID string identifying this RAC Property Mapping. + required: true + tags: + - propertymappings + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PatchedRACPropertyMappingRequest' + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/RACPropertyMapping' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + delete: + operationId: propertymappings_rac_destroy + description: RACPropertyMapping Viewset + parameters: + - in: path + name: pm_uuid + schema: + type: string + format: uuid + description: A UUID string identifying this RAC Property Mapping. + required: true + tags: + - propertymappings + security: + - authentik: [] + responses: + '204': + description: No response body + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + /propertymappings/rac/{pm_uuid}/used_by/: + get: + operationId: propertymappings_rac_used_by_list + description: Get a list of all objects that use this object + parameters: + - in: path + name: pm_uuid + schema: + type: string + format: uuid + description: A UUID string identifying this RAC Property Mapping. + required: true + tags: + - propertymappings + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/UsedBy' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' /propertymappings/saml/: get: operationId: propertymappings_saml_list @@ -16060,6 +16333,274 @@ paths: schema: $ref: '#/components/schemas/GenericError' description: '' + /providers/rac/: + get: + operationId: providers_rac_list + description: RACProvider Viewset + parameters: + - in: query + name: application__isnull + schema: + type: boolean + - in: query + name: name__iexact + schema: + type: string + - name: ordering + required: false + in: query + description: Which field to use when ordering the results. + schema: + type: string + - name: page + required: false + in: query + description: A page number within the paginated result set. + schema: + type: integer + - name: page_size + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - name: search + required: false + in: query + description: A search term. + schema: + type: string + tags: + - providers + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PaginatedRACProviderList' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + post: + operationId: providers_rac_create + description: RACProvider Viewset + tags: + - providers + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/RACProviderRequest' + required: true + security: + - authentik: [] + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/RACProvider' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + /providers/rac/{id}/: + get: + operationId: providers_rac_retrieve + description: RACProvider Viewset + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this RAC Provider. + required: true + tags: + - providers + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/RACProvider' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + put: + operationId: providers_rac_update + description: RACProvider Viewset + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this RAC Provider. + required: true + tags: + - providers + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/RACProviderRequest' + required: true + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/RACProvider' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + patch: + operationId: providers_rac_partial_update + description: RACProvider Viewset + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this RAC Provider. + required: true + tags: + - providers + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PatchedRACProviderRequest' + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/RACProvider' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + delete: + operationId: providers_rac_destroy + description: RACProvider Viewset + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this RAC Provider. + required: true + tags: + - providers + security: + - authentik: [] + responses: + '204': + description: No response body + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + /providers/rac/{id}/used_by/: + get: + operationId: providers_rac_used_by_list + description: Get a list of all objects that use this object + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this RAC Provider. + required: true + tags: + - providers + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/UsedBy' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' /providers/radius/: get: operationId: providers_radius_list @@ -17131,6 +17672,277 @@ paths: schema: $ref: '#/components/schemas/GenericError' description: '' + /rac/endpoints/: + get: + operationId: rac_endpoints_list + description: List accessible endpoints + parameters: + - in: query + name: name + schema: + type: string + - name: ordering + required: false + in: query + description: Which field to use when ordering the results. + schema: + type: string + - name: page + required: false + in: query + description: A page number within the paginated result set. + schema: + type: integer + - name: page_size + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - in: query + name: provider + schema: + type: integer + - in: query + name: search + schema: + type: string + - in: query + name: superuser_full_list + schema: + type: boolean + tags: + - rac + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PaginatedEndpointList' + description: '' + '400': + description: Bad request + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + post: + operationId: rac_endpoints_create + description: Endpoint Viewset + tags: + - rac + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/EndpointRequest' + required: true + security: + - authentik: [] + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/Endpoint' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + /rac/endpoints/{pbm_uuid}/: + get: + operationId: rac_endpoints_retrieve + description: Endpoint Viewset + parameters: + - in: path + name: pbm_uuid + schema: + type: string + format: uuid + description: A UUID string identifying this RAC Endpoint. + required: true + tags: + - rac + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Endpoint' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + put: + operationId: rac_endpoints_update + description: Endpoint Viewset + parameters: + - in: path + name: pbm_uuid + schema: + type: string + format: uuid + description: A UUID string identifying this RAC Endpoint. + required: true + tags: + - rac + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/EndpointRequest' + required: true + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Endpoint' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + patch: + operationId: rac_endpoints_partial_update + description: Endpoint Viewset + parameters: + - in: path + name: pbm_uuid + schema: + type: string + format: uuid + description: A UUID string identifying this RAC Endpoint. + required: true + tags: + - rac + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PatchedEndpointRequest' + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Endpoint' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + delete: + operationId: rac_endpoints_destroy + description: Endpoint Viewset + parameters: + - in: path + name: pbm_uuid + schema: + type: string + format: uuid + description: A UUID string identifying this RAC Endpoint. + required: true + tags: + - rac + security: + - authentik: [] + responses: + '204': + description: No response body + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + /rac/endpoints/{pbm_uuid}/used_by/: + get: + operationId: rac_endpoints_used_by_list + description: Get a list of all objects that use this object + parameters: + - in: path + name: pbm_uuid + schema: + type: string + format: uuid + description: A UUID string identifying this RAC Endpoint. + required: true + tags: + - rac + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/UsedBy' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' /rbac/permissions/: get: operationId: rbac_permissions_list @@ -17279,6 +18091,9 @@ paths: - authentik_providers_oauth2.refreshtoken - authentik_providers_oauth2.scopemapping - authentik_providers_proxy.proxyprovider + - authentik_providers_rac.endpoint + - authentik_providers_rac.racpropertymapping + - authentik_providers_rac.racprovider - authentik_providers_radius.radiusprovider - authentik_providers_saml.samlpropertymapping - authentik_providers_saml.samlprovider @@ -17396,6 +18211,9 @@ paths: * `authentik_core.application` - Application * `authentik_core.token` - Token * `authentik_enterprise.license` - License + * `authentik_providers_rac.racprovider` - RAC Provider + * `authentik_providers_rac.endpoint` - RAC Endpoint + * `authentik_providers_rac.racpropertymapping` - RAC Property Mapping required: true - in: query name: object_pk @@ -17567,6 +18385,9 @@ paths: - authentik_providers_oauth2.refreshtoken - authentik_providers_oauth2.scopemapping - authentik_providers_proxy.proxyprovider + - authentik_providers_rac.endpoint + - authentik_providers_rac.racpropertymapping + - authentik_providers_rac.racprovider - authentik_providers_radius.radiusprovider - authentik_providers_saml.samlpropertymapping - authentik_providers_saml.samlprovider @@ -17684,6 +18505,9 @@ paths: * `authentik_core.application` - Application * `authentik_core.token` - Token * `authentik_enterprise.license` - License + * `authentik_providers_rac.racprovider` - RAC Provider + * `authentik_providers_rac.endpoint` - RAC Endpoint + * `authentik_providers_rac.racpropertymapping` - RAC Property Mapping required: true - in: query name: object_pk @@ -18334,7 +19158,6 @@ paths: - tr - tt - udm - - ug - uk - ur - uz @@ -27946,6 +28769,7 @@ components: - authentik.blueprints - authentik.core - authentik.enterprise + - authentik.enterprise.providers.rac type: string description: |- * `authentik.admin` - authentik Admin @@ -27997,6 +28821,7 @@ components: * `authentik.blueprints` - authentik Blueprints * `authentik.core` - authentik Core * `authentik.enterprise` - authentik Enterprise + * `authentik.enterprise.providers.rac` - authentik Enterprise.Providers.RAC AppleChallengeResponseRequest: type: object description: Pseudo class for plex response @@ -28142,6 +28967,14 @@ components: required: - name - slug + AuthModeEnum: + enum: + - static + - prompt + type: string + description: |- + * `static` - Static + * `prompt` - Prompt AuthTypeEnum: enum: - basic @@ -30511,6 +31344,79 @@ components: description: Activate users upon completion of stage. required: - name + Endpoint: + type: object + description: Endpoint Serializer + properties: + pk: + type: string + format: uuid + readOnly: true + title: Pbm uuid + name: + type: string + provider: + type: integer + provider_obj: + allOf: + - $ref: '#/components/schemas/RACProvider' + readOnly: true + protocol: + $ref: '#/components/schemas/ProtocolEnum' + host: + type: string + settings: {} + property_mappings: + type: array + items: + type: string + format: uuid + auth_mode: + $ref: '#/components/schemas/AuthModeEnum' + launch_url: + type: string + nullable: true + description: |- + Build actual launch URL (the provider itself does not have one, just + individual endpoints) + readOnly: true + required: + - auth_mode + - host + - launch_url + - name + - pk + - protocol + - provider + - provider_obj + EndpointRequest: + type: object + description: Endpoint Serializer + properties: + name: + type: string + minLength: 1 + provider: + type: integer + protocol: + $ref: '#/components/schemas/ProtocolEnum' + host: + type: string + minLength: 1 + settings: {} + property_mappings: + type: array + items: + type: string + format: uuid + auth_mode: + $ref: '#/components/schemas/AuthModeEnum' + required: + - auth_mode + - host + - name + - protocol + - provider ErrorDetail: type: object description: Serializer for rest_framework's error messages @@ -30767,6 +31673,7 @@ components: * `authentik.blueprints` - authentik Blueprints * `authentik.core` - authentik Core * `authentik.enterprise` - authentik Enterprise + * `authentik.enterprise.providers.rac` - authentik Enterprise.Providers.RAC model: allOf: - $ref: '#/components/schemas/ModelEnum' @@ -30848,6 +31755,9 @@ components: * `authentik_core.application` - Application * `authentik_core.token` - Token * `authentik_enterprise.license` - License + * `authentik_providers_rac.racprovider` - RAC Provider + * `authentik_providers_rac.endpoint` - RAC Endpoint + * `authentik_providers_rac.racpropertymapping` - RAC Property Mapping required: - bound_to - component @@ -30963,6 +31873,7 @@ components: * `authentik.blueprints` - authentik Blueprints * `authentik.core` - authentik Core * `authentik.enterprise` - authentik Enterprise + * `authentik.enterprise.providers.rac` - authentik Enterprise.Providers.RAC model: allOf: - $ref: '#/components/schemas/ModelEnum' @@ -31044,6 +31955,9 @@ components: * `authentik_core.application` - Application * `authentik_core.token` - Token * `authentik_enterprise.license` - License + * `authentik_providers_rac.racprovider` - RAC Provider + * `authentik_providers_rac.endpoint` - RAC Endpoint + * `authentik_providers_rac.racpropertymapping` - RAC Property Mapping required: - name EventRequest: @@ -33359,6 +34273,9 @@ components: - authentik_core.application - authentik_core.token - authentik_enterprise.license + - authentik_providers_rac.racprovider + - authentik_providers_rac.endpoint + - authentik_providers_rac.racpropertymapping type: string description: |- * `authentik_crypto.certificatekeypair` - Certificate-Key Pair @@ -33435,6 +34352,9 @@ components: * `authentik_core.application` - Application * `authentik_core.token` - Token * `authentik_enterprise.license` - License + * `authentik_providers_rac.racprovider` - RAC Provider + * `authentik_providers_rac.endpoint` - RAC Endpoint + * `authentik_providers_rac.racpropertymapping` - RAC Property Mapping NameIdPolicyEnum: enum: - urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress @@ -34421,11 +35341,13 @@ components: - proxy - ldap - radius + - rac type: string description: |- * `proxy` - Proxy * `ldap` - Ldap * `radius` - Radius + * `rac` - Rac PaginatedApplicationList: type: object properties: @@ -34642,6 +35564,18 @@ components: required: - pagination - results + PaginatedEndpointList: + type: object + properties: + pagination: + $ref: '#/components/schemas/Pagination' + results: + type: array + items: + $ref: '#/components/schemas/Endpoint' + required: + - pagination + - results PaginatedEventList: type: object properties: @@ -35110,6 +36044,30 @@ components: required: - pagination - results + PaginatedRACPropertyMappingList: + type: object + properties: + pagination: + $ref: '#/components/schemas/Pagination' + results: + type: array + items: + $ref: '#/components/schemas/RACPropertyMapping' + required: + - pagination + - results + PaginatedRACProviderList: + type: object + properties: + pagination: + $ref: '#/components/schemas/Pagination' + results: + type: array + items: + $ref: '#/components/schemas/RACProvider' + required: + - pagination + - results PaginatedRadiusOutpostConfigList: type: object properties: @@ -36317,6 +37275,28 @@ components: activate_user_on_success: type: boolean description: Activate users upon completion of stage. + PatchedEndpointRequest: + type: object + description: Endpoint Serializer + properties: + name: + type: string + minLength: 1 + provider: + type: integer + protocol: + $ref: '#/components/schemas/ProtocolEnum' + host: + type: string + minLength: 1 + settings: {} + property_mappings: + type: array + items: + type: string + format: uuid + auth_mode: + $ref: '#/components/schemas/AuthModeEnum' PatchedEventMatcherPolicyRequest: type: object description: Event Matcher Policy Serializer @@ -36424,6 +37404,7 @@ components: * `authentik.blueprints` - authentik Blueprints * `authentik.core` - authentik Core * `authentik.enterprise` - authentik Enterprise + * `authentik.enterprise.providers.rac` - authentik Enterprise.Providers.RAC model: allOf: - $ref: '#/components/schemas/ModelEnum' @@ -36505,6 +37486,9 @@ components: * `authentik_core.application` - Application * `authentik_core.token` - Token * `authentik_enterprise.license` - License + * `authentik_providers_rac.racprovider` - RAC Provider + * `authentik_providers_rac.endpoint` - RAC Endpoint + * `authentik_providers_rac.racpropertymapping` - RAC Property Mapping PatchedEventRequest: type: object description: Event Serializer @@ -37631,6 +38615,55 @@ components: minLength: 1 description: 'Tokens not valid on or after current time + this value (Format: hours=1;minutes=2;seconds=3).' + PatchedRACPropertyMappingRequest: + type: object + description: RACPropertyMapping Serializer + properties: + managed: + type: string + nullable: true + minLength: 1 + title: Managed by authentik + description: Objects that are managed by authentik. These objects are created + and updated automatically. This flag only indicates that an object can + be overwritten by migrations. You can still modify the objects via the + API, but expect changes to be overwritten in a later update. + name: + type: string + minLength: 1 + expression: + type: string + static_settings: + type: object + additionalProperties: {} + PatchedRACProviderRequest: + type: object + description: RACProvider Serializer + properties: + name: + type: string + minLength: 1 + authentication_flow: + type: string + format: uuid + nullable: true + description: Flow used for authentication when the associated application + is accessed by an un-authenticated user. + authorization_flow: + type: string + format: uuid + description: Flow used when authorizing this provider. + property_mappings: + type: array + items: + type: string + format: uuid + settings: {} + connection_expiry: + type: string + minLength: 1 + description: 'Determines how long a session lasts. Default of 0 means that + the sessions lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)' PatchedRadiusProviderRequest: type: object description: RadiusProvider Serializer @@ -39066,6 +40099,16 @@ components: required: - result - successful + ProtocolEnum: + enum: + - rdp + - vnc + - ssh + type: string + description: |- + * `rdp` - Rdp + * `vnc` - Vnc + * `ssh` - Ssh Provider: type: object description: Provider Serializer @@ -39148,6 +40191,7 @@ components: - authentik_providers_ldap.ldapprovider - authentik_providers_oauth2.oauth2provider - authentik_providers_proxy.proxyprovider + - authentik_providers_rac.racprovider - authentik_providers_radius.radiusprovider - authentik_providers_saml.samlprovider - authentik_providers_scim.scimprovider @@ -39156,6 +40200,7 @@ components: * `authentik_providers_ldap.ldapprovider` - authentik_providers_ldap.ldapprovider * `authentik_providers_oauth2.oauth2provider` - authentik_providers_oauth2.oauth2provider * `authentik_providers_proxy.proxyprovider` - authentik_providers_proxy.proxyprovider + * `authentik_providers_rac.racprovider` - authentik_providers_rac.racprovider * `authentik_providers_radius.radiusprovider` - authentik_providers_radius.radiusprovider * `authentik_providers_saml.samlprovider` - authentik_providers_saml.samlprovider * `authentik_providers_scim.scimprovider` - authentik_providers_scim.scimprovider @@ -39563,6 +40608,189 @@ components: - authorization_flow - external_host - name + RACPropertyMapping: + type: object + description: RACPropertyMapping Serializer + properties: + pk: + type: string + format: uuid + readOnly: true + title: Pm uuid + managed: + type: string + nullable: true + title: Managed by authentik + description: Objects that are managed by authentik. These objects are created + and updated automatically. This flag only indicates that an object can + be overwritten by migrations. You can still modify the objects via the + API, but expect changes to be overwritten in a later update. + name: + type: string + expression: + type: string + component: + type: string + description: Get object's component so that we know how to edit the object + readOnly: true + verbose_name: + type: string + description: Return object's verbose_name + readOnly: true + verbose_name_plural: + type: string + description: Return object's plural verbose_name + readOnly: true + meta_model_name: + type: string + description: Return internal model name + readOnly: true + static_settings: + type: object + additionalProperties: {} + required: + - component + - meta_model_name + - name + - pk + - static_settings + - verbose_name + - verbose_name_plural + RACPropertyMappingRequest: + type: object + description: RACPropertyMapping Serializer + properties: + managed: + type: string + nullable: true + minLength: 1 + title: Managed by authentik + description: Objects that are managed by authentik. These objects are created + and updated automatically. This flag only indicates that an object can + be overwritten by migrations. You can still modify the objects via the + API, but expect changes to be overwritten in a later update. + name: + type: string + minLength: 1 + expression: + type: string + static_settings: + type: object + additionalProperties: {} + required: + - name + - static_settings + RACProvider: + type: object + description: RACProvider Serializer + properties: + pk: + type: integer + readOnly: true + title: ID + name: + type: string + authentication_flow: + type: string + format: uuid + nullable: true + description: Flow used for authentication when the associated application + is accessed by an un-authenticated user. + authorization_flow: + type: string + format: uuid + description: Flow used when authorizing this provider. + property_mappings: + type: array + items: + type: string + format: uuid + component: + type: string + description: Get object component so that we know how to edit the object + readOnly: true + assigned_application_slug: + type: string + description: Internal application name, used in URLs. + readOnly: true + assigned_application_name: + type: string + description: Application's display Name. + readOnly: true + assigned_backchannel_application_slug: + type: string + description: Internal application name, used in URLs. + readOnly: true + assigned_backchannel_application_name: + type: string + description: Application's display Name. + readOnly: true + verbose_name: + type: string + description: Return object's verbose_name + readOnly: true + verbose_name_plural: + type: string + description: Return object's plural verbose_name + readOnly: true + meta_model_name: + type: string + description: Return internal model name + readOnly: true + settings: {} + outpost_set: + type: array + items: + type: string + readOnly: true + connection_expiry: + type: string + description: 'Determines how long a session lasts. Default of 0 means that + the sessions lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)' + required: + - assigned_application_name + - assigned_application_slug + - assigned_backchannel_application_name + - assigned_backchannel_application_slug + - authorization_flow + - component + - meta_model_name + - name + - outpost_set + - pk + - verbose_name + - verbose_name_plural + RACProviderRequest: + type: object + description: RACProvider Serializer + properties: + name: + type: string + minLength: 1 + authentication_flow: + type: string + format: uuid + nullable: true + description: Flow used for authentication when the associated application + is accessed by an un-authenticated user. + authorization_flow: + type: string + format: uuid + description: Flow used when authorizing this provider. + property_mappings: + type: array + items: + type: string + format: uuid + settings: {} + connection_expiry: + type: string + minLength: 1 + description: 'Determines how long a session lasts. Default of 0 means that + the sessions lasts until the browser is closed. (Format: hours=-1;minutes=-2;seconds=-3)' + required: + - authorization_flow + - name RadiusOutpostConfig: type: object description: RadiusProvider Serializer @@ -42786,6 +44014,7 @@ components: - $ref: '#/components/schemas/LDAPProviderRequest' - $ref: '#/components/schemas/OAuth2ProviderRequest' - $ref: '#/components/schemas/ProxyProviderRequest' + - $ref: '#/components/schemas/RACProviderRequest' - $ref: '#/components/schemas/RadiusProviderRequest' - $ref: '#/components/schemas/SAMLProviderRequest' - $ref: '#/components/schemas/SCIMProviderRequest' @@ -42795,6 +44024,7 @@ components: authentik_providers_ldap.ldapprovider: '#/components/schemas/LDAPProviderRequest' authentik_providers_oauth2.oauth2provider: '#/components/schemas/OAuth2ProviderRequest' authentik_providers_proxy.proxyprovider: '#/components/schemas/ProxyProviderRequest' + authentik_providers_rac.racprovider: '#/components/schemas/RACProviderRequest' authentik_providers_radius.radiusprovider: '#/components/schemas/RadiusProviderRequest' authentik_providers_saml.samlprovider: '#/components/schemas/SAMLProviderRequest' authentik_providers_scim.scimprovider: '#/components/schemas/SCIMProviderRequest' diff --git a/web/package-lock.json b/web/package-lock.json index 59c543660..ac34f18b7 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -35,6 +35,7 @@ "core-js": "^3.35.0", "country-flag-icons": "^1.5.9", "fuse.js": "^7.0.0", + "guacamole-common-js": "^1.5.0", "lit": "^2.8.0", "mermaid": "^10.6.1", "rapidoc": "^9.3.4", @@ -72,6 +73,7 @@ "@types/chart.js": "^2.9.41", "@types/codemirror": "5.60.15", "@types/grecaptcha": "^3.0.7", + "@types/guacamole-common-js": "1.3.2", "@typescript-eslint/eslint-plugin": "^6.16.0", "@typescript-eslint/parser": "^6.16.0", "babel-plugin-macros": "^3.1.0", @@ -7369,6 +7371,12 @@ "integrity": "sha512-ah5GDQfsiK3dnkaCbYcDFZXkZCG3o90VRu9hzXHnSe4kACrRB1KUI/ZyWHvYmqm1W5Tl8B5YxxT98uGTlkbf2Q==", "dev": true }, + "node_modules/@types/guacamole-common-js": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/guacamole-common-js/-/guacamole-common-js-1.3.2.tgz", + "integrity": "sha512-217AvsdGfuoqrXLWjrZOjO1CRzY0PNCG07NQf+cW6gYZhExCpjwDrpIbi5pFrmskPZB3T8n1CZLEoYW7rTERNQ==", + "dev": true + }, "node_modules/@types/http-errors": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.1.tgz", @@ -11966,6 +11974,11 @@ "node": ">=6.0" } }, + "node_modules/guacamole-common-js": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/guacamole-common-js/-/guacamole-common-js-1.5.0.tgz", + "integrity": "sha512-zxztif3GGhKbg1RgOqwmqot8kXgv2HmHFg1EvWwd4q7UfEKvBcYZ0f+7G8HzvU+FUxF0Psqm9Kl5vCbgfrRgJg==" + }, "node_modules/gunzip-maybe": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/gunzip-maybe/-/gunzip-maybe-1.4.2.tgz", diff --git a/web/package.json b/web/package.json index f84bf97a8..f446eee57 100644 --- a/web/package.json +++ b/web/package.json @@ -60,6 +60,7 @@ "core-js": "^3.35.0", "country-flag-icons": "^1.5.9", "fuse.js": "^7.0.0", + "guacamole-common-js": "^1.5.0", "lit": "^2.8.0", "mermaid": "^10.6.1", "rapidoc": "^9.3.4", @@ -97,6 +98,7 @@ "@types/chart.js": "^2.9.41", "@types/codemirror": "5.60.15", "@types/grecaptcha": "^3.0.7", + "@types/guacamole-common-js": "1.3.2", "@typescript-eslint/eslint-plugin": "^6.16.0", "@typescript-eslint/parser": "^6.16.0", "babel-plugin-macros": "^3.1.0", diff --git a/web/rollup.config.mjs b/web/rollup.config.mjs index 49825a29d..c4139e13e 100644 --- a/web/rollup.config.mjs +++ b/web/rollup.config.mjs @@ -129,6 +129,21 @@ export const standalone = ["api-browser", "loading"].map((input) => { }; }); +export const enterprise = ["rac"].map((input) => { + return { + input: `./src/enterprise/${input}`, + output: [ + { + format: "es", + dir: `dist/enterprise/${input}`, + sourcemap: true, + manualChunks: manualChunks, + }, + ], + ...defaultOptions, + }; +}); + export default [ POLY, // Standalone @@ -172,4 +187,6 @@ export default [ ], ...defaultOptions, }, + // Enterprise + ...enterprise, ]; diff --git a/web/src/admin/outposts/OutpostForm.ts b/web/src/admin/outposts/OutpostForm.ts index 1952cfe85..2c5ac9722 100644 --- a/web/src/admin/outposts/OutpostForm.ts +++ b/web/src/admin/outposts/OutpostForm.ts @@ -21,6 +21,7 @@ import { OutpostsServiceConnectionsAllListRequest, PaginatedLDAPProviderList, PaginatedProxyProviderList, + PaginatedRACProviderList, PaginatedRadiusProviderList, ProvidersApi, ServiceConnection, @@ -38,7 +39,8 @@ export class OutpostForm extends ModelForm { providers?: | PaginatedProxyProviderList | PaginatedLDAPProviderList - | PaginatedRadiusProviderList; + | PaginatedRadiusProviderList + | PaginatedRACProviderList; defaultConfig?: OutpostDefaultConfig; @@ -73,6 +75,12 @@ export class OutpostForm extends ModelForm { applicationIsnull: false, }); break; + case OutpostTypeEnum.Rac: + this.providers = await new ProvidersApi(DEFAULT_CONFIG).providersRacList({ + ordering: "name", + applicationIsnull: false, + }); + break; case OutpostTypeEnum.UnknownDefaultOpenApi: this.providers = undefined; } @@ -133,6 +141,12 @@ export class OutpostForm extends ModelForm { > ${msg("Radius")} + diff --git a/web/src/admin/outposts/OutpostListPage.ts b/web/src/admin/outposts/OutpostListPage.ts index 390134ad0..318355585 100644 --- a/web/src/admin/outposts/OutpostListPage.ts +++ b/web/src/admin/outposts/OutpostListPage.ts @@ -41,6 +41,8 @@ export function TypeToLabel(type?: OutpostTypeEnum): string { return msg("LDAP"); case OutpostTypeEnum.Radius: return msg("Radius"); + case OutpostTypeEnum.Rac: + return msg("RAC"); case OutpostTypeEnum.UnknownDefaultOpenApi: return msg("Unknown type"); } diff --git a/web/src/admin/property-mappings/PropertyMappingListPage.ts b/web/src/admin/property-mappings/PropertyMappingListPage.ts index e961a744c..18521f5e4 100644 --- a/web/src/admin/property-mappings/PropertyMappingListPage.ts +++ b/web/src/admin/property-mappings/PropertyMappingListPage.ts @@ -1,5 +1,6 @@ import "@goauthentik/admin/property-mappings/PropertyMappingLDAPForm"; import "@goauthentik/admin/property-mappings/PropertyMappingNotification"; +import "@goauthentik/admin/property-mappings/PropertyMappingRACForm"; import "@goauthentik/admin/property-mappings/PropertyMappingSAMLForm"; import "@goauthentik/admin/property-mappings/PropertyMappingSCIMForm"; import "@goauthentik/admin/property-mappings/PropertyMappingScopeForm"; diff --git a/web/src/admin/property-mappings/PropertyMappingRACForm.ts b/web/src/admin/property-mappings/PropertyMappingRACForm.ts new file mode 100644 index 000000000..72e2bb090 --- /dev/null +++ b/web/src/admin/property-mappings/PropertyMappingRACForm.ts @@ -0,0 +1,195 @@ +import { first } from "@goauthentik/app/common/utils"; +import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; +import { docLink } from "@goauthentik/common/global"; +import "@goauthentik/elements/CodeMirror"; +import { CodeMirrorMode } from "@goauthentik/elements/CodeMirror"; +import "@goauthentik/elements/forms/FormGroup"; +import "@goauthentik/elements/forms/HorizontalFormElement"; +import { ModelForm } from "@goauthentik/elements/forms/ModelForm"; + +import { msg } from "@lit/localize"; +import { TemplateResult, html } from "lit"; +import { customElement } from "lit/decorators.js"; +import { ifDefined } from "lit/directives/if-defined.js"; + +import { PropertymappingsApi, RACPropertyMapping } from "@goauthentik/api"; + +@customElement("ak-property-mapping-rac-form") +export class PropertyMappingLDAPForm extends ModelForm { + loadInstance(pk: string): Promise { + return new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsRacRetrieve({ + pmUuid: pk, + }); + } + + getSuccessMessage(): string { + if (this.instance) { + return msg("Successfully updated mapping."); + } else { + return msg("Successfully created mapping."); + } + } + + async send(data: RACPropertyMapping): Promise { + if (this.instance) { + return new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsRacUpdate({ + pmUuid: this.instance.pk || "", + rACPropertyMappingRequest: data, + }); + } else { + return new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsRacCreate({ + rACPropertyMappingRequest: data, + }); + } + } + + renderForm(): TemplateResult { + return html` + + + + + ${msg("General settings")} +
+ + + + + + +
+
+ + ${msg("RDP settings")} +
+ + + + + + + + + + + + +
+
+ + ${msg("Advanced settings")} +
+ + `; + } +} diff --git a/web/src/admin/property-mappings/PropertyMappingWizard.ts b/web/src/admin/property-mappings/PropertyMappingWizard.ts index 9086546a0..4773dd93a 100644 --- a/web/src/admin/property-mappings/PropertyMappingWizard.ts +++ b/web/src/admin/property-mappings/PropertyMappingWizard.ts @@ -1,5 +1,6 @@ import "@goauthentik/admin/property-mappings/PropertyMappingLDAPForm"; import "@goauthentik/admin/property-mappings/PropertyMappingNotification"; +import "@goauthentik/admin/property-mappings/PropertyMappingRACForm"; import "@goauthentik/admin/property-mappings/PropertyMappingSAMLForm"; import "@goauthentik/admin/property-mappings/PropertyMappingScopeForm"; import "@goauthentik/admin/property-mappings/PropertyMappingTestForm"; diff --git a/web/src/admin/providers/ProviderListPage.ts b/web/src/admin/providers/ProviderListPage.ts index 6ff994611..87a123c82 100644 --- a/web/src/admin/providers/ProviderListPage.ts +++ b/web/src/admin/providers/ProviderListPage.ts @@ -3,6 +3,7 @@ import "@goauthentik/admin/providers/ProviderWizard"; import "@goauthentik/admin/providers/ldap/LDAPProviderForm"; import "@goauthentik/admin/providers/oauth2/OAuth2ProviderForm"; import "@goauthentik/admin/providers/proxy/ProxyProviderForm"; +import "@goauthentik/admin/providers/rac/RACProviderForm"; import "@goauthentik/admin/providers/radius/RadiusProviderForm"; import "@goauthentik/admin/providers/saml/SAMLProviderForm"; import "@goauthentik/admin/providers/scim/SCIMProviderForm"; diff --git a/web/src/admin/providers/ProviderViewPage.ts b/web/src/admin/providers/ProviderViewPage.ts index 4157081d8..5cebd14dd 100644 --- a/web/src/admin/providers/ProviderViewPage.ts +++ b/web/src/admin/providers/ProviderViewPage.ts @@ -1,6 +1,7 @@ import "@goauthentik/admin/providers/ldap/LDAPProviderViewPage"; import "@goauthentik/admin/providers/oauth2/OAuth2ProviderViewPage"; import "@goauthentik/admin/providers/proxy/ProxyProviderViewPage"; +import "@goauthentik/admin/providers/rac/RACProviderViewPage"; import "@goauthentik/admin/providers/radius/RadiusProviderViewPage"; import "@goauthentik/admin/providers/saml/SAMLProviderViewPage"; import "@goauthentik/admin/providers/scim/SCIMProviderViewPage"; @@ -65,6 +66,10 @@ export class ProviderViewPage extends AKElement { return html``; + case "ak-provider-rac-form": + return html``; default: return html`

Invalid provider type ${this.provider?.component}

`; } diff --git a/web/src/admin/providers/rac/EndpointForm.ts b/web/src/admin/providers/rac/EndpointForm.ts new file mode 100644 index 000000000..af83af23f --- /dev/null +++ b/web/src/admin/providers/rac/EndpointForm.ts @@ -0,0 +1,146 @@ +import { first } from "@goauthentik/app/common/utils"; +import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; +import "@goauthentik/components/ak-radio-input"; +import "@goauthentik/elements/CodeMirror"; +import "@goauthentik/elements/forms/FormGroup"; +import "@goauthentik/elements/forms/HorizontalFormElement"; +import { ModelForm } from "@goauthentik/elements/forms/ModelForm"; +import YAML from "yaml"; + +import { msg } from "@lit/localize"; +import { TemplateResult, html } from "lit"; +import { customElement, property } from "lit/decorators.js"; +import { ifDefined } from "lit/directives/if-defined.js"; + +import { + AuthModeEnum, + Endpoint, + PaginatedRACPropertyMappingList, + PropertymappingsApi, + ProtocolEnum, + RacApi, +} from "@goauthentik/api"; + +@customElement("ak-rac-endpoint-form") +export class EndpointForm extends ModelForm { + @property({ type: Number }) + providerID?: number; + + propertyMappings?: PaginatedRACPropertyMappingList; + + async load(): Promise { + this.propertyMappings = await new PropertymappingsApi( + DEFAULT_CONFIG, + ).propertymappingsRacList({ + ordering: "name", + }); + } + + loadInstance(pk: string): Promise { + return new RacApi(DEFAULT_CONFIG).racEndpointsRetrieve({ + pbmUuid: pk, + }); + } + + getSuccessMessage(): string { + return this.instance + ? msg("Successfully updated endpoint.") + : msg("Successfully created endpoint."); + } + + async send(data: Endpoint): Promise { + data.authMode = AuthModeEnum.Prompt; + if (!this.instance) { + data.provider = this.providerID || 0; + } else { + data.provider = this.instance.provider; + } + if (this.instance) { + return new RacApi(DEFAULT_CONFIG).racEndpointsPartialUpdate({ + pbmUuid: this.instance.pk || "", + patchedEndpointRequest: data, + }); + } else { + return new RacApi(DEFAULT_CONFIG).racEndpointsCreate({ + endpointRequest: data, + }); + } + } + + renderForm(): TemplateResult { + return html` + + + + + + + + + +

${msg("Hostname/IP to connect to.")}

+
+ + +

+ ${msg("Hold control/command to select multiple items.")} +

+
+ + ${msg("Advanced settings")} +
+ + + +

${msg("Connection settings.")}

+
+
+
+ `; + } +} diff --git a/web/src/admin/providers/rac/EndpointList.ts b/web/src/admin/providers/rac/EndpointList.ts new file mode 100644 index 000000000..d3c3f88c3 --- /dev/null +++ b/web/src/admin/providers/rac/EndpointList.ts @@ -0,0 +1,142 @@ +import "@goauthentik/admin/policies/BoundPoliciesList"; +import "@goauthentik/app/admin/providers/rac/EndpointForm"; +import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; +import { uiConfig } from "@goauthentik/common/ui/config"; +import "@goauthentik/elements/buttons/SpinnerButton"; +import "@goauthentik/elements/forms/DeleteBulkForm"; +import "@goauthentik/elements/forms/ModalForm"; +import "@goauthentik/elements/rbac/ObjectPermissionModal"; +import { PaginatedResponse, Table } from "@goauthentik/elements/table/Table"; +import { TableColumn } from "@goauthentik/elements/table/Table"; +import "@patternfly/elements/pf-tooltip/pf-tooltip.js"; + +import { msg } from "@lit/localize"; +import { CSSResult, TemplateResult, html } from "lit"; +import { customElement, property } from "lit/decorators.js"; + +import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css"; + +import { + Endpoint, + RACProvider, + RacApi, + RbacPermissionsAssignedByUsersListModelEnum, +} from "@goauthentik/api"; + +@customElement("ak-rac-endpoint-list") +export class EndpointListPage extends Table { + expandable = true; + checkbox = true; + + searchEnabled(): boolean { + return true; + } + + @property() + order = "name"; + + @property({ attribute: false }) + provider?: RACProvider; + + static get styles(): CSSResult[] { + return super.styles.concat(PFDescriptionList); + } + + async apiEndpoint(page: number): Promise> { + return new RacApi(DEFAULT_CONFIG).racEndpointsList({ + ordering: this.order, + page: page, + pageSize: (await uiConfig()).pagination.perPage, + search: this.search || "", + provider: this.provider?.pk, + superuserFullList: true, + }); + } + + columns(): TableColumn[] { + return [ + new TableColumn(msg("Name"), "name"), + new TableColumn(msg("Host"), "host"), + new TableColumn(msg("Actions")), + ]; + } + + renderToolbarSelected(): TemplateResult { + const disabled = this.selectedElements.length < 1; + return html` { + return [ + { key: msg("Name"), value: item.name }, + { key: msg("Host"), value: item.host }, + ]; + }} + .usedBy=${(item: Endpoint) => { + return new RacApi(DEFAULT_CONFIG).racEndpointsUsedByList({ + pbmUuid: item.pk, + }); + }} + .delete=${(item: Endpoint) => { + return new RacApi(DEFAULT_CONFIG).racEndpointsDestroy({ + pbmUuid: item.pk, + }); + }} + > + + `; + } + + row(item: Endpoint): TemplateResult[] { + return [ + html`${item.name}`, + html`${item.host}`, + html` + ${msg("Update")} + ${msg("Update Endpoint")} + + + + + + `, + ]; + } + + renderExpanded(item: Endpoint): TemplateResult { + return html` + +
+
+

+ ${msg( + "These bindings control which users will have access to this endpoint. Users must also have access to the application.", + )} +

+ +
+
+ `; + } + + renderObjectCreate(): TemplateResult { + return html` + + ${msg("Create")} + ${msg("Create Endpoint")} + + + + + `; + } +} diff --git a/web/src/admin/providers/rac/RACProviderForm.ts b/web/src/admin/providers/rac/RACProviderForm.ts new file mode 100644 index 000000000..53a5357a9 --- /dev/null +++ b/web/src/admin/providers/rac/RACProviderForm.ts @@ -0,0 +1,158 @@ +import "@goauthentik/admin/common/ak-crypto-certificate-search"; +import "@goauthentik/admin/common/ak-flow-search/ak-tenanted-flow-search"; +import { first } from "@goauthentik/app/common/utils"; +import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; +import "@goauthentik/elements/CodeMirror"; +import "@goauthentik/elements/forms/FormGroup"; +import "@goauthentik/elements/forms/HorizontalFormElement"; +import { ModelForm } from "@goauthentik/elements/forms/ModelForm"; +import "@goauthentik/elements/forms/Radio"; +import "@goauthentik/elements/forms/SearchSelect"; +import "@goauthentik/elements/utils/TimeDeltaHelp"; +import YAML from "yaml"; + +import { msg } from "@lit/localize"; +import { TemplateResult, html } from "lit"; +import { customElement, state } from "lit/decorators.js"; +import { ifDefined } from "lit/directives/if-defined.js"; + +import { + FlowsInstancesListDesignationEnum, + PaginatedEndpointList, + PaginatedRACPropertyMappingList, + PropertymappingsApi, + ProvidersApi, + RACProvider, + RacApi, +} from "@goauthentik/api"; + +@customElement("ak-provider-rac-form") +export class RACProviderFormPage extends ModelForm { + @state() + endpoints?: PaginatedEndpointList; + + propertyMappings?: PaginatedRACPropertyMappingList; + + async load(): Promise { + this.endpoints = await new RacApi(DEFAULT_CONFIG).racEndpointsList({}); + this.propertyMappings = await new PropertymappingsApi( + DEFAULT_CONFIG, + ).propertymappingsRacList({ + ordering: "name", + }); + } + + async loadInstance(pk: number): Promise { + return new ProvidersApi(DEFAULT_CONFIG).providersRacRetrieve({ + id: pk, + }); + } + + getSuccessMessage(): string { + if (this.instance) { + return msg("Successfully updated provider."); + } else { + return msg("Successfully created provider."); + } + } + + async send(data: RACProvider): Promise { + if (this.instance) { + return new ProvidersApi(DEFAULT_CONFIG).providersRacUpdate({ + id: this.instance.pk || 0, + rACProviderRequest: data, + }); + } else { + return new ProvidersApi(DEFAULT_CONFIG).providersRacCreate({ + rACProviderRequest: data, + }); + } + } + + renderForm(): TemplateResult { + return html` + + + + + + +

+ ${msg("Flow used when authorizing this provider.")} +

+
+ + +

+ ${msg( + "Determines how long a session lasts before being disconnected and requiring re-authorization.", + )} +

+ +
+ + + ${msg("Protocol settings")} +
+ + +

+ ${msg("Hold control/command to select multiple items.")} +

+
+ + + +

${msg("Connection settings.")}

+
+
+
+ `; + } +} diff --git a/web/src/admin/providers/rac/RACProviderViewPage.ts b/web/src/admin/providers/rac/RACProviderViewPage.ts new file mode 100644 index 000000000..393fa4375 --- /dev/null +++ b/web/src/admin/providers/rac/RACProviderViewPage.ts @@ -0,0 +1,181 @@ +import "@goauthentik/admin/providers/RelatedApplicationButton"; +import "@goauthentik/admin/providers/rac/EndpointForm"; +import "@goauthentik/admin/providers/rac/EndpointList"; +import "@goauthentik/admin/providers/rac/RACProviderForm"; +import "@goauthentik/app/elements/rbac/ObjectPermissionsPage"; +import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; +import { EVENT_REFRESH } from "@goauthentik/common/constants"; +import "@goauthentik/components/ak-status-label"; +import "@goauthentik/components/events/ObjectChangelog"; +import { AKElement } from "@goauthentik/elements/Base"; +import "@goauthentik/elements/CodeMirror"; +import "@goauthentik/elements/Tabs"; +import "@goauthentik/elements/buttons/ModalButton"; +import "@goauthentik/elements/buttons/SpinnerButton"; + +import { msg } from "@lit/localize"; +import { CSSResult, TemplateResult, html } from "lit"; +import { customElement, property } from "lit/decorators.js"; + +import PFBanner from "@patternfly/patternfly/components/Banner/banner.css"; +import PFButton from "@patternfly/patternfly/components/Button/button.css"; +import PFCard from "@patternfly/patternfly/components/Card/card.css"; +import PFContent from "@patternfly/patternfly/components/Content/content.css"; +import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css"; +import PFForm from "@patternfly/patternfly/components/Form/form.css"; +import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css"; +import PFList from "@patternfly/patternfly/components/List/list.css"; +import PFPage from "@patternfly/patternfly/components/Page/page.css"; +import PFGrid from "@patternfly/patternfly/layouts/Grid/grid.css"; +import PFBase from "@patternfly/patternfly/patternfly-base.css"; + +import { + ProvidersApi, + RACProvider, + RbacPermissionsAssignedByUsersListModelEnum, +} from "@goauthentik/api"; + +@customElement("ak-provider-rac-view") +export class RACProviderViewPage extends AKElement { + @property() + set args(value: { [key: string]: number }) { + this.providerID = value.id; + } + + @property({ type: Number }) + set providerID(value: number) { + new ProvidersApi(DEFAULT_CONFIG) + .providersRacRetrieve({ + id: value, + }) + .then((prov) => (this.provider = prov)); + } + + @property({ attribute: false }) + provider?: RACProvider; + + static get styles(): CSSResult[] { + return [ + PFBase, + PFButton, + PFPage, + PFGrid, + PFContent, + PFList, + PFForm, + PFFormControl, + PFCard, + PFDescriptionList, + PFBanner, + ]; + } + + constructor() { + super(); + this.addEventListener(EVENT_REFRESH, () => { + if (!this.provider?.pk) return; + this.providerID = this.provider?.pk; + }); + } + + render(): TemplateResult { + if (!this.provider) { + return html``; + } + return html` +
+ ${this.renderTabOverview()} +
+
+
+
+ + +
+
+
+ +
`; + } + + renderTabOverview(): TemplateResult { + if (!this.provider) { + return html``; + } + return html`
+ ${msg("RAC is in preview.")} + ${msg("Send us feedback!")} +
+ ${this.provider?.assignedApplicationName + ? html`` + : html`
+ ${msg("Warning: Provider is not used by an Application.")} +
`} + ${this.provider?.outpostSet.length < 1 + ? html`
+ ${msg("Warning: Provider is not used by any Outpost.")} +
` + : html``} +
+
+
+
+
+
+ ${msg("Name")} +
+
+
+ ${this.provider.name} +
+
+
+
+
+ ${msg("Assigned to application")} +
+
+
+ +
+
+
+
+
+ +
+
+
${msg("Endpoints")}
+
+ +
+
+
`; + } +} diff --git a/web/src/components/events/ObjectChangelog.ts b/web/src/components/events/ObjectChangelog.ts index 160a98d73..dcfef105b 100644 --- a/web/src/components/events/ObjectChangelog.ts +++ b/web/src/components/events/ObjectChangelog.ts @@ -1,3 +1,5 @@ +import { EventGeo } from "@goauthentik/app/admin/events/utils"; +import { actionToLabel } from "@goauthentik/app/common/labels"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { EventWithContext } from "@goauthentik/common/events"; import { uiConfig } from "@goauthentik/common/ui/config"; @@ -73,7 +75,7 @@ export class ObjectChangelog extends Table { row(item: EventWithContext): TemplateResult[] { return [ - html`${item.action}`, + html`${actionToLabel(item.action)}`, html`
${item.user?.username}
${item.user.on_behalf_of ? html` @@ -81,7 +83,9 @@ export class ObjectChangelog extends Table { ` : html``}`, html`${item.created?.toLocaleString()}`, - html`${item.clientIp || msg("-")}`, + html`
${item.clientIp || msg("-")}
+ + ${EventGeo(item)}`, ]; } diff --git a/web/src/elements/LoadingOverlay.ts b/web/src/elements/LoadingOverlay.ts index 25ed89667..8420156df 100644 --- a/web/src/elements/LoadingOverlay.ts +++ b/web/src/elements/LoadingOverlay.ts @@ -1,5 +1,5 @@ import { AKElement } from "@goauthentik/elements/Base"; -import { PFSize } from "@goauthentik/elements/Spinner"; +import "@goauthentik/elements/EmptyState"; import { CSSResult, TemplateResult, css, html } from "lit"; import { customElement, property } from "lit/decorators.js"; @@ -33,6 +33,8 @@ export class LoadingOverlay extends AKElement { } render(): TemplateResult { - return html``; + return html` + + `; } } diff --git a/web/src/elements/table/Table.ts b/web/src/elements/table/Table.ts index 0b78c4dfb..82fb9f5ae 100644 --- a/web/src/elements/table/Table.ts +++ b/web/src/elements/table/Table.ts @@ -27,6 +27,11 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css"; import { Pagination, ResponseError } from "@goauthentik/api"; +export interface TableLike { + order?: string; + fetch: () => void; +} + export class TableColumn { title: string; orderBy?: string; @@ -38,7 +43,7 @@ export class TableColumn { this.orderBy = orderBy; } - headerClickHandler(table: Table): void { + headerClickHandler(table: TableLike): void { if (!this.orderBy) { return; } @@ -46,7 +51,7 @@ export class TableColumn { table.fetch(); } - private getSortIndicator(table: Table): string { + private getSortIndicator(table: TableLike): string { switch (table.order) { case this.orderBy: return "fa-long-arrow-alt-down"; @@ -57,7 +62,7 @@ export class TableColumn { } } - renderSortable(table: Table): TemplateResult { + renderSortable(table: TableLike): TemplateResult { return html` `; } - render(table: Table): TemplateResult { + render(table: TableLike): TemplateResult { const classes = { "pf-c-table__sort": !!this.orderBy, "pf-m-selected": table.order === this.orderBy || table.order === `-${this.orderBy}`, @@ -89,7 +94,7 @@ export interface PaginatedResponse { results: Array; } -export abstract class Table extends AKElement { +export abstract class Table extends AKElement implements TableLike { abstract apiEndpoint(page: number): Promise>; abstract columns(): TableColumn[]; abstract row(item: T): TemplateResult[]; @@ -123,6 +128,12 @@ export abstract class Table extends AKElement { @property({ type: Boolean }) checkbox = false; + @property({ type: Boolean }) + clickable = false; + + @property({ attribute: false }) + clickHandler: (item: T) => void = () => {}; + @property({ type: Boolean }) radioSelect = false; @@ -356,8 +367,12 @@ export abstract class Table extends AKElement { return html` { + this.clickHandler(item); + } + : itemSelectHandler} > ${this.checkbox ? renderCheckbox() : html``} ${this.expandable ? renderExpansion() : html``} diff --git a/web/src/elements/table/TableModal.ts b/web/src/elements/table/TableModal.ts index 328f5ffdf..341951fe6 100644 --- a/web/src/elements/table/TableModal.ts +++ b/web/src/elements/table/TableModal.ts @@ -19,7 +19,18 @@ export abstract class TableModal extends Table { size: PFSize = PFSize.Large; @property({ type: Boolean }) - open = false; + set open(value: boolean) { + this._open = value; + if (value) { + this.fetch(); + } + } + + get open(): boolean { + return this._open; + } + + _open = false; static get styles(): CSSResult[] { return super.styles.concat( @@ -43,6 +54,13 @@ export abstract class TableModal extends Table { }); } + public async fetch(): Promise { + if (!this.open) { + return; + } + return super.fetch(); + } + resetForms(): void { this.querySelectorAll("[slot=form]").forEach((form) => { if ("resetForm" in form) { diff --git a/web/src/enterprise/rac/index.ts b/web/src/enterprise/rac/index.ts new file mode 100644 index 000000000..495e09801 --- /dev/null +++ b/web/src/enterprise/rac/index.ts @@ -0,0 +1,324 @@ +import { TITLE_DEFAULT } from "@goauthentik/app/common/constants"; +import { Interface } from "@goauthentik/elements/Base"; +import "@goauthentik/elements/LoadingOverlay"; +import Guacamole from "guacamole-common-js"; + +import { msg, str } from "@lit/localize"; +import { CSSResult, TemplateResult, css, html } from "lit"; +import { customElement, property, state } from "lit/decorators.js"; + +import AKGlobal from "@goauthentik/common/styles/authentik.css"; +import PFContent from "@patternfly/patternfly/components/Content/content.css"; +import PFPage from "@patternfly/patternfly/components/Page/page.css"; +import PFBase from "@patternfly/patternfly/patternfly-base.css"; + +enum GuacClientState { + IDLE = 0, + CONNECTING = 1, + WAITING = 2, + CONNECTED = 3, + DISCONNECTING = 4, + DISCONNECTED = 5, +} + +const AUDIO_INPUT_MIMETYPE = "audio/L16;rate=44100,channels=2"; +const RECONNECT_ATTEMPTS_INITIAL = 5; +const RECONNECT_ATTEMPTS = 5; + +@customElement("ak-rac") +export class RacInterface extends Interface { + static get styles(): CSSResult[] { + return [ + PFBase, + PFPage, + PFContent, + AKGlobal, + css` + :host { + cursor: none; + } + canvas { + z-index: unset !important; + } + .container { + overflow: hidden; + height: 100vh; + background-color: black; + display: flex; + justify-content: center; + align-items: center; + } + ak-loading-overlay { + z-index: 5; + } + `, + ]; + } + + client?: Guacamole.Client; + tunnel?: Guacamole.Tunnel; + + @state() + container?: HTMLElement; + + @state() + clientState?: GuacClientState; + + @state() + reconnectingMessage = ""; + + @property() + token?: string; + + @property() + endpointName?: string; + + @state() + clipboardWatcherTimer = 0; + + _previousClipboardValue: unknown; + + // Set to `true` if we've successfully connected once + hasConnected = false; + // Keep track of current connection attempt + connectionAttempt = 0; + + static domSize(): DOMRect { + return document.body.getBoundingClientRect(); + } + + constructor() { + super(); + this.initKeyboard(); + this.checkClipboard(); + this.clipboardWatcherTimer = setInterval( + this.checkClipboard.bind(this), + 500, + ) as unknown as number; + } + + connectedCallback(): void { + super.connectedCallback(); + window.addEventListener( + "focus", + () => { + this.checkClipboard(); + }, + { + capture: false, + }, + ); + window.addEventListener("resize", () => { + this.client?.sendSize( + Math.floor(RacInterface.domSize().width), + Math.floor(RacInterface.domSize().height), + ); + }); + } + + disconnectedCallback(): void { + super.disconnectedCallback(); + clearInterval(this.clipboardWatcherTimer); + } + + async firstUpdated(): Promise { + this.updateTitle(); + const wsUrl = `${window.location.protocol.replace("http", "ws")}//${ + window.location.host + }/ws/rac/${this.token}/`; + this.tunnel = new Guacamole.WebSocketTunnel(wsUrl); + this.tunnel.receiveTimeout = 10 * 1000; // 10 seconds + this.tunnel.onerror = (status) => { + console.debug("authentik/rac: tunnel error: ", status); + this.reconnect(); + }; + this.client = new Guacamole.Client(this.tunnel); + this.client.onerror = (err) => { + console.debug("authentik/rac: error: ", err); + this.reconnect(); + }; + this.client.onstatechange = (state) => { + this.clientState = state; + if (state === GuacClientState.CONNECTED) { + this.onConnected(); + } + }; + this.client.onclipboard = (stream, mimetype) => { + // If the received data is text, read it as a simple string + if (/^text\//.exec(mimetype)) { + const reader = new Guacamole.StringReader(stream); + let data = ""; + reader.ontext = (text) => { + data += text; + }; + reader.onend = () => { + this._previousClipboardValue = data; + navigator.clipboard.writeText(data); + }; + } else { + const reader = new Guacamole.BlobReader(stream, mimetype); + reader.onend = () => { + const blob = reader.getBlob(); + navigator.clipboard.write([ + new ClipboardItem({ + [blob.type]: blob, + }), + ]); + }; + } + console.debug("authentik/rac: updated clipboard from remote"); + }; + const params = new URLSearchParams(); + params.set("screen_width", Math.floor(RacInterface.domSize().width).toString()); + params.set("screen_height", Math.floor(RacInterface.domSize().height).toString()); + params.set("screen_dpi", (window.devicePixelRatio * 96).toString()); + this.client.connect(params.toString()); + } + + reconnect(): void { + this.clientState = undefined; + this.connectionAttempt += 1; + if (!this.hasConnected) { + // Check connection attempts if we haven't had a successful connection + if (this.connectionAttempt >= RECONNECT_ATTEMPTS_INITIAL) { + this.hasConnected = true; + this.reconnectingMessage = msg( + str`Connection failed after ${this.connectionAttempt} attempts.`, + ); + return; + } + } else { + if (this.connectionAttempt >= RECONNECT_ATTEMPTS) { + this.reconnectingMessage = msg( + str`Connection failed after ${this.connectionAttempt} attempts.`, + ); + return; + } + } + const delay = 500 * this.connectionAttempt; + this.reconnectingMessage = msg( + str`Re-connecting in ${Math.max(1, delay / 1000)} second(s).`, + ); + setTimeout(() => { + this.firstUpdated(); + }, delay); + } + + updateTitle(): void { + let title = this.tenant?.brandingTitle || TITLE_DEFAULT; + if (this.endpointName) { + title = `${this.endpointName} - ${title}`; + } + document.title = `${title}`; + } + + onConnected(): void { + console.debug("authentik/rac: connected"); + if (!this.client) { + return; + } + this.hasConnected = true; + this.container = this.client.getDisplay().getElement(); + this.initMouse(this.container); + this.client?.sendSize( + Math.floor(RacInterface.domSize().width), + Math.floor(RacInterface.domSize().height), + ); + } + + initMouse(container: HTMLElement): void { + const mouse = new Guacamole.Mouse(container); + const handler = (mouseState: Guacamole.Mouse.State, scaleMouse = false) => { + if (!this.client) return; + + if (scaleMouse) { + mouseState.y = mouseState.y / this.client.getDisplay().getScale(); + mouseState.x = mouseState.x / this.client.getDisplay().getScale(); + } + + this.client.sendMouseState(mouseState); + }; + mouse.onmouseup = mouse.onmousedown = (mouseState) => { + this.container?.focus(); + handler(mouseState); + }; + mouse.onmousemove = (mouseState) => { + handler(mouseState, true); + }; + } + + initAudioInput(): void { + const stream = this.client?.createAudioStream(AUDIO_INPUT_MIMETYPE); + if (!stream) return; + // Guacamole.AudioPlayer + const recorder = Guacamole.AudioRecorder.getInstance(stream, AUDIO_INPUT_MIMETYPE); + // If creation of the AudioRecorder failed, simply end the stream + if (!recorder) { + stream.sendEnd(); + return; + } + // Otherwise, ensure that another audio stream is created after this + // audio stream is closed + recorder.onclose = this.initAudioInput.bind(this); + } + + initKeyboard(): void { + const keyboard = new Guacamole.Keyboard(document); + keyboard.onkeydown = (keysym) => { + this.client?.sendKeyEvent(1, keysym); + }; + keyboard.onkeyup = (keysym) => { + this.client?.sendKeyEvent(0, keysym); + }; + } + + async checkClipboard(): Promise { + try { + if (!this._previousClipboardValue) { + this._previousClipboardValue = await navigator.clipboard.readText(); + return; + } + const newValue = await navigator.clipboard.readText(); + if (newValue !== this._previousClipboardValue) { + console.debug(`authentik/rac: new clipboard value: ${newValue}`); + this._previousClipboardValue = newValue; + this.writeClipboard(newValue); + } + } catch (ex) { + // The error is most likely caused by the document not being in focus + // in which case we can ignore it and just retry + if (ex instanceof DOMException) { + return; + } + console.warn("authentik/rac: error reading clipboard", ex); + } + } + + private writeClipboard(value: string) { + if (!this.client) { + return; + } + const stream = this.client.createClipboardStream("text/plain", "clipboard"); + const writer = new Guacamole.StringWriter(stream); + writer.sendText(value); + writer.sendEnd(); + console.debug("authentik/rac: Sent clipboard"); + } + + render(): TemplateResult { + return html` + ${this.clientState !== GuacClientState.CONNECTED + ? html` + + + ${this.hasConnected + ? html`${this.reconnectingMessage}` + : html`${msg("Connecting...")}`} + + + ` + : html``} +
${this.container}
+ `; + } +} diff --git a/web/src/user/LibraryApplication/RACLaunchEndpointModal.ts b/web/src/user/LibraryApplication/RACLaunchEndpointModal.ts new file mode 100644 index 000000000..40f5668f7 --- /dev/null +++ b/web/src/user/LibraryApplication/RACLaunchEndpointModal.ts @@ -0,0 +1,71 @@ +import { DEFAULT_CONFIG } from "@goauthentik/app/common/api/config"; +import { PaginatedResponse, TableColumn } from "@goauthentik/app/elements/table/Table"; +import { TableModal } from "@goauthentik/app/elements/table/TableModal"; + +import { msg } from "@lit/localize"; +import { TemplateResult, html } from "lit"; +import { customElement, property } from "lit/decorators.js"; + +import { Application, Endpoint, RacApi } from "@goauthentik/api"; + +@customElement("ak-library-rac-endpoint-launch") +export class RACLaunchEndpointModal extends TableModal { + clickable = true; + searchEnabled(): boolean { + return true; + } + + clickHandler = (item: Endpoint) => { + if (!item.launchUrl) { + return; + } + if (this.app?.openInNewTab) { + window.open(item.launchUrl); + } else { + window.location.assign(item.launchUrl); + } + }; + + @property({ attribute: false }) + app?: Application; + + async apiEndpoint(page: number): Promise> { + const endpoints = await new RacApi(DEFAULT_CONFIG).racEndpointsList({ + provider: this.app?.provider || 0, + page: page, + search: this.search, + }); + if (this.open && endpoints.pagination.count === 1) { + this.clickHandler(endpoints.results[0]); + this.open = false; + } + return endpoints; + } + + columns(): TableColumn[] { + return [new TableColumn("Name")]; + } + + row(item: Endpoint): TemplateResult[] { + return [html`${item.name}`]; + } + + renderModalInner(): TemplateResult { + return html`
+
+

${msg("Select endpoint to connect to")}

+
+
+
${this.renderTable()}
+
+ { + this.open = false; + }} + class="pf-m-secondary" + > + ${msg("Cancel")} + +
`; + } +} diff --git a/web/src/user/LibraryApplication/index.ts b/web/src/user/LibraryApplication/index.ts index 282ce63b2..35f60804f 100644 --- a/web/src/user/LibraryApplication/index.ts +++ b/web/src/user/LibraryApplication/index.ts @@ -3,6 +3,7 @@ import { truncateWords } from "@goauthentik/common/utils"; import "@goauthentik/components/ak-app-icon"; import { AKElement, rootInterface } from "@goauthentik/elements/Base"; import "@goauthentik/elements/Expand"; +import "@goauthentik/user/LibraryApplication/RACLaunchEndpointModal"; import { UserInterface } from "@goauthentik/user/UserInterface"; import { msg } from "@lit/localize"; @@ -85,6 +86,22 @@ export class LibraryApplication extends AKElement { `; } + renderLaunch(): TemplateResult { + if (!this.application) { + return html``; + } + if (this.application?.launchUrl === "goauthentik.io://providers/rac/launch") { + return html` + ${this.application.name} + `; + } + return html`${this.application.name}`; + } + render(): TemplateResult { if (!this.application) { return html``; @@ -111,13 +128,7 @@ export class LibraryApplication extends AKElement { - +
${this.renderLaunch()}
${expandable ? this.renderExpansion(this.application) : nothing} `; diff --git a/web/src/user/LibraryPage/LibraryPageImpl.utils.ts b/web/src/user/LibraryPage/LibraryPageImpl.utils.ts index bac9186e8..0b3375dc3 100644 --- a/web/src/user/LibraryPage/LibraryPageImpl.utils.ts +++ b/web/src/user/LibraryPage/LibraryPageImpl.utils.ts @@ -2,10 +2,16 @@ import type { Application } from "@goauthentik/api"; const isFullUrlRe = new RegExp("://"); const isHttpRe = new RegExp("http(s?)://"); +const isAuthentikSpecialRe = new RegExp("goauthentik.io://"); const isNotFullUrl = (url: string) => !isFullUrlRe.test(url); const isHttp = (url: string) => isHttpRe.test(url); +const isAuthentikSpecial = (url: string) => isAuthentikSpecialRe.test(url); export const appHasLaunchUrl = (app: Application) => { const url = app.launchUrl; - return !!(typeof url === "string" && url !== "" && (isHttp(url) || isNotFullUrl(url))); + return !!( + typeof url === "string" && + url !== "" && + (isHttp(url) || isNotFullUrl(url) || isAuthentikSpecial(url)) + ); }; diff --git a/web/xliff/de.xlf b/web/xliff/de.xlf index 68164cbb3..8cac9d9de 100644 --- a/web/xliff/de.xlf +++ b/web/xliff/de.xlf @@ -6117,6 +6117,126 @@ Bindings to groups/users are checked against the user of the event. Require Outpost (flow can only be executed from an outpost). + + + Connection settings. + + + Successfully updated endpoint. + + + Successfully created endpoint. + + + Protocol + + + RDP + + + SSH + + + VNC + + + Host + + + Hostname/IP to connect to. + + + Endpoint(s) + + + Update Endpoint + + + These bindings control which users will have access to this endpoint. Users must also have access to the application. + + + Create Endpoint + + + RAC is in preview. + + + Update RAC Provider + + + Endpoints + + + General settings + + + RDP settings + + + Ignore server certificate + + + Enable wallpaper + + + Enable font-smoothing + + + Enable full window dragging + + + Network binding + + + No binding + + + Bind ASN + + + Bind ASN and Network + + + Bind ASN, Network and IP + + + Configure if sessions created by this stage should be bound to the Networks they were created in. + + + GeoIP binding + + + Bind Continent + + + Bind Continent and Country + + + Bind Continent, Country and City + + + Configure if sessions created by this stage should be bound to their GeoIP-based location + + + RAC + + + Connection failed after attempts. + + + Re-connecting in second(s). + + + Connecting... + + + Select endpoint to connect to + + + Connection expiry + + + Determines how long a session lasts before being disconnected and requiring re-authorization. diff --git a/web/xliff/en.xlf b/web/xliff/en.xlf index 29f454e9b..aa28b7c6a 100644 --- a/web/xliff/en.xlf +++ b/web/xliff/en.xlf @@ -6393,6 +6393,126 @@ Bindings to groups/users are checked against the user of the event. Require Outpost (flow can only be executed from an outpost). + + + Connection settings. + + + Successfully updated endpoint. + + + Successfully created endpoint. + + + Protocol + + + RDP + + + SSH + + + VNC + + + Host + + + Hostname/IP to connect to. + + + Endpoint(s) + + + Update Endpoint + + + These bindings control which users will have access to this endpoint. Users must also have access to the application. + + + Create Endpoint + + + RAC is in preview. + + + Update RAC Provider + + + Endpoints + + + General settings + + + RDP settings + + + Ignore server certificate + + + Enable wallpaper + + + Enable font-smoothing + + + Enable full window dragging + + + Network binding + + + No binding + + + Bind ASN + + + Bind ASN and Network + + + Bind ASN, Network and IP + + + Configure if sessions created by this stage should be bound to the Networks they were created in. + + + GeoIP binding + + + Bind Continent + + + Bind Continent and Country + + + Bind Continent, Country and City + + + Configure if sessions created by this stage should be bound to their GeoIP-based location + + + RAC + + + Connection failed after attempts. + + + Re-connecting in second(s). + + + Connecting... + + + Select endpoint to connect to + + + Connection expiry + + + Determines how long a session lasts before being disconnected and requiring re-authorization. diff --git a/web/xliff/es.xlf b/web/xliff/es.xlf index 3d45d2983..cbe16ba84 100644 --- a/web/xliff/es.xlf +++ b/web/xliff/es.xlf @@ -6033,6 +6033,126 @@ Bindings to groups/users are checked against the user of the event. Require Outpost (flow can only be executed from an outpost). + + + Connection settings. + + + Successfully updated endpoint. + + + Successfully created endpoint. + + + Protocol + + + RDP + + + SSH + + + VNC + + + Host + + + Hostname/IP to connect to. + + + Endpoint(s) + + + Update Endpoint + + + These bindings control which users will have access to this endpoint. Users must also have access to the application. + + + Create Endpoint + + + RAC is in preview. + + + Update RAC Provider + + + Endpoints + + + General settings + + + RDP settings + + + Ignore server certificate + + + Enable wallpaper + + + Enable font-smoothing + + + Enable full window dragging + + + Network binding + + + No binding + + + Bind ASN + + + Bind ASN and Network + + + Bind ASN, Network and IP + + + Configure if sessions created by this stage should be bound to the Networks they were created in. + + + GeoIP binding + + + Bind Continent + + + Bind Continent and Country + + + Bind Continent, Country and City + + + Configure if sessions created by this stage should be bound to their GeoIP-based location + + + RAC + + + Connection failed after attempts. + + + Re-connecting in second(s). + + + Connecting... + + + Select endpoint to connect to + + + Connection expiry + + + Determines how long a session lasts before being disconnected and requiring re-authorization. diff --git a/web/xliff/fr.xlf b/web/xliff/fr.xlf index 63b478d2a..f808bbde3 100644 --- a/web/xliff/fr.xlf +++ b/web/xliff/fr.xlf @@ -1,4 +1,4 @@ - + @@ -613,9 +613,9 @@ Il y a jour(s) - The URL "" was not found. - L'URL " - " n'a pas été trouvée. + The URL "" was not found. + L'URL " + " n'a pas été trouvée. @@ -1057,8 +1057,8 @@ Il y a jour(s) - To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. - Pour permettre n'importe quelle URI de redirection, définissez cette valeur sur ".*". Soyez conscient des possibles implications de sécurité que cela peut avoir. + To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. + Pour permettre n'importe quelle URI de redirection, définissez cette valeur sur ".*". Soyez conscient des possibles implications de sécurité que cela peut avoir. @@ -1630,7 +1630,7 @@ Il y a jour(s) Token to authenticate with. Currently only bearer authentication is supported. - Jeton d'authentification à utiliser. Actuellement, seule l'authentification "bearer authentication" est prise en charge. + Jeton d'authentification à utiliser. Actuellement, seule l'authentification "bearer authentication" est prise en charge. @@ -1798,8 +1798,8 @@ Il y a jour(s) - Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". - Entrez une URL complète, un chemin relatif ou utilisez 'fa://fa-test' pour utiliser l'icône Font Awesome "fa-test". + Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". + Entrez une URL complète, un chemin relatif ou utilisez 'fa://fa-test' pour utiliser l'icône Font Awesome "fa-test". @@ -2892,7 +2892,7 @@ doesn't pass when either or both of the selected options are equal or above the To use SSL instead, use 'ldaps://' and disable this option. - Pour utiliser SSL à la base, utilisez "ldaps://" et désactviez cette option. + Pour utiliser SSL à la base, utilisez "ldaps://" et désactviez cette option. @@ -2981,8 +2981,8 @@ doesn't pass when either or both of the selected options are equal or above the - Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' - Champ qui contient les membres d'un groupe. Si vous utilisez le champ "memberUid", la valeur est censée contenir un nom distinctif relatif, par exemple 'memberUid=un-utilisateur' au lieu de 'memberUid=cn=un-utilisateur,ou=groups,...' + Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' + Champ qui contient les membres d'un groupe. Si vous utilisez le champ "memberUid", la valeur est censée contenir un nom distinctif relatif, par exemple 'memberUid=un-utilisateur' au lieu de 'memberUid=cn=un-utilisateur,ou=groups,...' @@ -3277,7 +3277,7 @@ doesn't pass when either or both of the selected options are equal or above the Time offset when temporary users should be deleted. This only applies if your IDP uses the NameID Format 'transient', and the user doesn't log out manually. - Moment où les utilisateurs temporaires doivent être supprimés. Cela ne s'applique que si votre IDP utilise le format NameID "transient" et que l'utilisateur ne se déconnecte pas manuellement. + Moment où les utilisateurs temporaires doivent être supprimés. Cela ne s'applique que si votre IDP utilise le format NameID "transient" et que l'utilisateur ne se déconnecte pas manuellement. @@ -3445,7 +3445,7 @@ doesn't pass when either or both of the selected options are equal or above the Optionally set the 'FriendlyName' value of the Assertion attribute. - Indiquer la valeur "FriendlyName" de l'attribut d'assertion (optionnel) + Indiquer la valeur "FriendlyName" de l'attribut d'assertion (optionnel) @@ -3774,8 +3774,8 @@ doesn't pass when either or both of the selected options are equal or above the - When using an external logging solution for archiving, this can be set to "minutes=5". - En cas d'utilisation d'une solution de journalisation externe pour l'archivage, cette valeur peut être fixée à "minutes=5". + When using an external logging solution for archiving, this can be set to "minutes=5". + En cas d'utilisation d'une solution de journalisation externe pour l'archivage, cette valeur peut être fixée à "minutes=5". @@ -3784,8 +3784,8 @@ doesn't pass when either or both of the selected options are equal or above the - Format: "weeks=3;days=2;hours=3,seconds=2". - Format : "weeks=3;days=2;hours=3,seconds=2". + Format: "weeks=3;days=2;hours=3,seconds=2". + Format : "weeks=3;days=2;hours=3,seconds=2". @@ -3981,10 +3981,10 @@ doesn't pass when either or both of the selected options are equal or above the - Are you sure you want to update ""? + Are you sure you want to update ""? Êtes-vous sûr de vouloir mettre à jour - " - " ? + " + " ? @@ -5070,8 +5070,8 @@ doesn't pass when either or both of the selected options are equal or above the - A "roaming" authenticator, like a YubiKey - Un authentificateur "itinérant", comme une YubiKey + A "roaming" authenticator, like a YubiKey + Un authentificateur "itinérant", comme une YubiKey @@ -5396,7 +5396,7 @@ doesn't pass when either or both of the selected options are equal or above the Show arbitrary input fields to the user, for example during enrollment. Data is saved in the flow context under the 'prompt_data' variable. - Afficher des champs de saisie arbitraires à l'utilisateur, par exemple pendant l'inscription. Les données sont enregistrées dans le contexte du flux sous la variable "prompt_data". + Afficher des champs de saisie arbitraires à l'utilisateur, par exemple pendant l'inscription. Les données sont enregistrées dans le contexte du flux sous la variable "prompt_data". @@ -5405,10 +5405,10 @@ doesn't pass when either or both of the selected options are equal or above the - ("", of type ) + ("", of type ) - (" - ", de type + (" + ", de type ) @@ -5457,8 +5457,8 @@ doesn't pass when either or both of the selected options are equal or above the - If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. - Si défini à une durée supérieure à 0, l'utilisateur aura la possibilité de choisir de "rester connecté", ce qui prolongera sa session jusqu'à la durée spécifiée ici. + If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. + Si défini à une durée supérieure à 0, l'utilisateur aura la possibilité de choisir de "rester connecté", ce qui prolongera sa session jusqu'à la durée spécifiée ici. @@ -6242,7 +6242,7 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti Can be in the format of 'unix://' when connecting to a local docker daemon, using 'ssh://' to connect via SSH, or 'https://:2376' when connecting to a remote system. - Peut être au format "unix://" pour une connexion à un service docker local, "ssh://" pour une connexion via SSH, ou "https://:2376" pour une connexion à un système distant. + Peut être au format "unix://" pour une connexion à un service docker local, "ssh://" pour une connexion via SSH, ou "https://:2376" pour une connexion à un système distant. @@ -7549,7 +7549,7 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you). - Utilisez ce fournisseur avec l'option "auth_request" de Nginx ou "forwardAuth" de Traefik. Chaque application/domaine a besoin de son propre fournisseur. De plus, sur chaque domaine, "/outpost.goauthentik.io" doit être routé vers le poste avancé (lorsque vous utilisez un poste avancé géré, cela est fait pour vous). + Utilisez ce fournisseur avec l'option "auth_request" de Nginx ou "forwardAuth" de Traefik. Chaque application/domaine a besoin de son propre fournisseur. De plus, sur chaque domaine, "/outpost.goauthentik.io" doit être routé vers le poste avancé (lorsque vous utilisez un poste avancé géré, cela est fait pour vous). Default relay state @@ -7963,7 +7963,7 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti Utilisateur créé et ajouté au groupe avec succès - This user will be added to the group "". + This user will be added to the group "". Cet utilisateur sera ajouté au groupe &quot;&quot;. @@ -8041,7 +8041,127 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti Require Outpost (flow can only be executed from an outpost). Forcer l'utilisation d'un avant-poste (le flux ne pourrait être exécuter que depuis un outpost). + + + Connection settings. + + + Successfully updated endpoint. + + + Successfully created endpoint. + + + Protocol + + + RDP + + + SSH + + + VNC + + + Host + + + Hostname/IP to connect to. + + + Endpoint(s) + + + Update Endpoint + + + These bindings control which users will have access to this endpoint. Users must also have access to the application. + + + Create Endpoint + + + RAC is in preview. + + + Update RAC Provider + + + Endpoints + + + General settings + + + RDP settings + + + Ignore server certificate + + + Enable wallpaper + + + Enable font-smoothing + + + Enable full window dragging + + + Network binding + + + No binding + + + Bind ASN + + + Bind ASN and Network + + + Bind ASN, Network and IP + + + Configure if sessions created by this stage should be bound to the Networks they were created in. + + + GeoIP binding + + + Bind Continent + + + Bind Continent and Country + + + Bind Continent, Country and City + + + Configure if sessions created by this stage should be bound to their GeoIP-based location + + + RAC + + + Connection failed after attempts. + + + Re-connecting in second(s). + + + Connecting... + + + Select endpoint to connect to + + + Connection expiry + + + Determines how long a session lasts before being disconnected and requiring re-authorization. - \ No newline at end of file + diff --git a/web/xliff/pl.xlf b/web/xliff/pl.xlf index 3dbed2422..b52ea863c 100644 --- a/web/xliff/pl.xlf +++ b/web/xliff/pl.xlf @@ -6241,6 +6241,126 @@ Bindings to groups/users are checked against the user of the event. Require Outpost (flow can only be executed from an outpost). + + + Connection settings. + + + Successfully updated endpoint. + + + Successfully created endpoint. + + + Protocol + + + RDP + + + SSH + + + VNC + + + Host + + + Hostname/IP to connect to. + + + Endpoint(s) + + + Update Endpoint + + + These bindings control which users will have access to this endpoint. Users must also have access to the application. + + + Create Endpoint + + + RAC is in preview. + + + Update RAC Provider + + + Endpoints + + + General settings + + + RDP settings + + + Ignore server certificate + + + Enable wallpaper + + + Enable font-smoothing + + + Enable full window dragging + + + Network binding + + + No binding + + + Bind ASN + + + Bind ASN and Network + + + Bind ASN, Network and IP + + + Configure if sessions created by this stage should be bound to the Networks they were created in. + + + GeoIP binding + + + Bind Continent + + + Bind Continent and Country + + + Bind Continent, Country and City + + + Configure if sessions created by this stage should be bound to their GeoIP-based location + + + RAC + + + Connection failed after attempts. + + + Re-connecting in second(s). + + + Connecting... + + + Select endpoint to connect to + + + Connection expiry + + + Determines how long a session lasts before being disconnected and requiring re-authorization. diff --git a/web/xliff/pseudo-LOCALE.xlf b/web/xliff/pseudo-LOCALE.xlf index ecd85ea7c..bc883faa7 100644 --- a/web/xliff/pseudo-LOCALE.xlf +++ b/web/xliff/pseudo-LOCALE.xlf @@ -7979,4 +7979,124 @@ Bindings to groups/users are checked against the user of the event. Require Outpost (flow can only be executed from an outpost). + + Connection settings. + + + Successfully updated endpoint. + + + Successfully created endpoint. + + + Protocol + + + RDP + + + SSH + + + VNC + + + Host + + + Hostname/IP to connect to. + + + Endpoint(s) + + + Update Endpoint + + + These bindings control which users will have access to this endpoint. Users must also have access to the application. + + + Create Endpoint + + + RAC is in preview. + + + Update RAC Provider + + + Endpoints + + + General settings + + + RDP settings + + + Ignore server certificate + + + Enable wallpaper + + + Enable font-smoothing + + + Enable full window dragging + + + Network binding + + + No binding + + + Bind ASN + + + Bind ASN and Network + + + Bind ASN, Network and IP + + + Configure if sessions created by this stage should be bound to the Networks they were created in. + + + GeoIP binding + + + Bind Continent + + + Bind Continent and Country + + + Bind Continent, Country and City + + + Configure if sessions created by this stage should be bound to their GeoIP-based location + + + RAC + + + Connection failed after attempts. + + + Re-connecting in second(s). + + + Connecting... + + + Select endpoint to connect to + + + Connection expiry + + + Determines how long a session lasts before being disconnected and requiring re-authorization. + diff --git a/web/xliff/tr.xlf b/web/xliff/tr.xlf index 1b95f3f75..7b03127c0 100644 --- a/web/xliff/tr.xlf +++ b/web/xliff/tr.xlf @@ -6026,6 +6026,126 @@ Bindings to groups/users are checked against the user of the event. Require Outpost (flow can only be executed from an outpost). + + + Connection settings. + + + Successfully updated endpoint. + + + Successfully created endpoint. + + + Protocol + + + RDP + + + SSH + + + VNC + + + Host + + + Hostname/IP to connect to. + + + Endpoint(s) + + + Update Endpoint + + + These bindings control which users will have access to this endpoint. Users must also have access to the application. + + + Create Endpoint + + + RAC is in preview. + + + Update RAC Provider + + + Endpoints + + + General settings + + + RDP settings + + + Ignore server certificate + + + Enable wallpaper + + + Enable font-smoothing + + + Enable full window dragging + + + Network binding + + + No binding + + + Bind ASN + + + Bind ASN and Network + + + Bind ASN, Network and IP + + + Configure if sessions created by this stage should be bound to the Networks they were created in. + + + GeoIP binding + + + Bind Continent + + + Bind Continent and Country + + + Bind Continent, Country and City + + + Configure if sessions created by this stage should be bound to their GeoIP-based location + + + RAC + + + Connection failed after attempts. + + + Re-connecting in second(s). + + + Connecting... + + + Select endpoint to connect to + + + Connection expiry + + + Determines how long a session lasts before being disconnected and requiring re-authorization. diff --git a/web/xliff/zh-Hans.xlf b/web/xliff/zh-Hans.xlf index 61687089d..b2a6e07d1 100644 --- a/web/xliff/zh-Hans.xlf +++ b/web/xliff/zh-Hans.xlf @@ -1,4 +1,4 @@ - + @@ -613,9 +613,9 @@ - The URL "" was not found. - 未找到 URL " - "。 + The URL "" was not found. + 未找到 URL " + "。 @@ -1057,8 +1057,8 @@ - To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. - 要允许任何重定向 URI,请将此值设置为 ".*"。请注意这可能带来的安全影响。 + To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. + 要允许任何重定向 URI,请将此值设置为 ".*"。请注意这可能带来的安全影响。 @@ -1799,8 +1799,8 @@ - Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". - 输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。 + Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". + 输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。 @@ -2983,8 +2983,8 @@ doesn't pass when either or both of the selected options are equal or above the - Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' - 包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...' + Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' + 包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...' @@ -3776,8 +3776,8 @@ doesn't pass when either or both of the selected options are equal or above the - When using an external logging solution for archiving, this can be set to "minutes=5". - 使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。 + When using an external logging solution for archiving, this can be set to "minutes=5". + 使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。 @@ -3786,8 +3786,8 @@ doesn't pass when either or both of the selected options are equal or above the - Format: "weeks=3;days=2;hours=3,seconds=2". - 格式:"weeks=3;days=2;hours=3,seconds=2"。 + Format: "weeks=3;days=2;hours=3,seconds=2". + 格式:"weeks=3;days=2;hours=3,seconds=2"。 @@ -3983,10 +3983,10 @@ doesn't pass when either or both of the selected options are equal or above the - Are you sure you want to update ""? + Are you sure you want to update ""? 您确定要更新 - " - " 吗? + " + " 吗? @@ -5072,7 +5072,7 @@ doesn't pass when either or both of the selected options are equal or above the - A "roaming" authenticator, like a YubiKey + A "roaming" authenticator, like a YubiKey 像 YubiKey 这样的“漫游”身份验证器 @@ -5407,10 +5407,10 @@ doesn't pass when either or both of the selected options are equal or above the - ("", of type ) + ("", of type ) - (" - ",类型为 + (" + ",类型为 @@ -5459,7 +5459,7 @@ doesn't pass when either or both of the selected options are equal or above the - If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. + If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. 如果设置时长大于 0,用户可以选择“保持登录”选项,这将使用户的会话延长此处设置的时间。 @@ -7965,7 +7965,7 @@ Bindings to groups/users are checked against the user of the event. 成功创建用户并添加到组 - This user will be added to the group "". + This user will be added to the group "". 此用户将会被添加到组 &quot;&quot;。 @@ -8043,7 +8043,127 @@ Bindings to groups/users are checked against the user of the event. Require Outpost (flow can only be executed from an outpost). 需要前哨(流程只能从前哨执行)。 + + + Connection settings. + + + Successfully updated endpoint. + + + Successfully created endpoint. + + + Protocol + + + RDP + + + SSH + + + VNC + + + Host + + + Hostname/IP to connect to. + + + Endpoint(s) + + + Update Endpoint + + + These bindings control which users will have access to this endpoint. Users must also have access to the application. + + + Create Endpoint + + + RAC is in preview. + + + Update RAC Provider + + + Endpoints + + + General settings + + + RDP settings + + + Ignore server certificate + + + Enable wallpaper + + + Enable font-smoothing + + + Enable full window dragging + + + Network binding + + + No binding + + + Bind ASN + + + Bind ASN and Network + + + Bind ASN, Network and IP + + + Configure if sessions created by this stage should be bound to the Networks they were created in. + + + GeoIP binding + + + Bind Continent + + + Bind Continent and Country + + + Bind Continent, Country and City + + + Configure if sessions created by this stage should be bound to their GeoIP-based location + + + RAC + + + Connection failed after attempts. + + + Re-connecting in second(s). + + + Connecting... + + + Select endpoint to connect to + + + Connection expiry + + + Determines how long a session lasts before being disconnected and requiring re-authorization. - \ No newline at end of file + diff --git a/web/xliff/zh-Hant.xlf b/web/xliff/zh-Hant.xlf index ff31e2854..65794b706 100644 --- a/web/xliff/zh-Hant.xlf +++ b/web/xliff/zh-Hant.xlf @@ -6074,6 +6074,126 @@ Bindings to groups/users are checked against the user of the event. Require Outpost (flow can only be executed from an outpost). + + + Connection settings. + + + Successfully updated endpoint. + + + Successfully created endpoint. + + + Protocol + + + RDP + + + SSH + + + VNC + + + Host + + + Hostname/IP to connect to. + + + Endpoint(s) + + + Update Endpoint + + + These bindings control which users will have access to this endpoint. Users must also have access to the application. + + + Create Endpoint + + + RAC is in preview. + + + Update RAC Provider + + + Endpoints + + + General settings + + + RDP settings + + + Ignore server certificate + + + Enable wallpaper + + + Enable font-smoothing + + + Enable full window dragging + + + Network binding + + + No binding + + + Bind ASN + + + Bind ASN and Network + + + Bind ASN, Network and IP + + + Configure if sessions created by this stage should be bound to the Networks they were created in. + + + GeoIP binding + + + Bind Continent + + + Bind Continent and Country + + + Bind Continent, Country and City + + + Configure if sessions created by this stage should be bound to their GeoIP-based location + + + RAC + + + Connection failed after attempts. + + + Re-connecting in second(s). + + + Connecting... + + + Select endpoint to connect to + + + Connection expiry + + + Determines how long a session lasts before being disconnected and requiring re-authorization. diff --git a/web/xliff/zh_TW.xlf b/web/xliff/zh_TW.xlf index 66c5d3228..9a9b690bd 100644 --- a/web/xliff/zh_TW.xlf +++ b/web/xliff/zh_TW.xlf @@ -7963,6 +7963,126 @@ Bindings to groups/users are checked against the user of the event. Require Outpost (flow can only be executed from an outpost). + + + Connection settings. + + + Successfully updated endpoint. + + + Successfully created endpoint. + + + Protocol + + + RDP + + + SSH + + + VNC + + + Host + + + Hostname/IP to connect to. + + + Endpoint(s) + + + Update Endpoint + + + These bindings control which users will have access to this endpoint. Users must also have access to the application. + + + Create Endpoint + + + RAC is in preview. + + + Update RAC Provider + + + Endpoints + + + General settings + + + RDP settings + + + Ignore server certificate + + + Enable wallpaper + + + Enable font-smoothing + + + Enable full window dragging + + + Network binding + + + No binding + + + Bind ASN + + + Bind ASN and Network + + + Bind ASN, Network and IP + + + Configure if sessions created by this stage should be bound to the Networks they were created in. + + + GeoIP binding + + + Bind Continent + + + Bind Continent and Country + + + Bind Continent, Country and City + + + Configure if sessions created by this stage should be bound to their GeoIP-based location + + + RAC + + + Connection failed after attempts. + + + Re-connecting in second(s). + + + Connecting... + + + Select endpoint to connect to + + + Connection expiry + + + Determines how long a session lasts before being disconnected and requiring re-authorization. diff --git a/website/docs/outposts/index.mdx b/website/docs/outposts/index.mdx index bd3d7744c..b5ffe1c25 100644 --- a/website/docs/outposts/index.mdx +++ b/website/docs/outposts/index.mdx @@ -7,6 +7,7 @@ An outpost is a single deployment of an authentik component, which can be deploy - [LDAP Provider](../providers/ldap/index.md) - [Proxy Provider](../providers/proxy/index.md) - [RADIUS Provider](../providers/radius/index.md) +- [RAC Provider](../providers/rac/index.md) ![](outposts.png) diff --git a/website/docs/providers/rac/index.md b/website/docs/providers/rac/index.md new file mode 100644 index 000000000..67e3b74da --- /dev/null +++ b/website/docs/providers/rac/index.md @@ -0,0 +1,47 @@ +--- +title: Remote Access (RAC) Provider +--- + +Enterprise + +--- + +:::info +This feature is in technical preview, so please report any Bugs you run into on [GitHub](https://github.com/goauthentik/authentik/issues) +::: + +The Remote access provider allows users to access Windows/macOS/Linux machines via [RDP](https://en.wikipedia.org/wiki/Remote_Desktop_Protocol)/[SSH](https://en.wikipedia.org/wiki/Secure_Shell)/[VNC](https://en.wikipedia.org/wiki/Virtual_Network_Computing). + +:::info +This provider requires the deployment of the [RAC Outpost](../../outposts/) +::: + +## Endpoints + +Unlike other providers, where one provider-application pair must be created for each resource you wish to access, the RAC provider handles this slightly differently. For each machine (computer/server) that should be accessible, an _Endpoint_ object must be created within an RAC provider. + +The _Endpoint_ object specifies the hostname/IP of the machine to connect to, as well as the protocol to use. Additionally it is possible to bind policies to _endpoint_ objects to restrict access. Users must have access to both the application the RAC Provider is using as well as the individual endpoint. + +Configuration like credentials can be specified through _settings_, which can be specified on different levels and are all merged together when connecting: + +1. Provider settings +2. Endpoint settings +3. Connection settings (see [Connections](#connections)) +4. Provider property mapping settings +5. Endpoint property mapping settings + +## Connections + +Each connection is authorized through the policies bound to the application and the endpoint, and additional verification can be done with the authorization flow. + +Additionally it is possible to modify the connection settings through the authorization flow. Configuration set in `connection_settings` in the flow plan context will be merged with other settings as shown above. + +A new connection is created every time an endpoint is selected in the [User Interface](../../interfaces/user/customization.mdx). Once the user's authentik session expires, the connection is terminated. Additionally, the connection timeout can be specified in the provider, which applies even if the user is still authenticated. The connection can also be terminated manually. + +## Capabilities + +The following features are currently supported: + +- Bi-directional clipboard +- Audio redirection (from remote machine to browser) +- Resizing diff --git a/website/docs/providers/radius/index.md b/website/docs/providers/radius/index.md index f9f0b5403..f7966ef2f 100644 --- a/website/docs/providers/radius/index.md +++ b/website/docs/providers/radius/index.md @@ -2,10 +2,6 @@ title: Radius Provider --- -:::info -This feature is still in technical preview, so please report any Bugs you run into on [GitHub](https://github.com/goauthentik/authentik/issues) -::: - You can configure a Radius Provider for applications that don't support any other protocols or require Radius. :::info diff --git a/website/sidebars.js b/website/sidebars.js index fe1b6725e..25c08ea1b 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -110,6 +110,7 @@ const docsSidebar = { items: ["providers/ldap/generic_setup"], }, "providers/scim/index", + "providers/rac/index", ], }, { From 5304bd65f5bdd6325c5cdbfdecef8d5776864594 Mon Sep 17 00:00:00 2001 From: "authentik-automation[bot]" <135050075+authentik-automation[bot]@users.noreply.github.com> Date: Sat, 30 Dec 2023 21:55:53 +0100 Subject: [PATCH 16/31] web: bump API Client version (#8025) * web: bump API Client version Signed-off-by: GitHub * bump go api too Signed-off-by: Jens Langhammer --------- Signed-off-by: GitHub Signed-off-by: Jens Langhammer Co-authored-by: authentik-automation[bot] <135050075+authentik-automation[bot]@users.noreply.github.com> Co-authored-by: Jens Langhammer --- go.mod | 2 +- go.sum | 4 ++-- web/package-lock.json | 8 ++++---- web/package.json | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 269d4c295..ed9759796 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/spf13/cobra v1.8.0 github.com/stretchr/testify v1.8.4 github.com/wwt/guac v1.3.2 - goauthentik.io/api/v3 v3.2023105.2 + goauthentik.io/api/v3 v3.2023105.3 golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab golang.org/x/oauth2 v0.15.0 golang.org/x/sync v0.5.0 diff --git a/go.sum b/go.sum index d9acde526..3000d744b 100644 --- a/go.sum +++ b/go.sum @@ -316,8 +316,8 @@ go.opentelemetry.io/otel/trace v1.17.0 h1:/SWhSRHmDPOImIAetP1QAeMnZYiQXrTy4fMMYO go.opentelemetry.io/otel/trace v1.17.0/go.mod h1:I/4vKTgFclIsXRVucpH25X0mpFSczM7aHeaz0ZBLWjY= go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= -goauthentik.io/api/v3 v3.2023105.2 h1:ZUblqN5LidnCSlEZ/L19h7OnwppnAA3m5AGC7wUN0Ew= -goauthentik.io/api/v3 v3.2023105.2/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw= +goauthentik.io/api/v3 v3.2023105.3 h1:x0pMJIKkbN198OOssqA94h8bO6ft9gwG8bpZqZL7WVg= +goauthentik.io/api/v3 v3.2023105.3/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= diff --git a/web/package-lock.json b/web/package-lock.json index ac34f18b7..e4ccbd389 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -17,7 +17,7 @@ "@codemirror/theme-one-dark": "^6.1.2", "@formatjs/intl-listformat": "^7.5.3", "@fortawesome/fontawesome-free": "^6.5.1", - "@goauthentik/api": "^2023.10.5-1703290840", + "@goauthentik/api": "^2023.10.5-1703968412", "@lit-labs/context": "^0.4.0", "@lit-labs/task": "^3.1.0", "@lit/localize": "^0.11.4", @@ -2916,9 +2916,9 @@ } }, "node_modules/@goauthentik/api": { - "version": "2023.10.5-1703290840", - "resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2023.10.5-1703290840.tgz", - "integrity": "sha512-xYZ2TnUskucxc6sjM7WGl6eiHyXI+ioB3xeXMBd+v07Bvx1xFuQIcv3PXwauKvFzAQD8GtSUbL8tgZ08WpePLQ==" + "version": "2023.10.5-1703968412", + "resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2023.10.5-1703968412.tgz", + "integrity": "sha512-/2QDgGkWGXOYDqH49/2hNs+U8TqdE94hkMrJc8A6L+NAy8x/zKAY39eUHs85jmwt013N5duD/jKiJsRftHsDig==" }, "node_modules/@hcaptcha/types": { "version": "1.0.3", diff --git a/web/package.json b/web/package.json index f446eee57..6a55bfc87 100644 --- a/web/package.json +++ b/web/package.json @@ -42,7 +42,7 @@ "@codemirror/theme-one-dark": "^6.1.2", "@formatjs/intl-listformat": "^7.5.3", "@fortawesome/fontawesome-free": "^6.5.1", - "@goauthentik/api": "^2023.10.5-1703290840", + "@goauthentik/api": "^2023.10.5-1703968412", "@lit-labs/context": "^0.4.0", "@lit-labs/task": "^3.1.0", "@lit/localize": "^0.11.4", From b778c35396fa26f7aa95523bd86f0d9c2efbe784 Mon Sep 17 00:00:00 2001 From: Bryan J <132493975+chkpwd@users.noreply.github.com> Date: Sun, 31 Dec 2023 15:32:13 -0500 Subject: [PATCH 17/31] website/docs: fix typo (#8015) Update kubernetes.md Signed-off-by: Bryan J. <132493975+chkpwd@users.noreply.github.com> --- website/docs/outposts/integrations/kubernetes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/outposts/integrations/kubernetes.md b/website/docs/outposts/integrations/kubernetes.md index 0a94f9893..f50d48a50 100644 --- a/website/docs/outposts/integrations/kubernetes.md +++ b/website/docs/outposts/integrations/kubernetes.md @@ -2,7 +2,7 @@ title: Kubernetes --- -The kubernetes integration with automatically deploy outposts on any Kubernetes Cluster. +The kubernetes integration will automatically deploy outposts on any Kubernetes Cluster. This integration has the advantage over manual deployments of automatic updates (whenever authentik is updated, it updates the outposts), and authentik can (in a future version) automatically rotate the token that the outpost uses to communicate with the core authentik server. From b84facb9fcef6cc7edd7960affbd43e1e3c56b1c Mon Sep 17 00:00:00 2001 From: Jens L Date: Mon, 1 Jan 2024 21:08:40 +0100 Subject: [PATCH 18/31] tests/e2e: fix tests to work without docker network_mode host (#8035) * tests/e2e: start fixing tests to work without docker network_mode host Signed-off-by: Jens Langhammer * migrate saml and oauth source Signed-off-by: Jens Langhammer * update deps (mainly to update lxml which was causing a segfault on macos) Signed-off-by: Jens Langhammer * migrate saml source Signed-off-by: Jens Langhammer * format Signed-off-by: Jens Langhammer * fix sentry env in testing Signed-off-by: Jens Langhammer * make oauth types name and slug make more sense Signed-off-by: Jens Langhammer * migrate ldap Signed-off-by: Jens Langhammer * make tests run with --keepdb? partially? Signed-off-by: Jens Langhammer * migrate radius Signed-off-by: Jens Langhammer * fix proxy provider first half Signed-off-by: Jens Langhammer * install libxml2-dev to work around seg fault? Signed-off-by: Jens Langhammer * actually that doesn't change anything since use latest libxml2 Signed-off-by: Jens Langhammer * format Signed-off-by: Jens Langhammer * refactor did not refactor the code Signed-off-by: Jens Langhammer --------- Signed-off-by: Jens Langhammer --- authentik/root/test_runner.py | 7 +- authentik/sources/oauth/api/source.py | 4 +- authentik/sources/oauth/types/apple.py | 4 +- authentik/sources/oauth/types/azure_ad.py | 4 +- authentik/sources/oauth/types/discord.py | 4 +- authentik/sources/oauth/types/facebook.py | 4 +- authentik/sources/oauth/types/github.py | 4 +- authentik/sources/oauth/types/google.py | 4 +- authentik/sources/oauth/types/mailcow.py | 4 +- authentik/sources/oauth/types/oidc.py | 4 +- authentik/sources/oauth/types/okta.py | 4 +- authentik/sources/oauth/types/patreon.py | 4 +- authentik/sources/oauth/types/reddit.py | 4 +- authentik/sources/oauth/types/registry.py | 10 +- authentik/sources/oauth/types/twitch.py | 4 +- authentik/sources/oauth/types/twitter.py | 4 +- poetry.lock | 1065 +++++++++-------- pyproject.toml | 7 +- tests/e2e/test_provider_ldap.py | 15 +- tests/e2e/test_provider_oauth2_github.py | 7 +- tests/e2e/test_provider_oauth2_grafana.py | 7 +- tests/e2e/test_provider_oidc.py | 9 +- tests/e2e/test_provider_oidc_implicit.py | 9 +- tests/e2e/test_provider_proxy.py | 13 +- tests/e2e/test_provider_radius.py | 5 +- tests/e2e/test_provider_saml.py | 7 +- tests/e2e/test_source_oauth_oauth1.py | 141 +++ ...e_oauth.py => test_source_oauth_oauth2.py} | 138 +-- tests/e2e/test_source_saml.py | 36 +- tests/e2e/utils.py | 9 + 30 files changed, 836 insertions(+), 705 deletions(-) create mode 100644 tests/e2e/test_source_oauth_oauth1.py rename tests/e2e/{test_source_oauth.py => test_source_oauth_oauth2.py} (62%) diff --git a/authentik/root/test_runner.py b/authentik/root/test_runner.py index bc3b3b968..d1e50bad4 100644 --- a/authentik/root/test_runner.py +++ b/authentik/root/test_runner.py @@ -40,10 +40,9 @@ class PytestTestRunner(DiscoverRunner): # pragma: no cover f"ghcr.io/goauthentik/dev-%(type)s:{get_docker_tag()}", ) CONFIG.set("error_reporting.sample_rate", 0) - sentry_init( - environment="testing", - send_default_pii=True, - ) + CONFIG.set("error_reporting.environment", "testing") + CONFIG.set("error_reporting.send_pii", True) + sentry_init() @classmethod def add_arguments(cls, parser: ArgumentParser): diff --git a/authentik/sources/oauth/api/source.py b/authentik/sources/oauth/api/source.py index a17bc6b03..08b676de5 100644 --- a/authentik/sources/oauth/api/source.py +++ b/authentik/sources/oauth/api/source.py @@ -99,7 +99,9 @@ class OAuthSourceSerializer(SourceSerializer): ]: if getattr(provider_type, url, None) is None: if url not in attrs: - raise ValidationError(f"{url} is required for provider {provider_type.name}") + raise ValidationError( + f"{url} is required for provider {provider_type.verbose_name}" + ) return attrs class Meta: diff --git a/authentik/sources/oauth/types/apple.py b/authentik/sources/oauth/types/apple.py index 2e0cc8f85..5ead5bdbd 100644 --- a/authentik/sources/oauth/types/apple.py +++ b/authentik/sources/oauth/types/apple.py @@ -104,8 +104,8 @@ class AppleType(SourceType): callback_view = AppleOAuth2Callback redirect_view = AppleOAuthRedirect - name = "Apple" - slug = "apple" + verbose_name = "Apple" + name = "apple" authorization_url = "https://appleid.apple.com/auth/authorize" access_token_url = "https://appleid.apple.com/auth/token" # nosec diff --git a/authentik/sources/oauth/types/azure_ad.py b/authentik/sources/oauth/types/azure_ad.py index a247cea5d..ec57640d1 100644 --- a/authentik/sources/oauth/types/azure_ad.py +++ b/authentik/sources/oauth/types/azure_ad.py @@ -43,8 +43,8 @@ class AzureADType(SourceType): callback_view = AzureADOAuthCallback redirect_view = AzureADOAuthRedirect - name = "Azure AD" - slug = "azuread" + verbose_name = "Azure AD" + name = "azuread" urls_customizable = True diff --git a/authentik/sources/oauth/types/discord.py b/authentik/sources/oauth/types/discord.py index 10c461f5a..4fb34c672 100644 --- a/authentik/sources/oauth/types/discord.py +++ b/authentik/sources/oauth/types/discord.py @@ -36,8 +36,8 @@ class DiscordType(SourceType): callback_view = DiscordOAuth2Callback redirect_view = DiscordOAuthRedirect - name = "Discord" - slug = "discord" + verbose_name = "Discord" + name = "discord" authorization_url = "https://discord.com/api/oauth2/authorize" access_token_url = "https://discord.com/api/oauth2/token" # nosec diff --git a/authentik/sources/oauth/types/facebook.py b/authentik/sources/oauth/types/facebook.py index 9176afeb5..69893298b 100644 --- a/authentik/sources/oauth/types/facebook.py +++ b/authentik/sources/oauth/types/facebook.py @@ -48,8 +48,8 @@ class FacebookType(SourceType): callback_view = FacebookOAuth2Callback redirect_view = FacebookOAuthRedirect - name = "Facebook" - slug = "facebook" + verbose_name = "Facebook" + name = "facebook" authorization_url = "https://www.facebook.com/v7.0/dialog/oauth" access_token_url = "https://graph.facebook.com/v7.0/oauth/access_token" # nosec diff --git a/authentik/sources/oauth/types/github.py b/authentik/sources/oauth/types/github.py index 327a4ee81..b9e5ed17c 100644 --- a/authentik/sources/oauth/types/github.py +++ b/authentik/sources/oauth/types/github.py @@ -68,8 +68,8 @@ class GitHubType(SourceType): callback_view = GitHubOAuth2Callback redirect_view = GitHubOAuthRedirect - name = "GitHub" - slug = "github" + verbose_name = "GitHub" + name = "github" urls_customizable = True diff --git a/authentik/sources/oauth/types/google.py b/authentik/sources/oauth/types/google.py index 1956aadcd..94b6f7842 100644 --- a/authentik/sources/oauth/types/google.py +++ b/authentik/sources/oauth/types/google.py @@ -34,8 +34,8 @@ class GoogleType(SourceType): callback_view = GoogleOAuth2Callback redirect_view = GoogleOAuthRedirect - name = "Google" - slug = "google" + verbose_name = "Google" + name = "google" authorization_url = "https://accounts.google.com/o/oauth2/auth" access_token_url = "https://oauth2.googleapis.com/token" # nosec diff --git a/authentik/sources/oauth/types/mailcow.py b/authentik/sources/oauth/types/mailcow.py index 8be201105..8bff86af5 100644 --- a/authentik/sources/oauth/types/mailcow.py +++ b/authentik/sources/oauth/types/mailcow.py @@ -63,7 +63,7 @@ class MailcowType(SourceType): callback_view = MailcowOAuth2Callback redirect_view = MailcowOAuthRedirect - name = "Mailcow" - slug = "mailcow" + verbose_name = "Mailcow" + name = "mailcow" urls_customizable = True diff --git a/authentik/sources/oauth/types/oidc.py b/authentik/sources/oauth/types/oidc.py index bd6853117..4e32f3fee 100644 --- a/authentik/sources/oauth/types/oidc.py +++ b/authentik/sources/oauth/types/oidc.py @@ -42,7 +42,7 @@ class OpenIDConnectType(SourceType): callback_view = OpenIDConnectOAuth2Callback redirect_view = OpenIDConnectOAuthRedirect - name = "OpenID Connect" - slug = "openidconnect" + verbose_name = "OpenID Connect" + name = "openidconnect" urls_customizable = True diff --git a/authentik/sources/oauth/types/okta.py b/authentik/sources/oauth/types/okta.py index 2de02edde..1f1f07dc7 100644 --- a/authentik/sources/oauth/types/okta.py +++ b/authentik/sources/oauth/types/okta.py @@ -42,7 +42,7 @@ class OktaType(SourceType): callback_view = OktaOAuth2Callback redirect_view = OktaOAuthRedirect - name = "Okta" - slug = "okta" + verbose_name = "Okta" + name = "okta" urls_customizable = True diff --git a/authentik/sources/oauth/types/patreon.py b/authentik/sources/oauth/types/patreon.py index d02c3d33d..8d11bf27a 100644 --- a/authentik/sources/oauth/types/patreon.py +++ b/authentik/sources/oauth/types/patreon.py @@ -43,8 +43,8 @@ class PatreonType(SourceType): callback_view = PatreonOAuthCallback redirect_view = PatreonOAuthRedirect - name = "Patreon" - slug = "patreon" + verbose_name = "Patreon" + name = "patreon" authorization_url = "https://www.patreon.com/oauth2/authorize" access_token_url = "https://www.patreon.com/api/oauth2/token" # nosec diff --git a/authentik/sources/oauth/types/reddit.py b/authentik/sources/oauth/types/reddit.py index 1afd0ca06..7d558cbb3 100644 --- a/authentik/sources/oauth/types/reddit.py +++ b/authentik/sources/oauth/types/reddit.py @@ -51,8 +51,8 @@ class RedditType(SourceType): callback_view = RedditOAuth2Callback redirect_view = RedditOAuthRedirect - name = "Reddit" - slug = "reddit" + verbose_name = "Reddit" + name = "reddit" authorization_url = "https://www.reddit.com/api/v1/authorize" access_token_url = "https://www.reddit.com/api/v1/access_token" # nosec diff --git a/authentik/sources/oauth/types/registry.py b/authentik/sources/oauth/types/registry.py index ae8a5dd0b..99cb87dd5 100644 --- a/authentik/sources/oauth/types/registry.py +++ b/authentik/sources/oauth/types/registry.py @@ -28,7 +28,7 @@ class SourceType: callback_view = OAuthCallback redirect_view = OAuthRedirect name: str = "default" - slug: str = "default" + verbose_name: str = "Default source type" urls_customizable = False @@ -41,7 +41,7 @@ class SourceType: def icon_url(self) -> str: """Get Icon URL for login""" - return static(f"authentik/sources/{self.slug}.svg") + return static(f"authentik/sources/{self.name}.svg") def login_challenge(self, source: OAuthSource, request: HttpRequest) -> Challenge: """Allow types to return custom challenges""" @@ -77,20 +77,20 @@ class SourceTypeRegistry: def get_name_tuple(self): """Get list of tuples of all registered names""" - return [(x.slug, x.name) for x in self.__sources] + return [(x.name, x.verbose_name) for x in self.__sources] def find_type(self, type_name: str) -> Type[SourceType]: """Find type based on source""" found_type = None for src_type in self.__sources: - if src_type.slug == type_name: + if src_type.name == type_name: return src_type if not found_type: found_type = SourceType LOGGER.warning( "no matching type found, using default", wanted=type_name, - have=[x.slug for x in self.__sources], + have=[x.name for x in self.__sources], ) return found_type diff --git a/authentik/sources/oauth/types/twitch.py b/authentik/sources/oauth/types/twitch.py index 62e7b94d4..52b8bae0b 100644 --- a/authentik/sources/oauth/types/twitch.py +++ b/authentik/sources/oauth/types/twitch.py @@ -49,8 +49,8 @@ class TwitchType(SourceType): callback_view = TwitchOAuth2Callback redirect_view = TwitchOAuthRedirect - name = "Twitch" - slug = "twitch" + verbose_name = "Twitch" + name = "twitch" authorization_url = "https://id.twitch.tv/oauth2/authorize" access_token_url = "https://id.twitch.tv/oauth2/token" # nosec diff --git a/authentik/sources/oauth/types/twitter.py b/authentik/sources/oauth/types/twitter.py index dc9909adb..7b75f04ea 100644 --- a/authentik/sources/oauth/types/twitter.py +++ b/authentik/sources/oauth/types/twitter.py @@ -66,8 +66,8 @@ class TwitterType(SourceType): callback_view = TwitterOAuthCallback redirect_view = TwitterOAuthRedirect - name = "Twitter" - slug = "twitter" + verbose_name = "Twitter" + name = "twitter" authorization_url = "https://twitter.com/i/oauth2/authorize" access_token_url = "https://api.twitter.com/2/oauth2/token" # nosec diff --git a/poetry.lock b/poetry.lock index 500e2e832..ce3e4f754 100644 --- a/poetry.lock +++ b/poetry.lock @@ -263,21 +263,22 @@ files = [ [[package]] name = "attrs" -version = "23.1.0" +version = "23.2.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.7" files = [ - {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, - {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, + {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, + {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, ] [package.extras] cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] -dev = ["attrs[docs,tests]", "pre-commit"] +dev = ["attrs[tests]", "pre-commit"] docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] tests = ["attrs[tests-no-zope]", "zope-interface"] -tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] +tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] +tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] [[package]] name = "autobahn" @@ -415,33 +416,33 @@ files = [ [[package]] name = "black" -version = "23.12.0" +version = "23.12.1" description = "The uncompromising code formatter." optional = false python-versions = ">=3.8" files = [ - {file = "black-23.12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:67f19562d367468ab59bd6c36a72b2c84bc2f16b59788690e02bbcb140a77175"}, - {file = "black-23.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bbd75d9f28a7283b7426160ca21c5bd640ca7cd8ef6630b4754b6df9e2da8462"}, - {file = "black-23.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:593596f699ca2dcbbbdfa59fcda7d8ad6604370c10228223cd6cf6ce1ce7ed7e"}, - {file = "black-23.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:12d5f10cce8dc27202e9a252acd1c9a426c83f95496c959406c96b785a92bb7d"}, - {file = "black-23.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e73c5e3d37e5a3513d16b33305713237a234396ae56769b839d7c40759b8a41c"}, - {file = "black-23.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ba09cae1657c4f8a8c9ff6cfd4a6baaf915bb4ef7d03acffe6a2f6585fa1bd01"}, - {file = "black-23.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ace64c1a349c162d6da3cef91e3b0e78c4fc596ffde9413efa0525456148873d"}, - {file = "black-23.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:72db37a2266b16d256b3ea88b9affcdd5c41a74db551ec3dd4609a59c17d25bf"}, - {file = "black-23.12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fdf6f23c83078a6c8da2442f4d4eeb19c28ac2a6416da7671b72f0295c4a697b"}, - {file = "black-23.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39dda060b9b395a6b7bf9c5db28ac87b3c3f48d4fdff470fa8a94ab8271da47e"}, - {file = "black-23.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7231670266ca5191a76cb838185d9be59cfa4f5dd401b7c1c70b993c58f6b1b5"}, - {file = "black-23.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:193946e634e80bfb3aec41830f5d7431f8dd5b20d11d89be14b84a97c6b8bc75"}, - {file = "black-23.12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bcf91b01ddd91a2fed9a8006d7baa94ccefe7e518556470cf40213bd3d44bbbc"}, - {file = "black-23.12.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:996650a89fe5892714ea4ea87bc45e41a59a1e01675c42c433a35b490e5aa3f0"}, - {file = "black-23.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bdbff34c487239a63d86db0c9385b27cdd68b1bfa4e706aa74bb94a435403672"}, - {file = "black-23.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:97af22278043a6a1272daca10a6f4d36c04dfa77e61cbaaf4482e08f3640e9f0"}, - {file = "black-23.12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ead25c273adfad1095a8ad32afdb8304933efba56e3c1d31b0fee4143a1e424a"}, - {file = "black-23.12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c71048345bdbced456cddf1622832276d98a710196b842407840ae8055ade6ee"}, - {file = "black-23.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a832b6e00eef2c13b3239d514ea3b7d5cc3eaa03d0474eedcbbda59441ba5d"}, - {file = "black-23.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:6a82a711d13e61840fb11a6dfecc7287f2424f1ca34765e70c909a35ffa7fb95"}, - {file = "black-23.12.0-py3-none-any.whl", hash = "sha256:a7c07db8200b5315dc07e331dda4d889a56f6bf4db6a9c2a526fa3166a81614f"}, - {file = "black-23.12.0.tar.gz", hash = "sha256:330a327b422aca0634ecd115985c1c7fd7bdb5b5a2ef8aa9888a82e2ebe9437a"}, + {file = "black-23.12.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0aaf6041986767a5e0ce663c7a2f0e9eaf21e6ff87a5f95cbf3675bfd4c41d2"}, + {file = "black-23.12.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c88b3711d12905b74206227109272673edce0cb29f27e1385f33b0163c414bba"}, + {file = "black-23.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a920b569dc6b3472513ba6ddea21f440d4b4c699494d2e972a1753cdc25df7b0"}, + {file = "black-23.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:3fa4be75ef2a6b96ea8d92b1587dd8cb3a35c7e3d51f0738ced0781c3aa3a5a3"}, + {file = "black-23.12.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8d4df77958a622f9b5a4c96edb4b8c0034f8434032ab11077ec6c56ae9f384ba"}, + {file = "black-23.12.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:602cfb1196dc692424c70b6507593a2b29aac0547c1be9a1d1365f0d964c353b"}, + {file = "black-23.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c4352800f14be5b4864016882cdba10755bd50805c95f728011bcb47a4afd59"}, + {file = "black-23.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:0808494f2b2df923ffc5723ed3c7b096bd76341f6213989759287611e9837d50"}, + {file = "black-23.12.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:25e57fd232a6d6ff3f4478a6fd0580838e47c93c83eaf1ccc92d4faf27112c4e"}, + {file = "black-23.12.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2d9e13db441c509a3763a7a3d9a49ccc1b4e974a47be4e08ade2a228876500ec"}, + {file = "black-23.12.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1bd9c210f8b109b1762ec9fd36592fdd528485aadb3f5849b2740ef17e674e"}, + {file = "black-23.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:ae76c22bde5cbb6bfd211ec343ded2163bba7883c7bc77f6b756a1049436fbb9"}, + {file = "black-23.12.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1fa88a0f74e50e4487477bc0bb900c6781dbddfdfa32691e780bf854c3b4a47f"}, + {file = "black-23.12.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a4d6a9668e45ad99d2f8ec70d5c8c04ef4f32f648ef39048d010b0689832ec6d"}, + {file = "black-23.12.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b18fb2ae6c4bb63eebe5be6bd869ba2f14fd0259bda7d18a46b764d8fb86298a"}, + {file = "black-23.12.1-cp38-cp38-win_amd64.whl", hash = "sha256:c04b6d9d20e9c13f43eee8ea87d44156b8505ca8a3c878773f68b4e4812a421e"}, + {file = "black-23.12.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e1b38b3135fd4c025c28c55ddfc236b05af657828a8a6abe5deec419a0b7055"}, + {file = "black-23.12.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4f0031eaa7b921db76decd73636ef3a12c942ed367d8c3841a0739412b260a54"}, + {file = "black-23.12.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97e56155c6b737854e60a9ab1c598ff2533d57e7506d97af5481141671abf3ea"}, + {file = "black-23.12.1-cp39-cp39-win_amd64.whl", hash = "sha256:dd15245c8b68fe2b6bd0f32c1556509d11bb33aec9b5d0866dd8e2ed3dba09c2"}, + {file = "black-23.12.1-py3-none-any.whl", hash = "sha256:78baad24af0f033958cad29731e27363183e140962595def56423e626f4bee3e"}, + {file = "black-23.12.1.tar.gz", hash = "sha256:4ce3ef14ebe8d9509188014d96af1c456a910d5b5cbf434a09fef7e024b3d0d5"}, ] [package.dependencies] @@ -904,63 +905,63 @@ files = [ [[package]] name = "coverage" -version = "7.3.3" +version = "7.4.0" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d874434e0cb7b90f7af2b6e3309b0733cde8ec1476eb47db148ed7deeb2a9494"}, - {file = "coverage-7.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ee6621dccce8af666b8c4651f9f43467bfbf409607c604b840b78f4ff3619aeb"}, - {file = "coverage-7.3.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1367aa411afb4431ab58fd7ee102adb2665894d047c490649e86219327183134"}, - {file = "coverage-7.3.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f0f8f0c497eb9c9f18f21de0750c8d8b4b9c7000b43996a094290b59d0e7523"}, - {file = "coverage-7.3.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db0338c4b0951d93d547e0ff8d8ea340fecf5885f5b00b23be5aa99549e14cfd"}, - {file = "coverage-7.3.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d31650d313bd90d027f4be7663dfa2241079edd780b56ac416b56eebe0a21aab"}, - {file = "coverage-7.3.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9437a4074b43c177c92c96d051957592afd85ba00d3e92002c8ef45ee75df438"}, - {file = "coverage-7.3.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9e17d9cb06c13b4f2ef570355fa45797d10f19ca71395910b249e3f77942a837"}, - {file = "coverage-7.3.3-cp310-cp310-win32.whl", hash = "sha256:eee5e741b43ea1b49d98ab6e40f7e299e97715af2488d1c77a90de4a663a86e2"}, - {file = "coverage-7.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:593efa42160c15c59ee9b66c5f27a453ed3968718e6e58431cdfb2d50d5ad284"}, - {file = "coverage-7.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8c944cf1775235c0857829c275c777a2c3e33032e544bcef614036f337ac37bb"}, - {file = "coverage-7.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:eda7f6e92358ac9e1717ce1f0377ed2b9320cea070906ece4e5c11d172a45a39"}, - {file = "coverage-7.3.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c854c1d2c7d3e47f7120b560d1a30c1ca221e207439608d27bc4d08fd4aeae8"}, - {file = "coverage-7.3.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:222b038f08a7ebed1e4e78ccf3c09a1ca4ac3da16de983e66520973443b546bc"}, - {file = "coverage-7.3.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff4800783d85bff132f2cc7d007426ec698cdce08c3062c8d501ad3f4ea3d16c"}, - {file = "coverage-7.3.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fc200cec654311ca2c3f5ab3ce2220521b3d4732f68e1b1e79bef8fcfc1f2b97"}, - {file = "coverage-7.3.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:307aecb65bb77cbfebf2eb6e12009e9034d050c6c69d8a5f3f737b329f4f15fb"}, - {file = "coverage-7.3.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ffb0eacbadb705c0a6969b0adf468f126b064f3362411df95f6d4f31c40d31c1"}, - {file = "coverage-7.3.3-cp311-cp311-win32.whl", hash = "sha256:79c32f875fd7c0ed8d642b221cf81feba98183d2ff14d1f37a1bbce6b0347d9f"}, - {file = "coverage-7.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:243576944f7c1a1205e5cd658533a50eba662c74f9be4c050d51c69bd4532936"}, - {file = "coverage-7.3.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a2ac4245f18057dfec3b0074c4eb366953bca6787f1ec397c004c78176a23d56"}, - {file = "coverage-7.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f9191be7af41f0b54324ded600e8ddbcabea23e1e8ba419d9a53b241dece821d"}, - {file = "coverage-7.3.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31c0b1b8b5a4aebf8fcd227237fc4263aa7fa0ddcd4d288d42f50eff18b0bac4"}, - {file = "coverage-7.3.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee453085279df1bac0996bc97004771a4a052b1f1e23f6101213e3796ff3cb85"}, - {file = "coverage-7.3.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1191270b06ecd68b1d00897b2daddb98e1719f63750969614ceb3438228c088e"}, - {file = "coverage-7.3.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:007a7e49831cfe387473e92e9ff07377f6121120669ddc39674e7244350a6a29"}, - {file = "coverage-7.3.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:af75cf83c2d57717a8493ed2246d34b1f3398cb8a92b10fd7a1858cad8e78f59"}, - {file = "coverage-7.3.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:811ca7373da32f1ccee2927dc27dc523462fd30674a80102f86c6753d6681bc6"}, - {file = "coverage-7.3.3-cp312-cp312-win32.whl", hash = "sha256:733537a182b5d62184f2a72796eb6901299898231a8e4f84c858c68684b25a70"}, - {file = "coverage-7.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:e995efb191f04b01ced307dbd7407ebf6e6dc209b528d75583277b10fd1800ee"}, - {file = "coverage-7.3.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fbd8a5fe6c893de21a3c6835071ec116d79334fbdf641743332e442a3466f7ea"}, - {file = "coverage-7.3.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:50c472c1916540f8b2deef10cdc736cd2b3d1464d3945e4da0333862270dcb15"}, - {file = "coverage-7.3.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e9223a18f51d00d3ce239c39fc41410489ec7a248a84fab443fbb39c943616c"}, - {file = "coverage-7.3.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f501e36ac428c1b334c41e196ff6bd550c0353c7314716e80055b1f0a32ba394"}, - {file = "coverage-7.3.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:475de8213ed95a6b6283056d180b2442eee38d5948d735cd3d3b52b86dd65b92"}, - {file = "coverage-7.3.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:afdcc10c01d0db217fc0a64f58c7edd635b8f27787fea0a3054b856a6dff8717"}, - {file = "coverage-7.3.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:fff0b2f249ac642fd735f009b8363c2b46cf406d3caec00e4deeb79b5ff39b40"}, - {file = "coverage-7.3.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a1f76cfc122c9e0f62dbe0460ec9cc7696fc9a0293931a33b8870f78cf83a327"}, - {file = "coverage-7.3.3-cp38-cp38-win32.whl", hash = "sha256:757453848c18d7ab5d5b5f1827293d580f156f1c2c8cef45bfc21f37d8681069"}, - {file = "coverage-7.3.3-cp38-cp38-win_amd64.whl", hash = "sha256:ad2453b852a1316c8a103c9c970db8fbc262f4f6b930aa6c606df9b2766eee06"}, - {file = "coverage-7.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b15e03b8ee6a908db48eccf4e4e42397f146ab1e91c6324da44197a45cb9132"}, - {file = "coverage-7.3.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:89400aa1752e09f666cc48708eaa171eef0ebe3d5f74044b614729231763ae69"}, - {file = "coverage-7.3.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c59a3e59fb95e6d72e71dc915e6d7fa568863fad0a80b33bc7b82d6e9f844973"}, - {file = "coverage-7.3.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9ede881c7618f9cf93e2df0421ee127afdfd267d1b5d0c59bcea771cf160ea4a"}, - {file = "coverage-7.3.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3bfd2c2f0e5384276e12b14882bf2c7621f97c35320c3e7132c156ce18436a1"}, - {file = "coverage-7.3.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7f3bad1a9313401ff2964e411ab7d57fb700a2d5478b727e13f156c8f89774a0"}, - {file = "coverage-7.3.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:65d716b736f16e250435473c5ca01285d73c29f20097decdbb12571d5dfb2c94"}, - {file = "coverage-7.3.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a702e66483b1fe602717020a0e90506e759c84a71dbc1616dd55d29d86a9b91f"}, - {file = "coverage-7.3.3-cp39-cp39-win32.whl", hash = "sha256:7fbf3f5756e7955174a31fb579307d69ffca91ad163467ed123858ce0f3fd4aa"}, - {file = "coverage-7.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:cad9afc1644b979211989ec3ff7d82110b2ed52995c2f7263e7841c846a75348"}, - {file = "coverage-7.3.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:d299d379b676812e142fb57662a8d0d810b859421412b4d7af996154c00c31bb"}, - {file = "coverage-7.3.3.tar.gz", hash = "sha256:df04c64e58df96b4427db8d0559e95e2df3138c9916c96f9f6a4dd220db2fdb7"}, + {file = "coverage-7.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36b0ea8ab20d6a7564e89cb6135920bc9188fb5f1f7152e94e8300b7b189441a"}, + {file = "coverage-7.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0676cd0ba581e514b7f726495ea75aba3eb20899d824636c6f59b0ed2f88c471"}, + {file = "coverage-7.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0ca5c71a5a1765a0f8f88022c52b6b8be740e512980362f7fdbb03725a0d6b9"}, + {file = "coverage-7.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7c97726520f784239f6c62506bc70e48d01ae71e9da128259d61ca5e9788516"}, + {file = "coverage-7.4.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:815ac2d0f3398a14286dc2cea223a6f338109f9ecf39a71160cd1628786bc6f5"}, + {file = "coverage-7.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:80b5ee39b7f0131ebec7968baa9b2309eddb35b8403d1869e08f024efd883566"}, + {file = "coverage-7.4.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5b2ccb7548a0b65974860a78c9ffe1173cfb5877460e5a229238d985565574ae"}, + {file = "coverage-7.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:995ea5c48c4ebfd898eacb098164b3cc826ba273b3049e4a889658548e321b43"}, + {file = "coverage-7.4.0-cp310-cp310-win32.whl", hash = "sha256:79287fd95585ed36e83182794a57a46aeae0b64ca53929d1176db56aacc83451"}, + {file = "coverage-7.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:5b14b4f8760006bfdb6e08667af7bc2d8d9bfdb648351915315ea17645347137"}, + {file = "coverage-7.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:04387a4a6ecb330c1878907ce0dc04078ea72a869263e53c72a1ba5bbdf380ca"}, + {file = "coverage-7.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ea81d8f9691bb53f4fb4db603203029643caffc82bf998ab5b59ca05560f4c06"}, + {file = "coverage-7.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74775198b702868ec2d058cb92720a3c5a9177296f75bd97317c787daf711505"}, + {file = "coverage-7.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:76f03940f9973bfaee8cfba70ac991825611b9aac047e5c80d499a44079ec0bc"}, + {file = "coverage-7.4.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:485e9f897cf4856a65a57c7f6ea3dc0d4e6c076c87311d4bc003f82cfe199d25"}, + {file = "coverage-7.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6ae8c9d301207e6856865867d762a4b6fd379c714fcc0607a84b92ee63feff70"}, + {file = "coverage-7.4.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bf477c355274a72435ceb140dc42de0dc1e1e0bf6e97195be30487d8eaaf1a09"}, + {file = "coverage-7.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:83c2dda2666fe32332f8e87481eed056c8b4d163fe18ecc690b02802d36a4d26"}, + {file = "coverage-7.4.0-cp311-cp311-win32.whl", hash = "sha256:697d1317e5290a313ef0d369650cfee1a114abb6021fa239ca12b4849ebbd614"}, + {file = "coverage-7.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:26776ff6c711d9d835557ee453082025d871e30b3fd6c27fcef14733f67f0590"}, + {file = "coverage-7.4.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:13eaf476ec3e883fe3e5fe3707caeb88268a06284484a3daf8250259ef1ba143"}, + {file = "coverage-7.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846f52f46e212affb5bcf131c952fb4075b55aae6b61adc9856222df89cbe3e2"}, + {file = "coverage-7.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26f66da8695719ccf90e794ed567a1549bb2644a706b41e9f6eae6816b398c4a"}, + {file = "coverage-7.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:164fdcc3246c69a6526a59b744b62e303039a81e42cfbbdc171c91a8cc2f9446"}, + {file = "coverage-7.4.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:316543f71025a6565677d84bc4df2114e9b6a615aa39fb165d697dba06a54af9"}, + {file = "coverage-7.4.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bb1de682da0b824411e00a0d4da5a784ec6496b6850fdf8c865c1d68c0e318dd"}, + {file = "coverage-7.4.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:0e8d06778e8fbffccfe96331a3946237f87b1e1d359d7fbe8b06b96c95a5407a"}, + {file = "coverage-7.4.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a56de34db7b7ff77056a37aedded01b2b98b508227d2d0979d373a9b5d353daa"}, + {file = "coverage-7.4.0-cp312-cp312-win32.whl", hash = "sha256:51456e6fa099a8d9d91497202d9563a320513fcf59f33991b0661a4a6f2ad450"}, + {file = "coverage-7.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:cd3c1e4cb2ff0083758f09be0f77402e1bdf704adb7f89108007300a6da587d0"}, + {file = "coverage-7.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e9d1bf53c4c8de58d22e0e956a79a5b37f754ed1ffdbf1a260d9dcfa2d8a325e"}, + {file = "coverage-7.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:109f5985182b6b81fe33323ab4707011875198c41964f014579cf82cebf2bb85"}, + {file = "coverage-7.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cc9d4bc55de8003663ec94c2f215d12d42ceea128da8f0f4036235a119c88ac"}, + {file = "coverage-7.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc6d65b21c219ec2072c1293c505cf36e4e913a3f936d80028993dd73c7906b1"}, + {file = "coverage-7.4.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a10a4920def78bbfff4eff8a05c51be03e42f1c3735be42d851f199144897ba"}, + {file = "coverage-7.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b8e99f06160602bc64da35158bb76c73522a4010f0649be44a4e167ff8555952"}, + {file = "coverage-7.4.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7d360587e64d006402b7116623cebf9d48893329ef035278969fa3bbf75b697e"}, + {file = "coverage-7.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:29f3abe810930311c0b5d1a7140f6395369c3db1be68345638c33eec07535105"}, + {file = "coverage-7.4.0-cp38-cp38-win32.whl", hash = "sha256:5040148f4ec43644702e7b16ca864c5314ccb8ee0751ef617d49aa0e2d6bf4f2"}, + {file = "coverage-7.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:9864463c1c2f9cb3b5db2cf1ff475eed2f0b4285c2aaf4d357b69959941aa555"}, + {file = "coverage-7.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:936d38794044b26c99d3dd004d8af0035ac535b92090f7f2bb5aa9c8e2f5cd42"}, + {file = "coverage-7.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:799c8f873794a08cdf216aa5d0531c6a3747793b70c53f70e98259720a6fe2d7"}, + {file = "coverage-7.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e7defbb9737274023e2d7af02cac77043c86ce88a907c58f42b580a97d5bcca9"}, + {file = "coverage-7.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a1526d265743fb49363974b7aa8d5899ff64ee07df47dd8d3e37dcc0818f09ed"}, + {file = "coverage-7.4.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf635a52fc1ea401baf88843ae8708591aa4adff875e5c23220de43b1ccf575c"}, + {file = "coverage-7.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:756ded44f47f330666843b5781be126ab57bb57c22adbb07d83f6b519783b870"}, + {file = "coverage-7.4.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0eb3c2f32dabe3a4aaf6441dde94f35687224dfd7eb2a7f47f3fd9428e421058"}, + {file = "coverage-7.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bfd5db349d15c08311702611f3dccbef4b4e2ec148fcc636cf8739519b4a5c0f"}, + {file = "coverage-7.4.0-cp39-cp39-win32.whl", hash = "sha256:53d7d9158ee03956e0eadac38dfa1ec8068431ef8058fe6447043db1fb40d932"}, + {file = "coverage-7.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:cfd2a8b6b0d8e66e944d47cdec2f47c48fef2ba2f2dff5a9a75757f64172857e"}, + {file = "coverage-7.4.0-pp38.pp39.pp310-none-any.whl", hash = "sha256:c530833afc4707fe48524a44844493f36d8727f04dcce91fb978c414a8556cc6"}, + {file = "coverage-7.4.0.tar.gz", hash = "sha256:707c0f58cb1712b8809ece32b68996ee1e609f71bd14615bd8f87a1293cb610e"}, ] [package.extras] @@ -1072,13 +1073,13 @@ files = [ [[package]] name = "deepmerge" -version = "1.1.0" +version = "1.1.1" description = "a toolset to deeply merge python dictionaries." optional = false python-versions = "*" files = [ - {file = "deepmerge-1.1.0-py3-none-any.whl", hash = "sha256:59e6ef80b77dc52af3882a1ea78da22bcfc91ae9cdabc0c80729049fe295ff8b"}, - {file = "deepmerge-1.1.0.tar.gz", hash = "sha256:4c27a0db5de285e1a7ceac7dbc1531deaa556b627dea4900c8244581ecdfea2d"}, + {file = "deepmerge-1.1.1-py3-none-any.whl", hash = "sha256:7219dad9763f15be9dcd4bcb53e00f48e4eed6f5ed8f15824223eb934bb35977"}, + {file = "deepmerge-1.1.1.tar.gz", hash = "sha256:53a489dc9449636e480a784359ae2aab3191748c920649551c8e378622f0eca4"}, ] [[package]] @@ -1412,13 +1413,13 @@ tornado = ">=5.0.0,<7.0.0" [[package]] name = "freezegun" -version = "1.3.1" +version = "1.4.0" description = "Let your Python tests travel through time" optional = false python-versions = ">=3.7" files = [ - {file = "freezegun-1.3.1-py3-none-any.whl", hash = "sha256:065e77a12624d05531afa87ade12a0b9bdb53495c4573893252a055b545ce3ea"}, - {file = "freezegun-1.3.1.tar.gz", hash = "sha256:48984397b3b58ef5dfc645d6a304b0060f612bcecfdaaf45ce8aff0077a6cb6a"}, + {file = "freezegun-1.4.0-py3-none-any.whl", hash = "sha256:55e0fc3c84ebf0a96a5aa23ff8b53d70246479e9a68863f1fcac5a3e52f19dd6"}, + {file = "freezegun-1.4.0.tar.gz", hash = "sha256:10939b0ba0ff5adaecf3b06a5c2f73071d9678e507c5eaedb23c761d56ac774b"}, ] [package.dependencies] @@ -1715,13 +1716,13 @@ files = [ [[package]] name = "importlib-metadata" -version = "7.0.0" +version = "7.0.1" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-7.0.0-py3-none-any.whl", hash = "sha256:d97503976bb81f40a193d41ee6570868479c69d5068651eb039c40d850c59d67"}, - {file = "importlib_metadata-7.0.0.tar.gz", hash = "sha256:7fc841f8b8332803464e5dc1c63a2e59121f46ca186c0e2e182e80bf8c1319f7"}, + {file = "importlib_metadata-7.0.1-py3-none-any.whl", hash = "sha256:4805911c3a4ec7c3966410053e9ec6a1fecd629117df5adee56dfc9432a1081e"}, + {file = "importlib_metadata-7.0.1.tar.gz", hash = "sha256:f238736bb06590ae52ac1fab06a3a9ef1d8dce2b7a35b5ab329371d6c8f5d2cc"}, ] [package.dependencies] @@ -1848,13 +1849,13 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339- [[package]] name = "jsonschema-specifications" -version = "2023.11.2" +version = "2023.12.1" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" optional = false python-versions = ">=3.8" files = [ - {file = "jsonschema_specifications-2023.11.2-py3-none-any.whl", hash = "sha256:e74ba7c0a65e8cb49dc26837d6cfe576557084a8b423ed16a420984228104f93"}, - {file = "jsonschema_specifications-2023.11.2.tar.gz", hash = "sha256:9472fc4fea474cd74bea4a2b190daeccb5a9e4db2ea80efcf7a1b582fc9a81b8"}, + {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"}, + {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"}, ] [package.dependencies] @@ -1934,110 +1935,214 @@ pyasn1 = ">=0.4.6" [[package]] name = "lxml" -version = "4.9.3" +version = "4.9.4" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" files = [ - {file = "lxml-4.9.3-cp27-cp27m-macosx_11_0_x86_64.whl", hash = "sha256:b0a545b46b526d418eb91754565ba5b63b1c0b12f9bd2f808c852d9b4b2f9b5c"}, - {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:075b731ddd9e7f68ad24c635374211376aa05a281673ede86cbe1d1b3455279d"}, - {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1e224d5755dba2f4a9498e150c43792392ac9b5380aa1b845f98a1618c94eeef"}, - {file = "lxml-4.9.3-cp27-cp27m-win32.whl", hash = "sha256:2c74524e179f2ad6d2a4f7caf70e2d96639c0954c943ad601a9e146c76408ed7"}, - {file = "lxml-4.9.3-cp27-cp27m-win_amd64.whl", hash = "sha256:4f1026bc732b6a7f96369f7bfe1a4f2290fb34dce00d8644bc3036fb351a4ca1"}, - {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c0781a98ff5e6586926293e59480b64ddd46282953203c76ae15dbbbf302e8bb"}, - {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cef2502e7e8a96fe5ad686d60b49e1ab03e438bd9123987994528febd569868e"}, - {file = "lxml-4.9.3-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:b86164d2cff4d3aaa1f04a14685cbc072efd0b4f99ca5708b2ad1b9b5988a991"}, - {file = "lxml-4.9.3-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:42871176e7896d5d45138f6d28751053c711ed4d48d8e30b498da155af39aebd"}, - {file = "lxml-4.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ae8b9c6deb1e634ba4f1930eb67ef6e6bf6a44b6eb5ad605642b2d6d5ed9ce3c"}, - {file = "lxml-4.9.3-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:411007c0d88188d9f621b11d252cce90c4a2d1a49db6c068e3c16422f306eab8"}, - {file = "lxml-4.9.3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:cd47b4a0d41d2afa3e58e5bf1f62069255aa2fd6ff5ee41604418ca925911d76"}, - {file = "lxml-4.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0e2cb47860da1f7e9a5256254b74ae331687b9672dfa780eed355c4c9c3dbd23"}, - {file = "lxml-4.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1247694b26342a7bf47c02e513d32225ededd18045264d40758abeb3c838a51f"}, - {file = "lxml-4.9.3-cp310-cp310-win32.whl", hash = "sha256:cdb650fc86227eba20de1a29d4b2c1bfe139dc75a0669270033cb2ea3d391b85"}, - {file = "lxml-4.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:97047f0d25cd4bcae81f9ec9dc290ca3e15927c192df17331b53bebe0e3ff96d"}, - {file = "lxml-4.9.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:1f447ea5429b54f9582d4b955f5f1985f278ce5cf169f72eea8afd9502973dd5"}, - {file = "lxml-4.9.3-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:57d6ba0ca2b0c462f339640d22882acc711de224d769edf29962b09f77129cbf"}, - {file = "lxml-4.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:9767e79108424fb6c3edf8f81e6730666a50feb01a328f4a016464a5893f835a"}, - {file = "lxml-4.9.3-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:71c52db65e4b56b8ddc5bb89fb2e66c558ed9d1a74a45ceb7dcb20c191c3df2f"}, - {file = "lxml-4.9.3-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d73d8ecf8ecf10a3bd007f2192725a34bd62898e8da27eb9d32a58084f93962b"}, - {file = "lxml-4.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0a3d3487f07c1d7f150894c238299934a2a074ef590b583103a45002035be120"}, - {file = "lxml-4.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e28c51fa0ce5674be9f560c6761c1b441631901993f76700b1b30ca6c8378d6"}, - {file = "lxml-4.9.3-cp311-cp311-win32.whl", hash = "sha256:0bfd0767c5c1de2551a120673b72e5d4b628737cb05414f03c3277bf9bed3305"}, - {file = "lxml-4.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:25f32acefac14ef7bd53e4218fe93b804ef6f6b92ffdb4322bb6d49d94cad2bc"}, - {file = "lxml-4.9.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:d3ff32724f98fbbbfa9f49d82852b159e9784d6094983d9a8b7f2ddaebb063d4"}, - {file = "lxml-4.9.3-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:48d6ed886b343d11493129e019da91d4039826794a3e3027321c56d9e71505be"}, - {file = "lxml-4.9.3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9a92d3faef50658dd2c5470af249985782bf754c4e18e15afb67d3ab06233f13"}, - {file = "lxml-4.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b4e4bc18382088514ebde9328da057775055940a1f2e18f6ad2d78aa0f3ec5b9"}, - {file = "lxml-4.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fc9b106a1bf918db68619fdcd6d5ad4f972fdd19c01d19bdb6bf63f3589a9ec5"}, - {file = "lxml-4.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:d37017287a7adb6ab77e1c5bee9bcf9660f90ff445042b790402a654d2ad81d8"}, - {file = "lxml-4.9.3-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:56dc1f1ebccc656d1b3ed288f11e27172a01503fc016bcabdcbc0978b19352b7"}, - {file = "lxml-4.9.3-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:578695735c5a3f51569810dfebd05dd6f888147a34f0f98d4bb27e92b76e05c2"}, - {file = "lxml-4.9.3-cp35-cp35m-win32.whl", hash = "sha256:704f61ba8c1283c71b16135caf697557f5ecf3e74d9e453233e4771d68a1f42d"}, - {file = "lxml-4.9.3-cp35-cp35m-win_amd64.whl", hash = "sha256:c41bfca0bd3532d53d16fd34d20806d5c2b1ace22a2f2e4c0008570bf2c58833"}, - {file = "lxml-4.9.3-cp36-cp36m-macosx_11_0_x86_64.whl", hash = "sha256:64f479d719dc9f4c813ad9bb6b28f8390360660b73b2e4beb4cb0ae7104f1c12"}, - {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:dd708cf4ee4408cf46a48b108fb9427bfa00b9b85812a9262b5c668af2533ea5"}, - {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c31c7462abdf8f2ac0577d9f05279727e698f97ecbb02f17939ea99ae8daa98"}, - {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e3cd95e10c2610c360154afdc2f1480aea394f4a4f1ea0a5eacce49640c9b190"}, - {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:4930be26af26ac545c3dffb662521d4e6268352866956672231887d18f0eaab2"}, - {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4aec80cde9197340bc353d2768e2a75f5f60bacda2bab72ab1dc499589b3878c"}, - {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:14e019fd83b831b2e61baed40cab76222139926b1fb5ed0e79225bc0cae14584"}, - {file = "lxml-4.9.3-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0c0850c8b02c298d3c7006b23e98249515ac57430e16a166873fc47a5d549287"}, - {file = "lxml-4.9.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:aca086dc5f9ef98c512bac8efea4483eb84abbf926eaeedf7b91479feb092458"}, - {file = "lxml-4.9.3-cp36-cp36m-win32.whl", hash = "sha256:50baa9c1c47efcaef189f31e3d00d697c6d4afda5c3cde0302d063492ff9b477"}, - {file = "lxml-4.9.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bef4e656f7d98aaa3486d2627e7d2df1157d7e88e7efd43a65aa5dd4714916cf"}, - {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:46f409a2d60f634fe550f7133ed30ad5321ae2e6630f13657fb9479506b00601"}, - {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:4c28a9144688aef80d6ea666c809b4b0e50010a2aca784c97f5e6bf143d9f129"}, - {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:141f1d1a9b663c679dc524af3ea1773e618907e96075262726c7612c02b149a4"}, - {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:53ace1c1fd5a74ef662f844a0413446c0629d151055340e9893da958a374f70d"}, - {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:17a753023436a18e27dd7769e798ce302963c236bc4114ceee5b25c18c52c693"}, - {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7d298a1bd60c067ea75d9f684f5f3992c9d6766fadbc0bcedd39750bf344c2f4"}, - {file = "lxml-4.9.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:081d32421db5df44c41b7f08a334a090a545c54ba977e47fd7cc2deece78809a"}, - {file = "lxml-4.9.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:23eed6d7b1a3336ad92d8e39d4bfe09073c31bfe502f20ca5116b2a334f8ec02"}, - {file = "lxml-4.9.3-cp37-cp37m-win32.whl", hash = "sha256:1509dd12b773c02acd154582088820893109f6ca27ef7291b003d0e81666109f"}, - {file = "lxml-4.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:120fa9349a24c7043854c53cae8cec227e1f79195a7493e09e0c12e29f918e52"}, - {file = "lxml-4.9.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:4d2d1edbca80b510443f51afd8496be95529db04a509bc8faee49c7b0fb6d2cc"}, - {file = "lxml-4.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8d7e43bd40f65f7d97ad8ef5c9b1778943d02f04febef12def25f7583d19baac"}, - {file = "lxml-4.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:71d66ee82e7417828af6ecd7db817913cb0cf9d4e61aa0ac1fde0583d84358db"}, - {file = "lxml-4.9.3-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:6fc3c450eaa0b56f815c7b62f2b7fba7266c4779adcf1cece9e6deb1de7305ce"}, - {file = "lxml-4.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:65299ea57d82fb91c7f019300d24050c4ddeb7c5a190e076b5f48a2b43d19c42"}, - {file = "lxml-4.9.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:eadfbbbfb41b44034a4c757fd5d70baccd43296fb894dba0295606a7cf3124aa"}, - {file = "lxml-4.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3e9bdd30efde2b9ccfa9cb5768ba04fe71b018a25ea093379c857c9dad262c40"}, - {file = "lxml-4.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fcdd00edfd0a3001e0181eab3e63bd5c74ad3e67152c84f93f13769a40e073a7"}, - {file = "lxml-4.9.3-cp38-cp38-win32.whl", hash = "sha256:57aba1bbdf450b726d58b2aea5fe47c7875f5afb2c4a23784ed78f19a0462574"}, - {file = "lxml-4.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:92af161ecbdb2883c4593d5ed4815ea71b31fafd7fd05789b23100d081ecac96"}, - {file = "lxml-4.9.3-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:9bb6ad405121241e99a86efff22d3ef469024ce22875a7ae045896ad23ba2340"}, - {file = "lxml-4.9.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8ed74706b26ad100433da4b9d807eae371efaa266ffc3e9191ea436087a9d6a7"}, - {file = "lxml-4.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fbf521479bcac1e25a663df882c46a641a9bff6b56dc8b0fafaebd2f66fb231b"}, - {file = "lxml-4.9.3-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:303bf1edce6ced16bf67a18a1cf8339d0db79577eec5d9a6d4a80f0fb10aa2da"}, - {file = "lxml-4.9.3-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:5515edd2a6d1a5a70bfcdee23b42ec33425e405c5b351478ab7dc9347228f96e"}, - {file = "lxml-4.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:690dafd0b187ed38583a648076865d8c229661ed20e48f2335d68e2cf7dc829d"}, - {file = "lxml-4.9.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b6420a005548ad52154c8ceab4a1290ff78d757f9e5cbc68f8c77089acd3c432"}, - {file = "lxml-4.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bb3bb49c7a6ad9d981d734ef7c7193bc349ac338776a0360cc671eaee89bcf69"}, - {file = "lxml-4.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d27be7405547d1f958b60837dc4c1007da90b8b23f54ba1f8b728c78fdb19d50"}, - {file = "lxml-4.9.3-cp39-cp39-win32.whl", hash = "sha256:8df133a2ea5e74eef5e8fc6f19b9e085f758768a16e9877a60aec455ed2609b2"}, - {file = "lxml-4.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:4dd9a263e845a72eacb60d12401e37c616438ea2e5442885f65082c276dfb2b2"}, - {file = "lxml-4.9.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6689a3d7fd13dc687e9102a27e98ef33730ac4fe37795d5036d18b4d527abd35"}, - {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f6bdac493b949141b733c5345b6ba8f87a226029cbabc7e9e121a413e49441e0"}, - {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:05186a0f1346ae12553d66df1cfce6f251589fea3ad3da4f3ef4e34b2d58c6a3"}, - {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c2006f5c8d28dee289f7020f721354362fa304acbaaf9745751ac4006650254b"}, - {file = "lxml-4.9.3-pp38-pypy38_pp73-macosx_11_0_x86_64.whl", hash = "sha256:5c245b783db29c4e4fbbbfc9c5a78be496c9fea25517f90606aa1f6b2b3d5f7b"}, - {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:4fb960a632a49f2f089d522f70496640fdf1218f1243889da3822e0a9f5f3ba7"}, - {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:50670615eaf97227d5dc60de2dc99fb134a7130d310d783314e7724bf163f75d"}, - {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9719fe17307a9e814580af1f5c6e05ca593b12fb7e44fe62450a5384dbf61b4b"}, - {file = "lxml-4.9.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:3331bece23c9ee066e0fb3f96c61322b9e0f54d775fccefff4c38ca488de283a"}, - {file = "lxml-4.9.3-pp39-pypy39_pp73-macosx_11_0_x86_64.whl", hash = "sha256:ed667f49b11360951e201453fc3967344d0d0263aa415e1619e85ae7fd17b4e0"}, - {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8b77946fd508cbf0fccd8e400a7f71d4ac0e1595812e66025bac475a8e811694"}, - {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e4da8ca0c0c0aea88fd46be8e44bd49716772358d648cce45fe387f7b92374a7"}, - {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fe4bda6bd4340caa6e5cf95e73f8fea5c4bfc55763dd42f1b50a94c1b4a2fbd4"}, - {file = "lxml-4.9.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f3df3db1d336b9356dd3112eae5f5c2b8b377f3bc826848567f10bfddfee77e9"}, - {file = "lxml-4.9.3.tar.gz", hash = "sha256:48628bd53a426c9eb9bc066a923acaa0878d1e86129fd5359aee99285f4eed9c"}, + {file = "lxml-4.9.4-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e214025e23db238805a600f1f37bf9f9a15413c7bf5f9d6ae194f84980c78722"}, + {file = "lxml-4.9.4-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ec53a09aee61d45e7dbe7e91252ff0491b6b5fee3d85b2d45b173d8ab453efc1"}, + {file = "lxml-4.9.4-cp27-cp27m-win32.whl", hash = "sha256:7d1d6c9e74c70ddf524e3c09d9dc0522aba9370708c2cb58680ea40174800013"}, + {file = "lxml-4.9.4-cp27-cp27m-win_amd64.whl", hash = "sha256:cb53669442895763e61df5c995f0e8361b61662f26c1b04ee82899c2789c8f69"}, + {file = "lxml-4.9.4-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:647bfe88b1997d7ae8d45dabc7c868d8cb0c8412a6e730a7651050b8c7289cf2"}, + {file = "lxml-4.9.4-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:4d973729ce04784906a19108054e1fd476bc85279a403ea1a72fdb051c76fa48"}, + {file = "lxml-4.9.4-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:056a17eaaf3da87a05523472ae84246f87ac2f29a53306466c22e60282e54ff8"}, + {file = "lxml-4.9.4-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:aaa5c173a26960fe67daa69aa93d6d6a1cd714a6eb13802d4e4bd1d24a530644"}, + {file = "lxml-4.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:647459b23594f370c1c01768edaa0ba0959afc39caeeb793b43158bb9bb6a663"}, + {file = "lxml-4.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:bdd9abccd0927673cffe601d2c6cdad1c9321bf3437a2f507d6b037ef91ea307"}, + {file = "lxml-4.9.4-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:00e91573183ad273e242db5585b52670eddf92bacad095ce25c1e682da14ed91"}, + {file = "lxml-4.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a602ed9bd2c7d85bd58592c28e101bd9ff9c718fbde06545a70945ffd5d11868"}, + {file = "lxml-4.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:de362ac8bc962408ad8fae28f3967ce1a262b5d63ab8cefb42662566737f1dc7"}, + {file = "lxml-4.9.4-cp310-cp310-win32.whl", hash = "sha256:33714fcf5af4ff7e70a49731a7cc8fd9ce910b9ac194f66eaa18c3cc0a4c02be"}, + {file = "lxml-4.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:d3caa09e613ece43ac292fbed513a4bce170681a447d25ffcbc1b647d45a39c5"}, + {file = "lxml-4.9.4-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:359a8b09d712df27849e0bcb62c6a3404e780b274b0b7e4c39a88826d1926c28"}, + {file = "lxml-4.9.4-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:43498ea734ccdfb92e1886dfedaebeb81178a241d39a79d5351ba2b671bff2b2"}, + {file = "lxml-4.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:4855161013dfb2b762e02b3f4d4a21cc7c6aec13c69e3bffbf5022b3e708dd97"}, + {file = "lxml-4.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c71b5b860c5215fdbaa56f715bc218e45a98477f816b46cfde4a84d25b13274e"}, + {file = "lxml-4.9.4-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:9a2b5915c333e4364367140443b59f09feae42184459b913f0f41b9fed55794a"}, + {file = "lxml-4.9.4-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d82411dbf4d3127b6cde7da0f9373e37ad3a43e89ef374965465928f01c2b979"}, + {file = "lxml-4.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:273473d34462ae6e97c0f4e517bd1bf9588aa67a1d47d93f760a1282640e24ac"}, + {file = "lxml-4.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:389d2b2e543b27962990ab529ac6720c3dded588cc6d0f6557eec153305a3622"}, + {file = "lxml-4.9.4-cp311-cp311-win32.whl", hash = "sha256:8aecb5a7f6f7f8fe9cac0bcadd39efaca8bbf8d1bf242e9f175cbe4c925116c3"}, + {file = "lxml-4.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:c7721a3ef41591341388bb2265395ce522aba52f969d33dacd822da8f018aff8"}, + {file = "lxml-4.9.4-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:dbcb2dc07308453db428a95a4d03259bd8caea97d7f0776842299f2d00c72fc8"}, + {file = "lxml-4.9.4-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:01bf1df1db327e748dcb152d17389cf6d0a8c5d533ef9bab781e9d5037619229"}, + {file = "lxml-4.9.4-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:e8f9f93a23634cfafbad6e46ad7d09e0f4a25a2400e4a64b1b7b7c0fbaa06d9d"}, + {file = "lxml-4.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3f3f00a9061605725df1816f5713d10cd94636347ed651abdbc75828df302b20"}, + {file = "lxml-4.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:953dd5481bd6252bd480d6ec431f61d7d87fdcbbb71b0d2bdcfc6ae00bb6fb10"}, + {file = "lxml-4.9.4-cp312-cp312-win32.whl", hash = "sha256:266f655d1baff9c47b52f529b5f6bec33f66042f65f7c56adde3fcf2ed62ae8b"}, + {file = "lxml-4.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:f1faee2a831fe249e1bae9cbc68d3cd8a30f7e37851deee4d7962b17c410dd56"}, + {file = "lxml-4.9.4-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:23d891e5bdc12e2e506e7d225d6aa929e0a0368c9916c1fddefab88166e98b20"}, + {file = "lxml-4.9.4-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e96a1788f24d03e8d61679f9881a883ecdf9c445a38f9ae3f3f193ab6c591c66"}, + {file = "lxml-4.9.4-cp36-cp36m-macosx_11_0_x86_64.whl", hash = "sha256:5557461f83bb7cc718bc9ee1f7156d50e31747e5b38d79cf40f79ab1447afd2d"}, + {file = "lxml-4.9.4-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:fdb325b7fba1e2c40b9b1db407f85642e32404131c08480dd652110fc908561b"}, + {file = "lxml-4.9.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d74d4a3c4b8f7a1f676cedf8e84bcc57705a6d7925e6daef7a1e54ae543a197"}, + {file = "lxml-4.9.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ac7674d1638df129d9cb4503d20ffc3922bd463c865ef3cb412f2c926108e9a4"}, + {file = "lxml-4.9.4-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:ddd92e18b783aeb86ad2132d84a4b795fc5ec612e3545c1b687e7747e66e2b53"}, + {file = "lxml-4.9.4-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2bd9ac6e44f2db368ef8986f3989a4cad3de4cd55dbdda536e253000c801bcc7"}, + {file = "lxml-4.9.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:bc354b1393dce46026ab13075f77b30e40b61b1a53e852e99d3cc5dd1af4bc85"}, + {file = "lxml-4.9.4-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:f836f39678cb47c9541f04d8ed4545719dc31ad850bf1832d6b4171e30d65d23"}, + {file = "lxml-4.9.4-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:9c131447768ed7bc05a02553d939e7f0e807e533441901dd504e217b76307745"}, + {file = "lxml-4.9.4-cp36-cp36m-win32.whl", hash = "sha256:bafa65e3acae612a7799ada439bd202403414ebe23f52e5b17f6ffc2eb98c2be"}, + {file = "lxml-4.9.4-cp36-cp36m-win_amd64.whl", hash = "sha256:6197c3f3c0b960ad033b9b7d611db11285bb461fc6b802c1dd50d04ad715c225"}, + {file = "lxml-4.9.4-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:7b378847a09d6bd46047f5f3599cdc64fcb4cc5a5a2dd0a2af610361fbe77b16"}, + {file = "lxml-4.9.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:1343df4e2e6e51182aad12162b23b0a4b3fd77f17527a78c53f0f23573663545"}, + {file = "lxml-4.9.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6dbdacf5752fbd78ccdb434698230c4f0f95df7dd956d5f205b5ed6911a1367c"}, + {file = "lxml-4.9.4-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:506becdf2ecaebaf7f7995f776394fcc8bd8a78022772de66677c84fb02dd33d"}, + {file = "lxml-4.9.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ca8e44b5ba3edb682ea4e6185b49661fc22b230cf811b9c13963c9f982d1d964"}, + {file = "lxml-4.9.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9d9d5726474cbbef279fd709008f91a49c4f758bec9c062dfbba88eab00e3ff9"}, + {file = "lxml-4.9.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:bbdd69e20fe2943b51e2841fc1e6a3c1de460d630f65bde12452d8c97209464d"}, + {file = "lxml-4.9.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8671622256a0859f5089cbe0ce4693c2af407bc053dcc99aadff7f5310b4aa02"}, + {file = "lxml-4.9.4-cp37-cp37m-win32.whl", hash = "sha256:dd4fda67f5faaef4f9ee5383435048ee3e11ad996901225ad7615bc92245bc8e"}, + {file = "lxml-4.9.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6bee9c2e501d835f91460b2c904bc359f8433e96799f5c2ff20feebd9bb1e590"}, + {file = "lxml-4.9.4-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:1f10f250430a4caf84115b1e0f23f3615566ca2369d1962f82bef40dd99cd81a"}, + {file = "lxml-4.9.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:3b505f2bbff50d261176e67be24e8909e54b5d9d08b12d4946344066d66b3e43"}, + {file = "lxml-4.9.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:1449f9451cd53e0fd0a7ec2ff5ede4686add13ac7a7bfa6988ff6d75cff3ebe2"}, + {file = "lxml-4.9.4-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:4ece9cca4cd1c8ba889bfa67eae7f21d0d1a2e715b4d5045395113361e8c533d"}, + {file = "lxml-4.9.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:59bb5979f9941c61e907ee571732219fa4774d5a18f3fa5ff2df963f5dfaa6bc"}, + {file = "lxml-4.9.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b1980dbcaad634fe78e710c8587383e6e3f61dbe146bcbfd13a9c8ab2d7b1192"}, + {file = "lxml-4.9.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9ae6c3363261021144121427b1552b29e7b59de9d6a75bf51e03bc072efb3c37"}, + {file = "lxml-4.9.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bcee502c649fa6351b44bb014b98c09cb00982a475a1912a9881ca28ab4f9cd9"}, + {file = "lxml-4.9.4-cp38-cp38-win32.whl", hash = "sha256:a8edae5253efa75c2fc79a90068fe540b197d1c7ab5803b800fccfe240eed33c"}, + {file = "lxml-4.9.4-cp38-cp38-win_amd64.whl", hash = "sha256:701847a7aaefef121c5c0d855b2affa5f9bd45196ef00266724a80e439220e46"}, + {file = "lxml-4.9.4-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:f610d980e3fccf4394ab3806de6065682982f3d27c12d4ce3ee46a8183d64a6a"}, + {file = "lxml-4.9.4-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:aa9b5abd07f71b081a33115d9758ef6077924082055005808f68feccb27616bd"}, + {file = "lxml-4.9.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:365005e8b0718ea6d64b374423e870648ab47c3a905356ab6e5a5ff03962b9a9"}, + {file = "lxml-4.9.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:16b9ec51cc2feab009e800f2c6327338d6ee4e752c76e95a35c4465e80390ccd"}, + {file = "lxml-4.9.4-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:a905affe76f1802edcac554e3ccf68188bea16546071d7583fb1b693f9cf756b"}, + {file = "lxml-4.9.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fd814847901df6e8de13ce69b84c31fc9b3fb591224d6762d0b256d510cbf382"}, + {file = "lxml-4.9.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:91bbf398ac8bb7d65a5a52127407c05f75a18d7015a270fdd94bbcb04e65d573"}, + {file = "lxml-4.9.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f99768232f036b4776ce419d3244a04fe83784bce871b16d2c2e984c7fcea847"}, + {file = "lxml-4.9.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bb5bd6212eb0edfd1e8f254585290ea1dadc3687dd8fd5e2fd9a87c31915cdab"}, + {file = "lxml-4.9.4-cp39-cp39-win32.whl", hash = "sha256:88f7c383071981c74ec1998ba9b437659e4fd02a3c4a4d3efc16774eb108d0ec"}, + {file = "lxml-4.9.4-cp39-cp39-win_amd64.whl", hash = "sha256:936e8880cc00f839aa4173f94466a8406a96ddce814651075f95837316369899"}, + {file = "lxml-4.9.4-pp310-pypy310_pp73-macosx_11_0_x86_64.whl", hash = "sha256:f6c35b2f87c004270fa2e703b872fcc984d714d430b305145c39d53074e1ffe0"}, + {file = "lxml-4.9.4-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:606d445feeb0856c2b424405236a01c71af7c97e5fe42fbc778634faef2b47e4"}, + {file = "lxml-4.9.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a1bdcbebd4e13446a14de4dd1825f1e778e099f17f79718b4aeaf2403624b0f7"}, + {file = "lxml-4.9.4-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:0a08c89b23117049ba171bf51d2f9c5f3abf507d65d016d6e0fa2f37e18c0fc5"}, + {file = "lxml-4.9.4-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:232fd30903d3123be4c435fb5159938c6225ee8607b635a4d3fca847003134ba"}, + {file = "lxml-4.9.4-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:231142459d32779b209aa4b4d460b175cadd604fed856f25c1571a9d78114771"}, + {file = "lxml-4.9.4-pp38-pypy38_pp73-macosx_11_0_x86_64.whl", hash = "sha256:520486f27f1d4ce9654154b4494cf9307b495527f3a2908ad4cb48e4f7ed7ef7"}, + {file = "lxml-4.9.4-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:562778586949be7e0d7435fcb24aca4810913771f845d99145a6cee64d5b67ca"}, + {file = "lxml-4.9.4-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a9e7c6d89c77bb2770c9491d988f26a4b161d05c8ca58f63fb1f1b6b9a74be45"}, + {file = "lxml-4.9.4-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:786d6b57026e7e04d184313c1359ac3d68002c33e4b1042ca58c362f1d09ff58"}, + {file = "lxml-4.9.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:95ae6c5a196e2f239150aa4a479967351df7f44800c93e5a975ec726fef005e2"}, + {file = "lxml-4.9.4-pp39-pypy39_pp73-macosx_11_0_x86_64.whl", hash = "sha256:9b556596c49fa1232b0fff4b0e69b9d4083a502e60e404b44341e2f8fb7187f5"}, + {file = "lxml-4.9.4-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:cc02c06e9e320869d7d1bd323df6dd4281e78ac2e7f8526835d3d48c69060683"}, + {file = "lxml-4.9.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:857d6565f9aa3464764c2cb6a2e3c2e75e1970e877c188f4aeae45954a314e0c"}, + {file = "lxml-4.9.4-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c42ae7e010d7d6bc51875d768110c10e8a59494855c3d4c348b068f5fb81fdcd"}, + {file = "lxml-4.9.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f10250bb190fb0742e3e1958dd5c100524c2cc5096c67c8da51233f7448dc137"}, + {file = "lxml-4.9.4.tar.gz", hash = "sha256:b1541e50b78e15fa06a2670157a1962ef06591d4c998b998047fff5e3236880e"}, ] [package.extras] cssselect = ["cssselect (>=0.7)"] html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] -source = ["Cython (>=0.29.35)"] +source = ["Cython (==0.29.37)"] + +[[package]] +name = "lxml" +version = "5.0.0" +description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" +files = [ + {file = "lxml-5.0.0-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:73bfab795d354aaf2f4eb7a5b0db513031734fd371047342d5803834ce19ec18"}, + {file = "lxml-5.0.0-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cb564bbe55ff0897d9cf1225041a44576d7ae87f06fd60163544c91de2623d3f"}, + {file = "lxml-5.0.0-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6a5501438dd521bb7e0dde5008c40c7bfcfaafaf86eccb3f9bd27509abb793da"}, + {file = "lxml-5.0.0-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7ba26a7dc929a1b3487d51bbcb0099afed2fc06e891b82845c8f37a2d7d7fbbd"}, + {file = "lxml-5.0.0-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:9b59c429e1a2246da86ae237ffc3565efcdc71c281cd38ca8b44d5fb6a3b993a"}, + {file = "lxml-5.0.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:3ffa066db40b0347e48334bd4465de768e295a3525b9a59831228b5f4f93162d"}, + {file = "lxml-5.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8ce8b468ab50f9e944719d1134709ec11fe0d2840891a6cae369e22141b1094c"}, + {file = "lxml-5.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:583c0e15ae06adc81035346ae2abb2e748f0b5197e7740d8af31222db41bbf7b"}, + {file = "lxml-5.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:904d36165848b59c4e04ae5b969072e602bd987485076fca8ec42c6cd7a7aedc"}, + {file = "lxml-5.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ac21aace6712472e77ea9dfc38329f53830c4259ece54c786107105ebb069053"}, + {file = "lxml-5.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f92d73faa0b1a76d1932429d684b7ce95829e93c3eef3715ec9b98ab192c9d31"}, + {file = "lxml-5.0.0-cp310-cp310-win32.whl", hash = "sha256:03290e2f714f2e7431c8430c08b48167f657da7bc689c6248e828ff3c66d5b1b"}, + {file = "lxml-5.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:3e6cbb68bf70081f036bfc018649cf4b46c4e7eaf7860a277cae92dee2a57f69"}, + {file = "lxml-5.0.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:5382612ba2424cea5d2c89e2c29077023d8de88f8d60d5ceff5f76334516df9e"}, + {file = "lxml-5.0.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:07a900735bad9af7be3085480bf384f68ed5580ba465b39a098e6a882c060d6b"}, + {file = "lxml-5.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:980ba47c8db4b9d870014c7040edb230825b79017a6a27aa54cdb6fcc02d8cc0"}, + {file = "lxml-5.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6507c58431dbd95b50654b3313c5ad54f90e54e5f2cdacf733de61eae478eec5"}, + {file = "lxml-5.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:4a45a278518e4308865c1e9dbb2c42ce84fb154efb03adeb16fdae3c1687c7c9"}, + {file = "lxml-5.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:59cea9ba1c675fbd6867ca1078fc717a113e7f5b7644943b74137b7cc55abebf"}, + {file = "lxml-5.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:dd39ef87fd1f7bb5c4aa53454936e6135cbfe03fe3744e8218be193f9e4fef16"}, + {file = "lxml-5.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e6bb39d91bf932e7520cb5718ae3c2f498052aca53294d5d59fdd9068fe1a7f2"}, + {file = "lxml-5.0.0-cp311-cp311-win32.whl", hash = "sha256:21af2c3862db6f4f486cddf73ec1157b40d5828876c47cd880edcbad8240ea1b"}, + {file = "lxml-5.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:c1249aa4eaced30b59ecf8b8cae0b1ccede04583c74ca7d10b6f8bbead908b2c"}, + {file = "lxml-5.0.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:f30e697b6215e759d0824768b2c5b0618d2dc19abe6c67eeed2b0460f52470d1"}, + {file = "lxml-5.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:d1bb64646480c36a4aa1b6a44a5b6e33d0fcbeab9f53f1b39072cd3bb2c6243a"}, + {file = "lxml-5.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:4e69c36c8618707a90ed3fb6f48a6cc9254ffcdbf7b259e439a5ae5fbf9c5206"}, + {file = "lxml-5.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9ca498f8554a09fbc3a2f8fc4b23261e07bc27bef99b3df98e2570688033f6fc"}, + {file = "lxml-5.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0326e9b8176ea77269fb39e7af4010906e73e9496a9f8eaf06d253b1b1231ceb"}, + {file = "lxml-5.0.0-cp312-cp312-win32.whl", hash = "sha256:5fb988e15378d6e905ca8f60813950a0c56da9469d0e8e5d8fe785b282684ec5"}, + {file = "lxml-5.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:bb58e8f4b2cfe012cd312239b8d5139995fe8f5945c7c26d5fbbbb1ddb9acd47"}, + {file = "lxml-5.0.0-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:81509dffd8aba3bdb43e90cbd218c9c068a1f4047d97bc9546b3ac9e3a4ae81d"}, + {file = "lxml-5.0.0-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e675a4b95208e74c34ac0751cc4bab9170e7728b61601fb0f4746892c2bb7e0b"}, + {file = "lxml-5.0.0-cp36-cp36m-macosx_11_0_x86_64.whl", hash = "sha256:405e3760f83a8ba3bdb6e622ec79595cdc20db916ce37377bbcb95b5711fa4ca"}, + {file = "lxml-5.0.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f15844a1b93dcaa09c2b22e22a73384f3ae4502347c3881cfdd674e14ac04e21"}, + {file = "lxml-5.0.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88f559f8beb6b90e41a7faae4aca4c8173a4819874a9bf8e74c8d7c1d51f3162"}, + {file = "lxml-5.0.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e8c63f5c7d87e7044880b01851ac4e863c3349e6f6b6ab456fe218d9346e816d"}, + {file = "lxml-5.0.0-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:0d277d4717756fe8816f0beeff229cb72f9dd02a43b70e1d3f07c8efadfb9fe1"}, + {file = "lxml-5.0.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c8954da15403db1acfc0544b3c3f963a6ef4e428283ab6555e3e298bbbff1cf6"}, + {file = "lxml-5.0.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:aebd8fd378e074b22e79cad329dcccd243c40ff1cafaa512d19276c5bb9554e1"}, + {file = "lxml-5.0.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:b6d4e148edee59c2ad38af15810dbcb8b5d7b13e5de3509d8cf3edfe74c0adca"}, + {file = "lxml-5.0.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:70ab4e02f7aa5fb4131c8b222a111ce7676f3767e36084fba3a4e7338dc82dcd"}, + {file = "lxml-5.0.0-cp36-cp36m-win32.whl", hash = "sha256:de1a8b54170024cf1c0c2718c82412bca42cd82e390556e3d8031af9541b416f"}, + {file = "lxml-5.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:5b39f63edbe7e018c2ac1cf0259ee0dd2355274e8a3003d404699b040782e55e"}, + {file = "lxml-5.0.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:77b73952534967a4497d9e4f26fbeebfba19950cbc66b7cc3a706214429d8106"}, + {file = "lxml-5.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8cc0a951e5616ac626f7036309c41fb9774adcd4aa7db0886463da1ce5b65edb"}, + {file = "lxml-5.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:4b9d5b01900a760eb3acf6cef50aead4ef2fa79e7ddb927084244e41dfe37b65"}, + {file = "lxml-5.0.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:173bcead3af5d87c7bca9a030675073ddaad8e0a9f0b04be07cd9390453e7226"}, + {file = "lxml-5.0.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:44fa9afd632210f1eeda51cf284ed8dbab0c7ec8b008dd39ba02818e0e114e69"}, + {file = "lxml-5.0.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:fef10f27d6318d2d7c88680e113511ddecf09ee4f9559b3623b73ee89fa8f6cc"}, + {file = "lxml-5.0.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3663542aee845129a981889c19b366beab0b1dadcf5ca164696aabfe1aa51667"}, + {file = "lxml-5.0.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7188495c1bf71bfda87d78ed50601e72d252119ce11710d6e71ff36e35fea5a0"}, + {file = "lxml-5.0.0-cp37-cp37m-win32.whl", hash = "sha256:6a2de85deabf939b0af89e2e1ea46bfb1239545e2da6f8ac96522755a388025f"}, + {file = "lxml-5.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ea56825c1e23c9c8ea385a191dac75f9160477057285b88c88736d9305e6118f"}, + {file = "lxml-5.0.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:3f908afd0477cace17f941d1b9cfa10b769fe1464770abe4cfb3d9f35378d0f8"}, + {file = "lxml-5.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:52a9ab31853d3808e7cf0183b3a5f7e8ffd622ea4aee1deb5252dbeaefd5b40d"}, + {file = "lxml-5.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c7fe19abb3d3c55a9e65d289b12ad73b3a31a3f0bda3c539a890329ae9973bd6"}, + {file = "lxml-5.0.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:1ef0793e1e2dd221fce7c142177008725680f7b9e4a184ab108d90d5d3ab69b7"}, + {file = "lxml-5.0.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:581a78f299a9f5448b2c3aea904bfcd17c59bf83016d221d7f93f83633bb2ab2"}, + {file = "lxml-5.0.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:affdd833f82334fdb10fc9a1c7b35cdb5a86d0b672b4e14dd542e1fe7bcea894"}, + {file = "lxml-5.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6bba06d8982be0f0f6432d289a8d104417a0ab9ed04114446c4ceb6d4a40c65d"}, + {file = "lxml-5.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:80209b31dd3908bc5b014f540fd192c97ea52ab179713a730456c5baf7ce80c1"}, + {file = "lxml-5.0.0-cp38-cp38-win32.whl", hash = "sha256:dac2733fe4e159b0aae0439db6813b7b1d23ff96d0b34c0107b87faf79208c4e"}, + {file = "lxml-5.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:ee60f33456ff34b2dd1d048a740a2572798356208e4c494301c931de3a0ab3a2"}, + {file = "lxml-5.0.0-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:5eff173f0ff408bfa578cbdafd35a7e0ca94d1a9ffe09a8a48e0572d0904d486"}, + {file = "lxml-5.0.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:78d6d8e5b54ed89dc0f0901eaaa579c384ad8d59fa43cc7fb06e9bb89115f8f4"}, + {file = "lxml-5.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:71a7cee869578bc17b18050532bb2f0bc682a7b97dda77041741a1bd2febe6c7"}, + {file = "lxml-5.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:7df433d08d4587dc3932f7fcfc3194519a6824824104854e76441fd3bc000d29"}, + {file = "lxml-5.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:793be9b4945c2dfd69828fb5948d7d9569b78e0599e4a2e88d92affeb0ff3aa3"}, + {file = "lxml-5.0.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c7cfb6af73602c8d288581df8a225989d7e9d5aab0a174be0e19fcfa800b6797"}, + {file = "lxml-5.0.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:bfdc4668ac56687a89ca3eca44231144a2e9d02ba3b877558db74ba20e2bd9fa"}, + {file = "lxml-5.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2992591e2294bb07faf7f5f6d5cb60710c046404f4bfce09fb488b85d2a8f58f"}, + {file = "lxml-5.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4786b0af7511ea614fd86407a52a7bc161aa5772d311d97df2591ed2351de768"}, + {file = "lxml-5.0.0-cp39-cp39-win32.whl", hash = "sha256:016de3b29a262655fc3d2075dc1b2611f84f4c3d97a71d579c883d45e201eee4"}, + {file = "lxml-5.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:52c0acc2f29b0a204efc11a5ed911a74f50a25eb7d7d5069c2b1fd3b3346ce11"}, + {file = "lxml-5.0.0-pp310-pypy310_pp73-macosx_11_0_x86_64.whl", hash = "sha256:96095bfc0c02072fc89afa67626013a253596ea5118b8a7f4daaae049dafa096"}, + {file = "lxml-5.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:992029258ed719f130d5a9c443d142c32843046f1263f2c492862b2a853be570"}, + {file = "lxml-5.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:db40e85cffd22f7d65dcce30e85af565a66401a6ed22fc0c56ed342cfa4ffc43"}, + {file = "lxml-5.0.0-pp38-pypy38_pp73-macosx_11_0_x86_64.whl", hash = "sha256:cfa8a4cdc3765574b7fd0c7cfa5fbd1e2108014c9dfd299c679e5152bea9a55e"}, + {file = "lxml-5.0.0-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:049fef98d02513c34f5babd07569fc1cf1ed14c0f2fbff18fe72597f977ef3c2"}, + {file = "lxml-5.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a85136d0ee18a41c91cc3e2844c683be0e72e6dda4cb58da9e15fcaef3726af7"}, + {file = "lxml-5.0.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:766868f729f3ab84125350f1a0ea2594d8b1628a608a574542a5aff7355b9941"}, + {file = "lxml-5.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:99cad5c912f359e59e921689c04e54662cdd80835d80eeaa931e22612f515df7"}, + {file = "lxml-5.0.0-pp39-pypy39_pp73-macosx_11_0_x86_64.whl", hash = "sha256:c90c593aa8dd57d5dab0ef6d7d64af894008971d98e6a41b320fdd75258fbc6e"}, + {file = "lxml-5.0.0-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8134d5441d1ed6a682e3de3d7a98717a328dce619ee9c4c8b3b91f0cb0eb3e28"}, + {file = "lxml-5.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f298ac9149037d6a3d5c74991bded39ac46292520b9c7c182cb102486cc87677"}, + {file = "lxml-5.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:894c5f71186b410679aaab5774543fcb9cbabe8893f0b31d11cf28a0740e80be"}, + {file = "lxml-5.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:9cd3d6c2c67d4fdcd795e4945e2ba5434909c96640b4cc09453bd0dc7e8e1bac"}, + {file = "lxml-5.0.0.zip", hash = "sha256:2219cbf790e701acf9a21a31ead75f983e73daf0eceb9da6990212e4d20ebefe"}, +] + +[package.extras] +cssselect = ["cssselect (>=0.7)"] +html5 = ["html5lib"] +htmlsoup = ["BeautifulSoup4"] +source = ["Cython (>=3.0.7)"] [[package]] name = "markdown-it-py" @@ -2375,13 +2480,13 @@ files = [ [[package]] name = "netaddr" -version = "0.9.0" +version = "0.10.0" description = "A network address manipulation library for Python" optional = false python-versions = "*" files = [ - {file = "netaddr-0.9.0-py3-none-any.whl", hash = "sha256:5148b1055679d2a1ec070c521b7db82137887fabd6d7e37f5199b44f775c3bb1"}, - {file = "netaddr-0.9.0.tar.gz", hash = "sha256:7b46fa9b1a2d71fd5de9e4a3784ef339700a53a08c8040f08baf5f1194da0128"}, + {file = "netaddr-0.10.0-py2.py3-none-any.whl", hash = "sha256:8752f96c8fc24162edbf5b73d3e464b5d88e62869917582daa37b2695b65afb4"}, + {file = "netaddr-0.10.0.tar.gz", hash = "sha256:4c30c54adf4ea4318b3c055ea3d8c7f6554a50aa2cd8aea4605a23caa0b0229e"}, ] [[package]] @@ -2480,13 +2585,13 @@ files = [ [[package]] name = "pdoc" -version = "14.2.0" +version = "14.3.0" description = "API Documentation for Python Projects" optional = false python-versions = ">=3.8" files = [ - {file = "pdoc-14.2.0-py3-none-any.whl", hash = "sha256:c9c0aa79090dcdcdb0a6c7e367cb0e241e891a836348ef741a8847397dcf98cc"}, - {file = "pdoc-14.2.0.tar.gz", hash = "sha256:a6fac864b2690391e89cb16b280603646eddaa5a2a3057c2973261b9a398416e"}, + {file = "pdoc-14.3.0-py3-none-any.whl", hash = "sha256:9a8f9a48bda5a99c249367c2b99779dbdd9f4a56f905068c9c2d6868dbae6882"}, + {file = "pdoc-14.3.0.tar.gz", hash = "sha256:40bf8f092fcd91560d5e6cebb7c21b65df699f90a468c8ea316235c3368d5449"}, ] [package.dependencies] @@ -2557,36 +2662,36 @@ wcwidth = "*" [[package]] name = "psycopg" -version = "3.1.15" +version = "3.1.16" description = "PostgreSQL database adapter for Python" optional = false python-versions = ">=3.7" files = [ - {file = "psycopg-3.1.15-py3-none-any.whl", hash = "sha256:a6c03e508be0e42facb1e8581156fdc2904322fe8077ba4f298f5f0a947cb8e0"}, - {file = "psycopg-3.1.15.tar.gz", hash = "sha256:1b8e3e8d1612ea289a2684a5bf0c1f9a209549b222b6958377ce970a6e10b80c"}, + {file = "psycopg-3.1.16-py3-none-any.whl", hash = "sha256:0bfe9741f4fb1c8115cadd8fe832fa91ac277e81e0652ff7fa1400f0ef0f59ba"}, + {file = "psycopg-3.1.16.tar.gz", hash = "sha256:a34d922fd7df3134595e71c3428ba6f1bd5f4968db74857fe95de12db2d6b763"}, ] [package.dependencies] -psycopg-c = {version = "3.1.15", optional = true, markers = "implementation_name != \"pypy\" and extra == \"c\""} +psycopg-c = {version = "3.1.16", optional = true, markers = "implementation_name != \"pypy\" and extra == \"c\""} typing-extensions = ">=4.1" tzdata = {version = "*", markers = "sys_platform == \"win32\""} [package.extras] -binary = ["psycopg-binary (==3.1.15)"] -c = ["psycopg-c (==3.1.15)"] -dev = ["black (>=23.1.0)", "dnspython (>=2.1)", "flake8 (>=4.0)", "mypy (>=1.4.1)", "types-setuptools (>=57.4)", "wheel (>=0.37)"] +binary = ["psycopg-binary (==3.1.16)"] +c = ["psycopg-c (==3.1.16)"] +dev = ["black (>=23.1.0)", "codespell (>=2.2)", "dnspython (>=2.1)", "flake8 (>=4.0)", "mypy (>=1.4.1)", "types-setuptools (>=57.4)", "wheel (>=0.37)"] docs = ["Sphinx (>=5.0)", "furo (==2022.6.21)", "sphinx-autobuild (>=2021.3.14)", "sphinx-autodoc-typehints (>=1.12)"] pool = ["psycopg-pool"] test = ["anyio (>=3.6.2,<4.0)", "mypy (>=1.4.1)", "pproxy (>=2.7)", "pytest (>=6.2.5)", "pytest-cov (>=3.0)", "pytest-randomly (>=3.5)"] [[package]] name = "psycopg-c" -version = "3.1.15" +version = "3.1.16" description = "PostgreSQL database adapter for Python -- C optimisation distribution" optional = false python-versions = ">=3.7" files = [ - {file = "psycopg-c-3.1.15.tar.gz", hash = "sha256:7f1513e8fb494f54be83ec02b4f1c91c729b72510c192434c563c1d95bdc74b7"}, + {file = "psycopg-c-3.1.16.tar.gz", hash = "sha256:24f9805e0c20742c72c7be1412e3a600de0980104ff1a264a49333996e6adba3"}, ] [[package]] @@ -2638,60 +2743,60 @@ files = [ [[package]] name = "pycryptodome" -version = "3.19.0" +version = "3.19.1" description = "Cryptographic library for Python" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ - {file = "pycryptodome-3.19.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3006c44c4946583b6de24fe0632091c2653d6256b99a02a3db71ca06472ea1e4"}, - {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:7c760c8a0479a4042111a8dd2f067d3ae4573da286c53f13cf6f5c53a5c1f631"}, - {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:08ce3558af5106c632baf6d331d261f02367a6bc3733086ae43c0f988fe042db"}, - {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45430dfaf1f421cf462c0dd824984378bef32b22669f2635cb809357dbaab405"}, - {file = "pycryptodome-3.19.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:a9bcd5f3794879e91970f2bbd7d899780541d3ff439d8f2112441769c9f2ccea"}, - {file = "pycryptodome-3.19.0-cp27-cp27m-win32.whl", hash = "sha256:190c53f51e988dceb60472baddce3f289fa52b0ec38fbe5fd20dd1d0f795c551"}, - {file = "pycryptodome-3.19.0-cp27-cp27m-win_amd64.whl", hash = "sha256:22e0ae7c3a7f87dcdcf302db06ab76f20e83f09a6993c160b248d58274473bfa"}, - {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:7822f36d683f9ad7bc2145b2c2045014afdbbd1d9922a6d4ce1cbd6add79a01e"}, - {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:05e33267394aad6db6595c0ce9d427fe21552f5425e116a925455e099fdf759a"}, - {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:829b813b8ee00d9c8aba417621b94bc0b5efd18c928923802ad5ba4cf1ec709c"}, - {file = "pycryptodome-3.19.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:fc7a79590e2b5d08530175823a242de6790abc73638cc6dc9d2684e7be2f5e49"}, - {file = "pycryptodome-3.19.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:542f99d5026ac5f0ef391ba0602f3d11beef8e65aae135fa5b762f5ebd9d3bfb"}, - {file = "pycryptodome-3.19.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:61bb3ccbf4bf32ad9af32da8badc24e888ae5231c617947e0f5401077f8b091f"}, - {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d49a6c715d8cceffedabb6adb7e0cbf41ae1a2ff4adaeec9432074a80627dea1"}, - {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e249a784cc98a29c77cea9df54284a44b40cafbfae57636dd2f8775b48af2434"}, - {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d033947e7fd3e2ba9a031cb2d267251620964705a013c5a461fa5233cc025270"}, - {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:84c3e4fffad0c4988aef0d5591be3cad4e10aa7db264c65fadbc633318d20bde"}, - {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:139ae2c6161b9dd5d829c9645d781509a810ef50ea8b657e2257c25ca20efe33"}, - {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:5b1986c761258a5b4332a7f94a83f631c1ffca8747d75ab8395bf2e1b93283d9"}, - {file = "pycryptodome-3.19.0-cp35-abi3-win32.whl", hash = "sha256:536f676963662603f1f2e6ab01080c54d8cd20f34ec333dcb195306fa7826997"}, - {file = "pycryptodome-3.19.0-cp35-abi3-win_amd64.whl", hash = "sha256:04dd31d3b33a6b22ac4d432b3274588917dcf850cc0c51c84eca1d8ed6933810"}, - {file = "pycryptodome-3.19.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:8999316e57abcbd8085c91bc0ef75292c8618f41ca6d2b6132250a863a77d1e7"}, - {file = "pycryptodome-3.19.0-pp27-pypy_73-win32.whl", hash = "sha256:a0ab84755f4539db086db9ba9e9f3868d2e3610a3948cbd2a55e332ad83b01b0"}, - {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0101f647d11a1aae5a8ce4f5fad6644ae1b22bb65d05accc7d322943c69a74a6"}, - {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c1601e04d32087591d78e0b81e1e520e57a92796089864b20e5f18c9564b3fa"}, - {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:506c686a1eee6c00df70010be3b8e9e78f406af4f21b23162bbb6e9bdf5427bc"}, - {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7919ccd096584b911f2a303c593280869ce1af9bf5d36214511f5e5a1bed8c34"}, - {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:560591c0777f74a5da86718f70dfc8d781734cf559773b64072bbdda44b3fc3e"}, - {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1cc2f2ae451a676def1a73c1ae9120cd31af25db3f381893d45f75e77be2400"}, - {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:17940dcf274fcae4a54ec6117a9ecfe52907ed5e2e438fe712fe7ca502672ed5"}, - {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d04f5f623a280fbd0ab1c1d8ecbd753193ab7154f09b6161b0f857a1a676c15f"}, - {file = "pycryptodome-3.19.0.tar.gz", hash = "sha256:bc35d463222cdb4dbebd35e0784155c81e161b9284e567e7e933d722e533331e"}, + {file = "pycryptodome-3.19.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:694020d2ff985cd714381b9da949a21028c24b86f562526186f6af7c7547e986"}, + {file = "pycryptodome-3.19.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:4464b0e8fd5508bff9baf18e6fd4c6548b1ac2ce9862d6965ff6a84ec9cb302a"}, + {file = "pycryptodome-3.19.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:420972f9c62978e852c74055d81c354079ce3c3a2213a92c9d7e37bbc63a26e2"}, + {file = "pycryptodome-3.19.1-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1bc0c49d986a1491d66d2a56570f12e960b12508b7e71f2423f532e28857f36"}, + {file = "pycryptodome-3.19.1-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:e038ab77fec0956d7aa989a3c647652937fc142ef41c9382c2ebd13c127d5b4a"}, + {file = "pycryptodome-3.19.1-cp27-cp27m-win32.whl", hash = "sha256:a991f8ffe8dfe708f86690948ae46442eebdd0fff07dc1b605987939a34ec979"}, + {file = "pycryptodome-3.19.1-cp27-cp27m-win_amd64.whl", hash = "sha256:2c16426ef49d9cba018be2340ea986837e1dfa25c2ea181787971654dd49aadd"}, + {file = "pycryptodome-3.19.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6d0d2b97758ebf2f36c39060520447c26455acb3bcff309c28b1c816173a6ff5"}, + {file = "pycryptodome-3.19.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:b8b80ff92049fd042177282917d994d344365ab7e8ec2bc03e853d93d2401786"}, + {file = "pycryptodome-3.19.1-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd4e7e8bf0fc1ada854688b9b309ee607e2aa85a8b44180f91021a4dd330a928"}, + {file = "pycryptodome-3.19.1-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:8cf5d3d6cf921fa81acd1f632f6cedcc03f5f68fc50c364cd39490ba01d17c49"}, + {file = "pycryptodome-3.19.1-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:67939a3adbe637281c611596e44500ff309d547e932c449337649921b17b6297"}, + {file = "pycryptodome-3.19.1-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:11ddf6c9b52116b62223b6a9f4741bc4f62bb265392a4463282f7f34bb287180"}, + {file = "pycryptodome-3.19.1-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3e6f89480616781d2a7f981472d0cdb09b9da9e8196f43c1234eff45c915766"}, + {file = "pycryptodome-3.19.1-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27e1efcb68993b7ce5d1d047a46a601d41281bba9f1971e6be4aa27c69ab8065"}, + {file = "pycryptodome-3.19.1-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c6273ca5a03b672e504995529b8bae56da0ebb691d8ef141c4aa68f60765700"}, + {file = "pycryptodome-3.19.1-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:b0bfe61506795877ff974f994397f0c862d037f6f1c0bfc3572195fc00833b96"}, + {file = "pycryptodome-3.19.1-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:f34976c5c8eb79e14c7d970fb097482835be8d410a4220f86260695ede4c3e17"}, + {file = "pycryptodome-3.19.1-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:7c9e222d0976f68d0cf6409cfea896676ddc1d98485d601e9508f90f60e2b0a2"}, + {file = "pycryptodome-3.19.1-cp35-abi3-win32.whl", hash = "sha256:4805e053571140cb37cf153b5c72cd324bb1e3e837cbe590a19f69b6cf85fd03"}, + {file = "pycryptodome-3.19.1-cp35-abi3-win_amd64.whl", hash = "sha256:a470237ee71a1efd63f9becebc0ad84b88ec28e6784a2047684b693f458f41b7"}, + {file = "pycryptodome-3.19.1-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:ed932eb6c2b1c4391e166e1a562c9d2f020bfff44a0e1b108f67af38b390ea89"}, + {file = "pycryptodome-3.19.1-pp27-pypy_73-win32.whl", hash = "sha256:81e9d23c0316fc1b45d984a44881b220062336bbdc340aa9218e8d0656587934"}, + {file = "pycryptodome-3.19.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:37e531bf896b70fe302f003d3be5a0a8697737a8d177967da7e23eff60d6483c"}, + {file = "pycryptodome-3.19.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd4e95b0eb4b28251c825fe7aa941fe077f993e5ca9b855665935b86fbb1cc08"}, + {file = "pycryptodome-3.19.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c22c80246c3c880c6950d2a8addf156cee74ec0dc5757d01e8e7067a3c7da015"}, + {file = "pycryptodome-3.19.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e70f5c839c7798743a948efa2a65d1fe96bb397fe6d7f2bde93d869fe4f0ad69"}, + {file = "pycryptodome-3.19.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6c3df3613592ea6afaec900fd7189d23c8c28b75b550254f4bd33fe94acb84b9"}, + {file = "pycryptodome-3.19.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08b445799d571041765e7d5c9ca09c5d3866c2f22eeb0dd4394a4169285184f4"}, + {file = "pycryptodome-3.19.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:954d156cd50130afd53f8d77f830fe6d5801bd23e97a69d358fed068f433fbfe"}, + {file = "pycryptodome-3.19.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b7efd46b0b4ac869046e814d83244aeab14ef787f4850644119b1c8b0ec2d637"}, + {file = "pycryptodome-3.19.1.tar.gz", hash = "sha256:8ae0dd1bcfada451c35f9e29a3e5db385caabc190f98e4a80ad02a61098fb776"}, ] [[package]] name = "pydantic" -version = "2.5.2" +version = "2.5.3" description = "Data validation using Python type hints" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-2.5.2-py3-none-any.whl", hash = "sha256:80c50fb8e3dcecfddae1adbcc00ec5822918490c99ab31f6cf6140ca1c1429f0"}, - {file = "pydantic-2.5.2.tar.gz", hash = "sha256:ff177ba64c6faf73d7afa2e8cad38fd456c0dbe01c9954e71038001cd15a6edd"}, + {file = "pydantic-2.5.3-py3-none-any.whl", hash = "sha256:d0caf5954bee831b6bfe7e338c32b9e30c85dfe080c843680783ac2b631673b4"}, + {file = "pydantic-2.5.3.tar.gz", hash = "sha256:b3ef57c62535b0941697cce638c08900d87fcb67e29cfa99e8a68f747f393f7a"}, ] [package.dependencies] annotated-types = ">=0.4.0" email-validator = {version = ">=2.0.0", optional = true, markers = "extra == \"email\""} -pydantic-core = "2.14.5" +pydantic-core = "2.14.6" typing-extensions = ">=4.6.1" [package.extras] @@ -2699,116 +2804,116 @@ email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.14.5" +version = "2.14.6" description = "" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic_core-2.14.5-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:7e88f5696153dc516ba6e79f82cc4747e87027205f0e02390c21f7cb3bd8abfd"}, - {file = "pydantic_core-2.14.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4641e8ad4efb697f38a9b64ca0523b557c7931c5f84e0fd377a9a3b05121f0de"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:774de879d212db5ce02dfbf5b0da9a0ea386aeba12b0b95674a4ce0593df3d07"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ebb4e035e28f49b6f1a7032920bb9a0c064aedbbabe52c543343d39341a5b2a3"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b53e9ad053cd064f7e473a5f29b37fc4cc9dc6d35f341e6afc0155ea257fc911"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aa1768c151cf562a9992462239dfc356b3d1037cc5a3ac829bb7f3bda7cc1f9"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eac5c82fc632c599f4639a5886f96867ffced74458c7db61bc9a66ccb8ee3113"}, - {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2ae91f50ccc5810b2f1b6b858257c9ad2e08da70bf890dee02de1775a387c66"}, - {file = "pydantic_core-2.14.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6b9ff467ffbab9110e80e8c8de3bcfce8e8b0fd5661ac44a09ae5901668ba997"}, - {file = "pydantic_core-2.14.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:61ea96a78378e3bd5a0be99b0e5ed00057b71f66115f5404d0dae4819f495093"}, - {file = "pydantic_core-2.14.5-cp310-none-win32.whl", hash = "sha256:bb4c2eda937a5e74c38a41b33d8c77220380a388d689bcdb9b187cf6224c9720"}, - {file = "pydantic_core-2.14.5-cp310-none-win_amd64.whl", hash = "sha256:b7851992faf25eac90bfcb7bfd19e1f5ffa00afd57daec8a0042e63c74a4551b"}, - {file = "pydantic_core-2.14.5-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:4e40f2bd0d57dac3feb3a3aed50f17d83436c9e6b09b16af271b6230a2915459"}, - {file = "pydantic_core-2.14.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ab1cdb0f14dc161ebc268c09db04d2c9e6f70027f3b42446fa11c153521c0e88"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aae7ea3a1c5bb40c93cad361b3e869b180ac174656120c42b9fadebf685d121b"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:60b7607753ba62cf0739177913b858140f11b8af72f22860c28eabb2f0a61937"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2248485b0322c75aee7565d95ad0e16f1c67403a470d02f94da7344184be770f"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:823fcc638f67035137a5cd3f1584a4542d35a951c3cc68c6ead1df7dac825c26"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96581cfefa9123accc465a5fd0cc833ac4d75d55cc30b633b402e00e7ced00a6"}, - {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a33324437018bf6ba1bb0f921788788641439e0ed654b233285b9c69704c27b4"}, - {file = "pydantic_core-2.14.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9bd18fee0923ca10f9a3ff67d4851c9d3e22b7bc63d1eddc12f439f436f2aada"}, - {file = "pydantic_core-2.14.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:853a2295c00f1d4429db4c0fb9475958543ee80cfd310814b5c0ef502de24dda"}, - {file = "pydantic_core-2.14.5-cp311-none-win32.whl", hash = "sha256:cb774298da62aea5c80a89bd58c40205ab4c2abf4834453b5de207d59d2e1651"}, - {file = "pydantic_core-2.14.5-cp311-none-win_amd64.whl", hash = "sha256:e87fc540c6cac7f29ede02e0f989d4233f88ad439c5cdee56f693cc9c1c78077"}, - {file = "pydantic_core-2.14.5-cp311-none-win_arm64.whl", hash = "sha256:57d52fa717ff445cb0a5ab5237db502e6be50809b43a596fb569630c665abddf"}, - {file = "pydantic_core-2.14.5-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:e60f112ac88db9261ad3a52032ea46388378034f3279c643499edb982536a093"}, - {file = "pydantic_core-2.14.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6e227c40c02fd873c2a73a98c1280c10315cbebe26734c196ef4514776120aeb"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0cbc7fff06a90bbd875cc201f94ef0ee3929dfbd5c55a06674b60857b8b85ed"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:103ef8d5b58596a731b690112819501ba1db7a36f4ee99f7892c40da02c3e189"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c949f04ecad823f81b1ba94e7d189d9dfb81edbb94ed3f8acfce41e682e48cef"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c1452a1acdf914d194159439eb21e56b89aa903f2e1c65c60b9d874f9b950e5d"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb4679d4c2b089e5ef89756bc73e1926745e995d76e11925e3e96a76d5fa51fc"}, - {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf9d3fe53b1ee360e2421be95e62ca9b3296bf3f2fb2d3b83ca49ad3f925835e"}, - {file = "pydantic_core-2.14.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:70f4b4851dbb500129681d04cc955be2a90b2248d69273a787dda120d5cf1f69"}, - {file = "pydantic_core-2.14.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:59986de5710ad9613ff61dd9b02bdd2f615f1a7052304b79cc8fa2eb4e336d2d"}, - {file = "pydantic_core-2.14.5-cp312-none-win32.whl", hash = "sha256:699156034181e2ce106c89ddb4b6504c30db8caa86e0c30de47b3e0654543260"}, - {file = "pydantic_core-2.14.5-cp312-none-win_amd64.whl", hash = "sha256:5baab5455c7a538ac7e8bf1feec4278a66436197592a9bed538160a2e7d11e36"}, - {file = "pydantic_core-2.14.5-cp312-none-win_arm64.whl", hash = "sha256:e47e9a08bcc04d20975b6434cc50bf82665fbc751bcce739d04a3120428f3e27"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:af36f36538418f3806048f3b242a1777e2540ff9efaa667c27da63d2749dbce0"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:45e95333b8418ded64745f14574aa9bfc212cb4fbeed7a687b0c6e53b5e188cd"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e47a76848f92529879ecfc417ff88a2806438f57be4a6a8bf2961e8f9ca9ec7"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d81e6987b27bc7d101c8597e1cd2bcaa2fee5e8e0f356735c7ed34368c471550"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34708cc82c330e303f4ce87758828ef6e457681b58ce0e921b6e97937dd1e2a3"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:652c1988019752138b974c28f43751528116bcceadad85f33a258869e641d753"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e4d090e73e0725b2904fdbdd8d73b8802ddd691ef9254577b708d413bf3006e"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5c7d5b5005f177764e96bd584d7bf28d6e26e96f2a541fdddb934c486e36fd59"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a71891847f0a73b1b9eb86d089baee301477abef45f7eaf303495cd1473613e4"}, - {file = "pydantic_core-2.14.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a717aef6971208f0851a2420b075338e33083111d92041157bbe0e2713b37325"}, - {file = "pydantic_core-2.14.5-cp37-none-win32.whl", hash = "sha256:de790a3b5aa2124b8b78ae5faa033937a72da8efe74b9231698b5a1dd9be3405"}, - {file = "pydantic_core-2.14.5-cp37-none-win_amd64.whl", hash = "sha256:6c327e9cd849b564b234da821236e6bcbe4f359a42ee05050dc79d8ed2a91588"}, - {file = "pydantic_core-2.14.5-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:ef98ca7d5995a82f43ec0ab39c4caf6a9b994cb0b53648ff61716370eadc43cf"}, - {file = "pydantic_core-2.14.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6eae413494a1c3f89055da7a5515f32e05ebc1a234c27674a6956755fb2236f"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcf4e6d85614f7a4956c2de5a56531f44efb973d2fe4a444d7251df5d5c4dcfd"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6637560562134b0e17de333d18e69e312e0458ee4455bdad12c37100b7cad706"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77fa384d8e118b3077cccfcaf91bf83c31fe4dc850b5e6ee3dc14dc3d61bdba1"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16e29bad40bcf97aac682a58861249ca9dcc57c3f6be22f506501833ddb8939c"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:531f4b4252fac6ca476fbe0e6f60f16f5b65d3e6b583bc4d87645e4e5ddde331"}, - {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:074f3d86f081ce61414d2dc44901f4f83617329c6f3ab49d2bc6c96948b2c26b"}, - {file = "pydantic_core-2.14.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c2adbe22ab4babbca99c75c5d07aaf74f43c3195384ec07ccbd2f9e3bddaecec"}, - {file = "pydantic_core-2.14.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0f6116a558fd06d1b7c2902d1c4cf64a5bd49d67c3540e61eccca93f41418124"}, - {file = "pydantic_core-2.14.5-cp38-none-win32.whl", hash = "sha256:fe0a5a1025eb797752136ac8b4fa21aa891e3d74fd340f864ff982d649691867"}, - {file = "pydantic_core-2.14.5-cp38-none-win_amd64.whl", hash = "sha256:079206491c435b60778cf2b0ee5fd645e61ffd6e70c47806c9ed51fc75af078d"}, - {file = "pydantic_core-2.14.5-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:a6a16f4a527aae4f49c875da3cdc9508ac7eef26e7977952608610104244e1b7"}, - {file = "pydantic_core-2.14.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:abf058be9517dc877227ec3223f0300034bd0e9f53aebd63cf4456c8cb1e0863"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49b08aae5013640a3bfa25a8eebbd95638ec3f4b2eaf6ed82cf0c7047133f03b"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c2d97e906b4ff36eb464d52a3bc7d720bd6261f64bc4bcdbcd2c557c02081ed2"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3128e0bbc8c091ec4375a1828d6118bc20404883169ac95ffa8d983b293611e6"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88e74ab0cdd84ad0614e2750f903bb0d610cc8af2cc17f72c28163acfcf372a4"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c339dabd8ee15f8259ee0f202679b6324926e5bc9e9a40bf981ce77c038553db"}, - {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3387277f1bf659caf1724e1afe8ee7dbc9952a82d90f858ebb931880216ea955"}, - {file = "pydantic_core-2.14.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ba6b6b3846cfc10fdb4c971980a954e49d447cd215ed5a77ec8190bc93dd7bc5"}, - {file = "pydantic_core-2.14.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ca61d858e4107ce5e1330a74724fe757fc7135190eb5ce5c9d0191729f033209"}, - {file = "pydantic_core-2.14.5-cp39-none-win32.whl", hash = "sha256:ec1e72d6412f7126eb7b2e3bfca42b15e6e389e1bc88ea0069d0cc1742f477c6"}, - {file = "pydantic_core-2.14.5-cp39-none-win_amd64.whl", hash = "sha256:c0b97ec434041827935044bbbe52b03d6018c2897349670ff8fe11ed24d1d4ab"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:79e0a2cdbdc7af3f4aee3210b1172ab53d7ddb6a2d8c24119b5706e622b346d0"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:678265f7b14e138d9a541ddabbe033012a2953315739f8cfa6d754cc8063e8ca"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95b15e855ae44f0c6341ceb74df61b606e11f1087e87dcb7482377374aac6abe"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09b0e985fbaf13e6b06a56d21694d12ebca6ce5414b9211edf6f17738d82b0f8"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3ad873900297bb36e4b6b3f7029d88ff9829ecdc15d5cf20161775ce12306f8a"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2d0ae0d8670164e10accbeb31d5ad45adb71292032d0fdb9079912907f0085f4"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d37f8ec982ead9ba0a22a996129594938138a1503237b87318392a48882d50b7"}, - {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:35613015f0ba7e14c29ac6c2483a657ec740e5ac5758d993fdd5870b07a61d8b"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ab4ea451082e684198636565224bbb179575efc1658c48281b2c866bfd4ddf04"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ce601907e99ea5b4adb807ded3570ea62186b17f88e271569144e8cca4409c7"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb2ed8b3fe4bf4506d6dab3b93b83bbc22237e230cba03866d561c3577517d18"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:70f947628e074bb2526ba1b151cee10e4c3b9670af4dbb4d73bc8a89445916b5"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4bc536201426451f06f044dfbf341c09f540b4ebdb9fd8d2c6164d733de5e634"}, - {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4791cf0f8c3104ac668797d8c514afb3431bc3305f5638add0ba1a5a37e0d88"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:038c9f763e650712b899f983076ce783175397c848da04985658e7628cbe873b"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:27548e16c79702f1e03f5628589c6057c9ae17c95b4c449de3c66b589ead0520"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97bee68898f3f4344eb02fec316db93d9700fb1e6a5b760ffa20d71d9a46ce3"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9b759b77f5337b4ea024f03abc6464c9f35d9718de01cfe6bae9f2e139c397e"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:439c9afe34638ace43a49bf72d201e0ffc1a800295bed8420c2a9ca8d5e3dbb3"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:ba39688799094c75ea8a16a6b544eb57b5b0f3328697084f3f2790892510d144"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ccd4d5702bb90b84df13bd491be8d900b92016c5a455b7e14630ad7449eb03f8"}, - {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:81982d78a45d1e5396819bbb4ece1fadfe5f079335dd28c4ab3427cd95389944"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:7f8210297b04e53bc3da35db08b7302a6a1f4889c79173af69b72ec9754796b8"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:8c8a8812fe6f43a3a5b054af6ac2d7b8605c7bcab2804a8a7d68b53f3cd86e00"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:206ed23aecd67c71daf5c02c3cd19c0501b01ef3cbf7782db9e4e051426b3d0d"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2027d05c8aebe61d898d4cffd774840a9cb82ed356ba47a90d99ad768f39789"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40180930807ce806aa71eda5a5a5447abb6b6a3c0b4b3b1b1962651906484d68"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:615a0a4bff11c45eb3c1996ceed5bdaa2f7b432425253a7c2eed33bb86d80abc"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5e412d717366e0677ef767eac93566582518fe8be923361a5c204c1a62eaafe"}, - {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:513b07e99c0a267b1d954243845d8a833758a6726a3b5d8948306e3fe14675e3"}, - {file = "pydantic_core-2.14.5.tar.gz", hash = "sha256:6d30226dfc816dd0fdf120cae611dd2215117e4f9b124af8c60ab9093b6e8e71"}, + {file = "pydantic_core-2.14.6-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:72f9a942d739f09cd42fffe5dc759928217649f070056f03c70df14f5770acf9"}, + {file = "pydantic_core-2.14.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6a31d98c0d69776c2576dda4b77b8e0c69ad08e8b539c25c7d0ca0dc19a50d6c"}, + {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5aa90562bc079c6c290f0512b21768967f9968e4cfea84ea4ff5af5d917016e4"}, + {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:370ffecb5316ed23b667d99ce4debe53ea664b99cc37bfa2af47bc769056d534"}, + {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f85f3843bdb1fe80e8c206fe6eed7a1caeae897e496542cee499c374a85c6e08"}, + {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9862bf828112e19685b76ca499b379338fd4c5c269d897e218b2ae8fcb80139d"}, + {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:036137b5ad0cb0004c75b579445a1efccd072387a36c7f217bb8efd1afbe5245"}, + {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92879bce89f91f4b2416eba4429c7b5ca22c45ef4a499c39f0c5c69257522c7c"}, + {file = "pydantic_core-2.14.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0c08de15d50fa190d577e8591f0329a643eeaed696d7771760295998aca6bc66"}, + {file = "pydantic_core-2.14.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:36099c69f6b14fc2c49d7996cbf4f87ec4f0e66d1c74aa05228583225a07b590"}, + {file = "pydantic_core-2.14.6-cp310-none-win32.whl", hash = "sha256:7be719e4d2ae6c314f72844ba9d69e38dff342bc360379f7c8537c48e23034b7"}, + {file = "pydantic_core-2.14.6-cp310-none-win_amd64.whl", hash = "sha256:36fa402dcdc8ea7f1b0ddcf0df4254cc6b2e08f8cd80e7010d4c4ae6e86b2a87"}, + {file = "pydantic_core-2.14.6-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:dea7fcd62915fb150cdc373212141a30037e11b761fbced340e9db3379b892d4"}, + {file = "pydantic_core-2.14.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ffff855100bc066ff2cd3aa4a60bc9534661816b110f0243e59503ec2df38421"}, + {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b027c86c66b8627eb90e57aee1f526df77dc6d8b354ec498be9a757d513b92b"}, + {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:00b1087dabcee0b0ffd104f9f53d7d3eaddfaa314cdd6726143af6bc713aa27e"}, + {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:75ec284328b60a4e91010c1acade0c30584f28a1f345bc8f72fe8b9e46ec6a96"}, + {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e1f4744eea1501404b20b0ac059ff7e3f96a97d3e3f48ce27a139e053bb370b"}, + {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2602177668f89b38b9f84b7b3435d0a72511ddef45dc14446811759b82235a1"}, + {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6c8edaea3089bf908dd27da8f5d9e395c5b4dc092dbcce9b65e7156099b4b937"}, + {file = "pydantic_core-2.14.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:478e9e7b360dfec451daafe286998d4a1eeaecf6d69c427b834ae771cad4b622"}, + {file = "pydantic_core-2.14.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b6ca36c12a5120bad343eef193cc0122928c5c7466121da7c20f41160ba00ba2"}, + {file = "pydantic_core-2.14.6-cp311-none-win32.whl", hash = "sha256:2b8719037e570639e6b665a4050add43134d80b687288ba3ade18b22bbb29dd2"}, + {file = "pydantic_core-2.14.6-cp311-none-win_amd64.whl", hash = "sha256:78ee52ecc088c61cce32b2d30a826f929e1708f7b9247dc3b921aec367dc1b23"}, + {file = "pydantic_core-2.14.6-cp311-none-win_arm64.whl", hash = "sha256:a19b794f8fe6569472ff77602437ec4430f9b2b9ec7a1105cfd2232f9ba355e6"}, + {file = "pydantic_core-2.14.6-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:667aa2eac9cd0700af1ddb38b7b1ef246d8cf94c85637cbb03d7757ca4c3fdec"}, + {file = "pydantic_core-2.14.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cdee837710ef6b56ebd20245b83799fce40b265b3b406e51e8ccc5b85b9099b7"}, + {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c5bcf3414367e29f83fd66f7de64509a8fd2368b1edf4351e862910727d3e51"}, + {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26a92ae76f75d1915806b77cf459811e772d8f71fd1e4339c99750f0e7f6324f"}, + {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a983cca5ed1dd9a35e9e42ebf9f278d344603bfcb174ff99a5815f953925140a"}, + {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cb92f9061657287eded380d7dc455bbf115430b3aa4741bdc662d02977e7d0af"}, + {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4ace1e220b078c8e48e82c081e35002038657e4b37d403ce940fa679e57113b"}, + {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef633add81832f4b56d3b4c9408b43d530dfca29e68fb1b797dcb861a2c734cd"}, + {file = "pydantic_core-2.14.6-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7e90d6cc4aad2cc1f5e16ed56e46cebf4877c62403a311af20459c15da76fd91"}, + {file = "pydantic_core-2.14.6-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e8a5ac97ea521d7bde7621d86c30e86b798cdecd985723c4ed737a2aa9e77d0c"}, + {file = "pydantic_core-2.14.6-cp312-none-win32.whl", hash = "sha256:f27207e8ca3e5e021e2402ba942e5b4c629718e665c81b8b306f3c8b1ddbb786"}, + {file = "pydantic_core-2.14.6-cp312-none-win_amd64.whl", hash = "sha256:b3e5fe4538001bb82e2295b8d2a39356a84694c97cb73a566dc36328b9f83b40"}, + {file = "pydantic_core-2.14.6-cp312-none-win_arm64.whl", hash = "sha256:64634ccf9d671c6be242a664a33c4acf12882670b09b3f163cd00a24cffbd74e"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:24368e31be2c88bd69340fbfe741b405302993242ccb476c5c3ff48aeee1afe0"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:e33b0834f1cf779aa839975f9d8755a7c2420510c0fa1e9fa0497de77cd35d2c"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6af4b3f52cc65f8a0bc8b1cd9676f8c21ef3e9132f21fed250f6958bd7223bed"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d15687d7d7f40333bd8266f3814c591c2e2cd263fa2116e314f60d82086e353a"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:095b707bb287bfd534044166ab767bec70a9bba3175dcdc3371782175c14e43c"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94fc0e6621e07d1e91c44e016cc0b189b48db053061cc22d6298a611de8071bb"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ce830e480f6774608dedfd4a90c42aac4a7af0a711f1b52f807130c2e434c06"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a306cdd2ad3a7d795d8e617a58c3a2ed0f76c8496fb7621b6cd514eb1532cae8"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:2f5fa187bde8524b1e37ba894db13aadd64faa884657473b03a019f625cee9a8"}, + {file = "pydantic_core-2.14.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:438027a975cc213a47c5d70672e0d29776082155cfae540c4e225716586be75e"}, + {file = "pydantic_core-2.14.6-cp37-none-win32.whl", hash = "sha256:f96ae96a060a8072ceff4cfde89d261837b4294a4f28b84a28765470d502ccc6"}, + {file = "pydantic_core-2.14.6-cp37-none-win_amd64.whl", hash = "sha256:e646c0e282e960345314f42f2cea5e0b5f56938c093541ea6dbf11aec2862391"}, + {file = "pydantic_core-2.14.6-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:db453f2da3f59a348f514cfbfeb042393b68720787bbef2b4c6068ea362c8149"}, + {file = "pydantic_core-2.14.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3860c62057acd95cc84044e758e47b18dcd8871a328ebc8ccdefd18b0d26a21b"}, + {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36026d8f99c58d7044413e1b819a67ca0e0b8ebe0f25e775e6c3d1fabb3c38fb"}, + {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8ed1af8692bd8d2a29d702f1a2e6065416d76897d726e45a1775b1444f5928a7"}, + {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:314ccc4264ce7d854941231cf71b592e30d8d368a71e50197c905874feacc8a8"}, + {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:982487f8931067a32e72d40ab6b47b1628a9c5d344be7f1a4e668fb462d2da42"}, + {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dbe357bc4ddda078f79d2a36fc1dd0494a7f2fad83a0a684465b6f24b46fe80"}, + {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2f6ffc6701a0eb28648c845f4945a194dc7ab3c651f535b81793251e1185ac3d"}, + {file = "pydantic_core-2.14.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7f5025db12fc6de7bc1104d826d5aee1d172f9ba6ca936bf6474c2148ac336c1"}, + {file = "pydantic_core-2.14.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dab03ed811ed1c71d700ed08bde8431cf429bbe59e423394f0f4055f1ca0ea60"}, + {file = "pydantic_core-2.14.6-cp38-none-win32.whl", hash = "sha256:dfcbebdb3c4b6f739a91769aea5ed615023f3c88cb70df812849aef634c25fbe"}, + {file = "pydantic_core-2.14.6-cp38-none-win_amd64.whl", hash = "sha256:99b14dbea2fdb563d8b5a57c9badfcd72083f6006caf8e126b491519c7d64ca8"}, + {file = "pydantic_core-2.14.6-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:4ce8299b481bcb68e5c82002b96e411796b844d72b3e92a3fbedfe8e19813eab"}, + {file = "pydantic_core-2.14.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b9a9d92f10772d2a181b5ca339dee066ab7d1c9a34ae2421b2a52556e719756f"}, + {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd9e98b408384989ea4ab60206b8e100d8687da18b5c813c11e92fd8212a98e0"}, + {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4f86f1f318e56f5cbb282fe61eb84767aee743ebe32c7c0834690ebea50c0a6b"}, + {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86ce5fcfc3accf3a07a729779d0b86c5d0309a4764c897d86c11089be61da160"}, + {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dcf1978be02153c6a31692d4fbcc2a3f1db9da36039ead23173bc256ee3b91b"}, + {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eedf97be7bc3dbc8addcef4142f4b4164066df0c6f36397ae4aaed3eb187d8ab"}, + {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5f916acf8afbcab6bacbb376ba7dc61f845367901ecd5e328fc4d4aef2fcab0"}, + {file = "pydantic_core-2.14.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8a14c192c1d724c3acbfb3f10a958c55a2638391319ce8078cb36c02283959b9"}, + {file = "pydantic_core-2.14.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0348b1dc6b76041516e8a854ff95b21c55f5a411c3297d2ca52f5528e49d8411"}, + {file = "pydantic_core-2.14.6-cp39-none-win32.whl", hash = "sha256:de2a0645a923ba57c5527497daf8ec5df69c6eadf869e9cd46e86349146e5975"}, + {file = "pydantic_core-2.14.6-cp39-none-win_amd64.whl", hash = "sha256:aca48506a9c20f68ee61c87f2008f81f8ee99f8d7f0104bff3c47e2d148f89d9"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d5c28525c19f5bb1e09511669bb57353d22b94cf8b65f3a8d141c389a55dec95"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:78d0768ee59baa3de0f4adac9e3748b4b1fffc52143caebddfd5ea2961595277"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b93785eadaef932e4fe9c6e12ba67beb1b3f1e5495631419c784ab87e975670"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a874f21f87c485310944b2b2734cd6d318765bcbb7515eead33af9641816506e"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89f4477d915ea43b4ceea6756f63f0288941b6443a2b28c69004fe07fde0d0d"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:172de779e2a153d36ee690dbc49c6db568d7b33b18dc56b69a7514aecbcf380d"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:dfcebb950aa7e667ec226a442722134539e77c575f6cfaa423f24371bb8d2e94"}, + {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:55a23dcd98c858c0db44fc5c04fc7ed81c4b4d33c653a7c45ddaebf6563a2f66"}, + {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:4241204e4b36ab5ae466ecec5c4c16527a054c69f99bba20f6f75232a6a534e2"}, + {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e574de99d735b3fc8364cba9912c2bec2da78775eba95cbb225ef7dda6acea24"}, + {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1302a54f87b5cd8528e4d6d1bf2133b6aa7c6122ff8e9dc5220fbc1e07bffebd"}, + {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8e81e4b55930e5ffab4a68db1af431629cf2e4066dbdbfef65348b8ab804ea8"}, + {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c99462ffc538717b3e60151dfaf91125f637e801f5ab008f81c402f1dff0cd0f"}, + {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e4cf2d5829f6963a5483ec01578ee76d329eb5caf330ecd05b3edd697e7d768a"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:cf10b7d58ae4a1f07fccbf4a0a956d705356fea05fb4c70608bb6fa81d103cda"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:399ac0891c284fa8eb998bcfa323f2234858f5d2efca3950ae58c8f88830f145"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c6a5c79b28003543db3ba67d1df336f253a87d3112dac3a51b94f7d48e4c0e1"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:599c87d79cab2a6a2a9df4aefe0455e61e7d2aeede2f8577c1b7c0aec643ee8e"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43e166ad47ba900f2542a80d83f9fc65fe99eb63ceec4debec160ae729824052"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3a0b5db001b98e1c649dd55afa928e75aa4087e587b9524a4992316fa23c9fba"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:747265448cb57a9f37572a488a57d873fd96bf51e5bb7edb52cfb37124516da4"}, + {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:7ebe3416785f65c28f4f9441e916bfc8a54179c8dea73c23023f7086fa601c5d"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:86c963186ca5e50d5c8287b1d1c9d3f8f024cbe343d048c5bd282aec2d8641f2"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e0641b506486f0b4cd1500a2a65740243e8670a2549bb02bc4556a83af84ae03"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71d72ca5eaaa8d38c8df16b7deb1a2da4f650c41b58bb142f3fb75d5ad4a611f"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27e524624eace5c59af499cd97dc18bb201dc6a7a2da24bfc66ef151c69a5f2a"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a3dde6cac75e0b0902778978d3b1646ca9f438654395a362cb21d9ad34b24acf"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:00646784f6cd993b1e1c0e7b0fdcbccc375d539db95555477771c27555e3c556"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:23598acb8ccaa3d1d875ef3b35cb6376535095e9405d91a3d57a8c7db5d29341"}, + {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7f41533d7e3cf9520065f610b41ac1c76bc2161415955fbcead4981b22c7611e"}, + {file = "pydantic_core-2.14.6.tar.gz", hash = "sha256:1fd0c1d395372843fba13a51c28e3bb9d59bd7aebfeb17358ffaaa1e4dbbe948"}, ] [package.dependencies] @@ -2992,13 +3097,13 @@ files = [ [[package]] name = "pytest" -version = "7.4.3" +version = "7.4.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, - {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, ] [package.dependencies] @@ -3299,110 +3404,110 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "rpds-py" -version = "0.15.2" +version = "0.16.2" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false python-versions = ">=3.8" files = [ - {file = "rpds_py-0.15.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:337a8653fb11d2fbe7157c961cc78cb3c161d98cf44410ace9a3dc2db4fad882"}, - {file = "rpds_py-0.15.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:813a65f95bfcb7c8f2a70dd6add9b51e9accc3bdb3e03d0ff7a9e6a2d3e174bf"}, - {file = "rpds_py-0.15.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:082e0e55d73690ffb4da4352d1b5bbe1b5c6034eb9dc8c91aa2a3ee15f70d3e2"}, - {file = "rpds_py-0.15.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5595c80dd03d7e6c6afb73f3594bf3379a7d79fa57164b591d012d4b71d6ac4c"}, - {file = "rpds_py-0.15.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fb10bb720348fe1647a94eb605accb9ef6a9b1875d8845f9e763d9d71a706387"}, - {file = "rpds_py-0.15.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:53304cc14b1d94487d70086e1cb0cb4c29ec6da994d58ae84a4d7e78c6a6d04d"}, - {file = "rpds_py-0.15.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d64a657de7aae8db2da60dc0c9e4638a0c3893b4d60101fd564a3362b2bfeb34"}, - {file = "rpds_py-0.15.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ee40206d1d6e95eaa2b7b919195e3689a5cf6ded730632de7f187f35a1b6052c"}, - {file = "rpds_py-0.15.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:1607cda6129f815493a3c184492acb5ae4aa6ed61d3a1b3663aa9824ed26f7ac"}, - {file = "rpds_py-0.15.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f3e6e2e502c4043c52a99316d89dc49f416acda5b0c6886e0dd8ea7bb35859e8"}, - {file = "rpds_py-0.15.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:044f6f46d62444800402851afa3c3ae50141f12013060c1a3a0677e013310d6d"}, - {file = "rpds_py-0.15.2-cp310-none-win32.whl", hash = "sha256:c827a931c6b57f50f1bb5de400dcfb00bad8117e3753e80b96adb72d9d811514"}, - {file = "rpds_py-0.15.2-cp310-none-win_amd64.whl", hash = "sha256:3bbc89ce2a219662ea142f0abcf8d43f04a41d5b1880be17a794c39f0d609cb0"}, - {file = "rpds_py-0.15.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:1fd0f0b1ccd7d537b858a56355a250108df692102e08aa2036e1a094fd78b2dc"}, - {file = "rpds_py-0.15.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b414ef79f1f06fb90b5165db8aef77512c1a5e3ed1b4807da8476b7e2c853283"}, - {file = "rpds_py-0.15.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c31272c674f725dfe0f343d73b0abe8c878c646967ec1c6106122faae1efc15b"}, - {file = "rpds_py-0.15.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a6945c2d61c42bb7e818677f43638675b8c1c43e858b67a96df3eb2426a86c9d"}, - {file = "rpds_py-0.15.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02744236ac1895d7be837878e707a5c35fb8edc5137602f253b63623d7ad5c8c"}, - {file = "rpds_py-0.15.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2181e86d4e1cdf49a7320cb72a36c45efcb7670d0a88f09fd2d3a7967c0540fd"}, - {file = "rpds_py-0.15.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a8ff8e809da81363bffca2b965cb6e4bf6056b495fc3f078467d1f8266fe27f"}, - {file = "rpds_py-0.15.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:97532802f14d383f37d603a56e226909f825a83ff298dc1b6697de00d2243999"}, - {file = "rpds_py-0.15.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:13716e53627ad97babf72ac9e01cf9a7d4af2f75dd5ed7b323a7a9520e948282"}, - {file = "rpds_py-0.15.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:2f1f295a5c28cfa74a7d48c95acc1c8a7acd49d7d9072040d4b694fe11cd7166"}, - {file = "rpds_py-0.15.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8ec464f20fe803ae00419bd1610934e3bda963aeba1e6181dfc9033dc7e8940c"}, - {file = "rpds_py-0.15.2-cp311-none-win32.whl", hash = "sha256:b61d5096e75fd71018b25da50b82dd70ec39b5e15bb2134daf7eb7bbbc103644"}, - {file = "rpds_py-0.15.2-cp311-none-win_amd64.whl", hash = "sha256:9d41ebb471a6f064c0d1c873c4f7dded733d16ca5db7d551fb04ff3805d87802"}, - {file = "rpds_py-0.15.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:13ff62d3561a23c17341b4afc78e8fcfd799ab67c0b1ca32091d71383a98ba4b"}, - {file = "rpds_py-0.15.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b70b45a40ad0798b69748b34d508259ef2bdc84fb2aad4048bc7c9cafb68ddb3"}, - {file = "rpds_py-0.15.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4ecbba7efd82bd2a4bb88aab7f984eb5470991c1347bdd1f35fb34ea28dba6e"}, - {file = "rpds_py-0.15.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9d38494a8d21c246c535b41ecdb2d562c4b933cf3d68de03e8bc43a0d41be652"}, - {file = "rpds_py-0.15.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:13152dfe7d7c27c40df8b99ac6aab12b978b546716e99f67e8a67a1d441acbc3"}, - {file = "rpds_py-0.15.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:164fcee32f15d04d61568c9cb0d919e37ff3195919cd604039ff3053ada0461b"}, - {file = "rpds_py-0.15.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a5122b17a4faf5d7a6d91fa67b479736c0cacc7afe791ddebb7163a8550b799"}, - {file = "rpds_py-0.15.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:46b4f3d47d1033db569173be62365fbf7808c2bd3fb742314d251f130d90d44c"}, - {file = "rpds_py-0.15.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c61e42b4ceb9759727045765e87d51c1bb9f89987aca1fcc8a040232138cad1c"}, - {file = "rpds_py-0.15.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d2aa3ca9552f83b0b4fa6ca8c6ce08da6580f37e3e0ab7afac73a1cfdc230c0e"}, - {file = "rpds_py-0.15.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ec19e823b4ccd87bd69e990879acbce9e961fc7aebe150156b8f4418d4b27b7f"}, - {file = "rpds_py-0.15.2-cp312-none-win32.whl", hash = "sha256:afeabb382c1256a7477b739820bce7fe782bb807d82927102cee73e79b41b38b"}, - {file = "rpds_py-0.15.2-cp312-none-win_amd64.whl", hash = "sha256:422b0901878a31ef167435c5ad46560362891816a76cc0d150683f3868a6f0d1"}, - {file = "rpds_py-0.15.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:baf744e5f9d5ee6531deea443be78b36ed1cd36c65a0b95ea4e8d69fa0102268"}, - {file = "rpds_py-0.15.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7e072f5da38d6428ba1fc1115d3cc0dae895df671cb04c70c019985e8c7606be"}, - {file = "rpds_py-0.15.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f138f550b83554f5b344d6be35d3ed59348510edc3cb96f75309db6e9bfe8210"}, - {file = "rpds_py-0.15.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b2a4cd924d0e2f4b1a68034abe4cadc73d69ad5f4cf02db6481c0d4d749f548f"}, - {file = "rpds_py-0.15.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5eb05b654a41e0f81ab27a7c3e88b6590425eb3e934e1d533ecec5dc88a6ffff"}, - {file = "rpds_py-0.15.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2ee066a64f0d2ba45391cac15b3a70dcb549e968a117bd0500634754cfe0e5fc"}, - {file = "rpds_py-0.15.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c51a899792ee2c696072791e56b2020caff58b275abecbc9ae0cb71af0645c95"}, - {file = "rpds_py-0.15.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ac2ac84a4950d627d84b61f082eba61314373cfab4b3c264b62efab02ababe83"}, - {file = "rpds_py-0.15.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:62b292fff4739c6be89e6a0240c02bda5a9066a339d90ab191cf66e9fdbdc193"}, - {file = "rpds_py-0.15.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:98ee201a52a7f65608e5494518932e1473fd43535f12cade0a1b4ab32737fe28"}, - {file = "rpds_py-0.15.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:3d40fb3ca22e3d40f494d577441b263026a3bd8c97ae6ce89b2d3c4b39ac9581"}, - {file = "rpds_py-0.15.2-cp38-none-win32.whl", hash = "sha256:30479a9f1fce47df56b07460b520f49fa2115ec2926d3b1303c85c81f8401ed1"}, - {file = "rpds_py-0.15.2-cp38-none-win_amd64.whl", hash = "sha256:2df3d07a16a3bef0917b28cd564778fbb31f3ffa5b5e33584470e2d1b0f248f0"}, - {file = "rpds_py-0.15.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:56b51ba29a18e5f5810224bcf00747ad931c0716e3c09a76b4a1edd3d4aba71f"}, - {file = "rpds_py-0.15.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3c11bc5814554b018f6c5d6ae0969e43766f81e995000b53a5d8c8057055e886"}, - {file = "rpds_py-0.15.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2faa97212b0dc465afeedf49045cdd077f97be1188285e646a9f689cb5dfff9e"}, - {file = "rpds_py-0.15.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:86c01299942b0f4b5b5f28c8701689181ad2eab852e65417172dbdd6c5b3ccc8"}, - {file = "rpds_py-0.15.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd7d3608589072f63078b4063a6c536af832e76b0b3885f1bfe9e892abe6c207"}, - {file = "rpds_py-0.15.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:938518a11780b39998179d07f31a4a468888123f9b00463842cd40f98191f4d3"}, - {file = "rpds_py-0.15.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dccc623725d0b298f557d869a68496a2fd2a9e9c41107f234fa5f7a37d278ac"}, - {file = "rpds_py-0.15.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d46ee458452727a147d7897bb33886981ae1235775e05decae5d5d07f537695a"}, - {file = "rpds_py-0.15.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d9d7ebcd11ea76ba0feaae98485cd8e31467c3d7985210fab46983278214736b"}, - {file = "rpds_py-0.15.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:8a5f574b92b3ee7d254e56d56e37ec0e1416acb1ae357c4956d76a1788dc58fb"}, - {file = "rpds_py-0.15.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3db0c998c92b909d7c90b66c965590d4f3cd86157176a6cf14aa1f867b77b889"}, - {file = "rpds_py-0.15.2-cp39-none-win32.whl", hash = "sha256:bbc7421cbd28b4316d1d017db338039a7943f945c6f2bb15e1439b14b5682d28"}, - {file = "rpds_py-0.15.2-cp39-none-win_amd64.whl", hash = "sha256:1c24e30d720c0009b6fb2e1905b025da56103c70a8b31b99138e4ed1c2a6c5b0"}, - {file = "rpds_py-0.15.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1e6fcd0a0f62f2997107f758bb372397b8d5fd5f39cc6dcb86f7cb98a2172d6c"}, - {file = "rpds_py-0.15.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d800a8e2ac62db1b9ea5d6d1724f1a93c53907ca061de4d05ed94e8dfa79050c"}, - {file = "rpds_py-0.15.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e09d017e3f4d9bd7d17a30d3f59e4d6d9ba2d2ced280eec2425e84112cf623f"}, - {file = "rpds_py-0.15.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b88c3ab98556bc351b36d6208a6089de8c8db14a7f6e1f57f82a334bd2c18f0b"}, - {file = "rpds_py-0.15.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f333bfe782a2d05a67cfaa0cc9cd68b36b39ee6acfe099f980541ed973a7093"}, - {file = "rpds_py-0.15.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b629db53fe17e6ce478a969d30bd1d0e8b53238c46e3a9c9db39e8b65a9ef973"}, - {file = "rpds_py-0.15.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:485fbdd23becb822804ed05622907ee5c8e8a5f43f6f43894a45f463b2217045"}, - {file = "rpds_py-0.15.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:893e38d0f4319dfa70c0f36381a37cc418985c87b11d9784365b1fff4fa6973b"}, - {file = "rpds_py-0.15.2-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:8ffdeb7dbd0160d4e391e1f857477e4762d00aa2199c294eb95dfb9451aa1d9f"}, - {file = "rpds_py-0.15.2-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fc33267d58dfbb2361baed52668c5d8c15d24bc0372cecbb79fed77339b55e0d"}, - {file = "rpds_py-0.15.2-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:2e7e5633577b3bd56bf3af2ef6ae3778bbafb83743989d57f0e7edbf6c0980e4"}, - {file = "rpds_py-0.15.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:8b9650f92251fdef843e74fc252cdfd6e3c700157ad686eeb0c6d7fdb2d11652"}, - {file = "rpds_py-0.15.2-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:07a2e1d78d382f7181789713cdf0c16edbad4fe14fe1d115526cb6f0eef0daa3"}, - {file = "rpds_py-0.15.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03f9c5875515820633bd7709a25c3e60c1ea9ad1c5d4030ce8a8c203309c36fd"}, - {file = "rpds_py-0.15.2-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:580182fa5b269c2981e9ce9764367cb4edc81982ce289208d4607c203f44ffde"}, - {file = "rpds_py-0.15.2-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa1e626c524d2c7972c0f3a8a575d654a3a9c008370dc2a97e46abd0eaa749b9"}, - {file = "rpds_py-0.15.2-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ae9d83a81b09ce3a817e2cbb23aabc07f86a3abc664c613cd283ce7a03541e95"}, - {file = "rpds_py-0.15.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9235be95662559141934fced8197de6fee8c58870f36756b0584424b6d708393"}, - {file = "rpds_py-0.15.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a72e00826a2b032dda3eb25aa3e3579c6d6773d22d8446089a57a123481cc46c"}, - {file = "rpds_py-0.15.2-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:ab095edf1d840a6a6a4307e1a5b907a299a94e7b90e75436ee770b8c35d22a25"}, - {file = "rpds_py-0.15.2-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:3b79c63d29101cbaa53a517683557bb550462394fb91044cc5998dd2acff7340"}, - {file = "rpds_py-0.15.2-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:911e600e798374c0d86235e7ef19109cf865d1336942d398ff313375a25a93ba"}, - {file = "rpds_py-0.15.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3cd61e759c4075510052d1eca5cddbd297fe1164efec14ef1fce3f09b974dfe4"}, - {file = "rpds_py-0.15.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:9d2ae79f31da5143e020a8d4fc74e1f0cbcb8011bdf97453c140aa616db51406"}, - {file = "rpds_py-0.15.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e99d6510c8557510c220b865d966b105464740dcbebf9b79ecd4fbab30a13d9"}, - {file = "rpds_py-0.15.2-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6c43e1b89099279cc03eb1c725c5de12af6edcd2f78e2f8a022569efa639ada3"}, - {file = "rpds_py-0.15.2-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac7187bee72384b9cfedf09a29a3b2b6e8815cc64c095cdc8b5e6aec81e9fd5f"}, - {file = "rpds_py-0.15.2-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3423007fc0661827e06f8a185a3792c73dda41f30f3421562f210cf0c9e49569"}, - {file = "rpds_py-0.15.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2974e6dff38afafd5ccf8f41cb8fc94600b3f4fd9b0a98f6ece6e2219e3158d5"}, - {file = "rpds_py-0.15.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:93c18a1696a8e0388ed84b024fe1a188a26ba999b61d1d9a371318cb89885a8c"}, - {file = "rpds_py-0.15.2-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:c7cd0841a586b7105513a7c8c3d5c276f3adc762a072d81ef7fae80632afad1e"}, - {file = "rpds_py-0.15.2-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:709dc11af2f74ba89c68b1592368c6edcbccdb0a06ba77eb28c8fe08bb6997da"}, - {file = "rpds_py-0.15.2-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:fc066395e6332da1e7525d605b4c96055669f8336600bef8ac569d5226a7c76f"}, - {file = "rpds_py-0.15.2.tar.gz", hash = "sha256:373b76eeb79e8c14f6d82cb1d4d5293f9e4059baec6c1b16dca7ad13b6131b39"}, + {file = "rpds_py-0.16.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:509b617ac787cd1149600e731db9274ebbef094503ca25158e6f23edaba1ca8f"}, + {file = "rpds_py-0.16.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:413b9c17388bbd0d87a329d8e30c1a4c6e44e2bb25457f43725a8e6fe4161e9e"}, + {file = "rpds_py-0.16.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2946b120718eba9af2b4dd103affc1164a87b9e9ebff8c3e4c05d7b7a7e274e2"}, + {file = "rpds_py-0.16.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:35ae5ece284cf36464eb160880018cf6088a9ac5ddc72292a6092b6ef3f4da53"}, + {file = "rpds_py-0.16.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dc6a7620ba7639a3db6213da61312cb4aa9ac0ca6e00dc1cbbdc21c2aa6eb57"}, + {file = "rpds_py-0.16.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8cb6fe8ecdfffa0e711a75c931fb39f4ba382b4b3ccedeca43f18693864fe850"}, + {file = "rpds_py-0.16.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6dace7b26a13353e24613417ce2239491b40a6ad44e5776a18eaff7733488b44"}, + {file = "rpds_py-0.16.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1bdbc5fcb04a7309074de6b67fa9bc4b418ab3fc435fec1f2779a0eced688d04"}, + {file = "rpds_py-0.16.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f42e25c016927e2a6b1ce748112c3ab134261fc2ddc867e92d02006103e1b1b7"}, + {file = "rpds_py-0.16.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:eab36eae3f3e8e24b05748ec9acc66286662f5d25c52ad70cadab544e034536b"}, + {file = "rpds_py-0.16.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0474df4ade9a3b4af96c3d36eb81856cb9462e4c6657d4caecfd840d2a13f3c9"}, + {file = "rpds_py-0.16.2-cp310-none-win32.whl", hash = "sha256:84c5a4d1f9dd7e2d2c44097fb09fffe728629bad31eb56caf97719e55575aa82"}, + {file = "rpds_py-0.16.2-cp310-none-win_amd64.whl", hash = "sha256:2bd82db36cd70b3628c0c57d81d2438e8dd4b7b32a6a9f25f24ab0e657cb6c4e"}, + {file = "rpds_py-0.16.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:adc0c3d6fc6ae35fee3e4917628983f6ce630d513cbaad575b4517d47e81b4bb"}, + {file = "rpds_py-0.16.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ec23fcad480e77ede06cf4127a25fc440f7489922e17fc058f426b5256ee0edb"}, + {file = "rpds_py-0.16.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07aab64e2808c3ebac2a44f67e9dc0543812b715126dfd6fe4264df527556cb6"}, + {file = "rpds_py-0.16.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a4ebb8b20bd09c5ce7884c8f0388801100f5e75e7f733b1b6613c713371feefc"}, + {file = "rpds_py-0.16.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3d7e2ea25d3517c6d7e5a1cc3702cffa6bd18d9ef8d08d9af6717fc1c700eed"}, + {file = "rpds_py-0.16.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f28ac0e8e7242d140f99402a903a2c596ab71550272ae9247ad78f9a932b5698"}, + {file = "rpds_py-0.16.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19f00f57fdd38db4bb5ad09f9ead1b535332dbf624200e9029a45f1f35527ebb"}, + {file = "rpds_py-0.16.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3da5a4c56953bdbf6d04447c3410309616c54433146ccdb4a277b9cb499bc10e"}, + {file = "rpds_py-0.16.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ec2e1cf025b2c0f48ec17ff3e642661da7ee332d326f2e6619366ce8e221f018"}, + {file = "rpds_py-0.16.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e0441fb4fdd39a230477b2ca9be90868af64425bfe7b122b57e61e45737a653b"}, + {file = "rpds_py-0.16.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9f0350ef2fba5f34eb0c9000ea328e51b9572b403d2f7f3b19f24085f6f598e8"}, + {file = "rpds_py-0.16.2-cp311-none-win32.whl", hash = "sha256:5a80e2f83391ad0808b4646732af2a7b67550b98f0cae056cb3b40622a83dbb3"}, + {file = "rpds_py-0.16.2-cp311-none-win_amd64.whl", hash = "sha256:e04e56b4ca7a770593633556e8e9e46579d66ec2ada846b401252a2bdcf70a6d"}, + {file = "rpds_py-0.16.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:5e6caa3809e50690bd92fa490f5c38caa86082c8c3315aa438bce43786d5e90d"}, + {file = "rpds_py-0.16.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e53b9b25cac9065328901713a7e9e3b12e4f57ef4280b370fbbf6fef2052eef"}, + {file = "rpds_py-0.16.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af27423662f32d7501a00c5e7342f7dbd1e4a718aea7a239781357d15d437133"}, + {file = "rpds_py-0.16.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:43d4dd5fb16eb3825742bad8339d454054261ab59fed2fbac84e1d84d5aae7ba"}, + {file = "rpds_py-0.16.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e061de3b745fe611e23cd7318aec2c8b0e4153939c25c9202a5811ca911fd733"}, + {file = "rpds_py-0.16.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b811d182ad17ea294f2ec63c0621e7be92a1141e1012383461872cead87468f"}, + {file = "rpds_py-0.16.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5552f328eaef1a75ff129d4d0c437bf44e43f9436d3996e8eab623ea0f5fcf73"}, + {file = "rpds_py-0.16.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dcbe1f8dd179e4d69b70b1f1d9bb6fd1e7e1bdc9c9aad345cdeb332e29d40748"}, + {file = "rpds_py-0.16.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8aad80645a011abae487d356e0ceb359f4938dfb6f7bcc410027ed7ae4f7bb8b"}, + {file = "rpds_py-0.16.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b6f5549d6ed1da9bfe3631ca9483ae906f21410be2445b73443fa9f017601c6f"}, + {file = "rpds_py-0.16.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d452817e0d9c749c431a1121d56a777bd7099b720b3d1c820f1725cb40928f58"}, + {file = "rpds_py-0.16.2-cp312-none-win32.whl", hash = "sha256:888a97002e986eca10d8546e3c8b97da1d47ad8b69726dcfeb3e56348ebb28a3"}, + {file = "rpds_py-0.16.2-cp312-none-win_amd64.whl", hash = "sha256:d8dda2a806dfa4a9b795950c4f5cc56d6d6159f7d68080aedaff3bdc9b5032f5"}, + {file = "rpds_py-0.16.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:071980663c273bf3d388fe5c794c547e6f35ba3335477072c713a3176bf14a60"}, + {file = "rpds_py-0.16.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:726ac36e8a3bb8daef2fd482534cabc5e17334052447008405daca7ca04a3108"}, + {file = "rpds_py-0.16.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9e557db6a177470316c82f023e5d571811c9a4422b5ea084c85da9aa3c035fc"}, + {file = "rpds_py-0.16.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:90123853fc8b1747f80b0d354be3d122b4365a93e50fc3aacc9fb4c2488845d6"}, + {file = "rpds_py-0.16.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a61f659665a39a4d17d699ab3593d7116d66e1e2e3f03ef3fb8f484e91908808"}, + {file = "rpds_py-0.16.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc97f0640e91d7776530f06e6836c546c1c752a52de158720c4224c9e8053cad"}, + {file = "rpds_py-0.16.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44a54e99a2b9693a37ebf245937fd6e9228b4cbd64b9cc961e1f3391ec6c7391"}, + {file = "rpds_py-0.16.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd4b677d929cf1f6bac07ad76e0f2d5de367e6373351c01a9c0a39f6b21b4a8b"}, + {file = "rpds_py-0.16.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:5ef00873303d678aaf8b0627e111fd434925ca01c657dbb2641410f1cdaef261"}, + {file = "rpds_py-0.16.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:349cb40897fd529ca15317c22c0eab67f5ac5178b5bd2c6adc86172045210acc"}, + {file = "rpds_py-0.16.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:2ddef620e70eaffebed5932ce754d539c0930f676aae6212f8e16cd9743dd365"}, + {file = "rpds_py-0.16.2-cp38-none-win32.whl", hash = "sha256:882ce6e25e585949c3d9f9abd29202367175e0aab3aba0c58c9abbb37d4982ff"}, + {file = "rpds_py-0.16.2-cp38-none-win_amd64.whl", hash = "sha256:f4bd4578e44f26997e9e56c96dedc5f1af43cc9d16c4daa29c771a00b2a26851"}, + {file = "rpds_py-0.16.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:69ac7ea9897ec201ce68b48582f3eb34a3f9924488a5432a93f177bf76a82a7e"}, + {file = "rpds_py-0.16.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a9880b4656efe36ccad41edc66789e191e5ee19a1ea8811e0aed6f69851a82f4"}, + {file = "rpds_py-0.16.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee94cb58c0ba2c62ee108c2b7c9131b2c66a29e82746e8fa3aa1a1effbd3dcf1"}, + {file = "rpds_py-0.16.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:24f7a2eb3866a9e91f4599851e0c8d39878a470044875c49bd528d2b9b88361c"}, + {file = "rpds_py-0.16.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ca57468da2d9a660bcf8961637c85f2fbb2aa64d9bc3f9484e30c3f9f67b1dd7"}, + {file = "rpds_py-0.16.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ccd4e400309e1f34a5095bf9249d371f0fd60f8a3a5c4a791cad7b99ce1fd38d"}, + {file = "rpds_py-0.16.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80443fe2f7b3ea3934c5d75fb0e04a5dbb4a8e943e5ff2de0dec059202b70a8b"}, + {file = "rpds_py-0.16.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4d6a9f052e72d493efd92a77f861e45bab2f6be63e37fa8ecf0c6fd1a58fedb0"}, + {file = "rpds_py-0.16.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:35953f4f2b3216421af86fd236b7c0c65935936a94ea83ddbd4904ba60757773"}, + {file = "rpds_py-0.16.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:981d135c7cdaf6cd8eadae1c950de43b976de8f09d8e800feed307140d3d6d00"}, + {file = "rpds_py-0.16.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d0dd7ed2f16df2e129496e7fbe59a34bc2d7fc8db443a606644d069eb69cbd45"}, + {file = "rpds_py-0.16.2-cp39-none-win32.whl", hash = "sha256:703d95c75a72e902544fda08e965885525e297578317989fd15a6ce58414b41d"}, + {file = "rpds_py-0.16.2-cp39-none-win_amd64.whl", hash = "sha256:e93ec1b300acf89730cf27975ef574396bc04edecc358e9bd116fb387a123239"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:44627b6ca7308680a70766454db5249105fa6344853af6762eaad4158a2feebe"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:3f91df8e6dbb7360e176d1affd5fb0246d2b88d16aa5ebc7db94fd66b68b61da"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d904c5693e08bad240f16d79305edba78276be87061c872a4a15e2c301fa2c0"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:290a81cfbe4673285cdf140ec5cd1658ffbf63ab359f2b352ebe172e7cfa5bf0"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b634c5ec0103c5cbebc24ebac4872b045cccb9456fc59efdcf6fe39775365bd2"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a297a4d08cc67c7466c873c78039d87840fb50d05473db0ec1b7b03d179bf322"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2e75e17bd0bb66ee34a707da677e47c14ee51ccef78ed6a263a4cc965a072a1"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f1b9d9260e06ea017feb7172976ab261e011c1dc2f8883c7c274f6b2aabfe01a"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:162d7cd9cd311c1b0ff1c55a024b8f38bd8aad1876b648821da08adc40e95734"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:9b32f742ce5b57201305f19c2ef7a184b52f6f9ba6871cc042c2a61f0d6b49b8"}, + {file = "rpds_py-0.16.2-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac08472f41ea77cd6a5dae36ae7d4ed3951d6602833af87532b556c1b4601d63"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:495a14b72bbe217f2695dcd9b5ab14d4f8066a00f5d209ed94f0aca307f85f6e"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:8d6b6937ae9eac6d6c0ca3c42774d89fa311f55adff3970fb364b34abde6ed3d"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a61226465bda9283686db8f17d02569a98e4b13c637be5a26d44aa1f1e361c2"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5cf6af100ffb5c195beec11ffaa8cf8523057f123afa2944e6571d54da84cdc9"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6df15846ee3fb2e6397fe25d7ca6624af9f89587f3f259d177b556fed6bebe2c"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1be2f033df1b8be8c3167ba3c29d5dca425592ee31e35eac52050623afba5772"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96f957d6ab25a78b9e7fc9749d754b98eac825a112b4e666525ce89afcbd9ed5"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:088396c7c70e59872f67462fcac3ecbded5233385797021976a09ebd55961dfe"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:4c46ad6356e1561f2a54f08367d1d2e70a0a1bb2db2282d2c1972c1d38eafc3b"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:47713dc4fce213f5c74ca8a1f6a59b622fc1b90868deb8e8e4d993e421b4b39d"}, + {file = "rpds_py-0.16.2-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:f811771019f063bbd0aa7bb72c8a934bc13ebacb4672d712fc1639cfd314cccc"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f19afcfc0dd0dca35694df441e9b0f95bc231b512f51bded3c3d8ca32153ec19"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a4b682c5775d6a3d21e314c10124599976809455ee67020e8e72df1769b87bc3"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c647ca87fc0ebe808a41de912e9a1bfef9acb85257e5d63691364ac16b81c1f0"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:302bd4983bbd47063e452c38be66153760112f6d3635c7eeefc094299fa400a9"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bf721ede3eb7b829e4a9b8142bd55db0bdc82902720548a703f7e601ee13bdc3"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:358dafc89ce3894c7f486c615ba914609f38277ef67f566abc4c854d23b997fa"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cad0f59ee3dc35526039f4bc23642d52d5f6616b5f687d846bfc6d0d6d486db0"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cffa76b385dfe1e38527662a302b19ffb0e7f5cf7dd5e89186d2c94a22dd9d0c"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:83640a5d7cd3bff694747d50436b8b541b5b9b9782b0c8c1688931d6ee1a1f2d"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:ed99b4f7179d2111702020fd7d156e88acd533f5a7d3971353e568b6051d5c97"}, + {file = "rpds_py-0.16.2-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:4022b9dc620e14f30201a8a73898a873c8e910cb642bcd2f3411123bc527f6ac"}, + {file = "rpds_py-0.16.2.tar.gz", hash = "sha256:781ef8bfc091b19960fc0142a23aedadafa826bc32b433fdfe6fd7f964d7ef44"}, ] [[package]] @@ -3421,28 +3526,28 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.1.8" +version = "0.1.9" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.1.8-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7de792582f6e490ae6aef36a58d85df9f7a0cfd1b0d4fe6b4fb51803a3ac96fa"}, - {file = "ruff-0.1.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:c8e3255afd186c142eef4ec400d7826134f028a85da2146102a1172ecc7c3696"}, - {file = "ruff-0.1.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff78a7583020da124dd0deb835ece1d87bb91762d40c514ee9b67a087940528b"}, - {file = "ruff-0.1.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd8ee69b02e7bdefe1e5da2d5b6eaaddcf4f90859f00281b2333c0e3a0cc9cd6"}, - {file = "ruff-0.1.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a05b0ddd7ea25495e4115a43125e8a7ebed0aa043c3d432de7e7d6e8e8cd6448"}, - {file = "ruff-0.1.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:e6f08ca730f4dc1b76b473bdf30b1b37d42da379202a059eae54ec7fc1fbcfed"}, - {file = "ruff-0.1.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f35960b02df6b827c1b903091bb14f4b003f6cf102705efc4ce78132a0aa5af3"}, - {file = "ruff-0.1.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7d076717c67b34c162da7c1a5bda16ffc205e0e0072c03745275e7eab888719f"}, - {file = "ruff-0.1.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6a21ab023124eafb7cef6d038f835cb1155cd5ea798edd8d9eb2f8b84be07d9"}, - {file = "ruff-0.1.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ce697c463458555027dfb194cb96d26608abab920fa85213deb5edf26e026664"}, - {file = "ruff-0.1.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:db6cedd9ffed55548ab313ad718bc34582d394e27a7875b4b952c2d29c001b26"}, - {file = "ruff-0.1.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:05ffe9dbd278965271252704eddb97b4384bf58b971054d517decfbf8c523f05"}, - {file = "ruff-0.1.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5daaeaf00ae3c1efec9742ff294b06c3a2a9db8d3db51ee4851c12ad385cda30"}, - {file = "ruff-0.1.8-py3-none-win32.whl", hash = "sha256:e49fbdfe257fa41e5c9e13c79b9e79a23a79bd0e40b9314bc53840f520c2c0b3"}, - {file = "ruff-0.1.8-py3-none-win_amd64.whl", hash = "sha256:f41f692f1691ad87f51708b823af4bb2c5c87c9248ddd3191c8f088e66ce590a"}, - {file = "ruff-0.1.8-py3-none-win_arm64.whl", hash = "sha256:aa8ee4f8440023b0a6c3707f76cadce8657553655dcbb5fc9b2f9bb9bee389f6"}, - {file = "ruff-0.1.8.tar.gz", hash = "sha256:f7ee467677467526cfe135eab86a40a0e8db43117936ac4f9b469ce9cdb3fb62"}, + {file = "ruff-0.1.9-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e6a212f436122ac73df851f0cf006e0c6612fe6f9c864ed17ebefce0eff6a5fd"}, + {file = "ruff-0.1.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:28d920e319783d5303333630dae46ecc80b7ba294aeffedf946a02ac0b7cc3db"}, + {file = "ruff-0.1.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:104aa9b5e12cb755d9dce698ab1b97726b83012487af415a4512fedd38b1459e"}, + {file = "ruff-0.1.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1e63bf5a4a91971082a4768a0aba9383c12392d0d6f1e2be2248c1f9054a20da"}, + {file = "ruff-0.1.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4d0738917c203246f3e275b37006faa3aa96c828b284ebfe3e99a8cb413c8c4b"}, + {file = "ruff-0.1.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:69dac82d63a50df2ab0906d97a01549f814b16bc806deeac4f064ff95c47ddf5"}, + {file = "ruff-0.1.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2aec598fb65084e41a9c5d4b95726173768a62055aafb07b4eff976bac72a592"}, + {file = "ruff-0.1.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:744dfe4b35470fa3820d5fe45758aace6269c578f7ddc43d447868cfe5078bcb"}, + {file = "ruff-0.1.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:479ca4250cab30f9218b2e563adc362bd6ae6343df7c7b5a7865300a5156d5a6"}, + {file = "ruff-0.1.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:aa8344310f1ae79af9ccd6e4b32749e93cddc078f9b5ccd0e45bd76a6d2e8bb6"}, + {file = "ruff-0.1.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:837c739729394df98f342319f5136f33c65286b28b6b70a87c28f59354ec939b"}, + {file = "ruff-0.1.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:e6837202c2859b9f22e43cb01992373c2dbfeae5c0c91ad691a4a2e725392464"}, + {file = "ruff-0.1.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:331aae2cd4a0554667ac683243b151c74bd60e78fb08c3c2a4ac05ee1e606a39"}, + {file = "ruff-0.1.9-py3-none-win32.whl", hash = "sha256:8151425a60878e66f23ad47da39265fc2fad42aed06fb0a01130e967a7a064f4"}, + {file = "ruff-0.1.9-py3-none-win_amd64.whl", hash = "sha256:c497d769164df522fdaf54c6eba93f397342fe4ca2123a2e014a5b8fc7df81c7"}, + {file = "ruff-0.1.9-py3-none-win_arm64.whl", hash = "sha256:0e17f53bcbb4fff8292dfd84cf72d767b5e146f009cccd40c2fad27641f8a7a9"}, + {file = "ruff-0.1.9.tar.gz", hash = "sha256:b041dee2734719ddbb4518f762c982f2e912e7f28b8ee4fe1dee0b15d1b6e800"}, ] [[package]] @@ -3533,13 +3638,13 @@ tests = ["coverage[toml] (>=5.0.2)", "pytest"] [[package]] name = "setuptools" -version = "69.0.2" +version = "69.0.3" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-69.0.2-py3-none-any.whl", hash = "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"}, - {file = "setuptools-69.0.2.tar.gz", hash = "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6"}, + {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"}, + {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"}, ] [package.extras] @@ -3623,18 +3728,18 @@ pbr = ">=2.0.0,<2.1.0 || >2.1.0" [[package]] name = "structlog" -version = "23.2.0" +version = "23.3.0" description = "Structured Logging for Python" optional = false python-versions = ">=3.8" files = [ - {file = "structlog-23.2.0-py3-none-any.whl", hash = "sha256:16a167e87b9fa7fae9a972d5d12805ef90e04857a93eba479d4be3801a6a1482"}, - {file = "structlog-23.2.0.tar.gz", hash = "sha256:334666b94707f89dbc4c81a22a8ccd34449f0201d5b1ee097a030b577fa8c858"}, + {file = "structlog-23.3.0-py3-none-any.whl", hash = "sha256:d6922a88ceabef5b13b9eda9c4043624924f60edbb00397f4d193bd754cde60a"}, + {file = "structlog-23.3.0.tar.gz", hash = "sha256:24b42b914ac6bc4a4e6f716e82ac70d7fb1e8c3b1035a765591953bfc37101a5"}, ] [package.extras] dev = ["structlog[tests,typing]"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "twisted"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-mermaid", "sphinxext-opengraph", "twisted"] tests = ["freezegun (>=0.2.8)", "pretend", "pytest (>=6.0)", "pytest-asyncio (>=0.17)", "simplejson"] typing = ["mypy (>=1.4)", "rich", "twisted"] @@ -3832,13 +3937,13 @@ files = [ [[package]] name = "tzdata" -version = "2023.3" +version = "2023.4" description = "Provider of IANA time zone data" optional = false python-versions = ">=2" files = [ - {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, - {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"}, + {file = "tzdata-2023.4-py2.py3-none-any.whl", hash = "sha256:aa3ace4329eeacda5b7beb7ea08ece826c28d761cda36e747cfbf97996d39bf3"}, + {file = "tzdata-2023.4.tar.gz", hash = "sha256:dd54c94f294765522c77399649b4fefd95522479a664a0cec87f41bebc6148c9"}, ] [[package]] @@ -3884,13 +3989,13 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "uvicorn" -version = "0.24.0.post1" +version = "0.25.0" description = "The lightning-fast ASGI server." optional = false python-versions = ">=3.8" files = [ - {file = "uvicorn-0.24.0.post1-py3-none-any.whl", hash = "sha256:7c84fea70c619d4a710153482c0d230929af7bcf76c7bfa6de151f0a3a80121e"}, - {file = "uvicorn-0.24.0.post1.tar.gz", hash = "sha256:09c8e5a79dc466bdf28dead50093957db184de356fcdc48697bad3bde4c2588e"}, + {file = "uvicorn-0.25.0-py3-none-any.whl", hash = "sha256:ce107f5d9bd02b4636001a77a4e74aab5e1e2b146868ebbad565237145af444c"}, + {file = "uvicorn-0.25.0.tar.gz", hash = "sha256:6dddbad1d7ee0f5140aba5ec138ddc9612c5109399903828b4874c9937f009c2"}, ] [package.dependencies] @@ -4437,4 +4542,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "~3.12" -content-hash = "d0fe6ae1be389f8a5ca5112aa90555e2ce0a4f336f07a1da9c43dd521e9d9340" +content-hash = "9d28b9e79139895839ffcba88e2eaad0f842a15888f3f6f8c0ac8879616ac850" diff --git a/pyproject.toml b/pyproject.toml index aa5851881..d26428045 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -145,7 +145,12 @@ geoip2 = "*" gunicorn = "*" kubernetes = "*" ldap3 = "*" -lxml = "*" +lxml = [ + # 5.0.0 works with libxml2 2.11.x, which is standard on brew + { version = "5.0.0", platform = "darwin" }, + # 4.9.x works with previous libxml2 versions, which is what we get on linux + { version = "4.9.4", platform = "linux" }, +] opencontainers = { extras = ["reggie"], version = "*" } packaging = "*" paramiko = "*" diff --git a/tests/e2e/test_provider_ldap.py b/tests/e2e/test_provider_ldap.py index aa12587ab..aad5e7826 100644 --- a/tests/e2e/test_provider_ldap.py +++ b/tests/e2e/test_provider_ldap.py @@ -1,8 +1,6 @@ """LDAP and Outpost e2e tests""" from dataclasses import asdict -from sys import platform from time import sleep -from unittest.case import skipUnless from docker.client import DockerClient, from_env from docker.models.containers import Container @@ -14,13 +12,13 @@ from authentik.blueprints.tests import apply_blueprint, reconcile_app from authentik.core.models import Application, User from authentik.events.models import Event, EventAction from authentik.flows.models import Flow +from authentik.lib.generators import generate_id from authentik.outposts.apps import MANAGED_OUTPOST from authentik.outposts.models import Outpost, OutpostConfig, OutpostType from authentik.providers.ldap.models import APIAccessMode, LDAPProvider from tests.e2e.utils import SeleniumTestCase, retry -@skipUnless(platform.startswith("linux"), "requires local docker") class TestProviderLDAP(SeleniumTestCase): """LDAP and Outpost e2e tests""" @@ -37,7 +35,10 @@ class TestProviderLDAP(SeleniumTestCase): container = client.containers.run( image=self.get_container_image("ghcr.io/goauthentik/dev-ldap"), detach=True, - network_mode="host", + ports={ + "3389": "3389", + "6636": "6636", + }, environment={ "AUTHENTIK_HOST": self.live_server_url, "AUTHENTIK_TOKEN": outpost.token.key, @@ -51,15 +52,15 @@ class TestProviderLDAP(SeleniumTestCase): self.user.save() ldap: LDAPProvider = LDAPProvider.objects.create( - name="ldap_provider", + name=generate_id(), authorization_flow=Flow.objects.get(slug="default-authentication-flow"), search_group=self.user.ak_groups.first(), search_mode=APIAccessMode.CACHED, ) # we need to create an application to actually access the ldap - Application.objects.create(name="ldap", slug="ldap", provider=ldap) + Application.objects.create(name=generate_id(), slug=generate_id(), provider=ldap) outpost: Outpost = Outpost.objects.create( - name="ldap_outpost", + name=generate_id(), type=OutpostType.LDAP, _config=asdict(OutpostConfig(log_level="debug")), ) diff --git a/tests/e2e/test_provider_oauth2_github.py b/tests/e2e/test_provider_oauth2_github.py index 7df12137b..5e19dd146 100644 --- a/tests/e2e/test_provider_oauth2_github.py +++ b/tests/e2e/test_provider_oauth2_github.py @@ -1,8 +1,6 @@ """test OAuth Provider flow""" -from sys import platform from time import sleep from typing import Any, Optional -from unittest.case import skipUnless from docker.types import Healthcheck from selenium.webdriver.common.by import By @@ -18,7 +16,6 @@ from authentik.providers.oauth2.models import ClientTypes, OAuth2Provider from tests.e2e.utils import SeleniumTestCase, retry -@skipUnless(platform.startswith("linux"), "requires local docker") class TestProviderOAuth2Github(SeleniumTestCase): """test OAuth Provider flow""" @@ -32,7 +29,9 @@ class TestProviderOAuth2Github(SeleniumTestCase): return { "image": "grafana/grafana:7.1.0", "detach": True, - "network_mode": "host", + "ports": { + "3000": "3000", + }, "auto_remove": True, "healthcheck": Healthcheck( test=["CMD", "wget", "--spider", "http://localhost:3000"], diff --git a/tests/e2e/test_provider_oauth2_grafana.py b/tests/e2e/test_provider_oauth2_grafana.py index fdb75e1b9..2538fae70 100644 --- a/tests/e2e/test_provider_oauth2_grafana.py +++ b/tests/e2e/test_provider_oauth2_grafana.py @@ -1,8 +1,6 @@ """test OAuth2 OpenID Provider flow""" -from sys import platform from time import sleep from typing import Any, Optional -from unittest.case import skipUnless from docker.types import Healthcheck from selenium.webdriver.common.by import By @@ -24,7 +22,6 @@ from authentik.providers.oauth2.models import ClientTypes, OAuth2Provider, Scope from tests.e2e.utils import SeleniumTestCase, retry -@skipUnless(platform.startswith("linux"), "requires local docker") class TestProviderOAuth2OAuth(SeleniumTestCase): """test OAuth with OAuth Provider flow""" @@ -38,13 +35,15 @@ class TestProviderOAuth2OAuth(SeleniumTestCase): return { "image": "grafana/grafana:7.1.0", "detach": True, - "network_mode": "host", "auto_remove": True, "healthcheck": Healthcheck( test=["CMD", "wget", "--spider", "http://localhost:3000"], interval=5 * 1_000 * 1_000_000, start_period=1 * 1_000 * 1_000_000, ), + "ports": { + "3000": "3000", + }, "environment": { "GF_AUTH_GENERIC_OAUTH_ENABLED": "true", "GF_AUTH_GENERIC_OAUTH_CLIENT_ID": self.client_id, diff --git a/tests/e2e/test_provider_oidc.py b/tests/e2e/test_provider_oidc.py index 23cbd1412..3180f9534 100644 --- a/tests/e2e/test_provider_oidc.py +++ b/tests/e2e/test_provider_oidc.py @@ -1,8 +1,6 @@ """test OAuth2 OpenID Provider flow""" from json import loads -from sys import platform from time import sleep -from unittest.case import skipUnless from docker import DockerClient, from_env from docker.models.containers import Container @@ -25,7 +23,6 @@ from authentik.providers.oauth2.models import ClientTypes, OAuth2Provider, Scope from tests.e2e.utils import SeleniumTestCase, retry -@skipUnless(platform.startswith("linux"), "requires local docker") class TestProviderOAuth2OIDC(SeleniumTestCase): """test OAuth with OpenID Provider flow""" @@ -36,13 +33,15 @@ class TestProviderOAuth2OIDC(SeleniumTestCase): super().setUp() def setup_client(self) -> Container: - """Setup client saml-sp container which we test SAML against""" + """Setup client oidc-test-client container which we test OIDC against""" sleep(1) client: DockerClient = from_env() container = client.containers.run( image="ghcr.io/beryju/oidc-test-client:1.3", detach=True, - network_mode="host", + ports={ + "9009": "9009", + }, environment={ "OIDC_CLIENT_ID": self.client_id, "OIDC_CLIENT_SECRET": self.client_secret, diff --git a/tests/e2e/test_provider_oidc_implicit.py b/tests/e2e/test_provider_oidc_implicit.py index e952d4e18..c5d9d37d0 100644 --- a/tests/e2e/test_provider_oidc_implicit.py +++ b/tests/e2e/test_provider_oidc_implicit.py @@ -1,8 +1,6 @@ """test OAuth2 OpenID Provider flow""" from json import loads -from sys import platform from time import sleep -from unittest.case import skipUnless from docker import DockerClient, from_env from docker.models.containers import Container @@ -25,7 +23,6 @@ from authentik.providers.oauth2.models import ClientTypes, OAuth2Provider, Scope from tests.e2e.utils import SeleniumTestCase, retry -@skipUnless(platform.startswith("linux"), "requires local docker") class TestProviderOAuth2OIDCImplicit(SeleniumTestCase): """test OAuth with OpenID Provider flow""" @@ -36,13 +33,15 @@ class TestProviderOAuth2OIDCImplicit(SeleniumTestCase): super().setUp() def setup_client(self) -> Container: - """Setup client saml-sp container which we test SAML against""" + """Setup client oidc-test-client container which we test OIDC against""" sleep(1) client: DockerClient = from_env() container = client.containers.run( image="ghcr.io/beryju/oidc-test-client:1.3", detach=True, - network_mode="host", + ports={ + "9009": "9009", + }, environment={ "OIDC_CLIENT_ID": self.client_id, "OIDC_CLIENT_SECRET": self.client_secret, diff --git a/tests/e2e/test_provider_proxy.py b/tests/e2e/test_provider_proxy.py index c8484c205..e91e80666 100644 --- a/tests/e2e/test_provider_proxy.py +++ b/tests/e2e/test_provider_proxy.py @@ -21,7 +21,6 @@ from authentik.providers.proxy.models import ProxyProvider from tests.e2e.utils import SeleniumTestCase, retry -@skipUnless(platform.startswith("linux"), "requires local docker") class TestProviderProxy(SeleniumTestCase): """Proxy and Outpost e2e tests""" @@ -36,7 +35,9 @@ class TestProviderProxy(SeleniumTestCase): return { "image": "traefik/whoami:latest", "detach": True, - "network_mode": "host", + "ports": { + "80": "80", + }, "auto_remove": True, } @@ -46,7 +47,9 @@ class TestProviderProxy(SeleniumTestCase): container = client.containers.run( image=self.get_container_image("ghcr.io/goauthentik/dev-proxy"), detach=True, - network_mode="host", + ports={ + "9000": "9000", + }, environment={ "AUTHENTIK_HOST": self.live_server_url, "AUTHENTIK_TOKEN": outpost.token.key, @@ -78,7 +81,7 @@ class TestProviderProxy(SeleniumTestCase): authorization_flow=Flow.objects.get( slug="default-provider-authorization-implicit-consent" ), - internal_host="http://localhost", + internal_host=f"http://{self.host}", external_host="http://localhost:9000", ) # Ensure OAuth2 Params are set @@ -145,7 +148,7 @@ class TestProviderProxy(SeleniumTestCase): authorization_flow=Flow.objects.get( slug="default-provider-authorization-implicit-consent" ), - internal_host="http://localhost", + internal_host=f"http://{self.host}", external_host="http://localhost:9000", basic_auth_enabled=True, basic_auth_user_attribute="basic-username", diff --git a/tests/e2e/test_provider_radius.py b/tests/e2e/test_provider_radius.py index e711e5103..b4856e034 100644 --- a/tests/e2e/test_provider_radius.py +++ b/tests/e2e/test_provider_radius.py @@ -1,8 +1,6 @@ """Radius e2e tests""" from dataclasses import asdict -from sys import platform from time import sleep -from unittest.case import skipUnless from docker.client import DockerClient, from_env from docker.models.containers import Container @@ -19,7 +17,6 @@ from authentik.providers.radius.models import RadiusProvider from tests.e2e.utils import SeleniumTestCase, retry -@skipUnless(platform.startswith("linux"), "requires local docker") class TestProviderRadius(SeleniumTestCase): """Radius Outpost e2e tests""" @@ -40,7 +37,7 @@ class TestProviderRadius(SeleniumTestCase): container = client.containers.run( image=self.get_container_image("ghcr.io/goauthentik/dev-radius"), detach=True, - network_mode="host", + ports={"1812/udp": "1812/udp"}, environment={ "AUTHENTIK_HOST": self.live_server_url, "AUTHENTIK_TOKEN": outpost.token.key, diff --git a/tests/e2e/test_provider_saml.py b/tests/e2e/test_provider_saml.py index 9252ab0c0..eefb2c45e 100644 --- a/tests/e2e/test_provider_saml.py +++ b/tests/e2e/test_provider_saml.py @@ -1,8 +1,6 @@ """test SAML Provider flow""" from json import loads -from sys import platform from time import sleep -from unittest.case import skipUnless from docker import DockerClient, from_env from docker.models.containers import Container @@ -20,7 +18,6 @@ from authentik.sources.saml.processors.constants import SAML_BINDING_POST from tests.e2e.utils import SeleniumTestCase, retry -@skipUnless(platform.startswith("linux"), "requires local docker") class TestProviderSAML(SeleniumTestCase): """test SAML Provider flow""" @@ -41,7 +38,9 @@ class TestProviderSAML(SeleniumTestCase): container = client.containers.run( image="ghcr.io/beryju/saml-test-sp:1.1", detach=True, - network_mode="host", + ports={ + "9009": "9009", + }, environment={ "SP_ENTITY_ID": provider.issuer, "SP_SSO_BINDING": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST", diff --git a/tests/e2e/test_source_oauth_oauth1.py b/tests/e2e/test_source_oauth_oauth1.py new file mode 100644 index 000000000..97152321f --- /dev/null +++ b/tests/e2e/test_source_oauth_oauth1.py @@ -0,0 +1,141 @@ +"""test OAuth Source""" +from time import sleep +from typing import Any, Optional + +from selenium.webdriver.common.by import By +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.support import expected_conditions as ec +from selenium.webdriver.support.wait import WebDriverWait + +from authentik.blueprints.tests import apply_blueprint +from authentik.core.models import User +from authentik.flows.models import Flow +from authentik.lib.generators import generate_id, generate_key +from authentik.sources.oauth.models import OAuthSource +from authentik.sources.oauth.types.registry import SourceType, registry +from authentik.sources.oauth.views.callback import OAuthCallback +from authentik.stages.identification.models import IdentificationStage +from tests.e2e.utils import SeleniumTestCase, retry + + +class OAuth1Callback(OAuthCallback): + """OAuth1 Callback with custom getters""" + + def get_user_id(self, info: dict[str, str]) -> str: + return info.get("id") + + def get_user_enroll_context( + self, + info: dict[str, Any], + ) -> dict[str, Any]: + return { + "username": info.get("screen_name"), + "email": info.get("email"), + "name": info.get("name"), + } + + +@registry.register() +class OAUth1Type(SourceType): + """OAuth1 Type definition""" + + callback_view = OAuth1Callback + verbose_name = "OAuth1" + name = "oauth1" + + request_token_url = "http://localhost:5001/oauth/request_token" # nosec + access_token_url = "http://localhost:5001/oauth/access_token" # nosec + authorization_url = "http://localhost:5001/oauth/authorize" + profile_url = "http://localhost:5001/api/me" + urls_customizable = False + + +class TestSourceOAuth1(SeleniumTestCase): + """Test OAuth1 Source""" + + def setUp(self) -> None: + self.client_id = generate_id() + self.client_secret = generate_key() + self.source_slug = generate_id() + super().setUp() + + def get_container_specs(self) -> Optional[dict[str, Any]]: + return { + "image": "ghcr.io/beryju/oauth1-test-server:v1.1", + "detach": True, + "ports": {"5000": "5001"}, + "auto_remove": True, + "environment": { + "OAUTH1_CLIENT_ID": self.client_id, + "OAUTH1_CLIENT_SECRET": self.client_secret, + "OAUTH1_REDIRECT_URI": self.url( + "authentik_sources_oauth:oauth-client-callback", + source_slug=self.source_slug, + ), + }, + } + + def create_objects(self): + """Create required objects""" + # Bootstrap all needed objects + authentication_flow = Flow.objects.get(slug="default-source-authentication") + enrollment_flow = Flow.objects.get(slug="default-source-enrollment") + + source = OAuthSource.objects.create( # nosec + name=generate_id(), + slug=self.source_slug, + authentication_flow=authentication_flow, + enrollment_flow=enrollment_flow, + provider_type="oauth1", + consumer_key=self.client_id, + consumer_secret=self.client_secret, + ) + ident_stage = IdentificationStage.objects.first() + ident_stage.sources.set([source]) + ident_stage.save() + + @retry() + @apply_blueprint( + "default/flow-default-authentication-flow.yaml", + "default/flow-default-invalidation-flow.yaml", + ) + @apply_blueprint( + "default/flow-default-source-authentication.yaml", + "default/flow-default-source-enrollment.yaml", + "default/flow-default-source-pre-authentication.yaml", + ) + def test_oauth_enroll(self): + """test OAuth Source With With OIDC""" + self.create_objects() + self.driver.get(self.live_server_url) + + flow_executor = self.get_shadow_root("ak-flow-executor") + identification_stage = self.get_shadow_root("ak-stage-identification", flow_executor) + wait = WebDriverWait(identification_stage, self.wait_timeout) + + wait.until( + ec.presence_of_element_located( + (By.CSS_SELECTOR, ".pf-c-login__main-footer-links-item > button") + ) + ) + identification_stage.find_element( + By.CSS_SELECTOR, ".pf-c-login__main-footer-links-item > button" + ).click() + + # Now we should be at the IDP, wait for the login field + self.wait.until(ec.presence_of_element_located((By.NAME, "username"))) + self.driver.find_element(By.NAME, "username").send_keys("example-user") + self.driver.find_element(By.NAME, "username").send_keys(Keys.ENTER) + sleep(2) + + # Wait until we're logged in + self.wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "[name='confirm']"))) + self.driver.find_element(By.CSS_SELECTOR, "[name='confirm']").click() + + # Wait until we've loaded the user info page + sleep(2) + # Wait until we've logged in + self.wait_for_url(self.if_user_url("/library")) + self.driver.get(self.if_user_url("/settings")) + + self.assert_user(User(username="example-user", name="test name", email="foo@example.com")) diff --git a/tests/e2e/test_source_oauth.py b/tests/e2e/test_source_oauth_oauth2.py similarity index 62% rename from tests/e2e/test_source_oauth.py rename to tests/e2e/test_source_oauth_oauth2.py index c7f0fd881..17a26279e 100644 --- a/tests/e2e/test_source_oauth.py +++ b/tests/e2e/test_source_oauth_oauth2.py @@ -1,9 +1,7 @@ """test OAuth Source""" from pathlib import Path -from sys import platform from time import sleep from typing import Any, Optional -from unittest.case import skipUnless from docker.models.containers import Container from docker.types import Healthcheck @@ -18,47 +16,12 @@ from authentik.core.models import User from authentik.flows.models import Flow from authentik.lib.generators import generate_id, generate_key from authentik.sources.oauth.models import OAuthSource -from authentik.sources.oauth.types.registry import SourceType, registry -from authentik.sources.oauth.views.callback import OAuthCallback from authentik.stages.identification.models import IdentificationStage from tests.e2e.utils import SeleniumTestCase, retry CONFIG_PATH = "/tmp/dex.yml" # nosec -class OAuth1Callback(OAuthCallback): - """OAuth1 Callback with custom getters""" - - def get_user_id(self, info: dict[str, str]) -> str: - return info.get("id") - - def get_user_enroll_context( - self, - info: dict[str, Any], - ) -> dict[str, Any]: - return { - "username": info.get("screen_name"), - "email": info.get("email"), - "name": info.get("name"), - } - - -@registry.register() -class OAUth1Type(SourceType): - """OAuth1 Type definition""" - - callback_view = OAuth1Callback - name = "OAuth1" - slug = "oauth1" - - request_token_url = "http://localhost:5000/oauth/request_token" # nosec - access_token_url = "http://localhost:5000/oauth/access_token" # nosec - authorization_url = "http://localhost:5000/oauth/authorize" - profile_url = "http://localhost:5000/api/me" - urls_customizable = False - - -@skipUnless(platform.startswith("linux"), "requires local docker") class TestSourceOAuth2(SeleniumTestCase): """test OAuth Source flow""" @@ -66,6 +29,7 @@ class TestSourceOAuth2(SeleniumTestCase): def setUp(self): self.client_secret = generate_key() + self.slug = generate_id() self.prepare_dex_config() super().setUp() @@ -83,7 +47,7 @@ class TestSourceOAuth2(SeleniumTestCase): "redirectURIs": [ self.url( "authentik_sources_oauth:oauth-client-callback", - source_slug="dex", + source_slug=self.slug, ) ], "secret": self.client_secret, @@ -108,7 +72,7 @@ class TestSourceOAuth2(SeleniumTestCase): return { "image": "ghcr.io/dexidp/dex:v2.28.1", "detach": True, - "network_mode": "host", + "ports": {"5556": "5556"}, "auto_remove": True, "command": "dex serve /config.yml", "healthcheck": Healthcheck( @@ -126,8 +90,8 @@ class TestSourceOAuth2(SeleniumTestCase): enrollment_flow = Flow.objects.get(slug="default-source-enrollment") source = OAuthSource.objects.create( # nosec - name="dex", - slug="dex", + name=generate_id(), + slug=self.slug, authentication_flow=authentication_flow, enrollment_flow=enrollment_flow, provider_type="openidconnect", @@ -229,95 +193,3 @@ class TestSourceOAuth2(SeleniumTestCase): self.driver.get(self.if_user_url("/settings")) self.assert_user(User(username="foo", name="admin", email="admin@example.com")) - - -@skipUnless(platform.startswith("linux"), "requires local docker") -class TestSourceOAuth1(SeleniumTestCase): - """Test OAuth1 Source""" - - def setUp(self) -> None: - self.client_id = generate_id() - self.client_secret = generate_key() - self.source_slug = "oauth1-test" - super().setUp() - - def get_container_specs(self) -> Optional[dict[str, Any]]: - return { - "image": "ghcr.io/beryju/oauth1-test-server:v1.1", - "detach": True, - "network_mode": "host", - "auto_remove": True, - "environment": { - "OAUTH1_CLIENT_ID": self.client_id, - "OAUTH1_CLIENT_SECRET": self.client_secret, - "OAUTH1_REDIRECT_URI": self.url( - "authentik_sources_oauth:oauth-client-callback", - source_slug=self.source_slug, - ), - }, - } - - def create_objects(self): - """Create required objects""" - # Bootstrap all needed objects - authentication_flow = Flow.objects.get(slug="default-source-authentication") - enrollment_flow = Flow.objects.get(slug="default-source-enrollment") - - source = OAuthSource.objects.create( # nosec - name="oauth1", - slug=self.source_slug, - authentication_flow=authentication_flow, - enrollment_flow=enrollment_flow, - provider_type="oauth1", - consumer_key=self.client_id, - consumer_secret=self.client_secret, - ) - ident_stage = IdentificationStage.objects.first() - ident_stage.sources.set([source]) - ident_stage.save() - - @retry() - @apply_blueprint( - "default/flow-default-authentication-flow.yaml", - "default/flow-default-invalidation-flow.yaml", - ) - @apply_blueprint( - "default/flow-default-source-authentication.yaml", - "default/flow-default-source-enrollment.yaml", - "default/flow-default-source-pre-authentication.yaml", - ) - def test_oauth_enroll(self): - """test OAuth Source With With OIDC""" - self.create_objects() - self.driver.get(self.live_server_url) - - flow_executor = self.get_shadow_root("ak-flow-executor") - identification_stage = self.get_shadow_root("ak-stage-identification", flow_executor) - wait = WebDriverWait(identification_stage, self.wait_timeout) - - wait.until( - ec.presence_of_element_located( - (By.CSS_SELECTOR, ".pf-c-login__main-footer-links-item > button") - ) - ) - identification_stage.find_element( - By.CSS_SELECTOR, ".pf-c-login__main-footer-links-item > button" - ).click() - - # Now we should be at the IDP, wait for the login field - self.wait.until(ec.presence_of_element_located((By.NAME, "username"))) - self.driver.find_element(By.NAME, "username").send_keys("example-user") - self.driver.find_element(By.NAME, "username").send_keys(Keys.ENTER) - sleep(2) - - # Wait until we're logged in - self.wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, "[name='confirm']"))) - self.driver.find_element(By.CSS_SELECTOR, "[name='confirm']").click() - - # Wait until we've loaded the user info page - sleep(2) - # Wait until we've logged in - self.wait_for_url(self.if_user_url("/library")) - self.driver.get(self.if_user_url("/settings")) - - self.assert_user(User(username="example-user", name="test name", email="foo@example.com")) diff --git a/tests/e2e/test_source_saml.py b/tests/e2e/test_source_saml.py index 0921335b7..2051b56a1 100644 --- a/tests/e2e/test_source_saml.py +++ b/tests/e2e/test_source_saml.py @@ -1,8 +1,6 @@ """test SAML Source""" -from sys import platform from time import sleep from typing import Any, Optional -from unittest.case import skipUnless from docker.types import Healthcheck from guardian.utils import get_anonymous_user @@ -15,6 +13,7 @@ from authentik.blueprints.tests import apply_blueprint from authentik.core.models import User from authentik.crypto.models import CertificateKeyPair from authentik.flows.models import Flow +from authentik.lib.generators import generate_id from authentik.sources.saml.models import SAMLBindingTypes, SAMLSource from authentik.stages.identification.models import IdentificationStage from tests.e2e.utils import SeleniumTestCase, retry @@ -71,15 +70,18 @@ Sm75WXsflOxuTn08LbgGc4s= -----END PRIVATE KEY-----""" -@skipUnless(platform.startswith("linux"), "requires local docker") class TestSourceSAML(SeleniumTestCase): """test SAML Source flow""" + def setUp(self): + self.slug = generate_id() + super().setUp() + def get_container_specs(self) -> Optional[dict[str, Any]]: return { "image": "kristophjunge/test-saml-idp:1.15", "detach": True, - "network_mode": "host", + "ports": {"8080": "8080"}, "auto_remove": True, "healthcheck": Healthcheck( test=["CMD", "curl", "http://localhost:8080"], @@ -89,7 +91,7 @@ class TestSourceSAML(SeleniumTestCase): "environment": { "SIMPLESAMLPHP_SP_ENTITY_ID": "entity-id", "SIMPLESAMLPHP_SP_ASSERTION_CONSUMER_SERVICE": ( - f"{self.live_server_url}/source/saml/saml-idp-test/acs/" + self.url("authentik_sources_saml:acs", source_slug=self.slug) ), }, } @@ -111,19 +113,19 @@ class TestSourceSAML(SeleniumTestCase): enrollment_flow = Flow.objects.get(slug="default-source-enrollment") pre_authentication_flow = Flow.objects.get(slug="default-source-pre-authentication") keypair = CertificateKeyPair.objects.create( - name="test-idp-cert", + name=generate_id(), certificate_data=IDP_CERT, key_data=IDP_KEY, ) source = SAMLSource.objects.create( - name="saml-idp-test", - slug="saml-idp-test", + name=generate_id(), + slug=self.slug, authentication_flow=authentication_flow, enrollment_flow=enrollment_flow, pre_authentication_flow=pre_authentication_flow, issuer="entity-id", - sso_url="http://localhost:8080/simplesaml/saml2/idp/SSOService.php", + sso_url=f"http://{self.host}:8080/simplesaml/saml2/idp/SSOService.php", binding_type=SAMLBindingTypes.REDIRECT, signing_kp=keypair, ) @@ -181,19 +183,19 @@ class TestSourceSAML(SeleniumTestCase): enrollment_flow = Flow.objects.get(slug="default-source-enrollment") pre_authentication_flow = Flow.objects.get(slug="default-source-pre-authentication") keypair = CertificateKeyPair.objects.create( - name="test-idp-cert", + name=generate_id(), certificate_data=IDP_CERT, key_data=IDP_KEY, ) source = SAMLSource.objects.create( - name="saml-idp-test", - slug="saml-idp-test", + name=generate_id(), + slug=self.slug, authentication_flow=authentication_flow, enrollment_flow=enrollment_flow, pre_authentication_flow=pre_authentication_flow, issuer="entity-id", - sso_url="http://localhost:8080/simplesaml/saml2/idp/SSOService.php", + sso_url=f"http://{self.host}:8080/simplesaml/saml2/idp/SSOService.php", binding_type=SAMLBindingTypes.POST, signing_kp=keypair, ) @@ -264,19 +266,19 @@ class TestSourceSAML(SeleniumTestCase): enrollment_flow = Flow.objects.get(slug="default-source-enrollment") pre_authentication_flow = Flow.objects.get(slug="default-source-pre-authentication") keypair = CertificateKeyPair.objects.create( - name="test-idp-cert", + name=generate_id(), certificate_data=IDP_CERT, key_data=IDP_KEY, ) source = SAMLSource.objects.create( - name="saml-idp-test", - slug="saml-idp-test", + name=generate_id(), + slug=self.slug, authentication_flow=authentication_flow, enrollment_flow=enrollment_flow, pre_authentication_flow=pre_authentication_flow, issuer="entity-id", - sso_url="http://localhost:8080/simplesaml/saml2/idp/SSOService.php", + sso_url=f"http://{self.host}:8080/simplesaml/saml2/idp/SSOService.php", binding_type=SAMLBindingTypes.POST_AUTO, signing_kp=keypair, ) diff --git a/tests/e2e/utils.py b/tests/e2e/utils.py index 7092ac4e9..a7a813448 100644 --- a/tests/e2e/utils.py +++ b/tests/e2e/utils.py @@ -1,6 +1,7 @@ """authentik e2e testing utilities""" import json import os +import socket from functools import lru_cache, wraps from os import environ from sys import stderr @@ -43,6 +44,13 @@ def get_docker_tag() -> str: return f"gh-{branch_name}" +def get_local_ip() -> str: + """Get the local machine's IP""" + hostname = socket.gethostname() + ip_addr = socket.gethostbyname(hostname) + return ip_addr + + class DockerTestCase: """Mixin for dealing with containers""" @@ -63,6 +71,7 @@ class DockerTestCase: class SeleniumTestCase(DockerTestCase, StaticLiveServerTestCase): """StaticLiveServerTestCase which automatically creates a Webdriver instance""" + host = get_local_ip() container: Optional[Container] = None wait_timeout: int user: User From 23e8fc5a496e292b67dd15561b777fab59d41a47 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 21:13:04 +0100 Subject: [PATCH 19/31] web: bump rollup from 4.9.1 to 4.9.2 in /web (#8031) Bumps [rollup](https://github.com/rollup/rollup) from 4.9.1 to 4.9.2. - [Release notes](https://github.com/rollup/rollup/releases) - [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md) - [Commits](https://github.com/rollup/rollup/compare/v4.9.1...v4.9.2) --- updated-dependencies: - dependency-name: rollup dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- web/package-lock.json | 112 +++++++++++++++++++++--------------------- web/package.json | 2 +- 2 files changed, 57 insertions(+), 57 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index e4ccbd389..239027d1b 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -92,7 +92,7 @@ "pyright": "=1.1.338", "react": "^18.2.0", "react-dom": "^18.2.0", - "rollup": "^4.9.1", + "rollup": "^4.9.2", "rollup-plugin-copy": "^3.5.0", "rollup-plugin-cssimport": "^1.0.3", "rollup-plugin-modify": "^3.0.0", @@ -4585,9 +4585,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.1.tgz", - "integrity": "sha512-6vMdBZqtq1dVQ4CWdhFwhKZL6E4L1dV6jUjuBvsavvNJSppzi6dLBbuV+3+IyUREaj9ZFvQefnQm28v4OCXlig==", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.2.tgz", + "integrity": "sha512-RKzxFxBHq9ysZ83fn8Iduv3A283K7zPPYuhL/z9CQuyFrjwpErJx0h4aeb/bnJ+q29GRLgJpY66ceQ/Wcsn3wA==", "cpu": [ "arm" ], @@ -4598,9 +4598,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.1.tgz", - "integrity": "sha512-Jto9Fl3YQ9OLsTDWtLFPtaIMSL2kwGyGoVCmPC8Gxvym9TCZm4Sie+cVeblPO66YZsYH8MhBKDMGZ2NDxuk/XQ==", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.2.tgz", + "integrity": "sha512-yZ+MUbnwf3SHNWQKJyWh88ii2HbuHCFQnAYTeeO1Nb8SyEiWASEi5dQUygt3ClHWtA9My9RQAYkjvrsZ0WK8Xg==", "cpu": [ "arm64" ], @@ -4611,9 +4611,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.1.tgz", - "integrity": "sha512-LtYcLNM+bhsaKAIGwVkh5IOWhaZhjTfNOkGzGqdHvhiCUVuJDalvDxEdSnhFzAn+g23wgsycmZk1vbnaibZwwA==", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.2.tgz", + "integrity": "sha512-vqJ/pAUh95FLc/G/3+xPqlSBgilPnauVf2EXOQCZzhZJCXDXt/5A8mH/OzU6iWhb3CNk5hPJrh8pqJUPldN5zw==", "cpu": [ "arm64" ], @@ -4624,9 +4624,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.1.tgz", - "integrity": "sha512-KyP/byeXu9V+etKO6Lw3E4tW4QdcnzDG/ake031mg42lob5tN+5qfr+lkcT/SGZaH2PdW4Z1NX9GHEkZ8xV7og==", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.2.tgz", + "integrity": "sha512-otPHsN5LlvedOprd3SdfrRNhOahhVBwJpepVKUN58L0RnC29vOAej1vMEaVU6DadnpjivVsNTM5eNt0CcwTahw==", "cpu": [ "x64" ], @@ -4637,9 +4637,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.1.tgz", - "integrity": "sha512-Yqz/Doumf3QTKplwGNrCHe/B2p9xqDghBZSlAY0/hU6ikuDVQuOUIpDP/YcmoT+447tsZTmirmjgG3znvSCR0Q==", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.2.tgz", + "integrity": "sha512-ewG5yJSp+zYKBYQLbd1CUA7b1lSfIdo9zJShNTyc2ZP1rcPrqyZcNlsHgs7v1zhgfdS+kW0p5frc0aVqhZCiYQ==", "cpu": [ "arm" ], @@ -4650,9 +4650,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.1.tgz", - "integrity": "sha512-u3XkZVvxcvlAOlQJ3UsD1rFvLWqu4Ef/Ggl40WAVCuogf4S1nJPHh5RTgqYFpCOvuGJ7H5yGHabjFKEZGExk5Q==", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.2.tgz", + "integrity": "sha512-pL6QtV26W52aCWTG1IuFV3FMPL1m4wbsRG+qijIvgFO/VBsiXJjDPE/uiMdHBAO6YcpV4KvpKtd0v3WFbaxBtg==", "cpu": [ "arm64" ], @@ -4663,9 +4663,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.1.tgz", - "integrity": "sha512-0XSYN/rfWShW+i+qjZ0phc6vZ7UWI8XWNz4E/l+6edFt+FxoEghrJHjX1EY/kcUGCnZzYYRCl31SNdfOi450Aw==", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.2.tgz", + "integrity": "sha512-On+cc5EpOaTwPSNetHXBuqylDW+765G/oqB9xGmWU3npEhCh8xu0xqHGUA+4xwZLqBbIZNcBlKSIYfkBm6ko7g==", "cpu": [ "arm64" ], @@ -4676,9 +4676,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.1.tgz", - "integrity": "sha512-LmYIO65oZVfFt9t6cpYkbC4d5lKHLYv5B4CSHRpnANq0VZUQXGcCPXHzbCXCz4RQnx7jvlYB1ISVNCE/omz5cw==", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.2.tgz", + "integrity": "sha512-Wnx/IVMSZ31D/cO9HSsU46FjrPWHqtdF8+0eyZ1zIB5a6hXaZXghUKpRrC4D5DcRTZOjml2oBhXoqfGYyXKipw==", "cpu": [ "riscv64" ], @@ -4689,9 +4689,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.1.tgz", - "integrity": "sha512-kr8rEPQ6ns/Lmr/hiw8sEVj9aa07gh1/tQF2Y5HrNCCEPiCBGnBUt9tVusrcBBiJfIt1yNaXN6r1CCmpbFEDpg==", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.2.tgz", + "integrity": "sha512-ym5x1cj4mUAMBummxxRkI4pG5Vht1QMsJexwGP8547TZ0sox9fCLDHw9KCH9c1FO5d9GopvkaJsBIOkTKxksdw==", "cpu": [ "x64" ], @@ -4702,9 +4702,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.1.tgz", - "integrity": "sha512-t4QSR7gN+OEZLG0MiCgPqMWZGwmeHhsM4AkegJ0Kiy6TnJ9vZ8dEIwHw1LcZKhbHxTY32hp9eVCMdR3/I8MGRw==", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.2.tgz", + "integrity": "sha512-m0hYELHGXdYx64D6IDDg/1vOJEaiV8f1G/iO+tejvRCJNSwK4jJ15e38JQy5Q6dGkn1M/9KcyEOwqmlZ2kqaZg==", "cpu": [ "x64" ], @@ -4715,9 +4715,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.1.tgz", - "integrity": "sha512-7XI4ZCBN34cb+BH557FJPmh0kmNz2c25SCQeT9OiFWEgf8+dL6ZwJ8f9RnUIit+j01u07Yvrsuu1rZGxJCc51g==", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.2.tgz", + "integrity": "sha512-x1CWburlbN5JjG+juenuNa4KdedBdXLjZMp56nHFSHTOsb/MI2DYiGzLtRGHNMyydPGffGId+VgjOMrcltOksA==", "cpu": [ "arm64" ], @@ -4728,9 +4728,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.1.tgz", - "integrity": "sha512-yE5c2j1lSWOH5jp+Q0qNL3Mdhr8WuqCNVjc6BxbVfS5cAS6zRmdiw7ktb8GNpDCEUJphILY6KACoFoRtKoqNQg==", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.2.tgz", + "integrity": "sha512-VVzCB5yXR1QlfsH1Xw1zdzQ4Pxuzv+CPr5qpElpKhVxlxD3CRdfubAG9mJROl6/dmj5gVYDDWk8sC+j9BI9/kQ==", "cpu": [ "ia32" ], @@ -4741,9 +4741,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.1.tgz", - "integrity": "sha512-PyJsSsafjmIhVgaI1Zdj7m8BB8mMckFah/xbpplObyHfiXzKcI5UOUXRyOdHW7nz4DpMCuzLnF7v5IWHenCwYA==", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.2.tgz", + "integrity": "sha512-SYRedJi+mweatroB+6TTnJYLts0L0bosg531xnQWtklOI6dezEagx4Q0qDyvRdK+qgdA3YZpjjGuPFtxBmddBA==", "cpu": [ "x64" ], @@ -16310,9 +16310,9 @@ "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" }, "node_modules/rollup": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.1.tgz", - "integrity": "sha512-pgPO9DWzLoW/vIhlSoDByCzcpX92bKEorbgXuZrqxByte3JFk2xSW2JEeAcyLc9Ru9pqcNNW+Ob7ntsk2oT/Xw==", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.2.tgz", + "integrity": "sha512-66RB8OtFKUTozmVEh3qyNfH+b+z2RXBVloqO2KCC/pjFaGaHtxP9fVfOQKPSGXg2mElmjmxjW/fZ7iKrEpMH5Q==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -16322,19 +16322,19 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.9.1", - "@rollup/rollup-android-arm64": "4.9.1", - "@rollup/rollup-darwin-arm64": "4.9.1", - "@rollup/rollup-darwin-x64": "4.9.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.9.1", - "@rollup/rollup-linux-arm64-gnu": "4.9.1", - "@rollup/rollup-linux-arm64-musl": "4.9.1", - "@rollup/rollup-linux-riscv64-gnu": "4.9.1", - "@rollup/rollup-linux-x64-gnu": "4.9.1", - "@rollup/rollup-linux-x64-musl": "4.9.1", - "@rollup/rollup-win32-arm64-msvc": "4.9.1", - "@rollup/rollup-win32-ia32-msvc": "4.9.1", - "@rollup/rollup-win32-x64-msvc": "4.9.1", + "@rollup/rollup-android-arm-eabi": "4.9.2", + "@rollup/rollup-android-arm64": "4.9.2", + "@rollup/rollup-darwin-arm64": "4.9.2", + "@rollup/rollup-darwin-x64": "4.9.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.9.2", + "@rollup/rollup-linux-arm64-gnu": "4.9.2", + "@rollup/rollup-linux-arm64-musl": "4.9.2", + "@rollup/rollup-linux-riscv64-gnu": "4.9.2", + "@rollup/rollup-linux-x64-gnu": "4.9.2", + "@rollup/rollup-linux-x64-musl": "4.9.2", + "@rollup/rollup-win32-arm64-msvc": "4.9.2", + "@rollup/rollup-win32-ia32-msvc": "4.9.2", + "@rollup/rollup-win32-x64-msvc": "4.9.2", "fsevents": "~2.3.2" } }, diff --git a/web/package.json b/web/package.json index 6a55bfc87..58e5c623c 100644 --- a/web/package.json +++ b/web/package.json @@ -117,7 +117,7 @@ "pyright": "=1.1.338", "react": "^18.2.0", "react-dom": "^18.2.0", - "rollup": "^4.9.1", + "rollup": "^4.9.2", "rollup-plugin-copy": "^3.5.0", "rollup-plugin-cssimport": "^1.0.3", "rollup-plugin-modify": "^3.0.0", From 4cd9b99de737c34d7819d1a167e0888bf5e36287 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 21:13:11 +0100 Subject: [PATCH 20/31] web: bump the esbuild group in /web with 2 updates (#8029) Bumps the esbuild group in /web with 2 updates: [@esbuild/darwin-arm64](https://github.com/evanw/esbuild) and [@esbuild/linux-arm64](https://github.com/evanw/esbuild). Updates `@esbuild/darwin-arm64` from 0.19.10 to 0.19.11 - [Release notes](https://github.com/evanw/esbuild/releases) - [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md) - [Commits](https://github.com/evanw/esbuild/compare/v0.19.10...v0.19.11) Updates `@esbuild/linux-arm64` from 0.19.10 to 0.19.11 - [Release notes](https://github.com/evanw/esbuild/releases) - [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md) - [Commits](https://github.com/evanw/esbuild/compare/v0.19.10...v0.19.11) --- updated-dependencies: - dependency-name: "@esbuild/darwin-arm64" dependency-type: direct:production update-type: version-update:semver-patch dependency-group: esbuild - dependency-name: "@esbuild/linux-arm64" dependency-type: direct:production update-type: version-update:semver-patch dependency-group: esbuild ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- web/package-lock.json | 17 +++++++++-------- web/package.json | 4 ++-- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 239027d1b..63e3a76aa 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -15,6 +15,7 @@ "@codemirror/lang-xml": "^6.0.2", "@codemirror/legacy-modes": "^6.3.3", "@codemirror/theme-one-dark": "^6.1.2", + "@esbuild/linux-arm64": "^0.19.11", "@formatjs/intl-listformat": "^7.5.3", "@fortawesome/fontawesome-free": "^6.5.1", "@goauthentik/api": "^2023.10.5-1703968412", @@ -109,9 +110,9 @@ "node": ">=20" }, "optionalDependencies": { - "@esbuild/darwin-arm64": "^0.19.10", + "@esbuild/darwin-arm64": "^0.19.11", "@esbuild/linux-amd64": "^0.18.11", - "@esbuild/linux-arm64": "^0.19.10" + "@esbuild/linux-arm64": "^0.19.11" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -2436,9 +2437,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.10.tgz", - "integrity": "sha512-YSRRs2zOpwypck+6GL3wGXx2gNP7DXzetmo5pHXLrY/VIMsS59yKfjPizQ4lLt5vEI80M41gjm2BxrGZ5U+VMA==", + "version": "0.19.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.11.tgz", + "integrity": "sha512-ETp87DRWuSt9KdDVkqSoKoLFHYTrkyz2+65fj9nfXsaV3bMhTCjtQfw3y+um88vGRKRiF7erPrh/ZuIdLUIVxQ==", "cpu": [ "arm64" ], @@ -2515,9 +2516,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.19.10", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.10.tgz", - "integrity": "sha512-QxaouHWZ+2KWEj7cGJmvTIHVALfhpGxo3WLmlYfJ+dA5fJB6lDEIg+oe/0//FuyVHuS3l79/wyBxbHr0NgtxJQ==", + "version": "0.19.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.11.tgz", + "integrity": "sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg==", "cpu": [ "arm64" ], diff --git a/web/package.json b/web/package.json index 58e5c623c..fee401974 100644 --- a/web/package.json +++ b/web/package.json @@ -131,9 +131,9 @@ "vite-tsconfig-paths": "^4.2.3" }, "optionalDependencies": { - "@esbuild/darwin-arm64": "^0.19.10", + "@esbuild/darwin-arm64": "^0.19.11", "@esbuild/linux-amd64": "^0.18.11", - "@esbuild/linux-arm64": "^0.19.10" + "@esbuild/linux-arm64": "^0.19.11" }, "engines": { "node": ">=20" From bdb5abaab0405df26666ad368ddbec57c37d4ab7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 21:13:22 +0100 Subject: [PATCH 21/31] web: bump the babel group in /web with 4 updates (#8028) Bumps the babel group in /web with 4 updates: [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core), [@babel/plugin-proposal-decorators](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-proposal-decorators), [@babel/plugin-transform-runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-runtime) and [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env). Updates `@babel/core` from 7.23.6 to 7.23.7 - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.23.7/packages/babel-core) Updates `@babel/plugin-proposal-decorators` from 7.23.6 to 7.23.7 - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.23.7/packages/babel-plugin-proposal-decorators) Updates `@babel/plugin-transform-runtime` from 7.23.6 to 7.23.7 - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.23.7/packages/babel-plugin-transform-runtime) Updates `@babel/preset-env` from 7.23.6 to 7.23.7 - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.23.7/packages/babel-preset-env) --- updated-dependencies: - dependency-name: "@babel/core" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: babel - dependency-name: "@babel/plugin-proposal-decorators" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: babel - dependency-name: "@babel/plugin-transform-runtime" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: babel - dependency-name: "@babel/preset-env" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: babel ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- web/package-lock.json | 135 +++++++++++++++++++++--------------------- web/package.json | 8 +-- 2 files changed, 70 insertions(+), 73 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 63e3a76aa..8ba596075 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -45,13 +45,13 @@ "yaml": "^2.3.4" }, "devDependencies": { - "@babel/core": "^7.23.6", + "@babel/core": "^7.23.7", "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/plugin-proposal-decorators": "^7.23.6", + "@babel/plugin-proposal-decorators": "^7.23.7", "@babel/plugin-transform-private-methods": "^7.23.3", "@babel/plugin-transform-private-property-in-object": "^7.23.4", - "@babel/plugin-transform-runtime": "^7.23.6", - "@babel/preset-env": "^7.23.6", + "@babel/plugin-transform-runtime": "^7.23.7", + "@babel/preset-env": "^7.23.7", "@babel/preset-typescript": "^7.23.3", "@hcaptcha/types": "^1.0.3", "@jackfranklin/rollup-plugin-markdown": "^0.4.0", @@ -180,9 +180,9 @@ } }, "node_modules/@babel/core": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.6.tgz", - "integrity": "sha512-FxpRyGjrMJXh7X3wGLGhNDCRiwpWEF74sKjTLDJSG5Kyvow3QZaG0Adbqzi9ZrVjTWpsX+2cxWXD71NMg93kdw==", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz", + "integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", @@ -190,10 +190,10 @@ "@babel/generator": "^7.23.6", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.6", + "@babel/helpers": "^7.23.7", "@babel/parser": "^7.23.6", "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.6", + "@babel/traverse": "^7.23.7", "@babel/types": "^7.23.6", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -210,9 +210,9 @@ } }, "node_modules/@babel/core/node_modules/@babel/traverse": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.6.tgz", - "integrity": "sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.7.tgz", + "integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==", "dev": true, "dependencies": { "@babel/code-frame": "^7.23.5", @@ -292,9 +292,9 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.6.tgz", - "integrity": "sha512-cBXU1vZni/CpGF29iTu4YRbOZt3Wat6zCoMDxRF1MayiEc4URxOj31tT65HUM0CRpMowA3HCJaAOVOUnMf96cw==", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.7.tgz", + "integrity": "sha512-xCoqR/8+BoNnXOY7RVSgv6X+o7pmT5q1d+gGcRlXYkI+9B31glE4jeejhKVpA04O1AtzOt7OSQ6VYKP5FcRl9g==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.22.5", @@ -332,9 +332,9 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.3.tgz", - "integrity": "sha512-WBrLmuPP47n7PNwsZ57pqam6G/RGo1vw/87b0Blc53tZNGZ4x7YvZ6HgQe2vo1W/FR20OgjeZuGXzudPiXHFug==", + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.4.tgz", + "integrity": "sha512-QcJMILQCu2jm5TFPGA3lCpJJTeEP+mqeXooG/NZbg/h5FTFi6V0+99ahlRsW8/kRLyb24LZVCCiclDedhLKcBA==", "dev": true, "dependencies": { "@babel/helper-compilation-targets": "^7.22.6", @@ -557,13 +557,13 @@ } }, "node_modules/@babel/helpers": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.6.tgz", - "integrity": "sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA==", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.7.tgz", + "integrity": "sha512-6AMnjCoC8wjqBzDHkuqpa7jAKwvMo4dC+lr/TFBz+ucfulO1XMpDnwWPGBNwClOKZ8h6xn5N81W/R5OrcKtCbQ==", "dev": true, "dependencies": { "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.6", + "@babel/traverse": "^7.23.7", "@babel/types": "^7.23.6" }, "engines": { @@ -571,9 +571,9 @@ } }, "node_modules/@babel/helpers/node_modules/@babel/traverse": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.6.tgz", - "integrity": "sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.7.tgz", + "integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==", "dev": true, "dependencies": { "@babel/code-frame": "^7.23.5", @@ -650,9 +650,9 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.3.tgz", - "integrity": "sha512-XaJak1qcityzrX0/IU5nKHb34VaibwP3saKqG6a/tppelgllOH13LUann4ZCIBcVOeE6H18K4Vx9QKkVww3z/w==", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.7.tgz", + "integrity": "sha512-LlRT7HgaifEpQA1ZgLVOIJZZFVPWN5iReq/7/JixwBtwcoeVGDBD53ZV28rrsLYOZs1Y/EHhA8N/Z6aazHR8cw==", "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", @@ -683,16 +683,13 @@ } }, "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.23.6.tgz", - "integrity": "sha512-D7Ccq9LfkBFnow3azZGJvZYgcfeqAw3I1e5LoTpj6UKIFQilh8yqXsIGcRIqbBdsPWIz+Ze7ZZfggSj62Qp+Fg==", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.23.7.tgz", + "integrity": "sha512-b1s5JyeMvqj7d9m9KhJNHKc18gEJiSyVzVX3bwbiPalQBQpuvfPh6lA9F7Kk/dWH0TIiXRpB9yicwijY6buPng==", "dev": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.23.6", + "@babel/helper-create-class-features-plugin": "^7.23.7", "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.20", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", "@babel/plugin-syntax-decorators": "^7.23.3" }, "engines": { @@ -1025,9 +1022,9 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.4.tgz", - "integrity": "sha512-efdkfPhHYTtn0G6n2ddrESE91fgXxjlqLsnUtPWnJs4a4mZIbUaK7ffqKIIUKXSHwcDvaCVX6GXkaJJFqtX7jw==", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.7.tgz", + "integrity": "sha512-PdxEpL71bJp1byMG0va5gwQcXHxuEYC/BgI/e88mGTtohbZN28O5Yit0Plkkm/dBzCF/BxmbNcses1RH1T+urA==", "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", @@ -1660,16 +1657,16 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.23.6.tgz", - "integrity": "sha512-kF1Zg62aPseQ11orDhFRw+aPG/eynNQtI+TyY+m33qJa2cJ5EEvza2P2BNTIA9E5MyqFABHEyY6CPHwgdy9aNg==", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.23.7.tgz", + "integrity": "sha512-fa0hnfmiXc9fq/weK34MUV0drz2pOL/vfKWvN7Qw127hiUPabFCUMgAbYWcchRzMJit4o5ARsK/s+5h0249pLw==", "dev": true, "dependencies": { "@babel/helper-module-imports": "^7.22.15", "@babel/helper-plugin-utils": "^7.22.5", - "babel-plugin-polyfill-corejs2": "^0.4.6", - "babel-plugin-polyfill-corejs3": "^0.8.5", - "babel-plugin-polyfill-regenerator": "^0.5.3", + "babel-plugin-polyfill-corejs2": "^0.4.7", + "babel-plugin-polyfill-corejs3": "^0.8.7", + "babel-plugin-polyfill-regenerator": "^0.5.4", "semver": "^6.3.1" }, "engines": { @@ -1837,9 +1834,9 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.6.tgz", - "integrity": "sha512-2XPn/BqKkZCpzYhUUNZ1ssXw7DcXfKQEjv/uXZUXgaebCMYmkEsfZ2yY+vv+xtXv50WmL5SGhyB6/xsWxIvvOQ==", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.7.tgz", + "integrity": "sha512-SY27X/GtTz/L4UryMNJ6p4fH4nsgWbz84y9FE0bQeWJP6O5BhgVCt53CotQKHCOeXJel8VyhlhujhlltKms/CA==", "dev": true, "dependencies": { "@babel/compat-data": "^7.23.5", @@ -1848,7 +1845,7 @@ "@babel/helper-validator-option": "^7.23.5", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.3", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.7", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", @@ -1869,7 +1866,7 @@ "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.23.3", - "@babel/plugin-transform-async-generator-functions": "^7.23.4", + "@babel/plugin-transform-async-generator-functions": "^7.23.7", "@babel/plugin-transform-async-to-generator": "^7.23.3", "@babel/plugin-transform-block-scoped-functions": "^7.23.3", "@babel/plugin-transform-block-scoping": "^7.23.4", @@ -1917,9 +1914,9 @@ "@babel/plugin-transform-unicode-regex": "^7.23.3", "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.6", - "babel-plugin-polyfill-corejs3": "^0.8.5", - "babel-plugin-polyfill-regenerator": "^0.5.3", + "babel-plugin-polyfill-corejs2": "^0.4.7", + "babel-plugin-polyfill-corejs3": "^0.8.7", + "babel-plugin-polyfill-regenerator": "^0.5.4", "core-js-compat": "^3.31.0", "semver": "^6.3.1" }, @@ -8364,13 +8361,13 @@ } }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.6.tgz", - "integrity": "sha512-jhHiWVZIlnPbEUKSSNb9YoWcQGdlTLq7z1GHL4AjFxaoOUMuuEVJ+Y4pAaQUGOGk93YsVCKPbqbfw3m0SM6H8Q==", + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.7.tgz", + "integrity": "sha512-LidDk/tEGDfuHW2DWh/Hgo4rmnw3cduK6ZkOI1NPFceSK3n/yAGeOsNT7FLnSGHkXj3RHGSEVkN3FsCTY6w2CQ==", "dev": true, "dependencies": { "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.4.3", + "@babel/helper-define-polyfill-provider": "^0.4.4", "semver": "^6.3.1" }, "peerDependencies": { @@ -8378,25 +8375,25 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.5.tgz", - "integrity": "sha512-Q6CdATeAvbScWPNLB8lzSO7fgUVBkQt6zLgNlfyeCr/EQaEQR+bWiBYYPYAFyE528BMjRhL+1QBMOI4jc/c5TA==", + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.7.tgz", + "integrity": "sha512-KyDvZYxAzkC0Aj2dAPyDzi2Ym15e5JKZSK+maI7NAwSqofvuFglbSsxE7wUOvTg9oFVnHMzVzBKcqEb4PJgtOA==", "dev": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.4.3", - "core-js-compat": "^3.32.2" + "@babel/helper-define-polyfill-provider": "^0.4.4", + "core-js-compat": "^3.33.1" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.3.tgz", - "integrity": "sha512-8sHeDOmXC8csczMrYEOf0UTNa4yE2SxV5JGeT/LP1n0OYVDUUFPxG9vdk2AlDlIit4t+Kf0xCtpgXPBwnn/9pw==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.4.tgz", + "integrity": "sha512-S/x2iOCvDaCASLYsOOgWOq4bCfKYVqvO/uxjkaYyZ3rVsVE3CeAI/c84NpyuBBymEgNvHgjEot3a9/Z/kXvqsg==", "dev": true, "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.4.3" + "@babel/helper-define-polyfill-provider": "^0.4.4" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -9215,12 +9212,12 @@ } }, "node_modules/core-js-compat": { - "version": "3.32.2", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.32.2.tgz", - "integrity": "sha512-+GjlguTDINOijtVRUxrQOv3kfu9rl+qPNdX2LTbJ/ZyVTuxK+ksVSAGX1nHstu4hrv1En/uPTtWgq2gI5wt4AQ==", + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.35.0.tgz", + "integrity": "sha512-5blwFAddknKeNgsjBzilkdQ0+YK8L1PfqPYq40NOYMYFSS38qj+hpTcLLWwpIwA2A5bje/x5jmVn2tzUMg9IVw==", "dev": true, "dependencies": { - "browserslist": "^4.21.10" + "browserslist": "^4.22.2" }, "funding": { "type": "opencollective", diff --git a/web/package.json b/web/package.json index fee401974..ed7681155 100644 --- a/web/package.json +++ b/web/package.json @@ -69,13 +69,13 @@ "yaml": "^2.3.4" }, "devDependencies": { - "@babel/core": "^7.23.6", + "@babel/core": "^7.23.7", "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/plugin-proposal-decorators": "^7.23.6", + "@babel/plugin-proposal-decorators": "^7.23.7", "@babel/plugin-transform-private-methods": "^7.23.3", "@babel/plugin-transform-private-property-in-object": "^7.23.4", - "@babel/plugin-transform-runtime": "^7.23.6", - "@babel/preset-env": "^7.23.6", + "@babel/plugin-transform-runtime": "^7.23.7", + "@babel/preset-env": "^7.23.7", "@babel/preset-typescript": "^7.23.3", "@hcaptcha/types": "^1.0.3", "@jackfranklin/rollup-plugin-markdown": "^0.4.0", From 45dccd30f90f2e632afbceb87c11d4b01893e9e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 21:13:42 +0100 Subject: [PATCH 22/31] core: bump golang from 1.21.3-bookworm to 1.21.5-bookworm (#8027) Bumps golang from 1.21.3-bookworm to 1.21.5-bookworm. --- updated-dependencies: - dependency-name: golang dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- rac.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rac.Dockerfile b/rac.Dockerfile index ecfd86688..ba69bd367 100644 --- a/rac.Dockerfile +++ b/rac.Dockerfile @@ -1,7 +1,7 @@ # syntax=docker/dockerfile:1 # Stage 1: Build -FROM docker.io/golang:1.21.3-bookworm AS builder +FROM docker.io/golang:1.21.5-bookworm AS builder WORKDIR /go/src/goauthentik.io From 3906c3fc90a57e7b92b93e005559e003092e307b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 21:14:01 +0100 Subject: [PATCH 23/31] website: bump clsx from 2.0.0 to 2.1.0 in /website (#8033) Bumps [clsx](https://github.com/lukeed/clsx) from 2.0.0 to 2.1.0. - [Release notes](https://github.com/lukeed/clsx/releases) - [Commits](https://github.com/lukeed/clsx/compare/v2.0.0...v2.1.0) --- updated-dependencies: - dependency-name: clsx dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- website/package-lock.json | 8 ++++---- website/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/website/package-lock.json b/website/package-lock.json index 4e7d1a5a8..743f24714 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -16,7 +16,7 @@ "@docusaurus/theme-common": "^3.0.1", "@docusaurus/theme-mermaid": "^3.0.1", "@mdx-js/react": "^3.0.0", - "clsx": "^2.0.0", + "clsx": "^2.1.0", "disqus-react": "^1.1.5", "postcss": "^8.4.32", "prism-react-renderer": "^2.3.1", @@ -5696,9 +5696,9 @@ } }, "node_modules/clsx": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", - "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", "engines": { "node": ">=6" } diff --git a/website/package.json b/website/package.json index 5e8dca12e..7773daee1 100644 --- a/website/package.json +++ b/website/package.json @@ -23,7 +23,7 @@ "@docusaurus/theme-common": "^3.0.1", "@docusaurus/theme-mermaid": "^3.0.1", "@mdx-js/react": "^3.0.0", - "clsx": "^2.0.0", + "clsx": "^2.1.0", "disqus-react": "^1.1.5", "postcss": "^8.4.32", "prism-react-renderer": "^2.3.1", From 4d2c85c3a3c1dab1819afdc5acd27cc9915bc762 Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 21:14:25 +0100 Subject: [PATCH 24/31] translate: Updates for file web/xliff/en.xlf in zh-Hans (#8039) Translate web/xliff/en.xlf in zh-Hans 100% translated source file: 'web/xliff/en.xlf' on 'zh-Hans'. Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com> --- web/xliff/zh-Hans.xlf | 88 +++++++++++++++++++++++++++++++------------ 1 file changed, 64 insertions(+), 24 deletions(-) diff --git a/web/xliff/zh-Hans.xlf b/web/xliff/zh-Hans.xlf index b2a6e07d1..1ef89db75 100644 --- a/web/xliff/zh-Hans.xlf +++ b/web/xliff/zh-Hans.xlf @@ -1,4 +1,4 @@ - + @@ -613,9 +613,9 @@ - The URL "" was not found. - 未找到 URL " - "。 + The URL "" was not found. + 未找到 URL " + "。 @@ -1057,8 +1057,8 @@ - To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. - 要允许任何重定向 URI,请将此值设置为 ".*"。请注意这可能带来的安全影响。 + To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. + 要允许任何重定向 URI,请将此值设置为 ".*"。请注意这可能带来的安全影响。 @@ -1799,8 +1799,8 @@ - Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". - 输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。 + Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". + 输入完整 URL、相对路径,或者使用 'fa://fa-test' 来使用 Font Awesome 图标 "fa-test"。 @@ -2983,8 +2983,8 @@ doesn't pass when either or both of the selected options are equal or above the - Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' - 包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...' + Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' + 包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...' @@ -3776,8 +3776,8 @@ doesn't pass when either or both of the selected options are equal or above the - When using an external logging solution for archiving, this can be set to "minutes=5". - 使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。 + When using an external logging solution for archiving, this can be set to "minutes=5". + 使用外部日志记录解决方案进行存档时,可以将其设置为 "minutes=5"。 @@ -3786,8 +3786,8 @@ doesn't pass when either or both of the selected options are equal or above the - Format: "weeks=3;days=2;hours=3,seconds=2". - 格式:"weeks=3;days=2;hours=3,seconds=2"。 + Format: "weeks=3;days=2;hours=3,seconds=2". + 格式:"weeks=3;days=2;hours=3,seconds=2"。 @@ -3983,10 +3983,10 @@ doesn't pass when either or both of the selected options are equal or above the - Are you sure you want to update ""? + Are you sure you want to update ""? 您确定要更新 - " - " 吗? + " + " 吗? @@ -5072,7 +5072,7 @@ doesn't pass when either or both of the selected options are equal or above the - A "roaming" authenticator, like a YubiKey + A "roaming" authenticator, like a YubiKey 像 YubiKey 这样的“漫游”身份验证器 @@ -5407,10 +5407,10 @@ doesn't pass when either or both of the selected options are equal or above the - ("", of type ) + ("", of type ) - (" - ",类型为 + (" + ",类型为 @@ -5459,7 +5459,7 @@ doesn't pass when either or both of the selected options are equal or above the - If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. + If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. 如果设置时长大于 0,用户可以选择“保持登录”选项,这将使用户的会话延长此处设置的时间。 @@ -7965,7 +7965,7 @@ Bindings to groups/users are checked against the user of the event. 成功创建用户并添加到组 - This user will be added to the group "". + This user will be added to the group "". 此用户将会被添加到组 &quot;&quot;。 @@ -8046,124 +8046,164 @@ Bindings to groups/users are checked against the user of the event. Connection settings. + 连接设置。 Successfully updated endpoint. + 已成功更新端点。 Successfully created endpoint. + 已成功创建端点。 Protocol + 协议 RDP + RDP SSH + SSH VNC + VNC Host + 主机 Hostname/IP to connect to. + 要连接的主机名/IP。 Endpoint(s) + 端点 Update Endpoint + 更新端点 These bindings control which users will have access to this endpoint. Users must also have access to the application. + 这些绑定控制哪些用户能够访问此端点。用户必须也能访问此应用程序。 Create Endpoint + 创建端点 RAC is in preview. + RAC 目前处于预览状态。 Update RAC Provider + 更新 RAC 提供程序 Endpoints + 端点 General settings + 常规设置 RDP settings + RDP 设置 Ignore server certificate + 忽略服务器证书 Enable wallpaper + 启用壁纸 Enable font-smoothing + 启用字体平滑 Enable full window dragging + 启用完整窗口拖拽 Network binding + 网络绑定 No binding + 无绑定 Bind ASN + 绑定 ASN Bind ASN and Network + 绑定 ASN 和网络 Bind ASN, Network and IP + 绑定 ASN、网络和 IP Configure if sessions created by this stage should be bound to the Networks they were created in. + 配置由此阶段创建的会话是否应该绑定到创建它们的网络。 GeoIP binding + GeoIP 绑定 Bind Continent + 绑定大陆 Bind Continent and Country + 绑定大陆和国家 Bind Continent, Country and City + 绑定大陆、国家和城市 Configure if sessions created by this stage should be bound to their GeoIP-based location + 配置由此阶段创建的会话是否应该绑定到基于 GeoIP 的位置。 RAC + RAC Connection failed after attempts. + 连接在 次尝试后失败。 Re-connecting in second(s). + 将在 秒后重新连接。 Connecting... + 正在连接… Select endpoint to connect to + 选择要连接到的端点 Connection expiry + 连接过期 Determines how long a session lasts before being disconnected and requiring re-authorization. + 设置会话在被断开连接并需要重新授权之前持续的时间。 - + \ No newline at end of file From 7337f48d0af9befc4b88032c7b7ba24138604d86 Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 21:14:41 +0100 Subject: [PATCH 25/31] translate: Updates for file web/xliff/en.xlf in zh_CN (#8038) Translate web/xliff/en.xlf in zh_CN 100% translated source file: 'web/xliff/en.xlf' on 'zh_CN'. Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com> --- web/xliff/zh_CN.xlf | 165 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 160 insertions(+), 5 deletions(-) diff --git a/web/xliff/zh_CN.xlf b/web/xliff/zh_CN.xlf index 15ba558f0..ea9939a67 100644 --- a/web/xliff/zh_CN.xlf +++ b/web/xliff/zh_CN.xlf @@ -2217,11 +2217,6 @@ Update SCIM Provider 更新 SCIM 提供程序 - - - Sync not run yet. - 尚未同步过。 - Run sync again @@ -8048,6 +8043,166 @@ Bindings to groups/users are checked against the user of the event. Require Outpost (flow can only be executed from an outpost). 需要前哨(流程只能从前哨执行)。 + + + Connection settings. + 连接设置。 + + + Successfully updated endpoint. + 已成功更新端点。 + + + Successfully created endpoint. + 已成功创建端点。 + + + Protocol + 协议 + + + RDP + RDP + + + SSH + SSH + + + VNC + VNC + + + Host + 主机 + + + Hostname/IP to connect to. + 要连接的主机名/IP。 + + + Endpoint(s) + 端点 + + + Update Endpoint + 更新端点 + + + These bindings control which users will have access to this endpoint. Users must also have access to the application. + 这些绑定控制哪些用户能够访问此端点。用户必须也能访问此应用程序。 + + + Create Endpoint + 创建端点 + + + RAC is in preview. + RAC 目前处于预览状态。 + + + Update RAC Provider + 更新 RAC 提供程序 + + + Endpoints + 端点 + + + General settings + 常规设置 + + + RDP settings + RDP 设置 + + + Ignore server certificate + 忽略服务器证书 + + + Enable wallpaper + 启用壁纸 + + + Enable font-smoothing + 启用字体平滑 + + + Enable full window dragging + 启用完整窗口拖拽 + + + Network binding + 网络绑定 + + + No binding + 无绑定 + + + Bind ASN + 绑定 ASN + + + Bind ASN and Network + 绑定 ASN 和网络 + + + Bind ASN, Network and IP + 绑定 ASN、网络和 IP + + + Configure if sessions created by this stage should be bound to the Networks they were created in. + 配置由此阶段创建的会话是否应该绑定到创建它们的网络。 + + + GeoIP binding + GeoIP 绑定 + + + Bind Continent + 绑定大陆 + + + Bind Continent and Country + 绑定大陆和国家 + + + Bind Continent, Country and City + 绑定大陆、国家和城市 + + + Configure if sessions created by this stage should be bound to their GeoIP-based location + 配置由此阶段创建的会话是否应该绑定到基于 GeoIP 的位置。 + + + RAC + RAC + + + Connection failed after attempts. + 连接在 次尝试后失败。 + + + Re-connecting in second(s). + 将在 秒后重新连接。 + + + Connecting... + 正在连接… + + + Select endpoint to connect to + 选择要连接到的端点 + + + Connection expiry + 连接过期 + + + Determines how long a session lasts before being disconnected and requiring re-authorization. + 设置会话在被断开连接并需要重新授权之前持续的时间。 From d71171378547f5a0c02aa5c6bd2e7dcd7a5db106 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jan 2024 21:26:43 +0100 Subject: [PATCH 26/31] web: bump @types/guacamole-common-js from 1.3.2 to 1.5.2 in /web (#8030) * web: bump @types/guacamole-common-js from 1.3.2 to 1.5.2 in /web Bumps [@types/guacamole-common-js](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/guacamole-common-js) from 1.3.2 to 1.5.2. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/guacamole-common-js) --- updated-dependencies: - dependency-name: "@types/guacamole-common-js" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * fix Signed-off-by: Jens Langhammer --------- Signed-off-by: dependabot[bot] Signed-off-by: Jens Langhammer Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jens Langhammer --- web/package-lock.json | 8 ++++---- web/package.json | 2 +- web/src/enterprise/rac/index.ts | 16 +++++++++------- 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index 8ba596075..c7f87fa9d 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -74,7 +74,7 @@ "@types/chart.js": "^2.9.41", "@types/codemirror": "5.60.15", "@types/grecaptcha": "^3.0.7", - "@types/guacamole-common-js": "1.3.2", + "@types/guacamole-common-js": "1.5.2", "@typescript-eslint/eslint-plugin": "^6.16.0", "@typescript-eslint/parser": "^6.16.0", "babel-plugin-macros": "^3.1.0", @@ -7370,9 +7370,9 @@ "dev": true }, "node_modules/@types/guacamole-common-js": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/guacamole-common-js/-/guacamole-common-js-1.3.2.tgz", - "integrity": "sha512-217AvsdGfuoqrXLWjrZOjO1CRzY0PNCG07NQf+cW6gYZhExCpjwDrpIbi5pFrmskPZB3T8n1CZLEoYW7rTERNQ==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@types/guacamole-common-js/-/guacamole-common-js-1.5.2.tgz", + "integrity": "sha512-S01txydRyBscHyV8giYNdrfU7dzwUkLb8prQPP68/YCpY/gMtcL9e7BXGpQttj4XpelSUVkA++TjllalZ0AHjg==", "dev": true }, "node_modules/@types/http-errors": { diff --git a/web/package.json b/web/package.json index ed7681155..e7fe1cb19 100644 --- a/web/package.json +++ b/web/package.json @@ -98,7 +98,7 @@ "@types/chart.js": "^2.9.41", "@types/codemirror": "5.60.15", "@types/grecaptcha": "^3.0.7", - "@types/guacamole-common-js": "1.3.2", + "@types/guacamole-common-js": "1.5.2", "@typescript-eslint/eslint-plugin": "^6.16.0", "@typescript-eslint/parser": "^6.16.0", "babel-plugin-macros": "^3.1.0", diff --git a/web/src/enterprise/rac/index.ts b/web/src/enterprise/rac/index.ts index 495e09801..272ba2211 100644 --- a/web/src/enterprise/rac/index.ts +++ b/web/src/enterprise/rac/index.ts @@ -238,13 +238,15 @@ export class RacInterface extends Interface { this.client.sendMouseState(mouseState); }; - mouse.onmouseup = mouse.onmousedown = (mouseState) => { + // @ts-ignore + mouse.onEach(["mouseup", "mousedown"], (ev: Guacamole.Mouse.Event) => { this.container?.focus(); - handler(mouseState); - }; - mouse.onmousemove = (mouseState) => { - handler(mouseState, true); - }; + handler(ev.state); + }); + // @ts-ignore + mouse.on("mousemove", (ev: Guacamole.Mouse.Event) => { + handler(ev.state, true); + }); } initAudioInput(): void { @@ -298,7 +300,7 @@ export class RacInterface extends Interface { if (!this.client) { return; } - const stream = this.client.createClipboardStream("text/plain", "clipboard"); + const stream = this.client.createClipboardStream("text/plain"); const writer = new Guacamole.StringWriter(stream); writer.sendText(value); writer.sendEnd(); From 9120cf8642f25266dd78ad4f70e1a4805b4f4864 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Jan 2024 11:35:55 +0100 Subject: [PATCH 27/31] web: bump the eslint group in /web with 2 updates (#8043) Bumps the eslint group in /web with 2 updates: [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) and [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser). Updates `@typescript-eslint/eslint-plugin` from 6.16.0 to 6.17.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.17.0/packages/eslint-plugin) Updates `@typescript-eslint/parser` from 6.16.0 to 6.17.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.17.0/packages/parser) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: eslint - dependency-name: "@typescript-eslint/parser" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: eslint ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- web/package-lock.json | 89 +++++++++++++++++++++---------------------- web/package.json | 4 +- 2 files changed, 46 insertions(+), 47 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index c7f87fa9d..d6bf9bbfc 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -15,7 +15,6 @@ "@codemirror/lang-xml": "^6.0.2", "@codemirror/legacy-modes": "^6.3.3", "@codemirror/theme-one-dark": "^6.1.2", - "@esbuild/linux-arm64": "^0.19.11", "@formatjs/intl-listformat": "^7.5.3", "@fortawesome/fontawesome-free": "^6.5.1", "@goauthentik/api": "^2023.10.5-1703968412", @@ -75,8 +74,8 @@ "@types/codemirror": "5.60.15", "@types/grecaptcha": "^3.0.7", "@types/guacamole-common-js": "1.5.2", - "@typescript-eslint/eslint-plugin": "^6.16.0", - "@typescript-eslint/parser": "^6.16.0", + "@typescript-eslint/eslint-plugin": "^6.17.0", + "@typescript-eslint/parser": "^6.17.0", "babel-plugin-macros": "^3.1.0", "babel-plugin-tsconfig-paths": "^1.0.3", "cross-env": "^7.0.3", @@ -7611,16 +7610,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.16.0.tgz", - "integrity": "sha512-O5f7Kv5o4dLWQtPX4ywPPa+v9G+1q1x8mz0Kr0pXUtKsevo+gIJHLkGc8RxaZWtP8RrhwhSNIWThnW42K9/0rQ==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.17.0.tgz", + "integrity": "sha512-Vih/4xLXmY7V490dGwBQJTpIZxH4ZFH6eCVmQ4RFkB+wmaCTDAx4dtgoWwMNGKLkqRY1L6rPqzEbjorRnDo4rQ==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.16.0", - "@typescript-eslint/type-utils": "6.16.0", - "@typescript-eslint/utils": "6.16.0", - "@typescript-eslint/visitor-keys": "6.16.0", + "@typescript-eslint/scope-manager": "6.17.0", + "@typescript-eslint/type-utils": "6.17.0", + "@typescript-eslint/utils": "6.17.0", + "@typescript-eslint/visitor-keys": "6.17.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -7679,15 +7678,15 @@ "dev": true }, "node_modules/@typescript-eslint/parser": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.16.0.tgz", - "integrity": "sha512-H2GM3eUo12HpKZU9njig3DF5zJ58ja6ahj1GoHEHOgQvYxzoFJJEvC1MQ7T2l9Ha+69ZSOn7RTxOdpC/y3ikMw==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.17.0.tgz", + "integrity": "sha512-C4bBaX2orvhK+LlwrY8oWGmSl4WolCfYm513gEccdWZj0CwGadbIADb0FtVEcI+WzUyjyoBj2JRP8g25E6IB8A==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.16.0", - "@typescript-eslint/types": "6.16.0", - "@typescript-eslint/typescript-estree": "6.16.0", - "@typescript-eslint/visitor-keys": "6.16.0", + "@typescript-eslint/scope-manager": "6.17.0", + "@typescript-eslint/types": "6.17.0", + "@typescript-eslint/typescript-estree": "6.17.0", + "@typescript-eslint/visitor-keys": "6.17.0", "debug": "^4.3.4" }, "engines": { @@ -7707,13 +7706,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.16.0.tgz", - "integrity": "sha512-0N7Y9DSPdaBQ3sqSCwlrm9zJwkpOuc6HYm7LpzLAPqBL7dmzAUimr4M29dMkOP/tEwvOCC/Cxo//yOfJD3HUiw==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.17.0.tgz", + "integrity": "sha512-RX7a8lwgOi7am0k17NUO0+ZmMOX4PpjLtLRgLmT1d3lBYdWH4ssBUbwdmc5pdRX8rXon8v9x8vaoOSpkHfcXGA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.16.0", - "@typescript-eslint/visitor-keys": "6.16.0" + "@typescript-eslint/types": "6.17.0", + "@typescript-eslint/visitor-keys": "6.17.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -7724,13 +7723,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.16.0.tgz", - "integrity": "sha512-ThmrEOcARmOnoyQfYkHw/DX2SEYBalVECmoldVuH6qagKROp/jMnfXpAU/pAIWub9c4YTxga+XwgAkoA0pxfmg==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.17.0.tgz", + "integrity": "sha512-hDXcWmnbtn4P2B37ka3nil3yi3VCQO2QEB9gBiHJmQp5wmyQWqnjA85+ZcE8c4FqnaB6lBwMrPkgd4aBYz3iNg==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.16.0", - "@typescript-eslint/utils": "6.16.0", + "@typescript-eslint/typescript-estree": "6.17.0", + "@typescript-eslint/utils": "6.17.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -7751,9 +7750,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.16.0.tgz", - "integrity": "sha512-hvDFpLEvTJoHutVl87+MG/c5C8I6LOgEx05zExTSJDEVU7hhR3jhV8M5zuggbdFCw98+HhZWPHZeKS97kS3JoQ==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.17.0.tgz", + "integrity": "sha512-qRKs9tvc3a4RBcL/9PXtKSehI/q8wuU9xYJxe97WFxnzH8NWWtcW3ffNS+EWg8uPvIerhjsEZ+rHtDqOCiH57A==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -7764,13 +7763,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.16.0.tgz", - "integrity": "sha512-VTWZuixh/vr7nih6CfrdpmFNLEnoVBF1skfjdyGnNwXOH1SLeHItGdZDHhhAIzd3ACazyY2Fg76zuzOVTaknGA==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.17.0.tgz", + "integrity": "sha512-gVQe+SLdNPfjlJn5VNGhlOhrXz4cajwFd5kAgWtZ9dCZf4XJf8xmgCTLIqec7aha3JwgLI2CK6GY1043FRxZwg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.16.0", - "@typescript-eslint/visitor-keys": "6.16.0", + "@typescript-eslint/types": "6.17.0", + "@typescript-eslint/visitor-keys": "6.17.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -7849,17 +7848,17 @@ "dev": true }, "node_modules/@typescript-eslint/utils": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.16.0.tgz", - "integrity": "sha512-T83QPKrBm6n//q9mv7oiSvy/Xq/7Hyw9SzSEhMHJwznEmQayfBM87+oAlkNAMEO7/MjIwKyOHgBJbxB0s7gx2A==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.17.0.tgz", + "integrity": "sha512-LofsSPjN/ITNkzV47hxas2JCsNCEnGhVvocfyOcLzT9c/tSZE7SfhS/iWtzP1lKNOEfLhRTZz6xqI8N2RzweSQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.16.0", - "@typescript-eslint/types": "6.16.0", - "@typescript-eslint/typescript-estree": "6.16.0", + "@typescript-eslint/scope-manager": "6.17.0", + "@typescript-eslint/types": "6.17.0", + "@typescript-eslint/typescript-estree": "6.17.0", "semver": "^7.5.4" }, "engines": { @@ -7907,12 +7906,12 @@ "dev": true }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.16.0.tgz", - "integrity": "sha512-QSFQLruk7fhs91a/Ep/LqRdbJCZ1Rq03rqBdKT5Ky17Sz8zRLUksqIe9DW0pKtg/Z35/ztbLQ6qpOCN6rOC11A==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.17.0.tgz", + "integrity": "sha512-H6VwB/k3IuIeQOyYczyyKN8wH6ed8EwliaYHLxOIhyF0dYEIsN8+Bk3GE19qafeMKyZJJHP8+O1HiFhFLUNKSg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.16.0", + "@typescript-eslint/types": "6.17.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { diff --git a/web/package.json b/web/package.json index e7fe1cb19..da7a1004c 100644 --- a/web/package.json +++ b/web/package.json @@ -99,8 +99,8 @@ "@types/codemirror": "5.60.15", "@types/grecaptcha": "^3.0.7", "@types/guacamole-common-js": "1.5.2", - "@typescript-eslint/eslint-plugin": "^6.16.0", - "@typescript-eslint/parser": "^6.16.0", + "@typescript-eslint/eslint-plugin": "^6.17.0", + "@typescript-eslint/parser": "^6.17.0", "babel-plugin-macros": "^3.1.0", "babel-plugin-tsconfig-paths": "^1.0.3", "cross-env": "^7.0.3", From 10a5466436f53504929f0c1b284f0cf79ecdb217 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Jan 2024 11:36:07 +0100 Subject: [PATCH 28/31] web: bump the storybook group in /web with 7 updates (#8042) Bumps the storybook group in /web with 7 updates: | Package | From | To | | --- | --- | --- | | [@storybook/addon-essentials](https://github.com/storybookjs/storybook/tree/HEAD/code/addons/essentials) | `7.6.6` | `7.6.7` | | [@storybook/addon-links](https://github.com/storybookjs/storybook/tree/HEAD/code/addons/links) | `7.6.6` | `7.6.7` | | [@storybook/api](https://github.com/storybookjs/storybook/tree/HEAD/code/deprecated/manager-api-shim) | `7.6.6` | `7.6.7` | | [@storybook/manager-api](https://github.com/storybookjs/storybook/tree/HEAD/code/lib/manager-api) | `7.6.6` | `7.6.7` | | [@storybook/web-components](https://github.com/storybookjs/storybook/tree/HEAD/code/renderers/web-components) | `7.6.6` | `7.6.7` | | [@storybook/web-components-vite](https://github.com/storybookjs/storybook/tree/HEAD/code/frameworks/web-components-vite) | `7.6.6` | `7.6.7` | | [storybook](https://github.com/storybookjs/storybook/tree/HEAD/code/lib/cli) | `7.6.6` | `7.6.7` | Updates `@storybook/addon-essentials` from 7.6.6 to 7.6.7 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v7.6.7/code/addons/essentials) Updates `@storybook/addon-links` from 7.6.6 to 7.6.7 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v7.6.7/code/addons/links) Updates `@storybook/api` from 7.6.6 to 7.6.7 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/v7.6.7/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v7.6.7/code/deprecated/manager-api-shim) Updates `@storybook/manager-api` from 7.6.6 to 7.6.7 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v7.6.7/code/lib/manager-api) Updates `@storybook/web-components` from 7.6.6 to 7.6.7 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v7.6.7/code/renderers/web-components) Updates `@storybook/web-components-vite` from 7.6.6 to 7.6.7 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v7.6.7/code/frameworks/web-components-vite) Updates `storybook` from 7.6.6 to 7.6.7 - [Release notes](https://github.com/storybookjs/storybook/releases) - [Changelog](https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md) - [Commits](https://github.com/storybookjs/storybook/commits/v7.6.7/code/lib/cli) --- updated-dependencies: - dependency-name: "@storybook/addon-essentials" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook - dependency-name: "@storybook/addon-links" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook - dependency-name: "@storybook/api" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook - dependency-name: "@storybook/manager-api" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook - dependency-name: "@storybook/web-components" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook - dependency-name: "@storybook/web-components-vite" dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook - dependency-name: storybook dependency-type: direct:development update-type: version-update:semver-patch dependency-group: storybook ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- web/package-lock.json | 894 ++++++++++++++++++++++++------------------ web/package.json | 14 +- 2 files changed, 513 insertions(+), 395 deletions(-) diff --git a/web/package-lock.json b/web/package-lock.json index d6bf9bbfc..d6305b661 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -62,13 +62,13 @@ "@rollup/plugin-replace": "^5.0.5", "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^11.1.5", - "@storybook/addon-essentials": "^7.6.6", - "@storybook/addon-links": "^7.6.6", - "@storybook/api": "^7.6.6", + "@storybook/addon-essentials": "^7.6.7", + "@storybook/addon-links": "^7.6.7", + "@storybook/api": "^7.6.7", "@storybook/blocks": "^7.6.4", - "@storybook/manager-api": "^7.6.6", - "@storybook/web-components": "^7.6.6", - "@storybook/web-components-vite": "^7.6.6", + "@storybook/manager-api": "^7.6.7", + "@storybook/web-components": "^7.6.7", + "@storybook/web-components-vite": "^7.6.7", "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@types/chart.js": "^2.9.41", "@types/codemirror": "5.60.15", @@ -97,7 +97,7 @@ "rollup-plugin-cssimport": "^1.0.3", "rollup-plugin-modify": "^3.0.0", "rollup-plugin-postcss-lit": "^2.1.0", - "storybook": "^7.6.6", + "storybook": "^7.6.7", "storybook-addon-mock": "^4.3.0", "ts-lit-plugin": "^2.0.1", "tslib": "^2.6.2", @@ -1977,15 +1977,15 @@ } }, "node_modules/@babel/register": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.22.15.tgz", - "integrity": "sha512-V3Q3EqoQdn65RCgTLwauZaTfd1ShhwPmbBv+1dkZV/HpCGMKVyn6oFcRlI7RaKqiDQjX2Qd3AuoEguBgdjIKlg==", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.23.7.tgz", + "integrity": "sha512-EjJeB6+kvpk+Y5DAkEAmbOBEFkh9OASx0huoEkqYTFxAZHzOAX2Oh5uwAUuL2rUddqfM0SA+KPXV2TbzoZ2kvQ==", "dev": true, "dependencies": { "clone-deep": "^4.0.1", "find-cache-dir": "^2.0.0", "make-dir": "^2.1.0", - "pirates": "^4.0.5", + "pirates": "^4.0.6", "source-map-support": "^0.5.16" }, "engines": { @@ -4855,12 +4855,12 @@ "dev": true }, "node_modules/@storybook/addon-actions": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-7.6.6.tgz", - "integrity": "sha512-mLJip9Evb2Chj7ymKbpaybe5NgDy3Du7oSWeURPy/0qXJ2cBqHWnhZ8CTK2DasrstsUhQSJaZVXHhaENT+fn+g==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-7.6.7.tgz", + "integrity": "sha512-+6EZvhIeKEqG/RNsU3R5DxOrd60BL5GEvmzE2w60s2eKaNNxtyilDjiO1g4z2s2zDNyr7JL/Ft03pJ0Jgo0lew==", "dev": true, "dependencies": { - "@storybook/core-events": "7.6.6", + "@storybook/core-events": "7.6.7", "@storybook/global": "^5.0.0", "@types/uuid": "^9.0.1", "dequal": "^2.0.2", @@ -4873,9 +4873,9 @@ } }, "node_modules/@storybook/addon-backgrounds": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-7.6.6.tgz", - "integrity": "sha512-w5dZ/0cOe55M2G/Lx9f+Ptk4txUPb+Ng+KqEvTaTNqHoh0Xw4QxEn/ciJwmh1u1g3aMZsOgOvwPwug7ykmLgsA==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-7.6.7.tgz", + "integrity": "sha512-55sBy1YUqponAVe+qL16qtWxdf63vHEnIoqFyHEwGpk7K9IhFA1BmdSpFr5VnWEwXeJXKj30db78frh2LUdk3Q==", "dev": true, "dependencies": { "@storybook/global": "^5.0.0", @@ -4888,12 +4888,12 @@ } }, "node_modules/@storybook/addon-controls": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-7.6.6.tgz", - "integrity": "sha512-VAXXfPLi1M3RXhBf3uIBZ2hrD9UPDe7yvXHIlCzgj1HIJELODCFyUc+RtvN0mPc/nnlEfzhGfJtenZou5LYwIw==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-7.6.7.tgz", + "integrity": "sha512-DJ3gfvcdCgqi7AQxu83vx0AEUKiuJrNcSATfWV3Jqi8dH6fYO2yqpemHEeWOEy+DAHxIOaqLKwb1QjIBj+vSRQ==", "dev": true, "dependencies": { - "@storybook/blocks": "7.6.6", + "@storybook/blocks": "7.6.7", "lodash": "^4.17.21", "ts-dedent": "^2.0.0" }, @@ -4903,26 +4903,26 @@ } }, "node_modules/@storybook/addon-docs": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-7.6.6.tgz", - "integrity": "sha512-l4gtoNTn1wHE11x44te1cDkqfm+/w+eNonHe56bwgSqETclS5z18wvM9bQZF32G6C9fpSefaJW3cxVvcuJL1fg==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-7.6.7.tgz", + "integrity": "sha512-2dfajNhweofJ3LxjGO83UE5sBMvKtJB0Agj7q8mMtK/9PUCUcbvsFSyZnO/s6X1zAjSn5ZrirbSoTXU4IqxwSA==", "dev": true, "dependencies": { "@jest/transform": "^29.3.1", "@mdx-js/react": "^2.1.5", - "@storybook/blocks": "7.6.6", - "@storybook/client-logger": "7.6.6", - "@storybook/components": "7.6.6", - "@storybook/csf-plugin": "7.6.6", - "@storybook/csf-tools": "7.6.6", + "@storybook/blocks": "7.6.7", + "@storybook/client-logger": "7.6.7", + "@storybook/components": "7.6.7", + "@storybook/csf-plugin": "7.6.7", + "@storybook/csf-tools": "7.6.7", "@storybook/global": "^5.0.0", "@storybook/mdx2-csf": "^1.0.0", - "@storybook/node-logger": "7.6.6", - "@storybook/postinstall": "7.6.6", - "@storybook/preview-api": "7.6.6", - "@storybook/react-dom-shim": "7.6.6", - "@storybook/theming": "7.6.6", - "@storybook/types": "7.6.6", + "@storybook/node-logger": "7.6.7", + "@storybook/postinstall": "7.6.7", + "@storybook/preview-api": "7.6.7", + "@storybook/react-dom-shim": "7.6.7", + "@storybook/theming": "7.6.7", + "@storybook/types": "7.6.7", "fs-extra": "^11.1.0", "remark-external-links": "^8.0.0", "remark-slug": "^6.0.0", @@ -4938,17 +4938,17 @@ } }, "node_modules/@storybook/addon-docs/node_modules/@storybook/preview-api": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.6.tgz", - "integrity": "sha512-Bt6xIAR5yZ/JWc90X4BbLOA97iL65glZ1SOBgFFv2mHrdZ1lcdKhAlQr2aeJAf1mLvBtalPjvKzi9EuVY3FZ4w==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.7.tgz", + "integrity": "sha512-ja85ItrT6q2TeBQ6n0CNoRi1R6L8yF2kkis9hVeTQHpwLdZyHUTRqqR5WmhtLqqQXcofyasBPOeJV06wuOhgRQ==", "dev": true, "dependencies": { - "@storybook/channels": "7.6.6", - "@storybook/client-logger": "7.6.6", - "@storybook/core-events": "7.6.6", + "@storybook/channels": "7.6.7", + "@storybook/client-logger": "7.6.7", + "@storybook/core-events": "7.6.7", "@storybook/csf": "^0.1.2", "@storybook/global": "^5.0.0", - "@storybook/types": "7.6.6", + "@storybook/types": "7.6.7", "@types/qs": "^6.9.5", "dequal": "^2.0.2", "lodash": "^4.17.21", @@ -4978,24 +4978,24 @@ } }, "node_modules/@storybook/addon-essentials": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/addon-essentials/-/addon-essentials-7.6.6.tgz", - "integrity": "sha512-OQ8A6r06mg/HvyIk/j2Gt9DK5Qtqgtwq2Ydm5IgVW6gZsuRnv1FAeUG6okf8oXowAzpYoHdsDmCVwNOAGWGO7w==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/addon-essentials/-/addon-essentials-7.6.7.tgz", + "integrity": "sha512-nNLMrpIvc04z4XCA+kval/44eKAFJlUJeeL2pxwP7F/PSzjWe5BXv1bQHOiw8inRO5II0PzqwWnVCI9jsj7K5A==", "dev": true, "dependencies": { - "@storybook/addon-actions": "7.6.6", - "@storybook/addon-backgrounds": "7.6.6", - "@storybook/addon-controls": "7.6.6", - "@storybook/addon-docs": "7.6.6", - "@storybook/addon-highlight": "7.6.6", - "@storybook/addon-measure": "7.6.6", - "@storybook/addon-outline": "7.6.6", - "@storybook/addon-toolbars": "7.6.6", - "@storybook/addon-viewport": "7.6.6", - "@storybook/core-common": "7.6.6", - "@storybook/manager-api": "7.6.6", - "@storybook/node-logger": "7.6.6", - "@storybook/preview-api": "7.6.6", + "@storybook/addon-actions": "7.6.7", + "@storybook/addon-backgrounds": "7.6.7", + "@storybook/addon-controls": "7.6.7", + "@storybook/addon-docs": "7.6.7", + "@storybook/addon-highlight": "7.6.7", + "@storybook/addon-measure": "7.6.7", + "@storybook/addon-outline": "7.6.7", + "@storybook/addon-toolbars": "7.6.7", + "@storybook/addon-viewport": "7.6.7", + "@storybook/core-common": "7.6.7", + "@storybook/manager-api": "7.6.7", + "@storybook/node-logger": "7.6.7", + "@storybook/preview-api": "7.6.7", "ts-dedent": "^2.0.0" }, "funding": { @@ -5008,17 +5008,17 @@ } }, "node_modules/@storybook/addon-essentials/node_modules/@storybook/preview-api": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.6.tgz", - "integrity": "sha512-Bt6xIAR5yZ/JWc90X4BbLOA97iL65glZ1SOBgFFv2mHrdZ1lcdKhAlQr2aeJAf1mLvBtalPjvKzi9EuVY3FZ4w==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.7.tgz", + "integrity": "sha512-ja85ItrT6q2TeBQ6n0CNoRi1R6L8yF2kkis9hVeTQHpwLdZyHUTRqqR5WmhtLqqQXcofyasBPOeJV06wuOhgRQ==", "dev": true, "dependencies": { - "@storybook/channels": "7.6.6", - "@storybook/client-logger": "7.6.6", - "@storybook/core-events": "7.6.6", + "@storybook/channels": "7.6.7", + "@storybook/client-logger": "7.6.7", + "@storybook/core-events": "7.6.7", "@storybook/csf": "^0.1.2", "@storybook/global": "^5.0.0", - "@storybook/types": "7.6.6", + "@storybook/types": "7.6.7", "@types/qs": "^6.9.5", "dequal": "^2.0.2", "lodash": "^4.17.21", @@ -5034,9 +5034,9 @@ } }, "node_modules/@storybook/addon-highlight": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/addon-highlight/-/addon-highlight-7.6.6.tgz", - "integrity": "sha512-B85UaCts2uMpa0yHBSnupzy2WCdW4vfB+lfaBug9beyOyZQdel07BumblE0KwSJftYgdCNPUZ5MRlqEDzMLTWQ==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/addon-highlight/-/addon-highlight-7.6.7.tgz", + "integrity": "sha512-2F/tJdn45d4zrvf/cmE1vsczl99wK8+I+kkj0G7jLsrJR0w1zTgbgjy6T9j86HBTBvWcnysNFNIRWPAOh5Wdbw==", "dev": true, "dependencies": { "@storybook/global": "^5.0.0" @@ -5047,9 +5047,9 @@ } }, "node_modules/@storybook/addon-links": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-7.6.6.tgz", - "integrity": "sha512-NEcqOz6zZ1dJnCcVmYdaQTAMAGIb8NFAZGnr9DU0q+t4B1fTaWUgqLtBM5V6YqIrXGSC/oKLpjWUkS5UpswlHA==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-7.6.7.tgz", + "integrity": "sha512-O5LekPslkAIDtXC/TCIyg/3c0htBxDYwb/s+NrZUPTNWJsngxvTAwp6aIk6aVSeSCFUMWvBFcVsuV3hv+ndK6w==", "dev": true, "dependencies": { "@storybook/csf": "^0.1.2", @@ -5070,9 +5070,9 @@ } }, "node_modules/@storybook/addon-measure": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/addon-measure/-/addon-measure-7.6.6.tgz", - "integrity": "sha512-b4hyCudlhsbYN1We8pfZHZJ0i0sfC8+GJvrqZQqdSqGicUmA00mggY1GE+gEoHziQ5/4auxFRS3HfUgaQWUNjg==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/addon-measure/-/addon-measure-7.6.7.tgz", + "integrity": "sha512-t1RnnNO4Xzgnsxu63FlZwsCTF0+9jKxr44NiJAUOxW9ppbCvs/JfSDOOvcDRtPWyjgnyzexNUUctMfxvLrU01A==", "dev": true, "dependencies": { "@storybook/global": "^5.0.0", @@ -5084,9 +5084,9 @@ } }, "node_modules/@storybook/addon-outline": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/addon-outline/-/addon-outline-7.6.6.tgz", - "integrity": "sha512-BMjpjzNEnN8LC7JK92WCXyWgmJwAaEQjRDinr7eD4cBt4Uas5kbciw1g8PtTnh0GbYUsImKao0nzakSVObAdzg==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/addon-outline/-/addon-outline-7.6.7.tgz", + "integrity": "sha512-gu2y46ijjMkXlxy1f8Cctgjw5b5y8vSIqNAYlrs5/Qy+hJAWyU6lj2PFGOCCUG4L+F45fAjwWAin6qz43+WnRQ==", "dev": true, "dependencies": { "@storybook/global": "^5.0.0", @@ -5098,9 +5098,9 @@ } }, "node_modules/@storybook/addon-toolbars": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/addon-toolbars/-/addon-toolbars-7.6.6.tgz", - "integrity": "sha512-sQm5+FcoSMSGn1ioXHoukO6OhUlcNZil0/fonAY50uvp6Z4DyI0FTU7BKIm/NoMqAExQk3sZRfAC/nZZ9Epb0Q==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/addon-toolbars/-/addon-toolbars-7.6.7.tgz", + "integrity": "sha512-vT+YMzw8yVwndhJglI0XtELfXWq1M0HEy5ST3XPzbjmsJ54LgTf1b29UMkh0E/05qBQNFCcbT9B/tLxqWezxlg==", "dev": true, "funding": { "type": "opencollective", @@ -5108,9 +5108,9 @@ } }, "node_modules/@storybook/addon-viewport": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/addon-viewport/-/addon-viewport-7.6.6.tgz", - "integrity": "sha512-/ijbzDf1Iq30LvZW2NE8cO4TeHusw0N+jTDUK1+vhxGNMFo9DUIgRkAi6VpFEfS0aQ5d82523WSWzVso7b/Hmg==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/addon-viewport/-/addon-viewport-7.6.7.tgz", + "integrity": "sha512-Q/BKjJaKzl4RWxH45K2iIXwkicj4ReVAUIpIyd7dPBb/Bx+hEDYZxR5dDg82AMkZdA71x5ttMnuDSuVpmWAE6g==", "dev": true, "dependencies": { "memoizerific": "^1.11.3" @@ -5303,13 +5303,13 @@ "dev": true }, "node_modules/@storybook/api": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/api/-/api-7.6.6.tgz", - "integrity": "sha512-e3k45k7twP3z5ZJ+rCCaHI+jmYm5yoFo2eLjYmnYFUv2V3vvYPgqD2CiT0crne7uWmhpRxP49aU9DEvQaEZtdA==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/api/-/api-7.6.7.tgz", + "integrity": "sha512-07cvtF10/KJ3dX/GdTsvpFbRwHNQnDziWAtR0J80Eno3niNzEdF/Dr/Ot35hGGrsnV29Snvnd6O2nF2HByOOpg==", "dev": true, "dependencies": { - "@storybook/client-logger": "7.6.6", - "@storybook/manager-api": "7.6.6" + "@storybook/client-logger": "7.6.7", + "@storybook/manager-api": "7.6.7" }, "funding": { "type": "opencollective", @@ -5317,22 +5317,22 @@ } }, "node_modules/@storybook/blocks": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/blocks/-/blocks-7.6.6.tgz", - "integrity": "sha512-QLqkiSNrtGnh8RK9ipD63jVAUenkRu+72xR31DViZWRV9V8G2hzky5E/RoZWPEx+DfmBIUJ7Tcef6cCRcxEj9A==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/blocks/-/blocks-7.6.7.tgz", + "integrity": "sha512-+QEvGQ0he/YvFS3lsZORJWxhQIyqcCDWsxbJxJiByePd+Z4my3q8xwtPhHW0TKRL0xUgNE/GnTfMMqJfevTuSw==", "dev": true, "dependencies": { - "@storybook/channels": "7.6.6", - "@storybook/client-logger": "7.6.6", - "@storybook/components": "7.6.6", - "@storybook/core-events": "7.6.6", + "@storybook/channels": "7.6.7", + "@storybook/client-logger": "7.6.7", + "@storybook/components": "7.6.7", + "@storybook/core-events": "7.6.7", "@storybook/csf": "^0.1.2", - "@storybook/docs-tools": "7.6.6", + "@storybook/docs-tools": "7.6.7", "@storybook/global": "^5.0.0", - "@storybook/manager-api": "7.6.6", - "@storybook/preview-api": "7.6.6", - "@storybook/theming": "7.6.6", - "@storybook/types": "7.6.6", + "@storybook/manager-api": "7.6.7", + "@storybook/preview-api": "7.6.7", + "@storybook/theming": "7.6.7", + "@storybook/types": "7.6.7", "@types/lodash": "^4.14.167", "color-convert": "^2.0.1", "dequal": "^2.0.2", @@ -5356,17 +5356,17 @@ } }, "node_modules/@storybook/blocks/node_modules/@storybook/preview-api": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.6.tgz", - "integrity": "sha512-Bt6xIAR5yZ/JWc90X4BbLOA97iL65glZ1SOBgFFv2mHrdZ1lcdKhAlQr2aeJAf1mLvBtalPjvKzi9EuVY3FZ4w==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.7.tgz", + "integrity": "sha512-ja85ItrT6q2TeBQ6n0CNoRi1R6L8yF2kkis9hVeTQHpwLdZyHUTRqqR5WmhtLqqQXcofyasBPOeJV06wuOhgRQ==", "dev": true, "dependencies": { - "@storybook/channels": "7.6.6", - "@storybook/client-logger": "7.6.6", - "@storybook/core-events": "7.6.6", + "@storybook/channels": "7.6.7", + "@storybook/client-logger": "7.6.7", + "@storybook/core-events": "7.6.7", "@storybook/csf": "^0.1.2", "@storybook/global": "^5.0.0", - "@storybook/types": "7.6.6", + "@storybook/types": "7.6.7", "@types/qs": "^6.9.5", "dequal": "^2.0.2", "lodash": "^4.17.21", @@ -5382,15 +5382,15 @@ } }, "node_modules/@storybook/builder-manager": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/builder-manager/-/builder-manager-7.6.6.tgz", - "integrity": "sha512-96vmtUqh016H2n80xhvBZU2w5flTOzY7S0nW9nfxbY4UY4b39WajgwJ5wpg8l0YmCwQTrxCwY9/VE2Pd6CCqPA==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/builder-manager/-/builder-manager-7.6.7.tgz", + "integrity": "sha512-6HYpj6+g/qbDMvImVz/G/aANbkhppyBa1ozfHxLK7tRD79YvozCWmj2Z9umRekPv9VIeMxnI5EEzJXOsoMX5DQ==", "dev": true, "dependencies": { "@fal-works/esbuild-plugin-global-externals": "^2.1.2", - "@storybook/core-common": "7.6.6", - "@storybook/manager": "7.6.6", - "@storybook/node-logger": "7.6.6", + "@storybook/core-common": "7.6.7", + "@storybook/manager": "7.6.7", + "@storybook/node-logger": "7.6.7", "@types/ejs": "^3.1.1", "@types/find-cache-dir": "^3.2.1", "@yarnpkg/esbuild-plugin-pnp": "^3.0.0-rc.10", @@ -5424,19 +5424,19 @@ } }, "node_modules/@storybook/builder-vite": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-7.6.6.tgz", - "integrity": "sha512-vDBHjsswnVScVgGHeIZ22R/LoRt5T1F62p5czusydBSxKGzma5Va4JHQJp4/IKXwiCZbXcua/Cs7VKtBLO+50A==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/builder-vite/-/builder-vite-7.6.7.tgz", + "integrity": "sha512-Sv+0ROFU9k+mkvIPsPHC0lkKDzBeMpvfO9uFRl1RDSsXBfcPPZKNo5YK7U7fOhesH0BILzurGA+U/aaITMSZ9g==", "dev": true, "dependencies": { - "@storybook/channels": "7.6.6", - "@storybook/client-logger": "7.6.6", - "@storybook/core-common": "7.6.6", - "@storybook/csf-plugin": "7.6.6", - "@storybook/node-logger": "7.6.6", - "@storybook/preview": "7.6.6", - "@storybook/preview-api": "7.6.6", - "@storybook/types": "7.6.6", + "@storybook/channels": "7.6.7", + "@storybook/client-logger": "7.6.7", + "@storybook/core-common": "7.6.7", + "@storybook/csf-plugin": "7.6.7", + "@storybook/node-logger": "7.6.7", + "@storybook/preview": "7.6.7", + "@storybook/preview-api": "7.6.7", + "@storybook/types": "7.6.7", "@types/find-cache-dir": "^3.2.1", "browser-assert": "^1.2.1", "es-module-lexer": "^0.9.3", @@ -5469,17 +5469,17 @@ } }, "node_modules/@storybook/builder-vite/node_modules/@storybook/preview-api": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.6.tgz", - "integrity": "sha512-Bt6xIAR5yZ/JWc90X4BbLOA97iL65glZ1SOBgFFv2mHrdZ1lcdKhAlQr2aeJAf1mLvBtalPjvKzi9EuVY3FZ4w==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.7.tgz", + "integrity": "sha512-ja85ItrT6q2TeBQ6n0CNoRi1R6L8yF2kkis9hVeTQHpwLdZyHUTRqqR5WmhtLqqQXcofyasBPOeJV06wuOhgRQ==", "dev": true, "dependencies": { - "@storybook/channels": "7.6.6", - "@storybook/client-logger": "7.6.6", - "@storybook/core-events": "7.6.6", + "@storybook/channels": "7.6.7", + "@storybook/client-logger": "7.6.7", + "@storybook/core-events": "7.6.7", "@storybook/csf": "^0.1.2", "@storybook/global": "^5.0.0", - "@storybook/types": "7.6.6", + "@storybook/types": "7.6.7", "@types/qs": "^6.9.5", "dequal": "^2.0.2", "lodash": "^4.17.21", @@ -5525,13 +5525,13 @@ } }, "node_modules/@storybook/channels": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-7.6.6.tgz", - "integrity": "sha512-vvo7fBe2WffPonNNOA7Xx7jcHAto8qJYlq+VMysfheXrsRRbhHl3WQOA18Vm8hV9txtqdqk0hwQiXOWvhYVpeQ==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-7.6.7.tgz", + "integrity": "sha512-u1hURhfQHHtZyRIDUENRCp+CRRm7IQfcjQaoWI06XCevQPuhVEtFUfXHjG+J74aA/JuuTLFUtqwNm1zGqbXTAQ==", "dev": true, "dependencies": { - "@storybook/client-logger": "7.6.6", - "@storybook/core-events": "7.6.6", + "@storybook/client-logger": "7.6.7", + "@storybook/core-events": "7.6.7", "@storybook/global": "^5.0.0", "qs": "^6.10.0", "telejson": "^7.2.0", @@ -5543,23 +5543,23 @@ } }, "node_modules/@storybook/cli": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/cli/-/cli-7.6.6.tgz", - "integrity": "sha512-FLmWrbmGOqe1VYwqyIWxU2lJcYPssORmSbSVVPw6OqQIXx3NrNBrmZDLncMwbVCDQ8eU54J1zb+MyDmSqMbVFg==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/cli/-/cli-7.6.7.tgz", + "integrity": "sha512-DwDWzkifBH17ry+n+d+u52Sv69dZQ+04ETJdDDzghcyAcKnFzrRNukj4tJ21cm+ZAU/r0fKR9d4Qpbogca9fAg==", "dev": true, "dependencies": { "@babel/core": "^7.23.2", "@babel/preset-env": "^7.23.2", "@babel/types": "^7.23.0", "@ndelangen/get-tarball": "^3.0.7", - "@storybook/codemod": "7.6.6", - "@storybook/core-common": "7.6.6", - "@storybook/core-events": "7.6.6", - "@storybook/core-server": "7.6.6", - "@storybook/csf-tools": "7.6.6", - "@storybook/node-logger": "7.6.6", - "@storybook/telemetry": "7.6.6", - "@storybook/types": "7.6.6", + "@storybook/codemod": "7.6.7", + "@storybook/core-common": "7.6.7", + "@storybook/core-events": "7.6.7", + "@storybook/core-server": "7.6.7", + "@storybook/csf-tools": "7.6.7", + "@storybook/node-logger": "7.6.7", + "@storybook/telemetry": "7.6.7", + "@storybook/types": "7.6.7", "@types/semver": "^7.3.4", "@yarnpkg/fslib": "2.10.3", "@yarnpkg/libzip": "2.3.0", @@ -5723,9 +5723,9 @@ "dev": true }, "node_modules/@storybook/client-logger": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-7.6.6.tgz", - "integrity": "sha512-WEvVyuQR5oNF8jcMmGA13zDjxP/l46kOBBvB6JSc8toUdtLZ/kZWSnU0ioNM8+ECpFqXHjBcF2K6uSJOEb6YEg==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-7.6.7.tgz", + "integrity": "sha512-A16zpWgsa0gSdXMR9P3bWVdC9u/1B1oG4H7Z1+JhNzgnL3CdyOYO0qFSiAtNBso4nOjIAJVb6/AoBzdRhmSVQg==", "dev": true, "dependencies": { "@storybook/global": "^5.0.0" @@ -5736,18 +5736,18 @@ } }, "node_modules/@storybook/codemod": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/codemod/-/codemod-7.6.6.tgz", - "integrity": "sha512-6QwW6T6ZgwwbTkEoZ7CAoX7lUUob7Sy7bRkMHhSjJe2++wEVFOYLvzHcLUJCupK59+WhmsJU9PpUMlXEKi40TQ==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/codemod/-/codemod-7.6.7.tgz", + "integrity": "sha512-an2pD5OHqO7CE8Wb7JxjrDnpQgeoxB22MyOs8PPJ9Rvclhpjg+Ku9RogoObYm//zR4g406l7Ec8mTltUkVCEOA==", "dev": true, "dependencies": { "@babel/core": "^7.23.2", "@babel/preset-env": "^7.23.2", "@babel/types": "^7.23.0", "@storybook/csf": "^0.1.2", - "@storybook/csf-tools": "7.6.6", - "@storybook/node-logger": "7.6.6", - "@storybook/types": "7.6.6", + "@storybook/csf-tools": "7.6.7", + "@storybook/node-logger": "7.6.7", + "@storybook/types": "7.6.7", "@types/cross-spawn": "^6.0.2", "cross-spawn": "^7.0.3", "globby": "^11.0.2", @@ -5777,18 +5777,18 @@ } }, "node_modules/@storybook/components": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/components/-/components-7.6.6.tgz", - "integrity": "sha512-FSfcRxdmV4+LJHjMk0eodGVnZdb2qrKKmbtsn0O/434z586zPA287/wJJsm4JS/Xr1WS9oTvU6mYMDChkcxgeQ==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/components/-/components-7.6.7.tgz", + "integrity": "sha512-1HN4p+MCI4Tx9VGZayZyqbW7SB7mXQLnS5fUbTE1gXaMYHpzFvcrRNROeV1LZPClJX6qx1jgE5ngZojhxGuxMA==", "dev": true, "dependencies": { "@radix-ui/react-select": "^1.2.2", "@radix-ui/react-toolbar": "^1.0.4", - "@storybook/client-logger": "7.6.6", + "@storybook/client-logger": "7.6.7", "@storybook/csf": "^0.1.2", "@storybook/global": "^5.0.0", - "@storybook/theming": "7.6.6", - "@storybook/types": "7.6.6", + "@storybook/theming": "7.6.7", + "@storybook/types": "7.6.7", "memoizerific": "^1.11.3", "use-resize-observer": "^9.1.0", "util-deprecate": "^1.0.2" @@ -5803,13 +5803,13 @@ } }, "node_modules/@storybook/core-client": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/core-client/-/core-client-7.6.6.tgz", - "integrity": "sha512-P100aNf+WpvzlfULZp1NPd60/nxsppLmft2DdIyAx1j4QPMZvUJyJB+hdBMzTFiPEhIUncIMoIVf2R3UXC5DfA==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/core-client/-/core-client-7.6.7.tgz", + "integrity": "sha512-ZQivyEzYsZok8vRj5Qan7LbiMUnO89rueWzTnZs4IS6JIaQtjoPI1rGVq+h6qOCM6tki478hic8FS+zwGQ6q+w==", "dev": true, "dependencies": { - "@storybook/client-logger": "7.6.6", - "@storybook/preview-api": "7.6.6" + "@storybook/client-logger": "7.6.7", + "@storybook/preview-api": "7.6.7" }, "funding": { "type": "opencollective", @@ -5817,17 +5817,17 @@ } }, "node_modules/@storybook/core-client/node_modules/@storybook/preview-api": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.6.tgz", - "integrity": "sha512-Bt6xIAR5yZ/JWc90X4BbLOA97iL65glZ1SOBgFFv2mHrdZ1lcdKhAlQr2aeJAf1mLvBtalPjvKzi9EuVY3FZ4w==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.7.tgz", + "integrity": "sha512-ja85ItrT6q2TeBQ6n0CNoRi1R6L8yF2kkis9hVeTQHpwLdZyHUTRqqR5WmhtLqqQXcofyasBPOeJV06wuOhgRQ==", "dev": true, "dependencies": { - "@storybook/channels": "7.6.6", - "@storybook/client-logger": "7.6.6", - "@storybook/core-events": "7.6.6", + "@storybook/channels": "7.6.7", + "@storybook/client-logger": "7.6.7", + "@storybook/core-events": "7.6.7", "@storybook/csf": "^0.1.2", "@storybook/global": "^5.0.0", - "@storybook/types": "7.6.6", + "@storybook/types": "7.6.7", "@types/qs": "^6.9.5", "dequal": "^2.0.2", "lodash": "^4.17.21", @@ -5843,14 +5843,14 @@ } }, "node_modules/@storybook/core-common": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-7.6.6.tgz", - "integrity": "sha512-DpbFSYw8LHuwpeU2ec5uWryxrSqslFJnWTfNA7AvpzCviWXkz4kq+YYrDee9XExF6OozNwILmG6m52SnraysBA==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-7.6.7.tgz", + "integrity": "sha512-F1fJnauVSPQtAlpicbN/O4XW38Ai8kf/IoU0Hgm9gEwurIk6MF5hiVLsaTI/5GUbrepMl9d9J+iIL4lHAT8IyA==", "dev": true, "dependencies": { - "@storybook/core-events": "7.6.6", - "@storybook/node-logger": "7.6.6", - "@storybook/types": "7.6.6", + "@storybook/core-events": "7.6.7", + "@storybook/node-logger": "7.6.7", + "@storybook/types": "7.6.7", "@types/find-cache-dir": "^3.2.1", "@types/node": "^18.0.0", "@types/node-fetch": "^2.6.4", @@ -5878,9 +5878,9 @@ } }, "node_modules/@storybook/core-common/node_modules/@types/node": { - "version": "18.19.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.3.tgz", - "integrity": "sha512-k5fggr14DwAytoA/t8rPrIz++lXK7/DqckthCmoZOKNsEbJkId4Z//BqgApXBUGrGddrigYa1oqheo/7YmW4rg==", + "version": "18.19.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.4.tgz", + "integrity": "sha512-xNzlUhzoHotIsnFoXmJB+yWmBvFZgKCI9TtPIEdYIMM1KWfwuY8zh7wvc1u1OAXlC7dlf6mZVx/s+Y5KfFz19A==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -5999,9 +5999,9 @@ } }, "node_modules/@storybook/core-events": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-7.6.6.tgz", - "integrity": "sha512-7+q9HiZiLxaQcwpaSLQrLdjHNHBoOoUY9ZcZXI9iNFSopOgb/ItDnzzlpv08NC7CbKae1hVKJM/t5aSTl7tCMw==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-7.6.7.tgz", + "integrity": "sha512-KZ5d03c47pnr5/kY26pJtWq7WpmCPXLbgyjJZDSc+TTY153BdZksvlBXRHtqM1yj2UM6QsSyIuiJaADJNAbP2w==", "dev": true, "dependencies": { "ts-dedent": "^2.0.0" @@ -6012,26 +6012,26 @@ } }, "node_modules/@storybook/core-server": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/core-server/-/core-server-7.6.6.tgz", - "integrity": "sha512-QFVahaExgGtq9swBXgQAMUiCqpCcyVXOiKTIy1j+1uAhPVqhpCxBkkFoXruih5hbIMZyohE4mLPCAr/ivicoDg==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/core-server/-/core-server-7.6.7.tgz", + "integrity": "sha512-elKRv/DNahNNkGcQY/FdOBrLPmZF0T0fwmAmbc4qqeAisjl+to9TO77zdo2ieaEHKyRwE3B3dOB4EXomdF4N/g==", "dev": true, "dependencies": { "@aw-web-design/x-default-browser": "1.4.126", "@discoveryjs/json-ext": "^0.5.3", - "@storybook/builder-manager": "7.6.6", - "@storybook/channels": "7.6.6", - "@storybook/core-common": "7.6.6", - "@storybook/core-events": "7.6.6", + "@storybook/builder-manager": "7.6.7", + "@storybook/channels": "7.6.7", + "@storybook/core-common": "7.6.7", + "@storybook/core-events": "7.6.7", "@storybook/csf": "^0.1.2", - "@storybook/csf-tools": "7.6.6", + "@storybook/csf-tools": "7.6.7", "@storybook/docs-mdx": "^0.1.0", "@storybook/global": "^5.0.0", - "@storybook/manager": "7.6.6", - "@storybook/node-logger": "7.6.6", - "@storybook/preview-api": "7.6.6", - "@storybook/telemetry": "7.6.6", - "@storybook/types": "7.6.6", + "@storybook/manager": "7.6.7", + "@storybook/node-logger": "7.6.7", + "@storybook/preview-api": "7.6.7", + "@storybook/telemetry": "7.6.7", + "@storybook/types": "7.6.7", "@types/detect-port": "^1.3.0", "@types/node": "^18.0.0", "@types/pretty-hrtime": "^1.0.0", @@ -6065,17 +6065,17 @@ } }, "node_modules/@storybook/core-server/node_modules/@storybook/preview-api": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.6.tgz", - "integrity": "sha512-Bt6xIAR5yZ/JWc90X4BbLOA97iL65glZ1SOBgFFv2mHrdZ1lcdKhAlQr2aeJAf1mLvBtalPjvKzi9EuVY3FZ4w==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.7.tgz", + "integrity": "sha512-ja85ItrT6q2TeBQ6n0CNoRi1R6L8yF2kkis9hVeTQHpwLdZyHUTRqqR5WmhtLqqQXcofyasBPOeJV06wuOhgRQ==", "dev": true, "dependencies": { - "@storybook/channels": "7.6.6", - "@storybook/client-logger": "7.6.6", - "@storybook/core-events": "7.6.6", + "@storybook/channels": "7.6.7", + "@storybook/client-logger": "7.6.7", + "@storybook/core-events": "7.6.7", "@storybook/csf": "^0.1.2", "@storybook/global": "^5.0.0", - "@storybook/types": "7.6.6", + "@storybook/types": "7.6.7", "@types/qs": "^6.9.5", "dequal": "^2.0.2", "lodash": "^4.17.21", @@ -6091,9 +6091,9 @@ } }, "node_modules/@storybook/core-server/node_modules/@types/node": { - "version": "18.19.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.3.tgz", - "integrity": "sha512-k5fggr14DwAytoA/t8rPrIz++lXK7/DqckthCmoZOKNsEbJkId4Z//BqgApXBUGrGddrigYa1oqheo/7YmW4rg==", + "version": "18.19.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.4.tgz", + "integrity": "sha512-xNzlUhzoHotIsnFoXmJB+yWmBvFZgKCI9TtPIEdYIMM1KWfwuY8zh7wvc1u1OAXlC7dlf6mZVx/s+Y5KfFz19A==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -6208,12 +6208,12 @@ } }, "node_modules/@storybook/csf-plugin": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-7.6.6.tgz", - "integrity": "sha512-SqdffT14+XNpf+7vA29Elur28VArXtFv4cXMlsCbswbRuY+a0A8vYNwVIfCUy9u4WHTcQX1/tUkDAMh80lrVRQ==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/csf-plugin/-/csf-plugin-7.6.7.tgz", + "integrity": "sha512-YL7e6H4iVcsDI0UpgpdQX2IiGDrlbgaQMHQgDLWXmZyKxBcy0ONROAX5zoT1ml44EHkL60TMaG4f7SinviJCog==", "dev": true, "dependencies": { - "@storybook/csf-tools": "7.6.6", + "@storybook/csf-tools": "7.6.7", "unplugin": "^1.3.1" }, "funding": { @@ -6222,9 +6222,9 @@ } }, "node_modules/@storybook/csf-tools": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-7.6.6.tgz", - "integrity": "sha512-VXOZCzfSVJL832u17pPhFu1x3PPaAN9d8VXNFX+t/2raga7tK3T7Qhe7lWfP7EZcrVvSCEEp0aMRz2EzzDGVtw==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-7.6.7.tgz", + "integrity": "sha512-hyRbUGa2Uxvz3U09BjcOfMNf/5IYgRum1L6XszqK2O8tK9DGte1r6hArCIAcqiEmFMC40d0kalPzqu6WMNn7sg==", "dev": true, "dependencies": { "@babel/generator": "^7.23.0", @@ -6232,7 +6232,7 @@ "@babel/traverse": "^7.23.2", "@babel/types": "^7.23.0", "@storybook/csf": "^0.1.2", - "@storybook/types": "7.6.6", + "@storybook/types": "7.6.7", "fs-extra": "^11.1.0", "recast": "^0.23.1", "ts-dedent": "^2.0.0" @@ -6263,14 +6263,14 @@ "dev": true }, "node_modules/@storybook/docs-tools": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/docs-tools/-/docs-tools-7.6.6.tgz", - "integrity": "sha512-nc5ZjN2s8SC2PtsZoFf9Wm6gD8TcSlkYbF/mjtyLCGN+Fi+k5B5iudqoa65H19hwiLlzBdcnpQ8C89AiK33J9Q==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/docs-tools/-/docs-tools-7.6.7.tgz", + "integrity": "sha512-enTO/xVjBqwUraGCYTwdyjMvug3OSAM7TPPUEJ3KPieJNwAzcYkww/qNDMIAR4S39zPMrkAmtS3STvVadlJz7g==", "dev": true, "dependencies": { - "@storybook/core-common": "7.6.6", - "@storybook/preview-api": "7.6.6", - "@storybook/types": "7.6.6", + "@storybook/core-common": "7.6.7", + "@storybook/preview-api": "7.6.7", + "@storybook/types": "7.6.7", "@types/doctrine": "^0.0.3", "assert": "^2.1.0", "doctrine": "^3.0.0", @@ -6282,17 +6282,17 @@ } }, "node_modules/@storybook/docs-tools/node_modules/@storybook/preview-api": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.6.tgz", - "integrity": "sha512-Bt6xIAR5yZ/JWc90X4BbLOA97iL65glZ1SOBgFFv2mHrdZ1lcdKhAlQr2aeJAf1mLvBtalPjvKzi9EuVY3FZ4w==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.7.tgz", + "integrity": "sha512-ja85ItrT6q2TeBQ6n0CNoRi1R6L8yF2kkis9hVeTQHpwLdZyHUTRqqR5WmhtLqqQXcofyasBPOeJV06wuOhgRQ==", "dev": true, "dependencies": { - "@storybook/channels": "7.6.6", - "@storybook/client-logger": "7.6.6", - "@storybook/core-events": "7.6.6", + "@storybook/channels": "7.6.7", + "@storybook/client-logger": "7.6.7", + "@storybook/core-events": "7.6.7", "@storybook/csf": "^0.1.2", "@storybook/global": "^5.0.0", - "@storybook/types": "7.6.6", + "@storybook/types": "7.6.7", "@types/qs": "^6.9.5", "dequal": "^2.0.2", "lodash": "^4.17.21", @@ -6314,9 +6314,9 @@ "dev": true }, "node_modules/@storybook/manager": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/manager/-/manager-7.6.6.tgz", - "integrity": "sha512-Ga3LcSu/xxSyg+cLlO9AS8QjW+D667V+c9qQPmsFyU6qfFc6m6mVqcRLSmFVD5e7P/o0FL7STOf9jAKkDcW8xw==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/manager/-/manager-7.6.7.tgz", + "integrity": "sha512-ZCrkB2zEXogzdOcVzD242ZVm4tlHqrayotnI6iOn9uiun0Pgny0m2d7s9Zge6K2dTOO1vZiOHuA/Mr6nnIDjsA==", "dev": true, "funding": { "type": "opencollective", @@ -6324,23 +6324,22 @@ } }, "node_modules/@storybook/manager-api": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/manager-api/-/manager-api-7.6.6.tgz", - "integrity": "sha512-euRAbSZAUzHDt6z1Pq/g45N/RNqta9RaQAym18zt/oLWiYOIrkLmdf7kCuFYsmuA5XQBytiJqwkAD7uF1aLe0g==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/manager-api/-/manager-api-7.6.7.tgz", + "integrity": "sha512-3Wk/BvuGUlw/X05s57zZO7gJbzfUeE9Xe+CSIvuH7RY5jx9PYnNwqNlTXPXhJ5LPvwMthae7WJVn3SuBpbptoQ==", "dev": true, "dependencies": { - "@storybook/channels": "7.6.6", - "@storybook/client-logger": "7.6.6", - "@storybook/core-events": "7.6.6", + "@storybook/channels": "7.6.7", + "@storybook/client-logger": "7.6.7", + "@storybook/core-events": "7.6.7", "@storybook/csf": "^0.1.2", "@storybook/global": "^5.0.0", - "@storybook/router": "7.6.6", - "@storybook/theming": "7.6.6", - "@storybook/types": "7.6.6", + "@storybook/router": "7.6.7", + "@storybook/theming": "7.6.7", + "@storybook/types": "7.6.7", "dequal": "^2.0.2", "lodash": "^4.17.21", "memoizerific": "^1.11.3", - "semver": "^7.3.7", "store2": "^2.14.2", "telejson": "^7.2.0", "ts-dedent": "^2.0.0" @@ -6350,39 +6349,6 @@ "url": "https://opencollective.com/storybook" } }, - "node_modules/@storybook/manager-api/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@storybook/manager-api/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@storybook/manager-api/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@storybook/mdx2-csf": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@storybook/mdx2-csf/-/mdx2-csf-1.1.0.tgz", @@ -6390,9 +6356,9 @@ "dev": true }, "node_modules/@storybook/node-logger": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-7.6.6.tgz", - "integrity": "sha512-b2OF9GRNI01MlBlnDGS8S6/yOpBNl8eH/0ONafuMPzFEZs5PouHGsFflJvQwwcdVTknMjF5uVS2eSmnLZ8spvA==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-7.6.7.tgz", + "integrity": "sha512-XLih8MxylkpZG9+8tgp8sPGc2tldlWF+DpuAkUv6J3Mc81mPyc3cQKQWZ7Hb+m1LpRGqKV4wyOQj1rC+leVMoQ==", "dev": true, "funding": { "type": "opencollective", @@ -6400,9 +6366,9 @@ } }, "node_modules/@storybook/postinstall": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/postinstall/-/postinstall-7.6.6.tgz", - "integrity": "sha512-jamn7QNTJPZiu22nu25LqfSTJohugFhCu4b48yqP+pdMdkQ3qVd3NdDYhBlgkH/Btar+kppiJP1gRtoiJF761w==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/postinstall/-/postinstall-7.6.7.tgz", + "integrity": "sha512-mrpRmcwFd9FcvtHPXA9x6vOrHLVCKScZX/Xx2QPWgAvB3W6uzP8G+8QNb1u834iToxrWeuszUMB9UXZK4Qj5yg==", "dev": true, "funding": { "type": "opencollective", @@ -6410,9 +6376,9 @@ } }, "node_modules/@storybook/preview": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/preview/-/preview-7.6.6.tgz", - "integrity": "sha512-Rl+Pom2bNwzc0MdlbFALmvxsbCkbIwlpTZlRZZTh5Ah8JViV9htQgP9e8uwo3NZA2BhjbDLkmnZeloWxQnI5Ig==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/preview/-/preview-7.6.7.tgz", + "integrity": "sha512-/ddKIyT+6b8CKGJAma1wood4nwCAoi/E1olCqgpCmviMeUtAiMzgK0xzPwvq5Mxkz/cPeXVi8CQgaQZCa4yvNA==", "dev": true, "funding": { "type": "opencollective", @@ -6506,9 +6472,9 @@ } }, "node_modules/@storybook/react-dom-shim": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-7.6.6.tgz", - "integrity": "sha512-WWNlXtCVoBWXX/kLNulUeMgzmlAEHi2aBrdIv2jz0DScPf0YxeWAkWmgK7F0zMot9mdwYncr+pk1AILbTBJSyg==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/react-dom-shim/-/react-dom-shim-7.6.7.tgz", + "integrity": "sha512-b/rmy/YzVrwP+ifyZG4yXVIdeFVdTbmziodHUlbrWiUNsqtTZZur9kqkKRUH/7ofji9MFe81nd0MRlcTNFomqg==", "dev": true, "funding": { "type": "opencollective", @@ -6520,12 +6486,12 @@ } }, "node_modules/@storybook/router": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/router/-/router-7.6.6.tgz", - "integrity": "sha512-dkn81MtxrG7JMDbOHEcVZkTDVKsneg72CyqJ8ELZfC81iKQcDMQkV9mdmnMl45aKn6UrscudI4K23OxQmsevkw==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/router/-/router-7.6.7.tgz", + "integrity": "sha512-kkhNSdC3fXaQxILg8a26RKk4/ZbF/AUVrepUEyO8lwvbJ6LItTyWSE/4I9Ih4qV2Mjx33ncc8vLqM9p8r5qnMA==", "dev": true, "dependencies": { - "@storybook/client-logger": "7.6.6", + "@storybook/client-logger": "7.6.7", "memoizerific": "^1.11.3", "qs": "^6.10.0" }, @@ -6535,14 +6501,14 @@ } }, "node_modules/@storybook/telemetry": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/telemetry/-/telemetry-7.6.6.tgz", - "integrity": "sha512-2WdDcrMrt1bPVgdMVO0tFmVxT6YIjiPRfKbH/7wwYMOGmV75m4mJ9Ha2gzZc/oXTSK1M4/fiK12IgW+S3ErcMg==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/telemetry/-/telemetry-7.6.7.tgz", + "integrity": "sha512-NHGzC/LGLXpK4AFbVj8ln5ab86ZiiNFvORQMn3+LNGwUt3ZdsHBzExN+WPZdw7OPtfk4ubUY89FXH2GedhTALw==", "dev": true, "dependencies": { - "@storybook/client-logger": "7.6.6", - "@storybook/core-common": "7.6.6", - "@storybook/csf-tools": "7.6.6", + "@storybook/client-logger": "7.6.7", + "@storybook/core-common": "7.6.7", + "@storybook/csf-tools": "7.6.7", "chalk": "^4.1.0", "detect-package-manager": "^2.0.1", "fetch-retry": "^5.0.2", @@ -6621,13 +6587,13 @@ } }, "node_modules/@storybook/theming": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-7.6.6.tgz", - "integrity": "sha512-hNZOOxaF55iAGUEM0dvAIP6LfGMgPKCJQIk/qyotFk+SKkg3PBqzph89XfFl9yCD3KiX5cryqarULgVuNawLJg==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-7.6.7.tgz", + "integrity": "sha512-+42rfC4rZtWVAXJ7JBUQKnQ6vWBXJVHZ9HtNUWzQLPR9sJSMmHnnSMV6y5tizGgZqmBnAIkuoYk+Tt6NfwUmSA==", "dev": true, "dependencies": { "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", - "@storybook/client-logger": "7.6.6", + "@storybook/client-logger": "7.6.7", "@storybook/global": "^5.0.0", "memoizerific": "^1.11.3" }, @@ -6641,12 +6607,12 @@ } }, "node_modules/@storybook/types": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/types/-/types-7.6.6.tgz", - "integrity": "sha512-77vbQp3GX93OD8UzFkY4a0fAmkZrqLe61XVo6yABrwbVDY0EcAwaCF5gcXRhOHldlH7KYbLfEQkDkkKTBjX7ow==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/types/-/types-7.6.7.tgz", + "integrity": "sha512-VcGwrI4AkBENxkoAUJ+Z7SyMK73hpoY0TTtw2J7tc05/xdiXhkQTX15Qa12IBWIkoXCyNrtaU+q7KR8Tjzi+uw==", "dev": true, "dependencies": { - "@storybook/channels": "7.6.6", + "@storybook/channels": "7.6.7", "@types/babel__core": "^7.0.0", "@types/express": "^4.7.0", "file-system-cache": "2.3.0" @@ -6657,18 +6623,18 @@ } }, "node_modules/@storybook/web-components": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/web-components/-/web-components-7.6.6.tgz", - "integrity": "sha512-oBfZBM1Vkzs/rZySk/HXCIRZ10FSYx6wgyMbiT5EmGm7Jz9y5qaqQhG/sPYKsYL0TlPRRKjf1iukHkxD6DWmpA==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/web-components/-/web-components-7.6.7.tgz", + "integrity": "sha512-TrBhMctSIgV2qqyV7fhhaNIdAvuaca2jEDXLXFiH/M2NkyXRepNjG7AZndWhQUGvG01ojs1+2vRNqJZtKCmFDg==", "dev": true, "dependencies": { - "@storybook/client-logger": "7.6.6", - "@storybook/core-client": "7.6.6", - "@storybook/docs-tools": "7.6.6", + "@storybook/client-logger": "7.6.7", + "@storybook/core-client": "7.6.7", + "@storybook/docs-tools": "7.6.7", "@storybook/global": "^5.0.0", - "@storybook/manager-api": "7.6.6", - "@storybook/preview-api": "7.6.6", - "@storybook/types": "7.6.6", + "@storybook/manager-api": "7.6.7", + "@storybook/preview-api": "7.6.7", + "@storybook/types": "7.6.7", "tiny-invariant": "^1.3.1", "ts-dedent": "^2.0.0" }, @@ -6684,15 +6650,15 @@ } }, "node_modules/@storybook/web-components-vite": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/web-components-vite/-/web-components-vite-7.6.6.tgz", - "integrity": "sha512-AOxvnA7eIRnKqZ21QgUHJ/ENX1MMhJCKPiytvkX8U02gs+0HE+NnZPbhZLPh/Ruax7KfLPUGItv3BcfrIxV5lw==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/web-components-vite/-/web-components-vite-7.6.7.tgz", + "integrity": "sha512-jfnVNhmgDYBdEnOliNcfo9FwfDDke66y6Zw2zkOz9qhJy8DCd5TzgDEmE7AU2XRzb1a464A90xfvJpvlUracfA==", "dev": true, "dependencies": { - "@storybook/builder-vite": "7.6.6", - "@storybook/core-server": "7.6.6", - "@storybook/node-logger": "7.6.6", - "@storybook/web-components": "7.6.6", + "@storybook/builder-vite": "7.6.7", + "@storybook/core-server": "7.6.7", + "@storybook/node-logger": "7.6.7", + "@storybook/web-components": "7.6.7", "magic-string": "^0.30.0" }, "engines": { @@ -6704,17 +6670,17 @@ } }, "node_modules/@storybook/web-components/node_modules/@storybook/preview-api": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.6.tgz", - "integrity": "sha512-Bt6xIAR5yZ/JWc90X4BbLOA97iL65glZ1SOBgFFv2mHrdZ1lcdKhAlQr2aeJAf1mLvBtalPjvKzi9EuVY3FZ4w==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/@storybook/preview-api/-/preview-api-7.6.7.tgz", + "integrity": "sha512-ja85ItrT6q2TeBQ6n0CNoRi1R6L8yF2kkis9hVeTQHpwLdZyHUTRqqR5WmhtLqqQXcofyasBPOeJV06wuOhgRQ==", "dev": true, "dependencies": { - "@storybook/channels": "7.6.6", - "@storybook/client-logger": "7.6.6", - "@storybook/core-events": "7.6.6", + "@storybook/channels": "7.6.7", + "@storybook/client-logger": "7.6.7", + "@storybook/core-events": "7.6.7", "@storybook/csf": "^0.1.2", "@storybook/global": "^5.0.0", - "@storybook/types": "7.6.6", + "@storybook/types": "7.6.7", "@types/qs": "^6.9.5", "dequal": "^2.0.2", "lodash": "^4.17.21", @@ -8077,15 +8043,12 @@ } }, "node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", + "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==", "dev": true, - "dependencies": { - "debug": "^4.3.4" - }, "engines": { - "node": ">= 14" + "node": ">= 6.0.0" } }, "node_modules/aggregate-error": { @@ -8878,6 +8841,15 @@ "node": ">=8" } }, + "node_modules/citty": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.5.tgz", + "integrity": "sha512-AS7n5NSc0OQVMV9v6wt3ByujNIrne0/cTjiC2MYqhvao57VNfiuVksTSr2p17nVOhEr2KtqiAkGwHcgMC/qUuQ==", + "dev": true, + "dependencies": { + "consola": "^3.2.3" + } + }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -9134,6 +9106,15 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/consola": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", + "integrity": "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==", + "dev": true, + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, "node_modules/construct-style-sheets-polyfill": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/construct-style-sheets-polyfill/-/construct-style-sheets-polyfill-3.1.0.tgz", @@ -11466,9 +11447,9 @@ "dev": true }, "node_modules/flow-parser": { - "version": "0.225.0", - "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.225.0.tgz", - "integrity": "sha512-wTr10/1z9wBuaNf+RGdGwD5FOI6TsNcWrMDhE+JBc2vEKe1e4SZuO5zVZCBq9SrFqPyWy0wFO9+hTH4zuPDbMA==", + "version": "0.225.1", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.225.1.tgz", + "integrity": "sha512-50fjR6zbLQcpq5IFNkheUSY/AFPxVeeLiBM5B3NQBSKId2G0cUuExOlDDOguxc49dl9lnh8hI1xcYlPJWNp4KQ==", "dev": true, "engines": { "node": ">=0.4.0" @@ -11789,16 +11770,17 @@ } }, "node_modules/giget": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/giget/-/giget-1.1.3.tgz", - "integrity": "sha512-zHuCeqtfgqgDwvXlR84UNgnJDuUHQcNI5OqWqFxxuk2BshuKbYhJWdxBsEo4PvKqoGh23lUAIvBNpChMLv7/9Q==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/giget/-/giget-1.2.1.tgz", + "integrity": "sha512-4VG22mopWtIeHwogGSy1FViXVo0YT+m6BrqZfz0JJFwbSsePsCdOzdLIIli5BtMp7Xe8f/o2OmBpQX2NBOC24g==", "dev": true, "dependencies": { - "colorette": "^2.0.20", - "defu": "^6.1.2", - "https-proxy-agent": "^7.0.2", - "mri": "^1.2.0", - "node-fetch-native": "^1.4.0", + "citty": "^0.1.5", + "consola": "^3.2.3", + "defu": "^6.1.3", + "node-fetch-native": "^1.6.1", + "nypm": "^0.3.3", + "ohash": "^1.1.3", "pathe": "^1.1.1", "tar": "^6.2.0" }, @@ -11806,12 +11788,6 @@ "giget": "dist/cli.mjs" } }, - "node_modules/giget/node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true - }, "node_modules/github-from-package": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", @@ -12141,16 +12117,16 @@ } }, "node_modules/https-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", - "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", + "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==", "dev": true, "dependencies": { - "agent-base": "^7.0.2", + "agent-base": "5", "debug": "4" }, "engines": { - "node": ">= 14" + "node": ">= 6.0.0" } }, "node_modules/human-signals": { @@ -14608,9 +14584,9 @@ } }, "node_modules/node-fetch-native": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.4.1.tgz", - "integrity": "sha512-NsXBU0UgBxo2rQLOeWNZqS3fvflWePMECr8CoSWoSTqCqGbVVsvl9vZu1HfQicYN0g5piV9Gh8RTEvo/uP752w==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.1.tgz", + "integrity": "sha512-bW9T/uJDPAJB2YNYEpWzE54U5O3MQidXsOyTfnbKYtTtFexRvGzb1waphBN4ZwP6EcIvYYEOwW0b72BpAqydTw==", "dev": true }, "node_modules/node-int64": { @@ -14764,6 +14740,158 @@ "node": ">=8" } }, + "node_modules/nypm": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.3.4.tgz", + "integrity": "sha512-1JLkp/zHBrkS3pZ692IqOaIKSYHmQXgqfELk6YTOfVBnwealAmPA1q2kKK7PHJAHSMBozerThEFZXP3G6o7Ukg==", + "dev": true, + "dependencies": { + "citty": "^0.1.5", + "execa": "^8.0.1", + "pathe": "^1.1.1", + "ufo": "^1.3.2" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": "^14.16.0 || >=16.10.0" + } + }, + "node_modules/nypm/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/nypm/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/nypm/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm/node_modules/npm-run-path": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", + "integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nypm/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nypm/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -14824,6 +14952,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/ohash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-1.1.3.tgz", + "integrity": "sha512-zuHHiGTYTA1sYJ/wZN+t5HKZaH23i4yI1HMwbuXm24Nid7Dv0KcuRlKoNKS9UNfAVSBlnGLcuQrnOKWOZoEGaw==", + "dev": true + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -15538,15 +15672,6 @@ "node": ">=8.16.0" } }, - "node_modules/puppeteer-core/node_modules/agent-base": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", - "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==", - "dev": true, - "engines": { - "node": ">= 6.0.0" - } - }, "node_modules/puppeteer-core/node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -15567,19 +15692,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/puppeteer-core/node_modules/https-proxy-agent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", - "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==", - "dev": true, - "dependencies": { - "agent-base": "5", - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, "node_modules/puppeteer-core/node_modules/mime": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", @@ -16987,12 +17099,12 @@ "dev": true }, "node_modules/storybook": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/storybook/-/storybook-7.6.6.tgz", - "integrity": "sha512-PmJxpjGdLvDOHaRzqLOvcJ3ALQPaNeW6D5Lv7rPPVbuO24wdDzd/75dPRP7gJKYcGE0NnDZ6cLQq3UlCfbkIBA==", + "version": "7.6.7", + "resolved": "https://registry.npmjs.org/storybook/-/storybook-7.6.7.tgz", + "integrity": "sha512-1Cd895dqYIT5MOUOCDlD73OTWoJubLq/sWC7AMzkMrLu76yD4Cu6f+wv1HDrRAheRaCaeT3yhYEhsMB6qHIcaA==", "dev": true, "dependencies": { - "@storybook/cli": "7.6.6" + "@storybook/cli": "7.6.7" }, "bin": { "sb": "index.js", @@ -17936,6 +18048,12 @@ "node": ">=14.17" } }, + "node_modules/ufo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.2.tgz", + "integrity": "sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==", + "dev": true + }, "node_modules/uglify-js": { "version": "3.17.4", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", diff --git a/web/package.json b/web/package.json index da7a1004c..92cb66ec9 100644 --- a/web/package.json +++ b/web/package.json @@ -87,13 +87,13 @@ "@rollup/plugin-replace": "^5.0.5", "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^11.1.5", - "@storybook/addon-essentials": "^7.6.6", - "@storybook/addon-links": "^7.6.6", - "@storybook/api": "^7.6.6", + "@storybook/addon-essentials": "^7.6.7", + "@storybook/addon-links": "^7.6.7", + "@storybook/api": "^7.6.7", "@storybook/blocks": "^7.6.4", - "@storybook/manager-api": "^7.6.6", - "@storybook/web-components": "^7.6.6", - "@storybook/web-components-vite": "^7.6.6", + "@storybook/manager-api": "^7.6.7", + "@storybook/web-components": "^7.6.7", + "@storybook/web-components-vite": "^7.6.7", "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@types/chart.js": "^2.9.41", "@types/codemirror": "5.60.15", @@ -122,7 +122,7 @@ "rollup-plugin-cssimport": "^1.0.3", "rollup-plugin-modify": "^3.0.0", "rollup-plugin-postcss-lit": "^2.1.0", - "storybook": "^7.6.6", + "storybook": "^7.6.7", "storybook-addon-mock": "^4.3.0", "ts-lit-plugin": "^2.0.1", "tslib": "^2.6.2", From aa1bb7b9c922075f8436ddc881e810c694a492c5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Jan 2024 11:36:18 +0100 Subject: [PATCH 29/31] web: bump the eslint group in /tests/wdio with 2 updates (#8041) Bumps the eslint group in /tests/wdio with 2 updates: [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) and [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser). Updates `@typescript-eslint/eslint-plugin` from 6.16.0 to 6.17.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.17.0/packages/eslint-plugin) Updates `@typescript-eslint/parser` from 6.16.0 to 6.17.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v6.17.0/packages/parser) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: eslint - dependency-name: "@typescript-eslint/parser" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: eslint ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- tests/wdio/package-lock.json | 88 ++++++++++++++++++------------------ tests/wdio/package.json | 4 +- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/tests/wdio/package-lock.json b/tests/wdio/package-lock.json index 486739f5c..3d56efbe1 100644 --- a/tests/wdio/package-lock.json +++ b/tests/wdio/package-lock.json @@ -7,8 +7,8 @@ "name": "@goauthentik/web-tests", "devDependencies": { "@trivago/prettier-plugin-sort-imports": "^4.3.0", - "@typescript-eslint/eslint-plugin": "^6.16.0", - "@typescript-eslint/parser": "^6.16.0", + "@typescript-eslint/eslint-plugin": "^6.17.0", + "@typescript-eslint/parser": "^6.17.0", "@wdio/cli": "^8.27.1", "@wdio/local-runner": "^8.27.0", "@wdio/mocha-framework": "^8.27.0", @@ -946,16 +946,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.16.0.tgz", - "integrity": "sha512-O5f7Kv5o4dLWQtPX4ywPPa+v9G+1q1x8mz0Kr0pXUtKsevo+gIJHLkGc8RxaZWtP8RrhwhSNIWThnW42K9/0rQ==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.17.0.tgz", + "integrity": "sha512-Vih/4xLXmY7V490dGwBQJTpIZxH4ZFH6eCVmQ4RFkB+wmaCTDAx4dtgoWwMNGKLkqRY1L6rPqzEbjorRnDo4rQ==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.16.0", - "@typescript-eslint/type-utils": "6.16.0", - "@typescript-eslint/utils": "6.16.0", - "@typescript-eslint/visitor-keys": "6.16.0", + "@typescript-eslint/scope-manager": "6.17.0", + "@typescript-eslint/type-utils": "6.17.0", + "@typescript-eslint/utils": "6.17.0", + "@typescript-eslint/visitor-keys": "6.17.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -981,15 +981,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.16.0.tgz", - "integrity": "sha512-H2GM3eUo12HpKZU9njig3DF5zJ58ja6ahj1GoHEHOgQvYxzoFJJEvC1MQ7T2l9Ha+69ZSOn7RTxOdpC/y3ikMw==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.17.0.tgz", + "integrity": "sha512-C4bBaX2orvhK+LlwrY8oWGmSl4WolCfYm513gEccdWZj0CwGadbIADb0FtVEcI+WzUyjyoBj2JRP8g25E6IB8A==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.16.0", - "@typescript-eslint/types": "6.16.0", - "@typescript-eslint/typescript-estree": "6.16.0", - "@typescript-eslint/visitor-keys": "6.16.0", + "@typescript-eslint/scope-manager": "6.17.0", + "@typescript-eslint/types": "6.17.0", + "@typescript-eslint/typescript-estree": "6.17.0", + "@typescript-eslint/visitor-keys": "6.17.0", "debug": "^4.3.4" }, "engines": { @@ -1009,13 +1009,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.16.0.tgz", - "integrity": "sha512-0N7Y9DSPdaBQ3sqSCwlrm9zJwkpOuc6HYm7LpzLAPqBL7dmzAUimr4M29dMkOP/tEwvOCC/Cxo//yOfJD3HUiw==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.17.0.tgz", + "integrity": "sha512-RX7a8lwgOi7am0k17NUO0+ZmMOX4PpjLtLRgLmT1d3lBYdWH4ssBUbwdmc5pdRX8rXon8v9x8vaoOSpkHfcXGA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.16.0", - "@typescript-eslint/visitor-keys": "6.16.0" + "@typescript-eslint/types": "6.17.0", + "@typescript-eslint/visitor-keys": "6.17.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1026,13 +1026,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.16.0.tgz", - "integrity": "sha512-ThmrEOcARmOnoyQfYkHw/DX2SEYBalVECmoldVuH6qagKROp/jMnfXpAU/pAIWub9c4YTxga+XwgAkoA0pxfmg==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.17.0.tgz", + "integrity": "sha512-hDXcWmnbtn4P2B37ka3nil3yi3VCQO2QEB9gBiHJmQp5wmyQWqnjA85+ZcE8c4FqnaB6lBwMrPkgd4aBYz3iNg==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.16.0", - "@typescript-eslint/utils": "6.16.0", + "@typescript-eslint/typescript-estree": "6.17.0", + "@typescript-eslint/utils": "6.17.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -1053,9 +1053,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.16.0.tgz", - "integrity": "sha512-hvDFpLEvTJoHutVl87+MG/c5C8I6LOgEx05zExTSJDEVU7hhR3jhV8M5zuggbdFCw98+HhZWPHZeKS97kS3JoQ==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.17.0.tgz", + "integrity": "sha512-qRKs9tvc3a4RBcL/9PXtKSehI/q8wuU9xYJxe97WFxnzH8NWWtcW3ffNS+EWg8uPvIerhjsEZ+rHtDqOCiH57A==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1066,13 +1066,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.16.0.tgz", - "integrity": "sha512-VTWZuixh/vr7nih6CfrdpmFNLEnoVBF1skfjdyGnNwXOH1SLeHItGdZDHhhAIzd3ACazyY2Fg76zuzOVTaknGA==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.17.0.tgz", + "integrity": "sha512-gVQe+SLdNPfjlJn5VNGhlOhrXz4cajwFd5kAgWtZ9dCZf4XJf8xmgCTLIqec7aha3JwgLI2CK6GY1043FRxZwg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.16.0", - "@typescript-eslint/visitor-keys": "6.16.0", + "@typescript-eslint/types": "6.17.0", + "@typescript-eslint/visitor-keys": "6.17.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1118,17 +1118,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.16.0.tgz", - "integrity": "sha512-T83QPKrBm6n//q9mv7oiSvy/Xq/7Hyw9SzSEhMHJwznEmQayfBM87+oAlkNAMEO7/MjIwKyOHgBJbxB0s7gx2A==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.17.0.tgz", + "integrity": "sha512-LofsSPjN/ITNkzV47hxas2JCsNCEnGhVvocfyOcLzT9c/tSZE7SfhS/iWtzP1lKNOEfLhRTZz6xqI8N2RzweSQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.16.0", - "@typescript-eslint/types": "6.16.0", - "@typescript-eslint/typescript-estree": "6.16.0", + "@typescript-eslint/scope-manager": "6.17.0", + "@typescript-eslint/types": "6.17.0", + "@typescript-eslint/typescript-estree": "6.17.0", "semver": "^7.5.4" }, "engines": { @@ -1143,12 +1143,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.16.0.tgz", - "integrity": "sha512-QSFQLruk7fhs91a/Ep/LqRdbJCZ1Rq03rqBdKT5Ky17Sz8zRLUksqIe9DW0pKtg/Z35/ztbLQ6qpOCN6rOC11A==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.17.0.tgz", + "integrity": "sha512-H6VwB/k3IuIeQOyYczyyKN8wH6ed8EwliaYHLxOIhyF0dYEIsN8+Bk3GE19qafeMKyZJJHP8+O1HiFhFLUNKSg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.16.0", + "@typescript-eslint/types": "6.17.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { diff --git a/tests/wdio/package.json b/tests/wdio/package.json index 9e0cc07b2..768dabac3 100644 --- a/tests/wdio/package.json +++ b/tests/wdio/package.json @@ -4,8 +4,8 @@ "type": "module", "devDependencies": { "@trivago/prettier-plugin-sort-imports": "^4.3.0", - "@typescript-eslint/eslint-plugin": "^6.16.0", - "@typescript-eslint/parser": "^6.16.0", + "@typescript-eslint/eslint-plugin": "^6.17.0", + "@typescript-eslint/parser": "^6.17.0", "@wdio/cli": "^8.27.1", "@wdio/local-runner": "^8.27.0", "@wdio/mocha-framework": "^8.27.0", From 1a6077c0742665ad5e6a004ec6978458cb885fa0 Mon Sep 17 00:00:00 2001 From: "transifex-integration[bot]" <43880903+transifex-integration[bot]@users.noreply.github.com> Date: Tue, 2 Jan 2024 16:28:22 +0000 Subject: [PATCH 30/31] translate: Updates for file web/xliff/en.xlf in fr (#8046) Translate web/xliff/en.xlf in fr 100% translated source file: 'web/xliff/en.xlf' on 'fr'. Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com> --- web/xliff/fr.xlf | 108 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 74 insertions(+), 34 deletions(-) diff --git a/web/xliff/fr.xlf b/web/xliff/fr.xlf index f808bbde3..407618e65 100644 --- a/web/xliff/fr.xlf +++ b/web/xliff/fr.xlf @@ -1,4 +1,4 @@ - + @@ -613,9 +613,9 @@ Il y a jour(s) - The URL "" was not found. - L'URL " - " n'a pas été trouvée. + The URL "" was not found. + L'URL " + " n'a pas été trouvée. @@ -1057,8 +1057,8 @@ Il y a jour(s) - To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. - Pour permettre n'importe quelle URI de redirection, définissez cette valeur sur ".*". Soyez conscient des possibles implications de sécurité que cela peut avoir. + To allow any redirect URI, set this value to ".*". Be aware of the possible security implications this can have. + Pour permettre n'importe quelle URI de redirection, définissez cette valeur sur ".*". Soyez conscient des possibles implications de sécurité que cela peut avoir. @@ -1630,7 +1630,7 @@ Il y a jour(s) Token to authenticate with. Currently only bearer authentication is supported. - Jeton d'authentification à utiliser. Actuellement, seule l'authentification "bearer authentication" est prise en charge. + Jeton d'authentification à utiliser. Actuellement, seule l'authentification "bearer authentication" est prise en charge. @@ -1798,8 +1798,8 @@ Il y a jour(s) - Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". - Entrez une URL complète, un chemin relatif ou utilisez 'fa://fa-test' pour utiliser l'icône Font Awesome "fa-test". + Either input a full URL, a relative path, or use 'fa://fa-test' to use the Font Awesome icon "fa-test". + Entrez une URL complète, un chemin relatif ou utilisez 'fa://fa-test' pour utiliser l'icône Font Awesome "fa-test". @@ -2892,7 +2892,7 @@ doesn't pass when either or both of the selected options are equal or above the To use SSL instead, use 'ldaps://' and disable this option. - Pour utiliser SSL à la base, utilisez "ldaps://" et désactviez cette option. + Pour utiliser SSL à la base, utilisez "ldaps://" et désactviez cette option. @@ -2981,8 +2981,8 @@ doesn't pass when either or both of the selected options are equal or above the - Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' - Champ qui contient les membres d'un groupe. Si vous utilisez le champ "memberUid", la valeur est censée contenir un nom distinctif relatif, par exemple 'memberUid=un-utilisateur' au lieu de 'memberUid=cn=un-utilisateur,ou=groups,...' + Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...' + Champ qui contient les membres d'un groupe. Si vous utilisez le champ "memberUid", la valeur est censée contenir un nom distinctif relatif, par exemple 'memberUid=un-utilisateur' au lieu de 'memberUid=cn=un-utilisateur,ou=groups,...' @@ -3277,7 +3277,7 @@ doesn't pass when either or both of the selected options are equal or above the Time offset when temporary users should be deleted. This only applies if your IDP uses the NameID Format 'transient', and the user doesn't log out manually. - Moment où les utilisateurs temporaires doivent être supprimés. Cela ne s'applique que si votre IDP utilise le format NameID "transient" et que l'utilisateur ne se déconnecte pas manuellement. + Moment où les utilisateurs temporaires doivent être supprimés. Cela ne s'applique que si votre IDP utilise le format NameID "transient" et que l'utilisateur ne se déconnecte pas manuellement. @@ -3445,7 +3445,7 @@ doesn't pass when either or both of the selected options are equal or above the Optionally set the 'FriendlyName' value of the Assertion attribute. - Indiquer la valeur "FriendlyName" de l'attribut d'assertion (optionnel) + Indiquer la valeur "FriendlyName" de l'attribut d'assertion (optionnel) @@ -3774,8 +3774,8 @@ doesn't pass when either or both of the selected options are equal or above the - When using an external logging solution for archiving, this can be set to "minutes=5". - En cas d'utilisation d'une solution de journalisation externe pour l'archivage, cette valeur peut être fixée à "minutes=5". + When using an external logging solution for archiving, this can be set to "minutes=5". + En cas d'utilisation d'une solution de journalisation externe pour l'archivage, cette valeur peut être fixée à "minutes=5". @@ -3784,8 +3784,8 @@ doesn't pass when either or both of the selected options are equal or above the - Format: "weeks=3;days=2;hours=3,seconds=2". - Format : "weeks=3;days=2;hours=3,seconds=2". + Format: "weeks=3;days=2;hours=3,seconds=2". + Format : "weeks=3;days=2;hours=3,seconds=2". @@ -3981,10 +3981,10 @@ doesn't pass when either or both of the selected options are equal or above the - Are you sure you want to update ""? + Are you sure you want to update ""? Êtes-vous sûr de vouloir mettre à jour - " - " ? + " + " ? @@ -5070,8 +5070,8 @@ doesn't pass when either or both of the selected options are equal or above the - A "roaming" authenticator, like a YubiKey - Un authentificateur "itinérant", comme une YubiKey + A "roaming" authenticator, like a YubiKey + Un authentificateur "itinérant", comme une YubiKey @@ -5396,7 +5396,7 @@ doesn't pass when either or both of the selected options are equal or above the Show arbitrary input fields to the user, for example during enrollment. Data is saved in the flow context under the 'prompt_data' variable. - Afficher des champs de saisie arbitraires à l'utilisateur, par exemple pendant l'inscription. Les données sont enregistrées dans le contexte du flux sous la variable "prompt_data". + Afficher des champs de saisie arbitraires à l'utilisateur, par exemple pendant l'inscription. Les données sont enregistrées dans le contexte du flux sous la variable "prompt_data". @@ -5405,10 +5405,10 @@ doesn't pass when either or both of the selected options are equal or above the - ("", of type ) + ("", of type ) - (" - ", de type + (" + ", de type ) @@ -5457,8 +5457,8 @@ doesn't pass when either or both of the selected options are equal or above the - If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. - Si défini à une durée supérieure à 0, l'utilisateur aura la possibilité de choisir de "rester connecté", ce qui prolongera sa session jusqu'à la durée spécifiée ici. + If set to a duration above 0, the user will have the option to choose to "stay signed in", which will extend their session by the time specified here. + Si défini à une durée supérieure à 0, l'utilisateur aura la possibilité de choisir de "rester connecté", ce qui prolongera sa session jusqu'à la durée spécifiée ici. @@ -6242,7 +6242,7 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti Can be in the format of 'unix://' when connecting to a local docker daemon, using 'ssh://' to connect via SSH, or 'https://:2376' when connecting to a remote system. - Peut être au format "unix://" pour une connexion à un service docker local, "ssh://" pour une connexion via SSH, ou "https://:2376" pour une connexion à un système distant. + Peut être au format "unix://" pour une connexion à un service docker local, "ssh://" pour une connexion via SSH, ou "https://:2376" pour une connexion à un système distant. @@ -7549,7 +7549,7 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti Use this provider with nginx's auth_request or traefik's forwardAuth. Each application/domain needs its own provider. Additionally, on each domain, /outpost.goauthentik.io must be routed to the outpost (when using a managed outpost, this is done for you). - Utilisez ce fournisseur avec l'option "auth_request" de Nginx ou "forwardAuth" de Traefik. Chaque application/domaine a besoin de son propre fournisseur. De plus, sur chaque domaine, "/outpost.goauthentik.io" doit être routé vers le poste avancé (lorsque vous utilisez un poste avancé géré, cela est fait pour vous). + Utilisez ce fournisseur avec l'option "auth_request" de Nginx ou "forwardAuth" de Traefik. Chaque application/domaine a besoin de son propre fournisseur. De plus, sur chaque domaine, "/outpost.goauthentik.io" doit être routé vers le poste avancé (lorsque vous utilisez un poste avancé géré, cela est fait pour vous). Default relay state @@ -7896,7 +7896,7 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti RBAC is in preview. - RBAC est en aperçu, + RBAC est en aperçu. User type used for newly created users. @@ -7963,7 +7963,7 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti Utilisateur créé et ajouté au groupe avec succès - This user will be added to the group "". + This user will be added to the group "". Cet utilisateur sera ajouté au groupe &quot;&quot;. @@ -8044,124 +8044,164 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti Connection settings. + Paramètres de connexion. Successfully updated endpoint. + Point de terminaison mis à jour avec succès. Successfully created endpoint. + Point de terminaison créé avec succès. Protocol + Protocole RDP + RDP SSH + SSH VNC + VNC Host + Hôte Hostname/IP to connect to. + Nom d'hôte/IP à laquelle se connecter. Endpoint(s) + Point(s) de terminaison Update Endpoint + Mettre à jour le point de terminaison These bindings control which users will have access to this endpoint. Users must also have access to the application. + Ces liaisons controllent quels utilisateurs auront accès à ce point de terminaison. Les utilisateurs doivent également avoir accès à l'application. Create Endpoint + Créer un point de terminaison RAC is in preview. + RAC est en aperçu. Update RAC Provider + Mettre à jour le fournisseur RAC Endpoints + Points de terminaison General settings + Paramètres généraux RDP settings + Paramètres RDP Ignore server certificate + Ignorer le certificat serveur Enable wallpaper + Activer le fond d'écran Enable font-smoothing + Activer le lissage des polices d'écriture Enable full window dragging + Activer le déplacement dans toute la fenêtre Network binding + Liaison réseau No binding + Pas de liaison Bind ASN + Lier l'ASN Bind ASN and Network + Lier l'ASN et le réseau Bind ASN, Network and IP + Lier l'ASN, le réseau et l'IP Configure if sessions created by this stage should be bound to the Networks they were created in. + Configurer si les sessions créer par cette étape doivent être liées aux réseaux depuis lesquelles elle ont été créées. GeoIP binding + Liaison GeoIP Bind Continent + Lier le continent Bind Continent and Country + Lier le continent et le pays Bind Continent, Country and City + Lier le continent, pays et ville Configure if sessions created by this stage should be bound to their GeoIP-based location + Configurer si les sessions créer par cette étape doivent être liées à la localisation GeoIP depuis lesquelles elle ont été créées. RAC + RAC Connection failed after attempts. + Connexion échouée après essais. Re-connecting in second(s). + Re-connexion dans seconde(s). Connecting... + Connexion... Select endpoint to connect to + Sélectionner le point de terminaison auquel se connecter Connection expiry + Expiration de la connection Determines how long a session lasts before being disconnected and requiring re-authorization. + Détermine combien de temps une session dure avant déconnexion et ré-authorisation. - + \ No newline at end of file From d54b410429f02dd411367fe442d6c689c47b8796 Mon Sep 17 00:00:00 2001 From: Marc 'risson' Schmitt Date: Tue, 2 Jan 2024 21:01:53 +0100 Subject: [PATCH 31/31] outposts/proxy: better Redis error message (#8044) * outposts/proxy: better Redis error message Signed-off-by: Marc 'risson' Schmitt * Update internal/outpost/proxyv2/application/session.go Co-authored-by: Jens L. Signed-off-by: Marc 'risson' Schmitt --------- Signed-off-by: Marc 'risson' Schmitt Co-authored-by: Jens L. --- internal/outpost/proxyv2/application/session.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/outpost/proxyv2/application/session.go b/internal/outpost/proxyv2/application/session.go index 468baf4d9..b30934fb4 100644 --- a/internal/outpost/proxyv2/application/session.go +++ b/internal/outpost/proxyv2/application/session.go @@ -13,6 +13,7 @@ import ( "github.com/gorilla/securecookie" "github.com/gorilla/sessions" "github.com/redis/go-redis/v9" + "goauthentik.io/api/v3" "goauthentik.io/internal/config" "goauthentik.io/internal/outpost/proxyv2/codecs" @@ -40,7 +41,7 @@ func (a *Application) getStore(p api.ProxyOutpostConfig, externalHost *url.URL) // New default RedisStore rs, err := redisstore.NewRedisStore(context.Background(), client) if err != nil { - panic(err) + a.log.WithError(err).Panic("failed to connect to redis") } rs.KeyPrefix(RedisKeyPrefix)