"use strict"; window.packageRoot = "packages://encrypt-tool/"; var Fs = require('fs'); var Path = require('path'); const jpgBufferHeader = { bufBegin: [0xff, 0xd8], bufEnd: [0xff, 0xd9], suffix: '.jpg' }; const pngBufferHeader = { bufBegin: [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a], bufEnd: [0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82], suffix: '.png' }; //暂时没用,存着备用 const imageBufferHeaders = [{ bufBegin: [0x00, 0x00, 0x02, 0x00, 0x00], suffix: '.tga' }, { bufBegin: [0x00, 0x00, 0x10, 0x00, 0x00], suffix: '.rle' }, { bufBegin: [0x47, 0x49, 0x46, 0x38, 0x39, 0x61], suffix: '.gif' }, { bufBegin: [0x47, 0x49, 0x46, 0x38, 0x37, 0x61], suffix: '.gif' }, { bufBegin: [0x42, 0x4d], suffix: '.bmp' }, { bufBegin: [0x0a], suffix: '.pcx' }, { bufBegin: [0x49, 0x49], suffix: '.tif' }, { bufBegin: [0x4d, 0x4d], suffix: '.tif' }, { bufBegin: [0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x20, 0x20], suffix: '.ico' }, { bufBegin: [0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x20, 0x20], suffix: '.cur' }, { bufBegin: [0x46, 0x4f, 0x52, 0x4d], suffix: '.iff' }, { bufBegin: [0x52, 0x49, 0x46, 0x46], suffix: '.ani' }] Editor.Panel.extend({ style:` h2 { color: #f90; font-size: 15px; width: 200px; text-align: left } .middle { width: 200px; margin-left: 100px; align-items: center; } .inputstyle { width: 200px } .okstyle { margin-top: 50px; width: 100px; margin-left: 100px; }`, template:`

请输入签名:

请输入密码:

请选择构项目建模板:

加密

日志:

`, $:{ logTextArea: "#logTextArea", }, ready() { let logarea = this.$logTextArea; window.plugin = new window.Vue({ el: this.shadowRoot, created: function() { this.initPluginCfg(); }, init: function() { }, data: { logView: "", //默认的是这个 signKey: "civiTool", passWord: "civiTool2020", engineVersion:"", rootPath: "", cfgPath: "", totalPng: [], hasEncrypt: 0, hasBuildProj: false, isNewVersion:false, buildTypeSelect:0, }, computed: {}, methods: { stringToHex(str) { if (str === "")     return "";   var hexCharCode = [];   for (var i = 0; i < str.length; i++) { hexCharCode.push((str.charCodeAt(i)));   }   return hexCharCode; }, checkPngSig(fileBuffer) { let isEqual = false // 判断标识头前缀 if (pngBufferHeader.bufBegin) { const buf = Buffer.from(pngBufferHeader.bufBegin); isEqual = buf.equals(fileBuffer.slice(0, pngBufferHeader.bufBegin.length)); } // 判断标识头后缀 if (isEqual && pngBufferHeader.bufEnd) { const buf = Buffer.from(pngBufferHeader.bufEnd); isEqual = buf.equals(fileBuffer.slice(-pngBufferHeader.bufEnd.length)); } if (isEqual) { return pngBufferHeader.suffix; } return '' }, walk(path) { var isPNG = function(pathStr) { let extname = Path.extname(pathStr); if (extname == ".png" || extname == ".PNG") { let buf = Fs.readFileSync(pathStr); let sig = this.checkPngSig(buf); if (sig == ".png") { return true; }; } else { return false; } }.bind(this); //先取出文件夹 var dirList = Fs.readdirSync(path); //遍历文件夹 dirList.forEach(function(item) { //判断是不是文件夹 if (Fs.statSync(path + '/' + item).isDirectory()) { if (this.isNewVersion) { if (item == "internal" ) { //默认的不管pass }else{ this.walk(path + '/' + item); } }else{ this.walk(path + '/' + item); } } else { //判断是不是PNG图片 if (isPNG(path + '/' + item)) { //进行加密 this.totalPng.push(path + '/' + item); } else { // pass } } }.bind(this)); }, onDoEncrypt() { if (this.hasBuildProj) { this.addLog("请不要重复点击"); return; }; Editor.log("encrypt tool init") this.logView = ""; this.hasEncrypt = 0; this.totalPng = []; this.hasBuildProj = true; let target = this.getBuildTips(); if (Fs.existsSync(this.rootPath + "/build/"+target)) { let imgh = this.rootPath + "/build/jsb-default/frameworks/cocos2d-x/cocos/platform/CCImage.h"; let imgcpp = this.rootPath + "/build/jsb-default/frameworks/cocos2d-x/cocos/platform/CCImage.cpp"; if (this.buildTypeSelect == 0) { let simulatorP = Editor.url('unpack://simulator', 'utf8'); let Cpath = Path.resolve(simulatorP, '..'); imgh = Cpath + "/cocos/platform/CCImage.h"; imgcpp = Cpath + "/cocos/platform/CCImage.cpp"; this.addLog("img.h:" + imgh); this.addLog("img.cpp:" + imgcpp); }; let buf = Fs.readFileSync(imgh, "UTF-8"); let tmp = buf.split("//civi encrypt,don't delete//"); if (tmp.length < 2) { this.addLog("CCImage尚未添加代码,准备添加代码"); let finalRes = this.addEncryptScriptHeader(buf); Fs.writeFileSync(imgh, finalRes); let cppbuf = Fs.readFileSync(imgcpp, "UTF-8"); let finalSres = this.addEncryptScript(cppbuf); Fs.writeFileSync(imgcpp, finalSres); this.addLog("CCImage添加代码完成"); } else { this.addLog("CCImage已经添加代码"); this.addLog("更新签名及密码"); let cppbuf = Fs.readFileSync(imgcpp, "UTF-8"); let changeBuf = this.changeEncryptSignPass(cppbuf); Fs.writeFileSync(imgcpp, changeBuf); } } else { Editor.log("项目还未构建,请先构建"+target+"项目"); this.addLog("项目还未构建,请先构建"+target+"项目"); this.hasBuildProj = false return; } this.saveCfg(); this.addLog("开始加密...请耐心等待"); if (this.isNewVersion) { this.walk(this.rootPath + "/build/"+target+"/assets"); }else{ //this.walk(this.rootPath + "/build/"+target+"/res/raw-assets"); this.walk(this.rootPath + "/library"); } this.addLog("共检测到" + this.totalPng.length + "张需要加密的png"); for (var i = 0; i < this.totalPng.length; i++) { let pathStr = this.totalPng[i]; this.beginEncrypt(pathStr); }; }, beginEncrypt(pathStr) { let buf = Fs.readFileSync(pathStr); let newData = this.encryptPng(buf); Fs.writeFile(pathStr, newData,function(error) { this.addLog(pathStr + "加密完成"); this.hasEncrypt = this.hasEncrypt + 1; if (this.hasEncrypt == this.totalPng.length) { this.addLog("全部加密完成"); Editor.log("png资源加密完成"); this.hasBuildProj = false; }; }.bind(this)); }, onBuildTypeChange(e) { let t = e.target.value; this.checkBuildDir(); }, encryptPng(fileBuffer) { //预处理,先切头,再去尾 let cutHeader = fileBuffer.slice(pngBufferHeader.bufBegin.length); let iendData = cutHeader.slice( - pngBufferHeader.bufEnd.length); let lastData; const buf = Buffer.from(pngBufferHeader.bufEnd); if (buf.equals(iendData)) { lastData = cutHeader.slice(0, -pngBufferHeader.bufEnd.length); } else { lastData = cutHeader; } let k = this.stringToHex(this.passWord); let klen = k.length; let kindex = 0; for (var i = 0; i < lastData.length; i++) { if (kindex >= klen) { kindex = 0; }; lastData[i] = lastData[i] ^ k[kindex]; kindex = kindex + 1; }; let sign = new Buffer(this.signKey); let finalData = Buffer.concat([sign, lastData]); return finalData; }, addLog(t) { let i = new Date; this.logView += "[" + i.toLocaleString() + "]: " + t + "\n", setTimeout(function() { logarea.scrollTop = logarea.scrollHeight; },10) }, versionCompareHandle(versionA, versionB) { var vA = versionA.split('.'); var vB = versionB.split('.'); for (var i = 0; i < vA.length; ++i) { var a = parseInt(vA[i]); var b = parseInt(vB[i] || 0); if (a === b) { continue; } else { return a - b; } } if (vB.length > vA.length) { return -1; } else { return 0; } }, initPluginCfg() { let e = Editor.libraryPath; this.rootPath = e.substring(0, e.length - 7); this.cfgPath = this.rootPath + "/packages/encrypt-tool/cfg.json"; this.addLog("项目路径为" + e.substring(0, e.length - 7)); this.readCfg(); this.checkBuildDir(); }, checkBuildDir() { let target = this.getBuildTips() this.addLog("当前加密目标模板为"+target+",即"+target+"目录下的png将被加密"); if (Fs.existsSync(this.rootPath + "/build/"+target)) { let projCfg = this.rootPath + "/build/"+target+"/.cocos-project.json"; let buf = Fs.readFileSync(projCfg,"UTF-8"); let cfg = JSON.parse(buf); this.engineVersion = cfg.engine_version; this.addLog("当前引擎版本为" + this.engineVersion); let ret = this.versionCompareHandle(this.engineVersion,"2.4.0"); if (ret >= 0) { this.isNewVersion = true; }; }else{ Editor.log("项目还未构建,请先构建"+target+"项目"); this.addLog("项目还未构建,请先构建"+target+"项目"); } }, saveCfg() { let newData = this.signKey + "civiEncrypt" + this.passWord + "civiEncrypt"+this.buildTypeSelect; Fs.writeFile(this.cfgPath, newData,function(error) { }); }, readCfg() { if (Fs.existsSync(this.cfgPath)) { let st = Fs.readFileSync(this.cfgPath, "UTF-8"); let signData = st.split("civiEncrypt"); if (signData.length > 1) { this.signKey = signData[0]; this.passWord = signData[1]; if (signData.length > 2) { this.buildTypeSelect = signData[2]; }; this.addLog("上次签名为" + this.signKey); this.addLog("上次密码为" + this.passWord); }; } else { this.addLog("未检测到历史配置"); } }, getBuildTips() { if(this.buildTypeSelect== 1) { return "jsb-default"; } return "jsb-link"; }, addEncryptScriptHeader(buf) { let splitStr = "PNG,"; let addEnum = buf.split(splitStr); if (addEnum.length == 2) { buf = addEnum[0] + splitStr + "\n\ //civi encrypt,don't delete//\n\ ENCRYPTEDPNG, //加密后的Png图片\n\ //civi encrypt,don't delete//" + addEnum[1]; }; let splitStr1 = "bool initWithImageFile(const std::string& path);"; let tmp1 = buf.split(splitStr1); if (tmp1.length == 2) { buf = tmp1[0] + splitStr1 + "\n\ //civi encrypt,don't delete//\n\ void deEncryptPng(unsigned char **copyData, const char *key, ssize_t dataLen);\n\ //civi encrypt,don't delete//" + tmp1[1]; }; let splitStr2 = "std::string _filePath;"; let tmp2 = buf.split(splitStr2); if (tmp2.length == 2) { buf = tmp2[0] + splitStr2 + "\n\ //civi encrypt signPass,don't delete//\n\ std::string _signKey;\n\ std::string _passWord;\n\ //civi encrypt signPass,don't delete//" + tmp2[1]; }; let splitStr3 = "bool isEtc(const unsigned char * data, ssize_t dataLen);"; let tmp3 = buf.split(splitStr3); if (tmp3.length == 2) { buf = tmp3[0] + splitStr3 + "\n\ //civi encrypt,don't delete//\n\ bool isEncryptedPng(const unsigned char * data,ssize_t dataLen);\n\ //civi encrypt,don't delete//" + tmp3[1]; }; return buf; }, addEncryptScript(buf) { let splitStr3 = ", _hasPremultipliedAlpha(false)"; let addSignPass = buf.split(splitStr3); if (addSignPass.length == 2) { buf = addSignPass[0] + splitStr3 + "//civi encrypt signPass,don't delete//\n\ ,_signKey(\"" + this.signKey + "\")\n\ ,_passWord(\"" + this.passWord + "\")\n\ //civi encrypt signPass,don't delete//" + addSignPass[1]; }; let splitStr4 = "NS_CC_END"; let addEnum = buf.split(splitStr4); if (addEnum.length == 2) { buf = addEnum[0] + "//civi encrypt,don't delete//\n\ void Image::deEncryptPng(unsigned char **copyData, const char *key, ssize_t dataLen)\ {\n\ static const unsigned char PNG_SIGNATURE[] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };\n\ static const unsigned char PNG_IEND[] = { 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 };\n\ unsigned char* data = *copyData;\n\ memcpy(data, PNG_SIGNATURE, 8);\n\ memcpy(data + (dataLen - 12), PNG_IEND, 12);\n\ unsigned char* destart = data + 8;\n\ unsigned char* de_end = data + dataLen - 13;\n\ ssize_t keyLen = strlen(key);\n\ ssize_t keyIndex = 0;\n\ for(; destart <= de_end; destart++, keyIndex++)\ {\n\ if (keyIndex >= keyLen)\n\ keyIndex = 0;\n\ *destart ^= key[keyIndex];\n\ }\n\ }\n\ bool Image::isEncryptedPng(const unsigned char *data, ssize_t dataLen)\n\ {\n\ if (dataLen > 8 && memcmp(\"wckj8888\", data, 8) == 0)\ {\n\ _signKey = \"wckj8888\";\n\ }\ if (dataLen <= _signKey.length() || memcmp(_signKey.c_str(), data, _signKey.length()) != 0)\ {\n\ return false;\n\ }\n\ return true;\n\ }\n\ //civi encrypt,don't delete//\n" + splitStr4; }; let splitStr1 = "else if (isJpg(data, dataLen))"; let tmp1 = buf.split(splitStr1); if (tmp1.length == 2) { buf = tmp1[0] + "//civi encrypt,don't delete//\n\ else if (isEncryptedPng(data, dataLen))\ {\n\ return Format::ENCRYPTEDPNG;\n\ }\n\ //civi encrypt,don't delete//\n " + splitStr1 + tmp1[1]; }; let splitStr2 = "case Format::PNG:"; let tmp2 = buf.split(splitStr2); if (tmp2.length == 2) { buf = tmp2[0] + "//civi encrypt,don't delete//\n\ case Format::ENCRYPTEDPNG:\n\ {\n\ unsigned char* copyData = new unsigned char[unpackedLen + 20-_signKey.length()];\ // 头部信息固定8 + 尾部信息固定12 - 插入密钥的长度\n\ memcpy(copyData + 8, unpackedData + _signKey.length(), unpackedLen - _signKey.length());\n\ deEncryptPng(©Data, _passWord.c_str(), unpackedLen + 20-_signKey.length());\n\ ret = initWithPngData(copyData, unpackedLen + 20-_signKey.length());\n\ delete [] copyData;\n\ }\n\ break;\n\ //civi encrypt,don't delete//\n " + splitStr2 + tmp2[1]; }; return buf; }, changeEncryptSignPass(buf) { let splitStr2 = "//civi encrypt signPass,don't delete//"; let tmp2 = buf.split(splitStr2); if (tmp2.length == 3) { buf = tmp2[0] + splitStr2 + "\n\ ,_signKey(\"" + this.signKey + "\")\n\ ,_passWord(\"" + this.passWord + "\")\n\ //civi encrypt signPass,don't delete//" + tmp2[2]; } return buf; }, onBuildFinished(t) { } } }) }, messages: { "encrypt-tool:onBuildFinished":function(e, t) { } }, });