From c8d6de055668c3b068dc5a7f8839ba216d7f295e Mon Sep 17 00:00:00 2001 From: merelendor Date: Wed, 19 Apr 2023 09:34:46 +0300 Subject: [PATCH] change crypto library --- actions/questionnaireActions.js | 20 +- .../forms/DigitalCertificates.js | 222 ++++++++++++++++++ .../forms/Form_3_Signer/index.js | 2 +- .../forms/Form_8_Signing/index.js | 8 +- package.json | 1 + pages/api/questionnaire/download.js | 17 +- yarn.lock | 24 ++ 7 files changed, 280 insertions(+), 14 deletions(-) create mode 100644 components/questionnaire/forms/DigitalCertificates.js diff --git a/actions/questionnaireActions.js b/actions/questionnaireActions.js index a533973..5745107 100644 --- a/actions/questionnaireActions.js +++ b/actions/questionnaireActions.js @@ -384,7 +384,7 @@ export const removeAttachmentFile = (id) => }); } -export const downloadQuestionnaire = ({ filename, download = true }) => +export const downloadQuestionnaire = ({ filename, download = true, base64 = false }) => { console.log("ACTION", "questionnaireActions", "downloadQuestionnaire()", ); @@ -398,23 +398,29 @@ export const downloadQuestionnaire = ({ filename, download = true }) => console.log("questionnaire", questionnaire); const { main, contacts, signatory_person, founder_persons, head_person, non_profit, } = questionnaire; - const playload = { main, contacts, signatory_person, founder_persons, head_person, non_profit, }; - console.log({ playload }); + const payload = { main, contacts, signatory_person, founder_persons, head_person, non_profit, }; + console.log({ payload }); -/* axios.post(`${ process.env.NEXT_PUBLIC_INT_API_HOST }/questionnaire/download`, { questionnaire: playload }, { +/* axios.post(`${ process.env.NEXT_PUBLIC_INT_API_HOST }/questionnaire/download`, { questionnaire: payload }, { headers: { "Authorization": `Bearer ${ cookies_list.jwt }`, }, }) */ - axios.post(`${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/questionnaire/download`, { questionnaire: playload, filename }, { + const options = { headers: { 'Content-Type': 'application/json', 'Accept': 'application/pdf' }, - responseType: 'arraybuffer', - }) + }; + + if(!base64) + { + options.responseType = "arraybuffer"; + } + + axios.post(`${ process.env.NEXT_PUBLIC_SELF_API_HOST }/api/questionnaire/download`, { questionnaire: payload, filename, base64: download ? false : true }, options) .then((response) => { if(download) diff --git a/components/questionnaire/forms/DigitalCertificates.js b/components/questionnaire/forms/DigitalCertificates.js new file mode 100644 index 0000000..3bb089f --- /dev/null +++ b/components/questionnaire/forms/DigitalCertificates.js @@ -0,0 +1,222 @@ +import React from "react"; +import Link from "next/link"; +import { SpinnerCircular } from "spinners-react"; +import moment from "moment"; +import dynamic from 'next/dynamic'; +import { concatSeries } from 'async'; +import fileDownload from 'js-file-download'; + +import FormMessage from "./FormMessage"; +import { downloadQuestionnaire, uploadSignedFile } from "../../../actions"; +//import { generateSignature } from "../../../utils/digital_signature"; + + +export default class DigitalCertificates extends React.Component +{ + constructor(props) + { + super(props); + + this.state = { + loading: true, + certificates: [], + certificates_error: null, + certificate_selected: undefined, + signing: false, + }; + this.cryptopro = null; + } + + async componentDidMount() + { + console.log("DC", "CDM"); + const { CryptoPro } = await import('ruscryptojs'); + + this.cryptopro = new CryptoPro(); + this.cryptopro.init() + .then((info) => + { + console.log('Initialized', info); + this.cryptopro.listCertificates() + .then((certificates_list) => + { + console.log({ certificates_list }); + + concatSeries(certificates_list, (certificate, callback) => + { + console.log(certificate.id, certificate.name); + this.cryptopro.certificateInfo(certificate.id) + .then((cert) => + { + if(cert.IsValid) + { + callback(null, [ { id: certificate.id, fields: cert.Subject, valid_to_date: moment(cert.ValidToDate).format("DD.MM.YYYY") } ]); + } + else + { + callback(null, []); + } + }); + }, (error, certificates) => + { + if(certificates.length === 0) + { + this.setState({ loading: false, certificates_error: "ISSUED" }); + } + else + { + this.setState({ loading: false, certificates }); + } + }); + }) + .catch((error_certificates_list) => + { + console.error({ error_certificates_list }); + this.setState({ loading: false, certificates_error: "CERTIFICATES" }); + }); + }) + .catch((error_init) => + { + console.error({ error_init }); + this.setState({ loading: false, certificates_error: "NOT_INSTALLED" }); + }); + } + + _sign = () => + { + this.setState({ signing: true }, () => + { + const { company, main, onSignDigital } = this.props; + const filename = `${ main.inn }_questionnaire_${ moment().format("DDMMYYYY_HHmmss") }.pdf`; + + downloadQuestionnaire({ filename, download: false, base64: true }) + .then(({ file }) => + { + let file_to_sign = file; + + const now = moment().format("DDMMYYYY_HHmmss"); + this.cryptopro.signData(file_to_sign, this.state.certificate_selected.id) + .then(signature => + { + uploadSignedFile(signature, company.questionnaire_id, true) + .then(() => + { + onSignDigital(); + }) + .catch(() => + { + this.setState({ signing: false }); + }); + }) + .catch((error_sign) => + { + console.error({ error_sign }); + this.setState({ signing: false }); + }) + }) + .catch((e) => + { + console.error("exception on sign"); + console.error(e); + }); + }); + } + + render() + { + const { loading, certificates, certificates_error, certificate_selected, signing } = this.state; + console.log("render()", { certificates }); + + if(loading) + { + return ( +
+ +
+ ); + } + else + { + if(certificates_error === null) + { + return ( + +
+

Выберите подписанта

+
+ + { certificates.map((certificate, index) => ( +
+ { this.setState({ certificate_selected: certificate }) } } + /> + +
+ )) } + +
+
+
+
+ +
+
+ ) + } + else + { + return ( + + { certificates_error === "NOT_INSTALLED" && ( + Плагин КриптоПРО не установлен, посмотрите инструкцию как установить плагин КриптоПРО. }/> + ) } + { certificates_error === "CERTIFICATES" && ( + Плагин КриптоПРО не активирован, пожалуйста, обновите страницу и подтвердите разрешение для сайта на доступ к списку сертификатов. }/> + ) } + { certificates_error === "ISSUED" && ( + Отсутствуют действующие сертификаты. }/> + ) } + { certificates_error === "MISMATCH" && ( + Подписант не соответствует указанному подписанту в анкете. }/> + ) } + + + ) + } + } + } +} \ No newline at end of file diff --git a/components/questionnaire/forms/Form_3_Signer/index.js b/components/questionnaire/forms/Form_3_Signer/index.js index 3e44250..6c959dd 100644 --- a/components/questionnaire/forms/Form_3_Signer/index.js +++ b/components/questionnaire/forms/Form_3_Signer/index.js @@ -1107,7 +1107,7 @@ class Form_3_Signer extends QuestionnaireForm { errors.indexOf("signatory_person.identical") > -1 && ( - + ) }
diff --git a/components/questionnaire/forms/Form_8_Signing/index.js b/components/questionnaire/forms/Form_8_Signing/index.js index 1c78e82..b7d0790 100644 --- a/components/questionnaire/forms/Form_8_Signing/index.js +++ b/components/questionnaire/forms/Form_8_Signing/index.js @@ -9,12 +9,14 @@ import { SpinnerCircular } from "spinners-react"; import { connect } from "react-redux"; import { withRouter } from 'next/router'; import moment from "moment"; +import NoSSR from "@mpth/react-no-ssr"; import QuestionnaireForm from "../QuestionnaireForm"; import { MatchMedia } from '../../../../utils/mediaqueries'; import { reduxWrapper } from '../../../../store'; import DigitalSignaturesList from "../DigitalSignaturesList"; import { downloadQuestionnaire } from "../../../../actions"; +import DigitalCertificates from "../DigitalCertificates"; import FormMessage from "../FormMessage"; class Form_8_Signing extends QuestionnaireForm @@ -159,8 +161,12 @@ class Form_8_Signing extends QuestionnaireForm

) : ( - + + + + ) } + {/**/} )} diff --git a/package.json b/package.json index 735928d..6f7a014 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "react-widgets": "^5.5.1", "redux": "^4.1.2", "redux-persist": "^6.0.0", + "ruscryptojs": "^2.6.1", "spinners-react": "^1.0.6" }, "devDependencies": { diff --git a/pages/api/questionnaire/download.js b/pages/api/questionnaire/download.js index b4fb9a6..e9389c8 100644 --- a/pages/api/questionnaire/download.js +++ b/pages/api/questionnaire/download.js @@ -120,7 +120,7 @@ export default async function handler(req, res) console.log("API", "questionnaire", "get"); console.log(req.body); console.log("-".repeat(50)); - const { questionnaire, filename } = req.body; + const { questionnaire, filename, base64 } = req.body; await cors(req, res); @@ -326,10 +326,17 @@ export default async function handler(req, res) //res.setHeader('Content-Type', 'application/pdf'); //res.send(pdfBytes); console.log("pdfBytes.size", pdfBytes, pdfBytes.byteLength); - res.setHeader("filename", filename); - res.setHeader('Content-Type', 'application/pdf'); - res.send(Buffer.from(pdfBytes)); - + if(base64) + { + //, 'binary' + res.status(200).send(Buffer.from(pdfBytes).toString('base64')); + } + else + { + res.setHeader("filename", filename); + res.setHeader('Content-Type', 'application/pdf'); + res.status(200).send(Buffer.from(pdfBytes)); + } //res.setHeader('Content-Type', 'application/pdf'); //res.status(200).send(pdfBytes); } diff --git a/yarn.lock b/yarn.lock index ea1e2b7..fdbee09 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2071,6 +2071,11 @@ console-browserify@^1.1.0: resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== +console-polyfill@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/console-polyfill/-/console-polyfill-0.3.0.tgz#84900902a18c47a5eba932be75fa44d23e8af861" + integrity sha512-w+JSDZS7XML43Xnwo2x5O5vxB0ID7T5BdqDtyqT6uiCAX2kZAgcWxNaGqT97tZfSHzfOcvrfsDAodKcJ3UvnXQ== + constants-browserify@1.0.0, constants-browserify@^1.0.0, constants-browserify@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" @@ -4054,6 +4059,11 @@ js-file-download@^0.4.12: resolved "https://registry.yarnpkg.com/js-file-download/-/js-file-download-0.4.12.tgz#10c70ef362559a5b23cdbdc3bd6f399c3d91d821" integrity sha512-rML+NkoD08p5Dllpjo0ffy4jRHeY6Zsapvr/W86N7E0yuzAO6qa5X9+xog6zQNlH102J7IXljNY2FtS6Lj3ucg== +js-sha1@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/js-sha1/-/js-sha1-0.6.0.tgz#adbee10f0e8e18aa07cdea807cf08e9183dbc7f9" + integrity sha512-01gwBFreYydzmU9BmZxpVk6svJJHrVxEN3IOiGl6VO93bVKYETJ0sIth6DASI6mIFdt7NmfX9UiByRzsYHGU9w== + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -5954,6 +5964,20 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +ruscryptojs@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/ruscryptojs/-/ruscryptojs-2.6.1.tgz#f9af6a95d63d8f575f1c65ea510ec586c2ab753b" + integrity sha512-CV41M1w02O5Yb9KLUBtDfIgPvgp+OjFxe7nT6uJ8lYyJInNIZeYBsUaegRVto01pNCG353DBlF9DWckJZ6/4Iw== + dependencies: + console-polyfill "^0.3.0" + js-sha1 "^0.6.0" + rutoken "^1.0.8" + +rutoken@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/rutoken/-/rutoken-1.0.8.tgz#443e16022fa8e1d7c638ba852f91d7fcb3a68be7" + integrity sha512-85C4CJk650iZauCmOes2TeQmVjkWviI1ys3E7nDw8pWlMI2mBuLz1fCD30ZjAfnNQ6OL19OMTYDNPFrJ60NfEA== + safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"