[libsocialweb/libsocialweb-0.25] lastfm: login to last.fm to validate credentials (BMC#8986)
- From: Rob Bradford <rbradford src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libsocialweb/libsocialweb-0.25] lastfm: login to last.fm to validate credentials (BMC#8986)
- Date: Sat, 12 Nov 2011 11:08:16 +0000 (UTC)
commit fb42bf7173a418713211b31c35fb979b65f33381
Author: Raul Gutiereez Segales <raul gutierrez segales collabora co uk>
Date: Fri May 20 19:19:11 2011 +0100
lastfm: login to last.fm to validate credentials (BMC#8986)
services/lastfm/lastfm.c | 224 +++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 210 insertions(+), 14 deletions(-)
---
diff --git a/services/lastfm/lastfm.c b/services/lastfm/lastfm.c
index 0b780bc..4547568 100644
--- a/services/lastfm/lastfm.c
+++ b/services/lastfm/lastfm.c
@@ -1,6 +1,7 @@
/*
* libsocialweb - social data store
* Copyright (C) 2009 Intel Corporation.
+ * Copyright (C) 2011 Collabora Ltd.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
@@ -27,6 +28,7 @@
#include <libsocialweb/sw-service.h>
#include <libsocialweb/sw-item.h>
#include <libsocialweb/sw-utils.h>
+#include <libsocialweb/sw-online.h>
#include <libsocialweb/sw-web.h>
#include <libsocialweb/sw-call-list.h>
#include <libsocialweb/sw-debug.h>
@@ -62,6 +64,12 @@ G_DEFINE_TYPE_WITH_CODE (SwServiceLastfm, sw_service_lastfm, SW_TYPE_SERVICE,
struct _SwServiceLastfmPrivate {
RestProxy *proxy;
char *username;
+ char *password;
+ char *session_key;
+ char *api_key;
+ char *api_secret;
+ gboolean checked_with_server;
+ gboolean inited;
};
static const char ** get_dynamic_caps (SwService *service);
@@ -97,6 +105,155 @@ lastfm_submit_track (SwLastfmIface *self,
sw_lastfm_iface_return_from_submit_track (context);
}
+/* FIXME: This is mostly copied from services/twitter/twitter.c
+ * so we should move it to some common location and make
+ * it accessible */
+static RestXmlNode *
+node_from_call (RestProxyCall *call)
+{
+ static RestXmlParser *parser = NULL;
+ RestXmlNode *root;
+
+ if (parser == NULL)
+ parser = rest_xml_parser_new ();
+
+ if (!SOUP_STATUS_IS_SUCCESSFUL (rest_proxy_call_get_status_code (call))) {
+ g_message ("Error from LastFM: %s (%d)",
+ rest_proxy_call_get_status_message (call),
+ rest_proxy_call_get_status_code (call));
+ return NULL;
+ }
+
+ root = rest_xml_parser_parse_from_data (parser,
+ rest_proxy_call_get_payload (call),
+ rest_proxy_call_get_payload_length (call));
+
+ if (root == NULL) {
+ g_message ("Error from LastFM: %s",
+ rest_proxy_call_get_payload (call));
+ return NULL;
+ }
+
+ return root;
+}
+
+static void
+_mobile_session_cb (RestProxyCall *call,
+ const GError *error,
+ GObject *weak_object,
+ gpointer userdata)
+{
+ const gchar *status;
+ SwService *service = SW_SERVICE (weak_object);
+ SwServiceLastfm *lastfm = SW_SERVICE_LASTFM (service);
+ SwServiceLastfmPrivate *priv = lastfm->priv;
+ RestXmlNode *node;
+
+ priv->checked_with_server = TRUE;
+
+ if (error) {
+ g_message ("Error: %s", error->message);
+ g_object_unref (call);
+ sw_service_emit_capabilities_changed (service, get_dynamic_caps (service));
+ return;
+ }
+
+ node = node_from_call (call);
+ if (!node)
+ return;
+
+ status = g_hash_table_lookup (node->attrs, "status");
+
+ if (g_strcmp0 (status, "ok") == 0) {
+ RestXmlNode *session_key = rest_xml_node_find (node, "key");
+
+ if (session_key) {
+ g_free (priv->session_key);
+ priv->session_key = g_strdup (session_key->content);
+ }
+ }
+
+ rest_xml_node_unref (node);
+ g_object_unref (call);
+
+ sw_service_emit_capabilities_changed (service, get_dynamic_caps (service));
+}
+
+static char *
+build_call_sig (GHashTable *params, const char *secret)
+{
+ char *str = NULL;
+ char *sig, *temp;
+ GList *keys = g_hash_table_get_keys (params);
+ keys = g_list_sort (keys, (GCompareFunc)g_strcmp0);
+
+ while (keys) {
+ const char *value = (const char *) g_hash_table_lookup (params, keys->data);
+
+ if (str == NULL) {
+ str = g_strconcat((char *)keys->data, value, NULL);
+ } else {
+ temp = str;
+ str = g_strconcat(str, (char *)keys->data, value, NULL);
+ g_free (temp);
+ }
+
+ keys = keys->next;
+ }
+
+ temp = str;
+ str = g_strconcat(str, secret, NULL);
+ g_free (temp);
+
+ sig = g_compute_checksum_for_string (G_CHECKSUM_MD5, str, -1);
+
+ g_free (str);
+ g_list_free (keys);
+
+ return sig;
+}
+
+static void
+verify_user (SwService *service)
+{
+ SwServiceLastfm *lastfm = SW_SERVICE_LASTFM (service);
+ SwServiceLastfmPrivate *priv = lastfm->priv;
+ char *hash_pw, *user_pass, *auth_token;
+ RestProxyCall *call;
+ RestParams *params;
+ GHashTable *params_t;
+ char *api_sig;
+
+ hash_pw = g_compute_checksum_for_string (G_CHECKSUM_MD5,
+ priv->password, -1);
+ user_pass = g_strconcat(priv->username, hash_pw, NULL);
+ auth_token = g_compute_checksum_for_string (G_CHECKSUM_MD5,
+ user_pass, -1);
+
+ call = rest_proxy_new_call (priv->proxy);
+ rest_proxy_call_add_params (call,
+ "api_key", priv->api_key,
+ "username", priv->username,
+ "authToken", auth_token,
+ "method", "auth.getMobileSession",
+ NULL);
+ params = rest_proxy_call_get_params (call);
+ params_t = rest_params_as_string_hash_table (params);
+
+ api_sig = build_call_sig (params_t, priv->api_secret);
+ rest_proxy_call_add_params (call,
+ "api_sig", api_sig,
+ NULL);
+
+ rest_proxy_call_async (call, _mobile_session_cb, (GObject*)lastfm, NULL, NULL);
+
+ g_hash_table_unref (params_t);
+ g_free (api_sig);
+ g_free (hash_pw);
+ g_free (user_pass);
+ g_free (auth_token);
+}
+
/*
* Callback from the keyring lookup in refresh_credentials.
*/
@@ -109,15 +266,24 @@ found_password_cb (GnomeKeyringResult result,
SwServiceLastfm *lastfm = SW_SERVICE_LASTFM (service);
SwServiceLastfmPrivate *priv = lastfm->priv;
+ g_free (priv->username);
+ g_free (priv->password);
+ g_free (priv->session_key);
+ priv->session_key = NULL;
+ priv->username = NULL;
+ priv->password = NULL;
+ priv->checked_with_server = FALSE;
+
if (result == GNOME_KEYRING_RESULT_OK && list != NULL) {
GnomeKeyringNetworkPasswordData *data = list->data;
- g_free (priv->username);
priv->username = g_strdup (data->user);
- } else {
- g_free (priv->username);
- priv->username = NULL;
+ priv->password = g_strdup (data->password);
+ if (sw_is_online ()) {
+ verify_user (service);
+ }
+ } else {
if (result != GNOME_KEYRING_RESULT_NO_MATCH) {
g_warning (G_STRLOC ": Error getting password: %s", gnome_keyring_result_to_message (result));
}
@@ -156,22 +322,40 @@ get_dynamic_caps (SwService *service)
{
SwServiceLastfmPrivate *priv = GET_PRIVATE (service);
+ static const char *no_caps[] = { NULL };
+
static const char *configured_caps[] = {
IS_CONFIGURED,
- CREDENTIALS_VALID,
NULL
};
- static const char *unconfigured_caps[] = {
+ static const char *invalid_caps[] = {
+ IS_CONFIGURED,
+ CREDENTIALS_INVALID,
NULL
};
- if (priv->username)
- {
+ static const char *full_caps[] = {
+ IS_CONFIGURED,
+ CREDENTIALS_VALID,
+ NULL
+ };
+
+ if (priv->username == NULL) {
+ return no_caps;
+ } else if (priv->username && priv->checked_with_server == FALSE) {
return configured_caps;
- } else {
- return unconfigured_caps;
+ } else if (priv->checked_with_server == TRUE) {
+ if (priv->session_key != NULL) {
+ return full_caps;
+ } else {
+ return invalid_caps;
+ }
}
+
+ /* Just in case we fell through */
+ g_warning ("Unhandled credential state");
+ return no_caps;
}
static const char **
@@ -214,6 +398,10 @@ sw_service_lastfm_finalize (GObject *object)
SwServiceLastfmPrivate *priv = ((SwServiceLastfm*)object)->priv;
g_free (priv->username);
+ g_free (priv->password);
+ g_free (priv->session_key);
+ g_free (priv->api_key);
+ g_free (priv->api_secret);
G_OBJECT_CLASS (sw_service_lastfm_parent_class)->finalize (object);
}
@@ -225,8 +413,14 @@ sw_service_lastfm_initable (GInitable *initable,
{
SwServiceLastfm *lastfm = SW_SERVICE_LASTFM (initable);
SwServiceLastfmPrivate *priv = lastfm->priv;
+ const char *key = NULL, *secret = NULL;
+
+ if (priv->inited)
+ return TRUE;
- if (sw_keystore_get_key ("lastfm") == NULL) {
+ sw_keystore_get_key_secret ("lastfm", &key, &secret);
+
+ if (key == NULL || secret == NULL) {
g_set_error_literal (error,
SW_SERVICE_ERROR,
SW_SERVICE_ERROR_NO_KEYS,
@@ -234,13 +428,14 @@ sw_service_lastfm_initable (GInitable *initable,
return FALSE;
}
- if (priv->proxy)
- return TRUE;
-
priv->proxy = rest_proxy_new ("http://ws.audioscrobbler.com/2.0/", FALSE);
+ priv->api_key = g_strdup (key);
+ priv->api_secret = g_strdup (secret);
refresh_credentials (lastfm);
+ priv->inited = TRUE;
+
return TRUE;
}
@@ -397,6 +592,7 @@ static void
sw_service_lastfm_init (SwServiceLastfm *self)
{
self->priv = GET_PRIVATE (self);
+ self->priv->inited = FALSE;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]