Merge lp:~urbanape/bindwood/using-oauth into lp:bindwood
- using-oauth
- Merge into trunk
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 |
Related bugs: |
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.
Description of the change
To post a comment you must log in.
Revision history for this message
Zachery Bir (urbanape) wrote : | # |
Revision history for this message
Tim Cole (tcole) wrote : | # |
Looks okay. Good catch with the semicolons.
review:
Approve
- 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
1 | === modified file 'content/browserOverlay.xul' | |||
2 | --- content/browserOverlay.xul 2009-08-18 14:17:30 +0000 | |||
3 | +++ content/browserOverlay.xul 2009-09-02 17:07:11 +0000 | |||
4 | @@ -19,6 +19,8 @@ | |||
5 | 19 | <overlay id="bindwood" | 19 | <overlay id="bindwood" |
6 | 20 | xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> | 20 | xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> |
7 | 21 | 21 | ||
8 | 22 | <script type="application/x-javascript" src="chrome://bindwood/content/sha1.js" /> | ||
9 | 23 | <script type="application/x-javascript" src="chrome://bindwood/content/oauth.js" /> | ||
10 | 22 | <script type="application/x-javascript" src="chrome://bindwood/content/couch.js" /> | 24 | <script type="application/x-javascript" src="chrome://bindwood/content/couch.js" /> |
11 | 23 | <script type="application/x-javascript" src="chrome://bindwood/content/sync.js" /> | 25 | <script type="application/x-javascript" src="chrome://bindwood/content/sync.js" /> |
12 | 24 | 26 | ||
13 | 25 | 27 | ||
14 | === modified file 'content/couch.js' | |||
15 | --- content/couch.js 2009-07-08 01:24:33 +0000 | |||
16 | +++ content/couch.js 2009-09-08 15:29:55 +0000 | |||
17 | @@ -1,12 +1,12 @@ | |||
18 | 1 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not | 1 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
21 | 2 | // use this file except in compliance with the License. You may obtain a copy | 2 | // use this file except in compliance with the License. You may obtain a copy of |
22 | 3 | // of the License at | 3 | // the License at |
23 | 4 | // | 4 | // |
24 | 5 | // http://www.apache.org/licenses/LICENSE-2.0 | 5 | // http://www.apache.org/licenses/LICENSE-2.0 |
25 | 6 | // | 6 | // |
26 | 7 | // Unless required by applicable law or agreed to in writing, software | 7 | // Unless required by applicable law or agreed to in writing, software |
27 | 8 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | 8 | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
29 | 9 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | 9 | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
30 | 10 | // License for the specific language governing permissions and limitations under | 10 | // License for the specific language governing permissions and limitations under |
31 | 11 | // the License. | 11 | // the License. |
32 | 12 | 12 | ||
33 | @@ -22,17 +22,26 @@ | |||
34 | 22 | this.last_req = null; | 22 | this.last_req = null; |
35 | 23 | 23 | ||
36 | 24 | this.request = function(method, uri, requestOptions) { | 24 | this.request = function(method, uri, requestOptions) { |
39 | 25 | requestOptions = requestOptions || {} | 25 | CouchDB.message.action = uri; |
40 | 26 | requestOptions.headers = combine(requestOptions.headers, httpHeaders) | 26 | Bindwood.writeMessage("Set the action of the CouchDB.message to: " + uri); |
41 | 27 | CouchDB.message.method = method; | ||
42 | 28 | Bindwood.writeMessage("Set the method of the CouchDB.message to: " + method); | ||
43 | 29 | OAuth.completeRequest(CouchDB.message, CouchDB.accessor); | ||
44 | 30 | Bindwood.writeMessage("Signed the message"); | ||
45 | 31 | var parameters = CouchDB.message.parameters; | ||
46 | 32 | requestOptions = requestOptions || {}; | ||
47 | 33 | requestOptions.headers = combine(requestOptions.headers, httpHeaders); | ||
48 | 34 | requestOptions.headers = combine(requestOptions.headers, {Authorization: OAuth.getAuthorizationHeader('', parameters)}); | ||
49 | 35 | Bindwood.writeMessage("Request headers: " + JSON.stringify(headers)); | ||
50 | 27 | return CouchDB.request(method, uri, requestOptions); | 36 | return CouchDB.request(method, uri, requestOptions); |
52 | 28 | } | 37 | }; |
53 | 29 | 38 | ||
54 | 30 | // Creates the database on the server | 39 | // Creates the database on the server |
55 | 31 | this.createDb = function() { | 40 | this.createDb = function() { |
56 | 32 | this.last_req = this.request("PUT", this.uri); | 41 | this.last_req = this.request("PUT", this.uri); |
57 | 33 | CouchDB.maybeThrowError(this.last_req); | 42 | CouchDB.maybeThrowError(this.last_req); |
58 | 34 | return JSON.parse(this.last_req.responseText); | 43 | return JSON.parse(this.last_req.responseText); |
60 | 35 | } | 44 | }; |
61 | 36 | 45 | ||
62 | 37 | // Deletes the database on the server | 46 | // Deletes the database on the server |
63 | 38 | this.deleteDb = function() { | 47 | this.deleteDb = function() { |
64 | @@ -41,7 +50,7 @@ | |||
65 | 41 | return false; | 50 | return false; |
66 | 42 | CouchDB.maybeThrowError(this.last_req); | 51 | CouchDB.maybeThrowError(this.last_req); |
67 | 43 | return JSON.parse(this.last_req.responseText); | 52 | return JSON.parse(this.last_req.responseText); |
69 | 44 | } | 53 | }; |
70 | 45 | 54 | ||
71 | 46 | // Save a document to the database | 55 | // Save a document to the database |
72 | 47 | this.save = function(doc, options) { | 56 | this.save = function(doc, options) { |
73 | @@ -55,7 +64,7 @@ | |||
74 | 55 | var result = JSON.parse(this.last_req.responseText); | 64 | var result = JSON.parse(this.last_req.responseText); |
75 | 56 | doc._rev = result.rev; | 65 | doc._rev = result.rev; |
76 | 57 | return result; | 66 | return result; |
78 | 58 | } | 67 | }; |
79 | 59 | 68 | ||
80 | 60 | // Open a document from the database | 69 | // Open a document from the database |
81 | 61 | this.open = function(docId, options) { | 70 | this.open = function(docId, options) { |
82 | @@ -64,7 +73,7 @@ | |||
83 | 64 | return null; | 73 | return null; |
84 | 65 | CouchDB.maybeThrowError(this.last_req); | 74 | CouchDB.maybeThrowError(this.last_req); |
85 | 66 | return JSON.parse(this.last_req.responseText); | 75 | return JSON.parse(this.last_req.responseText); |
87 | 67 | } | 76 | }; |
88 | 68 | 77 | ||
89 | 69 | // Deletes a document from the database | 78 | // Deletes a document from the database |
90 | 70 | this.deleteDoc = function(doc) { | 79 | this.deleteDoc = function(doc) { |
91 | @@ -74,7 +83,7 @@ | |||
92 | 74 | doc._rev = result.rev; //record rev in input document | 83 | doc._rev = result.rev; //record rev in input document |
93 | 75 | doc._deleted = true; | 84 | doc._deleted = true; |
94 | 76 | return result; | 85 | return result; |
96 | 77 | } | 86 | }; |
97 | 78 | 87 | ||
98 | 79 | // Deletes an attachment from a document | 88 | // Deletes an attachment from a document |
99 | 80 | this.deleteDocAttachment = function(doc, attachment_name) { | 89 | this.deleteDocAttachment = function(doc, attachment_name) { |
100 | @@ -83,17 +92,17 @@ | |||
101 | 83 | var result = JSON.parse(this.last_req.responseText); | 92 | var result = JSON.parse(this.last_req.responseText); |
102 | 84 | doc._rev = result.rev; //record rev in input document | 93 | doc._rev = result.rev; //record rev in input document |
103 | 85 | return result; | 94 | return result; |
105 | 86 | } | 95 | }; |
106 | 87 | 96 | ||
107 | 88 | this.bulkSave = function(docs, options) { | 97 | this.bulkSave = function(docs, options) { |
108 | 89 | // first prepoulate the UUIDs for new documents | 98 | // first prepoulate the UUIDs for new documents |
110 | 90 | var newCount = 0 | 99 | var newCount = 0; |
111 | 91 | for (var i=0; i<docs.length; i++) { | 100 | for (var i=0; i<docs.length; i++) { |
112 | 92 | if (docs[i]._id == undefined) | 101 | if (docs[i]._id == undefined) |
113 | 93 | newCount++; | 102 | newCount++; |
114 | 94 | } | 103 | } |
115 | 95 | var newUuids = CouchDB.newUuids(docs.length); | 104 | var newUuids = CouchDB.newUuids(docs.length); |
117 | 96 | var newCount = 0 | 105 | var newCount = 0; |
118 | 97 | for (var i=0; i<docs.length; i++) { | 106 | for (var i=0; i<docs.length; i++) { |
119 | 98 | if (docs[i]._id == undefined) | 107 | if (docs[i]._id == undefined) |
120 | 99 | docs[i]._id = newUuids.pop(); | 108 | docs[i]._id = newUuids.pop(); |
121 | @@ -118,17 +127,17 @@ | |||
122 | 118 | } | 127 | } |
123 | 119 | return results; | 128 | return results; |
124 | 120 | } | 129 | } |
126 | 121 | } | 130 | }; |
127 | 122 | 131 | ||
128 | 123 | this.ensureFullCommit = function() { | 132 | this.ensureFullCommit = function() { |
129 | 124 | this.last_req = this.request("POST", this.uri + "_ensure_full_commit"); | 133 | this.last_req = this.request("POST", this.uri + "_ensure_full_commit"); |
130 | 125 | CouchDB.maybeThrowError(this.last_req); | 134 | CouchDB.maybeThrowError(this.last_req); |
131 | 126 | return JSON.parse(this.last_req.responseText); | 135 | return JSON.parse(this.last_req.responseText); |
133 | 127 | } | 136 | }; |
134 | 128 | 137 | ||
135 | 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. |
138 | 130 | this.query = function(mapFun, reduceFun, options, keys) { | 139 | this.query = function(mapFun, reduceFun, options, keys, language) { |
139 | 131 | var body = {language: "javascript"}; | 140 | var body = {language: language || "javascript"}; |
140 | 132 | if(keys) { | 141 | if(keys) { |
141 | 133 | body.keys = keys ; | 142 | body.keys = keys ; |
142 | 134 | } | 143 | } |
143 | @@ -144,13 +153,16 @@ | |||
144 | 144 | body.options = options.options; | 153 | body.options = options.options; |
145 | 145 | delete options.options; | 154 | delete options.options; |
146 | 146 | } | 155 | } |
148 | 147 | this.last_req = this.request("POST", this.uri + "_temp_view" + encodeOptions(options), { | 156 | var uri = this.uri + "_temp_view" + encodeOptions(options); |
149 | 157 | Bindwood.writeMessage("Query URI: " + uri); | ||
150 | 158 | Bindwood.writeMessage("Query body: " + JSON.stringify(body)); | ||
151 | 159 | this.last_req = this.request("POST", uri , { | ||
152 | 148 | headers: {"Content-Type": "application/json"}, | 160 | headers: {"Content-Type": "application/json"}, |
153 | 149 | body: JSON.stringify(body) | 161 | body: JSON.stringify(body) |
154 | 150 | }); | 162 | }); |
155 | 151 | CouchDB.maybeThrowError(this.last_req); | 163 | CouchDB.maybeThrowError(this.last_req); |
156 | 152 | return JSON.parse(this.last_req.responseText); | 164 | return JSON.parse(this.last_req.responseText); |
158 | 153 | } | 165 | }; |
159 | 154 | 166 | ||
160 | 155 | this.view = function(viewname, options, keys) { | 167 | this.view = function(viewname, options, keys) { |
161 | 156 | var viewParts = viewname.split('/'); | 168 | var viewParts = viewname.split('/'); |
162 | @@ -168,14 +180,27 @@ | |||
163 | 168 | return null; | 180 | return null; |
164 | 169 | CouchDB.maybeThrowError(this.last_req); | 181 | CouchDB.maybeThrowError(this.last_req); |
165 | 170 | return JSON.parse(this.last_req.responseText); | 182 | return JSON.parse(this.last_req.responseText); |
167 | 171 | } | 183 | }; |
168 | 172 | 184 | ||
169 | 173 | // gets information about the database | 185 | // gets information about the database |
170 | 174 | this.info = function() { | 186 | this.info = function() { |
171 | 175 | this.last_req = this.request("GET", this.uri); | 187 | this.last_req = this.request("GET", this.uri); |
172 | 176 | CouchDB.maybeThrowError(this.last_req); | 188 | CouchDB.maybeThrowError(this.last_req); |
173 | 177 | return JSON.parse(this.last_req.responseText); | 189 | return JSON.parse(this.last_req.responseText); |
175 | 178 | } | 190 | }; |
176 | 191 | |||
177 | 192 | // gets information about a design doc | ||
178 | 193 | this.designInfo = function(docid) { | ||
179 | 194 | this.last_req = this.request("GET", this.uri + docid + "/_info"); | ||
180 | 195 | CouchDB.maybeThrowError(this.last_req); | ||
181 | 196 | return JSON.parse(this.last_req.responseText); | ||
182 | 197 | }; | ||
183 | 198 | |||
184 | 199 | this.viewCleanup = function() { | ||
185 | 200 | this.last_req = this.request("POST", this.uri + "_view_cleanup"); | ||
186 | 201 | CouchDB.maybeThrowError(this.last_req); | ||
187 | 202 | return JSON.parse(this.last_req.responseText); | ||
188 | 203 | }; | ||
189 | 179 | 204 | ||
190 | 180 | this.allDocs = function(options,keys) { | 205 | this.allDocs = function(options,keys) { |
191 | 181 | if(!keys) { | 206 | if(!keys) { |
192 | @@ -188,7 +213,7 @@ | |||
193 | 188 | } | 213 | } |
194 | 189 | CouchDB.maybeThrowError(this.last_req); | 214 | CouchDB.maybeThrowError(this.last_req); |
195 | 190 | return JSON.parse(this.last_req.responseText); | 215 | return JSON.parse(this.last_req.responseText); |
197 | 191 | } | 216 | }; |
198 | 192 | 217 | ||
199 | 193 | this.designDocs = function() { | 218 | this.designDocs = function() { |
200 | 194 | return this.allDocs({startkey:"_design", endkey:"_design0"}); | 219 | return this.allDocs({startkey:"_design", endkey:"_design0"}); |
201 | @@ -206,13 +231,13 @@ | |||
202 | 206 | } | 231 | } |
203 | 207 | CouchDB.maybeThrowError(req); | 232 | CouchDB.maybeThrowError(req); |
204 | 208 | return JSON.parse(req.responseText); | 233 | return JSON.parse(req.responseText); |
206 | 209 | } | 234 | }; |
207 | 210 | 235 | ||
208 | 211 | this.compact = function() { | 236 | this.compact = function() { |
209 | 212 | this.last_req = this.request("POST", this.uri + "_compact"); | 237 | this.last_req = this.request("POST", this.uri + "_compact"); |
210 | 213 | CouchDB.maybeThrowError(this.last_req); | 238 | CouchDB.maybeThrowError(this.last_req); |
211 | 214 | return JSON.parse(this.last_req.responseText); | 239 | return JSON.parse(this.last_req.responseText); |
213 | 215 | } | 240 | }; |
214 | 216 | 241 | ||
215 | 217 | this.setDbProperty = function(propId, propValue) { | 242 | this.setDbProperty = function(propId, propValue) { |
216 | 218 | this.last_req = this.request("PUT", this.uri + propId,{ | 243 | this.last_req = this.request("PUT", this.uri + propId,{ |
217 | @@ -220,13 +245,13 @@ | |||
218 | 220 | }); | 245 | }); |
219 | 221 | CouchDB.maybeThrowError(this.last_req); | 246 | CouchDB.maybeThrowError(this.last_req); |
220 | 222 | return JSON.parse(this.last_req.responseText); | 247 | return JSON.parse(this.last_req.responseText); |
222 | 223 | } | 248 | }; |
223 | 224 | 249 | ||
224 | 225 | this.getDbProperty = function(propId) { | 250 | this.getDbProperty = function(propId) { |
225 | 226 | this.last_req = this.request("GET", this.uri + propId); | 251 | this.last_req = this.request("GET", this.uri + propId); |
226 | 227 | CouchDB.maybeThrowError(this.last_req); | 252 | CouchDB.maybeThrowError(this.last_req); |
227 | 228 | return JSON.parse(this.last_req.responseText); | 253 | return JSON.parse(this.last_req.responseText); |
229 | 229 | } | 254 | }; |
230 | 230 | 255 | ||
231 | 231 | this.setAdmins = function(adminsArray) { | 256 | this.setAdmins = function(adminsArray) { |
232 | 232 | this.last_req = this.request("PUT", this.uri + "_admins",{ | 257 | this.last_req = this.request("PUT", this.uri + "_admins",{ |
233 | @@ -234,18 +259,18 @@ | |||
234 | 234 | }); | 259 | }); |
235 | 235 | CouchDB.maybeThrowError(this.last_req); | 260 | CouchDB.maybeThrowError(this.last_req); |
236 | 236 | return JSON.parse(this.last_req.responseText); | 261 | return JSON.parse(this.last_req.responseText); |
238 | 237 | } | 262 | }; |
239 | 238 | 263 | ||
240 | 239 | this.getAdmins = function() { | 264 | this.getAdmins = function() { |
241 | 240 | this.last_req = this.request("GET", this.uri + "_admins"); | 265 | this.last_req = this.request("GET", this.uri + "_admins"); |
242 | 241 | CouchDB.maybeThrowError(this.last_req); | 266 | CouchDB.maybeThrowError(this.last_req); |
243 | 242 | return JSON.parse(this.last_req.responseText); | 267 | return JSON.parse(this.last_req.responseText); |
245 | 243 | } | 268 | }; |
246 | 244 | 269 | ||
247 | 245 | // Convert a options object to an url query string. | 270 | // Convert a options object to an url query string. |
248 | 246 | // ex: {key:'value',key2:'value2'} becomes '?key="value"&key2="value2"' | 271 | // ex: {key:'value',key2:'value2'} becomes '?key="value"&key2="value2"' |
249 | 247 | function encodeOptions(options) { | 272 | function encodeOptions(options) { |
251 | 248 | var buf = [] | 273 | var buf = []; |
252 | 249 | if (typeof(options) == "object" && options !== null) { | 274 | if (typeof(options) == "object" && options !== null) { |
253 | 250 | for (var name in options) { | 275 | for (var name in options) { |
254 | 251 | if (!options.hasOwnProperty(name)) continue; | 276 | if (!options.hasOwnProperty(name)) continue; |
255 | @@ -278,22 +303,82 @@ | |||
256 | 278 | return object1; | 303 | return object1; |
257 | 279 | } | 304 | } |
258 | 280 | 305 | ||
259 | 281 | |||
260 | 282 | } | 306 | } |
261 | 283 | 307 | ||
262 | 284 | CouchDB.PORT_NUMBER = 5984; // default | ||
263 | 285 | |||
264 | 286 | // this is the XMLHttpRequest object from last request made by the following | 308 | // this is the XMLHttpRequest object from last request made by the following |
265 | 287 | // CouchDB.* functions (except for calls to request itself). | 309 | // CouchDB.* functions (except for calls to request itself). |
266 | 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. |
267 | 289 | CouchDB.last_req = null; | 311 | CouchDB.last_req = null; |
268 | 290 | 312 | ||
269 | 313 | CouchDB.login = function(username, password) { | ||
270 | 314 | CouchDB.last_req = CouchDB.request("POST", "/_session", { | ||
271 | 315 | headers: {"Content-Type": "application/x-www-form-urlencoded", | ||
272 | 316 | "X-CouchDB-WWW-Authenticate": "Cookie"}, | ||
273 | 317 | body: "username=" + encodeURIComponent(username) + "&password=" + encodeURIComponent(password) | ||
274 | 318 | }); | ||
275 | 319 | return JSON.parse(CouchDB.last_req.responseText); | ||
276 | 320 | }; | ||
277 | 321 | |||
278 | 322 | CouchDB.logout = function() { | ||
279 | 323 | CouchDB.last_req = CouchDB.request("DELETE", "/_session", { | ||
280 | 324 | headers: {"Content-Type": "application/x-www-form-urlencoded", | ||
281 | 325 | "X-CouchDB-WWW-Authenticate": "Cookie"} | ||
282 | 326 | }); | ||
283 | 327 | return JSON.parse(CouchDB.last_req.responseText); | ||
284 | 328 | }; | ||
285 | 329 | |||
286 | 330 | CouchDB.createUser = function(username, password, email, roles, basicAuth) { | ||
287 | 331 | var roles_str = ""; | ||
288 | 332 | if (roles) { | ||
289 | 333 | for (var i=0; i< roles.length; i++) { | ||
290 | 334 | roles_str += "&roles=" + encodeURIComponent(roles[i]); | ||
291 | 335 | } | ||
292 | 336 | } | ||
293 | 337 | var headers = {"Content-Type": "application/x-www-form-urlencoded"}; | ||
294 | 338 | if (basicAuth) { | ||
295 | 339 | headers['Authorization'] = basicAuth; | ||
296 | 340 | } else { | ||
297 | 341 | headers['X-CouchDB-WWW-Authenticate'] = 'Cookie'; | ||
298 | 342 | } | ||
299 | 343 | |||
300 | 344 | CouchDB.last_req = CouchDB.request("POST", "/_user/", { | ||
301 | 345 | headers: headers, | ||
302 | 346 | body: "username=" + encodeURIComponent(username) + "&password=" + encodeURIComponent(password) | ||
303 | 347 | + "&email="+ encodeURIComponent(email)+ roles_str | ||
304 | 348 | |||
305 | 349 | }); | ||
306 | 350 | return JSON.parse(CouchDB.last_req.responseText); | ||
307 | 351 | }; | ||
308 | 352 | |||
309 | 353 | CouchDB.updateUser = function(username, email, roles, password, old_password) { | ||
310 | 354 | var roles_str = ""; | ||
311 | 355 | if (roles) { | ||
312 | 356 | for (var i=0; i< roles.length; i++) { | ||
313 | 357 | roles_str += "&roles=" + encodeURIComponent(roles[i]); | ||
314 | 358 | } | ||
315 | 359 | } | ||
316 | 360 | |||
317 | 361 | var body = "email="+ encodeURIComponent(email)+ roles_str; | ||
318 | 362 | |||
319 | 363 | if (typeof(password) != "undefined" && password) | ||
320 | 364 | body += "&password=" + password; | ||
321 | 365 | |||
322 | 366 | if (typeof(old_password) != "undefined" && old_password) | ||
323 | 367 | body += "&old_password=" + old_password; | ||
324 | 368 | |||
325 | 369 | CouchDB.last_req = CouchDB.request("PUT", "/_user/"+encodeURIComponent(username), { | ||
326 | 370 | headers: {"Content-Type": "application/x-www-form-urlencoded", | ||
327 | 371 | "X-CouchDB-WWW-Authenticate": "Cookie"}, | ||
328 | 372 | body: body | ||
329 | 373 | }); | ||
330 | 374 | return JSON.parse(CouchDB.last_req.responseText); | ||
331 | 375 | }; | ||
332 | 291 | 376 | ||
333 | 292 | CouchDB.allDbs = function() { | 377 | CouchDB.allDbs = function() { |
334 | 293 | CouchDB.last_req = CouchDB.request("GET", "/_all_dbs"); | 378 | CouchDB.last_req = CouchDB.request("GET", "/_all_dbs"); |
335 | 294 | CouchDB.maybeThrowError(CouchDB.last_req); | 379 | CouchDB.maybeThrowError(CouchDB.last_req); |
336 | 295 | return JSON.parse(CouchDB.last_req.responseText); | 380 | return JSON.parse(CouchDB.last_req.responseText); |
338 | 296 | } | 381 | }; |
339 | 297 | 382 | ||
340 | 298 | CouchDB.allDesignDocs = function() { | 383 | CouchDB.allDesignDocs = function() { |
341 | 299 | var ddocs = {}, dbs = CouchDB.allDbs(); | 384 | var ddocs = {}, dbs = CouchDB.allDbs(); |
342 | @@ -308,7 +393,7 @@ | |||
343 | 308 | CouchDB.last_req = CouchDB.request("GET", "/"); | 393 | CouchDB.last_req = CouchDB.request("GET", "/"); |
344 | 309 | CouchDB.maybeThrowError(CouchDB.last_req); | 394 | CouchDB.maybeThrowError(CouchDB.last_req); |
345 | 310 | return JSON.parse(CouchDB.last_req.responseText).version; | 395 | return JSON.parse(CouchDB.last_req.responseText).version; |
347 | 311 | } | 396 | }; |
348 | 312 | 397 | ||
349 | 313 | CouchDB.replicate = function(source, target, rep_options) { | 398 | CouchDB.replicate = function(source, target, rep_options) { |
350 | 314 | rep_options = rep_options || {}; | 399 | rep_options = rep_options || {}; |
351 | @@ -319,29 +404,40 @@ | |||
352 | 319 | }); | 404 | }); |
353 | 320 | CouchDB.maybeThrowError(CouchDB.last_req); | 405 | CouchDB.maybeThrowError(CouchDB.last_req); |
354 | 321 | return JSON.parse(CouchDB.last_req.responseText); | 406 | return JSON.parse(CouchDB.last_req.responseText); |
356 | 322 | } | 407 | }; |
357 | 323 | 408 | ||
361 | 324 | CouchDB.request = function(method, uri, options) { | 409 | CouchDB.newXhr = function() { |
359 | 325 | options = options || {}; | ||
360 | 326 | var req = null; | ||
362 | 327 | if (typeof(XMLHttpRequest) != "undefined") { | 410 | if (typeof(XMLHttpRequest) != "undefined") { |
364 | 328 | req = new XMLHttpRequest(); | 411 | return new XMLHttpRequest(); |
365 | 329 | } else if (typeof(ActiveXObject) != "undefined") { | 412 | } else if (typeof(ActiveXObject) != "undefined") { |
367 | 330 | req = new ActiveXObject("Microsoft.XMLHTTP"); | 413 | return new ActiveXObject("Microsoft.XMLHTTP"); |
368 | 331 | } else { | 414 | } else { |
369 | 332 | throw new Error("No XMLHTTPRequest support detected"); | 415 | throw new Error("No XMLHTTPRequest support detected"); |
370 | 333 | } | 416 | } |
372 | 334 | req.open(method, "http://localhost:" + CouchDB.PORT_NUMBER + uri, false); | 417 | }; |
373 | 418 | |||
374 | 419 | CouchDB.request = function(method, uri, options) { | ||
375 | 420 | options = options || {}; | ||
376 | 421 | var req = CouchDB.newXhr(); | ||
377 | 422 | var computed_uri = "http://localhost:" + CouchDB.port + uri; | ||
378 | 423 | Bindwood.writeMessage("Opening a request to: " + computed_uri); | ||
379 | 424 | req.open(method, computed_uri, false); | ||
380 | 335 | if (options.headers) { | 425 | if (options.headers) { |
381 | 426 | Bindwood.writeMessage("Setting optional headers"); | ||
382 | 336 | var headers = options.headers; | 427 | var headers = options.headers; |
383 | 337 | for (var headerName in headers) { | 428 | for (var headerName in headers) { |
384 | 338 | if (!headers.hasOwnProperty(headerName)) continue; | 429 | if (!headers.hasOwnProperty(headerName)) continue; |
385 | 339 | req.setRequestHeader(headerName, headers[headerName]); | 430 | req.setRequestHeader(headerName, headers[headerName]); |
386 | 340 | } | 431 | } |
387 | 341 | } | 432 | } |
389 | 342 | req.send(options.body || ""); | 433 | Bindwood.writeMessage("Sending the request"); |
390 | 434 | try { | ||
391 | 435 | req.send(options.body || ""); | ||
392 | 436 | } catch(e) { | ||
393 | 437 | Bindwood.writeError("Problem sending request: ", e); | ||
394 | 438 | } | ||
395 | 343 | return req; | 439 | return req; |
397 | 344 | } | 440 | }; |
398 | 345 | 441 | ||
399 | 346 | CouchDB.requestStats = function(module, key, test) { | 442 | CouchDB.requestStats = function(module, key, test) { |
400 | 347 | var query_arg = ""; | 443 | var query_arg = ""; |
401 | @@ -351,7 +447,7 @@ | |||
402 | 351 | 447 | ||
403 | 352 | var stat = CouchDB.request("GET", "/_stats/" + module + "/" + key + query_arg).responseText; | 448 | var stat = CouchDB.request("GET", "/_stats/" + module + "/" + key + query_arg).responseText; |
404 | 353 | return JSON.parse(stat)[module][key]; | 449 | return JSON.parse(stat)[module][key]; |
406 | 354 | } | 450 | }; |
407 | 355 | 451 | ||
408 | 356 | CouchDB.uuids_cache = []; | 452 | CouchDB.uuids_cache = []; |
409 | 357 | 453 | ||
410 | @@ -373,7 +469,7 @@ | |||
411 | 373 | CouchDB.uuids_cache.concat(result.uuids.slice(0, 100)); | 469 | CouchDB.uuids_cache.concat(result.uuids.slice(0, 100)); |
412 | 374 | return result.uuids.slice(100); | 470 | return result.uuids.slice(100); |
413 | 375 | } | 471 | } |
415 | 376 | } | 472 | }; |
416 | 377 | 473 | ||
417 | 378 | CouchDB.maybeThrowError = function(req) { | 474 | CouchDB.maybeThrowError = function(req) { |
418 | 379 | if (req.status >= 400) { | 475 | if (req.status >= 400) { |
419 | @@ -384,7 +480,7 @@ | |||
420 | 384 | } | 480 | } |
421 | 385 | throw result; | 481 | throw result; |
422 | 386 | } | 482 | } |
424 | 387 | } | 483 | }; |
425 | 388 | 484 | ||
426 | 389 | CouchDB.params = function(options) { | 485 | CouchDB.params = function(options) { |
427 | 390 | options = options || {}; | 486 | options = options || {}; |
428 | @@ -394,4 +490,4 @@ | |||
429 | 394 | returnArray.push(key + "=" + value); | 490 | returnArray.push(key + "=" + value); |
430 | 395 | } | 491 | } |
431 | 396 | return returnArray.join("&"); | 492 | return returnArray.join("&"); |
433 | 397 | } | 493 | }; |
434 | 398 | 494 | ||
435 | === added file 'content/oauth.js' | |||
436 | --- content/oauth.js 1970-01-01 00:00:00 +0000 | |||
437 | +++ content/oauth.js 2009-09-04 14:10:27 +0000 | |||
438 | @@ -0,0 +1,515 @@ | |||
439 | 1 | /* | ||
440 | 2 | * Copyright 2008 Netflix, Inc. | ||
441 | 3 | * | ||
442 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
443 | 5 | * you may not use this file except in compliance with the License. | ||
444 | 6 | * You may obtain a copy of the License at | ||
445 | 7 | * | ||
446 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
447 | 9 | * | ||
448 | 10 | * Unless required by applicable law or agreed to in writing, software | ||
449 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
450 | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
451 | 13 | * See the License for the specific language governing permissions and | ||
452 | 14 | * limitations under the License. | ||
453 | 15 | */ | ||
454 | 16 | |||
455 | 17 | /* Here's some JavaScript software for implementing OAuth. | ||
456 | 18 | |||
457 | 19 | This isn't as useful as you might hope. OAuth is based around | ||
458 | 20 | allowing tools and websites to talk to each other. However, | ||
459 | 21 | JavaScript running in web browsers is hampered by security | ||
460 | 22 | restrictions that prevent code running on one website from | ||
461 | 23 | accessing data stored or served on another. | ||
462 | 24 | |||
463 | 25 | Before you start hacking, make sure you understand the limitations | ||
464 | 26 | posed by cross-domain XMLHttpRequest. | ||
465 | 27 | |||
466 | 28 | On the bright side, some platforms use JavaScript as their | ||
467 | 29 | language, but enable the programmer to access other web sites. | ||
468 | 30 | Examples include Google Gadgets, and Microsoft Vista Sidebar. | ||
469 | 31 | For those platforms, this library should come in handy. | ||
470 | 32 | */ | ||
471 | 33 | |||
472 | 34 | // The HMAC-SHA1 signature method calls b64_hmac_sha1, defined by | ||
473 | 35 | // http://pajhome.org.uk/crypt/md5/sha1.js | ||
474 | 36 | |||
475 | 37 | /* An OAuth message is represented as an object like this: | ||
476 | 38 | {method: "GET", action: "http://server.com/path", parameters: ...} | ||
477 | 39 | |||
478 | 40 | The parameters may be either a map {name: value, name2: value2} | ||
479 | 41 | or an Array of name-value pairs [[name, value], [name2, value2]]. | ||
480 | 42 | The latter representation is more powerful: it supports parameters | ||
481 | 43 | in a specific sequence, or several parameters with the same name; | ||
482 | 44 | for example [["a", 1], ["b", 2], ["a", 3]]. | ||
483 | 45 | |||
484 | 46 | Parameter names and values are NOT percent-encoded in an object. | ||
485 | 47 | They must be encoded before transmission and decoded after reception. | ||
486 | 48 | For example, this message object: | ||
487 | 49 | {method: "GET", action: "http://server/path", parameters: {p: "x y"}} | ||
488 | 50 | ... can be transmitted as an HTTP request that begins: | ||
489 | 51 | GET /path?p=x%20y HTTP/1.0 | ||
490 | 52 | (This isn't a valid OAuth request, since it lacks a signature etc.) | ||
491 | 53 | Note that the object "x y" is transmitted as x%20y. To encode | ||
492 | 54 | parameters, you can call OAuth.addToURL, OAuth.formEncode or | ||
493 | 55 | OAuth.getAuthorization. | ||
494 | 56 | |||
495 | 57 | This message object model harmonizes with the browser object model for | ||
496 | 58 | input elements of an form, whose value property isn't percent encoded. | ||
497 | 59 | The browser encodes each value before transmitting it. For example, | ||
498 | 60 | see consumer.setInputs in example/consumer.js. | ||
499 | 61 | */ | ||
500 | 62 | var OAuth; if (OAuth == null) OAuth = {}; | ||
501 | 63 | |||
502 | 64 | OAuth.setProperties = function setProperties(into, from) { | ||
503 | 65 | if (into != null && from != null) { | ||
504 | 66 | for (var key in from) { | ||
505 | 67 | into[key] = from[key]; | ||
506 | 68 | } | ||
507 | 69 | } | ||
508 | 70 | return into; | ||
509 | 71 | } | ||
510 | 72 | |||
511 | 73 | OAuth.setProperties(OAuth, // utility functions | ||
512 | 74 | { | ||
513 | 75 | percentEncode: function percentEncode(s) { | ||
514 | 76 | if (s == null) { | ||
515 | 77 | return ""; | ||
516 | 78 | } | ||
517 | 79 | if (s instanceof Array) { | ||
518 | 80 | var e = ""; | ||
519 | 81 | for (var i = 0; i < s.length; ++s) { | ||
520 | 82 | if (e != "") e += '&'; | ||
521 | 83 | e += percentEncode(s[i]); | ||
522 | 84 | } | ||
523 | 85 | return e; | ||
524 | 86 | } | ||
525 | 87 | s = encodeURIComponent(s); | ||
526 | 88 | // Now replace the values which encodeURIComponent doesn't do | ||
527 | 89 | // encodeURIComponent ignores: - _ . ! ~ * ' ( ) | ||
528 | 90 | // OAuth dictates the only ones you can ignore are: - _ . ~ | ||
529 | 91 | // Source: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Functions:encodeURIComponent | ||
530 | 92 | s = s.replace(/\!/g, "%21"); | ||
531 | 93 | s = s.replace(/\*/g, "%2A"); | ||
532 | 94 | s = s.replace(/\'/g, "%27"); | ||
533 | 95 | s = s.replace(/\(/g, "%28"); | ||
534 | 96 | s = s.replace(/\)/g, "%29"); | ||
535 | 97 | return s; | ||
536 | 98 | } | ||
537 | 99 | , | ||
538 | 100 | decodePercent: function decodePercent(s) { | ||
539 | 101 | if (s != null) { | ||
540 | 102 | // Handle application/x-www-form-urlencoded, which is defined by | ||
541 | 103 | // http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1 | ||
542 | 104 | s = s.replace(/\+/g, " "); | ||
543 | 105 | } | ||
544 | 106 | return decodeURIComponent(s); | ||
545 | 107 | } | ||
546 | 108 | , | ||
547 | 109 | /** Convert the given parameters to an Array of name-value pairs. */ | ||
548 | 110 | getParameterList: function getParameterList(parameters) { | ||
549 | 111 | if (parameters == null) { | ||
550 | 112 | return []; | ||
551 | 113 | } | ||
552 | 114 | if (typeof parameters != "object") { | ||
553 | 115 | return decodeForm(parameters + ""); | ||
554 | 116 | } | ||
555 | 117 | if (parameters instanceof Array) { | ||
556 | 118 | return parameters; | ||
557 | 119 | } | ||
558 | 120 | var list = []; | ||
559 | 121 | for (var p in parameters) { | ||
560 | 122 | list.push([p, parameters[p]]); | ||
561 | 123 | } | ||
562 | 124 | return list; | ||
563 | 125 | } | ||
564 | 126 | , | ||
565 | 127 | /** Convert the given parameters to a map from name to value. */ | ||
566 | 128 | getParameterMap: function getParameterMap(parameters) { | ||
567 | 129 | if (parameters == null) { | ||
568 | 130 | return {}; | ||
569 | 131 | } | ||
570 | 132 | if (typeof parameters != "object") { | ||
571 | 133 | return getParameterMap(decodeForm(parameters + "")); | ||
572 | 134 | } | ||
573 | 135 | if (parameters instanceof Array) { | ||
574 | 136 | var map = {}; | ||
575 | 137 | for (var p = 0; p < parameters.length; ++p) { | ||
576 | 138 | var key = parameters[p][0]; | ||
577 | 139 | if (map[key] === undefined) { // first value wins | ||
578 | 140 | map[key] = parameters[p][1]; | ||
579 | 141 | } | ||
580 | 142 | } | ||
581 | 143 | return map; | ||
582 | 144 | } | ||
583 | 145 | return parameters; | ||
584 | 146 | } | ||
585 | 147 | , | ||
586 | 148 | getParameter: function getParameter(parameters, name) { | ||
587 | 149 | if (parameters instanceof Array) { | ||
588 | 150 | for (var p = 0; p < parameters.length; ++p) { | ||
589 | 151 | if (parameters[p][0] == name) { | ||
590 | 152 | return parameters[p][1]; // first value wins | ||
591 | 153 | } | ||
592 | 154 | } | ||
593 | 155 | } else { | ||
594 | 156 | return OAuth.getParameterMap(parameters)[name]; | ||
595 | 157 | } | ||
596 | 158 | return null; | ||
597 | 159 | } | ||
598 | 160 | , | ||
599 | 161 | formEncode: function formEncode(parameters) { | ||
600 | 162 | var form = ""; | ||
601 | 163 | var list = OAuth.getParameterList(parameters); | ||
602 | 164 | for (var p = 0; p < list.length; ++p) { | ||
603 | 165 | var value = list[p][1]; | ||
604 | 166 | if (value == null) value = ""; | ||
605 | 167 | if (form != "") form += '&'; | ||
606 | 168 | form += OAuth.percentEncode(list[p][0]) | ||
607 | 169 | +'='+ OAuth.percentEncode(value); | ||
608 | 170 | } | ||
609 | 171 | return form; | ||
610 | 172 | } | ||
611 | 173 | , | ||
612 | 174 | decodeForm: function decodeForm(form) { | ||
613 | 175 | var list = []; | ||
614 | 176 | var nvps = form.split('&'); | ||
615 | 177 | for (var n = 0; n < nvps.length; ++n) { | ||
616 | 178 | var nvp = nvps[n]; | ||
617 | 179 | if (nvp == "") { | ||
618 | 180 | continue; | ||
619 | 181 | } | ||
620 | 182 | var equals = nvp.indexOf('='); | ||
621 | 183 | var name; | ||
622 | 184 | var value; | ||
623 | 185 | if (equals < 0) { | ||
624 | 186 | name = OAuth.decodePercent(nvp); | ||
625 | 187 | value = null; | ||
626 | 188 | } else { | ||
627 | 189 | name = OAuth.decodePercent(nvp.substring(0, equals)); | ||
628 | 190 | value = OAuth.decodePercent(nvp.substring(equals + 1)); | ||
629 | 191 | } | ||
630 | 192 | list.push([name, value]); | ||
631 | 193 | } | ||
632 | 194 | return list; | ||
633 | 195 | } | ||
634 | 196 | , | ||
635 | 197 | setParameter: function setParameter(message, name, value) { | ||
636 | 198 | var parameters = message.parameters; | ||
637 | 199 | if (parameters instanceof Array) { | ||
638 | 200 | for (var p = 0; p < parameters.length; ++p) { | ||
639 | 201 | if (parameters[p][0] == name) { | ||
640 | 202 | if (value === undefined) { | ||
641 | 203 | parameters.splice(p, 1); | ||
642 | 204 | } else { | ||
643 | 205 | parameters[p][1] = value; | ||
644 | 206 | value = undefined; | ||
645 | 207 | } | ||
646 | 208 | } | ||
647 | 209 | } | ||
648 | 210 | if (value !== undefined) { | ||
649 | 211 | parameters.push([name, value]); | ||
650 | 212 | } | ||
651 | 213 | } else { | ||
652 | 214 | parameters = OAuth.getParameterMap(parameters); | ||
653 | 215 | parameters[name] = value; | ||
654 | 216 | message.parameters = parameters; | ||
655 | 217 | } | ||
656 | 218 | } | ||
657 | 219 | , | ||
658 | 220 | setParameters: function setParameters(message, parameters) { | ||
659 | 221 | var list = OAuth.getParameterList(parameters); | ||
660 | 222 | for (var i = 0; i < list.length; ++i) { | ||
661 | 223 | OAuth.setParameter(message, list[i][0], list[i][1]); | ||
662 | 224 | } | ||
663 | 225 | } | ||
664 | 226 | , | ||
665 | 227 | /** Fill in parameters to help construct a request message. | ||
666 | 228 | This function doesn't fill in every parameter. | ||
667 | 229 | The accessor object should be like: | ||
668 | 230 | {consumerKey:'foo', consumerSecret:'bar', accessorSecret:'nurn', token:'krelm', tokenSecret:'blah'} | ||
669 | 231 | The accessorSecret property is optional. | ||
670 | 232 | */ | ||
671 | 233 | completeRequest: function completeRequest(message, accessor) { | ||
672 | 234 | if (message.method == null) { | ||
673 | 235 | message.method = "GET"; | ||
674 | 236 | } | ||
675 | 237 | var map = OAuth.getParameterMap(message.parameters); | ||
676 | 238 | if (map.oauth_consumer_key == null) { | ||
677 | 239 | OAuth.setParameter(message, "oauth_consumer_key", accessor.consumerKey || ""); | ||
678 | 240 | } | ||
679 | 241 | if (map.oauth_token == null && accessor.token != null) { | ||
680 | 242 | OAuth.setParameter(message, "oauth_token", accessor.token); | ||
681 | 243 | } | ||
682 | 244 | if (map.oauth_version == null) { | ||
683 | 245 | OAuth.setParameter(message, "oauth_version", "1.0"); | ||
684 | 246 | } | ||
685 | 247 | if (map.oauth_timestamp == null) { | ||
686 | 248 | OAuth.setParameter(message, "oauth_timestamp", OAuth.timestamp()); | ||
687 | 249 | } | ||
688 | 250 | if (map.oauth_nonce == null) { | ||
689 | 251 | OAuth.setParameter(message, "oauth_nonce", OAuth.nonce(6)); | ||
690 | 252 | } | ||
691 | 253 | OAuth.SignatureMethod.sign(message, accessor); | ||
692 | 254 | } | ||
693 | 255 | , | ||
694 | 256 | setTimestampAndNonce: function setTimestampAndNonce(message) { | ||
695 | 257 | OAuth.setParameter(message, "oauth_timestamp", OAuth.timestamp()); | ||
696 | 258 | OAuth.setParameter(message, "oauth_nonce", OAuth.nonce(6)); | ||
697 | 259 | } | ||
698 | 260 | , | ||
699 | 261 | addToURL: function addToURL(url, parameters) { | ||
700 | 262 | newURL = url; | ||
701 | 263 | if (parameters != null) { | ||
702 | 264 | var toAdd = OAuth.formEncode(parameters); | ||
703 | 265 | if (toAdd.length > 0) { | ||
704 | 266 | var q = url.indexOf('?'); | ||
705 | 267 | if (q < 0) newURL += '?'; | ||
706 | 268 | else newURL += '&'; | ||
707 | 269 | newURL += toAdd; | ||
708 | 270 | } | ||
709 | 271 | } | ||
710 | 272 | return newURL; | ||
711 | 273 | } | ||
712 | 274 | , | ||
713 | 275 | /** Construct the value of the Authorization header for an HTTP request. */ | ||
714 | 276 | getAuthorizationHeader: function getAuthorizationHeader(realm, parameters) { | ||
715 | 277 | var header = 'OAuth realm="' + OAuth.percentEncode(realm) + '"'; | ||
716 | 278 | var list = OAuth.getParameterList(parameters); | ||
717 | 279 | for (var p = 0; p < list.length; ++p) { | ||
718 | 280 | var parameter = list[p]; | ||
719 | 281 | var name = parameter[0]; | ||
720 | 282 | if (name.indexOf("oauth_") == 0) { | ||
721 | 283 | header += ',' + OAuth.percentEncode(name) + '="' + OAuth.percentEncode(parameter[1]) + '"'; | ||
722 | 284 | } | ||
723 | 285 | } | ||
724 | 286 | return header; | ||
725 | 287 | } | ||
726 | 288 | , | ||
727 | 289 | timestamp: function timestamp() { | ||
728 | 290 | var d = new Date(); | ||
729 | 291 | return Math.floor(d.getTime()/1000); | ||
730 | 292 | } | ||
731 | 293 | , | ||
732 | 294 | nonce: function nonce(length) { | ||
733 | 295 | var chars = OAuth.nonce.CHARS; | ||
734 | 296 | var result = ""; | ||
735 | 297 | for (var i = 0; i < length; ++i) { | ||
736 | 298 | var rnum = Math.floor(Math.random() * chars.length); | ||
737 | 299 | result += chars.substring(rnum, rnum+1); | ||
738 | 300 | } | ||
739 | 301 | return result; | ||
740 | 302 | } | ||
741 | 303 | }); | ||
742 | 304 | |||
743 | 305 | OAuth.nonce.CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz"; | ||
744 | 306 | |||
745 | 307 | /** Define a constructor function, | ||
746 | 308 | without causing trouble to anyone who was using it as a namespace. | ||
747 | 309 | That is, if parent[name] already existed and had properties, | ||
748 | 310 | copy those properties into the new constructor. | ||
749 | 311 | */ | ||
750 | 312 | OAuth.declareClass = function declareClass(parent, name, newConstructor) { | ||
751 | 313 | var previous = parent[name]; | ||
752 | 314 | parent[name] = newConstructor; | ||
753 | 315 | if (newConstructor != null && previous != null) { | ||
754 | 316 | for (var key in previous) { | ||
755 | 317 | if (key != "prototype") { | ||
756 | 318 | newConstructor[key] = previous[key]; | ||
757 | 319 | } | ||
758 | 320 | } | ||
759 | 321 | } | ||
760 | 322 | return newConstructor; | ||
761 | 323 | } | ||
762 | 324 | |||
763 | 325 | /** An abstract algorithm for signing messages. */ | ||
764 | 326 | OAuth.declareClass(OAuth, "SignatureMethod", function OAuthSignatureMethod(){}); | ||
765 | 327 | |||
766 | 328 | OAuth.setProperties(OAuth.SignatureMethod.prototype, // instance members | ||
767 | 329 | { | ||
768 | 330 | /** Add a signature to the message. */ | ||
769 | 331 | sign: function sign(message) { | ||
770 | 332 | var baseString = OAuth.SignatureMethod.getBaseString(message); | ||
771 | 333 | var signature = this.getSignature(baseString); | ||
772 | 334 | OAuth.setParameter(message, "oauth_signature", signature); | ||
773 | 335 | return signature; // just in case someone's interested | ||
774 | 336 | } | ||
775 | 337 | , | ||
776 | 338 | /** Set the key string for signing. */ | ||
777 | 339 | initialize: function initialize(name, accessor) { | ||
778 | 340 | var consumerSecret; | ||
779 | 341 | if (accessor.accessorSecret != null | ||
780 | 342 | && name.length > 9 | ||
781 | 343 | && name.substring(name.length-9) == "-Accessor") | ||
782 | 344 | { | ||
783 | 345 | consumerSecret = accessor.accessorSecret; | ||
784 | 346 | } else { | ||
785 | 347 | consumerSecret = accessor.consumerSecret; | ||
786 | 348 | } | ||
787 | 349 | this.key = OAuth.percentEncode(consumerSecret) | ||
788 | 350 | +"&"+ OAuth.percentEncode(accessor.tokenSecret); | ||
789 | 351 | } | ||
790 | 352 | }); | ||
791 | 353 | |||
792 | 354 | /* SignatureMethod expects an accessor object to be like this: | ||
793 | 355 | {tokenSecret: "lakjsdflkj...", consumerSecret: "QOUEWRI..", accessorSecret: "xcmvzc..."} | ||
794 | 356 | The accessorSecret property is optional. | ||
795 | 357 | */ | ||
796 | 358 | // Class members: | ||
797 | 359 | OAuth.setProperties(OAuth.SignatureMethod, // class members | ||
798 | 360 | { | ||
799 | 361 | sign: function sign(message, accessor) { | ||
800 | 362 | var name = OAuth.getParameterMap(message.parameters).oauth_signature_method; | ||
801 | 363 | if (name == null || name == "") { | ||
802 | 364 | name = "HMAC-SHA1"; | ||
803 | 365 | OAuth.setParameter(message, "oauth_signature_method", name); | ||
804 | 366 | } | ||
805 | 367 | OAuth.SignatureMethod.newMethod(name, accessor).sign(message); | ||
806 | 368 | } | ||
807 | 369 | , | ||
808 | 370 | /** Instantiate a SignatureMethod for the given method name. */ | ||
809 | 371 | newMethod: function newMethod(name, accessor) { | ||
810 | 372 | var impl = OAuth.SignatureMethod.REGISTERED[name]; | ||
811 | 373 | if (impl != null) { | ||
812 | 374 | var method = new impl(); | ||
813 | 375 | method.initialize(name, accessor); | ||
814 | 376 | return method; | ||
815 | 377 | } | ||
816 | 378 | var err = new Error("signature_method_rejected"); | ||
817 | 379 | var acceptable = ""; | ||
818 | 380 | for (var r in OAuth.SignatureMethod.REGISTERED) { | ||
819 | 381 | if (acceptable != "") acceptable += '&'; | ||
820 | 382 | acceptable += OAuth.percentEncode(r); | ||
821 | 383 | } | ||
822 | 384 | err.oauth_acceptable_signature_methods = acceptable; | ||
823 | 385 | throw err; | ||
824 | 386 | } | ||
825 | 387 | , | ||
826 | 388 | /** A map from signature method name to constructor. */ | ||
827 | 389 | REGISTERED : {} | ||
828 | 390 | , | ||
829 | 391 | /** Subsequently, the given constructor will be used for the named methods. | ||
830 | 392 | The constructor will be called with no parameters. | ||
831 | 393 | The resulting object should usually implement getSignature(baseString). | ||
832 | 394 | You can easily define such a constructor by calling makeSubclass, below. | ||
833 | 395 | */ | ||
834 | 396 | registerMethodClass: function registerMethodClass(names, classConstructor) { | ||
835 | 397 | for (var n = 0; n < names.length; ++n) { | ||
836 | 398 | OAuth.SignatureMethod.REGISTERED[names[n]] = classConstructor; | ||
837 | 399 | } | ||
838 | 400 | } | ||
839 | 401 | , | ||
840 | 402 | /** Create a subclass of OAuth.SignatureMethod, with the given getSignature function. */ | ||
841 | 403 | makeSubclass: function makeSubclass(getSignatureFunction) { | ||
842 | 404 | var superClass = OAuth.SignatureMethod; | ||
843 | 405 | var subClass = function() { | ||
844 | 406 | superClass.call(this); | ||
845 | 407 | }; | ||
846 | 408 | subClass.prototype = new superClass(); | ||
847 | 409 | // Delete instance variables from prototype: | ||
848 | 410 | // delete subclass.prototype... There aren't any. | ||
849 | 411 | subClass.prototype.getSignature = getSignatureFunction; | ||
850 | 412 | subClass.prototype.constructor = subClass; | ||
851 | 413 | return subClass; | ||
852 | 414 | } | ||
853 | 415 | , | ||
854 | 416 | getBaseString: function getBaseString(message) { | ||
855 | 417 | var URL = message.action; | ||
856 | 418 | var q = URL.indexOf('?'); | ||
857 | 419 | var parameters; | ||
858 | 420 | if (q < 0) { | ||
859 | 421 | parameters = message.parameters; | ||
860 | 422 | } else { | ||
861 | 423 | // Combine the URL query string with the other parameters: | ||
862 | 424 | parameters = OAuth.decodeForm(URL.substring(q + 1)); | ||
863 | 425 | var toAdd = OAuth.getParameterList(message.parameters); | ||
864 | 426 | for (var a = 0; a < toAdd.length; ++a) { | ||
865 | 427 | parameters.push(toAdd[a]); | ||
866 | 428 | } | ||
867 | 429 | } | ||
868 | 430 | return OAuth.percentEncode(message.method.toUpperCase()) | ||
869 | 431 | +'&'+ OAuth.percentEncode(OAuth.SignatureMethod.normalizeUrl(URL)) | ||
870 | 432 | +'&'+ OAuth.percentEncode(OAuth.SignatureMethod.normalizeParameters(parameters)); | ||
871 | 433 | } | ||
872 | 434 | , | ||
873 | 435 | normalizeUrl: function normalizeUrl(url) { | ||
874 | 436 | var uri = OAuth.SignatureMethod.parseUri(url); | ||
875 | 437 | var scheme = uri.protocol.toLowerCase(); | ||
876 | 438 | var authority = uri.authority.toLowerCase(); | ||
877 | 439 | var dropPort = (scheme == "http" && uri.port == 80) | ||
878 | 440 | || (scheme == "https" && uri.port == 443); | ||
879 | 441 | if (dropPort) { | ||
880 | 442 | // find the last : in the authority | ||
881 | 443 | var index = authority.lastIndexOf(":"); | ||
882 | 444 | if (index >= 0) { | ||
883 | 445 | authority = authority.substring(0, index); | ||
884 | 446 | } | ||
885 | 447 | } | ||
886 | 448 | var path = uri.path; | ||
887 | 449 | /* This actually produces different signatures from the python lib | ||
888 | 450 | if (!path) { | ||
889 | 451 | path = "/"; // conforms to RFC 2616 section 3.2.2 | ||
890 | 452 | } | ||
891 | 453 | */ | ||
892 | 454 | // we know that there is no query and no fragment here. | ||
893 | 455 | return scheme + "://" + authority + path; | ||
894 | 456 | } | ||
895 | 457 | , | ||
896 | 458 | parseUri: function parseUri (str) { | ||
897 | 459 | /* This function was adapted from parseUri 1.2.1 | ||
898 | 460 | http://stevenlevithan.com/demo/parseuri/js/assets/parseuri.js | ||
899 | 461 | */ | ||
900 | 462 | var o = {key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], | ||
901 | 463 | parser: {strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/ }}; | ||
902 | 464 | var m = o.parser.strict.exec(str); | ||
903 | 465 | var uri = {}; | ||
904 | 466 | var i = 14; | ||
905 | 467 | while (i--) uri[o.key[i]] = m[i] || ""; | ||
906 | 468 | return uri; | ||
907 | 469 | } | ||
908 | 470 | , | ||
909 | 471 | normalizeParameters: function normalizeParameters(parameters) { | ||
910 | 472 | if (parameters == null) { | ||
911 | 473 | return ""; | ||
912 | 474 | } | ||
913 | 475 | var list = OAuth.getParameterList(parameters); | ||
914 | 476 | var sortable = []; | ||
915 | 477 | for (var p = 0; p < list.length; ++p) { | ||
916 | 478 | var nvp = list[p]; | ||
917 | 479 | if (nvp[0] == "oauth_signature" || nvp[0] == "realm") { | ||
918 | 480 | continue; | ||
919 | 481 | } else { | ||
920 | 482 | sortable.push([ OAuth.percentEncode(nvp[0]) | ||
921 | 483 | + " " // because it comes before any character that can appear in a percentEncoded string. | ||
922 | 484 | + OAuth.percentEncode(nvp[1]) | ||
923 | 485 | , nvp]); | ||
924 | 486 | } | ||
925 | 487 | } | ||
926 | 488 | sortable.sort(function(a,b) { | ||
927 | 489 | if (a[0] < b[0]) return -1; | ||
928 | 490 | if (a[0] > b[0]) return 1; | ||
929 | 491 | return 0; | ||
930 | 492 | }); | ||
931 | 493 | var sorted = []; | ||
932 | 494 | for (var s = 0; s < sortable.length; ++s) { | ||
933 | 495 | sorted.push(sortable[s][1]); | ||
934 | 496 | } | ||
935 | 497 | return OAuth.formEncode(sorted); | ||
936 | 498 | } | ||
937 | 499 | }); | ||
938 | 500 | |||
939 | 501 | OAuth.SignatureMethod.registerMethodClass(["PLAINTEXT", "PLAINTEXT-Accessor"], | ||
940 | 502 | OAuth.SignatureMethod.makeSubclass( | ||
941 | 503 | function getSignature(baseString) { | ||
942 | 504 | return this.key; | ||
943 | 505 | } | ||
944 | 506 | )); | ||
945 | 507 | |||
946 | 508 | OAuth.SignatureMethod.registerMethodClass(["HMAC-SHA1", "HMAC-SHA1-Accessor"], | ||
947 | 509 | OAuth.SignatureMethod.makeSubclass( | ||
948 | 510 | function getSignature(baseString) { | ||
949 | 511 | b64pad = '='; | ||
950 | 512 | var signature = b64_hmac_sha1(this.key, baseString); | ||
951 | 513 | return signature; | ||
952 | 514 | } | ||
953 | 515 | )); | ||
954 | 0 | 516 | ||
955 | === added file 'content/sha1.js' | |||
956 | --- content/sha1.js 1970-01-01 00:00:00 +0000 | |||
957 | +++ content/sha1.js 2009-09-02 17:07:11 +0000 | |||
958 | @@ -0,0 +1,202 @@ | |||
959 | 1 | /* | ||
960 | 2 | * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined | ||
961 | 3 | * in FIPS PUB 180-1 | ||
962 | 4 | * Version 2.1a Copyright Paul Johnston 2000 - 2002. | ||
963 | 5 | * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet | ||
964 | 6 | * Distributed under the BSD License | ||
965 | 7 | * See http://pajhome.org.uk/crypt/md5 for details. | ||
966 | 8 | */ | ||
967 | 9 | |||
968 | 10 | /* | ||
969 | 11 | * Configurable variables. You may need to tweak these to be compatible with | ||
970 | 12 | * the server-side, but the defaults work in most cases. | ||
971 | 13 | */ | ||
972 | 14 | var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ | ||
973 | 15 | var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ | ||
974 | 16 | var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ | ||
975 | 17 | |||
976 | 18 | /* | ||
977 | 19 | * These are the functions you'll usually want to call | ||
978 | 20 | * They take string arguments and return either hex or base-64 encoded strings | ||
979 | 21 | */ | ||
980 | 22 | function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));} | ||
981 | 23 | function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));} | ||
982 | 24 | function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));} | ||
983 | 25 | function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));} | ||
984 | 26 | function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));} | ||
985 | 27 | function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));} | ||
986 | 28 | |||
987 | 29 | /* | ||
988 | 30 | * Perform a simple self-test to see if the VM is working | ||
989 | 31 | */ | ||
990 | 32 | function sha1_vm_test() | ||
991 | 33 | { | ||
992 | 34 | return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d"; | ||
993 | 35 | } | ||
994 | 36 | |||
995 | 37 | /* | ||
996 | 38 | * Calculate the SHA-1 of an array of big-endian words, and a bit length | ||
997 | 39 | */ | ||
998 | 40 | function core_sha1(x, len) | ||
999 | 41 | { | ||
1000 | 42 | /* append padding */ | ||
1001 | 43 | x[len >> 5] |= 0x80 << (24 - len % 32); | ||
1002 | 44 | x[((len + 64 >> 9) << 4) + 15] = len; | ||
1003 | 45 | |||
1004 | 46 | var w = Array(80); | ||
1005 | 47 | var a = 1732584193; | ||
1006 | 48 | var b = -271733879; | ||
1007 | 49 | var c = -1732584194; | ||
1008 | 50 | var d = 271733878; | ||
1009 | 51 | var e = -1009589776; | ||
1010 | 52 | |||
1011 | 53 | for(var i = 0; i < x.length; i += 16) | ||
1012 | 54 | { | ||
1013 | 55 | var olda = a; | ||
1014 | 56 | var oldb = b; | ||
1015 | 57 | var oldc = c; | ||
1016 | 58 | var oldd = d; | ||
1017 | 59 | var olde = e; | ||
1018 | 60 | |||
1019 | 61 | for(var j = 0; j < 80; j++) | ||
1020 | 62 | { | ||
1021 | 63 | if(j < 16) w[j] = x[i + j]; | ||
1022 | 64 | else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); | ||
1023 | 65 | var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), | ||
1024 | 66 | safe_add(safe_add(e, w[j]), sha1_kt(j))); | ||
1025 | 67 | e = d; | ||
1026 | 68 | d = c; | ||
1027 | 69 | c = rol(b, 30); | ||
1028 | 70 | b = a; | ||
1029 | 71 | a = t; | ||
1030 | 72 | } | ||
1031 | 73 | |||
1032 | 74 | a = safe_add(a, olda); | ||
1033 | 75 | b = safe_add(b, oldb); | ||
1034 | 76 | c = safe_add(c, oldc); | ||
1035 | 77 | d = safe_add(d, oldd); | ||
1036 | 78 | e = safe_add(e, olde); | ||
1037 | 79 | } | ||
1038 | 80 | return Array(a, b, c, d, e); | ||
1039 | 81 | |||
1040 | 82 | } | ||
1041 | 83 | |||
1042 | 84 | /* | ||
1043 | 85 | * Perform the appropriate triplet combination function for the current | ||
1044 | 86 | * iteration | ||
1045 | 87 | */ | ||
1046 | 88 | function sha1_ft(t, b, c, d) | ||
1047 | 89 | { | ||
1048 | 90 | if(t < 20) return (b & c) | ((~b) & d); | ||
1049 | 91 | if(t < 40) return b ^ c ^ d; | ||
1050 | 92 | if(t < 60) return (b & c) | (b & d) | (c & d); | ||
1051 | 93 | return b ^ c ^ d; | ||
1052 | 94 | } | ||
1053 | 95 | |||
1054 | 96 | /* | ||
1055 | 97 | * Determine the appropriate additive constant for the current iteration | ||
1056 | 98 | */ | ||
1057 | 99 | function sha1_kt(t) | ||
1058 | 100 | { | ||
1059 | 101 | return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : | ||
1060 | 102 | (t < 60) ? -1894007588 : -899497514; | ||
1061 | 103 | } | ||
1062 | 104 | |||
1063 | 105 | /* | ||
1064 | 106 | * Calculate the HMAC-SHA1 of a key and some data | ||
1065 | 107 | */ | ||
1066 | 108 | function core_hmac_sha1(key, data) | ||
1067 | 109 | { | ||
1068 | 110 | var bkey = str2binb(key); | ||
1069 | 111 | if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz); | ||
1070 | 112 | |||
1071 | 113 | var ipad = Array(16), opad = Array(16); | ||
1072 | 114 | for(var i = 0; i < 16; i++) | ||
1073 | 115 | { | ||
1074 | 116 | ipad[i] = bkey[i] ^ 0x36363636; | ||
1075 | 117 | opad[i] = bkey[i] ^ 0x5C5C5C5C; | ||
1076 | 118 | } | ||
1077 | 119 | |||
1078 | 120 | var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz); | ||
1079 | 121 | return core_sha1(opad.concat(hash), 512 + 160); | ||
1080 | 122 | } | ||
1081 | 123 | |||
1082 | 124 | /* | ||
1083 | 125 | * Add integers, wrapping at 2^32. This uses 16-bit operations internally | ||
1084 | 126 | * to work around bugs in some JS interpreters. | ||
1085 | 127 | */ | ||
1086 | 128 | function safe_add(x, y) | ||
1087 | 129 | { | ||
1088 | 130 | var lsw = (x & 0xFFFF) + (y & 0xFFFF); | ||
1089 | 131 | var msw = (x >> 16) + (y >> 16) + (lsw >> 16); | ||
1090 | 132 | return (msw << 16) | (lsw & 0xFFFF); | ||
1091 | 133 | } | ||
1092 | 134 | |||
1093 | 135 | /* | ||
1094 | 136 | * Bitwise rotate a 32-bit number to the left. | ||
1095 | 137 | */ | ||
1096 | 138 | function rol(num, cnt) | ||
1097 | 139 | { | ||
1098 | 140 | return (num << cnt) | (num >>> (32 - cnt)); | ||
1099 | 141 | } | ||
1100 | 142 | |||
1101 | 143 | /* | ||
1102 | 144 | * Convert an 8-bit or 16-bit string to an array of big-endian words | ||
1103 | 145 | * In 8-bit function, characters >255 have their hi-byte silently ignored. | ||
1104 | 146 | */ | ||
1105 | 147 | function str2binb(str) | ||
1106 | 148 | { | ||
1107 | 149 | var bin = Array(); | ||
1108 | 150 | var mask = (1 << chrsz) - 1; | ||
1109 | 151 | for(var i = 0; i < str.length * chrsz; i += chrsz) | ||
1110 | 152 | bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (32 - chrsz - i%32); | ||
1111 | 153 | return bin; | ||
1112 | 154 | } | ||
1113 | 155 | |||
1114 | 156 | /* | ||
1115 | 157 | * Convert an array of big-endian words to a string | ||
1116 | 158 | */ | ||
1117 | 159 | function binb2str(bin) | ||
1118 | 160 | { | ||
1119 | 161 | var str = ""; | ||
1120 | 162 | var mask = (1 << chrsz) - 1; | ||
1121 | 163 | for(var i = 0; i < bin.length * 32; i += chrsz) | ||
1122 | 164 | str += String.fromCharCode((bin[i>>5] >>> (32 - chrsz - i%32)) & mask); | ||
1123 | 165 | return str; | ||
1124 | 166 | } | ||
1125 | 167 | |||
1126 | 168 | /* | ||
1127 | 169 | * Convert an array of big-endian words to a hex string. | ||
1128 | 170 | */ | ||
1129 | 171 | function binb2hex(binarray) | ||
1130 | 172 | { | ||
1131 | 173 | var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; | ||
1132 | 174 | var str = ""; | ||
1133 | 175 | for(var i = 0; i < binarray.length * 4; i++) | ||
1134 | 176 | { | ||
1135 | 177 | str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) + | ||
1136 | 178 | hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF); | ||
1137 | 179 | } | ||
1138 | 180 | return str; | ||
1139 | 181 | } | ||
1140 | 182 | |||
1141 | 183 | /* | ||
1142 | 184 | * Convert an array of big-endian words to a base-64 string | ||
1143 | 185 | */ | ||
1144 | 186 | function binb2b64(binarray) | ||
1145 | 187 | { | ||
1146 | 188 | var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||
1147 | 189 | var str = ""; | ||
1148 | 190 | for(var i = 0; i < binarray.length * 4; i += 3) | ||
1149 | 191 | { | ||
1150 | 192 | var triplet = (((binarray[i >> 2] >> 8 * (3 - i %4)) & 0xFF) << 16) | ||
1151 | 193 | | (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 ) | ||
1152 | 194 | | ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF); | ||
1153 | 195 | for(var j = 0; j < 4; j++) | ||
1154 | 196 | { | ||
1155 | 197 | if(i * 8 + j * 6 > binarray.length * 32) str += b64pad; | ||
1156 | 198 | else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); | ||
1157 | 199 | } | ||
1158 | 200 | } | ||
1159 | 201 | return str; | ||
1160 | 202 | } | ||
1161 | 0 | 203 | ||
1162 | === modified file 'content/sync.js' | |||
1163 | --- content/sync.js 2009-08-27 18:45:48 +0000 | |||
1164 | +++ content/sync.js 2009-09-08 15:29:55 +0000 | |||
1165 | @@ -112,11 +112,11 @@ | |||
1166 | 112 | .getService(Components.interfaces.nsIWindowMediator) | 112 | .getService(Components.interfaces.nsIWindowMediator) |
1167 | 113 | .getEnumerator("").getNext() == window) { | 113 | .getEnumerator("").getNext() == window) { |
1168 | 114 | Bindwood.writeMessage("First window opened. Getting a Couch Port"); | 114 | Bindwood.writeMessage("First window opened. Getting a Couch Port"); |
1170 | 115 | Bindwood.getCouchPortNumber(Bindwood.startProcess); | 115 | Bindwood.getCouchEnvironment(Bindwood.startProcess); |
1171 | 116 | } | 116 | } |
1172 | 117 | }, | 117 | }, |
1173 | 118 | 118 | ||
1175 | 119 | getCouchPortNumber: function(continueFunction) { | 119 | getCouchEnvironment: function(continueFunction) { |
1176 | 120 | // find the desktop Couch port number by making a D-Bus call | 120 | // find the desktop Couch port number by making a D-Bus call |
1177 | 121 | // we call D-Bus by shelling out to a bash script which calls | 121 | // we call D-Bus by shelling out to a bash script which calls |
1178 | 122 | // it for us, and writes the port number into a temp file | 122 | // it for us, and writes the port number into a temp file |
1179 | @@ -139,12 +139,12 @@ | |||
1180 | 139 | var MY_ID = "bindwood@ubuntu.com"; | 139 | var MY_ID = "bindwood@ubuntu.com"; |
1181 | 140 | var em = Components.classes["@mozilla.org/extensions/manager;1"]. | 140 | var em = Components.classes["@mozilla.org/extensions/manager;1"]. |
1182 | 141 | getService(Components.interfaces.nsIExtensionManager); | 141 | getService(Components.interfaces.nsIExtensionManager); |
1185 | 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"); |
1186 | 143 | Bindwood.writeMessage("Found path to dbus_script: " + dbus_script.path); | 143 | Bindwood.writeMessage("Found path to dbus_script: " + couchdb_env_script.path); |
1187 | 144 | // create an nsILocalFile for the executable | 144 | // create an nsILocalFile for the executable |
1188 | 145 | var nsifile = Components.classes["@mozilla.org/file/local;1"] | 145 | var nsifile = Components.classes["@mozilla.org/file/local;1"] |
1189 | 146 | .createInstance(Components.interfaces.nsILocalFile); | 146 | .createInstance(Components.interfaces.nsILocalFile); |
1191 | 147 | nsifile.initWithPath(dbus_script.path); | 147 | nsifile.initWithPath(couchdb_env_script.path); |
1192 | 148 | 148 | ||
1193 | 149 | // create an nsIProcess2 to execute this bash script | 149 | // create an nsIProcess2 to execute this bash script |
1194 | 150 | var process = Components.classes["@mozilla.org/process/util;1"] | 150 | var process = Components.classes["@mozilla.org/process/util;1"] |
1195 | @@ -153,14 +153,16 @@ | |||
1196 | 153 | 153 | ||
1197 | 154 | // Run the process, passing the tmpfile path | 154 | // Run the process, passing the tmpfile path |
1198 | 155 | var args = [tmpfile.path]; | 155 | var args = [tmpfile.path]; |
1200 | 156 | Bindwood.writeMessage("Running dbus script"); | 156 | Bindwood.writeMessage("Running couchdb env script"); |
1201 | 157 | process.runAsync(args, args.length, { | 157 | process.runAsync(args, args.length, { |
1202 | 158 | observe: function(process, finishState, unused_data) { | 158 | observe: function(process, finishState, unused_data) { |
1204 | 159 | var port = 5984; | 159 | // If the script exists cleanly, we should have a file |
1205 | 160 | // containing the port couch is running on as well as | ||
1206 | 161 | // the various OAuth tokens necessary to talk to it. | ||
1207 | 160 | if (finishState == "process-finished") { | 162 | if (finishState == "process-finished") { |
1209 | 161 | // read temp file to find port number | 163 | // read temp file to find couch environment |
1210 | 162 | // https://developer.mozilla.org/en/Code_snippets/File_I%2f%2fO#Reading_from_a_file | 164 | // https://developer.mozilla.org/en/Code_snippets/File_I%2f%2fO#Reading_from_a_file |
1212 | 163 | var data = ""; | 165 | var environment; |
1213 | 164 | var fstream = Components.classes["@mozilla.org/network/file-input-stream;1"]. | 166 | var fstream = Components.classes["@mozilla.org/network/file-input-stream;1"]. |
1214 | 165 | createInstance(Components.interfaces.nsIFileInputStream); | 167 | createInstance(Components.interfaces.nsIFileInputStream); |
1215 | 166 | var cstream = Components.classes["@mozilla.org/intl/converter-input-stream;1"]. | 168 | var cstream = Components.classes["@mozilla.org/intl/converter-input-stream;1"]. |
1216 | @@ -169,28 +171,56 @@ | |||
1217 | 169 | cstream.init(fstream, "UTF-8", 0, 0); | 171 | cstream.init(fstream, "UTF-8", 0, 0); |
1218 | 170 | let (str = {}) { | 172 | let (str = {}) { |
1219 | 171 | cstream.readString(-1, str); // read the whole file and put it in str.value | 173 | cstream.readString(-1, str); // read the whole file and put it in str.value |
1221 | 172 | data = str.value; | 174 | environment = str.value; |
1222 | 173 | }; | 175 | }; |
1223 | 174 | cstream.close(); // this closes fstream | 176 | cstream.close(); // this closes fstream |
1230 | 175 | data = data.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); | 177 | environment = environment.replace(/^\s\s*/, '').replace(/\s\s*$/, ''); |
1225 | 176 | if (/^[0-9]+$/.test(data)) { | ||
1226 | 177 | port = data; | ||
1227 | 178 | } else { | ||
1228 | 179 | Bindwood.writeMessage("D-Bus port data is not a number (" + data + ")"); | ||
1229 | 180 | } | ||
1231 | 181 | } else { | 178 | } else { |
1232 | 182 | // fall back to system CouchDB | 179 | // fall back to system CouchDB |
1233 | 183 | Bindwood.writeMessage("D-Bus port find failed"); | 180 | Bindwood.writeMessage("D-Bus port find failed"); |
1234 | 184 | } | 181 | } |
1235 | 185 | tmpfile.remove(false); | 182 | tmpfile.remove(false); |
1238 | 186 | continueFunction(port); | 183 | |
1239 | 187 | } | 184 | if (environment == 'ENOCOUCH') { |
1240 | 185 | // No Couch environment found. Just spit out a | ||
1241 | 186 | // message and return, stopping Bindwood from | ||
1242 | 187 | // doing anything further. | ||
1243 | 188 | Bindwood.writeError("No suitable Couch environment found. Not proceeding.", e); | ||
1244 | 189 | } else { | ||
1245 | 190 | // If we don't have a Couch environment, don't bother | ||
1246 | 191 | // trying to fall back on the system CouchDB. | ||
1247 | 192 | continueFunction(environment); | ||
1248 | 193 | } | ||
1249 | 194 | } | ||
1250 | 188 | }); | 195 | }); |
1251 | 189 | }, | 196 | }, |
1252 | 190 | 197 | ||
1256 | 191 | startProcess: function(couchPortNumber) { | 198 | startProcess: function(couchEnvironment) { |
1257 | 192 | Bindwood.writeMessage("Starting process with Couch on port " + couchPortNumber); | 199 | Bindwood.writeMessage("Starting process with Couch environment: " + couchEnvironment); |
1258 | 193 | CouchDB.PORT_NUMBER = couchPortNumber; | 200 | |
1259 | 201 | var env_array = couchEnvironment.split(':'); | ||
1260 | 202 | var port = env_array[0]; | ||
1261 | 203 | var consumer_key = env_array[1]; | ||
1262 | 204 | var consumer_secret = env_array[2]; | ||
1263 | 205 | var token = env_array[3]; | ||
1264 | 206 | var token_secret = env_array[4]; | ||
1265 | 207 | |||
1266 | 208 | CouchDB.port = port; | ||
1267 | 209 | CouchDB.accessor = { | ||
1268 | 210 | consumerSecret: consumer_secret, | ||
1269 | 211 | tokenSecret: token_secret | ||
1270 | 212 | }; | ||
1271 | 213 | CouchDB.message = { | ||
1272 | 214 | parameters: { | ||
1273 | 215 | oauth_callback: "None", | ||
1274 | 216 | oauth_consumer_key: consumer_key, | ||
1275 | 217 | oauth_signature_method: "HMAC-SHA1", | ||
1276 | 218 | oauth_token: token, | ||
1277 | 219 | oauth_verifier: "None", | ||
1278 | 220 | oauth_version: "1.0" | ||
1279 | 221 | } | ||
1280 | 222 | }; | ||
1281 | 223 | |||
1282 | 194 | try { | 224 | try { |
1283 | 195 | Bindwood.writeMessage("Pushing bookmarks"); | 225 | Bindwood.writeMessage("Pushing bookmarks"); |
1284 | 196 | Bindwood.pushBookmarks(); | 226 | Bindwood.pushBookmarks(); |
1285 | @@ -260,10 +290,19 @@ | |||
1286 | 260 | } | 290 | } |
1287 | 261 | } | 291 | } |
1288 | 262 | 292 | ||
1293 | 263 | Bindwood.pushBookmarksFromList(Bindwood.bookmarksService.toolbarFolder, | 293 | try { |
1294 | 264 | "toolbarFolder", couch); | 294 | Bindwood.pushBookmarksFromList(Bindwood.bookmarksService.toolbarFolder, |
1295 | 265 | Bindwood.pushBookmarksFromList(Bindwood.bookmarksService.bookmarksMenuFolder, | 295 | "toolbarFolder", couch); |
1296 | 266 | "bookmarksMenuFolder", couch); | 296 | } catch(e) { |
1297 | 297 | Bindwood.writeError("Error pushing toolbarFolder bookmarks: ", e); | ||
1298 | 298 | } | ||
1299 | 299 | |||
1300 | 300 | try { | ||
1301 | 301 | Bindwood.pushBookmarksFromList(Bindwood.bookmarksService.bookmarksMenuFolder, | ||
1302 | 302 | "bookmarksMenuFolder", couch); | ||
1303 | 303 | } catch(e) { | ||
1304 | 304 | Bindwood.writeError("Error pushing bookmarksMenuFolder bookmarks: ", e); | ||
1305 | 305 | } | ||
1306 | 267 | }, | 306 | }, |
1307 | 268 | 307 | ||
1308 | 269 | getBookmarksFromList: function(bookmarksList) { | 308 | getBookmarksFromList: function(bookmarksList) { |
1309 | @@ -320,15 +359,19 @@ | |||
1310 | 320 | 359 | ||
1311 | 321 | Bindwood.uuidItemIdMap[uuid] = itemId; | 360 | Bindwood.uuidItemIdMap[uuid] = itemId; |
1312 | 322 | 361 | ||
1322 | 323 | var results = db.query(function(doc) { | 362 | try { |
1323 | 324 | if (doc.application_annotations && | 363 | var results = db.query(function(doc) { |
1324 | 325 | doc.application_annotations.Firefox && | 364 | if (doc.application_annotations && |
1325 | 326 | doc.application_annotations.Firefox.uuid) { | 365 | doc.application_annotations.Firefox && |
1326 | 327 | emit(doc.application_annotations.Firefox.uuid, doc); | 366 | doc.application_annotations.Firefox.uuid) { |
1327 | 328 | } | 367 | emit(doc.application_annotations.Firefox.uuid, doc); |
1328 | 329 | }, null, { | 368 | } |
1329 | 330 | startkey: uuid, endkey: uuid | 369 | }, null, { |
1330 | 331 | }); | 370 | startkey: uuid, endkey: uuid |
1331 | 371 | }); | ||
1332 | 372 | } catch(e) { | ||
1333 | 373 | Bindwood.writeError("Error querying couch: ", e); | ||
1334 | 374 | } | ||
1335 | 332 | 375 | ||
1336 | 333 | if (results.rows.length === 0) { | 376 | if (results.rows.length === 0) { |
1337 | 334 | // this bookmark is not in CouchDB, so write it | 377 | // this bookmark is not in CouchDB, so write it |
1338 | @@ -440,7 +483,7 @@ | |||
1339 | 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 + ")"); |
1340 | 441 | try { | 484 | try { |
1341 | 442 | var new_uri = Bindwood.ioService.newURI(bm.uri, null, null); | 485 | var new_uri = Bindwood.ioService.newURI(bm.uri, null, null); |
1343 | 443 | Bindowod.writeMessage("Creating a new URI for our local bookmark"); | 486 | Bindwood.writeMessage("Creating a new URI for our local bookmark"); |
1344 | 444 | Bindwood.bookmarksService.changeBookmarkURI(itemId, new_uri); | 487 | Bindwood.bookmarksService.changeBookmarkURI(itemId, new_uri); |
1345 | 445 | } catch(e) { | 488 | } catch(e) { |
1346 | 446 | Bindwood.writeError("Problem creating a new URI for bookmark: ", e); | 489 | Bindwood.writeError("Problem creating a new URI for bookmark: ", e); |
1347 | @@ -482,7 +525,7 @@ | |||
1348 | 482 | 525 | ||
1349 | 483 | try { | 526 | try { |
1350 | 484 | var new_uri = Bindwood.ioService.newURI(bm.uri, null, null); | 527 | var new_uri = Bindwood.ioService.newURI(bm.uri, null, null); |
1352 | 485 | Bindowod.writeMessage("Creating a new URI for our local bookmark"); | 528 | Bindwood.writeMessage("Creating a new URI for our local bookmark"); |
1353 | 486 | Bindwood.bookmarksService.changeBookmarkURI(itemId, new_uri); | 529 | Bindwood.bookmarksService.changeBookmarkURI(itemId, new_uri); |
1354 | 487 | } catch(e) { | 530 | } catch(e) { |
1355 | 488 | Bindwood.writeError("Problem creating a new URI for bookmark: ", e); | 531 | Bindwood.writeError("Problem creating a new URI for bookmark: ", e); |
1356 | 489 | 532 | ||
1357 | === renamed file 'dbus.sh' => 'couchdb_env.sh' | |||
1358 | --- dbus.sh 2009-08-18 14:17:30 +0000 | |||
1359 | +++ couchdb_env.sh 2009-09-01 19:40:34 +0000 | |||
1360 | @@ -13,12 +13,16 @@ | |||
1361 | 13 | # You should have received a copy of the GNU General Public License along | 13 | # You should have received a copy of the GNU General Public License along |
1362 | 14 | # with this program. If not, see <http://www.gnu.org/licenses/>. | 14 | # with this program. If not, see <http://www.gnu.org/licenses/>. |
1363 | 15 | OUT=$1 | 15 | OUT=$1 |
1365 | 16 | PORT=$(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 | |
1366 | 17 | PORT=$(dbus-send --session --dest=org.desktopcouch.CouchDB --print-reply --type=method_call / org.desktopcouch.CouchDB.getPort 2>/dev/null | grep int32 | awk '{print $2}') | ||
1367 | 18 | |||
1368 | 19 | TOKENS=$(python -c "import gnomekeyring; print gnomekeyring.find_items_sync(gnomekeyring.ITEM_GENERIC_SECRET, {'desktopcouch': 'oauth'})[0].secret" 2>/dev/null) | ||
1369 | 20 | |||
1370 | 17 | if [ -z "$PORT" ]; then | 21 | if [ -z "$PORT" ]; then |
1373 | 18 | # D-Bus call failed for some reason, so use default port | 22 | # D-Bus call failed for some reason, so just punt |
1374 | 19 | echo 5984 > $OUT | 23 | echo ENOCOUCH > $OUT |
1375 | 20 | else | 24 | else |
1377 | 21 | echo $PORT > $OUT | 25 | echo $PORT:$TOKENS > $OUT |
1378 | 22 | fi | 26 | fi |
1379 | 23 | 27 | ||
1380 | 24 | 28 |
This branch enables OAuth integration with our Desktop CouchDB.