The system offers modules to work with some cryptographic service providers (CSPs) that allow you to sign user data.
The default providers include CryptoPro and NCA.
Client scripts help you sign data using other cloud CSPs. To work with these features, you need to
configure a digital signature in an app.
To get specific data and manage changes in the system, you can sign data using an internal signature. A signature
of this type is not legally valid; it is used specifically to control changes in an app and capture a version of data stored
in an app item. Along with the signature, you can obtain data calculated based on an app’s signature settings.
With an internal signature, you can sign attributes of an item of any app type or a file
in a Document type app. To get an internal signature, you need to store the app in the context
or find it using the Global or Namespace objects:
asyncfunctionworkWithDataSigns(): Promise<void> {
// Getting the app from the context// `document` is a Document type appconst app = Context.data.document!;
// Getting the app’s dataconst appData = await app.fetch();
// Getting signaturesconst innerSigns = await appData.getDataSigns();
// Getting the attributes’ internal signature to sign the data using a CSPconst attributesInnerSign = innerSigns.find(innerSign => innerSign.type === SignType.Attributes);
if (!attributesInnerSign) {
thrownewError('Internal signature not found');
}
}
In the previous example, we signed an app item’s attributes. Each internal digital signature
stores the data’s hash (data footprint) and the signed data itself. This data can then be used to send it
to the CSP that signs it:
asyncfunctionsaveSign(): Promise<void> {
// `SignProvider` is an example of a CSP// Includes one method of calculating a signature using the dataconst signProvider = new SignProvider();
// Getting a signature for an app item’s attributesconst signData = signProvider.sign(attributesInnerSign.body);
const newSign: NewSign = {
// Signature in the base64 formatsign: signData;
// Type of signature, depending on what needs to be signed, `signature` or `files`
signType: attributesInnerSign.type;
// Code of the signature provider
codeProvider: 'signProvider';
// ID of the base64 file
body: attributesInnerSign.body,
// Hash of the signed data (it is needed to identify the version of the signed data)hash: attributesInnerSign.hash,
}
await appData.uploadSign(newSign);
}
To get the content of the signed attributes and the signature itself, you the createAttributesFile and
EntitySign.createSignFile methods. To get EntitySign, you need the history of app item signatures.
To find the necessary version of the signature in the history, use the app’s
internal signature:
asyncfunctiongetSignsFiles(): Promise<void> {
// Getting a Document type app from the context of the client scriptconst app = Context.data.document!;
// Getting the app’s dataconst appData = await app.fetch();
// Getting the history of an app item’s signaturesconst signsHistory = await appData.getSignHistory();
// Getting internal signaturesconst innerSigns = await appData.getDataSigns();
// Let’s add the attributes’ internal signature to sign the data using a CSPconst attributesInnerSign = innerSigns.find(innerSign => innerSign.type === SignType.Attributes);
if (!attributesInnerSign) {
thrownewError('Internal signature not found');
}
// Let’s find the signatures of the last version of an app item in the signatures archiveconst signs = signsHistory.find(signs => signs.hash === attributesInnerSigns.hash);
if (!signs) {
thrownewError('This version is not signed');
}
const dataSign = signs.signs[0];
const attributesFile = await dataSign.createAttributesFile();
const signFile = await dataSign.createSignFile();
}
The system allows you to get detailed information about a signature, including:
Information about the signature itself
Signature content
Information on the public key that was used to sign the data
Signed data
To get the information, call the EntitySign.getDetails method. This method allows you to get
detailed information about a signature. Let’s say we need to define whether data was signed by an individual
or a legal entity. To do that, we need to get the signature from the history and call the EntitySign.getDetails method.
After obtaining the data, we need to analyze the content of the certificate:
asyncfunctionwhoMadeSign(): Promise<void> {
// Getting a Document type app from the context of a client scriptconst app = Context.data.document!;
// Getting the app’s dataconst appData = await app.fetch();
// Getting the history of an app’s signaturesconst signsHistory = await appData.getSignHistory();
// Getting the most recent signatureconst sign = signsHistory[0].signs[0];
// Getting information about the signatureconst signDetails = await sign.getDetails();
// If one of the following fields is filled out, the data is signed by a legal entity// Other fields of a certificate can also be used for checks of this type,// depending on the provider who issued the digital signatureconst orgField = signDetails.subject['O'] || signDetails.subject['OU'];
if (orgField !== '') {
// Signed by a legal entity
} else {
// Signed by an individual
}
}
You can also obtain information about signature certificates, including data about the issuing CA, the entity to whom the certificate was issued, and its validity period.
Here’s an example script to retrieve information about signature certificates expiring within a month:
asyncfunctionsignWithSoonExpiredCerts (): Promise<void> {
// Get current userconst user = await System.users.getCurrentUser();
// Date the signature certificate expiresconst expiredDate = new Datetime().addDate(0, 1, 0);
// Get the user’s signaturesconst digitalSigns = await System.signs.digitalSigns.search().where(sign => sign.__createdBy.eq(user)).all();
// Get signatures with certificates expiring within the next monthconst expiredSigns = digitalSigns.filter(sign => sign.data.validUntilAt?.beforeOrEqual(expiredDate));
// Write information about signatures with expiring certificates to the context
Context.data.expiredcerts = 'Certificates expiring within a month: ';
for (let sign of expiredSigns) {
const subjectName = sign.data.subject ? sign.data.subject['CN'] ?? 'name unknown' : 'signer unknown';
Context.data.expiredcerts += `${sign.id} : ${subjectName},`;
}
return;
}
Getting started with signatures
The system offers modules to work with some cryptographic service providers (CSPs) that allow you to sign user data. The default providers include CryptoPro and NCA. Client scripts help you sign data using other cloud CSPs. To work with these features, you need to configure a digital signature in an app.
Internal signature
To get specific data and manage changes in the system, you can sign data using an internal signature. A signature of this type is not legally valid; it is used specifically to control changes in an app and capture a version of data stored in an app item. Along with the signature, you can obtain data calculated based on an app’s signature settings. With an internal signature, you can sign attributes of an item of any app type or a file in a Document type app. To get an internal signature, you need to store the app in the context or find it using the Global or Namespace objects:
async function workWithDataSigns(): Promise<void> { // Getting the app from the context // `document` is a Document type app const app = Context.data.document!; // Getting the app’s data const appData = await app.fetch(); // Getting signatures const innerSigns = await appData.getDataSigns(); // Getting the attributes’ internal signature to sign the data using a CSP const attributesInnerSign = innerSigns.find(innerSign => innerSign.type === SignType.Attributes); if (!attributesInnerSign) { throw new Error('Internal signature not found'); } }
Upload an obtained signature to the system
In the previous example, we signed an app item’s attributes. Each internal digital signature stores the data’s hash (data footprint) and the signed data itself. This data can then be used to send it to the CSP that signs it:
async function saveSign(): Promise<void> { // `SignProvider` is an example of a CSP // Includes one method of calculating a signature using the data const signProvider = new SignProvider(); // Getting a signature for an app item’s attributes const signData = signProvider.sign(attributesInnerSign.body); const newSign: NewSign = { // Signature in the base64 format sign: signData; // Type of signature, depending on what needs to be signed, `signature` or `files` signType: attributesInnerSign.type; // Code of the signature provider codeProvider: 'signProvider'; // ID of the base64 file body: attributesInnerSign.body, // Hash of the signed data (it is needed to identify the version of the signed data) hash: attributesInnerSign.hash, } await appData.uploadSign(newSign); }
Get the signed attributes and the signature as a file
To get the content of the signed attributes and the signature itself, you the createAttributesFile and EntitySign.createSignFile methods. To get EntitySign, you need the history of app item signatures. To find the necessary version of the signature in the history, use the app’s internal signature:
async function getSignsFiles(): Promise<void> { // Getting a Document type app from the context of the client script const app = Context.data.document!; // Getting the app’s data const appData = await app.fetch(); // Getting the history of an app item’s signatures const signsHistory = await appData.getSignHistory(); // Getting internal signatures const innerSigns = await appData.getDataSigns(); // Let’s add the attributes’ internal signature to sign the data using a CSP const attributesInnerSign = innerSigns.find(innerSign => innerSign.type === SignType.Attributes); if (!attributesInnerSign) { throw new Error('Internal signature not found'); } // Let’s find the signatures of the last version of an app item in the signatures archive const signs = signsHistory.find(signs => signs.hash === attributesInnerSigns.hash); if (!signs) { throw new Error('This version is not signed'); } const dataSign = signs.signs[0]; const attributesFile = await dataSign.createAttributesFile(); const signFile = await dataSign.createSignFile(); }
Get detailed information about a signature
The system allows you to get detailed information about a signature, including:
To get the information, call the EntitySign.getDetails method. This method allows you to get detailed information about a signature. Let’s say we need to define whether data was signed by an individual or a legal entity. To do that, we need to get the signature from the history and call the EntitySign.getDetails method. After obtaining the data, we need to analyze the content of the certificate:
async function whoMadeSign(): Promise<void> { // Getting a Document type app from the context of a client script const app = Context.data.document!; // Getting the app’s data const appData = await app.fetch(); // Getting the history of an app’s signatures const signsHistory = await appData.getSignHistory(); // Getting the most recent signature const sign = signsHistory[0].signs[0]; // Getting information about the signature const signDetails = await sign.getDetails(); // If one of the following fields is filled out, the data is signed by a legal entity // Other fields of a certificate can also be used for checks of this type, // depending on the provider who issued the digital signature const orgField = signDetails.subject['O'] || signDetails.subject['OU']; if (orgField !== '') { // Signed by a legal entity } else { // Signed by an individual } }
You can also obtain information about signature certificates, including data about the issuing CA, the entity to whom the certificate was issued, and its validity period.
Here’s an example script to retrieve information about signature certificates expiring within a month:
async function signWithSoonExpiredCerts (): Promise<void> { // Get current user const user = await System.users.getCurrentUser(); // Date the signature certificate expires const expiredDate = new Datetime().addDate(0, 1, 0); // Get the user’s signatures const digitalSigns = await System.signs.digitalSigns.search().where(sign => sign.__createdBy.eq(user)).all(); // Get signatures with certificates expiring within the next month const expiredSigns = digitalSigns.filter(sign => sign.data.validUntilAt?.beforeOrEqual(expiredDate)); // Write information about signatures with expiring certificates to the context Context.data.expiredcerts = 'Certificates expiring within a month: '; for (let sign of expiredSigns) { const subjectName = sign.data.subject ? sign.data.subject['CN'] ?? 'name unknown' : 'signer unknown'; Context.data.expiredcerts += `${sign.id} : ${subjectName},`; } return; }