0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2024-12-16 20:26:19 -05:00

refactor: fix cloud dev (#3281)

This commit is contained in:
Gao Sun 2023-03-03 19:04:22 +08:00 committed by GitHub
parent 0a3d4bb345
commit afe39f6f46
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 46 additions and 6 deletions

View file

@ -16,7 +16,9 @@ import { log } from '../../../utils.js';
export const appendAdminConsoleRedirectUris = async (pool: CommonQueryMethods) => {
const redirectUris = new GlobalValues().cloudUrlSet
.deduplicated()
.map((endpoint) => appendPath(endpoint, defaultTenantId, 'callback'));
.flatMap((endpoint) =>
[defaultTenantId, adminTenantId].map((tenantId) => appendPath(endpoint, tenantId, 'callback'))
);
const metadataKey = sql.identifier(['oidc_client_metadata']);

View file

@ -11,8 +11,12 @@ type Props = {
};
export type AppEndpoints = {
/**
* The Logto endpoint for the current tenant.
*
* Always use this value as the base URL when referring to the Logto URL of the current user's tenant.
*/
userEndpoint?: URL;
adminEndpoint?: URL;
};
export const AppEndpointsContext = createContext<AppEndpoints>({});

View file

@ -119,7 +119,7 @@ describe('submit action', () => {
id: 'uid',
...upsertProfile,
},
[]
['user']
);
expect(assignInteractionResults).toBeCalledWith(ctx, tenant.provider, {
login: { accountId: 'uid' },

View file

@ -10,11 +10,13 @@ import {
} from '@logto/schemas';
import { conditional } from '@silverhand/essentials';
import { EnvSet } from '#src/env-set/index.js';
import type { ConnectorLibrary } from '#src/libraries/connector.js';
import { assignInteractionResults } from '#src/libraries/session.js';
import { encryptUserPassword } from '#src/libraries/user.js';
import type { LogEntry } from '#src/middleware/koa-audit-log.js';
import type TenantContext from '#src/tenants/TenantContext.js';
import { conditionalArray } from '#src/utils/array.js';
import { getTenantId } from '#src/utils/tenant.js';
import type { WithInteractionDetailsContext } from '../middleware/koa-interaction-details.js';
@ -166,8 +168,10 @@ export default async function submitInteraction(
const { client_id } = ctx.interactionDetails.params;
const { isCloud } = EnvSet.values;
const isInAdminTenant = getTenantId(ctx.URL) === adminTenantId;
const isCreatingFirstAdminUser =
getTenantId(ctx.URL) === adminTenantId &&
isInAdminTenant &&
String(client_id) === adminConsoleApplicationId &&
!(await hasActiveUsers());
@ -176,13 +180,19 @@ export default async function submitInteraction(
id,
...upsertProfile,
},
isCreatingFirstAdminUser ? [UserRole.User, getManagementApiAdminName(defaultTenantId)] : []
conditionalArray<string>(
isInAdminTenant && UserRole.User,
isCreatingFirstAdminUser && getManagementApiAdminName(defaultTenantId),
isCreatingFirstAdminUser && isCloud && getManagementApiAdminName(adminTenantId)
)
);
// In OSS, we need to limit sign-in experience to "sign-in only" once
// the first admin has been create since we don't want other unexpected registrations
if (isCreatingFirstAdminUser) {
await updateDefaultSignInExperience({ signInMode: SignInMode.SignIn });
await updateDefaultSignInExperience({
signInMode: isCloud ? SignInMode.SignInAndRegister : SignInMode.SignIn,
});
}
await assignInteractionResults(ctx, provider, { login: { accountId: id } });

View file

@ -0,0 +1,5 @@
import type { Falsy } from '@silverhand/essentials';
import { notFalsy } from '@silverhand/essentials';
export const conditionalArray = <T>(...exp: Array<T | Falsy>): T[] =>
exp.filter((value): value is Exclude<T, Falsy> => notFalsy(value));

View file

@ -57,6 +57,8 @@ export default class GlobalValues {
public readonly isDomainBasedMultiTenancy = this.urlSet.endpoint.hostname.includes('*');
/**
* **NOTE: This is an internal dev-only feature.**
*
* This value indicates path-based multi-tenancy (PBMT) is enabled by setting env variable `PATH_BASED_MULTI_TENANCY` to a truthy value.
*
* Note the value will always be `false` if domain-based multi-tenancy is enabled.
@ -85,6 +87,9 @@ export default class GlobalValues {
return this.isDomainBasedMultiTenancy || this.isPathBasedMultiTenancy;
}
/** If the env explicitly indicates it's in the cloud environment. */
public readonly isCloud = yes(getEnv('IS_CLOUD'));
// eslint-disable-next-line unicorn/consistent-function-scoping
public readonly databaseUrl = tryThat(() => assertEnv('DB_URL'), throwErrorWithDsnMessage);
public readonly developmentTenantId = getEnv('DEVELOPMENT_TENANT_ID');
@ -100,4 +105,18 @@ export default class GlobalValues {
public get endpoint(): URL {
return this.urlSet.endpoint;
}
constructor() {
if (this.isPathBasedMultiTenancy) {
console.warn(
'\n****** LOGTO WARNING ******\n\n' +
'Path-based multi-tenancy is an internal dev-only feature. It is unstable and not intended for production use.\n\n' +
'Known issues:\n\n' +
'- Sign-in experience is unavailable in user tenants.\n' +
'- The Admin Console may display incorrect user endpoints on multiple pages, such as guide, config, etc.' +
' This issue is caused by the native URL constructor new URL(), which overrides the base pathname.\n\n' +
'****** END LOGTO WARNING ******\n'
);
}
}
}