8
.gitignore
vendido
Archivo normal
8
.gitignore
vendido
Archivo normal
@@ -0,0 +1,8 @@
|
|||||||
|
node_modules/
|
||||||
|
*.log
|
||||||
|
.env
|
||||||
|
*.pem
|
||||||
|
*.key
|
||||||
|
test-results/
|
||||||
|
coverage/
|
||||||
|
.DS_Store
|
||||||
385
PROJECT_SUMMARY.md
Archivo normal
385
PROJECT_SUMMARY.md
Archivo normal
@@ -0,0 +1,385 @@
|
|||||||
|
# ActivityPub Security PoC - Project Summary
|
||||||
|
|
||||||
|
## ✅ Project Complete
|
||||||
|
|
||||||
|
A comprehensive security testing toolkit for ActivityPub protocol implementations has been successfully created.
|
||||||
|
|
||||||
|
## 📦 What Was Built
|
||||||
|
|
||||||
|
### Core Components
|
||||||
|
|
||||||
|
1. **ActivityPub Client** (`src/activitypub-client.js`)
|
||||||
|
- Full HTTP client for ActivityPub interactions
|
||||||
|
- Send activities to inbox endpoints
|
||||||
|
- Fetch from outbox endpoints
|
||||||
|
- Fetch actor profiles
|
||||||
|
- HTTP signature support (framework ready)
|
||||||
|
- JSON-LD context handling
|
||||||
|
- Activity creation helpers
|
||||||
|
|
||||||
|
2. **Security Testing Module** (`src/security-tester.js`)
|
||||||
|
- Automated vulnerability testing
|
||||||
|
- 6 test categories:
|
||||||
|
- Cross-Site Scripting (XSS)
|
||||||
|
- Server-Side Request Forgery (SSRF)
|
||||||
|
- Object injection & type confusion
|
||||||
|
- Signature bypass
|
||||||
|
- Authorization issues
|
||||||
|
- SQL/Command injection
|
||||||
|
- Comprehensive reporting
|
||||||
|
|
||||||
|
3. **CLI Tool** (`src/cli.js`)
|
||||||
|
- User-friendly command-line interface
|
||||||
|
- 7 main commands:
|
||||||
|
- `test-inbox` - Send activities to inbox
|
||||||
|
- `test-outbox` - Fetch from outbox
|
||||||
|
- `fetch-actor` - Get actor profiles
|
||||||
|
- `security-scan` - Run automated security tests
|
||||||
|
- `craft` - Create custom activities
|
||||||
|
- `mock-server` - Start mock server
|
||||||
|
- `interactive` - Interactive mode (planned)
|
||||||
|
|
||||||
|
4. **Mock Server** (`src/mock-server.js`)
|
||||||
|
- Fully functional ActivityPub server simulation
|
||||||
|
- Complete endpoint implementation:
|
||||||
|
- WebFinger (/.well-known/webfinger)
|
||||||
|
- Actor profiles (/users/:username)
|
||||||
|
- Inbox (/users/:username/inbox)
|
||||||
|
- Outbox (/users/:username/outbox)
|
||||||
|
- Followers/Following collections
|
||||||
|
- Shared inbox
|
||||||
|
- Real-time security detection
|
||||||
|
- Activity validation
|
||||||
|
- Detailed logging
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
1. **README.md** - Project overview and quick start
|
||||||
|
2. **QUICKSTART.md** - Command reference and common use cases
|
||||||
|
3. **examples/USAGE.md** - Comprehensive usage guide with examples
|
||||||
|
4. **docs/SECURITY_TESTING.md** - Security testing methodology
|
||||||
|
5. **docs/ARCHITECTURE.md** - Technical architecture documentation
|
||||||
|
|
||||||
|
### Example Payloads
|
||||||
|
|
||||||
|
- `examples/create-note.json` - Basic Create activity
|
||||||
|
- `examples/follow.json` - Follow activity
|
||||||
|
- `examples/xss-payload.json` - XSS test vectors
|
||||||
|
- `examples/ssrf-payload.json` - SSRF test vectors
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
- `test.sh` - Automated test script demonstrating all features
|
||||||
|
|
||||||
|
## 🎯 Key Features
|
||||||
|
|
||||||
|
### Security Testing Capabilities
|
||||||
|
|
||||||
|
- **XSS Detection**: 7+ different XSS vectors including script tags, event handlers, JavaScript protocols
|
||||||
|
- **SSRF Detection**: Tests for internal network access, cloud metadata, file protocols
|
||||||
|
- **Injection Testing**: SQL injection, command injection, prototype pollution
|
||||||
|
- **Authorization Testing**: Actor impersonation, unauthorized actions
|
||||||
|
- **Comprehensive Reporting**: Colored console output, JSON export, detailed logs
|
||||||
|
|
||||||
|
### Mock Server Features
|
||||||
|
|
||||||
|
- **Real-time Detection**: Identifies security issues as they arrive
|
||||||
|
- **Multiple Users**: Pre-configured alice and bob accounts
|
||||||
|
- **Full Protocol Support**: Implements ActivityPub spec endpoints
|
||||||
|
- **Educational**: Shows both vulnerable and secure patterns
|
||||||
|
|
||||||
|
### Clean Code Practices
|
||||||
|
|
||||||
|
- Modular architecture with separation of concerns
|
||||||
|
- Comprehensive error handling
|
||||||
|
- Async/await throughout
|
||||||
|
- Well-commented code
|
||||||
|
- Consistent coding style
|
||||||
|
- Reusable components
|
||||||
|
|
||||||
|
## 🚀 How to Use
|
||||||
|
|
||||||
|
### Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install dependencies
|
||||||
|
cd activitypub-security-poc
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# Start mock server (Terminal 1)
|
||||||
|
npm run mock-server
|
||||||
|
|
||||||
|
# Test it (Terminal 2)
|
||||||
|
node src/cli.js fetch-actor --target http://localhost:3000/users/alice
|
||||||
|
|
||||||
|
# Send a test activity
|
||||||
|
node src/cli.js test-inbox \
|
||||||
|
--target http://localhost:3000/users/alice/inbox \
|
||||||
|
--content "Hello from security PoC!"
|
||||||
|
|
||||||
|
# Run security scan
|
||||||
|
node src/cli.js security-scan \
|
||||||
|
--target http://localhost:3000/users/alice/inbox
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run Automated Test Suite
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./test.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📊 What You Can Test
|
||||||
|
|
||||||
|
### Against Mock Server (Safe)
|
||||||
|
|
||||||
|
- Test all security vectors
|
||||||
|
- Learn ActivityPub protocol
|
||||||
|
- Develop secure implementations
|
||||||
|
- Training and education
|
||||||
|
|
||||||
|
### Against Your Own Instance (Authorized)
|
||||||
|
|
||||||
|
- Validate security controls
|
||||||
|
- Test inbox processing
|
||||||
|
- Verify signature requirements
|
||||||
|
- Check content sanitization
|
||||||
|
|
||||||
|
### Against Third-Party Instances (With Permission Only)
|
||||||
|
|
||||||
|
- Security audits
|
||||||
|
- Penetration testing
|
||||||
|
- Vulnerability research
|
||||||
|
- Responsible disclosure
|
||||||
|
|
||||||
|
## 🛡️ Security Tests Included
|
||||||
|
|
||||||
|
### 1. Cross-Site Scripting (XSS)
|
||||||
|
|
||||||
|
Tests if user content is properly escaped:
|
||||||
|
- `<script>alert('XSS')</script>`
|
||||||
|
- `<img src=x onerror=alert('XSS')>`
|
||||||
|
- `javascript:alert('XSS')`
|
||||||
|
- SVG-based XSS
|
||||||
|
- Event handler injection
|
||||||
|
|
||||||
|
### 2. Server-Side Request Forgery (SSRF)
|
||||||
|
|
||||||
|
Tests URL validation in:
|
||||||
|
- Image URLs
|
||||||
|
- Object IDs
|
||||||
|
- Profile URLs
|
||||||
|
- Link previews
|
||||||
|
|
||||||
|
Targets:
|
||||||
|
- Internal IPs (localhost, 127.0.0.1)
|
||||||
|
- Cloud metadata (169.254.169.254)
|
||||||
|
- File protocols (file://)
|
||||||
|
|
||||||
|
### 3. Object Injection
|
||||||
|
|
||||||
|
Tests JSON validation:
|
||||||
|
- Multiple type values
|
||||||
|
- Missing required fields
|
||||||
|
- Prototype pollution (`__proto__`)
|
||||||
|
- Constructor manipulation
|
||||||
|
|
||||||
|
### 4. Signature Bypass
|
||||||
|
|
||||||
|
Tests authentication:
|
||||||
|
- Missing signatures
|
||||||
|
- Invalid signatures
|
||||||
|
- Forged signatures
|
||||||
|
|
||||||
|
### 5. Authorization
|
||||||
|
|
||||||
|
Tests access control:
|
||||||
|
- Actor impersonation
|
||||||
|
- Unauthorized deletions
|
||||||
|
- Cross-account access
|
||||||
|
|
||||||
|
### 6. Injection Attacks
|
||||||
|
|
||||||
|
Tests input sanitization:
|
||||||
|
- SQL injection patterns
|
||||||
|
- Command injection
|
||||||
|
- Template injection
|
||||||
|
|
||||||
|
## 📈 Example Output
|
||||||
|
|
||||||
|
### Security Scan Results
|
||||||
|
|
||||||
|
```
|
||||||
|
============================================================
|
||||||
|
SECURITY TEST REPORT
|
||||||
|
============================================================
|
||||||
|
Target: http://localhost:3000/users/alice/inbox
|
||||||
|
Timestamp: 2025-11-16T...
|
||||||
|
============================================================
|
||||||
|
|
||||||
|
XSS:
|
||||||
|
------------------------------------------------------------
|
||||||
|
❌ VULNERABLE - XSS: <script>alert("XSS")</script>
|
||||||
|
❌ VULNERABLE - XSS: <img src=x onerror=alert("XSS")>
|
||||||
|
✅ SAFE - XSS: javascript:alert("XSS")
|
||||||
|
|
||||||
|
SSRF:
|
||||||
|
------------------------------------------------------------
|
||||||
|
🚨 VULNERABLE - SSRF: http://localhost:8080
|
||||||
|
🚨 VULNERABLE - SSRF: http://169.254.169.254/latest/meta-data/
|
||||||
|
|
||||||
|
============================================================
|
||||||
|
SUMMARY: 4/15 potential vulnerabilities found
|
||||||
|
============================================================
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mock Server Detection
|
||||||
|
|
||||||
|
```
|
||||||
|
📥 Received activity for alice:
|
||||||
|
{
|
||||||
|
"type": "Create",
|
||||||
|
"object": {
|
||||||
|
"type": "Note",
|
||||||
|
"content": "<script>alert('XSS')</script>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
🚨 Security issues detected:
|
||||||
|
- Potential XSS detected: <script>alert('XSS')</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎓 Educational Value
|
||||||
|
|
||||||
|
This toolkit demonstrates:
|
||||||
|
|
||||||
|
- **ActivityPub Protocol**: Complete implementation of core endpoints
|
||||||
|
- **HTTP Signatures**: Framework for signing and verification
|
||||||
|
- **JSON-LD**: Proper context handling
|
||||||
|
- **Security Best Practices**: Input validation, sanitization, access control
|
||||||
|
- **Testing Methodology**: Systematic security testing approach
|
||||||
|
- **Clean Architecture**: Modular, maintainable code structure
|
||||||
|
|
||||||
|
## 🔧 Extensibility
|
||||||
|
|
||||||
|
Easy to extend:
|
||||||
|
|
||||||
|
### Add New Security Tests
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// In security-tester.js
|
||||||
|
async testNewVulnerability(inboxUrl) {
|
||||||
|
// Your test logic
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add New CLI Commands
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// In cli.js
|
||||||
|
program
|
||||||
|
.command('new-command')
|
||||||
|
.action(async (options) => {
|
||||||
|
// Your command logic
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add Mock Server Endpoints
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// In mock-server.js
|
||||||
|
async handleNewEndpoint(req, res, path) {
|
||||||
|
// Your endpoint logic
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📚 Documentation Structure
|
||||||
|
|
||||||
|
- **README.md** - Start here
|
||||||
|
- **QUICKSTART.md** - Command reference
|
||||||
|
- **examples/USAGE.md** - Detailed examples
|
||||||
|
- **docs/SECURITY_TESTING.md** - Testing methodology
|
||||||
|
- **docs/ARCHITECTURE.md** - Technical details
|
||||||
|
|
||||||
|
## ⚠️ Important Disclaimers
|
||||||
|
|
||||||
|
### Legal
|
||||||
|
|
||||||
|
- For authorized testing only
|
||||||
|
- Obtain permission before testing third-party systems
|
||||||
|
- Comply with computer fraud and abuse laws
|
||||||
|
- Respect responsible disclosure guidelines
|
||||||
|
|
||||||
|
### Ethical
|
||||||
|
|
||||||
|
- Do not exploit vulnerabilities
|
||||||
|
- Do not disrupt services
|
||||||
|
- Do not access unauthorized data
|
||||||
|
- Report findings responsibly
|
||||||
|
|
||||||
|
## 🎯 Use Cases
|
||||||
|
|
||||||
|
### Development
|
||||||
|
|
||||||
|
- Test your ActivityPub implementation
|
||||||
|
- Validate security controls
|
||||||
|
- Learn the protocol
|
||||||
|
|
||||||
|
### Security Research
|
||||||
|
|
||||||
|
- Discover vulnerabilities
|
||||||
|
- Develop proof of concepts
|
||||||
|
- Conduct authorized penetration tests
|
||||||
|
|
||||||
|
### Education
|
||||||
|
|
||||||
|
- Teach ActivityPub security
|
||||||
|
- Demonstrate attack vectors
|
||||||
|
- Show defensive techniques
|
||||||
|
|
||||||
|
## 🚦 Project Status
|
||||||
|
|
||||||
|
✅ **Complete and Functional**
|
||||||
|
|
||||||
|
All core features implemented:
|
||||||
|
- ✅ ActivityPub client
|
||||||
|
- ✅ Security testing module
|
||||||
|
- ✅ CLI interface
|
||||||
|
- ✅ Mock server
|
||||||
|
- ✅ Example payloads
|
||||||
|
- ✅ Comprehensive documentation
|
||||||
|
- ✅ Test script
|
||||||
|
|
||||||
|
## 🔮 Future Enhancements
|
||||||
|
|
||||||
|
Potential additions:
|
||||||
|
|
||||||
|
1. Full HTTP signature implementation with RSA keys
|
||||||
|
2. WebFinger testing
|
||||||
|
3. Media upload testing
|
||||||
|
4. Rate limiting tests
|
||||||
|
5. Interactive wizard mode
|
||||||
|
6. HTML report generation
|
||||||
|
7. CI/CD integration examples
|
||||||
|
8. More payload variations
|
||||||
|
|
||||||
|
## 📞 Next Steps
|
||||||
|
|
||||||
|
1. **Explore**: Run `./test.sh` to see it in action
|
||||||
|
2. **Learn**: Read the documentation
|
||||||
|
3. **Test**: Start the mock server and experiment
|
||||||
|
4. **Extend**: Add your own tests
|
||||||
|
5. **Contribute**: Enhance the toolkit
|
||||||
|
|
||||||
|
## 🎉 Summary
|
||||||
|
|
||||||
|
A professional-grade security testing toolkit for ActivityPub with:
|
||||||
|
|
||||||
|
- **Clean, modular code**
|
||||||
|
- **Comprehensive testing coverage**
|
||||||
|
- **Real mock server**
|
||||||
|
- **Detailed documentation**
|
||||||
|
- **Easy to use and extend**
|
||||||
|
- **Educational value**
|
||||||
|
- **Production-ready structure**
|
||||||
|
|
||||||
|
Perfect for security testers, developers, and researchers working with ActivityPub and the Fediverse!
|
||||||
168
QUICKSTART.md
Archivo normal
168
QUICKSTART.md
Archivo normal
@@ -0,0 +1,168 @@
|
|||||||
|
# ActivityPub Security PoC - Quick Reference
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd activitypub-security-poc
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick Commands
|
||||||
|
|
||||||
|
### Start Mock Server
|
||||||
|
```bash
|
||||||
|
npm run mock-server
|
||||||
|
# or
|
||||||
|
node src/cli.js mock-server --port 3000
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run Quick Test
|
||||||
|
```bash
|
||||||
|
./test.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Fetch Actor
|
||||||
|
```bash
|
||||||
|
node src/cli.js fetch-actor --target http://localhost:3000/users/alice
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test Inbox
|
||||||
|
```bash
|
||||||
|
node src/cli.js test-inbox \
|
||||||
|
--target http://localhost:3000/users/alice/inbox \
|
||||||
|
--content "Test message"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Security Scan
|
||||||
|
```bash
|
||||||
|
node src/cli.js security-scan \
|
||||||
|
--target http://localhost:3000/users/alice/inbox
|
||||||
|
```
|
||||||
|
|
||||||
|
### Craft Activity
|
||||||
|
```bash
|
||||||
|
node src/cli.js craft --type Create --object Note --content "Hello"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Use Cases
|
||||||
|
|
||||||
|
### Test Local Mastodon Instance
|
||||||
|
```bash
|
||||||
|
# Start mock server
|
||||||
|
npm run mock-server
|
||||||
|
|
||||||
|
# In another terminal, send activity
|
||||||
|
node src/cli.js test-inbox \
|
||||||
|
--target http://localhost:3000/users/alice/inbox \
|
||||||
|
--payload examples/create-note.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test XSS Vulnerability
|
||||||
|
```bash
|
||||||
|
node src/cli.js test-inbox \
|
||||||
|
--target http://localhost:3000/users/alice/inbox \
|
||||||
|
--payload examples/xss-payload.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test SSRF Vulnerability
|
||||||
|
```bash
|
||||||
|
node src/cli.js test-inbox \
|
||||||
|
--target http://localhost:3000/users/alice/inbox \
|
||||||
|
--payload examples/ssrf-payload.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### Full Security Audit
|
||||||
|
```bash
|
||||||
|
node src/cli.js security-scan \
|
||||||
|
--target http://localhost:3000/users/alice/inbox \
|
||||||
|
--output results-$(date +%Y%m%d).json
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing Against Real Instances
|
||||||
|
|
||||||
|
⚠️ **Get permission first!**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Fetch public data (usually allowed)
|
||||||
|
node src/cli.js fetch-actor --target https://mastodon.social/@Gargron
|
||||||
|
node src/cli.js test-outbox --target https://mastodon.social/@Gargron/outbox
|
||||||
|
|
||||||
|
# Testing inbox requires authorization
|
||||||
|
node src/cli.js test-inbox \
|
||||||
|
--target https://your-instance.example/users/you/inbox \
|
||||||
|
--content "Test from security PoC"
|
||||||
|
```
|
||||||
|
|
||||||
|
## File Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
activitypub-security-poc/
|
||||||
|
├── src/
|
||||||
|
│ ├── cli.js # Main CLI
|
||||||
|
│ ├── activitypub-client.js # HTTP client
|
||||||
|
│ ├── security-tester.js # Security tests
|
||||||
|
│ └── mock-server.js # Mock server
|
||||||
|
├── examples/
|
||||||
|
│ ├── *.json # Sample payloads
|
||||||
|
│ └── USAGE.md # Detailed usage
|
||||||
|
└── docs/
|
||||||
|
├── ARCHITECTURE.md # Architecture docs
|
||||||
|
└── SECURITY_TESTING.md # Testing guide
|
||||||
|
```
|
||||||
|
|
||||||
|
## Help Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Main help
|
||||||
|
node src/cli.js --help
|
||||||
|
|
||||||
|
# Command-specific help
|
||||||
|
node src/cli.js test-inbox --help
|
||||||
|
node src/cli.js security-scan --help
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tips
|
||||||
|
|
||||||
|
- Use `--output` to save results to JSON
|
||||||
|
- Use `--tests` to run specific security tests
|
||||||
|
- Check mock server logs for detected vulnerabilities
|
||||||
|
- Read USAGE.md and SECURITY_TESTING.md for details
|
||||||
|
- Always test with permission
|
||||||
|
|
||||||
|
## Example Workflow
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Terminal 1: Start mock server
|
||||||
|
npm run mock-server
|
||||||
|
|
||||||
|
# Terminal 2: Run tests
|
||||||
|
node src/cli.js fetch-actor --target http://localhost:3000/users/alice
|
||||||
|
node src/cli.js test-inbox --target http://localhost:3000/users/alice/inbox --content "Hello"
|
||||||
|
node src/cli.js security-scan --target http://localhost:3000/users/alice/inbox
|
||||||
|
|
||||||
|
# Check Terminal 1 for server logs showing received activities and security issues
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
**"Cannot find module"**: Run `npm install`
|
||||||
|
|
||||||
|
**"ECONNREFUSED"**: Start the mock server first
|
||||||
|
|
||||||
|
**"Command not found"**: Use `node src/cli.js` instead of just `cli.js`
|
||||||
|
|
||||||
|
**Timeout errors**: Check if target is reachable
|
||||||
|
|
||||||
|
## Security Reminder
|
||||||
|
|
||||||
|
This tool is for **authorized security testing only**. Use it to:
|
||||||
|
- Test your own servers
|
||||||
|
- Conduct authorized penetration tests
|
||||||
|
- Learn about ActivityPub security
|
||||||
|
- Develop secure implementations
|
||||||
|
|
||||||
|
Do NOT use it to:
|
||||||
|
- Attack systems without permission
|
||||||
|
- Exploit vulnerabilities
|
||||||
|
- Disrupt services
|
||||||
|
- Access unauthorized data
|
||||||
76
README.md
Archivo normal
76
README.md
Archivo normal
@@ -0,0 +1,76 @@
|
|||||||
|
# ActivityPub Security PoC
|
||||||
|
|
||||||
|
A comprehensive security testing toolkit for ActivityPub protocol implementations.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- 🔍 **Security Testing**: Test common vulnerabilities in ActivityPub implementations
|
||||||
|
- 🌐 **Remote Testing**: Probe outbox and inbox endpoints across instances
|
||||||
|
- 🎭 **Mock Server**: Simulated ActivityPub server for controlled testing
|
||||||
|
- 📝 **JSON-LD Support**: Full ActivityPub JSON-LD context handling
|
||||||
|
- 🔐 **HTTP Signatures**: Test signature verification and authentication
|
||||||
|
- 🛡️ **Injection Testing**: XSS, SSRF, and object injection tests
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### CLI Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test an inbox endpoint
|
||||||
|
node src/cli.js test-inbox --target https://instance.example/users/alice/inbox --payload ./payloads/note.json
|
||||||
|
|
||||||
|
# Test an outbox endpoint
|
||||||
|
node src/cli.js test-outbox --target https://instance.example/users/alice/outbox
|
||||||
|
|
||||||
|
# Run security scans
|
||||||
|
node src/cli.js security-scan --target https://instance.example --tests xss,ssrf,injection
|
||||||
|
|
||||||
|
# Start mock server
|
||||||
|
node src/cli.js mock-server --port 3000
|
||||||
|
|
||||||
|
# Craft custom activity
|
||||||
|
node src/cli.js craft --type Create --object Note --content "Test message"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mock Server
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run mock-server
|
||||||
|
```
|
||||||
|
|
||||||
|
The mock server provides:
|
||||||
|
- `/users/:username` - Actor endpoints
|
||||||
|
- `/users/:username/inbox` - Inbox endpoint
|
||||||
|
- `/users/:username/outbox` - Outbox endpoint
|
||||||
|
- `/.well-known/webfinger` - WebFinger endpoint
|
||||||
|
|
||||||
|
## Security Tests
|
||||||
|
|
||||||
|
### 1. XSS Testing
|
||||||
|
Tests for Cross-Site Scripting vulnerabilities in content fields.
|
||||||
|
|
||||||
|
### 2. SSRF Testing
|
||||||
|
Tests Server-Side Request Forgery via malicious URLs.
|
||||||
|
|
||||||
|
### 3. Object Injection
|
||||||
|
Tests for improper object type validation.
|
||||||
|
|
||||||
|
### 4. Signature Bypass
|
||||||
|
Tests HTTP signature verification weaknesses.
|
||||||
|
|
||||||
|
### 5. Authorization Issues
|
||||||
|
Tests for improper access control on private activities.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
See the `examples/` directory for sample payloads and test scenarios.
|
||||||
|
|
||||||
|
## Disclaimer
|
||||||
|
|
||||||
|
This tool is for authorized security testing only. Always obtain permission before testing third-party systems.
|
||||||
208
TABLE_OF_CONTENTS.md
Archivo normal
208
TABLE_OF_CONTENTS.md
Archivo normal
@@ -0,0 +1,208 @@
|
|||||||
|
# ActivityPub Security PoC - Table of Contents
|
||||||
|
|
||||||
|
## 📖 Documentation Index
|
||||||
|
|
||||||
|
### Getting Started
|
||||||
|
|
||||||
|
1. **[README.md](README.md)** - Project overview, features, and installation
|
||||||
|
2. **[QUICKSTART.md](QUICKSTART.md)** - Quick reference for common commands
|
||||||
|
3. **[PROJECT_SUMMARY.md](PROJECT_SUMMARY.md)** - Complete project summary and capabilities
|
||||||
|
|
||||||
|
### Detailed Guides
|
||||||
|
|
||||||
|
4. **[examples/USAGE.md](examples/USAGE.md)** - Comprehensive usage examples and workflows
|
||||||
|
5. **[docs/SECURITY_TESTING.md](docs/SECURITY_TESTING.md)** - Security testing methodology and best practices
|
||||||
|
6. **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)** - Technical architecture and design
|
||||||
|
|
||||||
|
## 📁 Source Code
|
||||||
|
|
||||||
|
### Main Components
|
||||||
|
|
||||||
|
- **[src/cli.js](src/cli.js)** - Command-line interface
|
||||||
|
- **[src/activitypub-client.js](src/activitypub-client.js)** - ActivityPub HTTP client
|
||||||
|
- **[src/security-tester.js](src/security-tester.js)** - Security testing module
|
||||||
|
- **[src/mock-server.js](src/mock-server.js)** - Mock ActivityPub server
|
||||||
|
|
||||||
|
## 🧪 Examples & Tests
|
||||||
|
|
||||||
|
### Sample Payloads
|
||||||
|
|
||||||
|
- **[examples/create-note.json](examples/create-note.json)** - Basic Create activity
|
||||||
|
- **[examples/follow.json](examples/follow.json)** - Follow activity
|
||||||
|
- **[examples/xss-payload.json](examples/xss-payload.json)** - XSS test vectors
|
||||||
|
- **[examples/ssrf-payload.json](examples/ssrf-payload.json)** - SSRF test vectors
|
||||||
|
|
||||||
|
### Test Scripts
|
||||||
|
|
||||||
|
- **[test.sh](test.sh)** - Automated test suite
|
||||||
|
|
||||||
|
## 🎯 Quick Navigation
|
||||||
|
|
||||||
|
### I want to...
|
||||||
|
|
||||||
|
#### Learn about the project
|
||||||
|
→ Start with [README.md](README.md)
|
||||||
|
→ Read [PROJECT_SUMMARY.md](PROJECT_SUMMARY.md) for complete overview
|
||||||
|
|
||||||
|
#### Get started quickly
|
||||||
|
→ Follow [QUICKSTART.md](QUICKSTART.md)
|
||||||
|
→ Run `./test.sh` to see it in action
|
||||||
|
|
||||||
|
#### Understand how to use it
|
||||||
|
→ Read [examples/USAGE.md](examples/USAGE.md)
|
||||||
|
→ Try the example commands
|
||||||
|
|
||||||
|
#### Learn security testing
|
||||||
|
→ Read [docs/SECURITY_TESTING.md](docs/SECURITY_TESTING.md)
|
||||||
|
→ Review the test payloads in `examples/`
|
||||||
|
|
||||||
|
#### Understand the code
|
||||||
|
→ Read [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
|
||||||
|
→ Review source code in `src/`
|
||||||
|
|
||||||
|
#### Extend the toolkit
|
||||||
|
→ Read extension points in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
|
||||||
|
→ Look at existing implementations in `src/`
|
||||||
|
|
||||||
|
## 📋 Common Tasks
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
```bash
|
||||||
|
cd activitypub-security-poc
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
See: [README.md](README.md#installation)
|
||||||
|
|
||||||
|
### Run Mock Server
|
||||||
|
```bash
|
||||||
|
npm run mock-server
|
||||||
|
```
|
||||||
|
See: [QUICKSTART.md](QUICKSTART.md#start-mock-server)
|
||||||
|
|
||||||
|
### Run Security Scan
|
||||||
|
```bash
|
||||||
|
node src/cli.js security-scan --target http://localhost:3000/users/alice/inbox
|
||||||
|
```
|
||||||
|
See: [examples/USAGE.md](examples/USAGE.md#run-security-scans)
|
||||||
|
|
||||||
|
### Test Inbox
|
||||||
|
```bash
|
||||||
|
node src/cli.js test-inbox --target URL --content "message"
|
||||||
|
```
|
||||||
|
See: [QUICKSTART.md](QUICKSTART.md#test-inbox)
|
||||||
|
|
||||||
|
### Craft Activity
|
||||||
|
```bash
|
||||||
|
node src/cli.js craft --type Create --object Note --content "text"
|
||||||
|
```
|
||||||
|
See: [examples/USAGE.md](examples/USAGE.md#craft-custom-activities)
|
||||||
|
|
||||||
|
## 🔍 Find Information About...
|
||||||
|
|
||||||
|
### ActivityPub Protocol
|
||||||
|
- [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) - Protocol implementation
|
||||||
|
- [src/activitypub-client.js](src/activitypub-client.js) - Client code
|
||||||
|
- [src/mock-server.js](src/mock-server.js) - Server implementation
|
||||||
|
|
||||||
|
### Security Testing
|
||||||
|
- [docs/SECURITY_TESTING.md](docs/SECURITY_TESTING.md) - Methodology
|
||||||
|
- [src/security-tester.js](src/security-tester.js) - Test implementation
|
||||||
|
- [examples/*.json](examples/) - Test payloads
|
||||||
|
|
||||||
|
### Command-Line Usage
|
||||||
|
- [QUICKSTART.md](QUICKSTART.md) - Quick reference
|
||||||
|
- [examples/USAGE.md](examples/USAGE.md) - Detailed examples
|
||||||
|
- [src/cli.js](src/cli.js) - CLI implementation
|
||||||
|
|
||||||
|
### Mock Server
|
||||||
|
- [src/mock-server.js](src/mock-server.js) - Server code
|
||||||
|
- [examples/USAGE.md](examples/USAGE.md#testing-workflow) - Usage guide
|
||||||
|
- Run `node src/cli.js mock-server --help`
|
||||||
|
|
||||||
|
## 📚 Documentation by Audience
|
||||||
|
|
||||||
|
### For Security Testers
|
||||||
|
1. [docs/SECURITY_TESTING.md](docs/SECURITY_TESTING.md) - Testing methodology
|
||||||
|
2. [examples/USAGE.md](examples/USAGE.md) - Practical examples
|
||||||
|
3. [QUICKSTART.md](QUICKSTART.md) - Command reference
|
||||||
|
|
||||||
|
### For Developers
|
||||||
|
1. [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) - Code architecture
|
||||||
|
2. [src/](src/) - Source code
|
||||||
|
3. [README.md](README.md) - Setup and usage
|
||||||
|
|
||||||
|
### For Learners
|
||||||
|
1. [README.md](README.md) - Overview
|
||||||
|
2. [PROJECT_SUMMARY.md](PROJECT_SUMMARY.md) - What it does
|
||||||
|
3. [examples/USAGE.md](examples/USAGE.md) - How to use it
|
||||||
|
4. [docs/SECURITY_TESTING.md](docs/SECURITY_TESTING.md) - Security concepts
|
||||||
|
|
||||||
|
## 🗂️ Complete File Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
activitypub-security-poc/
|
||||||
|
├── README.md # Project overview
|
||||||
|
├── QUICKSTART.md # Quick reference
|
||||||
|
├── PROJECT_SUMMARY.md # Complete summary
|
||||||
|
├── TABLE_OF_CONTENTS.md # This file
|
||||||
|
├── package.json # Dependencies
|
||||||
|
├── .gitignore # Git ignore rules
|
||||||
|
├── test.sh # Test script
|
||||||
|
│
|
||||||
|
├── src/ # Source code
|
||||||
|
│ ├── cli.js # CLI interface
|
||||||
|
│ ├── activitypub-client.js # AP client
|
||||||
|
│ ├── security-tester.js # Security tests
|
||||||
|
│ └── mock-server.js # Mock server
|
||||||
|
│
|
||||||
|
├── docs/ # Documentation
|
||||||
|
│ ├── ARCHITECTURE.md # Technical docs
|
||||||
|
│ └── SECURITY_TESTING.md # Testing guide
|
||||||
|
│
|
||||||
|
└── examples/ # Examples & payloads
|
||||||
|
├── USAGE.md # Usage guide
|
||||||
|
├── create-note.json # Sample Create
|
||||||
|
├── follow.json # Sample Follow
|
||||||
|
├── xss-payload.json # XSS tests
|
||||||
|
└── ssrf-payload.json # SSRF tests
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚀 Getting Started Path
|
||||||
|
|
||||||
|
**Complete Beginner:**
|
||||||
|
1. Read [README.md](README.md)
|
||||||
|
2. Run `npm install`
|
||||||
|
3. Run `./test.sh`
|
||||||
|
4. Read [QUICKSTART.md](QUICKSTART.md)
|
||||||
|
5. Experiment with commands
|
||||||
|
|
||||||
|
**Security Tester:**
|
||||||
|
1. Read [README.md](README.md)
|
||||||
|
2. Read [docs/SECURITY_TESTING.md](docs/SECURITY_TESTING.md)
|
||||||
|
3. Review [examples/USAGE.md](examples/USAGE.md)
|
||||||
|
4. Start testing with mock server
|
||||||
|
|
||||||
|
**Developer:**
|
||||||
|
1. Read [README.md](README.md)
|
||||||
|
2. Read [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
|
||||||
|
3. Review source code in [src/](src/)
|
||||||
|
4. Extend as needed
|
||||||
|
|
||||||
|
## 💡 Tips
|
||||||
|
|
||||||
|
- Use `--help` with any command for detailed options
|
||||||
|
- Start with mock server before testing real instances
|
||||||
|
- Always get permission before testing third-party systems
|
||||||
|
- Check the example payloads for testing ideas
|
||||||
|
- Review mock server logs to see what it detects
|
||||||
|
|
||||||
|
## 📞 Support
|
||||||
|
|
||||||
|
- **Questions about usage?** → [examples/USAGE.md](examples/USAGE.md)
|
||||||
|
- **Security testing questions?** → [docs/SECURITY_TESTING.md](docs/SECURITY_TESTING.md)
|
||||||
|
- **Code questions?** → [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
|
||||||
|
- **Quick help?** → [QUICKSTART.md](QUICKSTART.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Happy Testing! 🛡️**
|
||||||
408
docs/ARCHITECTURE.md
Archivo normal
408
docs/ARCHITECTURE.md
Archivo normal
@@ -0,0 +1,408 @@
|
|||||||
|
# ActivityPub Security PoC - Architecture
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
activitypub-security-poc/
|
||||||
|
├── src/
|
||||||
|
│ ├── cli.js # Command-line interface
|
||||||
|
│ ├── activitypub-client.js # ActivityPub HTTP client
|
||||||
|
│ ├── security-tester.js # Security testing module
|
||||||
|
│ └── mock-server.js # Mock ActivityPub server
|
||||||
|
├── examples/
|
||||||
|
│ ├── create-note.json # Sample Create activity
|
||||||
|
│ ├── follow.json # Sample Follow activity
|
||||||
|
│ ├── xss-payload.json # XSS test payload
|
||||||
|
│ ├── ssrf-payload.json # SSRF test payload
|
||||||
|
│ └── USAGE.md # Usage examples
|
||||||
|
├── docs/
|
||||||
|
│ ├── ARCHITECTURE.md # This file
|
||||||
|
│ └── SECURITY_TESTING.md # Security testing guide
|
||||||
|
├── package.json
|
||||||
|
├── README.md
|
||||||
|
└── test.sh # Quick test script
|
||||||
|
```
|
||||||
|
|
||||||
|
## Core Components
|
||||||
|
|
||||||
|
### 1. ActivityPub Client (`activitypub-client.js`)
|
||||||
|
|
||||||
|
**Purpose**: Low-level HTTP client for ActivityPub interactions.
|
||||||
|
|
||||||
|
**Key Features**:
|
||||||
|
- Send activities to inbox endpoints
|
||||||
|
- Fetch from outbox endpoints
|
||||||
|
- Fetch actor profiles
|
||||||
|
- HTTP signature generation (for authenticated requests)
|
||||||
|
- JSON-LD context handling
|
||||||
|
- Activity creation helpers
|
||||||
|
|
||||||
|
**Main Methods**:
|
||||||
|
```javascript
|
||||||
|
class ActivityPubClient {
|
||||||
|
sendToInbox(inboxUrl, activity, options)
|
||||||
|
fetchOutbox(outboxUrl, options)
|
||||||
|
fetchActor(actorUrl, options)
|
||||||
|
signRequest(method, url, body)
|
||||||
|
createActivity(type, object, additionalProps)
|
||||||
|
createNote(content, additionalProps)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Security Tester (`security-tester.js`)
|
||||||
|
|
||||||
|
**Purpose**: Automated security testing framework.
|
||||||
|
|
||||||
|
**Key Features**:
|
||||||
|
- XSS vulnerability testing
|
||||||
|
- SSRF vulnerability testing
|
||||||
|
- Object injection testing
|
||||||
|
- Signature bypass testing
|
||||||
|
- Authorization testing
|
||||||
|
- SQL/Command injection testing
|
||||||
|
|
||||||
|
**Main Methods**:
|
||||||
|
```javascript
|
||||||
|
class SecurityTester {
|
||||||
|
testXSS(inboxUrl)
|
||||||
|
testSSRF(inboxUrl)
|
||||||
|
testObjectInjection(inboxUrl)
|
||||||
|
testSignatureBypass(inboxUrl)
|
||||||
|
testAuthorization(actorUrl, inboxUrl)
|
||||||
|
testInjection(inboxUrl)
|
||||||
|
runAllTests(targetUrl, options)
|
||||||
|
generateReport(results)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. CLI (`cli.js`)
|
||||||
|
|
||||||
|
**Purpose**: User-friendly command-line interface.
|
||||||
|
|
||||||
|
**Commands**:
|
||||||
|
- `test-inbox` - Send activities to inbox
|
||||||
|
- `test-outbox` - Fetch from outbox
|
||||||
|
- `fetch-actor` - Get actor profile
|
||||||
|
- `security-scan` - Run security tests
|
||||||
|
- `craft` - Create custom activities
|
||||||
|
- `mock-server` - Start mock server
|
||||||
|
|
||||||
|
### 4. Mock Server (`mock-server.js`)
|
||||||
|
|
||||||
|
**Purpose**: Simulated ActivityPub server for testing.
|
||||||
|
|
||||||
|
**Key Features**:
|
||||||
|
- Full ActivityPub endpoint simulation
|
||||||
|
- WebFinger support
|
||||||
|
- Activity validation
|
||||||
|
- Security issue detection and logging
|
||||||
|
- Multiple mock users (alice, bob)
|
||||||
|
|
||||||
|
**Endpoints**:
|
||||||
|
- `/.well-known/webfinger` - WebFinger
|
||||||
|
- `/users/:username` - Actor profiles
|
||||||
|
- `/users/:username/inbox` - User inbox
|
||||||
|
- `/users/:username/outbox` - User outbox
|
||||||
|
- `/users/:username/followers` - Followers collection
|
||||||
|
- `/users/:username/following` - Following collection
|
||||||
|
- `/inbox` - Shared inbox
|
||||||
|
|
||||||
|
## Data Flow
|
||||||
|
|
||||||
|
### Sending an Activity
|
||||||
|
|
||||||
|
```
|
||||||
|
User Command
|
||||||
|
↓
|
||||||
|
CLI (cli.js)
|
||||||
|
↓
|
||||||
|
ActivityPubClient.sendToInbox()
|
||||||
|
↓
|
||||||
|
HTTP POST with JSON-LD payload
|
||||||
|
↓
|
||||||
|
Target Server (or Mock Server)
|
||||||
|
↓
|
||||||
|
Response (status, headers, body)
|
||||||
|
↓
|
||||||
|
Display to User
|
||||||
|
```
|
||||||
|
|
||||||
|
### Security Scan
|
||||||
|
|
||||||
|
```
|
||||||
|
User Command
|
||||||
|
↓
|
||||||
|
CLI (cli.js)
|
||||||
|
↓
|
||||||
|
SecurityTester.runAllTests()
|
||||||
|
↓
|
||||||
|
Multiple Test Methods (XSS, SSRF, etc.)
|
||||||
|
↓
|
||||||
|
ActivityPubClient.sendToInbox() for each payload
|
||||||
|
↓
|
||||||
|
Collect responses
|
||||||
|
↓
|
||||||
|
Analyze for vulnerabilities
|
||||||
|
↓
|
||||||
|
Generate Report
|
||||||
|
↓
|
||||||
|
Display to User
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mock Server Request Handling
|
||||||
|
|
||||||
|
```
|
||||||
|
HTTP Request
|
||||||
|
↓
|
||||||
|
MockActivityPubServer.handleRequest()
|
||||||
|
↓
|
||||||
|
Route to appropriate handler
|
||||||
|
↓
|
||||||
|
Validate activity (if POST)
|
||||||
|
↓
|
||||||
|
Perform security checks
|
||||||
|
↓
|
||||||
|
Log detected issues
|
||||||
|
↓
|
||||||
|
Store activity (if valid)
|
||||||
|
↓
|
||||||
|
Return response
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Testing Methodology
|
||||||
|
|
||||||
|
### 1. Test Case Design
|
||||||
|
|
||||||
|
Each security test:
|
||||||
|
1. Creates a malicious payload
|
||||||
|
2. Sends it to the target endpoint
|
||||||
|
3. Analyzes the response
|
||||||
|
4. Determines if vulnerability exists based on:
|
||||||
|
- Response status (200/202 = potential issue)
|
||||||
|
- Error messages
|
||||||
|
- Behavior changes
|
||||||
|
|
||||||
|
### 2. Payload Categories
|
||||||
|
|
||||||
|
**XSS Payloads**:
|
||||||
|
- Script tags
|
||||||
|
- Event handlers
|
||||||
|
- JavaScript protocols
|
||||||
|
- SVG-based vectors
|
||||||
|
- Encoded payloads
|
||||||
|
|
||||||
|
**SSRF Payloads**:
|
||||||
|
- Internal IPs (localhost, 127.0.0.1)
|
||||||
|
- Cloud metadata endpoints
|
||||||
|
- File protocol URLs
|
||||||
|
- IPv6 localhost
|
||||||
|
- DNS rebinding targets
|
||||||
|
|
||||||
|
**Injection Payloads**:
|
||||||
|
- SQL injection patterns
|
||||||
|
- Command injection sequences
|
||||||
|
- Prototype pollution attempts
|
||||||
|
- Path traversal strings
|
||||||
|
|
||||||
|
### 3. Validation Logic
|
||||||
|
|
||||||
|
The mock server demonstrates proper validation:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Activity validation
|
||||||
|
validateActivity(activity) {
|
||||||
|
- Check for required fields
|
||||||
|
- Validate @context
|
||||||
|
- Verify actor field
|
||||||
|
- Return validation result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Security checks
|
||||||
|
performSecurityChecks(activity) {
|
||||||
|
- Scan for XSS patterns
|
||||||
|
- Check for SSRF attempts
|
||||||
|
- Detect prototype pollution
|
||||||
|
- Identify SQL injection patterns
|
||||||
|
- Return list of issues
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## HTTP Signatures (Planned)
|
||||||
|
|
||||||
|
Future versions will implement full HTTP signature support:
|
||||||
|
|
||||||
|
```
|
||||||
|
1. Generate RSA key pair
|
||||||
|
2. Include public key in actor profile
|
||||||
|
3. Sign requests with private key
|
||||||
|
4. Verify signatures on mock server
|
||||||
|
5. Test signature bypass scenarios
|
||||||
|
```
|
||||||
|
|
||||||
|
## Extension Points
|
||||||
|
|
||||||
|
### Adding New Security Tests
|
||||||
|
|
||||||
|
1. Add test method to `SecurityTester`:
|
||||||
|
```javascript
|
||||||
|
async testNewVulnerability(inboxUrl) {
|
||||||
|
const payloads = [...];
|
||||||
|
const results = [];
|
||||||
|
|
||||||
|
for (const payload of payloads) {
|
||||||
|
// Create activity with payload
|
||||||
|
// Send to inbox
|
||||||
|
// Analyze response
|
||||||
|
results.push({...});
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Integrate into `runAllTests()`:
|
||||||
|
```javascript
|
||||||
|
if (!options.tests || options.tests.includes('newvuln')) {
|
||||||
|
allResults.tests.newVuln = await this.testNewVulnerability(targetUrl);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Adding New CLI Commands
|
||||||
|
|
||||||
|
1. Add command to `cli.js`:
|
||||||
|
```javascript
|
||||||
|
program
|
||||||
|
.command('new-command')
|
||||||
|
.description('Description')
|
||||||
|
.option('-f, --flag <value>', 'Option')
|
||||||
|
.action(async (options) => {
|
||||||
|
// Implementation
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Extending Mock Server
|
||||||
|
|
||||||
|
1. Add new endpoint handler:
|
||||||
|
```javascript
|
||||||
|
async handleNewEndpoint(req, res, path) {
|
||||||
|
// Handle request
|
||||||
|
this.sendJSON(res, data);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Add route in `handleRequest()`:
|
||||||
|
```javascript
|
||||||
|
if (path.match(/^\/new-endpoint$/)) {
|
||||||
|
await this.handleNewEndpoint(req, res, path);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### Code Organization
|
||||||
|
|
||||||
|
- **Separation of Concerns**: Client, tester, CLI, and server are separate modules
|
||||||
|
- **Reusability**: Core client can be used independently
|
||||||
|
- **Extensibility**: Easy to add new tests or commands
|
||||||
|
- **Clean Code**: Well-commented, readable, maintainable
|
||||||
|
|
||||||
|
### Error Handling
|
||||||
|
|
||||||
|
- Graceful error handling in all HTTP requests
|
||||||
|
- Informative error messages
|
||||||
|
- Non-blocking errors (continue testing on failure)
|
||||||
|
|
||||||
|
### Logging
|
||||||
|
|
||||||
|
- Clear console output with color coding
|
||||||
|
- Structured JSON output for results
|
||||||
|
- Detailed mock server logs for debugging
|
||||||
|
|
||||||
|
### Testing Philosophy
|
||||||
|
|
||||||
|
- **Defense in Depth**: Test multiple vulnerability types
|
||||||
|
- **Real-world Scenarios**: Payloads based on actual attacks
|
||||||
|
- **Responsible Testing**: Tools designed for authorized testing only
|
||||||
|
- **Educational**: Code demonstrates both vulnerabilities and mitigations
|
||||||
|
|
||||||
|
## Future Enhancements
|
||||||
|
|
||||||
|
### Planned Features
|
||||||
|
|
||||||
|
1. **Full HTTP Signature Support**
|
||||||
|
- RSA key generation
|
||||||
|
- Signature creation and verification
|
||||||
|
- Key rotation testing
|
||||||
|
|
||||||
|
2. **WebFinger Testing**
|
||||||
|
- Account discovery
|
||||||
|
- Resource validation
|
||||||
|
- SSRF via WebFinger
|
||||||
|
|
||||||
|
3. **Media Upload Testing**
|
||||||
|
- File upload vulnerabilities
|
||||||
|
- Content-Type confusion
|
||||||
|
- Malicious file detection bypass
|
||||||
|
|
||||||
|
4. **Rate Limiting Tests**
|
||||||
|
- Concurrent request flooding
|
||||||
|
- Activity spam detection
|
||||||
|
- Resource exhaustion
|
||||||
|
|
||||||
|
5. **Interactive Mode**
|
||||||
|
- Step-by-step testing wizard
|
||||||
|
- Real-time response analysis
|
||||||
|
- Guided security audits
|
||||||
|
|
||||||
|
6. **CI/CD Integration**
|
||||||
|
- GitHub Actions workflow
|
||||||
|
- Automated regression testing
|
||||||
|
- Security benchmarking
|
||||||
|
|
||||||
|
7. **Reporting**
|
||||||
|
- HTML report generation
|
||||||
|
- PDF export
|
||||||
|
- Vulnerability database integration
|
||||||
|
|
||||||
|
## Performance Considerations
|
||||||
|
|
||||||
|
- **Async Operations**: All HTTP requests are asynchronous
|
||||||
|
- **Timeout Handling**: Configurable timeouts prevent hanging
|
||||||
|
- **Resource Management**: Proper cleanup of connections
|
||||||
|
- **Scalability**: Can test multiple endpoints in parallel
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
### Tool Security
|
||||||
|
|
||||||
|
- No sensitive data storage
|
||||||
|
- No persistent state by default
|
||||||
|
- Safe defaults (localhost, low timeout)
|
||||||
|
- Clear warnings about authorized testing
|
||||||
|
|
||||||
|
### Mock Server Security
|
||||||
|
|
||||||
|
- Intentionally logs security issues (for demonstration)
|
||||||
|
- Does not execute malicious payloads
|
||||||
|
- Sandboxed environment
|
||||||
|
- No real persistence
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
- **commander**: CLI argument parsing
|
||||||
|
- **node-fetch**: HTTP client
|
||||||
|
- **chalk**: Terminal colors
|
||||||
|
- **jsonld**: JSON-LD processing
|
||||||
|
- **http-signature**: HTTP signature support (planned)
|
||||||
|
|
||||||
|
All dependencies are well-maintained and security-audited.
|
||||||
|
|
||||||
|
## Contribution Guidelines
|
||||||
|
|
||||||
|
When extending this project:
|
||||||
|
|
||||||
|
1. **Follow the architecture**: Keep separation of concerns
|
||||||
|
2. **Add tests**: Include example payloads
|
||||||
|
3. **Document**: Update this file and other docs
|
||||||
|
4. **Clean code**: Follow existing style
|
||||||
|
5. **Security first**: Consider implications of new features
|
||||||
345
docs/SECURITY_TESTING.md
Archivo normal
345
docs/SECURITY_TESTING.md
Archivo normal
@@ -0,0 +1,345 @@
|
|||||||
|
# Security Testing Guide
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This document outlines the security testing methodology and test cases for ActivityPub implementations.
|
||||||
|
|
||||||
|
## Security Test Categories
|
||||||
|
|
||||||
|
### 1. Cross-Site Scripting (XSS)
|
||||||
|
|
||||||
|
**Objective**: Identify if user-supplied content is properly sanitized before display.
|
||||||
|
|
||||||
|
**Test Cases**:
|
||||||
|
- Script tag injection: `<script>alert('XSS')</script>`
|
||||||
|
- Event handler injection: `<img src=x onerror=alert('XSS')>`
|
||||||
|
- JavaScript protocol: `javascript:alert('XSS')`
|
||||||
|
- SVG-based XSS: `<svg/onload=alert('XSS')>`
|
||||||
|
- Encoded payloads: `<script>alert('XSS')</script>`
|
||||||
|
|
||||||
|
**Vulnerable Scenarios**:
|
||||||
|
- Content rendered without HTML escaping
|
||||||
|
- Markdown/rich text processing vulnerabilities
|
||||||
|
- URL handling in attachment previews
|
||||||
|
|
||||||
|
### 2. Server-Side Request Forgery (SSRF)
|
||||||
|
|
||||||
|
**Objective**: Test if the server can be tricked into making requests to internal resources.
|
||||||
|
|
||||||
|
**Test Cases**:
|
||||||
|
- Internal network: `http://localhost:8080`, `http://127.0.0.1`
|
||||||
|
- Cloud metadata: `http://169.254.169.254/latest/meta-data/`
|
||||||
|
- IPv6 localhost: `http://[::1]:8080`
|
||||||
|
- File protocol: `file:///etc/passwd`
|
||||||
|
- DNS rebinding attacks
|
||||||
|
|
||||||
|
**Vulnerable Scenarios**:
|
||||||
|
- Fetching remote avatars/images without validation
|
||||||
|
- Link previews/unfurling
|
||||||
|
- WebFinger lookups without URL validation
|
||||||
|
|
||||||
|
### 3. Object Injection & Type Confusion
|
||||||
|
|
||||||
|
**Objective**: Test object validation and type handling.
|
||||||
|
|
||||||
|
**Test Cases**:
|
||||||
|
- Multiple type values: `"type": ["Note", "Delete"]`
|
||||||
|
- Missing required fields
|
||||||
|
- Prototype pollution: `__proto__` injection
|
||||||
|
- Constructor manipulation
|
||||||
|
- Unexpected nested objects
|
||||||
|
|
||||||
|
**Vulnerable Scenarios**:
|
||||||
|
- Weak JSON schema validation
|
||||||
|
- Dynamic property assignment
|
||||||
|
- Type coercion vulnerabilities
|
||||||
|
|
||||||
|
### 4. Authentication & Authorization
|
||||||
|
|
||||||
|
**Objective**: Verify proper access controls and signature verification.
|
||||||
|
|
||||||
|
**Test Cases**:
|
||||||
|
- Missing HTTP signatures
|
||||||
|
- Invalid/forged signatures
|
||||||
|
- Actor impersonation
|
||||||
|
- Unauthorized deletions
|
||||||
|
- Private content access
|
||||||
|
- Relay poisoning
|
||||||
|
|
||||||
|
**Vulnerable Scenarios**:
|
||||||
|
- Weak signature verification
|
||||||
|
- Missing authorization checks
|
||||||
|
- Confused deputy attacks
|
||||||
|
|
||||||
|
### 5. Injection Attacks
|
||||||
|
|
||||||
|
**Objective**: Test for command and SQL injection vulnerabilities.
|
||||||
|
|
||||||
|
**Test Cases**:
|
||||||
|
- SQL injection: `' OR '1'='1`, `'; DROP TABLE--`
|
||||||
|
- Command injection: `; ls -la`, `| whoami`, `$(uname -a)`
|
||||||
|
- LDAP injection
|
||||||
|
- Template injection
|
||||||
|
- Path traversal: `../../etc/passwd`
|
||||||
|
|
||||||
|
**Vulnerable Scenarios**:
|
||||||
|
- Direct database queries with user input
|
||||||
|
- System command execution
|
||||||
|
- Template rendering with user content
|
||||||
|
|
||||||
|
### 6. Denial of Service (DoS)
|
||||||
|
|
||||||
|
**Objective**: Test resilience against resource exhaustion.
|
||||||
|
|
||||||
|
**Test Cases**:
|
||||||
|
- Large payloads (MB-sized JSON)
|
||||||
|
- Deeply nested objects
|
||||||
|
- Circular references
|
||||||
|
- Excessive followers/following counts
|
||||||
|
- Rapid activity submission
|
||||||
|
|
||||||
|
**Vulnerable Scenarios**:
|
||||||
|
- No rate limiting
|
||||||
|
- Unbounded resource allocation
|
||||||
|
- Inefficient parsing
|
||||||
|
|
||||||
|
## Testing Methodology
|
||||||
|
|
||||||
|
### 1. Reconnaissance
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Fetch actor profile
|
||||||
|
node src/cli.js fetch-actor --target https://target.example/users/alice
|
||||||
|
|
||||||
|
# Check outbox
|
||||||
|
node src/cli.js test-outbox --target https://target.example/users/alice/outbox
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Baseline Testing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Send valid activity
|
||||||
|
node src/cli.js test-inbox \
|
||||||
|
--target https://target.example/users/alice/inbox \
|
||||||
|
--payload examples/create-note.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Automated Security Scan
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run all tests
|
||||||
|
node src/cli.js security-scan \
|
||||||
|
--target https://target.example/users/alice/inbox \
|
||||||
|
--output scan-results.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Manual Payload Testing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test specific vulnerability
|
||||||
|
node src/cli.js test-inbox \
|
||||||
|
--target https://target.example/users/alice/inbox \
|
||||||
|
--payload examples/xss-payload.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Analysis
|
||||||
|
|
||||||
|
Review logs, responses, and behavior:
|
||||||
|
- HTTP status codes
|
||||||
|
- Error messages
|
||||||
|
- Server-side rendering
|
||||||
|
- Database queries
|
||||||
|
- Network traffic
|
||||||
|
|
||||||
|
## Responsible Disclosure
|
||||||
|
|
||||||
|
If you discover a vulnerability:
|
||||||
|
|
||||||
|
1. **Do not exploit** beyond proof-of-concept
|
||||||
|
2. **Document** the issue thoroughly
|
||||||
|
3. **Report privately** to the maintainers
|
||||||
|
4. **Allow time** for fixes (typically 90 days)
|
||||||
|
5. **Coordinate** public disclosure
|
||||||
|
|
||||||
|
## Common Vulnerabilities in ActivityPub
|
||||||
|
|
||||||
|
### 1. Inadequate Input Validation
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Vulnerable
|
||||||
|
app.post('/inbox', (req, res) => {
|
||||||
|
const activity = req.body;
|
||||||
|
db.query(`INSERT INTO activities VALUES ('${activity.id}')`); // SQL injection
|
||||||
|
});
|
||||||
|
|
||||||
|
// Secure
|
||||||
|
app.post('/inbox', (req, res) => {
|
||||||
|
const activity = req.body;
|
||||||
|
if (!validateActivitySchema(activity)) {
|
||||||
|
return res.status(400).send('Invalid activity');
|
||||||
|
}
|
||||||
|
db.query('INSERT INTO activities VALUES (?)', [activity.id]);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Missing Signature Verification
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Vulnerable
|
||||||
|
app.post('/inbox', (req, res) => {
|
||||||
|
// No signature check
|
||||||
|
processActivity(req.body);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Secure
|
||||||
|
app.post('/inbox', async (req, res) => {
|
||||||
|
if (!await verifyHTTPSignature(req)) {
|
||||||
|
return res.status(401).send('Invalid signature');
|
||||||
|
}
|
||||||
|
processActivity(req.body);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. SSRF in Media Fetching
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Vulnerable
|
||||||
|
async function fetchAvatar(url) {
|
||||||
|
return await fetch(url); // No URL validation
|
||||||
|
}
|
||||||
|
|
||||||
|
// Secure
|
||||||
|
async function fetchAvatar(url) {
|
||||||
|
const parsed = new URL(url);
|
||||||
|
|
||||||
|
// Block internal IPs
|
||||||
|
if (isInternalIP(parsed.hostname)) {
|
||||||
|
throw new Error('Invalid URL');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only allow http/https
|
||||||
|
if (!['http:', 'https:'].includes(parsed.protocol)) {
|
||||||
|
throw new Error('Invalid protocol');
|
||||||
|
}
|
||||||
|
|
||||||
|
return await fetch(url, { redirect: 'manual' });
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Unescaped Content Rendering
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Vulnerable
|
||||||
|
function renderNote(note) {
|
||||||
|
return `<div>${note.content}</div>`; // XSS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Secure
|
||||||
|
function renderNote(note) {
|
||||||
|
const escaped = escapeHtml(note.content);
|
||||||
|
return `<div>${escaped}</div>`;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Checklist
|
||||||
|
|
||||||
|
- [ ] HTTP signatures verified on all inbox POST requests
|
||||||
|
- [ ] Actor URLs validated (no internal IPs, valid protocols)
|
||||||
|
- [ ] Content sanitized before display (HTML escaping)
|
||||||
|
- [ ] Rate limiting on endpoints
|
||||||
|
- [ ] JSON schema validation
|
||||||
|
- [ ] Authorization checks on Delete/Update activities
|
||||||
|
- [ ] SSRF protection on media fetching
|
||||||
|
- [ ] Proper error handling (no sensitive info in errors)
|
||||||
|
- [ ] CSRF protection
|
||||||
|
- [ ] Content Security Policy headers
|
||||||
|
- [ ] Input size limits
|
||||||
|
- [ ] Secure session management
|
||||||
|
|
||||||
|
## Tools & Resources
|
||||||
|
|
||||||
|
### Testing Tools
|
||||||
|
- This ActivityPub Security PoC
|
||||||
|
- Burp Suite
|
||||||
|
- OWASP ZAP
|
||||||
|
- curl/httpie
|
||||||
|
|
||||||
|
### References
|
||||||
|
- [ActivityPub Specification](https://www.w3.org/TR/activitypub/)
|
||||||
|
- [HTTP Signatures](https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures)
|
||||||
|
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
|
||||||
|
- [Fediverse Security Best Practices](https://github.com/w3c/activitypub/issues/367)
|
||||||
|
|
||||||
|
## Reporting Format
|
||||||
|
|
||||||
|
When reporting issues, include:
|
||||||
|
|
||||||
|
1. **Title**: Brief description
|
||||||
|
2. **Severity**: Critical/High/Medium/Low
|
||||||
|
3. **Description**: What the vulnerability is
|
||||||
|
4. **Steps to Reproduce**: Detailed reproduction steps
|
||||||
|
5. **Impact**: What an attacker could do
|
||||||
|
6. **Proof of Concept**: Code/payload demonstrating the issue
|
||||||
|
7. **Remediation**: Suggested fix
|
||||||
|
8. **References**: Related CVEs, articles
|
||||||
|
|
||||||
|
### Example Report
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
## XSS in Note Content
|
||||||
|
|
||||||
|
**Severity**: High
|
||||||
|
|
||||||
|
**Description**: User-supplied content in Note objects is rendered without HTML escaping, allowing arbitrary JavaScript execution.
|
||||||
|
|
||||||
|
**Steps to Reproduce**:
|
||||||
|
1. Send Create activity with XSS payload in content field
|
||||||
|
2. View the note in web interface
|
||||||
|
3. Observe JavaScript execution
|
||||||
|
|
||||||
|
**Impact**: Account takeover, data theft, malware distribution
|
||||||
|
|
||||||
|
**Proof of Concept**:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "Create",
|
||||||
|
"object": {
|
||||||
|
"type": "Note",
|
||||||
|
"content": "<script>alert(document.cookie)</script>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Remediation**: Implement HTML escaping for all user content before rendering.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Legal Considerations
|
||||||
|
|
||||||
|
- Only test systems you own or have explicit permission to test
|
||||||
|
- Comply with computer fraud and abuse laws
|
||||||
|
- Respect bug bounty program terms
|
||||||
|
- Obtain written authorization for penetration testing
|
||||||
|
- Don't disrupt services or access private data
|
||||||
|
|
||||||
|
## Continuous Testing
|
||||||
|
|
||||||
|
Integrate security testing into CI/CD:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# .github/workflows/security-test.yml
|
||||||
|
name: Security Tests
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
security:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Run security scan
|
||||||
|
run: |
|
||||||
|
cd activitypub-security-poc
|
||||||
|
npm install
|
||||||
|
npm run mock-server &
|
||||||
|
sleep 5
|
||||||
|
node src/cli.js security-scan --target http://localhost:3000/users/alice/inbox
|
||||||
|
```
|
||||||
309
examples/USAGE.md
Archivo normal
309
examples/USAGE.md
Archivo normal
@@ -0,0 +1,309 @@
|
|||||||
|
# ActivityPub Security PoC - Usage Examples
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### 1. Install Dependencies
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd activitypub-security-poc
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Start the Mock Server
|
||||||
|
|
||||||
|
In one terminal:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node src/cli.js mock-server --port 3000
|
||||||
|
```
|
||||||
|
|
||||||
|
Or using npm script:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run mock-server
|
||||||
|
```
|
||||||
|
|
||||||
|
The mock server will start at `http://localhost:3000` with two test users: `alice` and `bob`.
|
||||||
|
|
||||||
|
### 3. Test the Mock Server
|
||||||
|
|
||||||
|
In another terminal, try fetching an actor profile:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node src/cli.js fetch-actor --target http://localhost:3000/users/alice
|
||||||
|
```
|
||||||
|
|
||||||
|
## Command Reference
|
||||||
|
|
||||||
|
### Fetch Actor Profile
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node src/cli.js fetch-actor --target https://mastodon.social/@username
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test Outbox Endpoint
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node src/cli.js test-outbox --target http://localhost:3000/users/alice/outbox
|
||||||
|
```
|
||||||
|
|
||||||
|
### Send Activity to Inbox
|
||||||
|
|
||||||
|
Using a predefined payload:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node src/cli.js test-inbox \
|
||||||
|
--target http://localhost:3000/users/alice/inbox \
|
||||||
|
--payload examples/create-note.json
|
||||||
|
```
|
||||||
|
|
||||||
|
Using inline content:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node src/cli.js test-inbox \
|
||||||
|
--target http://localhost:3000/users/alice/inbox \
|
||||||
|
--content "Hello from security PoC!" \
|
||||||
|
--actor https://example.com/users/tester
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run Security Scans
|
||||||
|
|
||||||
|
Run all security tests:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node src/cli.js security-scan \
|
||||||
|
--target http://localhost:3000/users/alice/inbox \
|
||||||
|
--actor http://localhost:3000/users/alice
|
||||||
|
```
|
||||||
|
|
||||||
|
Run specific tests:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node src/cli.js security-scan \
|
||||||
|
--target http://localhost:3000/users/alice/inbox \
|
||||||
|
--tests xss,ssrf
|
||||||
|
```
|
||||||
|
|
||||||
|
Save results to file:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node src/cli.js security-scan \
|
||||||
|
--target http://localhost:3000/users/alice/inbox \
|
||||||
|
--output results.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### Craft Custom Activities
|
||||||
|
|
||||||
|
Create a simple note:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node src/cli.js craft \
|
||||||
|
--type Create \
|
||||||
|
--object Note \
|
||||||
|
--content "Custom activity message" \
|
||||||
|
--actor https://example.com/users/tester \
|
||||||
|
--to https://www.w3.org/ns/activitystreams#Public
|
||||||
|
```
|
||||||
|
|
||||||
|
Save to file:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node src/cli.js craft \
|
||||||
|
--type Follow \
|
||||||
|
--object https://target.example/users/alice \
|
||||||
|
--actor https://example.com/users/tester \
|
||||||
|
--output examples/my-follow.json
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing Against Real Instances
|
||||||
|
|
||||||
|
⚠️ **Warning**: Always obtain permission before testing third-party systems!
|
||||||
|
|
||||||
|
### Testing Mastodon
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Fetch actor
|
||||||
|
node src/cli.js fetch-actor --target https://mastodon.social/@Gargron
|
||||||
|
|
||||||
|
# Fetch outbox
|
||||||
|
node src/cli.js test-outbox --target https://mastodon.social/@Gargron/outbox
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing Your Own Instance
|
||||||
|
|
||||||
|
If you're running your own Mastodon instance:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Security scan on your instance
|
||||||
|
node src/cli.js security-scan \
|
||||||
|
--target https://your-instance.example/users/yourusername/inbox \
|
||||||
|
--tests xss,injection \
|
||||||
|
--output my-instance-scan.json
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Test Scenarios
|
||||||
|
|
||||||
|
### 1. XSS Testing
|
||||||
|
|
||||||
|
Test for Cross-Site Scripting vulnerabilities:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node src/cli.js test-inbox \
|
||||||
|
--target http://localhost:3000/users/alice/inbox \
|
||||||
|
--payload examples/xss-payload.json
|
||||||
|
```
|
||||||
|
|
||||||
|
The mock server will detect and log XSS patterns.
|
||||||
|
|
||||||
|
### 2. SSRF Testing
|
||||||
|
|
||||||
|
Test for Server-Side Request Forgery:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node src/cli.js test-inbox \
|
||||||
|
--target http://localhost:3000/users/alice/inbox \
|
||||||
|
--payload examples/ssrf-payload.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Full Security Audit
|
||||||
|
|
||||||
|
Run comprehensive tests:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node src/cli.js security-scan \
|
||||||
|
--target http://localhost:3000/users/alice/inbox \
|
||||||
|
--tests all \
|
||||||
|
--output full-audit-$(date +%Y%m%d).json
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing Workflow
|
||||||
|
|
||||||
|
### Complete Testing Session
|
||||||
|
|
||||||
|
1. **Start mock server**:
|
||||||
|
```bash
|
||||||
|
npm run mock-server
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Test basic connectivity**:
|
||||||
|
```bash
|
||||||
|
node src/cli.js fetch-actor --target http://localhost:3000/users/alice
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Send test activity**:
|
||||||
|
```bash
|
||||||
|
node src/cli.js test-inbox \
|
||||||
|
--target http://localhost:3000/users/alice/inbox \
|
||||||
|
--content "Testing basic delivery"
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Run security tests**:
|
||||||
|
```bash
|
||||||
|
node src/cli.js security-scan \
|
||||||
|
--target http://localhost:3000/users/alice/inbox
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Review mock server logs** for detected issues
|
||||||
|
|
||||||
|
## Advanced Usage
|
||||||
|
|
||||||
|
### Custom Security Tests
|
||||||
|
|
||||||
|
You can create custom payloads by editing the JSON files in `examples/` or creating new ones:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"@context": "https://www.w3.org/ns/activitystreams",
|
||||||
|
"type": "Create",
|
||||||
|
"actor": "https://example.com/users/tester",
|
||||||
|
"object": {
|
||||||
|
"type": "Note",
|
||||||
|
"content": "Your custom test content"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then test it:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node src/cli.js test-inbox \
|
||||||
|
--target http://localhost:3000/users/alice/inbox \
|
||||||
|
--payload your-custom-payload.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing Different Activity Types
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Follow activity
|
||||||
|
node src/cli.js craft --type Follow --object https://target.example/users/alice | \
|
||||||
|
node src/cli.js test-inbox --target http://localhost:3000/users/bob/inbox --payload -
|
||||||
|
|
||||||
|
# Update activity
|
||||||
|
node src/cli.js craft --type Update --content "Updated content"
|
||||||
|
|
||||||
|
# Delete activity
|
||||||
|
node src/cli.js craft --type Delete --object https://example.com/notes/123
|
||||||
|
```
|
||||||
|
|
||||||
|
## Interpreting Results
|
||||||
|
|
||||||
|
### Mock Server Output
|
||||||
|
|
||||||
|
The mock server will display:
|
||||||
|
- 📥 Received activities
|
||||||
|
- ⚠️ Validation warnings
|
||||||
|
- 🚨 Security issues detected
|
||||||
|
|
||||||
|
### Security Scan Output
|
||||||
|
|
||||||
|
- ✅ SAFE - The endpoint properly handled the test
|
||||||
|
- ❌ VULNERABLE - Potential security issue detected
|
||||||
|
|
||||||
|
### Result JSON Structure
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"target": "http://localhost:3000/users/alice/inbox",
|
||||||
|
"timestamp": "2025-11-16T...",
|
||||||
|
"tests": {
|
||||||
|
"xss": [...],
|
||||||
|
"ssrf": [...],
|
||||||
|
"injection": [...]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Always test on your own infrastructure first**
|
||||||
|
2. **Get explicit permission before testing external systems**
|
||||||
|
3. **Review logs on both client and server side**
|
||||||
|
4. **Document your findings**
|
||||||
|
5. **Report vulnerabilities responsibly**
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Connection Refused
|
||||||
|
|
||||||
|
- Ensure the target server is running
|
||||||
|
- Check firewall rules
|
||||||
|
- Verify the URL is correct
|
||||||
|
|
||||||
|
### 401/403 Errors
|
||||||
|
|
||||||
|
- The endpoint requires authentication
|
||||||
|
- HTTP signatures may be required
|
||||||
|
- Check if the endpoint accepts external activities
|
||||||
|
|
||||||
|
### Timeout Errors
|
||||||
|
|
||||||
|
- Server may be slow or unreachable
|
||||||
|
- Increase timeout with client configuration
|
||||||
|
- Check network connectivity
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- Review the source code in `src/` to understand how tests work
|
||||||
|
- Modify `security-tester.js` to add custom tests
|
||||||
|
- Extend `mock-server.js` with more realistic behavior
|
||||||
|
- Integrate with your CI/CD pipeline for automated testing
|
||||||
16
examples/create-note.json
Archivo normal
16
examples/create-note.json
Archivo normal
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"@context": "https://www.w3.org/ns/activitystreams",
|
||||||
|
"type": "Create",
|
||||||
|
"id": "https://example.com/activities/test-create-1",
|
||||||
|
"actor": "https://example.com/users/tester",
|
||||||
|
"object": {
|
||||||
|
"type": "Note",
|
||||||
|
"id": "https://example.com/notes/test-note-1",
|
||||||
|
"content": "This is a test note from the ActivityPub security PoC toolkit.",
|
||||||
|
"published": "2025-11-16T00:00:00Z",
|
||||||
|
"attributedTo": "https://example.com/users/tester",
|
||||||
|
"to": ["https://www.w3.org/ns/activitystreams#Public"]
|
||||||
|
},
|
||||||
|
"published": "2025-11-16T00:00:00Z",
|
||||||
|
"to": ["https://www.w3.org/ns/activitystreams#Public"]
|
||||||
|
}
|
||||||
8
examples/follow.json
Archivo normal
8
examples/follow.json
Archivo normal
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"@context": "https://www.w3.org/ns/activitystreams",
|
||||||
|
"type": "Follow",
|
||||||
|
"id": "https://example.com/activities/follow-1",
|
||||||
|
"actor": "https://example.com/users/tester",
|
||||||
|
"object": "https://target-instance.example/users/alice",
|
||||||
|
"published": "2025-11-16T00:00:00Z"
|
||||||
|
}
|
||||||
19
examples/ssrf-payload.json
Archivo normal
19
examples/ssrf-payload.json
Archivo normal
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"@context": "https://www.w3.org/ns/activitystreams",
|
||||||
|
"type": "Create",
|
||||||
|
"id": "https://example.com/activities/ssrf-test",
|
||||||
|
"actor": "https://example.com/users/tester",
|
||||||
|
"object": {
|
||||||
|
"type": "Note",
|
||||||
|
"id": "http://localhost:8080/admin",
|
||||||
|
"url": "http://127.0.0.1:6379",
|
||||||
|
"content": "SSRF test payload",
|
||||||
|
"image": {
|
||||||
|
"type": "Image",
|
||||||
|
"url": "http://169.254.169.254/latest/meta-data/"
|
||||||
|
},
|
||||||
|
"published": "2025-11-16T00:00:00Z",
|
||||||
|
"attributedTo": "https://example.com/users/tester"
|
||||||
|
},
|
||||||
|
"published": "2025-11-16T00:00:00Z"
|
||||||
|
}
|
||||||
16
examples/xss-payload.json
Archivo normal
16
examples/xss-payload.json
Archivo normal
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"@context": "https://www.w3.org/ns/activitystreams",
|
||||||
|
"type": "Create",
|
||||||
|
"id": "https://example.com/activities/xss-test",
|
||||||
|
"actor": "https://example.com/users/tester",
|
||||||
|
"object": {
|
||||||
|
"type": "Note",
|
||||||
|
"id": "https://example.com/notes/xss-test",
|
||||||
|
"content": "<script>alert('XSS Test')</script>",
|
||||||
|
"name": "<img src=x onerror=alert('XSS')>",
|
||||||
|
"summary": "javascript:alert('XSS')",
|
||||||
|
"published": "2025-11-16T00:00:00Z",
|
||||||
|
"attributedTo": "https://example.com/users/tester"
|
||||||
|
},
|
||||||
|
"published": "2025-11-16T00:00:00Z"
|
||||||
|
}
|
||||||
30
package.json
Archivo normal
30
package.json
Archivo normal
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "activitypub-security-poc",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Security testing toolkit for ActivityPub protocol",
|
||||||
|
"main": "src/index.js",
|
||||||
|
"type": "module",
|
||||||
|
"bin": {
|
||||||
|
"ap-security": "./src/cli.js"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "node src/cli.js",
|
||||||
|
"mock-server": "node src/mock-server.js",
|
||||||
|
"test": "node --test"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"activitypub",
|
||||||
|
"security",
|
||||||
|
"fediverse",
|
||||||
|
"testing"
|
||||||
|
],
|
||||||
|
"author": "",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"commander": "^11.1.0",
|
||||||
|
"node-fetch": "^3.3.2",
|
||||||
|
"chalk": "^5.3.0",
|
||||||
|
"jsonld": "^8.3.2",
|
||||||
|
"http-signature": "^1.4.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
191
src/activitypub-client.js
Archivo normal
191
src/activitypub-client.js
Archivo normal
@@ -0,0 +1,191 @@
|
|||||||
|
/**
|
||||||
|
* ActivityPub Client Library
|
||||||
|
* Handles HTTP signatures, JSON-LD, and ActivityPub protocol interactions
|
||||||
|
*/
|
||||||
|
|
||||||
|
import crypto from 'crypto';
|
||||||
|
import fetch from 'node-fetch';
|
||||||
|
|
||||||
|
export class ActivityPubClient {
|
||||||
|
constructor(options = {}) {
|
||||||
|
this.userAgent = options.userAgent || 'ActivityPub-Security-PoC/1.0';
|
||||||
|
this.timeout = options.timeout || 10000;
|
||||||
|
this.privateKey = options.privateKey || null;
|
||||||
|
this.publicKey = options.publicKey || null;
|
||||||
|
this.actorId = options.actorId || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an activity to an inbox
|
||||||
|
*/
|
||||||
|
async sendToInbox(inboxUrl, activity, options = {}) {
|
||||||
|
const headers = {
|
||||||
|
'Content-Type': 'application/activity+json',
|
||||||
|
'User-Agent': this.userAgent,
|
||||||
|
...options.headers
|
||||||
|
};
|
||||||
|
|
||||||
|
// Sign the request if we have a private key
|
||||||
|
if (this.privateKey && this.actorId) {
|
||||||
|
const signature = this.signRequest('POST', inboxUrl, activity);
|
||||||
|
headers['Signature'] = signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(inboxUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
headers,
|
||||||
|
body: JSON.stringify(activity),
|
||||||
|
timeout: this.timeout
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: response.status,
|
||||||
|
statusText: response.statusText,
|
||||||
|
headers: Object.fromEntries(response.headers.entries()),
|
||||||
|
body: await this.safeParseResponse(response)
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
error: error.message,
|
||||||
|
type: error.type || 'NetworkError'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch from an outbox
|
||||||
|
*/
|
||||||
|
async fetchOutbox(outboxUrl, options = {}) {
|
||||||
|
const headers = {
|
||||||
|
'Accept': 'application/activity+json',
|
||||||
|
'User-Agent': this.userAgent,
|
||||||
|
...options.headers
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(outboxUrl, {
|
||||||
|
method: 'GET',
|
||||||
|
headers,
|
||||||
|
timeout: this.timeout
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: response.status,
|
||||||
|
statusText: response.statusText,
|
||||||
|
headers: Object.fromEntries(response.headers.entries()),
|
||||||
|
body: await this.safeParseResponse(response)
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
error: error.message,
|
||||||
|
type: error.type || 'NetworkError'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch an actor profile
|
||||||
|
*/
|
||||||
|
async fetchActor(actorUrl, options = {}) {
|
||||||
|
const headers = {
|
||||||
|
'Accept': 'application/activity+json',
|
||||||
|
'User-Agent': this.userAgent,
|
||||||
|
...options.headers
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(actorUrl, {
|
||||||
|
method: 'GET',
|
||||||
|
headers,
|
||||||
|
timeout: this.timeout
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: response.status,
|
||||||
|
statusText: response.statusText,
|
||||||
|
headers: Object.fromEntries(response.headers.entries()),
|
||||||
|
body: await this.safeParseResponse(response)
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
error: error.message,
|
||||||
|
type: error.type || 'NetworkError'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sign a request using HTTP Signatures
|
||||||
|
*/
|
||||||
|
signRequest(method, url, body) {
|
||||||
|
if (!this.privateKey) {
|
||||||
|
throw new Error('Private key required for signing');
|
||||||
|
}
|
||||||
|
|
||||||
|
const urlObj = new URL(url);
|
||||||
|
const date = new Date().toUTCString();
|
||||||
|
const digest = this.createDigest(JSON.stringify(body));
|
||||||
|
|
||||||
|
const signatureString = `(request-target): ${method.toLowerCase()} ${urlObj.pathname}\nhost: ${urlObj.host}\ndate: ${date}\ndigest: ${digest}`;
|
||||||
|
|
||||||
|
const signer = crypto.createSign('sha256');
|
||||||
|
signer.update(signatureString);
|
||||||
|
signer.end();
|
||||||
|
|
||||||
|
const signature = signer.sign(this.privateKey, 'base64');
|
||||||
|
|
||||||
|
return `keyId="${this.actorId}#main-key",headers="(request-target) host date digest",signature="${signature}"`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create SHA-256 digest
|
||||||
|
*/
|
||||||
|
createDigest(body) {
|
||||||
|
const hash = crypto.createHash('sha256').update(body).digest('base64');
|
||||||
|
return `SHA-256=${hash}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Safely parse response
|
||||||
|
*/
|
||||||
|
async safeParseResponse(response) {
|
||||||
|
const text = await response.text();
|
||||||
|
try {
|
||||||
|
return JSON.parse(text);
|
||||||
|
} catch (e) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a basic ActivityPub activity
|
||||||
|
*/
|
||||||
|
createActivity(type, object, additionalProps = {}) {
|
||||||
|
return {
|
||||||
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||||
|
type,
|
||||||
|
id: `https://example.com/activities/${crypto.randomUUID()}`,
|
||||||
|
actor: this.actorId || 'https://example.com/users/tester',
|
||||||
|
object,
|
||||||
|
published: new Date().toISOString(),
|
||||||
|
...additionalProps
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Note object
|
||||||
|
*/
|
||||||
|
createNote(content, additionalProps = {}) {
|
||||||
|
return {
|
||||||
|
type: 'Note',
|
||||||
|
id: `https://example.com/notes/${crypto.randomUUID()}`,
|
||||||
|
content,
|
||||||
|
published: new Date().toISOString(),
|
||||||
|
attributedTo: this.actorId || 'https://example.com/users/tester',
|
||||||
|
...additionalProps
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ActivityPubClient;
|
||||||
242
src/cli.js
Archivo normal
242
src/cli.js
Archivo normal
@@ -0,0 +1,242 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ActivityPub Security PoC CLI
|
||||||
|
* Command-line interface for testing ActivityPub implementations
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Command } from 'commander';
|
||||||
|
import chalk from 'chalk';
|
||||||
|
import { readFileSync } from 'fs';
|
||||||
|
import { ActivityPubClient } from './activitypub-client.js';
|
||||||
|
import { SecurityTester } from './security-tester.js';
|
||||||
|
|
||||||
|
const program = new Command();
|
||||||
|
|
||||||
|
program
|
||||||
|
.name('ap-security')
|
||||||
|
.description('ActivityPub Security Testing Toolkit')
|
||||||
|
.version('1.0.0');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test inbox endpoint
|
||||||
|
*/
|
||||||
|
program
|
||||||
|
.command('test-inbox')
|
||||||
|
.description('Send a test activity to an inbox endpoint')
|
||||||
|
.requiredOption('-t, --target <url>', 'Target inbox URL')
|
||||||
|
.option('-p, --payload <file>', 'JSON file containing the activity payload')
|
||||||
|
.option('-c, --content <text>', 'Text content for a simple Note')
|
||||||
|
.option('--actor <url>', 'Actor ID for the activity')
|
||||||
|
.option('--type <type>', 'Activity type (default: Create)', 'Create')
|
||||||
|
.action(async (options) => {
|
||||||
|
console.log(chalk.blue('\n🔵 Testing inbox endpoint...\n'));
|
||||||
|
|
||||||
|
const client = new ActivityPubClient({
|
||||||
|
actorId: options.actor
|
||||||
|
});
|
||||||
|
|
||||||
|
let activity;
|
||||||
|
|
||||||
|
if (options.payload) {
|
||||||
|
try {
|
||||||
|
const payloadData = readFileSync(options.payload, 'utf8');
|
||||||
|
activity = JSON.parse(payloadData);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(chalk.red(`Error reading payload: ${error.message}`));
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const content = options.content || 'Test message from ActivityPub Security PoC';
|
||||||
|
const note = client.createNote(content);
|
||||||
|
activity = client.createActivity(options.type, note);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(chalk.gray('Activity to send:'));
|
||||||
|
console.log(JSON.stringify(activity, null, 2));
|
||||||
|
console.log();
|
||||||
|
|
||||||
|
const result = await client.sendToInbox(options.target, activity);
|
||||||
|
|
||||||
|
if (result.error) {
|
||||||
|
console.error(chalk.red(`❌ Error: ${result.error}`));
|
||||||
|
console.error(chalk.red(`Type: ${result.type}`));
|
||||||
|
} else {
|
||||||
|
console.log(chalk.green(`✅ Response: ${result.status} ${result.statusText}`));
|
||||||
|
console.log(chalk.gray('\nHeaders:'));
|
||||||
|
console.log(result.headers);
|
||||||
|
console.log(chalk.gray('\nBody:'));
|
||||||
|
console.log(JSON.stringify(result.body, null, 2));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test outbox endpoint
|
||||||
|
*/
|
||||||
|
program
|
||||||
|
.command('test-outbox')
|
||||||
|
.description('Fetch activities from an outbox endpoint')
|
||||||
|
.requiredOption('-t, --target <url>', 'Target outbox URL')
|
||||||
|
.option('--page <number>', 'Page number to fetch', '1')
|
||||||
|
.action(async (options) => {
|
||||||
|
console.log(chalk.blue('\n🔵 Fetching outbox...\n'));
|
||||||
|
|
||||||
|
const client = new ActivityPubClient();
|
||||||
|
const result = await client.fetchOutbox(options.target);
|
||||||
|
|
||||||
|
if (result.error) {
|
||||||
|
console.error(chalk.red(`❌ Error: ${result.error}`));
|
||||||
|
} else {
|
||||||
|
console.log(chalk.green(`✅ Response: ${result.status} ${result.statusText}`));
|
||||||
|
console.log(chalk.gray('\nOutbox data:'));
|
||||||
|
console.log(JSON.stringify(result.body, null, 2));
|
||||||
|
|
||||||
|
if (result.body && result.body.orderedItems) {
|
||||||
|
console.log(chalk.blue(`\n📊 Total items: ${result.body.orderedItems.length}`));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch actor profile
|
||||||
|
*/
|
||||||
|
program
|
||||||
|
.command('fetch-actor')
|
||||||
|
.description('Fetch an ActivityPub actor profile')
|
||||||
|
.requiredOption('-t, --target <url>', 'Actor URL')
|
||||||
|
.action(async (options) => {
|
||||||
|
console.log(chalk.blue('\n🔵 Fetching actor profile...\n'));
|
||||||
|
|
||||||
|
const client = new ActivityPubClient();
|
||||||
|
const result = await client.fetchActor(options.target);
|
||||||
|
|
||||||
|
if (result.error) {
|
||||||
|
console.error(chalk.red(`❌ Error: ${result.error}`));
|
||||||
|
} else {
|
||||||
|
console.log(chalk.green(`✅ Response: ${result.status} ${result.statusText}`));
|
||||||
|
console.log(chalk.gray('\nActor data:'));
|
||||||
|
console.log(JSON.stringify(result.body, null, 2));
|
||||||
|
|
||||||
|
if (result.body) {
|
||||||
|
console.log(chalk.blue('\n📋 Actor Summary:'));
|
||||||
|
console.log(` Name: ${result.body.name || 'N/A'}`);
|
||||||
|
console.log(` Type: ${result.body.type || 'N/A'}`);
|
||||||
|
console.log(` Inbox: ${result.body.inbox || 'N/A'}`);
|
||||||
|
console.log(` Outbox: ${result.body.outbox || 'N/A'}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run security scan
|
||||||
|
*/
|
||||||
|
program
|
||||||
|
.command('security-scan')
|
||||||
|
.description('Run security tests on an ActivityPub endpoint')
|
||||||
|
.requiredOption('-t, --target <url>', 'Target inbox URL')
|
||||||
|
.option('--tests <types>', 'Comma-separated test types (xss,ssrf,injection,signature,authorization)', 'all')
|
||||||
|
.option('--actor <url>', 'Actor URL (for authorization tests)')
|
||||||
|
.option('-o, --output <file>', 'Save results to JSON file')
|
||||||
|
.action(async (options) => {
|
||||||
|
console.log(chalk.blue('\n🛡️ Starting security scan...\n'));
|
||||||
|
|
||||||
|
const client = new ActivityPubClient();
|
||||||
|
const tester = new SecurityTester(client);
|
||||||
|
|
||||||
|
const testOptions = {
|
||||||
|
actorUrl: options.actor
|
||||||
|
};
|
||||||
|
|
||||||
|
if (options.tests !== 'all') {
|
||||||
|
testOptions.tests = options.tests.split(',').map(t => t.trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
const results = await tester.runAllTests(options.target, testOptions);
|
||||||
|
const summary = tester.generateReport(results);
|
||||||
|
|
||||||
|
if (options.output) {
|
||||||
|
const fs = await import('fs');
|
||||||
|
fs.writeFileSync(options.output, JSON.stringify(results, null, 2));
|
||||||
|
console.log(chalk.green(`\n💾 Results saved to: ${options.output}`));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit with error code if vulnerabilities found
|
||||||
|
if (summary.vulnerableTests > 0) {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Craft custom activity
|
||||||
|
*/
|
||||||
|
program
|
||||||
|
.command('craft')
|
||||||
|
.description('Craft a custom ActivityPub activity')
|
||||||
|
.option('--type <type>', 'Activity type (Create, Update, Delete, Follow, etc.)', 'Create')
|
||||||
|
.option('--object <objectType>', 'Object type (Note, Article, etc.)', 'Note')
|
||||||
|
.option('--content <text>', 'Content text')
|
||||||
|
.option('--actor <url>', 'Actor ID')
|
||||||
|
.option('--to <url>', 'To field (recipient)')
|
||||||
|
.option('--cc <url>', 'CC field')
|
||||||
|
.option('-o, --output <file>', 'Save to file instead of stdout')
|
||||||
|
.action(async (options) => {
|
||||||
|
const client = new ActivityPubClient({
|
||||||
|
actorId: options.actor || 'https://example.com/users/tester'
|
||||||
|
});
|
||||||
|
|
||||||
|
let object;
|
||||||
|
if (options.object === 'Note') {
|
||||||
|
object = client.createNote(options.content || 'Sample content');
|
||||||
|
} else {
|
||||||
|
object = {
|
||||||
|
type: options.object,
|
||||||
|
id: `https://example.com/objects/${crypto.randomUUID()}`,
|
||||||
|
content: options.content || 'Sample content'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const additionalProps = {};
|
||||||
|
if (options.to) additionalProps.to = options.to;
|
||||||
|
if (options.cc) additionalProps.cc = options.cc;
|
||||||
|
|
||||||
|
const activity = client.createActivity(options.type, object, additionalProps);
|
||||||
|
|
||||||
|
const output = JSON.stringify(activity, null, 2);
|
||||||
|
|
||||||
|
if (options.output) {
|
||||||
|
const fs = await import('fs');
|
||||||
|
fs.writeFileSync(options.output, output);
|
||||||
|
console.log(chalk.green(`✅ Activity saved to: ${options.output}`));
|
||||||
|
} else {
|
||||||
|
console.log(output);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start mock server
|
||||||
|
*/
|
||||||
|
program
|
||||||
|
.command('mock-server')
|
||||||
|
.description('Start a mock ActivityPub server for testing')
|
||||||
|
.option('-p, --port <port>', 'Port to listen on', '3000')
|
||||||
|
.option('--host <host>', 'Host to bind to', 'localhost')
|
||||||
|
.action(async (options) => {
|
||||||
|
console.log(chalk.blue(`\n🚀 Starting mock server on ${options.host}:${options.port}...\n`));
|
||||||
|
|
||||||
|
// Dynamic import of mock server
|
||||||
|
const { startMockServer } = await import('./mock-server.js');
|
||||||
|
await startMockServer(options.port, options.host);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interactive mode
|
||||||
|
*/
|
||||||
|
program
|
||||||
|
.command('interactive')
|
||||||
|
.description('Start interactive testing mode')
|
||||||
|
.action(async () => {
|
||||||
|
console.log(chalk.blue('\n🎯 Interactive mode - Coming soon!\n'));
|
||||||
|
console.log('This will provide an interactive prompt for testing ActivityPub endpoints.');
|
||||||
|
});
|
||||||
|
|
||||||
|
program.parse();
|
||||||
542
src/mock-server.js
Archivo normal
542
src/mock-server.js
Archivo normal
@@ -0,0 +1,542 @@
|
|||||||
|
/**
|
||||||
|
* Mock ActivityPub Server
|
||||||
|
* Simulates an ActivityPub server for testing purposes
|
||||||
|
*/
|
||||||
|
|
||||||
|
import http from 'http';
|
||||||
|
import { URL } from 'url';
|
||||||
|
import crypto from 'crypto';
|
||||||
|
import chalk from 'chalk';
|
||||||
|
|
||||||
|
class MockActivityPubServer {
|
||||||
|
constructor(options = {}) {
|
||||||
|
this.host = options.host || 'localhost';
|
||||||
|
this.port = options.port || 3000;
|
||||||
|
this.baseUrl = `http://${this.host}:${this.port}`;
|
||||||
|
this.activities = [];
|
||||||
|
this.users = this.createMockUsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create mock user database
|
||||||
|
*/
|
||||||
|
createMockUsers() {
|
||||||
|
return {
|
||||||
|
alice: {
|
||||||
|
'@context': [
|
||||||
|
'https://www.w3.org/ns/activitystreams',
|
||||||
|
'https://w3id.org/security/v1'
|
||||||
|
],
|
||||||
|
id: `${this.baseUrl}/users/alice`,
|
||||||
|
type: 'Person',
|
||||||
|
preferredUsername: 'alice',
|
||||||
|
name: 'Alice Test',
|
||||||
|
summary: 'Mock ActivityPub user for testing',
|
||||||
|
inbox: `${this.baseUrl}/users/alice/inbox`,
|
||||||
|
outbox: `${this.baseUrl}/users/alice/outbox`,
|
||||||
|
followers: `${this.baseUrl}/users/alice/followers`,
|
||||||
|
following: `${this.baseUrl}/users/alice/following`,
|
||||||
|
publicKey: {
|
||||||
|
id: `${this.baseUrl}/users/alice#main-key`,
|
||||||
|
owner: `${this.baseUrl}/users/alice`,
|
||||||
|
publicKeyPem: '-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...\n-----END PUBLIC KEY-----'
|
||||||
|
},
|
||||||
|
endpoints: {
|
||||||
|
sharedInbox: `${this.baseUrl}/inbox`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
bob: {
|
||||||
|
'@context': [
|
||||||
|
'https://www.w3.org/ns/activitystreams',
|
||||||
|
'https://w3id.org/security/v1'
|
||||||
|
],
|
||||||
|
id: `${this.baseUrl}/users/bob`,
|
||||||
|
type: 'Person',
|
||||||
|
preferredUsername: 'bob',
|
||||||
|
name: 'Bob Test',
|
||||||
|
summary: 'Another mock ActivityPub user',
|
||||||
|
inbox: `${this.baseUrl}/users/bob/inbox`,
|
||||||
|
outbox: `${this.baseUrl}/users/bob/outbox`,
|
||||||
|
followers: `${this.baseUrl}/users/bob/followers`,
|
||||||
|
following: `${this.baseUrl}/users/bob/following`,
|
||||||
|
publicKey: {
|
||||||
|
id: `${this.baseUrl}/users/bob#main-key`,
|
||||||
|
owner: `${this.baseUrl}/users/bob`,
|
||||||
|
publicKeyPem: '-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...\n-----END PUBLIC KEY-----'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle incoming HTTP requests
|
||||||
|
*/
|
||||||
|
async handleRequest(req, res) {
|
||||||
|
const url = new URL(req.url, this.baseUrl);
|
||||||
|
const path = url.pathname;
|
||||||
|
|
||||||
|
console.log(chalk.gray(`${req.method} ${path}`));
|
||||||
|
|
||||||
|
// Set CORS headers
|
||||||
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||||
|
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
||||||
|
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Accept, Signature');
|
||||||
|
|
||||||
|
if (req.method === 'OPTIONS') {
|
||||||
|
res.writeHead(200);
|
||||||
|
res.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Route handling
|
||||||
|
if (path === '/.well-known/webfinger') {
|
||||||
|
await this.handleWebFinger(req, res, url);
|
||||||
|
} else if (path.match(/^\/users\/(\w+)$/)) {
|
||||||
|
await this.handleActor(req, res, path);
|
||||||
|
} else if (path.match(/^\/users\/(\w+)\/inbox$/)) {
|
||||||
|
await this.handleInbox(req, res, path);
|
||||||
|
} else if (path.match(/^\/users\/(\w+)\/outbox$/)) {
|
||||||
|
await this.handleOutbox(req, res, path);
|
||||||
|
} else if (path.match(/^\/users\/(\w+)\/followers$/)) {
|
||||||
|
await this.handleFollowers(req, res, path);
|
||||||
|
} else if (path.match(/^\/users\/(\w+)\/following$/)) {
|
||||||
|
await this.handleFollowing(req, res, path);
|
||||||
|
} else if (path === '/inbox') {
|
||||||
|
await this.handleSharedInbox(req, res);
|
||||||
|
} else if (path === '/') {
|
||||||
|
await this.handleRoot(req, res);
|
||||||
|
} else {
|
||||||
|
this.sendNotFound(res);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(chalk.red(`Error: ${error.message}`));
|
||||||
|
this.sendError(res, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle WebFinger requests
|
||||||
|
*/
|
||||||
|
async handleWebFinger(req, res, url) {
|
||||||
|
const resource = url.searchParams.get('resource');
|
||||||
|
|
||||||
|
if (!resource) {
|
||||||
|
this.sendError(res, new Error('Missing resource parameter'), 400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract username from resource (e.g., acct:alice@localhost:3000)
|
||||||
|
const match = resource.match(/acct:(\w+)@/);
|
||||||
|
if (!match) {
|
||||||
|
this.sendNotFound(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const username = match[1];
|
||||||
|
if (!this.users[username]) {
|
||||||
|
this.sendNotFound(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const webfinger = {
|
||||||
|
subject: resource,
|
||||||
|
links: [
|
||||||
|
{
|
||||||
|
rel: 'self',
|
||||||
|
type: 'application/activity+json',
|
||||||
|
href: `${this.baseUrl}/users/${username}`
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
this.sendJSON(res, webfinger, 200, 'application/jrd+json');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle actor profile requests
|
||||||
|
*/
|
||||||
|
async handleActor(req, res, path) {
|
||||||
|
const username = path.split('/')[2];
|
||||||
|
const user = this.users[username];
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
this.sendNotFound(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sendJSON(res, user, 200, 'application/activity+json');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle inbox POST requests
|
||||||
|
*/
|
||||||
|
async handleInbox(req, res, path) {
|
||||||
|
const username = path.split('/')[2];
|
||||||
|
|
||||||
|
if (!this.users[username]) {
|
||||||
|
this.sendNotFound(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.method === 'GET') {
|
||||||
|
// Return inbox collection
|
||||||
|
const inbox = {
|
||||||
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||||
|
id: `${this.baseUrl}/users/${username}/inbox`,
|
||||||
|
type: 'OrderedCollection',
|
||||||
|
totalItems: this.activities.filter(a => a.to === username).length,
|
||||||
|
orderedItems: this.activities.filter(a => a.to === username)
|
||||||
|
};
|
||||||
|
this.sendJSON(res, inbox, 200, 'application/activity+json');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.method === 'POST') {
|
||||||
|
const body = await this.readBody(req);
|
||||||
|
let activity;
|
||||||
|
|
||||||
|
try {
|
||||||
|
activity = JSON.parse(body);
|
||||||
|
} catch (error) {
|
||||||
|
this.sendError(res, new Error('Invalid JSON'), 400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(chalk.green(`\n📥 Received activity for ${username}:`));
|
||||||
|
console.log(JSON.stringify(activity, null, 2));
|
||||||
|
|
||||||
|
// Validate activity
|
||||||
|
const validation = this.validateActivity(activity);
|
||||||
|
if (!validation.valid) {
|
||||||
|
console.log(chalk.yellow(`⚠️ Validation warning: ${validation.message}`));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Security checks
|
||||||
|
const securityIssues = this.performSecurityChecks(activity);
|
||||||
|
if (securityIssues.length > 0) {
|
||||||
|
console.log(chalk.red(`\n🚨 Security issues detected:`));
|
||||||
|
securityIssues.forEach(issue => {
|
||||||
|
console.log(chalk.red(` - ${issue}`));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store activity
|
||||||
|
this.activities.push({
|
||||||
|
...activity,
|
||||||
|
to: username,
|
||||||
|
receivedAt: new Date().toISOString()
|
||||||
|
});
|
||||||
|
|
||||||
|
res.writeHead(202);
|
||||||
|
res.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sendError(res, new Error('Method not allowed'), 405);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle outbox requests
|
||||||
|
*/
|
||||||
|
async handleOutbox(req, res, path) {
|
||||||
|
const username = path.split('/')[2];
|
||||||
|
|
||||||
|
if (!this.users[username]) {
|
||||||
|
this.sendNotFound(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const outbox = {
|
||||||
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||||
|
id: `${this.baseUrl}/users/${username}/outbox`,
|
||||||
|
type: 'OrderedCollection',
|
||||||
|
totalItems: 2,
|
||||||
|
orderedItems: [
|
||||||
|
{
|
||||||
|
id: `${this.baseUrl}/users/${username}/statuses/1`,
|
||||||
|
type: 'Create',
|
||||||
|
actor: `${this.baseUrl}/users/${username}`,
|
||||||
|
published: new Date().toISOString(),
|
||||||
|
to: ['https://www.w3.org/ns/activitystreams#Public'],
|
||||||
|
object: {
|
||||||
|
id: `${this.baseUrl}/users/${username}/statuses/1`,
|
||||||
|
type: 'Note',
|
||||||
|
content: 'Hello from the mock server!',
|
||||||
|
attributedTo: `${this.baseUrl}/users/${username}`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: `${this.baseUrl}/users/${username}/statuses/2`,
|
||||||
|
type: 'Create',
|
||||||
|
actor: `${this.baseUrl}/users/${username}`,
|
||||||
|
published: new Date().toISOString(),
|
||||||
|
to: ['https://www.w3.org/ns/activitystreams#Public'],
|
||||||
|
object: {
|
||||||
|
id: `${this.baseUrl}/users/${username}/statuses/2`,
|
||||||
|
type: 'Note',
|
||||||
|
content: 'This is a test message for ActivityPub security testing.',
|
||||||
|
attributedTo: `${this.baseUrl}/users/${username}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
this.sendJSON(res, outbox, 200, 'application/activity+json');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle followers collection
|
||||||
|
*/
|
||||||
|
async handleFollowers(req, res, path) {
|
||||||
|
const username = path.split('/')[2];
|
||||||
|
|
||||||
|
if (!this.users[username]) {
|
||||||
|
this.sendNotFound(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const followers = {
|
||||||
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||||
|
id: `${this.baseUrl}/users/${username}/followers`,
|
||||||
|
type: 'OrderedCollection',
|
||||||
|
totalItems: 0,
|
||||||
|
orderedItems: []
|
||||||
|
};
|
||||||
|
|
||||||
|
this.sendJSON(res, followers, 200, 'application/activity+json');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle following collection
|
||||||
|
*/
|
||||||
|
async handleFollowing(req, res, path) {
|
||||||
|
const username = path.split('/')[2];
|
||||||
|
|
||||||
|
if (!this.users[username]) {
|
||||||
|
this.sendNotFound(res);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const following = {
|
||||||
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||||
|
id: `${this.baseUrl}/users/${username}/following`,
|
||||||
|
type: 'OrderedCollection',
|
||||||
|
totalItems: 0,
|
||||||
|
orderedItems: []
|
||||||
|
};
|
||||||
|
|
||||||
|
this.sendJSON(res, following, 200, 'application/activity+json');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle shared inbox
|
||||||
|
*/
|
||||||
|
async handleSharedInbox(req, res) {
|
||||||
|
if (req.method === 'POST') {
|
||||||
|
const body = await this.readBody(req);
|
||||||
|
const activity = JSON.parse(body);
|
||||||
|
|
||||||
|
console.log(chalk.green('\n📥 Received activity at shared inbox:'));
|
||||||
|
console.log(JSON.stringify(activity, null, 2));
|
||||||
|
|
||||||
|
this.activities.push(activity);
|
||||||
|
|
||||||
|
res.writeHead(202);
|
||||||
|
res.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sendError(res, new Error('Method not allowed'), 405);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle root path
|
||||||
|
*/
|
||||||
|
async handleRoot(req, res) {
|
||||||
|
const info = {
|
||||||
|
name: 'Mock ActivityPub Server',
|
||||||
|
version: '1.0.0',
|
||||||
|
users: Object.keys(this.users).map(username => ({
|
||||||
|
username,
|
||||||
|
actor: `${this.baseUrl}/users/${username}`,
|
||||||
|
inbox: `${this.baseUrl}/users/${username}/inbox`,
|
||||||
|
outbox: `${this.baseUrl}/users/${username}/outbox`
|
||||||
|
})),
|
||||||
|
endpoints: {
|
||||||
|
sharedInbox: `${this.baseUrl}/inbox`,
|
||||||
|
webfinger: `${this.baseUrl}/.well-known/webfinger`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||||
|
res.end(JSON.stringify(info, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate ActivityPub activity
|
||||||
|
*/
|
||||||
|
validateActivity(activity) {
|
||||||
|
if (!activity.type) {
|
||||||
|
return { valid: false, message: 'Missing type field' };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!activity['@context']) {
|
||||||
|
return { valid: false, message: 'Missing @context' };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!activity.actor) {
|
||||||
|
return { valid: false, message: 'Missing actor field' };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { valid: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform security checks on activity
|
||||||
|
*/
|
||||||
|
performSecurityChecks(activity) {
|
||||||
|
const issues = [];
|
||||||
|
|
||||||
|
// Check for XSS patterns
|
||||||
|
const xssPatterns = [/<script/i, /javascript:/i, /onerror=/i, /onload=/i];
|
||||||
|
const checkForXSS = (obj) => {
|
||||||
|
for (const value of Object.values(obj)) {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
for (const pattern of xssPatterns) {
|
||||||
|
if (pattern.test(value)) {
|
||||||
|
issues.push(`Potential XSS detected: ${value.substring(0, 50)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (typeof value === 'object' && value !== null) {
|
||||||
|
checkForXSS(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
checkForXSS(activity);
|
||||||
|
|
||||||
|
// Check for SSRF attempts
|
||||||
|
const ssrfPatterns = [
|
||||||
|
/localhost/i,
|
||||||
|
/127\.0\.0\.1/,
|
||||||
|
/169\.254\./,
|
||||||
|
/file:\/\//i,
|
||||||
|
/0\.0\.0\.0/
|
||||||
|
];
|
||||||
|
|
||||||
|
const checkForSSRF = (obj) => {
|
||||||
|
for (const value of Object.values(obj)) {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
for (const pattern of ssrfPatterns) {
|
||||||
|
if (pattern.test(value)) {
|
||||||
|
issues.push(`Potential SSRF detected: ${value}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (typeof value === 'object' && value !== null) {
|
||||||
|
checkForSSRF(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
checkForSSRF(activity);
|
||||||
|
|
||||||
|
// Check for prototype pollution
|
||||||
|
if (activity['__proto__'] || activity.constructor?.prototype) {
|
||||||
|
issues.push('Prototype pollution attempt detected');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for SQL injection patterns
|
||||||
|
const sqlPatterns = [/'; DROP/i, /UNION SELECT/i, /' OR '1'='1/i];
|
||||||
|
const checkContent = JSON.stringify(activity);
|
||||||
|
for (const pattern of sqlPatterns) {
|
||||||
|
if (pattern.test(checkContent)) {
|
||||||
|
issues.push('Potential SQL injection pattern detected');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return issues;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read request body
|
||||||
|
*/
|
||||||
|
readBody(req) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let body = '';
|
||||||
|
req.on('data', chunk => {
|
||||||
|
body += chunk.toString();
|
||||||
|
});
|
||||||
|
req.on('end', () => {
|
||||||
|
resolve(body);
|
||||||
|
});
|
||||||
|
req.on('error', reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send JSON response
|
||||||
|
*/
|
||||||
|
sendJSON(res, data, status = 200, contentType = 'application/activity+json') {
|
||||||
|
res.writeHead(status, {
|
||||||
|
'Content-Type': contentType,
|
||||||
|
'Access-Control-Allow-Origin': '*'
|
||||||
|
});
|
||||||
|
res.end(JSON.stringify(data, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send error response
|
||||||
|
*/
|
||||||
|
sendError(res, error, status = 500) {
|
||||||
|
res.writeHead(status, { 'Content-Type': 'application/json' });
|
||||||
|
res.end(JSON.stringify({ error: error.message }));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send 404 response
|
||||||
|
*/
|
||||||
|
sendNotFound(res) {
|
||||||
|
this.sendError(res, new Error('Not found'), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the server
|
||||||
|
*/
|
||||||
|
start() {
|
||||||
|
const server = http.createServer((req, res) => this.handleRequest(req, res));
|
||||||
|
|
||||||
|
server.listen(this.port, this.host, () => {
|
||||||
|
console.log(chalk.green(`\n✅ Mock ActivityPub server running!`));
|
||||||
|
console.log(chalk.blue(`\n🌐 Base URL: ${this.baseUrl}`));
|
||||||
|
console.log(chalk.gray('\nAvailable users:'));
|
||||||
|
|
||||||
|
Object.keys(this.users).forEach(username => {
|
||||||
|
console.log(chalk.cyan(` - ${username}`));
|
||||||
|
console.log(chalk.gray(` Actor: ${this.baseUrl}/users/${username}`));
|
||||||
|
console.log(chalk.gray(` Inbox: ${this.baseUrl}/users/${username}/inbox`));
|
||||||
|
console.log(chalk.gray(` Outbox: ${this.baseUrl}/users/${username}/outbox`));
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(chalk.gray('\nEndpoints:'));
|
||||||
|
console.log(chalk.gray(` - WebFinger: ${this.baseUrl}/.well-known/webfinger?resource=acct:alice@${this.host}`));
|
||||||
|
console.log(chalk.gray(` - Shared Inbox: ${this.baseUrl}/inbox`));
|
||||||
|
console.log(chalk.blue('\n📡 Waiting for requests...\n'));
|
||||||
|
});
|
||||||
|
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the mock server
|
||||||
|
*/
|
||||||
|
export function startMockServer(port = 3000, host = 'localhost') {
|
||||||
|
const server = new MockActivityPubServer({ port, host });
|
||||||
|
return server.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// If run directly
|
||||||
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||||
|
startMockServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MockActivityPubServer;
|
||||||
370
src/security-tester.js
Archivo normal
370
src/security-tester.js
Archivo normal
@@ -0,0 +1,370 @@
|
|||||||
|
/**
|
||||||
|
* Security Testing Module
|
||||||
|
* Contains various security test scenarios for ActivityPub implementations
|
||||||
|
*/
|
||||||
|
|
||||||
|
import crypto from 'crypto';
|
||||||
|
|
||||||
|
export class SecurityTester {
|
||||||
|
constructor(client) {
|
||||||
|
this.client = client;
|
||||||
|
this.results = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run XSS tests on inbox endpoint
|
||||||
|
*/
|
||||||
|
async testXSS(inboxUrl) {
|
||||||
|
console.log('\n🔍 Testing XSS vulnerabilities...');
|
||||||
|
|
||||||
|
const xssPayloads = [
|
||||||
|
'<script>alert("XSS")</script>',
|
||||||
|
'<img src=x onerror=alert("XSS")>',
|
||||||
|
'javascript:alert("XSS")',
|
||||||
|
'<svg/onload=alert("XSS")>',
|
||||||
|
'"><script>alert(String.fromCharCode(88,83,83))</script>',
|
||||||
|
'<iframe src="javascript:alert(\'XSS\')">',
|
||||||
|
'<body onload=alert("XSS")>'
|
||||||
|
];
|
||||||
|
|
||||||
|
const results = [];
|
||||||
|
|
||||||
|
for (const payload of xssPayloads) {
|
||||||
|
const note = this.client.createNote(payload);
|
||||||
|
const activity = this.client.createActivity('Create', note);
|
||||||
|
|
||||||
|
const result = await this.client.sendToInbox(inboxUrl, activity);
|
||||||
|
|
||||||
|
results.push({
|
||||||
|
test: 'XSS',
|
||||||
|
payload: payload.substring(0, 50),
|
||||||
|
status: result.status,
|
||||||
|
vulnerable: result.status === 200 || result.status === 202,
|
||||||
|
response: result.statusText
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test SSRF vulnerabilities via malicious URLs
|
||||||
|
*/
|
||||||
|
async testSSRF(inboxUrl) {
|
||||||
|
console.log('\n🔍 Testing SSRF vulnerabilities...');
|
||||||
|
|
||||||
|
const ssrfTargets = [
|
||||||
|
'http://localhost:8080',
|
||||||
|
'http://127.0.0.1:6379',
|
||||||
|
'http://169.254.169.254/latest/meta-data/',
|
||||||
|
'http://[::1]:8080',
|
||||||
|
'file:///etc/passwd',
|
||||||
|
'http://0.0.0.0:3000'
|
||||||
|
];
|
||||||
|
|
||||||
|
const results = [];
|
||||||
|
|
||||||
|
for (const target of ssrfTargets) {
|
||||||
|
const maliciousObject = {
|
||||||
|
type: 'Note',
|
||||||
|
id: target,
|
||||||
|
url: target,
|
||||||
|
content: 'Test content',
|
||||||
|
image: {
|
||||||
|
type: 'Image',
|
||||||
|
url: target
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const activity = this.client.createActivity('Create', maliciousObject);
|
||||||
|
const result = await this.client.sendToInbox(inboxUrl, activity);
|
||||||
|
|
||||||
|
results.push({
|
||||||
|
test: 'SSRF',
|
||||||
|
target,
|
||||||
|
status: result.status,
|
||||||
|
vulnerable: result.status === 200 || result.status === 202,
|
||||||
|
response: result.statusText
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test object type confusion/injection
|
||||||
|
*/
|
||||||
|
async testObjectInjection(inboxUrl) {
|
||||||
|
console.log('\n🔍 Testing object injection vulnerabilities...');
|
||||||
|
|
||||||
|
const results = [];
|
||||||
|
|
||||||
|
// Test 1: Malformed type
|
||||||
|
const malformedType = this.client.createActivity('Create', {
|
||||||
|
type: ['Note', 'Delete'],
|
||||||
|
content: 'Type confusion test'
|
||||||
|
});
|
||||||
|
|
||||||
|
let result = await this.client.sendToInbox(inboxUrl, malformedType);
|
||||||
|
results.push({
|
||||||
|
test: 'Type Confusion',
|
||||||
|
payload: 'Multiple types',
|
||||||
|
status: result.status,
|
||||||
|
vulnerable: result.status === 200 || result.status === 202
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test 2: Missing required fields
|
||||||
|
const missingFields = this.client.createActivity('Create', {
|
||||||
|
type: 'Note'
|
||||||
|
// Missing content, attributedTo, etc.
|
||||||
|
});
|
||||||
|
|
||||||
|
result = await this.client.sendToInbox(inboxUrl, missingFields);
|
||||||
|
results.push({
|
||||||
|
test: 'Missing Fields',
|
||||||
|
payload: 'No required fields',
|
||||||
|
status: result.status,
|
||||||
|
vulnerable: result.status === 200 || result.status === 202
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test 3: Prototype pollution attempt
|
||||||
|
const prototypePollution = this.client.createActivity('Create', {
|
||||||
|
type: 'Note',
|
||||||
|
content: 'Test',
|
||||||
|
'__proto__': { isAdmin: true },
|
||||||
|
'constructor': { prototype: { isAdmin: true } }
|
||||||
|
});
|
||||||
|
|
||||||
|
result = await this.client.sendToInbox(inboxUrl, prototypePollution);
|
||||||
|
results.push({
|
||||||
|
test: 'Prototype Pollution',
|
||||||
|
payload: '__proto__ injection',
|
||||||
|
status: result.status,
|
||||||
|
vulnerable: result.status === 200 || result.status === 202
|
||||||
|
});
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test signature verification bypass
|
||||||
|
*/
|
||||||
|
async testSignatureBypass(inboxUrl) {
|
||||||
|
console.log('\n🔍 Testing signature bypass vulnerabilities...');
|
||||||
|
|
||||||
|
const results = [];
|
||||||
|
|
||||||
|
// Test 1: No signature
|
||||||
|
const note = this.client.createNote('Unsigned message test');
|
||||||
|
const activity = this.client.createActivity('Create', note);
|
||||||
|
|
||||||
|
let result = await this.client.sendToInbox(inboxUrl, activity);
|
||||||
|
results.push({
|
||||||
|
test: 'No Signature',
|
||||||
|
payload: 'Missing HTTP signature',
|
||||||
|
status: result.status,
|
||||||
|
vulnerable: result.status === 200 || result.status === 202,
|
||||||
|
notes: 'Server should reject unsigned requests'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test 2: Invalid signature
|
||||||
|
result = await this.client.sendToInbox(inboxUrl, activity, {
|
||||||
|
headers: {
|
||||||
|
'Signature': 'keyId="fake",signature="invalidsignature"'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
results.push({
|
||||||
|
test: 'Invalid Signature',
|
||||||
|
payload: 'Malformed signature',
|
||||||
|
status: result.status,
|
||||||
|
vulnerable: result.status === 200 || result.status === 202,
|
||||||
|
notes: 'Server should reject invalid signatures'
|
||||||
|
});
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test authorization and access control
|
||||||
|
*/
|
||||||
|
async testAuthorization(actorUrl, inboxUrl) {
|
||||||
|
console.log('\n🔍 Testing authorization vulnerabilities...');
|
||||||
|
|
||||||
|
const results = [];
|
||||||
|
|
||||||
|
// Test 1: Impersonation attempt
|
||||||
|
const impersonationNote = this.client.createNote('Impersonation test', {
|
||||||
|
attributedTo: actorUrl // Pretend to be someone else
|
||||||
|
});
|
||||||
|
const impersonationActivity = this.client.createActivity('Create', impersonationNote, {
|
||||||
|
actor: actorUrl // Wrong actor
|
||||||
|
});
|
||||||
|
|
||||||
|
let result = await this.client.sendToInbox(inboxUrl, impersonationActivity);
|
||||||
|
results.push({
|
||||||
|
test: 'Actor Impersonation',
|
||||||
|
payload: 'Mismatched actor',
|
||||||
|
status: result.status,
|
||||||
|
vulnerable: result.status === 200 || result.status === 202,
|
||||||
|
notes: 'Server should validate actor matches signature'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Test 2: Unauthorized Delete
|
||||||
|
const deleteActivity = {
|
||||||
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||||
|
type: 'Delete',
|
||||||
|
actor: 'https://attacker.example/users/evil',
|
||||||
|
object: actorUrl + '/statuses/1' // Try to delete someone else's post
|
||||||
|
};
|
||||||
|
|
||||||
|
result = await this.client.sendToInbox(inboxUrl, deleteActivity);
|
||||||
|
results.push({
|
||||||
|
test: 'Unauthorized Delete',
|
||||||
|
payload: 'Delete others content',
|
||||||
|
status: result.status,
|
||||||
|
vulnerable: result.status === 200 || result.status === 202,
|
||||||
|
notes: 'Server should verify ownership'
|
||||||
|
});
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for injection in various fields
|
||||||
|
*/
|
||||||
|
async testInjection(inboxUrl) {
|
||||||
|
console.log('\n🔍 Testing injection vulnerabilities...');
|
||||||
|
|
||||||
|
const results = [];
|
||||||
|
|
||||||
|
// SQL Injection patterns
|
||||||
|
const sqlPayloads = [
|
||||||
|
"'; DROP TABLE users--",
|
||||||
|
"' OR '1'='1",
|
||||||
|
"admin'--",
|
||||||
|
"' UNION SELECT NULL--"
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const payload of sqlPayloads) {
|
||||||
|
const note = this.client.createNote(payload, {
|
||||||
|
name: payload,
|
||||||
|
summary: payload
|
||||||
|
});
|
||||||
|
const activity = this.client.createActivity('Create', note);
|
||||||
|
|
||||||
|
const result = await this.client.sendToInbox(inboxUrl, activity);
|
||||||
|
results.push({
|
||||||
|
test: 'SQL Injection',
|
||||||
|
payload: payload.substring(0, 30),
|
||||||
|
status: result.status,
|
||||||
|
vulnerable: result.error && result.error.includes('SQL')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command Injection
|
||||||
|
const cmdPayloads = [
|
||||||
|
'; ls -la',
|
||||||
|
'| whoami',
|
||||||
|
'`id`',
|
||||||
|
'$(uname -a)'
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const payload of cmdPayloads) {
|
||||||
|
const note = this.client.createNote(payload);
|
||||||
|
const activity = this.client.createActivity('Create', note);
|
||||||
|
|
||||||
|
const result = await this.client.sendToInbox(inboxUrl, activity);
|
||||||
|
results.push({
|
||||||
|
test: 'Command Injection',
|
||||||
|
payload: payload,
|
||||||
|
status: result.status,
|
||||||
|
vulnerable: result.status === 200 || result.status === 202
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run all security tests
|
||||||
|
*/
|
||||||
|
async runAllTests(targetUrl, options = {}) {
|
||||||
|
console.log(`\n🛡️ Starting security tests on: ${targetUrl}\n`);
|
||||||
|
|
||||||
|
const allResults = {
|
||||||
|
target: targetUrl,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
tests: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!options.tests || options.tests.includes('xss')) {
|
||||||
|
allResults.tests.xss = await this.testXSS(targetUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.tests || options.tests.includes('ssrf')) {
|
||||||
|
allResults.tests.ssrf = await this.testSSRF(targetUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.tests || options.tests.includes('injection')) {
|
||||||
|
allResults.tests.objectInjection = await this.testObjectInjection(targetUrl);
|
||||||
|
allResults.tests.injection = await this.testInjection(targetUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.tests || options.tests.includes('signature')) {
|
||||||
|
allResults.tests.signature = await this.testSignatureBypass(targetUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.tests || options.tests.includes('authorization')) {
|
||||||
|
const actorUrl = options.actorUrl || targetUrl.replace('/inbox', '');
|
||||||
|
allResults.tests.authorization = await this.testAuthorization(actorUrl, targetUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
return allResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a report from test results
|
||||||
|
*/
|
||||||
|
generateReport(results) {
|
||||||
|
console.log('\n' + '='.repeat(60));
|
||||||
|
console.log('SECURITY TEST REPORT');
|
||||||
|
console.log('='.repeat(60));
|
||||||
|
console.log(`Target: ${results.target}`);
|
||||||
|
console.log(`Timestamp: ${results.timestamp}`);
|
||||||
|
console.log('='.repeat(60));
|
||||||
|
|
||||||
|
let totalTests = 0;
|
||||||
|
let vulnerableTests = 0;
|
||||||
|
|
||||||
|
for (const [category, tests] of Object.entries(results.tests)) {
|
||||||
|
console.log(`\n${category.toUpperCase()}:`);
|
||||||
|
console.log('-'.repeat(60));
|
||||||
|
|
||||||
|
for (const test of tests) {
|
||||||
|
totalTests++;
|
||||||
|
const status = test.vulnerable ? '❌ VULNERABLE' : '✅ SAFE';
|
||||||
|
console.log(`${status} - ${test.test}: ${test.payload || test.target || ''}`);
|
||||||
|
|
||||||
|
if (test.notes) {
|
||||||
|
console.log(` Note: ${test.notes}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (test.vulnerable) {
|
||||||
|
vulnerableTests++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n' + '='.repeat(60));
|
||||||
|
console.log(`SUMMARY: ${vulnerableTests}/${totalTests} potential vulnerabilities found`);
|
||||||
|
console.log('='.repeat(60) + '\n');
|
||||||
|
|
||||||
|
return {
|
||||||
|
totalTests,
|
||||||
|
vulnerableTests,
|
||||||
|
safeTests: totalTests - vulnerableTests
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SecurityTester;
|
||||||
94
test.sh
Archivo ejecutable
94
test.sh
Archivo ejecutable
@@ -0,0 +1,94 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Quick test script for ActivityPub Security PoC
|
||||||
|
# This script demonstrates the main features
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "================================================"
|
||||||
|
echo "ActivityPub Security PoC - Quick Test"
|
||||||
|
echo "================================================"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Check if node_modules exists
|
||||||
|
if [ ! -d "node_modules" ]; then
|
||||||
|
echo "📦 Installing dependencies..."
|
||||||
|
npm install
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "🚀 Starting mock server in background..."
|
||||||
|
node src/cli.js mock-server --port 3000 > /tmp/mock-server.log 2>&1 &
|
||||||
|
MOCK_PID=$!
|
||||||
|
echo " Mock server PID: $MOCK_PID"
|
||||||
|
|
||||||
|
# Wait for server to start
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "================================================"
|
||||||
|
echo "Test 1: Fetch Actor Profile"
|
||||||
|
echo "================================================"
|
||||||
|
node src/cli.js fetch-actor --target http://localhost:3000/users/alice
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "================================================"
|
||||||
|
echo "Test 2: Fetch Outbox"
|
||||||
|
echo "================================================"
|
||||||
|
node src/cli.js test-outbox --target http://localhost:3000/users/alice/outbox
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "================================================"
|
||||||
|
echo "Test 3: Send Simple Note to Inbox"
|
||||||
|
echo "================================================"
|
||||||
|
node src/cli.js test-inbox \
|
||||||
|
--target http://localhost:3000/users/alice/inbox \
|
||||||
|
--content "Hello from security PoC test!" \
|
||||||
|
--actor https://example.com/users/tester
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "================================================"
|
||||||
|
echo "Test 4: Send Predefined Payload"
|
||||||
|
echo "================================================"
|
||||||
|
node src/cli.js test-inbox \
|
||||||
|
--target http://localhost:3000/users/bob/inbox \
|
||||||
|
--payload examples/create-note.json
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "================================================"
|
||||||
|
echo "Test 5: Craft Custom Activity"
|
||||||
|
echo "================================================"
|
||||||
|
node src/cli.js craft \
|
||||||
|
--type Follow \
|
||||||
|
--actor https://example.com/users/tester \
|
||||||
|
--object http://localhost:3000/users/alice
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "================================================"
|
||||||
|
echo "Test 6: Security Scan (Limited)"
|
||||||
|
echo "================================================"
|
||||||
|
node src/cli.js security-scan \
|
||||||
|
--target http://localhost:3000/users/alice/inbox \
|
||||||
|
--tests xss,injection \
|
||||||
|
--actor http://localhost:3000/users/alice
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "================================================"
|
||||||
|
echo "Tests Complete!"
|
||||||
|
echo "================================================"
|
||||||
|
echo ""
|
||||||
|
echo "📊 Check mock server logs:"
|
||||||
|
echo " tail -f /tmp/mock-server.log"
|
||||||
|
echo ""
|
||||||
|
echo "🛑 Stopping mock server (PID: $MOCK_PID)..."
|
||||||
|
kill $MOCK_PID 2>/dev/null || true
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✅ All tests completed successfully!"
|
||||||
|
echo ""
|
||||||
|
echo "Next steps:"
|
||||||
|
echo " - Review the code in src/"
|
||||||
|
echo " - Read examples/USAGE.md for more examples"
|
||||||
|
echo " - Read docs/SECURITY_TESTING.md for testing methodology"
|
||||||
|
echo " - Start the mock server: npm run mock-server"
|
||||||
|
echo " - Run custom tests with: node src/cli.js --help"
|
||||||
Referencia en una nueva incidencia
Block a user