diff --git a/frontend/src/app.js b/frontend/src/app.js
index 3f6bad9..97a5af9 100644
--- a/frontend/src/app.js
+++ b/frontend/src/app.js
@@ -115,7 +115,7 @@ app.get( '/clientDisplayNotifier', ( req, res ) => {
app.get( '/mainNotifier', ( req, res ) => {
const ipRetrieved = req.headers[ 'x-forwarded-for' ];
const ip = ipRetrieved ? ipRetrieved.split( /, / )[ 0 ] : req.connection.remoteAddress;
- if ( ip === '::ffff:127.0.0.1' ) {
+ if ( ip === '::ffff:127.0.0.1' || ip === '::1' ) {
res.writeHead( 200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
@@ -123,7 +123,7 @@ app.get( '/mainNotifier', ( req, res ) => {
} );
res.status( 200 );
res.flushHeaders();
- let det = { 'type': 'basics', 'data': connectedClients };
+ let det = { 'type': 'basics' };
res.write( `data: ${ JSON.stringify( det ) }\n\n` );
connectedMain = res;
} else {
@@ -199,22 +199,23 @@ app.post( '/statusUpdate', ( req, res ) => {
} );
// STATUS UPDATE from the client display to send to main ui
-const allowedMainUpdates = [ 'disconnect', 'fullScreenStatus', 'visibility' ];
-app.get( '/clientStatusUpdate/:status', ( req, res ) => {
- if ( allowedTypes.includes( req.body.type ) ) {
+// Send update if page is closed
+const allowedMainUpdates = [ 'blur', 'visibility' ];
+app.post( '/clientStatusUpdate', ( req, res ) => {
+ if ( allowedMainUpdates.includes( req.body.type ) ) {
const ipRetrieved = req.headers[ 'x-forwarded-for' ];
const ip = ipRetrieved ? ipRetrieved.split( /, / )[ 0 ] : req.connection.remoteAddress;
- sendClientUpdate( req.body.type, req.body.data, ip );
+ sendClientUpdate( req.body.type, ip );
res.send( 'ok' );
} else {
res.status( 400 ).send( 'ERR_UNKNOWN_TYPE' );
}
} );
-const sendClientUpdate = ( update, data, ip ) => {
- for ( let main in connectedMain ) {
- connectedMain[ main ].write( 'data: ' + JSON.stringify( { 'type': update, 'ip': ip, 'data': data } ) + '\n\n' );
- }
+const sendClientUpdate = ( update, ip ) => {
+ try {
+ connectedMain.write( 'data: ' + JSON.stringify( { 'type': update, 'ip': ip } ) + '\n\n' );
+ } catch ( err ) {}
}
app.get( '/indexDirs', ( req, res ) => {
diff --git a/frontend/src/client/appleMusic/index.html b/frontend/src/client/appleMusic/index.html
index 6f35934..32f69cb 100644
--- a/frontend/src/client/appleMusic/index.html
+++ b/frontend/src/client/appleMusic/index.html
@@ -11,6 +11,14 @@
+
+
WARNING!
+
A client display is being tampered with!
+
A desktop notification with a warning has already been dispatched.
+
+
+
+
autorenew
Loading player...
diff --git a/frontend/src/client/appleMusic/index.js b/frontend/src/client/appleMusic/index.js
index 5a4a549..5cbeeb1 100644
--- a/frontend/src/client/appleMusic/index.js
+++ b/frontend/src/client/appleMusic/index.js
@@ -38,6 +38,7 @@ const app = Vue.createApp( {
isPreparingToPlay: false,
additionalSongInfo: {},
hasFinishedInit: false,
+ isShowingWarning: false,
// For use with playlists that are partially from apple music and
// local drive
@@ -290,7 +291,9 @@ const app = Vue.createApp( {
} );
} );
}
- this.audioPlayer.pause();
+ try {
+ this.audioPlayer.pause();
+ } catch ( err ) {}
} else {
this.audioPlayer.play();
this.musicKit.pause();
@@ -619,6 +622,43 @@ const app = Vue.createApp( {
const result = await this.musicKit.api.music( '/v1/catalog/ch/search', queryParameters );
console.log( result );
} )();
+ },
+ connectToNotifier() {
+ let source = new EventSource( '/mainNotifier', { withCredentials: true } );
+ source.onmessage = ( e ) => {
+ let data;
+ try {
+ data = JSON.parse( e.data );
+ } catch ( err ) {
+ data = { 'type': e.data };
+ }
+ if ( data.type === 'blur' ) {
+ this.isShowingWarning = true;
+ } else if ( data.type === 'visibility' ) {
+ this.isShowingWarning = true;
+ }
+ };
+
+ source.onopen = () => {
+ console.log( 'client notifier connected successfully' );
+ };
+
+ let self = this;
+
+ source.addEventListener( 'error', function( e ) {
+ if ( e.eventPhase == EventSource.CLOSED ) source.close();
+
+ if ( e.target.readyState == EventSource.CLOSED ) {
+ console.log( 'disconnected' );
+ }
+
+ setTimeout( () => {
+ self.connectToNotifier();
+ }, 1000 );
+ }, false );
+ },
+ dismissNotification() {
+ this.isShowingWarning = false;
}
},
watch: {
@@ -653,6 +693,7 @@ const app = Vue.createApp( {
} else {
this.initMusicKit();
}
+ this.connectToNotifier();
fetch( '/getLocalIP' ).then( res => {
if ( res.status === 200 ) {
res.text().then( ip => {
diff --git a/frontend/src/client/appleMusic/style.css b/frontend/src/client/appleMusic/style.css
index c2b7aa3..097e646 100644
--- a/frontend/src/client/appleMusic/style.css
+++ b/frontend/src/client/appleMusic/style.css
@@ -312,4 +312,48 @@ body, html {
.slider-inactive {
cursor: default !important;
+}
+
+
+.warning {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 40vw;
+ height: 50vh;
+ font-size: 2vh;
+ background-color: rgb(255, 0, 0);
+ color: white;
+ position: fixed;
+ right: 1vh;
+ top: 1vh;
+ flex-direction: column;
+ z-index: 100;
+}
+
+.warning h3 {
+ font-size: 4vh;
+}
+
+.warning .flash {
+ background-color: rgba(255, 0, 0, 0.4);
+ animation: flashing linear infinite 1s;
+ width: 100vw;
+ height: 100vh;
+ top: 0;
+ left: 0;
+ position: fixed;
+ z-index: -1;
+}
+
+@keyframes flashing {
+ 0% {
+ opacity: 0;
+ }
+ 50% {
+ opacity: 1;
+ }
+ 100% {
+ opacity: 0;
+ }
}
\ No newline at end of file
diff --git a/frontend/src/client/showcase.js b/frontend/src/client/showcase.js
index 5058967..64cde9b 100644
--- a/frontend/src/client/showcase.js
+++ b/frontend/src/client/showcase.js
@@ -17,6 +17,7 @@ createApp( {
micAnalyzer: null,
beatDetected: false,
colorThief: null,
+ lastDispatch: new Date().getTime() - 5000,
};
},
computed: {
@@ -290,23 +291,41 @@ createApp( {
return flux;
},
notifier() {
- console.log( 'notifier enabled' );
+ if ( parseInt( this.lastDispatch ) + 5000 < new Date().getTime() ) {
+
+ }
+ Notification.requestPermission();
+
+ console.warn( '[ notifier ]: Status is now enabled \n\n-> Any leaving or tampering with the website will send a notification to the host' );
// Detect if window is currently in focus
window.onblur = () => {
- console.log( 'left browser or page' );
+ this.sendNotification( 'blur' );
}
- // Detect key events
- window.addEventListener( 'keypress', keyEvent => {
- console.log( keyEvent.key );
+ // Detect if browser window becomes hidden (also with blur event)
+ document.onvisibilitychange = () => {
+ if ( document.visibilityState === 'hidden' ) {
+ this.sendNotification( 'visibility' );
+ }
+ };
+ },
+ sendNotification( notification ) {
+ let fetchOptions = {
+ method: 'post',
+ body: JSON.stringify( { 'type': notification } ),
+ headers: {
+ 'Content-Type': 'application/json',
+ 'charset': 'utf-8'
+ },
+ };
+ fetch( '/clientStatusUpdate', fetchOptions ).catch( err => {
+ console.error( err );
} );
- // Detect if browser window becomes hidden (also with blur event)
- document.addEventListener( 'visibilitychange', visibilityEvent => {
- if ( document.visibilityState === 'hidden' ) {
- console.log( 'left page' );
- }
- } );
+ new Notification( 'YOU ARE UNDER SURVEILLANCE', {
+ body: 'Please return to the original webpage immediately!',
+ requireInteraction: true,
+ } )
}
},
mounted() {