Merge lp:~urbanape/bindwood/using-oauth into lp:bindwood

Proposed by Zachery Bir
Status: Merged
Approved by: Guillermo Gonzalez
Approved revision: 21
Merged at revision: not available
Proposed branch: lp:~urbanape/bindwood/using-oauth
Merge into: lp:bindwood
Diff against target: None lines
To merge this branch: bzr merge lp:~urbanape/bindwood/using-oauth
Reviewer Review Type Date Requested Status
Guillermo Gonzalez Approve
Tim Cole (community) Approve
Review via email: mp+11371@code.launchpad.net

Commit message

This branch enables OAuth integration for Bindwood.

To post a comment you must log in.
Revision history for this message
Zachery Bir (urbanape) wrote :

This branch enables OAuth integration with our Desktop CouchDB.

Revision history for this message
Tim Cole (tcole) wrote :

Looks okay. Good catch with the semicolons.

review: Approve
lp:~urbanape/bindwood/using-oauth updated
21. By Zachery Bir

Woops, renamed this variable

Revision history for this message
Guillermo Gonzalez (verterok) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'content/browserOverlay.xul'
--- content/browserOverlay.xul 2009-08-18 14:17:30 +0000
+++ content/browserOverlay.xul 2009-09-02 17:07:11 +0000
@@ -19,6 +19,8 @@
19<overlay id="bindwood"19<overlay id="bindwood"
20 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">20 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
2121
22 <script type="application/x-javascript" src="chrome://bindwood/content/sha1.js" />
23 <script type="application/x-javascript" src="chrome://bindwood/content/oauth.js" />
22 <script type="application/x-javascript" src="chrome://bindwood/content/couch.js" />24 <script type="application/x-javascript" src="chrome://bindwood/content/couch.js" />
23 <script type="application/x-javascript" src="chrome://bindwood/content/sync.js" />25 <script type="application/x-javascript" src="chrome://bindwood/content/sync.js" />
2426
2527
=== modified file 'content/couch.js'
--- content/couch.js 2009-07-08 01:24:33 +0000
+++ content/couch.js 2009-09-08 15:29:55 +0000
@@ -1,12 +1,12 @@
1// Licensed under the Apache License, Version 2.0 (the "License"); you may not1// Licensed under the Apache License, Version 2.0 (the "License"); you may not
2// use this file except in compliance with the License. You may obtain a copy2// use this file except in compliance with the License. You may obtain a copy of
3// of the License at3// the License at
4//4//
5// http://www.apache.org/licenses/LICENSE-2.05// http://www.apache.org/licenses/LICENSE-2.0
6//6//
7// Unless required by applicable law or agreed to in writing, software7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT8// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the9// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10// License for the specific language governing permissions and limitations under10// License for the specific language governing permissions and limitations under
11// the License.11// the License.
1212
@@ -22,17 +22,26 @@
22 this.last_req = null;22 this.last_req = null;
2323
24 this.request = function(method, uri, requestOptions) {24 this.request = function(method, uri, requestOptions) {
25 requestOptions = requestOptions || {}25 CouchDB.message.action = uri;
26 requestOptions.headers = combine(requestOptions.headers, httpHeaders)26 Bindwood.writeMessage("Set the action of the CouchDB.message to: " + uri);
27 CouchDB.message.method = method;
28 Bindwood.writeMessage("Set the method of the CouchDB.message to: " + method);
29 OAuth.completeRequest(CouchDB.message, CouchDB.accessor);
30 Bindwood.writeMessage("Signed the message");
31 var parameters = CouchDB.message.parameters;
32 requestOptions = requestOptions || {};
33 requestOptions.headers = combine(requestOptions.headers, httpHeaders);
34 requestOptions.headers = combine(requestOptions.headers, {Authorization: OAuth.getAuthorizationHeader('', parameters)});
35 Bindwood.writeMessage("Request headers: " + JSON.stringify(headers));
27 return CouchDB.request(method, uri, requestOptions);36 return CouchDB.request(method, uri, requestOptions);
28 }37 };
2938
30 // Creates the database on the server39 // Creates the database on the server
31 this.createDb = function() {40 this.createDb = function() {
32 this.last_req = this.request("PUT", this.uri);41 this.last_req = this.request("PUT", this.uri);
33 CouchDB.maybeThrowError(this.last_req);42 CouchDB.maybeThrowError(this.last_req);
34 return JSON.parse(this.last_req.responseText);43 return JSON.parse(this.last_req.responseText);
35 }44 };
3645
37 // Deletes the database on the server46 // Deletes the database on the server
38 this.deleteDb = function() {47 this.deleteDb = function() {
@@ -41,7 +50,7 @@
41 return false;50 return false;
42 CouchDB.maybeThrowError(this.last_req);51 CouchDB.maybeThrowError(this.last_req);
43 return JSON.parse(this.last_req.responseText);52 return JSON.parse(this.last_req.responseText);
44 }53 };
4554
46 // Save a document to the database55 // Save a document to the database
47 this.save = function(doc, options) {56 this.save = function(doc, options) {
@@ -55,7 +64,7 @@
55 var result = JSON.parse(this.last_req.responseText);64 var result = JSON.parse(this.last_req.responseText);
56 doc._rev = result.rev;65 doc._rev = result.rev;
57 return result;66 return result;
58 }67 };
5968
60 // Open a document from the database69 // Open a document from the database
61 this.open = function(docId, options) {70 this.open = function(docId, options) {
@@ -64,7 +73,7 @@
64 return null;73 return null;
65 CouchDB.maybeThrowError(this.last_req);74 CouchDB.maybeThrowError(this.last_req);
66 return JSON.parse(this.last_req.responseText);75 return JSON.parse(this.last_req.responseText);
67 }76 };
6877
69 // Deletes a document from the database78 // Deletes a document from the database
70 this.deleteDoc = function(doc) {79 this.deleteDoc = function(doc) {
@@ -74,7 +83,7 @@
74 doc._rev = result.rev; //record rev in input document83 doc._rev = result.rev; //record rev in input document
75 doc._deleted = true;84 doc._deleted = true;
76 return result;85 return result;
77 }86 };
7887
79 // Deletes an attachment from a document88 // Deletes an attachment from a document
80 this.deleteDocAttachment = function(doc, attachment_name) {89 this.deleteDocAttachment = function(doc, attachment_name) {
@@ -83,17 +92,17 @@
83 var result = JSON.parse(this.last_req.responseText);92 var result = JSON.parse(this.last_req.responseText);
84 doc._rev = result.rev; //record rev in input document93 doc._rev = result.rev; //record rev in input document
85 return result;94 return result;
86 }95 };
8796
88 this.bulkSave = function(docs, options) {97 this.bulkSave = function(docs, options) {
89 // first prepoulate the UUIDs for new documents98 // first prepoulate the UUIDs for new documents
90 var newCount = 099 var newCount = 0;
91 for (var i=0; i<docs.length; i++) {100 for (var i=0; i<docs.length; i++) {
92 if (docs[i]._id == undefined)101 if (docs[i]._id == undefined)
93 newCount++;102 newCount++;
94 }103 }
95 var newUuids = CouchDB.newUuids(docs.length);104 var newUuids = CouchDB.newUuids(docs.length);
96 var newCount = 0105 var newCount = 0;
97 for (var i=0; i<docs.length; i++) {106 for (var i=0; i<docs.length; i++) {
98 if (docs[i]._id == undefined)107 if (docs[i]._id == undefined)
99 docs[i]._id = newUuids.pop();108 docs[i]._id = newUuids.pop();
@@ -118,17 +127,17 @@
118 }127 }
119 return results;128 return results;
120 }129 }
121 }130 };
122131
123 this.ensureFullCommit = function() {132 this.ensureFullCommit = function() {
124 this.last_req = this.request("POST", this.uri + "_ensure_full_commit");133 this.last_req = this.request("POST", this.uri + "_ensure_full_commit");
125 CouchDB.maybeThrowError(this.last_req);134 CouchDB.maybeThrowError(this.last_req);
126 return JSON.parse(this.last_req.responseText);135 return JSON.parse(this.last_req.responseText);
127 }136 };
128137
129 // Applies the map function to the contents of database and returns the results.138 // Applies the map function to the contents of database and returns the results.
130 this.query = function(mapFun, reduceFun, options, keys) {139 this.query = function(mapFun, reduceFun, options, keys, language) {
131 var body = {language: "javascript"};140 var body = {language: language || "javascript"};
132 if(keys) {141 if(keys) {
133 body.keys = keys ;142 body.keys = keys ;
134 }143 }
@@ -144,13 +153,16 @@
144 body.options = options.options;153 body.options = options.options;
145 delete options.options;154 delete options.options;
146 }155 }
147 this.last_req = this.request("POST", this.uri + "_temp_view" + encodeOptions(options), {156 var uri = this.uri + "_temp_view" + encodeOptions(options);
157 Bindwood.writeMessage("Query URI: " + uri);
158 Bindwood.writeMessage("Query body: " + JSON.stringify(body));
159 this.last_req = this.request("POST", uri , {
148 headers: {"Content-Type": "application/json"},160 headers: {"Content-Type": "application/json"},
149 body: JSON.stringify(body)161 body: JSON.stringify(body)
150 });162 });
151 CouchDB.maybeThrowError(this.last_req);163 CouchDB.maybeThrowError(this.last_req);
152 return JSON.parse(this.last_req.responseText);164 return JSON.parse(this.last_req.responseText);
153 }165 };
154166
155 this.view = function(viewname, options, keys) {167 this.view = function(viewname, options, keys) {
156 var viewParts = viewname.split('/');168 var viewParts = viewname.split('/');
@@ -168,14 +180,27 @@
168 return null;180 return null;
169 CouchDB.maybeThrowError(this.last_req);181 CouchDB.maybeThrowError(this.last_req);
170 return JSON.parse(this.last_req.responseText);182 return JSON.parse(this.last_req.responseText);
171 }183 };
172184
173 // gets information about the database185 // gets information about the database
174 this.info = function() {186 this.info = function() {
175 this.last_req = this.request("GET", this.uri);187 this.last_req = this.request("GET", this.uri);
176 CouchDB.maybeThrowError(this.last_req);188 CouchDB.maybeThrowError(this.last_req);
177 return JSON.parse(this.last_req.responseText);189 return JSON.parse(this.last_req.responseText);
178 }190 };
191
192 // gets information about a design doc
193 this.designInfo = function(docid) {
194 this.last_req = this.request("GET", this.uri + docid + "/_info");
195 CouchDB.maybeThrowError(this.last_req);
196 return JSON.parse(this.last_req.responseText);
197 };
198
199 this.viewCleanup = function() {
200 this.last_req = this.request("POST", this.uri + "_view_cleanup");
201 CouchDB.maybeThrowError(this.last_req);
202 return JSON.parse(this.last_req.responseText);
203 };
179204
180 this.allDocs = function(options,keys) {205 this.allDocs = function(options,keys) {
181 if(!keys) {206 if(!keys) {
@@ -188,7 +213,7 @@
188 }213 }
189 CouchDB.maybeThrowError(this.last_req);214 CouchDB.maybeThrowError(this.last_req);
190 return JSON.parse(this.last_req.responseText);215 return JSON.parse(this.last_req.responseText);
191 }216 };
192217
193 this.designDocs = function() {218 this.designDocs = function() {
194 return this.allDocs({startkey:"_design", endkey:"_design0"});219 return this.allDocs({startkey:"_design", endkey:"_design0"});
@@ -206,13 +231,13 @@
206 }231 }
207 CouchDB.maybeThrowError(req);232 CouchDB.maybeThrowError(req);
208 return JSON.parse(req.responseText);233 return JSON.parse(req.responseText);
209 }234 };
210235
211 this.compact = function() {236 this.compact = function() {
212 this.last_req = this.request("POST", this.uri + "_compact");237 this.last_req = this.request("POST", this.uri + "_compact");
213 CouchDB.maybeThrowError(this.last_req);238 CouchDB.maybeThrowError(this.last_req);
214 return JSON.parse(this.last_req.responseText);239 return JSON.parse(this.last_req.responseText);
215 }240 };
216241
217 this.setDbProperty = function(propId, propValue) {242 this.setDbProperty = function(propId, propValue) {
218 this.last_req = this.request("PUT", this.uri + propId,{243 this.last_req = this.request("PUT", this.uri + propId,{
@@ -220,13 +245,13 @@
220 });245 });
221 CouchDB.maybeThrowError(this.last_req);246 CouchDB.maybeThrowError(this.last_req);
222 return JSON.parse(this.last_req.responseText);247 return JSON.parse(this.last_req.responseText);
223 }248 };
224249
225 this.getDbProperty = function(propId) {250 this.getDbProperty = function(propId) {
226 this.last_req = this.request("GET", this.uri + propId);251 this.last_req = this.request("GET", this.uri + propId);
227 CouchDB.maybeThrowError(this.last_req);252 CouchDB.maybeThrowError(this.last_req);
228 return JSON.parse(this.last_req.responseText);253 return JSON.parse(this.last_req.responseText);
229 }254 };
230255
231 this.setAdmins = function(adminsArray) {256 this.setAdmins = function(adminsArray) {
232 this.last_req = this.request("PUT", this.uri + "_admins",{257 this.last_req = this.request("PUT", this.uri + "_admins",{
@@ -234,18 +259,18 @@
234 });259 });
235 CouchDB.maybeThrowError(this.last_req);260 CouchDB.maybeThrowError(this.last_req);
236 return JSON.parse(this.last_req.responseText);261 return JSON.parse(this.last_req.responseText);
237 }262 };
238263
239 this.getAdmins = function() {264 this.getAdmins = function() {
240 this.last_req = this.request("GET", this.uri + "_admins");265 this.last_req = this.request("GET", this.uri + "_admins");
241 CouchDB.maybeThrowError(this.last_req);266 CouchDB.maybeThrowError(this.last_req);
242 return JSON.parse(this.last_req.responseText);267 return JSON.parse(this.last_req.responseText);
243 }268 };
244269
245 // Convert a options object to an url query string.270 // Convert a options object to an url query string.
246 // ex: {key:'value',key2:'value2'} becomes '?key="value"&key2="value2"'271 // ex: {key:'value',key2:'value2'} becomes '?key="value"&key2="value2"'
247 function encodeOptions(options) {272 function encodeOptions(options) {
248 var buf = []273 var buf = [];
249 if (typeof(options) == "object" && options !== null) {274 if (typeof(options) == "object" && options !== null) {
250 for (var name in options) {275 for (var name in options) {
251 if (!options.hasOwnProperty(name)) continue;276 if (!options.hasOwnProperty(name)) continue;
@@ -278,22 +303,82 @@
278 return object1;303 return object1;
279 }304 }
280305
281
282}306}
283307
284CouchDB.PORT_NUMBER = 5984; // default
285
286// this is the XMLHttpRequest object from last request made by the following308// this is the XMLHttpRequest object from last request made by the following
287// CouchDB.* functions (except for calls to request itself).309// CouchDB.* functions (except for calls to request itself).
288// Use this from callers to check HTTP status or header values of requests.310// Use this from callers to check HTTP status or header values of requests.
289CouchDB.last_req = null;311CouchDB.last_req = null;
290312
313CouchDB.login = function(username, password) {
314 CouchDB.last_req = CouchDB.request("POST", "/_session", {
315 headers: {"Content-Type": "application/x-www-form-urlencoded",
316 "X-CouchDB-WWW-Authenticate": "Cookie"},
317 body: "username=" + encodeURIComponent(username) + "&password=" + encodeURIComponent(password)
318 });
319 return JSON.parse(CouchDB.last_req.responseText);
320};
321
322CouchDB.logout = function() {
323 CouchDB.last_req = CouchDB.request("DELETE", "/_session", {
324 headers: {"Content-Type": "application/x-www-form-urlencoded",
325 "X-CouchDB-WWW-Authenticate": "Cookie"}
326 });
327 return JSON.parse(CouchDB.last_req.responseText);
328};
329
330CouchDB.createUser = function(username, password, email, roles, basicAuth) {
331 var roles_str = "";
332 if (roles) {
333 for (var i=0; i< roles.length; i++) {
334 roles_str += "&roles=" + encodeURIComponent(roles[i]);
335 }
336 }
337 var headers = {"Content-Type": "application/x-www-form-urlencoded"};
338 if (basicAuth) {
339 headers['Authorization'] = basicAuth;
340 } else {
341 headers['X-CouchDB-WWW-Authenticate'] = 'Cookie';
342 }
343
344 CouchDB.last_req = CouchDB.request("POST", "/_user/", {
345 headers: headers,
346 body: "username=" + encodeURIComponent(username) + "&password=" + encodeURIComponent(password)
347 + "&email="+ encodeURIComponent(email)+ roles_str
348
349 });
350 return JSON.parse(CouchDB.last_req.responseText);
351};
352
353CouchDB.updateUser = function(username, email, roles, password, old_password) {
354 var roles_str = "";
355 if (roles) {
356 for (var i=0; i< roles.length; i++) {
357 roles_str += "&roles=" + encodeURIComponent(roles[i]);
358 }
359 }
360
361 var body = "email="+ encodeURIComponent(email)+ roles_str;
362
363 if (typeof(password) != "undefined" && password)
364 body += "&password=" + password;
365
366 if (typeof(old_password) != "undefined" && old_password)
367 body += "&old_password=" + old_password;
368
369 CouchDB.last_req = CouchDB.request("PUT", "/_user/"+encodeURIComponent(username), {
370 headers: {"Content-Type": "application/x-www-form-urlencoded",
371 "X-CouchDB-WWW-Authenticate": "Cookie"},
372 body: body
373 });
374 return JSON.parse(CouchDB.last_req.responseText);
375};
291376
292CouchDB.allDbs = function() {377CouchDB.allDbs = function() {
293 CouchDB.last_req = CouchDB.request("GET", "/_all_dbs");378 CouchDB.last_req = CouchDB.request("GET", "/_all_dbs");
294 CouchDB.maybeThrowError(CouchDB.last_req);379 CouchDB.maybeThrowError(CouchDB.last_req);
295 return JSON.parse(CouchDB.last_req.responseText);380 return JSON.parse(CouchDB.last_req.responseText);
296}381};
297382
298CouchDB.allDesignDocs = function() {383CouchDB.allDesignDocs = function() {
299 var ddocs = {}, dbs = CouchDB.allDbs();384 var ddocs = {}, dbs = CouchDB.allDbs();
@@ -308,7 +393,7 @@
308 CouchDB.last_req = CouchDB.request("GET", "/");393 CouchDB.last_req = CouchDB.request("GET", "/");
309 CouchDB.maybeThrowError(CouchDB.last_req);394 CouchDB.maybeThrowError(CouchDB.last_req);
310 return JSON.parse(CouchDB.last_req.responseText).version;395 return JSON.parse(CouchDB.last_req.responseText).version;
311}396};
312397
313CouchDB.replicate = function(source, target, rep_options) {398CouchDB.replicate = function(source, target, rep_options) {
314 rep_options = rep_options || {};399 rep_options = rep_options || {};
@@ -319,29 +404,40 @@
319 });404 });
320 CouchDB.maybeThrowError(CouchDB.last_req);405 CouchDB.maybeThrowError(CouchDB.last_req);
321 return JSON.parse(CouchDB.last_req.responseText);406 return JSON.parse(CouchDB.last_req.responseText);
322}407};
323408
324CouchDB.request = function(method, uri, options) {409CouchDB.newXhr = function() {
325 options = options || {};
326 var req = null;
327 if (typeof(XMLHttpRequest) != "undefined") {410 if (typeof(XMLHttpRequest) != "undefined") {
328 req = new XMLHttpRequest();411 return new XMLHttpRequest();
329 } else if (typeof(ActiveXObject) != "undefined") {412 } else if (typeof(ActiveXObject) != "undefined") {
330 req = new ActiveXObject("Microsoft.XMLHTTP");413 return new ActiveXObject("Microsoft.XMLHTTP");
331 } else {414 } else {
332 throw new Error("No XMLHTTPRequest support detected");415 throw new Error("No XMLHTTPRequest support detected");
333 }416 }
334 req.open(method, "http://localhost:" + CouchDB.PORT_NUMBER + uri, false);417};
418
419CouchDB.request = function(method, uri, options) {
420 options = options || {};
421 var req = CouchDB.newXhr();
422 var computed_uri = "http://localhost:" + CouchDB.port + uri;
423 Bindwood.writeMessage("Opening a request to: " + computed_uri);
424 req.open(method, computed_uri, false);
335 if (options.headers) {425 if (options.headers) {
426 Bindwood.writeMessage("Setting optional headers");
336 var headers = options.headers;427 var headers = options.headers;
337 for (var headerName in headers) {428 for (var headerName in headers) {
338 if (!headers.hasOwnProperty(headerName)) continue;429 if (!headers.hasOwnProperty(headerName)) continue;
339 req.setRequestHeader(headerName, headers[headerName]);430 req.setRequestHeader(headerName, headers[headerName]);
340 }431 }
341 }432 }
342 req.send(options.body || "");433 Bindwood.writeMessage("Sending the request");
434 try {
435 req.send(options.body || "");
436 } catch(e) {
437 Bindwood.writeError("Problem sending request: ", e);
438 }
343 return req;439 return req;
344}440};
345441
346CouchDB.requestStats = function(module, key, test) {442CouchDB.requestStats = function(module, key, test) {
347 var query_arg = "";443 var query_arg = "";
@@ -351,7 +447,7 @@
351447
352 var stat = CouchDB.request("GET", "/_stats/" + module + "/" + key + query_arg).responseText;448 var stat = CouchDB.request("GET", "/_stats/" + module + "/" + key + query_arg).responseText;
353 return JSON.parse(stat)[module][key];449 return JSON.parse(stat)[module][key];
354}450};
355451
356CouchDB.uuids_cache = [];452CouchDB.uuids_cache = [];
357453
@@ -373,7 +469,7 @@
373 CouchDB.uuids_cache.concat(result.uuids.slice(0, 100));469 CouchDB.uuids_cache.concat(result.uuids.slice(0, 100));
374 return result.uuids.slice(100);470 return result.uuids.slice(100);
375 }471 }
376}472};
377473
378CouchDB.maybeThrowError = function(req) {474CouchDB.maybeThrowError = function(req) {
379 if (req.status >= 400) {475 if (req.status >= 400) {
@@ -384,7 +480,7 @@
384 }480 }
385 throw result;481 throw result;
386 }482 }
387}483};
388484
389CouchDB.params = function(options) {485CouchDB.params = function(options) {
390 options = options || {};486 options = options || {};
@@ -394,4 +490,4 @@
394 returnArray.push(key + "=" + value);490 returnArray.push(key + "=" + value);
395 }491 }
396 return returnArray.join("&");492 return returnArray.join("&");
397}493};
398494
=== added file 'content/oauth.js'
--- content/oauth.js 1970-01-01 00:00:00 +0000
+++ content/oauth.js 2009-09-04 14:10:27 +0000
@@ -0,0 +1,515 @@
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 */
62var OAuth; if (OAuth == null) OAuth = {};
63
64OAuth.setProperties = function setProperties(into, from) {
65 if (into != null && from != null) {
66 for (var key in from) {
67 into[key] = from[key];
68 }
69 }
70 return into;
71}
72
73OAuth.setProperties(OAuth, // utility functions
74{
75 percentEncode: function percentEncode(s) {
76 if (s == null) {
77 return "";
78 }
79 if (s instanceof Array) {
80 var e = "";
81 for (var i = 0; i < s.length; ++s) {
82 if (e != "") e += '&';
83 e += percentEncode(s[i]);
84 }
85 return e;
86 }
87 s = encodeURIComponent(s);
88 // Now replace the values which encodeURIComponent doesn't do
89 // encodeURIComponent ignores: - _ . ! ~ * ' ( )
90 // OAuth dictates the only ones you can ignore are: - _ . ~
91 // Source: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Functions:encodeURIComponent
92 s = s.replace(/\!/g, "%21");
93 s = s.replace(/\*/g, "%2A");
94 s = s.replace(/\'/g, "%27");
95 s = s.replace(/\(/g, "%28");
96 s = s.replace(/\)/g, "%29");
97 return s;
98 }
99,
100 decodePercent: function decodePercent(s) {
101 if (s != null) {
102 // Handle application/x-www-form-urlencoded, which is defined by
103 // http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
104 s = s.replace(/\+/g, " ");
105 }
106 return decodeURIComponent(s);
107 }
108,
109 /** Convert the given parameters to an Array of name-value pairs. */
110 getParameterList: function getParameterList(parameters) {
111 if (parameters == null) {
112 return [];
113 }
114 if (typeof parameters != "object") {
115 return decodeForm(parameters + "");
116 }
117 if (parameters instanceof Array) {
118 return parameters;
119 }
120 var list = [];
121 for (var p in parameters) {
122 list.push([p, parameters[p]]);
123 }
124 return list;
125 }
126,
127 /** Convert the given parameters to a map from name to value. */
128 getParameterMap: function getParameterMap(parameters) {
129 if (parameters == null) {
130 return {};
131 }
132 if (typeof parameters != "object") {
133 return getParameterMap(decodeForm(parameters + ""));
134 }
135 if (parameters instanceof Array) {
136 var map = {};
137 for (var p = 0; p < parameters.length; ++p) {
138 var key = parameters[p][0];
139 if (map[key] === undefined) { // first value wins
140 map[key] = parameters[p][1];
141 }
142 }
143 return map;
144 }
145 return parameters;
146 }
147,
148 getParameter: function getParameter(parameters, name) {
149 if (parameters instanceof Array) {
150 for (var p = 0; p < parameters.length; ++p) {
151 if (parameters[p][0] == name) {
152 return parameters[p][1]; // first value wins
153 }
154 }
155 } else {
156 return OAuth.getParameterMap(parameters)[name];
157 }
158 return null;
159 }
160,
161 formEncode: function formEncode(parameters) {
162 var form = "";
163 var list = OAuth.getParameterList(parameters);
164 for (var p = 0; p < list.length; ++p) {
165 var value = list[p][1];
166 if (value == null) value = "";
167 if (form != "") form += '&';
168 form += OAuth.percentEncode(list[p][0])
169 +'='+ OAuth.percentEncode(value);
170 }
171 return form;
172 }
173,
174 decodeForm: function decodeForm(form) {
175 var list = [];
176 var nvps = form.split('&');
177 for (var n = 0; n < nvps.length; ++n) {
178 var nvp = nvps[n];
179 if (nvp == "") {
180 continue;
181 }
182 var equals = nvp.indexOf('=');
183 var name;
184 var value;
185 if (equals < 0) {
186 name = OAuth.decodePercent(nvp);
187 value = null;
188 } else {
189 name = OAuth.decodePercent(nvp.substring(0, equals));
190 value = OAuth.decodePercent(nvp.substring(equals + 1));
191 }
192 list.push([name, value]);
193 }
194 return list;
195 }
196,
197 setParameter: function setParameter(message, name, value) {
198 var parameters = message.parameters;
199 if (parameters instanceof Array) {
200 for (var p = 0; p < parameters.length; ++p) {
201 if (parameters[p][0] == name) {
202 if (value === undefined) {
203 parameters.splice(p, 1);
204 } else {
205 parameters[p][1] = value;
206 value = undefined;
207 }
208 }
209 }
210 if (value !== undefined) {
211 parameters.push([name, value]);
212 }
213 } else {
214 parameters = OAuth.getParameterMap(parameters);
215 parameters[name] = value;
216 message.parameters = parameters;
217 }
218 }
219,
220 setParameters: function setParameters(message, parameters) {
221 var list = OAuth.getParameterList(parameters);
222 for (var i = 0; i < list.length; ++i) {
223 OAuth.setParameter(message, list[i][0], list[i][1]);
224 }
225 }
226,
227 /** Fill in parameters to help construct a request message.
228 This function doesn't fill in every parameter.
229 The accessor object should be like:
230 {consumerKey:'foo', consumerSecret:'bar', accessorSecret:'nurn', token:'krelm', tokenSecret:'blah'}
231 The accessorSecret property is optional.
232 */
233 completeRequest: function completeRequest(message, accessor) {
234 if (message.method == null) {
235 message.method = "GET";
236 }
237 var map = OAuth.getParameterMap(message.parameters);
238 if (map.oauth_consumer_key == null) {
239 OAuth.setParameter(message, "oauth_consumer_key", accessor.consumerKey || "");
240 }
241 if (map.oauth_token == null && accessor.token != null) {
242 OAuth.setParameter(message, "oauth_token", accessor.token);
243 }
244 if (map.oauth_version == null) {
245 OAuth.setParameter(message, "oauth_version", "1.0");
246 }
247 if (map.oauth_timestamp == null) {
248 OAuth.setParameter(message, "oauth_timestamp", OAuth.timestamp());
249 }
250 if (map.oauth_nonce == null) {
251 OAuth.setParameter(message, "oauth_nonce", OAuth.nonce(6));
252 }
253 OAuth.SignatureMethod.sign(message, accessor);
254 }
255,
256 setTimestampAndNonce: function setTimestampAndNonce(message) {
257 OAuth.setParameter(message, "oauth_timestamp", OAuth.timestamp());
258 OAuth.setParameter(message, "oauth_nonce", OAuth.nonce(6));
259 }
260,
261 addToURL: function addToURL(url, parameters) {
262 newURL = url;
263 if (parameters != null) {
264 var toAdd = OAuth.formEncode(parameters);
265 if (toAdd.length > 0) {
266 var q = url.indexOf('?');
267 if (q < 0) newURL += '?';
268 else newURL += '&';
269 newURL += toAdd;
270 }
271 }
272 return newURL;
273 }
274,
275 /** Construct the value of the Authorization header for an HTTP request. */
276 getAuthorizationHeader: function getAuthorizationHeader(realm, parameters) {
277 var header = 'OAuth realm="' + OAuth.percentEncode(realm) + '"';
278 var list = OAuth.getParameterList(parameters);
279 for (var p = 0; p < list.length; ++p) {
280 var parameter = list[p];
281 var name = parameter[0];
282 if (name.indexOf("oauth_") == 0) {
283 header += ',' + OAuth.percentEncode(name) + '="' + OAuth.percentEncode(parameter[1]) + '"';
284 }
285 }
286 return header;
287 }
288,
289 timestamp: function timestamp() {
290 var d = new Date();
291 return Math.floor(d.getTime()/1000);
292 }
293,
294 nonce: function nonce(length) {
295 var chars = OAuth.nonce.CHARS;
296 var result = "";
297 for (var i = 0; i < length; ++i) {
298 var rnum = Math.floor(Math.random() * chars.length);
299 result += chars.substring(rnum, rnum+1);
300 }
301 return result;
302 }
303});
304
305OAuth.nonce.CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
306
307/** Define a constructor function,
308 without causing trouble to anyone who was using it as a namespace.
309 That is, if parent[name] already existed and had properties,
310 copy those properties into the new constructor.
311 */
312OAuth.declareClass = function declareClass(parent, name, newConstructor) {
313 var previous = parent[name];
314 parent[name] = newConstructor;
315 if (newConstructor != null && previous != null) {
316 for (var key in previous) {
317 if (key != "prototype") {
318 newConstructor[key] = previous[key];
319 }
320 }
321 }
322 return newConstructor;
323}
324
325/** An abstract algorithm for signing messages. */
326OAuth.declareClass(OAuth, "SignatureMethod", function OAuthSignatureMethod(){});
327
328OAuth.setProperties(OAuth.SignatureMethod.prototype, // instance members
329{
330 /** Add a signature to the message. */
331 sign: function sign(message) {
332 var baseString = OAuth.SignatureMethod.getBaseString(message);
333 var signature = this.getSignature(baseString);
334 OAuth.setParameter(message, "oauth_signature", signature);
335 return signature; // just in case someone's interested
336 }
337,
338 /** Set the key string for signing. */
339 initialize: function initialize(name, accessor) {
340 var consumerSecret;
341 if (accessor.accessorSecret != null
342 && name.length > 9
343 && name.substring(name.length-9) == "-Accessor")
344 {
345 consumerSecret = accessor.accessorSecret;
346 } else {
347 consumerSecret = accessor.consumerSecret;
348 }
349 this.key = OAuth.percentEncode(consumerSecret)
350 +"&"+ OAuth.percentEncode(accessor.tokenSecret);
351 }
352});
353
354/* SignatureMethod expects an accessor object to be like this:
355 {tokenSecret: "lakjsdflkj...", consumerSecret: "QOUEWRI..", accessorSecret: "xcmvzc..."}
356 The accessorSecret property is optional.
357 */
358// Class members:
359OAuth.setProperties(OAuth.SignatureMethod, // class members
360{
361 sign: function sign(message, accessor) {
362 var name = OAuth.getParameterMap(message.parameters).oauth_signature_method;
363 if (name == null || name == "") {
364 name = "HMAC-SHA1";
365 OAuth.setParameter(message, "oauth_signature_method", name);
366 }
367 OAuth.SignatureMethod.newMethod(name, accessor).sign(message);
368 }
369,
370 /** Instantiate a SignatureMethod for the given method name. */
371 newMethod: function newMethod(name, accessor) {
372 var impl = OAuth.SignatureMethod.REGISTERED[name];
373 if (impl != null) {
374 var method = new impl();
375 method.initialize(name, accessor);
376 return method;
377 }
378 var err = new Error("signature_method_rejected");
379 var acceptable = "";
380 for (var r in OAuth.SignatureMethod.REGISTERED) {
381 if (acceptable != "") acceptable += '&';
382 acceptable += OAuth.percentEncode(r);
383 }
384 err.oauth_acceptable_signature_methods = acceptable;
385 throw err;
386 }
387,
388 /** A map from signature method name to constructor. */
389 REGISTERED : {}
390,
391 /** Subsequently, the given constructor will be used for the named methods.
392 The constructor will be called with no parameters.
393 The resulting object should usually implement getSignature(baseString).
394 You can easily define such a constructor by calling makeSubclass, below.
395 */
396 registerMethodClass: function registerMethodClass(names, classConstructor) {
397 for (var n = 0; n < names.length; ++n) {
398 OAuth.SignatureMethod.REGISTERED[names[n]] = classConstructor;
399 }
400 }
401,
402 /** Create a subclass of OAuth.SignatureMethod, with the given getSignature function. */
403 makeSubclass: function makeSubclass(getSignatureFunction) {
404 var superClass = OAuth.SignatureMethod;
405 var subClass = function() {
406 superClass.call(this);
407 };
408 subClass.prototype = new superClass();
409 // Delete instance variables from prototype:
410 // delete subclass.prototype... There aren't any.
411 subClass.prototype.getSignature = getSignatureFunction;
412 subClass.prototype.constructor = subClass;
413 return subClass;
414 }
415,
416 getBaseString: function getBaseString(message) {
417 var URL = message.action;
418 var q = URL.indexOf('?');
419 var parameters;
420 if (q < 0) {
421 parameters = message.parameters;
422 } else {
423 // Combine the URL query string with the other parameters:
424 parameters = OAuth.decodeForm(URL.substring(q + 1));
425 var toAdd = OAuth.getParameterList(message.parameters);
426 for (var a = 0; a < toAdd.length; ++a) {
427 parameters.push(toAdd[a]);
428 }
429 }
430 return OAuth.percentEncode(message.method.toUpperCase())
431 +'&'+ OAuth.percentEncode(OAuth.SignatureMethod.normalizeUrl(URL))
432 +'&'+ OAuth.percentEncode(OAuth.SignatureMethod.normalizeParameters(parameters));
433 }
434,
435 normalizeUrl: function normalizeUrl(url) {
436 var uri = OAuth.SignatureMethod.parseUri(url);
437 var scheme = uri.protocol.toLowerCase();
438 var authority = uri.authority.toLowerCase();
439 var dropPort = (scheme == "http" && uri.port == 80)
440 || (scheme == "https" && uri.port == 443);
441 if (dropPort) {
442 // find the last : in the authority
443 var index = authority.lastIndexOf(":");
444 if (index >= 0) {
445 authority = authority.substring(0, index);
446 }
447 }
448 var path = uri.path;
449 /* This actually produces different signatures from the python lib
450 if (!path) {
451 path = "/"; // conforms to RFC 2616 section 3.2.2
452 }
453 */
454 // we know that there is no query and no fragment here.
455 return scheme + "://" + authority + path;
456 }
457,
458 parseUri: function parseUri (str) {
459 /* This function was adapted from parseUri 1.2.1
460 http://stevenlevithan.com/demo/parseuri/js/assets/parseuri.js
461 */
462 var o = {key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
463 parser: {strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/ }};
464 var m = o.parser.strict.exec(str);
465 var uri = {};
466 var i = 14;
467 while (i--) uri[o.key[i]] = m[i] || "";
468 return uri;
469 }
470,
471 normalizeParameters: function normalizeParameters(parameters) {
472 if (parameters == null) {
473 return "";
474 }
475 var list = OAuth.getParameterList(parameters);
476 var sortable = [];
477 for (var p = 0; p < list.length; ++p) {
478 var nvp = list[p];
479 if (nvp[0] == "oauth_signature" || nvp[0] == "realm") {
480 continue;
481 } else {
482 sortable.push([ OAuth.percentEncode(nvp[0])
483 + " " // because it comes before any character that can appear in a percentEncoded string.
484 + OAuth.percentEncode(nvp[1])
485 , nvp]);
486 }
487 }
488 sortable.sort(function(a,b) {
489 if (a[0] < b[0]) return -1;
490 if (a[0] > b[0]) return 1;
491 return 0;
492 });
493 var sorted = [];
494 for (var s = 0; s < sortable.length; ++s) {
495 sorted.push(sortable[s][1]);
496 }
497 return OAuth.formEncode(sorted);
498 }
499});
500
501OAuth.SignatureMethod.registerMethodClass(["PLAINTEXT", "PLAINTEXT-Accessor"],
502 OAuth.SignatureMethod.makeSubclass(
503 function getSignature(baseString) {
504 return this.key;
505 }
506 ));
507
508OAuth.SignatureMethod.registerMethodClass(["HMAC-SHA1", "HMAC-SHA1-Accessor"],
509 OAuth.SignatureMethod.makeSubclass(
510 function getSignature(baseString) {
511 b64pad = '=';
512 var signature = b64_hmac_sha1(this.key, baseString);
513 return signature;
514 }
515 ));
0516
=== added file 'content/sha1.js'
--- content/sha1.js 1970-01-01 00:00:00 +0000
+++ content/sha1.js 2009-09-02 17:07:11 +0000
@@ -0,0 +1,202 @@
1/*
2 * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
3 * in FIPS PUB 180-1
4 * Version 2.1a Copyright Paul Johnston 2000 - 2002.
5 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
6 * Distributed under the BSD License
7 * See http://pajhome.org.uk/crypt/md5 for details.
8 */
9
10/*
11 * Configurable variables. You may need to tweak these to be compatible with
12 * the server-side, but the defaults work in most cases.
13 */
14var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
15var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
16var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */
17
18/*
19 * These are the functions you'll usually want to call
20 * They take string arguments and return either hex or base-64 encoded strings
21 */
22function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));}
23function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));}
24function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));}
25function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));}
26function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));}
27function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));}
28
29/*
30 * Perform a simple self-test to see if the VM is working
31 */
32function sha1_vm_test()
33{
34 return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d";
35}
36
37/*
38 * Calculate the SHA-1 of an array of big-endian words, and a bit length
39 */
40function core_sha1(x, len)
41{
42 /* append padding */
43 x[len >> 5] |= 0x80 << (24 - len % 32);
44 x[((len + 64 >> 9) << 4) + 15] = len;
45
46 var w = Array(80);
47 var a = 1732584193;
48 var b = -271733879;
49 var c = -1732584194;
50 var d = 271733878;
51 var e = -1009589776;
52
53 for(var i = 0; i < x.length; i += 16)
54 {
55 var olda = a;
56 var oldb = b;
57 var oldc = c;
58 var oldd = d;
59 var olde = e;
60
61 for(var j = 0; j < 80; j++)
62 {
63 if(j < 16) w[j] = x[i + j];
64 else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
65 var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)),
66 safe_add(safe_add(e, w[j]), sha1_kt(j)));
67 e = d;
68 d = c;
69 c = rol(b, 30);
70 b = a;
71 a = t;
72 }
73
74 a = safe_add(a, olda);
75 b = safe_add(b, oldb);
76 c = safe_add(c, oldc);
77 d = safe_add(d, oldd);
78 e = safe_add(e, olde);
79 }
80 return Array(a, b, c, d, e);
81
82}
83
84/*
85 * Perform the appropriate triplet combination function for the current
86 * iteration
87 */
88function sha1_ft(t, b, c, d)
89{
90 if(t < 20) return (b & c) | ((~b) & d);
91 if(t < 40) return b ^ c ^ d;
92 if(t < 60) return (b & c) | (b & d) | (c & d);
93 return b ^ c ^ d;
94}
95
96/*
97 * Determine the appropriate additive constant for the current iteration
98 */
99function sha1_kt(t)
100{
101 return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
102 (t < 60) ? -1894007588 : -899497514;
103}
104
105/*
106 * Calculate the HMAC-SHA1 of a key and some data
107 */
108function core_hmac_sha1(key, data)
109{
110 var bkey = str2binb(key);
111 if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz);
112
113 var ipad = Array(16), opad = Array(16);
114 for(var i = 0; i < 16; i++)
115 {
116 ipad[i] = bkey[i] ^ 0x36363636;
117 opad[i] = bkey[i] ^ 0x5C5C5C5C;
118 }
119
120 var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz);
121 return core_sha1(opad.concat(hash), 512 + 160);
122}
123
124/*
125 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
126 * to work around bugs in some JS interpreters.
127 */
128function safe_add(x, y)
129{
130 var lsw = (x & 0xFFFF) + (y & 0xFFFF);
131 var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
132 return (msw << 16) | (lsw & 0xFFFF);
133}
134
135/*
136 * Bitwise rotate a 32-bit number to the left.
137 */
138function rol(num, cnt)
139{
140 return (num << cnt) | (num >>> (32 - cnt));
141}
142
143/*
144 * Convert an 8-bit or 16-bit string to an array of big-endian words
145 * In 8-bit function, characters >255 have their hi-byte silently ignored.
146 */
147function str2binb(str)
148{
149 var bin = Array();
150 var mask = (1 << chrsz) - 1;
151 for(var i = 0; i < str.length * chrsz; i += chrsz)
152 bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32);
153 return bin;
154}
155
156/*
157 * Convert an array of big-endian words to a string
158 */
159function binb2str(bin)
160{
161 var str = "";
162 var mask = (1 << chrsz) - 1;
163 for(var i = 0; i < bin.length * 32; i += chrsz)
164 str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask);
165 return str;
166}
167
168/*
169 * Convert an array of big-endian words to a hex string.
170 */
171function binb2hex(binarray)
172{
173 var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
174 var str = "";
175 for(var i = 0; i < binarray.length * 4; i++)
176 {
177 str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) +
178 hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF);
179 }
180 return str;
181}
182
183/*
184 * Convert an array of big-endian words to a base-64 string
185 */
186function binb2b64(binarray)
187{
188 var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
189 var str = "";
190 for(var i = 0; i < binarray.length * 4; i += 3)
191 {
192 var triplet = (((binarray[i >> 2] >> 8 * (3 - i %4)) & 0xFF) << 16)
193 | (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 )
194 | ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF);
195 for(var j = 0; j < 4; j++)
196 {
197 if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
198 else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
199 }
200 }
201 return str;
202}
0203
=== modified file 'content/sync.js'
--- content/sync.js 2009-08-27 18:45:48 +0000
+++ content/sync.js 2009-09-08 15:29:55 +0000
@@ -112,11 +112,11 @@
112 .getService(Components.interfaces.nsIWindowMediator)112 .getService(Components.interfaces.nsIWindowMediator)
113 .getEnumerator("").getNext() == window) {113 .getEnumerator("").getNext() == window) {
114 Bindwood.writeMessage("First window opened. Getting a Couch Port");114 Bindwood.writeMessage("First window opened. Getting a Couch Port");
115 Bindwood.getCouchPortNumber(Bindwood.startProcess);115 Bindwood.getCouchEnvironment(Bindwood.startProcess);
116 }116 }
117 },117 },
118118
119 getCouchPortNumber: function(continueFunction) {119 getCouchEnvironment: function(continueFunction) {
120 // find the desktop Couch port number by making a D-Bus call120 // find the desktop Couch port number by making a D-Bus call
121 // we call D-Bus by shelling out to a bash script which calls121 // we call D-Bus by shelling out to a bash script which calls
122 // it for us, and writes the port number into a temp file122 // it for us, and writes the port number into a temp file
@@ -139,12 +139,12 @@
139 var MY_ID = "bindwood@ubuntu.com";139 var MY_ID = "bindwood@ubuntu.com";
140 var em = Components.classes["@mozilla.org/extensions/manager;1"].140 var em = Components.classes["@mozilla.org/extensions/manager;1"].
141 getService(Components.interfaces.nsIExtensionManager);141 getService(Components.interfaces.nsIExtensionManager);
142 var dbus_script = em.getInstallLocation(MY_ID).getItemFile(MY_ID, "dbus.sh");142 var couchdb_env_script = em.getInstallLocation(MY_ID).getItemFile(MY_ID, "couchdb_env.sh");
143 Bindwood.writeMessage("Found path to dbus_script: " + dbus_script.path);143 Bindwood.writeMessage("Found path to dbus_script: " + couchdb_env_script.path);
144 // create an nsILocalFile for the executable144 // create an nsILocalFile for the executable
145 var nsifile = Components.classes["@mozilla.org/file/local;1"]145 var nsifile = Components.classes["@mozilla.org/file/local;1"]
146 .createInstance(Components.interfaces.nsILocalFile);146 .createInstance(Components.interfaces.nsILocalFile);
147 nsifile.initWithPath(dbus_script.path);147 nsifile.initWithPath(couchdb_env_script.path);
148148
149 // create an nsIProcess2 to execute this bash script149 // create an nsIProcess2 to execute this bash script
150 var process = Components.classes["@mozilla.org/process/util;1"]150 var process = Components.classes["@mozilla.org/process/util;1"]
@@ -153,14 +153,16 @@
153153
154 // Run the process, passing the tmpfile path154 // Run the process, passing the tmpfile path
155 var args = [tmpfile.path];155 var args = [tmpfile.path];
156 Bindwood.writeMessage("Running dbus script");156 Bindwood.writeMessage("Running couchdb env script");
157 process.runAsync(args, args.length, {157 process.runAsync(args, args.length, {
158 observe: function(process, finishState, unused_data) {158 observe: function(process, finishState, unused_data) {
159 var port = 5984;159 // If the script exists cleanly, we should have a file
160 // containing the port couch is running on as well as
161 // the various OAuth tokens necessary to talk to it.
160 if (finishState == "process-finished") {162 if (finishState == "process-finished") {
161 // read temp file to find port number163 // read temp file to find couch environment
162 // https://developer.mozilla.org/en/Code_snippets/File_I%2f%2fO#Reading_from_a_file164 // https://developer.mozilla.org/en/Code_snippets/File_I%2f%2fO#Reading_from_a_file
163 var data = "";165 var environment;
164 var fstream = Components.classes["@mozilla.org/network/file-input-stream;1"].166 var fstream = Components.classes["@mozilla.org/network/file-input-stream;1"].
165 createInstance(Components.interfaces.nsIFileInputStream);167 createInstance(Components.interfaces.nsIFileInputStream);
166 var cstream = Components.classes["@mozilla.org/intl/converter-input-stream;1"].168 var cstream = Components.classes["@mozilla.org/intl/converter-input-stream;1"].
@@ -169,28 +171,56 @@
169 cstream.init(fstream, "UTF-8", 0, 0);171 cstream.init(fstream, "UTF-8", 0, 0);
170 let (str = {}) {172 let (str = {}) {
171 cstream.readString(-1, str); // read the whole file and put it in str.value173 cstream.readString(-1, str); // read the whole file and put it in str.value
172 data = str.value;174 environment = str.value;
173 };175 };
174 cstream.close(); // this closes fstream176 cstream.close(); // this closes fstream
175 data = data.replace(/^\s\s*/, '').replace(/\s\s*$/, '');177 environment = environment.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
176 if (/^[0-9]+$/.test(data)) {
177 port = data;
178 } else {
179 Bindwood.writeMessage("D-Bus port data is not a number (" + data + ")");
180 }
181 } else {178 } else {
182 // fall back to system CouchDB179 // fall back to system CouchDB
183 Bindwood.writeMessage("D-Bus port find failed");180 Bindwood.writeMessage("D-Bus port find failed");
184 }181 }
185 tmpfile.remove(false);182 tmpfile.remove(false);
186 continueFunction(port);183
187 }184 if (environment == 'ENOCOUCH') {
185 // No Couch environment found. Just spit out a
186 // message and return, stopping Bindwood from
187 // doing anything further.
188 Bindwood.writeError("No suitable Couch environment found. Not proceeding.", e);
189 } else {
190 // If we don't have a Couch environment, don't bother
191 // trying to fall back on the system CouchDB.
192 continueFunction(environment);
193 }
194 }
188 });195 });
189 },196 },
190197
191 startProcess: function(couchPortNumber) {198 startProcess: function(couchEnvironment) {
192 Bindwood.writeMessage("Starting process with Couch on port " + couchPortNumber);199 Bindwood.writeMessage("Starting process with Couch environment: " + couchEnvironment);
193 CouchDB.PORT_NUMBER = couchPortNumber;200
201 var env_array = couchEnvironment.split(':');
202 var port = env_array[0];
203 var consumer_key = env_array[1];
204 var consumer_secret = env_array[2];
205 var token = env_array[3];
206 var token_secret = env_array[4];
207
208 CouchDB.port = port;
209 CouchDB.accessor = {
210 consumerSecret: consumer_secret,
211 tokenSecret: token_secret
212 };
213 CouchDB.message = {
214 parameters: {
215 oauth_callback: "None",
216 oauth_consumer_key: consumer_key,
217 oauth_signature_method: "HMAC-SHA1",
218 oauth_token: token,
219 oauth_verifier: "None",
220 oauth_version: "1.0"
221 }
222 };
223
194 try {224 try {
195 Bindwood.writeMessage("Pushing bookmarks");225 Bindwood.writeMessage("Pushing bookmarks");
196 Bindwood.pushBookmarks();226 Bindwood.pushBookmarks();
@@ -260,10 +290,19 @@
260 }290 }
261 }291 }
262292
263 Bindwood.pushBookmarksFromList(Bindwood.bookmarksService.toolbarFolder,293 try {
264 "toolbarFolder", couch);294 Bindwood.pushBookmarksFromList(Bindwood.bookmarksService.toolbarFolder,
265 Bindwood.pushBookmarksFromList(Bindwood.bookmarksService.bookmarksMenuFolder,295 "toolbarFolder", couch);
266 "bookmarksMenuFolder", couch);296 } catch(e) {
297 Bindwood.writeError("Error pushing toolbarFolder bookmarks: ", e);
298 }
299
300 try {
301 Bindwood.pushBookmarksFromList(Bindwood.bookmarksService.bookmarksMenuFolder,
302 "bookmarksMenuFolder", couch);
303 } catch(e) {
304 Bindwood.writeError("Error pushing bookmarksMenuFolder bookmarks: ", e);
305 }
267 },306 },
268307
269 getBookmarksFromList: function(bookmarksList) {308 getBookmarksFromList: function(bookmarksList) {
@@ -320,15 +359,19 @@
320359
321 Bindwood.uuidItemIdMap[uuid] = itemId;360 Bindwood.uuidItemIdMap[uuid] = itemId;
322361
323 var results = db.query(function(doc) {362 try {
324 if (doc.application_annotations &&363 var results = db.query(function(doc) {
325 doc.application_annotations.Firefox &&364 if (doc.application_annotations &&
326 doc.application_annotations.Firefox.uuid) {365 doc.application_annotations.Firefox &&
327 emit(doc.application_annotations.Firefox.uuid, doc);366 doc.application_annotations.Firefox.uuid) {
328 }367 emit(doc.application_annotations.Firefox.uuid, doc);
329 }, null, {368 }
330 startkey: uuid, endkey: uuid369 }, null, {
331 });370 startkey: uuid, endkey: uuid
371 });
372 } catch(e) {
373 Bindwood.writeError("Error querying couch: ", e);
374 }
332375
333 if (results.rows.length === 0) {376 if (results.rows.length === 0) {
334 // this bookmark is not in CouchDB, so write it377 // this bookmark is not in CouchDB, so write it
@@ -440,7 +483,7 @@
440 Bindwood.writeMessage("The URI from Couch (" + bm.uri + ") is different from local (" + metadata.spec + ")");483 Bindwood.writeMessage("The URI from Couch (" + bm.uri + ") is different from local (" + metadata.spec + ")");
441 try {484 try {
442 var new_uri = Bindwood.ioService.newURI(bm.uri, null, null);485 var new_uri = Bindwood.ioService.newURI(bm.uri, null, null);
443 Bindowod.writeMessage("Creating a new URI for our local bookmark");486 Bindwood.writeMessage("Creating a new URI for our local bookmark");
444 Bindwood.bookmarksService.changeBookmarkURI(itemId, new_uri);487 Bindwood.bookmarksService.changeBookmarkURI(itemId, new_uri);
445 } catch(e) {488 } catch(e) {
446 Bindwood.writeError("Problem creating a new URI for bookmark: ", e);489 Bindwood.writeError("Problem creating a new URI for bookmark: ", e);
@@ -482,7 +525,7 @@
482525
483 try {526 try {
484 var new_uri = Bindwood.ioService.newURI(bm.uri, null, null);527 var new_uri = Bindwood.ioService.newURI(bm.uri, null, null);
485 Bindowod.writeMessage("Creating a new URI for our local bookmark");528 Bindwood.writeMessage("Creating a new URI for our local bookmark");
486 Bindwood.bookmarksService.changeBookmarkURI(itemId, new_uri);529 Bindwood.bookmarksService.changeBookmarkURI(itemId, new_uri);
487 } catch(e) {530 } catch(e) {
488 Bindwood.writeError("Problem creating a new URI for bookmark: ", e);531 Bindwood.writeError("Problem creating a new URI for bookmark: ", e);
489532
=== renamed file 'dbus.sh' => 'couchdb_env.sh'
--- dbus.sh 2009-08-18 14:17:30 +0000
+++ couchdb_env.sh 2009-09-01 19:40:34 +0000
@@ -13,12 +13,16 @@
13# You should have received a copy of the GNU General Public License along13# You should have received a copy of the GNU General Public License along
14# with this program. If not, see <http://www.gnu.org/licenses/>.14# with this program. If not, see <http://www.gnu.org/licenses/>.
15OUT=$115OUT=$1
16PORT=$(dbus-send --session --dest=org.desktopcouch.CouchDB --print-reply --type=method_call / org.desktopcouch.CouchDB.getPort 2>/dev/null | grep int32 | awk '{print $2}' )16
17PORT=$(dbus-send --session --dest=org.desktopcouch.CouchDB --print-reply --type=method_call / org.desktopcouch.CouchDB.getPort 2>/dev/null | grep int32 | awk '{print $2}')
18
19TOKENS=$(python -c "import gnomekeyring; print gnomekeyring.find_items_sync(gnomekeyring.ITEM_GENERIC_SECRET, {'desktopcouch': 'oauth'})[0].secret" 2>/dev/null)
20
17if [ -z "$PORT" ]; then21if [ -z "$PORT" ]; then
18 # D-Bus call failed for some reason, so use default port22 # D-Bus call failed for some reason, so just punt
19 echo 5984 > $OUT23 echo ENOCOUCH > $OUT
20else24else
21 echo $PORT > $OUT25 echo $PORT:$TOKENS > $OUT
22fi26fi
2327
2428

Subscribers

People subscribed via source and target branches