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:
parent
0a3d4bb345
commit
afe39f6f46
6 changed files with 46 additions and 6 deletions
|
@ -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']);
|
||||
|
||||
|
|
|
@ -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>({});
|
||||
|
|
|
@ -119,7 +119,7 @@ describe('submit action', () => {
|
|||
id: 'uid',
|
||||
...upsertProfile,
|
||||
},
|
||||
[]
|
||||
['user']
|
||||
);
|
||||
expect(assignInteractionResults).toBeCalledWith(ctx, tenant.provider, {
|
||||
login: { accountId: 'uid' },
|
||||
|
|
|
@ -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 } });
|
||||
|
|
5
packages/core/src/utils/array.ts
Normal file
5
packages/core/src/utils/array.ts
Normal 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));
|
19
packages/shared/src/env/GlobalValues.ts
vendored
19
packages/shared/src/env/GlobalValues.ts
vendored
|
@ -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'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue