shirk
Shirk
Shirk is a Crystal shard that enables applications to be controlled via SSH. It allows users to send messages, files, and interact with UIs through standard SSH protocols.
Installation
Prerequisites
- Crystal 1.0.0 or higher
- libssh development libraries
Install libssh on different systems:
Ubuntu/Debian:
sudo apt-get install libssh-dev
Fedora/CentOS/RHEL:
sudo dnf install libssh-devel
# or on older systems
sudo yum install libssh-devel
Arch Linux:
sudo pacman -S libssh
macOS (with Homebrew):
brew install libssh
Add to your project
Add this to your application's shard.yml:
dependencies:
shirk:
github: your-username/shirk
Then run:
shards install
Usage
Basic SSH Server
Create a basic SSH server that can receive messages:
require "shirk"
# Create SSH server on port 2222
server = Shirk::SSH::Server.new(2222)
# Set up message handler
server.on_message do |message|
puts "Received: #{message}"
case message.strip
when "hello"
"Hello! SSH server is working."
when "time"
"Current time: #{Time.local}"
else
"Echo: #{message}"
end
end
# Handle Ctrl+C gracefully
Signal::INT.trap do
puts "\nShutting down..."
server.stop
exit
end
puts "Starting SSH server on port 2222..."
server.start
Custom Authentication
Shirk supports customizable authentication handlers. You can control which users and public keys are allowed to connect:
require "shirk"
# Create a public key whitelist auth handler
auth_handler = Shirk::SSH::PublicKeyWhitelistAuth.new
# Add allowed public keys for users
auth_handler.add_key("alice", "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC3 alice@example.com")
auth_handler.add_key("bob", "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGb bob@workstation")
# Load keys from authorized_keys file
auth_handler.load_authorized_keys("alice", "/home/alice/.ssh/authorized_keys")
# Create server with custom authentication
server = Shirk::SSH::Server.new(2222, "0.0.0.0", auth_handler)
# Or set auth handler after creation
server.auth_handler = auth_handler
server.on_message do |message|
"Hello authenticated user! You sent: #{message}"
end
server.start
Built-in Authentication Handlers
- AcceptAllAuth - Accepts all authentication requests (demo/testing only)
- RejectAllAuth - Rejects all authentication requests
- PublicKeyWhitelistAuth - Allows only users with whitelisted public keys
Custom Authentication Handler
class MyAuthHandler < Shirk::SSH::AuthHandler
def authenticate(request : Shirk::SSH::AuthRequest) : Shirk::SSH::AuthResult
# Your custom authentication logic here
if request.username == "admin" && request.pubkey?
Shirk::SSH::AuthResult::Success
else
Shirk::SSH::AuthResult::Failure
end
end
end
server = Shirk::SSH::Server.new(2222)
server.auth_handler = MyAuthHandler.new
Connection Management and Validation
Shirk provides comprehensive connection management features including connection validation, rate limiting, event callbacks, and connection metadata tracking.
require "shirk"
server = Shirk::SSH::Server.new(2222)
# Set maximum concurrent connections
server.max_connections = 100
# Add IP whitelist validator
ip_validator = Shirk::SSH::IPWhitelistValidator.from_cidr(["127.0.0.1", "10.0.0.0/8"])
server.add_connection_validator(ip_validator)
# Add event callback for logging
logging_callback = Shirk::SSH::LoggingCallback.new
server.add_event_callback(logging_callback)
# Custom event callback
class MyEventCallback < Shirk::SSH::EventCallback
def call(event : Shirk::SSH::Event) : Nil
case event.type
when .connection_start?
puts "New connection from #{event.connection.remote_ip}"
when .auth_success?
puts "User authenticated: #{event.data}"
when .message_received?
puts "Message: #{event.data}"
end
end
end
server.add_event_callback(MyEventCallback.new)
server.on_message do |message|
"Connection received: #{message}"
end
server.start
Built-in Connection Validators
- IPWhitelistValidator - Allows connections only from whitelisted IP addresses or CIDR ranges
- RateLimitValidator - Limits number of concurrent connections per IP address
Custom Connection Validator
class MyValidator < Shirk::SSH::ConnectionValidator
def validate(connection : Shirk::SSH::ConnectionInfo) : Shirk::SSH::ConnectionResult
# Your validation logic here
if connection.remote_ip.starts_with?("192.168.")
Shirk::SSH::ConnectionResult::Accept
else
Shirk::SSH::ConnectionResult::Reject
end
end
end
server.add_connection_validator(MyValidator.new)
Connection Information and Events
The system tracks comprehensive connection metadata:
# Get active connections
active_connections = server.active_connections
puts "Active connections: #{server.active_connections_count}"
# Each connection contains:
# - remote_ip : String
# - remote_port : Int32
# - connect_time : Time
# - username : String?
# - auth_method : String?
# - key_fingerprint : String?
# - duration : Time::Span
# - authenticated? : Bool
Event Types
- ConnectionStart - New connection established
- ConnectionEnd - Connection closed
- AuthStart - Authentication attempt started
- AuthSuccess - Authentication successful
- AuthFailure - Authentication failed
- MessageReceived - Message received from client
- Error - Error occurred
Running the server
Save the code above to a file (e.g., server.cr) and run:
crystal build server.cr --link-flags "-lssh"
./server
Testing the server
You can test the SSH server using standard SSH clients:
# Send a message via SSH
echo "hello" | ssh localhost -p 2222
# Or use netcat/telnet for basic testing
echo "hello" | nc localhost 2222
Message Handlers
Shirk provides built-in message handlers and allows custom handlers:
Built-in Echo Handler
require "shirk"
require "shirk/handlers/message_handler"
# Use built-in echo handler
handler = Shirk::Handlers::MessageHandler.echo("Server")
server = Shirk::SSH::Server.new(2222)
server.on_message(&handler.handle)
server.start
Custom Handler with Block
server = Shirk::SSH::Server.new(2222)
server.on_message do |message|
# Custom message processing
if message.starts_with?("CMD:")
command = message[4..-1].strip
`#{command}`
else
"Unknown command: #{message}"
end
end
server.start
Custom Handler Class
class MyHandler
def handle(message : String) : String
# Your custom logic here
"Processed: #{message.reverse}"
end
end
server = Shirk::SSH::Server.new(2222)
server.on_message(&MyHandler.new.handle)
server.start
API Reference
Shirk::SSH::Server
The main server class for handling SSH connections.
Constructors
new(port : Int32 = 2222, host : String = "0.0.0.0")- Create a new SSH server
Methods
on_message(&handler : String -> String)- Register a message handlerstart- Start the SSH serverstop- Stop the SSH server
Shirk::Handlers
MessageHandler
new(prefix : String = "Echo")- Create a new message handler with prefixecho(prefix : String = "Echo")- Factory method for echo handlerhandle(message : String) : String- Process a message
CustomMessageHandler
new(&handler : String -> String)- Create custom handler with block
Examples
See the examples/ directory for complete examples:
message_server.cr- Basic message handling serverauth_demo.cr- Demonstration of custom authentication handlersconnection_demo.cr- NEW! Comprehensive connection management demo with validation, rate limiting, and event callbackssimple_server.cr- Simple TCP server without SSH- More examples coming soon...
Connection Management Demo
The connection_demo.cr example showcases all the new connection management features:
# Build and run the connection management demo
crystal build examples/connection_demo.cr --link-flags "-lssh"
./connection_demo
# In another terminal, test the server
ssh localhost -p 3333
# Then try: stats, connections, help, hello
Features demonstrated:
- Connection validation with IP whitelisting
- Rate limiting and connection limits
- Event callbacks for logging and monitoring
- Connection metadata tracking
- Authentication event tracking
- Real-time statistics
Development
Building the project
# Build example
crystal build examples/message_server.cr --link-flags "-lssh"
# Run tests
crystal spec
# Build all examples
crystal build examples/*.cr --link-flags "-lssh"
Running the linter
ameba
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create a Pull Request
Security Considerations
This is a basic SSH server implementation. For production use:
- Authentication: The current implementation accepts all authentication requests for demo purposes. Implement proper authentication in production.
- Key Management: Set up proper SSH host keys
- Input Validation: Validate and sanitize all incoming messages
- Rate Limiting: Implement rate limiting to prevent abuse
- Logging: Add proper logging for security auditing
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
shirk
- 0
- 0
- 0
- 1
- 0
- about 8 hours ago
- November 26, 2025
MIT License
Thu, 27 Nov 2025 00:34:02 GMT