From bcae1b0299ebb8359de44e4c30fd8877d589fd46 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 26 Aug 2021 18:11:08 +0530 Subject: [PATCH 01/58] prototype QR code generation --- www/common/common-interface.js | 19 +++++++++++++++++++ www/lib/qrcode.min.js | 1 + 2 files changed, 20 insertions(+) create mode 100644 www/lib/qrcode.min.js diff --git a/www/common/common-interface.js b/www/common/common-interface.js index 71a1ed8af..9227c600e 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -1482,5 +1482,24 @@ define([ }); }; +/* QR code generation is synchronous once the library is loaded + so this could be syncronous if we load the library separately. + It could also just return the rendered code instead of displaying + it in an alert. + + to test: + require(['/common/common-interface.js'], function (UI) { UI.createQRCode('https://cryptpad.fr'); }); +*/ + UI.createQRCode = function (data, _cb) { + var cb = Util.once(Util.mkAsync(_cb || Util.noop)); + require(['/lib/qrcode.min.js'], function () { + var div = h('div'); + var code = new window.QRCode(div, data); + // code._el === div + UI.alert(div, cb); + }); + }; + + return UI; }); diff --git a/www/lib/qrcode.min.js b/www/lib/qrcode.min.js new file mode 100644 index 000000000..993e88f39 --- /dev/null +++ b/www/lib/qrcode.min.js @@ -0,0 +1 @@ +var QRCode;!function(){function a(a){this.mode=c.MODE_8BIT_BYTE,this.data=a,this.parsedData=[];for(var b=[],d=0,e=this.data.length;e>d;d++){var f=this.data.charCodeAt(d);f>65536?(b[0]=240|(1835008&f)>>>18,b[1]=128|(258048&f)>>>12,b[2]=128|(4032&f)>>>6,b[3]=128|63&f):f>2048?(b[0]=224|(61440&f)>>>12,b[1]=128|(4032&f)>>>6,b[2]=128|63&f):f>128?(b[0]=192|(1984&f)>>>6,b[1]=128|63&f):b[0]=f,this.parsedData=this.parsedData.concat(b)}this.parsedData.length!=this.data.length&&(this.parsedData.unshift(191),this.parsedData.unshift(187),this.parsedData.unshift(239))}function b(a,b){this.typeNumber=a,this.errorCorrectLevel=b,this.modules=null,this.moduleCount=0,this.dataCache=null,this.dataList=[]}function i(a,b){if(void 0==a.length)throw new Error(a.length+"/"+b);for(var c=0;c=f;f++){var h=0;switch(b){case d.L:h=l[f][0];break;case d.M:h=l[f][1];break;case d.Q:h=l[f][2];break;case d.H:h=l[f][3]}if(h>=e)break;c++}if(c>l.length)throw new Error("Too long data");return c}function s(a){var b=encodeURI(a).toString().replace(/\%[0-9a-fA-F]{2}/g,"a");return b.length+(b.length!=a?3:0)}a.prototype={getLength:function(){return this.parsedData.length},write:function(a){for(var b=0,c=this.parsedData.length;c>b;b++)a.put(this.parsedData[b],8)}},b.prototype={addData:function(b){var c=new a(b);this.dataList.push(c),this.dataCache=null},isDark:function(a,b){if(0>a||this.moduleCount<=a||0>b||this.moduleCount<=b)throw new Error(a+","+b);return this.modules[a][b]},getModuleCount:function(){return this.moduleCount},make:function(){this.makeImpl(!1,this.getBestMaskPattern())},makeImpl:function(a,c){this.moduleCount=4*this.typeNumber+17,this.modules=new Array(this.moduleCount);for(var d=0;d=7&&this.setupTypeNumber(a),null==this.dataCache&&(this.dataCache=b.createData(this.typeNumber,this.errorCorrectLevel,this.dataList)),this.mapData(this.dataCache,c)},setupPositionProbePattern:function(a,b){for(var c=-1;7>=c;c++)if(!(-1>=a+c||this.moduleCount<=a+c))for(var d=-1;7>=d;d++)-1>=b+d||this.moduleCount<=b+d||(this.modules[a+c][b+d]=c>=0&&6>=c&&(0==d||6==d)||d>=0&&6>=d&&(0==c||6==c)||c>=2&&4>=c&&d>=2&&4>=d?!0:!1)},getBestMaskPattern:function(){for(var a=0,b=0,c=0;8>c;c++){this.makeImpl(!0,c);var d=f.getLostPoint(this);(0==c||a>d)&&(a=d,b=c)}return b},createMovieClip:function(a,b,c){var d=a.createEmptyMovieClip(b,c),e=1;this.make();for(var f=0;f=g;g++)for(var h=-2;2>=h;h++)this.modules[d+g][e+h]=-2==g||2==g||-2==h||2==h||0==g&&0==h?!0:!1}},setupTypeNumber:function(a){for(var b=f.getBCHTypeNumber(this.typeNumber),c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[Math.floor(c/3)][c%3+this.moduleCount-8-3]=d}for(var c=0;18>c;c++){var d=!a&&1==(1&b>>c);this.modules[c%3+this.moduleCount-8-3][Math.floor(c/3)]=d}},setupTypeInfo:function(a,b){for(var c=this.errorCorrectLevel<<3|b,d=f.getBCHTypeInfo(c),e=0;15>e;e++){var g=!a&&1==(1&d>>e);6>e?this.modules[e][8]=g:8>e?this.modules[e+1][8]=g:this.modules[this.moduleCount-15+e][8]=g}for(var e=0;15>e;e++){var g=!a&&1==(1&d>>e);8>e?this.modules[8][this.moduleCount-e-1]=g:9>e?this.modules[8][15-e-1+1]=g:this.modules[8][15-e-1]=g}this.modules[this.moduleCount-8][8]=!a},mapData:function(a,b){for(var c=-1,d=this.moduleCount-1,e=7,g=0,h=this.moduleCount-1;h>0;h-=2)for(6==h&&h--;;){for(var i=0;2>i;i++)if(null==this.modules[d][h-i]){var j=!1;g>>e));var k=f.getMask(b,d,h-i);k&&(j=!j),this.modules[d][h-i]=j,e--,-1==e&&(g++,e=7)}if(d+=c,0>d||this.moduleCount<=d){d-=c,c=-c;break}}}},b.PAD0=236,b.PAD1=17,b.createData=function(a,c,d){for(var e=j.getRSBlocks(a,c),g=new k,h=0;h8*l)throw new Error("code length overflow. ("+g.getLengthInBits()+">"+8*l+")");for(g.getLengthInBits()+4<=8*l&&g.put(0,4);0!=g.getLengthInBits()%8;)g.putBit(!1);for(;;){if(g.getLengthInBits()>=8*l)break;if(g.put(b.PAD0,8),g.getLengthInBits()>=8*l)break;g.put(b.PAD1,8)}return b.createBytes(g,e)},b.createBytes=function(a,b){for(var c=0,d=0,e=0,g=new Array(b.length),h=new Array(b.length),j=0;j=0?p.get(q):0}}for(var r=0,m=0;mm;m++)for(var j=0;jm;m++)for(var j=0;j=0;)b^=f.G15<=0;)b^=f.G18<>>=1;return b},getPatternPosition:function(a){return f.PATTERN_POSITION_TABLE[a-1]},getMask:function(a,b,c){switch(a){case e.PATTERN000:return 0==(b+c)%2;case e.PATTERN001:return 0==b%2;case e.PATTERN010:return 0==c%3;case e.PATTERN011:return 0==(b+c)%3;case e.PATTERN100:return 0==(Math.floor(b/2)+Math.floor(c/3))%2;case e.PATTERN101:return 0==b*c%2+b*c%3;case e.PATTERN110:return 0==(b*c%2+b*c%3)%2;case e.PATTERN111:return 0==(b*c%3+(b+c)%2)%2;default:throw new Error("bad maskPattern:"+a)}},getErrorCorrectPolynomial:function(a){for(var b=new i([1],0),c=0;a>c;c++)b=b.multiply(new i([1,g.gexp(c)],0));return b},getLengthInBits:function(a,b){if(b>=1&&10>b)switch(a){case c.MODE_NUMBER:return 10;case c.MODE_ALPHA_NUM:return 9;case c.MODE_8BIT_BYTE:return 8;case c.MODE_KANJI:return 8;default:throw new Error("mode:"+a)}else if(27>b)switch(a){case c.MODE_NUMBER:return 12;case c.MODE_ALPHA_NUM:return 11;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 10;default:throw new Error("mode:"+a)}else{if(!(41>b))throw new Error("type:"+b);switch(a){case c.MODE_NUMBER:return 14;case c.MODE_ALPHA_NUM:return 13;case c.MODE_8BIT_BYTE:return 16;case c.MODE_KANJI:return 12;default:throw new Error("mode:"+a)}}},getLostPoint:function(a){for(var b=a.getModuleCount(),c=0,d=0;b>d;d++)for(var e=0;b>e;e++){for(var f=0,g=a.isDark(d,e),h=-1;1>=h;h++)if(!(0>d+h||d+h>=b))for(var i=-1;1>=i;i++)0>e+i||e+i>=b||(0!=h||0!=i)&&g==a.isDark(d+h,e+i)&&f++;f>5&&(c+=3+f-5)}for(var d=0;b-1>d;d++)for(var e=0;b-1>e;e++){var j=0;a.isDark(d,e)&&j++,a.isDark(d+1,e)&&j++,a.isDark(d,e+1)&&j++,a.isDark(d+1,e+1)&&j++,(0==j||4==j)&&(c+=3)}for(var d=0;b>d;d++)for(var e=0;b-6>e;e++)a.isDark(d,e)&&!a.isDark(d,e+1)&&a.isDark(d,e+2)&&a.isDark(d,e+3)&&a.isDark(d,e+4)&&!a.isDark(d,e+5)&&a.isDark(d,e+6)&&(c+=40);for(var e=0;b>e;e++)for(var d=0;b-6>d;d++)a.isDark(d,e)&&!a.isDark(d+1,e)&&a.isDark(d+2,e)&&a.isDark(d+3,e)&&a.isDark(d+4,e)&&!a.isDark(d+5,e)&&a.isDark(d+6,e)&&(c+=40);for(var k=0,e=0;b>e;e++)for(var d=0;b>d;d++)a.isDark(d,e)&&k++;var l=Math.abs(100*k/b/b-50)/5;return c+=10*l}},g={glog:function(a){if(1>a)throw new Error("glog("+a+")");return g.LOG_TABLE[a]},gexp:function(a){for(;0>a;)a+=255;for(;a>=256;)a-=255;return g.EXP_TABLE[a]},EXP_TABLE:new Array(256),LOG_TABLE:new Array(256)},h=0;8>h;h++)g.EXP_TABLE[h]=1<h;h++)g.EXP_TABLE[h]=g.EXP_TABLE[h-4]^g.EXP_TABLE[h-5]^g.EXP_TABLE[h-6]^g.EXP_TABLE[h-8];for(var h=0;255>h;h++)g.LOG_TABLE[g.EXP_TABLE[h]]=h;i.prototype={get:function(a){return this.num[a]},getLength:function(){return this.num.length},multiply:function(a){for(var b=new Array(this.getLength()+a.getLength()-1),c=0;cf;f++)for(var g=c[3*f+0],h=c[3*f+1],i=c[3*f+2],k=0;g>k;k++)e.push(new j(h,i));return e},j.getRsBlockTable=function(a,b){switch(b){case d.L:return j.RS_BLOCK_TABLE[4*(a-1)+0];case d.M:return j.RS_BLOCK_TABLE[4*(a-1)+1];case d.Q:return j.RS_BLOCK_TABLE[4*(a-1)+2];case d.H:return j.RS_BLOCK_TABLE[4*(a-1)+3];default:return void 0}},k.prototype={get:function(a){var b=Math.floor(a/8);return 1==(1&this.buffer[b]>>>7-a%8)},put:function(a,b){for(var c=0;b>c;c++)this.putBit(1==(1&a>>>b-c-1))},getLengthInBits:function(){return this.length},putBit:function(a){var b=Math.floor(this.length/8);this.buffer.length<=b&&this.buffer.push(0),a&&(this.buffer[b]|=128>>>this.length%8),this.length++}};var l=[[17,14,11,7],[32,26,20,14],[53,42,32,24],[78,62,46,34],[106,84,60,44],[134,106,74,58],[154,122,86,64],[192,152,108,84],[230,180,130,98],[271,213,151,119],[321,251,177,137],[367,287,203,155],[425,331,241,177],[458,362,258,194],[520,412,292,220],[586,450,322,250],[644,504,364,280],[718,560,394,310],[792,624,442,338],[858,666,482,382],[929,711,509,403],[1003,779,565,439],[1091,857,611,461],[1171,911,661,511],[1273,997,715,535],[1367,1059,751,593],[1465,1125,805,625],[1528,1190,868,658],[1628,1264,908,698],[1732,1370,982,742],[1840,1452,1030,790],[1952,1538,1112,842],[2068,1628,1168,898],[2188,1722,1228,958],[2303,1809,1283,983],[2431,1911,1351,1051],[2563,1989,1423,1093],[2699,2099,1499,1139],[2809,2213,1579,1219],[2953,2331,1663,1273]],o=function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){function g(a,b){var c=document.createElementNS("http://www.w3.org/2000/svg",a);for(var d in b)b.hasOwnProperty(d)&&c.setAttribute(d,b[d]);return c}var b=this._htOption,c=this._el,d=a.getModuleCount();Math.floor(b.width/d),Math.floor(b.height/d),this.clear();var h=g("svg",{viewBox:"0 0 "+String(d)+" "+String(d),width:"100%",height:"100%",fill:b.colorLight});h.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xlink","http://www.w3.org/1999/xlink"),c.appendChild(h),h.appendChild(g("rect",{fill:b.colorDark,width:"1",height:"1",id:"template"}));for(var i=0;d>i;i++)for(var j=0;d>j;j++)if(a.isDark(i,j)){var k=g("use",{x:String(i),y:String(j)});k.setAttributeNS("http://www.w3.org/1999/xlink","href","#template"),h.appendChild(k)}},a.prototype.clear=function(){for(;this._el.hasChildNodes();)this._el.removeChild(this._el.lastChild)},a}(),p="svg"===document.documentElement.tagName.toLowerCase(),q=p?o:m()?function(){function a(){this._elImage.src=this._elCanvas.toDataURL("image/png"),this._elImage.style.display="block",this._elCanvas.style.display="none"}function d(a,b){var c=this;if(c._fFail=b,c._fSuccess=a,null===c._bSupportDataURI){var d=document.createElement("img"),e=function(){c._bSupportDataURI=!1,c._fFail&&_fFail.call(c)},f=function(){c._bSupportDataURI=!0,c._fSuccess&&c._fSuccess.call(c)};return d.onabort=e,d.onerror=e,d.onload=f,d.src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==",void 0}c._bSupportDataURI===!0&&c._fSuccess?c._fSuccess.call(c):c._bSupportDataURI===!1&&c._fFail&&c._fFail.call(c)}if(this._android&&this._android<=2.1){var b=1/window.devicePixelRatio,c=CanvasRenderingContext2D.prototype.drawImage;CanvasRenderingContext2D.prototype.drawImage=function(a,d,e,f,g,h,i,j){if("nodeName"in a&&/img/i.test(a.nodeName))for(var l=arguments.length-1;l>=1;l--)arguments[l]=arguments[l]*b;else"undefined"==typeof j&&(arguments[1]*=b,arguments[2]*=b,arguments[3]*=b,arguments[4]*=b);c.apply(this,arguments)}}var e=function(a,b){this._bIsPainted=!1,this._android=n(),this._htOption=b,this._elCanvas=document.createElement("canvas"),this._elCanvas.width=b.width,this._elCanvas.height=b.height,a.appendChild(this._elCanvas),this._el=a,this._oContext=this._elCanvas.getContext("2d"),this._bIsPainted=!1,this._elImage=document.createElement("img"),this._elImage.style.display="none",this._el.appendChild(this._elImage),this._bSupportDataURI=null};return e.prototype.draw=function(a){var b=this._elImage,c=this._oContext,d=this._htOption,e=a.getModuleCount(),f=d.width/e,g=d.height/e,h=Math.round(f),i=Math.round(g);b.style.display="none",this.clear();for(var j=0;e>j;j++)for(var k=0;e>k;k++){var l=a.isDark(j,k),m=k*f,n=j*g;c.strokeStyle=l?d.colorDark:d.colorLight,c.lineWidth=1,c.fillStyle=l?d.colorDark:d.colorLight,c.fillRect(m,n,f,g),c.strokeRect(Math.floor(m)+.5,Math.floor(n)+.5,h,i),c.strokeRect(Math.ceil(m)-.5,Math.ceil(n)-.5,h,i)}this._bIsPainted=!0},e.prototype.makeImage=function(){this._bIsPainted&&d.call(this,a)},e.prototype.isPainted=function(){return this._bIsPainted},e.prototype.clear=function(){this._oContext.clearRect(0,0,this._elCanvas.width,this._elCanvas.height),this._bIsPainted=!1},e.prototype.round=function(a){return a?Math.floor(1e3*a)/1e3:a},e}():function(){var a=function(a,b){this._el=a,this._htOption=b};return a.prototype.draw=function(a){for(var b=this._htOption,c=this._el,d=a.getModuleCount(),e=Math.floor(b.width/d),f=Math.floor(b.height/d),g=[''],h=0;d>h;h++){g.push("");for(var i=0;d>i;i++)g.push('');g.push("")}g.push("
"),c.innerHTML=g.join("");var j=c.childNodes[0],k=(b.width-j.offsetWidth)/2,l=(b.height-j.offsetHeight)/2;k>0&&l>0&&(j.style.margin=l+"px "+k+"px")},a.prototype.clear=function(){this._el.innerHTML=""},a}();QRCode=function(a,b){if(this._htOption={width:256,height:256,typeNumber:4,colorDark:"#000000",colorLight:"#ffffff",correctLevel:d.H},"string"==typeof b&&(b={text:b}),b)for(var c in b)this._htOption[c]=b[c];"string"==typeof a&&(a=document.getElementById(a)),this._android=n(),this._el=a,this._oQRCode=null,this._oDrawing=new q(this._el,this._htOption),this._htOption.text&&this.makeCode(this._htOption.text)},QRCode.prototype.makeCode=function(a){this._oQRCode=new b(r(a,this._htOption.correctLevel),this._htOption.correctLevel),this._oQRCode.addData(a),this._oQRCode.make(),this._el.title=a,this._oDrawing.draw(this._oQRCode),this.makeImage()},QRCode.prototype.makeImage=function(){"function"==typeof this._oDrawing.makeImage&&(!this._android||this._android>=3)&&this._oDrawing.makeImage()},QRCode.prototype.clear=function(){this._oDrawing.clear()},QRCode.CorrectLevel=d}(); \ No newline at end of file From 44f8235ad111d1e3300f0e32ac6f762fa4d7a518 Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 26 Aug 2021 18:14:57 +0530 Subject: [PATCH 02/58] add qrcode.min.js to the dependency changelog --- www/lib/changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/www/lib/changelog.md b/www/lib/changelog.md index 1913b78df..a782c3761 100644 --- a/www/lib/changelog.md +++ b/www/lib/changelog.md @@ -8,4 +8,5 @@ This file is intended to be used as a log of what third-party source we have ven * [jscolor v2.0.5](https://jscolor.com/) for providing a consistent color picker across all browsers * [jquery.ui 1.12.1](https://jqueryui.com/) for its 'autocomplete' extension which is used for our tag picker * [pdfjs](https://mozilla.github.io/pdf.js/) with some minor modifications to prevent CSP errors +* [qrcode.js](https://github.com/davidshimjs/qrcodejs) from [this commit](https://github.com/davidshimjs/qrcodejs/commit/06c7a5e134f116402699f03cda5819e10a0e5787) since the repo doesn't use tags From 9704fb8165e17487eeeca42e9f85bca54dfee50a Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 13 Apr 2022 13:58:12 +0530 Subject: [PATCH 03/58] nearly usable QR code tab in share menu --- www/common/common-interface.js | 2 +- www/common/inner/share.js | 34 ++++++++++++++++++++++++++++------ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/www/common/common-interface.js b/www/common/common-interface.js index bc5979fb1..aa76c4ae6 100644 --- a/www/common/common-interface.js +++ b/www/common/common-interface.js @@ -1492,7 +1492,7 @@ define([ var cb = Util.once(Util.mkAsync(_cb || Util.noop)); require(['/lib/qrcode.min.js'], function () { var div = h('div'); - var code = new window.QRCode(div, data); + /*var code =*/ new window.QRCode(div, data); cb(void 0, div); }, function (err) { cb(err); diff --git a/www/common/inner/share.js b/www/common/inner/share.js index 048f09e37..cc25697b2 100644 --- a/www/common/inner/share.js +++ b/www/common/inner/share.js @@ -13,6 +13,7 @@ define([ '/bower_components/nthen/index.js', '/customize/pages.js', + '/bower_components/file-saver/FileSaver.min.js', '/lib/qrcode.min.js', ], function ($, ApiConfig, Util, Hash, UI, UIElements, Feedback, Modal, h, Clipboard, Messages, nThen, Pages) { @@ -490,25 +491,46 @@ define([ var getQRCode = function (link) { var div = h('div'); - var code = new window.QRCode(div, link); + /*var code =*/ new window.QRCode(div, link); return div; }; var getQRTab = function (Env, data, opts, _cb) { var qr = getQRCode(opts.getLinkValue()); - var link = h('div.cp-share-modal', [ + + var container = h('span#cp-qr-container', [ h('div#cp-qr-link-preview', qr), ]); + var link = h('div.cp-share-modal', [ + container, + ]); + + $(container).css({ + 'background-color': 'white', + display: 'inline-flex', + padding: '5px', + }); + var buttons = [ makeCancelButton(), + { + className: 'primary cp-bar', + name: Messages.share_bar, + onClick: function () { + UI.warn("OOPS: NOT IMPLEMENTED"); // XXX + return true; + }, + }, { className: 'primary cp-nobar', - name: Messages.download_dl, //'PEWPEW', //Messages // XXX + name: Messages.download_dl, iconClass: '.fa.fa-download', onClick: function () { - console.log("TODO SAVE IMAGE"); - UI.warn("NOT IMPLEMENTED"); + qr.querySelector('canvas').toBlob(blob => { + var name = Util.fixFileName((opts.title || 'document') + '-qr.png'); + window.saveAs(blob, name); + }); }, }, ]; @@ -700,7 +722,7 @@ define([ return $rights.parent().find('#cp-embed-link-preview'); }; var getQR = function () { - return $rights.parent().find('#cp-qr-link-preview'); + return $rights.parent().find('#cp-qr-container'); }; // update values for link and embed preview when radio btns change From c762353cad511125b7e2e25e3a68da2a32e1d9d8 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 7 Dec 2022 13:04:07 +0530 Subject: [PATCH 04/58] interpret maxWorkers config in lib/env instead of in worker handler --- lib/env.js | 10 +++++++++- lib/workers/index.js | 17 +---------------- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/lib/env.js b/lib/env.js index bb32f88c0..6519b46d2 100644 --- a/lib/env.js +++ b/lib/env.js @@ -205,7 +205,7 @@ module.exports.create = function (config) { // but it is referenced in Quota domain: config.domain, - maxWorkers: config.maxWorkers, + maxWorkers: undefined, disableIntegratedTasks: config.disableIntegratedTasks || false, disableIntegratedEviction: typeof(config.disableIntegratedEviction) === 'undefined'? true: config.disableIntegratedEviction, lastEviction: +new Date(), @@ -213,6 +213,14 @@ module.exports.create = function (config) { commandTimers: {}, }; + (function () { + var max = config.maxWorkers; + // if the supplied value is not a positive number, leave maxWorkers undefined + // one worker will be created for each CPU core + if (typeof(max) !== 'number' || isNaN(max) || max < 1) { return; } + Env.maxWorkers = max; + }()); + (function () { // mode can be FRESH (default), DEV, or PACKAGE if (process.env.PACKAGE) { diff --git a/lib/workers/index.js b/lib/workers/index.js index 7d82eab0f..6371e5929 100644 --- a/lib/workers/index.js +++ b/lib/workers/index.js @@ -260,22 +260,7 @@ Workers.initialize = function (Env, config, _cb) { }; nThen(function (w) { - const max = config.maxWorkers; - - var limit; - if (typeof(max) !== 'undefined') { - // the admin provided a limit on the number of workers - if (typeof(max) === 'number' && !isNaN(max)) { - if (max < 1) { - Log.info("INSUFFICIENT_MAX_WORKERS", max); - limit = 1; - } - limit = max; - } else { - Log.error("INVALID_MAX_WORKERS", '[' + max + ']'); - } - } - + var limit = Env.maxWorkers; var logged; OS.cpus().forEach(function (cpu, index) { From ed981f2b633f29643fa4c0e69e33a5eee527f6a8 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 7 Dec 2022 13:09:24 +0530 Subject: [PATCH 05/58] generalize recommended version code for easier updates --- lib/env.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/env.js b/lib/env.js index 6519b46d2..9c6e97723 100644 --- a/lib/env.js +++ b/lib/env.js @@ -27,7 +27,9 @@ var deriveSandboxOrigin = function (unsafe, port) { return url.origin; }; +var RECOMMENDED_VERSION = [16, 14, 2]; var isRecentVersion = function () { + var R = RECOMMENDED_VERSION; var V = process.version; if (typeof(V) !== 'string') { return false; } var parts = V.replace(/^v/, '').split('.').map(Number); @@ -35,13 +37,13 @@ var isRecentVersion = function () { if (!parts.every(n => typeof(n) === 'number' && !isNaN(n))) { return false; } - if (parts[0] < 16) { return false; } - if (parts[0] > 16) { return true; } + if (parts[0] < R[0]) { return false; } + if (parts[0] > R[0]) { return true; } // v16 - if (parts[1] < 14) { return false; } - if (parts[1] > 14) { return true; } - if (parts[2] >= 2) { return true; } + if (parts[1] < R[1]) { return false; } + if (parts[1] > R[1]) { return true; } + if (parts[2] >= R[2]) { return true; } return false; }; From afdc4b72d3d1fdc40041019bd68615e5930c8838 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 7 Dec 2022 13:13:19 +0530 Subject: [PATCH 06/58] include whitespace before appended text on checkup page --- www/checkup/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/checkup/main.js b/www/checkup/main.js index 0afd0323d..d396c5f88 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -900,7 +900,7 @@ define([ 'child-src': '', 'frame-src': '', 'script-src': '', - 'connect-src': "This rule restricts which URLs can be loaded by scripts. Overly permissive settings can allow users to be tracking using external resources, while overly restrictive settings may block pages from loading entirely.", + 'connect-src': " This rule restricts which URLs can be loaded by scripts. Overly permissive settings can allow users to be tracked using external resources, while overly restrictive settings may block pages from loading entirely.", 'img-src': '', 'media-src': '', 'worker-src': '', From b32f2826fbfd7e3363264add61a698efeb91ea97 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 7 Dec 2022 13:14:56 +0530 Subject: [PATCH 07/58] expose map of pending queries in Util.response handler so that we can more easily generate 'globally' unique identifiers --- www/common/common-util.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/www/common/common-util.js b/www/common/common-util.js index efcb46227..c4b2b3dab 100644 --- a/www/common/common-util.js +++ b/www/common/common-util.js @@ -160,6 +160,7 @@ }, expect: expect, handle: handle, + _pending: pending, }; }; @@ -187,6 +188,14 @@ .toString(32).replace(/\./g, ''); }; + Util.guid = function (map) { + var id = Util.uid(); + // the guid (globally unique id) is valid if it does already exist in the map + if (typeof(map[id]) === 'undefined') { return id; } + // otherwise try again + return Util.guid(map); + }; + Util.fixHTML = function (str) { if (!str) { return ''; } return str.replace(/[<>&"']/g, function (x) { From c9fd6359aaa3e9c6c9a788c322d10afd5e3e3502 Mon Sep 17 00:00:00 2001 From: Ente Date: Tue, 13 Apr 2021 22:55:40 +0200 Subject: [PATCH 08/58] Send HTTP credentials when fetching blobs With this change media-tag now sends HTTP credentials when fetching blobs. Also changed the example nginx config to send Access-Control-Allow-Credentials CORS headers. For this to work, we can no longer use '*' for Access-Control-Allow-Origin [1][2]: Therefore the example config was changed to set Access-Control-Allow-Origin to the sandbox domain only. Fixes: - #705: Blob fetch fails with 401 Unauthorized when HTTP basic auth is enabled [3] Referenes: [1]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin [2]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSNotSupportingCredentials [3]: https://github.com/xwiki-labs/cryptpad/issues/705 --- docs/example.nginx.conf | 3 +++ www/common/media-tag.js | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/docs/example.nginx.conf b/docs/example.nginx.conf index 1f71fc8b7..94d228c30 100644 --- a/docs/example.nginx.conf +++ b/docs/example.nginx.conf @@ -69,6 +69,7 @@ server { add_header X-XSS-Protection "1; mode=block"; add_header X-Content-Type-Options nosniff; add_header Access-Control-Allow-Origin "${allowed_origins}"; + add_header Access-Control-Allow-Credentials true; # add_header X-Frame-Options "SAMEORIGIN"; # Opt out of Google's FLoC Network @@ -201,6 +202,7 @@ server { location ^~ /blob/ { if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' "${allowed_origins}"; + add_header 'Access-Control-Allow-Credentials' true; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range'; add_header 'Access-Control-Max-Age' 1728000; @@ -211,6 +213,7 @@ server { add_header X-Content-Type-Options nosniff; add_header Cache-Control max-age=31536000; add_header 'Access-Control-Allow-Origin' "${allowed_origins}"; + add_header 'Access-Control-Allow-Credentials' true; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,Content-Length'; add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,Content-Length'; diff --git a/www/common/media-tag.js b/www/common/media-tag.js index 264fbb462..f05b39d9a 100644 --- a/www/common/media-tag.js +++ b/www/common/media-tag.js @@ -244,6 +244,7 @@ var factory = function () { var check = function () { var xhr = new XMLHttpRequest(); xhr.open("HEAD", src); + xhr.withCredentials = true; xhr.onerror = function () { return void cb("XHR_ERROR"); }; xhr.onreadystatechange = function() { if (this.readyState === this.DONE) { @@ -276,6 +277,7 @@ var factory = function () { var fetch = function () { var xhr = new XMLHttpRequest(); xhr.open('GET', src, true); + xhr.withCredentials = true; xhr.responseType = 'arraybuffer'; var progress = function (offset) { @@ -387,6 +389,7 @@ var factory = function () { var fetch = function () { var xhr = new XMLHttpRequest(); xhr.open('GET', src, true); + xhr.withCredentials = true; xhr.setRequestHeader('Range', 'bytes=0-1'); xhr.responseType = 'arraybuffer'; @@ -399,6 +402,7 @@ var factory = function () { var xhr2 = new XMLHttpRequest(); xhr2.open("GET", src, true); + xhr2.withCredentials = true; xhr2.setRequestHeader('Range', 'bytes=2-' + (size + 2)); xhr2.responseType = 'arraybuffer'; xhr2.onload = function () { From 6f19101f42e81bc0278db6a561662a43cbc8ef58 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 20 Dec 2022 14:20:59 +0530 Subject: [PATCH 09/58] big server changes: * use the nodejs cluster module to handle http traffic with multiple threads * listen for websocket traffic on a new port because all such logic needs to share state * proxy websocket URLs from the cluster to the new port so everything is backwards compatible * implement logic for http workers to make requests and stay in sync with the main process * unrelated: define the expected nodejs version in a constant --- lib/decrees.js | 7 +- lib/defaults.js | 6 + lib/env.js | 55 ++++- lib/http-worker.js | 463 +++++++++++++++++++++++++++++++++++++++++ package-lock.json | 256 ++++++++++++++++++++++- package.json | 1 + server.js | 506 +++++++++++++-------------------------------- 7 files changed, 918 insertions(+), 376 deletions(-) create mode 100644 lib/http-worker.js diff --git a/lib/decrees.js b/lib/decrees.js index 1d48f0164..52f587ef9 100644 --- a/lib/decrees.js +++ b/lib/decrees.js @@ -331,7 +331,12 @@ var handleCommand = Decrees.handleCommand = function (Env, line) { throw new Error("DECREE_UNSUPPORTED_COMMAND"); } - return commands[command](Env, args); + var outcome = commands[command](Env, args); + if (outcome) { + // trigger Env change event... + Env.envUpdated.fire(); // XXX + } + return outcome; }; Decrees.createLineHandler = function (Env) { diff --git a/lib/defaults.js b/lib/defaults.js index f22277538..590e65475 100644 --- a/lib/defaults.js +++ b/lib/defaults.js @@ -65,6 +65,12 @@ Default.mainPages = function () { ]; }; +/* The recommmended minimum Node.js version + * ideally managed using NVM and not your system's + * package manager, which usually provides a very outdated version + */ +Default.recommendedVersion = [16,14,2]; + /* By default the CryptPad server will run scheduled tasks every five minutes * If you want to run scheduled tasks in a separate process (like a crontab) * you can disable this behaviour by setting the following value to true diff --git a/lib/env.js b/lib/env.js index 9c6e97723..2dbc20a96 100644 --- a/lib/env.js +++ b/lib/env.js @@ -11,6 +11,7 @@ const Core = require("./commands/core"); const Quota = require("./commands/quota"); const Util = require("./common-util"); const Package = require("../package.json"); +const Default = require("./defaults"); var canonicalizeOrigin = function (s) { if (typeof(s) === 'undefined') { return; } @@ -27,9 +28,8 @@ var deriveSandboxOrigin = function (unsafe, port) { return url.origin; }; -var RECOMMENDED_VERSION = [16, 14, 2]; var isRecentVersion = function () { - var R = RECOMMENDED_VERSION; + var R = Default.recommendedVersion; var V = process.version; if (typeof(V) !== 'string') { return false; } var parts = V.replace(/^v/, '').split('.').map(Number); @@ -70,6 +70,9 @@ module.exports.create = function (config) { } const Env = { + logFeedback: Boolean(config.logFeedback), + mainPages: config.mainPages || Default.mainPages(), + protocol: new URL(httpUnsafeOrigin).protocol, fileHost: config.fileHost || undefined, @@ -103,15 +106,9 @@ module.exports.create = function (config) { apiHeadersCache: undefined, flushCache: function () { - Env.configCache = {}; - Env.broadcastCache = {}; - - Env.officeHeadersCache = undefined; - Env.standardHeadersCache = undefined; - Env.apiHeadersCache = undefined; - Env.FRESH_KEY = +new Date(); if (!(Env.DEV_MODE || Env.FRESH_MODE)) { Env.FRESH_MODE = true; } + Env.cacheFlushed.fire(); if (!Env.Log) { return; } Env.Log.info("UPDATING_FRESH_KEY", Env.FRESH_KEY); }, @@ -343,5 +340,45 @@ module.exports.create = function (config) { console.error("Can't parse admin keys. Please update or fix your config.js file!"); } + Env.envUpdated = Util.mkEvent(); + Env.cacheFlushed = Util.mkEvent(); + return Env; }; + +// don't serialize these things +const BAD = [ + 'Log', + 'envUpdated', + 'cacheFlushed', + 'evictionReports', + 'commandTimers', + 'metadata_cache', + 'channel_cache', + 'cache_checks', + 'intervals', + 'Sessions', + 'netfluxUsers', + 'limits', + 'customLimits', + 'scheduleDecree', + + 'httpServer', + + 'pinStore', + 'msgStore', + 'store', + 'blobStore', +]; + +module.exports.serialize = function (Env) { + return JSON.stringify(Env, function (key, value) { + if (value === Env) { return value; } + if (BAD.includes(key)) { return; } + + if (typeof(value) === 'function') { return; } + //console.log('serializing', { key, value, }); + if (Util.isCircular(value)) { return; } + return value; + }); +}; diff --git a/lib/http-worker.js b/lib/http-worker.js new file mode 100644 index 000000000..130cd5f0d --- /dev/null +++ b/lib/http-worker.js @@ -0,0 +1,463 @@ +const process = require("node:process"); +const Http = require("node:http"); +const Default = require("./defaults"); +const Path = require("node:path"); +const Fs = require("node:fs"); +const nThen = require("nthen"); +const Util = require("./common-util"); +const Logger = require("./log"); + +const DEFAULT_QUERY_TIMEOUT = 5000; +const PID = process.pid; + +const response = Util.response(function (errLabel, info) { + // XXX handle error + console.error({ + _: '// XXX', + errLabel: errLabel, + info: info, + }); +}); + +const guid = () => { + return Util.guid(response._pending); +}; + +const sendMessage = (msg, cb, opt) => { + var txid = guid(); + var timeout = (opt && opt.timeout) || DEFAULT_QUERY_TIMEOUT; + + /// XXX don't nest + var obj = { + pid: PID, + txid: txid, + content: msg, + }; + response.expect(txid, cb, timeout); + process.send(obj); +}; + +const Log = {}; +Logger.levels.forEach(level => { + Log[level] = function (tag, info) { + sendMessage({ + command: 'LOG', + level: level, + tag: tag, + info: info, + }, (err) => { + if (err) { + return void console.error(err); // XXX + } + //console.log("Log statement received"); // XXX + }); + }; +}); + +const EVENTS = {}; + +var Env = JSON.parse(process.env.Env); +EVENTS.ENV_UPDATE = function (data /*, cb */) { // XXX + // XXX log? + Env = JSON.parse(data); +}; + +EVENTS.FLUSH_CACHE = function (data /*, cb */) { // XXX + if (typeof(data) !== 'number') { + return Log.error('INVALID_FRESH_KEY', data); + } + + Env.FRESH_KEY = data; + [ 'configCache', 'broadcastCache', ].forEach(key => { + Env[key] = {}; + }); + [ 'officeHeadersCache', 'standardHeadersCache', 'apiHeadersCache', ].forEach(key => { + Env[key] = undefined; + }); +}; + +process.on('message', msg => { + // XXX +/* + console.log({ + _: 'Message from main process to worker', + msg: msg, + pid: process.pid, + }); +*/ + if (!(msg && msg.txid)) { return; } + //console.log('MESSAGE_RECEIVED', msg); + + + if (msg.type === 'REPLY') { + var txid = msg.txid; + return void response.handle(txid, [msg.error, msg.value]); + } else if (msg.type === 'EVENT') { + // response to event... + // ie. Update Env, flush cache, etc. + var ev = EVENTS[msg.command]; + if (typeof(ev) === 'function') { + return void ev(msg.data, () => {}); + } + } + + console.error("UNHANDLED_MESSAGE", msg); + + // XXX unhandled +}); + + +var applyHeaderMap = function (res, map) { + for (let header in map) { + if (typeof(map[header]) === 'string') { res.setHeader(header, map[header]); } + } +}; + +var EXEMPT = [ + /^\/common\/onlyoffice\/.*\.html.*/, + /^\/(sheet|presentation|doc)\/inner\.html.*/, + /^\/unsafeiframe\/inner\.html.*$/, +]; + +var cacheHeaders = function (Env, key, headers) { + if (Env.DEV_MODE) { return; } // XXX clustering + Env[key] = headers; +}; + +var getHeaders = function (Env, type) { // XXX clustering + var key = type + 'HeadersCache'; + if (Env[key]) { return Env[key]; } + + var headers = {}; + + var custom; // = undefined; //config.httpHeaders; // XXX drop support for this? + // if the admin provided valid http headers then use them + if (custom && typeof(custom) === 'object' && !Array.isArray(custom)) { + headers = Util.clone(custom); + } else { + // otherwise use the default + headers = Default.httpHeaders(Env); + } + + headers['Content-Security-Policy'] = type === 'office'? + Default.padContentSecurity(Env): + Default.contentSecurity(Env); + + if (Env.NO_SANDBOX) { // handles correct configuration for local development + // https://stackoverflow.com/questions/11531121/add-duplicate-http-response-headers-in-nodejs + headers["Cross-Origin-Resource-Policy"] = 'cross-origin'; + headers["Cross-Origin-Embedder-Policy"] = 'require-corp'; + } + + // Don't set CSP headers on /api/ endpoints + // because they aren't necessary and they cause problems + // when duplicated by NGINX in production environments + if (type === 'api') { + cacheHeaders(Env, key, headers); + return headers; + } + + headers["Cross-Origin-Resource-Policy"] = 'cross-origin'; + cacheHeaders(Env, key, headers); + return headers; +}; + +var setHeaders = function (req, res) { + var type; + if (EXEMPT.some(regex => regex.test(req.url))) { + type = 'office'; + } else if (/^\/api\/(broadcast|config)/.test(req.url)) { + type = 'api'; + } else { + type = 'standard'; + } + + var h = getHeaders(Env, type); + applyHeaderMap(res, h); +}; + +const Express = require("express"); +var app = Express(); + +(function () { +if (!Env.logFeedback) { return; } + +const logFeedback = function (url) { + url.replace(/\?(.*?)=/, function (all, fb) { + Log.feedback(fb, ''); + }); +}; + +app.head(/^\/common\/feedback\.html/, function (req, res, next) { + logFeedback(req.url); + next(); +}); +}()); + +const { createProxyMiddleware } = require("http-proxy-middleware"); +const wsProxy = createProxyMiddleware({ + target: 'ws://localhost:3003', // XXX + ws: true, + logLevel: 'error', ///silent', + //pathFilter: '/cryptpad_websocket', +}); + +app.use('/cryptpad_websocket', wsProxy); + +app.use('/blob', function (req, res, next) { + // XXX update atime? + if (req.method === 'HEAD') { + console.log(`Blob head: ${req.url}`); + Express.static(Path.resolve(Env.paths.blob), { + setHeaders: function (res /*, path, stat */) { + res.set('Access-Control-Allow-Origin', Env.enableEmbedding? '*': Env.permittedEmbedders); + res.set('Access-Control-Allow-Headers', 'Content-Length'); + res.set('Access-Control-Expose-Headers', 'Content-Length'); + } + })(req, res, next); + return; + } else { + console.log(`Blob !head: ${req.url}`); + } + next(); +}); + +app.use(function (req, res, next) { + // XXX update atime? + if (req.method === 'OPTIONS' && /\/blob\//.test(req.url)) { + console.log(`Blob options: ${req.url}`); + res.setHeader('Access-Control-Allow-Origin', Env.enableEmbedding? '*': Env.permittedEmbedders); + res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS'); + res.setHeader('Access-Control-Allow-Headers', 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,Access-Control-Allow-Origin'); + res.setHeader('Access-Control-Max-Age', 1728000); + res.setHeader('Content-Type', 'application/octet-stream; charset=utf-8'); + res.setHeader('Content-Length', 0); + res.statusCode = 204; + return void res.end(); + } + + setHeaders(req, res); + if (/[\?\&]ver=[^\/]+$/.test(req.url)) { res.setHeader("Cache-Control", "max-age=31536000"); } + else { res.setHeader("Cache-Control", "no-cache"); } + next(); +}); + +// serve custom app content from the customize directory +// useful for testing pages customized with opengraph data +app.use(Express.static(Path.resolve('./customize/www'))); +app.use(Express.static(Path.resolve('./www'))); + +// FIXME I think this is a regression caused by a recent PR +// correct this hack without breaking the contributor's intended behaviour. + +var mainPages = Env.mainPages || Default.mainPages(); +var mainPagePattern = new RegExp('^\/(' + mainPages.join('|') + ').html$'); +app.get(mainPagePattern, Express.static('./customize')); +app.get(mainPagePattern, Express.static('./customize.dist')); + +app.use("/blob", Express.static(Path.resolve(Env.paths.blob), { + maxAge: Env.DEV_MODE? "0d": "365d" +})); + +// XXX update atime? +app.use("/block", Express.static(Path.resolve(Env.paths.block), { + maxAge: "0d", +})); + +app.use("/customize", Express.static('customize')); +app.use("/customize", Express.static('customize.dist')); +app.use("/customize.dist", Express.static('customize.dist')); +app.use(/^\/[^\/]*$/, Express.static('customize')); +app.use(/^\/[^\/]*$/, Express.static('customize.dist')); + +// if dev mode: never cache +var cacheString = function () { + return (Env.FRESH_KEY? '-' + Env.FRESH_KEY: '') + (Env.DEV_MODE? '-' + (+new Date()): ''); +}; + +var makeRouteCache = function (template, cacheName) { + var cleanUp = {}; + var cache = Env[cacheName] = Env[cacheName] || {}; + + return function (req, res) { + var host = req.headers.host.replace(/\:[0-9]+/, ''); + res.setHeader('Content-Type', 'text/javascript'); + // don't cache anything if you're in dev mode + if (Env.DEV_MODE) { + return void res.send(template(host)); + } + // generate a lookup key for the cache + var cacheKey = host + ':' + cacheString(); + + // FIXME mutable + // we must be able to clear the cache when updating any mutable key + // if there's nothing cached for that key... + if (!cache[cacheKey]) { + // generate the response and cache it in memory + cache[cacheKey] = template(host); + // and create a function to conditionally evict cache entries + // which have not been accessed in the last 20 seconds + cleanUp[cacheKey] = Util.throttle(function () { + delete cleanUp[cacheKey]; + delete cache[cacheKey]; + }, 20000); + } + + // successive calls to this function + cleanUp[cacheKey](); + return void res.send(cache[cacheKey]); + }; +}; + +var serveConfig = makeRouteCache(function (/* host */) { // XXX + return [ + 'define(function(){', + 'return ' + JSON.stringify({ + requireConf: { + waitSeconds: 600, + urlArgs: 'ver=' + Env.version + cacheString(), + }, + removeDonateButton: (Env.removeDonateButton === true), + allowSubscriptions: (Env.allowSubscriptions === true), + websocketPath: Env.websocketPath, + httpUnsafeOrigin: Env.httpUnsafeOrigin, + adminEmail: Env.adminEmail, + adminKeys: Env.admins, + inactiveTime: Env.inactiveTime, + supportMailbox: Env.supportMailbox, + defaultStorageLimit: Env.defaultStorageLimit, + maxUploadSize: Env.maxUploadSize, + premiumUploadSize: Env.premiumUploadSize, + restrictRegistration: Env.restrictRegistration, + httpSafeOrigin: Env.httpSafeOrigin, + enableEmbedding: Env.enableEmbedding, + fileHost: Env.fileHost, + shouldUpdateNode: Env.shouldUpdateNode || undefined, + listMyInstance: Env.listMyInstance, + accounts_api: Env.accounts_api, + }, null, '\t'), + '});' + ].join(';\n'); +}, 'configCache'); + +var serveBroadcast = makeRouteCache(function (/* host */) { // XXX + var maintenance = Env.maintenance; + if (maintenance && maintenance.end && maintenance.end < (+new Date())) { + maintenance = undefined; + } + return [ + 'define(function(){', + 'return ' + JSON.stringify({ + lastBroadcastHash: Env.lastBroadcastHash, + surveyURL: Env.surveyURL, + maintenance: maintenance + }, null, '\t'), + '});' + ].join(';\n'); +}, 'broadcastCache'); + +app.get('/api/config', serveConfig); +app.get('/api/broadcast', serveBroadcast); + +var Define = function (obj) { + return `define(function (){ + return ${JSON.stringify(obj, null, '\t')}; +});`; +}; + +app.get('/api/instance', function (req, res) { // XXX use caching? + res.setHeader('Content-Type', 'text/javascript'); + res.send(Define({ + name: Env.instanceName, + description: Env.instanceDescription, + location: Env.instanceJurisdiction, + notice: Env.instanceNotice, + })); +}); + +var four04_path = Path.resolve('./customize.dist/404.html'); +var fivehundred_path = Path.resolve('./customize.dist/500.html'); +var custom_four04_path = Path.resolve('./customize/404.html'); +var custom_fivehundred_path = Path.resolve('./customize/500.html'); + +var send404 = function (res, path) { + if (!path && path !== four04_path) { path = four04_path; } + Fs.exists(path, function (exists) { + res.setHeader('Content-Type', 'text/html; charset=utf-8'); + if (exists) { return Fs.createReadStream(path).pipe(res); } + send404(res); + }); +}; +var send500 = function (res, path) { + if (!path && path !== fivehundred_path) { path = fivehundred_path; } + Fs.exists(path, function (exists) { + res.setHeader('Content-Type', 'text/html; charset=utf-8'); + if (exists) { return Fs.createReadStream(path).pipe(res); } + send500(res); + }); +}; + +app.get('/api/updatequota', function (req, res) { + if (!Env.accounts_api) { + res.status(404); + return void send404(res); + } + sendMessage({ // XXX test this + command: 'UPDATE_QUOTA', + }, (err /*, value */) => { + if (err) { + res.status(500); + return void send500(res); + } + res.send(); + }); +}); + +app.get('/api/profiling', function (req, res) { + if (!Env.enableProfiling) { return void send404(res); } + sendMessage({ // XXX test this + command: 'GET_PROFILING_DATA', + }, (err /*, value */) => { // XXX + if (err) { + res.status(500); + return void send500(res); + } + res.setHeader('Content-Type', 'text/javascript'); + res.send(JSON.stringify({ + bytesWritten: Env.bytesWritten, + })); + }); +}); + +app.use(function (req, res /*, next */) { + Log.info('HTTP_404', req.url); + res.status(404); + send404(res, custom_four04_path); +}); + +// default message for thrown errors in ExpressJS routes +app.use(function (err, req, res /*, next*/) { + Log.error('EXPRESSJS_ROUTING', { + error: err.stack || err, + }); + res.status(500); + send500(res, custom_fivehundred_path); +}); + +var server = Http.createServer(app); + +nThen(function (w) { + server.listen(3000, w()); + if (Env.httpSafePort) { + server.listen(3001, w()); // if (Env.httpSafePort) {... + } + server.on('upgrade', function (req, socket, head) { + //console.log("This should only happen in a dev environment"); // XXX + wsProxy.upgrade(req, socket, head); + }); +}).nThen(function () { + // XXX inform the parent process that this worker is ready + + +}); + diff --git a/package-lock.json b/package-lock.json index 524ddd868..35e40873d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "express": "~4.16.0", "fs-extra": "^7.0.0", "get-folder-size": "^2.0.1", + "http-proxy-middleware": "^2.0.6", "netflux-websocket": "^0.1.20", "nthen": "0.1.8", "pull-stream": "^3.6.1", @@ -73,6 +74,14 @@ "@types/node": "*" } }, + "node_modules/@types/http-proxy": { + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz", + "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/minimatch": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", @@ -82,8 +91,7 @@ "node_modules/@types/node": { "version": "17.0.33", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.33.tgz", - "integrity": "sha512-miWq2m2FiQZmaHfdZNcbpp9PuXg34W5JZ5CrJ/BaS70VuhoJENBEQybeiYSaPBRNq6KQGnjfEnc/F3PN++D+XQ==", - "dev": true + "integrity": "sha512-miWq2m2FiQZmaHfdZNcbpp9PuXg34W5JZ5CrJ/BaS70VuhoJENBEQybeiYSaPBRNq6KQGnjfEnc/F3PN++D+XQ==" }, "node_modules/accepts": { "version": "1.3.8", @@ -933,6 +941,11 @@ "node": ">= 0.6" } }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, "node_modules/exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -1277,6 +1290,25 @@ "deprecated": "flatten is deprecated in favor of utility frameworks such as lodash.", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -1569,6 +1601,95 @@ "node": ">= 0.6" } }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/http-proxy-middleware/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/http-proxy-middleware/node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/http-proxy-middleware/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/http-proxy-middleware/node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/http-proxy-middleware/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -1741,7 +1862,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -1750,7 +1870,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -1782,6 +1901,17 @@ "node": ">=0.10.0" } }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -2502,6 +2632,17 @@ "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", @@ -2740,6 +2881,11 @@ "node": ">= 6" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, "node_modules/resolve-from": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", @@ -3706,6 +3852,14 @@ "@types/node": "*" } }, + "@types/http-proxy": { + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz", + "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==", + "requires": { + "@types/node": "*" + } + }, "@types/minimatch": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", @@ -3715,8 +3869,7 @@ "@types/node": { "version": "17.0.33", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.33.tgz", - "integrity": "sha512-miWq2m2FiQZmaHfdZNcbpp9PuXg34W5JZ5CrJ/BaS70VuhoJENBEQybeiYSaPBRNq6KQGnjfEnc/F3PN++D+XQ==", - "dev": true + "integrity": "sha512-miWq2m2FiQZmaHfdZNcbpp9PuXg34W5JZ5CrJ/BaS70VuhoJENBEQybeiYSaPBRNq6KQGnjfEnc/F3PN++D+XQ==" }, "accepts": { "version": "1.3.8", @@ -4410,6 +4563,11 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, "exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -4694,6 +4852,11 @@ "integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg==", "dev": true }, + "follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -4931,6 +5094,68 @@ "statuses": ">= 1.4.0 < 2" } }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "requires": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "dependencies": { + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + } + } + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -5065,14 +5290,12 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "requires": { "is-extglob": "^2.1.1" } @@ -5097,6 +5320,11 @@ } } }, + "is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==" + }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -5689,6 +5917,11 @@ "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", "dev": true }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + }, "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", @@ -5877,6 +6110,11 @@ "uuid": "^3.3.2" } }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, "resolve-from": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", diff --git a/package.json b/package.json index 8f624fcdd..d52d4ff51 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "express": "~4.16.0", "fs-extra": "^7.0.0", "get-folder-size": "^2.0.1", + "http-proxy-middleware": "^2.0.6", "netflux-websocket": "^0.1.20", "nthen": "0.1.8", "pull-stream": "^3.6.1", diff --git a/server.js b/server.js index cbed35cf7..a921759e8 100644 --- a/server.js +++ b/server.js @@ -4,25 +4,20 @@ var Express = require('express'); var Http = require('http'); var Fs = require('fs'); -var Path = require("path"); +//var Path = require("path"); var nThen = require("nthen"); var Util = require("./lib/common-util"); -var Default = require("./lib/defaults"); var Keys = require("./lib/keys"); +var OS = require("node:os"); +var Cluster = require("node:cluster"); var config = require("./lib/load-config"); -var Env = require("./lib/env").create(config); +var Environment = require("./lib/env"); +var Env = Environment.create(config); +var Default = require("./lib/defaults"); var app = Express(); -var fancyURL = function (domain, path) { - try { - if (domain && path) { return new URL(path, domain).href; } - return new URL(domain); - } catch (err) {} - return false; -}; - (function () { // you absolutely must provide an 'httpUnsafeOrigin' (a truthy string) if (typeof(Env.httpUnsafeOrigin) !== 'string' || !Env.httpUnsafeOrigin.trim()) { @@ -30,320 +25,29 @@ var fancyURL = function (domain, path) { } }()); -var applyHeaderMap = function (res, map) { - for (let header in map) { - if (typeof(map[header]) === 'string') { res.setHeader(header, map[header]); } - } +var COMMANDS = {}; + +COMMANDS.LOG = function (msg, cb) { + var level = msg.level; + Env.Log[level](msg.tag, msg.info); + cb(); }; -var EXEMPT = [ - /^\/common\/onlyoffice\/.*\.html.*/, - /^\/(sheet|presentation|doc)\/inner\.html.*/, - /^\/unsafeiframe\/inner\.html.*$/, -]; - -var cacheHeaders = function (Env, key, headers) { - if (Env.DEV_MODE) { return; } - Env[key] = headers; -}; - -var getHeaders = function (Env, type) { - var key = type + 'HeadersCache'; - if (Env[key]) { return Env[key]; } - - var headers = {}; - - var custom = config.httpHeaders; - // if the admin provided valid http headers then use them - if (custom && typeof(custom) === 'object' && !Array.isArray(custom)) { - headers = Util.clone(custom); - } else { - // otherwise use the default - headers = Default.httpHeaders(Env); - } - - headers['Content-Security-Policy'] = type === 'office'? - Default.padContentSecurity(Env): - Default.contentSecurity(Env); - - if (Env.NO_SANDBOX) { // handles correct configuration for local development - // https://stackoverflow.com/questions/11531121/add-duplicate-http-response-headers-in-nodejs - headers["Cross-Origin-Resource-Policy"] = 'cross-origin'; - headers["Cross-Origin-Embedder-Policy"] = 'require-corp'; - } - - // Don't set CSP headers on /api/ endpoints - // because they aren't necessary and they cause problems - // when duplicated by NGINX in production environments - if (type === 'api') { - cacheHeaders(Env, key, headers); - return headers; - } - - headers["Cross-Origin-Resource-Policy"] = 'cross-origin'; - cacheHeaders(Env, key, headers); - return headers; -}; - -var setHeaders = function (req, res) { - var type; - if (EXEMPT.some(regex => regex.test(req.url))) { - type = 'office'; - } else if (/^\/api\/(broadcast|config)/.test(req.url)) { - type = 'api'; - } else { - type = 'standard'; - } - - var h = getHeaders(Env, type); - //console.log('PEWPEW', type, h); - applyHeaderMap(res, h); -}; - -(function () { -if (!config.logFeedback) { return; } - -const logFeedback = function (url) { - url.replace(/\?(.*?)=/, function (all, fb) { - if (!config.log) { return; } - config.log.feedback(fb, ''); - }); -}; - -app.head(/^\/common\/feedback\.html/, function (req, res, next) { - logFeedback(req.url); - next(); -}); -}()); - -app.use('/blob', function (req, res, next) { - if (req.method === 'HEAD') { - Express.static(Path.join(__dirname, Env.paths.blob), { - setHeaders: function (res, path, stat) { - res.set('Access-Control-Allow-Origin', Env.enableEmbedding? '*': Env.permittedEmbedders); - res.set('Access-Control-Allow-Headers', 'Content-Length'); - res.set('Access-Control-Expose-Headers', 'Content-Length'); - } - })(req, res, next); - return; - } - next(); -}); - -app.use(function (req, res, next) { - if (req.method === 'OPTIONS' && /\/blob\//.test(req.url)) { - res.setHeader('Access-Control-Allow-Origin', Env.enableEmbedding? '*': Env.permittedEmbedders); - res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS'); - res.setHeader('Access-Control-Allow-Headers', 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,Access-Control-Allow-Origin'); - res.setHeader('Access-Control-Max-Age', 1728000); - res.setHeader('Content-Type', 'application/octet-stream; charset=utf-8'); - res.setHeader('Content-Length', 0); - res.statusCode = 204; - return void res.end(); - } - - setHeaders(req, res); - if (/[\?\&]ver=[^\/]+$/.test(req.url)) { res.setHeader("Cache-Control", "max-age=31536000"); } - else { res.setHeader("Cache-Control", "no-cache"); } - next(); -}); - -// serve custom app content from the customize directory -// useful for testing pages customized with opengraph data -app.use(Express.static(__dirname + '/customize/www')); -app.use(Express.static(__dirname + '/www')); - -// FIXME I think this is a regression caused by a recent PR -// correct this hack without breaking the contributor's intended behaviour. - -var mainPages = config.mainPages || Default.mainPages(); -var mainPagePattern = new RegExp('^\/(' + mainPages.join('|') + ').html$'); -app.get(mainPagePattern, Express.static(__dirname + '/customize')); -app.get(mainPagePattern, Express.static(__dirname + '/customize.dist')); - -app.use("/blob", Express.static(Path.join(__dirname, Env.paths.blob), { - maxAge: Env.DEV_MODE? "0d": "365d" -})); -app.use("/datastore", Express.static(Path.join(__dirname, Env.paths.data), { - maxAge: "0d" -})); -app.use("/block", Express.static(Path.join(__dirname, Env.paths.block), { - maxAge: "0d", -})); - -app.use("/customize", Express.static(__dirname + '/customize')); -app.use("/customize", Express.static(__dirname + '/customize.dist')); -app.use("/customize.dist", Express.static(__dirname + '/customize.dist')); -app.use(/^\/[^\/]*$/, Express.static('customize')); -app.use(/^\/[^\/]*$/, Express.static('customize.dist')); - -// if dev mode: never cache -var cacheString = function () { - return (Env.FRESH_KEY? '-' + Env.FRESH_KEY: '') + (Env.DEV_MODE? '-' + (+new Date()): ''); -}; - -var makeRouteCache = function (template, cacheName) { - var cleanUp = {}; - var cache = Env[cacheName] = Env[cacheName] || {}; - - return function (req, res) { - var host = req.headers.host.replace(/\:[0-9]+/, ''); - res.setHeader('Content-Type', 'text/javascript'); - // don't cache anything if you're in dev mode - if (Env.DEV_MODE) { - return void res.send(template(host)); - } - // generate a lookup key for the cache - var cacheKey = host + ':' + cacheString(); - - // FIXME mutable - // we must be able to clear the cache when updating any mutable key - // if there's nothing cached for that key... - if (!cache[cacheKey]) { - // generate the response and cache it in memory - cache[cacheKey] = template(host); - // and create a function to conditionally evict cache entries - // which have not been accessed in the last 20 seconds - cleanUp[cacheKey] = Util.throttle(function () { - delete cleanUp[cacheKey]; - delete cache[cacheKey]; - }, 20000); - } - - // successive calls to this function - cleanUp[cacheKey](); - return void res.send(cache[cacheKey]); - }; -}; - -var serveConfig = makeRouteCache(function (host) { - return [ - 'define(function(){', - 'return ' + JSON.stringify({ - requireConf: { - waitSeconds: 600, - urlArgs: 'ver=' + Env.version + cacheString(), - }, - removeDonateButton: (Env.removeDonateButton === true), - allowSubscriptions: (Env.allowSubscriptions === true), - websocketPath: Env.websocketPath, - httpUnsafeOrigin: Env.httpUnsafeOrigin, - adminEmail: Env.adminEmail, - adminKeys: Env.admins, - inactiveTime: Env.inactiveTime, - supportMailbox: Env.supportMailbox, - defaultStorageLimit: Env.defaultStorageLimit, - maxUploadSize: Env.maxUploadSize, - premiumUploadSize: Env.premiumUploadSize, - restrictRegistration: Env.restrictRegistration, - httpSafeOrigin: Env.httpSafeOrigin, - enableEmbedding: Env.enableEmbedding, - fileHost: Env.fileHost, - shouldUpdateNode: Env.shouldUpdateNode || undefined, - listMyInstance: Env.listMyInstance, - accounts_api: Env.accounts_api, - }, null, '\t'), - '});' - ].join(';\n') -}, 'configCache'); - -var serveBroadcast = makeRouteCache(function (host) { - var maintenance = Env.maintenance; - if (maintenance && maintenance.end && maintenance.end < (+new Date())) { - maintenance = undefined; - } - return [ - 'define(function(){', - 'return ' + JSON.stringify({ - lastBroadcastHash: Env.lastBroadcastHash, - surveyURL: Env.surveyURL, - maintenance: maintenance - }, null, '\t'), - '});' - ].join(';\n') -}, 'broadcastCache'); - -app.get('/api/config', serveConfig); -app.get('/api/broadcast', serveBroadcast); - -var define = function (obj) { - return `define(function (){ - return ${JSON.stringify(obj, null, '\t')}; -});` -}; - -app.get('/api/instance', function (req, res) { // XXX use caching? - res.setHeader('Content-Type', 'text/javascript'); - res.send(define({ - name: Env.instanceName, - description: Env.instanceDescription, - location: Env.instanceJurisdiction, - notice: Env.instanceNotice, - })); -}); - -var four04_path = Path.resolve(__dirname + '/customize.dist/404.html'); -var fivehundred_path = Path.resolve(__dirname + '/customize.dist/500.html'); -var custom_four04_path = Path.resolve(__dirname + '/customize/404.html'); -var custom_fivehundred_path = Path.resolve(__dirname + '/customize/500.html'); - -var send404 = function (res, path) { - if (!path && path !== four04_path) { path = four04_path; } - Fs.exists(path, function (exists) { - res.setHeader('Content-Type', 'text/html; charset=utf-8'); - if (exists) { return Fs.createReadStream(path).pipe(res); } - send404(res); - }); -}; -var send500 = function (res, path) { - if (!path && path !== fivehundred_path) { path = fivehundred_path; } - Fs.exists(path, function (exists) { - res.setHeader('Content-Type', 'text/html; charset=utf-8'); - if (exists) { return Fs.createReadStream(path).pipe(res); } - send500(res); - }); -}; - -app.get('/api/updatequota', function (req, res) { - if (!Env.accounts_api) { - res.status(404); - return void send404(res); - } +COMMANDS.UPDATE_QUOTA = function (msg, cb) { var Quota = require("./lib/commands/quota"); Quota.updateCachedLimits(Env, (e) => { if (e) { Env.Log.warn('UPDATE_QUOTA_ERR', e); - res.status(500); - return void send500(res); + return void cb(err); } Env.Log.info('QUOTA_UPDATED', {}); - res.send(); + cb(); }); -}); +}; -app.get('/api/profiling', function (req, res, next) { - if (!Env.enableProfiling) { return void send404(res); } - res.setHeader('Content-Type', 'text/javascript'); - res.send(JSON.stringify({ - bytesWritten: Env.bytesWritten, - })); -}); - -app.use(function (req, res, next) { - res.status(404); - send404(res, custom_four04_path); -}); - -// default message for thrown errors in ExpressJS routes -app.use(function (err, req, res, next) { - Env.Log.error('EXPRESSJS_ROUTING', { - error: err.stack || err, - }); - res.status(500); - send500(res, custom_fivehundred_path); -}); - -var httpServer = Env.httpServer = Http.createServer(app); +COMMANDS.GET_PROFILING_DATA = function (msg, cb) { + cb(void 0, Env.bytesWritten); +}; nThen(function (w) { Fs.exists(__dirname + "/customize", w(function (e) { @@ -351,51 +55,139 @@ nThen(function (w) { console.log("CryptPad is customizable, see customize.dist/readme.md for details"); })); }).nThen(function (w) { - httpServer.listen(Env.httpPort, Env.httpAddress, function(){ - var host = Env.httpAddress; - var hostName = !host.indexOf(':') ? '[' + host + ']' : host; - - var port = Env.httpPort; - var ps = port === 80? '': ':' + port; - - var roughAddress = 'http://' + hostName + ps; - var betterAddress = fancyURL(Env.httpUnsafeOrigin); - - if (betterAddress) { - console.log('Serving content for %s via %s.\n', betterAddress, roughAddress); - } else { - console.log('Serving content via %s.\n', roughAddress); - } - if (!Env.admins.length) { - console.log("Your instance is not correctly configured for safe use in production.\nSee %s for more information.\n", - fancyURL(Env.httpUnsafeOrigin, '/checkup/') || 'https://your-domain.com/checkup/' - ); - } - }); - - if (Env.httpSafePort) { - Http.createServer(app).listen(Env.httpSafePort, Env.httpAddress, w()); - } -}).nThen(function () { - var wsConfig = { server: httpServer }; - - // Initialize logging then start the API server - require("./lib/log").create(config, function (_log) { + require("./lib/log").create(config, w(function (_log) { Env.Log = _log; config.log = _log; + })); +}).nThen(function (w) { + Env.httpServer = Http.createServer(app); + Env.httpServer.listen(3003, '::', w(function () { // XXX 3003 should not be hardcoded + console.log("Socket server is listening on 3003"); // XXX + })); +}).nThen(function (w) { + var limit = Env.maxWorkers; + var workerState = { + Env: Environment.serialize(Env), + }; - if (Env.shouldUpdateNode) { - Env.Log.warn("NODEJS_OLD_VERSION", { - message: `The CryptPad development team recommends using at least NodeJS v16.14.2`, - currentVersion: process.version, - }); - } - - if (Env.OFFLINE_MODE) { return; } - if (Env.websocketPath) { return; } - - require("./lib/api").create(Env); + Cluster.setupPrimary({ + exec: './lib/http-worker.js', + args: [], }); + + var launchWorker = (online) => { + var worker = Cluster.fork(workerState); + worker.on('online', () => { + online(); + }); + + worker.on('message', msg => { + if (!msg) { return; } + var txid = msg.txid; + var content = msg.content; // XXX don't nest + if (!content) { return; } // XXX + + var command = COMMANDS[content.command]; + if (typeof(command) !== 'function') { + return void Env.Log.error('UNHANDLED_HTTP_WORKER_COMMAND', msg); + } + + const cb = Util.once(Util.mkAsync(function (err, value) { + value = Math.random(); + worker.send({ + type: 'REPLY', + error: Util.serializeError(err), + txid: txid, + pid: msg.pid, + value: value, // XXX + }); + })); + + command(content, cb); + }); + }; + + var txids = {}; + + var sendCommand = (worker, command, data /*, cb */) => { + worker.send({ + type: 'EVENT', + txid: Util.guid(txids), + command: command, + data: data, + }); + }; + + var broadcast = (command, data, cb) => { + cb = cb; // XXX nThen/concurrency + for (const worker of Object.values(Cluster.workers)) { + sendCommand(worker, command, data /*, cb */); + } + }; + + var throttledEnvChange = Util.throttle(function () { + Env.Log.info('WORKER_ENV_UPDATE', 'Updating HTTP workers with latest state'); // XXX + broadcast('ENV_UPDATE', Environment.serialize(Env)); //JSON.stringify(Env)); + }, 250); + + var throttledCacheFlush = Util.throttle(function () { + Env.Log.info('WORKER_CACHE_FLUSH', 'Instructing HTTP workers to flush cache'); // XXX + broadcast('FLUSH_CACHE', Env.FRESH_KEY); + }, 250); + + Env.envUpdated.reg(throttledEnvChange); + Env.cacheFlushed.reg(throttledCacheFlush); + + var logCPULimit = Util.once(function (index) { + Env.Log.info('HTTP_WORKER_LIMIT', `(Opting not to use available CPUs beyond ${index})`); + }); + + OS.cpus().forEach((cpu, index) => { + if (limit && index >= limit) { + return; + //return logCPULimit(index); + } + launchWorker(w()); + }); +}).nThen(function (w) { + var fancyURL = function (domain, path) { + try { + if (domain && path) { return new URL(path, domain).href; } + return new URL(domain); + } catch (err) {} + return false; + }; + + var host = Env.httpAddress; + var hostName = !host.indexOf(':') ? '[' + host + ']' : host; + + var port = Env.httpPort; + var ps = port === 80? '': ':' + port; + + var roughAddress = 'http://' + hostName + ps; + var betterAddress = fancyURL(Env.httpUnsafeOrigin); + + if (betterAddress) { + console.log('Serving content for %s via %s.\n', betterAddress, roughAddress); + } else { + console.log('Serving content via %s.\n', roughAddress); + } + if (!Env.admins.length) { + console.log("Your instance is not correctly configured for safe use in production.\nSee %s for more information.\n", + fancyURL(Env.httpUnsafeOrigin, '/checkup/') || 'https://your-domain.com/checkup/' + ); + } +}).nThen(function () { + if (Env.shouldUpdateNode) { + Env.Log.warn("NODEJS_OLD_VERSION", { + message: `The CryptPad development team recommends using at least NodeJS v${Default.recommendedVersion.join('.')}`, + currentVersion: process.version, + }); + } + + if (Env.OFFLINE_MODE) { return; } + //if (Env.websocketPath) { return; } // XXX + + require("./lib/api").create(Env); }); - From 7e4518b43d7efed1fad30c3c6e7627cb25a5d6fe Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 20 Dec 2022 16:29:38 +0530 Subject: [PATCH 10/58] More server cleanup: * make the websocket port configurable * reorder some tasks at launch time to use more consistent logging * relaunch http workers if they crash * refuse to launch if httpUnsafeOrigin cannot be parsed as a URL * fix a path issue reintroduced by a git merge --- config/config.example.js | 13 ++++++ lib/env.js | 6 +++ server.js | 90 +++++++++++++++++++++------------------- 3 files changed, 67 insertions(+), 42 deletions(-) diff --git a/config/config.example.js b/config/config.example.js index b78bf8fc3..4f289b56b 100644 --- a/config/config.example.js +++ b/config/config.example.js @@ -92,6 +92,19 @@ module.exports = { */ //httpSafePort: 3001, +/* Websockets need to be exposed on a separate port from the rest of + * the platform's HTTP traffic. Port 3003 is used by default. + * You can change this to a different port if it is in use by a + * different service, but under most circumstances you can leave this + * commented and it will work. + * + * In production environments, your reverse proxy (usually NGINX) + * will need to forward websocket traffic (/cryptpad_websocket) + * to this port. + * + */ + // websocketPort: 3003, + /* CryptPad will launch a child process for every core available * in order to perform CPU-intensive tasks in parallel. * Some host environments may have a very large number of cores available diff --git a/lib/env.js b/lib/env.js index 176673ffb..3fa39809f 100644 --- a/lib/env.js +++ b/lib/env.js @@ -65,6 +65,10 @@ module.exports.create = function (config) { httpSafeOrigin = canonicalizeOrigin(config.httpSafeOrigin); } + if (typeof(config.websocketPort) !== 'number') { + config.websocketPort = 3003; + } + var permittedEmbedders = config.permittedEmbedders; if (typeof(permittedEmbedders) === 'string') { permittedEmbedders = permittedEmbedders.trim(); @@ -79,6 +83,8 @@ module.exports.create = function (config) { fileHost: config.fileHost || undefined, NO_SANDBOX: NO_SANDBOX, httpSafePort: httpSafePort, + websocketPort: config.websocketPort, + accounts_api: config.accounts_api || undefined, // this simplifies integration with an accounts page shouldUpdateNode: !isRecentVersion(), diff --git a/server.js b/server.js index e7d1e4688..e3904eb4f 100644 --- a/server.js +++ b/server.js @@ -4,11 +4,9 @@ var Express = require('express'); var Http = require('http'); var Fs = require('fs'); -//var Path = require("path"); var nThen = require("nthen"); var Util = require("./lib/common-util"); -//var Keys = require("./lib/keys"); var OS = require("node:os"); var Cluster = require("node:cluster"); @@ -51,19 +49,43 @@ COMMANDS.GET_PROFILING_DATA = function (msg, cb) { }; nThen(function (w) { - Fs.exists(__dirname + "/customize", w(function (e) { - if (e) { return; } - console.log("CryptPad is customizable, see customize.dist/readme.md for details"); - })); -}).nThen(function (w) { require("./lib/log").create(config, w(function (_log) { Env.Log = _log; config.log = _log; })); +}).nThen(function (w) { + Fs.exists("customize", w(function (e) { + if (e) { return; } + Env.Log.info('NO_CUSTOMIZE_FOLDER', { + message: "CryptPad is customizable, see customize.dist/readme.md for details", + }); + })); +}).nThen(function () { + // check that a valid origin was provided in the config + try { + var url = new URL('', Env.httpUnsafeOrigin).href; + Env.Log.info("WEBSERVER_LISTENING", { + origin: url, + }); + + if (!Env.admins.length) { + Env.Log.info('NO_ADMIN_CONFIGURED', { + message: `Your instance is not correctly configured for production usage. Review its checkup page for more information.`, + details: new URL('/checkup/', Env.httpUnsafeOrigin).href, + }); + } + } catch (err) { + Env.Log.error("INVALID_ORIGIN", { + httpUnsafeOrigin: Env.httpUnsafeOrigin, + }); + process.exit(1); + } }).nThen(function (w) { Env.httpServer = Http.createServer(app); - Env.httpServer.listen(3003, '::', w(function () { // XXX 3003 should not be hardcoded - console.log("Socket server is listening on 3003"); // XXX + Env.httpServer.listen(Env.websocketPort, '::', w(function () { + Env.Log.info('WEBSOCKET_LISTENING', { + port: Env.websocketPort, + }); })); }).nThen(function (w) { var limit = Env.maxWorkers; @@ -106,6 +128,20 @@ nThen(function (w) { command(content, cb); }); + + worker.on('exit', (code, signal) => { + if (!signal && code === 0) { return; } + // relaunch http workers if they crash + Env.Log.error('HTTP_WORKER_EXIT', { + signal, + code, + }); + // update the environment with the latest state before relaunching + workerState.Env = Environment.serialize(Env); + launchWorker(function () { + Env.Log.info('HTTP_WORKER_RELAUNCH', {}); + }); + }); }; var txids = {}; @@ -127,12 +163,12 @@ nThen(function (w) { }; var throttledEnvChange = Util.throttle(function () { - Env.Log.info('WORKER_ENV_UPDATE', 'Updating HTTP workers with latest state'); // XXX - broadcast('ENV_UPDATE', Environment.serialize(Env)); //JSON.stringify(Env)); + Env.Log.info('WORKER_ENV_UPDATE', 'Updating HTTP workers with latest state'); + broadcast('ENV_UPDATE', Environment.serialize(Env)); }, 250); var throttledCacheFlush = Util.throttle(function () { - Env.Log.info('WORKER_CACHE_FLUSH', 'Instructing HTTP workers to flush cache'); // XXX + Env.Log.info('WORKER_CACHE_FLUSH', 'Instructing HTTP workers to flush cache'); broadcast('FLUSH_CACHE', Env.FRESH_KEY); }, 250); @@ -145,36 +181,6 @@ nThen(function (w) { } launchWorker(w()); }); -}).nThen(function () { - // Nothing async happens here but I'm using this function scope - // as a logical grouping for readability - var fancyURL = function (domain, path) { - try { - if (domain && path) { return new URL(path, domain).href; } - return new URL(domain); - } catch (err) {} - return false; - }; - - var host = Env.httpAddress; - var hostName = !host.indexOf(':') ? '[' + host + ']' : host; - - var port = Env.httpPort; - var ps = port === 80? '': ':' + port; - - var roughAddress = 'http://' + hostName + ps; - var betterAddress = fancyURL(Env.httpUnsafeOrigin); - - if (betterAddress) { - console.log('Serving content for %s via %s.\n', betterAddress, roughAddress); - } else { - console.log('Serving content via %s.\n', roughAddress); - } - if (!Env.admins.length) { - console.log("Your instance is not correctly configured for safe use in production.\nSee %s for more information.\n", - fancyURL(Env.httpUnsafeOrigin, '/checkup/') || 'https://your-domain.com/checkup/' - ); - } }).nThen(function () { if (Env.shouldUpdateNode) { Env.Log.warn("NODEJS_OLD_VERSION", { From 24274e6c9b744b1a49350b2f529713940f446332 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 20 Dec 2022 17:10:10 +0530 Subject: [PATCH 11/58] remove some prototyping code that was overwriting values in responses to http-workers --- lib/http-worker.js | 4 ++-- server.js | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/http-worker.js b/lib/http-worker.js index 130cd5f0d..ef5194941 100644 --- a/lib/http-worker.js +++ b/lib/http-worker.js @@ -417,14 +417,14 @@ app.get('/api/profiling', function (req, res) { if (!Env.enableProfiling) { return void send404(res); } sendMessage({ // XXX test this command: 'GET_PROFILING_DATA', - }, (err /*, value */) => { // XXX + }, (err, value) => { if (err) { res.status(500); return void send500(res); } res.setHeader('Content-Type', 'text/javascript'); res.send(JSON.stringify({ - bytesWritten: Env.bytesWritten, + bytesWritten: value, })); }); }); diff --git a/server.js b/server.js index e3904eb4f..e215db4ee 100644 --- a/server.js +++ b/server.js @@ -116,13 +116,12 @@ nThen(function (w) { } const cb = Util.once(Util.mkAsync(function (err, value) { - value = Math.random(); worker.send({ type: 'REPLY', error: Util.serializeError(err), txid: txid, pid: msg.pid, - value: value, // XXX + value: value, }); })); From 953c817c5b2c5343270dfd00ec247e6039d3c162 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 20 Dec 2022 18:03:52 +0530 Subject: [PATCH 12/58] clean up more prototype code: * remove commented code * serialize errors sent from http workers to the main process * drop support for custom http headers set via config.js#httpHeaders * websockets: only listen on localhost, respect websocketPort config in workers' proxy config --- lib/http-worker.js | 53 +++++++++++++++++++--------------------------- server.js | 2 +- 2 files changed, 23 insertions(+), 32 deletions(-) diff --git a/lib/http-worker.js b/lib/http-worker.js index ef5194941..bec5d718f 100644 --- a/lib/http-worker.js +++ b/lib/http-worker.js @@ -47,9 +47,8 @@ Logger.levels.forEach(level => { info: info, }, (err) => { if (err) { - return void console.error(err); // XXX + return void console.error(new Error(err)); } - //console.log("Log statement received"); // XXX }); }; }); @@ -57,9 +56,12 @@ Logger.levels.forEach(level => { const EVENTS = {}; var Env = JSON.parse(process.env.Env); -EVENTS.ENV_UPDATE = function (data /*, cb */) { // XXX - // XXX log? - Env = JSON.parse(data); +EVENTS.ENV_UPDATE = function (data /*, cb */) { + try { + Env = JSON.parse(data); + } catch (err) { + Log.error('HTTP_WORKER_ENV_UPDATE', Util.serializeError(err)); + } }; EVENTS.FLUSH_CACHE = function (data /*, cb */) { // XXX @@ -86,9 +88,6 @@ process.on('message', msg => { }); */ if (!(msg && msg.txid)) { return; } - //console.log('MESSAGE_RECEIVED', msg); - - if (msg.type === 'REPLY') { var txid = msg.txid; return void response.handle(txid, [msg.error, msg.value]); @@ -100,9 +99,7 @@ process.on('message', msg => { return void ev(msg.data, () => {}); } } - console.error("UNHANDLED_MESSAGE", msg); - // XXX unhandled }); @@ -120,24 +117,15 @@ var EXEMPT = [ ]; var cacheHeaders = function (Env, key, headers) { - if (Env.DEV_MODE) { return; } // XXX clustering + if (Env.DEV_MODE) { return; } Env[key] = headers; }; -var getHeaders = function (Env, type) { // XXX clustering +var getHeaders = function (Env, type) { var key = type + 'HeadersCache'; if (Env[key]) { return Env[key]; } - var headers = {}; - - var custom; // = undefined; //config.httpHeaders; // XXX drop support for this? - // if the admin provided valid http headers then use them - if (custom && typeof(custom) === 'object' && !Array.isArray(custom)) { - headers = Util.clone(custom); - } else { - // otherwise use the default - headers = Default.httpHeaders(Env); - } + var headers = Default.httpHeaders(Env); headers['Content-Security-Policy'] = type === 'office'? Default.padContentSecurity(Env): @@ -195,11 +183,14 @@ app.head(/^\/common\/feedback\.html/, function (req, res, next) { }()); const { createProxyMiddleware } = require("http-proxy-middleware"); + +var proxyTarget = new URL('', 'ws:localhost'); +proxyTarget.port = Env.websocketPort; + const wsProxy = createProxyMiddleware({ - target: 'ws://localhost:3003', // XXX + target: proxyTarget.href, ws: true, - logLevel: 'error', ///silent', - //pathFilter: '/cryptpad_websocket', + logLevel: 'error', }); app.use('/cryptpad_websocket', wsProxy); @@ -309,7 +300,7 @@ var makeRouteCache = function (template, cacheName) { }; }; -var serveConfig = makeRouteCache(function (/* host */) { // XXX +var serveConfig = makeRouteCache(function () { return [ 'define(function(){', 'return ' + JSON.stringify({ @@ -340,7 +331,7 @@ var serveConfig = makeRouteCache(function (/* host */) { // XXX ].join(';\n'); }, 'configCache'); -var serveBroadcast = makeRouteCache(function (/* host */) { // XXX +var serveBroadcast = makeRouteCache(function () { var maintenance = Env.maintenance; if (maintenance && maintenance.end && maintenance.end < (+new Date())) { maintenance = undefined; @@ -365,7 +356,7 @@ var Define = function (obj) { });`; }; -app.get('/api/instance', function (req, res) { // XXX use caching? +app.get('/api/instance', function (req, res) { res.setHeader('Content-Type', 'text/javascript'); res.send(Define({ name: Env.instanceName, @@ -402,9 +393,9 @@ app.get('/api/updatequota', function (req, res) { res.status(404); return void send404(res); } - sendMessage({ // XXX test this + sendMessage({ command: 'UPDATE_QUOTA', - }, (err /*, value */) => { + }, (err) => { if (err) { res.status(500); return void send500(res); @@ -415,7 +406,7 @@ app.get('/api/updatequota', function (req, res) { app.get('/api/profiling', function (req, res) { if (!Env.enableProfiling) { return void send404(res); } - sendMessage({ // XXX test this + sendMessage({ command: 'GET_PROFILING_DATA', }, (err, value) => { if (err) { diff --git a/server.js b/server.js index e215db4ee..9983ceb79 100644 --- a/server.js +++ b/server.js @@ -82,7 +82,7 @@ nThen(function (w) { } }).nThen(function (w) { Env.httpServer = Http.createServer(app); - Env.httpServer.listen(Env.websocketPort, '::', w(function () { + Env.httpServer.listen(Env.websocketPort, 'localhost', w(function () { Env.Log.info('WEBSOCKET_LISTENING', { port: Env.websocketPort, }); From 4968bbf9613ddec64ecb87082ee62724c4d0147e Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 11 Jan 2023 14:50:16 +0530 Subject: [PATCH 13/58] WIP limit on block size --- customize.dist/login.js | 2 +- lib/storage/block.js | 2 ++ lib/workers/index.js | 7 +++++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/customize.dist/login.js b/customize.dist/login.js index efce968ca..ce1c4eb3d 100644 --- a/customize.dist/login.js +++ b/customize.dist/login.js @@ -99,7 +99,7 @@ define([ opt.channelHex = parsed.channel; opt.keys = parsed.keys; opt.edPublic = blockInfo.edPublic; - opt.User_name = blockInfo.User_name; + opt.User_name = blockInfo.User_name; // XXX do we actually use this? can we drop it? return opt; }; diff --git a/lib/storage/block.js b/lib/storage/block.js index fb82f0e41..9f02fc02b 100644 --- a/lib/storage/block.js +++ b/lib/storage/block.js @@ -116,6 +116,8 @@ Block.check = function (Env, publicKey, _cb) { // 'check' because 'exists' impli Fs.access(path, Fs.constants.F_OK, cb); }; +Block.MAX_SIZE = 256; // XXX confirm that this is sufficient, prevent user inputs that would result in larger blocks + Block.write = function (Env, publicKey, buffer, _cb) { var cb = Util.once(Util.mkAsync(_cb)); var path = Block.mkPath(Env, publicKey); diff --git a/lib/workers/index.js b/lib/workers/index.js index 7d82eab0f..c9955c2d2 100644 --- a/lib/workers/index.js +++ b/lib/workers/index.js @@ -6,6 +6,7 @@ const OS = require("os"); const { fork } = require('child_process'); const Workers = module.exports; const PID = process.pid; +const Block = require("../storage/block"); const DB_PATH = 'lib/workers/db-worker'; const MAX_JOBS = 16; @@ -472,6 +473,12 @@ Workers.initialize = function (Env, config, _cb) { }; Env.validateLoginBlock = function (publicKey, signature, block, cb) { + if (!block || !block.length || !block.length > Block.MAX_SIZE) { + return void setTimeout(function () { + cb('E_INVALID_BLOCK_SIZE'); + }); + } + sendCommand({ command: 'VALIDATE_LOGIN_BLOCK', publicKey: publicKey, From 3f18a3871419fcde7d840f90588deaee185ed3b4 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 11 Jan 2023 15:02:02 +0530 Subject: [PATCH 14/58] report http-worker RPC errors to the main process for logging --- lib/http-worker.js | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/lib/http-worker.js b/lib/http-worker.js index bec5d718f..5e86dae49 100644 --- a/lib/http-worker.js +++ b/lib/http-worker.js @@ -11,12 +11,7 @@ const DEFAULT_QUERY_TIMEOUT = 5000; const PID = process.pid; const response = Util.response(function (errLabel, info) { - // XXX handle error - console.error({ - _: '// XXX', - errLabel: errLabel, - info: info, - }); + Env.Log.error(errLabel, info); }); const guid = () => { @@ -64,7 +59,7 @@ EVENTS.ENV_UPDATE = function (data /*, cb */) { } }; -EVENTS.FLUSH_CACHE = function (data /*, cb */) { // XXX +EVENTS.FLUSH_CACHE = function (data) { if (typeof(data) !== 'number') { return Log.error('INVALID_FRESH_KEY', data); } @@ -443,12 +438,13 @@ nThen(function (w) { server.listen(3001, w()); // if (Env.httpSafePort) {... } server.on('upgrade', function (req, socket, head) { - //console.log("This should only happen in a dev environment"); // XXX + // TODO warn admins that websockets should only be proxied in this way in a dev environment + // in production it's more efficient to have your reverse proxy (NGINX) directly forward + // websocket traffic to the correct port (Env.websocketPort) wsProxy.upgrade(req, socket, head); }); }).nThen(function () { - // XXX inform the parent process that this worker is ready - + // TODO inform the parent process that this worker is ready }); From b0d10c3777d6976a6bc6a6513c1830153a81500f Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 11 Jan 2023 15:08:16 +0530 Subject: [PATCH 15/58] oops - fix inverted not --- lib/workers/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/workers/index.js b/lib/workers/index.js index c9955c2d2..96cb0e795 100644 --- a/lib/workers/index.js +++ b/lib/workers/index.js @@ -473,7 +473,7 @@ Workers.initialize = function (Env, config, _cb) { }; Env.validateLoginBlock = function (publicKey, signature, block, cb) { - if (!block || !block.length || !block.length > Block.MAX_SIZE) { + if (!block || !block.length || block.length > Block.MAX_SIZE) { return void setTimeout(function () { cb('E_INVALID_BLOCK_SIZE'); }); From 8fce5bcaf6c8949986d2d7b3b8bd671605de155a Mon Sep 17 00:00:00 2001 From: ansuz Date: Thu, 2 Mar 2023 12:45:38 +0530 Subject: [PATCH 16/58] use configured http ports --- lib/http-worker.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/http-worker.js b/lib/http-worker.js index 5e86dae49..cad694ac2 100644 --- a/lib/http-worker.js +++ b/lib/http-worker.js @@ -433,9 +433,9 @@ app.use(function (err, req, res /*, next*/) { var server = Http.createServer(app); nThen(function (w) { - server.listen(3000, w()); + server.listen(Env.httpPort, w()); if (Env.httpSafePort) { - server.listen(3001, w()); // if (Env.httpSafePort) {... + server.listen(Env.httpSafePort, w()); } server.on('upgrade', function (req, socket, head) { // TODO warn admins that websockets should only be proxied in this way in a dev environment From 64d24f8b20e1646e6b5f61bd01d1892c8fe1e8fb Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 7 Mar 2023 11:17:46 +0530 Subject: [PATCH 17/58] clean up http-worker code and add comments --- lib/http-worker.js | 46 +++++++++++++++++++++++++++------------------- server.js | 4 ++-- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/lib/http-worker.js b/lib/http-worker.js index cad694ac2..121471577 100644 --- a/lib/http-worker.js +++ b/lib/http-worker.js @@ -21,8 +21,6 @@ const guid = () => { const sendMessage = (msg, cb, opt) => { var txid = guid(); var timeout = (opt && opt.timeout) || DEFAULT_QUERY_TIMEOUT; - - /// XXX don't nest var obj = { pid: PID, txid: txid, @@ -31,7 +29,6 @@ const sendMessage = (msg, cb, opt) => { response.expect(txid, cb, timeout); process.send(obj); }; - const Log = {}; Logger.levels.forEach(level => { Log[level] = function (tag, info) { @@ -74,14 +71,6 @@ EVENTS.FLUSH_CACHE = function (data) { }; process.on('message', msg => { - // XXX -/* - console.log({ - _: 'Message from main process to worker', - msg: msg, - pid: process.pid, - }); -*/ if (!(msg && msg.txid)) { return; } if (msg.type === 'REPLY') { var txid = msg.txid; @@ -94,8 +83,7 @@ process.on('message', msg => { return void ev(msg.data, () => {}); } } - console.error("UNHANDLED_MESSAGE", msg); - // XXX unhandled + console.error("UNHANDLED_MESSAGE", msg); // XXX }); @@ -190,10 +178,12 @@ const wsProxy = createProxyMiddleware({ app.use('/cryptpad_websocket', wsProxy); + app.use('/blob', function (req, res, next) { - // XXX update atime? +/* Head requests are used to check the size of a blob. + Clients can configure a maximum size to download automatically, + and can manually click to download blobs which exceed that limit. */ if (req.method === 'HEAD') { - console.log(`Blob head: ${req.url}`); Express.static(Path.resolve(Env.paths.blob), { setHeaders: function (res /*, path, stat */) { res.set('Access-Control-Allow-Origin', Env.enableEmbedding? '*': Env.permittedEmbedders); @@ -202,16 +192,34 @@ app.use('/blob', function (req, res, next) { } })(req, res, next); return; - } else { - console.log(`Blob !head: ${req.url}`); } + +/* Some GET requests concern the whole file, + others only target ranges, either: + + 1. a two octet prefix which encodes the length of the metadata in octets + 2. the metadata itself, excluding the two preceding octets +*/ + +/* + // Example code to demonstrate the types of requests which are handled + if (req.method === 'GET') { + if (!req.headers.range) { + // metadata + } else { + // full request + } + } +*/ + next(); }); app.use(function (req, res, next) { - // XXX update atime? +/* These are pre-flight requests, through which the client + confirms with the server that it is permitted to make the + actual requests which will follow */ if (req.method === 'OPTIONS' && /\/blob\//.test(req.url)) { - console.log(`Blob options: ${req.url}`); res.setHeader('Access-Control-Allow-Origin', Env.enableEmbedding? '*': Env.permittedEmbedders); res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range,Access-Control-Allow-Origin'); diff --git a/server.js b/server.js index 9983ceb79..1ea944044 100644 --- a/server.js +++ b/server.js @@ -107,8 +107,8 @@ nThen(function (w) { worker.on('message', msg => { if (!msg) { return; } var txid = msg.txid; - var content = msg.content; // XXX don't nest - if (!content) { return; } // XXX + var content = msg.content; + if (!content) { return; } var command = COMMANDS[content.command]; if (typeof(command) !== 'function') { From 08b6009a846c2666cd864e404174199dc10de139 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 7 Mar 2023 13:29:45 +0530 Subject: [PATCH 18/58] stop including username in login block --- customize.dist/login.js | 1 - www/common/cryptpad-common.js | 1 - 2 files changed, 2 deletions(-) diff --git a/customize.dist/login.js b/customize.dist/login.js index ce1c4eb3d..15707ca94 100644 --- a/customize.dist/login.js +++ b/customize.dist/login.js @@ -99,7 +99,6 @@ define([ opt.channelHex = parsed.channel; opt.keys = parsed.keys; opt.edPublic = blockInfo.edPublic; - opt.User_name = blockInfo.User_name; // XXX do we actually use this? can we drop it? return opt; }; diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index f417a4507..9911a6e72 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -2068,7 +2068,6 @@ define([ }).nThen(function (waitFor) { // Write the new login block var temp = { - User_name: accountName, User_hash: newHash, edPublic: edPublic, }; From d8ef2c83710341500cd983698fef9674e795f02e Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 7 Mar 2023 13:30:30 +0530 Subject: [PATCH 19/58] print login block size when it exceeds the maximum --- lib/workers/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/workers/index.js b/lib/workers/index.js index 96cb0e795..d97f52225 100644 --- a/lib/workers/index.js +++ b/lib/workers/index.js @@ -475,6 +475,10 @@ Workers.initialize = function (Env, config, _cb) { Env.validateLoginBlock = function (publicKey, signature, block, cb) { if (!block || !block.length || block.length > Block.MAX_SIZE) { return void setTimeout(function () { + Env.Log.error('E_INVALID_BLOCK_SIZE', { + size: block.length, + }); + cb('E_INVALID_BLOCK_SIZE'); }); } From 0b6ac69e324d2bafd58804e1ece05c2c375b5580 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 7 Mar 2023 14:02:25 +0530 Subject: [PATCH 20/58] enforce maximum username length of 64 characters --- www/common/common-credential.js | 11 +++++++++-- www/register/main.js | 7 +++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/www/common/common-credential.js b/www/common/common-credential.js index ffbc482d6..b3be97308 100644 --- a/www/common/common-credential.js +++ b/www/common/common-credential.js @@ -3,7 +3,10 @@ var factory = function (AppConfig, Scrypt) { var Cred = {}; Cred.MINIMUM_PASSWORD_LENGTH = typeof(AppConfig.minimumPasswordLength) === 'number'? - AppConfig.minimumPasswordLength: 8; + AppConfig.minimumPasswordLength: 8; // TODO 14 or higher is a decent default for 2023 + + Cred.MINIMUM_NAME_LENGTH = 1; + Cred.MAXIMUM_NAME_LENGTH = 64; // https://stackoverflow.com/questions/46155/how-to-validate-an-email-address-in-javascript Cred.isEmail = function (email) { @@ -19,8 +22,12 @@ var factory = function (AppConfig, Scrypt) { return typeof(x) === 'string'; }; + // Maximum username length is enforced at registration time + // rather than in this function + // in order to maintain backwards compatibility with accounts + // that might have already registered with a longer name. Cred.isValidUsername = function (name) { - return !!(name && isString(name)); + return !!(isString(name) && name.length >= Cred.MINIMUM_NAME_LENGTH); }; Cred.isValidPassword = function (passwd) { diff --git a/www/register/main.js b/www/register/main.js index fa26f38b4..d772c770f 100644 --- a/www/register/main.js +++ b/www/register/main.js @@ -48,12 +48,19 @@ define([ var I_REALLY_WANT_TO_USE_MY_EMAIL_FOR_MY_USERNAME = false; var br = function () { return h('br'); }; + Messages.register_nameTooLong = "Usernames must be shorter than {0} characters"; // XXX var registerClick = function () { var uname = $uname.val().trim(); // trim whitespace surrounding the username since it is otherwise included in key derivation // most people won't realize that its presence is significant $uname.val(uname); + if (uname.length > Cred.MAXIMUM_NAME_LENGTH) { + let nameWarning = Messages._getKey('register_nameTooLong', [ Cred.MAXIMUM_NAME_LENGTH ]); + return void UI.alert(nameWarning, function () { + registering = false; + }); + } var passwd = $passwd.val(); var confirmPassword = $confirm.val(); From 71ad9f2688c523e744423f17b9f9878800148a07 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 10 Mar 2023 12:57:25 +0530 Subject: [PATCH 21/58] check allowed origins for blob and block URLs on checkup page --- www/checkup/main.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/www/checkup/main.js b/www/checkup/main.js index 7748b3b22..cf4f716a9 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -1091,12 +1091,14 @@ define([ }); }; - assert(function (cb, msg) { - var header = 'Access-Control-Allow-Origin'; - var url = new URL('/', trimmedUnsafe).href; - Tools.common_xhr(url, function (xhr) { - var raw = xhr.getResponseHeader(header); - checkAllowedOrigins(raw, url, msg, cb); + ['/', '/blob/placeholder.txt', '/block/placeholder.txt'].forEach(relativeURL => { + assert(function (cb, msg) { + var header = 'Access-Control-Allow-Origin'; + var url = new URL(relativeURL, trimmedUnsafe).href; + Tools.common_xhr(url, function (xhr) { + var raw = xhr.getResponseHeader(header); + checkAllowedOrigins(raw, url, msg, cb); + }); }); }); From cfbb5e1fc6493943ac47aba22a84af744ca2fb89 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 10 Mar 2023 13:52:03 +0530 Subject: [PATCH 22/58] WIP debug duplicated headers in production envs --- www/checkup/main.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/www/checkup/main.js b/www/checkup/main.js index cf4f716a9..1743d99da 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -1177,6 +1177,19 @@ define([ }); }); + ['/', '/blob/placeholder.txt', '/block/placeholder.txt'].forEach(relativeURL => { + assert(function (cb, msg) { + var url = new URL(relativeURL, trimmedUnsafe).href; + Tools.common_xhr(url, xhr => { + msg.appendChild(h('span', [ + h('p', '// XXX DEBUGGING DUPLICATED HEADERS'), + h('pre', xhr.getAllResponseHeaders()), + ])); + cb(false); + }); + }); + }); + var POLICY_ADVISORY = " This link will be included in the home page footer and 'About CryptPad' menu. It's advised that you either provide one or disable registration."; var APPCONFIG_DOCS_LINK = function (key, href) { return h('span', [ From f96492d5b48fd37f69dba59f3929435ef2f67031 Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 10 Mar 2023 14:05:21 +0530 Subject: [PATCH 23/58] fix pre tag overflow in checkup error message --- www/checkup/app-checkup.less | 9 +++++++++ www/checkup/main.js | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/www/checkup/app-checkup.less b/www/checkup/app-checkup.less index d7be2f4c9..ae1f805db 100644 --- a/www/checkup/app-checkup.less +++ b/www/checkup/app-checkup.less @@ -75,6 +75,10 @@ html, body { padding: 5px; //font-size: 16px; border-radius: @corner; + + max-width: 100%; + box-sizing: border-box; + &.cp-danger { border: 1px solid @cp_alerts-danger-bg; background-color: @cp_alerts-danger-bg; @@ -85,6 +89,11 @@ html, body { background-color: @cp_alerts-warning-bg; color: @cp_alerts-warning-text; } + pre.cp-raw-text { + overflow: auto; + background-color: #2222; + } + code { word-break: keep-all; font-style: italic; diff --git a/www/checkup/main.js b/www/checkup/main.js index 1743d99da..2383d1f4b 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -1183,7 +1183,7 @@ define([ Tools.common_xhr(url, xhr => { msg.appendChild(h('span', [ h('p', '// XXX DEBUGGING DUPLICATED HEADERS'), - h('pre', xhr.getAllResponseHeaders()), + h('pre.cp-raw-text', xhr.getAllResponseHeaders()), ])); cb(false); }); From 95ee95ece7346af2a9d1fd63112698e2fbdd82ef Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 10 Mar 2023 14:35:54 +0530 Subject: [PATCH 24/58] more obvious message for duplicated header detection on checkup --- www/checkup/main.js | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/www/checkup/main.js b/www/checkup/main.js index 2383d1f4b..3f40bd897 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -1177,15 +1177,43 @@ define([ }); }); + var COMMONLY_DUPLICATED_HEADERS = [ + 'X-Content-Type-Options', + 'Access-Control-Allow-Origin', + 'Permissions-Policy', + 'X-XSS-Protection', + ]; + ['/', '/blob/placeholder.txt', '/block/placeholder.txt'].forEach(relativeURL => { assert(function (cb, msg) { var url = new URL(relativeURL, trimmedUnsafe).href; Tools.common_xhr(url, xhr => { + var span = h('span', h('p', '// XXX DEBUGGING DUPLICATED HEADERS')); + + var duplicated = false; + var pre = []; + COMMONLY_DUPLICATED_HEADERS.forEach(h => { + var value = xhr.getResponseHeader(h); + if (/,/.test(value)) { + pre.push(`${h}: ${value}`); + duplicated = true; + } + }); + if (duplicated) { + span.appendChild(h('pre', pre.join('\n'))); + } + + // none of the headers should include a comma + // as that indicates they are duplicated + if (!duplicated) { return void cb(true); } + msg.appendChild(h('span', [ - h('p', '// XXX DEBUGGING DUPLICATED HEADERS'), h('pre.cp-raw-text', xhr.getAllResponseHeaders()), ])); - cb(false); + cb({ + duplicated, + url, + }); }); }); }); From b7a796cc6ffd52808ab7624c1e2155c90b7a505a Mon Sep 17 00:00:00 2001 From: ansuz Date: Fri, 10 Mar 2023 14:37:01 +0530 Subject: [PATCH 25/58] oops --- www/checkup/main.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/www/checkup/main.js b/www/checkup/main.js index 3f40bd897..517c03912 100644 --- a/www/checkup/main.js +++ b/www/checkup/main.js @@ -1207,9 +1207,7 @@ define([ // as that indicates they are duplicated if (!duplicated) { return void cb(true); } - msg.appendChild(h('span', [ - h('pre.cp-raw-text', xhr.getAllResponseHeaders()), - ])); + msg.appendChild(span); cb({ duplicated, url, From 3c6a35b713f9e14a14e64d0030abc6e94d5ec2ac Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 2 May 2023 23:35:09 +0530 Subject: [PATCH 26/58] new types of storage for challenges, MFA settings, and sessions --- lib/env.js | 1 + lib/storage/basic.js | 53 ++++++++++++++++++++++++++++++++++++++++ lib/storage/challenge.js | 39 +++++++++++++++++++++++++++++ lib/storage/mfa.js | 43 ++++++++++++++++++++++++++++++++ lib/storage/sessions.js | 44 +++++++++++++++++++++++++++++++++ 5 files changed, 180 insertions(+) create mode 100644 lib/storage/basic.js create mode 100644 lib/storage/challenge.js create mode 100644 lib/storage/mfa.js create mode 100644 lib/storage/sessions.js diff --git a/lib/env.js b/lib/env.js index ecea533df..687d5bed0 100644 --- a/lib/env.js +++ b/lib/env.js @@ -329,6 +329,7 @@ module.exports.create = function (config) { paths.staging = keyOrDefaultString('blobStagingPath', './blobstage'); paths.blob = keyOrDefaultString('blobPath', './blob'); paths.decree = keyOrDefaultString('decreePath', './data/'); + paths.base = keyOrDefaultString('base', './data'); paths.archive = keyOrDefaultString('archivePath', './data/archive'); paths.task = keyOrDefaultString('taskPath', './tasks'); diff --git a/lib/storage/basic.js b/lib/storage/basic.js new file mode 100644 index 000000000..215ffc0fe --- /dev/null +++ b/lib/storage/basic.js @@ -0,0 +1,53 @@ +/* Mulfi-factor auth requires some rudimentary storage methods + for a number of data types: + +* "challenges" (described in challenge.js) +* account settings for MFA (described in mfa.js) +* session tokens (described in sessions.js) + +Each data type requires the same three simple methods: + +* read +* write +* delete + +These could be implemented as tables in a relational database, but committing to a relational DB +is a big decision, so these methods are instead implemented using the filesystem, with each +file's path and naming convention implemented outside of this module. + +Feel free to migrate all of these to a relational DB at some point in the future if you like. + +*/ + +const Basic = module.exports; +const Fs = require("node:fs"); +const Path = require("node:path"); + +var pathError = (cb) => { + setTimeout(function () { + cb(new Error("INVALID_PATH")); + }); +}; + +Basic.read = function (Env, path, cb) { + if (!path) { return void pathError(cb); } + Fs.readFile(path, 'utf8', (err, content) => { + if (err) { return void cb(err); } + cb(void 0, content); + }); +}; + +Basic.write = function (Env, path, data, cb) { + if (!path) { return void pathError(cb); } + var dirpath = Path.dirname(path); + Fs.mkdir(dirpath, { recursive: true }, function (err) { + if (err) { return void cb(err); } + Fs.writeFile(path, data, cb); + }); +}; + +Basic.delete = function (Env, path, cb) { + if (!path) { return void pathError(cb); } + Fs.rm(path, cb); +}; + diff --git a/lib/storage/challenge.js b/lib/storage/challenge.js new file mode 100644 index 000000000..e4d9ca6c8 --- /dev/null +++ b/lib/storage/challenge.js @@ -0,0 +1,39 @@ +const Basic = require("./basic.js"); +const Path = require("node:path"); + +const Challenge = module.exports; +/* This module manages storage used to implement a public-key authenticated + challenge-response protocol. + + Each 'challenge' is only intended to be valid for a short period of time. + 1. A client makes a request of the server + 2. The server stores their request with a nonce and challenges them to sign for this request + 3. If the client successfully signs for the request within a short window then the request is executed + 4. Whether the signature is valid or not, the challenge is removed + + Thus, we only expect challenges to remain in storage if the request was aborted or interrupted + for some unexpected reason. + + Some form of garbage collection should be implemented in the future. +*/ + +const pathFromId = function (Env, id) { + if (!id || typeof(id) !== 'string') { return void console.error('CHALLENGE_BAD_ID', id); } + return Path.join(Env.paths.base, "challenges", id.slice(0, 2), id); +}; + +Challenge.read = function (Env, id, cb) { + var path = pathFromId(Env, id); + Basic.read(Env, path, cb); +}; + +Challenge.write = function (Env, id, data, cb) { + var path = pathFromId(Env, id); + Basic.write(Env, path, data, cb); +}; + +Challenge.delete = function (Env, id, cb) { + var path = pathFromId(Env, id); + Basic.delete(Env, path, cb); +}; + diff --git a/lib/storage/mfa.js b/lib/storage/mfa.js new file mode 100644 index 000000000..0cb957817 --- /dev/null +++ b/lib/storage/mfa.js @@ -0,0 +1,43 @@ +const Basic = require("./basic"); +const Path = require("node:path"); +const Util = require("../common-util"); + +const MFA = module.exports; + +/* +This module manages storage related to accounts' multi-factor authentication settings. + +These settings are checked every time a block is accessed, so we do as little as possible +so that it can be accessed quickly. + +*/ + +/* The path for a given account's settings is based on the public signing key + which identifies its "login block". We expect that any action to create or access + a block will be authenticated with a challenge-response protocol, so we + don't bother checking the validity of an identifier in here aside from + ensuring that it won't throw when using string methods. + +*/ +var pathFromId = function (Env, id) { + if (!id || typeof(id) !== 'string') { return; } + id = Util.escapeKeyCharacters(id); + return Path.join(Env.paths.base, "mfa", id.slice(0, 2), `${id}.json`); +}; + +MFA.read = function (Env, id, cb) { + var path = pathFromId(Env, id); + Basic.read(Env, path, cb); +}; + +// data should be a string +MFA.write = function (Env, id, data, cb) { + var path = pathFromId(Env, id); + Basic.write(Env, path, data, cb); +}; + +MFA.delete = function (Env, id, cb) { + var path = pathFromId(Env, id); + Basic.delete(Env, path, cb); +}; + diff --git a/lib/storage/sessions.js b/lib/storage/sessions.js new file mode 100644 index 000000000..d9056ae4b --- /dev/null +++ b/lib/storage/sessions.js @@ -0,0 +1,44 @@ +const Basic = require("./basic"); +const Path = require("node:path"); +const Nacl = require("tweetnacl/nacl-fast"); +const Util = require("../common-util"); + +const Sessions = module.exports; +/* This module manages storage for per-acccount session tokens - currently assumed to be + JSON Web Tokens (JWTs). + + Decisions about what goes into each of those JWTs happens upstream, so the storage + itself is relatively unopinionated. + + The key things to understand are: + +* valid sessions allow the holder of a given JWT to access a given "login block" +* JWTs are signed with a key held in the server's memory. If that key leaks then it should be rotated (with the SET_BEARER_SECRET decree) to invalidate all existing JWTs. Under these conditions then all tokens signed with the old key can be removed. Garbage collection of these older tokens is not implemented. +* it is expected that any given login-block can have multiple active sessions (for different devices, or if their browser clears its cache automatically). All sessions for a given block are stored in a per-user directory which is intended to make listing or iterating over them simple. +* It could be desirable to expose the list of sessions to the relevant user and allow them to revoke sessions individually or en-masse, though this is not currently implemented. + +*/ + +var pathFromId = function (Env, id, ref) { + if (!id || typeof(id) !== 'string') { return; } + id = Util.escapeKeyCharacters(id); + return Path.join(Env.paths.base, "sessions", id.slice(0, 2), id, ref); +}; + +Sessions.randomId = () => Nacl.util.encodeBase64(Nacl.randomBytes(24)).replace(/\//g, '-'); + +Sessions.read = function (Env, id, ref, cb) { + var path = pathFromId(Env, id, ref); + Basic.read(Env, path, cb); +}; + +Sessions.write = function (Env, id, ref, data, cb) { + var path = pathFromId(Env, id, ref); + Basic.write(Env, path, data, cb); +}; + +Sessions.delete = function (Env, id, ref, cb) { + var path = pathFromId(Env, id, ref); + Basic.delete(Env, path, cb); +}; + From 987607a7d8ec3a48e11a1a24c8e804844bb9c7cb Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 3 May 2023 15:45:27 +0530 Subject: [PATCH 27/58] add new serverside dependencies for TOTP --- package-lock.json | 1893 ++++++++++++++++++++++++++++++++++++++++++--- package.json | 3 + 2 files changed, 1808 insertions(+), 88 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8941a8f10..0f03b2329 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,12 +16,16 @@ "fs-extra": "^7.0.0", "get-folder-size": "^2.0.1", "http-proxy-middleware": "^2.0.6", + "jsonwebtoken": "^9.0.0", "netflux-websocket": "^0.1.20", + "notp": "^2.0.3", "nthen": "0.1.8", + "prompt-confirm": "^2.0.4", "pull-stream": "^3.6.1", "saferphore": "0.0.1", "sortify": "^1.0.4", "stream-to-pull-stream": "^1.7.2", + "thirty-two": "^1.0.2", "tweetnacl": "~0.12.2", "ulimit": "0.0.2", "ws": "^3.3.1" @@ -122,6 +126,345 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ansi-bgblack": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgblack/-/ansi-bgblack-0.1.1.tgz", + "integrity": "sha512-tp8M/NCmSr6/skdteeo9UgJ2G1rG88X3ZVNZWXUxFw4Wh0PAGaAAWQS61sfBt/1QNcwMTY3EBKOMPujwioJLaw==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-bgblue": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgblue/-/ansi-bgblue-0.1.1.tgz", + "integrity": "sha512-R8JmX2Xv3+ichUQE99oL+LvjsyK+CDWo/BtVb4QUz3hOfmf2bdEmiDot3fQcpn2WAHW3toSRdjSLm6bgtWRDlA==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-bgcyan": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgcyan/-/ansi-bgcyan-0.1.1.tgz", + "integrity": "sha512-6SByK9q2H978bmqzuzA5NPT1lRDXl3ODLz/DjC4URO5f/HqK7dnRKfoO/xQLx/makOz7zWIbRf6+Uf7bmaPSkQ==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-bggreen": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bggreen/-/ansi-bggreen-0.1.1.tgz", + "integrity": "sha512-8TRtOKmIPOuxjpklrkhUbqD2NnVb4WZQuIjXrT+TGKFKzl7NrL7wuNvEap3leMt2kQaCngIN1ZzazSbJNzF+Aw==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-bgmagenta": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgmagenta/-/ansi-bgmagenta-0.1.1.tgz", + "integrity": "sha512-UZYhobiGAlV4NiwOlKAKbkCyxOl1PPZNvdIdl/Ce5by45vwiyNdBetwHk/AjIpo1Ji9z+eE29PUBAjjfVmz5SA==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-bgred": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgred/-/ansi-bgred-0.1.1.tgz", + "integrity": "sha512-BpPHMnYmRBhcjY5knRWKjQmPDPvYU7wrgBSW34xj7JCH9+a/SEIV7+oSYVOgMFopRIadOz9Qm4zIy+mEBvUOPA==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-bgwhite": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgwhite/-/ansi-bgwhite-0.1.1.tgz", + "integrity": "sha512-KIF19t+HOYOorUnHTOhZpeZ3bJsjzStBG2hSGM0WZ8YQQe4c7lj9CtwnucscJDPrNwfdz6GBF+pFkVfvHBq6uw==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-bgyellow": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgyellow/-/ansi-bgyellow-0.1.1.tgz", + "integrity": "sha512-WyRoOFSIvOeM7e7YdlSjfAV82Z6K1+VUVbygIQ7C/VGzWYuO/d30F0PG7oXeo4uSvSywR0ozixDQvtXJEorq4Q==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-black": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-black/-/ansi-black-0.1.1.tgz", + "integrity": "sha512-hl7re02lWus7lFOUG6zexhoF5gssAfG5whyr/fOWK9hxNjUFLTjhbU/b4UHWOh2dbJu9/STSUv+80uWYzYkbTQ==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-blue": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-blue/-/ansi-blue-0.1.1.tgz", + "integrity": "sha512-8Um59dYNDdQyoczlf49RgWLzYgC2H/28W3JAIyOAU/+WkMcfZmaznm+0i1ikrE0jME6Ypk9CJ9CY2+vxbPs7Fg==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-bold": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bold/-/ansi-bold-0.1.1.tgz", + "integrity": "sha512-wWKwcViX1E28U6FohtWOP4sHFyArELHJ2p7+3BzbibqJiuISeskq6t7JnrLisUngMF5zMhgmXVw8Equjzz9OlA==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-colors": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-0.2.0.tgz", + "integrity": "sha512-ScRNUT0TovnYw6+Xo3iKh6G+VXDw2Ds7ZRnMIuKBgHY02DgvT2T2K22/tc/916Fi0W/5Z1RzDaHQwnp75hqdbA==", + "dependencies": { + "ansi-bgblack": "^0.1.1", + "ansi-bgblue": "^0.1.1", + "ansi-bgcyan": "^0.1.1", + "ansi-bggreen": "^0.1.1", + "ansi-bgmagenta": "^0.1.1", + "ansi-bgred": "^0.1.1", + "ansi-bgwhite": "^0.1.1", + "ansi-bgyellow": "^0.1.1", + "ansi-black": "^0.1.1", + "ansi-blue": "^0.1.1", + "ansi-bold": "^0.1.1", + "ansi-cyan": "^0.1.1", + "ansi-dim": "^0.1.1", + "ansi-gray": "^0.1.1", + "ansi-green": "^0.1.1", + "ansi-grey": "^0.1.1", + "ansi-hidden": "^0.1.1", + "ansi-inverse": "^0.1.1", + "ansi-italic": "^0.1.1", + "ansi-magenta": "^0.1.1", + "ansi-red": "^0.1.1", + "ansi-reset": "^0.1.1", + "ansi-strikethrough": "^0.1.1", + "ansi-underline": "^0.1.1", + "ansi-white": "^0.1.1", + "ansi-yellow": "^0.1.1", + "lazy-cache": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-cyan": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz", + "integrity": "sha512-eCjan3AVo/SxZ0/MyIYRtkpxIu/H3xZN7URr1vXVrISxeyz8fUFz0FJziamK4sS8I+t35y4rHg1b2PklyBe/7A==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-dim": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-dim/-/ansi-dim-0.1.1.tgz", + "integrity": "sha512-zAfb1fokXsq4BoZBkL0eK+6MfFctbzX3R4UMcoWrL1n2WHewFKentTvOZv2P11u6P4NtW/V47hVjaN7fJiefOg==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-gray": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "integrity": "sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-green": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-green/-/ansi-green-0.1.1.tgz", + "integrity": "sha512-WJ70OI4jCaMy52vGa/ypFSKFb/TrYNPaQ2xco5nUwE0C5H8piume/uAZNNdXXiMQ6DbRmiE7l8oNBHu05ZKkrw==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-grey": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-grey/-/ansi-grey-0.1.1.tgz", + "integrity": "sha512-+J1nM4lC+whSvf3T4jsp1KR+C63lypb+VkkwtLQMc1Dlt+nOvdZpFT0wwFTYoSlSwCcLUAaOpHF6kPkYpSa24A==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-hidden": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-hidden/-/ansi-hidden-0.1.1.tgz", + "integrity": "sha512-8gB1bo9ym9qZ/Obvrse1flRsfp2RE+40B23DhQcKxY+GSeaOJblLnzBOxzvmLTWbi5jNON3as7wd9rC0fNK73Q==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-inverse": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-inverse/-/ansi-inverse-0.1.1.tgz", + "integrity": "sha512-Kq8Z0dBRhQhDMN/Rso1Nu9niwiTsRkJncfJZXiyj7ApbfJrGrrubHXqXI37feJZkYcIx6SlTBdNCeK0OQ6X6ag==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-italic": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-italic/-/ansi-italic-0.1.1.tgz", + "integrity": "sha512-jreCxifSAqbaBvcibeQxcwhQDbEj7gF69XnpA6x83qbECEBaRBD1epqskrmov1z4B+zzQuEdwbWxgzvhKa+PkA==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-magenta": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-magenta/-/ansi-magenta-0.1.1.tgz", + "integrity": "sha512-A1Giu+HRwyWuiXKyXPw2AhG1yWZjNHWO+5mpt+P+VWYkmGRpLPry0O5gmlJQEvpjNpl4RjFV7DJQ4iozWOmkbQ==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-red": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", + "integrity": "sha512-ewaIr5y+9CUTGFwZfpECUbFlGcC0GCw1oqR9RI6h1gQCd9Aj2GxSckCnPsVJnmfMZbwFYE+leZGASgkWl06Jow==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/ansi-reset": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-reset/-/ansi-reset-0.1.1.tgz", + "integrity": "sha512-n+D0qD3B+h/lP0dSwXX1SZMoXufdUVotLMwUuvXa50LtBAh3f+WV8b5nFMfLL/hgoPBUt+rG/pqqzF8krlZKcw==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-strikethrough": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-strikethrough/-/ansi-strikethrough-0.1.1.tgz", + "integrity": "sha512-gWkLPDvHH2pC9YEKqp8dIl0mg3sRglMPvioqGDIOXiwxjxUwIJ1gF86E2o4R5yLNh8IAkwHbaMtASkJfkQ2hIA==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-underline": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-underline/-/ansi-underline-0.1.1.tgz", + "integrity": "sha512-D+Bzwio/0/a0Fu5vJzrIT6bFk43TW46vXfSvzysOTEHcXOAUJTVMHWDbELIzGU4AVxVw2rCTb7YyWS4my2cSKQ==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-white": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-white/-/ansi-white-0.1.1.tgz", + "integrity": "sha512-DJHaF2SRzBb9wZBgqIJNjjTa7JUJTO98sHeTS1sDopyKKRopL1KpaJ20R6W2f/ZGras8bYyIZDtNwYOVXNgNFg==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-yellow": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-yellow/-/ansi-yellow-0.1.1.tgz", + "integrity": "sha512-6E3D4BQLXHLl3c/NwirWVZ+BCkMq2qsYxdeAGGOijKrx09FaqU+HktFL6QwAwNvgJiMLnv6AQ2C1gFZx0h1CBg==", + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -144,7 +487,17 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-swap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arr-swap/-/arr-swap-1.0.1.tgz", + "integrity": "sha512-SxBKd/By8+AaREcv/ZhFqmapfpqK4kyaQkUHwmJjlczI5ZtuuT5gofKHlCrSJ4oR7zXezFhv+7zsnLEdg9uGgQ==", + "dependencies": { + "is-number": "^3.0.0" + }, "engines": { "node": ">=0.10.0" } @@ -412,6 +765,11 @@ "node": ">=0.10.0" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -517,6 +875,19 @@ "ws": "^3.3.1" } }, + "node_modules/choices-separator": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/choices-separator/-/choices-separator-2.0.0.tgz", + "integrity": "sha512-BCKlzRcP2V6X+85TSKn09oGZkO2zK2zytGyZeHvM2s+kv/ydAzJtsc+rZqYRWNlojIBfkOnPxgKXrBefTFZbTQ==", + "dependencies": { + "ansi-dim": "^0.1.1", + "debug": "^2.6.6", + "strip-color": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", @@ -628,11 +999,32 @@ "node": ">=0.2.5" } }, + "node_modules/clone-deep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-1.0.0.tgz", + "integrity": "sha512-hmJRX8x1QOJVV+GUjOBzi6iauhPqc9hIF6xitWRBbiPZOBb6vGo/mDRIK9P74RTKSQK7AE8B0DDWY/vpRrPmQw==", + "dependencies": { + "for-own": "^1.0.0", + "is-plain-object": "^2.0.4", + "kind-of": "^5.0.0", + "shallow-clone": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clone-deep/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, "dependencies": { "map-visit": "^1.0.0", "object-visit": "^1.0.0" @@ -663,8 +1055,7 @@ "node_modules/component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" }, "node_modules/concat-map": { "version": "0.0.1", @@ -736,7 +1127,6 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -814,7 +1204,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, "dependencies": { "is-descriptor": "^1.0.2", "isobject": "^3.0.1" @@ -929,6 +1318,14 @@ "safer-buffer": "^2.1.0" } }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -970,6 +1367,14 @@ "is-arrayish": "^0.2.1" } }, + "node_modules/error-symbol": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/error-symbol/-/error-symbol-0.1.0.tgz", + "integrity": "sha512-VyjaKxUmeDX/m2lxm/aknsJ1GWDWUO2Ze2Ad8S1Pb9dykAm9TjSKp5CjrNyltYqZ5W/PO6TInAmO2/BfwMyT1g==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1402,7 +1807,17 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", + "dependencies": { + "for-in": "^1.0.1" + }, "engines": { "node": ">=0.10.0" } @@ -1556,7 +1971,7 @@ "node_modules/glob-parent": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", "dev": true, "dependencies": { "is-glob": "^3.1.0", @@ -1904,6 +2319,14 @@ "wrappy": "1" } }, + "node_modules/info-symbol": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/info-symbol/-/info-symbol-0.1.0.tgz", + "integrity": "sha512-qkc9wjLDQ+dYYZnY5uJXGNNHyZ0UOMDUnhvy0SEZGVVYmQ5s4i8cPAin2MbU6OxJgi8dfj/AnwqPx0CJE6+Lsw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -1921,7 +2344,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, "dependencies": { "kind-of": "^6.0.0" }, @@ -1938,14 +2360,12 @@ "node_modules/is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, "node_modules/is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, "dependencies": { "kind-of": "^6.0.0" }, @@ -1957,7 +2377,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, "dependencies": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", @@ -1996,6 +2415,14 @@ "node": ">=0.10.0" } }, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "engines": { + "node": ">=4" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -2011,7 +2438,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, "dependencies": { "kind-of": "^3.0.2" }, @@ -2023,7 +2449,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "dependencies": { "is-buffer": "^1.1.5" }, @@ -2046,7 +2471,6 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, "dependencies": { "isobject": "^3.0.1" }, @@ -2065,7 +2489,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -2080,7 +2503,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -2165,6 +2587,26 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", + "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", + "dependencies": { + "jws": "^3.2.2", + "lodash": "^4.17.21", + "ms": "^2.1.1", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, "node_modules/jsprim": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", @@ -2223,11 +2665,48 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/koalas": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/koalas/-/koalas-1.0.2.tgz", + "integrity": "sha512-RYhBbYaTTTHId3l6fnMZc3eGQNW6FVCqMG6AMwA5I1Mafr6AflaXeoi6x3xQuATRotGYRLk6+1ELZH4dstFNOA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lazy-cache": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", + "integrity": "sha512-7vp2Acd2+Kz4XkzxGxaB1FWOi8KjWIWsgdfD5MCb86DWvlLqhRPM+d6Pro3iNEL5VT9mstz5hKAlcd+QR6H3aA==", + "dependencies": { + "set-getter": "^0.1.0" + }, "engines": { "node": ">=0.10.0" } @@ -2307,8 +2786,7 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash.merge": { "version": "4.6.2", @@ -2322,11 +2800,51 @@ "integrity": "sha1-5pfwTOXXhSL1TZM4syuBozk+TrM=", "dev": true }, + "node_modules/log-ok": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/log-ok/-/log-ok-0.1.1.tgz", + "integrity": "sha512-cc8VrkS6C+9TFuYAwuHpshrcrGRAv7d0tUJ0GdM72ZBlKXtlgjUZF84O+OhQUdiVHoF7U/nVxwpjOdwUJ8d3Vg==", + "dependencies": { + "ansi-green": "^0.1.1", + "success-symbol": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/log-utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/log-utils/-/log-utils-0.2.1.tgz", + "integrity": "sha512-udyegKoMz9eGfpKAX//Khy7sVAZ8b1F7oLDnepZv/1/y8xTvsyPgqQrM94eG8V0vcc2BieYI2kVW4+aa6m+8Qw==", + "dependencies": { + "ansi-colors": "^0.2.0", + "error-symbol": "^0.1.0", + "info-symbol": "^0.1.0", + "log-ok": "^0.1.1", + "success-symbol": "^0.1.0", + "time-stamp": "^1.0.1", + "warning-symbol": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/looper": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/looper/-/looper-3.0.0.tgz", "integrity": "sha1-LvpUw7HLq6m5Su4uWRSwvlf7t0k=" }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", @@ -2340,7 +2858,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, "dependencies": { "object-visit": "^1.0.0" }, @@ -2464,6 +2981,34 @@ "node": ">=0.10.0" } }, + "node_modules/mixin-object": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", + "integrity": "sha512-ALGF1Jt9ouehcaXaHhn6t1yGWRqGaHkPFndtFVHfZXOvkIZ/yoGaSi0AHVTafb3ZBGg4dr/bDwnaEKqCXzchMA==", + "dependencies": { + "for-in": "^0.1.3", + "is-extendable": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-object/node_modules/for-in": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", + "integrity": "sha512-F0to7vbBSHP8E3l6dCjxNOLuSFAACIxFy3UehTUlG7svlXi37HHsDkyVcHo0Pq8QwrE+pXvWSVX3ZT1T9wAZ9g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-object/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", @@ -2482,6 +3027,11 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "node_modules/mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==" + }, "node_modules/nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -2517,6 +3067,14 @@ "resolved": "https://registry.npmjs.org/netflux-websocket/-/netflux-websocket-0.1.21.tgz", "integrity": "sha512-Zjl5lefg8urC0a0T7YCPGiUgRsISZBsTZl1STylmQz8Bq4ohcZ8cP3r6VoCpeVcvJ1Y/e3ZCXPxndWlNP9Jfug==" }, + "node_modules/notp": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/notp/-/notp-2.0.3.tgz", + "integrity": "sha512-oBig/2uqkjQ5AkBuw4QJYwkEWa/q+zHxI5/I5z6IeP2NT0alpJFsP/trrfCC+9xOAgQSZXssNi962kp5KBmypQ==", + "engines": { + "node": "> v0.6.0" + } + }, "node_modules/nthen": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/nthen/-/nthen-0.1.8.tgz", @@ -2536,7 +3094,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, "dependencies": { "copy-descriptor": "^0.1.0", "define-property": "^0.2.5", @@ -2550,7 +3107,6 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, "dependencies": { "is-descriptor": "^0.1.0" }, @@ -2562,7 +3118,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, "dependencies": { "kind-of": "^3.0.2" }, @@ -2574,7 +3129,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, "dependencies": { "kind-of": "^3.0.2" }, @@ -2586,7 +3140,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, "dependencies": { "is-accessor-descriptor": "^0.1.6", "is-data-descriptor": "^0.1.4", @@ -2600,7 +3153,6 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -2609,7 +3161,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "dependencies": { "is-buffer": "^1.1.5" }, @@ -2629,7 +3180,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, "dependencies": { "isobject": "^3.0.0" }, @@ -2788,6 +3338,14 @@ "node": ">=6" } }, + "node_modules/pointer-symbol": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pointer-symbol/-/pointer-symbol-1.0.0.tgz", + "integrity": "sha512-pozTTFO3kG9HQWXCSTJkCgq4fBF8lUQf+5bLddTEW6v4zdjQhcBVfLmKzABEMJMA7s8jhzi0sgANIwdrf4kq+A==", + "engines": { + "node": ">=4" + } + }, "node_modules/posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -2870,6 +3428,179 @@ "asap": "~2.0.3" } }, + "node_modules/prompt-actions": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/prompt-actions/-/prompt-actions-3.0.2.tgz", + "integrity": "sha512-dhz2Fl7vK+LPpmnQ/S/eSut4BnH4NZDLyddHKi5uTU/2PDn3grEMGkgsll16V5RpVUh/yxdiam0xsM0RD4xvtg==", + "dependencies": { + "debug": "^2.6.8" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/prompt-base": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/prompt-base/-/prompt-base-4.1.0.tgz", + "integrity": "sha512-svGzgLUKZoqomz9SGMkf1hBG8Wl3K7JGuRCXc/Pv7xw8239hhaTBXrmjt7EXA9P/QZzdyT8uNWt9F/iJTXq75g==", + "dependencies": { + "component-emitter": "^1.2.1", + "debug": "^3.0.1", + "koalas": "^1.0.2", + "log-utils": "^0.2.1", + "prompt-actions": "^3.0.2", + "prompt-question": "^5.0.1", + "readline-ui": "^2.2.3", + "readline-utils": "^2.2.3", + "static-extend": "^0.1.2" + }, + "engines": { + "node": ">=5.0" + } + }, + "node_modules/prompt-base/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/prompt-base/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/prompt-choices": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/prompt-choices/-/prompt-choices-4.1.0.tgz", + "integrity": "sha512-ZNYLv6rW9z9n0WdwCkEuS+w5nUAGzRgtRt6GQ5aFNFz6MIcU7nHFlHOwZtzy7RQBk80KzUGPSRQphvMiQzB8pg==", + "dependencies": { + "arr-flatten": "^1.1.0", + "arr-swap": "^1.0.1", + "choices-separator": "^2.0.0", + "clone-deep": "^4.0.0", + "collection-visit": "^1.0.0", + "define-property": "^2.0.2", + "is-number": "^6.0.0", + "kind-of": "^6.0.2", + "koalas": "^1.0.2", + "log-utils": "^0.2.1", + "pointer-symbol": "^1.0.0", + "radio-symbol": "^2.0.0", + "set-value": "^3.0.0", + "strip-color": "^0.1.0", + "terminal-paginator": "^2.0.2", + "toggle-array": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/prompt-choices/node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/prompt-choices/node_modules/is-number": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-6.0.0.tgz", + "integrity": "sha512-Wu1VHeILBK8KAWJUAiSZQX94GmOE45Rg6/538fKwiloUu21KncEkYGPqob2oSZ5mUT73vLGrHQjKw3KMPwfDzg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prompt-choices/node_modules/set-value": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-3.0.3.tgz", + "integrity": "sha512-Xsn/XSatoVOGBbp5hs3UylFDs5Bi9i+ArpVJKdHPniZHoEgRniXTqHWrWrGQ0PbEClVT6WtfnBwR8CAHC9sveg==", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/prompt-choices/node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/prompt-confirm": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/prompt-confirm/-/prompt-confirm-2.0.4.tgz", + "integrity": "sha512-X5lzbC8/kMNHdPOqQPfMKpH4VV2f7v2OTRJoN69ZYBirSwTeQaf9ZhmzPEO9ybMA0YV2Pha5MV27u2/U4ahWfg==", + "dependencies": { + "ansi-cyan": "^0.1.1", + "prompt-base": "^4.0.1" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/prompt-question": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/prompt-question/-/prompt-question-5.0.2.tgz", + "integrity": "sha512-wreaLbbu8f5+7zXds199uiT11Ojp59Z4iBi6hONlSLtsKGTvL2UY8VglcxQ3t/X4qWIxsNCg6aT4O8keO65v6Q==", + "dependencies": { + "clone-deep": "^1.0.0", + "debug": "^3.0.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "kind-of": "^5.0.2", + "koalas": "^1.0.2", + "prompt-choices": "^4.0.5" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/prompt-question/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/prompt-question/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prompt-question/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prompt-question/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -2921,6 +3652,19 @@ "node": ">=0.6" } }, + "node_modules/radio-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/radio-symbol/-/radio-symbol-2.0.0.tgz", + "integrity": "sha512-fpuWhwGD4XG1BfUWKXhCqdguCXzGi/DDb6RzmAGZo9R75enjlx0l+ZhHF93KNG7iNpT0Vi7wEqbf8ZErbe+JtQ==", + "dependencies": { + "ansi-gray": "^0.1.1", + "ansi-green": "^0.1.1", + "is-windows": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -2955,6 +3699,58 @@ "string_decoder": "~0.10.x" } }, + "node_modules/readline-ui": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/readline-ui/-/readline-ui-2.2.3.tgz", + "integrity": "sha512-ix7jz0PxqQqcIuq3yQTHv1TOhlD2IHO74aNO+lSuXsRYm1d+pdyup1yF3zKyLK1wWZrVNGjkzw5tUegO2IDy+A==", + "dependencies": { + "component-emitter": "^1.2.1", + "debug": "^2.6.8", + "readline-utils": "^2.2.1", + "string-width": "^2.0.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/readline-utils": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/readline-utils/-/readline-utils-2.2.3.tgz", + "integrity": "sha512-cjFo7R7e7AaFOz2JLQ4EgsHh4+l7mw29Eu3DAEPgGeWbYQFKqyxWsL61/McC6b2oJAvn14Ea8eUms9o8ZFC1iQ==", + "dependencies": { + "arr-flatten": "^1.1.0", + "extend-shallow": "^2.0.1", + "is-buffer": "^1.1.5", + "is-number": "^3.0.0", + "is-windows": "^1.0.1", + "koalas": "^1.0.2", + "mute-stream": "0.0.7", + "strip-color": "^0.1.0", + "window-size": "^1.1.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/readline-utils/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readline-utils/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -3106,6 +3902,20 @@ "node": ">= 6.9.0" } }, + "node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -3148,6 +3958,17 @@ "node": ">= 0.8.0" } }, + "node_modules/set-getter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/set-getter/-/set-getter-0.1.1.tgz", + "integrity": "sha512-9sVWOy+gthr+0G9DzqqLaYNA7+5OKkSmcqjL9cBpDEaZrr3ShQlyX2cZ/O/ozE41oxn/Tt0LGEM/w4Rub3A3gw==", + "dependencies": { + "to-object-path": "^0.3.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/set-immediate-shim": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", @@ -3198,6 +4019,35 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "node_modules/shallow-clone": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz", + "integrity": "sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==", + "dependencies": { + "is-extendable": "^0.1.1", + "kind-of": "^5.0.0", + "mixin-object": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shallow-clone/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shallow-clone/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -3495,7 +4345,6 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, "dependencies": { "define-property": "^0.2.5", "object-copy": "^0.1.0" @@ -3508,7 +4357,6 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, "dependencies": { "is-descriptor": "^0.1.0" }, @@ -3520,7 +4368,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, "dependencies": { "kind-of": "^3.0.2" }, @@ -3532,7 +4379,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "dependencies": { "is-buffer": "^1.1.5" }, @@ -3544,7 +4390,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, "dependencies": { "kind-of": "^3.0.2" }, @@ -3556,7 +4401,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "dependencies": { "is-buffer": "^1.1.5" }, @@ -3568,7 +4412,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, "dependencies": { "is-accessor-descriptor": "^0.1.6", "is-data-descriptor": "^0.1.4", @@ -3582,7 +4425,6 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3610,6 +4452,37 @@ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true }, + "node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-color": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/strip-color/-/strip-color-0.1.0.tgz", + "integrity": "sha512-p9LsUieSjWNNAxVCXLeilaDlmuUOrDS5/dF9znM1nZc7EGX5+zEFC0bEevsNIaldjlks+2jns5Siz6F9iK6jwA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/strip-json-comments": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", @@ -3622,6 +4495,62 @@ "node": ">=0.8.0" } }, + "node_modules/success-symbol": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/success-symbol/-/success-symbol-0.1.0.tgz", + "integrity": "sha512-7S6uOTxPklNGxOSbDIg4KlVLBQw1UiGVyfCUYgYxrZUKRblUkmGj7r8xlfQoFudvqLv6Ap5gd76/IIFfI9JG2A==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/terminal-paginator": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/terminal-paginator/-/terminal-paginator-2.0.2.tgz", + "integrity": "sha512-IZMT5ECF9p4s+sNCV8uvZSW9E1+9zy9Ji9xz2oee8Jfo7hUFpauyjxkhfRcIH6Lu3Wdepv5D1kVRc8Hx74/LfQ==", + "dependencies": { + "debug": "^2.6.6", + "extend-shallow": "^2.0.1", + "log-utils": "^0.2.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/terminal-paginator/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/terminal-paginator/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/thirty-two": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/thirty-two/-/thirty-two-1.0.2.tgz", + "integrity": "sha512-OEI0IWCe+Dw46019YLl6V10Us5bi574EvlJEOcAkB29IzQ/mYD1A6RyNHLjZPiHCmuodxvgF6U+vZO1L15lxVA==", + "engines": { + "node": ">=0.2.6" + } + }, + "node_modules/time-stamp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", + "integrity": "sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/tiny-each-async": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/tiny-each-async/-/tiny-each-async-2.0.3.tgz", @@ -3643,7 +4572,6 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, "dependencies": { "kind-of": "^3.0.2" }, @@ -3655,7 +4583,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "dependencies": { "is-buffer": "^1.1.5" }, @@ -3691,6 +4618,17 @@ "node": ">=0.10.0" } }, + "node_modules/toggle-array": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toggle-array/-/toggle-array-1.0.1.tgz", + "integrity": "sha512-TZXgboKpD5Iu0Goi8hRXuJpE06Pbo+bies4I4jnTBhlRRgyen9c37nMylnquK/ZPKXXOeh1mJ14p9QdKp+9v7A==", + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -3937,6 +4875,40 @@ "dev": true, "optional": true }, + "node_modules/warning-symbol": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/warning-symbol/-/warning-symbol-0.1.0.tgz", + "integrity": "sha512-1S0lwbHo3kNUKA4VomBAhqn4DPjQkIKSdbOin5K7EFUQNwyIKx+wZMGXKI53RUjla8V2B8ouQduUlgtx8LoSMw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/window-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-1.1.1.tgz", + "integrity": "sha512-5D/9vujkmVQ7pSmc0SCBmHXbkv6eaHwXEx65MywhmUMsI8sGqJ972APq1lotfcwMKPFLuCFfL8xGHLIp7jaBmA==", + "dependencies": { + "define-property": "^1.0.0", + "is-number": "^3.0.0" + }, + "bin": { + "window-size": "cli.js" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/window-size/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -3974,6 +4946,11 @@ "engines": { "node": ">=4.0" } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } }, "dependencies": { @@ -4049,6 +5026,258 @@ "uri-js": "^4.2.2" } }, + "ansi-bgblack": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgblack/-/ansi-bgblack-0.1.1.tgz", + "integrity": "sha512-tp8M/NCmSr6/skdteeo9UgJ2G1rG88X3ZVNZWXUxFw4Wh0PAGaAAWQS61sfBt/1QNcwMTY3EBKOMPujwioJLaw==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-bgblue": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgblue/-/ansi-bgblue-0.1.1.tgz", + "integrity": "sha512-R8JmX2Xv3+ichUQE99oL+LvjsyK+CDWo/BtVb4QUz3hOfmf2bdEmiDot3fQcpn2WAHW3toSRdjSLm6bgtWRDlA==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-bgcyan": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgcyan/-/ansi-bgcyan-0.1.1.tgz", + "integrity": "sha512-6SByK9q2H978bmqzuzA5NPT1lRDXl3ODLz/DjC4URO5f/HqK7dnRKfoO/xQLx/makOz7zWIbRf6+Uf7bmaPSkQ==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-bggreen": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bggreen/-/ansi-bggreen-0.1.1.tgz", + "integrity": "sha512-8TRtOKmIPOuxjpklrkhUbqD2NnVb4WZQuIjXrT+TGKFKzl7NrL7wuNvEap3leMt2kQaCngIN1ZzazSbJNzF+Aw==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-bgmagenta": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgmagenta/-/ansi-bgmagenta-0.1.1.tgz", + "integrity": "sha512-UZYhobiGAlV4NiwOlKAKbkCyxOl1PPZNvdIdl/Ce5by45vwiyNdBetwHk/AjIpo1Ji9z+eE29PUBAjjfVmz5SA==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-bgred": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgred/-/ansi-bgred-0.1.1.tgz", + "integrity": "sha512-BpPHMnYmRBhcjY5knRWKjQmPDPvYU7wrgBSW34xj7JCH9+a/SEIV7+oSYVOgMFopRIadOz9Qm4zIy+mEBvUOPA==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-bgwhite": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgwhite/-/ansi-bgwhite-0.1.1.tgz", + "integrity": "sha512-KIF19t+HOYOorUnHTOhZpeZ3bJsjzStBG2hSGM0WZ8YQQe4c7lj9CtwnucscJDPrNwfdz6GBF+pFkVfvHBq6uw==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-bgyellow": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bgyellow/-/ansi-bgyellow-0.1.1.tgz", + "integrity": "sha512-WyRoOFSIvOeM7e7YdlSjfAV82Z6K1+VUVbygIQ7C/VGzWYuO/d30F0PG7oXeo4uSvSywR0ozixDQvtXJEorq4Q==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-black": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-black/-/ansi-black-0.1.1.tgz", + "integrity": "sha512-hl7re02lWus7lFOUG6zexhoF5gssAfG5whyr/fOWK9hxNjUFLTjhbU/b4UHWOh2dbJu9/STSUv+80uWYzYkbTQ==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-blue": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-blue/-/ansi-blue-0.1.1.tgz", + "integrity": "sha512-8Um59dYNDdQyoczlf49RgWLzYgC2H/28W3JAIyOAU/+WkMcfZmaznm+0i1ikrE0jME6Ypk9CJ9CY2+vxbPs7Fg==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-bold": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-bold/-/ansi-bold-0.1.1.tgz", + "integrity": "sha512-wWKwcViX1E28U6FohtWOP4sHFyArELHJ2p7+3BzbibqJiuISeskq6t7JnrLisUngMF5zMhgmXVw8Equjzz9OlA==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-colors": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-0.2.0.tgz", + "integrity": "sha512-ScRNUT0TovnYw6+Xo3iKh6G+VXDw2Ds7ZRnMIuKBgHY02DgvT2T2K22/tc/916Fi0W/5Z1RzDaHQwnp75hqdbA==", + "requires": { + "ansi-bgblack": "^0.1.1", + "ansi-bgblue": "^0.1.1", + "ansi-bgcyan": "^0.1.1", + "ansi-bggreen": "^0.1.1", + "ansi-bgmagenta": "^0.1.1", + "ansi-bgred": "^0.1.1", + "ansi-bgwhite": "^0.1.1", + "ansi-bgyellow": "^0.1.1", + "ansi-black": "^0.1.1", + "ansi-blue": "^0.1.1", + "ansi-bold": "^0.1.1", + "ansi-cyan": "^0.1.1", + "ansi-dim": "^0.1.1", + "ansi-gray": "^0.1.1", + "ansi-green": "^0.1.1", + "ansi-grey": "^0.1.1", + "ansi-hidden": "^0.1.1", + "ansi-inverse": "^0.1.1", + "ansi-italic": "^0.1.1", + "ansi-magenta": "^0.1.1", + "ansi-red": "^0.1.1", + "ansi-reset": "^0.1.1", + "ansi-strikethrough": "^0.1.1", + "ansi-underline": "^0.1.1", + "ansi-white": "^0.1.1", + "ansi-yellow": "^0.1.1", + "lazy-cache": "^2.0.1" + } + }, + "ansi-cyan": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz", + "integrity": "sha512-eCjan3AVo/SxZ0/MyIYRtkpxIu/H3xZN7URr1vXVrISxeyz8fUFz0FJziamK4sS8I+t35y4rHg1b2PklyBe/7A==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-dim": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-dim/-/ansi-dim-0.1.1.tgz", + "integrity": "sha512-zAfb1fokXsq4BoZBkL0eK+6MfFctbzX3R4UMcoWrL1n2WHewFKentTvOZv2P11u6P4NtW/V47hVjaN7fJiefOg==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-gray": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "integrity": "sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-green": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-green/-/ansi-green-0.1.1.tgz", + "integrity": "sha512-WJ70OI4jCaMy52vGa/ypFSKFb/TrYNPaQ2xco5nUwE0C5H8piume/uAZNNdXXiMQ6DbRmiE7l8oNBHu05ZKkrw==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-grey": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-grey/-/ansi-grey-0.1.1.tgz", + "integrity": "sha512-+J1nM4lC+whSvf3T4jsp1KR+C63lypb+VkkwtLQMc1Dlt+nOvdZpFT0wwFTYoSlSwCcLUAaOpHF6kPkYpSa24A==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-hidden": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-hidden/-/ansi-hidden-0.1.1.tgz", + "integrity": "sha512-8gB1bo9ym9qZ/Obvrse1flRsfp2RE+40B23DhQcKxY+GSeaOJblLnzBOxzvmLTWbi5jNON3as7wd9rC0fNK73Q==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-inverse": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-inverse/-/ansi-inverse-0.1.1.tgz", + "integrity": "sha512-Kq8Z0dBRhQhDMN/Rso1Nu9niwiTsRkJncfJZXiyj7ApbfJrGrrubHXqXI37feJZkYcIx6SlTBdNCeK0OQ6X6ag==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-italic": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-italic/-/ansi-italic-0.1.1.tgz", + "integrity": "sha512-jreCxifSAqbaBvcibeQxcwhQDbEj7gF69XnpA6x83qbECEBaRBD1epqskrmov1z4B+zzQuEdwbWxgzvhKa+PkA==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-magenta": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-magenta/-/ansi-magenta-0.1.1.tgz", + "integrity": "sha512-A1Giu+HRwyWuiXKyXPw2AhG1yWZjNHWO+5mpt+P+VWYkmGRpLPry0O5gmlJQEvpjNpl4RjFV7DJQ4iozWOmkbQ==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-red": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", + "integrity": "sha512-ewaIr5y+9CUTGFwZfpECUbFlGcC0GCw1oqR9RI6h1gQCd9Aj2GxSckCnPsVJnmfMZbwFYE+leZGASgkWl06Jow==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==" + }, + "ansi-reset": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-reset/-/ansi-reset-0.1.1.tgz", + "integrity": "sha512-n+D0qD3B+h/lP0dSwXX1SZMoXufdUVotLMwUuvXa50LtBAh3f+WV8b5nFMfLL/hgoPBUt+rG/pqqzF8krlZKcw==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-strikethrough": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-strikethrough/-/ansi-strikethrough-0.1.1.tgz", + "integrity": "sha512-gWkLPDvHH2pC9YEKqp8dIl0mg3sRglMPvioqGDIOXiwxjxUwIJ1gF86E2o4R5yLNh8IAkwHbaMtASkJfkQ2hIA==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-underline": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-underline/-/ansi-underline-0.1.1.tgz", + "integrity": "sha512-D+Bzwio/0/a0Fu5vJzrIT6bFk43TW46vXfSvzysOTEHcXOAUJTVMHWDbELIzGU4AVxVw2rCTb7YyWS4my2cSKQ==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-white": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-white/-/ansi-white-0.1.1.tgz", + "integrity": "sha512-DJHaF2SRzBb9wZBgqIJNjjTa7JUJTO98sHeTS1sDopyKKRopL1KpaJ20R6W2f/ZGras8bYyIZDtNwYOVXNgNFg==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==" + }, + "ansi-yellow": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-yellow/-/ansi-yellow-0.1.1.tgz", + "integrity": "sha512-6E3D4BQLXHLl3c/NwirWVZ+BCkMq2qsYxdeAGGOijKrx09FaqU+HktFL6QwAwNvgJiMLnv6AQ2C1gFZx0h1CBg==", + "requires": { + "ansi-wrap": "0.1.0" + } + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -4067,8 +5296,15 @@ "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + }, + "arr-swap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arr-swap/-/arr-swap-1.0.1.tgz", + "integrity": "sha512-SxBKd/By8+AaREcv/ZhFqmapfpqK4kyaQkUHwmJjlczI5ZtuuT5gofKHlCrSJ4oR7zXezFhv+7zsnLEdg9uGgQ==", + "requires": { + "is-number": "^3.0.0" + } }, "arr-union": { "version": "3.1.0", @@ -4289,6 +5525,11 @@ } } }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -4376,6 +5617,16 @@ "ws": "^3.3.1" } }, + "choices-separator": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/choices-separator/-/choices-separator-2.0.0.tgz", + "integrity": "sha512-BCKlzRcP2V6X+85TSKn09oGZkO2zK2zytGyZeHvM2s+kv/ydAzJtsc+rZqYRWNlojIBfkOnPxgKXrBefTFZbTQ==", + "requires": { + "ansi-dim": "^0.1.1", + "debug": "^2.6.6", + "strip-color": "^0.1.0" + } + }, "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", @@ -4466,11 +5717,28 @@ "glob": "^7.1.1" } }, + "clone-deep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-1.0.0.tgz", + "integrity": "sha512-hmJRX8x1QOJVV+GUjOBzi6iauhPqc9hIF6xitWRBbiPZOBb6vGo/mDRIK9P74RTKSQK7AE8B0DDWY/vpRrPmQw==", + "requires": { + "for-own": "^1.0.0", + "is-plain-object": "^2.0.4", + "kind-of": "^5.0.0", + "shallow-clone": "^1.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, "requires": { "map-visit": "^1.0.0", "object-visit": "^1.0.0" @@ -4495,8 +5763,7 @@ "component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" }, "concat-map": { "version": "0.0.1", @@ -4546,8 +5813,7 @@ "copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" }, "core-util-is": { "version": "1.0.3", @@ -4607,7 +5873,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, "requires": { "is-descriptor": "^1.0.2", "isobject": "^3.0.1" @@ -4699,6 +5964,14 @@ "safer-buffer": "^2.1.0" } }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -4734,6 +6007,11 @@ "is-arrayish": "^0.2.1" } }, + "error-symbol": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/error-symbol/-/error-symbol-0.1.0.tgz", + "integrity": "sha512-VyjaKxUmeDX/m2lxm/aknsJ1GWDWUO2Ze2Ad8S1Pb9dykAm9TjSKp5CjrNyltYqZ5W/PO6TInAmO2/BfwMyT1g==" + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -5063,8 +6341,15 @@ "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", + "requires": { + "for-in": "^1.0.1" + } }, "forever-agent": { "version": "0.6.1", @@ -5193,7 +6478,7 @@ "glob-parent": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "integrity": "sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==", "dev": true, "requires": { "is-glob": "^3.1.0", @@ -5453,6 +6738,11 @@ "wrappy": "1" } }, + "info-symbol": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/info-symbol/-/info-symbol-0.1.0.tgz", + "integrity": "sha512-qkc9wjLDQ+dYYZnY5uJXGNNHyZ0UOMDUnhvy0SEZGVVYmQ5s4i8cPAin2MbU6OxJgi8dfj/AnwqPx0CJE6+Lsw==" + }, "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -5467,7 +6757,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -5481,14 +6770,12 @@ "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -5497,7 +6784,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", @@ -5524,6 +6810,11 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" + }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -5536,7 +6827,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, "requires": { "kind-of": "^3.0.2" }, @@ -5545,7 +6835,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -5561,7 +6850,6 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, "requires": { "isobject": "^3.0.1" } @@ -5576,8 +6864,7 @@ "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" }, "isarray": { "version": "0.0.1", @@ -5588,8 +6875,7 @@ "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" }, "isstream": { "version": "0.1.2", @@ -5665,6 +6951,24 @@ "graceful-fs": "^4.1.6" } }, + "jsonwebtoken": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", + "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", + "requires": { + "jws": "^3.2.2", + "lodash": "^4.17.21", + "ms": "^2.1.1", + "semver": "^7.3.8" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, "jsprim": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", @@ -5722,11 +7026,42 @@ } } }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, + "koalas": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/koalas/-/koalas-1.0.2.tgz", + "integrity": "sha512-RYhBbYaTTTHId3l6fnMZc3eGQNW6FVCqMG6AMwA5I1Mafr6AflaXeoi6x3xQuATRotGYRLk6+1ELZH4dstFNOA==" + }, + "lazy-cache": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", + "integrity": "sha512-7vp2Acd2+Kz4XkzxGxaB1FWOi8KjWIWsgdfD5MCb86DWvlLqhRPM+d6Pro3iNEL5VT9mstz5hKAlcd+QR6H3aA==", + "requires": { + "set-getter": "^0.1.0" + } }, "less": { "version": "3.7.1", @@ -5787,8 +7122,7 @@ "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "lodash.merge": { "version": "4.6.2", @@ -5802,11 +7136,42 @@ "integrity": "sha1-5pfwTOXXhSL1TZM4syuBozk+TrM=", "dev": true }, + "log-ok": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/log-ok/-/log-ok-0.1.1.tgz", + "integrity": "sha512-cc8VrkS6C+9TFuYAwuHpshrcrGRAv7d0tUJ0GdM72ZBlKXtlgjUZF84O+OhQUdiVHoF7U/nVxwpjOdwUJ8d3Vg==", + "requires": { + "ansi-green": "^0.1.1", + "success-symbol": "^0.1.0" + } + }, + "log-utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/log-utils/-/log-utils-0.2.1.tgz", + "integrity": "sha512-udyegKoMz9eGfpKAX//Khy7sVAZ8b1F7oLDnepZv/1/y8xTvsyPgqQrM94eG8V0vcc2BieYI2kVW4+aa6m+8Qw==", + "requires": { + "ansi-colors": "^0.2.0", + "error-symbol": "^0.1.0", + "info-symbol": "^0.1.0", + "log-ok": "^0.1.1", + "success-symbol": "^0.1.0", + "time-stamp": "^1.0.1", + "warning-symbol": "^0.1.0" + } + }, "looper": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/looper/-/looper-3.0.0.tgz", "integrity": "sha1-LvpUw7HLq6m5Su4uWRSwvlf7t0k=" }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, "map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", @@ -5817,7 +7182,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, "requires": { "object-visit": "^1.0.0" } @@ -5908,6 +7272,27 @@ "is-extendable": "^1.0.1" } }, + "mixin-object": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", + "integrity": "sha512-ALGF1Jt9ouehcaXaHhn6t1yGWRqGaHkPFndtFVHfZXOvkIZ/yoGaSi0AHVTafb3ZBGg4dr/bDwnaEKqCXzchMA==", + "requires": { + "for-in": "^0.1.3", + "is-extendable": "^0.1.1" + }, + "dependencies": { + "for-in": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", + "integrity": "sha512-F0to7vbBSHP8E3l6dCjxNOLuSFAACIxFy3UehTUlG7svlXi37HHsDkyVcHo0Pq8QwrE+pXvWSVX3ZT1T9wAZ9g==" + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==" + } + } + }, "mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", @@ -5923,6 +7308,11 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha512-r65nCZhrbXXb6dXOACihYApHw2Q6pV0M3V0PSxd74N0+D8nzAdEAITq2oAjA1jVnKI+tGvEBUpqiMh0+rW6zDQ==" + }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -5952,6 +7342,11 @@ "resolved": "https://registry.npmjs.org/netflux-websocket/-/netflux-websocket-0.1.21.tgz", "integrity": "sha512-Zjl5lefg8urC0a0T7YCPGiUgRsISZBsTZl1STylmQz8Bq4ohcZ8cP3r6VoCpeVcvJ1Y/e3ZCXPxndWlNP9Jfug==" }, + "notp": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/notp/-/notp-2.0.3.tgz", + "integrity": "sha512-oBig/2uqkjQ5AkBuw4QJYwkEWa/q+zHxI5/I5z6IeP2NT0alpJFsP/trrfCC+9xOAgQSZXssNi962kp5KBmypQ==" + }, "nthen": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/nthen/-/nthen-0.1.8.tgz", @@ -5968,7 +7363,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, "requires": { "copy-descriptor": "^0.1.0", "define-property": "^0.2.5", @@ -5979,7 +7373,6 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, "requires": { "is-descriptor": "^0.1.0" } @@ -5988,7 +7381,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, "requires": { "kind-of": "^3.0.2" } @@ -5997,7 +7389,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, "requires": { "kind-of": "^3.0.2" } @@ -6006,7 +7397,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, "requires": { "is-accessor-descriptor": "^0.1.6", "is-data-descriptor": "^0.1.4", @@ -6016,8 +7406,7 @@ "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" } } }, @@ -6025,7 +7414,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -6041,7 +7429,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, "requires": { "isobject": "^3.0.0" } @@ -6163,6 +7550,11 @@ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true }, + "pointer-symbol": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pointer-symbol/-/pointer-symbol-1.0.0.tgz", + "integrity": "sha512-pozTTFO3kG9HQWXCSTJkCgq4fBF8lUQf+5bLddTEW6v4zdjQhcBVfLmKzABEMJMA7s8jhzi0sgANIwdrf4kq+A==" + }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -6226,6 +7618,152 @@ "asap": "~2.0.3" } }, + "prompt-actions": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/prompt-actions/-/prompt-actions-3.0.2.tgz", + "integrity": "sha512-dhz2Fl7vK+LPpmnQ/S/eSut4BnH4NZDLyddHKi5uTU/2PDn3grEMGkgsll16V5RpVUh/yxdiam0xsM0RD4xvtg==", + "requires": { + "debug": "^2.6.8" + } + }, + "prompt-base": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/prompt-base/-/prompt-base-4.1.0.tgz", + "integrity": "sha512-svGzgLUKZoqomz9SGMkf1hBG8Wl3K7JGuRCXc/Pv7xw8239hhaTBXrmjt7EXA9P/QZzdyT8uNWt9F/iJTXq75g==", + "requires": { + "component-emitter": "^1.2.1", + "debug": "^3.0.1", + "koalas": "^1.0.2", + "log-utils": "^0.2.1", + "prompt-actions": "^3.0.2", + "prompt-question": "^5.0.1", + "readline-ui": "^2.2.3", + "readline-utils": "^2.2.3", + "static-extend": "^0.1.2" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "prompt-choices": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/prompt-choices/-/prompt-choices-4.1.0.tgz", + "integrity": "sha512-ZNYLv6rW9z9n0WdwCkEuS+w5nUAGzRgtRt6GQ5aFNFz6MIcU7nHFlHOwZtzy7RQBk80KzUGPSRQphvMiQzB8pg==", + "requires": { + "arr-flatten": "^1.1.0", + "arr-swap": "^1.0.1", + "choices-separator": "^2.0.0", + "clone-deep": "^4.0.0", + "collection-visit": "^1.0.0", + "define-property": "^2.0.2", + "is-number": "^6.0.0", + "kind-of": "^6.0.2", + "koalas": "^1.0.2", + "log-utils": "^0.2.1", + "pointer-symbol": "^1.0.0", + "radio-symbol": "^2.0.0", + "set-value": "^3.0.0", + "strip-color": "^0.1.0", + "terminal-paginator": "^2.0.2", + "toggle-array": "^1.0.1" + }, + "dependencies": { + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "is-number": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-6.0.0.tgz", + "integrity": "sha512-Wu1VHeILBK8KAWJUAiSZQX94GmOE45Rg6/538fKwiloUu21KncEkYGPqob2oSZ5mUT73vLGrHQjKw3KMPwfDzg==" + }, + "set-value": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-3.0.3.tgz", + "integrity": "sha512-Xsn/XSatoVOGBbp5hs3UylFDs5Bi9i+ArpVJKdHPniZHoEgRniXTqHWrWrGQ0PbEClVT6WtfnBwR8CAHC9sveg==", + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "requires": { + "kind-of": "^6.0.2" + } + } + } + }, + "prompt-confirm": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/prompt-confirm/-/prompt-confirm-2.0.4.tgz", + "integrity": "sha512-X5lzbC8/kMNHdPOqQPfMKpH4VV2f7v2OTRJoN69ZYBirSwTeQaf9ZhmzPEO9ybMA0YV2Pha5MV27u2/U4ahWfg==", + "requires": { + "ansi-cyan": "^0.1.1", + "prompt-base": "^4.0.1" + } + }, + "prompt-question": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/prompt-question/-/prompt-question-5.0.2.tgz", + "integrity": "sha512-wreaLbbu8f5+7zXds199uiT11Ojp59Z4iBi6hONlSLtsKGTvL2UY8VglcxQ3t/X4qWIxsNCg6aT4O8keO65v6Q==", + "requires": { + "clone-deep": "^1.0.0", + "debug": "^3.0.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "kind-of": "^5.0.2", + "koalas": "^1.0.2", + "prompt-choices": "^4.0.5" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -6268,6 +7806,16 @@ "dev": true, "optional": true }, + "radio-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/radio-symbol/-/radio-symbol-2.0.0.tgz", + "integrity": "sha512-fpuWhwGD4XG1BfUWKXhCqdguCXzGi/DDb6RzmAGZo9R75enjlx0l+ZhHF93KNG7iNpT0Vi7wEqbf8ZErbe+JtQ==", + "requires": { + "ansi-gray": "^0.1.1", + "ansi-green": "^0.1.1", + "is-windows": "^1.0.1" + } + }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -6296,6 +7844,48 @@ "string_decoder": "~0.10.x" } }, + "readline-ui": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/readline-ui/-/readline-ui-2.2.3.tgz", + "integrity": "sha512-ix7jz0PxqQqcIuq3yQTHv1TOhlD2IHO74aNO+lSuXsRYm1d+pdyup1yF3zKyLK1wWZrVNGjkzw5tUegO2IDy+A==", + "requires": { + "component-emitter": "^1.2.1", + "debug": "^2.6.8", + "readline-utils": "^2.2.1", + "string-width": "^2.0.0" + } + }, + "readline-utils": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/readline-utils/-/readline-utils-2.2.3.tgz", + "integrity": "sha512-cjFo7R7e7AaFOz2JLQ4EgsHh4+l7mw29Eu3DAEPgGeWbYQFKqyxWsL61/McC6b2oJAvn14Ea8eUms9o8ZFC1iQ==", + "requires": { + "arr-flatten": "^1.1.0", + "extend-shallow": "^2.0.1", + "is-buffer": "^1.1.5", + "is-number": "^3.0.0", + "is-windows": "^1.0.1", + "koalas": "^1.0.2", + "mute-stream": "0.0.7", + "strip-color": "^0.1.0", + "window-size": "^1.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==" + } + } + }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -6421,6 +8011,14 @@ "xml2js": "^0.4.17" } }, + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "requires": { + "lru-cache": "^6.0.0" + } + }, "send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -6459,6 +8057,14 @@ "send": "0.18.0" } }, + "set-getter": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/set-getter/-/set-getter-0.1.1.tgz", + "integrity": "sha512-9sVWOy+gthr+0G9DzqqLaYNA7+5OKkSmcqjL9cBpDEaZrr3ShQlyX2cZ/O/ozE41oxn/Tt0LGEM/w4Rub3A3gw==", + "requires": { + "to-object-path": "^0.3.0" + } + }, "set-immediate-shim": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", @@ -6499,6 +8105,28 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "shallow-clone": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-1.0.0.tgz", + "integrity": "sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==", + "requires": { + "is-extendable": "^0.1.1", + "kind-of": "^5.0.0", + "mixin-object": "^2.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==" + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, "side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -6741,7 +8369,6 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, "requires": { "define-property": "^0.2.5", "object-copy": "^0.1.0" @@ -6751,7 +8378,6 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, "requires": { "is-descriptor": "^0.1.0" } @@ -6760,7 +8386,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, "requires": { "kind-of": "^3.0.2" }, @@ -6769,7 +8394,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -6780,7 +8404,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, "requires": { "kind-of": "^3.0.2" }, @@ -6789,7 +8412,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -6800,7 +8422,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, "requires": { "is-accessor-descriptor": "^0.1.6", "is-data-descriptor": "^0.1.4", @@ -6810,8 +8431,7 @@ "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" } } }, @@ -6835,12 +8455,74 @@ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "strip-color": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/strip-color/-/strip-color-0.1.0.tgz", + "integrity": "sha512-p9LsUieSjWNNAxVCXLeilaDlmuUOrDS5/dF9znM1nZc7EGX5+zEFC0bEevsNIaldjlks+2jns5Siz6F9iK6jwA==" + }, "strip-json-comments": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", "dev": true }, + "success-symbol": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/success-symbol/-/success-symbol-0.1.0.tgz", + "integrity": "sha512-7S6uOTxPklNGxOSbDIg4KlVLBQw1UiGVyfCUYgYxrZUKRblUkmGj7r8xlfQoFudvqLv6Ap5gd76/IIFfI9JG2A==" + }, + "terminal-paginator": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/terminal-paginator/-/terminal-paginator-2.0.2.tgz", + "integrity": "sha512-IZMT5ECF9p4s+sNCV8uvZSW9E1+9zy9Ji9xz2oee8Jfo7hUFpauyjxkhfRcIH6Lu3Wdepv5D1kVRc8Hx74/LfQ==", + "requires": { + "debug": "^2.6.6", + "extend-shallow": "^2.0.1", + "log-utils": "^0.2.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==" + } + } + }, + "thirty-two": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/thirty-two/-/thirty-two-1.0.2.tgz", + "integrity": "sha512-OEI0IWCe+Dw46019YLl6V10Us5bi574EvlJEOcAkB29IzQ/mYD1A6RyNHLjZPiHCmuodxvgF6U+vZO1L15lxVA==" + }, + "time-stamp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", + "integrity": "sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==" + }, "tiny-each-async": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/tiny-each-async/-/tiny-each-async-2.0.3.tgz", @@ -6859,7 +8541,6 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, "requires": { "kind-of": "^3.0.2" }, @@ -6868,7 +8549,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -6897,6 +8577,14 @@ "repeat-string": "^1.6.1" } }, + "toggle-array": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toggle-array/-/toggle-array-1.0.1.tgz", + "integrity": "sha512-TZXgboKpD5Iu0Goi8hRXuJpE06Pbo+bies4I4jnTBhlRRgyen9c37nMylnquK/ZPKXXOeh1mJ14p9QdKp+9v7A==", + "requires": { + "isobject": "^3.0.0" + } + }, "toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -7095,6 +8783,30 @@ } } }, + "warning-symbol": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/warning-symbol/-/warning-symbol-0.1.0.tgz", + "integrity": "sha512-1S0lwbHo3kNUKA4VomBAhqn4DPjQkIKSdbOin5K7EFUQNwyIKx+wZMGXKI53RUjla8V2B8ouQduUlgtx8LoSMw==" + }, + "window-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-1.1.1.tgz", + "integrity": "sha512-5D/9vujkmVQ7pSmc0SCBmHXbkv6eaHwXEx65MywhmUMsI8sGqJ972APq1lotfcwMKPFLuCFfL8xGHLIp7jaBmA==", + "requires": { + "define-property": "^1.0.0", + "is-number": "^3.0.0" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "requires": { + "is-descriptor": "^1.0.0" + } + } + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -7126,6 +8838,11 @@ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } } } diff --git a/package.json b/package.json index 168fc3596..9fe5bb1a5 100644 --- a/package.json +++ b/package.json @@ -19,13 +19,16 @@ "fs-extra": "^7.0.0", "get-folder-size": "^2.0.1", "http-proxy-middleware": "^2.0.6", + "jsonwebtoken": "^9.0.0", "netflux-websocket": "^0.1.20", + "notp": "^2.0.3", "nthen": "0.1.8", "prompt-confirm": "^2.0.4", "pull-stream": "^3.6.1", "saferphore": "0.0.1", "sortify": "^1.0.4", "stream-to-pull-stream": "^1.7.2", + "thirty-two": "^1.0.2", "tweetnacl": "~0.12.2", "ulimit": "0.0.2", "ws": "^3.3.1" From e895990426d3a45dd307cea141c45815384281d2 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 3 May 2023 16:19:01 +0530 Subject: [PATCH 28/58] generate a secret at launch time used for issuing and validating JWTs --- lib/api.js | 16 ++++++++++++++++ lib/decrees.js | 14 ++++++++++++++ lib/env.js | 3 +++ 3 files changed, 33 insertions(+) diff --git a/lib/api.js b/lib/api.js index 9a317be86..252edc1a4 100644 --- a/lib/api.js +++ b/lib/api.js @@ -6,6 +6,7 @@ const Decrees = require("./decrees"); const nThen = require("nthen"); const Fs = require("fs"); const Path = require("path"); +const Nacl = require("tweetnacl/nacl-fast"); module.exports.create = function (Env) { var log = Env.Log; @@ -21,6 +22,21 @@ nThen(function (w) { console.error(err); } })); +}).nThen(function (w) { + // we assume the server has generated a secret used to validate JWT tokens + if (typeof(Env.bearerSecret) === 'string') { return; } + // if one does not exist, then create one and remember it + // 256 bits + var bearerSecret = Nacl.util.encodeBase64(Nacl.randomBytes(32)); + Env.Log.info("GENERATING_BEARER_SECRET", {}); + Decrees.write(Env, [ + 'SET_BEARER_SECRET', + [bearerSecret], + 'INTERNAL', + +new Date() + ], w(function (err) { + if (err) { throw err; } + })); }).nThen(function (w) { var fullPath = Path.join(Env.paths.block, 'placeholder.txt'); Fs.writeFile(fullPath, 'PLACEHOLDER\n', w()); diff --git a/lib/decrees.js b/lib/decrees.js index 9b8878157..8f4b53ad8 100644 --- a/lib/decrees.js +++ b/lib/decrees.js @@ -49,6 +49,9 @@ SET_INSTANCE_DESCRIPTION SET_INSTANCE_NAME SET_INSTANCE_NOTICE +// bearer secret +SET_BEARER_SECRET + NOT IMPLEMENTED: // RESTRICTED REGISTRATION @@ -348,6 +351,17 @@ commands.ADD_ADMIN_KEY = function (Env, args) { return true; }; +commands.SET_BEARER_SECRET = function (Env, args) { + if (!args_isString(args) || args.length !== 1 || !args[0]) { + throw new Error("INVALID_ARGS"); + } + + var secret = args[0]; + if (secret === Env.bearerSecret) { return false; } + Env.bearerSecret = secret; + return true; +}; + // [, , ,