├── .editorconfig
├── .gitattributes
├── .github
├── ISSUE_TEMPLATE
│ ├── blacklist_appeal.yml
│ ├── bug_report.yml
│ ├── config.yml
│ ├── feature_request.yml
│ └── security_vulnerabilty.yml
└── workflows
│ ├── build.yml
│ ├── deploy.yml
│ └── docs.yml
├── .gitignore
├── .gitmodules
├── .vscode
├── launch.json
└── tasks.json
├── CODEOWNERS
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── SECURITY.md
├── docs
├── CNAME
├── assets
│ ├── logo.svg
│ └── theme.css
├── index.md
├── legal
│ ├── index.md
│ ├── privacy-policy.md
│ └── tos.md
├── overrides
│ ├── assets
│ │ └── stylesheets
│ │ │ └── main.css
│ └── main.html
└── request-data-deletion.md
├── mkdocs.yml
├── proto
└── grid_bot.proto
├── scripts
└── clean.sh
├── services
├── Directory.Build.props
├── Directory.Build.targets
├── grid-bot
│ ├── .component.yaml
│ ├── .dockerignore
│ ├── Dockerfile
│ ├── README.md
│ ├── grid-bot-bare.sln
│ ├── grid-bot.sln
│ ├── lib
│ │ ├── Directory.Build.props
│ │ ├── Directory.Build.targets
│ │ ├── commands
│ │ │ ├── Attributes
│ │ │ │ ├── LockDownCommandAttribute.cs
│ │ │ │ └── RequireCommandBotRoleAttribute.cs
│ │ │ ├── Modules
│ │ │ │ ├── Commands
│ │ │ │ │ ├── ExecuteScript.cs
│ │ │ │ │ ├── Help.cs
│ │ │ │ │ ├── Render.cs
│ │ │ │ │ └── Support.cs
│ │ │ │ └── Interactions
│ │ │ │ │ ├── ExecuteScript.cs
│ │ │ │ │ ├── Render.cs
│ │ │ │ │ └── Support.cs
│ │ │ ├── Monitoring
│ │ │ │ ├── RenderPerformanceCounters.cs
│ │ │ │ └── ScriptExecutionPerformanceCounters.cs
│ │ │ ├── PrivateModules
│ │ │ │ └── Commands
│ │ │ │ │ ├── ClientSettings.cs
│ │ │ │ │ ├── Maintenance.cs
│ │ │ │ │ ├── Roles.cs
│ │ │ │ │ └── Settings.cs
│ │ │ └── Shared.Commands.csproj
│ │ ├── events
│ │ │ ├── Events
│ │ │ │ ├── OnCommandExecuted.cs
│ │ │ │ ├── OnLogMessage.cs
│ │ │ │ ├── OnMessage.cs
│ │ │ │ ├── OnReady.cs
│ │ │ │ ├── OnSlashCommand.cs
│ │ │ │ └── OnSlashCommandExecuted.cs
│ │ │ └── Shared.Events.csproj
│ │ ├── grpc
│ │ │ ├── Extensions
│ │ │ │ └── IServiceProviderExtensions.cs
│ │ │ ├── Grid.Bot.Grpc.csproj
│ │ │ └── Implementation
│ │ │ │ └── GridBotGrpcServer.cs
│ │ ├── settings
│ │ │ ├── EnvironmentProvider.cs
│ │ │ ├── Providers
│ │ │ │ ├── AvatarSettings.cs
│ │ │ │ ├── BacktraceSettings.cs
│ │ │ │ ├── BaseSettingsProvider.cs
│ │ │ │ ├── ClientSettingsSettings.cs
│ │ │ │ ├── CommandsSettings.cs
│ │ │ │ ├── ConsulSettings.cs
│ │ │ │ ├── DiscordRolesSettings.cs
│ │ │ │ ├── DiscordSettings.cs
│ │ │ │ ├── FloodCheckerSettings.cs
│ │ │ │ ├── GlobalSettings.cs
│ │ │ │ ├── GridSettings.cs
│ │ │ │ ├── GrpcSettings.cs
│ │ │ │ ├── MaintenanceSettings.cs
│ │ │ │ ├── ScriptsSettings.cs
│ │ │ │ ├── UsersClientSettings.cs
│ │ │ │ └── WebSettings.cs
│ │ │ ├── SettingsProvidersDefaults.cs
│ │ │ └── Shared.Settings.csproj
│ │ ├── utility
│ │ │ ├── Enums
│ │ │ │ ├── BotRole.cs
│ │ │ │ ├── FilterType.cs
│ │ │ │ └── SettingType.cs
│ │ │ ├── Extensions
│ │ │ │ ├── DictionaryExtensions.cs
│ │ │ │ ├── IAttachmentExtensions.cs
│ │ │ │ ├── IUserMessageExtensions.cs
│ │ │ │ ├── ModuleBaseExtensions.cs
│ │ │ │ └── SocketInteractionExtensions.cs
│ │ │ ├── Implementation
│ │ │ │ ├── AdminUtility.cs
│ │ │ │ ├── AvatarUtility.cs
│ │ │ │ ├── BacktraceUtility.cs
│ │ │ │ ├── ClientSettingsFactory.cs
│ │ │ │ ├── ClientSettingsNameHelper.cs
│ │ │ │ ├── DiscordWebhookAlertManager.cs
│ │ │ │ ├── ExpirableDictionary.cs
│ │ │ │ ├── FilteredValue.cs
│ │ │ │ ├── FloodCheckerRegistry.cs
│ │ │ │ ├── JobManager.cs
│ │ │ │ ├── LazyWithRetry.cs
│ │ │ │ ├── LoggerFactory.cs
│ │ │ │ ├── LuaUtility.cs
│ │ │ │ ├── MicrosoftLogger.cs
│ │ │ │ ├── MicrosoftLoggerProvider.cs
│ │ │ │ ├── RbxUsersUtility.cs
│ │ │ │ ├── RefreshAhead.cs
│ │ │ │ └── ScriptLogger.cs
│ │ │ ├── Interfaces
│ │ │ │ ├── IAdminUtility.cs
│ │ │ │ ├── IAvatarUtility.cs
│ │ │ │ ├── IBacktraceUtility.cs
│ │ │ │ ├── IClientSettingsFactory.cs
│ │ │ │ ├── IDiscordWebhookAlertManager.cs
│ │ │ │ ├── IFloodCheckerRegistry.cs
│ │ │ │ ├── IJobManager.cs
│ │ │ │ ├── ILoggerFactory.cs
│ │ │ │ ├── ILuaUtility.cs
│ │ │ │ ├── IRbxUsersUtility.cs
│ │ │ │ └── IScriptLogger.cs
│ │ │ ├── Lua
│ │ │ │ └── LuaVMTemplate.lua
│ │ │ └── Shared.Utility.csproj
│ │ └── web
│ │ │ ├── Extensions
│ │ │ ├── HttpContextExtensions.cs
│ │ │ ├── HttpServerTelemetryExtensions.cs
│ │ │ └── IServiceProviderExtensions.cs
│ │ │ ├── Grid.Bot.Web.csproj
│ │ │ ├── Middleware
│ │ │ ├── HttpServerConcurrentRequestsMiddleware.cs
│ │ │ ├── HttpServerMiddlewareBase.cs
│ │ │ ├── HttpServerRequestCountMiddleware.cs
│ │ │ ├── HttpServerRequestLoggingMiddleware.cs
│ │ │ ├── HttpServerResponseMiddleware.cs
│ │ │ └── UnhandledExceptionMiddleware.cs
│ │ │ └── Routes
│ │ │ ├── Avatar.cs
│ │ │ ├── ClientSettings.cs
│ │ │ └── VersionCompatibility.cs
│ ├── src
│ │ ├── App.config
│ │ ├── Grid.Bot.csproj
│ │ ├── Program.cs
│ │ ├── Runner.cs
│ │ └── appsettings.json
│ └── ssl
│ │ └── global-root-ca.crt
└── recovery
│ ├── .component.yaml
│ ├── .dockerignore
│ ├── Dockerfile
│ ├── README.md
│ ├── grid-bot-recovery.sln
│ └── src
│ ├── Events
│ ├── OnLogMessage.cs
│ ├── OnMessage.cs
│ ├── OnReady.cs
│ └── OnSlashCommand.cs
│ ├── Grid.Bot.Recovery.csproj
│ ├── Implementation
│ ├── BotCheckWorker.cs
│ ├── BotManager.cs
│ ├── DiscordWebhookAlertManager.cs
│ └── Settings.cs
│ ├── Interfaces
│ ├── IBotManager.cs
│ ├── IDiscordWebhookAlertManager.cs
│ └── ISettings.cs
│ ├── Program.cs
│ └── Runner.cs
└── targets
└── git-metadata.targets
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | *.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | *.jpg binary
44 | *.png binary
45 | *.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/blacklist_appeal.yml:
--------------------------------------------------------------------------------
1 | name: Blacklist Appeal
2 | description: Request a blacklist appeal. File this if you would like to appeal a blacklist for yourself or a guild you own.
3 | title: "[Appeal]: "
4 | labels: ["kind: appeal", "status: backlogged", "status: needs-review"]
5 | assignees: ["nikita-petko"]
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: Thanks for taking the time to fill out this blacklist appeal!
10 | - type: checkboxes
11 | attributes:
12 | label: You have read the blacklist guidelines?
13 | description: Please check the [guidelines](https://grid-bot.ops.vmminfra.net/moderation) to determine if your appeal conforms to them.
14 | options:
15 | - label: "I double checked the guidelines and my appeal conforms to them."
16 | required: true
17 | - type: checkboxes
18 | attributes:
19 | label: You haven't been blacklisted before?
20 | description: If you have been blacklisted before, then don't file an appeal as you'll get declined.
21 | options:
22 | - label: "I double checked the blacklist and I haven't been blacklisted before."
23 | required: true
24 | - type: input
25 | id: discord-user-id
26 | attributes:
27 | label: The ID of the Discord User you are appealing for. If you are appealing for a guild this must be the ID of the owner.
28 | description: Please refer to the [Discord Helpcenter](https://support.discord.com/hc/en-us/articles/206346498) for more information on how to find the Discord ID of a user.
29 | placeholder: ex. 819791451436482600
30 | validations:
31 | required: true
32 | - type: input
33 | id: date-blacklisted
34 | attributes:
35 | label: The date you were blacklisted.
36 | description: You must provide the date you were blacklisted. As the moderation team will need to determine *why* you were blacklisted. In the format of `YYYY-MM-DD HH:MM:SS`.
37 | placeholder: ex. 2020-01-01 00:00:00
38 | validations:
39 | required: true
40 | - type: input
41 | id: guild-id
42 | attributes:
43 | label: The ID of the guild you think you were blacklisted in or you are getting a blacklist revoked for.
44 | description: Please refer to the [Discord Helpcenter](https://support.discord.com/hc/en-us/articles/206346498) for more information on how to find the ID of a guild.
45 | placeholder: ex. 559083251805978644
46 | validations:
47 | required: true
48 | - type: input
49 | id: channel-id
50 | attributes:
51 | label: The ID of the channel you think you were blacklisted in. This does not apply if you are appealing guild blacklist.
52 | description: Please refer to the [Discord Helpcenter](https://support.discord.com/hc/en-us/articles/206346498) for more information on how to find the ID of a channel.
53 | placeholder: ex. 954168914273767484
54 | validations:
55 | required: false
56 | - type: textarea
57 | id: appeal-reason
58 | attributes:
59 | label: The reason you are appealing.
60 | description: Minimum of 50 characters on why you are appealing.
61 | placeholder: I am appealing because I was blacklisted for spamming...
62 | validations:
63 | required: true
64 | - type: textarea
65 | id: apology
66 | attributes:
67 | label: An apology for the moderation team.
68 | description: Minimum of 100 characters apology towards the moderation team and the clients who use the bot.
69 | placeholder: I am sorry for the spamming and I am trying to get this removed.
70 | validations:
71 | required: true
72 | - type: textarea
73 | id: images
74 | attributes:
75 | label: Images
76 | description: Attach images to the appeal. This is optional if you have evidence to prove your innocence.
77 | validations:
78 | required: false
79 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.yml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: File a bug report, use this if you have discovered a bug in production and wish the internal team to investigate.
3 | title: "[Bug]: "
4 | labels: ["kind: fix", "status: backlogged", "status: needs-review"]
5 | assignees: ["nikita-petko"]
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: Thanks for taking the time to fill out this bug report!
10 | - type: checkboxes
11 | attributes:
12 | label: Check if there is an existing issue or pull request.
13 | description: Please check the [issues](https://github.com/mfdlabs/grid-bot/issues) to determine if your issue has already been filed.
14 | options:
15 | - label: "I double checked issues and couldn't find any duplicates."
16 | required: true
17 | - type: checkboxes
18 | attributes:
19 | label: This occurs on the latest version of the bot.
20 | description: If this bug occurs on a previous version of the bot, please check this box. There will be a version string in the README.md that will correlate to a version that you can check on the bot.
21 | options:
22 | - label: I verified that the bot is running on the latest version.
23 | required: true
24 | - type: checkboxes
25 | attributes:
26 | label: Does this bug occur frequently?
27 | description: If this bug occurs frequently, please tick this box.
28 | options:
29 | - label: This bug occurs frequently.
30 | required: false
31 | - type: textarea
32 | id: description
33 | attributes:
34 | label: Description
35 | description: A detailed explination of the bug.
36 | placeholder: When rendering, it will throw an error.
37 | validations:
38 | required: true
39 | - type: input
40 | id: deployment-id
41 | attributes:
42 | label: The deployment ID of the bot.
43 | description: This refers to the deployment ID of the bot, there will be a command that lets you retrieve this value (/support). Use this if it's version specific.
44 | placeholder: ex. 2022.03.06-01.36.27_master_561a09f-net48-Release
45 | validations:
46 | required: false
47 | - type: input
48 | id: dates-of-occurrence
49 | attributes:
50 | label: The dates of occurrence of the bug.
51 | description: This refers to the dates of occurrence of the bug. These can be on any time zone, but must include the year, month, day, hour, minute, and second (if possible). This accepts multiple dates, separated by commas.
52 | placeholder: ex. 2022/03/06 01:36:27 UTC+1, 2022/03/06 01:37:28 UTC+1, 2022/03/06 01:38:11 UTC+1
53 | validations:
54 | required: false
55 | - type: input
56 | id: machine-id
57 | attributes:
58 | label: The hostname, Machine ID and IP of the machine
59 | description: This refers to the hostname, Machine ID and IP of the machine, there will be a command that lets you retrieve this value (/support). This is optional, but is very helpful for debugging.
60 | placeholder: ex. dapp181-dec.distrubuted.jfk01-us-east-01.mfdlabs.local, JFK01-DApp181, 10.128.29.28
61 | validations:
62 | required: false
63 | - type: textarea
64 | id: images
65 | attributes:
66 | label: Images
67 | description: Attach images to the bug report. This is optional.
68 | validations:
69 | required: false
70 | - type: textarea
71 | id: steps-to-reproduce
72 | attributes:
73 | label: Steps to Reproduce
74 | description: Please provide steps to reproduce the bug. This is optional, but is highly recommended.
75 | placeholder: >
76 | 1. Execute command /execute script script:BLAH BLAH
77 | 2. Paste this code in blah blah.
78 | 3. Magic!!
79 | validations:
80 | required: false
81 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: true
2 | contact_links:
3 | - name: Discord Guild Invite
4 | url: https://discord.gg/DURUeUcfar
5 | about: Join this Guild if you want to talk directly to the owner of the bot.
6 | - name: Discord Bot Invite
7 | url: https://discord.com/api/oauth2/authorize?client_id=819791451436482600&permissions=2147798080&response_type=code&scope=bot%20applications.commands%20messages.read
8 | about: If you wish to add the bot to your guilds, use this invite url to do so.
9 | - name: Grid Bot Moderation Guidelines
10 | url: https://grid-bot.ops.vmminfra.net/moderation
11 | about: Please refer to here before opening Blacklist appeals.
12 | - name: Grid Bot Terms of Service
13 | url: https://grid-bot.ops.vmminfra.net/legal/tos
14 | about: Please refer to here for the terms and conditions for using or integrating this bot within Discord.
15 | - name: Grid Bot Privacy Policy
16 | url: https://grid-bot.ops.vmminfra.net/legal/privacy-policy
17 | about: Please refer to here for the information on how we use your data internally.
18 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------
1 | name: Feature Request
2 | description: Request a new feature. File this if you would like to see a new feature added to the bot.
3 | title: "[Feature]: "
4 | labels: ["kind: feature", "kind: enhancement", "status: backlogged", "status: needs-review"]
5 | assignees: ["nikita-petko"]
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: Thanks for taking the time to fill out this feature request!
10 | - type: checkboxes
11 | attributes:
12 | label: Check if there is an existing issue or pull request
13 | description: Please check the [issues](https://github.com/mfdlabs/grid-bot/issues) to determine if your feature request is already in the works or has already been requested.
14 | options:
15 | - label: "I double checked issues and couldn't find any duplicates."
16 | required: true
17 | - type: checkboxes
18 | attributes:
19 | label: Verify Feature Quality.
20 | description: >
21 | If your feature is actually worth being integrated. This includes things like:
22 | - Does it work?
23 | - Is it a good idea?
24 | - Does it benefit the user?
25 | - Will it generate traffic?
26 | options:
27 | - label: I verified the feature I requested, and it is worth being integrated.
28 | required: true
29 | - type: textarea
30 | id: description
31 | attributes:
32 | label: Description
33 | description: A detailed explaintion of the feature. Be as detailed as possible. Going from how the feature works to the benefits of the feature.
34 | placeholder: It adds new code and stuff blah blah.
35 | validations:
36 | required: true
37 | - type: textarea
38 | id: images
39 | attributes:
40 | label: Images
41 | description: Attach images to the feature request.
42 | validations:
43 | required: false
44 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/security_vulnerabilty.yml:
--------------------------------------------------------------------------------
1 | name: Security Vulnerabilty Report
2 | description: File a security vulnerability report, use this if you have discovered a security vulnerability and wish the internal team to investigate.
3 | title: "[Vulnerability]: "
4 | labels: ["kind: hotfix", "priority: key deliverable", "status: backlogged", "status: needs-review"]
5 | assignees: ["nikita-petko"]
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: Thanks for taking the time to fill out this security vulnerability report! This will be marked with the label "key deliverable", which will email @mfdlabs/sec-ops, @mfdlabs/ops and @mfdlabs/grid-team
10 | - type: checkboxes
11 | attributes:
12 | label: Check if there is an existing issue or pull request.
13 | description: Please check the [issues](https://github.com/mfdlabs/grid-bot/issues) to determine if your vulnerability has already been filed.
14 | options:
15 | - label: "I double checked issues and couldn't find any duplicates."
16 | required: true
17 | - type: checkboxes
18 | attributes:
19 | label: This occurs on the latest version of the bot.
20 | description: If this bug occurs on the latest version of the bot, please check this box. There will be a version string in the README.md that will correlate to a version that you can check on the bot.
21 | options:
22 | - label: I verified that this occurs on the latest version.
23 | required: true
24 | - type: checkboxes
25 | attributes:
26 | label: Have you read the Security Vulnerability Guidelines?
27 | description: If you have read the [Security Vulnerability Guidelines](https://github.com/mfdlabs/grid-bot/blob/master/SECURITY.md), and this issue conforms to them, please check this box.
28 | options:
29 | - label: I have read the Security Vulnerability Guidelines.
30 | required: true
31 | - type: dropdown
32 | id: severity
33 | attributes:
34 | label: Vulernability Severity
35 | description: This refers to the severity of the vulnerability. This is required.
36 | options:
37 | - "Critical"
38 | - "High"
39 | - "Medium"
40 | - "Low"
41 | - "Invonvenience"
42 | validations:
43 | required: true
44 | - type: textarea
45 | id: description
46 | attributes:
47 | label: Description
48 | description: A brief explination of the vulnerability.
49 | placeholder: ex. Public IP address is exposed.
50 | validations:
51 | required: true
52 | - type: input
53 | id: deployment-id
54 | attributes:
55 | label: The deployment ID of the bot.
56 | description: This refers to the deployment ID of the bot, there will be a command that lets you retrieve this value (/support). Use this if it's version specific.
57 | placeholder: ex. 2022.03.06-01.36.27_master_561a09f-net48-Release
58 | validations:
59 | required: false
60 | - type: input
61 | id: dates-of-occurrence
62 | attributes:
63 | label: The dates of occurrence of the vulnerability.
64 | description: This refers to the dates of occurrence of the vulnerability. These can be on any time zone, but must include the year, month, day, hour, minute, and second (if possible). This accepts multiple dates, separated by commas.
65 | placeholder: ex. 2022/03/06 01:36:27 UTC+1, 2022/03/06 01:37:28 UTC+1, 2022/03/06 01:38:11 UTC+1
66 | validations:
67 | required: false
68 | - type: input
69 | id: machine-id
70 | attributes:
71 | label: The hostname, Machine ID and IP of the machine
72 | description: This refers to the hostname, Machine ID and IP of the machine, there will be a command that lets you retrieve this value (/support). This is optional, but is very helpful for debugging.
73 | placeholder: ex. dapp181-dec.distrubuted.jfk01-us-east-01.mfdlabs.local, JFK01-DApp181, 10.128.29.28
74 | validations:
75 | required: false
76 | - type: textarea
77 | id: images
78 | attributes:
79 | label: Images
80 | description: Attach images to the vulnerability report. This is optional, but is very helpful for debugging.
81 | validations:
82 | required: false
83 | - type: textarea
84 | id: steps-to-reproduce
85 | attributes:
86 | label: Steps to Reproduce
87 | description: Please provide steps to reproduce the bug. This is optional, but is highly recommended.
88 | placeholder: >
89 | 1. Execute command /execute script script:BLAH BLAH
90 | 2. Paste this code in blah blah.
91 | 3. Magic!!
92 | validations:
93 | required: false
94 |
--------------------------------------------------------------------------------
/.github/workflows/docs.yml:
--------------------------------------------------------------------------------
1 | name: MkDocs Deploy
2 |
3 | on:
4 | push:
5 | branches:
6 | - "master"
7 | paths:
8 | - "docs/**"
9 | - ".github/workflows/docs.yml"
10 | - "mkdocs.yml"
11 |
12 | permissions:
13 | contents: write
14 |
15 | jobs:
16 | mkdocs:
17 | name: MkDocs Deploy
18 | if: ${{ !contains(toJSON(github.event.head_commit.message), '!#skip-build#!') }}
19 | runs-on: ubuntu-latest
20 | steps:
21 | - name: Checkout code
22 | uses: actions/checkout@v4
23 | with:
24 | fetch-depth: 0
25 |
26 | - name: Set up Python
27 | uses: actions/setup-python@v5
28 | with:
29 | python-version: '3.10'
30 |
31 | - name: Install dependencies
32 | run: |
33 | pip install mkdocs-material mkdocs-minify-plugin
34 |
35 | - name: Configure Git user
36 | run: |
37 | git config --local user.email "ops+grid-bot-gh@vmminfra.net"
38 | git config --local user.name "grid-bot-gh"
39 |
40 | - name: Deploy docs
41 | run: |
42 | mkdocs gh-deploy --force
43 | env:
44 | GITHUB_TOKEN: ${{ secrets.DEPLOYER_TOKEN }}
45 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "lib"]
2 | path = lib
3 | url = git@github.com:mfdlabs/grid-bot-libraries.git
4 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | "name": "Grid.Bot",
6 | "type": "coreclr",
7 | "request": "launch",
8 | "preLaunchTask": "build",
9 | "program": "${workspaceFolder}/services/grid-bot/src/bin/Debug/net8.0/Grid.Bot.dll",
10 | "cwd": "${workspaceFolder}/services/grid-bot/src/",
11 | "console": "internalConsole",
12 | "stopAtEntry": false,
13 | "logging": {
14 | "moduleLoad": false
15 | },
16 | "requireExactSource": false,
17 | "envFile": "${workspaceFolder}/.env"
18 | }
19 | ]
20 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "build",
6 | "command": "dotnet",
7 | "type": "process",
8 | "args": [
9 | "build",
10 | "${workspaceFolder}/services/grid-bot/src/Grid.Bot.csproj",
11 | "/property:GenerateFullPaths=true",
12 | "/consoleloggerparameters:NoSummary",
13 | "/p:Configuration=Debug",
14 | "/p:Platform=AnyCPU",
15 | ],
16 | "problemMatcher": "$msCompile"
17 | },
18 | {
19 | "label": "build-full",
20 | "command": "dotnet",
21 | "type": "process",
22 | "args": [
23 | "build",
24 | "${workspaceFolder}/services/grid-bot/src/Grid.Bot.csproj",
25 | "/property:GenerateFullPaths=true",
26 | "/consoleloggerparameters:NoSummary",
27 | "/p:Configuration=Debug",
28 | "/p:Platform=AnyCPU",
29 | "/p:LocalBuild=true"
30 | ],
31 | "problemMatcher": "$msCompile"
32 | }
33 | ]
34 | }
--------------------------------------------------------------------------------
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # "Who Owns This Sector?", "Grid Team"
2 | * @mfdlabs/grid-team @mfdlabs/who-owns-this-sector
3 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Contributing
2 |
3 | Please conform to the following guidelines when contributing:
4 |
5 | ## Development Cycle
6 |
7 | We prefer all changes to the app to be discussed beforehand,
8 | either in a GitHub issue, or in a an email thread with primary developers or other contributors.
9 |
10 | ### Issues
11 |
12 | Unless the change is tied to a hot-fix, all pull requests must have an issue related to them.
13 |
14 | ### Labels
15 |
16 | Issues and pull requests must include labels prefixed with "kind" and "priority", all others are optional and can be applied as such.
17 |
18 | ### Pull Requests
19 |
20 | We prefer pull-requests that are descriptive of the changes being made
21 | and highlight any potential benefits/drawbacks of the change, but these
22 | types of write-ups are not required.
23 |
24 | Even if your change is really small, please open a pull request about it.
25 |
26 | Please note that as this project is under MFDLABS, branch naming rules for this organization will be enforced and are as follows:
27 |
28 | > Revised Code Branches, supersedes old branches rules.
29 | > Branches are split like this for branches ***not specific to teams***:
30 | > ***{operation}/{fixture}***
31 | >
32 | > Branchesare split like this for branches ***specific to teams***:
33 | > ***{operation}/{teamName}/{fixture}***
34 | >
35 | > The following operations are allowed:
36 | >
37 | >
38 | > **feature** -> *Represents a single feature to be integrated.*
39 | > **ops** -> *Refers to a major overhaul with a core operation of the system or a dependency change.*
40 | > **fix** -> *Refers to a single bug fix.*
41 | > **enhancement** -> *Refers to changes or enhancements made to already existing repository files.*
42 | > **dev** -> *Use this to refer to an entire branch prefix of releases dedicated to a team (as in it will be merged here before it gets merged to master)*
43 | > **hotfix** -> *Use this when implementing crucial hotfixes into production.*
44 | >
45 | >
46 | >
47 | > You ***MUST*** create a new branch for every new change, fix etc. you make, if the changes can be split, do it.
48 | >
49 | > For the fixture, it can only contain characters *`a-zA-Z1-0\-_`*, try to be brief with the name but also giving information about the change.
50 | >
51 | > If you can, try to also include Jira ticket IDs or backlog issue urls.
52 | > Example:
53 | > PR Title: ***[BCKLOG-657](https://jira.dex2.vmminfra.dev/BCKLOG-657?from=gh)***: *Runtime fixture for possible crash exploit exposure through admin API.*
54 | > Branch: ***[fix/security-ops/bcklog-657-potential-crash-exploit](https://github.vmminfra.dev/mfdlabs/backlog/tree/fix/security-ops/bcklog-657-potential-crash-exploit)***.
55 | >
56 | > When you merge your PR into your chosen branch, do not delete the branch.
57 | >
58 | > Pull requests must be reviewed by codeowners (if applicable) or a repository owner if you are contributing to them.
59 |
60 | ### Commits
61 |
62 | The main ruling for commits is that they are preferred be signed with a GPG key, if you made the change via github.com, they should be signed as default.
63 |
64 | To learn how to do this, please follow this guide:
65 | - [Signing Commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits)
66 |
67 | ### Reviews
68 |
69 | When you create a pull-request, even if you're a repository administrator, you will have to go through code review. You can review the [CODEOWNERS](./CODEOWNERS) file for a list of default assigned members that will review your pull-request, or you can request another repository administrator or organization member to do it for you.
70 |
71 | ## Coding Style
72 |
73 | As a general rule, follow the coding style already set in the file you
74 | are editing, or look at a similar file if you are adding a new one.
75 |
76 | ### Documentation Style
77 |
78 | Any new code should always have documentation comments above it, and your code should also be either self documenting or have it's own comments to explain what it does, but that doesn't mean commenting on the most obvious things like variable assignment.
79 |
80 | If using GitHub co-pilot, please try to remove any of the comments made to generate the code.
81 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # MFDLABS Grid Bot Security Vulnerability Report guidelines
2 |
3 | Thank you for your interest in reporting security vulnerabilities to MFDLABS Grid Team.
4 | There are a few things you should know before you start:
5 |
6 | ## 1. Determing if the vulnerability causes critical security that should not be used by other users.
7 |
8 | Determine if the vulnerability you have found can cause damage to the system or to other users. If so please email it to [ops+code-security-grid-bot@vmminfra.net](mailto:ops+code-security-grid-bot@vmminfra.net)
9 |
10 | ## 2. Collecting as much information as possible about the vulnerability.
11 |
12 | Collect as much information as possible about the vulnerability is important to ensure that the vulnerability is not a false positive.
13 | Images, text, deployments, and other information that can help you identify the vulnerability is helpful.
--------------------------------------------------------------------------------
/docs/CNAME:
--------------------------------------------------------------------------------
1 | grid-bot.ops.vmminfra.net
--------------------------------------------------------------------------------
/docs/assets/theme.css:
--------------------------------------------------------------------------------
1 | [data-md-color-scheme=slate] {
2 | --md-default-bg-color: #1d1d1f;
3 | --md-typeset-a-color: var(--md-accent-fg-color) !important;
4 | }
5 |
6 | .md-typeset a:focus, .md-typeset a:hover {
7 | color: #72b8ff;
8 | }
9 |
10 | .md-footer-copyright::after{
11 | content: "· Original theme by Elttob";
12 | }
13 |
14 | :root {
15 | color-scheme: dark;
16 | }
17 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Home"
3 | description: "The home page for the Grid Bot!"
4 | ---
5 |
6 | # Announcement
7 |
8 | As of Tuesday, the 21st of March 2024, Grid Bot's infrastructure was turned off.
9 |
10 | The reasoning behind this was simply put, it became majorily costly.
11 |
12 | This bot ran on this stack of infrastructure on AWS:
13 |
14 | 1 Linux machine, @ 16 cores, 32 GiB -- This hosted the Bot, as well as its underlying dependencies such as Redis, Consul and grid-service-websrv
15 | 1 Client VPN -- This prevented outside access to internal components such as configuration and a job management.
16 |
17 | Overall, this costed upwards of $1000 a month to maintain fully, which did get cost draws but in the end, for the whole year it would nearly cost $11.000.
18 |
19 | ## What now?
20 |
21 | The position of hosting this is open for applications, if people wish to work with me they may open an issue on [GitHub](https://github.com/mfdlabs/grid-bot) or email me [petko@vmminfra.net](mailto:petko@vmminfra.net). You must have infrastructure capabilities to handle the following:
22 |
23 | - Constant throughput from ~31.000 guilds every second.
24 | - Enough storage and compute power to handle clients hosting upwards of 30 shards.
25 |
--------------------------------------------------------------------------------
/docs/legal/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Legal
3 | description: The legal documents such as ToS and Privacy Policy
4 | ---
5 |
6 | # Legal
7 | This subdirectory contains documents pertaining the Terms of Use and Privacy Policy involved when you either use or integrate this "Bot" in or into any guild you may own.
8 |
9 | # Terms Of Use
10 | Terms of use are the rules, specifications, and requirements for the use of a product or service. They serve as a contract between the product or service provider and user.
11 |
12 | The phrase is sometimes used interchangeably with “terms of service” or “terms and conditions”.
13 |
14 | # Privacy Policy
15 | A privacy policy is a legal document that explains how a company or website collects, uses, and shares personal information. Privacy policies should outline what personal information is collected, how the information is used, whether the information is shared with third parties, and what rights users have over their data.
16 |
--------------------------------------------------------------------------------
/docs/legal/privacy-policy.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Privacy Policy
3 | description: This document outlines how we use your data to enhance the experience of this "Bot"
4 | ---
5 |
6 | # Privacy Policy
7 |
8 | To be determined
9 |
--------------------------------------------------------------------------------
/docs/legal/tos.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Terms of Use
3 | description: This document outlines the terms to be followed by the clients that use this "Bot"
4 | ---
5 |
6 | # Terms of Use
7 |
8 | To be determined
9 |
--------------------------------------------------------------------------------
/docs/overrides/assets/stylesheets/main.css:
--------------------------------------------------------------------------------
1 | .md-banner strong {
2 | white-space: nowrap;
3 | }
4 | .md-banner a {
5 | color: white;
6 | font-size: 0.8rem;
7 | }
8 |
--------------------------------------------------------------------------------
/docs/overrides/main.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block extrahead %}
4 |
8 | {% if page and page.meta and page.meta.robots %}
9 |
10 | {% else %}
11 |
12 | {% endif %}
13 | {% endblock %}
14 |
--------------------------------------------------------------------------------
/docs/request-data-deletion.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Request Deletion of your Data
3 | description: Outlines the steps you need to take in order to request the deletion of your Discord user information from the bot's registry.
4 | ---
5 |
6 | # Pre requisitories
7 |
8 | In order to submit a data deletion request, you must do the following:
9 |
10 | 1. You must be the rightful owner of the account in question, you will be asked further down the request to verify your ownership.
11 | 1. You must have a list of all information you think is stored in the bot's registries that you would like deleted.
12 | 1. You must be sure that this is what you want to do, as this operation is irreversible.
13 |
14 | # Submitting the request
15 |
16 | In order to submit the request, you must email [ops+grid-bot-deletion-requests@vmminfra.net](mailto:ops+grid-bot-deletion-requests@vmminfra.net) from the email of the account in question.
17 | Please include all of the data mentioned above, and be ready to be asked for ownership verification.
18 |
--------------------------------------------------------------------------------
/mkdocs.yml:
--------------------------------------------------------------------------------
1 | site_name: "MFDLABS Grid Bot Documentation"
2 | site_url: "https://grid-bot.ops.vmminfra.net/"
3 | repo_name: "mfdlabs/grid-bot"
4 | repo_url: "https://github.com/mfdlabs/grid-bot/issues"
5 | edit_uri: ""
6 | remote_branch: deploy/docs-dev/docs-deploy
7 |
8 | theme:
9 | name: material
10 | custom_dir: docs/overrides
11 | logo: assets/logo.svg
12 | favicon: assets/logo.svg
13 | font:
14 | text: Inter
15 | code: JetBrains Mono
16 | icon:
17 | repo: fontawesome/brands/github
18 | palette:
19 | scheme: slate
20 | primary: black
21 | accent: blue
22 | features:
23 | - content.code.annotate
24 | - navigation.instant
25 | - navigation.tracking
26 | - navigation.tabs
27 |
28 | extra_css:
29 | - assets/theme.css
30 |
31 | plugins:
32 | - search
33 | - minify:
34 | minify_html: true
35 |
36 | markdown_extensions:
37 | - admonition
38 | - attr_list
39 | - def_list
40 | - meta
41 | - pymdownx.betterem
42 | - pymdownx.details
43 | - pymdownx.tasklist:
44 | custom_checkbox: true
45 | - pymdownx.tabbed:
46 | alternate_style: true
47 | - pymdownx.inlinehilite
48 | - pymdownx.keys
49 | - pymdownx.magiclink
50 | - pymdownx.superfences
51 | - pymdownx.highlight:
52 | guess_lang: false
53 | - toc:
54 | permalink: true
55 | - pymdownx.emoji:
56 | emoji_index: !!python/name:materialx.emoji.twemoji
57 | emoji_generator: !!python/name:materialx.emoji.to_svg
58 |
59 | extra:
60 | social:
61 | - icon: material/application-brackets-outline
62 | link: https://discord.com/api/oauth2/authorize?client_id=819791451436482600&permissions=2147798080&response_type=code&scope=bot%20applications.commands%20messages.read
63 | name: Discord Bot Invite Referrer
64 | analytics:
65 | provider: google
66 | property: G-QV4S1YRK2D
67 | generator: false
68 |
69 | copyright: Copyright © 2024 MFDLABS Corporation
70 |
--------------------------------------------------------------------------------
/proto/grid_bot.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package grid.bot.v1;
4 |
5 | option csharp_namespace = "Grid.Bot.V1";
6 |
7 | // GridBotAPI defines the gRPC service for checking health
8 | service GridBotAPI {
9 | // CheckHealth checks the health of the service.
10 | // Used by the recovery instance to determine if recovery is needed.
11 | rpc CheckHealth(CheckHealthRequest) returns (CheckHealthResponse);
12 | };
13 |
14 | // CheckHealthRequest is the request for the CheckHealth RPC.
15 | message CheckHealthRequest {
16 | };
17 |
18 | // CheckHealthResponse is the response for the CheckHealth RPC.
19 | message CheckHealthResponse {
20 | // latency is the latency of the Discord.Net API.
21 | int32 latency = 1;
22 |
23 | // status is the status of the Discord.Net API.
24 | string status = 2;
25 |
26 | // shards is a list of shard display names.
27 | repeated string shards = 3;
28 | };
29 |
--------------------------------------------------------------------------------
/scripts/clean.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # This will enumerate the workspace and remove obj and bin folders
4 |
5 | # The workspace is always one directory up from the script directory
6 | WORKSPACE=$(dirname $(dirname $(realpath $0)))
7 |
8 | echo "Cleaning workspace: $WORKSPACE"
9 |
10 | # Find all obj and bin folders and remove them recursively and log each removal
11 | find $WORKSPACE -type d -name obj -exec rm -rf {} \; -print
12 | find $WORKSPACE -type d -name bin -exec rm -rf {} \; -print
--------------------------------------------------------------------------------
/services/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | $(NoWarn);4014
4 |
5 |
6 |
7 | net8.0
8 | preview
9 | Grid.Bot
10 |
11 | debug;release
12 |
13 |
14 |
15 | false
16 |
17 |
18 |
19 | $(MSBuildThisFileDirectory)..\
20 |
21 |
22 |
23 |
24 |
25 | MFDLABS
26 | Copyright © $(Company) $([System.DateTime]::Now.ToString(`yyyy`)). All rights reserved.
27 | $(Company);Nikita Petko
28 |
29 | https://github.com/mfdlabs/grid-bot
30 | git
31 |
32 | $([System.DateTime]::Now.ToString(`yyyy.MM.dd`))
33 |
34 | false
35 | $(IMAGE_TAG)
36 | dev
37 |
38 |
39 |
40 | true
41 |
42 |
43 |
44 | true
45 |
46 |
--------------------------------------------------------------------------------
/services/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <_Parameter1>$(AssemblyName).Tests.Unit
5 |
6 |
7 |
8 | <_Parameter1>DynamicProxyGenAssembly2
9 |
10 |
11 |
--------------------------------------------------------------------------------
/services/grid-bot/.component.yaml:
--------------------------------------------------------------------------------
1 | component: grid-bot
2 |
3 | # This is only used by the build worklow,
4 | # it determines how the component is built
5 | # Docker only relevant when the argument
6 | #
7 | build:
8 | project_file: src/Grid.Bot.csproj
9 | component_directory: ./.deploy
10 |
11 | additional_args:
12 | - -p:IMAGE_TAG=${{ env.NOMAD_VERSION }}
13 | - -p:CI=true
14 |
15 | docker:
16 | docker_file: Dockerfile
17 | image_name: mfdlabs/grid-bot
18 |
19 | deployment:
20 | count: 1
21 | namespace: grid-bot
22 |
23 | job: grid-bot-${{ env.NOMAD_SHORT_ENVIRONMENT }}
24 |
25 | vault_policies:
26 | - vault_secret_grid_settings_read_write
27 |
28 | # Passed to the meta section in Nomad
29 | meta:
30 | ENVIRONMENT: ${{ env.NOMAD_ENVIRONMENT }}
31 |
32 | containers: # Maps to the groups section in Nomad
33 | - image: mfdlabs/grid-bot
34 | resources:
35 | cpu: ${{ env.NOMAD_CPU }}
36 | ram: ${{ env.NOMAD_RAM }}
37 | network:
38 | mode: host
39 | ports:
40 | metrics:
41 | static: 8101
42 | grpc:
43 | static: 5000
44 | http:
45 | static: 8888
46 | services:
47 | - name: ${{ env.NOMAD_ENVIRONMENT }}-grid-bot
48 | port: metrics
49 | tags:
50 | - ${{ env.NOMAD_ENVIRONMENT }}
51 | checks:
52 | - type: http
53 | path: /metrics
54 |
55 | - name: ${{ env.NOMAD_ENVIRONMENT }}-grid-bot-web
56 | port: http
57 | tags:
58 | - ${{ env.NOMAD_ENVIRONMENT }}
59 | - "traefik.enable=true"
60 | - "traefik.http.routers.${{ env.NOMAD_ENVIRONMENT }}-grid-bot-web-http.rule=(HostRegexp(`{host:[a-zA-Z]+}.sitetest4.robloxlabs.com`) || Host(`versioncompatibility.api.sitetest4.robloxlabs.com`))"
61 | - "traefik.http.routers.${{ env.NOMAD_ENVIRONMENT }}-grid-bot-web-http.entrypoints=http"
62 | checks:
63 | - type: http
64 | path: /health
65 |
66 | - name: ${{ env.NOMAD_ENVIRONMENT }}-grid-bot-web-https
67 | port: http
68 | tags:
69 | - ${{ env.NOMAD_ENVIRONMENT }}
70 | - "traefik.enable=true"
71 | - "traefik.http.routers.${{ env.NOMAD_ENVIRONMENT }}-grid-bot-web-https.rule=(HostRegexp(`{host:[a-zA-Z]+}.sitetest4.robloxlabs.com`) || Host(`versioncompatibility.api.sitetest4.robloxlabs.com`))"
72 | - "traefik.http.routers.${{ env.NOMAD_ENVIRONMENT }}-grid-bot-web-https.entrypoints=https"
73 | - "traefik.http.routers.${{ env.NOMAD_ENVIRONMENT }}-grid-bot-web-https.tls=true"
74 | checks:
75 | - type: http
76 | path: /health
77 |
78 | volumes:
79 | - '/var/run/docker.sock:/var/run/docker.sock'
80 | - '/tmp/.X11-unix:/tmp/.X11-unix'
81 | - '/opt/grid/scripts:/opt/grid/scripts'
82 | - '/_/_logs/grid-bot/${{ env.NOMAD_ENVIRONMENT }}:/tmp/mfdlabs/logs'
83 | config_maps:
84 | - destination: secrets/file.env
85 | env: true
86 | on_change: restart
87 | data: |
88 | DISPLAY=:1
89 | DEFAULT_LOG_LEVEL=Information
90 | VAULT_ADDR="http://vault.service.consul:8200"
91 | VAULT_TOKEN="{{ with secret "grid-bot-settings/grid-bot-vault" }}{{ .Data.data.vault_token }}{{ end }}"
92 |
--------------------------------------------------------------------------------
/services/grid-bot/.dockerignore:
--------------------------------------------------------------------------------
1 | *
2 | !ssl
3 |
--------------------------------------------------------------------------------
/services/grid-bot/Dockerfile:
--------------------------------------------------------------------------------
1 | # Base Image: net8.0
2 | FROM mcr.microsoft.com/dotnet/aspnet:8.0.1-jammy
3 |
4 | WORKDIR /opt/grid
5 | COPY . /opt/grid/
6 |
7 | COPY ./ssl/global-root-ca.crt /usr/local/share/ca-certificates/global-root-ca.crt
8 | RUN chmod 644 /usr/local/share/ca-certificates/global-root-ca.crt && update-ca-certificates
9 |
10 | RUN mkdir /opt/grid/logs
11 | RUN mkdir /opt/grid/scripts
12 |
13 | CMD ["dotnet", "/opt/grid/Grid.Bot.dll"]
14 |
--------------------------------------------------------------------------------
/services/grid-bot/README.md:
--------------------------------------------------------------------------------
1 | # Grid Bot
2 |
3 | This is a Daemon that runs the main code for the Grid Bot.
--------------------------------------------------------------------------------
/services/grid-bot/lib/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | $(NoWarn);4014
4 |
5 |
6 |
7 | net8.0
8 | preview
9 | Grid.Bot
10 |
11 | debug;release
12 |
13 |
14 |
15 | false
16 |
17 |
18 |
19 | MFDLABS
20 | Copyright © $(Company) $([System.DateTime]::Now.ToString(`yyyy`)). All rights reserved.
21 | $(Company);Nikita Petko
22 |
23 | https://github.com/mfdlabs/grid-bot
24 | git
25 |
26 | $([System.DateTime]::Now.ToString(`yyyy.MM.dd`))
27 |
28 | false
29 | $(IMAGE_TAG)
30 | dev
31 |
32 |
33 |
34 | true
35 |
36 |
37 |
38 | true
39 |
40 |
41 |
42 | $(MSBuildThisFileDirectory)..\..\..\
43 |
44 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <_Parameter1>$(AssemblyName).Tests.Unit
5 |
6 |
7 |
8 | <_Parameter1>DynamicProxyGenAssembly2
9 |
10 |
11 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/commands/Attributes/LockDownCommandAttribute.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot.Commands;
2 |
3 | using System;
4 | using System.Threading.Tasks;
5 |
6 | using Microsoft.Extensions.DependencyInjection;
7 |
8 | using Discord.Commands;
9 |
10 | using Utility;
11 |
12 | ///
13 | /// An attribute only allows the command to be executed within the DMs of
14 | /// users within the specified bot role, or within the specified guild (if configured).
15 | ///
16 | ///
17 | /// Construct a new instance of .
18 | ///
19 | /// The .
20 | public class LockDownCommandAttribute(BotRole botRole = BotRole.Administrator) : PreconditionAttribute
21 | {
22 | private readonly BotRole _botRole = botRole;
23 |
24 | ///
25 | /// The marker to indicate that the command should not respond.
26 | ///
27 | public const string MarkerDoNotRespond = "___||DO_NOT_RESPOND||___";
28 |
29 | ///
30 | public override Task CheckPermissionsAsync(ICommandContext context, CommandInfo commandInfo, IServiceProvider services)
31 | {
32 | var commandsSettings = services.GetRequiredService();
33 | if (!commandsSettings.EnableLockdownCommands)
34 | return Task.FromResult(PreconditionResult.FromSuccess());
35 |
36 | if (context.Guild is not null)
37 | return context.Guild.Id == commandsSettings.LockdownGuildId
38 | ? Task.FromResult(PreconditionResult.FromSuccess())
39 | : Task.FromResult(PreconditionResult.FromError(MarkerDoNotRespond));
40 |
41 | var adminUtility = services.GetRequiredService();
42 |
43 | var isInRole = _botRole switch
44 | {
45 | BotRole.Privileged => adminUtility.UserIsPrivilaged(context.User),
46 | BotRole.Administrator => adminUtility.UserIsPrivilaged(context.User),
47 | BotRole.Owner => adminUtility.UserIsOwner(context.User),
48 | _ => throw new ArgumentOutOfRangeException(nameof(_botRole), _botRole, null),
49 | };
50 |
51 | return isInRole
52 | ? Task.FromResult(PreconditionResult.FromSuccess())
53 | : Task.FromResult(PreconditionResult.FromError(MarkerDoNotRespond));
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/commands/Attributes/RequireCommandBotRoleAttribute.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot.Commands;
2 |
3 | using System;
4 | using System.Threading.Tasks;
5 |
6 | using Microsoft.Extensions.DependencyInjection;
7 |
8 | using Discord.Commands;
9 |
10 | using Utility;
11 |
12 | ///
13 | /// An attribute that validates if the user has the required bot role.
14 | ///
15 | ///
16 | /// Construct a new instance of .
17 | ///
18 | /// The .
19 | public class RequireBotRoleAttribute(BotRole botRole = BotRole.Privileged) : PreconditionAttribute
20 | {
21 | ///
22 | /// The role.
23 | ///
24 | public BotRole BotRole { get; } = botRole;
25 |
26 | private const string _permissionDeniedText = "You lack permission to execute this command.";
27 |
28 |
29 | ///
30 | public override Task CheckPermissionsAsync(ICommandContext context, CommandInfo commandInfo, IServiceProvider services)
31 | {
32 | var adminUtility = services.GetRequiredService();
33 |
34 | return BotRole switch
35 | {
36 | BotRole.Privileged => Task.FromResult(!adminUtility.UserIsPrivilaged(context.User)
37 | ? PreconditionResult.FromError(_permissionDeniedText)
38 | : PreconditionResult.FromSuccess()),
39 | BotRole.Administrator => Task.FromResult(!adminUtility.UserIsPrivilaged(context.User)
40 | ? PreconditionResult.FromError(_permissionDeniedText)
41 | : PreconditionResult.FromSuccess()),
42 | BotRole.Owner => Task.FromResult(!adminUtility.UserIsOwner(context.User)
43 | ? PreconditionResult.FromError(_permissionDeniedText)
44 | : PreconditionResult.FromSuccess()),
45 | _ => throw new ArgumentOutOfRangeException(nameof(BotRole), BotRole, null),
46 | };
47 |
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/commands/Modules/Commands/Support.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot.Commands.Public;
2 |
3 | using System;
4 | using System.Reflection;
5 | using System.Diagnostics;
6 | using System.Threading.Tasks;
7 | using System.Runtime.InteropServices;
8 |
9 | using Discord;
10 |
11 | using Discord.Commands;
12 |
13 | using Networking;
14 |
15 | using Extensions;
16 |
17 | ///
18 | /// Interaction handler for the support commands.
19 | ///
20 | ///
21 | /// Construct a new instance of .
22 | ///
23 | /// The .
24 | /// The .
25 | /// The .
26 | /// The .
27 | ///
28 | /// - cannot be null.
29 | /// - cannot be null.
30 | /// - cannot be null.
31 | /// - cannot be null.
32 | ///
33 | [Group("support"), Summary("Commands used for grid-bot-support.")]
34 | public class Support(
35 | GridSettings gridSettings,
36 | GlobalSettings globalSettings,
37 | ILocalIpAddressProvider localIpAddressProvider,
38 | IGridServerFileHelper gridServerFileHelper
39 | ) : ModuleBase
40 | {
41 | private readonly GridSettings _gridSettings = gridSettings ?? throw new ArgumentNullException(nameof(gridSettings));
42 | private readonly GlobalSettings _globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings));
43 | private readonly ILocalIpAddressProvider _localIpAddressProvider = localIpAddressProvider ?? throw new ArgumentNullException(nameof(localIpAddressProvider));
44 | private readonly IGridServerFileHelper _gridServerFileHelper = gridServerFileHelper ?? throw new ArgumentNullException(nameof(gridServerFileHelper));
45 |
46 | ///
47 | /// Gets informational links for the bot, in a stylish embed.
48 | ///
49 | [Command("info"), Summary("Get information about Grid Bot."), Alias("information", "about")]
50 | public async Task GetGeneralInformationAsync()
51 | {
52 | var entryAssembly = Assembly.GetEntryAssembly();
53 | var informationalVersion = entryAssembly.GetCustomAttribute().InformationalVersion;
54 |
55 | var gridServerVersion = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
56 | ? FileVersionInfo.GetVersionInfo(_gridServerFileHelper.GetFullyQualifiedGridServerPath()).FileVersion
57 | : _gridSettings.GridServerImageTag;
58 |
59 | var embed = new EmbedBuilder()
60 | .WithTitle("Grid Bot")
61 | .WithDescription("Grid Bot is a Discord bot that provides a variety of features for interacting with Roblox Grid Servers, such as thumbnailing and Luau execution.")
62 | .WithColor(Color.Blue)
63 | .WithFooter("Grid Bot Support")
64 | .WithCurrentTimestamp()
65 | .AddField("Grid Bot Support Guild", _globalSettings.SupportGuildDiscordUrl)
66 | .AddField("Grid Bot Support Hub", _globalSettings.SupportHubGitHubUrl)
67 | .AddField("Grid Bot Documentation", _globalSettings.DocumentationHubUrl)
68 | .AddField("Machine Name", Environment.MachineName)
69 | .AddField("Machine Host", _localIpAddressProvider.GetHostName())
70 | .AddField("Local IP Address", _localIpAddressProvider.AddressV4)
71 | .AddField("Bot Version", informationalVersion)
72 | .AddField("Grid Server Version", gridServerVersion)
73 | .Build();
74 |
75 | await this.ReplyWithReferenceAsync(embed: embed);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/commands/Modules/Interactions/Support.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot.Interactions.Public;
2 |
3 | using System;
4 | using System.Reflection;
5 | using System.Diagnostics;
6 | using System.Threading.Tasks;
7 | using System.Runtime.InteropServices;
8 |
9 | using Discord;
10 | using Discord.Interactions;
11 |
12 | using Networking;
13 |
14 | ///
15 | /// Interaction handler for the support commands.
16 | ///
17 | ///
18 | /// Construct a new instance of .
19 | ///
20 | /// The .
21 | /// The .
22 | /// The .
23 | /// The .
24 | ///
25 | /// - cannot be null.
26 | /// - cannot be null.
27 | /// - cannot be null.
28 | /// - cannot be null.
29 | ///
30 | [Group("support", "Commands used for grid-bot-support.")]
31 | [IntegrationType(ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall)]
32 | [CommandContextType(InteractionContextType.Guild, InteractionContextType.BotDm, InteractionContextType.PrivateChannel)]
33 | public class Support(
34 | GridSettings gridSettings,
35 | GlobalSettings globalSettings,
36 | ILocalIpAddressProvider localIpAddressProvider,
37 | IGridServerFileHelper gridServerFileHelper
38 | ) : InteractionModuleBase
39 | {
40 | private readonly GridSettings _gridSettings = gridSettings ?? throw new ArgumentNullException(nameof(gridSettings));
41 | private readonly GlobalSettings _globalSettings = globalSettings ?? throw new ArgumentNullException(nameof(globalSettings));
42 | private readonly ILocalIpAddressProvider _localIpAddressProvider = localIpAddressProvider ?? throw new ArgumentNullException(nameof(localIpAddressProvider));
43 | private readonly IGridServerFileHelper _gridServerFileHelper = gridServerFileHelper ?? throw new ArgumentNullException(nameof(gridServerFileHelper));
44 |
45 | ///
46 | /// Gets informational links for the bot, in a stylish embed.
47 | ///
48 | [SlashCommand("info", "Get information about Grid Bot.")]
49 | public async Task GetGeneralInformationAsync()
50 | {
51 | var entryAssembly = Assembly.GetEntryAssembly();
52 | var informationalVersion = entryAssembly.GetCustomAttribute().InformationalVersion;
53 |
54 | var gridServerVersion = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
55 | ? FileVersionInfo.GetVersionInfo(_gridServerFileHelper.GetFullyQualifiedGridServerPath()).FileVersion
56 | : _gridSettings.GridServerImageTag;
57 |
58 | var embed = new EmbedBuilder()
59 | .WithTitle("Grid Bot")
60 | .WithDescription("Grid Bot is a Discord bot that provides a variety of features for interacting with Roblox Grid Servers, such as thumbnailing and Luau execution.")
61 | .WithColor(Color.Blue)
62 | .WithFooter("Grid Bot Support")
63 | .WithCurrentTimestamp()
64 | .AddField("Grid Bot Support Guild", _globalSettings.SupportGuildDiscordUrl)
65 | .AddField("Grid Bot Support Hub", _globalSettings.SupportHubGitHubUrl)
66 | .AddField("Grid Bot Documentation", _globalSettings.DocumentationHubUrl)
67 | .AddField("Machine Name", Environment.MachineName)
68 | .AddField("Machine Host", _localIpAddressProvider.GetHostName())
69 | .AddField("Local IP Address", _localIpAddressProvider.AddressV4)
70 | .AddField("Bot Version", informationalVersion)
71 | .AddField("Grid Server Version", gridServerVersion)
72 | .Build();
73 |
74 | await FollowupAsync(embed: embed);
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/commands/Monitoring/RenderPerformanceCounters.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot;
2 |
3 | using Prometheus;
4 |
5 | internal class RenderPerformanceCounters
6 | {
7 | public static readonly Counter TotalRendersBlockedByGlobalFloodChecker = Metrics.CreateCounter(
8 | "renders_blocked_by_global_flood_checker_total",
9 | "The total number of renders blocked by the global flood checker."
10 | );
11 | public static readonly Counter TotalRendersBlockedByPerUserFloodChecker = Metrics.CreateCounter(
12 | "renders_blocked_by_per_user_flood_checker_total",
13 | "The total number of renders blocked by the per user flood checker.",
14 | "user_id"
15 | );
16 | public static readonly Counter TotalRenders = Metrics.CreateCounter(
17 | "renders_total",
18 | "The total number of renders.",
19 | "user_name_or_id"
20 | );
21 | public static readonly Counter TotalRendersViaUsername = Metrics.CreateCounter(
22 | "renders_via_username_total",
23 | "The total number of renders via username."
24 | );
25 | public static readonly Counter TotalRendersWithInvalidIds = Metrics.CreateCounter(
26 | "renders_with_invalid_ids_total",
27 | "The total number of renders with invalid IDs."
28 | );
29 | public static readonly Counter TotalRendersAgainstBannedUsers = Metrics.CreateCounter(
30 | "renders_against_banned_users_total",
31 | "The total number of renders against banned users.",
32 | "user_name_or_id"
33 | );
34 | public static readonly Counter TotalRendersWithErrors = Metrics.CreateCounter(
35 | "renders_with_errors_total",
36 | "The total number of renders with errors."
37 | );
38 | public static readonly Counter TotalRendersWithRbxThumbnailsErrors = Metrics.CreateCounter(
39 | "renders_with_rbx_thumbnails_errors_total",
40 | "The total number of renders with rbx-thumbnails errors.",
41 | "state"
42 | );
43 | }
--------------------------------------------------------------------------------
/services/grid-bot/lib/commands/Shared.Commands.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Shared library for commands used by grid-bot registered dynamically.
4 |
5 | true
6 |
7 |
8 |
9 | $(DefineConstants);WE_LOVE_EM_SLASH_COMMANDS
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/events/Shared.Events.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Library containg event objects that are dispatched via the Discord gateway.
4 |
5 | true
6 |
7 |
8 |
9 | $(DefineConstants);WE_LOVE_EM_SLASH_COMMANDS;DISCORD_SHARDING_ENABLED;DEBUG_LOGGING_IN_PROD;DEBUG_LOG_WEBSOCKET_CLOSED_EXCEPTIONS
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/grpc/Extensions/IServiceProviderExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot.Grpc;
2 |
3 | using System;
4 | using System.Threading.Tasks;
5 | using System.Collections.Generic;
6 | using System.Security.Authentication;
7 |
8 | using Microsoft.AspNetCore.Hosting;
9 | using Microsoft.AspNetCore.Builder;
10 | using Microsoft.AspNetCore.Server.Kestrel.Core;
11 |
12 | using Microsoft.Extensions.Logging;
13 | using Microsoft.Extensions.DependencyInjection;
14 |
15 | using Discord.WebSocket;
16 |
17 | using Logging;
18 | using Utility;
19 |
20 | ///
21 | /// gRPC extensions for the
22 | ///
23 | public static class IServiceProviderExtensions
24 | {
25 | ///
26 | /// Implement the grid-bot gRPC server into the current service provider.
27 | ///
28 | /// The
29 | /// The application arguments.
30 | public static void UseGrpcServer(this IServiceProvider services, IEnumerable args)
31 | {
32 | var grpcSettings = services.GetRequiredService();
33 | var logger = new Logger(
34 | name: grpcSettings.GrpcServerLoggerName,
35 | logLevelGetter: () => grpcSettings.GrpcServerLoggerLevel,
36 | logToConsole: true,
37 | logToFileSystem: false
38 | );
39 |
40 | if (!grpcSettings.GridBotGrpcServerEnabled)
41 | {
42 | logger.Warning("The grid-bot gRPC server is disabled in settings, not starting gRPC server!");
43 |
44 | return;
45 | }
46 |
47 | var client = services.GetRequiredService();
48 |
49 | logger.Information("Starting gRPC server on {0}", grpcSettings.GridBotGrpcServerEndpoint);
50 |
51 | var builder = WebApplication.CreateBuilder([.. args]);
52 |
53 | builder.Logging.ClearProviders();
54 | builder.Logging.AddProvider(new MicrosoftLoggerProvider(logger));
55 |
56 | builder.Services.AddSingleton(client);
57 |
58 | builder.Services.AddGrpc();
59 |
60 | if (grpcSettings.GrpcServerUseTls)
61 | {
62 | builder.Services.Configure(options =>
63 | {
64 | options.ConfigureEndpointDefaults(listenOptions =>
65 | {
66 | listenOptions.Protocols = HttpProtocols.Http2;
67 |
68 | try
69 | {
70 | listenOptions.UseHttps(grpcSettings.GrpcServerCertificatePath, grpcSettings.GrpcServerCertificatePassword, httpsOptions =>
71 | {
72 | httpsOptions.SslProtocols = SslProtocols.Tls13 | SslProtocols.Tls12;
73 | });
74 | }
75 | catch (Exception ex)
76 | {
77 | logger.Warning("Failed to configure gRPC with HTTPS because: {0}. Will resort to insecure host instead!", ex.Message);
78 | }
79 | });
80 | });
81 |
82 | // set urls
83 | }
84 | else
85 | {
86 | builder.Services.Configure(options =>
87 | {
88 | options.ConfigureEndpointDefaults(listenOptions =>
89 | {
90 | listenOptions.Protocols = HttpProtocols.Http2;
91 | });
92 | });
93 | }
94 |
95 | var app = builder.Build();
96 |
97 | app.MapGrpcService();
98 |
99 | Task.Factory.StartNew(() => app.Run(grpcSettings.GridBotGrpcServerEndpoint), TaskCreationOptions.LongRunning);
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/grpc/Grid.Bot.Grpc.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | gRPC server exposed by the mfdlabs grid bot.
4 | true
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | all
20 | runtime; build; native; contentfiles; analyzers; buildtransitive
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/grpc/Implementation/GridBotGrpcServer.cs:
--------------------------------------------------------------------------------
1 | using Grpc.Core;
2 |
3 | namespace Grid.Bot.Grpc;
4 |
5 | using System;
6 | using System.Linq;
7 | using System.Threading.Tasks;
8 |
9 | using Prometheus;
10 |
11 | using Discord;
12 | using Discord.WebSocket;
13 |
14 | using V1;
15 |
16 | ///
17 | /// The Grid Bot gRPC server implementation.
18 | ///
19 | ///
20 | /// Initializes a new instance of the class.
21 | ///
22 | /// The instance.
23 | /// Thrown when the is null.
24 | public class GridBotGrpcServer(DiscordShardedClient client) : GridBotAPI.GridBotAPIBase
25 | {
26 | private readonly DiscordShardedClient _client = client ?? throw new ArgumentNullException(nameof(client));
27 |
28 | private static readonly Counter _grpcServerRequestCounter = Metrics.CreateCounter(
29 | "grpc_health_check_requests_total",
30 | "Total number of gRPC health check requests"
31 | );
32 |
33 | ///
34 | public override Task CheckHealth(CheckHealthRequest request, ServerCallContext context)
35 | {
36 | _grpcServerRequestCounter.Inc();
37 |
38 | var response = new CheckHealthResponse();
39 |
40 | if (_client.LoginState == LoginState.LoggedOut || _client.LoginState == LoginState.LoggingOut || _client.LoginState == LoginState.LoggingIn)
41 | return Task.FromResult(response);
42 |
43 | try
44 | {
45 | response.Status = _client.Status.ToString();
46 | response.Latency = _client.Latency;
47 | response.Shards.AddRange(_client.Shards.Select(x => x.ShardId.ToString()).ToList());
48 | }
49 | catch (Exception)
50 | {
51 | response.Status = "error";
52 | response.Latency = 0;
53 | }
54 |
55 | return Task.FromResult(response);
56 | }
57 | }
--------------------------------------------------------------------------------
/services/grid-bot/lib/settings/EnvironmentProvider.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot;
2 |
3 | using System;
4 |
5 | ///
6 | /// Provides the environment name for the settings provider.
7 | ///
8 | public static class EnvironmentProvider
9 | {
10 | private const string _providerEnvironmentNameEnvVar = "ENVIRONMENT";
11 | private const string _nomadEnvironmentMetadataEnvVar = $"NOMAD_META_{_providerEnvironmentNameEnvVar}";
12 |
13 | private const string _defaultEnvironmentName = "development";
14 | private static readonly string _providerEnvironmentName =
15 | Environment.GetEnvironmentVariable(_providerEnvironmentNameEnvVar)
16 | ?? Environment.GetEnvironmentVariable(_nomadEnvironmentMetadataEnvVar)
17 | ?? _defaultEnvironmentName;
18 |
19 | ///
20 | /// Gets the environment name for the settings provider.
21 | ///
22 | public static string EnvironmentName => _providerEnvironmentName;
23 | }
--------------------------------------------------------------------------------
/services/grid-bot/lib/settings/Providers/BacktraceSettings.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot;
2 |
3 | ///
4 | /// Settings provider for all Backtrace related stuff.
5 | ///
6 | public class BacktraceSettings : BaseSettingsProvider
7 | {
8 | ///
9 | public override string Path => SettingsProvidersDefaults.BacktracePath;
10 |
11 | ///
12 | /// Gets the percentage to upload log files to Backtrace.
13 | ///
14 | public int UploadLogFilesToBacktraceEnabledPercent => GetOrDefault(
15 | nameof(UploadLogFilesToBacktraceEnabledPercent),
16 | 100
17 | );
18 |
19 | ///
20 | /// Gets the url for Backtrace.
21 | ///
22 | public string BacktraceUrl => GetOrDefault(
23 | nameof(BacktraceUrl),
24 | "http://mfdlabs.sp.backtrace.io:6097"
25 | );
26 |
27 | ///
28 | /// Gets the backtrace token.
29 | ///
30 | public string BacktraceToken => GetOrDefault(
31 | nameof(BacktraceToken),
32 | "9f55e8c1e2a0bc06f874371f33d7c24e38b88c48f3c3cd853fc95174a13beb9b"
33 | );
34 | }
35 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/settings/Providers/BaseSettingsProvider.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot;
2 |
3 | using System.Collections.Generic;
4 |
5 | using Configuration;
6 |
7 | ///
8 | /// Base provider class for grid operations.
9 | ///
10 | public abstract class BaseSettingsProvider : VaultProvider
11 | {
12 | ///
13 | public override string Mount => SettingsProvidersDefaults.MountPath;
14 |
15 | ///
16 | /// Construct a new instance of
17 | ///
18 | protected BaseSettingsProvider()
19 | : base(Logging.Logger.Singleton)
20 | {
21 | }
22 |
23 | ///
24 | /// Gets the raw values associated with this settings provider.
25 | ///
26 | /// Te raw values.
27 | public IDictionary GetRawValues() => _CachedValues;
28 | }
29 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/settings/Providers/ClientSettingsSettings.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot;
2 |
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | ///
7 | /// Settings provider for client-settings
8 | ///
9 | public class ClientSettingsSettings : BaseSettingsProvider
10 | {
11 | ///
12 | public override string Path => SettingsProvidersDefaults.ClientSettingsPath;
13 |
14 |
15 | ///
16 | /// Determines if data access should be via Vault or local JSON files.
17 | ///
18 | public bool ClientSettingsViaVault => GetOrDefault(nameof(ClientSettingsViaVault), false);
19 |
20 | ///
21 | /// Gets the Vault mount for the client settings.
22 | ///
23 | public string ClientSettingsVaultMount => GetOrDefault(nameof(ClientSettingsVaultMount), "client-settings");
24 |
25 | ///
26 | /// Gets the absolute path to the client settings vault path.
27 | ///
28 | public string ClientSettingsVaultPath => GetOrDefault(nameof(ClientSettingsVaultPath), "/");
29 |
30 | ///
31 | /// Gets the Vault address for the client settings.
32 | ///
33 | public string ClientSettingsVaultAddress => GetOrDefault(nameof(ClientSettingsVaultAddress), Environment.GetEnvironmentVariable("VAULT_ADDR"));
34 |
35 | ///
36 | /// Gets the Vault token for the client settings.
37 | ///
38 | public string ClientSettingsVaultToken => GetOrDefault(nameof(ClientSettingsVaultToken), Environment.GetEnvironmentVariable("VAULT_TOKEN"));
39 |
40 | ///
41 | /// Gets the refresh interval for the client settings factory.
42 | ///
43 | public TimeSpan ClientSettingsRefreshInterval => GetOrDefault(nameof(ClientSettingsRefreshInterval), TimeSpan.FromSeconds(30));
44 |
45 | ///
46 | /// Gets the absolute path to the client settings configuration file if is false.
47 | ///
48 | public string ClientSettingsFilePath => GetOrDefault(nameof(ClientSettingsFilePath), "/var/cache/mfdlabs/client-settings.json");
49 |
50 | ///
51 | /// Resolves the dependency maps for specific application settings.
52 | ///
53 | ///
54 | /// The value is formatted like this:
55 | ///
56 | /// Group1=Group2,Group3
57 | /// Group2=Group4
58 | ///
59 | ///
60 | public Dictionary ClientSettingsApplicationDependencies => GetOrDefault(nameof(ClientSettingsApplicationDependencies), new Dictionary());
61 |
62 | ///
63 | /// A list of application names that can be read from the API endpoints.
64 | ///
65 | public string[] PermissibleReadApplications
66 | {
67 | get => GetOrDefault(nameof(PermissibleReadApplications), Array.Empty());
68 | set => Set(nameof(PermissibleReadApplications), value);
69 | }
70 |
71 | ///
72 | /// Gets a command seperated list of API keys that can be used for reading non-permissable applications,
73 | /// as well as executing privalaged commands.
74 | ///
75 | /// If this is empty, it will leave endpoints open!!!
76 | public string[] ClientSettingsApiKeys => GetOrDefault(nameof(ClientSettingsApiKeys), Array.Empty());
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/settings/Providers/CommandsSettings.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot;
2 |
3 | using System;
4 |
5 | ///
6 | /// Settings provider for all commands related stuff.
7 | ///
8 | public class CommandsSettings : BaseSettingsProvider
9 | {
10 | ///
11 | public override string Path => SettingsProvidersDefaults.CommandsPath;
12 |
13 | ///
14 | /// Determines whether or not lockdown commands are enabled.
15 | ///
16 | public bool EnableLockdownCommands => GetOrDefault(
17 | nameof(EnableLockdownCommands),
18 | true
19 | );
20 |
21 | ///
22 | /// Gets the ID of the guild to use for lockdown commands.
23 | ///
24 | public ulong LockdownGuildId => GetOrDefault(
25 | nameof(LockdownGuildId),
26 | 0UL
27 | );
28 |
29 | ///
30 | /// Gets the command prefix.
31 | ///
32 | public string Prefix => GetOrDefault(
33 | nameof(Prefix),
34 | ">"
35 | );
36 |
37 | ///
38 | /// The text to respond with when commands are disabled and the is true.
39 | ///
40 | public string TextCommandsDisabledWarningText => GetOrDefault(
41 | nameof(TextCommandsDisabledWarningText),
42 | string.Empty
43 | );
44 |
45 | ///
46 | /// Determines whether or not text based commands should be enabled.
47 | ///
48 | ///
49 | /// If this is disabled, the commands module will not be loaded, therefore this cannot
50 | /// be used to dynamically load commands.
51 | ///
52 | /// If you wish to consume commands, then this must be enabled before the last shard
53 | /// within the connection pool has completed its initialization phase.
54 | ///
55 | /// If is false and this is false, then the bot
56 | /// will not respond to any text based commands whatever. Otherwise, it will respond with the text
57 | /// defined in on each subsequent attempt of text
58 | /// usage.
59 | ///
60 | public bool EnableTextCommands => GetOrDefault(
61 | nameof(EnableTextCommands),
62 | true
63 | );
64 |
65 | ///
66 | /// Determines whether or not the bot should warn the user when commands are disabled.
67 | ///
68 | ///
69 | /// This is only applicable when is false.
70 | ///
71 | public bool ShouldWarnWhenCommandsAreDisabled => GetOrDefault(
72 | nameof(ShouldWarnWhenCommandsAreDisabled),
73 | true
74 | );
75 | }
76 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/settings/Providers/ConsulSettings.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot;
2 |
3 | using System;
4 |
5 | using Configuration;
6 |
7 | using IServiceDiscoverySettings = global::ServiceDiscovery.ISettings;
8 |
9 | ///
10 | /// Settings provider for all Consul related stuff.
11 | ///
12 | public class ConsulSettings : BaseSettingsProvider, IServiceDiscoverySettings
13 | {
14 | ///
15 | public override string Path => SettingsProvidersDefaults.ConsulPath;
16 |
17 | ///
18 | [SettingName("CONSUL_ADDR")]
19 | public string ConsulAddress => GetOrDefault(
20 | "CONSUL_ADDR", // Accom for local ENV var.
21 | "http://127.0.0.1:8500"
22 | );
23 |
24 | ///
25 | public TimeSpan ConsulBackoffBase => GetOrDefault(
26 | nameof(ConsulBackoffBase),
27 | TimeSpan.FromMilliseconds(1)
28 | );
29 |
30 | ///
31 | public TimeSpan ConsulLongPollingMaxWaitTime => GetOrDefault(
32 | nameof(ConsulLongPollingMaxWaitTime),
33 | TimeSpan.FromMinutes(5)
34 | );
35 |
36 | ///
37 | public TimeSpan MaximumConsulBackoff => GetOrDefault(
38 | nameof(MaximumConsulBackoff),
39 | TimeSpan.FromSeconds(30)
40 | );
41 | }
42 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/settings/Providers/DiscordRolesSettings.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot;
2 |
3 | using System;
4 |
5 | ///
6 | /// Settings provider for all Discord roles related stuff.
7 | ///
8 | public class DiscordRolesSettings : BaseSettingsProvider
9 | {
10 | ///
11 | public override string Path => SettingsProvidersDefaults.DiscordRolesPath;
12 |
13 | ///
14 | /// Gets or sets the admin user ids.
15 | ///
16 | public ulong[] AdminUserIds
17 | {
18 | get => GetOrDefault(nameof(AdminUserIds), Array.Empty());
19 | set => Set(nameof(AdminUserIds), value);
20 | }
21 |
22 | ///
23 | /// Gets or sets the blacklisted user ids.
24 | ///
25 | public ulong[] BlacklistedUserIds
26 | {
27 | get => GetOrDefault(nameof(BlacklistedUserIds), Array.Empty());
28 | set => Set(nameof(BlacklistedUserIds), value);
29 | }
30 |
31 | ///
32 | /// Gets or sets the higher privilaged user ids.
33 | ///
34 | public ulong[] HigherPrivilagedUserIds
35 | {
36 | get => GetOrDefault(nameof(HigherPrivilagedUserIds), Array.Empty());
37 | set => Set(nameof(HigherPrivilagedUserIds), value);
38 | }
39 |
40 | ///
41 | /// Gets the bot owner id.
42 | ///
43 | public ulong BotOwnerId => GetOrDefault(nameof(BotOwnerId), default(ulong));
44 |
45 | ///
46 | /// Gets the ID of the role that is used to create notifications for alerts.
47 | ///
48 | public ulong AlertRoleId => GetOrDefault(nameof(AlertRoleId), default(ulong));
49 | }
50 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/settings/Providers/DiscordSettings.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot;
2 |
3 | using System;
4 |
5 | using Discord;
6 | using Logging;
7 |
8 | ///
9 | /// Settings provider for all Discord related stuff.
10 | ///
11 | public class DiscordSettings : BaseSettingsProvider
12 | {
13 | ///
14 | public override string Path => SettingsProvidersDefaults.DiscordPath;
15 |
16 | ///
17 | /// Gets the bot token.
18 | ///
19 | /// The setting is required!
20 | public string BotToken => GetOrDefault(
21 | nameof(BotToken),
22 | #if DEBUG
23 | string.Empty
24 | #else
25 | () => throw new InvalidOperationException($"Environment Variable {nameof(BotToken)} is required!")
26 | #endif
27 | );
28 |
29 | #if DEBUG || DEBUG_LOGGING_IN_PROD
30 | ///
31 | /// Can task cancelled exceptions be loggeD?
32 | ///
33 | public bool DebugAllowTaskCanceledExceptions => GetOrDefault(
34 | nameof(DebugAllowTaskCanceledExceptions),
35 | false
36 | );
37 | #endif
38 |
39 | #if DEBUG
40 |
41 | ///
42 | /// Gets the ID of the guild to register slash commands in.
43 | ///
44 | ///
45 | /// This is only valid for debug builds.
46 | /// If this is 0, then the bot will not register slash commands.
47 | ///
48 | public ulong DebugGuildId => GetOrDefault(
49 | nameof(DebugGuildId),
50 | 0UL
51 | );
52 |
53 | ///
54 | /// Determines if the bot should not be enabled.
55 | ///
56 | ///
57 | /// This is only valid for debug builds.
58 | /// If this is true, then the bot will not be enabled.
59 | ///
60 | public bool DebugBotDisabled => GetOrDefault(
61 | nameof(DebugBotDisabled),
62 | false
63 | );
64 |
65 | #endif
66 |
67 | ///
68 | /// Should discord internals be logged?
69 | ///
70 | public bool ShouldLogDiscordInternals => GetOrDefault(
71 | nameof(ShouldLogDiscordInternals),
72 | true
73 | );
74 |
75 | ///
76 | /// Gets the of the bot.
77 | ///
78 | public UserStatus BotStatus => GetOrDefault(
79 | nameof(BotStatus),
80 | UserStatus.Online
81 | );
82 |
83 | ///
84 | /// Gets the status message of the bot.
85 | ///
86 | public string BotStatusMessage => GetOrDefault(
87 | nameof(BotStatusMessage),
88 | string.Empty
89 | );
90 |
91 | ///
92 | /// Gets the name of the
93 | ///
94 | public string DiscordLoggerName => GetOrDefault(
95 | nameof(DiscordLoggerName),
96 | "discord"
97 | );
98 |
99 | ///
100 | /// Gets the of the
101 | ///
102 | public LogLevel DiscordLoggerLogLevel => GetOrDefault(
103 | nameof(DiscordLoggerLogLevel),
104 | LogLevel.Information
105 | );
106 |
107 | ///
108 | /// Should the log to console?
109 | ///
110 | public bool DiscordLoggerLogToConsole => GetOrDefault(
111 | nameof(DiscordLoggerLogToConsole),
112 | true
113 | );
114 | }
115 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/settings/Providers/GlobalSettings.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot;
2 |
3 | using System;
4 |
5 | using Configuration;
6 |
7 | using Logging;
8 |
9 | ///
10 | /// Settings provider for global entrypoint stuff.
11 | ///
12 | public class GlobalSettings : BaseSettingsProvider
13 | {
14 | ///
15 | public override string Path => SettingsProvidersDefaults.GlobalPath;
16 |
17 | ///
18 | /// Gets the name of the default logger.
19 | ///
20 | public string DefaultLoggerName => GetOrDefault(
21 | nameof(DefaultLoggerName),
22 | "bot"
23 | );
24 |
25 | ///
26 | /// Gets the log level for the default logger.
27 | ///
28 | public LogLevel DefaultLoggerLevel => GetOrDefault(
29 | nameof(DefaultLoggerLevel),
30 | LogLevel.Information
31 | );
32 |
33 | ///
34 | /// Gets the port for the metrics server.
35 | ///
36 | public int MetricsPort => GetOrDefault(
37 | nameof(MetricsPort),
38 | 8081
39 | );
40 |
41 | ///
42 | /// Should the default logger log to console?
43 | ///
44 | public bool DefaultLoggerLogToConsole => GetOrDefault(
45 | nameof(DefaultLoggerLogToConsole),
46 | true
47 | );
48 |
49 | ///
50 | /// Gets the Discord URL for the primary support guild.
51 | ///
52 | public string SupportGuildDiscordUrl => GetOrDefault(
53 | nameof(SupportGuildDiscordUrl),
54 | "https://discord.gg/hdg2z6bm5c"
55 | );
56 |
57 | ///
58 | /// Gets the GitHub url for the support hub.
59 | ///
60 | public string SupportHubGitHubUrl => GetOrDefault(
61 | nameof(SupportHubGitHubUrl),
62 | "https://github.com/mfdlabs/grid-bot-support"
63 | );
64 |
65 | ///
66 | /// Gets the Url for the documentation hub.
67 | ///
68 | public string DocumentationHubUrl => GetOrDefault(
69 | nameof(DocumentationHubUrl),
70 | "https://grid-bot.ops.vmminfra.net"
71 | );
72 |
73 | ///
74 | /// Is alerting via Discord webhook enabled?
75 | ///
76 | public bool DiscordWebhookAlertingEnabled => GetOrDefault(
77 | nameof(DiscordWebhookAlertingEnabled),
78 | false
79 | );
80 |
81 | ///
82 | /// Gets the Discord webhook URL for alerts.
83 | ///
84 | public string DiscordWebhookUrl => GetOrDefault(
85 | nameof(DiscordWebhookUrl),
86 | string.Empty
87 | );
88 | }
89 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/settings/Providers/GrpcSettings.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot;
2 |
3 | using System;
4 |
5 | using Logging;
6 |
7 | ///
8 | /// Settings provider for all gRPC Server related stuff.
9 | ///
10 | public class GrpcSettings : BaseSettingsProvider
11 | {
12 | ///
13 | public override string Path => SettingsProvidersDefaults.GrpcPath;
14 |
15 | ///
16 | /// Determines if the grid-bot grpc server should be enabled or not.
17 | ///
18 | public bool GridBotGrpcServerEnabled => GetOrDefault(
19 | nameof(GridBotGrpcServerEnabled),
20 | false
21 | );
22 |
23 | ///
24 | /// Gets the endpoint for the Grid Bot gRPC server.
25 | ///
26 | public string GridBotGrpcServerEndpoint => GetOrDefault(
27 | nameof(GridBotGrpcServerEndpoint),
28 | "http://+:5000"
29 | );
30 |
31 | ///
32 | /// ASP.NET Core logger name for the gRPC server.
33 | ///
34 | public string GrpcServerLoggerName => GetOrDefault(
35 | nameof(GrpcServerLoggerName),
36 | "grpc"
37 | );
38 |
39 | ///
40 | /// ASP.NET Core logger level for the gRPC server.
41 | ///
42 | public LogLevel GrpcServerLoggerLevel => GetOrDefault(
43 | nameof(GrpcServerLoggerLevel),
44 | LogLevel.Information
45 | );
46 |
47 | ///
48 | /// Determines if the gRPC server should use TLS.
49 | ///
50 | public bool GrpcServerUseTls => GetOrDefault(
51 | nameof(GrpcServerUseTls),
52 | true
53 | );
54 |
55 | ///
56 | /// Gets the certificate path for the gRPC server.
57 | ///
58 | public string GrpcServerCertificatePath => GetOrDefault(
59 | nameof(GrpcServerCertificatePath),
60 | () => throw new InvalidOperationException($"'{nameof(GrpcServerCertificatePath)}' is required when '{nameof(GrpcServerUseTls)}' is true.")
61 | );
62 |
63 | ///
64 | /// Gets the certificate password for the gRPC server.
65 | ///
66 | public string GrpcServerCertificatePassword => GetOrDefault(
67 | nameof(GrpcServerCertificatePassword),
68 | () => throw new InvalidOperationException($"'{nameof(GrpcServerCertificatePassword)}' is required when '{nameof(GrpcServerUseTls)}' is true.")
69 | );
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/settings/Providers/MaintenanceSettings.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot;
2 |
3 | ///
4 | /// Settings provider for all maintenance related stuff.
5 | ///
6 | public class MaintenanceSettings : BaseSettingsProvider
7 | {
8 | ///
9 | public override string Path => SettingsProvidersDefaults.MaintenancePath;
10 |
11 | ///
12 | /// Is maintenance enabled?
13 | ///
14 | public bool MaintenanceEnabled
15 | {
16 | get => GetOrDefault(nameof(MaintenanceEnabled), false);
17 | set => Set(nameof(MaintenanceEnabled), value);
18 | }
19 |
20 | ///
21 | /// Gets or sets the maintenance status message.
22 | ///
23 | public string MaintenanceStatus
24 | {
25 | get => GetOrDefault(nameof(MaintenanceStatus), string.Empty);
26 | set => Set(nameof(MaintenanceStatus), value);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/settings/Providers/ScriptsSettings.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot;
2 |
3 | using System;
4 |
5 | ///
6 | /// Settings provider for all script execution related stuff.
7 | ///
8 | public class ScriptsSettings : BaseSettingsProvider
9 | {
10 | ///
11 | public override string Path => SettingsProvidersDefaults.ScriptsPath;
12 |
13 | ///
14 | /// Gets the max size for a script used by the Execute Script commands in KiB.
15 | ///
16 | public int ScriptExecutionMaxFileSizeKb => GetOrDefault(
17 | nameof(ScriptExecutionMaxFileSizeKb),
18 | 75
19 | );
20 |
21 | ///
22 | /// Gets the max size for the result file used by the Execute Script command in KiB.
23 | ///
24 | public int ScriptExecutionMaxResultSizeKb => GetOrDefault(
25 | nameof(ScriptExecutionMaxResultSizeKb),
26 | 50
27 | );
28 |
29 | ///
30 | /// Determines if the LuaVM is enabled.
31 | ///
32 | public bool LuaVMEnabled => GetOrDefault(
33 | nameof(LuaVMEnabled),
34 | true
35 | );
36 |
37 | ///
38 | /// Gets the percentage to use for logging scripts.
39 | ///
40 | public int ScriptLoggingPercentage => GetOrDefault(
41 | nameof(ScriptLoggingPercentage),
42 | 0
43 | );
44 |
45 | ///
46 | /// Gets a Discord webhook URL to send script logs to.
47 | ///
48 | public string ScriptLoggingDiscordWebhookUrl => GetOrDefault(
49 | nameof(ScriptLoggingDiscordWebhookUrl),
50 | string.Empty
51 | );
52 |
53 | ///
54 | /// Gets or sets a list of hashes of scripts that have already been logged and should not be logged again.
55 | ///
56 | public string[] LoggedScriptHashes
57 | {
58 | get => GetOrDefault(
59 | nameof(LoggedScriptHashes),
60 | Array.Empty()
61 | );
62 | set => Set(nameof(LoggedScriptHashes), value);
63 | }
64 |
65 | ///
66 | /// Gets the interval to persist the logged script hashes.
67 | ///
68 | public TimeSpan LoggedScriptHashesPersistInterval => GetOrDefault(
69 | nameof(LoggedScriptHashesPersistInterval),
70 | TimeSpan.FromMinutes(5)
71 | );
72 | }
73 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/settings/Providers/UsersClientSettings.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot;
2 |
3 | ///
4 | /// Settings provider for settings used by the Roblox Users API.
5 | ///
6 | public class UsersClientSettings : BaseSettingsProvider
7 | {
8 | ///
9 | public override string Path => SettingsProvidersDefaults.UsersClientPath;
10 |
11 | ///
12 | /// Gets the base url for the Users ApiSite.
13 | ///
14 | public string UsersApiBaseUrl => GetOrDefault(
15 | nameof(UsersApiBaseUrl),
16 | "https://users.roblox.com"
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/settings/Providers/WebSettings.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot;
2 |
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | using Logging;
7 |
8 | ///
9 | /// Settings provider for all Web Server related stuff.
10 | ///
11 | public class WebSettings : BaseSettingsProvider
12 | {
13 | ///
14 | public override string Path => SettingsProvidersDefaults.WebPath;
15 |
16 | ///
17 | /// Determines if the web server should be enabled.
18 | ///
19 | public bool IsWebServerEnabled => GetOrDefault(nameof(IsWebServerEnabled), true);
20 |
21 | ///
22 | /// Gets the bind address for the web server.
23 | ///
24 | public string WebServerBindAddress => GetOrDefault(nameof(WebServerBindAddress), "http://+:8888");
25 |
26 | ///
27 | /// Determines if the web server is behind a reverse proxy.
28 | ///
29 | ///
30 | /// If true, then x-forwarded-for and x-forwarded-proto headers will be used to determine the client IP address.
31 | ///
32 | public bool IsWebServerBehindProxy => GetOrDefault(nameof(IsWebServerBehindProxy), false);
33 |
34 | ///
35 | /// Gets the list of allowed proxy networks.
36 | ///
37 | public string[] WebServerAllowedProxyRanges => GetOrDefault(nameof(WebServerAllowedProxyRanges), new[] { "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16" });
38 |
39 | ///
40 | /// Determines if the web server should use TLS.
41 | ///
42 | ///
43 | /// This should be set to true always in post-2017 grid servers
44 | /// if this is the standard web server.
45 | ///
46 | public bool WebServerUseTls => GetOrDefault(nameof(WebServerUseTls), false);
47 |
48 | ///
49 | /// Gets the path to the PFX certificate for the web server.
50 | ///
51 | public string WebServerCertificatePath => GetOrDefault(
52 | nameof(WebServerCertificatePath),
53 | () => throw new InvalidOperationException($"'{nameof(WebServerCertificatePath)}' is required when '{nameof(WebServerUseTls)}' is true.")
54 | );
55 |
56 | ///
57 | /// Gets the password for the PFX certificate for the web server.
58 | ///
59 | public string WebServerCertificatePassword => GetOrDefault(
60 | nameof(WebServerCertificatePassword),
61 | () => throw new InvalidOperationException($"'{nameof(WebServerCertificatePassword)}' is required when '{nameof(WebServerUseTls)}' is true.")
62 | );
63 |
64 | ///
65 | /// Gets the ASP.NET Core logger name for the web server.
66 | ///
67 | public string WebServerLoggerName => GetOrDefault(nameof(WebServerLoggerName), "web");
68 |
69 | ///
70 | /// Gets the ASP.NET Core logger level for the web server.
71 | ///
72 | public LogLevel WebServerLoggerLevel => GetOrDefault(nameof(WebServerLoggerLevel), LogLevel.Information);
73 | }
74 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/settings/SettingsProvidersDefaults.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot;
2 |
3 | using System;
4 |
5 | internal static class SettingsProvidersDefaults
6 | {
7 | private const string _vaultMountEnvVar = "VAULT_MOUNT";
8 |
9 | public static string DiscordPath => $"{EnvironmentProvider.EnvironmentName}/discord";
10 | public static string DiscordRolesPath => $"{EnvironmentProvider.EnvironmentName}/discord-roles";
11 | public static string AvatarPath => $"{EnvironmentProvider.EnvironmentName}/avatar";
12 | public static string GridPath => $"{EnvironmentProvider.EnvironmentName}/grid";
13 | public static string BacktracePath => $"{EnvironmentProvider.EnvironmentName}/backtrace";
14 | public static string MaintenancePath => $"{EnvironmentProvider.EnvironmentName}/maintenance";
15 | public static string CommandsPath => $"{EnvironmentProvider.EnvironmentName}/commands";
16 | public static string FloodCheckerPath => $"{EnvironmentProvider.EnvironmentName}/floodcheckers";
17 | public static string ConsulPath => $"{EnvironmentProvider.EnvironmentName}/consul";
18 | public static string UsersClientPath => $"{EnvironmentProvider.EnvironmentName}/users-client";
19 | public static string ScriptsPath => $"{EnvironmentProvider.EnvironmentName}/scripts";
20 | public static string ClientSettingsPath => $"{EnvironmentProvider.EnvironmentName}/client-settings";
21 | public static string GlobalPath => $"{EnvironmentProvider.EnvironmentName}/global";
22 | public static string WebPath => $"{EnvironmentProvider.EnvironmentName}/web";
23 | public static string GrpcPath => $"{EnvironmentProvider.EnvironmentName}/grpc";
24 |
25 | public const string DefaultMountPath = "grid-bot-settings";
26 | public static string MountPath = Environment.GetEnvironmentVariable(_vaultMountEnvVar) ?? DefaultMountPath;
27 | }
28 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/settings/Shared.Settings.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Shared library containing settings used by the grid-bot
4 |
5 | true
6 | $(NoWarn);1591
7 |
8 |
9 |
10 | $(DefineConstants);DEBUG_LOGGING_IN_PROD
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/utility/Enums/BotRole.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot.Utility;
2 |
3 | ///
4 | /// Bot role.
5 | ///
6 | public enum BotRole
7 | {
8 | ///
9 | /// Default role. Used for everyone.
10 | ///
11 | Default,
12 |
13 | ///
14 | /// A privileged role. Mostly used for testers.
15 | ///
16 | Privileged,
17 |
18 | ///
19 | /// Administrator role. Used for administrators.
20 | ///
21 | Administrator,
22 |
23 | ///
24 | /// Owner role. Used for the owner of the bot.
25 | ///
26 | Owner
27 | }
28 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/utility/Enums/FilterType.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot.Utility;
2 |
3 | ///
4 | /// Type of a client setting filter.
5 | ///
6 | public enum FilterType
7 | {
8 | ///
9 | /// The filter is filtering places. _PlaceFilter
10 | ///
11 | Place,
12 |
13 | ///
14 | /// The filter is filtering datacenters. _DataCenterFilter
15 | ///
16 | DataCenter
17 | }
18 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/utility/Enums/SettingType.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot.Utility;
2 |
3 | ///
4 | /// The type of a setting.
5 | ///
6 | public enum SettingType
7 | {
8 | ///
9 | /// String type setting -- default.
10 | ///
11 | String,
12 |
13 | ///
14 | /// Boolean type setting -- a flag.
15 | ///
16 | Bool,
17 |
18 | ///
19 | /// Integer type setting.
20 | ///
21 | Int
22 | }
23 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/utility/Extensions/DictionaryExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot.Extensions;
2 |
3 | using System.Linq;
4 | using System.Collections.Generic;
5 |
6 | ///
7 | /// Extension methods for Dictionary.
8 | ///
9 | public static class DictionaryExtensions
10 | {
11 | ///
12 | /// Merges the current dictionary with others, left to right.
13 | /// If a key exists in multiple dictionaries, the value from the last one will be used.
14 | ///
15 | /// The type of the dictionary.
16 | /// The type of the key.
17 | /// The type of the value.
18 | /// The current dictionary.
19 | /// The dictionaries to merge with.
20 | /// A new dictionary containing the merged key-value pairs.
21 | public static T MergeLeft(this T me, params IDictionary[] others)
22 | where T : IDictionary, new()
23 | {
24 | var newMap = new T();
25 |
26 | foreach (IDictionary src in new List> { me }.Concat(others))
27 | {
28 | // ^-- echk. Not quite there type-system.
29 | foreach (KeyValuePair p in src)
30 | {
31 | newMap[p.Key] = p.Value;
32 | }
33 | }
34 |
35 | return newMap;
36 | }
37 | }
--------------------------------------------------------------------------------
/services/grid-bot/lib/utility/Extensions/IAttachmentExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot.Extensions;
2 |
3 | using System.Text;
4 | using System.Net.Http;
5 | using System.Threading.Tasks;
6 |
7 | using Discord;
8 |
9 | ///
10 | /// Extension methods for
11 | ///
12 | public static class IAttachmentExtensions
13 | {
14 | ///
15 | /// Gets the data for the
16 | ///
17 | /// The
18 | /// The raw bytes of the
19 | public static async Task GetRawAttachmentBuffer(this IAttachment attachment)
20 | {
21 | using var client = new HttpClient();
22 |
23 | return await client.GetByteArrayAsync(attachment.Url);
24 | }
25 |
26 | ///
27 | /// Gets the data from the and returns an ASCII string.
28 | ///
29 | /// The
30 | /// The raw string.
31 | public static async Task GetAttachmentContentsAscii(this IAttachment attachment)
32 | => Encoding.ASCII.GetString(await attachment.GetRawAttachmentBuffer());
33 | }
34 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/utility/Extensions/IUserMessageExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot.Extensions;
2 |
3 | using System.IO;
4 | using System.Threading.Tasks;
5 |
6 | using Discord;
7 |
8 | ///
9 | /// Extension methods for
10 | ///
11 | public static class IUserMessageExtensions
12 | {
13 | ///
14 | /// Sends an inline reply that references a message.
15 | ///
16 | /// The message that is being replied on.
17 | /// The stream of the file to send.
18 | /// The name of the file to send.
19 | /// The message to be sent.
20 | /// Determines whether the message should be read aloud by Discord or not.
21 | /// The to be sent.
22 | /// A array of s to send with this response. Max 10.
23 | ///
24 | /// Specifies if notifications are sent for mentioned users and roles in the message .
25 | /// If , all mentioned roles and users will be notified.
26 | ///
27 | /// The options to be used when sending the request.
28 | /// Determines whether the file should be sent as a spoiler or not.
29 | /// The message components to be included with this message. Used for interactions.
30 | /// A collection of stickers to send with the message.
31 | /// Message flags combined as a bitfield.
32 | ///
33 | /// A task that represents an asynchronous send operation for delivering the message. The task result
34 | /// contains the sent message.
35 | ///
36 | public static Task ReplyWithFileAsync(
37 | this IUserMessage msg,
38 | Stream fileStream,
39 | string fileName,
40 | string text = null,
41 | bool isTTS = false,
42 | Embed embed = null,
43 | AllowedMentions allowedMentions = null,
44 | RequestOptions options = null,
45 | bool isSpoiler = false,
46 | MessageComponent components = null,
47 | ISticker[] stickers = null,
48 | Embed[] embeds = null,
49 | MessageFlags flags = MessageFlags.None
50 | )
51 | => msg.Channel.SendFileAsync(
52 | fileStream,
53 | fileName,
54 | text,
55 | isTTS,
56 | embed,
57 | options,
58 | isSpoiler,
59 | allowedMentions,
60 | new MessageReference(messageId: msg.Id),
61 | components,
62 | stickers,
63 | embeds,
64 | flags
65 | );
66 | }
--------------------------------------------------------------------------------
/services/grid-bot/lib/utility/Extensions/SocketInteractionExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot.Extensions;
2 |
3 | using Discord;
4 | using Discord.WebSocket;
5 |
6 | using Threading.Extensions;
7 |
8 | ///
9 | /// Extension methods for
10 | ///
11 | public static class SocketInteractionExtensions
12 | {
13 | ///
14 | /// Gets the from the , taking private threads into consideration.
15 | ///
16 | /// The current
17 | /// An
18 | public static IMessageChannel GetChannel(this SocketInteraction interaction)
19 | => interaction.Channel ?? interaction.InteractionChannel;
20 |
21 | ///
22 | /// Gets the channel from the , taking private threads into consideration.
23 | ///
24 | /// The current
25 | /// A string version of either or
26 | public static string GetChannelAsString(this SocketInteraction interaction)
27 | => interaction.GetChannel().ToString();
28 |
29 | ///
30 | /// Gets an for a specific , taking private threads into consideration.
31 | ///
32 | ///
33 | ///
34 | ///
35 | public static IGuild GetGuild(this SocketInteraction interaction, IDiscordClient client)
36 | {
37 | if (interaction.GuildId == null) return null;
38 |
39 | if (interaction.Channel is SocketGuildChannel guildChannel)
40 | return guildChannel.Guild;
41 |
42 | return client.GetGuildAsync(interaction.GuildId.Value).SyncOrDefault();
43 | }
44 | }
--------------------------------------------------------------------------------
/services/grid-bot/lib/utility/Implementation/BacktraceUtility.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot.Utility;
2 |
3 | using System;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 |
8 | using Prometheus;
9 |
10 | using Backtrace;
11 | using Backtrace.Model;
12 | using Backtrace.Interfaces;
13 |
14 | using Logging;
15 | using FileSystem;
16 |
17 | ///
18 | /// Utility for interacting with Backtrace.
19 | ///
20 | public class BacktraceUtility : IBacktraceUtility
21 | {
22 | private readonly ILogger _logger;
23 | private readonly BacktraceClient _client;
24 |
25 | private static readonly Counter _uploadExceptionCounter = Metrics.CreateCounter(
26 | "backtrace_exception_upload_total",
27 | "Total number of exceptions uploaded to Backtrace"
28 | );
29 |
30 | ///
31 | /// Construct a new instance of .
32 | ///
33 | /// The .
34 | /// The .
35 | ///
36 | /// - cannot be null.
37 | /// - cannot be null.
38 | ///
39 | public BacktraceUtility(ILogger logger, BacktraceSettings backtraceSettings)
40 | {
41 | if (backtraceSettings == null)
42 | throw new ArgumentNullException(nameof(backtraceSettings));
43 |
44 | _logger = logger ?? throw new ArgumentNullException(nameof(logger));
45 |
46 | if (!string.IsNullOrEmpty(backtraceSettings.BacktraceUrl))
47 | {
48 | var bckTraceCreds = new BacktraceCredentials(
49 | backtraceSettings.BacktraceUrl,
50 | backtraceSettings.BacktraceToken
51 | );
52 |
53 | _client = new BacktraceClient(bckTraceCreds);
54 | }
55 | }
56 |
57 | ///
58 | public IBacktraceClient Client => _client;
59 |
60 | ///
61 | public void UploadException(Exception ex)
62 | {
63 | if (ex == null)
64 | return;
65 |
66 | _uploadExceptionCounter.Inc();
67 |
68 | Task.Factory.StartNew(() =>
69 | {
70 | try
71 | {
72 | Console.WriteLine("Uploading exception to Backtrace...");
73 |
74 | _client?.Send(ex);
75 |
76 | Console.WriteLine("Exception uploaded to Backtrace.");
77 | }
78 | catch (Exception e)
79 | {
80 | Console.WriteLine("Failed to upload exception to Backtrace: {0}", e);
81 | }
82 | });
83 | }
84 |
85 | private static bool IsFileLocked(string filePath)
86 | {
87 | try
88 | {
89 | using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None);
90 |
91 | stream.Close();
92 | }
93 | catch (IOException)
94 | {
95 | return true;
96 | }
97 |
98 | return false;
99 | }
100 |
101 | ///
102 | public BacktraceResult UploadAllLogFiles(bool delete = true)
103 | {
104 | var attachments = from file in Directory.EnumerateFiles(Logger.LogFileBaseDirectory)
105 | // Do not include files that are in use.
106 | where File.Exists(file) && !IsFileLocked(file)
107 | select file;
108 |
109 | if (!attachments.Any())
110 | {
111 | _logger.Warning("No log files found to upload!");
112 |
113 | return null;
114 | }
115 |
116 | _logger.Information("Uploading the following log files to Backtrace: {0}", string.Join(", ", from log in attachments select Path.GetFileName(log)));
117 |
118 | var result = _client?.Send("Log files upload", attachmentPaths: attachments.ToList());
119 |
120 | if (delete)
121 | foreach (var log in attachments)
122 | {
123 | if (log == _logger.FullyQualifiedFileName) continue;
124 |
125 | _logger.Warning("Deleting old log file: {0}", log);
126 |
127 | log.PollDeletion();
128 | }
129 |
130 | return result;
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/services/grid-bot/lib/utility/Implementation/ClientSettingsNameHelper.cs:
--------------------------------------------------------------------------------
1 | namespace Grid.Bot.Utility;
2 |
3 | using System;
4 | using System.Text.RegularExpressions;
5 |
6 | ///
7 | /// Helper for client settings.
8 | ///
9 | public static partial class ClientSettingsNameHelper
10 | {
11 | [GeneratedRegex(@"^([DS])?F(Flag|Log|Int|String)", RegexOptions.Compiled)]
12 | public static partial Regex PrefixedSettingRegex();
13 |
14 | ///
15 | /// Determines if the setting name is a filtered value setting.
16 | ///
17 | /// The name of the setting.
18 | /// True if the setting is a filtered setting, otherwise false.
19 | public static bool IsFilteredSetting(string name)
20 | => name.EndsWith(FilteredValue