You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
gnome-online-accounts/SOURCES/0002-Drop-dependency-on-Web...

4923 lines
181 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

diff --git a/configure.ac b/configure.ac
index ddf98f1..f997d36 100644
--- a/configure.ac
+++ b/configure.ac
@@ -124,10 +124,6 @@ if test "$enable_backend" != "no"; then
AC_SUBST(GTK_CFLAGS)
AC_SUBST(GTK_LIBS)
- PKG_CHECK_MODULES(WEBKIT_GTK, [webkit2gtk-4.0 >= 2.12.0])
- AC_SUBST(WEBKIT_GTK_CFLAGS)
- AC_SUBST(WEBKIT_GTK_LIBS)
-
PKG_CHECK_MODULES(LIBSOUP, [libsoup-2.4 >= 2.42])
AC_SUBST(LIBSOUP_CFLAGS)
AC_SUBST(LIBSOUP_LIBS)
@@ -176,14 +172,6 @@ if test "$enable_backend" != "no"; then
fi
fi
-AC_ARG_ENABLE([inspector],
- [AS_HELP_STRING([--enable-inspector], [Enable a WebKitWebInspector for the embedded web view])],
- [],
- [enable_inspector=no])
-if test "$enable_inspector" != "no"; then
- AC_DEFINE(GOA_INSPECTOR_ENABLED, 1, [Enable a WebKitWebInspector for the embedded web view])
-fi
-
AC_ARG_WITH(template-file,
[AS_HELP_STRING([--with-template-file], [Path to the template file])],
[],
@@ -271,7 +259,11 @@ AC_DEFINE_UNQUOTED(GOA_GOOGLE_CLIENT_ID, ["$with_google_client_id"], [Google OAu
AC_DEFINE_UNQUOTED(GOA_GOOGLE_CLIENT_SECRET, ["$with_google_client_secret"], [Google OAuth 2.0 client secret])
if test "$enable_google" != "no"; then
AC_DEFINE(GOA_GOOGLE_ENABLED, 1, [Enable Google data provider])
+ if test "$with_google_client_id" != "44438659992-7kgjeitenc16ssihbtdjbgguch7ju55s.apps.googleusercontent.com"; then
+ AC_MSG_ERROR([Unexpected Google OAuth2 Client ID, correct it here and in data/Makefile.am in oauth2_schemes, to be reverse-DNS of the new Client ID])
+ fi
fi
+AM_CONDITIONAL(GOOGLE_ENABLED, [test x$enable_google != xno])
# IMAP/SMTP
AC_DEFINE(GOA_IMAP_SMTP_NAME, ["imap_smtp"], [ProviderType and extension point name])
diff --git a/data/Makefile.am b/data/Makefile.am
index 286dcd0..61b69e1 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -20,16 +20,30 @@ service_DATA = $(service_in_files:.service.in=.service)
@sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@
endif
+desktopdir = $(datadir)/applications
+desktop_in_files = org.gnome.OnlineAccounts.OAuth2.desktop.in
+desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
+if GOOGLE_ENABLED
+ oauth2_schemes=x-scheme-handler/com.googleusercontent.apps.44438659992-7kgjeitenc16ssihbtdjbgguch7ju55s;
+else
+ oauth2_schemes=
+endif
+
+%.desktop: %.desktop.in Makefile
+ @sed -e "s|\@libexecdir\@|$(libexecdir)|" -e "s|\@oauth2_schemes\@|$(oauth2_schemes)|" $< > $@
+
EXTRA_DIST = \
$(gsettings_SCHEMAS) \
dbus-interfaces.xml \
org.gnome.Identity.service.in \
org.gnome.OnlineAccounts.service.in \
+ org.gnome.OnlineAccounts.OAuth2.desktop.in \
$(NULL)
CLEANFILES = \
org.gnome.OnlineAccounts.service \
org.gnome.Identity.service \
+ org.gnome.OnlineAccounts.OAuth2.desktop \
$(NULL)
clean-local :
diff --git a/data/org.gnome.OnlineAccounts.OAuth2.desktop.in b/data/org.gnome.OnlineAccounts.OAuth2.desktop.in
new file mode 100644
index 0000000..d0478aa
--- /dev/null
+++ b/data/org.gnome.OnlineAccounts.OAuth2.desktop.in
@@ -0,0 +1,6 @@
+[Desktop Entry]
+Name=GNOME OAuth2 Handler
+Exec=@libexecdir@/goa-oauth2-handler %u
+Type=Application
+MimeType=x-scheme-handler/goa-oauth2;@oauth2_schemes@
+NoDisplay=true
diff --git a/doc/goa-docs.xml b/doc/goa-docs.xml
index 0abb53a..a9d45e1 100644
--- a/doc/goa-docs.xml
+++ b/doc/goa-docs.xml
@@ -171,7 +171,6 @@
<title>Core</title>
<xi:include href="xml/goautil.xml"/>
<xi:include href="xml/goaprovider.xml"/>
- <xi:include href="xml/goaoauthprovider.xml"/>
<xi:include href="xml/goaoauth2provider.xml"/>
</chapter>
</part>
diff --git a/doc/goa-sections.txt b/doc/goa-sections.txt
index 306846e..a27d942 100644
--- a/doc/goa-sections.txt
+++ b/doc/goa-sections.txt
@@ -498,36 +498,6 @@ GoaOAuth2ProviderPrivate
goa_oauth2_provider_get_type
</SECTION>
-<SECTION>
-<FILE>goaoauthprovider</FILE>
-GoaOAuthProvider
-GoaOAuthProviderClass
-goa_oauth_provider_get_request_uri
-goa_oauth_provider_get_request_uri_params
-goa_oauth_provider_get_authorization_uri
-goa_oauth_provider_get_token_uri
-goa_oauth_provider_get_callback_uri
-goa_oauth_provider_get_consumer_key
-goa_oauth_provider_get_consumer_secret
-goa_oauth_provider_build_authorization_uri
-goa_oauth_provider_get_use_mobile_browser
-goa_oauth_provider_is_deny_node
-goa_oauth_provider_is_identity_node
-goa_oauth_provider_is_password_node
-goa_oauth_provider_add_account_key_values
-goa_oauth_provider_get_identity_sync
-goa_oauth_provider_get_access_token_sync
-goa_oauth_provider_parse_request_token_error
-<SUBSECTION Standard>
-GOA_OAUTH_PROVIDER
-GOA_OAUTH_PROVIDER_CLASS
-GOA_OAUTH_PROVIDER_GET_CLASS
-GOA_IS_OAUTH_PROVIDER
-GOA_IS_OAUTH_PROVIDER_CLASS
-GOA_TYPE_OAUTH_PROVIDER
-goa_oauth_provider_get_type
-</SECTION>
-
<SECTION>
<FILE>GoaMail</FILE>
GoaMail
diff --git a/doc/goa.types b/doc/goa.types
index 56ba3c4..d8d7325 100644
--- a/doc/goa.types
+++ b/doc/goa.types
@@ -62,5 +62,4 @@ goa_printers_proxy_get_type
goa_printers_skeleton_get_type
goa_provider_get_type
-goa_oauth_provider_get_type
goa_oauth2_provider_get_type
diff --git a/po/POTFILES.in b/po/POTFILES.in
index b65650c..8ee89ae 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -22,7 +22,6 @@ src/goabackend/goasmtpauth.c
src/goabackend/goatelepathyprovider.c
src/goabackend/goatodoistprovider.c
src/goabackend/goautils.c
-src/goabackend/goawebview.c
src/goabackend/goawindowsliveprovider.c
src/goaidentity/goaidentityservice.c
src/goaidentity/goakerberosidentity.c
diff --git a/src/goabackend/Makefile.am b/src/goabackend/Makefile.am
index c254594..7f15518 100644
--- a/src/goabackend/Makefile.am
+++ b/src/goabackend/Makefile.am
@@ -19,7 +19,6 @@ AM_CPPFLAGS = \
-DPACKAGE_LOCALSTATE_DIR=\""$(localstatedir)"\" \
-DPACKAGE_LOCALE_DIR=\""$(localedir)"\" \
-DPACKAGE_LIB_DIR=\""$(libdir)"\" \
- -DPACKAGE_WEB_EXTENSIONS_DIR=\""$(libdir)/goa-1.0/web-extensions"\" \
-D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT \
$(WARN_CFLAGS) \
$(NULL)
@@ -81,17 +80,13 @@ libgoa_backend_1_0_la_SOURCES = \
goasouplogger.h goasouplogger.c \
goamailclient.h goamailclient.c \
goaexchangeprovider.h goaexchangeprovider.c \
- goaoauthprovider.h goaoauthprovider.c \
goaoauth2provider.h goaoauth2provider-priv.h \
- goaoauth2provider-web-extension.h \
- goaoauth2provider-web-view.h \
goaoauth2provider.c \
goagoogleprovider.h goagoogleprovider.c \
goafacebookprovider.h goafacebookprovider.c \
goaimapsmtpprovider.h goaimapsmtpprovider.c \
goamediaserverprovider.h goamediaserverprovider.c \
goaowncloudprovider.h goaowncloudprovider.c \
- goaflickrprovider.h goaflickrprovider.c \
goafoursquareprovider.h goafoursquareprovider.c \
goawindowsliveprovider.h goawindowsliveprovider.c \
goapocketprovider.h goapocketprovider.c \
@@ -99,7 +94,6 @@ libgoa_backend_1_0_la_SOURCES = \
goatodoistprovider.h goatodoistprovider.c \
goaobjectskeletonutils.h goaobjectskeletonutils.c \
goautils.h goautils.c \
- goawebview.h goawebview.c \
nautilus-floating-bar.h nautilus-floating-bar.c \
$(top_builddir)/src/goaidentity/org.gnome.Identity.c \
$(top_srcdir)/src/goaidentity/goaidentitymanagererror.c \
@@ -119,7 +113,6 @@ libgoa_backend_1_0_la_SOURCES += \
endif
libgoa_backend_1_0_la_CFLAGS = \
- $(WEBKIT_GTK_CFLAGS) \
$(JSON_GLIB_CFLAGS) \
$(GCR_CFLAGS) \
$(GLIB_CFLAGS) \
@@ -134,7 +127,6 @@ libgoa_backend_1_0_la_CFLAGS = \
libgoa_backend_1_0_la_LIBADD = \
$(top_builddir)/src/goa/libgoa-1.0.la \
- $(WEBKIT_GTK_LIBS) \
$(JSON_GLIB_LIBS) \
$(GCR_LIBS) \
$(GLIB_LIBS) \
@@ -154,39 +146,29 @@ libgoa_backend_1_0_la_LDFLAGS = \
# ----------------------------------------------------------------------------------------------------
-webextension_LTLIBRARIES = libgoawebextension.la
+libexec_PROGRAMS = goa-oauth2-handler
-webextensiondir = $(libdir)/goa-1.0/web-extensions
-
-libgoawebextension_la_SOURCES = \
- goawebextension.h goawebextension.c \
- goawebextensionmain.c \
+goa_oauth2_handler_SOURCES = \
+ goaoauth2handler.c \
$(NULL)
-libgoawebextension_la_CFLAGS = \
- $(REST_CFLAGS) \
- $(WEBKIT_GTK_CFLAGS) \
+goa_oauth2_handler_CFLAGS = \
+ $(GLIB_CFLAGS) \
+ $(LIBSOUP_CFLAGS) \
+ $(SECRET_CFLAGS) \
+ -DG_LOG_DOMAIN=\"goa-oauth2-handler\" \
$(NULL)
-libgoawebextension_la_LIBADD = \
- libgoa-backend-1.0.la \
- $(REST_LIBS) \
- $(WEBKIT_GTK_LIBS) \
+goa_oauth2_handler_LDADD = \
+ $(GLIB_LIBS) \
+ $(LIBSOUP_LIBS) \
+ $(SECRET_LIBS) \
$(NULL)
-libgoawebextension_la_LDFLAGS = \
- -avoid-version \
- -module \
- -no-undefined \
+goa_oauth2_handler_LDFLAGS = \
+ $(WARN_LDFLAGS) \
$(NULL)
-# Force installation order: libgoa-backend-1.0 must be installed first, othwerwise
-# libtool will incorrectly relink libgoawebextension.la under parallel make install.
-# Requires ugly automake syntax - see http://debbugs.gnu.org/cgi/bugreport.cgi?bug=7328
-
-installwebextensionLTLIBRARIES = install-webextensionLTLIBRARIES
-$(installwebextensionLTLIBRARIES): install-libLTLIBRARIES
-
# ----------------------------------------------------------------------------------------------------
BUILT_SOURCES = \
diff --git a/src/goabackend/goafacebookprovider.c b/src/goabackend/goafacebookprovider.c
index c6033fb..c1d35d0 100644
--- a/src/goabackend/goafacebookprovider.c
+++ b/src/goabackend/goafacebookprovider.c
@@ -243,31 +243,6 @@ get_identity_sync (GoaOAuth2Provider *oauth2_provider,
/* ---------------------------------------------------------------------------------------------------- */
-static gboolean
-is_identity_node (GoaOAuth2Provider *oauth2_provider, WebKitDOMHTMLInputElement *element)
-{
- gboolean ret = FALSE;
- gchar *element_type = NULL;
- gchar *name = NULL;
-
- g_object_get (element, "type", &element_type, NULL);
- if (g_strcmp0 (element_type, "text") != 0)
- goto out;
-
- name = webkit_dom_html_input_element_get_name (element);
- if (g_strcmp0 (name, "email") != 0)
- goto out;
-
- ret = TRUE;
-
- out:
- g_free (element_type);
- g_free (name);
- return ret;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
static gboolean
build_object (GoaProvider *provider,
GoaObjectSkeleton *object,
@@ -367,6 +342,5 @@ goa_facebook_provider_class_init (GoaFacebookProviderClass *klass)
oauth2_class->get_client_id = get_client_id;
oauth2_class->get_client_secret = get_client_secret;
oauth2_class->get_identity_sync = get_identity_sync;
- oauth2_class->is_identity_node = is_identity_node;
oauth2_class->add_account_key_values = add_account_key_values;
}
diff --git a/src/goabackend/goaflickrprovider.c b/src/goabackend/goaflickrprovider.c
deleted file mode 100644
index 702ed1e..0000000
--- a/src/goabackend/goaflickrprovider.c
+++ /dev/null
@@ -1,364 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-/*
- * Copyright (C) 2011 Willem van Engen <gnome@willem.engen.nl>
- * Copyright © 2012 2017 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-#include <glib/gi18n-lib.h>
-
-#include <rest/oauth-proxy.h>
-#include <json-glib/json-glib.h>
-
-#include "goaprovider.h"
-#include "goaprovider-priv.h"
-#include "goaflickrprovider.h"
-#include "goaobjectskeletonutils.h"
-#include "goasouplogger.h"
-
-struct _GoaFlickrProvider
-{
- GoaOAuthProvider parent_instance;
-};
-
-G_DEFINE_TYPE_WITH_CODE (GoaFlickrProvider, goa_flickr_provider, GOA_TYPE_OAUTH_PROVIDER,
- goa_provider_ensure_extension_points_registered ();
- g_io_extension_point_implement (GOA_PROVIDER_EXTENSION_POINT_NAME,
- g_define_type_id,
- GOA_FLICKR_NAME,
- 0));
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static const gchar *
-get_provider_type (GoaProvider *provider)
-{
- return GOA_FLICKR_NAME;
-}
-
-static gchar *
-get_provider_name (GoaProvider *provider,
- GoaObject *object)
-{
- return g_strdup (_("Flickr"));
-}
-
-static GoaProviderGroup
-get_provider_group (GoaProvider *provider)
-{
- return GOA_PROVIDER_GROUP_BRANDED;
-}
-
-static GoaProviderFeatures
-get_provider_features (GoaProvider *provider)
-{
- return GOA_PROVIDER_FEATURE_BRANDED | GOA_PROVIDER_FEATURE_PHOTOS;
-}
-
-static const gchar *
-get_consumer_key (GoaOAuthProvider *oauth_provider)
-{
- return GOA_FLICKR_CONSUMER_KEY;
-}
-
-static const gchar *
-get_consumer_secret (GoaOAuthProvider *oauth_provider)
-{
- return GOA_FLICKR_CONSUMER_SECRET;
-}
-
-static const gchar *
-get_request_uri (GoaOAuthProvider *oauth_provider)
-{
- return "https://www.flickr.com/services/oauth/request_token";
-}
-
-static const gchar *
-get_authorization_uri (GoaOAuthProvider *oauth_provider)
-{
- return "https://www.flickr.com/services/oauth/authorize";
-}
-
-static const gchar *
-get_token_uri (GoaOAuthProvider *oauth_provider)
-{
- return "https://www.flickr.com/services/oauth/access_token";
-}
-
-static const gchar *
-get_callback_uri (GoaOAuthProvider *oauth_provider)
-{
- /* Should match the URI specified in the Flickr App
- * Garden in order to detect when the user denied access via
- * the OAuth1 web page.
- */
- return "https://www.gnome.org/";
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static gchar *
-get_identity_sync (GoaOAuthProvider *oauth_provider,
- const gchar *access_token,
- const gchar *access_token_secret,
- gchar **out_presentation_identity,
- GCancellable *cancellable,
- GError **error)
-{
- GError *identity_error = NULL;
- RestProxy *proxy = NULL;
- RestProxyCall *call = NULL;
- JsonParser *parser = NULL;
- JsonObject *json_object;
- SoupLogger *logger = NULL;
- gchar *ret = NULL;
- gchar *id = NULL;
- gchar *presentation_identity = NULL;
-
- /* TODO: cancellable */
-
- proxy = oauth_proxy_new_with_token (goa_oauth_provider_get_consumer_key (oauth_provider),
- goa_oauth_provider_get_consumer_secret (oauth_provider),
- access_token,
- access_token_secret,
- "https://api.flickr.com/services/rest",
- FALSE);
- logger = goa_soup_logger_new (SOUP_LOGGER_LOG_BODY, -1);
- rest_proxy_add_soup_feature (proxy, SOUP_SESSION_FEATURE (logger));
-
- call = rest_proxy_new_call (proxy);
- rest_proxy_call_add_param (call, "method", "flickr.test.login");
- rest_proxy_call_add_param (call, "format", "json");
- rest_proxy_call_add_param (call, "nojsoncallback", "1");
- rest_proxy_call_set_method (call, "GET");
-
- if (!rest_proxy_call_sync (call, error))
- goto out;
- if (rest_proxy_call_get_status_code (call) != 200)
- {
- g_set_error (error,
- GOA_ERROR,
- GOA_ERROR_FAILED,
- _("Expected status 200 when requesting your identity, instead got status %d (%s)"),
- rest_proxy_call_get_status_code (call),
- rest_proxy_call_get_status_message (call));
- goto out;
- }
-
- parser = json_parser_new ();
- if (!json_parser_load_from_data (parser,
- rest_proxy_call_get_payload (call),
- rest_proxy_call_get_payload_length (call),
- &identity_error))
- {
- g_warning ("json_parser_load_from_data() failed: %s (%s, %d)",
- identity_error->message,
- g_quark_to_string (identity_error->domain),
- identity_error->code);
- g_set_error (error,
- GOA_ERROR,
- GOA_ERROR_FAILED,
- _("Could not parse response"));
- goto out;
- }
-
- json_object = json_node_get_object (json_parser_get_root (parser));
- if (!json_object_has_member (json_object, "user"))
- {
- g_warning ("Did not find user in JSON data");
- g_set_error (error,
- GOA_ERROR,
- GOA_ERROR_FAILED,
- _("Could not parse response"));
- goto out;
- }
-
- json_object = json_object_get_object_member (json_object, "user");
- if (!json_object_has_member (json_object, "id"))
- {
- g_warning ("Did not find user.id in JSON data");
- g_set_error (error,
- GOA_ERROR,
- GOA_ERROR_FAILED,
- _("Could not parse response"));
- goto out;
- }
- if (!json_object_has_member (json_object, "username"))
- {
- g_warning ("Did not find user.username in JSON data");
- g_set_error (error,
- GOA_ERROR,
- GOA_ERROR_FAILED,
- _("Could not parse response"));
- goto out;
- }
-
- id = g_strdup (json_object_get_string_member (json_object, "id"));
-
- json_object = json_object_get_object_member (json_object, "username");
- if (!json_object_has_member (json_object, "_content"))
- {
- g_warning ("Did not find user.username._content in JSON data");
- g_set_error (error,
- GOA_ERROR,
- GOA_ERROR_FAILED,
- _("Could not parse response"));
- goto out;
- }
-
- presentation_identity = g_strdup (json_object_get_string_member (json_object, "_content"));
-
- ret = id;
- id = NULL;
- if (out_presentation_identity != NULL)
- {
- *out_presentation_identity = presentation_identity;
- presentation_identity = NULL;
- }
-
- out:
- g_clear_object (&parser);
- g_clear_error (&identity_error);
- g_clear_object (&call);
- g_clear_object (&proxy);
- g_clear_object (&logger);
- g_free (id);
- g_free (presentation_identity);
- return ret;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static gboolean
-is_identity_node (GoaOAuthProvider *oauth_provider, WebKitDOMHTMLInputElement *element)
-{
- /* Flickr does not provide a way to query the string used by the
- * user to log in via the web interface. The user id and username
- * returned by flickr.test.login [1] are not what we are looking
- * for.
- *
- * [1] http://www.flickr.com/services/api/flickr.test.login.html
- */
- return FALSE;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static gchar *
-parse_request_token_error (GoaOAuthProvider *oauth_provider, RestProxyCall *call)
-{
- const gchar *payload;
- gchar *msg = NULL;
- guint status;
-
- payload = rest_proxy_call_get_payload (call);
- status = rest_proxy_call_get_status_code (call);
-
- if (status == 401 && g_strcmp0 (payload, "oauth_problem=timestamp_refused") == 0)
- msg = g_strdup (_("Your system time is invalid. Check your date and time settings."));
-
- return msg;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static gboolean
-build_object (GoaProvider *provider,
- GoaObjectSkeleton *object,
- GKeyFile *key_file,
- const gchar *group,
- GDBusConnection *connection,
- gboolean just_added,
- GError **error)
-{
- GoaAccount *account = NULL;
- gboolean photos_enabled;
- gboolean ret = FALSE;
-
- /* Chain up */
- if (!GOA_PROVIDER_CLASS (goa_flickr_provider_parent_class)->build_object (provider,
- object,
- key_file,
- group,
- connection,
- just_added,
- error))
- goto out;
-
- account = goa_object_get_account (GOA_OBJECT (object));
-
- /* Photos */
- photos_enabled = g_key_file_get_boolean (key_file, group, "PhotosEnabled", NULL);
- goa_object_skeleton_attach_photos (object, photos_enabled);
-
- if (just_added)
- {
- goa_account_set_photos_disabled (account, !photos_enabled);
-
- g_signal_connect (account,
- "notify::photos-disabled",
- G_CALLBACK (goa_util_account_notify_property_cb),
- (gpointer) "PhotosEnabled");
- }
-
- ret = TRUE;
-
- out:
- g_clear_object (&account);
- return ret;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static void
-add_account_key_values (GoaOAuthProvider *oauth_provider,
- GVariantBuilder *builder)
-{
- g_variant_builder_add (builder, "{ss}", "PhotosEnabled", "true");
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static void
-goa_flickr_provider_init (GoaFlickrProvider *self)
-{
-}
-
-static void
-goa_flickr_provider_class_init (GoaFlickrProviderClass *klass)
-{
- GoaProviderClass *provider_class;
- GoaOAuthProviderClass *oauth_class;
-
- provider_class = GOA_PROVIDER_CLASS (klass);
- provider_class->get_provider_type = get_provider_type;
- provider_class->get_provider_name = get_provider_name;
- provider_class->get_provider_group = get_provider_group;
- provider_class->get_provider_features = get_provider_features;
- provider_class->build_object = build_object;
-
- oauth_class = GOA_OAUTH_PROVIDER_CLASS (klass);
- oauth_class->get_identity_sync = get_identity_sync;
- oauth_class->is_identity_node = is_identity_node;
- oauth_class->get_consumer_key = get_consumer_key;
- oauth_class->get_consumer_secret = get_consumer_secret;
- oauth_class->get_request_uri = get_request_uri;
- oauth_class->get_authorization_uri = get_authorization_uri;
- oauth_class->get_token_uri = get_token_uri;
- oauth_class->get_callback_uri = get_callback_uri;
- oauth_class->parse_request_token_error = parse_request_token_error;
- oauth_class->add_account_key_values = add_account_key_values;
-}
diff --git a/src/goabackend/goaflickrprovider.h b/src/goabackend/goaflickrprovider.h
deleted file mode 100644
index f08a8a6..0000000
--- a/src/goabackend/goaflickrprovider.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-/*
- * Copyright © 2012 Willem van Engen <gnome@willem.engen.nl>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#if !defined (__GOA_BACKEND_INSIDE_GOA_BACKEND_H__) && !defined (GOA_BACKEND_COMPILATION)
-#error "Only <goabackend/goabackend.h> can be included directly."
-#endif
-
-#ifndef __GOA_FLICKR_PROVIDER_H__
-#define __GOA_FLICKR_PROVIDER_H__
-
-#include <glib-object.h>
-
-#include "goaoauthprovider.h"
-
-G_BEGIN_DECLS
-
-#define GOA_TYPE_FLICKR_PROVIDER (goa_flickr_provider_get_type ())
-G_DECLARE_FINAL_TYPE (GoaFlickrProvider, goa_flickr_provider, GOA, FLICKR_PROVIDER, GoaOAuthProvider);
-
-G_END_DECLS
-
-#endif /* __GOA_FLICKR_PROVIDER_H__ */
diff --git a/src/goabackend/goafoursquareprovider.c b/src/goabackend/goafoursquareprovider.c
index c1e4146..def21cb 100644
--- a/src/goabackend/goafoursquareprovider.c
+++ b/src/goabackend/goafoursquareprovider.c
@@ -251,31 +251,6 @@ get_identity_sync (GoaOAuth2Provider *oauth2_provider,
/* ---------------------------------------------------------------------------------------------------- */
-static gboolean
-is_identity_node (GoaOAuth2Provider *oauth2_provider, WebKitDOMHTMLInputElement *element)
-{
- gboolean ret = FALSE;
- gchar *element_type = NULL;
- gchar *name = NULL;
-
- g_object_get (element, "type", &element_type, NULL);
- if (g_strcmp0 (element_type, "email") != 0)
- goto out;
-
- name = webkit_dom_html_input_element_get_name (element);
- if (g_strcmp0 (name, "emailOrPhone") != 0)
- goto out;
-
- ret = TRUE;
-
- out:
- g_free (element_type);
- g_free (name);
- return ret;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
static gboolean
build_object (GoaProvider *provider,
GoaObjectSkeleton *object,
@@ -366,6 +341,5 @@ goa_foursquare_provider_class_init (GoaFoursquareProviderClass *klass)
oauth2_class->get_client_secret = get_client_secret;
oauth2_class->get_use_mobile_browser = get_use_mobile_browser;
oauth2_class->get_identity_sync = get_identity_sync;
- oauth2_class->is_identity_node = is_identity_node;
oauth2_class->add_account_key_values = add_account_key_values;
}
diff --git a/src/goabackend/goagoogleprovider.c b/src/goabackend/goagoogleprovider.c
index 6e4ace2..6f951e5 100644
--- a/src/goabackend/goagoogleprovider.c
+++ b/src/goabackend/goagoogleprovider.c
@@ -32,6 +32,7 @@
struct _GoaGoogleProvider
{
GoaOAuth2Provider parent_instance;
+ gchar *redirect_uri;
};
G_DEFINE_TYPE_WITH_CODE (GoaGoogleProvider, goa_google_provider, GOA_TYPE_OAUTH2_PROVIDER,
@@ -81,19 +82,50 @@ get_provider_features (GoaProvider *provider)
static const gchar *
get_authorization_uri (GoaOAuth2Provider *oauth2_provider)
{
- return "https://accounts.google.com/o/oauth2/auth";
+ return "https://accounts.google.com/o/oauth2/v2/auth";
}
static const gchar *
get_token_uri (GoaOAuth2Provider *oauth2_provider)
{
- return "https://accounts.google.com/o/oauth2/token";
+ return "https://oauth2.googleapis.com/token";
}
static const gchar *
get_redirect_uri (GoaOAuth2Provider *oauth2_provider)
{
- return "http://localhost";
+ G_LOCK_DEFINE_STATIC (redirect_uri);
+ GoaGoogleProvider *self = GOA_GOOGLE_PROVIDER (oauth2_provider);
+
+ G_LOCK (redirect_uri);
+
+ if (!self->redirect_uri) {
+ GPtrArray *array;
+ gchar **strv;
+ gchar *joinstr;
+ guint ii;
+
+ strv = g_strsplit (GOA_GOOGLE_CLIENT_ID, ".", -1);
+ array = g_ptr_array_new ();
+
+ for (ii = 0; strv[ii]; ii++) {
+ g_ptr_array_insert (array, 0, strv[ii]);
+ }
+
+ g_ptr_array_add (array, NULL);
+
+ joinstr = g_strjoinv (".", (gchar **) array->pdata);
+ /* Use reverse-DNS of the client ID with the below path */
+ self->redirect_uri = g_strconcat (joinstr, ":/oauth2redirect", NULL);
+
+ g_ptr_array_free (array, TRUE);
+ g_strfreev (strv);
+ g_free (joinstr);
+ }
+
+ G_UNLOCK (redirect_uri);
+
+ return self->redirect_uri;
}
static const gchar *
@@ -241,37 +273,6 @@ get_identity_sync (GoaOAuth2Provider *oauth2_provider,
/* ---------------------------------------------------------------------------------------------------- */
-static gboolean
-is_identity_node (GoaOAuth2Provider *oauth2_provider, WebKitDOMHTMLInputElement *element)
-{
- gboolean ret = FALSE;
- gchar *element_type = NULL;
- gchar *id = NULL;
- gchar *name = NULL;
-
- g_object_get (element, "type", &element_type, NULL);
- if (g_strcmp0 (element_type, "email") != 0)
- goto out;
-
- id = webkit_dom_element_get_id (WEBKIT_DOM_ELEMENT (element));
- if (g_strcmp0 (id, "identifierId") != 0)
- goto out;
-
- name = webkit_dom_html_input_element_get_name (element);
- if (g_strcmp0 (name, "identifier") != 0)
- goto out;
-
- ret = TRUE;
-
- out:
- g_free (element_type);
- g_free (id);
- g_free (name);
- return ret;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
static gboolean
build_object (GoaProvider *provider,
GoaObjectSkeleton *object,
@@ -446,6 +447,16 @@ add_account_key_values (GoaOAuth2Provider *oauth2_provider,
/* ---------------------------------------------------------------------------------------------------- */
+static void
+goa_google_finalize (GObject *object)
+{
+ GoaGoogleProvider *self = GOA_GOOGLE_PROVIDER (object);
+
+ g_free (self->redirect_uri);
+
+ G_OBJECT_CLASS (goa_google_provider_parent_class)->finalize (object);
+}
+
static void
goa_google_provider_init (GoaGoogleProvider *self)
{
@@ -456,6 +467,10 @@ goa_google_provider_class_init (GoaGoogleProviderClass *klass)
{
GoaProviderClass *provider_class;
GoaOAuth2ProviderClass *oauth2_class;
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = goa_google_finalize;
provider_class = GOA_PROVIDER_CLASS (klass);
provider_class->get_provider_type = get_provider_type;
@@ -472,7 +487,6 @@ goa_google_provider_class_init (GoaGoogleProviderClass *klass)
oauth2_class->get_identity_sync = get_identity_sync;
oauth2_class->get_redirect_uri = get_redirect_uri;
oauth2_class->get_scope = get_scope;
- oauth2_class->is_identity_node = is_identity_node;
oauth2_class->get_token_uri = get_token_uri;
oauth2_class->add_account_key_values = add_account_key_values;
}
diff --git a/src/goabackend/goaoauth2handler.c b/src/goabackend/goaoauth2handler.c
new file mode 100644
index 0000000..c5a86cb
--- /dev/null
+++ b/src/goabackend/goaoauth2handler.c
@@ -0,0 +1,173 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright © 2023 GNOME Foundation Inc.
+ * Contributor: Andy Holmes <andyholmes@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <libsoup/soup.h>
+#include <libsecret/secret.h>
+
+
+static const SecretSchema oauth2_schema =
+{
+ .name = "org.gnome.OnlineAccounts.OAuth2",
+ .flags = SECRET_SCHEMA_NONE,
+ .attributes = {
+ {
+ .name = "goa-oauth2-client",
+ .type = SECRET_SCHEMA_ATTRIBUTE_STRING,
+ },
+ {
+ .name = "goa-oauth2-provider",
+ .type = SECRET_SCHEMA_ATTRIBUTE_STRING,
+ },
+ { "NULL", 0 }
+ }
+};
+
+static struct
+{
+ const char *client_id;
+ const char *provider;
+}
+oauth2_providers[] =
+{
+#ifdef GOA_GOOGLE_ENABLED
+ {
+ .client_id = GOA_GOOGLE_CLIENT_ID,
+ .provider = GOA_GOOGLE_NAME,
+ },
+#endif
+#ifdef GOA_WINDOWS_LIVE_ENABLED
+ {
+ .client_id = GOA_WINDOWS_LIVE_CLIENT_ID,
+ .provider = GOA_WINDOWS_LIVE_NAME,
+ },
+#endif
+ { NULL, NULL },
+};
+
+static gboolean
+get_oauth2_provider (const char *needle,
+ const char **client_out,
+ const char **provider_out)
+{
+ g_return_val_if_fail (needle != NULL, FALSE);
+
+ for (unsigned int i = 0; oauth2_providers[i].client_id != NULL; i++)
+ {
+ if (g_str_equal (needle, oauth2_providers[i].client_id))
+ {
+ if (client_out)
+ *client_out = oauth2_providers[i].client_id;
+
+ if (provider_out)
+ *provider_out = oauth2_providers[i].provider;
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ SoupURI *uri = NULL;
+ const char *scheme = NULL;
+ const char *path = NULL;
+ const char *client_id = NULL;
+ const char *provider_type = NULL;
+ GError *error = NULL;
+
+ if (argc < 2)
+ {
+ g_printerr ("%s: Missing URI\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ uri = soup_uri_new (argv[1]);
+ if (uri == NULL)
+ {
+ g_printerr ("%s: Invalid URI: %s\n", argv[0], argv[1]);
+ return EXIT_FAILURE;
+ }
+
+ /* Google apps may use a reverse-DNS form of the client ID as the URI scheme
+ * See: https://developers.google.com/identity/protocols/oauth2/native-app
+ */
+ scheme = soup_uri_get_scheme (uri);
+ if (scheme != NULL)
+ {
+ g_auto (GStrv) strv = g_strsplit (scheme, ".", -1);
+ g_autoptr (GString) tmp = g_string_new ("");
+
+ for (unsigned int i = 0; strv[i] != NULL; i++)
+ {
+ if (i > 0)
+ g_string_prepend_c (tmp, '.');
+ g_string_prepend (tmp, strv[i]);
+ }
+
+ get_oauth2_provider (tmp->str, &client_id, &provider_type);
+ }
+
+ /* Windows Live uses goa-oauth2:// with the client ID as the first path segment
+ */
+ if (client_id == NULL)
+ {
+ path = soup_uri_get_path (uri);
+ if (path != NULL && *path != '\0')
+ {
+ g_auto (GStrv) strv = NULL;
+
+ strv = g_strsplit (*path == '/' ? path +1 : path, "/", 1);
+ get_oauth2_provider (strv[0], &client_id, &provider_type);
+ }
+ }
+
+ if (client_id == NULL)
+ {
+ g_printerr ("%s: Unknown provider\n", argv[0]);
+ soup_uri_free (uri);
+ return EXIT_FAILURE;
+ }
+
+ if (!secret_password_store_sync (&oauth2_schema,
+ SECRET_COLLECTION_SESSION,
+ "GNOME Online Accounts OAuth2 URI",
+ argv[1], /* Secret */
+ NULL,
+ &error,
+ "goa-oauth2-client", client_id,
+ "goa-oauth2-provider", provider_type,
+ NULL))
+ {
+ if (error != NULL)
+ g_printerr ("%s: Failed to store OAuth2 URI: %s\n", argv[0], error->message);
+
+ soup_uri_free (uri);
+ g_clear_error (&error);
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/goabackend/goaoauth2provider-priv.h b/src/goabackend/goaoauth2provider-priv.h
index de1b808..4b00a24 100644
--- a/src/goabackend/goaoauth2provider-priv.h
+++ b/src/goabackend/goaoauth2provider-priv.h
@@ -26,8 +26,6 @@
#include <gio/gio.h>
#include <goabackend/goaoauth2provider.h>
#include <goabackend/goaprovider-priv.h>
-#include <webkit2/webkit2.h>
-#include <webkitdom/webkitdom.h>
G_BEGIN_DECLS
@@ -51,11 +49,7 @@ G_BEGIN_DECLS
* @build_authorization_uri: Virtual function for goa_oauth2_provider_build_authorization_uri().
* @get_use_mobile_browser: Virtual function for goa_oauth2_provider_get_use_mobile_browser().
* @add_account_key_values: Virtual function for goa_oauth2_provider_add_account_key_values().
- * @decide_navigation_policy: Virtual function for goa_oauth2_provider_decide_navigation_policy().
* @process_redirect_url: Virtual function for goa_oauth2_provider_process_redirect_url().
- * @is_deny_node: Virtual function for goa_oauth2_provider_is_deny_node().
- * @is_identity_node: Virtual function for goa_oauth2_provider_is_identity_node().
- * @is_password_node: Virtual function for goa_oauth2_provider_is_password_node().
*
* Class structure for #GoaOAuth2Provider.
*/
@@ -86,18 +80,7 @@ struct _GoaOAuth2ProviderClass
void (*add_account_key_values) (GoaOAuth2Provider *provider,
GVariantBuilder *builder);
- /* pure virtual */
- gboolean (*is_identity_node) (GoaOAuth2Provider *provider,
- WebKitDOMHTMLInputElement *element);
-
/* virtual but with default implementation */
- gboolean (*is_deny_node) (GoaOAuth2Provider *provider,
- WebKitDOMNode *node);
- gboolean (*is_password_node) (GoaOAuth2Provider *provider,
- WebKitDOMHTMLInputElement *element);
- gboolean (*decide_navigation_policy) (GoaOAuth2Provider *provider,
- WebKitWebView *web_view,
- WebKitNavigationPolicyDecision *decision);
gboolean (*process_redirect_url) (GoaOAuth2Provider *provider,
const gchar *redirect_url,
gchar **access_token,
diff --git a/src/goabackend/goaoauth2provider-web-extension.h b/src/goabackend/goaoauth2provider-web-extension.h
deleted file mode 100644
index baac005..0000000
--- a/src/goabackend/goaoauth2provider-web-extension.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-/*
- * Copyright © 2016 2017 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#if !defined (__GOA_BACKEND_INSIDE_GOA_BACKEND_H__) && !defined (GOA_BACKEND_COMPILATION)
-#error "Only <goabackend/goabackend.h> can be included directly."
-#endif
-
-#ifndef __GOA_OAUTH2_PROVIDER_WEB_EXTENSION_H__
-#define __GOA_OAUTH2_PROVIDER_WEB_EXTENSION_H__
-
-#include <goabackend/goaoauth2provider.h>
-#include <webkitdom/webkitdom.h>
-
-G_BEGIN_DECLS
-
-gboolean goa_oauth2_provider_is_deny_node (GoaOAuth2Provider *provider,
- WebKitDOMNode *node);
-gboolean goa_oauth2_provider_is_identity_node (GoaOAuth2Provider *provider,
- WebKitDOMHTMLInputElement *element);
-gboolean goa_oauth2_provider_is_password_node (GoaOAuth2Provider *provider,
- WebKitDOMHTMLInputElement *element);
-
-G_END_DECLS
-
-#endif /* __GOA_OAUTH2_PROVIDER_WEB_EXTENSION_H__ */
diff --git a/src/goabackend/goaoauth2provider-web-view.h b/src/goabackend/goaoauth2provider-web-view.h
deleted file mode 100644
index f2dae5e..0000000
--- a/src/goabackend/goaoauth2provider-web-view.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-/*
- * Copyright © 2016 2017 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#if !defined (__GOA_BACKEND_INSIDE_GOA_BACKEND_H__) && !defined (GOA_BACKEND_COMPILATION)
-#error "Only <goabackend/goabackend.h> can be included directly."
-#endif
-
-#ifndef __GOA_OAUTH2_PROVIDER_WEB_VIEW_H__
-#define __GOA_OAUTH2_PROVIDER_WEB_VIEW_H__
-
-#include <goabackend/goaoauth2provider.h>
-#include <webkit2/webkit2.h>
-
-G_BEGIN_DECLS
-
-gboolean goa_oauth2_provider_decide_navigation_policy (GoaOAuth2Provider *provider,
- WebKitWebView *web_view,
- WebKitNavigationPolicyDecision *decision);
-
-G_END_DECLS
-
-#endif /* __GOA_OAUTH2_PROVIDER_WEB_VIEW_H__ */
diff --git a/src/goabackend/goaoauth2provider.c b/src/goabackend/goaoauth2provider.c
index 9092605..1ceacb5 100644
--- a/src/goabackend/goaoauth2provider.c
+++ b/src/goabackend/goaoauth2provider.c
@@ -22,16 +22,13 @@
#include <rest/oauth2-proxy.h>
#include <libsoup/soup.h>
+#include <libsecret/secret.h>
#include <json-glib/json-glib.h>
-#include <webkit2/webkit2.h>
#include "goaprovider.h"
#include "goautils.h"
-#include "goawebview.h"
#include "goaoauth2provider.h"
#include "goaoauth2provider-priv.h"
-#include "goaoauth2provider-web-extension.h"
-#include "goaoauth2provider-web-view.h"
#include "goarestproxy.h"
/**
@@ -81,6 +78,8 @@ struct _GoaOAuth2ProviderPrivate
gchar *identity;
gchar *presentation_identity;
gchar *password;
+ gchar *request_uri;
+ SecretCollection *session;
};
G_LOCK_DEFINE_STATIC (provider_lock);
@@ -134,70 +133,6 @@ goa_oauth2_provider_get_use_mobile_browser (GoaOAuth2Provider *self)
/* ---------------------------------------------------------------------------------------------------- */
-static gboolean
-goa_oauth2_provider_is_deny_node_default (GoaOAuth2Provider *self, WebKitDOMNode *node)
-{
- return FALSE;
-}
-
-/**
- * goa_oauth2_provider_is_deny_node:
- * @self: A #GoaOAuth2Provider.
- * @node: A WebKitDOMNode.
- *
- * Checks whether @node is the HTML UI element that the user can use
- * to deny permission to access his account. Usually they are either a
- * WebKitDOMHTMLButtonElement or a WebKitDOMHTMLInputElement.
- *
- * Please note that providers may have multiple such elements in their
- * UI and this method should catch all of them.
- *
- * This is a virtual method where the default implementation returns
- * %FALSE.
- *
- * Returns: %TRUE if the @node can be used to deny permission.
- */
-gboolean
-goa_oauth2_provider_is_deny_node (GoaOAuth2Provider *self, WebKitDOMNode *node)
-{
- g_return_val_if_fail (GOA_IS_OAUTH2_PROVIDER (self), FALSE);
- return GOA_OAUTH2_PROVIDER_GET_CLASS (self)->is_deny_node (self, node);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static gboolean
-goa_oauth2_provider_is_password_node_default (GoaOAuth2Provider *self, WebKitDOMHTMLInputElement *element)
-{
- return FALSE;
-}
-
-/**
- * goa_oauth2_provider_is_password_node:
- * @self: A #GoaOAuth2Provider.
- * @element: A WebKitDOMHTMLInputElement
- *
- * Checks whether @element is the HTML UI element that the user can
- * use to enter her password. This can be used to offer a
- * #GoaPasswordBased interface by saving the user's
- * password. Providers usually frown upon doing this, so this is not
- * recommended.
- *
- * This is a virtual method where the default implementation returns
- * %FALSE.
- *
- * Returns: %TRUE if @element can be used to enter the password.
- */
-gboolean
-goa_oauth2_provider_is_password_node (GoaOAuth2Provider *self, WebKitDOMHTMLInputElement *element)
-{
- g_return_val_if_fail (GOA_IS_OAUTH2_PROVIDER (self), FALSE);
- g_return_val_if_fail (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT (element), FALSE);
- return GOA_OAUTH2_PROVIDER_GET_CLASS (self)->is_password_node (self, element);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
static void
goa_oauth2_provider_add_account_key_values_default (GoaOAuth2Provider *self,
GVariantBuilder *builder)
@@ -287,45 +222,6 @@ goa_oauth2_provider_build_authorization_uri (GoaOAuth2Provider *self,
/* ---------------------------------------------------------------------------------------------------- */
-static gboolean
-goa_oauth2_provider_decide_navigation_policy_default (GoaOAuth2Provider *self,
- WebKitWebView *web_view,
- WebKitNavigationPolicyDecision *decision)
-{
- return FALSE;
-}
-
-/*
- * goa_oauth2_provider_decide_navigation_policy_default:
- * @self: A #GoaOAuth2Provider.
- * @decision: A #WebKitNavigationPolicyDecision
- *
- * Certain OAuth2-like, but not exactly <ulink
- * url="http://tools.ietf.org/html/draft-ietf-oauth-v2-15">OAuth2</ulink>,
- * providers may not send us to the redirect URI, as expected. They
- * might need some special handling for that. This is a provider
- * specific hook to accommodate them.
- *
- * This is a virtual method where the default implementation returns
- * %FALSE.
- *
- * Returns: %TRUE if @provider decided what to do with @decision,
- * %FALSE otherwise.
- */
-gboolean
-goa_oauth2_provider_decide_navigation_policy (GoaOAuth2Provider *self,
- WebKitWebView *web_view,
- WebKitNavigationPolicyDecision *decision)
-{
- g_return_val_if_fail (GOA_IS_OAUTH2_PROVIDER (self), FALSE);
- g_return_val_if_fail (WEBKIT_IS_WEB_VIEW (web_view), FALSE);
- g_return_val_if_fail (WEBKIT_IS_NAVIGATION_POLICY_DECISION (decision), FALSE);
-
- return GOA_OAUTH2_PROVIDER_GET_CLASS (self)->decide_navigation_policy (self, web_view, decision);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
/**
* goa_oauth2_provider_process_redirect_url:
* @self: A #GoaOAuth2Provider.
@@ -551,26 +447,6 @@ goa_oauth2_provider_get_identity_sync (GoaOAuth2Provider *self,
error);
}
-/**
- * goa_oauth2_provider_is_identity_node:
- * @self: A #GoaOAuth2Provider.
- * @element: A WebKitDOMHTMLInputElement.
- *
- * Checks whether @element is the HTML UI element that the user can
- * use to identify herself at the provider.
- *
- * This is a pure virtual method - a subclass must provide an
- * implementation.
- *
- * Returns: %TRUE if the @element can be used to deny permission.
- */
-gboolean
-goa_oauth2_provider_is_identity_node (GoaOAuth2Provider *self, WebKitDOMHTMLInputElement *element)
-{
- g_return_val_if_fail (GOA_IS_OAUTH2_PROVIDER (self), FALSE);
- return GOA_OAUTH2_PROVIDER_GET_CLASS (self)->is_identity_node (self, element);
-}
-
/* ---------------------------------------------------------------------------------------------------- */
static gchar *
@@ -730,72 +606,42 @@ get_tokens_sync (GoaOAuth2Provider *self,
/* ---------------------------------------------------------------------------------------------------- */
-static void
-on_web_view_deny_click (GoaWebView *web_view, gpointer user_data)
-{
- GoaOAuth2Provider *self = GOA_OAUTH2_PROVIDER (user_data);
- GoaOAuth2ProviderPrivate *priv;
-
- priv = goa_oauth2_provider_get_instance_private (self);
- gtk_dialog_response (priv->dialog, GTK_RESPONSE_CANCEL);
-}
-
-static void
-on_web_view_password_submit (GoaWebView *web_view, const gchar *password, gpointer user_data)
-{
- GoaOAuth2Provider *self = GOA_OAUTH2_PROVIDER (user_data);
- GoaOAuth2ProviderPrivate *priv;
-
- priv = goa_oauth2_provider_get_instance_private (self);
-
- g_free (priv->password);
- priv->password = g_strdup (password);
-}
-
static gboolean
-on_web_view_decide_policy (WebKitWebView *web_view,
- WebKitPolicyDecision *decision,
- WebKitPolicyDecisionType decision_type,
- gpointer user_data)
+parse_requested_uri (GoaOAuth2Provider *self,
+ const char *requested_uri)
{
- GoaOAuth2Provider *self = GOA_OAUTH2_PROVIDER (user_data);
- GoaOAuth2ProviderPrivate *priv;
+ GoaOAuth2ProviderPrivate *priv = goa_oauth2_provider_get_instance_private (self);
GHashTable *key_value_pairs;
- WebKitNavigationAction *action;
- WebKitURIRequest *request;
SoupURI *uri;
const gchar *fragment;
const gchar *oauth2_error;
const gchar *query;
const gchar *redirect_uri;
- const gchar *requested_uri;
- gint response_id = GTK_RESPONSE_NONE;
-
- priv = goa_oauth2_provider_get_instance_private (self);
-
- if (decision_type != WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION)
- goto default_behaviour;
-
- if (goa_oauth2_provider_decide_navigation_policy (self,
- web_view,
- WEBKIT_NAVIGATION_POLICY_DECISION (decision)))
- {
- response_id = 0;
- goto ignore_request;
- }
/* TODO: use oauth2_proxy_extract_access_token() */
+ g_assert (priv->error == NULL);
- action = webkit_navigation_policy_decision_get_navigation_action (WEBKIT_NAVIGATION_POLICY_DECISION (decision));
- request = webkit_navigation_action_get_request (action);
- requested_uri = webkit_uri_request_get_uri (request);
redirect_uri = goa_oauth2_provider_get_redirect_uri (self);
if (!g_str_has_prefix (requested_uri, redirect_uri))
- goto default_behaviour;
+ {
+ g_set_error (&priv->error,
+ GOA_ERROR,
+ GOA_ERROR_FAILED,
+ "Invalid URI: %s",
+ requested_uri);
+ return FALSE;
+ }
uri = soup_uri_new (requested_uri);
- fragment = soup_uri_get_fragment (uri);
- query = soup_uri_get_query (uri);
+ if (uri == NULL)
+ {
+ g_set_error (&priv->error,
+ GOA_ERROR,
+ GOA_ERROR_FAILED,
+ "Invalid URI: %s",
+ requested_uri);
+ return FALSE;
+ }
/* Three cases:
* 1) we can either have the backend handle the URI for us, or
@@ -806,23 +652,23 @@ on_web_view_decide_policy (WebKitWebView *web_view,
*/
if (GOA_OAUTH2_PROVIDER_GET_CLASS (self)->process_redirect_url)
{
- gchar *url;
+ g_autofree char *url = NULL;
url = soup_uri_to_string (uri, FALSE);
+ soup_uri_free (uri);
if (!goa_oauth2_provider_process_redirect_url (self, url, &priv->access_token, &priv->error))
{
g_prefix_error (&priv->error, _("Authorization response: "));
priv->error->domain = GOA_ERROR;
priv->error->code = GOA_ERROR_NOT_AUTHORIZED;
- response_id = GTK_RESPONSE_CLOSE;
+
+ return FALSE;
}
- else
- response_id = GTK_RESPONSE_OK;
- g_free (url);
- goto ignore_request;
+ return TRUE;
}
+ fragment = soup_uri_get_fragment (uri);
if (fragment != NULL)
{
/* fragment is encoded into a key/value pairs for the token and
@@ -846,57 +692,175 @@ on_web_view_decide_policy (WebKitWebView *web_view,
priv->access_token_expires_in = atoi (expires_in_str);
priv->refresh_token = g_strdup (g_hash_table_lookup (key_value_pairs, "refresh_token"));
-
- response_id = GTK_RESPONSE_OK;
}
g_hash_table_unref (key_value_pairs);
- }
- if (priv->access_token != NULL)
- goto ignore_request;
+ if (priv->access_token != NULL)
+ {
+ soup_uri_free (uri);
+ return TRUE;
+ }
+ }
+ query = soup_uri_get_query (uri);
if (query != NULL)
{
key_value_pairs = soup_form_decode (query);
priv->authorization_code = g_strdup (g_hash_table_lookup (key_value_pairs, "code"));
- if (priv->authorization_code != NULL)
- response_id = GTK_RESPONSE_OK;
-
g_hash_table_unref (key_value_pairs);
+ if (priv->authorization_code != NULL)
+ {
+ soup_uri_free (uri);
+ return TRUE;
+ }
}
- if (priv->authorization_code != NULL)
- goto ignore_request;
-
/* In case we don't find the access_token or auth code, then look
* for the error in the query part of the URI.
*/
key_value_pairs = soup_form_decode (query);
oauth2_error = (const gchar *) g_hash_table_lookup (key_value_pairs, "error");
if (g_strcmp0 (oauth2_error, GOA_OAUTH2_ACCESS_DENIED) == 0)
- response_id = GTK_RESPONSE_CANCEL;
- else
{
g_set_error (&priv->error,
GOA_ERROR,
GOA_ERROR_NOT_AUTHORIZED,
_("Authorization response: %s"),
oauth2_error);
- response_id = GTK_RESPONSE_CLOSE;
+ }
+ else
+ {
+ g_set_error_literal (&priv->error,
+ GOA_ERROR,
+ GOA_ERROR_FAILED,
+ _("Failed to authenticate"));
}
g_hash_table_unref (key_value_pairs);
- goto ignore_request;
+ soup_uri_free (uri);
+ return FALSE;
+}
- ignore_request:
- g_assert (response_id != GTK_RESPONSE_NONE);
- if (response_id < 0)
- gtk_dialog_response (priv->dialog, response_id);
- webkit_policy_decision_ignore (decision);
- return TRUE;
+/* ---------------------------------------------------------------------------------------------------- */
- default_behaviour:
- return FALSE;
+static const SecretSchema oauth2_schema =
+{
+ .name = "org.gnome.OnlineAccounts.OAuth2",
+ .flags = SECRET_SCHEMA_NONE,
+ .attributes = {
+ {
+ .name = "goa-oauth2-client",
+ .type = SECRET_SCHEMA_ATTRIBUTE_STRING,
+ },
+ {
+ .name = "goa-oauth2-provider",
+ .type = SECRET_SCHEMA_ATTRIBUTE_STRING,
+ },
+ { "NULL", 0 }
+ }
+};
+
+static void
+on_secrets_changed (SecretCollection *collection,
+ GParamSpec *pspec,
+ GoaOAuth2Provider *self)
+{
+ GoaOAuth2ProviderPrivate *priv = goa_oauth2_provider_get_instance_private (self);
+ const char *client_id = NULL;
+ const char *provider_type = NULL;
+ g_autofree char *requested_uri = NULL;
+ GtkResponseType response_id = GTK_RESPONSE_NONE;
+
+ client_id = goa_oauth2_provider_get_client_id (self);
+ provider_type = goa_provider_get_provider_type (GOA_PROVIDER (self));
+ requested_uri = secret_password_lookup_sync (&oauth2_schema, NULL, NULL,
+ "goa-oauth2-client", client_id,
+ "goa-oauth2-provider", provider_type,
+ NULL);
+
+ if (requested_uri != NULL)
+ {
+ if (parse_requested_uri (self, requested_uri))
+ response_id = GTK_RESPONSE_OK;
+ else
+ response_id = GTK_RESPONSE_CANCEL;
+ }
+
+ if (response_id != GTK_RESPONSE_NONE)
+ {
+ g_signal_handlers_disconnect_by_func (collection, on_secrets_changed, self);
+ gtk_dialog_response (priv->dialog, response_id);
+ }
+}
+
+static void
+secret_service_get_cb (GObject *object,
+ GAsyncResult *result,
+ GoaOAuth2Provider *self)
+{
+ GoaOAuth2ProviderPrivate *priv = goa_oauth2_provider_get_instance_private (self);
+ SecretService *service = NULL;
+ GList *collections = NULL;
+
+ service = secret_service_get_finish (result, &priv->error);
+ if (service == NULL)
+ goto out;
+
+ collections = secret_service_get_collections (service);
+ for (const GList *iter = collections; iter != NULL; iter = iter->next)
+ {
+ g_autofree char *label = secret_collection_get_label (iter->data);
+
+ /* The session collection is an empty string (?) */
+ if (g_strcmp0 (label, "") == 0)
+ {
+ const char *client_id = NULL;
+ const char *provider_type = NULL;
+
+ /* Ensure there's no dangling entry */
+ client_id = goa_oauth2_provider_get_client_id (self);
+ provider_type = goa_provider_get_provider_type (GOA_PROVIDER (self));
+ secret_password_clear_sync (&oauth2_schema, NULL, NULL,
+ "goa-oauth2-client", client_id,
+ "goa-oauth2-provider", provider_type,
+ NULL);
+
+ /* Watch the session collection for the requested URI */
+ priv->session = g_object_ref (iter->data);
+ g_signal_connect_object (priv->session,
+ "notify::items",
+ G_CALLBACK (on_secrets_changed),
+ self,
+ 0);
+ goto out;
+ }
+ }
+
+ if (priv->session == NULL && priv->error == NULL)
+ {
+ g_set_error (&priv->error,
+ GOA_ERROR,
+ GOA_ERROR_FAILED,
+ "Failed to connect to session keyring");
+ goto out;
+ }
+
+out:
+ g_clear_object (&service);
+ g_list_free_full (collections, g_object_unref);
+ g_main_loop_quit (priv->loop);
+}
+
+static void
+on_continue_in_browser (GtkButton *button,
+ GoaOAuth2Provider *self)
+{
+ GoaOAuth2ProviderPrivate *priv = goa_oauth2_provider_get_instance_private (self);
+
+ if (!g_app_info_launch_default_for_uri (priv->request_uri, NULL, &priv->error))
+ gtk_dialog_response (priv->dialog, GTK_RESPONSE_CANCEL);
+ else
+ gtk_widget_set_sensitive (GTK_WIDGET (button), FALSE);
}
static gboolean
@@ -906,12 +870,13 @@ get_tokens_and_identity (GoaOAuth2Provider *self,
GtkDialog *dialog,
GtkBox *vbox)
{
- GoaOAuth2ProviderPrivate *priv;
+ GoaOAuth2ProviderPrivate *priv = goa_oauth2_provider_get_instance_private (self);
gboolean ret = FALSE;
- gchar *url;
- GtkWidget *embed;
+ int response_id = GTK_RESPONSE_NONE;
GtkWidget *grid;
- GtkWidget *web_view;
+ GtkWidget *image;
+ GtkWidget *label;
+ GtkWidget *button;
const gchar *scope;
gchar *escaped_redirect_uri = NULL;
gchar *escaped_client_id = NULL;
@@ -923,7 +888,6 @@ get_tokens_and_identity (GoaOAuth2Provider *self,
g_return_val_if_fail (GTK_IS_DIALOG (dialog), FALSE);
g_return_val_if_fail (GTK_IS_BOX (vbox), FALSE);
- priv = goa_oauth2_provider_get_instance_private (self);
g_return_val_if_fail (priv->error == NULL, FALSE);
/* TODO: check with NM whether we're online, if not - return error */
@@ -937,6 +901,8 @@ get_tokens_and_identity (GoaOAuth2Provider *self,
g_clear_pointer (&priv->authorization_code, g_free);
g_clear_pointer (&priv->access_token, g_free);
g_clear_pointer (&priv->refresh_token, g_free);
+ g_clear_pointer (&priv->request_uri, g_free);
+ g_clear_object (&priv->session);
/* TODO: use oauth2_proxy_build_login_url_full() */
escaped_redirect_uri = g_uri_escape_string (goa_oauth2_provider_get_redirect_uri (self), NULL, TRUE);
@@ -946,40 +912,71 @@ get_tokens_and_identity (GoaOAuth2Provider *self,
escaped_scope = g_uri_escape_string (goa_oauth2_provider_get_scope (self), NULL, TRUE);
else
escaped_scope = NULL;
- url = goa_oauth2_provider_build_authorization_uri (self,
- goa_oauth2_provider_get_authorization_uri (self),
- escaped_redirect_uri,
- escaped_client_id,
- escaped_scope);
+ priv->request_uri = goa_oauth2_provider_build_authorization_uri (self,
+ goa_oauth2_provider_get_authorization_uri (self),
+ escaped_redirect_uri,
+ escaped_client_id,
+ escaped_scope);
goa_utils_set_dialog_title (GOA_PROVIDER (self), dialog, add_account);
- grid = gtk_grid_new ();
- gtk_orientable_set_orientation (GTK_ORIENTABLE (grid), GTK_ORIENTATION_VERTICAL);
- gtk_grid_set_row_spacing (GTK_GRID (grid), 12);
+ grid = g_object_new (GTK_TYPE_BOX,
+ "orientation", GTK_ORIENTATION_VERTICAL,
+ "spacing", 18,
+ "halign", GTK_ALIGN_CENTER,
+ "hexpand", TRUE,
+ "valign", GTK_ALIGN_CENTER,
+ "vexpand", TRUE,
+ "margin", 12,
+ NULL);
gtk_container_add (GTK_CONTAINER (vbox), grid);
- web_view = goa_web_view_new (GOA_PROVIDER (self), existing_identity);
- gtk_widget_set_hexpand (web_view, TRUE);
- gtk_widget_set_vexpand (web_view, TRUE);
- embed = goa_web_view_get_view (GOA_WEB_VIEW (web_view));
-
- if (goa_oauth2_provider_get_use_mobile_browser (self))
- goa_web_view_fake_mobile (GOA_WEB_VIEW (web_view));
-
- webkit_web_view_load_uri (WEBKIT_WEB_VIEW (embed), url);
- g_signal_connect (embed,
- "decide-policy",
- G_CALLBACK (on_web_view_decide_policy),
- self);
- g_signal_connect (web_view, "deny-click", G_CALLBACK (on_web_view_deny_click), self);
- g_signal_connect (web_view, "password-submit", G_CALLBACK (on_web_view_password_submit), self);
+ image = g_object_new (GTK_TYPE_IMAGE,
+ "icon-name", "web-browser-symbolic",
+ "pixel-size", 128,
+ NULL);
+ gtk_style_context_add_class (gtk_widget_get_style_context (image), "dim-label");
+ gtk_container_add (GTK_CONTAINER (grid), image);
+
+ label = gtk_label_new (_("Sign in with your browser to setup an account."));
+ gtk_style_context_add_class (gtk_widget_get_style_context (label), "heading");
+ gtk_container_add (GTK_CONTAINER (grid), label);
+
+ button = gtk_button_new_with_label (_("Continue"));
+ gtk_widget_set_halign (button, GTK_ALIGN_CENTER);
+ gtk_style_context_add_class (gtk_widget_get_style_context (button), "suggested-action");
+ g_signal_connect_object (button,
+ "clicked",
+ G_CALLBACK (on_continue_in_browser),
+ self, 0);
+ gtk_container_add (GTK_CONTAINER (grid), button);
+ gtk_dialog_add_button (priv->dialog, _("_Cancel"), GTK_RESPONSE_CANCEL);
- gtk_container_add (GTK_CONTAINER (grid), web_view);
+ gtk_widget_show_all (GTK_WIDGET (vbox));
gtk_window_set_default_size (GTK_WINDOW (dialog), -1, -1);
- gtk_widget_show_all (GTK_WIDGET (vbox));
- gtk_dialog_run (GTK_DIALOG (dialog));
+ /* Watch the session secret collection for the OAuth2 URI */
+ secret_service_get (SECRET_SERVICE_LOAD_COLLECTIONS | SECRET_SERVICE_OPEN_SESSION,
+ NULL,
+ (GAsyncReadyCallback) secret_service_get_cb,
+ self);
+ g_main_loop_run (priv->loop);
+ if (priv->error != NULL)
+ goto out;
+
+ /* Inform the user authentication should be completed in the browser */
+ response_id = gtk_dialog_run (GTK_DIALOG (dialog));
+ if (response_id != GTK_RESPONSE_OK)
+ {
+ if (priv->error == NULL)
+ {
+ g_set_error (&priv->error,
+ GOA_ERROR,
+ GOA_ERROR_DIALOG_DISMISSED,
+ _("Dialog was dismissed"));
+ }
+ goto out;
+ }
/* We can have either the auth code, with which we'll obtain the token, or
* the token directly if we are using a client side flow, since we don't
@@ -1038,12 +1035,14 @@ get_tokens_and_identity (GoaOAuth2Provider *self,
}
ret = TRUE;
+ gtk_dialog_response (dialog, GTK_RESPONSE_OK);
out:
- g_free (url);
g_free (escaped_redirect_uri);
g_free (escaped_client_id);
g_free (escaped_scope);
+ g_clear_pointer (&priv->request_uri, g_free);
+ g_clear_object (&priv->session);
return ret;
}
@@ -1131,6 +1130,7 @@ goa_oauth2_provider_add_account (GoaProvider *provider,
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
priv = goa_oauth2_provider_get_instance_private (self);
+ priv->loop = g_main_loop_new (NULL, FALSE);
if (!get_tokens_and_identity (self, TRUE, NULL, dialog, vbox))
goto out;
@@ -1165,7 +1165,6 @@ goa_oauth2_provider_add_account (GoaProvider *provider,
NULL, /* GCancellable* */
(GAsyncReadyCallback) add_account_cb,
self);
- priv->loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (priv->loop);
if (priv->error != NULL)
goto out;
@@ -1215,6 +1214,7 @@ goa_oauth2_provider_refresh_account (GoaProvider *provider,
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
priv = goa_oauth2_provider_get_instance_private (self);
+ priv->loop = g_main_loop_new (NULL, FALSE);
dialog = gtk_dialog_new_with_buttons (NULL,
parent,
@@ -1625,6 +1625,8 @@ goa_oauth2_provider_finalize (GObject *object)
g_free (priv->authorization_code);
g_free (priv->access_token);
g_free (priv->refresh_token);
+ g_clear_pointer (&priv->request_uri, g_free);
+ g_clear_object (&priv->session);
G_OBJECT_CLASS (goa_oauth2_provider_parent_class)->finalize (object);
}
@@ -1650,12 +1652,9 @@ goa_oauth2_provider_class_init (GoaOAuth2ProviderClass *klass)
provider_class->ensure_credentials_sync = goa_oauth2_provider_ensure_credentials_sync;
klass->build_authorization_uri = goa_oauth2_provider_build_authorization_uri_default;
- klass->decide_navigation_policy = goa_oauth2_provider_decide_navigation_policy_default;
klass->get_token_uri = goa_oauth2_provider_get_token_uri_default;
klass->get_scope = goa_oauth2_provider_get_scope_default;
klass->get_use_mobile_browser = goa_oauth2_provider_get_use_mobile_browser_default;
- klass->is_deny_node = goa_oauth2_provider_is_deny_node_default;
- klass->is_password_node = goa_oauth2_provider_is_password_node_default;
klass->add_account_key_values = goa_oauth2_provider_add_account_key_values_default;
}
diff --git a/src/goabackend/goaoauthprovider.c b/src/goabackend/goaoauthprovider.c
deleted file mode 100644
index 71bcad6..0000000
--- a/src/goabackend/goaoauthprovider.c
+++ /dev/null
@@ -1,1662 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-/*
- * Copyright © 2011 2017 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-#include <glib/gi18n-lib.h>
-#include <stdlib.h>
-
-#include <rest/oauth-proxy.h>
-#include <libsoup/soup.h>
-#include <json-glib/json-glib.h>
-#include <webkit2/webkit2.h>
-
-#include "goaprovider.h"
-#include "goautils.h"
-#include "goawebview.h"
-#include "goaoauthprovider.h"
-#include "goasouplogger.h"
-
-/**
- * SECTION:goaoauthprovider
- * @title: GoaOAuthProvider
- * @short_description: Abstract base class for OAuth 1.0a providers
- *
- * #GoaOAuthProvider is an abstract base class for OAuth 1.0a
- * compliant implementations as defined by <ulink
- * url="http://tools.ietf.org/html/rfc5849">RFC
- * 5849</ulink>. Additionally, the code works with providers
- * implementing <ulink
- * url="http://oauth.googlecode.com/svn/spec/ext/session/1.0/drafts/1/spec.html">OAuth
- * Session 1.0 Draft 1</ulink> for refreshing access tokens.
- *
- * Subclasses must implement
- * #GoaOAuthProviderClass.get_consumer_key,
- * #GoaOAuthProviderClass.get_consumer_secret,
- * #GoaOAuthProviderClass.get_request_uri,
- * #GoaOAuthProviderClass.get_authorization_uri,
- * #GoaOAuthProviderClass.get_token_uri,
- * #GoaOAuthProviderClass.get_callback_uri and
- * #GoaOAuthProviderClass.get_identity_sync methods.
- *
- * Additionally, the
- * #GoaProviderClass.get_provider_type,
- * #GoaProviderClass.get_provider_name,
- * #GoaProviderClass.build_object (this should chain up to its
- * parent class) methods must be implemented.
- *
- * Note that the #GoaProviderClass.add_account,
- * #GoaProviderClass.refresh_account and
- * #GoaProviderClass.ensure_credentials_sync methods do not
- * need to be implemented - this type implements these methods.
- */
-
-G_LOCK_DEFINE_STATIC (provider_lock);
-
-G_DEFINE_ABSTRACT_TYPE (GoaOAuthProvider, goa_oauth_provider, GOA_TYPE_PROVIDER);
-
-static gboolean
-is_authorization_error (GError *error)
-{
- gboolean ret;
-
- g_return_val_if_fail (error != NULL, FALSE);
-
- ret = FALSE;
- if (error->domain == REST_PROXY_ERROR || error->domain == SOUP_HTTP_ERROR)
- {
- if (SOUP_STATUS_IS_CLIENT_ERROR (error->code))
- ret = TRUE;
- }
- return ret;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static gboolean
-goa_oauth_provider_get_use_mobile_browser_default (GoaOAuthProvider *provider)
-{
- return FALSE;
-}
-
-/**
- * goa_oauth_provider_get_use_mobile_browser:
- * @provider: A #GoaOAuthProvider.
- *
- * Returns whether there is a need for the embedded browser to identify
- * itself as running on a mobile phone in order to get a more compact
- * version of the approval page.
- *
- * This is a virtual method where the default implementation returns
- * %FALSE.
- *
- * Returns: %TRUE if the embedded browser should identify itself as
- * running on a mobile platform, %FALSE otherwise.
- */
-gboolean
-goa_oauth_provider_get_use_mobile_browser (GoaOAuthProvider *provider)
-{
- g_return_val_if_fail (GOA_IS_OAUTH_PROVIDER (provider), FALSE);
- return GOA_OAUTH_PROVIDER_GET_CLASS (provider)->get_use_mobile_browser (provider);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static gboolean
-goa_oauth_provider_is_deny_node_default (GoaOAuthProvider *provider, WebKitDOMNode *node)
-{
- return FALSE;
-}
-
-/**
- * goa_oauth_provider_is_deny_node:
- * @provider: A #GoaOAuthProvider.
- * @node: A WebKitDOMNode.
- *
- * Checks whether @node is the HTML UI element that the user can use
- * to deny permission to access his account. Usually they are either a
- * WebKitDOMHTMLButtonElement or a WebKitDOMHTMLInputElement.
- *
- * Please note that providers may have multiple such elements in their
- * UI and this method should catch all of them.
- *
- * This is a virtual method where the default implementation returns
- * %FALSE.
- *
- * Returns: %TRUE if the @node can be used to deny permission.
- */
-gboolean
-goa_oauth_provider_is_deny_node (GoaOAuthProvider *provider, WebKitDOMNode *node)
-{
- g_return_val_if_fail (GOA_IS_OAUTH_PROVIDER (provider), FALSE);
- return GOA_OAUTH_PROVIDER_GET_CLASS (provider)->is_deny_node (provider, node);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static gboolean
-goa_oauth_provider_is_password_node_default (GoaOAuthProvider *provider, WebKitDOMHTMLInputElement *element)
-{
- return FALSE;
-}
-
-/**
- * goa_oauth_provider_is_password_node:
- * @provider: A #GoaOAuthProvider.
- * @element: A WebKitDOMHTMLInputElement
- *
- * Checks whether @element is the HTML UI element that the user can
- * use to enter her password. This can be used to offer a
- * #GoaPasswordBased interface by saving the user's
- * password. Providers usually frown upon doing this, so this is not
- * recommended.
- *
- * This is a virtual method where the default implementation returns
- * %FALSE.
- *
- * Returns: %TRUE if @element can be used to enter the password.
- */
-gboolean
-goa_oauth_provider_is_password_node (GoaOAuthProvider *provider, WebKitDOMHTMLInputElement *element)
-{
- g_return_val_if_fail (GOA_IS_OAUTH_PROVIDER (provider), FALSE);
- g_return_val_if_fail (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT (element), FALSE);
- return GOA_OAUTH_PROVIDER_GET_CLASS (provider)->is_password_node (provider, element);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static void
-goa_oauth_provider_add_account_key_values_default (GoaOAuthProvider *provider,
- GVariantBuilder *builder)
-{
- /* do nothing */
-}
-
-/**
- * goa_oauth_provider_add_account_key_values:
- * @provider: A #GoaProvider.
- * @builder: A #GVariantBuilder for a <literal>a{ss}</literal> variant.
- *
- * Hook for implementations to add key/value pairs to the key-file
- * when creating an account.
- *
- * This is a virtual method where the default implementation does nothing.
- */
-void
-goa_oauth_provider_add_account_key_values (GoaOAuthProvider *provider,
- GVariantBuilder *builder)
-{
- g_return_if_fail (GOA_IS_OAUTH_PROVIDER (provider));
- return GOA_OAUTH_PROVIDER_GET_CLASS (provider)->add_account_key_values (provider, builder);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static gchar *
-goa_oauth_provider_build_authorization_uri_default (GoaOAuthProvider *provider,
- const gchar *authorization_uri,
- const gchar *escaped_oauth_token)
-{
- return g_strdup_printf ("%s"
- "?oauth_token=%s",
- authorization_uri,
- escaped_oauth_token);
-}
-
-/**
- * goa_oauth_provider_build_authorization_uri:
- * @provider: A #GoaOAuthProvider.
- * @authorization_uri: An authorization URI.
- * @escaped_oauth_token: An escaped oauth token.
- *
- * Builds the URI that can be opened in a web browser (or embedded web
- * browser widget) to start authenticating an user.
- *
- * The default implementation just returns the expected URI
- * (e.g. <literal>http://example.com/dialog/oauth?auth_token=1234567890</literal>)
- * - override (and chain up) if you e.g. need to to pass additional
- * parameters.
- *
- * The @authorization_uri parameter originate from the result of the
- * the goa_oauth_provider_get_authorization_uri() method. The
- * @escaped_oauth_token parameter is the temporary credentials identifier
- * escaped using g_uri_escape_string().
- *
- * Returns: (transfer full): An authorization URI that must be freed with g_free().
- */
-gchar *
-goa_oauth_provider_build_authorization_uri (GoaOAuthProvider *provider,
- const gchar *authorization_uri,
- const gchar *escaped_oauth_token)
-{
- g_return_val_if_fail (GOA_IS_OAUTH_PROVIDER (provider), NULL);
- g_return_val_if_fail (authorization_uri != NULL, NULL);
- g_return_val_if_fail (escaped_oauth_token != NULL, NULL);
- return GOA_OAUTH_PROVIDER_GET_CLASS (provider)->build_authorization_uri (provider,
- authorization_uri,
- escaped_oauth_token);
-}
-
-/**
- * goa_oauth_provider_get_consumer_key:
- * @provider: A #GoaOAuthProvider.
- *
- * Gets the consumer key identifying the client.
- *
- * This is a pure virtual method - a subclass must provide an
- * implementation.
- *
- * Returns: (transfer none): A string owned by @provider - do not free.
- */
-const gchar *
-goa_oauth_provider_get_consumer_key (GoaOAuthProvider *provider)
-{
- g_return_val_if_fail (GOA_IS_OAUTH_PROVIDER (provider), NULL);
- return GOA_OAUTH_PROVIDER_GET_CLASS (provider)->get_consumer_key (provider);
-}
-
-/**
- * goa_oauth_provider_get_consumer_secret:
- * @provider: A #GoaOAuthProvider.
- *
- * Gets the consumer secret identifying the client.
- *
- * This is a pure virtual method - a subclass must provide an
- * implementation.
- *
- * Returns: (transfer none): A string owned by @provider - do not free.
- */
-const gchar *
-goa_oauth_provider_get_consumer_secret (GoaOAuthProvider *provider)
-{
- g_return_val_if_fail (GOA_IS_OAUTH_PROVIDER (provider), NULL);
- return GOA_OAUTH_PROVIDER_GET_CLASS (provider)->get_consumer_secret (provider);
-}
-
-/**
- * goa_oauth_provider_get_request_uri:
- * @provider: A #GoaOAuthProvider.
- *
- * Gets the request uri.
- *
- * http://tools.ietf.org/html/rfc5849#section-2.1
- *
- * This is a pure virtual method - a subclass must provide an
- * implementation.
- *
- * Returns: (transfer none): A string owned by @provider - do not free.
- */
-const gchar *
-goa_oauth_provider_get_request_uri (GoaOAuthProvider *provider)
-{
- g_return_val_if_fail (GOA_IS_OAUTH_PROVIDER (provider), NULL);
- return GOA_OAUTH_PROVIDER_GET_CLASS (provider)->get_request_uri (provider);
-}
-
-/**
- * goa_oauth_provider_get_request_uri_params:
- * @provider: A #GoaOAuthProvider.
- *
- * Gets additional parameters for the request URI.
- *
- * http://tools.ietf.org/html/rfc5849#section-2.1
- *
- * This is a virtual method where the default implementation returns
- * %NULL.
- *
- * Returns: (transfer full): %NULL (for no parameters) or a
- * %NULL-terminated array of (key, value) pairs that will be added to
- * the URI. The caller will free the returned value with g_strfreev().
- */
-gchar **
-goa_oauth_provider_get_request_uri_params (GoaOAuthProvider *provider)
-{
- g_return_val_if_fail (GOA_IS_OAUTH_PROVIDER (provider), NULL);
- return GOA_OAUTH_PROVIDER_GET_CLASS (provider)->get_request_uri_params (provider);
-}
-
-static gchar **
-goa_oauth_provider_get_request_uri_params_default (GoaOAuthProvider *provider)
-{
- g_return_val_if_fail (GOA_IS_OAUTH_PROVIDER (provider), NULL);
- return NULL;
-}
-
-/**
- * goa_oauth_provider_get_authorization_uri:
- * @provider: A #GoaOAuthProvider.
- *
- * Gets the authorization uri.
- *
- * http://tools.ietf.org/html/rfc5849#section-2.2
- *
- * This is a pure virtual method - a subclass must provide an
- * implementation.
- *
- * Returns: (transfer none): A string owned by @provider - do not free.
- */
-const gchar *
-goa_oauth_provider_get_authorization_uri (GoaOAuthProvider *provider)
-{
- g_return_val_if_fail (GOA_IS_OAUTH_PROVIDER (provider), NULL);
- return GOA_OAUTH_PROVIDER_GET_CLASS (provider)->get_authorization_uri (provider);
-}
-
-/**
- * goa_oauth_provider_get_token_uri:
- * @provider: A #GoaOAuthProvider.
- *
- * Gets the token uri.
- *
- * http://tools.ietf.org/html/rfc5849#section-2.3
- *
- * This is a pure virtual method - a subclass must provide an
- * implementation.
- *
- * Returns: (transfer none): A string owned by @provider - do not free.
- */
-const gchar *
-goa_oauth_provider_get_token_uri (GoaOAuthProvider *provider)
-{
- g_return_val_if_fail (GOA_IS_OAUTH_PROVIDER (provider), NULL);
- return GOA_OAUTH_PROVIDER_GET_CLASS (provider)->get_token_uri (provider);
-}
-
-/**
- * goa_oauth_provider_get_callback_uri:
- * @provider: A #GoaOAuthProvider.
- *
- * Gets the callback uri.
- *
- * http://tools.ietf.org/html/rfc5849#section-2.1
- *
- * This is a pure virtual method - a subclass must provide an
- * implementation.
- *
- * Returns: (transfer none): A string owned by @provider - do not free.
- */
-const gchar *
-goa_oauth_provider_get_callback_uri (GoaOAuthProvider *provider)
-{
- g_return_val_if_fail (GOA_IS_OAUTH_PROVIDER (provider), NULL);
- return GOA_OAUTH_PROVIDER_GET_CLASS (provider)->get_callback_uri (provider);
-}
-
-/**
- * goa_oauth_provider_get_identity_sync:
- * @provider: A #GoaOAuthProvider.
- * @access_token: A valid OAuth 1.0 access token.
- * @access_token_secret: The valid secret for @access_token.
- * @out_presentation_identity: (out): Return location for presentation identity or %NULL.
- * @cancellable: (allow-none): A #GCancellable or %NULL.
- * @error: Return location for error or %NULL.
- *
- * Method that returns the identity corresponding to @access_token and
- * @access_token_secret.
- *
- * The identity is needed because all authentication happens out of
- * band. In addition to the identity, an implementation also returns a
- * <emphasis>presentation identity</emphasis> that is more suitable
- * for presentation (the identity could be a GUID for example).
- *
- * The calling thread is blocked while the identity is obtained.
- *
- * This is a pure virtual method - a subclass must provide an
- * implementation.
- *
- * Returns: The identity or %NULL if error is set. The returned string
- * must be freed with g_free().
- */
-gchar *
-goa_oauth_provider_get_identity_sync (GoaOAuthProvider *provider,
- const gchar *access_token,
- const gchar *access_token_secret,
- gchar **out_presentation_identity,
- GCancellable *cancellable,
- GError **error)
-{
- g_return_val_if_fail (GOA_IS_OAUTH_PROVIDER (provider), NULL);
- g_return_val_if_fail (access_token != NULL, NULL);
- g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
- g_return_val_if_fail (error == NULL || *error == NULL, NULL);
-
- return GOA_OAUTH_PROVIDER_GET_CLASS (provider)->get_identity_sync (provider,
- access_token,
- access_token_secret,
- out_presentation_identity,
- cancellable,
- error);
-}
-
-/**
- * goa_oauth_provider_is_identity_node:
- * @provider: A #GoaOAuthProvider.
- * @element: A WebKitDOMHTMLInputElement.
- *
- * Checks whether @element is the HTML UI element that the user can
- * use to identify herself at the provider.
- *
- * This is a pure virtual method - a subclass must provide an
- * implementation.
- *
- * Returns: %TRUE if the @element can be used to deny permission.
- */
-gboolean
-goa_oauth_provider_is_identity_node (GoaOAuthProvider *provider, WebKitDOMHTMLInputElement *element)
-{
- g_return_val_if_fail (GOA_IS_OAUTH_PROVIDER (provider), FALSE);
- return GOA_OAUTH_PROVIDER_GET_CLASS (provider)->is_identity_node (provider, element);
-}
-
-/**
- * goa_oauth_provider_parse_request_token_error:
- * @provider: A #GoaOAuthProvider.
- * @call: The #RestProxyCall that was used to fetch the request token.
- *
- * Tries to parse the headers and payload within @call to provide a
- * human readable error message in case the request token could not
- * be fetched.
- *
- * This is a pure virtual method - a subclass must provide an
- * implementation.
- *
- * Returns: A human readable error message or %NULL if the cause of the
- * error could not be determined. The returned string must be freed with
- * g_free().
- */
-gchar *
-goa_oauth_provider_parse_request_token_error (GoaOAuthProvider *provider, RestProxyCall *call)
-{
- g_return_val_if_fail (GOA_IS_OAUTH_PROVIDER (provider), NULL);
- return GOA_OAUTH_PROVIDER_GET_CLASS (provider)->parse_request_token_error (provider, call);
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static gchar *
-get_tokens_sync (GoaOAuthProvider *provider,
- const gchar *token,
- const gchar *token_secret,
- const gchar *session_handle, /* may be NULL */
- const gchar *verifier, /* may be NULL */
- gchar **out_access_token_secret,
- gint *out_access_token_expires_in,
- gchar **out_session_handle,
- gint *out_session_handle_expires_in,
- GCancellable *cancellable,
- GError **error)
-{
- RestProxy *proxy;
- RestProxyCall *call;
- SoupLogger *logger = NULL;
- gchar *ret = NULL;
- guint status_code;
- GHashTable *f;
- const gchar *expires_in_str;
- gchar *ret_access_token = NULL;
- gchar *ret_access_token_secret = NULL;
- gint ret_access_token_expires_in = 0;
- gchar *ret_session_handle = NULL;
- gint ret_session_handle_expires_in = 0;
-
- proxy = oauth_proxy_new (goa_oauth_provider_get_consumer_key (provider),
- goa_oauth_provider_get_consumer_secret (provider),
- goa_oauth_provider_get_token_uri (provider),
- FALSE);
- logger = goa_soup_logger_new (SOUP_LOGGER_LOG_BODY, -1);
- rest_proxy_add_soup_feature (proxy, SOUP_SESSION_FEATURE (logger));
- oauth_proxy_set_token (OAUTH_PROXY (proxy), token);
- oauth_proxy_set_token_secret (OAUTH_PROXY (proxy), token_secret);
- call = rest_proxy_new_call (proxy);
- rest_proxy_call_set_method (call, "POST");
- if (verifier != NULL)
- rest_proxy_call_add_param (call, "oauth_verifier", verifier);
- if (session_handle != NULL)
- rest_proxy_call_add_param (call, "oauth_session_handle", session_handle);
- /* TODO: cancellable support? */
- if (!rest_proxy_call_sync (call, error))
- goto out;
-
- status_code = rest_proxy_call_get_status_code (call);
- if (status_code != 200)
- {
- g_set_error (error,
- GOA_ERROR,
- GOA_ERROR_FAILED,
- /* Translators: the %d is a HTTP status code and the %s is a textual description of it */
- _("Expected status 200 when requesting access token, instead got status %d (%s)"),
- status_code,
- rest_proxy_call_get_status_message (call));
- goto out;
- }
-
- f = soup_form_decode (rest_proxy_call_get_payload (call));
- ret_access_token = g_strdup (g_hash_table_lookup (f, "oauth_token"));
- ret_access_token_secret = g_strdup (g_hash_table_lookup (f, "oauth_token_secret"));
- ret_session_handle = g_strdup (g_hash_table_lookup (f, "oauth_session_handle"));
- expires_in_str = g_hash_table_lookup (f, "oauth_expires_in");
- if (expires_in_str != NULL)
- ret_access_token_expires_in = atoi (expires_in_str);
- expires_in_str = g_hash_table_lookup (f, "oauth_authorization_expires_in");
- if (expires_in_str != NULL)
- ret_session_handle_expires_in = atoi (expires_in_str);
- g_hash_table_unref (f);
-
- if (ret_access_token == NULL || ret_access_token_secret == NULL)
- {
- g_set_error (error,
- GOA_ERROR,
- GOA_ERROR_FAILED,
- _("Missing access_token or access_token_secret headers in response"));
- goto out;
- }
-
- ret = ret_access_token; ret_access_token = NULL;
- if (out_access_token_secret != NULL)
- {
- *out_access_token_secret = ret_access_token_secret;
- ret_access_token_secret = NULL;
- }
- if (out_access_token_expires_in != NULL)
- *out_access_token_expires_in = ret_access_token_expires_in;
- if (out_session_handle != NULL)
- {
- *out_session_handle = ret_session_handle;
- ret_session_handle = NULL;
- }
- if (out_session_handle_expires_in != NULL)
- *out_session_handle_expires_in = ret_session_handle_expires_in;
-
- out:
- g_free (ret_access_token);
- g_free (ret_access_token_secret);
- g_free (ret_session_handle);
- g_clear_object (&call);
- g_clear_object (&proxy);
- g_clear_object (&logger);
- return ret;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-typedef struct
-{
- GoaOAuthProvider *provider;
- GtkDialog *dialog;
- GError *error;
- GMainLoop *loop;
-
- gchar *password;
-
- gchar *oauth_verifier;
-
- const gchar *existing_identity;
-
- gchar *identity;
- gchar *presentation_identity;
-
- gchar *request_token;
- gchar *request_token_secret;
- gchar *access_token;
- gchar *access_token_secret;
- gint access_token_expires_in;
- gchar *session_handle;
- gint session_handle_expires_in;
-} IdentifyData;
-
-static void
-on_web_view_deny_click (GoaWebView *web_view, gpointer user_data)
-{
- IdentifyData *data = user_data;
- gtk_dialog_response (data->dialog, GTK_RESPONSE_CANCEL);
-}
-
-static void
-on_web_view_password_submit (GoaWebView *web_view, const gchar *password, gpointer user_data)
-{
- IdentifyData *data = user_data;
-
- g_free (data->password);
- data->password = g_strdup (password);
-}
-
-static gboolean
-on_web_view_decide_policy (WebKitWebView *web_view,
- WebKitPolicyDecision *decision,
- WebKitPolicyDecisionType decision_type,
- gpointer user_data)
-{
- GHashTable *key_value_pairs;
- IdentifyData *data = user_data;
- SoupURI *uri;
- WebKitNavigationAction *action;
- WebKitURIRequest *request;
- const gchar *query;
- const gchar *redirect_uri;
- const gchar *requested_uri;
- gint response_id = GTK_RESPONSE_NONE;
-
- if (decision_type != WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION)
- return FALSE;
-
- /* TODO: use oauth_proxy_extract_access_token() */
-
- action = webkit_navigation_policy_decision_get_navigation_action (WEBKIT_NAVIGATION_POLICY_DECISION (decision));
- request = webkit_navigation_action_get_request (action);
- requested_uri = webkit_uri_request_get_uri (request);
- redirect_uri = goa_oauth_provider_get_callback_uri (data->provider);
-
- if (!g_str_has_prefix (requested_uri, redirect_uri))
- goto default_behaviour;
-
- uri = soup_uri_new (requested_uri);
- query = soup_uri_get_query (uri);
-
- if (query != NULL)
- {
- key_value_pairs = soup_form_decode (query);
-
- data->oauth_verifier = g_strdup (g_hash_table_lookup (key_value_pairs, "oauth_verifier"));
- if (data->oauth_verifier != NULL)
- response_id = GTK_RESPONSE_OK;
-
- g_hash_table_unref (key_value_pairs);
- }
-
- if (data->oauth_verifier != NULL)
- goto ignore_request;
-
- /* TODO: The only OAuth1 provider is Flickr. It doesn't send any
- * error code and only redirects to the URI specified in the Flickr
- * App Garden. Re-evaluate when the situation changes.
- */
- response_id = GTK_RESPONSE_CANCEL;
- goto ignore_request;
-
- ignore_request:
- g_assert (response_id != GTK_RESPONSE_NONE);
- gtk_dialog_response (data->dialog, response_id);
- webkit_policy_decision_ignore (decision);
- return TRUE;
-
- default_behaviour:
- return FALSE;
-}
-
-static void
-rest_proxy_call_cb (RestProxyCall *call, const GError *error, GObject *weak_object, gpointer user_data)
-{
- IdentifyData *data = user_data;
- g_main_loop_quit (data->loop);
-}
-
-static gboolean
-get_tokens_and_identity (GoaOAuthProvider *provider,
- gboolean add_account,
- const gchar *existing_identity,
- GtkDialog *dialog,
- GtkBox *vbox,
- gchar **out_access_token,
- gchar **out_access_token_secret,
- gint *out_access_token_expires_in,
- gchar **out_session_handle,
- gint *out_session_handle_expires_in,
- gchar **out_identity,
- gchar **out_presentation_identity,
- gchar **out_password,
- GError **error)
-{
- gboolean ret = FALSE;
- gchar *url = NULL;
- IdentifyData data;
- gchar *escaped_request_token = NULL;
- RestProxy *proxy = NULL;
- RestProxyCall *call = NULL;
- SoupLogger *logger = NULL;
- GHashTable *f;
- GtkWidget *embed;
- GtkWidget *grid;
- GtkWidget *spinner;
- GtkWidget *web_view;
- gchar **request_params = NULL;
- guint n;
-
- g_return_val_if_fail (GOA_IS_OAUTH_PROVIDER (provider), FALSE);
- g_return_val_if_fail ((!add_account && existing_identity != NULL && existing_identity[0] != '\0')
- || (add_account && existing_identity == NULL), FALSE);
- g_return_val_if_fail (GTK_IS_DIALOG (dialog), FALSE);
- g_return_val_if_fail (GTK_IS_BOX (vbox), FALSE);
- g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
- /* TODO: check with NM whether we're online, if not - return error */
-
- memset (&data, '\0', sizeof (IdentifyData));
- data.provider = provider;
- data.dialog = dialog;
- data.loop = g_main_loop_new (NULL, FALSE);
- data.existing_identity = existing_identity;
-
- proxy = oauth_proxy_new (goa_oauth_provider_get_consumer_key (provider),
- goa_oauth_provider_get_consumer_secret (provider),
- goa_oauth_provider_get_request_uri (provider), FALSE);
- logger = goa_soup_logger_new (SOUP_LOGGER_LOG_BODY, -1);
- rest_proxy_add_soup_feature (proxy, SOUP_SESSION_FEATURE (logger));
-
- call = rest_proxy_new_call (proxy);
- rest_proxy_call_set_method (call, "POST");
- rest_proxy_call_add_param (call, "oauth_callback", goa_oauth_provider_get_callback_uri (provider));
-
- request_params = goa_oauth_provider_get_request_uri_params (provider);
- if (request_params != NULL)
- {
- g_assert (g_strv_length (request_params) % 2 == 0);
- for (n = 0; request_params[n] != NULL; n += 2)
- rest_proxy_call_add_param (call, request_params[n], request_params[n+1]);
- }
- if (!rest_proxy_call_async (call, rest_proxy_call_cb, NULL, &data, &data.error))
- {
- g_prefix_error (&data.error, _("Error getting a Request Token: "));
- goto out;
- }
-
- goa_utils_set_dialog_title (GOA_PROVIDER (provider), dialog, add_account);
-
- grid = gtk_grid_new ();
- gtk_orientable_set_orientation (GTK_ORIENTABLE (grid), GTK_ORIENTATION_VERTICAL);
- gtk_grid_set_row_spacing (GTK_GRID (grid), 12);
- gtk_container_add (GTK_CONTAINER (vbox), grid);
-
- spinner = gtk_spinner_new ();
- gtk_widget_set_hexpand (spinner, TRUE);
- gtk_widget_set_halign (spinner, GTK_ALIGN_CENTER);
- gtk_widget_set_vexpand (spinner, TRUE);
- gtk_widget_set_valign (spinner, GTK_ALIGN_CENTER);
- gtk_widget_set_size_request (GTK_WIDGET (spinner), 24, 24);
- gtk_spinner_start (GTK_SPINNER (spinner));
- gtk_container_add (GTK_CONTAINER (grid), spinner);
- gtk_widget_show_all (GTK_WIDGET (vbox));
-
- g_main_loop_run (data.loop);
- gtk_container_remove (GTK_CONTAINER (grid), spinner);
-
- if (rest_proxy_call_get_status_code (call) != 200)
- {
- gchar *msg;
-
- msg = goa_oauth_provider_parse_request_token_error (provider, call);
- if (msg == NULL)
- /* Translators: the %d is a HTTP status code and the %s is a textual description of it */
- msg = g_strdup_printf (_("Expected status 200 for getting a Request Token, instead got status %d (%s)"),
- rest_proxy_call_get_status_code (call),
- rest_proxy_call_get_status_message (call));
-
- g_set_error_literal (&data.error, GOA_ERROR, GOA_ERROR_FAILED, msg);
- g_free (msg);
- goto out;
- }
- f = soup_form_decode (rest_proxy_call_get_payload (call));
- data.request_token = g_strdup (g_hash_table_lookup (f, "oauth_token"));
- data.request_token_secret = g_strdup (g_hash_table_lookup (f, "oauth_token_secret"));
- g_hash_table_unref (f);
- if (data.request_token == NULL || data.request_token_secret == NULL)
- {
- g_set_error (&data.error,
- GOA_ERROR,
- GOA_ERROR_FAILED,
- _("Missing request_token or request_token_secret headers in response"));
- goto out;
- }
-
- escaped_request_token = g_uri_escape_string (data.request_token, NULL, TRUE);
- url = goa_oauth_provider_build_authorization_uri (provider,
- goa_oauth_provider_get_authorization_uri (provider),
- escaped_request_token);
-
- web_view = goa_web_view_new (GOA_PROVIDER (provider), existing_identity);
- gtk_widget_set_hexpand (web_view, TRUE);
- gtk_widget_set_vexpand (web_view, TRUE);
- embed = goa_web_view_get_view (GOA_WEB_VIEW (web_view));
-
- if (goa_oauth_provider_get_use_mobile_browser (provider))
- goa_web_view_fake_mobile (GOA_WEB_VIEW (web_view));
-
- webkit_web_view_load_uri (WEBKIT_WEB_VIEW (embed), url);
- g_signal_connect (embed,
- "decide-policy",
- G_CALLBACK (on_web_view_decide_policy),
- &data);
- g_signal_connect (web_view, "deny-click", G_CALLBACK (on_web_view_deny_click), &data);
- g_signal_connect (web_view, "password-submit", G_CALLBACK (on_web_view_password_submit), &data);
-
- gtk_container_add (GTK_CONTAINER (grid), web_view);
- gtk_window_set_default_size (GTK_WINDOW (dialog), -1, -1);
-
- gtk_widget_show_all (GTK_WIDGET (vbox));
- gtk_dialog_run (GTK_DIALOG (dialog));
-
- if (data.oauth_verifier == NULL)
- {
- if (data.error == NULL)
- {
- g_set_error (&data.error,
- GOA_ERROR,
- GOA_ERROR_DIALOG_DISMISSED,
- _("Dialog was dismissed"));
- }
- goto out;
- }
- g_assert (data.error == NULL);
-
- /* OK, we are done interacting with the user ... but before we can
- * make up our mind, there are two more RPC calls to make and these
- * call may take some time. So hide the dialog immediately.
- */
- gtk_widget_hide (GTK_WIDGET (dialog));
-
- /* OK, we now have the request token... we can exchange that for a
- * (short-lived) access token and session_handle (used to refresh the
- * access token)..
- */
-
- /* TODO: run in worker thread */
- data.access_token = get_tokens_sync (provider,
- data.request_token,
- data.request_token_secret,
- NULL, /* session_handle */
- data.oauth_verifier,
- &data.access_token_secret,
- &data.access_token_expires_in,
- &data.session_handle,
- &data.session_handle_expires_in,
- NULL, /* GCancellable */
- &data.error);
- if (data.access_token == NULL)
- {
- g_prefix_error (&data.error, _("Error getting an Access Token: "));
- goto out;
- }
-
- /* TODO: run in worker thread */
- data.identity = goa_oauth_provider_get_identity_sync (provider,
- data.access_token,
- data.access_token_secret,
- &data.presentation_identity,
- NULL, /* TODO: GCancellable */
- &data.error);
- if (data.identity == NULL)
- {
- g_prefix_error (&data.error, _("Error getting identity: "));
- goto out;
- }
-
- ret = TRUE;
-
- out:
- g_clear_object (&call);
-
- if (ret)
- {
- g_warn_if_fail (data.error == NULL);
- if (out_access_token != NULL)
- *out_access_token = g_strdup (data.access_token);
- if (out_access_token_secret != NULL)
- *out_access_token_secret = g_strdup (data.access_token_secret);
- if (out_access_token_expires_in != NULL)
- *out_access_token_expires_in = data.access_token_expires_in;
- if (out_session_handle != NULL)
- *out_session_handle = g_strdup (data.session_handle);
- if (out_session_handle_expires_in != NULL)
- *out_session_handle_expires_in = data.session_handle_expires_in;
- if (out_identity != NULL)
- *out_identity = g_strdup (data.identity);
- if (out_presentation_identity != NULL)
- *out_presentation_identity = g_strdup (data.presentation_identity);
- if (out_password != NULL)
- *out_password = g_strdup (data.password);
- }
- else
- {
- g_warn_if_fail (data.error != NULL);
- g_propagate_error (error, data.error);
- }
-
- g_free (data.password);
- g_free (data.presentation_identity);
- g_free (data.identity);
- g_free (url);
-
- g_free (data.oauth_verifier);
- g_clear_pointer (&data.loop, (GDestroyNotify) g_main_loop_unref);
- g_free (data.access_token);
- g_free (data.access_token_secret);
- g_free (escaped_request_token);
-
- g_free (data.request_token);
- g_free (data.request_token_secret);
-
- g_strfreev (request_params);
- g_clear_object (&proxy);
- g_clear_object (&logger);
- return ret;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-typedef struct
-{
- GError *error;
- GMainLoop *loop;
- gchar *account_object_path;
-} AddData;
-
-static void
-add_account_cb (GoaManager *manager,
- GAsyncResult *res,
- gpointer user_data)
-{
- AddData *data = user_data;
- goa_manager_call_add_account_finish (manager,
- &data->account_object_path,
- res,
- &data->error);
- g_main_loop_quit (data->loop);
-}
-
-static gint64
-duration_to_abs_usec (gint duration_sec)
-{
- gint64 ret;
- GTimeVal now;
-
- g_get_current_time (&now);
- ret = ((gint64) now.tv_sec) * 1000L * 1000L + ((gint64) now.tv_usec);
- ret += ((gint64) duration_sec) * 1000L * 1000L;
- return ret;
-}
-
-static gint
-abs_usec_to_duration (gint64 abs_usec)
-{
- gint64 ret;
- GTimeVal now;
-
- g_get_current_time (&now);
- ret = abs_usec - (((gint64) now.tv_sec) * 1000L * 1000L + ((gint64) now.tv_usec));
- ret /= 1000L * 1000L;
- return ret;
-}
-
-static GoaObject *
-goa_oauth_provider_add_account (GoaProvider *_provider,
- GoaClient *client,
- GtkDialog *dialog,
- GtkBox *vbox,
- GError **error)
-{
- GoaOAuthProvider *provider = GOA_OAUTH_PROVIDER (_provider);
- GoaObject *ret = NULL;
- gchar *access_token = NULL;
- gchar *access_token_secret = NULL;
- gint access_token_expires_in;
- gchar *session_handle = NULL;
- gint session_handle_expires_in;
- gchar *identity = NULL;
- gchar *presentation_identity = NULL;
- gchar *password = NULL;
- AddData data;
- GVariantBuilder credentials;
- GVariantBuilder details;
-
- g_return_val_if_fail (GOA_IS_OAUTH_PROVIDER (provider), NULL);
- g_return_val_if_fail (GOA_IS_CLIENT (client), NULL);
- g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
- g_return_val_if_fail (GTK_IS_BOX (vbox), NULL);
- g_return_val_if_fail (error == NULL || *error == NULL, NULL);
-
- memset (&data, '\0', sizeof (AddData));
- data.loop = g_main_loop_new (NULL, FALSE);
-
- if (!get_tokens_and_identity (provider,
- TRUE,
- NULL,
- dialog,
- vbox,
- &access_token,
- &access_token_secret,
- &access_token_expires_in,
- &session_handle,
- &session_handle_expires_in,
- &identity,
- &presentation_identity,
- &password,
- &data.error))
- goto out;
-
- /* OK, got the identity... see if there's already an account
- * of this type with the given identity
- */
- if (!goa_utils_check_duplicate (client,
- identity,
- presentation_identity,
- goa_provider_get_provider_type (GOA_PROVIDER (provider)),
- (GoaPeekInterfaceFunc) goa_object_peek_oauth_based,
- &data.error))
- goto out;
-
- g_variant_builder_init (&credentials, G_VARIANT_TYPE_VARDICT);
- g_variant_builder_add (&credentials, "{sv}", "access_token", g_variant_new_string (access_token));
- g_variant_builder_add (&credentials, "{sv}", "access_token_secret", g_variant_new_string (access_token_secret));
- if (access_token_expires_in > 0)
- g_variant_builder_add (&credentials, "{sv}", "access_token_expires_at",
- g_variant_new_int64 (duration_to_abs_usec (access_token_expires_in)));
- if (session_handle != NULL)
- g_variant_builder_add (&credentials, "{sv}", "session_handle", g_variant_new_string (session_handle));
- if (session_handle_expires_in > 0)
- g_variant_builder_add (&credentials, "{sv}", "session_handle_expires_at",
- g_variant_new_int64 (duration_to_abs_usec (session_handle_expires_in)));
- if (password != NULL)
- g_variant_builder_add (&credentials, "{sv}", "password", g_variant_new_string (password));
-
- g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}"));
- goa_oauth_provider_add_account_key_values (provider, &details);
-
- /* we want the GoaClient to update before this method returns (so it
- * can create a proxy for the new object) so run the mainloop while
- * waiting for this to complete
- */
- goa_manager_call_add_account (goa_client_get_manager (client),
- goa_provider_get_provider_type (GOA_PROVIDER (provider)),
- identity,
- presentation_identity,
- g_variant_builder_end (&credentials),
- g_variant_builder_end (&details),
- NULL, /* GCancellable* */
- (GAsyncReadyCallback) add_account_cb,
- &data);
- g_main_loop_run (data.loop);
- if (data.error != NULL)
- goto out;
-
- ret = GOA_OBJECT (g_dbus_object_manager_get_object (goa_client_get_object_manager (client),
- data.account_object_path));
-
- out:
- /* We might have an object even when data.error is set.
- * eg., if we failed to store the credentials in the keyring.
- */
- if (data.error != NULL)
- g_propagate_error (error, data.error);
- else
- g_assert (ret != NULL);
-
- g_free (identity);
- g_free (presentation_identity);
- g_free (password);
- g_free (access_token);
- g_free (access_token_secret);
- g_free (session_handle);
- g_free (data.account_object_path);
- g_clear_pointer (&data.loop, (GDestroyNotify) g_main_loop_unref);
- return ret;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static gboolean
-goa_oauth_provider_refresh_account (GoaProvider *_provider,
- GoaClient *client,
- GoaObject *object,
- GtkWindow *parent,
- GError **error)
-{
- GoaOAuthProvider *provider = GOA_OAUTH_PROVIDER (_provider);
- GoaAccount *account;
- GtkWidget *dialog;
- gchar *access_token = NULL;
- gchar *access_token_secret = NULL;
- gchar *password = NULL;
- gint access_token_expires_in;
- gchar *session_handle = NULL;
- gint session_handle_expires_in;
- gchar *identity = NULL;
- const gchar *existing_identity;
- const gchar *existing_presentation_identity;
- GVariantBuilder builder;
- gboolean ret = FALSE;
-
- g_return_val_if_fail (GOA_IS_OAUTH_PROVIDER (provider), FALSE);
- g_return_val_if_fail (GOA_IS_CLIENT (client), FALSE);
- g_return_val_if_fail (GOA_IS_OBJECT (object), FALSE);
- g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), FALSE);
- g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
- dialog = gtk_dialog_new_with_buttons (NULL,
- parent,
- GTK_DIALOG_MODAL
- | GTK_DIALOG_DESTROY_WITH_PARENT
- | GTK_DIALOG_USE_HEADER_BAR,
- NULL,
- NULL);
- gtk_container_set_border_width (GTK_CONTAINER (dialog), 12);
- gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
- gtk_widget_show_all (dialog);
-
- account = goa_object_peek_account (object);
-
- /* We abuse presentation identity here because for some providers
- * identity can be a machine readable ID, which can not be used to
- * log in via the provider's web interface.
- */
- existing_presentation_identity = goa_account_get_presentation_identity (account);
- if (!get_tokens_and_identity (provider,
- FALSE,
- existing_presentation_identity,
- GTK_DIALOG (dialog),
- GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
- &access_token,
- &access_token_secret,
- &access_token_expires_in,
- &session_handle,
- &session_handle_expires_in,
- &identity,
- NULL, /* out_presentation_identity */
- &password,
- error))
- goto out;
-
- /* Changes made to the web interface by the providers can break our
- * DOM parsing. So we should still query and check the identity
- * afterwards.
- */
- existing_identity = goa_account_get_identity (account);
- if (g_strcmp0 (identity, existing_identity) != 0)
- {
- g_set_error (error,
- GOA_ERROR,
- GOA_ERROR_FAILED,
- _("Was asked to log in as %s, but logged in as %s"),
- existing_identity,
- identity);
- goto out;
- }
-
- g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
- g_variant_builder_add (&builder, "{sv}", "access_token", g_variant_new_string (access_token));
- g_variant_builder_add (&builder, "{sv}", "access_token_secret", g_variant_new_string (access_token_secret));
- if (access_token_expires_in > 0)
- g_variant_builder_add (&builder, "{sv}", "access_token_expires_at",
- g_variant_new_int64 (duration_to_abs_usec (access_token_expires_in)));
- if (session_handle != NULL)
- g_variant_builder_add (&builder, "{sv}", "session_handle", g_variant_new_string (session_handle));
- if (session_handle_expires_in > 0)
- g_variant_builder_add (&builder, "{sv}", "session_handle_expires_at",
- g_variant_new_int64 (duration_to_abs_usec (session_handle_expires_in)));
- if (password != NULL)
- g_variant_builder_add (&builder, "{sv}", "password", g_variant_new_string (password));
- /* TODO: run in worker thread */
- if (!goa_utils_store_credentials_for_object_sync (GOA_PROVIDER (provider),
- object,
- g_variant_builder_end (&builder),
- NULL, /* GCancellable */
- error))
- goto out;
-
- goa_account_call_ensure_credentials (goa_object_peek_account (object),
- NULL, /* GCancellable */
- NULL, NULL); /* callback, user_data */
-
- ret = TRUE;
-
- out:
- gtk_widget_destroy (dialog);
-
- g_free (identity);
- g_free (access_token);
- g_free (access_token_secret);
- g_free (password);
- g_free (session_handle);
- return ret;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static void
-free_mutex (GMutex *mutex)
-{
- g_mutex_clear (mutex);
- g_slice_free (GMutex, mutex);
-}
-
-/**
- * goa_oauth_provider_get_access_token_sync:
- * @provider: A #GoaOAuthProvider.
- * @object: A #GoaObject.
- * @force_refresh: If set to %TRUE, forces a refresh of the access token, if possible.
- * @out_access_token_secret: (out): The secret for the return access token.
- * @out_access_token_expires_in: (out): Return location for how many seconds the returned token is valid for (0 if unknown) or %NULL.
- * @cancellable: (allow-none): A #GCancellable or %NULL.
- * @error: Return location for error or %NULL.
- *
- * Synchronously gets an access token for @object. The calling thread
- * is blocked while the operation is pending.
- *
- * The resulting token is typically read from the local cache so most
- * of the time only a local roundtrip to the storage for the token
- * cache (e.g. <command>gnome-keyring-daemon</command>) is
- * needed. However, the operation may involve refreshing the token
- * with the service provider so a full network round-trip may be
- * needed.
- *
- * Note that multiple calls are serialized to avoid multiple
- * outstanding requests to the service provider.
- *
- * This operation may fail if e.g. unable to refresh the credentials
- * or if network connectivity is not available. Note that even if a
- * token is returned, the returned token isn't guaranteed to work -
- * use goa_provider_ensure_credentials_sync() if you need
- * stronger guarantees.
- *
- * Returns: The access token or %NULL if error is set. The returned
- * string must be freed with g_free().
- */
-gchar *
-goa_oauth_provider_get_access_token_sync (GoaOAuthProvider *provider,
- GoaObject *object,
- gboolean force_refresh,
- gchar **out_access_token_secret,
- gint *out_access_token_expires_in,
- GCancellable *cancellable,
- GError **error)
-{
- GVariant *credentials = NULL;
- GVariantIter iter;
- const gchar *key;
- GVariant *value;
- gchar *access_token = NULL;
- gchar *access_token_secret = NULL;
- gchar *session_handle = NULL;
- gchar *access_token_for_refresh = NULL;
- gchar *access_token_secret_for_refresh = NULL;
- gchar *session_handle_for_refresh = NULL;
- gchar *password = NULL;
- gint access_token_expires_in = 0;
- gint session_handle_expires_in = 0;
- gboolean success = FALSE;
- GVariantBuilder builder;
- gchar *ret = NULL;
- GMutex *lock;
-
- g_return_val_if_fail (GOA_IS_OAUTH_PROVIDER (provider), NULL);
- g_return_val_if_fail (GOA_IS_OBJECT (object), NULL);
- g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
- g_return_val_if_fail (error == NULL || *error == NULL, NULL);
-
- /* provider_lock is too coarse, use a per-object lock instead */
- G_LOCK (provider_lock);
- lock = g_object_get_data (G_OBJECT (object), "-goa-oauth-provider-get-access-token-lock");
- if (lock == NULL)
- {
- lock = g_slice_new0 (GMutex);
- g_mutex_init (lock);
- g_object_set_data_full (G_OBJECT (object),
- "-goa-oauth-provider-get-access-token-lock",
- lock,
- (GDestroyNotify) free_mutex);
- }
- G_UNLOCK (provider_lock);
-
- g_mutex_lock (lock);
-
- /* First, get the credentials from the keyring */
- credentials = goa_utils_lookup_credentials_sync (GOA_PROVIDER (provider),
- object,
- cancellable,
- error);
- if (credentials == NULL)
- {
- if (error != NULL)
- {
- (*error)->domain = GOA_ERROR;
- (*error)->code = GOA_ERROR_NOT_AUTHORIZED;
- }
- goto out;
- }
-
- g_variant_iter_init (&iter, credentials);
- while (g_variant_iter_next (&iter, "{&sv}", &key, &value))
- {
- if (g_strcmp0 (key, "access_token") == 0)
- access_token = g_variant_dup_string (value, NULL);
- else if (g_strcmp0 (key, "access_token_secret") == 0)
- access_token_secret = g_variant_dup_string (value, NULL);
- else if (g_strcmp0 (key, "access_token_expires_at") == 0)
- access_token_expires_in = abs_usec_to_duration (g_variant_get_int64 (value));
- else if (g_strcmp0 (key, "session_handle") == 0)
- session_handle = g_variant_dup_string (value, NULL);
- else if (g_strcmp0 (key, "session_handle_expires_at") == 0)
- session_handle_expires_in = abs_usec_to_duration (g_variant_get_int64 (value));
- else if (g_strcmp0 (key, "password") == 0)
- password = g_variant_dup_string (value, NULL);
- g_variant_unref (value);
- }
-
- if (access_token == NULL || access_token_secret == NULL)
- {
- g_set_error (error,
- GOA_ERROR,
- GOA_ERROR_NOT_AUTHORIZED,
- _("Credentials do not contain access_token or access_token_secret"));
- goto out;
- }
-
- /* if we can't refresh the token, just return it no matter what */
- if (session_handle == NULL)
- {
- g_debug ("Returning locally cached credentials that cannot be refreshed");
- success = TRUE;
- goto out;
- }
-
- /* If access_token is still "fresh enough" (e.g. more than ten
- * minutes of life left in it), just return it unless we've been
- * asked to forcibly refresh it
- */
- if (!force_refresh && access_token_expires_in > 10*60)
- {
- g_debug ("Returning locally cached credentials (expires in %d seconds)", access_token_expires_in);
- success = TRUE;
- goto out;
- }
-
- g_debug ("Refreshing locally cached credentials (expires in %d seconds, force_refresh=%d)", access_token_expires_in, force_refresh);
-
- /* Otherwise, refresh it */
- access_token_for_refresh = access_token; access_token = NULL;
- access_token_secret_for_refresh = access_token_secret; access_token_secret = NULL;
- session_handle_for_refresh = session_handle; session_handle = NULL;
- access_token = get_tokens_sync (provider,
- access_token_for_refresh,
- access_token_secret_for_refresh,
- session_handle_for_refresh,
- NULL, /* verifier */
- &access_token_secret,
- &access_token_expires_in,
- &session_handle,
- &session_handle_expires_in,
- cancellable,
- error);
- if (access_token == NULL)
- {
- if (error != NULL)
- {
- g_prefix_error (error, _("Failed to refresh access token (%s, %d): "),
- g_quark_to_string ((*error)->domain), (*error)->code);
- (*error)->code = is_authorization_error (*error) ? GOA_ERROR_NOT_AUTHORIZED : GOA_ERROR_FAILED;
- (*error)->domain = GOA_ERROR;
- }
- goto out;
- }
-
- /* Good. Now update the keyring with the refreshed credentials */
- g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
- g_variant_builder_add (&builder, "{sv}", "access_token", g_variant_new_string (access_token));
- g_variant_builder_add (&builder, "{sv}", "access_token_secret", g_variant_new_string (access_token_secret));
- if (access_token_expires_in > 0)
- g_variant_builder_add (&builder, "{sv}", "access_token_expires_at",
- g_variant_new_int64 (duration_to_abs_usec (access_token_expires_in)));
- if (session_handle != NULL)
- g_variant_builder_add (&builder, "{sv}", "session_handle", g_variant_new_string (session_handle));
- if (session_handle_expires_in > 0)
- g_variant_builder_add (&builder, "{sv}", "session_handle_expires_at",
- g_variant_new_int64 (duration_to_abs_usec (session_handle_expires_in)));
- if (password != NULL)
- g_variant_builder_add (&builder, "{sv}", "password", g_variant_new_string (password));
-
- /* TODO: run in worker thread */
- if (!goa_utils_store_credentials_for_object_sync (GOA_PROVIDER (provider),
- object,
- g_variant_builder_end (&builder),
- cancellable,
- error))
- {
- if (error != NULL)
- {
- (*error)->domain = GOA_ERROR;
- (*error)->code = GOA_ERROR_NOT_AUTHORIZED;
- }
- goto out;
- }
-
- success = TRUE;
-
- out:
- if (success)
- {
- ret = access_token; access_token = NULL;
- g_assert (ret != NULL);
- if (out_access_token_secret != NULL)
- {
- *out_access_token_secret = access_token_secret; access_token_secret = NULL;
- }
- if (out_access_token_expires_in != NULL)
- *out_access_token_expires_in = access_token_expires_in;
- }
- g_free (access_token);
- g_free (access_token_secret);
- g_free (session_handle);
- g_free (access_token_for_refresh);
- g_free (access_token_secret_for_refresh);
- g_free (session_handle_for_refresh);
- g_free (password);
- g_clear_pointer (&credentials, (GDestroyNotify) g_variant_unref);
-
- g_mutex_unlock (lock);
-
- return ret;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static gboolean on_handle_get_access_token (GoaOAuthBased *object,
- GDBusMethodInvocation *invocation,
- gpointer user_data);
-
-static gboolean
-goa_oauth_provider_build_object (GoaProvider *provider,
- GoaObjectSkeleton *object,
- GKeyFile *key_file,
- const gchar *group,
- GDBusConnection *connection,
- gboolean just_added,
- GError **error)
-{
- GoaOAuthBased *oauth_based;
- gchar *identity;
-
- identity = NULL;
-
- oauth_based = goa_object_get_oauth_based (GOA_OBJECT (object));
- if (oauth_based != NULL)
- goto out;
-
- oauth_based = goa_oauth_based_skeleton_new ();
- goa_oauth_based_set_consumer_key (oauth_based,
- goa_oauth_provider_get_consumer_key (GOA_OAUTH_PROVIDER (provider)));
- goa_oauth_based_set_consumer_secret (oauth_based,
- goa_oauth_provider_get_consumer_secret (GOA_OAUTH_PROVIDER (provider)));
- /* Ensure D-Bus method invocations run in their own thread */
- g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (oauth_based),
- G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
- goa_object_skeleton_set_oauth_based (object, oauth_based);
- g_signal_connect (oauth_based,
- "handle-get-access-token",
- G_CALLBACK (on_handle_get_access_token),
- NULL);
-
- out:
- g_object_unref (oauth_based);
- g_free (identity);
- return TRUE;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static gboolean
-goa_oauth_provider_ensure_credentials_sync (GoaProvider *_provider,
- GoaObject *object,
- gint *out_expires_in,
- GCancellable *cancellable,
- GError **error)
-{
- GoaOAuthProvider *provider = GOA_OAUTH_PROVIDER (_provider);
- gboolean ret = FALSE;
- gchar *access_token = NULL;
- gchar *access_token_secret = NULL;
- gint access_token_expires_in;
- gchar *identity = NULL;
- gboolean force_refresh = FALSE;
-
- again:
- access_token = goa_oauth_provider_get_access_token_sync (provider,
- object,
- force_refresh,
- &access_token_secret,
- &access_token_expires_in,
- cancellable,
- error);
- if (access_token == NULL)
- goto out;
-
- identity = goa_oauth_provider_get_identity_sync (provider,
- access_token,
- access_token_secret,
- NULL, /* out_presentation_identity */
- cancellable,
- error);
- if (identity == NULL)
- {
- /* OK, try again, with forcing the locally cached credentials to be refreshed */
- if (!force_refresh)
- {
- force_refresh = TRUE;
- g_free (access_token); access_token = NULL;
- g_free (access_token_secret); access_token_secret = NULL;
- g_clear_error (error);
- goto again;
- }
- else
- {
- goto out;
- }
- }
-
- /* TODO: maybe check with the identity we have */
- ret = TRUE;
- if (out_expires_in != NULL)
- *out_expires_in = access_token_expires_in;
-
- out:
- g_free (identity);
- g_free (access_token);
- g_free (access_token_secret);
- return ret;
-}
-
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-static void
-goa_oauth_provider_init (GoaOAuthProvider *client)
-{
-}
-
-static void
-goa_oauth_provider_class_init (GoaOAuthProviderClass *klass)
-{
- GoaProviderClass *provider_class;
-
- provider_class = GOA_PROVIDER_CLASS (klass);
- provider_class->add_account = goa_oauth_provider_add_account;
- provider_class->refresh_account = goa_oauth_provider_refresh_account;
- provider_class->build_object = goa_oauth_provider_build_object;
- provider_class->ensure_credentials_sync = goa_oauth_provider_ensure_credentials_sync;
-
- klass->build_authorization_uri = goa_oauth_provider_build_authorization_uri_default;
- klass->get_use_mobile_browser = goa_oauth_provider_get_use_mobile_browser_default;
- klass->is_deny_node = goa_oauth_provider_is_deny_node_default;
- klass->is_password_node = goa_oauth_provider_is_password_node_default;
- klass->get_request_uri_params = goa_oauth_provider_get_request_uri_params_default;
- klass->add_account_key_values = goa_oauth_provider_add_account_key_values_default;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-/* runs in a thread dedicated to handling @invocation */
-static gboolean
-on_handle_get_access_token (GoaOAuthBased *interface,
- GDBusMethodInvocation *invocation,
- gpointer user_data)
-{
- GoaObject *object;
- GoaAccount *account;
- GoaProvider *provider;
- GError *error;
- const gchar *id;
- const gchar *method_name;
- const gchar *provider_type;
- gchar *access_token = NULL;
- gchar *access_token_secret = NULL;
- gint access_token_expires_in;
-
- /* TODO: maybe log what app is requesting access */
-
- object = GOA_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (interface)));
- account = goa_object_peek_account (object);
-
- id = goa_account_get_id (account);
- provider_type = goa_account_get_provider_type (account);
- method_name = g_dbus_method_invocation_get_method_name (invocation);
- g_debug ("Handling %s for account (%s, %s)", method_name, provider_type, id);
-
- provider = goa_provider_get_for_provider_type (provider_type);
-
- error = NULL;
- access_token = goa_oauth_provider_get_access_token_sync (GOA_OAUTH_PROVIDER (provider),
- object,
- FALSE, /* force_refresh */
- &access_token_secret,
- &access_token_expires_in,
- NULL, /* GCancellable* */
- &error);
- if (access_token == NULL)
- {
- g_dbus_method_invocation_take_error (invocation, error);
- }
- else
- {
- goa_oauth_based_complete_get_access_token (interface,
- invocation,
- access_token,
- access_token_secret,
- access_token_expires_in);
- }
- g_free (access_token);
- g_free (access_token_secret);
- g_object_unref (provider);
- return TRUE; /* invocation was handled */
-}
diff --git a/src/goabackend/goaoauthprovider.h b/src/goabackend/goaoauthprovider.h
deleted file mode 100644
index d4ffa3c..0000000
--- a/src/goabackend/goaoauthprovider.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-/*
- * Copyright © 2011 2017 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#if !defined (__GOA_BACKEND_INSIDE_GOA_BACKEND_H__) && !defined (GOA_BACKEND_COMPILATION)
-#error "Only <goabackend/goabackend.h> can be included directly."
-#endif
-
-#ifndef __GOA_OAUTH_PROVIDER_H__
-#define __GOA_OAUTH_PROVIDER_H__
-
-#include <goabackend/goaprovider.h>
-#include <goabackend/goaprovider-priv.h>
-#include <rest/rest-proxy-call.h>
-#include <webkitdom/webkitdom.h>
-
-G_BEGIN_DECLS
-
-#define GOA_TYPE_OAUTH_PROVIDER (goa_oauth_provider_get_type ())
-G_DECLARE_DERIVABLE_TYPE (GoaOAuthProvider, goa_oauth_provider, GOA, OAUTH_PROVIDER, GoaProvider);
-
-/**
- * GoaOAuthProvider:
- *
- * The #GoaOAuthProvider structure contains only private data and should
- * only be accessed using the provided API.
- */
-
-/**
- * GoaOAuthProviderClass:
- * @parent_class: The parent class.
- * @get_consumer_key: Virtual function for goa_oauth_provider_get_consumer_key().
- * @get_consumer_secret: Virtual function for goa_oauth_provider_get_consumer_secret().
- * @get_request_uri: Virtual function for goa_oauth_provider_get_request_uri().
- * @get_authorization_uri: Virtual function for goa_oauth_provider_get_authorization_uri().
- * @get_token_uri: Virtual function for goa_oauth_provider_get_token_uri().
- * @get_callback_uri: Virtual function for goa_oauth_provider_get_callback_uri().
- * @get_identity_sync: Virtual function for goa_oauth_provider_get_identity_sync().
- * @parse_request_token_error: Virtual function for goa_oauth_provider_parse_request_token_error().
- * @build_authorization_uri: Virtual function for goa_oauth_provider_build_authorization_uri().
- * @get_use_mobile_browser: Virtual function for goa_oauth_provider_get_use_mobile_browser().
- * @get_request_uri_params: Virtual function for goa_oauth_provider_get_request_uri_params().
- * @add_account_key_values: Virtual function for goa_oauth_provider_add_account_key_values().
- * @is_deny_node: Virtual function for goa_oauth_provider_is_deny_node().
- * @is_identity_node: Virtual function for goa_oauth_provider_is_identity_node().
- * @is_password_node: Virtual function for goa_oauth_provider_is_password_node().
- *
- * Class structure for #GoaOAuthProvider.
- */
-struct _GoaOAuthProviderClass
-{
- GoaProviderClass parent_class;
-
- /* pure virtual */
- const gchar *(*get_consumer_key) (GoaOAuthProvider *provider);
- const gchar *(*get_consumer_secret) (GoaOAuthProvider *provider);
- const gchar *(*get_request_uri) (GoaOAuthProvider *provider);
- const gchar *(*get_authorization_uri) (GoaOAuthProvider *provider);
- const gchar *(*get_token_uri) (GoaOAuthProvider *provider);
- const gchar *(*get_callback_uri) (GoaOAuthProvider *provider);
-
- gchar *(*get_identity_sync) (GoaOAuthProvider *provider,
- const gchar *access_token,
- const gchar *access_token_secret,
- gchar **out_presentation_identity,
- GCancellable *cancellable,
- GError **error);
-
- gchar *(*parse_request_token_error) (GoaOAuthProvider *provider,
- RestProxyCall *call);
-
- /* virtual but with default implementation */
- gchar *(*build_authorization_uri) (GoaOAuthProvider *provider,
- const gchar *authorization_uri,
- const gchar *escaped_oauth_token);
- gboolean (*get_use_mobile_browser) (GoaOAuthProvider *provider);
- gchar **(*get_request_uri_params) (GoaOAuthProvider *provider);
- void (*add_account_key_values) (GoaOAuthProvider *provider,
- GVariantBuilder *builder);
-
- /* pure virtual */
- gboolean (*is_identity_node) (GoaOAuthProvider *provider,
- WebKitDOMHTMLInputElement *element);
-
- /* virtual but with default implementation */
- gboolean (*is_deny_node) (GoaOAuthProvider *provider,
- WebKitDOMNode *node);
- gboolean (*is_password_node) (GoaOAuthProvider *provider,
- WebKitDOMHTMLInputElement *element);
-};
-
-const gchar *goa_oauth_provider_get_consumer_key (GoaOAuthProvider *provider);
-const gchar *goa_oauth_provider_get_consumer_secret (GoaOAuthProvider *provider);
-const gchar *goa_oauth_provider_get_request_uri (GoaOAuthProvider *provider);
-gchar **goa_oauth_provider_get_request_uri_params (GoaOAuthProvider *provider);
-const gchar *goa_oauth_provider_get_authorization_uri (GoaOAuthProvider *provider);
-const gchar *goa_oauth_provider_get_token_uri (GoaOAuthProvider *provider);
-const gchar *goa_oauth_provider_get_callback_uri (GoaOAuthProvider *provider);
-gchar *goa_oauth_provider_get_identity_sync (GoaOAuthProvider *provider,
- const gchar *access_token,
- const gchar *access_token_secret,
- gchar **out_presentation_identity,
- GCancellable *cancellable,
- GError **error);
-gboolean goa_oauth_provider_is_deny_node (GoaOAuthProvider *provider,
- WebKitDOMNode *node);
-gboolean goa_oauth_provider_is_identity_node (GoaOAuthProvider *provider,
- WebKitDOMHTMLInputElement *element);
-gboolean goa_oauth_provider_is_password_node (GoaOAuthProvider *provider,
- WebKitDOMHTMLInputElement *element);
-gchar *goa_oauth_provider_parse_request_token_error (GoaOAuthProvider *provider,
- RestProxyCall *call);
-gchar *goa_oauth_provider_get_access_token_sync (GoaOAuthProvider *provider,
- GoaObject *object,
- gboolean force_refresh,
- gchar **out_access_token_secret,
- gint *out_access_token_expires_in,
- GCancellable *cancellable,
- GError **error);
-gchar *goa_oauth_provider_build_authorization_uri (GoaOAuthProvider *provider,
- const gchar *authorization_uri,
- const gchar *escaped_oauth_token);
-gboolean goa_oauth_provider_get_use_mobile_browser (GoaOAuthProvider *provider);
-void goa_oauth_provider_add_account_key_values (GoaOAuthProvider *provider,
- GVariantBuilder *builder);
-
-G_END_DECLS
-
-#endif /* __GOA_OAUTH_PROVIDER_H__ */
diff --git a/src/goabackend/goapocketprovider.c b/src/goabackend/goapocketprovider.c
index 38f9863..0d1a8ce 100644
--- a/src/goabackend/goapocketprovider.c
+++ b/src/goabackend/goapocketprovider.c
@@ -185,32 +185,6 @@ build_authorization_uri (GoaOAuth2Provider *oauth2_provider,
return url;
}
-static gboolean
-decide_navigation_policy (GoaOAuth2Provider *oauth2_provider,
- WebKitWebView *web_view,
- WebKitNavigationPolicyDecision *decision)
-{
- GoaPocketProvider *self = GOA_POCKET_PROVIDER (oauth2_provider);
- WebKitNavigationAction *action;
- WebKitURIRequest *request;
- gboolean ret = FALSE;
- const gchar *uri;
-
- action = webkit_navigation_policy_decision_get_navigation_action (decision);
- request = webkit_navigation_action_get_request (action);
- uri = webkit_uri_request_get_uri (request);
- if (!g_str_has_prefix (uri, "https://getpocket.com/a/"))
- goto out;
-
- webkit_uri_request_set_uri (request, self->authorization_uri);
- webkit_web_view_load_request (web_view, request);
-
- ret = TRUE;
-
- out:
- return ret;
-}
-
static gboolean
process_redirect_url (GoaOAuth2Provider *oauth2_provider,
const gchar *redirect_url,
@@ -279,68 +253,6 @@ get_identity_sync (GoaOAuth2Provider *oauth2_provider,
/* ---------------------------------------------------------------------------------------------------- */
-static gboolean
-is_deny_node (GoaOAuth2Provider *oauth2_provider, WebKitDOMNode *node)
-{
- WebKitDOMElement *element;
- gboolean ret = FALSE;
- gchar *id = NULL;
- gchar *class = NULL;
- gchar *text = NULL;
-
- if (!WEBKIT_DOM_IS_ELEMENT (node))
- goto out;
-
- element = WEBKIT_DOM_ELEMENT (node);
-
- /* Desktop version */
- id = webkit_dom_element_get_id (element);
- if (g_strcmp0 (id, "denyButton") == 0)
- {
- ret = TRUE;
- goto out;
- }
-
- /* Mobile version */
- class = webkit_dom_element_get_class_name (element);
- if (g_strcmp0 (class, "toolbarButton") != 0)
- goto out;
-
- /* FIXME: This only seems to work if we don't click on the "Sign Up"
- * button, does the check need to be done again? */
- text = webkit_dom_node_get_text_content (node);
- if (g_strcmp0 (text, "Cancel") != 0)
- goto out;
-
- ret = TRUE;
-
- out:
- g_free (id);
- g_free (class);
- g_free (text);
- return ret;
-}
-
-static gboolean
-is_identity_node (GoaOAuth2Provider *oauth2_provider, WebKitDOMHTMLInputElement *element)
-{
- gboolean ret = FALSE;
- gchar *name;
-
- name = webkit_dom_html_input_element_get_name (element);
- if (g_strcmp0 (name, "feed_id") != 0)
- goto out;
-
- ret = TRUE;
-
-out:
- g_free (name);
- return ret;
-
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
static gboolean
build_object (GoaProvider *provider,
GoaObjectSkeleton *object,
@@ -431,15 +343,12 @@ goa_pocket_provider_class_init (GoaPocketProviderClass *klass)
provider_class->build_object = build_object;
oauth2_class->build_authorization_uri = build_authorization_uri;
- oauth2_class->decide_navigation_policy = decide_navigation_policy;
oauth2_class->get_authorization_uri = get_authorization_uri;
oauth2_class->get_token_uri = get_token_uri;
oauth2_class->get_redirect_uri = get_redirect_uri;
oauth2_class->get_client_id = get_client_id;
oauth2_class->get_client_secret = get_client_secret;
oauth2_class->get_identity_sync = get_identity_sync;
- oauth2_class->is_deny_node = is_deny_node;
- oauth2_class->is_identity_node = is_identity_node;
oauth2_class->add_account_key_values = add_account_key_values;
oauth2_class->process_redirect_url = process_redirect_url;
}
diff --git a/src/goabackend/goaprovider.c b/src/goabackend/goaprovider.c
index c8f7f0d..fe8ce22 100644
--- a/src/goabackend/goaprovider.c
+++ b/src/goabackend/goaprovider.c
@@ -28,7 +28,6 @@
#include "goafacebookprovider.h"
#include "goaimapsmtpprovider.h"
#include "goaowncloudprovider.h"
-#include "goaflickrprovider.h"
#include "goafoursquareprovider.h"
#include "goawindowsliveprovider.h"
#include "goatelepathyfactory.h"
@@ -968,9 +967,6 @@ static struct
#ifdef GOA_WINDOWS_LIVE_ENABLED
{ GOA_WINDOWS_LIVE_NAME, goa_windows_live_provider_get_type },
#endif
-#ifdef GOA_FLICKR_ENABLED
- { GOA_FLICKR_NAME, goa_flickr_provider_get_type },
-#endif
#ifdef GOA_POCKET_ENABLED
{ GOA_POCKET_NAME, goa_pocket_provider_get_type },
#endif
diff --git a/src/goabackend/goatodoistprovider.c b/src/goabackend/goatodoistprovider.c
index d97c33c..7f17a59 100644
--- a/src/goabackend/goatodoistprovider.c
+++ b/src/goabackend/goatodoistprovider.c
@@ -133,33 +133,6 @@ build_authorization_uri (GoaOAuth2Provider *oauth2_provider,
/* ---------------------------------------------------------------------------------------------------- */
-static gboolean
-is_identity_node (GoaOAuth2Provider *oauth2_provider, WebKitDOMHTMLInputElement *element)
-{
- gboolean ret = FALSE;
- gchar *element_type = NULL;
- gchar *id = NULL;
- gchar *name = NULL;
-
- g_object_get (element, "type", &element_type, NULL);
- if (g_strcmp0 (element_type, "email") != 0)
- goto out;
-
- id = webkit_dom_element_get_id (WEBKIT_DOM_ELEMENT (element));
- if (g_strcmp0 (id, "email") != 0)
- goto out;
-
- ret = TRUE;
-
- out:
- g_free (element_type);
- g_free (id);
- g_free (name);
- return ret;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
static gchar *
get_identity_sync (GoaOAuth2Provider *oauth2_provider,
const gchar *access_token,
@@ -337,6 +310,5 @@ goa_todoist_provider_class_init (GoaTodoistProviderClass *klass)
oauth2_class->get_client_secret = get_client_secret;
oauth2_class->get_scope = get_scope;
oauth2_class->get_identity_sync = get_identity_sync;
- oauth2_class->is_identity_node = is_identity_node;
oauth2_class->add_account_key_values = add_account_key_values;
}
diff --git a/src/goabackend/goawebextension.c b/src/goabackend/goawebextension.c
deleted file mode 100644
index 6a25ab9..0000000
--- a/src/goabackend/goawebextension.c
+++ /dev/null
@@ -1,273 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-/*
- * Copyright © 2015 Damián Nohales
- * Copyright © 2015 2017 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include <webkitdom/webkitdom.h>
-
-#include "goaoauthprovider.h"
-#include "goaoauth2provider.h"
-#include "goaoauth2provider-web-extension.h"
-#include "goaprovider.h"
-#include "goawebextension.h"
-
-struct _GoaWebExtension
-{
- GObject parent;
- GoaProvider *provider;
- WebKitWebExtension *wk_extension;
- gchar *existing_identity;
- gchar *provider_type;
-};
-
-struct _GoaWebExtensionClass
-{
- GObjectClass parent;
-};
-
-enum
-{
- PROP_0,
- PROP_EXISTING_IDENTITY,
- PROP_PROVIDER_TYPE,
- PROP_WK_EXTENSION
-};
-
-G_DEFINE_TYPE (GoaWebExtension, goa_web_extension, G_TYPE_OBJECT)
-
-static void
-web_extension_dom_node_deny_click_cb (WebKitDOMNode *element, WebKitDOMEvent *event, gpointer user_data)
-{
- WebKitDOMDOMWindow *dom_window = WEBKIT_DOM_DOM_WINDOW (user_data);
- webkit_dom_dom_window_webkit_message_handlers_post_message (dom_window, "deny-click", "");
-}
-
-static void
-web_extension_dom_node_password_submit_cb (WebKitDOMNode *element, WebKitDOMEvent *event, gpointer user_data)
-{
- WebKitDOMDOMWindow *dom_window = WEBKIT_DOM_DOM_WINDOW (user_data);
- WebKitDOMHTMLInputElement *password_node;
- gchar *password;
-
- password_node = WEBKIT_DOM_HTML_INPUT_ELEMENT (g_object_get_data (G_OBJECT (dom_window), "goa-password-node"));
- password = webkit_dom_html_input_element_get_value (password_node);
- webkit_dom_dom_window_webkit_message_handlers_post_message (dom_window, "password-submit", password);
- g_free (password);
-}
-
-static void
-web_extension_document_loaded_cb (WebKitWebPage *web_page, gpointer user_data)
-{
- GoaWebExtension *self = GOA_WEB_EXTENSION (user_data);
- WebKitDOMDocument *document;
- WebKitDOMDOMWindow *dom_window;
- WebKitDOMHTMLCollection *elements = NULL;
- gulong element_count;
- gulong i;
-
- document = webkit_web_page_get_dom_document (web_page);
- elements = webkit_dom_document_get_elements_by_tag_name_as_html_collection (document, "*");
- element_count = webkit_dom_html_collection_get_length (elements);
-
- dom_window = webkit_dom_document_get_default_view (document);
-
- for (i = 0; i < element_count; i++)
- {
- WebKitDOMNode *element = webkit_dom_html_collection_item (elements, i);
-
- if ((GOA_IS_OAUTH_PROVIDER (self->provider)
- && goa_oauth_provider_is_deny_node (GOA_OAUTH_PROVIDER (self->provider), element))
- || (GOA_IS_OAUTH2_PROVIDER (self->provider)
- && goa_oauth2_provider_is_deny_node (GOA_OAUTH2_PROVIDER (self->provider), element)))
- {
- webkit_dom_event_target_add_event_listener (WEBKIT_DOM_EVENT_TARGET (element),
- "click",
- G_CALLBACK (web_extension_dom_node_deny_click_cb),
- FALSE,
- dom_window);
- }
- else if (self->existing_identity != NULL
- && self->existing_identity[0] != '\0'
- && WEBKIT_DOM_IS_HTML_INPUT_ELEMENT (element)
- && ((GOA_IS_OAUTH_PROVIDER (self->provider)
- && goa_oauth_provider_is_identity_node (GOA_OAUTH_PROVIDER (self->provider),
- WEBKIT_DOM_HTML_INPUT_ELEMENT (element)))
- || (GOA_IS_OAUTH2_PROVIDER (self->provider)
- && goa_oauth2_provider_is_identity_node (GOA_OAUTH2_PROVIDER (self->provider),
- WEBKIT_DOM_HTML_INPUT_ELEMENT (element)))))
- {
- webkit_dom_html_input_element_set_value (WEBKIT_DOM_HTML_INPUT_ELEMENT (element),
- self->existing_identity);
- webkit_dom_html_input_element_set_read_only (WEBKIT_DOM_HTML_INPUT_ELEMENT (element), TRUE);
- }
- else if (WEBKIT_DOM_IS_HTML_INPUT_ELEMENT (element)
- && ((GOA_IS_OAUTH_PROVIDER (self->provider)
- && goa_oauth_provider_is_password_node (GOA_OAUTH_PROVIDER (self->provider),
- WEBKIT_DOM_HTML_INPUT_ELEMENT (element)))
- || (GOA_IS_OAUTH2_PROVIDER (self->provider)
- && goa_oauth2_provider_is_password_node (GOA_OAUTH2_PROVIDER (self->provider),
- WEBKIT_DOM_HTML_INPUT_ELEMENT (element)))))
- {
- WebKitDOMHTMLFormElement *form;
-
- form = webkit_dom_html_input_element_get_form (WEBKIT_DOM_HTML_INPUT_ELEMENT (element));
- if (form != NULL)
- {
- g_object_set_data_full (G_OBJECT (dom_window),
- "goa-password-node",
- g_object_ref (element),
- g_object_unref);
- webkit_dom_event_target_add_event_listener (WEBKIT_DOM_EVENT_TARGET (form),
- "submit",
- G_CALLBACK (web_extension_dom_node_password_submit_cb),
- FALSE,
- dom_window);
- }
- }
- }
-
- g_clear_object (&elements);
-}
-
-static void
-web_extension_page_created_cb (GoaWebExtension *self, WebKitWebPage *web_page)
-{
- g_signal_connect_object (web_page, "document-loaded", G_CALLBACK (web_extension_document_loaded_cb), self, 0);
-}
-
-static void
-goa_web_extension_constructed (GObject *object)
-{
- GoaWebExtension *self = GOA_WEB_EXTENSION (object);
-
- G_OBJECT_CLASS (goa_web_extension_parent_class)->constructed (object);
-
- self->provider = goa_provider_get_for_provider_type (self->provider_type);
-
- g_signal_connect_object (self->wk_extension,
- "page-created",
- G_CALLBACK (web_extension_page_created_cb),
- self,
- G_CONNECT_SWAPPED);
-}
-
-static void
-goa_web_extension_dispose (GObject *object)
-{
- GoaWebExtension *self = GOA_WEB_EXTENSION (object);
-
- g_clear_object (&self->provider);
- g_clear_object (&self->wk_extension);
-
- G_OBJECT_CLASS (goa_web_extension_parent_class)->dispose (object);
-}
-
-static void
-goa_web_extension_finalize (GObject *object)
-{
- GoaWebExtension *self = GOA_WEB_EXTENSION (object);
-
- g_free (self->existing_identity);
- g_free (self->provider_type);
-
- G_OBJECT_CLASS (goa_web_extension_parent_class)->finalize (object);
-}
-
-static void
-goa_web_extension_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
- GoaWebExtension *self = GOA_WEB_EXTENSION (object);
-
- switch (prop_id)
- {
- case PROP_EXISTING_IDENTITY:
- self->existing_identity = g_value_dup_string (value);
- break;
-
- case PROP_PROVIDER_TYPE:
- self->provider_type = g_value_dup_string (value);
- break;
-
- case PROP_WK_EXTENSION:
- self->wk_extension = WEBKIT_WEB_EXTENSION (g_value_dup_object (value));
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-goa_web_extension_class_init (GoaWebExtensionClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->constructed = goa_web_extension_constructed;
- object_class->dispose = goa_web_extension_dispose;
- object_class->finalize = goa_web_extension_finalize;
- object_class->set_property = goa_web_extension_set_property;
-
- g_object_class_install_property (object_class,
- PROP_EXISTING_IDENTITY,
- g_param_spec_string ("existing-identity",
- "A GoaAccount identity",
- "The user name with which we want to prefill the form",
- NULL,
- G_PARAM_WRITABLE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property (object_class,
- PROP_PROVIDER_TYPE,
- g_param_spec_string ("provider-type",
- "A GoaProvider type",
- "The provider type that is represented by this view",
- NULL,
- G_PARAM_WRITABLE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property (object_class,
- PROP_WK_EXTENSION,
- g_param_spec_object ("wk-extension",
- "A WebKitWebExtension",
- "The associated WebKitWebExtension",
- WEBKIT_TYPE_WEB_EXTENSION,
- G_PARAM_WRITABLE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS));
-}
-
-static void
-goa_web_extension_init (GoaWebExtension *self)
-{
-}
-
-GoaWebExtension *
-goa_web_extension_new (WebKitWebExtension *wk_extension,
- const gchar *provider_type,
- const gchar *existing_identity)
-{
- return g_object_new (GOA_TYPE_WEB_EXTENSION,
- "existing-identity", existing_identity,
- "provider-type", provider_type,
- "wk-extension", wk_extension,
- NULL);
-}
diff --git a/src/goabackend/goawebextension.h b/src/goabackend/goawebextension.h
deleted file mode 100644
index 4a8cf8f..0000000
--- a/src/goabackend/goawebextension.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-/*
- * Copyright © 2015 Damián Nohales
- * Copyright © 2015 2017 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GOA_WEB_EXTENSION_H__
-#define __GOA_WEB_EXTENSION_H__
-
-#include <glib-object.h>
-#include <webkit2/webkit-web-extension.h>
-
-G_BEGIN_DECLS
-
-#define GOA_TYPE_WEB_EXTENSION (goa_web_extension_get_type())
-#define GOA_WEB_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GOA_TYPE_WEB_EXTENSION, GoaWebExtension))
-#define GOA_IS_WEB_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GOA_TYPE_WEB_EXTENSION))
-
-typedef struct _GoaWebExtension GoaWebExtension;
-typedef struct _GoaWebExtensionClass GoaWebExtensionClass;
-
-GType goa_web_extension_get_type (void);
-GoaWebExtension *goa_web_extension_new (WebKitWebExtension *wk_extension,
- const gchar *provider_type,
- const gchar *existing_identity);
-
-G_END_DECLS
-
-#endif /* __GOA_WEB_EXTENSION_H__ */
diff --git a/src/goabackend/goawebextensionmain.c b/src/goabackend/goawebextensionmain.c
deleted file mode 100644
index 4fc91e5..0000000
--- a/src/goabackend/goawebextensionmain.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-/*
- * Copyright © 2015 Damián Nohales
- * Copyright © 2015 2017 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "config.h"
-
-#include <gmodule.h>
-#include <webkit2/webkit-web-extension.h>
-
-#include "goawebextension.h"
-
-static GoaWebExtension *the_extension;
-
-/* Silence -Wmissing-prototypes */
-void webkit_web_extension_initialize (WebKitWebExtension *wk_extension);
-void webkit_web_extension_initialize_with_user_data (WebKitWebExtension *wk_extension, GVariant *user_data);
-
-G_MODULE_EXPORT void
-webkit_web_extension_initialize (WebKitWebExtension *wk_extension)
-{
- g_warning ("Error initializing web extension: user data not set");
-}
-
-G_MODULE_EXPORT void
-webkit_web_extension_initialize_with_user_data (WebKitWebExtension *wk_extension, GVariant *user_data)
-{
- const gchar *existing_identity;
- const gchar *provider_type;
-
- g_variant_get (user_data, "(&s&s)", &provider_type, &existing_identity);
- the_extension = goa_web_extension_new (wk_extension, provider_type, existing_identity);
-}
-
-static void __attribute__((destructor))
-goa_web_extension_shutdown (void)
-{
- g_clear_object (&the_extension);
-}
diff --git a/src/goabackend/goawebview.c b/src/goabackend/goawebview.c
deleted file mode 100644
index b7af122..0000000
--- a/src/goabackend/goawebview.c
+++ /dev/null
@@ -1,501 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright © 2015 Damián Nohales
- * Copyright © 2012 2017 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/* Based on code by the Epiphany team.
- */
-
-#include "config.h"
-
-#include <glib.h>
-#include <glib/gi18n-lib.h>
-#include <JavaScriptCore/JavaScript.h>
-#include <libsoup/soup.h>
-#include <webkit2/webkit2.h>
-
-#include "goawebview.h"
-#include "nautilus-floating-bar.h"
-
-struct _GoaWebView
-{
- GtkOverlay parent_instance;
- GoaProvider *provider;
- GtkWidget *floating_bar;
- GtkWidget *progress_bar;
- GtkWidget *web_view;
- WebKitUserContentManager *user_content_manager;
- WebKitWebContext *context;
- gchar *existing_identity;
- gulong clear_notify_progress_id;
- gulong notify_load_status_id;
- gulong notify_progress_id;
-};
-
-struct _GoaWebViewClass
-{
- GtkOverlayClass parent_class;
-};
-
-enum
-{
- PROP_0,
- PROP_EXISTING_IDENTITY,
- PROP_PROVIDER
-};
-
-enum
-{
- DENY_CLICK,
- PASSWORD_SUBMIT,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-G_DEFINE_TYPE (GoaWebView, goa_web_view, GTK_TYPE_OVERLAY)
-
-static gboolean
-web_view_clear_notify_progress_cb (gpointer user_data)
-{
- GoaWebView *self = GOA_WEB_VIEW (user_data);
-
- gtk_widget_hide (self->progress_bar);
- self->clear_notify_progress_id = 0;
- return FALSE;
-}
-
-static char *
-web_view_create_loading_title (const gchar *url)
-{
- SoupURI *uri;
- const gchar *hostname;
- gchar *title;
-
- g_return_val_if_fail (url != NULL && url[0] != '\0', NULL);
-
- uri = soup_uri_new (url);
- hostname = soup_uri_get_host (uri);
- /* translators: %s here is the address of the web page */
- title = g_strdup_printf (_("Loading “%s”…"), hostname);
- soup_uri_free (uri);
-
- return title;
-}
-
-static void
-web_view_floating_bar_update (GoaWebView *self, const gchar *text)
-{
- nautilus_floating_bar_set_label (NAUTILUS_FLOATING_BAR (self->floating_bar), text);
-
- if (text == NULL || text[0] == '\0')
- {
- gtk_widget_hide (self->floating_bar);
- gtk_widget_set_halign (self->floating_bar, GTK_ALIGN_START);
- }
- else
- gtk_widget_show (self->floating_bar);
-}
-
-static void
-web_view_initialize_web_extensions_cb (GoaWebView *self)
-{
- GVariant *data;
- const gchar *existing_identity;
- const gchar *provider_type;
-
- webkit_web_context_set_web_extensions_directory (self->context, PACKAGE_WEB_EXTENSIONS_DIR);
-
- if (self->provider == NULL)
- return;
-
- provider_type = goa_provider_get_provider_type (self->provider);
- existing_identity = (self->existing_identity == NULL) ? "" : self->existing_identity;
- data = g_variant_new ("(ss)", provider_type, existing_identity);
- webkit_web_context_set_web_extensions_initialization_user_data (self->context, data);
-}
-
-#ifdef GOA_INSPECTOR_ENABLED
-static void
-web_view_inspector_closed_cb (WebKitWebInspector *inspector)
-{
- GtkWidget *window;
- WebKitWebViewBase *inspector_web_view;
-
- inspector_web_view = webkit_web_inspector_get_web_view (inspector);
- window = gtk_widget_get_toplevel (GTK_WIDGET (inspector_web_view));
- if (gtk_widget_is_toplevel (window))
- gtk_widget_destroy (window);
-}
-
-static gboolean
-web_view_inspector_open_window_cb (WebKitWebInspector *inspector)
-{
- GtkWidget *window;
- GtkWindowGroup *group;
- WebKitWebViewBase *inspector_web_view;
-
- group = gtk_window_group_new ();
-
- window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- gtk_window_resize (GTK_WINDOW (window), 800, 600);
- gtk_window_group_add_window (group, GTK_WINDOW (window));
- g_object_unref (group);
-
- inspector_web_view = webkit_web_inspector_get_web_view (inspector);
- gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (inspector_web_view));
-
- gtk_widget_show_all (window);
- gtk_window_present (GTK_WINDOW (window));
-
- return GDK_EVENT_STOP;
-}
-#endif /* GOA_INSPECTOR_ENABLED */
-
-static void
-web_view_load_changed_cb (WebKitWebView *web_view,
- WebKitLoadEvent load_event,
- gpointer user_data)
-{
- GoaWebView *self = GOA_WEB_VIEW (user_data);
-
- switch (load_event)
- {
- case WEBKIT_LOAD_STARTED:
- case WEBKIT_LOAD_COMMITTED:
- {
- const gchar *uri;
- gchar *title;
-
- uri = webkit_web_view_get_uri (web_view);
- title = web_view_create_loading_title (uri);
-
- web_view_floating_bar_update (self, title);
- g_free (title);
- break;
- }
-
- case WEBKIT_LOAD_REDIRECTED:
- /* TODO: Update the loading uri */
- break;
-
- case WEBKIT_LOAD_FINISHED:
- web_view_floating_bar_update (self, NULL);
- break;
-
- default:
- break;
- }
-}
-
-static void
-web_view_notify_estimated_load_progress_cb (GObject *object,
- GParamSpec *pspec,
- gpointer user_data)
-{
- GoaWebView *self = GOA_WEB_VIEW (user_data);
- WebKitWebView *web_view = WEBKIT_WEB_VIEW (object);
- gboolean loading;
- const gchar *uri;
- gdouble progress;
-
- if (self->clear_notify_progress_id != 0)
- {
- g_source_remove (self->clear_notify_progress_id);
- self->clear_notify_progress_id = 0;
- }
-
- uri = webkit_web_view_get_uri (web_view);
- if (!uri || g_str_equal (uri, "about:blank"))
- return;
-
- progress = webkit_web_view_get_estimated_load_progress (web_view);
- loading = webkit_web_view_is_loading (web_view);
-
- if (progress == 1.0 || !loading)
- self->clear_notify_progress_id = g_timeout_add (500, web_view_clear_notify_progress_cb, self);
- else
- gtk_widget_show (self->progress_bar);
-
- gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (self->progress_bar),
- (loading || progress == 1.0) ? progress : 0.0);
-}
-
-static void
-web_view_script_message_received_deny_click_cb (GoaWebView *self)
-{
- g_signal_emit (self, signals[DENY_CLICK], 0);
-}
-
-static void
-web_view_script_message_received_password_submit_cb (GoaWebView *self, WebKitJavascriptResult *js_result)
-{
- JSGlobalContextRef js_context;
- JSStringRef js_string;
- JSValueRef js_value;
- gsize max_size;
-
- js_value = webkit_javascript_result_get_value (js_result);
- js_context = webkit_javascript_result_get_global_context (js_result);
- js_string = JSValueToStringCopy (js_context, js_value, NULL);
- max_size = JSStringGetMaximumUTF8CStringSize (js_string);
- if (max_size > 0)
- {
- gchar *password;
-
- password = g_malloc0 (max_size);
- JSStringGetUTF8CString (js_string, password, max_size);
- g_signal_emit (self, signals[PASSWORD_SUBMIT], 0, password);
- g_free (password);
- }
-
- JSStringRelease (js_string);
-}
-
-static void
-goa_web_view_constructed (GObject *object)
-{
- GoaWebView *self = GOA_WEB_VIEW (object);
- const gchar *const *language_names;
-
- G_OBJECT_CLASS (goa_web_view_parent_class)->constructed (object);
-
- self->context = webkit_web_context_new ();
- language_names = g_get_language_names ();
- webkit_web_context_set_preferred_languages (self->context, language_names);
- g_signal_connect_swapped (self->context,
- "initialize-web-extensions",
- G_CALLBACK (web_view_initialize_web_extensions_cb),
- self);
-
- self->user_content_manager = webkit_user_content_manager_new ();
- g_signal_connect_swapped (self->user_content_manager,
- "script-message-received::deny-click",
- G_CALLBACK (web_view_script_message_received_deny_click_cb),
- self);
- g_signal_connect_swapped (self->user_content_manager,
- "script-message-received::password-submit",
- G_CALLBACK (web_view_script_message_received_password_submit_cb),
- self);
- webkit_user_content_manager_register_script_message_handler (self->user_content_manager, "deny-click");
- webkit_user_content_manager_register_script_message_handler (self->user_content_manager, "password-submit");
-
- self->web_view = GTK_WIDGET (g_object_new (WEBKIT_TYPE_WEB_VIEW,
- "user-content-manager", self->user_content_manager,
- "web-context", self->context,
- NULL));
- gtk_widget_set_size_request (self->web_view, 500, 400);
- gtk_container_add (GTK_CONTAINER (self), self->web_view);
-
-#ifdef GOA_INSPECTOR_ENABLED
- {
- WebKitSettings *settings;
- WebKitWebInspector *inspector;
-
- /* Setup the inspector */
- settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (self->web_view));
- g_object_set (settings, "enable-developer-extras", TRUE, NULL);
-
- inspector = webkit_web_view_get_inspector (WEBKIT_WEB_VIEW (self->web_view));
- g_signal_connect (inspector, "closed", G_CALLBACK (web_view_inspector_closed_cb), NULL);
- g_signal_connect (inspector, "open-window", G_CALLBACK (web_view_inspector_open_window_cb), NULL);
- }
-#endif /* GOA_INSPECTOR_ENABLED */
-
- /* statusbar is hidden by default */
- self->floating_bar = nautilus_floating_bar_new (NULL, FALSE);
- gtk_widget_set_halign (self->floating_bar, GTK_ALIGN_START);
- gtk_widget_set_valign (self->floating_bar, GTK_ALIGN_END);
- gtk_widget_set_no_show_all (self->floating_bar, TRUE);
- gtk_overlay_add_overlay (GTK_OVERLAY (self), self->floating_bar);
-
- self->progress_bar = gtk_progress_bar_new ();
- gtk_style_context_add_class (gtk_widget_get_style_context (self->progress_bar),
- GTK_STYLE_CLASS_OSD);
- gtk_widget_set_halign (self->progress_bar, GTK_ALIGN_FILL);
- gtk_widget_set_valign (self->progress_bar, GTK_ALIGN_START);
- gtk_overlay_add_overlay (GTK_OVERLAY (self), self->progress_bar);
-
- self->notify_progress_id = g_signal_connect (self->web_view,
- "notify::estimated-load-progress",
- G_CALLBACK (web_view_notify_estimated_load_progress_cb),
- self);
- self->notify_load_status_id = g_signal_connect (self->web_view,
- "load_changed",
- G_CALLBACK (web_view_load_changed_cb),
- self);
-}
-
-static void
-goa_web_view_dispose (GObject *object)
-{
- GoaWebView *self = GOA_WEB_VIEW (object);
-
- g_clear_object (&self->user_content_manager);
- g_clear_object (&self->context);
-
- if (self->clear_notify_progress_id != 0)
- {
- g_source_remove (self->clear_notify_progress_id);
- self->clear_notify_progress_id = 0;
- }
-
- if (self->notify_load_status_id != 0)
- {
- g_signal_handler_disconnect (self->web_view, self->notify_load_status_id);
- self->notify_load_status_id = 0;
- }
-
- if (self->notify_progress_id != 0)
- {
- g_signal_handler_disconnect (self->web_view, self->notify_progress_id);
- self->notify_progress_id = 0;
- }
-
- G_OBJECT_CLASS (goa_web_view_parent_class)->dispose (object);
-}
-
-static void
-goa_web_view_finalize (GObject *object)
-{
- GoaWebView *self = GOA_WEB_VIEW (object);
-
- g_free (self->existing_identity);
-
- if (self->provider != NULL)
- g_object_remove_weak_pointer (G_OBJECT (self->provider), (gpointer *) &self->provider);
-
- G_OBJECT_CLASS (goa_web_view_parent_class)->finalize (object);
-}
-
-static void
-goa_web_view_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
-{
- GoaWebView *self = GOA_WEB_VIEW (object);
-
- switch (prop_id)
- {
- case PROP_EXISTING_IDENTITY:
- self->existing_identity = g_value_dup_string (value);
- break;
-
- case PROP_PROVIDER:
- self->provider = GOA_PROVIDER (g_value_get_object (value));
- if (self->provider != NULL)
- g_object_add_weak_pointer (G_OBJECT (self->provider), (gpointer *) &self->provider);
- break;
-
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-goa_web_view_init (GoaWebView *self)
-{
-}
-
-static void
-goa_web_view_class_init (GoaWebViewClass *klass)
-{
- GObjectClass *object_class;
-
- object_class = G_OBJECT_CLASS (klass);
- object_class->constructed = goa_web_view_constructed;
- object_class->dispose = goa_web_view_dispose;
- object_class->finalize = goa_web_view_finalize;
- object_class->set_property = goa_web_view_set_property;
-
- g_object_class_install_property (object_class,
- PROP_EXISTING_IDENTITY,
- g_param_spec_string ("existing-identity",
- "A GoaAccount identity",
- "The user name with which we want to prefill the form",
- NULL,
- G_PARAM_WRITABLE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property (object_class,
- PROP_PROVIDER,
- g_param_spec_object ("provider",
- "A GoaProvider",
- "The provider that is represented by this view",
- GOA_TYPE_PROVIDER,
- G_PARAM_WRITABLE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS));
-
- signals[DENY_CLICK] = g_signal_new ("deny-click",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL,
- NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE,
- 0);
-
- signals[PASSWORD_SUBMIT] = g_signal_new ("password-submit",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL,
- NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE,
- 1,
- G_TYPE_STRING);
-}
-
-GtkWidget *
-goa_web_view_new (GoaProvider *provider, const gchar *existing_identity)
-{
- return g_object_new (GOA_TYPE_WEB_VIEW, "provider", provider, "existing-identity", existing_identity, NULL);
-}
-
-GtkWidget *
-goa_web_view_get_view (GoaWebView *self)
-{
- return self->web_view;
-}
-
-void
-goa_web_view_fake_mobile (GoaWebView *self)
-{
- WebKitSettings *settings;
-
- settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (self->web_view));
-
- /* This is based on the HTC Wildfire's user agent. Some
- * providers, like Google, refuse to provide the mobile
- * version of their authentication pages otherwise. eg.,
- * in Google's case, passing btmpl=mobile does not help.
- *
- * The actual user agent used by a HTC Wildfire is:
- * Mozilla/5.0 (Linux; U; Android 2.2.1; en-us; HTC Wildfire
- * Build/FRG83D) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0
- * Mobile Safari/533.1
- *
- * Also note that the user agents of some mobile browsers may
- * not work. eg., Nokia N9.
- */
- webkit_settings_set_user_agent (settings,
- "Mozilla/5.0 (GNOME; not Android) "
- "AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile");
-}
diff --git a/src/goabackend/goawebview.h b/src/goabackend/goawebview.h
deleted file mode 100644
index 4b415cd..0000000
--- a/src/goabackend/goawebview.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
- *
- * Copyright © 2012 2017 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __GOA_WEB_VIEW_H__
-#define __GOA_WEB_VIEW_H__
-
-#include <gtk/gtk.h>
-
-#include "goaprovider.h"
-
-G_BEGIN_DECLS
-
-#define GOA_TYPE_WEB_VIEW (goa_web_view_get_type ())
-#define GOA_WEB_VIEW(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GOA_TYPE_WEB_VIEW, GoaWebView))
-#define GOA_IS_WEB_VIEW(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GOA_TYPE_WEB_VIEW))
-
-typedef struct _GoaWebView GoaWebView;
-typedef struct _GoaWebViewClass GoaWebViewClass;
-
-GType goa_web_view_get_type (void) G_GNUC_CONST;
-GtkWidget *goa_web_view_new (GoaProvider *provider,
- const gchar *existing_identity);
-GtkWidget *goa_web_view_get_view (GoaWebView *self);
-void goa_web_view_fake_mobile (GoaWebView *self);
-
-G_END_DECLS
-
-#endif /* __GOA_WEB_VIEW_H__ */
diff --git a/src/goabackend/goawindowsliveprovider.c b/src/goabackend/goawindowsliveprovider.c
index 10c2dcf..2135fbd 100644
--- a/src/goabackend/goawindowsliveprovider.c
+++ b/src/goabackend/goawindowsliveprovider.c
@@ -94,7 +94,8 @@ get_token_uri (GoaOAuth2Provider *oauth2_provider)
static const gchar *
get_redirect_uri (GoaOAuth2Provider *oauth2_provider)
{
- return "https://login.live.com/oauth20_desktop.srf";
+ /* See: https://learn.microsoft.com/en-us/entra/identity-platform/reply-url */
+ return "goa-oauth2://localhost/"GOA_WINDOWS_LIVE_CLIENT_ID;
}
static const gchar *
@@ -234,36 +235,6 @@ get_identity_sync (GoaOAuth2Provider *oauth2_provider,
/* ---------------------------------------------------------------------------------------------------- */
-static gboolean
-is_identity_node (GoaOAuth2Provider *oauth2_provider, WebKitDOMHTMLInputElement *element)
-{
- gboolean ret = FALSE;
- gchar *element_type = NULL;
- gchar *name = NULL;
-
- /* FIXME: This does not show up in
- * webkit_dom_document_get_elements_by_tag_name, but can be
- * seen in the inspector. Needs further investigation.
- */
-
- g_object_get (element, "type", &element_type, NULL);
- if (g_strcmp0 (element_type, "email") != 0)
- goto out;
-
- name = webkit_dom_html_input_element_get_name (element);
- if (g_strcmp0 (name, "login") != 0)
- goto out;
-
- ret = TRUE;
-
- out:
- g_free (element_type);
- g_free (name);
- return ret;
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
static gboolean
build_object (GoaProvider *provider,
GoaObjectSkeleton *object,
@@ -390,6 +361,5 @@ goa_windows_live_provider_class_init (GoaWindowsLiveProviderClass *klass)
oauth2_class->get_client_id = get_client_id;
oauth2_class->get_client_secret = get_client_secret;
oauth2_class->get_identity_sync = get_identity_sync;
- oauth2_class->is_identity_node = is_identity_node;
oauth2_class->add_account_key_values = add_account_key_values;
}