223 Commits
v1b5 ... v1b17

Author SHA1 Message Date
Marcel Baumgartner
eca9b6ec52 Merge pull request #275 from Moonlight-Panel/RedesignServerPage
Redesign server page
2023-08-15 22:10:39 +02:00
Marcel Baumgartner
b6e048e982 Added spacing to network tab 2023-08-15 22:07:47 +02:00
Marcel Baumgartner
b8b2ae7865 Merge pull request #274 from Moonlight-Panel/ImproveServerTabIconHandling
Improved server tab icon handling
2023-08-15 21:59:51 +02:00
Marcel Baumgartner
0611988019 Improved server tab icon handling 2023-08-15 21:59:35 +02:00
Marcel Baumgartner
f9fd7199b6 Merge pull request #273 from realspinelle/SomeUXFix
Set unsorted servers to open by default
2023-08-15 19:58:28 +02:00
realspinelle
6ff4861fc6 Set unsorted servers to open by default 2023-08-15 19:21:31 +02:00
Marcel Baumgartner
2db7748703 Merge pull request #272 from Moonlight-Panel/ImproveLatencyCheckThreshold
Improved latency check default threshould
2023-08-15 15:50:30 +02:00
Marcel Baumgartner
87744e4846 Improved latency check default threshould
As mentioned in issue 263
2023-08-15 15:49:55 +02:00
Marcel Baumgartner
ce7125b50b Merge pull request #271 from Moonlight-Panel/ImproveAutoAdminSecurity
Improved auto admin security
2023-08-15 15:45:46 +02:00
Marcel Baumgartner
31d8c3f469 Improved auto admin security
As mentioned in issue 253
2023-08-15 15:45:12 +02:00
Marcel Baumgartner
c80622c2fd Merge pull request #270 from Moonlight-Panel/ImproveSecurityLogPrivacy
Improved the privacy for security logs
2023-08-15 15:33:38 +02:00
Marcel Baumgartner
95e659e5f7 Improved the privacy for security logs
As mentioned in issue 262
2023-08-15 15:33:18 +02:00
Marcel Baumgartner
c155909e82 Merge pull request #269 from Moonlight-Panel/MoveChangelog
Moved changelog to admin section
2023-08-15 15:26:44 +02:00
Marcel Baumgartner
0011ed29b7 Moved changelog to admin section 2023-08-15 15:26:24 +02:00
Marcel Baumgartner
52c4ca0c0a Merge pull request #268 from Moonlight-Panel/AddBetterSelfbotDetection
Improved the whole malware scan system. Made it possible for plugins to add them. Improved self bot detection for python
2023-08-15 15:15:30 +02:00
Marcel Baumgartner
c197d0ca96 Improved the whole malware scan system. Made it possible for plugins to add them. Improved self bot detection for python 2023-08-15 15:14:28 +02:00
Marcel Baumgartner
25902034e9 Switched to horizontal nav bar in the server view 2023-08-14 22:16:59 +02:00
Marcel Baumgartner
b10db643fe Merge pull request #266 from Moonlight-Panel/ImproveSoftErrors
Improved soft error boundary
2023-08-14 18:33:58 +02:00
Marcel Baumgartner
4c7ffe6714 Improved soft error boundary 2023-08-14 18:22:20 +02:00
Marcel Baumgartner
a0c2b45a61 Merge pull request #249 from Dannyx1604/main
Update README.md because of new installer
2023-08-13 21:16:53 +02:00
Marcel Baumgartner
e49a9d3505 Merge branch 'main' into main 2023-08-13 21:16:42 +02:00
Dannyx
7ddae9c3e1 t
t
2023-08-13 20:04:47 +02:00
Daniel Balk
290e865ae0 Merge pull request #261 from NaysKutzu/main
Fix a lot of typing mistakes and added Romanian translations.
2023-08-09 15:52:42 +02:00
NaysKutzu
00ee625e2e Create ro_ro.lang 2023-08-09 15:10:57 +02:00
NaysKutzu
274e2d93f2 Fix the locations of the elements. 2023-08-09 14:48:09 +02:00
NaysKutzu
781171f7c5 Fix typo 2023-08-09 14:46:41 +02:00
NaysKutzu
4a8618da79 Merge pull request #1 from NaysKutzu/NaysKutzu-patch-1
Fix some typos in the README.
2023-08-09 14:44:23 +02:00
NaysKutzu
296cf0db6f Fix typo in readme 2023-08-09 14:43:26 +02:00
Marcel Baumgartner
48cdba5155 Removed unused a tags in ticket view 2023-08-09 04:08:28 +02:00
Marcel Baumgartner
35c1b255b5 Update README.md 2023-08-09 03:47:50 +02:00
Marcel Baumgartner
244b920305 Merge pull request #260 from Moonlight-Panel/RemoveFormatterByteUtils
switched to the new converter instead of the formatter functions to convert byte sizes
2023-08-09 03:46:42 +02:00
Marcel Baumgartner
3d4a2128e2 switched to the new converter instead of the formatter functions to convert byte sizes 2023-08-09 03:42:33 +02:00
Marcel Baumgartner
1cf8430ad8 Small include improvment 2023-08-09 03:33:28 +02:00
Marcel Baumgartner
a9b7d10fb0 Fix invalid include with new include 2023-08-09 03:23:34 +02:00
Marcel Baumgartner
47e333630e Removed useless links in the tickets overview for admins 2023-08-09 01:00:55 +02:00
Marcel Baumgartner
8b41a9fc13 Add message sender include 2023-08-09 00:57:40 +02:00
Marcel Baumgartner
d09957fdac Merge pull request #259 from Moonlight-Panel/ImproveBackgroundImage
Made the background image darker
2023-08-09 00:37:53 +02:00
Marcel Baumgartner
f9ecb61d71 Made the background image darker
Thanks to https://github.com/nuhuhwy
2023-08-09 00:37:36 +02:00
Marcel Baumgartner
ef92dd47ad Merge pull request #258 from Moonlight-Panel/ImproveTicketSystemUI
Improved ticket system ui and some backend code
2023-08-09 00:36:33 +02:00
Marcel Baumgartner
c2c533675b Improved ticket system ui and some backend code 2023-08-09 00:35:49 +02:00
Marcel Baumgartner
569dd69bdd Merge pull request #257 from Moritz-Deiaco/main
pagination button gap fix
2023-08-08 17:14:07 +02:00
Moritz
242870b3e1 pagination button gap fix 2023-08-08 17:08:54 +02:00
Daniel Balk
30b6e45235 Merge pull request #254 from Moritz-Deiaco/main
New Translations
2023-08-08 16:33:00 +02:00
Moritz
cd62fdc5f6 fixed a typo, rechecked everything 2023-08-08 16:28:46 +02:00
Moritz Deiaco
2c54b91e6c New translations in de_de.lang 2023-08-08 12:16:14 +02:00
Marcel Baumgartner
388deacf60 Merge pull request #250 from Moonlight-Panel/ImproveInstallUX
Improved install user experience
2023-08-08 00:54:10 +02:00
Marcel Baumgartner
aa547038de Improved install user experience 2023-08-08 00:53:00 +02:00
Dannyx
78bfd68d63 Update README.md because of New installer 2023-08-07 22:23:20 +02:00
Marcel Baumgartner
17e3345b8a Added date formatter for user overview 2023-08-06 22:00:59 +02:00
Marcel Baumgartner
f95312c1e3 Merge pull request #248 from Moonlight-Panel/AddTicketSystem
Added ticket system
2023-08-06 21:57:24 +02:00
Marcel Baumgartner
2144ca3823 Added byte converter and fixed memory view at the nodes 2023-08-06 21:55:23 +02:00
Marcel Baumgartner
de45ff40d8 Implemented a basic ticket system 2023-08-04 14:00:25 +02:00
Marcel Baumgartner
606085c012 Merge pull request #242 from Moonlight-Panel/AddNewBackupFormat
Added new backup format
2023-08-02 22:05:39 +02:00
Marcel Baumgartner
00525d8099 Added new backup format 2023-08-02 22:05:07 +02:00
Marcel Baumgartner
26617d67f5 Merge pull request #241 from Moonlight-Panel/SmallFixes
Did some small fixes, added connection timeout check, improved ux
2023-08-02 03:07:47 +02:00
Marcel Baumgartner
600bec3417 Did some small fixes, added connection timeout check, improved ux 2023-08-02 03:06:54 +02:00
Marcel Baumgartner
4e85d1755a Merge pull request #240 from DatGamet/patch-1
Update de_de.lang
2023-08-02 01:39:58 +02:00
DatGamet
0832936933 Update de_de.lang 2023-08-02 01:39:08 +02:00
Marcel Baumgartner
ecda2ec6d1 Merge pull request #239 from Moonlight-Panel/FixPluginSystem
Fixed plugin loading system
2023-08-01 22:21:54 +02:00
Marcel Baumgartner
6f3765a3bf Fixed plugin loading system 2023-08-01 22:21:19 +02:00
Marcel Baumgartner
29002d3445 Update Moonlight.csproj 2023-08-01 20:38:22 +02:00
Marcel Baumgartner
6d0456a008 Merge pull request #238 from Moonlight-Panel/AddDdosProtection
Added new ddos protection
2023-07-24 00:33:22 +02:00
Marcel Baumgartner
3e698123bb Merge branch 'main' into AddDdosProtection 2023-07-24 00:33:01 +02:00
Marcel Baumgartner
f3fb86819a Merge pull request #237 from Moonlight-Panel/FixDomainIdentityIssues
Fixed domain identity issues
2023-07-24 00:30:50 +02:00
Marcel Baumgartner
e2248a8444 Fixed domain identity issues 2023-07-24 00:30:18 +02:00
Marcel Baumgartner
2cf2b77090 Added new ddos protection 2023-07-24 00:23:29 +02:00
Marcel Baumgartner
fedc9278d4 Updated dependencies 2023-07-23 22:12:17 +02:00
Marcel Baumgartner
f29206a69b Merge pull request #236 from Moonlight-Panel/AddPluginSystem
Add plugin system
2023-07-23 21:31:26 +02:00
Marcel Baumgartner
0658e55a78 Implemented basic plugin store and improved plugin system 2023-07-23 21:30:57 +02:00
Marcel Baumgartner
21bea974a9 Implemented a basic plugin system 2023-07-22 23:44:45 +02:00
Marcel Baumgartner
33ef09433e Merge pull request #235 from Moonlight-Panel/AddMinerCheck
Add basic miner check
2023-07-22 02:24:16 +02:00
Marcel Baumgartner
173bff67df Add basic miner check 2023-07-22 02:08:39 +02:00
Marcel Baumgartner
512a989609 Merge pull request #234 from Moonlight-Panel/FixDomainOwnerMatching
Fixed domain owner matching
2023-07-20 17:24:05 +02:00
Marcel Baumgartner
2d7dac5089 Fixed domain owner matching 2023-07-20 17:17:05 +02:00
Marcel Baumgartner
11708fbc3b Merge pull request #231 from Moonlight-Panel/AdditionalDnsErrorHandling
Added additional dns error handling
2023-07-20 02:00:41 +02:00
Marcel Baumgartner
daeb4dd5b9 Added additional dns error handling 2023-07-20 02:00:03 +02:00
Marcel Baumgartner
daba4cba04 Merge pull request #230 from Moonlight-Panel/AddSecurityLogs
Added security logs. Removed unsued log models. Added dynamic config load
2023-07-19 22:09:58 +02:00
Marcel Baumgartner
1cd0f0f96f Added security logs. Removed unsued log models. Added dynamisc config load system for development 2023-07-19 20:07:57 +02:00
Marcel Baumgartner
6a30db07a7 Merge pull request #229 from Moonlight-Panel/AddPermissionSystem
Added permission system and improved UIs and the IdentityService
2023-07-18 02:02:31 +02:00
Marcel Baumgartner
6c8754d008 Removed moved navigation items 2023-07-18 02:01:02 +02:00
Marcel Baumgartner
356ba94592 Implemented new user editing including permission groups 2023-07-18 01:57:48 +02:00
Marcel Baumgartner
d3b55d155b Added permission groups. Cleaned security ui. Added some permission stuff 2023-07-17 22:16:39 +02:00
Marcel Baumgartner
0015001d7c Fixed some permissions. Cleaned some UIs 2023-07-17 16:22:22 +02:00
Marcel Baumgartner
0a86aa8aa4 Implemented new permission and identity system 2023-07-17 00:48:27 +02:00
Marcel Baumgartner
74d4ee729d Adding permissions. I hate my life ;) 2023-07-16 22:44:36 +02:00
Marcel Baumgartner
178ff36e86 Implemented a basic permission system base 2023-07-16 02:21:53 +02:00
Marcel Baumgartner
f852df5807 Merge pull request #227 from Moonlight-Panel/StripeIntegration
Implemented a basic stripe integration
2023-07-13 21:36:57 +02:00
Marcel Baumgartner
90f4b04857 Changed configuration file 2023-07-13 21:36:19 +02:00
Marcel Baumgartner
244e87ed18 Implemented a basic stripe interation 2023-07-13 21:29:20 +02:00
Marcel Baumgartner
80ea5a543f Merge pull request #226 from Moonlight-Panel/main
Update branch StripeIntegration with latest commits
2023-07-13 20:46:39 +02:00
Marcel Baumgartner
5baba05f5f Merge pull request #225 from Moonlight-Panel/NewMailSystem
Added new mail system
2023-07-13 20:40:43 +02:00
Marcel Baumgartner
591da6de5c Implemented new mail system components 2023-07-13 20:39:02 +02:00
Marcel Baumgartner
c1ddff4ae3 Update .gitattributes 2023-07-13 17:33:34 +02:00
Marcel Baumgartner
67d78d7104 Merge pull request #224 from Moonlight-Panel/FixGravatarBug
Fixed gravatar bug
2023-07-13 17:26:09 +02:00
Marcel Baumgartner
52f4b00f84 Fixed gravatar bug 2023-07-13 17:25:48 +02:00
Marcel Baumgartner
8f028e2ac6 Update .gitattributes 2023-07-13 17:21:22 +02:00
Marcel Baumgartner
5bd6f15203 Added a mail template editor 2023-07-12 15:48:30 +02:00
Marcel Baumgartner
4c39ad6170 Removed legacy trash mail detector service 2023-07-12 14:34:26 +02:00
Marcel Baumgartner
12392d4f47 Merge pull request #223 from Moonlight-Panel/AddTempMailCheck
Added temp mail check
2023-07-12 14:22:41 +02:00
Marcel Baumgartner
b75147e4c0 Added temp mail check 2023-07-12 14:20:55 +02:00
Marcel Baumgartner
8f9508f30b Merge pull request #222 from Moonlight-Panel/FixServerList
Fixed server list and server navigation
2023-07-12 02:03:45 +02:00
Marcel Baumgartner
428e2668d3 Fixed server list and server navigation 2023-07-12 02:03:20 +02:00
Marcel Baumgartner
c1cfb35c86 Merge pull request #221 from Moonlight-Panel/FixDnsBug
Fixed dns bug
2023-07-12 01:29:43 +02:00
Marcel Baumgartner
d6777c463e Fixed dns bug 2023-07-12 01:29:23 +02:00
Marcel Baumgartner
f9126bffe0 Merge pull request #219 from Moonlight-Panel/AddEggImporter
Implemented pterodactyl egg import function
2023-07-10 22:01:29 +02:00
Marcel Baumgartner
0488e83a38 Implemented pterodactyl egg import function 2023-07-10 22:01:10 +02:00
Marcel Baumgartner
d87ddc90e3 Merge pull request #216 from Moonlight-Panel/UiEnhancements
Added some UI enhancements
2023-07-09 19:48:10 +02:00
Marcel Baumgartner
151bc82998 Added better server image seletor 2023-07-09 19:46:32 +02:00
Marcel Baumgartner
e4c21c74a5 Added custom scroll bar 2023-07-09 19:46:18 +02:00
Marcel Baumgartner
13741a2be9 Merge pull request #215 from Moonlight-Panel/EnhanceInstallConsole
Enhanced install console
2023-07-08 02:50:56 +02:00
Marcel Baumgartner
c866e89b72 Enhanced install console 2023-07-08 02:50:13 +02:00
Marcel Baumgartner
8be93bc53c Merge pull request #214 from Moonlight-Panel/FixSessionView
Fixed session view
2023-07-07 19:10:47 +02:00
Marcel Baumgartner
384b6a3e7d Fixed session view 2023-07-07 19:09:23 +02:00
Marcel Baumgartner
ba2de54c60 Update README.md 2023-07-07 19:01:08 +02:00
Marcel Baumgartner
bd5567e24f Merge pull request #213 from Moonlight-Panel/AddCloudflareEnableOption
Added cloudflare enable option
2023-07-07 18:22:35 +02:00
Marcel Baumgartner
b8e39824b5 Added cloudflare enable option 2023-07-07 18:22:18 +02:00
Marcel Baumgartner
d8c9bdbd8d Merge pull request #212 from Moonlight-Panel/AddLoginRegisterDeny
Add config option to prevent users from login and register
2023-07-07 18:11:45 +02:00
Marcel Baumgartner
80eb210af0 Add config option to prevent users from login and register 2023-07-07 18:09:38 +02:00
Marcel Baumgartner
a295354549 Merge pull request #210 from Dannyx1604/patch-1
I got bored again (de_de.lang)
2023-07-07 03:23:31 +02:00
Marcel Baumgartner
749ea5dc8e Merge pull request #211 from Moonlight-Panel/AddTelemetryReporter
Added telemetry reporter
2023-07-07 03:14:06 +02:00
Marcel Baumgartner
f52b9e2951 Added telemetry reporter 2023-07-07 03:06:16 +02:00
Dannyx
d2dbb68967 I got bored again (de_de.lang) 2023-07-06 23:28:08 +02:00
Marcel Baumgartner
d1c9009e9f Merge pull request #209 from Moonlight-Panel/NewVisualConfigEditor
Added a new visual config editor
2023-07-06 16:46:29 +02:00
Marcel Baumgartner
d024a834f9 Added a new visual config editor 2023-07-06 16:46:01 +02:00
Marcel Baumgartner
c0df8ac507 Implemented new subscription system and basic stripe support 2023-07-06 02:12:06 +02:00
Marcel Baumgartner
ab529991fd Fix some javascript not loaded issues
Because all js files are executed in the order they were put into the document some js files were not loaded while starting blazor. this should fix it (hopefully ;) )
2023-07-04 18:06:14 +02:00
Marcel Baumgartner
92705837ba Merge pull request #208 from Moonlight-Panel/RewriteSessionSystem
Rewritten session system to match new standarts and be more performant
2023-07-04 17:51:09 +02:00
Marcel Baumgartner
609d5451f9 Rewritten session system to match new standarts and be more performant 2023-07-04 17:49:27 +02:00
Marcel Baumgartner
2bb2caeeed Merge pull request #207 from Moonlight-Panel/AddIpLogs
Added ip log for register and last visit
2023-07-03 20:17:20 +02:00
Marcel Baumgartner
61db49bfb7 Added ip log for register and last visit 2023-07-03 20:01:34 +02:00
Marcel Baumgartner
a75678d305 Merge pull request #206 from Moonlight-Panel/SmallFixes
Small fixes
2023-07-02 21:33:12 +02:00
Marcel Baumgartner
d418c91efa Fixed js invoke errors 2023-07-02 21:30:34 +02:00
Marcel Baumgartner
7f2da5a55d Updated sweet alert 2 2023-07-02 20:56:10 +02:00
Marcel Baumgartner
5e592ccdcb Added ignore for unexpected dispose errors 2023-07-02 20:51:08 +02:00
Marcel Baumgartner
016f50fb1c Added ignore for json serialize errors 2023-07-02 20:48:47 +02:00
Marcel Baumgartner
fe21668a2b Removed wrong logged warn 2023-07-02 20:44:29 +02:00
Marcel Baumgartner
1aab86a317 Fixed wrong ssl config for nodes 2023-07-02 20:41:31 +02:00
Marcel Baumgartner
243d23d4e2 Fixed repatcha config for empty values 2023-07-02 20:40:47 +02:00
Marcel Baumgartner
2fe17473ae Merge pull request #204 from Moonlight-Panel/SwitchToNewConfigSystem
Switched to new config system
2023-07-02 02:19:32 +02:00
Marcel Baumgartner
609cf8cfac Switched to new config system 2023-07-02 02:16:44 +02:00
Marcel Baumgartner
678da30b09 Merge pull request #203 from Moonlight-Panel/LogsAndFixes
Added new log files and log migrators. Fixed some errors with js invokes
2023-07-02 00:21:55 +02:00
Marcel Baumgartner
d19412f4bb Added new log files and log migrators. Fixed some errors with js invokes 2023-07-02 00:21:35 +02:00
Marcel Baumgartner
1665d6e537 Merge pull request #202 from Moonlight-Panel/AddSentrySupport
Added new sentry support
2023-07-01 19:01:00 +02:00
Marcel Baumgartner
fd210f2404 Added new sentry support 2023-07-01 19:00:38 +02:00
Marcel Baumgartner
c33729fb44 Merge pull request #201 from Moonlight-Panel/FixServerList
Fixed server list
2023-06-30 21:55:58 +02:00
Marcel Baumgartner
7983bf3ee4 Fixed server list 2023-06-30 21:55:32 +02:00
Marcel Baumgartner
a09f60aea7 Merge pull request #200 from Moonlight-Panel/HttpTimeoutFixes
Fixed timeout options from assumed seconds to real value miliseconds
2023-06-29 23:28:07 +02:00
Marcel Baumgartner
28b5893c21 Fixed timeout options from assumed seconds to real value miliseconds 2023-06-29 23:27:48 +02:00
Marcel Baumgartner
25b47d8b6c Merge pull request #199 from Moonlight-Panel/AddNewGermanTranslation
Added new german translations
2023-06-29 23:10:21 +02:00
Marcel Baumgartner
85f5b8a7da Added new german translations 2023-06-29 23:09:58 +02:00
Marcel Baumgartner
ab9333f99a Merge pull request #198 from Moonlight-Panel/FixServerDelete
Fixed server delete
2023-06-26 22:51:17 +02:00
Marcel Baumgartner
d60f8fc905 Fixed server delete 2023-06-26 22:50:45 +02:00
Marcel Baumgartner
fe1f4412d8 Merge pull request #197 from Moonlight-Panel/AddedRetry
Added retry class and added it to some api calls that need it
2023-06-26 22:45:56 +02:00
Marcel Baumgartner
f191533410 Added retry class and added it to some api calls that need it 2023-06-26 22:45:33 +02:00
Marcel Baumgartner
a894707536 Merge pull request #196 from Moonlight-Panel/SmallBugFixes
Small bug fixes
2023-06-26 18:05:58 +02:00
Marcel Baumgartner
d2ccc84286 Fixed sidebar text sizing issues 2023-06-26 17:23:25 +02:00
Marcel Baumgartner
f2ec43f2d2 Fixed not enabled installing screen for new servers 2023-06-26 17:19:54 +02:00
Marcel Baumgartner
7feccc8d9f Fixed error loop for fileaccess providers not supporting the launch url 2023-06-26 17:19:32 +02:00
Marcel Baumgartner
a8bd1193ce Merge pull request #195 from Moonlight-Panel/SecurityPatches
Security patches
2023-06-26 00:10:03 +02:00
Marcel Baumgartner
366d1a9205 Merge pull request #194 from Moonlight-Panel/AddStreamerModeAndFixUI
Added streamer mode and fixed security settings ui
2023-06-26 00:07:23 +02:00
Marcel Baumgartner
df9ed95c6b Added streamer mode and fixed security settings ui 2023-06-26 00:06:44 +02:00
Marcel Baumgartner
23a211362e Merge pull request #193 from Moonlight-Panel/EnhanceFileManager
Enhanced winscp button and new file/folder menu
2023-06-25 17:32:57 +02:00
Marcel Baumgartner
cf91d44902 Enhanced winscp button and new file/folder menu 2023-06-25 17:31:36 +02:00
Marcel Baumgartner
35633e21a9 Merge pull request #192 from Moonlight-Panel/EnhanceServerListLayout
Enhanced server list
2023-06-25 00:01:53 +02:00
Marcel Baumgartner
ce8b8f6798 Enhanced server list 2023-06-25 00:01:28 +02:00
Marcel Baumgartner
c28c80ba25 Merge pull request #191 from Moonlight-Panel/FixDnsManager
Fixed dns loading issues. Added udp support
2023-06-24 23:45:49 +02:00
Marcel Baumgartner
da17b1df93 Fixed dns loading issues. Added udp support 2023-06-24 23:45:29 +02:00
Marcel Baumgartner
f9f5865ef9 Prevent user locking when duplicating the email entries 2023-06-24 22:35:38 +02:00
Marcel Baumgartner
389ded9b77 Fixed oauth2 account spoofing using unverified discord accounts for claiming identity 2023-06-24 22:15:04 +02:00
Marcel Baumgartner
faebaa59dd Merge pull request #189 from Moonlight-Panel/AddCustomLayoutServerList
Added custom layout options for the server list
2023-06-24 02:35:21 +02:00
Marcel Baumgartner
6b7dc2ad05 Added custom layout options for the server list 2023-06-24 02:35:01 +02:00
Marcel Baumgartner
e356c9d0c8 Update README.md 2023-06-23 05:06:12 +02:00
Marcel Baumgartner
efed2a6a5c Merge pull request #188 from Moonlight-Panel/ImproveLogging
Improved logging. Added better error handling for mysql database backup
2023-06-23 00:51:32 +02:00
Marcel Baumgartner
6f138c2c51 Improved logging. Added better error handling for mysql database backup 2023-06-23 00:51:09 +02:00
Marcel Baumgartner
6c43e6a533 Merge pull request #187 from Moonlight-Panel/AddMalwareScan
Added maleware scan
2023-06-22 20:36:58 +02:00
Marcel Baumgartner
0379afd831 Added maleware scan 2023-06-22 20:36:33 +02:00
Marcel Baumgartner
b8bfdb7729 Merge pull request #185 from Moonlight-Panel/SwitchToSerilog
Switched to serilog as logging system
2023-06-21 19:15:53 +02:00
Marcel Baumgartner
72f60ec97c Switched to serilog as logging system 2023-06-21 19:15:30 +02:00
Marcel Baumgartner
1b40250750 Revert "Merge branch 'DiscordBot' into main"
This reverts commit cdf2988cb6, reversing
changes made to 76415b4a0a.
2023-06-20 20:59:49 +02:00
Ole Sziedat
cdf2988cb6 Merge branch 'DiscordBot' into main 2023-06-20 20:52:46 +02:00
Marcel Baumgartner
76415b4a0a Merge pull request #182 from Moonlight-Panel/ImproveFileEditor
Added STRG+S support for editor and better saving
2023-06-20 20:38:17 +02:00
Marcel Baumgartner
52d00baf2b Added STRG+S support for editor and better saving 2023-06-20 20:37:57 +02:00
Marcel Baumgartner
cd41db510e Merge pull request #181 from Moonlight-Panel/AddServerAllocationEditor
Added a basic allocation editor for servers
2023-06-20 19:21:41 +02:00
Marcel Baumgartner
1afd4e8b92 Added a basic allocation editor for servers 2023-06-20 19:18:18 +02:00
Marcel Baumgartner
ef37088c7a Merge pull request #180 from Moonlight-Panel/ImproveUserInterface
Fixed ui bugs, improved plugins page, added new 404 component
2023-06-20 02:56:15 +02:00
Marcel Baumgartner
e71495533b Fixed ui bugs, improved plugins page, added new 404 component 2023-06-20 02:55:50 +02:00
Marcel Baumgartner
e2a6d70f6a Update README.md 2023-06-18 06:23:17 +02:00
Marcel Baumgartner
e95853b09c Update README.md 2023-06-18 03:25:23 +02:00
Marcel Baumgartner
0537ca115e Remove assets from github language statistics 2023-06-18 02:50:08 +02:00
Marcel Baumgartner
432e441972 Change moonlight service to always fetch the changelog 2023-06-18 02:37:07 +02:00
Marcel Baumgartner
1dae5150bd Merge pull request #178 from Moonlight-Panel/RewriteNotificationSystem
Rewrite notification system
2023-06-18 02:32:33 +02:00
Marcel Baumgartner
72c6f636ee Rewritten notification system 2023-06-17 20:47:07 +02:00
Daniel Balk
e54d04277d Merge pull request #177 from Moonlight-Panel/ShowMoonlightAppInSessions
added check for moonlight app for getting the device
2023-06-17 17:52:41 +02:00
Daniel Balk
f559f08e8d added check for moonlight app for getting the device 2023-06-17 17:51:34 +02:00
Daniel Balk
2674fb3fa7 Update Debugging.razor 2023-06-17 14:10:24 +02:00
Marcel Baumgartner
d5d77ae7da Merge pull request #175 from Moonlight-Panel/AddMoonlightSideDnsCheckSsl
Added moonlight side dns check for ssl
2023-06-17 13:39:25 +02:00
Marcel Baumgartner
3ae905038c Added moonlight side dns check for ssl 2023-06-17 13:38:32 +02:00
Marcel Baumgartner
6707d722e0 Merge pull request #174 from Moonlight-Panel/SomeHotfixes
Fixed cleanup, error handling missing and missing gif
2023-06-17 13:00:12 +02:00
Marcel Baumgartner
bc9fecf6d9 Fixed cleanup, error handling missing and missing gif 2023-06-17 12:57:01 +02:00
Marcel Baumgartner
c2cb10f069 Merge pull request #173 from Moonlight-Panel/CleanupHotfix
Fixed cleanup calculation errors
2023-06-17 00:30:16 +02:00
Marcel Baumgartner
cc06d1eb0b Fixed cleanup calculation errors 2023-06-17 00:29:47 +02:00
Marcel Baumgartner
916ff71022 Merge pull request #172 from Moonlight-Panel/FixConsoleIssues
Fixed xterm console issues
2023-06-16 22:57:04 +02:00
Marcel Baumgartner
9e80342e26 Fixed xterm console issues 2023-06-16 22:56:33 +02:00
Marcel Baumgartner
0fb97683bf Merge pull request #171 from Moonlight-Panel/DisableServerDelete
Disabled server delete
2023-06-16 20:30:00 +02:00
Marcel Baumgartner
32415bad54 Merge pull request #170 from Moonlight-Panel/AddModrinthSupport
Add modrinth support
2023-06-16 20:29:45 +02:00
Marcel Baumgartner
d2b0bcc4a3 Disabled server delete 2023-06-16 20:29:23 +02:00
Daniel Balk
2f4f4193d3 Merge pull request #169 from Moonlight-Panel/NotificationDebuggingUi
added simple debugging page
2023-06-16 20:25:39 +02:00
Daniel Balk
7279f05a16 added simple debugging page 2023-06-16 20:24:32 +02:00
Marcel Baumgartner
3962723acb Implemented plugin installer 2023-06-16 20:24:03 +02:00
Marcel Baumgartner
125e72fa58 Switched to new routing for the server manage page 2023-06-16 17:43:48 +02:00
Marcel Baumgartner
880cce060f Added missing server installing db change 2023-06-16 17:33:47 +02:00
Marcel Baumgartner
0e04942111 Merge pull request #168 from Moonlight-Panel/AddServerArchive
Added archive system. Added ml debug menu and related stuff
2023-06-16 17:21:05 +02:00
Marcel Baumgartner
46a88d4638 Added archive system. Added ml debug menu and related stuff 2023-06-16 16:58:58 +02:00
Marcel Baumgartner
c7c39fc511 Merge pull request #167 from Moonlight-Panel/RemoveUselessConsoleLogs
Removed useless console streaming logs
2023-06-13 22:41:46 +02:00
Marcel Baumgartner
3b9bdd1916 Removed useless console streaming logs 2023-06-13 22:35:03 +02:00
Marcel Baumgartner
d267be6d69 Merge pull request #166 from Moonlight-Panel/AddServerFetchBotApi
Added server fetch for single server in bot api
2023-06-13 21:51:20 +02:00
Marcel Baumgartner
18f6a1acdc Added server fetch for single server in bot api 2023-06-13 21:50:33 +02:00
Marcel Baumgartner
2ca41ff18f Merge pull request #165 from Moonlight-Panel/FixSessionListEmailFilter
Fixed session list email filter
2023-06-12 22:12:37 +02:00
Marcel Baumgartner
74c77bc744 Fixed session list email filter 2023-06-12 22:12:05 +02:00
Marcel Baumgartner
1ff8cdd7a9 Merge pull request #164 from Moonlight-Panel/RemovedUnnecessaryReload
Removed unnecessary reload
2023-06-12 00:47:42 +02:00
Marcel Baumgartner
bd320d025a Removed unnecessary reload 2023-06-12 00:47:00 +02:00
0fde9a5005 bot hotfix 2023-05-04 20:40:34 +02:00
Marcel Baumgartner
74541d7f87 Merge pull request #107 from Moonlight-Panel/main
Update to upstream branch
2023-04-29 23:39:46 +02:00
364 changed files with 26991 additions and 7607 deletions

8
.gitattributes vendored
View File

@@ -1,2 +1,10 @@
# Auto detect text files and perform LF normalization
* text=auto
Moonlight/wwwroot/** linguist-vendored
Moonlight/wwwroot/assets/js/scripts.bundle.js linguist-vendored
Moonlight/wwwroot/assets/js/widgets.bundle.js linguist-vendored
Moonlight/wwwroot/assets/js/theme.js linguist-vendored
Moonlight/wwwroot/assets/css/boxicons.min.css linguist-vendored
Moonlight/wwwroot/assets/css/style.bundle.css linguist-vendored
Moonlight/wwwroot/assets/plugins/** linguist-vendored
Moonlight/wwwroot/assets/fonts/** linguist-vendored

View File

@@ -0,0 +1,58 @@
using Newtonsoft.Json;
using RestSharp;
namespace Moonlight.App.ApiClients.Modrinth;
public class ModrinthApiHelper
{
private readonly RestClient Client;
public ModrinthApiHelper()
{
Client = new();
Client.AddDefaultParameter(
new HeaderParameter("User-Agent", "Moonlight-Panel/Moonlight (admin@endelon-hosting.de)")
);
}
public async Task<T> Get<T>(string resource)
{
var request = CreateRequest(resource);
request.Method = Method.Get;
var response = await Client.ExecuteAsync(request);
if (!response.IsSuccessful)
{
if (response.StatusCode != 0)
{
throw new ModrinthException(
$"An error occured: ({response.StatusCode}) {response.Content}",
(int)response.StatusCode
);
}
else
{
throw new Exception($"An internal error occured: {response.ErrorMessage}");
}
}
return JsonConvert.DeserializeObject<T>(response.Content!)!;
}
private RestRequest CreateRequest(string resource)
{
var url = "https://api.modrinth.com/v2/" + resource;
var request = new RestRequest(url)
{
Timeout = 300000
};
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Accept", "application/json");
return request;
}
}

View File

@@ -0,0 +1,19 @@
namespace Moonlight.App.ApiClients.Modrinth;
public class ModrinthException : Exception
{
public int StatusCode { get; set; }
public ModrinthException()
{
}
public ModrinthException(string message, int statusCode) : base(message)
{
StatusCode = statusCode;
}
public ModrinthException(string message, Exception inner) : base(message, inner)
{
}
}

View File

@@ -0,0 +1,14 @@
using Newtonsoft.Json;
namespace Moonlight.App.ApiClients.Modrinth.Resources;
public class Pagination
{
[JsonProperty("hits")] public Project[] Hits { get; set; }
[JsonProperty("offset")] public long Offset { get; set; }
[JsonProperty("limit")] public long Limit { get; set; }
[JsonProperty("total_hits")] public long TotalHits { get; set; }
}

View File

@@ -0,0 +1,48 @@
using Newtonsoft.Json;
namespace Moonlight.App.ApiClients.Modrinth.Resources;
public class Project
{
[JsonProperty("project_id")] public string ProjectId { get; set; }
[JsonProperty("project_type")] public string ProjectType { get; set; }
[JsonProperty("slug")] public string Slug { get; set; }
[JsonProperty("author")] public string Author { get; set; }
[JsonProperty("title")] public string Title { get; set; }
[JsonProperty("description")] public string Description { get; set; }
[JsonProperty("categories")] public string[] Categories { get; set; }
[JsonProperty("display_categories")] public string[] DisplayCategories { get; set; }
[JsonProperty("versions")] public string[] Versions { get; set; }
[JsonProperty("downloads")] public long Downloads { get; set; }
[JsonProperty("follows")] public long Follows { get; set; }
[JsonProperty("icon_url")] public string IconUrl { get; set; }
[JsonProperty("date_created")] public DateTimeOffset DateCreated { get; set; }
[JsonProperty("date_modified")] public DateTimeOffset DateModified { get; set; }
[JsonProperty("latest_version")] public string LatestVersion { get; set; }
[JsonProperty("license")] public string License { get; set; }
[JsonProperty("client_side")] public string ClientSide { get; set; }
[JsonProperty("server_side")] public string ServerSide { get; set; }
[JsonProperty("gallery")] public Uri[] Gallery { get; set; }
[JsonProperty("featured_gallery")] public Uri FeaturedGallery { get; set; }
[JsonProperty("color")] public long? Color { get; set; }
}

View File

@@ -0,0 +1,57 @@
using Newtonsoft.Json;
namespace Moonlight.App.ApiClients.Modrinth.Resources;
public class Version
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("version_number")]
public string VersionNumber { get; set; }
[JsonProperty("changelog")]
public string Changelog { get; set; }
[JsonProperty("dependencies")]
public object[] Dependencies { get; set; }
[JsonProperty("game_versions")]
public object[] GameVersions { get; set; }
[JsonProperty("version_type")]
public string VersionType { get; set; }
[JsonProperty("loaders")]
public object[] Loaders { get; set; }
[JsonProperty("featured")]
public bool Featured { get; set; }
[JsonProperty("status")]
public string Status { get; set; }
[JsonProperty("requested_status")]
public string RequestedStatus { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("project_id")]
public string ProjectId { get; set; }
[JsonProperty("author_id")]
public string AuthorId { get; set; }
[JsonProperty("date_published")]
public DateTime DatePublished { get; set; }
[JsonProperty("downloads")]
public long Downloads { get; set; }
[JsonProperty("changelog_url")]
public object ChangelogUrl { get; set; }
[JsonProperty("files")]
public VersionFile[] Files { get; set; }
}

View File

@@ -0,0 +1,21 @@
using Newtonsoft.Json;
namespace Moonlight.App.ApiClients.Modrinth.Resources;
public class VersionFile
{
[JsonProperty("url")]
public Uri Url { get; set; }
[JsonProperty("filename")]
public string Filename { get; set; }
[JsonProperty("primary")]
public bool Primary { get; set; }
[JsonProperty("size")]
public long Size { get; set; }
[JsonProperty("file_type")]
public string FileType { get; set; }
}

View File

@@ -0,0 +1,11 @@
namespace Moonlight.App.ApiClients.Telemetry.Requests;
public class TelemetryData
{
public string AppUrl { get; set; } = "";
public int Servers { get; set; }
public int Nodes { get; set; }
public int Users { get; set; }
public int Databases { get; set; }
public int Webspaces { get; set; }
}

View File

@@ -0,0 +1,52 @@
using Newtonsoft.Json;
using RestSharp;
namespace Moonlight.App.ApiClients.Telemetry;
public class TelemetryApiHelper
{
private readonly RestClient Client;
public TelemetryApiHelper()
{
Client = new();
}
public async Task Post(string resource, object? body)
{
var request = CreateRequest(resource);
request.Method = Method.Post;
request.AddParameter("application/json", JsonConvert.SerializeObject(body), ParameterType.RequestBody);
var response = await Client.ExecuteAsync(request);
if (!response.IsSuccessful)
{
if (response.StatusCode != 0)
{
throw new TelemetryException(
$"An error occured: ({response.StatusCode}) {response.Content}",
(int)response.StatusCode
);
}
else
{
throw new Exception($"An internal error occured: {response.ErrorMessage}");
}
}
}
private RestRequest CreateRequest(string resource)
{
var url = "https://telemetry.moonlightpanel.xyz/" + resource;
var request = new RestRequest(url)
{
Timeout = 3000000
};
return request;
}
}

View File

@@ -0,0 +1,32 @@
using System.Runtime.Serialization;
namespace Moonlight.App.ApiClients.Telemetry;
[Serializable]
public class TelemetryException : Exception
{
public int StatusCode { get; set; }
public TelemetryException()
{
}
public TelemetryException(string message, int statusCode) : base(message)
{
StatusCode = statusCode;
}
public TelemetryException(string message) : base(message)
{
}
public TelemetryException(string message, Exception inner) : base(message, inner)
{
}
protected TelemetryException(
SerializationInfo info,
StreamingContext context) : base(info, context)
{
}
}

View File

@@ -209,7 +209,7 @@ public class WingsApiHelper
var request = new RestRequest(url)
{
Timeout = 60 * 15
Timeout = 300000
};
request.AddHeader("Content-Type", "application/json");

View File

@@ -0,0 +1,361 @@
using System.ComponentModel;
using Moonlight.App.Helpers;
namespace Moonlight.App.Configuration;
using System;
using Newtonsoft.Json;
public class ConfigV1
{
[JsonProperty("Moonlight")]
public MoonlightData Moonlight { get; set; } = new();
public class MoonlightData
{
[JsonProperty("AppUrl")]
[Description("The url moonlight is accesible with from the internet")]
public string AppUrl { get; set; } = "http://your-moonlight-url-without-slash";
[JsonProperty("EnableLatencyCheck")]
[Description(
"This will enable a latency check for connections to moonlight. Users with an too high latency will be warned that moonlight might be buggy for them")]
public bool EnableLatencyCheck { get; set; } = true;
[JsonProperty("LatencyCheckThreshold")]
[Description("Specify the latency threshold which has to be reached in order to trigger the warning message")]
public int LatencyCheckThreshold { get; set; } = 1000;
[JsonProperty("Auth")] public AuthData Auth { get; set; } = new();
[JsonProperty("Database")] public DatabaseData Database { get; set; } = new();
[JsonProperty("DiscordBotApi")] public DiscordBotApiData DiscordBotApi { get; set; } = new();
[JsonProperty("DiscordBot")] public DiscordBotData DiscordBot { get; set; } = new();
[JsonProperty("Domains")] public DomainsData Domains { get; set; } = new();
[JsonProperty("Html")] public HtmlData Html { get; set; } = new();
[JsonProperty("Marketing")] public MarketingData Marketing { get; set; } = new();
[JsonProperty("OAuth2")] public OAuth2Data OAuth2 { get; set; } = new();
[JsonProperty("Security")] public SecurityData Security { get; set; } = new();
[JsonProperty("Mail")] public MailData Mail { get; set; } = new();
[JsonProperty("Cleanup")] public CleanupData Cleanup { get; set; } = new();
[JsonProperty("DiscordNotifications")] public DiscordNotificationsData DiscordNotifications { get; set; } = new();
[JsonProperty("Statistics")] public StatisticsData Statistics { get; set; } = new();
[JsonProperty("Rating")] public RatingData Rating { get; set; } = new();
[JsonProperty("SmartDeploy")] public SmartDeployData SmartDeploy { get; set; } = new();
[JsonProperty("Sentry")] public SentryData Sentry { get; set; } = new();
[JsonProperty("Stripe")] public StripeData Stripe { get; set; } = new();
[JsonProperty("Tickets")] public TicketsData Tickets { get; set; } = new();
}
public class TicketsData
{
[JsonProperty("WelcomeMessage")]
[Description("The message that will be sent when a user created a ticket")]
public string WelcomeMessage { get; set; } = "Welcome to the support";
}
public class StripeData
{
[JsonProperty("ApiKey")]
[Description("Put here your stripe api key if you add subscriptions. Currently the only billing option is stripe which is enabled by default and cannot be turned off. This feature is still experimental")]
public string ApiKey { get; set; } = "";
}
public class AuthData
{
[JsonProperty("DenyLogin")]
[Description("Prevent every new login")]
public bool DenyLogin { get; set; } = false;
[JsonProperty("DenyRegister")]
[Description("Prevent every new user to register")]
public bool DenyRegister { get; set; } = false;
}
public class CleanupData
{
[JsonProperty("Cpu")]
[Description("The maximum amount of cpu usage in percent a node is allowed to use before the cleanup starts")]
public long Cpu { get; set; } = 90;
[JsonProperty("Memory")]
[Description("The minumum amount of memory in megabytes avaliable before the cleanup starts")]
public long Memory { get; set; } = 8192;
[JsonProperty("Wait")]
[Description("The delay between every cleanup check in minutes")]
public long Wait { get; set; } = 15;
[JsonProperty("Uptime")]
[Description("The maximum uptime of any server in hours before it the server restarted by the cleanup system")]
public long Uptime { get; set; } = 6;
[JsonProperty("Enable")]
[Description("The cleanup system provides a fair way for stopping unused servers and staying stable even with overallocation. A detailed explanation: docs.endelon-hosting.de/erklaerungen/cleanup")]
public bool Enable { get; set; } = false;
[JsonProperty("MinUptime")]
[Description("The minumum uptime of a server in minutes to prevent stopping servers which just started")]
public long MinUptime { get; set; } = 10;
}
public class DatabaseData
{
[JsonProperty("Database")] public string Database { get; set; } = "moonlight_db";
[JsonProperty("Host")] public string Host { get; set; } = "your.database.host";
[JsonProperty("Password")]
[Blur]
public string Password { get; set; } = "secret";
[JsonProperty("Port")] public long Port { get; set; } = 3306;
[JsonProperty("Username")] public string Username { get; set; } = "moonlight_user";
}
public class DiscordBotApiData
{
[JsonProperty("Enable")]
[Description("Enable the discord bot api. Currently only DatBot is using this api")]
public bool Enable { get; set; } = false;
[JsonProperty("Token")]
[Description("Specify the token the api client needs to provide")]
[Blur]
public string Token { get; set; } = Guid.NewGuid().ToString();
}
public class DiscordBotData
{
[JsonProperty("Enable")]
[Description("The discord bot can be used to allow customers to manage their servers via discord")]
public bool Enable { get; set; } = false;
[JsonProperty("Token")]
[Description("Your discord bot token goes here")]
[Blur]
public string Token { get; set; } = "discord token here";
[JsonProperty("PowerActions")]
[Description("Enable actions like starting and stopping servers")]
public bool PowerActions { get; set; } = false;
[JsonProperty("SendCommands")]
[Description("Allow users to send commands to their servers")]
public bool SendCommands { get; set; } = false;
}
public class DiscordNotificationsData
{
[JsonProperty("Enable")]
[Description("The discord notification system sends you a message everytime a event like a new support chat message is triggered with usefull data describing the event")]
public bool Enable { get; set; } = false;
[JsonProperty("WebHook")]
[Description("The discord webhook the notifications are being sent to")]
[Blur]
public string WebHook { get; set; } = "http://your-discord-webhook-url";
}
public class DomainsData
{
[JsonProperty("Enable")]
[Description("This enables the domain system")]
public bool Enable { get; set; } = false;
[JsonProperty("AccountId")]
[Description("This option specifies the cloudflare account id")]
public string AccountId { get; set; } = "cloudflare acc id";
[JsonProperty("Email")]
[Description("This specifies the cloudflare email to use for communicating with the cloudflare api")]
public string Email { get; set; } = "cloudflare@acc.email";
[JsonProperty("Key")]
[Description("Your cloudflare api key goes here")]
[Blur]
public string Key { get; set; } = "secret";
}
public class HtmlData
{
[JsonProperty("Headers")] public HeadersData Headers { get; set; } = new();
}
public class HeadersData
{
[JsonProperty("Color")]
[Description("This specifies the color of the embed generated by platforms like discord when someone posts a link to your moonlight instance")]
public string Color { get; set; } = "#4b27e8";
[JsonProperty("Description")]
[Description("This specifies the description text of the embed generated by platforms like discord when someone posts a link to your moonlight instance and can also help google to index your moonlight instance correctly")]
public string Description { get; set; } = "the next generation hosting panel";
[JsonProperty("Keywords")]
[Description("To help search engines like google to index your moonlight instance correctly you can specify keywords seperated by a comma here")]
public string Keywords { get; set; } = "moonlight";
[JsonProperty("Title")]
[Description("This specifies the title of the embed generated by platforms like discord when someone posts a link to your moonlight instance")]
public string Title { get; set; } = "Moonlight - endelon.link";
}
public class MailData
{
[JsonProperty("Email")] public string Email { get; set; } = "username@your.mail.host";
[JsonProperty("Server")] public string Server { get; set; } = "your.mail.host";
[JsonProperty("Password")]
[Blur]
public string Password { get; set; } = "secret";
[JsonProperty("Port")] public int Port { get; set; } = 465;
[JsonProperty("Ssl")] public bool Ssl { get; set; } = true;
}
public class MarketingData
{
[JsonProperty("BrandName")] public string BrandName { get; set; } = "Endelon Hosting";
[JsonProperty("Imprint")] public string Imprint { get; set; } = "https://your-site.xyz/imprint";
[JsonProperty("Privacy")] public string Privacy { get; set; } = "https://your-site.xyz/privacy";
[JsonProperty("About")] public string About { get; set; } = "https://your-site.xyz/about";
[JsonProperty("Website")] public string Website { get; set; } = "https://your-site.xyz";
}
public class OAuth2Data
{
[JsonProperty("OverrideUrl")]
[Description("This overrides the redirect url which would be typicaly the app url")]
public string OverrideUrl { get; set; } = "https://only-for-development.cases";
[JsonProperty("EnableOverrideUrl")]
[Description("This enables the url override")]
public bool EnableOverrideUrl { get; set; } = false;
[JsonProperty("Providers")]
public OAuth2ProviderData[] Providers { get; set; } = Array.Empty<OAuth2ProviderData>();
}
public class OAuth2ProviderData
{
[JsonProperty("Id")] public string Id { get; set; }
[JsonProperty("ClientId")] public string ClientId { get; set; }
[JsonProperty("ClientSecret")]
[Blur]
public string ClientSecret { get; set; }
}
public class RatingData
{
[JsonProperty("Enabled")]
[Description("The rating systems shows a user who is registered longer than the set amout of days a popup to rate this platform if he hasnt rated it before")]
public bool Enabled { get; set; } = false;
[JsonProperty("Url")]
[Description("This is the url a user who rated above a set limit is shown to rate you again. Its recommended to put your google or trustpilot rate link here")]
public string Url { get; set; } = "https://link-to-google-or-smth";
[JsonProperty("MinRating")]
[Description("The minimum star count on the rating ranging from 1 to 5")]
public int MinRating { get; set; } = 4;
[JsonProperty("DaysSince")]
[Description("The days a user has to be registered to even be able to get this popup")]
public int DaysSince { get; set; } = 5;
}
public class SecurityData
{
[JsonProperty("Token")]
[Description("This is the moonlight app token. It is used to encrypt and decrypt data and validate tokens and sessions")]
[Blur]
public string Token { get; set; } = Guid.NewGuid().ToString();
[JsonProperty("MalwareCheckOnStart")]
[Description(
"This option will enable the scanning for malware on every server before it has been started and if something has been found, the power action will be canceled")]
public bool MalwareCheckOnStart { get; set; } = true;
[JsonProperty("BlockIpDuration")]
[Description("The duration in minutes a ip will be blocked by the anti ddos system")]
public int BlockIpDuration { get; set; } = 15;
[JsonProperty("ReCaptcha")] public ReCaptchaData ReCaptcha { get; set; } = new();
}
public class ReCaptchaData
{
[JsonProperty("Enable")]
[Description("Enables repatcha at places like the register page. For information how to get your recaptcha credentails go to google.com/recaptcha/about/")]
public bool Enable { get; set; } = false;
[JsonProperty("SiteKey")]
[Blur]
public string SiteKey { get; set; } = "recaptcha site key here";
[JsonProperty("SecretKey")]
[Blur]
public string SecretKey { get; set; } = "recaptcha secret here";
}
public class SentryData
{
[JsonProperty("Enable")]
[Description("Sentry is a way to monitor application crashes and performance issues in real time. Enable this option only if you set a sentry dsn")]
public bool Enable { get; set; } = false;
[JsonProperty("Dsn")]
[Description("The dsn is the key moonlight needs to communicate with your sentry instance")]
[Blur]
public string Dsn { get; set; } = "http://your-sentry-url-here";
}
public class SmartDeployData
{
[JsonProperty("Server")] public SmartDeployServerData Server { get; set; } = new();
}
public class SmartDeployServerData
{
[JsonProperty("EnableOverride")] public bool EnableOverride { get; set; } = false;
[JsonProperty("OverrideNode")] public long OverrideNode { get; set; } = 1;
}
public class StatisticsData
{
[JsonProperty("Enabled")] public bool Enabled { get; set; } = false;
[JsonProperty("Wait")] public long Wait { get; set; } = 15;
}
public class SellPassData
{
[JsonProperty("Enable")] public bool Enable { get; set; } = false;
[JsonProperty("Url")] public string Url { get; set; } = "https://not-implemented-yet";
}
}

View File

@@ -1,9 +1,7 @@
using Microsoft.EntityFrameworkCore;
using Moonlight.App.Database.Entities;
using Moonlight.App.Database.Entities.LogsEntries;
using Moonlight.App.Database.Entities.Notification;
using Moonlight.App.Database.Interceptors;
using Moonlight.App.Models.Misc;
using Moonlight.App.Services;
namespace Moonlight.App.Database;
@@ -27,10 +25,6 @@ public class DataContext : DbContext
public DbSet<ServerVariable> ServerVariables { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<LoadingMessage> LoadingMessages { get; set; }
public DbSet<AuditLogEntry> AuditLog { get; set; }
public DbSet<ErrorLogEntry> ErrorLog { get; set; }
public DbSet<SecurityLogEntry> SecurityLog { get; set; }
public DbSet<SharedDomain> SharedDomains { get; set; }
public DbSet<Domain> Domains { get; set; }
public DbSet<Revoke> Revokes { get; set; }
@@ -46,20 +40,27 @@ public class DataContext : DbContext
public DbSet<WebSpace> WebSpaces { get; set; }
public DbSet<SupportChatMessage> SupportChatMessages { get; set; }
public DbSet<IpBan> IpBans { get; set; }
public DbSet<PermissionGroup> PermissionGroups { get; set; }
public DbSet<SecurityLog> SecurityLogs { get; set; }
public DbSet<BlocklistIp> BlocklistIps { get; set; }
public DbSet<WhitelistIp> WhitelistIps { get; set; }
public DbSet<Ticket> Tickets { get; set; }
public DbSet<TicketMessage> TicketMessages { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
var config = ConfigService
.GetSection("Moonlight")
.GetSection("Database");
.Get()
.Moonlight.Database;
var connectionString = $"host={config.GetValue<string>("Host")};" +
$"port={config.GetValue<int>("Port")};" +
$"database={config.GetValue<string>("Database")};" +
$"uid={config.GetValue<string>("Username")};" +
$"pwd={config.GetValue<string>("Password")}";
var connectionString = $"host={config.Host};" +
$"port={config.Port};" +
$"database={config.Database};" +
$"uid={config.Username};" +
$"pwd={config.Password}";
optionsBuilder.UseMySql(
connectionString,

View File

@@ -0,0 +1,10 @@
namespace Moonlight.App.Database.Entities;
public class BlocklistIp
{
public int Id { get; set; }
public string Ip { get; set; } = "";
public DateTime ExpiresAt { get; set; }
public long Packets { get; set; }
public DateTime CreatedAt { get; set; }
}

View File

@@ -1,13 +0,0 @@
using Moonlight.App.Models.Misc;
namespace Moonlight.App.Database.Entities.LogsEntries;
public class AuditLogEntry
{
public int Id { get; set; }
public AuditLogType Type { get; set; }
public string JsonData { get; set; } = "";
public bool System { get; set; }
public string Ip { get; set; } = "";
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}

View File

@@ -1,12 +0,0 @@
namespace Moonlight.App.Database.Entities.LogsEntries;
public class ErrorLogEntry
{
public int Id { get; set; }
public string Stacktrace { get; set; } = "";
public bool System { get; set; }
public string JsonData { get; set; } = "";
public string Ip { get; set; } = "";
public string Class { get; set; } = "";
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}

View File

@@ -1,13 +0,0 @@
using Moonlight.App.Models.Misc;
namespace Moonlight.App.Database.Entities.LogsEntries;
public class SecurityLogEntry
{
public int Id { get; set; }
public bool System { get; set; }
public string Ip { get; set; } = "";
public SecurityLogType Type { get; set; }
public string JsonData { get; set; } = "";
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}

View File

@@ -0,0 +1,8 @@
namespace Moonlight.App.Database.Entities;
public class PermissionGroup
{
public int Id { get; set; }
public string Name { get; set; } = "";
public byte[] Permissions { get; set; } = Array.Empty<byte>();
}

View File

@@ -0,0 +1,8 @@
namespace Moonlight.App.Database.Entities;
public class SecurityLog
{
public int Id { get; set; }
public string Text { get; set; } = "";
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}

View File

@@ -13,6 +13,8 @@ public class Server
public string OverrideStartup { get; set; } = "";
public bool Installing { get; set; } = false;
public bool Suspended { get; set; } = false;
public bool IsArchived { get; set; } = false;
public ServerBackup? Archive { get; set; } = null;
public List<ServerVariable> Variables { get; set; } = new();
public List<ServerBackup> Backups { get; set; } = new();

View File

@@ -1,9 +1,16 @@
namespace Moonlight.App.Database.Entities;
using Moonlight.App.Models.Misc;
namespace Moonlight.App.Database.Entities;
public class Subscription
{
public int Id { get; set; }
public string Name { get; set; } = "";
public string Description { get; set; } = "";
public Currency Currency { get; set; } = Currency.USD;
public double Price { get; set; }
public string StripeProductId { get; set; } = "";
public string StripePriceId { get; set; } = "";
public string LimitsJson { get; set; } = "";
public int Duration { get; set; } = 30;
}

View File

@@ -0,0 +1,19 @@
using Moonlight.App.Models.Misc;
namespace Moonlight.App.Database.Entities;
public class Ticket
{
public int Id { get; set; }
public string IssueTopic { get; set; } = "";
public string IssueDescription { get; set; } = "";
public string IssueTries { get; set; } = "";
public User CreatedBy { get; set; }
public User? AssignedTo { get; set; }
public TicketPriority Priority { get; set; }
public TicketStatus Status { get; set; }
public TicketSubject Subject { get; set; }
public int SubjectId { get; set; }
public List<TicketMessage> Messages { get; set; } = new();
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}

View File

@@ -0,0 +1,14 @@
namespace Moonlight.App.Database.Entities;
public class TicketMessage
{
public int Id { get; set; }
public string Content { get; set; } = "";
public string? AttachmentUrl { get; set; }
public User? Sender { get; set; }
public bool IsSystemMessage { get; set; }
public bool IsEdited { get; set; }
public bool IsSupportMessage { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
}

View File

@@ -1,4 +1,5 @@
using Moonlight.App.Models.Misc;
using System.ComponentModel.DataAnnotations;
using Moonlight.App.Models.Misc;
namespace Moonlight.App.Database.Entities;
@@ -23,7 +24,9 @@ public class User
public string State { get; set; } = "";
public string Country { get; set; } = "";
public string ServerListLayoutJson { get; set; } = "";
// States
public UserStatus Status { get; set; } = UserStatus.Unverified;
@@ -31,11 +34,14 @@ public class User
public bool SupportPending { get; set; } = false;
public bool HasRated { get; set; } = false;
public int Rating { get; set; } = 0;
public bool StreamerMode { get; set; } = false;
// Security
public bool TotpEnabled { get; set; } = false;
public string TotpSecret { get; set; } = "";
public DateTime TokenValidTime { get; set; } = DateTime.UtcNow;
public byte[] Permissions { get; set; } = Array.Empty<byte>();
public PermissionGroup? PermissionGroup { get; set; }
// Discord
public ulong DiscordId { get; set; }
@@ -48,6 +54,10 @@ public class User
// Subscriptions
public Subscription? CurrentSubscription { get; set; } = null;
public DateTime SubscriptionSince { get; set; } = DateTime.Now;
public int SubscriptionDuration { get; set; }
public DateTime SubscriptionSince { get; set; } = DateTime.UtcNow;
public DateTime SubscriptionExpires { get; set; } = DateTime.UtcNow;
// Ip logs
public string RegisterIp { get; set; } = "";
public string LastIp { get; set; } = "";
}

View File

@@ -0,0 +1,7 @@
namespace Moonlight.App.Database.Entities;
public class WhitelistIp
{
public int Id { get; set; }
public string Ip { get; set; } = "";
}

View File

@@ -1,6 +1,6 @@
using System.Data.Common;
using Logging.Net;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Moonlight.App.Helpers;
namespace Moonlight.App.Database.Interceptors;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,59 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Moonlight.App.Database.Migrations
{
/// <inheritdoc />
public partial class AddedServerAchive : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "ArchiveId",
table: "Servers",
type: "int",
nullable: true);
migrationBuilder.AddColumn<bool>(
name: "IsArchived",
table: "Servers",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
migrationBuilder.CreateIndex(
name: "IX_Servers_ArchiveId",
table: "Servers",
column: "ArchiveId");
migrationBuilder.AddForeignKey(
name: "FK_Servers_ServerBackups_ArchiveId",
table: "Servers",
column: "ArchiveId",
principalTable: "ServerBackups",
principalColumn: "Id");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Servers_ServerBackups_ArchiveId",
table: "Servers");
migrationBuilder.DropIndex(
name: "IX_Servers_ArchiveId",
table: "Servers");
migrationBuilder.DropColumn(
name: "ArchiveId",
table: "Servers");
migrationBuilder.DropColumn(
name: "IsArchived",
table: "Servers");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Moonlight.App.Database.Migrations
{
/// <inheritdoc />
public partial class AddedServerListLayoutToUser : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "ServerListLayoutJson",
table: "Users",
type: "longtext",
nullable: false)
.Annotation("MySql:CharSet", "utf8mb4");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "ServerListLayoutJson",
table: "Users");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Moonlight.App.Database.Migrations
{
/// <inheritdoc />
public partial class AddedStreamerMode : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "StreamerMode",
table: "Users",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "StreamerMode",
table: "Users");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,40 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Moonlight.App.Database.Migrations
{
/// <inheritdoc />
public partial class AddedIpLogsForUser : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "LastIp",
table: "Users",
type: "longtext",
nullable: false)
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AddColumn<string>(
name: "RegisterIp",
table: "Users",
type: "longtext",
nullable: false)
.Annotation("MySql:CharSet", "utf8mb4");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "LastIp",
table: "Users");
migrationBuilder.DropColumn(
name: "RegisterIp",
table: "Users");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,96 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Moonlight.App.Database.Migrations
{
/// <inheritdoc />
public partial class AddedStripeIntegration : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "SubscriptionDuration",
table: "Users");
migrationBuilder.AddColumn<DateTime>(
name: "SubscriptionExpires",
table: "Users",
type: "datetime(6)",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
migrationBuilder.AddColumn<int>(
name: "Currency",
table: "Subscriptions",
type: "int",
nullable: false,
defaultValue: 0);
migrationBuilder.AddColumn<int>(
name: "Duration",
table: "Subscriptions",
type: "int",
nullable: false,
defaultValue: 0);
migrationBuilder.AddColumn<double>(
name: "Price",
table: "Subscriptions",
type: "double",
nullable: false,
defaultValue: 0.0);
migrationBuilder.AddColumn<string>(
name: "StripePriceId",
table: "Subscriptions",
type: "longtext",
nullable: false)
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AddColumn<string>(
name: "StripeProductId",
table: "Subscriptions",
type: "longtext",
nullable: false)
.Annotation("MySql:CharSet", "utf8mb4");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "SubscriptionExpires",
table: "Users");
migrationBuilder.DropColumn(
name: "Currency",
table: "Subscriptions");
migrationBuilder.DropColumn(
name: "Duration",
table: "Subscriptions");
migrationBuilder.DropColumn(
name: "Price",
table: "Subscriptions");
migrationBuilder.DropColumn(
name: "StripePriceId",
table: "Subscriptions");
migrationBuilder.DropColumn(
name: "StripeProductId",
table: "Subscriptions");
migrationBuilder.AddColumn<int>(
name: "SubscriptionDuration",
table: "Users",
type: "int",
nullable: false,
defaultValue: 0);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,28 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Moonlight.App.Database.Migrations
{
/// <inheritdoc />
public partial class AddPermissions : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<byte[]>(
name: "Permissions",
table: "Users",
type: "longblob",
nullable: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Permissions",
table: "Users");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,68 @@
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Moonlight.App.Database.Migrations
{
/// <inheritdoc />
public partial class AddPermissionGroup : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "PermissionGroupId",
table: "Users",
type: "int",
nullable: true);
migrationBuilder.CreateTable(
name: "PermissionGroups",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
Name = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Permissions = table.Column<byte[]>(type: "longblob", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_PermissionGroups", x => x.Id);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateIndex(
name: "IX_Users_PermissionGroupId",
table: "Users",
column: "PermissionGroupId");
migrationBuilder.AddForeignKey(
name: "FK_Users_PermissionGroups_PermissionGroupId",
table: "Users",
column: "PermissionGroupId",
principalTable: "PermissionGroups",
principalColumn: "Id");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Users_PermissionGroups_PermissionGroupId",
table: "Users");
migrationBuilder.DropTable(
name: "PermissionGroups");
migrationBuilder.DropIndex(
name: "IX_Users_PermissionGroupId",
table: "Users");
migrationBuilder.DropColumn(
name: "PermissionGroupId",
table: "Users");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,111 @@
using System;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Moonlight.App.Database.Migrations
{
/// <inheritdoc />
public partial class RemovedOldLogsAndAddedErrorLog : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AuditLog");
migrationBuilder.DropTable(
name: "ErrorLog");
migrationBuilder.DropTable(
name: "SecurityLog");
migrationBuilder.CreateTable(
name: "SecurityLogs",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
Text = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_SecurityLogs", x => x.Id);
})
.Annotation("MySql:CharSet", "utf8mb4");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "SecurityLogs");
migrationBuilder.CreateTable(
name: "AuditLog",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
Ip = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
JsonData = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
System = table.Column<bool>(type: "tinyint(1)", nullable: false),
Type = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_AuditLog", x => x.Id);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "ErrorLog",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
Class = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
Ip = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
JsonData = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Stacktrace = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
System = table.Column<bool>(type: "tinyint(1)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ErrorLog", x => x.Id);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "SecurityLog",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
Ip = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
JsonData = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
System = table.Column<bool>(type: "tinyint(1)", nullable: false),
Type = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_SecurityLog", x => x.Id);
})
.Annotation("MySql:CharSet", "utf8mb4");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,59 @@
using System;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Moonlight.App.Database.Migrations
{
/// <inheritdoc />
public partial class AddIpRules : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "BlocklistIps",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
Ip = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
ExpiresAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
Packets = table.Column<long>(type: "bigint", nullable: false),
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_BlocklistIps", x => x.Id);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "WhitelistIps",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
Ip = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4")
},
constraints: table =>
{
table.PrimaryKey("PK_WhitelistIps", x => x.Id);
})
.Annotation("MySql:CharSet", "utf8mb4");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "BlocklistIps");
migrationBuilder.DropTable(
name: "WhitelistIps");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,117 @@
using System;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Moonlight.App.Database.Migrations
{
/// <inheritdoc />
public partial class AddNewTicketModels : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Tickets",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
IssueTopic = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
IssueDescription = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
IssueTries = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
CreatedById = table.Column<int>(type: "int", nullable: false),
AssignedToId = table.Column<int>(type: "int", nullable: true),
Priority = table.Column<int>(type: "int", nullable: false),
Status = table.Column<int>(type: "int", nullable: false),
Subject = table.Column<int>(type: "int", nullable: false),
SubjectId = table.Column<int>(type: "int", nullable: false),
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Tickets", x => x.Id);
table.ForeignKey(
name: "FK_Tickets_Users_AssignedToId",
column: x => x.AssignedToId,
principalTable: "Users",
principalColumn: "Id");
table.ForeignKey(
name: "FK_Tickets_Users_CreatedById",
column: x => x.CreatedById,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "TicketMessages",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
Content = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
AttachmentUrl = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
SenderId = table.Column<int>(type: "int", nullable: true),
IsSystemMessage = table.Column<bool>(type: "tinyint(1)", nullable: false),
IsEdited = table.Column<bool>(type: "tinyint(1)", nullable: false),
IsSupportMessage = table.Column<bool>(type: "tinyint(1)", nullable: false),
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
UpdatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
TicketId = table.Column<int>(type: "int", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_TicketMessages", x => x.Id);
table.ForeignKey(
name: "FK_TicketMessages_Tickets_TicketId",
column: x => x.TicketId,
principalTable: "Tickets",
principalColumn: "Id");
table.ForeignKey(
name: "FK_TicketMessages_Users_SenderId",
column: x => x.SenderId,
principalTable: "Users",
principalColumn: "Id");
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateIndex(
name: "IX_TicketMessages_SenderId",
table: "TicketMessages",
column: "SenderId");
migrationBuilder.CreateIndex(
name: "IX_TicketMessages_TicketId",
table: "TicketMessages",
column: "TicketId");
migrationBuilder.CreateIndex(
name: "IX_Tickets_AssignedToId",
table: "Tickets",
column: "AssignedToId");
migrationBuilder.CreateIndex(
name: "IX_Tickets_CreatedById",
table: "Tickets",
column: "CreatedById");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "TicketMessages");
migrationBuilder.DropTable(
name: "Tickets");
}
}
}

View File

@@ -19,6 +19,30 @@ namespace Moonlight.App.Database.Migrations
.HasAnnotation("ProductVersion", "7.0.3")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
modelBuilder.Entity("Moonlight.App.Database.Entities.BlocklistIp", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<DateTime>("ExpiresAt")
.HasColumnType("datetime(6)");
b.Property<string>("Ip")
.IsRequired()
.HasColumnType("longtext");
b.Property<long>("Packets")
.HasColumnType("bigint");
b.HasKey("Id");
b.ToTable("BlocklistIps");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.CloudPanel", b =>
{
b.Property<int>("Id")
@@ -241,95 +265,6 @@ namespace Moonlight.App.Database.Migrations
b.ToTable("LoadingMessages");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.AuditLogEntry", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("Ip")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("JsonData")
.IsRequired()
.HasColumnType("longtext");
b.Property<bool>("System")
.HasColumnType("tinyint(1)");
b.Property<int>("Type")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("AuditLog");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.ErrorLogEntry", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("Class")
.IsRequired()
.HasColumnType("longtext");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("Ip")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("JsonData")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Stacktrace")
.IsRequired()
.HasColumnType("longtext");
b.Property<bool>("System")
.HasColumnType("tinyint(1)");
b.HasKey("Id");
b.ToTable("ErrorLog");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.LogsEntries.SecurityLogEntry", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("Ip")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("JsonData")
.IsRequired()
.HasColumnType("longtext");
b.Property<bool>("System")
.HasColumnType("tinyint(1)");
b.Property<int>("Type")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("SecurityLog");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.MySqlDatabase", b =>
{
b.Property<int>("Id")
@@ -475,6 +410,25 @@ namespace Moonlight.App.Database.Migrations
b.ToTable("NotificationClients");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.PermissionGroup", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("longtext");
b.Property<byte[]>("Permissions")
.IsRequired()
.HasColumnType("longblob");
b.HasKey("Id");
b.ToTable("PermissionGroups");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Revoke", b =>
{
b.Property<int>("Id")
@@ -490,12 +444,33 @@ namespace Moonlight.App.Database.Migrations
b.ToTable("Revokes");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.SecurityLog", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<string>("Text")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("SecurityLogs");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int?>("ArchiveId")
.HasColumnType("int");
b.Property<int>("Cpu")
.HasColumnType("int");
@@ -511,6 +486,9 @@ namespace Moonlight.App.Database.Migrations
b.Property<bool>("Installing")
.HasColumnType("tinyint(1)");
b.Property<bool>("IsArchived")
.HasColumnType("tinyint(1)");
b.Property<bool>("IsCleanupException")
.HasColumnType("tinyint(1)");
@@ -542,6 +520,8 @@ namespace Moonlight.App.Database.Migrations
b.HasKey("Id");
b.HasIndex("ArchiveId");
b.HasIndex("ImageId");
b.HasIndex("MainAllocationId");
@@ -655,10 +635,16 @@ namespace Moonlight.App.Database.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int>("Currency")
.HasColumnType("int");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("Duration")
.HasColumnType("int");
b.Property<string>("LimitsJson")
.IsRequired()
.HasColumnType("longtext");
@@ -667,6 +653,17 @@ namespace Moonlight.App.Database.Migrations
.IsRequired()
.HasColumnType("longtext");
b.Property<double>("Price")
.HasColumnType("double");
b.Property<string>("StripePriceId")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("StripeProductId")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("Subscriptions");
@@ -717,6 +714,97 @@ namespace Moonlight.App.Database.Migrations
b.ToTable("SupportChatMessages");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Ticket", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int?>("AssignedToId")
.HasColumnType("int");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<int>("CreatedById")
.HasColumnType("int");
b.Property<string>("IssueDescription")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("IssueTopic")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("IssueTries")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("Priority")
.HasColumnType("int");
b.Property<int>("Status")
.HasColumnType("int");
b.Property<int>("Subject")
.HasColumnType("int");
b.Property<int>("SubjectId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("AssignedToId");
b.HasIndex("CreatedById");
b.ToTable("Tickets");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.TicketMessage", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("AttachmentUrl")
.HasColumnType("longtext");
b.Property<string>("Content")
.IsRequired()
.HasColumnType("longtext");
b.Property<DateTime>("CreatedAt")
.HasColumnType("datetime(6)");
b.Property<bool>("IsEdited")
.HasColumnType("tinyint(1)");
b.Property<bool>("IsSupportMessage")
.HasColumnType("tinyint(1)");
b.Property<bool>("IsSystemMessage")
.HasColumnType("tinyint(1)");
b.Property<int?>("SenderId")
.HasColumnType("int");
b.Property<int?>("TicketId")
.HasColumnType("int");
b.Property<DateTime>("UpdatedAt")
.HasColumnType("datetime(6)");
b.HasKey("Id");
b.HasIndex("SenderId");
b.HasIndex("TicketId");
b.ToTable("TicketMessages");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
{
b.Property<int>("Id")
@@ -758,6 +846,10 @@ namespace Moonlight.App.Database.Migrations
b.Property<bool>("HasRated")
.HasColumnType("tinyint(1)");
b.Property<string>("LastIp")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("LastName")
.IsRequired()
.HasColumnType("longtext");
@@ -769,9 +861,24 @@ namespace Moonlight.App.Database.Migrations
.IsRequired()
.HasColumnType("longtext");
b.Property<int?>("PermissionGroupId")
.HasColumnType("int");
b.Property<byte[]>("Permissions")
.IsRequired()
.HasColumnType("longblob");
b.Property<int>("Rating")
.HasColumnType("int");
b.Property<string>("RegisterIp")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("ServerListLayoutJson")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("State")
.IsRequired()
.HasColumnType("longtext");
@@ -779,8 +886,11 @@ namespace Moonlight.App.Database.Migrations
b.Property<int>("Status")
.HasColumnType("int");
b.Property<int>("SubscriptionDuration")
.HasColumnType("int");
b.Property<bool>("StreamerMode")
.HasColumnType("tinyint(1)");
b.Property<DateTime>("SubscriptionExpires")
.HasColumnType("datetime(6)");
b.Property<DateTime>("SubscriptionSince")
.HasColumnType("datetime(6)");
@@ -805,6 +915,8 @@ namespace Moonlight.App.Database.Migrations
b.HasIndex("CurrentSubscriptionId");
b.HasIndex("PermissionGroupId");
b.ToTable("Users");
});
@@ -845,6 +957,21 @@ namespace Moonlight.App.Database.Migrations
b.ToTable("WebSpaces");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.WhitelistIp", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("Ip")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("WhitelistIps");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.DdosAttack", b =>
{
b.HasOne("Moonlight.App.Database.Entities.Node", "Node")
@@ -935,6 +1062,10 @@ namespace Moonlight.App.Database.Migrations
modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b =>
{
b.HasOne("Moonlight.App.Database.Entities.ServerBackup", "Archive")
.WithMany()
.HasForeignKey("ArchiveId");
b.HasOne("Moonlight.App.Database.Entities.Image", "Image")
.WithMany()
.HasForeignKey("ImageId")
@@ -957,6 +1088,8 @@ namespace Moonlight.App.Database.Migrations
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Archive");
b.Navigation("Image");
b.Navigation("MainAllocation");
@@ -997,13 +1130,49 @@ namespace Moonlight.App.Database.Migrations
b.Navigation("Sender");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Ticket", b =>
{
b.HasOne("Moonlight.App.Database.Entities.User", "AssignedTo")
.WithMany()
.HasForeignKey("AssignedToId");
b.HasOne("Moonlight.App.Database.Entities.User", "CreatedBy")
.WithMany()
.HasForeignKey("CreatedById")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("AssignedTo");
b.Navigation("CreatedBy");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.TicketMessage", b =>
{
b.HasOne("Moonlight.App.Database.Entities.User", "Sender")
.WithMany()
.HasForeignKey("SenderId");
b.HasOne("Moonlight.App.Database.Entities.Ticket", null)
.WithMany("Messages")
.HasForeignKey("TicketId");
b.Navigation("Sender");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
{
b.HasOne("Moonlight.App.Database.Entities.Subscription", "CurrentSubscription")
.WithMany()
.HasForeignKey("CurrentSubscriptionId");
b.HasOne("Moonlight.App.Database.Entities.PermissionGroup", "PermissionGroup")
.WithMany()
.HasForeignKey("PermissionGroupId");
b.Navigation("CurrentSubscription");
b.Navigation("PermissionGroup");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.WebSpace", b =>
@@ -1046,6 +1215,11 @@ namespace Moonlight.App.Database.Migrations
b.Navigation("Variables");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.Ticket", b =>
{
b.Navigation("Messages");
});
modelBuilder.Entity("Moonlight.App.Database.Entities.WebSpace", b =>
{
b.Navigation("Databases");

View File

@@ -1,5 +1,5 @@
using System.Diagnostics;
using Logging.Net;
using Moonlight.App.Helpers;
namespace Moonlight.App.Events;
@@ -112,4 +112,22 @@ public class EventSystem
return Task.CompletedTask;
}
public Task<T> WaitForEvent<T>(string id, object handle, Func<T, bool> filter)
{
var taskCompletionSource = new TaskCompletionSource<T>();
Func<T, Task> action = async data =>
{
if (filter.Invoke(data))
{
taskCompletionSource.SetResult(data);
await Off(id, handle);
}
};
On<T>(id, handle, action);
return taskCompletionSource.Task;
}
}

View File

@@ -5,6 +5,8 @@ namespace Moonlight.App.Exceptions;
[Serializable]
public class DisplayException : Exception
{
public bool DoNotTranslate { get; set; } = false;
//
// For guidelines regarding the creation of new exception types, see
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconerrorraisinghandlingguidelines.asp
@@ -19,6 +21,11 @@ public class DisplayException : Exception
public DisplayException(string message) : base(message)
{
}
public DisplayException(string message, bool doNotTranslate) : base(message)
{
DoNotTranslate = doNotTranslate;
}
public DisplayException(string message, Exception inner) : base(message, inner)
{

View File

@@ -0,0 +1,30 @@
using Microsoft.JSInterop;
namespace Moonlight.App.Extensions;
public static class JSRuntimeExtensions
{
public static async Task InvokeVoidSafeAsync(this IJSRuntime jsRuntime, string method, params object[] args)
{
try
{
await jsRuntime.InvokeVoidAsync(method, args);
}
catch (Exception)
{
// ignored
}
}
public static void InvokeVoidSafe(this IJSRuntime jsRuntime, string method, params object[] args)
{
try
{
jsRuntime.InvokeVoidAsync(method, args);
}
catch (Exception)
{
// ignored
}
}
}

View File

@@ -0,0 +1,119 @@
using System.Diagnostics;
using System.IO.Compression;
using Microsoft.EntityFrameworkCore;
using Moonlight.App.Database;
using Moonlight.App.Services;
using MySql.Data.MySqlClient;
namespace Moonlight.App.Helpers;
public class BackupHelper
{
public async Task CreateBackup(string path)
{
Logger.Info("Started moonlight backup creation");
Logger.Info($"This backup will be saved to '{path}'");
var stopWatch = new Stopwatch();
stopWatch.Start();
var cachePath = PathBuilder.Dir("storage", "backups", "cache");
Directory.CreateDirectory(cachePath);
//
// Exporting database
//
Logger.Info("Exporting database");
var configService = new ConfigService(new());
var dataContext = new DataContext(configService);
await using MySqlConnection conn = new MySqlConnection(dataContext.Database.GetConnectionString());
await using MySqlCommand cmd = new MySqlCommand();
using MySqlBackup mb = new MySqlBackup(cmd);
cmd.Connection = conn;
await conn.OpenAsync();
mb.ExportToFile(PathBuilder.File(cachePath, "database.sql"));
await conn.CloseAsync();
//
// Saving config
//
Logger.Info("Saving configuration");
File.Copy(
PathBuilder.File("storage", "configs", "config.json"),
PathBuilder.File(cachePath, "config.json"));
//
// Saving all storage items needed to restore the panel
//
Logger.Info("Saving resources");
CopyDirectory(
PathBuilder.Dir("storage", "resources"),
PathBuilder.Dir(cachePath, "resources"));
Logger.Info("Saving logs");
CopyDirectory(
PathBuilder.Dir("storage", "logs"),
PathBuilder.Dir(cachePath, "logs"));
Logger.Info("Saving uploads");
CopyDirectory(
PathBuilder.Dir("storage", "uploads"),
PathBuilder.Dir(cachePath, "uploads"));
//
// Compressing the backup to a single file
//
Logger.Info("Compressing");
ZipFile.CreateFromDirectory(cachePath,
path,
CompressionLevel.Fastest,
false);
Directory.Delete(cachePath, true);
stopWatch.Stop();
Logger.Info($"Backup successfully created. Took {stopWatch.Elapsed.TotalSeconds} seconds");
}
private void CopyDirectory(string sourceDirName, string destDirName, bool copySubDirs = true)
{
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
if (!dir.Exists)
{
throw new DirectoryNotFoundException($"Source directory does not exist or could not be found: {sourceDirName}");
}
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
}
FileInfo[] files = dir.GetFiles();
foreach (FileInfo file in files)
{
string tempPath = Path.Combine(destDirName, file.Name);
file.CopyTo(tempPath, false);
}
if (copySubDirs)
{
DirectoryInfo[] dirs = dir.GetDirectories();
foreach (DirectoryInfo subdir in dirs)
{
string tempPath = Path.Combine(destDirName, subdir.Name);
CopyDirectory(subdir.FullName, tempPath, copySubDirs);
}
}
}
}

View File

@@ -0,0 +1,88 @@
namespace Moonlight.App.Helpers;
public class BitHelper
{
public static bool ReadBit(byte[] byteArray, int bitIndex)
{
if (bitIndex < 0)
throw new ArgumentOutOfRangeException("bitIndex");
int byteIndex = bitIndex / 8;
if (byteIndex >= byteArray.Length)
throw new ArgumentOutOfRangeException("bitIndex");
int bitNumber = bitIndex % 8;
byte mask = (byte)(1 << bitNumber);
return (byteArray[byteIndex] & mask) != 0;
}
public static byte[] WriteBit(byte[] byteArray, int bitIndex, bool value)
{
if (bitIndex < 0)
throw new ArgumentOutOfRangeException("bitIndex");
int byteIndex = bitIndex / 8;
byte[] resultArray;
if (byteIndex >= byteArray.Length)
{
// Create a new array with increased size and copy elements from old array
resultArray = new byte[byteIndex + 1];
Array.Copy(byteArray, resultArray, byteArray.Length);
}
else
{
// Create a new array and copy elements from old array
resultArray = new byte[byteArray.Length];
Array.Copy(byteArray, resultArray, byteArray.Length);
}
int bitNumber = bitIndex % 8;
byte mask = (byte)(1 << bitNumber);
if (value)
resultArray[byteIndex] |= mask; // Set the bit to 1
else
resultArray[byteIndex] &= (byte)~mask; // Set the bit to 0
return resultArray;
}
public static byte[] OverwriteByteArrays(byte[] targetArray, byte[] overwriteArray)
{
int targetLength = targetArray.Length;
int overwriteLength = overwriteArray.Length;
int maxLength = Math.Max(targetLength, overwriteLength);
byte[] resultArray = new byte[maxLength];
for (int i = 0; i < maxLength; i++)
{
byte targetByte = i < targetLength ? targetArray[i] : (byte)0;
byte overwriteByte = i < overwriteLength ? overwriteArray[i] : (byte)0;
for (int j = 0; j < 8; j++)
{
bool overwriteBit = (overwriteByte & (1 << j)) != 0;
if (i < targetLength)
{
bool targetBit = (targetByte & (1 << j)) != 0;
if (overwriteBit)
{
targetByte = targetBit ? (byte)(targetByte | (1 << j)) : (byte)(targetByte & ~(1 << j));
}
}
else if (overwriteBit)
{
targetByte |= (byte)(1 << j);
}
}
resultArray[i] = targetByte;
}
return resultArray;
}
}

View File

@@ -0,0 +1,6 @@
namespace Moonlight.App.Helpers;
public class BlurAttribute : Attribute
{
}

View File

@@ -0,0 +1,56 @@
namespace Moonlight.App.Helpers;
public class ByteSizeValue
{
public long Bytes { get; set; }
public long KiloBytes
{
get => Bytes / 1024;
set => Bytes = value * 1024;
}
public long MegaBytes
{
get => KiloBytes / 1024;
set => KiloBytes = value * 1024;
}
public long GigaBytes
{
get => MegaBytes / 1024;
set => MegaBytes = value * 1024;
}
public static ByteSizeValue FromBytes(long bytes)
{
return new()
{
Bytes = bytes
};
}
public static ByteSizeValue FromKiloBytes(long kiloBytes)
{
return new()
{
KiloBytes = kiloBytes
};
}
public static ByteSizeValue FromMegaBytes(long megaBytes)
{
return new()
{
MegaBytes = megaBytes
};
}
public static ByteSizeValue FromGigaBytes(long gigaBytes)
{
return new()
{
GigaBytes = gigaBytes
};
}
}

View File

@@ -1,252 +0,0 @@
using System.Diagnostics;
using Logging.Net;
using Logging.Net.Loggers.SB;
using Moonlight.App.Models.Misc;
using ILogger = Logging.Net.ILogger;
namespace Moonlight.App.Helpers;
public class CacheLogger : ILogger
{
private SBLogger SbLogger = new();
private List<LogEntry> Messages = new();
public LogEntry[] GetMessages()
{
lock (Messages)
{
var result = new LogEntry[Messages.Count];
Messages.CopyTo(result);
return result;
}
}
public void Clear(int messages)
{
lock (Messages)
{
Messages.RemoveRange(0, Math.Min(messages, Messages.Count));
}
}
public void Info(string? s)
{
if (s == null)
return;
lock (Messages)
{
Messages.Add(new()
{
Level = "info",
Message = s
});
}
SbLogger.Info(s);
}
public void Debug(string? s)
{
if (s == null)
return;
lock (Messages)
{
Messages.Add(new()
{
Level = "debug",
Message = s
});
}
SbLogger.Debug(s);
}
public void Warn(string? s)
{
if (s == null)
return;
lock (Messages)
{
Messages.Add(new()
{
Level = "warn",
Message = s
});
}
SbLogger.Warn(s);
}
public void Error(string? s)
{
if (s == null)
return;
lock (Messages)
{
Messages.Add(new()
{
Level = "error",
Message = s
});
}
SbLogger.Error(s);
}
public void Fatal(string? s)
{
if (s == null)
return;
lock (Messages)
{
Messages.Add(new()
{
Level = "fatal",
Message = s
});
}
SbLogger.Fatal(s);
}
public void InfoEx(Exception ex)
{
lock (Messages)
{
Messages.Add(new()
{
Level = "info",
Message = ex.ToStringDemystified()
});
}
SbLogger.InfoEx(ex);
}
public void DebugEx(Exception ex)
{
lock (Messages)
{
Messages.Add(new()
{
Level = "debug",
Message = ex.ToStringDemystified()
});
}
SbLogger.DebugEx(ex);
}
public void WarnEx(Exception ex)
{
lock (Messages)
{
Messages.Add(new()
{
Level = "warn",
Message = ex.ToStringDemystified()
});
}
SbLogger.WarnEx(ex);
}
public void ErrorEx(Exception ex)
{
lock (Messages)
{
Messages.Add(new()
{
Level = "error",
Message = ex.ToStringDemystified()
});
}
SbLogger.ErrorEx(ex);
}
public void FatalEx(Exception ex)
{
lock (Messages)
{
Messages.Add(new()
{
Level = "fatal",
Message = ex.ToStringDemystified()
});
}
SbLogger.FatalEx(ex);
}
public LoggingConfiguration GetErrorConfiguration()
{
return SbLogger.GetErrorConfiguration();
}
public void SetErrorConfiguration(LoggingConfiguration configuration)
{
SbLogger.SetErrorConfiguration(configuration);
}
public LoggingConfiguration GetFatalConfiguration()
{
return SbLogger.GetFatalConfiguration();
}
public void SetFatalConfiguration(LoggingConfiguration configuration)
{
SbLogger.SetFatalConfiguration(configuration);
}
public LoggingConfiguration GetWarnConfiguration()
{
return SbLogger.GetWarnConfiguration();
}
public void SetWarnConfiguration(LoggingConfiguration configuration)
{
SbLogger.SetWarnConfiguration(configuration);
}
public LoggingConfiguration GetInfoConfiguration()
{
return SbLogger.GetInfoConfiguration();
}
public void SetInfoConfiguration(LoggingConfiguration configuration)
{
SbLogger.SetInfoConfiguration(configuration);
}
public LoggingConfiguration GetDebugConfiguration()
{
return SbLogger.GetDebugConfiguration();
}
public void SetDebugConfiguration(LoggingConfiguration configuration)
{
SbLogger.SetDebugConfiguration(configuration);
}
public ILoggingAddition GetAddition()
{
return SbLogger.GetAddition();
}
public void SetAddition(ILoggingAddition addition)
{
SbLogger.SetAddition(addition);
}
public bool LogCallingClass
{
get => SbLogger.LogCallingClass;
set => SbLogger.LogCallingClass = value;
}
}

View File

@@ -0,0 +1,12 @@
using Microsoft.AspNetCore.Components;
namespace Moonlight.App.Helpers;
public class ComponentHelper
{
public static RenderFragment FromType(Type type) => builder =>
{
builder.OpenComponent(0, type);
builder.CloseComponent();
};
}

View File

@@ -1,5 +1,4 @@
using System.Diagnostics;
using Logging.Net;
using Microsoft.EntityFrameworkCore;
using Moonlight.App.Database;
using Moonlight.App.Services;
@@ -45,8 +44,19 @@ public class DatabaseCheckupService
if (migrations.Any())
{
Logger.Info($"{migrations.Length} migrations pending. Updating now");
await BackupDatabase();
try
{
var backupHelper = new BackupHelper();
await backupHelper.CreateBackup(
PathBuilder.File("storage", "backups", $"{new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds()}.zip"));
}
catch (Exception e)
{
Logger.Fatal("Unable to create backup");
Logger.Fatal(e);
Logger.Fatal("Moonlight will continue to start and apply the migrations without a backup");
}
Logger.Info("Applying migrations");
@@ -59,42 +69,4 @@ public class DatabaseCheckupService
Logger.Info("Database is up-to-date. No migrations have been performed");
}
}
public async Task BackupDatabase()
{
Logger.Info("Creating backup from database");
var configService = new ConfigService(new StorageService());
var dateTimeService = new DateTimeService();
var config = configService
.GetSection("Moonlight")
.GetSection("Database");
var connectionString = $"host={config.GetValue<string>("Host")};" +
$"port={config.GetValue<int>("Port")};" +
$"database={config.GetValue<string>("Database")};" +
$"uid={config.GetValue<string>("Username")};" +
$"pwd={config.GetValue<string>("Password")}";
string file = PathBuilder.File("storage", "backups", $"{dateTimeService.GetCurrentUnix()}-mysql.sql");
Logger.Info($"Saving it to: {file}");
Logger.Info("Starting backup...");
var sw = new Stopwatch();
sw.Start();
await using MySqlConnection conn = new MySqlConnection(connectionString);
await using MySqlCommand cmd = new MySqlCommand();
using MySqlBackup mb = new MySqlBackup(cmd);
cmd.Connection = conn;
await conn.OpenAsync();
mb.ExportToFile(file);
await conn.CloseAsync();
sw.Stop();
Logger.Info($"Done. {sw.Elapsed.TotalSeconds}s");
}
}

View File

@@ -0,0 +1,71 @@
using System.Text;
using Moonlight.App.Database.Entities;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Moonlight.App.Helpers;
public static class EggConverter
{
public static Image Convert(string json)
{
var result = new Image();
var data = new ConfigurationBuilder().AddJsonStream(
new MemoryStream(Encoding.ASCII.GetBytes(json))
).Build();
result.Allocations = 1;
result.Description = data.GetValue<string>("description") ?? "";
result.Uuid = Guid.NewGuid();
result.Startup = data.GetValue<string>("startup") ?? "";
result.Name = data.GetValue<string>("name") ?? "Ptero Egg";
foreach (var variable in data.GetSection("variables").GetChildren())
{
result.Variables.Add(new()
{
Key = variable.GetValue<string>("env_variable") ?? "",
DefaultValue = variable.GetValue<string>("default_value") ?? ""
});
}
var configData = data.GetSection("config");
result.ConfigFiles = configData.GetValue<string>("files") ?? "{}";
var dImagesData = JObject.Parse(json);
var dImages = (JObject)dImagesData["docker_images"]!;
foreach (var dockerImage in dImages)
{
var di = new DockerImage()
{
Default = dockerImage.Key == dImages.Properties().Last().Name,
Name = dockerImage.Value!.ToString()
};
result.DockerImages.Add(di);
}
var installSection = data.GetSection("scripts").GetSection("installation");
result.InstallEntrypoint = installSection.GetValue<string>("entrypoint") ?? "bash";
result.InstallScript = installSection.GetValue<string>("script") ?? "";
result.InstallDockerImage = installSection.GetValue<string>("container") ?? "";
var rawJson = configData.GetValue<string>("startup");
var startupData = new ConfigurationBuilder().AddJsonStream(
new MemoryStream(Encoding.ASCII.GetBytes(rawJson!))
).Build();
result.StartupDetection = startupData.GetValue<string>("done", "") ?? "";
result.StopCommand = configData.GetValue<string>("stop") ?? "";
result.TagsJson = "[]";
result.BackgroundImageUrl = "";
return result;
}
}

View File

@@ -1,5 +1,4 @@
using Logging.Net;
using Renci.SshNet;
using Renci.SshNet;
using ConnectionInfo = Renci.SshNet.ConnectionInfo;
namespace Moonlight.App.Helpers.Files;

View File

@@ -43,19 +43,22 @@ public class WingsFileAccess : FileAccess
$"api/servers/{Server.Uuid}/files/list-directory?directory={CurrentPath}"
);
var x = new List<FileData>();
var result = new List<FileData>();
foreach (var response in res)
foreach (var resGrouped in res.GroupBy(x => x.Directory))
{
x.Add(new()
foreach (var resItem in resGrouped.OrderBy(x => x.Name))
{
Name = response.Name,
Size = response.File ? response.Size : 0,
IsFile = response.File,
});
result.Add(new()
{
Name = resItem.Name,
Size = resItem.File ? resItem.Size : 0,
IsFile = resItem.File,
});
}
}
return x.ToArray();
return result.ToArray();
}
public override Task Cd(string dir)
@@ -111,7 +114,7 @@ public class WingsFileAccess : FileAccess
request.AddParameter("name", "files");
request.AddParameter("filename", name);
request.AddHeader("Content-Type", "multipart/form-data");
request.AddHeader("Origin", ConfigService.GetSection("Moonlight").GetValue<string>("AppUrl"));
request.AddHeader("Origin", ConfigService.Get().Moonlight.AppUrl);
request.AddFile("files", () =>
{
return new StreamProgressHelper(dataStream)

View File

@@ -1,9 +1,37 @@
using Moonlight.App.Services;
using System.Text;
using Microsoft.AspNetCore.Components;
using Moonlight.App.Services;
namespace Moonlight.App.Helpers;
public static class Formatter
{
public static string ReplaceEnd(string input, string substringToReplace, string newSubstring)
{
int lastIndexOfSubstring = input.LastIndexOf(substringToReplace);
if (lastIndexOfSubstring >= 0)
{
input = input.Remove(lastIndexOfSubstring, substringToReplace.Length).Insert(lastIndexOfSubstring, newSubstring);
}
return input;
}
public static string ConvertCamelCaseToSpaces(string input)
{
StringBuilder output = new StringBuilder();
foreach (char c in input)
{
if (char.IsUpper(c))
{
output.Append(' ');
}
output.Append(c);
}
return output.ToString().Trim();
}
public static string FormatUptime(double uptime)
{
TimeSpan t = TimeSpan.FromMilliseconds(uptime);
@@ -128,12 +156,22 @@ public static class Formatter
return (i / (1024D * 1024D)).Round(2) + " GB";
}
}
public static double BytesToGb(long bytes)
{
const double gbMultiplier = 1024 * 1024 * 1024; // 1 GB = 1024 MB * 1024 KB * 1024 B
double gigabytes = (double)bytes / gbMultiplier;
return gigabytes;
public static RenderFragment FormatLineBreaks(string content)
{
return builder =>
{
int i = 0;
var arr = content.Split("\n", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
foreach (var line in arr)
{
builder.AddContent(i, line);
if (i++ != arr.Length - 1)
{
builder.AddMarkupContent(i, "<br/>");
}
}
};
}
}

View File

@@ -1,6 +1,5 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
using Logging.Net;
namespace Moonlight.App.Helpers;

View File

@@ -0,0 +1,171 @@
using System.Diagnostics;
using System.Reflection;
using Moonlight.App.Database;
using Moonlight.App.Services;
using Moonlight.App.Services.Files;
using Serilog;
namespace Moonlight.App.Helpers;
public static class Logger
{
// The private static instance of the config service, because we have no di here
private static ConfigService ConfigService = new(new StorageService());
#region String method calls
public static void Verbose(string message, string channel = "default")
{
Log.ForContext("SourceContext", GetNameOfCallingClass())
.Verbose("{Message}", message);
if(channel == "security")
LogSecurityInDb(message);
}
public static void Info(string message, string channel = "default")
{
Log.ForContext("SourceContext", GetNameOfCallingClass())
.Information("{Message}", message);
if(channel == "security")
LogSecurityInDb(message);
}
public static void Debug(string message, string channel = "default")
{
Log.ForContext("SourceContext", GetNameOfCallingClass())
.Debug("{Message}", message);
if(channel == "security")
LogSecurityInDb(message);
}
public static void Error(string message, string channel = "default")
{
Log.ForContext("SourceContext", GetNameOfCallingClass())
.Error("{Message}", message);
if(channel == "security")
LogSecurityInDb(message);
}
public static void Warn(string message, string channel = "default")
{
Log.ForContext("SourceContext", GetNameOfCallingClass())
.Warning("{Message}", message);
if(channel == "security")
LogSecurityInDb(message);
}
public static void Fatal(string message, string channel = "default")
{
Log.ForContext("SourceContext", GetNameOfCallingClass())
.Fatal("{Message}", message);
if(channel == "security")
LogSecurityInDb(message);
}
#endregion
#region Exception method calls
public static void Verbose(Exception exception, string channel = "default")
{
Log.ForContext("SourceContext", GetNameOfCallingClass())
.Verbose(exception, "");
if(channel == "security")
LogSecurityInDb(exception);
}
public static void Info(Exception exception, string channel = "default")
{
Log.ForContext("SourceContext", GetNameOfCallingClass())
.Information(exception, "");
if(channel == "security")
LogSecurityInDb(exception);
}
public static void Debug(Exception exception, string channel = "default")
{
Log.ForContext("SourceContext", GetNameOfCallingClass())
.Debug(exception, "");
if(channel == "security")
LogSecurityInDb(exception);
}
public static void Error(Exception exception, string channel = "default")
{
Log.ForContext("SourceContext", GetNameOfCallingClass())
.Error(exception, "");
if(channel == "security")
LogSecurityInDb(exception);
}
public static void Warn(Exception exception, string channel = "default")
{
Log.ForContext("SourceContext", GetNameOfCallingClass())
.Warning(exception, "");
if(channel == "security")
LogSecurityInDb(exception);
}
public static void Fatal(Exception exception, string channel = "default")
{
Log.ForContext("SourceContext", GetNameOfCallingClass())
.Fatal(exception, "");
if(channel == "security")
LogSecurityInDb(exception);
}
#endregion
private static string GetNameOfCallingClass(int skipFrames = 4)
{
string fullName;
Type declaringType;
do
{
MethodBase method = new StackFrame(skipFrames, false).GetMethod();
declaringType = method.DeclaringType;
if (declaringType == null)
{
return method.Name;
}
skipFrames++;
if (declaringType.Name.Contains("<"))
fullName = declaringType.ReflectedType.Name;
else
fullName = declaringType.Name;
}
while (declaringType.Module.Name.Equals("mscorlib.dll", StringComparison.OrdinalIgnoreCase) | fullName.Contains("Logger"));
return fullName;
}
private static void LogSecurityInDb(Exception exception)
{
LogSecurityInDb(exception.ToStringDemystified());
}
private static void LogSecurityInDb(string text)
{
Task.Run(() =>
{
var dataContext = new DataContext(ConfigService);
dataContext.SecurityLogs.Add(new()
{
Text = text
});
dataContext.SaveChanges();
dataContext.Dispose();
});
}
}

View File

@@ -1,5 +1,4 @@
using System.ComponentModel.DataAnnotations;
using Logging.Net;
namespace Moonlight.App.Helpers;

View File

@@ -1,6 +1,4 @@
using Logging.Net;
namespace Moonlight.App.Helpers;
namespace Moonlight.App.Helpers;
public static class ParseHelper
{

View File

@@ -0,0 +1,51 @@
using System.Reflection;
namespace Moonlight.App.Helpers;
public class PropBinder
{
private PropertyInfo PropertyInfo;
private object DataObject;
public PropBinder(PropertyInfo propertyInfo, object dataObject)
{
PropertyInfo = propertyInfo;
DataObject = dataObject;
}
public string StringValue
{
get => (string)PropertyInfo.GetValue(DataObject)!;
set => PropertyInfo.SetValue(DataObject, value);
}
public int IntValue
{
get => (int)PropertyInfo.GetValue(DataObject)!;
set => PropertyInfo.SetValue(DataObject, value);
}
public long LongValue
{
get => (long)PropertyInfo.GetValue(DataObject)!;
set => PropertyInfo.SetValue(DataObject, value);
}
public bool BoolValue
{
get => (bool)PropertyInfo.GetValue(DataObject)!;
set => PropertyInfo.SetValue(DataObject, value);
}
public DateTime DateTimeValue
{
get => (DateTime)PropertyInfo.GetValue(DataObject)!;
set => PropertyInfo.SetValue(DataObject, value);
}
public double DoubleValue
{
get => (double)PropertyInfo.GetValue(DataObject)!;
set => PropertyInfo.SetValue(DataObject, value);
}
}

View File

@@ -0,0 +1,66 @@
namespace Moonlight.App.Helpers;
public class Retry
{
private List<Type> RetryExceptionTypes;
private List<Func<Exception, bool>> RetryFilters;
private int RetryTimes = 1;
public Retry()
{
RetryExceptionTypes = new();
RetryFilters = new();
}
public Retry Times(int times)
{
RetryTimes = times;
return this;
}
public Retry At(Func<Exception, bool> filter)
{
RetryFilters.Add(filter);
return this;
}
public Retry At<T>()
{
RetryExceptionTypes.Add(typeof(T));
return this;
}
public async Task Call(Func<Task> method)
{
int triesLeft = RetryTimes;
do
{
try
{
await method.Invoke();
return;
}
catch (Exception e)
{
if(triesLeft < 1) // Throw if no tries left
throw;
if (RetryExceptionTypes.Any(x => x.FullName == e.GetType().FullName))
{
triesLeft--;
continue;
}
if (RetryFilters.Any(x => x.Invoke(e)))
{
triesLeft--;
continue;
}
// Throw if not filtered -> unknown/unhandled
throw;
}
} while (triesLeft >= 0);
}
}

View File

@@ -43,4 +43,15 @@ public static class StringHelper
return firstChar + restOfString;
}
public static string CutInHalf(string input)
{
if (string.IsNullOrEmpty(input))
return input;
int length = input.Length;
int halfLength = length / 2;
return input.Substring(0, halfLength);
}
}

View File

@@ -1,6 +1,5 @@
using System.Net.WebSockets;
using System.Text;
using Logging.Net;
using Moonlight.App.Helpers.Wings.Data;
using Moonlight.App.Helpers.Wings.Enums;
using Moonlight.App.Helpers.Wings.Events;
@@ -243,6 +242,8 @@ public class WingsConsole : IDisposable
break;
}
}
catch(JsonReaderException){}
catch(JsonSerializationException){}
catch (Exception e)
{
if (!Disconnecting)

View File

@@ -20,7 +20,7 @@ public class WingsConsoleHelper
{
ServerRepository = serverRepository;
AppUrl = configService.GetSection("Moonlight").GetValue<string>("AppUrl");
AppUrl = configService.Get().Moonlight.AppUrl;
}
public async Task ConnectWings(WingsConsole console, Server server)

View File

@@ -15,7 +15,7 @@ public class WingsJwtHelper
{
ConfigService = configService;
AppUrl = ConfigService.GetSection("Moonlight").GetValue<string>("AppUrl");
AppUrl = ConfigService.Get().Moonlight.AppUrl;
}
public string Generate(string secret, Action<Dictionary<string, string>> claimsAction)

View File

@@ -25,7 +25,7 @@ public class AvatarController : Controller
try
{
var url = GravatarController.GetImageUrl(user.Email, 100);
var url = GravatarController.GetImageUrl(user.Email.ToLower(), 100);
using var client = new HttpClient();
var res = await client.GetByteArrayAsync(url);

View File

@@ -0,0 +1,47 @@
using Microsoft.AspNetCore.Mvc;
using Moonlight.App.Services;
using Moonlight.App.Services.Sessions;
using Stripe;
using Stripe.Checkout;
namespace Moonlight.App.Http.Controllers.Api.Moonlight;
[ApiController]
[Route("api/moonlight/billing")]
public class BillingController : Controller
{
private readonly IdentityService IdentityService;
private readonly BillingService BillingService;
public BillingController(
IdentityService identityService,
BillingService billingService)
{
IdentityService = identityService;
BillingService = billingService;
}
[HttpGet("cancel")]
public async Task<ActionResult> Cancel()
{
var user = IdentityService.User;
if (user == null)
return Redirect("/login");
return Redirect("/profile/subscriptions/close");
}
[HttpGet("success")]
public async Task<ActionResult> Success()
{
var user = IdentityService.User;
if (user == null)
return Redirect("/login");
await BillingService.CompleteCheckout(user);
return Redirect("/profile/subscriptions/close");
}
}

View File

@@ -30,14 +30,14 @@ public class DiscordBotController : Controller
ServerService = serverService;
var config = configService
.GetSection("Moonlight")
.GetSection("DiscordBotApi");
.Get()
.Moonlight.DiscordBotApi;
Enable = config.GetValue<bool>("Enable");
Enable = config.Enable;
if (Enable)
{
Token = config.GetValue<string>("Token");
Token = config.Token;
}
}
@@ -102,7 +102,7 @@ public class DiscordBotController : Controller
return BadRequest();
}
[HttpGet("{id}/servers/{uuid}")]
[HttpGet("{id}/servers/{uuid}/details")]
public async Task<ActionResult<ServerDetails>> GetServerDetails(ulong id, Guid uuid)
{
if (!await IsAuth(Request))
@@ -123,6 +123,33 @@ public class DiscordBotController : Controller
return await ServerService.GetDetails(server);
}
[HttpGet("{id}/servers/{uuid}")]
public async Task<ActionResult<ServerDetails>> GetServer(ulong id, Guid uuid)
{
if (!await IsAuth(Request))
return StatusCode(403);
var user = await GetUserFromDiscordId(id);
if (user == null)
return BadRequest();
var server = ServerRepository
.Get()
.Include(x => x.Owner)
.Include(x => x.Image)
.Include(x => x.Node)
.FirstOrDefault(x => x.Owner.Id == user.Id && x.Uuid == uuid);
if (server == null)
return NotFound();
server.Node.Token = "";
server.Node.TokenId = "";
return Ok(server);
}
private Task<User?> GetUserFromDiscordId(ulong discordId)
{

View File

@@ -2,145 +2,166 @@
using System.Text;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Moonlight.App.Database.Entities;
using Moonlight.App.Database.Entities.Notification;
using Moonlight.App.Models.Notifications;
using Moonlight.App.Repositories;
using Moonlight.App.Services;
using Moonlight.App.Services.Notifications;
using Moonlight.App.Services.Sessions;
using Newtonsoft.Json;
namespace Moonlight.App.Http.Controllers.Api.Moonlight.Notifications;
public class ListenController : ControllerBase
[ApiController]
[Route("api/moonlight/notification/listen")]
public class ListenController : Controller
{
internal WebSocket ws;
private bool active = true;
private bool isAuth = false;
private WebSocket WebSocket;
private NotificationClient Client;
private readonly IdentityService IdentityService;
private readonly NotificationRepository NotificationRepository;
private readonly OneTimeJwtService OneTimeJwtService;
private readonly NotificationClientService NotificationClientService;
private readonly NotificationServerService NotificationServerService;
private CancellationTokenSource CancellationTokenSource = new();
public ListenController(IdentityService identityService,
NotificationRepository notificationRepository,
OneTimeJwtService oneTimeJwtService,
NotificationClientService notificationClientService,
NotificationServerService notificationServerService)
private User? CurrentUser;
private readonly OneTimeJwtService OneTimeJwtService;
private readonly NotificationServerService NotificationServerService;
private readonly Repository<NotificationClient> NotificationClientRepository;
public ListenController(
OneTimeJwtService oneTimeJwtService,
NotificationServerService notificationServerService, Repository<NotificationClient> notificationClientRepository)
{
IdentityService = identityService;
NotificationRepository = notificationRepository;
OneTimeJwtService = oneTimeJwtService;
NotificationClientService = notificationClientService;
NotificationServerService = notificationServerService;
NotificationClientRepository = notificationClientRepository;
}
[Route("/api/moonlight/notifications/listen")]
public async Task Get()
public async Task<ActionResult> Get()
{
if (HttpContext.WebSockets.IsWebSocketRequest)
{
using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
ws = webSocket;
await Echo();
WebSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
await ProcessWebsocket();
return new EmptyResult();
}
else
{
HttpContext.Response.StatusCode = StatusCodes.Status403Forbidden;
return StatusCode(400);
}
}
private async Task Echo()
private async Task ProcessWebsocket()
{
while (active)
while (!CancellationTokenSource.Token.IsCancellationRequested && WebSocket.State == WebSocketState.Open)
{
byte[] bytes = new byte[1024 * 16];
var asg = new ArraySegment<byte>(bytes);
var res = await ws.ReceiveAsync(asg, CancellationToken.None);
var text = Encoding.UTF8.GetString(bytes).Trim('\0');
var obj = JsonConvert.DeserializeObject<BasicWSModel>(text);
if (!string.IsNullOrWhiteSpace(obj.Action))
try
{
await HandleRequest(text, obj.Action);
byte[] buffer = new byte[1024 * 16];
_ = await WebSocket.ReceiveAsync(buffer, CancellationTokenSource.Token);
var text = Encoding.UTF8.GetString(buffer).Trim('\0');
var basicWsModel = JsonConvert.DeserializeObject<BasicWSModel>(text) ?? new();
if (!string.IsNullOrWhiteSpace(basicWsModel.Action))
{
await HandleRequest(text, basicWsModel.Action);
}
if (WebSocket.State != WebSocketState.Open)
{
CancellationTokenSource.Cancel();
}
}
catch (WebSocketException e)
{
CancellationTokenSource.Cancel();
}
active = ws.State == WebSocketState.Open;
}
await NotificationServerService.UnRegisterClient(Client);
}
private async Task HandleRequest(string text, string action)
{
if (!isAuth && action == "login")
await Login(text);
else if (!isAuth)
await ws.SendAsync(Encoding.UTF8.GetBytes("{\"error\": \"Unauthorised\"}"), WebSocketMessageType.Text,
WebSocketMessageFlags.EndOfMessage, CancellationToken.None);
else switch (action)
if (CurrentUser == null && action != "login")
{
await Send("{\"error\": \"Unauthorised\"}");
}
switch (action)
{
case "login":
await Login(text);
break;
case "received":
await Received(text);
break;
case "read":
await Read(text);
break;
default:
break;
}
}
private async Task Send(string text)
{
await WebSocket.SendAsync(
Encoding.UTF8.GetBytes(text),
WebSocketMessageType.Text,
WebSocketMessageFlags.EndOfMessage, CancellationTokenSource.Token
);
}
private async Task Login(string json)
{
var jwt = JsonConvert.DeserializeObject<Login>(json).token;
var dict = await OneTimeJwtService.Validate(jwt);
var loginModel = JsonConvert.DeserializeObject<Login>(json) ?? new();
var dict = await OneTimeJwtService.Validate(loginModel.Token);
if (dict == null)
{
string error = "{\"status\":false}";
var bytes = Encoding.UTF8.GetBytes(error);
await ws.SendAsync(bytes, WebSocketMessageType.Text, WebSocketMessageFlags.EndOfMessage, CancellationToken.None);
await Send("{\"status\":false}");
return;
}
var _clientId = dict["clientId"];
var clientId = int.Parse(_clientId);
if (!int.TryParse(dict["clientId"], out int clientId))
{
await Send("{\"status\":false}");
return;
}
var client = NotificationRepository.GetClients().Include(x => x.User).First(x => x.Id == clientId);
Client = NotificationClientRepository
.Get()
.Include(x => x.User)
.First(x => x.Id == clientId);
Client = client;
await InitWebsocket();
string success = "{\"status\":true}";
var byt = Encoding.UTF8.GetBytes(success);
await ws.SendAsync(byt, WebSocketMessageType.Text, WebSocketMessageFlags.EndOfMessage, CancellationToken.None);
}
CurrentUser = Client.User;
private async Task InitWebsocket()
{
NotificationClientService.listenController = this;
NotificationClientService.WebsocketReady(Client);
await NotificationServerService.RegisterClient(WebSocket, Client);
isAuth = true;
await Send("{\"status\":true}");
}
private async Task Received(string json)
{
var id = JsonConvert.DeserializeObject<NotificationById>(json).notification;
var id = JsonConvert.DeserializeObject<NotificationById>(json).Notification;
//TODO: Implement ws notification received
}
private async Task Read(string json)
{
var id = JsonConvert.DeserializeObject<NotificationById>(json).notification;
var model = JsonConvert.DeserializeObject<NotificationById>(json) ?? new();
await NotificationServerService.SendAction(NotificationClientService.User,
JsonConvert.SerializeObject(new NotificationById() {Action = "hide", notification = id}));
await NotificationServerService.SendAction(
CurrentUser!,
JsonConvert.SerializeObject(
new NotificationById()
{
Action = "hide", Notification = model.Notification
}
)
);
}
}

View File

@@ -25,7 +25,7 @@ public class RegisterController : Controller
[HttpGet]
public async Task<ActionResult<TokenRegister>> Register()
{
var user = await IdentityService.Get();
var user = IdentityService.User;
if (user == null)
return NotFound();

View File

@@ -1,5 +1,5 @@
using Logging.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc;
using Moonlight.App.Helpers;
using Moonlight.App.Services;
using Moonlight.App.Services.Sessions;
@@ -54,7 +54,7 @@ public class OAuth2Controller : Controller
{
try
{
var currentUser = await IdentityService.Get();
var currentUser = IdentityService.User;
if (currentUser != null)
{

View File

@@ -1,12 +1,6 @@
using System.Text;
using Logging.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc;
using Moonlight.App.Helpers;
using Moonlight.App.Models.Misc;
using Moonlight.App.Services;
using Moonlight.App.Services.Files;
using Moonlight.App.Services.LogServices;
using Moonlight.App.Services.Sessions;
namespace Moonlight.App.Http.Controllers.Api.Moonlight;
@@ -14,13 +8,10 @@ namespace Moonlight.App.Http.Controllers.Api.Moonlight;
[Route("api/moonlight/resources")]
public class ResourcesController : Controller
{
private readonly SecurityLogService SecurityLogService;
private readonly BucketService BucketService;
public ResourcesController(SecurityLogService securityLogService,
BucketService bucketService)
public ResourcesController(BucketService bucketService)
{
SecurityLogService = securityLogService;
BucketService = bucketService;
}
@@ -29,10 +20,7 @@ public class ResourcesController : Controller
{
if (name.Contains(".."))
{
await SecurityLogService.Log(SecurityLogType.PathTransversal, x =>
{
x.Add<string>(name);
});
Logger.Warn($"Detected an attempted path transversal. Path: {name}", "security");
return NotFound();
}
@@ -52,10 +40,7 @@ public class ResourcesController : Controller
{
if (name.Contains(".."))
{
await SecurityLogService.Log(SecurityLogType.PathTransversal, x =>
{
x.Add<string>(name);
});
Logger.Warn($"Detected an attempted path transversal. Path: {name}", "security");
return NotFound();
}
@@ -75,10 +60,7 @@ public class ResourcesController : Controller
{
if (name.Contains(".."))
{
await SecurityLogService.Log(SecurityLogType.PathTransversal, x =>
{
x.Add<string>(name);
});
Logger.Warn($"Detected an attempted path transversal. Path: {name}", "security");
return NotFound();
}

View File

@@ -1,10 +1,9 @@
using Logging.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc;
using Moonlight.App.Database.Entities;
using Moonlight.App.Events;
using Moonlight.App.Http.Requests.Daemon;
using Moonlight.App.Repositories;
using Moonlight.App.Services;
using Moonlight.App.Services.Background;
namespace Moonlight.App.Http.Controllers.Api.Remote;
@@ -12,19 +11,17 @@ namespace Moonlight.App.Http.Controllers.Api.Remote;
[Route("api/remote/ddos")]
public class DdosController : Controller
{
private readonly NodeRepository NodeRepository;
private readonly EventSystem Event;
private readonly DdosAttackRepository DdosAttackRepository;
private readonly Repository<Node> NodeRepository;
private readonly DdosProtectionService DdosProtectionService;
public DdosController(NodeRepository nodeRepository, EventSystem eventSystem, DdosAttackRepository ddosAttackRepository)
public DdosController(Repository<Node> nodeRepository, DdosProtectionService ddosProtectionService)
{
NodeRepository = nodeRepository;
Event = eventSystem;
DdosAttackRepository = ddosAttackRepository;
DdosProtectionService = ddosProtectionService;
}
[HttpPost("update")]
public async Task<ActionResult> Update([FromBody] DdosStatus ddosStatus)
[HttpPost("start")]
public async Task<ActionResult> Start([FromBody] DdosStart ddosStart)
{
var tokenData = Request.Headers.Authorization.ToString().Replace("Bearer ", "");
var id = tokenData.Split(".")[0];
@@ -37,18 +34,26 @@ public class DdosController : Controller
if (token != node.Token)
return Unauthorized();
await DdosProtectionService.ProcessDdosSignal(ddosStart.Ip, ddosStart.Packets);
return Ok();
}
var ddosAttack = new DdosAttack()
{
Ongoing = ddosStatus.Ongoing,
Data = ddosStatus.Data,
Ip = ddosStatus.Ip,
Node = node
};
[HttpPost("stop")]
public async Task<ActionResult> Stop([FromBody] DdosStop ddosStop)
{
var tokenData = Request.Headers.Authorization.ToString().Replace("Bearer ", "");
var id = tokenData.Split(".")[0];
var token = tokenData.Split(".")[1];
ddosAttack = DdosAttackRepository.Add(ddosAttack);
var node = NodeRepository.Get().FirstOrDefault(x => x.TokenId == id);
await Event.Emit("node.ddos", ddosAttack);
if (node == null)
return NotFound();
if (token != node.Token)
return Unauthorized();
return Ok();
}

View File

@@ -0,0 +1,7 @@
namespace Moonlight.App.Http.Requests.Daemon;
public class DdosStart
{
public string Ip { get; set; } = "";
public long Packets { get; set; }
}

View File

@@ -1,8 +0,0 @@
namespace Moonlight.App.Http.Requests.Daemon;
public class DdosStatus
{
public bool Ongoing { get; set; }
public long Data { get; set; }
public string Ip { get; set; } = "";
}

View File

@@ -0,0 +1,7 @@
namespace Moonlight.App.Http.Requests.Daemon;
public class DdosStop
{
public string Ip { get; set; } = "";
public long Traffic { get; set; }
}

View File

@@ -1,5 +1,4 @@
using Logging.Net;
using ILogger = Microsoft.Extensions.Logging.ILogger;
using Moonlight.App.Helpers;
namespace Moonlight.App.LogMigrator;
@@ -28,19 +27,39 @@ public class LogMigrator : ILogger
switch (logLevel)
{
case LogLevel.Critical:
Logger.Fatal($"[{Name}] {formatter(state, exception)}");
Logger.Fatal(formatter(state, exception));
if(exception != null)
Logger.Fatal(exception);
break;
case LogLevel.Warning:
Logger.Warn($"[{Name}] {formatter(state, exception)}");
Logger.Warn(formatter(state, exception));
if(exception != null)
Logger.Warn(exception);
break;
case LogLevel.Debug:
Logger.Debug($"[{Name}] {formatter(state, exception)}");
Logger.Debug(formatter(state, exception));
if(exception != null)
Logger.Debug(exception);
break;
case LogLevel.Error:
Logger.Error($"[{Name}] {formatter(state, exception)}");
Logger.Error(formatter(state, exception));
if(exception != null)
Logger.Error(exception);
break;
case LogLevel.Information:
Logger.Info($"[{Name}] {formatter(state, exception)}");
Logger.Info(formatter(state, exception));
if(exception != null)
Logger.Info(exception);
break;
}
}

View File

@@ -0,0 +1,71 @@
using Moonlight.App.Helpers;
using Sentry;
using Sentry.Extensibility;
namespace Moonlight.App.LogMigrator;
public class SentryDiagnosticsLogger : IDiagnosticLogger
{
private readonly SentryLevel Level;
public SentryDiagnosticsLogger(SentryLevel level)
{
Level = level;
}
public bool IsEnabled(SentryLevel level)
{
if ((int)level >= (int)Level)
{
return true;
}
return false;
}
public void Log(SentryLevel logLevel, string message, Exception? exception = null, params object?[] args)
{
switch (logLevel)
{
case SentryLevel.Debug:
Logger.Debug(string.Format(message, args));
if(exception != null)
Logger.Debug(exception);
break;
case SentryLevel.Info:
Logger.Info(string.Format(message, args));
if(exception != null)
Logger.Info(exception);
break;
case SentryLevel.Warning:
Logger.Warn(string.Format(message, args));
if(exception != null)
Logger.Warn(exception);
break;
case SentryLevel.Error:
Logger.Error(string.Format(message, args));
if(exception != null)
Logger.Error(exception);
break;
case SentryLevel.Fatal:
Logger.Fatal(string.Format(message, args));
if(exception != null)
Logger.Fatal(exception);
break;
}
}
}

View File

@@ -0,0 +1,42 @@
using Moonlight.App.Database.Entities;
using Moonlight.App.Models.Misc;
using Moonlight.App.Services;
namespace Moonlight.App.MalwareScans;
public class FakePlayerPluginScan : MalwareScan
{
public override string Name => "Fake player plugin scan";
public override string Description => "This scan is a simple fake player plugin scan provided by moonlight";
public override async Task<MalwareScanResult[]> Scan(Server server, IServiceProvider serviceProvider)
{
var serverService = serviceProvider.GetRequiredService<ServerService>();
var access = await serverService.CreateFileAccess(server, null!);
var fileElements = await access.Ls();
if (fileElements.Any(x => !x.IsFile && x.Name == "plugins")) // Check for plugins folder
{
await access.Cd("plugins");
fileElements = await access.Ls();
foreach (var fileElement in fileElements)
{
if (fileElement.Name.ToLower().Contains("fakeplayer"))
{
return new[]
{
new MalwareScanResult
{
Title = "Fake player plugin",
Description = $"Suspicious plugin file: {fileElement.Name}",
Author = "Marcel Baumgartner"
}
};
}
}
}
return Array.Empty<MalwareScanResult>();
}
}

View File

@@ -0,0 +1,40 @@
using Moonlight.App.Database.Entities;
using Moonlight.App.Models.Misc;
using Moonlight.App.Services;
namespace Moonlight.App.MalwareScans;
public class MinerJarScan : MalwareScan
{
public override string Name => "Miner jar scan";
public override string Description => "This scan is a simple miner jar scan provided by moonlight";
public override async Task<MalwareScanResult[]> Scan(Server server, IServiceProvider serviceProvider)
{
var serverService = serviceProvider.GetRequiredService<ServerService>();
var access = await serverService.CreateFileAccess(server, null!);
var fileElements = await access.Ls();
if (fileElements.Any(x => x.Name == "libraries" && !x.IsFile))
{
await access.Cd("libraries");
fileElements = await access.Ls();
if (fileElements.Any(x => x.Name == "jdk" && !x.IsFile))
{
return new[]
{
new MalwareScanResult
{
Title = "Found Miner",
Description = "Detected suspicious library directory which may contain a script for miners",
Author = "Marcel Baumgartner"
}
};
}
}
return Array.Empty<MalwareScanResult>();
}
}

View File

@@ -0,0 +1,38 @@
using Moonlight.App.Database.Entities;
using Moonlight.App.Models.Misc;
using Moonlight.App.Services;
namespace Moonlight.App.MalwareScans;
public class SelfBotCodeScan : MalwareScan
{
public override string Name => "Selfbot code scan";
public override string Description => "This scan is a simple selfbot code scan provided by moonlight";
public override async Task<MalwareScanResult[]> Scan(Server server, IServiceProvider serviceProvider)
{
var serverService = serviceProvider.GetRequiredService<ServerService>();
var access = await serverService.CreateFileAccess(server, null!);
var fileElements = await access.Ls();
foreach (var script in fileElements.Where(x => x.Name.EndsWith(".py") && x.IsFile))
{
var rawScript = await access.Read(script);
if (rawScript.Contains("https://discord.com/api") && !rawScript.Contains("https://discord.com/api/oauth2") && !rawScript.Contains("https://discord.com/api/webhook") || rawScript.Contains("https://rblxwild.com")) //TODO: Export to plugins, add regex for checking
{
return new[]
{
new MalwareScanResult
{
Title = "Potential selfbot",
Description = $"Suspicious script file: {script.Name}",
Author = "Marcel Baumgartner"
}
};
}
}
return Array.Empty<MalwareScanResult>();
}
}

View File

@@ -0,0 +1,33 @@
using Moonlight.App.Database.Entities;
using Moonlight.App.Models.Misc;
using Moonlight.App.Services;
namespace Moonlight.App.MalwareScans;
public class SelfBotScan : MalwareScan
{
public override string Name => "Selfbot Scan";
public override string Description => "This scan is a simple selfbot scan provided by moonlight";
public override async Task<MalwareScanResult[]> Scan(Server server, IServiceProvider serviceProvider)
{
var serverService = serviceProvider.GetRequiredService<ServerService>();
var access = await serverService.CreateFileAccess(server, null!);
var fileElements = await access.Ls();
if (fileElements.Any(x => x.Name == "tokens.txt"))
{
return new[]
{
new MalwareScanResult
{
Title = "Found SelfBot",
Description = "Detected suspicious 'tokens.txt' file which may contain tokens for a selfbot",
Author = "Marcel Baumgartner"
}
};
}
return Array.Empty<MalwareScanResult>();
}
}

View File

@@ -0,0 +1,21 @@
using System.ComponentModel.DataAnnotations;
using Moonlight.App.Models.Misc;
namespace Moonlight.App.Models.Forms;
public class CreateTicketDataModel
{
[Required(ErrorMessage = "You need to specify a issue topic")]
[MinLength(5, ErrorMessage = "The issue topic needs to be longer than 5 characters")]
public string IssueTopic { get; set; }
[Required(ErrorMessage = "You need to specify a issue description")]
[MinLength(10, ErrorMessage = "The issue description needs to be longer than 10 characters")]
public string IssueDescription { get; set; }
[Required(ErrorMessage = "You need to specify your tries to solve this issue")]
public string IssueTries { get; set; }
public TicketSubject Subject { get; set; }
public int SubjectId { get; set; }
}

View File

@@ -0,0 +1,8 @@
namespace Moonlight.App.Models.Forms;
public class ServerImageDataModel
{
public string OverrideStartup { get; set; }
public int DockerImageIndex { get; set; }
}

View File

@@ -0,0 +1,14 @@
using System.ComponentModel.DataAnnotations;
using Moonlight.App.Database.Entities;
namespace Moonlight.App.Models.Forms;
public class ServerOverviewDataModel
{
[Required(ErrorMessage = "You need to enter a name")]
[MaxLength(32, ErrorMessage = "The name cannot be longer that 32 characters")]
public string Name { get; set; }
[Required(ErrorMessage = "You need to specify a owner")]
public User Owner { get; set; }
}

View File

@@ -0,0 +1,15 @@
using System.ComponentModel.DataAnnotations;
namespace Moonlight.App.Models.Forms;
public class ServerResourcesDataModel
{
[Required(ErrorMessage = "You need to specify the cpu cores")]
public int Cpu { get; set; }
[Required(ErrorMessage = "You need to specify the memory")]
public long Memory { get; set; }
[Required(ErrorMessage = "You need to specify the disk")]
public long Disk { get; set; }
}

View File

@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using Moonlight.App.Models.Misc;
namespace Moonlight.App.Models.Forms;
@@ -10,4 +11,8 @@ public class SubscriptionDataModel
[Required(ErrorMessage = "You need to enter a description")]
public string Description { get; set; } = "";
public double Price { get; set; } = 0;
public Currency Currency { get; set; } = Currency.USD;
public int Duration { get; set; } = 30;
}

View File

@@ -0,0 +1,34 @@
using System.ComponentModel.DataAnnotations;
using Moonlight.App.Database.Entities;
using Moonlight.App.Models.Misc;
namespace Moonlight.App.Models.Forms;
public class UserEditDataModel
{
[Required]
public string FirstName { get; set; } = "";
[Required]
public string LastName { get; set; } = "";
[Required]
public string Email { get; set; } = "";
[Required]
public string Address { get; set; } = "";
[Required]
public string City { get; set; } = "";
[Required]
public string State { get; set; } = "";
[Required]
public string Country { get; set; } = "";
public bool Admin { get; set; }
public bool TotpEnabled { get; set; }
public ulong DiscordId { get; set; }
public PermissionGroup? PermissionGroup { get; set; }
}

View File

@@ -0,0 +1,6 @@
namespace Moonlight.App.Models.Forms;
public class UserPreferencesDataModel
{
public bool StreamerMode { get; set; } = false;
}

View File

@@ -0,0 +1,19 @@
using System.Net.WebSockets;
using System.Text;
using Moonlight.App.Database.Entities.Notification;
namespace Moonlight.App.Models.Misc;
public class ActiveNotificationClient
{
public WebSocket WebSocket { get; set; }
public NotificationClient Client { get; set; }
public async Task SendAction(string action)
{
await WebSocket.SendAsync(
Encoding.UTF8.GetBytes(action),
WebSocketMessageType.Text,
WebSocketMessageFlags.EndOfMessage, CancellationToken.None);
}
}

View File

@@ -1,27 +0,0 @@
namespace Moonlight.App.Models.Misc;
public enum AuditLogType
{
Login,
Register,
ChangePassword,
ChangePowerState,
CreateBackup,
RestoreBackup,
DeleteBackup,
DownloadBackup,
CreateServer,
ReinstallServer,
CancelSubscription,
ApplySubscriptionCode,
EnableTotp,
DisableTotp,
AddDomainRecord,
UpdateDomainRecord,
DeleteDomainRecord,
PasswordReset,
CleanupEnabled,
CleanupDisabled,
CleanupTriggered,
PasswordChange,
}

View File

@@ -0,0 +1,7 @@
namespace Moonlight.App.Models.Misc;
public enum Currency
{
USD = 1,
EUR = 2
}

View File

@@ -0,0 +1,9 @@
using Moonlight.App.Helpers.Files;
namespace Moonlight.App.Models.Misc;
public class MailTemplate // This is just for the blazor table at /admin/system/mail
{
public string Name { get; set; } = "";
public FileData File { get; set; }
}

View File

@@ -0,0 +1,10 @@
using Moonlight.App.Database.Entities;
namespace Moonlight.App.Models.Misc;
public abstract class MalwareScan
{
public abstract string Name { get; }
public abstract string Description { get; }
public abstract Task<MalwareScanResult[]> Scan(Server server, IServiceProvider serviceProvider);
}

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