Browse Source

login: Remove support for SSO identity providers

Instead of having support for a handful of SSO providers on our end,
the user is always redirected to the default SSO URL where they will be
presented with all the providers supported by the homeserver.

This matches the UX of OAuth 2.0 where we can only redirect the user to
the homeserver's UI, and allows us to remove a bunch of code and files.
merge-requests/1714/merge
Kévin Commaille 1 month ago
parent
commit
b8f3e91e45
No known key found for this signature in database
GPG Key ID: F26F4BE20A08255B
  1. 1
      data/resources/icons/scalable/actions/idp-apple-dark.svg
  2. 1
      data/resources/icons/scalable/actions/idp-apple.svg
  3. 1
      data/resources/icons/scalable/actions/idp-facebook.svg
  4. 1
      data/resources/icons/scalable/actions/idp-github-dark.svg
  5. 1
      data/resources/icons/scalable/actions/idp-github.svg
  6. 1
      data/resources/icons/scalable/actions/idp-gitlab.svg
  7. 1
      data/resources/icons/scalable/actions/idp-google-dark.svg
  8. 1
      data/resources/icons/scalable/actions/idp-google.svg
  9. 1
      data/resources/icons/scalable/actions/idp-x-dark.svg
  10. 1
      data/resources/icons/scalable/actions/idp-x-light.svg
  11. 10
      data/resources/resources.gresource.xml
  12. 1
      po/POTFILES.in
  13. 16
      src/login/method_page.blp
  14. 64
      src/login/method_page.rs
  15. 27
      src/login/mod.rs
  16. 10
      src/login/sso_idp_button.blp
  17. 183
      src/login/sso_idp_button.rs
  18. 1
      src/ui-blueprint-resources.in

1
data/resources/icons/scalable/actions/idp-apple-dark.svg

@ -1 +0,0 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="3.78 1.25 17.75 21.82"><path fill-rule="evenodd" clip-rule="evenodd" d="M16.98 1.28a4.872 4.872 0 0 1-1.114 3.49 4.099 4.099 0 0 1-3.237 1.53 4.636 4.636 0 0 1 1.144-3.36 4.957 4.957 0 0 1 3.207-1.66Zm3.974 7.428a4.949 4.949 0 0 0-2.357 4.152 4.782 4.782 0 0 0 2.92 4.4 10.963 10.963 0 0 1-1.519 3.092c-.894 1.338-1.832 2.645-3.32 2.669-.708.016-1.186-.187-1.684-.4-.52-.22-1.06-.451-1.907-.451-.899 0-1.464.238-2.01.467-.47.198-.927.39-1.57.417-1.417.053-2.5-1.428-3.427-2.753-1.853-2.707-3.296-7.628-1.362-10.976a5.315 5.315 0 0 1 4.473-2.728c.804-.017 1.576.293 2.252.565.517.208.979.393 1.357.393.332 0 .78-.178 1.304-.386.824-.326 1.832-.727 2.859-.619 1.596.05 3.075.85 3.99 2.158Z" fill="#fff"/></svg>

Before

Width:  |  Height:  |  Size: 769 B

1
data/resources/icons/scalable/actions/idp-apple.svg

@ -1 +0,0 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="3.78 1.25 17.75 21.82"><path fill-rule="evenodd" clip-rule="evenodd" d="M16.98 1.28a4.872 4.872 0 0 1-1.114 3.49 4.099 4.099 0 0 1-3.237 1.53 4.636 4.636 0 0 1 1.144-3.36 4.957 4.957 0 0 1 3.207-1.66Zm3.974 7.428a4.949 4.949 0 0 0-2.357 4.152 4.782 4.782 0 0 0 2.92 4.4 10.963 10.963 0 0 1-1.519 3.092c-.894 1.338-1.832 2.645-3.32 2.669-.708.016-1.186-.187-1.684-.4-.52-.22-1.06-.451-1.907-.451-.899 0-1.464.238-2.01.467-.47.198-.927.39-1.57.417-1.417.053-2.5-1.428-3.427-2.753-1.853-2.707-3.296-7.628-1.362-10.976a5.315 5.315 0 0 1 4.473-2.728c.804-.017 1.576.293 2.252.565.517.208.979.393 1.357.393.332 0 .78-.178 1.304-.386.824-.326 1.832-.727 2.859-.619 1.596.05 3.075.85 3.99 2.158Z" fill="#17191C"/></svg>

Before

Width:  |  Height:  |  Size: 772 B

1
data/resources/icons/scalable/actions/idp-facebook.svg

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="22" height="22"><defs><clipPath id="c"><path d="M0 0h23v22H0z"/></clipPath><clipPath id="d"><path d="M0 0h22v22H0z"/></clipPath><g id="e" clip-path="url(#c)"><path style="stroke:none;fill-rule:evenodd;fill:#1877f2;fill-opacity:1" d="M22 11c0-6.074-4.926-11-11-11C4.922 0-.004 4.926-.004 11c0 5.488 4.024 10.043 9.285 10.867V14.18H6.484V11h2.793V8.578c0-2.758 1.645-4.281 4.157-4.281 1.207 0 2.46.215 2.46.215v2.707h-1.382c-1.367 0-1.793.847-1.793 1.718V11h3.05l-.488 3.18H12.72v7.687C17.977 21.043 22 16.492 22 11Zm0 0"/></g><g id="g" clip-path="url(#d)"><use xlink:href="#e" mask="url(#f)"/></g><filter id="a" filterUnits="objectBoundingBox" x="0%" y="0%" width="100%" height="100%"><feColorMatrix in="SourceGraphic" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/></filter><image id="b" width="23" height="22" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAAWCAYAAAArdgcFAAAABmJLR0QA/wD/AP+gvaeTAAAALUlEQVQ4je3MQQ0AIBADsB7Bv0WkgIp9yCqggytjVigGzZs3b968+cf5xknlDwBCAg1iefLzAAAAAElFTkSuQmCC"/><mask id="f"><g filter="url(#a)"><use xlink:href="#b"/></g></mask></defs><use xlink:href="#g"/><path style="stroke:none;fill-rule:evenodd;fill:#fff;fill-opacity:1" d="M15.281 14.18 15.77 11h-3.051V8.937c0-.87.426-1.718 1.793-1.718h1.386V4.512s-1.257-.215-2.46-.215c-2.516 0-4.157 1.523-4.157 4.281V11H6.488v3.18h2.793v7.687c1.137.18 2.297.18 3.438 0V14.18Zm0 0"/></svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

1
data/resources/icons/scalable/actions/idp-github-dark.svg

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22"><path style="stroke:none;fill-rule:nonzero;fill:#fff;fill-opacity:1" d="M20.504 5.613a11.103 11.103 0 0 0-4-4.101C14.82.504 12.984 0 10.988 0 8.996 0 7.156.504 5.473 1.512a11.103 11.103 0 0 0-4 4.101C.493 7.34 0 9.227 0 11.273c0 2.454.7 4.665 2.098 6.625 1.394 1.961 3.199 3.317 5.414 4.07.258.052.449.016.574-.1a.576.576 0 0 0 .184-.438l-.008-.797c-.004-.496-.008-.934-.008-1.305l-.328.059a3.849 3.849 0 0 1-.793.05 5.667 5.667 0 0 1-.996-.101 2.214 2.214 0 0 1-.957-.441 1.87 1.87 0 0 1-.633-.899l-.14-.34c-.122-.27-.27-.52-.45-.75-.207-.273-.414-.457-.625-.554l-.098-.075a1.001 1.001 0 0 1-.316-.382c-.027-.07-.004-.125.07-.168.078-.047.215-.067.418-.067l.285.043c.192.04.426.156.707.352.286.199.512.453.696.765.218.403.484.707.793.918.312.207.625.313.937.313.317 0 .586-.024.817-.07.226-.051.441-.126.644-.223.086-.656.32-1.16.7-1.512a9.84 9.84 0 0 1-1.465-.262 5.758 5.758 0 0 1-1.344-.574 3.818 3.818 0 0 1-1.153-.984c-.308-.39-.558-.906-.753-1.54-.196-.636-.293-1.37-.293-2.202 0-1.184.378-2.192 1.132-3.024-.355-.89-.32-1.887.098-2.996.277-.086.688-.02 1.23.2.543.222.942.41 1.196.566.254.156.457.289.61.398a9.776 9.776 0 0 1 2.745-.383c.946 0 1.86.125 2.75.383l.543-.355c.371-.235.809-.45 1.317-.645.504-.195.89-.25 1.156-.164.43 1.11.469 2.106.117 2.996.75.832 1.129 1.84 1.129 3.024 0 .832-.098 1.57-.293 2.207-.195.644-.45 1.156-.758 1.543-.324.398-.715.73-1.16.976a5.84 5.84 0 0 1-1.344.574 9.41 9.41 0 0 1-1.468.262c.496.442.746 1.137.746 2.086v3.094c0 .176.058.324.18.441.117.117.304.153.562.102 2.215-.754 4.02-2.11 5.418-4.07 1.394-1.965 2.094-4.172 2.094-6.63 0-2.042-.493-3.93-1.473-5.656Zm0 0"/></svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

1
data/resources/icons/scalable/actions/idp-github.svg

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22"><path style="stroke:none;fill-rule:nonzero;fill:#000;fill-opacity:1" d="M20.504 5.613a11.103 11.103 0 0 0-4-4.101C14.82.504 12.984 0 10.988 0 8.996 0 7.156.504 5.473 1.512a11.103 11.103 0 0 0-4 4.101C.493 7.34 0 9.227 0 11.273c0 2.454.7 4.665 2.098 6.625 1.394 1.961 3.199 3.317 5.414 4.07.258.052.449.016.574-.1a.576.576 0 0 0 .184-.438l-.008-.797c-.004-.496-.008-.934-.008-1.305l-.328.059a3.849 3.849 0 0 1-.793.05 5.667 5.667 0 0 1-.996-.101 2.214 2.214 0 0 1-.957-.441 1.87 1.87 0 0 1-.633-.899l-.14-.34c-.122-.27-.27-.52-.45-.75-.207-.273-.414-.457-.625-.554l-.098-.075a1.001 1.001 0 0 1-.316-.382c-.027-.07-.004-.125.07-.168.078-.047.215-.067.418-.067l.285.043c.192.04.426.156.707.352.286.199.512.453.696.765.218.403.484.707.793.918.312.207.625.313.937.313.317 0 .586-.024.817-.07.226-.051.441-.126.644-.223.086-.656.32-1.16.7-1.512a9.84 9.84 0 0 1-1.465-.262 5.758 5.758 0 0 1-1.344-.574 3.818 3.818 0 0 1-1.153-.984c-.308-.39-.558-.906-.753-1.54-.196-.636-.293-1.37-.293-2.202 0-1.184.378-2.192 1.132-3.024-.355-.89-.32-1.887.098-2.996.277-.086.688-.02 1.23.2.543.222.942.41 1.196.566.254.156.457.289.61.398a9.776 9.776 0 0 1 2.745-.383c.946 0 1.86.125 2.75.383l.543-.355c.371-.235.809-.45 1.317-.645.504-.195.89-.25 1.156-.164.43 1.11.469 2.106.117 2.996.75.832 1.129 1.84 1.129 3.024 0 .832-.098 1.57-.293 2.207-.195.644-.45 1.156-.758 1.543-.324.398-.715.73-1.16.976a5.84 5.84 0 0 1-1.344.574 9.41 9.41 0 0 1-1.468.262c.496.442.746 1.137.746 2.086v3.094c0 .176.058.324.18.441.117.117.304.153.562.102 2.215-.754 4.02-2.11 5.418-4.07 1.394-1.965 2.094-4.172 2.094-6.63 0-2.042-.493-3.93-1.473-5.656Zm0 0"/></svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

1
data/resources/icons/scalable/actions/idp-gitlab.svg

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22"><path style="stroke:none;fill-rule:nonzero;fill:#e24329;fill-opacity:1" d="m11.008 22 4.047-13.535h-8.09Zm0 0"/><path style="stroke:none;fill-rule:nonzero;fill:#fca326;fill-opacity:1" d="m1.297 8.465-1.23 4.113a.944.944 0 0 0 .304 1.016L11.008 22Zm0 0"/><path style="stroke:none;fill-rule:nonzero;fill:#e24329;fill-opacity:1" d="M1.297 8.465h5.668L4.523.313c-.125-.418-.668-.418-.796 0Zm0 0"/><path style="stroke:none;fill-rule:nonzero;fill:#fca326;fill-opacity:1" d="m20.719 8.465 1.226 4.113a.95.95 0 0 1-.3 1.016L11.004 22Zm0 0"/><path style="stroke:none;fill-rule:nonzero;fill:#e24329;fill-opacity:1" d="M20.723 8.465h-5.668L17.488.313c.125-.418.668-.418.797 0Zm0 0"/><path style="stroke:none;fill-rule:nonzero;fill:#fc6d26;fill-opacity:1" d="M11.008 22 15.05 8.465h5.668Zm-.004 0L1.297 8.465h5.668L11.008 22Zm0 0"/></svg>

Before

Width:  |  Height:  |  Size: 889 B

1
data/resources/icons/scalable/actions/idp-google-dark.svg

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22"><path style="stroke:none;fill-rule:nonzero;fill:#4285f4;fill-opacity:1" d="M21.98 11.234c0-.902-.074-1.562-.238-2.246H11.215v4.078h6.18c-.125 1.012-.797 2.54-2.293 3.563l-.02.137 3.328 2.527.23.023c2.118-1.918 3.34-4.738 3.34-8.082Zm0 0"/><path style="stroke:none;fill-rule:nonzero;fill:#34a853;fill-opacity:1" d="M11.215 21.98c3.027 0 5.57-.976 7.426-2.664L15.1 16.63c-.945.648-2.218 1.101-3.886 1.101a6.736 6.736 0 0 1-6.38-4.566l-.132.012-3.46 2.625-.048.12c1.844 3.59 5.633 6.06 10.02 6.06Zm0 0"/><path style="stroke:none;fill-rule:nonzero;fill:#fbbc05;fill-opacity:1" d="M4.836 13.164a6.652 6.652 0 0 1-.375-2.176c0-.754.137-1.488.363-2.172l-.008-.144-3.503-2.668-.114.05A10.846 10.846 0 0 0 0 10.989c0 1.774.438 3.446 1.2 4.934Zm0 0"/><path style="stroke:none;fill-rule:nonzero;fill:#eb4335;fill-opacity:1" d="M11.215 4.25c2.105 0 3.527.89 4.336 1.637l3.164-3.032C16.77 1.085 14.242 0 11.215 0 6.828 0 3.039 2.469 1.195 6.059L4.82 8.816a6.773 6.773 0 0 1 6.395-4.566Zm0 0"/></svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

1
data/resources/icons/scalable/actions/idp-google.svg

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22"><path style="stroke:none;fill-rule:nonzero;fill:#4285f4;fill-opacity:1" d="M21.98 11.234c0-.902-.074-1.562-.238-2.246H11.215v4.078h6.18c-.125 1.012-.797 2.54-2.293 3.563l-.02.137 3.328 2.527.23.023c2.118-1.918 3.34-4.738 3.34-8.082Zm0 0"/><path style="stroke:none;fill-rule:nonzero;fill:#34a853;fill-opacity:1" d="M11.215 21.98c3.027 0 5.57-.976 7.426-2.664L15.1 16.63c-.945.648-2.218 1.101-3.886 1.101a6.736 6.736 0 0 1-6.38-4.566l-.132.012-3.46 2.625-.048.12c1.844 3.59 5.633 6.06 10.02 6.06Zm0 0"/><path style="stroke:none;fill-rule:nonzero;fill:#fbbc05;fill-opacity:1" d="M4.836 13.164a6.652 6.652 0 0 1-.375-2.176c0-.754.137-1.488.363-2.172l-.008-.144-3.503-2.668-.114.05A10.846 10.846 0 0 0 0 10.989c0 1.774.438 3.446 1.2 4.934Zm0 0"/><path style="stroke:none;fill-rule:nonzero;fill:#eb4335;fill-opacity:1" d="M11.215 4.25c2.105 0 3.527.89 4.336 1.637l3.164-3.032C16.77 1.085 14.242 0 11.215 0 6.828 0 3.039 2.469 1.195 6.059L4.82 8.816a6.773 6.773 0 0 1 6.395-4.566Zm0 0"/></svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

1
data/resources/icons/scalable/actions/idp-x-dark.svg

@ -1 +0,0 @@
<svg width="1200" height="1227" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M714 519 1161 0h-106L667 451 357 0H0l468 682L0 1226h106l409-476 328 476h357L714 519ZM569 688l-47-68L144 80h163l304 436 48 68 396 566H892L569 688Z" fill="#fff"/></svg>

Before

Width:  |  Height:  |  Size: 254 B

1
data/resources/icons/scalable/actions/idp-x-light.svg

@ -1 +0,0 @@
<svg width="1200" height="1227" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M714 519 1161 0h-106L667 451 357 0H0l468 682L0 1226h106l409-476 328 476h357L714 519ZM569 688l-47-68L144 80h163l304 436 48 68 396 566H892L569 688Z" fill="#000"/></svg>

Before

Width:  |  Height:  |  Size: 254 B

10
data/resources/resources.gresource.xml

@ -19,16 +19,6 @@
<file preprocess="xml-stripblanks">icons/scalable/actions/go-next-symbolic.svg</file> <file preprocess="xml-stripblanks">icons/scalable/actions/go-next-symbolic.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/go-previous-symbolic.svg</file> <file preprocess="xml-stripblanks">icons/scalable/actions/go-previous-symbolic.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/hide-symbolic.svg</file> <file preprocess="xml-stripblanks">icons/scalable/actions/hide-symbolic.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/idp-apple-dark.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/idp-apple.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/idp-facebook.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/idp-github-dark.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/idp-github.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/idp-gitlab.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/idp-google-dark.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/idp-google.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/idp-x-dark.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/idp-x-light.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/map-marker-symbolic.svg</file> <file preprocess="xml-stripblanks">icons/scalable/actions/map-marker-symbolic.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/media-playback-pause-symbolic.svg</file> <file preprocess="xml-stripblanks">icons/scalable/actions/media-playback-pause-symbolic.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/media-playback-start-symbolic.svg</file> <file preprocess="xml-stripblanks">icons/scalable/actions/media-playback-start-symbolic.svg</file>

1
po/POTFILES.in

@ -99,7 +99,6 @@ src/login/method_page.rs
src/login/mod.blp src/login/mod.blp
src/login/mod.rs src/login/mod.rs
src/login/session_setup_view.blp src/login/session_setup_view.blp
src/login/sso_idp_button.rs
src/secret/linux.rs src/secret/linux.rs
src/session/mod.rs src/session/mod.rs
src/session/notifications/mod.rs src/session/notifications/mod.rs

16
src/login/method_page.blp

@ -113,28 +113,16 @@ template $LoginMethodPage: Adw.NavigationPage {
} }
} }
Gtk.Box sso_idp_box { Gtk.Button sso_button {
visible: false;
spacing: 12;
homogeneous: true;
hexpand: true;
vexpand: true;
accessibility {
label: _("Single Sign-On Providers");
}
}
Gtk.Button more_sso_btn {
styles [ styles [
"standalone-button", "standalone-button",
"pill", "pill",
] ]
label: _("Login via SSO");
can-shrink: true; can-shrink: true;
halign: center; halign: center;
action-name: "login.sso"; action-name: "login.sso";
action-target: "@ms nothing";
} }
$LoadingButton next_button { $LoadingButton next_button {

64
src/login/method_page.rs

@ -1,16 +1,14 @@
use adw::{prelude::*, subclass::prelude::*}; use adw::{prelude::*, subclass::prelude::*};
use gettextrs::gettext; use gettextrs::gettext;
use gtk::glib; use gtk::glib;
use ruma::{OwnedServerName, api::client::session::get_login_types::v3::LoginType}; use ruma::OwnedServerName;
use tracing::warn; use tracing::warn;
use url::Url; use url::Url;
use super::{Login, sso_idp_button::SsoIdpButton}; use super::Login;
use crate::{components::LoadingButton, gettext_f, prelude::*, spawn_tokio, toast}; use crate::{components::LoadingButton, gettext_f, prelude::*, spawn_tokio, toast};
mod imp { mod imp {
use std::cell::RefCell;
use glib::subclass::InitializingObject; use glib::subclass::InitializingObject;
use super::*; use super::*;
@ -28,10 +26,7 @@ mod imp {
#[template_child] #[template_child]
password_entry: TemplateChild<adw::PasswordEntryRow>, password_entry: TemplateChild<adw::PasswordEntryRow>,
#[template_child] #[template_child]
sso_idp_box: TemplateChild<gtk::Box>, sso_button: TemplateChild<gtk::Button>,
sso_idp_box_children: RefCell<Vec<SsoIdpButton>>,
#[template_child]
more_sso_btn: TemplateChild<gtk::Button>,
#[template_child] #[template_child]
next_button: TemplateChild<LoadingButton>, next_button: TemplateChild<LoadingButton>,
/// The parent `Login` object. /// The parent `Login` object.
@ -108,45 +103,8 @@ mod imp {
} }
/// Update the SSO group. /// Update the SSO group.
pub(super) fn update_sso(&self, login_types: Vec<LoginType>) { pub(super) fn update_sso(&self, supports_sso: bool) {
let Some(sso_login) = login_types.into_iter().find_map(|t| match t { self.sso_button.set_visible(supports_sso);
LoginType::Sso(sso) => Some(sso),
_ => None,
}) else {
self.sso_idp_box.set_visible(false);
self.more_sso_btn.set_visible(false);
return;
};
self.clean_idp_box();
let mut has_unknown_methods = false;
let mut has_known_methods = false;
if !sso_login.identity_providers.is_empty() {
let mut sso_idp_box_children = self.sso_idp_box_children.borrow_mut();
sso_idp_box_children.reserve(sso_login.identity_providers.len());
for identity_provider in sso_login.identity_providers {
if let Some(btn) = SsoIdpButton::new(identity_provider) {
self.sso_idp_box.append(&btn);
sso_idp_box_children.push(btn);
has_known_methods = true;
} else {
has_unknown_methods = true;
}
}
}
self.sso_idp_box.set_visible(has_known_methods);
if has_known_methods {
self.more_sso_btn.set_label(&gettext("More SSO Providers"));
self.more_sso_btn.set_visible(has_unknown_methods);
} else {
self.more_sso_btn.set_label(&gettext("Login via SSO"));
self.more_sso_btn.set_visible(true);
}
} }
/// Whether the current state allows to login with a password. /// Whether the current state allows to login with a password.
@ -210,14 +168,6 @@ mod imp {
self.password_entry.set_text(""); self.password_entry.set_text("");
self.next_button.set_is_loading(false); self.next_button.set_is_loading(false);
self.update_next_state(); self.update_next_state();
self.clean_idp_box();
}
/// Empty the identity providers box.
fn clean_idp_box(&self) {
for child in self.sso_idp_box_children.borrow_mut().drain(..) {
self.sso_idp_box.remove(&child);
}
} }
} }
} }
@ -239,11 +189,11 @@ impl LoginMethodPage {
&self, &self,
homeserver_url: &Url, homeserver_url: &Url,
domain_name: Option<&OwnedServerName>, domain_name: Option<&OwnedServerName>,
login_types: Vec<LoginType>, supports_sso: bool,
) { ) {
let imp = self.imp(); let imp = self.imp();
imp.update_title(homeserver_url, domain_name); imp.update_title(homeserver_url, domain_name);
imp.update_sso(login_types); imp.update_sso(supports_sso);
imp.update_next_state(); imp.update_next_state();
} }

27
src/login/mod.rs

@ -23,7 +23,6 @@ mod in_browser_page;
mod local_server; mod local_server;
mod method_page; mod method_page;
mod session_setup_view; mod session_setup_view;
mod sso_idp_button;
use self::{ use self::{
advanced_dialog::LoginAdvancedDialog, advanced_dialog::LoginAdvancedDialog,
@ -105,14 +104,9 @@ mod imp {
klass.set_css_name("login"); klass.set_css_name("login");
klass.set_accessible_role(gtk::AccessibleRole::Group); klass.set_accessible_role(gtk::AccessibleRole::Group);
klass.install_action_async( klass.install_action_async("login.sso", None, |obj, _, _| async move {
"login.sso", obj.imp().init_matrix_sso_login().await;
Some(&Option::<String>::static_variant_type()), });
|obj, _, variant| async move {
let idp = variant.and_then(|v| v.get::<Option<String>>()).flatten();
obj.imp().init_matrix_sso_login(idp).await;
},
);
klass.install_action_async("login.open-advanced", None, |obj, _, _| async move { klass.install_action_async("login.open-advanced", None, |obj, _, _| async move {
obj.imp().open_advanced_dialog().await; obj.imp().open_advanced_dialog().await;
@ -328,6 +322,9 @@ mod imp {
let supports_password = login_types let supports_password = login_types
.iter() .iter()
.any(|login_type| matches!(login_type, LoginType::Password(_))); .any(|login_type| matches!(login_type, LoginType::Password(_)));
let supports_sso = login_types
.iter()
.any(|login_type| matches!(login_type, LoginType::Sso(_)));
if supports_password { if supports_password {
let server_name = self let server_name = self
@ -336,14 +333,14 @@ mod imp {
.then(|| self.homeserver_page.homeserver()) .then(|| self.homeserver_page.homeserver())
.and_then(|s| sanitize_server_name(&s).ok()); .and_then(|s| sanitize_server_name(&s).ok());
self.show_method_page(&client.homeserver(), server_name.as_ref(), login_types); self.show_method_page(&client.homeserver(), server_name.as_ref(), supports_sso);
} else { } else {
self.init_matrix_sso_login(None).await; self.init_matrix_sso_login().await;
} }
} }
/// Prepare to log in via the Matrix SSO API. /// Prepare to log in via the Matrix SSO API.
pub(super) async fn init_matrix_sso_login(&self, idp: Option<String>) { pub(super) async fn init_matrix_sso_login(&self) {
let Some(client) = self.client.borrow().clone() else { let Some(client) = self.client.borrow().clone() else {
return; return;
}; };
@ -355,7 +352,7 @@ mod imp {
let matrix_auth = client.matrix_auth(); let matrix_auth = client.matrix_auth();
let handle = spawn_tokio!(async move { let handle = spawn_tokio!(async move {
matrix_auth matrix_auth
.get_sso_login_url(redirect_uri.as_str(), idp.as_deref()) .get_sso_login_url(redirect_uri.as_str(), None)
.await .await
}); });
@ -376,10 +373,10 @@ mod imp {
&self, &self,
homeserver: &Url, homeserver: &Url,
server_name: Option<&OwnedServerName>, server_name: Option<&OwnedServerName>,
login_types: Vec<LoginType>, supports_sso: bool,
) { ) {
self.method_page self.method_page
.update(homeserver, server_name, login_types); .update(homeserver, server_name, supports_sso);
self.navigation.push_by_tag(LoginPage::Method.as_ref()); self.navigation.push_by_tag(LoginPage::Method.as_ref());
} }

10
src/login/sso_idp_button.blp

@ -1,10 +0,0 @@
using Gtk 4.0;
template $SsoIdpButton: Gtk.Button {
action-name: "login.sso";
styles [
"card",
"sso-button",
]
}

183
src/login/sso_idp_button.rs

@ -1,183 +0,0 @@
use gtk::{glib, glib::clone, prelude::*, subclass::prelude::*};
use matrix_sdk::ruma::api::client::session::get_login_types::v3::{
IdentityProvider, IdentityProviderBrand,
};
use crate::gettext_f;
mod imp {
use std::{cell::OnceCell, marker::PhantomData};
use glib::subclass::InitializingObject;
use super::*;
#[derive(Debug, Default, gtk::CompositeTemplate, glib::Properties)]
#[template(resource = "/org/gnome/Fractal/ui/login/sso_idp_button.ui")]
#[properties(wrapper_type = super::SsoIdpButton)]
pub struct SsoIdpButton {
/// The identity provider of this button.
identity_provider: OnceCell<IdentityProvider>,
/// The ID of the identity provider.
#[property(get = Self::id)]
id: PhantomData<String>,
/// The name of the identity provider.
#[property(get = Self::name)]
name: PhantomData<String>,
/// The brand of the identity provider, as a string.
#[property(get = Self::brand_string)]
brand_string: PhantomData<String>,
}
#[glib::object_subclass]
impl ObjectSubclass for SsoIdpButton {
const NAME: &'static str = "SsoIdpButton";
type Type = super::SsoIdpButton;
type ParentType = gtk::Button;
fn class_init(klass: &mut Self::Class) {
Self::bind_template(klass);
klass.set_accessible_role(gtk::AccessibleRole::Button);
}
fn instance_init(obj: &InitializingObject<Self>) {
obj.init_template();
}
}
#[glib::derived_properties]
impl ObjectImpl for SsoIdpButton {}
impl WidgetImpl for SsoIdpButton {}
impl ButtonImpl for SsoIdpButton {}
impl SsoIdpButton {
/// Set the identity provider of this button.
pub(super) fn set_identity_provider(&self, identity_provider: IdentityProvider) {
let identity_provider = self.identity_provider.get_or_init(|| identity_provider);
adw::StyleManager::default().connect_dark_notify(clone!(
#[weak(rename_to = imp)]
self,
move |_| imp.update_icon()
));
self.update_icon();
self.obj()
.set_action_target_value(Some(&Some(&identity_provider.id).to_variant()));
self.obj().set_tooltip_text(Some(&gettext_f(
// Translators: Do NOT translate the content between '{' and '}', this is a
// variable name.
// This is the tooltip text on buttons to log in via Single Sign-On.
// The brand is something like Facebook, Apple, GitHub…
"Log in with {brand}",
&[("brand", &identity_provider.name)],
)));
}
/// The identity provider of this button.
fn identity_provider(&self) -> &IdentityProvider {
self.identity_provider
.get()
.expect("identity provider is initialized")
}
/// The ID of the identity provider.
fn id(&self) -> String {
self.identity_provider().id.clone()
}
/// The name of the identity provider.
fn name(&self) -> String {
self.identity_provider().name.clone()
}
/// The brand of the identity provider.
fn brand(&self) -> &IdentityProviderBrand {
self.identity_provider()
.brand
.as_ref()
.expect("identity provider has a brand")
}
/// The brand of the identity provider, as a string.
fn brand_string(&self) -> String {
self.brand().to_string()
}
/// The icon name of the brand, according to the current theme.
fn brand_icon(&self) -> &str {
let is_dark = adw::StyleManager::default().is_dark();
match self.brand() {
IdentityProviderBrand::Apple => {
if is_dark {
"idp-apple-dark"
} else {
"idp-apple"
}
}
IdentityProviderBrand::Facebook => "idp-facebook",
IdentityProviderBrand::GitHub => {
if is_dark {
"idp-github-dark"
} else {
"idp-github"
}
}
IdentityProviderBrand::GitLab => "idp-gitlab",
IdentityProviderBrand::Google => "idp-google",
IdentityProviderBrand::Twitter => {
if is_dark {
"idp-x-dark"
} else {
"idp-x-light"
}
}
// We do not construct this for other brands.
_ => unreachable!(),
}
}
/// Update the icon of this button for the current state.
fn update_icon(&self) {
self.obj().set_icon_name(self.brand_icon());
}
}
}
glib::wrapper! {
/// A button to represent an SSO identity provider.
pub struct SsoIdpButton(ObjectSubclass<imp::SsoIdpButton>)
@extends gtk::Widget, gtk::Button,
@implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget, gtk::Actionable;
}
impl SsoIdpButton {
/// The supported SSO identity provider brands of `SsoIdpButton`.
const SUPPORTED_IDP_BRANDS: &[IdentityProviderBrand] = &[
IdentityProviderBrand::Apple,
IdentityProviderBrand::Facebook,
IdentityProviderBrand::GitHub,
IdentityProviderBrand::GitLab,
IdentityProviderBrand::Google,
IdentityProviderBrand::Twitter,
];
/// Create a new `SsoIdpButton` with the given identity provider.
///
/// Returns `None` if the identity provider's brand is not supported.
pub fn new(identity_provider: IdentityProvider) -> Option<Self> {
// If this is not a supported brand, return `None`.
let brand = identity_provider.brand.as_ref()?;
if !Self::SUPPORTED_IDP_BRANDS.contains(brand) {
return None;
}
let obj = glib::Object::new::<Self>();
obj.imp().set_identity_provider(identity_provider);
Some(obj)
}
}

1
src/ui-blueprint-resources.in

@ -74,7 +74,6 @@ login/in_browser_page.blp
login/method_page.blp login/method_page.blp
login/mod.blp login/mod.blp
login/session_setup_view.blp login/session_setup_view.blp
login/sso_idp_button.blp
session_view/content.blp session_view/content.blp
session_view/create_direct_chat_dialog/mod.blp session_view/create_direct_chat_dialog/mod.blp
session_view/create_room_dialog.blp session_view/create_room_dialog.blp

Loading…
Cancel
Save