diff --git a/AES.js b/AES.js new file mode 100644 index 0000000..ff3bb7b --- /dev/null +++ b/AES.js @@ -0,0 +1,39 @@ +"use strict";var AES={cipher:{},hash:{},mode:{},misc:{},codec:{},exception:{corrupt:function(a){this.toString=function(){return"CORRUPT: "+this.message};this.message=a},invalid:function(a){this.toString=function(){return"INVALID: "+this.message};this.message=a},bug:function(a){this.toString=function(){return"BUG: "+this.message};this.message=a}}}; +AES.cipher.aes=function(a){this.h[0][0][0]||this.w();var b,c,d,e,f=this.h[0][4],g=this.h[1];b=a.length;var h=1;if(b!==4&&b!==6&&b!==8)throw new AES.exception.invalid("invalid aes key size");this.a=[d=a.slice(0),e=[]];for(a=b;a<4*b+28;a++){c=d[a-1];if(a%b===0||b===8&&a%b===4){c=f[c>>>24]<<24^f[c>>16&255]<<16^f[c>>8&255]<<8^f[c&255];if(a%b===0){c=c<<8^c>>>24^h<<24;h=h<<1^(h>>7)*283}}d[a]=d[a-b]^c}for(b=0;a;b++,a--){c=d[b&3?a:a-4];e[b]=a<=4||b<4?c:g[0][f[c>>>24]]^g[1][f[c>>16&255]]^g[2][f[c>>8&255]]^ +g[3][f[c&255]]}}; +AES.cipher.aes.prototype={encrypt:function(a){return this.H(a,0)},decrypt:function(a){return this.H(a,1)},h:[[[],[],[],[],[]],[[],[],[],[],[]]],w:function(){var a=this.h[0],b=this.h[1],c=a[4],d=b[4],e,f,g,h=[],i=[],k,j,l,m;for(e=0;e<0x100;e++)i[(h[e]=e<<1^(e>>7)*283)^e]=e;for(f=g=0;!c[f];f^=k||1,g=i[g]||1){l=g^g<<1^g<<2^g<<3^g<<4;l=l>>8^l&255^99;c[f]=l;d[l]=f;j=h[e=h[k=h[f]]];m=j*0x1010101^e*0x10001^k*0x101^f*0x1010100;j=h[l]*0x101^l*0x1010100;for(e=0;e<4;e++){a[e][f]=j=j<<24^j>>>8;b[e][l]=m=m<<24^m>>>8}}for(e= +0;e<5;e++){a[e]=a[e].slice(0);b[e]=b[e].slice(0)}},H:function(a,b){if(a.length!==4)throw new AES.exception.invalid("invalid aes block size");var c=this.a[b],d=a[0]^c[0],e=a[b?3:1]^c[1],f=a[2]^c[2];a=a[b?1:3]^c[3];var g,h,i,k=c.length/4-2,j,l=4,m=[0,0,0,0];g=this.h[b];var n=g[0],o=g[1],p=g[2],q=g[3],r=g[4];for(j=0;j>>24]^o[e>>16&255]^p[f>>8&255]^q[a&255]^c[l];h=n[e>>>24]^o[f>>16&255]^p[a>>8&255]^q[d&255]^c[l+1];i=n[f>>>24]^o[a>>16&255]^p[d>>8&255]^q[e&255]^c[l+2];a=n[a>>>24]^o[d>>16& +255]^p[e>>8&255]^q[f&255]^c[l+3];l+=4;d=g;e=h;f=i}for(j=0;j<4;j++){m[b?3&-j:j]=r[d>>>24]<<24^r[e>>16&255]<<16^r[f>>8&255]<<8^r[a&255]^c[l++];g=d;d=e;e=f;f=a;a=g}return m}}; +AES.bitArray={bitSlice:function(a,b,c){a=AES.bitArray.P(a.slice(b/32),32-(b&31)).slice(1);return c===undefined?a:AES.bitArray.clamp(a,c-b)},concat:function(a,b){if(a.length===0||b.length===0)return a.concat(b);var c=a[a.length-1],d=AES.bitArray.getPartial(c);return d===32?a.concat(b):AES.bitArray.P(b,d,c|0,a.slice(0,a.length-1))},bitLength:function(a){var b=a.length;if(b===0)return 0;return(b-1)*32+AES.bitArray.getPartial(a[b-1])},clamp:function(a,b){if(a.length*320&&b)a[c-1]=AES.bitArray.partial(b,a[c-1]&2147483648>>b-1,1);return a},partial:function(a,b,c){if(a===32)return b;return(c?b|0:b<<32-a)+a*0x10000000000},getPartial:function(a){return Math.round(a/0x10000000000)||32},equal:function(a,b){if(AES.bitArray.bitLength(a)!==AES.bitArray.bitLength(b))return false;var c=0,d;for(d=0;d=32;b-=32){d.push(c);c=0}if(b===0)return d.concat(a); +for(e=0;e>>b);c=a[e]<<32-b}e=a.length?a[a.length-1]:0;a=AES.bitArray.getPartial(e);d.push(AES.bitArray.partial(b+a&31,b+a>32?c:d.pop(),1));return d},k:function(a,b){return[a[0]^b[0],a[1]^b[1],a[2]^b[2],a[3]^b[3]]}}; +AES.codec.utf8String={fromBits:function(a){var b="",c=AES.bitArray.bitLength(a),d,e;for(d=0;d>>24);e<<=8}return decodeURIComponent(escape(b))},toBits:function(a){a=unescape(encodeURIComponent(a));var b=[],c,d=0;for(c=0;c>>e)>>>26);if(e<6){g=a[d]<<6-e;e+=26;d++}else{g<<=6;e-=6}}for(;c.length&3&&!b;)c+="=";return c},toBits:function(a){a=a.replace(/\s|=/g,"");var b=[],c,d=0,e=AES.codec.base64.D,f=0,g;for(c=0;c26){d-=26;b.push(f^g>>>d);f=g<<32-d}else{d+=6;f^=g<<32-d}}d&56&&b.push(AES.bitArray.partial(d&56,f,1));return b}};AES.hash.sha256=function(a){this.a[0]||this.w();if(a){this.n=a.n.slice(0);this.i=a.i.slice(0);this.e=a.e}else this.reset()};AES.hash.sha256.hash=function(a){return(new AES.hash.sha256).update(a).finalize()}; +AES.hash.sha256.prototype={blockSize:512,reset:function(){this.n=this.N.slice(0);this.i=[];this.e=0;return this},update:function(a){if(typeof a==="string")a=AES.codec.utf8String.toBits(a);var b,c=this.i=AES.bitArray.concat(this.i,a);b=this.e;a=this.e=b+AES.bitArray.bitLength(a);for(b=512+b&-512;b<=a;b+=512)this.C(c.splice(0,16));return this},finalize:function(){var a,b=this.i,c=this.n;b=AES.bitArray.concat(b,[AES.bitArray.partial(1,1)]);for(a=b.length+2;a&15;a++)b.push(0);b.push(Math.floor(this.e/ +4294967296));for(b.push(this.e|0);b.length;)this.C(b.splice(0,16));this.reset();return c},N:[],a:[],w:function(){function a(e){return(e-Math.floor(e))*0x100000000|0}var b=0,c=2,d;a:for(;b<64;c++){for(d=2;d*d<=c;d++)if(c%d===0)continue a;if(b<8)this.N[b]=a(Math.pow(c,0.5));this.a[b]=a(Math.pow(c,1/3));b++}},C:function(a){var b,c,d=a.slice(0),e=this.n,f=this.a,g=e[0],h=e[1],i=e[2],k=e[3],j=e[4],l=e[5],m=e[6],n=e[7];for(a=0;a<64;a++){if(a<16)b=d[a];else{b=d[a+1&15];c=d[a+14&15];b=d[a&15]=(b>>>7^b>>>18^ +b>>>3^b<<25^b<<14)+(c>>>17^c>>>19^c>>>10^c<<15^c<<13)+d[a&15]+d[a+9&15]|0}b=b+n+(j>>>6^j>>>11^j>>>25^j<<26^j<<21^j<<7)+(m^j&(l^m))+f[a];n=m;m=l;l=j;j=k+b|0;k=i;i=h;h=g;g=b+(h&i^k&(h^i))+(h>>>2^h>>>13^h>>>22^h<<30^h<<19^h<<10)|0}e[0]=e[0]+g|0;e[1]=e[1]+h|0;e[2]=e[2]+i|0;e[3]=e[3]+k|0;e[4]=e[4]+j|0;e[5]=e[5]+l|0;e[6]=e[6]+m|0;e[7]=e[7]+n|0}}; +AES.mode.ccm={name:"ccm",encrypt:function(a,b,c,d,e){var f,g=b.slice(0),h=AES.bitArray,i=h.bitLength(c)/8,k=h.bitLength(g)/8;e=e||64;d=d||[];if(i<7)throw new AES.exception.invalid("ccm: iv must be at least 7 bytes");for(f=2;f<4&&k>>>8*f;f++);if(f<15-i)f=15-i;c=h.clamp(c,8*(15-f));b=AES.mode.ccm.G(a,b,c,d,e,f);g=AES.mode.ccm.I(a,g,c,b,e,f);return h.concat(g.data,g.tag)},decrypt:function(a,b,c,d,e){e=e||64;d=d||[];var f=AES.bitArray,g=f.bitLength(c)/8,h=f.bitLength(b),i=f.clamp(b,h-e),k=f.bitSlice(b, +h-e);h=(h-e)/8;if(g<7)throw new AES.exception.invalid("ccm: iv must be at least 7 bytes");for(b=2;b<4&&h>>>8*b;b++);if(b<15-g)b=15-g;c=f.clamp(c,8*(15-b));i=AES.mode.ccm.I(a,i,c,k,e,b);a=AES.mode.ccm.G(a,i.data,c,d,e,b);if(!f.equal(i.tag,a))throw new AES.exception.corrupt("ccm: tag doesn't match");return i.data},G:function(a,b,c,d,e,f){var g=[],h=AES.bitArray,i=h.k;e/=8;if(e%2||e<4||e>16)throw new AES.exception.invalid("ccm: invalid tag length");if(d.length>0xffffffff||b.length>0xffffffff)throw new AES.exception.bug("ccm: can't deal with 4GiB or more data"); +f=[h.partial(8,(d.length?64:0)|e-2<<2|f-1)];f=h.concat(f,c);f[3]|=h.bitLength(b)/8;f=a.encrypt(f);if(d.length){c=h.bitLength(d)/8;if(c<=65279)g=[h.partial(16,c)];else if(c<=0xffffffff)g=h.concat([h.partial(16,65534)],[c]);g=h.concat(g,d);for(d=0;d>>31,a[1]<<1^a[2]>>>31,a[2]<<1^a[3]>>>31,a[3]<<1^(a[0]>>>31)*135]}};AES.misc.hmac=function(a,b){this.M=b=b||AES.hash.sha256;var c=[[],[]],d=b.prototype.blockSize/32;this.l=[new b,new b];if(a.length>d)a=b.hash(a);for(b=0;b0;){b++;e>>>=1}this.b[g].update([d,this.J++,2,b,f,a.length].concat(a));break;case "string":if(b===undefined)b=a.length;this.b[g].update([d,this.J++,3,b,f,a.length]);this.b[g].update(a);break;default:throw new AES.exception.bug("random: addEntropy only supports number, array or string");}this.j[g]+=b;this.f+=b;if(h===0){this.isReady()!==0&&this.K("seeded",Math.max(this.g, +this.f));this.K("progress",this.getProgress())}},isReady:function(a){a=this.B[a!==undefined?a:this.t];return this.g&&this.g>=a?this.j[0]>80&&(new Date).valueOf()>this.O?3:1:this.f>=a?2:0},getProgress:function(a){a=this.B[a?a:this.t];return this.g>=a?1["0"]:this.f>a?1["0"]:this.f/a},startCollectors:function(){if(!this.m){if(window.addEventListener){window.addEventListener("load",this.o,false);window.addEventListener("mousemove",this.p,false)}else if(document.attachEvent){document.attachEvent("onload", +this.o);document.attachEvent("onmousemove",this.p)}else throw new AES.exception.bug("can't attach event");this.m=true}},stopCollectors:function(){if(this.m){if(window.removeEventListener){window.removeEventListener("load",this.o);window.removeEventListener("mousemove",this.p)}else if(window.detachEvent){window.detachEvent("onload",this.o);window.detachEvent("onmousemove",this.p)}this.m=false}},addEventListener:function(a,b){this.r[a][this.Q++]=b},removeEventListener:function(a,b){var c;a=this.r[a]; +var d=[];for(c in a)a.hasOwnProperty[c]&&a[c]===b&&d.push(c);for(b=0;b=1<this.g)this.g=c;this.z++;this.T(b)},p:function(a){AES.random.addEntropy([a.x|| +a.clientX||a.offsetX,a.y||a.clientY||a.offsetY],2,"mouse")},o:function(){AES.random.addEntropy(new Date,2,"loadtime")},K:function(a,b){var c;a=AES.random.r[a];var d=[];for(c in a)a.hasOwnProperty(c)&&d.push(a[c]);for(c=0;c +4)throw new AES.exception.invalid("json encrypt: invalid parameters");if(typeof a==="string"){c=AES.misc.cachedPbkdf2(a,f);a=c.key.slice(0,f.ks/32);f.salt=c.salt}if(typeof b==="string")b=AES.codec.utf8String.toBits(b);c=new AES.cipher[f.cipher](a);e.c(d,f);d.key=a;f.ct=AES.mode[f.mode].encrypt(c,b,f.iv,f.adata,f.tag);return e.encode(e.V(f,e.defaults))},decrypt:function(a,b,c,d){c=c||{};d=d||{};var e=AES.json;b=e.c(e.c(e.c({},e.defaults),e.decode(b)),c,true);if(typeof b.salt==="string")b.salt= +AES.codec.base64.toBits(b.salt);if(typeof b.iv==="string")b.iv=AES.codec.base64.toBits(b.iv);if(!AES.mode[b.mode]||!AES.cipher[b.cipher]||typeof a==="string"&&b.iter<=100||b.ts!==64&&b.ts!==96&&b.ts!==128||b.ks!==128&&b.ks!==192&&b.ks!==0x100||!b.iv||b.iv.length<2||b.iv.length>4)throw new AES.exception.invalid("json decrypt: invalid parameters");if(typeof a==="string"){c=AES.misc.cachedPbkdf2(a,b);a=c.key.slice(0,b.ks/32);b.salt=c.salt}c=new AES.cipher[b.cipher](a);c=AES.mode[b.mode].decrypt(c, +b.ct,b.iv,b.adata,b.tag);e.c(d,b);d.key=a;return AES.codec.utf8String.fromBits(c)},encode:function(a){var b,c="{",d="";for(b in a)if(a.hasOwnProperty(b)){if(!b.match(/^[a-z0-9]+$/i))throw new AES.exception.invalid("json encode: invalid property name");c+=d+b+":";d=",";switch(typeof a[b]){case "number":case "boolean":c+=a[b];break;case "string":c+='"'+escape(a[b])+'"';break;case "object":c+='"'+AES.codec.base64.fromBits(a[b],1)+'"';break;default:throw new AES.exception.bug("json encode: unsupported type"); +}}return c+"}"},decode:function(a){a=a.replace(/\s/g,"");if(!a.match(/^\{.*\}$/))throw new AES.exception.invalid("json decode: this isn't json!");a=a.replace(/^\{|\}$/g,"").split(/,/);var b={},c,d;for(c=0;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; + }; + + // private method for UTF-8 decoding + var _utf8_decode = function (utftext) { + var string = ""; + var i = 0; + var c = c1 = c2 = 0; + + while ( i < utftext.length ) { + + c = utftext.charCodeAt(i); + + if (c < 128) { + string += String.fromCharCode(c); + i++; + } + else if((c > 191) && (c < 224)) { + c2 = utftext.charCodeAt(i+1); + string += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); + i += 2; + } + else { + c2 = utftext.charCodeAt(i+1); + c3 = utftext.charCodeAt(i+2); + string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); + i += 3; + } + + } + + return string; + }; + + var Base64 = global.Base64 = { + // public method for encoding + encode : function (input) { + var output = ""; + var chr1, chr2, chr3, enc1, enc2, enc3, enc4; + var i = 0; + + input = _utf8_encode(input); + + while (i < input.length) { + + chr1 = input.charCodeAt(i++); + chr2 = input.charCodeAt(i++); + chr3 = input.charCodeAt(i++); + + enc1 = chr1 >> 2; + enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); + enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); + enc4 = chr3 & 63; + + if (isNaN(chr2)) { + enc3 = enc4 = 64; + } else if (isNaN(chr3)) { + enc4 = 64; + } + + output = output + + _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + + _keyStr.charAt(enc3) + _keyStr.charAt(enc4); + + } + + return output; + }, + + // public method for decoding + decode : function (input) { + var output = ""; + var chr1, chr2, chr3; + var enc1, enc2, enc3, enc4; + var i = 0; + + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); + + while (i < input.length) { + + enc1 = _keyStr.indexOf(input.charAt(i++)); + enc2 = _keyStr.indexOf(input.charAt(i++)); + enc3 = _keyStr.indexOf(input.charAt(i++)); + enc4 = _keyStr.indexOf(input.charAt(i++)); + + chr1 = (enc1 << 2) | (enc2 >> 4); + chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); + chr3 = ((enc3 & 3) << 6) | enc4; + + output = output + String.fromCharCode(chr1); + + if (enc3 != 64) { + output = output + String.fromCharCode(chr2); + } + if (enc4 != 64) { + output = output + String.fromCharCode(chr3); + } + + } + output = _utf8_decode(output); + return output; + } + } + +})(this) diff --git a/options.css b/options.css new file mode 100644 index 0000000..91bf064 --- /dev/null +++ b/options.css @@ -0,0 +1,74 @@ +.container { + width: 600px; + margin: 1em 2em; +} +fieldset { + border: 0; + border-left: 1px solid #999; + padding-top: 3em; + position: relative; +} +fieldset.disabled { + background-color: #EEE; + color: #999; +} +fieldset.disabled * { cursor: default; } +fieldset.disabled legend:hover label { cursor: pointer; } +fieldset.disabled legend:hover { color: #555; } +fieldset p { + margin: 0 0 0.5em; + clear: both; + position: relative; +} +fieldset label { cursor: pointer; } +fieldset p label { + text-transform: lowercase; + float: left; + width: 8em; + margin-right: 0.7em; + text-align: right; + padding-top: 5px; + vertical-align: top; +} +fieldset p input[disabled] { + background-color: #eee; +} +fieldset p input[type="radio"]+label, +fieldset p input[type="checkbox"]+label { + text-align: left; + float: none; + margin-left: 0.5em; +} +fieldset legend { + font-variant: small-caps; + text-transform: capitalize; + position: relative; + top: 1em; + font-size: 1.5em; + cursor: default; +} +button#reset { + float: right; +} +label acronym { + text-transform: uppercase; + vertical-align: top; +} +img#logo { + float: left; + margin-right: 1.2em; + margin-left: 0.5em; +} +.title { + padding: 0.5em; + vertical-align: baseline; +} +label[for="additional_trackers"] { width: auto; } +#additional_trackers { + width: 100%; + height: 12em; + clear: left; +} +fieldset select { border-color: #bbb; } +fieldset select:focus { border-color: #666; } +#full_rpc_url { margin-left: 9em; } diff --git a/options.html b/options.html index bb07307..e8724f6 100644 --- a/options.html +++ b/options.html @@ -1,80 +1,11 @@ - - - + + + + + @@ -84,16 +15,26 @@

Transmission Torrent Downloader

server configuration

- - + + +

+

+ +

- + +

+

+ +

- - http://localhost:9091/ + https://localhost:9091/transmission/rpc

@@ -104,18 +45,18 @@

Transmission Torrent Downloader

- +

- +

- +

- +

diff --git a/options.js b/options.js index af1d36d..a16920f 100644 --- a/options.js +++ b/options.js @@ -1,4 +1,17 @@ (function($, global, undefined){ + + localStorage.defaultServerProtocol = JSON.stringify('https'); + localStorage.defaultServerHost = JSON.stringify('localhost'); + localStorage.defaultServerPort = JSON.stringify(9091); + localStorage.defaultServerPath = JSON.stringify('/transmission/rpc'); + localStorage.defaultAuthenticationEnabled = JSON.stringify(false); + localStorage.defaultAuthenticationEncrypted = JSON.stringify(false); + localStorage.defaultAuthenticationUsername = JSON.stringify(''); + localStorage.defaultAuthenticationPassword = JSON.stringify(''); + localStorage.defaultAddTrackers = JSON.stringify(true); + localStorage.defaultAdditionalTrackers = JSON.stringify([]); + console.log(localStorage); + var hasClass = function(klass){ return new RegExp('(^|\\s)'+klass+'(\\s|$)').test(this.className); }, @@ -11,19 +24,61 @@ this.className = this.className.replace(new RegExp('(^|\\s+)'+klass+'($|\\s+)','g'),' '); }; - var elemEnableAuthentication = $('authentication_enabled'); - elemEnableAuthentication.addEventListener('click',function(){ - var state = this.checked, - elemAuthenticationContainer = $('authentication_container'); + var fixAuthentication = function(){ + var elemAuthenticationEnabled = $('authentication_enabled'), + state = elemAuthenticationEnabled.checked, + elemAuthenticationContainer = $('authentication_container'), + elemAuthenticationPassword = $('password'), + elemEncryptionEnabled = $('encryption_enabled'); (state ? removeClass : addClass).call(elemAuthenticationContainer,'disabled'); - $('username').disabled = !state; - $('password').disabled = !state; - $('encryption_key').disabled = $('encryption_enabled').disabled; - }); + $('username').disabled = !state || elemEncryptionEnabled.checked; + $('password').disabled = !state || elemEncryptionEnabled.checked; + $('encryption_key').disabled = !state; + elemEncryptionEnabled.disabled = !state; + elemAuthenticationPassword.type = elemEncryptionEnabled.checked ? 'text' : 'password'; + } - var elemSaveButton = $('save'); - elemSaveButton.addEventListener('click',function(){ - console.log('save'); + $('authentication_enabled').addEventListener('click',fixAuthentication); + $('encryption_enabled').addEventListener('click',function(){ + var username, password, + elemEncryptionKey = $('encryption_key'), + encryptionKey = elemEncryptionKey.value, + elemAuthenticationUsername = $('username'), + elemAuthenticationPassword = $('password'); + if(!this.checked) { + if(!encryptionKey) { + elemEncryptionKey.focus(); + this.checked = true; + return; + } + username = elemAuthenticationUsername.value; + password = elemAuthenticationPassword.value; + try { + elemAuthenticationUsername.value = AES.decrypt(encryptionKey, Base64.decode(username)); + elemAuthenticationPassword.value = AES.decrypt(encryptionKey, Base64.decode(password)); + elemEncryptionKey.value = ''; + } catch(e) { + this.checked = true; + alert('invalid decryption key') + elemAuthenticationUsername.value = username; + elemAuthenticationPassword.value = password; + elemEncryptionKey.value = encryptionKey; + elemEncryptionKey.focus(); + return null; + } + } else { + if(!encryptionKey) { + elemEncryptionKey.focus(); + this.checked = false; + return; + } + username = elemAuthenticationUsername.value; + elemAuthenticationUsername.value = Base64.encode(AES.encrypt(encryptionKey, username)); + password = elemAuthenticationPassword.value; + elemAuthenticationPassword.value = Base64.encode(AES.encrypt(encryptionKey, password)); + elemEncryptionKey.value = ''; + } + fixAuthentication(); }); var elemCancelButton = $('cancel'); @@ -35,6 +90,71 @@ var elemResetButton = $('reset'); elemResetButton.addEventListener('click',function(){ if(!global.confirm('Are you sure you would like to reset everything to defaults?')) return; - console.log('reset'); + for(var key in localStorage) + if(key.slice(0,3)=='opt') delete localStorage[key]; + loadOptions(); }); + + var getOption = function(opt){ + var def, obj; + if((obj=localStorage['opt'+opt])!=null) return JSON.parse(obj); + return (def=localStorage['default'+opt])!=null ? JSON.parse(def) : null; + }, + setOption = function(opt, value){ + localStorage['opt'+opt] = value==null ? null : JSON.stringify(value); + }; + + var loadOptions; + (loadOptions = function(){ + var elemProtocol = $('protocol'), + elemHost = $('host'), + elemPort = $('port'), + elemPath = $('path'); + elemProtocol.value = getOption('ServerProtocol'); + elemHost.value = getOption('ServerHost'); + elemPort.value = getOption('ServerPort'); + elemPath.value = getOption('ServerPath'); + + var elemAuthenticationEnabled = $('authentication_enabled'), + elemAuthenticationUsername = $('username'), + elemAuthenticationPassword = $('password'), + elemEncryptionEnabled = $('encryption_enabled'); + elemAuthenticationEnabled.checked = !!getOption('AuthenticationEnabled'); + elemAuthenticationUsername.value = getOption('AuthenticationUsername'); + elemAuthenticationPassword.value = getOption('AuthenticationPassword'); + elemEncryptionEnabled.checked = !!getOption('AuthenticationEncrypted'); + fixAuthentication(); + + var elemAddTrackers = $('add_trackers'), + elemAdditionalTrackers = $('additional_trackers'); + elemAddTrackers.checked = !!getOption('AddTrackers'); + elemAdditionalTrackers.innerText = getOption('AdditionalTrackers').join("\n"); + })(); + + var saveOptions = function(){ + setOption('ServerProtocol', $('protocol').value); + setOption('ServerHost', $('host').value); + var port = $('port').value; + setOption('ServerPort', port==+port ? +port : null); + var path = $('path').value.replace(/\/(\.\/|\/)+/g,'/'); + setOption('ServerPath', path); + + setOption('AuthenticationEnabled', !!$('authentication_enabled').checked); + setOption('AuthenticationUsername', $('username').value); + setOption('AuthenticationPassword', $('password').value); + setOption('AuthenticationEncrypted', !!$('encryption_enabled').checked); + + setOption('AddTrackers', !!$('add_trackers').checked); + var trackers = $('additional_trackers').value; + trackers = trackers.split(/\s+/g).filter(function(_){ return !!_; }); + setOption('AdditionalTrackers', trackers); + + loadOptions(); + } + var elemSaveButton = $('save'); + elemSaveButton.addEventListener('click',function(){ + console.log('save'); + saveOptions(); + }); + })(function(){ return document.getElementById.apply(document,arguments) }, this)