1/* eslint-disable */ 2// JavaScript library as described in 3// https://github.com/open-eid/hwcrypto.js 4var hwcrypto = (function hwcrypto() { 5 'use strict'; 6 var chromeExtensionName = null; 7 var npapiPluginName = null; 8 var nativeHostVersion = null; 9 var isignDebug = function(x) { 10 // console.log(x); 11 }; 12 var pluginAvailable = false; 13 isignDebug("hwcrypto.js activated"); 14 // Fix up IE8 15 window.addEventListener = window.addEventListener || window.attachEvent; 16 // Returns "true" if a plugin is present for the MIME 17 function hasPluginFor(mime) { 18 if(hwcrypto.pluginAvailable){ 19 return true; 20 } 21 22 return navigator.mimeTypes && mime in navigator.mimeTypes; 23 } 24 // Checks if a function is present (used for Chrome) 25 function hasExtensionFor(cls) { 26 try{ 27 if (typeof parent[cls] === "function"){ 28 window[cls] = parent[cls]; 29 } 30 }catch(e){ 31 //ignore if can't access parent 32 } 33 if (typeof window[cls] === "function") return true; 34 return false; 35 } 36 37 function _hex2array(str) { 38 if(typeof str == 'string') { 39 var len = Math.floor(str.length / 2); 40 var ret = new Uint8Array(len); 41 for (var i = 0; i < len; i++) { 42 ret[i] = parseInt(str.substr(i * 2, 2), 16); 43 } 44 return ret; 45 } 46 } 47 48 function _array2hex(args) { 49 var ret = ""; 50 for(var i = 0; i < args.length; i++) ret += (args[i] < 16 ? "0" : "") + args[i].toString(16); 51 return ret.toLowerCase(); 52 } 53 54 function _mimeid(mime) { 55 return "hwc" + mime.replace('/', '').replace('-', ''); 56 } 57 58 function loadPluginFor(mime) { 59 var element = _mimeid(mime); 60 if(document.getElementById(element)) { 61 isignDebug("Plugin element already loaded"); 62 return document.getElementById(element); 63 } 64 isignDebug('Loading plugin for ' + mime + ' into ' + element); 65 // Must insert tag as string (not as an Element object) so that IE9 can access plugin methods 66 var objectTag = '<object id="' + element + '" type="' + mime + '" style="width: 1px; height: 1px; position: absolute; visibility: hidden;"></object>'; 67 var div = document.createElement("div"); 68 div.setAttribute("id", 'pluginLocation' + element); 69 document.body.appendChild(div); 70 // Must not manipulate body's innerHTML directly, otherwise previous Element references get lost 71 document.getElementById('pluginLocation' + element).innerHTML = objectTag; 72 return document.getElementById(element); 73 } 74 // Important constants 75 76 var chromeExtensionNames = { 77 'lt': 'IsignChromeSigning', 78 'fi': 'IsignChromeSigning', 79 'lv': 'eParakstsTokenSigning', 80 'ee': 'TokenSigning', 81 'e-residency': 'TokenSigning', 82 'be': 'IsignChromeSigning', 83 'is': 'IsignChromeSigning' 84 }; 85 var npapiPluginNames = { 86 'lt': null, 87 'fi': null, 88 'lv': 'application/x-eparaksts', 89 'ee': 'application/x-digidoc', 90 'e-residency': 'application/x-digidoc', 91 'be': null, 92 'is': null 93 }; 94 // Some error strings 95 var USER_CANCEL = "user_cancel"; 96 var NO_CERTIFICATES = "no_certificates"; 97 var INVALID_ARGUMENT = "invalid_argument"; 98 var TECHNICAL_ERROR = "technical_error"; 99 var NO_IMPLEMENTATION = "no_implementation"; 100 var NOT_ALLOWED = "not_allowed"; 101 // Probe all existing backends in a failsafe manner. 102 function probe() { 103 fields.calculateHash = false; 104 var msg = 'probe() detected '; 105 // First try Chrome extensions 106 if(hasExtensionFor(window.hwcrypto.chromeExtensionName)) { 107 isignDebug(msg + window.hwcrypto.chromeExtensionName); 108 if(window.hwcrypto.chromeExtensionName != chromeExtensionNames['lt']){ 109 fields.calculateHash = true; 110 extensionLoaded(); 111 }else{ 112 window.hwcrypto.getVersion().then(function(response) { 113// if(typeof response.nativeHostVersion == "undefined"){ 114// updateRequired(); 115// return; 116// } 117 if(response.nativeHostVersion){ 118 nativeHostVersion = response.nativeHostVersion; 119 } 120 extensionLoaded(); 121 }, function(error) { 122 extensionUnavailable(); 123 }); 124 } 125 126 return; 127 } 128 129 130 if(window.hwcrypto.npapiPluginName != null) { 131 _testAndUse(DigiDocPlugin).then(function(result) { 132 if (result) { 133 isignDebug(msg + window.hwcrypto.npapiPluginName); 134 hwcrypto.pluginAvailable = true; 135 fields.calculateHash = true; 136 extensionLoaded(); 137 } else { 138 extensionUnavailable(); 139 } 140 }); 141 return; 142 }else{ 143 extensionUnavailable(); 144 } 145 } 146 // TODO: remove 147// window.addEventListener('load', function(event) { 148// // There's a timeout because chrome content script needs to be loaded 149// probe(); 150// }); 151 // Backend for DigiDoc plugin 152 function DigiDocPlugin() { 153 this._name = "NPAPI/BHO for application/x-digidoc"; 154 var p = loadPluginFor(window.hwcrypto.npapiPluginName); 155 // keeps track of detected certificates and their ID-s 156 var certificate_ids = {}; 157 158 function code2str(err) { 159 isignDebug("Error: " + err + " with: " + p.errorMessage); 160 switch(parseInt(err)) { 161 case 1: 162 return USER_CANCEL; 163 case 2: 164 return INVALID_ARGUMENT; 165 case 17: 166 // invalid hash length 167 return INVALID_ARGUMENT; 168 case 19: 169 return NOT_ALLOWED; 170 default: 171 isignDebug("Unknown error: " + err + " with: " + p.errorMessage); 172 return TECHNICAL_ERROR; 173 } 174 } 175 176 function code2err(err) { 177 return new Error(code2str(err)); 178 } 179 this.check = function() { 180 return new Promise(function(resolve, reject) { 181 // IE8 cannot access the newly inserted plugin object before the end of call queue 182 setTimeout(function() { 183 resolve(typeof p.version !== "undefined"); 184 }, 0); 185 }); 186 }; 187 this.getVersion = function() { 188 return new Promise(function(resolve, reject) { 189 var v = p.version; 190 resolve(v); 191 }); 192 }; 193 this.getCertificate = function(options) { 194 // Ignore everything except language 195 if(options && options.lang) { 196 p.pluginLanguage = options.lang; 197 } 198 return new Promise(function(resolve, reject) { 199 try { 200 var v = p.getCertificate(); 201 if(parseInt(p.errorCode) !== 0) { 202 reject(code2err(p.errorCode)); 203 } else { 204 // Store plugin-internal ID 205 certificate_ids[v.cert] = v.id; 206 resolve({ 207 hex: v.cert 208 }); 209 } 210 } catch(ex) { 211 isignDebug(ex); 212 reject(code2err(p.errorCode)); 213 } 214 }); 215 }; 216 this.sign = function(cert, hash, options) { 217 return new Promise(function(resolve, reject) { 218 // get the ID of the certificate 219 var cid = certificate_ids[cert.hex]; 220 if(cid) { 221 try { 222 //var v = p.sign(cid, hash, 'en'); // FIXME: only BHO requires language but does not use it 223 var language = options.lang || 'en'; 224 //p.pluginLanguage = language; 225 var v = p.sign(cid, hash.hex, language); 226 resolve({ 227 hex: v 228 }); 229 } catch(ex) { 230 isignDebug(JSON.stringify(ex)); 231 reject(code2err(p.errorCode)); 232 } 233 } else { 234 isignDebug("invalid certificate: " + cert); 235 reject(new Error(INVALID_ARGUMENT)); 236 } 237 }); 238 }; 239 }
240 // Backend for Digidoc Chrome Extension 241 function DigiDocExtension() { 242 this._name = "Chrome native messaging extension"; 243 var p = null; 244 var _this = this; 245 this.check = function() { 246 return new Promise(function(resolve, reject) { 247 if (!hasExtensionFor(window.hwcrypto.chromeExtensionName)) { 248 return resolve(false); 249 } 250 // FIXME: remove this from content script! 251 p = new window[window.hwcrypto.chromeExtensionName](); 252 if (p) { 253 resolve(true); 254 } else { 255 resolve(false); 256 } 257 }); 258 }; 259 this.getVersion = function() { 260 return p.getVersion(); 261 }; 262 this.getCertificate = function(options) { 263 return p.getCertificate(options); 264 }; 265 this.sign = function(cert, hash, options) { 266 return p.sign(cert, hash, options); 267 }; 268 } 269 270 // Dummy 271 function NoBackend() { 272 this._name = "No implementation"; 273 this.check = function() { 274 return new Promise(function(resolve, reject) { 275 resolve(true); 276 }); 277 }; 278 this.getVersion = function() { 279 return Promise.reject(new Error(NO_IMPLEMENTATION)); 280 }; 281 this.getCertificate = function() { 282 return Promise.reject(new Error(NO_IMPLEMENTATION)); 283 }; 284 this.sign = function() { 285 return Promise.reject(new Error(NO_IMPLEMENTATION)); 286 }; 287 } 288 // Active backend 289 var _backend = null; 290 // To be exposed 291 var fields = {}; 292 293 function _testAndUse(Backend) { 294 return new Promise(function(resolve, reject) { 295 var b = new Backend(); 296 b.check().then(function(isLoaded) { 297 if (isLoaded) { 298 isignDebug("Using backend: " + b._name); 299 _backend = b; 300 resolve(true); 301 } else { 302 isignDebug(b._name + " check() failed"); 303 resolve(false); 304 } 305 }); 306 }); 307 } 308 309 function browserSupportsIsignExtension(){ 310 var userAgent = navigator.userAgent.toLowerCase(); 311 312 if(userAgent.match(/opera|opr\//)){ 313 return false; 314 } 315 316 if(userAgent.indexOf('chrome') > -1){ 317 return true; 318 } 319 320 if(userAgent.indexOf('firefox') > -1){ 321 var matches = userAgent.match(/firefox\/([0-9\.]+)/); 322 if(matches.length > 1 && parseInt(matches[1]) >= 50){ 323 return true; 324 } 325 } 326 327 return false; 328 } 329 330 function _autodetect(force) { 331 return new Promise(function(resolve, reject) { 332 isignDebug("Autodetecting best backend"); 333 if (typeof force === 'undefined') { 334 force = false; 335 } 336 if (_backend !== null && !force) { 337 return resolve(true); 338 } 339 340 function tryDigiDocPlugin() { 341 _testAndUse(DigiDocPlugin).then(function(result) { 342 if (result) { 343 resolve(true); 344 } else { 345 resolve(_testAndUse(NoBackend)); 346 } 347 }); 348 } 349 350 // IE BHO 351 if (navigator.userAgent.indexOf("MSIE") != -1 || navigator.userAgent.indexOf("Trident") != -1) { 352 isignDebug("Assuming IE BHO, testing"); 353 return tryDigiDocPlugin(); 354 } 355 356 // Chrome extension or NPAPI 357 if (browserSupportsIsignExtension() && hasExtensionFor(window.hwcrypto.chromeExtensionName)) { 358 _testAndUse(DigiDocExtension).then(function(result) { 359 if (result) { 360 resolve(true); 361 } else { 362 tryDigiDocPlugin(); 363 } 364 }); 365 return; 366 } 367 368 // Other browsers with NPAPI support 369 if (window.hwcrypto.npapiPluginName != null && hasPluginFor(window.hwcrypto.npapiPluginName)) { 370 return tryDigiDocPlugin(); 371 } 372 373 // No backend supported 374 resolve(_testAndUse(NoBackend)); 375 }); 376 } 377 // Use a specific backend or autodetect 378 fields.use = function(backend) { 379 return new Promise(function(resolve, reject) { 380 if (typeof backend === "undefined" || backend === 'auto') { 381 _autodetect().then(function(result) { resolve(result);}); 382 } else { 383 if (backend === "chrome") { 384 resolve(_testAndUse(DigiDocExtension)); 385 } else if (backend === "npapi") { 386 resolve(_testAndUse(DigiDocPlugin)); 387 } else { 388 resolve(false); // unknown backend 389 } 390 } 391 }); 392 }; 393 // Give debugging information. 394 fields.debug = function() { 395 return new Promise(function(resolve, reject) { 396 var hwversion = "hwcrypto.js 0.0.10"; 397 _autodetect().then(function(result) { 398 _backend.getVersion().then(function(version) { 399 resolve(hwversion + " with " + _backend._name + " " + version); 400 }, function(error) { 401 resolve(hwversion + " with failing backend " + _backend._name); 402 }); 403 }); 404 }); 405 }; 406 fields.getVersion = function() { 407 return _autodetect().then(function(result) { 408 return _backend.getVersion().then(function(result) { 409 return result; 410 }); 411 }); 412 }; 413 // Get a certificate 414 fields.getCertificate = function(options) { 415 if(typeof options !== 'object') { 416 isignDebug("getCertificate options parameter must be an object"); 417 return Promise.reject(new Error(INVALID_ARGUMENT)); 418 } 419 // If options does not specify a language, set to 'en' 420 if(options && !options.lang) { 421 options.lang = 'en'; 422 } 423 if (options && !options.certificatePurpose) { 424 options.certificatePurpose = "sign"; 425 } 426 if (options && !options.bulkSigning) { 427 options.bulkSigning = false;
428 } 429 if (options && !options.isInitial) { 430 options.isInitial = false; 431 } 432 if (options && !options.policyIds) { 433 options.policyIds = []; 434 } 435 return _autodetect().then(function(result) { 436 // FIXME: dummy security check in website context 437// if (location.protocol !== 'https:' && location.protocol !== 'file:') { 438// return Promise.reject(new Error(NOT_ALLOWED)); 439// } 440 return _backend.getCertificate(options).then(function(certificate) { 441 // Add binary value as well 442 if (certificate.hardwareLabel && nativeHostVersion == '1.1.0' && typeof updateRequired === 'function'){ 443 updateRequired(); 444 return {'hex': ''}; 445 } 446 if (certificate.hex && !certificate.encoded) 447 certificate.encoded = _hex2array(certificate.hex); 448 return certificate; 449 }); 450 }); 451 }; 452 // Sign a hash 453 fields.sign = function(cert, hash, options) { 454 if (arguments.length < 2) 455 return Promise.reject(new Error(INVALID_ARGUMENT)); 456 // If options does not specify a language, set to 'en' 457 if(options && !options.lang) { 458 options.lang = 'en'; 459 } 460 // Hash type and value must be present 461 if (!hash.type || (!hash.value && !hash.hex)) 462 return Promise.reject(new Error(INVALID_ARGUMENT)); 463 464 // Convert Hash to hex and vice versa. 465 // TODO: All backends currently expect the presence of Hex. 466 if (hash.hex && !hash.value) { 467 isignDebug("DEPRECATED: hash.hex as argument to sign() is deprecated, use hash.value instead"); 468 hash.value = _hex2array(hash.hex); 469 } 470 if (hash.value && !hash.hex) 471 hash.hex = _array2hex(hash.value); 472 473 return _autodetect().then(function(result) { 474 // FIXME: dummy security check in website context 475// if(location.protocol !== 'https:' && location.protocol !== 'file:') { 476// return Promise.reject(new Error(NOT_ALLOWED)); 477// } 478 return _backend.sign(cert, hash, options).then(function(signature) { 479 // Add binary value as well 480 // TODO: all backends return hex currently 481 if (signature.hex && !signature.value) 482 signature.value = _hex2array(signature.hex); 483 return signature; 484 }); 485 }); 486 }; 487 fields.reset = function(){ 488 _backend = null; 489 }; 490 fields.probe = probe; 491 fields.hasExtensionFor = hasExtensionFor; 492 fields.hasPluginFor = hasPluginFor; 493 fields.NO_IMPLEMENTATION = NO_IMPLEMENTATION; 494 fields.USER_CANCEL = USER_CANCEL; 495 fields.NOT_ALLOWED = NOT_ALLOWED; 496 fields.NO_CERTIFICATES = NO_CERTIFICATES; 497 fields.TECHNICAL_ERROR = TECHNICAL_ERROR; 498 fields.INVALID_ARGUMENT = INVALID_ARGUMENT; 499 fields.calculateHash = false; 500 fields.chromeExtensionNames = chromeExtensionNames; 501 fields.npapiPluginNames = npapiPluginNames; 502 fields.missingDriversUrls = { 503 'lt': 'https://www.isign.io/lt/tvarkykliu-atsisiuntimai', 504 'en': 'https://www.isign.io/driver-downloads', 505 'et': 'https://www.isign.io/driver-downloads', 506 'ru': 'https://www.isign.io/driver-downloads', 507 'is': 'https://www.audkenni.is/en/electronic-certificates/nexus-hugbunadur-en/', 508 }; 509 fields.missingSoftwareUrls = { 510 'lt': { 511 'lt': 'https://www.isign.io/lt/atsisiuntimai', 512 'en': 'https://www.isign.io/downloads', 513 'et': 'https://www.isign.io/downloads', 514 'ru': 'https://www.isign.io/downloads' 515 }, 516 'fi': { 517 'lt': 'https://www.isign.io/lt/atsisiuntimai', 518 'en': 'https://www.isign.io/downloads', 519 'et': 'https://www.isign.io/downloads', 520 'ru': 'https://www.isign.io/downloads' 521 }, 522 'lv': { 523 'lt': 'https://www.eparaksts.lv/en/', 524 'en': 'https://www.eparaksts.lv/en/', 525 'et': 'https://www.eparaksts.lv/en/', 526 'ru': 'https://www.eparaksts.lv/ru/', 527 'lv': 'https://www.eparaksts.lv/lv/' 528 }, 529 'ee': { 530 'lt': 'https://installer.id.ee/?lang=eng', 531 'en': 'https://installer.id.ee/?lang=eng', 532 'et': 'https://installer.id.ee/', 533 'ru': 'https://installer.id.ee/?lang=rus' 534 }, 535 'e-residency': { 536 'lt': 'https://installer.id.ee/?lang=eng', 537 'en': 'https://installer.id.ee/?lang=eng', 538 'et': 'https://installer.id.ee/', 539 'ru': 'https://installer.id.ee/?lang=rus' 540 }, 541 'be': { 542 'lt': 'https://www.isign.io/lt/atsisiuntimai', 543 'en': 'https://www.isign.io/downloads', 544 'et': 'https://www.isign.io/downloads', 545 'ru': 'https://www.isign.io/downloads' 546 }, 547 'is': { 548 'lt': 'https://www.isign.io/lt/atsisiuntimai', 549 'en': 'https://www.isign.io/downloads', 550 'et': 'https://www.isign.io/downloads', 551 'ru': 'https://www.isign.io/downloads' 552 }, 553 }; 554 return fields; 555}());
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.