mirror of
https://github.com/screentinker/screentinker.git
synced 2026-08-13 13:53:12 -06:00
Merge pull request #243 from a10kiloham/screenshot-ack-and-proxy-docs
Toast the screenshot-request verdict; document proxy header pitfall
This commit is contained in:
commit
127a6265e0
22
README.md
22
README.md
|
|
@ -499,6 +499,28 @@ server {
|
|||
}
|
||||
```
|
||||
|
||||
#### Don't add security headers at the proxy
|
||||
|
||||
The app already sets `X-Frame-Options`, `Strict-Transport-Security`, `Content-Security-Policy`,
|
||||
`X-Content-Type-Options`, etc. via [helmet](https://helmetjs.github.io/), and manages them
|
||||
**per route**: widget/kiosk renders and the device preview deliberately remove or relax
|
||||
`X-Frame-Options` so they can be framed, while the dashboard keeps the strict policy.
|
||||
|
||||
A proxy-level header block (nginx `add_header X-Frame-Options DENY;`, a Caddy
|
||||
`header { ... }` snippet, or a "security headers" preset) *adds a second copy* of these
|
||||
headers on top of the app's. Browsers treat conflicting duplicate `X-Frame-Options`
|
||||
values as `deny`, which breaks the dashboard's device Preview (a same-origin iframe of
|
||||
`/player`) and widget previews with console errors like:
|
||||
|
||||
```
|
||||
Refused to display 'https://…' in a frame because it set multiple
|
||||
'X-Frame-Options' headers with conflicting values ('DENY, SAMEORIGIN').
|
||||
Falling back to 'deny'.
|
||||
```
|
||||
|
||||
Let the proxy handle TLS, compression, and body-size limits only, and leave security
|
||||
headers to the app.
|
||||
|
||||
### Updating
|
||||
|
||||
To update a running instance to the latest version:
|
||||
|
|
|
|||
|
|
@ -347,6 +347,9 @@ export default {
|
|||
'device.assign.select_first': 'Erst etwas auswählen',
|
||||
'device.assign.kiosk_widget_name': 'Kiosk: {name}',
|
||||
'device.toast.screenshot_requested': 'Screenshot angefordert',
|
||||
'device.toast.screenshot_unsupported': 'Der Player dieses Displays unterstützt keine Screenshots',
|
||||
'device.toast.screenshot_offline': 'Display ist offline — Screenshot nicht angefordert',
|
||||
'device.toast.screenshot_failed': 'Screenshot-Anfrage fehlgeschlagen — keine Antwort vom Server',
|
||||
'device.toast.renamed': 'Bildschirm umbenannt',
|
||||
'device.toast.removing': 'Wird entfernt...',
|
||||
'device.toast.removed': 'Bildschirm entfernt',
|
||||
|
|
|
|||
|
|
@ -648,6 +648,9 @@ export default {
|
|||
'device.assign.kiosk_widget_name': 'Kiosk: {name}',
|
||||
// Toasts
|
||||
'device.toast.screenshot_requested': 'Screenshot requested',
|
||||
'device.toast.screenshot_unsupported': 'This display\'s player can\'t take screenshots',
|
||||
'device.toast.screenshot_offline': 'Display is offline — screenshot not requested',
|
||||
'device.toast.screenshot_failed': 'Screenshot request failed — no response from server',
|
||||
'device.toast.renamed': 'Display renamed',
|
||||
'device.toast.removing': 'Removing...',
|
||||
'device.toast.removed': 'Display removed',
|
||||
|
|
|
|||
|
|
@ -377,6 +377,9 @@ export default {
|
|||
'device.assign.select_first': 'Primero selecciona algo',
|
||||
'device.assign.kiosk_widget_name': 'Kiosco: {name}',
|
||||
'device.toast.screenshot_requested': 'Captura solicitada',
|
||||
'device.toast.screenshot_unsupported': 'El reproductor de esta pantalla no admite capturas de pantalla',
|
||||
'device.toast.screenshot_offline': 'La pantalla está desconectada — captura no solicitada',
|
||||
'device.toast.screenshot_failed': 'La solicitud de captura falló — sin respuesta del servidor',
|
||||
'device.toast.renamed': 'Pantalla renombrada',
|
||||
'device.toast.removing': 'Eliminando...',
|
||||
'device.toast.removed': 'Pantalla eliminada',
|
||||
|
|
|
|||
|
|
@ -347,6 +347,9 @@ export default {
|
|||
'device.assign.select_first': 'Sélectionnez d\'abord un élément',
|
||||
'device.assign.kiosk_widget_name': 'Kiosque : {name}',
|
||||
'device.toast.screenshot_requested': 'Capture demandée',
|
||||
'device.toast.screenshot_unsupported': 'Le lecteur de cet écran ne prend pas en charge les captures d\'écran',
|
||||
'device.toast.screenshot_offline': 'Écran hors ligne — capture non demandée',
|
||||
'device.toast.screenshot_failed': 'Échec de la demande de capture — pas de réponse du serveur',
|
||||
'device.toast.renamed': 'Écran renommé',
|
||||
'device.toast.removing': 'Suppression...',
|
||||
'device.toast.removed': 'Écran retiré',
|
||||
|
|
|
|||
|
|
@ -371,6 +371,9 @@ export default {
|
|||
'device.assign.kiosk_widget_name': 'Chiosco: {name}',
|
||||
// Toasts
|
||||
'device.toast.screenshot_requested': 'Richiesta screenshot inviata',
|
||||
'device.toast.screenshot_unsupported': 'Il player di questo schermo non supporta gli screenshot',
|
||||
'device.toast.screenshot_offline': 'Lo schermo è offline — screenshot non richiesto',
|
||||
'device.toast.screenshot_failed': 'Richiesta screenshot non riuscita — nessuna risposta dal server',
|
||||
'device.toast.renamed': 'Schermo rinominato',
|
||||
'device.toast.removing': 'Rimozione in corso...',
|
||||
'device.toast.removed': 'Schermo rimosso',
|
||||
|
|
|
|||
|
|
@ -347,6 +347,9 @@ export default {
|
|||
'device.assign.select_first': 'Selecione algo primeiro',
|
||||
'device.assign.kiosk_widget_name': 'Quiosque: {name}',
|
||||
'device.toast.screenshot_requested': 'Captura solicitada',
|
||||
'device.toast.screenshot_unsupported': 'O player desta tela não suporta capturas de tela',
|
||||
'device.toast.screenshot_offline': 'A tela está offline — captura não solicitada',
|
||||
'device.toast.screenshot_failed': 'Falha na solicitação de captura — sem resposta do servidor',
|
||||
'device.toast.renamed': 'Tela renomeada',
|
||||
'device.toast.removing': 'Removendo...',
|
||||
'device.toast.removed': 'Tela removida',
|
||||
|
|
|
|||
|
|
@ -112,9 +112,22 @@ function emit(event, data) {
|
|||
if (cbs) cbs.forEach(cb => cb(data));
|
||||
}
|
||||
|
||||
export function requestScreenshot(deviceId) {
|
||||
// Optional callback receives the server-side ack: { delivered, reason, capability }.
|
||||
// reason is 'offline' (no live connection) or 'unsupported' (this player type can't
|
||||
// take screenshots). Callers without a callback keep firing-and-forgetting — the
|
||||
// dashboard grid and the device-detail 5s poll stay silent; only the explicit
|
||||
// Screenshot button asks for the verdict.
|
||||
export function requestScreenshot(deviceId, callback) {
|
||||
console.log('requestScreenshot:', deviceId, 'socket connected:', dashboardSocket?.connected);
|
||||
if (dashboardSocket) dashboardSocket.emit('dashboard:request-screenshot', { device_id: deviceId });
|
||||
if (!dashboardSocket) return;
|
||||
if (typeof callback === 'function') {
|
||||
dashboardSocket.timeout(5000).emit('dashboard:request-screenshot', { device_id: deviceId }, (err, ack) => {
|
||||
if (err) callback({ delivered: false, reason: 'no_ack' });
|
||||
else callback(ack || { delivered: false, reason: 'no_ack' });
|
||||
});
|
||||
} else {
|
||||
dashboardSocket.emit('dashboard:request-screenshot', { device_id: deviceId });
|
||||
}
|
||||
}
|
||||
|
||||
export function startRemote(deviceId) {
|
||||
|
|
|
|||
|
|
@ -1084,10 +1084,16 @@ function setupActions(device) {
|
|||
|
||||
document.getElementById('devicePreviewBtn')?.addEventListener('click', () => showDevicePreview(device));
|
||||
|
||||
// Screenshot button
|
||||
// Screenshot button — pass a callback so the server's verdict surfaces as a toast
|
||||
// instead of the request silently going nowhere (offline device, or a player type
|
||||
// that can't capture at all, e.g. BrightSign).
|
||||
document.getElementById('screenshotBtn')?.addEventListener('click', () => {
|
||||
requestScreenshot(device.id);
|
||||
showToast(t('device.toast.screenshot_requested'), 'info');
|
||||
requestScreenshot(device.id, (ack) => {
|
||||
if (ack?.delivered) showToast(t('device.toast.screenshot_requested'), 'info');
|
||||
else if (ack?.reason === 'unsupported') showToast(t('device.toast.screenshot_unsupported'), 'warning');
|
||||
else if (ack?.reason === 'offline') showToast(t('device.toast.screenshot_offline'), 'warning');
|
||||
else showToast(t('device.toast.screenshot_failed'), 'error');
|
||||
});
|
||||
});
|
||||
|
||||
// Rename
|
||||
|
|
|
|||
Loading…
Reference in a new issue