├── README.txt ├── app ├── assistants │ ├── oauth-assistant.js │ └── utils │ │ └── oauth.js └── views │ └── oauth │ ├── oauth-scene.html │ ├── oauth.css │ └── progress-indicator.png └── sources.json /README.txt: -------------------------------------------------------------------------------- 1 | /// WebOS OAuth \\\ 2 | 3 | This Files where downloaded from http://github.com/fillito/WebOS-OAuth 4 | 5 | By: Daniel García (fillito) 6 | E-Mail: fillito@gmail.com 7 | Web: www.fillito.com 8 | Madrid - Spain 9 | Last Update : 2010 Jul 22 10 | 11 | Description : 12 | ------------ 13 | 14 | This is just a small library for making OAuth Authentications in Palm WebOS. 15 | You just have to instantiate it passing a json object with the complete OAuth configurations (requestToken Url, authorize Url, accessToken Url, consumer_key, consumer_key_secret) and push it as a normal Mojo Scene. 16 | 17 | The application MUST be configured as a web-application on the server side (non client application). 18 | This library captures the callback redirect url to get the final token to complete the authentication. 19 | 20 | 21 | Installation : 22 | ------------- 23 | 24 | 1. Simple copy and paste All files except the sources.json into your WebOS Application folder. 25 | 2. Open your application's sources.json file and paste the content of the sources.json included in this library 26 | 27 | {"source": "app/assistants/utils/oauth.js"}, 28 | { 29 | "scenes": "oauth", 30 | "source": "app/assistants/oauth-assistant.js" 31 | } 32 | 33 | So your application can access the library files 34 | 35 | 3. Simple set up a json object containing the configuration data as shown here and push the oauth Scene 36 | 37 | var oauthConfig={ 38 | callbackScene:'assistantName', //Name of the assistant to be called on the OAuth Success 39 | requestTokenUrl:'http:// -domain- /oauth/request_token', 40 | requestTokenMethod:'GET', // Optional - 'GET' by default if not specified 41 | authorizeUrl:'http:// -domain- /oauth/authorize', 42 | accessTokenUrl:'http:// -domain- /oauth/access_token', 43 | accessTokenMethod:'GET', // Optional - 'GET' by default if not specified 44 | consumer_key:' -your consumer key- ', 45 | consumer_key_secret:' -your consumer key secret- ', 46 | callback:'http://www.google.com' // Optional - 'oob' by default if not specified 47 | }; 48 | Mojo.Controller.stageController.pushScene('oauth',oauthConfig); 49 | 50 | 51 | Web App Configuration : 52 | ---------------------- 53 | 54 | This library does a little tricky hack so you can make an OAuth Authentication for any OAuth API. 55 | Some OAuth API offers two types of application authentication : web app & client app. 56 | Client Apps type returns a PIN code that you can use as authentication token, but not all API offers this method. 57 | 58 | This library enable OAuth on WebOS ONLY for Web App type Authentication. If you know a little bit about OAuth, you will realise that web app type needs a Callback URL to return the oauth token as a GET parameter. The trick this library uses, is to capture this token as the server redirects. 59 | 60 | To enable this, the only thing you have to take into account, is to configure your application (registered to access the API) callback URL to redirect to www.google.com. <----- IMPORTANT !!!! 61 | 62 | This library listen the embedded web browser to be redirected to www.google.com/?oauth_token=******* , so you MUST set it so it works. 63 | 64 | - Contact me if you have dubts about it - 65 | ------------------------------ 66 | | UPDATE ! : 2010 April 30 | 67 | ------------------------------ 68 | 69 | APIs also accept the callback to be passed as a parameter throught the OAuth process. Configure it on your application OAuth Server if it's mandatory or on your self application if this option is enabled. 70 | 71 | 72 | Comments : 73 | --------- 74 | 75 | This is just the first version of this library. Please, contact me if you need anything related to this library or you want to make any suggestion to improve it. 76 | 77 | Thanks for download !! 78 | Fork me at GitHub !! http://github.com/fillito/WebOS-OAuth 79 | 80 | 81 | 82 | (CC) 2010 Daniel García 83 | 84 | Licensed under the Creative Commons, Attribution-ShareAlike 3.0 Unported; 85 | you may not use this file except in compliance with the License. 86 | You may obtain a copy of the License at 87 | 88 | http://creativecommons.org/licenses/by-sa/3.0/ 89 | 90 | Unless MUTUALLY AGREED TO BY THE PARTIES IN WRITING, licensor offers 91 | the work "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 92 | either express or implied. 93 | See the License for the specific language governing permissions and 94 | limitations under the License. 95 | -------------------------------------------------------------------------------- /app/assistants/oauth-assistant.js: -------------------------------------------------------------------------------- 1 | function OauthAssistant(oauthConfig) { 2 | this.message=null; 3 | this.accessor=null; 4 | this.authHeader=null; 5 | this.method=null; 6 | this.oauth_verifier=null; 7 | this.callbackScene=oauthConfig.callbackScene; 8 | this.requestTokenUrl=oauthConfig.requestTokenUrl; 9 | this.authorizeUrl=oauthConfig.authorizeUrl; 10 | this.accessTokenUrl=oauthConfig.accessTokenUrl; 11 | this.consumer_key=oauthConfig.consumer_key; 12 | this.consumer_key_secret=oauthConfig.consumer_key_secret; 13 | if(oauthConfig.callback!=undefined) 14 | this.callback=oauthConfig.callback; 15 | else 16 | this.callback='oob'; 17 | if(oauthConfig.requestTokenMethod!=undefined) 18 | this.requestTokenMethod=oauthConfig.requestTokenMethod; 19 | else 20 | this.requestTokenMethod='GET'; 21 | if(oauthConfig.accessTokenMethod!=undefined) 22 | this.accessTokenMethod=oauthConfig.accessTokenMethod; 23 | else 24 | this.accessTokenMethod='GET'; 25 | this.url=''; 26 | this.requested_token=''; 27 | this.exchangingToken=false; 28 | } 29 | OauthAssistant.prototype.setup = function() { 30 | this.controller.setupWidget('browser',{},this.storyViewModel = {}); 31 | this.reloadModel = { 32 | label: $L('Reload'), 33 | icon: 'refresh', 34 | command: 'refresh' 35 | }; 36 | this.stopModel = { 37 | label: $L('Stop'), 38 | icon: 'load-progress', 39 | command: 'stop' 40 | }; 41 | this.cmdMenuModel = { 42 | visible: true, 43 | items: [{}, this.reloadModel] 44 | }; 45 | this.controller.setupWidget(Mojo.Menu.commandMenu, {menuClass:'no-fade'}, this.cmdMenuModel); 46 | Mojo.Event.listen(this.controller.get('browser'),Mojo.Event.webViewLoadProgress, this.loadProgress.bind(this)); 47 | Mojo.Event.listen(this.controller.get('browser'),Mojo.Event.webViewLoadStarted, this.loadStarted.bind(this)); 48 | Mojo.Event.listen(this.controller.get('browser'),Mojo.Event.webViewLoadStopped, this.loadStopped.bind(this)); 49 | Mojo.Event.listen(this.controller.get('browser'),Mojo.Event.webViewLoadFailed, this.loadStopped.bind(this)); 50 | Mojo.Event.listen(this.controller.get('browser'),Mojo.Event.webViewTitleUrlChanged, this.titleChanged.bind(this)); 51 | this.requestToken(); 52 | } 53 | OauthAssistant.prototype.titleChanged = function(event) { 54 | var callbackUrl=event.url; 55 | var responseVars=callbackUrl.split("?"); 56 | if(!this.exchangingToken && (responseVars[0]==this.callbackURL+'/' || responseVars[0]==this.callbackURL)){ 57 | this.controller.get('browser').hide(); 58 | var response_param=responseVars[1]; 59 | var result=response_param.match(/oauth_token=*/g); 60 | if(result!=null){ 61 | var params=response_param.split("&"); 62 | var token=params[0].replace("oauth_token=",""); 63 | this.oauth_verifier=params[1].replace("oauth_verifier=",""); 64 | this.exchangeToken(token); 65 | } 66 | } 67 | } 68 | OauthAssistant.prototype.signHeader = function (params){ 69 | if(params==undefined) 70 | params=''; 71 | if(this.method==undefined) 72 | this.method='GET'; 73 | var timestamp=OAuth.timestamp(); 74 | var nonce=OAuth.nonce(11); 75 | this.accessor = {consumerSecret: this.consumer_key_secret, tokenSecret : this.tokenSecret}; 76 | this.message = {method: this.method, action: this.url, parameters: OAuth.decodeForm(params)}; 77 | this.message.parameters.push(['oauth_consumer_key',this.consumer_key]); 78 | this.message.parameters.push(['oauth_nonce',nonce]); 79 | this.message.parameters.push(['oauth_signature_method','HMAC-SHA1']); 80 | this.message.parameters.push(['oauth_timestamp',timestamp]); 81 | if(this.token!=null) 82 | this.message.parameters.push(['oauth_token',this.token]); 83 | this.message.parameters.push(['oauth_version','1.0']); 84 | this.message.parameters.sort() 85 | OAuth.SignatureMethod.sign(this.message, this.accessor); 86 | this.authHeader=OAuth.getAuthorizationHeader("", this.message.parameters); 87 | return true; 88 | } 89 | OauthAssistant.prototype.requestToken = function (){ 90 | this.url=this.requestTokenUrl; 91 | this.method=this.requestTokenMethod; 92 | this.signHeader("oauth_callback="+this.callback); 93 | new Ajax.Request(this.url,{ 94 | method: this.method, 95 | encoding: 'UTF-8', 96 | requestHeaders:['Authorization',this.authHeader], 97 | onComplete:function(response){ 98 | var response_text=response.responseText; 99 | var responseVars=response_text.split("&"); 100 | var auth_url=this.authorizeUrl+"?"+responseVars[0]+"&oauth_consumer="+this.consumer_key; 101 | var oauth_token=responseVars[0].replace("oauth_token=",""); 102 | var oauth_token_secret=responseVars[1].replace("oauth_token_secret=",""); 103 | this.requested_token=oauth_token; 104 | this.token=this.requested_token; 105 | this.tokenSecret=oauth_token_secret; 106 | var oauthBrowserParams={ 107 | authUrl:auth_url, 108 | callbackUrl:this.callback 109 | } 110 | this.instanceBrowser(oauthBrowserParams); 111 | }.bind(this) 112 | }); 113 | } 114 | OauthAssistant.prototype.exchangeToken = function (token){ 115 | this.exchangingToken=true; 116 | this.url=this.accessTokenUrl; 117 | this.token=token; 118 | this.method=this.accessTokenMethod; 119 | this.signHeader("oauth_verifier="+this.oauth_verifier); 120 | new Ajax.Request(this.url,{ 121 | method: this.method, 122 | encoding: 'UTF-8', 123 | requestHeaders:['Authorization',this.authHeader], 124 | onComplete:function(response){ 125 | var response_text=response.responseText; 126 | this.controller.stageController.swapScene({name:this.callbackScene,transition:Mojo.Transition.none},{source:'oauth',response:response_text}); 127 | }.bind(this) 128 | }); 129 | } 130 | OauthAssistant.prototype.instanceBrowser = function(oauthBrowserParams) { 131 | this.storyURL = oauthBrowserParams.authUrl; 132 | this.callbackURL=oauthBrowserParams.callbackUrl 133 | this.controller.get('browser').mojo.openURL(oauthBrowserParams.authUrl); 134 | } 135 | OauthAssistant.prototype.handleCommand = function(event) { 136 | if (event.type == Mojo.Event.command) { 137 | switch (event.command) { 138 | case 'refresh': 139 | this.controller.get('browser').mojo.reloadPage(); 140 | break; 141 | case 'stop': 142 | this.controller.get('browser').mojo.stopLoad(); 143 | break; 144 | } 145 | } 146 | }; 147 | // loadStarted - switch command button to stop icon & command 148 | // 149 | OauthAssistant.prototype.loadStarted = function(event) { 150 | this.cmdMenuModel.items.pop(this.reloadModel); 151 | this.cmdMenuModel.items.push(this.stopModel); 152 | this.controller.modelChanged(this.cmdMenuModel); 153 | this.currLoadProgressImage = 0; 154 | }; 155 | // loadStopped - switch command button to reload icon & command 156 | OauthAssistant.prototype.loadStopped = function(event) { 157 | this.cmdMenuModel.items.pop(this.stopModel); 158 | this.cmdMenuModel.items.push(this.reloadModel); 159 | this.controller.modelChanged(this.cmdMenuModel); 160 | }; 161 | // loadProgress - check for completion, then update progress 162 | OauthAssistant.prototype.loadProgress = function(event) { 163 | var percent = event.progress; 164 | try { 165 | if (percent > 100) { 166 | percent = 100; 167 | } 168 | else if (percent < 0) { 169 | percent = 0; 170 | } 171 | // Update the percentage complete 172 | this.currLoadProgressPercentage = percent; 173 | // Convert the percentage complete to an image number 174 | // Image must be from 0 to 23 (24 images available) 175 | var image = Math.round(percent / 4.1); 176 | if (image > 23) { 177 | image = 23; 178 | } 179 | // Ignore this update if the percentage is lower than where we're showing 180 | if (image < this.currLoadProgressImage) { 181 | return; 182 | } 183 | // Has the progress changed? 184 | if (this.currLoadProgressImage != image) { 185 | // Cancel the existing animator if there is one 186 | if (this.loadProgressAnimator) { 187 | this.loadProgressAnimator.cancel(); 188 | delete this.loadProgressAnimator; 189 | } 190 | // Animate from the current value to the new value 191 | var icon = this.controller.select('div.load-progress')[0]; 192 | if (icon) { 193 | this.loadProgressAnimator = Mojo.Animation.animateValue(Mojo.Animation.queueForElement(icon), 194 | "linear", this._updateLoadProgress.bind(this), { 195 | from: this.currLoadProgressImage, 196 | to: image, 197 | duration: 0.5 198 | }); 199 | } 200 | } 201 | } 202 | catch (e) { 203 | Mojo.Log.logException(e, e.description); 204 | } 205 | }; 206 | OauthAssistant.prototype._updateLoadProgress = function(image) { 207 | // Find the progress image 208 | image = Math.round(image); 209 | // Don't do anything if the progress is already displayed 210 | if (this.currLoadProgressImage == image) { 211 | return; 212 | } 213 | var icon = this.controller.select('div.load-progress'); 214 | if (icon && icon[0]) { 215 | icon[0].setStyle({'background-position': "0px -" + (image * 48) + "px"}); 216 | } 217 | this.currLoadProgressImage = image; 218 | }; 219 | OauthAssistant.prototype.activate = function(event) { 220 | 221 | } 222 | 223 | OauthAssistant.prototype.deactivate = function(event) { 224 | 225 | } 226 | OauthAssistant.prototype.cleanup = function(event) { 227 | Mojo.Event.stopListening(this.controller.get('browser'),Mojo.Event.webViewLoadProgress, this.loadProgress); 228 | Mojo.Event.stopListening(this.controller.get('browser'),Mojo.Event.webViewLoadStarted, this.loadStarted); 229 | Mojo.Event.stopListening(this.controller.get('browser'),Mojo.Event.webViewLoadStopped, this.loadStopped); 230 | Mojo.Event.stopListening(this.controller.get('browser'),Mojo.Event.webViewLoadFailed, this.loadStopped); 231 | Mojo.Event.stopListening(this.controller.get('browser'),Mojo.Event.webViewTitleUrlChanged, this.titleChanged); 232 | } 233 | 234 | -------------------------------------------------------------------------------- /app/assistants/utils/oauth.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2008 Netflix, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /* Here's some JavaScript software for implementing OAuth. 18 | 19 | This isn't as useful as you might hope. OAuth is based around 20 | allowing tools and websites to talk to each other. However, 21 | JavaScript running in web browsers is hampered by security 22 | restrictions that prevent code running on one website from 23 | accessing data stored or served on another. 24 | 25 | Before you start hacking, make sure you understand the limitations 26 | posed by cross-domain XMLHttpRequest. 27 | 28 | On the bright side, some platforms use JavaScript as their 29 | language, but enable the programmer to access other web sites. 30 | Examples include Google Gadgets, and Microsoft Vista Sidebar. 31 | For those platforms, this library should come in handy. 32 | */ 33 | 34 | // The HMAC-SHA1 signature method calls b64_hmac_sha1, defined by 35 | // http://pajhome.org.uk/crypt/md5/sha1.js 36 | 37 | /* An OAuth message is represented as an object like this: 38 | {method: "GET", action: "http://server.com/path", parameters: ...} 39 | 40 | The parameters may be either a map {name: value, name2: value2} 41 | or an Array of name-value pairs [[name, value], [name2, value2]]. 42 | The latter representation is more powerful: it supports parameters 43 | in a specific sequence, or several parameters with the same name; 44 | for example [["a", 1], ["b", 2], ["a", 3]]. 45 | 46 | Parameter names and values are NOT percent-encoded in an object. 47 | They must be encoded before transmission and decoded after reception. 48 | For example, this message object: 49 | {method: "GET", action: "http://server/path", parameters: {p: "x y"}} 50 | ... can be transmitted as an HTTP request that begins: 51 | GET /path?p=x%20y HTTP/1.0 52 | (This isn't a valid OAuth request, since it lacks a signature etc.) 53 | Note that the object "x y" is transmitted as x%20y. To encode 54 | parameters, you can call OAuth.addToURL, OAuth.formEncode or 55 | OAuth.getAuthorization. 56 | 57 | This message object model harmonizes with the browser object model for 58 | input elements of an form, whose value property isn't percent encoded. 59 | The browser encodes each value before transmitting it. For example, 60 | see consumer.setInputs in example/consumer.js. 61 | */ 62 | 63 | /* This script needs to know what time it is. By default, it uses the local 64 | clock (new Date), which is apt to be inaccurate in browsers. To do 65 | better, you can load this script from a URL whose query string contains 66 | an oauth_timestamp parameter, whose value is a current Unix timestamp. 67 | For example, when generating the enclosing document using PHP: 68 | 69 |