feat(server): support multiple hosts in one deployment (#12950)

close CLOUD-233



#### PR Dependency Tree


* **PR #12950** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added support for configuring multiple server hosts across backend and
frontend settings.
* Enhanced deployment and Helm chart configuration to allow specifying
multiple ingress hosts.
* Updated admin and configuration interfaces to display and manage
multiple server hosts.

* **Improvements**
* Improved URL generation, OAuth, and worker service logic to
dynamically handle requests from multiple hosts.
  * Enhanced captcha verification to support multiple allowed hostnames.
* Updated frontend logic for platform-specific server base URLs and
allowed origins, including Apple app domains.
  * Expanded test coverage for multi-host scenarios.

* **Bug Fixes**
* Corrected backend logic to consistently use dynamic base URLs and
origins based on request host context.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
fengmk2
2025-06-27 17:41:37 +08:00
committed by GitHub
parent 5c45c66ce8
commit dc55518c5b
21 changed files with 214 additions and 43 deletions
@@ -37,6 +37,10 @@ test.before(async t => {
},
},
},
server: {
hosts: ['localhost', 'test.affine.dev'],
https: true,
},
}),
AppModule,
],
@@ -90,6 +94,38 @@ test("should be able to redirect to oauth provider's login page", async t => {
);
});
test('should be able to redirect to oauth provider with multiple hosts', async t => {
const { app } = t.context;
const res = await app
.POST('/api/oauth/preflight')
.set('host', 'test.affine.dev')
.send({ provider: 'Google' })
.expect(HttpStatus.OK);
const { url } = res.body;
const redirect = new URL(url);
t.is(redirect.origin, 'https://accounts.google.com');
t.is(redirect.pathname, '/o/oauth2/v2/auth');
t.is(redirect.searchParams.get('client_id'), 'google-client-id');
t.is(
redirect.searchParams.get('redirect_uri'),
'https://test.affine.dev/oauth/callback'
);
t.is(redirect.searchParams.get('response_type'), 'code');
t.is(redirect.searchParams.get('prompt'), 'select_account');
t.truthy(redirect.searchParams.get('state'));
// state should be a json string
const state = JSON.parse(redirect.searchParams.get('state')!);
t.is(state.provider, 'Google');
t.regex(
state.state,
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/
);
});
test('should be able to redirect to oauth provider with client_nonce', async t => {
const { app } = t.context;