Vibe-guided bskyoauth and custom repo example code in Golang 🤖 probably not safe to use in prod
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Archive completed TODO issues to separate file (v1.1.4)

Improved documentation maintainability by archiving all completed
security issues from TODO.md to new COMPLETED_ISSUES.md file.

Changes:
- Created COMPLETED_ISSUES.md with 14 completed security issues (~550 lines)
- Reduced TODO.md from 757 to 220 lines (71% reduction)
- Added cross-reference links between files
- Kept only active work items in TODO.md (Issues #15-18)
- Preserved complete historical record in COMPLETED_ISSUES.md

Impact:
- Easier to identify pending work vs completed issues
- Cleaner, more actionable TODO list
- Historical documentation preserved
- No functional changes (documentation only)

This is a pure documentation maintenance release with zero code changes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

+653 -541
+557
COMPLETED_ISSUES.md
··· 1 + # Completed Issues Archive 2 + 3 + This file contains security issues and improvements that have been successfully implemented in the bskyoauth library. These items have been moved from [TODO.md](TODO.md) to reduce noise and keep the active TODO list focused on pending work. 4 + 5 + All completed issues are documented in [CHANGELOG.md](CHANGELOG.md) with version numbers and implementation details. 6 + 7 + --- 8 + 9 + ## COMPLETED ISSUES 10 + 11 + ### 1. Session Cookie Security Enhancement ✅ **COMPLETED** 12 + **File:** [examples/web-demo/main.go:137-157](examples/web-demo/main.go#L137-L157), [examples/web-demo/main.go:270-297](examples/web-demo/main.go#L270-L297) 13 + 14 + **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 15 + 16 + **Issue:** Session cookies lack `Secure` flag and session expiration controls. 17 + 18 + **Implementation:** 19 + - ✅ Added `Secure` flag with automatic HTTPS detection 20 + - Checks BASE_URL environment variable 21 + - Enables Secure flag when https:// is detected 22 + - Safe for localhost development (HTTP allowed) 23 + - ✅ Added `MaxAge: 86400` (24 hours) for session expiration 24 + - ✅ Updated callback success handler with enhanced cookie security 25 + - ✅ Updated logout handler to match cookie attributes for proper deletion 26 + - ✅ Maintained HttpOnly and SameSite protections 27 + - ✅ Environment-aware: automatically adapts to deployment context 28 + 29 + **Cookie Configuration:** 30 + ```go 31 + http.SetCookie(w, &http.Cookie{ 32 + Name: "session_id", 33 + Value: sessionID, 34 + Path: "/", 35 + HttpOnly: true, // Prevents JavaScript access 36 + Secure: isSecure, // HTTPS only in production 37 + SameSite: http.SameSiteLaxMode, // CSRF protection 38 + MaxAge: 86400, // 24 hours 39 + }) 40 + ``` 41 + 42 + **Impact:** Prevents cookie interception via HTTPS enforcement and limits session hijacking with time-bound expiration. 43 + 44 + --- 45 + 46 + ### 2. In-Memory Session Store Lacks Expiration ✅ **COMPLETED** 47 + **File:** [types.go:61-185](types.go#L61-L185) 48 + 49 + **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 50 + 51 + **Issue:** MemorySessionStore had no automatic cleanup or TTL mechanism. Sessions persisted indefinitely, causing: 52 + - Memory leaks in long-running applications 53 + - Increased attack surface for stolen sessions 54 + - No automatic session invalidation 55 + 56 + **Implementation:** 57 + - ✅ Added 30-day TTL for sessions (configurable, matches cookie MaxAge) 58 + - ✅ Implemented automatic cleanup goroutine (runs every 5 minutes) 59 + - ✅ Added expiration validation on retrieval (defense-in-depth) 60 + - ✅ Created `sessionEntry` wrapper with `expiresAt` timestamp 61 + - ✅ Added `NewMemorySessionStoreWithTTL()` for custom TTL configuration 62 + - ✅ Added `Stop()` method for graceful shutdown 63 + - ✅ Comprehensive test coverage added (7 new tests) 64 + - ✅ Thread-safe with proper RWMutex usage 65 + - ✅ Documentation added to README.md with examples 66 + 67 + **Impact:** Memory leaks prevented, session hijacking window limited to 30 days (configurable), proper resource management in long-running applications. 68 + 69 + --- 70 + 71 + ### 3. OAuth State Store Memory Leak ✅ **COMPLETED** 72 + **File:** [oauth.go:36-138](oauth.go#L36-L138) 73 + 74 + **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 75 + 76 + **Issue:** `globalStateStore` never expires entries. If authorization flow is abandoned: 77 + - State tokens persist forever 78 + - DPoP private keys remain in memory 79 + - Potential memory exhaustion 80 + 81 + **Implementation:** 82 + - ✅ Added 10-minute TTL for OAuth state entries (configurable) 83 + - ✅ Implemented automatic cleanup goroutine (runs every 1 minute) 84 + - ✅ Added expiration validation on retrieval (defense-in-depth) 85 + - ✅ Graceful shutdown support for cleanup goroutine 86 + - ✅ Comprehensive test coverage added 87 + - ✅ Thread-safe with proper mutex usage 88 + 89 + **Impact:** Memory leaks prevented, DoS vector eliminated, improved resource management. 90 + 91 + --- 92 + 93 + ### 4. Missing HTTPS Enforcement Documentation ✅ **COMPLETED** 94 + **File:** [README.md](README.md), [examples/web-demo/main.go](examples/web-demo/main.go) 95 + 96 + **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 97 + 98 + **Issue:** Documentation doesn't emphasize HTTPS requirement for production. OAuth flows over HTTP expose: 99 + - Authorization codes 100 + - State parameters 101 + - Session cookies 102 + 103 + **Implementation:** 104 + - ✅ Added prominent ⚠️ HTTPS warning at top of Security section 105 + - ✅ Created comprehensive "Production Deployment Best Practices" section 106 + - ✅ Added reverse proxy configuration examples (nginx, Caddy) 107 + - ✅ Documented cookie security settings with code examples 108 + - ✅ Added production security checklist (12 items) 109 + - ✅ Web-demo example now validates BASE_URL and warns when HTTP is used 110 + - ✅ Web-demo shows success message when HTTPS is configured 111 + - ✅ Documented session storage, rate limiting, and additional security measures 112 + 113 + **Impact:** Prevents credential exposure in transit, provides clear guidance for secure deployments. 114 + 115 + --- 116 + 117 + ### 5. Missing CSRF Token Validation Enhancement ✅ **COMPLETED** 118 + **File:** [oauth.go:246-254](oauth.go#L246-L254) 119 + 120 + **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 121 + 122 + **Issue:** While OAuth state parameter provides CSRF protection, the callback handler doesn't validate issuer (`iss`) parameter matches expected domain. 123 + 124 + **Implementation:** 125 + - ✅ Added `ExpectedIssuer` field to `internalOAuthState` struct 126 + - ✅ Expected issuer stored during `StartAuthFlow` based on resolved handle 127 + - ✅ Issuer validation performed in `CompleteAuthFlow` before token exchange 128 + - ✅ New `ErrIssuerMismatch` error type for attack detection 129 + - ✅ Security event logging to stderr for monitoring (includes expected vs actual) 130 + - ✅ Validation occurs before any network requests to issuer 131 + - ✅ Test coverage added for issuer storage and retrieval 132 + 133 + **Impact:** Prevents authorization code injection attacks, enables security monitoring. 134 + 135 + --- 136 + 137 + ### 6. Error Information Disclosure ✅ **COMPLETED** 138 + **Files:** [oauth.go:202-208](oauth.go#L202-L208), [oauth.go:388-393](oauth.go#L388-L393) 139 + 140 + **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 141 + 142 + **Issue:** Error messages expose internal implementation details: 143 + - Auth server metadata request failures exposed HTTP status and response body 144 + - Token exchange failures exposed HTTP status and response body 145 + - Could leak internal server details, error messages, or system information to attackers 146 + 147 + **Implementation:** 148 + - ✅ Added internal logging to stderr for detailed error information 149 + - ✅ Generic error messages returned to users (only status code included) 150 + - ✅ Auth metadata errors: Log full details, return generic message 151 + - ✅ Token exchange errors: Log full details, return generic message 152 + - ✅ Prefix logging with "AUTH_ERROR:" and "TOKEN_ERROR:" for easy monitoring 153 + - ✅ Maintains error wrapping for proper error handling 154 + - ✅ No breaking changes - error types remain consistent 155 + 156 + **Impact:** Prevents information leakage while maintaining debugging capability through logs. 157 + 158 + --- 159 + 160 + ### 8. Missing Rate Limiting ✅ **COMPLETED** 161 + **Files:** [ratelimit.go](ratelimit.go), [examples/web-demo/main.go:31-47](examples/web-demo/main.go#L31-L47) 162 + 163 + **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 164 + 165 + **Issue:** No rate limiting on: 166 + - Login attempts - vulnerable to brute force 167 + - OAuth callback endpoint - vulnerable to enumeration 168 + - API operations - vulnerable to DoS 169 + 170 + **Implementation:** 171 + - ✅ Created `RateLimiter` type using golang.org/x/time/rate 172 + - ✅ Token bucket algorithm with configurable rate and burst limits 173 + - ✅ IP-based rate limiting per endpoint 174 + - ✅ Middleware pattern for easy integration 175 + - ✅ X-Forwarded-For header support for proxied requests 176 + - ✅ Automatic cleanup of idle limiters (prevents memory leaks) 177 + - ✅ Applied to web-demo example: 178 + - Auth endpoints (login, callback): 5 req/s, burst 10 179 + - API endpoints (post, create, delete): 10 req/s, burst 20 180 + - ✅ Returns HTTP 429 (Too Many Requests) when limit exceeded 181 + - ✅ Periodic cleanup every 5 minutes 182 + 183 + **Impact:** Prevents brute force, enumeration, and DoS attacks on sensitive endpoints. 184 + 185 + --- 186 + 187 + ### 9. Missing Input Validation and Sanitization ✅ **COMPLETED** 188 + **File:** [validation.go](validation.go), [client.go:103-104](client.go#L103-L104), [client.go:167-174](client.go#L167-L174), [examples/web-demo/main.go:185-188](examples/web-demo/main.go#L185-L188) 189 + 190 + **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 191 + 192 + **Issue:** Limited validation on user inputs: 193 + - Handle validation is minimal 194 + - Post text has no length limits 195 + - Custom record data not validated 196 + 197 + **Implementation:** 198 + - ✅ Created comprehensive validation.go module with centralized validation functions 199 + - ✅ Added `ValidateHandle()` to validate handles per AT Protocol spec (max 253 chars, proper format) 200 + - ✅ Added `ValidatePostText()` to validate post text (max 300 chars per AT Protocol spec) 201 + - ✅ Added `ValidateTextField()` for generic text field validation with configurable limits 202 + - ✅ Added `ValidateRecordFields()` for record structure validation 203 + - ✅ Added `ValidateCollectionNSID()` for collection name validation 204 + - ✅ Leverages AT Protocol syntax package from indigo for spec-compliant validation 205 + - ✅ UTF-8 validation and null byte rejection 206 + - ✅ Deep nesting prevention (max 10 levels) to prevent memory exhaustion 207 + - ✅ Comprehensive error types: ErrHandleInvalid, ErrTextTooLong, ErrInvalidUTF8, etc. 208 + - ✅ Created validation_test.go with 36 comprehensive test cases 209 + - ✅ Updated `LoginHandler` to validate handle format before OAuth flow 210 + - ✅ Updated `CreatePost` to validate text before API call 211 + - ✅ Updated `CreateRecord` to validate collection NSID and record fields 212 + - ✅ Updated web-demo `postHandler` to validate post text client-side 213 + - ✅ Updated web-demo `createOngakuHandler` to validate text field (1000 char limit) 214 + - ✅ All validation functions exported for use by library consumers 215 + - ✅ Comprehensive README documentation with usage examples 216 + - ✅ Test count increased from 127 to 193 tests (66 new validation tests) 217 + 218 + **Validation Features:** 219 + - **Handles**: Max 253 chars, segments max 63 chars, valid characters (a-z, 0-9, hyphen) 220 + - **Post Text**: Max 300 chars (AT Protocol spec), UTF-8 validated, no null bytes 221 + - **Custom Records**: Configurable limits, datetime validation, nesting prevention 222 + - **Collection NSIDs**: Validated using AT Protocol syntax package 223 + 224 + **Example Usage:** 225 + ```go 226 + // Validate handle 227 + if err := bskyoauth.ValidateHandle("alice.bsky.social"); err != nil { 228 + return err 229 + } 230 + 231 + // Validate post text 232 + if err := bskyoauth.ValidatePostText("Hello, world!"); err != nil { 233 + return err 234 + } 235 + 236 + // Validate custom field 237 + if err := bskyoauth.ValidateTextField(text, "description", 500); err != nil { 238 + return err 239 + } 240 + ``` 241 + 242 + **Impact:** Prevents injection attacks, resource exhaustion, and API errors. Provides early validation with clear error messages. 243 + 244 + --- 245 + 246 + ### 10. Missing Security Headers ✅ **COMPLETED** 247 + **File:** [securityheaders.go](securityheaders.go), [securityheaders_test.go](securityheaders_test.go), [examples/web-demo/main.go](examples/web-demo/main.go) 248 + 249 + **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 250 + 251 + **Issue:** No security headers middleware in main library: 252 + - No Content-Security-Policy 253 + - No X-Frame-Options 254 + - No X-Content-Type-Options 255 + - No Strict-Transport-Security 256 + 257 + **Implementation:** 258 + - ✅ Created `SecurityHeadersMiddleware()` in main library (securityheaders.go) 259 + - ✅ Automatic localhost detection from HTTP request's Host header 260 + - ✅ Localhost CSP: Relaxed with 'unsafe-inline' and 'unsafe-eval' for development 261 + - ✅ Production CSP: Strict with no unsafe directives, includes frame-ancestors 'none' 262 + - ✅ HSTS: Automatically enabled for HTTPS in production (never for localhost) 263 + - ✅ HTTPS detection via r.TLS or X-Forwarded-Proto header 264 + - ✅ Zero configuration required - works automatically from HTTP request 265 + - ✅ Handles reverse proxies, Docker, and cloud platforms automatically 266 + - ✅ Comprehensive test suite (securityheaders_test.go) with 13 test cases 267 + - ✅ Applied to web-demo example with single line of code 268 + - ✅ Documentation added to README.md with usage examples 269 + - ✅ CHANGELOG.md updated with technical details 270 + 271 + **Headers Applied:** 272 + - **Content-Security-Policy**: Environment-aware (relaxed localhost, strict production) 273 + - **X-Frame-Options**: DENY (prevents clickjacking) 274 + - **X-Content-Type-Options**: nosniff (prevents MIME-sniffing attacks) 275 + - **Strict-Transport-Security**: HTTPS production only (not localhost) 276 + - **X-XSS-Protection**: 1; mode=block 277 + - **Referrer-Policy**: strict-origin-when-cross-origin 278 + 279 + **How It Works:** 280 + ```go 281 + // Simply wrap your handler 282 + mux := http.NewServeMux() 283 + // ... set up handlers ... 284 + handler := bskyoauth.SecurityHeadersMiddleware()(mux) 285 + http.ListenAndServe(":8080", handler) 286 + ``` 287 + 288 + **Localhost Detection:** 289 + - Checks r.Host for: `localhost`, `127.0.0.1`, `[::1]`, `0.0.0.0` 290 + - Handles IPv6 addresses with brackets correctly 291 + - Strips port numbers for detection 292 + 293 + **Test Coverage:** 294 + - Localhost detection tests (IPv4, IPv6, ports) 295 + - CSP policy tests (localhost vs production) 296 + - HSTS tests (HTTP, HTTPS, localhost) 297 + - Header application tests (all headers present) 298 + - Handler execution tests (middleware doesn't break handlers) 299 + 300 + **Impact:** All library users get security headers automatically. Localhost-friendly development with production-ready security. Works in any deployment scenario without configuration. 301 + 302 + --- 303 + 304 + ### 11. Insufficient Logging and Monitoring ✅ **COMPLETED** 305 + **Files:** Multiple locations (oauth.go, session.go, client.go, ratelimit.go, logger.go, logger_test.go) 306 + 307 + **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 308 + 309 + **Issue:** Limited security event logging: 310 + - No failed login attempt logging 311 + - No session lifecycle events 312 + - No suspicious activity monitoring 313 + 314 + **Implementation:** 315 + - ✅ Added comprehensive structured logging using Go's standard `log/slog` package 316 + - ✅ Environment-based configuration (Info for localhost, Error for production) 317 + - ✅ Silent by default (logs to `io.Discard` unless explicitly configured) 318 + - ✅ Automatic format selection: Text for development, JSON for production 319 + - ✅ Context-aware logging with request ID and session ID correlation 320 + - ✅ Security event logging throughout the codebase: 321 + - OAuth flow: start/completion, token exchange, DPoP nonce retries 322 + - Session management: creation, retrieval, deletion, expiration, cleanup 323 + - API operations: post creation, record operations, failures 324 + - Rate limiting: exceeded limits, cleanup operations 325 + - ✅ Security events logged at ERROR level: 326 + - Issuer mismatch attacks 327 + - Invalid OAuth states 328 + - Token exchange failures 329 + - No valid session errors 330 + - ✅ New logger functions: 331 + - `SetLogger()` - Configure global logger 332 + - `NewLoggerFromEnv()` - One-line setup with environment detection 333 + - `LogLevelFromEnv()` - Detect log level from BASE_URL 334 + - `NewDefaultLogger()` - JSON logger with custom level 335 + - `NewTextLogger()` - Text logger with custom level 336 + - ✅ Context helpers for correlation: 337 + - `WithRequestID()` - Add request ID to context 338 + - `WithSessionID()` - Add session ID to context 339 + - `LoggerFromContext()` - Retrieve logger from context 340 + - `GenerateRequestID()` - Generate unique request ID 341 + - ✅ Comprehensive test coverage (11 new tests in logger_test.go) 342 + - ✅ Documentation added to README.md with examples 343 + - ✅ All tests passing (193 total tests) 344 + 345 + **Logging Levels:** 346 + - **Debug**: Rate limit checks passed, session retrieval details 347 + - **Info**: OAuth flow events, session lifecycle, API operations 348 + - **Warn**: Failed lookups, invalid inputs, rate limit exceeded 349 + - **Error**: Security events, critical failures, authentication errors 350 + 351 + **Example Usage:** 352 + ```go 353 + // Automatic environment-based setup 354 + logger := bskyoauth.NewLoggerFromEnv(os.Getenv("BASE_URL")) 355 + bskyoauth.SetLogger(logger) 356 + 357 + // Manual configuration 358 + logger := bskyoauth.NewDefaultLogger(slog.LevelError) // JSON, Error level 359 + bskyoauth.SetLogger(logger) 360 + 361 + // Context-aware logging 362 + ctx := bskyoauth.WithRequestID(r.Context(), bskyoauth.GenerateRequestID()) 363 + ctx = bskyoauth.WithSessionID(ctx, sessionID) 364 + session, err := client.CompleteAuthFlow(ctx, code, state, iss) 365 + // Logs include request_id and session_id fields 366 + ``` 367 + 368 + **Impact:** Enables security incident detection and investigation. Provides request correlation through IDs. Environment-aware configuration for development and production. Zero external dependencies using Go standard library. 369 + 370 + --- 371 + 372 + ### 12. Refresh Token Not Implemented ✅ **COMPLETED** 373 + **Files:** oauth.go, types.go, client.go, token_test.go 374 + 375 + **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 376 + 377 + **Issue:** Refresh token is stored but never used. Access tokens will expire requiring full re-authentication. 378 + 379 + **Implementation:** 380 + - ✅ Added `RefreshToken()` method to exchange refresh tokens for new access tokens 381 + - ✅ Added token expiration tracking to `Session` struct: 382 + - `AccessTokenExpiresAt time.Time` - When access token expires 383 + - `RefreshTokenExpiresAt time.Time` - When refresh token expires (optional) 384 + - ✅ Token expiration automatically parsed from OAuth token responses in `CompleteAuthFlow()` 385 + - ✅ Added token expiration helper methods: 386 + - `IsAccessTokenExpired(buffer time.Duration)` - Check if token expired or will expire soon 387 + - `IsRefreshTokenExpired()` - Check if refresh token expired 388 + - `TimeUntilAccessTokenExpiry()` - Get duration until expiration 389 + - ✅ Added `UpdateSession()` method to update sessions after refresh 390 + - ✅ DPoP binding maintained across token refresh (same DPoP key used) 391 + - ✅ Single-use refresh tokens per AT Protocol spec (old token invalidated after use) 392 + - ✅ Added `refreshTokenRequest()` helper with DPoP nonce retry support 393 + - ✅ Comprehensive logging throughout refresh process: 394 + - Token expiration parsing 395 + - Refresh initiation and completion 396 + - Error conditions (no token, expired token, network errors) 397 + - ✅ 6 new test cases in token_test.go: 398 + - `TestIsAccessTokenExpired` (5 sub-cases) 399 + - `TestIsRefreshTokenExpired` (3 sub-cases) 400 + - `TestTimeUntilAccessTokenExpiry` (3 sub-cases) 401 + - `TestUpdateSession` 402 + - `TestRefreshToken_NoRefreshToken` 403 + - `TestRefreshToken_ExpiredRefreshToken` 404 + - ✅ Full documentation in README with examples 405 + - ✅ Zero breaking changes - all additions backwards compatible 406 + 407 + **Key Features:** 408 + - **Manual Refresh**: Call `RefreshToken()` when tokens expire 409 + - **Expiration Checking**: Helper methods to check token status 410 + - **Error Handling**: Clear errors for expired/missing tokens 411 + - **AT Protocol Compliance**: Single-use tokens, DPoP binding maintained 412 + - **Flexible**: No expiration data? Methods assume tokens valid 413 + 414 + **Example Usage:** 415 + ```go 416 + // Check if token needs refresh 417 + if session.IsAccessTokenExpired(5 * time.Minute) { 418 + newSession, err := client.RefreshToken(ctx, session) 419 + if err != nil { 420 + // Refresh failed - redirect to login 421 + return redirectToLogin(w, r) 422 + } 423 + 424 + // Update session in store 425 + client.UpdateSession(sessionID, newSession) 426 + session = newSession 427 + } 428 + 429 + // Use refreshed session 430 + client.CreatePost(ctx, session, "Hello!") 431 + ``` 432 + 433 + **Impact:** Users no longer need to re-authenticate when access tokens expire. Improves user experience and enables shorter-lived access tokens for better security. 434 + 435 + --- 436 + 437 + ### 13. Add Context Timeout Handling ✅ **COMPLETED** 438 + **Files:** oauth.go, client.go, errors.go, timeout_test.go, errors_test.go 439 + 440 + **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 441 + 442 + **Issue:** HTTP requests lacked explicit timeout configurations, potentially causing indefinite hangs. 443 + 444 + **Implementation:** 445 + - ✅ Added `defaultHTTPClient` with comprehensive timeout configuration: 446 + - Total request timeout: 30 seconds 447 + - Connection timeout: 10 seconds (TCP handshake) 448 + - TLS handshake timeout: 10 seconds 449 + - Response header timeout: 10 seconds 450 + - Idle connection reuse: 90 seconds 451 + - Connection pooling: Max 100 idle connections, 10 per host 452 + - ✅ Replaced all `http.Get()` calls with context-aware `http.NewRequestWithContext()`: 453 + - 3 occurrences in `StartAuthFlow()`, `CompleteAuthFlow()`, and `RefreshToken()` 454 + - All requests now respect context cancellation and timeouts 455 + - ✅ Updated all `http.NewRequest()` calls to use context: 456 + - 2 main requests and 2 retry requests in token exchange functions 457 + - Proper error handling for request creation failures 458 + - ✅ Added `SetHTTPClient()` and `GetHTTPClient()` for global HTTP client configuration 459 + - ✅ Added `HTTPClient` field to `ClientOptions` for per-client timeout customization 460 + - ✅ Created `errors.go` with `IsTimeoutError()` helper function: 461 + - Detects `context.DeadlineExceeded` 462 + - Detects `net.Error` with `Timeout() == true` 463 + - Detects `os.ErrDeadlineExceeded` 464 + - Supports wrapped errors 465 + - ✅ Added timeout-specific error logging throughout OAuth flow 466 + - ✅ 10 comprehensive test cases: 467 + - `TestHTTPClientTimeout` - Verifies HTTP timeout behavior 468 + - `TestContextCancellation` - Tests context cancellation handling 469 + - `TestSetHTTPClient` / `TestGetHTTPClient` - Tests client configuration 470 + - `TestClientOptionsWithHTTPClient` - Tests per-client configuration 471 + - `TestIsTimeoutError_*` - 5 tests for timeout error detection 472 + - `TestDefaultHTTPClientSettings` - Validates default timeout values 473 + - ✅ Full documentation in README with examples for: 474 + - Custom HTTP client timeouts 475 + - Context-based per-request timeouts 476 + - Testing with custom timeouts 477 + - Timeout error detection 478 + - ✅ Zero breaking changes - all additions backwards compatible with sensible defaults 479 + 480 + **Key Features:** 481 + - **Automatic Timeouts**: All requests have 30s default timeout 482 + - **Configurable**: Set custom HTTP client globally or per-client 483 + - **Context-Aware**: Respect context cancellation and deadlines 484 + - **Error Detection**: Easy identification of timeout errors 485 + - **Connection Pooling**: Efficient connection reuse 486 + 487 + **Example Usage:** 488 + ```go 489 + // Custom timeout for specific client 490 + customClient := &http.Client{Timeout: 10 * time.Second} 491 + client := bskyoauth.NewClientWithOptions(bskyoauth.ClientOptions{ 492 + BaseURL: "https://myapp.com", 493 + HTTPClient: customClient, 494 + }) 495 + 496 + // Context timeout for specific request 497 + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 498 + defer cancel() 499 + 500 + flowState, err := client.StartAuthFlow(ctx, handle) 501 + if err != nil { 502 + if bskyoauth.IsTimeoutError(err) { 503 + log.Println("Request timed out") 504 + } 505 + } 506 + ``` 507 + 508 + **Impact:** Prevents indefinite hangs from unresponsive servers or network issues. Improves reliability and enables better error handling for production deployments. 509 + 510 + --- 511 + 512 + ### 14. Dependency Security Scanning ✅ **COMPLETED** 513 + **Files:** .github/dependabot.yml, .github/workflows/security.yml 514 + 515 + **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 516 + 517 + **Issue:** No automated dependency vulnerability scanning. 518 + 519 + **Implementation:** 520 + - ✅ Added Dependabot configuration (.github/dependabot.yml): 521 + - Weekly Go module dependency updates (Mondays at 9am Pacific) 522 + - Groups minor and patch updates together to reduce PR noise 523 + - Maximum 5 open PRs to keep review manageable 524 + - Auto-labels PRs with "dependencies" and "go" 525 + - Auto-rebase strategy for conflict resolution 526 + - Commit message prefix: "deps" 527 + - ✅ Added GitHub Actions security workflow (.github/workflows/security.yml): 528 + - Runs `govulncheck` for vulnerability scanning 529 + - Executes on push, pull requests, and weekly schedule 530 + - Test suite with race detection (-race flag) 531 + - Coverage reporting to Codecov 532 + - Uses Go version from go.mod for consistency 533 + - ✅ Scheduled weekly security scans (Mondays at 9am Pacific) 534 + - ✅ Automatic monitoring of security advisories via Dependabot 535 + 536 + **Key Features:** 537 + - **Automated Updates**: Weekly dependency update PRs 538 + - **Vulnerability Scanning**: govulncheck integration in CI/CD 539 + - **Smart Grouping**: Minor/patch updates grouped to reduce noise 540 + - **Test Coverage**: Full test suite runs on all security checks 541 + - **Zero Maintenance**: Fully automated, no manual intervention needed 542 + 543 + **Example Workflow:** 544 + 1. Dependabot checks for updates every Monday 545 + 2. Creates PR with grouped dependency updates 546 + 3. Security workflow runs automatically 547 + 4. govulncheck scans for vulnerabilities 548 + 5. Tests run with race detection 549 + 6. Review and merge PR if checks pass 550 + 551 + **Impact:** Proactive security monitoring ensures vulnerabilities are detected quickly. Automated updates keep dependencies current with minimal maintenance overhead. 552 + 553 + --- 554 + 555 + *For details on implementation and version numbers, see [CHANGELOG.md](CHANGELOG.md).* 556 + 557 + *Last updated: 2025-10-29*
+2 -540
TODO.md
··· 213 213 214 214 ## COMPLETED ISSUES 215 215 216 - ### 1. Session Cookie Security Enhancement ✅ **COMPLETED** 217 - **File:** [examples/web-demo/main.go:137-157](examples/web-demo/main.go#L137-L157), [examples/web-demo/main.go:270-297](examples/web-demo/main.go#L270-L297) 218 - 219 - **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 220 - 221 - **Issue:** Session cookies lack `Secure` flag and session expiration controls. 222 - 223 - **Implementation:** 224 - - ✅ Added `Secure` flag with automatic HTTPS detection 225 - - Checks BASE_URL environment variable 226 - - Enables Secure flag when https:// is detected 227 - - Safe for localhost development (HTTP allowed) 228 - - ✅ Added `MaxAge: 86400` (24 hours) for session expiration 229 - - ✅ Updated callback success handler with enhanced cookie security 230 - - ✅ Updated logout handler to match cookie attributes for proper deletion 231 - - ✅ Maintained HttpOnly and SameSite protections 232 - - ✅ Environment-aware: automatically adapts to deployment context 233 - 234 - **Cookie Configuration:** 235 - ```go 236 - http.SetCookie(w, &http.Cookie{ 237 - Name: "session_id", 238 - Value: sessionID, 239 - Path: "/", 240 - HttpOnly: true, // Prevents JavaScript access 241 - Secure: isSecure, // HTTPS only in production 242 - SameSite: http.SameSiteLaxMode, // CSRF protection 243 - MaxAge: 86400, // 24 hours 244 - }) 245 - ``` 246 - 247 - **Impact:** Prevents cookie interception via HTTPS enforcement and limits session hijacking with time-bound expiration. 248 - 249 - --- 250 - 251 - ### 2. In-Memory Session Store Lacks Expiration ✅ **COMPLETED** 252 - **File:** [types.go:61-185](types.go#L61-L185) 253 - 254 - **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 255 - 256 - **Issue:** MemorySessionStore had no automatic cleanup or TTL mechanism. Sessions persisted indefinitely, causing: 257 - - Memory leaks in long-running applications 258 - - Increased attack surface for stolen sessions 259 - - No automatic session invalidation 260 - 261 - **Implementation:** 262 - - ✅ Added 30-day TTL for sessions (configurable, matches cookie MaxAge) 263 - - ✅ Implemented automatic cleanup goroutine (runs every 5 minutes) 264 - - ✅ Added expiration validation on retrieval (defense-in-depth) 265 - - ✅ Created `sessionEntry` wrapper with `expiresAt` timestamp 266 - - ✅ Added `NewMemorySessionStoreWithTTL()` for custom TTL configuration 267 - - ✅ Added `Stop()` method for graceful shutdown 268 - - ✅ Comprehensive test coverage added (7 new tests) 269 - - ✅ Thread-safe with proper RWMutex usage 270 - - ✅ Documentation added to README.md with examples 271 - 272 - **Impact:** Memory leaks prevented, session hijacking window limited to 30 days (configurable), proper resource management in long-running applications. 273 - 274 - --- 275 - 276 - ### 3. OAuth State Store Memory Leak ✅ **COMPLETED** 277 - **File:** [oauth.go:36-138](oauth.go#L36-L138) 278 - 279 - **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 280 - 281 - **Issue:** `globalStateStore` never expires entries. If authorization flow is abandoned: 282 - - State tokens persist forever 283 - - DPoP private keys remain in memory 284 - - Potential memory exhaustion 285 - 286 - **Implementation:** 287 - - ✅ Added 10-minute TTL for OAuth state entries (configurable) 288 - - ✅ Implemented automatic cleanup goroutine (runs every 1 minute) 289 - - ✅ Added expiration validation on retrieval (defense-in-depth) 290 - - ✅ Graceful shutdown support for cleanup goroutine 291 - - ✅ Comprehensive test coverage added 292 - - ✅ Thread-safe with proper mutex usage 293 - 294 - **Impact:** Memory leaks prevented, DoS vector eliminated, improved resource management. 295 - 296 - --- 297 - 298 - ### 4. Missing HTTPS Enforcement Documentation ✅ **COMPLETED** 299 - **File:** [README.md](README.md), [examples/web-demo/main.go](examples/web-demo/main.go) 300 - 301 - **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 302 - 303 - **Issue:** Documentation doesn't emphasize HTTPS requirement for production. OAuth flows over HTTP expose: 304 - - Authorization codes 305 - - State parameters 306 - - Session cookies 307 - 308 - **Implementation:** 309 - - ✅ Added prominent ⚠️ HTTPS warning at top of Security section 310 - - ✅ Created comprehensive "Production Deployment Best Practices" section 311 - - ✅ Added reverse proxy configuration examples (nginx, Caddy) 312 - - ✅ Documented cookie security settings with code examples 313 - - ✅ Added production security checklist (12 items) 314 - - ✅ Web-demo example now validates BASE_URL and warns when HTTP is used 315 - - ✅ Web-demo shows success message when HTTPS is configured 316 - - ✅ Documented session storage, rate limiting, and additional security measures 317 - 318 - **Impact:** Prevents credential exposure in transit, provides clear guidance for secure deployments. 319 - 320 - --- 321 - 322 - ### 5. Missing CSRF Token Validation Enhancement ✅ **COMPLETED** 323 - **File:** [oauth.go:246-254](oauth.go#L246-L254) 324 - 325 - **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 326 - 327 - **Issue:** While OAuth state parameter provides CSRF protection, the callback handler doesn't validate issuer (`iss`) parameter matches expected domain. 328 - 329 - **Implementation:** 330 - - ✅ Added `ExpectedIssuer` field to `internalOAuthState` struct 331 - - ✅ Expected issuer stored during `StartAuthFlow` based on resolved handle 332 - - ✅ Issuer validation performed in `CompleteAuthFlow` before token exchange 333 - - ✅ New `ErrIssuerMismatch` error type for attack detection 334 - - ✅ Security event logging to stderr for monitoring (includes expected vs actual) 335 - - ✅ Validation occurs before any network requests to issuer 336 - - ✅ Test coverage added for issuer storage and retrieval 337 - 338 - **Impact:** Prevents authorization code injection attacks, enables security monitoring. 339 - 340 - --- 341 - 342 - ### 6. Error Information Disclosure ✅ **COMPLETED** 343 - **Files:** [oauth.go:202-208](oauth.go#L202-L208), [oauth.go:388-393](oauth.go#L388-L393) 344 - 345 - **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 346 - 347 - **Issue:** Error messages expose internal implementation details: 348 - - Auth server metadata request failures exposed HTTP status and response body 349 - - Token exchange failures exposed HTTP status and response body 350 - - Could leak internal server details, error messages, or system information to attackers 351 - 352 - **Implementation:** 353 - - ✅ Added internal logging to stderr for detailed error information 354 - - ✅ Generic error messages returned to users (only status code included) 355 - - ✅ Auth metadata errors: Log full details, return generic message 356 - - ✅ Token exchange errors: Log full details, return generic message 357 - - ✅ Prefix logging with "AUTH_ERROR:" and "TOKEN_ERROR:" for easy monitoring 358 - - ✅ Maintains error wrapping for proper error handling 359 - - ✅ No breaking changes - error types remain consistent 360 - 361 - **Impact:** Prevents information leakage while maintaining debugging capability through logs. 362 - 363 - --- 364 - 365 - ### 8. Missing Rate Limiting ✅ **COMPLETED** 366 - **Files:** [ratelimit.go](ratelimit.go), [examples/web-demo/main.go:31-47](examples/web-demo/main.go#L31-L47) 367 - 368 - **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 369 - 370 - **Issue:** No rate limiting on: 371 - - Login attempts - vulnerable to brute force 372 - - OAuth callback endpoint - vulnerable to enumeration 373 - - API operations - vulnerable to DoS 374 - 375 - **Implementation:** 376 - - ✅ Created `RateLimiter` type using golang.org/x/time/rate 377 - - ✅ Token bucket algorithm with configurable rate and burst limits 378 - - ✅ IP-based rate limiting per endpoint 379 - - ✅ Middleware pattern for easy integration 380 - - ✅ X-Forwarded-For header support for proxied requests 381 - - ✅ Automatic cleanup of idle limiters (prevents memory leaks) 382 - - ✅ Applied to web-demo example: 383 - - Auth endpoints (login, callback): 5 req/s, burst 10 384 - - API endpoints (post, create, delete): 10 req/s, burst 20 385 - - ✅ Returns HTTP 429 (Too Many Requests) when limit exceeded 386 - - ✅ Periodic cleanup every 5 minutes 387 - 388 - **Impact:** Prevents brute force, enumeration, and DoS attacks on sensitive endpoints. 389 - 390 - --- 391 - 392 - ### 9. Missing Input Validation and Sanitization ✅ **COMPLETED** 393 - **File:** [validation.go](validation.go), [client.go:103-104](client.go#L103-L104), [client.go:167-174](client.go#L167-L174), [examples/web-demo/main.go:185-188](examples/web-demo/main.go#L185-L188) 394 - 395 - **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 396 - 397 - **Issue:** Limited validation on user inputs: 398 - - Handle validation is minimal 399 - - Post text has no length limits 400 - - Custom record data not validated 401 - 402 - **Implementation:** 403 - - ✅ Created comprehensive validation.go module with centralized validation functions 404 - - ✅ Added `ValidateHandle()` to validate handles per AT Protocol spec (max 253 chars, proper format) 405 - - ✅ Added `ValidatePostText()` to validate post text (max 300 chars per AT Protocol spec) 406 - - ✅ Added `ValidateTextField()` for generic text field validation with configurable limits 407 - - ✅ Added `ValidateRecordFields()` for record structure validation 408 - - ✅ Added `ValidateCollectionNSID()` for collection name validation 409 - - ✅ Leverages AT Protocol syntax package from indigo for spec-compliant validation 410 - - ✅ UTF-8 validation and null byte rejection 411 - - ✅ Deep nesting prevention (max 10 levels) to prevent memory exhaustion 412 - - ✅ Comprehensive error types: ErrHandleInvalid, ErrTextTooLong, ErrInvalidUTF8, etc. 413 - - ✅ Created validation_test.go with 36 comprehensive test cases 414 - - ✅ Updated `LoginHandler` to validate handle format before OAuth flow 415 - - ✅ Updated `CreatePost` to validate text before API call 416 - - ✅ Updated `CreateRecord` to validate collection NSID and record fields 417 - - ✅ Updated web-demo `postHandler` to validate post text client-side 418 - - ✅ Updated web-demo `createOngakuHandler` to validate text field (1000 char limit) 419 - - ✅ All validation functions exported for use by library consumers 420 - - ✅ Comprehensive README documentation with usage examples 421 - - ✅ Test count increased from 127 to 193 tests (66 new validation tests) 422 - 423 - **Validation Features:** 424 - - **Handles**: Max 253 chars, segments max 63 chars, valid characters (a-z, 0-9, hyphen) 425 - - **Post Text**: Max 300 chars (AT Protocol spec), UTF-8 validated, no null bytes 426 - - **Custom Records**: Configurable limits, datetime validation, nesting prevention 427 - - **Collection NSIDs**: Validated using AT Protocol syntax package 428 - 429 - **Example Usage:** 430 - ```go 431 - // Validate handle 432 - if err := bskyoauth.ValidateHandle("alice.bsky.social"); err != nil { 433 - return err 434 - } 435 - 436 - // Validate post text 437 - if err := bskyoauth.ValidatePostText("Hello, world!"); err != nil { 438 - return err 439 - } 440 - 441 - // Validate custom field 442 - if err := bskyoauth.ValidateTextField(text, "description", 500); err != nil { 443 - return err 444 - } 445 - ``` 446 - 447 - **Impact:** Prevents injection attacks, resource exhaustion, and API errors. Provides early validation with clear error messages. 448 - 449 - --- 450 - 451 - ### 10. Missing Security Headers ✅ **COMPLETED** 452 - **File:** [securityheaders.go](securityheaders.go), [securityheaders_test.go](securityheaders_test.go), [examples/web-demo/main.go](examples/web-demo/main.go) 453 - 454 - **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 455 - 456 - **Issue:** No security headers middleware in main library: 457 - - No Content-Security-Policy 458 - - No X-Frame-Options 459 - - No X-Content-Type-Options 460 - - No Strict-Transport-Security 461 - 462 - **Implementation:** 463 - - ✅ Created `SecurityHeadersMiddleware()` in main library (securityheaders.go) 464 - - ✅ Automatic localhost detection from HTTP request's Host header 465 - - ✅ Localhost CSP: Relaxed with 'unsafe-inline' and 'unsafe-eval' for development 466 - - ✅ Production CSP: Strict with no unsafe directives, includes frame-ancestors 'none' 467 - - ✅ HSTS: Automatically enabled for HTTPS in production (never for localhost) 468 - - ✅ HTTPS detection via r.TLS or X-Forwarded-Proto header 469 - - ✅ Zero configuration required - works automatically from HTTP request 470 - - ✅ Handles reverse proxies, Docker, and cloud platforms automatically 471 - - ✅ Comprehensive test suite (securityheaders_test.go) with 13 test cases 472 - - ✅ Applied to web-demo example with single line of code 473 - - ✅ Documentation added to README.md with usage examples 474 - - ✅ CHANGELOG.md updated with technical details 475 - 476 - **Headers Applied:** 477 - - **Content-Security-Policy**: Environment-aware (relaxed localhost, strict production) 478 - - **X-Frame-Options**: DENY (prevents clickjacking) 479 - - **X-Content-Type-Options**: nosniff (prevents MIME-sniffing attacks) 480 - - **Strict-Transport-Security**: HTTPS production only (not localhost) 481 - - **X-XSS-Protection**: 1; mode=block 482 - - **Referrer-Policy**: strict-origin-when-cross-origin 483 - 484 - **How It Works:** 485 - ```go 486 - // Simply wrap your handler 487 - mux := http.NewServeMux() 488 - // ... set up handlers ... 489 - handler := bskyoauth.SecurityHeadersMiddleware()(mux) 490 - http.ListenAndServe(":8080", handler) 491 - ``` 492 - 493 - **Localhost Detection:** 494 - - Checks r.Host for: `localhost`, `127.0.0.1`, `[::1]`, `0.0.0.0` 495 - - Handles IPv6 addresses with brackets correctly 496 - - Strips port numbers for detection 497 - 498 - **Test Coverage:** 499 - - Localhost detection tests (IPv4, IPv6, ports) 500 - - CSP policy tests (localhost vs production) 501 - - HSTS tests (HTTP, HTTPS, localhost) 502 - - Header application tests (all headers present) 503 - - Handler execution tests (middleware doesn't break handlers) 504 - 505 - **Impact:** All library users get security headers automatically. Localhost-friendly development with production-ready security. Works in any deployment scenario without configuration. 506 - 507 - --- 508 - 509 - ### 11. Insufficient Logging and Monitoring ✅ **COMPLETED** 510 - **Files:** Multiple locations (oauth.go, session.go, client.go, ratelimit.go, logger.go, logger_test.go) 511 - 512 - **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 513 - 514 - **Issue:** Limited security event logging: 515 - - No failed login attempt logging 516 - - No session lifecycle events 517 - - No suspicious activity monitoring 518 - 519 - **Implementation:** 520 - - ✅ Added comprehensive structured logging using Go's standard `log/slog` package 521 - - ✅ Environment-based configuration (Info for localhost, Error for production) 522 - - ✅ Silent by default (logs to `io.Discard` unless explicitly configured) 523 - - ✅ Automatic format selection: Text for development, JSON for production 524 - - ✅ Context-aware logging with request ID and session ID correlation 525 - - ✅ Security event logging throughout the codebase: 526 - - OAuth flow: start/completion, token exchange, DPoP nonce retries 527 - - Session management: creation, retrieval, deletion, expiration, cleanup 528 - - API operations: post creation, record operations, failures 529 - - Rate limiting: exceeded limits, cleanup operations 530 - - ✅ Security events logged at ERROR level: 531 - - Issuer mismatch attacks 532 - - Invalid OAuth states 533 - - Token exchange failures 534 - - No valid session errors 535 - - ✅ New logger functions: 536 - - `SetLogger()` - Configure global logger 537 - - `NewLoggerFromEnv()` - One-line setup with environment detection 538 - - `LogLevelFromEnv()` - Detect log level from BASE_URL 539 - - `NewDefaultLogger()` - JSON logger with custom level 540 - - `NewTextLogger()` - Text logger with custom level 541 - - ✅ Context helpers for correlation: 542 - - `WithRequestID()` - Add request ID to context 543 - - `WithSessionID()` - Add session ID to context 544 - - `LoggerFromContext()` - Retrieve logger from context 545 - - `GenerateRequestID()` - Generate unique request ID 546 - - ✅ Comprehensive test coverage (11 new tests in logger_test.go) 547 - - ✅ Documentation added to README.md with examples 548 - - ✅ All tests passing (193 total tests) 549 - 550 - **Logging Levels:** 551 - - **Debug**: Rate limit checks passed, session retrieval details 552 - - **Info**: OAuth flow events, session lifecycle, API operations 553 - - **Warn**: Failed lookups, invalid inputs, rate limit exceeded 554 - - **Error**: Security events, critical failures, authentication errors 555 - 556 - **Example Usage:** 557 - ```go 558 - // Automatic environment-based setup 559 - logger := bskyoauth.NewLoggerFromEnv(os.Getenv("BASE_URL")) 560 - bskyoauth.SetLogger(logger) 561 - 562 - // Manual configuration 563 - logger := bskyoauth.NewDefaultLogger(slog.LevelError) // JSON, Error level 564 - bskyoauth.SetLogger(logger) 565 - 566 - // Context-aware logging 567 - ctx := bskyoauth.WithRequestID(r.Context(), bskyoauth.GenerateRequestID()) 568 - ctx = bskyoauth.WithSessionID(ctx, sessionID) 569 - session, err := client.CompleteAuthFlow(ctx, code, state, iss) 570 - // Logs include request_id and session_id fields 571 - ``` 572 - 573 - **Impact:** Enables security incident detection and investigation. Provides request correlation through IDs. Environment-aware configuration for development and production. Zero external dependencies using Go standard library. 574 - 575 - --- 576 - 577 - ### 12. Refresh Token Not Implemented ✅ **COMPLETED** 578 - **Files:** oauth.go, types.go, client.go, token_test.go 579 - 580 - **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 581 - 582 - **Issue:** Refresh token is stored but never used. Access tokens will expire requiring full re-authentication. 583 - 584 - **Implementation:** 585 - - ✅ Added `RefreshToken()` method to exchange refresh tokens for new access tokens 586 - - ✅ Added token expiration tracking to `Session` struct: 587 - - `AccessTokenExpiresAt time.Time` - When access token expires 588 - - `RefreshTokenExpiresAt time.Time` - When refresh token expires (optional) 589 - - ✅ Token expiration automatically parsed from OAuth token responses in `CompleteAuthFlow()` 590 - - ✅ Added token expiration helper methods: 591 - - `IsAccessTokenExpired(buffer time.Duration)` - Check if token expired or will expire soon 592 - - `IsRefreshTokenExpired()` - Check if refresh token expired 593 - - `TimeUntilAccessTokenExpiry()` - Get duration until expiration 594 - - ✅ Added `UpdateSession()` method to update sessions after refresh 595 - - ✅ DPoP binding maintained across token refresh (same DPoP key used) 596 - - ✅ Single-use refresh tokens per AT Protocol spec (old token invalidated after use) 597 - - ✅ Added `refreshTokenRequest()` helper with DPoP nonce retry support 598 - - ✅ Comprehensive logging throughout refresh process: 599 - - Token expiration parsing 600 - - Refresh initiation and completion 601 - - Error conditions (no token, expired token, network errors) 602 - - ✅ 6 new test cases in token_test.go: 603 - - `TestIsAccessTokenExpired` (5 sub-cases) 604 - - `TestIsRefreshTokenExpired` (3 sub-cases) 605 - - `TestTimeUntilAccessTokenExpiry` (3 sub-cases) 606 - - `TestUpdateSession` 607 - - `TestRefreshToken_NoRefreshToken` 608 - - `TestRefreshToken_ExpiredRefreshToken` 609 - - ✅ Full documentation in README with examples 610 - - ✅ Zero breaking changes - all additions backwards compatible 216 + All completed issues have been archived to [COMPLETED_ISSUES.md](COMPLETED_ISSUES.md) to keep this TODO focused on active work. 611 217 612 - **Key Features:** 613 - - **Manual Refresh**: Call `RefreshToken()` when tokens expire 614 - - **Expiration Checking**: Helper methods to check token status 615 - - **Error Handling**: Clear errors for expired/missing tokens 616 - - **AT Protocol Compliance**: Single-use tokens, DPoP binding maintained 617 - - **Flexible**: No expiration data? Methods assume tokens valid 618 - 619 - **Example Usage:** 620 - ```go 621 - // Check if token needs refresh 622 - if session.IsAccessTokenExpired(5 * time.Minute) { 623 - newSession, err := client.RefreshToken(ctx, session) 624 - if err != nil { 625 - // Refresh failed - redirect to login 626 - return redirectToLogin(w, r) 627 - } 628 - 629 - // Update session in store 630 - client.UpdateSession(sessionID, newSession) 631 - session = newSession 632 - } 633 - 634 - // Use refreshed session 635 - client.CreatePost(ctx, session, "Hello!") 636 - ``` 637 - 638 - **Impact:** Users no longer need to re-authenticate when access tokens expire. Improves user experience and enables shorter-lived access tokens for better security. 639 - 640 - --- 641 - 642 - ### 13. Add Context Timeout Handling ✅ **COMPLETED** 643 - **Files:** oauth.go, client.go, errors.go, timeout_test.go, errors_test.go 644 - 645 - **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 646 - 647 - **Issue:** HTTP requests lacked explicit timeout configurations, potentially causing indefinite hangs. 648 - 649 - **Implementation:** 650 - - ✅ Added `defaultHTTPClient` with comprehensive timeout configuration: 651 - - Total request timeout: 30 seconds 652 - - Connection timeout: 10 seconds (TCP handshake) 653 - - TLS handshake timeout: 10 seconds 654 - - Response header timeout: 10 seconds 655 - - Idle connection reuse: 90 seconds 656 - - Connection pooling: Max 100 idle connections, 10 per host 657 - - ✅ Replaced all `http.Get()` calls with context-aware `http.NewRequestWithContext()`: 658 - - 3 occurrences in `StartAuthFlow()`, `CompleteAuthFlow()`, and `RefreshToken()` 659 - - All requests now respect context cancellation and timeouts 660 - - ✅ Updated all `http.NewRequest()` calls to use context: 661 - - 2 main requests and 2 retry requests in token exchange functions 662 - - Proper error handling for request creation failures 663 - - ✅ Added `SetHTTPClient()` and `GetHTTPClient()` for global HTTP client configuration 664 - - ✅ Added `HTTPClient` field to `ClientOptions` for per-client timeout customization 665 - - ✅ Created `errors.go` with `IsTimeoutError()` helper function: 666 - - Detects `context.DeadlineExceeded` 667 - - Detects `net.Error` with `Timeout() == true` 668 - - Detects `os.ErrDeadlineExceeded` 669 - - Supports wrapped errors 670 - - ✅ Added timeout-specific error logging throughout OAuth flow 671 - - ✅ 10 comprehensive test cases: 672 - - `TestHTTPClientTimeout` - Verifies HTTP timeout behavior 673 - - `TestContextCancellation` - Tests context cancellation handling 674 - - `TestSetHTTPClient` / `TestGetHTTPClient` - Tests client configuration 675 - - `TestClientOptionsWithHTTPClient` - Tests per-client configuration 676 - - `TestIsTimeoutError_*` - 5 tests for timeout error detection 677 - - `TestDefaultHTTPClientSettings` - Validates default timeout values 678 - - ✅ Full documentation in README with examples for: 679 - - Custom HTTP client timeouts 680 - - Context-based per-request timeouts 681 - - Testing with custom timeouts 682 - - Timeout error detection 683 - - ✅ Zero breaking changes - all additions backwards compatible with sensible defaults 684 - 685 - **Key Features:** 686 - - **Automatic Timeouts**: All requests have 30s default timeout 687 - - **Configurable**: Set custom HTTP client globally or per-client 688 - - **Context-Aware**: Respect context cancellation and deadlines 689 - - **Error Detection**: Easy identification of timeout errors 690 - - **Connection Pooling**: Efficient connection reuse 691 - 692 - **Example Usage:** 693 - ```go 694 - // Custom timeout for specific client 695 - customClient := &http.Client{Timeout: 10 * time.Second} 696 - client := bskyoauth.NewClientWithOptions(bskyoauth.ClientOptions{ 697 - BaseURL: "https://myapp.com", 698 - HTTPClient: customClient, 699 - }) 700 - 701 - // Context timeout for specific request 702 - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 703 - defer cancel() 704 - 705 - flowState, err := client.StartAuthFlow(ctx, handle) 706 - if err != nil { 707 - if bskyoauth.IsTimeoutError(err) { 708 - log.Println("Request timed out") 709 - } 710 - } 711 - ``` 712 - 713 - **Impact:** Prevents indefinite hangs from unresponsive servers or network issues. Improves reliability and enables better error handling for production deployments. 714 - 715 - --- 716 - 717 - ### 14. Dependency Security Scanning ✅ **COMPLETED** 718 - **Files:** .github/dependabot.yml, .github/workflows/security.yml 719 - 720 - **Status:** FIXED - See [CHANGELOG.md](CHANGELOG.md) for details 721 - 722 - **Issue:** No automated dependency vulnerability scanning. 723 - 724 - **Implementation:** 725 - - ✅ Added Dependabot configuration (.github/dependabot.yml): 726 - - Weekly Go module dependency updates (Mondays at 9am Pacific) 727 - - Groups minor and patch updates together to reduce PR noise 728 - - Maximum 5 open PRs to keep review manageable 729 - - Auto-labels PRs with "dependencies" and "go" 730 - - Auto-rebase strategy for conflict resolution 731 - - Commit message prefix: "deps" 732 - - ✅ Added GitHub Actions security workflow (.github/workflows/security.yml): 733 - - Runs `govulncheck` for vulnerability scanning 734 - - Executes on push, pull requests, and weekly schedule 735 - - Test suite with race detection (-race flag) 736 - - Coverage reporting to Codecov 737 - - Uses Go version from go.mod for consistency 738 - - ✅ Scheduled weekly security scans (Mondays at 9am Pacific) 739 - - ✅ Automatic monitoring of security advisories via Dependabot 740 - 741 - **Key Features:** 742 - - **Automated Updates**: Weekly dependency update PRs 743 - - **Vulnerability Scanning**: govulncheck integration in CI/CD 744 - - **Smart Grouping**: Minor/patch updates grouped to reduce noise 745 - - **Test Coverage**: Full test suite runs on all security checks 746 - - **Zero Maintenance**: Fully automated, no manual intervention needed 747 - 748 - **Example Workflow:** 749 - 1. Dependabot checks for updates every Monday 750 - 2. Creates PR with grouped dependency updates 751 - 3. Security workflow runs automatically 752 - 4. govulncheck scans for vulnerabilities 753 - 5. Tests run with race detection 754 - 6. Review and merge PR if checks pass 755 - 756 - **Impact:** Proactive security monitoring ensures vulnerabilities are detected quickly. Automated updates keep dependencies current with minimal maintenance overhead. 218 + For implementation details, see [CHANGELOG.md](CHANGELOG.md). 757 219
+94 -1
VERSION.md
··· 9 9 - **Minor version (v1.x.0)**: New features, non-breaking enhancements 10 10 - **Patch version (v1.0.x)**: Bug fixes, documentation updates, internal improvements 11 11 12 - ## Current Version: v1.0.0 12 + ## Current Version: v1.1.4 13 + 14 + ### v1.1.4 (2025-10-29) 15 + 16 + **Documentation maintenance release** - Archived completed TODO issues 17 + 18 + #### Changes 19 + - Archived all completed security issues from TODO.md to new COMPLETED_ISSUES.md 20 + - Reduced TODO.md from 757 lines to 220 lines (71% reduction) 21 + - Improved TODO.md focus by keeping only active work items 22 + - Added cross-reference links between TODO.md and COMPLETED_ISSUES.md 23 + - Preserved historical documentation of all completed security improvements 24 + 25 + #### Impact 26 + - **Documentation**: Cleaner, more actionable TODO list 27 + - **Maintainability**: Easier to identify pending work vs completed issues 28 + - **Historical Record**: All completed work preserved in COMPLETED_ISSUES.md 29 + - **Zero functional changes**: Documentation-only release 30 + 31 + --- 32 + 33 + ### v1.1.3 (2025-10-29) 34 + 35 + **Maintenance release** - Removed empty jwt.go file 36 + 37 + #### Changes 38 + - Removed empty jwt.go file (only contained package declaration) 39 + - Updated CHANGELOG.md references to clarify JWT code is in internal/jwt 40 + - Updated TODO.md to note JWT functionality is internal-only per AT Protocol spec 41 + - Clarified that access tokens are treated as opaque per specification 42 + 43 + #### Impact 44 + - **Code Cleanup**: Removed unnecessary empty file 45 + - **Documentation**: Clearer guidance on JWT handling 46 + - **No Breaking Changes**: JWT verification remains available in internal/jwt package 47 + 48 + --- 49 + 50 + ### v1.1.2 (2025-10-29) 51 + 52 + **Minor feature release** - Display record ID in web demo 53 + 54 + #### Features 55 + - Added record ID display in web-demo after creating custom records 56 + - New success page shows AT URI and rkey immediately after creation 57 + - Added quick action buttons: View Record (JSON), Delete Record, Create Another 58 + - New utility function `extractRkeyFromURI()` for parsing record keys 59 + - Improved user experience by eliminating need to check server logs 60 + 61 + #### Web Demo Enhancements 62 + - Eliminated redirect after record creation 63 + - Display full AT URI: `at://did:plc:abc.../com.demo.bskyoauth/rkey` 64 + - Copyable record key (rkey) with user-select CSS 65 + - One-click access to view and delete newly created records 66 + - Styled success page matching existing web-demo design 67 + 68 + #### Impact 69 + - **User Experience**: Immediate feedback on record creation 70 + - **Usability**: Easy access to record operations 71 + - **No Breaking Changes**: Only affects web-demo example, library unchanged 72 + 73 + --- 74 + 75 + ### v1.1.1 (2025-10-29) 76 + 77 + **Minor feature release** - Lexicon support for custom records 78 + 79 + #### Features 80 + - Added proper AT Protocol lexicon support for custom record types 81 + - Created `lexicon` package with `DemoRecord` type 82 + - Implemented CBOR marshaling/unmarshaling for custom records 83 + - Added lexicon JSON schema at `lexicons/com/demo/bskyoauth.json` 84 + - Automatic type registration with indigo library via `init()` 85 + - Field validation for lexicon records (text length, timestamps) 86 + 87 + #### New Files 88 + - `lexicon/demo.go` - DemoRecord type with CBOR methods 89 + - `lexicon/validation.go` - Field validation for DemoRecord 90 + - `lexicon/demo_test.go` - Comprehensive test coverage (15+ tests) 91 + - `lexicons/com/demo/bskyoauth.json` - AT Protocol lexicon schema 92 + 93 + #### Changes 94 + - Updated `client.go` with blank import to trigger lexicon registration 95 + - Updated `internal/api/client.go` with lexicon registration 96 + - Updated `examples/web-demo/main.go` to use typed `DemoRecord` 97 + - GetRecord now works with custom lexicon types 98 + 99 + #### Impact 100 + - **Correctness**: Proper AT Protocol lexicon implementation 101 + - **Type Safety**: Typed records instead of generic maps 102 + - **Validation**: Built-in field validation for custom records 103 + - **No Breaking Changes**: Existing code continues to work 104 + 105 + --- 13 106 14 107 ### v1.0.0 (2025-10-29) 15 108