From ac8dba4ba094f20d484915f8de108321ce66f686 Mon Sep 17 00:00:00 2001 From: Vincent LAURENT Date: Wed, 2 Oct 2024 01:11:05 +0200 Subject: [PATCH] The signature works without the cache and therefore in incognito mode --- public/js/common.js | 146 +++++++++++++++++++++++++++++++++++ public/js/metadata.js | 104 +++++++------------------ public/js/signature.js | 134 ++++++-------------------------- templates/metadata.html.php | 1 + templates/signature.html.php | 1 + 5 files changed, 200 insertions(+), 186 deletions(-) create mode 100644 public/js/common.js diff --git a/public/js/common.js b/public/js/common.js new file mode 100644 index 0000000..5727a94 --- /dev/null +++ b/public/js/common.js @@ -0,0 +1,146 @@ +function is_mobile() { + return !(window.getComputedStyle(document.getElementById('is_mobile')).display === "none"); +}; + +async function canUseCache() { + try { + cache = await caches.open('pdf'); + return true; + } catch (e) { + return false; + } +}; + +async function loadFileFromCache(cacheUrl, pageUrl) { + if(!await canUseCache()) { + document.location = pageUrl; + return false; + } + const cache = await caches.open('pdf'); + let responsePdf = await cache.match(cacheUrl); + + if(!responsePdf) { + return; + } + + let filename = cacheUrl.replace('/pdf/', ''); + + let pdfBlob = await responsePdf.blob(); + + let dataTransfer = new DataTransfer(); + dataTransfer.items.add(new File([pdfBlob], filename, { + type: 'application/pdf' + })); + document.getElementById('input_pdf_upload').files = dataTransfer.files; +} + +async function storeFileInCache() { + let cache = await caches.open('pdf'); + let filename = document.getElementById('input_pdf_upload').files[0].name; + let response = new Response(document.getElementById('input_pdf_upload').files[0], { "status" : 200, "statusText" : "OK" }); + await cache.put('/pdf/'+filename, response); +} + +async function loadFileFromUrl(url, pageUrl, local = null) { + history.replaceState({}, '', pageUrl); + let response = await fetch(url); + if(response.status != 200) { + return; + } + let pdfBlob = await response.blob(); + let file_id = url.replace(/^.*\//, ''); + + if(response.headers.has('content-disposition') && response.headers.get('Content-Disposition').match(/attachment; filename="/)) { + file_id = response.headers.get('Content-Disposition').replace(/^[^"]*"/, "").replace(/"[^"]*$/, "").replace(/_signe-[0-9]+\x.pdf/, '.pdf'); + } + + if(pdfBlob.type != 'application/pdf' && pdfBlob.type != 'application/octet-stream') { + return; + } + let dataTransfer = new DataTransfer(); + if (local) { + file_id = local; + } + dataTransfer.items.add(new File([pdfBlob], file_id, { + type: 'application/pdf' + })); + document.getElementById('input_pdf_upload').files = dataTransfer.files; +} + +function storeSymmetricKeyCookie(hash, symmetricKey) { + if (symmetricKey.length != 15) { + console.error("Erreur taille cle symétrique."); + return; + } + document.cookie = hash + "=" + symmetricKey + "; SameSite=Lax; Path=/;"; +} + +function getSymmetricKey(hash) { + return getCookieValue(hash); +} + +function getCookieValue (name) { + return document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]+)')?.pop() || ''; +} + +function generateSymmetricKey() { + const length = 15; + const keySpace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + let key = ''; + + for (let i = 0; i < length; ++i) { + const randomIndex = Math.floor(Math.random() * keySpace.length); + key += keySpace.charAt(randomIndex); + } + + return key; +} + +function generatePdfHash() { + const length = 20; + const keySpace = '0123456789abcdefghijklmnopqrstuvwxyz'; + let key = ''; + + for (let i = 0; i < length; ++i) { + const randomIndex = Math.floor(Math.random() * keySpace.length); + key += keySpace.charAt(randomIndex); + } + + return key; +} + +function dataURLtoBlob(dataurl) { + let arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], + bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); + while(n--){ + u8arr[n] = bstr.charCodeAt(n); + } + return new Blob([u8arr], {type:mime}); +} + +function svgToDataUrl(svg) { + + return "data:image/svg+xml;base64," + btoa(svg); +} + +function trimSvgWhitespace(svgContent) { + if(!svgContent) { + + return null; + } + let svgContainer = document.createElement("div") + svgContainer.classList.add('invisible'); + svgContainer.classList.add('position-absolute'); + svgContainer.classList.add('top-0'); + svgContainer.classList.add('start-0'); + svgContainer.style = "z-index: -1;"; + svgContainer.innerHTML = svgContent; + document.body.appendChild(svgContainer); + let svg = svgContainer.querySelector('svg'); + let box = svg.getBBox(); + svg.setAttribute("viewBox", [box.x, box.y, box.width, box.height].join(" ")); + svgContent = svgContainer.innerHTML; + document.body.removeChild(svgContainer) + + return svgContent = svgContainer.innerHTML; +} diff --git a/public/js/metadata.js b/public/js/metadata.js index 1206919..7d165d6 100644 --- a/public/js/metadata.js +++ b/public/js/metadata.js @@ -208,102 +208,56 @@ function createEventsListener() { }) } -async function loadFileFromCache(cacheUrl) { - if(!await canUseCache()) { - document.location = '/metadata'; - return false; - } - const cache = await caches.open('pdf'); - let responsePdf = await cache.match(cacheUrl); - - if(!responsePdf) { - document.location = '/metadata'; - return false; - } - - let filename = cacheUrl.replace('/pdf/', ''); - - let pdfBlob = await responsePdf.blob(); - - let dataTransfer = new DataTransfer(); - dataTransfer.items.add(new File([pdfBlob], filename, { - type: 'application/pdf' - })); - document.getElementById('input_pdf_upload').files = dataTransfer.files; - document.getElementById('input_pdf_upload').dispatchEvent(new Event("change")); - - return true; -} - -async function storeFileInCache() { - if(!await canUseCache()) { - return; - } - let cache = await caches.open('pdf'); - let filename = document.getElementById('input_pdf_upload').files[0].name; - let response = new Response(document.getElementById('input_pdf_upload').files[0], { "status" : 200, "statusText" : "OK" }); - await cache.put('/pdf/'+filename, response); - history.pushState({}, '', '/metadata#'+filename); -} - -async function loadFileFromUrl(url, local = null) { - history.replaceState({}, '', '/metadata'); - var response = await fetch(url); - if(response.status != 200) { - return; - } - var pdfBlob = await response.blob(); - - if(pdfBlob.type != 'application/pdf' && pdfBlob.type != 'application/octet-stream') { - return; - } - let dataTransfer = new DataTransfer(); - let file_id = url.replace(/^.*\//, ''); - if (local) { - file_id = local; - } - dataTransfer.items.add(new File([pdfBlob], file_id, { - type: 'application/pdf' - })); - document.getElementById('input_pdf_upload').files = dataTransfer.files; - document.getElementById('input_pdf_upload').dispatchEvent(new Event("change")); -} - -var pageUpload = async function() { +async function pageUpload() { document.querySelector('body').classList.remove('bg-light'); document.getElementById('input_pdf_upload').value = ''; document.getElementById('page-upload').classList.remove('d-none'); document.getElementById('page-metadata').classList.add('d-none'); document.getElementById('input_pdf_upload').focus(); + window.addEventListener('hashchange', function() { + window.location.reload(); + }) document.getElementById('input_pdf_upload').addEventListener('change', async function(event) { - storeFileInCache(); - pageMetadata(); + if(await canUseCache()) { + storeFileInCache(); + history.pushState({}, '', '/metadata#'+document.getElementById('input_pdf_upload').files[0].name); + } + pageMetadata(null); }); } -var pageMetadata = async function() { - filename = document.getElementById('input_pdf_upload').files[0].name; - document.title = filename + ' - ' + document.title; +async function pageMetadata(url) { document.querySelector('body').classList.add('bg-light'); document.getElementById('page-upload').classList.add('d-none'); document.getElementById('page-metadata').classList.remove('d-none'); - menu = document.getElementById('sidebarTools'); - menuOffcanvas = new bootstrap.Offcanvas(menu); + if(url && url.match(/^cache:\/\//)) { + await loadFileFromCache(url.replace(/^cache:\/\//, '')); + } else if (url) { + await loadFileFromUrl(url); + } + + if(!document.getElementById('input_pdf_upload').files.length) { + alert("Chargement du PDF impossible"); + document.location = '/metadata'; + return; + } + responsiveDisplay(); createEventsListener(); - loadPDF(document.getElementById('input_pdf_upload').files[0], filename); + loadPDF(document.getElementById('input_pdf_upload').files[0]); }; (function () { - pageUpload(); if(window.location.hash && window.location.hash.match(/^\#http/)) { - loadFileFromUrl(window.location.hash.replace(/^\#/, '')); + pageMetadata(window.location.hash.replace(/^\#/, '')); } else if(window.location.hash && window.location.hash.match(/^\#local/)) { - let hashUrl = window.location.origin + "/api/file/get?path=" + window.location.hash.replace(/^\#local:/, ''); - loadFileFromUrl(hashUrl, window.location.hash.replace(/^\#/, '')); + pageMetadata(window.location.origin + "/api/file/get?path=" + window.location.hash.replace(/^\#local:/, ''), '/metadata', window.location.hash.replace(/^\#/, '')); } else if(window.location.hash) { - loadFileFromCache('/pdf/'+window.location.hash.replace(/^\#/, '')); + pageMetadata('cache:///pdf/'+window.location.hash.replace(/^\#/, '')); + } else { + pageUpload(); } + window.addEventListener('hashchange', function() { window.location.reload(); }) diff --git a/public/js/signature.js b/public/js/signature.js index e31e32a..5481414 100644 --- a/public/js/signature.js +++ b/public/js/signature.js @@ -966,27 +966,7 @@ async function getPDFBlobFromCache(cacheUrl) { return pdfBlob; } -async function uploadFromUrl(url) { - history.replaceState({}, '', '/signature'); - let response = await fetch(url); - if(response.status != 200) { - return; - } - let pdfBlob = await response.blob(); - - if(pdfBlob.type != 'application/pdf' && pdfBlob.type != 'application/octet-stream') { - return; - } - let dataTransfer = new DataTransfer(); - let filename = url.replace(/^.*\//, ''); - dataTransfer.items.add(new File([pdfBlob], filename, { - type: 'application/pdf' - })); - document.getElementById('input_pdf_upload').files = dataTransfer.files; - document.getElementById('input_pdf_upload').dispatchEvent(new Event("change")); -} - -var modalSharing = function() { +function modalSharing() { if(openModal == "shareinformations") { let modalInformationsEl = document.getElementById('modal-share-informations'); let modalInformations = bootstrap.Modal.getOrCreateInstance(modalInformationsEl); @@ -1012,27 +992,12 @@ async function pageUpload() { document.getElementById('page-upload').classList.remove('d-none'); document.getElementById('page-signature').classList.add('d-none'); document.getElementById('input_pdf_upload').focus(); - let cache; - try { - cache = await caches.open('pdf'); - } catch (e) { - console.error(e) - alert("Erreur d'accès au cache. Cette application ne fonctionne pas en mode de navigation privée"); - return; - } document.getElementById('input_pdf_upload').addEventListener('change', async function(event) { - if(document.getElementById('input_pdf_upload').files[0].size > maxSize) { - - alert("Le PDF ne doit pas dépasser " + Math.round(maxSize/1024/1024) + " Mo");s - document.getElementById('input_pdf_upload').value = ""; - return; + if(await canUseCache()) { + storeFileInCache(); + history.pushState({}, '', '/signature#'+document.getElementById('input_pdf_upload').files[0].name); } - let filename = document.getElementById('input_pdf_upload').files[0].name; - let response = new Response(document.getElementById('input_pdf_upload').files[0], { "status" : 200, "statusText" : "OK" }); - let urlPdf = '/pdf/'+filename; - await cache.put(urlPdf, response); - history.pushState({}, '', '/signature#'+filename); - pageSignature(urlPdf) + pageSignature(null); }); } @@ -1082,27 +1047,22 @@ async function pageSignature(url) { fontCaveat = font; }); - let pdfBlob = null; - let filename = url.replace('/pdf/', ''); + if(url && url.match(/^cache:\/\//)) { + await loadFileFromCache(url.replace(/^cache:\/\//, '')); + } else if (url) { + await loadFileFromUrl(url); + } - if(pdfHash) { - let response = await fetch(url); - if(response.status != 200) { - document.location = url; - return; - } - pdfBlob = await response.blob(); - if(response.headers.get('Content-Disposition').match(/attachment; filename="/)) { - filename = response.headers.get('Content-Disposition').replace(/^[^"]*"/, "").replace(/"[^"]*$/, "").replace(/_signe-[0-9]+\x.pdf/, '.pdf'); - } - } else { - pdfBlob = await getPDFBlobFromCache(url); + if(!document.getElementById('input_pdf_upload').files.length) { + alert("Chargement du PDF impossible"); + document.location = '/signature'; + return; } - document.title = filename + ' - ' + document.title; + if(document.getElementById('input_pdf_upload').files[0].size > maxSize) { - if(!pdfBlob) { - document.location = '/signature'; + alert("Le PDF ne doit pas dépasser " + Math.round(maxSize/1024/1024) + " Mo"); + document.getElementById('input_pdf_upload').value = ""; return; } @@ -1111,13 +1071,14 @@ async function pageSignature(url) { displaysSVG(); stateAddLock(); createEventsListener(); - loadPDF(pdfBlob, filename); + loadPDF(document.getElementById('input_pdf_upload').files[0]); }; (function () { if(sharingMode) { setTimeout(function() { runCron() }, 2000); } + if(pdfHash) { if (window.location.hash && window.location.hash.match(/^\#/)) { storeSymmetricKeyCookie(pdfHash, window.location.hash.replace(/^#/, '')); @@ -1125,64 +1086,15 @@ async function pageSignature(url) { window.location.hash = getSymmetricKey(pdfHash); } pageSignature('/signature/'+pdfHash+'/pdf'); - window.addEventListener('hashchange', function() { - window.location.reload(); - }) - return; - } - - if(window.location.hash && window.location.hash.match(/^\#http/)) { - let hashUrl = window.location.hash.replace(/^\#/, ''); - pageUpload(); - uploadFromUrl(hashUrl); + } else if(window.location.hash && window.location.hash.match(/^\#http/)) { + pageSignature(window.location.hash.replace(/^\#/, '')); } else if(window.location.hash) { - pageSignature('/pdf/'+window.location.hash.replace(/^\#/, '')); + pageSignature('cache:///pdf/'+window.location.hash.replace(/^\#/, '')); } else { pageUpload(); } + window.addEventListener('hashchange', function() { window.location.reload(); }) })(); - -function storeSymmetricKeyCookie(hash, symmetricKey) { - if (symmetricKey.length != 15) { - console.error("Erreur taille cle symétrique."); - return; - } - document.cookie = hash + "=" + symmetricKey + "; SameSite=Lax; Path=/;"; -} - -function getSymmetricKey(hash) { - return getCookieValue(hash); -} - -function getCookieValue (name) { - return document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]+)')?.pop() || ''; -} - -function generateSymmetricKey() { - const length = 15; - const keySpace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; - let key = ''; - - for (let i = 0; i < length; ++i) { - const randomIndex = Math.floor(Math.random() * keySpace.length); - key += keySpace.charAt(randomIndex); - } - - return key; -} - -function generatePdfHash() { - const length = 20; - const keySpace = '0123456789abcdefghijklmnopqrstuvwxyz'; - let key = ''; - - for (let i = 0; i < length; ++i) { - const randomIndex = Math.floor(Math.random() * keySpace.length); - key += keySpace.charAt(randomIndex); - } - - return key; -} diff --git a/templates/metadata.html.php b/templates/metadata.html.php index 2983651..24ed82d 100644 --- a/templates/metadata.html.php +++ b/templates/metadata.html.php @@ -95,6 +95,7 @@ + diff --git a/templates/signature.html.php b/templates/signature.html.php index 9a06bb3..83a6323 100644 --- a/templates/signature.html.php +++ b/templates/signature.html.php @@ -297,6 +297,7 @@ url_font = +