add new plan
This commit is contained in:
parent
4e78dade64
commit
8dc6b5d849
228
readme.plan.md
228
readme.plan.md
@ -6,6 +6,21 @@
|
||||
## Overview
|
||||
Simplify the ACME/Certificate system by consolidating components, removing unnecessary abstraction layers, and integrating directly into SmartProxy's route-based architecture.
|
||||
|
||||
## Core Principles
|
||||
1. **No backward compatibility** - Clean break from legacy implementations
|
||||
2. **No migration helpers** - Users must update to new configuration format
|
||||
3. **Remove all legacy code** - Delete deprecated methods and interfaces
|
||||
4. **Forward-only approach** - Focus on simplicity over compatibility
|
||||
5. **No complexity for edge cases** - Only support the clean, new way
|
||||
|
||||
## Key Discoveries from Implementation Analysis
|
||||
|
||||
1. **SmartProxy already supports static routes** - The 'static' type exists in TRouteActionType
|
||||
2. **Path-based routing works perfectly** - The route matching system handles paths with glob patterns
|
||||
3. **Dynamic route updates are safe** - SmartProxy's updateRoutes() method handles changes gracefully
|
||||
4. **Priority-based routing exists** - Routes are sorted by priority, ensuring ACME routes match first
|
||||
5. **No separate HTTP server needed** - ACME challenges can be regular SmartProxy routes
|
||||
|
||||
## Current State Analysis
|
||||
|
||||
### Files to be Removed/Replaced
|
||||
@ -353,10 +368,12 @@ export class SmartCertManager {
|
||||
|
||||
/**
|
||||
* Create ACME challenge route
|
||||
* NOTE: SmartProxy already handles path-based routing and priority
|
||||
*/
|
||||
private createChallengeRoute(): IRouteConfig {
|
||||
return {
|
||||
name: 'acme-challenge',
|
||||
priority: 1000, // High priority to ensure it's checked first
|
||||
match: {
|
||||
ports: 80,
|
||||
path: '/.well-known/acme-challenge/*'
|
||||
@ -656,7 +673,7 @@ export class CertStore {
|
||||
```
|
||||
|
||||
|
||||
### Phase 2: Update Route Types
|
||||
### Phase 2: Update Route Types and Handler
|
||||
|
||||
#### 2.1 Update route-types.ts
|
||||
```typescript
|
||||
@ -683,6 +700,7 @@ export interface IStaticResponse {
|
||||
|
||||
/**
|
||||
* Update IRouteAction to support static handlers
|
||||
* NOTE: The 'static' type already exists in TRouteActionType
|
||||
*/
|
||||
export interface IRouteAction {
|
||||
type: TRouteActionType;
|
||||
@ -694,6 +712,16 @@ export interface IRouteAction {
|
||||
handler?: (context: IRouteContext) => Promise<IStaticResponse>; // For static routes
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend IRouteConfig to ensure challenge routes have higher priority
|
||||
*/
|
||||
export interface IRouteConfig {
|
||||
name?: string;
|
||||
match: IRouteMatch;
|
||||
action: IRouteAction;
|
||||
priority?: number; // Already exists - ACME routes should use high priority
|
||||
}
|
||||
|
||||
/**
|
||||
* Extended TLS configuration for route actions
|
||||
*/
|
||||
@ -714,6 +742,101 @@ export interface IRouteTls {
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.2 Add Static Route Handler
|
||||
```typescript
|
||||
// Add to ts/proxies/smart-proxy/route-connection-handler.ts
|
||||
|
||||
/**
|
||||
* Handle the route based on its action type
|
||||
*/
|
||||
switch (route.action.type) {
|
||||
case 'forward':
|
||||
return this.handleForwardAction(socket, record, route, initialChunk);
|
||||
|
||||
case 'redirect':
|
||||
return this.handleRedirectAction(socket, record, route);
|
||||
|
||||
case 'block':
|
||||
return this.handleBlockAction(socket, record, route);
|
||||
|
||||
case 'static':
|
||||
return this.handleStaticAction(socket, record, route);
|
||||
|
||||
default:
|
||||
console.log(`[${connectionId}] Unknown action type: ${(route.action as any).type}`);
|
||||
socket.end();
|
||||
this.connectionManager.cleanupConnection(record, 'unknown_action');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a static action for a route
|
||||
*/
|
||||
private async handleStaticAction(
|
||||
socket: plugins.net.Socket,
|
||||
record: IConnectionRecord,
|
||||
route: IRouteConfig
|
||||
): Promise<void> {
|
||||
const connectionId = record.id;
|
||||
|
||||
if (!route.action.handler) {
|
||||
console.error(`[${connectionId}] Static route '${route.name}' has no handler`);
|
||||
socket.end();
|
||||
this.connectionManager.cleanupConnection(record, 'no_handler');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Build route context
|
||||
const context: IRouteContext = {
|
||||
port: record.localPort,
|
||||
domain: record.lockedDomain,
|
||||
clientIp: record.remoteIP,
|
||||
serverIp: socket.localAddress!,
|
||||
path: record.path, // Will need to be extracted from HTTP request
|
||||
isTls: record.isTLS,
|
||||
tlsVersion: record.tlsVersion,
|
||||
routeName: route.name,
|
||||
routeId: route.name,
|
||||
timestamp: Date.now(),
|
||||
connectionId
|
||||
};
|
||||
|
||||
// Call the handler
|
||||
const response = await route.action.handler(context);
|
||||
|
||||
// Send HTTP response
|
||||
const headers = response.headers || {};
|
||||
headers['Content-Length'] = Buffer.byteLength(response.body).toString();
|
||||
|
||||
let httpResponse = `HTTP/1.1 ${response.status} ${getStatusText(response.status)}\r\n`;
|
||||
for (const [key, value] of Object.entries(headers)) {
|
||||
httpResponse += `${key}: ${value}\r\n`;
|
||||
}
|
||||
httpResponse += '\r\n';
|
||||
|
||||
socket.write(httpResponse);
|
||||
socket.write(response.body);
|
||||
socket.end();
|
||||
|
||||
this.connectionManager.cleanupConnection(record, 'completed');
|
||||
} catch (error) {
|
||||
console.error(`[${connectionId}] Error in static handler: ${error}`);
|
||||
socket.end();
|
||||
this.connectionManager.cleanupConnection(record, 'handler_error');
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function for status text
|
||||
function getStatusText(status: number): string {
|
||||
const statusTexts: Record<number, string> = {
|
||||
200: 'OK',
|
||||
404: 'Not Found',
|
||||
500: 'Internal Server Error'
|
||||
};
|
||||
return statusTexts[status] || 'Unknown';
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 3: SmartProxy Integration
|
||||
|
||||
#### 3.1 Update SmartProxy class
|
||||
@ -1033,49 +1156,9 @@ export class NetworkProxyBridge {
|
||||
}
|
||||
```
|
||||
|
||||
### Phase 4: Migration Guide
|
||||
### Phase 4: Configuration Examples (No Migration)
|
||||
|
||||
#### 4.1 Configuration Migration
|
||||
```typescript
|
||||
// Old configuration style
|
||||
const proxy = new SmartProxy({
|
||||
acme: {
|
||||
enabled: true,
|
||||
accountEmail: 'admin@example.com',
|
||||
useProduction: true,
|
||||
certificateStore: './certs'
|
||||
},
|
||||
routes: [{
|
||||
match: { ports: 443, domains: 'example.com' },
|
||||
action: {
|
||||
type: 'forward',
|
||||
target: { host: 'backend', port: 8080 },
|
||||
tls: { mode: 'terminate', certificate: 'auto' }
|
||||
}
|
||||
}]
|
||||
});
|
||||
|
||||
// New configuration style
|
||||
const proxy = new SmartProxy({
|
||||
routes: [{
|
||||
match: { ports: 443, domains: 'example.com' },
|
||||
action: {
|
||||
type: 'forward',
|
||||
target: { host: 'backend', port: 8080 },
|
||||
tls: {
|
||||
mode: 'terminate',
|
||||
certificate: 'auto',
|
||||
acme: {
|
||||
email: 'admin@example.com',
|
||||
useProduction: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}]
|
||||
});
|
||||
```
|
||||
|
||||
#### 4.2 Test Migration
|
||||
#### 4.1 New Configuration Format ONLY
|
||||
```typescript
|
||||
// Update test files to use new structure
|
||||
// test/test.certificate-provisioning.ts
|
||||
@ -1282,6 +1365,17 @@ sed -i '/port80\//d' ts/http/index.ts
|
||||
# sed -i '/smartexpress/d' ts/plugins.ts
|
||||
```
|
||||
|
||||
#### 6.2 Key Simplifications Achieved
|
||||
|
||||
1. **No custom ACME wrapper** - Direct use of @push.rocks/smartacme
|
||||
2. **No separate HTTP server** - ACME challenges are regular routes
|
||||
3. **Built-in path routing** - SmartProxy already handles path-based matching
|
||||
4. **Built-in priorities** - Routes are already sorted by priority
|
||||
5. **Safe updates** - Route updates are already thread-safe
|
||||
6. **Minimal new code** - Mostly configuration and integration
|
||||
|
||||
The simplification leverages SmartProxy's existing capabilities rather than reinventing them.
|
||||
|
||||
#### 6.2 Update Package.json
|
||||
```json
|
||||
{
|
||||
@ -1304,10 +1398,10 @@ sed -i '/port80\//d' ts/http/index.ts
|
||||
- Simplify NetworkProxyBridge
|
||||
- Remove old certificate system
|
||||
|
||||
3. **Day 3: Testing & Migration**
|
||||
- Migrate existing tests
|
||||
- Create new integration tests
|
||||
- Test migration scenarios
|
||||
3. **Day 3: Testing**
|
||||
- Create new tests using new format only
|
||||
- No migration testing needed
|
||||
- Test all new functionality
|
||||
|
||||
4. **Day 4: Documentation & Cleanup**
|
||||
- Update all documentation
|
||||
@ -1316,17 +1410,33 @@ sed -i '/port80\//d' ts/http/index.ts
|
||||
|
||||
## Risk Mitigation
|
||||
|
||||
1. **Backward Compatibility**
|
||||
- Create migration helper to convert old configs
|
||||
- Deprecation warnings for old methods
|
||||
- Phased rollout with feature flags
|
||||
1. **Static Route Handler**
|
||||
- Already exists in the type system
|
||||
- Just needs implementation in route-connection-handler.ts
|
||||
- Low risk as it follows existing patterns
|
||||
|
||||
2. **Testing Strategy**
|
||||
- Unit tests for each new component
|
||||
- Integration tests for full workflow
|
||||
- Migration tests for existing deployments
|
||||
2. **Route Updates During Operation**
|
||||
- SmartProxy's updateRoutes() is already thread-safe
|
||||
- Sequential processing prevents race conditions
|
||||
- Challenge routes are added/removed atomically
|
||||
|
||||
3. **Rollback Plan**
|
||||
- Keep old certificate module in separate branch
|
||||
- Document rollback procedures
|
||||
- Test rollback scenarios
|
||||
3. **Port 80 Conflicts**
|
||||
- Priority-based routing ensures ACME routes match first
|
||||
- Path-based matching (`/.well-known/acme-challenge/*`) is specific
|
||||
- Other routes on port 80 won't interfere
|
||||
|
||||
4. **Error Recovery**
|
||||
- SmartAcme initialization failures are handled gracefully
|
||||
- Null checks prevent crashes if ACME isn't available
|
||||
- Routes continue to work without certificates
|
||||
|
||||
5. **Testing Strategy**
|
||||
- Test concurrent ACME challenges
|
||||
- Test route priority conflicts
|
||||
- Test certificate renewal during high traffic
|
||||
- Test the new configuration format only
|
||||
|
||||
6. **No Migration Path**
|
||||
- Breaking change is intentional
|
||||
- Old configurations must be manually updated
|
||||
- No compatibility shims or helpers provided
|
Loading…
x
Reference in New Issue
Block a user