[ACR][secure element] extension of listener
[platform/core/api/webapi-plugins.git] / src / secureelement / secureelement_api.js
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
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 var validator_ = xwalk.utils.validator;
18 var types_ = validator_.Types;
19 var type_utils = xwalk.utils.type;
20 var native_ = new xwalk.utils.NativeManager(extension);
21 var privUtils_ = xwalk.utils;
22 var privilege_ = xwalk.utils.privilege;
23
24 //////////////////SEService/////////////////
25
26 function ListenerManager(native, listenerName) {
27     this.listeners = {};
28     this.nextId = 1;
29     this.nativeSet = false;
30     this.native = native;
31     this.listenerName = listenerName;
32 }
33
34 ListenerManager.prototype.onListenerCalled = function(msg) {
35     var d = undefined;
36     var e = undefined;
37     switch (msg.action) {
38     case 'onSEError':
39         e = new WebAPIException(
40             WebAPIException.IO_ERR,
41             'I/O error occurred on Secure Element reader'
42         );
43     case 'onSEReady':
44     case 'onSENotReady':
45     case 'onUSBCardInserted':
46     case 'onUSBCardRemoved':
47         d = new Reader(msg.handle);
48         break;
49     default:
50         privUtils_.log('Unknown mode: ' + msg.action);
51         return;
52     }
53
54     for (var watchId in this.listeners) {
55         if (
56             this.listeners.hasOwnProperty(watchId) &&
57             this.listeners[watchId][msg.action]
58         ) {
59             this.listeners[watchId][msg.action](d, e);
60         }
61     }
62 };
63
64 ListenerManager.prototype.addListener = function(callback) {
65     var id = this.nextId;
66     if (!this.nativeSet) {
67         this.native.addListener(this.listenerName, this.onListenerCalled.bind(this));
68         var result = this.native.callSync('SEServiceRegisterSEListener');
69         if (this.native.isFailure(result)) {
70             throw this.native.getErrorObject(result);
71         }
72         this.nativeSet = true;
73     }
74
75     this.listeners[id] = callback;
76     ++this.nextId;
77
78     return id;
79 };
80
81 ListenerManager.prototype.removeListener = function(watchId) {
82     if (type_utils.isEmptyObject(this.listeners)) {
83         privUtils_.checkPrivilegeAccess(privilege_.SECUREELEMENT);
84     }
85
86     if (this.listeners.hasOwnProperty(watchId)) {
87         delete this.listeners[watchId];
88     }
89
90     if (this.nativeSet && type_utils.isEmptyObject(this.listeners)) {
91         var result = this.native.callSync('SEServiceUnregisterSEListener');
92         if (this.native.isFailure(result)) {
93             throw this.native.getErrorObject(result);
94         }
95         this.native.removeListener(this.listenerName);
96         this.nativeSet = false;
97     }
98 };
99
100 var SE_CHANGE_LISTENER = 'SecureElementChangeListener';
101 var SEChangeListener = new ListenerManager(native_, SE_CHANGE_LISTENER);
102
103 function SEService() {}
104
105 var SEServiceGetReaders = function() {
106     xwalk.utils.checkPrivilegeAccess(xwalk.utils.privilege.SECUREELEMENT);
107     var args = validator_.validateArgs(arguments, [
108         { name: 'successCallback', type: types_.FUNCTION },
109         { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
110     ]);
111
112     var callback = function(result) {
113         if (native_.isFailure(result)) {
114             native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
115         } else {
116             var result_obj = native_.getResultObject(result);
117             var readers_array = [];
118
119             result_obj.forEach(function(data) {
120                 readers_array.push(new Reader(data));
121             });
122
123             args.successCallback(readers_array);
124         }
125     };
126
127     var result = native_.call('SEServiceGetReaders', {}, callback);
128     if (native_.isFailure(result)) {
129         throw native_.getErrorObject(result);
130     }
131 };
132
133 SEService.prototype.getReaders = function() {
134     SEServiceGetReaders.apply(this, arguments);
135 };
136
137 var SEServiceRegisterSEListener = function() {
138     xwalk.utils.checkPrivilegeAccess(xwalk.utils.privilege.SECUREELEMENT);
139     var args = validator_.validateArgs(arguments, [
140         {
141             name: 'eventCallback',
142             type: types_.LISTENER,
143             values: ['onSEReady', 'onSENotReady', 'onSEError']
144         }
145     ]);
146
147     return SEChangeListener.addListener(args.eventCallback);
148 };
149
150 SEService.prototype.registerSEListener = function() {
151     return SEServiceRegisterSEListener.apply(this, arguments);
152 };
153
154 var SEServiceUnregisterSEListener = function() {
155     xwalk.utils.checkPrivilegeAccess(xwalk.utils.privilege.SECUREELEMENT);
156     var args = validator_.validateArgs(arguments, [
157         {
158             name: 'id',
159             type: types_.UNSIGNED_LONG
160         }
161     ]);
162
163     SEChangeListener.removeListener(args.id);
164 };
165
166 SEService.prototype.unregisterSEListener = function() {
167     SEServiceUnregisterSEListener.apply(this, arguments);
168 };
169
170 var SEServiceShutdown = function() {
171     xwalk.utils.checkPrivilegeAccess(xwalk.utils.privilege.SECUREELEMENT);
172     var result = native_.callSync('SEServiceShutdown', {});
173
174     if (native_.isFailure(result)) {
175         throw native_.getErrorObject(result);
176     }
177 };
178
179 SEService.prototype.shutdown = function() {
180     SEServiceShutdown.apply(this, arguments);
181 };
182
183 //////////////////Reader/////////////////
184
185 function Reader(reader_handle) {
186     Object.defineProperties(this, {
187         isPresent: {
188             configurable: false,
189             enumerable: true,
190             set: function() {},
191             get: function() {
192                 var callArgs = { handle: reader_handle };
193                 var result = native_.callSync('SEReaderIsPresent', callArgs);
194                 if (native_.isFailure(result)) {
195                     privUtils_.log(
196                         'SEReader_isPresent error: ' + native_.getErrorObject(result)
197                     );
198                     return false;
199                 } else {
200                     return native_.getResultObject(result);
201                 }
202             }
203         },
204         _handle: {
205             configurable: false,
206             enumerable: false,
207             set: function() {},
208             get: function() {
209                 return reader_handle;
210             }
211         }
212     });
213 }
214
215 Reader.prototype.getName = function() {
216     var callArgs = { handle: this._handle };
217     var result = native_.callSync('SEReaderGetName', callArgs);
218
219     if (native_.isFailure(result)) {
220         throw native_.getErrorObject(result);
221     }
222
223     return native_.getResultObject(result);
224 };
225
226 Reader.prototype.openSession = function() {
227     var args = validator_.validateArgs(arguments, [
228         { name: 'successCallback', type: types_.FUNCTION },
229         { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
230     ]);
231
232     var callback = function(result) {
233         if (native_.isFailure(result)) {
234             native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
235         } else {
236             var result_obj = native_.getResultObject(result);
237             var session = new Session(result_obj.handle);
238             args.successCallback(session);
239         }
240     };
241
242     var callArgs = { handle: this._handle };
243
244     var result = native_.call('SEReaderOpenSession', callArgs, callback);
245
246     if (native_.isFailure(result)) {
247         throw native_.getErrorObject(result);
248     }
249 };
250
251 Reader.prototype.closeSessions = function() {
252     var callArgs = { handle: this._handle };
253     var result = native_.callSync('SEReaderCloseSessions', callArgs);
254     if (native_.isFailure(result)) {
255         throw native_.getErrorObject(result);
256     }
257 };
258
259 //////////////////Channel/////////////////
260
261 function Channel(channel_handle, is_basic_channel) {
262     Object.defineProperties(this, {
263         _handle: {
264             enumerable: false,
265             configurable: false,
266             set: function() {},
267             get: function() {
268                 return channel_handle;
269             }
270         },
271         isBasicChannel: {
272             enumerable: true,
273             configurable: false,
274             set: function() {},
275             get: function() {
276                 return is_basic_channel;
277             }
278         }
279     });
280 }
281
282 Channel.prototype.close = function() {
283     var callArgs = { handle: this._handle };
284     var result = native_.callSync('SEChannelClose', callArgs);
285
286     if (native_.isFailure(result)) {
287         throw native_.getErrorObject(result);
288     }
289 };
290
291 Channel.prototype.transmit = function() {
292     var args = validator_.validateArgs(arguments, [
293         { name: 'command', type: types_.ARRAY, values: types_.BYTE },
294         { name: 'successCallback', type: types_.FUNCTION },
295         { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
296     ]);
297
298     var callback = function(result) {
299         if (native_.isFailure(result)) {
300             native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
301         } else {
302             args.successCallback(native_.getResultObject(result));
303         }
304     };
305
306     var callArgs = {
307         handle: this._handle,
308         command: args.command
309     };
310
311     var result = native_.call('SEChannelTransmit', callArgs, callback);
312
313     if (native_.isFailure(result)) {
314         throw native_.getErrorObject(result);
315     }
316 };
317
318 Channel.prototype.getSelectResponse = function() {
319     var callArgs = { handle: this._handle };
320     var result = native_.callSync('SEChannelGetSelectResponse', callArgs);
321
322     if (native_.isFailure(result)) {
323         throw native_.getErrorObject(result);
324     }
325 };
326
327 //////////////////Session/////////////////
328
329 function Session(session_handle) {
330     Object.defineProperties(this, {
331         isClosed: {
332             configurable: false,
333             enumerable: true,
334             set: function() {},
335             get: function() {
336                 var callArgs = { handle: session_handle };
337                 var result = native_.callSync('SESessionIsClosed', callArgs);
338                 if (native_.isFailure(result)) {
339                     privUtils_.log(
340                         'SESession_isClosed error: ' + native_.getErrorObject(result)
341                     );
342                     return true;
343                 } else {
344                     return native_.getResultObject(result);
345                 }
346             }
347         },
348         _handle: {
349             enumerable: false,
350             configurable: false,
351             set: function() {},
352             get: function() {
353                 return session_handle;
354             }
355         }
356     });
357 }
358
359 Session.prototype.openBasicChannel = function() {
360     var args = validator_.validateArgs(arguments, [
361         { name: 'aid', type: types_.ARRAY, values: types_.BYTE },
362         { name: 'successCallback', type: types_.FUNCTION },
363         { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
364     ]);
365
366     var callback = function(result) {
367         if (native_.isFailure(result)) {
368             native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
369         } else {
370             var result_obj = native_.getResultObject(result);
371             var channel = new Channel(result_obj.handle, result_obj.isBasicChannel);
372             args.successCallback(channel);
373         }
374     };
375
376     var callArgs = {
377         handle: this._handle,
378         aid: args.aid
379     };
380
381     var result = native_.call('SESessionOpenBasicChannel', callArgs, callback);
382
383     if (native_.isFailure(result)) {
384         throw native_.getErrorObject(result);
385     }
386 };
387
388 Session.prototype.openLogicalChannel = function() {
389     var args = validator_.validateArgs(arguments, [
390         { name: 'aid', type: types_.ARRAY, values: types_.BYTE },
391         { name: 'successCallback', type: types_.FUNCTION },
392         { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
393     ]);
394
395     var callback = function(result) {
396         if (native_.isFailure(result)) {
397             native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
398         } else {
399             var result_obj = native_.getResultObject(result);
400             var channel = new Channel(result_obj.handle, result_obj.isBasicChannel);
401             args.successCallback(channel);
402         }
403     };
404
405     var callArgs = {
406         handle: this._handle,
407         aid: args.aid
408     };
409
410     var result = native_.call('SESessionOpenLogicalChannel', callArgs, callback);
411
412     if (native_.isFailure(result)) {
413         throw native_.getErrorObject(result);
414     }
415 };
416
417 Session.prototype.getATR = function() {
418     var callArgs = { handle: this._handle };
419     var result = native_.callSync('SESessionGetATR', callArgs);
420     if (native_.isFailure(result)) {
421         throw native_.getErrorObject(result);
422     } else {
423         return native_.getResultObject(result);
424     }
425 };
426
427 Session.prototype.close = function() {
428     var callArgs = { handle: this._handle };
429     var result = native_.callSync('SESessionClose', callArgs);
430
431     if (native_.isFailure(result)) {
432         throw native_.getErrorObject(result);
433     }
434 };
435
436 Session.prototype.closeChannels = function() {
437     var callArgs = { handle: this._handle };
438     var result = native_.callSync('SESessionCloseChannels', callArgs);
439
440     if (native_.isFailure(result)) {
441         throw native_.getErrorObject(result);
442     }
443 };
444
445 exports = new SEService();