This commit is contained in:
秦圆圆 2022-01-17 14:50:31 +08:00
parent e8d4537366
commit ab2cdfbdda
664 changed files with 96390 additions and 16 deletions

13
.editorconfig Normal file
View File

@ -0,0 +1,13 @@
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false

51
.eslintrc.json Normal file
View File

@ -0,0 +1,51 @@
{
"root": true,
"ignorePatterns": [
"app/**/*", // ignore nodeJs files
"dist/**/*",
"release/**/*"
],
"overrides": [
{
"files": [
"*.ts"
],
"parserOptions": {
"project": [
"./tsconfig.serve.json",
"./src/tsconfig.app.json",
"./src/tsconfig.spec.json",
"./e2e/tsconfig.e2e.json"
],
"createDefaultProgram": true
},
"extends": [
"plugin:@angular-eslint/ng-cli-compat",
"plugin:@angular-eslint/ng-cli-compat--formatting-add-on",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {
"prefer-arrow/prefer-arrow-functions": 0,
"@angular-eslint/directive-selector": 0,
"@angular-eslint/component-selector": [
"error",
{
"type": "element",
"prefix": "eo",
"style": "kebab-case"
}
]
}
},
{
"files": [
"*.html"
],
"extends": [
"plugin:@angular-eslint/template/recommended"
],
"rules": {
}
}
]
}

65
.gitignore vendored
View File

@ -1,18 +1,55 @@
# Build and Release Folders
bin-debug/
bin-release/
[Oo]bj/
[Bb]in/
# See http://help.github.com/ignore-files/ for more about ignoring files.
# Other files and folders
# compiled output
/dist
/build/SetupScripts/nim/skin.zip
/tmp
/out-tsc
/app-builds
/release
app/main.js
src/**/*.js
!src/karma.conf.js
!src/ng1/**/*.js
*.js.map
# dependencies
node_modules
# IDEs and editors
.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# Executables
*.swf
*.air
*.ipa
*.apk
# IDE - VSCode
.vscode/*
.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
# Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties`
# should NOT be excluded as they contain compiler settings and other important
# information for Eclipse / Flash Builder.
# misc
/.angular/cache
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
testem.log
/typings
# e2e
/e2e/*.js
!/e2e/protractor.conf.js
/e2e/*.map
/e2e/tracing
/e2e/screenshots
# System Files
.DS_Store
Thumbs.db
*-lock.json

2
.npmrc Normal file
View File

@ -0,0 +1,2 @@
save=true
save-exact=true

4
.prettierrc Normal file
View File

@ -0,0 +1,4 @@
{
"singleQuote": true,
"printWidth": 120
}

46
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,46 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Renderer",
"type": "chrome",
"request": "attach",
"port": 9876,
"url": "http://localhost:4200",
"sourceMaps": true,
"timeout": 10000,
"trace": "verbose",
"sourceMapPathOverrides": {
"webpack:///./*": "${workspaceFolder}/*"
},
"preLaunchTask": "Build.Renderer"
},
{
"name": "Main",
"type": "node",
"request": "launch",
"protocol": "inspector",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"trace": "verbose",
"runtimeArgs": [
"--serve",
".",
"--remote-debugging-port=9876"
],
"windows": {
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
},
"preLaunchTask": "Build.Main"
}
],
"compounds": [
{
"name": "Application Debug",
"configurations": [ "Renderer", "Main" ]
}
]
}

49
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,49 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Build.Main",
"type": "shell",
"command": "npm run electron:serve-tsc",
"isBackground": false,
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": {
"owner": "typescript",
"source": "ts",
"applyTo": "closedDocuments",
"fileLocation": ["relative", "${cwd}"],
"pattern": "$tsc",
"background": {
"activeOnStart": true,
"beginsPattern": "^.*",
"endsPattern": "^.*Terminal will be reused by tasks, press any key to close it.*"
}
}
},
{
"label": "Build.Renderer",
"type": "shell",
"command": "npm run ng:serve",
"isBackground": true,
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": {
"owner": "typescript",
"source": "ts",
"applyTo": "closedDocuments",
"fileLocation": ["relative", "${cwd}"],
"pattern": "$tsc",
"background": {
"activeOnStart": true,
"beginsPattern": "^.*",
"endsPattern": "^.*Compiled successfully.*"
}
}
}
]
}

856
CHANGELOG.md Normal file
View File

@ -0,0 +1,856 @@
## <small>10.4.1 (2021-11-17)</small>
* misc/ Upgrade eslint version ([4321d9d](https://github.com/maximegris/angular-electron/commit/4321d9d))
* misc/ Upgrade to Angular 13.0.0 ([99e9f35](https://github.com/maximegris/angular-electron/commit/99e9f35))
## 10.4.0 (2021-11-17)
* [Bumped Version] 10.4.0 ([7a4f527](https://github.com/maximegris/angular-electron/commit/7a4f527))
* misc/ upgrade to Angular 12.2.13 ([74df637](https://github.com/maximegris/angular-electron/commit/74df637))
* misc/ upgrade to Electron 16 ([65d285c](https://github.com/maximegris/angular-electron/commit/65d285c))
* misc/ upgrade wait-on dependency ([e427f26](https://github.com/maximegris/angular-electron/commit/e427f26))
## <small>10.3.1 (2021-11-17)</small>
* [Bumped Version] 10.3.1 ([ebde830](https://github.com/maximegris/angular-electron/commit/ebde830))
* fix/ TS Config : module resolution in main process ([a9d3044](https://github.com/maximegris/angular-electron/commit/a9d3044))
## 10.3.0 (2021-11-15)
* [Bumped Version] 10.3.0 ([20e9142](https://github.com/maximegris/angular-electron/commit/20e9142))
* fix/Polyfill Node.js core modules in Webpack (5+) ([e3c0d9f](https://github.com/maximegris/angular-electron/commit/e3c0d9f))
* ref/ move angularCompilerOptions to tsconfig ([e07410b](https://github.com/maximegris/angular-electron/commit/e07410b))
* remove include statement from base tsconfig.json ([aebec1a](https://github.com/maximegris/angular-electron/commit/aebec1a))
* Update README.md ([47fc3ff](https://github.com/maximegris/angular-electron/commit/47fc3ff))
## 10.2.0 (2021-11-14)
* [Bumped Version] 10.2.0 ([edb5269](https://github.com/maximegris/angular-electron/commit/edb5269))
* add missing @ on the SCSS import for Material theme fix ([dc9ee14](https://github.com/maximegris/angular-electron/commit/dc9ee14))
* bugfix/ electron builder 22.11 needs Node 14+ ([c7dbb3f](https://github.com/maximegris/angular-electron/commit/c7dbb3f))
* Bump electron from 13.1.7 to 13.3.0 ([fe0280a](https://github.com/maximegris/angular-electron/commit/fe0280a))
* remove screenshot test ([62facb1](https://github.com/maximegris/angular-electron/commit/62facb1))
* replace Spectron by Playwright ([558c646](https://github.com/maximegris/angular-electron/commit/558c646))
* Update README.md ([4b44d8b](https://github.com/maximegris/angular-electron/commit/4b44d8b))
* Update README.md ([c385d6a](https://github.com/maximegris/angular-electron/commit/c385d6a))
## 10.1.0 (2021-07-17)
* [Bumped Version] 10.1.0 ([f399d75](https://github.com/maximegris/angular-electron/commit/f399d75))
* Fix typo & some spacing ([d2b6ee0](https://github.com/maximegris/angular-electron/commit/d2b6ee0))
* Fix typo in branch section ([623d0fa](https://github.com/maximegris/angular-electron/commit/623d0fa))
* ref/action-xvfb-linux ([60b591b](https://github.com/maximegris/angular-electron/commit/60b591b))
* Upgrade to Angular 12.1.2 / Electron 13.1.7 ([8274ae3](https://github.com/maximegris/angular-electron/commit/8274ae3))
## <small>10.0.2 (2021-06-25)</small>
* [Bumped Version] 10.0.2 ([e8f36a3](https://github.com/maximegris/angular-electron/commit/e8f36a3))
* ci/ workflow ubuntu without test ([2b819d7](https://github.com/maximegris/angular-electron/commit/2b819d7))
* fix/ spectron e2e test ([742095f](https://github.com/maximegris/angular-electron/commit/742095f))
* ref/ set default angular eslint rules ([7d531d1](https://github.com/maximegris/angular-electron/commit/7d531d1))
## <small>10.0.1 (2021-06-19)</small>
* [Bumped Version] 10.0.1 ([9b79616](https://github.com/maximegris/angular-electron/commit/9b79616))
* fix/ use node 3rd party libraries in renderer process ([1fb08a7](https://github.com/maximegris/angular-electron/commit/1fb08a7))
* ref/ eslint conf ([af0a677](https://github.com/maximegris/angular-electron/commit/af0a677))
* update README (electron builder two package structure) ([2e29232](https://github.com/maximegris/angular-electron/commit/2e29232))
* Update README.md ([33f5f6d](https://github.com/maximegris/angular-electron/commit/33f5f6d))
## 10.0.0 (2021-05-30)
* [Bumped Version] 10.0.0 ([987e996](https://github.com/maximegris/angular-electron/commit/987e996))
* [Bumped Version] 10.0.0 ([38f58de](https://github.com/maximegris/angular-electron/commit/38f58de))
* add HOW_TO.md ([3a85294](https://github.com/maximegris/angular-electron/commit/3a85294))
* fix/ github actions - angular-cli need node 12+ ([154d3fc](https://github.com/maximegris/angular-electron/commit/154d3fc))
* fix/ github actions - angular12 need node 11+ ([323aeb8](https://github.com/maximegris/angular-electron/commit/323aeb8))
* github action - node 12/14/15 ([dd9cf0d](https://github.com/maximegris/angular-electron/commit/dd9cf0d))
* ref/ electron builder two packages build ([d533e49](https://github.com/maximegris/angular-electron/commit/d533e49))
* ref/ move how to install with ng add in HOW_TO.md ([34e1232](https://github.com/maximegris/angular-electron/commit/34e1232))
* Upgrade to Angular 12 / Electron 13 ([fc006d2](https://github.com/maximegris/angular-electron/commit/fc006d2))
## <small>9.0.8 (2021-05-30)</small>
* [Bumped Version] 9.0.8 ([21197ab](https://github.com/maximegris/angular-electron/commit/21197ab))
* Added how to install Angular Material to readme ([d904101](https://github.com/maximegris/angular-electron/commit/d904101))
* fix README typo ([aa691d9](https://github.com/maximegris/angular-electron/commit/aa691d9))
* Update electron version ([b1f4451](https://github.com/maximegris/angular-electron/commit/b1f4451))
* Update electron version ([494c607](https://github.com/maximegris/angular-electron/commit/494c607))
* fix: solving bug related in fsevents/fsevents#320 ([5b091ca](https://github.com/maximegris/angular-electron/commit/5b091ca)), closes [fsevents/fsevents#320](https://github.com/fsevents/fsevents/issues/320)
## <small>9.0.7 (2021-04-07)</small>
* [Bumped Version] 9.0.7 ([b8371ee](https://github.com/maximegris/angular-electron/commit/b8371ee))
* Account for the change in context isolation with Electron 12 ([d08ae8f](https://github.com/maximegris/angular-electron/commit/d08ae8f))
* fix/ angular.json - files to lint ([ec7ce0c](https://github.com/maximegris/angular-electron/commit/ec7ce0c))
* misc/ vscode debug ([f4225a3](https://github.com/maximegris/angular-electron/commit/f4225a3))
* montée version Angular 11.2.8 / Electrion 12.0.2 ([371dafa](https://github.com/maximegris/angular-electron/commit/371dafa))
* Update FUNDING.yml ([54a42eb](https://github.com/maximegris/angular-electron/commit/54a42eb))
* Update FUNDING.yml ([3749cfa](https://github.com/maximegris/angular-electron/commit/3749cfa))
## <small>9.0.6 (2021-03-21)</small>
* [Bumped Version] 9.0.6 ([0a7842f](https://github.com/maximegris/angular-electron/commit/0a7842f))
* Create pull_request_template.md ([adac86e](https://github.com/maximegris/angular-electron/commit/adac86e))
* fix/ eslint parsing 'parserOptions.project' ([08ce022](https://github.com/maximegris/angular-electron/commit/08ce022))
* img for loading the portable .exe ([5c18d64](https://github.com/maximegris/angular-electron/commit/5c18d64))
* misc/ add code of conduct ([742c9fb](https://github.com/maximegris/angular-electron/commit/742c9fb))
* misc/ readme typo ([f4d3ebb](https://github.com/maximegris/angular-electron/commit/f4d3ebb))
* misc/ remove useless files from final package ([414d61b](https://github.com/maximegris/angular-electron/commit/414d61b))
* misc/ Update issue templates ([2dede45](https://github.com/maximegris/angular-electron/commit/2dede45))
## <small>9.0.5 (2021-03-19)</small>
* [Bumped version] 9.0.5 ([2e8e630](https://github.com/maximegris/angular-electron/commit/2e8e630))
* add github actions badges ([6b505e3](https://github.com/maximegris/angular-electron/commit/6b505e3))
* github actions on master & puul request ([e474264](https://github.com/maximegris/angular-electron/commit/e474264))
* misc / upgrade to angular 11.2.6 ([982cbac](https://github.com/maximegris/angular-electron/commit/982cbac))
* misc/ upgrade angular-eslint to 2.0.2 ([b8230c9](https://github.com/maximegris/angular-electron/commit/b8230c9))
* misc/ upgrade to Electron 12.0.1 ([d2f9fc2](https://github.com/maximegris/angular-electron/commit/d2f9fc2))
* redirect to github actions when click on badges ([a26d5f1](https://github.com/maximegris/angular-electron/commit/a26d5f1))
* ref/ replace electron.remote (deprecated) by @electron/remote ([8a4b624](https://github.com/maximegris/angular-electron/commit/8a4b624))
* remove travisci ([831ea51](https://github.com/maximegris/angular-electron/commit/831ea51))
* set github actions ([edb6f2a](https://github.com/maximegris/angular-electron/commit/edb6f2a))
## <small>9.0.4 (2021-02-13)</small>
* [Bumped Version] 9.0.4 ([e6d0aa6](https://github.com/maximegris/angular-electron/commit/e6d0aa6))
* extractCss true by default & deprecated ([4af9def](https://github.com/maximegris/angular-electron/commit/4af9def))
* Fix typo in introduction ([c3b8258](https://github.com/maximegris/angular-electron/commit/c3b8258))
* misc/ upgrade to Angular 11.2.0 & Electrion 11.2.0 ([0662793](https://github.com/maximegris/angular-electron/commit/0662793))
* spelling ([3b7f69a](https://github.com/maximegris/angular-electron/commit/3b7f69a))
* target only chrome 85 matching electron version ([b947d2d](https://github.com/maximegris/angular-electron/commit/b947d2d))
* Update README.md ([bdb91e4](https://github.com/maximegris/angular-electron/commit/bdb91e4))
## <small>9.0.3 (2020-12-08)</small>
* [Bumped Version] 9.0.3 ([fe55273](https://github.com/maximegris/angular-electron/commit/fe55273))
* fix/ upgrade angular to 11.0.2 ([203e608](https://github.com/maximegris/angular-electron/commit/203e608))
* misc/ upgrade dependencies ([922bbf9](https://github.com/maximegris/angular-electron/commit/922bbf9))
* misc/ upgrade to Electron 11 ([becaa73](https://github.com/maximegris/angular-electron/commit/becaa73))
## <small>9.0.2 (2020-11-15)</small>
* [Bumped Version] 9.0.2 ([be43e09](https://github.com/maximegris/angular-electron/commit/be43e09))
* Fix typo in eslint rule ([b8429b8](https://github.com/maximegris/angular-electron/commit/b8429b8))
* misc/ remove old code ([9933622](https://github.com/maximegris/angular-electron/commit/9933622))
## <small>9.0.1 (2020-11-14)</small>
* [Bumped Version] 9.0.1 ([066dcdb](https://github.com/maximegris/angular-electron/commit/066dcdb))
* ref/ support remote module in unit test ([04d9e8a](https://github.com/maximegris/angular-electron/commit/04d9e8a))
## 9.0.0 (2020-11-14)
* [Bumped Version] 9.0.0 ([a7964be](https://github.com/maximegris/angular-electron/commit/a7964be))
* misc/ upgrade to Angular 11 ([d265dfa](https://github.com/maximegris/angular-electron/commit/d265dfa))
## <small>8.0.6 (2020-11-14)</small>
* [Bumped Version] 8.0.6 ([e0fb539](https://github.com/maximegris/angular-electron/commit/e0fb539))
* fix/ zonejs version ([0b9b8b3](https://github.com/maximegris/angular-electron/commit/0b9b8b3))
## <small>8.0.5 (2020-09-28)</small>
* [Bumped Version] 8.0.5 ([2374427](https://github.com/maximegris/angular-electron/commit/2374427))
* misc/ ci - remove fast finish option ([d4ce11d](https://github.com/maximegris/angular-electron/commit/d4ce11d))
* misc/ enable remote module in renderer process (needed for spectron) ([3309855](https://github.com/maximegris/angular-electron/commit/3309855))
* misc/ revert electron because spectron cannot handle: electron-userland/spectron#693 ([b1affd0](https://github.com/maximegris/angular-electron/commit/b1affd0)), closes [electron-userland/spectron#693](https://github.com/electron-userland/spectron/issues/693)
* misc/ upgrade to Electron 10 & Angular 10.1 ([07786a2](https://github.com/maximegris/angular-electron/commit/07786a2))
## <small>8.0.4 (2020-08-30)</small>
* [Bumped Version] 8.0.4 ([ac3682d](https://github.com/maximegris/angular-electron/commit/ac3682d))
* fix/ ng lint config ([753f828](https://github.com/maximegris/angular-electron/commit/753f828))
* fix/ README typo (e2e chapter) ([85aaf86](https://github.com/maximegris/angular-electron/commit/85aaf86))
* fix/ travis ci conf ([2632a2d](https://github.com/maximegris/angular-electron/commit/2632a2d))
* misc/ clarify node lib import ([f41ce65](https://github.com/maximegris/angular-electron/commit/f41ce65))
* misc/ upgrade Electron 10 ([b71c514](https://github.com/maximegris/angular-electron/commit/b71c514))
* ref/ clean custom webpack target ('electron-renderer' or 'web') ([e3a4e01](https://github.com/maximegris/angular-electron/commit/e3a4e01))
* Update README.md ([5cf5e2b](https://github.com/maximegris/angular-electron/commit/5cf5e2b))
* Update README.md ([0b70270](https://github.com/maximegris/angular-electron/commit/0b70270))
## <small>8.0.3 (2020-08-12)</small>
* [Bumped Version] 8.0.2 ([84598a5](https://github.com/maximegris/angular-electron/commit/84598a5))
* [Bumped Version] 8.0.3 ([00ce410](https://github.com/maximegris/angular-electron/commit/00ce410))
* fix/ e2e tests with Spectron ([472afc8](https://github.com/maximegris/angular-electron/commit/472afc8))
* fix/ require error with nodeIntegration = false ([61c5c6b](https://github.com/maximegris/angular-electron/commit/61c5c6b))
* misc/ Upgrade Angular (10.0.9) and Electron (9.2.0) ([e3d2fca](https://github.com/maximegris/angular-electron/commit/e3d2fca))
## <small>8.0.1 (2020-08-12)</small>
* [Bumped Version] 8.0.1 ([e032729](https://github.com/maximegris/angular-electron/commit/e032729))
* fix/ eslint on main.ts file ([4b17ab6](https://github.com/maximegris/angular-electron/commit/4b17ab6))
* misc/ remove warinng npm start ( tsconfg.app include key) ([8a73b4a](https://github.com/maximegris/angular-electron/commit/8a73b4a))
* misc/ upgrade Angular ([a1ef40d](https://github.com/maximegris/angular-electron/commit/a1ef40d))
## 8.0.0 (2020-07-13)
* [Bumped Version] 8.0.0 ([78a4c9e](https://github.com/maximegris/angular-electron/commit/78a4c9e))
* added "style" key to "schematics" ([6f5bbc5](https://github.com/maximegris/angular-electron/commit/6f5bbc5))
* Create FUNDING.yml ([087570a](https://github.com/maximegris/angular-electron/commit/087570a))
* misc/ update README (Angular & Electron version) ([2d33b15](https://github.com/maximegris/angular-electron/commit/2d33b15))
* ref/ Upgrade to Angular 10.3 & Electron 9.1 ([84f0519](https://github.com/maximegris/angular-electron/commit/84f0519))
* Update README.md ([11d0a17](https://github.com/maximegris/angular-electron/commit/11d0a17))
## <small>7.2.1 (2020-06-20)</small>
* [Bumped Version] 7.2.1 ([cabd11e](https://github.com/maximegris/angular-electron/commit/cabd11e))
* ref/ keep only 1 eslint config ([e942747](https://github.com/maximegris/angular-electron/commit/e942747))
## 7.2.0 (2020-06-20)
* [Bumped Version] 7.2.0 ([a98a84a](https://github.com/maximegris/angular-electron/commit/a98a84a))
* feat/ merge electron-builder npm scripts ([ddd92b3](https://github.com/maximegris/angular-electron/commit/ddd92b3))
* fix/ ng lint with eslint ([92d7419](https://github.com/maximegris/angular-electron/commit/92d7419))
* misc/ upgrade Electron (9.0.4) / Angular (9.1.11) ([21f7401](https://github.com/maximegris/angular-electron/commit/21f7401))
* ref/ electron remote deprecated ([a8628fc](https://github.com/maximegris/angular-electron/commit/a8628fc))
## 7.1.0 (2020-05-02)
* [Bumped Version] 7.1.0 ([8dffcea](https://github.com/maximegris/angular-electron/commit/8dffcea))
* feat/ VSCode : add Debugging config for man process (#465) + Karma ([acc62d9](https://github.com/maximegris/angular-electron/commit/acc62d9)), closes [#465](https://github.com/maximegris/angular-electron/issues/465)
* fix/ Karma configuration to debug easily ([273e752](https://github.com/maximegris/angular-electron/commit/273e752))
## <small>7.0.5 (2020-04-26)</small>
* [Bumped Version] 7.0.5 ([63eed52](https://github.com/maximegris/angular-electron/commit/63eed52))
* Upgrade Angular 9.1.3 & Electron 8.2.3 ([00b9d43](https://github.com/maximegris/angular-electron/commit/00b9d43))
## <small>7.0.4 (2020-04-20)</small>
* [Bumped Version] 7.0.4 ([dbce7a0](https://github.com/maximegris/angular-electron/commit/dbce7a0))
* ref/ make app reloading/working with and without usehash routing strategy ([386ce67](https://github.com/maximegris/angular-electron/commit/386ce67))
* Transparent background issue fix for Linux ([4c0c169](https://github.com/maximegris/angular-electron/commit/4c0c169))
## <small>7.0.3 (2020-04-11)</small>
* [Bumped Version] 7.0.2 ([c4c36f6](https://github.com/maximegris/angular-electron/commit/c4c36f6))
* [Bumped Version] 7.0.3 ([6206066](https://github.com/maximegris/angular-electron/commit/6206066))
* Fix a typo in README.md ([86ac910](https://github.com/maximegris/angular-electron/commit/86ac910))
* fix/ polyfills in tsconfig ([cf4f172](https://github.com/maximegris/angular-electron/commit/cf4f172))
* misc/ changelog ([19f6027](https://github.com/maximegris/angular-electron/commit/19f6027))
* misc/ Changelog ([67437ba](https://github.com/maximegris/angular-electron/commit/67437ba))
* misc/ maj angular 9.1.1 & electron 8.2.1 ([061e01e](https://github.com/maximegris/angular-electron/commit/061e01e))
* misc/ maj eslint dep ([09fc1f7](https://github.com/maximegris/angular-electron/commit/09fc1f7))
* moved all app icons to assets/icons folder ([7d6bb69](https://github.com/maximegris/angular-electron/commit/7d6bb69))
* ref/ set allowRendererProcessReuse to true ([7c5c43b](https://github.com/maximegris/angular-electron/commit/7c5c43b))
## <small>7.0.1 (2020-02-22)</small>
* [Bumped Version] 7.0.1 ([7a84ca0](https://github.com/maximegris/angular-electron/commit/7a84ca0))
* fix/ README dependencies version ([7276d96](https://github.com/maximegris/angular-electron/commit/7276d96))
* misc/ upgrade Angular 9.0.2 & Electron 8.0.1 ([174b36f](https://github.com/maximegris/angular-electron/commit/174b36f))
* ref/ travis test node 10 & 12 ([8b7ee5b](https://github.com/maximegris/angular-electron/commit/8b7ee5b))
## 7.0.0 (2020-02-09)
* [Bumped Version] 7.0.0 ([0f304d2](https://github.com/maximegris/angular-electron/commit/0f304d2))
* cast isElectron to boolean #429 ([ee06695](https://github.com/maximegris/angular-electron/commit/ee06695)), closes [#429](https://github.com/maximegris/angular-electron/issues/429)
* feat/ update angular 8 deps ([7df49ff](https://github.com/maximegris/angular-electron/commit/7df49ff))
* feat/ update to Angular 9 & Electron 8 ([a304034](https://github.com/maximegris/angular-electron/commit/a304034))
* fix/ e2e tests ([395d2da](https://github.com/maximegris/angular-electron/commit/395d2da))
* hot reload note ([28e1854](https://github.com/maximegris/angular-electron/commit/28e1854))
* ref/ upgrade electron to v8 ([320ce2f](https://github.com/maximegris/angular-electron/commit/320ce2f))
## <small>6.4.1 (2019-12-25)</small>
* feat/ update Electron (7.1.2) ([3d76ff5](https://github.com/maximegris/angular-electron/commit/3d76ff5))
* misc/ maj changelog ([eb46727](https://github.com/maximegris/angular-electron/commit/eb46727))
* reef/ update stale bot ([671b7c9](https://github.com/maximegris/angular-electron/commit/671b7c9))
* ref/ remove usunsed files ([9bf5824](https://github.com/maximegris/angular-electron/commit/9bf5824))
## 6.4.0 (2019-11-19)
* [Bumped Version] 6.4.0 ([fac9eef](https://github.com/maximegris/angular-electron/commit/fac9eef))
* #412 change selector of WebviewDirective ([76e7918](https://github.com/maximegris/angular-electron/commit/76e7918)), closes [#412](https://github.com/maximegris/angular-electron/issues/412)
* eslint-migration ([7637f45](https://github.com/maximegris/angular-electron/commit/7637f45))
* eslint-migration - disable warnings/errors ([99e7ec0](https://github.com/maximegris/angular-electron/commit/99e7ec0))
* eslint-migration - fix removed translation import ([2f64f37](https://github.com/maximegris/angular-electron/commit/2f64f37))
* eslint-migration - remove tslint.json configuration ([3c1f9f6](https://github.com/maximegris/angular-electron/commit/3c1f9f6))
* karma-electron ([21f97fd](https://github.com/maximegris/angular-electron/commit/21f97fd))
* karma-electron - remove chrome deps for travis ([0f09907](https://github.com/maximegris/angular-electron/commit/0f09907))
* misc/ add npmrc ([9d94f9c](https://github.com/maximegris/angular-electron/commit/9d94f9c))
* misc/ typo README ([d52b03a](https://github.com/maximegris/angular-electron/commit/d52b03a))
* permissive eslint rules to remove linter warnings ([964b57f](https://github.com/maximegris/angular-electron/commit/964b57f))
* require is not defined ([632c454](https://github.com/maximegris/angular-electron/commit/632c454))
## <small>6.3.1 (2019-11-01)</small>
* [Bumped Version] 6.3.1 ([671b6a3](https://github.com/maximegris/angular-electron/commit/671b6a3))
* #395 - require is not defined ([c4b2cb6](https://github.com/maximegris/angular-electron/commit/c4b2cb6)), closes [#395](https://github.com/maximegris/angular-electron/issues/395)
* changelog ([39b0bca](https://github.com/maximegris/angular-electron/commit/39b0bca))
## 6.3.0 (2019-10-25)
* [Bumped Version] 6.3.0 ([09f9646](https://github.com/maximegris/angular-electron/commit/09f9646))
* misc/ change Electron version to 7.0.0 in README ([6a4e2de](https://github.com/maximegris/angular-electron/commit/6a4e2de))
* misc/ remove link to dependenciesci ([93d5a8c](https://github.com/maximegris/angular-electron/commit/93d5a8c))
* misc/ upgrade Electron 7 ([d732340](https://github.com/maximegris/angular-electron/commit/d732340))
## 6.2.0 (2019-09-29)
* [Bumped Version] 6.2.0 ([8838e0e](https://github.com/maximegris/angular-electron/commit/8838e0e))
* Maj Changelog ([bc4c950](https://github.com/maximegris/angular-electron/commit/bc4c950))
* misc/ add Stale to close unactive issues ([398bdf1](https://github.com/maximegris/angular-electron/commit/398bdf1))
* Upgrade Angular 8.2.8 & Electron 6.0.10 ([2ecda63](https://github.com/maximegris/angular-electron/commit/2ecda63))
## 6.1.0 (2019-08-15)
* [Bumped Version] 6.1.0 ([b47c594](https://github.com/maximegris/angular-electron/commit/b47c594))
* [DELETE]: vscode settings removed ([becc9b4](https://github.com/maximegris/angular-electron/commit/becc9b4))
* [UPDATE]: Typescript version fixes ([a284c23](https://github.com/maximegris/angular-electron/commit/a284c23))
* Angular src restructured as modular as per angular official guidelines, .travis.yml support added fo ([5983703](https://github.com/maximegris/angular-electron/commit/5983703))
* bump tslint & codelyzer versions, update tslint rules & alphabetize ([8425cdc](https://github.com/maximegris/angular-electron/commit/8425cdc))
* Corejs path updates ([88056d6](https://github.com/maximegris/angular-electron/commit/88056d6))
* Electron 6.0.0 ([1aef350](https://github.com/maximegris/angular-electron/commit/1aef350))
* fix/ Version Electron in README ([acf0d4f](https://github.com/maximegris/angular-electron/commit/acf0d4f))
* misc/ upgrade Angular 8.2 / Spectron 7 ([6e2211f](https://github.com/maximegris/angular-electron/commit/6e2211f))
* Update dependencies ([bd51f28](https://github.com/maximegris/angular-electron/commit/bd51f28))
## <small>6.0.1 (2019-05-31)</small>
* [Bumped Version] 6.0.1 ([4f9cef3](https://github.com/maximegris/angular-electron/commit/4f9cef3))
* Add CI for macOS. ([3ba02e3](https://github.com/maximegris/angular-electron/commit/3ba02e3))
* ref/ strict version build-angular & zonejs ([5a24b56](https://github.com/maximegris/angular-electron/commit/5a24b56))
* ref/ strict version codelyzer ([6ede0c8](https://github.com/maximegris/angular-electron/commit/6ede0c8))
* Remove Node.js v12. ([ccbf6cd](https://github.com/maximegris/angular-electron/commit/ccbf6cd))
* Run CI for Node.js version 10 ([2538965](https://github.com/maximegris/angular-electron/commit/2538965))
* Use service xvfb. ([4db31e3](https://github.com/maximegris/angular-electron/commit/4db31e3))
## 6.0.0 (2019-05-31)
* [Bumped Version] 6.0.0 ([fb719ab](https://github.com/maximegris/angular-electron/commit/fb719ab))
* bump angular version ([7a564a0](https://github.com/maximegris/angular-electron/commit/7a564a0))
* Fix Travis CI link ([10aaa4c](https://github.com/maximegris/angular-electron/commit/10aaa4c))
* Not gitignore src/karma.conf.js ([7599320](https://github.com/maximegris/angular-electron/commit/7599320))
* ref/ upgrade Angular 8 and Electron 5 ([92334cf](https://github.com/maximegris/angular-electron/commit/92334cf))
* update versions and prepare for electron 5 ([07a5786](https://github.com/maximegris/angular-electron/commit/07a5786))
* version bump ([bb1d6bb](https://github.com/maximegris/angular-electron/commit/bb1d6bb))
* feat(CI): update Ubuntu and Node versions in Travis ([e0ff557](https://github.com/maximegris/angular-electron/commit/e0ff557))
* fix: type conflicts ([a2971bf](https://github.com/maximegris/angular-electron/commit/a2971bf))
* fix(e2e): add mocha types ([20e1e89](https://github.com/maximegris/angular-electron/commit/20e1e89))
* fix(e2e): without devTools ([2581983](https://github.com/maximegris/angular-electron/commit/2581983)), closes [/github.com/electron/spectron/issues/174#issuecomment-319242097](https://github.com//github.com/electron/spectron/issues/174/issues/issuecomment-319242097)
* chore: Spectron for e2e tests ([901438a](https://github.com/maximegris/angular-electron/commit/901438a))
## 5.1.0 (2018-11-30)
* [Bumped Version] 5.1.0 ([b790e12](https://github.com/maximegris/angular-electron/commit/b790e12))
* fix/ typo Angular 7 ([fde371f](https://github.com/maximegris/angular-electron/commit/fde371f))
* fix/ typo README ([723233c](https://github.com/maximegris/angular-electron/commit/723233c))
* fix/ typo script npm electron:windows ([45bab44](https://github.com/maximegris/angular-electron/commit/45bab44))
* ref/ remve npx - fix vulnerabilities ([41aeb57](https://github.com/maximegris/angular-electron/commit/41aeb57))
* update README ([f146d5d](https://github.com/maximegris/angular-electron/commit/f146d5d))
## 5.0.0 (2018-11-11)
* Fix typos in README file ([0440ee9](https://github.com/maximegris/angular-electron/commit/0440ee9))
* ref/ Generate changelog ([a89b3ce](https://github.com/maximegris/angular-electron/commit/a89b3ce))
* ref/ Upgrade to Angular 7 ([315a79b](https://github.com/maximegris/angular-electron/commit/315a79b))
* Update electron-builder.json files rule ([82c7bcf](https://github.com/maximegris/angular-electron/commit/82c7bcf))
* Update Version Electron 2 to 3 #hacktoberfest ([f083328](https://github.com/maximegris/angular-electron/commit/f083328))
## <small>4.2.2 (2018-08-22)</small>
* fix/ build serve & electron with single tsc command ([9106c8f](https://github.com/maximegris/angular-electron/commit/9106c8f))
* fix/ typo README ([a9448aa](https://github.com/maximegris/angular-electron/commit/a9448aa))
## <small>4.2.1 (2018-08-22)</small>
* fix/ jslib in main process error ([ef33f5e](https://github.com/maximegris/angular-electron/commit/ef33f5e))
## 4.2.0 (2018-08-19)
* [Bumped Version] V4.2.0 ([0da3856](https://github.com/maximegris/angular-electron/commit/0da3856))
* fix/ electron builder output directories #200 ([f4535e5](https://github.com/maximegris/angular-electron/commit/f4535e5)), closes [#200](https://github.com/maximegris/angular-electron/issues/200)
* Make sure tsconfig be used. ([961c8b1](https://github.com/maximegris/angular-electron/commit/961c8b1))
* ref/ remove some directories of tsconfig.app.json ([1adad4a](https://github.com/maximegris/angular-electron/commit/1adad4a))
* Upgrade Angular (6.1.2) deps ([d8818c1](https://github.com/maximegris/angular-electron/commit/d8818c1))
## 4.1.0 (2018-06-27)
* Allow Angular Using Electron Modules ([ec705ee](https://github.com/maximegris/angular-electron/commit/ec705ee))
* fix/ version angular (revert 6.0.6 -> 6.0.5) ([63a41b8](https://github.com/maximegris/angular-electron/commit/63a41b8))
* fix/ version ts-node ([0d8341a](https://github.com/maximegris/angular-electron/commit/0d8341a))
* ref/ postinstall web & electron ([50657d0](https://github.com/maximegris/angular-electron/commit/50657d0))
* update README ([1d48e32](https://github.com/maximegris/angular-electron/commit/1d48e32))
* feat(zone): add zone-patch-electron to patch Electron native APIs in polyfills ([01842e2](https://github.com/maximegris/angular-electron/commit/01842e2))
## 4.0.0 (2018-05-25)
* misc/ remove unused packages ([a7e33b6](https://github.com/maximegris/angular-electron/commit/a7e33b6))
* misc/ update Changelog ([b758122](https://github.com/maximegris/angular-electron/commit/b758122))
* ref/ upgrade angular to 6.0.3 ([e7fac6e](https://github.com/maximegris/angular-electron/commit/e7fac6e))
* refactor: update electron, electron-builder to latest (2.0.2, 20.14.7) ([f19e6ee](https://github.com/maximegris/angular-electron/commit/f19e6ee))
* refactor: upgrade to NodeJS 8, Angular 6, CLI 6, Electron 2.0, RxJS 6.1 ([e37efdb](https://github.com/maximegris/angular-electron/commit/e37efdb))
* refactor(hooks): replace hooks to ng-cli fileReplacements logic ([c940037](https://github.com/maximegris/angular-electron/commit/c940037))
* fix(test): create polyfills-test.ts for karma test & setup Travis CI ([7fbc68c](https://github.com/maximegris/angular-electron/commit/7fbc68c))
* fix(travis): set progress to false (speed up npm) ([be48531](https://github.com/maximegris/angular-electron/commit/be48531))
## <small>3.4.1 (2018-05-25)</small>
* misc/ update changelog ([70b359f](https://github.com/maximegris/angular-electron/commit/70b359f))
* Modify electron builder configuration to remove source code and tests ([0cf6899](https://github.com/maximegris/angular-electron/commit/0cf6899))
* version 3.4.1 ([308ea9c](https://github.com/maximegris/angular-electron/commit/308ea9c))
## 3.4.0 (2018-05-25)
* misc/ update changelog ([7d5eeb3](https://github.com/maximegris/angular-electron/commit/7d5eeb3))
* ref/ remove contributors ([6dc97a1](https://github.com/maximegris/angular-electron/commit/6dc97a1))
* The file is unused ([05c9e39](https://github.com/maximegris/angular-electron/commit/05c9e39))
* Translation issue ([35354b1](https://github.com/maximegris/angular-electron/commit/35354b1))
* version 3.4.0 ([06d6b0f](https://github.com/maximegris/angular-electron/commit/06d6b0f))
## 3.3.0 (2018-04-15)
* add Changelog file ([71083f1](https://github.com/maximegris/angular-electron/commit/71083f1))
* fix/ typo README.md (production variables) ([a8c2b63](https://github.com/maximegris/angular-electron/commit/a8c2b63))
* version 3.3.0 ([a88bda6](https://github.com/maximegris/angular-electron/commit/a88bda6))
* version 3.3.0 changelog ([ddfbbf9](https://github.com/maximegris/angular-electron/commit/ddfbbf9))
## 3.2.0 (2018-04-15)
* fix e2e tests based on PR #161 and terminate the npm process after test execution ([fccf348](https://github.com/maximegris/angular-electron/commit/fccf348)), closes [#161](https://github.com/maximegris/angular-electron/issues/161)
* fix/ app e2e spec ([8046b2a](https://github.com/maximegris/angular-electron/commit/8046b2a))
* Including electron to eliminate Electron not found err sg ([d78203f](https://github.com/maximegris/angular-electron/commit/d78203f))
* provide webFrame access ([6bd044e](https://github.com/maximegris/angular-electron/commit/6bd044e))
* ref/ add node/electron module import as exemple : fs and remote ([e3ad12d](https://github.com/maximegris/angular-electron/commit/e3ad12d))
* remove copyfiles ([9af5138](https://github.com/maximegris/angular-electron/commit/9af5138))
* update dependencies ([89963ab](https://github.com/maximegris/angular-electron/commit/89963ab))
* version 3.2.0 ([8dc69fa](https://github.com/maximegris/angular-electron/commit/8dc69fa))
## 3.1.0 (2018-03-15)
* Added option -o to script npm run ng:serve so that it really open the browser ([72aff8d](https://github.com/maximegris/angular-electron/commit/72aff8d))
* Fix to change environment ([448d68b](https://github.com/maximegris/angular-electron/commit/448d68b))
* version 3.1.0 ([f7c71e7](https://github.com/maximegris/angular-electron/commit/f7c71e7))
## <small>3.0.1 (2018-03-07)</small>
* fix/ icon app ([22699ef](https://github.com/maximegris/angular-electron/commit/22699ef))
* version 3.0.1 ([5258ff1](https://github.com/maximegris/angular-electron/commit/5258ff1))
## 3.0.0 (2018-02-25)
* fix/ TranslateModule test ([7863aa9](https://github.com/maximegris/angular-electron/commit/7863aa9))
* Ng not ejected anymore ([67ab31c](https://github.com/maximegris/angular-electron/commit/67ab31c))
* pin all dependency versions ([0558d6a](https://github.com/maximegris/angular-electron/commit/0558d6a))
* update dependencies and fix unit tests ([4d3ca6e](https://github.com/maximegris/angular-electron/commit/4d3ca6e))
## <small>2.7.1 (2018-02-15)</small>
* ref/ dernière version cli ([3df8158](https://github.com/maximegris/angular-electron/commit/3df8158))
* version 2.7.1 ([1ae6f7a](https://github.com/maximegris/angular-electron/commit/1ae6f7a))
## 2.7.0 (2018-02-15)
* Correction of a word. ([d6655c7](https://github.com/maximegris/angular-electron/commit/d6655c7))
* feat/ add webview directive ([e1b5600](https://github.com/maximegris/angular-electron/commit/e1b5600))
* migrate Angular to 5.2.0 ([b8cf343](https://github.com/maximegris/angular-electron/commit/b8cf343))
* ref/ Remove sponsor ([2a28239](https://github.com/maximegris/angular-electron/commit/2a28239))
* ref/ update angular & dep ([e3b1fab](https://github.com/maximegris/angular-electron/commit/e3b1fab))
* ref/ upgrade electron (security issue) ([f6a0c4e](https://github.com/maximegris/angular-electron/commit/f6a0c4e))
* version bump + logo resize ([3545d16](https://github.com/maximegris/angular-electron/commit/3545d16))
* fix: fixes maximegris/angular-electron#118 ([6d21e69](https://github.com/maximegris/angular-electron/commit/6d21e69)), closes [maximegris/angular-electron#118](https://github.com/maximegris/angular-electron/issues/118)
* fix: fixes maximegris/angular-electron#98 ([136344b](https://github.com/maximegris/angular-electron/commit/136344b)), closes [maximegris/angular-electron#98](https://github.com/maximegris/angular-electron/issues/98)
## <small>2.4.1 (2017-12-14)</small>
* fix/ Manage icons for linux binary generation ([ccd0601](https://github.com/maximegris/angular-electron/commit/ccd0601))
* version 2.4.1 ([5fcfca0](https://github.com/maximegris/angular-electron/commit/5fcfca0))
## 2.4.0 (2017-12-08)
* Use HttpClientModule ([5704e2e](https://github.com/maximegris/angular-electron/commit/5704e2e))
* version 2.4.0 ([0437b33](https://github.com/maximegris/angular-electron/commit/0437b33))
## 2.3.0 (2017-12-04)
* add ngx translate ([facda37](https://github.com/maximegris/angular-electron/commit/facda37))
## 2.2.0 (2017-11-28)
* Brought back scripts defined in webpack.config.js ([441da3d](https://github.com/maximegris/angular-electron/commit/441da3d))
* migrate to Angular 5.0.3 ([f4bc5b2](https://github.com/maximegris/angular-electron/commit/f4bc5b2))
* Update LICENSE badge ([fa783aa](https://github.com/maximegris/angular-electron/commit/fa783aa))
* Update to electron-builder ([0e94b52](https://github.com/maximegris/angular-electron/commit/0e94b52))
## <small>2.1.1 (2017-11-19)</small>
* Move codesponsor ([064be4c](https://github.com/maximegris/angular-electron/commit/064be4c))
## 2.1.0 (2017-11-19)
* Add codesponsor ([87e695d](https://github.com/maximegris/angular-electron/commit/87e695d))
* Add script for winportable ([2be2dae](https://github.com/maximegris/angular-electron/commit/2be2dae))
* Add support for building a Windows self-contained executable ([7cfa790](https://github.com/maximegris/angular-electron/commit/7cfa790))
* fix/ electron-packager need favicon >= 256x256 on Windows ([d2c253f](https://github.com/maximegris/angular-electron/commit/d2c253f))
* fix/ refact webpack config (inspired by ng eject Angular 5) ([d1c30ac](https://github.com/maximegris/angular-electron/commit/d1c30ac))
* fix/ replace aotPlugin in no prod mode ([a0caf1e](https://github.com/maximegris/angular-electron/commit/a0caf1e))
* fix/ Replace AotPlugin to AngularCompilerPlugin ([bef106e](https://github.com/maximegris/angular-electron/commit/bef106e))
* fix/ Update README Angular 5 ([93c6949](https://github.com/maximegris/angular-electron/commit/93c6949))
* fix/ webpack template path ([518b66b](https://github.com/maximegris/angular-electron/commit/518b66b))
* Mgrate to Angular 5.0.2 ([bd7bed6](https://github.com/maximegris/angular-electron/commit/bd7bed6))
* Update package.json ([b16cf73](https://github.com/maximegris/angular-electron/commit/b16cf73))
* Version 2.1.0 ([fccef2f](https://github.com/maximegris/angular-electron/commit/fccef2f))
## 2.0.0 (2017-11-13)
* Add buffer to externals ([7e797f0](https://github.com/maximegris/angular-electron/commit/7e797f0))
* Edit a typo on README ([956a2bc](https://github.com/maximegris/angular-electron/commit/956a2bc))
* Fix #55 , and also added functionality for scripts global building ([012a894](https://github.com/maximegris/angular-electron/commit/012a894)), closes [#55](https://github.com/maximegris/angular-electron/issues/55)
* Fix #55 removed bootstraps.css which for example purpose before. ([41445eb](https://github.com/maximegris/angular-electron/commit/41445eb)), closes [#55](https://github.com/maximegris/angular-electron/issues/55)
* License MIT ([73494b7](https://github.com/maximegris/angular-electron/commit/73494b7))
* Migrate to Angular 5 ([3a3ffe1](https://github.com/maximegris/angular-electron/commit/3a3ffe1))
## 1.9.0 (2017-09-22)
* feat/ launch electron & webpack in // (npm run start) ([8c37cc4](https://github.com/maximegris/angular-electron/commit/8c37cc4))
* ref/ Exclude node_modules (tslint) ([412a0a5](https://github.com/maximegris/angular-electron/commit/412a0a5))
## <small>1.8.1 (2017-09-22)</small>
* ref/ add package-lock in gitignore ([4edd98d](https://github.com/maximegris/angular-electron/commit/4edd98d))
* remove package-lock ([8e98627](https://github.com/maximegris/angular-electron/commit/8e98627))
* upgrade angular version 4.4.3 ([10d0f87](https://github.com/maximegris/angular-electron/commit/10d0f87))
* version 1.8.1 ([70879d1](https://github.com/maximegris/angular-electron/commit/70879d1))
## 1.8.0 (2017-09-09)
* upgrade lib version ([2ac2aa0](https://github.com/maximegris/angular-electron/commit/2ac2aa0))
## 1.7.0 (2017-08-18)
* ref/ Update Angular (4.3.5) / Electron (1.7.2) / Electron Packager (8.7.2) / Typescript (2.5.0) ([f97cd81](https://github.com/maximegris/angular-electron/commit/f97cd81))
## <small>1.6.1 (2017-07-27)</small>
* fix/ angular-cli error in prod compilation with aot ([c26a5ae](https://github.com/maximegris/angular-electron/commit/c26a5ae))
* version 1.6.1 ([899babd](https://github.com/maximegris/angular-electron/commit/899babd))
## 1.6.0 (2017-07-16)
* ajout package-lock npm v5 ([09c0840](https://github.com/maximegris/angular-electron/commit/09c0840))
* Change background img ([7e58717](https://github.com/maximegris/angular-electron/commit/7e58717))
* Fix npm run build:prod ([c23bade](https://github.com/maximegris/angular-electron/commit/c23bade))
* fix/ Bindings not updating automatically #44 ([2a90191](https://github.com/maximegris/angular-electron/commit/2a90191)), closes [#44](https://github.com/maximegris/angular-electron/issues/44)
* fix/ e2e test with jasmine2 ([9c51f32](https://github.com/maximegris/angular-electron/commit/9c51f32))
* fix/ typescript issues ([bb0a6ab](https://github.com/maximegris/angular-electron/commit/bb0a6ab))
* increment version deps ([bde452c](https://github.com/maximegris/angular-electron/commit/bde452c))
* Revert last pull request - break production compilation ([ccc9064](https://github.com/maximegris/angular-electron/commit/ccc9064))
* upgrade angular version to 4.3.0 ([ab16959](https://github.com/maximegris/angular-electron/commit/ab16959))
## 1.5.0 (2017-06-10)
* fix/ karma Unit test ([ea13d6d](https://github.com/maximegris/angular-electron/commit/ea13d6d))
* fix/ remove yarn because of error with module dep in prod builds ([8a49a45](https://github.com/maximegris/angular-electron/commit/8a49a45))
* update yarn lock ([18c0e62](https://github.com/maximegris/angular-electron/commit/18c0e62))
## <small>1.4.4 (2017-06-08)</small>
* fix/ Fix npm run lint ([db7972a](https://github.com/maximegris/angular-electron/commit/db7972a))
* ref/ electron ./dist more generic ([7e71add](https://github.com/maximegris/angular-electron/commit/7e71add))
* Replace const icon to let icon ([dadf65f](https://github.com/maximegris/angular-electron/commit/dadf65f))
## <small>1.4.3 (2017-06-06)</small>
* fix/ favicon path during packaging ([aa2b012](https://github.com/maximegris/angular-electron/commit/aa2b012))
* remove build node 8 till node-sass failed ([34f201d](https://github.com/maximegris/angular-electron/commit/34f201d))
* v1.4.3 ([4961fb0](https://github.com/maximegris/angular-electron/commit/4961fb0))
## <small>1.4.2 (2017-05-31)</small>
* Change dep versions ([62d08d3](https://github.com/maximegris/angular-electron/commit/62d08d3))
* install npm dep when building ([56948d0](https://github.com/maximegris/angular-electron/commit/56948d0))
* Minor update ([5f282b7](https://github.com/maximegris/angular-electron/commit/5f282b7))
* No hot reload in browser ([7892f0d](https://github.com/maximegris/angular-electron/commit/7892f0d))
* update Electron v1.6.10 ([f2f2080](https://github.com/maximegris/angular-electron/commit/f2f2080))
* upgrade ng/electron dependencies ([78b0f27](https://github.com/maximegris/angular-electron/commit/78b0f27))
* chore(package): bump dependencies ([b62c7b6](https://github.com/maximegris/angular-electron/commit/b62c7b6))
## 1.4.0 (2017-05-23)
* 1.4.0 ([23213c4](https://github.com/maximegris/angular-electron/commit/23213c4))
* Change style home page ([93dcc52](https://github.com/maximegris/angular-electron/commit/93dcc52))
* Fixed compiler warnings ([fca6b15](https://github.com/maximegris/angular-electron/commit/fca6b15))
* ref/ electron main from js to ts ([835d32b](https://github.com/maximegris/angular-electron/commit/835d32b))
* Remove caret & tilde ([dd98155](https://github.com/maximegris/angular-electron/commit/dd98155))
## <small>1.3.5 (2017-05-18)</small>
* Add new tags ([cd07a86](https://github.com/maximegris/angular-electron/commit/cd07a86))
* v 1.3.5 ([d528a71](https://github.com/maximegris/angular-electron/commit/d528a71))
## <small>1.3.4 (2017-05-12)</small>
* feat/ add nodejs native lib in webpack config ([27d9bc6](https://github.com/maximegris/angular-electron/commit/27d9bc6))
* Fix issue #15 ([d77cbf1](https://github.com/maximegris/angular-electron/commit/d77cbf1)), closes [#15](https://github.com/maximegris/angular-electron/issues/15)
* Ref/ Electron packager in external file ([17b04e8](https://github.com/maximegris/angular-electron/commit/17b04e8))
* version 1.3.4 ([374af16](https://github.com/maximegris/angular-electron/commit/374af16))
## <small>1.3.3 (2017-05-10)</small>
* Chapters order ([a772b9c](https://github.com/maximegris/angular-electron/commit/a772b9c))
* Chapters order ([06547e5](https://github.com/maximegris/angular-electron/commit/06547e5))
* Delete spec file of electron.service ([083498e](https://github.com/maximegris/angular-electron/commit/083498e))
* Fix issue #15 ([e7cd6e6](https://github.com/maximegris/angular-electron/commit/e7cd6e6)), closes [#15](https://github.com/maximegris/angular-electron/issues/15)
* Move Browser mode chapter ([8818750](https://github.com/maximegris/angular-electron/commit/8818750))
* Version 1.3.3 ([f4db75b](https://github.com/maximegris/angular-electron/commit/f4db75b))
## <small>1.3.2 (2017-05-05)</small>
* Add comments of how conditional import works ([e6c1b3b](https://github.com/maximegris/angular-electron/commit/e6c1b3b))
* Conditional import of Electron/NodeJS libs - The app can be launch in browser mode ([c434f8a](https://github.com/maximegris/angular-electron/commit/c434f8a))
* Fix indentation ([6a9836a](https://github.com/maximegris/angular-electron/commit/6a9836a))
* Fix prepree2e script ([b2af4fd](https://github.com/maximegris/angular-electron/commit/b2af4fd))
* Set e2e tests ([d223974](https://github.com/maximegris/angular-electron/commit/d223974))
* Suround electron browser by try/catch ([88be472](https://github.com/maximegris/angular-electron/commit/88be472))
* Update @types/node ([9d43304](https://github.com/maximegris/angular-electron/commit/9d43304))
* Update readme with e2e info ([01bbf13](https://github.com/maximegris/angular-electron/commit/01bbf13))
* update version ([0849a0a](https://github.com/maximegris/angular-electron/commit/0849a0a))
## <small>1.3.1 (2017-05-05)</small>
* Add routing module ([7334ce8](https://github.com/maximegris/angular-electron/commit/7334ce8))
* Fixed hardcoded path in glob copy, blocking assets after eject ([815d519](https://github.com/maximegris/angular-electron/commit/815d519))
* update comments in dev/prod env files ([7cf6a51](https://github.com/maximegris/angular-electron/commit/7cf6a51))
* Version 1.3.1 ([f18ac77](https://github.com/maximegris/angular-electron/commit/f18ac77))
## 1.3.0 (2017-05-01)
* Fix webpack prod/dev env ([8549da1](https://github.com/maximegris/angular-electron/commit/8549da1))
## <small>1.2.1 (2017-04-30)</small>
* allowJs ([4efd188](https://github.com/maximegris/angular-electron/commit/4efd188))
* Example url background in scss ([3705a35](https://github.com/maximegris/angular-electron/commit/3705a35))
* Fix electron build (extract-zip workaround) ([a7ee90e](https://github.com/maximegris/angular-electron/commit/a7ee90e))
* Fix webpack config url in css ([cea4be5](https://github.com/maximegris/angular-electron/commit/cea4be5))
* html loader ([c55558a](https://github.com/maximegris/angular-electron/commit/c55558a))
* update version 1.2.1 ([78e8da7](https://github.com/maximegris/angular-electron/commit/78e8da7))
## 1.2.0 (2017-04-19)
* Set one example of css class in app component ([a15775f](https://github.com/maximegris/angular-electron/commit/a15775f))
* Update npm dependencies ([0a93ebe](https://github.com/maximegris/angular-electron/commit/0a93ebe))
## <small>1.1.2 (2017-04-18)</small>
* Fix typo & fix script electron:mac ([bd06859](https://github.com/maximegris/angular-electron/commit/bd06859))
* Set theme jekyll-theme-architect ([644d857](https://github.com/maximegris/angular-electron/commit/644d857))
* update README ([97fa63d](https://github.com/maximegris/angular-electron/commit/97fa63d))
* update README ([23fc0a9](https://github.com/maximegris/angular-electron/commit/23fc0a9))
* update README ([a8dcf6a](https://github.com/maximegris/angular-electron/commit/a8dcf6a))
* v1.1.2 ([e29e467](https://github.com/maximegris/angular-electron/commit/e29e467))
## <small>1.1.1 (2017-04-12)</small>
* Fix webpack.config file path (travisci) ([a172df9](https://github.com/maximegris/angular-electron/commit/a172df9))
* live reload on disk ([7bb2f8b](https://github.com/maximegris/angular-electron/commit/7bb2f8b))
* Remove unused dependency (webpack-dev-server) ([e9150f4](https://github.com/maximegris/angular-electron/commit/e9150f4))
## 1.1.0 (2017-04-12)
* add depdencies CI & Licence ([6ceb0f2](https://github.com/maximegris/angular-electron/commit/6ceb0f2))
* Override webpack configuration ([60d6116](https://github.com/maximegris/angular-electron/commit/60d6116))
## <small>1.0.3 (2017-04-07)</small>
* Add TravisCI ([e5640fd](https://github.com/maximegris/angular-electron/commit/e5640fd))
* v1.0.3 ([9866d53](https://github.com/maximegris/angular-electron/commit/9866d53))
## <small>1.0.2 (2017-04-07)</small>
* Add TravisCI ([ef4b80e](https://github.com/maximegris/angular-electron/commit/ef4b80e))
* Fix typo ([f964c3f](https://github.com/maximegris/angular-electron/commit/f964c3f))
* Fix typo ([e42bb5e](https://github.com/maximegris/angular-electron/commit/e42bb5e))
* Update README ([3bb45b3](https://github.com/maximegris/angular-electron/commit/3bb45b3))
* Update README with angular-cli doc ([5a57578](https://github.com/maximegris/angular-electron/commit/5a57578))
* v1.0.2 ([1bd8e0e](https://github.com/maximegris/angular-electron/commit/1bd8e0e))
## <small>1.0.1 (2017-04-03)</small>
* feat/ Add electron-packager scripts ([57891dc](https://github.com/maximegris/angular-electron/commit/57891dc))
* ref/ update README ([7fddc20](https://github.com/maximegris/angular-electron/commit/7fddc20))
* update README ([9a983c1](https://github.com/maximegris/angular-electron/commit/9a983c1))
* v1.0.0 ([7a21eb9](https://github.com/maximegris/angular-electron/commit/7a21eb9))
* v1.0.1 ([68275a3](https://github.com/maximegris/angular-electron/commit/68275a3))
* chore: initial commit from @angular/cli ([616a69e](https://github.com/maximegris/angular-electron/commit/616a69e))

128
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
maxime.gris@gmail.com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

7
LICENSE.md Normal file
View File

@ -0,0 +1,7 @@
Copyright 2020 - Maxime GRIS
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,2 +1,29 @@
# eoapi
apimanage app
# NodeJS
requires a minimum Node.js version of either v12.20, v14.15, or v16.10.
# 安装依赖
```
npm install -g electron-builder
npm install -g @angular/cli
npm install
cd app&&npm install
```
# 启动应用
```
npm start
```
# 打包
Windows 如果需要安装包样式:
```
npm run pack:win
```
不需要安装包样式的 windows/其他系统打包:
```
npm run build
```

1
_config.yml Normal file
View File

@ -0,0 +1 @@
theme: jekyll-theme-architect

252
angular.json Normal file
View File

@ -0,0 +1,252 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"cli": {
"analytics": false,
"defaultCollection": "@angular-eslint/schematics"
},
"version": 1,
"newProjectRoot": "projects",
"projects": {
"eoapi": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"schematics": {
"@schematics/angular:application": {
"strict": true
}
},
"architect": {
"build": {
"builder": "@angular-builders/custom-webpack:browser",
"options": {
"outputPath": "dist",
"index": "src/index.html",
"main": "src/main.ts",
"tsConfig": "src/tsconfig.app.json",
"polyfills": "src/polyfills.ts",
"assets": [
"src/favicon.ico",
"src/assets",
{
"glob": "**/*",
"input": "./node_modules/@ant-design/icons-angular/src/inline-svg/",
"output": "/assets/"
}
],
"styles": [
"src/assets/theme/antd.less",
"src/styles.scss",
"src/ng1/index.css",
"src/assets/font/iconfont.css",
{
"input": "src/assets/theme/classic_forest.scss",
"bundleName": "classic_forest",
"inject": false
},
{
"input": "src/assets/theme/classic_sunrise.scss",
"bundleName": "classic_sunrise",
"inject": false
},
{
"input": "src/assets/theme/classic_toy.scss",
"bundleName": "classic_toy",
"inject": false
},
{
"input": "src/assets/theme/clean_cloud.scss",
"bundleName": "clean_cloud",
"inject": false
},
{
"input": "src/assets/theme/clean_forest.scss",
"bundleName": "clean_forest",
"inject": false
},
{
"input": "src/assets/theme/clean_sunrise.scss",
"bundleName": "clean_sunrise",
"inject": false
},
{
"input": "src/assets/theme/night_black.scss",
"bundleName": "night_black",
"inject": false
},
{
"input": "src/assets/theme/night_cmd.scss",
"bundleName": "night_cmd",
"inject": false
},
{
"input": "src/assets/theme/night_dusk.scss",
"bundleName": "night_dusk",
"inject": false
},
{
"input": "src/assets/theme/night_forest.scss",
"bundleName": "night_forest",
"inject": false
}
],
"scripts": [
"src/ng1/lib/angular/angular.js",
"src/ng1/app.module.js",
"src/ng1/component/select-default.js",
"src/ng1/component/sort-and-filter.js",
"src/ng1/component/auto-complete.js",
"src/ng1/component/list-block.js",
"src/ng1/directive/get-dom-length.directive.js",
"src/ng1/directive/drop-down-menu.directive.js",
"src/ng1/directive/sort.directive.js",
"src/ng1/directive/drop-change-space.directive.js",
"src/ng1/directive/inner-html.directive.js"
],
"customWebpackConfig": {
"path": "./angular.webpack.js",
"replaceDuplicatePlugins": true
},
"allowedCommonJsDependencies": ["brace"]
},
"configurations": {
"dev": {
"optimization": false,
"outputHashing": "none",
"sourceMap": true,
"namedChunks": false,
"aot": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": false,
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.dev.ts"
}
]
},
"web": {
"optimization": false,
"outputHashing": "none",
"sourceMap": true,
"namedChunks": false,
"aot": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": false,
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.web.ts"
}
]
},
"webaot": {
"optimization": false,
"outputHashing": "none",
"sourceMap": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": false,
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.web.ts"
}
]
},
"production": {
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
]
}
}
},
"serve": {
"builder": "@angular-builders/custom-webpack:dev-server",
"options": {
"browserTarget": "eoapi:build"
},
"configurations": {
"dev": {
"browserTarget": "eoapi:build:dev"
},
"web": {
"browserTarget": "eoapi:build:web"
},
"webaot": {
"browserTarget": "eoapi:build:web"
},
"production": {
"browserTarget": "eoapi:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "eoapi:build"
}
},
"test": {
"builder": "@angular-builders/custom-webpack:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills-test.ts",
"tsConfig": "src/tsconfig.spec.json",
"karmaConfig": "src/karma.conf.js",
"scripts": [],
"styles": ["src/styles.scss"],
"assets": ["src/assets"],
"customWebpackConfig": {
"path": "./angular.webpack.js",
"replaceDuplicatePlugins": true
}
}
},
"lint": {
"builder": "@angular-eslint/builder:lint",
"options": {
"lintFilePatterns": ["src/**/*.ts", "src/**/*.html"]
}
}
}
},
"eoapi-e2e": {
"root": "e2e",
"projectType": "application",
"architect": {
"lint": {
"builder": "@angular-eslint/builder:lint",
"options": {
"lintFilePatterns": ["e2e/**/*.ts"]
}
}
}
}
},
"defaultProject": "eoapi",
"schematics": {
"@schematics/angular:component": {
"prefix": "eo",
"style": "scss"
},
"@schematics/angular:directive": {
"prefix": "eo"
}
}
}

47
angular.webpack.js Normal file
View File

@ -0,0 +1,47 @@
//Polyfill Node.js core modules in Webpack. This module is only needed for webpack 5+.
const NodePolyfillPlugin = require("node-polyfill-webpack-plugin");
/**
* Custom angular webpack configuration
*/
module.exports = (config, options) => {
config.target = "electron-renderer";
if (options.fileReplacements) {
for (let fileReplacement of options.fileReplacements) {
if (fileReplacement.replace !== "src/environments/environment.ts") {
continue;
}
let fileReplacementParts = fileReplacement["with"].split(".");
if (
fileReplacementParts.length > 1 &&
["web"].indexOf(fileReplacementParts[1]) >= 0
) {
config.target = "web";
}
break;
}
}
if(config.module&&config.module.rules){
config.module.rules.push( {
test: /\.html$/i,
use: [
{
loader: 'raw-loader',
options: {
esModule: false,
}
},
],
},)
}
config.plugins = [
...config.plugins,
new NodePolyfillPlugin({
excludeAliases: ["console"],
}),
];
return config;
};

146
app/main.ts Normal file
View File

@ -0,0 +1,146 @@
import { app, BrowserWindow, screen, ipcMain } from 'electron';
import * as path from 'path';
import * as fs from 'fs';
import * as os from 'os';
import * as url from 'url';
import * as child_process from 'child_process';
let win: BrowserWindow = null;
const args = process.argv.slice(1),
serve = args.some((val) => val === '--serve'),
workerLoop = {};
function createWindow(): BrowserWindow {
const electronScreen = screen;
const size = electronScreen.getPrimaryDisplay().workAreaSize;
// Create the browser window.
win = new BrowserWindow({
width: size.width * 0.8,
height: size.height * 0.8,
frame: os.type() === 'Darwin' ? true : false, //mac use default frame
webPreferences: {
nodeIntegration: true,
allowRunningInsecureContent: serve ? true : false,
contextIsolation: false, // false if you want to run e2e test with Spectron
},
});
if (serve) {
win.webContents.openDevTools();
require('electron-reload')(__dirname, {
electron: require(path.join(__dirname, '/../node_modules/electron')),
});
win.loadURL('http://localhost:4200');
} else {
// Path when running electron executable
let pathIndex = './index.html';
if (fs.existsSync(path.join(__dirname, '../dist/index.html'))) {
// Path when running electron in local folder
pathIndex = '../dist/index.html';
}
win.loadURL(
url.format({
pathname: path.join(__dirname, pathIndex),
protocol: 'file:',
slashes: true,
})
);
}
// Emitted when the window is closed.
win.on('closed', () => {
// Dereference the window object, usually you would store window
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
win = null;
});
return win;
}
class UnitWorker {
instance: child_process.ChildProcess;
constructor() {}
start(message) {
this.instance = child_process.fork(`${__dirname}/request/main.js`);
this.watch();
this.instance.send(message);
}
finish(message) {
win.webContents.send('unitTest', message);
this.kill();
}
kill() {
this.instance.kill();
}
private watch() {
this.instance.on('message', (message: any) => {
switch (message.action) {
case 'finish': {
this.finish(message.data);
break;
}
}
});
}
}
try {
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
// Added 400 ms to fix the black background issue while using transparent window. More detais at https://github.com/electron/electron/issues/15947
app.on('ready', () => setTimeout(createWindow, 400));
// Quit when all windows are closed.
app.on('window-all-closed', () => {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (win === null) {
createWindow();
}
});
ipcMain.on('message', function (event, arg) {
console.log('recieve render msg=>', arg, arg.action);
switch (arg.action) {
case 'minimize': {
win.minimize();
break;
}
case 'restore': {
win.restore();
break;
}
case 'maximize': {
win.maximize();
break;
}
case 'close': {
win.close();
break;
}
}
});
ipcMain.on('unitTest', function (event, message) {
let id=message.id;
switch (message.action) {
case 'ajax': {
workerLoop[id] = new UnitWorker();
workerLoop[id].start(message);
break;
}
case 'abort': {
workerLoop[id].kill();
break;
}
}
});
} catch (e) {
// Catch Error
// throw e;
}

19
app/package.json Normal file
View File

@ -0,0 +1,19 @@
{
"name": "eoapi",
"version": "0.0.1",
"main": "main.js",
"private": true,
"scripts": {
"postinstall": "electron-builder install-app-deps"
},
"dependencies": {
"crypto-js": "^4.0.0",
"form-data": "^2.5.1",
"https-proxy-agent": "^5.0.0",
"iconv-lite": "^0.6.2"
},
"devDependencies": {
"electron": "16.0.0"
},
"__npminstall_done": false
}

5
app/request/config.json Normal file
View File

@ -0,0 +1,5 @@
{
"MAX_TIME_LIMIT": 3600000,
"MAX_TIME_DELAY":3600000,
"REQUEST_BODY_LIMIT_STORAGE_LENGTH": 1048576
}

45
app/request/domain.json Normal file
View File

@ -0,0 +1,45 @@
[
"com",
"cn",
"xin",
"net",
"top",
"xyz",
"wang",
"shop",
"site",
"club",
"cc",
"fun",
"online",
"biz",
"red",
"link",
"ltd",
"mobi",
"info",
"org",
"name",
"vip",
"pro",
"work",
"tv",
"kim",
"group",
"tech",
"store",
"ren",
"ink",
"pub",
"live",
"wiki",
"design",
"ai",
"me",
"io",
"test",
"example",
"invalid",
"localhost"
]

9
app/request/lang.json Normal file
View File

@ -0,0 +1,9 @@
{
"en": {
"213d3b0f-b267-4d5c-9512-0a06e2a5a522": "JWT signature construction failed"
},
"cn": {
"213d3b0f-b267-4d5c-9512-0a06e2a5a522": "jwt签名构造失败"
}
}

509
app/request/libs/apiUtil.js Normal file
View File

@ -0,0 +1,509 @@
/**
* @name 返回通用方法
* @author 广州银云信息科技有限公司
*/
let _LIB_WORKER_THREAD = require('./exec_worker_thread');
let CryptoJS = require('crypto-js');
let privateFun = {},
_LibsCommon = require('./common'),
_LibsEncrypt = require('./encrypt').core,
_Xml_Class = new (require('./xml').core)();
const DOMAIN_CONSTANT = require('../domain.json');
const DOMAIN_REGEX =
'(^((http|wss|ws|ftp|https)://))|(^(((http|wss|ws|ftp|https)://)|)(([\\w\\-_]+([\\w\\-\\.]*)?(\\.(' +
DOMAIN_CONSTANT.join('|') +
')))|((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(localhost))((\\/)|(\\?)|(:)|($)))';
const TIMINGSUMMARY = {
NS_PER_SEC: 1e9,
MS_PER_NS: 1e6,
};
const { NodeVM } = require('./vm2/index');
let querystring = require('querystring');
/**
* @desc 重置env
* @param {object} inputSanboxVar 沙箱中的env变量
* @param {object} inputBaiscEnv 基础的env
*/
privateFun.resetEnv = (inputBaiscEnv, inputSanboxVar) => {
let tmpResult = Object.assign({}, inputBaiscEnv);
tmpResult.envParam = _LibsCommon.deepCopy(inputSanboxVar.envParam);
['http'].map((val) => {
tmpResult[val] = {};
for (let itemKey in inputSanboxVar[val]) {
if (
['extraFormDataParam', 'queryParam', 'headerParam', 'baseUrlParam', 'requestScript', 'responseScript'].indexOf(
itemKey
) > -1
) {
tmpResult[val][itemKey] = inputSanboxVar[val][itemKey];
}
}
});
return tmpResult;
};
privateFun.getMicrosToMs = (inputStartTime, inputEndTime) => {
if (inputStartTime === undefined || inputEndTime === undefined) return 0.0;
let tmpSecondDiff = inputEndTime[0] - inputStartTime[0];
let tmpNanoSecondDiff = inputEndTime[1] - inputStartTime[1];
let tmpDiffInNanoSecond = tmpSecondDiff * TIMINGSUMMARY.NS_PER_SEC + tmpNanoSecondDiff;
let tmpOutput = tmpDiffInNanoSecond / TIMINGSUMMARY.MS_PER_NS;
if (tmpOutput < 0) {
return 0.0;
} else {
return tmpOutput;
}
};
privateFun.getHttpTiming = (timingSummary) => {
return {
dnsTiming: _LibsEncrypt.getMicrosToMsStr(timingSummary.startAt, timingSummary.dnsTiming),
tcpTiming: _LibsEncrypt.getMicrosToMsStr(timingSummary.dnsTiming || timingSummary.startAt, timingSummary.tcpTiming),
tlsTiming: _LibsEncrypt.getMicrosToMsStr(timingSummary.tcpTiming, timingSummary.tlsTiming),
requestSentTiming: _LibsEncrypt.getMicrosToMsStr(
timingSummary.tlsTiming || timingSummary.tcpTiming,
timingSummary.firstByteTiming
),
firstByteTiming: _LibsEncrypt.getMicrosToMsStr(timingSummary.startAt, timingSummary.firstByteTiming),
contentDeliveryTiming: _LibsEncrypt.getMicrosToMsStr(timingSummary.firstByteTiming, timingSummary.endAt),
responseTiming: _LibsEncrypt.getMicrosToMsStr(timingSummary.startAt, timingSummary.endAt),
};
};
privateFun.getBaiscEoFn = (inputSanboxVar, inputEnv = {}) => {
let tmpResult = {
env: {
envParam: inputEnv.envParam,
},
};
['http', 'websocket', 'socket', 'rpc'].map((val) => {
tmpResult.env[val] = _LibsCommon.deepCopy(inputEnv[val]) || {};
});
return tmpResult;
};
privateFun.setExecWorkerThread = (inputPostMsg, inputMsgCallback) => {
return new _LIB_WORKER_THREAD.core(inputPostMsg, inputMsgCallback);
};
/**
* @desc 主要用于UI脚本中公用函数补全
* @param {*} inputSanboxVar 沙盒变量
* @param {*} inputEnv 环境
* @param {*} inputOpts 可选配置项主要结构需要(globalHeader:全局头部)
*/
privateFun.constructUiCodeBasicFn = (inputSanboxVar, inputEnv, inputOpts = {}) => {
inputOpts = inputOpts || {};
let tmpResult = Object.assign({}, inputSanboxVar.eo, privateFun.getBaiscEoFn(inputSanboxVar, inputEnv));
tmpResult.env['http'] = _LibsCommon.deepCopy(inputEnv['http']) || {};
return tmpResult;
};
/**
* @desc 构造各种类型的sanbox结构
* @param {object} inputSanboxVar 沙箱中的变量
* @param {object} inputInitialData 初始化的变量集合
* @param {boolean} inputIsResponse 是否为返回信息
*/
privateFun.setTypesRefFns = (inputSanboxVar, inputInitialData, inputIsResponse) => {
let tmpTypes = ['http', 'socket', 'rpc', 'websocket'],
tmpBasicConf = {
apiUrl: (inputInitialData.url || '').split('?')[0],
bodyParam: inputInitialData.raw || '',
bodyParseParam: inputInitialData.params || {},
queryParam: inputInitialData.query || {},
headerParam: inputInitialData.headers || {},
restParam: inputInitialData.rest || {},
responseParam: inputInitialData.response || '',
responseHeaderParam: inputInitialData.responseHeaders || {},
};
tmpTypes.map((val) => {
inputSanboxVar[val] = _LibsCommon.deepCopy(tmpBasicConf);
inputSanboxVar[val].url = {
parse() {
return privateFun.parseRealSendUrl(
{
baseUrlParam: inputSanboxVar[val].baseUrlParam,
queryParam: inputSanboxVar[val].queryParam,
apiUrl: inputSanboxVar[val].apiUrl,
restParam: inputSanboxVar[val].restParam,
},
{
baseUrlParam: inputSanboxVar.env[val].baseUrlParam,
queryParam: inputSanboxVar.env[val].queryParam,
envParam: inputSanboxVar.env.envParam,
}
);
},
get: () => {
return inputSanboxVar[val].apiUrl;
},
set: (inputVal) => {
inputSanboxVar[val].apiUrl = inputVal;
},
};
inputSanboxVar[val].query = {
get: (inputKey) => {
return inputSanboxVar[val].queryParam[inputKey];
},
set: (inputKey, inputVal) => {
inputSanboxVar[val].queryParam[inputKey] = inputVal;
},
unset: (inputKey) => {
delete inputSanboxVar[val].queryParam[inputKey];
},
clear: () => {
inputSanboxVar[val].queryParam = {};
},
};
inputSanboxVar[val].header = {
get: (inputKey) => {
return inputSanboxVar[val].headerParam[inputKey];
},
set: (inputKey, inputVal) => {
inputSanboxVar[val].headerParam[inputKey] = inputVal;
},
unset: (inputKey) => {
delete inputSanboxVar[val].headerParam[inputKey];
},
clear: () => {
inputSanboxVar[val].headerParam = {};
},
};
inputSanboxVar[val].rest = {
get: (inputKey) => {
return inputSanboxVar[val].restParam[inputKey];
},
set: (inputKey, inputVal) => {
inputSanboxVar[val].restParam[inputKey] = inputVal;
},
unset: (inputKey) => {
delete inputSanboxVar[val].restParam[inputKey];
},
clear: () => {
inputSanboxVar[val].restParam = {};
},
};
if (inputIsResponse) {
inputSanboxVar[val].response = {
get: () => {
return inputSanboxVar[val].responseParam;
},
set: (inputVal) => {
inputSanboxVar[val].responseParam = inputVal;
},
};
inputSanboxVar[val].responseHeader = {
get: (inputKey) => {
return inputSanboxVar[val].responseHeaderParam[inputKey];
},
set: (inputKey, inputVal) => {
inputSanboxVar[val].responseHeaderParam[inputKey] = inputVal;
},
unset: (inputKey) => {
delete inputSanboxVar[val].responseHeaderParam[inputKey];
},
clear: () => {
inputSanboxVar[val].responseHeaderParam = {};
},
};
}
});
};
/**
* @desc 构造各种类型的sanbox结构
* @param {object} inputSanboxVar 沙箱中的变量
* @param {object} inputInitialData 初始化的变量集合
* @param {boolean} inputIsResponse 是否为返回信息
*/
privateFun.setTypesRefFns = (inputSanboxVar, inputInitialData, inputIsResponse) => {
let tmpTypes = ['http'],
tmpBasicConf = {
apiUrl: (inputInitialData.url || '').split('?')[0],
bodyParam: inputInitialData.raw || '',
bodyParseParam: inputInitialData.params || {},
queryParam: inputInitialData.query || {},
headerParam: inputInitialData.headers || {},
restParam: inputInitialData.rest || {},
responseParam: inputInitialData.response || '',
responseHeaderParam: inputInitialData.responseHeaders || {},
};
tmpTypes.map((val) => {
inputSanboxVar[val] = _LibsCommon.deepCopy(tmpBasicConf);
});
};
/**
* 前置脚本代码
* @param {string} inputData 请求可分别赋值信息
* @param {string} inputScript 前置脚本代码
* @param {object} inputOpts options
* @return {object} 前置组合请求信息
*/
privateFun.parseBeforeCode = function (inputData, inputScript, inputOpts = {}) {
let tmpBasicEnv = inputData.env || _LibsCommon.parseEnv(),
tmpApiType = inputOpts.type || 'http';
inputData = JSON.parse(JSON.stringify(inputData));
let tmpReportList = [],
tmpBinary = inputData.binary,
tmpSanboxObj = {
requestBody: inputData.requestBody || {},
requestHeaders: inputData.requestHeaders || {},
restParams: inputData.restParams || {},
queryParams: inputData.queryParams || {},
responseHeaders: inputData.responseHeaders || {},
response: inputData.response || {},
CryptoJS: CryptoJS,
eo: {},
};
const tmpVm = new NodeVM({
sandbox: tmpSanboxObj,
require: {
external: true,
builtin: ['crypto'],
},
}),
tmpCodeEvalObj = tmpVm._context;
tmpCodeEvalObj.eo = privateFun.constructUiCodeBasicFn(tmpCodeEvalObj, tmpBasicEnv, inputOpts);
privateFun.setTypesRefFns(tmpCodeEvalObj.eo, inputData);
let tmpTargetTypeData = tmpCodeEvalObj.eo[tmpApiType],
tmpTargetTypeEnv = tmpCodeEvalObj.eo.env[tmpApiType];
let tmpOutput = {
status: 'finish',
url: tmpTargetTypeData.apiUrl,
headers: {},
params: null,
env: privateFun.resetEnv(tmpBasicEnv, tmpCodeEvalObj.eo.env),
reportList: tmpReportList,
},
tmpParams,
tmpHeaders;
if (inputData.isReturnSoonWhenExecCode) return tmpOutput;
try {
let tmp_query_param_obj = Object.assign({}, tmpTargetTypeEnv.queryParam, tmpTargetTypeData.queryParam);
tmpHeaders = Object.assign({}, tmpTargetTypeEnv.headerParam, tmpTargetTypeData.headerParam);
switch (inputData.requestType.toString()) {
case '0': {
tmpParams = _LibsCommon.mergeObj(tmpTargetTypeData.bodyParseParam, tmpTargetTypeEnv.extraFormDataParam);
break;
}
case '2': {
if (/^\[/.test(tmpTargetTypeData.bodyParam)) {
tmpParams = JSON.stringify([JSON.parse(tmpTargetTypeData.bodyParam)[0]]);
} else {
tmpParams = tmpTargetTypeData.bodyParam;
}
break;
}
case '3': {
/**
* @desc 去除xml自动补全额外参数功能
*/
tmpParams = _Xml_Class.jsonToXml()(tmpTargetTypeData.bodyParseParam, inputData.xmlAttrObj);
break;
}
case '1': {
tmpParams =
typeof tmpTargetTypeData.bodyParam === 'string'
? tmpTargetTypeData.bodyParam
: JSON.stringify(tmpTargetTypeData.bodyParam);
break;
}
}
let tmpEnvGlobals = Object.assign({}, global.eoTestGlobals || {}, tmpCodeEvalObj.eo.env.envParam || {});
for (let key in tmpEnvGlobals) {
let val = tmpEnvGlobals[key];
let templateParamObject = {};
let templateHeaderObject = {};
for (let tmp_query_param_key in tmp_query_param_obj) {
let tmp_query_param_val = _LibsCommon.replaceAll(
'{{' + key + '}}',
val || '',
tmp_query_param_obj[tmp_query_param_key]
);
delete tmp_query_param_obj[tmp_query_param_key];
tmp_query_param_obj[_LibsCommon.replaceAll('{{' + key + '}}', val || '', tmp_query_param_key)] =
tmp_query_param_val;
}
tmpOutput.url = _LibsCommon.replaceAll('{{' + key + '}}', val || '', tmpOutput.url);
for (let childKey in tmpHeaders) {
tmpHeaders[childKey] = _LibsCommon.replaceAll('{{' + key + '}}', val, tmpHeaders[childKey]);
if (childKey.indexOf('{{' + key + '}}') > -1) {
templateHeaderObject[_LibsCommon.replaceAll('{{' + key + '}}', val, childKey)] = tmpHeaders[childKey];
} else {
templateHeaderObject[childKey] = tmpHeaders[childKey];
}
}
tmpHeaders = templateHeaderObject;
if (!tmpBinary) {
switch (typeof tmpParams) {
case 'string': {
tmpParams = _LibsCommon.replaceAll('{{' + key + '}}', val, tmpParams);
break;
}
default: {
for (let childKey in tmpParams) {
switch (typeof tmpParams[childKey]) {
case 'string': {
tmpParams[childKey] = _LibsCommon.replaceAll('{{' + key + '}}', val, tmpParams[childKey]);
break;
}
default: {
for (let grandSonKey in tmpParams[childKey]) {
let grandSonVal = tmpParams[childKey][grandSonKey];
switch (typeof grandSonVal) {
case 'string': {
tmpParams[childKey][grandSonKey] = _LibsCommon.replaceAll('{{' + key + '}}', val, grandSonVal);
break;
}
}
}
break;
}
}
if (childKey.indexOf('{{' + key + '}}') > -1) {
let tmpHadReplaceString = _LibsCommon.replaceAll('{{' + key + '}}', val, childKey);
templateParamObject[tmpHadReplaceString] = tmpParams[childKey];
if (tmpParams[tmpHadReplaceString]) {
switch (_LibsCommon.getTypeOfVar(templateParamObject[tmpHadReplaceString])) {
case 'Array': {
if (_LibsCommon.getTypeOfVar(tmpParams[tmpHadReplaceString]) == 'Array') {
templateParamObject[tmpHadReplaceString] = templateParamObject[tmpHadReplaceString].concat(
tmpParams[tmpHadReplaceString]
);
} else {
templateParamObject[tmpHadReplaceString] = templateParamObject[tmpHadReplaceString].push(
tmpParams[tmpHadReplaceString]
);
}
break;
}
default: {
if (_LibsCommon.getTypeOfVar(tmpParams[tmpHadReplaceString]) == 'Array') {
templateParamObject[tmpHadReplaceString] = tmpParams[tmpHadReplaceString].push(
templateParamObject[tmpHadReplaceString]
);
} else {
templateParamObject[tmpHadReplaceString] = [
templateParamObject[tmpHadReplaceString],
tmpParams[tmpHadReplaceString],
];
}
break;
}
}
}
} else {
templateParamObject[childKey] = tmpParams[childKey];
}
}
tmpParams = templateParamObject;
}
}
}
}
tmpOutput.headers = tmpHeaders;
tmpOutput.queryParams = tmp_query_param_obj;
let queryString = querystring.stringify(tmpOutput.queryParams);
tmpOutput.url += queryString ? '?' + queryString : '';
for (let key in tmpTargetTypeData.restParam) {
tmpOutput.url = privateFun.replaceRestParam(key, tmpTargetTypeData.restParam[key], tmpOutput.url);
}
if (tmpBinary) {
tmpOutput.params = {};
} else {
tmpOutput.params = tmpParams;
}
if (!new RegExp(DOMAIN_REGEX).test(tmpOutput.url)) {
tmpOutput.url = (tmpTargetTypeEnv.baseUrlParam || '') + tmpOutput.url;
}
if (!/"content-type":/i.test(JSON.stringify(tmpOutput.headers))) {
switch (inputData.requestType.toString()) {
case '0': {
tmpOutput.headers['Content-Type'] = 'application/x-www-form-urlencoded';
break;
}
case '2': {
tmpOutput.headers['Content-Type'] = 'application/json';
break;
}
case '3': {
tmpOutput.headers['Content-Type'] = 'application/xml';
break;
}
case '4': {
if (/(data:)(.*)(;base64),/.test(tmpBinary)) {
tmpOutput.headers['Content-Type'] = RegExp.$2;
} else {
tmpOutput.headers['Content-Type'] = 'false';
}
break;
}
}
}
} catch (e) {
console.error(new Date() + 'libs/common.js 217:', e);
}
return tmpOutput;
};
/**
* 后置脚本代码
* @param {string} inputData 返回结果信息
* @param {string} inputScript 后置脚本代码
* @param {object} inputEnv env
* @param {object} inputOpts options
* @return {object} 后置组合请求信息
*/
privateFun.parseAfterCode = function (inputData, inputScript, inputEnv, inputOpts = {}) {
let tmpReportList = [],
tmpApiType = inputOpts.type || 'http',
tmpBasicEnv = inputEnv || _LibsCommon.parseEnv();
let tmpStatus, tmpErrorContent; //不可删,与提示预警有关
let tmpBindObj = (inputOpts || {}).bindObj || {};
const tmpVm = new NodeVM({
sandbox: {
CryptoJS: CryptoJS,
db_result: inputOpts.dbResult || {},
eo: {},
requestBody: tmpBindObj.requestBody || {},
requestHeaders: tmpBindObj.requestHeaders || {},
restParams: tmpBindObj.restParams || {},
queryParams: tmpBindObj.queryParams || {},
response: tmpBindObj.response || {},
responseHeaders: (inputOpts || {}).responseHeaders,
},
require: {
external: true,
builtin: ['crypto'],
},
}),
tmpCodeEvalObj = tmpVm._context;
tmpCodeEvalObj.eo = privateFun.constructUiCodeBasicFn(tmpCodeEvalObj, tmpBasicEnv, inputOpts);
privateFun.setTypesRefFns(
tmpCodeEvalObj.eo,
Object.assign({}, inputOpts, {
response: inputData,
}),
true
);
let tmpTargetTypeData = tmpCodeEvalObj.eo[tmpApiType];
return {
status: 'finish',
content: tmpTargetTypeData.responseParam,
env: privateFun.resetEnv(tmpBasicEnv, tmpCodeEvalObj.eo.env),
reportList: tmpReportList,
};
};
privateFun.requestPreReduceByPromise = (inputData, inputCode, inputOptions) => {
return new Promise((resolve) => {
let tmpResponse = privateFun.parseBeforeCode(inputData, inputCode, inputOptions);
resolve(tmpResponse);
});
};
privateFun.responsePreReduceByPromise = (inputData, inputCode, inputEnv, inputOptions) => {
return new Promise((resolve) => {
let tmpResponse = privateFun.parseAfterCode(inputData, inputCode, inputEnv, inputOptions);
resolve(tmpResponse);
});
};
exports.getMicrosToMs = privateFun.getMicrosToMs;
exports.getHttpTiming = privateFun.getHttpTiming;
exports.requestPreReduceByPromise = privateFun.requestPreReduceByPromise;
exports.responsePreReduceByPromise = privateFun.responsePreReduceByPromise;

187
app/request/libs/common.js Normal file
View File

@ -0,0 +1,187 @@
/**
* @name 通用方法
* @author 广州银云信息科技有限公司
*/
'use strict';
let _LibsDataConstructor = new (require('./data_constructor').core)();
let xml2json = require('xml2js');
let privateFun = {};
const LOCAL_REGEXP_CONST = 'eoundefined$';
privateFun.deepCopy = (inputObject) => {
try {
return JSON.parse(JSON.stringify(inputObject));
} catch (JSON_STRINGIFY_ERROR) {
return inputObject;
}
};
/**
* @desc 解析请求信息组合成合适的对象
* @param [object] inputData 原始待组合对象
* @return [object]
*/
privateFun.parseRequestDataToObj = (inputData) => {
let tmpOutputObj = {
restParams: inputData.restParams,
queryParams: inputData.queryParams,
requestBody: null,
},
tmpRequestBody = inputData.requestBody.body;
try {
switch (inputData.requestType) {
case '2': {
tmpRequestBody = JSON.parse(tmpRequestBody);
break;
}
case '3': {
xml2json.parseString(
tmpRequestBody,
{
explicitArray: false,
ignoreAttrs: true,
},
function (error, result) {
if (!error) {
tmpRequestBody = result;
}
}
);
break;
}
case '1': {
tmpOutputObj.raw = tmpRequestBody;
tmpRequestBody = {
raw: tmpRequestBody,
};
break;
}
case '4': {
tmpOutputObj.binary = tmpRequestBody;
tmpRequestBody = {
binary: tmpRequestBody,
};
break;
}
}
} catch (PARSE_REQUEST_BODY_DATA_ERR) {
console.error(new Date() + 'PARSE_REQUEST_BODY_DATA_ERR', PARSE_REQUEST_BODY_DATA_ERR);
}
tmpOutputObj.requestBody = tmpRequestBody;
return tmpOutputObj;
};
privateFun.bodyQueryToJson = function (inputArray, inputOptions) {
inputOptions = inputOptions || {
apiRequestParamJsonType: 0
}
let tmpXmlAttrObj={};
let tmpJsonObj=_LibsDataConstructor.eo_define_arr_to_json(inputArray, {},inputOptions,tmpXmlAttrObj);
if(inputOptions.isXml){
return {
value:JSON.stringify(tmpJsonObj),
attr:tmpXmlAttrObj
}
}
if ((inputOptions.apiRequestParamJsonType || 0).toString() == '1') {
return JSON.stringify([tmpJsonObj]).replace(/("eo_big_int_)(((?!").)*)(")/g,"$2");
} else {
return JSON.stringify(tmpJsonObj).replace(/("eo_big_int_)(((?!").)*)(")/g,"$2");
}
}
/**
* 解析环境变量
* @param {array} env 环境变量
* @return object 返回环境
*/
privateFun.parseEnv = function (env) {
env = env || {};
//设置全局的配置环境变量、全局脚本、环境ID、环境名称
let tmpConf = {
envID: env.envID || 0,
envName: env.envName || '',
envParam: {},
startup: env.globalBeforeProcess || '',
teardown: env.globalAfterProcess || '',
envAuth: env.envAuth || {
status: '0',
},
};
//处理全局变量
try {
for (let val of env.paramList) {
if (val.paramKey)
tmpConf.envParam[val.paramKey] = JSON.stringify(val.paramValue || '')
.replace(/^"/, '')
.replace(/"$/, '');
}
} catch (MAP_ERR) {}
//轮询协议,设置协议配置
let tmpProtocolRef = ['http', 'socket', 'websocket', 'rpc'],
tmpIsLessThan780 = !env.hasOwnProperty('socket');
let tmpBuildArr = [
{
origin: 'additionalParamList',
target: 'extraFormDataParam',
key: 'paramKey',
value: 'paramValue',
},
{
origin: 'urlParamList',
target: 'queryParam',
key: 'paramKey',
value: 'paramValue',
},
{
origin: 'headerList',
target: 'headerParam',
key: 'headerName',
value: 'headerValue',
},
];
for (let key of tmpProtocolRef) {
let tmpEnvItem = (tmpIsLessThan780 || key === 'http' ? env : env[key]) || {};
let tmpItem = {
baseUrlParam: tmpEnvItem.host || tmpEnvItem.frontURI || '',
headerParam: {},
extraFormDataParam: {},
queryParam: {},
requestScript: tmpEnvItem.beforeInject || '',
responseScript: tmpEnvItem.afterInject || '',
};
if (tmpEnvItem.hasOwnProperty('connectInject')) {
tmpItem.connectInject = tmpEnvItem.connectInject || '';
}
tmpBuildArr.map((item) => {
if (tmpEnvItem[item.origin]) {
tmpEnvItem[item.origin].map((val) => {
if (val[item.key]) tmpItem[item.target][val[item.key]] = val[item.value] || '';
});
}
});
tmpConf[key] = tmpItem;
}
return tmpConf;
};
/**
* merge对象数据
* @param {object} inputTargetItem 目标对象
* @param {object} inputSourceItem 源对象
* @returns {object} 已合并输出对象
*/
privateFun.mergeObj = (inputTargetItem, inputSourceItem) => {
let tmpOutputObj = privateFun.deepCopy(inputTargetItem);
for (let key in inputSourceItem) {
if (tmpOutputObj[key] || tmpOutputObj[key] === 0 || tmpOutputObj[key] === null || tmpOutputObj[key] === false)
continue;
tmpOutputObj[key] = inputSourceItem[key];
}
return tmpOutputObj;
};
exports.mergeObj = privateFun.mergeObj;
exports.parseEnv = privateFun.parseEnv;
exports.deepCopy = privateFun.deepCopy;
exports.parseRequestDataToObj = privateFun.parseRequestDataToObj;
exports.bodyQueryToJson = privateFun.bodyQueryToJson;
exports.LOCAL_REGEXP_CONST=LOCAL_REGEXP_CONST;
exports.replaceAll = function () {
return _LibsDataConstructor.text_replace_all(...arguments);
};

View File

@ -0,0 +1,215 @@
(() => {
'use strict';
/**
* @name 信息构造器类
* @author 广州银云信息科技有限公司
*/
class main {
constructor() {
this.DEFAULT_REFS_FROM_EO_TYPE = {
"8": "false",
"12": "[]",
"13": "{}",
"14": "0",
"15": "null"
};
}
/**
* @desc eolinker自定义格式转换为json
* @param {array} input_eo_original_arr 原始 eo 定义队列
* @param {object} input_parent_obj 父对象
* @param {object} input_opts 可选配置项 {needToParseBindData:是否特殊解析定义字符串,isXml:组装内容是否为xml,bindObj:绑定对象,fnSetXmlAttr:xml属性处理函数}
* @param {object} input_xml_attr_parent_obj 可选配置项当且仅当构造对象为xml时生效为xml父属性继承对象
* @return {object} json字符串
*
*/
eo_define_arr_to_json(input_eo_original_arr, input_parent_obj={}, input_opts={}, input_xml_attr_parent_obj={}) {
let vm = this;
input_eo_original_arr.map(function (val) {
if (!val.paramKey || !val.checkbox) {
return;
}
try {
if (input_opts.needToParseBindData) {
val.paramKey = vm.construct_text_by_express_builder(vm.replace_text_from_bind_obj(val.paramKey, input_opts.bindObj));
val.paramInfo = vm.construct_text_by_express_builder(vm.replace_text_from_bind_obj(val.paramInfo || val.paramValue || '', input_opts.bindObj));
if (input_opts.isXml) val.attribute = vm.construct_text_by_express_builder(vm.replace_text_from_bind_obj(val.attribute || "", input_opts.bindObj));
} else {
val.paramKey = vm.construct_text_by_express_builder(val.paramKey);
val.paramInfo = vm.construct_text_by_express_builder(val.paramInfo || val.paramValue || '');
if (input_opts.isXml) val.attribute = vm.construct_text_by_express_builder(val.attribute || "");
}
} catch (BIND_PARSE_ERROR) {}
let tmp_value = input_parent_obj[val.paramKey] = val.paramInfo || val.paramValue || '';
if (input_opts.isXml) input_xml_attr_parent_obj[val.paramKey] = val.attribute || "";
if (val.childList && val.childList.length > 0) {
if (input_opts.isXml) input_xml_attr_parent_obj[val.paramKey] = [input_xml_attr_parent_obj[val.paramKey], {}];
let tmp_cb_result;
switch (val.paramType.toString()) {
case '12': { //array
if((val.childList[0]||{}).isArrItem){
//新数据结构,多项值数组
input_parent_obj[val.paramKey] = [];
tmp_cb_result={has_text:true};//设置tmp_cb_result用于确认当前数组已经有内容无需重新json_parse
val.childList.map((tmp_child_item,tmp_child_key)=>{
if(!tmp_child_item.checkbox)return;
let tmp_item_parent_obj={},tmp_item_xml_attr_parent_obj={};
if(tmp_child_item.paramType.toString()==="12"||!(tmp_child_item.childList&&tmp_child_item.childList.length>0)){
vm.eo_define_arr_to_json([tmp_child_item], tmp_item_parent_obj, input_opts, input_opts.isXml ? tmp_item_xml_attr_parent_obj : {});
tmp_item_parent_obj=tmp_item_parent_obj[tmp_child_item.paramKey];
tmp_item_xml_attr_parent_obj=tmp_item_xml_attr_parent_obj[tmp_child_item.paramKey];
}else{
vm.eo_define_arr_to_json(tmp_child_item.childList, tmp_item_parent_obj, input_opts, input_opts.isXml ? tmp_item_xml_attr_parent_obj : {});
}
input_parent_obj[val.paramKey].push(tmp_item_parent_obj);
if (input_opts.isXml) {
if(typeof input_xml_attr_parent_obj[val.paramKey][0] !=="object")input_xml_attr_parent_obj[val.paramKey][0]=[];
input_xml_attr_parent_obj[val.paramKey][0].push(tmp_child_item.attribute||"");
input_xml_attr_parent_obj[val.paramKey].splice(tmp_child_key+1,1,tmp_item_xml_attr_parent_obj);
}
})
}else{
//为老数据第一项数值不存在字段isArrItem
input_parent_obj[val.paramKey] = [{}];
tmp_cb_result = vm.eo_define_arr_to_json(val.childList, input_parent_obj[val.paramKey][0], input_opts, input_opts.isXml ? input_xml_attr_parent_obj[val.paramKey][1] : {});
}
break;
}
default: {
input_parent_obj[val.paramKey] = {};
tmp_cb_result = vm.eo_define_arr_to_json(val.childList, input_parent_obj[val.paramKey], input_opts, input_opts.isXml ? input_xml_attr_parent_obj[val.paramKey][1] : {});
break;
}
}
if (vm.check_empty_obj(tmp_cb_result)) {
try {
input_parent_obj[val.paramKey] = JSON.parse(tmp_value);
} catch (JSON_PARSE_ERROR) {
input_parent_obj[val.paramKey] = tmp_value;
}
}
} else {
let tmp_param_type = val.paramType.toString();
switch (tmp_param_type) {
case '0': { //字符串
break;
}
case '15': { //null
input_parent_obj[val.paramKey] = null;
}
case '14': { //number
let tmp_num_text = input_parent_obj[val.paramKey] || vm.DEFAULT_REFS_FROM_EO_TYPE[tmp_param_type];
if (input_opts.isXml) {
input_parent_obj[val.paramKey] = `${tmp_num_text}`;
} else {
try {
if (JSON.parse(tmp_num_text) > Number.MAX_SAFE_INTEGER) {
input_parent_obj[val.paramKey] = `eo_big_int_${tmp_num_text}`;
} else {
input_parent_obj[val.paramKey] = JSON.parse(tmp_num_text);
}
} catch (JSON_PARSE_ERROR) {
input_parent_obj[val.paramKey] = `${tmp_num_text}`;
}
}
break;
}
default: { //其他
let tmp_default_value = input_parent_obj[val.paramKey] || vm.DEFAULT_REFS_FROM_EO_TYPE[tmp_param_type];
try {
input_parent_obj[val.paramKey] = JSON.parse(tmp_default_value);
} catch (JSON_PARSE_ERROR) {
input_parent_obj[val.paramKey] = `${tmp_default_value}`;
}
break;
}
}
}
if (input_opts.isXml && input_opts.fnSetXmlAttr && val.attribute) {
input_opts.fnSetXmlAttr(val.paramKey, val.attribute);
}
})
return input_parent_obj;
}
/**
* @desc 绑定管理解析
* @param {string} input_old_text 源数据
* @param {object} input_bind_obj 待解析的绑定对象
* @return {string} 替换绑定变量后的字符串
*/
replace_text_from_bind_obj(input_old_text, input_bind_obj) {
let vm = this;
if (!input_bind_obj) return input_old_text;
input_old_text = input_old_text || "";
let response = input_bind_obj.response,
responseHeaders = input_bind_obj.responseHeaders,
requestBody = input_bind_obj.requestBody,
requestHeaders = input_bind_obj.requestHeaders,
restParams = input_bind_obj.restParams,
queryParams = input_bind_obj.queryParams;
let tmp_result = input_old_text,
tmp_fn_replace_bind_text = (tmp_input_mark, tmp_input_match_text_arr) => {
tmp_input_match_text_arr.map(function (val) {
let tmp_new_text = '';
try {
let tmp_header_key_end_index = val.indexOf("]"); //头部信息关键字结束字符
tmp_new_text = eval(/Headers/.test(tmp_input_mark) ? `${val.substring(1,val.indexOf("]"))}${val.substring(tmp_header_key_end_index,val.length - 1).toLowerCase()}` : val.substring(1, val.length - 1));
if (tmp_new_text === undefined) {
tmp_new_text = 'NULL';
} else if (typeof tmp_new_text == 'object') {
tmp_new_text = JSON.stringify(tmp_new_text);
}
} catch (EVAL_ERR) {
tmp_new_text = 'NULL';
}
tmp_result = vm.text_replace_all('.' + val + '.', tmp_new_text, tmp_result);
tmp_result = vm.text_replace_all('.' + val, tmp_new_text, tmp_result);
tmp_result = vm.text_replace_all(val + '.', tmp_new_text, tmp_result);
tmp_result = vm.text_replace_all(val, tmp_new_text, tmp_result);
})
return
}
tmp_fn_replace_bind_text('requestBody', input_old_text.trim().match(/(<requestBody[.\[])((?!(>)).)*(>)/g) || []);
tmp_fn_replace_bind_text('requestHeaders', input_old_text.trim().match(/(<requestHeaders[.\[])((?!(>)).)*(>)/g) || []);
tmp_fn_replace_bind_text('restParams', input_old_text.trim().match(/(<restParams[.\[])((?!(>)).)*(>)/g) || []);
tmp_fn_replace_bind_text('queryParams', input_old_text.trim().match(/(<queryParams[.\[])((?!(>)).)*(>)/g) || []);
tmp_fn_replace_bind_text('responseHeaders', input_old_text.trim().match(/(<responseHeaders[.\[])((?!(>)).)*(>)/g) || []);
tmp_fn_replace_bind_text('response', input_old_text.trim().match(/(<response[.\[])((?!(>)).)*(>)/g) || []);
return tmp_result;
}
/**
* 文本替换全部
* @param {string} input_old_text 被替换文本
* @param {string} input_new_text 替换文本
* @param {any} input_text 源数据
*/
text_replace_all(input_old_text, input_new_text, input_text) {
if (input_old_text === input_new_text) return input_text;
let tmp_text = input_text || "";
if (typeof tmp_text !== "string") {
try{
tmp_text = JSON.stringify(tmp_text);
return JSON.parse(tmp_text.split(input_old_text).join(input_new_text));
}catch(JSON_ERR){
}
}
return tmp_text.split(input_old_text).join(input_new_text);
}
/**
* @desc 表达式构造器
* @param {*} input_text
* @returns {string} 构造后内容
*/
construct_text_by_express_builder(input_text) {
return input_text;
}
check_empty_obj(input_check_obj) {
for (let key in input_check_obj) {
return false;
}
return true;
}
}
exports.core = main;
})()

534
app/request/libs/encrypt.js Normal file
View File

@ -0,0 +1,534 @@
(function () {
'use strict';
let Crypto = require('crypto');
let CryptoJS = require('crypto-js');
let privateFun = {};
let publicFun = {};
const TIMINGSUMMARY = {
NS_PER_SEC: 1e9,
MS_PER_NS: 1e6,
};
/**
* @desc AES/DES解密
* @param {string} inputMode 选择模式
* @param {string} inputKey 加密密钥
* @param {string} inputData 待加密数据
* @param {object} inputOpts 配置项,padding/iv/mode
* @return {string} 结果字符串
*/
privateFun.aesOrDesAndEncryptOrDecrypt=(inputMode,inputData, inputKey, inputOpts)=>{
if (inputOpts) {
inputOpts=Object.assign({},inputOpts);
if (inputOpts.mode) inputOpts.mode = CryptoJS.mode[inputOpts.mode];
if (inputOpts.padding) inputOpts.padding = CryptoJS.pad[inputOpts.padding];
if(inputOpts.iv)inputOpts.iv=CryptoJS.enc.Latin1.parse(inputOpts.iv || "")
}
inputKey=CryptoJS.enc.Latin1.parse(inputKey || "");
let tmpType=inputMode.split("-")[0],tmpOpr=inputMode.split("-")[1];
switch(tmpOpr){
case "decrypt":{
return CryptoJS[tmpType].decrypt(inputData, inputKey, inputOpts).toString(CryptoJS.enc.Utf8);
}
case "encrypt":{
return CryptoJS[tmpType].encrypt(inputData, inputKey, inputOpts).toString();
}
}
}
/**
* @desc AES/DES解密
* @param {string} inputKey 加密密钥
* @param {string} inputData 待加密数据
* @param {object} inputOpts 配置项,padding/iv/mode
* @return {string} 解密后字符串
*/
publicFun.aesDecrypt = (inputData, inputKey, inputOpts) => {
return privateFun.aesOrDesAndEncryptOrDecrypt("AES-decrypt",inputData, inputKey, inputOpts);
}
publicFun.desDecrypt = (inputData, inputKey, inputOpts) => {
return privateFun.aesOrDesAndEncryptOrDecrypt("DES-decrypt",inputData, inputKey, inputOpts);
}
/**
* @desc AES/DES加密
* @param {string} inputKey 加密密钥
* @param {string} inputData 待加密数据
* @param {object} inputOpts 配置项,padding/iv/mode
* @return {string} 加密后字符串
*/
publicFun.aesEncrypt = (inputData, inputKey, inputOpts) => {
return privateFun.aesOrDesAndEncryptOrDecrypt("AES-encrypt",inputData, inputKey, inputOpts);
}
publicFun.desEncrypt = (inputData, inputKey, inputOpts) => {
return privateFun.aesOrDesAndEncryptOrDecrypt("DES-encrypt",inputData, inputKey, inputOpts);
}
/**
* @description
*/
privateFun.createEcdsa = () => {
var MAX_OCTET = 0x80,
CLASS_UNIVERSAL = 0,
PRIMITIVE_BIT = 0x20,
TAG_SEQ = 0x10,
TAG_INT = 0x02,
ENCODED_TAG_SEQ = (TAG_SEQ | PRIMITIVE_BIT) | (CLASS_UNIVERSAL << 6),
ENCODED_TAG_INT = TAG_INT | (CLASS_UNIVERSAL << 6);
function getParamSize(keySize) {
switch (keySize) {
case 512: {
keySize = 521;
break;
}
default: {
break;
}
}
var result = ((keySize / 8) | 0) + (keySize % 8 === 0 ? 0 : 1);
return result;
}
function derToJose(signature, bits) {
signature = Buffer.from(signature, 'base64');
var paramBytes = getParamSize(parseInt(bits));
var maxEncodedParamLength = paramBytes + 1;
var inputLength = signature.length;
var offset = 0;
if (signature[offset++] !== ENCODED_TAG_SEQ) {
throw new Error('Could not find expected "seq"');
}
var seqLength = signature[offset++];
if (seqLength === (MAX_OCTET | 1)) {
seqLength = signature[offset++];
}
if (inputLength - offset < seqLength) {
throw new Error('"seq" specified length of "' + seqLength + '", only "' + (inputLength - offset) + '" remaining');
}
if (signature[offset++] !== ENCODED_TAG_INT) {
throw new Error('Could not find expected "int" for "r"');
}
var rLength = signature[offset++];
if (inputLength - offset - 2 < rLength) {
throw new Error('"r" specified length of "' + rLength + '", only "' + (inputLength - offset - 2) + '" available');
}
if (maxEncodedParamLength < rLength) {
throw new Error('"r" specified length of "' + rLength + '", max of "' + maxEncodedParamLength + '" is acceptable');
}
var rOffset = offset;
offset += rLength;
if (signature[offset++] !== ENCODED_TAG_INT) {
throw new Error('Could not find expected "int" for "s"');
}
var sLength = signature[offset++];
if (inputLength - offset !== sLength) {
throw new Error('"s" specified length of "' + sLength + '", expected "' + (inputLength - offset) + '"');
}
if (maxEncodedParamLength < sLength) {
throw new Error('"s" specified length of "' + sLength + '", max of "' + maxEncodedParamLength + '" is acceptable');
}
var sOffset = offset;
offset += sLength;
if (offset !== inputLength) {
throw new Error('Expected to consume entire buffer, but "' + (inputLength - offset) + '" bytes remain');
}
var rPadding = paramBytes - rLength,
sPadding = paramBytes - sLength;
var dst = Buffer.allocUnsafe(rPadding + rLength + sPadding + sLength);
for (offset = 0; offset < rPadding; ++offset) {
dst[offset] = 0;
}
signature.copy(dst, offset, rOffset + Math.max(-rPadding, 0), rOffset + rLength);
offset = paramBytes;
for (var o = offset; offset < o + sPadding; ++offset) {
dst[offset] = 0;
}
signature.copy(dst, offset, sOffset + Math.max(-sPadding, 0), sOffset + sLength);
dst = dst.toString('base64');
dst = publicFun.setBase64Url(dst);
return dst;
}
return function (bits, message, secretKey) {
try {
var signature = publicFun.setBase64Url(privateFun.createSign('RSA-SHA' + bits, message, secretKey));
signature = derToJose(signature, bits);
return signature;
} catch (e) {
console.error(new Date() + 'libs/encrypt.js122ES 签名错误):' + e);
return 'EcdsaError';
}
}
}
/**
* @description 公用加密算法create sign
* @param [string] encryption 加密方式
* @param [string] message 待加密内容
* @param [string] secretKey 密钥
* @param [object] options 配置可选项
* @returns [string] 已加密内容
*/
privateFun.createSign = function (encryption, message, secretKey, options) {
options = options || {
hash: 'base64'
};
let sign = Crypto.createSign(encryption);
sign.update(message || '', 'utf8');
try {
if(typeof secretKey==="object"&& typeof secretKey.padding ==="string"){
secretKey.padding=Crypto.constants[secretKey.padding];
}
return sign.sign(secretKey, options.hash);
} catch (e) {
return 'SignError';
}
}
/**
* @description 公用加密算法createHash
* @param [string] encryption 加密方式
* @param [string] message 待加密内容
* @param [object] options
* @returns [string] 已加密内容
*/
privateFun.createHash = function (encryption, message, options) {
options = options || {
hash: 'hex'
};
return Crypto.createHash(encryption).update(message || '').digest(options.hash);
}
/**
* @description 公用加密算法createHmac
* @param [string] encryption 加密方式
* @param [string] message 待加密内容
* @returns [string] 已加密内容
*/
privateFun.createHmac = function (encryption, message, key, options) {
options = options || {
hash: 'hex'
};
return Crypto.createHmac(encryption, key || '').update(message || '').digest(options.hash);
}
/**
* md5数据加密
* @param {string} info 需加密信息体
* return {string} md5加密后信息
*/
publicFun.md5 = function (info) {
return privateFun.createHash('md5', info);
}
/**
* HmacSHA1数据加密
* @param {string} info 需加密信息体
* @param {string} key 密钥
* @param {object} options 配置
* return {string} HmacSHA1加密后信息
*/
publicFun.HmacSHA1 = function (info, key, options) {
return privateFun.createHmac('sha1', info, key, options);
}
/**
* HmacSHA256数据加密
* @param {string} info 需加密信息体
* @param {string} key 密钥
* @param {object} options 配置
* return {string} HmacSHA256加密后信息
*/
publicFun.HmacSHA256 = function (info, key, options) {
return privateFun.createHmac('sha256', info, key, options);
}
/**
* HmacSHA224
* @param {string} info 需加密信息体
* @param {string} key 密钥
* @param {object} options 配置
* return {string} HmacSHA224加密后信息
*/
publicFun.HmacSHA224 = function (info, key, options) {
return privateFun.createHmac('sha224', info, key, options);
}
/**
* HmacSHA384
* @param {string} info 需加密信息体
* @param {string} key 密钥
* @param {object} options 配置
* return {string} HmacSHA384加密后信息
*/
publicFun.HmacSHA384 = function (info, key, options) {
return privateFun.createHmac('sha384', info, key, options);
}
/**
* HmacSHA512
* @param {string} info 需加密信息体
* @param {string} key 密钥
* @param {object} options 配置
* return {string} HmacSHA512加密后信息
*/
publicFun.HmacSHA512 = function (info, key, options) {
return privateFun.createHmac('sha512', info, key, options);
}
/**
* sha1数据加密
* @param {string} info 需加密信息体
* @param {object} options 配置
* return {string} sha1加密后信息
*/
publicFun.sha1 = function (info, options) {
return privateFun.createHash('sha1', info, options);
}
/**
* sha256数据加密
* @param {string} info 需加密信息体
* @param {object} options 配置
* return {string} sha256加密后信息
*/
publicFun.sha256 = function (info, options) {
return privateFun.createHash('sha256', info, options);
}
/**
* sha224
* @param {string} info 需加密信息体
* @param {object} options 配置
* return {string} sha224加密后信息
*/
publicFun.sha224 = function (info, options) {
return privateFun.createHash('sha224', info, options);
}
/**
* sha384
* @param {string} info 需加密信息体
* @param {object} options 配置
* return {string} sha384加密后信息
*/
publicFun.sha384 = function (info, options) {
return privateFun.createHash('sha384', info, options);
}
/**
* sha512
* @param {string} info 需加密信息体
* @param {object} options 配置
* return {string} sha512加密后信息
*/
publicFun.sha512 = function (info, options) {
return privateFun.createHash('sha512', info, options);
}
/**
* RS256
* @param {string} info 需加密信息体
* @param {string} priviteKey 私钥
* @param {object} options 配置
* return {string} RS256加密后信息
*/
publicFun.RS256 = function (info, privateKey, options) {
if (typeof options === "string") {
options = {
hash: options
}
}
return privateFun.createSign('RSA-SHA256', info, privateKey, options);
}
/**
* RS384
* @param {string} info 需加密信息体
* @param {string} priviteKey 私钥
* @param {object} options 配置
* return {string} RS384加密后信息
*/
publicFun.RS384 = function (info, privateKey, options) {
return privateFun.createSign('RSA-SHA384', info, privateKey, options);
}
/**
* RS512
* @param {string} info 需加密信息体
* @param {string} priviteKey 私钥
* @param {object} options 配置
* return {string} RS512加密后信息
*/
publicFun.RS512 = function (info, privateKey, options) {
return privateFun.createSign('RSA-SHA512', info, privateKey, options);
}
/**
* RS1
* @param {string} info 需加密信息体
* @param {string} priviteKey 私钥
* @param {object} options 配置
* return {string} RSA-SHA1加密后信息
*/
publicFun.RS1 = function (info, privateKey, options) {
if (typeof options === "string") {
options = {
hash: options
}
}
return privateFun.createSign('RSA-SHA1', info, privateKey, options);
}
/**
* ES256
* @param {string} info 需加密信息体
* @param {string} priviteKey 私钥
* @param {object} options 配置
* return {string} ES256加密后信息
*/
publicFun.ES256 = function (info, privateKey, options) {
return privateFun.createEcdsa()('256', info, privateKey, options);
}
/**
* ES384
* @param {string} info 需加密信息体
* @param {string} priviteKey 私钥
* @param {object} options 配置
* return {string} ES384加密后信息
*/
publicFun.ES384 = function (info, privateKey, options) {
return privateFun.createEcdsa()('384', info, privateKey, options);
}
/**
* ES512
* @param {string} info 需加密信息体
* @param {string} priviteKey 私钥
* @param {object} options 配置
* return {string} ES512加密后信息
*/
publicFun.ES512 = function (info, privateKey, options) {
return privateFun.createEcdsa()('512', info, privateKey, options);
}
/**
* base64 to base64Url
* @param {string} info 需转换信息体
* return {string} base64Url 信息体
*/
publicFun.setBase64Url = function (info) {
return info.replace(/=/g, '')
.replace(/\+/g, '-')
.replace(/\//g, '_');
}
/**
* String/object to base64
* @param {string/object} info 需转换信息体
* @param {object} options 可选项
* return {string} base64 信息体
*/
publicFun.stringToBase64 = function (info, options) {
options = options || {
toUrl: false
}
let output = '';
switch (typeof info) {
case 'string': {
output = info;
break;
}
default: {
output = JSON.stringify(info);
break;
}
}
output = Buffer.from(output).toString('base64');
if (options.toUrl) {
return publicFun.setBase64Url(output);
}
return output;
}
/**
* uuid生成器
* return {string} uuid
*/
publicFun.uuidGeneration = function (info, options) {
var template = {
array: [],
hexSingle: "0123456789abcdef"
}
for (var i = 0; i < 36; i++) {
template.array[i] = template.hexSingle.substr(Math.floor(Math.random() * 0x10), 1);
}
template.array[14] = "4";
template.array[19] = template.hexSingle.substr((template.array[19] & 0x3) | 0x8, 1);
template.array[8] = template.array[13] = template.array[18] = template.array[23] = "-";
return template.array.join("");
}
publicFun.getMicrosToMsStr = (inputStartTime, inputEndTime) => {
if (inputStartTime === undefined || inputEndTime === undefined) return "0.00";
let tmpSecondDiff = inputEndTime[0] - inputStartTime[0]
let tmpNanoSecondDiff = inputEndTime[1] - inputStartTime[1]
let tmpDiffInNanoSecond = tmpSecondDiff * TIMINGSUMMARY.NS_PER_SEC + tmpNanoSecondDiff;
let tmpOutput = tmpDiffInNanoSecond / TIMINGSUMMARY.MS_PER_NS;
if (tmpOutput < 0) {
return "0.00"
} else {
return "" + tmpOutput.toFixed(2)
}
}
/**
* @desc RSA 公私钥 加密
* @param {string/object} inputKey 密钥
* @param {string} inputData 待处理数据
* @param {object} inputHash 结果的编码格式,base64(默认)/hex
* @return {string} 结果字符串
*/
publicFun.rsaPublicEncrypt = ( inputKey,inputData, inputHash="base64") => {
if(typeof inputKey==="object"&& typeof inputKey.padding ==="string"){
inputKey.padding=Crypto.constants[inputKey.padding];
}
return Crypto.publicEncrypt(inputKey,new Buffer.from(inputData, 'utf8')).toString(inputHash);
}
publicFun.rsaPrivateEncrypt = (inputKey,inputData, inputHash="base64") => {
if(typeof inputKey==="object"&& typeof inputKey.padding ==="string"){
inputKey.padding=Crypto.constants[inputKey.padding];
}
return Crypto.privateEncrypt(inputKey,new Buffer.from(inputData, 'utf8')).toString(inputHash);
}
/**
* @desc RSA 公私钥 解密
* @param {string/object} inputKey 密钥
* @param {string} inputData 待处理数据
* @param {object} inputHash 结果的编码格式,base64(默认)/hex
* @return {string} 结果字符串
*/
publicFun.rsaPublicDecrypt = ( inputKey, inputData,inputHash="base64") => {
if(typeof inputKey==="object"&& typeof inputKey.padding ==="string"){
inputKey.padding=Crypto.constants[inputKey.padding];
}
return Crypto.publicDecrypt(inputKey, new Buffer.from(inputData, inputHash)).toString("utf-8");
}
publicFun.rsaPrivateDecrypt = (inputKey,inputData, inputHash="base64") => {
if(typeof inputKey==="object"&& typeof inputKey.padding ==="string"){
inputKey.padding=Crypto.constants[inputKey.padding];
}
return Crypto.privateDecrypt(inputKey, new Buffer.from(inputData, inputHash)).toString("utf-8");
}
exports.core = publicFun;
})();

View File

@ -0,0 +1,491 @@
(function () {
'use strict';
let _RedirectClass = require('./redirect');
let _ApiUtil = require('./apiUtil');
let _LibsCommon = require('./common');
let _HttpPackageClass = new (require('./http.package').core)();
const CONFIG = require('../config.json');
let url = require('url'),
querystring = require('querystring');
class Main {
constructor(input_args, input_callback) {
if (Object.prototype.toString.call(input_args) === '[object SharedArrayBuffer]') {
global._WORKER_DATA = input_args;
return;
}
try {
switch (input_args.opr) {
case 'exec_http': {
this.execute(input_args.data, input_args.env, input_args.opts, null, (tmp_input_res) => {
this.wakeTopThread(tmp_input_res);
});
break;
}
}
} catch (EXEC_ERR) {
console.error(EXEC_ERR);
this.wakeTopThread(EXEC_ERR.stack || EXEC_ERR);
}
return this.EXEC_RESULT;
}
//执行ajax http请求
async execute(input_test_data, input_env, input_opts, input_callback, input_return_callback) {
let tmp_request_script_data = {};
input_test_data = _LibsCommon.deepCopy(input_test_data);
input_env = input_env || _LibsCommon.parseEnv();
let tmp_target_type_env = input_env.http;
if (input_test_data.requestScript || tmp_target_type_env.requestScript) {
tmp_request_script_data = _ApiUtil.scriptExecuteBeforeCode(
input_test_data,
input_test_data.requestScript || '',
{
env: input_env,
fnCodeArr: input_opts.fnCodeArr,
}
);
if (tmp_request_script_data.status === 'success') {
input_test_data = tmp_request_script_data.data;
input_env = tmp_request_script_data.env;
}
}
tmp_target_type_env = input_env.http;
if (input_test_data.timelimit === 'follow') {
input_test_data.timelimit = global._TIMEOUTLIMIT || CONFIG.MAX_TIME_LIMIT;
input_test_data.timelimitType = global._TIMEOUTLIMITTYPE || 'totalTime';
}
let tmp_result;
await new Promise(function (resolve, reject) {
let tmp_report_data = {
reportList: tmp_request_script_data.reportList || [],
response: '',
},
tmp_response_str = '';
if (!input_test_data.hasOwnProperty('params') && input_test_data.hasOwnProperty('body')) {
input_test_data.params = input_test_data.body;
input_test_data.isBody = true;
}
if (Object.prototype.toString.call(input_test_data.params) === '[object Array]') {
input_test_data.params = input_test_data.params;
} else if (typeof input_test_data.params == 'object') {
input_test_data.params = Object.assign({}, tmp_target_type_env.extraFormDataParam, input_test_data.params);
} else {
input_test_data.params = (input_test_data.params || '').toString();
}
input_test_data.headers = Object.assign({}, tmp_target_type_env.headerParam, input_test_data.headers || {});
let template = {
urlObject: {},
matchUrlArray: [],
chunk: {
array: [],
length: 0,
},
queryParam: [],
jwt: '',
},
tmp_test_data = _ApiUtil.parseApiByEnvGlobalParam(input_test_data, input_env.envParam),
tmp_ajax_xhr,
tmp_post_data,
tmp_multi_form;
tmp_test_data.url = _ApiUtil.parseUri(tmp_test_data.url, tmp_target_type_env.baseUrlParam);
template.queryParam = url.parse(tmp_test_data.url).query || [];
input_env.envAuth = input_env.envAuth || {};
switch (input_env.envAuth.status) {
case '1': {
if (input_env.envAuth.basicAuth) {
tmp_test_data.headers['Authorization'] =
'Basic ' +
Buffer.from(
(input_env.envAuth.basicAuth.username || '') + ':' + (input_env.envAuth.basicAuth.password || '')
).toString('base64');
}
break;
}
case '2': {
template.jwt = _LibsCommon.jwt(
{
alg: input_env.envAuth.jwtAuth.alg,
typ: 'JWT',
},
input_env.envAuth.jwtAuth.payload,
input_env.envAuth.jwtAuth.secretSalt
);
if (template.jwt == 'jwtError') {
throw 'jwtError';
} else if (input_env.envAuth.jwtAuth.isBearer) {
template.jwt = `Bearer ${template.jwt}`;
}
switch (input_env.envAuth.jwtAuth.position) {
case 'header': {
tmp_test_data.headers[input_env.envAuth.jwtAuth.tokenName || 'tokenName'] = template.jwt;
break;
}
case 'query': {
if (tmp_test_data.url.indexOf('?') > -1) {
tmp_test_data.url +=
(template.queryParam.length > 0 ? '&' : '') +
(input_env.envAuth.jwtAuth.tokenName || 'tokenName') +
'=' +
template.jwt;
} else {
tmp_test_data.url += '?' + (input_env.envAuth.jwtAuth.tokenName || 'tokenName') + '=' + template.jwt;
}
break;
}
}
break;
}
}
let tmp_query_str = querystring.stringify(
Object.assign({}, tmp_target_type_env.queryParam, querystring.parse(url.parse(tmp_test_data.url).query))
);
if (tmp_query_str) {
let tmp_url_param_index = tmp_test_data.url.indexOf('?');
if (tmp_url_param_index > -1) {
tmp_test_data.url = `${tmp_test_data.url.substr(0, tmp_url_param_index)}?${tmp_query_str}`;
} else {
tmp_test_data.url = `${tmp_test_data.url}?${tmp_query_str}`;
}
}
template.urlObject = url.parse(tmp_test_data.url);
let tmp_test_opts = {
path: template.urlObject.path,
hostname: template.urlObject.hostname,
port: template.urlObject.port,
protocol: template.urlObject.protocol,
headers: tmp_test_data.headers,
method: input_test_data.method || 'GET',
};
if (/"content-type":"multipart\/form-data/i.test(JSON.stringify(tmp_test_data.headers))) {
tmp_test_data.isMuti = true;
}
tmp_post_data = tmp_test_data.params;
if (input_test_data.bodyType !== 'binary') {
tmp_report_data.requestBody = {
body: tmp_test_data.params,
requestType: typeof tmp_post_data == 'string' ? 1 : 0,
};
if (tmp_test_data.isMuti) {
let tmpMutiCallbackObj = _ApiUtil.parseRequestBody(tmp_post_data);
tmp_multi_form = tmpMutiCallbackObj.class;
tmp_report_data.requestBody.body =
typeof tmp_test_data.params == 'object' ? tmpMutiCallbackObj.params : tmp_post_data;
} else {
tmp_post_data =
typeof tmp_post_data == 'object' ? querystring.stringify(tmp_post_data || {}) : tmp_post_data;
}
} else {
tmp_report_data.requestBody = {
body: `[binary]${tmp_test_data.binaryFileName}`,
requestType: 1,
};
}
try {
tmp_report_data.general = {
redirectTimes: 0,
downloadSize: 0,
downloadRate: 0,
requestUrl: tmp_test_data.url,
requestMethod: tmp_test_opts.method,
name: input_test_data.name,
timeLimit: input_test_data.timelimit,
};
if (input_test_data.timelimit > CONFIG.MAX_TIME_LIMIT || !input_test_data.timelimit) {
input_test_data.timelimit = CONFIG.MAX_TIME_LIMIT;
}
tmp_report_data.requestHeaders = tmp_test_opts.headers;
if (tmp_test_data.isMuti) {
tmp_test_opts.headers = Object.assign({}, tmp_test_opts.headers, tmp_multi_form.getHeaders());
} else {
let tmpJsonStringifyHeaders = JSON.stringify(tmp_test_opts.headers);
if (!/"content-length":/i.test(tmpJsonStringifyHeaders)) {
tmp_test_opts.headers['Content-length'] = Buffer.byteLength(tmp_post_data);
}
if (!/"content-type":/i.test(tmpJsonStringifyHeaders)) {
tmp_test_opts.headers['Content-Type'] = tmp_test_data.contentType || 'application/x-www-form-urlencoded';
}
}
tmp_test_opts.headers = _HttpPackageClass.setCookieToHeaders(
tmp_test_opts.headers,
tmp_test_opts.hostname,
input_opts.globalHeader
);
if (tmp_request_script_data.status && tmp_request_script_data.status !== 'success') {
tmp_report_data.general.time = '0.00ms';
tmp_report_data.general.status = tmp_request_script_data.status;
tmp_report_data.errorReason = [tmp_request_script_data.msg];
if (input_callback) input_callback(tmp_report_data);
reject('error');
return;
}
let tmp_fn_check_is_illegal_url = (tmp_input_hostname, tmp_input_total_time) => {
let tmp_is_localhost = new RegExp(_LibsCommon.LOCAL_REGEXP_CONST).test(tmp_input_hostname);
if (!tmp_input_hostname || tmp_is_localhost) {
tmp_report_data.general.time = tmp_input_total_time.toFixed(2) + 'ms';
tmp_report_data.general.status = 'error';
if (input_callback) input_callback(tmp_report_data);
if (tmp_is_localhost) {
tmp_report_data.isLocal = true;
tmp_report_data.errorReason = [global.eoLang['63be68fa-31fc-498c-b49c-d3b6db10a95b']];
reject('localhost');
} else {
tmp_report_data.errorReason = [global.eoLang['d6fa1d73-6a43-477f-a6df-6752661c9df3']];
reject('illegal');
}
return true;
}
},
tmp_fn_parse_ajax_resolve = (tmp_input_total_time) => {
tmp_report_data.general.time = tmp_input_total_time.toFixed(2) + 'ms';
tmp_report_data.env = input_env;
if (input_callback) input_callback(tmp_report_data);
try {
return {
time: tmp_report_data.general.time,
code: tmp_report_data.general.statusCode,
response: tmp_response_str,
header: tmp_report_data.responseHeaders,
};
} catch (childE) {
return {
time: tmp_report_data.general.time,
code: tmp_report_data.general.statusCode,
response: tmp_response_str,
header: tmp_report_data.responseHeaders,
};
}
};
if (tmp_fn_check_is_illegal_url(tmp_test_opts.hostname, 0)) return;
if (tmp_test_opts.method == 'GET') {
template.matchUrlArray = tmp_test_opts.path.split('?');
if (template.matchUrlArray.length > 2) {
template.matchUrlArray = template.matchUrlArray.slice(2).join('?').split('&');
tmp_test_opts.path += '&' + template.matchUrlArray[0];
}
}
let tmp_fn_ajax_err = (tmp_input_err, tmp_input_total_time) => {
if (tmp_report_data.general.status == 'timeout') {
if (typeof input_test_data.timelimitContinue == 'boolean' && !input_test_data.timelimitContinue) {
tmp_report_data.general.time = tmp_input_total_time.toFixed(2) + 'ms';
if (input_callback) input_callback(tmp_report_data);
reject('timeout');
} else {
resolve(tmp_fn_parse_ajax_resolve(tmp_input_total_time));
}
return;
}
tmp_report_data.general.status = 'error';
tmp_report_data.errorReason = [tmp_input_err.name + '' + tmp_input_err.message];
// tmp_report_data.reportList.push({
// type: 'error',
// content: tmp_input_err.name + '' + tmp_input_err.message
// });
resolve(tmp_fn_parse_ajax_resolve(tmp_input_total_time));
},
tmp_fn_ajax_end = (tmp_input_res, tmp_input_res_obj) => {
tmp_response_str = tmp_report_data.response = tmp_input_res_obj.str;
tmp_report_data.general['statusCode'] = tmp_input_res.statusCode;
tmp_report_data.general.downloadSize = tmp_input_res_obj.chunk.length;
tmp_report_data.general.downloadRate = (
(tmp_input_res_obj.chunk.length / tmp_input_res_obj.contentDeliveryTiming / 1024) *
1000
).toFixed(2);
if (input_test_data.responseScript || tmp_target_type_env.responseScript) {
let tmpExecutResponseScriptResult = _ApiUtil.scriptExecuteAfterCode(
{
response: tmp_response_str,
},
input_test_data.responseScript,
{
env: input_env,
functionCode: input_opts.fnCodeArr,
globalHeader: input_opts.globalHeader,
responseHeaders: tmp_input_res.headers,
body: input_test_data.params || input_test_data.body,
headers: tmp_ajax_xhr.getHeaders(),
query: querystring.parse(url.parse(input_test_data.url).query),
}
);
tmp_report_data.reportList = [
...tmp_report_data.reportList,
...(tmpExecutResponseScriptResult.reportList || []),
];
if (tmpExecutResponseScriptResult.status && tmpExecutResponseScriptResult.status !== 'success') {
tmp_report_data.errorReason = [tmpExecutResponseScriptResult.msg];
tmp_report_data.general.status = tmpExecutResponseScriptResult.status;
tmp_report_data.general.time = tmp_input_res_obj.totalTime.toFixed(2) + 'ms';
if (input_callback) input_callback(tmp_report_data);
reject('error');
return;
}
input_env = tmpExecutResponseScriptResult.env;
tmp_response_str = tmp_report_data.response = tmpExecutResponseScriptResult.data;
}
_ApiUtil
.parseResponse(
tmp_input_res.headers,
Buffer.concat(tmp_input_res_obj.chunk.array, tmp_input_res_obj.chunk.length),
{
path: tmp_test_opts.path,
size: tmp_report_data.general.downloadSize,
}
)
.then((tmp_input_file_obj) => {
tmp_report_data.returnResultType = tmp_input_file_obj.type;
if (tmp_input_file_obj.name) tmp_report_data.general.downloadUrl = tmp_input_file_obj.name;
tmp_report_data.general.status = 'finish';
tmp_report_data.responseHeaders = tmp_input_res.headers;
resolve(tmp_fn_parse_ajax_resolve(tmp_input_res_obj.totalTime));
});
};
let tmp_timeout_type_obj = {
total: 0,
first_byte: 1,
},
tmp_advanced_setting = {};
if (input_test_data.sendNocacheToken) {
tmp_advanced_setting.sendNocacheToken = 1;
}
if (input_test_data.checkSSL) {
tmp_advanced_setting.checkSSL = 1;
}
if (input_test_data.sendEoToken) {
tmp_advanced_setting.sendEoToken = 1;
}
_HttpPackageClass.socketReduce(
{
postData: tmp_test_data.isMuti ? tmp_multi_form : tmp_post_data,
isMuti: tmp_test_data.isMuti,
options: tmp_test_opts,
timeoutLimit: input_test_data.timelimit,
globalHeader: input_opts.globalHeader,
timeoutLimitType: tmp_timeout_type_obj[input_test_data.timelimitType] || 'totalTime',
advancedSetting: tmp_advanced_setting,
messageEncoding: input_test_data.encode || 'utf-8',
},
(tmp_input_ajax_status, tmp_input_data_obj, tmp_input_xhr) => {
tmp_ajax_xhr = tmp_input_xhr;
if (tmp_input_ajax_status === 'ajaxTimeout') {
tmp_report_data.general.status = 'timeout';
return;
}
let tmp_http_total_time = _ApiUtil.getMicrosToMs(
tmp_input_data_obj.summaryObj.startAt,
tmp_input_data_obj.summaryObj.endAt
);
tmp_report_data.general.timingSummary = [_ApiUtil.getHttpTiming(tmp_input_data_obj.summaryObj)];
switch (tmp_input_ajax_status) {
case 'ajax_end': {
tmp_report_data.requestHeaders = tmp_ajax_xhr.getHeaders();
if (input_test_data.redirect || !input_test_data.hasOwnProperty('redirect')) {
let tmp_redirect_class = new _RedirectClass.core();
let tmp_redirect_obj = tmp_redirect_class.structureAjaxFun(
tmp_test_opts,
tmp_multi_form ? tmp_multi_form : tmp_post_data,
tmp_input_data_obj.res
);
if (tmp_redirect_obj) {
tmp_report_data.general.redirectTimes++;
if (tmp_fn_check_is_illegal_url(tmp_redirect_obj.options.hostname, tmp_http_total_time)) return;
_HttpPackageClass.socketReduce(
{
postData: tmp_redirect_obj.postData,
isMuti: tmp_test_data.isMuti,
options: tmp_redirect_obj.options,
timeoutLimit: input_test_data.timelimit - tmp_http_total_time,
globalHeader: input_opts.globalHeader,
advancedSetting: tmp_advanced_setting,
messageEncoding: input_test_data.encode || 'utf-8',
},
(tmpInputRedirectAjaxStatus, tmpInputRedirectDataObj) => {
if (tmpInputRedirectAjaxStatus === 'ajaxTimeout') {
tmp_report_data.general.status = 'timeout';
return;
}
let tmpRedirectHttpTotalTime = _ApiUtil.getMicrosToMs(
tmpInputRedirectDataObj.summaryObj.startAt,
tmpInputRedirectDataObj.summaryObj.endAt
);
tmp_report_data.general.timingSummary.push(
_ApiUtil.getHttpTiming(tmpInputRedirectDataObj.summaryObj)
);
switch (tmpInputRedirectAjaxStatus) {
case 'ajax_end': {
tmp_fn_ajax_end(tmpInputRedirectDataObj.res, {
chunk: tmpInputRedirectDataObj.chunk,
str: tmpInputRedirectDataObj.responseStr,
totalTime: tmp_http_total_time + tmpRedirectHttpTotalTime,
contentDeliveryTiming: _ApiUtil.getMicrosToMs(
tmpInputRedirectDataObj.summaryObj.firstByteTiming,
tmpInputRedirectDataObj.summaryObj.endAt
),
});
break;
}
case 'ajaxErr': {
tmp_fn_ajax_err(
tmpInputRedirectDataObj.errObj,
tmp_http_total_time + tmpRedirectHttpTotalTime
);
break;
}
}
}
);
return;
}
}
tmp_fn_ajax_end(tmp_input_data_obj.res, {
chunk: tmp_input_data_obj.chunk,
str: tmp_input_data_obj.responseStr,
totalTime: tmp_http_total_time,
contentDeliveryTiming: _ApiUtil.getMicrosToMs(
tmp_input_data_obj.summaryObj.firstByteTiming,
tmp_input_data_obj.summaryObj.endAt
),
});
break;
}
case 'ajaxErr': {
tmp_fn_ajax_err(tmp_input_data_obj.errObj, tmp_http_total_time);
break;
}
}
}
);
} catch (e) {
_HttpPackageClass.clearAjaxTimeout();
console.error(new Date() + 'automated pro.js 433', e);
tmp_report_data.reportList.push({
type: 'error',
content: e.name + '' + e.message,
});
resolve(tmp_fn_parse_ajax_resolve(0));
}
})
.then((response) => {
tmp_result = response;
})
.catch((error) => {
tmp_result = error;
});
if (input_test_data.delay) {
await new Promise((resolve) => {
setTimeout(
() => {
resolve('success');
},
input_test_data.delay > CONFIG.MAX_TIME_DELAY ? CONFIG.MAX_TIME_DELAY : input_test_data.delay || 0
);
});
}
input_return_callback(tmp_result);
}
//异步操作,作用于纤程唤起
wakeTopThread(input_text, input_current_fibers) {
this.EXEC_RESULT = input_text;
if (input_current_fibers) input_current_fibers.run();
}
}
exports.core = Main;
})();

View File

@ -0,0 +1,458 @@
(function () {
'use strict';
class mainClass {
constructor() {}
byContent(buf) {
if (!(buf && buf.length > 1)) {
return null;
}
if (buf[0] === 0xFF && buf[1] === 0xD8 && buf[2] === 0xFF) {
return {
ext: 'jpg',
mime: 'image/jpeg'
};
}
if (buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4E && buf[3] === 0x47) {
return {
ext: 'png',
mime: 'image/png'
};
}
if (buf[0] === 0x47 && buf[1] === 0x49 && buf[2] === 0x46) {
return {
ext: 'gif',
mime: 'image/gif'
};
}
if (buf[8] === 0x57 && buf[9] === 0x45 && buf[10] === 0x42 && buf[11] === 0x50) {
return {
ext: 'webp',
mime: 'image/webp'
};
}
if (buf[0] === 0x46 && buf[1] === 0x4C && buf[2] === 0x49 && buf[3] === 0x46) {
return {
ext: 'flif',
mime: 'image/flif'
};
}
// needs to be before `tif` check
if (((buf[0] === 0x49 && buf[1] === 0x49 && buf[2] === 0x2A && buf[3] === 0x0) || (buf[0] === 0x4D && buf[1] === 0x4D && buf[2] === 0x0 && buf[3] === 0x2A)) && buf[8] === 0x43 && buf[9] === 0x52) {
return {
ext: 'cr2',
mime: 'image/x-canon-cr2'
};
}
if ((buf[0] === 0x49 && buf[1] === 0x49 && buf[2] === 0x2A && buf[3] === 0x0) || (buf[0] === 0x4D && buf[1] === 0x4D && buf[2] === 0x0 && buf[3] === 0x2A)) {
return {
ext: 'tif',
mime: 'image/tiff'
};
}
if (buf[0] === 0x42 && buf[1] === 0x4D) {
return {
ext: 'bmp',
mime: 'image/bmp'
};
}
if (buf[0] === 0x49 && buf[1] === 0x49 && buf[2] === 0xBC) {
return {
ext: 'jxr',
mime: 'image/vnd.ms-photo'
};
}
if (buf[0] === 0x38 && buf[1] === 0x42 && buf[2] === 0x50 && buf[3] === 0x53) {
return {
ext: 'psd',
mime: 'image/vnd.adobe.photoshop'
};
}
// needs to be before `zip` check
if (buf[0] === 0x50 && buf[1] === 0x4B && buf[2] === 0x3 && buf[3] === 0x4 && buf[30] === 0x6D && buf[31] === 0x69 && buf[32] === 0x6D && buf[33] === 0x65 && buf[34] === 0x74 && buf[35] === 0x79 && buf[36] === 0x70 && buf[37] === 0x65 && buf[38] === 0x61 && buf[39] === 0x70 && buf[40] === 0x70 && buf[41] === 0x6C && buf[42] === 0x69 && buf[43] === 0x63 && buf[44] === 0x61 && buf[45] === 0x74 && buf[46] === 0x69 && buf[47] === 0x6F && buf[48] === 0x6E && buf[49] === 0x2F && buf[50] === 0x65 && buf[51] === 0x70 && buf[52] === 0x75 && buf[53] === 0x62 && buf[54] === 0x2B && buf[55] === 0x7A && buf[56] === 0x69 && buf[57] === 0x70) {
return {
ext: 'epub',
mime: 'application/epub+zip'
};
}
// needs to be before `zip` check
// assumes signed .xpi from addons.mozilla.org
if (buf[0] === 0x50 && buf[1] === 0x4B && buf[2] === 0x3 && buf[3] === 0x4 && buf[30] === 0x4D && buf[31] === 0x45 && buf[32] === 0x54 && buf[33] === 0x41 && buf[34] === 0x2D && buf[35] === 0x49 && buf[36] === 0x4E && buf[37] === 0x46 && buf[38] === 0x2F && buf[39] === 0x6D && buf[40] === 0x6F && buf[41] === 0x7A && buf[42] === 0x69 && buf[43] === 0x6C && buf[44] === 0x6C && buf[45] === 0x61 && buf[46] === 0x2E && buf[47] === 0x72 && buf[48] === 0x73 && buf[49] === 0x61) {
return {
ext: 'xpi',
mime: 'application/x-xpinstall'
};
}
if (buf[0] === 0x50 && buf[1] === 0x4B && (buf[2] === 0x3 || buf[2] === 0x5 || buf[2] === 0x7) && (buf[3] === 0x4 || buf[3] === 0x6 || buf[3] === 0x8)) {
return {
ext: 'zip',
mime: 'application/zip'
};
}
if (buf[257] === 0x75 && buf[258] === 0x73 && buf[259] === 0x74 && buf[260] === 0x61 && buf[261] === 0x72) {
return {
ext: 'tar',
mime: 'application/x-tar'
};
}
if (buf[0] === 0x52 && buf[1] === 0x61 && buf[2] === 0x72 && buf[3] === 0x21 && buf[4] === 0x1A && buf[5] === 0x7 && (buf[6] === 0x0 || buf[6] === 0x1)) {
return {
ext: 'rar',
mime: 'application/x-rar-compressed'
};
}
if (buf[0] === 0x1F && buf[1] === 0x8B && buf[2] === 0x8) {
return {
ext: 'gz',
mime: 'application/gzip'
};
}
if (buf[0] === 0x42 && buf[1] === 0x5A && buf[2] === 0x68) {
return {
ext: 'bz2',
mime: 'application/x-bzip2'
};
}
if (buf[0] === 0x37 && buf[1] === 0x7A && buf[2] === 0xBC && buf[3] === 0xAF && buf[4] === 0x27 && buf[5] === 0x1C) {
return {
ext: '7z',
mime: 'application/x-7z-compressed'
};
}
if (buf[0] === 0x78 && buf[1] === 0x01) {
return {
ext: 'dmg',
mime: 'application/x-apple-diskimage'
};
}
if (
(buf[0] === 0x0 && buf[1] === 0x0 && buf[2] === 0x0 && (buf[3] === 0x18 || buf[3] === 0x20) && buf[4] === 0x66 && buf[5] === 0x74 && buf[6] === 0x79 && buf[7] === 0x70) ||
(buf[0] === 0x33 && buf[1] === 0x67 && buf[2] === 0x70 && buf[3] === 0x35) ||
(buf[0] === 0x0 && buf[1] === 0x0 && buf[2] === 0x0 && buf[3] === 0x1C && buf[4] === 0x66 && buf[5] === 0x74 && buf[6] === 0x79 && buf[7] === 0x70 && buf[8] === 0x6D && buf[9] === 0x70 && buf[10] === 0x34 && buf[11] === 0x32 && buf[16] === 0x6D && buf[17] === 0x70 && buf[18] === 0x34 && buf[19] === 0x31 && buf[20] === 0x6D && buf[21] === 0x70 && buf[22] === 0x34 && buf[23] === 0x32 && buf[24] === 0x69 && buf[25] === 0x73 && buf[26] === 0x6F && buf[27] === 0x6D) ||
(buf[0] === 0x0 && buf[1] === 0x0 && buf[2] === 0x0 && buf[3] === 0x1C && buf[4] === 0x66 && buf[5] === 0x74 && buf[6] === 0x79 && buf[7] === 0x70 && buf[8] === 0x69 && buf[9] === 0x73 && buf[10] === 0x6F && buf[11] === 0x6D) ||
(buf[0] === 0x0 && buf[1] === 0x0 && buf[2] === 0x0 && buf[3] === 0x1c && buf[4] === 0x66 && buf[5] === 0x74 && buf[6] === 0x79 && buf[7] === 0x70 && buf[8] === 0x6D && buf[9] === 0x70 && buf[10] === 0x34 && buf[11] === 0x32 && buf[12] === 0x0 && buf[13] === 0x0 && buf[14] === 0x0 && buf[15] === 0x0)
) {
return {
ext: 'mp4',
mime: 'video/mp4'
};
}
if ((buf[0] === 0x0 && buf[1] === 0x0 && buf[2] === 0x0 && buf[3] === 0x1C && buf[4] === 0x66 && buf[5] === 0x74 && buf[6] === 0x79 && buf[7] === 0x70 && buf[8] === 0x4D && buf[9] === 0x34 && buf[10] === 0x56)) {
return {
ext: 'm4v',
mime: 'video/x-m4v'
};
}
if (buf[0] === 0x4D && buf[1] === 0x54 && buf[2] === 0x68 && buf[3] === 0x64) {
return {
ext: 'mid',
mime: 'audio/midi'
};
}
// needs to be before the `webm` check
if (buf[31] === 0x6D && buf[32] === 0x61 && buf[33] === 0x74 && buf[34] === 0x72 && buf[35] === 0x6f && buf[36] === 0x73 && buf[37] === 0x6B && buf[38] === 0x61) {
return {
ext: 'mkv',
mime: 'video/x-matroska'
};
}
if (buf[0] === 0x1A && buf[1] === 0x45 && buf[2] === 0xDF && buf[3] === 0xA3) {
return {
ext: 'webm',
mime: 'video/webm'
};
}
if (buf[0] === 0x0 && buf[1] === 0x0 && buf[2] === 0x0 && buf[3] === 0x14 && buf[4] === 0x66 && buf[5] === 0x74 && buf[6] === 0x79 && buf[7] === 0x70) {
return {
ext: 'mov',
mime: 'video/quicktime'
};
}
if (buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46 && buf[8] === 0x41 && buf[9] === 0x56 && buf[10] === 0x49) {
return {
ext: 'avi',
mime: 'video/x-msvideo'
};
}
if (buf[0] === 0x30 && buf[1] === 0x26 && buf[2] === 0xB2 && buf[3] === 0x75 && buf[4] === 0x8E && buf[5] === 0x66 && buf[6] === 0xCF && buf[7] === 0x11 && buf[8] === 0xA6 && buf[9] === 0xD9) {
return {
ext: 'wmv',
mime: 'video/x-ms-wmv'
};
}
if (buf[0] === 0x0 && buf[1] === 0x0 && buf[2] === 0x1 && buf[3].toString(16)[0] === 'b') {
return {
ext: 'mpg',
mime: 'video/mpeg'
};
}
if ((buf[0] === 0x49 && buf[1] === 0x44 && buf[2] === 0x33) || (buf[0] === 0xFF && buf[1] === 0xfb)) {
return {
ext: 'mp3',
mime: 'audio/mpeg'
};
}
if ((buf[4] === 0x66 && buf[5] === 0x74 && buf[6] === 0x79 && buf[7] === 0x70 && buf[8] === 0x4D && buf[9] === 0x34 && buf[10] === 0x41) || (buf[0] === 0x4D && buf[1] === 0x34 && buf[2] === 0x41 && buf[3] === 0x20)) {
return {
ext: 'm4a',
mime: 'audio/m4a'
};
}
// needs to be before `ogg` check
if (buf[28] === 0x4F && buf[29] === 0x70 && buf[30] === 0x75 && buf[31] === 0x73 && buf[32] === 0x48 && buf[33] === 0x65 && buf[34] === 0x61 && buf[35] === 0x64) {
return {
ext: 'opus',
mime: 'audio/opus'
};
}
if (buf[0] === 0x4F && buf[1] === 0x67 && buf[2] === 0x67 && buf[3] === 0x53) {
return {
ext: 'ogg',
mime: 'audio/ogg'
};
}
if (buf[0] === 0x66 && buf[1] === 0x4C && buf[2] === 0x61 && buf[3] === 0x43) {
return {
ext: 'flac',
mime: 'audio/x-flac'
};
}
if (buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46 && buf[8] === 0x57 && buf[9] === 0x41 && buf[10] === 0x56 && buf[11] === 0x45) {
return {
ext: 'wav',
mime: 'audio/x-wav'
};
}
if (buf[0] === 0x23 && buf[1] === 0x21 && buf[2] === 0x41 && buf[3] === 0x4D && buf[4] === 0x52 && buf[5] === 0x0A) {
return {
ext: 'amr',
mime: 'audio/amr'
};
}
if (buf[0] === 0x25 && buf[1] === 0x50 && buf[2] === 0x44 && buf[3] === 0x46) {
return {
ext: 'pdf',
mime: 'application/pdf'
};
}
if (buf[0] === 0x4D && buf[1] === 0x5A) {
return {
ext: 'exe',
mime: 'application/x-msdownload'
};
}
if ((buf[0] === 0x43 || buf[0] === 0x46) && buf[1] === 0x57 && buf[2] === 0x53) {
return {
ext: 'swf',
mime: 'application/x-shockwave-flash'
};
}
if (buf[0] === 0x7B && buf[1] === 0x5C && buf[2] === 0x72 && buf[3] === 0x74 && buf[4] === 0x66) {
return {
ext: 'rtf',
mime: 'application/rtf'
};
}
if (
(buf[0] === 0x77 && buf[1] === 0x4F && buf[2] === 0x46 && buf[3] === 0x46) &&
(
(buf[4] === 0x00 && buf[5] === 0x01 && buf[6] === 0x00 && buf[7] === 0x00) ||
(buf[4] === 0x4F && buf[5] === 0x54 && buf[6] === 0x54 && buf[7] === 0x4F)
)
) {
return {
ext: 'woff',
mime: 'application/font-woff'
};
}
if (
(buf[0] === 0x77 && buf[1] === 0x4F && buf[2] === 0x46 && buf[3] === 0x32) &&
(
(buf[4] === 0x00 && buf[5] === 0x01 && buf[6] === 0x00 && buf[7] === 0x00) ||
(buf[4] === 0x4F && buf[5] === 0x54 && buf[6] === 0x54 && buf[7] === 0x4F)
)
) {
return {
ext: 'woff2',
mime: 'application/font-woff'
};
}
if (
(buf[34] === 0x4C && buf[35] === 0x50) &&
(
(buf[8] === 0x00 && buf[9] === 0x00 && buf[10] === 0x01) ||
(buf[8] === 0x01 && buf[9] === 0x00 && buf[10] === 0x02) ||
(buf[8] === 0x02 && buf[9] === 0x00 && buf[10] === 0x02)
)
) {
return {
ext: 'eot',
mime: 'application/octet-stream'
};
}
if (buf[0] === 0x00 && buf[1] === 0x01 && buf[2] === 0x00 && buf[3] === 0x00 && buf[4] === 0x00) {
return {
ext: 'ttf',
mime: 'application/font-sfnt'
};
}
if (buf[0] === 0x4F && buf[1] === 0x54 && buf[2] === 0x54 && buf[3] === 0x4F && buf[4] === 0x00) {
return {
ext: 'otf',
mime: 'application/font-sfnt'
};
}
if (buf[0] === 0x00 && buf[1] === 0x00 && buf[2] === 0x01 && buf[3] === 0x00) {
return {
ext: 'ico',
mime: 'image/x-icon'
};
}
if (buf[0] === 0x46 && buf[1] === 0x4C && buf[2] === 0x56 && buf[3] === 0x01) {
return {
ext: 'flv',
mime: 'video/x-flv'
};
}
if (buf[0] === 0x25 && buf[1] === 0x21) {
return {
ext: 'ps',
mime: 'application/postscript'
};
}
if (buf[0] === 0xFD && buf[1] === 0x37 && buf[2] === 0x7A && buf[3] === 0x58 && buf[4] === 0x5A && buf[5] === 0x00) {
return {
ext: 'xz',
mime: 'application/x-xz'
};
}
if (buf[0] === 0x53 && buf[1] === 0x51 && buf[2] === 0x4C && buf[3] === 0x69) {
return {
ext: 'sqlite',
mime: 'application/x-sqlite3'
};
}
if (buf[0] === 0x4E && buf[1] === 0x45 && buf[2] === 0x53 && buf[3] === 0x1A) {
return {
ext: 'nes',
mime: 'application/x-nintendo-nes-rom'
};
}
if (buf[0] === 0x43 && buf[1] === 0x72 && buf[2] === 0x32 && buf[3] === 0x34) {
return {
ext: 'crx',
mime: 'application/x-google-chrome-extension'
};
}
if (
(buf[0] === 0x4D && buf[1] === 0x53 && buf[2] === 0x43 && buf[3] === 0x46) ||
(buf[0] === 0x49 && buf[1] === 0x53 && buf[2] === 0x63 && buf[3] === 0x28)
) {
return {
ext: 'cab',
mime: 'application/vnd.ms-cab-compressed'
};
}
// needs to be before `ar` check
if (buf[0] === 0x21 && buf[1] === 0x3C && buf[2] === 0x61 && buf[3] === 0x72 && buf[4] === 0x63 && buf[5] === 0x68 && buf[6] === 0x3E && buf[7] === 0x0A && buf[8] === 0x64 && buf[9] === 0x65 && buf[10] === 0x62 && buf[11] === 0x69 && buf[12] === 0x61 && buf[13] === 0x6E && buf[14] === 0x2D && buf[15] === 0x62 && buf[16] === 0x69 && buf[17] === 0x6E && buf[18] === 0x61 && buf[19] === 0x72 && buf[20] === 0x79) {
return {
ext: 'deb',
mime: 'application/x-deb'
};
}
if (buf[0] === 0x21 && buf[1] === 0x3C && buf[2] === 0x61 && buf[3] === 0x72 && buf[4] === 0x63 && buf[5] === 0x68 && buf[6] === 0x3E) {
return {
ext: 'ar',
mime: 'application/x-unix-archive'
};
}
if (buf[0] === 0xED && buf[1] === 0xAB && buf[2] === 0xEE && buf[3] === 0xDB) {
return {
ext: 'rpm',
mime: 'application/x-rpm'
};
}
if (
(buf[0] === 0x1F && buf[1] === 0xA0) ||
(buf[0] === 0x1F && buf[1] === 0x9D)
) {
return {
ext: 'Z',
mime: 'application/x-compress'
};
}
if (buf[0] === 0x4C && buf[1] === 0x5A && buf[2] === 0x49 && buf[3] === 0x50) {
return {
ext: 'lz',
mime: 'application/x-lzip'
};
}
if (buf[0] === 0xD0 && buf[1] === 0xCF && buf[2] === 0x11 && buf[3] === 0xE0 && buf[4] === 0xA1 && buf[5] === 0xB1 && buf[6] === 0x1A && buf[7] === 0xE1) {
return {
ext: 'msi',
mime: 'application/x-msi'
};
}
return null;
}
}
exports.core = mainClass;
})();

View File

@ -0,0 +1,298 @@
(function () {
'use strict';
var http = require("http"),
https = require('https'),
zlib = require('zlib'),
iconv = require("iconv-lite"),
fs=require("fs");
var HttpsProxyAgent = require('https-proxy-agent'); // HTTP/HTTPS
const _LibsEncrypt = require("./encrypt").core,_CERT_FILE_REFS=[{
key:"cert",
value:"crt"
},{
key:"key"
},{
key:"pfx"
}];
global.PROXY_OBJ = {};
const SOCKET_HANG_UP_TIP_TEXT_OBJ={
SAAS_SERVER:"无法访问目标地址,请检查接口是否能被正常访问,如果您使用的是服务器方式测试,请检查测试服务器能否访问目标地址,是否存在网络隔离或防火墙,您可以尝试切换到 PC 客户端。",
}
class mainClass {
constructor() {}
/**
* @desc 设置默认的请求头部
*/
setDefaultRequestHeader(inputHeaderObj = {}, inputOptions = {}) {
let TMP_DEAFULT_HEADER_OBJ = {
"User-Agent": "Eolink",
"Accept":"*/*"
};
if (inputOptions.sendNocacheToken) {
TMP_DEAFULT_HEADER_OBJ["Cache-Control"] = "no-cache";
}
if (inputOptions.sendEoToken) {
TMP_DEAFULT_HEADER_OBJ["Eo-Token"] = _LibsEncrypt.uuidGeneration();
}
let tmpRepareStr = JSON.stringify(inputHeaderObj);
for (let key in TMP_DEAFULT_HEADER_OBJ) {
let val = TMP_DEAFULT_HEADER_OBJ[key];
if (!new RegExp(`"${key}":`, "i").test(tmpRepareStr)) {
inputHeaderObj[key] = val;
}
}
}
/**
* @desc ajax请求数据信息处理
*/
socketReduce(inputTestData = {}, inputCallback) {
let _MainClass = this;
async function main() {
let tmpEncoding=inputTestData.messageEncoding||"utf-8";
inputTestData.advancedSetting = inputTestData.advancedSetting || {
requestRedirect: 1,
sendNocacheToken: 0,
checkSSL: 0,
sendEoToken: 1
};
let tmpSummaryObj = {
startAt: undefined,
dnsTiming: undefined,
tcpTiming: undefined,
tlsTiming: undefined,
requestSentTiming: undefined,
firstByteTiming: undefined,
endAt: undefined
},
tmpChunk = {
array: [],
length: 0
},
tmpAjaxXhr={}, tmpResponseString = "",
tmpProtocol, tmpTimer;
if (inputTestData.options.method == 'GET') {
let tmpMatchUrlArr = inputTestData.options.path.split('?');
if (tmpMatchUrlArr.length > 2) {
tmpMatchUrlArr = tmpMatchUrlArr.slice(2).join('?').split('&');
inputTestData.options.path += '&' + tmpMatchUrlArr[0];
}
}
switch (inputTestData.options.protocol) {
case 'https:': {
if (!inputTestData.advancedSetting.checkSSL){
inputTestData.options.rejectUnauthorized = false;
inputTestData.options.minVersion="TLSv1";
}
tmpProtocol = https;
break;
}
default: {
tmpProtocol = http;
break;
}
}
_MainClass.setDefaultRequestHeader(inputTestData.options.headers, inputTestData.advancedSetting);
let tmpPathArr = (inputTestData.options.path || "").split("?");
tmpPathArr[0] = encodeURI(decodeURI(tmpPathArr[0]));
inputTestData.options.path = tmpPathArr.join("?");
try {
tmpAjaxXhr = tmpProtocol.request(inputTestData.options, (tmpInputRes) => {
tmpInputRes.on('data', (tmpInputChunk) => {
tmpChunk.array.push(tmpInputChunk);
tmpChunk.length += tmpInputChunk.length;
tmpResponseString += tmpInputChunk;
});
tmpInputRes.once('readable', () => {
if (inputTestData.timeoutLimitType === "firstByte" && tmpTimer) { //首字节时间超时
clearTimeout(tmpTimer);
}
tmpSummaryObj.firstByteTiming = process.hrtime();
})
tmpInputRes.on('end', () => {
tmpSummaryObj.endAt = process.hrtime();
if (tmpTimer) {
clearTimeout(tmpTimer);
}
if (tmpInputRes.headers['set-cookie']) {
_MainClass.setCookieToHeaders({
'cookie': tmpInputRes.headers['set-cookie'].join(';')
}, inputTestData.options.hostname, inputTestData.globalHeader);
}
let tmpBuffer=Buffer.concat(tmpChunk.array, tmpChunk.length);
let tmpFnZlibCallback=(inputErr,inputBuff)=>{
if(!inputErr){
tmpBuffer=inputBuff;
}
if(tmpEncoding==="gbk"){
tmpBuffer=Buffer.from(iconv.decode(tmpBuffer,'gbk'));
}
let tmpResponseStr;
if(inputTestData.pckSplitByHeader){//是否分割报文头
tmpResponseStr=tmpBuffer.toString("utf8",4);
}else{
tmpResponseStr=tmpBuffer.toString('utf8');
}
inputCallback("ajax_end", {
res: tmpInputRes,
chunk: tmpChunk,
responseStr: tmpResponseStr,
summaryObj: tmpSummaryObj
}, tmpAjaxXhr)
}
switch (tmpInputRes.headers['content-encoding']) {
case 'br': {
zlib.brotliDecompress(tmpBuffer, tmpFnZlibCallback)
break;
}
case 'gzip': {
zlib.gunzip(tmpBuffer, tmpFnZlibCallback)
break;
}
case 'deflate': {
zlib.inflate(tmpBuffer, tmpFnZlibCallback)
break;
}
default: {
tmpFnZlibCallback(true,tmpBuffer);
break;
}
}
});
});
} catch (REQUEST_ERR) {
inputCallback("ajaxErr", {
summaryObj: tmpSummaryObj,
errObj: REQUEST_ERR
}, tmpAjaxXhr);
return;
}
tmpAjaxXhr.on('socket', (socket) => {
tmpSummaryObj.startAt = process.hrtime();
_MainClass.ajaxTimer = tmpTimer = setTimeout(function () {
tmpSummaryObj.endAt = process.hrtime();
inputCallback("ajaxTimeout", {
summaryObj: tmpSummaryObj
}, tmpAjaxXhr)
clearTimeout(tmpTimer);
tmpAjaxXhr.abort();
}, inputTestData.timeoutLimit);
socket.on('lookup', () => {
tmpSummaryObj.dnsTiming = process.hrtime()
})
socket.on('connect', () => {
tmpSummaryObj.tcpTiming = process.hrtime()
})
socket.on('secureConnect', () => {
tmpSummaryObj.tlsTiming = process.hrtime();
})
});
tmpAjaxXhr.on('error', (tmpInputErr) => {
if (tmpTimer) clearTimeout(tmpTimer);
inputCallback("ajaxErr", {
summaryObj: tmpSummaryObj,
errObj: /getaddrinfo enotfound/i.test(tmpInputErr.message) ? {
name: "API请求地址有误",
message: "请检查是否正确填写URL以及URL是否允许访问"
} : /socket hang up/i.test(tmpInputErr.message) ? {
name: "请求错误",
message: SOCKET_HANG_UP_TIP_TEXT_OBJ["SAAS_SERVER"]||"无法访问目标地址,请检查接口是否能被正常访问,是否存在网络隔离或防火墙。"
} :tmpInputErr
}, tmpAjaxXhr)
});
if (!inputTestData.postData) {
tmpAjaxXhr.end();
} else if (inputTestData.isMuti) {
inputTestData.postData.getLength((tmpInputErr, tmpInputLength) => {
if (!tmpInputErr) {
tmpAjaxXhr.setHeader('content-length', tmpInputLength);
}
inputTestData.postData.pipe(tmpAjaxXhr);
})
} else {
if(typeof inputTestData.postData==="string"){
if(tmpEncoding==="gbk"){
inputTestData.postData=iconv.encode(inputTestData.postData,'gbk');
tmpAjaxXhr.setHeader('Content-Length', Buffer.byteLength(inputTestData.postData));
}else{
inputTestData.postData=Buffer.from(inputTestData.postData);
}
if(inputTestData.pckSplitByHeader)inputTestData.postData=_MainClass.writeInt(inputTestData.postData,Buffer.byteLength(inputTestData.postData,tmpEncoding));
}
tmpAjaxXhr.write(inputTestData.postData);
tmpAjaxXhr.end();
}
}
main();
}
writeInt(inputBuff,inputLen){
let tmpBytes=new Array(4);
tmpBytes[0]=inputLen >> 24;
tmpBytes[1]=inputLen >> 16;
tmpBytes[2]=inputLen >> 8;
tmpBytes[3]=inputLen;
return Buffer.concat([new Buffer(tmpBytes),inputBuff]);
}
/**
* @desc 将cookie注入headers
*/
setCookieToHeaders(inputHeaders, inputDomain, inputGlobalObj) {
inputGlobalObj = inputGlobalObj || {};
let tmpReturnObj, tmpSplitCookieArr = [],
tmpSplitCookieParamArr = [],
tmpTargetCookirStr = "";
try {
tmpReturnObj = JSON.parse(JSON.stringify(inputHeaders || {}).replace(/"cookie":/i, '"cookie":'));
if(!inputGlobalObj[inputDomain]){
for(let key in inputGlobalObj){
if(inputDomain.indexOf(key)>-1){
inputDomain=key;
break;
}
}
}
if (tmpReturnObj.cookie) {
tmpSplitCookieArr = tmpReturnObj.cookie.split(';');
if (inputGlobalObj[inputDomain]) {
if (inputGlobalObj[inputDomain]['cookie']) {
tmpTargetCookirStr = inputGlobalObj[inputDomain]['cookie'][0] || '';
for (let key in tmpSplitCookieArr) {
if (tmpSplitCookieArr[key]) {
let splitString = tmpSplitCookieArr[key].split('=')[0];
if (tmpTargetCookirStr.indexOf(splitString) > -1) {
tmpSplitCookieParamArr = tmpTargetCookirStr.split(splitString + '=');
if (tmpSplitCookieParamArr.length > 1) {
tmpTargetCookirStr = tmpTargetCookirStr.replace(splitString + '=' + tmpSplitCookieParamArr[1].split(';')[0], tmpSplitCookieArr[key]);
} else {
tmpTargetCookirStr = tmpTargetCookirStr.replace(splitString, tmpSplitCookieArr[key]);
}
} else {
tmpTargetCookirStr = tmpTargetCookirStr+(/;$/.test(tmpTargetCookirStr)?"":';')+tmpSplitCookieArr[key] ;
}
}
}
inputGlobalObj[inputDomain]['cookie'] = [tmpTargetCookirStr];
} else {
inputGlobalObj[inputDomain]['cookie'] = [tmpReturnObj.cookie];
}
} else {
inputGlobalObj[inputDomain] = {
cookie: [tmpReturnObj.cookie]
}
}
}
} catch (e) {}
if (inputGlobalObj[inputDomain]) {
tmpReturnObj.cookie = inputGlobalObj[inputDomain]['cookie'].join(';');
}
return tmpReturnObj;
}
clearAjaxTimeout() {
if (this.ajaxTimer) clearTimeout(this.ajaxTimer);
}
}
exports.core = mainClass;
})();

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,73 @@
(function () {
'use strict';
let url = require("url");
class redirectClass {
constructor() {}
checkRedirectStatusFun(inputRes) {
let tmpLocaltion=inputRes.headers['location'];
if (inputRes.statusCode >= 300 && inputRes.statusCode < 400 && tmpLocaltion) {
return {
status:'3xx',
uri:tmpLocaltion
}
}
return {
status:'xxx'
}
}
structureAjaxFun(inputOption,inputPostData,inputRes){
let tmp={
redirectStatusObject:this.checkRedirectStatusFun(inputRes),
callbackArg:{
postData:typeof inputPostData==="string"?inputPostData:Object.assign({},inputPostData),
options:null
},
protocol:null
}
switch(tmp.redirectStatusObject.status){
case '3xx':{
tmp.callbackArg.options=Object.assign({},inputOption,url.parse(tmp.redirectStatusObject.uri));
break;
}
default:{
return;
}
}
if(!tmp.callbackArg.options.hostname){
tmp.callbackArg.options.hostname=inputOption.hostname;
tmp.callbackArg.options.protocol=inputOption.protocol;
tmp.callbackArg.options.port=inputOption.port;
tmp.callbackArg.options.auth=inputOption.auth;
}
if (inputRes.statusCode !== 307) {
delete tmp.callbackArg.postData;
if (tmp.callbackArg.options.headers) {
for(let key in tmp.callbackArg.options.headers){
if(/(host)|(content-type)|(content-length)/i.test(key)){
delete tmp.callbackArg.options.headers[key];
}
}
if (tmp.callbackArg.options.hostname !== inputOption.hostname.split(':')[0]) {
for(let key in tmp.callbackArg.options.headers){
if(/(authorization)/i.test(key)){
delete tmp.callbackArg.options.headers[key];
break;
}
}
}
}
}
switch(inputRes.statusCode){
case 301:
case 302:
case 303:{
tmp.callbackArg.options.method="GET";
break;
}
}
return tmp.callbackArg;
}
}
exports.core = redirectClass;
})();

View File

@ -0,0 +1,3 @@
if (parseInt(process.versions.node.split('.')[0]) < 6) throw new Error('vm2 requires Node.js version 6 or newer.');
module.exports = require('./lib/main');

View File

@ -0,0 +1,35 @@
'use strict';
const pa = require('path');
const {NodeVM, VMError} = require('../');
if (process.argv[2]) {
const path = pa.resolve(process.argv[2]);
console.log(`\x1B[90m[vm] creating VM for ${path}\x1B[39m`);
const started = Date.now();
try {
NodeVM.file(path, {
verbose: true,
require: {
external: true
}
});
console.log(`\x1B[90m[vm] VM completed in ${Date.now() - started}ms\x1B[39m`);
} catch (ex) {
if (ex instanceof VMError) {
console.error(`\x1B[31m[vm:error] ${ex.message}\x1B[39m`);
} else {
const {stack} = ex;
if (stack) {
console.error(`\x1B[31m[vm:error] ${stack}\x1B[39m`);
} else {
console.error(`\x1B[31m[vm:error] ${ex}\x1B[39m`);
}
}
}
}

View File

@ -0,0 +1,815 @@
/* global host */
/* eslint-disable block-spacing, no-multi-spaces, brace-style, no-array-constructor, new-cap, no-use-before-define */
'use strict';
// eslint-disable-next-line no-invalid-this, no-shadow
const global = this;
const local = host.Object.create(null);
local.Object = Object;
local.Array = Array;
local.Reflect = host.Object.create(null);
local.Reflect.ownKeys = Reflect.ownKeys;
local.Reflect.enumerable = Reflect.enumerate;
local.Reflect.getPrototypeOf = Reflect.getPrototypeOf;
local.Reflect.construct = Reflect.construct;
local.Reflect.apply = Reflect.apply;
local.Reflect.set = Reflect.set;
local.Reflect.deleteProperty = Reflect.deleteProperty;
local.Reflect.has = Reflect.has;
// global is originally prototype of host.Object so it can be used to climb up from the sandbox.
Object.setPrototypeOf(global, Object.prototype);
Object.defineProperties(global, {
global: {value: global},
GLOBAL: {value: global},
root: {value: global},
isVM: {value: true}
});
const DEBUG = false;
const OPNA = 'Operation not allowed on contextified object.';
const captureStackTrace = Error.captureStackTrace;
const FROZEN_TRAPS = host.Object.create(null);
FROZEN_TRAPS.set = (target, key) => false;
FROZEN_TRAPS.setPrototypeOf = (target, key) => false;
FROZEN_TRAPS.defineProperty = (target, key) => false;
FROZEN_TRAPS.deleteProperty = (target, key) => false;
FROZEN_TRAPS.isExtensible = (target, key) => false;
FROZEN_TRAPS.preventExtensions = (target) => false;
// Map of contextified objects to original objects
const Contextified = new host.WeakMap();
const Decontextified = new host.WeakMap();
// We can't use host's hasInstance method
const hasInstance = local.Object[Symbol.hasInstance];
function instanceOf(value, construct) {
try {
return host.Reflect.apply(hasInstance, construct, [value]);
} catch (ex) {
// Never pass the handled expcetion through!
throw new VMError('Unable to perform instanceOf check.');
// This exception actually never get to the user. It only instructs the caller to return null because we wasn't able to perform instanceOf check.
}
}
/**
* VMError definition.
*/
class VMError extends Error {
constructor(message, code) {
super(message);
this.name = 'VMError';
this.code = code;
captureStackTrace(this, this.constructor);
}
}
global.VMError = VMError;
/*
* This function will throw a TypeError for accessing properties
* on a strict mode function
*/
function throwCallerCalleeArgumentsAccess(key) {
'use strict';
throwCallerCalleeArgumentsAccess[key];
return new VMError('Unreachable');
}
/*
* Proxy Helper
*
* Here we track Proxy creations so that we know for every proxy in the VM the
* target. If the Proxy is given to decontextify we are going to lookup
* the target and unsing this non proxy as target for the decontextify proxy.
*
*/
const ProxyHelper = host.Object.create(null);
// Marker for revoked proxy objects
ProxyHelper.revoked = 'Revoked';
// Tracks for every proxy the target.
ProxyHelper.tracker = new host.WeakMap();
// Gets the target of a proxy recursively until target is not any more a proxy
ProxyHelper.getTarget = (proxy) => {
let obj = proxy;
let next;
while ((next = ProxyHelper.tracker.get(obj))!==undefined) {
obj = next;
}
// Target could be revoked.
if (obj === ProxyHelper.revoked) {
obj = host.Object.create(null);
}
return obj;
};
// This is not so nice, I would prefer globalThis.Proxy but globalThis is relatively new
Proxy = ((ProxyFunc) => {
// Handle Proxy.revocable()
const ProxyRevocableHandler = host.Object.create(null);
ProxyRevocableHandler.apply = (target, thiz, args) => {
const proxyTarget = args[0];
const ret = local.Reflect.apply(target, thiz, args);
const proxy = ret.proxy;
ProxyHelper.tracker.set(proxy, proxyTarget);
const revokeHandler = host.Object.create(null);
revokeHandler.apply = (rTarget, rThiz, rArgs) => {
const rRet = local.Reflect.apply(rTarget, rThiz, rArgs);
ProxyHelper.tracker.set(proxy, ProxyHelper.revoked);
return rRet;
};
ret.revoke = new host.Proxy(ret.revoke, revokeHandler);
return ret;
};
ProxyFunc.revocable = new host.Proxy(Proxy.revocable, ProxyRevocableHandler);
// Handle new Proxy()
const ProxyHandler = host.Object.create(null);
ProxyHandler.construct = (target, args, newTarget) => {
const proxyTarget = args[0];
const proxy = local.Reflect.construct(target, args, newTarget);
ProxyHelper.tracker.set(proxy, proxyTarget);
return proxy;
};
return new host.Proxy(ProxyFunc, ProxyHandler);
})(Proxy);
/**
* Decontextify.
*/
const Decontextify = host.Object.create(null);
Decontextify.proxies = new host.WeakMap();
Decontextify.arguments = args => {
if (!host.Array.isArray(args)) return new host.Array();
try {
const arr = new host.Array();
for (let i = 0, l = args.length; i < l; i++) arr[i] = Decontextify.value(args[i]);
return arr;
} catch (e) {
// Never pass the handled expcetion through!
return new host.Array();
}
};
Decontextify.instance = (instance, klass, deepTraps, flags, toStringTag) => {
if (typeof instance === 'function') return Decontextify.function(instance);
// We must not use normal object because there's a chance object already contains malicious code in the prototype
const base = host.Object.create(null);
base.get = (target, key, receiver) => {
try {
if (key === 'vmProxyTarget' && DEBUG) return instance;
if (key === 'isVMProxy') return true;
if (key === 'constructor') return klass;
if (key === '__proto__') return klass.prototype;
} catch (e) {
// Never pass the handled expcetion through! This block can't throw an exception under normal conditions.
return null;
}
if (key === '__defineGetter__') return host.Object.prototype.__defineGetter__;
if (key === '__defineSetter__') return host.Object.prototype.__defineSetter__;
if (key === '__lookupGetter__') return host.Object.prototype.__lookupGetter__;
if (key === '__lookupSetter__') return host.Object.prototype.__lookupSetter__;
if (key === host.Symbol.toStringTag && toStringTag) return toStringTag;
try {
return Decontextify.value(instance[key], null, deepTraps, flags);
} catch (e) {
throw Decontextify.value(e);
}
};
base.getPrototypeOf = (target) => {
return klass && klass.prototype;
};
return Decontextify.object(instance, base, deepTraps, flags);
};
Decontextify.function = (fnc, traps, deepTraps, flags, mock) => {
// We must not use normal object because there's a chance object already contains malicious code in the prototype
const base = host.Object.create(null);
// eslint-disable-next-line prefer-const
let proxy;
base.apply = (target, context, args) => {
context = Contextify.value(context);
// Set context of all arguments to vm's context.
args = Contextify.arguments(args);
try {
return Decontextify.value(fnc.apply(context, args));
} catch (e) {
throw Decontextify.value(e);
}
};
base.construct = (target, args, newTarget) => {
args = Contextify.arguments(args);
try {
return Decontextify.instance(new fnc(...args), proxy, deepTraps, flags);
} catch (e) {
throw Decontextify.value(e);
}
};
base.get = (target, key, receiver) => {
try {
if (key === 'vmProxyTarget' && DEBUG) return fnc;
if (key === 'isVMProxy') return true;
if (mock && host.Object.prototype.hasOwnProperty.call(mock, key)) return mock[key];
if (key === 'constructor') return host.Function;
if (key === '__proto__') return host.Function.prototype;
} catch (e) {
// Never pass the handled expcetion through! This block can't throw an exception under normal conditions.
return null;
}
if (key === '__defineGetter__') return host.Object.prototype.__defineGetter__;
if (key === '__defineSetter__') return host.Object.prototype.__defineSetter__;
if (key === '__lookupGetter__') return host.Object.prototype.__lookupGetter__;
if (key === '__lookupSetter__') return host.Object.prototype.__lookupSetter__;
try {
return Decontextify.value(fnc[key], null, deepTraps, flags);
} catch (e) {
throw Decontextify.value(e);
}
};
base.getPrototypeOf = (target) => {
return host.Function.prototype;
};
proxy = Decontextify.object(fnc, host.Object.assign(base, traps), deepTraps);
return proxy;
};
Decontextify.object = (object, traps, deepTraps, flags, mock) => {
// We must not use normal object because there's a chance object already contains malicious code in the prototype
const base = host.Object.create(null);
base.get = (target, key, receiver) => {
try {
if (key === 'vmProxyTarget' && DEBUG) return object;
if (key === 'isVMProxy') return true;
if (mock && host.Object.prototype.hasOwnProperty.call(mock, key)) return mock[key];
if (key === 'constructor') return host.Object;
if (key === '__proto__') return host.Object.prototype;
} catch (e) {
// Never pass the handled expcetion through! This block can't throw an exception under normal conditions.
return null;
}
if (key === '__defineGetter__') return host.Object.prototype.__defineGetter__;
if (key === '__defineSetter__') return host.Object.prototype.__defineSetter__;
if (key === '__lookupGetter__') return host.Object.prototype.__lookupGetter__;
if (key === '__lookupSetter__') return host.Object.prototype.__lookupSetter__;
try {
return Decontextify.value(object[key], null, deepTraps, flags);
} catch (e) {
throw Decontextify.value(e);
}
};
base.set = (target, key, value, receiver) => {
value = Contextify.value(value);
try {
return local.Reflect.set(object, key, value);
} catch (e) {
throw Decontextify.value(e);
}
};
base.getOwnPropertyDescriptor = (target, prop) => {
let def;
try {
def = host.Object.getOwnPropertyDescriptor(object, prop);
} catch (e) {
throw Decontextify.value(e);
}
// Following code prevents V8 to throw
// TypeError: 'getOwnPropertyDescriptor' on proxy: trap reported non-configurability for property '<prop>'
// which is either non-existant or configurable in the proxy target
if (!def) {
return undefined;
} else if (def.get || def.set) {
return {
get: Decontextify.value(def.get) || undefined,
set: Decontextify.value(def.set) || undefined,
enumerable: def.enumerable === true,
configurable: def.configurable === true
};
} else {
return {
value: Decontextify.value(def.value),
writable: def.writable === true,
enumerable: def.enumerable === true,
configurable: def.configurable === true
};
}
};
base.defineProperty = (target, key, descriptor) => {
// There's a chance accessing a property throws an error so we must not access them
// in try catch to prevent contextyfing local objects.
const propertyDescriptor = host.Object.create(null);
if (descriptor.get || descriptor.set) {
propertyDescriptor.get = Contextify.value(descriptor.get, null, deepTraps, flags) || undefined;
propertyDescriptor.set = Contextify.value(descriptor.set, null, deepTraps, flags) || undefined;
propertyDescriptor.enumerable = descriptor.enumerable === true;
propertyDescriptor.configurable = descriptor.configurable === true;
} else {
propertyDescriptor.value = Contextify.value(descriptor.value, null, deepTraps, flags);
propertyDescriptor.writable = descriptor.writable === true;
propertyDescriptor.enumerable = descriptor.enumerable === true;
propertyDescriptor.configurable = descriptor.configurable === true;
}
try {
return host.Object.defineProperty(target, key, propertyDescriptor);
} catch (e) {
throw Decontextify.value(e);
}
};
base.deleteProperty = (target, prop) => {
try {
return Decontextify.value(local.Reflect.deleteProperty(object, prop));
} catch (e) {
throw Decontextify.value(e);
}
};
base.getPrototypeOf = (target) => {
return host.Object.prototype;
};
base.setPrototypeOf = (target) => {
throw new host.Error(OPNA);
};
base.has = (target, key) => {
try {
return Decontextify.value(local.Reflect.has(object, key));
} catch (e) {
throw Decontextify.value(e);
}
};
base.isExtensible = target => {
try {
return Decontextify.value(local.Object.isExtensible(object));
} catch (e) {
throw Decontextify.value(e);
}
};
base.ownKeys = target => {
try {
return Decontextify.value(local.Reflect.ownKeys(object));
} catch (e) {
throw Decontextify.value(e);
}
};
base.preventExtensions = target => {
try {
local.Object.preventExtensions(object);
return true;
} catch (e) {
throw Decontextify.value(e);
}
};
base.enumerate = target => {
try {
return Decontextify.value(local.Reflect.enumerate(object));
} catch (e) {
throw Decontextify.value(e);
}
};
const proxy = new host.Proxy(ProxyHelper.getTarget(object), host.Object.assign(base, traps, deepTraps));
Decontextify.proxies.set(object, proxy);
Decontextified.set(proxy, object);
return proxy;
};
Decontextify.value = (value, traps, deepTraps, flags, mock) => {
try {
if (Contextified.has(value)) {
// Contextified object has returned back from vm
return Contextified.get(value);
} else if (Decontextify.proxies.has(value)) {
// Decontextified proxy already exists, reuse
return Decontextify.proxies.get(value);
}
switch (typeof value) {
case 'object':
if (value === null) {
return null;
} else if (instanceOf(value, Number)) { return host.Number(value);
} else if (instanceOf(value, String)) { return host.String(value);
} else if (instanceOf(value, Boolean)) { return host.Boolean(value);
} else if (instanceOf(value, Date)) { return Decontextify.instance(value, host.Date, deepTraps, flags, 'Date');
} else if (instanceOf(value, RangeError)) { return Decontextify.instance(value, host.RangeError, deepTraps, flags, 'Error');
} else if (instanceOf(value, ReferenceError)) { return Decontextify.instance(value, host.ReferenceError, deepTraps, flags, 'Error');
} else if (instanceOf(value, SyntaxError)) { return Decontextify.instance(value, host.SyntaxError, deepTraps, flags, 'Error');
} else if (instanceOf(value, TypeError)) { return Decontextify.instance(value, host.TypeError, deepTraps, flags, 'Error');
} else if (instanceOf(value, VMError)) { return Decontextify.instance(value, host.VMError, deepTraps, flags, 'Error');
} else if (instanceOf(value, EvalError)) { return Decontextify.instance(value, host.EvalError, deepTraps, flags, 'Error');
} else if (instanceOf(value, URIError)) { return Decontextify.instance(value, host.URIError, deepTraps, flags, 'Error');
} else if (instanceOf(value, Error)) { return Decontextify.instance(value, host.Error, deepTraps, flags, 'Error');
} else if (instanceOf(value, Array)) { return value;
} else if (instanceOf(value, RegExp)) { return Decontextify.instance(value, host.RegExp, deepTraps, flags, 'RegExp');
} else if (instanceOf(value, Map)) { return Decontextify.instance(value, host.Map, deepTraps, flags, 'Map');
} else if (instanceOf(value, WeakMap)) { return Decontextify.instance(value, host.WeakMap, deepTraps, flags, 'WeakMap');
} else if (instanceOf(value, Set)) { return Decontextify.instance(value, host.Set, deepTraps, flags, 'Set');
} else if (instanceOf(value, WeakSet)) { return Decontextify.instance(value, host.WeakSet, deepTraps, flags, 'WeakSet');
} else if (Promise && instanceOf(value, Promise)) { return Decontextify.instance(value, host.Promise, deepTraps, flags, 'Promise');
} else if (local.Reflect.getPrototypeOf(value) === null) {
return Decontextify.instance(value, null, deepTraps, flags);
} else {
return Decontextify.object(value, traps, deepTraps, flags, mock);
}
case 'function':
return Decontextify.function(value, traps, deepTraps, flags, mock);
case 'undefined':
return undefined;
default: // string, number, boolean, symbol
return value;
}
} catch (ex) {
// Never pass the handled expcetion through! This block can't throw an exception under normal conditions.
return null;
}
};
/**
* Contextify.
*/
const Contextify = host.Object.create(null);
Contextify.proxies = new host.WeakMap();
Contextify.arguments = args => {
if (!host.Array.isArray(args)) return new local.Array();
try {
const arr = new local.Array();
for (let i = 0, l = args.length; i < l; i++) arr[i] = Contextify.value(args[i]);
return arr;
} catch (e) {
// Never pass the handled expcetion through!
return new local.Array();
}
};
Contextify.instance = (instance, klass, deepTraps, flags, toStringTag) => {
if (typeof instance === 'function') return Contextify.function(instance);
// We must not use normal object because there's a chance object already contains malicious code in the prototype
const base = host.Object.create(null);
base.get = (target, key, receiver) => {
try {
if (key === 'vmProxyTarget' && DEBUG) return instance;
if (key === 'isVMProxy') return true;
if (key === 'constructor') return klass;
if (key === '__proto__') return klass.prototype;
} catch (e) {
// Never pass the handled expcetion through! This block can't throw an exception under normal conditions.
return null;
}
if (key === '__defineGetter__') return local.Object.prototype.__defineGetter__;
if (key === '__defineSetter__') return local.Object.prototype.__defineSetter__;
if (key === '__lookupGetter__') return local.Object.prototype.__lookupGetter__;
if (key === '__lookupSetter__') return local.Object.prototype.__lookupSetter__;
if (key === host.Symbol.toStringTag && toStringTag) return toStringTag;
try {
return Contextify.value(host.Reflect.get(instance, key), null, deepTraps, flags);
} catch (e) {
throw Contextify.value(e);
}
};
base.getPrototypeOf = (target) => {
return klass && klass.prototype;
};
return Contextify.object(instance, base, deepTraps, flags);
};
Contextify.function = (fnc, traps, deepTraps, flags, mock) => {
// We must not use normal object because there's a chance object already contains malicious code in the prototype
const base = host.Object.create(null);
// eslint-disable-next-line prefer-const
let proxy;
base.apply = (target, context, args) => {
context = Decontextify.value(context);
// Set context of all arguments to host's context.
args = Decontextify.arguments(args);
try {
return Contextify.value(fnc.apply(context, args));
} catch (e) {
throw Contextify.value(e);
}
};
base.construct = (target, args, newTarget) => {
// Fixes buffer unsafe allocation for node v6/7
if (host.version < 8 && fnc === host.Buffer && 'number' === typeof args[0]) {
args[0] = new Array(args[0]).fill(0);
}
args = Decontextify.arguments(args);
try {
return Contextify.instance(new fnc(...args), proxy, deepTraps, flags);
} catch (e) {
throw Contextify.value(e);
}
};
base.get = (target, key, receiver) => {
try {
if (key === 'vmProxyTarget' && DEBUG) return fnc;
if (key === 'isVMProxy') return true;
if (mock && host.Object.prototype.hasOwnProperty.call(mock, key)) return mock[key];
if (key === 'constructor') return Function;
if (key === '__proto__') return Function.prototype;
} catch (e) {
// Never pass the handled expcetion through! This block can't throw an exception under normal conditions.
return null;
}
if (key === '__defineGetter__') return local.Object.prototype.__defineGetter__;
if (key === '__defineSetter__') return local.Object.prototype.__defineSetter__;
if (key === '__lookupGetter__') return local.Object.prototype.__lookupGetter__;
if (key === '__lookupSetter__') return local.Object.prototype.__lookupSetter__;
if (key === 'caller' || key === 'callee' || key === 'arguments') throw throwCallerCalleeArgumentsAccess(key);
try {
return Contextify.value(host.Reflect.get(fnc, key), null, deepTraps, flags);
} catch (e) {
throw Contextify.value(e);
}
};
base.getPrototypeOf = (target) => {
return Function.prototype;
};
proxy = Contextify.object(fnc, host.Object.assign(base, traps), deepTraps);
return proxy;
};
Contextify.object = (object, traps, deepTraps, flags, mock) => {
// We must not use normal object because there's a chance object already contains malicious code in the prototype
const base = host.Object.create(null);
base.get = (target, key, receiver) => {
try {
if (key === 'vmProxyTarget' && DEBUG) return object;
if (key === 'isVMProxy') return true;
if (mock && host.Object.prototype.hasOwnProperty.call(mock, key)) return mock[key];
if (key === 'constructor') return Object;
if (key === '__proto__') return Object.prototype;
} catch (e) {
// Never pass the handled expcetion through! This block can't throw an exception under normal conditions.
return null;
}
if (key === '__defineGetter__') return local.Object.prototype.__defineGetter__;
if (key === '__defineSetter__') return local.Object.prototype.__defineSetter__;
if (key === '__lookupGetter__') return local.Object.prototype.__lookupGetter__;
if (key === '__lookupSetter__') return local.Object.prototype.__lookupSetter__;
try {
return Contextify.value(host.Reflect.get(object, key), null, deepTraps, flags);
} catch (e) {
throw Contextify.value(e);
}
};
base.set = (target, key, value, receiver) => {
if (key === '__proto__') return false;
if (flags && flags.protected && typeof value === 'function') return false;
value = Decontextify.value(value);
try {
return host.Reflect.set(object, key, value);
} catch (e) {
throw Contextify.value(e);
}
};
base.getOwnPropertyDescriptor = (target, prop) => {
let def;
try {
def = host.Object.getOwnPropertyDescriptor(object, prop);
} catch (e) {
throw Contextify.value(e);
}
// Following code prevents V8 to throw
// TypeError: 'getOwnPropertyDescriptor' on proxy: trap reported non-configurability for property '<prop>'
// which is either non-existant or configurable in the proxy target
if (!def) {
return undefined;
} else if (def.get || def.set) {
return {
get: Contextify.value(def.get, null, deepTraps, flags) || undefined,
set: Contextify.value(def.set, null, deepTraps, flags) || undefined,
enumerable: def.enumerable === true,
configurable: def.configurable === true
};
} else {
return {
value: Contextify.value(def.value, null, deepTraps, flags),
writable: def.writable === true,
enumerable: def.enumerable === true,
configurable: def.configurable === true
};
}
};
base.defineProperty = (target, key, descriptor) => {
// There's a chance accessing a property throws an error so we must not access them
// in try catch to prevent contextyfing local objects.
const descGet = descriptor.get;
const descSet = descriptor.set;
const descValue = descriptor.value;
if (flags && flags.protected) {
if (descGet || descSet || typeof descValue === 'function') return false;
}
const propertyDescriptor = host.Object.create(null);
if (descGet || descSet) {
propertyDescriptor.get = Decontextify.value(descGet, null, deepTraps, flags) || undefined;
propertyDescriptor.set = Decontextify.value(descSet, null, deepTraps, flags) || undefined;
propertyDescriptor.enumerable = descriptor.enumerable === true;
propertyDescriptor.configurable = descriptor.configurable === true;
} else {
propertyDescriptor.value = Decontextify.value(descValue, null, deepTraps, flags);
propertyDescriptor.writable = descriptor.writable === true;
propertyDescriptor.enumerable = descriptor.enumerable === true;
propertyDescriptor.configurable = descriptor.configurable === true;
}
try {
return host.Object.defineProperty(object, key, propertyDescriptor);
} catch (e) {
throw Contextify.value(e);
}
};
base.deleteProperty = (target, prop) => {
try {
return Contextify.value(host.Reflect.deleteProperty(object, prop));
} catch (e) {
throw Contextify.value(e);
}
};
base.getPrototypeOf = (target) => {
return local.Object.prototype;
};
base.setPrototypeOf = (target) => {
throw new VMError(OPNA);
};
base.has = (target, key) => {
try {
return Contextify.value(host.Reflect.has(object, key));
} catch (e) {
throw Contextify.value(e);
}
};
base.isExtensible = target => {
try {
return Contextify.value(host.Object.isExtensible(object));
} catch (e) {
throw Contextify.value(e);
}
};
base.ownKeys = target => {
try {
return Contextify.value(host.Reflect.ownKeys(object));
} catch (e) {
throw Contextify.value(e);
}
};
base.preventExtensions = target => {
try {
host.Object.preventExtensions(object);
return true;
} catch (e) {
throw Contextify.value(e);
}
};
base.enumerate = target => {
try {
return Contextify.value(host.Reflect.enumerate(object));
} catch (e) {
throw Contextify.value(e);
}
};
const proxy = new host.Proxy(object, host.Object.assign(base, traps, deepTraps));
Contextify.proxies.set(object, proxy);
Contextified.set(proxy, object);
return proxy;
};
Contextify.value = (value, traps, deepTraps, flags, mock) => {
try {
if (Decontextified.has(value)) {
// Decontextified object has returned back to vm
return Decontextified.get(value);
} else if (Contextify.proxies.has(value)) {
// Contextified proxy already exists, reuse
return Contextify.proxies.get(value);
}
switch (typeof value) {
case 'object':
if (value === null) {
return null;
} else if (instanceOf(value, host.Number)) { return host.Number(value);
} else if (instanceOf(value, host.String)) { return host.String(value);
} else if (instanceOf(value, host.Boolean)) { return host.Boolean(value);
} else if (instanceOf(value, host.Date)) { return Contextify.instance(value, Date, deepTraps, flags, 'Date');
} else if (instanceOf(value, host.RangeError)) { return Contextify.instance(value, RangeError, deepTraps, flags, 'Error');
} else if (instanceOf(value, host.ReferenceError)) { return Contextify.instance(value, ReferenceError, deepTraps, flags, 'Error');
} else if (instanceOf(value, host.SyntaxError)) { return Contextify.instance(value, SyntaxError, deepTraps, flags, 'Error');
} else if (instanceOf(value, host.TypeError)) { return Contextify.instance(value, TypeError, deepTraps, flags, 'Error');
} else if (instanceOf(value, host.VMError)) { return Contextify.instance(value, VMError, deepTraps, flags, 'Error');
} else if (instanceOf(value, host.EvalError)) { return Contextify.instance(value, EvalError, deepTraps, flags, 'Error');
} else if (instanceOf(value, host.URIError)) { return Contextify.instance(value, URIError, deepTraps, flags, 'Error');
} else if (instanceOf(value, host.Error)) { return Contextify.instance(value, Error, deepTraps, flags, 'Error');
} else if (instanceOf(value, host.Array)) { return Contextify.instance(value, Array, deepTraps, flags, 'Array');
} else if (instanceOf(value, host.RegExp)) { return Contextify.instance(value, RegExp, deepTraps, flags, 'RegExp');
} else if (instanceOf(value, host.Map)) { return Contextify.instance(value, Map, deepTraps, flags, 'Map');
} else if (instanceOf(value, host.WeakMap)) { return Contextify.instance(value, WeakMap, deepTraps, flags, 'WeakMap');
} else if (instanceOf(value, host.Set)) { return Contextify.instance(value, Set, deepTraps, flags, 'Set');
} else if (instanceOf(value, host.WeakSet)) { return Contextify.instance(value, WeakSet, deepTraps, flags, 'WeakSet');
} else if (instanceOf(value, host.Promise)) { return Contextify.instance(value, Promise, deepTraps, flags, 'Promise');
} else if (instanceOf(value, host.Buffer)) { return Contextify.instance(value, LocalBuffer, deepTraps, flags, 'Uint8Array');
} else if (host.Reflect.getPrototypeOf(value) === null) {
return Contextify.instance(value, null, deepTraps, flags);
} else {
return Contextify.object(value, traps, deepTraps, flags, mock);
}
case 'function':
return Contextify.function(value, traps, deepTraps, flags, mock);
case 'undefined':
return undefined;
default: // string, number, boolean, symbol
return value;
}
} catch (ex) {
// Never pass the handled expcetion through! This block can't throw an exception under normal conditions.
return null;
}
};
Contextify.globalValue = (value, name) => {
return (global[name] = Contextify.value(value));
};
Contextify.readonly = (value, mock) => {
return Contextify.value(value, null, FROZEN_TRAPS, null, mock);
};
Contextify.protected = (value, mock) => {
return Contextify.value(value, null, null, {protected: true}, mock);
};
const BufferMock = host.Object.create(null);
BufferMock.allocUnsafe = function allocUnsafe(size) {
return this.alloc(size);
};
BufferMock.allocUnsafeSlow = function allocUnsafeSlow(size) {
return this.alloc(size);
};
/**
* start
* @author 广州银云信息科技有限公司
* @desc Buffer默认取原始的Buffer不做安全过滤不能随意更改会导致脚本步骤crypto执行错误
*/
const LocalBuffer = global.Buffer = Contextify.readonly(host.Buffer, BufferMock);
// const LocalBuffer = global.Buffer = host.Buffer;
//end
const exportsMap = host.Object.create(null);
exportsMap.Contextify = Contextify;
exportsMap.Decontextify = Decontextify;
exportsMap.Buffer = LocalBuffer;
return exportsMap;

View File

@ -0,0 +1,613 @@
/* eslint-disable global-require, no-use-before-define */
'use strict';
const fs = require('fs');
const vm = require('vm');
const pa = require('path');
const {EventEmitter} = require('events');
const _compileToJS = function compileToJS(code, compiler, filename) {
if ('function' === typeof compiler) return compiler(code, filename);
switch (compiler) {
case 'coffeescript':
case 'coffee-script':
case 'cs':
case 'text/coffeescript':
try {
return require('coffee-script').compile(code, {header: false, bare: true});
} catch (ex) {
throw new VMError('Coffee-Script compiler is not installed.');
}
case 'javascript':
case 'java-script':
case 'js':
case 'text/javascript':
return code;
default:
throw new VMError(`Unsupported compiler '${compiler}'.`);
}
};
/**
* Class Script
*
* @class
*/
class VMScript {
/**
* Create VMScript instance.
*
* @param {String} code Code to run.
* @param {String} [filename] Filename that shows up in any stack traces produced from this script.
* @return {VMScript}
*/
constructor(code, filename) {
this._code = String(code);
this.filename = filename || 'vm.js';
this._prefix = '';
this._suffix = '';
this._compiledVM = null;
this._compiledNodeVM = null;
}
/**
* Wraps the code.
* Will invalidate the code cache.
*
* @return {VMScript}
*/
wrap(prefix, suffix) {
const strPrefix = String(prefix);
const strSuffix = String(suffix);
if (this._prefix === strPrefix && this._suffix === strSuffix) return this;
this._prefix = strPrefix;
this._suffix = strSuffix;
this._compiledVM = null;
this._compiledNodeVM = null;
return this;
}
/**
* Noop.
* We need to change the code depending whether it is run in VM or NodeVM.
* This function cannot decide for which to compile.
*
* @deprecated Will be done on first run
* @return {VMScript}
*/
compile() {
return this;
}
/**
* For backwards compatibility.
*
* @return {String} The wrapped code
*/
get code() {
return this._prefix + this._code + this._suffix;
}
/**
* For backwards compatibility.
* Will invalidate the code cache.
*
* @param {String} newCode The new code to run.
*/
set code(newCode) {
const strNewCode = String(newCode);
if (strNewCode === this._prefix + this._code + this._suffix) return;
this._code = strNewCode;
this._prefix = '';
this._suffix = '';
this._compiledVM = null;
this._compiledNodeVM = null;
}
/**
* Will compile the code for VM and cache it
*
* @return {VMScript}
*/
_compileVM() {
if (this._compiledVM) return this;
this._compiledVM = new vm.Script(this._prefix + this._code + this._suffix, {
filename: this.filename,
displayErrors: false
});
return this;
}
/**
* Will compile the code for NodeVM and cache it
*
* @return {VMScript}
*/
_compileNodeVM() {
if (this._compiledNodeVM) return this;
this._compiledNodeVM = new vm.Script('(function (exports, require, module, __filename, __dirname) { ' +
this._prefix + this._code + this._suffix + '\n})', {
filename: this.filename,
displayErrors: false
});
return this;
}
}
function loadScript(filename) {
const data = fs.readFileSync(filename, 'utf8');
return new VMScript(data, filename);
}
const SCRIPT_CACHE = {
cf: loadScript(`${__dirname}/contextify.js`).wrap('(function(require, host) { ', '\n})')._compileVM(),
sb: loadScript(`${__dirname}/sandbox.js`).wrap('(function (vm, host, Contextify, Decontextify, Buffer) { ', '\n})')._compileVM(),
exp: new VMScript('({exports: {}})')._compileVM()
};
/**
* Class VM.
*
* @property {Object} options VM options.
*/
class VM extends EventEmitter {
/**
* Create VM instance.
*
* @param {Object} [options] VM options.
* @return {VM}
*/
constructor(options = {}) {
super();
// defaults
this.options = {
timeout: options.timeout,
sandbox: options.sandbox,
compiler: options.compiler || 'javascript',
eval: options.eval === false ? false : true,
wasm: options.wasm === false ? false : true
};
const host = {
version: parseInt(process.versions.node.split('.')[0]),
console,
String,
Number,
Buffer,
Boolean,
Array,
Date,
Error,
EvalError,
RangeError,
ReferenceError,
SyntaxError,
TypeError,
URIError,
RegExp,
Function,
Object,
VMError,
Proxy,
Reflect,
Map,
WeakMap,
Set,
WeakSet,
Promise,
Symbol,
Object
};
this._context = vm.createContext(undefined, {
codeGeneration: {
strings: this.options.eval,
wasm: this.options.wasm
}
});
Reflect.defineProperty(this, '_internal', {
value: SCRIPT_CACHE.cf._compiledVM.runInContext(this._context, {
filename: SCRIPT_CACHE.cf.filename,
displayErrors: false
}).call(this._context, require, host)
});
// prepare global sandbox
if (this.options.sandbox) {
if ('object' !== typeof this.options.sandbox) {
throw new VMError('Sandbox must be object.');
}
for (const name in this.options.sandbox) {
if (Object.prototype.hasOwnProperty.call(this.options.sandbox, name)) {
this._internal.Contextify.globalValue(this.options.sandbox[name], name);
}
}
}
}
/**
* Freezes the object inside VM making it read-only. Not available for primitive values.
*
* @static
* @param {*} object Object to freeze.
* @param {String} [globalName] Whether to add the object to global.
* @return {*} Object to freeze.
*/
freeze(value, globalName) {
this._internal.Contextify.readonly(value);
if (globalName) this._internal.Contextify.globalValue(value, globalName);
return value;
}
/**
* Protects the object inside VM making impossible to set functions as it's properties. Not available for primitive values.
*
* @static
* @param {*} object Object to protect.
* @param {String} [globalName] Whether to add the object to global.
* @return {*} Object to protect.
*/
protect(value, globalName) {
this._internal.Contextify.protected(value);
if (globalName) this._internal.Contextify.globalValue(value, globalName);
return value;
}
/**
* Run the code in VM.
*
* @param {String} code Code to run.
* @return {*} Result of executed code.
*/
run(code) {
if (this.options.compiler !== 'javascript') {
code = _compileToJS(code, this.options.compiler);
}
const script = code instanceof VMScript ? code : new VMScript(code);
script._compileVM();
try {
return this._internal.Decontextify.value(script._compiledVM.runInContext(this._context, {
filename: script.filename,
displayErrors: false,
timeout: this.options.timeout
}));
} catch (e) {
throw this._internal.Decontextify.value(e);
}
}
}
/**
* Class NodeVM.
*
* @class
* @extends {EventEmitter}
* @property {Object} module Pointer to main module.
*/
class NodeVM extends EventEmitter {
/**
* Create NodeVM instance.
*
* Unlike VM, NodeVM lets you use require same way like in regular node.
*
* @param {Object} [options] VM options.
* @return {NodeVM}
*/
constructor(options = {}) {
super();
// defaults
this.options = {
sandbox: options.sandbox,
console: options.console || 'inherit',
require: options.require || false,
compiler: options.compiler || 'javascript',
eval: options.eval === false ? false : true,
wasm: options.wasm === false ? false : true,
nesting: options.nesting || false,
wrapper: options.wrapper || 'commonjs',
sourceExtensions: options.sourceExtensions || ['js']
};
const host = {
version: parseInt(process.versions.node.split('.')[0]),
require,
process,
console,
setTimeout,
setInterval,
setImmediate,
clearTimeout,
clearInterval,
clearImmediate,
String,
Number,
Buffer,
Boolean,
Array,
Date,
Error,
EvalError,
RangeError,
ReferenceError,
SyntaxError,
TypeError,
URIError,
RegExp,
Function,
Object,
VMError,
Proxy,
Reflect,
Map,
WeakMap,
Set,
WeakSet,
Promise,
Symbol
};
if (this.options.nesting) {
host.VM = VM;
host.NodeVM = NodeVM;
}
this._context = vm.createContext(undefined, {
codeGeneration: {
strings: this.options.eval,
wasm: this.options.wasm
}
});
Object.defineProperty(this, '_internal', {
value: SCRIPT_CACHE.cf._compiledVM.runInContext(this._context, {
filename: SCRIPT_CACHE.cf.filename,
displayErrors: false
}).call(this._context, require, host)
});
const closure = SCRIPT_CACHE.sb._compiledVM.runInContext(this._context, {
filename: SCRIPT_CACHE.sb.filename,
displayErrors: false
});
Object.defineProperty(this, '_prepareRequire', {
value: closure.call(this._context, this, host, this._internal.Contextify, this._internal.Decontextify, this._internal.Buffer)
});
// prepare global sandbox
if (this.options.sandbox) {
if ('object' !== typeof this.options.sandbox) {
throw new VMError('Sandbox must be object.');
}
for (const name in this.options.sandbox) {
if (Object.prototype.hasOwnProperty.call(this.options.sandbox, name)) {
this._internal.Contextify.globalValue(this.options.sandbox[name], name);
}
}
}
if (this.options.require && this.options.require.import) {
if (!Array.isArray(this.options.require.import)) {
this.options.require.import = [this.options.require.import];
}
for (let i = 0, l = this.options.require.import.length; i < l; i++) {
this.require(this.options.require.import[i]);
}
}
}
/**
* @deprecated
*/
call(method, ...args) {
if ('function' === typeof method) {
return method.apply(args);
} else {
throw new VMError('Unrecognized method type.');
}
}
/**
* Freezes the object inside VM making it read-only. Not available for primitive values.
*
* @static
* @param {*} object Object to freeze.
* @param {String} [globalName] Whether to add the object to global.
* @return {*} Object to freeze.
*/
freeze(value, globalName) {
this._internal.Contextify.readonly(value);
if (global) this._internal.Contextify.globalValue(value, globalName);
return value;
}
/**
* Protects the object inside VM making impossible to set functions as it's properties. Not available for primitive values.
*
* @static
* @param {*} object Object to protect.
* @param {String} [globalName] Whether to add the object to global.
* @return {*} Object to protect.
*/
protect(value, globalName) {
this._internal.Contextify.protected(value);
if (global) this._internal.Contextify.globalValue(value, globalName);
return value;
}
/**
* Require a module in VM and return it's exports.
*
* @param {String} module Module name.
* @return {*} Exported module.
*/
require(module) {
return this.run(`module.exports = require('${module}');`, 'vm.js');
}
/**
* Run the code in NodeVM.
*
* First time you run this method, code is executed same way like in node's regular `require` - it's executed with
* `module`, `require`, `exports`, `__dirname`, `__filename` variables and expect result in `module.exports'.
*
* @param {String} code Code to run.
* @param {String} [filename] Filename that shows up in any stack traces produced from this script.
* @return {*} Result of executed code.
*/
run(code, filename) {
if (this.options.compiler !== 'javascript') {
code = _compileToJS(code, this.options.compiler, filename);
}
let dirname;
let returned;
if (filename) {
filename = pa.resolve(filename);
dirname = pa.dirname(filename);
} else {
filename = null;
dirname = null;
}
const module = SCRIPT_CACHE.exp._compiledVM.runInContext(this._context, {
displayErrors: false
});
const script = code instanceof VMScript ? code : new VMScript(code, filename);
script._compileNodeVM();
try {
const closure = script._compiledNodeVM.runInContext(this._context, {
filename: script.filename,
displayErrors: false
});
returned = closure.call(this._context, module.exports, this._prepareRequire(dirname), module, filename, dirname);
} catch (e) {
throw this._internal.Decontextify.value(e);
}
if (this.options.wrapper === 'commonjs') {
return this._internal.Decontextify.value(module.exports);
} else {
return this._internal.Decontextify.value(returned);
}
}
/**
* Create NodeVM and run code inside it.
*
* @param {String} script Javascript code.
* @param {String} [filename] File name (used in stack traces only).
* @param {Object} [options] VM options.
* @return {NodeVM} VM.
*/
static code(script, filename, options) {
if (filename != null) {
if ('object' === typeof filename) {
options = filename;
filename = null;
} else if ('string' === typeof filename) {
filename = pa.resolve(filename);
} else {
throw new VMError('Invalid arguments.');
}
}
if (arguments.length > 3) {
throw new VMError('Invalid number of arguments.');
}
return new NodeVM(options).run(script, filename);
}
/**
* Create NodeVM and run script from file inside it.
*
* @param {String} [filename] File name (used in stack traces only).
* @param {Object} [options] VM options.
* @return {NodeVM} VM.
*/
static file(filename, options) {
filename = pa.resolve(filename);
if (!fs.existsSync(filename)) {
throw new VMError(`Script '${filename}' not found.`);
}
if (fs.statSync(filename).isDirectory()) {
throw new VMError('Script must be file, got directory.');
}
return new NodeVM(options).run(fs.readFileSync(filename, 'utf8'), filename);
}
}
/**
* VMError.
*
* @class
* @extends {Error}
* @property {String} stack Call stack.
* @property {String} message Error message.
*/
class VMError extends Error {
/**
* Create VMError instance.
*
* @param {String} message Error message.
* @return {VMError}
*/
constructor(message) {
super(message);
this.name = 'VMError';
Error.captureStackTrace(this, this.constructor);
}
}
exports.VMError = VMError;
exports.NodeVM = NodeVM;
exports.VM = VM;
exports.VMScript = VMScript;

View File

@ -0,0 +1,526 @@
/* eslint-disable no-shadow, no-invalid-this */
/* global vm, host, Contextify, Decontextify, VMError */
'use strict';
const {Script} = host.require('vm');
const fs = host.require('fs');
const pa = host.require('path');
const {match} = host.require('../lib/wildcard');
const BUILTIN_MODULES = host.process.binding('natives');
const parseJSON = JSON.parse;
/**
* @param {Object} host Hosts's internal objects.
*/
return ((vm, host) => {
'use strict';
const global = this;
const TIMERS = new host.WeakMap(); // Contains map of timers created inside sandbox
const BUILTINS = {};
const CACHE = {};
const EXTENSIONS = {
['.json'](module, filename) {
try {
const code = fs.readFileSync(filename, 'utf8');
module.exports = parseJSON(code);
} catch (e) {
throw Contextify.value(e);
}
},
['.node'](module, filename) {
if (vm.options.require.context === 'sandbox') throw new VMError('Native modules can be required only with context set to \'host\'.');
try {
module.exports = Contextify.readonly(host.require(filename));
} catch (e) {
throw Contextify.value(e);
}
}
};
for (let i = 0; i < vm.options.sourceExtensions.length; i++) {
const ext = vm.options.sourceExtensions[i];
EXTENSIONS['.' + ext] = (module, filename, dirname) => {
if (vm.options.require.context !== 'sandbox') {
try {
module.exports = Contextify.readonly(host.require(filename));
} catch (e) {
throw Contextify.value(e);
}
} else {
let closure;
try {
// Load module
let contents = fs.readFileSync(filename, 'utf8');
if (typeof vm.options.compiler === 'function') {
contents = vm.options.compiler(contents, filename);
}
const code = `(function (exports, require, module, __filename, __dirname) { 'use strict'; ${contents} \n});`;
// Precompile script
const script = new Script(code, {
filename: filename || 'vm.js',
displayErrors: false
});
closure = script.runInContext(global, {
filename: filename || 'vm.js',
displayErrors: false
});
} catch (ex) {
throw Contextify.value(ex);
}
// run the script
closure(module.exports, module.require, module, filename, dirname);
}
};
}
const _parseExternalOptions = (options) => {
if (Array.isArray(options)) {
return {
external: options,
transitive: false
};
}
return {
external: options.modules,
transitive: options.transitive
};
};
/**
* Resolve filename.
*/
const _resolveFilename = (path) => {
if (!path) return null;
path = pa.resolve(path);
const exists = fs.existsSync(path);
const isdir = exists ? fs.statSync(path).isDirectory() : false;
// direct file match
if (exists && !isdir) return path;
// load as file
for (let i = 0; i < vm.options.sourceExtensions.length; i++) {
const ext = vm.options.sourceExtensions[i];
if (fs.existsSync(`${path}.${ext}`)) return `${path}.${ext}`;
}
if (fs.existsSync(`${path}.json`)) return `${path}.json`;
if (fs.existsSync(`${path}.node`)) return `${path}.node`;
// load as module
if (fs.existsSync(`${path}/package.json`)) {
let pkg;
try {
pkg = JSON.parse(fs.readFileSync(`${path}/package.json`, 'utf8'));
} catch (ex) {
throw new VMError(`Module '${path}' has invalid package.json`, 'EMODULEINVALID');
}
let main;
if (pkg && pkg.main) {
main = _resolveFilename(`${path}/${pkg.main}`);
if (!main) main = _resolveFilename(`${path}/index`);
} else {
main = _resolveFilename(`${path}/index`);
}
return main;
}
// load as directory
for (let i = 0; i < vm.options.sourceExtensions.length; i++) {
const ext = vm.options.sourceExtensions[i];
if (fs.existsSync(`${path}/index.${ext}`)) return `${path}/index.${ext}`;
}
if (fs.existsSync(`${path}/index.json`)) return `${path}/index.json`;
if (fs.existsSync(`${path}/index.node`)) return `${path}/index.node`;
return null;
};
/**
* Builtin require.
*/
const _requireBuiltin = (moduleName) => {
if (moduleName === 'buffer') return ({Buffer});
if (BUILTINS[moduleName]) return BUILTINS[moduleName].exports; // Only compiled builtins are stored here
if (moduleName === 'util') {
return Contextify.readonly(host.require(moduleName), {
// Allows VM context to use util.inherits
inherits: (ctor, superCtor) => {
ctor.super_ = superCtor;
Object.setPrototypeOf(ctor.prototype, superCtor.prototype);
}
});
}
if (moduleName === 'events' || moduleName === 'internal/errors') {
try {
const script = new Script(`(function (exports, require, module, process, internalBinding) {
'use strict';
const primordials = global;
${BUILTIN_MODULES[moduleName]}
\n
});`, {
filename: `${moduleName}.vm.js`
});
// setup module scope
const module = BUILTINS[moduleName] = {
exports: {},
require: _requireBuiltin
};
// run script
script.runInContext(global)(module.exports, module.require, module, host.process, host.process.binding);
return module.exports;
} catch (e) {
throw Contextify.value(e);
}
}
return Contextify.readonly(host.require(moduleName));
};
/**
* Prepare require.
*/
const _prepareRequire = (currentDirname, parentAllowsTransitive = false) => {
const _require = moduleName => {
if (vm.options.nesting && moduleName === 'vm2') return {VM: Contextify.readonly(host.VM), NodeVM: Contextify.readonly(host.NodeVM)};
if (!vm.options.require) throw new VMError(`Access denied to require '${moduleName}'`, 'EDENIED');
if (moduleName == null) throw new VMError("Module '' not found.", 'ENOTFOUND');
if (typeof moduleName !== 'string') throw new VMError(`Invalid module name '${moduleName}'`, 'EINVALIDNAME');
let filename;
let allowRequireTransitive = false;
// Mock?
if (vm.options.require.mock && vm.options.require.mock[moduleName]) {
return Contextify.readonly(vm.options.require.mock[moduleName]);
}
// Builtin?
if (BUILTIN_MODULES[moduleName]) {
if (host.Array.isArray(vm.options.require.builtin)) {
if (vm.options.require.builtin.indexOf('*') >= 0) {
if (vm.options.require.builtin.indexOf(`-${moduleName}`) >= 0) {
throw new VMError(`Access denied to require '${moduleName}'`, 'EDENIED');
}
} else if (vm.options.require.builtin.indexOf(moduleName) === -1) {
throw new VMError(`Access denied to require '${moduleName}'`, 'EDENIED');
}
} else if (vm.options.require.builtin) {
if (!vm.options.require.builtin[moduleName]) {
throw new VMError(`Access denied to require '${moduleName}'`, 'EDENIED');
}
} else {
throw new VMError(`Access denied to require '${moduleName}'`, 'EDENIED');
}
return _requireBuiltin(moduleName);
}
// External?
if (!vm.options.require.external) throw new VMError(`Access denied to require '${moduleName}'`, 'EDENIED');
if (/^(\.|\.\/|\.\.\/)/.exec(moduleName)) {
// Module is relative file, e.g. ./script.js or ../script.js
if (!currentDirname) throw new VMError('You must specify script path to load relative modules.', 'ENOPATH');
filename = _resolveFilename(`${currentDirname}/${moduleName}`);
} else if (/^(\/|\\|[a-zA-Z]:\\)/.exec(moduleName)) {
// Module is absolute file, e.g. /script.js or //server/script.js or C:\script.js
filename = _resolveFilename(moduleName);
} else {
// Check node_modules in path
if (!currentDirname) throw new VMError('You must specify script path to load relative modules.', 'ENOPATH');
if (typeof vm.options.require.external === 'object') {
const { external, transitive } = _parseExternalOptions(vm.options.require.external);
const isWhitelisted = external.some(ext => match(ext, moduleName)) || (transitive && parentAllowsTransitive);
if (!isWhitelisted) {
throw new VMError(`The module '${moduleName}' is not whitelisted in VM.`, 'EDENIED');
}
allowRequireTransitive = true;
}
const paths = currentDirname.split(pa.sep);
while (paths.length) {
const path = paths.join(pa.sep);
// console.log moduleName, "#{path}#{pa.sep}node_modules#{pa.sep}#{moduleName}"
filename = _resolveFilename(`${path}${pa.sep}node_modules${pa.sep}${moduleName}`);
if (filename) break;
paths.pop();
}
}
if (!filename && vm.options.require.resolve) {
filename = _resolveFilename(vm.options.require.resolve(moduleName, currentDirname));
}
if (!filename) throw new VMError(`Cannot find module '${moduleName}'`, 'ENOTFOUND');
// return cache whenever possible
if (CACHE[filename]) return CACHE[filename].exports;
const dirname = pa.dirname(filename);
const extname = pa.extname(filename);
if (vm.options.require.root) {
const rootPaths = Array.isArray(vm.options.require.root) ? vm.options.require.root : [vm.options.require.root];
const allowedModule = rootPaths.some(path => dirname.startsWith(pa.resolve(path)));
if (!allowedModule) {
throw new VMError(`Module '${moduleName}' is not allowed to be required. The path is outside the border!`, 'EDENIED');
}
}
const module = CACHE[filename] = {
filename,
exports: {},
require: _prepareRequire(dirname, allowRequireTransitive)
};
// lookup extensions
if (EXTENSIONS[extname]) {
EXTENSIONS[extname](module, filename, dirname);
return module.exports;
}
throw new VMError(`Failed to load '${moduleName}': Unknown type.`, 'ELOADFAIL');
};
return _require;
};
/**
* Prepare sandbox.
*/
global.setTimeout = (callback, delay, ...args) => {
const tmr = host.setTimeout(Decontextify.value(() => {
callback(...args);
}), Decontextify.value(delay));
const local = {
ref: () => tmr.ref(),
unref: () => tmr.unref()
};
TIMERS.set(local, tmr);
return local;
};
global.setInterval = (callback, interval, ...args) => {
const tmr = host.setInterval(Decontextify.value(() => {
callback(...args);
}), Decontextify.value(interval));
const local = {
ref: () => tmr.ref(),
unref: () => tmr.unref()
};
TIMERS.set(local, tmr);
return local;
};
global.setImmediate = (callback, ...args) => {
const tmr = host.setImmediate(Decontextify.value(() => {
callback(...args);
}));
const local = {
ref: () => tmr.ref(),
unref: () => tmr.unref()
};
TIMERS.set(local, tmr);
return local;
};
global.clearTimeout = (local) => {
host.clearTimeout(TIMERS.get(local));
return null;
};
global.clearInterval = (local) => {
host.clearInterval(TIMERS.get(local));
return null;
};
global.clearImmediate = (local) => {
host.clearImmediate(TIMERS.get(local));
return null;
};
global.process = {
argv: [],
title: host.process.title,
version: host.process.version,
versions: Contextify.readonly(host.process.versions),
arch: host.process.arch,
platform: host.process.platform,
env: {},
pid: host.process.pid,
features: Contextify.readonly(host.process.features),
nextTick(callback, ...args) {
if (typeof callback !== 'function') {
throw new Error('Callback must be a function.');
}
try {
return host.process.nextTick(Decontextify.value(() => {
callback(...args);
}));
} catch (e) {
throw Contextify.value(e);
}
},
hrtime() {
try {
return host.process.hrtime();
} catch (e) {
throw Contextify.value(e);
}
},
cwd() {
try {
return host.process.cwd();
} catch (e) {
throw Contextify.value(e);
}
},
on(name, handler) {
if (name !== 'beforeExit' && name !== 'exit') {
throw new Error(`Access denied to listen for '${name}' event.`);
}
try {
host.process.on(name, Decontextify.value(handler));
} catch (e) {
throw Contextify.value(e);
}
return this;
},
once(name, handler) {
if (name !== 'beforeExit' && name !== 'exit') {
throw new Error(`Access denied to listen for '${name}' event.`);
}
try {
host.process.once(name, Decontextify.value(handler));
} catch (e) {
throw Contextify.value(e);
}
return this;
},
listeners(name) {
// Filter out listeners, which were not created in this sandbox (isVMProxy is undefined)
return Contextify.value(host.process.listeners(name).filter(listener => !Contextify.value(listener).isVMProxy));
},
removeListener(name, handler) {
try {
host.process.removeListener(name, Decontextify.value(handler));
} catch (e) {
throw Contextify.value(e);
}
return this;
},
umask() {
if (arguments.length) {
throw new Error('Access denied to set umask.');
}
try {
return host.process.umask();
} catch (e) {
throw Contextify.value(e);
}
}
};
if (vm.options.console === 'inherit') {
global.console = Contextify.readonly(host.console);
} else if (vm.options.console === 'redirect') {
global.console = {
debug(...args) {
vm.emit('console.debug', ...Decontextify.arguments(args));
return null;
},
log(...args) {
vm.emit('console.log', ...Decontextify.arguments(args));
return null;
},
info(...args) {
vm.emit('console.info', ...Decontextify.arguments(args));
return null;
},
warn(...args) {
vm.emit('console.warn', ...Decontextify.arguments(args));
return null;
},
error(...args) {
vm.emit('console.error', ...Decontextify.arguments(args));
return null;
},
dir(...args) {
vm.emit('console.dir', ...Decontextify.arguments(args));
return null;
},
time: () => {},
timeEnd: () => {},
trace(...args) {
vm.emit('console.trace', ...Decontextify.arguments(args));
return null;
}
};
}
/*
Return contextized require.
*/
return _prepareRequire;
})(vm, host);

View File

@ -0,0 +1,7 @@
const match = (wildcard, s) => {
const regexString = wildcard.replace(/\*/, '\\S*').replace(/\?/g, '.');
const regex = new RegExp(regexString);
return regex.test(s);
};
module.exports = {match};

112
app/request/libs/xml.js Normal file
View File

@ -0,0 +1,112 @@
(() => {
'use strict';
class mainClass {
constructor() {}
jsonToXml() {
var XML = function () {};
XML.ObjTree = function () {
return this;
};
XML.ObjTree.prototype.xmlDecl = '<?xml version="1.0" encoding="UTF-8" ?>\n';
XML.ObjTree.prototype.attr_prefix = '-';
XML.ObjTree.prototype.writeXML = function (tree,attr_obj) {
var xml = this.hash_to_xml(null, tree,attr_obj);
return this.xmlDecl + xml;
};
XML.ObjTree.prototype.hash_to_xml = function (name, tree,attr_obj) {
var elem = [];
var attr = [];
for (var key in tree) {
if (!tree.hasOwnProperty(key)) continue;
var val = tree[key],tmp_attr_obj={};
if(attr_obj[key]){
if(attr_obj[key] instanceof Array){
if(typeof (val) == "object" && val.constructor == Array&&attr_obj[key][1]){//如果是数组,且没有子对象,则走此内容
tmp_attr_obj=attr_obj[key];
}else{
tmp_attr_obj=attr_obj[key][1]||{};if(attr_obj[key][0])key = `${key} ${attr_obj[key][0]||""}`;
}
}
else if(attr_obj[key])key = `${key} ${attr_obj[key]||""}`;
}
key=key.replace(/\s\s/g," ")
if (key.charAt(0) != this.attr_prefix) {
if (typeof (val) == "undefined" || val == null) {
elem[elem.length] = "<" + key + " />";
} else if (typeof (val) == "object" && val.constructor == Array) {
elem[elem.length] = this.array_to_xml(key, val,tmp_attr_obj);
} else if (typeof (val) == "object") {
elem[elem.length] = this.hash_to_xml(key, val,tmp_attr_obj);
} else {
elem[elem.length] = this.scalar_to_xml(key, val);
}
} else {
attr[attr.length] = " " + (key.substring(1)) + '="' + (this.xml_escape(val)) + '"';
}
}
var jattr = attr.join("");
var jelem = elem.join("");
if (typeof (name) == "undefined" || name == null) {
// no tag
} else if (elem.length > 0) {
if (jelem.match(/\n/)) {
jelem = "<" + name + jattr + ">\n" + jelem + "</" + (name || "").split(" ")[0] + ">\n";
} else {
jelem = "<" + name + jattr + ">" + jelem + "</" + (name || "").split(" ")[0] + ">\n";
}
} else {
jelem = "<" + name + jattr + " />\n";
}
return jelem;
};
XML.ObjTree.prototype.array_to_xml = function (name, array,attr_obj) {
var out = [];
for (var i = 0; i < array.length; i++) {
var val = array[i];
let tmp_name=attr_obj[0]&&attr_obj[0][i]?`${name} ${typeof(attr_obj[0]==="string")?attr_obj[0]:attr_obj[0][i]}`:name;
if (typeof (val) == "undefined" || val == null) {
out[out.length] = "<" + tmp_name + " />";
} else if (typeof (val) == "object" && val.constructor == Array) {
out[out.length] = this.array_to_xml(tmp_name, val,attr_obj[i+1]);
} else if (typeof (val) == "object") {
out[out.length] = this.hash_to_xml(tmp_name, val,attr_obj[i+1]);
} else {
out[out.length] = this.scalar_to_xml(tmp_name, val);
}
}
return out.join("");
};
XML.ObjTree.prototype.scalar_to_xml = function (name, text) {
if (name == "#text") {
return this.xml_escape(text);
} else {
return "<" + name + ">" + this.xml_escape(text) + "</" + (name || "").split(" ")[0] + ">\n";
}
};
XML.ObjTree.prototype.xml_escape = function (text) {
let tmpResult=String(text);
if(/<!\[CDATA/.test(tmpResult)&&/]]>/.test(tmpResult)){
let tmpPreIndex=tmpResult.indexOf("<![CDATA[");
let tmpLastIndex=tmpResult.substr(tmpPreIndex,tmpResult.length).indexOf("]]>")+3;
return tmpResult.substr(0,tmpPreIndex).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;')+tmpResult.substr(tmpPreIndex,tmpLastIndex)+tmpResult.substr(tmpLastIndex,tmpResult.length).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
}
return String(text).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
};
return function (input,inputXmlAttrObj) {
var xotree = new XML.ObjTree();
return xotree.writeXML(input,inputXmlAttrObj||{});
}
}
}
exports.core = mainClass;
})();

23
app/request/main.js Normal file
View File

@ -0,0 +1,23 @@
let _LibsFlowCommon = require('./unit.js');
let _LibsCommon = require('./libs/common.js');
process.on('message', (message) => {
switch (message.action) {
case 'ajax': {
message.data.env = _LibsCommon.parseEnv(message.data.env);
new _LibsFlowCommon.core().main(message.data, (tmpInputReport, tmpInputHistory) => {
['general', 'requestInfo', 'resultInfo'].forEach((keyName) => {
if (typeof tmpInputHistory[keyName] === 'string')
tmpInputHistory[keyName] = JSON.parse(tmpInputHistory[keyName]);
});
process.send({
action: 'finish',
data: {
report: tmpInputReport,
history: tmpInputHistory,
},
});
});
break;
}
}
});

830
app/request/unit.js Normal file
View File

@ -0,0 +1,830 @@
(function () {
'use strict';
var url = require('url'),
querystring = require('querystring'),
_LibsCommon = require('./libs/common'),
_LibsApiUtil = require('./libs/apiUtil'),
_Formdata = require('form-data'),
parse = {},
privateFun = {},
_ContentDisposition = require('content-disposition'),
_RedirectClass = require('./libs/redirect'),
_HttpPackageClass = new (require('./libs/http.package').core)(),
_GetFileClass = new (require('./libs/getFile.package').core)(),
_LibsMineType = require('./libs/mineType.package');
let CONFIG = require('./config.json');
const _EO_LANG_OBJ = require('./lang.json');
var iconv = require('iconv-lite');
global.eoLang = _EO_LANG_OBJ['cn'];
/**
* 解析uri信息
* @param {number} protocol 请求协议
* @param {string} uri 原始数据
* @return uri
*/
parse.uri = function (protocol, uri) {
if (!/((http:\/\/)|(https:\/\/))/.test(uri)) {
uri = (protocol == '1' ? 'https://' : 'http://') + uri;
}
return uri;
};
/**
* 渲染请求数据
* @param {object} inputTestData 请求数据信息
* @param {array} response 返回信息体列表
* @return {object} request信息
*/
privateFun.parseTestData = function (inputTestData, env) {
return new Promise(async (resolve) => {
var template = {
pathObject: null,
uri: '',
options: {
uri: '',
method: inputTestData.method,
headers: {},
},
beforeObject: null,
body: null,
formToJsonBody: [],
label: {
muti: false,
},
jwt: '',
},
tmpHeaderObj = {},
tmpBinaryFileName,
tmpRequestType = inputTestData.requestType.toString();
try {
inputTestData.headers.map(function (val, key) {
tmpHeaderObj[val.headerName] = val.headerValue;
});
switch (inputTestData.auth.status) {
case '1': {
if (inputTestData.auth.basicAuth) {
tmpHeaderObj['Authorization'] =
'Basic ' +
Buffer.from(
(inputTestData.auth.basicAuth.username || '') + ':' + (inputTestData.auth.basicAuth.password || '')
).toString('base64');
}
break;
}
case '2': {
template.jwt = _LibsCommon.jwt(
{
alg: inputTestData.auth.jwtAuth.alg,
typ: 'JWT',
},
inputTestData.auth.jwtAuth.payload,
inputTestData.auth.jwtAuth.secretSalt
);
switch (template.jwt) {
case 'jwtError': {
resolve({
status: 'preCode error',
content: global.eoLang['213d3b0f-b267-4d5c-9512-0a06e2a5a522'],
});
return;
}
}
if (inputTestData.auth.jwtAuth.isBearer) {
template.jwt = `Bearer ${template.jwt}`;
}
switch (inputTestData.auth.jwtAuth.position) {
case 'header': {
tmpHeaderObj[inputTestData.auth.jwtAuth.tokenName || 'tokenName'] = template.jwt;
break;
}
case 'query': {
if (inputTestData.URL.indexOf('?') > -1) {
inputTestData.URL +=
(inputTestData.URL.replace(/(((?!\?).)*)\?/, '') ? '&' : '') +
(inputTestData.auth.jwtAuth.tokenName || 'tokenName') +
'=' +
template.jwt;
} else {
inputTestData.URL += '?' + (inputTestData.auth.jwtAuth.tokenName || 'tokenName') + '=' + template.jwt;
}
break;
}
}
break;
}
}
let tmpNewUri =
inputTestData.URL.indexOf('?') === -1 ? '' : inputTestData.URL.replace(/(((?!\?).)*)\?/, '') || '';
switch (tmpRequestType) {
case '0': {
let tmpParamObj = {};
inputTestData.params.map(function (val, key) {
if ((val.paramType || 0).toString() == '1') {
switch (Object.prototype.toString.call(tmpParamObj[val.paramKey])) {
case '[object Array]': {
break;
}
default: {
tmpParamObj[val.paramKey] = [];
break;
}
}
let tmpFileNameArr = (val.paramInfo || '').split(','),
tmpFileArr = val.files || [];
tmpFileArr.map((tmpFileVal, tmpFileKey) => {
if (typeof tmpFileVal === 'object') {
tmpParamObj[val.paramKey].push(tmpFileVal);
} else {
tmpParamObj[val.paramKey].push({
name: tmpFileNameArr[tmpFileKey] || '',
dataUrl: tmpFileVal,
});
}
});
template.label.muti = true;
} else {
switch (Object.prototype.toString.call(tmpParamObj[val.paramKey])) {
case '[object Array]': {
tmpParamObj[val.paramKey].push(val.paramInfo || '');
break;
}
default: {
if (tmpParamObj[val.paramKey]) {
tmpParamObj[val.paramKey] = [tmpParamObj[val.paramKey], val.paramInfo || ''];
} else {
tmpParamObj[val.paramKey] = val.paramInfo || '';
}
break;
}
}
}
});
await _LibsApiUtil
.requestPreReduceByPromise(
{
requestType: inputTestData.requestType,
url: inputTestData.URL,
headers: tmpHeaderObj,
params: tmpParamObj,
raw: '',
query: querystring.parse(tmpNewUri),
env: env,
apiRequestType: inputTestData.methodType,
},
inputTestData.beforeInject,
{
functionCode: inputTestData.functionCode,
globalHeader: inputTestData.globalHeader,
}
)
.then((tmpInputDataObj) => {
template.beforeObject = tmpInputDataObj;
});
break;
}
case '2':
case '3': {
template.formToJsonBody = _LibsCommon.bodyQueryToJson(inputTestData.params, {
apiRequestParamJsonType:
inputTestData.requestType.toString() == '2' ? inputTestData.apiRequestParamJsonType || '0' : '0',
isXml: tmpRequestType === '3',
});
let tmpWantToExecuteData = {
requestType: inputTestData.requestType,
url: inputTestData.URL,
headers: tmpHeaderObj,
params: {},
raw: '',
query: querystring.parse(tmpNewUri),
env: env,
apiRequestType: inputTestData.methodType,
};
if (tmpRequestType === '3') {
tmpWantToExecuteData.raw = template.formToJsonBody.value;
tmpWantToExecuteData.xmlAttrObj = template.formToJsonBody.attr;
} else {
tmpWantToExecuteData.raw = template.formToJsonBody;
}
await _LibsApiUtil
.requestPreReduceByPromise(tmpWantToExecuteData, inputTestData.beforeInject, {
functionCode: inputTestData.functionCode,
globalHeader: inputTestData.globalHeader,
})
.then((tmpInputDataObj) => {
template.beforeObject = tmpInputDataObj;
});
break;
}
case '4': {
await _LibsApiUtil
.requestPreReduceByPromise(
{
requestType: '4',
url: inputTestData.URL,
headers: tmpHeaderObj,
query: querystring.parse(tmpNewUri),
env: env,
binary: inputTestData.params.dataUrl,
apiRequestType: inputTestData.methodType,
},
inputTestData.beforeInject,
{
functionCode: inputTestData.functionCode,
globalHeader: inputTestData.globalHeader,
}
)
.then((tmpInputDataObj) => {
template.beforeObject = tmpInputDataObj;
});
template.body = Buffer.from(
(inputTestData.params.dataUrl || '').replace(/^data:(.*);base64,/gi, ''),
'base64'
);
tmpBinaryFileName = `[binary]${inputTestData.params.name}`;
break;
}
case '1': {
await _LibsApiUtil
.requestPreReduceByPromise(
{
requestType: '1',
url: inputTestData.URL,
headers: tmpHeaderObj,
raw: inputTestData.params,
query: querystring.parse(tmpNewUri),
env: env,
apiRequestType: inputTestData.methodType,
},
inputTestData.beforeInject,
{
functionCode: inputTestData.functionCode,
globalHeader: inputTestData.globalHeader,
}
)
.then((tmpInputDataObj) => {
template.beforeObject = tmpInputDataObj;
});
break;
}
}
switch (template.beforeObject.status) {
case 'beforeCodeError':
case 'info':
case 'terminateRequest': {
resolve({
status: 'preCode error',
content: template.beforeObject.content,
reportList: template.beforeObject.reportList,
});
return;
}
}
template.options.headers = template.beforeObject.headers;
if (tmpRequestType !== '4') {
if (
!template.label.muti &&
/"content-type":"multipart\/form-data/i.test(JSON.stringify(template.options.headers))
) {
template.label.muti = true;
}
if (template.label.muti) {
template.body = template.beforeObject.params;
} else {
template.body =
typeof template.beforeObject.params == 'string'
? template.beforeObject.params
: querystring.stringify(template.beforeObject.params || {});
}
}
template.uri = parse.uri(inputTestData.httpHeader, template.beforeObject.url);
template.pathObject = url.parse(template.uri);
template.options.path = template.pathObject.path;
template.options.hostname = template.pathObject.hostname;
template.options.port = template.pathObject.port;
template.options.protocol = template.pathObject.protocol;
template.options.auth = template.pathObject.auth;
} catch (e) {
console.error(new Date() + 'unit/common.js 227', e);
}
resolve({
options: template.options,
body: template.body,
afterInject: inputTestData.afterInject,
isMuti: template.label.muti,
functionCode: inputTestData.functionCode,
env: template.beforeObject.env,
advancedSetting: Object.assign(
{},
{
requestRedirect: 1,
sendNocacheToken: 0,
checkSSL: 0,
sendEoToken: 1,
},
inputTestData.advancedSetting || {}
),
history: {
body: template.beforeObject.params,
headers: template.options.headers,
uri: template.uri,
},
requestBody: {
body: template.beforeObject.params,
},
requestType: tmpRequestType,
queryParams: template.beforeObject.queryParams,
reportList: template.beforeObject.reportList,
binaryFileName: tmpBinaryFileName,
});
});
};
class unitCommon {
constructor() {
this.xhr = null;
this.areadyAbortXhr = false;
}
ajax(inputTestData, inputOptions, callback) {
this.areadyAbortXhr = false;
return new Promise(function (resolve, reject) {
let tmpReportData = {
response: {
headers: [],
body: '',
httpCode: 0,
testDeny: '',
responseLength: 0,
responseType: 'text',
},
request: {
headers: [],
},
reportList: inputTestData.reportList,
general: {
redirectTimes: 0,
downloadSize: 0,
downloadRate: 0,
},
},
tmpMultiForm = {},
tmpAjaxXhr;
for (let key in inputTestData.options.headers) {
tmpReportData.request.headers.push({
key: key,
value: inputTestData.options.headers[key],
});
}
try {
let tmpFunCheckIsIllegalUrl = (inputHostName, tmpInputTotalTime) => {
if (!inputHostName || new RegExp(_LibsCommon.LOCAL_REGEXP_CONST).test(inputHostName)) {
tmpReportData.response.body = inputHostName
? global.eoLang['63be68fa-31fc-498c-b49c-d3b6db10a95b']
: global.eoLang['d6fa1d73-6a43-477f-a6df-6752661c9df3'];
tmpReportData.response.testDeny = tmpInputTotalTime.toFixed(2);
tmpReportData.general.time = tmpInputTotalTime.toFixed(2) + 'ms';
if (callback) callback(tmpReportData);
reject('illegal');
return true;
}
};
if (tmpFunCheckIsIllegalUrl(inputTestData.options.hostname, 0)) return;
let tmpFunOprAjaxErr = (tmpInputErr, tmpInputTotalTime) => {
tmpReportData.response.testDeny = tmpInputTotalTime;
tmpReportData.response.body = tmpInputErr.name + '' + tmpInputErr.message;
tmpReportData.general.time = tmpInputTotalTime.toFixed(2) + 'ms';
if (callback) callback(tmpReportData);
reject('request error');
},
tmpFunReduceAjaxResEnd = (inputRes, tmpInputResponseObj) => {
tmpReportData.general.time = tmpInputResponseObj.totalTime.toFixed(2) + 'ms';
tmpReportData.general.downloadSize = tmpInputResponseObj.chunk.length;
tmpReportData.general.downloadRate = (
(tmpInputResponseObj.chunk.length / tmpInputResponseObj.contentDeliveryTiming / 1024) *
1000
).toFixed(2);
tmpReportData.response.body = tmpInputResponseObj.str;
tmpReportData.response.httpCode = inputRes.statusCode;
tmpReportData.response.responseLength = tmpInputResponseObj.chunk.length;
let tmpDetected = {},
tmpSuffix = _LibsMineType.getSuffix(inputRes.headers['content-type']),
tmpFileBinary;
if (!inputRes.headers['content-type']) {
tmpDetected =
_GetFileClass.byContent(
Buffer.concat(tmpInputResponseObj.chunk.array, tmpInputResponseObj.chunk.length) ||
tmpReportData.response.body
) || {};
}
if (
/^(text\/(.*))|(application(.*)((\/)|(\+))json)|(application(.*)((\/)|(\+))xml)/gi.test(
inputRes.headers['content-type']
) ||
(!(inputRes.headers['content-type'] && tmpSuffix) && !(tmpDetected && tmpDetected.mime))
) {
tmpReportData.response.contentType = inputRes.headers['content-type'];
if (tmpReportData.response.responseLength >= 300 * 1024) {
tmpFileBinary = Buffer.concat(
tmpInputResponseObj.chunk.array,
tmpInputResponseObj.chunk.length
).toString('base64');
tmpReportData.response.responseType = 'longText';
let tmpPathUrl = inputTestData.options.path;
tmpReportData.blobFileName = tmpPathUrl.substring(
tmpPathUrl.lastIndexOf('/') + 1,
tmpPathUrl.lastIndexOf('?') === -1 ? tmpPathUrl.length : tmpPathUrl.lastIndexOf('?')
);
}
} else {
tmpFileBinary = Buffer.concat(
tmpInputResponseObj.chunk.array,
tmpInputResponseObj.chunk.length
).toString('base64');
tmpReportData.response.responseType = 'stream';
tmpReportData.response.contentType = inputRes.headers['content-type'] || tmpDetected.mime;
let tmpPathUrl = inputTestData.options.path;
try {
tmpReportData.blobFileName = _ContentDisposition.parse(
inputRes.headers['content-disposition'] || 'undefined'
).parameters.filename;
} catch (PARSE_CONTENT_DISPOSITION_ERR) {
try {
tmpReportData.blobFileName = _ContentDisposition.parse(
encodeURI(inputRes.headers['content-disposition'] || 'undefined').replace(/\?/g, '')
).parameters.filename;
} catch (URL_ENCODE_PARSE_CONTENT_DISPOSITION_ERR) {}
}
if (!tmpReportData.blobFileName && tmpDetected && tmpDetected.ext) {
tmpReportData.blobFileName = `response.${tmpDetected.ext}`;
} else if (!tmpReportData.blobFileName) {
tmpReportData.blobFileName = tmpPathUrl.substring(
tmpPathUrl.lastIndexOf('/') + 1,
tmpPathUrl.lastIndexOf('?') === -1 ? tmpPathUrl.length : tmpPathUrl.lastIndexOf('?')
);
}
}
_LibsApiUtil
.responsePreReduceByPromise(
tmpReportData.response.body,
inputTestData.afterInject,
inputTestData.env || {},
{
globalHeader: inputOptions.globalHeader,
functionCode: inputTestData.functionCode,
responseHeaders: inputRes.headers,
params: inputOptions.requestData.requestBody,
headers: tmpAjaxXhr.getHeaders(),
query: inputOptions.requestData.queryParams,
raw: inputOptions.requestData.raw,
}
)
.then((tmpInputDataObj) => {
let tmpAfterCodeObj = tmpInputDataObj;
tmpReportData.reportList = tmpReportData.reportList.concat(tmpAfterCodeObj.reportList);
if (tmpAfterCodeObj.status === 'finish') {
if (tmpFileBinary) {
tmpReportData.response.body = tmpFileBinary;
} else {
tmpReportData.response.body = tmpAfterCodeObj.content;
tmpReportData.response.body =
typeof tmpReportData.response.body == 'string'
? tmpReportData.response.body
: JSON.stringify(tmpReportData.response.body);
}
} else {
tmpReportData.response.body = tmpAfterCodeObj.errorReason;
delete tmpReportData.response.responseType;
delete tmpReportData.blobFileName;
delete tmpReportData.response.contentType;
}
for (let key in inputRes.headers) {
tmpReportData.response.headers.push({
key: key,
value: inputRes.headers[key],
});
}
tmpReportData.response.testDeny = tmpInputResponseObj.totalTime.toFixed(2);
if (callback) callback(tmpReportData);
resolve('success');
});
};
inputOptions.timeoutLimit = CONFIG.MAX_TIME_LIMIT;
inputOptions.timeoutLimitType = 'totalTime';
if (inputTestData.isMuti) {
tmpMultiForm = _Formdata();
for (let key in inputTestData.body) {
let val = inputTestData.body[key];
switch (typeof val) {
case 'string': {
switch (inputOptions.messageEncoding) {
case 'gbk': {
val = iconv.encode(Buffer.from(val), 'gbk');
break;
}
}
tmpMultiForm.append(key, val);
break;
}
case 'object': {
if (val.length > 0) {
for (let childKey in val) {
let childVal = val[childKey];
switch (typeof childVal) {
case 'object': {
tmpMultiForm.append(
key,
Buffer.from((childVal.dataUrl || '').replace(/^data:(.*);base64,/gi, ''), 'base64'),
{
filename: childVal.name,
}
);
val[childKey] = '[file] ' + childVal.name;
break;
}
default: {
tmpMultiForm.append(key, childVal);
break;
}
}
}
} else {
tmpMultiForm.append(key, '');
}
break;
}
}
}
inputTestData.options.headers = Object.assign({}, inputTestData.options.headers, tmpMultiForm.getHeaders());
} else {
if (!/"content-length":/i.test(JSON.stringify(inputTestData.options.headers))) {
inputTestData.options.headers['Content-Length'] = Buffer.byteLength(inputTestData.body);
}
}
inputTestData.options.headers = _HttpPackageClass.setCookieToHeaders(
inputTestData.options.headers,
inputTestData.options.hostname,
inputOptions.globalHeader || {}
);
_HttpPackageClass.socketReduce(
{
postData: inputTestData.isMuti ? tmpMultiForm : inputTestData.body,
isMuti: inputTestData.isMuti,
options: inputTestData.options,
timeoutLimit: inputOptions.timeoutLimit,
timeoutLimitType: inputOptions.timeoutLimitType,
advancedSetting: inputTestData.advancedSetting,
globalHeader: inputOptions.globalHeader,
pckSplitByHeader: inputOptions.pckSplitByHeader,
messageEncoding: inputOptions.messageEncoding,
},
(tmpInputAjaxStatus, tmpInputDataObj, tmpInputXhr) => {
tmpAjaxXhr = tmpInputXhr;
tmpReportData.request.headers = [];
tmpReportData.general.timingSummary = [_LibsApiUtil.getHttpTiming(tmpInputDataObj.summaryObj)];
let headers = {};
if (tmpAjaxXhr.getHeaders) {
headers = tmpAjaxXhr.getHeaders();
for (let key in headers) {
tmpReportData.request.headers.push({
key: key,
value: headers[key],
});
}
}
let tmpHttpTotalTime = _LibsApiUtil.getMicrosToMs(
tmpInputDataObj.summaryObj.startAt,
tmpInputDataObj.summaryObj.endAt
);
switch (tmpInputAjaxStatus) {
case 'ajax_end': {
if (inputTestData.advancedSetting.requestRedirect == 1) {
tmpReportData.general.redirectTimes++;
let tmpRedirectClass = new _RedirectClass.core();
let tmpRedirectObject = tmpRedirectClass.structureAjaxFun(
inputTestData.options,
inputTestData.isMuti ? tmpMultiForm : inputTestData.body,
tmpInputDataObj.res
);
if (tmpRedirectObject) {
if (tmpFunCheckIsIllegalUrl(tmpRedirectObject.options.hostname, tmpHttpTotalTime)) return;
_HttpPackageClass.socketReduce(
{
postData: tmpRedirectObject.postData,
isMuti: inputTestData.isMuti,
options: tmpRedirectObject.options,
timeoutLimit: inputOptions.timeoutLimit - tmpHttpTotalTime,
timeoutLimitType: inputOptions.timeoutLimitType,
advancedSetting: inputOptions.advancedSetting,
pckSplitByHeader: inputOptions.pckSplitByHeader,
messageEncoding: inputOptions.messageEncoding,
},
(tmpInputRedirectAjaxStatus, tmpInputRedirectDataObj) => {
tmpReportData.general.timingSummary.push(
_LibsApiUtil.getHttpTiming(tmpInputRedirectDataObj.summaryObj)
);
let tmpRedirectHttpTotalTime = _LibsApiUtil.getMicrosToMs(
tmpInputRedirectDataObj.summaryObj.startAt,
tmpInputRedirectDataObj.summaryObj.endAt
);
switch (tmpInputRedirectAjaxStatus) {
case 'ajax_end': {
tmpFunReduceAjaxResEnd(tmpInputRedirectDataObj.res, {
chunk: tmpInputRedirectDataObj.chunk,
str: tmpInputRedirectDataObj.responseStr,
totalTime: tmpHttpTotalTime + tmpRedirectHttpTotalTime,
contentDeliveryTiming: _LibsApiUtil.getMicrosToMs(
tmpInputRedirectDataObj.summaryObj.firstByteTiming,
tmpInputRedirectDataObj.summaryObj.endAt
),
});
break;
}
case 'ajaxErr': {
tmpFunOprAjaxErr(
tmpInputRedirectDataObj.errObj,
tmpHttpTotalTime + tmpRedirectHttpTotalTime
);
break;
}
}
}
);
return;
}
}
tmpFunReduceAjaxResEnd(tmpInputDataObj.res, {
chunk: tmpInputDataObj.chunk,
str: tmpInputDataObj.responseStr,
totalTime: tmpHttpTotalTime,
contentDeliveryTiming: _LibsApiUtil.getMicrosToMs(
tmpInputDataObj.summaryObj.firstByteTiming,
tmpInputDataObj.summaryObj.endAt
),
});
break;
}
case 'ajaxErr': {
tmpFunOprAjaxErr(tmpInputDataObj.errObj, tmpHttpTotalTime);
break;
}
}
}
);
} catch (e) {
tmpReportData.response.testDeny = 0;
tmpReportData.general.time = tmpReportData.general.time || '0ms';
tmpReportData.response.body = e.name + '' + e.message;
if (callback) callback(tmpReportData);
reject(e);
}
});
}
main(inputTestData, callback) {
let unitCommonClass = this;
async function main() {
let template = {
ajax: {},
status: 'finish',
},
tmpDecorateObj,
tmpReportData = {
afterInject: inputTestData.afterInject,
beforeInject: inputTestData.beforeInject,
};
try {
inputTestData.globalHeader = inputTestData.globalHeader || {};
await privateFun.parseTestData(inputTestData, inputTestData.env || {}).then((tmpInputData) => {
tmpDecorateObj = tmpInputData;
});
switch (tmpDecorateObj.status) {
case 'preCode error': {
template.ajax = {
status: 'error',
errorReason: tmpDecorateObj.content,
reportList: tmpDecorateObj.reportList,
general: {
time: '0.00ms',
},
};
break;
}
default: {
tmpReportData.requestInfo = {
messageSeparatorSetting: inputTestData.messageSeparatorSetting,
params: [],
apiProtocol: '0',
URL: tmpDecorateObj.history.uri,
headers: [],
methodType: inputTestData.methodType,
method: inputTestData.method,
};
if (tmpDecorateObj.requestType === '4') {
tmpReportData.requestInfo.requestType = '2';
delete tmpReportData.requestInfo.params;
} else {
switch (typeof tmpDecorateObj.history.body) {
case 'object': {
tmpReportData.requestInfo.requestType = '0';
for (let key in tmpDecorateObj.history.body) {
switch (typeof tmpDecorateObj.history.body[key]) {
case 'object': {
for (let childKey in tmpDecorateObj.history.body[key]) {
tmpReportData.requestInfo.params.push({
key: key,
value:
typeof tmpDecorateObj.history.body[key][childKey] == 'string'
? tmpDecorateObj.history.body[key][childKey]
: '[file]',
});
if (typeof tmpDecorateObj.history.body[key][childKey] != 'string') break;
}
break;
}
default: {
tmpReportData.requestInfo.params.push({
key: key,
value: tmpDecorateObj.history.body[key],
});
break;
}
}
}
break;
}
default: {
tmpReportData.requestInfo.requestType = '1';
tmpReportData.requestInfo.params = tmpDecorateObj.history.body;
break;
}
}
}
for (let key in tmpDecorateObj.history.headers) {
tmpReportData.requestInfo.headers.push({
name: key,
value: tmpDecorateObj.history.headers[key],
});
}
let tmpIsOversized,
tmpRequestBodyStr =
typeof tmpReportData.requestInfo.params === 'object'
? JSON.stringify(tmpReportData.requestInfo.params)
: tmpReportData.requestInfo.params;
if ((tmpRequestBodyStr || '').length > CONFIG.REQUEST_BODY_LIMIT_STORAGE_LENGTH) {
tmpReportData.requestInfo.requestType = 'oversized';
tmpReportData.requestInfo.params = '';
tmpIsOversized = true;
}
tmpReportData.requestInfo = JSON.stringify(tmpReportData.requestInfo);
await unitCommonClass.ajax(
tmpDecorateObj,
{
requestData: _LibsCommon.parseRequestDataToObj(tmpDecorateObj),
globalHeader: inputTestData.globalHeader,
pckSplitByHeader: inputTestData.messageSeparatorSetting === 'spliceLength',
messageEncoding: inputTestData.messageEncoding,
},
function (res) {
template.ajax = res;
if (res.status != 'abort') {
let tmpHistoryResponse = Object.assign({}, res.response);
tmpHistoryResponse.reportList = res.reportList;
if (tmpHistoryResponse.responseType !== 'text') delete tmpHistoryResponse.body;
tmpReportData.general = JSON.stringify(res.general);
tmpReportData.resultInfo = JSON.stringify(tmpHistoryResponse);
template.ajax.request.body = tmpDecorateObj.binaryFileName || tmpDecorateObj.requestBody.body;
if (tmpIsOversized) {
template.ajax.request.requestType = 'oversized';
} else {
template.ajax.request.requestType =
tmpDecorateObj.requestType === '4'
? '1'
: typeof tmpDecorateObj.requestBody.body == 'object'
? '0'
: '1';
}
}
}
);
break;
}
}
if (callback) {
callback(template.ajax, tmpReportData);
}
} catch (e) {
if (callback) {
callback(template.ajax, tmpReportData);
}
console.error(new Date() + 'unit/common.js 336', e);
}
}
main();
}
abort() {
this.areadyAbortXhr = true;
if (this.xhr) this.xhr.abort();
}
}
exports.core = unitCommon;
})();

BIN
build/7z.dll Normal file

Binary file not shown.

BIN
build/7z.exe Normal file

Binary file not shown.

BIN
build/NSIS/Bin/GenPat.exe Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
build/NSIS/Bin/RegTool.bin Normal file

Binary file not shown.

BIN
build/NSIS/Bin/zip2exe.exe Normal file

Binary file not shown.

BIN
build/NSIS/COPYING Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 886 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 886 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 886 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 886 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 886 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 886 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 886 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Some files were not shown because too many files have changed in this diff Show More