5

I have added voice to this chat, so it is now a combined voice/text chat. You can find my contribution up on github at the following URL:

https://github.com/HowardRichman/simple-text-voice-chat-in-node-and-javascript

Here is a working example of a secure websocket chat using a Node.js server and a jquery javascript client in Centos 6.9. There are only two files involved: (1) server.js and (2) client.htm.

Here is the code for server.js which I run using the following linux command line: node server.js

const fs = require('fs');
const https = require('https');
const WebSocket = require('ws');

const server = new https.createServer({
  cert: fs.readFileSync('/var/cpanel/ssl/apache_tls/example.com/combined'),
  key: fs.readFileSync('/var/cpanel/ssl/apache_tls/example.com/combined')
});
const wss = new WebSocket.Server({ server });
var msg;

wss.on('connection', function connection(ws) 
{
  ws.on('message', function incoming(message) 
  {
    msg = message;
    console.log('received: %s', msg);
    wss.clients.forEach(function (client) 
    {
       if (client.readyState == WebSocket.OPEN) 
       {
          client.send( msg );
       }
    });
  });

  ws.send('Chat room is working!');
});

server.listen(8089);

Notes:

  1. You must change the paths in the above to the paths to your secure certificate and key. I found these paths in my server's httpd.conf file.

  2. Optionally, you can change the port from 8089 in this and the client file to another available port. (Ports from 8081 to 8099 are usually available.)

Here's the code for client.htm file which should be accessed using an https URL (e.g., https://example.com/client.htm):

<!DOCTYPE html>
<html>
<head>
<TITLE>Chat Client</TITLE>
</head>
<body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
var webSocket;
var firstTime = true;

function connectWsChat()
{
  try 
  {
    window.WebSocket = window.WebSocket || window.MozWebSocket;
    var host = 'wss://example.com:8089/';
    webSocket = new WebSocket( host );
     webSocket.onopen = function() 
     {
      var chatUser = $( '#chatUser' ).val();
      webSocket.send( '<p>' + chatUser + ' has entered the chat room' );
       $( '#chatButton' ).text( 'Disconnect' );
     }
     webSocket.onmessage = function( msg ) 
     {
        logWsChatMessage( '<p class="message">' + msg.data + '</p>' );
     }
     webSocket.onclose = function() 
     {
      var chatUser = $( '#chatUser' ).val();
       logWsChatMessage( '<p>' + chatUser + ' has left the chat room</p>' );
       // $( '#chatButton' ).text( 'Connect' );
     }
   } 
   catch( exception ) 
   {
      logWsChatMessage( '<p>Error ' + exception + '.</p>' );
   }
}

function isConnectedWsChat() {
  if( webSocket && webSocket.readyState==1 ) {
    $( '#chatButton' ).text( 'Disconnect' );
    return 1;
  }
}

function playSound(){
    var audio = new Audio('notify.mp3');
    audio.play();   
}


function sendWsChat() {
  var chatLog = $( '#chatLog' );
  if( isConnectedWsChat() ) {
    var chatUser = $( '#chatUser' ).val();
    var chatText = $( '#chatText' ).val();
    if( chatUser=='' || chatText=='' ){
      return;
    }
    try{
      chatLog.scrollTop( chatLog.prop( 'scrollHeight' ) );
      webSocket.send( chatUser + ': ' + chatText );
      //logWsChatMessage( '<p class="event">Sent: ' + chatText + '</p>' )
    } catch( exception ){
      logWsChatMessage( '<p class="warning"> Error: ' + exception + '</p>' );
    }
    $( '#chatText' ).val( '' );
  }
}

function logWsChatMessage(msg) {
  var chatLog = $( '#chatLog' );
  var sTop = Math.round( chatLog.prop( 'scrollTop') );
  var sHeight = chatLog.prop( 'scrollHeight' );
  var cHeight = chatLog.prop( 'clientHeight' );

  chatLog.append( '<p>' + msg + '</p>' );

  if (firstTime) 
  {
    chatLog.scrollTop( chatLog.prop( 'scrollHeight' ) );
    firstTime = false;
  } 
  else if (sTop + cHeight == sHeight ) 
  {
    chatLog.scrollTop( chatLog.prop( 'scrollHeight' ) );
  }
  playSound();
}

$(document).ready( function() {

  if( !( 'WebSocket' in window ) ) {
    $( '#chatInput').fadeOut( 'fast' );
    $( '<p>Oh no, you need a browser that supports WebSockets.</p>' )
        .appendTo( '#chatContainer' );
  } else {
    connectWsChat();
  }

  $( '#chatText' ).keypress( function( event ) {
    if( event.keyCode == '13' ) {
      sendWsChat();
    }
  });

  $( '#startButton' ).click( function() {
     window.open('chat.pl','_self');
  });

  $( '#saveButton' ).click( function() {
     window.open('chat1.pl','_self');
  });


  $( '#chatButton' ).click( function() {
    if( webSocket && webSocket.readyState==1 ) {
      var chatUser = $( '#chatUser' ).val();
      webSocket.send( '<p>' + chatUser + ' has left the chat room.</p>' );
      webSocket.close();
      $( this ).text( 'Connect' );
    } else {
      //webSocket.open();
      connectWsChat();
      $( this ).text( 'Disconnect' );
    }
  });

  $( window ).on ("unload", function(e) {
    if( webSocket && webSocket.readyState==1 ) {
      var chatUser = $( '#chatUser' ).val();
      webSocket.send( '<p>' + chatUser + ' has left the chat room.</p>' );
      webSocket.close();
    }
  });

});
</script>
<div id="chatContainer">
<div id="chatLog">
</div>
<div id="chatInput">
<p>Name: <input id='chatUser' type="text" size=40 />
<br>Text: <input id="chatText" type="text" size=40 />
<br><button id="chatButton">Chat not yet set up</button>
</p>
</div>
</div>
</body>
</html>

Notes:

  1. Change example.com to the name of your website.

  2. I have only tested this code in Chrome and Firefox. In Firefox the user's name automatically appears in the name box when the user enters the chat if he or she has been in the chat room before. That doesn't happen in Chrome, but you could probably use a cookie to make sure that the name appears in Chrome.

  3. The user posts by clicking "Enter".

  4. The sound file notify.mp3 is a beep that plays whenever a new post arrives from the server. I have not included that file here.

  5. The commands regarding scroll and client height allow the user to scroll up to read earlier postings in a fast-moving chat without being forced to the bottom whenever new messages come in. My css file (not included) includes a max-height command for the chatLog division which may be necessary to get this to work Here's part of my css code: #chatLog {max-height: 430px; overflow-y: auto; width:100%}.

My Question:

Shortly before I got this chat working, I was working on a different solution and loaded mod_proxy_wstunnel.so in my Apache configuration file. I don't know whether that was necessary.

My question is: Can you get a secure websocket chat working if you don't have mod_proxy_wstunnel.so loaded?

Howard Richman
  • 51
  • 1
  • 1
  • 3
  • Welcome to Stack Overflow. Could you edit your post to provide a [minimal, complete, and verifiable example](https://stackoverflow.com/help/mcve)? – kepe Jan 06 '19 at 18:41
  • This program is based upon a nice "How to Create a Chat Application" by Peter Thoeny. He created a non-secure websocket using perl as his server. – Howard Richman Jan 07 '19 at 12:38
  • Here's Peter Thoeny [link](http://twiki.org/cgi-bin/view/Blog/BlogEntry201604x1). In order to make it secure, I replaced his perl server with a node.js server. The only changes that I *had* to make to his client were in the connection lines at the top of the javascript. – Howard Richman Jan 07 '19 at 12:44
  • My node.js server extends the External HTTP/S server posted by ipinca on GitHub: [link](https://github.com/websockets/ws). – Howard Richman Jan 08 '19 at 15:38
  • This script only seems to allow connections externally, tried using localhost as the host address and connecting to it from my local machine but does not connect. – Dion Nov 10 '21 at 16:32

0 Answers0