@it-enterprise/digital-signature 1.1.5 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/Models.js CHANGED
@@ -2,7 +2,7 @@ import { EndUserCertificate, EndUserError, EndUserOwnerInfo, EndUserConstants }
2
2
  import GlSign from "./GlSign";
3
3
  import { downloadData, byteArrayToBase64, base64ToByteArray, signAlgoToHashAlgo, getSupportedSignAlgos } from "./Utils";
4
4
 
5
- const LIBRARY_VERSION = "1.3.49";
5
+ const LIBRARY_VERSION = "1.3.53";
6
6
 
7
7
  /**
8
8
  * Параметры библиотеки электронной подписи
@@ -12,14 +12,14 @@ export class DigitalSignatureSettings {
12
12
  * @param {string} language - Язык. Поддержываемые значения: en, ru, uk
13
13
  * @param {string} userId - id пользователя (для сохранения ключей и предпочитаемого типа ключа)
14
14
  * @param {string} httpProxyServiceURL - Ссылка на ProxyHandler
15
- * @param {UriCertificatesProvider | WebCalcCertificatesProvider} certificatesProvider - Список центров сертификации, или ссылка на их скачивание
15
+ * @param {DefaultCertificatesProvider | WebCalcCertificatesProvider} certificatesProvider - Сервис для получения сертификатов
16
+ * @param {string} libraryUrl - ссылка на WebWorker
16
17
  */
17
- constructor(language, userId, httpProxyServiceURL, certificatesProvider, mssServiceURL, libraryUrl) {
18
- this.language = language || "ru";
18
+ constructor(language, userId, httpProxyServiceURL, certificatesProvider, libraryUrl) {
19
+ this.language = language || "en";
19
20
  this.userId = userId;
20
21
  this.httpProxyServiceURL = httpProxyServiceURL;
21
22
  this.certificatesProvider = certificatesProvider;
22
- this.mssServiceURL = mssServiceURL;
23
23
  this.libraryUrl = libraryUrl;
24
24
  }
25
25
  }
@@ -31,10 +31,7 @@ export class DefaultSettingProvider {
31
31
  /**
32
32
  * @param {string} language - Язык ошибок
33
33
  * @param {string | function} userId - id пользователя (для сохранения ключей и предпочитаемого типа ключа)
34
- * @param {string} glSign - ПГУ GlSign
35
- * @param {string} basePath - путь к ProxyHandler
36
- * @param {string} certificatesPath - путь к папке с сертификатами
37
- *
34
+ * @param {string} basePath - путь к api ЕЦП
38
35
  */
39
36
  constructor(language, userId, basePath) {
40
37
  if (typeof basePath !== "string") {
@@ -56,64 +53,63 @@ export class DefaultSettingProvider {
56
53
  }
57
54
 
58
55
  async getSettings() {
59
-
60
- if (!this._settings) {
61
- this._settings = new DigitalSignatureSettings(
62
- this.language,
63
- this.userId,
64
- this.basePath + "/ProxyHandler",
65
- new UriCertificatesProvider(
66
- this.basePath + "/files?name=CAs.json",
67
- this.basePath + "/files?name=CACertificates.p7b"
68
- ),
69
- this.basePath + "/KSPSign",
70
- URL.createObjectURL(await downloadData(this.basePath + `/files?name=euscp.worker-${LIBRARY_VERSION}.js`, "blob"))
71
- );
56
+ if (this._settings) {
57
+ return this._settings;
72
58
  }
73
59
 
60
+ this._settings = new DigitalSignatureSettings(
61
+ this.language,
62
+ this.userId,
63
+ this.basePath + "/ProxyHandler",
64
+ new DefaultCertificatesProvider(
65
+ this.basePath + "/files?name=CAs.json",
66
+ this.basePath + "/files?name=CACertificates.p7b"
67
+ ),
68
+ URL.createObjectURL(await downloadData(this.basePath + `/files?name=euscp.worker-${LIBRARY_VERSION}.js`, "blob"))
69
+ );
70
+
74
71
  return this._settings;
75
72
  }
76
73
  }
77
74
 
78
- /**
79
- * Фабрика настроек для библиотеки. Использовать в GraphQl приложениях
80
- */
81
- export class GraphQlSettingProvider {
75
+ export class LegacySettingsProvider {
82
76
  /**
83
77
  * @param {string} language - Язык ошибок
84
78
  * @param {string | function} userId - id пользователя (для сохранения ключей и предпочитаемого типа ключа)
85
- * @param {string} graphQlUri - Ссылка на GraphQl сервер
86
- * @param {string} wsUri - Ссылка на веб-сервисы
87
- * @param {Object} auth - Функция для получения токена авторизации
79
+ * @param {string} basePath - путь к api ЕЦП
80
+ * @param {string} glsign - ПГУ GlSign
88
81
  */
89
- constructor(language, userId, graphQlUri, wsUri, auth) {
90
- if (typeof graphQlUri !== "string") {
82
+ constructor(language, userId, basePath, glsign) {
83
+ if (typeof basePath !== "string") {
91
84
  throw {
92
85
  code: EndUserError.EU_ERROR_BAD_PARAMETER,
93
- message: "graphQlUri is not string"
86
+ message: "basePath is not a string"
94
87
  };
95
- }
96
- if (graphQlUri.endsWith("/")) {
97
- graphQlUri = graphQlUri.substring(0, graphQlUri.length - 1);
88
+ } else if (basePath.endsWith("/")) {
89
+ basePath = basePath.substring(0, basePath.length - 1);
98
90
  }
99
91
 
100
92
  this.language = language;
101
93
  this.userId = userId;
102
- this.graphQlUri = graphQlUri;
103
- this.wsUri = wsUri;
104
- this.auth = auth;
94
+ this.basePath = basePath;
95
+ this.glsign = glsign;
105
96
  }
106
97
 
107
- async getGlSign() {
108
- return new GlSign(await downloadData(this.graphQlUri + "/api/digitalSignature/GlSign", "string", await this.auth.getToken()));
98
+ getGlSign() {
99
+ return typeof this.glsign === "string" ? new GlSign(this.glsign) : this.glsign;
109
100
  }
110
101
 
111
102
  getSettings(testMode) {
112
- return new DigitalSignatureSettings(
113
- this.language,
103
+ return new DigitalSignatureSettings(this.language,
114
104
  this.userId,
115
- this.graphQlUri + "/api/digitalSignature/ProxyHandler",
116
- new GraphQlCertificatesProvider(testMode, this.graphQlUri, this.wsUri)
105
+ this.basePath + "/ProxyHandler",
106
+ new LegacyCertificatesProvider(
107
+ testMode,
108
+ this.basePath + "/Data/version.txt",
109
+ this.basePath + testMode ? "/Data/CAs.test.json" : "/Data/CAs.json",
110
+ this.basePath + testMode ? "/Data/CACertificates.p7b" : "/Data/CACertificates.p7b"
111
+ ),
112
+ this.basePath + `/Scripts/euscp.worker.ex-${LIBRARY_VERSION}.js`
117
113
  );
118
114
  }
119
115
  }
@@ -157,7 +153,7 @@ export class CertificatesProvider {
157
153
  /**
158
154
  * Класс для загрузки сертификатов по ссылкам
159
155
  */
160
- export class UriCertificatesProvider extends CertificatesProvider {
156
+ export class DefaultCertificatesProvider extends CertificatesProvider {
161
157
  /**
162
158
  * @param {boolean} testMode - Тестовый режим
163
159
  * @param {string} versionUri - Ссылка на файл с текущей версией сертификатов
@@ -185,83 +181,64 @@ export class UriCertificatesProvider extends CertificatesProvider {
185
181
  }
186
182
  }
187
183
 
188
- /**
189
- * Класс для загрузки сертификатов через GraphQl
190
- */
191
- export class GraphQlCertificatesProvider extends CertificatesProvider {
184
+ export class LegacyCertificatesProvider extends CertificatesProvider {
192
185
  /**
193
- * @param {boolean} testMode - тестовый режим
194
- * @param {string} graphQlUri - ссылка на GraphQl
195
- * @param {string} wsUri - ссылка на веб-сервисы
186
+ * @param {boolean} testMode - Тестовый режим
187
+ * @param {string} versionUri - Ссылка на файл с текущей версией сертификатов
188
+ * @param {string} CAsUri - Ссылка на файл со списком ЦСК
189
+ * @param {string} CACertificatesUri - Ссылка на файл с корневыми сертификатами ЦСК
196
190
  */
197
- constructor(testMode, graphQlUri, wsUri) {
191
+ constructor(testMode, versionUri, CAsUri, CACertificatesUri) {
198
192
  super(testMode);
199
-
200
- if (typeof wsUri !== "string") {
201
- throw {
202
- code: EndUserError.EU_ERROR_BAD_PARAMETER,
203
- message: "wsUri is not string"
204
- };
205
- }
206
- if (wsUri.endsWith("/")) {
207
- wsUri = wsUri.substring(0, wsUri.length - 1);
208
- }
209
- this.wsUri = wsUri;
210
- this.graphQlUri = graphQlUri;
193
+ this.versionUri = versionUri;
194
+ this.CAsUri = CAsUri;
195
+ this.CACertificatesUri = CACertificatesUri;
211
196
  }
212
197
 
213
198
  async loadCertificates() {
214
- let CAs = this._getItem("CAs"),
215
- CACertificates = this._getItem("CACertificates");
216
- const CACertificatesVersion = this._getItem("CACertificatesVersion"),
217
- CAsVersion = this._getItem("CAsVersion");
218
-
219
- const version = { VERSIONCAS: CAsVersion, VERSIONCERT: CACertificatesVersion, INCLUDETEST: this.testMode };
220
-
221
- if (CAs) {
222
- try {
223
- CAs = JSON.parse(CAs);
224
- } catch (error) {
225
- console.error(error);
226
- CAs = null;
227
- version.VERSIONCAS = null;
228
- }
229
- }
199
+ let CAs = this._getItem("CA"),
200
+ CACertificates = this._getItem("Certificates"),
201
+ CACertificatesVersion = this._getItem("CAVersion");
230
202
 
231
- if (CACertificates) {
232
- try {
233
- CACertificates = base64ToByteArray(CACertificates);
234
- } catch (error) {
235
- console.error(error);
203
+ try {
204
+ const currentVersion = await downloadData(this.versionUri);
205
+ if (currentVersion != CACertificatesVersion) {
206
+ CACertificatesVersion = currentVersion;
207
+ CAs = null;
236
208
  CACertificates = null;
237
- version.VERSIONCERT = null;
238
209
  }
239
- }
240
210
 
241
- try {
242
- const res = await downloadData(this.graphQlUri + "/api/digitalSignature/CAsAndCertificates?version=" + JSON.stringify(version), "json");
243
- if (!res) {
244
- return { CAs, CACertificates };
211
+ if (CAs) {
212
+ try {
213
+ CAs = JSON.parse(CAs);
214
+ } catch (error) {
215
+ console.error(error);
216
+ CAs = null;
217
+ }
245
218
  }
246
-
247
- if (res.FILECAS) {
248
- CAs = await downloadData(this.wsUri + "/GetFile.ashx?file=" + res.FILECAS, "json");
249
- this._setItem("CAs", JSON.stringify(CAs));
250
- this._setItem("CAsVersion", res.VERSIONCAS);
219
+ if (!CAs) {
220
+ CAs = await downloadData(this.CAsUri, "json");
221
+ this._setItem("CA", JSON.stringify(CAs));
251
222
  }
252
223
 
253
- if (res.FILECERT) {
254
- CACertificates = await downloadData(this.wsUri + "/GetFile.ashx?file=" + res.FILECERT, "binary");
255
- this._setItem("CACertificates", byteArrayToBase64(CACertificates));
256
- this._setItem("CACertificatesVersion", res.VERSIONCERT);
224
+ if (CACertificates) {
225
+ try {
226
+ CACertificates = base64ToByteArray(CACertificates);
227
+ } catch (error) {
228
+ console.error(error);
229
+ CACertificates = null;
230
+ }
257
231
  }
258
-
232
+ if (!CACertificates) {
233
+ CACertificates = await downloadData(this.CACertificatesUri, "binary");
234
+ this._setItem("Certificates", byteArrayToBase64(CACertificates));
235
+ }
236
+ this._setItem("CAVersion", CACertificatesVersion);
259
237
  return { CAs, CACertificates };
260
238
  } catch (error) {
261
- this._removeItem("CAs");
262
- this._removeItem("CAsVersion");
263
- this._removeItem("CACertificates");
264
- this._removeItem("CACertificatesVersion");
239
+ this._removeItem("CA");
240
+ this._removeItem("CAVersion");
241
+ this._removeItem("Certificates");
265
242
  console.error(error);
266
243
  throw {
267
244
  code: EndUserError.EU_ERROR_DOWNLOAD_FILE,
@@ -280,7 +257,7 @@ export const DigitalSignatureLibraryTypeSW = 1;
280
257
  * Типы библиотеки
281
258
  */
282
259
  export const DigitalSignatureLibraryType = {
283
- /** Подпись файловыми ключами */
260
+ /** Подпись файловыми ключами и через облачные сервисы */
284
261
  JS: DigitalSignatureLibraryTypeJS,
285
262
  /** Подпись аппартными ключами */
286
263
  SW: DigitalSignatureLibraryTypeSW
@@ -299,7 +276,7 @@ export const DigitalSignatureKeyTypeKSP = 2;
299
276
  export const DigitalSignatureKeyType = {
300
277
  File: DigitalSignatureKeyTypeFile,
301
278
  Token: DigitalSignatureKeyTypeToken,
302
- KSP: DigitalSignatureKeyTypeKSP
279
+ KSP: DigitalSignatureKeyTypeKSP,
303
280
  };
304
281
 
305
282
  export class PrivateKeyInfo {
@@ -370,13 +347,13 @@ export class PrivateKeyInfo {
370
347
  */
371
348
  getSignAlgo() {
372
349
  const certificates = this.certificates;
373
- if(this instanceof KspPrivateKeyInfo) {
350
+ if (this.keyType === DigitalSignatureKeyTypeKSP) {
374
351
  return EndUserConstants.EndUserSignAlgo.DSTU4145WithGOST34311;
375
352
  }
376
- else if(certificates.length > 0) {
353
+ else if (certificates.length > 0) {
377
354
  return getSupportedSignAlgos(certificates)[0];
378
355
  }
379
- else{
356
+ else {
380
357
  return EndUserConstants.EndUserSignAlgo.Unknown;
381
358
  }
382
359
  }
@@ -8,7 +8,17 @@
8
8
  "WebExtensionInstall": "Інсталяційний пакет бібліотеки підпису (web-розширення)",
9
9
  "LibraryInstall": "Інсталяційний пакет web-бібліотеки підпису",
10
10
  "LibraryUpdate": "Оновлення web-бібліотеки підпису",
11
- "PrivateKeyNotReaded": "Особистий ключ не считано."
11
+ "PrivateKeyNotReaded": "Особистий ключ не считано.",
12
+ "DiiaError": "Дія.Підпис – сервіс для накладання кваліфікованого електронного підпису за допомогою смартфону і додатку «Дія».<br/>Для можливості використання «Дія.Підпис» у даній інсталяції системи вам необхідно звернутися до свого постачальника.<br/>У зверненні вкажіть наступну інформацію:<br/><ul><li>Посилання: ",
13
+ "XadesError": "Перевірка кваліфікованого електронного підпису, який сформовано у вигляді окремого файлу з розширенням .xml виконується за умов наявності файлу з даними, на які накладено кваліфікований електронний підпис. Ім`я такого файлу зазвичай ідентичне з іменем файлу файлу з розширенням .xml. Оберіть цей файл разом з файлом кваліфікованого електронного підпису.",
14
+ "KSPSignFormatError": "Хмарні сервіси підтримують тільки підписи типу CAdES",
15
+ "BadSignatureType": "Невірний тип підпису",
16
+ "DownloadingRootCertificatesError": "Помилка при завантаженні сертифікатів ЦСК або списку ЦСК. Перевірте наявність налаштувань ЦСК в функції \"Інструменти і налаштування → Електронний підпис → Налаштування ЦСК\" та виконання задачі планувальника UPDATECASCERTIFICATES.",
17
+ "BadParameter": "Невірний параметр",
18
+ "PasswordNotSet": "Не вказано пароль до особистого ключа",
19
+ "ReadPrivateKeyCAAutoDetectError": "Надавач не підтримує автоматичний пошук сертифіката за ос. ключем. Необхідно обрати надавача самостійно",
20
+ "ReadPrivateKeyInvalidCAError": "Ваш сертифікат виданий іншим надавачем та не обслуговується в {0}. Необхідно обрати надавача Вашого сертифіката",
21
+ "ReadPrivateKeyNeedCertificateError": "Надавач {0} не підтримує автоматичний пошук сертифіката за ос. ключем. Необхідно обрати сертифікат(и) ос. ключа"
12
22
  },
13
23
  "ru": {
14
24
  "LibraryNotSupported": "Библиотека web-подписи не поддерживается в вашем браузере или ОС.",
@@ -19,7 +29,17 @@
19
29
  "WebExtensionInstall": "Установочный пакет библиотеки подписи (web-розширення)",
20
30
  "LibraryInstall": "Установочный пакет web-библиотеки подписи",
21
31
  "LibraryUpdate": "Обновление web-библиотеки подписи",
22
- "PrivateKeyNotReaded": "Приватный ключ не считан."
32
+ "PrivateKeyNotReaded": "Приватный ключ не считан.",
33
+ "DiiaError": "Дія.Підпис – сервис для наложения квалифицированной электронной подписи с помощью смартфона и приложения «Дія».<br/>Для возможности использования «Дія.Підпис» в данной инсталляции системы вам необходимо обратиться к своему поставщику.<br/>В обращении укажите следующую информацию:<br/><ul><li>Ссылка: ",
34
+ "XadesError": "Проверка квалифицированной электронной подписи, которая сформирована в виде отдельного файла с расширением .xml, выполняется при наличии файла с данными, на которые наложена квалифицированная электронная подпись. Имя такого файла обычно идентично с именем файла с расширением .xml. Выберите этот файл вместе с квалифицированной электронной подписью.",
35
+ "KSPSignFormatError": "Облачные сервисы поддерживают только подписи типа CAdES",
36
+ "BadSignatureType": "Неверный тип подписи",
37
+ "DownloadingRootCertificatesError": "Ошибка при загрузке корневых сертификатов ЦСК, либо списка ЦСК. Проверьте наличие настроек ЦСК в функции \"Инструменты и настройки → Электронная подпись → Настройки ЦСК\" и выполнение задачи планировщика UPDATECASCERTIFICATES.",
38
+ "BadParameter": "Неверный параметр",
39
+ "PasswordNotSet": "Не указан пароль к приватному ключу",
40
+ "ReadPrivateKeyCAAutoDetectError": "Центр сертификации не поддерживает автоматический поиск сертификата по приватному ключу. Необходимо выбрать центр сертификации самостоятельно,",
41
+ "ReadPrivateKeyInvalidCAError": "Ваш сертификат выдан в другом центре сертификации и не обслуживается в {0}. Необходимо выбрать центр сертификации Вашего сертификата,",
42
+ "ReadPrivateKeyNeedCertificateError": "Центр сертификации {0} не поддерживает автоматический поиск сертификата по приватному ключу. Нобходимо указать сертификат(ы) приватного ключа,"
23
43
  },
24
44
  "en": {
25
45
  "LibraryNotSupported": "Web-signature library is not supported in your browser or OS.",
@@ -30,6 +50,16 @@
30
50
  "WebExtensionInstall": "Signature library installation package (web-extension)",
31
51
  "LibraryInstall": "Web-signature library installation package",
32
52
  "LibraryUpdate": "Web-signature library update package",
33
- "PrivateKeyNotReaded": "Private key not readed."
53
+ "PrivateKeyNotReaded": "Private key not readed.",
54
+ "DiiaError": "Дія.Підпис - a service for applying a qualified digital signature using a smartphone and the application \"Дія\". <br/> To be able to use \"Дія.Підпис\" in this system, you need to contact your provider. <br/> Please include the following information in your request: <br/> <ul> <li> Link: ",
55
+ "XadesError": "The verification of a qualified digital signature, which is formed as a separate file with the extension .xml, is performed under the conditions of the file with the data on which the qualified digital signature is affixed. The name of such a file is usually identical to the filename of the .xml file. Select this file along with the qualified digital signature file.",
56
+ "KSPSignFormatError": "Cloud services only supports CAdES signatures",
57
+ "BadSignatureType": "Invalid signature type",
58
+ "DownloadingRootCertificatesError": "Error occured while downloading root CA certificates or CA list. Check for CA setting in function \"Tools and settings → Electronic signature → CA settings\" and execution of task scheduler UPDATECASCERTIFICATES.",
59
+ "BadParameter": "Invalid parameter",
60
+ "PasswordNotSet": "Private key password not specified.",
61
+ "ReadPrivateKeyCAAutoDetectError": "Certification authority does not support automatic search for a certificate by private key. You need to choose a certification authority yourself.",
62
+ "ReadPrivateKeyInvalidCAError": "Your certificate was issued by a different CA and is not being serviced in {0}. You need to select a certification authority for your certificate.",
63
+ "ReadPrivateKeyNeedCertificateError": "Certification authority {0} does not support automatic search for a certificate by private key. You must specify the certificates of the private key."
34
64
  }
35
65
  }
package/src/Utils.js CHANGED
@@ -1,4 +1,4 @@
1
- import { EndUserCertificate, EndUserConstants } from "../euscp/euscp";
1
+ import { EndUserCertificate, EndUserConstants, EndUserError } from "../euscp/euscp";
2
2
 
3
3
  /**
4
4
  * Загрузить данные по ссылке
@@ -84,6 +84,13 @@ export function makeUrl(url) {
84
84
  return url;
85
85
  }
86
86
 
87
+ export function format(format) {
88
+ const args = Array.prototype.slice.call(arguments, 1);
89
+ return format.replace(/{(\d+)}/g, function (match, number) {
90
+ return typeof args[number] != "undefined" ? args[number] : match;
91
+ });
92
+ }
93
+
87
94
  export function readFile(file) {
88
95
  return new Promise((resolve, reject) => {
89
96
  const reader = new FileReader();
@@ -176,3 +183,52 @@ export function getSupportedSignAlgos(certificates) {
176
183
  });
177
184
  return signAlgos;
178
185
  }
186
+
187
+ export function isUrlValid(url) {
188
+ try {
189
+ return !!new URL(url);
190
+ } catch {
191
+ return false;
192
+ }
193
+ }
194
+
195
+ export function getFileNameFromUrl(url) {
196
+ return new URL(url).pathname.split("/").pop();
197
+ }
198
+
199
+ export async function downloadAndSignFiles(fileUrl, signFunc) {
200
+ const isParamValid = (url) => typeof url === "string" && isUrlValid(url) || typeof url === "object" && typeof url.name === "string" && typeof url.val === "string" && isUrlValid(url.val);
201
+
202
+ if (Array.isArray(fileUrl)) {
203
+ if (!fileUrl.every(isParamValid) || !(fileUrl.every(url => typeof url === "string") || fileUrl.every(url => typeof url === "object"))) {
204
+ throw {
205
+ code: EndUserError.EU_ERROR_BAD_PARAMETER,
206
+ message: "Bad parameter fileUrl"
207
+ };
208
+ }
209
+ const returnNamedData = fileUrl.every(url => typeof url === "object");
210
+
211
+ fileUrl = await Promise.all(fileUrl.map(async (url) => typeof url === "object"
212
+ ? { name: url.name, val: await downloadData(url.val, "binary") }
213
+ : { name: getFileNameFromUrl(url), val: await downloadData(url, "binary") }));
214
+
215
+ const signs = await signFunc(fileUrl);
216
+ return returnNamedData ? signs : signs.map(sign => sign.val);
217
+ } else {
218
+ if (!isParamValid(fileUrl)) {
219
+ throw {
220
+ code: EndUserError.EU_ERROR_BAD_PARAMETER,
221
+ message: "Bad parameter fileUrl"
222
+ };
223
+ }
224
+
225
+ const returnNamedData = typeof fileUrl === "object";
226
+
227
+ fileUrl = typeof fileUrl === "object"
228
+ ? { name: fileUrl.name, val: await downloadData(fileUrl.val, "binary") }
229
+ : { name: getFileNameFromUrl(fileUrl), val: await downloadData(fileUrl, "binary") };
230
+
231
+ const sign = await signFunc(fileUrl);
232
+ return returnNamedData ? sign : sign.val;
233
+ }
234
+ }