1 | |
---|
2 | /* |
---|
3 | * JavaScript library for signing in web browsers - version 0.20 |
---|
4 | * |
---|
5 | * April 2014 (client library ver 0.20) |
---|
6 | * idCard.js - Changed IdCardPluginHandler methods getCertificate(), sign() and getVersion() API and behaviour - the methods must now be used asynchronously with callback functions. Users of 0.14 version need to make changes in the client code to continue using the library (see also user manual for more information). |
---|
7 | * - Added variable 'libraryVersion' which specifies the idCard.js library's version. It is strongly recommended to write the version information to log file during signature creation - additional information is provided in the documentation. |
---|
8 | * - Added method getType() which returns the signing module's type (asynchronous or synchronous). It is strongly recommended to write the type information to log file during signature creation - additional information is provided in the documentation. |
---|
9 | * - User manual "JavaScript library for Signing in Web Browsers" is now available in English. |
---|
10 | * sign.html - sign.html sample application is now available in English. |
---|
11 | * - changed the DigiDocService web service related steps to 'optional' |
---|
12 | * - added idCard.js library's version to the heading section of the sample. |
---|
13 | * - added the signing module's type information to the heading section of the sample. |
---|
14 | * - added Lithuanian to the language selection dropdown. |
---|
15 | * |
---|
16 | * |
---|
17 | * May 2013 (client library ver 0.14) |
---|
18 | * idCard.js - removed support for old plugin-s, default language is English |
---|
19 | * |
---|
20 | * |
---|
21 | * May 2013 (client library ver 0.13) |
---|
22 | * idCard.js - old Mac OSX plugin (application/x-idcard-plugin) support removed |
---|
23 | * |
---|
24 | * |
---|
25 | * 16 Mar 2012 (client library ver 0.12) |
---|
26 | * idCard.js - java applet support removed |
---|
27 | * |
---|
28 | * |
---|
29 | * 7 Sept 2011 (client library ver 0.11) |
---|
30 | * idCard.js - bug fixes, see also header of idCard.js |
---|
31 | * sign.html - minor fixes |
---|
32 | * documentation - "Veebis signeerimise Javascripti klienditeek.doc" - added error codes and description of inner logic behind idCard.js |
---|
33 | * |
---|
34 | * |
---|
35 | * 10 May 2011 (client library ver 0.10) |
---|
36 | * Bug fixes to idCard.js, sign.html, API documentation |
---|
37 | */ |
---|
38 | |
---|
39 | |
---|
40 | |
---|
41 | /* ------------------------------------ */ |
---|
42 | /* --- Variables and data structures --- */ |
---|
43 | /* ------------------------------------ */ |
---|
44 | |
---|
45 | // version of the idCard.js library |
---|
46 | var libraryVersion = '0.20'; |
---|
47 | |
---|
48 | var Certificate = { |
---|
49 | id: null, |
---|
50 | cert: null, |
---|
51 | CN: null, |
---|
52 | issuerCN: null, |
---|
53 | keyUsage: null, |
---|
54 | validFrom: "", // Certificate's "valid from" date, in format dd.mm.yyyy hh:mm:ss (Zulu time-zone) |
---|
55 | validTo: null // Certificate's "valid to" date, in format dd.mm.yyyy hh:mm:ss (Zulu time-zone) |
---|
56 | } |
---|
57 | |
---|
58 | var getCertificatesResponse = { |
---|
59 | certificates: [], |
---|
60 | returnCode: 0 |
---|
61 | } |
---|
62 | |
---|
63 | var SignResponse = { |
---|
64 | signature: null, |
---|
65 | returnCode: 0 |
---|
66 | } |
---|
67 | |
---|
68 | //1..99 are error codes returned by the signing module |
---|
69 | var dictionary = { |
---|
70 | 1: {est: 'Allkirjastamine katkestati', eng: 'Signing was cancelled', lit: 'Pasirašymas nutrauktas', rus: 'Подпись была отменена'}, |
---|
71 | 2: {est: 'Sertifikaate ei leitud', eng: 'Certificate not found', lit: 'Nerastas sertifikatas', rus: 'Сертификат не найден'}, |
---|
72 | 9: {est: 'Vale allkirjastamise PIN', eng: 'Incorrect PIN code', lit:'Incorrect PIN code', rus: 'Неверный ПИН-код'}, |
---|
73 | 12: {est: 'ID-kaardi lugemine ebaõnnestus', eng: 'Unable to read ID-Card', lit: 'Nepavyko perskaityti ID-kortos', rus: 'Невозможно считать ИД-карту'}, |
---|
74 | 14: {est: 'Tehniline viga', eng: 'Technical error', lit: 'Techninė klaida', rus: 'Техническая ошибка'}, |
---|
75 | 15: {est: 'Vajalik tarkvara on puudu', eng: 'Unable to find software', lit: 'Nerasta programinės įranga', rus: 'Отсутствует необходимое программное обеспечение'}, |
---|
76 | 16: {est: 'Vigane sertifikaadi identifikaator', eng: 'Invalid certificate identifier', lit: 'Neteisingas sertifikato identifikatorius',rus: 'Неверный идентификатор сертификата'}, |
---|
77 | 17: {est: 'Vigane räsi', eng: 'Invalid hash', lit: 'Neteisinga santrauka', rus: 'Неверный хеш'}, |
---|
78 | 19: {est: 'Veebis allkirjastamise käivitamine on võimalik vaid https aadressilt', eng: 'Web signing is allowed only from https:// URL', lit: 'Web signing is allowed only from https:// URL', rus: 'Подпись в интернете возможна только с URL-ов, начинающихся с https://'}, |
---|
79 | 100: {est: 'Teie arvutist puudub allkirjastamistarkvara või ei ole Teie operatsioonisüsteemi ja brauseri korral veebis allkirjastamine toetatud. Allkirjastamistarkvara saate aadressilt https://installer.id.ee', eng: 'Web signing module is missing from your computer or web signing is not supported on your operating system and browser platform. Signing software is available from https://installer.id.ee', lit: 'Web signing module is missing from your computer or web signing is not supported on your operating system and browser platform. Signing software is available from https://installer.id.ee', rus: 'На вашем компьютере отстутствует модуль для цифровой подписи в интернете или цифровая подпись в интернете не поддерживается вашей операционной системой и/или браузером. Программное обеспечение доступно здесь: https://installer.id.ee'} |
---|
80 | } |
---|
81 | |
---|
82 | // Variable for internal use in idCard.js |
---|
83 | var loadedPlugin = ''; |
---|
84 | |
---|
85 | |
---|
86 | // Exception |
---|
87 | function IdCardException(returnCode, message) { |
---|
88 | this.returnCode = returnCode; |
---|
89 | |
---|
90 | this.message = message; |
---|
91 | |
---|
92 | this.isError = function () { |
---|
93 | return this.returnCode != 1; |
---|
94 | } |
---|
95 | |
---|
96 | this.isCancelled = function () { |
---|
97 | return this.returnCode == 1; |
---|
98 | } |
---|
99 | } |
---|
100 | |
---|
101 | // This function is meant for internal use, do not use in client code. |
---|
102 | function isPluginSupported(pluginName) { |
---|
103 | if (navigator.mimeTypes && navigator.mimeTypes.length) { |
---|
104 | if (navigator.mimeTypes[pluginName]) { |
---|
105 | return true; |
---|
106 | } else { |
---|
107 | return false; |
---|
108 | } |
---|
109 | } else { |
---|
110 | return false; |
---|
111 | } |
---|
112 | } |
---|
113 | |
---|
114 | // This function is meant for internal use, do not use in client code. |
---|
115 | function checkIfPluginIsLoaded(pluginName, lang) |
---|
116 | { |
---|
117 | var plugin = document.getElementById('IdCardSigning'); |
---|
118 | |
---|
119 | if (pluginName == "digidocPlugin") |
---|
120 | { |
---|
121 | try |
---|
122 | { |
---|
123 | var ver = plugin.version; |
---|
124 | if (ver!==undefined) { |
---|
125 | return true; |
---|
126 | } |
---|
127 | } |
---|
128 | catch (ex) |
---|
129 | { |
---|
130 | } |
---|
131 | |
---|
132 | return false; |
---|
133 | } |
---|
134 | else // Other cases, e.g. pluginName == "" |
---|
135 | { |
---|
136 | return false; |
---|
137 | } |
---|
138 | } |
---|
139 | |
---|
140 | // Loads the signing module to browser |
---|
141 | function loadSigningPlugin(lang, pluginToLoad){ |
---|
142 | |
---|
143 | var pluginHTML = { |
---|
144 | digidocPlugin: '<object id="IdCardSigning" type="application/x-digidoc" style="width: 1px; height: 1px; visibility: hidden;"></object>' |
---|
145 | } |
---|
146 | var plugin; |
---|
147 | |
---|
148 | if (!lang || lang == undefined) |
---|
149 | { |
---|
150 | lang = 'eng'; |
---|
151 | } |
---|
152 | |
---|
153 | // It is checked if the connection is https during the signing module loading |
---|
154 | if (document.location.href.indexOf("https://") == -1) |
---|
155 | { |
---|
156 | throw new IdCardException(19, dictionary[19][lang]); |
---|
157 | } |
---|
158 | |
---|
159 | if (pluginToLoad != undefined) |
---|
160 | { |
---|
161 | if (pluginHTML[pluginToLoad] != undefined) // Signing module with the specified name exists |
---|
162 | { |
---|
163 | document.getElementById('pluginLocation').innerHTML = pluginHTML[pluginToLoad]; |
---|
164 | |
---|
165 | if (!checkIfPluginIsLoaded(pluginToLoad, lang)) |
---|
166 | { |
---|
167 | throw new IdCardException(100, dictionary[100][lang]); |
---|
168 | } |
---|
169 | |
---|
170 | loadedPlugin = pluginToLoad; |
---|
171 | } |
---|
172 | else |
---|
173 | { |
---|
174 | // Throw exception to return information about incorrect signing module's name |
---|
175 | throw new IdCardException(100, dictionary[100][lang]); |
---|
176 | } |
---|
177 | return; |
---|
178 | } else { |
---|
179 | |
---|
180 | if ( // Special case for Mac+Safari combination, it must be checked if the signing module is installed in the user's system. Otherwise an error is shown to the user. |
---|
181 | (!(navigator.userAgent.indexOf('Mac') != -1 && navigator.userAgent.indexOf('Safari') != -1)) || |
---|
182 | isPluginSupported('application/x-digidoc') |
---|
183 | ) |
---|
184 | { |
---|
185 | document.getElementById('pluginLocation').innerHTML = pluginHTML['digidocPlugin']; |
---|
186 | if (checkIfPluginIsLoaded('digidocPlugin', lang)) |
---|
187 | { |
---|
188 | loadedPlugin = "digidocPlugin"; |
---|
189 | return; |
---|
190 | } |
---|
191 | } |
---|
192 | |
---|
193 | // The signing module's loading was unsuccessful, throw exception |
---|
194 | if (loadedPlugin===undefined || loadedPlugin=="") |
---|
195 | { |
---|
196 | throw new IdCardException(100, dictionary[100][lang]); |
---|
197 | } |
---|
198 | } |
---|
199 | } |
---|
200 | |
---|
201 | // Returns ISO 639-1 compatible two-letter language code |
---|
202 | function getISO6391Language(lang) |
---|
203 | { |
---|
204 | var languageMap = {est: 'et', eng: 'en', rus: 'ru', lit: 'lt', et: 'et', en: 'en', ru: 'ru', lt: 'lt'}; |
---|
205 | return languageMap[lang]; |
---|
206 | } |
---|
207 | |
---|
208 | // Returns the signing module's type, possible values are 'SYNC' and 'ASYNC' (synchronous or asynchronous). |
---|
209 | function getType() { |
---|
210 | return 'SYNC'; |
---|
211 | } |
---|
212 | |
---|
213 | // This function is meant for internal use by the library |
---|
214 | function digidocPluginHandler(lang) |
---|
215 | { |
---|
216 | var plugin = document.getElementById('IdCardSigning'); |
---|
217 | |
---|
218 | plugin.pluginLanguage = getISO6391Language(lang); |
---|
219 | |
---|
220 | this.getCertificate = function () { |
---|
221 | var TempCert; |
---|
222 | var response; |
---|
223 | var tmpErrorMessage; |
---|
224 | |
---|
225 | try |
---|
226 | { |
---|
227 | TempCert = plugin.getCertificate(); |
---|
228 | } |
---|
229 | catch (ex) |
---|
230 | { |
---|
231 | |
---|
232 | } |
---|
233 | |
---|
234 | if (plugin.errorCode != "0") |
---|
235 | { |
---|
236 | |
---|
237 | try |
---|
238 | { |
---|
239 | tmpErrorMessage = dictionary[plugin.errorCode][lang]; // Exception is thrown if there is no respective element in the array |
---|
240 | } |
---|
241 | catch (ex) |
---|
242 | { |
---|
243 | tmpErrorMessage = plugin.errorMessage; |
---|
244 | } |
---|
245 | |
---|
246 | throw new IdCardException(parseInt(plugin.errorCode), tmpErrorMessage); |
---|
247 | } |
---|
248 | |
---|
249 | // Workaround for IE - in case the certificate is not returned in HEX format then the value is taken from certificateAsHex field. |
---|
250 | if ((TempCert.cert==undefined)){ |
---|
251 | response = '({' + |
---|
252 | ' id: "' + TempCert.id + '",' + |
---|
253 | ' cert: "'+TempCert.certificateAsHex+'",' + |
---|
254 | ' CN: "' + TempCert.CN + '",' + |
---|
255 | ' issuerCN: "' + TempCert.issuerCN + '",' + |
---|
256 | ' keyUsage: "Non-Repudiation"' + |
---|
257 | // ' validFrom: ' + TempCert.validFrom + ',' + |
---|
258 | // ' validTo: ' + TempCert.validTo + |
---|
259 | '})'; |
---|
260 | response = eval('' + response); |
---|
261 | return response; |
---|
262 | } else { |
---|
263 | return TempCert; |
---|
264 | } |
---|
265 | } |
---|
266 | |
---|
267 | this.sign = function (id, hash ) { |
---|
268 | var response; |
---|
269 | var tmpErrorMessage; |
---|
270 | |
---|
271 | try |
---|
272 | { |
---|
273 | response = plugin.sign(id, hash, ""); |
---|
274 | } |
---|
275 | catch (ex) |
---|
276 | {} |
---|
277 | |
---|
278 | if (plugin.errorCode != "0") |
---|
279 | { |
---|
280 | |
---|
281 | try |
---|
282 | { |
---|
283 | tmpErrorMessage = dictionary[plugin.errorCode][lang]; // Exception is thrown if there is no respective element in the array |
---|
284 | } |
---|
285 | catch (ex) |
---|
286 | { |
---|
287 | tmpErrorMessage = plugin.errorMessage; |
---|
288 | } |
---|
289 | |
---|
290 | throw new IdCardException(parseInt(plugin.errorCode), tmpErrorMessage); |
---|
291 | } |
---|
292 | |
---|
293 | |
---|
294 | if (response == null || response == undefined || response == "") |
---|
295 | { |
---|
296 | response = '({' + 'signature: "",' + 'returnCode: 14' + '})'; |
---|
297 | } |
---|
298 | else |
---|
299 | { |
---|
300 | response = '({' + 'signature: "' + response + '",' + 'returnCode:0' + '})' |
---|
301 | } |
---|
302 | |
---|
303 | response = eval('' + response); |
---|
304 | |
---|
305 | if (response.returnCode != 0) { |
---|
306 | throw new IdCardException(response.returnCode, dictionary[response.returnCode][lang]); |
---|
307 | } |
---|
308 | return response.signature; |
---|
309 | } |
---|
310 | |
---|
311 | this.getVersion = function () { |
---|
312 | return plugin.version; |
---|
313 | } |
---|
314 | } |
---|
315 | |
---|
316 | // Provides the main functionality for signature creation |
---|
317 | function IdCardPluginHandler(lang) |
---|
318 | { |
---|
319 | var plugin = document.getElementById('IdCardSigning'); |
---|
320 | var pluginHandler = null; |
---|
321 | var response = null; |
---|
322 | |
---|
323 | if (!lang || lang == undefined) |
---|
324 | { |
---|
325 | lang = 'eng'; |
---|
326 | } |
---|
327 | |
---|
328 | this.choosePluginHandler = function () { |
---|
329 | return new digidocPluginHandler(lang); |
---|
330 | } |
---|
331 | |
---|
332 | // Get the signer's certificate from the smart card |
---|
333 | this.getCertificate = function (successCallback, failureCallback) { |
---|
334 | |
---|
335 | pluginHandler = this.choosePluginHandler(); |
---|
336 | try { |
---|
337 | var result = pluginHandler.getCertificate(); |
---|
338 | successCallback(result); |
---|
339 | } catch (e) { |
---|
340 | failureCallback(e); |
---|
341 | } |
---|
342 | } |
---|
343 | |
---|
344 | // Get the signature value from the smart card |
---|
345 | this.sign = function (id, hash, successCallback, failureCallback) { |
---|
346 | |
---|
347 | pluginHandler = this.choosePluginHandler(); |
---|
348 | try { |
---|
349 | var result = pluginHandler.sign(id, hash); |
---|
350 | successCallback(result); |
---|
351 | } catch (e) { |
---|
352 | failureCallback(e); |
---|
353 | } |
---|
354 | } |
---|
355 | |
---|
356 | // Get the signing module's version |
---|
357 | this.getVersion = function (successCallback, failureCallback) { |
---|
358 | |
---|
359 | pluginHandler = this.choosePluginHandler(); |
---|
360 | try { |
---|
361 | var result = pluginHandler.getVersion(); |
---|
362 | successCallback(result); |
---|
363 | } catch (e) { |
---|
364 | failureCallback(e); |
---|
365 | } |
---|
366 | } |
---|
367 | |
---|
368 | } |
---|