|
|
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;
|
|
|
}
|