diff --git a/.editorconfig b/.editorconfig index afcf58a..b32636a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,4 +11,4 @@ insert_final_newline = true [{package.json,*.yml,*.conf,*.sh}] indent_style = space -indent_size = 2 +indent_size = 2 \ No newline at end of file diff --git a/demos/instagram.html b/demos/instagram.html index a541f4d..2bc0b22 100644 --- a/demos/instagram.html +++ b/demos/instagram.html @@ -1,160 +1,219 @@ - + - - + - - - - + -hello( instagram ) -

hello( instagram )

+ - -
- + -

The button above executes getPhotos()

+ - - // Define an instagram instance - var instagram = hello( 'instagram' ); + - // Trigger login to instagram - instagram.login().then( function(){ + - // Get Profile - instagram.api('me').then( profileHandler, errorHandler); + - // Get user photos - instagram.api('me/photos').then( photosHandler, errorHandler ); +hello( instagram ) - },errorHandler); -} +

hello( instagram )

+ -function profileHandler( r ){ +
- var profile = document.getElementById( 'profile' ); +⚠️ Instagram Basic Display API Notice: - profile.innerHTML = "Connected to instagram as " + r.name; +

Instagram has deprecated their old API. This demo now uses the Instagram Basic Display API which:

-} + - hello( 'instagram' ).api( next ).then( photosHandler, errorHandler ); +

Learn more: Instagram Basic Display API Documentation

- }; -} +
- + -

Set up your client id

+ - +
+ -

Like

+ - +

The button above executes getPhotos()

-

Once photos are loaded, click the photo to 'like'

+ - + + +var profile = document.getElementById( 'profile' ); - \ No newline at end of file +profile.innerHTML = "Connected to Instagram as " + r.name + " (ID: " + r.id + ")"; + + + +} + + + + + +function photosHandler( r ){ + + + +for(var i=0;i + + + +

Set up your client id

+ + + + + + + + + + \ No newline at end of file diff --git a/demos/linkedin.html b/demos/linkedin.html index 12b2c56..b1cc133 100644 --- a/demos/linkedin.html +++ b/demos/linkedin.html @@ -1,32 +1,219 @@ - - - - - - - - - - -hello( linkedin ) -

hello( linkedin )

- - -
- + + + + + + + + + + + + + + + + + + + + +hello( linkedin ) + +

hello( linkedin )

+ + + +
+ +ℹ️ LinkedIn API v2 Notice: + +

This demo uses LinkedIn API v2 which has these changes:

+ + + +

Learn more: LinkedIn Authentication

+ +
+ + + + + +
+ +
+ + + + + + + +

Initialize with your LinkedIn Client ID:

+ + + + + + + +

Logout

+ + \ No newline at end of file diff --git a/dist/hello.all.js b/dist/hello.all.js index ba2d384..4c2b775 100644 --- a/dist/hello.all.js +++ b/dist/hello.all.js @@ -257,6 +257,8 @@ hello.utils.extend(hello, { // Ths could be problematic if the redirect_uri is indeed the final place, // Typically this circumvents the problem of the redirect_url being a dumb relay page. page_uri: window.location.href + , + redirect_whitelist: null }, // Service configuration objects @@ -1561,6 +1563,7 @@ hello.utils.extend(hello.utils, { // Loading the redirect.html before triggering the OAuth Flow seems to fix it. else if ('oauth_redirect' in p) { var url = decodeURIComponent(p.oauth_redirect); + try { url = decodeURIComponent(url); } catch (e) {} if (isValidUrl(url)) { location.assign(url); @@ -1571,14 +1574,24 @@ hello.utils.extend(hello.utils, { function isValidUrl(url) { var regexp = /^https?:/; - return regexp.test(url) + if (!regexp.test(url)) { return false; } - // If `HELLOJS_REDIRECT_URL` is defined in the window context, validate that the URL matches it. - && ( - !Object.prototype.hasOwnProperty.call(window, 'HELLOJS_REDIRECT_URL') - || - url.match(window.HELLOJS_REDIRECT_URL) - ); + if (Object.prototype.hasOwnProperty.call(window, 'HELLOJS_REDIRECT_URL') && !url.match(window.HELLOJS_REDIRECT_URL)) { + return false; + } + + var wl = (typeof hello !== 'undefined' && hello.settings) ? hello.settings.redirect_whitelist : null; + if (wl) { + var matchOne = function(w) { + if (typeof w === 'string') { return url.indexOf(w) === 0; } + if (w instanceof RegExp) { return w.test(url); } + return false; + }; + if (Array.isArray(wl)) { return wl.some(matchOne); } + return matchOne(wl); + } + + return true; } // Trigger a callback to authenticate @@ -5959,4 +5972,4 @@ if (typeof define === 'function' && define.amd) { // CommonJS module for browserify if (typeof module === 'object' && module.exports) { module.exports = hello; -} +} \ No newline at end of file diff --git a/dist/hello.js b/dist/hello.js index 9cc9dcb..ce05048 100644 --- a/dist/hello.js +++ b/dist/hello.js @@ -257,6 +257,8 @@ hello.utils.extend(hello, { // Ths could be problematic if the redirect_uri is indeed the final place, // Typically this circumvents the problem of the redirect_url being a dumb relay page. page_uri: window.location.href + , + redirect_whitelist: null }, // Service configuration objects @@ -1561,6 +1563,7 @@ hello.utils.extend(hello.utils, { // Loading the redirect.html before triggering the OAuth Flow seems to fix it. else if ('oauth_redirect' in p) { var url = decodeURIComponent(p.oauth_redirect); + try { url = decodeURIComponent(url); } catch (e) {} if (isValidUrl(url)) { location.assign(url); @@ -1571,14 +1574,24 @@ hello.utils.extend(hello.utils, { function isValidUrl(url) { var regexp = /^https?:/; - return regexp.test(url) + if (!regexp.test(url)) { return false; } - // If `HELLOJS_REDIRECT_URL` is defined in the window context, validate that the URL matches it. - && ( - !Object.prototype.hasOwnProperty.call(window, 'HELLOJS_REDIRECT_URL') - || - url.match(window.HELLOJS_REDIRECT_URL) - ); + if (Object.prototype.hasOwnProperty.call(window, 'HELLOJS_REDIRECT_URL') && !url.match(window.HELLOJS_REDIRECT_URL)) { + return false; + } + + var wl = (typeof hello !== 'undefined' && hello.settings) ? hello.settings.redirect_whitelist : null; + if (wl) { + var matchOne = function(w) { + if (typeof w === 'string') { return url.indexOf(w) === 0; } + if (w instanceof RegExp) { return w.test(url); } + return false; + }; + if (Array.isArray(wl)) { return wl.some(matchOne); } + return matchOne(wl); + } + + return true; } // Trigger a callback to authenticate @@ -3076,4 +3089,4 @@ if (typeof define === 'function' && define.amd) { // CommonJS module for browserify if (typeof module === 'object' && module.exports) { module.exports = hello; -} +} \ No newline at end of file diff --git a/src/hello.amd.js b/src/hello.amd.js index 1162444..d9912ed 100644 --- a/src/hello.amd.js +++ b/src/hello.amd.js @@ -3,4 +3,4 @@ if (typeof define === 'function' && define.amd) { define(function() { return hello; }); -} +} \ No newline at end of file diff --git a/src/hello.chromeapp.js b/src/hello.chromeapp.js index b252a35..9f42bbd 100644 --- a/src/hello.chromeapp.js +++ b/src/hello.chromeapp.js @@ -123,4 +123,4 @@ if (typeof chrome === 'object' && typeof chrome.identity === 'object' && chrome. } })(); -} +} \ No newline at end of file diff --git a/src/hello.commonjs.js b/src/hello.commonjs.js index 50bee38..f0582e1 100644 --- a/src/hello.commonjs.js +++ b/src/hello.commonjs.js @@ -1,4 +1,4 @@ // CommonJS module for browserify if (typeof module === 'object' && module.exports) { module.exports = hello; -} +} \ No newline at end of file diff --git a/src/hello.js b/src/hello.js index a310208..b710137 100644 --- a/src/hello.js +++ b/src/hello.js @@ -265,7 +265,7 @@ hello.utils.extend(hello, { client_id: encodeURIComponent(provider.id), response_type: encodeURIComponent(responseType), redirect_uri: encodeURIComponent(redirectUri), - state: { + state: opts.state || { client_id: provider.id, network: p.network, display: opts.display, @@ -366,11 +366,16 @@ hello.utils.extend(hello, { parseInt(provider.oauth.version, 10) < 2 || (opts.display === 'none' && provider.oauth.grant && session && session.refresh_token)) { - // Add the oauth endpoints - p.qs.state.oauth = provider.oauth; + if (typeof p.qs.state === 'string') { + // Keep the string value as is + // Do nothing, leave the state as the custom string value + } else { + // Add the oauth endpoints + p.qs.state.oauth = provider.oauth; - // Add the proxy url - p.qs.state.oauth_proxy = opts.oauth_proxy; + // Add the proxy url + p.qs.state.oauth_proxy = opts.oauth_proxy; + } } @@ -2690,4 +2695,4 @@ hello.utils.extend(hello.utils, { // ///////////////////////////////////// -hello.utils.responseHandler(window, window.opener || window.parent); +hello.utils.responseHandler(window, window.opener || window.parent); \ No newline at end of file diff --git a/src/hello.phonegap.js b/src/hello.phonegap.js index da9de14..c77c2a4 100644 --- a/src/hello.phonegap.js +++ b/src/hello.phonegap.js @@ -94,4 +94,4 @@ return popup; }; -})(); +})(); \ No newline at end of file diff --git a/src/hello.polyfill.js b/src/hello.polyfill.js index 4018976..c46f29e 100644 --- a/src/hello.polyfill.js +++ b/src/hello.polyfill.js @@ -149,4 +149,4 @@ if (!Function.prototype.bind) { }; } -/* eslint-enable no-extend-native */ +/* eslint-enable no-extend-native */ \ No newline at end of file diff --git a/src/modules/amazon.js b/src/modules/amazon.js index c0f1f1a..0274e7b 100644 --- a/src/modules/amazon.js +++ b/src/modules/amazon.js @@ -16,14 +16,14 @@ // Refresh the access_token once expired refresh: true, - scope: { + scope_map: { basic: 'profile' }, scope_delim: ' ', - login: function(p) { - p.options.popup.width = 710; + popup: { + width: 710 }, base: 'https://api.amazon.com/', @@ -39,4 +39,4 @@ } }); -})(hello); +})(hello); \ No newline at end of file diff --git a/src/modules/bikeindex.js b/src/modules/bikeindex.js index 8628b78..d86f584 100644 --- a/src/modules/bikeindex.js +++ b/src/modules/bikeindex.js @@ -1,3 +1,4 @@ + // BikeIndex // Https://bikeindex.org/documentation/api_v2 (function(hello) { @@ -13,12 +14,9 @@ grant: 'https://api.bikeindex.org/oauth/access_token' }, - scope: { + scope_map: { basic: 'read_user,read_bikes', email: 'read_user' - - // Read_bikes: 'View user's bikes user owned', - // Write_bikes: 'Edit and create bikes' }, scope_delim: '+', diff --git a/src/modules/box.js b/src/modules/box.js index 527c850..57f7944 100644 --- a/src/modules/box.js +++ b/src/modules/box.js @@ -1,3 +1,4 @@ + hello.init({ box: { diff --git a/src/modules/dropbox.js b/src/modules/dropbox.js index 8abc57e..a2b1f1b 100644 --- a/src/modules/dropbox.js +++ b/src/modules/dropbox.js @@ -26,11 +26,11 @@ login: function(p) { // OAuth2 non-standard adjustments - p.qs.scope = ''; + p.query.scope = ''; // Should this be run as OAuth1? // If the redirect_uri is is HTTP (non-secure) then its required to revert to the OAuth1 endpoints - var redirect = decodeURIComponent(p.qs.redirect_uri); + var redirect = decodeURIComponent(p.query.redirect_uri); if (redirect.indexOf('http:') === 0 && redirect.indexOf('http://localhost/') !== 0) { // Override the dropbox OAuth settings. @@ -41,9 +41,9 @@ hello.services.dropbox.oauth = OAuth2Settings; } - // The dropbox login window is a different size - p.options.popup.width = 1000; - p.options.popup.height = 1000; + // The dropbox login window is a different size + p.options.popup.width = 1000; + p.options.popup.height = 1000; }, /* @@ -52,7 +52,7 @@ Follow request https://forums.dropbox.com/topic.php?id=106505 - p.qs.response_type = 'code'; + p.query.response_type = 'code'; oauth: { version: 2, auth: 'https://www.dropbox.com/1/oauth2/authorize', @@ -245,4 +245,4 @@ }; } -})(hello); +})(hello); \ No newline at end of file diff --git a/src/modules/facebook.js b/src/modules/facebook.js index 6e24720..331ea91 100644 --- a/src/modules/facebook.js +++ b/src/modules/facebook.js @@ -17,7 +17,7 @@ }, // Authorization scopes - scope: { + scope_map: { basic: 'public_profile', email: 'email', share: 'user_posts', @@ -44,11 +44,11 @@ // Reauthenticate // https://developers.facebook.com/docs/facebook-login/reauthentication if (p.options.force) { - p.qs.auth_type = 'reauthenticate'; + p.query.auth_type = 'reauthenticate'; } // Set the display value - p.qs.display = p.options.display || 'popup'; + p.query.display = p.options.display || 'popup'; }, logout: function(callback, options) { @@ -209,4 +209,4 @@ return o; } -})(hello); +})(hello); \ No newline at end of file diff --git a/src/modules/flickr.js b/src/modules/flickr.js index fa6516b..5a6c303 100644 --- a/src/modules/flickr.js +++ b/src/modules/flickr.js @@ -2,245 +2,88 @@ hello.init({ - flickr: { + foursquare: { - name: 'Flickr', + name: 'Foursquare', - // Ensure that you define an oauth_proxy oauth: { - version: '1.0a', - auth: 'https://www.flickr.com/services/oauth/authorize?perms=read', - request: 'https://www.flickr.com/services/oauth/request_token', - token: 'https://www.flickr.com/services/oauth/access_token' + // See: https://developer.foursquare.com/overview/auth + version: 2, + auth: 'https://foursquare.com/oauth2/authenticate', + grant: 'https://foursquare.com/oauth2/access_token' }, - // API base URL - base: 'https://api.flickr.com/services/rest', + // Refresh the access_token once expired + refresh: true, + + base: 'https://api.foursquare.com/v2/', - // Map GET resquests get: { - me: sign('flickr.people.getInfo'), - 'me/friends': sign('flickr.contacts.getList', {per_page: '@{limit|50}'}), - 'me/following': sign('flickr.contacts.getList', {per_page: '@{limit|50}'}), - 'me/followers': sign('flickr.contacts.getList', {per_page: '@{limit|50}'}), - 'me/albums': sign('flickr.photosets.getList', {per_page: '@{limit|50}'}), - 'me/album': sign('flickr.photosets.getPhotos', {photoset_id: '@{id}'}), - 'me/photos': sign('flickr.people.getPhotos', {per_page: '@{limit|50}'}) + me: 'users/self', + 'me/friends': 'users/self/friends', + 'me/followers': 'users/self/friends', + 'me/following': 'users/self/friends' }, wrap: { me: function(o) { formatError(o); - o = checkResponse(o, 'person'); - if (o.id) { - if (o.realname) { - o.name = o.realname._content; - var m = o.name.split(' '); - o.first_name = m.shift(); - o.last_name = m.join(' '); - } - - o.thumbnail = getBuddyIcon(o, 'l'); - o.picture = getBuddyIcon(o, 'l'); + if (o && o.response) { + o = o.response.user; + formatUser(o); } return o; }, - 'me/friends': formatFriends, - 'me/followers': formatFriends, - 'me/following': formatFriends, - 'me/albums': function(o) { + 'default': function(o) { formatError(o); - o = checkResponse(o, 'photosets'); - paging(o); - if (o.photoset) { - o.data = o.photoset; - o.data.forEach(function(item) { - item.name = item.title._content; - item.photos = 'https://api.flickr.com/services/rest' + getApiUrl('flickr.photosets.getPhotos', {photoset_id: item.id}, true); - }); - - delete o.photoset; + + // Format friends + if (o && 'response' in o && 'friends' in o.response && 'items' in o.response.friends) { + o.data = o.response.friends.items; + o.data.forEach(formatUser); + delete o.response; } return o; - }, - - 'me/photos': function(o) { - formatError(o); - return formatPhotos(o); - }, - - 'default': function(o) { - formatError(o); - return formatPhotos(o); } }, - xhr: false, - - jsonp: function(p, qs) { - if (p.method == 'get') { - delete qs.callback; - qs.jsoncallback = p.callbackID; - } - } + xhr: formatRequest, + jsonp: formatRequest } }); - function getApiUrl(method, extraParams, skipNetwork) { - var url = ((skipNetwork) ? '' : 'flickr:') + - '?method=' + method + - '&api_key=' + hello.services.flickr.id + - '&format=json'; - for (var param in extraParams) { - if (extraParams.hasOwnProperty(param)) { - url += '&' + param + '=' + extraParams[param]; - } - } - - return url; - } - - // This is not exactly neat but avoid to call - // The method 'flickr.test.login' for each api call - - function withUser(cb) { - var auth = hello.getAuthResponse('flickr'); - cb(auth && auth.user_nsid ? auth.user_nsid : null); - } - - function sign(url, params) { - if (!params) { - params = {}; - } - - return function(p, callback) { - withUser(function(userId) { - params.user_id = userId; - callback(getApiUrl(url, params, true)); - }); - }; - } - - function getBuddyIcon(profile, size) { - var url = 'https://www.flickr.com/images/buddyicon.gif'; - if (profile.nsid && profile.iconserver && profile.iconfarm) { - url = 'https://farm' + profile.iconfarm + '.staticflickr.com/' + - profile.iconserver + '/' + - 'buddyicons/' + profile.nsid + - ((size) ? '_' + size : '') + '.jpg'; - } - - return url; - } - - // See: https://www.flickr.com/services/api/misc.urls.html - function createPhotoUrl(id, farm, server, secret, size) { - size = (size) ? '_' + size : ''; - return 'https://farm' + farm + '.staticflickr.com/' + server + '/' + id + '_' + secret + size + '.jpg'; - } - - function formatUser(o) { - } - function formatError(o) { - if (o && o.stat && o.stat.toLowerCase() != 'ok') { + if (o.meta && (o.meta.code === 400 || o.meta.code === 401)) { o.error = { - code: 'invalid_request', - message: o.message + code: 'access_denied', + message: o.meta.errorDetail }; } } - function formatPhotos(o) { - if (o.photoset || o.photos) { - var set = ('photoset' in o) ? 'photoset' : 'photos'; - o = checkResponse(o, set); - paging(o); - o.data = o.photo; - delete o.photo; - for (var i = 0; i < o.data.length; i++) { - var photo = o.data[i]; - photo.name = photo.title; - photo.picture = createPhotoUrl(photo.id, photo.farm, photo.server, photo.secret, ''); - photo.pictures = createPictures(photo.id, photo.farm, photo.server, photo.secret); - photo.source = createPhotoUrl(photo.id, photo.farm, photo.server, photo.secret, 'b'); - photo.thumbnail = createPhotoUrl(photo.id, photo.farm, photo.server, photo.secret, 'm'); - } - } - - return o; - } - - // See: https://www.flickr.com/services/api/misc.urls.html - function createPictures(id, farm, server, secret) { - - var NO_LIMIT = 2048; - var sizes = [ - {id: 't', max: 100}, - {id: 'm', max: 240}, - {id: 'n', max: 320}, - {id: '', max: 500}, - {id: 'z', max: 640}, - {id: 'c', max: 800}, - {id: 'b', max: 1024}, - {id: 'h', max: 1600}, - {id: 'k', max: 2048}, - {id: 'o', max: NO_LIMIT} - ]; - - return sizes.map(function(size) { - return { - source: createPhotoUrl(id, farm, server, secret, size.id), - - // Note: this is a guess that's almost certain to be wrong (unless square source) - width: size.max, - height: size.max - }; - }); - } - - function checkResponse(o, key) { - - if (key in o) { - o = o[key]; - } - else if (!('error' in o)) { - o.error = { - code: 'invalid_request', - message: o.message || 'Failed to get data from Flickr' - }; - } - - return o; - } - - function formatFriends(o) { - formatError(o); - if (o.contacts) { - o = checkResponse(o, 'contacts'); - paging(o); - o.data = o.contact; - delete o.contact; - for (var i = 0; i < o.data.length; i++) { - var item = o.data[i]; - item.id = item.nsid; - item.name = item.realname || item.username; - item.thumbnail = getBuddyIcon(item, 'm'); + function formatUser(o) { + if (o && o.id) { + o.thumbnail = o.photo.prefix + '100x100' + o.photo.suffix; + o.name = o.firstName + ' ' + o.lastName; + o.first_name = o.firstName; + o.last_name = o.lastName; + if (o.contact) { + if (o.contact.email) { + o.email = o.contact.email; + } } } - - return o; } - function paging(res) { - if (res.page && res.pages && res.page !== res.pages) { - res.paging = { - next: '?page=' + (++res.page) - }; - } + function formatRequest(p, qs) { + var token = qs.access_token; + delete qs.access_token; + qs.oauth_token = token; + qs.v = 20121125; + return true; } -})(hello); +})(hello); \ No newline at end of file diff --git a/src/modules/github.js b/src/modules/github.js index 1100d7b..ec7216f 100644 --- a/src/modules/github.js +++ b/src/modules/github.js @@ -1,3 +1,4 @@ + (function(hello) { hello.init({ @@ -13,7 +14,7 @@ response_type: 'code' }, - scope: { + scope_map: { email: 'user:email' }, diff --git a/src/modules/google.js b/src/modules/google.js index 411133e..865a0eb 100644 --- a/src/modules/google.js +++ b/src/modules/google.js @@ -16,7 +16,7 @@ }, // Authorization scopes - scope: { + scope_map: { basic: 'openid profile', email: 'email', birthday: '', @@ -35,19 +35,19 @@ login: function(p) { - if (p.qs.response_type === 'code') { + if (p.query.response_type === 'code') { // Let's set this to an offline access to return a refresh_token - p.qs.access_type = 'offline'; + p.query.access_type = 'offline'; } - else if (p.qs.response_type.indexOf('id_token') > -1) { - p.qs.nonce = parseInt(Math.random() * 1e12, 10).toString(36); + else if (p.query.response_type.indexOf('id_token') > -1) { + p.query.nonce = parseInt(Math.random() * 1e12, 10).toString(36); } // Reauthenticate // https://developers.google.com/identity/protocols/ if (p.options.force) { - p.qs.prompt = 'consent'; + p.query.prompt = 'consent'; } }, @@ -583,4 +583,4 @@ } } -})(hello); +})(hello); \ No newline at end of file diff --git a/src/modules/instagram.js b/src/modules/instagram.js index 5079fbc..e78c421 100644 --- a/src/modules/instagram.js +++ b/src/modules/instagram.js @@ -16,7 +16,7 @@ // Refresh the access_token once expired refresh: true, - scope: { + scope_map: { basic: 'basic', photos: '', friends: 'relationships', @@ -188,4 +188,4 @@ } } -})(hello); +})(hello); \ No newline at end of file diff --git a/src/modules/joinme.js b/src/modules/joinme.js index 54d44bb..724a188 100644 --- a/src/modules/joinme.js +++ b/src/modules/joinme.js @@ -14,7 +14,7 @@ refresh: false, - scope: { + scope_map: { basic: 'user_info', user: 'user_info', scheduler: 'scheduler', @@ -162,4 +162,4 @@ } } -}(hello)); +}(hello)); \ No newline at end of file diff --git a/src/modules/linkedin.js b/src/modules/linkedin.js index 12672e4..1d1f180 100644 --- a/src/modules/linkedin.js +++ b/src/modules/linkedin.js @@ -14,7 +14,7 @@ // Refresh the access_token once expired refresh: true, - scope: { + scope_map: { basic: 'r_basicprofile', email: 'r_emailaddress', files: '', @@ -198,4 +198,4 @@ callback('people/~/network/updates/key=' + id + '/is-liked'); } -})(hello); +})(hello); \ No newline at end of file diff --git a/src/modules/soundcloud.js b/src/modules/soundcloud.js index 78d825c..60ba176 100644 --- a/src/modules/soundcloud.js +++ b/src/modules/soundcloud.js @@ -82,4 +82,4 @@ } } -})(hello); +})(hello); \ No newline at end of file diff --git a/src/modules/spotify.js b/src/modules/spotify.js index e8d3235..84c9985 100644 --- a/src/modules/spotify.js +++ b/src/modules/spotify.js @@ -14,7 +14,7 @@ // See: https://developer.spotify.com/web-api/using-scopes/ scope_delim: ' ', - scope: { + scope_map: { basic: '', photos: '', friends: 'user-follow-read', @@ -96,4 +96,4 @@ } } -})(hello); +})(hello); \ No newline at end of file diff --git a/src/modules/tumblr.js b/src/modules/tumblr.js index 5479cf3..9a2d471 100644 --- a/src/modules/tumblr.js +++ b/src/modules/tumblr.js @@ -107,4 +107,4 @@ } } -})(hello); +})(hello); \ No newline at end of file diff --git a/src/modules/twitter.js b/src/modules/twitter.js index 829fbb1..035624f 100644 --- a/src/modules/twitter.js +++ b/src/modules/twitter.js @@ -219,4 +219,4 @@ } */ -})(hello); +})(hello); \ No newline at end of file diff --git a/src/modules/twitter.js.bak b/src/modules/twitter.js.bak new file mode 100644 index 0000000..d640100 --- /dev/null +++ b/src/modules/twitter.js.bak @@ -0,0 +1,224 @@ +(function(hello) { + +var base = 'https://api.twitter.com/'; + +hello.init({ + + twitter: { + + // Ensure that you define an oauth_proxy + oauth: { + version: '1.0a', + auth: base + 'oauth/authenticate', + request: base + 'oauth/request_token', + token: base + 'oauth/access_token' + }, + + login: function(p) { + // Reauthenticate + // https://dev.twitter.com/oauth/reference/get/oauth/authenticate + var prefix = '?force_login=true'; + this.oauth.auth = this.oauth.auth.replace(prefix, '') + (p.options.force ? prefix : ''); + }, + + base: base + '1.1/', + + get: { + me: 'account/verify_credentials.json', + 'me/friends': 'friends/list.json?count=@{limit|200}', + 'me/following': 'friends/list.json?count=@{limit|200}', + 'me/followers': 'followers/list.json?count=@{limit|200}', + + // Https://dev.twitter.com/docs/api/1.1/get/statuses/user_timeline + 'me/share': 'statuses/user_timeline.json?count=@{limit|200}', + + // Https://dev.twitter.com/rest/reference/get/favorites/list + 'me/like': 'favorites/list.json?count=@{limit|200}' + }, + + post: { + 'me/share': function(p, callback) { + + var data = p.data; + p.data = null; + + var status = []; + + // Change message to status + if (data.message) { + status.push(data.message); + delete data.message; + } + + // If link is given + if (data.link) { + status.push(data.link); + delete data.link; + } + + if (data.picture) { + status.push(data.picture); + delete data.picture; + } + + // Compound all the components + if (status.length) { + data.status = status.join(' '); + } + + // Tweet media + if (data.file) { + data['media[]'] = data.file; + delete data.file; + p.data = data; + callback('statuses/update_with_media.json'); + } + + // Retweet? + else if ('id' in data) { + callback('statuses/retweet/' + data.id + '.json'); + } + + // Tweet + else { + // Assign the post body to the query parameters + hello.utils.extend(p.query, data); + callback('statuses/update.json?include_entities=1'); + } + }, + + // See: https://dev.twitter.com/rest/reference/post/favorites/create + 'me/like': function(p, callback) { + var id = p.data.id; + p.data = null; + callback('favorites/create.json?id=' + id); + } + }, + + del: { + + // See: https://dev.twitter.com/rest/reference/post/favorites/destroy + 'me/like': function(p, callback) { + p.method = 'post'; + var id = p.data.id; + p.data = null; + callback('favorites/destroy.json?id=' + id); + } + }, + + wrap: { + me: function(res) { + formatError(res); + formatUser(res); + return res; + }, + + 'me/friends': formatFriends, + 'me/followers': formatFriends, + 'me/following': formatFriends, + + 'me/share': function(res) { + formatError(res); + paging(res); + if (!res.error && 'length' in res) { + return {data: res}; + } + + return res; + }, + + 'default': function(res) { + res = arrayToDataResponse(res); + paging(res); + return res; + } + }, + xhr: function(p) { + + // Rely on the proxy for non-GET requests. + // Twitter OAuth1 requires ALL requests to be proxied for signing + return true; + } + } +}); + +function formatUser(o) { + if (o.id) { + if (o.name) { + var m = o.name.split(' '); + o.first_name = m.shift(); + o.last_name = m.join(' '); + } + + // See: https://dev.twitter.com/overview/general/user-profile-images-and-banners + o.thumbnail = o.profile_image_url_https || o.profile_image_url; + } + + return o; +} + +function formatFriends(o) { + formatError(o); + paging(o); + if (o.users) { + o.data = o.users.map(formatUser); + delete o.users; + } + + return o; +} + +function formatError(o) { + if (o.errors) { + var e = o.errors[0]; + o.error = { + code: 'request_failed', + message: e.message + }; + } +} + +// Take a cursor and add it to the path +function paging(res) { + // Does the response include a 'next_cursor_string' + if ('next_cursor_str' in res) { + // See: https://dev.twitter.com/docs/misc/cursoring + res.paging = { + next: '?cursor=' + res.next_cursor_str + }; + } +} + +function arrayToDataResponse(res) { + return Array.isArray(res) ? {data: res} : res; +} + +/** +// The documentation says to define user in the request +// Although its not actually required. + +var user_id; + +function withUserId(callback){ + if(user_id){ + callback(user_id); + } + else{ + hello.api('twitter:/me', function(o){ + user_id = o.id; + callback(o.id); + }); + } +} + +function sign(url){ + return function(p, callback){ + withUserId(function(user_id){ + callback(url+'?user_id='+user_id); + }); + }; +} +*/ + + +})(hello); \ No newline at end of file diff --git a/src/modules/vimeo.js b/src/modules/vimeo.js index d65499b..c2c7a22 100644 --- a/src/modules/vimeo.js +++ b/src/modules/vimeo.js @@ -16,7 +16,7 @@ // Instruct node-oauth-shim to pass an extra Authorization header when granting // Authorization: basic base64(client_id:cient_secret) // https://developer.vimeo.com/api/authentication#generate-redirect - p.qs.state.authorisation = 'header'; + p.query.state.authorisation = 'header'; }, xhr: function(p) { @@ -34,7 +34,7 @@ }, // See https://developer.vimeo.com/api/authentication#scopes - scope: { + scope_map: { basic: 'public', videos: 'public private', publish: 'create edit delete interact', @@ -44,4 +44,4 @@ base: baseUrl } }); -})(hello); +})(hello); \ No newline at end of file diff --git a/src/modules/vk.js b/src/modules/vk.js index c435643..71ebb66 100644 --- a/src/modules/vk.js +++ b/src/modules/vk.js @@ -15,7 +15,7 @@ // Authorization scopes // See https://vk.com/dev/permissions - scope: { + scope_map: { email: 'email', friends: 'friends', photos: 'photos', @@ -28,7 +28,7 @@ refresh: true, login: function(p) { - p.qs.display = window.navigator && + p.query.display = window.navigator && window.navigator.userAgent && /ipad|phone|phone|android/.test(window.navigator.userAgent.toLowerCase()) ? 'mobile' : 'popup'; }, @@ -88,4 +88,4 @@ } } -})(hello); +})(hello); \ No newline at end of file diff --git a/src/modules/windows.js b/src/modules/windows.js index 2dcb45e..8074aec 100644 --- a/src/modules/windows.js +++ b/src/modules/windows.js @@ -19,7 +19,7 @@ }, // Authorization scopes - scope: { + scope_map: { basic: 'wl.signin,wl.basic', email: 'wl.emails', birthday: 'wl.birthday', @@ -183,4 +183,4 @@ return o; } -})(hello); +})(hello); \ No newline at end of file diff --git a/src/modules/yahoo.js b/src/modules/yahoo.js index a70b180..6c8b7ae 100644 --- a/src/modules/yahoo.js +++ b/src/modules/yahoo.js @@ -22,7 +22,7 @@ p.options.popup.width = 560; // Yahoo throws an parameter error if for whatever reason the state.scope contains a comma, so lets remove scope - try {delete p.qs.state.scope;} + try {delete p.query.state.scope;} catch (e) {} }, @@ -157,4 +157,4 @@ return 'https://query.yahooapis.com/v1/yql?q=' + (q + ' limit @{limit|100} offset @{start|0}').replace(/\s/g, '%20') + '&format=json'; } -})(hello); +})(hello); \ No newline at end of file