Compare commits
479 Commits
Author | SHA1 | Date | |
---|---|---|---|
0ccddd4e75 | |||
5087359ac3 | |||
1ab70d7cd7 | |||
0438ee9a50 | |||
0ad978bb6b | |||
a001471451 | |||
5f10d50a3c | |||
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 | |||
53bc51a3af | |||
f95b769f11 | |||
5d8e195635 | |||
a60d0649c0 | |||
377d2bdd71 | |||
64fec9583d | |||
9b6637a697 | |||
af096d38b8 | |||
7eb960c711 | |||
a98c1cbc92 | |||
53970f97a1 | |||
9193df71b7 | |||
d180a01312 | |||
7f13b67f70 | |||
c9360c6651 | |||
489e10b76e | |||
28be18de01 | |||
c03a8011c2 | |||
06731f4d4b | |||
44de5bfd1a | |||
a00d43a59e | |||
9783e55069 | |||
3b101e177e | |||
08b10b4e4a | |||
65d5ee120b | |||
2fc9b11aa6 | |||
feb85625c5 | |||
e1d4df74b9 | |||
6eaeab5c24 | |||
b93c6cd48b | |||
94afeb406a | |||
9e623b645f | |||
4f92b782e9 | |||
16427b347f | |||
ea6add25ca | |||
89e3704f33 | |||
736356fe71 | |||
89dc45ac7c | |||
c3d4250094 | |||
5357ec167a | |||
7824de743f | |||
adce996aae | |||
2e334ec12e | |||
641c2070a4 | |||
86916d2ed9 | |||
c157116680 | |||
1a8c93627a | |||
ee5f503e42 | |||
c4c7d5480b | |||
06cb5095b2 | |||
f9ddd3b95e |
|
@ -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
|
@ -0,0 +1,2 @@
|
|||
github: gnh1201
|
||||
custom: ['https://gnh1201.link']
|
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
|
@ -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
|
@ -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
|
235
README.md
|
@ -2,101 +2,83 @@
|
|||
|
||||
[](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://doi.org/10.5281/zenodo.11382384)
|
||||
[](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
|
||||
- <img src="app/assets/img/github_octocat_logo.png" height="32" alt=""/> [GitHub Sponsors](https://github.com/sponsors/gnh1201)
|
||||
- <img src="app/assets/img/logo_oss.gif" height="32" alt=""/> Open Software Portal, Korea National Industry Promotion Agency - Awarded Prize
|
||||
- <img src="app/assets/img/signpath_logo.png" height="32" alt=""/> Free code signing provided by [SignPath.io](https://signpath.io), certificate by [SignPath Foundation](https://signpath.org/)
|
||||
* :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)...)
|
||||
|
||||
## [Partnerships](https://github.com/gnh1201/welsonjs/wiki/Partnerships)
|
||||
- [<img src="app/assets/img/scrapeops-logo.svg" height="32" alt=""/> ScrapeOps (scrapeops.io)](https://scrapeops.io?fpr=namhyeon75) - Proxy Aggregator (1,000 free calls/month, [10% discount coupon](https://github.com/gnh1201/welsonjs/wiki/Partnerships))
|
||||
- [<img src="app/assets/img/searchapi-logo.svg" height="32" alt="SearchApi"/> (searchapi.io)](https://www.searchapi.io/?via=namhyeon) - SERP (Google, Bing, Baidu, Amazon, YouTube, App Store (Google, Apple), etc.) scraping (100 free calls/month)
|
||||
## 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
|
||||
- [Includes binaries](https://github.com/gnh1201/welsonjs/blob/master/bin/README.MD)
|
||||
- [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), and [Web Proxy API](https://scrapeops.io?fpr=namhyeon75))
|
||||
- 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://github.com/gnh1201/welsonjs/wiki/Awesome-binaries) (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)
|
||||
- [WelsonJS.Service](https://github.com/gnh1201/welsonjs/wiki/Awesome-binaries) (Windows Service Application, For recent Windows based systems)
|
||||
- Write a Windows Service Application with JavaScript
|
||||
- [File Event Monitor](https://github.com/gnh1201/welsonjs/wiki/File-Event-Monitor): Trace file creation, network connections, and registry modifications.
|
||||
- [Screen Time Feature](https://github.com/gnh1201/welsonjs/wiki/Screen-Time-Feature): Find an image position on the computer screens or windows.
|
||||
- [WelsonJS.Launcher](https://github.com/gnh1201/welsonjs/wiki/Launcher) (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
|
||||
|
@ -107,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;
|
||||
```
|
||||
|
@ -127,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()
|
||||
|
@ -138,55 +120,62 @@ 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://github.com/gnh1201/welsonjs/wiki/Launcher).
|
||||
- **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
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||
|
||||
## Thanks to
|
||||
- Heavy-industry specialized CSP(Cloud Service Provider) in Republic of Korea - Use case establishment
|
||||
- Live-commerce specialized online advertisement companies in Republic of Korea - Use case establishment
|
||||
- Information security companies in Republic of Korea - Use case establishment
|
||||
- <img src="app/assets/img/morioh.svg" height="32" alt=""/> morioh.com - Mentioned
|
||||
- <img src="app/assets/img/CSDN_Logo.svg" height="32" alt=""/> CSDN - Mentioned
|
||||
- <img src="app/assets/img/qiita-logo.png" height="32" alt=""/> Qiita - Knowledge-base about WSH environment
|
||||
- <img src="app/assets/img/RedSky-logo-web.webp" height="32" alt=""/> Redsky Software - PoC(Proof of Concept) of the CommonJS on WSH environment
|
||||
- Inspired by a small-sized JavaScript payload demonstrated by a cybersecurity related group.
|
||||
- Inspired by the use of Named Shared Memory in an inter-language IPC implementation devised by an unidentified developer.
|
||||
- <img src="app/assets/img/Fediverse_logo_proposal.svg" height="32" alt=""/> Fediverse - Mentioned
|
||||
- <img src="app/assets/img/Hackernews_logo.png" height="32" alt=""/> Hacker News - Mentioned
|
||||
|
||||
## 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)
|
||||
* :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 [gnh1201@xmpp.catswords.net](https://policy.catswords.social/xmpp.html)
|
||||
- [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)
|
||||
|
|
46
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,15 +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)
|
||||
- [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.
|
||||
|
|
261
WelsonJS.Toolkit/WelsonJS.Launcher/EnvForm.Designer.cs
generated
Normal file
|
@ -0,0 +1,261 @@
|
|||
namespace WelsonJS.Launcher
|
||||
{
|
||||
partial class EnvForm
|
||||
{
|
||||
/// <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.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.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();
|
||||
this.btnOpenDirectory = new System.Windows.Forms.Button();
|
||||
this.textSetValue = new System.Windows.Forms.TextBox();
|
||||
this.textSetName = new System.Windows.Forms.TextBox();
|
||||
this.labelSetValue = new System.Windows.Forms.Label();
|
||||
this.labelSetName = new System.Windows.Forms.Label();
|
||||
this.gbImportAndExport = new System.Windows.Forms.GroupBox();
|
||||
this.btnExport = new System.Windows.Forms.Button();
|
||||
this.btnImport = new System.Windows.Forms.Button();
|
||||
this.gbUserDefinedVariables.SuspendLayout();
|
||||
this.gbUpdateUserDefinedVariable.SuspendLayout();
|
||||
this.gbImportAndExport.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// gbUserDefinedVariables
|
||||
//
|
||||
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";
|
||||
//
|
||||
// lvUserDefinedVariables
|
||||
//
|
||||
this.lvUserDefinedVariables.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
|
||||
this.columnHeader1,
|
||||
this.columnHeader2});
|
||||
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
|
||||
//
|
||||
this.columnHeader1.Text = "Name";
|
||||
//
|
||||
// columnHeader2
|
||||
//
|
||||
this.columnHeader2.Text = "Value";
|
||||
//
|
||||
// gbUpdateUserDefinedVariable
|
||||
//
|
||||
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
|
||||
//
|
||||
this.checkDeleteVariable.AutoSize = true;
|
||||
this.checkDeleteVariable.Location = new System.Drawing.Point(31, 88);
|
||||
this.checkDeleteVariable.Name = "checkDeleteVariable";
|
||||
this.checkDeleteVariable.Size = new System.Drawing.Size(131, 16);
|
||||
this.checkDeleteVariable.TabIndex = 7;
|
||||
this.checkDeleteVariable.Text = "Delete this variable";
|
||||
this.checkDeleteVariable.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// btnOk
|
||||
//
|
||||
this.btnOk.Image = global::WelsonJS.Launcher.Properties.Resources.icon_check_32;
|
||||
this.btnOk.Location = new System.Drawing.Point(303, 123);
|
||||
this.btnOk.Name = "btnOk";
|
||||
this.btnOk.Size = new System.Drawing.Size(86, 86);
|
||||
this.btnOk.TabIndex = 6;
|
||||
this.btnOk.Text = "Ok";
|
||||
this.btnOk.TextAlign = System.Drawing.ContentAlignment.BottomCenter;
|
||||
this.btnOk.UseVisualStyleBackColor = true;
|
||||
this.btnOk.Click += new System.EventHandler(this.btnOk_Click);
|
||||
//
|
||||
// btnOpenFile
|
||||
//
|
||||
this.btnOpenFile.Image = global::WelsonJS.Launcher.Properties.Resources.icon_file_32;
|
||||
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);
|
||||
//
|
||||
// btnOpenDirectory
|
||||
//
|
||||
this.btnOpenDirectory.Image = global::WelsonJS.Launcher.Properties.Resources.icon_directory_32;
|
||||
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);
|
||||
//
|
||||
// textSetValue
|
||||
//
|
||||
this.textSetValue.Location = new System.Drawing.Point(98, 55);
|
||||
this.textSetValue.Name = "textSetValue";
|
||||
this.textSetValue.Size = new System.Drawing.Size(291, 21);
|
||||
this.textSetValue.TabIndex = 3;
|
||||
//
|
||||
// textSetName
|
||||
//
|
||||
this.textSetName.Location = new System.Drawing.Point(98, 28);
|
||||
this.textSetName.Name = "textSetName";
|
||||
this.textSetName.Size = new System.Drawing.Size(291, 21);
|
||||
this.textSetName.TabIndex = 2;
|
||||
//
|
||||
// labelSetValue
|
||||
//
|
||||
this.labelSetValue.AutoSize = true;
|
||||
this.labelSetValue.Location = new System.Drawing.Point(29, 59);
|
||||
this.labelSetValue.Name = "labelSetValue";
|
||||
this.labelSetValue.Size = new System.Drawing.Size(61, 12);
|
||||
this.labelSetValue.TabIndex = 1;
|
||||
this.labelSetValue.Text = "Set value:";
|
||||
//
|
||||
// labelSetName
|
||||
//
|
||||
this.labelSetName.AutoSize = true;
|
||||
this.labelSetName.Location = new System.Drawing.Point(29, 31);
|
||||
this.labelSetName.Name = "labelSetName";
|
||||
this.labelSetName.Size = new System.Drawing.Size(63, 12);
|
||||
this.labelSetName.TabIndex = 0;
|
||||
this.labelSetName.Text = "Set name:";
|
||||
//
|
||||
// gbImportAndExport
|
||||
//
|
||||
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
|
||||
//
|
||||
this.btnExport.Image = global::WelsonJS.Launcher.Properties.Resources.icon_export_32;
|
||||
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";
|
||||
this.btnExport.UseVisualStyleBackColor = true;
|
||||
this.btnExport.Click += new System.EventHandler(this.btnExport_Click);
|
||||
//
|
||||
// btnImport
|
||||
//
|
||||
this.btnImport.Image = global::WelsonJS.Launcher.Properties.Resources.icon_import_32;
|
||||
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";
|
||||
this.btnImport.UseVisualStyleBackColor = true;
|
||||
this.btnImport.Click += new System.EventHandler(this.btnImport_Click);
|
||||
//
|
||||
// EnvForm
|
||||
//
|
||||
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.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.gbUserDefinedVariables.ResumeLayout(false);
|
||||
this.gbUpdateUserDefinedVariable.ResumeLayout(false);
|
||||
this.gbUpdateUserDefinedVariable.PerformLayout();
|
||||
this.gbImportAndExport.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
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;
|
||||
private System.Windows.Forms.Label labelSetName;
|
||||
private System.Windows.Forms.Button btnOk;
|
||||
private System.Windows.Forms.Button btnOpenFile;
|
||||
private System.Windows.Forms.Button btnOpenDirectory;
|
||||
private System.Windows.Forms.CheckBox checkDeleteVariable;
|
||||
private System.Windows.Forms.ListView lvUserDefinedVariables;
|
||||
private System.Windows.Forms.ColumnHeader columnHeader1;
|
||||
private System.Windows.Forms.ColumnHeader columnHeader2;
|
||||
private System.Windows.Forms.GroupBox gbImportAndExport;
|
||||
private System.Windows.Forms.Button btnImport;
|
||||
private System.Windows.Forms.Button btnExport;
|
||||
}
|
||||
}
|
295
WelsonJS.Toolkit/WelsonJS.Launcher/EnvForm.cs
Normal file
|
@ -0,0 +1,295 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace WelsonJS.Launcher
|
||||
{
|
||||
public partial class EnvForm : Form
|
||||
{
|
||||
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
|
||||
tempFilePath = Path.Combine(Program.GetAppDataPath(), "welsonjs_default.env");
|
||||
|
||||
LoadUserVariables(); // Load variables
|
||||
}
|
||||
|
||||
// Initialize ListView
|
||||
private void InitializeListView()
|
||||
{
|
||||
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
|
||||
private void LoadUserVariables()
|
||||
{
|
||||
if (File.Exists(tempFilePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
string fileContent = File.ReadAllText(tempFilePath);
|
||||
// Split based on new line characters
|
||||
string[] keyValuePairs = fileContent.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
userVariables = new Dictionary<string, string>();
|
||||
|
||||
foreach (string pair in keyValuePairs)
|
||||
{
|
||||
// Split by the first occurrence of '='
|
||||
int indexOfEquals = pair.IndexOf('=');
|
||||
if (indexOfEquals != -1)
|
||||
{
|
||||
string key = pair.Substring(0, indexOfEquals).Trim();
|
||||
string value = pair.Substring(indexOfEquals + 1).Trim();
|
||||
|
||||
// Remove surrounding quotes if present
|
||||
if (value.StartsWith("\"") && value.EndsWith("\""))
|
||||
{
|
||||
value = value.Substring(1, value.Length - 2); // Remove the first and last character
|
||||
}
|
||||
|
||||
// Unescape double quotes in the value
|
||||
value = value.Replace("\\\"", "\"");
|
||||
|
||||
userVariables[key] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show($"Error parsing line: '{pair}'.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"Error loading variable file: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
userVariables = new Dictionary<string, string>();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
userVariables = new Dictionary<string, string>();
|
||||
}
|
||||
UpdateListView();
|
||||
}
|
||||
|
||||
// Update ListView with current variables
|
||||
private void UpdateListView()
|
||||
{
|
||||
lvUserDefinedVariables.Items.Clear();
|
||||
foreach (var variable in userVariables)
|
||||
{
|
||||
var item = new ListViewItem(variable.Key);
|
||||
item.SubItems.Add(variable.Value);
|
||||
lvUserDefinedVariables.Items.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle ListView selection change
|
||||
private void lvUserDefinedVariables_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (lvUserDefinedVariables.SelectedItems.Count > 0)
|
||||
{
|
||||
var selectedItem = lvUserDefinedVariables.SelectedItems[0];
|
||||
textSetName.Text = selectedItem.Text;
|
||||
textSetValue.Text = selectedItem.SubItems[1].Text;
|
||||
checkDeleteVariable.Checked = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle OK button click
|
||||
private void btnOk_Click(object sender, EventArgs e)
|
||||
{
|
||||
var name = textSetName.Text.Trim();
|
||||
var value = textSetValue.Text.Trim();
|
||||
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
MessageBox.Show("Please enter a variable name.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (checkDeleteVariable.Checked)
|
||||
{
|
||||
if (userVariables.ContainsKey(name))
|
||||
{
|
||||
userVariables.Remove(name);
|
||||
MessageBox.Show("Variable deleted.", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("Variable not found.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
userVariables[name] = value;
|
||||
MessageBox.Show("Variable saved.", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
|
||||
UpdateListView();
|
||||
SaveUserVariables(); // Save variables
|
||||
ClearInputFields();
|
||||
}
|
||||
|
||||
// Save user-defined variables to the temporary folder in .env format
|
||||
private void SaveUserVariables()
|
||||
{
|
||||
try
|
||||
{
|
||||
List<string> lines = new List<string>();
|
||||
|
||||
foreach (var variable in userVariables)
|
||||
{
|
||||
// Escape double quotes in the value
|
||||
string value = variable.Value.Replace("\"", "\\\"");
|
||||
|
||||
// Enclose the value in double quotes if it contains spaces
|
||||
if (value.Contains(" "))
|
||||
{
|
||||
value = $"\"{value}\"";
|
||||
}
|
||||
|
||||
// Create the line in the format: KEY=VALUE
|
||||
string line = $"{variable.Key}={value}";
|
||||
lines.Add(line);
|
||||
}
|
||||
|
||||
// Write lines to the file
|
||||
File.WriteAllLines(tempFilePath, lines, defaultEncoding);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"Error saving variable file: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear input fields
|
||||
private void ClearInputFields()
|
||||
{
|
||||
textSetName.Clear();
|
||||
textSetValue.Clear();
|
||||
checkDeleteVariable.Checked = false;
|
||||
}
|
||||
|
||||
// Handle "Open Directory" button click
|
||||
private void btnOpenDirectory_Click(object sender, EventArgs e)
|
||||
{
|
||||
using (var folderDialog = new FolderBrowserDialog())
|
||||
{
|
||||
if (folderDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
textSetValue.Text = folderDialog.SelectedPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle "Open File" button click
|
||||
private void btnOpenFile_Click(object sender, EventArgs e)
|
||||
{
|
||||
using (var fileDialog = new OpenFileDialog())
|
||||
{
|
||||
if (fileDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
textSetName.Text = Path.GetFileName(fileDialog.FileName);
|
||||
textSetValue.Text = fileDialog.FileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void btnImport_Click(object sender, EventArgs e)
|
||||
{
|
||||
using (var openFileDialog = new OpenFileDialog())
|
||||
{
|
||||
openFileDialog.Filter = "Env files (*.env)|*.env|All files (*.*)|*.*";
|
||||
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Load variables from the selected file
|
||||
string filePath = openFileDialog.FileName;
|
||||
string[] lines = File.ReadAllLines(filePath, defaultEncoding);
|
||||
|
||||
foreach (string line in lines)
|
||||
{
|
||||
// Skip empty lines
|
||||
if (string.IsNullOrWhiteSpace(line)) continue;
|
||||
|
||||
int indexOfEquals = line.IndexOf('=');
|
||||
if (indexOfEquals != -1)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void btnExport_Click(object sender, EventArgs e)
|
||||
{
|
||||
SaveFileDialog saveFileDialog = new SaveFileDialog();
|
||||
saveFileDialog.Filter = "Env files (*.env)|*.env|All files (*.*)|*.*";
|
||||
if (saveFileDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Save the current variables to the selected file
|
||||
string filePath = saveFileDialog.FileName;
|
||||
List<string> lines = new List<string>();
|
||||
foreach (var variable in userVariables)
|
||||
{
|
||||
// Escape double quotes in the value
|
||||
string value = variable.Value.Replace("\"", "\\\"");
|
||||
|
||||
// Enclose the value in double quotes if it contains spaces
|
||||
if (value.Contains(" "))
|
||||
{
|
||||
value = $"\"{value}\"";
|
||||
}
|
||||
|
||||
lines.Add($"{variable.Key}={value}");
|
||||
}
|
||||
File.WriteAllLines(filePath, lines, defaultEncoding);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"Error exporting variable file: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
120
WelsonJS.Toolkit/WelsonJS.Launcher/EnvForm.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>
|
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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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>
|
260
WelsonJS.Toolkit/WelsonJS.Launcher/MainForm.Designer.cs
generated
|
@ -28,44 +28,59 @@
|
|||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
|
||||
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, 49);
|
||||
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, 49);
|
||||
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
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Location = new System.Drawing.Point(24, 23);
|
||||
this.label1.Location = new System.Drawing.Point(24, 41);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(312, 12);
|
||||
this.label1.TabIndex = 2;
|
||||
|
@ -74,7 +89,7 @@
|
|||
// linkLabel1
|
||||
//
|
||||
this.linkLabel1.AutoSize = true;
|
||||
this.linkLabel1.Location = new System.Drawing.Point(24, 327);
|
||||
this.linkLabel1.Location = new System.Drawing.Point(24, 345);
|
||||
this.linkLabel1.Name = "linkLabel1";
|
||||
this.linkLabel1.Size = new System.Drawing.Size(219, 12);
|
||||
this.linkLabel1.TabIndex = 3;
|
||||
|
@ -82,52 +97,156 @@
|
|||
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, 263);
|
||||
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, 260);
|
||||
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, 287);
|
||||
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
|
||||
//
|
||||
this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.settingsToolStripMenuItem});
|
||||
this.menuStrip1.Location = new System.Drawing.Point(0, 0);
|
||||
this.menuStrip1.Name = "menuStrip1";
|
||||
this.menuStrip1.Size = new System.Drawing.Size(461, 24);
|
||||
this.menuStrip1.TabIndex = 7;
|
||||
this.menuStrip1.Text = "menuStrip1";
|
||||
//
|
||||
// settingsToolStripMenuItem
|
||||
//
|
||||
this.settingsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
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";
|
||||
//
|
||||
// userdefinedVariablesToolStripMenuItem
|
||||
//
|
||||
this.userdefinedVariablesToolStripMenuItem.Name = "userdefinedVariablesToolStripMenuItem";
|
||||
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, 362);
|
||||
this.Controls.Add(this.checkBox2);
|
||||
this.Controls.Add(this.textBox1);
|
||||
this.Controls.Add(this.checkBox1);
|
||||
this.ClientSize = new System.Drawing.Size(461, 382);
|
||||
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 = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
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();
|
||||
|
||||
|
@ -135,13 +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,111 +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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,968 +117,13 @@
|
|||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>
|
||||
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
|
||||
BJ3QP5V6EB3RJ1cv9SACEG93YGClTxAAVyCAISCAMPQJAuAKBDAEBBCGPkEAXIEAhoAAwtAnCIArEMAQ
|
||||
EEAY+gQBcAUCGAICCEOfIACuQABDQABh6BMEwBUIYAgIIAx9ggC4AgEMAQGEoU8QAFcggCEggDD0CQLg
|
||||
CgQwBAQQhj5BAFyBAIaAAMLQJwiAKxDAEBBAGPSyXt9IPYgAaAEspB5ERy6pHxnt12Z8h8i6kvIhIAAA
|
||||
CgYCAKBgIAAACgYCAKBgIAAACgYCAKBgIAAACgYCAKBgIAAACgYCAKBgIAAACgYCAKBgIAAACgYCAKBg
|
||||
IAAACgYCAKBgIAAACgYCAKBgIAAACgYCAKBgIAAACgYCAKBgIAAACgYCAKBgIAAACgYCAKBgIAAACgYC
|
||||
AKBgIAAACgYCAKBgIAAACgYCAKBg/h+1RmVpkPBkawAAAABJRU5ErkJggigAAABAAAAAgAAAAAEAIAAA
|
||||
AAAAAEIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAA
|
||||
AADvAAAA7wAAAO8AAADvAAAA7wAAAO8AAADvAAAA7wAAAO8AAADvAAAA7wAAAO8AAADvAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3wAAAO8AAADvAAAA7wAAAO8A
|
||||
AADvAAAA7wAAAO8AAADvAAAA7wAAAO8AAADvAAAA7wAAAJ8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAACPAAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8A
|
||||
AAD/AAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO8A
|
||||
AAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAACfAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjwAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8A
|
||||
AAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAADvAAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8A
|
||||
AAD/AAAAnwAAAAAAAAAAAAAAAAAw/2AAMP9wADD/cAAw/3AAMP9wADD/cAAw/3AAMP9wADD/cAAw/3AA
|
||||
MP9gAAAAAAAAAAAAvUVgAL1HcAC9R3AAvUdwAL1HcAA5FbcAORW3ADkVtwAYCdsAAAD/AAAA/wQCAPNO
|
||||
LgC3Ti4At04uALdOLgC3Ti4At04uALclFgDNAAAA/wAAAP8AAAD/ADlOtwA5TrcAOU63AHuniwC9/3AA
|
||||
u/9AAAAAAAAAAAAAAAAwAAAAgAAAAIAAAACAAAAA7wAAAP8AAAD/AAAArwAAAIAAAACAAAAAgAAAAIAA
|
||||
AACAAAAAgAAAAN8AAAD/AAAA/wAAAM8AAACAAAAAgAAAAIAAMP+AADH//wAx//8AMf//ADH//wAx//8A
|
||||
Mf//ADH//wAx//8AMf//ADH//wAw/1AAAAAAALtGgAC9Rv8AvUb/AL1G/wC9Rv8ADAT/AAAA/wAAAP8A
|
||||
AAD/AAAA/wAAAP8RCgDe/5YA//+WAP//lgD//5YA//+WAP//lgD/n14A/wAAAP8AAAD/AAAA/wAAAP8A
|
||||
AAD/AAAA/wB2n/8Avf//AL7/zwAAAAAAAAAAAAAAYAAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAHAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/ADD/IAAx/+8A
|
||||
Mf//ADH//wAx//8AMf//ADH//wAx//8AMf//ADH//wAx//8AMf+/AAAAAAC/QBAAvUbvAL1G/wC9Rv8A
|
||||
vUb/AAwE/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAAz/+WAM//lgD//5YA//+WAP//lgD//5YA/59eAP8A
|
||||
AAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8Adp//AL3//wC9//8AvP9QAAAAAAAAAGAAAAD/AAAA/wAAAP8A
|
||||
AAD/AAAA/wAAAP8AAABwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAvwAAAP8AAAD/AAAA/wAAAP8A
|
||||
AAD/AAAA/wAAAAAAMv+PADH//wAx//8AMf//ADH//wAx//8AMf//ADH//wAx//8AMf//ADH//wAw/0AA
|
||||
AAAAALtGgAC9Rv8AvUb/AL1G/wAMBP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAM//lQBg/5YA//+WAP//
|
||||
lgD//5YA//+WAP+fXgD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AHaf/wC9//8Avf//AL3/rwAAAAAA
|
||||
AABgAAAA3wAAAN8AAADfAAAA3wAAAN8AAADfAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL8A
|
||||
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
|
||||
MP9AAAAAAAC7RoAAvUb/AL1G/wC9Rv8AvUb/AL1G/wC9Rv8AvUb/AL1G/wBBGJIAAAD/AAAA/wAAAP8A
|
||||
AAD/AAAA/wAAAP+fXgD//5YA//+WAP//lQAwAAAAAABbe7kAAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8A
|
||||
AABwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAACAAAAAgAAAAIAAAACAAAAAgAAAAIAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw/0AAMf//ADH//wAx//8AMf//ADH//wAx//8A
|
||||
Mf//ADH//wAx//8AMf//ADL/rwAAAAAAv0ggAL1G7wC9Rv8AvUb/AL1G/wC9Rv8AvUb/AL1G/wC9Rv8A
|
||||
aifXAAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/n14A//+WAP//lgD//5cAnwAAAAAAISx0AAAA/wAAAP8A
|
||||
AAD/AAAA/wAAAP8AAAD/ACUyiwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL8AAAD/AAAA/wAAAP8A
|
||||
AAD/AAAA/wAAAP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADH/vwAx//8A
|
||||
Mf//ADH//wAx//8AMf//ADH//wAx//8AMf//ADH//wAx/+8AMP8wAAAAAAC9R58AvUb/AL1G/wC9Rv8A
|
||||
vUb/AL1G/wC9Rv8AvUb/AHYs/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/59eAP//lgD//5YA//+WAO//
|
||||
lwAgAAAAYAAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wBZd9IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAC/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAw/1AAMf//ADH//wAx//8AMf//ADH//wAx//8AMf//ADH//wAx//8AMf//ADL/jwAAAAAA
|
||||
ukUwAL1G/wC9Rv8AvUb/AL1G/wC9Rv8AvUb/AL1G/wB2LP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP+f
|
||||
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
|
||||
AAAAAAAAAAAAAAAAMP8QADH/7wAx//8AMf//ADH//wAx//8AMf//ADH//wAx//8AMf//ADH//wAx/88A
|
||||
AAAAAL9AEAC9Rt8AvUb/AL1G/wC9Rv8AvUb/AL1G/wC9Rv8AvUb/AL1G7wC/QBAAAAAA/5YAv/+WAP//
|
||||
lgD//5YA//+WAP//lgD//5YA//+WAM8AAAAAAL//EAC9/98Avf//AL3//wC9//8Avf//AL3//wC9/2AA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw/4AAMf//ADH//wAx//8AMf//ADH//wAx//8A
|
||||
Mf//ADH//wAx//8AMf//ADD/UAAAAAAAu0aAAL1G/wC9Rv8AvUb/AL1G/wC9Rv8AvUb/AL1G/wC9Rv8A
|
||||
u0aAAAAAAP+WAFD/lgD//5YA//+WAP//lgD//5YA//+WAP//lgD//5YAUAAAAAAAu/+AAL3//wC9//8A
|
||||
vf//AL3//wC9//8Avv/PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMP8QADH/7wAx//8A
|
||||
Mf//ADH//wAx//8AMf//ADH//wAx//8AMf//ADH//wAx/78AAAAAAL9AEAC9Ru8AvUb/AL1G/wC9Rv8A
|
||||
vUb/AL1G/wC9Rv8AvUb/AL1G3wC/QBAAAAAA/5YAz/+WAP//lgD//5YA//+WAP//lgD//5YA//+WAL8A
|
||||
AAAAAL//EAC9/+8Avf//AL3//wC9//8Avf//AL3//wC8/1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAw/4AAMf//ADH//wAx//8AMf//ADH//wAx//8AMf//ADH//wAx//8AMf//ADD/QAAAAAAA
|
||||
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
|
||||
AAAAADD/EAAx/98AMf//ADH//wAx//8AMf//ADH//wAx//8AMf//ADH//wAx//8AMf/fADD/EAAAAAAA
|
||||
vkW/AL1G/wC9Rv8AvUb/AL1G/wC9Rv8AvUb/AL1G/wC9Ru8Av0ggAAAAAP+WAK//lgD//5YA//+WAP//
|
||||
lgD//5YA//+WAP//lgDf/48AEAAAAAAAvv/PAL3//wC9//8Avf//AL3//wC9//8Au/+AAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMP+AADH/3wAx/98AMf/fADH/3wAx/98AMf/fADH/3wAx/98A
|
||||
Mf/fADH/3wAw/1AAAAAAALxGUAC9Rt8AvUbfAL1G3wC9Rt8AvUbfAL1G3wC9Rt8AvUbfAL1FYAAAAAD/
|
||||
kwBA/5YA3/+WAN//lgDf/5YA3/+WAN//lgDf/5YA3/+TAEAAAAAAAL3/YAC9/98Avf/fAL3/3wC9/98A
|
||||
vf/fAL7/vwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////////////////////////////////////////
|
||||
////////////////////////////////////////////+AAf/gAH///4AB/+AAf///gAH/4ABwAYAAAA
|
||||
YAAAAAgAAABgH4AACAAAACAfgIAEAAAAIB+AgAQAAAAf/4DAAgBAAB//gMACAEAAD/+A4AEAIAAP+ADg
|
||||
AQAgAAf4B/AAgBAAB/gH8ACAEAADwAf4AEAIAAPAP/gAQAgAAcA/+AAgBAABwD/8ACAEAQAAf/wAIAIB
|
||||
AAP//gAQAgCAA//+ABAAAIAD//8ACAAAQB///wAIAABAH///gAQAACAfgP+ABAAAIB+A/8ACAAAAH4D/
|
||||
wAIAAAAPgP/gAQAAAAAA/+ABAAAIAAf/8ACAAAQAB//wAIAABAAH//AAQAgCA///+ABACAIB///4AEAE
|
||||
AgH///wAIAQBAf///AAgAgEA///+ABACAID///4AEAIAgH///wAIAQBAf///AAgBAEA///+ABACAID//
|
||||
/4AEAIAgH///wAIAQBAf///AAgBAEA///+ABACAID///4AEAIAgH///gAIAQBAf///AAgBAEB///////
|
||||
//////////////////////////////////////////////////////////////////////////////8o
|
||||
AAAAMAAAAGAAAAABACAAAAAAAIAlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
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
|
||||
AAD/AAAA/zAcAP//lgD//5YAzwAAAAAAcJmgAAAA/wAAAP8AAAD/AAAA/wAKDtsAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAACAAAAAgAAAAIAAAACAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw/4AA
|
||||
Mf//ADH//wAx//8AMf//ADH//wAx//8AMf//ADD/gAAAAAAAvkW/AL1G/wC9Rv8AvUb/AL1G/wC9Rv8A
|
||||
fC7pAAAA/wAAAP8AAAD/AAAA/zAcAP//lgD//5YA//+WAFAAHihMAAAA/wAAAP8AAAD/AAAA/wAaI/AA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAEAAAAP8AAAD/AAAA/wAAAP8AAAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAw/yAAMf/vADH//wAx//8AMf//ADH//wAx//8AMf//ADH/7wAw/xAAvEZQAL1G/wC9Rv8A
|
||||
vUb/AL1G/wC9Rv8AgjD/AAAA/wAAAP8AAAD/AAAA/zAcAP//lgD//5YA//+WAK8AAABAAAAA/wAAAP8A
|
||||
AAD/AAAA/wAjMP8Auv8wAAAAAAAAAAAAAAAAAAAAEAAAAP8AAAD/AAAA/wAAAP8AAAD/AAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMv+fADH//wAx//8AMf//ADH//wAx//8AMf//ADH//wAw/4AA
|
||||
AAAAAL5FvwC9Rv8AvUb/AL1G/wC9Rv8AgjD/AAAA/wAAAP8AAAD/AAAA/zAcAP//lgD//5YA//+WAP+i
|
||||
XQBYABsjggBoi/YAL0D/AAAA/wAYIP8APlTVAAAAjwAAAI8AAACPAAAAjwAAAP8AAAD/AAAAvwAAAHAA
|
||||
AABwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMP8wADH//wAx//8AMf//ADH//wAx//8A
|
||||
Mf//ADH//wAx/+8AMP8QALxGUAC9Rv8AvUb/AL1G/wC9Rv8AgjD/AAAA/wAAAP8AAAD/AAAA/zAcAP//
|
||||
lgD//5YA//+WAP//lgCvAAAAAAC9/58AO1D/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8A
|
||||
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
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADL/nwAx/98A
|
||||
Mf/fADH/3wAx/98AMf/fADH/3wAx/98AMP9gAAAAAAC9Rq8AvUbfAL1G3wC9Rt8AvUbfAL1G3wC9Rq8A
|
||||
AAAA/5UAgP+WAN//lgDf/5YA3/+WAN//lgDf/5UAMAC//yAAvf/fAL3/3wC9/98Avf/fAL3/jwAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAA////////AAD///////8AAP///////wAA////////AAD///////8AAP//////
|
||||
/wAA//8AH+ADAAD//wAf4AMAAAAAAAEAAAAAAEAAAQPAAAAAAAAAA8AAAIAgAAADwAAAgAAAAH/AAADA
|
||||
ABAAfwAAAMAAAAA/AwAA4AAIAD8DAADgCAAAGAMAAPAABAAYHwAA8AQABAAfAADwAAIAAH8AAPgCAAAA
|
||||
fwAA+AAAAAB/AAD8AQAAA/8AAPwAAAED4AAA/gCAAAPAAAD+AAAAAcAAAP8AQAAAAAAA/wAAAEADAAD/
|
||||
gAAAAAMAAP+AAAAgfwAA/8AAEAB/AAD/wBAAED8AAP/gAAgAPwAA/+AIAAgfAAD/4AAEAB8AAP/wBAAA
|
||||
HwAA//AAAgAPAAD/+AIAAA8AAP/4AAECBwAA//wBAAAHAAD//AAAAQMAAP/+AICAAwAA////////AAD/
|
||||
//////8AAP///////wAA////////AAD///////8AAP///////wAAKAAAACgAAABQAAAAAQAgAAAAAABA
|
||||
GgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
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
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/
|
||||
/////wAAAP//////AAAA//////8AAAD//////wAAAP//////AAAA//gD+AMAAAD/+AP4AwAAAAAAACAA
|
||||
AAAAAAAAIOAAAAAAgAAA4AAAAIAAAB/gAAAAgECAD4AAAADAAAAPgwAAAMAgAAYDAAAA4AAABg8AAADg
|
||||
AACADwAAAPAAAAA/AAAA8AAAAD8AAAD4AAAA/wAAAPgAAADwAAAA/AAAAOAAAAD8AAAAYAAAAP4AAAAD
|
||||
AAAA/gAAAAMAAAD+AAAAAwAAAP8AAAA/AAAA/wCBAB8AAAD/gAAAHwAAAP+AQAIPAAAA/8AAAA8AAAD/
|
||||
wAABBwAAAP/gAAAHAAAA/+AAAAMAAAD/8AAAAwAAAP/wAAADAAAA//////8AAAD//////wAAAP//////
|
||||
AAAA//////8AAAD//////wAAACgAAAAgAAAAQAAAAAEAIAAAAAAAgBAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAABAAAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAAgAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAcAAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAFAAAAAAADD/IAAw/zAAMP8wADD/MAAw/zAA
|
||||
MP8gAAAAAAC6RTAAukUwAEIaZAAdCpcAAAD/BAIA4w8JAMsPCQDLDwkAywAAAP8ADRKrAEJcZACKvD0A
|
||||
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
|
||||
Mf//ADH//wAx//8AMf//ADL/rwC7REAAvUb/AL1G/wC9Rv8AvUb/ALtEQP+XAJ//lgD//5YA//+WAP//
|
||||
lQAwAL7/vwC9//8Avf//ALv/gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAADD/UAAx//8AMf//ADH//wAx//8AMf//ADD/MAC+Rb8AvUb/AL1G/wC9Rv8AvUav/5UAMP+WAP//
|
||||
lgD//5YA//+XAJ8AvP9QAL3//wC9//8Avf/fAL//EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAADH/vwAx/+8AMf/vADH/7wAx/+8AMv+PALxGUAC9Ru8AvUbvAL1G7wC9Ru8A
|
||||
ukUw/5YAv/+WAO//lgDv/5YA3/+PABAAvv+/AL3/7wC9/+8AvP9QAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
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
|
||||
</value>
|
||||
</data>
|
||||
<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,157 @@ namespace WelsonJS.Launcher.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
/// <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/blob.config.xml과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string BlobConfigUrl {
|
||||
get {
|
||||
return ResourceManager.GetString("BlobConfigUrl", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// https://catswords.blob.core.windows.net/welsonjs/과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string BlobStoragePrefix {
|
||||
get {
|
||||
return ResourceManager.GetString("BlobStoragePrefix", 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>
|
||||
/// (아이콘)과(와) 유사한 System.Drawing.Icon 형식의 지역화된 리소스를 찾습니다.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Icon favicon {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("favicon", resourceCulture);
|
||||
return ((System.Drawing.Icon)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 90과(와) 유사한 지역화된 문자열을 찾습니다.
|
||||
/// </summary>
|
||||
internal static string HttpClientTimeout {
|
||||
get {
|
||||
return ResourceManager.GetString("HttpClientTimeout", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// System.Drawing.Bitmap 형식의 지역화된 리소스를 찾습니다.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap icon_check_32 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("icon_check_32", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <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>
|
||||
internal static System.Drawing.Bitmap icon_directory_32 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("icon_directory_32", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// System.Drawing.Bitmap 형식의 지역화된 리소스를 찾습니다.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap icon_export_32 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("icon_export_32", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// System.Drawing.Bitmap 형식의 지역화된 리소스를 찾습니다.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap icon_file_32 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("icon_file_32", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// System.Drawing.Bitmap 형식의 지역화된 리소스를 찾습니다.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap icon_import_32 {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("icon_import_32", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// System.Drawing.Bitmap 형식의 지역화된 리소스를 찾습니다.
|
||||
/// </summary>
|
||||
|
@ -70,6 +221,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>
|
||||
|
@ -79,5 +240,50 @@ namespace WelsonJS.Launcher.Properties {
|
|||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,16 +112,82 @@
|
|||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<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=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="icon_link_128" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\icon_link_128.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="icon_zip_128" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\icon_zip_128.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="favicon" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\favicon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="icon_directory_32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\icon_directory_32.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="icon_file_32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\icon_file_32.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="icon_check_32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\icon_check_32.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="icon_export_32" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Resources\icon_export_32.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<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="BlobConfigUrl" xml:space="preserve">
|
||||
<value>https://catswords.blob.core.windows.net/welsonjs/blob.config.xml</value>
|
||||
</data>
|
||||
<data name="HttpClientTimeout" xml:space="preserve">
|
||||
<value>90</value>
|
||||
</data>
|
||||
</root>
|
500
WelsonJS.Toolkit/WelsonJS.Launcher/ResourceServer.cs
Normal file
|
@ -0,0 +1,500 @@
|
|||
// 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;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
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 static readonly HttpClient _httpClient = new HttpClient();
|
||||
private static readonly string _defaultMimeType = "application/octet-stream";
|
||||
private static BlobConfig _blobConfig;
|
||||
|
||||
static ResourceServer()
|
||||
{
|
||||
// Set timeout
|
||||
int timeout = int.TryParse(Program.GetAppConfig("HttpClientTimeout"), out timeout) ? timeout : 90;
|
||||
_httpClient.Timeout = TimeSpan.FromSeconds(timeout);
|
||||
|
||||
// Fetch a blob config from Internet
|
||||
FetchBlobConfig();
|
||||
}
|
||||
|
||||
public ResourceServer(string prefix, string resourceName)
|
||||
{
|
||||
_prefix = prefix;
|
||||
_listener = new HttpListener();
|
||||
_listener.Prefixes.Add(prefix);
|
||||
_resourceName = resourceName;
|
||||
|
||||
// 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 a blob source
|
||||
if (await TryServeFromBlob(context, path))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task<bool> TryServeFromBlob(HttpListenerContext context, string path)
|
||||
{
|
||||
if (_blobConfig != null)
|
||||
{
|
||||
foreach (var route in _blobConfig.Routes)
|
||||
{
|
||||
foreach (var (regex, index) in route.RegexConditions.Select((r, i) => (r, i)))
|
||||
{
|
||||
if (!regex.Compiled.IsMatch(path)) continue;
|
||||
|
||||
var match = (index < route.Matches.Count) ? route.Matches[index] : route.Matches.First();
|
||||
var _path = route.StripPrefix ? path.Substring(match.Length) : path;
|
||||
|
||||
foreach (var prefixUrl in route.PrefixUrls)
|
||||
{
|
||||
if (await ServeBlob(context, _path, prefixUrl))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fallback
|
||||
string prefix = Program.GetAppConfig("BlobStoragePrefix");
|
||||
if (await ServeBlob(context, 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();
|
||||
}
|
||||
}
|
||||
|
||||
private static async void FetchBlobConfig()
|
||||
{
|
||||
try
|
||||
{
|
||||
string url = Program.GetAppConfig("BlobConfigUrl");
|
||||
var response = await _httpClient.GetStreamAsync(url);
|
||||
|
||||
var serializer = new XmlSerializer(typeof(BlobConfig));
|
||||
using (var reader = new StreamReader(response))
|
||||
{
|
||||
_blobConfig = (BlobConfig)serializer.Deserialize(reader);
|
||||
}
|
||||
|
||||
_blobConfig?.Compile();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Trace.TraceError($"Failed to fetch a blob config. Exception: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[XmlRoot("blobConfig")]
|
||||
public class BlobConfig
|
||||
{
|
||||
[XmlArray("routes")]
|
||||
[XmlArrayItem("route")]
|
||||
public List<BlobRoute> Routes { get; set; } = new List<BlobRoute>();
|
||||
|
||||
public void Compile()
|
||||
{
|
||||
foreach (var route in Routes)
|
||||
{
|
||||
if (route.Matches == null) continue;
|
||||
|
||||
route.RegexConditions = new List<RegexCondition>();
|
||||
foreach (var match in route.Matches)
|
||||
{
|
||||
route.RegexConditions.Add(new RegexCondition
|
||||
{
|
||||
Pattern = match,
|
||||
Compiled = new Regex(
|
||||
match.StartsWith("^") ? match : "^" + Regex.Escape(match),
|
||||
RegexOptions.Compiled)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class BlobRoute
|
||||
{
|
||||
[XmlArray("matches")]
|
||||
[XmlArrayItem("match")]
|
||||
public List<string> Matches { get; set; }
|
||||
|
||||
[XmlArray("prefixUrls")]
|
||||
[XmlArrayItem("url")]
|
||||
public List<string> PrefixUrls { get; set; }
|
||||
|
||||
[XmlAttribute("stripPrefix")]
|
||||
public bool StripPrefix { get; set; }
|
||||
|
||||
[XmlIgnore]
|
||||
public List<RegexCondition> RegexConditions { get; set; }
|
||||
}
|
||||
|
||||
public class RegexCondition
|
||||
{
|
||||
[XmlIgnore]
|
||||
public string Pattern { get; set; }
|
||||
|
||||
[XmlIgnore]
|
||||
public Regex Compiled { get; set; }
|
||||
}
|
||||
}
|
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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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/favicon.ico
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
WelsonJS.Toolkit/WelsonJS.Launcher/Resources/icon_check_32.png
Normal file
After Width: | Height: | Size: 317 B |
BIN
WelsonJS.Toolkit/WelsonJS.Launcher/Resources/icon_delete_32.png
Normal file
After Width: | Height: | Size: 974 B |
After Width: | Height: | Size: 179 B |
BIN
WelsonJS.Toolkit/WelsonJS.Launcher/Resources/icon_export_32.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
WelsonJS.Toolkit/WelsonJS.Launcher/Resources/icon_file_32.png
Normal file
After Width: | Height: | Size: 230 B |
BIN
WelsonJS.Toolkit/WelsonJS.Launcher/Resources/icon_import_32.png
Normal file
After Width: | Height: | Size: 837 B |
BIN
WelsonJS.Toolkit/WelsonJS.Launcher/Resources/icon_start_32.png
Normal file
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,10 +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>
|
||||
|
@ -78,25 +100,41 @@
|
|||
</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>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
<SubType>Designer</SubType>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="GlobalSettingsForm.resx">
|
||||
<DependentUpon>GlobalSettingsForm.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
<DesignTime>True</DesignTime>
|
||||
</Compile>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Properties\Settings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
|
@ -110,7 +148,22 @@
|
|||
<None Include="Resources\icon_zip_128.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="favicon.ico" />
|
||||
<None Include="favicon.ico" />
|
||||
<None Include="Resources\favicon.ico" />
|
||||
<None Include="Resources\icon_check_32.png" />
|
||||
<None Include="Resources\icon_directory_32.png" />
|
||||
<None Include="Resources\icon_file_32.png" />
|
||||
<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,22 @@
|
|||
<?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="BlobConfigUrl" value="https://catswords.blob.core.windows.net/welsonjs/blob.config.xml"/>
|
||||
<add key="HttpClientTimeout" value="90"/>
|
||||
</appSettings>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
|
||||
</startup>
|
||||
</configuration>
|
||||
|
|
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.GetSettingsFileHandler().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,25 +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 const int HeartbeatInterval = 2000; // 2 seconds
|
||||
private ServiceMain _parent;
|
||||
private int HeartbeatInterval;
|
||||
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.ReadSettingsValue("HEARTBEAT_INTERVAL") ?? "2000");
|
||||
|
||||
try
|
||||
{
|
||||
serverAddress = _parent.GetSettingsFileHandler().Read("GRPC_HOST", "Service");
|
||||
serverAddress = parent.ReadSettingsValue("GRPC_HOST");
|
||||
if (String.IsNullOrEmpty(serverAddress))
|
||||
{
|
||||
throw new Exception("The server address could not be empty.");
|
||||
|
@ -36,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();
|
||||
|
@ -49,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()
|
||||
|
@ -67,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); // HeartbeatInterval 동안 대기
|
||||
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);
|
||||
}
|
||||
|
||||
// 서버 응답을 수신하는 작업
|
||||
|
@ -83,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
|
||||
{
|
||||
|
@ -116,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
|
||||
|
@ -146,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
|
@ -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")]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// ScreenMatching.cs
|
||||
// https://github.com/gnh1201/welsonjs
|
||||
// https://github.com/gnh1201/welsonjs/wiki/Screen-Time-Feature
|
||||
// https://catswords-oss.rdbl.io/5719744820/8803957194
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
@ -15,6 +15,7 @@ using System.Windows.Forms;
|
|||
using System.Linq;
|
||||
using Tesseract;
|
||||
using WelsonJS.Service;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
public class ScreenMatch
|
||||
{
|
||||
|
@ -105,13 +106,14 @@ public class ScreenMatch
|
|||
}
|
||||
|
||||
private ServiceMain parent;
|
||||
private ILogger logger;
|
||||
private List<Bitmap> templateImages;
|
||||
private string templateDirectoryPath;
|
||||
private string outputDirectoryPath;
|
||||
private int templateCurrentIndex = 0;
|
||||
private double threshold = 0.4;
|
||||
private double threshold = 0.3;
|
||||
private string mode;
|
||||
private bool busy = false;
|
||||
private bool busy;
|
||||
private List<string> _params = new List<string>();
|
||||
private bool isSearchFromEnd = false;
|
||||
private bool isSaveToFile = false;
|
||||
|
@ -123,14 +125,62 @@ public class ScreenMatch
|
|||
private List<string> sampleOcr;
|
||||
private List<string> sampleNodup;
|
||||
private Size sampleNodupSize;
|
||||
private Queue<Bitmap> sampleOutdated;
|
||||
private byte thresholdConvertToBinary = 191;
|
||||
private Queue<Bitmap> outdatedSamples;
|
||||
private string tesseractDataPath;
|
||||
private string tesseractLanguage;
|
||||
|
||||
public ScreenMatch(ServiceBase parent, string workingDirectory)
|
||||
private void SetBusy(bool busy)
|
||||
{
|
||||
this.parent = (ServiceMain)parent;
|
||||
this.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
|
||||
{
|
||||
public string FileName { get; set; }
|
||||
public int Index { get; set; }
|
||||
|
||||
public TemplateInfo(string fileName, int index)
|
||||
{
|
||||
FileName = fileName;
|
||||
Index = index;
|
||||
}
|
||||
}
|
||||
|
||||
public class SampleInfo
|
||||
{
|
||||
public string FileName { get; set; }
|
||||
public uint Crc32 { get; set; }
|
||||
|
||||
public SampleInfo(string fileName, uint crc32)
|
||||
{
|
||||
FileName = fileName;
|
||||
Crc32 = crc32;
|
||||
}
|
||||
}
|
||||
|
||||
public ScreenMatch(ServiceBase _parent, string workingDirectory, ILogger _logger)
|
||||
{
|
||||
parent = (ServiceMain)_parent;
|
||||
logger = _logger;
|
||||
|
||||
SetBusy(false);
|
||||
|
||||
templateDirectoryPath = Path.Combine(workingDirectory, "app/assets/img/_templates");
|
||||
outputDirectoryPath = Path.Combine(workingDirectory, "app/assets/img/_captured");
|
||||
|
@ -150,24 +200,24 @@ public class ScreenMatch
|
|||
sampleNodup = new List<string>();
|
||||
sampleNodupSize = new Size
|
||||
{
|
||||
Width = 256,
|
||||
Height = 32
|
||||
Width = 180,
|
||||
Height = 60
|
||||
};
|
||||
sampleOutdated = new Queue<Bitmap>();
|
||||
outdatedSamples = new Queue<Bitmap>();
|
||||
|
||||
// Read values from configration file
|
||||
string screen_time_mode;
|
||||
string screen_time_params;
|
||||
try
|
||||
{
|
||||
screen_time_mode = this.parent.GetSettingsFileHandler().Read("SCREEN_TIME_MODE", "Service");
|
||||
screen_time_params = this.parent.GetSettingsFileHandler().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))
|
||||
|
@ -207,14 +257,21 @@ 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;
|
||||
}
|
||||
|
||||
case "threshold":
|
||||
{
|
||||
double.TryParse(config_value, out double t);
|
||||
threshold = t;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -246,6 +303,20 @@ public class ScreenMatch
|
|||
break;
|
||||
}
|
||||
|
||||
case "sample_nodup_width":
|
||||
{
|
||||
int.TryParse(config_value, out int w);
|
||||
sampleNodupSize.Width = w;
|
||||
break;
|
||||
}
|
||||
|
||||
case "sample_nodup_height":
|
||||
{
|
||||
int.TryParse(config_value, out int h);
|
||||
sampleNodupSize.Height = h;
|
||||
break;
|
||||
}
|
||||
|
||||
case "sample_adjust_x":
|
||||
{
|
||||
int.TryParse(config_value, out sampleAdjustX);
|
||||
|
@ -306,13 +377,27 @@ 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)
|
||||
{
|
||||
string filename = Path.GetFileName(file);
|
||||
Bitmap bitmap = new Bitmap(file)
|
||||
|
||||
string realpath;
|
||||
string altpath = parent.GetUserVariablesHandler().GetValue(filename);
|
||||
if (!String.IsNullOrEmpty(altpath))
|
||||
{
|
||||
realpath = altpath;
|
||||
logger.LogInformation($"Use the alternative image: {realpath}");
|
||||
}
|
||||
else
|
||||
{
|
||||
realpath = file;
|
||||
logger.LogInformation($"Use the default image: {realpath}");
|
||||
}
|
||||
|
||||
Bitmap bitmap = new Bitmap(realpath)
|
||||
{
|
||||
Tag = filename
|
||||
};
|
||||
|
@ -321,7 +406,7 @@ public class ScreenMatch
|
|||
{
|
||||
if (filename.StartsWith("binary_"))
|
||||
{
|
||||
templateImages.Add(ConvertToBinary(bitmap, thresholdConvertToBinary));
|
||||
templateImages.Add(ImageQuantize(bitmap));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -343,22 +428,22 @@ public class ScreenMatch
|
|||
|
||||
if (templateImages.Count > 0)
|
||||
{
|
||||
toggleBusy();
|
||||
SetBusy(true);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case "screen": // 화면 기준
|
||||
results = CaptureAndMatchAllScreens();
|
||||
toggleBusy();
|
||||
SetBusy(false);
|
||||
break;
|
||||
|
||||
case "window": // 윈도우 핸들 기준
|
||||
results = CaptureAndMatchAllWindows();
|
||||
toggleBusy();
|
||||
SetBusy(false);
|
||||
break;
|
||||
|
||||
default:
|
||||
toggleBusy();
|
||||
SetBusy(false);
|
||||
throw new Exception($"Unknown capture mode {mode}");
|
||||
}
|
||||
}
|
||||
|
@ -376,42 +461,96 @@ public class ScreenMatch
|
|||
Screen screen = Screen.AllScreens[i];
|
||||
Bitmap mainImage = CaptureScreen(screen);
|
||||
|
||||
if (isSaveToFile)
|
||||
{
|
||||
string outputFilePath = Path.Combine(outputDirectoryPath, $"{DateTime.Now.ToString("yyyy-MM-dd hh mm ss")}.png");
|
||||
((Bitmap)mainImage.Clone()).Save(outputFilePath);
|
||||
parent.Log($"Screenshot saved: {outputFilePath}");
|
||||
}
|
||||
|
||||
Bitmap image = templateImages[templateCurrentIndex];
|
||||
string templateName = image.Tag as string;
|
||||
string nextTemplateName = parent.GetNextTemplateName();
|
||||
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(nextTemplateName) && templateName != nextTemplateName)
|
||||
if (!String.IsNullOrEmpty(nextTemplateInfo.FileName) && templateName != nextTemplateInfo.FileName)
|
||||
{
|
||||
parent.Log($"Ignored the template {templateName}");
|
||||
logger.LogInformation($"Ignored the template {templateName}");
|
||||
break;
|
||||
}
|
||||
|
||||
Bitmap _mainImage;
|
||||
Bitmap out_mainImage;
|
||||
string out_filename;
|
||||
if (templateName.StartsWith("binary_"))
|
||||
{
|
||||
_mainImage = ConvertToBinary((Bitmap)mainImage.Clone(), thresholdConvertToBinary);
|
||||
out_mainImage = ImageQuantize((Bitmap)mainImage.Clone());
|
||||
out_filename = $"{DateTime.Now:yyyy-MM-dd hh mm ss} binary.png";
|
||||
}
|
||||
else
|
||||
{
|
||||
_mainImage = mainImage;
|
||||
out_mainImage = mainImage;
|
||||
out_filename = $"{DateTime.Now:yyyy-MM-dd hh mm ss}.png";
|
||||
}
|
||||
|
||||
if (isSaveToFile)
|
||||
{
|
||||
string out_filepath = Path.Combine(outputDirectoryPath, out_filename);
|
||||
((Bitmap)out_mainImage.Clone()).Save(out_filepath);
|
||||
logger.LogInformation($"Screenshot saved: {out_filepath}");
|
||||
}
|
||||
|
||||
// List to store the positions of matched templates in the main image
|
||||
List<Point> matchPositions;
|
||||
|
||||
// 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;
|
||||
try
|
||||
{
|
||||
// Since outdatedSamples is also used to detect duplicate work, we do not delete tasks with Dequeue.
|
||||
foreach (var image in outdatedSamples)
|
||||
{
|
||||
if (image.Tag != null &&
|
||||
((SampleInfo)image.Tag).FileName == nextTemplateInfo.FileName)
|
||||
{
|
||||
outdatedImage = image;
|
||||
logger.LogInformation($"Found the previous screen of {nextTemplateInfo.FileName}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogInformation($"Error finding a previous screen: {ex.Message}");
|
||||
}
|
||||
|
||||
// Find the matching positions of the outdated image in the main image
|
||||
if (outdatedImage != null) {
|
||||
matchPositions = FindTemplate(out_mainImage, outdatedImage);
|
||||
if (matchPositions.Count > 0)
|
||||
{
|
||||
logger.LogInformation("Match found with the outdated image");
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogInformation("No match found with the outdated image");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
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)templateImage.Clone());
|
||||
}
|
||||
|
||||
List<Point> matchPositions = FindTemplate(_mainImage, (Bitmap)image.Clone());
|
||||
foreach (Point matchPosition in matchPositions)
|
||||
{
|
||||
try
|
||||
|
@ -431,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;
|
||||
|
@ -490,34 +629,34 @@ public class ScreenMatch
|
|||
{
|
||||
Bitmap croppedNodupBitmap = CropBitmap(bitmap, matchPosition, templateSize, sampleNodupSize);
|
||||
uint bitmapCrc32 = ComputeBitmapCrc32(croppedNodupBitmap);
|
||||
croppedNodupBitmap.Tag = bitmapCrc32;
|
||||
croppedNodupBitmap.Tag = new SampleInfo(templateName, bitmapCrc32);
|
||||
|
||||
bool bitmapExists = sampleOutdated.Any(x => (uint)x.Tag == bitmapCrc32);
|
||||
bool bitmapExists = outdatedSamples.Any(x => ((SampleInfo)x.Tag).Crc32 == bitmapCrc32);
|
||||
if (bitmapExists)
|
||||
{
|
||||
throw new InvalidOperationException($"This may be a duplicate request. {templateName}");
|
||||
}
|
||||
else
|
||||
{
|
||||
sampleOutdated.Enqueue(croppedNodupBitmap);
|
||||
parent.Log($"Added to the image queue. {templateName}");
|
||||
outdatedSamples.Enqueue(croppedNodupBitmap);
|
||||
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);
|
||||
|
@ -535,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}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -552,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);
|
||||
|
@ -621,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;
|
||||
|
@ -706,11 +839,6 @@ public class ScreenMatch
|
|||
return matches;
|
||||
}
|
||||
|
||||
private void toggleBusy()
|
||||
{
|
||||
busy = !busy;
|
||||
}
|
||||
|
||||
private bool IsTemplateMatch(Bitmap mainImage, Bitmap templateImage, int offsetX, int offsetY, double threshold)
|
||||
{
|
||||
int templateWidth = templateImage.Width;
|
||||
|
@ -753,14 +881,16 @@ public class ScreenMatch
|
|||
return true;
|
||||
}
|
||||
|
||||
private Bitmap ConvertToBinary(Bitmap image, byte threshold)
|
||||
private Bitmap ImageQuantize(Bitmap image, int levels = 4)
|
||||
{
|
||||
Bitmap binaryImage = new Bitmap(image.Width, image.Height);
|
||||
Bitmap quantizedImage = new Bitmap(image.Width, image.Height);
|
||||
if (image.Tag != null)
|
||||
{
|
||||
binaryImage.Tag = image.Tag;
|
||||
quantizedImage.Tag = image.Tag;
|
||||
}
|
||||
|
||||
int step = 255 / (levels - 1); // step by step..... ooh baby...(?)
|
||||
|
||||
for (int y = 0; y < image.Height; y++)
|
||||
{
|
||||
for (int x = 0; x < image.Width; x++)
|
||||
|
@ -769,13 +899,16 @@ public class ScreenMatch
|
|||
Color pixelColor = image.GetPixel(x, y);
|
||||
byte grayValue = (byte)((pixelColor.R + pixelColor.G + pixelColor.B) / 3);
|
||||
|
||||
// Apply threshold to convert to binary
|
||||
Color binaryColor = grayValue >= threshold ? Color.White : Color.Black;
|
||||
binaryImage.SetPixel(x, y, binaryColor);
|
||||
// Convert the grayscale value to the quantize value
|
||||
byte quantizedValue = (byte)((grayValue / step) * step);
|
||||
|
||||
// Renew the colors
|
||||
Color quantizedColor = Color.FromArgb(quantizedValue, quantizedValue, quantizedValue);
|
||||
quantizedImage.SetPixel(x, y, quantizedColor);
|
||||
}
|
||||
}
|
||||
|
||||
return binaryImage;
|
||||
return quantizedImage;
|
||||
}
|
||||
|
||||
private uint ComputeBitmapCrc32(Bitmap bitmap)
|
||||
|
@ -791,4 +924,4 @@ public class ScreenMatch
|
|||
return BitConverter.ToUInt32(crc32.GetCurrentHash(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,19 +34,20 @@ 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 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 readonly string logFilePath = Path.Combine(Path.GetTempPath(), "WelsonJS.Service.Log.txt");
|
||||
private readonly string appName = "WelsonJS";
|
||||
private string[] args;
|
||||
private bool disabledHeartbeat = false;
|
||||
private bool disabledScreenTime = false;
|
||||
|
@ -54,18 +55,20 @@ namespace WelsonJS.Service
|
|||
private ScreenMatch screenMatcher;
|
||||
private FileEventMonitor fileEventMonitor;
|
||||
private IniFile settingsFileHandler;
|
||||
private UserVariables userVariablesHandler;
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern int GetSystemMetrics(int nIndex);
|
||||
|
||||
private static int SM_REMOTESESSION = 0x1000;
|
||||
|
||||
public ServiceMain(string[] args)
|
||||
public ServiceMain(string[] _args, ILogger _logger)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// set service arguments
|
||||
this.args = args;
|
||||
// set arguments and logger
|
||||
args = _args;
|
||||
logger = _logger;
|
||||
|
||||
// mapping arguments to each variables
|
||||
var arguments = ParseArguments(this.args);
|
||||
|
@ -95,19 +98,23 @@ namespace WelsonJS.Service
|
|||
}
|
||||
}
|
||||
|
||||
// load the user variables
|
||||
userVariablesHandler = new UserVariables(this);
|
||||
userVariablesHandler.Load();
|
||||
|
||||
// set timers
|
||||
timers = new List<Timer>();
|
||||
|
||||
// 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);
|
||||
|
@ -120,14 +127,14 @@ namespace WelsonJS.Service
|
|||
{
|
||||
settingsFileHandler = new IniFile(settingsFilePath);
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception ex)
|
||||
{
|
||||
settingsFileHandler = null;
|
||||
logger.LogWarning(ex.Message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log($"Configuration file not found: {settingsFilePath}");
|
||||
logger.LogInformation($"Configuration file not found: {settingsFilePath}");
|
||||
}
|
||||
|
||||
// read configrations from settings.ini
|
||||
|
@ -143,7 +150,7 @@ namespace WelsonJS.Service
|
|||
{
|
||||
try
|
||||
{
|
||||
if ("true" == GetSettingsFileHandler().Read(configName, "Service"))
|
||||
if ("true" == ReadSettingsValue(configName))
|
||||
{
|
||||
switch (configName)
|
||||
{
|
||||
|
@ -166,7 +173,7 @@ namespace WelsonJS.Service
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"{configName} is ignored: {ex.Message}");
|
||||
logger.LogInformation($"{configName} is ignored: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -175,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
|
||||
|
@ -184,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);
|
||||
}
|
||||
|
@ -199,21 +206,32 @@ 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)");
|
||||
}
|
||||
|
||||
// set the log file path
|
||||
logFilePath = Path.Combine(Path.GetTempPath(), "WelsonJS.Service.Log.txt");
|
||||
Log(appName + " Service Loaded");
|
||||
logger.LogInformation(applicationName + " Service Loaded");
|
||||
}
|
||||
|
||||
public IniFile GetSettingsFileHandler()
|
||||
public string ReadSettingsValue(string key, string defaultValue = null)
|
||||
{
|
||||
return settingsFileHandler;
|
||||
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()
|
||||
{
|
||||
return userVariablesHandler;
|
||||
}
|
||||
|
||||
internal void TestStartupAndStop()
|
||||
|
@ -230,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
|
||||
{
|
||||
|
@ -246,47 +264,59 @@ namespace WelsonJS.Service
|
|||
|
||||
// make the start arguments
|
||||
string[] startArguments;
|
||||
string[] _args;
|
||||
if (Environment.UserInteractive)
|
||||
{
|
||||
startArguments = new string[args.Length + 1];
|
||||
args.CopyTo(startArguments, 0);
|
||||
startArguments[args.Length] = "--user-interactive";
|
||||
_args = new string[]
|
||||
{
|
||||
$"--env-file={userVariablesHandler.GetEnvFilePath()}",
|
||||
"--user-interactive"
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
startArguments = args;
|
||||
_args = new string[]
|
||||
{
|
||||
$"--env-file={userVariablesHandler.GetEnvFilePath()}"
|
||||
};
|
||||
}
|
||||
startArguments = new string[args.Length + _args.Length];
|
||||
args.CopyTo(startArguments, 0);
|
||||
for (int i = 0; i < _args.Length; i++)
|
||||
{
|
||||
startArguments[args.Length + i] = _args[i];
|
||||
}
|
||||
|
||||
// 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()
|
||||
|
@ -300,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()
|
||||
|
@ -318,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
|
||||
{
|
||||
|
@ -333,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");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -347,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -362,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(),
|
||||
|
@ -373,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}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -393,7 +423,7 @@ namespace WelsonJS.Service
|
|||
}
|
||||
else
|
||||
{
|
||||
Log("InvokeScriptMethod Ignored: " + methodName);
|
||||
logger.LogInformation("InvokeScriptMethod Ignored: " + methodName);
|
||||
}
|
||||
|
||||
return "void";
|
||||
|
@ -411,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
|
||||
|
@ -425,20 +455,29 @@ namespace WelsonJS.Service
|
|||
return arguments;
|
||||
}
|
||||
|
||||
public string GetNextTemplateName()
|
||||
public ScreenMatch.TemplateInfo GetNextTemplateInfo()
|
||||
{
|
||||
string templateName = string.Empty;
|
||||
int index = 0;
|
||||
|
||||
try
|
||||
{
|
||||
templateName = DispatchServiceEvent("screenNextTemplate");
|
||||
|
||||
// Check if the received value contains an index
|
||||
string[] parts = templateName.Split(':');
|
||||
if (parts.Length > 1)
|
||||
{
|
||||
templateName = parts[0];
|
||||
int.TryParse(parts[1], out index);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log($"Use all templates because of {ex.Message}");
|
||||
logger.LogInformation($"Use all templates because of {ex.Message}");
|
||||
}
|
||||
|
||||
return templateName;
|
||||
return new ScreenMatch.TemplateInfo(templateName, index);
|
||||
}
|
||||
|
||||
public string DispatchServiceEvent(string eventType, string[] args = null)
|
||||
|
@ -453,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($"Failed to write log: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
82
WelsonJS.Toolkit/WelsonJS.Service/UserVariables.cs
Normal file
|
@ -0,0 +1,82 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.ServiceProcess;
|
||||
|
||||
namespace WelsonJS.Service
|
||||
{
|
||||
public class UserVariables
|
||||
{
|
||||
private ServiceMain parent;
|
||||
private Dictionary<string, string> userVariables;
|
||||
private string envFilePath;
|
||||
|
||||
public UserVariables(ServiceBase parent)
|
||||
{
|
||||
envFilePath = Path.Combine(Program.GetAppDataPath(), "welsonjs_default.env");
|
||||
this.parent = (ServiceMain)parent;
|
||||
}
|
||||
|
||||
// Load user-defined variables from the temporary folder in .env format
|
||||
public void Load()
|
||||
{
|
||||
if (File.Exists(envFilePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
string fileContent = File.ReadAllText(envFilePath);
|
||||
// Split based on new line characters
|
||||
string[] keyValuePairs = fileContent.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
userVariables = new Dictionary<string, string>();
|
||||
|
||||
foreach (string pair in keyValuePairs)
|
||||
{
|
||||
// Split by the first occurrence of '='
|
||||
int indexOfEquals = pair.IndexOf('=');
|
||||
if (indexOfEquals != -1)
|
||||
{
|
||||
string key = pair.Substring(0, indexOfEquals).Trim();
|
||||
string value = pair.Substring(indexOfEquals + 1).Trim();
|
||||
|
||||
// Remove surrounding quotes if present
|
||||
if (value.StartsWith("\"") && value.EndsWith("\""))
|
||||
{
|
||||
value = value.Substring(1, value.Length - 2); // Remove the first and last character
|
||||
}
|
||||
|
||||
// Unescape double quotes in the value
|
||||
value = value.Replace("\\\"", "\"");
|
||||
|
||||
userVariables[key] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"Error parsing line: '{pair}'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error loading variable file: {ex.Message}");
|
||||
userVariables = new Dictionary<string, string>();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
userVariables = new Dictionary<string, string>();
|
||||
}
|
||||
}
|
||||
|
||||
public string GetValue(string name)
|
||||
{
|
||||
userVariables.TryGetValue(name, out string value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public string GetEnvFilePath()
|
||||
{
|
||||
return envFilePath;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\packages\Grpc.Tools.2.66.0\build\Grpc.Tools.props" Condition="Exists('..\packages\Grpc.Tools.2.66.0\build\Grpc.Tools.props')" />
|
||||
<Import Project="..\packages\Grpc.Tools.2.67.0\build\Grpc.Tools.props" Condition="Exists('..\packages\Grpc.Tools.2.67.0\build\Grpc.Tools.props')" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
|
@ -103,42 +103,72 @@
|
|||
<Reference Include="ClamAV.Net, Version=0.1.166.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ClamAV.Net.0.1.166\lib\netstandard2.0\ClamAV.Net.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Google.Protobuf, Version=3.28.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Google.Protobuf.3.28.0\lib\net45\Google.Protobuf.dll</HintPath>
|
||||
<Reference Include="Google.Protobuf, Version=3.28.2.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Google.Protobuf.3.28.2\lib\net45\Google.Protobuf.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Grpc.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=d754f35622e28bad, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Grpc.Core.2.46.6\lib\net45\Grpc.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Grpc.Core.Api, Version=2.0.0.0, Culture=neutral, PublicKeyToken=d754f35622e28bad, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Grpc.Core.Api.2.65.0\lib\net462\Grpc.Core.Api.dll</HintPath>
|
||||
<HintPath>..\packages\Grpc.Core.Api.2.66.0\lib\net462\Grpc.Core.Api.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Grpc.Net.Client, Version=2.0.0.0, Culture=neutral, PublicKeyToken=d754f35622e28bad, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Grpc.Net.Client.2.65.0\lib\net462\Grpc.Net.Client.dll</HintPath>
|
||||
<HintPath>..\packages\Grpc.Net.Client.2.66.0\lib\net462\Grpc.Net.Client.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Grpc.Net.Client.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=d754f35622e28bad, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Grpc.Net.Client.Web.2.65.0\lib\netstandard2.0\Grpc.Net.Client.Web.dll</HintPath>
|
||||
<HintPath>..\packages\Grpc.Net.Client.Web.2.66.0\lib\netstandard2.0\Grpc.Net.Client.Web.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Grpc.Net.Common, Version=2.0.0.0, Culture=neutral, PublicKeyToken=d754f35622e28bad, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Grpc.Net.Common.2.65.0\lib\netstandard2.0\Grpc.Net.Common.dll</HintPath>
|
||||
<HintPath>..\packages\Grpc.Net.Common.2.66.0\lib\netstandard2.0\Grpc.Net.Common.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=8.0.0.1, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.8.0.1\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
|
||||
<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.Logging.Abstractions, Version=8.0.0.1, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.8.0.1\lib\net462\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
|
||||
<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="RestSharp, Version=112.0.0.0, Culture=neutral, PublicKeyToken=598062e77f915f75">
|
||||
<HintPath>..\packages\RestSharp.112.0.0\lib\net48\RestSharp.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
<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>
|
||||
<Reference Include="System" />
|
||||
<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">
|
||||
|
@ -160,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>
|
||||
|
@ -167,8 +198,8 @@
|
|||
<Reference Include="System.Text.Encodings.Web, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Text.Encodings.Web.8.0.0\lib\net462\System.Text.Encodings.Web.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Text.Json, Version=8.0.0.4, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Text.Json.8.0.4\lib\net462\System.Text.Json.dll</HintPath>
|
||||
<Reference Include="System.Text.Json, Version=8.0.0.5, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Text.Json.8.0.5\lib\net462\System.Text.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
|
@ -186,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>
|
||||
|
@ -203,6 +237,7 @@
|
|||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ScreenMatch.cs" />
|
||||
<Compile Include="Model\ScreenMatchResult.cs" />
|
||||
<Compile Include="UserVariables.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<COMReference Include="MSScriptControl">
|
||||
|
@ -255,11 +290,11 @@
|
|||
<ErrorText>이 프로젝트는 이 컴퓨터에 없는 NuGet 패키지를 참조합니다. 해당 패키지를 다운로드하려면 NuGet 패키지 복원을 사용하십시오. 자세한 내용은 http://go.microsoft.com/fwlink/?LinkID=322105를 참조하십시오. 누락된 파일은 {0}입니다.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\Grpc.Core.2.46.6\build\net45\Grpc.Core.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Grpc.Core.2.46.6\build\net45\Grpc.Core.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\Grpc.Tools.2.66.0\build\Grpc.Tools.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Grpc.Tools.2.66.0\build\Grpc.Tools.props'))" />
|
||||
<Error Condition="!Exists('..\packages\Grpc.Tools.2.66.0\build\Grpc.Tools.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Grpc.Tools.2.66.0\build\Grpc.Tools.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\Tesseract.5.2.0\build\Tesseract.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Tesseract.5.2.0\build\Tesseract.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\Grpc.Tools.2.67.0\build\Grpc.Tools.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Grpc.Tools.2.67.0\build\Grpc.Tools.props'))" />
|
||||
<Error Condition="!Exists('..\packages\Grpc.Tools.2.67.0\build\Grpc.Tools.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Grpc.Tools.2.67.0\build\Grpc.Tools.targets'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\Grpc.Core.2.46.6\build\net45\Grpc.Core.targets" Condition="Exists('..\packages\Grpc.Core.2.46.6\build\net45\Grpc.Core.targets')" />
|
||||
<Import Project="..\packages\Grpc.Tools.2.66.0\build\Grpc.Tools.targets" Condition="Exists('..\packages\Grpc.Tools.2.66.0\build\Grpc.Tools.targets')" />
|
||||
<Import Project="..\packages\Tesseract.5.2.0\build\Tesseract.targets" Condition="Exists('..\packages\Tesseract.5.2.0\build\Tesseract.targets')" />
|
||||
<Import Project="..\packages\Grpc.Tools.2.67.0\build\Grpc.Tools.targets" Condition="Exists('..\packages\Grpc.Tools.2.67.0\build\Grpc.Tools.targets')" />
|
||||
</Project>
|
|
@ -21,7 +21,7 @@
|
|||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Extensions.Logging.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="System.Diagnostics.DiagnosticSource" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
|
@ -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" />
|
||||
|
@ -81,12 +81,20 @@
|
|||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Text.Json" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-8.0.0.4" newVersion="8.0.0.4" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-8.0.0.5" newVersion="8.0.0.5" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<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>
|
||||
|
|
|
@ -1,18 +1,28 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="ClamAV.Net" version="0.1.166" targetFramework="net48" />
|
||||
<package id="Google.Protobuf" version="3.28.0" targetFramework="net48" />
|
||||
<package id="Google.Protobuf" version="3.28.2" targetFramework="net48" />
|
||||
<package id="Grpc" version="2.46.6" targetFramework="net48" />
|
||||
<package id="Grpc.Core" version="2.46.6" targetFramework="net48" />
|
||||
<package id="Grpc.Core.Api" version="2.65.0" targetFramework="net48" />
|
||||
<package id="Grpc.Net.Client" version="2.65.0" targetFramework="net48" />
|
||||
<package id="Grpc.Net.Client.Web" version="2.65.0" targetFramework="net48" />
|
||||
<package id="Grpc.Net.Common" version="2.65.0" targetFramework="net48" />
|
||||
<package id="Grpc.Tools" version="2.66.0" targetFramework="net48" developmentDependency="true" />
|
||||
<package id="Grpc.Core.Api" version="2.66.0" targetFramework="net48" />
|
||||
<package id="Grpc.Net.Client" version="2.66.0" targetFramework="net48" />
|
||||
<package id="Grpc.Net.Client.Web" version="2.66.0" targetFramework="net48" />
|
||||
<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.DependencyInjection.Abstractions" version="8.0.1" targetFramework="net48" />
|
||||
<package id="Microsoft.Extensions.Logging.Abstractions" version="8.0.1" targetFramework="net48" />
|
||||
<package id="RestSharp" version="112.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" />
|
||||
<package id="System.IO.Hashing" version="8.0.0" targetFramework="net48" />
|
||||
|
@ -21,7 +31,7 @@
|
|||
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net48" />
|
||||
<package id="System.Runtime.CompilerServices.Unsafe" version="6.0.0" targetFramework="net48" />
|
||||
<package id="System.Text.Encodings.Web" version="8.0.0" targetFramework="net48" />
|
||||
<package id="System.Text.Json" version="8.0.4" targetFramework="net48" />
|
||||
<package id="System.Text.Json" version="8.0.5" targetFramework="net48" />
|
||||
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net48" />
|
||||
<package id="System.ValueTuple" version="4.5.0" targetFramework="net48" />
|
||||
<package id="Tesseract" version="5.2.0" targetFramework="net48" />
|
||||
|
|
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
|
@ -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
|
@ -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
|
@ -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);
|
||||
|
|
|
@ -79,6 +79,7 @@
|
|||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>favicon.ico</ApplicationIcon>
|
||||
<PackageIcon>icon.png</PackageIcon>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
|
@ -88,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" />
|
||||
|
@ -100,6 +106,8 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="welsonjs.snk" />
|
||||
<None Include="WelsonJS.Toolkit.nuspec" />
|
||||
<None Include="assets/img/logo.png" Pack="true" PackagePath="" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="favicon.ico" />
|
||||
|
|
22
WelsonJS.Toolkit/WelsonJS.Toolkit/WelsonJS.Toolkit.nuspec
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<package >
|
||||
<metadata>
|
||||
<id>$id$</id>
|
||||
<version>0.2.7.49</version>
|
||||
<title>$title$</title>
|
||||
<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>Native toolkit for WelsonJS framework-based RPA applications.</description>
|
||||
<releaseNotes>Updated release</releaseNotes>
|
||||
<copyright>$copyright$</copyright>
|
||||
<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
|
@ -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
|
BIN
WelsonJS.Toolkit/WelsonJS.Toolkit/assets/img/logo.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
158
app.js
|
@ -1,48 +1,16 @@
|
|||
//////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// app.js
|
||||
//
|
||||
// Bootstrap code for running a javascript app in windows. Run as:
|
||||
//
|
||||
// cscript.js app.js <appname> <app arguments> ...
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// app.js
|
||||
// Bootstrap code for running a javascript app in windows. Run as:
|
||||
// cscript.js app.js <appname> <app arguments> ...
|
||||
//
|
||||
// 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
|
||||
// Join our team: https://teams.live.com/l/community/FEACHncAhq8ldnojAI
|
||||
//
|
||||
"use strict";
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Author: Namhyeon Go <abuse@catswords.net>
|
||||
// Repository: https://github.com/gnh1201/welsonjs
|
||||
// Report abuse: abuse@catswords.net
|
||||
// Latest news: ActivityPub @catswords_oss@catswords.social
|
||||
// Join our team: https://teams.live.com/l/community/FEACHncAhq8ldnojAI
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// Bootstrap code, basic module loading functionality
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//
|
||||
// The module loaded is run inside a function, with one argument, global which
|
||||
// points to the global context. So global.FN is the same as FN (as long as a
|
||||
// version of FN does not exist in local scope).
|
||||
//
|
||||
// The module should return its interface at the end of the script. The basic
|
||||
// pattern for a module is:-
|
||||
//
|
||||
// var module = { ... };
|
||||
// return module;
|
||||
//
|
||||
// Or:-
|
||||
//
|
||||
// return function() {
|
||||
// }
|
||||
//
|
||||
// The appname argument causes <appname>.js to be loaded. The interface returned
|
||||
// must define main = function(args) {}, which is called once the module is
|
||||
// loaded.
|
||||
//
|
||||
var exit = function(status) {
|
||||
console.error("Exit", status, "caused");
|
||||
|
||||
|
@ -78,7 +46,7 @@ var console = {
|
|||
},
|
||||
_echoCallback: null,
|
||||
_echo: function(args, type) {
|
||||
var message = "";
|
||||
var messages = [];
|
||||
var params = {
|
||||
type: type,
|
||||
scope: [],
|
||||
|
@ -86,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 {
|
||||
|
@ -238,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);
|
||||
|
||||
if (pos > -1) { // from a remote server
|
||||
if (["http", "https"].indexOf(FN.substring(0, pos)) > -1) {
|
||||
// load script from a remote server
|
||||
if (["http", "https"].indexOf(scheme) > -1) {
|
||||
require._addScriptProvider(function(url) {
|
||||
try {
|
||||
return require("lib/http").get(url);
|
||||
|
@ -250,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) {
|
||||
|
@ -263,7 +260,8 @@ function require(pathname) {
|
|||
i++;
|
||||
}
|
||||
}
|
||||
} else { // from a local server
|
||||
} else {
|
||||
// load script from a local server
|
||||
var _filename = (function(fs, path) {
|
||||
var filepaths = [
|
||||
FN, // default
|
||||
|
@ -347,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;
|
||||
|
@ -359,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 '';
|
||||
|
@ -665,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");
|
||||
|
@ -677,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;
|
||||
|
||||
|
@ -692,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") {
|
||||
|
|
54
app/assets/bat/clean_chrome_pup.bat
Normal file
|
@ -0,0 +1,54 @@
|
|||
@echo off
|
||||
title Remove Chrome policies created by potentially unwanted programs
|
||||
color 0C
|
||||
|
||||
echo [INFO] This script must be run with administrator privileges.
|
||||
echo [INFO] It will remove Chrome policies, enrollment tokens, forced extensions, and user profiles.
|
||||
echo.
|
||||
|
||||
:: Step 1: Remove policy-related registry keys
|
||||
echo [STEP 1] Removing Chrome policy registry keys...
|
||||
|
||||
reg delete "HKCU\Software\Google\Chrome" /f >nul 2>&1
|
||||
reg delete "HKCU\Software\Policies\Google\Chrome" /f >nul 2>&1
|
||||
reg delete "HKLM\Software\Google\Chrome" /f >nul 2>&1
|
||||
reg delete "HKLM\Software\Policies\Google\Chrome" /f >nul 2>&1
|
||||
reg delete "HKLM\Software\Policies\Google\Update" /f >nul 2>&1
|
||||
reg delete "HKLM\Software\WOW6432Node\Google\Enrollment" /f >nul 2>&1
|
||||
|
||||
:: Step 2: Remove CloudManagementEnrollmentToken value only
|
||||
echo [STEP 2] Removing CloudManagementEnrollmentToken value...
|
||||
|
||||
reg delete "HKLM\Software\WOW6432Node\Google\Update\ClientState\{430FD4D0-B729-4F61-AA34-91526481799D}" /v CloudManagementEnrollmentToken /f >nul 2>&1
|
||||
|
||||
:: Step 3: Remove policy-enforced extension installations
|
||||
echo [STEP 3] Removing extension force-install policies...
|
||||
|
||||
reg delete "HKCU\Software\Policies\Google\Chrome\ExtensionInstallForcelist" /f >nul 2>&1
|
||||
reg delete "HKLM\Software\Policies\Google\Chrome\ExtensionInstallForcelist" /f >nul 2>&1
|
||||
|
||||
:: Step 4: Remove Chrome policy directories
|
||||
echo [STEP 4] Removing Chrome policy directories...
|
||||
|
||||
if exist "%ProgramFiles(x86)%\Google\Policies" (
|
||||
rmdir /s /q "%ProgramFiles(x86)%\Google\Policies"
|
||||
)
|
||||
|
||||
if exist "%ProgramFiles%\Google\Policies" (
|
||||
rmdir /s /q "%ProgramFiles%\Google\Policies"
|
||||
)
|
||||
|
||||
if exist "%ProgramData%\Google\Policies" (
|
||||
rmdir /s /q "%ProgramData%\Google\Policies"
|
||||
)
|
||||
|
||||
:: Step 5: Remove entire user Chrome profile
|
||||
echo [STEP 5] Removing entire Chrome user profile directory...
|
||||
echo This includes all settings, cache, cookies, history, saved logins, extensions, etc.
|
||||
|
||||
RD /S /Q "%LocalAppData%\Google\Chrome"
|
||||
|
||||
echo.
|
||||
echo [COMPLETE] Chrome has been fully reset and cleaned.
|
||||
echo Restart Chrome or reboot the system to apply all changes.
|
||||
pause
|
|
@ -1,35 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height="113.54473"
|
||||
width="500"
|
||||
version="1.1"
|
||||
id="svg2"
|
||||
viewBox="0 0 500 113.54473">
|
||||
<metadata
|
||||
id="metadata12">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs10" />
|
||||
<path
|
||||
style="fill:#262626"
|
||||
id="path4"
|
||||
d="m 129.51179,83.4172 c 9.30714,3.40291 28.7193,6.78583 44.41737,6.78583 16.91482,0 26.32967,-4.68345 27.08366,-11.95203 0.68617,-6.6303 -6.23934,-7.5279 -25.34032,-12.05181 C 149.279,59.72847 132.43997,49.71122 134.09156,33.70198 136.01044,15.11563 160.884,1.06914 199.05006,1.06914 c 18.6063,0 36.64612,1.3125 45.99316,4.37631 l -3.20744,23.4374 c -6.06779,-2.11036 -29.29376,-5.04253 -45.0038,-5.04253 -15.92945,0 -24.17542,5.01062 -24.7459,10.50395 -0.71808,6.95343 7.55981,7.27656 28.25254,12.78585 28.02116,7.10901 40.27243,17.11828 38.66872,32.63683 -1.87898,18.25528 -24.25921,33.77778 -68.94785,33.77778 -18.60231,0 -34.63549,-3.3949 -43.4679,-6.7899 L 129.5078,83.42119 Z M 392.11041,6.89758 c 101.74823,-19.18476 110.52878,15.28717 107.38518,45.78969 l -5.92418,56.42926 -32.29773,0 5.40556,-51.46651 c 1.16888,-11.33373 8.44544,-33.50252 -26.68473,-32.67273 -12.15952,0.29521 -18.18742,1.96275 -18.18742,1.96275 0,0 -1.05718,13.69542 -2.33776,23.81639 l -6.12364,58.3601 -31.6754,0 6.28721,-57.51835 4.15291,-44.7006 z M 263.59766,4.2287 c 7.2606,-0.78989 18.41481,-1.59174 33.76581,-1.59174 25.62755,0 46.34821,4.46008 59.17794,13.83903 11.52123,8.74465 19.18875,22.90283 17.06642,43.41604 -1.95877,19.08902 -11.88426,32.4533 -26.33367,40.7192 -13.22069,7.7952 -29.88019,11.1263 -54.93327,11.1263 -14.77255,0 -28.86291,-0.7978 -39.57829,-2.3856 L 263.60165,4.2287 Z m 21.17544,84.22704 c 2.4694,0.47872 5.71673,0.95345 12.11963,0.95345 25.63553,0 43.71125,-12.59835 45.5264,-30.31104 2.63696,-25.60361 -13.39622,-34.5557 -40.40807,-34.40012 -3.49866,0 -8.36167,0 -10.9348,0.47074 l -6.30715,63.28298 z" />
|
||||
<path
|
||||
style="fill:#ca0c16"
|
||||
id="path6"
|
||||
d="m 111.14086,109.99823 c -6.07577,2.1063 -18.662147,3.5425 -36.247187,3.5425 -50.56893,0 -77.8640296,-23.7366 -74.63664955,-55.11678 C 4.1187134,21.03581 44.554713,0 88.828463,0 105.97466,0 116.07169,1.38031 125.53043,3.69413 l -3.03589,25.18872 c -6.2912,-2.11834 -21.03582,-4.06514 -32.971937,-4.06514 -26.05042,0 -48.17532,7.75928 -50.71255,32.30572 -2.26196,21.94937 13.26856,32.4413 42.57429,32.4413 10.20075,0 25.240577,-1.46005 32.194007,-3.57042 l -2.43749,24.00392 z" />
|
||||
</svg>
|
Before Width: | Height: | Size: 2.9 KiB |
|
@ -1,17 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="196.52mm" height="196.52mm" viewBox="0 0 196.52 196.52">
|
||||
<path fill="#a730b8" d="M47.9242 72.7966a18.2278 18.2278 0 0 1-7.7959 7.7597l42.7984 42.9653 10.3182-5.2291zm56.4524 56.6704-10.3182 5.2291 21.686 21.7708a18.2278 18.2278 0 0 1 7.7975-7.7608z"/>
|
||||
<path fill="#5496be" d="M129.6645 102.0765l1.7865 11.4272 27.4149-13.8942a18.2278 18.2278 0 0 1-4.9719-9.8124zm-14.0658 7.1282-57.2891 29.0339a18.2278 18.2278 0 0 1 4.9728 9.8133l54.1027-27.4194z"/>
|
||||
<path fill="#ce3d1a" d="M69.5312 91.6539l8.1618 8.1933 29.269-57.1387a18.2278 18.2278 0 0 1-9.787-5.0219zm-7.1897 14.0363-14.0022 27.3353a18.2278 18.2278 0 0 1 9.786 5.0214l12.3775-24.1639z"/>
|
||||
<path fill="#d0188f" d="M39.8906 80.6763a18.2278 18.2278 0 0 1-10.8655 1.7198l8.1762 52.2981a18.2278 18.2278 0 0 1 10.8645-1.7198z"/>
|
||||
<path fill="#5b36e9" d="M63.3259 148.3109a18.2278 18.2278 0 0 1-1.7322 10.8629l52.2893 8.3907a18.2278 18.2278 0 0 1 1.7322-10.8629z"/>
|
||||
<path fill="#30b873" d="M134.9148 146.9182a18.2278 18.2278 0 0 1 9.788 5.0224l24.1345-47.117a18.2278 18.2278 0 0 1-9.7875-5.0229z"/>
|
||||
<path fill="#ebe305" d="M126.1329 33.1603a18.2278 18.2278 0 0 1-7.7975 7.7608l37.3765 37.5207a18.2278 18.2278 0 0 1 7.7969-7.7608z"/>
|
||||
<path fill="#f47601" d="M44.7704 51.6279a18.2278 18.2278 0 0 1 4.9723 9.8123l47.2478-23.9453a18.2278 18.2278 0 0 1-4.9718-9.8113z"/>
|
||||
<path fill="#57c115" d="M118.2491 40.9645a18.2278 18.2278 0 0 1-10.8511 1.8123l4.1853 26.8 11.42 1.8324zm-4.2333 44.1927 9.8955 63.3631a18.2278 18.2278 0 0 1 10.88-1.6278l-9.355-59.9035z"/>
|
||||
<path fill="#dbb210" d="M49.7763 61.6412a18.2278 18.2278 0 0 1-1.694 10.8686l26.8206 4.3077 5.2715-10.2945zm45.9677 7.382-5.272 10.2955 63.3713 10.1777a18.2278 18.2278 0 0 1 1.7606-10.8593z"/>
|
||||
<path fill="#ffca00" d="M93.4385 23.8419a1 1 0 1 0 33.0924 1.8025 1 1 0 1 0-33.0924-1.8025"/>
|
||||
<path fill="#64ff00" d="M155.314 85.957a1 1 0 1 0 33.0923 1.8025 1 1 0 1 0-33.0923-1.8025"/>
|
||||
<path fill="#00a3ff" d="M115.3466 163.9824a1 1 0 1 0 33.0923 1.8025 1 1 0 1 0-33.0923-1.8025"/>
|
||||
<path fill="#9500ff" d="M28.7698 150.0898a1 1 0 1 0 33.0923 1.8025 1 1 0 1 0-33.0923-1.8025"/>
|
||||
<path fill="#ff0000" d="M15.2298 63.4781a1 1 0 1 0 33.0923 1.8025 1 1 0 1 0-33.0923-1.8025"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 118 KiB |
Before Width: | Height: | Size: 139 KiB |
Before Width: | Height: | Size: 188 KiB |
Before Width: | Height: | Size: 136 KiB |
Before Width: | Height: | Size: 405 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 4.3 KiB |
|
@ -1 +0,0 @@
|
|||
<svg class="h-10 w-auto" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 101.14 114.68"><defs><style>.cls-1{fill:#6366f1;}.cls-2{mask:url(#mask);}.cls-3{mask:url(#mask-2);}.cls-4{mask:url(#mask-3);}.cls-5{mask:url(#mask-4);}.cls-6{filter:url(#luminosity-noclip-4);}.cls-7{filter:url(#luminosity-noclip-3);}.cls-8{filter:url(#luminosity-noclip-2);}.cls-9{filter:url(#luminosity-noclip);}</style><filter id="luminosity-noclip" x="34.45" y="-8249.25" width="8" height="32766" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"><feFlood flood-color="#fff" result="bg"></feFlood><feBlend in="SourceGraphic" in2="bg"></feBlend></filter><mask id="mask" x="34.45" y="-8249.25" width="8" height="32766" maskUnits="userSpaceOnUse"><g class="cls-9"></g></mask><filter id="luminosity-noclip-2" x="65.59" y="-8249.25" width="8" height="32766" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"><feFlood flood-color="#fff" result="bg"></feFlood><feBlend in="SourceGraphic" in2="bg"></feBlend></filter><mask id="mask-2" x="65.59" y="-8249.25" width="8" height="32766" maskUnits="userSpaceOnUse"><g class="cls-8"></g></mask><filter id="luminosity-noclip-3" x="58.6" y="-8249.25" width="8" height="32766" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"><feFlood flood-color="#fff" result="bg"></feFlood><feBlend in="SourceGraphic" in2="bg"></feBlend></filter><mask id="mask-3" x="58.6" y="-8249.25" width="8" height="32766" maskUnits="userSpaceOnUse"><g class="cls-7"></g></mask><filter id="luminosity-noclip-4" x="28.15" y="-8249.25" width="8" height="32766" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"><feFlood flood-color="#fff" result="bg"></feFlood><feBlend in="SourceGraphic" in2="bg"></feBlend></filter><mask id="mask-4" x="28.15" y="-8249.25" width="8" height="32766" maskUnits="userSpaceOnUse"><g class="cls-6"></g></mask></defs><path class="cls-1" d="M41.55,4.25c3.6-2,7.66-5.85,12-3.52,14.93,8.43,29.77,17.05,44.6,25.65,3.87,2.07,2.77,7,3,10.59-.21,1.81.46,4.09-1,5.52C91,52.3,80.2,60.47,68.86,67.56c-3.23-1.67-7.17-2.59-10.55-.81-5.57,2.44-7.56,10.29-3.67,15,3.78,5.35,12.7,5.21,16.22-.34,2.2-2.52,1.21-6.14,2.19-9a187,187,0,0,0,28-21.82c0,10.83.09,21.66,0,32.49A5.78,5.78,0,0,1,98,88.38C87.31,94.71,76.43,100.72,65.72,107a151.64,151.64,0,0,1-25.33-31.7c1.49-2.86,2.6-6.24,1.26-9.37-1.83-6.12-10.11-8.81-15.17-4.89-5.08,3.24-5.75,11.19-1.3,15.25,2.56,2.86,6.57,3,10.14,2.86A164,164,0,0,0,60,110.26c-3.8,1.88-8,6.17-12.43,3.64C33.07,105.82,18.8,97.31,4.34,89.12c-1.65-1-3.56-2.07-4-4.11A75.22,75.22,0,0,1,.07,73.88c-.31-1.52,1-2.48,1.85-3.49A159.1,159.1,0,0,1,32.31,46.27c4.13,2.43,9.95,2.58,13.36-1.17A10,10,0,0,0,45,30.53c-4.28-3.89-11.82-2.92-14.86,2-1.86,2.45-1.47,5.61-1.69,8.48C18.49,47.78,8.69,54.87.05,63.31.11,52.52-.08,41.73.13,31,0,28.06,2.68,26.44,4.86,25.19c10.37-5.82,20.61-11.85,31-17.72C46,16.64,54.12,27.74,61.47,39.21c-1.51,2.84-2.65,6.17-1.41,9.35,1.73,5.83,9.29,8.76,14.48,5.55,5.28-2.75,6.79-10.58,2.79-15-2.51-3.23-6.81-4.06-10.66-3.43C59.47,24.33,51.33,13.49,41.55,4.25Z"></path><g class="cls-2"><circle class="cls-1" cx="38.45" cy="38.08" r="4"></circle></g><g class="cls-3"><circle class="cls-1" cx="69.59" cy="45.43" r="4"></circle></g><g class="cls-4"><circle class="cls-1" cx="62.6" cy="75.97" r="4"></circle></g><g class="cls-5"><circle class="cls-1" cx="32.15" cy="69.23" r="4"></circle></g></svg>
|
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 9.9 KiB |
|
@ -1 +0,0 @@
|
|||
<svg id="Layer_4" data-name="Layer 4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 141.09 184.89"><defs><style>.cls-1{fill:#0d53d7;}</style></defs><path class="cls-1" d="M664.89,596.67c1.12-.11,2.24-.26,3.34-.46a49.91,49.91,0,0,0,41.32-49.15h-91.2A49.88,49.88,0,0,0,568.45,597h91.2A47.74,47.74,0,0,0,664.89,596.67Z" transform="translate(-568.45 -547.06)"/><path class="cls-1" d="M643.08,681.5H599.56a49.89,49.89,0,0,0-28.13,44.9,48.09,48.09,0,0,0,.31,5.54H669.6l1.33-.28a49.91,49.91,0,0,0,38.62-48.61c0-.52,0-1,0-1.55Z" transform="translate(-568.45 -547.06)"/><path class="cls-1" d="M609.76,663.8h99.76a49.91,49.91,0,0,0-41.31-47.61c-1.2-.2-2.41-.37-3.63-.48l.1-.25H568.46A49.89,49.89,0,0,0,609.76,663.8Zm26.39-42.47c-1.08.58-2.13,1.19-3.16,1.84C634,622.52,635.07,621.91,636.15,621.33ZM616.67,640a49.59,49.59,0,0,1,4.16-6c.76-.94,1.55-1.86,2.38-2.74s1.69-1.74,2.58-2.57,1.81-1.61,2.75-2.37c-.94.76-1.86,1.55-2.75,2.37s-1.75,1.68-2.58,2.57-1.62,1.8-2.38,2.74a49.59,49.59,0,0,0-4.16,6c-.62,1-1.2,2.12-1.74,3.22C615.47,642.13,616.05,641.06,616.67,640Z" transform="translate(-568.45 -547.06)"/></svg>
|
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 122 KiB |
Before Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 103 KiB |
Before Width: | Height: | Size: 224 KiB |
Before Width: | Height: | Size: 599 KiB |
Before Width: | Height: | Size: 122 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 9.3 KiB |
Before Width: | Height: | Size: 69 KiB |
Before Width: | Height: | Size: 217 KiB |