feat: add Queue-based async server provisioning

- Add Cloudflare Queue for async server provisioning workflow
- Implement VPS provider abstraction (Linode, Vultr)
- Add provisioning API endpoints with API key authentication
- Fix race condition in balance deduction (atomic query)
- Remove root_password from Queue for security (fetch from DB)
- Add IP assignment wait logic after server creation
- Add rollback/refund on all failure cases

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
kappa
2026-01-27 17:19:19 +09:00
parent 8c543eeaa5
commit 9b51b8d427
12 changed files with 1796 additions and 5 deletions

View File

@@ -36,6 +36,36 @@ export function jsonResponse<T>(
});
}
/**
* Create error response
*/
export function createErrorResponse(
message: string,
status: number,
code?: string,
corsHeaders: Record<string, string> = {}
): Response {
return jsonResponse(
{
error: message,
code: code || 'ERROR',
},
status,
corsHeaders
);
}
/**
* Create success response
*/
export function createSuccessResponse<T>(
data: T,
status: number = 200,
corsHeaders: Record<string, string> = {}
): Response {
return jsonResponse(data, status, corsHeaders);
}
/**
* Helper function to get allowed CORS origin
*/
@@ -61,3 +91,34 @@ export function getAllowedOrigin(request: Request): string {
// Browser will block the response due to CORS mismatch
return allowedOrigins[0];
}
/**
* Validate request origin for sensitive endpoints (e.g., provision)
* Only allows requests from *.kappa-d8e.workers.dev or worker-to-worker calls
*/
export function isAllowedProvisionOrigin(request: Request): boolean {
const origin = request.headers.get('Origin');
const referer = request.headers.get('Referer');
// Allow worker-to-worker calls (Cloudflare adds this header)
// Note: This header indicates the request came from another Cloudflare Worker
const cfWorker = request.headers.get('CF-Worker');
if (cfWorker) {
return true;
}
// If no Origin header (server-to-server, curl, etc.) - check Referer or allow
// For strict mode, you might want to reject these too
if (!origin) {
// Check Referer as fallback
if (referer && referer.includes('.kappa-d8e.workers.dev')) {
return true;
}
// Allow server-to-server for now (can be made stricter with API key)
return true;
}
// Check if Origin is from allowed domain
const allowedPattern = /^https:\/\/[a-zA-Z0-9-]+\.kappa-d8e\.workers\.dev$/;
return allowedPattern.test(origin);
}

View File

@@ -7,7 +7,8 @@
export {
escapeHtml,
jsonResponse,
getAllowedOrigin
getAllowedOrigin,
isAllowedProvisionOrigin
} from './http';
// Validation utilities (type guards, request validation)