From bf6cb369301ac1c925c055de846385c843f37ccc Mon Sep 17 00:00:00 2001 From: Markus Birth Date: Tue, 14 Jun 2011 15:30:21 +0200 Subject: [PATCH] Latest version --- .gitignore | 5 +- Resources/app.js | 71 +---- Resources/lib/EzOAuth2.coffee | 110 +++++++ Resources/lib/EzOAuth2.js | 148 +++++++++ Resources/lib/oauth.js | 551 +++++++++++++++++++++++++++++++++ Resources/lib/sha1.js | 202 ++++++++++++ Resources/main.coffee | 69 +++++ Resources/main.js | 50 +++ Resources_coffee/make.sh | 5 + tests/content_node_2.json | 24 ++ tests/content_node_2_list.json | 129 ++++++++ tests/oauth2_london2_test.html | 84 +++++ tests/oauth2_london_test.html | 84 +++++ tests/oauth2_test.html | 86 +++++ tiapp.xml | 3 + 15 files changed, 1560 insertions(+), 61 deletions(-) create mode 100644 Resources/lib/EzOAuth2.coffee create mode 100644 Resources/lib/EzOAuth2.js create mode 100644 Resources/lib/oauth.js create mode 100644 Resources/lib/sha1.js create mode 100644 Resources/main.coffee create mode 100644 Resources/main.js create mode 100644 Resources_coffee/make.sh create mode 100644 tests/content_node_2.json create mode 100644 tests/content_node_2_list.json create mode 100644 tests/oauth2_london2_test.html create mode 100644 tests/oauth2_london_test.html create mode 100644 tests/oauth2_test.html diff --git a/.gitignore b/.gitignore index a9a5aec..d0d3a6d 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ -tmp +.DS_Store +.bzr/ +build/ +tmp/ diff --git a/Resources/app.js b/Resources/app.js index b10ea40..a00fe94 100644 --- a/Resources/app.js +++ b/Resources/app.js @@ -1,64 +1,15 @@ -// this sets the background color of the master UIView (when there are no windows/tab groups on it) -Titanium.UI.setBackgroundColor('#000'); +Ti.API.info( '▶▶▶ app.js' ); -// create tab group -var tabGroup = Titanium.UI.createTabGroup(); +$ = {}; // root element +$.config = { + client_id: '98896cbfaa12dfba67ccdc18352a6374', + client_secret: '20667fe88eaace9d86ad19e48c772490', + endpoint_uri: 'http://oauth.extranet.silversolutions.de/ssl/oauth/', + oauth_authorize: 'http://london2011.ez.no/oauth/authorize', + oauth_token: 'http://london2011.ez.no/oauth/token' +}; -// -// create base UI tab and root window -// -var win1 = Titanium.UI.createWindow({ - title:'Tab 1', - backgroundColor:'#fff' -}); -var tab1 = Titanium.UI.createTab({ - icon:'KS_nav_views.png', - title:'Tab 1', - window:win1 -}); +// TEST with ex. http://london2011.ez.no/api/ezp/content/node/2 -var label1 = Titanium.UI.createLabel({ - color:'#999', - text:'I am Window 1', - font:{fontSize:20,fontFamily:'Helvetica Neue'}, - textAlign:'center', - width:'auto' -}); - -win1.add(label1); - -// -// create controls tab and root window -// -var win2 = Titanium.UI.createWindow({ - title:'Tab 2', - backgroundColor:'#fff' -}); -var tab2 = Titanium.UI.createTab({ - icon:'KS_nav_ui.png', - title:'Tab 2', - window:win2 -}); - -var label2 = Titanium.UI.createLabel({ - color:'#999', - text:'I am Window 2', - font:{fontSize:20,fontFamily:'Helvetica Neue'}, - textAlign:'center', - width:'auto' -}); - -win2.add(label2); - - - -// -// add tabs -// -tabGroup.addTab(tab1); -tabGroup.addTab(tab2); - - -// open tab group -tabGroup.open(); +Ti.include( 'main.js' ); diff --git a/Resources/lib/EzOAuth2.coffee b/Resources/lib/EzOAuth2.coffee new file mode 100644 index 0000000..22ff491 --- /dev/null +++ b/Resources/lib/EzOAuth2.coffee @@ -0,0 +1,110 @@ +class EzOAuth2 + constructor: ( @root_url, @customer_id, @customer_secret, @endpoint_uri ) -> + id = Ti.Utils.md5HexDigest( @root_url + @customer_id + @customer_secret + @endpoint_uri ) + @access_token = Ti.App.Properties.getString( id + '_access', null ) + @refresh_token = Ti.App.Properties.getString( id + '_refresh', null ) + @update_stamp = Ti.App.Properties.getString( id + '_updated', null ) + @expiry_time = Ti.App.Properties.getInt( id + '_expires', 3600 ) + Ti.API.debug( 'EzOAuth2 object initialized.' ) + + saveSettings: -> + id = Ti.Utils.md5HexDigest( @root_url + @customer_id + @customer_secret + @endpoint_uri ) + Ti.App.Properties.setString( id + '_access', @access_token ) + Ti.App.Properties.setString( id + '_refresh', @refresh_token ) + Ti.App.Properties.setString( id + '_updated', @update_stamp ) + Ti.App.Properties.setInt( id + '_expires', @expiry_time ) + + getAuthView: ( success_function, cancel_function )-> + authUrl = @root_url + '/oauth/authorize' + + '?response_type=token' + + '&client_id=' + @customer_id + + '&redirect_uri=' + encodeURIComponent( @endpoint_uri ) + Ti.API.debug( 'authUrl: ' + authUrl ) + wv = Ti.UI.createWebView( + url: authUrl + ) + wv.parent_obj = this + wv.success_function = success_function + wv.cancel_function = cancel_function + wv.addEventListener( 'beforeload', @processOAuth2Response ) + @auth_web = wv + + @auth_btn = Ti.UI.createButton( + left: 0 + top: 0 + title: "Cancel" + ) + @auth_btn.click_function = cancel_function + @auth_btn.addEventListener( 'click', (e) -> + e.source.auth_view.hide() + e.source.click_function( e ) + ) + + @auth_view = Ti.UI.createView() + @auth_view.add( @auth_web ) + @auth_view.add( @auth_btn ) + @auth_web.auth_view = @auth_view + @auth_btn.auth_view = @auth_view + return @auth_view + + doRequest: ( url, success_function, type = 'GET' ) -> + if @access_token is null + Ti.API.warning( 'No access token.' ) + return false + if Ti.Network.networkType is Ti.Network.NETWORK_NONE + Ti.API.warning( 'No Internet connection.' ) + return false + xhr = Ti.Network.createHTTPClient( + onerror: -> + Ti.API.error( 'ERROR communicating. (' + this.responseText + ')' ) + onload: success_function + ) + xhr.open( type, @root_url + '/api/ezp/v1' + url ) + xhr.setRequestHeader( 'Authorization', 'OAuth ' + @access_token ) + xhr.setRequestHeader( 'Accept', 'application/json' ) + xhr.send() + + getNode: ( node_id, success_function ) -> + @doRequest( '/content/node/' + node_id, success_function ) + + getNodeFields: ( node_id, success_function ) -> + @doRequest( '/content/node/' + node_id + '/fields', success_function ) + + getNodeField: ( node_id, field_id, success_function ) -> + @doRequest( '/content/node/' + node_id + '/field/' + field_id, success_function ) + + getNodeList: ( root_node_id, success_function, offset = null, limit = null, sortKey = null, sortType = null ) -> + req_url = '/content/node/' + root_node_id + '/list' + req_url += '/offset/' + offset if offset? + req_url += '/limit/' + limit if limit? + if sortKey? + req_url += '/sort/' + sortKey + req_url += '/' + sortType if sortType? + @doRequest( req_url, success_function ) + + getGetParameters: ( url ) -> + # borrowed and modified from: http://jquery-howto.blogspot.com/2009/09/get-url-parameters-values-with-jquery.html + vars = {} + pairs = url.slice( url.indexOf( '?' ) + 1 ).split( '&' ) + for pair in pairs + Ti.API.debug( 'Now splitting: "' + pair + '"' ) + pair_split = pair.split( '=' ) + vars[ pair_split[0] ] = pair_split[1] + return vars + + processOAuth2Response: ( e ) -> + Ti.API.debug( '[beforeload] URL: ' + e.url ) + Ti.API.debug( 'Endpoint URI: ' + e.source.parent_obj.endpoint_uri ) + Ti.API.debug( 'Index:' + e.url.indexOf( e.source.parent_obj.endpoint_uri ) ) + if e.url.indexOf( e.source.parent_obj.endpoint_uri ) is 0 + Ti.API.info( 'ENDPOINT URL DETECTED!!!!' ) + e.source.parent_obj.final_url = e.url + params = e.source.parent_obj.getGetParameters( e.url ) + e.source.parent_obj.access_token = params['access_token'] + e.source.parent_obj.refresh_token = params['refresh_token'] + e.source.parent_obj.expiry_time = params['expires_in'] + e.source.parent_obj.update_stamp = Math.round( +new Date() / 1000 ) + e.source.auth_view.hide() + Ti.API.info( 'Got new token. Will expire in ' + params['expires_in'] + ' seconds.' ) + e.source.success_function( e ) + diff --git a/Resources/lib/EzOAuth2.js b/Resources/lib/EzOAuth2.js new file mode 100644 index 0000000..a01ec8e --- /dev/null +++ b/Resources/lib/EzOAuth2.js @@ -0,0 +1,148 @@ +var EzOAuth2; +EzOAuth2 = (function() { + function EzOAuth2(root_url, customer_id, customer_secret, endpoint_uri) { + var id; + this.root_url = root_url; + this.customer_id = customer_id; + this.customer_secret = customer_secret; + this.endpoint_uri = endpoint_uri; + id = Ti.Utils.md5HexDigest(this.root_url + this.customer_id + this.customer_secret + this.endpoint_uri); + this.access_token = Ti.App.Properties.getString(id + '_access', null); + this.refresh_token = Ti.App.Properties.getString(id + '_refresh', null); + this.update_stamp = Ti.App.Properties.getString(id + '_updated', null); + this.expiry_time = Ti.App.Properties.getInt(id + '_expires', 3600); + Ti.API.debug('EzOAuth2 object initialized.'); + } + EzOAuth2.prototype.saveSettings = function() { + var id; + id = Ti.Utils.md5HexDigest(this.root_url + this.customer_id + this.customer_secret + this.endpoint_uri); + Ti.App.Properties.setString(id + '_access', this.access_token); + Ti.App.Properties.setString(id + '_refresh', this.refresh_token); + Ti.App.Properties.setString(id + '_updated', this.update_stamp); + return Ti.App.Properties.setInt(id + '_expires', this.expiry_time); + }; + EzOAuth2.prototype.getAuthView = function(success_function, cancel_function) { + var authUrl, wv; + authUrl = this.root_url + '/oauth/authorize' + '?response_type=token' + '&client_id=' + this.customer_id + '&redirect_uri=' + encodeURIComponent(this.endpoint_uri); + Ti.API.debug('authUrl: ' + authUrl); + wv = Ti.UI.createWebView({ + url: authUrl + }); + wv.parent_obj = this; + wv.success_function = success_function; + wv.cancel_function = cancel_function; + wv.addEventListener('beforeload', this.processOAuth2Response); + this.auth_web = wv; + this.auth_btn = Ti.UI.createButton({ + left: 0, + top: 0, + width: 50, + height: 30, + title: "Cancel" + }); + this.auth_btn.click_function = cancel_function; + this.auth_btn.addEventListener('click', function(e) { + e.source.auth_view.hide(); + return e.source.click_function(e); + }); + this.auth_view = Ti.UI.createView(); + this.auth_view.add(this.auth_web); + this.auth_view.add(this.auth_btn); + this.auth_web.auth_view = this.auth_view; + this.auth_btn.auth_view = this.auth_view; + return this.auth_view; + }; + EzOAuth2.prototype.doRequest = function(url, success_function, type) { + var xhr; + if (type == null) { + type = 'GET'; + } + if (this.access_token === null) { + Ti.API.warning('No access token.'); + return false; + } + if (Ti.Network.networkType === Ti.Network.NETWORK_NONE) { + Ti.API.warning('No Internet connection.'); + return false; + } + xhr = Ti.Network.createHTTPClient({ + onerror: function() { + return Ti.API.error('ERROR communicating. (' + this.responseText + ')'); + }, + onload: success_function + }); + xhr.open(type, this.root_url + '/api/ezp/v1' + url); + xhr.setRequestHeader('Authorization', 'OAuth ' + this.access_token); + xhr.setRequestHeader('Accept', 'application/json'); + return xhr.send(); + }; + EzOAuth2.prototype.getNode = function(node_id, success_function) { + return this.doRequest('/content/node/' + node_id, success_function); + }; + EzOAuth2.prototype.getNodeFields = function(node_id, success_function) { + return this.doRequest('/content/node/' + node_id + '/fields', success_function); + }; + EzOAuth2.prototype.getNodeField = function(node_id, field_id, success_function) { + return this.doRequest('/content/node/' + node_id + '/field/' + field_id, success_function); + }; + EzOAuth2.prototype.getNodeList = function(root_node_id, success_function, offset, limit, sortKey, sortType) { + var req_url; + if (offset == null) { + offset = null; + } + if (limit == null) { + limit = null; + } + if (sortKey == null) { + sortKey = null; + } + if (sortType == null) { + sortType = null; + } + req_url = '/content/node/' + root_node_id + '/list'; + if (offset != null) { + req_url += '/offset/' + offset; + } + if (limit != null) { + req_url += '/limit/' + limit; + } + if (sortKey != null) { + req_url += '/sort/' + sortKey; + if (sortType != null) { + req_url += '/' + sortType; + } + } + return this.doRequest(req_url, success_function); + }; + EzOAuth2.prototype.getGetParameters = function(url) { + var pair, pair_split, pairs, vars, _i, _len; + vars = {}; + pairs = url.slice(url.indexOf('?') + 1).split('&'); + for (_i = 0, _len = pairs.length; _i < _len; _i++) { + pair = pairs[_i]; + Ti.API.debug('Now splitting: "' + pair + '"'); + pair_split = pair.split('='); + vars[pair_split[0]] = pair_split[1]; + } + return vars; + }; + EzOAuth2.prototype.processOAuth2Response = function(e) { + var params; + Ti.API.debug('[beforeload] URL: ' + e.url); + Ti.API.debug('Endpoint URI: ' + e.source.parent_obj.endpoint_uri); + Ti.API.debug('Index:' + e.url.indexOf(e.source.parent_obj.endpoint_uri)); + if (e.url.indexOf(e.source.parent_obj.endpoint_uri) === 0) { + Ti.API.info('ENDPOINT URL DETECTED!!!!'); + e.source.parent_obj.final_url = e.url; + params = e.source.parent_obj.getGetParameters(e.url); + e.source.parent_obj.access_token = params['access_token']; + e.source.parent_obj.refresh_token = params['refresh_token']; + e.source.parent_obj.expiry_time = params['expires_in']; + e.source.parent_obj.update_stamp = Math.round(+new Date() / 1000); + e.source.auth_view.hide(); + Ti.API.info('Got new token. Will expire in ' + params['expires_in'] + ' seconds.'); + return e.source.success_function(e); + } + }; + return EzOAuth2; +})(); \ No newline at end of file diff --git a/Resources/lib/oauth.js b/Resources/lib/oauth.js new file mode 100644 index 0000000..295569a --- /dev/null +++ b/Resources/lib/oauth.js @@ -0,0 +1,551 @@ +/* + * Copyright 2008 Netflix, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Here's some JavaScript software for implementing OAuth. + + This isn't as useful as you might hope. OAuth is based around + allowing tools and websites to talk to each other. However, + JavaScript running in web browsers is hampered by security + restrictions that prevent code running on one website from + accessing data stored or served on another. + + Before you start hacking, make sure you understand the limitations + posed by cross-domain XMLHttpRequest. + + On the bright side, some platforms use JavaScript as their + language, but enable the programmer to access other web sites. + Examples include Google Gadgets, and Microsoft Vista Sidebar. + For those platforms, this library should come in handy. +*/ + +// The HMAC-SHA1 signature method calls b64_hmac_sha1, defined by +// http://pajhome.org.uk/crypt/md5/sha1.js + +/* An OAuth message is represented as an object like this: + {method: "GET", action: "http://server.com/path", parameters: ...} + + The parameters may be either a map {name: value, name2: value2} + or an Array of name-value pairs [[name, value], [name2, value2]]. + The latter representation is more powerful: it supports parameters + in a specific sequence, or several parameters with the same name; + for example [["a", 1], ["b", 2], ["a", 3]]. + + Parameter names and values are NOT percent-encoded in an object. + They must be encoded before transmission and decoded after reception. + For example, this message object: + {method: "GET", action: "http://server/path", parameters: {p: "x y"}} + ... can be transmitted as an HTTP request that begins: + GET /path?p=x%20y HTTP/1.0 + (This isn't a valid OAuth request, since it lacks a signature etc.) + Note that the object "x y" is transmitted as x%20y. To encode + parameters, you can call OAuth.addToURL, OAuth.formEncode or + OAuth.getAuthorization. + + This message object model harmonizes with the browser object model for + input elements of an form, whose value property isn't percent encoded. + The browser encodes each value before transmitting it. For example, + see consumer.setInputs in example/consumer.js. + */ + +/* This script needs to know what time it is. By default, it uses the local + clock (new Date), which is apt to be inaccurate in browsers. To do + better, you can load this script from a URL whose query string contains + an oauth_timestamp parameter, whose value is a current Unix timestamp. + For example, when generating the enclosing document using PHP: + + + + + + + + + + + + diff --git a/tests/oauth2_london_test.html b/tests/oauth2_london_test.html new file mode 100644 index 0000000..582b2d6 --- /dev/null +++ b/tests/oauth2_london_test.html @@ -0,0 +1,84 @@ + + + + + OAuth 2 User Agent Authentication Flow Demo + + + + + + + + + + + diff --git a/tests/oauth2_test.html b/tests/oauth2_test.html new file mode 100644 index 0000000..5f59e93 --- /dev/null +++ b/tests/oauth2_test.html @@ -0,0 +1,86 @@ + + + + + OAuth 2 User Agent Authentication Flow Demo + + + + + + + + + + + diff --git a/tiapp.xml b/tiapp.xml index 99423ac..d4b021f 100644 --- a/tiapp.xml +++ b/tiapp.xml @@ -31,4 +31,7 @@ + + ti_coffee_plugin +