assets-obfuscator.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. const fs = require('fs');
  2. const path = require('path');
  3. const setting = require('./build-setting');
  4. const utils = require('./libs/utils');
  5. module.exports = (function (){
  6. var _instance;
  7. function AssetsCompress (params) {
  8. return {
  9. _ready: false,
  10. _map: {},
  11. _oldMap: null,
  12. _currDir: null,
  13. _dirPath: null,
  14. _tempDirMap: {},
  15. init (actualPlatform) {
  16. this._ready = false;
  17. this._map = {};
  18. this._currDir = null;
  19. this._dirPath = null;
  20. this._tempDirMap = {};
  21. this._actualPlatform = actualPlatform;
  22. let assetsObfuscator = `assetsObfuscator`;
  23. let obfuscator = setting.getInstance().getItem(assetsObfuscator);
  24. if (!obfuscator) { Editor.warn('缺少配置,跳过资源混淆!'); return false; }
  25. if (!obfuscator.enable) { Editor.warn('未开启资源混淆!'); return false; }
  26. let pwd = obfuscator.pwd;
  27. if (!pwd || pwd.length == 0) {
  28. this._oldMap = null;
  29. Editor.warn('混淆密码为空!');
  30. return false;
  31. }
  32. let pwdLen = pwd.length;
  33. let keys = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
  34. if (pwdLen !== keys.length) {
  35. this._oldMap = null;
  36. Editor.warn(`混淆密码长度为16位,是从 0123456789abcdef 中产生的乱序`);
  37. return false;
  38. }
  39. for (let i = 0; i < pwdLen; i++) {
  40. let key = keys[i];
  41. this._map[key] = pwd[i];
  42. }
  43. this._ready = true;
  44. return true;
  45. },
  46. isReady () {
  47. return this._ready;
  48. },
  49. getMima () {
  50. return this._map;
  51. },
  52. modifyDecodeUuidFile () {
  53. // 写文件前先删除缓存文件
  54. let cache = path.join(Editor.url('unpack://engine'), 'bin/.cache', this._actualPlatform);
  55. if (fs.existsSync(cache)) {
  56. utils.rmdirSync(cache);
  57. }
  58. // 原逻辑
  59. let mapTxt = '';
  60. let base64 = `if (base64.length !== 22) {
  61. return base64;
  62. }`;
  63. let ele = '';
  64. // 如果加密了,将原逻辑改成解密逻辑
  65. if (Object.keys(this._map).length > 0) {
  66. this._oldMap = this._map;
  67. mapTxt = `
  68. var mima = ${JSON.stringify(this._map)};
  69. `;
  70. base64 = `if (22 !== base64.length) {
  71. if (base64.indexOf("/") !== -1) {
  72. return base64;
  73. }
  74. var array = new Array(base64.length);
  75. for (var index = 0; index < array.length; index++) {
  76. var item = base64.charAt(index);
  77. array[index] = mima[item];
  78. }
  79. base64 = array.join("");
  80. return base64;
  81. }`;
  82. ele = `
  83. for (let index = 0; index < UuidTemplate.length; index++) {
  84. let element = UuidTemplate[index];
  85. if (element !== '-') {
  86. UuidTemplate[index] = mima[UuidTemplate[index]];
  87. }
  88. }`;
  89. }
  90. // 将上面的逻辑写入文件
  91. let filePath = path.join(Editor.url('unpack://engine'), 'cocos2d/core/utils/decode-uuid.js');
  92. if (fs.existsSync(filePath)) {
  93. try {
  94. var newStr = `
  95. /****************************************************************************
  96. Copyright (c) 2013-2016 Chukong Technologies Inc.
  97. Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
  98. https://www.cocos.com/
  99. Permission is hereby granted, free of charge, to any person obtaining a copy
  100. of this software and associated engine source code (the "Software"), a limited,
  101. worldwide, royalty-free, non-assignable, revocable and non-exclusive license
  102. to use Cocos Creator solely to develop games on your target platforms. You shall
  103. not use Cocos Creator software for developing other software or tools that's
  104. used for developing games. You are not granted to publish, distribute,
  105. sublicense, and/or sell copies of Cocos Creator.
  106. The software or tools in this License Agreement are licensed, not sold.
  107. Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
  108. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  109. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  110. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  111. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  112. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  113. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  114. THE SOFTWARE.
  115. ****************************************************************************/
  116. var Base64Values = require('./misc').BASE64_VALUES;
  117. var HexChars = '0123456789abcdef'.split('');
  118. var _t = ['', '', '', ''];
  119. var UuidTemplate = _t.concat(_t, '-', _t, '-', _t, '-', _t, '-', _t, _t, _t);
  120. var Indices = UuidTemplate.map(function (x, i) { return x === '-' ? NaN : i; }).filter(isFinite);
  121. ${mapTxt}
  122. // fcmR3XADNLgJ1ByKhqcC5Z -> fc991dd7-0033-4b80-9d41-c8a86a702e59
  123. module.exports = function (base64) {
  124. ${base64}
  125. UuidTemplate[0] = base64[0];
  126. UuidTemplate[1] = base64[1];
  127. for (var i = 2, j = 2; i < 22; i += 2) {
  128. var lhs = Base64Values[base64.charCodeAt(i)];
  129. var rhs = Base64Values[base64.charCodeAt(i + 1)];
  130. UuidTemplate[Indices[j++]] = HexChars[lhs >> 2];
  131. UuidTemplate[Indices[j++]] = HexChars[((lhs & 3) << 2) | rhs >> 4];
  132. UuidTemplate[Indices[j++]] = HexChars[rhs & 0xF];
  133. }
  134. ${ele}
  135. return UuidTemplate.join('');
  136. };
  137. if (CC_TEST) {
  138. cc._Test.decodeUuid = module.exports;
  139. }
  140. `;
  141. fs.writeFileSync(filePath, newStr);
  142. Editor.log('混淆逻辑写入' + filePath + '成功');
  143. } catch (error) {
  144. Editor.error('混淆逻辑写入' + filePath + '失败');
  145. }
  146. } else {
  147. Editor.error('读取' + filePath + '失败');
  148. }
  149. },
  150. modifyResUuid (buildDest, cb) {
  151. let importFolder = path.join(buildDest, 'res/import');
  152. let rawAssetsFolder = path.join(buildDest, 'res/raw-assets');
  153. if (!fs.existsSync(importFolder)) {
  154. Editor.warn(`${importFolder}文件夹不存在`);
  155. return;
  156. }
  157. if (!fs.existsSync(rawAssetsFolder)) {
  158. Editor.warn(`${rawAssetsFolder}文件夹不存在`);
  159. return;
  160. }
  161. this.syncFindFile(importFolder, 'import');
  162. this.syncFindFile(rawAssetsFolder, 'raw-assets');
  163. for (const temPath in this._tempDirMap) {
  164. const newPath = this._tempDirMap[temPath];
  165. fs.renameSync(temPath, newPath);
  166. }
  167. },
  168. getNewName (mima, oldName) {
  169. let mimaLen = Object.keys(mima).length;
  170. if (mimaLen <= 0) {
  171. Editor.warn('没有混淆密码');
  172. return;
  173. }
  174. if (oldName.length <= 0) {
  175. Editor.warn('混淆名称为空');
  176. return;
  177. }
  178. let name;
  179. let ext;
  180. let idx = oldName.lastIndexOf('.');
  181. if (idx !== -1) {
  182. name = oldName.substr(0, idx);
  183. ext = oldName.substr(idx);
  184. } else {
  185. name = oldName;
  186. ext = '';
  187. }
  188. let newName = '';
  189. for (let i = 0; i < name.length; i++) {
  190. const c = name[i];
  191. newName += mima[c] || c;
  192. }
  193. newName += ext;
  194. return newName;
  195. },
  196. syncFindFile (filePath, flag) {
  197. let total = 0;
  198. let dirs = fs.readdirSync(filePath);
  199. dirs.forEach((ele, index) => {
  200. let needRename = true;
  201. let fullpath = path.join(filePath, ele);
  202. let info = fs.statSync(fullpath);
  203. if (info.isDirectory() && ele.length == 2) {
  204. needRename = false;
  205. this._dirName = ele;
  206. this._dirPath = fullpath;
  207. this.syncFindFile(fullpath, flag);
  208. }
  209. if (needRename) {
  210. let newName = this.getNewName(this._map, ele);
  211. let newPath = path.join(fullpath.substr(0, fullpath.lastIndexOf('/')), newName);
  212. fs.renameSync(fullpath, newPath);
  213. ++total;
  214. if (total === dirs.length && this._dirPath && this._dirName) {
  215. let newDirName = this.getNewName(this._map, this._dirName);
  216. let newDirPath = path.join(this._dirPath.substr(0, this._dirPath.lastIndexOf('/')), newDirName);
  217. let newDirPathTemp = newDirPath + '_' + flag;
  218. fs.renameSync(this._dirPath, newDirPathTemp);
  219. this._tempDirMap[newDirPathTemp] = newDirPath;
  220. }
  221. }
  222. });
  223. }
  224. };
  225. }
  226. return {
  227. getInstance (params) {
  228. if (!_instance){
  229. _instance = AssetsCompress(params);
  230. }
  231. return _instance;
  232. }
  233. };
  234. })();