|
Packit |
4b6dd7 |
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
|
|
Packit |
4b6dd7 |
/*
|
|
Packit |
4b6dd7 |
* GData Client
|
|
Packit |
4b6dd7 |
* Copyright (C) Philip Withnall 2011 <philip@tecnocode.co.uk>
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* GData Client is free software; you can redistribute it and/or
|
|
Packit |
4b6dd7 |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
4b6dd7 |
* License as published by the Free Software Foundation; either
|
|
Packit |
4b6dd7 |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* GData Client is distributed in the hope that it will be useful,
|
|
Packit |
4b6dd7 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
4b6dd7 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
4b6dd7 |
* Lesser General Public License for more details.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
4b6dd7 |
* License along with GData Client. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* SECTION:gdata-oauth1-authorizer
|
|
Packit |
4b6dd7 |
* @short_description: GData OAuth 1.0 authorization interface
|
|
Packit |
4b6dd7 |
* @stability: Stable
|
|
Packit |
4b6dd7 |
* @include: gdata/gdata-oauth1-authorizer.h
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* #GDataOAuth1Authorizer provides an implementation of the #GDataAuthorizer interface for authentication and authorization using the
|
|
Packit |
4b6dd7 |
* <ulink type="http" url="http://code.google.com/apis/accounts/docs/OAuthForInstalledApps.html">OAuth 1.0</ulink> process,
|
|
Packit |
4b6dd7 |
* which was preferred by Google until OAuth 2.0 was released — it is now
|
|
Packit |
4b6dd7 |
* preferred to use #GDataOAuth2Authorizer.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* OAuth 1.0 replaces the deprecated ClientLogin process. One of the main reasons for this is to allow two-factor authentication to be supported, by
|
|
Packit |
4b6dd7 |
* moving the authentication interface to a web page under Google's control.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* The OAuth 1.0 process as implemented by Google follows the <ulink type="http" url="http://tools.ietf.org/html/rfc5849">OAuth 1.0 protocol as
|
|
Packit |
4b6dd7 |
* specified by IETF in RFC 5849</ulink>, with a few additions to support scopes (implemented in libgdata by #GDataAuthorizationDomains),
|
|
Packit |
4b6dd7 |
* locales and custom domains. Briefly, the process is initiated by requesting an authenticated request token from the Google accounts service
|
|
Packit |
4b6dd7 |
* (using gdata_oauth1_authorizer_request_authentication_uri()), going to the authentication URI for the request token, authenticating and authorizing
|
|
Packit |
4b6dd7 |
* access to the desired scopes, then providing the verifier returned by Google to the Google accounts service again (using
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_request_authorization()) to authorize the token. This results in an access token which is attached to all future requests
|
|
Packit |
4b6dd7 |
* to the online service.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* While Google supports unregistered and registered modes for OAuth 1.0 authorization, it only supports unregistered mode for installed applications.
|
|
Packit |
4b6dd7 |
* Consequently, libgdata also only supports unregistered mode. For this purpose, the application name to be presented to the user on the
|
|
Packit |
4b6dd7 |
* authentication page at the URI returned by gdata_oauth1_authorizer_request_authentication_uri() can be specified when constructing the
|
|
Packit |
4b6dd7 |
* #GDataOAuth1Authorizer.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* As described, each authentication/authorization operation is in two parts: gdata_oauth1_authorizer_request_authentication_uri() and
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_request_authorization(). #GDataOAuth1Authorizer stores no state about ongoing authentication operations (i.e. ones which
|
|
Packit |
4b6dd7 |
* have successfully called gdata_oauth1_authorizer_request_authentication_uri(), but are yet to successfully call
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_request_authorization()). Consequently, operations can be abandoned before calling
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_request_authorization() without problems. The only state necessary between the calls is the request token and request token
|
|
Packit |
4b6dd7 |
* secret, as returned by gdata_oauth1_authorizer_request_authentication_uri() and taken as parameters to
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_request_authorization().
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* #GDataOAuth1Authorizer natively supports authorization against multiple services in a single authorization request (unlike
|
|
Packit |
4b6dd7 |
* #GDataClientLoginAuthorizer).
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Each access token is long lived, so reauthorization is rarely necessary with #GDataOAuth1Authorizer. Consequently, refreshing authorization using
|
|
Packit |
4b6dd7 |
* gdata_authorizer_refresh_authorization() is not supported by #GDataOAuth1Authorizer, and will immediately return %FALSE with no error set.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* <example>
|
|
Packit |
4b6dd7 |
* <title>Authenticating Asynchronously Using OAuth 1.0</title>
|
|
Packit |
4b6dd7 |
* <programlisting>
|
|
Packit |
4b6dd7 |
* GDataSomeService *service;
|
|
Packit |
4b6dd7 |
* GDataOAuth1Authorizer *authorizer;
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* /* Create an authorizer and authenticate and authorize the service we're using, asynchronously. */
|
|
Packit |
4b6dd7 |
* authorizer = gdata_oauth1_authorizer_new (_("My libgdata application"), GDATA_TYPE_SOME_SERVICE);
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_request_authentication_uri_async (authorizer, cancellable,
|
|
Packit |
4b6dd7 |
* (GAsyncReadyCallback) request_authentication_uri_cb, user_data);
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* /* Create a service object and link it with the authorizer */
|
|
Packit |
4b6dd7 |
* service = gdata_some_service_new (GDATA_AUTHORIZER (authorizer));
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* static void
|
|
Packit |
4b6dd7 |
* request_authentication_uri_cb (GDataOAuth1Authorizer *authorizer, GAsyncResult *async_result, gpointer user_data)
|
|
Packit |
4b6dd7 |
* {
|
|
Packit |
4b6dd7 |
* gchar *authentication_uri, *token, *token_secret, *verifier;
|
|
Packit |
4b6dd7 |
* GError *error = NULL;
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* authentication_uri = gdata_oauth1_authorizer_request_authentication_uri_finish (authorizer, async_result, &token, &token_secret,
|
|
Packit |
4b6dd7 |
* &error);
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* if (error != NULL) {
|
|
Packit |
4b6dd7 |
* /* Notify the user of all errors except cancellation errors */
|
|
Packit |
4b6dd7 |
* if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
|
|
Packit |
4b6dd7 |
* g_error ("Requesting a token failed: %s", error->message);
|
|
Packit |
4b6dd7 |
* }
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* g_error_free (error);
|
|
Packit |
4b6dd7 |
* goto finish;
|
|
Packit |
4b6dd7 |
* }
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* /* (Present the page at the authentication URI to the user, either in an embedded or stand-alone web browser, and
|
|
Packit |
4b6dd7 |
* * ask them to grant access to the application and return the verifier Google gives them.) */
|
|
Packit |
4b6dd7 |
* verifier = ask_user_for_verifier (authentication_uri);
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_request_authorization_async (authorizer, token, token_secret, verifier, cancellable,
|
|
Packit |
4b6dd7 |
* (GAsyncReadyCallback) request_authorization_cb, user_data);
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* finish:
|
|
Packit |
4b6dd7 |
* g_free (verifier);
|
|
Packit |
4b6dd7 |
* g_free (authentication_uri);
|
|
Packit |
4b6dd7 |
* g_free (token);
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* /* Zero out the secret before freeing. */
|
|
Packit |
4b6dd7 |
* if (token_secret != NULL) {
|
|
Packit |
4b6dd7 |
* memset (token_secret, 0, strlen (token_secret));
|
|
Packit |
4b6dd7 |
* }
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* g_free (token_secret);
|
|
Packit |
4b6dd7 |
* }
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* static void
|
|
Packit |
4b6dd7 |
* request_authorization_cb (GDataOAuth1Authorizer *authorizer, GAsyncResult *async_result, gpointer user_data)
|
|
Packit |
4b6dd7 |
* {
|
|
Packit |
4b6dd7 |
* GError *error = NULL;
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* if (gdata_oauth1_authorizer_request_authorization_finish (authorizer, async_result, &error) == FALSE) {
|
|
Packit |
4b6dd7 |
* /* Notify the user of all errors except cancellation errors */
|
|
Packit |
4b6dd7 |
* if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
|
|
Packit |
4b6dd7 |
* g_error ("Authorization failed: %s", error->message);
|
|
Packit |
4b6dd7 |
* }
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* g_error_free (error);
|
|
Packit |
4b6dd7 |
* return;
|
|
Packit |
4b6dd7 |
* }
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* /* (The client is now authenticated and authorized against the service.
|
|
Packit |
4b6dd7 |
* * It can now proceed to execute queries on the service object which require the user to be authenticated.) */
|
|
Packit |
4b6dd7 |
* }
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* g_object_unref (service);
|
|
Packit |
4b6dd7 |
* g_object_unref (authorizer);
|
|
Packit |
4b6dd7 |
* </programlisting>
|
|
Packit |
4b6dd7 |
* </example>
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
#include <config.h>
|
|
Packit |
4b6dd7 |
#include <string.h>
|
|
Packit |
4b6dd7 |
#include <oauth.h>
|
|
Packit |
4b6dd7 |
#include <glib.h>
|
|
Packit |
4b6dd7 |
#include <glib/gi18n-lib.h>
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
#include "gdata-oauth1-authorizer.h"
|
|
Packit |
4b6dd7 |
#include "gdata-private.h"
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
#define HMAC_SHA1_LEN 20 /* bytes, raw */
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void authorizer_init (GDataAuthorizerInterface *iface);
|
|
Packit |
4b6dd7 |
static void dispose (GObject *object);
|
|
Packit |
4b6dd7 |
static void finalize (GObject *object);
|
|
Packit |
4b6dd7 |
static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
|
|
Packit |
4b6dd7 |
static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void process_request (GDataAuthorizer *self, GDataAuthorizationDomain *domain, SoupMessage *message);
|
|
Packit |
4b6dd7 |
static gboolean is_authorized_for_domain (GDataAuthorizer *self, GDataAuthorizationDomain *domain);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void sign_message (GDataOAuth1Authorizer *self, SoupMessage *message, const gchar *token, const gchar *token_secret, GHashTable *parameters);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void notify_proxy_uri_cb (GObject *object, GParamSpec *pspec, GDataOAuth1Authorizer *self);
|
|
Packit |
4b6dd7 |
static void notify_timeout_cb (GObject *gobject, GParamSpec *pspec, GObject *self);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static SoupURI *_get_proxy_uri (GDataOAuth1Authorizer *self);
|
|
Packit |
4b6dd7 |
static void _set_proxy_uri (GDataOAuth1Authorizer *self, SoupURI *proxy_uri);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
struct _GDataOAuth1AuthorizerPrivate {
|
|
Packit |
4b6dd7 |
SoupSession *session;
|
|
Packit |
4b6dd7 |
SoupURI *proxy_uri; /* cached version only set if gdata_oauth1_authorizer_get_proxy_uri() is called */
|
|
Packit |
4b6dd7 |
GProxyResolver *proxy_resolver;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
gchar *application_name;
|
|
Packit |
4b6dd7 |
gchar *locale;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
GMutex mutex; /* mutex for token, token_secret and authorization_domains */
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Note: This is the access token, not the request token returned by gdata_oauth1_authorizer_request_authentication_uri().
|
|
Packit |
4b6dd7 |
* It's NULL iff the authorizer isn't authenticated. token_secret must be NULL iff token is NULL. */
|
|
Packit |
4b6dd7 |
gchar *token;
|
|
Packit |
4b6dd7 |
GDataSecureString token_secret; /* must be allocated by _gdata_service_secure_strdup() */
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Mapping from GDataAuthorizationDomain to itself; a set of domains for which ->access_token is valid. */
|
|
Packit |
4b6dd7 |
GHashTable *authorization_domains;
|
|
Packit |
4b6dd7 |
};
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
enum {
|
|
Packit |
4b6dd7 |
PROP_APPLICATION_NAME = 1,
|
|
Packit |
4b6dd7 |
PROP_LOCALE,
|
|
Packit |
4b6dd7 |
PROP_PROXY_URI,
|
|
Packit |
4b6dd7 |
PROP_TIMEOUT,
|
|
Packit |
4b6dd7 |
PROP_PROXY_RESOLVER,
|
|
Packit |
4b6dd7 |
};
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
G_DEFINE_TYPE_WITH_CODE (GDataOAuth1Authorizer, gdata_oauth1_authorizer, G_TYPE_OBJECT,
|
|
Packit |
4b6dd7 |
G_IMPLEMENT_INTERFACE (GDATA_TYPE_AUTHORIZER, authorizer_init))
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
gdata_oauth1_authorizer_class_init (GDataOAuth1AuthorizerClass *klass)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_type_class_add_private (klass, sizeof (GDataOAuth1AuthorizerPrivate));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
gobject_class->get_property = get_property;
|
|
Packit |
4b6dd7 |
gobject_class->set_property = set_property;
|
|
Packit |
4b6dd7 |
gobject_class->dispose = dispose;
|
|
Packit |
4b6dd7 |
gobject_class->finalize = finalize;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* GDataOAuth1Authorizer:application-name:
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* The human-readable, translated application name for the client, to be presented to the user on the authentication page at the URI
|
|
Packit |
4b6dd7 |
* returned by gdata_oauth1_authorizer_request_authentication_uri().
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* If %NULL is provided in the constructor to #GDataOAuth1Authorizer, the value returned by g_get_application_name() will be used as a
|
|
Packit |
4b6dd7 |
* fallback. Note that this may also be %NULL: in this case, the authentication page will use the application name “anonymous”.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
g_object_class_install_property (gobject_class, PROP_APPLICATION_NAME,
|
|
Packit |
4b6dd7 |
g_param_spec_string ("application-name",
|
|
Packit |
4b6dd7 |
"Application name", "The human-readable, translated application name for the client.",
|
|
Packit |
4b6dd7 |
NULL,
|
|
Packit |
4b6dd7 |
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* GDataOAuth1Authorizer:locale:
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* The locale to use for network requests, in Unix locale format. (e.g. "en_GB", "cs", "de_DE".) Use %NULL for the default "C" locale
|
|
Packit |
4b6dd7 |
* (typically "en_US").
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* This locale will be used by the server-side software to localise the authentication and authorization pages at the URI returned by
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_request_authentication_uri().
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* The server-side behaviour is undefined if it doesn't support a given locale.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
g_object_class_install_property (gobject_class, PROP_LOCALE,
|
|
Packit |
4b6dd7 |
g_param_spec_string ("locale",
|
|
Packit |
4b6dd7 |
"Locale", "The locale to use for network requests, in Unix locale format.",
|
|
Packit |
4b6dd7 |
NULL,
|
|
Packit |
4b6dd7 |
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* GDataOAuth1Authorizer:proxy-uri:
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* The proxy URI used internally for all network requests.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
* Deprecated: 0.15.0: Use #GDataClientLoginAuthorizer:proxy-resolver instead, which gives more flexibility over the proxy used.
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
g_object_class_install_property (gobject_class, PROP_PROXY_URI,
|
|
Packit |
4b6dd7 |
g_param_spec_boxed ("proxy-uri",
|
|
Packit |
4b6dd7 |
"Proxy URI", "The proxy URI used internally for all network requests.",
|
|
Packit |
4b6dd7 |
SOUP_TYPE_URI,
|
|
Packit |
4b6dd7 |
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* GDataOAuth1Authorizer:timeout:
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* A timeout, in seconds, for network operations. If the timeout is exceeded, the operation will be cancelled and
|
|
Packit |
4b6dd7 |
* %GDATA_SERVICE_ERROR_NETWORK_ERROR will be returned.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* If the timeout is 0 , operations will never time out.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
g_object_class_install_property (gobject_class, PROP_TIMEOUT,
|
|
Packit |
4b6dd7 |
g_param_spec_uint ("timeout",
|
|
Packit |
4b6dd7 |
"Timeout", "A timeout, in seconds, for network operations.",
|
|
Packit |
4b6dd7 |
0, G_MAXUINT, 0,
|
|
Packit |
4b6dd7 |
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* GDataOAuth1Authorizer:proxy-resolver:
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* The #GProxyResolver used to determine a proxy URI. Setting this will clear the #GDataOAuth1Authorizer:proxy-uri property.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.15.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
g_object_class_install_property (gobject_class, PROP_PROXY_RESOLVER,
|
|
Packit |
4b6dd7 |
g_param_spec_object ("proxy-resolver",
|
|
Packit |
4b6dd7 |
"Proxy Resolver", "A GProxyResolver used to determine a proxy URI.",
|
|
Packit |
4b6dd7 |
G_TYPE_PROXY_RESOLVER,
|
|
Packit |
4b6dd7 |
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
authorizer_init (GDataAuthorizerInterface *iface)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
iface->process_request = process_request;
|
|
Packit |
4b6dd7 |
iface->is_authorized_for_domain = is_authorized_for_domain;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
gdata_oauth1_authorizer_init (GDataOAuth1Authorizer *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_OAUTH1_AUTHORIZER, GDataOAuth1AuthorizerPrivate);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Set up the authorizer's mutex */
|
|
Packit |
4b6dd7 |
g_mutex_init (&(self->priv->mutex));
|
|
Packit |
4b6dd7 |
self->priv->authorization_domains = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Set up the session */
|
|
Packit |
4b6dd7 |
self->priv->session = _gdata_service_build_session ();
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Proxy the SoupSession's proxy-uri and timeout properties */
|
|
Packit |
4b6dd7 |
g_signal_connect (self->priv->session, "notify::proxy-uri", (GCallback) notify_proxy_uri_cb, self);
|
|
Packit |
4b6dd7 |
g_signal_connect (self->priv->session, "notify::timeout", (GCallback) notify_timeout_cb, self);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Keep our GProxyResolver synchronized with SoupSession's. */
|
|
Packit |
4b6dd7 |
g_object_bind_property (self->priv->session, "proxy-resolver", self, "proxy-resolver", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
dispose (GObject *object)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataOAuth1AuthorizerPrivate *priv = GDATA_OAUTH1_AUTHORIZER (object)->priv;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (priv->session != NULL)
|
|
Packit |
4b6dd7 |
g_object_unref (priv->session);
|
|
Packit |
4b6dd7 |
priv->session = NULL;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_clear_object (&priv->proxy_resolver);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Chain up to the parent class */
|
|
Packit |
4b6dd7 |
G_OBJECT_CLASS (gdata_oauth1_authorizer_parent_class)->dispose (object);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
finalize (GObject *object)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataOAuth1AuthorizerPrivate *priv = GDATA_OAUTH1_AUTHORIZER (object)->priv;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_free (priv->application_name);
|
|
Packit |
4b6dd7 |
g_free (priv->locale);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_hash_table_destroy (priv->authorization_domains);
|
|
Packit |
4b6dd7 |
g_mutex_clear (&(priv->mutex));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (priv->proxy_uri != NULL) {
|
|
Packit |
4b6dd7 |
soup_uri_free (priv->proxy_uri);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_free (priv->token);
|
|
Packit |
4b6dd7 |
_gdata_service_secure_strfree (priv->token_secret);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Chain up to the parent class */
|
|
Packit |
4b6dd7 |
G_OBJECT_CLASS (gdata_oauth1_authorizer_parent_class)->finalize (object);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataOAuth1AuthorizerPrivate *priv = GDATA_OAUTH1_AUTHORIZER (object)->priv;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
switch (property_id) {
|
|
Packit |
4b6dd7 |
case PROP_APPLICATION_NAME:
|
|
Packit |
4b6dd7 |
g_value_set_string (value, priv->application_name);
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
case PROP_LOCALE:
|
|
Packit |
4b6dd7 |
g_value_set_string (value, priv->locale);
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
case PROP_PROXY_URI:
|
|
Packit |
4b6dd7 |
g_value_set_boxed (value, _get_proxy_uri (GDATA_OAUTH1_AUTHORIZER (object)));
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
case PROP_TIMEOUT:
|
|
Packit |
4b6dd7 |
g_value_set_uint (value, gdata_oauth1_authorizer_get_timeout (GDATA_OAUTH1_AUTHORIZER (object)));
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
case PROP_PROXY_RESOLVER:
|
|
Packit |
4b6dd7 |
g_value_set_object (value, gdata_oauth1_authorizer_get_proxy_resolver (GDATA_OAUTH1_AUTHORIZER (object)));
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
default:
|
|
Packit |
4b6dd7 |
/* We don't have any other property... */
|
|
Packit |
4b6dd7 |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataOAuth1AuthorizerPrivate *priv = GDATA_OAUTH1_AUTHORIZER (object)->priv;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
switch (property_id) {
|
|
Packit |
4b6dd7 |
/* Construct only */
|
|
Packit |
4b6dd7 |
case PROP_APPLICATION_NAME:
|
|
Packit |
4b6dd7 |
priv->application_name = g_value_dup_string (value);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Default to the value of g_get_application_name() */
|
|
Packit |
4b6dd7 |
if (priv->application_name == NULL || *(priv->application_name) == '\0') {
|
|
Packit |
4b6dd7 |
g_free (priv->application_name);
|
|
Packit |
4b6dd7 |
priv->application_name = g_strdup (g_get_application_name ());
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
case PROP_LOCALE:
|
|
Packit |
4b6dd7 |
gdata_oauth1_authorizer_set_locale (GDATA_OAUTH1_AUTHORIZER (object), g_value_get_string (value));
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
case PROP_PROXY_URI:
|
|
Packit |
4b6dd7 |
_set_proxy_uri (GDATA_OAUTH1_AUTHORIZER (object), g_value_get_boxed (value));
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
case PROP_TIMEOUT:
|
|
Packit |
4b6dd7 |
gdata_oauth1_authorizer_set_timeout (GDATA_OAUTH1_AUTHORIZER (object), g_value_get_uint (value));
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
case PROP_PROXY_RESOLVER:
|
|
Packit |
4b6dd7 |
gdata_oauth1_authorizer_set_proxy_resolver (GDATA_OAUTH1_AUTHORIZER (object), g_value_get_object (value));
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
default:
|
|
Packit |
4b6dd7 |
/* We don't have any other property... */
|
|
Packit |
4b6dd7 |
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
Packit |
4b6dd7 |
break;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
process_request (GDataAuthorizer *self, GDataAuthorizationDomain *domain, SoupMessage *message)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataOAuth1AuthorizerPrivate *priv = GDATA_OAUTH1_AUTHORIZER (self)->priv;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Set the authorisation header */
|
|
Packit |
4b6dd7 |
g_mutex_lock (&(priv->mutex));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Sanity check */
|
|
Packit |
4b6dd7 |
g_assert ((priv->token == NULL) == (priv->token_secret == NULL));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (priv->token != NULL && g_hash_table_lookup (priv->authorization_domains, domain) != NULL) {
|
|
Packit |
4b6dd7 |
sign_message (GDATA_OAUTH1_AUTHORIZER (self), message, priv->token, priv->token_secret, NULL);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_mutex_unlock (&(priv->mutex));
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static gboolean
|
|
Packit |
4b6dd7 |
is_authorized_for_domain (GDataAuthorizer *self, GDataAuthorizationDomain *domain)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataOAuth1AuthorizerPrivate *priv = GDATA_OAUTH1_AUTHORIZER (self)->priv;
|
|
Packit |
4b6dd7 |
gpointer result;
|
|
Packit |
4b6dd7 |
const gchar *token;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_mutex_lock (&(priv->mutex));
|
|
Packit |
4b6dd7 |
token = priv->token;
|
|
Packit |
4b6dd7 |
result = g_hash_table_lookup (priv->authorization_domains, domain);
|
|
Packit |
4b6dd7 |
g_mutex_unlock (&(priv->mutex));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Sanity check */
|
|
Packit |
4b6dd7 |
g_assert (result == NULL || result == domain);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return (token != NULL && result != NULL) ? TRUE : FALSE;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Sign the message and add the Authorization header to it containing the signature.
|
|
Packit |
4b6dd7 |
* NOTE: This must not lock priv->mutex, as it's called from within a critical section in process_request() and priv->mutex isn't recursive. */
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
sign_message (GDataOAuth1Authorizer *self, SoupMessage *message, const gchar *token, const gchar *token_secret, GHashTable *parameters)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GHashTableIter iter;
|
|
Packit |
4b6dd7 |
const gchar *key, *value, *consumer_key, *consumer_secret, *signature_method;
|
|
Packit |
4b6dd7 |
gsize params_length = 0;
|
|
Packit |
4b6dd7 |
GList *sorted_params = NULL, *i;
|
|
Packit |
4b6dd7 |
GString *query_string, *signature_base_string, *secret_string, *authorization_header;
|
|
Packit |
4b6dd7 |
SoupURI *normalised_uri;
|
|
Packit |
4b6dd7 |
gchar *uri, *signature, *timestamp;
|
|
Packit |
4b6dd7 |
char *nonce;
|
|
Packit |
4b6dd7 |
gboolean is_first = TRUE;
|
|
Packit |
4b6dd7 |
GTimeVal time_val;
|
|
Packit |
4b6dd7 |
guchar signature_buf[HMAC_SHA1_LEN];
|
|
Packit |
4b6dd7 |
gsize signature_buf_len;
|
|
Packit |
4b6dd7 |
GHmac *signature_hmac;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_return_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self));
|
|
Packit |
4b6dd7 |
g_return_if_fail (SOUP_IS_MESSAGE (message));
|
|
Packit |
4b6dd7 |
g_return_if_fail (token == NULL || *token != '\0');
|
|
Packit |
4b6dd7 |
g_return_if_fail (token_secret == NULL || *token_secret != '\0');
|
|
Packit |
4b6dd7 |
g_return_if_fail ((token == NULL) == (token_secret == NULL));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Build and return a HMAC-SHA1 signature for the given SoupMessage. We always use HMAC-SHA1, since installed applications have to be
|
|
Packit |
4b6dd7 |
* unregistered (see: http://code.google.com/apis/accounts/docs/OAuth_ref.html#SigningOAuth).
|
|
Packit |
4b6dd7 |
* Reference: http://tools.ietf.org/html/rfc5849#section-3.4 */
|
|
Packit |
4b6dd7 |
signature_method = "HMAC-SHA1";
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* As described here, we use an anonymous consumer key and secret, since we're designed for installed applications:
|
|
Packit |
4b6dd7 |
* http://code.google.com/apis/accounts/docs/OAuth_ref.html#SigningOAuth */
|
|
Packit |
4b6dd7 |
consumer_key = "anonymous";
|
|
Packit |
4b6dd7 |
consumer_secret = "anonymous";
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Add various standard parameters to the list (note: this modifies the hash table belonging to the caller) */
|
|
Packit |
4b6dd7 |
nonce = oauth_gen_nonce ();
|
|
Packit |
4b6dd7 |
g_get_current_time (&time_val);
|
|
Packit |
4b6dd7 |
timestamp = g_strdup_printf ("%li", time_val.tv_sec);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (parameters == NULL) {
|
|
Packit |
4b6dd7 |
parameters = g_hash_table_new (g_str_hash, g_str_equal);
|
|
Packit |
4b6dd7 |
} else {
|
|
Packit |
4b6dd7 |
g_hash_table_ref (parameters);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_hash_table_insert (parameters, (gpointer) "oauth_signature_method", (gpointer) signature_method);
|
|
Packit |
4b6dd7 |
g_hash_table_insert (parameters, (gpointer) "oauth_consumer_key", (gpointer) consumer_key);
|
|
Packit |
4b6dd7 |
g_hash_table_insert (parameters, (gpointer) "oauth_nonce", nonce);
|
|
Packit |
4b6dd7 |
g_hash_table_insert (parameters, (gpointer) "oauth_timestamp", timestamp);
|
|
Packit |
4b6dd7 |
g_hash_table_insert (parameters, (gpointer) "oauth_version", (gpointer) "1.0");
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Only add the token if it's been provided */
|
|
Packit |
4b6dd7 |
if (token != NULL) {
|
|
Packit |
4b6dd7 |
g_hash_table_insert (parameters, (gpointer) "oauth_token", (gpointer) token);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Sort the parameters and build a query string, as defined here: http://tools.ietf.org/html/rfc5849#section-3.4.1.3 */
|
|
Packit |
4b6dd7 |
g_hash_table_iter_init (&iter, parameters);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
while (g_hash_table_iter_next (&iter, (gpointer*) &key, (gpointer*) &value) == TRUE) {
|
|
Packit |
4b6dd7 |
GString *pair = g_string_new (NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_string_append_uri_escaped (pair, key, NULL, FALSE);
|
|
Packit |
4b6dd7 |
g_string_append_c (pair, '=');
|
|
Packit |
4b6dd7 |
g_string_append_uri_escaped (pair, value, NULL, FALSE);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Append the pair to the list for sorting, and keep track of the total length of the strings in the list so far */
|
|
Packit |
4b6dd7 |
params_length += pair->len + 1 /* sep */;
|
|
Packit |
4b6dd7 |
sorted_params = g_list_prepend (sorted_params, g_string_free (pair, FALSE));
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_hash_table_unref (parameters);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
sorted_params = g_list_sort (sorted_params, (GCompareFunc) g_strcmp0);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Concatenate the parameters to give the query string */
|
|
Packit |
4b6dd7 |
query_string = g_string_sized_new (params_length);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
for (i = sorted_params; i != NULL; i = i->next) {
|
|
Packit |
4b6dd7 |
if (is_first == FALSE) {
|
|
Packit |
4b6dd7 |
g_string_append_c (query_string, '&';;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_string_append (query_string, i->data);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_free (i->data);
|
|
Packit |
4b6dd7 |
is_first = FALSE;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_list_free (sorted_params);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Normalise the URI as described here: http://tools.ietf.org/html/rfc5849#section-3.4.1.2 */
|
|
Packit |
4b6dd7 |
normalised_uri = soup_uri_copy (soup_message_get_uri (message));
|
|
Packit |
4b6dd7 |
soup_uri_set_query (normalised_uri, NULL);
|
|
Packit |
4b6dd7 |
soup_uri_set_fragment (normalised_uri, NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Append it to the signature base string */
|
|
Packit |
4b6dd7 |
uri = soup_uri_to_string (normalised_uri, FALSE);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Start building the signature base string as described here: http://tools.ietf.org/html/rfc5849#section-3.4.1.1 */
|
|
Packit |
4b6dd7 |
signature_base_string = g_string_sized_new (4 /* method */ + 1 /* sep */ + strlen (uri) + 1 /* sep */ + params_length /* query string */);
|
|
Packit |
4b6dd7 |
g_string_append_uri_escaped (signature_base_string, message->method, NULL, FALSE);
|
|
Packit |
4b6dd7 |
g_string_append_c (signature_base_string, '&';;
|
|
Packit |
4b6dd7 |
g_string_append_uri_escaped (signature_base_string, uri, NULL, FALSE);
|
|
Packit |
4b6dd7 |
g_string_append_c (signature_base_string, '&';;
|
|
Packit |
4b6dd7 |
g_string_append_uri_escaped (signature_base_string, query_string->str, NULL, FALSE);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_free (uri);
|
|
Packit |
4b6dd7 |
soup_uri_free (normalised_uri);
|
|
Packit |
4b6dd7 |
g_string_free (query_string, TRUE);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Build the secret key to use in the HMAC */
|
|
Packit |
4b6dd7 |
secret_string = g_string_new (NULL);
|
|
Packit |
4b6dd7 |
g_string_append_uri_escaped (secret_string, consumer_secret, NULL, FALSE);
|
|
Packit |
4b6dd7 |
g_string_append_c (secret_string, '&';;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Only add token_secret if it was provided */
|
|
Packit |
4b6dd7 |
if (token_secret != NULL) {
|
|
Packit |
4b6dd7 |
g_string_append_uri_escaped (secret_string, token_secret, NULL, FALSE);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Create the signature as described here: http://tools.ietf.org/html/rfc5849#section-3.4.2 */
|
|
Packit |
4b6dd7 |
signature_hmac = g_hmac_new (G_CHECKSUM_SHA1, (const guchar*) secret_string->str, secret_string->len);
|
|
Packit |
4b6dd7 |
g_hmac_update (signature_hmac, (const guchar*) signature_base_string->str, signature_base_string->len);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
signature_buf_len = G_N_ELEMENTS (signature_buf);
|
|
Packit |
4b6dd7 |
g_hmac_get_digest (signature_hmac, signature_buf, &signature_buf_len);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_hmac_unref (signature_hmac);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
signature = g_base64_encode (signature_buf, signature_buf_len);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/*g_debug ("Signing message using Signature Base String: “%s” and key “%s” using method “%s” to give signature: “%s”.",
|
|
Packit |
4b6dd7 |
signature_base_string->str, secret_string->str, signature_method, signature);*/
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Zero out the secret_string before freeing it, to reduce the chance of secrets hitting disk. */
|
|
Packit |
4b6dd7 |
memset (secret_string->str, 0, secret_string->allocated_len);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_string_free (secret_string, TRUE);
|
|
Packit |
4b6dd7 |
g_string_free (signature_base_string, TRUE);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Build the Authorization header and append it to the message */
|
|
Packit |
4b6dd7 |
authorization_header = g_string_new ("OAuth oauth_consumer_key=\"");
|
|
Packit |
4b6dd7 |
g_string_append_uri_escaped (authorization_header, consumer_key, NULL, FALSE);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Only add the token if it's been provided */
|
|
Packit |
4b6dd7 |
if (token != NULL) {
|
|
Packit |
4b6dd7 |
g_string_append (authorization_header, "\",oauth_token=\"");
|
|
Packit |
4b6dd7 |
g_string_append_uri_escaped (authorization_header, token, NULL, FALSE);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_string_append (authorization_header, "\",oauth_signature_method=\"");
|
|
Packit |
4b6dd7 |
g_string_append_uri_escaped (authorization_header, signature_method, NULL, FALSE);
|
|
Packit |
4b6dd7 |
g_string_append (authorization_header, "\",oauth_signature=\"");
|
|
Packit |
4b6dd7 |
g_string_append_uri_escaped (authorization_header, signature, NULL, FALSE);
|
|
Packit |
4b6dd7 |
g_string_append (authorization_header, "\",oauth_timestamp=\"");
|
|
Packit |
4b6dd7 |
g_string_append_uri_escaped (authorization_header, timestamp, NULL, FALSE);
|
|
Packit |
4b6dd7 |
g_string_append (authorization_header, "\",oauth_nonce=\"");
|
|
Packit |
4b6dd7 |
g_string_append_uri_escaped (authorization_header, nonce, NULL, FALSE);
|
|
Packit |
4b6dd7 |
g_string_append (authorization_header, "\",oauth_version=\"1.0\"");
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
soup_message_headers_replace (message->request_headers, "Authorization", authorization_header->str);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_string_free (authorization_header, TRUE);
|
|
Packit |
4b6dd7 |
free (signature);
|
|
Packit |
4b6dd7 |
g_free (timestamp);
|
|
Packit |
4b6dd7 |
free (nonce);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_new:
|
|
Packit |
4b6dd7 |
* @application_name: (allow-none): a human-readable, translated application name to use on authentication pages, or %NULL
|
|
Packit |
4b6dd7 |
* @service_type: the #GType of a #GDataService subclass which the #GDataOAuth1Authorizer will be used with
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Creates a new #GDataOAuth1Authorizer.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* The #GDataAuthorizationDomains for the given @service_type (i.e. as returned by gdata_service_get_authorization_domains()) are the ones the
|
|
Packit |
4b6dd7 |
* user will be requested to authorize access to on the page at the URI returned by gdata_oauth1_authorizer_request_authentication_uri().
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* The given @application_name will set the value of #GDataOAuth1Authorizer:application-name and will be displayed to the user on authentication pages
|
|
Packit |
4b6dd7 |
* returned by Google. If %NULL is provided, the value of g_get_application_name() will be used as a fallback.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: (transfer full): a new #GDataOAuth1Authorizer; unref with g_object_unref()
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
GDataOAuth1Authorizer *
|
|
Packit |
4b6dd7 |
gdata_oauth1_authorizer_new (const gchar *application_name, GType service_type)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (g_type_is_a (service_type, GDATA_TYPE_SERVICE), NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return gdata_oauth1_authorizer_new_for_authorization_domains (application_name, gdata_service_get_authorization_domains (service_type));
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_new_for_authorization_domains:
|
|
Packit |
4b6dd7 |
* @application_name: (allow-none): a human-readable, translated application name to use on authentication pages, or %NULL
|
|
Packit |
4b6dd7 |
* @authorization_domains: (element-type GDataAuthorizationDomain) (transfer none): a non-empty list of #GDataAuthorizationDomains to be
|
|
Packit |
4b6dd7 |
* authorized against by the #GDataOAuth1Authorizer
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Creates a new #GDataOAuth1Authorizer. This function is intended to be used only when the default authorization domain list for a single
|
|
Packit |
4b6dd7 |
* #GDataService, as used by gdata_oauth1_authorizer_new(), isn't suitable. For example, this could be because the #GDataOAuth1Authorizer will be used
|
|
Packit |
4b6dd7 |
* with multiple #GDataService subclasses, or because the client requires a specific set of authorization domains.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* The specified #GDataAuthorizationDomains are the ones the user will be requested to authorize access to on the page at the URI returned by
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_request_authentication_uri().
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* The given @application_name will set the value of #GDataOAuth1Authorizer:application-name and will be displayed to the user on authentication pages
|
|
Packit |
4b6dd7 |
* returned by Google. If %NULL is provided, the value of g_get_application_name() will be used as a fallback.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: (transfer full): a new #GDataOAuth1Authorizer; unref with g_object_unref()
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
GDataOAuth1Authorizer *
|
|
Packit |
4b6dd7 |
gdata_oauth1_authorizer_new_for_authorization_domains (const gchar *application_name, GList *authorization_domains)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GList *i;
|
|
Packit |
4b6dd7 |
GDataOAuth1Authorizer *authorizer;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (authorization_domains != NULL, NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
authorizer = GDATA_OAUTH1_AUTHORIZER (g_object_new (GDATA_TYPE_OAUTH1_AUTHORIZER,
|
|
Packit |
4b6dd7 |
"application-name", application_name,
|
|
Packit |
4b6dd7 |
NULL));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Register all the domains with the authorizer */
|
|
Packit |
4b6dd7 |
for (i = authorization_domains; i != NULL; i = i->next) {
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_AUTHORIZATION_DOMAIN (i->data), NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* We don't have to lock the authoriser's mutex here as no other code has seen the authoriser yet */
|
|
Packit |
4b6dd7 |
g_hash_table_insert (authorizer->priv->authorization_domains, g_object_ref (GDATA_AUTHORIZATION_DOMAIN (i->data)), i->data);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return authorizer;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_request_authentication_uri:
|
|
Packit |
4b6dd7 |
* @self: a #GDataOAuth1Authorizer
|
|
Packit |
4b6dd7 |
* @token: (out callee-allocates): return location for the temporary credentials token returned by the authentication service; free with g_free()
|
|
Packit |
4b6dd7 |
* @token_secret: (out callee-allocates): return location for the temporary credentials token secret returned by the authentication service; free with
|
|
Packit |
4b6dd7 |
* g_free()
|
|
Packit |
4b6dd7 |
* @cancellable: (allow-none): optional #GCancellable object, or %NULL
|
|
Packit |
4b6dd7 |
* @error: a #GError, or %NULL
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Requests a fresh unauthenticated token from the Google accounts service and builds and returns the URI of an authentication page for that token.
|
|
Packit |
4b6dd7 |
* This should then be presented to the user (e.g. in an embedded or stand alone web browser). The authentication page will ask the user to log in
|
|
Packit |
4b6dd7 |
* using their Google account, then ask them to grant access to the #GDataAuthorizationDomains passed to the constructor of the
|
|
Packit |
4b6dd7 |
* #GDataOAuth1Authorizer. If the user grants access, they will be given a verifier, which can then be passed to
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_request_authorization() (along with the @token and @token_secret values returned by this method) to authorize the token.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* This method can fail if the server returns an error, but this is unlikely. If it does happen, a %GDATA_SERVICE_ERROR_PROTOCOL_ERROR will be
|
|
Packit |
4b6dd7 |
* raised, @token and @token_secret will be set to %NULL and %NULL will be returned.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* This method implements <ulink type="http" url="http://tools.ietf.org/html/rfc5849#section-2.1">Section 2.1</ulink> and
|
|
Packit |
4b6dd7 |
* <ulink type="http" url="http://tools.ietf.org/html/rfc5849#section-2.2">Section 2.2</ulink> of the
|
|
Packit |
4b6dd7 |
* <ulink type="http" url="http://tools.ietf.org/html/rfc5849">OAuth 1.0 protocol</ulink>.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* When freeing @token_secret, it's advisable to set it to all zeros first, to reduce the chance of the sensitive token being recoverable from the
|
|
Packit |
4b6dd7 |
* free memory pool and (accidentally) leaked by a different part of the process. This can be achieved with the following code:
|
|
Packit |
4b6dd7 |
* |[
|
|
Packit |
4b6dd7 |
* if (token_secret != NULL) {
|
|
Packit |
4b6dd7 |
* memset (token_secret, 0, strlen (token_secret));
|
|
Packit |
4b6dd7 |
* g_free (token_secret);
|
|
Packit |
4b6dd7 |
* }
|
|
Packit |
4b6dd7 |
* ]|
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: (transfer full): the URI of an authentication page for the user to use; free with g_free()
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
gchar *
|
|
Packit |
4b6dd7 |
gdata_oauth1_authorizer_request_authentication_uri (GDataOAuth1Authorizer *self, gchar **token, gchar **token_secret,
|
|
Packit |
4b6dd7 |
GCancellable *cancellable, GError **error)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataOAuth1AuthorizerPrivate *priv;
|
|
Packit |
4b6dd7 |
SoupMessage *message;
|
|
Packit |
4b6dd7 |
guint status;
|
|
Packit |
4b6dd7 |
gchar *request_body;
|
|
Packit |
4b6dd7 |
GString *scope_string, *authentication_uri;
|
|
Packit |
4b6dd7 |
GHashTable *parameters;
|
|
Packit |
4b6dd7 |
GHashTableIter iter;
|
|
Packit |
4b6dd7 |
gboolean is_first = TRUE;
|
|
Packit |
4b6dd7 |
GDataAuthorizationDomain *domain;
|
|
Packit |
4b6dd7 |
GHashTable *response_details;
|
|
Packit |
4b6dd7 |
const gchar *callback_uri, *_token, *_token_secret, *callback_confirmed;
|
|
Packit |
4b6dd7 |
SoupURI *_uri;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self), NULL);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (token != NULL, NULL);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (token_secret != NULL, NULL);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
priv = self->priv;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* This implements OAuthGetRequestToken and returns the URI for OAuthAuthorizeToken, which the client must then use themselves (e.g. in an
|
|
Packit |
4b6dd7 |
* embedded web browser) to authorise the temporary credentials token. They then pass the request token and verification code they get back
|
|
Packit |
4b6dd7 |
* from that to gdata_oauth1_authorizer_request_authorization(). */
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* We default to out-of-band callbacks */
|
|
Packit |
4b6dd7 |
callback_uri = "oob";
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Set the output parameters to NULL in case of failure */
|
|
Packit |
4b6dd7 |
*token = NULL;
|
|
Packit |
4b6dd7 |
*token_secret = NULL;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Build up the space-separated list of scopes we're requesting authorisation for */
|
|
Packit |
4b6dd7 |
g_mutex_lock (&(priv->mutex));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
scope_string = g_string_new (NULL);
|
|
Packit |
4b6dd7 |
g_hash_table_iter_init (&iter, priv->authorization_domains);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
while (g_hash_table_iter_next (&iter, (gpointer*) &domain, NULL) == TRUE) {
|
|
Packit |
4b6dd7 |
if (is_first == FALSE) {
|
|
Packit |
4b6dd7 |
/* Delimiter */
|
|
Packit |
4b6dd7 |
g_string_append_c (scope_string, ' ');
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_string_append (scope_string, gdata_authorization_domain_get_scope (domain));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
is_first = FALSE;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_mutex_unlock (&(priv->mutex));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Build the request body and the set of parameters to be signed */
|
|
Packit |
4b6dd7 |
parameters = g_hash_table_new (g_str_hash, g_str_equal);
|
|
Packit |
4b6dd7 |
g_hash_table_insert (parameters, (gpointer) "scope", scope_string->str);
|
|
Packit |
4b6dd7 |
g_hash_table_insert (parameters, (gpointer) "xoauth_displayname", priv->application_name);
|
|
Packit |
4b6dd7 |
g_hash_table_insert (parameters, (gpointer) "oauth_callback", (gpointer) callback_uri);
|
|
Packit |
4b6dd7 |
request_body = soup_form_encode_hash (parameters);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Build the message */
|
|
Packit |
4b6dd7 |
_uri = soup_uri_new ("https://www.google.com/accounts/OAuthGetRequestToken");
|
|
Packit |
4b6dd7 |
soup_uri_set_port (_uri, _gdata_service_get_https_port ());
|
|
Packit |
4b6dd7 |
message = soup_message_new_from_uri (SOUP_METHOD_POST, _uri);
|
|
Packit |
4b6dd7 |
soup_uri_free (_uri);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
soup_message_set_request (message, "application/x-www-form-urlencoded", SOUP_MEMORY_TAKE, request_body, strlen (request_body));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
sign_message (self, message, NULL, NULL, parameters);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_hash_table_destroy (parameters);
|
|
Packit |
4b6dd7 |
g_string_free (scope_string, TRUE);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Send the message */
|
|
Packit |
4b6dd7 |
_gdata_service_actually_send_message (priv->session, message, cancellable, error);
|
|
Packit |
4b6dd7 |
status = message->status_code;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (status == SOUP_STATUS_CANCELLED) {
|
|
Packit |
4b6dd7 |
/* Cancelled (the error has already been set) */
|
|
Packit |
4b6dd7 |
g_object_unref (message);
|
|
Packit |
4b6dd7 |
return NULL;
|
|
Packit |
4b6dd7 |
} else if (status != SOUP_STATUS_OK) {
|
|
Packit |
4b6dd7 |
/* Server returned an error. Not much we can do, since the error codes aren't documented and it shouldn't normally ever happen
|
|
Packit |
4b6dd7 |
* anyway. */
|
|
Packit |
4b6dd7 |
g_set_error_literal (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR,
|
|
Packit |
4b6dd7 |
_("The server rejected the temporary credentials request."));
|
|
Packit |
4b6dd7 |
g_object_unref (message);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return NULL;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_assert (message->response_body->data != NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Parse the response. We expect something like:
|
|
Packit |
4b6dd7 |
* oauth_token=ab3cd9j4ks73hf7g&oauth_token_secret=ZXhhbXBsZS5jb20&oauth_callback_confirmed=true
|
|
Packit |
4b6dd7 |
* See: http://code.google.com/apis/accounts/docs/OAuth_ref.html#RequestToken and
|
|
Packit |
4b6dd7 |
* http://tools.ietf.org/html/rfc5849#section-2.1 for details. */
|
|
Packit |
4b6dd7 |
response_details = soup_form_decode (message->response_body->data);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_object_unref (message);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
_token = g_hash_table_lookup (response_details, "oauth_token");
|
|
Packit |
4b6dd7 |
_token_secret = g_hash_table_lookup (response_details, "oauth_token_secret");
|
|
Packit |
4b6dd7 |
callback_confirmed = g_hash_table_lookup (response_details, "oauth_callback_confirmed");
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Validate the returned values */
|
|
Packit |
4b6dd7 |
if (_token == NULL || _token_secret == NULL || callback_confirmed == NULL ||
|
|
Packit |
4b6dd7 |
*_token == '\0' || *_token_secret == '\0' ||
|
|
Packit |
4b6dd7 |
strcmp (callback_confirmed, "true") != 0) {
|
|
Packit |
4b6dd7 |
g_set_error_literal (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR,
|
|
Packit |
4b6dd7 |
_("The server returned a malformed response."));
|
|
Packit |
4b6dd7 |
g_hash_table_destroy (response_details);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return NULL;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Build the authentication URI which the user will then open in a web browser and use to authenticate and authorise our application.
|
|
Packit |
4b6dd7 |
* We expect to build something like this:
|
|
Packit |
4b6dd7 |
* https://www.google.com/accounts/OAuthAuthorizeToken?oauth_token=ab3cd9j4ks73hf7g&hd=mycollege.edu&hl=en&btmpl=mobile
|
|
Packit |
4b6dd7 |
* See: http://code.google.com/apis/accounts/docs/OAuth_ref.html#GetAuth for more details. */
|
|
Packit |
4b6dd7 |
authentication_uri = g_string_new ("https://www.google.com/accounts/OAuthAuthorizeToken?oauth_token=");
|
|
Packit |
4b6dd7 |
g_string_append_uri_escaped (authentication_uri, g_hash_table_lookup (response_details, "oauth_token"), NULL, TRUE);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (priv->locale != NULL) {
|
|
Packit |
4b6dd7 |
g_string_append (authentication_uri, "&hl=");
|
|
Packit |
4b6dd7 |
g_string_append_uri_escaped (authentication_uri, priv->locale, NULL, TRUE);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Return the token and token secret */
|
|
Packit |
4b6dd7 |
*token = g_strdup (_token);
|
|
Packit |
4b6dd7 |
*token_secret = g_strdup (_token_secret); /* NOTE: Ideally this would be allocated in non-pageable memory, but changing that would break API */
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_hash_table_destroy (response_details);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return g_string_free (authentication_uri, FALSE);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
typedef struct {
|
|
Packit |
4b6dd7 |
/* All return values */
|
|
Packit |
4b6dd7 |
gchar *token;
|
|
Packit |
4b6dd7 |
gchar *token_secret; /* NOTE: Ideally this would be allocated in non-pageable memory, but changing that would break API */
|
|
Packit |
4b6dd7 |
gchar *authentication_uri;
|
|
Packit |
4b6dd7 |
} RequestAuthenticationUriAsyncData;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
request_authentication_uri_async_data_free (RequestAuthenticationUriAsyncData *data)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_free (data->token);
|
|
Packit |
4b6dd7 |
g_free (data->token_secret);
|
|
Packit |
4b6dd7 |
g_free (data->authentication_uri);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_slice_free (RequestAuthenticationUriAsyncData, data);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
G_DEFINE_AUTOPTR_CLEANUP_FUNC (RequestAuthenticationUriAsyncData, request_authentication_uri_async_data_free)
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
request_authentication_uri_thread (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataOAuth1Authorizer *authorizer = GDATA_OAUTH1_AUTHORIZER (source_object);
|
|
Packit |
4b6dd7 |
g_autoptr(RequestAuthenticationUriAsyncData) data = NULL;
|
|
Packit |
4b6dd7 |
g_autoptr(GError) error = NULL;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
data = g_slice_new0 (RequestAuthenticationUriAsyncData);
|
|
Packit |
4b6dd7 |
data->authentication_uri = gdata_oauth1_authorizer_request_authentication_uri (authorizer, &(data->token), &(data->token_secret),
|
|
Packit |
4b6dd7 |
cancellable, &error);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (error != NULL)
|
|
Packit |
4b6dd7 |
g_task_return_error (task, g_steal_pointer (&error));
|
|
Packit |
4b6dd7 |
else
|
|
Packit |
4b6dd7 |
g_task_return_pointer (task, g_steal_pointer (&data), (GDestroyNotify) request_authentication_uri_async_data_free);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_request_authentication_uri_async:
|
|
Packit |
4b6dd7 |
* @self: a #GDataOAuth1Authorizer
|
|
Packit |
4b6dd7 |
* @cancellable: (allow-none): optional #GCancellable object, or %NULL
|
|
Packit |
4b6dd7 |
* @callback: a #GAsyncReadyCallback to call when building the URI is finished
|
|
Packit |
4b6dd7 |
* @user_data: (closure): data to pass to the @callback function
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Requests a fresh unauthenticated token from the Google accounts service and builds and returns the URI of an authentication page for that token.
|
|
Packit |
4b6dd7 |
* @self is reffed when this method is called, so can safely be unreffed after this method returns.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* For more details, see gdata_oauth1_authorizer_request_authentication_uri(), which is the synchronous version of this method.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* When the operation is finished, @callback will be called. You can then call gdata_oauth1_authorizer_request_authentication_uri_finish() to get the
|
|
Packit |
4b6dd7 |
* results of the operation.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
void
|
|
Packit |
4b6dd7 |
gdata_oauth1_authorizer_request_authentication_uri_async (GDataOAuth1Authorizer *self, GCancellable *cancellable,
|
|
Packit |
4b6dd7 |
GAsyncReadyCallback callback, gpointer user_data)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_autoptr(GTask) task = NULL;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_return_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self));
|
|
Packit |
4b6dd7 |
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
|
|
Packit |
4b6dd7 |
g_return_if_fail (callback != NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
task = g_task_new (self, cancellable, callback, user_data);
|
|
Packit |
4b6dd7 |
g_task_set_source_tag (task, gdata_oauth1_authorizer_request_authentication_uri_async);
|
|
Packit |
4b6dd7 |
g_task_run_in_thread (task, request_authentication_uri_thread);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_request_authentication_uri_finish:
|
|
Packit |
4b6dd7 |
* @self: a #GDataOAuth1Authorizer
|
|
Packit |
4b6dd7 |
* @async_result: a #GAsyncResult
|
|
Packit |
4b6dd7 |
* @token: (out callee-allocates): return location for the temporary credentials token returned by the authentication service; free with g_free()
|
|
Packit |
4b6dd7 |
* @token_secret: (out callee-allocates): return location for the temporary credentials token secret returned by the authentication service; free with
|
|
Packit |
4b6dd7 |
* g_free()
|
|
Packit |
4b6dd7 |
* @error: a #GError, or %NULL
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Finishes an asynchronous authentication URI building operation started with gdata_oauth1_authorizer_request_authentication_uri_async().
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* This method can fail if the server has returned an error, but this is unlikely. If it does happen, a %GDATA_SERVICE_ERROR_PROTOCOL_ERROR will be
|
|
Packit |
4b6dd7 |
* raised, @token and @token_secret will be set to %NULL and %NULL will be returned.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* When freeing @token_secret, it's advisable to set it to all zeros first, to reduce the chance of the sensitive token being recoverable from the
|
|
Packit |
4b6dd7 |
* free memory pool and (accidentally) leaked by a different part of the process. This can be achieved with the following code:
|
|
Packit |
4b6dd7 |
* |[
|
|
Packit |
4b6dd7 |
* if (token_secret != NULL) {
|
|
Packit |
4b6dd7 |
* memset (token_secret, 0, strlen (token_secret));
|
|
Packit |
4b6dd7 |
* g_free (token_secret);
|
|
Packit |
4b6dd7 |
* }
|
|
Packit |
4b6dd7 |
* ]|
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: (transfer full): the URI of an authentication page for the user to use; free with g_free()
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
gchar *
|
|
Packit |
4b6dd7 |
gdata_oauth1_authorizer_request_authentication_uri_finish (GDataOAuth1Authorizer *self, GAsyncResult *async_result, gchar **token,
|
|
Packit |
4b6dd7 |
gchar **token_secret, GError **error)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_autoptr(RequestAuthenticationUriAsyncData) data = NULL;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self), NULL);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (G_IS_ASYNC_RESULT (async_result), NULL);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (token != NULL, NULL);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (token_secret != NULL, NULL);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (g_task_is_valid (async_result, self), NULL);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (g_async_result_is_tagged (async_result, gdata_oauth1_authorizer_request_authentication_uri_async), NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
data = g_task_propagate_pointer (G_TASK (async_result), error);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (data == NULL) {
|
|
Packit |
4b6dd7 |
/* Return the error and set all of the output parameters to NULL */
|
|
Packit |
4b6dd7 |
*token = NULL;
|
|
Packit |
4b6dd7 |
*token_secret = NULL;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return NULL;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Success! Transfer the output to the appropriate parameters and nullify it so it doesn't get freed when the async result gets finalised */
|
|
Packit |
4b6dd7 |
*token = g_steal_pointer (&data->token);
|
|
Packit |
4b6dd7 |
*token_secret = g_steal_pointer (&data->token_secret);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return g_steal_pointer (&data->authentication_uri);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_request_authorization:
|
|
Packit |
4b6dd7 |
* @self: a #GDataOAuth1Authorizer
|
|
Packit |
4b6dd7 |
* @token: the request token returned by gdata_oauth1_authorizer_request_authentication_uri()
|
|
Packit |
4b6dd7 |
* @token_secret: the request token secret returned by gdata_oauth1_authorizer_request_authentication_uri()
|
|
Packit |
4b6dd7 |
* @verifier: the verifier entered by the user from the authentication page
|
|
Packit |
4b6dd7 |
* @cancellable: (allow-none): optional #GCancellable object, or %NULL
|
|
Packit |
4b6dd7 |
* @error: a #GError, or %NULL
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Requests authorization of the given request @token from the Google accounts service using the given @verifier as entered by the user from the
|
|
Packit |
4b6dd7 |
* authentication page at the URI returned by gdata_oauth1_authorizer_request_authentication_uri(). @token and @token_secret must be the same values
|
|
Packit |
4b6dd7 |
* as were returned by gdata_oauth1_authorizer_request_authentication_uri() if it was successful.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* If the verifier is valid (i.e. the user granted access to the application and the Google accounts service has no reason to distrust the client),
|
|
Packit |
4b6dd7 |
* %TRUE will be returned and any operations performed from that point onwards on #GDataServices using this #GDataAuthorizer will be
|
|
Packit |
4b6dd7 |
* authorized.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* If the user denies access to the application or the Google accounts service distrusts it, a bogus verifier could be returned. In this case, %FALSE
|
|
Packit |
4b6dd7 |
* will be returned and a %GDATA_SERVICE_ERROR_FORBIDDEN error will be raised.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Note that if the user denies access to the application, it may be the case that they have no verifier to enter. In this case, the client can simply
|
|
Packit |
4b6dd7 |
* not call this method. The #GDataOAuth1Authorizer stores no state for authentication operations which have succeeded in calling
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_request_authentication_uri() but not yet successfully called gdata_oauth1_authorizer_request_authorization().
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* This method implements <ulink type="http" url="http://tools.ietf.org/html/rfc5849#section-2.3">Section 2.3</ulink> of the
|
|
Packit |
4b6dd7 |
* <ulink type="http" url="http://tools.ietf.org/html/rfc5849">OAuth 1.0 protocol</ulink>.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: %TRUE if authorization was successful, %FALSE otherwise
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
gboolean
|
|
Packit |
4b6dd7 |
gdata_oauth1_authorizer_request_authorization (GDataOAuth1Authorizer *self, const gchar *token, const gchar *token_secret, const gchar *verifier,
|
|
Packit |
4b6dd7 |
GCancellable *cancellable, GError **error)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataOAuth1AuthorizerPrivate *priv;
|
|
Packit |
4b6dd7 |
SoupMessage *message;
|
|
Packit |
4b6dd7 |
guint status;
|
|
Packit |
4b6dd7 |
gchar *request_body;
|
|
Packit |
4b6dd7 |
GHashTable *parameters;
|
|
Packit |
4b6dd7 |
GHashTable *response_details;
|
|
Packit |
4b6dd7 |
const gchar *_token, *_token_secret;
|
|
Packit |
4b6dd7 |
SoupURI *_uri;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self), FALSE);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (token != NULL && *token != '\0', FALSE);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (token_secret != NULL && *token_secret != '\0', FALSE);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (verifier != NULL && *verifier != '\0', FALSE);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* This implements OAuthGetAccessToken using the request token returned by OAuthGetRequestToken and the verification code returned by
|
|
Packit |
4b6dd7 |
* OAuthAuthorizeToken. See:
|
|
Packit |
4b6dd7 |
* • http://code.google.com/apis/accounts/docs/OAuth_ref.html#AccessToken
|
|
Packit |
4b6dd7 |
* • http://tools.ietf.org/html/rfc5849#section-2.3
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
priv = self->priv;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Build the request body and the set of parameters to be signed */
|
|
Packit |
4b6dd7 |
parameters = g_hash_table_new (g_str_hash, g_str_equal);
|
|
Packit |
4b6dd7 |
g_hash_table_insert (parameters, (gpointer) "oauth_verifier", (gpointer) verifier);
|
|
Packit |
4b6dd7 |
request_body = soup_form_encode_hash (parameters);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Build the message */
|
|
Packit |
4b6dd7 |
_uri = soup_uri_new ("https://www.google.com/accounts/OAuthGetAccessToken");
|
|
Packit |
4b6dd7 |
soup_uri_set_port (_uri, _gdata_service_get_https_port ());
|
|
Packit |
4b6dd7 |
message = soup_message_new_from_uri (SOUP_METHOD_POST, _uri);
|
|
Packit |
4b6dd7 |
soup_uri_free (_uri);
|
|
Packit |
4b6dd7 |
soup_message_set_request (message, "application/x-www-form-urlencoded", SOUP_MEMORY_TAKE, request_body, strlen (request_body));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
sign_message (self, message, token, token_secret, parameters);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_hash_table_destroy (parameters);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Send the message */
|
|
Packit |
4b6dd7 |
_gdata_service_actually_send_message (priv->session, message, cancellable, error);
|
|
Packit |
4b6dd7 |
status = message->status_code;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (status == SOUP_STATUS_CANCELLED) {
|
|
Packit |
4b6dd7 |
/* Cancelled (the error has already been set) */
|
|
Packit |
4b6dd7 |
g_object_unref (message);
|
|
Packit |
4b6dd7 |
return FALSE;
|
|
Packit |
4b6dd7 |
} else if (status != SOUP_STATUS_OK) {
|
|
Packit |
4b6dd7 |
/* Server returned an error. This either means that there was a server error or, more likely, the server doesn't trust the client
|
|
Packit |
4b6dd7 |
* or the user denied authorization to the token on the authorization web page. */
|
|
Packit |
4b6dd7 |
g_set_error_literal (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_FORBIDDEN, _("Access was denied by the user or server."));
|
|
Packit |
4b6dd7 |
g_object_unref (message);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return FALSE;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_assert (message->response_body->data != NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Parse the response. We expect something like:
|
|
Packit |
4b6dd7 |
* oauth_token=ab3cd9j4ks73hf7g&oauth_token_secret=ZXhhbXBsZS5jb20&oauth_callback_confirmed=true
|
|
Packit |
4b6dd7 |
* See: http://code.google.com/apis/accounts/docs/OAuth_ref.html#AccessToken and
|
|
Packit |
4b6dd7 |
* http://tools.ietf.org/html/rfc5849#section-2.3 for details. */
|
|
Packit |
4b6dd7 |
response_details = soup_form_decode (message->response_body->data);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Zero out the response body to lower the chance of it (with all the auth. tokens it contains) hitting disk or getting leaked in
|
|
Packit |
4b6dd7 |
* free memory. */
|
|
Packit |
4b6dd7 |
memset ((void*) message->response_body->data, 0, message->response_body->length);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_object_unref (message);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
_token = g_hash_table_lookup (response_details, "oauth_token");
|
|
Packit |
4b6dd7 |
_token_secret = g_hash_table_lookup (response_details, "oauth_token_secret");
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Validate the returned values */
|
|
Packit |
4b6dd7 |
if (_token == NULL || _token_secret == NULL ||
|
|
Packit |
4b6dd7 |
*_token == '\0' || *_token_secret == '\0') {
|
|
Packit |
4b6dd7 |
g_set_error_literal (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR, _("The server returned a malformed response."));
|
|
Packit |
4b6dd7 |
g_hash_table_destroy (response_details);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return FALSE;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Store the token and token secret in the authoriser */
|
|
Packit |
4b6dd7 |
g_mutex_lock (&(priv->mutex));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_free (priv->token);
|
|
Packit |
4b6dd7 |
priv->token = g_strdup (_token);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
_gdata_service_secure_strfree (priv->token_secret);
|
|
Packit |
4b6dd7 |
priv->token_secret = _gdata_service_secure_strdup (_token_secret);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_mutex_unlock (&(priv->mutex));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Zero out the secret token before freeing the hash table, to reduce the chance of it hitting disk later. */
|
|
Packit |
4b6dd7 |
memset ((void*) _token_secret, 0, strlen (_token_secret));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_hash_table_destroy (response_details);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return TRUE;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
typedef struct {
|
|
Packit |
4b6dd7 |
/* Input */
|
|
Packit |
4b6dd7 |
gchar *token;
|
|
Packit |
4b6dd7 |
GDataSecureString token_secret; /* must be allocated by _gdata_service_secure_strdup() */
|
|
Packit |
4b6dd7 |
gchar *verifier;
|
|
Packit |
4b6dd7 |
} RequestAuthorizationAsyncData;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
request_authorization_async_data_free (RequestAuthorizationAsyncData *data)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_free (data->token);
|
|
Packit |
4b6dd7 |
_gdata_service_secure_strfree (data->token_secret);
|
|
Packit |
4b6dd7 |
g_free (data->verifier);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_slice_free (RequestAuthorizationAsyncData, data);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
request_authorization_thread (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
GDataOAuth1Authorizer *authorizer = GDATA_OAUTH1_AUTHORIZER (source_object);
|
|
Packit |
4b6dd7 |
RequestAuthorizationAsyncData *data = task_data;
|
|
Packit |
4b6dd7 |
g_autoptr(GError) error = NULL;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (!gdata_oauth1_authorizer_request_authorization (authorizer, data->token, data->token_secret, data->verifier, cancellable, &error))
|
|
Packit |
4b6dd7 |
g_task_return_error (task, g_steal_pointer (&error));
|
|
Packit |
4b6dd7 |
else
|
|
Packit |
4b6dd7 |
g_task_return_boolean (task, TRUE);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_request_authorization_async:
|
|
Packit |
4b6dd7 |
* @self: a #GDataOAuth1Authorizer
|
|
Packit |
4b6dd7 |
* @token: the request token returned by gdata_oauth1_authorizer_request_authentication_uri()
|
|
Packit |
4b6dd7 |
* @token_secret: the request token secret returned by gdata_oauth1_authorizer_request_authentication_uri()
|
|
Packit |
4b6dd7 |
* @verifier: the verifier entered by the user from the authentication page
|
|
Packit |
4b6dd7 |
* @cancellable: (allow-none): an optional #GCancellable, or %NULL
|
|
Packit |
4b6dd7 |
* @callback: a #GAsyncReadyCallback to call when authorization is finished
|
|
Packit |
4b6dd7 |
* @user_data: (closure): data to pass to the @callback function
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Requests authorization of the given request @token from the Google accounts service using the given @verifier as entered by the user.
|
|
Packit |
4b6dd7 |
* @self, @token, @token_secret and @verifier are reffed/copied when this method is called, so can safely be freed after this method returns.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* For more details, see gdata_oauth1_authorizer_request_authorization(), which is the synchronous version of this method.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* When the operation is finished, @callback will be called. You can then call gdata_oauth1_authorizer_request_authorization_finish() to get the
|
|
Packit |
4b6dd7 |
* results of the operation.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
void
|
|
Packit |
4b6dd7 |
gdata_oauth1_authorizer_request_authorization_async (GDataOAuth1Authorizer *self, const gchar *token, const gchar *token_secret,
|
|
Packit |
4b6dd7 |
const gchar *verifier,
|
|
Packit |
4b6dd7 |
GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_autoptr(GTask) task = NULL;
|
|
Packit |
4b6dd7 |
RequestAuthorizationAsyncData *data;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_return_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self));
|
|
Packit |
4b6dd7 |
g_return_if_fail (token != NULL && *token != '\0');
|
|
Packit |
4b6dd7 |
g_return_if_fail (token_secret != NULL && *token_secret != '\0');
|
|
Packit |
4b6dd7 |
g_return_if_fail (verifier != NULL && *verifier != '\0');
|
|
Packit |
4b6dd7 |
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
data = g_slice_new (RequestAuthorizationAsyncData);
|
|
Packit |
4b6dd7 |
data->token = g_strdup (token);
|
|
Packit |
4b6dd7 |
data->token_secret = _gdata_service_secure_strdup (token_secret);
|
|
Packit |
4b6dd7 |
data->verifier = g_strdup (verifier);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
task = g_task_new (self, cancellable, callback, user_data);
|
|
Packit |
4b6dd7 |
g_task_set_source_tag (task, gdata_oauth1_authorizer_request_authorization_async);
|
|
Packit |
4b6dd7 |
g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) request_authorization_async_data_free);
|
|
Packit |
4b6dd7 |
g_task_run_in_thread (task, request_authorization_thread);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_request_authorization_finish:
|
|
Packit |
4b6dd7 |
* @self: a #GDataOAuth1Authorizer
|
|
Packit |
4b6dd7 |
* @async_result: a #GAsyncResult
|
|
Packit |
4b6dd7 |
* @error: a #GError, or %NULL
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Finishes an asynchronous authorization operation started with gdata_oauth1_authorizer_request_authorization_async().
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: %TRUE if authorization was successful, %FALSE otherwise
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
gboolean
|
|
Packit |
4b6dd7 |
gdata_oauth1_authorizer_request_authorization_finish (GDataOAuth1Authorizer *self, GAsyncResult *async_result, GError **error)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self), FALSE);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (G_IS_ASYNC_RESULT (async_result), FALSE);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (g_task_is_valid (async_result, self), FALSE);
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (g_async_result_is_tagged (async_result, gdata_oauth1_authorizer_request_authorization_async), FALSE);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return g_task_propagate_boolean (G_TASK (async_result), error);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_get_application_name:
|
|
Packit |
4b6dd7 |
* @self: a #GDataOAuth1Authorizer
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Returns the application name being used on the authentication page at the URI returned by gdata_oauth1_authorizer_request_authentication_uri();
|
|
Packit |
4b6dd7 |
* i.e. the value of #GDataOAuth1Authorizer:application-name.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: (allow-none): the application name, or %NULL if one isn't set
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
const gchar *
|
|
Packit |
4b6dd7 |
gdata_oauth1_authorizer_get_application_name (GDataOAuth1Authorizer *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self), NULL);
|
|
Packit |
4b6dd7 |
return self->priv->application_name;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_get_locale:
|
|
Packit |
4b6dd7 |
* @self: a #GDataOAuth1Authorizer
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Returns the locale currently being used for network requests, or %NULL if the locale is the default.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: (allow-none): the current locale
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
const gchar *
|
|
Packit |
4b6dd7 |
gdata_oauth1_authorizer_get_locale (GDataOAuth1Authorizer *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self), NULL);
|
|
Packit |
4b6dd7 |
return self->priv->locale;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_set_locale:
|
|
Packit |
4b6dd7 |
* @self: a #GDataOAuth1Authorizer
|
|
Packit |
4b6dd7 |
* @locale: (allow-none): the new locale in Unix locale format, or %NULL for the default locale
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Set the locale used for network requests to @locale, given in standard Unix locale format. See #GDataOAuth1Authorizer:locale for more details.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Note that while it's possible to change the locale after sending network requests (i.e. calling
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_request_authentication_uri() for the first time), it is unsupported, as the server-side software may behave unexpectedly.
|
|
Packit |
4b6dd7 |
* The only supported use of this method is after creation of the authorizer, but before any network requests are made.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
void
|
|
Packit |
4b6dd7 |
gdata_oauth1_authorizer_set_locale (GDataOAuth1Authorizer *self, const gchar *locale)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (g_strcmp0 (locale, self->priv->locale) == 0) {
|
|
Packit |
4b6dd7 |
/* Already has this value */
|
|
Packit |
4b6dd7 |
return;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_free (self->priv->locale);
|
|
Packit |
4b6dd7 |
self->priv->locale = g_strdup (locale);
|
|
Packit |
4b6dd7 |
g_object_notify (G_OBJECT (self), "locale");
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
notify_proxy_uri_cb (GObject *gobject, GParamSpec *pspec, GDataOAuth1Authorizer *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
/* Flush our cached version */
|
|
Packit |
4b6dd7 |
if (self->priv->proxy_uri != NULL) {
|
|
Packit |
4b6dd7 |
soup_uri_free (self->priv->proxy_uri);
|
|
Packit |
4b6dd7 |
self->priv->proxy_uri = NULL;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_object_notify (G_OBJECT (self), "proxy-uri");
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Static function which isn't deprecated so we can continue using it internally. */
|
|
Packit |
4b6dd7 |
static SoupURI *
|
|
Packit |
4b6dd7 |
_get_proxy_uri (GDataOAuth1Authorizer *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
SoupURI *proxy_uri;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self), NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* If we have a cached version, return that */
|
|
Packit |
4b6dd7 |
if (self->priv->proxy_uri != NULL) {
|
|
Packit |
4b6dd7 |
return self->priv->proxy_uri;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_object_get (self->priv->session, SOUP_SESSION_PROXY_URI, &proxy_uri, NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Update the cache; it takes ownership of the URI */
|
|
Packit |
4b6dd7 |
self->priv->proxy_uri = proxy_uri;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return proxy_uri;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_get_proxy_uri:
|
|
Packit |
4b6dd7 |
* @self: a #GDataOAuth1Authorizer
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Gets the proxy URI on the #GDataOAuth1Authorizer's #SoupSession.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: (transfer full) (allow-none): the proxy URI, or %NULL; free with soup_uri_free()
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
* Deprecated: 0.15.0: Use gdata_oauth1_authorizer_get_proxy_resolver() instead, which gives more flexibility over the proxy used.
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
SoupURI *
|
|
Packit |
4b6dd7 |
gdata_oauth1_authorizer_get_proxy_uri (GDataOAuth1Authorizer *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
return _get_proxy_uri (self);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Static function which isn't deprecated so we can continue using it internally. */
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
_set_proxy_uri (GDataOAuth1Authorizer *self, SoupURI *proxy_uri)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_object_set (self->priv->session, SOUP_SESSION_PROXY_URI, proxy_uri, NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Notification is handled in notify_proxy_uri_cb() which is called as a result of setting the property on the session */
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_set_proxy_uri:
|
|
Packit |
4b6dd7 |
* @self: a #GDataOAuth1Authorizer
|
|
Packit |
4b6dd7 |
* @proxy_uri: (allow-none): the proxy URI, or %NULL
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Sets the proxy URI on the #SoupSession used internally by the #GDataOAuth1Authorizer. This forces all requests through the given proxy.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* If @proxy_uri is %NULL, no proxy will be used.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
* Deprecated: 0.15.0: Use gdata_oauth1_authorizer_set_proxy_resolver() instead, which gives more flexibility over the proxy used.
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
void
|
|
Packit |
4b6dd7 |
gdata_oauth1_authorizer_set_proxy_uri (GDataOAuth1Authorizer *self, SoupURI *proxy_uri)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
_set_proxy_uri (self, proxy_uri);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_get_proxy_resolver:
|
|
Packit |
4b6dd7 |
* @self: a #GDataOAuth1Authorizer
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Gets the #GProxyResolver on the #GDataOAuth1Authorizer's #SoupSession.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: (transfer none) (allow-none): a #GProxyResolver, or %NULL
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.15.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
GProxyResolver *
|
|
Packit |
4b6dd7 |
gdata_oauth1_authorizer_get_proxy_resolver (GDataOAuth1Authorizer *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self), NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return self->priv->proxy_resolver;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_set_proxy_resolver:
|
|
Packit |
4b6dd7 |
* @self: a #GDataOAuth1Authorizer
|
|
Packit |
4b6dd7 |
* @proxy_resolver: (allow-none): a #GProxyResolver, or %NULL
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Sets the #GProxyResolver on the #SoupSession used internally by the given #GDataOAuth1Authorizer.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Setting this will clear the #GDataOAuth1Authorizer:proxy-uri property.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.15.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
void
|
|
Packit |
4b6dd7 |
gdata_oauth1_authorizer_set_proxy_resolver (GDataOAuth1Authorizer *self, GProxyResolver *proxy_resolver)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self));
|
|
Packit |
4b6dd7 |
g_return_if_fail (proxy_resolver == NULL || G_IS_PROXY_RESOLVER (proxy_resolver));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (proxy_resolver != NULL) {
|
|
Packit |
4b6dd7 |
g_object_ref (proxy_resolver);
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_clear_object (&self->priv->proxy_resolver);
|
|
Packit |
4b6dd7 |
self->priv->proxy_resolver = proxy_resolver;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_object_notify (G_OBJECT (self), "proxy-resolver");
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
static void
|
|
Packit |
4b6dd7 |
notify_timeout_cb (GObject *gobject, GParamSpec *pspec, GObject *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_object_notify (self, "timeout");
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_get_timeout:
|
|
Packit |
4b6dd7 |
* @self: a #GDataOAuth1Authorizer
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Gets the #GDataOAuth1Authorizer:timeout property; the network timeout, in seconds.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Return value: the timeout, or 0
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
guint
|
|
Packit |
4b6dd7 |
gdata_oauth1_authorizer_get_timeout (GDataOAuth1Authorizer *self)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
guint timeout;
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_return_val_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self), 0);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_object_get (self->priv->session, SOUP_SESSION_TIMEOUT, &timeout, NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
return timeout;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/**
|
|
Packit |
4b6dd7 |
* gdata_oauth1_authorizer_set_timeout:
|
|
Packit |
4b6dd7 |
* @self: a #GDataOAuth1Authorizer
|
|
Packit |
4b6dd7 |
* @timeout: the timeout, or 0
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Sets the #GDataOAuth1Authorizer:timeout property; the network timeout, in seconds.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* If @timeout is 0 , network operations will never time out.
|
|
Packit |
4b6dd7 |
*
|
|
Packit |
4b6dd7 |
* Since: 0.9.0
|
|
Packit |
4b6dd7 |
*/
|
|
Packit |
4b6dd7 |
void
|
|
Packit |
4b6dd7 |
gdata_oauth1_authorizer_set_timeout (GDataOAuth1Authorizer *self, guint timeout)
|
|
Packit |
4b6dd7 |
{
|
|
Packit |
4b6dd7 |
g_return_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self));
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
if (gdata_oauth1_authorizer_get_timeout (self) == timeout) {
|
|
Packit |
4b6dd7 |
/* Already has this value */
|
|
Packit |
4b6dd7 |
return;
|
|
Packit |
4b6dd7 |
}
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
g_object_set (self->priv->session, SOUP_SESSION_TIMEOUT, timeout, NULL);
|
|
Packit |
4b6dd7 |
|
|
Packit |
4b6dd7 |
/* Notification is handled in notify_timeout_cb() which is called as a result of setting the property on the session */
|
|
Packit |
4b6dd7 |
}
|