Skip to content

Commit 5b390a1

Browse files
authored
Merge branch 'master' into 28
2 parents 5971ce7 + 949026c commit 5b390a1

File tree

3 files changed

+312
-11
lines changed

3 files changed

+312
-11
lines changed

.github/copilot-instructions.md

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
# Copilot Instructions for FixSprayExploit Plugin
2+
3+
## Repository Overview
4+
5+
This repository contains a SourcePawn plugin for SourceMod that detects and prevents spray exploits in Source engine games. The plugin protects game servers from malicious spray files that can crash clients by validating spray file headers and blocking invalid uploads.
6+
7+
**Key Functionality:**
8+
- Real-time spray file validation during upload and usage
9+
- Automatic blocking and cleanup of malicious spray files
10+
- Player punishment (kick/ban) for exploit attempts
11+
- Integration with SourceBans++ and MaterialAdmin for banning
12+
- Comprehensive logging of spray activity
13+
- Support for multiple Source engine games (TF2, CSS, L4D2, etc.)
14+
15+
## Project Structure
16+
17+
```
18+
addons/sourcemod/
19+
├── scripting/
20+
│ ├── FixSprayExploit.sp # Main plugin implementation (~1150 lines)
21+
│ └── include/
22+
│ └── spray_exploit.inc # Native functions and forwards
23+
sourceknight.yaml # Build configuration
24+
.github/workflows/ci.yml # CI/CD pipeline
25+
```
26+
27+
## Technical Environment
28+
29+
**Language & Platform:**
30+
- **Language**: SourcePawn (SourceMod scripting language)
31+
- **Platform**: SourceMod 1.11.0+ (configured for 1.11.0-git6917)
32+
- **Build Tool**: SourceKnight 0.1
33+
- **Engine Support**: All Source engine games (TF2, CSS, L4D2, HL2DM, ZPS, etc.)
34+
35+
**Dependencies:**
36+
- SourceMod 1.11.0-git6917 (auto-downloaded via SourceKnight)
37+
- SourceBans++ (optional, for enhanced banning)
38+
- MaterialAdmin (optional, for alternative banning)
39+
40+
## Build System
41+
42+
The project uses **SourceKnight**, a modern SourceMod build tool:
43+
44+
### Build Configuration (`sourceknight.yaml`)
45+
- **Output**: `/addons/sourcemod/plugins` (compiled `.smx` files)
46+
- **Target**: `FixSprayExploit` (builds `FixSprayExploit.smx`)
47+
- **Dependencies**: Auto-downloaded and unpacked during build
48+
49+
### Building Locally
50+
```bash
51+
# Install SourceKnight if not available
52+
# Build the plugin
53+
sourceknight build
54+
55+
# Output will be in .sourceknight/package/addons/sourcemod/plugins/
56+
```
57+
58+
**Note**: SourceKnight may not be available in all environments. The GitHub Actions CI/CD pipeline is the primary build method. For local development, you can use the traditional SourceMod compiler (`spcomp`) if needed.
59+
60+
### CI/CD Pipeline
61+
- Uses GitHub Actions with `maxime1907/action-sourceknight@v1`
62+
- Builds on Ubuntu 24.04
63+
- Creates release packages automatically
64+
- Tags `latest` release from main/master branch
65+
66+
## Code Architecture
67+
68+
### Main Plugin (`FixSprayExploit.sp`)
69+
70+
**Core Components:**
71+
1. **File Validation Engine** (lines 995-1105): Validates spray file headers against known exploit patterns
72+
2. **Player Spray Monitoring** (lines 744-827): Hooks `Player Decal` temp entities to intercept spray attempts
73+
3. **File Receive/Send Hooks** (lines 914-992): Monitors file transfers to/from clients
74+
4. **Punishment System** (lines 887-912): Handles kicking/banning of exploit users
75+
5. **Cleanup System** (lines 582-680): Moves invalid sprays to backup folder
76+
77+
**Key Data Structures:**
78+
- `g_smChecked`: StringMap cache of validated files
79+
- `g_smReceive`: StringMap tracking received files
80+
- `g_smWaiting`: StringMap preventing duplicate log spam
81+
- `g_iVal[]`: Expected byte pattern for valid spray headers
82+
83+
### Include File (`spray_exploit.inc`)
84+
85+
**Provides:**
86+
- `OnSprayExploit(client, index, value)` forward for third-party plugins
87+
- `SprayExploitFixer_LogCustom()` native for custom logging
88+
89+
## SourcePawn Coding Guidelines
90+
91+
### Style Requirements
92+
- Use `#pragma semicolon 1` and `#pragma newdecls required`
93+
- Indentation: 4 spaces (represented as tabs)
94+
- Variables: camelCase for locals, PascalCase for functions, prefix globals with `g_`
95+
- No unnecessary headers/comments (plugin has extensive changelog - avoid this pattern)
96+
- Delete trailing spaces
97+
98+
### Best Practices Applied
99+
**Memory Management**: Uses `delete` for StringMaps/ArrayLists instead of `.Clear()`
100+
**Async Operations**: File operations use timers to prevent timeouts
101+
**StringMaps over Arrays**: Efficient data storage
102+
**Error Handling**: Comprehensive validation and logging
103+
**Performance**: Caching validated files, batched processing
104+
105+
### Anti-Patterns to Avoid
106+
❌ Extensive changelog headers (existing code has this but avoid in new code)
107+
❌ Using `.Clear()` on StringMaps (causes memory leaks)
108+
❌ Synchronous file operations in loops
109+
❌ Hardcoded values without configuration
110+
111+
## Development Workflows
112+
113+
### Adding New Exploit Detection
114+
1. Update `g_iVal[]` array with new byte patterns
115+
2. Modify `ValFile()` function for new validation logic
116+
3. Add corresponding test cases to `RecursiveSearchDirs()`
117+
4. Update `g_hCvarPunish` handling if needed
118+
119+
### Integrating New Banning Systems
120+
1. Add optional include: `#tryinclude <newsystem>`
121+
2. Add library detection in `OnLibraryAdded()/OnLibraryRemoved()`
122+
3. Extend `TestClient()` function with new banning method
123+
4. Mark natives as optional in `AskPluginLoad2()`
124+
125+
### Performance Optimization
126+
- Monitor `MAX_READ` constant (current: 50 files per batch)
127+
- Use `TIMEOUT_LOG` to prevent log spam (current: 10.0 seconds)
128+
- Cache results in StringMaps to avoid repeated validation
129+
- Use `RequestFrame()` for async operations
130+
131+
## Testing & Validation
132+
133+
### Manual Testing
134+
```bash
135+
# Test spray file validation
136+
sm_spray_test
137+
138+
# Monitor real-time activity
139+
sm_cvar spray_exploit_fixer_log 1
140+
sm_cvar spray_exploit_fixer_msg 1
141+
```
142+
143+
### Integration Testing
144+
- Test with SourceBans++ integration (`g_bSourceBans`)
145+
- Test with MaterialAdmin integration (`g_bMaterialAdmin`)
146+
- Validate different engine support (TF2 has special handling)
147+
- Test file cleanup and backup functionality
148+
149+
### Configuration Testing
150+
```bash
151+
# Test punishment modes
152+
sm_cvar spray_exploit_fixer_punish 1 # PlayerDecal only
153+
sm_cvar spray_exploit_fixer_punish 2 # FileCheck only
154+
sm_cvar spray_exploit_fixer_punish 3 # Both
155+
156+
# Test banning (not available in TF2)
157+
sm_cvar spray_exploit_fixer_ban 1
158+
sm_cvar spray_exploit_fixer_kick 1
159+
sm_cvar spray_exploit_fixer_bantime 5
160+
```
161+
162+
## Security Considerations
163+
164+
### Exploit Detection Logic
165+
- **Header Validation**: Checks VTF file header against `g_iVal[]` patterns
166+
- **RIFF/WAVE Detection**: Special handling for audio files (lines 1053-1058)
167+
- **Size Validation**: Prevents oversized dimensions (lines 1079-1086)
168+
- **Flag Validation**: Blocks dangerous VTF flags (line 1086)
169+
170+
### File System Security
171+
- Moves invalid files to `backup_sprays/` folder instead of deletion
172+
- Validates file paths to prevent directory traversal
173+
- Handles both `.dat` and `.dat.ztmp` file extensions
174+
- Recursive cleanup of empty directories
175+
176+
## File Exclusions (.gitignore)
177+
178+
The following should be excluded from version control:
179+
- `build/`, `release/` - Build artifacts
180+
- `*.smx` - Compiled plugins
181+
- `plugins/` - Plugin binaries
182+
- `.sourceknight/` - SourceKnight build cache
183+
- `.venv/` - Python virtual environments
184+
185+
## Common Tasks
186+
187+
### Adding ConVar
188+
```sourcepawn
189+
ConVar g_hCvarNewSetting = CreateConVar("spray_exploit_fixer_newsetting", "0", "Description");
190+
AutoExecConfig(true, "spray_exploit_fixer");
191+
```
192+
193+
### Adding New Log Message
194+
```sourcepawn
195+
if( g_hCvarLog.IntValue ) LogCustom("New event: %s from %N", data, client);
196+
if( g_hCvarMsg.IntValue ) PrintToServer("[Spray Exploit] New event: %s", data);
197+
```
198+
199+
### Extending File Validation
200+
```sourcepawn
201+
// In ValFile() function, add new checks:
202+
if( condition_check ) {
203+
return i; // Return position of invalid byte
204+
}
205+
```
206+
207+
## Debugging & Troubleshooting
208+
209+
### Common Issues
210+
1. **Build Failures**: Check SourceKnight version compatibility
211+
2. **File Not Found**: Verify `spray_exploit_fixer_path` cvar is correct
212+
3. **Memory Leaks**: Ensure StringMaps are `delete`d, not `.Clear()`ed
213+
4. **Timeouts**: Increase batch size or timer delays for large file sets
214+
215+
### Debug Logging
216+
- Set `spray_exploit_fixer_log 1` for all activity
217+
- Set `spray_exploit_fixer_msg 1` for console output
218+
- Check `sourcemod/logs/spray_downloads.log` for detailed logs
219+
220+
### Performance Monitoring
221+
- Monitor `g_iTotal` counter in batch processing
222+
- Check `g_fTime` for operation duration in `CmdSprays`
223+
- Watch for script execution timeouts during file operations
224+
225+
This plugin demonstrates advanced SourcePawn techniques for file validation, async processing, and multi-platform compatibility. Focus on maintaining the security-first approach while ensuring server performance.
226+
227+
## Quick Reference
228+
229+
### Key Files
230+
- `addons/sourcemod/scripting/FixSprayExploit.sp` - Main plugin (1150 lines)
231+
- `addons/sourcemod/scripting/include/spray_exploit.inc` - API definitions
232+
- `sourceknight.yaml` - Build configuration
233+
- `.github/workflows/ci.yml` - CI/CD pipeline
234+
235+
### Important Constants
236+
- `MAX_READ = 50` - Files processed per batch
237+
- `TIMEOUT_LOG = 10.0` - Seconds between duplicate log entries
238+
- `PATH_BACKUP = "backup_sprays"` - Invalid spray storage folder
239+
240+
### Key CVars
241+
- `spray_exploit_fixer_punish` - Which exploits to test (0-3)
242+
- `spray_exploit_fixer_ban` - Ban malicious users (0-1)
243+
- `spray_exploit_fixer_log` - Logging level (0-2)
244+
- `spray_exploit_fixer_msg` - Console output level (0-2)

.github/workflows/ci.yml

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ jobs:
99
strategy:
1010
fail-fast: false
1111
matrix:
12-
os: [ubuntu-20.04]
12+
os: [ubuntu-24.04]
1313
include:
14-
- os: ubuntu-20.04
14+
- os: ubuntu-24.04
1515
steps:
16-
- uses: actions/checkout@v4
16+
- uses: actions/checkout@v6
1717
- name: Build sourcemod plugin
1818
uses: maxime1907/action-sourceknight@v1
1919
with:
@@ -25,7 +25,7 @@ jobs:
2525
cp -R .sourceknight/package/* /tmp/package
2626
2727
- name: Upload build archive for test runners
28-
uses: actions/upload-artifact@v4
28+
uses: actions/upload-artifact@v5
2929
with:
3030
name: ${{ runner.os }}
3131
path: /tmp/package
@@ -35,7 +35,7 @@ jobs:
3535
needs: build
3636
runs-on: ubuntu-latest
3737
steps:
38-
- uses: actions/checkout@v4
38+
- uses: actions/checkout@v6
3939
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main'
4040

4141
- uses: dev-drprasad/[email protected]
@@ -59,7 +59,10 @@ jobs:
5959
runs-on: ubuntu-latest
6060
steps:
6161
- name: Download artifacts
62-
uses: actions/download-artifact@v4
62+
uses: actions/download-artifact@v6
63+
with:
64+
name: ${{ runner.os }}
65+
path: artifacts
6366

6467
- name: Versioning
6568
run: |
@@ -71,12 +74,11 @@ jobs:
7174
7275
- name: Package
7376
run: |
77+
cd artifacts
7478
ls -Rall
75-
if [ -d "./Linux/" ]; then
76-
cd ./Linux/
77-
tar -czf ../${{ github.event.repository.name }}-${{ env.RELEASE_VERSION }}.tar.gz -T <(\ls -1)
78-
cd -
79-
fi
79+
tar -czf ../${{ github.event.repository.name }}-${{ env.RELEASE_VERSION }}.tar.gz .
80+
cd ..
81+
ls -la *.tar.gz
8082
8183
- name: Release
8284
uses: svenstaro/upload-release-action@v2
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Spray Exploit Fixer
3+
* Copyright (C) 2025 Silvers
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
*/
18+
19+
#if defined _spray_exploit_included
20+
#endinput
21+
#endif
22+
#define _spray_exploit_included
23+
24+
25+
public SharedPlugin __pl_spray_exploit =
26+
{
27+
name = "spray_exploit_fixer",
28+
file = "spray_exploit_fixer.smx",
29+
#if defined REQUIRE_PLUGIN
30+
required = 1,
31+
#else
32+
required = 0,
33+
#endif
34+
};
35+
36+
37+
38+
/**
39+
* @brief Triggers when a clients spray was detected
40+
*
41+
* @param client client index of the detected player
42+
* @param index position of detection
43+
* @param value value detected
44+
*
45+
* @noreturn
46+
*/
47+
forward void OnSprayExploit(int client, int index, int value);
48+
49+
/**
50+
* Log a message into logs/spray_downloads.log
51+
*
52+
* @param format Message to log
53+
* @noreturn
54+
*/
55+
native void SprayExploitFixer_LogCustom(const char[] format, any ...);

0 commit comments

Comments
 (0)