ee-core 1.3.3 → 1.3.4-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,92 @@
1
+ const { BrowserWindow } = require('electron');
2
+
3
+ /**
4
+ * 窗口插件
5
+ * @class
6
+ */
7
+ class WinAddon {
8
+
9
+ constructor(app) {
10
+ this.app = app;
11
+ this.windowContentsIdMap = {};
12
+ }
13
+
14
+ /**
15
+ * create window
16
+ *
17
+ * @function
18
+ * @since 1.0.0
19
+ */
20
+ create(name, opt) {
21
+ const options = Object.assign({
22
+ x: 10,
23
+ y: 10,
24
+ width: 980,
25
+ height: 650,
26
+ webPreferences: {
27
+ contextIsolation: false,
28
+ nodeIntegration: true,
29
+ },
30
+ }, opt);
31
+ const win = new BrowserWindow(options)
32
+
33
+ const winContentsId = win.webContents.id;
34
+ win.webContents.on('did-finish-load', () => {
35
+ this.registerWCid(name, winContentsId);
36
+ })
37
+
38
+ win.webContents.on('destroyed', () => {
39
+ this.removeWCid(name);
40
+ })
41
+
42
+ win.webContents.on('render-process-gone', (event, details) => {
43
+ this.removeWCid(name);
44
+ })
45
+
46
+ return win;
47
+ }
48
+
49
+ /**
50
+ * 获取窗口Contents id
51
+ *
52
+ * @function
53
+ * @since 1.0.0
54
+ */
55
+ getWCid(name) {
56
+ const id = this.windowContentsIdMap[name] || null;
57
+ return id;
58
+ }
59
+
60
+ /**
61
+ * 获取主窗口Contents id
62
+ *
63
+ * @function
64
+ * @since 1.0.0
65
+ */
66
+ getMWCid() {
67
+ const id = this.windowContentsIdMap['main'] || null;
68
+ return id;
69
+ }
70
+
71
+ /**
72
+ * 注册窗口Contents id
73
+ *
74
+ * @function
75
+ * @since 1.0.0
76
+ */
77
+ registerWCid (name, id) {
78
+ this.windowContentsIdMap[name] = id;
79
+ }
80
+
81
+ /**
82
+ * 销毁窗口Contents id
83
+ *
84
+ * @function
85
+ * @since 1.0.0
86
+ */
87
+ removeWCid (name) {
88
+ delete this.windowContentsIdMap[name];
89
+ }
90
+ }
91
+
92
+ module.exports = WinAddon;
package/bin/tools.js CHANGED
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const codeCompress = require('../tools/codeCompress');
4
3
  const replaceDist = require('../tools/replaceDist');
5
4
  const encrypt = require('../tools/encrypt');
6
5
 
@@ -14,14 +13,6 @@ if (cmd == 'rd') {
14
13
  replaceDist.run();
15
14
  }
16
15
 
17
- if (cmd == 'compress') {
18
- codeCompress.compress();
19
- }
20
-
21
- if (cmd == 'restore') {
22
- codeCompress.restore();
23
- }
24
-
25
16
  if (cmd == 'encrypt') {
26
17
  encrypt.run();
27
18
  }
@@ -261,7 +261,16 @@ module.exports = appInfo => {
261
261
  /**
262
262
  * loading页(废弃)
263
263
  */
264
- config.loadingPage = false;
264
+ config.loadingPage = false;
265
+
266
+ /**
267
+ * addons
268
+ */
269
+ config.addons = {
270
+ window: {
271
+ enable: true,
272
+ }
273
+ };
265
274
 
266
275
  return config;
267
276
  };
package/core/lib/ee.js CHANGED
@@ -157,6 +157,15 @@ class EeCore extends KoaApplication {
157
157
  return this.loader ? this.loader.config : {};
158
158
  }
159
159
 
160
+ /**
161
+ * The addon of application
162
+ * @member {Addon}
163
+ * @since 1.0.0
164
+ */
165
+ get addon() {
166
+ return this.loader ? this.loader.addon : {};
167
+ }
168
+
160
169
  get [EE_LOADER]() {
161
170
  return require('./loader/ee_loader');
162
171
  }
@@ -373,10 +373,16 @@ class EeLoader {
373
373
  directory,
374
374
  property,
375
375
  inject: this.app,
376
+ loader: this
376
377
  }, opt);
377
378
  const timingKey = `Load "${String(property)}" to Context`;
378
379
  this.timing.start(timingKey);
379
- new ContextLoader(opt).load();
380
+ if (['addon'].includes(property)) {
381
+ new ContextLoader(opt).loadAddons();
382
+ } else {
383
+ new ContextLoader(opt).load();
384
+ }
385
+
380
386
  this.timing.end(timingKey);
381
387
  }
382
388
 
@@ -441,6 +447,7 @@ const loaders = [
441
447
  require('./mixin/config'),
442
448
  require('./mixin/service'),
443
449
  require('./mixin/controller'),
450
+ require('./mixin/addon'),
444
451
  ];
445
452
 
446
453
  for (const loader of loaders) {
@@ -23,6 +23,7 @@ const defaults = {
23
23
  override: false,
24
24
  inject: undefined,
25
25
  filter: null,
26
+ loader: undefined,
26
27
  };
27
28
 
28
29
  /**
@@ -44,6 +45,7 @@ class FileLoader {
44
45
  * @param {Object} options.inject - an object that be the argument when invoke the function
45
46
  * @param {Function} options.filter - a function that filter the exports which can be loaded
46
47
  * @param {String|Function} options.caseStyle - set property's case when converting a filepath to property list.
48
+ * @param {Object} options.loader - an object that be the argument when invoke the function
47
49
  */
48
50
  constructor(options) {
49
51
  assert(options.directory, 'options.directory is required');
@@ -175,6 +177,68 @@ class FileLoader {
175
177
  return items;
176
178
  }
177
179
 
180
+ /**
181
+ * attach items to target object for addons.
182
+ * `app/addon/group/index.js` => `target.group`
183
+ * @return {Object} target
184
+ * @since 1.0.0
185
+ */
186
+ loadAddons() {
187
+ const items = [];
188
+ const files = '*';
189
+ const app = this.options.inject;
190
+ const loader = this.options.loader;
191
+ const target = this.options.target;
192
+ let directories = this.options.directory;
193
+
194
+ if (!Array.isArray(directories)) {
195
+ directories = [ directories ];
196
+ }
197
+
198
+ // check addon
199
+ const config = app.config.addons;
200
+ let filterAddons = [];
201
+ for (let key of Object.keys(config)) {
202
+ if (!config[key].enable) {
203
+ filterAddons.push(key);
204
+ }
205
+ }
206
+
207
+ for (const directory of directories) {
208
+ const addonpaths = globby.sync(files, { cwd: directory, deep: 1, onlyDirectories: true});
209
+ for (const addonName of addonpaths) {
210
+ if (filterAddons.includes(addonName)) continue;
211
+
212
+ let fullpath = path.join(directory, addonName, 'index');
213
+ fullpath = loader.resolveModule(fullpath);
214
+ if (!fs.statSync(fullpath).isFile()) continue;
215
+
216
+ let exports = getExports(fullpath, this.options, addonName);
217
+ if (exports == null) continue;
218
+
219
+ const properties = [addonName];
220
+ if (is.class(exports) || utils.isBytecodeClass(exports)) {
221
+ exports.prototype.pathName = addonName;
222
+ exports.prototype.fullPath = fullpath;
223
+ }
224
+
225
+ items.push({ fullpath, properties, exports });
226
+ }
227
+
228
+ for (const item of items) {
229
+ const property = item.properties[0];
230
+ let obj = item.exports;
231
+ if (obj && !is.primitive(obj)) {
232
+ obj[FULLPATH] = item.fullpath;
233
+ obj[EXPORTS] = true;
234
+ }
235
+
236
+ target[property] = obj;
237
+ }
238
+ }
239
+
240
+ return target;
241
+ }
178
242
  }
179
243
 
180
244
  module.exports = FileLoader;
@@ -0,0 +1,32 @@
1
+ const path = require('path');
2
+
3
+ module.exports = {
4
+
5
+ /**
6
+ * Load app/addon
7
+ * @param {Object} opt - LoaderOptions
8
+ * @function
9
+ * @since 1.0.0
10
+ */
11
+ loadAddon(opt) {
12
+ this.timing.start('Load Addon');
13
+
14
+ // 加载ee-core的插件 和 用户插件
15
+ const directorys = [
16
+ path.join(this.options.framework, 'addon'),
17
+ path.join(this.options.baseDir, 'addon'),
18
+ ]
19
+ opt = Object.assign({
20
+ call: true,
21
+ caseStyle: 'lower',
22
+ directory: directorys
23
+ }, opt);
24
+
25
+ const addonPaths = opt.directory;
26
+ this.loadToContext(addonPaths, 'addon', opt);
27
+
28
+ this.timing.end('Load Addon');
29
+ },
30
+ };
31
+
32
+
@@ -2,7 +2,6 @@
2
2
 
3
3
  const path = require('path');
4
4
 
5
-
6
5
  module.exports = {
7
6
 
8
7
  /**
@@ -104,6 +104,18 @@ module.exports = {
104
104
 
105
105
  return isClass;
106
106
  },
107
+
108
+ /**
109
+ * 文件类型
110
+ */
111
+ filePatterns () {
112
+ const files = (process.env.EE_TYPESCRIPT === 'true' && Module._extensions['.ts'])
113
+ ? [ '**/*.(js|ts)', '!**/*.d.ts' ]
114
+ : [ '**/*.js','**/*.jsc' ];
115
+
116
+ return files;
117
+ }
118
+
107
119
  };
108
120
 
109
121
 
package/lib/appLoader.js CHANGED
@@ -30,6 +30,14 @@ class AppLoader extends EeLoader {
30
30
 
31
31
  }
32
32
 
33
+ /**
34
+ * load addons
35
+ * @since 1.0.0
36
+ */
37
+ loadAddons() {
38
+ this.loadAddon();
39
+ }
40
+
33
41
  /**
34
42
  * load electron modules
35
43
  * @since 1.0.0
package/lib/eeApp.js CHANGED
@@ -16,7 +16,7 @@ class EeApp extends BaseApp {
16
16
  tray: null,
17
17
  extra: {
18
18
  closeWindow: false,
19
- }
19
+ },
20
20
  };
21
21
  }
22
22
 
@@ -115,7 +115,9 @@ class EeApp extends BaseApp {
115
115
 
116
116
  await this.windowReady();
117
117
 
118
- await this.loderPreload();
118
+ await this._loderAddons();
119
+
120
+ await this._loderPreload();
119
121
 
120
122
  this.selectAppType();
121
123
 
@@ -256,10 +258,25 @@ class EeApp extends BaseApp {
256
258
  app.quit();
257
259
  }
258
260
 
261
+ /**
262
+ * 加载插件
263
+ */
264
+ async _loderAddons () {
265
+ this.loader.loadAddons();
266
+
267
+ // 注册主窗口Contents id
268
+ const addonsCfg = this.config.addons;
269
+ if (addonsCfg.window.enable) {
270
+ const win = this.electron.mainWindow;
271
+ const addonWindow = this.addon.window;
272
+ addonWindow.registerWCid('main', win.webContents.id);
273
+ }
274
+ }
275
+
259
276
  /**
260
277
  * 预加载模块
261
278
  */
262
- async loderPreload () {
279
+ async _loderPreload () {
263
280
  let filepath = this.loader.resolveModule(path.join(this.config.baseDir, 'preload', 'index'));
264
281
  if (!filepath) return;
265
282
  const fileObj = this.loader.loadFile(filepath);
@@ -268,7 +285,7 @@ class EeApp extends BaseApp {
268
285
  } else if (is.asyncFunction(fileObj)) {
269
286
  await fileObj();
270
287
  }
271
- }
288
+ }
272
289
 
273
290
  /**
274
291
  * 序列化参数
@@ -24,9 +24,7 @@ class IpcServer {
24
24
 
25
25
  const self = this;
26
26
  // 遍历方法
27
- const files = (process.env.EE_TYPESCRIPT === 'true' && utils.extensions['.ts'])
28
- ? [ '**/*.(js|ts)', '!**/*.d.ts' ]
29
- : [ '**/*.js','**/*.jsc' ];
27
+ const files = utils.filePatterns();
30
28
  const directory = path.join(this.app.config.baseDir, 'controller');
31
29
  const filepaths = globby.sync(files, { cwd: directory });
32
30
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ee-core",
3
- "version": "1.3.3",
3
+ "version": "1.3.4-beta.2",
4
4
  "description": "ee core",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -37,7 +37,7 @@
37
37
  "path-to-regexp": "^6.2.0",
38
38
  "socket.io": "^4.4.1",
39
39
  "socket.io-client": "^4.4.1",
40
- "uglify-js": "^3.14.5",
40
+ "javascript-obfuscator": "^4.0.0",
41
41
  "urllib": "^2.38.0",
42
42
  "utility": "^1.17.0"
43
43
  },
package/tools/encrypt.js CHANGED
@@ -4,10 +4,10 @@ const path = require('path');
4
4
  const fs = require('fs');
5
5
  const fsPro = require('fs-extra');
6
6
  const is = require('is-type-of');
7
- const UglifyJS = require('uglify-js');
8
7
  const bytenode = require('bytenode');
9
8
  const utility = require('utility');
10
9
  const crypto = require('crypto');
10
+ const JavaScriptObfuscator = require('javascript-obfuscator');
11
11
 
12
12
  class Encrypt {
13
13
  constructor() {
@@ -130,13 +130,33 @@ class Encrypt {
130
130
  generate (curPath) {
131
131
  if (this.type == 'bytecode') {
132
132
  this.generateBytecodeFile(curPath);
133
+ } else if (this.type == 'confuse') {
134
+ this.generateJSConfuseFile(curPath);
133
135
  } else {
134
- this.generateConfuseFile(curPath);
136
+ this.generateJSConfuseFile(curPath);
137
+ this.generateBytecodeFile(curPath);
138
+ }
139
+ }
140
+
141
+ /**
142
+ * 使用 javascript-obfuscator 生成压缩/混淆文件
143
+ */
144
+ generateJSConfuseFile (file) {
145
+ let defaultOpt = {
146
+ compact: true,
147
+ stringArray: true,
148
+ rotateStringArray: true,
149
+ stringArrayEncoding: ['base64'],
150
+ stringArrayThreshold: 1,
151
+ disableConsoleOutput: true,
135
152
  }
153
+ let code = fs.readFileSync(file, "utf8");
154
+ let result = JavaScriptObfuscator.obfuscate(code, defaultOpt);
155
+ fs.writeFileSync(file, result.getObfuscatedCode(), "utf8");
136
156
  }
137
157
 
138
158
  /**
139
- * 生成压缩/混淆文件
159
+ * (废弃) 使用 uglify 生成压缩/混淆文件
140
160
  */
141
161
  generateConfuseFile (file) {
142
162
  let defaultOpt = {
@@ -175,6 +195,9 @@ class Encrypt {
175
195
  output: jscFile,
176
196
  electron: true
177
197
  });
198
+
199
+ //fs.writeFileSync(curPath, 'require("bytenode");module.exports = require("./'+path.basename(jscFile)+'");', 'utf8');
200
+
178
201
  fsPro.removeSync(curPath);
179
202
  }
180
203
 
@@ -1,204 +0,0 @@
1
- 'use strict';
2
-
3
- const path = require('path');
4
- const fs = require('fs');
5
- const fsPro = require('fs-extra');
6
- const UglifyJS = require('uglify-js');
7
-
8
- class CodeCompress {
9
- constructor() {
10
- const directory = [
11
- 'app',
12
- 'electron',
13
- 'config'
14
- ];
15
- this.dirs = [];
16
-
17
- this.basePath = process.cwd();
18
- this.backupCodeDir = path.join(this.basePath, 'run', 'backup_code');
19
-
20
- // 检查存在的目录
21
- for (let i = 0; i < directory.length; i++) {
22
- let codeDirPath = path.join(this.basePath, directory[i]);
23
- if (fs.existsSync(codeDirPath)) {
24
- this.dirs.push(directory[i]);
25
- }
26
- }
27
- console.log('dirs:', this.dirs);
28
- }
29
-
30
- /**
31
- * 备份 app、electron目录代码
32
- */
33
- backup () {
34
- console.log('[ee-core] [code_compress] [backup] start');
35
- this.rmBackup();
36
-
37
- for (let i = 0; i < this.dirs.length; i++) {
38
- // check code dir
39
- let codeDirPath = path.join(this.basePath, this.dirs[i]);
40
- if (!fs.existsSync(codeDirPath)) {
41
- console.log('[ee-core] [code_compress] [backup] ERROR: %s is not exist', codeDirPath);
42
- return
43
- }
44
-
45
- // copy
46
- let targetDir = path.join(this.backupCodeDir, this.dirs[i]);
47
- console.log('[ee-core] [code_compress] [backup] targetDir:', targetDir);
48
- if (!fs.existsSync(targetDir)) {
49
- this.mkdir(targetDir);
50
- this.chmodPath(targetDir, '777');
51
- }
52
-
53
- fsPro.copySync(codeDirPath, targetDir);
54
- }
55
- console.log('[ee-core] [code_compress] [backup] success');
56
- }
57
-
58
- /**
59
- * 还原代码
60
- */
61
- restore () {
62
- console.log('[ee-core] [code_compress] [restore] start');
63
- for (let i = 0; i < this.dirs.length; i++) {
64
- let codeDirPath = path.join(this.backupCodeDir, this.dirs[i]);
65
- let targetDir = path.join(this.basePath, this.dirs[i]);
66
- fsPro.copySync(codeDirPath, targetDir);
67
- }
68
- console.log('[ee-core] [code_compress] [restore] success');
69
- };
70
-
71
- /**
72
- * 压缩代码
73
- */
74
- compress () {
75
- console.log('[ee-core] [code_compress] [compress] start');
76
- for (let i = 0; i < this.dirs.length; i++) {
77
- let codeDirPath = path.join(this.basePath, this.dirs[i]);
78
- this.compressLoop(codeDirPath);
79
- }
80
- console.log('[ee-core] [code_compress] [compress] success');
81
- };
82
-
83
- compressLoop (dirPath) {
84
- let files = [];
85
- if (fs.existsSync(dirPath)) {
86
- files = fs.readdirSync(dirPath);
87
- files.forEach((file, index) => {
88
- let curPath = dirPath + '/' + file;
89
- if (fs.statSync(curPath).isDirectory()) {
90
- this.compressLoop(curPath);
91
- } else {
92
- if (path.extname(curPath) === '.js') {
93
- this.miniFile(curPath);
94
- }
95
- }
96
- });
97
- }
98
- }
99
-
100
- miniFile (file) {
101
- let code = fs.readFileSync(file, "utf8");
102
- const options = {
103
- mangle: {
104
- toplevel: false,
105
- },
106
- };
107
-
108
- let result = UglifyJS.minify(code, options);
109
- fs.writeFileSync(file, result.code, "utf8");
110
- }
111
-
112
- /**
113
- * 格式化参数
114
- */
115
- formatArgvs () {
116
- // argv
117
- let argvs = [];
118
- for (let i = 0; i < process.argv.length; i++) {
119
- const tmpArgv = process.argv[i]
120
- if (tmpArgv.indexOf('--') !== -1) {
121
- argvs.push(tmpArgv.substring(2))
122
- }
123
- }
124
- return argvs;
125
- }
126
-
127
- /**
128
- * 移除备份
129
- */
130
- rmBackup () {
131
- if (fs.existsSync(this.backupCodeDir)) {
132
- fs.rmSync(this.backupCodeDir, {recursive: true, force: true});
133
- }
134
- return;
135
- }
136
-
137
- /**
138
- * 检查文件是否存在
139
- */
140
- fileExist (filePath) {
141
- try {
142
- return fs.statSync(filePath).isFile();
143
- } catch (err) {
144
- return false;
145
- }
146
- };
147
-
148
- mkdir (dirpath, dirname) {
149
- // 判断是否是第一次调用
150
- if (typeof dirname === 'undefined') {
151
- if (fs.existsSync(dirpath)) {
152
- return;
153
- }
154
- this.mkdir(dirpath, path.dirname(dirpath));
155
- } else {
156
- // 判断第二个参数是否正常,避免调用时传入错误参数
157
- if (dirname !== path.dirname(dirpath)) {
158
- this.mkdir(dirpath);
159
- return;
160
- }
161
- if (fs.existsSync(dirname)) {
162
- fs.mkdirSync(dirpath);
163
- } else {
164
- this.mkdir(dirname, path.dirname(dirname));
165
- fs.mkdirSync(dirpath);
166
- }
167
- }
168
- };
169
-
170
- chmodPath (path, mode) {
171
- let files = [];
172
- if (fs.existsSync(path)) {
173
- files = fs.readdirSync(path);
174
- files.forEach((file, index) => {
175
- const curPath = path + '/' + file;
176
- if (fs.statSync(curPath).isDirectory()) {
177
- this.chmodPath(curPath, mode); // 递归删除文件夹
178
- } else {
179
- fs.chmodSync(curPath, mode);
180
- }
181
- });
182
- fs.chmodSync(path, mode);
183
- }
184
- };
185
- }
186
-
187
- const compress = () => {
188
- const cc = new CodeCompress();
189
- cc.backup();
190
- cc.compress();
191
- }
192
-
193
- const restore = () => {
194
- const cc = new CodeCompress();
195
- cc.restore();
196
- }
197
-
198
- module.exports = {
199
- compress,
200
- restore
201
- };
202
-
203
-
204
-