PHP Classes
elePHPant
Icontem

File: js/cchat.js

Recommend this page to a friend!
  Classes of Martin Latter  >  PHP Secure Chat  >  js/cchat.js  >  Download  
File: js/cchat.js
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: PHP Secure Chat
Chat box between users using encrypted messages
Author: By
Last change: change form text to placeholders
Date: 2 years ago
Size: 11,629 bytes
 

 

Contents

Class file image Download
var Chatbox = {

	/**
		* Crypto Chatbox.
		*
		* @author            Martin Latter <copysense.co.uk>
		* @copyright         Martin Latter, 2010 (original), 2013 (encrypted)
		* @version           2.04
		* @license           GNU GPL version 3.0 (GPL v3); http://www.gnu.org/licenses/gpl.html
		* @link              https://github.com/Tinram/cchat.git
	*/


	/* CONFIGURATION */

	iCheckFreq: 6000, // 6-second checks
	sFilePath: "includes/",
	sCheckFile: "check.php",
	sUpdateFile: "update.php",
	sErrorBackground: "#ffcc66",
	sDefaultBackground: "background:linear-gradient(to bottom, #fff, #f0f8ff 100%);",
	bDebug: false,

	/* END CONFIGURATION */


	sBR: "<br>",
	reLB: /\~/g, // line break symbol used
	iDbGID: 0,
	bSubmit: true, // multiple submission block


	/**
		* Setup event handlers.
	*/

	loader: function() {

		document.getElementById("message").onclick = function() {

			Chatbox.charCounter();
		};

		document.getElementById("chatsubmit").onclick = function() {

			if (Chatbox.checkBlankSubmission()) { // if fn returns true, proceed with submission

				if (Chatbox.bSubmit) {

					Chatbox.bSubmit = false;
					Chatbox.checkUpdates(Chatbox.createUpdateObj(), "chatbox");
				}
			}
		};

		document.getElementById("message").onkeydown = Chatbox.charCounter;
		document.getElementById("message").onkeyup = Chatbox.charCounter;
		document.getElementById("decrypt").onclick = Chatbox.checkPass;
		Chatbox.scrollDown();
		Chatbox.charCounter(); // harmonise message box on page refresh if chars already added
		Chatbox.checkUpdates(); // initial AJAX check with id=0
		window.setInterval(Chatbox.checkUpdates, Chatbox.iCheckFreq); // incremental checks
	},


	/**
		* Chatbox field scroll handler.
	*/

	scrollDown: function() {

		var oCB = document.getElementById("chatbox");
		oCB.scrollTop = oCB.scrollHeight; // fix for lost position
	},


	/**
		* Check user input.
		*
		* @return   boolean
	*/

	checkBlankSubmission: function() {

		var 
			oName = document.getElementById("name"),
			oPassword = document.getElementById("pw"),
			oMessage = document.getElementById("message"),
			oError = document.getElementById("error");

		oName.style.cssText = this.sDefaultBackground;
		oPassword.style.cssText = this.sDefaultBackground;
		oMessage.style.cssText = this.sDefaultBackground;

		if (oName.value === "" || oName.value === "name") {

			oError.innerHTML = "Please enter your name.";
			oName.style.background = this.sErrorBackground;
			oName.select();
			oName.focus();
			return false;
		}
		else if (oPassword.value === "") {

			oError.innerHTML = "Please enter your password.";
			oPassword.style.background = this.sErrorBackground;
			oPassword.select();
			oPassword.focus();
			return false;
		}
		else if (oMessage.value === "" || oMessage.value === "message") {

			document.getElementById("error").innerHTML = "Please enter a message.";
			oMessage.style.background = this.sErrorBackground;
			oMessage.select();
			oMessage.focus();
			return false;
		}
		else {

			oError.innerHTML = "";
			return true;
		}
	},


	/**
		* Report and constrain character limit in message field.
	*/

	charCounter: function() {

		var 
			iMaxLimit = 255,
			oField = document.getElementById("message"),
			oCounter = document.getElementById("remchar");

		if (oField.value.length > iMaxLimit) {

			oField.value = oField.value.substring(0, iMaxLimit);
		}
		else {

			oCounter.innerHTML = iMaxLimit - oField.value.length;
		}
	},


	/**
		* Filter certain characters, hash password, and encrypt message.
		*
		* @return   object
	*/

	createUpdateObj: function() {

		var 
			sFileName = Chatbox.sFilePath + Chatbox.sUpdateFile,
			sName = document.getElementById("name").value,
			sPassword = document.getElementById("pw").value,
			sMessage = document.getElementById("message").value;

		sMessage = sMessage.replace(//g, "GBP-");
		sMessage = sMessage.replace(/\r\n/g, "~");
		sMessage = sMessage.replace(/\n/g, "~");
		sMessage = Bf.e(SHA256(sPassword), sMessage);
		sMessage = encodeURIComponent(sMessage); // do not remove = base64 character corruption

		return {file: sFileName, name: sName, message: sMessage};
	},


	/**
		* Check password field.
	*/

	checkPass: function() {

		var
			oPassword = document.getElementById("pw"),
			oError = document.getElementById("error"),
			oCont = {},
			oMessages = {},
			i = -1,
			n = 0,
			sTemp = "";

		if (oPassword .value === "") {

			oError.innerHTML = "Please enter your password.";
			oPassword.style.background = Chatbox.sErrorBackground;
			oPassword.select();
			oPassword.focus();
			return;
		}
		else {

			oPassword.style.background = "0"; // resets of any above errors
			oError.innerHTML = "";
			oError.style.background = "#fff";
			oCont = document.getElementById("chatbox");
			oMessages = oCont.getElementsByClassName("m");
			n = oMessages.length;

			for (; ++i < n;) {

				sTemp = Bf.d(SHA256(oPassword.value), oMessages[i].innerHTML);
				sTemp = sTemp.replace(Chatbox.reLB, Chatbox.sBR);
				oMessages[i].innerHTML = sTemp;
			}
		}
	},


	/**
		* Check for new messages on the server using POST AJAX.
		*
		* @param    object oPostData
		* @param    string sDiv
	*/

	checkUpdates: function(oPostData, sDiv) {

		var
			sParams = "",
			sFileName = "",
			sUrl = "",
			sCb = "",
			sDMessage = "",
			sBRprefix = ": <br>",
			iRemGlobalID = 0,
			iResponseLen = 0,
			i = -1,
			oXmlHttp = {},
			oResponse = {},
			oCb = {},
			oMessage = {};

		if (sDiv === undefined) {

			sFileName = Chatbox.sFilePath + Chatbox.sCheckFile;
			iRemGlobalID = Chatbox.iDbGID;
			sUrl = sFileName;
			sParams = "id=" + Chatbox.iDbGID;
		}
		else {

			sFileName = oPostData.file;
			sParams = "id=" + Chatbox.iDbGID + "&n=" + oPostData.name + "&m=" + oPostData.message; 
		}

		oXmlHttp = createXHR();
		oXmlHttp.open("POST", sFileName, true);
		oXmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

		oXmlHttp.onreadystatechange = function() {

			if (oXmlHttp.readyState === 4 || oXmlHttp.readyState === "complete") {

				if (oXmlHttp.status === 200 || oXmlHttp.status === 304) {

					oResponse = JSON.parse(oXmlHttp.responseText);
						// old browsers: oResponse = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(oXmlHttp.responseText.replace(/"(\\.|[^"\\])*"/g, ""))) && eval("(" + oXmlHttp.responseText + ")"); // RFC JSON cleanup

					if (sDiv === undefined) {

						iResponseLen = oResponse.length;
						oCb = document.getElementById("chatbox");
						Chatbox.iDbGID = parseInt(oResponse[iResponseLen - 1].id, 10);

						if (Chatbox.iDbGID > iRemGlobalID) {

							for (; ++i < iResponseLen;) { // -1 will not work here for multiple submissions
	
								if (document.getElementById("pw").value === "") {

									oCb.innerHTML += oResponse[i].n + ": " + oResponse[i].m + Chatbox.sBR;
									Chatbox.scrollDown();
								}
								else {

									sDMessage = Bf.d(SHA256(document.getElementById("pw").value), oResponse[i].m);
									sDMessage = sDMessage.replace(Chatbox.reLB, Chatbox.sBR);
									oCb.innerHTML += oResponse[i].n + ": " + sDMessage + Chatbox.sBR; // responsible for intermittent duplicate message bug
									Chatbox.scrollDown();
								}

								sCb = oCb.innerHTML;

								if (sCb.lastIndexOf(sBRprefix) > - 1) {

									sCb = sCb.slice(0, sCb.length - 6); // remove colon when no results returned
									oCb.innerHTML = sCb;
								}
							}

							Chatbox.scrollDown();
						}
					}
					else {

						oMessage = document.getElementById("message");
						sDMessage = Bf.d(SHA256(document.getElementById("pw").value), oResponse.m);
						sDMessage = sDMessage.replace(Chatbox.reLB, Chatbox.sBR);
						document.getElementById(sDiv).innerHTML += oResponse.n + ": " + sDMessage + Chatbox.sBR;
						oMessage.value = "";
						oMessage.focus();
						Chatbox.iDbGID = parseInt(oResponse.id, 10);
						Chatbox.scrollDown();
						Chatbox.charCounter();
					}
				}
				else {

					if (Chatbox.bDebug) {

						alert("An error occurred: " + oXmlHttp.statusText);
					}
				}
			}

			Chatbox.bSubmit = true;
		};

		oXmlHttp.send(sParams);


		function createXHR() {

			if (XMLHttpRequest !== undefined) {

				return new XMLHttpRequest();
			}
			else if (window.ActiveXObject) {

				try {

					var oXMLHttp = new ActiveXObject("MSXML2.XMLHttp"); 
					return oXMLHttp;
				}
				catch (xhrError) {

					alert("AJAX functionality is not supported (or trusted ActiveX has been disabled) in this version of IE.");
					return false;
				}
			}
			else {

				return false;
			}
		}

	}
};


/* SHA-256 hash implementation by Angel Marin and Paul Johnston, */
function SHA256(s){
var chrsz=8,hexcase=0;function sa(x,y){var lsw=(x&0xFFFF)+(y&0xFFFF),msw=(x>>16)+(y>>16)+(lsw>>16);return(msw<<16)|(lsw&0xFFFF);}function S(X,n){return(X>>>n)|(X<<(32-n));}function R(X,n){return(X>>>n);}function Ch(x,y,z){return((x&y)^((~x)&z));}function Maj(x,y,z){return((x&y)^(x&z)^(y&z));}function S0256(x){return(S(x,2)^S(x,13)^S(x,22));}function S1256(x){return(S(x,6)^S(x,11)^S(x,25));}function G0256(x){return(S(x,7)^S(x,18)^R(x,3));}function G1256(x){return(S(x,17)^S(x,19)^R(x,10));}function cs256(m,l){var a,b,c,d,e,f,g,h,i,j,ml,T1,T2,K=[0x428A2F98,0x71374491,0xB5C0FBCF,0xE9B5DBA5,0x3956C25B,0x59F111F1,0x923F82A4,0xAB1C5ED5,0xD807AA98,0x12835B01,0x243185BE,0x550C7DC3,0x72BE5D74,0x80DEB1FE,0x9BDC06A7,0xC19BF174,0xE49B69C1,0xEFBE4786,0xFC19DC6,0x240CA1CC,0x2DE92C6F,0x4A7484AA,0x5CB0A9DC,0x76F988DA,0x983E5152,0xA831C66D,0xB00327C8,0xBF597FC7,0xC6E00BF3,0xD5A79147,0x6CA6351,0x14292967,0x27B70A85,0x2E1B2138,0x4D2C6DFC,0x53380D13,0x650A7354,0x766A0ABB,0x81C2C92E,0x92722C85,0xA2BFE8A1,0xA81A664B,0xC24B8B70,0xC76C51A3,0xD192E819,0xD6990624,0xF40E3585,0x106AA070,0x19A4C116,0x1E376C08,0x2748774C,0x34B0BCB5,0x391C0CB3,0x4ED8AA4A,0x5B9CCA4F,0x682E6FF3,0x748F82EE,0x78A5636F,0x84C87814,0x8CC70208,0x90BEFFFA,0xA4506CEB,0xBEF9A3F7,0xC67178F2],HASH=[0x6A09E667,0xBB67AE85,0x3C6EF372,0xA54FF53A,0x510E527F,0x9B05688C,0x1F83D9AB,0x5BE0CD19],W=new Array(64);m[l>>5]|=0x80<<(24-l%32);m[((l+64>>9)<<4)+15]=l;for(i=0,ml=m.length;i<ml;i+=16){a=HASH[0];b=HASH[1];c=HASH[2];d=HASH[3];e=HASH[4];f=HASH[5];g=HASH[6];h=HASH[7];for(j=-1;++j<64;){if(j<16){W[j]=m[j+i];}else{W[j]=sa(sa(sa(G1256(W[j-2]),W[j-7]),G0256(W[j-15])),W[j-16]);}T1=sa(sa(sa(sa(h,S1256(e)),Ch(e,f,g)),K[j]),W[j]);T2=sa(S0256(a),Maj(a,b,c));h=g;g=f;f=e;e=sa(d,T1);d=c;c=b;b=a;a=sa(T1,T2);}HASH[0]=sa(a,HASH[0]);HASH[1]=sa(b,HASH[1]);HASH[2]=sa(c,HASH[2]);HASH[3]=sa(d,HASH[3]);HASH[4]=sa(e,HASH[4]);HASH[5]=sa(f,HASH[5]);HASH[6]=sa(g,HASH[6]);HASH[7]=sa(h,HASH[7]);}return HASH;}function str2binb(str){var bin=[],i=0,l=0,mask=(1<<chrsz)-1;for(l=str.length;i<l*chrsz;i+=chrsz){bin[i>>5]|=(str.charCodeAt(i/chrsz)&mask)<<(24-i%32);}return bin;}function Utf8Encode(string){string=string.replace(/\r\n/g,"\n");var utftext="",c="",n=-1,l=string.length;for(;++n<l;){c=string.charCodeAt(n);if(c<128){utftext+=String.fromCharCode(c);}else if((c>127)&&(c<2048)){utftext+=String.fromCharCode((c>>6)|192);utftext+=String.fromCharCode((c&63)|128);}else{utftext+=String.fromCharCode((c>>12)|224);utftext+=String.fromCharCode(((c>>6)&63)|128);utftext+=String.fromCharCode((c&63)|128);}}return utftext;}function binb2hex(binarray){var hex_tab=hexcase?"0123456789ABCDEF":"0123456789abcdef";var str="",i=-1,l=0;for(l=binarray.length*4;++i<l;){str+=hex_tab.charAt((binarray[i>>2]>>((3-i%4)*8+4))&0xF)+hex_tab.charAt((binarray[i>>2]>>((3-i%4)*8))&0xF);}return str;}s=Utf8Encode(s);return binb2hex(cs256(str2binb(s),s.length*chrsz));}


window.onload = Chatbox.loader;


window.onunload = function() {

	Chatbox = null;
};