Compare commits

...

837 Commits

Author SHA1 Message Date
0ccddd4e75
Merge pull request #249 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (javascript) (push) Waiting to run
Improve the concept to access a blob sources
2025-05-11 01:30:30 +09:00
5087359ac3 Revert "Replace the keyword void to Task for async method"
This reverts commit 0ad978bb6b.
2025-05-11 01:21:08 +09:00
1ab70d7cd7 Revert "Update CDN servers list"
This reverts commit 0438ee9a50.
2025-05-11 01:05:09 +09:00
0438ee9a50 Update CDN servers list 2025-05-10 21:31:49 +09:00
0ad978bb6b Replace the keyword void to Task for async method 2025-05-10 16:53:47 +09:00
a001471451 Improve the concept to access a blob sources 2025-05-10 16:07:36 +09:00
5f10d50a3c
Create clean_chrome_pup.bat
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-05-08 22:31:55 +09:00
aee5fb22d0
Merge pull request #245 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Add JavaScript CDN servers
2025-05-05 23:44:59 +09:00
14c8b12df7 Add a CDN servers 2025-05-05 23:32:41 +09:00
deed89560b Update ResourceServer.cs 2025-05-05 23:22:02 +09:00
eb32437f96 Update ResourceServer.cs 2025-05-05 21:34:50 +09:00
c95b7a373b Update ResourceServer.cs 2025-05-05 21:33:06 +09:00
302e7ce4fc Add an available CDN servers 2025-05-05 19:13:41 +09:00
a5fc5de78f Update ResourceServer.cs 2025-05-05 17:47:50 +09:00
d362d852ad Add JavaScript CDN servers 2025-05-05 17:38:48 +09:00
2a3f9fb4fa
Update README.md
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
2025-05-01 14:32:48 +09:00
944751121c
Merge pull request #243 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Add the example to use function calling on LLM
2025-04-27 13:14:27 +09:00
fb420d1116 Add the example to use function calling on LLM 2025-04-27 13:09:03 +09:00
26af578178
Merge pull request #242 from gnh1201/dev
Set throttle to the prompt context
2025-04-27 11:43:52 +09:00
245dd85341 Update editor.html 2025-04-27 11:39:43 +09:00
fb6596fe64 Update editor.html 2025-04-27 11:10:00 +09:00
a42180d244 Set throttle to the prompt context 2025-04-27 10:50:52 +09:00
73b24f9a56
Merge pull request #240 from gnh1201/dev
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
Fix bug when use DevTools CORS policy (WebSocket error)
2025-04-22 21:31:37 +09:00
eae2795bbf Update Program.cs 2025-04-22 21:27:23 +09:00
98e73b2372 Fix bug when use the devtools protocol with the remote allow origins (Fix WebSocket error) 2025-04-22 21:26:42 +09:00
2225ab9011
Merge pull request #239 from gnh1201/dev
Improve WelsonJS Editor with React framework
2025-04-18 19:51:56 +09:00
4c0895850b Update the integrity attributes 2025-04-18 19:48:41 +09:00
ea412908ef Update editor.html 2025-04-18 19:31:23 +09:00
05ea48a0be some updates 2025-04-18 19:22:25 +09:00
243ff95198 Migrate to React framework 2025-04-18 01:06:27 +09:00
8341394912
Merge pull request #238 from gnh1201/dev
Forward Whois and DNS query data to LLM services
2025-04-12 14:34:59 +09:00
e5a89c9182 Forward Whois and DNS query data to LLM services
Forward Whois and DNS query data to LLM services (e.g. Server configuration assistant)
2025-04-12 14:24:59 +09:00
df5b8cd9f0
Merge pull request #237 from gnh1201/dev
Add support the Azure AI, Optimize the HTTPClient object uses.
2025-04-11 14:19:55 +09:00
e7b6a87175 Reduce code complexity 2025-04-11 14:15:03 +09:00
5b2863058a Add support the Azure AI, Optimize the HTTPClient object uses. 2025-04-11 13:44:21 +09:00
cd8844afef
Merge pull request #236 from gnh1201/dev
Update the markdown files
2025-04-10 16:34:47 +09:00
b26d979b8d Update the markdown files 2025-04-10 16:12:43 +09:00
5446a1bee0
Update README.md
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-04-10 15:56:18 +09:00
10101986be
Update README.md
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-04-10 15:56:09 +09:00
47a5f50712
Update README.md
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-04-10 15:56:01 +09:00
86517f313c
Update README.md
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-04-10 15:55:48 +09:00
b6d34404b5 Update README.md 2025-04-10 13:50:37 +09:00
88ac0cd31e Update README.md 2025-04-10 13:41:57 +09:00
3e0fd7c532 Update README.md, SECURITY.MD 2025-04-10 13:39:23 +09:00
22d10cd28b
Merge pull request #235 from gnh1201/dev
Update SECURITY.MD
2025-04-10 13:29:19 +09:00
0e95b72b21 Update SECURITY.MD 2025-04-10 13:23:16 +09:00
426a9d7721
Merge pull request #234 from gnh1201/dev
Update 2025-04-10
2025-04-10 02:29:10 +09:00
d42210f922
Update WelsonJS.Toolkit/WelsonJS.Launcher/Program.cs
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-04-10 02:27:42 +09:00
e853003bda
Merge branch 'master' into dev 2025-04-10 02:26:21 +09:00
8ca4faa88a
Update README.md
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
2025-04-10 02:23:24 +09:00
f84f2195c3 Revert Cache Compression 2025-04-10 02:12:28 +09:00
1742ca385b Update AzureAi.cs 2025-04-10 02:00:18 +09:00
2a9ebaff51 Update AzureAi.cs 2025-04-10 01:48:33 +09:00
916154499c Some updates 2025-04-09 19:58:41 +09:00
53a84b2349 Update README.md 2025-04-07 14:45:25 +09:00
6e3eb5c1d3 Update README.md 2025-04-07 14:44:03 +09:00
4b4754ae16 Update README.md 2025-04-07 14:43:27 +09:00
a273d6aac6 Update README.md 2025-04-07 14:41:56 +09:00
9e1878628b Update README.md 2025-04-07 14:33:47 +09:00
04ce7fdae5 Update README.md, SECURITY.MD 2025-04-07 14:31:11 +09:00
f7de7bd430 Add Cache Compression 2025-04-06 15:23:19 +09:00
ab8a864519
Update README.md 2025-04-05 23:32:10 +09:00
427f8dded0
Update README.md 2025-04-05 23:24:54 +09:00
a96764f725
Update README.md 2025-04-05 23:24:17 +09:00
46d0244c34
Merge pull request #221 from gnh1201/dev
Add the cached blob #220
2025-04-05 20:13:40 +09:00
2cb3c1c331 Add the cached blob 2025-04-05 20:05:23 +09:00
231e6a56bd
Merge pull request #219 from gnh1201/dev
Change the remote blob server to localhost
2025-04-05 17:47:25 +09:00
295ad2fca8 Update ResourceServer.cs 2025-04-05 17:43:34 +09:00
9ecc93a399 Update ResourceServer.cs 2025-04-05 17:42:44 +09:00
2896cc6bf1 Some updates 2025-04-05 17:27:38 +09:00
be37951807 Add the blob server gateway 2025-04-05 17:10:19 +09:00
d38e26ba67
Merge pull request #218 from gnh1201/dev
Refactor an endpoints of the web based editor
2025-04-05 15:24:50 +09:00
dd85e98c9a Some updates 2025-04-05 15:16:15 +09:00
d8fa8779de Refactor an endpoints of the web based editor 2025-04-05 12:53:28 +09:00
f6fd43ae50
Merge pull request #214 from gnh1201/dev
Add Azure AI service (Azure AI Foundry), Add the AppConfig manager
2025-04-02 11:34:00 +09:00
96dbe7b2cd Add Azure AI service (Azure AI Foundry), Add the AppConfig manager 2025-04-02 11:25:23 +09:00
c1fe39d3cc
Merge pull request #213 from gnh1201/dev
Adapt a code review, SRI, CORS, etc.
2025-03-31 17:41:01 +09:00
56ee12741c some updates 2025-03-31 17:09:28 +09:00
4372bdb09d some updates 2025-03-31 16:59:56 +09:00
b21f967a6a Update bootstrap.bat 2025-03-31 16:31:07 +09:00
40b0b704e3 some updates 2025-03-31 15:06:03 +09:00
9a8ee4d7f9 some updates 2025-03-31 14:50:02 +09:00
4f319d474f some updates 2025-03-31 14:18:03 +09:00
93ed60bcf7 some updates 2025-03-31 14:16:35 +09:00
5d717505f4 Edit the codes from code review result 2025-03-30 22:24:35 +09:00
b0e50d33bc Merge branch 'dev' of https://github.com/gnh1201/welsonjs into dev 2025-03-30 21:12:10 +09:00
c0f9816000 Update editor.html 2025-03-30 20:50:54 +09:00
00ea473683 set SRI and CORS policy strictly to editor.html 2025-03-30 20:48:03 +09:00
7e9054fb8f
Merge pull request #203 from gnh1201/dev
Revert "Reduce SAS token period to 2 years"
2025-03-27 18:02:51 +09:00
f29a63027f Revert "Reduce SAS token period to 2 years"
This reverts commit e930cf86fd.
2025-03-27 17:55:13 +09:00
3419e62c6a
Merge pull request #202 from gnh1201/dev
Change the blob download server
2025-03-27 17:50:53 +09:00
e930cf86fd Reduce SAS token period to 2 years 2025-03-27 17:42:58 +09:00
c0a27efd8d Update bootstrap.bat 2025-03-27 17:35:10 +09:00
d42539c0a8
Update README.md 2025-03-26 11:44:37 +09:00
8389f755fd
Merge pull request #200 from gnh1201/dev
Update the assembly info
2025-03-23 16:02:36 +09:00
6d5af6d422 Update the assembly info 2025-03-23 15:55:45 +09:00
7738b3b898
Merge pull request #199 from gnh1201/dev
Add the mutex to avoid redundant
2025-03-23 15:31:28 +09:00
c1052e0147 Code consistency fix, Replace Random to RandomNumberGenerator, Mutex dispose 2025-03-23 15:12:15 +09:00
d3135bef8e Add the mutex to avoid redundant 2025-03-23 14:43:23 +09:00
54af38b6b6 Add TFA (TOTP) endpoint 2025-03-21 23:50:22 +09:00
9d4b7e535c
Merge pull request #198 from gnh1201/dev
Update setup.iss
2025-03-21 19:51:01 +09:00
8190c80f1a Update setup.iss 2025-03-21 19:39:28 +09:00
c887e1914d
Merge pull request #197 from gnh1201/dev
Update in 2025-03-21
2025-03-21 17:25:45 +09:00
394ce1e903 Update in 2025-03-21 2025-03-21 17:18:39 +09:00
d2cba59b6b Update in 2025-03-21
1. Remove PHP asset files. (Moved to github.com/gnh1201/caterpillar)
2. Add `ARM64` architecture support to lib/python3.js and lib/http.js files.
3. Update the installer profile
2025-03-21 12:03:12 +09:00
7a23340623
Merge pull request #196 from gnh1201/dev
Update http.js
2025-03-21 10:47:13 +09:00
5a2a48945b Update http.js 2025-03-21 10:26:54 +09:00
51da417506 Update http.js 2025-03-20 17:03:31 +09:00
a148319b44
Merge pull request #195 from gnh1201/dev
Update setup.iss
2025-03-20 13:24:31 +09:00
340794d14c Update setup.iss 2025-03-20 13:14:01 +09:00
f6b222e469
Merge pull request #194 from gnh1201/dev
Update the installer profile, Dns Query, and namespaces
2025-03-20 11:29:15 +09:00
fb17f37188 Update setup.iss 2025-03-20 11:15:37 +09:00
2450bc0b9c Update ResourceServer.cs 2025-03-20 11:02:33 +09:00
6737b4885b Update DnsQuery.cs 2025-03-20 10:11:29 +09:00
81d6e67f94 Update the namespaces 2025-03-20 09:42:38 +09:00
911be8135c
Merge pull request #193 from gnh1201/dev
Add DNS Query feature
2025-03-19 17:10:42 +09:00
e68c1e5e2f Add DNS Query feature 2025-03-19 17:03:06 +09:00
07e0665275
Merge pull request #192 from gnh1201/dev
Improve initial warming up time, and add WHOIS request feature
2025-03-19 16:02:23 +09:00
4e78905bbc Enhance a performance and security in PR 2025-03-19 15:48:12 +09:00
e2c9169121 Update editor.html, ResourceServer.cs 2025-03-19 14:02:12 +09:00
1f859c75c6 Improve initial start time, and Add WHOIS request 2025-03-19 12:10:00 +09:00
b2fdc38790
Merge pull request #191 from gnh1201/dev
Minor fixes
2025-03-17 17:53:41 +09:00
07991329fc Update editor.html 2025-03-17 17:47:44 +09:00
5cea33ec20
Merge pull request #190 from gnh1201/dev
Minor fixes
2025-03-17 17:40:37 +09:00
01e94830e7 Update editor.html 2025-03-17 17:23:55 +09:00
c8e757487e Update editor.html 2025-03-17 17:19:05 +09:00
9cd4f2d744
Merge pull request #189 from gnh1201/dev
Minor fixes for the context menus
2025-03-17 17:02:32 +09:00
2a2cdf8a4a Update MainForm.cs 2025-03-17 16:49:04 +09:00
4a46d6211c
Merge pull request #188 from gnh1201/dev
One more fixes for #187
2025-03-17 14:01:27 +09:00
98b9019633 Update editor.html 2025-03-17 13:54:38 +09:00
434f5d4a8d Update editor.html 2025-03-17 13:49:23 +09:00
46a3049d62 Update editor.html 2025-03-17 13:29:00 +09:00
be9ed37eea Update editor.html 2025-03-17 13:24:03 +09:00
dd978ab952
Merge pull request #187 from gnh1201/dev
LLM AI based code generation in the code editor
2025-03-17 12:39:46 +09:00
15b2e606b1 Some updates for optimization and security 2025-03-17 11:09:00 +09:00
0cbb22ac26 Add LLM AI code generation 2025-03-16 18:14:02 +09:00
11afb64706
Merge pull request #186 from gnh1201/dev
Update 2025-03-16
2025-03-16 15:50:52 +09:00
240a65e61c Update ResourceServer.cs 2025-03-16 15:37:26 +09:00
2da5051c5b Update ResourceServer.cs 2025-03-16 15:08:20 +09:00
1124dc5bf4 Add a setting to separate web browser user profiles. 2025-03-16 14:28:59 +09:00
b93d16669f Update ExecutablesCollector.cs 2025-03-16 04:33:39 +09:00
5ab1c97b79
Merge pull request #185 from gnh1201/dev
Add the code completion with Monaco Editor #183
2025-03-16 03:44:02 +09:00
0aceb0e86b Update ResourceServer.cs 2025-03-16 03:30:15 +09:00
dc06506276 Add the code completion with Monaco Editor #183
This update supports the ability to auto-completion executable file paths in the code editor through the list of software installed on the local computer.
2025-03-16 03:11:59 +09:00
7947d91c3a
Merge pull request #184 from gnh1201/dev
Add some code for #183 (Auto completion)
2025-03-15 00:55:40 +09:00
1f2a1e79b7 Update ResourceServer.cs 2025-03-15 00:46:07 +09:00
6722704859 Update ResourceServer.cs 2025-03-15 00:37:03 +09:00
96bd29c06a Adopt the comments of the AI reviewers 2025-03-15 00:23:20 +09:00
c6240fb793
Update codeql-analysis.yml 2025-03-15 00:13:02 +09:00
74ca7dcd6c
Update llm-code-review.yml 2025-03-15 00:12:27 +09:00
b1cabe9fbb Add some code for #183 2025-03-15 00:07:28 +09:00
6bb1dcc3f1
Merge pull request #182 from gnh1201/dev
Add the notify (tray) icon to Launcher
2025-03-14 17:59:20 +09:00
b3f75d3c53 Fix status code 2025-03-14 17:55:05 +09:00
4d26f504f8 Merge branch 'dev' of https://github.com/gnh1201/welsonjs into dev 2025-03-14 17:47:15 +09:00
4bc2a95c42 Add the notify (tray) icon to Launcher
Add the notify (tray) icon to Launcher
2025-03-14 17:46:38 +09:00
c382ffbf46
Update README.md
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2025-03-12 16:12:15 +09:00
6fa4f64e0b
Merge pull request #181 from gnh1201/dev
AI code review workflow test #180
2025-03-12 15:50:25 +09:00
6d601aa79f Update editor.html 2025-03-12 15:47:12 +09:00
4105b567ee Update editor.html 2025-03-12 15:03:43 +09:00
4fbd0970ed
Update llm-code-review.yml
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2025-03-11 14:54:29 +09:00
be782c1ebd Update codeql-analysis.yml 2025-03-10 10:43:21 +09:00
1982b0fc6b Update README.md 2025-03-10 10:28:08 +09:00
ff88f484f6
Update llm-code-review.yml
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2025-03-10 10:02:03 +09:00
e5c970bea1
Create llm-code-review.yml 2025-03-10 09:59:56 +09:00
653c44dbf6
Merge pull request #179 from gnh1201/dev
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Add the favicon.ico response when try a request
2025-03-10 00:33:14 +09:00
9213d18c90 Reduce complexity: Splitting the GetResource method into separate methods 2025-03-10 00:16:42 +09:00
7c19dd366f Add the favicon.ico response when try a request 2025-03-09 23:56:38 +09:00
39c1fbb29b
Update README.md 2025-03-09 18:44:03 +09:00
53124007c2
Update editor.html 2025-03-09 18:01:12 +09:00
fdc6062433
Update editor.html 2025-03-09 17:50:17 +09:00
bb3cd40012
Add the Monaco Editor to WelsonJS Launcher #137
Update editor.html
2025-03-09 17:17:54 +09:00
e9c6a493eb Add the Monaco Editor to WelsonJS Launcher #137
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2025-03-08 22:52:45 +09:00
24ba77d1f6
Update README.md
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2025-03-04 16:52:10 +09:00
a3c26a202d
Update README.md 2025-03-04 16:50:06 +09:00
e9a6e414c1
Update README.md 2025-03-04 16:49:51 +09:00
aa5f3c9b6c Add discord chat link
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2025-02-28 10:56:47 +09:00
1cf0a8920a Update README.md
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2025-02-26 22:16:24 +09:00
ba35b022c6 Update README.md 2025-02-26 22:15:29 +09:00
f68c7fd7bd Update README.md 2025-02-26 22:10:11 +09:00
e942f0b9e8 Add the global settings form 2025-02-26 22:01:57 +09:00
ac6cdb0d76
Update README.md
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2025-02-26 13:36:44 +09:00
16723acd97
Update README.md 2025-02-26 13:33:58 +09:00
b31a2d43bb
Update README.md 2025-02-26 13:19:57 +09:00
be6f4b027f
Update README.md 2025-02-26 13:14:18 +09:00
1e93dd22ce
Update README.md 2025-02-26 13:03:04 +09:00
64b2eb0f1b
Update README.md 2025-02-26 13:01:33 +09:00
a80c017206
Update README.md 2025-02-26 12:55:38 +09:00
913eb9f9bf
Update README.md 2025-02-26 12:54:35 +09:00
d9175b83a2
Update README.md 2025-02-26 12:53:06 +09:00
f6d112e38f
Update README.md
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2025-02-25 15:35:54 +09:00
40129f87e3
Update README.md
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2025-02-23 17:40:10 +09:00
e375ddf6f5 Add the toolstrip menu "Run as Administrator..." 2025-02-23 15:27:09 +09:00
51110e54b7 allow search an instances in the temporary folder
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2025-02-23 03:29:51 +09:00
7d2f76e2dd
Merge pull request #174 from eltociear/patch-1
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
docs: update README.md
2025-02-21 10:30:39 +09:00
Ikko Eltociear Ashimine
5590c81be5
docs: update README.md
minor fix
2025-02-21 03:30:08 +09:00
2c25eb2a43
Update README.md
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2025-02-20 21:49:19 +09:00
ece0054da6 Fix the letter case
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2025-02-20 14:25:39 +09:00
09e9cccc51 Change the toolkit binary download path 2025-02-20 14:19:54 +09:00
85a315eac7 Remove the detect Windows version because of syntax error 2025-02-20 14:11:22 +09:00
3349255d9a Update the .env file location 2025-02-20 13:54:59 +09:00
c4be361f95 Fix instance data survival time issue
The data in the Temp directory has a short retention period, posing a risk of data loss. Therefore, it has been changed to the AppData directory.
2025-02-20 12:57:53 +09:00
432fd39df2 Update bootstrap.bat
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2025-02-18 12:53:52 +09:00
b31add8d74 Update language-inference-engine.js
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2025-02-15 16:09:39 +09:00
e659c8daf2 Update installService.bat
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2025-02-11 23:00:27 +09:00
62ab354674 Update installService.bat
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2025-02-11 17:17:51 +09:00
8285825c8b Update test.html 2025-02-11 17:00:43 +09:00
e1ebb0ac2a Update test-oss-korea-2023.json 2025-02-11 16:53:26 +09:00
1aa575b13c Revert "Update test-oss-korea-2023.json"
This reverts commit 0f2e874a4a.
2025-02-11 16:50:42 +09:00
0f2e874a4a Update test-oss-korea-2023.json 2025-02-11 16:40:20 +09:00
c9578ae9f1 Update test.html 2025-02-11 16:36:53 +09:00
a4a7391de6 Fix test page error 2025-02-11 16:35:29 +09:00
495944a3b6
Update router.js 2025-02-11 16:25:13 +09:00
477848b77f Update InstancesForm.Designer.cs
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2025-02-09 22:42:16 +09:00
a3289cc81d Fix some bugs 2025-02-09 22:05:43 +09:00
4fd38e75c3 Add the list of instances
This commit allows restoring and rerunning previously deployed instances.
2025-02-09 21:41:21 +09:00
5a09d7a79a Add support the Content-Type based URI router
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Add support the Content-Type based URI router
2025-02-08 21:45:43 +09:00
b912ae0b08 Update apikey.json
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2025-02-07 23:47:17 +09:00
eacd68ce88 Update language-inference-engine.js 2025-02-07 23:41:11 +09:00
2251494a48 Update language-inference-engine.js
1. Fix mistypos (e.g.., missing return)
2. Add clovastudio LLM
2025-02-07 23:35:25 +09:00
5b092c7f7a Update README.md
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2025-02-03 16:42:50 +09:00
4d78bbf31e Update README.md 2025-02-03 16:42:43 +09:00
1c4e607d3d Update README.md 2025-02-03 16:36:03 +09:00
80de6da382 Update README.md 2025-02-03 16:21:51 +09:00
3edff1550c Update README.md 2025-02-03 16:12:21 +09:00
724b89f361 Update README.md 2025-02-03 16:00:03 +09:00
06a09fbc3e
Update language-inference-engine.js
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2025-01-31 15:55:41 +09:00
2c2696d75f
Update README.md 2025-01-31 13:12:49 +09:00
36d51749b3
Update README.md 2025-01-31 13:10:07 +09:00
ac84bb222d
Update README.md 2025-01-31 13:03:19 +09:00
7c87f25f25
Update README.md 2025-01-31 13:00:20 +09:00
a2123f8765 Update README.md
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2025-01-30 23:39:19 +09:00
2078b45566 Update language-inference-engine.js 2025-01-30 23:33:35 +09:00
a7a00a38d8 Update language-inference-engine.js 2025-01-30 23:28:44 +09:00
a5275388e2 Update language-inference-engine.js 2025-01-30 23:28:28 +09:00
b5704d5746 Update language-inference-engine.js 2025-01-30 23:15:58 +09:00
ee038c6c20 Update README.md
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2025-01-30 19:54:10 +09:00
827dea443c Update README.md 2025-01-30 19:53:39 +09:00
3cf7f6c07c Update language-inference-engine.js 2025-01-30 19:47:30 +09:00
408e98e46b Update README.md 2025-01-30 19:14:11 +09:00
2878eac81d Update README.md 2025-01-30 19:06:47 +09:00
60a26b3ad0 Update language-inference-engine.js 2025-01-30 18:59:04 +09:00
4c8a127ad3 Update language-inference-engine.js 2025-01-30 17:12:22 +09:00
3f993975eb Merge branch 'master' of https://github.com/gnh1201/welsonjs
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2025-01-29 18:41:25 +09:00
68e7e4aec0 Update language-inference-engine.js 2025-01-29 18:24:32 +09:00
e7031baf0b
Update test-oss-korea-2023.json 2025-01-29 18:13:46 +09:00
7d3659ebce Update README.md 2025-01-29 18:07:30 +09:00
a1e254ceb0 Update README.md 2025-01-29 18:06:25 +09:00
0f1c2f3e85 Update README.md 2025-01-29 18:05:35 +09:00
6496da9b7e Update language-inference-engine.js 2025-01-29 17:41:29 +09:00
8699d89694 Update language-inference-engine.js 2025-01-29 17:22:55 +09:00
fb947cc777 Update LIE(Language Inference Engine) integraton of the app.js
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2025-01-28 09:53:55 +09:00
fe5542a521 Update language-inference-engine.js 2025-01-28 09:46:45 +09:00
47bb893c49 Update language-inference-engine.js 2025-01-28 09:38:23 +09:00
0485412b52 Update apikey.json
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2025-01-28 00:19:06 +09:00
ab2f3df4ea Update language-inference-engine.js 2025-01-28 00:02:22 +09:00
df92b4c58e Create language-inference-engine.js 2025-01-27 23:48:34 +09:00
88e6bd27b2 Change the script URLs
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2025-01-22 14:28:02 +09:00
b640786f62 Create hanoi.ai.js 2025-01-22 13:55:45 +09:00
1c3a367b18
Update README.md
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2025-01-20 12:05:41 +09:00
8a2a4c4760 Update chatgpt.js 2025-01-20 10:18:10 +09:00
e585b3e2d4 Update app.js 2025-01-20 10:11:04 +09:00
94601cbf4f Update app.js 2025-01-20 10:06:21 +09:00
905b56beb2 Allow load script from ChatGPT (LLM based AI) service 2025-01-20 10:04:49 +09:00
1337320803
Update README.md
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2025-01-17 16:17:45 +09:00
1e3389acf4
Update README.md 2025-01-17 14:13:44 +09:00
74005364e2 Add Grok (x.ai) interface 2025-01-17 14:04:35 +09:00
1cea720a70
Update README.md
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2025-01-15 17:57:15 +09:00
eeb0d0bc19
Update README.md 2025-01-15 17:56:47 +09:00
9d47a18325
Update testloader.js 2025-01-15 16:18:06 +09:00
81f196eed2
Update test-misc.json 2025-01-15 16:09:37 +09:00
8adaf4bdb9
Update test-misc.json 2025-01-15 16:09:26 +09:00
daf7db76b6
Update ovftool.js 2025-01-15 15:38:25 +09:00
38b03fe026 Update shell.js, ovftool.js 2025-01-15 15:18:36 +09:00
e2582447cc Update shell.js 2025-01-15 14:56:14 +09:00
6babec9d6b Update shell.js 2025-01-15 14:56:01 +09:00
a5dce5b55d Update shell.js 2025-01-15 14:42:58 +09:00
babfbe4e38 Update .gitignore 2025-01-15 14:00:57 +09:00
c9f03a5e23 Update shell.js, ovftool.js 2025-01-15 13:58:54 +09:00
f9f35da4d4 Create ovftool.js
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2025-01-13 15:13:25 +09:00
dd3ebc16df Update the credential management 2025-01-13 14:46:48 +09:00
3120a5ea93
Update README.md 2025-01-13 10:59:45 +09:00
8571ec4d00 Update ip-reputation.js
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2025-01-10 13:29:05 +09:00
1c6d306760 Create lib/ip-reputation.js 2025-01-10 13:28:46 +09:00
9262d83fd5
Update SECURITY.MD 2025-01-09 16:59:31 +09:00
b682f8fc34
Update bootstrap.bat 2025-01-09 16:03:00 +09:00
e1720c5bcf
Update bootstrap.bat 2025-01-09 14:05:48 +09:00
a78581ee69
Update bootstrap.bat 2025-01-09 14:03:13 +09:00
4eb2d4ae06
Update bootstrap.bat 2025-01-09 13:58:48 +09:00
fdd5c74df5
Update README.md 2025-01-09 11:33:35 +09:00
1857712df4
Update README.md 2025-01-09 11:02:08 +09:00
c5ebf36274
Update README.md 2025-01-09 11:01:43 +09:00
8c2d403502
Update README.md 2025-01-08 17:42:29 +09:00
ec92b9605f
Update README.md 2025-01-06 15:06:19 +09:00
c0e8f92e84
Update README.md 2025-01-01 21:19:01 +09:00
fe4d0d562e Add the server-side script files 2025-01-01 21:12:42 +09:00
58e9bdc4ab Add DEFAULT_JSONRPC2_URL variable to lib/jsonrpc2.js 2025-01-01 19:51:11 +09:00
638b172e77 Fix a proxy services and HTTP request issues
1. Separated the data listing available HTTP proxy services into a separate file. (data/available_proxies.json)
2. Excluded the architecture of the user's PC (e.g., 32-bit, 64-bit) from the User-Agent in HTTP requests.
2025-01-01 19:18:40 +09:00
79295de4ce
Update README.md
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-12-30 13:23:16 +09:00
37aa3ea406
Update README.md 2024-12-30 13:22:08 +09:00
1c9e77f890 Create fix_wsh_js_engine_not_found.reg
Fix: Input Error: There is no script engine for file extension ".js".
해결: 입력 오류: 파일 확장자 ".js"에 해당하는 스크립트 엔진이 없습니다.
2024-12-30 13:17:54 +09:00
da153a7900
Update README.md 2024-12-29 06:27:26 +09:00
7903a38f61
Update aviation.js 2024-12-27 15:04:08 +09:00
a99f1c396f
Update testloader.js 2024-12-27 14:55:46 +09:00
5a5526df63
Update anthropic.js 2024-12-27 14:53:17 +09:00
46c5a91032
Update chatgpt.js 2024-12-27 14:52:17 +09:00
e9ba3cff96
Update apikey.json 2024-12-27 14:49:25 +09:00
b4ace286e3
Create apikey.js 2024-12-27 14:49:01 +09:00
7aeb8edfc2
Update apikey.json 2024-12-27 14:34:57 +09:00
31792ebecd
Update apikey.json 2024-12-27 14:33:41 +09:00
7dcd82e7b9
Create apikey.json 2024-12-27 14:33:21 +09:00
fc4d74b7ac
Update std.js 2024-12-27 14:11:15 +09:00
98ff88ffff
Update browser.js 2024-12-27 14:08:56 +09:00
a3fa1a558e Update task-scheduler.js
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-12-22 03:27:35 +09:00
bf6fa1c044 Create task-scheduler.js 2024-12-22 03:26:41 +09:00
8a185cb048 Add a fast-track consultation channels
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-12-20 17:57:44 +09:00
4d6239b606
Merge pull request #168 from chasca8/master
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Update test-oss-korea-2023.json
2024-12-20 15:39:46 +09:00
78445aa4dc
Merge branch 'master' into master 2024-12-20 15:36:56 +09:00
4a9f5a7fd8
Update data/test-oss-korea-2023.json
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2024-12-20 15:20:37 +09:00
e1d2d3e9ff
Update data/test-oss-korea-2023.json
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2024-12-20 15:20:04 +09:00
7ee1e2b745
Update data/test-oss-korea-2023.json
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2024-12-20 15:19:39 +09:00
Scarlet
442d081f9d
Update test-oss-korea-2023.json 2024-12-18 21:26:03 +09:00
Scarlet
36da5ec3a1
Update virustotal.js 2024-12-18 19:07:17 +09:00
Scarlet
f49ba40cb9
Update test-oss-korea-2023.json 2024-12-18 18:20:48 +09:00
a886363603
Merge pull request #166 from gnh1201/revert-165-master
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Revert "Update test-oss-korea-2023.json"
2024-12-18 14:02:57 +09:00
dee6ed1025
Revert "Update test-oss-korea-2023.json" 2024-12-18 14:02:40 +09:00
d8d67ac4c0
Merge pull request #165 from chasca8/master
Update test-oss-korea-2023.json
2024-12-18 13:58:05 +09:00
Scarlet
b400c8d64d
Update test-oss-korea-2023.json 2024-12-17 20:53:53 +09:00
Scarlet
98e2c6c837
Update test-oss-korea-2023.json 2024-12-17 12:03:26 +09:00
a947432134 Update README.md
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-12-12 15:30:22 +09:00
1d0f4172fb Update README.md 2024-12-12 15:28:32 +09:00
06972c2bd1 Update README.md 2024-12-12 15:27:45 +09:00
eccd60c340 Update README.md 2024-12-12 15:26:37 +09:00
c1f9249252 Update aviation.js 2024-12-12 14:36:16 +09:00
c14f4358f3 Add aviation.js, Updatre http.js 2024-12-12 14:22:00 +09:00
2dae3a3abb Update http.js 2024-12-12 13:43:41 +09:00
7d6046624c Update README.md
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-12-11 14:27:28 +09:00
de4016100a Update AnsiX923Padding.cs, PKCS5Padding.cs
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-12-10 18:31:31 +09:00
3ed38eec6a Add error handling flags for AnsiX923Padding, and PKCS5Padding 2024-12-10 17:50:10 +09:00
7ef4437447 Add LEA cryptography algorithm 2024-12-10 16:48:48 +09:00
9c662177ec Update ARIA.cs
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-12-09 17:18:54 +09:00
d6540f1351 Change MD5 to SHA256 in the CreateKey method 2024-12-09 17:17:39 +09:00
1b31859786 Update ARIA.cs 2024-12-09 17:13:58 +09:00
ca857d70eb Update ARIA.cs 2024-12-09 16:55:03 +09:00
eaa52e40a6 Add ARIA cryptography algorithm 2024-12-09 16:50:43 +09:00
5ba8744f6c Update SEED.cs
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-12-06 01:36:31 +09:00
92b3907a8e Clean HIGHT.cs 2024-12-06 00:51:07 +09:00
a95e7e3e0d Update SEED.cs 2024-12-06 00:30:31 +09:00
7a8ef89f09 Update SEED.cs 2024-12-05 18:52:33 +09:00
3b022d68a4 Update SEED.cs 2024-12-05 18:21:21 +09:00
eaa33e3b7b Update SEED.cs 2024-12-05 18:14:24 +09:00
ea78f08710 Update SEED.cs
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-12-05 17:56:11 +09:00
6fa089a854 Update SEED.cs 2024-12-05 17:45:16 +09:00
ba73fddba5 Update SEED.cs 2024-12-05 17:31:21 +09:00
ff0ab03630 Add the SEED cryptography algorithm (Experimental) 2024-12-05 17:24:06 +09:00
7ba17435ac
Update README.md
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-12-04 10:25:20 +09:00
5852e987c6
Update README.md 2024-12-03 19:32:32 +09:00
9b4273e370 Update SECURITY.MD 2024-12-02 19:34:19 +09:00
4e6b9ea086 Update SECURITY.MD 2024-12-02 19:33:10 +09:00
caa56cedb8 Update archive.js 2024-11-29 16:54:53 +09:00
701be4c351 Create archive.js 2024-11-29 16:53:31 +09:00
2ba05aa633 Update lib/punycode.js, lib/totp.js 2024-11-28 21:11:17 +09:00
f00e6eed1e
Update totp.js 2024-11-28 14:13:14 +09:00
81592beb64
Update totp.js 2024-11-28 14:10:28 +09:00
ebdc212afb
Update std.js 2024-11-27 19:26:25 +09:00
b880e7a13d
Update std.js 2024-11-27 19:25:01 +09:00
ce10ac7f7b Update std.js 2024-11-27 16:47:59 +09:00
9012a161c3 Update std.js, README.md, SECURITY.md 2024-11-27 16:45:53 +09:00
9038829f24 Remove the Public API URL
The Public API was proposed for the next version (0.2.7.54), but due to the increased security risks of providing an unauthenticated Public API, the Public API URL is being discontinued.

This service will be available in the future through marketplaces offered by cloud platforms. Additionally, as the server-side script is open-source, you can set it up yourself.

https://github.com/gnh1201/caterpillar
2024-11-27 15:36:35 +09:00
116bd84394
Update totp.js
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-11-26 02:46:06 +09:00
69d7d3c632
Update totp.js 2024-11-26 02:03:15 +09:00
400e904aa9 Update totp.js 2024-11-26 01:49:36 +09:00
27f4dc2084 Update totp.js 2024-11-26 01:42:39 +09:00
2ac75fd24e Add TOTP library 2024-11-26 01:41:21 +09:00
8ddff1cf94 Add the security notice to LLM integration libraries
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-11-25 20:55:47 +09:00
b1428867dc Update the Punycode Public API client 2024-11-25 16:15:14 +09:00
f2044bcfbf Ready use the JSON-RPC 2.0 based stateless proxy
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-11-24 03:15:37 +09:00
b5bc2bd851 Update jsonrpc2.js 2024-11-24 02:20:44 +09:00
b45a7cdd6c Ready use the JSON-RPC 2.0 based stateless proxy 2024-11-23 21:50:32 +09:00
ac31e5e884 Ready use the JSON-RPC 2.0 based stateless proxy 2024-11-23 21:44:03 +09:00
43b5781cbd Ready use the JSON-RPC 2.0 based stateless proxy 2024-11-23 21:26:04 +09:00
3fa72f86d6 Ready use the JSON-RPC 2.0 based stateless proxy 2024-11-23 21:10:06 +09:00
8942a98431 Update http.js 2024-11-23 19:06:43 +09:00
8bb0f68049 Update the search engines 2024-11-23 18:58:29 +09:00
d3743e206c
Update README.md
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-11-20 19:30:27 +09:00
4fe98d32a1
Update README.md 2024-11-20 18:47:20 +09:00
1fc0597f93
Update README.md
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-11-20 01:17:48 +09:00
0f57fba805 Update std.js
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-11-19 17:01:56 +09:00
2f74ceb013
Update README.md
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-11-19 15:31:35 +09:00
009b171946
Update README.md
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-11-18 20:03:16 +09:00
895bfe1ac8
Update README.md 2024-11-18 19:59:04 +09:00
3033382f64
Update README.md 2024-11-18 16:43:10 +09:00
fd21f2faae
Update README.md 2024-11-18 16:40:58 +09:00
5e1f41b48a Update app.js 2024-11-15 05:27:22 +09:00
b98901c75a Update app.js 2024-11-15 05:24:49 +09:00
9b50e5b078 Rename some files 2024-11-15 04:05:06 +09:00
d9ac6d01d0 Update README.md 2024-11-15 03:51:50 +09:00
57fbb16bd8 Add Advanced Mathematics Test 2024-11-15 03:48:19 +09:00
13a8c94bcf Add library numbers 2024-11-15 02:40:58 +09:00
0d6e2076d6
Rename FUNDING.yml to .github/FUNDING.yml 2024-11-13 16:23:47 +09:00
f6b04faea6
Update README.md 2024-11-13 16:06:55 +09:00
eedac13818
Update README.md 2024-11-13 16:03:38 +09:00
d45c21cf24
Delete lib/archive.js 2024-11-13 13:48:16 +09:00
54a1515bcb
Update README.md 2024-11-11 06:12:38 +09:00
4477ef84bf
Update archive.js 2024-11-08 00:07:06 +09:00
4370f40886
Create archive.js 2024-11-08 00:06:33 +09:00
fe2466b49a Update package.json 2024-11-07 23:39:51 +09:00
a8b54493f7
Update app.js 2024-11-06 16:31:37 +09:00
2ee54f77ae
Update FUNDING.yml 2024-11-06 16:21:25 +09:00
187578861b
Update FUNDING.yml 2024-11-06 16:16:27 +09:00
a0420cd10f
Update FUNDING.yml 2024-11-06 16:12:53 +09:00
2f1a0f6e41 Add support the Groq LLM API 2024-11-06 04:17:56 +09:00
6d0a6c645f Add README.md to WelsonJS.Toolkit 2024-11-05 21:03:41 +09:00
55d34f833d Update .appveyor.yml 2024-11-05 20:45:21 +09:00
a0e9a83ddd Update .appveyor.yml 2024-11-05 20:36:30 +09:00
9a35227728 Update WelsonJS.Toolkit.nuspec 2024-11-05 20:35:09 +09:00
af69d66ea9 Update the nuspec file 2024-11-05 20:33:50 +09:00
2487e56847 Merge branch 'master' of https://github.com/gnh1201/welsonjs 2024-11-05 20:01:50 +09:00
5b264b64fd Change the API name DecryptStringHIGHT to DecryptString and EncryptStringHIGHT to EncryptString 2024-11-05 20:01:34 +09:00
ce7a0034be
Update README.md 2024-11-05 14:29:17 +09:00
a8a13b539c Update ScreenMatch.cs 2024-11-04 03:55:11 +09:00
b2975e053c Update ScreenMatch.cs 2024-11-04 03:24:42 +09:00
41fcb8706f Update README.md 2024-11-04 02:22:15 +09:00
3fc6f19227 Update README.md 2024-11-04 02:18:21 +09:00
3e78e0b5d2 Fix bugs related to the settings and logger 2024-11-04 02:04:02 +09:00
020f99c5b2 Update MainForm.cs 2024-11-04 01:22:33 +09:00
3989eeba45 Add Anthropic API integration 2024-11-04 00:32:25 +09:00
412c72f624 Change the application name to lowercase when used in logging 2024-11-02 04:03:01 +09:00
30c0e20eae fix #154 (Migrate parent.Log() to Microsoft.Extensions.Logging)
Migrate parent.Log() to Microsoft.Extensions.Logging
2024-11-02 03:51:07 +09:00
53bc51a3af Update README.md 2024-10-24 23:20:45 +09:00
f95b769f11 Update README.md 2024-10-23 20:55:31 +09:00
5d8e195635 Update README.md 2024-10-23 20:48:11 +09:00
a60d0649c0 Move the images of README.md to ics.catswords.net 2024-10-23 20:45:40 +09:00
377d2bdd71 Update README.md 2024-10-23 18:15:34 +09:00
64fec9583d Remove unnecessary images 2024-10-23 18:08:19 +09:00
9b6637a697 Update README.md 2024-10-23 18:02:35 +09:00
af096d38b8 Update README.md 2024-10-23 18:01:11 +09:00
7eb960c711 Update README.md 2024-10-23 18:00:37 +09:00
a98c1cbc92 Update README.md 2024-10-23 17:58:47 +09:00
53970f97a1 Update README.md 2024-10-23 17:53:59 +09:00
9193df71b7 Merge branch 'master' of https://github.com/gnh1201/welsonjs 2024-10-23 17:53:22 +09:00
d180a01312 add nuget profile, update README.md 2024-10-23 17:53:12 +09:00
7f13b67f70
Update README.md 2024-10-23 15:32:21 +09:00
c9360c6651
Update README.md 2024-10-23 15:31:53 +09:00
489e10b76e
Update README.md 2024-10-22 18:22:48 +09:00
28be18de01 Update ScreenMatch.cs 2024-10-21 04:49:48 +09:00
c03a8011c2 Update ScreenMatch.cs 2024-10-21 04:16:46 +09:00
06731f4d4b Update ServiceMain.cs 2024-10-21 02:16:11 +09:00
44de5bfd1a
Update testloader.js 2024-10-20 00:07:53 +09:00
a00d43a59e
Update ScreenMatch.cs 2024-10-19 23:28:16 +09:00
9783e55069
Update extramath.js 2024-10-19 23:17:34 +09:00
3b101e177e
Update README.md 2024-10-19 21:04:34 +09:00
08b10b4e4a
Update http.js 2024-10-19 20:49:16 +09:00
65d5ee120b
Update README.md 2024-10-18 22:24:55 +09:00
2fc9b11aa6
Update README.md 2024-10-18 21:41:51 +09:00
feb85625c5 Update ScreenMatch.cs
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-10-15 05:22:07 +09:00
e1d4df74b9 Update defaultService.example.js
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-10-15 03:00:06 +09:00
6eaeab5c24 Update the dotnet dependencies 2024-10-15 02:26:35 +09:00
b93c6cd48b fix .env support
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-10-14 04:52:22 +09:00
94afeb406a Add some code to add the .env support
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-10-14 04:38:18 +09:00
9e623b645f
Update README.md
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-10-12 09:41:44 +09:00
4f92b782e9
Update README.md
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-10-08 16:25:59 +09:00
16427b347f
Update README.md 2024-10-08 15:49:22 +09:00
ea6add25ca
Update http.js 2024-10-08 15:24:24 +09:00
89e3704f33 Apply the color level based quantization 2024-10-08 14:59:04 +09:00
736356fe71 Check if the position of a specific template image has changed using previously extracted sample images.
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-10-07 03:39:28 +09:00
89dc45ac7c
Update SECURITY.MD
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-10-07 00:01:38 +09:00
c3d4250094
Update README.md 2024-10-06 22:04:22 +09:00
5357ec167a Update the Thanks to links
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-10-05 19:18:16 +09:00
7824de743f Update screenshot6.png
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-10-04 20:19:34 +09:00
adce996aae Update MainForm.cs 2024-10-04 17:01:02 +09:00
2e334ec12e
Merge pull request #150 from gnh1201/envform
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Add the user variables editor and update related files
2024-10-04 15:11:17 +09:00
641c2070a4 Update MainForm.cs, HeartbeatClient.cs 2024-10-04 15:09:05 +09:00
86916d2ed9 Add --user-variables-file parameter when starting a service 2024-10-03 22:56:04 +09:00
c157116680 Use the user variables in the screen matching feature 2024-10-03 22:27:26 +09:00
1a8c93627a Update EnvForm.cs 2024-10-03 21:23:51 +09:00
ee5f503e42 Add import and export feature 2024-10-03 20:58:42 +09:00
c4c7d5480b Update EnvForm.cs 2024-10-03 20:27:41 +09:00
06cb5095b2 Update the env form 2024-10-03 19:48:05 +09:00
f9ddd3b95e Add the env form 2024-10-03 18:09:14 +09:00
740f392c95
Update README.md
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-10-03 14:40:04 +09:00
be336e6e06 Update the favicon on the launcher app 2024-10-03 14:24:59 +09:00
2318092542 Update README.md 2024-10-03 13:57:09 +09:00
3964f081de Update README.md 2024-10-03 13:56:41 +09:00
ec451f633b Update favicon.ico and related files
New favicon designed by @druidesse
2024-10-03 13:55:26 +09:00
5a7165d142
Update README.md
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-10-02 14:36:47 +09:00
94183f1e60
Update http.js
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-09-28 16:44:43 +09:00
8300e1dba4
Update http.js 2024-09-28 16:44:27 +09:00
d413cb49b4
Update http.js 2024-09-28 16:36:38 +09:00
7babc6bad7
Update http.js 2024-09-28 16:26:47 +09:00
7e3a6bdf45
Update http.js 2024-09-28 16:24:24 +09:00
bd51f1d8e1
Update http.js 2024-09-28 16:23:39 +09:00
fac76f9328 Update README.md 2024-09-27 21:23:48 +09:00
8285eee3c1 Update testloader.js 2024-09-27 21:00:53 +09:00
a36dd8e257 Update lib/http.js, testloader.js 2024-09-27 20:53:29 +09:00
1e7061efae Update README.md 2024-09-27 16:34:13 +09:00
072110f282 Update README.md 2024-09-27 16:32:13 +09:00
3ecd35c4a6 Update README.md 2024-09-27 16:19:33 +09:00
b71366bac7 Add SearchAPI.io to README.MD 2024-09-27 16:17:15 +09:00
c6f614b106 Update testloader.js 2024-09-27 15:55:31 +09:00
a60e7e5d9e fix #145
* Fix #145
* Change the methods and variables `CharsetDetector` to `DetectCharset`
* Add searchapi.io SERP support
2024-09-27 15:53:19 +09:00
ad6cb7e430 Update README.md 2024-09-27 10:46:39 +09:00
e95275fa35 Update README.md 2024-09-27 10:44:26 +09:00
099e95bfd3 Update README.md 2024-09-27 10:22:09 +09:00
3c57828f3a Update README.md 2024-09-27 10:18:32 +09:00
6a4a94f486 Update README.md 2024-09-27 10:06:35 +09:00
27a0a0f5d7 Update README.md 2024-09-27 10:03:38 +09:00
dac6e7c5b1 Update README.md 2024-09-26 20:56:34 +09:00
80450467fc Update README.md 2024-09-26 20:47:00 +09:00
ff3cbd88dd Fix the Tab UI bug, and fix stdout/stderr clear issue 2024-09-26 19:35:43 +09:00
c411f596f9 Update webloader.js and the screenshot 2024-09-26 18:45:23 +09:00
a0933153ba Change the screenshot and the example log message 2024-09-26 18:35:25 +09:00
f03c0ef913 Change the screenshot and add ui components example page 2024-09-26 18:32:38 +09:00
f3a79a3523 Update README.md 2024-09-26 15:49:14 +09:00
f18cf9b859 Add support Tab UI with golden layout 2024-09-26 15:46:07 +09:00
bf66ef6354 Update README.md 2024-09-26 02:00:48 +09:00
330323f0c2 Update testloader.js 2024-09-26 01:26:06 +09:00
b82f00748a
Update README.md 2024-09-25 23:09:31 +09:00
0f7e74a5e2 Update README.md 2024-09-25 22:36:31 +09:00
4db50b12ca Add the partnerships section to README.md 2024-09-25 22:34:25 +09:00
abe59228be fix and test ok #143 2024-09-25 18:21:55 +09:00
3842d1bea8 Update http.js 2024-09-25 16:12:19 +09:00
4f1154f412 Add support ARM architecture (lib/http.js) 2024-09-25 16:11:41 +09:00
ce440ae7f7 Update websocket.js 2024-09-25 16:00:41 +09:00
124ea0ae30 Merge branch 'master' of https://github.com/gnh1201/welsonjs 2024-09-25 15:53:11 +09:00
4327651e1d Update http.js 2024-09-25 15:52:47 +09:00
f1e45f01bb Change the default binary path (lib/http,js, lib/websocket.js) 2024-09-25 15:52:08 +09:00
5e6e3e30ba
Update certchecker.js 2024-09-25 14:46:53 +09:00
266971f5d3 fix #144 2024-09-25 14:12:19 +09:00
ed3b631b30 Update testloader.js 2024-09-25 12:10:47 +09:00
7389131bdc Update README.md 2024-09-23 23:27:06 +09:00
f9302f50ee Update README.md 2024-09-23 23:19:35 +09:00
13bcbbbb15 Update README.md 2024-09-23 23:16:03 +09:00
27f4b24344 Merge branch 'master' of https://github.com/gnh1201/welsonjs 2024-09-23 22:53:40 +09:00
9a7cc6de38 Add the github octocat logo 2024-09-23 22:40:48 +09:00
15e31d60e6
Update README.md 2024-09-23 22:35:46 +09:00
528a9c93a4 Update README.md 2024-09-23 22:34:21 +09:00
7823a0a9b5 Add signpath logo 2024-09-23 22:32:57 +09:00
193fcb16c2
Update README.md 2024-09-23 22:29:45 +09:00
646c4babaa Update .appveyor.yml 2024-09-23 22:21:15 +09:00
f2e62d6602
Update README.md 2024-09-23 02:27:03 +09:00
8d5f88a488 Update MainForm.cs 2024-09-23 02:06:49 +09:00
c7af90896b Update http.js 2024-09-23 01:47:46 +09:00
b3bb9ba28c
Update http.js 2024-09-22 20:59:51 +09:00
54e7bb77f6
Update http.js 2024-09-22 00:15:01 +09:00
78a65f906e
Update http.js 2024-09-22 00:10:04 +09:00
9f8e930a45
Update http.js 2024-09-21 14:22:57 +09:00
5f91e9be12
Update http.js 2024-09-21 14:18:42 +09:00
e575f41a19
Update http.js 2024-09-21 14:14:43 +09:00
13cb1da59d
Update http.js 2024-09-21 14:12:39 +09:00
05874f90e5
Update http.js 2024-09-21 14:08:29 +09:00
25876bd81f Merge branch 'master' of https://github.com/gnh1201/welsonjs
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-09-20 23:41:33 +09:00
96c57b0daa Add keep_headers parameter #143 2024-09-20 23:41:04 +09:00
af395bf4ac
Update README.md #143 2024-09-20 23:27:27 +09:00
611c70a1ff
Update README.md 2024-09-20 23:26:30 +09:00
9730b639b9 Update the proxy API services #143 2024-09-20 23:21:37 +09:00
de6b70a5b1 Add the proxy API services #143 2024-09-20 23:10:30 +09:00
e7f65d50b0 Update ScreenMatch.cs and related files
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-09-20 16:53:50 +09:00
855cf6adef Update defaultService.example.js, .gitignore 2024-09-20 11:50:29 +09:00
5e82c58873 Update defaultService.example.js
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-09-20 10:56:28 +09:00
4b63596c3a Update ServiceMain.cs 2024-09-20 10:50:11 +09:00
8734f3f24a Update ScreenMatch.cs, ServiceMain.cs 2024-09-20 10:32:43 +09:00
c0e42480e0 Update ScreenMatch.cs 2024-09-20 09:36:44 +09:00
0742f17f2a Add the Bitmap Comparison with CRC32 hashing
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-09-19 03:29:43 +09:00
12ce97c385 Update ScreenMatch.cs
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-09-18 15:51:24 +09:00
c36d7fb71f Update ScreenMatch.cs 2024-09-18 15:01:05 +09:00
27e9a328d4 Save file in the droptop coffee 2024-09-18 14:33:15 +09:00
83efe8a156 Create fsm.js
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-09-18 03:32:10 +09:00
ec278ade7b Update .gitignore
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-09-17 23:44:30 +09:00
e38e3fb088 Rename defaultService.js to defaultService.example.js 2024-09-17 23:42:04 +09:00
9cdd9e85ed fix (Happy Chuseok) 2024-09-17 22:22:46 +09:00
775ffb924d
Update SECURITY.MD
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-09-15 23:30:40 +09:00
efd35cd273
Update README.md 2024-09-15 23:29:51 +09:00
4144679db7 Add the event listener onAvScanResult
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-09-15 02:54:18 +09:00
f7b1461cc5 Add to ClamAV integration to the File Event Monitor
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-09-14 22:33:58 +09:00
93ea20cf25 Update settings.example.ini 2024-09-14 20:18:10 +09:00
13d7b821be
Update README.md
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-09-10 14:42:11 +09:00
8db76f49ae Update FileEventMonitor.cs
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-09-09 17:13:07 +09:00
bc74515095 Update FileEventMonitor.cs 2024-09-09 17:10:31 +09:00
672a3637de Add event type: registry modification 2024-09-09 17:09:31 +09:00
91b73186d3 Fix the FileEventMonitor.cs 2024-09-09 16:47:51 +09:00
a18229afea Revert "Update app.js, defaultService.js"
This reverts commit c24166b36d.
2024-09-09 16:42:48 +09:00
c24166b36d Update app.js, defaultService.js 2024-09-09 15:28:33 +09:00
40edee2b83 Remove libyara.NET and a little fixes for sysmon events 2024-09-09 15:26:16 +09:00
671007bb79 Update FileEventMonitor.cs and related files
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-09-09 12:05:39 +09:00
bdee21a66f Update ScreenMatch.cs
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-09-06 17:04:15 +09:00
6f3153a816 Update ScreenMatch.cs, settings.example.ini 2024-09-06 17:03:11 +09:00
a69603a10c Add options to the screen time 2024-09-06 16:42:15 +09:00
28435522de Update ScreenMatch.cs 2024-09-06 16:10:58 +09:00
da08bb7bb9
Merge pull request #139 from soumt-r/grpc_fix
heartbeat grpc service
2024-09-06 15:35:14 +09:00
Soumt
126169e37c fix: fixed heartbeat grpc service 2024-09-06 00:54:00 +09:00
0eb897b07f
Update chrome.js
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-09-04 20:17:55 +09:00
38288153ed Apply Math.Sqrt(templateWidth * templateHeight) < 10.0
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-09-04 17:26:31 +09:00
9227518d1e Update ScreenMatch.cs 2024-09-04 16:20:48 +09:00
bab0a3bba2 Fix STAThreadAttribute issue 2024-09-04 16:18:05 +09:00
85ba0c14be Add the sample_clipboard option to the screen time 2024-09-04 14:12:28 +09:00
ca7b7ad3d5 Update ScreenMatch.cs 2024-09-04 13:26:20 +09:00
87d785df45
Update chrome.js
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-09-04 00:41:01 +09:00
34115728fe
Update chrome.js
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-09-02 21:41:35 +09:00
7ed1cab718
Update chrome.js 2024-09-02 21:14:05 +09:00
ecf12aa83f
Update chrome.js 2024-09-02 21:13:22 +09:00
ffbb560598
Update chrome.js 2024-09-02 20:51:42 +09:00
eb389d34c7
Update chrome.js 2024-09-02 20:51:28 +09:00
c6d55cd1fa Update settings.example.ini
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-09-02 16:03:26 +09:00
db557015fd Update ScreenMatch.cs 2024-09-02 16:01:30 +09:00
2f4b95313f Update ScreenMatch.cs 2024-09-02 15:30:20 +09:00
e70c152494 Add heartbeat.proto 2024-09-02 15:18:15 +09:00
9d7f14cddb Add submodule tessdata 2024-09-02 15:15:38 +09:00
dcdaaa11c2 Add tessdata to the assets 2024-09-02 14:58:05 +09:00
3a1d2ab1ba Update ScreenMatch.cs 2024-09-02 14:37:45 +09:00
ba654438ab Add option ocr128 to the screen time feature 2024-09-02 14:17:06 +09:00
4401ba6847 Remove orphan files 2024-09-02 12:48:07 +09:00
0777faaa5b
Update README.md 2024-09-02 12:39:36 +09:00
577b3f018a
Merge pull request #136 from gnh1201/dependabot/nuget/WelsonJS.Toolkit/WelsonJS.Service/RestSharp-112.0.0
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Bump RestSharp from 111.4.1 to 112.0.0 in /WelsonJS.Toolkit/WelsonJS.Service
2024-08-30 10:25:10 +09:00
dependabot[bot]
9b5fb5499c
Bump RestSharp in /WelsonJS.Toolkit/WelsonJS.Service
Bumps [RestSharp](https://github.com/restsharp/RestSharp) from 111.4.1 to 112.0.0.
- [Release notes](https://github.com/restsharp/RestSharp/releases)
- [Commits](https://github.com/restsharp/RestSharp/compare/111.4.1...112.0.0)

---
updated-dependencies:
- dependency-name: RestSharp
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-29 19:39:58 +00:00
6ab285bc89 Update testloader.js 2024-08-29 19:59:30 +09:00
af30097c6e Add pegjs test 2024-08-29 19:57:53 +09:00
a0e1e34974 Update README.md 2024-08-29 19:13:52 +09:00
09a472b956 Update README.md 2024-08-29 19:13:12 +09:00
1fec9c1f2a Update README.md 2024-08-29 19:12:26 +09:00
1c4b94faaf Add a parser generator (PEG.js) #135 2024-08-29 19:06:19 +09:00
3602cb4a00 refactor #132 2024-08-29 15:34:54 +09:00
e6fd3a800e Update ServiceMain.cs
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-08-29 11:40:23 +09:00
a8ad7746ee Sometimes we have to destroy everything to solve a problem. #132 2024-08-29 11:17:38 +09:00
4aace2a3ae Update settings.example.ini
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-08-27 01:48:32 +09:00
222fe3c1a0 Read the initial configurations from settings.ini 2024-08-27 01:47:55 +09:00
659fb12db1 Fix typos on FileEventMonitor.cs 2024-08-27 01:24:11 +09:00
8593240692 Use HTTP/1.1 on the gRPC client 2024-08-27 01:16:53 +09:00
34e97347f2 Remove non-free, non-microsoft, and no-updates in uriloader.js 2024-08-27 01:03:24 +09:00
7c0adf8f00 Update ScreenMatch.cs 2024-08-26 21:53:13 +09:00
7b7a25f5e9 Update ServiceMain.cs
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-08-26 18:29:13 +09:00
4e6b63df50 Update ScreenMatch.cs, ServiceMain.cs 2024-08-26 17:53:21 +09:00
0df9166a13 Update the screen time feature 2024-08-26 15:24:38 +09:00
2db49f85f0 Add method ConvertToBinary to the screen time feature
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-08-26 01:23:02 +09:00
4947151d00 Update FileEventMonitor.cs 2024-08-25 23:22:52 +09:00
44d7d431e3 Revert "Update app.js, defaultService.js"
This reverts commit c208e6dc6c.
2024-08-25 23:21:58 +09:00
72f70d990d Update FileEventMonitor.cs 2024-08-25 23:16:21 +09:00
1f2f940374 Update .gitignore 2024-08-25 23:10:43 +09:00
c208e6dc6c Update app.js, defaultService.js 2024-08-25 23:08:46 +09:00
0eceab3d9b Add option of the interactive service application 2024-08-25 23:04:34 +09:00
f4703ef7a0 Delete 2024-07-29 19 56 13.png 2024-08-25 22:49:26 +09:00
50d1c93f94 Update settings.example.ini 2024-08-25 22:45:25 +09:00
ecfbf7032b Update .gitignore 2024-08-25 22:44:24 +09:00
d9bdd5c578 Update ScreenMatch.cs 2024-08-25 22:43:34 +09:00
277eb08cba Update ScreenMatch.cs
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-08-25 18:07:31 +09:00
18e81f71ba Use backward search in the screen time 2024-08-25 17:57:22 +09:00
82ac8e5d02 Fix the argument passing convention 2024-08-25 15:28:03 +09:00
e4a8357715 Fix parameter types to pass arguments to scripting engine
Since `ArrayList` is highly compatible with COM, you can use it to pass an array to `ScriptControl`.
2024-08-25 12:56:01 +09:00
3a890168df Update ServiceMain.cs
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-08-24 22:27:26 +09:00
02681a135e Update the screen time feature 2024-08-24 22:24:26 +09:00
b345d655f1 Change the class names 2024-08-24 21:32:44 +09:00
7f6e21c96e
Update ScreenMatching.cs
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-08-24 16:18:24 +09:00
32975494f3
Update ScreenMatching.cs 2024-08-24 16:16:07 +09:00
ad06da549f
Update ScreenMatching.cs 2024-08-24 16:13:06 +09:00
ba9088f43f
Update ScreenMatching.cs 2024-08-24 15:57:42 +09:00
016239b014
Update ScreenMatching.cs 2024-08-24 15:40:15 +09:00
66d4926bba Update the screen time feature 2024-08-24 14:57:01 +09:00
7b62e47fd2 Update settings.example.ini 2024-08-24 14:14:01 +09:00
96b91b2298 Update the screen time feature 2024-08-24 13:44:48 +09:00
61ee6aeae0 Add thanks to Hacker News
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-08-23 13:11:32 +09:00
bbefd3331a Update .appveyor.yml 2024-08-23 12:21:37 +09:00
01477b97c5 Update .appveyor.yml 2024-08-23 12:17:35 +09:00
1751f81cce Update .appveyor.yml 2024-08-23 12:06:37 +09:00
cab0211e09 Update .appveyor.yml 2024-08-23 12:00:39 +09:00
2d5b79ceb1 Update .appveyor.yml 2024-08-23 12:00:31 +09:00
6b915a5b4c Update .appveyor.yml 2024-08-23 11:54:35 +09:00
1f0cb81105 Update .appveyor.yml 2024-08-23 11:48:13 +09:00
dbb008772e Update .appveyor.yml 2024-08-23 11:46:03 +09:00
0fa8286d08 Update .appveyor.yml 2024-08-23 11:44:37 +09:00
5146957ea1 Update .appveyor.yml 2024-08-23 11:42:46 +09:00
b183e1925d Update .appveyor.yml 2024-08-23 11:33:17 +09:00
158809732c Update README.md
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-08-23 08:56:01 +09:00
7633675b33 Update README.md 2024-08-23 08:54:01 +09:00
f8e6340fda Update README.md 2024-08-23 08:46:33 +09:00
4a02689c71 Update README.md 2024-08-23 08:44:42 +09:00
7899efcb9e Update README.md 2024-08-23 08:29:40 +09:00
2c67b77156 Update README.md 2024-08-23 08:28:12 +09:00
dc7b5a9fb2 Update MessageReceiver.cs
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-08-22 17:00:53 +09:00
97a930ccb3 Update MessageReceiver.cs 2024-08-22 16:59:58 +09:00
6ec6c07ad7 Update MessageReceiver.cs 2024-08-22 16:59:47 +09:00
3c90c76796 Update .appveyor.yml 2024-08-22 11:14:12 +09:00
0b0ca9912d Update .appveyor.yml 2024-08-22 10:39:01 +09:00
fabcdf185a Update .appveyor.yml 2024-08-22 10:34:14 +09:00
ad6eeb46d5 Update .appveyor.yml 2024-08-22 10:32:15 +09:00
6d43cb47a7 Update .appveyor.yml 2024-08-22 10:30:53 +09:00
ca9f0ba456 Update .appveyor.yml 2024-08-22 10:26:11 +09:00
bc0d6646e4 Update MainForm.cs
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-08-22 09:54:58 +09:00
8c59024b96 Update README.md 2024-08-22 04:16:36 +09:00
ecdc0767b8 Remove DeviceId package (not working) 2024-08-22 04:12:31 +09:00
f61dc98fa6 Update WelsonJS.Toolkit.sln 2024-08-22 04:11:06 +09:00
c985f1fa0a Update WelsonJS.Launcher build configurations 2024-08-22 04:08:37 +09:00
ce88ae603b Update WelsonJS.Launcher 2024-08-22 04:02:31 +09:00
1e82f18bc9 Update MainForm.cs 2024-08-22 03:58:35 +09:00
d8558a4398 Add WelsonJS.Launcher component 2024-08-22 03:36:58 +09:00
7c77daabfa Update .gitignore
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-08-22 00:55:54 +09:00
81a31c7b1f
Update http.js 2024-08-21 23:38:48 +09:00
f3f2cc482c
Update SECURITY.MD
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-08-21 08:03:52 +09:00
e8bc5348a8
Update README.md 2024-08-21 08:01:31 +09:00
fe31fd2c97 Update MessageReceiver.cs
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-08-20 19:37:10 +09:00
f6bbc31551 Update MessageReceiver.cs
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-08-20 16:31:23 +09:00
8821eb0ae0 fix 2024-08-20 16:03:27 +09:00
c497c0fb26 Update MessageReceiver.cs 2024-08-20 13:44:47 +09:00
ed9e1a6d05 fix 2024-08-20 13:42:44 +09:00
1fa024546a Add flag disabledMessageReceiver 2024-08-20 10:36:59 +09:00
b3548bc35f Update .gitignore 2024-08-20 09:50:30 +09:00
5de04579b7 Update settings.example.ini 2024-08-20 09:49:58 +09:00
80b3e49cb8 Some update configurations 2024-08-20 09:49:03 +09:00
68d100458f Merge branch 'master' of https://github.com/gnh1201/welsonjs 2024-08-20 09:35:27 +09:00
3765d21648
Update SECURITY.MD 2024-08-20 09:34:48 +09:00
e7ed4794e2 Merge branch 'master' of https://github.com/gnh1201/welsonjs 2024-08-20 09:25:56 +09:00
f181bf2696 Update MessageReceiver.cs, app.js #132 2024-08-20 09:25:50 +09:00
1704575cfb
Update SECURITY.MD 2024-08-20 09:11:19 +09:00
905c85a99c
Update SECURITY.MD 2024-08-20 09:06:57 +09:00
c8b3ac5d99 Related works for #132
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-08-19 17:04:50 +09:00
5d9fb71753 Replace GRPC proto file and delete the related file
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-08-19 00:35:23 +09:00
1863a76a4c Update build configurations
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-08-15 17:47:29 +09:00
8865723dd4 Update core-js version to 3.38.0
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-08-14 14:31:32 +09:00
eb05661e2b Update app.js 2024-08-14 14:25:55 +09:00
64e556f37a Update std.js
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-08-14 14:05:02 +09:00
a20ce41f73 Revert "Update std.js"
This reverts commit 9a583d0284.
2024-08-14 14:04:32 +09:00
9a583d0284 Update std.js 2024-08-14 14:04:17 +09:00
5ec537e142 Update std.js 2024-08-14 14:00:02 +09:00
243db3edaa Revert "Change variable naming convention, Remove dupilicate code (std.js)"
This reverts commit 3aa5a140d1.
2024-08-14 13:50:35 +09:00
3723f775bd Update .appveyor.yml
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-08-13 18:00:31 +09:00
83ecd79ec0 Update .appveyor.yml 2024-08-13 17:59:50 +09:00
9c77777577 Update .appveyor.yml 2024-08-13 17:59:18 +09:00
832bb12829 Revert "Add the package Costura.Fody"
This reverts commit d6012d88dd.
2024-08-13 17:39:26 +09:00
d6012d88dd Add the package Costura.Fody 2024-08-13 17:21:09 +09:00
d01d28fbf3
Update defaultService.js 2024-08-13 17:05:48 +09:00
f44f0b38b2 Update the files related to settings.ini
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-08-13 13:39:01 +09:00
d04e03200b some fixes 2024-08-13 11:21:48 +09:00
92bcb33171 Add settings.ini 2024-08-13 11:16:27 +09:00
41e542dc7a
Update FUNDING.yml
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-08-12 21:17:55 +09:00
c4740f7d61 Add ElasticsearchClient.cs, Update FileEventMonitor.cs 2024-08-12 21:15:03 +09:00
e8c69d1489 Update ScreenMatching.cs 2024-08-12 21:06:02 +09:00
5062d774b7 Some fixes 2024-08-12 21:05:17 +09:00
7de923f90c Remove the elasticsearch client library 2024-08-12 20:19:15 +09:00
7b03d9f020 Update .appveyor.yml 2024-08-12 17:16:16 +09:00
4ff438655d Update WelsonJS.Service.csproj 2024-08-12 17:10:34 +09:00
4ece37fdf4 Update FileEventMonitor 2024-08-12 17:08:32 +09:00
15bd7d40db Update ScreenMatching.cs, ServiceMain.cs 2024-08-12 16:53:31 +09:00
cf34039f5a Update FileEventMonitor.cs 2024-08-12 16:44:25 +09:00
f0a7316eef Some works #131 2024-08-12 16:42:37 +09:00
ee454527af Update FileEventMonitor.cs 2024-08-12 13:36:27 +09:00
5af61c3e76 Update ServiceMain.cs 2024-08-12 13:18:55 +09:00
e8ba073de2 Update FileEventMonitor.cs 2024-08-12 13:15:23 +09:00
0c03995f43 Update .appveyor.yml 2024-08-12 13:13:38 +09:00
5f0df92442 Update .appveyor.yml 2024-08-12 13:12:50 +09:00
1e16ff9483 Update pe.yar
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-08-12 13:07:16 +09:00
7c8fd0cd45 Update .appveyor.yml 2024-08-12 13:03:52 +09:00
bb2db7b64a Update .appveyor.yml 2024-08-12 13:02:11 +09:00
2631a8f577 some fixes 2024-08-12 13:00:04 +09:00
58d1829c9c Add Yara File Rule Matcher #131 2024-08-12 12:47:19 +09:00
1a4931e283
fix #122
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-08-08 11:07:52 +09:00
b2433e9057 Update .gitignore
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-08-07 16:31:19 +09:00
1b214a1604 Update bootstrap.bat 2024-08-07 11:58:00 +09:00
b8d2e362bf Update std.js 2024-08-07 11:55:50 +09:00
9f4f240493 Update std.js 2024-08-07 11:55:09 +09:00
3aa5a140d1 Change variable naming convention, Remove dupilicate code (std.js) 2024-08-07 11:52:34 +09:00
00868b708b
Update std.js 2024-08-06 22:03:24 +09:00
eead1f8775
Update std.js 2024-08-06 21:49:10 +09:00
cfadf1e369
Update std.js 2024-08-06 21:37:00 +09:00
fe31aa36bd
Update std.js 2024-08-06 21:34:50 +09:00
d6cf95b345
Update std.js 2024-08-06 21:34:01 +09:00
3ff02c442e
Update std.js 2024-08-06 21:30:31 +09:00
ca6f13196d
Update std.js 2024-08-06 21:15:59 +09:00
69888245bf
Update std.js 2024-08-06 21:00:02 +09:00
4a2fd7943a
Update std.js 2024-08-06 20:59:29 +09:00
3e86686613 Update .appveyor.yml 2024-08-06 20:27:40 +09:00
2bd104fc2f Update .appveyor.yml 2024-08-06 20:23:58 +09:00
334ec48d3e Update .appveyor.yml 2024-08-06 20:14:57 +09:00
ba5d038441 Update .appveyor.yml 2024-08-06 20:13:10 +09:00
93aababfc4 Update .appveyor.yml 2024-08-06 20:12:19 +09:00
daccf5e6de Create .appveyor.yml
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-08-06 20:08:17 +09:00
a6dbf1bb4b Update WelsonJS.Toolkit.csproj 2024-08-06 19:56:09 +09:00
34a9a843a4 JMT 2024-08-06 19:45:25 +09:00
8e88761547 Delete build_native_libraries.bat 2024-08-06 17:08:27 +09:00
1bb01be01d Remove the checked-in binaries #130 2024-08-06 17:05:51 +09:00
dbae10a4e5
Update har.js
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-08-03 21:56:26 +09:00
256ca14284
Update har.js
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-08-03 17:49:22 +09:00
ac2e1117a7
Update har.js 2024-08-03 17:10:34 +09:00
1b8fbf78bf
Update har.js 2024-08-03 16:49:30 +09:00
92e611f49a
Update har.js 2024-08-03 16:45:07 +09:00
5ff6680cee
Update har.js 2024-08-03 16:41:36 +09:00
aeef44d3d9
Update har.js 2024-08-03 15:53:30 +09:00
2e8c530ba9
Update har.js 2024-08-03 15:51:47 +09:00
c6cbe96e03
Update and rename hartool.js to har.js 2024-08-03 15:26:52 +09:00
45a1938aea
Create hartool.js 2024-08-03 15:25:41 +09:00
f55b70585a
Update SECURITY.MD 2024-08-03 14:07:30 +09:00
ff943d3fc2
Update SECURITY.MD
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-08-02 21:15:38 +09:00
a5672a16ff Update ScreenMatching.cs
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-08-02 16:53:33 +09:00
8df6270287 Update the screen time feature on WelsonJS.Service 2024-08-02 16:51:49 +09:00
70bce6eb72 Update .gitignore 2024-08-02 11:12:03 +09:00
75e386d2a7 Update .gitignore 2024-08-02 11:11:27 +09:00
05c06bffd2 Update WelsonJS.Service binaries 2024-08-02 11:09:32 +09:00
a7bc9fa21a Update ServiceMain.cs 2024-08-02 11:07:41 +09:00
8bd2382973 Update ServiceMain.cs 2024-08-02 11:07:04 +09:00
faf3d55d8d
Update README.md
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-07-31 18:17:09 +09:00
59d9d313f8
Update README.md 2024-07-31 18:14:57 +09:00
83e403cc54 Update setup.iss
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-07-31 16:19:08 +09:00
a80fd75ec3
Update SECURITY.MD 2024-07-31 09:44:30 +09:00
fc1694198b
Update SECURITY.MD 2024-07-31 09:41:12 +09:00
9ae992dc89 bug fix #126
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-07-31 00:43:42 +09:00
6297f9689d Add startInteractiveService.bat, uninstallService.bat 2024-07-30 18:17:26 +09:00
172a5109e9 Update setup.iss
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-07-30 15:46:11 +09:00
e881ec98ec Update README.md 2024-07-30 15:43:17 +09:00
6c9f905c2b Update README.md 2024-07-30 15:42:32 +09:00
0105ef9010 Update README.md 2024-07-30 15:41:05 +09:00
fe568f032e Add screenshot no.5 2024-07-30 15:40:17 +09:00
2766b2dcfc Update cover.png 2024-07-30 15:12:38 +09:00
2e37432990 Update README.md 2024-07-30 13:41:50 +09:00
38ad7ab669 Update README.md 2024-07-30 13:39:28 +09:00
27edbe4652 Update README.md 2024-07-30 13:30:10 +09:00
11abc2d1b3 Update README.md 2024-07-30 13:28:56 +09:00
119ad684ed Update README.md 2024-07-30 13:28:29 +09:00
accdf058c6 Update README.md 2024-07-30 13:22:05 +09:00
8d865b572d Change the cover image 2024-07-30 12:53:27 +09:00
3762dac556 Change the cover image 2024-07-30 12:53:06 +09:00
8f35bfb03b Update WelsonJS.Service
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-07-29 22:42:35 +09:00
3b09a47fb8 Update the Screen Matching feature 2024-07-29 22:28:07 +09:00
b687cf7727 Add Screen Matching feature 2024-07-29 21:43:14 +09:00
d5f55e0f28 Fix issue the cannot find the working directroy
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-07-29 16:06:04 +09:00
95a7588726 Revert "Some works for #124"
This reverts commit b5af648512.
2024-07-29 15:41:10 +09:00
f72db8bf2e Revert "Some works for #124"
This reverts commit f73b180329.
2024-07-29 15:41:05 +09:00
02d45ede0f Revert "Update defaultService.js"
This reverts commit ffd6cde177.
2024-07-29 15:40:11 +09:00
ffd6cde177 Update defaultService.js 2024-07-29 15:07:53 +09:00
f73b180329 Some works for #124 2024-07-29 15:04:22 +09:00
b5af648512 Some works for #124
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-07-29 01:35:46 +09:00
66879f229a Update installService.bat
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-07-27 21:38:38 +09:00
dad5c06a1b Add the service install script 2024-07-27 21:30:07 +09:00
0c5abb4658
Merge pull request #125 from gnh1201/dependabot/npm_and_yarn/requirejs-2.3.7
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Bump requirejs from 2.3.6 to 2.3.7
2024-07-26 17:29:31 +09:00
dependabot[bot]
0c09c5bd3b
Bump requirejs from 2.3.6 to 2.3.7
Bumps [requirejs](https://github.com/jrburke/r.js) from 2.3.6 to 2.3.7.
- [Commits](https://github.com/jrburke/r.js/compare/2.3.6...2.3.7)

---
updated-dependencies:
- dependency-name: requirejs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-26 08:25:56 +00:00
4a33238d7e Change the target framework version to 4.8, and renaming some functions 2024-07-26 17:24:56 +09:00
3b18896564 Fix incorrect version info of WelsonJS.Service
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
2024-07-23 13:28:16 +09:00
84e094fc19 Update WelsonJS.Service binaries 2024-07-23 13:16:25 +09:00
639dfeeb68 Merge branch 'master' of https://github.com/gnh1201/welsonjs 2024-07-23 13:13:38 +09:00
f60f99fc73 Update WelsonJS.Service and related files 2024-07-23 13:13:33 +09:00
95572825c3
Update README.md
Some checks are pending
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
2024-07-23 12:41:57 +09:00
209 changed files with 30600 additions and 1497 deletions

47
.appveyor.yml Normal file
View File

@ -0,0 +1,47 @@
version: 0.2.7.build{build}
image: Visual Studio 2019
clone_folder: C:\projects\welsonjs
environment:
ORGANIZATION_ID: 8ee5ec82-36dc-4619-ac33-5bc1117428fe
PROJECT_SLUG: welsonjs
ARTIFACT_CONFIGURATION_SLUG: initial
matrix:
- CONFIGURATION: Debug
SIGNING_POLICY_SLUG: test-signing
- CONFIGURATION: Release
SIGNING_POLICY_SLUG: release-signing
before_build:
- nuget restore WelsonJS.Toolkit
build_script:
- msbuild "C:\projects\welsonjs\WelsonJS.Toolkit\WelsonJS.Toolkit.sln" /verbosity:minimal /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /p:Configuration=%CONFIGURATION% /p:Platform="x86"
after_build:
- cmd: mkdir artifacts
#- 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:
- path: artifacts.zip
name: WelsonJS.Toolkit
deploy:
- provider: Webhook
url: https://app.signpath.io/API/v1/%ORGANIZATION_ID%/Integrations/AppVeyor?ProjectSlug=%PROJECT_SLUG%&SigningPolicySlug=%SIGNING_POLICY_SLUG%&ArtifactConfigurationSlug=%ARTIFACT_CONFIGURATION_SLUG%
authorization:
secure: nABfe+lksIRfS7lVnkq3EdIYNH8KOka+5ZFTUJqUW2nckBubhrlAXarbCPJHLp9FWWf3zxAWhNwT0It+qyqPRQ==
notifications:
- provider: Email
to:
- abuse@catswords.net
subject: 'Build #{{build}} {{status}}'
on_build_success: false
on_build_failure: true

2
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,2 @@
github: gnh1201
custom: ['https://gnh1201.link']

View File

@ -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
View 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 }}

12
.gitignore vendored
View File

@ -103,5 +103,13 @@ dist
# TernJS port file
.tern-port
# ChatGPT API Key
data/chatgpt-apikey.txt
# user private assets
bin
data/*-apikey.txt
data/*.nomedia.txt
app/assets/img/_templates
app/assets/img/_captured
settings.ini
defaultService.js
lib/*.private.js
data/python313.zip

9
.gitmodules vendored Normal file
View File

@ -0,0 +1,9 @@
[submodule "app/assets/tessdata"]
path = app/assets/tessdata
url = https://github.com/tesseract-ocr/tessdata
[submodule "app/assets/tessdata_best"]
path = app/assets/tessdata_best
url = https://github.com/tesseract-ocr/tessdata_best
[submodule "app/assets/tessdata_fast"]
path = app/assets/tessdata_fast
url = https://github.com/tesseract-ocr/tessdata_fast

View File

@ -1,8 +0,0 @@
# These are supported funding model platforms
github: gnh1201
open_collective: welsonjs
liberapay: catswords
custom: ['https://www.buymeacoffee.com/catswords', 'https://toss.me/catswords']
patreon: catswords # Replace with a single Patreon username
ko_fi: catswords

229
README.md
View File

@ -1,85 +1,84 @@
# welsonjs
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fgnh1201%2Fwelsonjs.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fgnh1201%2Fwelsonjs?ref=badge_shield)
[![DOI](https://zenodo.org/badge/275600068.svg)](https://zenodo.org/doi/10.5281/zenodo.11382384)
[![AppVeyor Status](https://ci.appveyor.com/api/projects/status/github/gnh1201/welsonjs?svg=true)](https://ci.appveyor.com/project/gnh1201/welsonjs)
[![DOI 10.5281/zenodo.11382384](https://zenodo.org/badge/DOI/10.5281/zenodo.11382384.svg)](https://doi.org/10.5281/zenodo.11382384)
[![ChatGPT available](https://img.shields.io/badge/ChatGPT-74aa9c?logo=openai&logoColor=white)](https://catswords-oss.rdbl.io/5719744820/5510319392)
[![Anthropic available](https://img.shields.io/badge/Anthropic-000000?logo=Anthropic&logoColor=white)](https://catswords-oss.rdbl.io/5719744820/5510319392)
[![Grok available](https://img.shields.io/badge/Grok-000000?logo=x&logoColor=white)](https://catswords-oss.rdbl.io/5719744820/5510319392)
[![Google Gemini available](https://img.shields.io/badge/Google%20Gemini-886FBF?logo=googlegemini&logoColor=fff)](https://catswords-oss.rdbl.io/5719744820/5510319392)
[![slideshare.net presentation](https://img.shields.io/badge/SlideShare-black?logo=slideshare)](https://www.slideshare.net/slideshow/welsonjs-javascript-framework-presentation-2024/276005486)
[![YouTube promotion video](https://img.shields.io/badge/YouTube-red?logo=youtube)](https://youtu.be/JavH7Dms8-U)
[![Discord chat](https://img.shields.io/discord/359930650330923008?logo=discord)](https://discord.gg/XKG5CjtXEj)
[![Open to work](https://img.shields.io/badge/%23-OPENTOWORK-green)](https://github.com/gnh1201/welsonjs/discussions/167)
WelsonJS - Build a Windows app on the Windows built-in JavaScript engine.
<img src="app/assets/img/logo.svg" height="32" alt=""/> WelsonJS - Build a Windows app on the Windows built-in JavaScript engine.
![(Cover Image) A man programming against a power plant facility, the screen that the man is watching shows the Windows logo](app/assets/img/overture.jpg)
![A Cover Image: Windows in 1999](https://ics.catswords.net/cover.png)
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](FUNDING.yml)
WelsonJS = ***W***indows + ***El***ectr***on***-like + ***Javascript(JS)*** + :heart:[Contributions](https://github.com/sponsors/gnh1201)
Dual license notice: The default license for this project is GPL 3.0. However, if the GPL 3.0 license is not compatible with Microsoft products, it is subject to the MS-RL license.
* :kissing_cat: [Download Latest WelsonJS Launcher (ics.catswords.net)](https://ics.catswords.net/welsonjs_launcher_latest.zip)
* :rocket: [Launch the WelsonJS environment on Microsoft Azure (azuremarketplace.microsoft.com)](https://azuremarketplace.microsoft.com/en-us/marketplace/apps/catswords.catswords-welsonjs-feb2025-02?tab=Overview)
**Note**: The default license for this project is GPL 3.0. However, if the GPL 3.0 license is not compatible with Microsoft products, it is subject to the MS-RL license.
## Sponsors
* :octocat: [GitHub Sponsors](https://github.com/sponsors/gnh1201), :coffee: [Buy me a coffee](https://buymeacoffee.com/catswords)
* <img src="https://ics.catswords.net/logo_oss.gif" height="32" alt=""/> [Open SW Portal](https://oss.kr), NIPA National IT Industry Promotion Agency<sup>(정보통신산업진흥원)</sup>
* <img src="https://ics.catswords.net/signpath_logo.png" height="32" alt=""/> Free code signing provided by [SignPath.io](https://signpath.io), certificate by [SignPath Foundation](https://signpath.org/)
* <img src="https://ics.catswords.net/f1security_logo.png" height="32" alt=""/> [F1Security<sup>(에프원시큐리티)</sup>](https://f1security.co.kr/) provides [industry-leading](https://www.ksecurity.or.kr/kisis/subIndex/469.do) web security services.
* <img src="https://ics.catswords.net/microsoft_logo.png" height="32" alt=""/> [Microsoft ISV Success Program](https://www.microsoft.com/en-us/isv/isv-success), Grow your business with powerful tools.
* :zap: [Integrations](https://catswords-oss.rdbl.io/5719744820/8278298336) ([ScrapeOps](https://scrapeops.io?fpr=namhyeon75), [SearchApi](https://www.searchapi.io/?via=namhyeon), [AviationStack](https://aviationstack.com?utm_source=FirstPromoter&utm_medium=Affiliate&fpr=namhyeon71), [Coupang](https://link.coupang.com/a/b7HV3V)...)
## System Requirements
* **Operating Systems**: Windows XP SP3 or later (Currently, Windows 11 24H2)
* For systems running Windows 2000 or earlier versions (e.g., 95, 98, Me), please contact us separately.
## Why Choose WelsonJS?
WelsonJS is an advanced JavaScript framework designed to operate in extreme conditions where conventional solutions may fail. Unlike traditional JavaScript frameworks, WelsonJS focuses on executing scripts in constrained environments, ensuring reliable performance even with minimal system resources.
### Key Features
* **Lightweight and Efficient**: Optimized for environments with limited computing power, WelsonJS delivers efficient script execution without unnecessary overhead.
* **Windows ECMAScript Compatibility**: Designed to run seamlessly on Windows-based systems, adhering to the ECMAScript standard while maintaining lightweight execution.
* **Standalone Execution**: Unlike well-known JavaScript runtimes, which require external dependencies, a WelsonJS application can operate as a self-contained app, making it suitable for embedded systems and isolated environments.
* **Security-Oriented**: Built with security in mind, ensuring controlled execution of scripts without compromising system integrity.
* **Minimalist Design**: WelsonJS strips away unnecessary complexities, focusing on core functionalities that maximize performance and reliability.
### Use Cases
* **Legacy System Integration**: WelsonJS provides a practical solution for running JavaScript on older Windows environments where modern frameworks are not feasible.
* **Automation and Scripting**: Ideal for executing scripts in constrained environments, enabling automated workflows and system-level scripting.
* **Embedded Applications**: Suitable for devices and systems with strict resource constraints, such as industrial controllers and embedded platforms.
* **Security-Focused Environments**: Useful in security-sensitive applications where dependencies on external network connections are limited.
* **Office Automation**: Suitable for office automation tasks using Microsoft Office and various LLM-based AI (such as ChatGPT).
WelsonJS is tailored for developers who need a reliable, lightweight JavaScript framework in environments where traditional solutions are impractical. Whether working with legacy systems, embedded devices, or security-critical applications, WelsonJS ensures that JavaScript remains a viable and efficient option.
## Structure
![Structure Overview](app/assets/img/structure.png)
![The structure of the WelsonJS framework can be extended based on whether it operates in a console (command prompt) environment, a GUI (with HTML/CSS) environment, or a service environment, with the `app.js` file at its core.](https://ics.catswords.net/structure.png)
## 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)
- Default CSS Framework
- [github.com/jslegers/cascadeframework](https://github.com/jslegers/cascadeframework)
- 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)
- [github.com/hiddentao/squel](https://github.com/hiddentao/squel)
- [github.com/BorisMoore/jsrender](https://github.com/BorisMoore/jsrender) - Templating engine
- [github.com/mihaifm/linq](https://github.com/mihaifm/linq) - LINQ 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 client with MSXML/cURL)
- 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-based IPC(Inter-Process Communication) implementation)
- lib/toolkit (`WelsonJS.Toolkit` native component)
- Find and attach a handle of the window
- alert(), prompt() implementation in console mode
- Virtualized Human Interfaces
- Cryptography
- [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)
- 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
@ -90,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;
```
@ -110,57 +109,73 @@ function main() {
exports.main = main;
```
### 3. Execute file on the command prompt
### 3. Execute script on the console
```cmd
C:\Users\oss\Documents\GitHub\welsonjs> cscript app.js sayhello
C:\Users\JohnDoe\Documents\GitHub\welsonjs> cscript app.js sayhello
calling say()
hello
ended say()
```
## How to make your own setup file
- Please check `setup.iss` file it could be compile with [Inno Setup](https://jrsoftware.org/isinfo.php)
## How to release my application?
The WelsonJS framework suggests the following application release methods:
* **Compress to Zip, and use the launcher**: Compress the files and directories necessary for running the project into a Zip file, and distribute it along with the [WelsonJS Launcher](https://catswords-oss.rdbl.io/5719744820/4131485779).
* **Build a setup file**: Use [Inno Setup](https://jrsoftware.org/isinfo.php). The setup profile (the `setup.iss` file) is already included.
* **Copy all directories and files**: This is the simplest and most straightforward method.
## Screenshots
![(Screenshot 1) GUI environment](app/assets/img/screenshot.png)
![(Screenshot 1) GUI environment](https://ics.catswords.net/screenshot.png)
![(Screenshot 2) Command-line environment](app/assets/img/screenshot2.png)
![(Screenshot 2) Command-line environment](https://ics.catswords.net/screenshot2.png)
![(Screenshot 3) WelsonJS with Microsoft Excel](app/assets/img/screenshot3.png)
![(Screenshot 3) WelsonJS with Microsoft Excel](https://ics.catswords.net/screenshot3.png)
![(Screenshot 4) Write a Windows Services with JavaScript](app/assets/img/screenshot4.png)
![(Screenshot 4) Write a Windows Services with JavaScript](https://ics.catswords.net/screenshot4.png)
![(Screenshot 5) Template Matching on the computer screen](https://ics.catswords.net/screenshot5.png)
![(Screenshot 6) The Launcher for WelsonJS Application Packages](https://ics.catswords.net/screenshot6.png)
![(Screenshot 7) Microsoft Monaco Editor on WelsonJS Launcher](https://ics.catswords.net/screenshot7.png)
## Thanks to
- <img src="app/assets/img/logo_oss.gif" height="30" alt=""/> Open Software Portal, Korea National Industry Promotion Agency - Awarded Prize
- 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="30" alt=""/> morioh.com - Mentioned
- <img src="app/assets/img/CSDN_Logo.svg" height="30" alt=""/> CSDN - Mentioned
- <img src="app/assets/img/qiita-logo.png" height="30" alt=""/> Qiita - Knowledge-base about WSH environment
- <img src="app/assets/img/RedSky-logo-web.webp" height="30" 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="30" alt=""/> Fediverse - Mentioned
- [GitHub Sponsors](https://github.com/sponsors/gnh1201)
## Related projects
- [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://pub-f926e14287b340cd9eff33731bb25329.r2.dev/fossa_report.html) [CSV](https://pub-f926e14287b340cd9eff33731bb25329.r2.dev/fossa_report.csv) [TXT](https://pub-f926e14287b340cd9eff33731bb25329.r2.dev/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
- 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)
* [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
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fgnh1201%2Fwelsonjs.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fgnh1201%2Fwelsonjs?ref=badge_large)

View File

@ -1,48 +1,63 @@
# Security Note for WelsonJS
## Caution
This repository contains information on accessing Windows APIs and functions on the JavaScript runtime, along with recent case studies. While this can provide a flexible development environment for anyone, it can also be misused for malicious purposes. Please be aware that using this project to create abuse tools, such as a DoS attack, may result in legal punishment in your country. We encourage you to use this project only for creating web technology-based applications, like Electron, or legally permitted testing tools.
## License
The WelsonJS project is available under either the GPLv3 or MS-RL opensource licenses. If the GPLv3 license is not compatible with Microsoft products, the MS-RL license applies; otherwise, the GPLv3 license is used. Under these licenses, if you distribute modified versions of this project's source code to third parties, you may be required to disclose the source code. For more details, please refer to the `LICENSE` and `LICENSE_MSRL` files.
## Known use cases
## Caution
This repository contains information on accessing Windows APIs and functions in the JavaScript runtime, along with recent case studies. While this can provide a flexible development environment for anyone, it can also be misused for malicious purposes. Please be aware that using this project to create abuse tools, such as for DoS attacks, may result in legal consequences in your country. We encourage you to use this project only for creating web technology-based applications, like Electron, or legally permitted testing tools.
## 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, CD/CI (Continuous Integration/Continuous Delivery), DevOps, and SecOps.
* Asset evaluation (e.g. Get a 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
### For the use of online shopping and delivery websites
We are aware of cases where WelsonJS has been used for asset valuation to access websites of online shopping or delivery companies. This is a good use case, but there have been reports of website downtime caused by excessive concurrent requests. Please exercise caution and avoid excessive simultaneous executions.
### Use of Online Shopping and Delivery Websites
We are aware of cases where WelsonJS has been used to access the websites of online shopping or delivery companies for asset valuation. This is a good use case, but there have been reports of website downtime caused by excessive concurrent requests. Please exercise caution and avoid excessive simultaneous executions.
### For the use of online video streaming quality testing and improvement
We are aware of cases where WelsonJS is used for the purpose of video streaming quality testing and improvement. It should be used solely for expert-level streaming quality testing, often referred to by terms like 4K, 8K, HD, FHD, UHD, 720p, 1080p, etc. For such purposes, it is recommended to use videos provided by television manufacturers (e.g., LG, Samsung) or graphics card manufacturers (e.g., NVIDIA, AMD) specifically for testing purposes. It is essential to avoid using videos that contain content not legally permitted in the region. The WelsonJS developers and maintainers take no responsibility for the use of videos containing illegal content.
### Use for Online Video Streaming Quality Testing and Improvement
We are aware of cases where WelsonJS is used for video streaming quality testing and improvement. It should be used solely for expert-level streaming quality testing, often referred to by terms like 4K, 8K, HD, FHD, UHD, 720p, 1080p, etc. For such purposes, it is recommended to use videos provided by television manufacturers (e.g., LG, Samsung) or graphics card manufacturers (e.g., NVIDIA, AMD) specifically for testing purposes. It is essential to avoid using videos that contain content not legally permitted in your region. The WelsonJS developers and maintainers take no responsibility for the use of videos containing illegal content.
### For the use of security testing
### Use for Scientific Research Institutes
WelsonJS is designed for flexible industrial facility control (a.k.a. Industrial Scripting) in environments where modifying compiled binaries is restricted. Parts or all of this project's source code may be found in use within scientific research institutes. In such cases, appropriate safety measures tailored to the specific application area may be required. If support is needed for these applications, please do not hesitate to contact us.
### Use for Security Testing
We are aware of instances where WelsonJS has been used by legitimate cybersecurity firms to discover and test vulnerabilities (such as credential stuffing) in IoT devices. If you intend to use WelsonJS as a security testing tool, it should be done in a controlled environment that complies with legal regulations.
### For the use of cloud monitoring
WelsonJS is a project initiated by a cloud service provider in response to a request to develop a lightweight software (e.g., agent) for collecting metrics on Windows systems. While using WelsonJS for this purpose is desirable, ensuring security in the server-client communication is entirely the responsibility of the user.
### Use for Cloud Monitoring
WelsonJS is a project inspired by the requirements of a cloud service provider to develop lightweight software (e.g., agents) for collecting metrics on Windows systems. While using WelsonJS for this purpose is desirable, ensuring security in the server-client communication is entirely the responsibility of the user.
## Alternative names
This program is also known by the following name. This name is used solely for the purpose of identifying the work and does not impact the license:
## 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)
- "A0562"(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.
* [GitHub Security Advisories](https://github.com/gnh1201/welsonjs/security)
* [abuse@catswords.net](mailto:abuse@catswords.net)
- 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.

View 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;
}
}

View 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);
}
}
}
}
}

View 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>

View 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;
}
}

View 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);
}
}
}
}

View 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>

View 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);
}
}

View 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;
}
}

View 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;
}
}
}

View 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>

View File

@ -0,0 +1,279 @@
namespace WelsonJS.Launcher
{
partial class MainForm
{
/// <summary>
/// 필수 디자이너 변수입니다.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 사용 중인 모든 리소스를 정리합니다.
/// </summary>
/// <param name="disposing">관리되는 리소스를 삭제해야 하면 true이고, 그렇지 않으면 false입니다.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form
/// <summary>
/// 디자이너 지원에 필요한 메서드입니다.
/// 이 메서드의 내용을 코드 편집기로 수정하지 마세요.
/// </summary>
private void InitializeComponent()
{
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.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();
//
// btnRunFromZipFile
//
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);
//
// btnRunFromExternalLink
//
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, 41);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(312, 12);
this.label1.TabIndex = 2;
this.label1.Text = "Choose the location of WelsonJS application package.";
//
// linkLabel1
//
this.linkLabel1.AutoSize = true;
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;
this.linkLabel1.TabStop = true;
this.linkLabel1.Text = "https://github.com/gnh1201/welsonjs";
this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked);
//
// cbUseSpecificScript
//
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);
//
// txtUseSpecificScript
//
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;
//
// cbInteractiveServiceApp
//
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, 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.btnRunFromExternalLink);
this.Controls.Add(this.btnRunFromZipFile);
this.Controls.Add(this.menuStrip1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = global::WelsonJS.Launcher.Properties.Resources.favicon;
this.MainMenuStrip = this.menuStrip1;
this.MaximizeBox = false;
this.Name = "MainForm";
this.Text = "WelsonJS Application Launcher";
this.menuStrip1.ResumeLayout(false);
this.menuStrip1.PerformLayout();
this.contextMenuStrip1.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
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 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;
}
}

View File

@ -0,0 +1,275 @@
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Security.Principal;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WelsonJS.Launcher
{
public partial class MainForm : Form
{
private string workingDirectory;
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.";
btnRunFromZipFile.Enabled = true;
btnRunFromExternalLink.Enabled = true;
cbUseSpecificScript.Enabled = true;
cbInteractiveServiceApp.Enabled = true;
if (cbUseSpecificScript.Checked)
{
txtUseSpecificScript.Enabled = true;
}
}
private void DisableUI()
{
label1.Text = "Please wait...";
btnRunFromZipFile.Enabled = false;
btnRunFromExternalLink.Enabled = false;
cbUseSpecificScript.Enabled = false;
cbInteractiveServiceApp.Enabled = false;
txtUseSpecificScript.Enabled = false;
}
private void SafeInvoke(Action action)
{
if (InvokeRequired)
{
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);
}
}
}
private void ExtractAndRun(string filePath)
{
instanceId = Guid.NewGuid().ToString();
workingDirectory = Program.GetWorkingDirectory(instanceId);
scriptName = txtUseSpecificScript.Text;
Task.Run(() =>
{
try
{
// If exists, delete all
if (Directory.Exists(workingDirectory))
{
Directory.Delete(workingDirectory, true);
}
// try to extact ZIP file
ZipFile.ExtractToDirectory(filePath, workingDirectory);
// record the first deploy time
RecordFirstDeployTime(workingDirectory);
// follow the sub-directory
workingDirectory = Program.GetWorkingDirectory(instanceId, true);
// Run the appliction
Program.RunCommandPrompt(workingDirectory, entryFileName, scriptName, cbUseSpecificScript.Checked, cbInteractiveServiceApp.Checked);
}
catch (Exception ex)
{
SafeInvoke(() =>
{
MessageBox.Show("Error: " + ex.Message);
});
}
// Enable UI
SafeInvoke(() => {
EnableUI();
});
});
DisableUI();
}
private void RecordFirstDeployTime(string directory)
{
try
{
string filePath = Path.Combine(directory, ".welsonjs_first_deploy_time");
string text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
File.WriteAllText(filePath, text);
}
catch (Exception ex)
{
throw new Exception($"Failed to record first deploy time: {ex.Message}");
}
}
private bool IsInAdministrator()
{
try
{
WindowsPrincipal wp = new WindowsPrincipal(WindowsIdentity.GetCurrent());
return wp.IsInRole(WindowsBuiltInRole.Administrator);
}
catch
{
return false;
}
}
private void cbUseSpecificScript_CheckedChanged(object sender, EventArgs e)
{
txtUseSpecificScript.Enabled = cbUseSpecificScript.Checked;
}
private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
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"));
}
}
}

View File

@ -0,0 +1,129 @@
<?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>
<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>

View File

@ -0,0 +1,191 @@
using System;
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
{
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;
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해
// 제어됩니다. 어셈블리와 관련된 정보를 수정하려면
// 이러한 특성 값을 변경하세요.
[assembly: AssemblyTitle("WelsonJS.Launcher")]
[assembly: AssemblyDescription("Launcher for WelsonJS Application Packages")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Catswords")]
[assembly: AssemblyProduct("WelsonJS")]
[assembly: AssemblyCopyright("Catswords OSS, GPLv3 or Ms-RL")]
[assembly: AssemblyTrademark("WelsonJS")]
[assembly: AssemblyCulture("")]
// ComVisible을 false로 설정하면 이 어셈블리의 형식이 COM 구성 요소에
// 표시되지 않습니다. COM에서 이 어셈블리의 형식에 액세스하려면
// 해당 형식에 대해 ComVisible 특성을 true로 설정하세요.
[assembly: ComVisible(false)]
// 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다.
[assembly: Guid("4074d413-195c-45e9-9e63-0d07914187b8")]
// 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다.
//
// 주 버전
// 부 버전
// 빌드 번호
// 수정 버전
//
// 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호를
// 기본값으로 할 수 있습니다.
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.2.7.54")]
[assembly: AssemblyFileVersion("0.2.7.54")]

View File

@ -0,0 +1,289 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 이 코드는 도구를 사용하여 생성되었습니다.
// 런타임 버전:4.0.30319.42000
//
// 파일 내용을 변경하면 잘못된 동작이 발생할 수 있으며, 코드를 다시 생성하면
// 이러한 변경 내용이 손실됩니다.
// </auto-generated>
//------------------------------------------------------------------------------
namespace WelsonJS.Launcher.Properties {
using System;
/// <summary>
/// 지역화된 문자열 등을 찾기 위한 강력한 형식의 리소스 클래스입니다.
/// </summary>
// 이 클래스는 ResGen 또는 Visual Studio와 같은 도구를 통해 StronglyTypedResourceBuilder
// 클래스에서 자동으로 생성되었습니다.
// 멤버를 추가하거나 제거하려면 .ResX 파일을 편집한 다음 /str 옵션을 사용하여 ResGen을
// 다시 실행하거나 VS 프로젝트를 다시 빌드하십시오.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// 이 클래스에서 사용하는 캐시된 ResourceManager 인스턴스를 반환합니다.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WelsonJS.Launcher.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 이 강력한 형식의 리소스 클래스를 사용하여 모든 리소스 조회에 대해 현재 스레드의 CurrentUICulture 속성을
/// 재정의합니다.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <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>
internal static System.Drawing.Bitmap icon_link_128 {
get {
object obj = ResourceManager.GetObject("icon_link_128", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <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>
internal static System.Drawing.Bitmap icon_zip_128 {
get {
object obj = ResourceManager.GetObject("icon_zip_128", resourceCulture);
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);
}
}
}
}

View File

@ -0,0 +1,193 @@
<?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>
<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>

View File

@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 이 코드는 도구를 사용하여 생성되었습니다.
// 런타임 버전:4.0.30319.42000
//
// 파일 내용을 변경하면 잘못된 동작이 발생할 수 있으며, 코드를 다시 생성하면
// 이러한 변경 내용이 손실됩니다.
// </auto-generated>
//------------------------------------------------------------------------------
namespace WelsonJS.Launcher.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.10.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}

View File

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View 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; }
}
}

View 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; }
}
}

View 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);
}
}
}
}

View 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);
}
}
}

View 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");
}
}
}

View 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();
}
}
}

View 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);
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 974 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 837 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 796 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,169 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{4074D413-195C-45E9-9E63-0D07914187B8}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>WelsonJS.Launcher</RootNamespace>
<AssemblyName>WelsonJS.Launcher</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>favicon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.IO.Compression.ZipFile, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.Compression.ZipFile.4.3.0\lib\net46\System.IO.Compression.ZipFile.dll</HintPath>
<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>
<Compile Include="MainForm.Designer.cs">
<DependentUpon>MainForm.cs</DependentUpon>
</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>
<SubType>Designer</SubType>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="GlobalSettingsForm.resx">
<DependentUpon>GlobalSettingsForm.cs</DependentUpon>
</EmbeddedResource>
<None Include="app.config" />
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<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>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="Resources\icon_link_128.png" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\icon_zip_128.png" />
</ItemGroup>
<ItemGroup>
<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>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<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>

View 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="System.IO.Compression.ZipFile" version="4.3.0" targetFramework="net472" />
</packages>

View File

@ -0,0 +1,30 @@
// ElasticsearchClient.cs
// https://github.com/gnh1201/welsonjs
using RestSharp.Authenticators;
using RestSharp;
namespace WelsonJS.Service
{
public class ElasticsearchClient
{
private readonly RestClient client;
public ElasticsearchClient(string baseUrl, string username, string password)
{
var options = new RestClientOptions(baseUrl)
{
Authenticator = new HttpBasicAuthenticator(username, password)
};
client = new RestClient(options);
}
public RestResponse IndexDocument(string indexName, object document)
{
var request = new RestRequest($"/{indexName}/_doc", Method.Post);
request.AddHeader("Content-Type", "application/json");
request.AddJsonBody(document);
return client.Execute(request);
}
}
}

View File

@ -0,0 +1,255 @@
// FileEventMonitor.cs
// Namhyeon Go <abuse@catswords.net>
// 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.ServiceProcess;
using System.Threading.Tasks;
namespace WelsonJS.Service
{
public class FileEventMonitor
{
private EventLogWatcher eventLogWatcher;
private ServiceMain parent;
private ILogger logger;
private enum EventType: int
{
FileCreate = 11,
NetworkConnection = 3,
RegistryEvent_1 = 12,
RegistryEvent_2 = 13,
RegistryEvent_3 = 14
};
private enum FileCreateEvent: int {
RuleName,
UtcTime,
ProcessGuid,
ProcessId,
Image,
TargetFilename,
CreationUtcTime,
User
};
private enum NetworkConnectionEvent: int
{
RuleName,
UtcTime,
ProcessGuid,
ProcessId,
Image,
User,
Protocol,
Initiated,
SourceIsIpv6,
SourceIp,
SourceHostname,
SourcePort,
SourcePortName,
DestinationIsIpv6,
DestinationIp,
DestinationHostname,
DestinationPort,
DestinationPortName,
};
private enum RegistryEvent: int
{
RuleName,
EventType,
UtcTime,
ProcessGuid,
ProcessId,
Image,
TargetObject,
Details,
User
}
private string clamAvConenctionString;
private IClamAvClient clamAvClient;
public FileEventMonitor(ServiceBase _parent, string workingDirectory, ILogger _logger)
{
parent = (ServiceMain)_parent;
logger = _logger;
try
{
clamAvConenctionString = parent.ReadSettingsValue("CLAMAV_HOST");
}
catch (Exception ex)
{
clamAvConenctionString = "tcp://127.0.0.1:3310";
logger.LogInformation($"Failed to read the address because of {ex.Message}. Set default: {clamAvConenctionString}");
}
ConnectToClamAv().Start();
}
public void Start()
{
try
{
string query = @"<QueryList>
<Query Id='0' Path='Microsoft-Windows-Sysmon/Operational'>
<Select Path='Microsoft-Windows-Sysmon/Operational'>*[System/EventID=11 or System/EventID=3 or System/EventID=12 or System/EventID=13 or System/EventID=14]</Select>
</Query>
</QueryList>";
EventLogQuery eventLogQuery = new EventLogQuery("Microsoft-Windows-Sysmon/Operational", PathType.LogName, query);
eventLogWatcher = new EventLogWatcher(eventLogQuery);
eventLogWatcher.EventRecordWritten += new EventHandler<EventRecordWrittenEventArgs>(OnEventRecordWritten);
eventLogWatcher.Enabled = true;
}
catch (Exception ex)
{
logger.LogInformation($"Could not reach to the Sysmon service: {ex.Message}");
}
}
public void Stop()
{
if (eventLogWatcher != null)
{
try
{
eventLogWatcher.Dispose();
eventLogWatcher = null;
}
catch (Exception)
{
eventLogWatcher = null;
}
}
}
private void OnEventRecordWritten(object sender, EventRecordWrittenEventArgs e)
{
if (e.EventRecord != null)
{
int eventId = e.EventRecord.Id;
try
{
switch (eventId)
{
case (int)EventType.FileCreate:
{
string ruleName = e.EventRecord.Properties[(int)FileCreateEvent.RuleName]?.Value?.ToString();
string processId = e.EventRecord.Properties[(int)FileCreateEvent.ProcessId]?.Value?.ToString();
string image = e.EventRecord.Properties[(int)FileCreateEvent.Image]?.Value?.ToString();
string fileName = e.EventRecord.Properties[(int)FileCreateEvent.TargetFilename]?.Value?.ToString();
logger.LogInformation($"> Detected the file creation: {fileName}");
logger.LogInformation(parent.DispatchServiceEvent("fileCreated", new string[] {
ruleName,
processId,
image,
fileName
}));
if (clamAvClient != null)
{
logger.LogInformation($"> Starting the ClamAV scan: {fileName}");
Task.Run(async () =>
{
await ScanWithClamAv(fileName);
});
}
break;
}
case (int)EventType.NetworkConnection:
{
string ruleName = e.EventRecord.Properties[(int)NetworkConnectionEvent.RuleName]?.Value?.ToString();
string processId = e.EventRecord.Properties[(int)NetworkConnectionEvent.ProcessId]?.Value?.ToString();
string image = e.EventRecord.Properties[(int)NetworkConnectionEvent.Image]?.Value?.ToString();
string protocol = e.EventRecord.Properties[(int)NetworkConnectionEvent.Protocol]?.Value?.ToString();
string destinationIp = e.EventRecord.Properties[(int)NetworkConnectionEvent.DestinationIp]?.Value?.ToString();
string desinationPort = e.EventRecord.Properties[(int)NetworkConnectionEvent.DestinationPort]?.Value?.ToString();
string dstinationAddress = $"{protocol}://{destinationIp}:{desinationPort}";
logger.LogInformation($"> Detected the network connection: {dstinationAddress}");
logger.LogInformation(parent.DispatchServiceEvent("networkConnected", new string[] {
ruleName,
processId,
image,
dstinationAddress
}));
break;
}
case (int)EventType.RegistryEvent_1:
case (int)EventType.RegistryEvent_2:
case (int)EventType.RegistryEvent_3:
{
string ruleName = e.EventRecord.Properties[(int)RegistryEvent.RuleName]?.Value?.ToString();
string processId = e.EventRecord.Properties[(int)RegistryEvent.ProcessId]?.Value?.ToString();
string image = e.EventRecord.Properties[(int)RegistryEvent.Image]?.Value?.ToString();
string eventType = e.EventRecord.Properties[(int)RegistryEvent.EventType]?.Value?.ToString();
string targetObject = e.EventRecord.Properties[(int)RegistryEvent.TargetObject]?.Value?.ToString();
logger.LogInformation($"> Detected the registry modification: {targetObject}");
logger.LogInformation(parent.DispatchServiceEvent("registryModified", new string[] {
ruleName,
processId,
image,
eventType,
targetObject
}));
break;
}
default:
throw new ArgumentException("Not supported event type");
}
}
catch (Exception ex)
{
logger.LogInformation($"Failed to process the event bacause of {ex.Message}.");
}
}
else
{
logger.LogInformation("The event instance was null.");
}
}
private async Task ConnectToClamAv()
{
try {
// Create a client
clamAvClient = ClamAvClient.Create(new Uri(clamAvConenctionString));
// Send PING command to ClamAV
await clamAvClient.PingAsync().ConfigureAwait(false);
// Get ClamAV engine and virus database version
VersionResult result = await clamAvClient.GetVersionAsync().ConfigureAwait(false);
logger.LogInformation($"ClamAV version {result.ProgramVersion}, Virus database version {result.VirusDbVersion}");
}
catch (Exception ex)
{
logger.LogInformation($"Failed to read the address because of {ex.Message}. {clamAvConenctionString}");
clamAvClient = null;
}
}
private async Task ScanWithClamAv(string remotePath)
{
ScanResult res = await clamAvClient.ScanRemotePathAsync(remotePath).ConfigureAwait(false);
logger.LogInformation($"> Scan result: Infected={res.Infected}, VirusName={res.VirusName}");
logger.LogInformation(parent.DispatchServiceEvent("avScanResult", new string[] {
res.Infected.ToString(),
res.VirusName
}));
}
}
}

View File

@ -0,0 +1,160 @@
// HeartbeatClient.cs
// Namhyeon Go <abuse@catswords.net>
// https://github.com/gnh1201/welsonjs
using Grpc.Core;
using System.Threading.Tasks;
using System;
using System.Management;
using System.ServiceProcess;
using Grpc.Net.Client;
using Grpc.Net.Client.Web;
using System.Net.Http;
using Microsoft.Extensions.Logging;
namespace WelsonJS.Service
{
public class HeartbeatClient
{
private readonly HeartbeatService.HeartbeatServiceClient _client;
private ILogger logger;
private readonly GrpcChannel _channel;
private int HeartbeatInterval;
private ServiceMain parent;
private string clientId;
private string serverAddress;
public HeartbeatClient(ServiceBase _parent, ILogger _logger)
{
parent = (ServiceMain)_parent;
logger = _logger;
HeartbeatInterval = int.Parse(parent.ReadSettingsValue("HEARTBEAT_INTERVAL") ?? "2000");
try
{
serverAddress = parent.ReadSettingsValue("GRPC_HOST");
if (String.IsNullOrEmpty(serverAddress))
{
throw new Exception("The server address could not be empty.");
}
}
catch (Exception ex)
{
serverAddress = "http://localhost:50051";
logger.LogInformation($"Failed to read the address because of {ex.Message}. Set default: {serverAddress}");
}
var httpClientHandler = new HttpClientHandler();
var grpcWebHandler = new GrpcWebHandler(GrpcWebMode.GrpcWebText, httpClientHandler);
_channel = GrpcChannel.ForAddress(serverAddress, new GrpcChannelOptions
{
HttpHandler = grpcWebHandler,
Credentials = ChannelCredentials.Insecure
});
_client = new HeartbeatService.HeartbeatServiceClient(_channel);
clientId = GetSystemUUID().ToLower();
logger.LogInformation($"Use the client ID: {clientId}");
}
public async Task StartHeartbeatAsync()
{
while (true)
{
var call = _client.CheckHeartbeat();
try
{
var request = new HeartbeatRequest
{
IsAlive = true
};
await call.RequestStream.WriteAsync(request);
await call.RequestStream.CompleteAsync();
logger.LogInformation("Sent heartbeat");
await Task.Delay(HeartbeatInterval); // Wait for HeartbeatInterval
}
catch (Exception ex)
{
logger.LogInformation("Heartbeat request stream failed: " + ex.Message);
}
// 서버 응답을 수신하는 작업
try
{
while (await call.ResponseStream.MoveNext())
{
var response = call.ResponseStream.Current;
logger.LogInformation("Heartbeat response received: " + response.IsAlive);
}
}
catch (RpcException ex)
{
logger.LogInformation($"gRPC error: {ex.Status.Detail}");
}
catch (Exception ex)
{
logger.LogInformation($"Unexpected error: {ex.Message}");
}
finally
{
// 잠시 대기 후 재연결
await Task.Delay(TimeSpan.FromMilliseconds(HeartbeatInterval));
}
}
}
public async Task StartEventListenerAsync()
{
var eventRequest = new FetchEventsRequest
{
ClientId = clientId
};
while (true)
{
var eventCall = _client.FetchPendingEvents(eventRequest);
try
{
while (await eventCall.ResponseStream.MoveNext())
{
var response = eventCall.ResponseStream.Current;
logger.LogInformation($"Received event from server: {response.EventType} with args: {string.Join(", ", response.Args)}");
}
}
finally
{
await Task.Delay(TimeSpan.FromMilliseconds(HeartbeatInterval));
}
}
}
public async Task ShutdownAsync()
{
await _channel.ShutdownAsync();
}
private string GetSystemUUID()
{
try
{
using (var searcher = new ManagementObjectSearcher("SELECT UUID FROM Win32_ComputerSystemProduct"))
{
foreach (var mo in searcher.Get())
{
return mo["UUID"].ToString();
}
}
}
catch (Exception ex)
{
logger.LogInformation($"An error occurred while retrieving the system UUID: {ex.Message}");
}
return "UNKNOWN";
}
}
}

View 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);
}
}
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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
}
}
}

View File

@ -0,0 +1,13 @@
using System;
namespace WelsonJS.Service.Model
{
public class FileMatchResult
{
public string Id { get; set; }
public string FilePath { get; set; }
public ulong Offset { get; set; }
public string RuleName { get; set; }
public DateTime LastChecked { get; set; }
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Drawing;
namespace WelsonJS.Service
{
public class ScreenMatchResult
{
public string FileName { get; set; }
public int ScreenNumber { get; set; }
public IntPtr WindowHandle { get; set; }
public string WindowTitle { get; set; }
public string ProcessName { get; set; }
public Point WindowPosition { get; set; }
public Point Position { get; set; }
public string Text { get; set; }
public override string ToString()
{
return $"Template: {FileName}, Screen Number: {ScreenNumber}, Window Title: {WindowTitle}, " +
$"Process Name: {ProcessName}, Window Position: (x: {WindowPosition.X}, y: {WindowPosition.Y}), " +
$"Location: (x: {Position.X}, y: {Position.Y})";
}
}
}

View File

@ -1,31 +1,63 @@
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)
{
ServiceMain svc = new ServiceMain();
svc.TestStartupAndStop(args);
Console.WriteLine("WelsonJS Service Application (User Interactive Mode)");
Console.WriteLine("https://github.com/gnh1201/welsonjs");
Console.WriteLine();
Console.WriteLine("Service is running...");
ServiceMain svc = new ServiceMain(args, logger);
svc.TestStartupAndStop();
}
else
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new ServiceMain()
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;
}
}
}

View File

@ -6,11 +6,11 @@ using System.Runtime.InteropServices;
// 제어됩니다. 어셈블리와 관련된 정보를 수정하려면
// 이러한 특성 값을 변경하세요.
[assembly: AssemblyTitle("WelsonJS.Service")]
[assembly: AssemblyDescription("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("1.2.7.20")]
[assembly: AssemblyFileVersion("1.2.7.20")]
[assembly: AssemblyVersion("0.2.7.54")]
[assembly: AssemblyFileVersion("0.2.7.54")]

View File

@ -0,0 +1,27 @@
syntax = "proto3";
option csharp_namespace = "WelsonJS.Service";
package heartbeat;
service HeartbeatService {
rpc CheckHeartbeat (stream HeartbeatRequest) returns (stream HeartbeatResponse);
rpc FetchPendingEvents (FetchEventsRequest) returns (stream FetchEventsResponse);
}
message HeartbeatRequest {
bool is_alive = 1;
}
message HeartbeatResponse {
bool is_alive = 1;
}
message FetchEventsRequest {
string client_id = 1;
}
message FetchEventsResponse {
string event_type = 1;
repeated string args = 2;
}

View File

@ -0,0 +1,927 @@
// ScreenMatching.cs
// https://github.com/gnh1201/welsonjs
// https://catswords-oss.rdbl.io/5719744820/8803957194
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.IO.Hashing;
using System.Runtime.InteropServices;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Linq;
using Tesseract;
using WelsonJS.Service;
using Microsoft.Extensions.Logging;
public class ScreenMatch
{
// User32.dll API 함수 선언
[DllImport("user32.dll")]
private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll")]
private static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern int GetWindowRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll")]
private static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("user32.dll")]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll")]
private static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("gdi32.dll")]
private static extern bool BitBlt(IntPtr hDestDC, int x, int y, int nWidth, int nHeight, IntPtr hSrcDC, int xSrc, int ySrc, int dwRop);
[DllImport("user32.dll", SetLastError = true)]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll")]
private static extern bool EnumDisplaySettings(string lpszDeviceName, int iModeNum, ref DEVMODE lpDevMode);
// https://stackoverflow.com/questions/60872044/how-to-get-scaling-factor-for-each-monitor-e-g-1-1-25-1-5
[StructLayout(LayoutKind.Sequential)]
private struct DEVMODE
{
private const int CCHDEVICENAME = 0x20;
private const int CCHFORMNAME = 0x20;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
public string dmDeviceName;
public short dmSpecVersion;
public short dmDriverVersion;
public short dmSize;
public short dmDriverExtra;
public int dmFields;
public int dmPositionX;
public int dmPositionY;
public ScreenOrientation dmDisplayOrientation;
public int dmDisplayFixedOutput;
public short dmColor;
public short dmDuplex;
public short dmYResolution;
public short dmTTOption;
public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
public string dmFormName;
public short dmLogPixels;
public int dmBitsPerPel;
public int dmPelsWidth;
public int dmPelsHeight;
public int dmDisplayFlags;
public int dmDisplayFrequency;
public int dmICMMethod;
public int dmICMIntent;
public int dmMediaType;
public int dmDitherType;
public int dmReserved1;
public int dmReserved2;
public int dmPanningWidth;
public int dmPanningHeight;
}
private const int SRCCOPY = 0x00CC0020;
// 델리게이트 선언
public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
// RECT 구조체 선언
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
private ServiceMain parent;
private ILogger logger;
private List<Bitmap> templateImages;
private string templateDirectoryPath;
private string outputDirectoryPath;
private int templateCurrentIndex = 0;
private double threshold = 0.3;
private string mode;
private bool busy;
private List<string> _params = new List<string>();
private bool isSearchFromEnd = false;
private bool isSaveToFile = false;
private Size sampleSize;
private int sampleAdjustX;
private int sampleAdjustY;
private List<string> sampleAny;
private List<string> sampleClipboard;
private List<string> sampleOcr;
private List<string> sampleNodup;
private Size sampleNodupSize;
private Queue<Bitmap> outdatedSamples;
private string tesseractDataPath;
private string tesseractLanguage;
private void SetBusy(bool busy)
{
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");
templateImages = new List<Bitmap>();
// Initialize variables for sampling process
sampleSize = new Size
{
Width = 128,
Height = 128
};
sampleAdjustX = 0;
sampleAdjustY = 0;
sampleAny = new List<string>();
sampleClipboard = new List<string>();
sampleOcr = new List<string>();
sampleNodup = new List<string>();
sampleNodupSize = new Size
{
Width = 180,
Height = 60
};
outdatedSamples = new Queue<Bitmap>();
// Read values from configration file
string screen_time_mode;
string screen_time_params;
try
{
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;
logger.LogInformation($"Failed to read from configration file: {ex.Message}");
}
if (!String.IsNullOrEmpty(screen_time_params))
{
var screen_time_configs = screen_time_params
.Split(',')
.Select(pair => pair.Split('='))
.ToDictionary(
parts => parts[0],
parts => parts.Length > 1 ? parts[1] : parts[0]
);
var config_keys = new string[]
{
"process_name",
"sample_width",
"sample_height",
"sample_adjust_x",
"sample_adjust_y",
"sample_any",
"sample_nodup",
"backward",
"save",
"sample_clipboard",
"sample_ocr"
};
foreach (var config_key in config_keys)
{
string config_value;
screen_time_configs.TryGetValue(config_key, out config_value);
if (config_value != null)
{
switch (config_key)
{
case "backward":
{
isSearchFromEnd = true;
logger.LogInformation("Use the backward search when screen time");
break;
}
case "save":
{
isSaveToFile = true;
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;
}
case "sample_clipboard":
{
sampleClipboard = new List<string>(config_value.Split(':'));
break;
}
case "sample_ocr":
{
tesseractDataPath = Path.Combine(workingDirectory, "app/assets/tessdata_best");
tesseractLanguage = "eng";
sampleOcr = new List<string>(config_value.Split(':'));
break;
}
case "sample_width":
{
int.TryParse(config_value, out int w);
sampleSize.Width = w;
break;
}
case "sample_height":
{
int.TryParse(config_value, out int h);
sampleSize.Height = h;
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);
break;
}
case "sample_adjust_y":
{
int.TryParse(config_value, out sampleAdjustY);
break;
}
case "sample_any":
{
sampleAny = new List<string>(config_value.Split(':'));
break;
}
case "sample_nodup":
{
sampleNodup = new List<string>(config_value.Split(':'));
break;
}
}
}
}
}
SetMode(screen_time_mode);
LoadTemplateImages();
}
public void SetMode(string mode)
{
if (!String.IsNullOrEmpty(mode))
{
this.mode = mode;
}
else
{
this.mode = "screen";
}
}
public void SetThreshold(double threshold)
{
this.threshold = threshold;
}
public void LoadTemplateImages()
{
string[] files;
try
{
files = Directory.GetFiles(templateDirectoryPath, "*.png");
}
catch (Exception ex)
{
files = new string[]{};
logger.LogInformation($"Failed to read the directory structure: {ex.Message}");
}
foreach (var file in files)
{
string filename = Path.GetFileName(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
};
if (!filename.StartsWith("no_"))
{
if (filename.StartsWith("binary_"))
{
templateImages.Add(ImageQuantize(bitmap));
}
else
{
templateImages.Add(bitmap);
}
}
}
}
// 캡쳐 및 템플릿 매칭 진행
public List<ScreenMatchResult> CaptureAndMatch()
{
List<ScreenMatchResult> results = new List<ScreenMatchResult>();
if (busy)
{
throw new Exception("Waiting done a previous job...");
}
if (templateImages.Count > 0)
{
SetBusy(true);
switch (mode)
{
case "screen": // 화면 기준
results = CaptureAndMatchAllScreens();
SetBusy(false);
break;
case "window": // 윈도우 핸들 기준
results = CaptureAndMatchAllWindows();
SetBusy(false);
break;
default:
SetBusy(false);
throw new Exception($"Unknown capture mode {mode}");
}
}
return results;
}
// 화면을 기준으로 찾기
public List<ScreenMatchResult> CaptureAndMatchAllScreens()
{
var results = new List<ScreenMatchResult>();
for (int i = 0; i < Screen.AllScreens.Length; i++)
{
Screen screen = Screen.AllScreens[i];
Bitmap mainImage = CaptureScreen(screen);
Bitmap templateImage = templateImages[templateCurrentIndex];
string templateName = templateImage.Tag as string;
TemplateInfo nextTemplateInfo = parent.GetNextTemplateInfo();
Size templateSize = new Size
{
Width = templateImage.Width,
Height = templateImage.Height
};
logger.LogInformation($"Trying match the template {templateName} on the screen {i}...");
if (!String.IsNullOrEmpty(nextTemplateInfo.FileName) && templateName != nextTemplateInfo.FileName)
{
logger.LogInformation($"Ignored the template {templateName}");
break;
}
Bitmap out_mainImage;
string out_filename;
if (templateName.StartsWith("binary_"))
{
out_mainImage = ImageQuantize((Bitmap)mainImage.Clone());
out_filename = $"{DateTime.Now:yyyy-MM-dd hh mm ss} binary.png";
}
else
{
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());
}
foreach (Point matchPosition in matchPositions)
{
try
{
string text = sampleAny.Contains(templateName) ?
InspectSample((Bitmap)mainImage.Clone(), matchPosition, templateSize, templateName, sampleSize) : string.Empty;
results.Add(new ScreenMatchResult
{
FileName = templateName,
ScreenNumber = i,
Position = matchPosition,
Text = text
});
break; // Only one
}
catch (Exception ex)
{
logger.LogInformation($"Ignore the match. {ex.Message}");
}
}
}
if (results.Count > 0)
{
logger.LogInformation("Match found");
}
else
{
logger.LogInformation($"No match found");
}
templateCurrentIndex = ++templateCurrentIndex % templateImages.Count;
return results;
}
public Bitmap CropBitmap(Bitmap bitmap, Point matchPosition, Size templateSize, Size sampleSize, int dx = 0, int dy = 0)
{
// Adjust coordinates to the center
int x = matchPosition.X + (templateSize.Width / 2);
int y = matchPosition.Y + (templateSize.Height / 2);
// Set range of crop image
int cropX = Math.Max((x - sampleSize.Width / 2) + dx, 0);
int cropY = Math.Max((y - sampleSize.Height / 2) + dy, 0);
int cropWidth = Math.Min(sampleSize.Width, bitmap.Width - cropX);
int cropHeight = Math.Min(sampleSize.Height, bitmap.Height - cropY);
Rectangle cropArea = new Rectangle(cropX, cropY, cropWidth, cropHeight);
// Crop image
return bitmap.Clone(cropArea, bitmap.PixelFormat);
}
public string InspectSample(Bitmap bitmap, Point matchPosition, Size templateSize, string templateName, Size sampleSize)
{
if (bitmap == null)
{
throw new ArgumentNullException(nameof(bitmap), "Bitmap cannot be null.");
}
if (matchPosition == null || matchPosition == Point.Empty)
{
throw new ArgumentException("matchPosition cannot be empty.");
}
// initialize the text
string text = "";
// Crop image
Bitmap croppedBitmap = CropBitmap(bitmap, matchPosition, templateSize, sampleSize, sampleAdjustX, sampleAdjustY);
// Save to the outdated samples
if (sampleNodup.Contains(templateName))
{
Bitmap croppedNodupBitmap = CropBitmap(bitmap, matchPosition, templateSize, sampleNodupSize);
uint bitmapCrc32 = ComputeBitmapCrc32(croppedNodupBitmap);
croppedNodupBitmap.Tag = new SampleInfo(templateName, bitmapCrc32);
bool bitmapExists = outdatedSamples.Any(x => ((SampleInfo)x.Tag).Crc32 == bitmapCrc32);
if (bitmapExists)
{
throw new InvalidOperationException($"This may be a duplicate request. {templateName}");
}
else
{
outdatedSamples.Enqueue(croppedNodupBitmap);
logger.LogInformation($"Added to the image queue. {templateName}");
}
}
// if use Clipboard
if (sampleClipboard.Contains(templateName))
{
logger.LogInformation($"Trying to use the clipboard... {templateName}");
Thread th = new Thread(new ThreadStart(() =>
{
try
{
Clipboard.SetImage((Bitmap)croppedBitmap.Clone());
logger.LogInformation($"Copied the image to Clipboard");
}
catch (Exception ex)
{
logger.LogInformation($"Failed to copy to the clipboard: {ex.Message}");
}
}));
th.SetApartmentState(ApartmentState.STA);
th.Start();
}
// if use OCR
if (sampleOcr.Contains(templateName))
{
try
{
using (var engine = new TesseractEngine(tesseractDataPath, tesseractLanguage, EngineMode.Default))
{
using (var page = engine.Process(croppedBitmap))
{
text = page.GetText();
logger.LogInformation($"Mean confidence: {page.GetMeanConfidence()}");
logger.LogInformation($"Text (GetText): {text}");
}
}
}
catch (Exception ex)
{
logger.LogInformation($"Failed to OCR: {ex.Message}");
}
}
return text;
}
public Bitmap CaptureScreen(Screen screen)
{
Rectangle screenSize = screen.Bounds;
decimal scalingFactor = GetScreenScalingFactor(screen);
int adjustedWidth = (int)(screenSize.Width * scalingFactor);
int adjustedHeight = (int)(screenSize.Height * scalingFactor);
Bitmap bitmap = new Bitmap(adjustedWidth, adjustedHeight);
using (Graphics bitmapGraphics = Graphics.FromImage(bitmap))
{
bitmapGraphics.CopyFromScreen(screenSize.Left, screenSize.Top, 0, 0, new Size(adjustedWidth, adjustedHeight));
}
return bitmap;
}
// 윈도우 핸들을 기준으로 찾기
public List<ScreenMatchResult> CaptureAndMatchAllWindows()
{
var results = new List<ScreenMatchResult>();
// 모든 윈도우 핸들을 열거
EnumWindows((hWnd, lParam) =>
{
if (IsWindowVisible(hWnd))
{
try
{
string windowTitle = GetWindowTitle(hWnd);
string processName = GetProcessName(hWnd);
GetWindowRect(hWnd, out RECT windowRect);
Point windowPosition = new Point(windowRect.Left, windowRect.Top);
Bitmap windowImage = CaptureWindow(hWnd);
if (windowImage != null)
{
Bitmap image = templateImages[templateCurrentIndex];
string templateName = image.Tag as string;
Size templateSize = new Size
{
Width = image.Width,
Height = image.Height
};
List<Point> matchPositions = FindTemplate(windowImage, image);
matchPositions.ForEach((matchPosition) =>
{
try
{
string text = sampleAny.Contains(templateName) ?
InspectSample((Bitmap)windowImage.Clone(), matchPosition, templateSize, templateName, sampleSize) : string.Empty;
results.Add(new ScreenMatchResult
{
FileName = templateName,
WindowHandle = hWnd,
WindowTitle = windowTitle,
ProcessName = processName,
WindowPosition = windowPosition,
Position = matchPosition,
Text = text
});
}
catch (Exception ex)
{
logger.LogInformation($"Ignore the match. {ex.Message}");
}
});
}
}
catch (Exception ex) {
logger.LogInformation($"Error {ex.Message}");
}
}
return true;
}, IntPtr.Zero);
templateCurrentIndex = ++templateCurrentIndex % templateImages.Count;
return results;
}
public string GetWindowTitle(IntPtr hWnd)
{
int length = GetWindowTextLength(hWnd);
StringBuilder sb = new StringBuilder(length + 1);
GetWindowText(hWnd, sb, sb.Capacity);
return sb.ToString();
}
public string GetProcessName(IntPtr hWnd)
{
uint processId;
GetWindowThreadProcessId(hWnd, out processId);
Process process = Process.GetProcessById((int)processId);
return process.ProcessName;
}
public Bitmap CaptureWindow(IntPtr hWnd)
{
GetWindowRect(hWnd, out RECT rect);
int width = rect.Right - rect.Left;
int height = rect.Bottom - rect.Top;
if (width <= 0 || height <= 0)
return null;
Bitmap bitmap = new Bitmap(width, height);
Graphics graphics = Graphics.FromImage(bitmap);
IntPtr hDC = graphics.GetHdc();
IntPtr windowDC = GetDC(hWnd);
bool success = BitBlt(hDC, 0, 0, width, height, windowDC, 0, 0, SRCCOPY);
ReleaseDC(hWnd, windowDC);
graphics.ReleaseHdc(hDC);
return success ? bitmap : null;
}
public List<Point> FindTemplate(Bitmap mainImage, Bitmap templateImage)
{
var matches = new List<Point>();
int mainWidth = mainImage.Width;
int mainHeight = mainImage.Height;
int templateWidth = templateImage.Width;
int templateHeight = templateImage.Height;
int startX = isSearchFromEnd ? mainWidth - templateWidth : 0;
int endX = isSearchFromEnd ? -1 : mainWidth - templateWidth + 1;
int stepX = isSearchFromEnd ? -1 : 1;
int startY = isSearchFromEnd ? mainHeight - templateHeight : 0;
int endY = isSearchFromEnd ? -1 : mainHeight - templateHeight + 1;
int stepY = isSearchFromEnd ? -1 : 1;
for (int x = startX; x != endX; x += stepX)
{
for (int y = startY; y != endY; y += stepY)
{
if (IsTemplateMatch(mainImage, templateImage, x, y, threshold))
{
matches.Add(new Point(x, y));
}
}
}
return matches;
}
private bool IsTemplateMatch(Bitmap mainImage, Bitmap templateImage, int offsetX, int offsetY, double threshold)
{
int templateWidth = templateImage.Width;
int templateHeight = templateImage.Height;
int totalPixels = templateWidth * templateHeight;
int requiredMatches = (int)(totalPixels * threshold);
// When the square root of the canvas size of the image to be matched is less than 10, a complete match is applied.
if (Math.Sqrt(templateWidth * templateHeight) < 10.0)
{
for (int y = 0; y < templateHeight; y++)
{
for (int x = 0; x < templateWidth; x++)
{
if (mainImage.GetPixel(x + offsetX, y + offsetY) != templateImage.GetPixel(x, y))
{
return false;
}
}
}
return true;
}
// Otherwise, randomness is used.
int matchedCount = 0;
Random rand = new Random();
while (matchedCount < requiredMatches)
{
int x = rand.Next(templateWidth);
int y = rand.Next(templateHeight);
if (mainImage.GetPixel(x + offsetX, y + offsetY) != templateImage.GetPixel(x, y))
{
return false;
}
matchedCount++;
}
return true;
}
private Bitmap ImageQuantize(Bitmap image, int levels = 4)
{
Bitmap quantizedImage = new Bitmap(image.Width, image.Height);
if (image.Tag != null)
{
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++)
{
// Convert the pixel to grayscale
Color pixelColor = image.GetPixel(x, y);
byte grayValue = (byte)((pixelColor.R + pixelColor.G + pixelColor.B) / 3);
// 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 quantizedImage;
}
private uint ComputeBitmapCrc32(Bitmap bitmap)
{
using (MemoryStream ms = new MemoryStream())
{
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
byte[] bitmapBytes = ms.ToArray();
Crc32 crc32 = new Crc32();
crc32.Append(bitmapBytes);
return BitConverter.ToUInt32(crc32.GetCurrentHash(), 0);
}
}
}

View File

@ -28,8 +28,11 @@
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
//
// ServiceMain
//
this.ServiceName = "ServiceMain";
}
#endregion

View File

@ -20,47 +20,58 @@
*
* references:
* - https://learn.microsoft.com/en-us/dotnet/framework/windows-services/how-to-debug-windows-service-applications
* - https://stackoverflow.com/questions/6490979/how-to-pass-parameters-to-windows-service
* - https://stackoverflow.com/questions/42812333/pass-an-argument-to-a-windows-service-at-automatic-startup
* - https://learn.microsoft.com/ko-kr/windows/win32/api/winuser/nf-winuser-getsystemmetrics
*/
using System;
using System.ServiceProcess;
using System.Timers;
using System.Runtime.InteropServices;
using MSScriptControl;
using System.IO;
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 Timer timer;
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 string scriptName;
private ScriptControl scriptControl;
private string logFilePath;
private readonly string appName = "WelsonJS";
private string[] args;
private bool disabledHeartbeat = false;
private bool disabledScreenTime = false;
private bool disabledFileMonitor = false;
private ScreenMatch screenMatcher;
private FileEventMonitor fileEventMonitor;
private IniFile settingsFileHandler;
private UserVariables userVariablesHandler;
public ServiceMain()
[DllImport("user32.dll")]
private static extern int GetSystemMetrics(int nIndex);
private static int SM_REMOTESESSION = 0x1000;
public ServiceMain(string[] _args, ILogger _logger)
{
InitializeComponent();
// set the log file path
logFilePath = Path.Combine(Path.GetTempPath(), "WelsonJS.Service.Log.txt");
Log(appName + " Service Loaded");
}
// set arguments and logger
args = _args;
logger = _logger;
internal void TestStartupAndStop(string[] args)
{
this.OnStart(args);
Console.ReadLine();
this.OnStop();
}
protected override void OnStart(string[] args)
{
// mapping arguments to each variables
var arguments = ParseArguments(args);
var arguments = ParseArguments(this.args);
foreach (KeyValuePair<string, string> entry in arguments)
{
switch (entry.Key)
@ -72,37 +83,172 @@ namespace WelsonJS.Service
case "script-name":
scriptName = entry.Value;
break;
case "disable-heartbeat":
disabledHeartbeat = true;
break;
case "disable-screen-time":
disabledScreenTime = true;
break;
case "disable-file-monitor":
disabledFileMonitor = true;
break;
}
}
// 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);
// read settings.ini
string settingsFilePath = Path.Combine(workingDirectory, "settings.ini");
if (File.Exists(settingsFilePath))
{
try
{
settingsFileHandler = new IniFile(settingsFilePath);
}
catch (Exception ex)
{
logger.LogWarning(ex.Message);
}
}
else
{
logger.LogInformation($"Configuration file not found: {settingsFilePath}");
}
// read configrations from settings.ini
if (settingsFileHandler != null)
{
string[] configNames = new string[]
{
"DISABLE_HEARTBEAT",
"DISABLE_SCREEN_TIME",
"DISABLE_FILE_MONITOR"
};
foreach (string configName in configNames)
{
try
{
if ("true" == ReadSettingsValue(configName))
{
switch (configName)
{
case "DISABLE_HEARTBEAT":
disabledHeartbeat = true;
break;
case "DISABLE_SCREEN_TIME":
disabledScreenTime = true;
break;
case "DISABLE_FILE_MONITOR":
disabledFileMonitor = true;
break;
default:
break;
}
}
}
catch (Exception ex)
{
logger.LogInformation($"{configName} is ignored: {ex.Message}");
}
}
}
// set script name
if (string.IsNullOrEmpty(scriptName))
{
scriptName = "helloworld";
Log("Script name not provided. Using default value: " + scriptName);
scriptName = "defaultService";
logger.LogInformation($"Script name not provided. Using default value: {scriptName}");
}
// set path of the script
scriptFilePath = Path.Combine(workingDirectory, "app.js");
// check the script file exists
// start the heartbeat
if (!disabledHeartbeat)
{
HeartbeatClient heartbeatClient = new HeartbeatClient(this, logger);
Task.Run(heartbeatClient.StartHeartbeatAsync);
Task.Run(heartbeatClient.StartEventListenerAsync);
}
// set default timer
Timer defaultTimer = new Timer
{
Interval = 60000 // 1 minute
};
defaultTimer.Elapsed += OnElapsedTime;
timers.Add(defaultTimer);
// check this session is the user interactive mode
if (Environment.UserInteractive) {
OnUserInteractiveEnvironment();
}
else
{
logger.LogInformation("Disabled the User Interactive Mode. (e.g., OnScreenTime)");
}
logger.LogInformation(applicationName + " Service Loaded");
}
public string ReadSettingsValue(string key, string defaultValue = null)
{
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()
{
this.OnStart(this.args);
Console.ReadLine();
this.OnStop();
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
// Check exists the entry script file
if (File.Exists(scriptFilePath))
{
Log($"Script file found: {scriptFilePath}");
logger.LogInformation($"Script file found: {scriptFilePath}");
try
{
@ -116,83 +262,173 @@ namespace WelsonJS.Service
scriptControl.Reset();
scriptControl.AddCode(scriptText);
// make the start arguments
string[] startArguments;
string[] _args;
if (Environment.UserInteractive)
{
_args = new string[]
{
$"--env-file={userVariablesHandler.GetEnvFilePath()}",
"--user-interactive"
};
}
else
{
_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(InvokeScriptMethod("initializeService", scriptName, "start"));
logger.LogInformation(DispatchServiceEvent("start", startArguments));
}
catch (Exception ex)
{
Log("Exception when start: " + 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}");
}
// set interval
timer = new Timer();
timer.Interval = 60000; // 1 minute
timer.Elapsed += OnElapsedTime;
timer.Start();
// Trace a Sysmon file events (If Sysinternals Sysmon installed)
if (!disabledFileMonitor)
{
fileEventMonitor = new FileEventMonitor(this, workingDirectory, logger);
fileEventMonitor.Start();
Log(appName + " Service Started");
logger.LogInformation("File Event Monitor Started");
}
else
{
logger.LogInformation("File Event Monitor is Disabled");
}
// Start all the registered timers
timers.ForEach(timer => timer?.Start());
logger.LogInformation(applicationName + " Service Started");
}
protected override void OnStop()
{
timer.Stop();
// stop timers
timers.ForEach(timer => timer?.Stop());
// stop the File Event Monitor
fileEventMonitor?.Stop();
// dispatch stop callback
try
{
Log(InvokeScriptMethod("initializeService", scriptName, "stop"));
if (scriptControl != null)
{
scriptControl.Reset();
}
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()
{
// check is it a remote desktop session
if (GetSystemMetrics(SM_REMOTESESSION) > 0)
{
disabledScreenTime = true;
logger.LogInformation("This application may not work correctly in a remote desktop session");
}
// set screen timer
if (!disabledScreenTime)
{
screenMatcher = new ScreenMatch(this, workingDirectory, logger);
Timer screenTimer = new Timer
{
Interval = 1000 // 1 seconds
};
screenTimer.Elapsed += OnScreenTime;
timers.Add(screenTimer);
logger.LogInformation("Screen Time Event Enabled");
}
else
{
disabledScreenTime = true;
logger.LogInformation("Screen Time Event Disabled");
}
}
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
try
{
Log(InvokeScriptMethod("initializeService", scriptName, "elapsedTime"));
logger.LogInformation(DispatchServiceEvent("elapsedTime"));
}
catch (Exception ex)
{
Log("Exception when elapsed time: " + ex.Message);
logger.LogInformation("Exception when elapsed time: " + ex.Message);
}
}
private string InvokeScriptMethod(string methodName, params object[] parameters)
private void OnScreenTime(object source, ElapsedEventArgs e)
{
try
{
List<ScreenMatchResult> matchedResults = screenMatcher.CaptureAndMatch();
matchedResults.ForEach(result =>
{
logger.LogInformation(DispatchServiceEvent("screenTemplateMatched", new string[]
{
result.FileName,
result.ScreenNumber.ToString(),
result.Position.X.ToString(),
result.Position.Y.ToString()
}));
});
}
catch (Exception ex)
{
logger.LogInformation($"Waiting a next screen time... {ex.Message}");
}
}
private string InvokeScriptMethod(string methodName, string scriptName, string eventType, string[] args)
{
if (scriptControl != null)
{
object[] parameters = new object[] {
scriptName,
eventType,
new ArrayList(args),
args.Length
};
//scriptControl.AddObject("extern_arguments", new ArrayList(args), true);
return scriptControl.Run(methodName, parameters)?.ToString() ?? "void";
}
else
{
Log("InvokeScriptMethod Ignored: " + methodName);
logger.LogInformation("InvokeScriptMethod Ignored: " + methodName);
}
return "void";
}
private void Log(string message)
{
using (StreamWriter writer = new StreamWriter(logFilePath, true))
{
writer.WriteLine($"{DateTime.Now}: {message}");
}
}
private Dictionary<string, string> ParseArguments(string[] args)
{
var arguments = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
@ -205,13 +441,56 @@ 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
{
var key = arg.Substring(2, index - 2);
arguments[key] = "";
}
}
}
return arguments;
}
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)
{
logger.LogInformation($"Use all templates because of {ex.Message}");
}
return new ScreenMatch.TemplateInfo(templateName, index);
}
public string DispatchServiceEvent(string eventType, string[] args = null)
{
if (args == null)
{
return InvokeScriptMethod("dispatchServiceEvent", scriptName, eventType, new string[] { });
}
else
{
return InvokeScriptMethod("dispatchServiceEvent", scriptName, eventType, args);
}
}
}
}

View 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;
}
}
}

View File

@ -1,17 +1,35 @@
<?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.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>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{09F295EE-5EDB-4327-ABBE-DDCCDF5EDD9E}</ProjectGuid>
<OutputType>WinExe</OutputType>
<OutputType>Exe</OutputType>
<RootNamespace>WelsonJS.Service</RootNamespace>
<AssemblyName>WelsonJS.Service</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<TargetFrameworkProfile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<PublishUrl>게시\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@ -78,16 +96,131 @@
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>favicon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<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.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.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.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.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.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.Configuration, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Configuration.8.0.0\lib\net462\Microsoft.Extensions.Configuration.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Configuration.Abstractions, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Configuration.Abstractions.8.0.0\lib\net462\Microsoft.Extensions.Configuration.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Configuration.Binder, Version=8.0.0.2, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Configuration.Binder.8.0.2\lib\net462\Microsoft.Extensions.Configuration.Binder.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.DependencyInjection, Version=8.0.0.1, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.8.0.1\lib\net462\Microsoft.Extensions.DependencyInjection.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=8.0.0.2, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.8.0.2\lib\net462\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Logging, Version=8.0.0.1, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Logging.8.0.1\lib\net462\Microsoft.Extensions.Logging.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=8.0.0.2, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.8.0.2\lib\net462\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Logging.Configuration, Version=8.0.0.1, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Logging.Configuration.8.0.1\lib\net462\Microsoft.Extensions.Logging.Configuration.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Logging.Console, Version=8.0.0.1, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Logging.Console.8.0.1\lib\net462\Microsoft.Extensions.Logging.Console.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Options, Version=8.0.0.2, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Options.8.0.2\lib\net462\Microsoft.Extensions.Options.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Options.ConfigurationExtensions, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Options.ConfigurationExtensions.8.0.0\lib\net462\Microsoft.Extensions.Options.ConfigurationExtensions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Primitives, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Primitives.8.0.0\lib\net462\Microsoft.Extensions.Primitives.dll</HintPath>
</Reference>
<Reference Include="RestSharp, Version=112.1.0.0, Culture=neutral, PublicKeyToken=598062e77f915f75, processorArchitecture=MSIL">
<HintPath>..\packages\RestSharp.112.1.0\lib\net48\RestSharp.dll</HintPath>
</Reference>
<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">
<HintPath>..\packages\System.Diagnostics.DiagnosticSource.8.0.1\lib\net462\System.Diagnostics.DiagnosticSource.dll</HintPath>
</Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.IO.Hashing, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.IO.Hashing.8.0.0\lib\net462\System.IO.Hashing.dll</HintPath>
</Reference>
<Reference Include="System.Management" />
<Reference Include="System.Memory, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.WinHttpHandler, Version=8.0.0.2, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Net.Http.WinHttpHandler.8.0.2\lib\net462\System.Net.Http.WinHttpHandler.dll</HintPath>
</Reference>
<Reference Include="System.Numerics" />
<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>
<Reference Include="System.ServiceProcess" />
<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.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>
</Reference>
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Web" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="Tesseract, Version=5.2.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Tesseract.5.2.0\lib\net48\Tesseract.dll</HintPath>
</Reference>
</ItemGroup>
<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>
</Compile>
@ -102,6 +235,9 @@
<DependentUpon>ProjectInstaller.cs</DependentUpon>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ScreenMatch.cs" />
<Compile Include="Model\ScreenMatchResult.cs" />
<Compile Include="UserVariables.cs" />
</ItemGroup>
<ItemGroup>
<COMReference Include="MSScriptControl">
@ -122,6 +258,43 @@
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WelsonJS.Toolkit\WelsonJS.Toolkit.csproj">
<Project>{d6007282-b4f7-4694-ac67-bb838d91b77a}</Project>
<Name>WelsonJS.Toolkit</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.8">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.8%28x86 및 x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<Content Include="favicon.ico" />
</ItemGroup>
<ItemGroup>
<Protobuf Include="Protos\heartbeat.proto" GrpcServices="Client" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<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\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\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>

View File

@ -1,3 +1,100 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" /></startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.2" newVersion="4.0.1.2" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Bcl.AsyncInterfaces" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.Logging.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<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" />
<bindingRedirect oldVersion="0.0.0.0-8.0.0.1" newVersion="8.0.0.1" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Net.Http.WinHttpHandler" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-8.0.0.2" newVersion="8.0.0.2" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="DeviceId" publicKeyToken="f755c371b5c59c52" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.7.0.0" newVersion="6.7.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Google.Protobuf" publicKeyToken="a7d26565bac4d604" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.27.3.0" newVersion="3.27.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Grpc.Core" publicKeyToken="d754f35622e28bad" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Grpc.Core.Api" publicKeyToken="d754f35622e28bad" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Grpc.Net.Client" publicKeyToken="d754f35622e28bad" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Grpc.Net.Client.Web" publicKeyToken="d754f35622e28bad" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Grpc.Net.Common" publicKeyToken="d754f35622e28bad" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.Extensions.DependencyInjection.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-8.0.0.2" newVersion="8.0.0.2" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="RestSharp" publicKeyToken="598062e77f915f75" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-112.0.0.0" newVersion="112.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.4.0" newVersion="4.1.4.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Text.Encodings.Web" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Text.Json" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

View File

@ -0,0 +1,38 @@
<?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.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.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.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" />
<package id="System.Memory" version="4.5.5" targetFramework="net48" />
<package id="System.Net.Http.WinHttpHandler" version="8.0.2" targetFramework="net48" />
<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.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" />
</packages>

View File

@ -7,40 +7,40 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WelsonJS.Toolkit", "WelsonJ
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WelsonJS.Service", "WelsonJS.Service\WelsonJS.Service.csproj", "{09F295EE-5EDB-4327-ABBE-DDCCDF5EDD9E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WelsonJS.Launcher", "WelsonJS.Launcher\WelsonJS.Launcher.csproj", "{4074D413-195C-45E9-9E63-0D07914187B8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D6007282-B4F7-4694-AC67-BB838D91B77A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D6007282-B4F7-4694-AC67-BB838D91B77A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D6007282-B4F7-4694-AC67-BB838D91B77A}.Debug|x64.ActiveCfg = Debug|x64
{D6007282-B4F7-4694-AC67-BB838D91B77A}.Debug|x64.Build.0 = Debug|x64
{D6007282-B4F7-4694-AC67-BB838D91B77A}.Debug|x86.ActiveCfg = Debug|x86
{D6007282-B4F7-4694-AC67-BB838D91B77A}.Debug|x86.Build.0 = Debug|x86
{D6007282-B4F7-4694-AC67-BB838D91B77A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D6007282-B4F7-4694-AC67-BB838D91B77A}.Release|Any CPU.Build.0 = Release|Any CPU
{D6007282-B4F7-4694-AC67-BB838D91B77A}.Release|x64.ActiveCfg = Release|x64
{D6007282-B4F7-4694-AC67-BB838D91B77A}.Release|x64.Build.0 = Release|x64
{D6007282-B4F7-4694-AC67-BB838D91B77A}.Release|x86.ActiveCfg = Release|x86
{D6007282-B4F7-4694-AC67-BB838D91B77A}.Release|x86.Build.0 = Release|x86
{09F295EE-5EDB-4327-ABBE-DDCCDF5EDD9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{09F295EE-5EDB-4327-ABBE-DDCCDF5EDD9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{09F295EE-5EDB-4327-ABBE-DDCCDF5EDD9E}.Debug|x64.ActiveCfg = Debug|x64
{09F295EE-5EDB-4327-ABBE-DDCCDF5EDD9E}.Debug|x64.Build.0 = Debug|x64
{09F295EE-5EDB-4327-ABBE-DDCCDF5EDD9E}.Debug|x86.ActiveCfg = Debug|x86
{09F295EE-5EDB-4327-ABBE-DDCCDF5EDD9E}.Debug|x86.Build.0 = Debug|x86
{09F295EE-5EDB-4327-ABBE-DDCCDF5EDD9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{09F295EE-5EDB-4327-ABBE-DDCCDF5EDD9E}.Release|Any CPU.Build.0 = Release|Any CPU
{09F295EE-5EDB-4327-ABBE-DDCCDF5EDD9E}.Release|x64.ActiveCfg = Release|x86
{09F295EE-5EDB-4327-ABBE-DDCCDF5EDD9E}.Release|x64.Build.0 = Release|x86
{09F295EE-5EDB-4327-ABBE-DDCCDF5EDD9E}.Release|x86.ActiveCfg = Release|x86
{09F295EE-5EDB-4327-ABBE-DDCCDF5EDD9E}.Release|x86.Build.0 = Release|x86
{4074D413-195C-45E9-9E63-0D07914187B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4074D413-195C-45E9-9E63-0D07914187B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4074D413-195C-45E9-9E63-0D07914187B8}.Debug|x86.ActiveCfg = Debug|x86
{4074D413-195C-45E9-9E63-0D07914187B8}.Debug|x86.Build.0 = Debug|x86
{4074D413-195C-45E9-9E63-0D07914187B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4074D413-195C-45E9-9E63-0D07914187B8}.Release|Any CPU.Build.0 = Release|Any CPU
{4074D413-195C-45E9-9E63-0D07914187B8}.Release|x86.ActiveCfg = Release|x86
{4074D413-195C-45E9-9E63-0D07914187B8}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View 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);
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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));
}
}
}

View 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);
}
}
}
}

View 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;
}
}
}

View 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;
}
}
}
}

View File

@ -27,7 +27,7 @@ namespace WelsonJS
{
public class ProcessUtils
{
public static List<int> ProcessIDs = new List<int>();
public static List<Process> ProcessList = new List<Process>();
public static string OpenFileDialog()
{
@ -48,12 +48,14 @@ namespace WelsonJS
public static int Open(string filepath)
{
int processId = -1;
if (string.IsNullOrEmpty(filepath))
{
filepath = OpenFileDialog();
if (string.IsNullOrEmpty(filepath))
{
return -1;
return processId;
}
}
@ -62,16 +64,13 @@ namespace WelsonJS
Process process = new Process();
process.StartInfo.FileName = filepath;
process.Start();
int processId = process.Id;
ProcessIDs.Add(processId);
return processId;
ProcessList.Add(process);
}
catch
{
return -1;
catch {
processId = -1;
}
return processId;
}
public static bool Close(int processId)
@ -79,12 +78,13 @@ namespace WelsonJS
try
{
Process.GetProcessById(processId).CloseMainWindow();
return true;
}
catch
{
return false;
}
return true;
}
}
}

View File

@ -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")]

View File

@ -0,0 +1,28 @@
using System.Collections.Generic;
using System.Text;
namespace WelsonJS.Serialization
{
public class KVSerializer
{
private static Dictionary<string, string> dict = new Dictionary<string, string>();
public void Add(string key, string value)
{
dict[key] = value;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
foreach (var x in dict)
{
sb.Append($"{x.Key}={x.Value}; ");
}
if (sb.Length > 0) sb.Length -= 2;
return sb.ToString();
}
}
}

View File

@ -0,0 +1,74 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
// TinyINIController
// Original source code: https://github.com/niklyadov/tiny-ini-file-class
namespace WelsonJS.TinyINIController
{
public class IniFile
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
static extern long WritePrivateProfileString(string section, string key, string value, string FilePath);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
static extern int GetPrivateProfileString(string section, string key, string Default, StringBuilder RetVal, int Size, string FilePath);
private readonly FileInfo FileInfo;
//private readonly string exe = Assembly.GetExecutingAssembly().GetName().Name;
private readonly string defaultSection = "Default";
private readonly FileAccess fileAccess;
public IniFile(string path = null, FileAccess access = FileAccess.ReadWrite)
{
fileAccess = access;
FileInfo = new FileInfo(path ?? defaultSection);
}
public string Read(string key, string section = null)
{
var RetVal = new StringBuilder(65025);
if (fileAccess != FileAccess.Write)
{
GetPrivateProfileString(section ?? defaultSection, key, "", RetVal, 65025, FileInfo.FullName);
}
else
{
throw new Exception("Can`t read file! No access!");
}
return RetVal.ToString();
}
public void Write(string key, string value, string section = null)
{
if (fileAccess != FileAccess.Read)
{
WritePrivateProfileString(section ?? defaultSection, key, value, FileInfo.FullName);
}
else
{
throw new Exception("Can`t write to file! No access!");
}
}
public void DeleteKey(string key, string section = null)
{
Write(key, null, section ?? defaultSection);
}
public void DeleteSection(string section = null)
{
Write(null, null, section ?? defaultSection);
}
public bool KeyExists(string key, string section = null)
{
return Read(key, section).Length > 0;
}
}
}

View File

@ -34,6 +34,7 @@ using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using WelsonJS.Cryptography;
using WelsonJS.Serialization;
namespace WelsonJS
{
@ -224,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);
@ -234,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);
@ -247,21 +248,25 @@ namespace WelsonJS
public string GetImageSize(string srcfile)
{
int[] result = BitmapUtils.GetSize(srcfile);
int width = result[0];
int height = result[1];
return $"width={width}; height={height}";
var serializer = new KVSerializer();
serializer.Add("width", result[0].ToString());
serializer.Add("height", result[1].ToString());
return serializer.ToString();
}
[ComVisible(true)]
public string GetImagePixel(string srcfile)
{
int[] result = BitmapUtils.GetSize(srcfile);
int red = result[0];
int green = result[1];
int blue = result[2];
return $"red={red}; green={green}; blue={blue}";
var serializer = new KVSerializer();
serializer.Add("red", result[0].ToString());
serializer.Add("green", result[1].ToString());
serializer.Add("blue", result[2].ToString());
return serializer.ToString();
}
[ComVisible(true)]
@ -275,7 +280,5 @@ namespace WelsonJS
{
BitmapUtils.Crop(srcfile, dstfile, x, y, a, b);
}
}
}

View File

@ -77,6 +77,10 @@
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>favicon.ico</ApplicationIcon>
<PackageIcon>icon.png</PackageIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Drawing" />
@ -85,16 +89,28 @@
<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" />
<Compile Include="Serialization\KVSerializer.cs" />
<Compile Include="TinyINIController\IniFile.cs" />
<Compile Include="Toolkit.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Window.cs" />
</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" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View 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>

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

212
app.js
View File

@ -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 {
@ -216,9 +193,12 @@ if (typeof CreateObject === "undefined") {
/**
* @FN {string} The name of the file.
*/
function __evalFile(FN) {
if (FN.substring(FN.length - 3) !== '.js') FN += ".js";
return eval(require._load(FN));
function __evalFile__(FN) {
try {
return eval(require._load(FN));
} catch (e) {
console.error(e.message);
}
}
/**
@ -235,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);
@ -247,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) {
@ -260,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
@ -344,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;
@ -356,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 '';
@ -589,24 +590,46 @@ function initializeWindow(name, args, w, h) {
}
}
function initializeService(name, eventType) {
function dispatchServiceEvent(name, eventType, w_args, argl) {
var app = require(name);
var args = [];
// convert the arguments to Array
for (var i = 0; i < argl; i++) {
args.push(w_args(i));
}
// load the service
if (app) {
var bind = function(eventType) {
var event_callback_name = "on" + eventType;
if (event_callback_name in app && typeof app[event_callback_name] === "function")
return app[event_callback_name];
return null;
};
return (function(action) {
if (eventType in action) {
try {
var f = action[eventType];
if (typeof f === "function") return f();
return (function(f) {
return (typeof f !== "function" ? null : f(args));
})(action[eventType]);
} catch (e) {
console.error("Exception:", e.message);
}
}
})({
start: app.onServiceStart,
stop: app.onServiceStop,
elapsedTime: app.onServiceElapsedTime
start: bind("ServiceStart"),
stop: bind("ServiceStop"),
elapsedTime: bind("ServiceElapsedTime"),
screenNextTemplate: bind("ScreenNextTemplate"),
screenTemplateMatched: bind("ScreenTemplateMatched"),
fileCreated: bind("FileCreated"),
networkConnected: bind("NetworkConnected"),
registryModified: bind("RegistryModified"),
avScanResult: bind("AvScanResult")
});
} else {
console.error("Could not find", name + ".js");
@ -633,14 +656,14 @@ if (!Date.prototype.toISOString) {
// JSON 2
if (typeof JSON === "undefined") {
__evalFile("app/assets/js/json2");
__evalFile__("app/assets/js/json2.js");
}
// core-js (aka. babel-polyfill)
require("app/assets/js/core-js-3.26.1.minified");
// core-js (formerly, babel-polyfill)
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");
@ -652,8 +675,14 @@ 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.js")._default;
var Enumerable = require("app/assets/js/linq-4.0.2.wsh")._default;
// PEG.js: Parser generator for JavaScript
var PEG = require("app/assets/js/peg-0.10.0");
// Dive into entrypoint
function __main__() {
@ -664,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") {

View 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

View File

@ -0,0 +1 @@
.lm_root{position:relative}.lm_row>.lm_item{float:left}.lm_content{overflow:hidden;position:relative}.lm_dragging,.lm_dragging *{cursor:move !important;user-select:none}.lm_maximised{position:absolute;top:0;left:0;z-index:40}.lm_maximise_placeholder{display:none}.lm_splitter{position:relative;z-index:20}.lm_splitter:hover,.lm_splitter.lm_dragging{background:orange}.lm_splitter.lm_vertical .lm_drag_handle{width:100%;position:absolute;cursor:ns-resize}.lm_splitter.lm_horizontal{float:left;height:100%}.lm_splitter.lm_horizontal .lm_drag_handle{height:100%;position:absolute;cursor:ew-resize}.lm_header{overflow:visible;position:relative;z-index:1}.lm_header [class^=lm_]{box-sizing:content-box !important}.lm_header .lm_controls{position:absolute;right:3px}.lm_header .lm_controls>li{cursor:pointer;float:left;width:18px;height:18px;text-align:center}.lm_header ul{margin:0;padding:0;list-style-type:none}.lm_header .lm_tabs{position:absolute}.lm_header .lm_tab{cursor:pointer;float:left;height:14px;margin-top:1px;padding:0 10px 5px;padding-right:25px;position:relative}.lm_header .lm_tab i{width:2px;height:19px;position:absolute}.lm_header .lm_tab i.lm_left{top:0;left:-2px}.lm_header .lm_tab i.lm_right{top:0;right:-2px}.lm_header .lm_tab .lm_title{display:inline-block;overflow:hidden;text-overflow:ellipsis}.lm_header .lm_tab .lm_close_tab{width:14px;height:14px;position:absolute;top:0;right:0;text-align:center}.lm_stack.lm_left .lm_header,.lm_stack.lm_right .lm_header{height:100%}.lm_dragProxy.lm_left .lm_header,.lm_dragProxy.lm_right .lm_header,.lm_stack.lm_left .lm_header,.lm_stack.lm_right .lm_header{width:20px;float:left;vertical-align:top}.lm_dragProxy.lm_left .lm_header .lm_tabs,.lm_dragProxy.lm_right .lm_header .lm_tabs,.lm_stack.lm_left .lm_header .lm_tabs,.lm_stack.lm_right .lm_header .lm_tabs{transform-origin:left top;top:0;width:1000px}.lm_dragProxy.lm_left .lm_header .lm_controls,.lm_dragProxy.lm_right .lm_header .lm_controls,.lm_stack.lm_left .lm_header .lm_controls,.lm_stack.lm_right .lm_header .lm_controls{bottom:0}.lm_dragProxy.lm_left .lm_items,.lm_dragProxy.lm_right .lm_items,.lm_stack.lm_left .lm_items,.lm_stack.lm_right .lm_items{float:left}.lm_dragProxy.lm_left .lm_header .lm_tabs,.lm_stack.lm_left .lm_header .lm_tabs{transform:rotate(-90deg) scaleX(-1);left:0}.lm_dragProxy.lm_left .lm_header .lm_tabs .lm_tab,.lm_stack.lm_left .lm_header .lm_tabs .lm_tab{transform:scaleX(-1);margin-top:1px}.lm_dragProxy.lm_left .lm_header .lm_tabdropdown_list,.lm_stack.lm_left .lm_header .lm_tabdropdown_list{top:initial;right:initial;left:20px}.lm_dragProxy.lm_right .lm_content{float:left}.lm_dragProxy.lm_right .lm_header .lm_tabs,.lm_stack.lm_right .lm_header .lm_tabs{transform:rotate(90deg) scaleX(1);left:100%;margin-left:0}.lm_dragProxy.lm_right .lm_header .lm_controls,.lm_stack.lm_right .lm_header .lm_controls{left:3px}.lm_dragProxy.lm_right .lm_header .lm_tabdropdown_list,.lm_stack.lm_right .lm_header .lm_tabdropdown_list{top:initial;right:20px}.lm_dragProxy.lm_bottom .lm_header .lm_tab,.lm_stack.lm_bottom .lm_header .lm_tab{margin-top:0;border-top:none}.lm_dragProxy.lm_bottom .lm_header .lm_controls,.lm_stack.lm_bottom .lm_header .lm_controls{top:3px}.lm_dragProxy.lm_bottom .lm_header .lm_tabdropdown_list,.lm_stack.lm_bottom .lm_header .lm_tabdropdown_list{top:initial;bottom:20px}.lm_drop_tab_placeholder{float:left;width:100px;height:10px;visibility:hidden}.lm_header .lm_controls .lm_tabdropdown:before{content:'';width:0;height:0;vertical-align:middle;display:inline-block;border-top:5px dashed;border-right:5px solid transparent;border-left:5px solid transparent;color:white}.lm_header .lm_tabdropdown_list{position:absolute;top:20px;right:0;z-index:5;overflow:hidden}.lm_header .lm_tabdropdown_list .lm_tab{clear:both;padding-right:10px;margin:0}.lm_header .lm_tabdropdown_list .lm_tab .lm_title{width:100px}.lm_header .lm_tabdropdown_list .lm_close_tab{display:none !important}.lm_dragProxy{position:absolute;top:0;left:0;z-index:30}.lm_dragProxy .lm_header{background:transparent}.lm_dragProxy .lm_content{border-top:none;overflow:hidden}.lm_dropTargetIndicator{display:none;position:absolute;z-index:20}.lm_dropTargetIndicator .lm_inner{width:100%;height:100%;position:relative;top:0;left:0}.lm_transition_indicator{display:none;width:20px;height:20px;position:absolute;top:0;left:0;z-index:20}.lm_popin{width:20px;height:20px;position:absolute;bottom:0;right:0;z-index:9999}.lm_popin>*{width:100%;height:100%;position:absolute;top:0;left:0}.lm_popin>.lm_bg{z-index:10}.lm_popin>.lm_icon{z-index:20}/*# sourceMappingURL=goldenlayout-base.css.map */

View File

@ -0,0 +1 @@
.lm_goldenlayout{background:#000000}.lm_content{background:#222222}.lm_dragProxy .lm_content{box-shadow:2px 2px 4px rgba(0,0,0,0.9)}.lm_dropTargetIndicator{box-shadow:inset 0 0 30px #000000;outline:1px dashed #cccccc;transition:all 200ms ease}.lm_dropTargetIndicator .lm_inner{background:#000000;opacity:.2}.lm_splitter{background:#000000;opacity:.001;transition:opacity 200ms ease}.lm_splitter:hover,.lm_splitter.lm_dragging{background:#444444;opacity:1}.lm_header{height:20px;user-select:none}.lm_header.lm_selectable{cursor:pointer}.lm_header .lm_tab{font-family:Arial,sans-serif;font-size:12px;color:#999999;background:#111111;box-shadow:2px -2px 2px rgba(0,0,0,0.3);margin-right:2px;padding-bottom:2px;padding-top:2px}.lm_header .lm_tab .lm_close_tab{width:11px;height:11px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAATElEQVR4nG3OwQ0DMQwDwZGRBtR/j1YJzMc5+IDoR+yCVO29g+pu981MFgqZmRdAfU7+CYWcbF11LwALjpBL0N0qybNx/RPU+gOeiS/+XCRwDlTgkQAAAABJRU5ErkJggg==);background-position:center center;background-repeat:no-repeat;top:4px;right:6px;opacity:.4}.lm_header .lm_tab .lm_close_tab:hover{opacity:1}.lm_header .lm_tab.lm_active{border-bottom:none;box-shadow:0 -2px 2px #000000;padding-bottom:3px}.lm_header .lm_tab.lm_active .lm_close_tab{opacity:1}.lm_dragProxy.lm_bottom .lm_header .lm_tab,.lm_stack.lm_bottom .lm_header .lm_tab{box-shadow:2px 2px 2px rgba(0,0,0,0.3)}.lm_dragProxy.lm_bottom .lm_header .lm_tab.lm_active,.lm_stack.lm_bottom .lm_header .lm_tab.lm_active{box-shadow:0 2px 2px #000000}.lm_selected .lm_header{background-color:#452500}.lm_tab:hover,.lm_tab.lm_active{background:#222222;color:#dddddd}.lm_header .lm_controls .lm_tabdropdown:before{color:#ffffff}.lm_controls>li{position:relative;background-position:center center;background-repeat:no-repeat;opacity:.4;transition:opacity 300ms ease}.lm_controls>li:hover{opacity:1}.lm_controls .lm_popout{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAPklEQVR4nI2Q0QoAIAwCNfr/X7aXCpGN8snBdgejJOzckpkxs9jR6K6T5JpU0nWl5pSXTk7qwh8SnNT+CAAWCgkKFpuSWsUAAAAASUVORK5CYII=)}.lm_controls .lm_maximise{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAKElEQVR4nGP8////fwYCgImQAgYGBgYWKM2IR81/okwajIpgvsMbVgAwgQYRVakEKQAAAABJRU5ErkJggg==)}.lm_controls .lm_close{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAQUlEQVR4nHXOQQ4AMAgCQeT/f6aXpsGK3jSTuCVJAAr7iBdoAwCKd0nwfaAdHbYERw5b44+E8JoBjEYGMBq5gAYP3usUDu2IvoUAAAAASUVORK5CYII=)}.lm_maximised .lm_header{background-color:#000000}.lm_maximised .lm_controls .lm_maximise{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAJ0lEQVR4nGP8//8/AzGAiShVI1YhCwMDA8OsWbPwBmZaWhoj0SYCAN1lBxMAX4n0AAAAAElFTkSuQmCC)}.lm_transition_indicator{background-color:#000000;border:1px dashed #555555}.lm_popin{cursor:pointer}.lm_popin .lm_bg{background:#ffffff;opacity:.3}.lm_popin .lm_icon{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAJCAYAAADpeqZqAAAAWklEQVR4nJWOyw3AIAxDHcQC7L8jbwT3AlJBfNp3SiI7dtRaLSlKKeoA1oEsKSQZCEluexw8Tm3ohk+E7bnOUHUGcNh+HwbBygw4AZ7FN/Lt84p0l+yTflV8AKQyLdcCRJi/AAAAAElFTkSuQmCC);background-position:center center;background-repeat:no-repeat;border-left:1px solid #eeeeee;border-top:1px solid #eeeeee;opacity:.7}.lm_popin:hover .lm_icon{opacity:1}/*# sourceMappingURL=goldenlayout-dark-theme.css.map */

View File

@ -0,0 +1,101 @@
.lm_header,
.lm_header .lm_tab{
background: -webkit-linear-gradient(#dadada, #f6f6f6);
/*background: url(http://subtlepatterns.com/patterns/p2.png);*/
}
.lm_splitter{
background: -webkit-linear-gradient(#fff, #eee);
}
.lm_header{
border-bottom: 1px solid #ccc;
height: 19px !important;
}
/*.lm_splitter.lm_vertical{
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAFCAIAAAAL5hHIAAAAHElEQVR4nGNYtGgJk7a2JtPPnz+ZGBgYmFhYWABG7AVnGY/wNAAAAABJRU5ErkJggg==);
background-repeat: repeat-x;
}
*/
.lm_header .lm_tab{
color: #4c4c51;
font-size: 13px;
font-weight: bold;
border-bottom: 1px solid #ccc;
border-right: 1px solid #ccc;
padding-bottom: 4px;
font-family: Arial, sans-serif;
}
.lm_header .lm_tab i.lm_left{
left: -2px;
top: 0;
}
.lm_header .lm_tab i.lm_right{
right: -2px;
top: 0;
width: 0;
z-index: 1;
}
.lm_header .lm_tab.active i.lm_right{
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAABCAYAAAD5PA/NAAAAGUlEQVR4nGNkYGAwZ2BgeMXAwPCBgYHhCwAQywMH5I3pAgAAAABJRU5ErkJggg==);
background-repeat: repeat-y;
width: 4px;
right: -5px;
border:none;
}
.lm_header .lm_tab.active i.lm_left{
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAABCAYAAAD5PA/NAAAAGUlEQVR4nGNkYGBgZWBg4GFgYBBgYGAQAwABNQA5SO3S/AAAAABJRU5ErkJggg==);
background-repeat: y;
z-index: 1;
width: 4px;
left: -5px;
}
.lm_header .lm_tab.active,
.lm_header .lm_tab:hover{
color: #18181a;
}
.lm_header .lm_tab:hover{
background: #ccc;
}
.lm_header .lm_tab.active{
padding-bottom: 5px;
border-bottom: none;
}
.lm_controls .lm_close,
.lm_header .lm_tab .lm_close_tab{
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAALCAYAAACprHcmAAAAyUlEQVR4nH3QXYrCMBDA8X+bWfQ2CsruJRrQwt5CT6OncCEKc4M+SC3ri7dZ1zK+JCWoOBBCmN98kKKqlmOgBaY8hwBnYKIaEOAUE51q+EzK+/oD+AVwzl2ApgQSGHlfdy9gfzj8NMCqqKolwAjoHneI8AisAEoA1fCXTUjwlsMBv4q+7y2HAG/XAG6qYZZ3HqCIXFVDA8xjXryvzzke4H6/a4G1avjPCxaL7wuwLYEvESHB1CUWzJxzRfo6zAwz28T78Tgz26b3Hdv9aHMjH0aYAAAAAElFTkSuQmCC);
}
.lm_header .lm_tab .lm_close_tab{
width: 11px;
height: 11px;
right: 6px;
top: 4px;
background-repeat: no-repeat;
}
.lm_header .lm_tab.active .lm_close_tab,
.lm_controls .lm_close:hover{
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAALCAYAAACprHcmAAAAfUlEQVR4nHWR0Q2AIAxED6Y46xAu5jhu5AQMQTrG+WEgCPUSAvRdaC9AEkgrpEHSskaWt20veNX2roldGcARwM/Zvd4AzkQa3OsHjmpGAEiSoraLEQBy9Nqgc7x0czTGXMtRGPcahk6kLakjo3u9QRpIK5Kuv09prBVD48weClyE4HksR0kAAAAASUVORK5CYII=);
}
.lm_controls .lm_close{
background-position: center center;
background-repeat: no-repeat;
position: relative;
}

View File

@ -0,0 +1 @@
.lm_goldenlayout{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAMAAAAp4XiDAAAAGFBMVEX29vb19fXw8PDy8vL09PTz8/Pv7+/x8fGKuegbAAAAyUlEQVR42pXRQQ7CMBRDwST9pfe/MahEmgURbt7WmpVb6+vG0dd9REnn66xRy/qXiCgmEIIJhGACIZhACCYQgvlDCDFIEAwSBIMEwSBBMEgQDBIEgwTBIEEwCJEMQiSDENFMQmQzCZEbNyGemd6KeGZ6u4hnXe2qbdLHFjhf1XqNLXHev4wdMd9nspiEiWISJgqECQJhgkCYIBAmCIQJAmGCQJggECYJhAkCEUMEwhCBMEQgDJEIQ2RSg0iEIRJhiB/S+rrjqvXQ3paIJUgPBXxiAAAAAElFTkSuQmCC)}.lm_content{background:#e1e1e1;border:1px solid #cccccc}.lm_dragProxy .lm_content{box-shadow:2px 2px 4px rgba(0,0,0,0.2);box-sizing:border-box}.lm_dropTargetIndicator{box-shadow:inset 0 0 30px rgba(0,0,0,0.4);outline:1px dashed #cccccc;margin:1px;transition:all 200ms ease}.lm_dropTargetIndicator .lm_inner{background:#000000;opacity:.1}.lm_splitter{background:#999999;opacity:.001;transition:opacity 200ms ease}.lm_splitter:hover,.lm_splitter.lm_dragging{background:#bbbbbb;opacity:1}.lm_header{height:20px}.lm_header.lm_selectable{cursor:pointer}.lm_header .lm_tab{font-family:Arial,sans-serif;font-size:12px;color:#888888;background:#fafafa;margin-right:2px;padding-bottom:4px;border:1px solid #cccccc;border-bottom:none}.lm_header .lm_tab .lm_title{padding-top:1px}.lm_header .lm_tab .lm_close_tab{width:11px;height:11px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAIklEQVR4nGNgYGD4z4Ad/Mdg4ODDBXCZRFgCp5EEHQMXBwAQAgz0SVCcggAAAABJRU5ErkJggg==);background-position:center center;background-repeat:no-repeat;right:6px;top:4px;opacity:.4}.lm_header .lm_tab .lm_close_tab:hover{opacity:1}.lm_header .lm_tab.lm_active{border-bottom:none;box-shadow:2px -2px 2px -2px rgba(0,0,0,0.2);padding-bottom:5px}.lm_header .lm_tab.lm_active .lm_close_tab{opacity:1}.lm_dragProxy.lm_bottom .lm_header .lm_tab.lm_active,.lm_stack.lm_bottom .lm_header .lm_tab.lm_active{box-shadow:2px 2px 2px -2px rgba(0,0,0,0.2)}.lm_selected .lm_header{background-color:#452500}.lm_tab:hover,.lm_tab.lm_active{background:#e1e1e1;color:#777777}.lm_header .lm_controls .lm_tabdropdown:before{color:#000000}.lm_controls>li{position:relative;background-position:center center;background-repeat:no-repeat;opacity:.4;transition:opacity 300ms ease}.lm_controls>li:hover{opacity:1}.lm_controls .lm_popout{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAANUlEQVR4nI2QMQoAMAwCz5L/f9mOzZIaN0E9UDyZhaaQz6atgBHgambEJ5wBKoS0WaIvfT+6K2MIECN19MAAAAAASUVORK5CYII=)}.lm_controls .lm_maximise{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAIklEQVR4nGNkYGD4z0AAMBFSAAOETPpPlEmDUREjAxHhBABPvAQLFv3qngAAAABJRU5ErkJggg==)}.lm_controls .lm_close{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAKUlEQVR4nGNgYGD4z4Af/Mdg4FKASwCnDf8JKSBoAtEmEXQTQd8RDCcA6+4Q8OvIgasAAAAASUVORK5CYII=)}.lm_maximised .lm_header{background-color:#ffffff}.lm_maximised .lm_controls .lm_maximise{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAJklEQVR4nGP8//8/AyHARFDFUFbEwsDAwMDIyIgzHP7//89IlEkApSkHEScJTKoAAAAASUVORK5CYII=)}.lm_transition_indicator{background-color:#000000;border:1px dashed #555555}.lm_popin{cursor:pointer}.lm_popin .lm_bg{background:#000000;opacity:.7}.lm_popin .lm_icon{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAJCAYAAADpeqZqAAAAWklEQVR4nJWOyw3AIAxDHcQC7L8jbwT3AlJBfNp3SiI7dtRaLSlKKeoA1oEsKSQZCEluexw8Tm3ohk+E7bnOUHUGcNh+HwbBygw4AZ7FN/Lt84p0l+yTflV8AKQyLdcCRJi/AAAAAElFTkSuQmCC);background-position:center center;background-repeat:no-repeat;opacity:.7}.lm_popin:hover .lm_icon{opacity:1}/*# sourceMappingURL=goldenlayout-light-theme.css.map */

View File

@ -0,0 +1 @@
.lm_goldenlayout{background:#000000;background:linear-gradient(#000000, #eeeeee);background-repeat:repeat}.lm_content{background:#272822}.lm_dragProxy .lm_content{box-shadow:2px 2px 4px rgba(0,0,0,0.9)}.lm_dropTargetIndicator{box-shadow:inset 0 0 30px #000000;outline:1px dashed #cccccc;transition:all 200ms ease}.lm_dropTargetIndicator .lm_inner{background:#000000;opacity:.2}.lm_splitter{background:#000000;opacity:.001;transition:opacity 200ms ease}.lm_splitter:hover,.lm_splitter.lm_dragging{background:#444444;opacity:1}.lm_header{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAcCAIAAAAvP0KbAAAANElEQVR4nH2IsQ0AMAyDHM5J/v8qD3ixulWdOiAQmhkAquoi6frt33udBEnYprvZXZJg+wAKcQ/o96fYNQAAAABJRU5ErkJggg==);height:28px}.lm_header.lm_selectable{cursor:pointer}.lm_header .lm_tab{font-family:Arial,sans-serif;font-size:13px;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAcCAIAAAAvP0KbAAAANklEQVR4nHXGsQ0AMAgDQcuFh2EC9p+HhpIGaCMlKV5/cHdKoiQC+DYzl8+/nJk0M0YEu5tVtXqyIehfJSkOAAAAAElFTkSuQmCC);color:#999999;margin:0;padding-bottom:4px}.lm_header .lm_tab .lm_close_tab{width:11px;height:11px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAATElEQVR4nG3OwQ0DMQwDwZGRBtR/j1YJzMc5+IDoR+yCVO29g+pu981MFgqZmRdAfU7+CYWcbF11LwALjpBL0N0qybNx/RPU+gOeiS/+XCRwDlTgkQAAAABJRU5ErkJggg==);background-position:center center;background-repeat:no-repeat;right:6px;top:4px;opacity:.4}.lm_header .lm_tab .lm_close_tab:hover{opacity:1}.lm_header .lm_tab.lm_active{border-bottom:none;padding-bottom:5px}.lm_header .lm_tab.lm_active .lm_close_tab{opacity:1}.lm_stack.lm_left .lm_header,.lm_stack.lm_right .lm_header{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAABCAIAAABCJ1mGAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4QQHEjUmFgXMqwAAADBJREFUCNdth7ENADAMwkjOIf9/xQMsqEPVTPVg2TUz3V0PANcb310nAWCbpKQktg/HHA+z1P+XmwAAAABJRU5ErkJggg==)}.lm_selected .lm_header{background-color:#452500}.lm_tab:hover,.lm_tab.lm_active{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAcCAIAAAAvP0KbAAAAKUlEQVR4nGPw8vJi4ubmZmJgYGD6//8/nEZnY+MTUoPM/vfvH9PPnz8BJQc56Apw2moAAAAASUVORK5CYII=);color:#eeeeee}.lm_header .lm_controls .lm_tabdropdown:before{color:#eeeeee}.lm_controls>li{position:relative;background-position:center center;background-repeat:no-repeat;opacity:.4;transition:opacity 300ms ease}.lm_controls>li:hover{opacity:1}.lm_controls .lm_popout{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAPklEQVR4nI2Q0QoAIAwCNfr/X7aXCpGN8snBdgejJOzckpkxs9jR6K6T5JpU0nWl5pSXTk7qwh8SnNT+CAAWCgkKFpuSWsUAAAAASUVORK5CYII=)}.lm_controls .lm_maximise{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAKElEQVR4nGP8////fwYCgImQAgYGBgYWKM2IR81/okwajIpgvsMbVgAwgQYRVakEKQAAAABJRU5ErkJggg==)}.lm_controls .lm_close{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAQUlEQVR4nHXOQQ4AMAgCQeT/f6aXpsGK3jSTuCVJAAr7iBdoAwCKd0nwfaAdHbYERw5b44+E8JoBjEYGMBq5gAYP3usUDu2IvoUAAAAASUVORK5CYII=)}.lm_maximised .lm_header{background-color:#000000}.lm_maximised .lm_controls .lm_maximise{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAJklEQVR4nGP8//8/AyHARFDFUFbEwsDAwMDIyIgzHP7//89IlEkApSkHEScJTKoAAAAASUVORK5CYII=)}.lm_transition_indicator{background-color:#000000;border:1px dashed #555555}.lm_popin{cursor:pointer}.lm_popin .lm_bg{background:#eeeeee;opacity:.7}.lm_popin .lm_icon{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAJCAYAAADpeqZqAAAAWklEQVR4nJWOyw3AIAxDHcQC7L8jbwT3AlJBfNp3SiI7dtRaLSlKKeoA1oEsKSQZCEluexw8Tm3ohk+E7bnOUHUGcNh+HwbBygw4AZ7FN/Lt84p0l+yTflV8AKQyLdcCRJi/AAAAAElFTkSuQmCC);background-position:center center;background-repeat:no-repeat;opacity:.7}.lm_popin:hover .lm_icon{opacity:1}/*# sourceMappingURL=goldenlayout-soda-theme.css.map */

View File

@ -0,0 +1 @@
.lm_goldenlayout{background:#dodgerblue;background:linear-gradient(to right bottom, dodgerblue, palevioletred)}.lm_content{background:rgba(255,255,255,0.1);box-shadow:0 0 15px 2px rgba(0,0,0,0.1);color:whitesmoke}.lm_dragProxy .lm_content{box-shadow:2px 2px 4px rgba(0,0,0,0.9)}.lm_dropTargetIndicator{box-shadow:inset 0 0 20px rgba(255,255,255,0.5);outline:1px dashed #ffffff;margin:1px;transition:all 200ms ease}.lm_splitter{background:#ffffff;opacity:.001;transition:opacity 200ms ease}.lm_splitter:hover,.lm_splitter.lm_dragging{background:#ffffff;opacity:.4}.lm_header{height:20px}.lm_header.lm_selectable{cursor:pointer}.lm_header .lm_tab{font-family:Arial,sans-serif;font-size:13px;color:#ffffff;background:rgba(255,255,255,0.1);margin-right:2px;padding-bottom:4px}.lm_header .lm_tab .lm_close_tab{width:11px;height:11px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAATElEQVR4nG3OwQ0DMQwDwZGRBtR/j1YJzMc5+IDoR+yCVO29g+pu981MFgqZmRdAfU7+CYWcbF11LwALjpBL0N0qybNx/RPU+gOeiS/+XCRwDlTgkQAAAABJRU5ErkJggg==);background-position:center center;background-repeat:no-repeat;right:6px;top:4px;opacity:.4}.lm_header .lm_tab .lm_close_tab:hover{opacity:1}.lm_header .lm_tab.lm_active{border-bottom:none;box-shadow:2px -2px 2px -2px rgba(0,0,0,0.2);padding-bottom:5px}.lm_header .lm_tab.lm_active .lm_close_tab{opacity:1}.lm_dragProxy.lm_bottom .lm_header .lm_tab.lm_active,.lm_stack.lm_bottom .lm_header .lm_tab.lm_active{box-shadow:2px 2px 2px -2px rgba(0,0,0,0.2)}.lm_tab:hover,.lm_tab.lm_active{background:rgba(255,255,255,0.3);color:#ffffff}.lm_controls>li{position:relative;background-position:center center;background-repeat:no-repeat;opacity:.4;transition:opacity 300ms ease}.lm_controls>li:hover{opacity:1}.lm_controls .lm_popout{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAPklEQVR4nI2Q0QoAIAwCNfr/X7aXCpGN8snBdgejJOzckpkxs9jR6K6T5JpU0nWl5pSXTk7qwh8SnNT+CAAWCgkKFpuSWsUAAAAASUVORK5CYII=)}.lm_controls .lm_maximise{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAKElEQVR4nGP8////fwYCgImQAgYGBgYWKM2IR81/okwajIpgvsMbVgAwgQYRVakEKQAAAABJRU5ErkJggg==)}.lm_controls .lm_close{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAQUlEQVR4nHXOQQ4AMAgCQeT/f6aXpsGK3jSTuCVJAAr7iBdoAwCKd0nwfaAdHbYERw5b44+E8JoBjEYGMBq5gAYP3usUDu2IvoUAAAAASUVORK5CYII=)}.lm_popin{cursor:pointer}.lm_popin .lm_icon{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAJCAYAAADpeqZqAAAAWklEQVR4nJWOyw3AIAxDHcQC7L8jbwT3AlJBfNp3SiI7dtRaLSlKKeoA1oEsKSQZCEluexw8Tm3ohk+E7bnOUHUGcNh+HwbBygw4AZ7FN/Lt84p0l+yTflV8AKQyLdcCRJi/AAAAAElFTkSuQmCC);background-position:center center;background-repeat:no-repeat;opacity:.7}.lm_popin:hover .lm_icon{opacity:1}.lm_item{box-shadow:2px 2px 2px rgba(0,0,0,0.1)}/*# sourceMappingURL=goldenlayout-translucent-theme.css.map */

View File

@ -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

View File

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 405 KiB

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