Commit 9648733a authored by Corentin Noël's avatar Corentin Noël
Browse files

Initial version of the Lastfm plugin

parents
build
*~
image: fedora:27
cache:
key: dnf-cache
paths:
- dnf-cache/
variables:
BUILDTOOLS_PKGS: "meson gcc redhat-rpm-config vala-tools"
GLIB2_PKGS: "pkgconfig(glib-2.0) pkgconfig(gobject-2.0)"
GSIGNOND_PKG: "pkgconfig(gsignond)"
SOUP_PKG: "pkgconfig(libsoup-2.4)"
JSON_GLIB_PKG: "pkgconfig(json-glib-1.0)"
DOCGEN_PKGS: "pkgconfig(gtk-doc)"
GIR_PKGS: "pkgconfig(gobject-introspection-1.0)"
CI_PKGS: "pkgconfig(check) lcov"
LOCALE_PKGS: "langpacks-en"
before_script:
- dnf --setopt=cachedir=`pwd`/dnf-cache --quiet --refresh --assumeyes install $BUILDTOOLS_PKGS $GLIB2_PKGS $SOUP_PKG $JSON_GLIB_PKG $GSIGNOND_PKG $DOCGEN_PKGS $GIR_PKGS $CI_PKGS $LOCALE_PKGS
build_x86-64:
stage: build
script:
- meson build -Db_coverage=true
- cd build
- ninja
artifacts:
paths:
- ./
test_x86-64:
stage: test
script:
- cd build
- ninja test
- ninja coverage-html
dependencies:
- build_x86-64
artifacts:
paths:
- ./
This diff is collapsed.
Last.FM Plugin for the gSignOn daemon
===========================================
This plugin for the Accounts-SSO gSignOn daemon handles the Last.FM credentials.
Build instructions
------------------
This project depends on GSignond, and uses the Meson build system. To build it, run
```
meson build --prefix=/usr
cd build
ninja
sudo ninja install
```
License
-------
See COPYING.LIB file.
Resources
---------
[Last.FM Plugin documentation](http://accounts-sso.gitlab.io/gsignond-plugin-lastfm/index.html)
[Official source code repository](https://gitlab.com/accounts-sso/gsignond-plugin-lastfm)
project('lastfm', 'c', 'vala', version: '0.1.0')
gnome = import('gnome')
glib_dep = dependency('glib-2.0')
gobject_dep = dependency('gobject-2.0')
gsignond_dep = dependency('gsignond')
soup_dep = dependency('libsoup-2.4')
json_dep = dependency('json-glib-1.0')
gplugins_dir = gsignond_dep.get_pkgconfig_variable('gpluginsdir')
dependencies = [glib_dep, gobject_dep, gsignond_dep, soup_dep, json_dep]
subdir('src')
/*-
* Copyright (c) 2016-2018 elementary LLC. (https://elementary.io)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Authored by: Corentin Noël <corentin@elementary.io>
*/
public class GSignond.LastfmPlugin : GLib.Object, GSignond.Plugin {
private GSignond.SessionData request_data;
public string type { owned get { return "lastfm"; } }
public string[] mechanisms { owned get { return {"lastfm"}; } }
private const string HOST = "http://www.last.fm/api/auth/";
public void cancel () {
var signond_error = new GSignond.Error.SESSION_CANCELED ("Session canceled");
error (signond_error);
}
public void request_initial (GSignond.SessionData session_data, GSignond.Dictionary token_cache, string mechanism) {
unowned string username = session_data.get_username ();
unowned string secret = session_data.get_secret ();
request_data = session_data;
string consumer_key = session_data.get_string ("ClientId");
if (consumer_key == null) {
var signond_error = new GSignond.Error.MISSING_DATA ("Client did not supply ClientId");
error (signond_error);
return;
}
GSignond.UiPolicy ui_policy;
if (session_data.get_ui_policy (out ui_policy) == false) {
var signond_error = new GSignond.Error.MISSING_DATA ("Client did not supply UI Policy");
error (signond_error);
return;
}
if (ui_policy != GSignond.UiPolicy.REQUEST_PASSWORD && ui_policy != GSignond.UiPolicy.DEFAULT) {
var signond_error = new GSignond.Error.MISSING_DATA ("UI policy must be set to DEFAULT or REQUEST_PASSWORD");
error (signond_error);
return;
}
if (token_cache == null) {
var signond_error = new GSignond.Error.MISSING_DATA ("Client did not supply token cache");
error (signond_error);
return;
}
if (ui_policy == GSignond.UiPolicy.DEFAULT) {
var secret_variant = token_cache.get ("Secret");
var username_variant = token_cache.get ("UserName");
if (secret_variant != null) {
secret = secret_variant.get_string ();
}
if (username_variant != null) {
username = username_variant.get_string ();
}
}
if (secret != null && secret != "") {
GSignond.SessionData response = (GSignond.SessionData)new GSignond.Dictionary ();
if (username != null)
response.set_username (username);
response.set_secret (secret);
response_final (response);
return;
}
GSignond.SignonuiData user_action_data = (GSignond.SignonuiData)new GSignond.Dictionary ();
string consumer_secret = session_data.get_string ("ClientSecret");
if (consumer_secret == null) {
var signond_error = new GSignond.Error.MISSING_DATA ("Client did not supply ClientSecret");
error (signond_error);
return;
}
var uri = new Soup.URI (HOST);
uri.set_query_from_fields ("api_key", consumer_key, "cb", "http://elementaryos.org");
user_action_data.set_open_url (uri.to_string (false));
user_action_data.set_final_url ("http://elementaryos.org");
user_action_required (user_action_data);
}
public void request (GSignond.SessionData session_data) {
var err = new GSignond.Error.WRONG_STATE ("Last.fm plugin doesn't support request");
error (err);
}
public void user_action_finished (GSignond.SignonuiData session_data) {
GSignond.SignonuiError query_error;
if (session_data.get_query_error (out query_error) == false) {
var err = new GSignond.Error.USER_INTERACTION ("user_action_finished did not return an error value");
error (err);
return;
}
string response_url = session_data.get_url_response ();
if (query_error == GSignond.SignonuiError.NONE && response_url != null) {
var url = new Soup.URI (response_url);
var fragments = Soup.Form.decode (url.get_query ());
var token = fragments.get ("token");
string api_key = request_data.get_string ("ClientId");
string api_secret = request_data.get_string ("ClientSecret");
var signature = generate_getsession_signature (token, api_key, api_secret);
Soup.Session session = new Soup.Session ();
var uri = new Soup.URI ("http://ws.audioscrobbler.com/2.0/");
uri.set_query_from_fields ("method", "auth.getSession", "token", token, "api_key", api_key, "api_sig", signature, "format", "json");
try {
var uri_request = session.request_uri (uri);
var stream = uri_request.send ();
var parser = new Json.Parser ();
parser.load_from_stream (stream);
var root_object = parser.get_root ().get_object ().get_object_member ("session");
if (root_object == null) {
var signond_error = new GSignond.Error.WRONG_STATE ("Missing 'session' object member");
error (signond_error);
}
var name = root_object.get_string_member ("name");
var key = root_object.get_string_member ("key");
if (name == null || key == null) {
var signond_error = new GSignond.Error.WRONG_STATE ("Missing 'name' or 'key' member");
error (signond_error);
}
var response = (GSignond.SessionData)new GSignond.Dictionary ();
response.set_username (name);
response.set_secret (key);
store (response);
response_final (response);
} catch (GLib.Error e) {
error (e);
return;
}
return;
} else if (query_error == GSignond.SignonuiError.CANCELED) {
var err = new GSignond.Error.SESSION_CANCELED ("Session canceled");
error (err);
} else {
var err = new GSignond.Error.USER_INTERACTION ("user_action_finished error: %d", query_error);
error (err);
}
}
private string generate_md5 (string text) {
return GLib.Checksum.compute_for_string (ChecksumType.MD5, text, text.length);
}
private string generate_getsession_signature (string token, string api, string secret) {
return generate_md5("api_key" + api + "methodauth.getSessiontoken" + token + secret);
}
public void refresh (GSignond.SignonuiData session_data) {
var err = new GSignond.Error.WRONG_STATE ("Last.fm plugin doesn't support refresh");
error (err);
}
}
lastfm_files = files(
'LastfmPlugin.vala'
)
src_include = include_directories('.')
lastfm_plugin = shared_module(meson.project_name(),
lastfm_files,
dependencies : dependencies,
install: true,
install_dir : gplugins_dir
)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment