package ee.tuleva.onboarding.mandate.signature;

import com.codeborne.security.mobileid.IdCardSignatureSession;
import com.codeborne.security.mobileid.MobileIDAuthenticator;
import com.codeborne.security.mobileid.SignatureFile;
import ee.sk.smartid.*;
import ee.sk.smartid.rest.dao.NationalIdentity;
import lombok.RequiredArgsConstructor;
import org.apache.commons.codec.binary.Hex;
import org.springframework.stereotype.Service;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateEncodingException;
import java.util.List;
import java.util.concurrent.Executor;

@Service
@RequiredArgsConstructor
public class SmartIdSigner {

    private final Executor smartIdExecutor;
    private final SmartIdClient smartIdClient;
    private final MobileIDAuthenticator signer;

    public SmartIdSignatureSession sign(List<SignatureFile> files, String personalCode) {

        NationalIdentity nationalIdentity = new NationalIdentity("EE", personalCode);

        SmartIdCertificate certificateResponse = smartIdClient
                .getCertificate()
                .withNationalIdentity(nationalIdentity)
                .withCertificateLevel("QUALIFIED")
                .fetch();

        IdCardSignatureSession idCardSession;
        try {
            idCardSession = signer.startSign(files, Hex.encodeHexString(certificateResponse.getCertificate().getEncoded()));
        } catch (CertificateEncodingException e) {
            throw new RuntimeException(e);
        }

        MessageDigest messageDigest = getMessageDigest();
        SignableHash signableHash = signableHash(messageDigest.digest(idCardSession.hash.getBytes()));

        SmartIdSignatureSession session = new SmartIdSignatureSession(signableHash.calculateVerificationCode(), idCardSession);

        smartIdExecutor.execute(() -> {
            String documentNumber = certificateResponse.getDocumentNumber();
            SmartIdSignature smartIdSignature = smartIdClient
                    .createSignature()
                    .withDocumentNumber(documentNumber)
                    .withSignableHash(signableHash)
                    .withCertificateLevel("QUALIFIED")
                    .sign();

            String signatureValue = Hex.encodeHexString(smartIdSignature.getValue());
            session.setSignedFile(signer.getSignedFile(idCardSession, signatureValue));
        });

        return session;
    }

    private MessageDigest getMessageDigest() {
        MessageDigest digest;
        try {
            digest = MessageDigest.getInstance("SHA-256");
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
        return digest;
    }

    private SignableHash signableHash(byte[] signatureToSign) {
        SignableHash hashToSign = new SignableHash();
        hashToSign.setHashType(HashType.SHA256);
        hashToSign.setHash(signatureToSign);
        return hashToSign;
    }

    public byte[] getSignedFile(SmartIdSignatureSession session) {
        return session.getSignedFile();
    }
}

@@ -328,24 +328,74 @@
 onstructor;%0A
+import org.apache.commons.codec.DecoderException;%0A
 import org.a
@@ -478,91 +478,8 @@
 e;%0A%0A
-import java.security.MessageDigest;%0Aimport java.security.NoSuchAlgorithmException;%0A
 impo
@@ -1507,158 +1507,293 @@
     
-MessageDigest messageDigest = getMessageDigest();%0A        SignableHash signableHash = signableHash(messageDigest.digest(idCardSession.hash.getBytes())
+SignableHash signableHash = new SignableHash();%0A        try %7B%0A            signableHash.setHash(Hex.decodeHex(idCardSession.hash.toCharArray()));%0A        %7D catch (DecoderException e) %7B%0A            throw new RuntimeException(e);%0A        %7D%0A        signableHash.setHashType(HashType.SHA256
 );%0A%0A
@@ -2554,534 +2554,8 @@
  %7D%0A%0A
-    private MessageDigest getMessageDigest() %7B%0A        MessageDigest digest;%0A        try %7B%0A            digest = MessageDigest.getInstance(%22SHA-256%22);%0A        %7D catch (NoSuchAlgorithmException e) %7B%0A            throw new RuntimeException(e);%0A        %7D%0A        return digest;%0A    %7D%0A%0A    private SignableHash signableHash(byte%5B%5D signatureToSign) %7B%0A        SignableHash hashToSign = new SignableHash();%0A        hashToSign.setHashType(HashType.SHA256);%0A        hashToSign.setHash(signatureToSign);%0A        return hashToSign;%0A    %7D%0A%0A
     

Convert signature from hex