>>0?1:0),w=c.low=w+P,c.high=B+F+(w>>>0>>0?1:0),m=a.low=m+O,a.high=k+W+(m>>>0>>0?1:0),x=h.low=x+U,h.high=S+I+(x>>>0>>0?1:0),r=l.low=r+X,l.high=b+K+(r>>>0>>0?1:0)},_doFinalize:function(){var t=this._data,e=t.words,r=8*this._nDataBytes,i=8*t.sigBytes;return e[i>>>5]|=128<<24-i%32,e[30+(128+i>>>10<<5)]=Math.floor(r/4294967296),e[31+(128+i>>>10<<5)]=r,t.sigBytes=4*e.length,this._process(),this._hash.toX32()},clone:function(){var t=e.clone.call(this);return t._hash=this._hash.clone(),t},blockSize:32});t.SHA512=e._createHelper(r),t.HmacSHA512=e._createHmacHelper(r)}(),P=(M=U).x64,c=P.Word,f=P.WordArray,P=M.algo,d=P.SHA512,P=P.SHA384=d.extend({_doReset:function(){this._hash=new f.init([new c.init(3418070365,3238371032),new c.init(1654270250,914150663),new c.init(2438529370,812702999),new c.init(355462360,4144912697),new c.init(1731405415,4290775857),new c.init(2394180231,1750603025),new c.init(3675008525,1694076839),new c.init(1203062813,3204075428)])},_doFinalize:function(){var t=d._doFinalize.call(this);return t.sigBytes-=16,t}}),M.SHA384=d._createHelper(P),M.HmacSHA384=d._createHmacHelper(P),function(l){var t=U,e=t.lib,f=e.WordArray,i=e.Hasher,d=t.x64.Word,e=t.algo,A=[],H=[],z=[];!function(){for(var t=1,e=0,r=0;r<24;r++){A[t+5*e]=(r+1)*(r+2)/2%64;var i=(2*t+3*e)%5;t=e%5,e=i}for(t=0;t<5;t++)for(e=0;e<5;e++)H[t+5*e]=e+(2*t+3*e)%5*5;for(var n=1,o=0;o<24;o++){for(var s,c=0,a=0,h=0;h<7;h++)1&n&&((s=(1<>>24)|4278255360&(o<<24|o>>>8);(m=r[n]).high^=s=16711935&(s<<8|s>>>24)|4278255360&(s<<24|s>>>8),m.low^=o}for(var c=0;c<24;c++){for(var a=0;a<5;a++){for(var h=0,l=0,f=0;f<5;f++)h^=(m=r[a+5*f]).high,l^=m.low;var d=C[a];d.high=h,d.low=l}for(a=0;a<5;a++)for(var u=C[(a+4)%5],p=C[(a+1)%5],_=p.high,p=p.low,h=u.high^(_<<1|p>>>31),l=u.low^(p<<1|_>>>31),f=0;f<5;f++)(m=r[a+5*f]).high^=h,m.low^=l;for(var y=1;y<25;y++){var v=(m=r[y]).high,g=m.low,B=A[y];l=B<32?(h=v<>>32-B,g<>>32-B):(h=g<>>64-B,v<>>64-B);B=C[H[y]];B.high=h,B.low=l}var w=C[0],k=r[0];w.high=k.high,w.low=k.low;for(a=0;a<5;a++)for(f=0;f<5;f++){var m=r[y=a+5*f],S=C[y],x=C[(a+1)%5+5*f],b=C[(a+2)%5+5*f];m.high=S.high^~x.high&b.high,m.low=S.low^~x.low&b.low}m=r[0],k=z[c];m.high^=k.high,m.low^=k.low}},_doFinalize:function(){var t=this._data,e=t.words,r=(this._nDataBytes,8*t.sigBytes),i=32*this.blockSize;e[r>>>5]|=1<<24-r%32,e[(l.ceil((1+r)/i)*i>>>5)-1]|=128,t.sigBytes=4*e.length,this._process();for(var n=this._state,e=this.cfg.outputLength/8,o=e/8,s=[],c=0;c>>24)|4278255360&(h<<24|h>>>8);s.push(a=16711935&(a<<8|a>>>24)|4278255360&(a<<24|a>>>8)),s.push(h)}return new f.init(s,e)},clone:function(){for(var t=i.clone.call(this),e=t._state=this._state.slice(0),r=0;r<25;r++)e[r]=e[r].clone();return t}});t.SHA3=i._createHelper(e),t.HmacSHA3=i._createHmacHelper(e)}(Math),Math,F=(w=U).lib,u=F.WordArray,p=F.Hasher,F=w.algo,S=u.create([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,7,4,13,1,10,6,15,3,12,0,9,5,2,14,11,8,3,10,14,4,9,15,8,1,2,7,0,6,13,11,5,12,1,9,11,10,0,8,12,4,13,3,7,15,14,5,6,2,4,0,5,9,7,12,2,10,14,1,3,8,11,6,15,13]),x=u.create([5,14,7,0,9,2,11,4,13,6,15,8,1,10,3,12,6,11,3,7,0,13,5,10,14,15,8,12,4,9,1,2,15,5,1,3,7,14,6,9,11,8,12,2,10,0,4,13,8,6,4,1,3,11,15,0,5,12,2,13,9,7,10,14,12,15,10,4,1,5,8,7,6,2,13,14,0,3,9,11]),b=u.create([11,14,15,12,5,8,7,9,11,13,14,15,6,7,9,8,7,6,8,13,11,9,7,15,7,12,15,9,11,7,13,12,11,13,6,7,14,9,13,15,14,8,13,6,5,12,7,5,11,12,14,15,14,15,9,8,9,14,5,6,8,6,5,12,9,15,5,11,6,8,13,12,5,12,13,14,11,8,5,6]),A=u.create([8,9,9,11,13,15,15,5,7,7,8,11,14,14,12,6,9,13,15,7,12,8,9,11,7,7,12,7,6,15,13,11,9,7,15,11,8,6,6,14,12,13,5,14,13,13,7,5,15,5,8,11,14,14,6,14,6,9,12,9,12,5,15,8,8,5,12,9,12,5,14,6,8,13,6,5,15,13,11,11]),H=u.create([0,1518500249,1859775393,2400959708,2840853838]),z=u.create([1352829926,1548603684,1836072691,2053994217,0]),F=F.RIPEMD160=p.extend({_doReset:function(){this._hash=u.create([1732584193,4023233417,2562383102,271733878,3285377520])},_doProcessBlock:function(t,e){for(var r=0;r<16;r++){var i=e+r,n=t[i];t[i]=16711935&(n<<8|n>>>24)|4278255360&(n<<24|n>>>8)}for(var o,s,c,a,h,l,f=this._hash.words,d=H.words,u=z.words,p=S.words,_=x.words,y=b.words,v=A.words,g=o=f[0],B=s=f[1],w=c=f[2],k=a=f[3],m=h=f[4],r=0;r<80;r+=1)l=o+t[e+p[r]]|0,l+=r<16?(s^c^a)+d[0]:r<32?K(s,c,a)+d[1]:r<48?((s|~c)^a)+d[2]:r<64?X(s,c,a)+d[3]:(s^(c|~a))+d[4],l=(l=L(l|=0,y[r]))+h|0,o=h,h=a,a=L(c,10),c=s,s=l,l=g+t[e+_[r]]|0,l+=r<16?(B^(w|~k))+u[0]:r<32?X(B,w,k)+u[1]:r<48?((B|~w)^k)+u[2]:r<64?K(B,w,k)+u[3]:(B^w^k)+u[4],l=(l=L(l|=0,v[r]))+m|0,g=m,m=k,k=L(w,10),w=B,B=l;l=f[1]+c+k|0,f[1]=f[2]+a+m|0,f[2]=f[3]+h+g|0,f[3]=f[4]+o+B|0,f[4]=f[0]+s+w|0,f[0]=l},_doFinalize:function(){var t=this._data,e=t.words,r=8*this._nDataBytes,i=8*t.sigBytes;e[i>>>5]|=128<<24-i%32,e[14+(64+i>>>9<<4)]=16711935&(r<<8|r>>>24)|4278255360&(r<<24|r>>>8),t.sigBytes=4*(e.length+1),this._process();for(var e=this._hash,n=e.words,o=0;o<5;o++){var s=n[o];n[o]=16711935&(s<<8|s>>>24)|4278255360&(s<<24|s>>>8)}return e},clone:function(){var t=p.clone.call(this);return t._hash=this._hash.clone(),t}}),w.RIPEMD160=p._createHelper(F),w.HmacRIPEMD160=p._createHmacHelper(F),P=(M=U).lib.Base,_=M.enc.Utf8,M.algo.HMAC=P.extend({init:function(t,e){t=this._hasher=new t.init,"string"==typeof e&&(e=_.parse(e));var r=t.blockSize,i=4*r;(e=e.sigBytes>i?t.finalize(e):e).clamp();for(var t=this._oKey=e.clone(),e=this._iKey=e.clone(),n=t.words,o=e.words,s=0;s>>2];t.sigBytes-=e}},d=(e.BlockCipher=a.extend({cfg:a.cfg.extend({mode:n,padding:l}),reset:function(){var t;a.reset.call(this);var e=this.cfg,r=e.iv,e=e.mode;this._xformMode==this._ENC_XFORM_MODE?t=e.createEncryptor:(t=e.createDecryptor,this._minBufferSize=1),this._mode&&this._mode.__creator==t?this._mode.init(this,r&&r.words):(this._mode=t.call(e,this,r&&r.words),this._mode.__creator=t)},_doProcessBlock:function(t,e){this._mode.processBlock(t,e)},_doFinalize:function(){var t,e=this.cfg.padding;return this._xformMode==this._ENC_XFORM_MODE?(e.pad(this._data,this.blockSize),t=this._process(!0)):(t=this._process(!0),e.unpad(t)),t},blockSize:4}),e.CipherParams=r.extend({init:function(t){this.mixIn(t)},toString:function(t){return(t||this.formatter).stringify(this)}})),l=(t.format={}).OpenSSL={stringify:function(t){var e=t.ciphertext,t=t.salt,e=t?s.create([1398893684,1701076831]).concat(t).concat(e):e;return e.toString(o)},parse:function(t){var e,r=o.parse(t),t=r.words;return 1398893684==t[0]&&1701076831==t[1]&&(e=s.create(t.slice(2,4)),t.splice(0,4),r.sigBytes-=16),d.create({ciphertext:r,salt:e})}},u=e.SerializableCipher=r.extend({cfg:r.extend({format:l}),encrypt:function(t,e,r,i){i=this.cfg.extend(i);var n=t.createEncryptor(r,i),e=n.finalize(e),n=n.cfg;return d.create({ciphertext:e,key:r,iv:n.iv,algorithm:t,mode:n.mode,padding:n.padding,blockSize:t.blockSize,formatter:i.format})},decrypt:function(t,e,r,i){return i=this.cfg.extend(i),e=this._parse(e,i.format),t.createDecryptor(r,i).finalize(e.ciphertext)},_parse:function(t,e){return"string"==typeof t?e.parse(t,this):t}}),t=(t.kdf={}).OpenSSL={execute:function(t,e,r,i){i=i||s.random(8);t=c.create({keySize:e+r}).compute(t,i),r=s.create(t.words.slice(e),4*r);return t.sigBytes=4*e,d.create({key:t,iv:r,salt:i})}},p=e.PasswordBasedCipher=u.extend({cfg:u.cfg.extend({kdf:t}),encrypt:function(t,e,r,i){r=(i=this.cfg.extend(i)).kdf.execute(r,t.keySize,t.ivSize);i.iv=r.iv;i=u.encrypt.call(this,t,e,r.key,i);return i.mixIn(r),i},decrypt:function(t,e,r,i){i=this.cfg.extend(i),e=this._parse(e,i.format);r=i.kdf.execute(r,t.keySize,t.ivSize,e.salt);return i.iv=r.iv,u.decrypt.call(this,t,e,r.key,i)}})}(),U.mode.CFB=((F=U.lib.BlockCipherMode.extend()).Encryptor=F.extend({processBlock:function(t,e){var r=this._cipher,i=r.blockSize;j.call(this,t,e,i,r),this._prevBlock=t.slice(e,e+i)}}),F.Decryptor=F.extend({processBlock:function(t,e){var r=this._cipher,i=r.blockSize,n=t.slice(e,e+i);j.call(this,t,e,i,r),this._prevBlock=n}}),F),U.mode.CTR=(M=U.lib.BlockCipherMode.extend(),P=M.Encryptor=M.extend({processBlock:function(t,e){var r=this._cipher,i=r.blockSize,n=this._iv,o=this._counter;n&&(o=this._counter=n.slice(0),this._iv=void 0);var s=o.slice(0);r.encryptBlock(s,0),o[i-1]=o[i-1]+1|0;for(var c=0;c>>2]|=e<<24-r%4*8,t.sigBytes+=e},unpad:function(t){var e=255&t.words[t.sigBytes-1>>>2];t.sigBytes-=e}},U.pad.Iso10126={pad:function(t,e){e*=4,e-=t.sigBytes%e;t.concat(U.lib.WordArray.random(e-1)).concat(U.lib.WordArray.create([e<<24],1))},unpad:function(t){var e=255&t.words[t.sigBytes-1>>>2];t.sigBytes-=e}},U.pad.Iso97971={pad:function(t,e){t.concat(U.lib.WordArray.create([2147483648],1)),U.pad.ZeroPadding.pad(t,e)},unpad:function(t){U.pad.ZeroPadding.unpad(t),t.sigBytes--}},U.pad.ZeroPadding={pad:function(t,e){e*=4;t.clamp(),t.sigBytes+=e-(t.sigBytes%e||e)},unpad:function(t){for(var e=t.words,r=t.sigBytes-1,r=t.sigBytes-1;0<=r;r--)if(e[r>>>2]>>>24-r%4*8&255){t.sigBytes=r+1;break}}},U.pad.NoPadding={pad:function(){},unpad:function(){}},m=(P=U).lib.CipherParams,C=P.enc.Hex,P.format.Hex={stringify:function(t){return t.ciphertext.toString(C)},parse:function(t){t=C.parse(t);return m.create({ciphertext:t})}},function(){var t=U,e=t.lib.BlockCipher,r=t.algo,h=[],l=[],f=[],d=[],u=[],p=[],_=[],y=[],v=[],g=[];!function(){for(var t=[],e=0;e<256;e++)t[e]=e<128?e<<1:e<<1^283;for(var r=0,i=0,e=0;e<256;e++){var n=i^i<<1^i<<2^i<<3^i<<4;h[r]=n=n>>>8^255&n^99;var o=t[l[n]=r],s=t[o],c=t[s],a=257*t[n]^16843008*n;f[r]=a<<24|a>>>8,d[r]=a<<16|a>>>16,u[r]=a<<8|a>>>24,p[r]=a,_[n]=(a=16843009*c^65537*s^257*o^16843008*r)<<24|a>>>8,y[n]=a<<16|a>>>16,v[n]=a<<8|a>>>24,g[n]=a,r?(r=o^t[t[t[c^o]]],i^=t[t[i]]):r=i=1}}();var B=[0,1,2,4,8,16,32,64,128,27,54],r=r.AES=e.extend({_doReset:function(){if(!this._nRounds||this._keyPriorReset!==this._key){for(var t=this._keyPriorReset=this._key,e=t.words,r=t.sigBytes/4,i=4*(1+(this._nRounds=6+r)),n=this._keySchedule=[],o=0;o>>24]<<24|h[a>>>16&255]<<16|h[a>>>8&255]<<8|h[255&a]):(a=h[(a=a<<8|a>>>24)>>>24]<<24|h[a>>>16&255]<<16|h[a>>>8&255]<<8|h[255&a],a^=B[o/r|0]<<24),n[o]=n[o-r]^a);for(var s=this._invKeySchedule=[],c=0;c>>24]]^y[h[a>>>16&255]]^v[h[a>>>8&255]]^g[h[255&a]]}}},encryptBlock:function(t,e){this._doCryptBlock(t,e,this._keySchedule,f,d,u,p,h)},decryptBlock:function(t,e){var r=t[e+1];t[e+1]=t[e+3],t[e+3]=r,this._doCryptBlock(t,e,this._invKeySchedule,_,y,v,g,l);r=t[e+1];t[e+1]=t[e+3],t[e+3]=r},_doCryptBlock:function(t,e,r,i,n,o,s,c){for(var a=this._nRounds,h=t[e]^r[0],l=t[e+1]^r[1],f=t[e+2]^r[2],d=t[e+3]^r[3],u=4,p=1;p>>24]^n[l>>>16&255]^o[f>>>8&255]^s[255&d]^r[u++],y=i[l>>>24]^n[f>>>16&255]^o[d>>>8&255]^s[255&h]^r[u++],v=i[f>>>24]^n[d>>>16&255]^o[h>>>8&255]^s[255&l]^r[u++],g=i[d>>>24]^n[h>>>16&255]^o[l>>>8&255]^s[255&f]^r[u++],h=_,l=y,f=v,d=g;_=(c[h>>>24]<<24|c[l>>>16&255]<<16|c[f>>>8&255]<<8|c[255&d])^r[u++],y=(c[l>>>24]<<24|c[f>>>16&255]<<16|c[d>>>8&255]<<8|c[255&h])^r[u++],v=(c[f>>>24]<<24|c[d>>>16&255]<<16|c[h>>>8&255]<<8|c[255&l])^r[u++],g=(c[d>>>24]<<24|c[h>>>16&255]<<16|c[l>>>8&255]<<8|c[255&f])^r[u++];t[e]=_,t[e+1]=y,t[e+2]=v,t[e+3]=g},keySize:8});t.AES=e._createHelper(r)}(),function(){var t=U,e=t.lib,i=e.WordArray,r=e.BlockCipher,e=t.algo,h=[57,49,41,33,25,17,9,1,58,50,42,34,26,18,10,2,59,51,43,35,27,19,11,3,60,52,44,36,63,55,47,39,31,23,15,7,62,54,46,38,30,22,14,6,61,53,45,37,29,21,13,5,28,20,12,4],l=[14,17,11,24,1,5,3,28,15,6,21,10,23,19,12,4,26,8,16,7,27,20,13,2,41,52,31,37,47,55,30,40,51,45,33,48,44,49,39,56,34,53,46,42,50,36,29,32],f=[1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28],d=[{0:8421888,268435456:32768,536870912:8421378,805306368:2,1073741824:512,1342177280:8421890,1610612736:8389122,1879048192:8388608,2147483648:514,2415919104:8389120,2684354560:33280,2952790016:8421376,3221225472:32770,3489660928:8388610,3758096384:0,4026531840:33282,134217728:0,402653184:8421890,671088640:33282,939524096:32768,1207959552:8421888,1476395008:512,1744830464:8421378,2013265920:2,2281701376:8389120,2550136832:33280,2818572288:8421376,3087007744:8389122,3355443200:8388610,3623878656:32770,3892314112:514,4160749568:8388608,1:32768,268435457:2,536870913:8421888,805306369:8388608,1073741825:8421378,1342177281:33280,1610612737:512,1879048193:8389122,2147483649:8421890,2415919105:8421376,2684354561:8388610,2952790017:33282,3221225473:514,3489660929:8389120,3758096385:32770,4026531841:0,134217729:8421890,402653185:8421376,671088641:8388608,939524097:512,1207959553:32768,1476395009:8388610,1744830465:2,2013265921:33282,2281701377:32770,2550136833:8389122,2818572289:514,3087007745:8421888,3355443201:8389120,3623878657:0,3892314113:33280,4160749569:8421378},{0:1074282512,16777216:16384,33554432:524288,50331648:1074266128,67108864:1073741840,83886080:1074282496,100663296:1073758208,117440512:16,134217728:540672,150994944:1073758224,167772160:1073741824,184549376:540688,201326592:524304,218103808:0,234881024:16400,251658240:1074266112,8388608:1073758208,25165824:540688,41943040:16,58720256:1073758224,75497472:1074282512,92274688:1073741824,109051904:524288,125829120:1074266128,142606336:524304,159383552:0,176160768:16384,192937984:1074266112,209715200:1073741840,226492416:540672,243269632:1074282496,260046848:16400,268435456:0,285212672:1074266128,301989888:1073758224,318767104:1074282496,335544320:1074266112,352321536:16,369098752:540688,385875968:16384,402653184:16400,419430400:524288,436207616:524304,452984832:1073741840,469762048:540672,486539264:1073758208,503316480:1073741824,520093696:1074282512,276824064:540688,293601280:524288,310378496:1074266112,327155712:16384,343932928:1073758208,360710144:1074282512,377487360:16,394264576:1073741824,411041792:1074282496,427819008:1073741840,444596224:1073758224,461373440:524304,478150656:0,494927872:16400,511705088:1074266128,528482304:540672},{0:260,1048576:0,2097152:67109120,3145728:65796,4194304:65540,5242880:67108868,6291456:67174660,7340032:67174400,8388608:67108864,9437184:67174656,10485760:65792,11534336:67174404,12582912:67109124,13631488:65536,14680064:4,15728640:256,524288:67174656,1572864:67174404,2621440:0,3670016:67109120,4718592:67108868,5767168:65536,6815744:65540,7864320:260,8912896:4,9961472:256,11010048:67174400,12058624:65796,13107200:65792,14155776:67109124,15204352:67174660,16252928:67108864,16777216:67174656,17825792:65540,18874368:65536,19922944:67109120,20971520:256,22020096:67174660,23068672:67108868,24117248:0,25165824:67109124,26214400:67108864,27262976:4,28311552:65792,29360128:67174400,30408704:260,31457280:65796,32505856:67174404,17301504:67108864,18350080:260,19398656:67174656,20447232:0,21495808:65540,22544384:67109120,23592960:256,24641536:67174404,25690112:65536,26738688:67174660,27787264:65796,28835840:67108868,29884416:67109124,30932992:67174400,31981568:4,33030144:65792},{0:2151682048,65536:2147487808,131072:4198464,196608:2151677952,262144:0,327680:4198400,393216:2147483712,458752:4194368,524288:2147483648,589824:4194304,655360:64,720896:2147487744,786432:2151678016,851968:4160,917504:4096,983040:2151682112,32768:2147487808,98304:64,163840:2151678016,229376:2147487744,294912:4198400,360448:2151682112,425984:0,491520:2151677952,557056:4096,622592:2151682048,688128:4194304,753664:4160,819200:2147483648,884736:4194368,950272:4198464,1015808:2147483712,1048576:4194368,1114112:4198400,1179648:2147483712,1245184:0,1310720:4160,1376256:2151678016,1441792:2151682048,1507328:2147487808,1572864:2151682112,1638400:2147483648,1703936:2151677952,1769472:4198464,1835008:2147487744,1900544:4194304,1966080:64,2031616:4096,1081344:2151677952,1146880:2151682112,1212416:0,1277952:4198400,1343488:4194368,1409024:2147483648,1474560:2147487808,1540096:64,1605632:2147483712,1671168:4096,1736704:2147487744,1802240:2151678016,1867776:4160,1933312:2151682048,1998848:4194304,2064384:4198464},{0:128,4096:17039360,8192:262144,12288:536870912,16384:537133184,20480:16777344,24576:553648256,28672:262272,32768:16777216,36864:537133056,40960:536871040,45056:553910400,49152:553910272,53248:0,57344:17039488,61440:553648128,2048:17039488,6144:553648256,10240:128,14336:17039360,18432:262144,22528:537133184,26624:553910272,30720:536870912,34816:537133056,38912:0,43008:553910400,47104:16777344,51200:536871040,55296:553648128,59392:16777216,63488:262272,65536:262144,69632:128,73728:536870912,77824:553648256,81920:16777344,86016:553910272,90112:537133184,94208:16777216,98304:553910400,102400:553648128,106496:17039360,110592:537133056,114688:262272,118784:536871040,122880:0,126976:17039488,67584:553648256,71680:16777216,75776:17039360,79872:537133184,83968:536870912,88064:17039488,92160:128,96256:553910272,100352:262272,104448:553910400,108544:0,112640:553648128,116736:16777344,120832:262144,124928:537133056,129024:536871040},{0:268435464,256:8192,512:270532608,768:270540808,1024:268443648,1280:2097152,1536:2097160,1792:268435456,2048:0,2304:268443656,2560:2105344,2816:8,3072:270532616,3328:2105352,3584:8200,3840:270540800,128:270532608,384:270540808,640:8,896:2097152,1152:2105352,1408:268435464,1664:268443648,1920:8200,2176:2097160,2432:8192,2688:268443656,2944:270532616,3200:0,3456:270540800,3712:2105344,3968:268435456,4096:268443648,4352:270532616,4608:270540808,4864:8200,5120:2097152,5376:268435456,5632:268435464,5888:2105344,6144:2105352,6400:0,6656:8,6912:270532608,7168:8192,7424:268443656,7680:270540800,7936:2097160,4224:8,4480:2105344,4736:2097152,4992:268435464,5248:268443648,5504:8200,5760:270540808,6016:270532608,6272:270540800,6528:270532616,6784:8192,7040:2105352,7296:2097160,7552:0,7808:268435456,8064:268443656},{0:1048576,16:33555457,32:1024,48:1049601,64:34604033,80:0,96:1,112:34603009,128:33555456,144:1048577,160:33554433,176:34604032,192:34603008,208:1025,224:1049600,240:33554432,8:34603009,24:0,40:33555457,56:34604032,72:1048576,88:33554433,104:33554432,120:1025,136:1049601,152:33555456,168:34603008,184:1048577,200:1024,216:34604033,232:1,248:1049600,256:33554432,272:1048576,288:33555457,304:34603009,320:1048577,336:33555456,352:34604032,368:1049601,384:1025,400:34604033,416:1049600,432:1,448:0,464:34603008,480:33554433,496:1024,264:1049600,280:33555457,296:34603009,312:1,328:33554432,344:1048576,360:1025,376:34604032,392:33554433,408:34603008,424:0,440:34604033,456:1049601,472:1024,488:33555456,504:1048577},{0:134219808,1:131072,2:134217728,3:32,4:131104,5:134350880,6:134350848,7:2048,8:134348800,9:134219776,10:133120,11:134348832,12:2080,13:0,14:134217760,15:133152,2147483648:2048,2147483649:134350880,2147483650:134219808,2147483651:134217728,2147483652:134348800,2147483653:133120,2147483654:133152,2147483655:32,2147483656:134217760,2147483657:2080,2147483658:131104,2147483659:134350848,2147483660:0,2147483661:134348832,2147483662:134219776,2147483663:131072,16:133152,17:134350848,18:32,19:2048,20:134219776,21:134217760,22:134348832,23:131072,24:0,25:131104,26:134348800,27:134219808,28:134350880,29:133120,30:2080,31:134217728,2147483664:131072,2147483665:2048,2147483666:134348832,2147483667:133152,2147483668:32,2147483669:134348800,2147483670:134217728,2147483671:134219808,2147483672:134350880,2147483673:134217760,2147483674:134219776,2147483675:0,2147483676:133120,2147483677:2080,2147483678:131104,2147483679:134350848}],u=[4160749569,528482304,33030144,2064384,129024,8064,504,2147483679],n=e.DES=r.extend({_doReset:function(){for(var t=this._key.words,e=[],r=0;r<56;r++){var i=h[r]-1;e[r]=t[i>>>5]>>>31-i%32&1}for(var n=this._subKeys=[],o=0;o<16;o++){for(var s=n[o]=[],c=f[o],r=0;r<24;r++)s[r/6|0]|=e[(l[r]-1+c)%28]<<31-r%6,s[4+(r/6|0)]|=e[28+(l[r+24]-1+c)%28]<<31-r%6;s[0]=s[0]<<1|s[0]>>>31;for(r=1;r<7;r++)s[r]=s[r]>>>4*(r-1)+3;s[7]=s[7]<<5|s[7]>>>27}for(var a=this._invSubKeys=[],r=0;r<16;r++)a[r]=n[15-r]},encryptBlock:function(t,e){this._doCryptBlock(t,e,this._subKeys)},decryptBlock:function(t,e){this._doCryptBlock(t,e,this._invSubKeys)},_doCryptBlock:function(t,e,r){this._lBlock=t[e],this._rBlock=t[e+1],p.call(this,4,252645135),p.call(this,16,65535),_.call(this,2,858993459),_.call(this,8,16711935),p.call(this,1,1431655765);for(var i=0;i<16;i++){for(var n=r[i],o=this._lBlock,s=this._rBlock,c=0,a=0;a<8;a++)c|=d[a][((s^n[a])&u[a])>>>0];this._lBlock=s,this._rBlock=o^c}var h=this._lBlock;this._lBlock=this._rBlock,this._rBlock=h,p.call(this,1,1431655765),_.call(this,8,16711935),_.call(this,2,858993459),p.call(this,16,65535),p.call(this,4,252645135),t[e]=this._lBlock,t[e+1]=this._rBlock},keySize:2,ivSize:2,blockSize:2});function p(t,e){e=(this._lBlock>>>t^this._rBlock)&e;this._rBlock^=e,this._lBlock^=e<>>t^this._lBlock)&e;this._lBlock^=e,this._rBlock^=e<192.");var e=t.slice(0,2),r=t.length<4?t.slice(0,2):t.slice(2,4),t=t.length<6?t.slice(0,2):t.slice(4,6);this._des1=n.createEncryptor(i.create(e)),this._des2=n.createEncryptor(i.create(r)),this._des3=n.createEncryptor(i.create(t))},encryptBlock:function(t,e){this._des1.encryptBlock(t,e),this._des2.decryptBlock(t,e),this._des3.encryptBlock(t,e)},decryptBlock:function(t,e){this._des3.decryptBlock(t,e),this._des2.encryptBlock(t,e),this._des1.decryptBlock(t,e)},keySize:6,ivSize:2,blockSize:2});t.TripleDES=r._createHelper(e)}(),function(){var t=U,e=t.lib.StreamCipher,r=t.algo,i=r.RC4=e.extend({_doReset:function(){for(var t=this._key,e=t.words,r=t.sigBytes,i=this._S=[],n=0;n<256;n++)i[n]=n;for(var n=0,o=0;n<256;n++){var s=n%r,s=e[s>>>2]>>>24-s%4*8&255,o=(o+i[n]+s)%256,s=i[n];i[n]=i[o],i[o]=s}this._i=this._j=0},_doProcessBlock:function(t,e){t[e]^=n.call(this)},keySize:8,ivSize:0});function n(){for(var t=this._S,e=this._i,r=this._j,i=0,n=0;n<4;n++){var r=(r+t[e=(e+1)%256])%256,o=t[e];t[e]=t[r],t[r]=o,i|=t[(t[e]+t[r])%256]<<24-8*n}return this._i=e,this._j=r,i}t.RC4=e._createHelper(i);r=r.RC4Drop=i.extend({cfg:i.cfg.extend({drop:192}),_doReset:function(){i._doReset.call(this);for(var t=this.cfg.drop;0>>24)|4278255360&(t[r]<<24|t[r]>>>8);for(var i=this._X=[t[0],t[3]<<16|t[2]>>>16,t[1],t[0]<<16|t[3]>>>16,t[2],t[1]<<16|t[0]>>>16,t[3],t[2]<<16|t[1]>>>16],n=this._C=[t[2]<<16|t[2]>>>16,4294901760&t[0]|65535&t[1],t[3]<<16|t[3]>>>16,4294901760&t[1]|65535&t[2],t[0]<<16|t[0]>>>16,4294901760&t[2]|65535&t[3],t[1]<<16|t[1]>>>16,4294901760&t[3]|65535&t[0]],r=this._b=0;r<4;r++)N.call(this);for(r=0;r<8;r++)n[r]^=i[r+4&7];if(e){var o=e.words,s=o[0],c=o[1],e=16711935&(s<<8|s>>>24)|4278255360&(s<<24|s>>>8),o=16711935&(c<<8|c>>>24)|4278255360&(c<<24|c>>>8),s=e>>>16|4294901760&o,c=o<<16|65535&e;n[0]^=e,n[1]^=s,n[2]^=o,n[3]^=c,n[4]^=e,n[5]^=s,n[6]^=o,n[7]^=c;for(r=0;r<4;r++)N.call(this)}},_doProcessBlock:function(t,e){var r=this._X;N.call(this),D[0]=r[0]^r[5]>>>16^r[3]<<16,D[1]=r[2]^r[7]>>>16^r[5]<<16,D[2]=r[4]^r[1]>>>16^r[7]<<16,D[3]=r[6]^r[3]>>>16^r[1]<<16;for(var i=0;i<4;i++)D[i]=16711935&(D[i]<<8|D[i]>>>24)|4278255360&(D[i]<<24|D[i]>>>8),t[e+i]^=D[i]},blockSize:4,ivSize:2}),M.Rabbit=F._createHelper(P),F=(M=U).lib.StreamCipher,P=M.algo,W=[],O=[],I=[],P=P.RabbitLegacy=F.extend({_doReset:function(){for(var t=this._key.words,e=this.cfg.iv,r=this._X=[t[0],t[3]<<16|t[2]>>>16,t[1],t[0]<<16|t[3]>>>16,t[2],t[1]<<16|t[0]>>>16,t[3],t[2]<<16|t[1]>>>16],i=this._C=[t[2]<<16|t[2]>>>16,4294901760&t[0]|65535&t[1],t[3]<<16|t[3]>>>16,4294901760&t[1]|65535&t[2],t[0]<<16|t[0]>>>16,4294901760&t[2]|65535&t[3],t[1]<<16|t[1]>>>16,4294901760&t[3]|65535&t[0]],n=this._b=0;n<4;n++)q.call(this);for(n=0;n<8;n++)i[n]^=r[n+4&7];if(e){var o=e.words,s=o[0],t=o[1],e=16711935&(s<<8|s>>>24)|4278255360&(s<<24|s>>>8),o=16711935&(t<<8|t>>>24)|4278255360&(t<<24|t>>>8),s=e>>>16|4294901760&o,t=o<<16|65535&e;i[0]^=e,i[1]^=s,i[2]^=o,i[3]^=t,i[4]^=e,i[5]^=s,i[6]^=o,i[7]^=t;for(n=0;n<4;n++)q.call(this)}},_doProcessBlock:function(t,e){var r=this._X;q.call(this),W[0]=r[0]^r[5]>>>16^r[3]<<16,W[1]=r[2]^r[7]>>>16^r[5]<<16,W[2]=r[4]^r[1]>>>16^r[7]<<16,W[3]=r[6]^r[3]>>>16^r[1]<<16;for(var i=0;i<4;i++)W[i]=16711935&(W[i]<<8|W[i]>>>24)|4278255360&(W[i]<<24|W[i]>>>8),t[e+i]^=W[i]},blockSize:4,ivSize:2}),M.RabbitLegacy=F._createHelper(P),U});
\ No newline at end of file
diff --git a/JS-hook/public/libs/jquery-3.6.0.min.js b/JS-hook/public/libs/jquery-3.6.0.min.js
new file mode 100644
index 0000000..200b54e
--- /dev/null
+++ b/JS-hook/public/libs/jquery-3.6.0.min.js
@@ -0,0 +1,2 @@
+/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */
+!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,""],col:[2,""],tr:[2,""],td:[3,""],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 02],r=(3&f)<<4,u=1;break;case 1:s[o++]=h[r|f>>4],r=(15&f)<<2,u=2;break;case 2:s[o++]=h[r|f>>6],s[o++]=h[63&f],u=0}8191>4,r=u,s=2;break;case 2:i[n++]=(15&r)<<4|(60&u)>>2,r=u,s=3;break;case 3:i[n++]=(3&r)<<6|u,s=0}}if(1===s)throw Error(a);return n-e},n.test=function(t){return/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(t)}},{}],3:[function(t,i,n){function c(i,n){"string"==typeof i&&(n=i,i=nt);var f=[];function h(t){if("string"!=typeof t){var i=a();if(c.verbose&&console.log("codegen: "+i),i="return "+i,t){for(var n=Object.keys(t),r=Array(n.length+1),e=Array(n.length),s=0;s>>0:i<11754943508222875e-54?(e<<31|Math.round(i/1401298464324817e-60))>>>0:(e<<31|127+(t=Math.floor(Math.log(i)/Math.LN2))<<23|8388607&Math.round(i*Math.pow(2,-t)*8388608))>>>0,n,r)}function n(t,i,n){t=t(i,n),i=2*(t>>31)+1,n=t>>>23&255,t&=8388607;return 255==n?t?NaN:1/0*i:0==n?1401298464324817e-60*i*t:i*Math.pow(2,n-150)*(8388608+t)}function r(t,i,n){u[0]=t,i[n]=f[0],i[n+1]=f[1],i[n+2]=f[2],i[n+3]=f[3]}function e(t,i,n){u[0]=t,i[n]=f[3],i[n+1]=f[2],i[n+2]=f[1],i[n+3]=f[0]}function s(t,i){return f[0]=t[i],f[1]=t[i+1],f[2]=t[i+2],f[3]=t[i+3],u[0]}function o(t,i){return f[3]=t[i],f[2]=t[i+1],f[1]=t[i+2],f[0]=t[i+3],u[0]}var u,f,h,a,c;function l(t,i,n,r,e,s){var o,u=r<0?1:0;0===(r=u?-r:r)?(t(0,e,s+i),t(0<1/r?0:2147483648,e,s+n)):isNaN(r)?(t(0,e,s+i),t(2146959360,e,s+n)):17976931348623157e292>>0,e,s+n)):r<22250738585072014e-324?(t((o=r/5e-324)>>>0,e,s+i),t((u<<31|o/4294967296)>>>0,e,s+n)):(t(4503599627370496*(o=r*Math.pow(2,-(r=1024===(r=Math.floor(Math.log(r)/Math.LN2))?1023:r)))>>>0,e,s+i),t((u<<31|r+1023<<20|1048576*o&1048575)>>>0,e,s+n))}function d(t,i,n,r,e){i=t(r,e+i),t=t(r,e+n),r=2*(t>>31)+1,e=t>>>20&2047,n=4294967296*(1048575&t)+i;return 2047==e?n?NaN:1/0*r:0==e?5e-324*r*n:r*Math.pow(2,e-1075)*(n+4503599627370496)}function p(t,i,n){h[0]=t,i[n]=a[0],i[n+1]=a[1],i[n+2]=a[2],i[n+3]=a[3],i[n+4]=a[4],i[n+5]=a[5],i[n+6]=a[6],i[n+7]=a[7]}function v(t,i,n){h[0]=t,i[n]=a[7],i[n+1]=a[6],i[n+2]=a[5],i[n+3]=a[4],i[n+4]=a[3],i[n+5]=a[2],i[n+6]=a[1],i[n+7]=a[0]}function b(t,i){return a[0]=t[i],a[1]=t[i+1],a[2]=t[i+2],a[3]=t[i+3],a[4]=t[i+4],a[5]=t[i+5],a[6]=t[i+6],a[7]=t[i+7],h[0]}function y(t,i){return a[7]=t[i],a[6]=t[i+1],a[5]=t[i+2],a[4]=t[i+3],a[3]=t[i+4],a[2]=t[i+5],a[1]=t[i+6],a[0]=t[i+7],h[0]}return"undefined"!=typeof Float32Array?(u=new Float32Array([-0]),f=new Uint8Array(u.buffer),c=128===f[3],t.writeFloatLE=c?r:e,t.writeFloatBE=c?e:r,t.readFloatLE=c?s:o,t.readFloatBE=c?o:s):(t.writeFloatLE=i.bind(null,w),t.writeFloatBE=i.bind(null,m),t.readFloatLE=n.bind(null,g),t.readFloatBE=n.bind(null,j)),"undefined"!=typeof Float64Array?(h=new Float64Array([-0]),a=new Uint8Array(h.buffer),c=128===a[7],t.writeDoubleLE=c?p:v,t.writeDoubleBE=c?v:p,t.readDoubleLE=c?b:y,t.readDoubleBE=c?y:b):(t.writeDoubleLE=l.bind(null,w,0,4),t.writeDoubleBE=l.bind(null,m,4,0),t.readDoubleLE=d.bind(null,g,0,4),t.readDoubleBE=d.bind(null,j,4,0)),t}function w(t,i,n){i[n]=255&t,i[n+1]=t>>>8&255,i[n+2]=t>>>16&255,i[n+3]=t>>>24}function m(t,i,n){i[n]=t>>>24,i[n+1]=t>>>16&255,i[n+2]=t>>>8&255,i[n+3]=255&t}function g(t,i){return(t[i]|t[i+1]<<8|t[i+2]<<16|t[i+3]<<24)>>>0}function j(t,i){return(t[i]<<24|t[i+1]<<16|t[i+2]<<8|t[i+3])>>>0}i.exports=r(r)},{}],7:[function(t,i,n){function r(t){try{var i=eval("require")(t);if(i&&(i.length||Object.keys(i).length))return i}catch(t){}return null}i.exports=r},{}],8:[function(t,i,n){var e=n.isAbsolute=function(t){return/^(?:\/|\w+:)/.test(t)},r=n.normalize=function(t){var i=(t=t.replace(/\\/g,"/").replace(/\/{2,}/g,"/")).split("/"),n=e(t),t="";n&&(t=i.shift()+"/");for(var r=0;r>>1,s=null,o=r;return function(t){if(t<1||e>10),s[o++]=56320+(1023&r)):s[o++]=(15&r)<<12|(63&t[i++])<<6|63&t[i++],8191>6|192:(55296==(64512&r)&&56320==(64512&(e=t.charCodeAt(o+1)))?(++o,i[n++]=(r=65536+((1023&r)<<10)+(1023&e))>>18|240,i[n++]=r>>12&63|128):i[n++]=r>>12|224,i[n++]=r>>6&63|128),i[n++]=63&r|128);return n-s}},{}],11:[function(t,i,n){i.exports=e;var r=/\/|\./;function e(t,i){r.test(t)||(t="google/protobuf/"+t+".proto",i={nested:{google:{nested:{protobuf:{nested:i}}}}}),e[t]=i}e("any",{Any:{fields:{type_url:{type:"string",id:1},value:{type:"bytes",id:2}}}}),e("duration",{Duration:i={fields:{seconds:{type:"int64",id:1},nanos:{type:"int32",id:2}}}}),e("timestamp",{Timestamp:i}),e("empty",{Empty:{fields:{}}}),e("struct",{Struct:{fields:{fields:{keyType:"string",type:"Value",id:1}}},Value:{oneofs:{kind:{oneof:["nullValue","numberValue","stringValue","boolValue","structValue","listValue"]}},fields:{nullValue:{type:"NullValue",id:1},numberValue:{type:"double",id:2},stringValue:{type:"string",id:3},boolValue:{type:"bool",id:4},structValue:{type:"Struct",id:5},listValue:{type:"ListValue",id:6}}},NullValue:{values:{NULL_VALUE:0}},ListValue:{fields:{values:{rule:"repeated",type:"Value",id:1}}}}),e("wrappers",{DoubleValue:{fields:{value:{type:"double",id:1}}},FloatValue:{fields:{value:{type:"float",id:1}}},Int64Value:{fields:{value:{type:"int64",id:1}}},UInt64Value:{fields:{value:{type:"uint64",id:1}}},Int32Value:{fields:{value:{type:"int32",id:1}}},UInt32Value:{fields:{value:{type:"uint32",id:1}}},BoolValue:{fields:{value:{type:"bool",id:1}}},StringValue:{fields:{value:{type:"string",id:1}}},BytesValue:{fields:{value:{type:"bytes",id:1}}}}),e("field_mask",{FieldMask:{fields:{paths:{rule:"repeated",type:"string",id:1}}}}),e.get=function(t){return e[t]||null}},{}]},{},[19])}();
diff --git a/JS-hook/public/proto/api.proto b/JS-hook/public/proto/api.proto
new file mode 100644
index 0000000..032a5e6
--- /dev/null
+++ b/JS-hook/public/proto/api.proto
@@ -0,0 +1,70 @@
+syntax = "proto3";
+
+package api;
+
+// 用户信息消息
+message UserInfo {
+ string name = 1;
+ string email = 2;
+ int32 age = 3;
+ string phone = 4;
+ string address = 5;
+ string company = 6;
+ string position = 7;
+ int64 salary = 8;
+ repeated string skills = 9;
+ map metadata = 10;
+}
+
+// 产品信息消息
+message ProductInfo {
+ string name = 1;
+ string description = 2;
+ double price = 3;
+ string category = 4;
+ string brand = 5;
+ int32 stock = 6;
+ repeated string tags = 7;
+ map attributes = 8;
+}
+
+// 订单信息消息
+message OrderInfo {
+ string order_id = 1;
+ string customer_name = 2;
+ string customer_email = 3;
+ repeated ProductInfo products = 4;
+ double total_amount = 5;
+ string status = 6;
+ int64 created_at = 7;
+ string shipping_address = 8;
+ string payment_method = 9;
+}
+
+// 通用请求消息
+message ApiRequest {
+ string request_id = 1;
+ int64 timestamp = 2;
+ string operation = 3;
+
+ oneof data {
+ UserInfo user_info = 10;
+ ProductInfo product_info = 11;
+ OrderInfo order_info = 12;
+ }
+}
+
+// 通用响应消息
+message ApiResponse {
+ string request_id = 1;
+ int64 timestamp = 2;
+ bool success = 3;
+ string message = 4;
+ int32 code = 5;
+
+ oneof data {
+ UserInfo user_info = 10;
+ ProductInfo product_info = 11;
+ OrderInfo order_info = 12;
+ }
+}
diff --git a/JS-hook/public/protobuf-request.html b/JS-hook/public/protobuf-request.html
new file mode 100644
index 0000000..30bc0c4
--- /dev/null
+++ b/JS-hook/public/protobuf-request.html
@@ -0,0 +1,965 @@
+
+
+
+
+
+ Protocol Buffers Request
+
+
+
+
+
+
+
+
+
+
🔧 选择API操作
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/JS-hook/public/protobuf-response.html b/JS-hook/public/protobuf-response.html
new file mode 100644
index 0000000..3950cc0
--- /dev/null
+++ b/JS-hook/public/protobuf-response.html
@@ -0,0 +1,778 @@
+
+
+
+
+
+ Protocol Buffers Response
+
+
+
+
+
+
+
+
+
+
📊 选择数据类型
+
+
+
+
📈
+
业务分析
+
获取业务指标、销售数据、用户行为等分析报告
+
+
+
📋
+
系统报告
+
查看系统性能、错误日志、监控数据等技术报告
+
+
+
📊
+
统计数据
+
获取用户统计、访问量、转化率等关键数据指标
+
+
+
🔍
+
深度洞察
+
AI驱动的数据洞察、趋势预测、智能建议等
+
+
+
+
+
+
📈 业务分析选项
+
+
销售数据
+
收入分析
+
客户分析
+
产品分析
+
+
+
+
+
+
📋 系统报告选项
+
+
性能报告
+
错误日志
+
安全报告
+
使用情况
+
+
+
+
+
+
📊 统计数据选项
+
+
流量统计
+
转化统计
+
用户参与
+
留存分析
+
+
+
+
+
+
🔍 深度洞察选项
+
+
趋势预测
+
智能推荐
+
异常检测
+
预测分析
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/JS-hook/public/query-string-param-encrypt.html b/JS-hook/public/query-string-param-encrypt.html
new file mode 100644
index 0000000..949482b
--- /dev/null
+++ b/JS-hook/public/query-string-param-encrypt.html
@@ -0,0 +1,206 @@
+
+
+
+
+
+ Query String Parameter Encryption
+
+
+
+
+
+ Query String Parameter Encryption Case
+ 这个案例演示如何对URL查询参数进行加密。用户输入查询条件,系统会加密这些参数并发送请求。
+
+
+
+
+
+
diff --git a/JS-hook/public/query-string-param-sign.html b/JS-hook/public/query-string-param-sign.html
new file mode 100644
index 0000000..7f9d2ff
--- /dev/null
+++ b/JS-hook/public/query-string-param-sign.html
@@ -0,0 +1,97 @@
+
+
+
+
+
+ 列表页面
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/JS-hook/public/response-field-decrypt.html b/JS-hook/public/response-field-decrypt.html
new file mode 100644
index 0000000..458d1b2
--- /dev/null
+++ b/JS-hook/public/response-field-decrypt.html
@@ -0,0 +1,394 @@
+
+
+
+
+
+ Response Field Decryption
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/JS-hook/public/response-header-cookie.html b/JS-hook/public/response-header-cookie.html
new file mode 100644
index 0000000..e96c33d
--- /dev/null
+++ b/JS-hook/public/response-header-cookie.html
@@ -0,0 +1,946 @@
+
+
+
+
+
+ Response Header Cookie
+
+
+
+
+
+
+
+
+
+
🔐 选择认证服务
+
+
+
+
🔑
+
用户登录
+
用户身份验证,返回加密的会话Cookie和认证令牌
+
+
+
🌐
+
OAuth授权
+
第三方OAuth认证,处理授权码和访问令牌
+
+
+
🎫
+
单点登录
+
企业SSO认证,统一身份管理和权限控制
+
+
+
🔄
+
令牌刷新
+
刷新访问令牌,延长会话有效期和权限更新
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/JS-hook/public/single-field-encrypt.html b/JS-hook/public/single-field-encrypt.html
new file mode 100644
index 0000000..96b4f2d
--- /dev/null
+++ b/JS-hook/public/single-field-encrypt.html
@@ -0,0 +1,410 @@
+
+
+
+
+
+ Single Field Encryption
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
欢迎来到加密聊天室!所有消息内容都会被加密传输。
+
+
+
+
+
+
+
+
+
+
diff --git a/JS-hook/public/video-segment-encryption.html b/JS-hook/public/video-segment-encryption.html
new file mode 100644
index 0000000..0f00d51
--- /dev/null
+++ b/JS-hook/public/video-segment-encryption.html
@@ -0,0 +1,863 @@
+
+
+
+
+
+ Video Segment Encryption
+
+
+
+
+
+
+
+
+
+
🎬 视频内容库
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 总片段数:
+ 0
+
+
+ 已加载:
+ 0
+
+
+ 已解密:
+ 0
+
+
+ 解密进度:
+ 0%
+
+
+
+
+
+
🎞️ 视频内容选择
+
+
+
🎬
+
动作电影
+
高清动作大片,包含多个加密片段
+
时长: 120分钟 | 分辨率: 1080p | 片段: 240个
+
待加载
+
+
+
📺
+
电视剧集
+
热门电视剧,分集加密存储
+
时长: 45分钟 | 分辨率: 720p | 片段: 90个
+
待加载
+
+
+
🌍
+
纪录片
+
自然纪录片,4K超高清画质
+
时长: 90分钟 | 分辨率: 4K | 片段: 180个
+
待加载
+
+
+
📡
+
直播流
+
实时直播内容,动态加密
+
实时流 | 分辨率: 1080p | 动态片段
+
待加载
+
+
+
+
+
+
📋 视频片段列表
+
+ 等待选择视频内容...
+ 待选择
+
+
+
+
+
+
+
+
+
diff --git a/JS-hook/query-string-param-sign.js b/JS-hook/query-string-param-sign.js
new file mode 100644
index 0000000..34ffc37
--- /dev/null
+++ b/JS-hook/query-string-param-sign.js
@@ -0,0 +1,52 @@
+const express = require('express');
+const crypto = require('crypto');
+const bodyParser = require('body-parser');
+const app = express();
+
+app.use(bodyParser.json());
+app.use(bodyParser.urlencoded({ extended: true }));
+
+// 静态文件服务
+app.use('/api', express.static('data'));
+
+// 示例数据目录
+const dataDir = 'data';
+
+// 定义一个简单的签名验证中间件
+const validateSign = (req, res, next) => {
+ const sign = req.query.sign;
+ const secretKey = 'my-secret-key'; // 替换为你的密钥
+
+ // 生成签名的原始字符串
+ const originalString = JSON.stringify(req.query);
+
+ // 使用 HMAC-SHA256 算法生成签名
+ const expectedSign = crypto
+ .createHmac('sha256', secretKey)
+ .update(originalString)
+ .digest('hex');
+
+ // 验证签名是否匹配
+ if (sign === expectedSign) {
+ next();
+ } else {
+ res.status(403).json({ error: 'Invalid sign' });
+ }
+};
+
+// 列表接口
+app.get('/api/items', validateSign, (req, res) => {
+ // 这里可以替换为从数据库加载数据
+ const items = [
+ { id: 1, name: 'Item 1' },
+ { id: 2, name: 'Item 2' },
+ { id: 3, name: 'Item 3' },
+ ];
+ res.json({ items });
+});
+
+// 启动服务器
+const port = 3000;
+app.listen(port, () => {
+ console.log(`Server is running on http://localhost:${port}`);
+});
\ No newline at end of file
diff --git a/JS-hook/server.js b/JS-hook/server.js
new file mode 100644
index 0000000..5973dc7
--- /dev/null
+++ b/JS-hook/server.js
@@ -0,0 +1,2442 @@
+const express = require('express');
+const app = express();
+const bodyParser = require('body-parser');
+const crypto = require('crypto');
+const CryptoJS = require('crypto-js');
+const protobuf = require('protobufjs');
+const {join} = require("node:path");
+
+// 设置静态文件目录
+app.use(express.static(join(__dirname, 'public')));
+app.use(bodyParser.urlencoded({extended: true}));
+app.use(bodyParser.json());
+
+// 定义一个简单的签名验证中间件
+const validateSign = (req, res, next) => {
+ const sign = req.query.sign;
+ const secretKey = 'my-secret-key'; // 替换为你的密钥
+
+ // 生成签名的原始字符串 (使用URL路径)
+ const originalString = req.path;
+
+ // 使用 HMAC-SHA256 算法生成签名
+ const expectedSign = crypto
+ .createHmac('sha256', secretKey)
+ .update(originalString)
+ .digest('hex');
+
+ // 验证签名是否匹配
+ if (sign === expectedSign) {
+ next();
+ } else {
+ res.status(403).json({ error: 'Invalid sign', expected: expectedSign, received: sign });
+ }
+};
+
+// 列表接口
+app.get('/api/items', validateSign, (req, res) => {
+ // 这里可以替换为从数据库加载数据
+ const items = [
+ { id: 1, name: 'Item 1' },
+ { id: 2, name: 'Item 2' },
+ { id: 3, name: 'Item 3' },
+ ];
+ res.json({ items });
+});
+
+// 解密查询参数的中间件
+const decryptQueryParams = (req, res, next) => {
+ const encryptedQuery = req.query.q;
+ const secretKey = 'query-encrypt-key-2025';
+
+ if (!encryptedQuery) {
+ return res.status(400).json({ error: 'Missing encrypted query parameter' });
+ }
+
+ try {
+ // 解密参数
+ const decryptedBytes = CryptoJS.AES.decrypt(encryptedQuery, secretKey);
+ const decryptedString = decryptedBytes.toString(CryptoJS.enc.Utf8);
+ const params = JSON.parse(decryptedString);
+
+ // 将解密后的参数添加到请求对象
+ req.decryptedParams = params;
+ next();
+ } catch (error) {
+ res.status(400).json({ error: 'Invalid encrypted parameters', details: error.message });
+ }
+};
+
+// 商品搜索接口 - 使用加密的查询参数
+app.get('/api/search-products', decryptQueryParams, (req, res) => {
+ const { keyword, category, minPrice, maxPrice } = req.decryptedParams;
+
+ // 模拟商品数据
+ const allProducts = [
+ { id: 1, name: '苹果手机', price: 6999, category: 'electronics' },
+ { id: 2, name: '华为手机', price: 4999, category: 'electronics' },
+ { id: 3, name: '小米手机', price: 2999, category: 'electronics' },
+ { id: 4, name: '时尚T恤', price: 199, category: 'clothing' },
+ { id: 5, name: '牛仔裤', price: 299, category: 'clothing' },
+ { id: 6, name: 'JavaScript高级程序设计', price: 89, category: 'books' },
+ { id: 7, name: 'Vue.js实战', price: 79, category: 'books' },
+ { id: 8, name: '智能台灯', price: 299, category: 'home' },
+ { id: 9, name: '蓝牙音箱', price: 399, category: 'electronics' },
+ { id: 10, name: '运动鞋', price: 599, category: 'clothing' }
+ ];
+
+ // 根据条件过滤商品
+ let filteredProducts = allProducts.filter(product => {
+ const matchesKeyword = !keyword || product.name.includes(keyword);
+ const matchesCategory = !category || product.category === category;
+ const matchesPrice = product.price >= (minPrice || 0) && product.price <= (maxPrice || 999999);
+
+ return matchesKeyword && matchesCategory && matchesPrice;
+ });
+
+ res.json({
+ products: filteredProducts,
+ searchParams: req.decryptedParams,
+ total: filteredProducts.length
+ });
+});
+
+// 验证登录表单签名的中间件
+const validateLoginSign = (req, res, next) => {
+ const { username, password, timestamp, sign } = req.body;
+ const secretKey = 'form-encrypt-key-2025';
+
+ if (!sign) {
+ return res.status(400).json({ error: 'Missing signature' });
+ }
+
+ try {
+ // 生成期望的签名
+ const signString = `${username}${password}${timestamp}`;
+ const expectedSign = CryptoJS.HmacSHA256(signString, secretKey).toString();
+
+ if (sign !== expectedSign) {
+ return res.status(403).json({ error: 'Invalid signature' });
+ }
+
+ // 解密密码
+ const decryptedPassword = CryptoJS.AES.decrypt(password, secretKey).toString(CryptoJS.enc.Utf8);
+ req.body.decryptedPassword = decryptedPassword;
+
+ next();
+ } catch (error) {
+ res.status(400).json({ error: 'Invalid encrypted data', details: error.message });
+ }
+};
+
+// 登录接口
+app.post('/api/login', validateLoginSign, (req, res) => {
+ const { username, decryptedPassword, rememberMe } = req.body;
+
+ // 模拟用户数据库
+ const users = [
+ { id: 1, username: 'admin@example.com', password: '123456', name: '管理员' },
+ { id: 2, username: 'user@example.com', password: 'password', name: '普通用户' },
+ { id: 3, username: 'test', password: 'test123', name: '测试用户' }
+ ];
+
+ // 验证用户名和密码
+ const user = users.find(u =>
+ (u.username === username || u.username.split('@')[0] === username) &&
+ u.password === decryptedPassword
+ );
+
+ if (!user) {
+ return res.status(401).json({ error: '用户名或密码错误' });
+ }
+
+ // 生成模拟token
+ const token = CryptoJS.HmacSHA256(`${user.id}${Date.now()}`, 'token-secret').toString();
+
+ res.json({
+ success: true,
+ message: '登录成功',
+ user: {
+ id: user.id,
+ username: user.name,
+ email: user.username
+ },
+ token: token,
+ loginTime: new Date().toISOString(),
+ rememberMe: rememberMe
+ });
+});
+
+// 解密JSON字段的中间件
+const decryptJsonFields = (req, res, next) => {
+ const secretKey = 'json-field-encrypt-2025';
+ const { phone, idCard, bankCard } = req.body;
+
+ try {
+ // 解密敏感字段
+ const decryptedPhone = CryptoJS.AES.decrypt(phone, secretKey).toString(CryptoJS.enc.Utf8);
+ const decryptedIdCard = CryptoJS.AES.decrypt(idCard, secretKey).toString(CryptoJS.enc.Utf8);
+ const decryptedBankCard = CryptoJS.AES.decrypt(bankCard, secretKey).toString(CryptoJS.enc.Utf8);
+
+ // 验证解密结果
+ if (!decryptedPhone || !decryptedIdCard || !decryptedBankCard) {
+ return res.status(400).json({ error: '解密敏感字段失败' });
+ }
+
+ // 将解密后的数据添加到请求对象
+ req.body.decryptedFields = {
+ phone: decryptedPhone,
+ idCard: decryptedIdCard,
+ bankCard: decryptedBankCard
+ };
+
+ next();
+ } catch (error) {
+ res.status(400).json({ error: '解密失败', details: error.message });
+ }
+};
+
+// 用户信息提交接口
+app.post('/api/submit-user-info', decryptJsonFields, (req, res) => {
+ const { name, email, city, age, remarks, timestamp, decryptedFields } = req.body;
+
+ // 验证必填字段
+ if (!name || !email || !decryptedFields.phone || !decryptedFields.idCard) {
+ return res.status(400).json({ error: '缺少必填字段' });
+ }
+
+ // 验证手机号格式
+ const phoneRegex = /^1[3-9]\d{9}$/;
+ if (!phoneRegex.test(decryptedFields.phone)) {
+ return res.status(400).json({ error: '手机号格式不正确' });
+ }
+
+ // 验证身份证号格式(简单验证)
+ const idCardRegex = /^\d{17}[\dX]$/;
+ if (!idCardRegex.test(decryptedFields.idCard)) {
+ return res.status(400).json({ error: '身份证号格式不正确' });
+ }
+
+ // 验证银行卡号格式(简单验证)
+ const bankCardRegex = /^\d{16,19}$/;
+ if (!bankCardRegex.test(decryptedFields.bankCard)) {
+ return res.status(400).json({ error: '银行卡号格式不正确' });
+ }
+
+ // 模拟保存到数据库
+ const userId = Math.floor(Math.random() * 100000) + 10000;
+
+ // 返回成功响应
+ res.json({
+ success: true,
+ message: '用户信息提交成功',
+ userId: userId,
+ submitTime: new Date().toISOString(),
+ status: '已处理',
+ decryptedData: {
+ phone: decryptedFields.phone,
+ idCard: decryptedFields.idCard.replace(/(\d{6})\d{8}(\d{4})/, '$1********$2'), // 脱敏显示
+ bankCard: decryptedFields.bankCard.replace(/(\d{4})\d{8,11}(\d{4})/, '$1****$2') // 脱敏显示
+ },
+ userInfo: {
+ name: name,
+ email: email,
+ city: city,
+ age: age,
+ remarks: remarks
+ }
+ });
+});
+
+// 加密响应字段的函数
+const encryptResponseField = (value) => {
+ const secretKey = 'response-decrypt-2025';
+ return CryptoJS.AES.encrypt(value, secretKey).toString();
+};
+
+// 用户详细信息接口 - 返回加密字段
+app.get('/api/user-details/:userId', (req, res) => {
+ const userId = req.params.userId;
+
+ // 模拟用户数据库
+ const users = {
+ '1001': {
+ id: 1001,
+ name: '张三',
+ email: 'zhangsan@company.com',
+ department: '技术部',
+ phone: '13800138001',
+ idCard: '110101199001011001',
+ bankCard: '6222021234567890001',
+ address: '北京市朝阳区某某街道123号',
+ createdAt: '2023-01-15T08:30:00Z',
+ lastLogin: '2025-01-31T10:15:00Z',
+ status: '正常'
+ },
+ '1002': {
+ id: 1002,
+ name: '李四',
+ email: 'lisi@company.com',
+ department: '市场部',
+ phone: '13800138002',
+ idCard: '110101199002022002',
+ bankCard: '6222021234567890002',
+ address: '上海市浦东新区某某路456号',
+ createdAt: '2023-02-20T09:45:00Z',
+ lastLogin: '2025-01-31T09:30:00Z',
+ status: '正常'
+ },
+ '1003': {
+ id: 1003,
+ name: '王五',
+ email: 'wangwu@company.com',
+ department: '财务部',
+ phone: '13800138003',
+ idCard: '110101199003033003',
+ bankCard: '6222021234567890003',
+ address: '广州市天河区某某大道789号',
+ createdAt: '2023-03-10T14:20:00Z',
+ lastLogin: '2025-01-30T16:45:00Z',
+ status: '正常'
+ },
+ '1004': {
+ id: 1004,
+ name: '赵六',
+ email: 'zhaoliu@company.com',
+ department: '人事部',
+ phone: '13800138004',
+ idCard: '110101199004044004',
+ bankCard: '6222021234567890004',
+ address: '深圳市南山区某某科技园101号',
+ createdAt: '2023-04-05T11:10:00Z',
+ lastLogin: '2025-01-29T14:20:00Z',
+ status: '正常'
+ }
+ };
+
+ const user = users[userId];
+
+ if (!user) {
+ return res.status(404).json({ error: '用户不存在' });
+ }
+
+ // 构建响应,敏感字段加密
+ const response = {
+ success: true,
+ message: '获取用户信息成功',
+ data: {
+ id: user.id,
+ name: user.name,
+ email: user.email,
+ department: user.department,
+ // 敏感字段加密
+ encryptedPhone: encryptResponseField(user.phone),
+ encryptedIdCard: encryptResponseField(user.idCard),
+ encryptedBankCard: encryptResponseField(user.bankCard),
+ encryptedAddress: encryptResponseField(user.address),
+ // 其他字段保持明文
+ createdAt: user.createdAt,
+ lastLogin: user.lastLogin,
+ status: user.status
+ },
+ timestamp: new Date().toISOString()
+ };
+
+ res.json(response);
+});
+
+// 单字段加密消息发送接口
+app.post('/api/send-message', (req, res) => {
+ const { sender, encryptedMessage, timestamp } = req.body;
+ const secretKey = 'single-field-2025';
+
+ // 验证必填字段
+ if (!sender || !encryptedMessage) {
+ return res.status(400).json({ error: '缺少必填字段' });
+ }
+
+ try {
+ // 解密消息内容
+ const decryptedBytes = CryptoJS.AES.decrypt(encryptedMessage, secretKey);
+ const decryptedMessage = decryptedBytes.toString(CryptoJS.enc.Utf8);
+
+ if (!decryptedMessage) {
+ return res.status(400).json({ error: '消息解密失败' });
+ }
+
+ // 模拟消息处理和存储
+ const messageId = Math.random().toString(36).substring(2, 15);
+
+ // 生成服务器回复消息(也加密)
+ const replyMessages = [
+ '消息已收到,谢谢!',
+ '收到您的消息,正在处理中...',
+ '感谢您的消息,我们会尽快回复。',
+ '您的消息很重要,已记录在案。',
+ '消息接收成功,系统已自动处理。'
+ ];
+
+ const randomReply = replyMessages[Math.floor(Math.random() * replyMessages.length)];
+ const encryptedReply = CryptoJS.AES.encrypt(randomReply, secretKey).toString();
+
+ // 构建响应
+ const response = {
+ success: true,
+ message: '消息发送成功',
+ messageId: messageId,
+ sender: sender,
+ timestamp: new Date().toISOString(),
+ // 服务器回复的加密消息
+ encryptedContent: encryptedReply,
+ // 解密后的原始消息(用于验证)
+ originalMessage: decryptedMessage
+ };
+
+ res.json(response);
+
+ } catch (error) {
+ res.status(400).json({ error: '消息处理失败', details: error.message });
+ }
+});
+
+// 处理十六进制加密请求体的中间件
+const handleHexEncryptedBody = (req, res, next) => {
+ const secretKey = 'hex-body-encrypt-2025';
+
+ // 获取原始请求体(十六进制字符串)
+ let hexData = '';
+
+ req.on('data', chunk => {
+ hexData += chunk.toString();
+ });
+
+ req.on('end', () => {
+ try {
+ // 1. 从十六进制转换回加密的字符串
+ const encryptedData = CryptoJS.enc.Hex.parse(hexData).toString(CryptoJS.enc.Utf8);
+
+ // 2. 解密数据
+ const decryptedBytes = CryptoJS.AES.decrypt(encryptedData, secretKey);
+ const decryptedString = decryptedBytes.toString(CryptoJS.enc.Utf8);
+
+ if (!decryptedString) {
+ return res.status(400).json({ error: '请求体解密失败' });
+ }
+
+ // 3. 解析JSON
+ const jsonData = JSON.parse(decryptedString);
+
+ // 将解密后的数据添加到请求对象
+ req.decryptedBody = jsonData;
+ req.originalHexData = hexData;
+ req.encryptedData = encryptedData;
+
+ next();
+ } catch (error) {
+ res.status(400).json({ error: '请求体处理失败', details: error.message });
+ }
+ });
+};
+
+// 安全数据提交接口 - 处理十六进制加密的请求体
+app.post('/api/secure-submit', handleHexEncryptedBody, (req, res) => {
+ const data = req.decryptedBody;
+
+ // 验证必填字段
+ if (!data.companyName || !data.contactPerson || !data.email) {
+ return res.status(400).json({ error: '缺少必填字段' });
+ }
+
+ // 验证邮箱格式
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+ if (!emailRegex.test(data.email)) {
+ return res.status(400).json({ error: '邮箱格式不正确' });
+ }
+
+ // 验证手机号格式
+ const phoneRegex = /^1[3-9]\d{9}$/;
+ if (!phoneRegex.test(data.contactPhone)) {
+ return res.status(400).json({ error: '手机号格式不正确' });
+ }
+
+ // 验证预算范围
+ if (data.budget < 0 || data.budget > 10000000) {
+ return res.status(400).json({ error: '预算金额超出有效范围' });
+ }
+
+ // 模拟数据处理
+ const submissionId = Math.random().toString(36).substring(2, 15).toUpperCase();
+
+ // 构建响应
+ const response = {
+ success: true,
+ message: '数据提交成功',
+ submissionId: submissionId,
+ status: '已接收并处理',
+ timestamp: new Date().toISOString(),
+ securityLevel: '最高级别加密',
+ decryptedData: {
+ companyName: data.companyName,
+ contactPerson: data.contactPerson,
+ budget: data.budget,
+ urgency: data.urgency,
+ industry: data.industry
+ },
+ processingInfo: {
+ hexDataLength: req.originalHexData.length,
+ encryptedDataLength: req.encryptedData.length,
+ originalDataSize: JSON.stringify(data).length
+ }
+ };
+
+ res.json(response);
+});
+
+// 加密响应体并转换为十六进制的函数
+const encryptResponseToHex = (data) => {
+ const secretKey = 'hex-response-decrypt-2025';
+
+ // 1. 将数据转换为JSON字符串
+ const jsonString = JSON.stringify(data);
+
+ // 2. 使用AES加密
+ const encrypted = CryptoJS.AES.encrypt(jsonString, secretKey).toString();
+
+ // 3. 转换为十六进制
+ const hexEncoded = CryptoJS.enc.Utf8.parse(encrypted).toString(CryptoJS.enc.Hex);
+
+ return hexEncoded;
+};
+
+// 安全查询接口 - 返回十六进制加密的响应体
+app.get('/api/secure-query/:type', (req, res) => {
+ const queryType = req.params.type;
+
+ // 模拟不同类型的机密数据
+ const mockData = {
+ financial: {
+ type: 'financial',
+ reportType: '年度财务报表',
+ period: '2024年度',
+ revenue: 15680000,
+ profit: 3420000,
+ assets: 45600000,
+ liabilities: 12300000,
+ timestamp: new Date().toISOString(),
+ securityLevel: '机密',
+ department: '财务部',
+ approver: '财务总监'
+ },
+ employee: {
+ type: 'employee',
+ name: '李明',
+ employeeId: 'EMP001234',
+ department: '技术部',
+ position: '高级工程师',
+ salary: 25000,
+ bonus: 50000,
+ socialSecurity: '已缴纳',
+ timestamp: new Date().toISOString(),
+ securityLevel: '机密',
+ hireDate: '2020-03-15',
+ performance: 'A级'
+ },
+ customer: {
+ type: 'customer',
+ companyName: '科技创新集团有限公司',
+ customerId: 'CUST789012',
+ contactPerson: '王总经理',
+ phone: '13800138000',
+ email: 'wang@techgroup.com',
+ annualRevenue: 8900000,
+ creditRating: 'AAA',
+ timestamp: new Date().toISOString(),
+ securityLevel: '机密',
+ contractValue: 12000000,
+ paymentStatus: '正常'
+ },
+ project: {
+ type: 'project',
+ projectName: '智能数据管理系统',
+ projectId: 'PROJ456789',
+ manager: '张项目经理',
+ budget: 5600000,
+ spent: 3200000,
+ progress: 68,
+ startDate: '2024-01-15',
+ expectedEnd: '2025-06-30',
+ timestamp: new Date().toISOString(),
+ securityLevel: '机密',
+ team: '技术团队A组',
+ status: '进行中'
+ }
+ };
+
+ const data = mockData[queryType];
+
+ if (!data) {
+ return res.status(404).json({ error: '查询类型不存在' });
+ }
+
+ // 加密整个响应并转换为十六进制
+ const hexResponse = encryptResponseToHex(data);
+
+ // 设置响应头为纯文本,因为返回的是十六进制字符串
+ res.setHeader('Content-Type', 'text/plain');
+ res.send(hexResponse);
+});
+
+// 处理双向十六进制加密通信的中间件
+const handleBidirectionalHexEncryption = (req, res, next) => {
+ const secretKey = 'bidirectional-hex-2025';
+
+ // 获取原始请求体(十六进制字符串)
+ let hexData = '';
+
+ req.on('data', chunk => {
+ hexData += chunk.toString();
+ });
+
+ req.on('end', () => {
+ try {
+ // 1. 从十六进制转换回加密的字符串
+ const encryptedData = CryptoJS.enc.Hex.parse(hexData).toString(CryptoJS.enc.Utf8);
+
+ // 2. 解密数据
+ const decryptedBytes = CryptoJS.AES.decrypt(encryptedData, secretKey);
+ const decryptedString = decryptedBytes.toString(CryptoJS.enc.Utf8);
+
+ if (!decryptedString) {
+ return res.status(400).json({ error: '请求体解密失败' });
+ }
+
+ // 3. 解析JSON
+ const jsonData = JSON.parse(decryptedString);
+
+ // 将解密后的数据添加到请求对象
+ req.decryptedBody = jsonData;
+ req.originalHexData = hexData;
+ req.encryptedData = encryptedData;
+
+ // 添加响应加密函数
+ req.encryptResponse = (responseData) => {
+ const jsonString = JSON.stringify(responseData);
+ const encrypted = CryptoJS.AES.encrypt(jsonString, secretKey).toString();
+ const hexEncoded = CryptoJS.enc.Utf8.parse(encrypted).toString(CryptoJS.enc.Hex);
+ return hexEncoded;
+ };
+
+ next();
+ } catch (error) {
+ res.status(400).json({ error: '请求体处理失败', details: error.message });
+ }
+ });
+};
+
+// 安全操作接口 - 双向十六进制加密通信
+app.post('/api/secure-operation', handleBidirectionalHexEncryption, (req, res) => {
+ const data = req.decryptedBody;
+
+ // 验证必填字段
+ if (!data.operation || !data.timestamp) {
+ return res.status(400).json({ error: '缺少必填字段' });
+ }
+
+ // 生成操作ID
+ const operationId = Math.random().toString(36).substring(2, 15).toUpperCase();
+
+ // 根据操作类型生成不同的响应
+ let responseData = {
+ success: true,
+ operationId: operationId,
+ operation: data.operation,
+ status: '执行成功',
+ executionTime: new Date().toISOString(),
+ securityLevel: 'TOP_SECRET',
+ requestId: data.requestId
+ };
+
+ // 根据操作类型添加特定的响应数据
+ switch(data.operation) {
+ case 'transfer':
+ responseData.details = {
+ amount: data.amount,
+ fee: Math.round(data.amount * 0.001), // 0.1% 手续费
+ transactionId: 'TXN' + Math.random().toString(36).substring(2, 15).toUpperCase(),
+ fromAccount: data.fromAccount.replace(/(\d{4})\d{8}(\d{4})/, '$1****$2'),
+ toAccount: data.toAccount.replace(/(\d{4})\d{8}(\d{4})/, '$1****$2'),
+ currency: data.currency,
+ estimatedArrival: '2-24小时'
+ };
+ break;
+
+ case 'contract':
+ responseData.details = {
+ contractNumber: 'CON' + Math.random().toString(36).substring(2, 15).toUpperCase(),
+ signatureStatus: '已签署',
+ legalStatus: '具有法律效力',
+ digitalSignature: 'SHA256:' + Math.random().toString(36).substring(2, 15),
+ contractValue: data.value,
+ effectiveDate: new Date().toISOString().split('T')[0]
+ };
+ break;
+
+ case 'audit':
+ responseData.details = {
+ reportId: 'AUD' + Math.random().toString(36).substring(2, 15).toUpperCase(),
+ issuesFound: Math.floor(Math.random() * 5) + 1,
+ riskLevel: ['低', '中', '高'][Math.floor(Math.random() * 3)],
+ auditScore: Math.floor(Math.random() * 20) + 80,
+ recommendations: '建议加强密码策略和访问控制',
+ nextAuditDate: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]
+ };
+ break;
+
+ case 'backup':
+ responseData.details = {
+ backupId: 'BAK' + Math.random().toString(36).substring(2, 15).toUpperCase(),
+ backupSize: (Math.random() * 100 + 50).toFixed(2) + ' GB',
+ integrityCheck: '通过',
+ compressionRatio: (Math.random() * 0.3 + 0.6).toFixed(2),
+ estimatedRestoreTime: Math.floor(Math.random() * 60 + 30) + '分钟',
+ storageLocation: data.location === 'cloud' ? '云端存储' : '本地存储'
+ };
+ break;
+
+ default:
+ responseData.details = {
+ message: '操作类型未识别,但已安全处理'
+ };
+ }
+
+ // 加密响应并返回十六进制
+ const hexResponse = req.encryptResponse(responseData);
+
+ // 设置响应头为纯文本
+ res.setHeader('Content-Type', 'text/plain');
+ res.send(hexResponse);
+});
+
+// Protocol Buffers schema
+let protobufRoot = null;
+
+// 初始化protobuf schema
+const initProtobufSchema = async () => {
+ try {
+ const protoSchema = `
+ syntax = "proto3";
+ package api;
+
+ message UserInfo {
+ string name = 1;
+ string email = 2;
+ int32 age = 3;
+ string phone = 4;
+ string address = 5;
+ string company = 6;
+ string position = 7;
+ int64 salary = 8;
+ repeated string skills = 9;
+ map metadata = 10;
+ }
+
+ message ProductInfo {
+ string name = 1;
+ string description = 2;
+ double price = 3;
+ string category = 4;
+ string brand = 5;
+ int32 stock = 6;
+ repeated string tags = 7;
+ map attributes = 8;
+ }
+
+ message OrderInfo {
+ string order_id = 1;
+ string customer_name = 2;
+ string customer_email = 3;
+ repeated ProductInfo products = 4;
+ double total_amount = 5;
+ string status = 6;
+ int64 created_at = 7;
+ string shipping_address = 8;
+ string payment_method = 9;
+ }
+
+ message ApiRequest {
+ string request_id = 1;
+ int64 timestamp = 2;
+ string operation = 3;
+
+ oneof data {
+ UserInfo user_info = 10;
+ ProductInfo product_info = 11;
+ OrderInfo order_info = 12;
+ }
+ }
+
+ message ApiResponse {
+ string request_id = 1;
+ int64 timestamp = 2;
+ bool success = 3;
+ string message = 4;
+ int32 code = 5;
+
+ oneof data {
+ UserInfo user_info = 10;
+ ProductInfo product_info = 11;
+ OrderInfo order_info = 12;
+ }
+ }
+ `;
+
+ protobufRoot = protobuf.parse(protoSchema).root;
+ console.log('Protocol Buffers schema initialized successfully');
+ } catch (error) {
+ console.error('Failed to initialize protobuf schema:', error);
+ }
+};
+
+// 处理protobuf请求体的中间件
+const handleProtobufRequest = (req, res, next) => {
+ if (!protobufRoot) {
+ return res.status(500).json({ error: 'Protocol Buffers schema not initialized' });
+ }
+
+ // 获取原始请求体(二进制数据)
+ let bufferData = Buffer.alloc(0);
+
+ req.on('data', chunk => {
+ bufferData = Buffer.concat([bufferData, chunk]);
+ });
+
+ req.on('end', () => {
+ try {
+ // 解析protobuf请求
+ const ApiRequest = protobufRoot.lookupType('api.ApiRequest');
+ const message = ApiRequest.decode(bufferData);
+ const requestData = ApiRequest.toObject(message);
+
+ // 将解析后的数据添加到请求对象
+ req.protobufData = requestData;
+ req.originalBuffer = bufferData;
+
+ // 添加响应序列化函数
+ req.sendProtobufResponse = (responseData) => {
+ try {
+ const ApiResponse = protobufRoot.lookupType('api.ApiResponse');
+ const responseMessage = ApiResponse.create(responseData);
+ const responseBuffer = ApiResponse.encode(responseMessage).finish();
+
+ res.setHeader('Content-Type', 'application/x-protobuf');
+ res.send(responseBuffer);
+ } catch (error) {
+ res.status(500).json({ error: '响应序列化失败', details: error.message });
+ }
+ };
+
+ next();
+ } catch (error) {
+ res.status(400).json({ error: 'Protocol Buffers 解析失败', details: error.message });
+ }
+ });
+};
+
+// Protocol Buffers API接口
+app.post('/api/protobuf', handleProtobufRequest, (req, res) => {
+ const data = req.protobufData;
+
+ // 验证必填字段
+ if (!data.request_id || !data.operation) {
+ return res.status(400).json({ error: '缺少必填字段' });
+ }
+
+ // 构建响应数据
+ let responseData = {
+ request_id: data.request_id,
+ timestamp: Math.floor(Date.now() / 1000),
+ success: true,
+ message: 'Protocol Buffers 请求处理成功',
+ code: 200
+ };
+
+ // 根据操作类型处理数据并构建响应
+ switch(data.operation) {
+ case 'user':
+ if (data.user_info) {
+ // 模拟用户数据处理
+ responseData.user_info = {
+ ...data.user_info,
+ // 添加一些服务器端生成的数据
+ metadata: {
+ ...data.user_info.metadata,
+ 'user_id': 'USR' + Math.random().toString(36).substring(2, 15).toUpperCase(),
+ 'created_at': new Date().toISOString(),
+ 'status': 'active'
+ }
+ };
+ responseData.message = `用户 ${data.user_info.name} 信息处理成功`;
+ }
+ break;
+
+ case 'product':
+ if (data.product_info) {
+ // 模拟产品数据处理
+ responseData.product_info = {
+ ...data.product_info,
+ // 添加一些服务器端生成的数据
+ attributes: {
+ ...data.product_info.attributes,
+ 'product_id': 'PRD' + Math.random().toString(36).substring(2, 15).toUpperCase(),
+ 'created_at': new Date().toISOString(),
+ 'status': 'available'
+ }
+ };
+ responseData.message = `产品 ${data.product_info.name} 信息处理成功`;
+ }
+ break;
+
+ case 'order':
+ if (data.order_info) {
+ // 模拟订单数据处理
+ responseData.order_info = {
+ ...data.order_info,
+ // 更新订单状态
+ status: 'confirmed',
+ // 添加确认时间
+ created_at: Math.floor(Date.now() / 1000)
+ };
+ responseData.message = `订单 ${data.order_info.order_id} 处理成功`;
+ }
+ break;
+
+ default:
+ responseData.success = false;
+ responseData.message = '不支持的操作类型';
+ responseData.code = 400;
+ }
+
+ // 发送protobuf响应
+ req.sendProtobufResponse(responseData);
+});
+
+// Protocol Buffers 响应接口
+app.get('/api/protobuf-response', (req, res) => {
+ if (!protobufRoot) {
+ return res.status(500).json({ error: 'Protocol Buffers schema not initialized' });
+ }
+
+ const category = req.query.category;
+ const option = req.query.option;
+
+ if (!category || !option) {
+ return res.status(400).json({ error: '缺少必填参数: category, option' });
+ }
+
+ try {
+ // 定义响应schema
+ const responseSchema = `
+ syntax = "proto3";
+ package api;
+
+ message DataPoint {
+ string label = 1;
+ double value = 2;
+ string unit = 3;
+ int64 timestamp = 4;
+ }
+
+ message ChartData {
+ string chart_type = 1;
+ string title = 2;
+ repeated DataPoint data_points = 3;
+ map metadata = 4;
+ }
+
+ message ReportData {
+ string report_id = 1;
+ string title = 2;
+ string description = 3;
+ repeated ChartData charts = 4;
+ map summary_metrics = 5;
+ int64 generated_at = 6;
+ }
+
+ message DataResponse {
+ string request_id = 1;
+ int64 timestamp = 2;
+ bool success = 3;
+ string message = 4;
+ int32 code = 5;
+ string category = 6;
+ string option = 7;
+ ReportData report_data = 8;
+ }
+ `;
+
+ const responseRoot = protobuf.parse(responseSchema).root;
+ const DataResponse = responseRoot.lookupType('api.DataResponse');
+
+ // 生成模拟数据
+ const mockData = generateMockData(category, option);
+
+ // 创建protobuf响应
+ const responseMessage = DataResponse.create(mockData);
+ const responseBuffer = DataResponse.encode(responseMessage).finish();
+
+ // 设置响应头并发送二进制数据
+ res.setHeader('Content-Type', 'application/x-protobuf');
+ res.send(responseBuffer);
+
+ } catch (error) {
+ res.status(500).json({ error: 'Protocol Buffers 响应生成失败', details: error.message });
+ }
+});
+
+// 生成模拟数据的函数
+function generateMockData(category, option) {
+ const requestId = Math.random().toString(36).substring(2, 15);
+ const timestamp = Math.floor(Date.now() / 1000);
+
+ const baseResponse = {
+ request_id: requestId,
+ timestamp: timestamp,
+ success: true,
+ message: `${category}-${option} 数据获取成功`,
+ code: 200,
+ category: category,
+ option: option
+ };
+
+ // 根据类型生成不同的报告数据
+ const reportData = {
+ report_id: 'RPT' + Math.random().toString(36).substring(2, 15).toUpperCase(),
+ generated_at: timestamp
+ };
+
+ switch(category) {
+ case 'analytics':
+ reportData.title = getAnalyticsTitle(option);
+ reportData.description = getAnalyticsDescription(option);
+ reportData.charts = generateAnalyticsCharts(option);
+ reportData.summary_metrics = generateAnalyticsMetrics(option);
+ break;
+
+ case 'reports':
+ reportData.title = getReportsTitle(option);
+ reportData.description = getReportsDescription(option);
+ reportData.charts = generateReportsCharts(option);
+ reportData.summary_metrics = generateReportsMetrics(option);
+ break;
+
+ case 'statistics':
+ reportData.title = getStatisticsTitle(option);
+ reportData.description = getStatisticsDescription(option);
+ reportData.charts = generateStatisticsCharts(option);
+ reportData.summary_metrics = generateStatisticsMetrics(option);
+ break;
+
+ case 'insights':
+ reportData.title = getInsightsTitle(option);
+ reportData.description = getInsightsDescription(option);
+ reportData.charts = generateInsightsCharts(option);
+ reportData.summary_metrics = generateInsightsMetrics(option);
+ break;
+
+ default:
+ reportData.title = '未知数据类型';
+ reportData.description = '无法识别的数据类型';
+ reportData.charts = [];
+ reportData.summary_metrics = {};
+ }
+
+ return {
+ ...baseResponse,
+ report_data: reportData
+ };
+}
+
+// 辅助函数:生成标题
+function getAnalyticsTitle(option) {
+ const titles = {
+ sales: '销售数据分析报告',
+ revenue: '收入分析报告',
+ customers: '客户分析报告',
+ products: '产品分析报告'
+ };
+ return titles[option] || '业务分析报告';
+}
+
+function getReportsTitle(option) {
+ const titles = {
+ performance: '系统性能报告',
+ errors: '错误日志报告',
+ security: '安全审计报告',
+ usage: '系统使用情况报告'
+ };
+ return titles[option] || '系统报告';
+}
+
+function getStatisticsTitle(option) {
+ const titles = {
+ traffic: '流量统计报告',
+ conversion: '转化率统计报告',
+ engagement: '用户参与度统计',
+ retention: '用户留存分析报告'
+ };
+ return titles[option] || '统计数据报告';
+}
+
+function getInsightsTitle(option) {
+ const titles = {
+ trends: '趋势预测分析',
+ recommendations: '智能推荐报告',
+ anomalies: '异常检测报告',
+ forecasting: '预测分析报告'
+ };
+ return titles[option] || '深度洞察报告';
+}
+
+// 辅助函数:生成描述
+function getAnalyticsDescription(option) {
+ const descriptions = {
+ sales: '基于最近30天的销售数据,分析销售趋势、热门产品和销售渠道表现',
+ revenue: '分析各业务线收入贡献,识别增长机会和风险点',
+ customers: '深入分析客户行为模式、价值分布和生命周期',
+ products: '评估产品性能、市场接受度和优化建议'
+ };
+ return descriptions[option] || '业务数据深度分析';
+}
+
+function getReportsDescription(option) {
+ const descriptions = {
+ performance: '系统各组件性能指标监控,包括响应时间、吞吐量和资源使用率',
+ errors: '系统错误日志汇总分析,识别常见问题和解决方案',
+ security: '安全事件监控和威胁分析,确保系统安全性',
+ usage: '用户使用行为分析,优化用户体验和系统设计'
+ };
+ return descriptions[option] || '系统运行状况分析';
+}
+
+function getStatisticsDescription(option) {
+ const descriptions = {
+ traffic: '网站流量来源分析,包括访问量、页面浏览量和用户行为路径',
+ conversion: '转化漏斗分析,识别转化瓶颈和优化机会',
+ engagement: '用户参与度指标分析,包括停留时间、互动频率等',
+ retention: '用户留存率分析,了解用户粘性和流失原因'
+ };
+ return descriptions[option] || '数据统计分析';
+}
+
+function getInsightsDescription(option) {
+ const descriptions = {
+ trends: '基于历史数据和机器学习算法预测未来趋势',
+ recommendations: 'AI驱动的个性化推荐和业务优化建议',
+ anomalies: '智能异常检测,及时发现数据异常和潜在问题',
+ forecasting: '预测模型分析,为决策提供数据支持'
+ };
+ return descriptions[option] || 'AI驱动的深度洞察';
+}
+
+// 生成图表数据的函数
+function generateAnalyticsCharts(option) {
+ const charts = [];
+ const now = Date.now();
+
+ switch(option) {
+ case 'sales':
+ charts.push({
+ chart_type: 'line',
+ title: '销售趋势图',
+ data_points: Array.from({length: 7}, (_, i) => ({
+ label: `第${i+1}天`,
+ value: Math.random() * 10000 + 5000,
+ unit: '元',
+ timestamp: Math.floor((now - (6-i) * 24 * 60 * 60 * 1000) / 1000)
+ })),
+ metadata: { period: '最近7天', currency: 'CNY' }
+ });
+ break;
+ case 'revenue':
+ charts.push({
+ chart_type: 'bar',
+ title: '收入分布图',
+ data_points: [
+ { label: '产品A', value: 45000, unit: '元', timestamp: Math.floor(now / 1000) },
+ { label: '产品B', value: 32000, unit: '元', timestamp: Math.floor(now / 1000) },
+ { label: '产品C', value: 28000, unit: '元', timestamp: Math.floor(now / 1000) }
+ ],
+ metadata: { period: '本月', currency: 'CNY' }
+ });
+ break;
+ case 'customers':
+ charts.push({
+ chart_type: 'pie',
+ title: '客户分布图',
+ data_points: [
+ { label: '新客户', value: 35, unit: '%', timestamp: Math.floor(now / 1000) },
+ { label: '老客户', value: 45, unit: '%', timestamp: Math.floor(now / 1000) },
+ { label: '流失客户', value: 20, unit: '%', timestamp: Math.floor(now / 1000) }
+ ],
+ metadata: { total_customers: '1250' }
+ });
+ break;
+ case 'products':
+ charts.push({
+ chart_type: 'bar',
+ title: '产品销量排行',
+ data_points: [
+ { label: '智能手机', value: 1250, unit: '台', timestamp: Math.floor(now / 1000) },
+ { label: '平板电脑', value: 890, unit: '台', timestamp: Math.floor(now / 1000) },
+ { label: '智能手表', value: 650, unit: '台', timestamp: Math.floor(now / 1000) }
+ ],
+ metadata: { period: '本月' }
+ });
+ break;
+ }
+
+ return charts;
+}
+
+function generateReportsCharts(option) {
+ const charts = [];
+ const now = Date.now();
+
+ switch(option) {
+ case 'performance':
+ charts.push({
+ chart_type: 'line',
+ title: '系统响应时间',
+ data_points: Array.from({length: 24}, (_, i) => ({
+ label: `${i}:00`,
+ value: Math.random() * 200 + 100,
+ unit: 'ms',
+ timestamp: Math.floor((now - (23-i) * 60 * 60 * 1000) / 1000)
+ })),
+ metadata: { period: '最近24小时' }
+ });
+ break;
+ case 'errors':
+ charts.push({
+ chart_type: 'bar',
+ title: '错误类型分布',
+ data_points: [
+ { label: '404错误', value: 125, unit: '次', timestamp: Math.floor(now / 1000) },
+ { label: '500错误', value: 45, unit: '次', timestamp: Math.floor(now / 1000) },
+ { label: '超时错误', value: 32, unit: '次', timestamp: Math.floor(now / 1000) }
+ ],
+ metadata: { period: '今日' }
+ });
+ break;
+ case 'security':
+ charts.push({
+ chart_type: 'line',
+ title: '安全事件趋势',
+ data_points: Array.from({length: 7}, (_, i) => ({
+ label: `第${i+1}天`,
+ value: Math.floor(Math.random() * 20),
+ unit: '次',
+ timestamp: Math.floor((now - (6-i) * 24 * 60 * 60 * 1000) / 1000)
+ })),
+ metadata: { period: '最近7天' }
+ });
+ break;
+ case 'usage':
+ charts.push({
+ chart_type: 'area',
+ title: '用户活跃度',
+ data_points: Array.from({length: 12}, (_, i) => ({
+ label: `${i+1}月`,
+ value: Math.random() * 5000 + 2000,
+ unit: '人',
+ timestamp: Math.floor((now - (11-i) * 30 * 24 * 60 * 60 * 1000) / 1000)
+ })),
+ metadata: { period: '最近12个月' }
+ });
+ break;
+ }
+
+ return charts;
+}
+
+function generateStatisticsCharts(option) {
+ const charts = [];
+ const now = Date.now();
+
+ switch(option) {
+ case 'traffic':
+ charts.push({
+ chart_type: 'line',
+ title: '网站流量趋势',
+ data_points: Array.from({length: 30}, (_, i) => ({
+ label: `第${i+1}天`,
+ value: Math.random() * 10000 + 5000,
+ unit: 'PV',
+ timestamp: Math.floor((now - (29-i) * 24 * 60 * 60 * 1000) / 1000)
+ })),
+ metadata: { period: '最近30天' }
+ });
+ break;
+ case 'conversion':
+ charts.push({
+ chart_type: 'funnel',
+ title: '转化漏斗',
+ data_points: [
+ { label: '访问', value: 10000, unit: '人', timestamp: Math.floor(now / 1000) },
+ { label: '注册', value: 2500, unit: '人', timestamp: Math.floor(now / 1000) },
+ { label: '购买', value: 750, unit: '人', timestamp: Math.floor(now / 1000) }
+ ],
+ metadata: { conversion_rate: '7.5%' }
+ });
+ break;
+ case 'engagement':
+ charts.push({
+ chart_type: 'bar',
+ title: '用户参与度指标',
+ data_points: [
+ { label: '平均停留时间', value: 4.5, unit: '分钟', timestamp: Math.floor(now / 1000) },
+ { label: '页面浏览深度', value: 3.2, unit: '页', timestamp: Math.floor(now / 1000) },
+ { label: '互动率', value: 15.8, unit: '%', timestamp: Math.floor(now / 1000) }
+ ],
+ metadata: { period: '本周' }
+ });
+ break;
+ case 'retention':
+ charts.push({
+ chart_type: 'line',
+ title: '用户留存率',
+ data_points: [
+ { label: '第1天', value: 100, unit: '%', timestamp: Math.floor(now / 1000) },
+ { label: '第7天', value: 65, unit: '%', timestamp: Math.floor(now / 1000) },
+ { label: '第30天', value: 35, unit: '%', timestamp: Math.floor(now / 1000) },
+ { label: '第90天', value: 20, unit: '%', timestamp: Math.floor(now / 1000) }
+ ],
+ metadata: { cohort: '新用户群体' }
+ });
+ break;
+ }
+
+ return charts;
+}
+
+function generateInsightsCharts(option) {
+ const charts = [];
+ const now = Date.now();
+
+ switch(option) {
+ case 'trends':
+ charts.push({
+ chart_type: 'line',
+ title: '趋势预测',
+ data_points: Array.from({length: 12}, (_, i) => ({
+ label: `未来第${i+1}月`,
+ value: Math.random() * 20000 + 10000,
+ unit: '元',
+ timestamp: Math.floor((now + i * 30 * 24 * 60 * 60 * 1000) / 1000)
+ })),
+ metadata: { confidence: '85%', model: 'ARIMA' }
+ });
+ break;
+ case 'recommendations':
+ charts.push({
+ chart_type: 'bar',
+ title: '推荐效果',
+ data_points: [
+ { label: '点击率提升', value: 25.5, unit: '%', timestamp: Math.floor(now / 1000) },
+ { label: '转化率提升', value: 18.2, unit: '%', timestamp: Math.floor(now / 1000) },
+ { label: '收入提升', value: 32.1, unit: '%', timestamp: Math.floor(now / 1000) }
+ ],
+ metadata: { algorithm: 'collaborative_filtering' }
+ });
+ break;
+ case 'anomalies':
+ charts.push({
+ chart_type: 'scatter',
+ title: '异常检测结果',
+ data_points: [
+ { label: '正常数据', value: 95.2, unit: '%', timestamp: Math.floor(now / 1000) },
+ { label: '轻微异常', value: 3.8, unit: '%', timestamp: Math.floor(now / 1000) },
+ { label: '严重异常', value: 1.0, unit: '%', timestamp: Math.floor(now / 1000) }
+ ],
+ metadata: { algorithm: 'isolation_forest', threshold: '0.05' }
+ });
+ break;
+ case 'forecasting':
+ charts.push({
+ chart_type: 'line',
+ title: '预测分析',
+ data_points: Array.from({length: 6}, (_, i) => ({
+ label: `Q${i+1}`,
+ value: Math.random() * 50000 + 100000,
+ unit: '元',
+ timestamp: Math.floor((now + i * 90 * 24 * 60 * 60 * 1000) / 1000)
+ })),
+ metadata: { model: 'prophet', accuracy: '92%' }
+ });
+ break;
+ }
+
+ return charts;
+}
+
+// 生成汇总指标的函数
+function generateAnalyticsMetrics(option) {
+ switch(option) {
+ case 'sales':
+ return {
+ '总销售额': 156780,
+ '订单数量': 1245,
+ '平均客单价': 125.9,
+ '同比增长': 15.6
+ };
+ case 'revenue':
+ return {
+ '月收入': 234560,
+ '毛利率': 45.2,
+ '净利润': 89340,
+ '增长率': 12.8
+ };
+ case 'customers':
+ return {
+ '总客户数': 12450,
+ '新增客户': 890,
+ '活跃客户': 8760,
+ '客户满意度': 4.6
+ };
+ case 'products':
+ return {
+ '产品总数': 156,
+ '热销产品': 23,
+ '库存周转率': 8.5,
+ '退货率': 2.1
+ };
+ default:
+ return {};
+ }
+}
+
+function generateReportsMetrics(option) {
+ switch(option) {
+ case 'performance':
+ return {
+ '平均响应时间': 145.6,
+ '系统可用性': 99.8,
+ 'CPU使用率': 65.2,
+ '内存使用率': 72.1
+ };
+ case 'errors':
+ return {
+ '总错误数': 234,
+ '错误率': 0.12,
+ '已修复': 198,
+ '待处理': 36
+ };
+ case 'security':
+ return {
+ '安全事件': 12,
+ '威胁等级': 2.3,
+ '防护成功率': 98.7,
+ '漏洞数量': 3
+ };
+ case 'usage':
+ return {
+ '日活用户': 8950,
+ '月活用户': 45600,
+ '使用时长': 25.6,
+ '功能使用率': 78.9
+ };
+ default:
+ return {};
+ }
+}
+
+function generateStatisticsMetrics(option) {
+ switch(option) {
+ case 'traffic':
+ return {
+ '总访问量': 156780,
+ '独立访客': 89450,
+ '页面浏览量': 345670,
+ '跳出率': 35.6
+ };
+ case 'conversion':
+ return {
+ '转化率': 7.5,
+ '注册转化': 25.0,
+ '购买转化': 30.0,
+ 'ROI': 3.2
+ };
+ case 'engagement':
+ return {
+ '平均停留': 4.5,
+ '页面深度': 3.2,
+ '互动率': 15.8,
+ '分享率': 8.9
+ };
+ case 'retention':
+ return {
+ '7日留存': 65.0,
+ '30日留存': 35.0,
+ '90日留存': 20.0,
+ '年留存': 12.5
+ };
+ default:
+ return {};
+ }
+}
+
+function generateInsightsMetrics(option) {
+ switch(option) {
+ case 'trends':
+ return {
+ '预测准确率': 85.6,
+ '趋势强度': 7.8,
+ '置信度': 92.3,
+ '预测周期': 12
+ };
+ case 'recommendations':
+ return {
+ '推荐精度': 78.9,
+ '点击提升': 25.5,
+ '转化提升': 18.2,
+ '满意度': 4.3
+ };
+ case 'anomalies':
+ return {
+ '检测精度': 95.2,
+ '误报率': 2.1,
+ '异常数量': 15,
+ '处理率': 87.5
+ };
+ case 'forecasting':
+ return {
+ '预测精度': 92.1,
+ '模型得分': 8.7,
+ '预测范围': 6,
+ '更新频率': 7
+ };
+ default:
+ return {};
+ }
+}
+
+// 双向 Protocol Buffers 通信接口
+app.post('/api/bidirectional-protobuf', (req, res) => {
+ if (!protobufRoot) {
+ return res.status(500).json({ error: 'Protocol Buffers schema not initialized' });
+ }
+
+ // 获取原始请求体(二进制数据)
+ let bufferData = Buffer.alloc(0);
+
+ req.on('data', chunk => {
+ bufferData = Buffer.concat([bufferData, chunk]);
+ });
+
+ req.on('end', () => {
+ try {
+ // 定义双向protobuf schema
+ const bidirectionalSchema = `
+ syntax = "proto3";
+ package microservice;
+
+ message UserRequest {
+ string action = 1;
+ string user_id = 2;
+ string name = 3;
+ string email = 4;
+ string role = 5;
+ string status = 6;
+ }
+
+ message UserResponse {
+ bool success = 1;
+ string message = 2;
+ string user_id = 3;
+ string name = 4;
+ string email = 5;
+ string role = 6;
+ string status = 7;
+ int64 created_at = 8;
+ int64 updated_at = 9;
+ }
+
+ message OrderRequest {
+ string action = 1;
+ string order_id = 2;
+ string customer_id = 3;
+ double amount = 4;
+ string payment_method = 5;
+ string status = 6;
+ }
+
+ message OrderResponse {
+ bool success = 1;
+ string message = 2;
+ string order_id = 3;
+ string customer_id = 4;
+ double amount = 5;
+ string payment_method = 6;
+ string status = 7;
+ int64 created_at = 8;
+ string tracking_number = 9;
+ }
+
+ message AnalyticsRequest {
+ string analytics_type = 1;
+ string time_range = 2;
+ string data_source = 3;
+ string output_format = 4;
+ }
+
+ message AnalyticsResponse {
+ bool success = 1;
+ string message = 2;
+ string report_id = 3;
+ string analytics_type = 4;
+ map metrics = 5;
+ string download_url = 6;
+ int64 generated_at = 7;
+ }
+
+ message NotificationRequest {
+ string notification_type = 1;
+ string priority = 2;
+ string recipient = 3;
+ string template = 4;
+ string content = 5;
+ }
+
+ message NotificationResponse {
+ bool success = 1;
+ string message = 2;
+ string notification_id = 3;
+ string status = 4;
+ int64 sent_at = 5;
+ string delivery_status = 6;
+ }
+
+ message ServiceRequest {
+ string request_id = 1;
+ int64 timestamp = 2;
+ string service_name = 3;
+
+ oneof request_data {
+ UserRequest user_request = 10;
+ OrderRequest order_request = 11;
+ AnalyticsRequest analytics_request = 12;
+ NotificationRequest notification_request = 13;
+ }
+ }
+
+ message ServiceResponse {
+ string request_id = 1;
+ int64 timestamp = 2;
+ bool success = 3;
+ string service_name = 4;
+ int32 status_code = 5;
+
+ oneof response_data {
+ UserResponse user_response = 10;
+ OrderResponse order_response = 11;
+ AnalyticsResponse analytics_response = 12;
+ NotificationResponse notification_response = 13;
+ }
+ }
+ `;
+
+ const bidirectionalRoot = protobuf.parse(bidirectionalSchema).root;
+
+ // 解析protobuf请求
+ const ServiceRequest = bidirectionalRoot.lookupType('microservice.ServiceRequest');
+ const requestMessage = ServiceRequest.decode(bufferData);
+ const requestData = ServiceRequest.toObject(requestMessage);
+
+ // 构建响应数据
+ const responseData = {
+ request_id: requestData.request_id,
+ timestamp: Math.floor(Date.now() / 1000),
+ success: true,
+ service_name: requestData.service_name,
+ status_code: 200
+ };
+
+ // 根据服务类型处理请求并构建响应
+ switch(requestData.service_name) {
+ case 'user-management':
+ if (requestData.user_request) {
+ const userReq = requestData.user_request;
+ responseData.user_response = {
+ success: true,
+ message: `用户${userReq.action}操作成功`,
+ user_id: userReq.user_id,
+ name: userReq.name,
+ email: userReq.email,
+ role: userReq.role,
+ status: userReq.status,
+ created_at: Math.floor(Date.now() / 1000),
+ updated_at: Math.floor(Date.now() / 1000)
+ };
+ }
+ break;
+
+ case 'order-processing':
+ if (requestData.order_request) {
+ const orderReq = requestData.order_request;
+ responseData.order_response = {
+ success: true,
+ message: `订单${orderReq.action}操作成功`,
+ order_id: orderReq.order_id,
+ customer_id: orderReq.customer_id,
+ amount: orderReq.amount,
+ payment_method: orderReq.payment_method,
+ status: orderReq.status === 'pending' ? 'processing' : orderReq.status,
+ created_at: Math.floor(Date.now() / 1000),
+ tracking_number: 'TRK' + Math.random().toString(36).substring(2, 15).toUpperCase()
+ };
+ }
+ break;
+
+ case 'data-analytics':
+ if (requestData.analytics_request) {
+ const analyticsReq = requestData.analytics_request;
+ responseData.analytics_response = {
+ success: true,
+ message: `${analyticsReq.analytics_type}分析完成`,
+ report_id: 'RPT' + Math.random().toString(36).substring(2, 15).toUpperCase(),
+ analytics_type: analyticsReq.analytics_type,
+ metrics: {
+ '总数据量': Math.floor(Math.random() * 100000) + 50000,
+ '处理时间': Math.floor(Math.random() * 60) + 30,
+ '准确率': Math.floor(Math.random() * 20) + 80,
+ '覆盖率': Math.floor(Math.random() * 30) + 70
+ },
+ download_url: `https://reports.example.com/download/${Math.random().toString(36).substring(2, 15)}`,
+ generated_at: Math.floor(Date.now() / 1000)
+ };
+ }
+ break;
+
+ case 'notification':
+ if (requestData.notification_request) {
+ const notificationReq = requestData.notification_request;
+ responseData.notification_response = {
+ success: true,
+ message: `${notificationReq.notification_type}通知发送成功`,
+ notification_id: 'NOT' + Math.random().toString(36).substring(2, 15).toUpperCase(),
+ status: 'sent',
+ sent_at: Math.floor(Date.now() / 1000),
+ delivery_status: 'delivered'
+ };
+ }
+ break;
+
+ default:
+ responseData.success = false;
+ responseData.status_code = 400;
+ }
+
+ // 序列化响应为protobuf
+ const ServiceResponse = bidirectionalRoot.lookupType('microservice.ServiceResponse');
+ const responseMessage = ServiceResponse.create(responseData);
+ const responseBuffer = ServiceResponse.encode(responseMessage).finish();
+
+ // 设置响应头并发送二进制数据
+ res.setHeader('Content-Type', 'application/x-protobuf');
+ res.send(responseBuffer);
+
+ } catch (error) {
+ res.status(400).json({ error: '双向 Protocol Buffers 通信失败', details: error.message });
+ }
+ });
+});
+
+// 请求头签名验证接口
+app.post('/api/header-sign', (req, res) => {
+ try {
+ // 获取请求头中的签名信息
+ const xSign = req.headers['x-sign'];
+ const xTimestamp = req.headers['x-timestamp'];
+ const xNonce = req.headers['x-nonce'];
+ const xClientId = req.headers['x-client-id'];
+
+ if (!xSign || !xTimestamp || !xNonce || !xClientId) {
+ return res.status(400).json({
+ error: '缺少必要的签名请求头',
+ required_headers: ['X-Sign', 'X-Timestamp', 'X-Nonce', 'X-Client-Id']
+ });
+ }
+
+ // 检查时间戳(防止重放攻击)
+ const currentTime = Math.floor(Date.now() / 1000);
+ const requestTime = parseInt(xTimestamp);
+ const timeDiff = Math.abs(currentTime - requestTime);
+
+ if (timeDiff > 300) { // 5分钟有效期
+ return res.status(401).json({
+ error: '请求时间戳过期',
+ current_time: currentTime,
+ request_time: requestTime,
+ time_diff: timeDiff
+ });
+ }
+
+ // 获取请求体数据
+ const requestData = req.body;
+
+ // 验证签名
+ const secretKey = 'your-secret-key-2025';
+ const isValid = verifySignature(requestData, xTimestamp, xNonce, xSign, secretKey);
+
+ if (!isValid) {
+ return res.status(401).json({
+ error: '签名验证失败',
+ signature_valid: false
+ });
+ }
+
+ // 构建响应数据
+ const responseData = {
+ request_id: 'REQ' + Math.random().toString(36).substring(2, 15).toUpperCase(),
+ timestamp: currentTime,
+ signature_valid: true,
+ api_type: requestData.api_type,
+ client_id: xClientId
+ };
+
+ // 根据API类型生成不同的响应
+ switch(requestData.api_type) {
+ case 'payment':
+ responseData.payment_result = {
+ status: 'success',
+ transaction_id: 'TXN' + Math.random().toString(36).substring(2, 15).toUpperCase(),
+ amount: requestData.amount,
+ payment_method: requestData.payment_method,
+ fee: (requestData.amount * 0.006).toFixed(2), // 0.6% 手续费
+ order_id: requestData.order_id,
+ merchant_id: requestData.merchant_id
+ };
+ break;
+
+ case 'transfer':
+ responseData.transfer_result = {
+ status: 'processing',
+ transfer_id: 'TRF' + Math.random().toString(36).substring(2, 15).toUpperCase(),
+ amount: requestData.amount,
+ currency: requestData.currency,
+ from_account: requestData.from_account,
+ to_account: requestData.to_account,
+ estimated_arrival: '2-24小时内到账'
+ };
+ break;
+
+ case 'sensitive':
+ responseData.access_result = {
+ status: 'granted',
+ data_type: requestData.data_type,
+ access_level: requestData.access_level,
+ user_id: requestData.user_id,
+ department: requestData.department,
+ access_token: 'AT' + Math.random().toString(36).substring(2, 25).toUpperCase(),
+ expires_in: 3600 // 1小时
+ };
+ break;
+
+ case 'admin':
+ responseData.admin_result = {
+ status: 'authorized',
+ action: requestData.action,
+ admin_level: requestData.admin_level,
+ admin_id: requestData.admin_id,
+ operation_id: 'OP' + Math.random().toString(36).substring(2, 15).toUpperCase(),
+ audit_log: `管理员${requestData.admin_id}执行${requestData.action}操作`,
+ session_id: requestData.session_id
+ };
+ break;
+
+ default:
+ responseData.error = '未知的API类型';
+ }
+
+ res.json(responseData);
+
+ } catch (error) {
+ res.status(500).json({
+ error: '请求头签名验证失败',
+ details: error.message
+ });
+ }
+});
+
+// 签名验证函数
+function verifySignature(data, timestamp, nonce, signature, secretKey) {
+ try {
+ // 将数据按key排序并拼接
+ const sortedKeys = Object.keys(data).sort();
+ const paramString = sortedKeys.map(key => `${key}=${data[key]}`).join('&');
+
+ // 构建签名字符串
+ const signString = `${paramString}×tamp=${timestamp}&nonce=${nonce}&key=${secretKey}`;
+
+ // 生成期望的签名
+ const expectedSignature = crypto.createHmac('sha256', secretKey)
+ .update(signString)
+ .digest('hex');
+
+ // 比较签名
+ return signature === expectedSignature;
+ } catch (error) {
+ console.error('签名验证错误:', error);
+ return false;
+ }
+}
+
+// 响应头加密Cookie接口
+app.post('/api/response-header-cookie', (req, res) => {
+ try {
+ const requestData = req.body;
+ const currentTime = Math.floor(Date.now() / 1000);
+
+ // 构建响应数据
+ const responseData = {
+ session_id: 'SES' + Math.random().toString(36).substring(2, 15).toUpperCase(),
+ timestamp: currentTime,
+ authenticated: true,
+ service_type: requestData.service_type,
+ client_ip: requestData.client_ip
+ };
+
+ // 构建Cookie数据
+ const cookieData = {
+ user_id: 'USER' + Math.random().toString(36).substring(2, 10).toUpperCase(),
+ session_token: 'TOKEN' + Math.random().toString(36).substring(2, 20).toUpperCase(),
+ permission_level: 'standard',
+ expires_at: currentTime + 86400, // 24小时后过期
+ device_info: requestData.device_type || 'web',
+ last_activity: currentTime
+ };
+
+ // 根据服务类型生成不同的响应和Cookie
+ switch(requestData.service_type) {
+ case 'login':
+ responseData.login_result = {
+ status: 'success',
+ user_id: cookieData.user_id,
+ access_token: 'AT' + Math.random().toString(36).substring(2, 25).toUpperCase(),
+ token_type: 'Bearer',
+ expires_in: 3600
+ };
+ cookieData.permission_level = 'authenticated';
+ cookieData.login_method = 'password';
+ cookieData.remember_me = requestData.remember;
+ break;
+
+ case 'oauth':
+ responseData.oauth_result = {
+ status: 'authorized',
+ provider: requestData.provider,
+ access_token: 'OAT' + Math.random().toString(36).substring(2, 25).toUpperCase(),
+ scope: requestData.scope,
+ user_info: `${requestData.provider}_user_${Math.random().toString(36).substring(2, 8)}`
+ };
+ cookieData.permission_level = 'oauth';
+ cookieData.oauth_provider = requestData.provider;
+ cookieData.oauth_scope = requestData.scope;
+ break;
+
+ case 'sso':
+ responseData.sso_result = {
+ status: 'authenticated',
+ provider: requestData.sso_provider,
+ user_identifier: `${requestData.domain}\\user_${Math.random().toString(36).substring(2, 8)}`,
+ domain: requestData.domain,
+ service_ticket: 'ST' + Math.random().toString(36).substring(2, 15).toUpperCase()
+ };
+ cookieData.permission_level = 'sso';
+ cookieData.sso_provider = requestData.sso_provider;
+ cookieData.domain = requestData.domain;
+ break;
+
+ case 'refresh':
+ responseData.refresh_result = {
+ status: 'refreshed',
+ new_access_token: 'RAT' + Math.random().toString(36).substring(2, 25).toUpperCase(),
+ new_refresh_token: 'RRT' + Math.random().toString(36).substring(2, 25).toUpperCase(),
+ expires_in: getExpirySeconds(requestData.expiry),
+ scope: requestData.scope
+ };
+ cookieData.permission_level = 'refreshed';
+ cookieData.refresh_scope = requestData.scope;
+ cookieData.device_verified = requestData.device_verification === 'verify';
+ break;
+
+ default:
+ responseData.error = '未知的服务类型';
+ }
+
+ // 加密Cookie数据
+ const secretKey = 'cookie-secret-key-2025';
+ const encryptedCookie = encryptCookieData(cookieData, secretKey);
+
+ // 设置响应头
+ res.setHeader('X-Cookie', encryptedCookie);
+ res.setHeader('X-Session-Id', responseData.session_id);
+ res.setHeader('X-Auth-Status', responseData.authenticated ? 'success' : 'failed');
+ res.setHeader('X-Service-Type', requestData.service_type);
+
+ res.json(responseData);
+
+ } catch (error) {
+ res.status(500).json({
+ error: '响应头Cookie处理失败',
+ details: error.message
+ });
+ }
+});
+
+// Cookie数据加密函数
+function encryptCookieData(cookieData, secretKey) {
+ try {
+ const cookieString = JSON.stringify(cookieData);
+ const encrypted = crypto.createCipher('aes-256-cbc', secretKey);
+ let encryptedData = encrypted.update(cookieString, 'utf8', 'base64');
+ encryptedData += encrypted.final('base64');
+ return encryptedData;
+ } catch (error) {
+ console.error('Cookie加密错误:', error);
+ return '';
+ }
+}
+
+// 获取过期时间(秒)
+function getExpirySeconds(expiry) {
+ switch(expiry) {
+ case '1h': return 3600;
+ case '24h': return 86400;
+ case '7d': return 604800;
+ case '30d': return 2592000;
+ default: return 3600;
+ }
+}
+
+// 拦截器加密API端点 - 通用处理函数
+function handleInterceptorRequest(serviceName, req, res) {
+ try {
+ const requestData = req.body;
+ const currentTime = Math.floor(Date.now() / 1000);
+
+ // 验证拦截器添加的必要参数
+ if (!requestData.sign || !requestData.timestamp || !requestData.nonce || !requestData.interceptor_id) {
+ return res.status(400).json({
+ error: '缺少拦截器签名参数',
+ required_params: ['sign', 'timestamp', 'nonce', 'interceptor_id']
+ });
+ }
+
+ // 检查时间戳(防止重放攻击)
+ const requestTime = parseInt(requestData.timestamp);
+ const timeDiff = Math.abs(currentTime - requestTime);
+
+ if (timeDiff > 300) { // 5分钟有效期
+ return res.status(401).json({
+ error: '请求时间戳过期',
+ current_time: currentTime,
+ request_time: requestTime,
+ time_diff: timeDiff
+ });
+ }
+
+ // 验证签名
+ const secretKey = 'interceptor-secret-key-2025';
+ const isValid = verifyInterceptorSignature(requestData, secretKey);
+
+ if (!isValid) {
+ return res.status(401).json({
+ error: '拦截器签名验证失败',
+ signature_valid: false
+ });
+ }
+
+ // 构建响应数据
+ const responseData = {
+ request_id: 'REQ' + Math.random().toString(36).substring(2, 15).toUpperCase(),
+ timestamp: currentTime,
+ signature_valid: true,
+ service_name: serviceName,
+ interceptor_id: requestData.interceptor_id,
+ client_id: requestData.client_id
+ };
+
+ // 根据服务类型生成不同的响应
+ switch(serviceName) {
+ case 'user-service':
+ responseData.service_result = {
+ status: 'success',
+ user_count: Math.floor(Math.random() * 10000) + 1000,
+ active_users: Math.floor(Math.random() * 5000) + 500,
+ new_registrations: Math.floor(Math.random() * 100) + 10,
+ user_data: {
+ total_users: Math.floor(Math.random() * 50000) + 10000,
+ premium_users: Math.floor(Math.random() * 5000) + 1000,
+ last_login_24h: Math.floor(Math.random() * 8000) + 2000
+ }
+ };
+ break;
+
+ case 'order-service':
+ responseData.service_result = {
+ status: 'success',
+ total_orders: Math.floor(Math.random() * 5000) + 1000,
+ pending_orders: Math.floor(Math.random() * 200) + 50,
+ completed_orders: Math.floor(Math.random() * 4000) + 800,
+ order_data: {
+ daily_orders: Math.floor(Math.random() * 500) + 100,
+ average_value: (Math.random() * 500 + 100).toFixed(2),
+ top_category: ['电子产品', '服装', '食品', '图书'][Math.floor(Math.random() * 4)]
+ }
+ };
+ break;
+
+ case 'payment-service':
+ responseData.service_result = {
+ status: 'success',
+ total_transactions: Math.floor(Math.random() * 8000) + 2000,
+ successful_payments: Math.floor(Math.random() * 7500) + 1900,
+ failed_payments: Math.floor(Math.random() * 100) + 10,
+ payment_data: {
+ total_amount: (Math.random() * 1000000 + 100000).toFixed(2),
+ average_transaction: (Math.random() * 200 + 50).toFixed(2),
+ payment_methods: {
+ 'credit_card': Math.floor(Math.random() * 40) + 30,
+ 'alipay': Math.floor(Math.random() * 30) + 25,
+ 'wechat_pay': Math.floor(Math.random() * 25) + 20
+ }
+ }
+ };
+ break;
+
+ case 'inventory-service':
+ responseData.service_result = {
+ status: 'success',
+ total_products: Math.floor(Math.random() * 2000) + 500,
+ in_stock: Math.floor(Math.random() * 1800) + 400,
+ out_of_stock: Math.floor(Math.random() * 50) + 10,
+ inventory_data: {
+ total_value: (Math.random() * 5000000 + 1000000).toFixed(2),
+ low_stock_alerts: Math.floor(Math.random() * 20) + 5,
+ categories: Math.floor(Math.random() * 50) + 20,
+ warehouses: Math.floor(Math.random() * 10) + 3
+ }
+ };
+ break;
+
+ case 'analytics-service':
+ responseData.service_result = {
+ status: 'success',
+ reports_generated: Math.floor(Math.random() * 100) + 20,
+ data_points: Math.floor(Math.random() * 1000000) + 100000,
+ processing_time: (Math.random() * 5 + 1).toFixed(2),
+ analytics_data: {
+ conversion_rate: (Math.random() * 10 + 5).toFixed(2),
+ bounce_rate: (Math.random() * 30 + 20).toFixed(2),
+ avg_session_duration: (Math.random() * 300 + 120).toFixed(0),
+ top_pages: ['首页', '产品页', '购物车', '结算页'][Math.floor(Math.random() * 4)]
+ }
+ };
+ break;
+
+ case 'notification-service':
+ responseData.service_result = {
+ status: 'success',
+ messages_sent: Math.floor(Math.random() * 5000) + 1000,
+ delivery_rate: (Math.random() * 10 + 90).toFixed(2),
+ failed_deliveries: Math.floor(Math.random() * 50) + 5,
+ notification_data: {
+ email_sent: Math.floor(Math.random() * 2000) + 500,
+ sms_sent: Math.floor(Math.random() * 1000) + 200,
+ push_sent: Math.floor(Math.random() * 3000) + 800,
+ channels: ['email', 'sms', 'push', 'webhook']
+ }
+ };
+ break;
+
+ default:
+ responseData.error = '未知的服务类型';
+ }
+
+ res.json(responseData);
+
+ } catch (error) {
+ res.status(500).json({
+ error: '拦截器请求处理失败',
+ service: serviceName,
+ details: error.message
+ });
+ }
+}
+
+// 拦截器签名验证函数
+function verifyInterceptorSignature(data, secretKey) {
+ try {
+ const { sign, ...signData } = data;
+
+ // 将数据按key排序并拼接
+ const sortedKeys = Object.keys(signData).sort();
+ const paramString = sortedKeys.map(key => `${key}=${signData[key]}`).join('&');
+ const signString = `${paramString}&key=${secretKey}`;
+
+ // 生成期望的签名(使用MD5)
+ const expectedSignature = crypto.createHash('md5')
+ .update(signString)
+ .digest('hex');
+
+ // 比较签名
+ return sign === expectedSignature;
+ } catch (error) {
+ console.error('拦截器签名验证错误:', error);
+ return false;
+ }
+}
+
+// 各个服务的拦截器API端点
+app.post('/api/interceptor-user-service', (req, res) => {
+ handleInterceptorRequest('user-service', req, res);
+});
+
+app.post('/api/interceptor-order-service', (req, res) => {
+ handleInterceptorRequest('order-service', req, res);
+});
+
+app.post('/api/interceptor-payment-service', (req, res) => {
+ handleInterceptorRequest('payment-service', req, res);
+});
+
+app.post('/api/interceptor-inventory-service', (req, res) => {
+ handleInterceptorRequest('inventory-service', req, res);
+});
+
+app.post('/api/interceptor-analytics-service', (req, res) => {
+ handleInterceptorRequest('analytics-service', req, res);
+});
+
+app.post('/api/interceptor-notification-service', (req, res) => {
+ handleInterceptorRequest('notification-service', req, res);
+});
+
+// 视频片段加密API端点
+app.get('/api/video-segment/:videoType/:segmentId', (req, res) => {
+ try {
+ const { videoType, segmentId } = req.params;
+ const segmentIndex = parseInt(segmentId);
+
+ // 视频配置
+ const videoConfigs = {
+ 'movie-action': {
+ title: '动作电影 - 速度与激情',
+ encryptionKey: 'movie-action-key-2025',
+ segmentCount: 240
+ },
+ 'series-drama': {
+ title: '电视剧集 - 权力的游戏',
+ encryptionKey: 'series-drama-key-2025',
+ segmentCount: 90
+ },
+ 'documentary': {
+ title: '纪录片 - 地球脉动',
+ encryptionKey: 'documentary-key-2025',
+ segmentCount: 180
+ },
+ 'live-stream': {
+ title: '直播流 - 新闻频道',
+ encryptionKey: 'live-stream-key-2025',
+ segmentCount: 20
+ }
+ };
+
+ const config = videoConfigs[videoType];
+ if (!config) {
+ return res.status(404).json({
+ error: '未知的视频类型',
+ available_types: Object.keys(videoConfigs)
+ });
+ }
+
+ if (segmentIndex < 0 || segmentIndex >= config.segmentCount) {
+ return res.status(404).json({
+ error: '片段索引超出范围',
+ segment_index: segmentIndex,
+ max_segments: config.segmentCount
+ });
+ }
+
+ // 生成模拟的视频片段数据
+ const segmentData = generateVideoSegmentData(videoType, segmentIndex);
+
+ // 加密视频片段
+ const encryptedSegment = encryptVideoSegment(segmentData, config.encryptionKey);
+
+ // 构建响应
+ const responseData = {
+ video_type: videoType,
+ segment_id: segmentIndex,
+ segment_name: `segment_${segmentIndex.toString().padStart(3, '0')}.ts`,
+ encrypted_data: encryptedSegment.encryptedData,
+ iv: encryptedSegment.iv,
+ encryption_method: 'AES-128-CBC',
+ segment_size: encryptedSegment.size,
+ duration: 30, // 30秒片段
+ timestamp: Math.floor(Date.now() / 1000),
+ content_type: 'video/mp2t'
+ };
+
+ res.json(responseData);
+
+ } catch (error) {
+ res.status(500).json({
+ error: '视频片段处理失败',
+ details: error.message
+ });
+ }
+});
+
+// 生成模拟视频片段数据
+function generateVideoSegmentData(videoType, segmentIndex) {
+ // 生成模拟的视频数据(实际应用中这里是真实的视频片段)
+ const baseData = `VIDEO_SEGMENT_${videoType.toUpperCase()}_${segmentIndex}`;
+ const timestamp = Math.floor(Date.now() / 1000);
+ const randomData = Math.random().toString(36).substring(2, 15);
+
+ // 模拟视频片段内容
+ const segmentContent = {
+ header: 'TS_PACKET_HEADER',
+ video_data: baseData + '_' + randomData,
+ audio_data: `AUDIO_${segmentIndex}_${randomData}`,
+ metadata: {
+ segment_index: segmentIndex,
+ timestamp: timestamp,
+ duration: 30,
+ video_codec: 'H.264',
+ audio_codec: 'AAC',
+ resolution: videoType === 'documentary' ? '4K' : (videoType === 'movie-action' ? '1080p' : '720p')
+ },
+ footer: 'TS_PACKET_FOOTER'
+ };
+
+ return JSON.stringify(segmentContent);
+}
+
+// 加密视频片段
+function encryptVideoSegment(segmentData, encryptionKey) {
+ try {
+ // 生成随机IV
+ const iv = crypto.randomBytes(16);
+
+ // 创建AES-128-CBC加密器
+ const cipher = crypto.createCipher('aes-128-cbc', encryptionKey);
+ cipher.setAutoPadding(true);
+
+ // 加密数据
+ let encrypted = cipher.update(segmentData, 'utf8', 'base64');
+ encrypted += cipher.final('base64');
+
+ return {
+ encryptedData: encrypted,
+ iv: iv.toString('hex'),
+ size: Buffer.from(encrypted, 'base64').length
+ };
+ } catch (error) {
+ console.error('视频片段加密错误:', error);
+ throw new Error('视频片段加密失败');
+ }
+}
+
+// 批量视频片段API(用于流式加载)
+app.post('/api/video-segments/batch', (req, res) => {
+ try {
+ const { video_type, segment_ids } = req.body;
+
+ if (!video_type || !Array.isArray(segment_ids)) {
+ return res.status(400).json({
+ error: '缺少必要参数',
+ required: ['video_type', 'segment_ids']
+ });
+ }
+
+ const videoConfigs = {
+ 'movie-action': { encryptionKey: 'movie-action-key-2025', segmentCount: 240 },
+ 'series-drama': { encryptionKey: 'series-drama-key-2025', segmentCount: 90 },
+ 'documentary': { encryptionKey: 'documentary-key-2025', segmentCount: 180 },
+ 'live-stream': { encryptionKey: 'live-stream-key-2025', segmentCount: 20 }
+ };
+
+ const config = videoConfigs[video_type];
+ if (!config) {
+ return res.status(404).json({
+ error: '未知的视频类型',
+ available_types: Object.keys(videoConfigs)
+ });
+ }
+
+ const segments = [];
+ const errors = [];
+
+ segment_ids.forEach(segmentId => {
+ try {
+ const segmentIndex = parseInt(segmentId);
+
+ if (segmentIndex < 0 || segmentIndex >= config.segmentCount) {
+ errors.push({
+ segment_id: segmentId,
+ error: '片段索引超出范围'
+ });
+ return;
+ }
+
+ const segmentData = generateVideoSegmentData(video_type, segmentIndex);
+ const encryptedSegment = encryptVideoSegment(segmentData, config.encryptionKey);
+
+ segments.push({
+ segment_id: segmentIndex,
+ segment_name: `segment_${segmentIndex.toString().padStart(3, '0')}.ts`,
+ encrypted_data: encryptedSegment.encryptedData,
+ iv: encryptedSegment.iv,
+ size: encryptedSegment.size
+ });
+ } catch (error) {
+ errors.push({
+ segment_id: segmentId,
+ error: error.message
+ });
+ }
+ });
+
+ res.json({
+ video_type: video_type,
+ total_requested: segment_ids.length,
+ successful_segments: segments.length,
+ failed_segments: errors.length,
+ segments: segments,
+ errors: errors,
+ timestamp: Math.floor(Date.now() / 1000)
+ });
+
+ } catch (error) {
+ res.status(500).json({
+ error: '批量视频片段处理失败',
+ details: error.message
+ });
+ }
+});
+
+const port = Number(process.env.PORT || 48159);
+
+// 启动服务器并初始化protobuf
+const startServer = async () => {
+ await initProtobufSchema();
+
+ app.listen(port, () => {
+ console.log(`Server is running on http://localhost:${port}`);
+ });
+};
+
+startServer();
diff --git a/JS-hook/src/main/java/com/myapp/jshook/CryptoJsCompat.java b/JS-hook/src/main/java/com/myapp/jshook/CryptoJsCompat.java
new file mode 100644
index 0000000..08212da
--- /dev/null
+++ b/JS-hook/src/main/java/com/myapp/jshook/CryptoJsCompat.java
@@ -0,0 +1,158 @@
+package com.myapp.jshook;
+
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.security.MessageDigest;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.Base64;
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+public final class CryptoJsCompat {
+ private static final byte[] SALTED = "Salted__".getBytes(StandardCharsets.US_ASCII);
+ private static final SecureRandom RANDOM = new SecureRandom();
+
+ private CryptoJsCompat() {
+ }
+
+ public static String encrypt(String plainText, String passphrase) {
+ try {
+ byte[] salt = new byte[8];
+ RANDOM.nextBytes(salt);
+ KeyAndIv keyAndIv = evpBytesToKey(passphrase.getBytes(StandardCharsets.UTF_8), salt, 32, 16);
+ Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+ cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyAndIv.key, "AES"), new IvParameterSpec(keyAndIv.iv));
+ byte[] cipherText = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
+
+ byte[] output = new byte[SALTED.length + salt.length + cipherText.length];
+ System.arraycopy(SALTED, 0, output, 0, SALTED.length);
+ System.arraycopy(salt, 0, output, SALTED.length, salt.length);
+ System.arraycopy(cipherText, 0, output, SALTED.length + salt.length, cipherText.length);
+ return Base64.getEncoder().encodeToString(output);
+ } catch (GeneralSecurityException ex) {
+ throw new IllegalStateException("Failed to encrypt CryptoJS payload", ex);
+ }
+ }
+
+ public static String decrypt(String encryptedText, String passphrase) {
+ try {
+ byte[] allBytes = Base64.getDecoder().decode(encryptedText);
+ byte[] salt = null;
+ byte[] cipherText = allBytes;
+
+ if (allBytes.length > 16 && startsWithSalted(allBytes)) {
+ salt = Arrays.copyOfRange(allBytes, 8, 16);
+ cipherText = Arrays.copyOfRange(allBytes, 16, allBytes.length);
+ }
+
+ KeyAndIv keyAndIv = evpBytesToKey(
+ passphrase.getBytes(StandardCharsets.UTF_8),
+ salt,
+ 32,
+ 16
+ );
+ Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+ cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keyAndIv.key, "AES"), new IvParameterSpec(keyAndIv.iv));
+ byte[] plain = cipher.doFinal(cipherText);
+ return new String(plain, StandardCharsets.UTF_8);
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("Failed to decrypt CryptoJS payload", ex);
+ }
+ }
+
+ public static byte[] sha256Bytes(String value) {
+ try {
+ MessageDigest digest = MessageDigest.getInstance("SHA-256");
+ return digest.digest(value.getBytes(StandardCharsets.UTF_8));
+ } catch (GeneralSecurityException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ public static String hmacSha256Hex(String value, String secret) {
+ try {
+ Mac mac = Mac.getInstance("HmacSHA256");
+ mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
+ return toHex(mac.doFinal(value.getBytes(StandardCharsets.UTF_8)));
+ } catch (GeneralSecurityException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ public static String md5Hex(String value) {
+ try {
+ MessageDigest digest = MessageDigest.getInstance("MD5");
+ return toHex(digest.digest(value.getBytes(StandardCharsets.UTF_8)));
+ } catch (GeneralSecurityException ex) {
+ throw new IllegalStateException(ex);
+ }
+ }
+
+ public static String toHex(byte[] bytes) {
+ StringBuilder builder = new StringBuilder(bytes.length * 2);
+ for (byte value : bytes) {
+ builder.append(String.format("%02x", value));
+ }
+ return builder.toString();
+ }
+
+ public static byte[] fromHex(String hex) {
+ String normalized = hex == null ? "" : hex.trim();
+ if (normalized.length() % 2 != 0) {
+ throw new IllegalArgumentException("Invalid hex string");
+ }
+ byte[] bytes = new byte[normalized.length() / 2];
+ for (int i = 0; i < normalized.length(); i += 2) {
+ bytes[i / 2] = (byte) Integer.parseInt(normalized.substring(i, i + 2), 16);
+ }
+ return bytes;
+ }
+
+ private static boolean startsWithSalted(byte[] bytes) {
+ for (int i = 0; i < SALTED.length; i++) {
+ if (bytes[i] != SALTED[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static KeyAndIv evpBytesToKey(byte[] password, byte[] salt, int keyLength, int ivLength)
+ throws GeneralSecurityException {
+ MessageDigest md5 = MessageDigest.getInstance("MD5");
+ byte[] derived = new byte[0];
+ byte[] block = new byte[0];
+
+ while (derived.length < keyLength + ivLength) {
+ md5.reset();
+ md5.update(block);
+ md5.update(password);
+ if (salt != null) {
+ md5.update(salt, 0, 8);
+ }
+ block = md5.digest();
+ byte[] next = new byte[derived.length + block.length];
+ System.arraycopy(derived, 0, next, 0, derived.length);
+ System.arraycopy(block, 0, next, derived.length, block.length);
+ derived = next;
+ }
+
+ return new KeyAndIv(
+ Arrays.copyOfRange(derived, 0, keyLength),
+ Arrays.copyOfRange(derived, keyLength, keyLength + ivLength)
+ );
+ }
+
+ private static final class KeyAndIv {
+ private final byte[] key;
+ private final byte[] iv;
+
+ private KeyAndIv(byte[] key, byte[] iv) {
+ this.key = key;
+ this.iv = iv;
+ }
+ }
+}
diff --git a/JS-hook/src/main/java/com/myapp/jshook/JsHookController.java b/JS-hook/src/main/java/com/myapp/jshook/JsHookController.java
new file mode 100644
index 0000000..d1be532
--- /dev/null
+++ b/JS-hook/src/main/java/com/myapp/jshook/JsHookController.java
@@ -0,0 +1,770 @@
+package com.myapp.jshook;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.myapp.jshook.proto.api.ApiRequest;
+import com.myapp.jshook.proto.api.ApiResponse;
+import com.myapp.jshook.proto.api.OrderInfo;
+import com.myapp.jshook.proto.api.ProductInfo;
+import com.myapp.jshook.proto.api.UserInfo;
+import com.myapp.jshook.proto.microservice.AnalyticsResponse;
+import com.myapp.jshook.proto.microservice.NotificationResponse;
+import com.myapp.jshook.proto.microservice.OrderResponse;
+import com.myapp.jshook.proto.microservice.ServiceRequest;
+import com.myapp.jshook.proto.microservice.ServiceResponse;
+import com.myapp.jshook.proto.microservice.UserResponse;
+import com.myapp.jshook.proto.report.ChartData;
+import com.myapp.jshook.proto.report.DataPoint;
+import com.myapp.jshook.proto.report.DataResponse;
+import com.myapp.jshook.proto.report.ReportData;
+import java.nio.charset.StandardCharsets;
+import java.security.SecureRandom;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.stream.Collectors;
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class JsHookController {
+ private static final ObjectMapper MAPPER = new ObjectMapper();
+ private static final SecureRandom RANDOM = new SecureRandom();
+
+ @GetMapping("/api/items")
+ public ResponseEntity> items(@RequestParam("sign") String sign) {
+ String expected = CryptoJsCompat.hmacSha256Hex("/api/items", "my-secret-key");
+ if (!expected.equals(sign)) {
+ return ResponseEntity.status(HttpStatus.FORBIDDEN)
+ .body(error("Invalid sign", "expected", expected, "received", sign));
+ }
+ return ResponseEntity.ok(mapOf(
+ "items", Arrays.asList(item(1, "Item 1"), item(2, "Item 2"), item(3, "Item 3"))
+ ));
+ }
+
+ @GetMapping("/api/search-products")
+ public ResponseEntity> searchProducts(@RequestParam("q") String encryptedQuery) {
+ try {
+ String decrypted = CryptoJsCompat.decrypt(encryptedQuery, "query-encrypt-key-2025");
+ Map params = MAPPER.readValue(decrypted, new TypeReference