diff --git a/docker/nginx/development.conf b/docker/nginx/development.conf index c5aef38..aa7bd8b 100644 --- a/docker/nginx/development.conf +++ b/docker/nginx/development.conf @@ -18,6 +18,9 @@ server { location /ca.crt { alias /etc/ssl/certs/snapdropCA.crt; } + + # To allow POST on static pages + error_page 405 =200 $uri; } server { @@ -42,5 +45,7 @@ server { location /ca.crt { alias /etc/ssl/certs/snapdropCA.crt; } + # To allow POST on static pages + error_page 405 =200 $uri; } diff --git a/docker/nginx/production.conf b/docker/nginx/production.conf index c0eedde..7a3d722 100644 --- a/docker/nginx/production.conf +++ b/docker/nginx/production.conf @@ -10,6 +10,8 @@ server { location /ca.crt { alias /etc/ssl/certs/snapdropCA.crt; } + # To allow POST on static pages + error_page 405 =200 $uri; } server { @@ -34,5 +36,7 @@ server { location /ca.crt { alias /etc/ssl/certs/snapdropCA.crt; } + # To allow POST on static pages + error_page 405 =200 $uri; } diff --git a/public/manifest.json b/public/manifest.json index 71f8164..768ac0c 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -2,27 +2,27 @@ "name": "PairDrop", "short_name": "PairDrop", "icons": [{ - "src": "images/android-chrome-192x192.png", - "sizes": "192x192", - "type": "image/png" - },{ - "src": "images/android-chrome-512x512.png", - "sizes": "512x512", - "type": "image/png" - },{ - "src": "images/android-chrome-192x192-maskable.png", - "sizes": "192x192", - "type": "image/png", - "purpose": "maskable" - },{ - "src": "images/android-chrome-512x512-maskable.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "maskable" - },{ - "src": "images/favicon-96x96.png", - "sizes": "96x96", - "type": "image/png" + "src": "images/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + },{ + "src": "images/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + },{ + "src": "images/android-chrome-192x192-maskable.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + },{ + "src": "images/android-chrome-512x512-maskable.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + },{ + "src": "images/favicon-96x96.png", + "sizes": "96x96", + "type": "image/png" }], "background_color": "#efefef", "start_url": "/", @@ -30,12 +30,18 @@ "display": "minimal-ui", "theme_color": "#3367d6", "share_target": { - "method":"GET", - "action": "/?share_target", + "action": "/", + "method":"POST", + "enctype": "multipart/form-data", "params": { "title": "title", "text": "text", - "url": "url" + "url": "url", + "files": [{ + "name": "allfiles", + "accept": ["*/*"] + }] + } } }, "file_handlers": [ diff --git a/public/scripts/ui.js b/public/scripts/ui.js index eb037a4..8b565e8 100644 --- a/public/scripts/ui.js +++ b/public/scripts/ui.js @@ -931,7 +931,6 @@ class SendTextDialog extends Dialog { _onRecipient(recipient) { this._recipient = recipient; - this._handleShareTargetText(); this.show(); const range = document.createRange(); @@ -943,12 +942,6 @@ class SendTextDialog extends Dialog { sel.addRange(range); } - _handleShareTargetText() { - if (!window.shareTargetText) return; - this.$text.textContent = window.shareTargetText; - window.shareTargetText = ''; - } - _send() { Events.fire('send-text', { to: this._recipient, @@ -1135,20 +1128,34 @@ class NetworkStatusUI { class WebShareTargetUI { constructor() { - const parsedUrl = new URL(window.location); - const title = parsedUrl.searchParams.get('title'); - const text = parsedUrl.searchParams.get('text'); - const url = parsedUrl.searchParams.get('url'); + const urlParams = new URL(window.location).searchParams; + const share_target_type = urlParams.get("share-target") + if (share_target_type) { + if (share_target_type === "text") { + const title = urlParams.get('title') || ''; + const text = urlParams.get('text') || ''; + const url = urlParams.get('url') || ''; + let shareTargetText; - let shareTargetText = title ? title : ''; - shareTargetText += text ? shareTargetText ? ' ' + text : text : ''; + if (url) { + shareTargetText = url; // We share only the Link - no text. Because link-only text becomes clickable. + } else if (title && text) { + shareTargetText = title + '\r\n' + text; + } else { + shareTargetText = title + text; + } - if(url) shareTargetText = url; // We share only the Link - no text. Because link-only text becomes clickable. - - if (!shareTargetText) return; - window.shareTargetText = shareTargetText; - history.pushState({}, 'URL Rewrite', '/'); - console.log('Shared Target Text:', '"' + shareTargetText + '"'); + console.log('Shared Target Text:', '"' + shareTargetText + '"'); + Events.fire('activate-paste-mode', {files: [], text: shareTargetText}) + } else if (share_target_type === "files") { + caches.match("share_target_files") + .then(files => { + console.debug(files) + Events.fire('activate-paste-mode', {files: files, text: ""}) + }) + } + history.pushState({}, 'URL Rewrite', '/'); + } } } diff --git a/public/service-worker.js b/public/service-worker.js index 17dc7ac..3a21c71 100644 --- a/public/service-worker.js +++ b/public/service-worker.js @@ -27,17 +27,48 @@ self.addEventListener('install', function(event) { self.addEventListener('fetch', function(event) { - event.respondWith( - caches.match(event.request) - .then(function(response) { - // Cache hit - return response - if (response) { - return response; - } - return fetch(event.request); - } - ) - ); + if (event.request.method === "POST") { + // Requests related to Web Share Target. + event.respondWith( + (async () => { + const formData = await event.request.formData(); + const title = formData.get("title"); + const text = formData.get("text"); + const url = formData.get("url"); + const files = formData.get("files"); + console.debug(title) + console.debug(text) + console.debug(url) + console.debug(files) + let share_url = "/"; + if (files.length > 0) { + // Save to Cache? + caches.open("share_target_files") + .then(cache => { + cache.addAll(files) + console.debug("files added to cache") + }); + share_url = "/?share-target=files"; + } else if (title.length > 0 || text.length > 0 || url.length) { + share_url = `/?share-target=text&title=${title}&text=${text}&url=${url}`; + } + return Response.redirect(encodeURI(share_url), 303); + })() + ); + } else { + // Regular requests not related to Web Share Target. + event.respondWith( + caches.match(event.request) + .then(function (response) { + // Cache hit - return response + if (response) { + return response; + } + return fetch(event.request); + } + ) + ); + } });