Initial commit: Open sourcing all of the Maple Open Technologies code.

This commit is contained in:
Bartlomiej Mika 2025-12-02 14:33:08 -05:00
commit 755d54a99d
2010 changed files with 448675 additions and 0 deletions

View file

@ -0,0 +1,126 @@
// File Path: monorepo/cloud/maplefile-backend/pkg/security/ipcountryblocker/ipcountryblocker.go
package ipcountryblocker
import (
"context"
"fmt"
"log"
"net"
"sync"
"github.com/oschwald/geoip2-golang"
"go.uber.org/zap"
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config"
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/validation"
)
// Provider defines the interface for IP-based country blocking operations.
// It provides methods to check if an IP or country is blocked and to retrieve
// country codes for given IP addresses.
type Provider interface {
// IsBlockedCountry checks if a country is in the blocked list.
// isoCode must be an ISO 3166-1 alpha-2 country code.
IsBlockedCountry(isoCode string) bool
// IsBlockedIP determines if an IP address originates from a blocked country.
// Returns false for nil IP addresses or if country lookup fails.
IsBlockedIP(ctx context.Context, ip net.IP) bool
// GetCountryCode returns the ISO 3166-1 alpha-2 country code for an IP address.
// Returns an error if the lookup fails or no country is found.
GetCountryCode(ctx context.Context, ip net.IP) (string, error)
// Close releases resources associated with the provider.
Close() error
}
// provider implements the Provider interface using MaxMind's GeoIP2 database.
type provider struct {
db *geoip2.Reader
blockedCountries map[string]struct{} // Uses empty struct to optimize memory
logger *zap.Logger
mu sync.RWMutex // Protects concurrent access to blockedCountries
}
// NewProvider creates a new IP country blocking provider using the provided configuration.
// It initializes the GeoIP2 database and sets up the blocked countries list.
// Fatally crashes the entire application if the database cannot be opened.
func NewProvider(cfg *config.Configuration, logger *zap.Logger) Provider {
db, err := geoip2.Open(cfg.Security.GeoLiteDBPath)
if err != nil {
log.Fatalf("failed to open GeoLite2 DB: %v", err)
}
blocked := make(map[string]struct{}, len(cfg.Security.BannedCountries))
for _, country := range cfg.Security.BannedCountries {
blocked[country] = struct{}{}
}
logger.Debug("ip blocker initialized",
zap.String("db_path", cfg.Security.GeoLiteDBPath),
zap.Any("blocked_countries", cfg.Security.BannedCountries))
return &provider{
db: db,
blockedCountries: blocked,
logger: logger,
}
}
// IsBlockedCountry checks if a country code exists in the blocked countries map.
// Thread-safe through RLock.
func (p *provider) IsBlockedCountry(isoCode string) bool {
p.mu.RLock()
defer p.mu.RUnlock()
_, exists := p.blockedCountries[isoCode]
return exists
}
// IsBlockedIP performs a country lookup for the IP and checks if it's blocked.
// Returns false for nil IPs or failed lookups to fail safely.
func (p *provider) IsBlockedIP(ctx context.Context, ip net.IP) bool {
if ip == nil {
return false
}
code, err := p.GetCountryCode(ctx, ip)
if err != nil {
// Developers Note:
// Comment this console log as it contributes a `noisy` server log.
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// p.logger.WarnContext(ctx, "failed to get country code",
// zap.Any("ip", ip),
// zap.Any("error", err))
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Developers Note:
// If the country d.n.e. exist that means we will return with `false`
// indicating this IP address is allowed to access our server. If this
// is concerning then you might set this to `true` to block on all
// IP address which are not categorized by country.
return false
}
return p.IsBlockedCountry(code)
}
// GetCountryCode performs a GeoIP2 database lookup to determine an IP's country.
// Returns an error if the lookup fails or no country is found.
func (p *provider) GetCountryCode(ctx context.Context, ip net.IP) (string, error) {
record, err := p.db.Country(ip)
if err != nil {
return "", fmt.Errorf("lookup country: %w", err)
}
if record == nil || record.Country.IsoCode == "" {
return "", fmt.Errorf("no country found for IP: %s", validation.MaskIP(ip.String()))
}
return record.Country.IsoCode, nil
}
// Close cleanly shuts down the GeoIP2 database connection.
func (p *provider) Close() error {
return p.db.Close()
}

View file

@ -0,0 +1,252 @@
// File Path: monorepo/cloud/maplefile-backend/pkg/security/ipcountryblocker/ipcountryblocker_test.go
package ipcountryblocker
import (
"context"
"net"
"testing"
"github.com/stretchr/testify/assert"
"go.uber.org/zap"
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config"
)
// testProvider is a test-specific wrapper that allows access to internal fields
// of the provider struct for verification in tests. This is a common pattern
// when you need to test internal state while keeping the production interface clean.
type testProvider struct {
Provider // Embedded interface for normal operations
internal *provider // Access to internal fields for testing
}
// newTestProvider creates a test provider instance with access to internal fields.
// This allows us to verify the internal state in our tests while maintaining
// encapsulation in production code.
func newTestProvider(cfg *config.Configuration, logger *zap.Logger) testProvider {
p := NewProvider(cfg, logger)
return testProvider{
Provider: p,
internal: p.(*provider), // Type assertion to get access to internal fields
}
}
// TestNewProvider verifies that the provider is properly initialized with all
// required components (database connection, blocked countries map, logger).
func TestNewProvider(t *testing.T) {
// Setup test configuration with path to test database
cfg := &config.Configuration{
Security: config.SecurityConfig{
GeoLiteDBPath: "../../../static/GeoLite2-Country.mmdb",
BannedCountries: []string{"US", "CN"},
},
}
// Initialize logger with JSON output for structured test logs
logger, _ := zap.NewDevelopment()
// Create test provider and verify internal components
p := newTestProvider(cfg, logger)
assert.NotNil(t, p.Provider, "Provider should not be nil")
assert.NotEmpty(t, p.internal.blockedCountries, "Blocked countries map should be initialized")
assert.NotNil(t, p.internal.logger, "Logger should be initialized")
assert.NotNil(t, p.internal.db, "Database connection should be initialized")
defer p.Close() // Ensure cleanup after test
}
// TestProvider_IsBlockedCountry tests the country blocking functionality with
// various country codes including edge cases like empty and invalid codes.
func TestProvider_IsBlockedCountry(t *testing.T) {
provider := setupTestProvider(t)
defer provider.Close()
// Table-driven test cases covering various scenarios
tests := []struct {
name string
country string
expected bool
}{
// Positive test cases - blocked countries
{
name: "blocked country US",
country: "US",
expected: true,
},
{
name: "blocked country CN",
country: "CN",
expected: true,
},
// Negative test cases - allowed countries
{
name: "non-blocked country GB",
country: "GB",
expected: false,
},
{
name: "non-blocked country JP",
country: "JP",
expected: false,
},
// Edge cases
{
name: "empty country code",
country: "",
expected: false,
},
{
name: "invalid country code",
country: "XX",
expected: false,
},
{
name: "lowercase country code", // Tests case sensitivity
country: "us",
expected: false,
},
}
// Run each test case
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := provider.IsBlockedCountry(tt.country)
assert.Equal(t, tt.expected, result)
})
}
}
// TestProvider_IsBlockedIP verifies IP blocking functionality using real-world
// IP addresses, including IPv4, IPv6, and various edge cases.
func TestProvider_IsBlockedIP(t *testing.T) {
provider := setupTestProvider(t)
defer provider.Close()
tests := []struct {
name string
ip net.IP
expected bool
}{
// Known IP addresses from blocked countries
{
name: "blocked IP (US - Google DNS)",
ip: net.ParseIP("8.8.8.8"), // Google's primary DNS
expected: true,
},
{
name: "blocked IP (US - Google DNS 2)",
ip: net.ParseIP("8.8.4.4"), // Google's secondary DNS
expected: true,
},
{
name: "blocked IP (CN - Alibaba)",
ip: net.ParseIP("223.5.5.5"), // Alibaba DNS
expected: true,
},
// Non-blocked country IPs
{
name: "non-blocked IP (GB)",
ip: net.ParseIP("178.62.1.1"),
expected: false,
},
// Edge cases and special scenarios
{
name: "nil IP",
ip: nil,
expected: false,
},
{
name: "invalid IP format",
ip: net.ParseIP("invalid"),
expected: false,
},
{
name: "IPv6 address",
ip: net.ParseIP("2001:4860:4860::8888"), // Google's IPv6 DNS
expected: true,
},
}
ctx := context.Background()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := provider.IsBlockedIP(ctx, tt.ip)
assert.Equal(t, tt.expected, result)
})
}
}
// TestProvider_GetCountryCode verifies the country code lookup functionality
// for various IP addresses, including error cases.
func TestProvider_GetCountryCode(t *testing.T) {
provider := setupTestProvider(t)
defer provider.Close()
tests := []struct {
name string
ip net.IP
expected string
expectError bool
}{
// Valid IP addresses with known countries
{
name: "US IP (Google DNS)",
ip: net.ParseIP("8.8.8.8"),
expected: "US",
expectError: false,
},
// Error cases
{
name: "nil IP",
ip: nil,
expected: "",
expectError: true,
},
{
name: "private IP", // RFC 1918 address
ip: net.ParseIP("192.168.1.1"),
expected: "",
expectError: true,
},
}
ctx := context.Background()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
code, err := provider.GetCountryCode(ctx, tt.ip)
if tt.expectError {
assert.Error(t, err, "Should return error for invalid IP")
assert.Empty(t, code, "Should return empty code on error")
return
}
assert.NoError(t, err, "Should not return error for valid IP")
assert.Equal(t, tt.expected, code, "Should return correct country code")
})
}
}
// TestProvider_Close verifies that the provider properly closes its resources
// and subsequent operations fail as expected.
func TestProvider_Close(t *testing.T) {
provider := setupTestProvider(t)
// Verify initial close succeeds
err := provider.Close()
assert.NoError(t, err, "Initial close should succeed")
// Verify operations fail after close
code, err := provider.GetCountryCode(context.Background(), net.ParseIP("8.8.8.8"))
assert.Error(t, err, "Operations should fail after close")
assert.Empty(t, code, "No data should be returned after close")
}
// setupTestProvider is a helper function that creates a properly configured
// provider instance for testing, using the test database path.
func setupTestProvider(t *testing.T) Provider {
cfg := &config.Configuration{
Security: config.SecurityConfig{
GeoLiteDBPath: "../../../static/GeoLite2-Country.mmdb",
BannedCountries: []string{"US", "CN"},
},
}
logger, _ := zap.NewDevelopment()
return NewProvider(cfg, logger)
}