mirror of
				http://git.whoc.org.uk/git/password-manager.git
				synced 2025-10-31 03:17:35 +01:00 
			
		
		
		
	More IE11 fixes
This commit is contained in:
		| @@ -43,7 +43,8 @@ Clipperz.PM.UI.AttachmentController = function(someParameters) { | ||||
| 		this.downloadMessageCallback    = someParameters['downloadMessageCallback']; | ||||
| 		this.reloadServerStatusCallback = someParameters['reloadServerStatusCallback']; | ||||
|  | ||||
| 		this.cryptoObject = window.crypto || window.msCrypto; | ||||
| 		// this.cryptoObject = window.crypto || window.msCrypto; // Not needed anymore because of polyfill | ||||
| 		this.cryptoObject = window.crypto | ||||
|  | ||||
| 		return this; | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										337
									
								
								frontend/delta/js/Promiz/promiz.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										337
									
								
								frontend/delta/js/Promiz/promiz.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,337 @@ | ||||
| /* | ||||
|  | ||||
| Copyright 2008-2015 Clipperz Srl | ||||
|  | ||||
| This file is part of Clipperz, the online password manager. | ||||
| For further information about its features and functionalities please | ||||
| refer to http://www.clipperz.com. | ||||
|  | ||||
| * Clipperz is free software: you can redistribute it and/or modify it | ||||
|   under the terms of the GNU Affero General Public License as published | ||||
|   by the Free Software Foundation, either version 3 of the License, or  | ||||
|   (at your option) any later version. | ||||
|  | ||||
| * Clipperz is distributed in the hope that it will be useful, but  | ||||
|   WITHOUT ANY WARRANTY; without even the implied warranty of  | ||||
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||||
|   See the GNU Affero General Public License for more details. | ||||
|  | ||||
| * You should have received a copy of the GNU Affero General Public | ||||
|   License along with Clipperz. If not, see http://www.gnu.org/licenses/. | ||||
|  | ||||
| */ | ||||
|  | ||||
| (function () { | ||||
|   global = this | ||||
|  | ||||
|   var queueId = 1 | ||||
|   var queue = {} | ||||
|   var isRunningTask = false | ||||
|  | ||||
|   if (!global.setImmediate) | ||||
|     global.addEventListener('message', function (e) { | ||||
|       if (e.source == global){ | ||||
|         if (isRunningTask) | ||||
|           nextTick(queue[e.data]) | ||||
|         else { | ||||
|           isRunningTask = true | ||||
|           try { | ||||
|             queue[e.data]() | ||||
|           } catch (e) {} | ||||
|  | ||||
|           delete queue[e.data] | ||||
|           isRunningTask = false | ||||
|         } | ||||
|       } | ||||
|     }) | ||||
|  | ||||
|   function nextTick(fn) { | ||||
|     if (global.setImmediate) setImmediate(fn) | ||||
|     // if inside of web worker | ||||
|     else if (global.importScripts) setTimeout(fn) | ||||
|     else { | ||||
|       queueId++ | ||||
|       queue[queueId] = fn | ||||
|       global.postMessage(queueId, '*') | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   Deferred.resolve = function (value) { | ||||
|     if (!(this._d == 1)) | ||||
|       throw TypeError() | ||||
|  | ||||
|     if (value instanceof Deferred) | ||||
|       return value | ||||
|  | ||||
|     return new Deferred(function (resolve) { | ||||
|         resolve(value) | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   Deferred.reject = function (value) { | ||||
|     if (!(this._d == 1)) | ||||
|       throw TypeError() | ||||
|  | ||||
|     return new Deferred(function (resolve, reject) { | ||||
|         reject(value) | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   Deferred.all = function (arr) { | ||||
|     if (!(this._d == 1)) | ||||
|       throw TypeError() | ||||
|  | ||||
|     if (!(arr instanceof Array)) | ||||
|       return Deferred.reject(TypeError()) | ||||
|  | ||||
|     var d = new Deferred() | ||||
|  | ||||
|     function done(e, v) { | ||||
|       if (v) | ||||
|         return d.resolve(v) | ||||
|  | ||||
|       if (e) | ||||
|         return d.reject(e) | ||||
|  | ||||
|       var unresolved = arr.reduce(function (cnt, v) { | ||||
|         if (v && v.then) | ||||
|           return cnt + 1 | ||||
|         return cnt | ||||
|       }, 0) | ||||
|  | ||||
|       if(unresolved == 0) | ||||
|         d.resolve(arr) | ||||
|  | ||||
|       arr.map(function (v, i) { | ||||
|         if (v && v.then) | ||||
|           v.then(function (r) { | ||||
|             arr[i] = r | ||||
|             done() | ||||
|             return r | ||||
|           }, done) | ||||
|       }) | ||||
|     } | ||||
|  | ||||
|     done() | ||||
|  | ||||
|     return d | ||||
|   } | ||||
|  | ||||
|   Deferred.race = function (arr) { | ||||
|     if (!(this._d == 1)) | ||||
|       throw TypeError() | ||||
|  | ||||
|     if (!(arr instanceof Array)) | ||||
|       return Deferred.reject(TypeError()) | ||||
|  | ||||
|     if (arr.length == 0) | ||||
|       return new Deferred() | ||||
|  | ||||
|     var d = new Deferred() | ||||
|  | ||||
|     function done(e, v) { | ||||
|       if (v) | ||||
|         return d.resolve(v) | ||||
|  | ||||
|       if (e) | ||||
|         return d.reject(e) | ||||
|  | ||||
|       var unresolved = arr.reduce(function (cnt, v) { | ||||
|         if (v && v.then) | ||||
|           return cnt + 1 | ||||
|         return cnt | ||||
|       }, 0) | ||||
|  | ||||
|       if(unresolved == 0) | ||||
|         d.resolve(arr) | ||||
|  | ||||
|       arr.map(function (v, i) { | ||||
|         if (v && v.then) | ||||
|           v.then(function (r) { | ||||
|             done(null, r) | ||||
|           }, done) | ||||
|       }) | ||||
|     } | ||||
|  | ||||
|     done() | ||||
|  | ||||
|     return d | ||||
|   } | ||||
|  | ||||
|   Deferred._d = 1 | ||||
|  | ||||
|  | ||||
|   /** | ||||
|    * @constructor | ||||
|    */ | ||||
|   function Deferred(resolver) { | ||||
|     'use strict' | ||||
|     if (typeof resolver != 'function' && resolver != undefined) | ||||
|       throw TypeError() | ||||
|  | ||||
|     if (typeof this != 'object' || (this && this.then)) | ||||
|       throw TypeError() | ||||
|  | ||||
|     // states | ||||
|     // 0: pending | ||||
|     // 1: resolving | ||||
|     // 2: rejecting | ||||
|     // 3: resolved | ||||
|     // 4: rejected | ||||
|     var self = this, | ||||
|       state = 0, | ||||
|       val = 0, | ||||
|       next = [], | ||||
|       fn, er; | ||||
|  | ||||
|     self['promise'] = self | ||||
|  | ||||
|     self['resolve'] = function (v) { | ||||
|       fn = self.fn | ||||
|       er = self.er | ||||
|       if (!state) { | ||||
|         val = v | ||||
|         state = 1 | ||||
|  | ||||
|         nextTick(fire) | ||||
|       } | ||||
|       return self | ||||
|     } | ||||
|  | ||||
|     self['reject'] = function (v) { | ||||
|       fn = self.fn | ||||
|       er = self.er | ||||
|       if (!state) { | ||||
|         val = v | ||||
|         state = 2 | ||||
|  | ||||
|         nextTick(fire) | ||||
|  | ||||
|       } | ||||
|       return self | ||||
|     } | ||||
|  | ||||
|     self['_d'] = 1 | ||||
|  | ||||
|     self['then'] = function (_fn, _er) { | ||||
|       if (!(this._d == 1)) | ||||
|         throw TypeError() | ||||
|  | ||||
|       var d = new Deferred() | ||||
|  | ||||
|       d.fn = _fn | ||||
|       d.er = _er | ||||
|       if (state == 3) { | ||||
|         d.resolve(val) | ||||
|       } | ||||
|       else if (state == 4) { | ||||
|         d.reject(val) | ||||
|       } | ||||
|       else { | ||||
|         next.push(d) | ||||
|       } | ||||
|  | ||||
|       return d | ||||
|     } | ||||
|  | ||||
|     self['catch'] = function (_er) { | ||||
|       return self['then'](null, _er) | ||||
|     } | ||||
|  | ||||
|     var finish = function (type) { | ||||
|       state = type || 4 | ||||
|       next.map(function (p) { | ||||
|         state == 3 && p.resolve(val) || p.reject(val) | ||||
|       }) | ||||
|     } | ||||
|  | ||||
|     try { | ||||
|       if (typeof resolver == 'function') | ||||
|         resolver(self['resolve'], self['reject']) | ||||
|     } catch (e) { | ||||
|       self['reject'](e) | ||||
|     } | ||||
|  | ||||
|     return self | ||||
|  | ||||
|     // ref : reference to 'then' function | ||||
|     // cb, ec, cn : successCallback, failureCallback, notThennableCallback | ||||
|     function thennable (ref, cb, ec, cn) { | ||||
|       if ((typeof val == 'object' || typeof val == 'function') && typeof ref == 'function') { | ||||
|         try { | ||||
|  | ||||
|           // cnt protects against abuse calls from spec checker | ||||
|           var cnt = 0 | ||||
|           ref.call(val, function (v) { | ||||
|             if (cnt++) return | ||||
|             val = v | ||||
|             cb() | ||||
|           }, function (v) { | ||||
|             if (cnt++) return | ||||
|             val = v | ||||
|             ec() | ||||
|           }) | ||||
|         } catch (e) { | ||||
|           val = e | ||||
|           ec() | ||||
|         } | ||||
|       } else { | ||||
|         cn() | ||||
|       } | ||||
|     }; | ||||
|  | ||||
|     function fire() { | ||||
|  | ||||
|       // check if it's a thenable | ||||
|       var ref; | ||||
|       try { | ||||
|         ref = val && val.then | ||||
|       } catch (e) { | ||||
|         val = e | ||||
|         state = 2 | ||||
|         return fire() | ||||
|       } | ||||
|  | ||||
|       thennable(ref, function () { | ||||
|         state = 1 | ||||
|         fire() | ||||
|       }, function () { | ||||
|         state = 2 | ||||
|         fire() | ||||
|       }, function () { | ||||
|         try { | ||||
|           if (state == 1 && typeof fn == 'function') { | ||||
|             val = fn(val) | ||||
|           } | ||||
|  | ||||
|           else if (state == 2 && typeof er == 'function') { | ||||
|             val = er(val) | ||||
|             state = 1 | ||||
|           } | ||||
|         } catch (e) { | ||||
|           val = e | ||||
|           return finish() | ||||
|         } | ||||
|  | ||||
|         if (val == self) { | ||||
|           val = TypeError() | ||||
|           finish() | ||||
|         } else thennable(ref, function () { | ||||
|             finish(3) | ||||
|           }, finish, function () { | ||||
|             finish(state == 1 && 3) | ||||
|           }) | ||||
|  | ||||
|       }) | ||||
|     } | ||||
|  | ||||
|  | ||||
|   } | ||||
|  | ||||
|   // Export our library object, either for node.js or as a globally scoped variable | ||||
|   if (typeof module != 'undefined') { | ||||
|     module['exports'] = Deferred | ||||
|   } else { | ||||
|     global['Promise'] = global['Promise'] || Deferred | ||||
|   } | ||||
| })() | ||||
							
								
								
									
										24
									
								
								frontend/delta/js/Promiz/promiz.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								frontend/delta/js/Promiz/promiz.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| /* | ||||
|  | ||||
| Copyright 2008-2015 Clipperz Srl | ||||
|  | ||||
| This file is part of Clipperz, the online password manager. | ||||
| For further information about its features and functionalities please | ||||
| refer to http://www.clipperz.com. | ||||
|  | ||||
| * Clipperz is free software: you can redistribute it and/or modify it | ||||
|   under the terms of the GNU Affero General Public License as published | ||||
|   by the Free Software Foundation, either version 3 of the License, or  | ||||
|   (at your option) any later version. | ||||
|  | ||||
| * Clipperz is distributed in the hope that it will be useful, but  | ||||
|   WITHOUT ANY WARRANTY; without even the implied warranty of  | ||||
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||||
|   See the GNU Affero General Public License for more details. | ||||
|  | ||||
| * You should have received a copy of the GNU Affero General Public | ||||
|   License along with Clipperz. If not, see http://www.gnu.org/licenses/. | ||||
|  | ||||
| */ | ||||
|  | ||||
| !function(){function a(a){global.setImmediate?setImmediate(a):global.importScripts?setTimeout(a):(c++,d[c]=a,global.postMessage(c,"*"))}function b(c){"use strict";function d(a,b,c,d){if("object"!=typeof j&&"function"!=typeof j||"function"!=typeof a)d();else try{var e=0;a.call(j,function(a){e++||(j=a,b())},function(a){e++||(j=a,c())})}catch(f){j=f,c()}}function e(){var a;try{a=j&&j.then}catch(b){return j=b,i=2,e()}d(a,function(){i=1,e()},function(){i=2,e()},function(){try{1==i&&"function"==typeof f?j=f(j):2==i&&"function"==typeof g&&(j=g(j),i=1)}catch(b){return j=b,l()}j==h?(j=TypeError(),l()):d(a,function(){l(3)},l,function(){l(1==i&&3)})})}if("function"!=typeof c&&void 0!=c)throw TypeError();if("object"!=typeof this||this&&this.then)throw TypeError();var f,g,h=this,i=0,j=0,k=[];h.promise=h,h.resolve=function(b){return f=h.fn,g=h.er,i||(j=b,i=1,a(e)),h},h.reject=function(b){return f=h.fn,g=h.er,i||(j=b,i=2,a(e)),h},h._d=1,h.then=function(a,c){if(1!=this._d)throw TypeError();var d=new b;return d.fn=a,d.er=c,3==i?d.resolve(j):4==i?d.reject(j):k.push(d),d},h["catch"]=function(a){return h.then(null,a)};var l=function(a){i=a||4,k.map(function(a){3==i&&a.resolve(j)||a.reject(j)})};try{"function"==typeof c&&c(h.resolve,h.reject)}catch(m){h.reject(m)}return h}global=this;var c=1,d={},e=!1;global.setImmediate||global.addEventListener("message",function(b){if(b.source==global)if(e)a(d[b.data]);else{e=!0;try{d[b.data]()}catch(b){}delete d[b.data],e=!1}}),b.resolve=function(a){if(1!=this._d)throw TypeError();return a instanceof b?a:new b(function(b){b(a)})},b.reject=function(a){if(1!=this._d)throw TypeError();return new b(function(b,c){c(a)})},b.all=function(a){function c(b,e){if(e)return d.resolve(e);if(b)return d.reject(b);var f=a.reduce(function(a,b){return b&&b.then?a+1:a},0);0==f&&d.resolve(a),a.map(function(b,d){b&&b.then&&b.then(function(b){return a[d]=b,c(),b},c)})}if(1!=this._d)throw TypeError();if(!(a instanceof Array))return b.reject(TypeError());var d=new b;return c(),d},b.race=function(a){function c(b,e){if(e)return d.resolve(e);if(b)return d.reject(b);var f=a.reduce(function(a,b){return b&&b.then?a+1:a},0);0==f&&d.resolve(a),a.map(function(a,b){a&&a.then&&a.then(function(a){c(null,a)},c)})}if(1!=this._d)throw TypeError();if(!(a instanceof Array))return b.reject(TypeError());if(0==a.length)return new b;var d=new b;return c(),d},b._d=1,"undefined"!=typeof module?module.exports=b:global.Promise=global.Promise||b}(); | ||||
							
								
								
									
										620
									
								
								frontend/delta/js/WebcryptoShim/webcrypto-shim.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										620
									
								
								frontend/delta/js/WebcryptoShim/webcrypto-shim.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,620 @@ | ||||
| /* | ||||
|  | ||||
| Copyright 2008-2015 Clipperz Srl | ||||
|  | ||||
| This file is part of Clipperz, the online password manager. | ||||
| For further information about its features and functionalities please | ||||
| refer to http://www.clipperz.com. | ||||
|  | ||||
| * Clipperz is free software: you can redistribute it and/or modify it | ||||
|   under the terms of the GNU Affero General Public License as published | ||||
|   by the Free Software Foundation, either version 3 of the License, or  | ||||
|   (at your option) any later version. | ||||
|  | ||||
| * Clipperz is distributed in the hope that it will be useful, but  | ||||
|   WITHOUT ANY WARRANTY; without even the implied warranty of  | ||||
|   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||||
|   See the GNU Affero General Public License for more details. | ||||
|  | ||||
| * You should have received a copy of the GNU Affero General Public | ||||
|   License along with Clipperz. If not, see http://www.gnu.org/licenses/. | ||||
|  | ||||
| */ | ||||
|  | ||||
| /** | ||||
|  * @file Web Cryptography API shim | ||||
|  * @author Artem S Vybornov <vybornov@gmail.com> | ||||
|  * @license MIT | ||||
|  */ | ||||
| !function ( global ) { | ||||
|     'use strict'; | ||||
|  | ||||
|     if ( typeof Promise !== 'function' ) | ||||
|         throw "Promise support required"; | ||||
|  | ||||
|     var _crypto = global.crypto || global.msCrypto; | ||||
|     if ( !_crypto ) return; | ||||
|  | ||||
|     var _subtle = _crypto.subtle || _crypto.webkitSubtle; | ||||
|     if ( !_subtle ) return; | ||||
|  | ||||
|     var _Crypto     = global.Crypto || _crypto.constructor || Object, | ||||
|         _SubtleCrypto = global.SubtleCrypto || _subtle.constructor || Object, | ||||
|         _CryptoKey  = global.CryptoKey || global.Key || Object; | ||||
|  | ||||
|     var isIE    = !!global.msCrypto, | ||||
|         isWebkit = !!_crypto.webkitSubtle; | ||||
|     if ( !isIE && !isWebkit ) return; | ||||
|  | ||||
|     function s2a ( s ) { | ||||
|         return btoa(s).replace(/\=+$/, '').replace(/\+/g, '-').replace(/\//g, '_'); | ||||
|     } | ||||
|  | ||||
|     function a2s ( s ) { | ||||
|         s += '===', s = s.slice( 0, -s.length % 4 ); | ||||
|         return atob( s.replace(/-/g, '+').replace(/_/g, '/') ); | ||||
|     } | ||||
|  | ||||
|     function s2b ( s ) { | ||||
|         var b = new Uint8Array(s.length); | ||||
|         for ( var i = 0; i < s.length; i++ ) b[i] = s.charCodeAt(i); | ||||
|         return b; | ||||
|     } | ||||
|  | ||||
|     function b2s ( b ) { | ||||
|         if ( b instanceof ArrayBuffer ) b = new Uint8Array(b); | ||||
|         return String.fromCharCode.apply( String, b ); | ||||
|     } | ||||
|  | ||||
|     function alg ( a ) { | ||||
|         var r = { 'name': (a.name || a || '').toUpperCase().replace('V','v') }; | ||||
|         switch ( r.name ) { | ||||
|             case 'SHA-1': | ||||
|             case 'SHA-256': | ||||
|             case 'SHA-384': | ||||
|             case 'SHA-512': | ||||
|                 break; | ||||
|             case 'AES-CBC': | ||||
|             case 'AES-GCM': | ||||
|             case 'AES-KW': | ||||
|                 if ( a.length ) r['length'] = a.length; | ||||
|                 break; | ||||
|             case 'HMAC': | ||||
|                 if ( a.hash ) r['hash'] = alg(a.hash); | ||||
|                 if ( a.length ) r['length'] = a.length; | ||||
|                 break; | ||||
|             case 'RSAES-PKCS1-v1_5': | ||||
|                 if ( a.publicExponent ) r['publicExponent'] = new Uint8Array(a.publicExponent); | ||||
|                 if ( a.modulusLength ) r['modulusLength'] = a.modulusLength; | ||||
|                 break; | ||||
|             case 'RSASSA-PKCS1-v1_5': | ||||
|             case 'RSA-OAEP': | ||||
|                 if ( a.hash ) r['hash'] = alg(a.hash); | ||||
|                 if ( a.publicExponent ) r['publicExponent'] = new Uint8Array(a.publicExponent); | ||||
|                 if ( a.modulusLength ) r['modulusLength'] = a.modulusLength; | ||||
|                 break; | ||||
|             default: | ||||
|                 throw new SyntaxError("Bad algorithm name"); | ||||
|         } | ||||
|         return r; | ||||
|     }; | ||||
|  | ||||
|     function jwkAlg ( a ) { | ||||
|         return { | ||||
|             'HMAC': { | ||||
|                 'SHA-1': 'HS1', | ||||
|                 'SHA-256': 'HS256', | ||||
|                 'SHA-384': 'HS384', | ||||
|                 'SHA-512': 'HS512', | ||||
|             }, | ||||
|             'RSASSA-PKCS1-v1_5': { | ||||
|                 'SHA-1': 'RS1', | ||||
|                 'SHA-256': 'RS256', | ||||
|                 'SHA-384': 'RS384', | ||||
|                 'SHA-512': 'RS512', | ||||
|             }, | ||||
|             'RSAES-PKCS1-v1_5': { | ||||
|                 '': 'RSA1_5', | ||||
|             }, | ||||
|             'RSA-OAEP': { | ||||
|                 'SHA-1': 'RSA-OAEP', | ||||
|                 'SHA-256': 'RSA-OAEP-256', | ||||
|             }, | ||||
|             'AES-KW': { | ||||
|                 '128': 'A128KW', | ||||
|                 '192': 'A192KW', | ||||
|                 '256': 'A256KW', | ||||
|             }, | ||||
|             'AES-GCM': { | ||||
|                 '128': 'A128GCM', | ||||
|                 '192': 'A192GCM', | ||||
|                 '256': 'A256GCM', | ||||
|             }, | ||||
|             'AES-CBC': { | ||||
|                 '128': 'A128CBC', | ||||
|                 '192': 'A192CBC', | ||||
|                 '256': 'A256CBC', | ||||
|             }, | ||||
|         }[a.name][ ( a.hash || {} ).name || a.length || '' ]; | ||||
|     } | ||||
|  | ||||
|     function b2jwk ( k ) { | ||||
|         if ( k instanceof ArrayBuffer || k instanceof Uint8Array ) k = JSON.parse( decodeURIComponent( escape( b2s(k) ) ) ); | ||||
|         var jwk = { 'kty': k.kty, 'alg': k.alg, 'ext': k.ext || k.extractable }; | ||||
|         switch ( jwk.kty ) { | ||||
|             case 'oct': | ||||
|                 jwk.k = k.k; | ||||
|             case 'RSA': | ||||
|                 [ 'n', 'e', 'd', 'p', 'q', 'dp', 'dq', 'qi', 'oth' ].forEach( function ( x ) { if ( x in k ) jwk[x] = k[x] } ); | ||||
|                 break; | ||||
|             default: | ||||
|                 throw new TypeError("Unsupported key type"); | ||||
|         } | ||||
|         return jwk; | ||||
|     } | ||||
|  | ||||
|     function jwk2b ( k ) { | ||||
|         var jwk = b2jwk(k); | ||||
|         if ( isIE ) jwk['extractable'] = jwk.ext, delete jwk.ext; | ||||
|         return s2b( unescape( encodeURIComponent( JSON.stringify(jwk) ) ) ).buffer; | ||||
|     } | ||||
|  | ||||
|     function pkcs2jwk ( k ) { | ||||
|         var info = b2der(k), prv = false; | ||||
|         if ( info.length > 2 ) prv = true, info.shift(); // remove version from PKCS#8 PrivateKeyInfo structure | ||||
|         var jwk = { 'ext': true }; | ||||
|         switch ( info[0][0] ) { | ||||
|             case '1.2.840.113549.1.1.1': | ||||
|                 var rsaComp = [ 'n', 'e', 'd', 'p', 'q', 'dp', 'dq', 'qi' ], | ||||
|                     rsaKey  = b2der( info[1] ); | ||||
|                 if ( prv ) rsaKey.shift(); // remove version from PKCS#1 RSAPrivateKey structure | ||||
|                 for ( var i = 0; i < rsaKey.length; i++ ) { | ||||
|                     if ( !rsaKey[i][0] ) rsaKey[i] = rsaKey[i].subarray(1); | ||||
|                     jwk[ rsaComp[i] ] = s2a( b2s( rsaKey[i] ) ); | ||||
|                 } | ||||
|                 jwk['kty'] = 'RSA'; | ||||
|                 break; | ||||
|             default: | ||||
|                 throw new TypeError("Unsupported key type"); | ||||
|         } | ||||
|         return jwk; | ||||
|     } | ||||
|  | ||||
|     function jwk2pkcs ( k ) { | ||||
|         var key, info = [ [ '', null ] ], prv = false; | ||||
|         switch ( k.kty ) { | ||||
|             case 'RSA': | ||||
|                 var rsaComp = [ 'n', 'e', 'd', 'p', 'q', 'dp', 'dq', 'qi' ], | ||||
|                     rsaKey = []; | ||||
|                 for ( var i = 0; i < rsaComp.length; i++ ) { | ||||
|                     if ( !( rsaComp[i] in k ) ) break; | ||||
|                     var b = rsaKey[i] = s2b( a2s( k[ rsaComp[i] ] ) ); | ||||
|                     if ( b[0] & 0x80 ) rsaKey[i] = new Uint8Array(b.length + 1), rsaKey[i].set( b, 1 ); | ||||
|                 } | ||||
|                 if ( rsaKey.length > 2 ) prv = true, rsaKey.unshift( new Uint8Array([0]) ); // add version to PKCS#1 RSAPrivateKey structure | ||||
|                 info[0][0] = '1.2.840.113549.1.1.1'; | ||||
|                 key = rsaKey; | ||||
|                 break; | ||||
|             default: | ||||
|                 throw new TypeError("Unsupported key type"); | ||||
|         } | ||||
|         info.push( new Uint8Array( der2b(key) ).buffer ); | ||||
|         if ( !prv ) info[1] = { 'tag': 0x03, 'value': info[1] }; | ||||
|         else info.unshift( new Uint8Array([0]) ); // add version to PKCS#8 PrivateKeyInfo structure | ||||
|         return new Uint8Array( der2b(info) ).buffer; | ||||
|     } | ||||
|  | ||||
|     var oid2str = { 'KoZIhvcNAQEB': '1.2.840.113549.1.1.1' }, | ||||
|         str2oid = { '1.2.840.113549.1.1.1': 'KoZIhvcNAQEB' }; | ||||
|  | ||||
|     function b2der ( buf, ctx ) { | ||||
|         if ( buf instanceof ArrayBuffer ) buf = new Uint8Array(buf); | ||||
|         if ( !ctx ) ctx = { pos: 0, end: buf.length }; | ||||
|  | ||||
|         if ( ctx.end - ctx.pos < 2 || ctx.end > buf.length ) throw new RangeError("Malformed DER"); | ||||
|  | ||||
|         var tag = buf[ctx.pos++], | ||||
|             len = buf[ctx.pos++]; | ||||
|  | ||||
|         if ( len >= 0x80 ) { | ||||
|             len &= 0x7f; | ||||
|             if ( ctx.end - ctx.pos < len ) throw new RangeError("Malformed DER"); | ||||
|             for ( var xlen = 0; len--; ) xlen <<= 8, xlen |= buf[ctx.pos++]; | ||||
|             len = xlen; | ||||
|         } | ||||
|  | ||||
|         if ( ctx.end - ctx.pos < len ) throw new RangeError("Malformed DER"); | ||||
|  | ||||
|         var rv; | ||||
|  | ||||
|         switch ( tag ) { | ||||
|             case 0x02: // Universal Primitive INTEGER | ||||
|                 rv = buf.subarray( ctx.pos, ctx.pos += len ); | ||||
|                 break; | ||||
|             case 0x03: // Universal Primitive BIT STRING | ||||
|                 if ( buf[ctx.pos++] ) throw new Error( "Unsupported bit string" ); | ||||
|                 len--; | ||||
|             case 0x04: // Universal Primitive OCTET STRING | ||||
|                 rv = new Uint8Array( buf.subarray( ctx.pos, ctx.pos += len ) ).buffer; | ||||
|                 break; | ||||
|             case 0x05: // Universal Primitive NULL | ||||
|                 rv = null; | ||||
|                 break; | ||||
|             case 0x06: // Universal Primitive OBJECT IDENTIFIER | ||||
|                 var oid = btoa( b2s( buf.subarray( ctx.pos, ctx.pos += len ) ) ); | ||||
|                 if ( !( oid in oid2str ) ) throw new Error( "Unsupported OBJECT ID " + oid ); | ||||
|                 rv = oid2str[oid]; | ||||
|                 break; | ||||
|             case 0x30: // Universal Constructed SEQUENCE | ||||
|                 rv = []; | ||||
|                 for ( var end = ctx.pos + len; ctx.pos < end; ) rv.push( b2der( buf, ctx ) ); | ||||
|                 break; | ||||
|             default: | ||||
|                 throw new Error( "Unsupported DER tag 0x" + tag.toString(16) ); | ||||
|         } | ||||
|  | ||||
|         return rv; | ||||
|     } | ||||
|  | ||||
|     function der2b ( val, buf ) { | ||||
|         if ( !buf ) buf = []; | ||||
|  | ||||
|         var tag = 0, len = 0, | ||||
|             pos = buf.length + 2; | ||||
|  | ||||
|         buf.push( 0, 0 ); // placeholder | ||||
|  | ||||
|         if ( val instanceof Uint8Array ) {  // Universal Primitive INTEGER | ||||
|             tag = 0x02, len = val.length; | ||||
|             for ( var i = 0; i < len; i++ ) buf.push( val[i] ); | ||||
|         } | ||||
|         else if ( val instanceof ArrayBuffer ) { // Universal Primitive OCTET STRING | ||||
|             tag = 0x04, len = val.byteLength, val = new Uint8Array(val); | ||||
|             for ( var i = 0; i < len; i++ ) buf.push( val[i] ); | ||||
|         } | ||||
|         else if ( val === null ) { // Universal Primitive NULL | ||||
|             tag = 0x05, len = 0; | ||||
|         } | ||||
|         else if ( typeof val === 'string' && val in str2oid ) { // Universal Primitive OBJECT IDENTIFIER | ||||
|             var oid = s2b( atob( str2oid[val] ) ); | ||||
|             tag = 0x06, len = oid.length; | ||||
|             for ( var i = 0; i < len; i++ ) buf.push( oid[i] ); | ||||
|         } | ||||
|         else if ( val instanceof Array ) { // Universal Constructed SEQUENCE | ||||
|             for ( var i = 0; i < val.length; i++ ) der2b( val[i], buf ); | ||||
|             tag = 0x30, len = buf.length - pos; | ||||
|         } | ||||
|         else if ( typeof val === 'object' && val.tag === 0x03 && val.value instanceof ArrayBuffer ) { // Tag hint | ||||
|             val = new Uint8Array(val.value), tag = 0x03, len = val.byteLength; | ||||
|             buf.push(0); for ( var i = 0; i < len; i++ ) buf.push( val[i] ); | ||||
|             len++; | ||||
|         } | ||||
|         else { | ||||
|             throw new Error( "Unsupported DER value " + val ); | ||||
|         } | ||||
|  | ||||
|         if ( len >= 0x80 ) { | ||||
|             var xlen = len, len = 4; | ||||
|             buf.splice( pos, 0, (xlen >> 24) & 0xff, (xlen >> 16) & 0xff, (xlen >> 8) & 0xff, xlen & 0xff ); | ||||
|             while ( len > 1 && !(xlen >> 24) ) xlen <<= 8, len--; | ||||
|             if ( len < 4 ) buf.splice( pos, 4 - len ); | ||||
|             len |= 0x80; | ||||
|         } | ||||
|  | ||||
|         buf.splice( pos - 2, 2, tag, len ); | ||||
|  | ||||
|         return buf; | ||||
|     } | ||||
|  | ||||
|     function CryptoKey ( key, alg, ext, use ) { | ||||
|         Object.defineProperties( this, { | ||||
|             _key: { | ||||
|                 value: key | ||||
|             }, | ||||
|             type: { | ||||
|                 value: key.type, | ||||
|                 enumerable: true, | ||||
|             }, | ||||
|             extractable: { | ||||
|                 value: (ext === undefined) ? key.extractable : ext, | ||||
|                 enumerable: true, | ||||
|             }, | ||||
|             algorithm: { | ||||
|                 value: (alg === undefined) ? key.algorithm : alg, | ||||
|                 enumerable: true, | ||||
|             }, | ||||
|             usages: { | ||||
|                 value: (use === undefined) ? key.usages : use, | ||||
|                 enumerable: true, | ||||
|             }, | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     function isPubKeyUse ( u ) { | ||||
|         return u === 'verify' || u === 'encrypt' || u === 'wrapKey'; | ||||
|     } | ||||
|  | ||||
|     function isPrvKeyUse ( u ) { | ||||
|         return u === 'sign' || u === 'decrypt' || u === 'unwrapKey'; | ||||
|     } | ||||
|  | ||||
|     [ 'generateKey', 'importKey', 'unwrapKey' ] | ||||
|         .forEach( function ( m ) { | ||||
|             var _fn = _subtle[m]; | ||||
|  | ||||
|             _subtle[m] = function ( a, b, c ) { | ||||
|                 var args = [].slice.call(arguments), | ||||
|                     ka, kx, ku; | ||||
|  | ||||
|                 switch ( m ) { | ||||
|                     case 'generateKey': | ||||
|                         ka = alg(a), kx = b, ku = c; | ||||
|                         break; | ||||
|                     case 'importKey': | ||||
|                         ka = alg(c), kx = args[3], ku = args[4]; | ||||
|                         if ( a === 'jwk' ) { | ||||
|                             b = b2jwk(b); | ||||
|                             if ( !b.alg ) b.alg = jwkAlg(ka); | ||||
|                             if ( !b.key_ops ) b.key_ops = ( b.kty !== 'oct' ) ? ( 'd' in b ) ? ku.filter(isPrvKeyUse) : ku.filter(isPubKeyUse) : ku.slice(); | ||||
|                             args[1] = jwk2b(b); | ||||
|                         } | ||||
|                         break; | ||||
|                     case 'unwrapKey': | ||||
|                         ka = args[4], kx = args[5], ku = args[6]; | ||||
|                         args[2] = c._key; | ||||
|                         break; | ||||
|                 } | ||||
|  | ||||
|                 if ( m === 'generateKey' && ka.name === 'HMAC' && ka.hash ) { | ||||
|                     ka.length = ka.length || { 'SHA-1': 512, 'SHA-256': 512, 'SHA-384': 1024, 'SHA-512': 1024 }[ka.hash.name]; | ||||
|                     return _subtle.importKey( 'raw', _crypto.getRandomValues( new Uint8Array( (ka.length+7)>>3 ) ), ka, kx, ku ); | ||||
|                 } | ||||
|  | ||||
|                 if ( isWebkit && m === 'generateKey' && ka.name === 'RSASSA-PKCS1-v1_5' && ( !ka.modulusLength || ka.modulusLength >= 2048 ) ) { | ||||
|                     a = alg(a), a.name = 'RSAES-PKCS1-v1_5', delete a.hash; | ||||
|                     return _subtle.generateKey( a, true, [ 'encrypt', 'decrypt' ] ) | ||||
|                         .then( function ( k ) { | ||||
|                             return Promise.all([ | ||||
|                                 _subtle.exportKey( 'jwk', k.publicKey ), | ||||
|                                 _subtle.exportKey( 'jwk', k.privateKey ), | ||||
|                             ]); | ||||
|                         }) | ||||
|                         .then( function ( keys ) { | ||||
|                             keys[0].alg = keys[1].alg = jwkAlg(ka); | ||||
|                             keys[0].key_ops = ku.filter(isPubKeyUse), keys[1].key_ops = ku.filter(isPrvKeyUse); | ||||
|                             return Promise.all([ | ||||
|                                 _subtle.importKey( 'jwk', keys[0], ka, kx, keys[0].key_ops ), | ||||
|                                 _subtle.importKey( 'jwk', keys[1], ka, kx, keys[1].key_ops ), | ||||
|                             ]); | ||||
|                         }) | ||||
|                         .then( function ( keys ) { | ||||
|                             return { | ||||
|                                 publicKey: keys[0], | ||||
|                                 privateKey: keys[1], | ||||
|                             }; | ||||
|                         }); | ||||
|                 } | ||||
|  | ||||
|                 if ( ( isWebkit || ( isIE && ( ka.hash || {} ).name === 'SHA-1' ) ) | ||||
|                         && m === 'importKey' && a === 'jwk' && ka.name === 'HMAC' && b.kty === 'oct' ) { | ||||
|                     return _subtle.importKey( 'raw', s2b( a2s(b.k) ), c, args[3], args[4] ); | ||||
|                 } | ||||
|  | ||||
|                 if ( isWebkit && m === 'importKey' && ( a === 'spki' || a === 'pkcs8' ) ) { | ||||
|                     return _subtle.importKey( 'jwk', pkcs2jwk(b), c, args[3], args[4] ); | ||||
|                 } | ||||
|  | ||||
|                 if ( isIE && m === 'unwrapKey' ) { | ||||
|                     return _subtle.decrypt( args[3], c, b ) | ||||
|                         .then( function ( k ) { | ||||
|                             return _subtle.importKey( a, k, args[4], args[5], args[6] ); | ||||
|                         }); | ||||
|                 } | ||||
|  | ||||
|                 var op; | ||||
|                 try { | ||||
|                     op = _fn.apply( _subtle, args ); | ||||
|                 } | ||||
|                 catch ( e ) { | ||||
|                     return Promise.reject(e); | ||||
|                 } | ||||
|  | ||||
|                 if ( isIE ) { | ||||
|                     op = new Promise( function ( res, rej ) { | ||||
|                         op.onabort = | ||||
|                         op.onerror =    function ( e ) { rej(e)               }; | ||||
|                         op.oncomplete = function ( r ) { res(r.target.result) }; | ||||
|                     }); | ||||
|                 } | ||||
|  | ||||
|                 op = op.then( function ( k ) { | ||||
|                     if ( ka.name === 'HMAC' ) { | ||||
|                         if ( !ka.length ) ka.length = 8 * k.algorithm.length; | ||||
|                     } | ||||
|                     if ( ka.name.search('RSA') == 0 ) { | ||||
|                         if ( !ka.modulusLength ) ka.modulusLength = (k.publicKey || k).algorithm.modulusLength; | ||||
|                         if ( !ka.publicExponent ) ka.publicExponent = (k.publicKey || k).algorithm.publicExponent; | ||||
|                     } | ||||
|                     if ( k.publicKey && k.privateKey ) { | ||||
|                         k = { | ||||
|                             publicKey: new CryptoKey( k.publicKey, ka, kx, ku.filter(isPubKeyUse) ), | ||||
|                             privateKey: new CryptoKey( k.privateKey, ka, kx, ku.filter(isPrvKeyUse) ), | ||||
|                         }; | ||||
|                     } | ||||
|                     else { | ||||
|                         k = new CryptoKey( k, ka, kx, ku ); | ||||
|                     } | ||||
|                     return k; | ||||
|                 }); | ||||
|  | ||||
|                 return op; | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|     [ 'exportKey', 'wrapKey' ] | ||||
|         .forEach( function ( m ) { | ||||
|             var _fn = _subtle[m]; | ||||
|  | ||||
|             _subtle[m] = function ( a, b, c ) { | ||||
|                 var args = [].slice.call(arguments); | ||||
|  | ||||
|                 switch ( m ) { | ||||
|                     case 'exportKey': | ||||
|                         args[1] = b._key; | ||||
|                         break; | ||||
|                     case 'wrapKey': | ||||
|                         args[1] = b._key, args[2] = c._key; | ||||
|                         break; | ||||
|                 } | ||||
|  | ||||
|                 if ( ( isWebkit || ( isIE && ( b.algorithm.hash || {} ).name === 'SHA-1' ) ) | ||||
|                         && m === 'exportKey' && a === 'jwk' && b.algorithm.name === 'HMAC' ) { | ||||
|                     args[0] = 'raw'; | ||||
|                 } | ||||
|  | ||||
|                 if ( isWebkit && m === 'exportKey' && ( a === 'spki' || a === 'pkcs8' ) ) { | ||||
|                     args[0] = 'jwk'; | ||||
|                 } | ||||
|  | ||||
|                 if ( isIE && m === 'wrapKey' ) { | ||||
|                     return _subtle.exportKey( a, b ) | ||||
|                         .then( function ( k ) { | ||||
|                             if ( a === 'jwk' ) k = s2b( unescape( encodeURIComponent( JSON.stringify( b2jwk(k) ) ) ) ); | ||||
|                             return  _subtle.encrypt( args[3], c, k ); | ||||
|                         }); | ||||
|                 } | ||||
|  | ||||
|                 var op; | ||||
|                 try { | ||||
|                     op = _fn.apply( _subtle, args ); | ||||
|                 } | ||||
|                 catch ( e ) { | ||||
|                     return Promise.reject(e); | ||||
|                 } | ||||
|  | ||||
|                 if ( isIE ) { | ||||
|                     op = new Promise( function ( res, rej ) { | ||||
|                         op.onabort = | ||||
|                         op.onerror =    function ( e ) { rej(e)               }; | ||||
|                         op.oncomplete = function ( r ) { res(r.target.result) }; | ||||
|                     }); | ||||
|                 } | ||||
|  | ||||
|                 if ( m === 'exportKey' && a === 'jwk' ) { | ||||
|                     op = op.then( function ( k ) { | ||||
|                         if ( ( isWebkit || ( isIE && ( b.algorithm.hash || {} ).name === 'SHA-1' ) ) | ||||
|                                 && b.algorithm.name === 'HMAC') { | ||||
|                             return { 'kty': 'oct', 'alg': jwkAlg(b.algorithm), 'key_ops': b.usages.slice(), 'ext': true, 'k': s2a( b2s(k) ) }; | ||||
|                         } | ||||
|                         k = b2jwk(k); | ||||
|                         if ( !k.alg ) k['alg'] = jwkAlg(b.algorithm); | ||||
|                         if ( !k.key_ops ) k['key_ops'] = ( b.type === 'public' ) ? b.usages.filter(isPubKeyUse) : ( b.type === 'private' ) ? b.usages.filter(isPrvKeyUse) : b.usages.slice(); | ||||
|                         return k; | ||||
|                     }); | ||||
|                 } | ||||
|  | ||||
|                 if ( isWebkit && m === 'exportKey' && ( a === 'spki' || a === 'pkcs8' ) ) { | ||||
|                     op = op.then( function ( k ) { | ||||
|                         k = jwk2pkcs( b2jwk(k) ); | ||||
|                         return k; | ||||
|                     }); | ||||
|                 } | ||||
|  | ||||
|                 return op; | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|     [ 'encrypt', 'decrypt', 'sign', 'verify' ] | ||||
|         .forEach( function ( m ) { | ||||
|             var _fn = _subtle[m]; | ||||
|  | ||||
|             _subtle[m] = function ( a, b, c, d ) { | ||||
|                 if ( isIE && ( !c.byteLength || ( d && !d.byteLength ) ) ) | ||||
|                     throw new Error("Empy input is not allowed"); | ||||
|  | ||||
|                 var args = [].slice.call(arguments), | ||||
|                     ka = alg(a); | ||||
|  | ||||
|                 if ( isIE && m === 'decrypt' && ka.name === 'AES-GCM' ) { | ||||
|                     var tl = a.tagLength >> 3; | ||||
|                     args[2] = (c.buffer || c).slice( 0, c.byteLength - tl ), | ||||
|                     a.tag = (c.buffer || c).slice( c.byteLength - tl ); | ||||
|                 } | ||||
|  | ||||
|                 args[1] = b._key; | ||||
|  | ||||
|                 var op; | ||||
|                 try { | ||||
|                     op = _fn.apply( _subtle, args ); | ||||
|                 } | ||||
|                 catch ( e ) { | ||||
|                     return Promise.reject(e); | ||||
|                 } | ||||
|  | ||||
|                 if ( isIE ) { | ||||
|                     op = new Promise( function ( res, rej ) { | ||||
|                         op.onabort = | ||||
|                         op.onerror = function ( e ) { | ||||
|                             rej(e); | ||||
|                         }; | ||||
|  | ||||
|                         op.oncomplete = function ( r ) { | ||||
|                             var r = r.target.result; | ||||
|  | ||||
|                             if ( m === 'encrypt' && r instanceof AesGcmEncryptResult ) { | ||||
|                                 var c = r.ciphertext, t = r.tag; | ||||
|                                 r = new Uint8Array( c.byteLength + t.byteLength ); | ||||
|                                 r.set( new Uint8Array(c), 0 ); | ||||
|                                 r.set( new Uint8Array(t), c.byteLength ); | ||||
|                                 r = r.buffer; | ||||
|                             } | ||||
|  | ||||
|                             res(r); | ||||
|                         }; | ||||
|                     }); | ||||
|                 } | ||||
|  | ||||
|                 return op; | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|     if ( isIE ) { | ||||
|         var _digest = _subtle.digest; | ||||
|  | ||||
|         _subtle['digest'] = function ( a, b ) { | ||||
|             if ( !b.byteLength ) | ||||
|                 throw new Error("Empy input is not allowed"); | ||||
|  | ||||
|             var op; | ||||
|             try { | ||||
|                 op = _digest.call( _subtle, a, b ); | ||||
|             } | ||||
|             catch ( e ) { | ||||
|                 return Promise.reject(e); | ||||
|             } | ||||
|  | ||||
|             op = new Promise( function ( res, rej ) { | ||||
|                 op.onabort = | ||||
|                 op.onerror =    function ( e ) { rej(e)               }; | ||||
|                 op.oncomplete = function ( r ) { res(r.target.result) }; | ||||
|             }); | ||||
|  | ||||
|             return op; | ||||
|         }; | ||||
|  | ||||
|         global.crypto = Object.create( _crypto, { | ||||
|             getRandomValues: { value: function ( a ) { return _crypto.getRandomValues(a) } }, | ||||
|             subtle:          { value: _subtle }, | ||||
|         }); | ||||
|  | ||||
|         global.CryptoKey = CryptoKey; | ||||
|     } | ||||
|  | ||||
|     if ( isWebkit ) { | ||||
|         _crypto.subtle = _subtle; | ||||
|  | ||||
|         global.Crypto = _Crypto; | ||||
|         global.SubtleCrypto = _SubtleCrypto; | ||||
|         global.CryptoKey = CryptoKey; | ||||
|     } | ||||
| }(this); | ||||
| @@ -34,7 +34,15 @@ | ||||
|  | ||||
| 		"filesize.repository":			"https://github.com/avoidwork/filesize.js.git", | ||||
| 		"filesize.version":				"3.1.3", | ||||
| 		"filesize.commit":				"20b4ac454f9c6236b6611ddd1b9cbe97d0efbbd2" | ||||
| 		"filesize.commit":				"20b4ac454f9c6236b6611ddd1b9cbe97d0efbbd2", | ||||
|  | ||||
| 		"promiz.repository":			"https://github.com/Zolmeister/promiz.git", | ||||
| 		"promiz.version":				"1.0.4", | ||||
| 		"promiz.commit":				"0b87e96be9f3cb444a29b0e5afbdf849455a59b1", | ||||
|  | ||||
| 		"webcryptoshim.repository":		"https://github.com/vibornoff/webcrypto-shim.git", | ||||
| 		"webcryptoshim.version":		"0.1.0", | ||||
| 		"webcryptoshim.commit":			"fb82fe0936adb4813a9b513991266a2bef51d32b" | ||||
| 	}, | ||||
|  | ||||
| 	"html.template": "index_template.html", | ||||
| @@ -81,6 +89,10 @@ | ||||
| 		"-- Filesize/filesize.js", | ||||
| 		"Filesize/filesize.min.js", | ||||
|  | ||||
| 		"-- WEBCRYPTO AND PROMISES POLYFILL FOR IE11", | ||||
| 		"Promiz/promiz.min.js", | ||||
| 		"WebcryptoShim/webcrypto-shim.js", | ||||
|  | ||||
| 		"-- IT WOULD BE NICE TO BE ABLE TO GET RID OF THESE IMPORTS", | ||||
| 		"Clipperz/YUI/Utils.js", | ||||
| 		"Clipperz/YUI/DomHelper.js", | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Dario Chiappetta
					Dario Chiappetta