1515use ImagickPixel ;
1616use OCA \Libresign \AppInfo \Application ;
1717use OCA \Libresign \Exception \LibresignException ;
18+ use OCA \Libresign \Vendor \Endroid \QrCode \Color \Color ;
19+ use OCA \Libresign \Vendor \Endroid \QrCode \Encoding \Encoding ;
20+ use OCA \Libresign \Vendor \Endroid \QrCode \ErrorCorrectionLevel ;
21+ use OCA \Libresign \Vendor \Endroid \QrCode \QrCode ;
22+ use OCA \Libresign \Vendor \Endroid \QrCode \RoundBlockSizeMode ;
23+ use OCA \Libresign \Vendor \Endroid \QrCode \Writer \PngWriter ;
1824use OCA \Libresign \Vendor \Twig \Environment ;
1925use OCA \Libresign \Vendor \Twig \Error \SyntaxError ;
2026use OCA \Libresign \Vendor \Twig \Loader \FilesystemLoader ;
2127use OCP \IAppConfig ;
2228use OCP \IDateTimeZone ;
2329use OCP \IL10N ;
2430use OCP \IRequest ;
31+ use OCP \IURLGenerator ;
2532use OCP \IUserSession ;
2633use Psr \Log \LoggerInterface ;
2734use Sabre \DAV \UUIDUtil ;
@@ -34,12 +41,14 @@ class SignatureTextService {
3441 public const FRONT_SIZE_MAX = 30 ;
3542 public const DEFAULT_SIGNATURE_WIDTH = 350 ;
3643 public const DEFAULT_SIGNATURE_HEIGHT = 100 ;
44+ private const QRCODE_SIZE = 100 ;
3745 public function __construct (
3846 private IAppConfig $ appConfig ,
3947 private IL10N $ l10n ,
4048 private IDateTimeZone $ dateTimeZone ,
4149 private IRequest $ request ,
4250 private IUserSession $ userSession ,
51+ private IURLGenerator $ urlGenerator ,
4352 protected LoggerInterface $ logger ,
4453 ) {
4554 }
@@ -137,8 +146,10 @@ public function parse(string $template = '', array $context = []): array {
137146 }
138147 if (empty ($ context )) {
139148 $ date = new \DateTime ('now ' , new \DateTimeZone ('UTC ' ));
149+ $ documentUuid = UUIDUtil::getUUID ();
150+ $ validationUrl = $ this ->buildValidationUrl ($ documentUuid );
140151 $ context = [
141- 'DocumentUUID ' => UUIDUtil:: getUUID () ,
152+ 'DocumentUUID ' => $ documentUuid ,
142153 'IssuerCommonName ' => 'Acme Cooperative ' ,
143154 'LocalSignerSignatureDateOnly ' => ($ date )->format ('Y-m-d ' ),
144155 'LocalSignerSignatureDateTime ' => ($ date )->format (DateTimeInterface::ATOM ),
@@ -148,8 +159,17 @@ public function parse(string $template = '', array $context = []): array {
148159 'SignerCommonName ' => $ this ->userSession ?->getUser()?->getDisplayName() ?? 'John Doe ' ,
149160 'SignerEmail ' => $ this ->userSession ?->getUser()?->getEMailAddress() ?? 'john.doe@libresign.coop ' ,
150161 'SignerUserAgent ' => $ this ->request ->getHeader ('User-Agent ' ),
162+ 'ValidationURL ' => $ validationUrl ,
163+ 'qrcode ' => $ this ->getQrCodeImageBase64 ($ validationUrl ),
151164 ];
152165 }
166+
167+ if (!isset ($ context ['ValidationURL ' ]) && isset ($ context ['DocumentUUID ' ]) && is_string ($ context ['DocumentUUID ' ]) && $ context ['DocumentUUID ' ] !== '' ) {
168+ $ context ['ValidationURL ' ] = $ this ->buildValidationUrl ($ context ['DocumentUUID ' ]);
169+ }
170+ if (!isset ($ context ['qrcode ' ]) && isset ($ context ['ValidationURL ' ]) && is_string ($ context ['ValidationURL ' ])) {
171+ $ context ['qrcode ' ] = $ this ->getQrCodeImageBase64 ($ context ['ValidationURL ' ]);
172+ }
153173 try {
154174 $ twigEnvironment = new Environment (
155175 new FilesystemLoader (),
@@ -189,6 +209,13 @@ public function getAvailableVariables(): array {
189209 '{{SignerCommonName}} ' => $ this ->l10n ->t ('Common Name (CN) used to identify the document signer. ' ),
190210 '{{SignerEmail}} ' => $ this ->l10n ->t ('The signer \'s email is optional and can be left blank. ' ),
191211 '{{SignerIdentifier}} ' => $ this ->l10n ->t ('Unique information used to identify the signer (such as email, phone number, or username). ' ),
212+ '{{ValidationURL}} ' => $ this ->l10n ->t ('Validation URL of the signed document. ' ),
213+ // TRANSLATORS This sentence is a description shown in the list of
214+ // available template variables.
215+ // Keep placeholder names unchanged: {{ qrcode }} and {{ValidationURL}}.
216+ // Keep this HTML snippet unchanged:
217+ // <img src="data:image/png;base64,{{ qrcode }}">
218+ '{{qrcode}} ' => $ this ->l10n ->t ('Base64-encoded PNG QR code for the validation URL. In HTML/Twig, use <img src="data:image/png;base64,{{ qrcode }}">. In plain-text templates, use {{ValidationURL}}. ' ),
192219 ];
193220 $ collectMetadata = $ this ->appConfig ->getValueBool (Application::APP_ID , 'collect_metadata ' , false );
194221 if ($ collectMetadata ) {
@@ -198,6 +225,24 @@ public function getAvailableVariables(): array {
198225 return $ list ;
199226 }
200227
228+ private function getQrCodeImageBase64 (string $ text ): string {
229+ $ qrCode = new QrCode (
230+ data: $ text ,
231+ encoding: new Encoding ('UTF-8 ' ),
232+ errorCorrectionLevel: ErrorCorrectionLevel::Low,
233+ size: self ::QRCODE_SIZE ,
234+ margin: 4 ,
235+ roundBlockSizeMode: RoundBlockSizeMode::Margin,
236+ foregroundColor: new Color (0 , 0 , 0 ),
237+ backgroundColor: new Color (255 , 255 , 255 )
238+ );
239+
240+ $ writer = new PngWriter ();
241+ $ result = $ writer ->write ($ qrCode );
242+
243+ return base64_encode ($ result ->getString ());
244+ }
245+
201246 public function signerNameImage (
202247 string $ text ,
203248 int $ width ,
@@ -506,4 +551,15 @@ public function getRenderMode(): string {
506551 public function isEnabled (): bool {
507552 return !empty ($ this ->getTemplate ());
508553 }
554+
555+ private function buildValidationUrl (string $ uuid ): string {
556+ $ validationSite = trim ($ this ->appConfig ->getValueString (Application::APP_ID , 'validation_site ' , '' ));
557+ if ($ validationSite !== '' ) {
558+ return rtrim ($ validationSite , '/ ' ) . '/ ' . $ uuid ;
559+ }
560+
561+ return $ this ->urlGenerator ->linkToRouteAbsolute ('libresign.page.validationFileWithShortUrl ' , [
562+ 'uuid ' => $ uuid ,
563+ ]);
564+ }
509565}
0 commit comments