var app = angular.module('souris-app', ['souris-common', 'hljs']). config(function ($routeProvider) { $routeProvider. when('/', {controller: CreateCtrl, templateUrl: 'create.html'}). when('/:id!:key', {controller: ViewCtrl, templateUrl: 'view.html'}). when('/:id', {controller: ViewCtrl, templateUrl: 'view.html'}). otherwise({redirectTo: '/'}); }); var TEXT = ""; function CreateCtrl($scope, $remoteService, $location, $route) { "use strict"; $scope.reload = $route.reload; $scope.o = {text: TEXT}; var base_url = $location.absUrl(); base_url = base_url.slice(0, base_url.indexOf('#')); $scope.$base_url = base_url; // Add Randomness to RNG console.info("Adding extra entropy from server and user input."); $scope.entropy = 0; var addEntropy = function (s) { $scope.entropy += s.length; fn.seed(s, {entropy: true}); }; $remoteService('/paste/rng').get().success(addEntropy); (function (events, count) { var t = []; function w(e) { t.push([e.pageX, e.pageY, e.keyCode, +new Date]); if (t.length < count) { return; } addEntropy(t); $scope.$apply(); t = []; } for (var i in events) if (events.hasOwnProperty(i)) document.addEventListener(events[i], w); })(['mousemove', 'keydown', 'keypress', 'click', 'scroll'], 16); $scope.HighliteLang = fn.obj(HighliteLang); $scope.ExpireTimes = fn.obj(ExpireTimes); // Encrypt and send function $scope.Encrypt = function (o) { if (o.text.length > 512) {o.zip = true; $scope.o.zip = true; } var e = encrypt(o); console.log("Sending:\n" + json(e)); $remoteService('/paste') .post({}, e.txt) .success(function (d) { console.log("Received:\n" + d); d = d.split(' '); $scope.result = {status: d[0], id: d[1], key: e.key, text: e.txt}; }); }; } CreateCtrl.$inject = ['$scope', '$remoteService', '$location', '$route']; function ViewCtrl($scope, $params, $remoteService, $location) { "use strict"; var base_url = $location.absUrl(); base_url = base_url.slice(0, base_url.indexOf('#')); $scope.$base_url = base_url; var id = $params.id, key = $params.key; $scope.id = id; $scope.key = key; function store(o) { $scope.store = o; } $scope.copy = function(t) { TEXT = t; $location.path('/'); } $remoteService('/paste/:id') .get({id: id}) .success(decrypt(key, store)) .error(function(d, c){ var msg = ''; switch(c){ case 403: msg = 'Authentication Required.'; break; case 404: msg = 'Message Not Found.'; break; case 410: msg = 'Message Expired.'; break; } $scope.store = {err:msg, code:c}; }); } ViewCtrl.$inject = ['$scope', '$routeParams', '$remoteService', '$location']; var HighliteLang = [["text", "Plain Text"], ["apache", "Apache"], ["bash", "Bash"], ["coffeescript", "CoffeeScript"], ["cpp", "C++"], ["cs", "C#"], ["css", "CSS"], ["diff", "Diff"], ["http", "HTTP"], ["ini", "Ini"], ["java", "Java"], ["javascript", "JavaScript"], ["json", "JSON"], ["makefile", "Makefile"], ["markdown", "Markdown"], ["nginx", "Nginx"], ["objectivec", "Objective C"], ["perl", "Perl"], ["php", "PHP"], ["python", "Python"], ["ruby", "Ruby"], ["sql", "SQL"], ["xml", "HTML, XML"]]; var ExpireTimes = [[3600, "1 Hour"], [86400, "1 Day"], [604800, "1 Week"], [2419200, "4 Weeks"], [15778463, "6 Months"], [31556926, "1 Year"]]; var fn = { sha: function (s) { return this.b64(CryptoJS.SHA256(s)); }, rmd: function (s) { return this.b64(CryptoJS.RIPEMD160(s)); }, chk: function (s) { return this.b64(CryptoJS.RIPEMD160(CryptoJS.SHA256(s))); }, enc: function (t, p) { return CryptoJS.AES.encrypt(t, p).toString(); }, dec: function (c, p) { return CryptoJS.AES.decrypt(c, p); }, b64: function (s) { if (s == undefined) return; return CryptoJS.enc.Base64.stringify(s).replace(/[=]+/, '').replace(/\//g, '_').replace(/\+/g, '-'); }, d64: function (s) { if (s == undefined) return; switch (s.length % 3) { case 2: s += '='; // fallthrough case 1: s += '='; } return CryptoJS.enc.Base64.parse(s.replace(/_/g, '/').replace(/-/g, '+')); }, rng: function (n) { return this.b64(CryptoJS.lib.WordArray.random(n)); }, seed: Math.seedrandom, u8a: function (wa) { var w = wa.words; var b = new Uint8Array(w.length * 4), v, i, j, k = 0; for (i = 0; i < w.length; ++i) { v = w[i]; for (j = 3; j >= 0; --j) { b[k++] = ((v >> 8 * j) & 0xFF); } } return b; }, u16a: function (ua) { var s = ''; for (var i = 0; i < ua.length; i++) { s += ('0' + ua[i].toString(16)).slice(-2); } return CryptoJS.enc.Hex.parse(s); }, str8: function (ua) { var s = ''; for (var i = 0; i < ua.byteLength; i++) { if ((ua[i]&0x80) == 0) s += String.fromCharCode(ua[i]); else if ((ua[i]&0xe0) == 0xc0 && (ua[i+1]&0xc0) == 0x80) { s += String.fromCharCode(((ua[i]&0x1f)<<6) + (ua[i+1]&0x3f)); i += 1; } else if ((ua[i]&0xf0) == 0xe0 && (ua[i+1]&0xc0) == 0x80 && (ua[i+2]&0xc0) == 0x80){ s += String.fromCharCode(((ua[i]&0x0f)<<12) + ((ua[i+1]&0x3f)<<6) + (ua[i+2]&0x3f)); i += 2; } else if ((ua[i]&0xf8) == 0xf0 && (ua[i+1]&0xc0) == 0x80 && (ua[i+2]&0xc0) == 0x80 && (ua[i+3]&0xc0) == 0x80) { s += String.fromCharCode(((ua[i]&0x0f)<<18) + ((ua[i+1]&0x3f)<<12) + ((ua[i+2]&0x3f)<<6) + (ua[i+3]&0x3f)); i += 3; } else { s += String.fromCharCode(65533); } } return s; }, obj: function (a) { var o = []; for (var i = 0; i < a.length; i++) { o.push({key: a[i][0], val: a[i][1]}); } return o; } }; var decrypt = function (key, tgt) { return function (d) { if (d.length === 0) tgt({err: "Not Found", code: 'not_found'}); var s = d.split('\n'); d = {}; var i = 0; while (true) { if (s[i] == "") break; var l = s[i].trim().split(':\t'); d[l[0]] = l[1]; i++; } d.tx = s.splice(i).join(''); if (key === undefined) tgt({err: "Missing Key", code: 'no_key'}); else if (d.chk != fn.rmd(fn.d64(key))) tgt({err: "Invalid Key", code: "bad_key"}); else { var tx; if (d.zip) { tx = fn.dec(d.tx, key); tx = fn.u8a(tx); tx = fn.str8(pako.inflate(tx)); } else { tx = fn.dec(d.tx, key).toString(CryptoJS.enc.Utf8); } var lang = 'text'; for (i = 0; i < HighliteLang.length; i++) if (d.lang == HighliteLang[i][0]) lang = HighliteLang[i][0]; tgt({code: 'ok', tx: tx, lang: lang, exp: d.exp, zip: d.zip}); } }; }; var encrypt = function (o) { var ts = Date.now(); console.info("Begin Encryption Process..."); var pass; if (o.pass !== undefined) pass = fn.chk(o.pass); var r = fn.rng(40); var key = fn.sha(r); var chk = fn.chk(r); var text = o.text; if (o.zip) { console.info("Compressing text..."); var bl = o.text.length, bs = Date.now(); var deflate = pako.gzip(text); text = fn.u16a(deflate); console.info("Compress complete: " + (Date.now() - bs) + "ms, " + bl + " => " + o.text.length + " bytes"); } var enc = fn.enc(text, key); var exp = (o.exp === undefined ? undefined : (o.exp + Date.now() / 1000 | 0)); var header = { 'pass': pass, 'chk': chk, 'lang': o.lang, 'exp': exp, 'zip': o.zip, 'burn': o.burn }; var s = ''; for (var i in header) if (header.hasOwnProperty(i)) if (header[i] !== undefined) { s += i + ":\t" + header[i] + "\n"; } s += "\n"; while (enc.length > 79) { s += enc.slice(0, 79) + "\n"; enc = enc.slice(79); } s += enc + "\n"; console.info("Encrypt complete: " + (Date.now() - ts) + " ms"); return {'txt': s, 'key': key}; }; m.filter('blength', function () { return function (o) { if (!(typeof o == 'string' || o instanceof String)) return; if (o === undefined || o.length === undefined) return; var utf8length = 0; for (var n = 0; n < o.length; n++) { var c = o.charCodeAt(n); if (c < 128) { utf8length++; } else if ((c > 127) && (c < 2048)) { utf8length = utf8length + 2; } else { utf8length = utf8length + 3; } } return utf8length; }; });