diff --git a/lib/Handler/JSignPdfHandler.php b/lib/Handler/JSignPdfHandler.php index 37af5c660e..6f5c573824 100644 --- a/lib/Handler/JSignPdfHandler.php +++ b/lib/Handler/JSignPdfHandler.php @@ -64,6 +64,33 @@ public function getJSignParam(): JSignParam { return $this->jSignParam; } + private function getHashAlgorithm(): string { + /** + * Need to respect the follow code: + * https://github.com/intoolswetrust/jsignpdf/blob/JSignPdf_2_2_2/jsignpdf/src/main/java/net/sf/jsignpdf/types/HashAlgorithm.java#L46-L47 + */ + $content = $this->getInputFile()->getContent(); + if (!$content) { + return 'SHA1'; + } + preg_match('/^%PDF-(?\d+(\.\d+)?)/', $content, $match); + if (isset($match['version'])) { + $version = (float)$match['version']; + if ($version < 1.6) { + return 'SHA1'; + } + if ($version < 1.7) { + return 'SHA256'; + } + } + + $hashAlgorithm = $this->appConfig->getAppValue('signature_hash_algorithm', 'SHA256'); + if (in_array($hashAlgorithm, ['SHA1', 'SHA256', 'SHA384', 'SHA512', 'RIPEMD160'])) { + return $hashAlgorithm; + } + return 'SHA256'; + } + /** * @psalm-suppress MixedReturnStatement */ @@ -112,6 +139,13 @@ private function signUsingVisibleElements(): string { private function signWrapper(JSignPDF $jSignPDF): string { try { + $param = $this->getJSignParam(); + $param + ->setJSignParameters( + $this->jSignParam->getJSignParameters() . + ' --hash-algorithm ' . $this->getHashAlgorithm() + ); + $jSignPDF->setParam($param); return $jSignPDF->sign(); } catch (\Throwable $th) { $rows = str_getcsv($th->getMessage()); diff --git a/lib/ResponseDefinitions.php b/lib/ResponseDefinitions.php index 44794f0e60..48af32f2e8 100644 --- a/lib/ResponseDefinitions.php +++ b/lib/ResponseDefinitions.php @@ -125,10 +125,23 @@ * label: string, * name: string, * } + * @psalm-type LibresignSignatureMethodEmailToken = array{ + * label: string, + * identifyMethod: "email"|"account", + * needCode: bool, + * hasConfirmCode: bool, + * blurredEmail: string, + * hashOfEmail: string, + * } + * @psalm-type LibresignSignatureMethodPassword = array{ + * label: string, + * name: string, + * hasSignatureFile: bool, + * } * @psalm-type LibresignSignatureMethods = array{ * clickToSign?: LibresignSignatureMethod, - * emailToken?: LibresignSignatureMethod, - * password?: LibresignSignatureMethod, + * emailToken?: LibresignSignatureMethodEmailToken, + * password?: LibresignSignatureMethodPassword, * } * @psalm-type LibresignSigner = array{ * description: ?string, @@ -143,7 +156,7 @@ * signRequestId: non-negative-int, * identifyMethods?: LibresignIdentifyMethod[], * visibleElements?: LibresignVisibleElement[], - * signatureMethods?: LibresignSignatureMethods[], + * signatureMethods?: LibresignSignatureMethods, * } * @psalm-type LibresignValidateFile = array{ * uuid: string, diff --git a/lib/Service/IdentifyMethodService.php b/lib/Service/IdentifyMethodService.php index 2d34f4a660..a1e690e1f4 100644 --- a/lib/Service/IdentifyMethodService.php +++ b/lib/Service/IdentifyMethodService.php @@ -178,9 +178,6 @@ public function getSignMethodsOfIdentifiedFactors(int $signRequestId): array { $return = []; foreach ($matrix as $identifyMethods) { foreach ($identifyMethods as $identifyMethod) { - if (empty($identifyMethod->getEntity()->getIdentifiedAtDate())) { - continue; - } $signatureMethods = $identifyMethod->getSignatureMethods(); foreach ($signatureMethods as $signatureMethod) { if (!$signatureMethod->isEnabled()) { diff --git a/openapi-full.json b/openapi-full.json index 24c98b83f0..fdd71cc001 100644 --- a/openapi-full.json +++ b/openapi-full.json @@ -612,6 +612,60 @@ } } }, + "SignatureMethodEmailToken": { + "type": "object", + "required": [ + "label", + "identifyMethod", + "needCode", + "hasConfirmCode", + "blurredEmail", + "hashOfEmail" + ], + "properties": { + "label": { + "type": "string" + }, + "identifyMethod": { + "type": "string", + "enum": [ + "email", + "account" + ] + }, + "needCode": { + "type": "boolean" + }, + "hasConfirmCode": { + "type": "boolean" + }, + "blurredEmail": { + "type": "string" + }, + "hashOfEmail": { + "type": "string" + } + } + }, + "SignatureMethodPassword": { + "type": "object", + "required": [ + "label", + "name", + "hasSignatureFile" + ], + "properties": { + "label": { + "type": "string" + }, + "name": { + "type": "string" + }, + "hasSignatureFile": { + "type": "boolean" + } + } + }, "SignatureMethods": { "type": "object", "properties": { @@ -619,10 +673,10 @@ "$ref": "#/components/schemas/SignatureMethod" }, "emailToken": { - "$ref": "#/components/schemas/SignatureMethod" + "$ref": "#/components/schemas/SignatureMethodEmailToken" }, "password": { - "$ref": "#/components/schemas/SignatureMethod" + "$ref": "#/components/schemas/SignatureMethodPassword" } } }, @@ -685,10 +739,7 @@ } }, "signatureMethods": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SignatureMethods" - } + "$ref": "#/components/schemas/SignatureMethods" } } }, diff --git a/openapi.json b/openapi.json index d70fd44572..37090de13c 100644 --- a/openapi.json +++ b/openapi.json @@ -516,6 +516,60 @@ } } }, + "SignatureMethodEmailToken": { + "type": "object", + "required": [ + "label", + "identifyMethod", + "needCode", + "hasConfirmCode", + "blurredEmail", + "hashOfEmail" + ], + "properties": { + "label": { + "type": "string" + }, + "identifyMethod": { + "type": "string", + "enum": [ + "email", + "account" + ] + }, + "needCode": { + "type": "boolean" + }, + "hasConfirmCode": { + "type": "boolean" + }, + "blurredEmail": { + "type": "string" + }, + "hashOfEmail": { + "type": "string" + } + } + }, + "SignatureMethodPassword": { + "type": "object", + "required": [ + "label", + "name", + "hasSignatureFile" + ], + "properties": { + "label": { + "type": "string" + }, + "name": { + "type": "string" + }, + "hasSignatureFile": { + "type": "boolean" + } + } + }, "SignatureMethods": { "type": "object", "properties": { @@ -523,10 +577,10 @@ "$ref": "#/components/schemas/SignatureMethod" }, "emailToken": { - "$ref": "#/components/schemas/SignatureMethod" + "$ref": "#/components/schemas/SignatureMethodEmailToken" }, "password": { - "$ref": "#/components/schemas/SignatureMethod" + "$ref": "#/components/schemas/SignatureMethodPassword" } } }, @@ -589,10 +643,7 @@ } }, "signatureMethods": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SignatureMethods" - } + "$ref": "#/components/schemas/SignatureMethods" } } }, diff --git a/src/types/openapi/openapi-full.ts b/src/types/openapi/openapi-full.ts index 43790efb0e..45fc4e040a 100644 --- a/src/types/openapi/openapi-full.ts +++ b/src/types/openapi/openapi-full.ts @@ -1210,10 +1210,24 @@ export type components = { label: string; name: string; }; + SignatureMethodEmailToken: { + label: string; + /** @enum {string} */ + identifyMethod: "email" | "account"; + needCode: boolean; + hasConfirmCode: boolean; + blurredEmail: string; + hashOfEmail: string; + }; + SignatureMethodPassword: { + label: string; + name: string; + hasSignatureFile: boolean; + }; SignatureMethods: { clickToSign?: components["schemas"]["SignatureMethod"]; - emailToken?: components["schemas"]["SignatureMethod"]; - password?: components["schemas"]["SignatureMethod"]; + emailToken?: components["schemas"]["SignatureMethodEmailToken"]; + password?: components["schemas"]["SignatureMethodPassword"]; }; Signer: { description: string | null; @@ -1229,7 +1243,7 @@ export type components = { signRequestId: number; identifyMethods?: components["schemas"]["IdentifyMethod"][]; visibleElements?: components["schemas"]["VisibleElement"][]; - signatureMethods?: components["schemas"]["SignatureMethods"][]; + signatureMethods?: components["schemas"]["SignatureMethods"]; }; UserElement: { /** Format: int64 */ diff --git a/src/types/openapi/openapi.ts b/src/types/openapi/openapi.ts index 1f7aa8f687..ef3d3ce084 100644 --- a/src/types/openapi/openapi.ts +++ b/src/types/openapi/openapi.ts @@ -1064,10 +1064,24 @@ export type components = { label: string; name: string; }; + SignatureMethodEmailToken: { + label: string; + /** @enum {string} */ + identifyMethod: "email" | "account"; + needCode: boolean; + hasConfirmCode: boolean; + blurredEmail: string; + hashOfEmail: string; + }; + SignatureMethodPassword: { + label: string; + name: string; + hasSignatureFile: boolean; + }; SignatureMethods: { clickToSign?: components["schemas"]["SignatureMethod"]; - emailToken?: components["schemas"]["SignatureMethod"]; - password?: components["schemas"]["SignatureMethod"]; + emailToken?: components["schemas"]["SignatureMethodEmailToken"]; + password?: components["schemas"]["SignatureMethodPassword"]; }; Signer: { description: string | null; @@ -1083,7 +1097,7 @@ export type components = { signRequestId: number; identifyMethods?: components["schemas"]["IdentifyMethod"][]; visibleElements?: components["schemas"]["VisibleElement"][]; - signatureMethods?: components["schemas"]["SignatureMethods"][]; + signatureMethods?: components["schemas"]["SignatureMethods"]; }; UserElement: { /** Format: int64 */ diff --git a/src/views/Settings/Settings.vue b/src/views/Settings/Settings.vue index e6da9e1228..e38ade0f66 100644 --- a/src/views/Settings/Settings.vue +++ b/src/views/Settings/Settings.vue @@ -18,6 +18,7 @@ + @@ -36,6 +37,7 @@ import IdentificationFactors from './IdentificationFactors.vue' import LegalInformation from './LegalInformation.vue' import RootCertificateCfssl from './RootCertificateCfssl.vue' import RootCertificateOpenSsl from './RootCertificateOpenSsl.vue' +import SignatureHashAlgorithm from './SignatureHashAlgorithm.vue' import Validation from './Validation.vue' export default { @@ -55,6 +57,7 @@ export default { IdentificationDocuments, CollectMetadata, DefaultUserFolder, + SignatureHashAlgorithm, }, data() { return { diff --git a/src/views/Settings/SignatureHashAlgorithm.vue b/src/views/Settings/SignatureHashAlgorithm.vue new file mode 100644 index 0000000000..baed98edd4 --- /dev/null +++ b/src/views/Settings/SignatureHashAlgorithm.vue @@ -0,0 +1,76 @@ + + + + + diff --git a/src/views/SignPDF/_partials/Sign.vue b/src/views/SignPDF/_partials/Sign.vue index 002a265156..6001cce5f6 100644 --- a/src/views/SignPDF/_partials/Sign.vue +++ b/src/views/SignPDF/_partials/Sign.vue @@ -283,9 +283,12 @@ export default { } }) .catch((err) => { - err.response.data.ocs.data.errors.forEach(err => { - showError(err) - }) + const errors = err.response?.data?.ocs?.data?.errors + if (errors) { + errors.forEach(error => { + showError(error) + }) + } }) this.loading = false },