change crypto library

This commit is contained in:
merelendor 2023-04-19 09:34:46 +03:00
parent b6d186ae0c
commit c8d6de0556
7 changed files with 280 additions and 14 deletions

View File

@ -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)

View File

@ -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 (
<div style={{ minHeight: 200, display: "flex", justifyContent: "center", alignItems: "center", }}>
<SpinnerCircular size={ 90 } thickness={ 51 } speed={ 100 } color="rgba(28, 1, 169, 1)" secondaryColor="rgba(236, 239, 244, 1)" />
</div>
);
}
else
{
if(certificates_error === null)
{
return (
<React.Fragment>
<div className="feed">
<p>Выберите подписанта</p>
<div className="feed_list">
{ certificates.map((certificate, index) => (
<div className="form_field checkbox" key={ index }>
<input type="radio"
hidden=""
id={ `certificate_${ certificate.id }` }
name={ `certificate_${ certificate.id }` }
checked={ certificate_selected !== undefined && certificate_selected.id === certificate.id ? true : false }
onChange={ () => { this.setState({ certificate_selected: certificate }) } }
/>
<label htmlFor={ `certificate_${ certificate.id }` }>
<div className="feed_item user">
<img src="/assets/images/icons/avatar.svg" alt="" />
<div>
<p className="item_title">{ certificate.fields['CN'].replace(/"/g, '') }</p>
<p className="item_desc">
{ certificate.fields['SN'] ? (<span>{ certificate.fields['SN'] } { certificate.fields['G'] }</span>) : null }
</p>
<p className="item_desc">
<span>ИНН { certificate.fields['INN'] }</span>
</p>
<p className="item_desc">
{ certificate.fields['OGRNIP'] && (<span>ОГРНИП { certificate.fields['OGRNIP'] }</span>) }
{ certificate.fields['OGRN'] && (<span>ОГРН { certificate.fields['ОГРН'] }</span>) }
</p>
<p className="item_desc">
<span>Подпись действительна до { certificate.valid_to_date }</span>
</p>
</div>
</div>
</label>
</div>
)) }
</div>
</div>
<div className="action" style={{marginBottom: "20px"}}>
<div></div>
<button
type="submit"
className="button button-blue"
disabled={ certificate_selected !== undefined ? false : true }
onClick={ this._sign }
style={{ minWidth: "250px" }}
>
{ signing ? (
<SpinnerCircular size={24} thickness={100} speed={100} color="rgba(255, 255, 255, 1)" secondaryColor="rgba(255, 255, 255, 0.5)" style={{ marginTop: "4px" }}/>
) : "Подписать выбранной подписью" }
</button>
</div>
</React.Fragment>
)
}
else
{
return (
<React.Fragment>
{ certificates_error === "NOT_INSTALLED" && (
<FormMessage type="error" title="Ошибка" message={ <>Плагин КриптоПРО не установлен, <Link href="https://cryptopro.ru/products/cades/plugin"><a target="_blank" rel="noopener noreferrer" style={{ color: "white", textDecoration: "underline" }}>посмотрите инструкцию</a></Link> как установить плагин КриптоПРО.</> }/>
) }
{ certificates_error === "CERTIFICATES" && (
<FormMessage type="error" title="Ошибка" message={ <>Плагин КриптоПРО не активирован, пожалуйста, обновите страницу и подтвердите разрешение для сайта на доступ к списку сертификатов.</> }/>
) }
{ certificates_error === "ISSUED" && (
<FormMessage type="error" title="Ошибка" message={ <>Отсутствуют действующие сертификаты.</> }/>
) }
{ certificates_error === "MISMATCH" && (
<FormMessage type="error" title="Ошибка" message={ <>Подписант не соответствует указанному подписанту в анкете.</> }/>
) }
</React.Fragment>
)
}
}
}
}

View File

@ -1107,7 +1107,7 @@ class Form_3_Signer extends QuestionnaireForm
{ errors.indexOf("signatory_person.identical") > -1 &&
(
<FormMessage type="error" title="Ошибка" message="Единоличный исполнительный орган и подписант договора лизинга совпадают. Укажите иного подписанта или откажитесь от указания иного подписанта."/>
<FormMessage type="error" title="Ошибка" message={ `Выбранный подписант совпадает с единоличным исполнительным органом. Выберите иного подписанта или снимите галку "Подписант отличается от единоличного исполнительного органа".` }/>
) }
<div className="form_field">

View File

@ -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
</p>
</div>
) : (
<DigitalSignaturesList form={ null } main={ main } company={ company } onSignDigital={ this._handle_onSignDigital }/>
<NoSSR>
<DigitalCertificates main={ main } company={ company } onSignDigital={ this._handle_onSignDigital }/>
</NoSSR>
) }
{/*<DigitalSignaturesList form={ null } main={ main } company={ company } onSignDigital={ this._handle_onSignDigital }/>*/}
</>
)}
</>

View File

@ -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": {

View File

@ -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);
}

View File

@ -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"