mirror of
https://github.com/gnh1201/welsonjs.git
synced 2025-05-07 12:16:04 +00:00
Compare commits
421 Commits
Author | SHA1 | Date | |
---|---|---|---|
aee5fb22d0 | |||
14c8b12df7 | |||
deed89560b | |||
eb32437f96 | |||
c95b7a373b | |||
302e7ce4fc | |||
a5fc5de78f | |||
d362d852ad | |||
2a3f9fb4fa | |||
944751121c | |||
fb420d1116 | |||
26af578178 | |||
245dd85341 | |||
fb6596fe64 | |||
a42180d244 | |||
73b24f9a56 | |||
eae2795bbf | |||
98e73b2372 | |||
2225ab9011 | |||
4c0895850b | |||
ea412908ef | |||
05ea48a0be | |||
243ff95198 | |||
8341394912 | |||
e5a89c9182 | |||
df5b8cd9f0 | |||
e7b6a87175 | |||
5b2863058a | |||
cd8844afef | |||
b26d979b8d | |||
5446a1bee0 | |||
10101986be | |||
47a5f50712 | |||
86517f313c | |||
b6d34404b5 | |||
88ac0cd31e | |||
3e0fd7c532 | |||
22d10cd28b | |||
0e95b72b21 | |||
426a9d7721 | |||
d42210f922 | |||
e853003bda | |||
8ca4faa88a | |||
f84f2195c3 | |||
1742ca385b | |||
2a9ebaff51 | |||
916154499c | |||
53a84b2349 | |||
6e3eb5c1d3 | |||
4b4754ae16 | |||
a273d6aac6 | |||
9e1878628b | |||
04ce7fdae5 | |||
f7de7bd430 | |||
ab8a864519 | |||
427f8dded0 | |||
a96764f725 | |||
46d0244c34 | |||
2cb3c1c331 | |||
231e6a56bd | |||
295ad2fca8 | |||
9ecc93a399 | |||
2896cc6bf1 | |||
be37951807 | |||
d38e26ba67 | |||
dd85e98c9a | |||
d8fa8779de | |||
f6fd43ae50 | |||
96dbe7b2cd | |||
c1fe39d3cc | |||
56ee12741c | |||
4372bdb09d | |||
b21f967a6a | |||
40b0b704e3 | |||
9a8ee4d7f9 | |||
4f319d474f | |||
93ed60bcf7 | |||
5d717505f4 | |||
b0e50d33bc | |||
c0f9816000 | |||
00ea473683 | |||
7e9054fb8f | |||
f29a63027f | |||
3419e62c6a | |||
e930cf86fd | |||
c0a27efd8d | |||
d42539c0a8 | |||
8389f755fd | |||
6d5af6d422 | |||
7738b3b898 | |||
c1052e0147 | |||
d3135bef8e | |||
54af38b6b6 | |||
9d4b7e535c | |||
8190c80f1a | |||
c887e1914d | |||
394ce1e903 | |||
d2cba59b6b | |||
7a23340623 | |||
5a2a48945b | |||
51da417506 | |||
a148319b44 | |||
340794d14c | |||
f6b222e469 | |||
fb17f37188 | |||
2450bc0b9c | |||
6737b4885b | |||
81d6e67f94 | |||
911be8135c | |||
e68c1e5e2f | |||
07e0665275 | |||
4e78905bbc | |||
e2c9169121 | |||
1f859c75c6 | |||
b2fdc38790 | |||
07991329fc | |||
5cea33ec20 | |||
01e94830e7 | |||
c8e757487e | |||
9cd4f2d744 | |||
2a2cdf8a4a | |||
4a46d6211c | |||
98b9019633 | |||
434f5d4a8d | |||
46a3049d62 | |||
be9ed37eea | |||
dd978ab952 | |||
15b2e606b1 | |||
0cbb22ac26 | |||
11afb64706 | |||
240a65e61c | |||
2da5051c5b | |||
1124dc5bf4 | |||
b93d16669f | |||
5ab1c97b79 | |||
0aceb0e86b | |||
dc06506276 | |||
7947d91c3a | |||
1f2a1e79b7 | |||
6722704859 | |||
96bd29c06a | |||
c6240fb793 | |||
74ca7dcd6c | |||
b1cabe9fbb | |||
6bb1dcc3f1 | |||
b3f75d3c53 | |||
4d26f504f8 | |||
4bc2a95c42 | |||
c382ffbf46 | |||
6fa4f64e0b | |||
6d601aa79f | |||
4105b567ee | |||
4fbd0970ed | |||
be782c1ebd | |||
1982b0fc6b | |||
ff88f484f6 | |||
e5c970bea1 | |||
653c44dbf6 | |||
9213d18c90 | |||
7c19dd366f | |||
39c1fbb29b | |||
53124007c2 | |||
fdc6062433 | |||
bb3cd40012 | |||
e9c6a493eb | |||
24ba77d1f6 | |||
a3c26a202d | |||
e9a6e414c1 | |||
aa5f3c9b6c | |||
1cf0a8920a | |||
ba35b022c6 | |||
f68c7fd7bd | |||
e942f0b9e8 | |||
ac6cdb0d76 | |||
16723acd97 | |||
b31a2d43bb | |||
be6f4b027f | |||
1e93dd22ce | |||
64b2eb0f1b | |||
a80c017206 | |||
913eb9f9bf | |||
d9175b83a2 | |||
f6d112e38f | |||
40129f87e3 | |||
e375ddf6f5 | |||
51110e54b7 | |||
7d2f76e2dd | |||
![]() |
5590c81be5 | ||
2c25eb2a43 | |||
ece0054da6 | |||
09e9cccc51 | |||
85a315eac7 | |||
3349255d9a | |||
c4be361f95 | |||
432fd39df2 | |||
b31add8d74 | |||
e659c8daf2 | |||
62ab354674 | |||
8285825c8b | |||
e1ebb0ac2a | |||
1aa575b13c | |||
0f2e874a4a | |||
c9578ae9f1 | |||
a4a7391de6 | |||
495944a3b6 | |||
477848b77f | |||
a3289cc81d | |||
4fd38e75c3 | |||
5a09d7a79a | |||
b912ae0b08 | |||
eacd68ce88 | |||
2251494a48 | |||
5b092c7f7a | |||
4d78bbf31e | |||
1c4e607d3d | |||
80de6da382 | |||
3edff1550c | |||
724b89f361 | |||
06a09fbc3e | |||
2c2696d75f | |||
36d51749b3 | |||
ac84bb222d | |||
7c87f25f25 | |||
a2123f8765 | |||
2078b45566 | |||
a7a00a38d8 | |||
a5275388e2 | |||
b5704d5746 | |||
ee038c6c20 | |||
827dea443c | |||
3cf7f6c07c | |||
408e98e46b | |||
2878eac81d | |||
60a26b3ad0 | |||
4c8a127ad3 | |||
3f993975eb | |||
68e7e4aec0 | |||
e7031baf0b | |||
7d3659ebce | |||
a1e254ceb0 | |||
0f1c2f3e85 | |||
6496da9b7e | |||
8699d89694 | |||
fb947cc777 | |||
fe5542a521 | |||
47bb893c49 | |||
0485412b52 | |||
ab2f3df4ea | |||
df92b4c58e | |||
88e6bd27b2 | |||
b640786f62 | |||
1c3a367b18 | |||
8a2a4c4760 | |||
e585b3e2d4 | |||
94601cbf4f | |||
905b56beb2 | |||
1337320803 | |||
1e3389acf4 | |||
74005364e2 | |||
1cea720a70 | |||
eeb0d0bc19 | |||
9d47a18325 | |||
81f196eed2 | |||
8adaf4bdb9 | |||
daf7db76b6 | |||
38b03fe026 | |||
e2582447cc | |||
6babec9d6b | |||
a5dce5b55d | |||
babfbe4e38 | |||
c9f03a5e23 | |||
f9f35da4d4 | |||
dd3ebc16df | |||
3120a5ea93 | |||
8571ec4d00 | |||
1c6d306760 | |||
9262d83fd5 | |||
b682f8fc34 | |||
e1720c5bcf | |||
a78581ee69 | |||
4eb2d4ae06 | |||
fdd5c74df5 | |||
1857712df4 | |||
c5ebf36274 | |||
8c2d403502 | |||
ec92b9605f | |||
c0e8f92e84 | |||
fe4d0d562e | |||
58e9bdc4ab | |||
638b172e77 | |||
79295de4ce | |||
37aa3ea406 | |||
1c9e77f890 | |||
da153a7900 | |||
7903a38f61 | |||
a99f1c396f | |||
5a5526df63 | |||
46c5a91032 | |||
e9ba3cff96 | |||
b4ace286e3 | |||
7aeb8edfc2 | |||
31792ebecd | |||
7dcd82e7b9 | |||
fc4d74b7ac | |||
98ff88ffff | |||
a3fa1a558e | |||
bf6fa1c044 | |||
8a185cb048 | |||
4d6239b606 | |||
78445aa4dc | |||
4a9f5a7fd8 | |||
e1d2d3e9ff | |||
7ee1e2b745 | |||
![]() |
442d081f9d | ||
![]() |
36da5ec3a1 | ||
![]() |
f49ba40cb9 | ||
a886363603 | |||
dee6ed1025 | |||
d8d67ac4c0 | |||
![]() |
b400c8d64d | ||
![]() |
98e2c6c837 | ||
a947432134 | |||
1d0f4172fb | |||
06972c2bd1 | |||
eccd60c340 | |||
c1f9249252 | |||
c14f4358f3 | |||
2dae3a3abb | |||
7d6046624c | |||
de4016100a | |||
3ed38eec6a | |||
7ef4437447 | |||
9c662177ec | |||
d6540f1351 | |||
1b31859786 | |||
ca857d70eb | |||
eaa52e40a6 | |||
5ba8744f6c | |||
92b3907a8e | |||
a95e7e3e0d | |||
7a8ef89f09 | |||
3b022d68a4 | |||
eaa33e3b7b | |||
ea78f08710 | |||
6fa089a854 | |||
ba73fddba5 | |||
ff0ab03630 | |||
7ba17435ac | |||
5852e987c6 | |||
9b4273e370 | |||
4e6b9ea086 | |||
caa56cedb8 | |||
701be4c351 | |||
2ba05aa633 | |||
f00e6eed1e | |||
81592beb64 | |||
ebdc212afb | |||
b880e7a13d | |||
ce10ac7f7b | |||
9012a161c3 | |||
9038829f24 | |||
116bd84394 | |||
69d7d3c632 | |||
400e904aa9 | |||
27f4dc2084 | |||
2ac75fd24e | |||
8ddff1cf94 | |||
b1428867dc | |||
f2044bcfbf | |||
b5bc2bd851 | |||
b45a7cdd6c | |||
ac31e5e884 | |||
43b5781cbd | |||
3fa72f86d6 | |||
8942a98431 | |||
8bb0f68049 | |||
d3743e206c | |||
4fe98d32a1 | |||
1fc0597f93 | |||
0f57fba805 | |||
2f74ceb013 | |||
009b171946 | |||
895bfe1ac8 | |||
3033382f64 | |||
fd21f2faae | |||
5e1f41b48a | |||
b98901c75a | |||
9b50e5b078 | |||
d9ac6d01d0 | |||
57fbb16bd8 | |||
13a8c94bcf | |||
0d6e2076d6 | |||
f6b04faea6 | |||
eedac13818 | |||
d45c21cf24 | |||
54a1515bcb | |||
4477ef84bf | |||
4370f40886 | |||
fe2466b49a | |||
a8b54493f7 | |||
2ee54f77ae | |||
187578861b | |||
a0420cd10f | |||
2f1a0f6e41 | |||
6d0a6c645f | |||
55d34f833d | |||
a0e9a83ddd | |||
9a35227728 | |||
af69d66ea9 | |||
2487e56847 | |||
5b264b64fd | |||
ce7a0034be | |||
a8a13b539c | |||
b2975e053c | |||
41fcb8706f | |||
3fc6f19227 | |||
3e78e0b5d2 | |||
020f99c5b2 | |||
3989eeba45 | |||
412c72f624 | |||
30c0e20eae |
|
@ -25,6 +25,7 @@ after_build:
|
|||
#- cmd: xcopy /s /y WelsonJS.Toolkit\WelsonJS.Toolkit\bin\x86\%CONFIGURATION%\* artifacts\
|
||||
- cmd: xcopy /s /y WelsonJS.Toolkit\WelsonJS.Service\bin\x86\%CONFIGURATION%\* artifacts\
|
||||
- cmd: xcopy /s /y WelsonJS.Toolkit\WelsonJS.Launcher\bin\x86\%CONFIGURATION%\* artifacts\
|
||||
- cmd: nuget pack WelsonJS.Toolkit\WelsonJS.Toolkit\ -properties Configuration=%CONFIGURATION% -properties Platform=x86 -OutputDirectory artifacts\
|
||||
- cmd: 7z a artifacts.zip artifacts\*
|
||||
|
||||
artifacts:
|
||||
|
|
2
.github/FUNDING.yml
vendored
Normal file
2
.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
github: gnh1201
|
||||
custom: ['https://gnh1201.link']
|
8
.github/workflows/codeql-analysis.yml
vendored
8
.github/workflows/codeql-analysis.yml
vendored
|
@ -32,7 +32,7 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'csharp', 'javascript', 'python' ]
|
||||
language: [ 'javascript' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Learn more about CodeQL language support at https://git.io/codeql-language-support
|
||||
|
||||
|
@ -42,7 +42,7 @@ jobs:
|
|||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
|
@ -53,7 +53,7 @@ jobs:
|
|||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
@ -67,4 +67,4 @@ jobs:
|
|||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
uses: github/codeql-action/analyze@v2
|
||||
|
|
23
.github/workflows/llm-code-review.yml
vendored
Normal file
23
.github/workflows/llm-code-review.yml
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
name: AI Code Review
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
issues:
|
||||
types: [opened, reopened]
|
||||
|
||||
jobs:
|
||||
repofix:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Run RepoFixAI
|
||||
uses: Manav916/llm-code-review@main
|
||||
with:
|
||||
groq_api_key: ${{ secrets.GROQ_API_KEY }}
|
||||
groq_model: 'llama-3.3-70b-versatile'
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# exclude_extensions: 'txt'
|
||||
repo_owner: ${{ github.repository_owner }}
|
||||
repo_name: ${{ github.event.repository.name }}
|
||||
event_number: ${{ github.event.number || github.event.issue.number }} # when listening for both pull requests and issues
|
||||
event_name: ${{ github.event_name }}
|
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -103,11 +103,13 @@ dist
|
|||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# user defined assets
|
||||
# user private assets
|
||||
bin
|
||||
data/chatgpt-apikey.txt
|
||||
data/*-apikey.txt
|
||||
data/*.nomedia.txt
|
||||
app/assets/img/_templates
|
||||
app/assets/img/_captured
|
||||
settings.ini
|
||||
defaultService.js
|
||||
lib/*.private.js
|
||||
data/python313.zip
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
github: gnh1201
|
||||
open_collective: welsonjs
|
||||
liberapay: catswords
|
||||
custom: ['https://www.buymeacoffee.com/catswords']
|
||||
patreon: catswords
|
||||
ko_fi: catswords
|
223
README.md
223
README.md
|
@ -3,99 +3,82 @@
|
|||
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fgnh1201%2Fwelsonjs?ref=badge_shield)
|
||||
[](https://ci.appveyor.com/project/gnh1201/welsonjs)
|
||||
[](https://doi.org/10.5281/zenodo.11382384)
|
||||
[](#)
|
||||
[](https://www.slideshare.net/slideshow/welsonjs-2023/263181443)
|
||||
[](https://catswords-oss.rdbl.io/5719744820/5510319392)
|
||||
[](https://catswords-oss.rdbl.io/5719744820/5510319392)
|
||||
[](https://catswords-oss.rdbl.io/5719744820/5510319392)
|
||||
[](https://catswords-oss.rdbl.io/5719744820/5510319392)
|
||||
[](https://www.slideshare.net/slideshow/welsonjs-javascript-framework-presentation-2024/276005486)
|
||||
[](https://youtu.be/JavH7Dms8-U)
|
||||
[](https://discord.gg/XKG5CjtXEj)
|
||||
[](https://github.com/gnh1201/welsonjs/discussions/167)
|
||||
|
||||
<img src="app/assets/img/logo.svg" height="32" alt=""/> WelsonJS - Build a Windows app on the Windows built-in JavaScript engine.
|
||||
|
||||

|
||||

|
||||
|
||||
Now, You can build an Windows desktop app with JavaScript, TypeScript, CoffeeScript, ReScript, and HTML/CSS on Windows built-in ECMAScript engine.
|
||||
Now, You can build a Windows desktop app with JavaScript, TypeScript, CoffeeScript, ReScript, and HTML/CSS on Windows built-in ECMAScript engine.
|
||||
|
||||
WelsonJS = ***W***indows + ***El***ectr***on***-like + ***Javascript(JS)*** + [Your contribution](https://github.com/sponsors/gnh1201)
|
||||
WelsonJS = ***W***indows + ***El***ectr***on***-like + ***Javascript(JS)*** + :heart:[Contributions](https://github.com/sponsors/gnh1201)
|
||||
|
||||
Dual license notice: The default license for this project is GPL 3.0. However, if the GPL 3.0 license is not compatible with Microsoft products, it is subject to the MS-RL license.
|
||||
* :kissing_cat: [Download Latest WelsonJS Launcher (ics.catswords.net)](https://ics.catswords.net/welsonjs_launcher_latest.zip)
|
||||
* :rocket: [Launch the WelsonJS environment on Microsoft Azure (azuremarketplace.microsoft.com)](https://azuremarketplace.microsoft.com/en-us/marketplace/apps/catswords.catswords-welsonjs-feb2025-02?tab=Overview)
|
||||
|
||||
**Note**: The default license for this project is GPL 3.0. However, if the GPL 3.0 license is not compatible with Microsoft products, it is subject to the MS-RL license.
|
||||
|
||||
## Sponsors
|
||||
- :octocat: [GitHub Sponsors](https://github.com/sponsors/gnh1201)
|
||||
- <img src="https://ics.catswords.net/logo_oss.gif" height="32" alt=""/> Open Software Portal, Korea National Industry Promotion Agency - Awarded Prize
|
||||
- <img src="https://ics.catswords.net/signpath_logo.png" height="32" alt=""/> Free code signing provided by [SignPath.io](https://signpath.io), certificate by [SignPath Foundation](https://signpath.org/)
|
||||
- :zap: [Integrations](https://catswords-oss.rdbl.io/5719744820/8278298336) ([ScrapeOps](https://scrapeops.io?fpr=namhyeon75), [SearchApi](https://www.searchapi.io/?via=namhyeon), ...)
|
||||
* :octocat: [GitHub Sponsors](https://github.com/sponsors/gnh1201), :coffee: [Buy me a coffee](https://buymeacoffee.com/catswords)
|
||||
* <img src="https://ics.catswords.net/logo_oss.gif" height="32" alt=""/> [Open SW Portal](https://oss.kr), NIPA National IT Industry Promotion Agency<sup>(정보통신산업진흥원)</sup>
|
||||
* <img src="https://ics.catswords.net/signpath_logo.png" height="32" alt=""/> Free code signing provided by [SignPath.io](https://signpath.io), certificate by [SignPath Foundation](https://signpath.org/)
|
||||
* <img src="https://ics.catswords.net/f1security_logo.png" height="32" alt=""/> [F1Security<sup>(에프원시큐리티)</sup>](https://f1security.co.kr/) provides [industry-leading](https://www.ksecurity.or.kr/kisis/subIndex/469.do) web security services.
|
||||
* <img src="https://ics.catswords.net/microsoft_logo.png" height="32" alt=""/> [Microsoft ISV Success Program](https://www.microsoft.com/en-us/isv/isv-success), Grow your business with powerful tools.
|
||||
* :zap: [Integrations](https://catswords-oss.rdbl.io/5719744820/8278298336) ([ScrapeOps](https://scrapeops.io?fpr=namhyeon75), [SearchApi](https://www.searchapi.io/?via=namhyeon), [AviationStack](https://aviationstack.com?utm_source=FirstPromoter&utm_medium=Affiliate&fpr=namhyeon71), [Coupang](https://link.coupang.com/a/b7HV3V)...)
|
||||
|
||||
## System Requirements
|
||||
* **Operating Systems**: Windows XP SP3 or later (Currently, Windows 11 24H2)
|
||||
* For systems running Windows 2000 or earlier versions (e.g., 95, 98, Me), please contact us separately.
|
||||
|
||||
## Why Choose WelsonJS?
|
||||
WelsonJS is an advanced JavaScript framework designed to operate in extreme conditions where conventional solutions may fail. Unlike traditional JavaScript frameworks, WelsonJS focuses on executing scripts in constrained environments, ensuring reliable performance even with minimal system resources.
|
||||
|
||||
### Key Features
|
||||
* **Lightweight and Efficient**: Optimized for environments with limited computing power, WelsonJS delivers efficient script execution without unnecessary overhead.
|
||||
* **Windows ECMAScript Compatibility**: Designed to run seamlessly on Windows-based systems, adhering to the ECMAScript standard while maintaining lightweight execution.
|
||||
* **Standalone Execution**: Unlike well-known JavaScript runtimes, which require external dependencies, a WelsonJS application can operate as a self-contained app, making it suitable for embedded systems and isolated environments.
|
||||
* **Security-Oriented**: Built with security in mind, ensuring controlled execution of scripts without compromising system integrity.
|
||||
* **Minimalist Design**: WelsonJS strips away unnecessary complexities, focusing on core functionalities that maximize performance and reliability.
|
||||
|
||||
### Use Cases
|
||||
* **Legacy System Integration**: WelsonJS provides a practical solution for running JavaScript on older Windows environments where modern frameworks are not feasible.
|
||||
* **Automation and Scripting**: Ideal for executing scripts in constrained environments, enabling automated workflows and system-level scripting.
|
||||
* **Embedded Applications**: Suitable for devices and systems with strict resource constraints, such as industrial controllers and embedded platforms.
|
||||
* **Security-Focused Environments**: Useful in security-sensitive applications where dependencies on external network connections are limited.
|
||||
* **Office Automation**: Suitable for office automation tasks using Microsoft Office and various LLM-based AI (such as ChatGPT).
|
||||
|
||||
WelsonJS is tailored for developers who need a reliable, lightweight JavaScript framework in environments where traditional solutions are impractical. Whether working with legacy systems, embedded devices, or security-critical applications, WelsonJS ensures that JavaScript remains a viable and efficient option.
|
||||
|
||||
## Structure
|
||||

|
||||
|
||||
## Specifications
|
||||
- Built-in transpilers: [TypeScript](https://www.typescriptlang.org/), [Rescript](https://rescript-lang.org/), [CoffeeScript 2](https://coffeescript.org/), [LiveScript](https://livescript.net/)
|
||||
- Ready to use on Windows machine immediately. No require additional software installation.
|
||||
- ES5(ECMAScript 5), XML, JSON, YAML compatibility
|
||||
- [github.com/zloirock/core-js](https://github.com/zloirock/core-js)
|
||||
- [github.com/douglascrockford/JSON-js](https://github.com/douglascrockford/JSON-js) (aka. JSON2.js)
|
||||
- [github.com/nodeca/js-yaml](https://github.com/nodeca/js-yaml)
|
||||
- HTML5, CSS3 compatibility
|
||||
- [github.com/aFarkas/html5shiv](https://github.com/aFarkas/html5shiv)
|
||||
- [github.com/parndt/jquery-html5-placeholder-shim](https://github.com/parndt/jquery-html5-placeholder-shim)
|
||||
- [github.com/scottjehl/Respond](https://github.com/scottjehl/Respond)
|
||||
- [github.com/keithclark/selectivizr](https://github.com/keithclark/selectivizr)
|
||||
- [github.com/arv/ExplorerCanvas](https://github.com/arv/ExplorerCanvas)
|
||||
- [github.com/Modernizr/Modernizr](https://github.com/Modernizr/Modernizr)
|
||||
- CSS Frameworks
|
||||
- [github.com/jslegers/cascadeframework](https://github.com/jslegers/cascadeframework)
|
||||
- [github.com/golden-layout/golden-layout](https://github.com/golden-layout/golden-layout)
|
||||
- WYSIWYG HTML Editor
|
||||
- [github.com/summernote/summernote](https://github.com/summernote/summernote)
|
||||
- Included libraries
|
||||
- [jQuery](https://jquery.com/)
|
||||
- [jQuery UI](https://jqueryui.com/)
|
||||
- [github.com/kamranahmedse/jquery-toast-plugin](https://github.com/kamranahmedse/jquery-toast-plugin) - Highly customizable jquery plugin to show toast messages
|
||||
- [github.com/hiddentao/squel](https://github.com/hiddentao/squel) - SQL query string builder for Javascript
|
||||
- [github.com/BorisMoore/jsrender](https://github.com/BorisMoore/jsrender) - A lightweight, powerful and highly extensible templating engine. In the browser or on Node.js, with or without jQuery.
|
||||
- [github.com/mihaifm/linq](https://github.com/mihaifm/linq) - LINQ for JavaScript
|
||||
- [github.com/pegjs/pegjs](https://github.com/pegjs/pegjs) - PEG.js: Parser generator for JavaScript
|
||||
- [module.exports](https://nodejs.org/api/modules.html#moduleexports), CommonJS, UMD compatibility
|
||||
- [NPM](https://www.npmjs.com/) compatibility
|
||||
- [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/) support
|
||||
- [ADB(Android Debug Bridge)](https://source.android.com/docs/setup/build/adb) support
|
||||
- RPC(Remote Procedure Call) protocol support
|
||||
- [gRPC](https://grpc.io/)
|
||||
- [JSON-RPC 2.0](https://www.jsonrpc.org/specification)
|
||||
* Built-in transpilers: [TypeScript](https://www.typescriptlang.org/), [Rescript](https://rescript-lang.org/), [CoffeeScript 2](https://coffeescript.org/), [LiveScript](https://livescript.net/)
|
||||
* **Ready to use on Windows machine immediately. No additional software installation is required.**
|
||||
* **WelsonJS Launcher**: Manage instances (Like a container), User-defined variable editor, [Microsoft Monaco Editor](https://github.com/microsoft/monaco-editor) and [React](https://react.dev/) (Pre-embedded rich code editor), [Microsoft Copilot](https://copilot.microsoft.com), and [Azure AI Services](https://azure.microsoft.com/en-us/products/ai-services) on the code editor.
|
||||
* ES5(ECMAScript 5), XML, JSON, YAML compatibility: [core-js](https://github.com/zloirock/core-js), [JSON2.js](https://github.com/douglascrockford/JSON-js), [js-yaml](https://github.com/nodeca/js-yaml)
|
||||
* HTML5 compatibility on the built-in HTML rendering engine: [html5shiv](https://github.com/aFarkas/html5shiv), [jquery-html5-placeholder-shim](https://github.com/parndt/jquery-html5-placeholder-shim), [Respond](https://github.com/scottjehl/Respond), [selectivizr](https://github.com/keithclark/selectivizr), [ExplorerCanvas](https://github.com/arv/ExplorerCanvas), [Modernizr](https://github.com/Modernizr/Modernizr)
|
||||
* Classical CSS Frameworks: [cascadeframework](https://github.com/jslegers/cascadeframework), [golden-layout](https://github.com/golden-layout/golden-layout)
|
||||
* WYSIWYG HTML Editor: [summernote](https://github.com/summernote/summernote)
|
||||
* Included libraries: [jQuery](https://jquery.com/), [jQuery UI](https://jqueryui.com/), [jquery-toast-plugin](https://github.com/kamranahmedse/jquery-toast-plugin), [squel](https://github.com/hiddentao/squel), [jsrender](https://github.com/BorisMoore/jsrender), [linq](https://github.com/mihaifm/linq), [pegjs](https://github.com/pegjs/pegjs), [numbers.js](https://github.com/numbers/numbers.js)
|
||||
* Compatible with modern JavaScript specifications: [module.exports](https://nodejs.org/api/modules.html#moduleexports), CommonJS, UMD compatibility, [NPM(Node Package Manager)](https://www.npmjs.com/) compatibility
|
||||
* Support a device debugging protocol clients: [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/), [ADB(Android Debug Bridge)](https://source.android.com/docs/setup/build/adb)
|
||||
* RPC(Remote Procedure Call) protocol clients: [gRPC](https://grpc.io/), [JSON-RPC 2.0](https://www.jsonrpc.org/specification)
|
||||
* Various types of HTTP clients: [XHR(MSXML)](https://developer.mozilla.org/docs/Glossary/XMLHttpRequest), [cURL](https://curl.se/), [BITS](https://en.m.wikipedia.org/w/index.php?title=Background_Intelligent_Transfer_Service), [CERT](https://github.com/MicrosoftDocs/windowsserverdocs/blob/main/WindowsServerDocs/administration/windows-commands/certutil.md), [Web Proxy, SEO/SERP](https://catswords-oss.rdbl.io/5719744820/1706431912)
|
||||
* The native toolkit for Windows environments: Write a Windows Service Application with JavaScript, Control a window handle, Cryptography (e.g., [ISO/IEC 18033-3:2010](https://www.iso.org/standard/54531.html) aka. [HIGHT](https://seed.kisa.or.kr/kisa/algorithm/EgovHightInfo.do)), [Named Shared Memory](https://learn.microsoft.com/en-us/windows/win32/memory/creating-named-shared-memory) based [IPC](https://qiita.com/gnh1201/items/4e70dccdb7adacf0ace5), [NuGet package](https://www.nuget.org/packages/WelsonJS.Toolkit)
|
||||
* Generative AI integrations: [Multiple LLM and sLLM](https://catswords-oss.rdbl.io/5719744820/5510319392) (e.g., ChatGPT, Claude, ...)
|
||||
* Aviation Data integrations: [AviationStack](https://aviationstack.com?utm_source=FirstPromoter&utm_medium=Affiliate&fpr=namhyeon71), [SearchApi Google Flight](https://www.searchapi.io/?via=namhyeon)
|
||||
* VM infrastructure tool integrations: [OVFTool for Broadcom/VMware infrastructures](https://developer.broadcom.com/tools/open-virtualization-format-ovf-tool/latest)
|
||||
* Everything you can imagine.
|
||||
|
||||
## Included modules
|
||||
- lib/std (Standard library)
|
||||
- lib/system (System interface)
|
||||
- lib/base64 (BASE64 encode and decode)
|
||||
- lib/file (File I/O interface)
|
||||
- lib/http (HTTP/HTTPS client with [XHR(MSXML)](https://developer.mozilla.org/docs/Glossary/XMLHttpRequest), [cURL](https://curl.se/), [BITS](https://en.m.wikipedia.org/w/index.php?title=Background_Intelligent_Transfer_Service), [CERT](https://github.com/MicrosoftDocs/windowsserverdocs/blob/main/WindowsServerDocs/administration/windows-commands/certutil.md), [Proxy/SEO/SERP](https://catswords-oss.rdbl.io/5719744820/1706431912))
|
||||
- lib/registry (Windows Registry interface)
|
||||
- lib/security (Windows Security Policy interface)
|
||||
- lib/shell (Windows Shell (Command Prompt) interface)
|
||||
- lib/powershell (Windows Powershell interface)
|
||||
- lib/service (Windows Service interface)
|
||||
- lib/browser (Modern web compatibility layer)
|
||||
- lib/uri (URI scheme interface)
|
||||
- lib/winlibs (Windows DLL(Dynamic-link library) interface)
|
||||
- lib/autohotkey ([AutoHotkey](https://www.autohotkey.com/) interface)
|
||||
- lib/autoit ([AutoIt3/AutoItX](https://www.autoitscript.com/) interface)
|
||||
- lib/msoffice (Microsoft Office (e.g. Excel, PowerPoint, Word) interface)
|
||||
- lib/gtk (GTK-server and GladeXML supported GUI interface)
|
||||
- lib/chrome ([Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/) based Chrome/Chromium web browser testing interface)
|
||||
- lib/pipe-ipc (PIPE (e.g., File IO, Standard IO) based IPC(Inter-Process Communication) implementation)
|
||||
- [WelsonJS.Toolkit](https://catswords-oss.rdbl.io/5719744820/0811015590) (DLL/COM component with .NET 2.0, For all Windows based systems)
|
||||
- User prompt methods (e.g., alert, confirm) implementation
|
||||
- Useful tools to control the windows and window handle (find, attach, trigger events. e.g., Virtual Human Interface
|
||||
- Cryptography ([ISO/IEC 18033-3:2010](https://www.iso.org/standard/54531.html) aka. [HIGHT](https://seed.kisa.or.kr/kisa/algorithm/EgovHightInfo.do))
|
||||
- [Named Shared Memory](https://learn.microsoft.com/en-us/windows/win32/memory/creating-named-shared-memory) based IPC(Inter-Process Communication) implementation [#](https://qiita.com/gnh1201/items/4e70dccdb7adacf0ace5)
|
||||
- [NuGet package](https://www.nuget.org/packages/WelsonJS.Toolkit) available
|
||||
- [WelsonJS.Service](https://catswords-oss.rdbl.io/5719744820/0811015590) (Windows Service Application, For recent Windows based systems)
|
||||
- Write a Windows Service Application with JavaScript
|
||||
- [File Event Monitor](https://catswords-oss.rdbl.io/5719744820/6159022056): Trace file creation, network connections, and registry modifications.
|
||||
- [Screen Time Feature](https://catswords-oss.rdbl.io/5719744820/8803957194): Find an image position on the computer screens or windows.
|
||||
- [WelsonJS.Launcher](https://catswords-oss.rdbl.io/5719744820/4131485779) (Launcher Application, For recent Windows based systems)
|
||||
- This is a launcher app designed to easily distribute WelsonJS application packages (based on ZIP compression files).
|
||||
- lib/chatgpt ([ChatGPT](https://openai.com/chatgpt) integration)
|
||||
- Everything you can imagine.
|
||||
|
||||
## Make your own `sayhello` example
|
||||
## Quick start
|
||||
|
||||
### 1. Write a file `lib/sayhello.js`
|
||||
```js
|
||||
|
@ -106,8 +89,8 @@ function say() {
|
|||
|
||||
exports.say = say;
|
||||
|
||||
exports.VERSIONINFO = "SayHello Library (sayhello.js) version 0.1";
|
||||
exports.AUTHOR = "abuse@catswords.net"; // e.g. YOUR EMAIL ADDRESS
|
||||
exports.VERSIONINFO = "SayHello (sayhello.js) version 0.1";
|
||||
exports.AUTHOR = "abuse@catswords.net";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
||||
```
|
||||
|
@ -126,9 +109,9 @@ function main() {
|
|||
exports.main = main;
|
||||
```
|
||||
|
||||
### 3. Execute file on the command prompt
|
||||
### 3. Execute script on the console
|
||||
```cmd
|
||||
C:\Users\knh94\Documents\GitHub\welsonjs> cscript app.js sayhello
|
||||
C:\Users\JohnDoe\Documents\GitHub\welsonjs> cscript app.js sayhello
|
||||
calling say()
|
||||
hello
|
||||
ended say()
|
||||
|
@ -137,9 +120,9 @@ ended say()
|
|||
## How to release my application?
|
||||
The WelsonJS framework suggests the following application release methods:
|
||||
|
||||
- **Compress to Zip, and use the launcher**: Compress the files and directories necessary for running the project into a Zip file, and distribute it along with the [WelsonJS.Launcher](https://catswords-oss.rdbl.io/5719744820/4131485779).
|
||||
- **Build a setup file**: Use [Inno Setup](https://jrsoftware.org/isinfo.php). Information needed to create the setup file (the `setup.iss` file) is already included.
|
||||
- **Copy all directories and files**: This is the simplest and most straightforward method.
|
||||
* **Compress to Zip, and use the launcher**: Compress the files and directories necessary for running the project into a Zip file, and distribute it along with the [WelsonJS Launcher](https://catswords-oss.rdbl.io/5719744820/4131485779).
|
||||
* **Build a setup file**: Use [Inno Setup](https://jrsoftware.org/isinfo.php). The setup profile (the `setup.iss` file) is already included.
|
||||
* **Copy all directories and files**: This is the simplest and most straightforward method.
|
||||
|
||||
## Screenshots
|
||||

|
||||
|
@ -154,41 +137,45 @@ The WelsonJS framework suggests the following application release methods:
|
|||
|
||||

|
||||
|
||||
## Thanks to
|
||||
- :sunglasses: Heavy-industry specialized CSP(Cloud Service Provider) in Republic of Korea - Use case establishment
|
||||
- :sunglasses: Live-commerce specialized online advertisement companies in Republic of Korea - Use case establishment
|
||||
- :sunglasses: Information security companies in Republic of Korea - Use case establishment
|
||||
- :eyes: Facebook Group "Javascript Programming"(javascript4u) - [Mentioned](https://www.facebook.com/javascript4u/posts/build-a-windows-desktop-apps-with-javascript-html-and-cssmorioh-javascript-html-/1484014618472735/)
|
||||
- :eyes: morioh.com - [Mentioned](https://morioh.com/a/23c427a82bf1/build-a-windows-desktop-apps-with-javascript-html-and-css)
|
||||
- :eyes: CSDN - Mentioned
|
||||
- :eyes: Qiita - Knowledge-base about WSH environment
|
||||
- :eyes: Redsky Software - PoC(Proof of Concept) of the CommonJS on WSH environment
|
||||
- :sunglasses: Inspired by a small-sized JavaScript payload demonstrated by a cybersecurity related group.
|
||||
- :sunglasses: Inspired by the use of Named Shared Memory in an inter-language IPC implementation devised by an unidentified developer.
|
||||
- :eyes: Fediverse - Mentioned
|
||||
- :eyes: Hacker News - [Mentioned](https://news.ycombinator.com/item?id=41316782)
|
||||
- :eyes: WebToolsWeekly - [Mentioned](https://webtoolsweekly.com/archives/issue-585/)
|
||||
- :eyes: GeekNews - [Mentioned](https://news.hada.io/weekly/202441) in GeekNews Weekly (2024-09-30 ~ 2024-10-06)
|
||||

|
||||
|
||||
## Related links
|
||||
- [gnh1201/wsh-js-gtk](https://github.com/gnh1201/wsh-js-gtk) - GTK GUI ported to Windows Scripting Host - Javascript (Microsoft JScript) (wsh-js)
|
||||
- [gnh1201/wsh-json](https://github.com/gnh1201/wsh-json) - JSON stringify/parse (encode/decode) for Windows Scripting Host
|
||||
- [redskyit/wsh-appjs](https://github.com/redskyit/wsh-appjs) - require-js and app framework for Windows Scripting Host JavaScript
|
||||
- [JohnLaTwC's gist](https://gist.github.com/JohnLaTwC/4315bbbd89da0996f5c08c032b391799) - JavaScript RAT
|
||||
- [JSMan-/JS-Framework](https://github.com/JSMan-/JS-Framework) - No description
|
||||
- [iconjack/setTimeout-for-windows-script-host](https://github.com/iconjack/setTimeout-for-windows-script-host) - Replacement for the missing setTimeout and clearTimeout function in Windows Script Host
|
||||
- [johnjohnsp1/WindowsScriptHostExtension](https://github.com/johnjohnsp1/WindowsScriptHostExtension) - Inject DLL Prototype using Microsoft.Windows.ACTCTX COM Object
|
||||
- [kuntashov/jsunit](https://github.com/kuntashov/jsunit) - JSUnit port for Windows Scripting Host
|
||||
- [nickdoth/WSHHttpServer](https://github.com/nickdoth/WSHHttpServer) - HTTP server based on Windows Script Host
|
||||
- FOSSA report [HTML](https://ics.catswords.net/fossa_report.html) [CSV](https://ics.catswords.net/fossa_report.csv) [TXT](https://ics.catswords.net/fossa_report.txt)
|
||||
- [License attributions of a stock images](https://policy.catswords.social/stock_images.html)
|
||||
## Thanks to
|
||||
* :heart: Artwork (Logo image): [@druidesse](https://github.com/druidesse)
|
||||
* :heart: Artwork (Cover image): [@_bag0@x.com](https://x.com/_bag0)
|
||||
* :heart: Special Contributors: [@hcho3](https://github.com/hcho3), :octocat: [GitHub Sponsors](https://github.com/sponsors/gnh1201)
|
||||
* :sunglasses: Heavy-industry specialized CSP(Cloud Service Provider) in Republic of Korea - Use case establishment
|
||||
* :sunglasses: Live-commerce specialized online advertisement companies in Republic of Korea - Use case establishment
|
||||
* :sunglasses: Information security companies in Republic of Korea - Use case establishment
|
||||
* :eyes: [Facebook Group "Javascript Programming"(javascript4u)](https://www.facebook.com/javascript4u/posts/build-a-windows-desktop-apps-with-javascript-html-and-cssmorioh-javascript-html-/1484014618472735/)
|
||||
* :eyes: [morioh.com](https://morioh.com/a/23c427a82bf1/build-a-windows-desktop-apps-with-javascript-html-and-css)
|
||||
* :eyes: CSDN
|
||||
* :eyes: Qiita - Knowledge-base about WSH environment
|
||||
* :sunglasses: Redsky Software - PoC(Proof of Concept) of the CommonJS on WSH environment
|
||||
* :sunglasses: Inspired by a small-sized JavaScript payload demonstrated by a cybersecurity related group.
|
||||
* :sunglasses: Inspired by the use of Named Shared Memory in a cross-runtime IPC implementation written by the unidentified developer.
|
||||
* :eyes: Fediverse
|
||||
* :eyes: [Hacker News](https://news.ycombinator.com/item?id=41316782)
|
||||
* :eyes: [WebToolsWeekly](https://webtoolsweekly.com/archives/issue-585/)
|
||||
* :eyes: [GeekNews](https://news.hada.io/weekly/202441) in GeekNews Weekly (2024-09-30 ~ 2024-10-06)
|
||||
* :eyes: [daily.dev](https://app.daily.dev/posts/js-libraries-svg-tools-json-databases-8quregz3a)
|
||||
* :eyes: [PitchHut](https://www.pitchhut.com/project/proj_Ya136OLSW5at)
|
||||
* :eyes: [Disquiet](https://dis.qa/nv6T6)
|
||||
|
||||
## Report abuse
|
||||
- [GitHub Security Advisories](https://github.com/gnh1201/welsonjs/security)
|
||||
- abuse@catswords.net
|
||||
- ActivityPub [@catswords_oss@catswords.social](https://catswords.social/@catswords_oss)
|
||||
- XMPP [catswords@conference.xmpp.catswords.net](xmpp:catswords@conference.xmpp.catswords.net?join)
|
||||
- [Join Catswords on Microsoft Teams](https://teams.live.com/l/community/FEACHncAhq8ldnojAI)
|
||||
* [GitHub Security Advisories (gnh1201/welsonjs)](https://github.com/gnh1201/welsonjs/security)
|
||||
* [abuse@catswords.net](mailto:abuse@catswords.net)
|
||||
|
||||
## Join the community
|
||||
I am always open. Collaboration, opportunities, and community activities are all welcome.
|
||||
|
||||
* ActivityPub [@catswords_oss@catswords.social](https://catswords.social/@catswords_oss)
|
||||
* XMPP [catswords@conference.omemo.id](xmpp:catswords@conference.omemo.id?join)
|
||||
* [Join Catswords OSS on Microsoft Teams (teams.live.com)](https://teams.live.com/l/community/FEACHncAhq8ldnojAI)
|
||||
* [Join Catswords OSS #welsonjs on Discord (discord.gg)](https://discord.gg/XKG5CjtXEj)
|
||||
|
||||
## Special channels
|
||||
* [A paid consultation channel (m.expert.naver.com)](https://m.expert.naver.com/mobile/expert/product/detail?storeId=100051156&productId=100144540) is available for Korean<sup>(한국어)</sup> region.
|
||||
* [Join the private operations channel (forms.gle)](https://forms.gle/ZKAAaGTiGamksHoo8) is available for all regions.
|
||||
|
||||
## License
|
||||
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fgnh1201%2Fwelsonjs?ref=badge_large)
|
||||
|
|
47
SECURITY.MD
47
SECURITY.MD
|
@ -9,17 +9,17 @@ This repository contains information on accessing Windows APIs and functions in
|
|||
## Known Use Cases
|
||||
WelsonJS is typically used for the following purposes:
|
||||
|
||||
* Testing web accessibility and compliance, including adherence to W3C standards (WEB-ARIA, WCAG), national laws (ADA/DDA, GDPR), and other relevant regulations.
|
||||
* Exploring vulnerabilities of equipment within the local network.
|
||||
* Improving the availability of VPN or proxy clients.
|
||||
* Building automation, CI/CD (Continuous Integration/Continuous Delivery), DevOps, and SecOps.
|
||||
* Asset evaluation (e.g., obtaining purchase history from online shopping and delivery websites).
|
||||
* Online video streaming quality testing and improvement.
|
||||
* Office automation and integration with LLM-based AI (e.g., ChatGPT) services.
|
||||
* Testing web accessibility and compliance, including adherence to W3C standards (WEB-ARIA, WCAG), national laws (ADA/DDA, GDPR), and other relevant regulations.
|
||||
* Exploring vulnerabilities of equipment within the local network.
|
||||
* Improving the availability of VPN or proxy clients.
|
||||
* Building automation, CI/CD (Continuous Integration/Continuous Delivery), DevOps, and SecOps.
|
||||
* Asset evaluation (e.g., obtaining purchase history from online shopping and delivery websites).
|
||||
* Online video streaming quality testing and improvement.
|
||||
* Office automation and integration with LLM-based AI (e.g., ChatGPT) services.
|
||||
|
||||
## Notes
|
||||
1. If you plan to use WelsonJS for a purpose other than those mentioned above, please contact us beforehand.
|
||||
2. If you are looking for ways to use WelsonJS more efficiently, referencing the [LOLBAS (Living Off The Land Binaries and Scripts)](https://lolbas-project.github.io/) list can be helpful.
|
||||
1. If you plan to use WelsonJS for a purpose other than those mentioned above, please contact us beforehand.
|
||||
2. If you are looking for ways to use WelsonJS more efficiently, referencing the [LOLBAS (Living Off The Land Binaries and Scripts)](https://lolbas-project.github.io/) list can be helpful.
|
||||
|
||||
## Guidelines
|
||||
|
||||
|
@ -41,16 +41,23 @@ WelsonJS is a project inspired by the requirements of a cloud service provider t
|
|||
## Alternative Names
|
||||
This program is also known by the following names. These names are used solely for the purpose of identifying the work and do not impact the license:
|
||||
|
||||
- DOI [10.5281/zenodo.11382384](https://zenodo.org/doi/10.5281/zenodo.11382384) (CERN/OpenAIRE Zenodo)
|
||||
- ["A0562"](https://www.oss.kr/dev_competition_activities/show/544723e6-850a-4956-9194-79640420c19a)(2023) (2023 Open-source Development Contest, NIPA National IT Industry Promotion Agency, Republic of Korea)
|
||||
- "C-2021-000237"(2021) (Copyright Registration Online System, Korea Copyright Commission, Republic of Korea)
|
||||
- "Codename Macadamia"(2020) (Heavy industry specialized CSP in the Republic of Korea)
|
||||
* DOI [10.5281/zenodo.11382384](https://zenodo.org/doi/10.5281/zenodo.11382384)(2024) (CERN/OpenAIRE Zenodo)
|
||||
* ["284757291"](https://ics.catswords.net/1494315-Certificate%2BSoR-284757291.pdf)(2024) (Registered with the [UK Copyright Service](https://copyrightservice.co.uk/))
|
||||
* ["A0562"](https://www.oss.kr/dev_competition_activities/show/544723e6-850a-4956-9194-79640420c19a)(2023) (2023 Open-source Development Contest, NIPA National IT Industry Promotion Agency<sup>(정보통신산업진흥원)</sup>, Republic of Korea)
|
||||
* ["2025-02-08-1952"](https://ics.catswords.net/20250410092300005.pdf)(2025) (Technical Data Bailment System (Technology Escrow), "Korea Foundation for Cooperation of Large & Small Business, Rural Affairs"<sup>(대·중소기업·농어업협력재단)</sup>, Republic of Korea)
|
||||
* "C-2021-000237"(2021) (Copyright Registration Online System, Korea Copyright Commission<sup>(한국저작권위원회)</sup>, Republic of Korea)
|
||||
* "Codename Macadamia"(2020) (Heavy industry specialized CSP in the Republic of Korea)
|
||||
|
||||
## Report Abuse
|
||||
If you discover any instances of this project being misused, please report them.
|
||||
## Report abuse
|
||||
* [GitHub Security Advisories](https://github.com/gnh1201/welsonjs/security)
|
||||
* [abuse@catswords.net](mailto:abuse@catswords.net)
|
||||
|
||||
- [GitHub Security Advisories](https://github.com/gnh1201/welsonjs/security)
|
||||
- abuse@catswords.net
|
||||
- ActivityPub [@catswords_oss@catswords.social](https://catswords.social/@catswords_oss)
|
||||
- XMPP [catswords@conference.xmpp.catswords.net](xmpp:catswords@conference.xmpp.catswords.net?join)
|
||||
- [Join Catswords on Microsoft Teams](https://teams.live.com/l/community/FEACHncAhq8ldnojAI)
|
||||
## Join the community
|
||||
* ActivityPub [@catswords_oss@catswords.social](https://catswords.social/@catswords_oss)
|
||||
* XMPP [catswords@conference.omemo.id](xmpp:catswords@conference.omemo.id?join)
|
||||
* [Join Catswords OSS on Microsoft Teams (teams.live.com)](https://teams.live.com/l/community/FEACHncAhq8ldnojAI)
|
||||
* [Join Catswords OSS #welsonjs on Discord (discord.gg)](https://discord.gg/XKG5CjtXEj)
|
||||
|
||||
## Special channels
|
||||
* [A paid consultation channel (m.expert.naver.com)](https://m.expert.naver.com/mobile/expert/product/detail?storeId=100051156&productId=100144540) is available for Korean<sup>(한국어)</sup> region.
|
||||
* [Join the private operations channel (forms.gle)](https://forms.gle/ZKAAaGTiGamksHoo8) is available for all regions.
|
||||
|
|
126
WelsonJS.Toolkit/WelsonJS.Launcher/EnvForm.Designer.cs
generated
126
WelsonJS.Toolkit/WelsonJS.Launcher/EnvForm.Designer.cs
generated
|
@ -28,11 +28,11 @@
|
|||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.groupBox1 = new System.Windows.Forms.GroupBox();
|
||||
this.listView1 = new System.Windows.Forms.ListView();
|
||||
this.gbUserDefinedVariables = new System.Windows.Forms.GroupBox();
|
||||
this.lvUserDefinedVariables = new System.Windows.Forms.ListView();
|
||||
this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.groupBox2 = new System.Windows.Forms.GroupBox();
|
||||
this.gbUpdateUserDefinedVariable = new System.Windows.Forms.GroupBox();
|
||||
this.checkDeleteVariable = new System.Windows.Forms.CheckBox();
|
||||
this.btnOk = new System.Windows.Forms.Button();
|
||||
this.btnOpenFile = new System.Windows.Forms.Button();
|
||||
|
@ -41,36 +41,36 @@
|
|||
this.textSetName = new System.Windows.Forms.TextBox();
|
||||
this.labelSetValue = new System.Windows.Forms.Label();
|
||||
this.labelSetName = new System.Windows.Forms.Label();
|
||||
this.groupBox3 = new System.Windows.Forms.GroupBox();
|
||||
this.gbImportAndExport = new System.Windows.Forms.GroupBox();
|
||||
this.btnExport = new System.Windows.Forms.Button();
|
||||
this.btnImport = new System.Windows.Forms.Button();
|
||||
this.groupBox1.SuspendLayout();
|
||||
this.groupBox2.SuspendLayout();
|
||||
this.groupBox3.SuspendLayout();
|
||||
this.gbUserDefinedVariables.SuspendLayout();
|
||||
this.gbUpdateUserDefinedVariable.SuspendLayout();
|
||||
this.gbImportAndExport.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// groupBox1
|
||||
// gbUserDefinedVariables
|
||||
//
|
||||
this.groupBox1.Controls.Add(this.listView1);
|
||||
this.groupBox1.Location = new System.Drawing.Point(12, 12);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Size = new System.Drawing.Size(419, 170);
|
||||
this.groupBox1.TabIndex = 0;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "User-defined variables";
|
||||
this.gbUserDefinedVariables.Controls.Add(this.lvUserDefinedVariables);
|
||||
this.gbUserDefinedVariables.Location = new System.Drawing.Point(12, 12);
|
||||
this.gbUserDefinedVariables.Name = "gbUserDefinedVariables";
|
||||
this.gbUserDefinedVariables.Size = new System.Drawing.Size(419, 170);
|
||||
this.gbUserDefinedVariables.TabIndex = 0;
|
||||
this.gbUserDefinedVariables.TabStop = false;
|
||||
this.gbUserDefinedVariables.Text = "User-defined variables";
|
||||
//
|
||||
// listView1
|
||||
// lvUserDefinedVariables
|
||||
//
|
||||
this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
||||
this.lvUserDefinedVariables.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
||||
this.columnHeader1,
|
||||
this.columnHeader2});
|
||||
this.listView1.HideSelection = false;
|
||||
this.listView1.Location = new System.Drawing.Point(16, 26);
|
||||
this.listView1.Name = "listView1";
|
||||
this.listView1.Size = new System.Drawing.Size(386, 129);
|
||||
this.listView1.TabIndex = 0;
|
||||
this.listView1.UseCompatibleStateImageBehavior = false;
|
||||
this.listView1.SelectedIndexChanged += new System.EventHandler(this.ListView1_SelectedIndexChanged);
|
||||
this.lvUserDefinedVariables.HideSelection = false;
|
||||
this.lvUserDefinedVariables.Location = new System.Drawing.Point(16, 26);
|
||||
this.lvUserDefinedVariables.Name = "lvUserDefinedVariables";
|
||||
this.lvUserDefinedVariables.Size = new System.Drawing.Size(386, 129);
|
||||
this.lvUserDefinedVariables.TabIndex = 0;
|
||||
this.lvUserDefinedVariables.UseCompatibleStateImageBehavior = false;
|
||||
this.lvUserDefinedVariables.SelectedIndexChanged += new System.EventHandler(this.lvUserDefinedVariables_SelectedIndexChanged);
|
||||
//
|
||||
// columnHeader1
|
||||
//
|
||||
|
@ -80,22 +80,22 @@
|
|||
//
|
||||
this.columnHeader2.Text = "Value";
|
||||
//
|
||||
// groupBox2
|
||||
// gbUpdateUserDefinedVariable
|
||||
//
|
||||
this.groupBox2.Controls.Add(this.checkDeleteVariable);
|
||||
this.groupBox2.Controls.Add(this.btnOk);
|
||||
this.groupBox2.Controls.Add(this.btnOpenFile);
|
||||
this.groupBox2.Controls.Add(this.btnOpenDirectory);
|
||||
this.groupBox2.Controls.Add(this.textSetValue);
|
||||
this.groupBox2.Controls.Add(this.textSetName);
|
||||
this.groupBox2.Controls.Add(this.labelSetValue);
|
||||
this.groupBox2.Controls.Add(this.labelSetName);
|
||||
this.groupBox2.Location = new System.Drawing.Point(12, 188);
|
||||
this.groupBox2.Name = "groupBox2";
|
||||
this.groupBox2.Size = new System.Drawing.Size(419, 229);
|
||||
this.groupBox2.TabIndex = 1;
|
||||
this.groupBox2.TabStop = false;
|
||||
this.groupBox2.Text = "Update the user-defined variable";
|
||||
this.gbUpdateUserDefinedVariable.Controls.Add(this.checkDeleteVariable);
|
||||
this.gbUpdateUserDefinedVariable.Controls.Add(this.btnOk);
|
||||
this.gbUpdateUserDefinedVariable.Controls.Add(this.btnOpenFile);
|
||||
this.gbUpdateUserDefinedVariable.Controls.Add(this.btnOpenDirectory);
|
||||
this.gbUpdateUserDefinedVariable.Controls.Add(this.textSetValue);
|
||||
this.gbUpdateUserDefinedVariable.Controls.Add(this.textSetName);
|
||||
this.gbUpdateUserDefinedVariable.Controls.Add(this.labelSetValue);
|
||||
this.gbUpdateUserDefinedVariable.Controls.Add(this.labelSetName);
|
||||
this.gbUpdateUserDefinedVariable.Location = new System.Drawing.Point(12, 188);
|
||||
this.gbUpdateUserDefinedVariable.Name = "gbUpdateUserDefinedVariable";
|
||||
this.gbUpdateUserDefinedVariable.Size = new System.Drawing.Size(419, 229);
|
||||
this.gbUpdateUserDefinedVariable.TabIndex = 1;
|
||||
this.gbUpdateUserDefinedVariable.TabStop = false;
|
||||
this.gbUpdateUserDefinedVariable.Text = "Update the user-defined variable";
|
||||
//
|
||||
// checkDeleteVariable
|
||||
//
|
||||
|
@ -125,9 +125,12 @@
|
|||
this.btnOpenFile.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
this.btnOpenFile.Location = new System.Drawing.Point(31, 169);
|
||||
this.btnOpenFile.Name = "btnOpenFile";
|
||||
this.btnOpenFile.Padding = new System.Windows.Forms.Padding(11, 0, 0, 0);
|
||||
this.btnOpenFile.Size = new System.Drawing.Size(201, 40);
|
||||
this.btnOpenFile.TabIndex = 5;
|
||||
this.btnOpenFile.Text = "Open the file...";
|
||||
this.btnOpenFile.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
this.btnOpenFile.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
|
||||
this.btnOpenFile.UseVisualStyleBackColor = true;
|
||||
this.btnOpenFile.Click += new System.EventHandler(this.btnOpenFile_Click);
|
||||
//
|
||||
|
@ -137,9 +140,12 @@
|
|||
this.btnOpenDirectory.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
this.btnOpenDirectory.Location = new System.Drawing.Point(31, 123);
|
||||
this.btnOpenDirectory.Name = "btnOpenDirectory";
|
||||
this.btnOpenDirectory.Padding = new System.Windows.Forms.Padding(11, 0, 0, 0);
|
||||
this.btnOpenDirectory.Size = new System.Drawing.Size(201, 40);
|
||||
this.btnOpenDirectory.TabIndex = 4;
|
||||
this.btnOpenDirectory.Text = "Open the directory...";
|
||||
this.btnOpenDirectory.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
this.btnOpenDirectory.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
|
||||
this.btnOpenDirectory.UseVisualStyleBackColor = true;
|
||||
this.btnOpenDirectory.Click += new System.EventHandler(this.btnOpenDirectory_Click);
|
||||
//
|
||||
|
@ -175,16 +181,16 @@
|
|||
this.labelSetName.TabIndex = 0;
|
||||
this.labelSetName.Text = "Set name:";
|
||||
//
|
||||
// groupBox3
|
||||
// gbImportAndExport
|
||||
//
|
||||
this.groupBox3.Controls.Add(this.btnExport);
|
||||
this.groupBox3.Controls.Add(this.btnImport);
|
||||
this.groupBox3.Location = new System.Drawing.Point(12, 423);
|
||||
this.groupBox3.Name = "groupBox3";
|
||||
this.groupBox3.Size = new System.Drawing.Size(419, 89);
|
||||
this.groupBox3.TabIndex = 2;
|
||||
this.groupBox3.TabStop = false;
|
||||
this.groupBox3.Text = "Import and export";
|
||||
this.gbImportAndExport.Controls.Add(this.btnExport);
|
||||
this.gbImportAndExport.Controls.Add(this.btnImport);
|
||||
this.gbImportAndExport.Location = new System.Drawing.Point(12, 423);
|
||||
this.gbImportAndExport.Name = "gbImportAndExport";
|
||||
this.gbImportAndExport.Size = new System.Drawing.Size(419, 89);
|
||||
this.gbImportAndExport.TabIndex = 2;
|
||||
this.gbImportAndExport.TabStop = false;
|
||||
this.gbImportAndExport.Text = "Import and export";
|
||||
//
|
||||
// btnExport
|
||||
//
|
||||
|
@ -192,6 +198,7 @@
|
|||
this.btnExport.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
this.btnExport.Location = new System.Drawing.Point(213, 29);
|
||||
this.btnExport.Name = "btnExport";
|
||||
this.btnExport.Padding = new System.Windows.Forms.Padding(11, 0, 0, 0);
|
||||
this.btnExport.Size = new System.Drawing.Size(176, 40);
|
||||
this.btnExport.TabIndex = 6;
|
||||
this.btnExport.Text = "Export";
|
||||
|
@ -204,6 +211,7 @@
|
|||
this.btnImport.ImageAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
this.btnImport.Location = new System.Drawing.Point(31, 29);
|
||||
this.btnImport.Name = "btnImport";
|
||||
this.btnImport.Padding = new System.Windows.Forms.Padding(11, 0, 0, 0);
|
||||
this.btnImport.Size = new System.Drawing.Size(176, 40);
|
||||
this.btnImport.TabIndex = 5;
|
||||
this.btnImport.Text = "Import";
|
||||
|
@ -215,26 +223,26 @@
|
|||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(447, 529);
|
||||
this.Controls.Add(this.groupBox3);
|
||||
this.Controls.Add(this.groupBox2);
|
||||
this.Controls.Add(this.groupBox1);
|
||||
this.Controls.Add(this.gbImportAndExport);
|
||||
this.Controls.Add(this.gbUpdateUserDefinedVariable);
|
||||
this.Controls.Add(this.gbUserDefinedVariables);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.Icon = global::WelsonJS.Launcher.Properties.Resources.favicon;
|
||||
this.MaximizeBox = false;
|
||||
this.Name = "EnvForm";
|
||||
this.Text = "User-defined variables editor";
|
||||
this.groupBox1.ResumeLayout(false);
|
||||
this.groupBox2.ResumeLayout(false);
|
||||
this.groupBox2.PerformLayout();
|
||||
this.groupBox3.ResumeLayout(false);
|
||||
this.gbUserDefinedVariables.ResumeLayout(false);
|
||||
this.gbUpdateUserDefinedVariable.ResumeLayout(false);
|
||||
this.gbUpdateUserDefinedVariable.PerformLayout();
|
||||
this.gbImportAndExport.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.GroupBox groupBox1;
|
||||
private System.Windows.Forms.GroupBox groupBox2;
|
||||
private System.Windows.Forms.GroupBox gbUserDefinedVariables;
|
||||
private System.Windows.Forms.GroupBox gbUpdateUserDefinedVariable;
|
||||
private System.Windows.Forms.TextBox textSetValue;
|
||||
private System.Windows.Forms.TextBox textSetName;
|
||||
private System.Windows.Forms.Label labelSetValue;
|
||||
|
@ -243,10 +251,10 @@
|
|||
private System.Windows.Forms.Button btnOpenFile;
|
||||
private System.Windows.Forms.Button btnOpenDirectory;
|
||||
private System.Windows.Forms.CheckBox checkDeleteVariable;
|
||||
private System.Windows.Forms.ListView listView1;
|
||||
private System.Windows.Forms.ListView lvUserDefinedVariables;
|
||||
private System.Windows.Forms.ColumnHeader columnHeader1;
|
||||
private System.Windows.Forms.ColumnHeader columnHeader2;
|
||||
private System.Windows.Forms.GroupBox groupBox3;
|
||||
private System.Windows.Forms.GroupBox gbImportAndExport;
|
||||
private System.Windows.Forms.Button btnImport;
|
||||
private System.Windows.Forms.Button btnExport;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace WelsonJS.Launcher
|
||||
|
@ -9,24 +10,27 @@ namespace WelsonJS.Launcher
|
|||
{
|
||||
private Dictionary<string, string> userVariables = new Dictionary<string, string>();
|
||||
private string tempFilePath;
|
||||
private readonly Encoding defaultEncoding = Encoding.UTF8;
|
||||
|
||||
public EnvForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
InitializeListView();
|
||||
// Set the variable file path in the temporary folder
|
||||
tempFilePath = Path.Combine(Path.GetTempPath(), "welsonjs_default.env");
|
||||
|
||||
// Set the variable file path
|
||||
tempFilePath = Path.Combine(Program.GetAppDataPath(), "welsonjs_default.env");
|
||||
|
||||
LoadUserVariables(); // Load variables
|
||||
}
|
||||
|
||||
// Initialize ListView
|
||||
private void InitializeListView()
|
||||
{
|
||||
listView1.View = View.Details;
|
||||
listView1.FullRowSelect = true;
|
||||
listView1.Columns[0].Width = 150;
|
||||
listView1.Columns[1].Width = 220;
|
||||
listView1.SelectedIndexChanged += ListView1_SelectedIndexChanged;
|
||||
lvUserDefinedVariables.View = View.Details;
|
||||
lvUserDefinedVariables.FullRowSelect = true;
|
||||
lvUserDefinedVariables.Columns[0].Width = 150;
|
||||
lvUserDefinedVariables.Columns[1].Width = 220;
|
||||
lvUserDefinedVariables.SelectedIndexChanged += lvUserDefinedVariables_SelectedIndexChanged;
|
||||
}
|
||||
|
||||
// Load user-defined variables from the temporary folder in .env format
|
||||
|
@ -84,21 +88,21 @@ namespace WelsonJS.Launcher
|
|||
// Update ListView with current variables
|
||||
private void UpdateListView()
|
||||
{
|
||||
listView1.Items.Clear();
|
||||
lvUserDefinedVariables.Items.Clear();
|
||||
foreach (var variable in userVariables)
|
||||
{
|
||||
var item = new ListViewItem(variable.Key);
|
||||
item.SubItems.Add(variable.Value);
|
||||
listView1.Items.Add(item);
|
||||
lvUserDefinedVariables.Items.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle ListView selection change
|
||||
private void ListView1_SelectedIndexChanged(object sender, EventArgs e)
|
||||
private void lvUserDefinedVariables_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (listView1.SelectedItems.Count > 0)
|
||||
if (lvUserDefinedVariables.SelectedItems.Count > 0)
|
||||
{
|
||||
var selectedItem = listView1.SelectedItems[0];
|
||||
var selectedItem = lvUserDefinedVariables.SelectedItems[0];
|
||||
textSetName.Text = selectedItem.Text;
|
||||
textSetValue.Text = selectedItem.SubItems[1].Text;
|
||||
checkDeleteVariable.Checked = false;
|
||||
|
@ -164,7 +168,7 @@ namespace WelsonJS.Launcher
|
|||
}
|
||||
|
||||
// Write lines to the file
|
||||
File.WriteAllLines(tempFilePath, lines);
|
||||
File.WriteAllLines(tempFilePath, lines, defaultEncoding);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -183,68 +187,74 @@ namespace WelsonJS.Launcher
|
|||
// Handle "Open Directory" button click
|
||||
private void btnOpenDirectory_Click(object sender, EventArgs e)
|
||||
{
|
||||
var folderDialog = new FolderBrowserDialog();
|
||||
if (folderDialog.ShowDialog() == DialogResult.OK)
|
||||
using (var folderDialog = new FolderBrowserDialog())
|
||||
{
|
||||
textSetValue.Text = folderDialog.SelectedPath;
|
||||
if (folderDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
textSetValue.Text = folderDialog.SelectedPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle "Open File" button click
|
||||
private void btnOpenFile_Click(object sender, EventArgs e)
|
||||
{
|
||||
var fileDialog = new OpenFileDialog();
|
||||
if (fileDialog.ShowDialog() == DialogResult.OK)
|
||||
using (var fileDialog = new OpenFileDialog())
|
||||
{
|
||||
textSetName.Text = Path.GetFileName(fileDialog.FileName);
|
||||
textSetValue.Text = fileDialog.FileName;
|
||||
if (fileDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
textSetName.Text = Path.GetFileName(fileDialog.FileName);
|
||||
textSetValue.Text = fileDialog.FileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void btnImport_Click(object sender, EventArgs e)
|
||||
{
|
||||
OpenFileDialog openFileDialog = new OpenFileDialog();
|
||||
openFileDialog.Filter = "Env files (*.env)|*.env|All files (*.*)|*.*";
|
||||
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
||||
using (var openFileDialog = new OpenFileDialog())
|
||||
{
|
||||
try
|
||||
openFileDialog.Filter = "Env files (*.env)|*.env|All files (*.*)|*.*";
|
||||
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
// Load variables from the selected file
|
||||
string filePath = openFileDialog.FileName;
|
||||
string[] lines = File.ReadAllLines(filePath);
|
||||
|
||||
foreach (string line in lines)
|
||||
try
|
||||
{
|
||||
// Skip empty lines
|
||||
if (string.IsNullOrWhiteSpace(line)) continue;
|
||||
// Load variables from the selected file
|
||||
string filePath = openFileDialog.FileName;
|
||||
string[] lines = File.ReadAllLines(filePath, defaultEncoding);
|
||||
|
||||
int indexOfEquals = line.IndexOf('=');
|
||||
if (indexOfEquals != -1)
|
||||
foreach (string line in lines)
|
||||
{
|
||||
string key = line.Substring(0, indexOfEquals).Trim();
|
||||
string value = line.Substring(indexOfEquals + 1).Trim();
|
||||
// Skip empty lines
|
||||
if (string.IsNullOrWhiteSpace(line)) continue;
|
||||
|
||||
// Remove surrounding quotes if present
|
||||
if (value.StartsWith("\"") && value.EndsWith("\""))
|
||||
int indexOfEquals = line.IndexOf('=');
|
||||
if (indexOfEquals != -1)
|
||||
{
|
||||
value = value.Substring(1, value.Length - 2);
|
||||
string key = line.Substring(0, indexOfEquals).Trim();
|
||||
string value = line.Substring(indexOfEquals + 1).Trim();
|
||||
|
||||
// Remove surrounding quotes if present
|
||||
if (value.StartsWith("\"") && value.EndsWith("\""))
|
||||
{
|
||||
value = value.Substring(1, value.Length - 2);
|
||||
}
|
||||
|
||||
// Unescape double quotes in the value
|
||||
value = value.Replace("\\\"", "\"");
|
||||
|
||||
// Update or add the key-value pair
|
||||
userVariables[key] = value;
|
||||
}
|
||||
|
||||
// Unescape double quotes in the value
|
||||
value = value.Replace("\\\"", "\"");
|
||||
|
||||
// Update or add the key-value pair
|
||||
userVariables[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// Save the updated variables to the file
|
||||
SaveUserVariables();
|
||||
UpdateListView(); // Refresh the display
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"Error importing variable file: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
// Save the updated variables to the file
|
||||
SaveUserVariables();
|
||||
UpdateListView(); // Refresh the display
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"Error importing variable file: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -273,7 +283,7 @@ namespace WelsonJS.Launcher
|
|||
|
||||
lines.Add($"{variable.Key}={value}");
|
||||
}
|
||||
File.WriteAllLines(filePath, lines);
|
||||
File.WriteAllLines(filePath, lines, defaultEncoding);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
89
WelsonJS.Toolkit/WelsonJS.Launcher/GlobalSettingsForm.Designer.cs
generated
Normal file
89
WelsonJS.Toolkit/WelsonJS.Launcher/GlobalSettingsForm.Designer.cs
generated
Normal file
|
@ -0,0 +1,89 @@
|
|||
namespace WelsonJS.Launcher
|
||||
{
|
||||
partial class GlobalSettingsForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.gbMaxScriptStatements = new System.Windows.Forms.GroupBox();
|
||||
this.btnOkMaxScriptStatements = new System.Windows.Forms.Button();
|
||||
this.txtMaxScriptStatements = new System.Windows.Forms.TextBox();
|
||||
this.gbMaxScriptStatements.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// gbMaxScriptStatements
|
||||
//
|
||||
this.gbMaxScriptStatements.Controls.Add(this.btnOkMaxScriptStatements);
|
||||
this.gbMaxScriptStatements.Controls.Add(this.txtMaxScriptStatements);
|
||||
this.gbMaxScriptStatements.Location = new System.Drawing.Point(12, 12);
|
||||
this.gbMaxScriptStatements.Name = "gbMaxScriptStatements";
|
||||
this.gbMaxScriptStatements.Size = new System.Drawing.Size(290, 67);
|
||||
this.gbMaxScriptStatements.TabIndex = 0;
|
||||
this.gbMaxScriptStatements.TabStop = false;
|
||||
this.gbMaxScriptStatements.Text = "MaxScriptStatements (GUI only)";
|
||||
//
|
||||
// btnOkMaxScriptStatements
|
||||
//
|
||||
this.btnOkMaxScriptStatements.Location = new System.Drawing.Point(218, 30);
|
||||
this.btnOkMaxScriptStatements.Name = "btnOkMaxScriptStatements";
|
||||
this.btnOkMaxScriptStatements.Size = new System.Drawing.Size(57, 21);
|
||||
this.btnOkMaxScriptStatements.TabIndex = 1;
|
||||
this.btnOkMaxScriptStatements.Text = "Ok";
|
||||
this.btnOkMaxScriptStatements.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
|
||||
this.btnOkMaxScriptStatements.UseVisualStyleBackColor = true;
|
||||
this.btnOkMaxScriptStatements.Click += new System.EventHandler(this.btnOkMaxScriptStatements_Click);
|
||||
//
|
||||
// txtMaxScriptStatements
|
||||
//
|
||||
this.txtMaxScriptStatements.Location = new System.Drawing.Point(15, 30);
|
||||
this.txtMaxScriptStatements.Name = "txtMaxScriptStatements";
|
||||
this.txtMaxScriptStatements.Size = new System.Drawing.Size(197, 21);
|
||||
this.txtMaxScriptStatements.TabIndex = 1;
|
||||
//
|
||||
// GlobalSettingsForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(315, 92);
|
||||
this.Controls.Add(this.gbMaxScriptStatements);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.Icon = global::WelsonJS.Launcher.Properties.Resources.favicon;
|
||||
this.MaximizeBox = false;
|
||||
this.Name = "GlobalSettingsForm";
|
||||
this.Text = "Global settings...";
|
||||
this.gbMaxScriptStatements.ResumeLayout(false);
|
||||
this.gbMaxScriptStatements.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.GroupBox gbMaxScriptStatements;
|
||||
private System.Windows.Forms.TextBox txtMaxScriptStatements;
|
||||
private System.Windows.Forms.Button btnOkMaxScriptStatements;
|
||||
}
|
||||
}
|
56
WelsonJS.Toolkit/WelsonJS.Launcher/GlobalSettingsForm.cs
Normal file
56
WelsonJS.Toolkit/WelsonJS.Launcher/GlobalSettingsForm.cs
Normal file
|
@ -0,0 +1,56 @@
|
|||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace WelsonJS.Launcher
|
||||
{
|
||||
public partial class GlobalSettingsForm : Form
|
||||
{
|
||||
private const string RegistryPath = "Software\\Microsoft\\Internet Explorer\\Styles";
|
||||
private const string RegistryKey = "MaxScriptStatements";
|
||||
|
||||
public GlobalSettingsForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
LoadRegistryValue();
|
||||
}
|
||||
|
||||
private void LoadRegistryValue()
|
||||
{
|
||||
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(RegistryPath))
|
||||
{
|
||||
if (key != null)
|
||||
{
|
||||
string value = key.GetValue(RegistryKey)?.ToString();
|
||||
if (value != null && int.TryParse(value, out int maxStatements))
|
||||
{
|
||||
txtMaxScriptStatements.Text = maxStatements.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void btnOkMaxScriptStatements_Click(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (int.TryParse(txtMaxScriptStatements.Text, out int maxStatements))
|
||||
{
|
||||
using (RegistryKey key = Registry.CurrentUser.CreateSubKey(RegistryPath))
|
||||
{
|
||||
key.SetValue(RegistryKey, maxStatements, RegistryValueKind.DWord);
|
||||
}
|
||||
MessageBox.Show($"MaxScriptStatements setting has been changed to {maxStatements}.", "Confirmation", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("Please enter a valid number within the DWORD range.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"An error occurred while trying to change the MaxScriptStatements setting: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
120
WelsonJS.Toolkit/WelsonJS.Launcher/GlobalSettingsForm.resx
Normal file
120
WelsonJS.Toolkit/WelsonJS.Launcher/GlobalSettingsForm.resx
Normal file
|
@ -0,0 +1,120 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
25
WelsonJS.Toolkit/WelsonJS.Launcher/IResourceTool.cs
Normal file
25
WelsonJS.Toolkit/WelsonJS.Launcher/IResourceTool.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WelsonJS.Launcher
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a contract for resource tools that can handle specific HTTP requests.
|
||||
/// </summary>
|
||||
public interface IResourceTool
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines whether this tool can handle the specified path.
|
||||
/// </summary>
|
||||
/// <param name="path">The request path to check.</param>
|
||||
/// <returns>True if this tool can handle the request; otherwise, false.</returns>
|
||||
bool CanHandle(string path);
|
||||
/// <summary>
|
||||
/// Asynchronously processes the HTTP request for the specified path.
|
||||
/// </summary>
|
||||
/// <param name="context">The HTTP listener context containing request and response objects.</param>
|
||||
/// <param name="path">The request path to handle.</param>
|
||||
/// <returns>A task representing the asynchronous operation.</returns>
|
||||
Task HandleAsync(HttpListenerContext context, string path);
|
||||
}
|
||||
}
|
170
WelsonJS.Toolkit/WelsonJS.Launcher/InstancesForm.Designer.cs
generated
Normal file
170
WelsonJS.Toolkit/WelsonJS.Launcher/InstancesForm.Designer.cs
generated
Normal file
|
@ -0,0 +1,170 @@
|
|||
namespace WelsonJS.Launcher
|
||||
{
|
||||
partial class InstancesForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.lvInstances = new System.Windows.Forms.ListView();
|
||||
this.chInstanceId = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.chFirstDeployTime = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
|
||||
this.btnDelete = new System.Windows.Forms.Button();
|
||||
this.btnOpenWithExplorer = new System.Windows.Forms.Button();
|
||||
this.cbInteractiveServiceApp = new System.Windows.Forms.CheckBox();
|
||||
this.txtUseSpecificScript = new System.Windows.Forms.TextBox();
|
||||
this.cbUseSpecificScript = new System.Windows.Forms.CheckBox();
|
||||
this.btnStart = new System.Windows.Forms.Button();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// lvInstances
|
||||
//
|
||||
this.lvInstances.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
||||
this.chInstanceId,
|
||||
this.chFirstDeployTime});
|
||||
this.lvInstances.HideSelection = false;
|
||||
this.lvInstances.Location = new System.Drawing.Point(8, 8);
|
||||
this.lvInstances.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
|
||||
this.lvInstances.Name = "lvInstances";
|
||||
this.lvInstances.Size = new System.Drawing.Size(384, 170);
|
||||
this.lvInstances.TabIndex = 0;
|
||||
this.lvInstances.UseCompatibleStateImageBehavior = false;
|
||||
this.lvInstances.View = System.Windows.Forms.View.Details;
|
||||
//
|
||||
// chInstanceId
|
||||
//
|
||||
this.chInstanceId.Text = "Instance ID";
|
||||
this.chInstanceId.Width = 220;
|
||||
//
|
||||
// chFirstDeployTime
|
||||
//
|
||||
this.chFirstDeployTime.Text = "First Deploy Time";
|
||||
this.chFirstDeployTime.Width = 160;
|
||||
//
|
||||
// btnDelete
|
||||
//
|
||||
this.btnDelete.Image = global::WelsonJS.Launcher.Properties.Resources.icon_delete_32;
|
||||
this.btnDelete.Location = new System.Drawing.Point(120, 243);
|
||||
this.btnDelete.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
|
||||
this.btnDelete.Name = "btnDelete";
|
||||
this.btnDelete.Size = new System.Drawing.Size(105, 40);
|
||||
this.btnDelete.TabIndex = 2;
|
||||
this.btnDelete.Text = "Delete";
|
||||
this.btnDelete.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
|
||||
this.btnDelete.UseVisualStyleBackColor = true;
|
||||
this.btnDelete.Click += new System.EventHandler(this.btnDelete_Click);
|
||||
//
|
||||
// btnOpenWithExplorer
|
||||
//
|
||||
this.btnOpenWithExplorer.Image = global::WelsonJS.Launcher.Properties.Resources.icon_directory_32;
|
||||
this.btnOpenWithExplorer.Location = new System.Drawing.Point(229, 243);
|
||||
this.btnOpenWithExplorer.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
|
||||
this.btnOpenWithExplorer.Name = "btnOpenWithExplorer";
|
||||
this.btnOpenWithExplorer.Size = new System.Drawing.Size(162, 40);
|
||||
this.btnOpenWithExplorer.TabIndex = 3;
|
||||
this.btnOpenWithExplorer.Text = "Open with Explorer";
|
||||
this.btnOpenWithExplorer.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
|
||||
this.btnOpenWithExplorer.UseVisualStyleBackColor = true;
|
||||
this.btnOpenWithExplorer.Click += new System.EventHandler(this.btnOpenWithExplorer_Click);
|
||||
//
|
||||
// cbInteractiveServiceApp
|
||||
//
|
||||
this.cbInteractiveServiceApp.AutoSize = true;
|
||||
this.cbInteractiveServiceApp.Location = new System.Drawing.Point(10, 215);
|
||||
this.cbInteractiveServiceApp.Name = "cbInteractiveServiceApp";
|
||||
this.cbInteractiveServiceApp.Size = new System.Drawing.Size(254, 16);
|
||||
this.cbInteractiveServiceApp.TabIndex = 9;
|
||||
this.cbInteractiveServiceApp.Text = "This is an Interactive Service Application";
|
||||
this.cbInteractiveServiceApp.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// txtUseSpecificScript
|
||||
//
|
||||
this.txtUseSpecificScript.Enabled = false;
|
||||
this.txtUseSpecificScript.Location = new System.Drawing.Point(199, 189);
|
||||
this.txtUseSpecificScript.Name = "txtUseSpecificScript";
|
||||
this.txtUseSpecificScript.Size = new System.Drawing.Size(110, 21);
|
||||
this.txtUseSpecificScript.TabIndex = 8;
|
||||
//
|
||||
// cbUseSpecificScript
|
||||
//
|
||||
this.cbUseSpecificScript.AutoSize = true;
|
||||
this.cbUseSpecificScript.Location = new System.Drawing.Point(10, 192);
|
||||
this.cbUseSpecificScript.Name = "cbUseSpecificScript";
|
||||
this.cbUseSpecificScript.Size = new System.Drawing.Size(184, 16);
|
||||
this.cbUseSpecificScript.TabIndex = 7;
|
||||
this.cbUseSpecificScript.Text = "I want to use specific script ";
|
||||
this.cbUseSpecificScript.UseVisualStyleBackColor = true;
|
||||
this.cbUseSpecificScript.CheckedChanged += new System.EventHandler(this.cbUseSpecificScript_CheckedChanged);
|
||||
//
|
||||
// btnStart
|
||||
//
|
||||
this.btnStart.Image = global::WelsonJS.Launcher.Properties.Resources.icon_start_32;
|
||||
this.btnStart.Location = new System.Drawing.Point(10, 243);
|
||||
this.btnStart.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
|
||||
this.btnStart.Name = "btnStart";
|
||||
this.btnStart.Size = new System.Drawing.Size(105, 40);
|
||||
this.btnStart.TabIndex = 1;
|
||||
this.btnStart.Text = "Start";
|
||||
this.btnStart.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
|
||||
this.btnStart.UseVisualStyleBackColor = true;
|
||||
this.btnStart.Click += new System.EventHandler(this.btnStart_Click);
|
||||
//
|
||||
// InstancesForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(401, 296);
|
||||
this.Controls.Add(this.btnStart);
|
||||
this.Controls.Add(this.lvInstances);
|
||||
this.Controls.Add(this.btnDelete);
|
||||
this.Controls.Add(this.cbUseSpecificScript);
|
||||
this.Controls.Add(this.cbInteractiveServiceApp);
|
||||
this.Controls.Add(this.btnOpenWithExplorer);
|
||||
this.Controls.Add(this.txtUseSpecificScript);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.Icon = global::WelsonJS.Launcher.Properties.Resources.favicon;
|
||||
this.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2);
|
||||
this.MaximizeBox = false;
|
||||
this.Name = "InstancesForm";
|
||||
this.Text = "Instances";
|
||||
this.Load += new System.EventHandler(this.InstancesForm_Load);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.ListView lvInstances;
|
||||
private System.Windows.Forms.Button btnDelete;
|
||||
private System.Windows.Forms.Button btnOpenWithExplorer;
|
||||
private System.Windows.Forms.CheckBox cbInteractiveServiceApp;
|
||||
private System.Windows.Forms.TextBox txtUseSpecificScript;
|
||||
private System.Windows.Forms.CheckBox cbUseSpecificScript;
|
||||
private System.Windows.Forms.ColumnHeader chInstanceId;
|
||||
private System.Windows.Forms.ColumnHeader chFirstDeployTime;
|
||||
private System.Windows.Forms.Button btnStart;
|
||||
}
|
||||
}
|
141
WelsonJS.Toolkit/WelsonJS.Launcher/InstancesForm.cs
Normal file
141
WelsonJS.Toolkit/WelsonJS.Launcher/InstancesForm.cs
Normal file
|
@ -0,0 +1,141 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace WelsonJS.Launcher
|
||||
{
|
||||
public partial class InstancesForm : Form
|
||||
{
|
||||
private string entryFileName;
|
||||
private string scriptName;
|
||||
private const string timestampFormat = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
public InstancesForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
entryFileName = "bootstrap.bat";
|
||||
}
|
||||
|
||||
private void InstancesForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
lvInstances.Items.Clear();
|
||||
LoadInstances(Program.GetAppDataPath());
|
||||
LoadInstances(Path.GetTempPath());
|
||||
}
|
||||
|
||||
private void LoadInstances(string instancesRoot)
|
||||
{
|
||||
if (!Directory.Exists(instancesRoot))
|
||||
return;
|
||||
|
||||
foreach (string dir in Directory.GetDirectories(instancesRoot))
|
||||
{
|
||||
string timestampFile = Path.Combine(dir, ".welsonjs_first_deploy_time");
|
||||
string entryScriptFile = Path.Combine(dir, "app.js");
|
||||
string firstDeployTime = null;
|
||||
|
||||
if (File.Exists(timestampFile)
|
||||
&& DateTime.TryParse(File.ReadAllText(timestampFile).Trim(), out DateTime parsedTimestamp))
|
||||
{
|
||||
firstDeployTime = parsedTimestamp.ToString(timestampFormat);
|
||||
}
|
||||
else if (File.Exists(entryScriptFile))
|
||||
{
|
||||
firstDeployTime = File.GetCreationTime(entryScriptFile).ToString(timestampFormat);
|
||||
}
|
||||
|
||||
if (firstDeployTime != null)
|
||||
{
|
||||
lvInstances.Items.Add(new ListViewItem(new[]
|
||||
{
|
||||
Path.GetFileName(dir),
|
||||
firstDeployTime
|
||||
})
|
||||
{
|
||||
Tag = dir
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void btnStart_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (lvInstances.SelectedItems.Count > 0)
|
||||
{
|
||||
scriptName = txtUseSpecificScript.Text;
|
||||
|
||||
string instanceId = lvInstances.SelectedItems[0].Text;
|
||||
string workingDirectory = Program.GetWorkingDirectory(instanceId, true);
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
// Run the appliction
|
||||
Program.RunCommandPrompt(workingDirectory, entryFileName, scriptName, cbUseSpecificScript.Checked, cbInteractiveServiceApp.Checked);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("No selected an instance");
|
||||
}
|
||||
}
|
||||
|
||||
private void btnDelete_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (lvInstances.SelectedItems.Count > 0)
|
||||
{
|
||||
string instanceId = lvInstances.SelectedItems[0].Text;
|
||||
string workingDirectory = Program.GetWorkingDirectory(instanceId, false);
|
||||
|
||||
if (!Directory.Exists(workingDirectory))
|
||||
{
|
||||
workingDirectory = Path.Combine(Path.GetTempPath(), instanceId);
|
||||
}
|
||||
|
||||
if (Directory.Exists(workingDirectory))
|
||||
{
|
||||
Directory.Delete(workingDirectory, true);
|
||||
|
||||
lvInstances.Items.Clear();
|
||||
LoadInstances(Program.GetAppDataPath());
|
||||
LoadInstances(Path.GetTempPath());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("No selected an instance");
|
||||
}
|
||||
}
|
||||
|
||||
private void btnOpenWithExplorer_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (lvInstances.SelectedItems.Count > 0)
|
||||
{
|
||||
string instanceId = lvInstances.SelectedItems[0].Text;
|
||||
string workingDirectory = Program.GetWorkingDirectory(instanceId, true);
|
||||
|
||||
if (Directory.Exists(workingDirectory))
|
||||
{
|
||||
System.Diagnostics.Process.Start("explorer", workingDirectory);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("No selected an instance");
|
||||
}
|
||||
}
|
||||
|
||||
private void cbUseSpecificScript_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
txtUseSpecificScript.Enabled = cbUseSpecificScript.Checked;
|
||||
}
|
||||
}
|
||||
}
|
120
WelsonJS.Toolkit/WelsonJS.Launcher/InstancesForm.resx
Normal file
120
WelsonJS.Toolkit/WelsonJS.Launcher/InstancesForm.resx
Normal file
|
@ -0,0 +1,120 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
219
WelsonJS.Toolkit/WelsonJS.Launcher/MainForm.Designer.cs
generated
219
WelsonJS.Toolkit/WelsonJS.Launcher/MainForm.Designer.cs
generated
|
@ -28,42 +28,54 @@
|
|||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.button1 = new System.Windows.Forms.Button();
|
||||
this.button2 = new System.Windows.Forms.Button();
|
||||
this.components = new System.ComponentModel.Container();
|
||||
this.btnRunFromZipFile = new System.Windows.Forms.Button();
|
||||
this.btnRunFromExternalLink = new System.Windows.Forms.Button();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.linkLabel1 = new System.Windows.Forms.LinkLabel();
|
||||
this.checkBox1 = new System.Windows.Forms.CheckBox();
|
||||
this.textBox1 = new System.Windows.Forms.TextBox();
|
||||
this.checkBox2 = new System.Windows.Forms.CheckBox();
|
||||
this.cbUseSpecificScript = new System.Windows.Forms.CheckBox();
|
||||
this.txtUseSpecificScript = new System.Windows.Forms.TextBox();
|
||||
this.cbInteractiveServiceApp = new System.Windows.Forms.CheckBox();
|
||||
this.menuStrip1 = new System.Windows.Forms.MenuStrip();
|
||||
this.settingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.userdefinedVariablesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.instancesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.runAsAdministratorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.globalSettingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.startCodeEditorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.openCopilotToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.notifyIcon1 = new System.Windows.Forms.NotifyIcon(this.components);
|
||||
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
|
||||
this.openLauncherToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.openCodeEditorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.menuStrip1.SuspendLayout();
|
||||
this.contextMenuStrip1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// button1
|
||||
// btnRunFromZipFile
|
||||
//
|
||||
this.button1.Image = global::WelsonJS.Launcher.Properties.Resources.icon_zip_128;
|
||||
this.button1.Location = new System.Drawing.Point(24, 67);
|
||||
this.button1.Name = "button1";
|
||||
this.button1.Size = new System.Drawing.Size(200, 200);
|
||||
this.button1.TabIndex = 0;
|
||||
this.button1.Text = "From ZIP file...";
|
||||
this.button1.TextAlign = System.Drawing.ContentAlignment.BottomCenter;
|
||||
this.button1.UseVisualStyleBackColor = true;
|
||||
this.button1.Click += new System.EventHandler(this.button1_Click);
|
||||
this.btnRunFromZipFile.Image = global::WelsonJS.Launcher.Properties.Resources.icon_zip_128;
|
||||
this.btnRunFromZipFile.Location = new System.Drawing.Point(24, 67);
|
||||
this.btnRunFromZipFile.Name = "btnRunFromZipFile";
|
||||
this.btnRunFromZipFile.Size = new System.Drawing.Size(200, 200);
|
||||
this.btnRunFromZipFile.TabIndex = 0;
|
||||
this.btnRunFromZipFile.Text = "From ZIP file...";
|
||||
this.btnRunFromZipFile.TextAlign = System.Drawing.ContentAlignment.BottomCenter;
|
||||
this.btnRunFromZipFile.UseVisualStyleBackColor = true;
|
||||
this.btnRunFromZipFile.Click += new System.EventHandler(this.btnRunFromZipFile_Click);
|
||||
//
|
||||
// button2
|
||||
// btnRunFromExternalLink
|
||||
//
|
||||
this.button2.Image = global::WelsonJS.Launcher.Properties.Resources.icon_link_128;
|
||||
this.button2.Location = new System.Drawing.Point(230, 67);
|
||||
this.button2.Name = "button2";
|
||||
this.button2.Size = new System.Drawing.Size(200, 200);
|
||||
this.button2.TabIndex = 1;
|
||||
this.button2.Text = "From external link...";
|
||||
this.button2.TextAlign = System.Drawing.ContentAlignment.BottomCenter;
|
||||
this.button2.UseVisualStyleBackColor = true;
|
||||
this.button2.Click += new System.EventHandler(this.button2_Click);
|
||||
this.btnRunFromExternalLink.Image = global::WelsonJS.Launcher.Properties.Resources.icon_link_128;
|
||||
this.btnRunFromExternalLink.Location = new System.Drawing.Point(230, 67);
|
||||
this.btnRunFromExternalLink.Name = "btnRunFromExternalLink";
|
||||
this.btnRunFromExternalLink.Size = new System.Drawing.Size(200, 200);
|
||||
this.btnRunFromExternalLink.TabIndex = 1;
|
||||
this.btnRunFromExternalLink.Text = "From external link...";
|
||||
this.btnRunFromExternalLink.TextAlign = System.Drawing.ContentAlignment.BottomCenter;
|
||||
this.btnRunFromExternalLink.UseVisualStyleBackColor = true;
|
||||
this.btnRunFromExternalLink.Click += new System.EventHandler(this.btnRunFromExternalLink_Click);
|
||||
//
|
||||
// label1
|
||||
//
|
||||
|
@ -85,34 +97,34 @@
|
|||
this.linkLabel1.Text = "https://github.com/gnh1201/welsonjs";
|
||||
this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked);
|
||||
//
|
||||
// checkBox1
|
||||
// cbUseSpecificScript
|
||||
//
|
||||
this.checkBox1.AutoSize = true;
|
||||
this.checkBox1.Location = new System.Drawing.Point(26, 281);
|
||||
this.checkBox1.Name = "checkBox1";
|
||||
this.checkBox1.Size = new System.Drawing.Size(184, 16);
|
||||
this.checkBox1.TabIndex = 4;
|
||||
this.checkBox1.Text = "I want to use specific script ";
|
||||
this.checkBox1.UseVisualStyleBackColor = true;
|
||||
this.checkBox1.CheckedChanged += new System.EventHandler(this.checkBox1_CheckedChanged);
|
||||
this.cbUseSpecificScript.AutoSize = true;
|
||||
this.cbUseSpecificScript.Location = new System.Drawing.Point(26, 281);
|
||||
this.cbUseSpecificScript.Name = "cbUseSpecificScript";
|
||||
this.cbUseSpecificScript.Size = new System.Drawing.Size(184, 16);
|
||||
this.cbUseSpecificScript.TabIndex = 4;
|
||||
this.cbUseSpecificScript.Text = "I want to use specific script ";
|
||||
this.cbUseSpecificScript.UseVisualStyleBackColor = true;
|
||||
this.cbUseSpecificScript.CheckedChanged += new System.EventHandler(this.cbUseSpecificScript_CheckedChanged);
|
||||
//
|
||||
// textBox1
|
||||
// txtUseSpecificScript
|
||||
//
|
||||
this.textBox1.Enabled = false;
|
||||
this.textBox1.Location = new System.Drawing.Point(214, 278);
|
||||
this.textBox1.Name = "textBox1";
|
||||
this.textBox1.Size = new System.Drawing.Size(110, 21);
|
||||
this.textBox1.TabIndex = 5;
|
||||
this.txtUseSpecificScript.Enabled = false;
|
||||
this.txtUseSpecificScript.Location = new System.Drawing.Point(214, 278);
|
||||
this.txtUseSpecificScript.Name = "txtUseSpecificScript";
|
||||
this.txtUseSpecificScript.Size = new System.Drawing.Size(110, 21);
|
||||
this.txtUseSpecificScript.TabIndex = 5;
|
||||
//
|
||||
// checkBox2
|
||||
// cbInteractiveServiceApp
|
||||
//
|
||||
this.checkBox2.AutoSize = true;
|
||||
this.checkBox2.Location = new System.Drawing.Point(26, 305);
|
||||
this.checkBox2.Name = "checkBox2";
|
||||
this.checkBox2.Size = new System.Drawing.Size(254, 16);
|
||||
this.checkBox2.TabIndex = 6;
|
||||
this.checkBox2.Text = "This is an Interactive Service Application";
|
||||
this.checkBox2.UseVisualStyleBackColor = true;
|
||||
this.cbInteractiveServiceApp.AutoSize = true;
|
||||
this.cbInteractiveServiceApp.Location = new System.Drawing.Point(26, 305);
|
||||
this.cbInteractiveServiceApp.Name = "cbInteractiveServiceApp";
|
||||
this.cbInteractiveServiceApp.Size = new System.Drawing.Size(254, 16);
|
||||
this.cbInteractiveServiceApp.TabIndex = 6;
|
||||
this.cbInteractiveServiceApp.Text = "This is an Interactive Service Application";
|
||||
this.cbInteractiveServiceApp.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// menuStrip1
|
||||
//
|
||||
|
@ -127,7 +139,12 @@
|
|||
// settingsToolStripMenuItem
|
||||
//
|
||||
this.settingsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.userdefinedVariablesToolStripMenuItem});
|
||||
this.userdefinedVariablesToolStripMenuItem,
|
||||
this.instancesToolStripMenuItem,
|
||||
this.runAsAdministratorToolStripMenuItem,
|
||||
this.globalSettingsToolStripMenuItem,
|
||||
this.startCodeEditorToolStripMenuItem,
|
||||
this.openCopilotToolStripMenuItem});
|
||||
this.settingsToolStripMenuItem.Name = "settingsToolStripMenuItem";
|
||||
this.settingsToolStripMenuItem.Size = new System.Drawing.Size(62, 20);
|
||||
this.settingsToolStripMenuItem.Text = "Settings";
|
||||
|
@ -135,31 +152,101 @@
|
|||
// userdefinedVariablesToolStripMenuItem
|
||||
//
|
||||
this.userdefinedVariablesToolStripMenuItem.Name = "userdefinedVariablesToolStripMenuItem";
|
||||
this.userdefinedVariablesToolStripMenuItem.Size = new System.Drawing.Size(192, 22);
|
||||
this.userdefinedVariablesToolStripMenuItem.Size = new System.Drawing.Size(196, 22);
|
||||
this.userdefinedVariablesToolStripMenuItem.Text = "User-defined variables";
|
||||
this.userdefinedVariablesToolStripMenuItem.Click += new System.EventHandler(this.userdefinedVariablesToolStripMenuItem_Click);
|
||||
//
|
||||
// instancesToolStripMenuItem
|
||||
//
|
||||
this.instancesToolStripMenuItem.Name = "instancesToolStripMenuItem";
|
||||
this.instancesToolStripMenuItem.Size = new System.Drawing.Size(196, 22);
|
||||
this.instancesToolStripMenuItem.Text = "Instances";
|
||||
this.instancesToolStripMenuItem.Click += new System.EventHandler(this.instancesToolStripMenuItem_Click);
|
||||
//
|
||||
// runAsAdministratorToolStripMenuItem
|
||||
//
|
||||
this.runAsAdministratorToolStripMenuItem.Name = "runAsAdministratorToolStripMenuItem";
|
||||
this.runAsAdministratorToolStripMenuItem.Size = new System.Drawing.Size(196, 22);
|
||||
this.runAsAdministratorToolStripMenuItem.Text = "Run as Administrator...";
|
||||
this.runAsAdministratorToolStripMenuItem.Click += new System.EventHandler(this.runAsAdministratorToolStripMenuItem_Click);
|
||||
//
|
||||
// globalSettingsToolStripMenuItem
|
||||
//
|
||||
this.globalSettingsToolStripMenuItem.Name = "globalSettingsToolStripMenuItem";
|
||||
this.globalSettingsToolStripMenuItem.Size = new System.Drawing.Size(196, 22);
|
||||
this.globalSettingsToolStripMenuItem.Text = "Global settings...";
|
||||
this.globalSettingsToolStripMenuItem.Click += new System.EventHandler(this.globalSettingsToolStripMenuItem_Click);
|
||||
//
|
||||
// startCodeEditorToolStripMenuItem
|
||||
//
|
||||
this.startCodeEditorToolStripMenuItem.Name = "startCodeEditorToolStripMenuItem";
|
||||
this.startCodeEditorToolStripMenuItem.Size = new System.Drawing.Size(196, 22);
|
||||
this.startCodeEditorToolStripMenuItem.Text = "Start the code editor...";
|
||||
this.startCodeEditorToolStripMenuItem.Click += new System.EventHandler(this.startCodeEditorToolStripMenuItem_Click);
|
||||
//
|
||||
// openCopilotToolStripMenuItem
|
||||
//
|
||||
this.openCopilotToolStripMenuItem.Name = "openCopilotToolStripMenuItem";
|
||||
this.openCopilotToolStripMenuItem.Size = new System.Drawing.Size(196, 22);
|
||||
this.openCopilotToolStripMenuItem.Text = "Open the Copilot...";
|
||||
this.openCopilotToolStripMenuItem.Click += new System.EventHandler(this.openCopilotToolStripMenuItem_Click);
|
||||
//
|
||||
// notifyIcon1
|
||||
//
|
||||
this.notifyIcon1.ContextMenuStrip = this.contextMenuStrip1;
|
||||
this.notifyIcon1.Icon = global::WelsonJS.Launcher.Properties.Resources.favicon;
|
||||
this.notifyIcon1.Text = "WelsonJS Launcher";
|
||||
//
|
||||
// contextMenuStrip1
|
||||
//
|
||||
this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.openLauncherToolStripMenuItem,
|
||||
this.openCodeEditorToolStripMenuItem,
|
||||
this.exitToolStripMenuItem});
|
||||
this.contextMenuStrip1.Name = "contextMenuStrip1";
|
||||
this.contextMenuStrip1.Size = new System.Drawing.Size(199, 70);
|
||||
//
|
||||
// openLauncherToolStripMenuItem
|
||||
//
|
||||
this.openLauncherToolStripMenuItem.Name = "openLauncherToolStripMenuItem";
|
||||
this.openLauncherToolStripMenuItem.Size = new System.Drawing.Size(198, 22);
|
||||
this.openLauncherToolStripMenuItem.Text = "Open the launcher...";
|
||||
//
|
||||
// openCodeEditorToolStripMenuItem
|
||||
//
|
||||
this.openCodeEditorToolStripMenuItem.Name = "openCodeEditorToolStripMenuItem";
|
||||
this.openCodeEditorToolStripMenuItem.Size = new System.Drawing.Size(198, 22);
|
||||
this.openCodeEditorToolStripMenuItem.Text = "Open the code editor...";
|
||||
this.openCodeEditorToolStripMenuItem.Click += new System.EventHandler(this.openCodeEditorToolStripMenuItem_Click);
|
||||
//
|
||||
// exitToolStripMenuItem
|
||||
//
|
||||
this.exitToolStripMenuItem.Name = "exitToolStripMenuItem";
|
||||
this.exitToolStripMenuItem.Size = new System.Drawing.Size(198, 22);
|
||||
this.exitToolStripMenuItem.Text = "Exit";
|
||||
//
|
||||
// MainForm
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 12F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(461, 382);
|
||||
this.Controls.Add(this.checkBox2);
|
||||
this.Controls.Add(this.textBox1);
|
||||
this.Controls.Add(this.checkBox1);
|
||||
this.Controls.Add(this.cbInteractiveServiceApp);
|
||||
this.Controls.Add(this.txtUseSpecificScript);
|
||||
this.Controls.Add(this.cbUseSpecificScript);
|
||||
this.Controls.Add(this.linkLabel1);
|
||||
this.Controls.Add(this.label1);
|
||||
this.Controls.Add(this.button2);
|
||||
this.Controls.Add(this.button1);
|
||||
this.Controls.Add(this.btnRunFromExternalLink);
|
||||
this.Controls.Add(this.btnRunFromZipFile);
|
||||
this.Controls.Add(this.menuStrip1);
|
||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
this.Icon = global::WelsonJS.Launcher.Properties.Resources.favicon;
|
||||
this.MainMenuStrip = this.menuStrip1;
|
||||
this.MaximizeBox = false;
|
||||
this.Name = "MainForm";
|
||||
this.Text = "WelsonJS.Launcher";
|
||||
this.Text = "WelsonJS Application Launcher";
|
||||
this.menuStrip1.ResumeLayout(false);
|
||||
this.menuStrip1.PerformLayout();
|
||||
this.contextMenuStrip1.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
|
@ -167,16 +254,26 @@
|
|||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button button1;
|
||||
private System.Windows.Forms.Button button2;
|
||||
private System.Windows.Forms.Button btnRunFromZipFile;
|
||||
private System.Windows.Forms.Button btnRunFromExternalLink;
|
||||
private System.Windows.Forms.Label label1;
|
||||
private System.Windows.Forms.LinkLabel linkLabel1;
|
||||
private System.Windows.Forms.CheckBox checkBox1;
|
||||
private System.Windows.Forms.TextBox textBox1;
|
||||
private System.Windows.Forms.CheckBox checkBox2;
|
||||
private System.Windows.Forms.CheckBox cbUseSpecificScript;
|
||||
private System.Windows.Forms.TextBox txtUseSpecificScript;
|
||||
private System.Windows.Forms.CheckBox cbInteractiveServiceApp;
|
||||
private System.Windows.Forms.MenuStrip menuStrip1;
|
||||
private System.Windows.Forms.ToolStripMenuItem settingsToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem userdefinedVariablesToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem instancesToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem runAsAdministratorToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem globalSettingsToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem startCodeEditorToolStripMenuItem;
|
||||
private System.Windows.Forms.NotifyIcon notifyIcon1;
|
||||
private System.Windows.Forms.ContextMenuStrip contextMenuStrip1;
|
||||
private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem openCodeEditorToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem openLauncherToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem openCopilotToolStripMenuItem;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,62 +2,113 @@
|
|||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Security.Principal;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Linq;
|
||||
|
||||
namespace WelsonJS.Launcher
|
||||
{
|
||||
public partial class MainForm : Form
|
||||
{
|
||||
private string workingDirectory;
|
||||
private string appName;
|
||||
private readonly string entrypointFileName = "bootstrap.bat";
|
||||
private string instanceId;
|
||||
private string entryFileName;
|
||||
private string scriptName;
|
||||
|
||||
public MainForm()
|
||||
{
|
||||
entryFileName = "bootstrap.bat";
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
if (IsInAdministrator())
|
||||
{
|
||||
Text = Text + " (Administrator)";
|
||||
}
|
||||
|
||||
notifyIcon1.DoubleClick += OnShow;
|
||||
openLauncherToolStripMenuItem.Click += OnShow;
|
||||
exitToolStripMenuItem.Click += OnExit;
|
||||
}
|
||||
|
||||
protected override void OnFormClosing(FormClosingEventArgs e)
|
||||
{
|
||||
if (e.CloseReason == CloseReason.UserClosing)
|
||||
{
|
||||
e.Cancel = true;
|
||||
this.Hide();
|
||||
this.ShowInTaskbar = false;
|
||||
notifyIcon1.Visible = true;
|
||||
}
|
||||
base.OnFormClosing(e);
|
||||
}
|
||||
|
||||
private void OnShow(object sender, EventArgs e)
|
||||
{
|
||||
this.Show();
|
||||
this.WindowState = FormWindowState.Normal;
|
||||
this.ShowInTaskbar = true;
|
||||
this.Focus();
|
||||
notifyIcon1.Visible = false;
|
||||
}
|
||||
|
||||
private void OnExit(object sender, EventArgs e)
|
||||
{
|
||||
notifyIcon1.Visible = false;
|
||||
Application.Exit();
|
||||
}
|
||||
|
||||
private void EnableUI()
|
||||
{
|
||||
label1.Text = "Choose the location of WelsonJS application package.";
|
||||
button1.Enabled = true;
|
||||
button2.Enabled = true;
|
||||
checkBox1.Enabled = true;
|
||||
if (checkBox1.Checked)
|
||||
btnRunFromZipFile.Enabled = true;
|
||||
btnRunFromExternalLink.Enabled = true;
|
||||
cbUseSpecificScript.Enabled = true;
|
||||
cbInteractiveServiceApp.Enabled = true;
|
||||
if (cbUseSpecificScript.Checked)
|
||||
{
|
||||
textBox1.Enabled = true;
|
||||
txtUseSpecificScript.Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void DisableUI()
|
||||
{
|
||||
label1.Text = "Please wait...";
|
||||
button1.Enabled = false;
|
||||
button2.Enabled = false;
|
||||
checkBox1.Enabled = false;
|
||||
textBox1.Enabled = false;
|
||||
btnRunFromZipFile.Enabled = false;
|
||||
btnRunFromExternalLink.Enabled = false;
|
||||
cbUseSpecificScript.Enabled = false;
|
||||
cbInteractiveServiceApp.Enabled = false;
|
||||
txtUseSpecificScript.Enabled = false;
|
||||
}
|
||||
|
||||
private void button2_Click(object sender, EventArgs e)
|
||||
private void SafeInvoke(Action action)
|
||||
{
|
||||
ShowMessageBox("Comming soon...!");
|
||||
}
|
||||
|
||||
private void button1_Click(object sender, EventArgs e)
|
||||
{
|
||||
string filePath = OpenFileDialog();
|
||||
if (filePath != null)
|
||||
if (InvokeRequired)
|
||||
{
|
||||
string fileExtension = Path.GetExtension(filePath);
|
||||
if (fileExtension != ".zip")
|
||||
{
|
||||
ShowMessageBox("It doesn't seems to a ZIP file.");
|
||||
}
|
||||
else
|
||||
Invoke(action);
|
||||
}
|
||||
else
|
||||
{
|
||||
action();
|
||||
}
|
||||
}
|
||||
|
||||
private void btnRunFromExternalLink_Click(object sender, EventArgs e)
|
||||
{
|
||||
MessageBox.Show("Coming soon...!");
|
||||
}
|
||||
|
||||
private void btnRunFromZipFile_Click(object sender, EventArgs e)
|
||||
{
|
||||
using (var openFileDialog = new OpenFileDialog())
|
||||
{
|
||||
openFileDialog.Filter = "zip files (*.zip)|*.zip|All files (*.*)|*.*";
|
||||
openFileDialog.FilterIndex = 2;
|
||||
openFileDialog.RestoreDirectory = true;
|
||||
|
||||
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
string filePath = openFileDialog.FileName;
|
||||
ExtractAndRun(filePath);
|
||||
}
|
||||
}
|
||||
|
@ -65,9 +116,9 @@ namespace WelsonJS.Launcher
|
|||
|
||||
private void ExtractAndRun(string filePath)
|
||||
{
|
||||
appName = Path.GetFileNameWithoutExtension(filePath);
|
||||
workingDirectory = Path.Combine(Path.GetTempPath(), appName);
|
||||
scriptName = textBox1.Text;
|
||||
instanceId = Guid.NewGuid().ToString();
|
||||
workingDirectory = Program.GetWorkingDirectory(instanceId);
|
||||
scriptName = txtUseSpecificScript.Text;
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
|
@ -82,19 +133,25 @@ namespace WelsonJS.Launcher
|
|||
// try to extact ZIP file
|
||||
ZipFile.ExtractToDirectory(filePath, workingDirectory);
|
||||
|
||||
// If it is created the sub-directory
|
||||
workingDirectory = GetFinalDirectory(workingDirectory);
|
||||
// record the first deploy time
|
||||
RecordFirstDeployTime(workingDirectory);
|
||||
|
||||
// follow the sub-directory
|
||||
workingDirectory = Program.GetWorkingDirectory(instanceId, true);
|
||||
|
||||
// Run the appliction
|
||||
RunCommandPrompt();
|
||||
Program.RunCommandPrompt(workingDirectory, entryFileName, scriptName, cbUseSpecificScript.Checked, cbInteractiveServiceApp.Checked);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ShowMessageBox(ex.Message);
|
||||
SafeInvoke(() =>
|
||||
{
|
||||
MessageBox.Show("Error: " + ex.Message);
|
||||
});
|
||||
}
|
||||
|
||||
// Enable UI
|
||||
label1.Invoke((MethodInvoker)delegate {
|
||||
SafeInvoke(() => {
|
||||
EnableUI();
|
||||
});
|
||||
});
|
||||
|
@ -102,116 +159,117 @@ namespace WelsonJS.Launcher
|
|||
DisableUI();
|
||||
}
|
||||
|
||||
private void RunCommandPrompt()
|
||||
private void RecordFirstDeployTime(string directory)
|
||||
{
|
||||
bool isConsoleApplication = checkBox1.Checked;
|
||||
bool isInteractiveServiceAapplication = checkBox2.Checked;
|
||||
try
|
||||
{
|
||||
string filePath = Path.Combine(directory, ".welsonjs_first_deploy_time");
|
||||
string text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
if (!isConsoleApplication)
|
||||
{
|
||||
if (!File.Exists(Path.Combine(workingDirectory, entrypointFileName)))
|
||||
{
|
||||
throw new Exception("Not Found: " + entrypointFileName);
|
||||
}
|
||||
File.WriteAllText(filePath, text);
|
||||
}
|
||||
else
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (!Directory.EnumerateFiles(workingDirectory, scriptName + ".*").Any())
|
||||
{
|
||||
throw new Exception("Not found matches file: " + scriptName);
|
||||
}
|
||||
throw new Exception($"Failed to record first deploy time: {ex.Message}");
|
||||
}
|
||||
|
||||
Process process = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo("cmd")
|
||||
{
|
||||
UseShellExecute = false,
|
||||
RedirectStandardInput = true,
|
||||
RedirectStandardOutput = true,
|
||||
CreateNoWindow = true,
|
||||
Arguments = "/k",
|
||||
}
|
||||
};
|
||||
process.Start();
|
||||
|
||||
process.StandardInput.WriteLine("pushd " + workingDirectory);
|
||||
process.StandardInput.WriteLine();
|
||||
process.StandardInput.Flush();
|
||||
process.StandardOutput.ReadLine();
|
||||
|
||||
if (isInteractiveServiceAapplication)
|
||||
{
|
||||
process.StandardInput.WriteLine($"start cmd /c startInteractiveService.bat");
|
||||
process.StandardInput.WriteLine();
|
||||
process.StandardInput.Flush();
|
||||
process.StandardOutput.ReadLine();
|
||||
}
|
||||
else if (!isConsoleApplication)
|
||||
{
|
||||
process.StandardInput.WriteLine(entrypointFileName);
|
||||
process.StandardInput.WriteLine();
|
||||
process.StandardInput.Flush();
|
||||
process.StandardOutput.ReadLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
process.StandardInput.WriteLine($"start cmd /c cscript app.js {scriptName}");
|
||||
process.StandardInput.WriteLine();
|
||||
process.StandardInput.Flush();
|
||||
process.StandardOutput.ReadLine();
|
||||
}
|
||||
process.StandardInput.Close();
|
||||
process.WaitForExit();
|
||||
}
|
||||
|
||||
private string OpenFileDialog()
|
||||
private bool IsInAdministrator()
|
||||
{
|
||||
string filePath = null;
|
||||
|
||||
using (OpenFileDialog openFileDialog = new OpenFileDialog())
|
||||
try
|
||||
{
|
||||
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
//Get the path of specified file
|
||||
filePath = openFileDialog.FileName;
|
||||
}
|
||||
WindowsPrincipal wp = new WindowsPrincipal(WindowsIdentity.GetCurrent());
|
||||
return wp.IsInRole(WindowsBuiltInRole.Administrator);
|
||||
}
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
private void ShowMessageBox(string message)
|
||||
{
|
||||
MessageBox.Show(message);
|
||||
}
|
||||
|
||||
private string GetFinalDirectory(string path)
|
||||
{
|
||||
string[] directories = Directory.GetDirectories(path);
|
||||
|
||||
while (directories.Length == 1)
|
||||
catch
|
||||
{
|
||||
path = directories[0];
|
||||
directories = Directory.GetDirectories(path);
|
||||
return false;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
private void checkBox1_CheckedChanged(object sender, EventArgs e)
|
||||
private void cbUseSpecificScript_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
textBox1.Enabled = checkBox1.Checked;
|
||||
txtUseSpecificScript.Enabled = cbUseSpecificScript.Checked;
|
||||
}
|
||||
|
||||
private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||
{
|
||||
System.Diagnostics.Process.Start("https://github.com/gnh1201/welsonjs");
|
||||
Program.OpenWebBrowser(Program.GetAppConfig("RepositoryUrl"));
|
||||
}
|
||||
|
||||
private void userdefinedVariablesToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
(new EnvForm()).Show();
|
||||
}
|
||||
|
||||
private void instancesToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
(new InstancesForm()).Show();
|
||||
}
|
||||
|
||||
private void runAsAdministratorToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!IsInAdministrator())
|
||||
{
|
||||
ProcessStartInfo procInfo = new ProcessStartInfo
|
||||
{
|
||||
UseShellExecute = true,
|
||||
FileName = Application.ExecutablePath,
|
||||
WorkingDirectory = Environment.CurrentDirectory,
|
||||
Verb = "runas"
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
Process.Start(procInfo);
|
||||
Application.Exit();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show("Failed to run as administrator: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("Already running as Administrator.");
|
||||
}
|
||||
}
|
||||
|
||||
private void globalSettingsToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
(new GlobalSettingsForm()).Show();
|
||||
}
|
||||
|
||||
private void startCodeEditorToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Program.StartResourceServer();
|
||||
|
||||
if (!Program.resourceServer.IsRunning())
|
||||
{
|
||||
Program.resourceServer.Start();
|
||||
((ToolStripMenuItem)sender).Text = "Open the code editor...";
|
||||
}
|
||||
else
|
||||
{
|
||||
Program.OpenWebBrowser(Program.resourceServer.GetPrefix());
|
||||
}
|
||||
}
|
||||
|
||||
private void openCodeEditorToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (Program.resourceServer == null)
|
||||
{
|
||||
MessageBox.Show("A resource server is not running.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Program.OpenWebBrowser(Program.resourceServer.GetPrefix());
|
||||
}
|
||||
}
|
||||
|
||||
private void openCopilotToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Program.OpenWebBrowser(Program.GetAppConfig("CopilotUrl"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -120,4 +120,10 @@
|
|||
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="notifyIcon1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>134, 17</value>
|
||||
</metadata>
|
||||
<metadata name="contextMenuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>249, 17</value>
|
||||
</metadata>
|
||||
</root>
|
|
@ -1,20 +1,191 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using System.Configuration;
|
||||
|
||||
namespace WelsonJS.Launcher
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
/// <summary>
|
||||
/// 해당 애플리케이션의 주 진입점입니다.
|
||||
/// </summary>
|
||||
static Mutex mutex;
|
||||
public static ResourceServer resourceServer;
|
||||
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
mutex = new Mutex(true, "WelsonJS.Launcher.Mutex", out bool isMutexNotExists);
|
||||
if (!isMutexNotExists)
|
||||
{
|
||||
MessageBox.Show("WelsonJS Launcher already running.");
|
||||
return;
|
||||
}
|
||||
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
Application.Run(new MainForm());
|
||||
|
||||
mutex.ReleaseMutex();
|
||||
mutex.Dispose();
|
||||
}
|
||||
|
||||
public static void RunCommandPrompt(string workingDirectory, string entryFileName, string scriptName, bool isConsoleApplication = false, bool isInteractiveServiceAapplication = false)
|
||||
{
|
||||
if (!isConsoleApplication)
|
||||
{
|
||||
if (!File.Exists(Path.Combine(workingDirectory, entryFileName)))
|
||||
{
|
||||
throw new Exception("Not Found: " + entryFileName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Directory.EnumerateFiles(workingDirectory, scriptName + ".*").Any())
|
||||
{
|
||||
throw new Exception("Not found matches file: " + scriptName);
|
||||
}
|
||||
}
|
||||
|
||||
Process process = new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo("cmd")
|
||||
{
|
||||
UseShellExecute = false,
|
||||
RedirectStandardInput = true,
|
||||
RedirectStandardOutput = true,
|
||||
CreateNoWindow = true,
|
||||
Arguments = "/k",
|
||||
}
|
||||
};
|
||||
process.Start();
|
||||
|
||||
process.StandardInput.WriteLine("pushd " + workingDirectory);
|
||||
process.StandardInput.WriteLine();
|
||||
process.StandardInput.Flush();
|
||||
process.StandardOutput.ReadLine();
|
||||
|
||||
if (isInteractiveServiceAapplication)
|
||||
{
|
||||
process.StandardInput.WriteLine($"start cmd /c startInteractiveService.bat");
|
||||
process.StandardInput.WriteLine();
|
||||
process.StandardInput.Flush();
|
||||
process.StandardOutput.ReadLine();
|
||||
}
|
||||
else if (!isConsoleApplication)
|
||||
{
|
||||
process.StandardInput.WriteLine(entryFileName);
|
||||
process.StandardInput.WriteLine();
|
||||
process.StandardInput.Flush();
|
||||
process.StandardOutput.ReadLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
process.StandardInput.WriteLine($"start cmd /c cscript app.js {scriptName}");
|
||||
process.StandardInput.WriteLine();
|
||||
process.StandardInput.Flush();
|
||||
process.StandardOutput.ReadLine();
|
||||
}
|
||||
process.StandardInput.Close();
|
||||
process.WaitForExit();
|
||||
}
|
||||
|
||||
public static string GetFinalDirectory(string path)
|
||||
{
|
||||
string[] directories = Directory.GetDirectories(path);
|
||||
|
||||
while (directories.Length == 1)
|
||||
{
|
||||
path = directories[0];
|
||||
directories = Directory.GetDirectories(path);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
public static string GetAppDataPath()
|
||||
{
|
||||
string path = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
"WelsonJS"
|
||||
);
|
||||
|
||||
Directory.CreateDirectory(path);
|
||||
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
throw new IOException("Failed to create directory: " + path);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
public static string GetWorkingDirectory(string instanceId, bool followSubDirectory = false)
|
||||
{
|
||||
string workingDirectory = Path.Combine(GetAppDataPath(), instanceId);
|
||||
|
||||
if (followSubDirectory)
|
||||
{
|
||||
if (!Directory.Exists(workingDirectory))
|
||||
{
|
||||
workingDirectory = Path.Combine(Path.GetTempPath(), instanceId);
|
||||
}
|
||||
|
||||
workingDirectory = GetFinalDirectory(workingDirectory);
|
||||
}
|
||||
|
||||
return workingDirectory;
|
||||
}
|
||||
|
||||
public static void StartResourceServer()
|
||||
{
|
||||
lock(typeof(Program))
|
||||
{
|
||||
if (resourceServer == null)
|
||||
{
|
||||
resourceServer = new ResourceServer(GetAppConfig("ResourceServerPrefix"), "editor.html");
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void OpenWebBrowser(string url)
|
||||
{
|
||||
Uri resourceServerUri = new Uri(GetAppConfig("ResourceServerPrefix"));
|
||||
Uri devToolsUri = new Uri(GetAppConfig("DevToolsPrefix"));
|
||||
|
||||
string userDataDir = Path.Combine(GetAppDataPath(), "EdgeUserProfile");
|
||||
string remoteAllowOrigins = $"{resourceServerUri.Scheme}://{resourceServerUri.Host}:{resourceServerUri.Port}";
|
||||
int remoteDebuggingPort = devToolsUri.Port;
|
||||
string[] arguments = {
|
||||
$"\"{url}\"",
|
||||
$"--remote-debugging-port={remoteDebuggingPort}",
|
||||
$"--remote-allow-origins={remoteAllowOrigins}", // for security reason
|
||||
$"--user-data-dir=\"{userDataDir}\""
|
||||
};
|
||||
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "msedge.exe",
|
||||
Arguments = string.Join(" ", arguments),
|
||||
UseShellExecute = true
|
||||
});
|
||||
}
|
||||
|
||||
public static string GetAppConfig(string key)
|
||||
{
|
||||
string value = ConfigurationManager.AppSettings[key];
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
value = Properties.Resources.ResourceManager.GetString(key);
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,11 +6,11 @@ using System.Runtime.InteropServices;
|
|||
// 제어됩니다. 어셈블리와 관련된 정보를 수정하려면
|
||||
// 이러한 특성 값을 변경하세요.
|
||||
[assembly: AssemblyTitle("WelsonJS.Launcher")]
|
||||
[assembly: AssemblyDescription("Launcher for WelsonJS Application Package")]
|
||||
[assembly: AssemblyDescription("Launcher for WelsonJS Application Packages")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Catswords")]
|
||||
[assembly: AssemblyProduct("WelsonJS")]
|
||||
[assembly: AssemblyCopyright("Catswords OSS, C-2021-000237, Opensource licensed under GPLv3 or MS-RL")]
|
||||
[assembly: AssemblyCopyright("Catswords OSS, GPLv3 or Ms-RL")]
|
||||
[assembly: AssemblyTrademark("WelsonJS")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
|
@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
|||
// 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호를
|
||||
// 기본값으로 할 수 있습니다.
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("0.2.7.31")]
|
||||
[assembly: AssemblyFileVersion("0.2.7.31")]
|
||||
[assembly: AssemblyVersion("0.2.7.54")]
|
||||
[assembly: AssemblyFileVersion("0.2.7.54")]
|
||||
|
|
|
@ -60,6 +60,105 @@ namespace WelsonJS.Launcher.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://ajax.aspnetcdn.com/과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string AspNetCdnPrefix {
|
||||
get {
|
||||
return ResourceManager.GetString("AspNetCdnPrefix", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string AzureAiServiceApiKey {
|
||||
get {
|
||||
return ResourceManager.GetString("AzureAiServiceApiKey", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 2024-05-01-preview과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string AzureAiServiceApiVersion {
|
||||
get {
|
||||
return ResourceManager.GetString("AzureAiServiceApiVersion", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://ai-catswords656881030318.services.ai.azure.com/과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string AzureAiServicePrefix {
|
||||
get {
|
||||
return ResourceManager.GetString("AzureAiServicePrefix", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://catswords.blob.core.windows.net/welsonjs/과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string BlobStoragePrefix {
|
||||
get {
|
||||
return ResourceManager.GetString("BlobStoragePrefix", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://cdnjs.cloudflare.com/과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string CdnJsPrefix {
|
||||
get {
|
||||
return ResourceManager.GetString("CdnJsPrefix", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://copilot.microsoft.com/과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string CopilotUrl {
|
||||
get {
|
||||
return ResourceManager.GetString("CopilotUrl", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// http://localhost:9222/과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string DevToolsPrefix {
|
||||
get {
|
||||
return ResourceManager.GetString("DevToolsPrefix", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 1.1.1.1과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string DnsServerAddress {
|
||||
get {
|
||||
return ResourceManager.GetString("DnsServerAddress", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://esm.run/과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string EsmRunPrefix {
|
||||
get {
|
||||
return ResourceManager.GetString("EsmRunPrefix", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://esm.sh/과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string EsmShPrefix {
|
||||
get {
|
||||
return ResourceManager.GetString("EsmShPrefix", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// (아이콘)과(와) 유사한 System.Drawing.Icon 형식의 지역화된 리소스를 찾습니다.
|
||||
/// </summary>
|
||||
|
@ -70,6 +169,15 @@ namespace WelsonJS.Launcher.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://ajax.googleapis.com/과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string GoogleApisPrefix {
|
||||
get {
|
||||
return ResourceManager.GetString("GoogleApisPrefix", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// System.Drawing.Bitmap 형식의 지역화된 리소스를 찾습니다.
|
||||
/// </summary>
|
||||
|
@ -80,6 +188,16 @@ namespace WelsonJS.Launcher.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// System.Drawing.Bitmap 형식의 지역화된 리소스를 찾습니다.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap icon_delete_32 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("icon_delete_32", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// System.Drawing.Bitmap 형식의 지역화된 리소스를 찾습니다.
|
||||
/// </summary>
|
||||
|
@ -130,6 +248,16 @@ namespace WelsonJS.Launcher.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// System.Drawing.Bitmap 형식의 지역화된 리소스를 찾습니다.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap icon_start_32 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("icon_start_32", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// System.Drawing.Bitmap 형식의 지역화된 리소스를 찾습니다.
|
||||
/// </summary>
|
||||
|
@ -139,5 +267,104 @@ namespace WelsonJS.Launcher.Properties {
|
|||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://code.jquery.com/과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string JqueryCdnPrefix {
|
||||
get {
|
||||
return ResourceManager.GetString("JqueryCdnPrefix", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://cdn.jsdelivr.net/과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string JsDeliverPrefix {
|
||||
get {
|
||||
return ResourceManager.GetString("JsDeliverPrefix", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://polyfill-fastly.io/과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string PolyfillPrefix {
|
||||
get {
|
||||
return ResourceManager.GetString("PolyfillPrefix", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://raw.githubusercontent.com/과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string RawGitHubPrefix {
|
||||
get {
|
||||
return ResourceManager.GetString("RawGitHubPrefix", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://github.com/gnh1201/welsonjs과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string RepositoryUrl {
|
||||
get {
|
||||
return ResourceManager.GetString("RepositoryUrl", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// http://localhost:3000/과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string ResourceServerPrefix {
|
||||
get {
|
||||
return ResourceManager.GetString("ResourceServerPrefix", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://www.skypack.dev/과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string SkypackPrefix {
|
||||
get {
|
||||
return ResourceManager.GetString("SkypackPrefix", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://unpkg.com/과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string UnpkgPrefix {
|
||||
get {
|
||||
return ResourceManager.GetString("UnpkgPrefix", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 141.101.82.1과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string WhoisClientAddress {
|
||||
get {
|
||||
return ResourceManager.GetString("WhoisClientAddress", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois/whois.jsp과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string WhoisReferrerUrl {
|
||||
get {
|
||||
return ResourceManager.GetString("WhoisReferrerUrl", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois.jsc과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string WhoisServerUrl {
|
||||
get {
|
||||
return ResourceManager.GetString("WhoisServerUrl", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -142,4 +142,79 @@
|
|||
<data name="icon_import_32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\icon_import_32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="icon_delete_32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\icon_delete_32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="icon_start_32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\icon_start_32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="CopilotUrl" xml:space="preserve">
|
||||
<value>https://copilot.microsoft.com/</value>
|
||||
</data>
|
||||
<data name="RepositoryUrl" xml:space="preserve">
|
||||
<value>https://github.com/gnh1201/welsonjs</value>
|
||||
</data>
|
||||
<data name="ResourceServerPrefix" xml:space="preserve">
|
||||
<value>http://localhost:3000/</value>
|
||||
</data>
|
||||
<data name="DevToolsPrefix" xml:space="preserve">
|
||||
<value>http://localhost:9222/</value>
|
||||
</data>
|
||||
<data name="AzureAiServiceApiKey" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="AzureAiServicePrefix" xml:space="preserve">
|
||||
<value>https://ai-catswords656881030318.services.ai.azure.com/</value>
|
||||
</data>
|
||||
<data name="DnsServerAddress" xml:space="preserve">
|
||||
<value>1.1.1.1</value>
|
||||
</data>
|
||||
<data name="WhoisClientAddress" xml:space="preserve">
|
||||
<value>141.101.82.1</value>
|
||||
</data>
|
||||
<data name="WhoisReferrerUrl" xml:space="preserve">
|
||||
<value>https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois/whois.jsp</value>
|
||||
</data>
|
||||
<data name="WhoisServerUrl" xml:space="preserve">
|
||||
<value>https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois.jsc</value>
|
||||
</data>
|
||||
<data name="BlobStoragePrefix" xml:space="preserve">
|
||||
<value>https://catswords.blob.core.windows.net/welsonjs/</value>
|
||||
</data>
|
||||
<data name="AzureAiServiceApiVersion" xml:space="preserve">
|
||||
<value>2024-05-01-preview</value>
|
||||
</data>
|
||||
<data name="CdnJsPrefix" xml:space="preserve">
|
||||
<value>https://cdnjs.cloudflare.com/</value>
|
||||
</data>
|
||||
<data name="EsmRunPrefix" xml:space="preserve">
|
||||
<value>https://esm.run/</value>
|
||||
</data>
|
||||
<data name="EsmShPrefix" xml:space="preserve">
|
||||
<value>https://esm.sh/</value>
|
||||
</data>
|
||||
<data name="JqueryCdnPrefix" xml:space="preserve">
|
||||
<value>https://code.jquery.com/</value>
|
||||
</data>
|
||||
<data name="JsDeliverPrefix" xml:space="preserve">
|
||||
<value>https://cdn.jsdelivr.net/</value>
|
||||
</data>
|
||||
<data name="SkypackPrefix" xml:space="preserve">
|
||||
<value>https://www.skypack.dev/</value>
|
||||
</data>
|
||||
<data name="UnpkgPrefix" xml:space="preserve">
|
||||
<value>https://unpkg.com/</value>
|
||||
</data>
|
||||
<data name="AspNetCdnPrefix" xml:space="preserve">
|
||||
<value>https://ajax.aspnetcdn.com/</value>
|
||||
</data>
|
||||
<data name="GoogleApisPrefix" xml:space="preserve">
|
||||
<value>https://ajax.googleapis.com/</value>
|
||||
</data>
|
||||
<data name="PolyfillPrefix" xml:space="preserve">
|
||||
<value>https://polyfill-fastly.io/</value>
|
||||
</data>
|
||||
<data name="RawGitHubPrefix" xml:space="preserve">
|
||||
<value>https://raw.githubusercontent.com/</value>
|
||||
</data>
|
||||
</root>
|
446
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceServer.cs
Normal file
446
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceServer.cs
Normal file
|
@ -0,0 +1,446 @@
|
|||
// ResourceServer.cs
|
||||
// A resource server of WelsonJS Editor (WelsonJS.Launcher)
|
||||
// Namhyeon Go <abuse@catswords.net>
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace WelsonJS.Launcher
|
||||
{
|
||||
public class ResourceServer
|
||||
{
|
||||
private readonly HttpListener _listener;
|
||||
private CancellationTokenSource _cts;
|
||||
private Task _serverTask;
|
||||
private bool _isRunning;
|
||||
private string _prefix;
|
||||
private string _resourceName;
|
||||
private List<IResourceTool> _tools = new List<IResourceTool>();
|
||||
private readonly HttpClient _httpClient = new HttpClient();
|
||||
private static readonly string _defaultMimeType = "application/octet-stream";
|
||||
private static readonly Regex _nodePackageRegex = new Regex(@"^[^/@]+@[^/]+/", RegexOptions.Compiled);
|
||||
private static readonly List<string[]> CDN_PREFIXES = new List<string[]> {
|
||||
new[] { "ajax/libs/" },
|
||||
new[] { "npm/", "gh/", "wp/" },
|
||||
new[] { "jquery/" },
|
||||
new[] { "polyfill/" },
|
||||
new[] { "ajax/" }, // https://learn.microsoft.com/en-us/aspnet/ajax/cdn/overview
|
||||
new[] { "raw/gh/"}
|
||||
};
|
||||
private enum CDN_TYPES: int
|
||||
{
|
||||
Cloudflare = 0,
|
||||
JsDeliver = 1,
|
||||
Jquery = 2,
|
||||
Polyfill = 3,
|
||||
Microsoft = 4,
|
||||
GitHub = 5
|
||||
};
|
||||
|
||||
public ResourceServer(string prefix, string resourceName)
|
||||
{
|
||||
_prefix = prefix;
|
||||
_listener = new HttpListener();
|
||||
_listener.Prefixes.Add(prefix);
|
||||
_resourceName = resourceName;
|
||||
_httpClient.Timeout = TimeSpan.FromSeconds(30);
|
||||
|
||||
// Add resource tools
|
||||
_tools.Add(new ResourceTools.Completion(this, _httpClient));
|
||||
_tools.Add(new ResourceTools.Settings(this, _httpClient));
|
||||
_tools.Add(new ResourceTools.DevTools(this, _httpClient));
|
||||
_tools.Add(new ResourceTools.DnsQuery(this, _httpClient));
|
||||
_tools.Add(new ResourceTools.Tfa(this, _httpClient));
|
||||
_tools.Add(new ResourceTools.Whois(this, _httpClient));
|
||||
}
|
||||
|
||||
public string GetPrefix()
|
||||
{
|
||||
return _prefix;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (_isRunning) return;
|
||||
|
||||
_isRunning = true;
|
||||
_cts = new CancellationTokenSource();
|
||||
_listener.Start();
|
||||
|
||||
// Open the web browser
|
||||
Program.OpenWebBrowser(_prefix);
|
||||
|
||||
// Run a task with cancellation token
|
||||
_serverTask = Task.Run(() => ListenLoop(_cts.Token));
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
_isRunning = false;
|
||||
_cts.Cancel();
|
||||
_listener.Stop();
|
||||
|
||||
MessageBox.Show("Server stopped.");
|
||||
}
|
||||
|
||||
public bool IsRunning()
|
||||
{
|
||||
return _isRunning;
|
||||
}
|
||||
|
||||
private async Task ListenLoop(CancellationToken token)
|
||||
{
|
||||
while (!token.IsCancellationRequested && _isRunning)
|
||||
{
|
||||
try
|
||||
{
|
||||
await ProcessRequest(await _listener.GetContextAsync());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (token.IsCancellationRequested || !_isRunning) break;
|
||||
MessageBox.Show($"Error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ProcessRequest(HttpListenerContext context)
|
||||
{
|
||||
string path = context.Request.Url.AbsolutePath.TrimStart('/');
|
||||
|
||||
// Serve from a resource name
|
||||
if (String.IsNullOrEmpty(path))
|
||||
{
|
||||
ServeResource(context, GetResource(_resourceName), "text/html");
|
||||
return;
|
||||
}
|
||||
|
||||
// Serve the favicon.ico file
|
||||
if ("favicon.ico".Equals(path, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
ServeResource(context, GetResource("favicon"), "image/x-icon");
|
||||
return;
|
||||
}
|
||||
|
||||
// Serve from a resource tool
|
||||
foreach (var tool in _tools)
|
||||
{
|
||||
if (tool.CanHandle(path))
|
||||
{
|
||||
await tool.HandleAsync(context, path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Serve from the blob server
|
||||
if (await ServeBlob(context, path)) return;
|
||||
|
||||
// Fallback to serve from a resource name
|
||||
ServeResource(context, GetResource(_resourceName), "text/html");
|
||||
}
|
||||
|
||||
private async Task<bool> ServeBlob(HttpListenerContext context, string path, string prefix = null)
|
||||
{
|
||||
byte[] data;
|
||||
string mimeType;
|
||||
|
||||
if (!String.IsNullOrEmpty(prefix))
|
||||
{
|
||||
string url = $"{prefix}{path}";
|
||||
|
||||
try
|
||||
{
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
|
||||
request.Headers.UserAgent.ParseAdd(context.Request.UserAgent);
|
||||
HttpResponseMessage response = await client.SendAsync(request);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
Trace.TraceError($"Failed to serve blob. URL: {url}, Status: {response.StatusCode}");
|
||||
return false;
|
||||
}
|
||||
|
||||
data = await response.Content.ReadAsByteArrayAsync();
|
||||
mimeType = response.Content.Headers.ContentType?.MediaType ?? _defaultMimeType;
|
||||
|
||||
ServeResource(context, data, mimeType);
|
||||
_ = TrySaveCachedBlob(path, data, mimeType);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Trace.TraceError($"Failed to serve blob. URL: {url}, Exception: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// use the cached data
|
||||
if (TryGetCachedBlob(path, out mimeType, true))
|
||||
{
|
||||
if (TryGetCachedBlob(path, out data))
|
||||
{
|
||||
if (String.IsNullOrEmpty(mimeType))
|
||||
{
|
||||
mimeType = _defaultMimeType;
|
||||
}
|
||||
|
||||
ServeResource(context, data, mimeType);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// use CDN sources
|
||||
if (await TryServeFromCdn(context, path))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task<bool> TryServeFromCdn(HttpListenerContext context, string path)
|
||||
{
|
||||
bool isNodePackageExpression = _nodePackageRegex.IsMatch(path);
|
||||
bool isPrefixMatched(CDN_TYPES type)
|
||||
{
|
||||
if (CDN_PREFIXES[(int)type].Any(prefix => path.StartsWith(prefix)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
var sources = new (bool isMatch, string configKey, Func<string, string> transform)[]
|
||||
{
|
||||
(isPrefixMatched(CDN_TYPES.Cloudflare), "CdnJsPrefix", p => p), // Libraries from Cloudflare
|
||||
(isPrefixMatched(CDN_TYPES.Cloudflare), "GoogleApisPrefix", p => p), // Libraries from Google
|
||||
(isNodePackageExpression, "UnpkgPrefix", p => p),
|
||||
(isNodePackageExpression, "SkypackPrefix", p => p),
|
||||
(isNodePackageExpression, "EsmShPrefix", p => p),
|
||||
(isNodePackageExpression, "EsmRunPrefix", p => p),
|
||||
(isPrefixMatched(CDN_TYPES.JsDeliver), "JsDeliverPrefix", p => p),
|
||||
(isPrefixMatched(CDN_TYPES.Jquery), "JqueryCdnPrefix", p => p.Substring("jquery/".Length)),
|
||||
(isPrefixMatched(CDN_TYPES.Polyfill), "CdnJsPrefix", p => p), // polyfill.js from Cloudflare
|
||||
(isPrefixMatched(CDN_TYPES.Polyfill), "PolyfillPrefix", p => p.Substring("polyfill/".Length)), // polyfill.js from Fastly
|
||||
(isPrefixMatched(CDN_TYPES.Microsoft), "AspNetCdnPrefix", p => p), // Libraries from Microsoft
|
||||
(isPrefixMatched(CDN_TYPES.GitHub), "RawGitHubPrefix", p => p.Substring("raw/gh/".Length)),
|
||||
(true, "BlobStoragePrefix", p => p) // fallback
|
||||
};
|
||||
|
||||
foreach (var (isMatch, configKey, transform) in sources)
|
||||
{
|
||||
if (isMatch)
|
||||
{
|
||||
string prefix = Program.GetAppConfig(configKey);
|
||||
if (await ServeBlob(context, transform(path), prefix))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private string GetCachedBlobPath(string path)
|
||||
{
|
||||
// Get a hash from the path
|
||||
string hashedPath;
|
||||
using (MD5 md5 = MD5.Create())
|
||||
{
|
||||
byte[] bHashedPath = md5.ComputeHash(Encoding.UTF8.GetBytes(path));
|
||||
hashedPath = BitConverter.ToString(bHashedPath).Replace("-", "").ToLowerInvariant();
|
||||
}
|
||||
|
||||
// Get a sub-directory paths from the hashed path
|
||||
string[] subDirectoryPaths = new string[] {
|
||||
hashedPath.Substring(0, 2),
|
||||
hashedPath.Substring(2, 2),
|
||||
hashedPath.Substring(4, 2)
|
||||
};
|
||||
|
||||
// Return the cache path
|
||||
return Path.Combine(Program.GetAppDataPath(), "BlobCache", String.Join("\\", subDirectoryPaths), hashedPath);
|
||||
}
|
||||
|
||||
private bool TryGetCachedBlob(string path, out byte[] data, bool isMetadata = false)
|
||||
{
|
||||
string cachePath = GetCachedBlobPath(path);
|
||||
if (isMetadata)
|
||||
{
|
||||
cachePath = $"{cachePath}.meta";
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (File.Exists(cachePath))
|
||||
{
|
||||
data = File.ReadAllBytes(cachePath);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Trace.TraceError($"Cache Read Error: {ex.Message}");
|
||||
}
|
||||
|
||||
data = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryGetCachedBlob(string path, out string data, bool isMetadata = false)
|
||||
{
|
||||
byte[] bData;
|
||||
if (TryGetCachedBlob(path, out bData, isMetadata))
|
||||
{
|
||||
data = Encoding.UTF8.GetString(bData);
|
||||
return true;
|
||||
}
|
||||
|
||||
data = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task<bool> TrySaveCachedBlob(string path, byte[] data, string mimeType)
|
||||
{
|
||||
await Task.Delay(0);
|
||||
|
||||
try
|
||||
{
|
||||
string cachePath = GetCachedBlobPath(path);
|
||||
string cacheDirectory = Path.GetDirectoryName(cachePath);
|
||||
|
||||
// Is exists the cached blob directory
|
||||
if (!Directory.Exists(cacheDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(cacheDirectory);
|
||||
}
|
||||
|
||||
// Save the cache
|
||||
File.WriteAllBytes(cachePath, data);
|
||||
|
||||
// Save the cache meta
|
||||
File.WriteAllBytes($"{cachePath}.meta", Encoding.UTF8.GetBytes(mimeType));
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Trace.TraceError($"Error: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void ServeResource(HttpListenerContext context)
|
||||
{
|
||||
ServeResource(context, "<error>Not Found</error>", "application/xml", 404);
|
||||
}
|
||||
|
||||
public void ServeResource(HttpListenerContext context, byte[] data, string mimeType = "text/html", int statusCode = 200)
|
||||
{
|
||||
string xmlHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
|
||||
|
||||
if (data == null) {
|
||||
data = Encoding.UTF8.GetBytes(xmlHeader + "\r\n<error>Could not find the resource.</error>");
|
||||
mimeType = "application/xml";
|
||||
statusCode = 404;
|
||||
}
|
||||
|
||||
context.Response.StatusCode = statusCode;
|
||||
context.Response.ContentType = mimeType;
|
||||
context.Response.ContentLength64 = data.Length;
|
||||
using (Stream outputStream = context.Response.OutputStream)
|
||||
{
|
||||
outputStream.Write(data, 0, data.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public void ServeResource(HttpListenerContext context, string data, string mimeType = "text/html", int statusCode = 200)
|
||||
{
|
||||
string xmlHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
|
||||
|
||||
if (data == null)
|
||||
{
|
||||
data = xmlHeader + "\r\n<error>Could not find the resource.</error>";
|
||||
mimeType = "application/xml";
|
||||
statusCode = 404;
|
||||
}
|
||||
else if (mimeType == "application/xml" && !data.StartsWith("<?xml"))
|
||||
{
|
||||
data = xmlHeader + "\r\n" + data;
|
||||
}
|
||||
|
||||
ServeResource(context, Encoding.UTF8.GetBytes(data), mimeType, statusCode);
|
||||
}
|
||||
|
||||
private byte[] GetResource(string resourceName)
|
||||
{
|
||||
// Try to fetch embedded resource.
|
||||
byte[] data = GetEmbeddedResource(typeof(Program).Namespace + "." + resourceName);
|
||||
if (data != null) return data;
|
||||
|
||||
// Fallback: Try to fetch resource from ResourceManager.
|
||||
return GetResourceFromManager(resourceName);
|
||||
}
|
||||
|
||||
private byte[] GetEmbeddedResource(string fullResourceName)
|
||||
{
|
||||
Assembly assembly = Assembly.GetExecutingAssembly();
|
||||
using (Stream stream = assembly.GetManifestResourceStream(fullResourceName))
|
||||
{
|
||||
if (stream != null)
|
||||
{
|
||||
using (MemoryStream memoryStream = new MemoryStream())
|
||||
{
|
||||
stream.CopyTo(memoryStream);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private byte[] GetResourceFromManager(string resourceName)
|
||||
{
|
||||
object resourceObject = Properties.Resources.ResourceManager.GetObject(resourceName);
|
||||
switch (resourceObject)
|
||||
{
|
||||
case byte[] resourceBytes:
|
||||
return resourceBytes;
|
||||
case System.Drawing.Icon icon:
|
||||
return ConvertIconToBytes(icon);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] ConvertIconToBytes(System.Drawing.Icon icon)
|
||||
{
|
||||
using (MemoryStream memoryStream = new MemoryStream())
|
||||
{
|
||||
icon.Save(memoryStream);
|
||||
return memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
214
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Completion.cs
Normal file
214
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Completion.cs
Normal file
|
@ -0,0 +1,214 @@
|
|||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace WelsonJS.Launcher.ResourceTools
|
||||
{
|
||||
public class Completion : IResourceTool
|
||||
{
|
||||
private readonly ResourceServer Server;
|
||||
private readonly HttpClient _httpClient;
|
||||
private const string Prefix = "completion/";
|
||||
private List<string> Executables = new List<string>();
|
||||
|
||||
public Completion(ResourceServer server, HttpClient httpClient)
|
||||
{
|
||||
Server = server;
|
||||
_httpClient = httpClient;
|
||||
|
||||
new Task(() =>
|
||||
{
|
||||
Executables.AddRange(GetInstalledSoftwareExecutables());
|
||||
Executables.AddRange(GetExecutablesFromPath());
|
||||
Executables.AddRange(GetExecutablesFromNetFx());
|
||||
}).Start();
|
||||
}
|
||||
|
||||
public bool CanHandle(string path)
|
||||
{
|
||||
return path.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public async Task HandleAsync(HttpListenerContext context, string path)
|
||||
{
|
||||
await Task.Delay(0);
|
||||
|
||||
string word = path.Substring(Prefix.Length);
|
||||
|
||||
try
|
||||
{
|
||||
CompletionItem[] completionItems = Executables
|
||||
.Where(exec => exec.IndexOf(word, 0, StringComparison.OrdinalIgnoreCase) > -1)
|
||||
.Take(100) // Limit the number of results
|
||||
.Select(exec => new CompletionItem
|
||||
{
|
||||
Label = Path.GetFileName(exec),
|
||||
Kind = "Text",
|
||||
Documentation = $"An executable file: {exec}",
|
||||
InsertText = exec
|
||||
})
|
||||
.ToArray();
|
||||
|
||||
XElement response = new XElement("suggestions",
|
||||
completionItems.Select(item => new XElement("item",
|
||||
new XElement("label", item.Label),
|
||||
new XElement("kind", item.Kind),
|
||||
new XElement("documentation", item.Documentation),
|
||||
new XElement("insertText", item.InsertText)
|
||||
))
|
||||
);
|
||||
|
||||
Server.ServeResource(context, response.ToString(), "application/xml");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Server.ServeResource(context, $"<error>Failed to process completion request. {ex.Message}</error>", "application/xml", 500);
|
||||
}
|
||||
}
|
||||
|
||||
private List<string> GetInstalledSoftwareExecutables()
|
||||
{
|
||||
List<string> executables = new List<string>();
|
||||
string registryKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
|
||||
|
||||
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(registryKey))
|
||||
{
|
||||
if (key != null)
|
||||
{
|
||||
foreach (string subKeyName in key.GetSubKeyNames())
|
||||
{
|
||||
using (RegistryKey subKey = key.OpenSubKey(subKeyName))
|
||||
{
|
||||
string installLocation = subKey?.GetValue("InstallLocation") as string;
|
||||
string uninstallString = subKey?.GetValue("UninstallString") as string;
|
||||
|
||||
List<string> executablePaths = FindExecutables(installLocation, uninstallString);
|
||||
executables.AddRange(executablePaths);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return executables;
|
||||
}
|
||||
|
||||
private List<string> FindExecutables(string installLocation, string uninstallString)
|
||||
{
|
||||
List<string> executables = new List<string>();
|
||||
|
||||
if (!string.IsNullOrEmpty(installLocation) && Directory.Exists(installLocation))
|
||||
{
|
||||
try
|
||||
{
|
||||
List<string> executableFiles = Directory.GetFiles(installLocation, "*.exe", SearchOption.AllDirectories)
|
||||
.OrderByDescending(f => new FileInfo(f).Length)
|
||||
.ToList();
|
||||
executables.AddRange(executableFiles);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"Error enumerating executables in '{installLocation}': {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(uninstallString))
|
||||
{
|
||||
if (TryParseExecutablePath(uninstallString, out string executablePath))
|
||||
{
|
||||
executables.Add(executablePath);
|
||||
}
|
||||
}
|
||||
|
||||
return executables;
|
||||
}
|
||||
|
||||
private static bool TryParseExecutablePath(string s, out string path)
|
||||
{
|
||||
Match match = Regex.Match(s, @"(?<=""|^)([a-zA-Z]:\\[^""]+\.exe)", RegexOptions.IgnoreCase);
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
path = match.Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
path = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private List<string> GetExecutablesFromPath()
|
||||
{
|
||||
List<string> executables = new List<string>();
|
||||
string[] paths = Environment.GetEnvironmentVariable("PATH")?.Split(';');
|
||||
|
||||
if (paths != null)
|
||||
{
|
||||
foreach (string path in paths)
|
||||
{
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
try
|
||||
{
|
||||
executables.AddRange(Directory.GetFiles(path, "*.exe", SearchOption.TopDirectoryOnly));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"Error enumerating executables in '{path}': {ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return executables;
|
||||
}
|
||||
|
||||
private List<string> GetExecutablesFromNetFx()
|
||||
{
|
||||
List<string> executables = new List<string>();
|
||||
|
||||
string windir = Environment.GetEnvironmentVariable("WINDIR");
|
||||
|
||||
if (!string.IsNullOrEmpty(windir))
|
||||
{
|
||||
string[] paths = new string[]
|
||||
{
|
||||
Path.Combine(windir, "Microsoft.NET", "Framework"),
|
||||
Path.Combine(windir, "Microsoft.NET", "Framework64")
|
||||
};
|
||||
|
||||
foreach (string path in paths)
|
||||
{
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
try
|
||||
{
|
||||
executables.AddRange(Directory.GetFiles(path, "*.exe", SearchOption.AllDirectories));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"Error enumerating executables in '{path}': {ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return executables;
|
||||
}
|
||||
}
|
||||
|
||||
public class CompletionItem
|
||||
{
|
||||
public string Label { get; set; }
|
||||
public string Kind { get; set; }
|
||||
public string Documentation { get; set; }
|
||||
public string InsertText { get; set; }
|
||||
}
|
||||
}
|
42
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/DevTools.cs
Normal file
42
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/DevTools.cs
Normal file
|
@ -0,0 +1,42 @@
|
|||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WelsonJS.Launcher.ResourceTools
|
||||
{
|
||||
public class DevTools : IResourceTool
|
||||
{
|
||||
private ResourceServer Server;
|
||||
private readonly HttpClient _httpClient;
|
||||
private const string Prefix = "devtools/";
|
||||
|
||||
public DevTools(ResourceServer server, HttpClient httpClient)
|
||||
{
|
||||
Server = server;
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
public bool CanHandle(string path)
|
||||
{
|
||||
return path.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public async Task HandleAsync(HttpListenerContext context, string path)
|
||||
{
|
||||
string endpoint = path.Substring(Prefix.Length);
|
||||
|
||||
try
|
||||
{
|
||||
string url = Program.GetAppConfig("DevToolsPrefix") + endpoint;
|
||||
string data = await _httpClient.GetStringAsync(url);
|
||||
|
||||
Server.ServeResource(context, data, "application/json");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Server.ServeResource(context, $"<error>Failed to process DevTools request. {ex.Message}</error>", "application/xml", 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
343
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/DnsQuery.cs
Normal file
343
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/DnsQuery.cs
Normal file
|
@ -0,0 +1,343 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WelsonJS.Launcher.ResourceTools
|
||||
{
|
||||
public class DnsQuery : IResourceTool
|
||||
{
|
||||
private readonly ResourceServer Server;
|
||||
private readonly HttpClient _httpClient;
|
||||
private const string Prefix = "dns-query/";
|
||||
private string DnsServer;
|
||||
private const int DnsPort = 53;
|
||||
private const int Timeout = 5000;
|
||||
private static readonly Random _random = new Random();
|
||||
|
||||
public DnsQuery(ResourceServer server, HttpClient httpClient)
|
||||
{
|
||||
Server = server;
|
||||
_httpClient = httpClient;
|
||||
|
||||
DnsServer = Program.GetAppConfig("DnsServerAddress");
|
||||
}
|
||||
|
||||
public bool CanHandle(string path)
|
||||
{
|
||||
return path.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public async Task HandleAsync(HttpListenerContext context, string path)
|
||||
{
|
||||
await Task.Delay(0);
|
||||
|
||||
string query = path.Substring(Prefix.Length);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(query) || query.Length > 255)
|
||||
{
|
||||
Server.ServeResource(context, "<error>Invalid query parameter</error>", "application/xml", 400);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Dictionary<string, List<string>> allRecords = QueryAll(query);
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
foreach (var recordType in allRecords.Keys)
|
||||
{
|
||||
result.AppendLine($"\n{recordType} Records:");
|
||||
foreach (var record in allRecords[recordType])
|
||||
{
|
||||
result.AppendLine(record);
|
||||
}
|
||||
}
|
||||
|
||||
string data = result.ToString();
|
||||
Server.ServeResource(context, data, "text/plain", 200);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Server.ServeResource(context, $"<error>Failed to process DNS query. {ex.Message}</error>", "application/xml", 500);
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> QueryA(string domain) => QueryDns(domain, 1);
|
||||
public List<string> QueryNS(string domain) => QueryDns(domain, 2);
|
||||
public List<string> QueryCNAME(string domain) => QueryDns(domain, 5);
|
||||
public List<string> QuerySOA(string domain) => QueryDns(domain, 6);
|
||||
public List<string> QueryPTR(string domain) => QueryDns(domain, 12);
|
||||
public List<string> QueryMX(string domain) => QueryDns(domain, 15);
|
||||
public List<string> QueryTXT(string domain) => QueryDns(domain, 16);
|
||||
public List<string> QueryAAAA(string domain) => QueryDns(domain, 28);
|
||||
public List<string> QuerySRV(string domain) => QueryDns(domain, 33);
|
||||
public List<string> QueryNAPTR(string domain) => QueryDns(domain, 35);
|
||||
public List<string> QueryCAA(string domain) => QueryDns(domain, 257);
|
||||
|
||||
public Dictionary<string, List<string>> QueryAll(string domain)
|
||||
{
|
||||
var results = new Dictionary<string, List<string>>();
|
||||
|
||||
results["A"] = QueryA(domain);
|
||||
results["NS"] = QueryNS(domain);
|
||||
results["CNAME"] = QueryCNAME(domain);
|
||||
results["SOA"] = QuerySOA(domain);
|
||||
results["PTR"] = QueryPTR(domain);
|
||||
results["MX"] = QueryMX(domain);
|
||||
results["TXT"] = QueryTXT(domain);
|
||||
results["AAAA"] = QueryAAAA(domain);
|
||||
results["SRV"] = QuerySRV(domain);
|
||||
results["NAPTR"] = QueryNAPTR(domain);
|
||||
results["CAA"] = QueryCAA(domain);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private List<string> QueryDns(string domain, ushort type)
|
||||
{
|
||||
List<string> records = new List<string>();
|
||||
|
||||
// Validate domain format
|
||||
if (string.IsNullOrWhiteSpace(domain))
|
||||
{
|
||||
records.Add("Error: Domain cannot be empty");
|
||||
return records;
|
||||
}
|
||||
|
||||
// Basic domain format validation
|
||||
if (domain.Length > 255 ||
|
||||
!domain.Split('.').All(part => part.Length > 0 && part.Length <= 63))
|
||||
{
|
||||
records.Add("Error: Invalid domain format");
|
||||
return records;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using (UdpClient udpClient = new UdpClient(DnsServer, DnsPort))
|
||||
{
|
||||
udpClient.Client.ReceiveTimeout = Timeout;
|
||||
|
||||
byte[] request = CreateDnsQuery(domain, type);
|
||||
udpClient.Send(request, request.Length);
|
||||
|
||||
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, DnsPort);
|
||||
byte[] response = udpClient.Receive(ref remoteEP);
|
||||
|
||||
records.AddRange(ParseDnsResponse(response, type));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
records.Add($"Error: {ex.Message}");
|
||||
}
|
||||
|
||||
return records;
|
||||
}
|
||||
|
||||
private byte[] CreateDnsQuery(string domain, ushort type)
|
||||
{
|
||||
byte[] query = new byte[512];
|
||||
|
||||
query[0] = (byte)_random.Next(0, 256);
|
||||
query[1] = (byte)_random.Next(0, 256);
|
||||
query[2] = 0x01;
|
||||
query[3] = 0x00;
|
||||
query[4] = 0x00;
|
||||
query[5] = 0x01;
|
||||
|
||||
for (int i = 6; i < 12; i++)
|
||||
query[i] = 0x00;
|
||||
|
||||
int position = 12;
|
||||
foreach (string part in domain.Split('.'))
|
||||
{
|
||||
query[position++] = (byte)part.Length;
|
||||
byte[] label = Encoding.ASCII.GetBytes(part);
|
||||
Array.Copy(label, 0, query, position, label.Length);
|
||||
position += label.Length;
|
||||
}
|
||||
query[position++] = 0x00;
|
||||
|
||||
query[position++] = (byte)(type >> 8);
|
||||
query[position++] = (byte)(type & 0xFF);
|
||||
query[position++] = 0x00;
|
||||
query[position++] = 0x01;
|
||||
|
||||
byte[] finalQuery = new byte[position];
|
||||
Array.Copy(query, finalQuery, position);
|
||||
|
||||
return finalQuery;
|
||||
}
|
||||
|
||||
private List<string> ParseDnsResponse(byte[] response, ushort queryType)
|
||||
{
|
||||
List<string> results = new List<string>();
|
||||
|
||||
// Check response code from DNS server
|
||||
int responseCode = response[3] & 0x0F;
|
||||
if (responseCode != 0)
|
||||
{
|
||||
string errorMessage = "DNS server returned error: ";
|
||||
switch (responseCode)
|
||||
{
|
||||
case 1: errorMessage += "Format Error"; break;
|
||||
case 2: errorMessage += "Server Failure"; break;
|
||||
case 3: errorMessage += "Name Error (Domain does not exist)"; break;
|
||||
case 4: errorMessage += "Not Implemented"; break;
|
||||
case 5: errorMessage += "Refused"; break;
|
||||
default: errorMessage += $"Unknown Error ({responseCode})"; break;
|
||||
}
|
||||
results.Add(errorMessage);
|
||||
return results;
|
||||
}
|
||||
|
||||
int answerCount = (response[6] << 8) | response[7];
|
||||
if (answerCount == 0)
|
||||
{
|
||||
results.Add("No records found.");
|
||||
return results;
|
||||
}
|
||||
|
||||
int position = 12; // Skip DNS header
|
||||
|
||||
while (response[position] != 0)
|
||||
position += response[position] + 1;
|
||||
position += 5; // End of Question section
|
||||
|
||||
for (int i = 0; i < answerCount; i++)
|
||||
{
|
||||
while (response[position] != 0 && (response[position] & 0xC0) == 0)
|
||||
position += response[position] + 1;
|
||||
position += 2; // Skip Type, Class fields
|
||||
|
||||
ushort recordType = (ushort)((response[position] << 8) | response[position + 1]);
|
||||
position += 8; // Skip TTL and Data length fields
|
||||
|
||||
ushort dataLength = (ushort)((response[position] << 8) | response[position + 1]);
|
||||
position += 2; // Read Data Length
|
||||
|
||||
byte[] data = new byte[dataLength];
|
||||
Array.Copy(response, position, data, 0, dataLength);
|
||||
position += dataLength;
|
||||
|
||||
switch (recordType)
|
||||
{
|
||||
case 1:
|
||||
results.Add($"A: {new IPAddress(data)}");
|
||||
break;
|
||||
case 2:
|
||||
results.Add($"NS: {DecodeDomainName(response, data, 0)}");
|
||||
break;
|
||||
case 5:
|
||||
results.Add($"CNAME: {DecodeDomainName(response, data, 0)}");
|
||||
break;
|
||||
case 6:
|
||||
results.Add($"SOA: {DecodeDomainName(response, data, 0)}");
|
||||
break;
|
||||
case 12:
|
||||
results.Add($"PTR: {DecodeDomainName(response, data, 0)}");
|
||||
break;
|
||||
case 15:
|
||||
// MX record processing (priority and exchange)
|
||||
if (data.Length >= 2)
|
||||
{
|
||||
ushort priority = (ushort)((data[0] << 8) | data[1]);
|
||||
string exchange = DecodeDomainName(response, data, 2); // Decode domain name after 2 bytes
|
||||
results.Add($"MX: Priority {priority}, Exchange {exchange}");
|
||||
}
|
||||
else
|
||||
{
|
||||
results.Add($"MX: Invalid data length.");
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
int txtPos = 0;
|
||||
while (txtPos < data.Length)
|
||||
{
|
||||
int txtLength = data[txtPos++];
|
||||
results.Add($"TXT: {Encoding.UTF8.GetString(data, txtPos, txtLength)}");
|
||||
txtPos += txtLength;
|
||||
}
|
||||
break;
|
||||
case 28:
|
||||
results.Add($"AAAA: {new IPAddress(data)}");
|
||||
break;
|
||||
case 33:
|
||||
ushort prioritySrv = (ushort)((data[0] << 8) | data[1]);
|
||||
ushort weight = (ushort)((data[2] << 8) | data[3]);
|
||||
ushort port = (ushort)((data[4] << 8) | data[5]);
|
||||
string target = DecodeDomainName(response, data, 6);
|
||||
results.Add($"SRV: Priority {prioritySrv}, Weight {weight}, Port {port}, Target {target}");
|
||||
break;
|
||||
case 35:
|
||||
if (data.Length >= 7)
|
||||
{
|
||||
ushort order = (ushort)((data[0] << 8) | data[1]);
|
||||
ushort preference = (ushort)((data[2] << 8) | data[3]);
|
||||
// Extract flags, services, regexp and replacement
|
||||
results.Add($"NAPTR: Order {order}, Preference {preference}");
|
||||
}
|
||||
else
|
||||
{
|
||||
results.Add($"NAPTR: Invalid data length: {BitConverter.ToString(data)}");
|
||||
}
|
||||
break;
|
||||
case 257:
|
||||
if (data.Length >= 2)
|
||||
{
|
||||
byte flags = data[0];
|
||||
int tagLen = data[1];
|
||||
if (data.Length >= 2 + tagLen)
|
||||
{
|
||||
string tag = Encoding.ASCII.GetString(data, 2, tagLen);
|
||||
string value = Encoding.ASCII.GetString(data, 2 + tagLen, data.Length - 2 - tagLen);
|
||||
results.Add($"CAA: Flags {flags}, Tag {tag}, Value {value}");
|
||||
}
|
||||
else
|
||||
{
|
||||
results.Add($"CAA: Invalid data length: {BitConverter.ToString(data)}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
results.Add($"CAA: Invalid data length: {BitConverter.ToString(data)}");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
results.Add($"Unknown Type {recordType}: {BitConverter.ToString(data)}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private string DecodeDomainName(byte[] response, byte[] data, int startIndex)
|
||||
{
|
||||
int position = startIndex;
|
||||
List<string> labels = new List<string>();
|
||||
|
||||
while (data[position] != 0)
|
||||
{
|
||||
// Handle 0xC0 pointer (compressed domain name handling)
|
||||
if ((data[position] & 0xC0) == 0xC0)
|
||||
{
|
||||
int pointer = ((data[position] & 0x3F) << 8) | data[position + 1];
|
||||
return DecodeDomainName(response, response, pointer); // Recursive call to decode from the pointer
|
||||
}
|
||||
|
||||
int labelLength = data[position++];
|
||||
labels.Add(Encoding.ASCII.GetString(data, position, labelLength));
|
||||
position += labelLength;
|
||||
}
|
||||
|
||||
return string.Join(".", labels);
|
||||
}
|
||||
}
|
||||
}
|
77
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Settings.cs
Normal file
77
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Settings.cs
Normal file
|
@ -0,0 +1,77 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace WelsonJS.Launcher.ResourceTools
|
||||
{
|
||||
public class Settings : IResourceTool
|
||||
{
|
||||
private readonly ResourceServer Server;
|
||||
private readonly HttpClient _httpClient;
|
||||
private const string Prefix = "settings";
|
||||
|
||||
public Settings(ResourceServer server, HttpClient httpClient)
|
||||
{
|
||||
Server = server;
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
public bool CanHandle(string path)
|
||||
{
|
||||
return path.Equals(Prefix, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public async Task HandleAsync(HttpListenerContext context, string path)
|
||||
{
|
||||
await Task.Delay(0);
|
||||
|
||||
// Get current namespace (e.g., WelsonJS.Launcher)
|
||||
string ns = typeof(Program).Namespace;
|
||||
|
||||
// Build resource base name (e.g., WelsonJS.Launcher.Properties.Resources)
|
||||
string resourceBaseName = ns + ".Properties.Resources";
|
||||
|
||||
// Load resource strings using ResourceManager
|
||||
var resourceManager = new ResourceManager(resourceBaseName, Assembly.GetExecutingAssembly());
|
||||
var resourceSet = resourceManager.GetResourceSet(
|
||||
System.Globalization.CultureInfo.CurrentCulture,
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
var resourceStrings = new Dictionary<string, string>();
|
||||
foreach (System.Collections.DictionaryEntry entry in resourceSet)
|
||||
{
|
||||
if (entry.Value is string strValue)
|
||||
{
|
||||
resourceStrings[(string)entry.Key] = strValue;
|
||||
}
|
||||
}
|
||||
|
||||
// Load settings from app.config
|
||||
var appConfig = ConfigurationManager.AppSettings.AllKeys
|
||||
.ToDictionary(k => k, k => ConfigurationManager.AppSettings[k]);
|
||||
|
||||
// Merge by starting with resourceStrings and letting app.config override
|
||||
var finalConfig = new Dictionary<string, string>(resourceStrings);
|
||||
foreach (var kv in appConfig)
|
||||
{
|
||||
finalConfig[kv.Key] = kv.Value;
|
||||
}
|
||||
|
||||
// Generate XML using XElement
|
||||
XElement xml = new XElement("settings",
|
||||
finalConfig.Select(kv => new XElement(kv.Key, kv.Value))
|
||||
);
|
||||
|
||||
Server.ServeResource(context, xml.ToString(), "application/xml");
|
||||
}
|
||||
}
|
||||
}
|
103
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Tfa.cs
Normal file
103
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Tfa.cs
Normal file
|
@ -0,0 +1,103 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace WelsonJS.Launcher.ResourceTools
|
||||
{
|
||||
public class Tfa : IResourceTool
|
||||
{
|
||||
private readonly ResourceServer Server;
|
||||
private readonly HttpClient _httpClient;
|
||||
private const string Prefix = "tfa/";
|
||||
private const string Base32Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||
|
||||
public Tfa(ResourceServer server, HttpClient httpClient)
|
||||
{
|
||||
Server = server;
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
public bool CanHandle(string path)
|
||||
{
|
||||
return path.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public async Task HandleAsync(HttpListenerContext context, string path)
|
||||
{
|
||||
await Task.Delay(0);
|
||||
|
||||
string endpoint = path.Substring(Prefix.Length);
|
||||
|
||||
if (endpoint.Equals("pubkey"))
|
||||
{
|
||||
Server.ServeResource(context, GetPubKey(), "text/plain", 200);
|
||||
return;
|
||||
}
|
||||
|
||||
Server.ServeResource(context);
|
||||
}
|
||||
|
||||
public int GetOtp(string key)
|
||||
{
|
||||
byte[] binaryKey = DecodeBase32(key.Replace(" ", ""));
|
||||
long timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds() / 30;
|
||||
byte[] timestampBytes = BitConverter.GetBytes(timestamp);
|
||||
Array.Reverse(timestampBytes); // Ensure big-endian order
|
||||
|
||||
using (var hmac = new HMACSHA1(binaryKey))
|
||||
{
|
||||
byte[] hash = hmac.ComputeHash(timestampBytes);
|
||||
int offset = hash[hash.Length - 1] & 0xF;
|
||||
|
||||
int otp = ((hash[offset] & 0x7F) << 24) |
|
||||
((hash[offset + 1] & 0xFF) << 16) |
|
||||
((hash[offset + 2] & 0xFF) << 8) |
|
||||
(hash[offset + 3] & 0xFF);
|
||||
|
||||
return otp % 1000000; // Ensure 6-digit OTP
|
||||
}
|
||||
}
|
||||
|
||||
public string GetPubKey()
|
||||
{
|
||||
using (var rng = RandomNumberGenerator.Create())
|
||||
{
|
||||
var key = new char[16];
|
||||
var randomBytes = new byte[16];
|
||||
rng.GetBytes(randomBytes);
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
key[i] = Base32Chars[randomBytes[i] % Base32Chars.Length];
|
||||
}
|
||||
|
||||
return string.Join(" ", Enumerable.Range(0, 4).Select(i => new string(key, i * 4, 4)));
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] DecodeBase32(string key)
|
||||
{
|
||||
int buffer = 0, bitsLeft = 0;
|
||||
var binaryKey = new List<byte>();
|
||||
|
||||
foreach (char c in key)
|
||||
{
|
||||
int value = Base32Chars.IndexOf(c);
|
||||
if (value < 0) continue; // Ignore invalid characters
|
||||
|
||||
buffer = (buffer << 5) + value;
|
||||
bitsLeft += 5;
|
||||
if (bitsLeft >= 8)
|
||||
{
|
||||
bitsLeft -= 8;
|
||||
binaryKey.Add((byte)((buffer >> bitsLeft) & 0xFF));
|
||||
}
|
||||
}
|
||||
return binaryKey.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
60
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Whois.cs
Normal file
60
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceTools/Whois.cs
Normal file
|
@ -0,0 +1,60 @@
|
|||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
|
||||
namespace WelsonJS.Launcher.ResourceTools
|
||||
{
|
||||
public class Whois : IResourceTool
|
||||
{
|
||||
private readonly ResourceServer Server;
|
||||
private readonly HttpClient _httpClient;
|
||||
private const string Prefix = "whois/";
|
||||
|
||||
public Whois(ResourceServer server, HttpClient httpClient)
|
||||
{
|
||||
Server = server;
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
public bool CanHandle(string path)
|
||||
{
|
||||
return path.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public async Task HandleAsync(HttpListenerContext context, string path)
|
||||
{
|
||||
string query = path.Substring(Prefix.Length);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(query) || query.Length > 255)
|
||||
{
|
||||
Server.ServeResource(context, "<error>Invalid query parameter</error>", "application/xml", 400);
|
||||
return;
|
||||
}
|
||||
|
||||
string clientAddress = Program.GetAppConfig("WhoisClientAddress");
|
||||
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, Program.GetAppConfig("WhoisServerUrl"))
|
||||
{
|
||||
Content = new StringContent($"query={Uri.EscapeDataString(query)}&ip={clientAddress}", Encoding.UTF8, "application/x-www-form-urlencoded")
|
||||
};
|
||||
|
||||
request.Headers.Add("Accept", "*/*");
|
||||
request.Headers.Add("User-Agent", context.Request.UserAgent);
|
||||
_httpClient.DefaultRequestHeaders.Referrer = new Uri(Program.GetAppConfig("WhoisReferrerUrl"));
|
||||
|
||||
try
|
||||
{
|
||||
HttpResponseMessage response = await _httpClient.SendAsync(request);
|
||||
string responseBody = await response.Content.ReadAsStringAsync();
|
||||
|
||||
Server.ServeResource(context, responseBody, "text/plain", (int)response.StatusCode);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Server.ServeResource(context, $"<error>Failed to process WHOIS request. {ex.Message}</error>", "application/xml", 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
BIN
WelsonJS.Toolkit/WelsonJS.Launcher/Resources/icon_delete_32.png
Normal file
BIN
WelsonJS.Toolkit/WelsonJS.Launcher/Resources/icon_delete_32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 974 B |
BIN
WelsonJS.Toolkit/WelsonJS.Launcher/Resources/icon_start_32.png
Normal file
BIN
WelsonJS.Toolkit/WelsonJS.Launcher/Resources/icon_start_32.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 796 B |
|
@ -57,6 +57,7 @@
|
|||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Deployment" />
|
||||
<Reference Include="System.Drawing" />
|
||||
|
@ -66,16 +67,31 @@
|
|||
<Private>True</Private>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="IResourceTool.cs" />
|
||||
<Compile Include="ResourceTools\Settings.cs" />
|
||||
<Compile Include="ResourceTools\Completion.cs" />
|
||||
<Compile Include="ResourceTools\DevTools.cs" />
|
||||
<Compile Include="ResourceTools\DnsQuery.cs" />
|
||||
<Compile Include="ResourceTools\Tfa.cs" />
|
||||
<Compile Include="ResourceTools\Whois.cs" />
|
||||
<Compile Include="EnvForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="EnvForm.Designer.cs">
|
||||
<DependentUpon>EnvForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="InstancesForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="InstancesForm.Designer.cs">
|
||||
<DependentUpon>InstancesForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="MainForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
|
@ -84,9 +100,19 @@
|
|||
</Compile>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="GlobalSettingsForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="GlobalSettingsForm.Designer.cs">
|
||||
<DependentUpon>GlobalSettingsForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="ResourceServer.cs" />
|
||||
<EmbeddedResource Include="EnvForm.resx">
|
||||
<DependentUpon>EnvForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="InstancesForm.resx">
|
||||
<DependentUpon>InstancesForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="MainForm.resx">
|
||||
<DependentUpon>MainForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
|
@ -95,6 +121,9 @@
|
|||
<SubType>Designer</SubType>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="GlobalSettingsForm.resx">
|
||||
<DependentUpon>GlobalSettingsForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
|
@ -127,5 +156,14 @@
|
|||
<None Include="Resources\icon_export_32.png" />
|
||||
<None Include="Resources\icon_import_32.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Resources\icon_delete_32.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Resources\icon_start_32.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="editor.html" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
|
@ -1,3 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/></startup></configuration>
|
||||
<appSettings>
|
||||
<add key="ResourceServerPrefix" value="http://localhost:3000/"/>
|
||||
<add key="RepositoryUrl" value="https://github.com/gnh1201/welsonjs"/>
|
||||
<add key="CopilotUrl" value="https://copilot.microsoft.com/"/>
|
||||
<add key="DevToolsPrefix" value="http://localhost:9222/"/>
|
||||
<add key="AzureAiServicePrefix" value="https://ai-catswords656881030318.services.ai.azure.com/"/>
|
||||
<add key="AzureAiServiceApiKey" value=""/>
|
||||
<add key="AzureAiServiceApiVersion" value="2024-05-01-preview"/>
|
||||
<add key="WhoisServerUrl" value="https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois.jsc"/>
|
||||
<add key="WhoisReferrerUrl" value="https://xn--c79as89aj0e29b77z.xn--3e0b707e/kor/whois/whois.jsp"/>
|
||||
<add key="WhoisClientAddress" value="141.101.82.1"/>
|
||||
<add key="DnsServerAddress" value="1.1.1.1"/>
|
||||
<add key="BlobStoragePrefix" value="https://catswords.blob.core.windows.net/welsonjs/"/>
|
||||
<add key="CdnJsPrefix" value="https://cdnjs.cloudflare.com/"/>
|
||||
<add key="JsDeliverPrefix" value="https://cdn.jsdelivr.net/"/>
|
||||
<add key="UnpkgPrefix" value="https://unpkg.com/"/>
|
||||
<add key="SkypackPrefix" value="https://www.skypack.dev/"/>
|
||||
<add key="EsmShPrefix" value="https://esm.sh/"/>
|
||||
<add key="EsmRunPrefix" value="https://esm.run/"/>
|
||||
<add key="JqueryCdnPrefix" value="https://code.jquery.com/"/>
|
||||
<add key="AspNetCdnPrefix" value="https://ajax.aspnetcdn.com/"/>
|
||||
<add key="GoogleApisPrefix" value="https://ajax.googleapis.com/"/>
|
||||
<add key="RawGitHubPrefix" value="https://raw.githubusercontent.com/"/>
|
||||
</appSettings>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
|
||||
</startup>
|
||||
</configuration>
|
||||
|
|
597
WelsonJS.Toolkit/WelsonJS.Launcher/editor.html
Normal file
597
WelsonJS.Toolkit/WelsonJS.Launcher/editor.html
Normal file
|
@ -0,0 +1,597 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>WelsonJS Editor</title>
|
||||
<meta name="title" content="WelsonJS Editor">
|
||||
<meta name="description" content="WelsonJS can build a Windows app on the Windows built-in JavaScript engine.">
|
||||
<meta name="keywords" content="ecmascript, javascript, windows">
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="language" content="English">
|
||||
<meta name="author" content="Namhyeon Go (abuse@catswords.net)">
|
||||
<style>
|
||||
html, body, #app, #app > .app {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#container {
|
||||
border: 1px solid grey;
|
||||
height: calc(100% - 167px);
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#editor {
|
||||
flex: 3;
|
||||
}
|
||||
|
||||
#promptEditor {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.banner {
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
background-color: #f1f1f1;
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script>
|
||||
var require = {
|
||||
paths: {
|
||||
vs: 'http://localhost:3000/ajax/libs/monaco-editor/0.52.2/min/vs'
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<script src="http://localhost:3000/ajax/libs/lodash/4.17.21/lodash.min.js" integrity="sha384-H6KKS1H1WwuERMSm+54dYLzjg0fKqRK5ZRyASdbrI/lwrCc6bXEmtGYr5SwvP1pZ" crossorigin="anonymous"></script>
|
||||
<script src="http://localhost:3000/ajax/libs/jsoneditor/10.1.3/jsoneditor.min.js" integrity="sha384-NdVVc20Tze856ZAWEoJNCk0mL4zJrGztRwULc5Hz25HUXQQgYtmjFtgVAxR4p5dD" crossorigin="anonymous"></script>
|
||||
<script src="http://localhost:3000/ajax/libs/react/18.3.1/umd/react.production.min.js" integrity="sha384-DGyLxAyjq0f9SPpVevD6IgztCFlnMF6oW/XQGmfe+IsZ8TqEiDrcHkMLKI6fiB/Z" crossorigin="anonymous"></script>
|
||||
<script src="http://localhost:3000/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js" integrity="sha384-gTGxhz21lVGYNMcdJOyq01Edg0jhn/c22nsx0kyqP0TxaV5WVdsSH1fSDUf5YJj1" crossorigin="anonymous"></script>
|
||||
<script src="http://localhost:3000/ajax/libs/axios/1.8.4/axios.min.js" integrity="sha384-06w+raHvkSL3+E7mbQ2X6DZwI5A3veU8Ba+NLrAPxxRGw4Xy78sihHDHQMustMM4" crossorigin="anonymous"></script>
|
||||
<script src="http://localhost:3000/ajax/libs/fast-xml-parser/4.5.1/fxparser.min.js" integrity="sha384-ae/HepOQ8hiJ/VA6yGwPMGXQXOkT/lJpjlcQ7EUgibUcfnBltuozgNj4IgOZ9QLc" crossorigin="anonymous"></script>
|
||||
<script src="http://localhost:3000/ajax/libs/dompurify/3.2.4/purify.min.js" integrity="sha384-eEu5CTj3qGvu9PdJuS+YlkNi7d2XxQROAFYOr59zgObtlcux1ae1Il3u7jvdCSWu" crossorigin="anonymous"></script>
|
||||
<script src="http://localhost:3000/ajax/libs/monaco-editor/0.52.2/min/vs/loader.js" integrity="sha384-pHG02SG8pId94Np3AbPmBEJ1yPqaH0IkJGLSNGXYmuGhkazT8Lr/57WYpbkGjJtu" crossorigin="anonymous"></script>
|
||||
<script src="http://localhost:3000/ajax/libs/monaco-editor/0.52.2/min/vs/editor/editor.main.js" integrity="sha384-fj9z+NUc93I3woCCy5IRQfrQ8Amu1E27tllwgb5gz3d9Vr1ymS13xcF6two3e4KH" crossorigin="anonymous"></script>
|
||||
<script>
|
||||
function loadResource(url, mimeType, integrity) {
|
||||
mimeType = mimeType || 'application/javascript';
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let el;
|
||||
|
||||
if (mimeType === 'text/css') {
|
||||
el = document.createElement('link');
|
||||
el.rel = 'stylesheet';
|
||||
el.type = mimeType;
|
||||
el.href = url;
|
||||
} else {
|
||||
el = document.createElement('script');
|
||||
el.type = mimeType;
|
||||
el.src = url;
|
||||
}
|
||||
|
||||
if (integrity) {
|
||||
el.integrity = integrity;
|
||||
el.crossOrigin = 'anonymous';
|
||||
}
|
||||
|
||||
el.onload = resolve;
|
||||
el.onerror = reject;
|
||||
|
||||
(mimeType === 'text/css' ? document.head : document.body).appendChild(el);
|
||||
});
|
||||
}
|
||||
|
||||
Promise.all([
|
||||
loadResource("http://localhost:3000/ajax/libs/metroui/dev/lib/metro.css", "text/css", "sha384-4XgOiXH2ZMaWt5s5B35yKi7EAOabhZvx7wO8Jr71q2vZ+uONdRza/6CsK2kpyocd"),
|
||||
loadResource("http://localhost:3000/ajax/libs/metroui/dev/lib/icons.css", "text/css", "sha384-FuLND994etg+RtnpPSPMyNBvL+fEz+xGhbN61WUWuDEeZ+wJzcQ8SGqAMuI5hWrt"),
|
||||
loadResource("http://localhost:3000/ajax/libs/monaco-editor/0.52.2/min/vs/editor/editor.main.css", "text/css", "sha384-06yHXpYRlHEPaR4AS0fB/W+lMN09Zh5e1XMtfkNQdHV38OlhfkOEW5M+pCj3QskC"),
|
||||
loadResource("http://localhost:3000/ajax/libs/jsoneditor/10.1.3/jsoneditor.min.css", "text/css", "sha384-cj1rYBc4/dVYAknZMTkVCDRL6Knzugf32igVqsuFW0iRWFHKH8Ci8+ekC8gNsFZ+")
|
||||
]).then(() => {
|
||||
const _e = React.createElement;
|
||||
|
||||
function Button({ id, icon, caption, onClick }) {
|
||||
return _e(
|
||||
'button',
|
||||
{ id, className: 'ribbon-button', onClick },
|
||||
_e('span', { className: `icon ${icon}` }),
|
||||
_e('span', { className: 'caption' }, caption)
|
||||
);
|
||||
}
|
||||
|
||||
function Group({ title, buttons }) {
|
||||
return _e(
|
||||
'div',
|
||||
{ className: 'group' },
|
||||
buttons.map((btn, index) =>
|
||||
_e(Button, { key: index, ...btn })
|
||||
),
|
||||
_e('span', { className: 'title' }, title)
|
||||
);
|
||||
}
|
||||
|
||||
function RibbonMenu({
|
||||
onOpenFileClick, onSaveFileClick, onCopliotClick, onAzureAiClick,
|
||||
onSavePromptClick, onLoadPromptClick, onQueryWhoisClick, onQueryDnsClick
|
||||
}) {
|
||||
const fileButtons = [
|
||||
{
|
||||
id: 'btnOpenFile',
|
||||
icon: 'mif-folder-open',
|
||||
caption: 'Open File',
|
||||
onClick: onOpenFileClick
|
||||
},
|
||||
{
|
||||
id: 'btnSaveFile',
|
||||
icon: 'mif-floppy-disks',
|
||||
caption: 'Save File',
|
||||
onClick: onSaveFileClick
|
||||
}
|
||||
];
|
||||
|
||||
const aiButtons = [
|
||||
{ id: 'btnCopilot', icon: 'mif-rocket', caption: 'Copilot', onClick: onCopliotClick },
|
||||
{ id: 'btnAzureAi', icon: 'mif-rocket', caption: 'Azure AI', onClick: onAzureAiClick },
|
||||
{ id: 'btnSavePrompt', icon: 'mif-floppy-disks', caption: 'Save', onClick: onSavePromptClick },
|
||||
{ id: 'btnLoadPrompt', icon: 'mif-file-upload', caption: 'Load', onClick: onLoadPromptClick }
|
||||
];
|
||||
|
||||
const networkToolsButtons = [
|
||||
{ id: 'btnWhois', icon: 'mif-earth', caption: 'Whois', onClick: onQueryWhoisClick },
|
||||
{ id: 'btnDnsQuery', icon: 'mif-earth', caption: 'DNS', onClick: onQueryDnsClick }
|
||||
];
|
||||
|
||||
return _e(
|
||||
'nav',
|
||||
{ 'className': 'ribbon-menu' },
|
||||
_e('ul', { className: 'tabs-holder' },
|
||||
_e('li', { className: 'static' }, _e('a', { href: '#heading-tab' }, 'WelsonJS')),
|
||||
_e('li', { className: 'active' }, _e('a', { href: '#editor-tab' }, 'Editor'))
|
||||
),
|
||||
_e('div', { className: 'content-holder' },
|
||||
_e('div', { className: 'section active', id: 'editor-tab' },
|
||||
_e(Group, { title: 'File', buttons: fileButtons }),
|
||||
_e(Group, { title: 'Generative AI', buttons: aiButtons }),
|
||||
_e(Group, { title: 'Network tools', buttons: networkToolsButtons })
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function Editor({ editorRef }) {
|
||||
const containerRef = React.useRef(null);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!containerRef.current)
|
||||
return;
|
||||
|
||||
require(['vs/editor/editor.main'], () => {
|
||||
const instance = monaco.editor.create(containerRef.current, {
|
||||
value: ['// lib/sayhello.js', 'function say() {', ' console.log("hello");', '}', '', 'exports.say = say;', '', 'exports.VERSIONINFO = "SayHello (sayhello.js) version 0.1";', 'exports.AUTHOR = "abuse@catswords.net";', 'exports.global = global;', 'exports.require = global.require;'].join('\n'),
|
||||
language: 'javascript'
|
||||
});
|
||||
|
||||
editorRef.current = instance;
|
||||
});
|
||||
}, []);
|
||||
|
||||
return _e('div', { id: 'editor', ref: containerRef });
|
||||
}
|
||||
|
||||
function PromptEditor({ promptEditorRef, promptMessagesRef }) {
|
||||
const containerRef = React.useRef(null);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!containerRef.current)
|
||||
return;
|
||||
|
||||
const invoke = () => {
|
||||
try {
|
||||
if (promptEditorRef.current) {
|
||||
const updated = promptEditorRef.current.get();
|
||||
promptMessagesRef.current = updated;
|
||||
} else {
|
||||
throw new Error("promptEditorRef.current is null");
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Invalid JSON structure", e);
|
||||
}
|
||||
};
|
||||
|
||||
const throttledInvoke = _.throttle(invoke, 300, {
|
||||
leading: true,
|
||||
trailing: true
|
||||
});
|
||||
|
||||
const options = {
|
||||
onChange: throttledInvoke
|
||||
};
|
||||
|
||||
const instance = new JSONEditor(containerRef.current, options);
|
||||
instance.set(promptMessagesRef.current);
|
||||
|
||||
promptEditorRef.current = instance;
|
||||
|
||||
return () => {
|
||||
if (instance) {
|
||||
throttledInvoke.flush();
|
||||
throttledInvoke.cancel();
|
||||
instance.destroy();
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
return _e('div', { id: 'promptEditor', ref: containerRef });
|
||||
}
|
||||
|
||||
function App() {
|
||||
const serverPrefix = "http://localhost:3000/";
|
||||
const editorRef = React.useRef(null);
|
||||
const promptEditorRef = React.useRef(null);
|
||||
const settingsRef = React.useRef({});
|
||||
const fileNameRef = React.useRef('sayhello.js');
|
||||
const promptMessagesRef = React.useRef([]);
|
||||
|
||||
const fetchSettings = () => axios.get(`${serverPrefix}settings`)
|
||||
.then(response => {
|
||||
const parser = new XMLParser();
|
||||
const result = parser.parse(response.data);
|
||||
settingsRef.current = result.settings;
|
||||
});
|
||||
|
||||
const resizeEditor = () => {
|
||||
if (editorRef.current) {
|
||||
const ribbon = document.querySelector('nav')?.offsetHeight || 0;
|
||||
const banner = document.querySelector('.banner')?.offsetHeight || 0;
|
||||
const h = document.documentElement.clientHeight - ribbon - banner;
|
||||
const editorDiv = document.getElementById('editor');
|
||||
if (editorDiv) editorDiv.style.height = h + 'px';
|
||||
if (editorRef.current) editorRef.current.layout();
|
||||
}
|
||||
};
|
||||
|
||||
const getSuggestions = (word) => axios.get(`${serverPrefix}completion/${encodeURIComponent(word)}`)
|
||||
.then(response => {
|
||||
const parser = new XMLParser();
|
||||
const result = parser.parse(response.data);
|
||||
|
||||
if (!result.suggestions || !result.suggestions.item) {
|
||||
return {
|
||||
suggestions: []
|
||||
};
|
||||
}
|
||||
|
||||
const items = Array.isArray(result.suggestions.item) ? result.suggestions.item : [result.suggestions.item];
|
||||
const suggestions = items.map(function (item) {
|
||||
return {
|
||||
label: item.label,
|
||||
kind: monaco.languages.CompletionItemKind.Text,
|
||||
documentation: item.documentation || "",
|
||||
insertText: '"' + item.insertText + '"',
|
||||
range: range
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
suggestions: suggestions
|
||||
};
|
||||
})
|
||||
.catch(function () {
|
||||
return {
|
||||
suggestions: []
|
||||
};
|
||||
});
|
||||
|
||||
const pushPromptMessage = (role, content) => {
|
||||
promptMessagesRef.current.push({
|
||||
role: role,
|
||||
content: content
|
||||
});
|
||||
promptEditorRef.current.set(promptMessagesRef.current);
|
||||
};
|
||||
|
||||
const navigate = (href) => {
|
||||
const a = document.createElement("a");
|
||||
a.href = href;
|
||||
a.target = "_blank";
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
};
|
||||
|
||||
const appendTextToEditor = (text) => {
|
||||
const editor = editorRef.current;
|
||||
const position = editor.getPosition();
|
||||
const range = new monaco.Range(position.lineNumber, position.column, position.lineNumber, position.column);
|
||||
editor.executeEdits('', [{
|
||||
range: range,
|
||||
text: "\n" + text,
|
||||
forceMoveMarkers: true
|
||||
}]);
|
||||
resizeEditor();
|
||||
};
|
||||
|
||||
const openFile = () => {
|
||||
const fileInput = document.createElement('input');
|
||||
fileInput.type = 'file';
|
||||
fileInput.onchange = () => {
|
||||
const file = fileInput.files[0];
|
||||
|
||||
if (!file)
|
||||
return;
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
const fileName = file.name;
|
||||
const ext = fileName.split('.').pop().toLowerCase();
|
||||
const langMap = {
|
||||
js: 'javascript', ts: 'typescript', html: 'html',
|
||||
css: 'css', json: 'json', py: 'python', java: 'java',
|
||||
c: 'c', cpp: 'cpp', cs: 'csharp', php: 'php',
|
||||
rb: 'ruby', go: 'go', rs: 'rust'
|
||||
};
|
||||
const lang = langMap[ext] || 'plaintext';
|
||||
|
||||
monaco.editor.setModelLanguage(editorRef.current.getModel(), lang);
|
||||
editorRef.current.setValue(e.target.result);
|
||||
|
||||
fileNameRef.current = fileName;
|
||||
};
|
||||
reader.readAsText(file);
|
||||
};
|
||||
fileInput.click();
|
||||
};
|
||||
|
||||
const saveFile = () => {
|
||||
const text = editorRef.current.getValue();
|
||||
const fileName = prompt("Enter file name:", fileNameRef.current);
|
||||
|
||||
if (!fileName)
|
||||
return;
|
||||
|
||||
const blob = new Blob([text], { type: 'text/plain' });
|
||||
const a = document.createElement('a');
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.download = fileNameRef.current;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
};
|
||||
|
||||
const sendMessageToCopilot = () => {
|
||||
const promptMessage = prompt("Enter a prompt message:", '');
|
||||
if (!promptMessage || promptMessage.trim() == '') {
|
||||
alert("A prompt message is required.");
|
||||
return;
|
||||
}
|
||||
|
||||
appendTextToEditor(`\n// ${promptMessage}... Generating text with Copilot...`);
|
||||
pushPromptMessage("user", promptMessage);
|
||||
|
||||
(async () => {
|
||||
const targetWsUrl = await getTargetByUrl('copilot.microsoft.com');
|
||||
if (targetWsUrl) {
|
||||
await _sendMessageToCopilot(targetWsUrl, promptMessage);
|
||||
} else {
|
||||
alert("Microsoft Copilot not running. Please visit copilot.microsoft.com first.");
|
||||
}
|
||||
})();
|
||||
};
|
||||
|
||||
const _sendMessageToCopilot = async (wsUrl, promptMessage) => {
|
||||
const socket = new WebSocket(wsUrl);
|
||||
const steps = [
|
||||
{
|
||||
id: 1,
|
||||
method: 'Input.insertText',
|
||||
params: {
|
||||
text: promptMessage
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
method: 'Input.dispatchKeyEvent',
|
||||
params: {
|
||||
type: 'keyDown',
|
||||
key: 'Enter',
|
||||
code: 'Enter'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
method: 'Runtime.evaluate',
|
||||
params: {
|
||||
expression: '((e)=>e[e.length-1].querySelector("code")?.innerText||e[e.length-1].innerText)(document.querySelectorAll("[data-content=ai-message]"))'
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
socket.onopen = () => {
|
||||
steps.forEach((step) => {
|
||||
if (step.id == 3) {
|
||||
setTimeout(() => {
|
||||
socket.send(JSON.stringify(step));
|
||||
}, 9000);
|
||||
} else {
|
||||
socket.send(JSON.stringify(step));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
socket.onmessage = (event) => {
|
||||
const response = JSON.parse(event.data);
|
||||
console.log("Sent successfully:", response.result);
|
||||
|
||||
if (response.id == 3) {
|
||||
const responseContent = response.result.result.value;
|
||||
|
||||
appendTextToEditor("/*\n" + responseContent + "\n*/");
|
||||
pushPromptMessage("assistant", responseContent);
|
||||
|
||||
socket.close();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const getTargetByUrl = async (urlPart) => {
|
||||
const response = await fetch(`${serverPrefix}devtools/json`);
|
||||
const targets = await response.json();
|
||||
|
||||
const target = targets.find(target => target.url.includes(urlPart));
|
||||
|
||||
if (target) {
|
||||
console.log(`Found target: ${target.title} (${target.id})`);
|
||||
return target.webSocketDebuggerUrl;
|
||||
} else {
|
||||
console.log('Target not found');
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const sendMessageToAzureAi = () => {
|
||||
const promptMessage = prompt("Enter a prompt message:", '');
|
||||
if (!promptMessage || promptMessage.trim() == '') {
|
||||
alert("A prompt message is required.");
|
||||
return;
|
||||
}
|
||||
|
||||
appendTextToEditor(`\n// ${promptMessage}... Generating text with Azure AI...`);
|
||||
pushPromptMessage("user", promptMessage);
|
||||
|
||||
const apiKey = settingsRef.current.AzureAiServiceApiKey;
|
||||
const url = `${settingsRef.current.AzureAiServicePrefix}models/chat/completions?api-version=${settingsRef.current.AzureAiServiceApiVersion}`;
|
||||
|
||||
const data = {
|
||||
messages: promptMessagesRef.current,
|
||||
max_tokens: 2048,
|
||||
temperature: 0.8,
|
||||
top_p: 0.1,
|
||||
presence_penalty: 0,
|
||||
frequency_penalty: 0,
|
||||
model: 'Phi-4'
|
||||
};
|
||||
|
||||
axios.post(url, data, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'api-key': apiKey
|
||||
}
|
||||
}).then(response => {
|
||||
response.data.choices.forEach(x => {
|
||||
const responseContent = x.message.content;
|
||||
pushPromptMessage("assistant", responseContent);
|
||||
|
||||
const responseText = DOMPurify.sanitize(responseContent, { ALLOWED_TAGS: [], ALLOWED_ATTR: [] });
|
||||
appendTextToEditor(`/*\n${responseText}\n*/`);
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error.response?.data || error.message);
|
||||
});
|
||||
};
|
||||
|
||||
const savePromptMessages = () => {
|
||||
const text = JSON.stringify(promptMessagesRef.current, null, 4);
|
||||
const blob = new Blob([text], { type: 'text/plain' });
|
||||
const a = document.createElement('a');
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.download = "prompt.json";
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
};
|
||||
|
||||
const loadPromptMessages = () => {
|
||||
const fileInput = document.createElement('input');
|
||||
fileInput.type = 'file';
|
||||
fileInput.accept = '.json';
|
||||
fileInput.onchange = function (event) {
|
||||
const file = event.target.files[0];
|
||||
|
||||
if (!file)
|
||||
return;
|
||||
|
||||
let reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
promptMessagesRef.current = JSON.parse(e.target.result);
|
||||
promptEditorRef.current.set(promptMessagesRef.current);
|
||||
appendTextToEditor("\n//Prompt loaded successfully.");
|
||||
};
|
||||
reader.readAsText(file);
|
||||
};
|
||||
fileInput.click();
|
||||
};
|
||||
|
||||
const queryWhois = () => {
|
||||
const hostname = prompt("Enter a hostname or IP address:", '');
|
||||
if (!hostname || hostname.trim() == '') {
|
||||
appendTextToEditor("\n// A hostname or IP address is required.");
|
||||
return;
|
||||
}
|
||||
|
||||
axios.get(`${serverPrefix}whois/${hostname}`).then(response => {
|
||||
const responseText = DOMPurify.sanitize(response.data, { ALLOWED_TAGS: [], ALLOWED_ATTR: [] });
|
||||
appendTextToEditor(`/*\n${responseText}\n*/`);
|
||||
pushPromptMessage("system", responseText);
|
||||
}).catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
};
|
||||
|
||||
const queryDns = () => {
|
||||
const hostname = prompt("Enter a hostname or IP address:", '');
|
||||
if (!hostname || hostname.trim() == '') {
|
||||
appendTextToEditor("\n// A hostname or IP address is required.");
|
||||
return;
|
||||
}
|
||||
|
||||
axios.get(`${serverPrefix}dns-query/${hostname}`).then(response => {
|
||||
const responseText = response.data;
|
||||
appendTextToEditor(`/*\n${responseText}\n*/`);
|
||||
pushPromptMessage("system", responseText);
|
||||
}).catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
window.addEventListener('resize', () => {
|
||||
resizeEditor();
|
||||
});
|
||||
window.dispatchEvent(new Event('resize'));
|
||||
}, []);
|
||||
|
||||
fetchSettings();
|
||||
|
||||
return _e('div', { className: 'app' },
|
||||
_e(RibbonMenu, {
|
||||
onOpenFileClick: openFile,
|
||||
onSaveFileClick: saveFile,
|
||||
onCopliotClick: sendMessageToCopilot,
|
||||
onAzureAiClick: sendMessageToAzureAi,
|
||||
onSavePromptClick: savePromptMessages,
|
||||
onLoadPromptClick: loadPromptMessages,
|
||||
onQueryWhoisClick: queryWhois,
|
||||
onQueryDnsClick: queryDns
|
||||
}),
|
||||
_e('div', { id: 'container' },
|
||||
_e(Editor, { editorRef }),
|
||||
_e(PromptEditor, { promptEditorRef, promptMessagesRef })
|
||||
),
|
||||
_e('div', { className: 'banner' }, _e('a', { href: 'https://github.com/gnh1201/welsonjs' }, 'WelsonJS'), ' Editor powered by Metro UI, Monaco Editor, and JSONEditor.'),
|
||||
);
|
||||
}
|
||||
|
||||
const container = document.getElementById('app');
|
||||
const root = ReactDOM.createRoot(container);
|
||||
root.render(_e(App));
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -3,9 +3,9 @@
|
|||
// https://github.com/gnh1201/welsonjs
|
||||
using ClamAV.Net.Client;
|
||||
using ClamAV.Net.Client.Results;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Diagnostics.Eventing.Reader;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.ServiceProcess;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
@ -15,6 +15,7 @@ namespace WelsonJS.Service
|
|||
{
|
||||
private EventLogWatcher eventLogWatcher;
|
||||
private ServiceMain parent;
|
||||
private ILogger logger;
|
||||
private enum EventType: int
|
||||
{
|
||||
FileCreate = 11,
|
||||
|
@ -69,18 +70,19 @@ namespace WelsonJS.Service
|
|||
private string clamAvConenctionString;
|
||||
private IClamAvClient clamAvClient;
|
||||
|
||||
public FileEventMonitor(ServiceBase parent, string workingDirectory)
|
||||
public FileEventMonitor(ServiceBase _parent, string workingDirectory, ILogger _logger)
|
||||
{
|
||||
this.parent = (ServiceMain)parent;
|
||||
parent = (ServiceMain)_parent;
|
||||
logger = _logger;
|
||||
|
||||
try
|
||||
{
|
||||
clamAvConenctionString = this.parent.GetSettingsHandler().Read("CLAMAV_HOST", "Service");
|
||||
clamAvConenctionString = parent.ReadSettingsValue("CLAMAV_HOST");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
clamAvConenctionString = "tcp://127.0.0.1:3310";
|
||||
this.parent.Log($"Failed to read the address because of {ex.Message}. Set default: {clamAvConenctionString}");
|
||||
logger.LogInformation($"Failed to read the address because of {ex.Message}. Set default: {clamAvConenctionString}");
|
||||
}
|
||||
ConnectToClamAv().Start();
|
||||
}
|
||||
|
@ -103,7 +105,7 @@ namespace WelsonJS.Service
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
parent.Log($"Could not reach to the Sysmon service: {ex.Message}");
|
||||
logger.LogInformation($"Could not reach to the Sysmon service: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,8 +142,8 @@ namespace WelsonJS.Service
|
|||
string image = e.EventRecord.Properties[(int)FileCreateEvent.Image]?.Value?.ToString();
|
||||
string fileName = e.EventRecord.Properties[(int)FileCreateEvent.TargetFilename]?.Value?.ToString();
|
||||
|
||||
parent.Log($"> Detected the file creation: {fileName}");
|
||||
parent.Log(parent.DispatchServiceEvent("fileCreated", new string[] {
|
||||
logger.LogInformation($"> Detected the file creation: {fileName}");
|
||||
logger.LogInformation(parent.DispatchServiceEvent("fileCreated", new string[] {
|
||||
ruleName,
|
||||
processId,
|
||||
image,
|
||||
|
@ -150,7 +152,7 @@ namespace WelsonJS.Service
|
|||
|
||||
if (clamAvClient != null)
|
||||
{
|
||||
parent.Log($"> Starting the ClamAV scan: {fileName}");
|
||||
logger.LogInformation($"> Starting the ClamAV scan: {fileName}");
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await ScanWithClamAv(fileName);
|
||||
|
@ -170,8 +172,8 @@ namespace WelsonJS.Service
|
|||
string desinationPort = e.EventRecord.Properties[(int)NetworkConnectionEvent.DestinationPort]?.Value?.ToString();
|
||||
string dstinationAddress = $"{protocol}://{destinationIp}:{desinationPort}";
|
||||
|
||||
parent.Log($"> Detected the network connection: {dstinationAddress}");
|
||||
parent.Log(parent.DispatchServiceEvent("networkConnected", new string[] {
|
||||
logger.LogInformation($"> Detected the network connection: {dstinationAddress}");
|
||||
logger.LogInformation(parent.DispatchServiceEvent("networkConnected", new string[] {
|
||||
ruleName,
|
||||
processId,
|
||||
image,
|
||||
|
@ -191,8 +193,8 @@ namespace WelsonJS.Service
|
|||
string eventType = e.EventRecord.Properties[(int)RegistryEvent.EventType]?.Value?.ToString();
|
||||
string targetObject = e.EventRecord.Properties[(int)RegistryEvent.TargetObject]?.Value?.ToString();
|
||||
|
||||
parent.Log($"> Detected the registry modification: {targetObject}");
|
||||
parent.Log(parent.DispatchServiceEvent("registryModified", new string[] {
|
||||
logger.LogInformation($"> Detected the registry modification: {targetObject}");
|
||||
logger.LogInformation(parent.DispatchServiceEvent("registryModified", new string[] {
|
||||
ruleName,
|
||||
processId,
|
||||
image,
|
||||
|
@ -209,12 +211,12 @@ namespace WelsonJS.Service
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
parent.Log($"Failed to process the event bacause of {ex.Message}.");
|
||||
logger.LogInformation($"Failed to process the event bacause of {ex.Message}.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
parent.Log("The event instance was null.");
|
||||
logger.LogInformation("The event instance was null.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -230,11 +232,11 @@ namespace WelsonJS.Service
|
|||
// Get ClamAV engine and virus database version
|
||||
VersionResult result = await clamAvClient.GetVersionAsync().ConfigureAwait(false);
|
||||
|
||||
parent.Log($"ClamAV version {result.ProgramVersion}, Virus database version {result.VirusDbVersion}");
|
||||
logger.LogInformation($"ClamAV version {result.ProgramVersion}, Virus database version {result.VirusDbVersion}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
parent.Log($"Failed to read the address because of {ex.Message}. {clamAvConenctionString}");
|
||||
logger.LogInformation($"Failed to read the address because of {ex.Message}. {clamAvConenctionString}");
|
||||
clamAvClient = null;
|
||||
}
|
||||
}
|
||||
|
@ -243,8 +245,8 @@ namespace WelsonJS.Service
|
|||
{
|
||||
ScanResult res = await clamAvClient.ScanRemotePathAsync(remotePath).ConfigureAwait(false);
|
||||
|
||||
parent.Log($"> Scan result: Infected={res.Infected}, VirusName={res.VirusName}");
|
||||
parent.Log(parent.DispatchServiceEvent("avScanResult", new string[] {
|
||||
logger.LogInformation($"> Scan result: Infected={res.Infected}, VirusName={res.VirusName}");
|
||||
logger.LogInformation(parent.DispatchServiceEvent("avScanResult", new string[] {
|
||||
res.Infected.ToString(),
|
||||
res.VirusName
|
||||
}));
|
||||
|
|
|
@ -9,27 +9,30 @@ using System.ServiceProcess;
|
|||
using Grpc.Net.Client;
|
||||
using Grpc.Net.Client.Web;
|
||||
using System.Net.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace WelsonJS.Service
|
||||
{
|
||||
public class HeartbeatClient
|
||||
{
|
||||
private readonly HeartbeatService.HeartbeatServiceClient _client;
|
||||
private ILogger logger;
|
||||
private readonly GrpcChannel _channel;
|
||||
private int HeartbeatInterval;
|
||||
private ServiceMain _parent;
|
||||
private ServiceMain parent;
|
||||
private string clientId;
|
||||
private string serverAddress;
|
||||
|
||||
public HeartbeatClient(ServiceBase parent)
|
||||
public HeartbeatClient(ServiceBase _parent, ILogger _logger)
|
||||
{
|
||||
_parent = (ServiceMain)parent;
|
||||
parent = (ServiceMain)_parent;
|
||||
logger = _logger;
|
||||
|
||||
HeartbeatInterval = int.Parse(_parent.GetSettingsHandler().Read("HEARTBEAT_INTERVAL", "Service") ?? "2000");
|
||||
HeartbeatInterval = int.Parse(parent.ReadSettingsValue("HEARTBEAT_INTERVAL") ?? "2000");
|
||||
|
||||
try
|
||||
{
|
||||
serverAddress = _parent.GetSettingsHandler().Read("GRPC_HOST", "Service");
|
||||
serverAddress = parent.ReadSettingsValue("GRPC_HOST");
|
||||
if (String.IsNullOrEmpty(serverAddress))
|
||||
{
|
||||
throw new Exception("The server address could not be empty.");
|
||||
|
@ -38,7 +41,7 @@ namespace WelsonJS.Service
|
|||
catch (Exception ex)
|
||||
{
|
||||
serverAddress = "http://localhost:50051";
|
||||
_parent.Log($"Failed to read the address because of {ex.Message}. Set default: {serverAddress}");
|
||||
logger.LogInformation($"Failed to read the address because of {ex.Message}. Set default: {serverAddress}");
|
||||
}
|
||||
|
||||
var httpClientHandler = new HttpClientHandler();
|
||||
|
@ -51,7 +54,7 @@ namespace WelsonJS.Service
|
|||
_client = new HeartbeatService.HeartbeatServiceClient(_channel);
|
||||
|
||||
clientId = GetSystemUUID().ToLower();
|
||||
_parent.Log($"Use the client ID: {clientId}");
|
||||
logger.LogInformation($"Use the client ID: {clientId}");
|
||||
}
|
||||
|
||||
public async Task StartHeartbeatAsync()
|
||||
|
@ -69,14 +72,14 @@ namespace WelsonJS.Service
|
|||
|
||||
await call.RequestStream.WriteAsync(request);
|
||||
await call.RequestStream.CompleteAsync();
|
||||
_parent.Log("Sent heartbeat");
|
||||
logger.LogInformation("Sent heartbeat");
|
||||
|
||||
await Task.Delay(HeartbeatInterval); // Wait for HeartbeatInterval
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_parent.Log("Heartbeat request stream failed: " + ex.Message);
|
||||
logger.LogInformation("Heartbeat request stream failed: " + ex.Message);
|
||||
}
|
||||
|
||||
// 서버 응답을 수신하는 작업
|
||||
|
@ -85,16 +88,16 @@ namespace WelsonJS.Service
|
|||
while (await call.ResponseStream.MoveNext())
|
||||
{
|
||||
var response = call.ResponseStream.Current;
|
||||
_parent.Log("Heartbeat response received: " + response.IsAlive);
|
||||
logger.LogInformation("Heartbeat response received: " + response.IsAlive);
|
||||
}
|
||||
}
|
||||
catch (RpcException ex)
|
||||
{
|
||||
_parent.Log($"gRPC error: {ex.Status.Detail}");
|
||||
logger.LogInformation($"gRPC error: {ex.Status.Detail}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_parent.Log($"Unexpected error: {ex.Message}");
|
||||
logger.LogInformation($"Unexpected error: {ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -118,7 +121,7 @@ namespace WelsonJS.Service
|
|||
while (await eventCall.ResponseStream.MoveNext())
|
||||
{
|
||||
var response = eventCall.ResponseStream.Current;
|
||||
_parent.Log($"Received event from server: {response.EventType} with args: {string.Join(", ", response.Args)}");
|
||||
logger.LogInformation($"Received event from server: {response.EventType} with args: {string.Join(", ", response.Args)}");
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
@ -148,7 +151,7 @@ namespace WelsonJS.Service
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_parent.Log($"An error occurred while retrieving the system UUID: {ex.Message}");
|
||||
logger.LogInformation($"An error occurred while retrieving the system UUID: {ex.Message}");
|
||||
}
|
||||
|
||||
return "UNKNOWN";
|
||||
|
|
62
WelsonJS.Toolkit/WelsonJS.Service/Logging/FileLogger.cs
Normal file
62
WelsonJS.Toolkit/WelsonJS.Service/Logging/FileLogger.cs
Normal file
|
@ -0,0 +1,62 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
using System.IO;
|
||||
using System;
|
||||
|
||||
namespace WelsonJS.Service.Logging
|
||||
{
|
||||
public class FileLogger : ILogger
|
||||
{
|
||||
private string loggingDirectory;
|
||||
private string categoryName;
|
||||
private static object _lock = new object();
|
||||
|
||||
public FileLogger(string _loggingDirectory, string _categoryName = "welsonjs")
|
||||
{
|
||||
loggingDirectory = _loggingDirectory;
|
||||
categoryName = _categoryName;
|
||||
}
|
||||
|
||||
public IDisposable BeginScope<TState>(TState state)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool IsEnabled(LogLevel logLevel)
|
||||
{
|
||||
//return logLevel == LogLevel.Trace;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
|
||||
{
|
||||
if (formatter != null)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(loggingDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(loggingDirectory);
|
||||
}
|
||||
|
||||
string path = Path.Combine(loggingDirectory, $"{categoryName}_service.{DateTime.Now.ToString("yyyy-MM-dd")}.log");
|
||||
string nl = Environment.NewLine;
|
||||
string err = "";
|
||||
|
||||
if (exception != null)
|
||||
{
|
||||
err = nl + exception.GetType() + ": " + exception.Message + nl + exception.StackTrace + nl;
|
||||
}
|
||||
|
||||
File.AppendAllText(path, logLevel.ToString() + ": [" + DateTime.Now.ToString() + "] " + formatter(state, exception) + nl + err);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(LogLevel.Warning.ToString() + ": [" + DateTime.Now.ToString() + "] Failed to write a log file. " + ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace WelsonJS.Service.Logging
|
||||
{
|
||||
public static class FileLoggerExtensions
|
||||
{
|
||||
public static ILoggerFactory AddDirectory(this ILoggerFactory factory, string loggingDirectory)
|
||||
{
|
||||
factory.AddProvider(new FileLoggerProvider(loggingDirectory));
|
||||
return factory;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace WelsonJS.Service.Logging
|
||||
{
|
||||
public class FileLoggerProvider : ILoggerProvider
|
||||
{
|
||||
private string loggingDirectory;
|
||||
|
||||
public FileLoggerProvider(string _loggingDirectory)
|
||||
{
|
||||
loggingDirectory = _loggingDirectory;
|
||||
}
|
||||
|
||||
public ILogger CreateLogger(string categoryName)
|
||||
{
|
||||
return new FileLogger(loggingDirectory, categoryName);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Dispose
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,17 +1,27 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.ServiceProcess;
|
||||
using System.Text;
|
||||
using WelsonJS.Service.Logging;
|
||||
|
||||
namespace WelsonJS.Service
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
private static ILogger logger;
|
||||
|
||||
/// <summary>
|
||||
/// 해당 애플리케이션의 주 진입점입니다.
|
||||
/// </summary>
|
||||
///
|
||||
static void Main(string[] args)
|
||||
{
|
||||
// create the logger
|
||||
ILoggerFactory factory = LoggerFactory.Create(builder => builder.AddConsole());
|
||||
factory.AddDirectory(Path.GetTempPath());
|
||||
logger = factory.CreateLogger("welsonjs");
|
||||
|
||||
// create the service
|
||||
if (Environment.UserInteractive)
|
||||
{
|
||||
Console.WriteLine("WelsonJS Service Application (User Interactive Mode)");
|
||||
|
@ -19,7 +29,7 @@ namespace WelsonJS.Service
|
|||
Console.WriteLine();
|
||||
Console.WriteLine("Service is running...");
|
||||
|
||||
ServiceMain svc = new ServiceMain(args);
|
||||
ServiceMain svc = new ServiceMain(args, logger);
|
||||
svc.TestStartupAndStop();
|
||||
}
|
||||
else
|
||||
|
@ -27,10 +37,27 @@ namespace WelsonJS.Service
|
|||
ServiceBase[] ServicesToRun;
|
||||
ServicesToRun = new ServiceBase[]
|
||||
{
|
||||
new ServiceMain(args)
|
||||
new ServiceMain(args, logger)
|
||||
};
|
||||
ServiceBase.Run(ServicesToRun);
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetAppDataPath()
|
||||
{
|
||||
string path = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
"WelsonJS"
|
||||
);
|
||||
|
||||
Directory.CreateDirectory(path);
|
||||
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
throw new IOException("Failed to create directory: " + path);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,11 +6,11 @@ using System.Runtime.InteropServices;
|
|||
// 제어됩니다. 어셈블리와 관련된 정보를 수정하려면
|
||||
// 이러한 특성 값을 변경하세요.
|
||||
[assembly: AssemblyTitle("WelsonJS.Service")]
|
||||
[assembly: AssemblyDescription("Windows Service for WelsonJS framework")]
|
||||
[assembly: AssemblyDescription("Windows Service for WelsonJS framework based applications")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Catswords")]
|
||||
[assembly: AssemblyProduct("WelsonJS")]
|
||||
[assembly: AssemblyCopyright("Catswords OSS, C-2021-000237, Opensource licensed under GPLv3 or MS-RL")]
|
||||
[assembly: AssemblyCopyright("Catswords OSS, GPLv3 or Ms-RL")]
|
||||
[assembly: AssemblyTrademark("WelsonJS")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
|
@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
|||
// 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호를
|
||||
// 기본값으로 할 수 있습니다.
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("0.2.7.26")]
|
||||
[assembly: AssemblyFileVersion("0.2.7.26")]
|
||||
[assembly: AssemblyVersion("0.2.7.54")]
|
||||
[assembly: AssemblyFileVersion("0.2.7.54")]
|
||||
|
|
|
@ -15,6 +15,7 @@ using System.Windows.Forms;
|
|||
using System.Linq;
|
||||
using Tesseract;
|
||||
using WelsonJS.Service;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
public class ScreenMatch
|
||||
{
|
||||
|
@ -105,6 +106,7 @@ public class ScreenMatch
|
|||
}
|
||||
|
||||
private ServiceMain parent;
|
||||
private ILogger logger;
|
||||
private List<Bitmap> templateImages;
|
||||
private string templateDirectoryPath;
|
||||
private string outputDirectoryPath;
|
||||
|
@ -130,7 +132,23 @@ public class ScreenMatch
|
|||
private void SetBusy(bool busy)
|
||||
{
|
||||
this.busy = busy;
|
||||
parent.Log($"State changed: busy={busy}");
|
||||
logger.LogInformation($"State changed: busy={busy}");
|
||||
}
|
||||
|
||||
private decimal GetScreenScalingFactor(Screen screen)
|
||||
{
|
||||
DEVMODE dm = new DEVMODE();
|
||||
dm.dmSize = (short)Marshal.SizeOf(typeof(DEVMODE));
|
||||
EnumDisplaySettings(screen.DeviceName, -1, ref dm);
|
||||
|
||||
decimal scalingFactor = Math.Round(Decimal.Divide(dm.dmPelsWidth, screen.Bounds.Width), 2);
|
||||
if (scalingFactor > 1)
|
||||
{
|
||||
logger.LogInformation($"Screen with scaling detected: {scalingFactor}x");
|
||||
logger.LogWarning("Please check the screen DPI.");
|
||||
}
|
||||
|
||||
return scalingFactor;
|
||||
}
|
||||
|
||||
public class TemplateInfo
|
||||
|
@ -157,9 +175,10 @@ public class ScreenMatch
|
|||
}
|
||||
}
|
||||
|
||||
public ScreenMatch(ServiceBase parent, string workingDirectory)
|
||||
public ScreenMatch(ServiceBase _parent, string workingDirectory, ILogger _logger)
|
||||
{
|
||||
this.parent = (ServiceMain)parent;
|
||||
parent = (ServiceMain)_parent;
|
||||
logger = _logger;
|
||||
|
||||
SetBusy(false);
|
||||
|
||||
|
@ -191,14 +210,14 @@ public class ScreenMatch
|
|||
string screen_time_params;
|
||||
try
|
||||
{
|
||||
screen_time_mode = this.parent.GetSettingsHandler().Read("SCREEN_TIME_MODE", "Service");
|
||||
screen_time_params = this.parent.GetSettingsHandler().Read("SCREEN_TIME_PARAMS", "Service");
|
||||
screen_time_mode = parent.ReadSettingsValue("SCREEN_TIME_MODE");
|
||||
screen_time_params = parent.ReadSettingsValue("SCREEN_TIME_PARAMS");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
screen_time_mode = null;
|
||||
screen_time_params = null;
|
||||
this.parent.Log($"Failed to read from configration file: {ex.Message}");
|
||||
logger.LogInformation($"Failed to read from configration file: {ex.Message}");
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(screen_time_params))
|
||||
|
@ -238,14 +257,14 @@ public class ScreenMatch
|
|||
case "backward":
|
||||
{
|
||||
isSearchFromEnd = true;
|
||||
this.parent.Log("Use the backward search when screen time");
|
||||
logger.LogInformation("Use the backward search when screen time");
|
||||
break;
|
||||
}
|
||||
|
||||
case "save":
|
||||
{
|
||||
isSaveToFile = true;
|
||||
this.parent.Log("Will be save an image file when capture the screens");
|
||||
logger.LogInformation("Will be save an image file when capture the screens");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -358,7 +377,7 @@ public class ScreenMatch
|
|||
catch (Exception ex)
|
||||
{
|
||||
files = new string[]{};
|
||||
parent.Log($"Failed to read the directory structure: {ex.Message}");
|
||||
logger.LogInformation($"Failed to read the directory structure: {ex.Message}");
|
||||
}
|
||||
|
||||
foreach (var file in files)
|
||||
|
@ -370,12 +389,12 @@ public class ScreenMatch
|
|||
if (!String.IsNullOrEmpty(altpath))
|
||||
{
|
||||
realpath = altpath;
|
||||
parent.Log($"Use the alternative image: {realpath}");
|
||||
logger.LogInformation($"Use the alternative image: {realpath}");
|
||||
}
|
||||
else
|
||||
{
|
||||
realpath = file;
|
||||
parent.Log($"Use the default image: {realpath}");
|
||||
logger.LogInformation($"Use the default image: {realpath}");
|
||||
}
|
||||
|
||||
Bitmap bitmap = new Bitmap(realpath)
|
||||
|
@ -442,21 +461,21 @@ public class ScreenMatch
|
|||
Screen screen = Screen.AllScreens[i];
|
||||
Bitmap mainImage = CaptureScreen(screen);
|
||||
|
||||
Bitmap image = templateImages[templateCurrentIndex];
|
||||
string templateName = image.Tag as string;
|
||||
Bitmap templateImage = templateImages[templateCurrentIndex];
|
||||
string templateName = templateImage.Tag as string;
|
||||
TemplateInfo nextTemplateInfo = parent.GetNextTemplateInfo();
|
||||
|
||||
Size templateSize = new Size
|
||||
{
|
||||
Width = image.Width,
|
||||
Height = image.Height
|
||||
Width = templateImage.Width,
|
||||
Height = templateImage.Height
|
||||
};
|
||||
|
||||
parent.Log($"Trying match the template {templateName} on the screen {i}...");
|
||||
logger.LogInformation($"Trying match the template {templateName} on the screen {i}...");
|
||||
|
||||
if (!String.IsNullOrEmpty(nextTemplateInfo.FileName) && templateName != nextTemplateInfo.FileName)
|
||||
{
|
||||
parent.Log($"Ignored the template {templateName}");
|
||||
logger.LogInformation($"Ignored the template {templateName}");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -477,7 +496,7 @@ public class ScreenMatch
|
|||
{
|
||||
string out_filepath = Path.Combine(outputDirectoryPath, out_filename);
|
||||
((Bitmap)out_mainImage.Clone()).Save(out_filepath);
|
||||
parent.Log($"Screenshot saved: {out_filepath}");
|
||||
logger.LogInformation($"Screenshot saved: {out_filepath}");
|
||||
}
|
||||
|
||||
// List to store the positions of matched templates in the main image
|
||||
|
@ -486,28 +505,26 @@ public class ScreenMatch
|
|||
// If the index value is negative, retrieve and use an outdated image from the queue
|
||||
if (nextTemplateInfo.Index < 0)
|
||||
{
|
||||
logger.LogInformation($"Finding a previous screen of {nextTemplateInfo.FileName}...");
|
||||
|
||||
Bitmap outdatedImage = null;
|
||||
|
||||
parent.Log($"Finding a previous screen of {nextTemplateInfo.FileName}...");
|
||||
|
||||
try
|
||||
{
|
||||
while (outdatedSamples.Count > 0)
|
||||
// Since outdatedSamples is also used to detect duplicate work, we do not delete tasks with Dequeue.
|
||||
foreach (var image in outdatedSamples)
|
||||
{
|
||||
outdatedImage = outdatedSamples.Dequeue();
|
||||
if (outdatedImage.Tag != null)
|
||||
if (image.Tag != null &&
|
||||
((SampleInfo)image.Tag).FileName == nextTemplateInfo.FileName)
|
||||
{
|
||||
if (((SampleInfo)outdatedImage.Tag).FileName == nextTemplateInfo.FileName)
|
||||
{
|
||||
parent.Log($"Found the previous screen of {nextTemplateInfo.FileName}");
|
||||
break;
|
||||
}
|
||||
outdatedImage = image;
|
||||
logger.LogInformation($"Found the previous screen of {nextTemplateInfo.FileName}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
parent.Log($"Error finding a previous screen: {ex.Message}");
|
||||
logger.LogInformation($"Error finding a previous screen: {ex.Message}");
|
||||
}
|
||||
|
||||
// Find the matching positions of the outdated image in the main image
|
||||
|
@ -515,23 +532,23 @@ public class ScreenMatch
|
|||
matchPositions = FindTemplate(out_mainImage, outdatedImage);
|
||||
if (matchPositions.Count > 0)
|
||||
{
|
||||
parent.Log("Match found with the outdated image");
|
||||
logger.LogInformation("Match found with the outdated image");
|
||||
}
|
||||
else
|
||||
{
|
||||
parent.Log("No match found with the outdated image");
|
||||
logger.LogInformation("No match found with the outdated image");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
parent.Log("Not found a outdated image");
|
||||
logger.LogInformation("No match found an outdated image");
|
||||
matchPositions = new List<Point>();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the index is not negative, use the current image for template matching
|
||||
matchPositions = FindTemplate(out_mainImage, (Bitmap)image.Clone());
|
||||
matchPositions = FindTemplate(out_mainImage, (Bitmap)templateImage.Clone());
|
||||
}
|
||||
|
||||
foreach (Point matchPosition in matchPositions)
|
||||
|
@ -553,18 +570,18 @@ public class ScreenMatch
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
parent.Log($"Ignore the match. {ex.Message}");
|
||||
logger.LogInformation($"Ignore the match. {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (results.Count > 0)
|
||||
{
|
||||
parent.Log("Match found");
|
||||
logger.LogInformation("Match found");
|
||||
}
|
||||
else
|
||||
{
|
||||
parent.Log($"No match found");
|
||||
logger.LogInformation($"No match found");
|
||||
}
|
||||
|
||||
templateCurrentIndex = ++templateCurrentIndex % templateImages.Count;
|
||||
|
@ -622,24 +639,24 @@ public class ScreenMatch
|
|||
else
|
||||
{
|
||||
outdatedSamples.Enqueue(croppedNodupBitmap);
|
||||
parent.Log($"Added to the image queue. {templateName}");
|
||||
logger.LogInformation($"Added to the image queue. {templateName}");
|
||||
}
|
||||
}
|
||||
|
||||
// if use Clipboard
|
||||
if (sampleClipboard.Contains(templateName))
|
||||
{
|
||||
parent.Log($"Trying to use the clipboard... {templateName}");
|
||||
logger.LogInformation($"Trying to use the clipboard... {templateName}");
|
||||
Thread th = new Thread(new ThreadStart(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Clipboard.SetImage((Bitmap)croppedBitmap.Clone());
|
||||
parent.Log($"Copied the image to Clipboard");
|
||||
logger.LogInformation($"Copied the image to Clipboard");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
parent.Log($"Failed to copy to the clipboard: {ex.Message}");
|
||||
logger.LogInformation($"Failed to copy to the clipboard: {ex.Message}");
|
||||
}
|
||||
}));
|
||||
th.SetApartmentState(ApartmentState.STA);
|
||||
|
@ -657,14 +674,14 @@ public class ScreenMatch
|
|||
{
|
||||
text = page.GetText();
|
||||
|
||||
parent.Log($"Mean confidence: {page.GetMeanConfidence()}");
|
||||
parent.Log($"Text (GetText): {text}");
|
||||
logger.LogInformation($"Mean confidence: {page.GetMeanConfidence()}");
|
||||
logger.LogInformation($"Text (GetText): {text}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
parent.Log($"Failed to OCR: {ex.Message}");
|
||||
logger.LogInformation($"Failed to OCR: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -674,13 +691,7 @@ public class ScreenMatch
|
|||
public Bitmap CaptureScreen(Screen screen)
|
||||
{
|
||||
Rectangle screenSize = screen.Bounds;
|
||||
|
||||
DEVMODE dm = new DEVMODE();
|
||||
dm.dmSize = (short)Marshal.SizeOf(typeof(DEVMODE));
|
||||
EnumDisplaySettings(screen.DeviceName, -1, ref dm);
|
||||
|
||||
var scalingFactor = Math.Round(Decimal.Divide(dm.dmPelsWidth, screen.Bounds.Width), 2);
|
||||
parent.Log($"Resolved the screen scale: {scalingFactor}");
|
||||
decimal scalingFactor = GetScreenScalingFactor(screen);
|
||||
|
||||
int adjustedWidth = (int)(screenSize.Width * scalingFactor);
|
||||
int adjustedHeight = (int)(screenSize.Height * scalingFactor);
|
||||
|
@ -743,13 +754,13 @@ public class ScreenMatch
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
parent.Log($"Ignore the match. {ex.Message}");
|
||||
logger.LogInformation($"Ignore the match. {ex.Message}");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
parent.Log($"Error {ex.Message}");
|
||||
logger.LogInformation($"Error {ex.Message}");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -34,26 +34,27 @@ using System.Collections.Generic;
|
|||
using WelsonJS.TinyINIController;
|
||||
using System.Collections;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace WelsonJS.Service
|
||||
{
|
||||
public partial class ServiceMain : ServiceBase
|
||||
{
|
||||
private readonly string appName = "WelsonJS";
|
||||
private readonly static string applicationName = "WelsonJS";
|
||||
private static List<Timer> timers;
|
||||
private ILogger logger;
|
||||
private string workingDirectory;
|
||||
private string scriptName;
|
||||
private string scriptFilePath;
|
||||
private string scriptText;
|
||||
private ScriptControl scriptControl;
|
||||
private string logFilePath;
|
||||
private string[] args;
|
||||
private bool disabledHeartbeat = false;
|
||||
private bool disabledScreenTime = false;
|
||||
private bool disabledFileMonitor = false;
|
||||
private ScreenMatch screenMatcher;
|
||||
private FileEventMonitor fileEventMonitor;
|
||||
private IniFile settingsHandler;
|
||||
private IniFile settingsFileHandler;
|
||||
private UserVariables userVariablesHandler;
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
|
@ -61,15 +62,13 @@ namespace WelsonJS.Service
|
|||
|
||||
private static int SM_REMOTESESSION = 0x1000;
|
||||
|
||||
public ServiceMain(string[] args)
|
||||
public ServiceMain(string[] _args, ILogger _logger)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// set service arguments
|
||||
this.args = args;
|
||||
|
||||
// set the log file path
|
||||
logFilePath = Path.Combine(Path.GetTempPath(), "welsonjs_service.log");
|
||||
// set arguments and logger
|
||||
args = _args;
|
||||
logger = _logger;
|
||||
|
||||
// mapping arguments to each variables
|
||||
var arguments = ParseArguments(this.args);
|
||||
|
@ -109,13 +108,13 @@ namespace WelsonJS.Service
|
|||
// set working directory
|
||||
if (string.IsNullOrEmpty(workingDirectory))
|
||||
{
|
||||
workingDirectory = Path.Combine(Path.GetTempPath(), appName);
|
||||
Log("Working directory not provided. Using default value: " + workingDirectory);
|
||||
workingDirectory = Path.Combine(Path.GetTempPath(), applicationName);
|
||||
logger.LogInformation("Working directory not provided. Using default value: " + workingDirectory);
|
||||
|
||||
if (!Directory.Exists(workingDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(workingDirectory);
|
||||
Log("Directory created: " + workingDirectory);
|
||||
logger.LogInformation("Directory created: " + workingDirectory);
|
||||
}
|
||||
}
|
||||
Directory.SetCurrentDirectory(workingDirectory);
|
||||
|
@ -126,20 +125,20 @@ namespace WelsonJS.Service
|
|||
{
|
||||
try
|
||||
{
|
||||
settingsHandler = new IniFile(settingsFilePath);
|
||||
settingsFileHandler = new IniFile(settingsFilePath);
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception ex)
|
||||
{
|
||||
settingsHandler = null;
|
||||
logger.LogWarning(ex.Message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log($"Configuration file not found: {settingsFilePath}");
|
||||
logger.LogInformation($"Configuration file not found: {settingsFilePath}");
|
||||
}
|
||||
|
||||
// read configrations from settings.ini
|
||||
if (settingsHandler != null)
|
||||
if (settingsFileHandler != null)
|
||||
{
|
||||
string[] configNames = new string[]
|
||||
{
|
||||
|
@ -151,7 +150,7 @@ namespace WelsonJS.Service
|
|||
{
|
||||
try
|
||||
{
|
||||
if ("true" == GetSettingsHandler().Read(configName, "Service"))
|
||||
if ("true" == ReadSettingsValue(configName))
|
||||
{
|
||||
switch (configName)
|
||||
{
|
||||
|
@ -174,7 +173,7 @@ namespace WelsonJS.Service
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"{configName} is ignored: {ex.Message}");
|
||||
logger.LogInformation($"{configName} is ignored: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -183,7 +182,7 @@ namespace WelsonJS.Service
|
|||
if (string.IsNullOrEmpty(scriptName))
|
||||
{
|
||||
scriptName = "defaultService";
|
||||
Log($"Script name not provided. Using default value: {scriptName}");
|
||||
logger.LogInformation($"Script name not provided. Using default value: {scriptName}");
|
||||
}
|
||||
|
||||
// set path of the script
|
||||
|
@ -192,7 +191,7 @@ namespace WelsonJS.Service
|
|||
// start the heartbeat
|
||||
if (!disabledHeartbeat)
|
||||
{
|
||||
HeartbeatClient heartbeatClient = new HeartbeatClient(this);
|
||||
HeartbeatClient heartbeatClient = new HeartbeatClient(this, logger);
|
||||
Task.Run(heartbeatClient.StartHeartbeatAsync);
|
||||
Task.Run(heartbeatClient.StartEventListenerAsync);
|
||||
}
|
||||
|
@ -207,19 +206,27 @@ namespace WelsonJS.Service
|
|||
|
||||
// check this session is the user interactive mode
|
||||
if (Environment.UserInteractive) {
|
||||
this.OnUserInteractiveEnvironment();
|
||||
OnUserInteractiveEnvironment();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log("Disabled the User Interactive Mode. (e.g., OnScreenTime)");
|
||||
logger.LogInformation("Disabled the User Interactive Mode. (e.g., OnScreenTime)");
|
||||
}
|
||||
|
||||
Log(appName + " Service Loaded");
|
||||
logger.LogInformation(applicationName + " Service Loaded");
|
||||
}
|
||||
|
||||
public IniFile GetSettingsHandler()
|
||||
public string ReadSettingsValue(string key, string defaultValue = null)
|
||||
{
|
||||
return settingsHandler;
|
||||
if (settingsFileHandler != null)
|
||||
{
|
||||
return settingsFileHandler.Read(key, "Service") ?? defaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogWarning("Unable to read the value. It seems that settings.ini is not configured correctly.");
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public UserVariables GetUserVariablesHandler()
|
||||
|
@ -241,7 +248,7 @@ namespace WelsonJS.Service
|
|||
// Check exists the entry script file
|
||||
if (File.Exists(scriptFilePath))
|
||||
{
|
||||
Log($"Script file found: {scriptFilePath}");
|
||||
logger.LogInformation($"Script file found: {scriptFilePath}");
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -281,35 +288,35 @@ namespace WelsonJS.Service
|
|||
}
|
||||
|
||||
// initialize
|
||||
Log(DispatchServiceEvent("start", startArguments));
|
||||
logger.LogInformation(DispatchServiceEvent("start", startArguments));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"Failed to start because of {ex.Message}");
|
||||
logger.LogInformation($"Failed to start because of {ex.Message}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log($"Script file not found: {scriptFilePath}");
|
||||
logger.LogInformation($"Script file not found: {scriptFilePath}");
|
||||
}
|
||||
|
||||
// Trace a Sysmon file events (If Sysinternals Sysmon installed)
|
||||
if (!disabledFileMonitor)
|
||||
{
|
||||
fileEventMonitor = new FileEventMonitor(this, workingDirectory);
|
||||
fileEventMonitor = new FileEventMonitor(this, workingDirectory, logger);
|
||||
fileEventMonitor.Start();
|
||||
|
||||
Log("File Event Monitor Started");
|
||||
logger.LogInformation("File Event Monitor Started");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log("File Event Monitor is Disabled");
|
||||
logger.LogInformation("File Event Monitor is Disabled");
|
||||
}
|
||||
|
||||
// Start all the registered timers
|
||||
timers.ForEach(timer => timer?.Start());
|
||||
timers.ForEach(timer => timer?.Start());
|
||||
|
||||
Log(appName + " Service Started");
|
||||
logger.LogInformation(applicationName + " Service Started");
|
||||
}
|
||||
|
||||
protected override void OnStop()
|
||||
|
@ -323,16 +330,16 @@ namespace WelsonJS.Service
|
|||
// dispatch stop callback
|
||||
try
|
||||
{
|
||||
Log(DispatchServiceEvent("stop"));
|
||||
logger.LogInformation(DispatchServiceEvent("stop"));
|
||||
scriptControl?.Reset();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log("Exception when stop: " + ex.Message);
|
||||
logger.LogInformation("Exception when stop: " + ex.Message);
|
||||
}
|
||||
scriptControl = null;
|
||||
|
||||
Log(appName + " Service Stopped");
|
||||
logger.LogInformation(applicationName + " Service Stopped");
|
||||
}
|
||||
|
||||
private void OnUserInteractiveEnvironment()
|
||||
|
@ -341,13 +348,13 @@ namespace WelsonJS.Service
|
|||
if (GetSystemMetrics(SM_REMOTESESSION) > 0)
|
||||
{
|
||||
disabledScreenTime = true;
|
||||
Log("This application may not work correctly in a remote desktop session");
|
||||
logger.LogInformation("This application may not work correctly in a remote desktop session");
|
||||
}
|
||||
|
||||
// set screen timer
|
||||
if (!disabledScreenTime)
|
||||
{
|
||||
screenMatcher = new ScreenMatch(this, workingDirectory);
|
||||
screenMatcher = new ScreenMatch(this, workingDirectory, logger);
|
||||
|
||||
Timer screenTimer = new Timer
|
||||
{
|
||||
|
@ -356,13 +363,13 @@ namespace WelsonJS.Service
|
|||
screenTimer.Elapsed += OnScreenTime;
|
||||
timers.Add(screenTimer);
|
||||
|
||||
Log("Screen Time Event Enabled");
|
||||
logger.LogInformation("Screen Time Event Enabled");
|
||||
}
|
||||
else
|
||||
{
|
||||
disabledScreenTime = true;
|
||||
|
||||
Log("Screen Time Event Disabled");
|
||||
logger.LogInformation("Screen Time Event Disabled");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -370,11 +377,11 @@ namespace WelsonJS.Service
|
|||
{
|
||||
try
|
||||
{
|
||||
Log(DispatchServiceEvent("elapsedTime"));
|
||||
logger.LogInformation(DispatchServiceEvent("elapsedTime"));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log("Exception when elapsed time: " + ex.Message);
|
||||
logger.LogInformation("Exception when elapsed time: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -385,7 +392,7 @@ namespace WelsonJS.Service
|
|||
List<ScreenMatchResult> matchedResults = screenMatcher.CaptureAndMatch();
|
||||
matchedResults.ForEach(result =>
|
||||
{
|
||||
Log(DispatchServiceEvent("screenTemplateMatched", new string[]
|
||||
logger.LogInformation(DispatchServiceEvent("screenTemplateMatched", new string[]
|
||||
{
|
||||
result.FileName,
|
||||
result.ScreenNumber.ToString(),
|
||||
|
@ -396,7 +403,7 @@ namespace WelsonJS.Service
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"Waiting a next screen time... {ex.Message}");
|
||||
logger.LogInformation($"Waiting a next screen time... {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -416,7 +423,7 @@ namespace WelsonJS.Service
|
|||
}
|
||||
else
|
||||
{
|
||||
Log("InvokeScriptMethod Ignored: " + methodName);
|
||||
logger.LogInformation("InvokeScriptMethod Ignored: " + methodName);
|
||||
}
|
||||
|
||||
return "void";
|
||||
|
@ -434,7 +441,7 @@ namespace WelsonJS.Service
|
|||
if (index > 2)
|
||||
{
|
||||
var key = arg.Substring(2, index - 2);
|
||||
var value = arg.Substring(index + 1);
|
||||
var value = arg.Substring(index + 1).Trim('"');
|
||||
arguments[key] = value;
|
||||
}
|
||||
else
|
||||
|
@ -467,7 +474,7 @@ namespace WelsonJS.Service
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"Use all templates because of {ex.Message}");
|
||||
logger.LogInformation($"Use all templates because of {ex.Message}");
|
||||
}
|
||||
|
||||
return new ScreenMatch.TemplateInfo(templateName, index);
|
||||
|
@ -485,27 +492,5 @@ namespace WelsonJS.Service
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
public void Log(string message)
|
||||
{
|
||||
string _message = $"{DateTime.Now}: {message}";
|
||||
|
||||
if (Environment.UserInteractive)
|
||||
{
|
||||
Console.WriteLine(_message);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using (StreamWriter writer = new StreamWriter(logFilePath, true))
|
||||
{
|
||||
writer.WriteLine(_message);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"LOGGING FAILED: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,10 +9,11 @@ namespace WelsonJS.Service
|
|||
{
|
||||
private ServiceMain parent;
|
||||
private Dictionary<string, string> userVariables;
|
||||
private readonly string envFilePath = Path.Combine(Path.GetTempPath(), "welsonjs_default.env");
|
||||
private string envFilePath;
|
||||
|
||||
public UserVariables(ServiceBase parent)
|
||||
{
|
||||
envFilePath = Path.Combine(Program.GetAppDataPath(), "welsonjs_default.env");
|
||||
this.parent = (ServiceMain)parent;
|
||||
}
|
||||
|
||||
|
@ -51,13 +52,13 @@ namespace WelsonJS.Service
|
|||
}
|
||||
else
|
||||
{
|
||||
parent.Log($"Error parsing line: '{pair}'.");
|
||||
throw new Exception($"Error parsing line: '{pair}'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
parent.Log($"Error loading variable file: {ex.Message}");
|
||||
Console.WriteLine($"Error loading variable file: {ex.Message}");
|
||||
userVariables = new Dictionary<string, string>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -125,12 +125,42 @@
|
|||
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="Microsoft.Extensions.Configuration, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Extensions.Configuration.8.0.0\lib\net462\Microsoft.Extensions.Configuration.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.Configuration.Abstractions, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Extensions.Configuration.Abstractions.8.0.0\lib\net462\Microsoft.Extensions.Configuration.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.Configuration.Binder, Version=8.0.0.2, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Extensions.Configuration.Binder.8.0.2\lib\net462\Microsoft.Extensions.Configuration.Binder.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.DependencyInjection, Version=8.0.0.1, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.8.0.1\lib\net462\Microsoft.Extensions.DependencyInjection.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=8.0.0.2, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.8.0.2\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.Logging, Version=8.0.0.1, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Extensions.Logging.8.0.1\lib\net462\Microsoft.Extensions.Logging.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=8.0.0.2, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.8.0.2\lib\net462\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.Logging.Configuration, Version=8.0.0.1, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Extensions.Logging.Configuration.8.0.1\lib\net462\Microsoft.Extensions.Logging.Configuration.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.Logging.Console, Version=8.0.0.1, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Extensions.Logging.Console.8.0.1\lib\net462\Microsoft.Extensions.Logging.Console.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.Options, Version=8.0.0.2, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Extensions.Options.8.0.2\lib\net462\Microsoft.Extensions.Options.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.Options.ConfigurationExtensions, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Extensions.Options.ConfigurationExtensions.8.0.0\lib\net462\Microsoft.Extensions.Options.ConfigurationExtensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Extensions.Primitives, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Extensions.Primitives.8.0.0\lib\net462\Microsoft.Extensions.Primitives.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="RestSharp, Version=112.1.0.0, Culture=neutral, PublicKeyToken=598062e77f915f75, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\RestSharp.112.1.0\lib\net48\RestSharp.dll</HintPath>
|
||||
</Reference>
|
||||
|
@ -138,6 +168,7 @@
|
|||
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||
<Reference Include="System.Configuration.Install" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Diagnostics.DiagnosticSource, Version=8.0.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
|
@ -159,6 +190,7 @@
|
|||
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime" />
|
||||
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
||||
</Reference>
|
||||
|
@ -185,6 +217,9 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="FileEventMonitor.cs" />
|
||||
<Compile Include="HeartbeatClient.cs" />
|
||||
<Compile Include="Logging\FileLogger.cs" />
|
||||
<Compile Include="Logging\FileLoggerExtensions.cs" />
|
||||
<Compile Include="Logging\FileLoggerProvider.cs" />
|
||||
<Compile Include="Model\FileMatchResult.cs" />
|
||||
<Compile Include="ServiceMain.cs">
|
||||
<SubType>Component</SubType>
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Extensions.DependencyInjection.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-8.0.0.1" newVersion="8.0.0.1" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-8.0.0.2" newVersion="8.0.0.2" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="RestSharp" publicKeyToken="598062e77f915f75" culture="neutral" />
|
||||
|
@ -87,6 +87,14 @@
|
|||
<assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.2.0.1" newVersion="4.2.0.1" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Extensions.Options" publicKeyToken="adb9793829ddae60" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-8.0.0.2" newVersion="8.0.0.2" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Extensions.Configuration.Binder" publicKeyToken="adb9793829ddae60" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-8.0.0.2" newVersion="8.0.0.2" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
|
|
|
@ -10,8 +10,18 @@
|
|||
<package id="Grpc.Net.Common" version="2.66.0" targetFramework="net48" />
|
||||
<package id="Grpc.Tools" version="2.67.0" targetFramework="net48" developmentDependency="true" />
|
||||
<package id="Microsoft.Bcl.AsyncInterfaces" version="8.0.0" targetFramework="net48" />
|
||||
<package id="Microsoft.Extensions.Configuration" version="8.0.0" targetFramework="net48" />
|
||||
<package id="Microsoft.Extensions.Configuration.Abstractions" version="8.0.0" targetFramework="net48" />
|
||||
<package id="Microsoft.Extensions.Configuration.Binder" version="8.0.2" targetFramework="net48" />
|
||||
<package id="Microsoft.Extensions.DependencyInjection" version="8.0.1" targetFramework="net48" />
|
||||
<package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="8.0.2" targetFramework="net48" />
|
||||
<package id="Microsoft.Extensions.Logging" version="8.0.1" targetFramework="net48" />
|
||||
<package id="Microsoft.Extensions.Logging.Abstractions" version="8.0.2" targetFramework="net48" />
|
||||
<package id="Microsoft.Extensions.Logging.Configuration" version="8.0.1" targetFramework="net48" />
|
||||
<package id="Microsoft.Extensions.Logging.Console" version="8.0.1" targetFramework="net48" />
|
||||
<package id="Microsoft.Extensions.Options" version="8.0.2" targetFramework="net48" />
|
||||
<package id="Microsoft.Extensions.Options.ConfigurationExtensions" version="8.0.0" targetFramework="net48" />
|
||||
<package id="Microsoft.Extensions.Primitives" version="8.0.0" targetFramework="net48" />
|
||||
<package id="RestSharp" version="112.1.0" targetFramework="net48" />
|
||||
<package id="System.Buffers" version="4.5.1" targetFramework="net48" />
|
||||
<package id="System.Diagnostics.DiagnosticSource" version="8.0.1" targetFramework="net48" />
|
||||
|
|
614
WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/ARIA.cs
Normal file
614
WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/ARIA.cs
Normal file
|
@ -0,0 +1,614 @@
|
|||
/*
|
||||
* WelsonJS.Toolkit: WelsonJS native component
|
||||
*
|
||||
* filename:
|
||||
* ARIA.cs
|
||||
*
|
||||
* description:
|
||||
* ARIA(KS X 1213-1, RFC5794, RFC6209) cryptography algorithm implementation (Experimental)
|
||||
*
|
||||
* website:
|
||||
* - https://github.com/gnh1201/welsonjs
|
||||
* - https://catswords.social/@catswords_oss
|
||||
* - https://teams.live.com/l/community/FEACHncAhq8ldnojAI
|
||||
* - https://discord.gg/XKG5CjtXEj
|
||||
*
|
||||
* authors:
|
||||
* - Namhyeon Go (@gnh1201) <abuse@catswords.net>
|
||||
* - @angelkum (blog.naver.com)
|
||||
* - KISA(Korea Internet & Security Agency) (kisa.or.kr)
|
||||
* - National Security Research Institute (NSRI)
|
||||
* - National Intelligence Service (nis.go.kr)
|
||||
*
|
||||
* references:
|
||||
* - https://seed.kisa.or.kr/kisa/Board/19/detailView.do
|
||||
* - https://blog.naver.com/angelkum/130154153446
|
||||
* - https://www.ncsc.go.kr:4018/PageLink.do?link=forward:/PageContent.do&tempParam1=&menuNo=060000&subMenuNo=060200&thirdMenuNo=
|
||||
* - https://www.nis.go.kr/AF/1_7_3_1.do
|
||||
* - https://datatracker.ietf.org/doc/html/rfc5794
|
||||
* - https://datatracker.ietf.org/doc/html/rfc6209
|
||||
* - https://github.com/eGovFrame/egovframework.rte.root/blob/master/Foundation/egovframework.rte.fdl.crypto/src/main/java/egovframework/rte/fdl/cryptography/impl/aria/ARIAEngine.java
|
||||
* - https://ics.catswords.net/ARIA-specification.pdf
|
||||
* - https://ics.catswords.net/ARIA-testvector.pdf
|
||||
*
|
||||
* license:
|
||||
* GPLv3 or MS-RL(Microsoft Reciprocal License)
|
||||
*
|
||||
*/
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace WelsonJS.Cryptography
|
||||
{
|
||||
public class ARIA
|
||||
{
|
||||
private static readonly uint[,] KRK = new uint[,] {
|
||||
{0x517cc1b7, 0x27220a94, 0xfe13abe8, 0xfa9a6ee0},
|
||||
{0x6db14acc, 0x9e21c820, 0xff28b1d5, 0xef5de2b0},
|
||||
{0xdb92371d, 0x2126e970, 0x03249775, 0x04e8c90e}
|
||||
};
|
||||
|
||||
private static readonly byte[] S1 = new byte[256];
|
||||
private static readonly byte[] S2 = new byte[256];
|
||||
private static readonly byte[] X1 = new byte[256];
|
||||
private static readonly byte[] X2 = new byte[256];
|
||||
|
||||
private static readonly uint[] TS1 = new uint[256];
|
||||
private static readonly uint[] TS2 = new uint[256];
|
||||
private static readonly uint[] TX1 = new uint[256];
|
||||
private static readonly uint[] TX2 = new uint[256];
|
||||
|
||||
// Static initializer. For setting up the tables
|
||||
static ARIA()
|
||||
{
|
||||
uint[] exp = new uint[256];
|
||||
uint[] log = new uint[256];
|
||||
exp[0] = 1;
|
||||
for (int i = 1; i < 256; i++)
|
||||
{
|
||||
uint j = (exp[i - 1] << 1) ^ exp[i - 1];
|
||||
if ((j & 0x100) != 0) j ^= 0x11b;
|
||||
exp[i] = j;
|
||||
}
|
||||
for (int i = 1; i < 255; i++)
|
||||
log[exp[i]] = (uint)i;
|
||||
|
||||
uint[,] A = new uint[,] {
|
||||
{1, 0, 0, 0, 1, 1, 1, 1},
|
||||
{1, 1, 0, 0, 0, 1, 1, 1},
|
||||
{1, 1, 1, 0, 0, 0, 1, 1},
|
||||
{1, 1, 1, 1, 0, 0, 0, 1},
|
||||
{1, 1, 1, 1, 1, 0, 0, 0},
|
||||
{0, 1, 1, 1, 1, 1, 0, 0},
|
||||
{0, 0, 1, 1, 1, 1, 1, 0},
|
||||
{0, 0, 0, 1, 1, 1, 1, 1}
|
||||
};
|
||||
|
||||
uint[,] B = new uint[,] {
|
||||
{0, 1, 0, 1, 1, 1, 1, 0},
|
||||
{0, 0, 1, 1, 1, 1, 0, 1},
|
||||
{1, 1, 0, 1, 0, 1, 1, 1},
|
||||
{1, 0, 0, 1, 1, 1, 0, 1},
|
||||
{0, 0, 1, 0, 1, 1, 0, 0},
|
||||
{1, 0, 0, 0, 0, 0, 0, 1},
|
||||
{0, 1, 0, 1, 1, 1, 0, 1},
|
||||
{1, 1, 0, 1, 0, 0, 1, 1}
|
||||
};
|
||||
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
uint t = 0, p;
|
||||
if (i == 0)
|
||||
p = 0;
|
||||
else
|
||||
p = exp[255 - log[i]];
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
uint s = 0;
|
||||
for (int k = 0; k < 8; k++)
|
||||
{
|
||||
if (((p >> (7 - k)) & 0x01) != 0)
|
||||
s ^= A[k, j];
|
||||
}
|
||||
t = (t << 1) ^ s;
|
||||
}
|
||||
t ^= 0x63;
|
||||
S1[i] = (byte)t;
|
||||
X1[t] = (byte)i;
|
||||
}
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
uint t = 0, p;
|
||||
if (i == 0)
|
||||
p = 0;
|
||||
else
|
||||
p = exp[(247 * log[i]) % 255];
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
uint s = 0;
|
||||
for (int k = 0; k < 8; k++)
|
||||
{
|
||||
if (((p >> k) & 0x01) != 0)
|
||||
s ^= B[7 - j, k];
|
||||
}
|
||||
t = (t << 1) ^ s;
|
||||
}
|
||||
t ^= 0xe2;
|
||||
S2[i] = (byte)t;
|
||||
X2[t] = (byte)i;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
TS1[i] = (uint)0x00010101 * (S1[i] & (uint)0xff);
|
||||
TS2[i] = (uint)0x01000101 * (S2[i] & (uint)0xff);
|
||||
TX1[i] = (uint)0x01010001 * (X1[i] & (uint)0xff);
|
||||
TX2[i] = (uint)0x01010100 * (X2[i] & (uint)0xff);
|
||||
}
|
||||
}
|
||||
|
||||
private int keySize = 0;
|
||||
private int numberOfRounds = 0;
|
||||
private byte[] masterKey = null;
|
||||
private uint[] encRoundKeys = null, decRoundKeys = null;
|
||||
|
||||
public ARIA(int keySize)
|
||||
{
|
||||
SetKeySize(keySize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the class so that it can be reused for another master key.
|
||||
*/
|
||||
private void Reset()
|
||||
{
|
||||
keySize = 0;
|
||||
numberOfRounds = 0;
|
||||
masterKey = null;
|
||||
encRoundKeys = null;
|
||||
decRoundKeys = null;
|
||||
}
|
||||
|
||||
public int GetKeySize()
|
||||
{
|
||||
return keySize;
|
||||
}
|
||||
|
||||
private void SetKeySize(int _keySize)
|
||||
{
|
||||
Reset();
|
||||
|
||||
if (_keySize != 128 && _keySize != 192 && _keySize != 256)
|
||||
throw new CryptographicException("keySize=" + _keySize);
|
||||
|
||||
switch (_keySize)
|
||||
{
|
||||
case 128:
|
||||
numberOfRounds = 12;
|
||||
break;
|
||||
case 192:
|
||||
numberOfRounds = 14;
|
||||
break;
|
||||
case 256:
|
||||
numberOfRounds = 16;
|
||||
break;
|
||||
}
|
||||
|
||||
keySize = _keySize;
|
||||
}
|
||||
|
||||
private void SetKey(byte[] masterKey)
|
||||
{
|
||||
if (masterKey.Length * 8 < keySize)
|
||||
throw new CryptographicException("masterKey size=" + masterKey.Length);
|
||||
|
||||
decRoundKeys = null;
|
||||
encRoundKeys = null;
|
||||
masterKey = (byte[])masterKey.Clone();
|
||||
}
|
||||
|
||||
private void SetupEncRoundKeys()
|
||||
{
|
||||
if (keySize == 0)
|
||||
throw new CryptographicException("keySize");
|
||||
if (masterKey == null)
|
||||
throw new CryptographicException("masterKey");
|
||||
if (encRoundKeys == null)
|
||||
encRoundKeys = new uint[4 * (numberOfRounds + 1)];
|
||||
|
||||
decRoundKeys = null;
|
||||
DoEncKeySetup(masterKey, encRoundKeys, keySize);
|
||||
}
|
||||
|
||||
void SetupDecRoundKeys()
|
||||
{
|
||||
if (keySize == 0)
|
||||
throw new CryptographicException("keySize");
|
||||
|
||||
if (encRoundKeys == null)
|
||||
{
|
||||
if (masterKey == null)
|
||||
{
|
||||
throw new CryptographicException("masterKey");
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupEncRoundKeys();
|
||||
}
|
||||
}
|
||||
|
||||
decRoundKeys = (uint[])encRoundKeys.Clone();
|
||||
DoDecKeySetup(masterKey, decRoundKeys, keySize);
|
||||
}
|
||||
|
||||
public void SetupRoundKeys()
|
||||
{
|
||||
SetupDecRoundKeys();
|
||||
}
|
||||
|
||||
private static void DoCrypt(byte[] i, int ioffset, uint[] rk, int nr, byte[] o, int ooffset)
|
||||
{
|
||||
uint t0, t1, t2, t3, j = 0;
|
||||
|
||||
t0 = ToInt(i[0 + ioffset], i[1 + ioffset], i[2 + ioffset], i[3 + ioffset]);
|
||||
t1 = ToInt(i[4 + ioffset], i[5 + ioffset], i[6 + ioffset], i[7 + ioffset]);
|
||||
t2 = ToInt(i[8 + ioffset], i[9 + ioffset], i[10 + ioffset], i[11 + ioffset]);
|
||||
t3 = ToInt(i[12 + ioffset], i[13 + ioffset], i[14 + ioffset], i[15 + ioffset]);
|
||||
|
||||
for (int r = 1; r < nr / 2; r++)
|
||||
{
|
||||
t0 ^= rk[j++]; t1 ^= rk[j++]; t2 ^= rk[j++]; t3 ^= rk[j++];
|
||||
t0 = TS1[(t0 >> 24) & 0xff] ^ TS2[(t0 >> 16) & 0xff] ^ TX1[(t0 >> 8) & 0xff] ^ TX2[t0 & 0xff];
|
||||
t1 = TS1[(t1 >> 24) & 0xff] ^ TS2[(t1 >> 16) & 0xff] ^ TX1[(t1 >> 8) & 0xff] ^ TX2[t1 & 0xff];
|
||||
t2 = TS1[(t2 >> 24) & 0xff] ^ TS2[(t2 >> 16) & 0xff] ^ TX1[(t2 >> 8) & 0xff] ^ TX2[t2 & 0xff];
|
||||
t3 = TS1[(t3 >> 24) & 0xff] ^ TS2[(t3 >> 16) & 0xff] ^ TX1[(t3 >> 8) & 0xff] ^ TX2[t3 & 0xff];
|
||||
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
|
||||
t1 = Badc(t1); t2 = Cdab(t2); t3 = Dcba(t3);
|
||||
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
|
||||
|
||||
t0 ^= rk[j++]; t1 ^= rk[j++]; t2 ^= rk[j++]; t3 ^= rk[j++];
|
||||
t0 = TX1[(t0 >> 24) & 0xff] ^ TX2[(t0 >> 16) & 0xff] ^ TS1[(t0 >> 8) & 0xff] ^ TS2[t0 & 0xff];
|
||||
t1 = TX1[(t1 >> 24) & 0xff] ^ TX2[(t1 >> 16) & 0xff] ^ TS1[(t1 >> 8) & 0xff] ^ TS2[t1 & 0xff];
|
||||
t2 = TX1[(t2 >> 24) & 0xff] ^ TX2[(t2 >> 16) & 0xff] ^ TS1[(t2 >> 8) & 0xff] ^ TS2[t2 & 0xff];
|
||||
t3 = TX1[(t3 >> 24) & 0xff] ^ TX2[(t3 >> 16) & 0xff] ^ TS1[(t3 >> 8) & 0xff] ^ TS2[t3 & 0xff];
|
||||
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
|
||||
t3 = Badc(t3); t0 = Cdab(t0); t1 = Dcba(t1);
|
||||
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
|
||||
}
|
||||
t0 ^= rk[j++]; t1 ^= rk[j++]; t2 ^= rk[j++]; t3 ^= rk[j++];
|
||||
t0 = TS1[(t0 >> 24) & 0xff] ^ TS2[(t0 >> 16) & 0xff] ^ TX1[(t0 >> 8) & 0xff] ^ TX2[t0 & 0xff];
|
||||
t1 = TS1[(t1 >> 24) & 0xff] ^ TS2[(t1 >> 16) & 0xff] ^ TX1[(t1 >> 8) & 0xff] ^ TX2[t1 & 0xff];
|
||||
t2 = TS1[(t2 >> 24) & 0xff] ^ TS2[(t2 >> 16) & 0xff] ^ TX1[(t2 >> 8) & 0xff] ^ TX2[t2 & 0xff];
|
||||
t3 = TS1[(t3 >> 24) & 0xff] ^ TS2[(t3 >> 16) & 0xff] ^ TX1[(t3 >> 8) & 0xff] ^ TX2[t3 & 0xff];
|
||||
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
|
||||
t1 = Badc(t1); t2 = Cdab(t2); t3 = Dcba(t3);
|
||||
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
|
||||
|
||||
t0 ^= rk[j++]; t1 ^= rk[j++]; t2 ^= rk[j++]; t3 ^= rk[j++];
|
||||
o[0 + ooffset] = (byte)(X1[0xff & (t0 >> 24)] ^ (rk[j] >> 24));
|
||||
o[1 + ooffset] = (byte)(X2[0xff & (t0 >> 16)] ^ (rk[j] >> 16));
|
||||
o[2 + ooffset] = (byte)(S1[0xff & (t0 >> 8)] ^ (rk[j] >> 8));
|
||||
o[3 + ooffset] = (byte)(S2[0xff & (t0)] ^ (rk[j]));
|
||||
o[4 + ooffset] = (byte)(X1[0xff & (t1 >> 24)] ^ (rk[j + 1] >> 24));
|
||||
o[5 + ooffset] = (byte)(X2[0xff & (t1 >> 16)] ^ (rk[j + 1] >> 16));
|
||||
o[6 + ooffset] = (byte)(S1[0xff & (t1 >> 8)] ^ (rk[j + 1] >> 8));
|
||||
o[7 + ooffset] = (byte)(S2[0xff & (t1)] ^ (rk[j + 1]));
|
||||
o[8 + ooffset] = (byte)(X1[0xff & (t2 >> 24)] ^ (rk[j + 2] >> 24));
|
||||
o[9 + ooffset] = (byte)(X2[0xff & (t2 >> 16)] ^ (rk[j + 2] >> 16));
|
||||
o[10 + ooffset] = (byte)(S1[0xff & (t2 >> 8)] ^ (rk[j + 2] >> 8));
|
||||
o[11 + ooffset] = (byte)(S2[0xff & (t2)] ^ (rk[j + 2]));
|
||||
o[12 + ooffset] = (byte)(X1[0xff & (t3 >> 24)] ^ (rk[j + 3] >> 24));
|
||||
o[13 + ooffset] = (byte)(X2[0xff & (t3 >> 16)] ^ (rk[j + 3] >> 16));
|
||||
o[14 + ooffset] = (byte)(S1[0xff & (t3 >> 8)] ^ (rk[j + 3] >> 8));
|
||||
o[15 + ooffset] = (byte)(S2[0xff & (t3)] ^ (rk[j + 3]));
|
||||
}
|
||||
|
||||
public void Encrypt(byte[] i, int ioffset, byte[] o, int ooffset)
|
||||
{
|
||||
if (keySize == 0)
|
||||
throw new CryptographicException("keySize");
|
||||
|
||||
if (encRoundKeys == null)
|
||||
{
|
||||
if (masterKey == null)
|
||||
{
|
||||
throw new CryptographicException("masterKey");
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupEncRoundKeys();
|
||||
}
|
||||
}
|
||||
|
||||
DoCrypt(i, ioffset, encRoundKeys, numberOfRounds, o, ooffset);
|
||||
}
|
||||
|
||||
public byte[] Encrypt(byte[] i, int ioffset)
|
||||
{
|
||||
byte[] o = new byte[16];
|
||||
Encrypt(i, ioffset, o, 0);
|
||||
return o;
|
||||
}
|
||||
|
||||
public void Decrypt(byte[] i, int ioffset, byte[] o, int ooffset)
|
||||
{
|
||||
if (keySize == 0)
|
||||
throw new CryptographicException("keySize");
|
||||
|
||||
if (decRoundKeys == null)
|
||||
{
|
||||
if (masterKey == null)
|
||||
{
|
||||
throw new CryptographicException("masterKey");
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupDecRoundKeys();
|
||||
}
|
||||
}
|
||||
|
||||
DoCrypt(i, ioffset, decRoundKeys, numberOfRounds, o, ooffset);
|
||||
}
|
||||
|
||||
public byte[] Decrypt(byte[] i, int ioffset)
|
||||
{
|
||||
byte[] o = new byte[16];
|
||||
Decrypt(i, ioffset, o, 0);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
private static void DoEncKeySetup(byte[] mk, uint[] rk, int keyBits)
|
||||
{
|
||||
uint t0, t1, t2, t3;
|
||||
int q, j = 0;
|
||||
uint[] w0 = new uint[4];
|
||||
uint[] w1 = new uint[4];
|
||||
uint[] w2 = new uint[4];
|
||||
uint[] w3 = new uint[4];
|
||||
|
||||
w0[0] = ToInt(mk[0], mk[1], mk[2], mk[3]);
|
||||
w0[1] = ToInt(mk[4], mk[5], mk[6], mk[7]);
|
||||
w0[2] = ToInt(mk[8], mk[9], mk[10], mk[11]);
|
||||
w0[3] = ToInt(mk[12], mk[13], mk[14], mk[15]);
|
||||
|
||||
q = (keyBits - 128) / 64;
|
||||
t0 = w0[0] ^ KRK[q, 0]; t1 = w0[1] ^ KRK[q, 1];
|
||||
t2 = w0[2] ^ KRK[q, 2]; t3 = w0[3] ^ KRK[q, 3];
|
||||
t0 = TS1[(t0 >> 24) & 0xff] ^ TS2[(t0 >> 16) & 0xff] ^ TX1[(t0 >> 8) & 0xff] ^ TX2[t0 & 0xff];
|
||||
t1 = TS1[(t1 >> 24) & 0xff] ^ TS2[(t1 >> 16) & 0xff] ^ TX1[(t1 >> 8) & 0xff] ^ TX2[t1 & 0xff];
|
||||
t2 = TS1[(t2 >> 24) & 0xff] ^ TS2[(t2 >> 16) & 0xff] ^ TX1[(t2 >> 8) & 0xff] ^ TX2[t2 & 0xff];
|
||||
t3 = TS1[(t3 >> 24) & 0xff] ^ TS2[(t3 >> 16) & 0xff] ^ TX1[(t3 >> 8) & 0xff] ^ TX2[t3 & 0xff];
|
||||
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
|
||||
t1 = Badc(t1); t2 = Cdab(t2); t3 = Dcba(t3);
|
||||
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
|
||||
|
||||
if (keyBits > 128)
|
||||
{
|
||||
w1[0] = ToInt(mk[16], mk[17], mk[18], mk[19]);
|
||||
w1[1] = ToInt(mk[20], mk[21], mk[22], mk[23]);
|
||||
if (keyBits > 192)
|
||||
{
|
||||
w1[2] = ToInt(mk[24], mk[25], mk[26], mk[27]);
|
||||
w1[3] = ToInt(mk[28], mk[29], mk[30], mk[31]);
|
||||
}
|
||||
else
|
||||
{
|
||||
w1[2] = w1[3] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
w1[0] = w1[1] = w1[2] = w1[3] = 0;
|
||||
}
|
||||
w1[0] ^= t0; w1[1] ^= t1; w1[2] ^= t2; w1[3] ^= t3;
|
||||
t0 = w1[0]; t1 = w1[1]; t2 = w1[2]; t3 = w1[3];
|
||||
|
||||
q = (q == 2) ? 0 : (q + 1);
|
||||
t0 ^= KRK[q, 0]; t1 ^= KRK[q, 1]; t2 ^= KRK[q, 2]; t3 ^= KRK[q, 3];
|
||||
t0 = TX1[(t0 >> 24) & 0xff] ^ TX2[(t0 >> 16) & 0xff] ^ TS1[(t0 >> 8) & 0xff] ^ TS2[t0 & 0xff];
|
||||
t1 = TX1[(t1 >> 24) & 0xff] ^ TX2[(t1 >> 16) & 0xff] ^ TS1[(t1 >> 8) & 0xff] ^ TS2[t1 & 0xff];
|
||||
t2 = TX1[(t2 >> 24) & 0xff] ^ TX2[(t2 >> 16) & 0xff] ^ TS1[(t2 >> 8) & 0xff] ^ TS2[t2 & 0xff];
|
||||
t3 = TX1[(t3 >> 24) & 0xff] ^ TX2[(t3 >> 16) & 0xff] ^ TS1[(t3 >> 8) & 0xff] ^ TS2[t3 & 0xff];
|
||||
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
|
||||
t3 = Badc(t3); t0 = Cdab(t0); t1 = Dcba(t1);
|
||||
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
|
||||
t0 ^= w0[0]; t1 ^= w0[1]; t2 ^= w0[2]; t3 ^= w0[3];
|
||||
w2[0] = t0; w2[1] = t1; w2[2] = t2; w2[3] = t3;
|
||||
|
||||
q = (q == 2) ? 0 : (q + 1);
|
||||
t0 ^= KRK[q, 0]; t1 ^= KRK[q, 1]; t2 ^= KRK[q, 2]; t3 ^= KRK[q, 3];
|
||||
t0 = TS1[(t0 >> 24) & 0xff] ^ TS2[(t0 >> 16) & 0xff] ^ TX1[(t0 >> 8) & 0xff] ^ TX2[t0 & 0xff];
|
||||
t1 = TS1[(t1 >> 24) & 0xff] ^ TS2[(t1 >> 16) & 0xff] ^ TX1[(t1 >> 8) & 0xff] ^ TX2[t1 & 0xff];
|
||||
t2 = TS1[(t2 >> 24) & 0xff] ^ TS2[(t2 >> 16) & 0xff] ^ TX1[(t2 >> 8) & 0xff] ^ TX2[t2 & 0xff];
|
||||
t3 = TS1[(t3 >> 24) & 0xff] ^ TS2[(t3 >> 16) & 0xff] ^ TX1[(t3 >> 8) & 0xff] ^ TX2[t3 & 0xff];
|
||||
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
|
||||
t1 = Badc(t1); t2 = Cdab(t2); t3 = Dcba(t3);
|
||||
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
|
||||
w3[0] = t0 ^ w1[0]; w3[1] = t1 ^ w1[1]; w3[2] = t2 ^ w1[2]; w3[3] = t3 ^ w1[3];
|
||||
|
||||
Gsrk(w0, w1, 19, rk, j); j += 4;
|
||||
Gsrk(w1, w2, 19, rk, j); j += 4;
|
||||
Gsrk(w2, w3, 19, rk, j); j += 4;
|
||||
Gsrk(w3, w0, 19, rk, j); j += 4;
|
||||
Gsrk(w0, w1, 31, rk, j); j += 4;
|
||||
Gsrk(w1, w2, 31, rk, j); j += 4;
|
||||
Gsrk(w2, w3, 31, rk, j); j += 4;
|
||||
Gsrk(w3, w0, 31, rk, j); j += 4;
|
||||
Gsrk(w0, w1, 67, rk, j); j += 4;
|
||||
Gsrk(w1, w2, 67, rk, j); j += 4;
|
||||
Gsrk(w2, w3, 67, rk, j); j += 4;
|
||||
Gsrk(w3, w0, 67, rk, j); j += 4;
|
||||
Gsrk(w0, w1, 97, rk, j); j += 4;
|
||||
if (keyBits > 128)
|
||||
{
|
||||
Gsrk(w1, w2, 97, rk, j); j += 4;
|
||||
Gsrk(w2, w3, 97, rk, j); j += 4;
|
||||
}
|
||||
if (keyBits > 192)
|
||||
{
|
||||
Gsrk(w3, w0, 97, rk, j); j += 4;
|
||||
Gsrk(w0, w1, 109, rk, j);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main bulk of the decryption key setup method. Here we assume that
|
||||
* the int array rk already contains the encryption round keys.
|
||||
* @param mk the master key
|
||||
* @param rk the array which contains the encryption round keys at the
|
||||
* beginning of the method execution. At the end of method execution
|
||||
* this will hold the decryption round keys.
|
||||
* @param keyBits the length of the master key
|
||||
* @return
|
||||
*/
|
||||
private static void DoDecKeySetup(byte[] mk, uint[] rk, int keyBits)
|
||||
{
|
||||
int a = 0, z;
|
||||
uint[] t = new uint[4];
|
||||
|
||||
z = 32 + keyBits / 8;
|
||||
SwapBlocks(rk, 0, z);
|
||||
a += 4; z -= 4;
|
||||
|
||||
for (; a < z; a += 4, z -= 4)
|
||||
SwapAndDiffuse(rk, a, z, t);
|
||||
Diff(rk, a, t, 0);
|
||||
rk[a] = t[0]; rk[a + 1] = t[1]; rk[a + 2] = t[2]; rk[a + 3] = t[3];
|
||||
}
|
||||
|
||||
private static uint ToInt(byte b0, byte b1, byte b2, byte b3)
|
||||
{
|
||||
return (uint)((b0 & 0xff) << 24 ^ (b1 & 0xff) << 16 ^ (b2 & 0xff) << 8 ^ b3 & 0xff);
|
||||
}
|
||||
|
||||
private static uint M(uint t)
|
||||
{
|
||||
return 0x00010101 * ((t >> 24) & 0xff) ^ 0x01000101 * ((t >> 16) & 0xff) ^
|
||||
0x01010001 * ((t >> 8) & 0xff) ^ 0x01010100 * (t & 0xff);
|
||||
}
|
||||
|
||||
// private static final int ms(int t) {
|
||||
// return TS1[(t>>>24)&0xff]^TS2[(t>>>16)&0xff]^TX1[(t>>>8)&0xff]^TX2[t&0xff];
|
||||
// }
|
||||
// private static final int mx(int t) {
|
||||
// return TX1[(t>>>24)&0xff]^TX2[(t>>>16)&0xff]^TS1[(t>>>8)&0xff]^TS2[t&0xff];
|
||||
// }
|
||||
private static uint Badc(uint t)
|
||||
{
|
||||
return ((t << 8) & 0xff00ff00) ^ ((t >> 8) & 0x00ff00ff);
|
||||
}
|
||||
|
||||
private static uint Cdab(uint t)
|
||||
{
|
||||
return ((t << 16) & 0xffff0000) ^ ((t >> 16) & 0x0000ffff);
|
||||
}
|
||||
|
||||
private static uint Dcba(uint t)
|
||||
{
|
||||
return (t & 0x000000ff) << 24 ^ (t & 0x0000ff00) << 8 ^ (t & 0x00ff0000) >> 8 ^ (t & 0xff000000) >> 24;
|
||||
}
|
||||
|
||||
private static void Gsrk(uint[] x, uint[] y, int rot, uint[] rk, int offset)
|
||||
{
|
||||
int q = 4 - (rot / 32), r = rot % 32, s = 32 - r;
|
||||
|
||||
rk[offset] = x[0] ^ y[(q) % 4] >> r ^ y[(q + 3) % 4] << s;
|
||||
rk[offset + 1] = x[1] ^ y[(q + 1) % 4] >> r ^ y[(q) % 4] << s;
|
||||
rk[offset + 2] = x[2] ^ y[(q + 2) % 4] >> r ^ y[(q + 1) % 4] << s;
|
||||
rk[offset + 3] = x[3] ^ y[(q + 3) % 4] >> r ^ y[(q + 2) % 4] << s;
|
||||
}
|
||||
|
||||
private static void Diff(uint[] i, int offset1, uint[] o, int offset2)
|
||||
{
|
||||
uint t0, t1, t2, t3;
|
||||
|
||||
t0 = M(i[offset1]); t1 = M(i[offset1 + 1]); t2 = M(i[offset1 + 2]); t3 = M(i[offset1 + 3]);
|
||||
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
|
||||
t1 = Badc(t1); t2 = Cdab(t2); t3 = Dcba(t3);
|
||||
t1 ^= t2; t2 ^= t3; t0 ^= t1; t3 ^= t1; t2 ^= t0; t1 ^= t2;
|
||||
o[offset2] = t0; o[offset2 + 1] = t1; o[offset2 + 2] = t2; o[offset2 + 3] = t3;
|
||||
}
|
||||
|
||||
private static void SwapBlocks(uint[] arr, int offset1, int offset2)
|
||||
{
|
||||
uint t;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
t = arr[offset1 + i];
|
||||
arr[offset1 + i] = arr[offset2 + i];
|
||||
arr[offset2 + i] = t;
|
||||
}
|
||||
}
|
||||
|
||||
private static void SwapAndDiffuse(uint[] arr, int offset1, int offset2, uint[] tmp)
|
||||
{
|
||||
Diff(arr, offset1, tmp, 0);
|
||||
Diff(arr, offset2, arr, offset1);
|
||||
arr[offset2] = tmp[0]; arr[offset2 + 1] = tmp[1];
|
||||
arr[offset2 + 2] = tmp[2]; arr[offset2 + 3] = tmp[3];
|
||||
}
|
||||
|
||||
public class ECB
|
||||
{
|
||||
private static readonly int BLOCK_SIZE = 16;
|
||||
private ARIA engine = null;
|
||||
|
||||
public ECB(byte[] key)
|
||||
{
|
||||
Init(key);
|
||||
}
|
||||
|
||||
public ECB(string key)
|
||||
{
|
||||
Init(CreateKey(key));
|
||||
}
|
||||
|
||||
private void Init(byte[] key)
|
||||
{
|
||||
engine = new ARIA(key.Length * 8);
|
||||
engine.SetKey(key);
|
||||
engine.SetupRoundKeys();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// allowed key size (bit): 128, 192, 256
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
private byte[] CreateKey(string key)
|
||||
{
|
||||
SHA256 hasher = SHA256.Create();
|
||||
byte[] hashData = hasher.ComputeHash(Encoding.Default.GetBytes(key));
|
||||
|
||||
return hashData;
|
||||
}
|
||||
|
||||
public byte[] Encrypt(byte[] data)
|
||||
{
|
||||
byte[] indata = AnsiX923Padding.AddPadding(data, BLOCK_SIZE);
|
||||
byte[] outdata = new byte[indata.Length];
|
||||
|
||||
for (int i = 0; i < indata.Length; i += BLOCK_SIZE)
|
||||
{
|
||||
engine.Encrypt(indata, i, outdata, i);
|
||||
}
|
||||
|
||||
return outdata;
|
||||
}
|
||||
|
||||
public byte[] Decrypt(byte[] data)
|
||||
{
|
||||
byte[] outdata = new byte[data.Length];
|
||||
|
||||
for (int i = 0; i < data.Length; i += BLOCK_SIZE)
|
||||
{
|
||||
engine.Decrypt(data, i, outdata, i);
|
||||
}
|
||||
|
||||
return AnsiX923Padding.RemovePadding(outdata, BLOCK_SIZE, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* WelsonJS.Toolkit: WelsonJS native component
|
||||
*
|
||||
* filename:
|
||||
* AnsiX923Padding.cs
|
||||
*
|
||||
* description:
|
||||
* AnsiX923Padding implementation
|
||||
*
|
||||
* website:
|
||||
* - https://github.com/gnh1201/welsonjs
|
||||
* - https://catswords.social/@catswords_oss
|
||||
* - https://teams.live.com/l/community/FEACHncAhq8ldnojAI
|
||||
* - https://discord.gg/XKG5CjtXEj
|
||||
*
|
||||
* authors:
|
||||
* - Namhyeon Go (@gnh1201) <abuse@catswords.net>
|
||||
*
|
||||
* references:
|
||||
* - https://github.com/eGovFrame/egovframework.rte.root/blob/master/Foundation/egovframework.rte.fdl.crypto/src/main/java/egovframework/rte/fdl/cryptography/impl/aria/AnsiX923Padding.java
|
||||
* - ChatGPT prompt "AnsiX923Padding with C#" (chatgpt.com)
|
||||
* - ChatGPT prompt "AnsiX923Padding with C#, Add a flag to decide how to handle possible errors when removing padding." (chatgpt.com)
|
||||
*
|
||||
* license:
|
||||
* GPLv3 or MS-RL(Microsoft Reciprocal License)
|
||||
*
|
||||
*/
|
||||
using System;
|
||||
|
||||
namespace WelsonJS.Cryptography
|
||||
{
|
||||
class AnsiX923Padding
|
||||
{
|
||||
/// <summary>
|
||||
/// Add ANSI X.923 padding to the input data to make it a multiple of the block size.
|
||||
/// </summary>
|
||||
/// <param name="data">The data to be padded.</param>
|
||||
/// <param name="blockSize">The block size to pad to.</param>
|
||||
/// <returns>Padded data with ANSI X.923 padding.</returns>
|
||||
public static byte[] AddPadding(byte[] data, int blockSize)
|
||||
{
|
||||
int paddingLength = blockSize - (data.Length % blockSize);
|
||||
|
||||
// If the data is already a multiple of the block size, no padding is needed
|
||||
if (paddingLength == blockSize)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
byte[] paddedData = new byte[data.Length + paddingLength];
|
||||
|
||||
// Copy original data into the padded array
|
||||
Array.Copy(data, paddedData, data.Length);
|
||||
|
||||
// Fill with 0x00 bytes, and the last byte is the padding length
|
||||
for (int i = data.Length; i < paddedData.Length - 1; i++)
|
||||
{
|
||||
paddedData[i] = 0x00;
|
||||
}
|
||||
|
||||
// Last byte is the padding length
|
||||
paddedData[paddedData.Length - 1] = (byte)paddingLength;
|
||||
|
||||
return paddedData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes ANSI X.923 padding from the given data.
|
||||
/// </summary>
|
||||
/// <param name="data">The input data, including padding.</param>
|
||||
/// <param name="blockSize">The block size used for padding.</param>
|
||||
/// <param name="ignoreErrors">If true, ignores errors and attempts to process the input data as-is.</param>
|
||||
/// <returns>The unpadded data as a byte array.</returns>
|
||||
/// <exception cref="ArgumentException">Thrown if the input data or padding is invalid and ignoreErrors is false.</exception>
|
||||
public static byte[] RemovePadding(byte[] data, int blockSize, bool ignoreErrors = false)
|
||||
{
|
||||
// Check for null or empty data
|
||||
if (data == null || data.Length == 0)
|
||||
{
|
||||
if (ignoreErrors)
|
||||
{
|
||||
return new byte[] { };
|
||||
}
|
||||
throw new ArgumentException("Input data cannot be null or empty.");
|
||||
}
|
||||
|
||||
// Ensure the data length is a multiple of the block size
|
||||
if (data.Length % blockSize != 0)
|
||||
{
|
||||
if (ignoreErrors)
|
||||
{
|
||||
// Return the original data if errors are ignored
|
||||
return data;
|
||||
}
|
||||
throw new ArgumentException("Input data length must be a multiple of the block size.");
|
||||
}
|
||||
|
||||
// Retrieve the padding length from the last byte
|
||||
int paddingLength = data[data.Length - 1];
|
||||
|
||||
// Validate padding length
|
||||
if (paddingLength <= 0 || paddingLength > blockSize)
|
||||
{
|
||||
if (!ignoreErrors)
|
||||
{
|
||||
throw new ArgumentException($"Invalid padding length: {paddingLength}. Must be between 1 and {blockSize}.");
|
||||
}
|
||||
|
||||
// Treat padding length as 0 and return the full data
|
||||
return data;
|
||||
}
|
||||
|
||||
// Validate the padding region (last paddingLength - 1 bytes must be 0x00)
|
||||
for (int i = data.Length - paddingLength; i < data.Length - 1; i++)
|
||||
{
|
||||
if (data[i] != 0x00)
|
||||
{
|
||||
if (!ignoreErrors)
|
||||
{
|
||||
throw new ArgumentException("Invalid padding detected. Expected padding bytes to be 0x00.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extract unpadded data
|
||||
byte[] unpaddedData = new byte[data.Length - paddingLength];
|
||||
Array.Copy(data, unpaddedData, unpaddedData.Length);
|
||||
|
||||
return unpaddedData;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,34 +5,38 @@
|
|||
* HIGHT.cs
|
||||
*
|
||||
* description:
|
||||
* HIGHT(ISO/IEC 18033-3) cryptography algorithm (ECB mode) implementation for WelsonJS
|
||||
* HIGHT(ISO/IEC 18033-3) cryptography algorithm implementation
|
||||
*
|
||||
* website:
|
||||
* - https://github.com/gnh1201/welsonjs
|
||||
* - https://catswords.social/@catswords_oss
|
||||
* - https://teams.live.com/l/community/FEACHncAhq8ldnojAI
|
||||
* - https://discord.gg/XKG5CjtXEj
|
||||
*
|
||||
* author:
|
||||
* - Namhyeon Go <abuse@catswords.net>
|
||||
* - @chandong83 (github.com) - Original author of CryptoHIGHT.cs
|
||||
* - KISA(Korea Internet & Security Agency)
|
||||
* authors:
|
||||
* - Namhyeon Go (@gnh1201) <abuse@catswords.net>
|
||||
* - @chandong83 (github.com)
|
||||
* - KISA(Korea Internet & Security Agency) (kisa.or.kr)
|
||||
* - Korea Unversity (www.korea.ac.kr)
|
||||
*
|
||||
* references:
|
||||
* - https://seed.kisa.or.kr/kisa/algorithm/EgovHightInfo.do
|
||||
* - https://github.com/chandong83/csharp_crypto_hight_ecb_examples
|
||||
* - https://blog.naver.com/chandong83/222198351602
|
||||
* - https://seed.kisa.or.kr/kisa/algorithm/EgovHightInfo.do
|
||||
* - https://www.iso.org/standard/54531.html
|
||||
* - https://ics.catswords.net/HIGHT-algorithm-specification-english.pdf
|
||||
* - https://ics.catswords.net/HIGHT-algorithm-specification-korean.pdf
|
||||
* - https://ics.catswords.net/HIGHT-sourcecode-explanation.pdf
|
||||
*
|
||||
* license:
|
||||
* GPLv3 or MS-RL(Microsoft Reciprocal License)
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace WelsonJS.Cryptography
|
||||
{
|
||||
public static class HIGHT
|
||||
public class HIGHT
|
||||
{
|
||||
private static readonly byte[] hightDelta = {
|
||||
0x5A,0x6D,0x36,0x1B,0x0D,0x06,0x03,0x41,
|
||||
|
@ -235,24 +239,6 @@ namespace WelsonJS.Cryptography
|
|||
dataOut[6] = (byte)((xx[6] ^ scheduleKey[3]) & 0xFF);
|
||||
}
|
||||
|
||||
void debugPrintHex(byte[] dat)
|
||||
{
|
||||
for (int i = 0; i < dat.Length; i++)
|
||||
{
|
||||
Console.Write(string.Format("0x{0:x2}, ", dat[i]));
|
||||
if (((i + 1) % 16) == 0)
|
||||
{
|
||||
Console.WriteLine("");
|
||||
}
|
||||
}
|
||||
Console.WriteLine("");
|
||||
}
|
||||
|
||||
void debugPrintLine(string str)
|
||||
{
|
||||
Console.WriteLine(str);
|
||||
}
|
||||
|
||||
void EncryptBlock(byte[] dataIn, byte[] dataOut)
|
||||
{
|
||||
byte[] xx = new byte[8];
|
||||
|
@ -317,6 +303,7 @@ namespace WelsonJS.Cryptography
|
|||
dataOut[4] = (byte)((xx[5] + scheduleKey[6]) & 0xFF);
|
||||
dataOut[6] = (byte)((xx[7] ^ scheduleKey[7]) & 0xFF);
|
||||
}
|
||||
|
||||
public byte[] Encrypt(byte[] dataIn)
|
||||
{
|
||||
int length;
|
||||
|
@ -346,6 +333,7 @@ namespace WelsonJS.Cryptography
|
|||
}
|
||||
return dataOut;
|
||||
}
|
||||
|
||||
public byte[] Decrypt(byte[] dataIn)
|
||||
{
|
||||
int length;
|
||||
|
@ -375,7 +363,7 @@ namespace WelsonJS.Cryptography
|
|||
return dataOut;
|
||||
}
|
||||
|
||||
public void test()
|
||||
public void Test()
|
||||
{
|
||||
byte[] dataIn = new byte[15];
|
||||
byte[] dataOut = new byte[15];
|
||||
|
@ -384,17 +372,17 @@ namespace WelsonJS.Cryptography
|
|||
{
|
||||
dataIn[i] = (byte)i;
|
||||
}
|
||||
debugPrintLine("schedule key data");
|
||||
debugPrintHex(scheduleKey);
|
||||
Console.WriteLine("schedule key data");
|
||||
Console.WriteLine(string.Format("0x{0:x2}", scheduleKey));
|
||||
|
||||
dataOut = Encrypt(dataIn);
|
||||
dataOut2 = Decrypt(dataOut);
|
||||
debugPrintLine("origin data");
|
||||
debugPrintHex(dataIn);
|
||||
debugPrintLine("encryption data");
|
||||
debugPrintHex(dataOut);
|
||||
debugPrintLine("decryption data");
|
||||
debugPrintHex(dataOut2);
|
||||
Console.WriteLine("origin data");
|
||||
Console.WriteLine(string.Format("0x{0:x2}", dataIn));
|
||||
Console.WriteLine("encryption data");
|
||||
Console.WriteLine(string.Format("0x{0:x2}", dataOut));
|
||||
Console.WriteLine("decryption data");
|
||||
Console.WriteLine(string.Format("0x{0:x2}", dataOut2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
349
WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/LEA.cs
Normal file
349
WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/LEA.cs
Normal file
|
@ -0,0 +1,349 @@
|
|||
/*
|
||||
* WelsonJS.Toolkit: WelsonJS native component
|
||||
*
|
||||
* filename:
|
||||
* LEA.cs
|
||||
*
|
||||
* description:
|
||||
* LEA(KS X 3246:2016) cryptography algorithm implementation (Experimental)
|
||||
*
|
||||
* website:
|
||||
* - https://github.com/gnh1201/welsonjs
|
||||
* - https://catswords.social/@catswords_oss
|
||||
* - https://teams.live.com/l/community/FEACHncAhq8ldnojAI
|
||||
* - https://discord.gg/XKG5CjtXEj
|
||||
*
|
||||
* authors:
|
||||
* - Namhyeon Go (@gnh1201) <abuse@catswords.net>
|
||||
* - KISA(Korea Internet & Security Agency) (kisa.or.kr)
|
||||
* - National Security Research Institute (NSRI)
|
||||
*
|
||||
* references:
|
||||
* - https://seed.kisa.or.kr/kisa/Board/20/detailView.do
|
||||
* - https://committee.tta.or.kr/data/standard_view.jsp?order=t.kor_standard&by=asc&pk_num=TTAK.KO-12.0223&commit_code=TC5
|
||||
* - https://ics.catswords.net/LEA%20A%20128-Bit%20Block%20Cipher%20Datasheets-Korean.pdf
|
||||
* - https://ics.catswords.net/LEA%20A%20128-Bit%20Block%20Cipher%20for%20Fast%20Encryption%20on%20Common%20Processors-English.pdf
|
||||
* - https://ics.catswords.net/LEA-sourcecode-explanation.pdf
|
||||
*
|
||||
* license:
|
||||
* GPLv3 or MS-RL(Microsoft Reciprocal License)
|
||||
*
|
||||
*/
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace WelsonJS.Cryptography
|
||||
{
|
||||
public class LEA
|
||||
{
|
||||
private const int BLOCKSIZE = 16;
|
||||
private static readonly uint[] delta = {
|
||||
0xc3efe9db, 0x44626b02, 0x79e27c8a, 0x78df30ec,
|
||||
0x715ea49e, 0xc785da0a, 0xe04ef22a, 0xe5c40957
|
||||
};
|
||||
|
||||
private Mode mode;
|
||||
private int rounds;
|
||||
private uint[,] roundKeys;
|
||||
private uint[] block;
|
||||
|
||||
public LEA()
|
||||
{
|
||||
block = new uint[BLOCKSIZE / 4];
|
||||
}
|
||||
|
||||
public void Init(Mode mode, byte[] mk)
|
||||
{
|
||||
this.mode = mode;
|
||||
GenerateRoundKeys(mk);
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Array.Clear(block, 0, block.Length);
|
||||
}
|
||||
|
||||
public string GetAlgorithmName()
|
||||
{
|
||||
return "LEA";
|
||||
}
|
||||
|
||||
public int GetBlockSize()
|
||||
{
|
||||
return BLOCKSIZE;
|
||||
}
|
||||
|
||||
public int ProcessBlock(byte[] input, int inputOffset, byte[] output, int outputOffset)
|
||||
{
|
||||
if (input == null || output == null)
|
||||
throw new ArgumentNullException("Input and output buffers must not be null.");
|
||||
|
||||
if (input.Length - inputOffset < BLOCKSIZE)
|
||||
throw new InvalidOperationException("Input data is too short.");
|
||||
|
||||
if (output.Length - outputOffset < BLOCKSIZE)
|
||||
throw new InvalidOperationException("Output buffer is too short.");
|
||||
|
||||
return mode == Mode.ENCRYPT
|
||||
? EncryptBlock(input, inputOffset, output, outputOffset)
|
||||
: DecryptBlock(input, inputOffset, output, outputOffset);
|
||||
}
|
||||
|
||||
private int EncryptBlock(byte[] input, int inputOffset, byte[] output, int outputOffset)
|
||||
{
|
||||
Pack(input, inputOffset, ref block, 0, 16);
|
||||
|
||||
for (int i = 0; i < rounds; ++i)
|
||||
{
|
||||
block[3] = ROR((block[2] ^ roundKeys[i, 4]) + (block[3] ^ roundKeys[i, 5]), 3);
|
||||
block[2] = ROR((block[1] ^ roundKeys[i, 2]) + (block[2] ^ roundKeys[i, 3]), 5);
|
||||
block[1] = ROL((block[0] ^ roundKeys[i, 0]) + (block[1] ^ roundKeys[i, 1]), 9);
|
||||
++i;
|
||||
|
||||
block[0] = ROR((block[3] ^ roundKeys[i, 4]) + (block[0] ^ roundKeys[i, 5]), 3);
|
||||
block[3] = ROR((block[2] ^ roundKeys[i, 2]) + (block[3] ^ roundKeys[i, 3]), 5);
|
||||
block[2] = ROL((block[1] ^ roundKeys[i, 0]) + (block[2] ^ roundKeys[i, 1]), 9);
|
||||
|
||||
++i;
|
||||
block[1] = ROR((block[0] ^ roundKeys[i, 4]) + (block[1] ^ roundKeys[i, 5]), 3);
|
||||
block[0] = ROR((block[3] ^ roundKeys[i, 2]) + (block[0] ^ roundKeys[i, 3]), 5);
|
||||
block[3] = ROL((block[2] ^ roundKeys[i, 0]) + (block[3] ^ roundKeys[i, 1]), 9);
|
||||
|
||||
++i;
|
||||
block[2] = ROR((block[1] ^ roundKeys[i, 4]) + (block[2] ^ roundKeys[i, 5]), 3);
|
||||
block[1] = ROR((block[0] ^ roundKeys[i, 2]) + (block[1] ^ roundKeys[i, 3]), 5);
|
||||
block[0] = ROL((block[3] ^ roundKeys[i, 0]) + (block[0] ^ roundKeys[i, 1]), 9);
|
||||
}
|
||||
|
||||
Unpack(block, 0, ref output, outputOffset, 4);
|
||||
|
||||
return BLOCKSIZE;
|
||||
}
|
||||
|
||||
private int DecryptBlock(byte[] input, int inputOffset, byte[] output, int outputOffset)
|
||||
{
|
||||
Pack(input, inputOffset, ref block, 0, 16);
|
||||
|
||||
for (int i = rounds - 1; i >= 0; --i)
|
||||
{
|
||||
block[0] = (ROR(block[0], 9) - (block[3] ^ roundKeys[i, 0])) ^ roundKeys[i, 1];
|
||||
block[1] = (ROL(block[1], 5) - (block[0] ^ roundKeys[i, 2])) ^ roundKeys[i, 3];
|
||||
block[2] = (ROL(block[2], 3) - (block[1] ^ roundKeys[i, 4])) ^ roundKeys[i, 5];
|
||||
--i;
|
||||
|
||||
block[3] = (ROR(block[3], 9) - (block[2] ^ roundKeys[i, 0])) ^ roundKeys[i, 1];
|
||||
block[0] = (ROL(block[0], 5) - (block[3] ^ roundKeys[i, 2])) ^ roundKeys[i, 3];
|
||||
block[1] = (ROL(block[1], 3) - (block[0] ^ roundKeys[i, 4])) ^ roundKeys[i, 5];
|
||||
--i;
|
||||
|
||||
block[2] = (ROR(block[2], 9) - (block[1] ^ roundKeys[i, 0])) ^ roundKeys[i, 1];
|
||||
block[3] = (ROL(block[3], 5) - (block[2] ^ roundKeys[i, 2])) ^ roundKeys[i, 3];
|
||||
block[0] = (ROL(block[0], 3) - (block[3] ^ roundKeys[i, 4])) ^ roundKeys[i, 5];
|
||||
--i;
|
||||
|
||||
block[1] = (ROR(block[1], 9) - (block[0] ^ roundKeys[i, 0])) ^ roundKeys[i, 1];
|
||||
block[2] = (ROL(block[2], 5) - (block[1] ^ roundKeys[i, 2])) ^ roundKeys[i, 3];
|
||||
block[3] = (ROL(block[3], 3) - (block[2] ^ roundKeys[i, 4])) ^ roundKeys[i, 5];
|
||||
}
|
||||
|
||||
Unpack(block, 0, ref output, outputOffset, 4);
|
||||
|
||||
return BLOCKSIZE;
|
||||
}
|
||||
|
||||
private void GenerateRoundKeys(byte[] mk)
|
||||
{
|
||||
if (mk == null || (mk.Length != 16 && mk.Length != 24 && mk.Length != 32))
|
||||
throw new ArgumentException("Illegal key size");
|
||||
|
||||
uint[] T = new uint[8];
|
||||
rounds = (mk.Length >> 1) + 16;
|
||||
roundKeys = new uint[rounds, 6];
|
||||
|
||||
Pack(mk, 0, ref T, 0, 16);
|
||||
|
||||
if (mk.Length > 16)
|
||||
{
|
||||
Pack(mk, 16, ref T, 4, 8);
|
||||
}
|
||||
|
||||
if (mk.Length > 24)
|
||||
{
|
||||
Pack(mk, 24, ref T, 6, 8);
|
||||
}
|
||||
|
||||
if (mk.Length == 16)
|
||||
{
|
||||
for (int i = 0; i < 24; ++i)
|
||||
{
|
||||
uint temp = ROL(delta[i & 3], i);
|
||||
|
||||
roundKeys[i, 0] = T[0] = ROL(T[0] + ROL(temp, 0), 1);
|
||||
roundKeys[i, 1] = roundKeys[i, 3] = roundKeys[i, 5] = T[1] = ROL(T[1] + ROL(temp, 1), 3);
|
||||
roundKeys[i, 2] = T[2] = ROL(T[2] + ROL(temp, 2), 6);
|
||||
roundKeys[i, 4] = T[3] = ROL(T[3] + ROL(temp, 3), 11);
|
||||
}
|
||||
|
||||
}
|
||||
else if (mk.Length == 24)
|
||||
{
|
||||
for (int i = 0; i < 28; ++i)
|
||||
{
|
||||
uint temp = ROL(delta[i % 6], i);
|
||||
|
||||
roundKeys[i, 0] = T[0] = ROL(T[0] + ROL(temp, 0), 1);
|
||||
roundKeys[i, 1] = T[1] = ROL(T[1] + ROL(temp, 1), 3);
|
||||
roundKeys[i, 2] = T[2] = ROL(T[2] + ROL(temp, 2), 6);
|
||||
roundKeys[i, 3] = T[3] = ROL(T[3] + ROL(temp, 3), 11);
|
||||
roundKeys[i, 4] = T[4] = ROL(T[4] + ROL(temp, 4), 13);
|
||||
roundKeys[i, 5] = T[5] = ROL(T[5] + ROL(temp, 5), 17);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 32; ++i)
|
||||
{
|
||||
uint temp = ROL(delta[i & 7], i & 0x1f);
|
||||
|
||||
roundKeys[i, 0] = T[(6 * i + 0) & 7] = ROL(T[(6 * i + 0) & 7] + temp, 1);
|
||||
roundKeys[i, 1] = T[(6 * i + 1) & 7] = ROL(T[(6 * i + 1) & 7] + ROL(temp, 1), 3);
|
||||
roundKeys[i, 2] = T[(6 * i + 2) & 7] = ROL(T[(6 * i + 2) & 7] + ROL(temp, 2), 6);
|
||||
roundKeys[i, 3] = T[(6 * i + 3) & 7] = ROL(T[(6 * i + 3) & 7] + ROL(temp, 3), 11);
|
||||
roundKeys[i, 4] = T[(6 * i + 4) & 7] = ROL(T[(6 * i + 4) & 7] + ROL(temp, 4), 13);
|
||||
roundKeys[i, 5] = T[(6 * i + 5) & 7] = ROL(T[(6 * i + 5) & 7] + ROL(temp, 5), 17);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static uint ROL(uint state, int num)
|
||||
{
|
||||
return (state << num) | state >> (32 - num);
|
||||
}
|
||||
|
||||
private static uint ROR(uint state, int num)
|
||||
{
|
||||
return (state >> num) | state << (32 - num);
|
||||
}
|
||||
|
||||
public static void Pack(in byte[] input, int inputOffset, ref uint[] output, int outputOffset, int inputLength)
|
||||
{
|
||||
if (input == null || output == null)
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
|
||||
if ((inputLength & 3) != 0)
|
||||
{
|
||||
throw new ArgumentException("Length should be a multiple of 4.");
|
||||
}
|
||||
|
||||
if (input.Length < inputOffset + inputLength || output.Length < outputOffset + inputLength / 4)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
|
||||
int outputIndex = 0;
|
||||
for (int inputIdx = 0; inputIdx < input.Length; ++inputIdx, ++outputIndex) {
|
||||
output[outputIndex] = (uint)(input[inputIdx] & 0xff);
|
||||
output[outputIndex] |= (uint)((input[++inputIdx] & 0xff) << 8);
|
||||
output[outputIndex] |= (uint)((input[++inputIdx] & 0xff) << 16);
|
||||
output[outputIndex] |= (uint)((input[++inputIdx] & 0xff) << 24);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Unpack(in uint[] input, int inputOffset, ref byte[] output, int outputOffset, int inputLength)
|
||||
{
|
||||
if (input == null || output == null)
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
|
||||
if (input.Length < inputOffset + inputLength || output.Length < outputOffset + inputLength * 4)
|
||||
{
|
||||
throw new IndexOutOfRangeException();
|
||||
}
|
||||
|
||||
int outputIdx = outputOffset;
|
||||
int endInIdx = inputOffset + inputLength;
|
||||
for (int inputIdx = inputOffset; inputIdx < endInIdx; ++inputIdx, ++outputIdx)
|
||||
{
|
||||
output[outputIdx] = (byte)input[inputIdx] ;
|
||||
output[++outputIdx] = (byte)(input[inputIdx] >> 8);
|
||||
output[++outputIdx] = (byte)(input[inputIdx] >> 16);
|
||||
output[++outputIdx] = (byte)(input[inputIdx] >> 24);
|
||||
}
|
||||
}
|
||||
|
||||
public enum Mode
|
||||
{
|
||||
ENCRYPT,
|
||||
DECRYPT
|
||||
}
|
||||
|
||||
public class ECB
|
||||
{
|
||||
private Mode mode;
|
||||
private LEA engine;
|
||||
private int blockSize;
|
||||
|
||||
ECB(Mode mode, string key)
|
||||
{
|
||||
engine = new LEA();
|
||||
Init(mode, CreateKey(key));
|
||||
blockSize = engine.GetBlockSize();
|
||||
}
|
||||
|
||||
public string GetAlgorithmName()
|
||||
{
|
||||
return engine.GetAlgorithmName() + "/ECB";
|
||||
}
|
||||
|
||||
public void Init(Mode mode, byte[] mk)
|
||||
{
|
||||
this.mode = mode;
|
||||
engine.Init(mode, mk);
|
||||
}
|
||||
|
||||
private byte[] CreateKey(string key)
|
||||
{
|
||||
SHA256 hasher = SHA256.Create();
|
||||
byte[] hashData = hasher.ComputeHash(Encoding.Default.GetBytes(key));
|
||||
|
||||
return hashData;
|
||||
}
|
||||
|
||||
public byte[] Encrypt(byte[] data)
|
||||
{
|
||||
if (this.mode != Mode.ENCRYPT)
|
||||
throw new InvalidOperationException("Not initialized for encryption mode.");
|
||||
|
||||
byte[] inputData = PKCS5Padding.AddPadding(data, blockSize);
|
||||
byte[] outputData = new byte[inputData.Length];
|
||||
|
||||
for (int i = 0; i < inputData.Length; i += blockSize)
|
||||
{
|
||||
engine.ProcessBlock(inputData, i, outputData, i);
|
||||
}
|
||||
|
||||
return outputData;
|
||||
}
|
||||
|
||||
public byte[] Decrypt(byte[] data)
|
||||
{
|
||||
if (this.mode != Mode.DECRYPT)
|
||||
throw new InvalidOperationException("Not initialized for decryption mode.");
|
||||
|
||||
byte[] outputData = new byte[data.Length];
|
||||
|
||||
for (int i = 0; i < data.Length; i += blockSize)
|
||||
{
|
||||
engine.ProcessBlock(data, i, outputData, i);
|
||||
}
|
||||
|
||||
return PKCS5Padding.RemovePadding(outputData, blockSize, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
118
WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/PKCS5Padding.cs
Normal file
118
WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/PKCS5Padding.cs
Normal file
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* WelsonJS.Toolkit: WelsonJS native component
|
||||
*
|
||||
* filename:
|
||||
* PKCS5Padding.cs
|
||||
*
|
||||
* description:
|
||||
* PKCS5Padding implementation
|
||||
*
|
||||
* website:
|
||||
* - https://github.com/gnh1201/welsonjs
|
||||
* - https://catswords.social/@catswords_oss
|
||||
* - https://teams.live.com/l/community/FEACHncAhq8ldnojAI
|
||||
* - https://discord.gg/XKG5CjtXEj
|
||||
*
|
||||
* authors:
|
||||
* - Namhyeon Go (@gnh1201) <abuse@catswords.net>
|
||||
*
|
||||
* references:
|
||||
* - ChatGPT prompt "PKCS5Padding with C#" (chatgpt.com)
|
||||
* - ChatGPT prompt "PKCS5Padding with C#, Add a flag to decide how to handle possible errors when removing padding." (chatgpt.com)
|
||||
*
|
||||
* license:
|
||||
* GPLv3 or MS-RL(Microsoft Reciprocal License)
|
||||
*
|
||||
*/
|
||||
using System;
|
||||
|
||||
namespace WelsonJS.Cryptography
|
||||
{
|
||||
public class PKCS5Padding
|
||||
{
|
||||
/// <summary>
|
||||
/// Add PKCS#5 padding to the input data to make it a multiple of the block size.
|
||||
/// </summary>
|
||||
/// <param name="data">The data to be padded.</param>
|
||||
/// <param name="blockSize">The block size to pad to.</param>
|
||||
/// <returns>Padded data with PKCS#5 padding.</returns>
|
||||
public static byte[] AddPadding(byte[] data, int blockSize)
|
||||
{
|
||||
int paddingLength = blockSize - (data.Length % blockSize);
|
||||
|
||||
// If the data is already a multiple of the block size, no padding is needed
|
||||
if (paddingLength == blockSize)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
byte[] paddedData = new byte[data.Length + paddingLength];
|
||||
|
||||
// Copy original data into the padded array
|
||||
Array.Copy(data, paddedData, data.Length);
|
||||
|
||||
// Fill padding with the padding length (PKCS5)
|
||||
for (int i = data.Length; i < paddedData.Length; i++)
|
||||
{
|
||||
paddedData[i] = (byte)paddingLength;
|
||||
}
|
||||
|
||||
return paddedData;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes PKCS#5 padding from the given data.
|
||||
/// </summary>
|
||||
/// <param name="data">The input data, including padding.</param>
|
||||
/// <param name="blockSize">The block size used for padding.</param>
|
||||
/// <param name="ignoreErrors">If true, ignores errors and attempts to process the input data as-is.</param>
|
||||
/// <returns>The unpadded data as a byte array.</returns>
|
||||
/// <exception cref="ArgumentException">Thrown if the input data or padding is invalid and ignoreErrors is false.</exception>
|
||||
public static byte[] RemovePadding(byte[] data, int blockSize, bool ignoreErrors = false)
|
||||
{
|
||||
// If data length is 0, return empty array
|
||||
if (data.Length == 0)
|
||||
{
|
||||
return new byte[] { };
|
||||
}
|
||||
|
||||
// If data length is smaller than block size, treat it as unpadded
|
||||
if (data.Length < blockSize)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
// Check if the last byte is valid padding (PKCS5)
|
||||
int paddingLength = data[data.Length - 1];
|
||||
|
||||
// Validate padding length
|
||||
if (paddingLength <= 0 || paddingLength > blockSize)
|
||||
{
|
||||
if (!ignoreErrors)
|
||||
{
|
||||
throw new ArgumentException($"Invalid padding length: {paddingLength}. Must be between 1 and {blockSize}.");
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
// Check if the padding is correct (i.e., all padding bytes must be equal to paddingLength)
|
||||
for (int i = data.Length - paddingLength; i < data.Length; i++)
|
||||
{
|
||||
if (data[i] != paddingLength)
|
||||
{
|
||||
if (!ignoreErrors)
|
||||
{
|
||||
throw new ArgumentException("Invalid padding detected.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the padding
|
||||
byte[] unpaddedData = new byte[data.Length - paddingLength];
|
||||
Array.Copy(data, unpaddedData, unpaddedData.Length);
|
||||
|
||||
return unpaddedData;
|
||||
}
|
||||
}
|
||||
}
|
755
WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/SEED.cs
Normal file
755
WelsonJS.Toolkit/WelsonJS.Toolkit/Cryptography/SEED.cs
Normal file
|
@ -0,0 +1,755 @@
|
|||
/*
|
||||
* WelsonJS.Toolkit: WelsonJS native component
|
||||
*
|
||||
* filename:
|
||||
* SEED.cs
|
||||
*
|
||||
* description:
|
||||
* SEED(ISO/IEC 18033-3) cryptography algorithm implementation (Experimental)
|
||||
*
|
||||
* website:
|
||||
* - https://github.com/gnh1201/welsonjs
|
||||
* - https://catswords.social/@catswords_oss
|
||||
* - https://teams.live.com/l/community/FEACHncAhq8ldnojAI
|
||||
* - https://discord.gg/XKG5CjtXEj
|
||||
*
|
||||
* author:
|
||||
* - Namhyeon Go (@gnh1201) <abuse@catswords.net>
|
||||
* - KISA(Korea Internet & Security Agency) (kisa.or.kr)
|
||||
*
|
||||
* references:
|
||||
* - https://seed.kisa.or.kr/kisa/Board/17/detailView.do
|
||||
* - https://www.iso.org/standard/54531.html
|
||||
* - https://ics.catswords.net/SEED%2B128_Specification_english_M.pdf
|
||||
* - https://ics.catswords.net/SEED_Algorithm_Specification_korean_M.pdf
|
||||
* - https://ics.catswords.net/SEED_sourcecode_explanation_korean.pdf
|
||||
*
|
||||
* license:
|
||||
* GPLv3 or MS-RL(Microsoft Reciprocal License)
|
||||
*
|
||||
*/
|
||||
using System;
|
||||
|
||||
namespace WelsonJS.Cryptography
|
||||
{
|
||||
public class SEED
|
||||
{
|
||||
public enum ENDIAN {
|
||||
BIG,
|
||||
LITTLE
|
||||
};
|
||||
private static ENDIAN DEFAULT_ENDIAN = ENDIAN.BIG;
|
||||
|
||||
// Constants for Key schedule
|
||||
private const uint KC0 = 0x9e3779b9;
|
||||
private const uint KC1 = 0x3c6ef373;
|
||||
private const uint KC2 = 0x78dde6e6;
|
||||
private const uint KC3 = 0xf1bbcdcc;
|
||||
private const uint KC4 = 0xe3779b99;
|
||||
private const uint KC5 = 0xc6ef3733;
|
||||
private const uint KC6 = 0x8dde6e67;
|
||||
private const uint KC7 = 0x1bbcdccf;
|
||||
private const uint KC8 = 0x3779b99e;
|
||||
private const uint KC9 = 0x6ef3733c;
|
||||
private const uint KC10 = 0xdde6e678;
|
||||
private const uint KC11 = 0xbbcdccf1;
|
||||
private const uint KC12 = 0x779b99e3;
|
||||
private const uint KC13 = 0xef3733c6;
|
||||
private const uint KC14 = 0xde6e678d;
|
||||
private const uint KC15 = 0xbcdccf1b;
|
||||
|
||||
private const int ABCD_A = 0;
|
||||
private const int ABCD_B = 1;
|
||||
private const int ABCD_C = 2;
|
||||
private const int ABCD_D = 3;
|
||||
|
||||
private const int LR_L0 = 0;
|
||||
private const int LR_L1 = 1;
|
||||
private const int LR_R0 = 2;
|
||||
private const int LR_R1 = 3;
|
||||
|
||||
private const int BLOCK_SIZE_SEED = 16;
|
||||
private const int BLOCK_SIZE_SEED_INT = 4;
|
||||
|
||||
// S-BOX
|
||||
private static readonly uint[] SS0 = new uint[] {
|
||||
0x2989a1a8, 0x05858184, 0x16c6d2d4, 0x13c3d3d0, 0x14445054, 0x1d0d111c, 0x2c8ca0ac, 0x25052124,
|
||||
0x1d4d515c, 0x03434340, 0x18081018, 0x1e0e121c, 0x11415150, 0x3cccf0fc, 0x0acac2c8, 0x23436360,
|
||||
0x28082028, 0x04444044, 0x20002020, 0x1d8d919c, 0x20c0e0e0, 0x22c2e2e0, 0x08c8c0c8, 0x17071314,
|
||||
0x2585a1a4, 0x0f8f838c, 0x03030300, 0x3b4b7378, 0x3b8bb3b8, 0x13031310, 0x12c2d2d0, 0x2ecee2ec,
|
||||
0x30407070, 0x0c8c808c, 0x3f0f333c, 0x2888a0a8, 0x32023230, 0x1dcdd1dc, 0x36c6f2f4, 0x34447074,
|
||||
0x2ccce0ec, 0x15859194, 0x0b0b0308, 0x17475354, 0x1c4c505c, 0x1b4b5358, 0x3d8db1bc, 0x01010100,
|
||||
0x24042024, 0x1c0c101c, 0x33437370, 0x18889098, 0x10001010, 0x0cccc0cc, 0x32c2f2f0, 0x19c9d1d8,
|
||||
0x2c0c202c, 0x27c7e3e4, 0x32427270, 0x03838380, 0x1b8b9398, 0x11c1d1d0, 0x06868284, 0x09c9c1c8,
|
||||
0x20406060, 0x10405050, 0x2383a3a0, 0x2bcbe3e8, 0x0d0d010c, 0x3686b2b4, 0x1e8e929c, 0x0f4f434c,
|
||||
0x3787b3b4, 0x1a4a5258, 0x06c6c2c4, 0x38487078, 0x2686a2a4, 0x12021210, 0x2f8fa3ac, 0x15c5d1d4,
|
||||
0x21416160, 0x03c3c3c0, 0x3484b0b4, 0x01414140, 0x12425250, 0x3d4d717c, 0x0d8d818c, 0x08080008,
|
||||
0x1f0f131c, 0x19899198, 0x00000000, 0x19091118, 0x04040004, 0x13435350, 0x37c7f3f4, 0x21c1e1e0,
|
||||
0x3dcdf1fc, 0x36467274, 0x2f0f232c, 0x27072324, 0x3080b0b0, 0x0b8b8388, 0x0e0e020c, 0x2b8ba3a8,
|
||||
0x2282a2a0, 0x2e4e626c, 0x13839390, 0x0d4d414c, 0x29496168, 0x3c4c707c, 0x09090108, 0x0a0a0208,
|
||||
0x3f8fb3bc, 0x2fcfe3ec, 0x33c3f3f0, 0x05c5c1c4, 0x07878384, 0x14041014, 0x3ecef2fc, 0x24446064,
|
||||
0x1eced2dc, 0x2e0e222c, 0x0b4b4348, 0x1a0a1218, 0x06060204, 0x21012120, 0x2b4b6368, 0x26466264,
|
||||
0x02020200, 0x35c5f1f4, 0x12829290, 0x0a8a8288, 0x0c0c000c, 0x3383b3b0, 0x3e4e727c, 0x10c0d0d0,
|
||||
0x3a4a7278, 0x07474344, 0x16869294, 0x25c5e1e4, 0x26062224, 0x00808080, 0x2d8da1ac, 0x1fcfd3dc,
|
||||
0x2181a1a0, 0x30003030, 0x37073334, 0x2e8ea2ac, 0x36063234, 0x15051114, 0x22022220, 0x38083038,
|
||||
0x34c4f0f4, 0x2787a3a4, 0x05454144, 0x0c4c404c, 0x01818180, 0x29c9e1e8, 0x04848084, 0x17879394,
|
||||
0x35053134, 0x0bcbc3c8, 0x0ecec2cc, 0x3c0c303c, 0x31417170, 0x11011110, 0x07c7c3c4, 0x09898188,
|
||||
0x35457174, 0x3bcbf3f8, 0x1acad2d8, 0x38c8f0f8, 0x14849094, 0x19495158, 0x02828280, 0x04c4c0c4,
|
||||
0x3fcff3fc, 0x09494148, 0x39093138, 0x27476364, 0x00c0c0c0, 0x0fcfc3cc, 0x17c7d3d4, 0x3888b0b8,
|
||||
0x0f0f030c, 0x0e8e828c, 0x02424240, 0x23032320, 0x11819190, 0x2c4c606c, 0x1bcbd3d8, 0x2484a0a4,
|
||||
0x34043034, 0x31c1f1f0, 0x08484048, 0x02c2c2c0, 0x2f4f636c, 0x3d0d313c, 0x2d0d212c, 0x00404040,
|
||||
0x3e8eb2bc, 0x3e0e323c, 0x3c8cb0bc, 0x01c1c1c0, 0x2a8aa2a8, 0x3a8ab2b8, 0x0e4e424c, 0x15455154,
|
||||
0x3b0b3338, 0x1cccd0dc, 0x28486068, 0x3f4f737c, 0x1c8c909c, 0x18c8d0d8, 0x0a4a4248, 0x16465254,
|
||||
0x37477374, 0x2080a0a0, 0x2dcde1ec, 0x06464244, 0x3585b1b4, 0x2b0b2328, 0x25456164, 0x3acaf2f8,
|
||||
0x23c3e3e0, 0x3989b1b8, 0x3181b1b0, 0x1f8f939c, 0x1e4e525c, 0x39c9f1f8, 0x26c6e2e4, 0x3282b2b0,
|
||||
0x31013130, 0x2acae2e8, 0x2d4d616c, 0x1f4f535c, 0x24c4e0e4, 0x30c0f0f0, 0x0dcdc1cc, 0x08888088,
|
||||
0x16061214, 0x3a0a3238, 0x18485058, 0x14c4d0d4, 0x22426260, 0x29092128, 0x07070304, 0x33033330,
|
||||
0x28c8e0e8, 0x1b0b1318, 0x05050104, 0x39497178, 0x10809090, 0x2a4a6268, 0x2a0a2228, 0x1a8a9298
|
||||
};
|
||||
|
||||
private static readonly uint[] SS1 = new uint[]
|
||||
{
|
||||
0x38380830, 0xe828c8e0, 0x2c2d0d21, 0xa42686a2, 0xcc0fcfc3, 0xdc1eced2, 0xb03383b3, 0xb83888b0,
|
||||
0xac2f8fa3, 0x60204060, 0x54154551, 0xc407c7c3, 0x44044440, 0x6c2f4f63, 0x682b4b63, 0x581b4b53,
|
||||
0xc003c3c3, 0x60224262, 0x30330333, 0xb43585b1, 0x28290921, 0xa02080a0, 0xe022c2e2, 0xa42787a3,
|
||||
0xd013c3d3, 0x90118191, 0x10110111, 0x04060602, 0x1c1c0c10, 0xbc3c8cb0, 0x34360632, 0x480b4b43,
|
||||
0xec2fcfe3, 0x88088880, 0x6c2c4c60, 0xa82888a0, 0x14170713, 0xc404c4c0, 0x14160612, 0xf434c4f0,
|
||||
0xc002c2c2, 0x44054541, 0xe021c1e1, 0xd416c6d2, 0x3c3f0f33, 0x3c3d0d31, 0x8c0e8e82, 0x98188890,
|
||||
0x28280820, 0x4c0e4e42, 0xf436c6f2, 0x3c3e0e32, 0xa42585a1, 0xf839c9f1, 0x0c0d0d01, 0xdc1fcfd3,
|
||||
0xd818c8d0, 0x282b0b23, 0x64264662, 0x783a4a72, 0x24270723, 0x2c2f0f23, 0xf031c1f1, 0x70324272,
|
||||
0x40024242, 0xd414c4d0, 0x40014141, 0xc000c0c0, 0x70334373, 0x64274763, 0xac2c8ca0, 0x880b8b83,
|
||||
0xf437c7f3, 0xac2d8da1, 0x80008080, 0x1c1f0f13, 0xc80acac2, 0x2c2c0c20, 0xa82a8aa2, 0x34340430,
|
||||
0xd012c2d2, 0x080b0b03, 0xec2ecee2, 0xe829c9e1, 0x5c1d4d51, 0x94148490, 0x18180810, 0xf838c8f0,
|
||||
0x54174753, 0xac2e8ea2, 0x08080800, 0xc405c5c1, 0x10130313, 0xcc0dcdc1, 0x84068682, 0xb83989b1,
|
||||
0xfc3fcff3, 0x7c3d4d71, 0xc001c1c1, 0x30310131, 0xf435c5f1, 0x880a8a82, 0x682a4a62, 0xb03181b1,
|
||||
0xd011c1d1, 0x20200020, 0xd417c7d3, 0x00020202, 0x20220222, 0x04040400, 0x68284860, 0x70314171,
|
||||
0x04070703, 0xd81bcbd3, 0x9c1d8d91, 0x98198991, 0x60214161, 0xbc3e8eb2, 0xe426c6e2, 0x58194951,
|
||||
0xdc1dcdd1, 0x50114151, 0x90108090, 0xdc1cccd0, 0x981a8a92, 0xa02383a3, 0xa82b8ba3, 0xd010c0d0,
|
||||
0x80018181, 0x0c0f0f03, 0x44074743, 0x181a0a12, 0xe023c3e3, 0xec2ccce0, 0x8c0d8d81, 0xbc3f8fb3,
|
||||
0x94168692, 0x783b4b73, 0x5c1c4c50, 0xa02282a2, 0xa02181a1, 0x60234363, 0x20230323, 0x4c0d4d41,
|
||||
0xc808c8c0, 0x9c1e8e92, 0x9c1c8c90, 0x383a0a32, 0x0c0c0c00, 0x2c2e0e22, 0xb83a8ab2, 0x6c2e4e62,
|
||||
0x9c1f8f93, 0x581a4a52, 0xf032c2f2, 0x90128292, 0xf033c3f3, 0x48094941, 0x78384870, 0xcc0cccc0,
|
||||
0x14150511, 0xf83bcbf3, 0x70304070, 0x74354571, 0x7c3f4f73, 0x34350531, 0x10100010, 0x00030303,
|
||||
0x64244460, 0x6c2d4d61, 0xc406c6c2, 0x74344470, 0xd415c5d1, 0xb43484b0, 0xe82acae2, 0x08090901,
|
||||
0x74364672, 0x18190911, 0xfc3ecef2, 0x40004040, 0x10120212, 0xe020c0e0, 0xbc3d8db1, 0x04050501,
|
||||
0xf83acaf2, 0x00010101, 0xf030c0f0, 0x282a0a22, 0x5c1e4e52, 0xa82989a1, 0x54164652, 0x40034343,
|
||||
0x84058581, 0x14140410, 0x88098981, 0x981b8b93, 0xb03080b0, 0xe425c5e1, 0x48084840, 0x78394971,
|
||||
0x94178793, 0xfc3cccf0, 0x1c1e0e12, 0x80028282, 0x20210121, 0x8c0c8c80, 0x181b0b13, 0x5c1f4f53,
|
||||
0x74374773, 0x54144450, 0xb03282b2, 0x1c1d0d11, 0x24250521, 0x4c0f4f43, 0x00000000, 0x44064642,
|
||||
0xec2dcde1, 0x58184850, 0x50124252, 0xe82bcbe3, 0x7c3e4e72, 0xd81acad2, 0xc809c9c1, 0xfc3dcdf1,
|
||||
0x30300030, 0x94158591, 0x64254561, 0x3c3c0c30, 0xb43686b2, 0xe424c4e0, 0xb83b8bb3, 0x7c3c4c70,
|
||||
0x0c0e0e02, 0x50104050, 0x38390931, 0x24260622, 0x30320232, 0x84048480, 0x68294961, 0x90138393,
|
||||
0x34370733, 0xe427c7e3, 0x24240420, 0xa42484a0, 0xc80bcbc3, 0x50134353, 0x080a0a02, 0x84078783,
|
||||
0xd819c9d1, 0x4c0c4c40, 0x80038383, 0x8c0f8f83, 0xcc0ecec2, 0x383b0b33, 0x480a4a42, 0xb43787b3
|
||||
};
|
||||
|
||||
private static readonly uint[] SS2 = new uint[]
|
||||
{
|
||||
0xa1a82989, 0x81840585, 0xd2d416c6, 0xd3d013c3, 0x50541444, 0x111c1d0d, 0xa0ac2c8c, 0x21242505,
|
||||
0x515c1d4d, 0x43400343, 0x10181808, 0x121c1e0e, 0x51501141, 0xf0fc3ccc, 0xc2c80aca, 0x63602343,
|
||||
0x20282808, 0x40440444, 0x20202000, 0x919c1d8d, 0xe0e020c0, 0xe2e022c2, 0xc0c808c8, 0x13141707,
|
||||
0xa1a42585, 0x838c0f8f, 0x03000303, 0x73783b4b, 0xb3b83b8b, 0x13101303, 0xd2d012c2, 0xe2ec2ece,
|
||||
0x70703040, 0x808c0c8c, 0x333c3f0f, 0xa0a82888, 0x32303202, 0xd1dc1dcd, 0xf2f436c6, 0x70743444,
|
||||
0xe0ec2ccc, 0x91941585, 0x03080b0b, 0x53541747, 0x505c1c4c, 0x53581b4b, 0xb1bc3d8d, 0x01000101,
|
||||
0x20242404, 0x101c1c0c, 0x73703343, 0x90981888, 0x10101000, 0xc0cc0ccc, 0xf2f032c2, 0xd1d819c9,
|
||||
0x202c2c0c, 0xe3e427c7, 0x72703242, 0x83800383, 0x93981b8b, 0xd1d011c1, 0x82840686, 0xc1c809c9,
|
||||
0x60602040, 0x50501040, 0xa3a02383, 0xe3e82bcb, 0x010c0d0d, 0xb2b43686, 0x929c1e8e, 0x434c0f4f,
|
||||
0xb3b43787, 0x52581a4a, 0xc2c406c6, 0x70783848, 0xa2a42686, 0x12101202, 0xa3ac2f8f, 0xd1d415c5,
|
||||
0x61602141, 0xc3c003c3, 0xb0b43484, 0x41400141, 0x52501242, 0x717c3d4d, 0x818c0d8d, 0x00080808,
|
||||
0x131c1f0f, 0x91981989, 0x00000000, 0x11181909, 0x00040404, 0x53501343, 0xf3f437c7, 0xe1e021c1,
|
||||
0xf1fc3dcd, 0x72743646, 0x232c2f0f, 0x23242707, 0xb0b03080, 0x83880b8b, 0x020c0e0e, 0xa3a82b8b,
|
||||
0xa2a02282, 0x626c2e4e, 0x93901383, 0x414c0d4d, 0x61682949, 0x707c3c4c, 0x01080909, 0x02080a0a,
|
||||
0xb3bc3f8f, 0xe3ec2fcf, 0xf3f033c3, 0xc1c405c5, 0x83840787, 0x10141404, 0xf2fc3ece, 0x60642444,
|
||||
0xd2dc1ece, 0x222c2e0e, 0x43480b4b, 0x12181a0a, 0x02040606, 0x21202101, 0x63682b4b, 0x62642646,
|
||||
0x02000202, 0xf1f435c5, 0x92901282, 0x82880a8a, 0x000c0c0c, 0xb3b03383, 0x727c3e4e, 0xd0d010c0,
|
||||
0x72783a4a, 0x43440747, 0x92941686, 0xe1e425c5, 0x22242606, 0x80800080, 0xa1ac2d8d, 0xd3dc1fcf,
|
||||
0xa1a02181, 0x30303000, 0x33343707, 0xa2ac2e8e, 0x32343606, 0x11141505, 0x22202202, 0x30383808,
|
||||
0xf0f434c4, 0xa3a42787, 0x41440545, 0x404c0c4c, 0x81800181, 0xe1e829c9, 0x80840484, 0x93941787,
|
||||
0x31343505, 0xc3c80bcb, 0xc2cc0ece, 0x303c3c0c, 0x71703141, 0x11101101, 0xc3c407c7, 0x81880989,
|
||||
0x71743545, 0xf3f83bcb, 0xd2d81aca, 0xf0f838c8, 0x90941484, 0x51581949, 0x82800282, 0xc0c404c4,
|
||||
0xf3fc3fcf, 0x41480949, 0x31383909, 0x63642747, 0xc0c000c0, 0xc3cc0fcf, 0xd3d417c7, 0xb0b83888,
|
||||
0x030c0f0f, 0x828c0e8e, 0x42400242, 0x23202303, 0x91901181, 0x606c2c4c, 0xd3d81bcb, 0xa0a42484,
|
||||
0x30343404, 0xf1f031c1, 0x40480848, 0xc2c002c2, 0x636c2f4f, 0x313c3d0d, 0x212c2d0d, 0x40400040,
|
||||
0xb2bc3e8e, 0x323c3e0e, 0xb0bc3c8c, 0xc1c001c1, 0xa2a82a8a, 0xb2b83a8a, 0x424c0e4e, 0x51541545,
|
||||
0x33383b0b, 0xd0dc1ccc, 0x60682848, 0x737c3f4f, 0x909c1c8c, 0xd0d818c8, 0x42480a4a, 0x52541646,
|
||||
0x73743747, 0xa0a02080, 0xe1ec2dcd, 0x42440646, 0xb1b43585, 0x23282b0b, 0x61642545, 0xf2f83aca,
|
||||
0xe3e023c3, 0xb1b83989, 0xb1b03181, 0x939c1f8f, 0x525c1e4e, 0xf1f839c9, 0xe2e426c6, 0xb2b03282,
|
||||
0x31303101, 0xe2e82aca, 0x616c2d4d, 0x535c1f4f, 0xe0e424c4, 0xf0f030c0, 0xc1cc0dcd, 0x80880888,
|
||||
0x12141606, 0x32383a0a, 0x50581848, 0xd0d414c4, 0x62602242, 0x21282909, 0x03040707, 0x33303303,
|
||||
0xe0e828c8, 0x13181b0b, 0x01040505, 0x71783949, 0x90901080, 0x62682a4a, 0x22282a0a, 0x92981a8a
|
||||
};
|
||||
|
||||
private static uint[] SS3 = new uint[]
|
||||
{
|
||||
0x08303838, 0xc8e0e828, 0x0d212c2d, 0x86a2a426, 0xcfc3cc0f, 0xced2dc1e, 0x83b3b033, 0x88b0b838,
|
||||
0x8fa3ac2f, 0x40606020, 0x45515415, 0xc7c3c407, 0x44404404, 0x4f636c2f, 0x4b63682b, 0x4b53581b,
|
||||
0xc3c3c003, 0x42626022, 0x03333033, 0x85b1b435, 0x09212829, 0x80a0a020, 0xc2e2e022, 0x87a3a427,
|
||||
0xc3d3d013, 0x81919011, 0x01111011, 0x06020406, 0x0c101c1c, 0x8cb0bc3c, 0x06323436, 0x4b43480b,
|
||||
0xcfe3ec2f, 0x88808808, 0x4c606c2c, 0x88a0a828, 0x07131417, 0xc4c0c404, 0x06121416, 0xc4f0f434,
|
||||
0xc2c2c002, 0x45414405, 0xc1e1e021, 0xc6d2d416, 0x0f333c3f, 0x0d313c3d, 0x8e828c0e, 0x88909818,
|
||||
0x08202828, 0x4e424c0e, 0xc6f2f436, 0x0e323c3e, 0x85a1a425, 0xc9f1f839, 0x0d010c0d, 0xcfd3dc1f,
|
||||
0xc8d0d818, 0x0b23282b, 0x46626426, 0x4a72783a, 0x07232427, 0x0f232c2f, 0xc1f1f031, 0x42727032,
|
||||
0x42424002, 0xc4d0d414, 0x41414001, 0xc0c0c000, 0x43737033, 0x47636427, 0x8ca0ac2c, 0x8b83880b,
|
||||
0xc7f3f437, 0x8da1ac2d, 0x80808000, 0x0f131c1f, 0xcac2c80a, 0x0c202c2c, 0x8aa2a82a, 0x04303434,
|
||||
0xc2d2d012, 0x0b03080b, 0xcee2ec2e, 0xc9e1e829, 0x4d515c1d, 0x84909414, 0x08101818, 0xc8f0f838,
|
||||
0x47535417, 0x8ea2ac2e, 0x08000808, 0xc5c1c405, 0x03131013, 0xcdc1cc0d, 0x86828406, 0x89b1b839,
|
||||
0xcff3fc3f, 0x4d717c3d, 0xc1c1c001, 0x01313031, 0xc5f1f435, 0x8a82880a, 0x4a62682a, 0x81b1b031,
|
||||
0xc1d1d011, 0x00202020, 0xc7d3d417, 0x02020002, 0x02222022, 0x04000404, 0x48606828, 0x41717031,
|
||||
0x07030407, 0xcbd3d81b, 0x8d919c1d, 0x89919819, 0x41616021, 0x8eb2bc3e, 0xc6e2e426, 0x49515819,
|
||||
0xcdd1dc1d, 0x41515011, 0x80909010, 0xccd0dc1c, 0x8a92981a, 0x83a3a023, 0x8ba3a82b, 0xc0d0d010,
|
||||
0x81818001, 0x0f030c0f, 0x47434407, 0x0a12181a, 0xc3e3e023, 0xcce0ec2c, 0x8d818c0d, 0x8fb3bc3f,
|
||||
0x86929416, 0x4b73783b, 0x4c505c1c, 0x82a2a022, 0x81a1a021, 0x43636023, 0x03232023, 0x4d414c0d,
|
||||
0xc8c0c808, 0x8e929c1e, 0x8c909c1c, 0x0a32383a, 0x0c000c0c, 0x0e222c2e, 0x8ab2b83a, 0x4e626c2e,
|
||||
0x8f939c1f, 0x4a52581a, 0xc2f2f032, 0x82929012, 0xc3f3f033, 0x49414809, 0x48707838, 0xccc0cc0c,
|
||||
0x05111415, 0xcbf3f83b, 0x40707030, 0x45717435, 0x4f737c3f, 0x05313435, 0x00101010, 0x03030003,
|
||||
0x44606424, 0x4d616c2d, 0xc6c2c406, 0x44707434, 0xc5d1d415, 0x84b0b434, 0xcae2e82a, 0x09010809,
|
||||
0x46727436, 0x09111819, 0xcef2fc3e, 0x40404000, 0x02121012, 0xc0e0e020, 0x8db1bc3d, 0x05010405,
|
||||
0xcaf2f83a, 0x01010001, 0xc0f0f030, 0x0a22282a, 0x4e525c1e, 0x89a1a829, 0x46525416, 0x43434003,
|
||||
0x85818405, 0x04101414, 0x89818809, 0x8b93981b, 0x80b0b030, 0xc5e1e425, 0x48404808, 0x49717839,
|
||||
0x87939417, 0xccf0fc3c, 0x0e121c1e, 0x82828002, 0x01212021, 0x8c808c0c, 0x0b13181b, 0x4f535c1f,
|
||||
0x47737437, 0x44505414, 0x82b2b032, 0x0d111c1d, 0x05212425, 0x4f434c0f, 0x00000000, 0x46424406,
|
||||
0xcde1ec2d, 0x48505818, 0x42525012, 0xcbe3e82b, 0x4e727c3e, 0xcad2d81a, 0xc9c1c809, 0xcdf1fc3d,
|
||||
0x00303030, 0x85919415, 0x45616425, 0x0c303c3c, 0x86b2b436, 0xc4e0e424, 0x8bb3b83b, 0x4c707c3c,
|
||||
0x0e020c0e, 0x40505010, 0x09313839, 0x06222426, 0x02323032, 0x84808404, 0x49616829, 0x83939013,
|
||||
0x07333437, 0xc7e3e427, 0x04202424, 0x84a0a424, 0xcbc3c80b, 0x43535013, 0x0a02080a, 0x87838407,
|
||||
0xc9d1d819, 0x4c404c0c, 0x83838003, 0x8f838c0f, 0xcec2cc0e, 0x0b33383b, 0x4a42480a, 0x87b3b437
|
||||
};
|
||||
|
||||
private static uint GetUIntFromByteArray(byte[] src, int srcOffset, ENDIAN endian = ENDIAN.BIG)
|
||||
{
|
||||
if (src == null || src.Length < srcOffset + 4)
|
||||
throw new ArgumentException("Invalid source array or offset.");
|
||||
|
||||
return (uint)(endian == ENDIAN.BIG
|
||||
? (src[srcOffset] & 0xFF) << 24 |
|
||||
(src[srcOffset + 1] & 0xFF) << 16 |
|
||||
(src[srcOffset + 2] & 0xFF) << 8 |
|
||||
(src[srcOffset + 3] & 0xFF)
|
||||
: (src[srcOffset] & 0xFF) |
|
||||
(src[srcOffset + 1] & 0xFF) << 8 |
|
||||
(src[srcOffset + 2] & 0xFF) << 16 |
|
||||
(src[srcOffset + 3] & 0xFF) << 24);
|
||||
}
|
||||
|
||||
private static byte GetByteFromUInt(uint value, int position)
|
||||
{
|
||||
if (position < 0 || position >= 4)
|
||||
throw new ArgumentException("Position must be between 0 and 3.");
|
||||
|
||||
return position > 0
|
||||
? (byte)((value >> (8 * position)) & 0xFF)
|
||||
: (byte)(value & 0xFF);
|
||||
}
|
||||
|
||||
public static void SetByteToUIntArray(ref uint[] dst, int byteOffset, byte value, ENDIAN endian)
|
||||
{
|
||||
if (dst == null || byteOffset < 0 || byteOffset >= dst.Length * 4)
|
||||
throw new ArgumentOutOfRangeException(nameof(byteOffset), "Invalid byte offset.");
|
||||
|
||||
int uintIndex = byteOffset / 4;
|
||||
int shiftValue = (endian == ENDIAN.BIG)
|
||||
? (3 - byteOffset % 4) * 8
|
||||
: (byteOffset % 4) * 8;
|
||||
|
||||
uint maskValue = (uint)(0xFF << shiftValue);
|
||||
uint maskValue2 = ~maskValue;
|
||||
uint valueToSet = (uint)(value & 0xFF) << shiftValue;
|
||||
|
||||
dst[uintIndex] = (dst[uintIndex] & maskValue2) | (valueToSet & maskValue);
|
||||
}
|
||||
|
||||
public static byte GetByteFromUIntArray(uint[] src, int byteOffset, ENDIAN endian)
|
||||
{
|
||||
if (src == null || byteOffset < 0 || byteOffset >= src.Length * 4)
|
||||
throw new ArgumentOutOfRangeException(nameof(byteOffset), "Invalid byte offset.");
|
||||
|
||||
int uintIndex = byteOffset / 4;
|
||||
int shiftValue = (endian == ENDIAN.BIG)
|
||||
? (3 - byteOffset % 4) * 8
|
||||
: (byteOffset % 4) * 8;
|
||||
|
||||
return (byte)((src[uintIndex] >> shiftValue) & 0xFF);
|
||||
}
|
||||
|
||||
private static uint[] ConvertToUIntArray(byte[] src, int inLen, ENDIAN endian = ENDIAN.BIG)
|
||||
{
|
||||
if (src == null)
|
||||
throw new ArgumentNullException(nameof(src), "source cannot be null.");
|
||||
|
||||
if (inLen <= 0 || inLen > src.Length)
|
||||
throw new ArgumentException("Invalid input length.", nameof(inLen));
|
||||
|
||||
int outLen = (inLen + 3) / 4;
|
||||
uint[] data = new uint[outLen];
|
||||
|
||||
for (int i = 0; i < outLen; i++)
|
||||
{
|
||||
data[i] = GetUIntFromByteArray(src, i * 4, endian);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private static byte[] ConvertToByteArray(uint[] src, int inLen, ENDIAN endian = ENDIAN.BIG)
|
||||
{
|
||||
if (src == null)
|
||||
throw new ArgumentNullException(nameof(src), "source cannot be null.");
|
||||
|
||||
if (inLen <= 0 || inLen > src.Length)
|
||||
throw new ArgumentException("Invalid input length.", nameof(inLen));
|
||||
|
||||
int outLen = inLen;
|
||||
byte[] data = new byte[outLen];
|
||||
|
||||
for (int i = 0; i < outLen; i++)
|
||||
{
|
||||
data[i] = GetByteFromUIntArray(src, i, endian);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private static uint Substitute(uint value)
|
||||
{
|
||||
return SS0[GetByteFromUInt(value, 0)] ^
|
||||
SS1[GetByteFromUInt(value, 1)] ^
|
||||
SS2[GetByteFromUInt(value, 2)] ^
|
||||
SS3[GetByteFromUInt(value, 3)];
|
||||
}
|
||||
|
||||
// Round function F and adding output of F to L.
|
||||
// L0, L1 : left input values at each round
|
||||
// R0, R1 : right input values at each round
|
||||
// K : round keys at each round
|
||||
private static void SeedRound(ref uint[] T, ref uint[] LR, int L0, int L1, int R0, int R1, uint[] K, int K_offset)
|
||||
{
|
||||
T[0] = LR[R0] ^ K[K_offset + 0];
|
||||
T[1] = LR[R1] ^ K[K_offset + 1];
|
||||
T[1] ^= T[0];
|
||||
T[1] = Substitute(T[1]);
|
||||
T[0] += T[1];
|
||||
T[0] = Substitute(T[0]);
|
||||
T[1] += T[0];
|
||||
T[1] = Substitute(T[1]);
|
||||
T[0] += T[1];
|
||||
LR[L0] ^= T[0]; LR[L1] ^= T[1];
|
||||
}
|
||||
|
||||
private static uint EndianChange(uint value)
|
||||
{
|
||||
return ((value & 0x000000FF) << 24) | // Move the first byte to the fourth byte position
|
||||
((value & 0x0000FF00) << 8) | // Move the second byte to the third byte position
|
||||
((value & 0x00FF0000) >> 8) | // Move the third byte to the second byte position
|
||||
((value & 0xFF000000) >> 24); // Move the fourth byte to the first byte position
|
||||
}
|
||||
|
||||
private static void RoundKeyUpdate0(ref uint[] T, ref uint[] K, int K_offset, ref uint[] ABCD, uint KC)
|
||||
{
|
||||
T[0] = ABCD[ABCD_A] + ABCD[ABCD_C] - KC;
|
||||
T[1] = ABCD[ABCD_B] + KC - ABCD[ABCD_D];
|
||||
K[K_offset + 0] = Substitute(T[0]);
|
||||
K[K_offset + 1] = Substitute(T[1]);
|
||||
T[0] = ABCD[ABCD_A];
|
||||
ABCD[ABCD_A] = ((ABCD[ABCD_A] >> 8) & 0x00ffffff) ^ (ABCD[ABCD_B] << 24);
|
||||
ABCD[ABCD_B] = ((ABCD[ABCD_B] >> 8) & 0x00ffffff) ^ (T[0] << 24);
|
||||
}
|
||||
|
||||
private static void RoundKeyUpdate1(ref uint[] T, ref uint[] K, int K_offset, ref uint[] ABCD, uint KC)
|
||||
{
|
||||
T[0] = ABCD[ABCD_A] + ABCD[ABCD_C] - KC;
|
||||
T[1] = ABCD[ABCD_B] + KC - ABCD[ABCD_D];
|
||||
K[K_offset + 0] = Substitute(T[0]);
|
||||
K[K_offset + 1] = Substitute(T[1]);
|
||||
T[0] = ABCD[ABCD_C];
|
||||
ABCD[ABCD_C] = (ABCD[ABCD_C] << 8) ^ ((ABCD[ABCD_D] >> 24) & 0x000000ff);
|
||||
ABCD[ABCD_D] = (ABCD[ABCD_D] << 8) ^ ((T[0] >> 24) & 0x000000ff);
|
||||
}
|
||||
|
||||
public class ECB
|
||||
{
|
||||
public void EncryptBlock(in uint[] _in, int in_offset, ref uint[] _out, int out_offset, KISA_SEED_KEY ks)
|
||||
{
|
||||
uint[] LR = new uint[4]; // Iuput/output values at each rounds
|
||||
uint[] T = new uint[2]; // Temporary variables for round function F
|
||||
uint[] K = ks.key_data; // Pointer of round keys
|
||||
|
||||
// Set up input values for first round
|
||||
LR[LR_L0] = _in[in_offset + 0];
|
||||
LR[LR_L1] = _in[in_offset + 1];
|
||||
LR[LR_R0] = _in[in_offset + 2];
|
||||
LR[LR_R1] = _in[in_offset + 3];
|
||||
|
||||
// Reorder for big endian
|
||||
// Because SEED use little endian order in default
|
||||
if (ENDIAN.BIG != DEFAULT_ENDIAN)
|
||||
{
|
||||
LR[LR_L0] = EndianChange(LR[LR_L0]);
|
||||
LR[LR_L1] = EndianChange(LR[LR_L1]);
|
||||
LR[LR_R0] = EndianChange(LR[LR_R0]);
|
||||
LR[LR_R1] = EndianChange(LR[LR_R1]);
|
||||
}
|
||||
|
||||
SeedRound(ref T, ref LR, LR_L0, LR_L1, LR_R0, LR_R1, K, 0); // Round 1
|
||||
SeedRound(ref T, ref LR, LR_R0, LR_R1, LR_L0, LR_L1, K, 2); // Round 2
|
||||
SeedRound(ref T, ref LR, LR_L0, LR_L1, LR_R0, LR_R1, K, 4); // Round 3
|
||||
SeedRound(ref T, ref LR, LR_R0, LR_R1, LR_L0, LR_L1, K, 6); // Round 4
|
||||
SeedRound(ref T, ref LR, LR_L0, LR_L1, LR_R0, LR_R1, K, 8); // Round 5
|
||||
SeedRound(ref T, ref LR, LR_R0, LR_R1, LR_L0, LR_L1, K, 10); // Round 6
|
||||
SeedRound(ref T, ref LR, LR_L0, LR_L1, LR_R0, LR_R1, K, 12); // Round 7
|
||||
SeedRound(ref T, ref LR, LR_R0, LR_R1, LR_L0, LR_L1, K, 14); // Round 8
|
||||
SeedRound(ref T, ref LR, LR_L0, LR_L1, LR_R0, LR_R1, K, 16); // Round 9
|
||||
SeedRound(ref T, ref LR, LR_R0, LR_R1, LR_L0, LR_L1, K, 18); // Round 10
|
||||
SeedRound(ref T, ref LR, LR_L0, LR_L1, LR_R0, LR_R1, K, 20); // Round 11
|
||||
SeedRound(ref T, ref LR, LR_R0, LR_R1, LR_L0, LR_L1, K, 22); // Round 12
|
||||
SeedRound(ref T, ref LR, LR_L0, LR_L1, LR_R0, LR_R1, K, 24); // Round 13
|
||||
SeedRound(ref T, ref LR, LR_R0, LR_R1, LR_L0, LR_L1, K, 26); // Round 14
|
||||
SeedRound(ref T, ref LR, LR_L0, LR_L1, LR_R0, LR_R1, K, 28); // Round 15
|
||||
SeedRound(ref T, ref LR, LR_R0, LR_R1, LR_L0, LR_L1, K, 30); // Round 16
|
||||
|
||||
if (ENDIAN.BIG != DEFAULT_ENDIAN)
|
||||
{
|
||||
LR[LR_L0] = EndianChange(LR[LR_L0]);
|
||||
LR[LR_L1] = EndianChange(LR[LR_L1]);
|
||||
LR[LR_R0] = EndianChange(LR[LR_R0]);
|
||||
LR[LR_R1] = EndianChange(LR[LR_R1]);
|
||||
}
|
||||
|
||||
// Copying output values from last round to pbData
|
||||
_out[out_offset + 0] = LR[LR_R0];
|
||||
_out[out_offset + 1] = LR[LR_R1];
|
||||
_out[out_offset + 2] = LR[LR_L0];
|
||||
_out[out_offset + 3] = LR[LR_L1];
|
||||
}
|
||||
|
||||
public void DecryptBlock(in uint[] _in, int in_offset, ref uint[] _out, int out_offset, KISA_SEED_KEY ks)
|
||||
{
|
||||
uint[] LR = new uint[4]; // Iuput/output values at each rounds
|
||||
uint[] T = new uint[2]; // Temporary variables for round function F
|
||||
uint[] K = ks.key_data; // Pointer of round keys
|
||||
|
||||
// Set up input values for first round
|
||||
LR[LR_L0] = _in[in_offset + 0];
|
||||
LR[LR_L1] = _in[in_offset + 1];
|
||||
LR[LR_R0] = _in[in_offset + 2];
|
||||
LR[LR_R1] = _in[in_offset + 3];
|
||||
|
||||
// Reorder for big endian
|
||||
if (ENDIAN.BIG != DEFAULT_ENDIAN)
|
||||
{
|
||||
LR[LR_L0] = EndianChange(LR[LR_L0]);
|
||||
LR[LR_L1] = EndianChange(LR[LR_L1]);
|
||||
LR[LR_R0] = EndianChange(LR[LR_R0]);
|
||||
LR[LR_R1] = EndianChange(LR[LR_R1]);
|
||||
}
|
||||
|
||||
SeedRound(ref T, ref LR, LR_L0, LR_L1, LR_R0, LR_R1, K, 30); // Round 1
|
||||
SeedRound(ref T, ref LR, LR_R0, LR_R1, LR_L0, LR_L1, K, 28); // Round 2
|
||||
SeedRound(ref T, ref LR, LR_L0, LR_L1, LR_R0, LR_R1, K, 26); // Round 3
|
||||
SeedRound(ref T, ref LR, LR_R0, LR_R1, LR_L0, LR_L1, K, 24); // Round 4
|
||||
SeedRound(ref T, ref LR, LR_L0, LR_L1, LR_R0, LR_R1, K, 22); // Round 5
|
||||
SeedRound(ref T, ref LR, LR_R0, LR_R1, LR_L0, LR_L1, K, 20); // Round 6
|
||||
SeedRound(ref T, ref LR, LR_L0, LR_L1, LR_R0, LR_R1, K, 18); // Round 7
|
||||
SeedRound(ref T, ref LR, LR_R0, LR_R1, LR_L0, LR_L1, K, 16); // Round 8
|
||||
SeedRound(ref T, ref LR, LR_L0, LR_L1, LR_R0, LR_R1, K, 14); // Round 9
|
||||
SeedRound(ref T, ref LR, LR_R0, LR_R1, LR_L0, LR_L1, K, 12); // Round 10
|
||||
SeedRound(ref T, ref LR, LR_L0, LR_L1, LR_R0, LR_R1, K, 10); // Round 11
|
||||
SeedRound(ref T, ref LR, LR_R0, LR_R1, LR_L0, LR_L1, K, 8); // Round 12
|
||||
SeedRound(ref T, ref LR, LR_L0, LR_L1, LR_R0, LR_R1, K, 6); // Round 13
|
||||
SeedRound(ref T, ref LR, LR_R0, LR_R1, LR_L0, LR_L1, K, 4); // Round 14
|
||||
SeedRound(ref T, ref LR, LR_L0, LR_L1, LR_R0, LR_R1, K, 2); // Round 15
|
||||
SeedRound(ref T, ref LR, LR_R0, LR_R1, LR_L0, LR_L1, K, 0); // Round 16
|
||||
|
||||
if (ENDIAN.BIG != DEFAULT_ENDIAN)
|
||||
{
|
||||
LR[LR_L0] = EndianChange(LR[LR_L0]);
|
||||
LR[LR_L1] = EndianChange(LR[LR_L1]);
|
||||
LR[LR_R0] = EndianChange(LR[LR_R0]);
|
||||
LR[LR_R1] = EndianChange(LR[LR_R1]);
|
||||
}
|
||||
|
||||
// Copy output values from last round to pbData
|
||||
_out[out_offset + 0] = LR[LR_R0];
|
||||
_out[out_offset + 1] = LR[LR_R1];
|
||||
_out[out_offset + 2] = LR[LR_L0];
|
||||
_out[out_offset + 3] = LR[LR_L1];
|
||||
}
|
||||
|
||||
public void Init(KISA_SEED_INFO pInfo, KISA_ENC_DEC enc, byte[] pbszUserKey)
|
||||
{
|
||||
uint[] ABCD = new uint[4]; // Iuput/output values at each rounds
|
||||
uint[] T = new uint[2]; // Temporary variable
|
||||
uint[] K;
|
||||
|
||||
if (pInfo == null || pbszUserKey == null)
|
||||
throw new ArgumentException("Invalid arguments");
|
||||
|
||||
K = pInfo.seed_key.key_data; // Pointer of round keys
|
||||
|
||||
pInfo.encrypt = enc.value;
|
||||
pInfo.last_block_flag = pInfo.buffer_length = 0;
|
||||
|
||||
// Set up input values for Key Schedule
|
||||
ABCD[ABCD_A] = GetUIntFromByteArray(pbszUserKey, 0 * 4, DEFAULT_ENDIAN);
|
||||
ABCD[ABCD_B] = GetUIntFromByteArray(pbszUserKey, 1 * 4, DEFAULT_ENDIAN);
|
||||
ABCD[ABCD_C] = GetUIntFromByteArray(pbszUserKey, 2 * 4, DEFAULT_ENDIAN);
|
||||
ABCD[ABCD_D] = GetUIntFromByteArray(pbszUserKey, 3 * 4, DEFAULT_ENDIAN);
|
||||
|
||||
// Reorder for big endian
|
||||
if (ENDIAN.BIG != DEFAULT_ENDIAN)
|
||||
{
|
||||
ABCD[ABCD_A] = EndianChange(ABCD[ABCD_A]);
|
||||
ABCD[ABCD_B] = EndianChange(ABCD[ABCD_B]);
|
||||
ABCD[ABCD_C] = EndianChange(ABCD[ABCD_C]);
|
||||
ABCD[ABCD_D] = EndianChange(ABCD[ABCD_D]);
|
||||
}
|
||||
|
||||
// i-th round keys( K_i,0 and K_i,1 ) are denoted as K[2*(i-1)] and K[2*i-1], respectively
|
||||
RoundKeyUpdate0(ref T, ref K, 0, ref ABCD, KC0); // K_1,0 and K_1,1
|
||||
RoundKeyUpdate1(ref T, ref K, 2, ref ABCD, KC1); // K_2,0 and K_2,1
|
||||
RoundKeyUpdate0(ref T, ref K, 4, ref ABCD, KC2); // K_3,0 and K_3,1
|
||||
RoundKeyUpdate1(ref T, ref K, 6, ref ABCD, KC3); // K_4,0 and K_4,1
|
||||
RoundKeyUpdate0(ref T, ref K, 8, ref ABCD, KC4); // K_5,0 and K_5,1
|
||||
RoundKeyUpdate1(ref T, ref K, 10, ref ABCD, KC5); // K_6,0 and K_6,1
|
||||
RoundKeyUpdate0(ref T, ref K, 12, ref ABCD, KC6); // K_7,0 and K_7,1
|
||||
RoundKeyUpdate1(ref T, ref K, 14, ref ABCD, KC7); // K_8,0 and K_8,1
|
||||
RoundKeyUpdate0(ref T, ref K, 16, ref ABCD, KC8); // K_9,0 and K_9,1
|
||||
RoundKeyUpdate1(ref T, ref K, 18, ref ABCD, KC9); // K_10,0 and K_10,1
|
||||
RoundKeyUpdate0(ref T, ref K, 20, ref ABCD, KC10); // K_11,0 and K_11,1
|
||||
RoundKeyUpdate1(ref T, ref K, 22, ref ABCD, KC11); // K_12,0 and K_12,1
|
||||
RoundKeyUpdate0(ref T, ref K, 24, ref ABCD, KC12); // K_13,0 and K_13,1
|
||||
RoundKeyUpdate1(ref T, ref K, 26, ref ABCD, KC13); // K_14,0 and K_14,1
|
||||
RoundKeyUpdate0(ref T, ref K, 28, ref ABCD, KC14); // K_15,0 and K_15,1
|
||||
|
||||
T[0] = ABCD[ABCD_A] + ABCD[ABCD_C] - KC15;
|
||||
T[1] = ABCD[ABCD_B] - ABCD[ABCD_D] + KC15;
|
||||
|
||||
K[30] = SS0[GetByteFromUInt(T[0], 0) & 0x0ff] ^ SS1[GetByteFromUInt(T[0], 1) & 0x0ff] ^ // K_16,0
|
||||
SS2[GetByteFromUInt(T[0], 2) & 0x0ff] ^ SS3[GetByteFromUInt(T[0], 3) & 0x0ff];
|
||||
K[31] = SS0[GetByteFromUInt(T[1], 0) & 0x0ff] ^ SS1[GetByteFromUInt(T[1], 1) & 0x0ff] ^ // K_16,1
|
||||
SS2[GetByteFromUInt(T[1], 2) & 0x0ff] ^ SS3[GetByteFromUInt(T[1], 3) & 0x0ff];
|
||||
}
|
||||
|
||||
public void Process(KISA_SEED_INFO pInfo, in uint[] _in, int inLen, ref uint[] _out, ref int[] outLen)
|
||||
{
|
||||
int nCurrentCount = BLOCK_SIZE_SEED;
|
||||
int in_offset = 0;
|
||||
int out_offset = 0;
|
||||
|
||||
if (pInfo == null || _in == null || _out == null || inLen <= 0)
|
||||
throw new ArgumentException("Invalid arguments.");
|
||||
|
||||
if (KISA_ENC_DEC._KISA_ENCRYPT == pInfo.encrypt)
|
||||
{
|
||||
while (nCurrentCount <= inLen)
|
||||
{
|
||||
EncryptBlock(_in, in_offset, ref _out, out_offset, pInfo.seed_key);
|
||||
nCurrentCount += BLOCK_SIZE_SEED;
|
||||
in_offset += BLOCK_SIZE_SEED_INT;
|
||||
out_offset += BLOCK_SIZE_SEED_INT;
|
||||
}
|
||||
|
||||
outLen[0] = nCurrentCount - BLOCK_SIZE_SEED;
|
||||
pInfo.buffer_length = inLen - outLen[0];
|
||||
Array.Copy(_in, in_offset, pInfo.ecb_buffer, 0, pInfo.buffer_length);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (nCurrentCount <= inLen)
|
||||
{
|
||||
DecryptBlock(_in, in_offset, ref _out, out_offset, pInfo.seed_key);
|
||||
nCurrentCount += BLOCK_SIZE_SEED;
|
||||
in_offset += BLOCK_SIZE_SEED_INT;
|
||||
out_offset += BLOCK_SIZE_SEED_INT;
|
||||
}
|
||||
outLen[0] = nCurrentCount - BLOCK_SIZE_SEED;
|
||||
Array.Copy(_out, out_offset - BLOCK_SIZE_SEED_INT, pInfo.ecb_last_block, 0, BLOCK_SIZE_SEED);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Close(KISA_SEED_INFO pInfo, uint[] _out, int out_offset, ref int[] outLen)
|
||||
{
|
||||
int nPaddngLen;
|
||||
|
||||
outLen[0] = 0;
|
||||
|
||||
if (_out == null)
|
||||
return false;
|
||||
|
||||
if (KISA_ENC_DEC._KISA_ENCRYPT == pInfo.encrypt)
|
||||
{
|
||||
nPaddngLen = BLOCK_SIZE_SEED - pInfo.buffer_length;
|
||||
for (int i = pInfo.buffer_length; i < BLOCK_SIZE_SEED; i++)
|
||||
{
|
||||
SetByteToUIntArray(ref pInfo.ecb_buffer, i, (byte)nPaddngLen, DEFAULT_ENDIAN);
|
||||
}
|
||||
EncryptBlock(pInfo.ecb_buffer, 0, ref _out, (out_offset) / 4, pInfo.seed_key);
|
||||
outLen[0] = BLOCK_SIZE_SEED;
|
||||
}
|
||||
else
|
||||
{
|
||||
nPaddngLen = GetByteFromUIntArray(pInfo.ecb_last_block, BLOCK_SIZE_SEED - 1, DEFAULT_ENDIAN);
|
||||
if (nPaddngLen > 0 && nPaddngLen <= BLOCK_SIZE_SEED)
|
||||
{
|
||||
for (int i = nPaddngLen; i > 0; i--)
|
||||
{
|
||||
SetByteToUIntArray(ref _out, out_offset - i, (byte)0x00, DEFAULT_ENDIAN);
|
||||
}
|
||||
outLen[0] = nPaddngLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public byte[] Encrypt(byte[] pbszUserKey, byte[] pbData, int offset, int length)
|
||||
{
|
||||
KISA_SEED_INFO info = new KISA_SEED_INFO();
|
||||
uint[] _out;
|
||||
uint[] data;
|
||||
byte[] cdata;
|
||||
int outLen;
|
||||
int[] nRetOutLen = new int[] { 0 };
|
||||
int[] nPaddingLen = new int[] { 0 };
|
||||
|
||||
byte[] pbszPlainText = new byte[length];
|
||||
Array.Copy(pbData, offset, pbszPlainText, 0, length);
|
||||
int nPlainTextLen = length;
|
||||
|
||||
int nPlainTextPadding = (BLOCK_SIZE_SEED - (nPlainTextLen) % BLOCK_SIZE_SEED);
|
||||
byte[] newpbszPlainText = new byte[nPlainTextLen + nPlainTextPadding];
|
||||
Array.Copy(pbszPlainText, newpbszPlainText, nPlainTextLen);
|
||||
|
||||
byte[] pbszCipherText = new byte[nPlainTextLen + nPlainTextPadding];
|
||||
|
||||
Init(info, KISA_ENC_DEC.KISA_ENCRYPT, pbszUserKey);
|
||||
|
||||
outLen = ((nPlainTextLen / 16) + 1) * 4;
|
||||
|
||||
_out = new uint[outLen];
|
||||
|
||||
data = ConvertToUIntArray(newpbszPlainText, nPlainTextLen);
|
||||
Process(info, data, nPlainTextLen, ref _out, ref nRetOutLen);
|
||||
Close(info, _out, nRetOutLen[0], ref nPaddingLen);
|
||||
|
||||
cdata = ConvertToByteArray(_out, nRetOutLen[0] + nPaddingLen[0]);
|
||||
Array.Copy(cdata, pbszCipherText, nRetOutLen[0] + nPaddingLen[0]);
|
||||
|
||||
data = null;
|
||||
cdata = null;
|
||||
_out = null;
|
||||
|
||||
return pbszCipherText;
|
||||
}
|
||||
|
||||
public byte[] Decrypt(byte[] pbszUserKey, byte[] pbData, int offset, int length)
|
||||
{
|
||||
byte[] result = new byte[] { };
|
||||
|
||||
KISA_SEED_INFO info = new KISA_SEED_INFO();
|
||||
uint[] _out;
|
||||
uint[] data;
|
||||
byte[] cdata;
|
||||
int outLen = 0;
|
||||
int[] nRetOutLen = new int[] { 0 };
|
||||
int[] nPaddingLen = new int[] { 0 };
|
||||
|
||||
byte[] pbszCipherText = pbData;
|
||||
int nCipherTextLen = length;
|
||||
|
||||
if (nCipherTextLen % BLOCK_SIZE_SEED > 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
byte[] newpbszCipherText = new byte[nCipherTextLen];
|
||||
Array.Copy(pbszCipherText, newpbszCipherText, nCipherTextLen);
|
||||
|
||||
byte[] pbszPlainText = new byte[nCipherTextLen];
|
||||
|
||||
Init(info, KISA_ENC_DEC.KISA_DECRYPT, pbszUserKey);
|
||||
|
||||
outLen = (nCipherTextLen / 16) * 4;
|
||||
_out = new uint[outLen];
|
||||
data = ConvertToUIntArray(newpbszCipherText, nCipherTextLen);
|
||||
Process(info, data, nCipherTextLen, ref _out, ref nRetOutLen);
|
||||
if (Close(info, _out, nRetOutLen[0], ref nPaddingLen))
|
||||
{
|
||||
cdata = ConvertToByteArray(_out, nRetOutLen[0] - nPaddingLen[0]);
|
||||
Array.Copy(cdata, pbszPlainText, nRetOutLen[0] - nPaddingLen[0]);
|
||||
int message_length = nRetOutLen[0] - nPaddingLen[0];
|
||||
|
||||
if (message_length < 0)
|
||||
{
|
||||
message_length = 0;
|
||||
}
|
||||
result = new byte[message_length];
|
||||
Array.Copy(pbszPlainText, 0, result, 0, message_length);
|
||||
|
||||
data = null;
|
||||
cdata = null;
|
||||
_out = null;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetDefaultEndian(ENDIAN endian)
|
||||
{
|
||||
DEFAULT_ENDIAN = endian;
|
||||
}
|
||||
|
||||
public class KISA_ENC_DEC
|
||||
{
|
||||
public const int _KISA_DECRYPT = 0;
|
||||
public const int _KISA_ENCRYPT = 1;
|
||||
|
||||
public int value;
|
||||
|
||||
public KISA_ENC_DEC(int value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static KISA_ENC_DEC KISA_ENCRYPT = new KISA_ENC_DEC(_KISA_ENCRYPT);
|
||||
public static KISA_ENC_DEC KISA_DECRYPT = new KISA_ENC_DEC(_KISA_DECRYPT);
|
||||
}
|
||||
|
||||
public class KISA_SEED_KEY
|
||||
{
|
||||
public uint[] key_data = new uint[32];
|
||||
|
||||
public void Init()
|
||||
{
|
||||
for (int i = 0; i < key_data.Length; i++)
|
||||
{
|
||||
key_data[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class KISA_SEED_INFO
|
||||
{
|
||||
public int encrypt;
|
||||
public KISA_SEED_KEY seed_key = new KISA_SEED_KEY();
|
||||
public uint[] ecb_buffer = new uint[4];
|
||||
public int buffer_length;
|
||||
public uint[] ecb_last_block = new uint[4];
|
||||
public int last_block_flag;
|
||||
|
||||
public KISA_SEED_INFO()
|
||||
{
|
||||
encrypt = 0;
|
||||
seed_key.Init();
|
||||
ecb_buffer[0] = ecb_buffer[1] = ecb_buffer[2] = ecb_buffer[3] = 0;
|
||||
buffer_length = 0;
|
||||
ecb_last_block[0] = ecb_last_block[1] = ecb_last_block[2] = ecb_last_block[3] = 0;
|
||||
last_block_flag = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,11 +6,11 @@ using System.Runtime.InteropServices;
|
|||
// 제어됩니다. 어셈블리와 관련된 정보를 수정하려면
|
||||
// 이러한 특성 값을 변경하세요.
|
||||
[assembly: AssemblyTitle("WelsonJS.Toolkit")]
|
||||
[assembly: AssemblyDescription("Toolkit for WelsonJS framework")]
|
||||
[assembly: AssemblyDescription("Toolkit for WelsonJS framework based applications")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Catswords")]
|
||||
[assembly: AssemblyProduct("WelsonJS")]
|
||||
[assembly: AssemblyCopyright("Catswords OSS, C-2021-000237, Opensource licensed under GPLv3 or MS-RL")]
|
||||
[assembly: AssemblyCopyright("Catswords OSS, GPLv3 or Ms-RL")]
|
||||
[assembly: AssemblyTrademark("WelsonJS")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
|
@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
|||
// 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호를
|
||||
// 기본값으로 할 수 있습니다.
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("0.2.7.22")]
|
||||
[assembly: AssemblyFileVersion("0.2.7.22")]
|
||||
[assembly: AssemblyVersion("0.2.7.54")]
|
||||
[assembly: AssemblyFileVersion("0.2.7.54")]
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
|
|
|
@ -225,7 +225,7 @@ namespace WelsonJS
|
|||
}
|
||||
|
||||
[ComVisible(true)]
|
||||
public string EncryptStringHIGHT(string key, string data)
|
||||
public string EncryptString(string key, string data)
|
||||
{
|
||||
byte[] userKey = Encoding.ASCII.GetBytes(key);
|
||||
byte[] dataIn = Encoding.UTF8.GetBytes(data);
|
||||
|
@ -235,7 +235,7 @@ namespace WelsonJS
|
|||
}
|
||||
|
||||
[ComVisible(true)]
|
||||
public string DecryptStringHIGHT(string key, string encryptedData)
|
||||
public string DecryptString(string key, string encryptedData)
|
||||
{
|
||||
byte[] userKey = Encoding.ASCII.GetBytes(key);
|
||||
byte[] dataIn = Convert.FromBase64String(encryptedData);
|
||||
|
|
|
@ -89,7 +89,12 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="BitmapUtils.cs" />
|
||||
<Compile Include="Compression\LZ77.cs" />
|
||||
<Compile Include="Cryptography\AnsiX923Padding.cs" />
|
||||
<Compile Include="Cryptography\ARIA.cs" />
|
||||
<Compile Include="Cryptography\HIGHT.cs" />
|
||||
<Compile Include="Cryptography\LEA.cs" />
|
||||
<Compile Include="Cryptography\PKCS5Padding.cs" />
|
||||
<Compile Include="Cryptography\SEED.cs" />
|
||||
<Compile Include="NamedSharedMemory.cs" />
|
||||
<Compile Include="ProcessUtils.cs" />
|
||||
<Compile Include="Prompt.cs" />
|
||||
|
|
|
@ -2,19 +2,21 @@
|
|||
<package >
|
||||
<metadata>
|
||||
<id>$id$</id>
|
||||
<version>0.2.7.22</version>
|
||||
<version>0.2.7.49</version>
|
||||
<title>$title$</title>
|
||||
<authors>Namhyeon Go</authors>
|
||||
<authors>Namhyeon Go, Catswords OSS</authors>
|
||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
||||
<license type="expression">GPL-3.0-only</license>
|
||||
<icon>logo.png</icon>
|
||||
<readme>README.md</readme>
|
||||
<projectUrl>https://github.com/gnh1201/welsonjs</projectUrl>
|
||||
<description>COM library for WelsonJS framework-based applications. Supports access to a Window Handle, Named Shared Memory, and INI files.</description>
|
||||
<releaseNotes>First release</releaseNotes>
|
||||
<description>Native toolkit for WelsonJS framework-based RPA applications.</description>
|
||||
<releaseNotes>Updated release</releaseNotes>
|
||||
<copyright>$copyright$</copyright>
|
||||
<tags>com scripting library javascript ini window-handle named-shared-memory</tags>
|
||||
<tags>rpa com scripting library javascript ini window-handle named-shared-memory</tags>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="assets\img\logo.png" />
|
||||
<file src="assets\docs\README.md" />
|
||||
</files>
|
||||
</package>
|
17
WelsonJS.Toolkit/WelsonJS.Toolkit/assets/docs/README.md
Normal file
17
WelsonJS.Toolkit/WelsonJS.Toolkit/assets/docs/README.md
Normal file
|
@ -0,0 +1,17 @@
|
|||
# WelsonJS.Toolkit
|
||||
|
||||
WelsonJS.Toolkit is a native toolkit for WelsonJS. Of course, it can also be used in other projects.
|
||||
|
||||
This library supports COM and provides the following features:
|
||||
|
||||
* Access and control Windows handles
|
||||
* Send keyboard and mouse click commands to Windows handles
|
||||
* Use Named Shared Memory
|
||||
* Read and modify INI files
|
||||
* Encryption (HIGHT)
|
||||
* Compression (LZ77)
|
||||
* Bitmap handling
|
||||
|
||||
For more details, refer to the [WelsonJS Documentation](https://catswords-oss.rdbl.io/5719744820/5330609327).
|
||||
|
||||
Source code available: https://github.com/gnh1201/welsonjs
|
102
app.js
102
app.js
|
@ -4,8 +4,9 @@
|
|||
//
|
||||
// Author: Namhyeon Go <abuse@catswords.net>
|
||||
// Repository: https://github.com/gnh1201/welsonjs
|
||||
// License: GPLv3 or MS-RL (Opensource)
|
||||
// Report abuse: abuse@catswords.net
|
||||
// Latest news: [ActivityPub @catswords_oss@catswords.social](https://catswords.social/@catswords_oss)
|
||||
// Latest news: ActivityPub @catswords_oss@catswords.social
|
||||
// Join our team: https://teams.live.com/l/community/FEACHncAhq8ldnojAI
|
||||
//
|
||||
"use strict";
|
||||
|
@ -45,7 +46,7 @@ var console = {
|
|||
},
|
||||
_echoCallback: null,
|
||||
_echo: function(args, type) {
|
||||
var message = "";
|
||||
var messages = [];
|
||||
var params = {
|
||||
type: type,
|
||||
scope: [],
|
||||
|
@ -53,32 +54,41 @@ var console = {
|
|||
datetime: new Date().toISOString()
|
||||
};
|
||||
|
||||
if (args.length > 0) {
|
||||
if (typeof args[0] === "string") {
|
||||
// if not type is "log", then "{type}: {message}"
|
||||
if (typeof type !== "undefined") {
|
||||
message += (type + ": " + this._join(args));
|
||||
} else {
|
||||
message += this._join(args);
|
||||
}
|
||||
this._echoDefault(message);
|
||||
this._messages.push(message);
|
||||
params.message = message;
|
||||
} else if (typeof args[0] === "object") {
|
||||
if ('message' in args[0]) {
|
||||
if (typeof type !== "undefined") {
|
||||
message += (type + ": " + args[0].message);
|
||||
var argl = args.length;
|
||||
for (var i = 0; i < argl; i++) {
|
||||
switch (typeof args[i]) {
|
||||
case "string":
|
||||
messages.push(args[i]);
|
||||
break;
|
||||
|
||||
case "number":
|
||||
case "boolean":
|
||||
messages.push(String(args[i]));
|
||||
break;
|
||||
|
||||
case "object":
|
||||
if ("message" in args[i]) {
|
||||
messages.push(args[i].message);
|
||||
for (var k in args[i]) {
|
||||
params[k] = args[i][k];
|
||||
}
|
||||
} else {
|
||||
message += args[0].message;
|
||||
messages.push("[object Object]");
|
||||
}
|
||||
}
|
||||
this._echoDefault(message);
|
||||
this._messages.push(args[0].message);
|
||||
for (var k in args[0]) {
|
||||
params[k] = args[0][k];
|
||||
}
|
||||
break;
|
||||
|
||||
case "unknown":
|
||||
messages.push("[unknown]");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var message = messages.join(' ');
|
||||
if (typeof type !== "undefined") {
|
||||
message = type + ": " + message;
|
||||
}
|
||||
this._echoDefault(message);
|
||||
this._messages.push(message);
|
||||
|
||||
if (params.scope.length > 0 && this._echoCallback != null) {
|
||||
try {
|
||||
|
@ -205,10 +215,12 @@ function require(pathname) {
|
|||
if (cache[FN]) return cache[FN];
|
||||
|
||||
var T = null;
|
||||
var pos = FN.indexOf('://');
|
||||
var sep = '://', pos = FN.indexOf(sep);
|
||||
if (pos > -1) {
|
||||
var scheme = FN.substring(0, pos);
|
||||
|
||||
// load script from a remote server
|
||||
if (["http", "https"].indexOf(FN.substring(0, pos)) > -1) {
|
||||
if (["http", "https"].indexOf(scheme) > -1) {
|
||||
require._addScriptProvider(function(url) {
|
||||
try {
|
||||
return require("lib/http").get(url);
|
||||
|
@ -217,7 +229,25 @@ function require(pathname) {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// load script from LIE(Language Inference Engine) service
|
||||
if (["ai"].indexOf(scheme) > -1) {
|
||||
require._addScriptProvider(function(url) {
|
||||
try {
|
||||
var text = url.substring(pos + sep.length);
|
||||
return require("lib/language-inference-engine")
|
||||
.create()
|
||||
.setProvider("openai")
|
||||
.inference(text, 0)
|
||||
.join(' ')
|
||||
;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// if exists the custom script providers
|
||||
if (require._scriptProviders.length > 0) {
|
||||
var i = 0;
|
||||
while (T == null && i < require._scriptProviders.length) {
|
||||
|
@ -315,7 +345,7 @@ function require(pathname) {
|
|||
});
|
||||
break;
|
||||
|
||||
case ".enc": // protected script (HIGHT, ISO/IEC 18033-3)
|
||||
case ".enc": // encrypted script (require WelsonJS.Toolkit)
|
||||
T = (function(data, o) {
|
||||
try {
|
||||
var s = '', i = 0, k = 6;
|
||||
|
@ -327,7 +357,7 @@ function require(pathname) {
|
|||
i++;
|
||||
}
|
||||
if (i == k) return '';
|
||||
return o.DecryptStringHIGHT(s, data);
|
||||
return o.DecryptString(s, data);
|
||||
} catch (e) {
|
||||
console.error("Failed to load the encrypted data:", e.message);
|
||||
return '';
|
||||
|
@ -633,7 +663,7 @@ if (typeof JSON === "undefined") {
|
|||
require("app/assets/js/core-js-3.38.0.minified");
|
||||
|
||||
// Squel.js SQL query string builder for Javascript
|
||||
var squel = require("app/assets/js/squel-basic-5.13.0.hiddentao-afa1cb5.wsh");
|
||||
var squel = require("app/assets/js/squel-basic-5.13.0-afa1cb5.wsh");
|
||||
|
||||
// JavaScript YAML parser and dumper.
|
||||
var yaml = require("app/assets/js/js-yaml-4.1.0.wsh");
|
||||
|
@ -645,6 +675,9 @@ var is = require("app/assets/js/is-0.9.0.min");
|
|||
//var Intl = require("app/assets/js/Intl-1.2.5-e93b114.min");
|
||||
//console.log(new Intl.NumberFormat().format(1234567890.123456));
|
||||
|
||||
// numbers.js - Advanced Mathematics Library for Node.js and JavaScript
|
||||
var numbers = require("app/assets/js/numbers-0.7.0.wsh");
|
||||
|
||||
// linq.js - LINQ for JavaScript
|
||||
var Enumerable = require("app/assets/js/linq-4.0.2.wsh")._default;
|
||||
|
||||
|
@ -660,10 +693,11 @@ function __main__() {
|
|||
console.log(" \\ V V / __/ \\__ \\ (_) | | | | |_| |___) |");
|
||||
console.log(" \\_/\\_/ \\___|_|___/\\___/|_| |_|\\___/|____/ ");
|
||||
console.log("");
|
||||
console.log(" WelsonJS - Build a Windows app on the Windows built-in JavaScript engine");
|
||||
console.log(" C-2021-000237 (cros.or.kr), 10.5281/zenodo.11382385 (doi.org), 2023-A0562 (oss.kr), Codename Macadamia");
|
||||
console.log(" This software is distributed as open source under the GPL 3.0 or MS-RL licenses.");
|
||||
console.log(" https://github.com/gnh1201/welsonjs");
|
||||
console.log(" WelsonJS - Build a Windows app on the Windows built-in JavaScript engine");
|
||||
console.log(" C-2021-000237 (cros.or.kr), 10.5281/zenodo.11382385 (doi.org), 2023-A0562 (oss.kr), Codename Macadamia");
|
||||
console.log(" This software is distributed as open source under the GPL 3.0 or MS-RL licenses.");
|
||||
console.log(" Please support this project: https://gnh1201.link");
|
||||
console.log(" Source code available: https://github.com/gnh1201/welsonjs");
|
||||
console.log("");
|
||||
|
||||
if (typeof window === "undefined") {
|
||||
|
|
3183
app/assets/js/numbers-0.7.0.wsh.js
Normal file
3183
app/assets/js/numbers-0.7.0.wsh.js
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -1,15 +0,0 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
|
||||
def main(args):
|
||||
if len(args) < 2:
|
||||
print("Insufficient arguments")
|
||||
sys.exit()
|
||||
|
||||
encoded_domain = args[1].encode('idna').decode("utf-8")
|
||||
|
||||
print(encoded_domain)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv)
|
86
app/assets/reg/fix_wsh_js_engine_not_found.reg
Normal file
86
app/assets/reg/fix_wsh_js_engine_not_found.reg
Normal file
|
@ -0,0 +1,86 @@
|
|||
Windows Registry Editor Version 5.00
|
||||
|
||||
;.JS file type association fix - Windows XP
|
||||
;Author : Ramesh Srinivasan
|
||||
;Created : Aug 30, 2007
|
||||
;Homepage: http://www.winhelponline.com
|
||||
|
||||
[HKEY_CLASSES_ROOT\.JS]
|
||||
@="JSFile"
|
||||
"CachedFilterIID"="{c1243ca0-bf96-11cd-b579-08002b30bfeb}"
|
||||
|
||||
[HKEY_CLASSES_ROOT\.JS\PersistentHandler]
|
||||
@="{5e941d80-bf96-11cd-b579-08002b30bfeb}"
|
||||
|
||||
|
||||
[HKEY_CLASSES_ROOT\JSFile]
|
||||
@="JScript Script File"
|
||||
"FriendlyTypeName"=hex(2):40,00,25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,\
|
||||
00,6f,00,6f,00,74,00,25,00,5c,00,53,00,79,00,73,00,74,00,65,00,6d,00,33,00,\
|
||||
32,00,5c,00,77,00,73,00,68,00,65,00,78,00,74,00,2e,00,64,00,6c,00,6c,00,2c,\
|
||||
00,2d,00,34,00,38,00,30,00,34,00,00,00
|
||||
|
||||
[HKEY_CLASSES_ROOT\JSFile\DefaultIcon]
|
||||
@=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,74,00,25,\
|
||||
00,5c,00,53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,57,00,53,00,\
|
||||
63,00,72,00,69,00,70,00,74,00,2e,00,65,00,78,00,65,00,2c,00,33,00,00,00
|
||||
|
||||
[HKEY_CLASSES_ROOT\JSFile\ScriptEngine]
|
||||
@="JScript"
|
||||
|
||||
[HKEY_CLASSES_ROOT\JSFile\ScriptHostEncode]
|
||||
@="{85131630-480C-11D2-B1F9-00C04F86C324}"
|
||||
|
||||
[HKEY_CLASSES_ROOT\JSFile\Shell]
|
||||
|
||||
[HKEY_CLASSES_ROOT\JSFile\Shell\Edit]
|
||||
@="&Edit"
|
||||
|
||||
[HKEY_CLASSES_ROOT\JSFile\Shell\Edit\Command]
|
||||
@="notepad.exe \"%1\""
|
||||
|
||||
[HKEY_CLASSES_ROOT\JSFile\Shell\Open]
|
||||
@="&Open"
|
||||
|
||||
[HKEY_CLASSES_ROOT\JSFile\Shell\Open\Command]
|
||||
@=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,74,00,25,\
|
||||
00,5c,00,53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,57,00,53,00,\
|
||||
63,00,72,00,69,00,70,00,74,00,2e,00,65,00,78,00,65,00,20,00,22,00,25,00,31,\
|
||||
00,22,00,20,00,25,00,2a,00,00,00
|
||||
|
||||
[HKEY_CLASSES_ROOT\JSFile\Shell\Open2]
|
||||
@="Open &with Command Prompt"
|
||||
|
||||
[HKEY_CLASSES_ROOT\JSFile\Shell\Open2\Command]
|
||||
@=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,74,00,25,\
|
||||
00,5c,00,53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,43,00,53,00,\
|
||||
63,00,72,00,69,00,70,00,74,00,2e,00,65,00,78,00,65,00,20,00,22,00,25,00,31,\
|
||||
00,22,00,20,00,25,00,2a,00,00,00
|
||||
|
||||
[HKEY_CLASSES_ROOT\JSFile\Shell\Print]
|
||||
@="&Print"
|
||||
|
||||
[HKEY_CLASSES_ROOT\JSFile\Shell\Print\Command]
|
||||
@=hex(2):25,00,53,00,79,00,73,00,74,00,65,00,6d,00,52,00,6f,00,6f,00,74,00,25,\
|
||||
00,5c,00,53,00,79,00,73,00,74,00,65,00,6d,00,33,00,32,00,5c,00,4e,00,6f,00,\
|
||||
74,00,65,00,70,00,61,00,64,00,2e,00,65,00,78,00,65,00,20,00,2f,00,70,00,20,\
|
||||
00,25,00,31,00,00,00
|
||||
|
||||
[HKEY_CLASSES_ROOT\JSFile\ShellEx]
|
||||
|
||||
[HKEY_CLASSES_ROOT\JSFile\ShellEx\DropHandler]
|
||||
@="{60254CA5-953B-11CF-8C96-00AA00B8708C}"
|
||||
|
||||
[HKEY_CLASSES_ROOT\JSFile\ShellEx\PropertySheetHandlers]
|
||||
|
||||
[HKEY_CLASSES_ROOT\JSFile\ShellEx\PropertySheetHandlers\WSHProps]
|
||||
@="{60254CA5-953B-11CF-8C96-00AA00B8708C}"
|
||||
|
||||
[HKEY_CLASSES_ROOT\JScript]
|
||||
@="JScript Language"
|
||||
|
||||
[HKEY_CLASSES_ROOT\JScript\CLSID]
|
||||
@="{f414c260-6ac0-11cf-b6d1-00aa00bbbb58}"
|
||||
|
||||
[HKEY_CLASSES_ROOT\JScript\OLEScript]
|
||||
|
|
@ -48,7 +48,13 @@ Router.add('/test', function(render) {
|
|||
};
|
||||
|
||||
var content = FILE.readFile(test_profile_filepath, FILE.CdoCharset.CdoUTF_8);
|
||||
var data = JSON.parse(content);
|
||||
var data;
|
||||
try {
|
||||
data = JSON.parse(content);
|
||||
} catch (e) {
|
||||
throw Error("JSON parse error: " + e.message);
|
||||
}
|
||||
|
||||
render("app/test.html", {
|
||||
"data": data
|
||||
});
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div class="col width-fill">
|
||||
<div class="col">
|
||||
<div class="panel cell">
|
||||
<div class="header">기능 테스트 목록</div>
|
||||
<div class="header">List of feature tests</div>
|
||||
{{for data.tests}}
|
||||
<div class="body">
|
||||
<div class="cell">
|
||||
|
@ -11,9 +11,9 @@
|
|||
<div class="col width-fill mobile-width-fill" style="position: relative">
|
||||
<span class="float-right" style="position: absolute; top: 0; right: 0;">
|
||||
{{if id == 'gui_check'}}
|
||||
<button class="button" type="button" onclick="javascript:gui_check()">시험</button>
|
||||
<button class="button" type="button" onclick="javascript:gui_check()">Test</button>
|
||||
{{else}}
|
||||
<button class="button" type="button" onclick="javascript:test_start('{{:id}}')">시험</button>
|
||||
<button class="button" type="button" onclick="javascript:test_start('{{:id}}')">Test</button>
|
||||
{{/if}}
|
||||
</span>
|
||||
<div class="col width-fill mobile-width-fill">
|
||||
|
|
|
@ -1,26 +1,50 @@
|
|||
REM bootstrap.bat
|
||||
REM WelsonJS 0.2.7
|
||||
REM https://github.com/gnh1201/welsonjs
|
||||
REM WelsonJS 0.2.7 bootstrapping script
|
||||
REM Source code available: https://github.com/gnh1201/welsonjs
|
||||
|
||||
@echo off
|
||||
pushd %~dp0
|
||||
|
||||
echo [*] Starting pre-configure script...
|
||||
:: Define variables
|
||||
set TOOLKIT_URL=https://catswords.blob.core.windows.net/welsonjs/welsonjs_toolkit_latest.cab
|
||||
set TOOLKIT_PATH=%APPDATA%\welsonjs\welsonjs_toolkit_latest.cab
|
||||
set TOOLKIT_EXTRACT_PATH=%APPDATA%\welsonjs
|
||||
set REGASM_PATH=%WINDIR%\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe
|
||||
set LOCAL_TOOLKIT_DLL=bin\x86\WelsonJS.Toolkit.dll
|
||||
set DOWNLOADED_TOOLKIT_DLL=%APPDATA%\welsonjs\WelsonJS.Toolkit.dll
|
||||
|
||||
echo [*] Registering HTA file association...
|
||||
:: Ensure directory exists
|
||||
if not exist "%APPDATA%\welsonjs" mkdir "%APPDATA%\welsonjs"
|
||||
|
||||
echo [*] Initializing WelsonJS pre-configuration...
|
||||
|
||||
:: Register HTA file association
|
||||
echo [*] Configuring HTA file association...
|
||||
reg import app\assets\reg\Default_HTA.reg
|
||||
|
||||
echo [*] Unlocking the performance limit of MSHTML...
|
||||
reg add "HKCU\Software\Microsoft\Internet Explorer\Styles" /f
|
||||
reg add "HKCU\Software\Microsoft\Internet Explorer\Styles" /v "MaxScriptStatements" /t REG_DWORD /d 0xFFFFFFFF /f
|
||||
|
||||
rem echo [*] Registering AutoItX component...
|
||||
rem regsvr32 /s "%PROGRAMFILES(X86)%\AutoIt3\AutoItX\AutoItX3.dll"
|
||||
rem regsvr32 /s "%PROGRAMFILES(X86)%\AutoIt3\AutoItX\AutoItX3_x64.dll"
|
||||
:: Determine which toolkit to use
|
||||
if exist "%LOCAL_TOOLKIT_DLL%" (
|
||||
echo [*] Local toolkit found. Using "%LOCAL_TOOLKIT_DLL%" for registration.
|
||||
set TOOLKIT_DLL=%LOCAL_TOOLKIT_DLL%
|
||||
) else if exist "%DOWNLOADED_TOOLKIT_DLL%" (
|
||||
echo [*] Downloaded toolkit found. Using "%DOWNLOADED_TOOLKIT_DLL%" for registration.
|
||||
set TOOLKIT_DLL=%DOWNLOADED_TOOLKIT_DLL%
|
||||
) else (
|
||||
echo [*] Toolkit not found locally. Downloading from external source...
|
||||
:: Download the latest WelsonJS.Toolkit component
|
||||
bitsadmin /transfer toolkit_download /download /priority normal %TOOLKIT_URL% %TOOLKIT_PATH%
|
||||
|
||||
:: Extract the downloaded CAB file
|
||||
echo [*] Extracting WelsonJS.Toolkit component...
|
||||
expand %TOOLKIT_PATH% -F:* %TOOLKIT_EXTRACT_PATH%
|
||||
|
||||
:: Set the downloaded DLL as the target
|
||||
set TOOLKIT_DLL=%DOWNLOADED_TOOLKIT_DLL%
|
||||
)
|
||||
|
||||
:: Register the WelsonJS.Toolkit component
|
||||
echo [*] Registering WelsonJS.Toolkit component...
|
||||
%WINDIR%\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe /codebase bin\x86\WelsonJS.Toolkit.dll
|
||||
REM %WINDIR%\Microsoft.NET\Framework64\v2.0.50727\RegAsm.exe /codebase bin\x64\WelsonJS.Toolkit.dll
|
||||
|
||||
echo [*] Done.
|
||||
%REGASM_PATH% /codebase %TOOLKIT_DLL%
|
||||
|
||||
:: Final step
|
||||
echo [*] Pre-configuration complete. Starting bootstrap script...
|
||||
cscript app.js bootstrap
|
||||
|
|
16
data/apikey.json
Normal file
16
data/apikey.json
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"chatgpt": "file:data/chatgpt_apikey.txt",
|
||||
"anthropic": "file:data/anthropic_apikey.txt",
|
||||
"groq": "file:data/groq_apikey.txt",
|
||||
"grok": "file:data/grok_apikey.txt",
|
||||
"gemini": "file:data/gemini_apikey.txt",
|
||||
"mistral": "file:data/mistral_apikey.txt",
|
||||
"deepseek": "file:data/deepseek_apikey.txt",
|
||||
"moonshot": "file:data/moonshot_apikey.txt",
|
||||
"clovastudio": "file:data/clovastudio_apikey.txt",
|
||||
"catswords-ai": "file:data/catswords_ai_apikey.txt",
|
||||
"scrapeops": "file:data/scrapeops_apikey.txt",
|
||||
"searchapi": "file:data/searchapi_apikey.txt",
|
||||
"aviationstack": "file:data/aviationstack_apikey.txt",
|
||||
"abuseipdb": "file:data/abuseipdb_apikey.txt"
|
||||
}
|
80
data/available_proxies.json
Normal file
80
data/available_proxies.json
Normal file
|
@ -0,0 +1,80 @@
|
|||
[
|
||||
{
|
||||
"type": "stateless",
|
||||
"provider": "scrapeops",
|
||||
"url": "https://proxy.scrapeops.io/v1/?api_key={api_key}&url={url}&render_js={render_js}&residential={residential}&country={country}&keep_headers={keep_headers}",
|
||||
"documentation": "https://scrapeops.io?fpr=namhyeon75"
|
||||
},
|
||||
{
|
||||
"type": "stateful",
|
||||
"provider": "scrapeops",
|
||||
"url": "http://scrapeops:{api_key}@residential-proxy.scrapeops.io:8181",
|
||||
"documentation": "https://scrapeops.io?fpr=namhyeon75"
|
||||
},
|
||||
{
|
||||
"type": "serp",
|
||||
"provider": "searchapi",
|
||||
"url": "https://www.searchapi.io/api/v1/search?api_key={api_key}&engine={engine}&q={q}",
|
||||
"documentation": "https://www.searchapi.io/?via=namhyeon"
|
||||
},
|
||||
{
|
||||
"type": "serp",
|
||||
"provider": "librey",
|
||||
"url": "https://serp.catswords.net/librex/api.php?q={q}&p=1&t=0",
|
||||
"documentation": "https://github.com/Ahwxorg/LibreY"
|
||||
},
|
||||
{
|
||||
"type": "serp",
|
||||
"provider": "invidious",
|
||||
"url": "https://invidious.jing.rocks/invidious/api/v1/search?q={q}",
|
||||
"documentation": "https://docs.invidious.io/instances/"
|
||||
},
|
||||
{
|
||||
"type": "stateless-jsonrpc2",
|
||||
"provider": "github.com/gnh1201/caterpillar",
|
||||
"url": "http://localhost:8080",
|
||||
"documentation": "https://github.com/gnh1201/caterpillar"
|
||||
},
|
||||
{
|
||||
"type": "stateful",
|
||||
"provider": "github.com/gnh1201/caterpillar",
|
||||
"url": "http://localhost:5555",
|
||||
"documentation": "https://github.com/gnh1201/caterpillar"
|
||||
},
|
||||
{
|
||||
"type": "stateful",
|
||||
"provider": "cloudflare",
|
||||
"url": "http://localhost:40000",
|
||||
"documentation": "https://developers.cloudflare.com/warp-client/warp-modes/"
|
||||
},
|
||||
{
|
||||
"type": "stateful",
|
||||
"provider": "fiddler",
|
||||
"url": "http://localhost:8888",
|
||||
"documentation": "https://www.telerik.com/fiddler/fiddler-classic"
|
||||
},
|
||||
{
|
||||
"type": "stateful",
|
||||
"provider": "fiddler2",
|
||||
"url": "http://localhost:8866",
|
||||
"documentation": "https://www.telerik.com/fiddler/fiddler-everywhere"
|
||||
},
|
||||
{
|
||||
"type": "stateful",
|
||||
"provider": "mitmproxy",
|
||||
"url": "http://localhost:8080",
|
||||
"documetation": "https://mitmproxy.org/"
|
||||
},
|
||||
{
|
||||
"type": "stateful",
|
||||
"provider": "burpsuite",
|
||||
"url": "http://localhost:8080",
|
||||
"documetation": "https://portswigger.net/burp"
|
||||
},
|
||||
{
|
||||
"type": "stateful",
|
||||
"provider": "zaproxy",
|
||||
"url": "http://localhost:8080",
|
||||
"documetation": "https://www.zaproxy.org/"
|
||||
}
|
||||
]
|
6
data/prompt_function_calling_en.json
Normal file
6
data/prompt_function_calling_en.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
[
|
||||
{
|
||||
"role": "system",
|
||||
"content": "If external information is required, provide the response according to the given conditions:\n\n* The type field should specify the search type (e.g., weather, location, stock, news, keyword), and the query field should specify the search target.\n* For types that require location information, request location information first.\n* The format must be in JSON-RPC 2.0.\n* The method should always be fixed as `get_search`."
|
||||
}
|
||||
]
|
6
data/prompt_function_calling_ko.json
Normal file
6
data/prompt_function_calling_ko.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
[
|
||||
{
|
||||
"role": "system",
|
||||
"content": "외부 정보가 필요한 경우 주어진 조건에 맞는 응답을 보내줘.\n\n* type 필드에 검색 유형(예: weather, location, stock, news, keyword), query 필드에 검색 대상을 지정\n* 위치 정보가 필요한 유형은 위치 정보를 먼저 요청\n* JSON-RPC 2.0 형식이여야 함.\n* method는 get_search으로 고정되어야 함."
|
||||
}
|
||||
]
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"description": "WelsonJS test profile (test-misc.json)",
|
||||
"released": "2024-09-27",
|
||||
"updated_on": "2025-01-15",
|
||||
"dependencies": {
|
||||
"welsonjs": "0.2.7"
|
||||
},
|
||||
|
@ -93,13 +93,28 @@
|
|||
},
|
||||
{
|
||||
"id": "proxy_custom_provider",
|
||||
"description": "HTTP proxy with an web proxy provider",
|
||||
"description": "HTTP request with an web proxy provider",
|
||||
"tags": ["Network", "HTTP"]
|
||||
},
|
||||
{
|
||||
"id": "proxy_serp",
|
||||
"description": "HTTP proxy with a SERP provider",
|
||||
"description": "HTTP request with a SERP provider",
|
||||
"tags": ["Network", "HTTP"]
|
||||
},
|
||||
{
|
||||
"id": "proxy_stateless_jsonrpc2",
|
||||
"description": "HTTP request with a JSON-RPC 2.0 based stateless proxy",
|
||||
"tags": ["Network", "HTTP"]
|
||||
},
|
||||
{
|
||||
"id": "numbers_test",
|
||||
"description": "number.js test",
|
||||
"tags": ["Mathematics"]
|
||||
},
|
||||
{
|
||||
"id": "backup_vmware_esxi",
|
||||
"description": "Open Virtualization Format (OVF) Tool for Broadcom/VMware virtualization infrastructures",
|
||||
"tags": ["Virtualization"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"description": "WelsonJS test profile for Microsoft Office",
|
||||
"released": "2024-06-02",
|
||||
"updated_on": "2024-06-02",
|
||||
"dependencies": {
|
||||
"welsonjs": "0.2.7"
|
||||
},
|
||||
"authors": [
|
||||
"Namhyeon Go <gnh1201@gmail.com>"
|
||||
"Namhyeon Go <abuse@catswords.net>"
|
||||
],
|
||||
"references": [
|
||||
"https://github.com/gnh1201/welsonjs",
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"description": "2023 South Korea OSS Contest Test Profile for WelsonJS",
|
||||
"released": "2023-10-30",
|
||||
"updated_on": "2023-10-30",
|
||||
"dependencies": {
|
||||
"welsonjs": "0.2.7"
|
||||
},
|
||||
"authors": [
|
||||
"Namhyeon Go <gnh1201@gmail.com>"
|
||||
"Namhyeon Go <abuse@catswords.net>"
|
||||
],
|
||||
"references": [
|
||||
"https://github.com/gnh1201/welsonjs",
|
||||
|
@ -39,358 +39,565 @@
|
|||
"tests": [
|
||||
{
|
||||
"id": "es5_polyfills",
|
||||
"description": "ES5 수준 이상의 폴리필(Polyfill) 성공 여부 (Windows 내장 엔진에서 ES5 수준 이상의 폴리필 수행)",
|
||||
"tags": ["Javascript 엔진", "ECMAScript Polyfills"]
|
||||
"description": "Indicates Whether Polyfill higher than ES5 level has successfully performed (Perform pollyfill higher than ES5 level in Windows built-in Engine)",
|
||||
"tags": [
|
||||
"Javascript engine",
|
||||
"ECMAScript Polyfills"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "registry_find_provider",
|
||||
"description": "레지스트리 제공자 찾기",
|
||||
"tags": ["Windows 시스템", "레지스트리(Registry) 제어"]
|
||||
"description": "find registry provider",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"Control Registry"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "registry_write",
|
||||
"description": "레지스트리 쓰기",
|
||||
"tags": ["Windows 시스템", "레지스트리(Registry) 제어"]
|
||||
"description": "writing Registry",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"control Registry"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "registry_read",
|
||||
"description": "레지스트리 읽기",
|
||||
"tags": ["Windows 시스템", "레지스트리(Registry) 제어"]
|
||||
"description": "reading Registry",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"control Registry"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "wmi_create_object",
|
||||
"description": "WMI 오브젝트 생성",
|
||||
"tags": ["Windows 시스템", "WMI(Windows Management Instrumentation) 제어"]
|
||||
"description": "create WMI object",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"control WMI(Windows Management Instrumentation) "
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "wmi_execute_query",
|
||||
"description": "WMI 쿼리 실행",
|
||||
"tags": ["Windows 시스템", "WMI(Windows Management Instrumentation) 제어"]
|
||||
"description": "executing WMI query",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"control WMI(Windows Management Instrumentation) "
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "wmi_result_query",
|
||||
"description": "WMI 쿼리 결과",
|
||||
"tags": ["Windows 시스템", "WMI(Windows Management Instrumentation) 제어"]
|
||||
"description": "the result of WMI query",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"control WMI(Windows Management Instrumentation) "
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "shell_create_object",
|
||||
"description": "쉘(Shell) 오브젝트 생성",
|
||||
"tags": ["Windows 시스템", "Windows 쉘(Shell)"]
|
||||
"description": "create Shell object",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"Windows Shell"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "shell_build_command_line",
|
||||
"description": "명령 행 빌드 (입력: Array Object, 출력: Unescaped Command String)",
|
||||
"tags": ["Windows 시스템", "Windows 쉘(Shell)"]
|
||||
"description": "building command line (input: Array Object, output: Unescaped Command String)",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"Windows Shell"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "shell_set_charset",
|
||||
"description": "문자셋(Charset) 설정",
|
||||
"tags": ["Windows 시스템", "Windows 쉘(Shell)"]
|
||||
"description": "set Charset",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"Windows Shell"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "shell_working_directory",
|
||||
"description": "작업 디렉토리(Working Directory) 설정",
|
||||
"tags": ["Windows 시스템", "Windows 쉘(Shell)"]
|
||||
"description": "set Working Directory",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"Windows Shell"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "shell_create_process",
|
||||
"description": "프로세스 생성",
|
||||
"tags": ["Windows 시스템", "Windows 쉘(Shell)"]
|
||||
"description": "creating process",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"Windows Shell"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "shell_execute",
|
||||
"description": "쉘 명령어 실행 (결과(stdout, stderr)를 수신)",
|
||||
"tags": ["Windows 시스템", "Windows 쉘(Shell)"]
|
||||
"description": "execute shell command (receive results(stdout, stderr))",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"Windows Shell"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "shell_run",
|
||||
"description": "쉘 명령어 실행 (결과와 무관하게 fork)",
|
||||
"tags": ["Windows 시스템", "Windows 쉘(Shell)"]
|
||||
"description": "run shell command (fork)regardless of result",
|
||||
"tags": "run shell command (fork) regardless of result"
|
||||
},
|
||||
{
|
||||
"id": "shell_run_as",
|
||||
"description": "쉘 명령어 실행 (관리자 권한으로 실행)",
|
||||
"tags": ["Windows 시스템", "Windows 쉘(Shell)"]
|
||||
"description": "run shell command (run with administrator's authority)",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"Windows Shell"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "shell_find_my_documents",
|
||||
"description": "내 문서(My Documents) 위치 가져오기",
|
||||
"tags": ["Windows 시스템", "Windows 쉘(Shell)"]
|
||||
"description": "bring (My Documents) location",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"Windows Shell"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "shell_release",
|
||||
"description": "생성된 쉘 오브젝트 해제",
|
||||
"tags": ["Windows 시스템", "Windows 쉘(Shell)"]
|
||||
"description": "release created shell object",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"Windows Shell"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "powershell_set_command",
|
||||
"description": "실행할 명령(커맨드라인) 지정",
|
||||
"tags": ["Windows 시스템", "Windows 파워쉘(Powershell)"]
|
||||
"description": "Set command line to execute",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"Windows Powershell"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "powershell_set_file",
|
||||
"description": "실행할 파일(*.ps1) 지정",
|
||||
"tags": ["Windows 시스템", "Windows 파워쉘(Powershell)"]
|
||||
"description": "set files(*.ps1)to execute",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"Windows Powershell"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "powershell_set_uri",
|
||||
"description": "URI를 이용하여 명령 지정",
|
||||
"tags": ["Windows 시스템", "Windows 파워쉘(Powershell)"]
|
||||
"description": "Use URI to set commands",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"Windows Powershell"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "powershell_execute",
|
||||
"description": "명령 실행 (유저 모드)",
|
||||
"tags": ["Windows 시스템", "Windows 파워쉘(Powershell)"]
|
||||
"description": "Execute command (user mode)",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"Windows Powershell"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "powershell_run_as",
|
||||
"description": "명령 실행 (관리자 모드)",
|
||||
"tags": ["Windows 시스템", "Windows 파워쉘(Powershell)"]
|
||||
"description": "Execute command (administrator mode)",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"Windows Powershell"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "system_resolve_env",
|
||||
"description": "환경변수 해석기(Resolver)가 환경변수를 적절히 해석하는지 확인",
|
||||
"tags": ["Windows 시스템", "시스템 정보"]
|
||||
"description": "Verify if the environment variable resolver interprets environment variables correctly",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"System Information"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "system_check_as",
|
||||
"description": "현재 프로세스 자신이 관리자 모드인지 체크",
|
||||
"tags": ["Windows 시스템", "시스템 정보"]
|
||||
"description": "Check if the current process is in administrator mode",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"System Information"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "system_get_os_version",
|
||||
"description": "현재 OS 버전 불러오기",
|
||||
"tags": ["Windows 시스템", "시스템 정보"]
|
||||
"description": "Get current OS version",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"System Information"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "system_get_architecture",
|
||||
"description": "현재 아키텍쳐 불러오기",
|
||||
"tags": ["Windows 시스템", "시스템 정보"]
|
||||
"description": "Get current system architecture",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"System Information"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "system_get_uuid",
|
||||
"description": "현재 장치 고유번호(UUID) 불러오기",
|
||||
"tags": ["Windows 시스템", "시스템 정보"]
|
||||
"description": "bringing the UUID of current device",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"System Information"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "system_get_working_directory",
|
||||
"description": "현재 작업 디렉토리 불러오기",
|
||||
"tags": ["Windows 시스템", "시스템 정보"]
|
||||
"description": "bringing current working directory",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"System Information"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "system_get_script_directory",
|
||||
"description": "현재 스크립트 디렉토리 불러오기",
|
||||
"tags": ["Windows 시스템", "시스템 정보"]
|
||||
"description": "bringing current script directory",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"System Information"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "system_get_network_interfaces",
|
||||
"description": "네트워크 인터페이스 정보 불러오기",
|
||||
"tags": ["Windows 시스템", "시스템 정보"]
|
||||
"description": "bringing network interface information",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"System Information"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "system_get_process_list",
|
||||
"description": "활성 프로세스 목록 불러오기",
|
||||
"tags": ["Windows 시스템", "시스템 정보"]
|
||||
"description": "get activated ",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"System Information"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "system_get_process_list_by_name",
|
||||
"description": "프로세스 이름으로 특정 활성 프로세스 찾기",
|
||||
"tags": ["Windows 시스템", "시스템 정보"]
|
||||
"description": "find certain active process by process name",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"System Information"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "system_register_uri",
|
||||
"description": "URI를 등록하고 URI 요청 내용에 따른 명령 수행",
|
||||
"tags": ["Windows 시스템", "URI(Uniform Resource Identifier) 등록"]
|
||||
"description": "Register URI and carry out command as URI has requested",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"Register URI(Uniform Resource Identifier)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "system_pipe_ipc",
|
||||
"description": "두개 이상의 프로세스 간 통신",
|
||||
"tags": ["Windows 시스템", "IPC(프로세스 간 통신)"]
|
||||
"description": "Interprocess communication between more than 2 processes",
|
||||
"tags": [
|
||||
"Windows Systems",
|
||||
"IPC(Inter Process Communication)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "vhid_find_window",
|
||||
"description": "활성창(Window) 핸들 찾기",
|
||||
"tags": ["휴먼 인터페이스", "가상 휴면 인터페이스"]
|
||||
"description": "find active window handle",
|
||||
"tags": [
|
||||
"human interface",
|
||||
"virtual human interface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "vhid_send_click",
|
||||
"description": "가상 클릭(Click) 보내기",
|
||||
"tags": ["휴먼 인터페이스", "가상 휴면 인터페이스"]
|
||||
"description": "send virtual click",
|
||||
"tags": [
|
||||
"human interface",
|
||||
"virtual human interface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "vhid_send_keys",
|
||||
"description": "가상 문자키(a-zA-Z0-9) 보내기",
|
||||
"tags": ["휴먼 인터페이스", "가상 휴면 인터페이스"]
|
||||
"description": "Send virtual text key (a-zA-Z0-9)",
|
||||
"tags": [
|
||||
"human interface",
|
||||
"virtual human interface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "vhid_send_key_enter",
|
||||
"description": "가상 엔터키 보내기",
|
||||
"tags": ["휴먼 인터페이스", "가상 휴면 인터페이스"]
|
||||
"description": "send virtual enter key",
|
||||
"tags": [
|
||||
"human interface",
|
||||
"virtual human interface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "vhid_send_key_functions",
|
||||
"description": "가상 FN키 보내기",
|
||||
"tags": ["휴먼 인터페이스", "가상 휴면 인터페이스"]
|
||||
"description": "Send virtual FN key",
|
||||
"tags": [
|
||||
"human interface",
|
||||
"virtual human interface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "vhid_alert",
|
||||
"description": "Alert() API 호출 시 메시지 출력 여부",
|
||||
"tags": ["휴먼 인터페이스", "가상 휴면 인터페이스"]
|
||||
"description": "Alert whether message output will be provided when API is called",
|
||||
"tags": [
|
||||
"human interface",
|
||||
"virtual human interface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "vhid_confirm",
|
||||
"description": "Confirm() API 호출 시 메시지 출력 및 Yes/No 선택",
|
||||
"tags": ["휴먼 인터페이스", "가상 휴면 인터페이스"]
|
||||
"description": "Confirm() message output when API is called and choose between Yes/No",
|
||||
"tags": [
|
||||
"human interface",
|
||||
"virtual human interface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "vhid_prompt",
|
||||
"description": "Prompt() API 호출 시 서술형 응답 받을 수 있음",
|
||||
"tags": ["휴먼 인터페이스", "가상 휴면 인터페이스"]
|
||||
"description": "Prompt() When calling API, can receive descriptive response",
|
||||
"tags": [
|
||||
"human interface",
|
||||
"virtual human interface"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "network_http_get",
|
||||
"description": "HTTP GET 전송",
|
||||
"tags": ["네트워크", "HTTP 전송 및 처리"]
|
||||
"description": "Send HTTP GET",
|
||||
"tags": [
|
||||
"network",
|
||||
"Send HTTP and handle HTTP"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "network_http_post",
|
||||
"description": "HTTP POST 전송",
|
||||
"tags": ["네트워크", "HTTP 전송 및 처리"]
|
||||
"description": "Send HTTP POST",
|
||||
"tags": [
|
||||
"network",
|
||||
"send HTTP and handle HTTP"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "network_http_extended",
|
||||
"description": "HTTP 확장 메소드(FETCH, PUT 등) 전송",
|
||||
"tags": ["네트워크", "HTTP 전송 및 처리"]
|
||||
"description": "send HTTP extension methods(FETCH, PUT, etc)",
|
||||
"tags": [
|
||||
"network",
|
||||
"send HTTP and handle HTTP"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "network_attach_debugger",
|
||||
"description": "HTTP 디버거(Fiddler 등) 설정(Attach) 지원",
|
||||
"tags": ["네트워크", "HTTP 전송 및 처리"]
|
||||
"description": "support attaching HTTP debugger(Fiddler, etc)",
|
||||
"tags": [
|
||||
"network",
|
||||
"send HTTP and handle HTTP"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "network_detect_charset",
|
||||
"description": "HTTP 응답 본문에서 문자셋(Charset) 탐지",
|
||||
"tags": ["네트워크", "HTTP 전송 및 처리"]
|
||||
"description": "detect Charset in HTTP response body",
|
||||
"tags": [
|
||||
"network",
|
||||
"send HTTP and handle HTTP"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "network_detect_http_ssl",
|
||||
"description": "접속 대상 웹사이트의 보안통신(SSL) 사용 여부 탐지",
|
||||
"tags": ["네트워크", "HTTP 전송 및 처리"]
|
||||
"description": "detect whether SSL is running in the website to access ",
|
||||
"tags": [
|
||||
"network",
|
||||
"send HTTP and handle HTTP"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "network_send_icmp",
|
||||
"description": "PING(ICMP) 전송",
|
||||
"tags": ["네트워크", "PING(ICMP) 전송"]
|
||||
"description": "send PING(ICMP)",
|
||||
"tags": [
|
||||
"network",
|
||||
"send PING(ICMP)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "extramath_dtm",
|
||||
"description": "2개 이상의 주어진 문장으로부터 DTM (문서-용어 행렬) 생성",
|
||||
"tags": ["고급 문자열 처리", "자연어 처리"]
|
||||
"description": "create DTM (Document-Term Matrix) from more than 2 sentences that are provided",
|
||||
"tags": [
|
||||
"advanced string manipulation",
|
||||
"natural language processing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "extramath_cosine_similarity",
|
||||
"description": "주어진 두 문장의 유사도를 코사인 유사도로 비교",
|
||||
"tags": ["고급 문자열 처리", "자연어 처리"]
|
||||
"description": "compare the similarity of 2 given sentences with cosine similarity",
|
||||
"tags": [
|
||||
"advanced string manipulation",
|
||||
"natural language processing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "base64_encode",
|
||||
"description": "BASE64 인코딩",
|
||||
"tags": ["고급 문자열 처리", "BASE64"]
|
||||
"description": "BASE64 encoding",
|
||||
"tags": [
|
||||
"advanced string manipulation",
|
||||
"BASE64"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "base64_decode",
|
||||
"description": "BASE64 디코딩",
|
||||
"tags": ["고급 문자열 처리", "BASE64"]
|
||||
"description": "BASE64 decoding",
|
||||
"tags": [
|
||||
"advanced string manipulation",
|
||||
"BASE64"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "chromium_run",
|
||||
"description": "웹 브라우저 실행",
|
||||
"tags": ["웹 브라우저 제어", "웹 브라우저 제어 (크로미움 계열)"]
|
||||
"description": "run web browser",
|
||||
"tags": [
|
||||
"control web browser",
|
||||
"control web browser (Chromium-based)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "chromium_create_profile",
|
||||
"description": "프로파일 생성",
|
||||
"tags": ["웹 브라우저 제어", "웹 브라우저 제어 (크로미움 계열)"]
|
||||
"description": "create profile",
|
||||
"tags": [
|
||||
"control web browser",
|
||||
"control web browser (Chromium-based)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "chromium_run_incognito",
|
||||
"description": "개인정보 보호 모드로 웹 브라우저 실행",
|
||||
"tags": ["웹 브라우저 제어", "웹 브라우저 제어 (크로미움 계열)"]
|
||||
"description": "run web browser in incognito mode",
|
||||
"tags": [
|
||||
"control web browser",
|
||||
"control web browser (Chromium-based)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "chromium_navigate",
|
||||
"description": "URL로 주소 이동",
|
||||
"tags": ["웹 브라우저 제어", "웹 브라우저 제어 (크로미움 계열)"]
|
||||
"description": "move to another address through URL",
|
||||
"tags": [
|
||||
"control web browser",
|
||||
"control web browser (Chromium-based)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "chromium_get_active_pages",
|
||||
"description": "활성 페이지 목록 불러오기",
|
||||
"tags": ["웹 브라우저 제어", "웹 브라우저 제어 (크로미움 계열)"]
|
||||
"description": "bringing active page list",
|
||||
"tags": [
|
||||
"control web browser",
|
||||
"control web browser (Chromium-based)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "chromium_find_page_by_id",
|
||||
"description": "고유 ID로 페이지 찾기",
|
||||
"tags": ["웹 브라우저 제어", "웹 브라우저 제어 (크로미움 계열)"]
|
||||
"description": "finding page by original ID",
|
||||
"tags": [
|
||||
"control web browser",
|
||||
"control web browser (Chromium-based)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "chromium_find_pages_by_title",
|
||||
"description": "페이지 제목으로 페이지 찾기",
|
||||
"tags": ["웹 브라우저 제어", "웹 브라우저 제어 (크로미움 계열)"]
|
||||
"description": "finding pages by title of the pages",
|
||||
"tags": [
|
||||
"control web browser",
|
||||
"control web browser (Chromium-based)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "chromium_move_focused",
|
||||
"description": "창 포커스 이동",
|
||||
"tags": ["웹 브라우저 제어", "웹 브라우저 제어 (크로미움 계열)"]
|
||||
"description": "move focus of the window",
|
||||
"tags": [
|
||||
"control web browser",
|
||||
"control web browser (Chromium-based)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "chromium_adjust_window_size",
|
||||
"description": "창 크기 제어",
|
||||
"tags": ["웹 브라우저 제어", "웹 브라우저 제어 (크로미움 계열)"]
|
||||
"description": "adjust size of the window",
|
||||
"tags": [
|
||||
"control web browser",
|
||||
"control web browser (Chromium-based)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "chromium_get_element_position",
|
||||
"description": "제공된 CSS Selector와 일치하는 단일 객체 포지션 찾기",
|
||||
"tags": ["웹 브라우저 제어", "웹 브라우저 제어 (크로미움 계열)"]
|
||||
"description": "finding single element position that matches with provided CSS Selector",
|
||||
"tags": [
|
||||
"control web browser",
|
||||
"control web browser (Chromium-based)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "chromium_get_mapreduced_element_position",
|
||||
"description": "CSS Selector와 일치하는 다중 객체 중 조건에 맞는 객체의 포지션 찾기",
|
||||
"tags": ["웹 브라우저 제어", "웹 브라우저 제어 (크로미움 계열)"]
|
||||
"description": "finding position of the element that meets requirement among multiple elements that match with CSS selector",
|
||||
"tags": [
|
||||
"control web browser",
|
||||
"control web browser (Chromium-based)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "chromium_set_value_to_textbox",
|
||||
"description": "대상 객체가 사용자 입력형(TextArea 또는 TextInput인 경우) 값 설정하기",
|
||||
"tags": ["웹 브라우저 제어", "웹 브라우저 제어 (크로미움 계열)"]
|
||||
"description": "setting the value in case the object of the action is input by users(TextArea or TextInput)",
|
||||
"tags": [
|
||||
"control web browser",
|
||||
"control web browser (Chromium-based)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "chromium_send_click",
|
||||
"description": "가상 클릭(Click) 보내기",
|
||||
"tags": ["웹 브라우저 제어", "웹 브라우저 제어 (크로미움 계열)"]
|
||||
"description": "send virtual click",
|
||||
"tags": [
|
||||
"control web browser",
|
||||
"control web browser (Chromium-based)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "chromium_send_keys",
|
||||
"description": "가상 키(Key) 보내기",
|
||||
"tags": ["웹 브라우저 제어", "웹 브라우저 제어 (크로미움 계열)"]
|
||||
"description": "send virtual key",
|
||||
"tags": [
|
||||
"control web browser",
|
||||
"control web browser (Chromium-based browser)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "chromium_auto_scroll_until_end",
|
||||
"description": "수직 스크롤이 있을 시 스크롤이 끝날 때까지 자동으로 화면 탐색하기",
|
||||
"tags": ["웹 브라우저 제어", "웹 브라우저 제어 (크로미움 계열)"]
|
||||
"description": "exploring the screen automatically until the scrolling finishes, in case of vertical scrolling",
|
||||
"tags": [
|
||||
"control web browser",
|
||||
"control web browser (Chromium-based browser)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "grpc_run_server",
|
||||
"description": "gRPC 서버 실행",
|
||||
"tags": ["gRPC"]
|
||||
"description": "run gRPC server",
|
||||
"tags": [
|
||||
"gRPC"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "grpc_receive_command",
|
||||
"description": "gRPC로 들어온 명령을 스크립트로 받음",
|
||||
"tags": ["gRPC"]
|
||||
"description": "receive command that is sent to grpc in script",
|
||||
"tags": [
|
||||
"gRPC"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "gui_check",
|
||||
"description": "WebView (GUI) 환경에서도 (1)Windows 시스템/Windows 쉘(Shell), (2)Windows 시스템/WMI 제어 기능이 동작 가능.",
|
||||
"tags": ["WebView"]
|
||||
"description": "Even in WebView (GUI) environment, (1)Windows Systems/Windows Shell, (2)(Windows Systems/WMI control functions work.",
|
||||
"tags": [
|
||||
"WebView"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@ function main(args) {
|
|||
}
|
||||
|
||||
var data = FILE.readFile(filename, FILE.CdoCharset.CdoUTF_8);
|
||||
var encryptedData = Toolkit.encryptStringHIGHT(userKey, data);
|
||||
var encryptedData = Toolkit.encryptString(userKey, data);
|
||||
|
||||
var dstfile = filename + ".enc";
|
||||
FILE.writeFile(dstfile, encryptedData, FILE.CdoCharset.CdoUTF_8);
|
||||
|
|
3
examples/hanoi.ai.js
Normal file
3
examples/hanoi.ai.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
// hanoi.ai.js
|
||||
var hanoi = require("ai://hanoi tower example");
|
||||
hanoi.test();
|
|
@ -24,10 +24,10 @@ function main(args) {
|
|||
var lines = [];
|
||||
var wbInstance = Chrome.startWithDebugging("https://virustotal.com", null, "virustotal", 9222);
|
||||
|
||||
// 대기
|
||||
// Wait
|
||||
sleep(5000);
|
||||
|
||||
// 브라우저 탭 찾기
|
||||
// finding browser tap
|
||||
pages = wbInstance.getPagesByTitle("VirusTotal");
|
||||
if (pages.length > 0) {
|
||||
page = pages[0];
|
||||
|
@ -38,12 +38,12 @@ function main(args) {
|
|||
var callback1 = function(row) {
|
||||
var hash = row[1];
|
||||
|
||||
console.log("탐색을 시도합니다:", hash);
|
||||
console.log("Attempt exploring:", hash);
|
||||
|
||||
wbInstance.navigate("https://www.virustotal.com/gui/file/" + hash);
|
||||
sleep(RAND.getInt(4000, 5000));
|
||||
|
||||
// 자료를 찾았는지 여부
|
||||
// Indicates whether data was found
|
||||
var msgNotFound = wbInstance.getEvaluatedValue(
|
||||
"__getDocument().querySelector('vt-ui-shell').shadowRoot.querySelector('#mainContent').querySelector('slot').assignedNodes()[2]" +
|
||||
wbInstance.getShadowRootSelector([
|
||||
|
@ -53,12 +53,12 @@ function main(args) {
|
|||
".shadowRoot.querySelector('.title slot').assignedNodes()[0].innerText"
|
||||
);
|
||||
if (msgNotFound == "No matches found") {
|
||||
console.log("찾을 수 없음 (No matches found): " + hash);
|
||||
console.log("No matches found"): " + hash);
|
||||
lines.push([hash, '', '0', '0', '0', ''].join(','));
|
||||
return;
|
||||
}
|
||||
|
||||
// 전체 진단 수 확인
|
||||
// Check how many times it was examined to detect and diagnose viruses
|
||||
var positives = wbInstance.getEvaluatedValue(
|
||||
"__getDocument().querySelector('vt-ui-shell').shadowRoot.querySelector('#mainContent').querySelector('slot').assignedNodes()[2]" +
|
||||
wbInstance.getShadowRootSelector([
|
||||
|
@ -69,7 +69,7 @@ function main(args) {
|
|||
".shadowRoot.querySelector('div > div > div.positives').innerText"
|
||||
);
|
||||
|
||||
// 알려진 파일 명
|
||||
// known filename
|
||||
var filename = wbInstance.getEvaluatedValue(
|
||||
"__getDocument().querySelector('vt-ui-shell').shadowRoot.querySelector('#mainContent').querySelector('slot').assignedNodes()[2]" +
|
||||
wbInstance.getShadowRootSelector([
|
||||
|
@ -79,7 +79,7 @@ function main(args) {
|
|||
".shadowRoot.querySelector('div > div.card-body > div > div.hstack.gap-4 > div.vstack.gap-2.align-self-center.text-truncate > div.file-name.text-truncate > a').innerText"
|
||||
);
|
||||
|
||||
// 최근 진단 날짜 확인
|
||||
// Check the latest date of the examination to detect and diagnose a virus
|
||||
var last = wbInstance.getEvaluatedValue(
|
||||
"__getDocument().querySelector('vt-ui-shell').shadowRoot.querySelector('#mainContent').querySelector('slot').assignedNodes()[2]" +
|
||||
wbInstance.getShadowRootSelector([
|
||||
|
@ -89,7 +89,7 @@ function main(args) {
|
|||
".shadowRoot.querySelector('div > div.card-body > div > div.hstack.gap-4 > div:nth-child(5) > vt-ui-time-ago').getAttribute('data-tooltip-text')"
|
||||
);
|
||||
|
||||
// 국내 백신 진단 여부 확인
|
||||
// Check whether a Korean vaccine programme has examined to detect and diagnose virus
|
||||
var score_undetected = wbInstance.getEvaluatedValue(
|
||||
'Object.values(' +
|
||||
"__getDocument().querySelector('vt-ui-shell').shadowRoot.querySelector('#mainContent').querySelector('slot').assignedNodes()[2].querySelector('file-view').shadowRoot.querySelector('vt-ui-main-generic-report').querySelector('.tab-slot')" +
|
||||
|
@ -100,13 +100,13 @@ function main(args) {
|
|||
".querySelectorAll('.detection')).reduce(function(a, x) { if(/AhnLab|ALYac|ViRobot/.test(x.innerText) && x.innerText.indexOf('Undetected') > -1) a = a + 1; return a; }, 0)"
|
||||
);
|
||||
|
||||
console.log("해시:", hash);
|
||||
console.log("알려진 파일 이름:", filename);
|
||||
console.log("전체 진단:", positives);
|
||||
console.log("최근 날짜:", last);
|
||||
console.log("국내 백신 미진단:", score_undetected + "건");
|
||||
console.log("hash:", hash);
|
||||
console.log("known filename:", filename);
|
||||
console.log("examined the whole to detect and diagnose viruses :", positives);
|
||||
console.log("date of the latest activity:", last);
|
||||
console.log("Hasn ' t examined with a Korean vaccine programme to detect and diagnose viruses:", score_undetected + "건");
|
||||
|
||||
// 쓰기 줄 생성
|
||||
// create lines for writing
|
||||
lines.push([hash, filename, '1', positives, score_undetected, last].join(','));
|
||||
};
|
||||
|
||||
|
|
|
@ -26,10 +26,11 @@ REM sc config "%SERVICE_NAME%" start= auto
|
|||
REM sc description "%SERVICE_NAME%" "Service installed via InstallUtil.exe"
|
||||
|
||||
REM Add parameters to the ImagePath registry key
|
||||
REG ADD "HKLM\SYSTEM\CurrentControlSet\Services\%SERVICE_NAME%" /v ImagePath /t REG_EXPAND_SZ /d "\"%EXE_PATH%\" --working-directory=%CURRENT_DIR% --script-name=defaultService" /f
|
||||
REG ADD "HKLM\SYSTEM\CurrentControlSet\Services\%SERVICE_NAME%" /v ImagePath /t REG_EXPAND_SZ /d "\"%EXE_PATH%\" --working-directory=\"%CURRENT_DIR%\" --script-name=defaultService" /f
|
||||
|
||||
echo Service "%SERVICE_NAME%" installed and configured successfully.
|
||||
|
||||
sc start "%SERVICE_NAME%"
|
||||
echo Service "%SERVICE_NAME%" started.
|
||||
pause
|
||||
|
||||
pause
|
||||
|
|
60
lib/anthropic.js
Normal file
60
lib/anthropic.js
Normal file
|
@ -0,0 +1,60 @@
|
|||
// anthropic.js
|
||||
// Namhyeon Go <abuse@catswords.net>
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
// ***SECURITY NOTICE***
|
||||
// Anthropic/Claude requires an internet connection, and data may be transmitted externally. Users must adhere to the terms of use and privacy policy.
|
||||
// - Privacy Policy: https://www.anthropic.com/legal/privacy
|
||||
//
|
||||
var FILE = require("lib/file");
|
||||
var HTTP = require("lib/http");
|
||||
var CRED = require("lib/credentials");
|
||||
|
||||
function chat(content) {
|
||||
var answers = [];
|
||||
|
||||
var apikey = CRED.get("apikey", "anthropic");
|
||||
console.log("Anthropic (Claude) API KEY:", apikey);
|
||||
|
||||
var response = HTTP.create("MSXML")
|
||||
.setVariables({
|
||||
"ANTHROPIC_API_KEY": apikey
|
||||
})
|
||||
.setContentType("application/json")
|
||||
.setHeaders({
|
||||
"x-api-key": "{ANTHROPIC_API_KEY}",
|
||||
"anthropic-version": "2023-06-01"
|
||||
})
|
||||
.setRequestBody({
|
||||
"model": "claude-3-5-sonnet-20241022",
|
||||
"max_tokens": 1024,
|
||||
"messages": [{
|
||||
"role": "user",
|
||||
"content": content
|
||||
}]
|
||||
})
|
||||
.open("post", "https://api.anthropic.com/v1/messages")
|
||||
.send()
|
||||
.responseBody;
|
||||
|
||||
if ("error" in response) {
|
||||
answers.push("Error: " + response.error.message);
|
||||
} else if ("content" in response && response.content.length > 0) {
|
||||
response.content.forEach(function(x) {
|
||||
if (x.type == "text") {
|
||||
answers.push(x.text);
|
||||
} else {
|
||||
answers.push("Not supported type: " + x.type);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return answers.join(' ');
|
||||
}
|
||||
|
||||
exports.chat = chat;
|
||||
|
||||
exports.VERSIONINFO = "Anthropic (Claude) interface (anthropic.js) version 0.1.4";
|
||||
exports.AUTHOR = "abuse@catswords.net";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
124
lib/archive.js
Normal file
124
lib/archive.js
Normal file
|
@ -0,0 +1,124 @@
|
|||
// archive.js
|
||||
// File archiver library for WelsonJS framework
|
||||
// Namhyeon Go (Catswords Research) <abuse@catswords.net>
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
var SHELL = require("lib/shell");
|
||||
var FILE = require("lib/file");
|
||||
|
||||
function ArchiveObject(engine) {
|
||||
this.workingDirectory = "";
|
||||
this.patterns = [];
|
||||
this.readFormat = "";
|
||||
this.writeFormat = "";
|
||||
this.engine = null;
|
||||
|
||||
this.setReadFormat = function(readFormat) {
|
||||
this.readFormat = readFormat;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
this.setWriteFormat = function(writeFormat) {
|
||||
this.writeFormat = writeFormat;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
this.setEngine = function(engine) {
|
||||
this.engine = engine;
|
||||
|
||||
if (this.engine == "cabinet") {
|
||||
this.setReadFormat("cab");
|
||||
this.setWriteFormat("cab");
|
||||
}
|
||||
|
||||
// TODO: zip, 7z, rar
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
this.extractTo = function(filename, targetDirectory) {
|
||||
var result;
|
||||
|
||||
if (this.engine == "cabinet") {
|
||||
// compress cab to target directory
|
||||
result = SHELL.exec([
|
||||
"expand",
|
||||
filename,
|
||||
targetDirectory
|
||||
]);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
this.compressTo = function(filename) {
|
||||
var result;
|
||||
|
||||
// https://superuser.com/questions/658021/whats-the-best-way-to-create-a-cab-file-of-multiple-files-quickly
|
||||
if (this.engine == "cabinet") {
|
||||
var directives = this.buildDirectives();
|
||||
|
||||
// create the directives file (temporary file)
|
||||
var tmp = PipeIPC.connect("volatile");
|
||||
tmp.write(directives);
|
||||
var tmp_path = out.path;
|
||||
tmp.close();
|
||||
|
||||
// compress to cab
|
||||
SHELL.exec([
|
||||
"makecab",
|
||||
"/d",
|
||||
"CabinetName1=" + filename,
|
||||
"/d",
|
||||
"DiskDirectoryTemplate=" + this.workingDirectory,
|
||||
"/f",
|
||||
tmp_path
|
||||
]);
|
||||
|
||||
// destroy the temporary file
|
||||
tmp.destroy();
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
this.buildDirectives = function() {
|
||||
var directives = [];
|
||||
|
||||
if (this.engine == "cabinet") {
|
||||
this.patterns.forEach(function(x) {
|
||||
if (FILE.fileExists(x)) directives.push(x);
|
||||
});
|
||||
}
|
||||
|
||||
return directives.join("\r\n");
|
||||
};
|
||||
|
||||
this.addFile = function(file) {
|
||||
this.patterns.push(file);
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
// set default engines
|
||||
this.create = function() {
|
||||
if (typeof engine === "undefined") {
|
||||
this.setEngine("cabinet");
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
this.create();
|
||||
}
|
||||
|
||||
exports.create = function(engine) {
|
||||
return new ArchiveObject(engine);
|
||||
};
|
||||
|
||||
exports.VERSIONINFO = "File archiver library (archive.js) version 0.1-dev";
|
||||
exports.AUTHOR = "abuse@catswords.net";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
119
lib/aviation.js
Normal file
119
lib/aviation.js
Normal file
|
@ -0,0 +1,119 @@
|
|||
// aviation.js
|
||||
// Namhyeon Go <abuse@catswords.net>
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
// ***SECURITY NOTICE***
|
||||
// Aviation Data Integration requires an internet connection, and data may be transmitted externally. Users must adhere to the terms of use and privacy policy.
|
||||
// - AviationStack website: https://aviationstack.com/?utm_source=FirstPromoter&utm_medium=Affiliate&fpr=namhyeon71
|
||||
// - SearchApi website: https://www.searchapi.io/?via=namhyeon
|
||||
//
|
||||
var HTTP = require("lib/http");
|
||||
var CRED = require("lib/credentials");
|
||||
|
||||
function getData(type, params, limit, offset) {
|
||||
var params = params || {};
|
||||
var limit = (function(n) {
|
||||
return n > 0 ? n : 100;
|
||||
}(parseInt(limit));
|
||||
var offset = (function(n) {
|
||||
return n > -1 ? n : 0;
|
||||
}(parseInt(limit));
|
||||
|
||||
params["limit"] = limit;
|
||||
params["offset"] = offset;
|
||||
params["access_key"] = CRED.get("apikey", "aviationstack");
|
||||
|
||||
var response = HTTP.create()
|
||||
.setParameters(params)
|
||||
.open("GET", "https://api.aviationstack.com/v1/" + type)
|
||||
.send();
|
||||
|
||||
return response.responseBody;
|
||||
}
|
||||
|
||||
function getFlights(params, limit, offset) {
|
||||
return getData("flights", params, limit, offset);
|
||||
}
|
||||
|
||||
function getRoutes(params, limit, offset) {
|
||||
return getData("routes", params, limit, offset);
|
||||
}
|
||||
|
||||
function getAirports(params, limit, offset) {
|
||||
return getData("airports", params, limit, offset);
|
||||
}
|
||||
|
||||
function getAirlines(params, limit, offset) {
|
||||
return getData("airlines", params, limit, offset);
|
||||
}
|
||||
|
||||
function getAircraftTypes(params, limit, offset) {
|
||||
return getData("aircraft_types", params, limit, offset);
|
||||
}
|
||||
|
||||
function getCities(params, limit, offset) {
|
||||
return getData("cities", params, limit, offset);
|
||||
}
|
||||
|
||||
function getCountries(params, limit, offset) {
|
||||
return getData("countries", params, limit, offset);
|
||||
}
|
||||
|
||||
function getFlightSchedules(params, limit, offset) {
|
||||
return getData("timetable", params, limit, offset);
|
||||
}
|
||||
|
||||
function getFlightsFuture(params, limit, offset) {
|
||||
return getData("flightsFuture", params, limit, offset);
|
||||
}
|
||||
|
||||
function getRoundTrip(arrival_id, departure_id, outbound_date, return_date) {
|
||||
var response = HTTP.create()
|
||||
.setParameters({
|
||||
"api_key": CRED.get("apikey", "searchapi"),
|
||||
"arrival_id": arrival_id,
|
||||
"departure_id": departure_id,
|
||||
"engine": "google_flights",
|
||||
"flight_type": "round_trip",
|
||||
"outbound_date": outbound_date,
|
||||
"return_date": return_date
|
||||
})
|
||||
.open("GET", "https://www.searchapi.io/api/v1/search")
|
||||
.send();
|
||||
|
||||
return response.responseBody;
|
||||
}
|
||||
|
||||
function getOneWay(arrival_id, departure_id, outbound_date) {
|
||||
var response = HTTP.create()
|
||||
.setParameters({
|
||||
"api_key": CRED.get("apikey", "searchapi"),
|
||||
"arrival_id": arrival_id,
|
||||
"departure_id": departure_id,
|
||||
"engine": "google_flights",
|
||||
"flight_type": "one_way",
|
||||
"outbound_date": outbound_date
|
||||
})
|
||||
.open("GET", "https://www.searchapi.io/api/v1/search")
|
||||
.send();
|
||||
|
||||
return response.responseBody;
|
||||
}
|
||||
|
||||
exports.getData = getData;
|
||||
exports.getFlights = getFlights;
|
||||
exports.getRoutes = getRoutes;
|
||||
exports.getAirports = getAirports;
|
||||
exports.getAirlines = getAirlines;
|
||||
exports.getAircraftTypes = getAircraftTypes;
|
||||
exports.getCities = getCities;
|
||||
exports.getCountries = getCountries;
|
||||
exports.getFlightSchedules = getFlightSchedules;
|
||||
exports.getFlightsFuture = getFlightsFuture;
|
||||
exports.getRoundTrip = getRoundTrip;
|
||||
exports.getOneWay = getOneWay;
|
||||
|
||||
exports.VERSIONINFO = "Aviation Data Integration (aviation.js) version 0.1.3";
|
||||
exports.AUTHOR = "abuse@catswords.net";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
|
@ -108,6 +108,36 @@ if (!window.addEventListener) {
|
|||
})(window, document, global.Element.prototype, []);
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/45552695/why-element-matches-polyfill-doesnt-work
|
||||
// https://github.com/zloirock/core-js/issues/780
|
||||
// https://github.com/joncasey/modern-hta/blob/master/src/element-closest.js
|
||||
if (Element && Element.prototype) {
|
||||
if (!Element.prototype.matches) {
|
||||
Element.prototype.matches = Element.prototype.msMatchesSelector;
|
||||
}
|
||||
|
||||
if (!Element.prototype.closest) {
|
||||
Element.prototype.closest = function(selector) {
|
||||
for (var p = this; p != null; p = p.parentElement) {
|
||||
if (p.matches(selector)) return p;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/summernote/summernote/pull/4625
|
||||
if (CanvasPixelArray && CanvasPixelArray.prototype) {
|
||||
if (!CanvasPixelArray.prototype.join) {
|
||||
CanvasPixelArray.prototype.join = function() {
|
||||
var pxInfo = this, s = '';
|
||||
for (var i = 0; i < pxInfo.length; i++) {
|
||||
s += pxInfo[i].toString();
|
||||
}
|
||||
return s;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// getIEVersion()
|
||||
function getIEVersion() {
|
||||
var undef,
|
||||
|
@ -205,8 +235,8 @@ function start(callback) {
|
|||
}
|
||||
addScript("app/assets/js/html5shiv-printshiv-3.7.3.min.js");
|
||||
if (msie < 9) {
|
||||
addScript("app/assets/js/respond-1.4.2.edited.js");
|
||||
addScript("app/assets/js/selectivizr-1.0.2.edited.js");
|
||||
addScript("app/assets/js/respond-1.4.2.wsh.js");
|
||||
addScript("app/assets/js/selectivizr-1.0.2.wsh.js");
|
||||
addScript("app/assets/js/excanvas.arv-565afad.js");
|
||||
|
||||
waitUntil(function(test, ttl) {
|
||||
|
@ -221,7 +251,7 @@ function start(callback) {
|
|||
return window.jQuery;
|
||||
});
|
||||
}
|
||||
addScript("app/assets/js/jquery.html5-placeholder-shim.jcampbell1-5a87f05.js");
|
||||
addScript("app/assets/js/jquery.html5-placeholder-shim-5a87f05.js");
|
||||
|
||||
// load Modernizr (2.8.3)
|
||||
addScript("app/assets/js/modernizr-2.8.3.min.js");
|
||||
|
@ -254,7 +284,7 @@ exports.start = start;
|
|||
exports.reload = reload;
|
||||
exports.close = close;
|
||||
|
||||
exports.VERSIONINFO = "Browser Compatibility Library (browser.js) version 0.1.5";
|
||||
exports.VERSIONINFO = "Browser Compatibility Layer (browser.js) version 0.1.7";
|
||||
exports.AUTHOR = "abuse@catswords.net";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
// chatgpt.js
|
||||
// Namhyeon Go <abuse@catswords.net>
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
// ***SECURITY NOTICE***
|
||||
// ChatGPT requires an internet connection, and data may be transmitted externally. Users must adhere to the terms of use and privacy policy.
|
||||
// - Privacy Policy: https://openai.com/policies/row-privacy-policy/
|
||||
//
|
||||
var FILE = require("lib/file");
|
||||
var HTTP = require("lib/http");
|
||||
|
||||
function loadApiKey() {
|
||||
var s = FILE.readFile("data/chatgpt-apikey.txt", FILE.CdoCharset.CdoUTF_8);
|
||||
return s.trim();
|
||||
}
|
||||
var CRED = require("lib/credentials");
|
||||
|
||||
function chat(content) {
|
||||
var s = '';
|
||||
|
||||
var apikey = loadApiKey();
|
||||
console.log("ChatGPT API KEY:", apikey);
|
||||
var answers = [];
|
||||
|
||||
var apikey = CRED.get("apikey", "chatgpt");
|
||||
console.log("OpenAI (ChatGPT) API KEY:", apikey);
|
||||
|
||||
var response = HTTP.create("MSXML")
|
||||
.setVariables({
|
||||
|
@ -21,12 +25,15 @@ function chat(content) {
|
|||
"Authorization": "Bearer {OPENAI_API_KEY}"
|
||||
})
|
||||
.setRequestBody({
|
||||
"model": "gpt-3.5-turbo",
|
||||
"model": "gpt-4o",
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": content
|
||||
}
|
||||
{
|
||||
"role": "developer",
|
||||
"content": "Write all future code examples in JavaScript ES3 using the exports variable. Include a test method with the fixed name test. Respond exclusively in code without blocks."
|
||||
}, {
|
||||
"role": "user",
|
||||
"content": content
|
||||
}
|
||||
]
|
||||
})
|
||||
.open("post", "https://api.openai.com/v1/chat/completions")
|
||||
|
@ -34,8 +41,10 @@ function chat(content) {
|
|||
.responseBody
|
||||
;
|
||||
|
||||
if (response.choices.length > 0) {
|
||||
s += response.choices[0].message.content;
|
||||
if ("choices" in response && response.choices.length > 0) {
|
||||
response.choices.forEach(function(x) {
|
||||
answers.push(x.message.content);
|
||||
});
|
||||
}
|
||||
|
||||
return s;
|
||||
|
@ -43,7 +52,7 @@ function chat(content) {
|
|||
|
||||
exports.chat = chat;
|
||||
|
||||
exports.VERSIONINFO = "ChatGPT interface (chatgpt.js) version 0.1";
|
||||
exports.VERSIONINFO = "OpenAI (ChatGPT) interface version 0.1.2";
|
||||
exports.AUTHOR = "abuse@catswords.net";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
||||
|
|
32
lib/coupang.js
Normal file
32
lib/coupang.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
// coupang.js
|
||||
// Namhyeon Go <abuse@catswords.net>
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
// ***SECURITY NOTICE***
|
||||
// Due to potential security issues, the Public API URL is not provided. If you need to request access, please refer to the project's contact information.
|
||||
// You can download the server-side script that implements this functionality from the link below:
|
||||
// https://github.com/gnh1201/caterpillar
|
||||
//
|
||||
var JsonRpc2 = require("lib/jsonrpc2");
|
||||
|
||||
function search(s) {
|
||||
var rpc = JsonRpc2.create(JsonRpc2.DEFAULT_JSONRPC2_URL);
|
||||
var result = rpc.invoke("relay_invoke_method", {
|
||||
"callback": "load_script",
|
||||
"requires": [
|
||||
"https://scriptas.catswords.net/coupang.class.php"
|
||||
],
|
||||
"args": [
|
||||
"$search = new CoupangProductSearch(); return $search->searchProducts('" + s + "')"
|
||||
]
|
||||
}, "");
|
||||
|
||||
return result.data;
|
||||
}
|
||||
|
||||
exports.search = search;
|
||||
|
||||
exports.VERSIONINFO = "Coupang Product Search Client (coupang.js) version 0.1.1";
|
||||
exports.AUTHOR = "abuse@catswords.net";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
69
lib/credentials.js
Normal file
69
lib/credentials.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
// credentials.js
|
||||
// Namhyeon Go <abuse@catswords.net>
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
var FILE = require("lib/file");
|
||||
|
||||
var CREDENTIALS_DATA = [];
|
||||
|
||||
function getTextFromFile(filename) {
|
||||
if (FILE.fileExists(filename)) {
|
||||
return FILE.readFile(filename, FILE.CdoCharset.CdoUTF_8);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
function readFromFile(type, filename) {
|
||||
var data = JSON.parse(getTextFromFile(filename));
|
||||
|
||||
for (var provider in data) {
|
||||
var prelude = "file:";
|
||||
var value = (function(s) {
|
||||
if (s.indexOf(prelude) == 0) {
|
||||
var filename = s.substring(prelude.length);
|
||||
return getTextFromFile(filename);
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
})(data[provider]);
|
||||
|
||||
push(type, provider, value);
|
||||
}
|
||||
}
|
||||
|
||||
function push(type, provider, value) {
|
||||
CREDENTIALS_DATA.push({
|
||||
"type": type,
|
||||
"provider": provider,
|
||||
"value": value
|
||||
});
|
||||
}
|
||||
|
||||
function get(type, provider, index) {
|
||||
var index = index || 0;
|
||||
var matches = CREDENTIALS_DATA.reduce(function(a, x) {
|
||||
if (x.type == type && x.provider == provider) {
|
||||
a.push(x.value);
|
||||
}
|
||||
|
||||
return a;
|
||||
}, []);
|
||||
|
||||
if (matches.length - 1 < index) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return matches[index];
|
||||
}
|
||||
|
||||
readFromFile("apikey", "data/apikey.json");
|
||||
|
||||
exports.readFromFile = readFromFile;
|
||||
exports.push = push;
|
||||
exports.get = get;
|
||||
|
||||
exports.VERSIONINFO = "Credential store (credentials.js) version 0.1";
|
||||
exports.AUTHOR = "abuse@catswords.net";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
53
lib/grok.js
Normal file
53
lib/grok.js
Normal file
|
@ -0,0 +1,53 @@
|
|||
// grok.js
|
||||
// Namhyeon Go <abuse@catswords.net>
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
// ***SECURITY NOTICE***
|
||||
// Grok (x.ai) requires an internet connection, and data may be transmitted externally. Users must adhere to the terms of use and privacy policy.
|
||||
// - Privacy Policy: https://x.ai/legal/privacy-policy
|
||||
//
|
||||
var FILE = require("lib/file");
|
||||
var HTTP = require("lib/http");
|
||||
var CRED = require("lib/credentials");
|
||||
|
||||
function chat(content) {
|
||||
var answers = [];
|
||||
|
||||
var apikey = CRED.get("apikey", "grok");
|
||||
console.log("Grok (x.ai) API KEY:", apikey);
|
||||
|
||||
var response = HTTP.create("MSXML")
|
||||
.setVariables({
|
||||
"GROK_API_KEY": apikey
|
||||
})
|
||||
.setHeaders({
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer {GROK_API_KEY}"
|
||||
})
|
||||
.setRequestBody({
|
||||
"messages": [{
|
||||
"role": "user",
|
||||
"content": content
|
||||
}],
|
||||
"model": "grok-2-latest"
|
||||
})
|
||||
.open("post", "https://api.x.ai/v1/chat/completions")
|
||||
.send()
|
||||
.responseBody
|
||||
;
|
||||
|
||||
if ("choices" in response && response.choices.length > 0) {
|
||||
response.choices.forEach(function(x) {
|
||||
answers.push(x.message.content);
|
||||
});
|
||||
}
|
||||
|
||||
return answers.join(' ');
|
||||
}
|
||||
|
||||
exports.chat = chat;
|
||||
|
||||
exports.VERSIONINFO = "Grok (x.ai) interface version 0.1";
|
||||
exports.AUTHOR = "abuse@catswords.net";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
47
lib/groq.js
Normal file
47
lib/groq.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
// groq.js
|
||||
// Namhyeon Go <abuse@catswords.net>
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
// ***SECURITY NOTICE***
|
||||
// Groq requires an internet connection, and data may be transmitted externally. Users must adhere to the terms of use and privacy policy.
|
||||
// - Privacy Policy: https://groq.com/privacy-policy/
|
||||
//
|
||||
var FILE = require("lib/file");
|
||||
var HTTP = require("lib/http");
|
||||
var CRED = require("lib/credentials");
|
||||
|
||||
function chat(content) {
|
||||
var answers = [];
|
||||
|
||||
var apikey = CRED.get("apikey", "groq");
|
||||
console.log("Groq (GroqCloud) API KEY:", apikey);
|
||||
|
||||
var response = HTTP.create("MSXML")
|
||||
.setContentType("application/json")
|
||||
.setBearerAuth(apikey)
|
||||
.setRequestBody({
|
||||
"model": "llama3-8b-8192",
|
||||
"messages": [{
|
||||
"role": "user",
|
||||
"content": content
|
||||
}]
|
||||
})
|
||||
.open("post", "https://api.groq.com/openai/v1/chat/completions")
|
||||
.send()
|
||||
.responseBody;
|
||||
|
||||
if ("error" in response) {
|
||||
answers.push("Error: " + response.error.message);
|
||||
} else if (response.choices.length > 0) {
|
||||
answers.push(response.choices[0].message.content);
|
||||
}
|
||||
|
||||
return answers.join(' ');
|
||||
}
|
||||
|
||||
exports.chat = chat;
|
||||
|
||||
exports.VERSIONINFO = "Groq (GroqCloud) interface (groq.js) version 0.1.1";
|
||||
exports.AUTHOR = "abuse@catswords.net";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
619
lib/http.js
619
lib/http.js
|
@ -1,6 +1,6 @@
|
|||
// http.js
|
||||
// HTTP REST Client for WelsonJS framework
|
||||
// Namhyeon Go (Catswords Research) <abuse@catswords.net>
|
||||
// HTTP REST API client for WelsonJS framework
|
||||
// Namhyeon Go (Catswords Research) <abuse@catswords.net>
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
var SYS = require("lib/system");
|
||||
var FILE = require("lib/file");
|
||||
|
@ -8,92 +8,20 @@ var SHELL = require("lib/shell");
|
|||
var RAND = require("lib/rand");
|
||||
var BASE64 = require("lib/base64");
|
||||
var PipeIPC = require("lib/pipe-ipc");
|
||||
var JsonRpc2 = require("lib/jsonrpc2");
|
||||
var SERP = require("lib/serp");
|
||||
|
||||
var OS_NAME = SYS.getOS();
|
||||
var OS_ARCH = SYS.getArch();
|
||||
var DEVICE_UUID = SYS.getUUID();
|
||||
var PROCESS_VERSION = SYS.getProcessVersion();
|
||||
var DEFAULT_USER_AGENT = "WelsonJS/0.2.7 (" + OS_NAME + "; " + OS_ARCH + "; " + PROCESS_VERSION + "; " + DEVICE_UUID + "; abuse@catswords.net)";
|
||||
var DEFAULT_USER_AGENT = "WelsonJS/0.2.7 (" + OS_NAME + "; " + PROCESS_VERSION + "; " + DEVICE_UUID + ")";
|
||||
|
||||
// If you have any suggestions for partnerships, please contact us at: abuse@catswords.net
|
||||
var AVAILABLE_PROXIES = [
|
||||
{
|
||||
"type": "stateless",
|
||||
"provider": "scrapeops",
|
||||
"url": "https://proxy.scrapeops.io/v1/?api_key={api_key}&url={url}&render_js={render_js}&residential={residential}&country={country}&keep_headers={keep_headers}",
|
||||
"documentation": "https://scrapeops.io?fpr=namhyeon75"
|
||||
},
|
||||
{
|
||||
"type": "stateful",
|
||||
"provider": "scrapeops",
|
||||
"url": "http://scrapeops:{api_key}@residential-proxy.scrapeops.io:8181",
|
||||
"documentation": "https://scrapeops.io?fpr=namhyeon75"
|
||||
},
|
||||
{
|
||||
"type": "serp",
|
||||
"provider": "searchapi",
|
||||
"url": "https://www.searchapi.io/api/v1/search?api_key={api_key}&engine={engine}&q={q}",
|
||||
"documentation": "https://www.searchapi.io/?via=namhyeon"
|
||||
},
|
||||
{
|
||||
"type": "serp",
|
||||
"provider": "librey",
|
||||
"url": "https://serp.catswords.net/api.php?q={q}&p=1&t=0",
|
||||
"documentation": "https://github.com/Ahwxorg/LibreY"
|
||||
},
|
||||
{
|
||||
"type": "serp",
|
||||
"provider": "invidious",
|
||||
"url": "https://invidious.example.org/api/v1/search?q={q}",
|
||||
"documentation": "https://docs.invidious.io/"
|
||||
},
|
||||
{
|
||||
"type": "stateless-jsonrpc2",
|
||||
"provider": "gnh1201/caterpillar",
|
||||
"url": "http://localhost:5555",
|
||||
"documentation": "https://github.com/gnh1201/caterpillar"
|
||||
},
|
||||
{
|
||||
"type": "stateful",
|
||||
"provider": "gnh1201/caterpillar",
|
||||
"url": "http://localhost:5555",
|
||||
"documentation": "https://github.com/gnh1201/caterpillar"
|
||||
},
|
||||
{
|
||||
"type": "stateful",
|
||||
"provider": "cloudflare",
|
||||
"url": "http://localhost:40000",
|
||||
"documentation": "https://developers.cloudflare.com/warp-client/warp-modes/"
|
||||
},
|
||||
{
|
||||
"type": "stateful",
|
||||
"provider": "fiddler",
|
||||
"url": "http://localhost:8888",
|
||||
"documentation": "https://www.telerik.com/fiddler/fiddler-classic"
|
||||
},
|
||||
{
|
||||
"type": "stateful",
|
||||
"provider": "fiddler2",
|
||||
"url": "http://localhost:8866",
|
||||
"documentation": "https://www.telerik.com/fiddler/fiddler-everywhere"
|
||||
},
|
||||
{
|
||||
"type": "stateful",
|
||||
"provider": "mitmproxy",
|
||||
"url": "http://localhost:8080",
|
||||
"documetation": "https://mitmproxy.org/"
|
||||
},
|
||||
{
|
||||
"type": "stateful",
|
||||
"provider": "burpsuite",
|
||||
"url": "http://localhost:8080",
|
||||
"documetation": "https://portswigger.net/burp"
|
||||
},
|
||||
{
|
||||
"type": "stateful",
|
||||
"provider": "zaproxy",
|
||||
"url": "http://localhost:8080",
|
||||
"documetation": "https://www.zaproxy.org/"
|
||||
"type": "file",
|
||||
"provider": "",
|
||||
"url": "data/available_proxies.json",
|
||||
"documentation": ""
|
||||
}
|
||||
];
|
||||
|
||||
|
@ -101,14 +29,14 @@ var HTTPObject = function(engine) {
|
|||
this._interface = null;
|
||||
|
||||
this.contentType = "application/x-www-form-urlencoded";
|
||||
this.requestBody = "";
|
||||
this.requestBody = null;
|
||||
this.responseBody = null;
|
||||
this.method = "GET";
|
||||
this.headers = {};
|
||||
this.parameters = {};
|
||||
this.dataType = null;
|
||||
this.userAgent = DEFAULT_USER_AGENT;
|
||||
this.isAsynchronous = false;
|
||||
this.isAsync = false;
|
||||
this.proxy = {
|
||||
"enabled": false,
|
||||
"type": "stateful",
|
||||
|
@ -116,8 +44,11 @@ var HTTPObject = function(engine) {
|
|||
"protocol": "http",
|
||||
"host": "127.0.0.1",
|
||||
"port": 80,
|
||||
"credential": null, // { username: "user", password: "pass" }
|
||||
"url": null // stateless only
|
||||
"credential": null, // e.g. { username: "user", password: "pass" }
|
||||
"method": null, // for stateless only. e.g. GET, POST
|
||||
"url": null, // for stateless only. e.g. http://localhost:8080
|
||||
"userAgent": "php-httpproxy/0.1.5 (Client; WelsonJS; abuse@catswords.net)", // for stateless only
|
||||
"rpcMethod": "relay_fetch_url" // for stateless proxy
|
||||
};
|
||||
this.engine = (typeof(engine) !== "undefined" ? engine : "MSXML");
|
||||
|
||||
|
@ -155,6 +86,7 @@ var HTTPObject = function(engine) {
|
|||
this.isLoggingCookie = false;
|
||||
this.debuggingText = '';
|
||||
|
||||
this.curlVersion = "8.12.1_4";
|
||||
this.curlOptions = [];
|
||||
|
||||
this.charset = FILE.CdoCharset.CdoUTF_8;
|
||||
|
@ -187,11 +119,11 @@ var HTTPObject = function(engine) {
|
|||
// the location of cURL binary
|
||||
var arch = SYS.getArch();
|
||||
if (arch.toLowerCase().indexOf("arm") > -1) {
|
||||
this.setBinPath("bin\\x64\\curl-8.10.1_1-win64a-mingw\\bin\\curl.exe");
|
||||
this.setBinPath("bin\\arm64\\curl-" + this.curlVersion + "-win64a-mingw\\bin\\curl.exe");
|
||||
} else if (arch.indexOf("64") > -1) {
|
||||
this.setBinPath("bin\\x64\\curl-8.10.1_1-win64-mingw\\bin\\curl.exe");
|
||||
this.setBinPath("bin\\x64\\curl-" + this.curlVersion + "-win64-mingw\\bin\\curl.exe");
|
||||
} else {
|
||||
this.setBinPath("bin\\x86\\curl-8.10.1_1-win32-mingw\\bin\\curl.exe");
|
||||
this.setBinPath("bin\\x86\\curl-" + this.curlVersion + "-win32-mingw\\bin\\curl.exe");
|
||||
}
|
||||
|
||||
// do not clear after calling the `exec`
|
||||
|
@ -211,6 +143,11 @@ var HTTPObject = function(engine) {
|
|||
console.info(this.engine, "is use", binPath);
|
||||
this._interface.setPrefix(binPath);
|
||||
};
|
||||
|
||||
this.setCurlVersion = function(curlVersion) {
|
||||
this.curlVersion = curlVersion;
|
||||
this.setEngine("CURL");
|
||||
};
|
||||
|
||||
this.jqEnabled = function() {
|
||||
return (typeof(window) !== "undefined" && typeof(window.jQuery) !== "undefined");
|
||||
|
@ -218,18 +155,18 @@ var HTTPObject = function(engine) {
|
|||
|
||||
this.jqAjax = function(url, callback, onError) {
|
||||
var options = {
|
||||
type: this.method,
|
||||
type: this.getMethod(),
|
||||
headers: this.headers,
|
||||
url: this.serializeParameters(url),
|
||||
//data: this.requestBody,
|
||||
data: null,
|
||||
contentType: this.contentType,
|
||||
success: callback,
|
||||
async: this.isAsynchronous,
|
||||
error: onError // (request, status, error)
|
||||
async: this.isAsync,
|
||||
error: onError // f(request, status, error)
|
||||
};
|
||||
|
||||
if (["POST", "PUT", "PATCH"].indexOf(this.method) > -1) {
|
||||
options['data'] = this.requestBody;
|
||||
options['data'] = this.serialize();
|
||||
}
|
||||
|
||||
this.setResponseBody(window.jQuery.ajax(options).responseText);
|
||||
|
@ -244,11 +181,11 @@ var HTTPObject = function(engine) {
|
|||
if (this.dataType === "json") {
|
||||
return true;
|
||||
} else if (this.engine == "MSXML") {
|
||||
var headers = this.getHeaders();
|
||||
var headers = this.getResponseHeaders();
|
||||
for (var key in headers) {
|
||||
var _k = key.toLowerCase();
|
||||
var _v = headers[key].toLowerCase();
|
||||
if (_k === "content-type" && _v === "application/json") {
|
||||
var header_key = key.toLowerCase();
|
||||
var header_value = headers[key].toLowerCase();
|
||||
if (header_key === "content-type" && header_value === "application/json") {
|
||||
this.dataType = "json";
|
||||
return true;
|
||||
}
|
||||
|
@ -283,7 +220,7 @@ var HTTPObject = function(engine) {
|
|||
this.proxy.credential = availableProxy['credential'] || this.proxy.credential;
|
||||
this.proxy.url = availableProxy['url'] || this.proxy.url;
|
||||
|
||||
console.info("Please check documentation:", availableProxy.documentation);
|
||||
console.info("See the documentation:", availableProxy.documentation);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -295,6 +232,11 @@ var HTTPObject = function(engine) {
|
|||
this.proxy[k] = proxy[k];
|
||||
}
|
||||
|
||||
// When JSON-RPC 2.0 based stateless proxy
|
||||
if (this.proxy.type == "stateless-jsonrpc2") {
|
||||
this.proxy.method = "POST";
|
||||
}
|
||||
|
||||
// check proxy configuration
|
||||
console.info("Proxy Configuration:", JSON.stringify(this.proxy));
|
||||
|
||||
|
@ -302,9 +244,13 @@ var HTTPObject = function(engine) {
|
|||
};
|
||||
|
||||
this.setMethod = function(method) {
|
||||
this.method = method;
|
||||
this.method = method.toUpperCase();
|
||||
return this;
|
||||
};
|
||||
|
||||
this.getMethod = function() {
|
||||
return (this.proxy.method != null ? this.proxy.method : this.method);
|
||||
};
|
||||
|
||||
this.setDataType = function(type) {
|
||||
this.dataType = type;
|
||||
|
@ -357,25 +303,24 @@ var HTTPObject = function(engine) {
|
|||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("HTTPObject.setHeaders() -> ", e.message);
|
||||
console.error("Exception on HTTPObject.setHeaders():", e.message);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
this.getHeader = function(key) {
|
||||
this.getResponseHeader = function(key) {
|
||||
try {
|
||||
return this._interface.getResponseHeader(key);
|
||||
} catch (e) {
|
||||
console.error("HTTPObject.getHeader() -> ", e.message);
|
||||
console.error("Exception on HTTPObject.getResponseHeader():", e.message);
|
||||
}
|
||||
};
|
||||
|
||||
this.getHeaders = function() {
|
||||
this.getResponseHeaders = function(callback) {
|
||||
try {
|
||||
var raw = this._interface.getAllResponseHeaders();
|
||||
|
||||
return raw.split(/[\r\n]+/).filter(function(s) {
|
||||
var text = this._interface.getAllResponseHeaders();
|
||||
var headers = text.split(/[\r\n]+/).filter(function(s) {
|
||||
return s.trim().length > 0;
|
||||
}).map(function(s) {
|
||||
return s.trim().split(": ");
|
||||
|
@ -383,11 +328,33 @@ var HTTPObject = function(engine) {
|
|||
acc[c[0].trim()] = c[1].trim();
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
if (typeof callback !== "function") {
|
||||
return headers;
|
||||
}
|
||||
|
||||
return callback(headers);
|
||||
} catch (e) {
|
||||
console.error("HTTPObject.getHeaders() -> ", e.message);
|
||||
console.error("Exception on HTTPObject.getResponseHeaders():", e.message);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.getRequestHeader = function(key) {
|
||||
return this.headers[key];
|
||||
}
|
||||
|
||||
this.getRequestHeaders = function(callback) {
|
||||
try {
|
||||
if (typeof callback !== "function") {
|
||||
return this.headers;
|
||||
}
|
||||
|
||||
return callback(this.headers);
|
||||
} catch (e) {
|
||||
console.error("Exception on HTTPObject.getRequestHeaders():", e.message);
|
||||
}
|
||||
};
|
||||
|
||||
this.setParameter = function(key, value) {
|
||||
this.parameters[key] = value;
|
||||
return this;
|
||||
|
@ -405,7 +372,7 @@ var HTTPObject = function(engine) {
|
|||
this.setParameter(key, value);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("HTTPObject.setParameters() -> ", e.message);
|
||||
console.error("Exception on HTTPObject.setParameters():", e.message);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
@ -431,7 +398,7 @@ var HTTPObject = function(engine) {
|
|||
};
|
||||
|
||||
this.setIsAsynchronous = function(flag) {
|
||||
this.isAsynchronous = flag;
|
||||
this.isAsync = flag;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -439,22 +406,46 @@ var HTTPObject = function(engine) {
|
|||
this.userAgent = agent;
|
||||
return this;
|
||||
};
|
||||
|
||||
this.serialize = function() {
|
||||
if (this.isJSONRequest() && typeof(this.requestBody) === "object") {
|
||||
return JSON.stringify(this.requestBody);
|
||||
} else if (typeof(this.requestBody) === "object") {
|
||||
return this.serializeURL(this.evaluate(this.requestBody));
|
||||
|
||||
this.getUserAgent = function() {
|
||||
return (this.proxy.userAgent != null ? this.proxy.userAgent : this.userAgent);
|
||||
};
|
||||
|
||||
this.serialize = function(url) {
|
||||
var data = "";
|
||||
|
||||
if (this.isJSONRequest() && typeof this.requestBody === "object") {
|
||||
data = JSON.stringify(this.requestBody);
|
||||
} else if (typeof this.requestBody === "object") {
|
||||
data = this.serializeURL(this.requestBody);
|
||||
} else {
|
||||
return this.evaluate(this.requestBody);
|
||||
data = this.evaluate(this.requestBody);
|
||||
}
|
||||
|
||||
if (this.proxy.type == "stateless-jsonrpc2") {
|
||||
data = JSON.stringify(
|
||||
JsonRpc2.wrap(this.proxy.rpcMethod, {
|
||||
"method": this.method,
|
||||
"url": url,
|
||||
"headers": this.getRequestHeaders(function(x) {
|
||||
return Object.keys(x).reduce(function(a, k) {
|
||||
a.push(k + ": " + x[k]);
|
||||
return a;
|
||||
}, []);
|
||||
}),
|
||||
"data": data
|
||||
}, "")
|
||||
);
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
this.serializeURL = function(parameters) {
|
||||
this.serializeURL = function(params) {
|
||||
var s = [];
|
||||
for (var k in parameters) {
|
||||
if (parameters.hasOwnProperty(k)) {
|
||||
s.push(encodeURIComponent(k) + "=" + encodeURIComponent(this.evaluate(parameters[k])));
|
||||
for (var k in params) {
|
||||
if (params.hasOwnProperty(k)) {
|
||||
s.push(encodeURIComponent(k) + "=" + encodeURIComponent(this.evaluate(params[k])));
|
||||
}
|
||||
}
|
||||
return s.join("&");
|
||||
|
@ -468,21 +459,21 @@ var HTTPObject = function(engine) {
|
|||
// Bind parameters
|
||||
if (Object.keys(this.parameters).length > 0) {
|
||||
// Type 2
|
||||
var parameters = {};
|
||||
var params = {};
|
||||
for (var k in this.parameters) {
|
||||
if (url.indexOf(':' + k) > -1) {
|
||||
url = url.replace(':' + k, this.evaluate(this.parameters[k]));
|
||||
} else {
|
||||
parameters[k] = this.evaluate(this.parameters[k]);
|
||||
params[k] = this.evaluate(this.parameters[k]);
|
||||
}
|
||||
}
|
||||
|
||||
// Type 1
|
||||
if (Object.keys(parameters).length > 0) {
|
||||
if (Object.keys(params).length > 0) {
|
||||
if (url.indexOf('?') > -1) {
|
||||
url += '&' + this.serializeURL(parameters);
|
||||
url += '&' + this.serializeURL(params);
|
||||
} else {
|
||||
url += '?' + this.serializeURL(parameters);
|
||||
url += '?' + this.serializeURL(params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -492,11 +483,11 @@ var HTTPObject = function(engine) {
|
|||
return url;
|
||||
};
|
||||
|
||||
this.getProxiedURL = function(url) {
|
||||
this.getProxiedUrl = function(url) {
|
||||
if (!this.proxy.enabled) return url;
|
||||
|
||||
if (this.proxy.type == "serp") {
|
||||
var serp = this.parseSerpUrl(url);
|
||||
var serp = SERP.parseUrl(url);
|
||||
this.setVariable("engine", serp.engine);
|
||||
this.setVariable("q", encodeURIComponent(serp.keyword));
|
||||
}
|
||||
|
@ -509,59 +500,30 @@ var HTTPObject = function(engine) {
|
|||
return url;
|
||||
};
|
||||
|
||||
this.parseSerpUrl = function(url) {
|
||||
var getEngine = function(url) {
|
||||
var match = url.match(/(?:https?:\/\/)?(?:www\.)?(google|youtube|bing|baidu|amazon|naver|daum)\.\w+/), result;
|
||||
if (match) {
|
||||
result = match[1];
|
||||
if (result == "naver" || result == "daum") {
|
||||
result = "google";
|
||||
}
|
||||
} else {
|
||||
result = "google";
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
var getKeyword = function(url) {
|
||||
var regex = /[?&](q|wd|query|search_query|k)=([^&]*)/g;
|
||||
var match, keywords = [];
|
||||
while ((match = regex.exec(url)) !== null) {
|
||||
keywords.push(match[2]);
|
||||
}
|
||||
return keywords.join(' ');
|
||||
};
|
||||
|
||||
return {
|
||||
"engine": getEngine(url),
|
||||
"keyword": getKeyword(url)
|
||||
}
|
||||
};
|
||||
|
||||
this.open = function(method, url) {
|
||||
var url = this.serializeParameters(url);
|
||||
|
||||
this.setMethod(method.toUpperCase()); // set method
|
||||
this.setMethod(method); // set method
|
||||
this.pushState(null, null, url); // push state
|
||||
this.setHeader("User-Agent", this.evaluate(this.userAgent)); // user agent
|
||||
this.setHeader("User-Agent", this.evaluate(this.getUserAgent())); // user agent
|
||||
|
||||
try {
|
||||
if (this.engine == "MSXML") {
|
||||
// Get the proxied URL
|
||||
url = this.getProxiedURL(url);
|
||||
url = this.getProxiedUrl(url);
|
||||
|
||||
// Open the URL
|
||||
switch (this.method) {
|
||||
switch (this.getMethod()) {
|
||||
case "POST":
|
||||
this._interface.open(method, url, this.isAsynchronous);
|
||||
this._interface.open("POST", url, this.isAsync);
|
||||
break;
|
||||
|
||||
case "GET":
|
||||
this._interface.open(method, url, this.isAsynchronous);
|
||||
this._interface.open("GET", url, this.isAsync);
|
||||
break;
|
||||
|
||||
default:
|
||||
console.warn("Switching the engine to cURL. Not supported method in MSXML: " + method);
|
||||
console.warn(this.method, "method not supported. Retrying with cURL...");
|
||||
this.setEngine("CURL");
|
||||
console.log("Use the engine:", this.engine);
|
||||
}
|
||||
|
@ -569,7 +531,7 @@ var HTTPObject = function(engine) {
|
|||
console.log("Use the engine:", this.engine);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("HTTPObject.open() ->", e.message);
|
||||
console.error("Exception on HTTPObject.open():", e.message);
|
||||
}
|
||||
|
||||
return this;
|
||||
|
@ -579,6 +541,17 @@ var HTTPObject = function(engine) {
|
|||
var responseText = null;
|
||||
var debuggingText = null;
|
||||
|
||||
// check exists the opened states
|
||||
if (this.states.length == 0) {
|
||||
console.error("No available states");
|
||||
return;
|
||||
}
|
||||
|
||||
// get opened URL from last states
|
||||
var state = this.states[this.states.length - 1];
|
||||
var target_url = state.url;
|
||||
var url = this.getProxiedUrl(target_url);
|
||||
|
||||
// [lib/http] cURL error with non-escaped ampersand on Command Prompt #103
|
||||
var replaceAndExcludeCaretAnd = function(inputString) {
|
||||
var result = "";
|
||||
|
@ -613,13 +586,13 @@ var HTTPObject = function(engine) {
|
|||
this._interface.setRequestHeader(key, this.evaluate(this.headers[key]));
|
||||
}
|
||||
|
||||
switch (this.method) {
|
||||
switch (this.getMethod()) {
|
||||
case "GET":
|
||||
this._interface.send();
|
||||
break;
|
||||
|
||||
default:
|
||||
this._interface.send(this.serialize());
|
||||
this._interface.send(this.serialize(target_url));
|
||||
}
|
||||
|
||||
// Waiting a response
|
||||
|
@ -628,148 +601,144 @@ var HTTPObject = function(engine) {
|
|||
// Get response text
|
||||
responseText = this._interface.responseText;
|
||||
} else if (this.engine == "CURL") {
|
||||
if (this.states.length > 0) {
|
||||
// Make CURL context
|
||||
var state = this.states[this.states.length - 1];
|
||||
var cmd = [];
|
||||
var url = this.getProxiedURL(state.url);
|
||||
// Build the cURL command line context
|
||||
var cmd = [];
|
||||
|
||||
if (this.isDebugging) {
|
||||
cmd.push("-v");
|
||||
}
|
||||
|
||||
if (this.isCompressedResponse) {
|
||||
cmd.push("--compressed");
|
||||
}
|
||||
|
||||
if (this.isFollowRedirect) {
|
||||
cmd.push("-L");
|
||||
}
|
||||
|
||||
cmd.push("-X");
|
||||
cmd.push(this.method);
|
||||
|
||||
if (Object.keys(this.headers).length > 0) {
|
||||
for (var key in this.headers) {
|
||||
var value = this.evaluate(this.headers[key]);
|
||||
if (value != null) {
|
||||
cmd.push("-H");
|
||||
cmd.push(key + ": " + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.cookie != null) {
|
||||
cmd.push("-b");
|
||||
cmd.push(this.evaluate(this.cookie));
|
||||
}
|
||||
|
||||
if (this.isLoggingCookie) {
|
||||
cmd.push("-c");
|
||||
cmd.push(this.storedCookie.path);
|
||||
}
|
||||
|
||||
cmd.push("-A");
|
||||
cmd.push(this.evaluate(this.userAgent));
|
||||
|
||||
// --connect-timeout
|
||||
if (this.connectTimeout > 0) {
|
||||
cmd.push("--connect-timeout");
|
||||
cmd.push(this.connectTimeout);
|
||||
}
|
||||
|
||||
// --max-time
|
||||
if (this.maxTime > 0) {
|
||||
cmd.push("--max-time");
|
||||
cmd.push(this.maxTime);
|
||||
}
|
||||
|
||||
// Add the credential parameters
|
||||
switch (this.credential.method.toUpperCase()) {
|
||||
case "BASIC":
|
||||
cmd.push("-u");
|
||||
cmd.push(this.credential.username + ":" + this.credential.password);
|
||||
break;
|
||||
}
|
||||
|
||||
// Add the request body if this is not GET method
|
||||
if (this.method !== "GET") {
|
||||
cmd.push("-d");
|
||||
cmd.push(replaceAndExcludeCaretAnd(this.serialize()));
|
||||
}
|
||||
|
||||
// Add proxy: <[protocol://][user:password@]proxyhost[:port]>
|
||||
if (this.proxy != null && this.proxy.enabled && this.proxy.type == "stateful") {
|
||||
cmd.push("-x");
|
||||
if (this.proxy.credential != null) {
|
||||
cmd.push([
|
||||
this.proxy.protocol,
|
||||
"://",
|
||||
this.proxy.credential.username,
|
||||
":",
|
||||
this.proxy.credential.password,
|
||||
"@",
|
||||
this.proxy.host,
|
||||
":",
|
||||
this.proxy.port
|
||||
].join(""));
|
||||
} else {
|
||||
cmd.push([
|
||||
this.proxy.protocol,
|
||||
"://",
|
||||
this.proxy.host,
|
||||
":",
|
||||
this.proxy.port
|
||||
].join(""));
|
||||
}
|
||||
}
|
||||
|
||||
// if it is download
|
||||
if (this.saveTo != null) {
|
||||
cmd.push("-o");
|
||||
cmd.push(this.saveTo);
|
||||
}
|
||||
|
||||
// If not verify SSL
|
||||
if (!this.isVerifySSL) {
|
||||
if (this.proxy.enabled) {
|
||||
cmd.push("--proxy-insecure");
|
||||
}
|
||||
cmd.push("-k");
|
||||
cmd.push("--ssl-no-revoke");
|
||||
}
|
||||
|
||||
// if the count of this.curlOptions greater than 0
|
||||
if (this.curlOptions.length > 0) {
|
||||
cmd = cmd.concat(this.curlOptions);
|
||||
}
|
||||
|
||||
// set the URL
|
||||
cmd.push(url);
|
||||
|
||||
// Get response text
|
||||
responseText = this._interface.setCharset(this.charset).exec(cmd);
|
||||
|
||||
// Reload a cookie in the pipe
|
||||
if (this.isLoggingCookie) {
|
||||
this.storedCookie.reload();
|
||||
}
|
||||
|
||||
// If enabled the charset(text encoding) detector
|
||||
if (this.isUseDetectCharset) {
|
||||
var detectedCharset = this.detectCharset(responseText);
|
||||
console.log("Detected charset:", detectedCharset);
|
||||
|
||||
if (detectedCharset != null && this.charset != detectedCharset) {
|
||||
var _interface = SHELL.create();
|
||||
responseText = _interface.setCharset(detectedCharset).exec(cmd);
|
||||
debuggingText = _interface.stderr.read();
|
||||
}
|
||||
}
|
||||
|
||||
// Get debuging text
|
||||
debuggingText = this._interface.stderr.read();
|
||||
if (this.isDebugging) {
|
||||
cmd.push("-v");
|
||||
}
|
||||
|
||||
if (this.isCompressedResponse) {
|
||||
cmd.push("--compressed");
|
||||
}
|
||||
|
||||
if (this.isFollowRedirect) {
|
||||
cmd.push("-L");
|
||||
}
|
||||
|
||||
cmd.push("-X");
|
||||
cmd.push(this.getMethod());
|
||||
|
||||
if (Object.keys(this.headers).length > 0) {
|
||||
for (var key in this.headers) {
|
||||
var value = this.evaluate(this.headers[key]);
|
||||
if (value != null) {
|
||||
cmd.push("-H");
|
||||
cmd.push(key + ": " + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.cookie != null) {
|
||||
cmd.push("-b");
|
||||
cmd.push(this.evaluate(this.cookie));
|
||||
}
|
||||
|
||||
if (this.isLoggingCookie) {
|
||||
cmd.push("-c");
|
||||
cmd.push(this.storedCookie.path);
|
||||
}
|
||||
|
||||
cmd.push("-A");
|
||||
cmd.push(this.evaluate(this.getUserAgent()));
|
||||
|
||||
// --connect-timeout
|
||||
if (this.connectTimeout > 0) {
|
||||
cmd.push("--connect-timeout");
|
||||
cmd.push(this.connectTimeout);
|
||||
}
|
||||
|
||||
// --max-time
|
||||
if (this.maxTime > 0) {
|
||||
cmd.push("--max-time");
|
||||
cmd.push(this.maxTime);
|
||||
}
|
||||
|
||||
// Add the credential parameters
|
||||
switch (this.credential.method.toUpperCase()) {
|
||||
case "BASIC":
|
||||
cmd.push("-u");
|
||||
cmd.push(this.credential.username + ":" + this.credential.password);
|
||||
break;
|
||||
}
|
||||
|
||||
// Add the request body if this is not GET method
|
||||
if (this.getMethod() !== "GET") {
|
||||
cmd.push("-d");
|
||||
cmd.push(replaceAndExcludeCaretAnd(this.serialize(target_url)));
|
||||
}
|
||||
|
||||
// Add proxy: <[protocol://][user:password@]proxyhost[:port]>
|
||||
if (this.proxy != null && this.proxy.enabled && this.proxy.type == "stateful") {
|
||||
cmd.push("-x");
|
||||
if (this.proxy.credential != null) {
|
||||
cmd.push([
|
||||
this.proxy.protocol,
|
||||
"://",
|
||||
this.proxy.credential.username,
|
||||
":",
|
||||
this.proxy.credential.password,
|
||||
"@",
|
||||
this.proxy.host,
|
||||
":",
|
||||
this.proxy.port
|
||||
].join(""));
|
||||
} else {
|
||||
cmd.push([
|
||||
this.proxy.protocol,
|
||||
"://",
|
||||
this.proxy.host,
|
||||
":",
|
||||
this.proxy.port
|
||||
].join(""));
|
||||
}
|
||||
}
|
||||
|
||||
// if it is download
|
||||
if (this.saveTo != null) {
|
||||
cmd.push("-o");
|
||||
cmd.push(this.saveTo);
|
||||
}
|
||||
|
||||
// If not verify SSL
|
||||
if (!this.isVerifySSL) {
|
||||
if (this.proxy.enabled) {
|
||||
cmd.push("--proxy-insecure");
|
||||
}
|
||||
cmd.push("-k");
|
||||
cmd.push("--ssl-no-revoke");
|
||||
}
|
||||
|
||||
// if the count of this.curlOptions greater than 0
|
||||
if (this.curlOptions.length > 0) {
|
||||
cmd = cmd.concat(this.curlOptions);
|
||||
}
|
||||
|
||||
// set the URL
|
||||
cmd.push(url);
|
||||
|
||||
// Get response text
|
||||
responseText = this._interface.setCharset(this.charset).exec(cmd);
|
||||
|
||||
// Reload a cookie in the pipe
|
||||
if (this.isLoggingCookie) {
|
||||
this.storedCookie.reload();
|
||||
}
|
||||
|
||||
// If enabled the charset(text encoding) detector
|
||||
if (this.isUseDetectCharset) {
|
||||
var detectedCharset = this.detectCharset(responseText);
|
||||
console.log("Detected charset:", detectedCharset);
|
||||
|
||||
if (detectedCharset != null && this.charset != detectedCharset) {
|
||||
var _interface = SHELL.create();
|
||||
responseText = _interface.setCharset(detectedCharset).exec(cmd);
|
||||
debuggingText = _interface.stderr.read();
|
||||
}
|
||||
}
|
||||
|
||||
// Get debuging text
|
||||
debuggingText = this._interface.stderr.read();
|
||||
|
||||
// clear manually
|
||||
this._interface.clear();
|
||||
|
@ -778,10 +747,10 @@ var HTTPObject = function(engine) {
|
|||
var job_priority = "normal";
|
||||
var state = this.states[this.states.length - 1];
|
||||
var cmd = ["/transfer", job_name];
|
||||
var url = this.getProxiedURL(state.url);
|
||||
var url = this.getProxiedUrl(state.url);
|
||||
var out = PipeIPC.connect("volatile");
|
||||
|
||||
if (this.method == "GET") {
|
||||
if (this.getMethod() == "GET") {
|
||||
cmd = cmd.concat(["/download", "/priority", job_priority, url, SYS.getCurrentScriptDirectory() + "\\" + out.path]); // build a BITS command
|
||||
this._interface.exec(cmd); // launch the download job
|
||||
out.reload(); // read the downloaded data
|
||||
|
@ -795,7 +764,7 @@ var HTTPObject = function(engine) {
|
|||
} else if (this.engine == "CERT") {
|
||||
var state = this.states[this.states.length - 1];
|
||||
var out = PipeIPC.connect("volatile");
|
||||
var url = this.getProxiedURL(state.url);
|
||||
var url = this.getProxiedUrl(state.url);
|
||||
var cmd = ["-urlcache", "-split", "-f", url, out.path];
|
||||
this._interface.exec(cmd);
|
||||
out.reload();
|
||||
|
@ -818,9 +787,14 @@ var HTTPObject = function(engine) {
|
|||
|
||||
if (this.isJSONResponse()) {
|
||||
try {
|
||||
this.setResponseBody(JSON.parse(responseText));
|
||||
var res = JSON.parse(responseText);
|
||||
if (this.proxy.type == "stateless-jsonrpc2") {
|
||||
this.setResponseBody(res.result.data);
|
||||
} else {
|
||||
this.setResponseBody(res);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("JSON parse error: " + e.message);
|
||||
console.error("JSON parse error:", e.message);
|
||||
this.setResponseBody({});
|
||||
}
|
||||
} else {
|
||||
|
@ -1217,6 +1191,25 @@ function parseURL(url) {
|
|||
};
|
||||
}
|
||||
|
||||
// Check an available proxies
|
||||
AVAILABLE_PROXIES.forEach(function(proxy) {
|
||||
if (proxy.type == "file") {
|
||||
if (FILE.fileExists(proxy.url)) {
|
||||
try {
|
||||
var fileContents = FILE.readFile(proxy.url, FILE.CdoCharset.CdoUTF_8);
|
||||
var data = JSON.parse(fileContents);
|
||||
data.forEach(function(x) {
|
||||
AVAILABLE_PROXIES.push(x);
|
||||
});
|
||||
} catch (e) {
|
||||
console.warn(proxy.url, "is not a valid file");
|
||||
}
|
||||
} else {
|
||||
console.warn(proxy.url, "does not exists");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
exports.create = create;
|
||||
exports.get = get;
|
||||
exports.post = post;
|
||||
|
@ -1228,7 +1221,7 @@ exports.parseURL = parseURL;
|
|||
exports.DEFAULT_USER_AGENT = DEFAULT_USER_AGENT;
|
||||
exports.defaultUserAgent = DEFAULT_USER_AGENT; // compatible
|
||||
|
||||
exports.VERSIONINFO = "HTTP REST Client (http.js) version 0.7.40";
|
||||
exports.VERSIONINFO = "WelsonJS framework HTTP client (http.js) version 0.7.48";
|
||||
exports.AUTHOR = "abuse@catswords.net";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
||||
|
|
32
lib/ip-reputation.js
Normal file
32
lib/ip-reputation.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
// ip-reputation.js
|
||||
// Namhyeon Go <abuse@catswords.net>
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
// ***SECURITY NOTICE***
|
||||
// IP Reputation Checker requires an internet connection, and data may be transmitted externally. Users must adhere to the terms of use and privacy policy.
|
||||
// - AbuseIPDB website: https://www.abuseipdb.com/
|
||||
//
|
||||
var HTTP = require("lib/http");
|
||||
var APIKEY = require("lib/apikey");
|
||||
|
||||
function check(ip_address) {
|
||||
var apikey = APIKEY.getApiKey("abuseipdb");
|
||||
|
||||
var response = HTTP.create()
|
||||
.setHeaders({
|
||||
"Key": apikey,
|
||||
"Accept": "application/json"
|
||||
})
|
||||
.setParameters({
|
||||
"ipAddress": ip_address
|
||||
});
|
||||
|
||||
return response.responseBody;
|
||||
}
|
||||
|
||||
exports.check = check;
|
||||
|
||||
exports.VERSIONINFO = "IP Reputation Checker (ip-reputation.js) version 0.1";
|
||||
exports.AUTHOR = "abuse@catswords.net";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
|
@ -2,18 +2,18 @@
|
|||
// JSON-RPC 2.0 wrapper for WelsonJS framework
|
||||
// Namhyeon Go <abuse@catswords.net>
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
var HTTP = require("lib/http");
|
||||
|
||||
function jsonrpc2(url) {
|
||||
//
|
||||
function JsonRpc2(url) {
|
||||
this.url = url;
|
||||
this.userAgent = "php-httpproxy/0.1.5 (Client; WelsonJS; abuse@catswords.net)";
|
||||
|
||||
this.userAgent = "php-httpproxy/0.1.5 (Client; WelsonJS)";
|
||||
|
||||
this.setUserAgent = function(agent) {
|
||||
this.userAgent = agent;
|
||||
};
|
||||
|
||||
this.invoke = function(method, params, id) {
|
||||
var result;
|
||||
var response = HTTP.create("MSXML")
|
||||
var response = require("lib/http").create("MSXML")
|
||||
.setContentType("application/json")
|
||||
.setDataType("json")
|
||||
.setUserAgent(this.userAgent)
|
||||
|
@ -46,13 +46,17 @@ function wrap(method, params, id) {
|
|||
}
|
||||
|
||||
function create(url) {
|
||||
return new jsonrpc2(url);
|
||||
return new JsonRpc2(url);
|
||||
}
|
||||
|
||||
var DEFAULT_JSONRPC2_URL = "https://azure-ashlan-40.tiiny.io/";
|
||||
|
||||
exports.wrap = wrap;
|
||||
exports.create = create;
|
||||
|
||||
exports.VERSIONINFO = "JSON-RPC 2.0 wrapper (jsonrpc2.js) version 0.1.4";
|
||||
exports.DEFAULT_JSONRPC2_URL = DEFAULT_JSONRPC2_URL;
|
||||
|
||||
exports.VERSIONINFO = "JSON-RPC 2.0 wrapper (jsonrpc2.js) version 0.1.5";
|
||||
exports.AUTHOR = "abuse@catswords.net";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
||||
|
|
539
lib/language-inference-engine.js
Normal file
539
lib/language-inference-engine.js
Normal file
|
@ -0,0 +1,539 @@
|
|||
// language-inference-engine.js
|
||||
// Language Inference Engine (e.g., NLP, LLM) services integration
|
||||
// Namhyeon Go <abuse@catswords.net>
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
|
||||
// ***SECURITY NOTICE***
|
||||
// Language Inference Engine requires an internet connection, and data may be transmitted externally. Users must adhere to the terms of use and privacy policy.
|
||||
// - OpenAI: https://openai.com/policies/row-privacy-policy/
|
||||
// - Anthropic: https://www.anthropic.com/legal/privacy
|
||||
// - Groq: https://groq.com/privacy-policy/
|
||||
// - Mistral: https://mistral.ai/terms/
|
||||
// - xAI: https://x.ai/legal/privacy-policy
|
||||
// - Google Gemini: https://developers.google.com/idx/support/privacy
|
||||
// - DeepSeek: https://chat.deepseek.com/downloads/DeepSeek%20Privacy%20Policy.html
|
||||
// - Moonshot: https://kimi.moonshot.cn/user/agreement/userPrivacy
|
||||
// - AlibabaCloud: https://www.alibabacloud.com/help/en/legal/latest/alibaba-cloud-international-website-privacy-policy
|
||||
// - ClovaStudio: https://clova-x.naver.com/ai_policies
|
||||
// - Catswords AI: https://policy.catswords.social/site_terms.html
|
||||
//
|
||||
var HTTP = require("lib/http");
|
||||
var CRED = require("lib/credentials");
|
||||
|
||||
var BIAS_MESSAGE = "Write all future code examples in JavaScript ES3 using the exports variable. " +
|
||||
"Include a test method with the fixed name test. " +
|
||||
"Respond exclusively in code without blocks.";
|
||||
|
||||
var ENGINE_PROFILES = {
|
||||
"openai": {
|
||||
"type": "llm",
|
||||
"availableModels": [
|
||||
"gpt-4o-mini",
|
||||
"gpt-4o",
|
||||
"o1",
|
||||
"o1-mini",
|
||||
"o3-mini",
|
||||
"gpt-4-turbo",
|
||||
"gpt-3.5-turbo"
|
||||
],
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer {apikey}"
|
||||
},
|
||||
"url": "https://api.openai.com/v1/chat/completions",
|
||||
"wrap": function(model, message, temperature) {
|
||||
return {
|
||||
"model": model,
|
||||
"messages": [{
|
||||
"role": "developer",
|
||||
"content": BIAS_MESSAGE
|
||||
}, {
|
||||
"role": "user",
|
||||
"content": message
|
||||
}],
|
||||
"temperature": temperature,
|
||||
"stream": false
|
||||
};
|
||||
},
|
||||
"callback": function(response) {
|
||||
if ("error" in response) {
|
||||
return ["Error: " + response.error.message];
|
||||
} else {
|
||||
return response.choices.reduce(function(a, x) {
|
||||
a.push(x.message.content);
|
||||
|
||||
return a;
|
||||
}, []);
|
||||
}
|
||||
}
|
||||
},
|
||||
"anthropic": {
|
||||
"type": "llm",
|
||||
"availableModels": [
|
||||
"claude-3-5-sonnet-20241022"
|
||||
],
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"x-api-key": "{apikey}",
|
||||
"anthropic-version": "2023-06-01"
|
||||
},
|
||||
"url": "https://api.anthropic.com/v1/messages",
|
||||
"wrap": function(model, message, temperature) {
|
||||
return {
|
||||
"model": model,
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": BIAS_MESSAGE
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": message
|
||||
}
|
||||
],
|
||||
"temperature": temperature,
|
||||
"stream": false
|
||||
};
|
||||
},
|
||||
"callback": function(response) {
|
||||
if ("error" in response) {
|
||||
return ["Error: " + response.error.message];
|
||||
} else {
|
||||
return response.content.reduce(function(a, x) {
|
||||
if (x.type == "text") {
|
||||
a.push(x.text);
|
||||
} else {
|
||||
a.push("Not supported type: " + x.type);
|
||||
}
|
||||
|
||||
return a;
|
||||
}, []);
|
||||
}
|
||||
}
|
||||
},
|
||||
"groq": {
|
||||
"type": "llm",
|
||||
"availableModels": [
|
||||
"llama-3.1-8b-instant"
|
||||
],
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer {apikey}"
|
||||
},
|
||||
"url": "https://api.groq.com/openai/v1/chat/completions",
|
||||
"wrap": function(model, message, temperature) {
|
||||
return {
|
||||
"model": model,
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": BIAS_MESSAGE
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": message
|
||||
}
|
||||
],
|
||||
"temperature": temperature,
|
||||
"stream": false
|
||||
};
|
||||
},
|
||||
"callback": function(response) {
|
||||
if ("error" in response) {
|
||||
return ["Error: " + response.error.message];
|
||||
} else {
|
||||
return response.choices.reduce(function(a, x) {
|
||||
a.push(x.message.content);
|
||||
|
||||
return a;
|
||||
}, []);
|
||||
}
|
||||
}
|
||||
},
|
||||
"xai": {
|
||||
"type": "llm",
|
||||
"availableModels": [
|
||||
"grok-2-latest"
|
||||
],
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer {apikey}"
|
||||
},
|
||||
"url": "https://api.x.ai/v1/chat/completions",
|
||||
"wrap": function(model, message, temperature) {
|
||||
return {
|
||||
"model": model,
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": BIAS_MESSAGE
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": message
|
||||
}
|
||||
],
|
||||
"temperature": temperature,
|
||||
"stream": false
|
||||
};
|
||||
},
|
||||
"callback": function(response) {
|
||||
return response.choices.reduce(function(a, x) {
|
||||
a.push(x.message.content);
|
||||
|
||||
return a;
|
||||
}, []);
|
||||
}
|
||||
},
|
||||
"google": {
|
||||
"type": "llm",
|
||||
"availableModels": [
|
||||
"gemini-1.5-flash"
|
||||
],
|
||||
"headers": {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
"url": "https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent?key={apikey}",
|
||||
"warp": function(model, message, temperature) {
|
||||
return {
|
||||
"contents": [
|
||||
{
|
||||
"parts": [
|
||||
{
|
||||
"text": message
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
"callback": function(response) {
|
||||
if ("error" in response) {
|
||||
return ["Error: " + response.error.message];
|
||||
} else {
|
||||
return response.candidates.reduce(function(a, x) {
|
||||
x.content.parts.forEach(function(part) {
|
||||
if ("text" in part) {
|
||||
a.push(part.text);
|
||||
} else {
|
||||
a.push("Not supported type");
|
||||
}
|
||||
});
|
||||
|
||||
return a;
|
||||
}, []);
|
||||
}
|
||||
}
|
||||
},
|
||||
"mistral": {
|
||||
"type": "llm",
|
||||
"availableModels": [
|
||||
"ministral-8b-latest"
|
||||
],
|
||||
"url": "https://api.mistral.ai/v1/chat/completions",
|
||||
"wrap": function(model, message, temperature) {
|
||||
return {
|
||||
"model": model,
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": BIAS_MESSAGE
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": message
|
||||
}
|
||||
],
|
||||
"temperature": temperature,
|
||||
"stream": false
|
||||
};
|
||||
},
|
||||
"callback": function(response) {
|
||||
if ("error" in response) {
|
||||
return ["Error: " + response.error.message];
|
||||
} else {
|
||||
return response.choices.reduce(function(a, x) {
|
||||
a.push(x.message.content);
|
||||
|
||||
return a;
|
||||
}, []);
|
||||
}
|
||||
}
|
||||
},
|
||||
"deepseek": {
|
||||
"type": "llm",
|
||||
"availableModels": [
|
||||
"deepseek-chat"
|
||||
],
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer {apikey}"
|
||||
},
|
||||
"url": "https://api.deepseek.com/chat/completions",
|
||||
"wrap": function(model, message, temperature) {
|
||||
return {
|
||||
"model": model,
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": BIAS_MESSAGE
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": message
|
||||
}
|
||||
],
|
||||
"temperature": temperature,
|
||||
"stream": false
|
||||
};
|
||||
},
|
||||
"callback": function(response) {
|
||||
if ("error" in response) {
|
||||
return ["Error: " + response.error.message];
|
||||
} else {
|
||||
return response.choices.reduce(function(a, x) {
|
||||
a.push(x.message.content);
|
||||
|
||||
return a;
|
||||
}, []);
|
||||
}
|
||||
}
|
||||
},
|
||||
"moonshot": {
|
||||
"type": "llm",
|
||||
"availableModels": [
|
||||
"moonshot-v1-8k"
|
||||
],
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer {apikey}"
|
||||
},
|
||||
"url": "https://api.moonshot.cn/v1",
|
||||
"wrap": function(model, message, temperature) {
|
||||
return {
|
||||
"model": model,
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": BIAS_MESSAGE
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": message
|
||||
}
|
||||
],
|
||||
"temperature": temperature,
|
||||
"stream": false
|
||||
};
|
||||
},
|
||||
"callback": function(response) {
|
||||
if ("error" in response) {
|
||||
return ["Error: " + response.error.message];
|
||||
} else {
|
||||
return response.choices.reduce(function(a, x) {
|
||||
a.push(x.message.content);
|
||||
|
||||
return a;
|
||||
}, []);
|
||||
}
|
||||
}
|
||||
},
|
||||
"clovastudio": {
|
||||
"type": "llm",
|
||||
"availableModels": [
|
||||
"HCX-003",
|
||||
"HCX-DASH-001"
|
||||
],
|
||||
"headers": {
|
||||
"Authorization": "Bearer {apikey}",
|
||||
"NCP-CLOVASTUDIO-REQUEST-ID": "",
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json"
|
||||
},
|
||||
"url": "https://clovastudio.stream.ntruss.com/testapp/v1/chat-completions/{model}",
|
||||
"wrap": function(model, message, temperature) {
|
||||
return {
|
||||
"topK": 0,
|
||||
"includeAiFilters": true,
|
||||
"maxTokens": 4096,
|
||||
"temperature": temperature,
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": BIAS_MESSAGE
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": message
|
||||
}
|
||||
],
|
||||
"stopBefore": [],
|
||||
"repeatPenalty": 5.0,
|
||||
"topP": 0.8
|
||||
};
|
||||
},
|
||||
"callback": function(response) {
|
||||
if (response.status.code != "20000") {
|
||||
return ["Error: " + response.status.message];
|
||||
} else {
|
||||
return [response.result.message];
|
||||
}
|
||||
}
|
||||
},
|
||||
"alibabacloud": {
|
||||
"type": "llm",
|
||||
"availableModels": [
|
||||
"qwen-plus",
|
||||
"qwen-max",
|
||||
"qwen-turbo"
|
||||
],
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer {apikey}"
|
||||
},
|
||||
"url": "https://dashscope-intl.aliyuncs.com/compatible-mode/v1/chat/completions",
|
||||
"wrap": function(model, message, temperature) {
|
||||
return {
|
||||
"model": model,
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": BIAS_MESSAGE
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": message
|
||||
}
|
||||
],
|
||||
"temperature": temperature,
|
||||
"stream": false
|
||||
};
|
||||
},
|
||||
"callback": function(response) {
|
||||
if ("error" in response) {
|
||||
return ["Error: " + response.error.message];
|
||||
} else {
|
||||
return response.choices.reduce(function(a, x) {
|
||||
a.push(x.message.content);
|
||||
|
||||
return a;
|
||||
}, []);
|
||||
}
|
||||
}
|
||||
},
|
||||
"catswords-ai": {
|
||||
"type": "llm",
|
||||
"availableModels": [
|
||||
"openchat-3.5-0106",
|
||||
"qwen1.5-14b-chat-awq",
|
||||
"gemma-7b-it",
|
||||
"una-cybertron-7b-v2-bf16",
|
||||
"starling-lm-7b-beta",
|
||||
"hermes-2-pro-mistral-7b"
|
||||
],
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer {apikey}"
|
||||
},
|
||||
"url": "https://ai.catswords.net",
|
||||
"wrap": function(model, message, temperature) {
|
||||
return {
|
||||
"model": model,
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": BIAS_MESSAGE
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": message
|
||||
}
|
||||
],
|
||||
"temperature": temperature,
|
||||
"stream": false
|
||||
};
|
||||
},
|
||||
"callback": function(response) {
|
||||
if ("error" in response) {
|
||||
return ["Error: " + response.error.message];
|
||||
} else {
|
||||
return response.choices.reduce(function(a, x) {
|
||||
a.push(x.message.content);
|
||||
|
||||
return a;
|
||||
}, []);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function LanguageInferenceEngine() {
|
||||
this.type = ""; // e.g. legacy (Legacy NLP), LLM based AI (LLM)
|
||||
this.provider = "";
|
||||
this.model = "";
|
||||
this.engineProfile = null;
|
||||
|
||||
this.setProvider = function(provider) {
|
||||
this.provider = provider;
|
||||
|
||||
if (this.provider in ENGINE_PROFILES) {
|
||||
this.engineProfile = ENGINE_PROFILES[provider];
|
||||
this.type = this.engineProfile.type;
|
||||
this.model = this.engineProfile.availableModels[0];
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
this.setModel = function(model) {
|
||||
this.model = model;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
this.setEngineProfileURL = function(url) {
|
||||
if (this.engineProfile == null)
|
||||
return this;
|
||||
|
||||
this.engineProfile.url = url;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
this.inference = function(message, temperature) {
|
||||
if (this.engineProfile == null)
|
||||
return this;
|
||||
|
||||
var apikey = CRED.get("apikey", this.provider); // Get API key
|
||||
var headers = this.engineProfile.headers;
|
||||
var wrap = this.engineProfile.wrap;
|
||||
var url = this.engineProfile.url;
|
||||
var callback = this.engineProfile.callback;
|
||||
|
||||
var response = HTTP.create("MSXML")
|
||||
.setVariables({
|
||||
"apikey": apikey
|
||||
})
|
||||
.setHeaders(headers)
|
||||
.setRequestBody(wrap(this.model, message, temperature))
|
||||
.open("post", url)
|
||||
.send()
|
||||
.responseBody;
|
||||
|
||||
return callback(response);
|
||||
};
|
||||
}
|
||||
|
||||
exports.setBiasMessage = function(biasMessage) {
|
||||
BIAS_MESSAGE = biasMessage;
|
||||
};
|
||||
|
||||
exports.LanguageInferenceEngine = LanguageInferenceEngine;
|
||||
exports.create = function() {
|
||||
return new LanguageInferenceEngine();
|
||||
};
|
||||
|
||||
exports.VERSIONINFO = "Language Inference Engine integration version 0.1.11";
|
||||
exports.AUTHOR = "abuse@catswords.net";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
71
lib/ovftool.js
Normal file
71
lib/ovftool.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
// ovftool.js
|
||||
// Namhyeon Go <abuse@catswords.net>
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
// Download OVFTool (Open Virtualization Format (OVF) Tool):
|
||||
// https://developer.broadcom.com/tools/open-virtualization-format-ovf-tool/latest
|
||||
//
|
||||
var SHELL = require("lib/shell");
|
||||
var CRED = require("lib/credentials");
|
||||
|
||||
function OVFObject() {
|
||||
this.binPath = "bin\\x64\\VMware-ovftool-4.6.3-24031167-win.x86_64\\ovftool\\ovftool.exe";
|
||||
this.hostname = "";
|
||||
this.port = 443;
|
||||
this.resourceName = "";
|
||||
|
||||
this.setBinPath = function(binPath) {
|
||||
this.binPath = binPath;
|
||||
};
|
||||
|
||||
this.setHostName = function(hostname) {
|
||||
this.hostname = hostname;
|
||||
};
|
||||
|
||||
this.setPort = function(port) {
|
||||
this.port = port;
|
||||
};
|
||||
|
||||
this.setResourceName = function(resourceName) {
|
||||
this.resourceName = resourceName;
|
||||
};
|
||||
|
||||
this.saveTo = function(filename) {
|
||||
var cred = CRED.get("password", "ovftool");
|
||||
var connectionString = "vi://" +
|
||||
encodeURIComponent(cred.username) + ":" +
|
||||
encodeURIComponent(cred.password) + "@" +
|
||||
this.hostname + (this.port == 443 ? "" : ":" + this.port) +
|
||||
this.resourceName
|
||||
;
|
||||
var cmd = [
|
||||
this.binPath,
|
||||
connectionString,
|
||||
filename
|
||||
];
|
||||
|
||||
console.log("Use this connection string:", connectionString);
|
||||
|
||||
// run the command synchronously
|
||||
SHELL.show(cmd, false);
|
||||
};
|
||||
}
|
||||
|
||||
function setCredential(username, password) {
|
||||
CRED.push("password", "ovftool", {
|
||||
"username": username,
|
||||
"password": password
|
||||
});
|
||||
}
|
||||
|
||||
function create() {
|
||||
return new OVFObject();
|
||||
}
|
||||
|
||||
exports.setCredential = setCredential;
|
||||
exports.create = create;
|
||||
|
||||
exports.VERSIONINFO = "Broadcom/VMware OVF Tool interface (ovftool.js) version 0.1.2";
|
||||
exports.AUTHOR = "abuse@catswords.net";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
|
@ -1,11 +1,48 @@
|
|||
var Py3 = require("lib/python3");
|
||||
// punycode.js
|
||||
// Namhyeon Go <abuse@catswords.net>
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
// ***SECURITY NOTICE***
|
||||
// Due to potential security issues, the Public API URL is not provided. If you need to request access, please refer to the project's contact information.
|
||||
// You can download the server-side script that implements this functionality from the link below:
|
||||
// https://github.com/gnh1201/caterpillar
|
||||
//
|
||||
var JsonRpc2 = require("lib/jsonrpc2");
|
||||
|
||||
function encode(s) {
|
||||
return Py3.execScript("app\\assets\\py\\idnaencode.py", [s]).trim();
|
||||
var rpc = JsonRpc2.create(JsonRpc2.DEFAULT_JSONRPC2_URL);
|
||||
var result = rpc.invoke("relay_invoke_method", {
|
||||
"callback": "load_script",
|
||||
"requires": [
|
||||
"https://scriptas.catswords.net/punycode.class.php"
|
||||
],
|
||||
"args": [
|
||||
"return Punycode::encodeHostname('" + s + "')"
|
||||
]
|
||||
}, "");
|
||||
|
||||
return result.data;
|
||||
}
|
||||
|
||||
function decode(s) {
|
||||
var rpc = JsonRpc2.create(JsonRpc2.DEFAULT_JSONRPC2_URL);
|
||||
var result = rpc.invoke("relay_invoke_method", {
|
||||
"callback": "load_script",
|
||||
"requires": [
|
||||
"https://scriptas.catswords.net/punycode.class.php"
|
||||
],
|
||||
"args": [
|
||||
"return Punycode::decodeHostname('" + s + "')"
|
||||
]
|
||||
}, "");
|
||||
|
||||
return result.data;
|
||||
}
|
||||
|
||||
exports.encode = encode;
|
||||
exports.decode = decode;
|
||||
|
||||
exports.VERSIONINFO = "Punycode Converter (punycode.js) version 0.1";
|
||||
exports.VERSIONINFO = "Punycode Conversion Client (punycode.js) version 0.2.4";
|
||||
exports.AUTHOR = "abuse@catswords.net";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
||||
|
|
|
@ -1,23 +1,44 @@
|
|||
// python3.js
|
||||
// Python Interface
|
||||
// Namhyeon Go (Catswords Research) <abuse@catswords.net>
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
var SYS = require("lib/system");
|
||||
var SHELL = require("lib/shell");
|
||||
|
||||
function PythonObject(platform) {
|
||||
this.version = "3.10.2-embed";
|
||||
this.platform = platform;
|
||||
function PythonObject() {
|
||||
this.binPath = null;
|
||||
this.version = "3.13.2";
|
||||
|
||||
this.create = function() {
|
||||
var arch = SYS.getArch();
|
||||
if (arch.toLowerCase().indexOf("arm") > -1) {
|
||||
this.setBinPath("bin\\arm64\\python-" + this.version + "-embed-arm64\\python.exe");
|
||||
} else if (arch.indexOf("64") > -1) {
|
||||
this.setBinPath("bin\\x64\\python-" + this.version + "-embed-amd64\\python.exe");
|
||||
} else {
|
||||
this.setBinPath("bin\\x86\\python-" + this.version + "-embed-win32\\python.exe");
|
||||
}
|
||||
};
|
||||
|
||||
this.setBinPath = function(binPath) {
|
||||
this.binPath = binPath;
|
||||
};
|
||||
|
||||
this.setVersion = function(version) {
|
||||
this.version = version;
|
||||
this.create();
|
||||
};
|
||||
|
||||
this.execScript = function(scriptName, args) {
|
||||
return SHELL.exec([
|
||||
"bin\\python-" + this.version + "\\" + this.platform + "\\python",
|
||||
this.binPath,
|
||||
scriptName
|
||||
].concat(args));
|
||||
};
|
||||
|
||||
this.runScript = function(scriptName, args) {
|
||||
return SHELL.show([
|
||||
"bin\\python-" + this.version + "\\" + this.platform + "\\python",
|
||||
this.binPath,
|
||||
scriptName
|
||||
].concat(args));
|
||||
};
|
||||
|
@ -25,15 +46,14 @@ function PythonObject(platform) {
|
|||
|
||||
exports.PythonObject = PythonObject;
|
||||
|
||||
exports.create = function(platform) {
|
||||
var platform = (typeof platform !== "undefined" ? platform : "amd64");
|
||||
return new PythonObject(platform);
|
||||
exports.create = function() {
|
||||
return new PythonObject();
|
||||
};
|
||||
|
||||
exports.execScript = function(scriptName, args) {
|
||||
return (new PythonObject()).execScript(scriptName, args);
|
||||
};
|
||||
|
||||
exports.VERSIONINFO = "Python Interface (python3.js) version 0.2";
|
||||
exports.VERSIONINFO = "Python Interface (python3.js) version 0.2.1";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
// router.js
|
||||
// Content-Type based URI router for WelsonJS framework
|
||||
// Namhyeon Go <abuse@catswords.net>
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
//
|
||||
function RouteModel(path, callback) {
|
||||
this.path = path;
|
||||
this.callback = callback;
|
||||
|
@ -8,32 +10,84 @@ function RouteModel(path, callback) {
|
|||
|
||||
function RouterObject() {
|
||||
var routes = [];
|
||||
var renders = [];
|
||||
|
||||
this.render = function(filename, data) {};
|
||||
this.setRender = function(render) {
|
||||
this.render = render;
|
||||
this.setRender = function(callback, contentType) {
|
||||
var contentType = (typeof contentType !== "undefined" ?
|
||||
contentType : ""
|
||||
);
|
||||
|
||||
renders.push({
|
||||
"contentType": contentType,
|
||||
"callback": callback
|
||||
});
|
||||
};
|
||||
|
||||
this.render = function(uri, data) {
|
||||
// Use expression: data:application/json,%7B%22key%22%3A%22value%22%7D
|
||||
// Use expression: data:text/html,%3Ch1%3EHello%3C%2Fh1%3E
|
||||
// Use expression: /path/to/file.html
|
||||
var contents = (function(uri, start, end) {
|
||||
if (start > -1 && end > start) {
|
||||
return [uri.substring(start, end), uri.substring(end + 1)];
|
||||
}
|
||||
|
||||
return ["", uri];
|
||||
})(uri, uri.indexOf("data:"), uri.indexOf(','));
|
||||
|
||||
var contentType = contents[0];
|
||||
var rawData = (contentType != "" ?
|
||||
decodeURIComponent(contents[1]) : contents[1]
|
||||
);
|
||||
|
||||
// Multiple renderers are allowed for the same content type. They are executed in the order they were registered.
|
||||
renders.forEach(function(x) {
|
||||
if (x.contentType == contentType) {
|
||||
try {
|
||||
if (typeof x.callback === "function") {
|
||||
x.callback(rawData, data);
|
||||
} else {
|
||||
console.warn("Failed to render content of type " + x.contentType, "Not a function");
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Failed to render content of type " + x.contentType, e.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.add = function(path, callback) {
|
||||
routes.push(new RouteModel(path, callback));
|
||||
};
|
||||
this.go = function(path) {
|
||||
|
||||
this.go = function(uri) {
|
||||
var path = uri.split(/[?#]/)[0];
|
||||
|
||||
var model = routes.find(function(x) {
|
||||
return (x.path == path);
|
||||
return path === x.path || path.indexOf(x.path + "/") === 0;
|
||||
});
|
||||
|
||||
if (typeof model !== "undefined") {
|
||||
//try {
|
||||
model.callback(this.render);
|
||||
//} catch (e) {
|
||||
// console.error(path, e.message);
|
||||
//}
|
||||
if (!model) {
|
||||
console.error("No matching route found for:", uri);
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof model.callback !== "function") {
|
||||
console.error("Invalid callback for route:", model.path);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
model.callback(this.render);
|
||||
} catch (e) {
|
||||
console.error("Error executing callback for route:", model.path, e.message);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
exports.Router = new RouterObject();
|
||||
|
||||
exports.VERSIONINFO = "URI Router (router.js) version 0.1.1";
|
||||
exports.VERSIONINFO = "Content-Type based URI router (router.js) version 0.1.2";
|
||||
exports.AUTHOR = "abuse@catswords.net";
|
||||
exports.global = global;
|
||||
exports.require = global.require;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user