robust_server_socket 0.3.2 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5ab7c243900b7f5a64995876c99501a830670a1dfddc217c5f49ec2699fac503
4
- data.tar.gz: 5c7552b5d17afae304cf186b5025b874a6a04b7afe80cd4c47092478a809689a
3
+ metadata.gz: b7b680d77f57104621b01b7abca736c21d819abc4e59355f5e70c3dff05df2eb
4
+ data.tar.gz: 15d86badaa9f0c76c97f330886188a3517b7d4dfd38d94c27f7c000cee1088d3
5
5
  SHA512:
6
- metadata.gz: 9faa202465b8c25c0ec07fee1a4ea9f18531488a1f6f6eb4717bb29e5424ddb8266912e1eaf7dda84c366ed276beede43b740eadb5fdde9a146f14b3b99b601b
7
- data.tar.gz: 410d43f438f999b0474d939319c65647ecc617c7a3313be38d0b7eb567cc20bc64d3f766bdca60089131c55fbd868849f3ba1f1cddf04bb4623f51e50c813f1c
6
+ metadata.gz: cbc390327dc4b6d4f382333c822cc367d0b936958d6ad8def8149e6b55a97d4137ff30690b3c3f4d9156120726a02ef12550e65065effb827a0adbe1bd196597
7
+ data.tar.gz: f8bc821809cabf3d0769c37549160f3d7b1456c0bc5bb3b787530171ba0eb83389fb9b4a4f65f94abc182fea34cabc740c1ca54ccd0f08d7578d5407956b0865
data/README.en.md ADDED
@@ -0,0 +1,614 @@
1
+ # RobustServerSocket
2
+
3
+ Gem for inter-service authorization, used in pair with RobustClientSocket
4
+
5
+ ### ⚠️ Not Production Tested (yet) but tested in staging environment
6
+
7
+ `Not vibecoded`
8
+
9
+ ## WHY
10
+
11
+ ### The Problem
12
+
13
+ When building microservice architecture, the server side faces:
14
+
15
+ - **Lack of verification**: How to verify that a request came from a trusted service?
16
+ - **Replay attacks**: Intercepted requests can be replayed
17
+ - **DDoS attacks**: Need to limit request frequency
18
+ - **Boilerplate code**: Repetitive validation logic in every service
19
+
20
+ ### The Solution
21
+
22
+ RobustServerSocket provides:
23
+
24
+ - **RSA decryption**: Token authenticity verification
25
+ - **Client whitelist**: Only authorized services allowed
26
+ - **Replay protection**: Blacklist of used tokens in Redis
27
+ - **Rate limiting**: Per-client request limits
28
+
29
+ ## HOW IT WORKS
30
+
31
+ ### Architecture
32
+
33
+ ```
34
+ Incoming request with Secure-Token
35
+
36
+ v
37
+ ┌──────────────────────────────┐
38
+ │ RobustServerSocket │
39
+ │ │
40
+ │ 1. RSA Decrypt │
41
+ │ 2. Validate Format │
42
+ │ 3. Check Client Whitelist │
43
+ │ 4. Check Rate Limit │
44
+ │ 5. Check Token Reuse │
45
+ │ 6. Check Token Expiration │
46
+ └──────────────┬───────────────┘
47
+
48
+ ┌────────┼────────┐
49
+ v v
50
+ ✅ Success ❌ Error
51
+ (continue) (401/403/429)
52
+ ```
53
+
54
+ ### Validation Flow
55
+
56
+ 1. **Decryption**: Base64 decode → RSA decrypt with private key
57
+ 2. **Parsing**: Extract `{client_name}_{timestamp}` from token
58
+ 3. **Whitelist**: Verify client_name is in `allowed_services`
59
+ 4. **Rate limit**: Check request count within window
60
+ 5. **Replay check**: Verify token hasn't been used (Redis)
61
+ 6. **Staleness**: Verify timestamp is current
62
+
63
+ ### Modular System
64
+
65
+ Checks are enabled via `using_modules`:
66
+ - `:client_auth_protection` — client whitelist
67
+ - `:replay_attack_protection` — prevent token reuse
68
+ - `:dos_attack_protection` — rate limiting
69
+
70
+ ## 📋 Table of Contents
71
+
72
+ - [Security Features](#security-features)
73
+ - [Installation](#installation)
74
+ - [Configuration](#configuration)
75
+ - [Usage](#usage)
76
+ - [Error Handling](#error-handling)
77
+
78
+ ## 🔒 Security Features
79
+
80
+ RobustServerSocket implements a multi-layered protection system for inter-service communications:
81
+
82
+ ### 1. Cryptographic Protection
83
+ - **RSA-2048 Encryption**: Uses RSA key pairs with minimum 2048-bit length
84
+ - **Key Validation**: Automatic key size verification during configuration
85
+ - **Asymmetric Encryption**: Private key on server, public keys on clients
86
+
87
+ ### 2. Token Reuse Protection
88
+ - **One-time Tokens**: Each token can only be used once
89
+ - **Redis Blacklist**: Used tokens are automatically added to blacklist
90
+ - **Atomic Verification**: Race conditions prevented via Redis Lua scripts
91
+
92
+ ### 3. Time-based Restrictions
93
+ - **Expiration Time**: Configurable token lifetime
94
+ - **Automatic Expiration**: Tokens automatically become invalid after expiration
95
+ - **Replay Attack Protection**: Old tokens cannot be reused
96
+
97
+ ### 4. Access Control
98
+ - **Client Whitelist**: Only authorized services can connect
99
+ - **Name-based Identification**: Each client must be explicitly listed in `allowed_services`
100
+ - **Token Format Validation**: Strict token structure verification
101
+
102
+ ### 5. Rate Limiting (optional)
103
+ - **DDoS Protection**: Limit number of requests from each client
104
+ - **Sliding Window**: Fair distribution of requests over time
105
+ - **Fail-open Strategy**: If Redis is unavailable, requests are allowed (for reliability)
106
+ - **Per-client Limits**: Individual counters for each client
107
+
108
+ ### 6. Injection Protection
109
+ - **Input Validation**: Type, length, and format verification of tokens
110
+ - **Maximum Token Length**: 2048 character limit
111
+ - **Empty Value Checks**: Rejection of empty or malformed tokens
112
+
113
+ ## 📦 Installation
114
+
115
+ Add to Gemfile:
116
+
117
+ ```ruby
118
+ gem 'robust_server_socket'
119
+ ```
120
+
121
+ Then execute:
122
+
123
+ ```bash
124
+ bundle install
125
+ ```
126
+
127
+ ## ⚙️ Configuration
128
+
129
+ Create file `config/initializers/robust_server_socket.rb`:
130
+
131
+ ```ruby
132
+ RobustServerSocket.configure do |c|
133
+ # REQUIRED PARAMETERS
134
+
135
+ # Service private key (RSA-2048 or higher)
136
+ # IMPORTANT: Store in environment variables, DO NOT commit to git!
137
+ c.private_key = ENV['ROBUST_SERVER_PRIVATE_KEY']
138
+
139
+ # Token lifetime in seconds
140
+ # Recommendation: 1-3 seconds for production (time from client request to server)
141
+ c.token_expiration_time = 3
142
+
143
+ # List of allowed services (whitelist)
144
+ # Must match names in client keychain
145
+ c.allowed_services = %w[core payments notifications]
146
+
147
+ # Redis for storing used tokens
148
+ c.redis_url = ENV.fetch('REDIS_URL', 'redis://localhost:6379/0')
149
+ c.redis_pass = ENV['REDIS_PASSWORD'] # can be nil for local development
150
+
151
+ # Maximum requests per time window (default: 100)
152
+ c.rate_limit_max_requests = 100
153
+
154
+ # Time window size in seconds (default: 60)
155
+ c.rate_limit_window_seconds = 60
156
+ end
157
+
158
+ # Load configuration with validation
159
+ RobustServerSocket.load!
160
+ ```
161
+
162
+ ## 🚀 Usage
163
+
164
+ ### Basic Authorization
165
+
166
+ ```ruby
167
+ # In controller or middleware
168
+ class ApiController < ApplicationController
169
+ before_action :authenticate_service!
170
+
171
+ private
172
+
173
+ def authenticate_service!
174
+ # Header configured in RobustClientSocket (SECURE-TOKEN default)
175
+ token = request.headers['SECURE-TOKEN']&.sub(/^Bearer /, '')
176
+
177
+ @current_service = RobustServerSocket::ClientToken.validate!(token) # bang method (raises errors)
178
+ rescue RobustServerSocket::ClientToken::InvalidToken
179
+ render json: { error: 'Invalid token' }, status: :unauthorized
180
+ rescue RobustServerSocket::ClientToken::UnauthorizedClient
181
+ render json: { error: 'Unauthorized service' }, status: :forbidden
182
+ rescue RobustServerSocket::ClientToken::UsedToken
183
+ render json: { error: 'Token already used' }, status: :unauthorized
184
+ rescue RobustServerSocket::ClientToken::StaleToken
185
+ render json: { error: 'Token expired' }, status: :unauthorized
186
+ rescue RobustServerSocket::RateLimiter::RateLimitExceeded => e
187
+ render json: { error: e.message }, status: :too_many_requests
188
+ end
189
+
190
+ def authenticate_service
191
+ token = request.headers['SECURE-TOKEN']&.sub(/^Bearer /, '')
192
+ @current_service = RobustServerSocket::ClientToken.new(token)
193
+
194
+ if @current_service.valid? # doesn't raise errors
195
+ # Token is valid
196
+ else
197
+ # Token is invalid
198
+ render json: { error: 'Unauthorized' }, status: :unauthorized
199
+ end
200
+ end
201
+ end
202
+ ```
203
+
204
+ ### Advanced Usage
205
+
206
+ ```ruby
207
+ # Create token object
208
+ token_string = request.headers['SECURE-TOKEN']&.sub(/^Bearer /, '')
209
+ client_token = RobustServerSocket::ClientToken.new(token_string)
210
+
211
+ # Check validity (returns true/false)
212
+ if client_token.valid?
213
+ # Get client name
214
+ client_name = client_token.client
215
+ puts "Authorized client: #{client_name}"
216
+ else
217
+ # Token is invalid
218
+ render json: { error: 'Unauthorized' }, status: :unauthorized
219
+ end
220
+
221
+ # Quick validation with exceptions (recommended)
222
+ begin
223
+ service_token = RobustServerSocket::ClientToken.validate!(token_string)
224
+ client_name = service_token.client
225
+ rescue => e
226
+ # Handle specific errors
227
+ end
228
+ ```
229
+
230
+ ## ❌ Error Handling
231
+
232
+ ### Exception Types
233
+
234
+ | Exception | Reason | HTTP Status | Action |
235
+ |-----------|--------|-------------|--------|
236
+ | `InvalidToken` | Token cannot be decrypted or has invalid format | 401 | Check token and key correctness |
237
+ | `UnauthorizedClient` | Client not in whitelist | 403 | Add client to `allowed_services` |
238
+ | `UsedToken` | Token has already been used | 401 | Client must request new token |
239
+ | `StaleToken` | Token has expired | 401 | Client must request new token |
240
+ | `RateLimitExceeded` | Rate limit exceeded | 429 | Client should wait or retry later |
241
+
242
+ ### Centralized Error Handling
243
+
244
+ ```ruby
245
+ # In ApplicationController
246
+ rescue_from RobustServerSocket::ClientToken::InvalidToken,
247
+ RobustServerSocket::ClientToken::UsedToken,
248
+ RobustServerSocket::ClientToken::StaleToken,
249
+ with: :unauthorized_response
250
+
251
+ rescue_from RobustServerSocket::ClientToken::UnauthorizedClient,
252
+ with: :forbidden_response
253
+
254
+ rescue_from RobustServerSocket::RateLimiter::RateLimitExceeded,
255
+ with: :rate_limit_response
256
+
257
+ private
258
+
259
+ def unauthorized_response(exception)
260
+ render json: {
261
+ error: 'Authentication failed',
262
+ message: exception.message,
263
+ type: exception.class.name
264
+ }, status: :unauthorized
265
+ end
266
+
267
+ def forbidden_response(exception)
268
+ render json: {
269
+ error: 'Access denied',
270
+ message: exception.message,
271
+ type: exception.class.name
272
+ }, status: :forbidden
273
+ end
274
+
275
+ def rate_limit_response(exception)
276
+ render json: {
277
+ error: 'Too many requests',
278
+ message: exception.message,
279
+ type: exception.class.name,
280
+ retry_after: RobustServerSocket.configuration.rate_limit_window_seconds
281
+ }, status: :too_many_requests
282
+ end
283
+ ```
284
+
285
+ ### 2. Redis Configuration
286
+
287
+ **✅ DO:**
288
+ ```ruby
289
+ # Use separate namespace for each environment
290
+ c.redis_url = ENV.fetch('REDIS_URL', 'redis://localhost:6379/0')
291
+
292
+ # Configure connection pool in production
293
+ # In config/initializers/redis.rb
294
+ Redis.current = ConnectionPool.new(size: 5, timeout: 5) do
295
+ Redis.new(url: ENV['REDIS_URL'], password: ENV['REDIS_PASSWORD'])
296
+ end
297
+
298
+ # Monitor Redis status
299
+ # Use Redis Sentinel or Cluster for high availability
300
+ ```
301
+
302
+ **❌ DON'T:**
303
+ ```ruby
304
+ # DON'T use same Redis DB for all environments, use separate Redis DB
305
+ # DON'T ignore Redis errors (rate limiter is already fail-open, but log them)
306
+ ```
307
+
308
+ ### 5. Service Whitelist
309
+
310
+ ```ruby
311
+ # Explicitly specify only necessary services
312
+ c.allowed_services = %w[core payments] # ✅
313
+
314
+ # DON'T use wildcards or regular expressions
315
+ c.allowed_services = %w[*] # ❌ DANGEROUS!
316
+
317
+ # Synchronize with client keychain
318
+ # Server (robust_server_socket):
319
+ c.allowed_services = %w[core]
320
+
321
+ # Client (robust_client_socket):
322
+ c.keychain = {
323
+ core: { # ← Must match
324
+ base_uri: 'https://core.example.com',
325
+ public_key: '-----BEGIN PUBLIC KEY-----...'
326
+ }
327
+ }
328
+ ```
329
+
330
+ ## 🤝 Integration with RobustClientSocket
331
+
332
+ For full functionality, configure the client side:
333
+
334
+ ```ruby
335
+ # On client (RobustClientSocket)
336
+ RobustClientSocket.configure do |c|
337
+ c.service_name = 'core' # ← Must be in server's allowed_services
338
+ c.keychain = {
339
+ payments: {
340
+ base_uri: 'https://payments.example.com',
341
+ public_key: '-----BEGIN PUBLIC KEY-----...' # Public key of payments server
342
+ }
343
+ }
344
+ end
345
+
346
+ # On server (RobustServerSocket)
347
+ RobustServerSocket.configure do |c|
348
+ c.allowed_services = %w[core] # ← Matches client's service_name
349
+ c.private_key = '-----BEGIN PRIVATE KEY-----...' # Private pair to public_key
350
+ end
351
+ ```
352
+
353
+ ## 📚 Additional Resources
354
+
355
+ - [RobustClientSocket documentation](https://github.com/tee0zed/robust_client_socket)
356
+ - [RSA encryption best practices](https://www.openssl.org/docs/)
357
+ - [Redis security guide](https://redis.io/topics/security)
358
+
359
+ ## 📝 License
360
+
361
+ See [MIT-LICENSE](MIT-LICENSE) file
362
+
363
+ ## 🐛 Bugs and Suggestions
364
+
365
+ Report issues through your repository's issue tracker.
366
+
367
+
368
+ #### Test: 1000 Requests with Token Validation
369
+
370
+ **Without RobustServerSocket (plain HTTP controller):**
371
+ ```ruby
372
+ Benchmark.measure do
373
+ 1000.times do
374
+ # Regular request without authorization
375
+ get '/api/v1/partners/719a68e4-3457-45dd-8d7f-73f1d367b87a/merchants'
376
+ end
377
+ end
378
+ ```
379
+
380
+ **Results (approximate):**
381
+ - **Real time**: ~2.5 seconds
382
+ - No token verification
383
+ - No RSA decryption
384
+ - No Redis checks
385
+
386
+ ---
387
+
388
+ **With RobustServerSocket (full protection):**
389
+ ```ruby
390
+ Benchmark.measure do
391
+ 1000.times do
392
+ # Request with RobustClientSocket (RSA + tokens)
393
+ RobustClientSocket::CoreApi.get('/api/v1/partners/719a68e4-3457-45dd-8d7f-73f1d367b87a/merchants')
394
+ end
395
+ end
396
+ ```
397
+
398
+ **Results:**
399
+ - **Real time**: 2.77 seconds
400
+ - **User CPU**: 0.23 seconds
401
+ - **System CPU**: 0.54 seconds
402
+ - **Total CPU**: 0.77 seconds
403
+
404
+ ### 📊 Security Overhead Analysis
405
+
406
+ | Operation | Time | % of Request |
407
+ |-----------|------|-------------|
408
+ | **RSA Decryption** | ~0.1-0.2ms | 3-7% |
409
+ | **Redis Token Check** | ~0.05-0.1ms | 2-3% |
410
+ | **Rate Limiting** | ~0.02-0.05ms | 1% |
411
+ | **Whitelist Validation** | <0.01ms | <1% |
412
+ | **Total Overhead** | **~0.2-0.4ms** | **~10-15%** |
413
+
414
+ ### 🎯 Key Findings
415
+
416
+ 1. **Minimal overhead (~0.3ms per request)**
417
+ - RSA-2048 decryption: ~0.15ms
418
+ - Redis operations: ~0.08ms
419
+ - Rate limiting: ~0.03ms
420
+
421
+ 2. **Scales linearly**
422
+ - 100 req/s = +30ms overhead
423
+ - 1000 req/s = +300ms overhead
424
+ - Acceptable for most applications
425
+
426
+ 3. **Redis is main bottleneck**
427
+ - Use Redis Sentinel/Cluster
428
+ - Connection pooling is critical
429
+ - Fail-open strategy for reliability
430
+
431
+ ### 💡 Performance Optimization
432
+
433
+ **1. Redis Connection Pool:**
434
+
435
+ ```ruby
436
+ # config/initializers/redis.rb
437
+ require 'connection_pool'
438
+
439
+ REDIS_POOL = ConnectionPool.new(size: 25, timeout: 5) do
440
+ Redis.new(
441
+ url: ENV['REDIS_URL'],
442
+ password: ENV['REDIS_PASSWORD'],
443
+ reconnect_attempts: 3,
444
+ reconnect_delay: 0.5,
445
+ reconnect_delay_max: 5.0
446
+ )
447
+ end
448
+
449
+ # In RobustServerSocket::Cacher
450
+ def self.with_redis
451
+ REDIS_POOL.with do |redis|
452
+ yield redis
453
+ end
454
+ end
455
+ ```
456
+
457
+ **2. Public Key Caching:**
458
+
459
+ ```ruby
460
+ # Keys are already cached at load!, but can be optimized
461
+ class RobustServerSocket::ClientToken
462
+ # Keys are loaded once at application startup
463
+ # No additional optimization needed
464
+ end
465
+ ```
466
+
467
+ **3. Rate Limiting Optimization:**
468
+
469
+ ```ruby
470
+ RobustServerSocket.configure do |c|
471
+ # For high-load systems
472
+ c.rate_limit_max_requests = 1000 # Increase limit
473
+ c.rate_limit_window_seconds = 60
474
+
475
+ # For low-load systems
476
+ c.rate_limit_max_requests = 100
477
+ c.rate_limit_window_seconds = 60
478
+ end
479
+ ```
480
+
481
+ **4. Token Expiration Optimization:**
482
+
483
+ ```ruby
484
+ # Short lifetime = more requests for new tokens
485
+ c.token_expiration_time = 10.minutes # ❌ High traffic
486
+
487
+ # Optimal time for inter-service calls
488
+ c.token_expiration_time = 3 # ✅ 3 seconds is enough
489
+ ```
490
+
491
+ ### 🔬 Performance Monitoring
492
+
493
+ **Metrics to Track:**
494
+
495
+ ```ruby
496
+ class ApiController < ApplicationController
497
+ around_action :track_auth_performance
498
+
499
+ private
500
+
501
+ def track_auth_performance
502
+ start = Time.now
503
+
504
+ begin
505
+ yield
506
+ ensure
507
+ duration = ((Time.now - start) * 1000).round(2)
508
+
509
+ # Total request time
510
+ Metrics.timing('request.duration', duration, tags: [
511
+ "controller:#{controller_name}",
512
+ "action:#{action_name}"
513
+ ])
514
+
515
+ # Authentication attempts
516
+ if @current_service
517
+ Metrics.increment('auth.success', tags: ["service:#{@current_service.client}"])
518
+ else
519
+ Metrics.increment('auth.failure')
520
+ end
521
+ end
522
+ end
523
+ end
524
+
525
+ # Specific metrics for RobustServerSocket
526
+ module RobustServerSocket
527
+ class ClientToken
528
+ def self.validate_with_metrics!(token)
529
+ start = Time.now
530
+ result = validate!(token)
531
+ duration = ((Time.now - start) * 1000).round(2)
532
+
533
+ Metrics.timing('robust_server.validation.duration', duration)
534
+ result
535
+ rescue StandardError => e
536
+ Metrics.increment('robust_server.validation.error', tags: ["error:#{e.class.name}"])
537
+ raise
538
+ end
539
+ end
540
+ end
541
+ ```
542
+
543
+ ### 📈 Performance at Different Loads
544
+
545
+ | Req/s | Without Protection | With RobustServerSocket | Overhead | Acceptable |
546
+ |-------|-------------------|------------------------|----------|-----------|
547
+ | 10 | 100ms | 103ms | 3ms | ✅ Excellent |
548
+ | 100 | 1s | 1.03s | 30ms | ✅ Excellent |
549
+ | 500 | 5s | 5.15s | 150ms | ✅ Good |
550
+ | 1,000 | 10s | 10.3s | 300ms | ✅ Acceptable |
551
+ | 5,000 | 50s | 51.5s | 1.5s | ⚠️ Redis scaling needed |
552
+ | 10,000 | 100s | 103s | 3s | ⚠️ Need Redis Cluster |
553
+
554
+ **Conclusion:** Up to 1000 req/s - excellent performance. Higher loads require Redis scaling.
555
+
556
+ ### 🚀 Production Recommendations
557
+
558
+ **For high-load systems (>1000 req/s):**
559
+
560
+ 1. **Redis Cluster** - distributed load
561
+ 2. **Connection Pool** - minimum 25-50 connections
562
+ 3. **Monitor Redis** - latency, memory, connections
563
+ 4. **Fail-over Strategy** - Redis Sentinel
564
+ 5. **CDN for static** - reduce overall load
565
+
566
+ **For medium load (100-1000 req/s):**
567
+
568
+ 1. **Standalone Redis** with persistence
569
+ 2. **Connection Pool** - 10-25 connections
570
+ 3. **Basic monitoring**
571
+ 4. **Rate limiting** - spike protection
572
+
573
+ **For low load (<100 req/s):**
574
+
575
+ 1. **Simple Redis** setup
576
+ 2. **Default connection pool** (5)
577
+ 3. **Standard configuration**
578
+
579
+ ## 🤝 Integration with RobustClientSocket
580
+
581
+ For full functionality, configure the client side:
582
+
583
+ ```ruby
584
+ # On client (RobustClientSocket)
585
+ RobustClientSocket.configure do |c|
586
+ c.service_name = 'core' # ← Must be in server's allowed_services
587
+ c.keychain = {
588
+ payments: {
589
+ base_uri: 'https://payments.example.com',
590
+ public_key: '-----BEGIN PUBLIC KEY-----...' # Public key of payments server
591
+ }
592
+ }
593
+ end
594
+
595
+ # On server (RobustServerSocket)
596
+ RobustServerSocket.configure do |c|
597
+ c.allowed_services = %w[core] # ← Matches client's service_name
598
+ c.private_key = '-----BEGIN PRIVATE KEY-----...' # Private pair to public_key
599
+ end
600
+ ```
601
+
602
+ ## 📚 Additional Resources
603
+
604
+ - [RobustClientSocket documentation](../robust_client_socket/README.md)
605
+ - [RSA encryption best practices](https://www.openssl.org/docs/)
606
+ - [Redis security guide](https://redis.io/topics/security)
607
+
608
+ ## 📝 License
609
+
610
+ See [MIT-LICENSE](MIT-LICENSE) file
611
+
612
+ ## 🐛 Bugs and Suggestions
613
+
614
+ Report issues to my telegram @cruel_mango or to email tee0zed@gmail.com