1
0
Fork 0
mirror of https://github.com/24eme/signaturepdf synced 2026-03-14 13:55:44 +01:00

Compilation du pdf signé en mode makefile

This commit is contained in:
Vincent LAURENT 2024-08-01 15:00:25 +02:00
commit 45e71e38af
3 changed files with 151 additions and 60 deletions

38
app.php
View file

@ -171,7 +171,7 @@ $f3->route('POST /image2svg',
$f3->route('POST /sign',
function($f3) {
$filename = null;
$tmpfile = tempnam($f3->get('UPLOADS'), 'pdfsignature_sign');
$tmpfile = tempnam($f3->get('UPLOADS'), 'pdfsignature_sign_'.uniqid(null, true));
unlink($tmpfile);
$svgFiles = [];
@ -220,10 +220,6 @@ $f3->route('POST /sign',
$f3->route('POST /share',
function($f3) {
$hash = Web::instance()->slug($_POST['hash']);
$sharingFolder = $f3->get('PDF_STORAGE_PATH').$hash;
$symmetricKey = (isset($_COOKIE[$hash])) ? GPGCryptography::protectSymmetricKey($_COOKIE[$hash]) : null;
if (!is_dir($f3->get('PDF_STORAGE_PATH'))) {
$f3->error(500, 'Sharing folder doesn\'t exist');
}
@ -231,15 +227,15 @@ $f3->route('POST /share',
$f3->error(500, 'Sharing folder is not writable');
}
$pdfSignature = new PDFSignature($sharingFolder, $symmetricKey);
$pdfSignature->createShare($f3->get('POST.duration'));
$hash = Web::instance()->slug($_POST['hash']);
$symmetricKey = (isset($_COOKIE[$hash])) ? GPGCryptography::protectSymmetricKey($_COOKIE[$hash]) : null;
$f3->set('UPLOADS', $sharingFolder."/");
$filename = "original.pdf";
$tmpfile = tempnam($sharingFolder, date('YmdHis'));
$tmpfile = tempnam($f3->get('UPLOADS'), 'pdfsignature_share_'.uniqid($hash, true));
unlink($tmpfile);
$svgFiles = [];
$originalFile = $tmpfile."_original.pdf";
$originalFileBaseName = null;
$files = Web::instance()->receive(function($file,$formFieldName){
if($formFieldName == "pdf" && strpos(Web::instance()->mime($file['tmp_name'], true), 'application/pdf') !== 0) {
$f3->error(403);
@ -249,10 +245,10 @@ $f3->route('POST /share',
}
return true;
}, false, function($fileBaseName, $formFieldName) use ($tmpfile, $filename, $sharingFolder, &$svgFiles) {
}, false, function($fileBaseName, $formFieldName) use ($tmpfile, $originalFile, &$svgFiles, &$originalFileBaseName) {
if($formFieldName == "pdf") {
file_put_contents($sharingFolder."/filename.txt", $fileBaseName);
return $filename;
$originalFileBaseName = $fileBaseName;
return basename($originalFile);
}
if($formFieldName == "svg") {
$svgFiles[] = $tmpfile."_".$fileBaseName;
@ -264,10 +260,10 @@ $f3->route('POST /share',
$f3->error(403);
}
$pdfSignature->saveShare();
$pdfSignature = new PDFSignature($f3->get('PDF_STORAGE_PATH').$hash, $symmetricKey);
$pdfSignature->createShare($originalFile, $originalFileBaseName, $f3->get('POST.duration'));
if(count($svgFiles)) {
$pdfSignature->addSignature($svgFiles, $tmpfile.".svg.pdf");
$pdfSignature->addSignature($svgFiles);
}
if(!$f3->get('DEBUG')) {
@ -302,9 +298,7 @@ $f3->route('POST /signature/@hash/save',
function($f3) {
$hash = Web::instance()->slug($f3->get('PARAMS.hash'));
$symmetricKey = (isset($_COOKIE[$hash])) ? GPGCryptography::protectSymmetricKey($_COOKIE[$hash]) : null;
$f3->set('UPLOADS', $f3->get('PDF_STORAGE_PATH').$hash."/");
$tmpfile = tempnam($f3->get('PDF_STORAGE_PATH').$hash, date('YmdHis'));
$tmpfile = tempnam($f3->get('UPLOADS'), 'pdfsignature_save_'.uniqid($hash, true));
unlink($tmpfile);
$svgFiles = [];
$files = Web::instance()->receive(function($file,$formFieldName){
@ -323,7 +317,7 @@ $f3->route('POST /signature/@hash/save',
}
$pdfSignature = new PDFSignature($f3->get('PDF_STORAGE_PATH').$hash, $symmetricKey);
$pdfSignature->addSignature($svgFiles, $tmpfile.".svg.pdf");
$pdfSignature->addSignature($svgFiles);
if(!$f3->get('DEBUG')) {
$pdfSignature->clean();
@ -402,7 +396,7 @@ $f3->route('GET /compress',
$f3->route ('POST /compress',
function($f3) {
$filename = null;
$tmpfile = tempnam($f3->get('UPLOADS'), 'pdfsignature_sign');
$tmpfile = tempnam($f3->get('UPLOADS'), 'pdfsignature_compress_'.uniqid());
unlink($tmpfile);
$files = Web::instance()->receive(function($file,$formFieldName) {

View file

@ -28,6 +28,9 @@ class GPGCryptography
putenv('HOME='.sys_get_temp_dir());
foreach ($this->getFiles(false) as $file) {
$outputFile = $file.".gpg";
if(file_exists($outputFile)) {
unlink($outputFile);
}
$command = "gpg --batch --passphrase $this->symmetricKey --symmetric --cipher-algo AES256 -o $outputFile $file > /dev/null";
$result = shell_exec($command);
if ($result) {
@ -40,6 +43,20 @@ class GPGCryptography
return true;
}
public function decryptFile($file) {
if (!file_exists($file.'.gpg')) {
return $file;
}
if (!$this->symmetricKey) {
return false;
}
$decryptTmpFile = sys_get_temp_dir()."/".uniqid('pdfsignature.decrypted.'.getmypid().md5($file), true).'_'.basename($file);
$this->runDecryptFile($file.'.gpg', $decryptTmpFile);
return $decryptTmpFile;
}
public function decrypt() {
if (!$this->isEncrypted()) {
return $this->pathHash;
@ -48,19 +65,18 @@ class GPGCryptography
return false;
}
$decryptFolder = sys_get_temp_dir()."/".uniqid('pdfsignature.decrypted.'.getmypid(), true);
putenv('HOME='.sys_get_temp_dir());
mkdir($decryptFolder);
foreach ($this->getFiles(true) as $file) {
$outputFile = $decryptFolder."/".str_replace(".gpg", "", basename($file));
$command = "gpg --batch --passphrase $this->symmetricKey --decrypt -o $outputFile $file > /dev/null";
$result = shell_exec($command);
if ($result) {
throw new Exception("Decipher failure");
}
$this->runDecryptFile($file, $decryptFolder."/".str_replace(".gpg", "", basename($file)));
}
return $decryptFolder;
}
public function runDecryptFile($file, $outputFile) {
putenv('HOME='.sys_get_temp_dir());
shell_exec("gpg --batch --passphrase $this->symmetricKey --decrypt -o $outputFile $file > /dev/null");
}
public function isEncrypted() {
return self::isPathEncrypted($this->pathHash);
}

View file

@ -7,62 +7,131 @@ class PDFSignature
protected $hash = null;
protected $gpg = null;
protected $toClean = [];
protected $lockFile = null;
public function __construct($pathHash, $symmetricKey = null) {
$this->symmetricKey = $symmetricKey;
$this->pathHash = $pathHash;
$this->hash = basename($this->pathHash);
$this->gpg = new GPGCryptography($symmetricKey, $pathHash);
}
$this->lockFile = $this->pathHash.'/.lock';
}
public function createShare($duration) {
public function createShare($originalFile, $originFileBaseName, $duration) {
mkdir($this->pathHash);
$expireFile = $this->pathHash.".expire";
file_put_contents($expireFile, $duration);
touch($expireFile, date_format(date_modify(date_create(), file_get_contents($expireFile)), 'U'));
}
public function saveShare() {
rename($originalFile, $this->pathHash.'/original.pdf');
file_put_contents($this->pathHash.'/filename.txt', $originFileBaseName);
if($this->symmetricKey) {
$this->gpg->encrypt();
}
}
public function isEncrypted() {
return $this->isEncrypted();
}
public function getDecryptFile($file) {
if($this->isEncrypted()) {
$file = $this->gpg->decryptFile($file);
$this->toClean[] = $file;
}
return $file;
}
public function getPDF() {
$originalPathHash = $this->pathHash;
$this->pathHash = $this->gpg->decrypt();
if ($this->pathHash == false) {
$this->compile();
return $this->getDecryptFile($this->pathHash.'/final.pdf');
}
public function needToCompile() {
$needToCompile = false;
foreach($this->getLayers() as $layerFile) {
if(!file_exists(str_replace('.svg.pdf', '.sign.pdf', $layerFile))) {
$needToCompile = true;
}
}
if(!$this->isEncrypted() && !file_exists($this->pathHash.'/final.pdf')) {
$needToCompile = true;
}
if($this->isEncrypted() && !file_exists($this->pathHash.'/final.pdf.gpg')) {
$needToCompile = true;
}
return $needToCompile;
}
protected function isCompileLock() {
if(file_exists(touch($this->lockFile)) && filemtime($this->lockFile) > time() + 30) {
unlink($this->lockFile);
}
return file_exists(touch($this->lockFile));
}
protected function lockCompile() {
touch($this->lockFile);
}
protected function unlockCompile() {
unlink($this->lockFile);
}
public function compile() {
if(!$this->needToCompile()) {
return;
}
if($this->isCompileLock()) {
sleep(5);
$this->compile();
}
$this->lockCompile();
$pathHashDecrypted = $this->gpg->decrypt();
if ($pathHashDecrypted == false) {
throw new Exception("PDF file could not be decrypted. Cookie encryption key might be missing.");
}
if ($this->pathHash != $originalPathHash && $this->gpg->isEncrypted()) {
$this->toClean[] = $this->pathHash;
if ($this->pathHash != $pathHashDecrypted && $this->isEncrypted()) {
$this->toClean[] = $pathHashDecrypted;
}
$originalFile = $this->pathHash.'/original.pdf';
$finalFile = $this->pathHash.'/'.$this->hash.uniqid().'.pdf';
$layers = $this->getLayers();
if(!count($layers)) {
return $originalFile;
}
copy($originalFile, $finalFile);
$bufferFile = $finalFile.".tmp";
$layers = $this->getLayers($pathHashDecrypted);
$currentSignedFile = $pathHashDecrypted.'/original.pdf';
$signedFileToCopy = [];
foreach($layers as $layerFile) {
self::addSvgToPDF($finalFile, $layerFile, $bufferFile, false);
rename($bufferFile, $finalFile);
$signedFile = str_replace('.svg.pdf', '.sign.pdf', $layerFile);
if(!file_exists($signedFile)) {
self::addSvgToPDF($currentSignedFile, $layerFile, $signedFile, false);
if ($this->pathHash != $pathHashDecrypted && $this->isEncrypted()) {
copy($signedFile, str_replace($pathHashDecrypted ,$this->pathHash, $signedFile));
}
}
$currentSignedFile = $signedFile;
}
if ($this->pathHash == $originalPathHash && !$this->gpg->isEncrypted()) {
$this->toClean[] = $finalFile;
copy($currentSignedFile, $this->pathHash.'/final.pdf');
if($this->isEncrypted()) {
$this->gpg->encrypt();
}
return $finalFile;
$this->unlockCompile();
}
public function getPublicFilename() {
$filename = $this->hash.'.pdf';
if(file_exists($this->pathHash."/filename.txt")) {
$filename = file_get_contents($this->pathHash."/filename.txt");
$file = $this->getDecryptFile($this->pathHash."/filename.txt");
if(file_exists($file)) {
$filename = file_get_contents($file);
}
$filename = str_replace('.pdf', '_signe-'.count($this->getLayers()).'x.pdf', $filename);
@ -70,27 +139,36 @@ class PDFSignature
return $filename;
}
protected function getLayers() {
$files = scandir($this->pathHash);
protected function getLayers($pathHash = null) {
if(is_null($pathHash)) {
$pathHash = $this->pathHash;
}
$files = scandir($pathHash);
$layers = [];
foreach($files as $file) {
if(strpos($file, '.svg.pdf') !== false) {
$layers[] = $this->pathHash.'/'.$file;
$layers[] = $pathHash.'/'.$file;
}
}
return $layers;
}
public function addSignature(array $svgFiles, $outputPdfFile) {
public function addSignature(array $svgFiles) {
$expireFile = $this->pathHash.".expire";
touch($expireFile, date_format(date_modify(date_create(), file_get_contents($expireFile)), 'U'));
self::createPDFFromSvg($svgFiles, $outputPdfFile);
do {
if(isset($svgPDFFile)) { usleep(1); }
$svgPDFFile = $this->pathHash."/".(new DateTime())->format('YmdHisu').'.svg.pdf';
} while (file_exists($svgPDFFile));
if($this->gpg->isEncrypted()) {
self::createPDFFromSvg($svgFiles, $svgPDFFile);
if($this->isEncrypted()) {
$this->gpg->encrypt();
}
$this->toClean = array_merge($this->toClean, $svgFiles);
$this->compile();
}
public static function createPDFFromSvg(array $svgFiles, $outputPdfFile) {
@ -106,6 +184,9 @@ class PDFSignature
public function clean() {
foreach($this->toClean as $path) {
if(strpos($path, $this->pathHash) !== false) {
continue;
}
GPGCryptography::hardUnlink($path);
}
}