authentification: access control, check manifest on whitelist
[contrib/cloudeebus.git] / cloudeebus / cloudeebus.js
1 /******************************************************************************
2  * Copyright 2012 Intel Corporation.
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
18
19 /*****************************************************************************/
20
21 var cloudeebus = window.cloudeebus = {};
22
23 cloudeebus.reset = function() {
24         cloudeebus.sessionBus = null;
25         cloudeebus.systemBus = null;
26         cloudeebus.wampSession = null;
27         cloudeebus.uri = null;
28 };
29
30
31 cloudeebus.log = function(msg) { 
32 };
33
34
35 cloudeebus.connect = function(uri, manifest, successCB, errorCB) {
36         cloudeebus.reset();
37         cloudeebus.uri = uri;
38         
39         function onWAMPSessionAuthenticatedCB(permissions) {
40 cloudeebus.log("Authenticated: " + JSON.stringify(permissions));
41                 cloudeebus.sessionBus = new cloudeebus.BusConnection("session", cloudeebus.wampSession);
42                 cloudeebus.systemBus = new cloudeebus.BusConnection("system", cloudeebus.wampSession);
43                 if (successCB)
44                         successCB();
45         }
46         
47         function onWAMPSessionChallengedCB(challenge) {
48 cloudeebus.log("Challenged: " + challenge);
49                 var signature = cloudeebus.wampSession.authsign(challenge, manifest.key);
50 cloudeebus.log("Signature: " + signature);
51                 cloudeebus.wampSession.auth(signature).then(onWAMPSessionAuthenticatedCB, errorCB);
52         }
53         
54         function onWAMPSessionConnectedCB(session) {
55                 cloudeebus.log("Connected to " + cloudeebus.uri);
56                 cloudeebus.wampSession = session;
57                 cloudeebus.wampSession.authreq(
58                                 manifest.name, 
59                                 {permissions: JSON.stringify(manifest.permissions)}
60                         ).then(onWAMPSessionChallengedCB, errorCB);
61         }
62
63         function onWAMPSessionErrorCB(code, reason) {
64                 if (code == ab.CONNECTION_UNSUPPORTED) {
65                         cloudeebus.log("Browser is not supported");
66                 }
67                 else {
68                         cloudeebus.log("Failed to open session, code = " + code + ", reason = " + reason);
69                 }
70                 if (errorCB)
71                         errorCB(reason);
72         }
73
74         return ab.connect(cloudeebus.uri, onWAMPSessionConnectedCB, onWAMPSessionErrorCB);
75 };
76
77
78 cloudeebus.SessionBus = function() {
79         return cloudeebus.sessionBus;
80 };
81
82
83 cloudeebus.SystemBus = function() {
84         return cloudeebus.systemBus;
85 };
86
87
88
89 /*****************************************************************************/
90
91 cloudeebus.BusConnection = function(name, session) {
92         this.name = name;
93         this.wampSession = session;
94         return this;
95 };
96
97
98 cloudeebus.BusConnection.prototype.getObject = function(busName, objectPath, introspectCB, errorCB) {
99         var proxy = new cloudeebus.ProxyObject(this.wampSession, this, busName, objectPath);
100         if (introspectCB)
101                 proxy._introspect(introspectCB, errorCB);
102         return proxy;
103 };
104
105
106
107 /*****************************************************************************/
108
109 cloudeebus.ProxyObject = function(session, busConnection, busName, objectPath) {
110         this.wampSession = session; 
111         this.busConnection = busConnection; 
112         this.busName = busName; 
113         this.objectPath = objectPath; 
114         return this;
115 };
116
117
118 cloudeebus.ProxyObject.prototype._introspect = function(successCB, errorCB) {
119         
120         var self = this; 
121
122         function getAllPropertiesSuccessCB(props) {
123                 for (var prop in props)
124                         self[prop] = props[prop];
125                 if (self.propInterfaces.length > 0) 
126                         self.callMethod("org.freedesktop.DBus.Properties", 
127                                 "GetAll", 
128                                 [self.propInterfaces.pop()], 
129                                 getAllPropertiesSuccessCB, 
130                                 errorCB);
131                 else {
132                         self.propInterfaces = null;
133                         if (successCB)
134                                 successCB(self);
135                 }
136         }
137         
138         function introspectSuccessCB(str) {
139                 var parser = new DOMParser();
140                 var xmlDoc = parser.parseFromString(str, "text/xml");
141                 var interfaces = xmlDoc.getElementsByTagName("interface");
142                 self.propInterfaces = [];
143                 var supportDBusProperties = false;
144                 for (var i=0; i < interfaces.length; i++) {
145                         var ifName = interfaces[i].attributes.getNamedItem("name").value;
146                         if (ifName == "org.freedesktop.DBus.Properties")
147                                 supportDBusProperties = true;
148                         var hasProperties = false;
149                         var ifChild = interfaces[i].firstChild;
150                         while (ifChild) {
151                                 if (ifChild.nodeName == "method") {
152                                         var nArgs = 0;
153                                         var metChild = ifChild.firstChild;
154                                         while (metChild) {
155                                                 if (metChild.nodeName == "arg" &&
156                                                         metChild.attributes.getNamedItem("direction").value == "in")
157                                                                 nArgs++;
158                                                 metChild = metChild.nextSibling;
159                                         }
160                                         self._addMethod(ifName, 
161                                                         ifChild.attributes.getNamedItem("name").value, 
162                                                         nArgs);
163                                 }
164                                 else if (ifChild.nodeName == "property") {
165                                         if (!hasProperties)
166                                                 self.propInterfaces.push(ifName);
167                                         hasProperties = true;
168                                 }
169                                 ifChild = ifChild.nextSibling;
170                         }
171                 }
172                 if (supportDBusProperties && self.propInterfaces.length > 0) {
173                         self.callMethod("org.freedesktop.DBus.Properties", 
174                                 "GetAll", 
175                                 [self.propInterfaces.pop()], 
176                                 getAllPropertiesSuccessCB, 
177                                 errorCB);
178                 }
179                 else {
180                         self.propInterfaces = null;
181                         if (successCB)
182                                 successCB(self);
183                 }
184         }
185
186         // call Introspect on self
187         self.callMethod("org.freedesktop.DBus.Introspectable", "Introspect", [], introspectSuccessCB, errorCB);
188 };
189
190
191 cloudeebus.ProxyObject.prototype._addMethod = function(ifName, method, nArgs) {
192
193         var self = this;
194         
195         self[method] = function() {
196                 if (arguments.length < nArgs || arguments.length > nArgs + 2)
197                         throw "Error: method " + method + " takes " + nArgs + " parameters, got " + arguments.length + ".";
198                 var args = [];
199                 var successCB = null;
200                 var errorCB = null;
201                 for (var i=0; i < nArgs; i++ )
202                         args.push(arguments[i]);
203                 if (arguments.length > nArgs)
204                         successCB = arguments[nArgs];
205                 if (arguments.length > nArgs + 1)
206                         errorCB = arguments[nArgs + 1];
207                 self.callMethod(ifName, method, args, successCB, errorCB);
208         };
209         
210 };
211
212
213 cloudeebus.ProxyObject.prototype.callMethod = function(ifName, method, args, successCB, errorCB) {
214         
215         var self = this; 
216
217         function callMethodSuccessCB(str) {
218                 if (successCB)
219                         successCB.apply(self, JSON.parse(str));
220         }
221
222         function callMethodErrorCB(error) {
223                 cloudeebus.log("Error calling method: " + method + " on object: " + self.objectPath + " : " + error.desc);
224                 if (errorCB)
225                         errorCB(error.desc);
226         }
227
228         var arglist = [
229                 self.busConnection.name,
230                 self.busName,
231                 self.objectPath,
232                 ifName,
233                 method,
234                 JSON.stringify(args)
235         ];
236
237         // call dbusSend with bus type, destination, object, message and arguments
238         self.wampSession.call("dbusSend", arglist).then(callMethodSuccessCB, callMethodErrorCB);
239 };
240
241
242 cloudeebus.ProxyObject.prototype.connectToSignal = function(ifName, signal, successCB, errorCB) {
243         
244         var self = this; 
245
246         function signalHandler(id, data) {
247                 if (successCB)
248                         successCB.apply(self, JSON.parse(data));                
249         }
250         
251         function connectToSignalSuccessCB(str) {
252                 try {
253                         self.wampSession.subscribe(str, signalHandler);
254                 }
255                 catch (e) {
256                         cloudeebus.log("Subscribe error: " + e);
257                 }
258         }
259
260         function connectToSignalErrorCB(error) {
261                 cloudeebus.log("Error connecting to signal: " + signal + " on object: " + self.objectPath + " : " + error.desc);
262                 if (errorCB)
263                         errorCB(error.desc);
264         }
265
266         var arglist = [
267                 self.busConnection.name,
268                 self.busName,
269                 self.objectPath,
270                 ifName,
271                 signal
272         ];
273
274         // call dbusSend with bus type, destination, object, message and arguments
275         self.wampSession.call("dbusRegister", arglist).then(connectToSignalSuccessCB, connectToSignalErrorCB);
276 };
277
278
279 cloudeebus.ProxyObject.prototype.disconnectSignal = function(ifName, signal) {
280         try {
281                 this.wampSession.unsubscribe(this.busName + "#" + this.objectPath + "#" + ifName + "#" + signal);
282         }
283         catch (e) {
284                 cloudeebus.log("Unsubscribe error: " + e);
285         }
286 };