Skip to content

Instantly share code, notes, and snippets.

@plugnburn
Last active August 29, 2015 14:17
Show Gist options
  • Select an option

  • Save plugnburn/bc773a2f912acba406ef to your computer and use it in GitHub Desktop.

Select an option

Save plugnburn/bc773a2f912acba406ef to your computer and use it in GitHub Desktop.
tweetStego
javascript:(function(s){s=document.createElement('script');document.body.appendChild(s);s.onload=function(){TSWidget()};s.src='https://cdn.rawgit.com/plugnburn/bc773a2f912acba406ef/raw/tweetStego.js'})(),void 0
TS = {
codeAlphabet: '.abcdefghijklmnopqrstuvwxyz +-@#',
coverAlphabets: [
'aceijopsxyABCEFHIJKMNOPSTXYZ \u200b',
'\u0430\u0441\u0435\u0456\u0458\u043e\u0440\u0455\u0445\u0443\u0410\u0412\u0421\u0415\u03dc\u041d\u0406\u0408\u041a\u041c\u039d\u041e\u0420\u0405\u0422\u0425\u03a5\u0396\u2005\u200c'
],
//return array of the cover text positions where hidden message bits can be placed according to the cover alphabets
//params: cover text
calcCoverTextPositions: function(coverText) {
var i, positions=[], t=this, c;
for(i=0;i<coverText.length;i++) {
c = coverText[i];
if(~t.coverAlphabets[0].indexOf(c) || ~t.coverAlphabets[1].indexOf(c)) {
positions.push(i);
}
}
return positions;
},
//main API functions
hide: function(msg, coverText) {
var t=this, ctPositions=[], i, p, c;
msg=msg.replace(/\s+/g,' ').toLowerCase().replace(/[^a-z\d +-@]+/g,'').trim().replace(/at/g,'@')
.replace(/\d+/g,function(seq){
return'#'+seq.replace(/\d/g,function(d){return t.codeAlphabet[1+(d|0)]})+'#'
})+'.';
bits = msg.split('').map(function(c){return('00000'+t.codeAlphabet.indexOf(c).toString(2)).slice(-5)}).join('');
do {
ctPositions = t.calcCoverTextPositions(coverText);
if(ctPositions.length<bits.length) coverText+='\u200b';
} while(ctPositions.length<bits.length)
for(i=0;i<ctPositions.length;i++) {
if(i>bits.length) break;
p = ctPositions[i];
c = t.coverAlphabets[0].indexOf(coverText[p]);
if(~c && bits[i]==1) coverText = coverText.slice(0,p)+t.coverAlphabets[1][c]+coverText.slice(p+1);
}
return coverText;
},
reveal: function(coverText) {
var t=this, bits='', ctPositions = t.calcCoverTextPositions(coverText), i, c;
for(i=0;i<ctPositions.length;i++) {
c = coverText[ctPositions[i]];
if(~t.coverAlphabets[0].indexOf(c)) bits += '0';
else if(~t.coverAlphabets[1].indexOf(c)) bits += '1';
}
return bits.match(/.{5}/g).map(function(s){return t.codeAlphabet[parseInt(s,2)]}).join('').replace(/#[a-j]+#/g,function(seq){
return seq.replace(/[a-j#]/g,function(d,i){i=t.codeAlphabet.indexOf(d);return i==31?'':(i-1)})
}).replace(/@/g,'at').replace(/\.+$/,'').trim()
}
};
//Widget
TSWidget = function() {
if(document.querySelector('[data-stegosaurus]')) return;
var widgetBlk = document.createElement('div'), widgetId = 'stegoWidget'+(Math.random()*32768|0)
widgetBlk.id = widgetId;
widgetBlk.setAttribute('data-stegosaurus', widgetId);
widgetBlk.style.cssText = "box-sizing:border-box;background-color:#DDD!important;opacity:0.8;max-width:200px;width:100%;font:14px Arial,'Droid Sans','Liberation Sans',sans-serif;text-align:center;position:fixed;left:0;top:50%;-webkit-transition:all 0.5s ease;-moz-transition:all 0.5s ease;-o-transition:all 0.5s ease;transition:all 0.5s ease;padding:10px;border-radius:6px;z-index:100500";
var widgetTitle = document.createElement('div');
widgetTitle.innerHTML = 'Stegosaurus';
widgetTitle.style.cssText = 'font-size:2em;box-sizing:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none';
var coverArea = document.createElement('textarea'), msgArea = document.createElement('textarea');
coverArea.style.cssText = msgArea.style.cssText = 'background-color:#eee;box-sizing:border-box;font:inherit;display:block;resize:none;outline:none;border:1px solid #ccc!important;width:100%;margin:5px auto;padding:5px;border-radius:5px;';
coverArea.rows = 7;
coverArea.placeholder = 'Cover text (plain or encoded)';
msgArea.rows = 3;
msgArea.placeholder = 'Secret message';
var controlPanel = document.createElement('div');
controlPanel.style.padding = '10px 0';
controlPanel.style.boxSizing = 'border-box';
var hideBtn = document.createElement('button');hideBtn.innerHTML = 'Hide';
var revealBtn = document.createElement('button');revealBtn.innerHTML = 'Reveal';
hideBtn.style.cssText = revealBtn.style.cssText = 'font:inherit;width:45%;max-width:90px;text-align:center;-moz-appearance: button!important;-webkit-appearance:button!important;appearance:button!important';
hideBtn.onclick = function(){coverArea.value=TS.hide(msgArea.value,coverArea.value);coverArea.focus()}
revealBtn.onclick = function(){msgArea.value=TS.reveal(coverArea.value)}
coverArea.onfocus = function(){setTimeout(function(){coverArea.select()},15)}
controlPanel.appendChild(hideBtn);
controlPanel.appendChild(revealBtn);
widgetBlk.appendChild(widgetTitle);
widgetBlk.appendChild(coverArea);
widgetBlk.appendChild(msgArea);
widgetBlk.appendChild(controlPanel);
widgetBlk.onmouseover = function(){widgetBlk.style.marginLeft=0}
widgetBlk.onmouseout = function(){widgetBlk.style.marginLeft = '-'+(widgetBlk.clientWidth-10)+'px'}
document.body.appendChild(widgetBlk);
widgetBlk.style.marginLeft = '-'+(widgetBlk.clientWidth-10)+'px';
widgetBlk.style.marginTop = '-'+(widgetBlk.clientHeight/2)+'px';
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment