287 lines
9.1 KiB
JavaScript
287 lines
9.1 KiB
JavaScript
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()
|
||
{
|
||
const { company, main, head_person } = this.props;
|
||
//console.log({ company, main });
|
||
//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) =>
|
||
{
|
||
//console.log({ cert });
|
||
if(cert.IsValid)
|
||
{
|
||
if(cert.Subject['OGRNIP'] !== undefined && cert.Subject['OGRNIP'] !== null && cert.Subject['OGRNIP'] !== "")
|
||
{
|
||
if(cert.Subject['INN'] !== undefined && cert.Subject['INN'] !== null && cert.Subject['INN'] !== "")
|
||
{
|
||
if(company.inn === cert.Subject['INN'])
|
||
{
|
||
callback(null, [ { id: certificate.id, fields: cert.Subject, valid_to_date: moment(cert.ValidToDate).format("DD.MM.YYYY") } ]);
|
||
}
|
||
else
|
||
{
|
||
callback(null, []);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
callback(null, []);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if(cert.Subject['INNLE'] !== undefined && cert.Subject['INNLE'] !== null && cert.Subject['INNLE'] !== "")
|
||
{
|
||
let owner_valid = true;
|
||
const fields = [ "lastname", "firstname", "middlename", ];
|
||
const cert_owner = `${ cert.Subject['SN']} ${ cert.Subject['G']}`.toUpperCase();
|
||
|
||
for(let i in fields)
|
||
{
|
||
if(head_person[fields[i]] !== null && head_person[fields[i]] !== "")
|
||
{
|
||
if(cert_owner.indexOf(head_person[fields[i]].toUpperCase().trim()) < 0)
|
||
{
|
||
owner_valid = false;
|
||
}
|
||
}
|
||
}
|
||
|
||
if(owner_valid)
|
||
{
|
||
callback(null, [ { id: certificate.id, fields: cert.Subject, valid_to_date: moment(cert.ValidToDate).format("DD.MM.YYYY") } ]);
|
||
}
|
||
else
|
||
{
|
||
callback(null, []);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
callback(null, []);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
callback(null, []);
|
||
}
|
||
})
|
||
.catch((error_certificates_info) =>
|
||
{
|
||
console.error({ error_certificates_info });
|
||
this.setState({ loading: false, certificates_error: "CERTIFICATES" });
|
||
});
|
||
}, (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") }.sig`;
|
||
|
||
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 =>
|
||
{
|
||
//console.log({ signature });
|
||
|
||
let signature_file = new File([ signature ], filename);
|
||
uploadSignedFile(signature_file, 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 { company, main, head_person } = this.props;
|
||
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['INNLE'] }</span>
|
||
</p>
|
||
<p className="item_desc">
|
||
{ certificate.fields['OGRNIP'] && (<span>ОГРНИП { certificate.fields['OGRNIP'] }</span>) }
|
||
{ certificate.fields['OGRN'] && (<span>ОГРН { certificate.fields['OGRN'] }</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="moderate" 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={ <>Отсутствует действующий сертификат. ИНН: { company.inn }. ФИО: { head_person.lastname } { head_person.firstname } { head_person.middlename }</> }/>
|
||
) }
|
||
{ certificates_error === "MISMATCH" && (
|
||
<FormMessage type="error" title="Ошибка" message={ <>Подписант не соответствует указанному подписанту в анкете.</> }/>
|
||
) }
|
||
</React.Fragment>
|
||
|
||
)
|
||
}
|
||
}
|
||
}
|
||
} |