1: // authenticate against the new Last.fm "rest" web service APIs
2: sbLastFm.prototype.apiAuth = function sbLastFm_apiAuth(onSuccess, onFailure) {
3: // clear our old session
4: this.sk = null;
5: Application.prefs.setValue("extensions.lastfm.session_key", "");
6:
7: // clear any web cookies we may have already
8: dump("web cookies cleared\n");
9: var cookieMgr = Cc["@mozilla.org/cookiemanager;1"]
10: .getService(Ci.nsICookieManager);
11: cookieMgr.remove(".last.fm", "Session", "/", false);
12: cookieMgr.remove(".last.fm", "s_cc", "/", false);
13: cookieMgr.remove(".last.fm", "s_sq", "/", false);
14: cookieMgr.remove(".last.fm", "wwwlang", "/", false);
15: cookieMgr.remove(".last.fm", "__qcb", "/", false);
16: cookieMgr.remove(".last.fm", "TREA", "/", false);
17: cookieMgr.remove(".last.fm", "s_nr", "/", false);
18: cookieMgr.remove(".last.fm", "__qca", "/", false);
19: cookieMgr.remove(".last.fm", "s_lastvisit", "/", false);
20: cookieMgr.remove(".last.fm", "LastUser", "/", false);
21: cookieMgr.remove(".last.fm", "AnonTrack", "/", false);
22: cookieMgr.remove(".last.fm", "fastq", "/", false);
23:
24: // get a lastfm desktop session
25: var self = this;
26: this.webLogin(function success() {
27: dump("webLogin SUCCESS\n");
28:
29: self.login_phase = AUTH_PHASE_TOKEN_REQUEST;
30: self._token_xhr = self.apiCall('auth.getToken', { },
31: function response(success, xml, xmlText) {
32: if (!success) {
33: dump("auth.getToken: FAILED TO AUTHENTICATE: " + xmlText + "\n\n");
34: return;
35: }
36:
37: var authtoken = xml.getElementsByTagName('token');
38: if (authtoken.length != 1) {
39: dump("auth.getToken: FAILED TO FIND TOKEN: " + xmlText + "\n\n");
40: return;
41: }
42: authtoken = authtoken[0].textContent;
43: dump("auth.getToken SUCCESS: " + authtoken + "\n");
44:
45: var window = Cc['@mozilla.org/appshell/window-mediator;1']
46: .getService(Ci.nsIWindowMediator)
47: .getMostRecentWindow('Songbird:Main');
48: if (!window) {
49: self.listeners.each(function(listener) {
50: listener.onLoginFailed();
51: });
52: return;
53: }
54: var gBrowser = window.gBrowser;
55:
56: function removeAuthListeners() {
57: gBrowser.removeEventListener("DOMContentLoaded",
58: self._authListener, false);
59: gBrowser.removeEventListener("unload", removeAuthListeners, false);
60: authTab.removeEventListener("TabClose",
61: self._authTabCloseListener, false);
62: }
63:
64: // Create a listener for last.fm's authorization grant page.
65: self._authListener = function (e) {
66:
67: // Ensure we are on the right tab.
68: if (gBrowser.getBrowserForDocument(e.target) !=
69: gBrowser.getBrowserForTab(authTab)) {
70: return;
71: }
72:
73: // We're listening for the LastFM "Permissions Granted" page. It will
74: // have pathname "/api/grantAccess" on the last.fm domain or a
75: // localized version such as lastfm.fr
76: var loc = e.target.location;
77: if (!/last\.?fm/.test(loc.host)) {
78: // If we get here, it implies that the user navigated away from
79: // LastFM without authorizing.
80: removeAuthListeners();
81: self.listeners.each(function(listener) {
82: listener.onLoginFailed();
83: });
84: return;
85: }
86:
87: if (loc.pathname != "/api/grantaccess") {
88: // Ignore LastFM pages that aren't the "Permissions Granted" page.
89: return;
90: }
91:
92: // We should be on the grantAccess page now, so remove the listeners
93: // and try to grab a session key.
94: removeAuthListeners();
95:
96: self.login_phase = AUTH_PHASE_SESSION_REQUEST;
97: self._session_xhr = self.apiCall('auth.getSession', {
98: token: authtoken
99: },
100: function response(success, xml, xmlText) {
101: if (!success) {
102: dump("auth.getSession: FAILED TO AUTHENTICATE: " +
103: xmlText + "\n\n");
104: return;
105: }
106: var keys = xml.getElementsByTagName("key");
107: if (keys.length != 1) {
108: dump("auth.getSession: FAILED TO AUTH. TOKEN: " +
109: xmlText + "\n\n");
110: return;
111: }
112: self.sk = keys[0].textContent;
113: dump("auth.getSession: AUTHENTICATED\n");
114: dump("session key: " + self.sk + "\n");
115: Application.prefs.setValue('extensions.lastfm.session_key',
116: self.sk);
117: var subscribers = xml.getElementsByTagName("subscriber");
118: if (subscribers.length == 1)
119: self._subscriber = (subscribers[0].textContent == "1");
120: if (Application.prefs.getValue(
121: "extensions.lastfm.subscriber_override", false))
122: self._subscriber = true;
123: dump("subscriber: " + self._subscriber + "\n");
124: self.listeners.each(function(l) {
125: l.onAuthorisationSuccess();
126: });
127:
128: if (typeof(onSuccess) == "function")
129: onSuccess();
130: });
131: }
132:
133: // Load the user authorization page.
134: var authURL = "http://" + self.geoBaseDomain + "/api/auth?api_key=" +
135: API_KEY + "&token=" + authtoken;
136:
137: gBrowser.addEventListener("DOMContentLoaded", self._authListener, false);
138: // Make sure we don't leak the listeners if the user takes no action.
139: gBrowser.addEventListener("unload", removeAuthListeners, false);
140:
141: var authTab = gBrowser.loadOneTab(authURL, null, null, null, false);
142:
143: // The user could close the auth page tab without granting permission.
144: self._authTabCloseListener = function(e) {
145: removeAuthListeners();
146: self.listeners.each(function(listener) {
147: listener.onLoginFailed();
148: });
149: }
150:
151: authTab.addEventListener("TabClose", self._authTabCloseListener, false);
152:
153: }, function failure() { // auth.getToken failure
154: dump("webLogin FAILED\n");
155: self.listeners.each(function(listener) {
156: listener.onLoginFailed();
157: });
158: }); // auth.getToken api call
159: }, function() {
160: dump("weblogin FAILURE\n");
161: self.listeners.each(function(listener) {
162: listener.onLoginFailed();
163: });
164: }); // weblogin
165: }