mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-05 16:37:46 +00:00
feat: change default listen port from 3000 to 1852 (#756)
Updates the backend listen port, Vite dev proxy target, Docker EXPOSE, compose port mapping, .env.example default, GitHub Actions smoke-test default, healthcheck URLs, and every doc/example reference. Test fixtures that include example URLs were updated for consistency, though their assertions are port-agnostic. The rate-limit value of 3000 in middleware/rateLimiters.ts and the 3000 entry in WEB_UI_PORTS (which detects user containers like Grafana) are intentionally untouched.
This commit is contained in:
@@ -63,7 +63,7 @@ describe('POST /api/nodes - api_url SSRF validation (C2 fix)', () => {
|
||||
.send({
|
||||
name: 'lan-node',
|
||||
type: 'remote',
|
||||
api_url: 'http://192.168.1.50:3000',
|
||||
api_url: 'http://192.168.1.50:1852',
|
||||
api_token: 'sometoken',
|
||||
});
|
||||
// Should succeed (201 or 200) - not a validation error
|
||||
|
||||
@@ -1185,7 +1185,7 @@ describe('SchedulerService - executeUpdateRemote', () => {
|
||||
it('proxies update execution to remote node', async () => {
|
||||
mockGetNode.mockReturnValue({ id: 2, name: 'remote', type: 'remote', status: 'online' });
|
||||
mockGetProxyTarget.mockReturnValue({
|
||||
apiUrl: 'http://remote:3000',
|
||||
apiUrl: 'http://remote:1852',
|
||||
apiToken: 'test-token',
|
||||
});
|
||||
|
||||
@@ -1211,7 +1211,7 @@ describe('SchedulerService - executeUpdateRemote', () => {
|
||||
await svc.triggerTask(88);
|
||||
|
||||
expect(mockFetch).toHaveBeenCalledWith(
|
||||
'http://remote:3000/api/auto-update/execute',
|
||||
'http://remote:1852/api/auto-update/execute',
|
||||
expect.objectContaining({
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ target: 'web-app' }),
|
||||
@@ -1226,7 +1226,7 @@ describe('SchedulerService - executeUpdateRemote', () => {
|
||||
it('records failure when remote node returns error', async () => {
|
||||
mockGetNode.mockReturnValue({ id: 2, name: 'remote', type: 'remote', status: 'online' });
|
||||
mockGetProxyTarget.mockReturnValue({
|
||||
apiUrl: 'http://remote:3000',
|
||||
apiUrl: 'http://remote:1852',
|
||||
apiToken: 'test-token',
|
||||
});
|
||||
|
||||
|
||||
@@ -210,11 +210,11 @@ describe('TemplateService', () => {
|
||||
it('handles values with special characters', () => {
|
||||
const result = service.generateEnvString({
|
||||
PASSWORD: 'p@ss=word!',
|
||||
URL: 'http://localhost:3000',
|
||||
URL: 'http://localhost:1852',
|
||||
});
|
||||
|
||||
expect(result).toContain('PASSWORD=p@ss=word!');
|
||||
expect(result).toContain('URL=http://localhost:3000');
|
||||
expect(result).toContain('URL=http://localhost:1852');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -568,7 +568,7 @@ describe('Orphaned role assignment cleanup', () => {
|
||||
it('deleting a node removes its role assignments', async () => {
|
||||
const db = DatabaseService.getInstance();
|
||||
// Create a test node
|
||||
const nodeId = db.addNode({ name: 'test-cleanup-node', type: 'remote', api_url: 'http://test:3000', api_token: '', compose_dir: '/tmp', is_default: false });
|
||||
const nodeId = db.addNode({ name: 'test-cleanup-node', type: 'remote', api_url: 'http://test:1852', api_token: '', compose_dir: '/tmp', is_default: false });
|
||||
// Create a role assignment for this node
|
||||
const hash = await bcrypt.hash('password123', 1);
|
||||
const userId = db.addUser({ username: 'nodeorphan', password_hash: hash, role: 'viewer' });
|
||||
|
||||
@@ -63,7 +63,7 @@ describe('isValidStackName', () => {
|
||||
|
||||
describe('isValidRemoteUrl', () => {
|
||||
it('accepts valid http URLs', () => {
|
||||
const result = isValidRemoteUrl('http://192.168.1.10:3000');
|
||||
const result = isValidRemoteUrl('http://192.168.1.10:1852');
|
||||
expect(result.valid).toBe(true);
|
||||
});
|
||||
|
||||
@@ -84,25 +84,25 @@ describe('isValidRemoteUrl', () => {
|
||||
});
|
||||
|
||||
it('rejects localhost', () => {
|
||||
expect(isValidRemoteUrl('http://localhost:3000').valid).toBe(false);
|
||||
expect(isValidRemoteUrl('http://LOCALHOST:3000').valid).toBe(false);
|
||||
expect(isValidRemoteUrl('http://localhost:1852').valid).toBe(false);
|
||||
expect(isValidRemoteUrl('http://LOCALHOST:1852').valid).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects loopback IPs', () => {
|
||||
expect(isValidRemoteUrl('http://127.0.0.1:3000').valid).toBe(false);
|
||||
expect(isValidRemoteUrl('http://127.0.0.1:1852').valid).toBe(false);
|
||||
expect(isValidRemoteUrl('http://127.1.2.3').valid).toBe(false);
|
||||
// Node.js URL.hostname preserves brackets: new URL('http://[::1]').hostname === '[::1]'
|
||||
expect(isValidRemoteUrl('http://[::1]:3000').valid).toBe(false);
|
||||
expect(isValidRemoteUrl('http://[::1]:1852').valid).toBe(false);
|
||||
});
|
||||
|
||||
it('rejects 0.0.0.0', () => {
|
||||
expect(isValidRemoteUrl('http://0.0.0.0:3000').valid).toBe(false);
|
||||
expect(isValidRemoteUrl('http://0.0.0.0:1852').valid).toBe(false);
|
||||
});
|
||||
|
||||
it('allows LAN/private IPs (users need these for local network nodes)', () => {
|
||||
// Users legitimately run Sencho nodes on their LAN
|
||||
expect(isValidRemoteUrl('http://192.168.1.100:3000').valid).toBe(true);
|
||||
expect(isValidRemoteUrl('http://10.0.0.5:3000').valid).toBe(true);
|
||||
expect(isValidRemoteUrl('http://192.168.1.100:1852').valid).toBe(true);
|
||||
expect(isValidRemoteUrl('http://10.0.0.5:1852').valid).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// monolith.
|
||||
|
||||
// Server
|
||||
export const PORT = 3000;
|
||||
export const PORT = 1852;
|
||||
|
||||
// Password policy
|
||||
export const MIN_PASSWORD_LENGTH = 8;
|
||||
|
||||
@@ -37,7 +37,7 @@ function mintPilotEnrollment(nodeId: number, req: Request): { token: string; exp
|
||||
const forwardedProto = req.headers['x-forwarded-proto'];
|
||||
const protoHeader = Array.isArray(forwardedProto) ? forwardedProto[0] : forwardedProto;
|
||||
const protocol = protoHeader || req.protocol || 'http';
|
||||
const host = req.get('host') || 'localhost:3000';
|
||||
const host = req.get('host') || 'localhost:1852';
|
||||
const primaryUrl = `${protocol}://${host}`;
|
||||
|
||||
const dockerRun =
|
||||
|
||||
@@ -22,7 +22,7 @@ export function isValidRemoteUrl(
|
||||
console.warn('[Validation] URL parse failure:', (e as Error).message, '— input:', raw);
|
||||
return {
|
||||
valid: false,
|
||||
reason: 'API URL must be a valid URL (e.g. https://my-server.example.com:3000)',
|
||||
reason: 'API URL must be a valid URL (e.g. https://my-server.example.com:1852)',
|
||||
};
|
||||
}
|
||||
if (!['http:', 'https:'].includes(url.protocol)) {
|
||||
|
||||
Reference in New Issue
Block a user