Merge branch 'master' into single-codebase

# Conflicts:
#	dist/1.crypto-pro.js.map
#	dist/2.crypto-pro.js.map
#	dist/crypto-pro.js.map
#	npm-shrinkwrap.json
This commit is contained in:
vgoma 2017-11-29 14:34:32 +03:00
commit 1b4c840d55
18 changed files with 944 additions and 1448 deletions

View File

@ -7,13 +7,23 @@
- [Mozilla Firefox](https://www.mozilla.org/ru/firefox/new/) (v43+). Начиная с версии 52, с [расширением](https://www.cryptopro.ru/sites/default/files/products/cades/extensions/cryptopro_extension_for_cades_browser_plug_in-1.1.1-an+fx-windows.xpi). - [Mozilla Firefox](https://www.mozilla.org/ru/firefox/new/) (v43+). Начиная с версии 52, с [расширением](https://www.cryptopro.ru/sites/default/files/products/cades/extensions/cryptopro_extension_for_cades_browser_plug_in-1.1.1-an+fx-windows.xpi).
- [Internet Explorer](http://windows.microsoft.com/ru-ru/internet-explorer/download-ie) (v8+). - [Internet Explorer](http://windows.microsoft.com/ru-ru/internet-explorer/download-ie) (v8+).
Полифилл для Promise необходимо подключать самостоятельно. Список необходимых полифиллов (подключаются самостоятельно):
- Promise
- EventTarget.addEventListener
- Array.prototype.forEach
- Array.prototype.map
## Установка и настройка ## Установка и настройка
### NPM
```bash ```bash
npm install crypto-pro npm install crypto-pro
``` ```
### Bower
```bash
bower install crypto-pro
```
Для корректной работы используйте: Для корректной работы используйте:
1. [КриптоПРО CSP](https://www.cryptopro.ru/products/csp/downloads) (v3.6+) *рекомендуется использование только сертифицированных версий*. Инструкция по установке: 1. [КриптоПРО CSP](https://www.cryptopro.ru/products/csp/downloads) (v3.6+) *рекомендуется использование только сертифицированных версий*. Инструкция по установке:
- [Linux / OSX](#install_csp_linux) - [Linux / OSX](#install_csp_linux)

24
bower.json Normal file
View File

@ -0,0 +1,24 @@
{
"name": "crypto-pro",
"description": "API для взаимодействия с КриптоПро",
"main": "dist/crypto-pro.js",
"authors": [
"vgoma <vgoma@yandex.ru>"
],
"license": "ISC",
"keywords": [
"crypto",
"cryptopro",
"crypto-pro",
"cades",
"КриптоПро"
],
"homepage": "https://github.com/vgoma/crypto-pro",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
]
}

View File

@ -733,7 +733,7 @@ webpackJsonpCryptoPro([1],[
* */ * */
function prepareCertsInfo(items) { function prepareCertsInfo(items) {
return items.map(function (c) { return items.map(function (c) {
c.name = c.subjectName.match(/CN=(.+?),/); c.name = c.subjectName.match(/CN=(.+?)(?:,|$)/);
// Удалось ли вытащить Common Name // Удалось ли вытащить Common Name
if (c.name && c.name[1]) { if (c.name && c.name[1]) {

File diff suppressed because one or more lines are too long

View File

@ -176,7 +176,7 @@ webpackJsonpCryptoPro([2],[
* */ * */
function prepareCertsInfo(items) { function prepareCertsInfo(items) {
return items.map(function (c) { return items.map(function (c) {
c.name = c.subjectName.match(/CN=(.+?),/); c.name = c.subjectName.match(/CN=(.+?)(?:,|$)/);
// Удалось ли вытащить Common Name // Удалось ли вытащить Common Name
if (c.name && c.name[1]) { if (c.name && c.name[1]) {

File diff suppressed because one or more lines are too long

131
dist/crypto-pro.js vendored
View File

@ -741,8 +741,8 @@ var CryptoPro =
var plugin_reject; var plugin_reject;
var plugin_resolve; var plugin_resolve;
var isOpera = 0; var isOpera = 0;
var isYaBrowser = 0;
var isFireFox = 0; var isFireFox = 0;
var isEdge = 0;
var failed_extensions = 0; var failed_extensions = 0;
var canPromise = !!window.Promise; var canPromise = !!window.Promise;
@ -760,6 +760,22 @@ var CryptoPro =
cadesplugin = {}; cadesplugin = {};
} }
function check_browser() {
var ua= navigator.userAgent, tem, M= ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
if(/trident/i.test(M[1])){
tem= /\brv[ :]+(\d+)/g.exec(ua) || [];
return {name:'IE',version:(tem[1] || '')};
}
if(M[1]=== 'Chrome'){
tem= ua.match(/\b(OPR|Edge)\/(\d+)/);
if(tem!= null) return {name:tem[1].replace('OPR', 'Opera'),version:tem[2]};
}
M= M[2]? [M[1], M[2]]: [navigator.appName, navigator.appVersion, '-?'];
if((tem= ua.match(/version\/(\d+)/i))!= null) M.splice(1, 1, tem[1]);
return {name:M[0],version:M[1]};
}
var browserSpecs = check_browser();
function cpcsp_console_log(level, msg){ function cpcsp_console_log(level, msg){
//IE9 не может писать в консоль если не открыта вкладка developer tools //IE9 не может писать в консоль если не открыта вкладка developer tools
if(typeof(console) == 'undefined') if(typeof(console) == 'undefined')
@ -920,9 +936,9 @@ var CryptoPro =
} }
function isIE() { function isIE() {
var retVal = (("Microsoft Internet Explorer" == navigator.appName) || // IE < 11 // var retVal = (("Microsoft Internet Explorer" == navigator.appName) || // IE < 11
navigator.userAgent.match(/Trident\/./i)); // IE 11 // navigator.userAgent.match(/Trident\/./i)); // IE 11
return retVal; return (browserSpecs.name == 'IE' || browserSpecs.name == 'MSIE');
} }
function isIOS() { function isIOS() {
@ -934,25 +950,41 @@ var CryptoPro =
function isNativeMessageSupported() function isNativeMessageSupported()
{ {
var retVal_chrome = navigator.userAgent.match(/chrome/i); // В IE работаем через NPAPI
isOpera = navigator.userAgent.match(/opr/i); if(isIE())
isYaBrowser = navigator.userAgent.match(/YaBrowser/i);
isFireFox = navigator.userAgent.match(/Firefox/i);
if(isFireFox && window.allow_firefox_cadesplugin_async)
return true;
if(retVal_chrome == null) // В IE работаем через NPAPI
return false; return false;
else // В Edge работаем через NativeMessage
{ if(browserSpecs.name == 'Edge') {
// В Chrome и Opera работаем через асинхронную версию isEdge = true;
if(retVal_chrome.length > 0 || isOpera != null ) return true;
{ }
// В Chrome, Firefox и Opera работаем через асинхронную версию в зависимости от версии
if(browserSpecs.name == 'Opera') {
isOpera = true;
if(browserSpecs.version >= 33){
return true; return true;
} }
else{
return false;
}
}
if(browserSpecs.name == 'Firefox') {
isFireFox = true;
if(browserSpecs.version >= 52){
return true;
}
else{
return false;
}
}
if(browserSpecs.name == 'Chrome') {
if(browserSpecs.version >= 42){
return true;
}
else{
return false;
}
} }
return false;
} }
// Функция активации объектов КриптоПро ЭЦП Browser plug-in // Функция активации объектов КриптоПро ЭЦП Browser plug-in
@ -984,7 +1016,7 @@ var CryptoPro =
return new ActiveXObject(name); return new ActiveXObject(name);
} }
} }
// В Firefox, Safari создаются объекты NPAPI // создаются объекты NPAPI
return pluginObject.CreateObject(name); return pluginObject.CreateObject(name);
} }
@ -1018,6 +1050,11 @@ var CryptoPro =
} }
} }
// Функция для удаления созданных объектов
function ReleasePluginObjects() {
return cpcsp_chrome_nmcades.ReleasePluginObjects();
}
// Функция активации асинхронных объектов КриптоПро ЭЦП Browser plug-in // Функция активации асинхронных объектов КриптоПро ЭЦП Browser plug-in
function CreateObjectAsync(name) { function CreateObjectAsync(name) {
return pluginObject.CreateObjectAsync(name); return pluginObject.CreateObjectAsync(name);
@ -1076,6 +1113,35 @@ var CryptoPro =
return tmpobj; return tmpobj;
} }
function show_firefox_missing_extension_dialog()
{
if (!window.cadesplugin_skip_extension_install)
{
var ovr = document.createElement('div');
ovr.id = "cadesplugin_ovr";
ovr.style = "visibility: hidden; position: fixed; left: 0px; top: 0px; width:100%; height:100%; background-color: rgba(0,0,0,0.7)";
ovr.innerHTML = "<div id='cadesplugin_ovr_item' style='position:relative; width:400px; margin:100px auto; background-color:#fff; border:2px solid #000; padding:10px; text-align:center; opacity: 1; z-index: 1500'>" +
"<button id='cadesplugin_close_install' style='float: right; font-size: 10px; background: transparent; border: 1; margin: -5px'>X</button>" +
"<p>Для работы КриптоПро ЭЦП Browser plugin на данном сайте необходимо расширение для браузера. Убедитесь, что оно у Вас включено или установите его." +
"<p><a href='https://www.cryptopro.ru/sites/default/files/products/cades/extensions/firefox_cryptopro_extension_latest.xpi'>Скачать расширение</a></p>" +
"</div>";
document.getElementsByTagName("Body")[0].appendChild(ovr);
document.getElementById("cadesplugin_close_install").addEventListener('click',function()
{
plugin_loaded_error("Плагин недоступен");
document.getElementById("cadesplugin_ovr").style.visibility = 'hidden';
});
ovr.addEventListener('click',function()
{
plugin_loaded_error("Плагин недоступен");
document.getElementById("cadesplugin_ovr").style.visibility = 'hidden';
});
ovr.style.visibility="visible";
}
}
//Выводим окно поверх других с предложением установить расширение для Opera. //Выводим окно поверх других с предложением установить расширение для Opera.
//Если установленна переменная cadesplugin_skip_extension_install - не предлагаем установить расширение //Если установленна переменная cadesplugin_skip_extension_install - не предлагаем установить расширение
function install_opera_extension() function install_opera_extension()
@ -1124,7 +1190,7 @@ var CryptoPro =
} }
} }
function firefox_nmcades_onload() { function firefox_or_edge_nmcades_onload() {
cpcsp_chrome_nmcades.check_chrome_plugin(plugin_loaded, plugin_loaded_error); cpcsp_chrome_nmcades.check_chrome_plugin(plugin_loaded, plugin_loaded_error);
} }
@ -1133,7 +1199,7 @@ var CryptoPro =
window.addEventListener("message", function (event){ window.addEventListener("message", function (event){
if (typeof(event.data) != "string" || !event.data.match("cadesplugin_loaded")) if (typeof(event.data) != "string" || !event.data.match("cadesplugin_loaded"))
return; return;
if(isFireFox) if(isFireFox || isEdge)
{ {
// Для Firefox вместе с сообщением cadesplugin_loaded прилетает url для загрузки nmcades_plugin_api.js // Для Firefox вместе с сообщением cadesplugin_loaded прилетает url для загрузки nmcades_plugin_api.js
var url = event.data.substring(event.data.indexOf("url:") + 4); var url = event.data.substring(event.data.indexOf("url:") + 4);
@ -1141,9 +1207,10 @@ var CryptoPro =
fileref.setAttribute("type", "text/javascript"); fileref.setAttribute("type", "text/javascript");
fileref.setAttribute("src", url); fileref.setAttribute("src", url);
fileref.onerror = plugin_loaded_error; fileref.onerror = plugin_loaded_error;
fileref.onload = firefox_nmcades_onload; fileref.onload = firefox_or_edge_nmcades_onload;
document.getElementsByTagName("head")[0].appendChild(fileref); document.getElementsByTagName("head")[0].appendChild(fileref);
// Для Firefox и Edge у нас только по одному расширению.
failed_extensions++;
}else { }else {
cpcsp_chrome_nmcades.check_chrome_plugin(plugin_loaded, plugin_loaded_error); cpcsp_chrome_nmcades.check_chrome_plugin(plugin_loaded, plugin_loaded_error);
} }
@ -1154,7 +1221,7 @@ var CryptoPro =
function load_extension() function load_extension()
{ {
if(isFireFox){ if(isFireFox || isEdge){
// вызываем callback руками т.к. нам нужно узнать ID расширения. Он уникальный для браузера. // вызываем callback руками т.к. нам нужно узнать ID расширения. Он уникальный для браузера.
nmcades_api_onload(); nmcades_api_onload();
return; return;
@ -1242,6 +1309,10 @@ var CryptoPro =
{ {
if(plugin_resolved == 1) if(plugin_resolved == 1)
return; return;
if(isFireFox)
{
show_firefox_missing_extension_dialog();
}
plugin_resolved = 1; plugin_resolved = 1;
if(canPromise) if(canPromise)
{ {
@ -1307,10 +1378,15 @@ var CryptoPro =
false); false);
}else }else
{ {
window.addEventListener("load", function (event) { if(document.readyState === "complete"){
load_npapi_plugin(); load_npapi_plugin();
check_npapi_plugin(); check_npapi_plugin();
}, false); } else {
window.addEventListener("load", function (event) {
load_npapi_plugin();
check_npapi_plugin();
}, false);
}
} }
} }
@ -1329,6 +1405,7 @@ var CryptoPro =
if(isNativeMessageSupported()) if(isNativeMessageSupported())
{ {
cadesplugin.CreateObjectAsync = CreateObjectAsync; cadesplugin.CreateObjectAsync = CreateObjectAsync;
cadesplugin.ReleasePluginObjects = ReleasePluginObjects;
} }
if(!isNativeMessageSupported()) if(!isNativeMessageSupported())

File diff suppressed because one or more lines are too long

View File

@ -3,7 +3,6 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Пример использования CryptoPro</title> <title>Пример использования CryptoPro</title>
<script src="https://cdn.polyfill.io/v2/polyfill.js"></script>
</head> </head>
<body> <body>
<select id="certList"></select> <select id="certList"></select>
@ -16,7 +15,20 @@
publicPath: '../dist/' publicPath: '../dist/'
}; };
</script> </script>
<!-- Полифиллы для работы библиотеки -->
<script src="polyfills/addEventListener.js"></script>
<script src="polyfills/promise.js"></script>
<script src="polyfills/forEach.js"></script>
<script src="polyfills/map.js"></script>
<!-- Библиотека -->
<script src="../dist/crypto-pro.js"></script> <script src="../dist/crypto-pro.js"></script>
<!-- Полифиллы для работы демо скриптов -->
<script src="polyfills/atob-btoa.js"></script>
<!-- Демо скрипты -->
<script src="cert-list.js"></script> <script src="cert-list.js"></script>
<script src="create-sign.js"></script> <script src="create-sign.js"></script>
</body> </body>

View File

@ -0,0 +1,32 @@
!window.addEventListener && (function (WindowPrototype, DocumentPrototype, ElementPrototype, addEventListener, removeEventListener, dispatchEvent, registry) {
WindowPrototype[addEventListener] = DocumentPrototype[addEventListener] = ElementPrototype[addEventListener] = function (type, listener) {
var target = this;
registry.unshift([target, type, listener, function (event) {
event.currentTarget = target;
event.preventDefault = function () {
event.returnValue = false
};
event.stopPropagation = function () {
event.cancelBubble = true
};
event.target = event.srcElement || target;
listener.call(target, event);
}]);
this.attachEvent("on" + type, registry[0][3]);
};
WindowPrototype[removeEventListener] = DocumentPrototype[removeEventListener] = ElementPrototype[removeEventListener] = function (type, listener) {
for (var index = 0, register; register = registry[index]; ++index) {
if (register[0] == this && register[1] == type && register[2] == listener) {
return this.detachEvent("on" + type, registry.splice(index, 1)[0][3]);
}
}
};
WindowPrototype[dispatchEvent] = DocumentPrototype[dispatchEvent] = ElementPrototype[dispatchEvent] = function (eventObject) {
return this.fireEvent("on" + eventObject.type, eventObject);
};
})(Window.prototype, HTMLDocument.prototype, Element.prototype, "addEventListener", "removeEventListener", "dispatchEvent", []);

View File

@ -0,0 +1,76 @@
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define([], function () {
factory(root);
});
} else factory(root);
// node.js has always supported base64 conversions, while browsers that support
// web workers support base64 too, but you may never know.
})(typeof exports !== "undefined" ? exports : this, function (root) {
if (root.atob) {
// Some browsers' implementation of atob doesn't support whitespaces
// in the encoded string (notably, IE). This wraps the native atob
// in a function that strips the whitespaces.
// The original function can be retrieved in atob.original
try {
root.atob(" ");
} catch (e) {
root.atob = (function (atob) {
var func = function (string) {
return atob(String(string).replace(/[\t\n\f\r ]+/g, ""));
};
func.original = atob;
return func;
})(root.atob);
}
return;
}
// base64 character set, plus padding character (=)
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
// Regular expression to check formal correctness of base64 encoded strings
b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/;
root.btoa = function (string) {
string = String(string);
var bitmap, a, b, c,
result = "", i = 0,
rest = string.length % 3; // To determine the final padding
for (; i < string.length;) {
if ((a = string.charCodeAt(i++)) > 255
|| (b = string.charCodeAt(i++)) > 255
|| (c = string.charCodeAt(i++)) > 255)
throw new TypeError("Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.");
bitmap = (a << 16) | (b << 8) | c;
result += b64.charAt(bitmap >> 18 & 63) + b64.charAt(bitmap >> 12 & 63)
+ b64.charAt(bitmap >> 6 & 63) + b64.charAt(bitmap & 63);
}
// If there's need of padding, replace the last 'A's with equal signs
return rest ? result.slice(0, rest - 3) + "===".substring(rest) : result;
};
root.atob = function (string) {
// atob can work with strings with whitespaces, even inside the encoded part,
// but only \t, \n, \f, \r and ' ', which can be stripped.
string = String(string).replace(/[\t\n\f\r ]+/g, "");
if (!b64re.test(string))
throw new TypeError("Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.");
// Adding the padding if missing, for semplicity
string += "==".slice(2 - (string.length & 3));
var bitmap, result = "", r1, r2, i = 0;
for (; i < string.length;) {
bitmap = b64.indexOf(string.charAt(i++)) << 18 | b64.indexOf(string.charAt(i++)) << 12
| (r1 = b64.indexOf(string.charAt(i++))) << 6 | (r2 = b64.indexOf(string.charAt(i++)));
result += r1 === 64 ? String.fromCharCode(bitmap >> 16 & 255)
: r2 === 64 ? String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255)
: String.fromCharCode(bitmap >> 16 & 255, bitmap >> 8 & 255, bitmap & 255);
}
return result;
};
});

View File

@ -0,0 +1,59 @@
// Шаги алгоритма ECMA-262, 5-е издание, 15.4.4.18
// Ссылка (en): http://es5.github.io/#x15.4.4.18
// Ссылка (ru): http://es5.javascript.ru/x15.4.html#x15.4.4.18
if (!Array.prototype.forEach) {
Array.prototype.forEach = function (callback, thisArg) {
var T, k;
if (this == null) {
throw new TypeError(' this is null or not defined');
}
// 1. Положим O равным результату вызова ToObject passing the |this| value as the argument.
var O = Object(this);
// 2. Положим lenValue равным результату вызова внутреннего метода Get объекта O с аргументом "length".
// 3. Положим len равным ToUint32(lenValue).
var len = O.length >>> 0;
// 4. Если IsCallable(callback) равен false, выкинем исключение TypeError.
// Смотрите: http://es5.github.com/#x9.11
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
// 5. Если thisArg присутствует, положим T равным thisArg; иначе положим T равным undefined.
if (arguments.length > 1) {
T = thisArg;
}
// 6. Положим k равным 0
k = 0;
// 7. Пока k < len, будем повторять
while (k < len) {
var kValue;
// a. Положим Pk равным ToString(k).
// Это неявное преобразование для левостороннего операнда в операторе in
// b. Положим kPresent равным результату вызова внутреннего метода HasProperty объекта O с аргументом Pk.
// Этот шаг может быть объединён с шагом c
// c. Если kPresent равен true, то
if (k in O) {
// i. Положим kValue равным результату вызова внутреннего метода Get объекта O с аргументом Pk.
kValue = O[k];
// ii. Вызовем внутренний метод Call функции callback с объектом T в качестве значения this и
// списком аргументов, содержащим kValue, k и O.
callback.call(T, kValue, k, O);
}
// d. Увеличим k на 1.
k++;
}
// 8. Вернём undefined.
};
}

91
example/polyfills/map.js Normal file
View File

@ -0,0 +1,91 @@
// Шаги алгоритма ECMA-262, 5-е издание, 15.4.4.19
// Ссылка (en): http://es5.github.com/#x15.4.4.19
// Ссылка (ru): http://es5.javascript.ru/x15.4.html#x15.4.4.19
if (!Array.prototype.map) {
Array.prototype.map = function(callback, thisArg) {
var T, A, k;
if (this == null) {
throw new TypeError(' this is null or not defined');
}
// 1. Положим O равным результату вызова ToObject с передачей ему
// значения |this| в качестве аргумента.
var O = Object(this);
// 2. Положим lenValue равным результату вызова внутреннего метода Get
// объекта O с аргументом "length".
// 3. Положим len равным ToUint32(lenValue).
var len = O.length >>> 0;
// 4. Если вызов IsCallable(callback) равен false, выкидываем исключение TypeError.
// Смотрите (en): http://es5.github.com/#x9.11
// Смотрите (ru): http://es5.javascript.ru/x9.html#x9.11
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
// 5. Если thisArg присутствует, положим T равным thisArg; иначе положим T равным undefined.
if (arguments.length > 1) {
T = thisArg;
}
// 6. Положим A равным новому масиву, как если бы он был создан выражением new Array(len),
// где Array является стандартным встроенным конструктором с этим именем,
// а len является значением len.
A = new Array(len);
// 7. Положим k равным 0
k = 0;
// 8. Пока k < len, будем повторять
while (k < len) {
var kValue, mappedValue;
// a. Положим Pk равным ToString(k).
// Это неявное преобразование для левостороннего операнда в операторе in
// b. Положим kPresent равным результату вызова внутреннего метода HasProperty
// объекта O с аргументом Pk.
// Этот шаг может быть объединён с шагом c
// c. Если kPresent равен true, то
if (k in O) {
// i. Положим kValue равным результату вызова внутреннего метода Get
// объекта O с аргументом Pk.
kValue = O[k];
// ii. Положим mappedValue равным результату вызова внутреннего метода Call
// функции callback со значением T в качестве значения this и списком
// аргументов, содержащим kValue, k и O.
mappedValue = callback.call(T, kValue, k, O);
// iii. Вызовем внутренний метод DefineOwnProperty объекта A с аргументами
// Pk, Описатель Свойства
// { Value: mappedValue,
// Writable: true,
// Enumerable: true,
// Configurable: true }
// и false.
// В браузерах, поддерживающих Object.defineProperty, используем следующий код:
// Object.defineProperty(A, k, {
// value: mappedValue,
// writable: true,
// enumerable: true,
// configurable: true
// });
// Для лучшей поддержки браузерами, используем следующий код:
A[k] = mappedValue;
}
// d. Увеличим k на 1.
k++;
}
// 9. Вернём A.
return A;
};
}

View File

@ -0,0 +1,236 @@
(function (root) {
// Store setTimeout reference so promise-polyfill will be unaffected by
// other code modifying setTimeout (like sinon.useFakeTimers())
var setTimeoutFunc = setTimeout;
function noop() {
}
// Polyfill for Function.prototype.bind
function bind(fn, thisArg) {
return function () {
fn.apply(thisArg, arguments);
};
}
function Promise(fn) {
if (typeof this !== 'object') throw new TypeError('Promises must be constructed via new');
if (typeof fn !== 'function') throw new TypeError('not a function');
this._state = 0;
this._handled = false;
this._value = undefined;
this._deferreds = [];
doResolve(fn, this);
}
function handle(self, deferred) {
while (self._state === 3) {
self = self._value;
}
if (self._state === 0) {
self._deferreds.push(deferred);
return;
}
self._handled = true;
Promise._immediateFn(function () {
var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
if (cb === null) {
(self._state === 1 ? resolve : reject)(deferred.promise, self._value);
return;
}
var ret;
try {
ret = cb(self._value);
} catch (e) {
reject(deferred.promise, e);
return;
}
resolve(deferred.promise, ret);
});
}
function resolve(self, newValue) {
try {
// Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
if (newValue === self) throw new TypeError('A promise cannot be resolved with itself.');
if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
var then = newValue.then;
if (newValue instanceof Promise) {
self._state = 3;
self._value = newValue;
finale(self);
return;
} else if (typeof then === 'function') {
doResolve(bind(then, newValue), self);
return;
}
}
self._state = 1;
self._value = newValue;
finale(self);
} catch (e) {
reject(self, e);
}
}
function reject(self, newValue) {
self._state = 2;
self._value = newValue;
finale(self);
}
function finale(self) {
if (self._state === 2 && self._deferreds.length === 0) {
Promise._immediateFn(function () {
if (!self._handled) {
Promise._unhandledRejectionFn(self._value);
}
});
}
for (var i = 0, len = self._deferreds.length; i < len; i++) {
handle(self, self._deferreds[i]);
}
self._deferreds = null;
}
function Handler(onFulfilled, onRejected, promise) {
this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
this.onRejected = typeof onRejected === 'function' ? onRejected : null;
this.promise = promise;
}
/**
* Take a potentially misbehaving resolver function and make sure
* onFulfilled and onRejected are only called once.
*
* Makes no guarantees about asynchrony.
*/
function doResolve(fn, self) {
var done = false;
try {
fn(function (value) {
if (done) return;
done = true;
resolve(self, value);
}, function (reason) {
if (done) return;
done = true;
reject(self, reason);
});
} catch (ex) {
if (done) return;
done = true;
reject(self, ex);
}
}
Promise.prototype['catch'] = function (onRejected) {
return this.then(null, onRejected);
};
Promise.prototype.then = function (onFulfilled, onRejected) {
var prom = new (this.constructor)(noop);
handle(this, new Handler(onFulfilled, onRejected, prom));
return prom;
};
Promise.all = function (arr) {
var args = Array.prototype.slice.call(arr);
return new Promise(function (resolve, reject) {
if (args.length === 0) return resolve([]);
var remaining = args.length;
function res(i, val) {
try {
if (val && (typeof val === 'object' || typeof val === 'function')) {
var then = val.then;
if (typeof then === 'function') {
then.call(val, function (val) {
res(i, val);
}, reject);
return;
}
}
args[i] = val;
if (--remaining === 0) {
resolve(args);
}
} catch (ex) {
reject(ex);
}
}
for (var i = 0; i < args.length; i++) {
res(i, args[i]);
}
});
};
Promise.resolve = function (value) {
if (value && typeof value === 'object' && value.constructor === Promise) {
return value;
}
return new Promise(function (resolve) {
resolve(value);
});
};
Promise.reject = function (value) {
return new Promise(function (resolve, reject) {
reject(value);
});
};
Promise.race = function (values) {
return new Promise(function (resolve, reject) {
for (var i = 0, len = values.length; i < len; i++) {
values[i].then(resolve, reject);
}
});
};
// Use polyfill for setImmediate for performance gains
Promise._immediateFn = (typeof setImmediate === 'function' && function (fn) {
setImmediate(fn);
}) ||
function (fn) {
setTimeoutFunc(fn, 0);
};
Promise._unhandledRejectionFn = function _unhandledRejectionFn(err) {
if (typeof console !== 'undefined' && console) {
console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console
}
};
/**
* Set the immediate function to execute callbacks
* @param fn {function} Function to execute
* @deprecated
*/
Promise._setImmediateFn = function _setImmediateFn(fn) {
Promise._immediateFn = fn;
};
/**
* Change the function to execute on unhandled rejection
* @param {function} fn Function to execute on unhandled rejection
* @deprecated
*/
Promise._setUnhandledRejectionFn = function _setUnhandledRejectionFn(fn) {
Promise._unhandledRejectionFn = fn;
};
if (typeof module !== 'undefined' && module.exports) {
module.exports = Promise;
} else if (!root.Promise) {
root.Promise = Promise;
}
})(this);

1572
npm-shrinkwrap.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"name": "crypto-pro", "name": "crypto-pro",
"version": "1.0.11", "version": "1.0.13",
"description": "API для взаимодействия с КриптоПро", "description": "API для взаимодействия с КриптоПро",
"main": "src/index.js", "main": "src/index.js",
"scripts": { "scripts": {

View File

@ -167,7 +167,7 @@ function getDateObj(dateObj) {
* */ * */
function prepareCertsInfo(items) { function prepareCertsInfo(items) {
return items.map(function (c) { return items.map(function (c) {
c.name = c.subjectName.match(/CN=(.+?),/); c.name = c.subjectName.match(/CN=(.+?)(?:,|$)/);
// Удалось ли вытащить Common Name // Удалось ли вытащить Common Name
if (c.name && c.name[1]) { if (c.name && c.name[1]) {

131
vendor/cadesplugin_api.js vendored Executable file → Normal file
View File

@ -8,8 +8,8 @@
var plugin_reject; var plugin_reject;
var plugin_resolve; var plugin_resolve;
var isOpera = 0; var isOpera = 0;
var isYaBrowser = 0;
var isFireFox = 0; var isFireFox = 0;
var isEdge = 0;
var failed_extensions = 0; var failed_extensions = 0;
var canPromise = !!window.Promise; var canPromise = !!window.Promise;
@ -27,6 +27,22 @@
cadesplugin = {}; cadesplugin = {};
} }
function check_browser() {
var ua= navigator.userAgent, tem, M= ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
if(/trident/i.test(M[1])){
tem= /\brv[ :]+(\d+)/g.exec(ua) || [];
return {name:'IE',version:(tem[1] || '')};
}
if(M[1]=== 'Chrome'){
tem= ua.match(/\b(OPR|Edge)\/(\d+)/);
if(tem!= null) return {name:tem[1].replace('OPR', 'Opera'),version:tem[2]};
}
M= M[2]? [M[1], M[2]]: [navigator.appName, navigator.appVersion, '-?'];
if((tem= ua.match(/version\/(\d+)/i))!= null) M.splice(1, 1, tem[1]);
return {name:M[0],version:M[1]};
}
var browserSpecs = check_browser();
function cpcsp_console_log(level, msg){ function cpcsp_console_log(level, msg){
//IE9 не может писать в консоль если не открыта вкладка developer tools //IE9 не может писать в консоль если не открыта вкладка developer tools
if(typeof(console) == 'undefined') if(typeof(console) == 'undefined')
@ -187,9 +203,9 @@
} }
function isIE() { function isIE() {
var retVal = (("Microsoft Internet Explorer" == navigator.appName) || // IE < 11 // var retVal = (("Microsoft Internet Explorer" == navigator.appName) || // IE < 11
navigator.userAgent.match(/Trident\/./i)); // IE 11 // navigator.userAgent.match(/Trident\/./i)); // IE 11
return retVal; return (browserSpecs.name == 'IE' || browserSpecs.name == 'MSIE');
} }
function isIOS() { function isIOS() {
@ -201,25 +217,41 @@
function isNativeMessageSupported() function isNativeMessageSupported()
{ {
var retVal_chrome = navigator.userAgent.match(/chrome/i); // В IE работаем через NPAPI
isOpera = navigator.userAgent.match(/opr/i); if(isIE())
isYaBrowser = navigator.userAgent.match(/YaBrowser/i);
isFireFox = navigator.userAgent.match(/Firefox/i);
if(isFireFox && window.allow_firefox_cadesplugin_async)
return true;
if(retVal_chrome == null) // В IE работаем через NPAPI
return false; return false;
else // В Edge работаем через NativeMessage
{ if(browserSpecs.name == 'Edge') {
// В Chrome и Opera работаем через асинхронную версию isEdge = true;
if(retVal_chrome.length > 0 || isOpera != null ) return true;
{ }
// В Chrome, Firefox и Opera работаем через асинхронную версию в зависимости от версии
if(browserSpecs.name == 'Opera') {
isOpera = true;
if(browserSpecs.version >= 33){
return true; return true;
} }
else{
return false;
}
}
if(browserSpecs.name == 'Firefox') {
isFireFox = true;
if(browserSpecs.version >= 52){
return true;
}
else{
return false;
}
}
if(browserSpecs.name == 'Chrome') {
if(browserSpecs.version >= 42){
return true;
}
else{
return false;
}
} }
return false;
} }
// Функция активации объектов КриптоПро ЭЦП Browser plug-in // Функция активации объектов КриптоПро ЭЦП Browser plug-in
@ -251,7 +283,7 @@
return new ActiveXObject(name); return new ActiveXObject(name);
} }
} }
// В Firefox, Safari создаются объекты NPAPI // создаются объекты NPAPI
return pluginObject.CreateObject(name); return pluginObject.CreateObject(name);
} }
@ -285,6 +317,11 @@
} }
} }
// Функция для удаления созданных объектов
function ReleasePluginObjects() {
return cpcsp_chrome_nmcades.ReleasePluginObjects();
}
// Функция активации асинхронных объектов КриптоПро ЭЦП Browser plug-in // Функция активации асинхронных объектов КриптоПро ЭЦП Browser plug-in
function CreateObjectAsync(name) { function CreateObjectAsync(name) {
return pluginObject.CreateObjectAsync(name); return pluginObject.CreateObjectAsync(name);
@ -343,6 +380,35 @@
return tmpobj; return tmpobj;
} }
function show_firefox_missing_extension_dialog()
{
if (!window.cadesplugin_skip_extension_install)
{
var ovr = document.createElement('div');
ovr.id = "cadesplugin_ovr";
ovr.style = "visibility: hidden; position: fixed; left: 0px; top: 0px; width:100%; height:100%; background-color: rgba(0,0,0,0.7)";
ovr.innerHTML = "<div id='cadesplugin_ovr_item' style='position:relative; width:400px; margin:100px auto; background-color:#fff; border:2px solid #000; padding:10px; text-align:center; opacity: 1; z-index: 1500'>" +
"<button id='cadesplugin_close_install' style='float: right; font-size: 10px; background: transparent; border: 1; margin: -5px'>X</button>" +
"<p>Для работы КриптоПро ЭЦП Browser plugin на данном сайте необходимо расширение для браузера. Убедитесь, что оно у Вас включено или установите его." +
"<p><a href='https://www.cryptopro.ru/sites/default/files/products/cades/extensions/firefox_cryptopro_extension_latest.xpi'>Скачать расширение</a></p>" +
"</div>";
document.getElementsByTagName("Body")[0].appendChild(ovr);
document.getElementById("cadesplugin_close_install").addEventListener('click',function()
{
plugin_loaded_error("Плагин недоступен");
document.getElementById("cadesplugin_ovr").style.visibility = 'hidden';
});
ovr.addEventListener('click',function()
{
plugin_loaded_error("Плагин недоступен");
document.getElementById("cadesplugin_ovr").style.visibility = 'hidden';
});
ovr.style.visibility="visible";
}
}
//Выводим окно поверх других с предложением установить расширение для Opera. //Выводим окно поверх других с предложением установить расширение для Opera.
//Если установленна переменная cadesplugin_skip_extension_install - не предлагаем установить расширение //Если установленна переменная cadesplugin_skip_extension_install - не предлагаем установить расширение
function install_opera_extension() function install_opera_extension()
@ -391,7 +457,7 @@
} }
} }
function firefox_nmcades_onload() { function firefox_or_edge_nmcades_onload() {
cpcsp_chrome_nmcades.check_chrome_plugin(plugin_loaded, plugin_loaded_error); cpcsp_chrome_nmcades.check_chrome_plugin(plugin_loaded, plugin_loaded_error);
} }
@ -400,7 +466,7 @@
window.addEventListener("message", function (event){ window.addEventListener("message", function (event){
if (typeof(event.data) != "string" || !event.data.match("cadesplugin_loaded")) if (typeof(event.data) != "string" || !event.data.match("cadesplugin_loaded"))
return; return;
if(isFireFox) if(isFireFox || isEdge)
{ {
// Для Firefox вместе с сообщением cadesplugin_loaded прилетает url для загрузки nmcades_plugin_api.js // Для Firefox вместе с сообщением cadesplugin_loaded прилетает url для загрузки nmcades_plugin_api.js
var url = event.data.substring(event.data.indexOf("url:") + 4); var url = event.data.substring(event.data.indexOf("url:") + 4);
@ -408,9 +474,10 @@
fileref.setAttribute("type", "text/javascript"); fileref.setAttribute("type", "text/javascript");
fileref.setAttribute("src", url); fileref.setAttribute("src", url);
fileref.onerror = plugin_loaded_error; fileref.onerror = plugin_loaded_error;
fileref.onload = firefox_nmcades_onload; fileref.onload = firefox_or_edge_nmcades_onload;
document.getElementsByTagName("head")[0].appendChild(fileref); document.getElementsByTagName("head")[0].appendChild(fileref);
// Для Firefox и Edge у нас только по одному расширению.
failed_extensions++;
}else { }else {
cpcsp_chrome_nmcades.check_chrome_plugin(plugin_loaded, plugin_loaded_error); cpcsp_chrome_nmcades.check_chrome_plugin(plugin_loaded, plugin_loaded_error);
} }
@ -421,7 +488,7 @@
function load_extension() function load_extension()
{ {
if(isFireFox){ if(isFireFox || isEdge){
// вызываем callback руками т.к. нам нужно узнать ID расширения. Он уникальный для браузера. // вызываем callback руками т.к. нам нужно узнать ID расширения. Он уникальный для браузера.
nmcades_api_onload(); nmcades_api_onload();
return; return;
@ -509,6 +576,10 @@
{ {
if(plugin_resolved == 1) if(plugin_resolved == 1)
return; return;
if(isFireFox)
{
show_firefox_missing_extension_dialog();
}
plugin_resolved = 1; plugin_resolved = 1;
if(canPromise) if(canPromise)
{ {
@ -574,10 +645,15 @@
false); false);
}else }else
{ {
window.addEventListener("load", function (event) { if(document.readyState === "complete"){
load_npapi_plugin(); load_npapi_plugin();
check_npapi_plugin(); check_npapi_plugin();
}, false); } else {
window.addEventListener("load", function (event) {
load_npapi_plugin();
check_npapi_plugin();
}, false);
}
} }
} }
@ -596,6 +672,7 @@
if(isNativeMessageSupported()) if(isNativeMessageSupported())
{ {
cadesplugin.CreateObjectAsync = CreateObjectAsync; cadesplugin.CreateObjectAsync = CreateObjectAsync;
cadesplugin.ReleasePluginObjects = ReleasePluginObjects;
} }
if(!isNativeMessageSupported()) if(!isNativeMessageSupported())