Skip to content

Commit

Permalink
refactor(auth): integrate UrlManagerService for URL management
Browse files Browse the repository at this point in the history
Replace manual URL handling with UrlManagerService across authentication and other core modules. This centralization improves maintainability and consistency by consolidating URL construction logic into a dedicated service.
  • Loading branch information
AMoreaux committed Nov 25, 2024
1 parent 0d41daf commit c782207
Show file tree
Hide file tree
Showing 34 changed files with 498 additions and 187 deletions.
1 change: 0 additions & 1 deletion packages/twenty-e2e-testing/drivers/env_variables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import path from 'path';
export const envVariables = (variables: string) => {
let payload = `
PG_DATABASE_URL=postgres://postgres:twenty@localhost:5432/default
FRONT_BASE_URL=http://localhost:3001
ACCESS_TOKEN_SECRET=replace_me_with_a_random_string_access
LOGIN_TOKEN_SECRET=replace_me_with_a_random_string_login
REFRESH_TOKEN_SECRET=replace_me_with_a_random_string_refresh
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ import { parseCoreBatchPath } from 'src/engine/api/rest/core/query-builder/utils
import { parseCorePath } from 'src/engine/api/rest/core/query-builder/utils/path-parsers/parse-core-path.utils';
import { Query } from 'src/engine/api/rest/core/types/query.type';
import { AccessTokenService } from 'src/engine/core-modules/auth/token/services/access-token.service';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service';
import { UrlManagerService } from 'src/engine/core-modules/url-manager/service/url-manager.service';

@Injectable()
export class CoreQueryBuilderFactory {
Expand All @@ -40,7 +40,7 @@ export class CoreQueryBuilderFactory {
private readonly findDuplicatesVariablesFactory: FindDuplicatesVariablesFactory,
private readonly objectMetadataService: ObjectMetadataService,
private readonly accessTokenService: AccessTokenService,
private readonly environmentService: EnvironmentService,
private readonly urlManagerService: UrlManagerService,
) {}

async getObjectMetadata(
Expand All @@ -58,9 +58,12 @@ export class CoreQueryBuilderFactory {

if (!objectMetadataItems.length) {
throw new BadRequestException(
`No object was found for the workspace associated with this API key. You may generate a new one here ${this.environmentService.get(
'FRONT_BASE_URL',
)}/settings/developers`,
`No object was found for the workspace associated with this API key. You may generate a new one here ${this.urlManagerService
.buildWorkspaceURL({
subdomain: workspace.subdomain,
pathname: '/settings/developers',
})
.toString()}`,
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import { CoreQueryBuilderFactory } from 'src/engine/api/rest/core/query-builder/
import { coreQueryBuilderFactories } from 'src/engine/api/rest/core/query-builder/factories/factories';
import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module';
import { AuthModule } from 'src/engine/core-modules/auth/auth.module';
import { UrlManagerModule } from 'src/engine/core-modules/url-manager/url-manager.module';

@Module({
imports: [ObjectMetadataModule, AuthModule],
imports: [ObjectMetadataModule, AuthModule, UrlManagerModule],
providers: [...coreQueryBuilderFactories, CoreQueryBuilderFactory],
exports: [CoreQueryBuilderFactory],
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/works
import { WorkspaceManagerModule } from 'src/engine/workspace-manager/workspace-manager.module';
import { ConnectedAccountModule } from 'src/modules/connected-account/connected-account.module';
import { SignUpAuthController } from 'src/engine/core-modules/auth/controllers/sign-up-auth.controller';
import { UrlManagerModule } from 'src/engine/core-modules/url-manager/url-manager.module';

import { AuthResolver } from './auth.resolver';

Expand All @@ -53,6 +54,7 @@ import { JwtAuthStrategy } from './strategies/jwt.auth.strategy';
JwtModule,
FileUploadModule,
DataSourceModule,
UrlManagerModule,
forwardRef(() => UserModule),
WorkspaceManagerModule,
TypeORMModule,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ import {
AuthExceptionCode,
} from 'src/engine/core-modules/auth/auth.exception';
import { OriginHeader } from 'src/engine/decorators/auth/origin-header.decorator';
import { getWorkspaceSubdomainByOrigin } from 'src/engine/utils/get-workspace-subdomain-by-origin';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
import { AvailableWorkspaceOutput } from 'src/engine/core-modules/auth/dto/available-workspaces.output';
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';
import { UrlManagerService } from 'src/engine/core-modules/url-manager/service/url-manager.service';

import { ChallengeInput } from './dto/challenge.input';
import { ImpersonateInput } from './dto/impersonate.input';
Expand Down Expand Up @@ -69,7 +69,7 @@ export class AuthResolver {
private switchWorkspaceService: SwitchWorkspaceService,
private transientTokenService: TransientTokenService,
private oauthService: OAuthService,
private environmentService: EnvironmentService,
private urlManagementService: UrlManagerService,
) {}

@UseGuards(CaptchaGuard)
Expand Down Expand Up @@ -128,14 +128,8 @@ export class AuthResolver {
): Promise<LoginToken> {
const user = await this.authService.signInUp({
...signUpInput,
targetWorkspaceSubdomain: this.environmentService.get(
'IS_MULTIWORKSPACE_ENABLED',
)
? getWorkspaceSubdomainByOrigin(
origin,
this.environmentService.get('FRONT_BASE_URL'),
)
: undefined,
targetWorkspaceSubdomain:
this.urlManagementService.getWorkspaceSubdomainByOrigin(origin),
fromSSO: false,
isAuthEnabled: workspaceValidator.isAuthEnabled(
'password',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,8 @@ import { TransientTokenService } from 'src/engine/core-modules/auth/token/servic
import { GoogleAPIsRequest } from 'src/engine/core-modules/auth/types/google-api-request.type';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service';
import { buildWorkspaceURL } from 'src/utils/workspace-url.utils';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { WorkspaceService } from 'src/engine/core-modules/workspace/services/workspace.service';
import { UrlManagerService } from 'src/engine/core-modules/url-manager/service/url-manager.service';

@Controller('auth/google-apis')
@UseFilters(AuthRestApiExceptionFilter)
Expand All @@ -35,7 +34,7 @@ export class GoogleAPIsAuthController {
private readonly transientTokenService: TransientTokenService,
private readonly environmentService: EnvironmentService,
private readonly onboardingService: OnboardingService,
private readonly workspaceService: WorkspaceService,
private readonly urlManagerService: UrlManagerService,
@InjectRepository(Workspace, 'core')
private readonly workspaceRepository: Repository<Workspace>,
) {}
Expand Down Expand Up @@ -116,11 +115,12 @@ export class GoogleAPIsAuthController {
}

return res.redirect(
buildWorkspaceURL(
this.environmentService.get('FRONT_BASE_URL'),
this.workspaceService.getSubdomainIfMultiworkspaceEnabled(workspace),
{ withPathname: redirectLocation || '/settings/accounts' },
).toString(),
this.urlManagerService
.buildWorkspaceURL({
subdomain: workspace.subdomain,
pathname: redirectLocation || '/settings/accounts',
})
.toString(),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@ import {
AuthExceptionCode,
} from 'src/engine/core-modules/auth/auth.exception';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
import { computeRedirectErrorUrl } from 'src/engine/core-modules/auth/utils/compute-redirect-error-url';
import { WorkspaceService } from 'src/engine/core-modules/workspace/services/workspace.service';
import { UrlManagerService } from 'src/engine/core-modules/url-manager/service/url-manager.service';
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';

@Controller('auth/google')
@UseFilters(AuthRestApiExceptionFilter)
export class GoogleAuthController {
constructor(
private readonly loginTokenService: LoginTokenService,
private readonly authService: AuthService,
private readonly workspaceService: WorkspaceService,
private readonly urlManagerService: UrlManagerService,
private readonly environmentService: EnvironmentService,
) {}

Expand Down Expand Up @@ -87,11 +87,8 @@ export class GoogleAuthController {
} catch (err) {
if (err instanceof AuthException) {
return res.redirect(
computeRedirectErrorUrl({
frontBaseUrl: this.environmentService.get('FRONT_BASE_URL'),
subdomain: this.environmentService.get('IS_MULTIWORKSPACE_ENABLED')
? 'app'
: null,
this.urlManagerService.computeRedirectErrorUrl({
subdomain: this.environmentService.get('DEFAULT_SUBDOMAIN'),
errorMessage: err.message,
}),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ import { TransientTokenService } from 'src/engine/core-modules/auth/token/servic
import { MicrosoftAPIsRequest } from 'src/engine/core-modules/auth/types/microsoft-api-request.type';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service';
import { buildWorkspaceURL } from 'src/utils/workspace-url.utils';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { WorkspaceService } from 'src/engine/core-modules/workspace/services/workspace.service';
import { UrlManagerService } from 'src/engine/core-modules/url-manager/service/url-manager.service';

@Controller('auth/microsoft-apis')
@UseFilters(AuthRestApiExceptionFilter)
Expand All @@ -35,6 +35,7 @@ export class MicrosoftAPIsAuthController {
private readonly transientTokenService: TransientTokenService,
private readonly environmentService: EnvironmentService,
private readonly workspaceService: WorkspaceService,
private readonly urlManagerService: UrlManagerService,
private readonly onboardingService: OnboardingService,
@InjectRepository(Workspace, 'core')
private readonly workspaceRepository: Repository<Workspace>,
Expand Down Expand Up @@ -116,11 +117,12 @@ export class MicrosoftAPIsAuthController {
}

return res.redirect(
buildWorkspaceURL(
this.environmentService.get('FRONT_BASE_URL'),
this.workspaceService.getSubdomainIfMultiworkspaceEnabled(workspace),
{ withPathname: redirectLocation || '/settings/accounts' },
).toString(),
this.urlManagerService
.buildWorkspaceURL({
subdomain: workspace.subdomain,
pathname: redirectLocation || '/settings/accounts',
})
.toString(),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@ import {
AuthException,
AuthExceptionCode,
} from 'src/engine/core-modules/auth/auth.exception';
import { computeRedirectErrorUrl } from 'src/engine/core-modules/auth/utils/compute-redirect-error-url';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
import { WorkspaceService } from 'src/engine/core-modules/workspace/services/workspace.service';
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';
import { UrlManagerService } from 'src/engine/core-modules/url-manager/service/url-manager.service';

@Controller('auth/microsoft')
@UseFilters(AuthRestApiExceptionFilter)
export class MicrosoftAuthController {
constructor(
private readonly loginTokenService: LoginTokenService,
private readonly authService: AuthService,
private readonly workspaceService: WorkspaceService,
private readonly urlManagerService: UrlManagerService,
private readonly environmentService: EnvironmentService,
) {}

Expand Down Expand Up @@ -86,15 +86,15 @@ export class MicrosoftAuthController {
),
);
} catch (err) {
return res.redirect(
computeRedirectErrorUrl({
frontBaseUrl: this.environmentService.get('FRONT_BASE_URL'),
subdomain: this.environmentService.get('IS_MULTIWORKSPACE_ENABLED')
? 'app'
: null,
errorMessage: err.message,
}),
);
if (err instanceof AuthException) {
return res.redirect(
this.urlManagerService.computeRedirectErrorUrl({
subdomain: this.environmentService.get('DEFAULT_SUBDOMAIN'),
errorMessage: err.message,
}),
);
}
throw err;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,19 @@ import {
AuthException,
AuthExceptionCode,
} from 'src/engine/core-modules/auth/auth.exception';
import { buildWorkspaceURL } from 'src/utils/workspace-url.utils';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
import { isDefined } from 'src/utils/is-defined';
import { AccessTokenService } from 'src/engine/core-modules/auth/token/services/access-token.service';
import ServerUrl from 'src/engine/utils/serverUrl';
import { WorkspaceService } from 'src/engine/core-modules/workspace/services/workspace.service';
import { UrlManagerService } from 'src/engine/core-modules/url-manager/service/url-manager.service';

@Controller('auth/redirect')
@UseFilters(AuthRestApiExceptionFilter)
export class SignUpAuthController {
constructor(
private readonly accessTokenService: AccessTokenService,
private readonly authService: AuthService,
private readonly workspaceService: WorkspaceService,
private readonly environmentService: EnvironmentService,
private readonly authService: AuthService,
private readonly urlManagerService: UrlManagerService,
) {}

@Get()
Expand Down Expand Up @@ -50,20 +48,17 @@ export class SignUpAuthController {

const { tokens } = await this.authService.verify(user.email, workspace.id);

const redirectUrl = buildWorkspaceURL(
this.environmentService.get('FRONT_BASE_URL'),
this.workspaceService.getSubdomainIfMultiworkspaceEnabled(
user.defaultWorkspace,
),
);
const redirectUrl = this.urlManagerService.buildWorkspaceURL({
subdomain: workspace.subdomain,
});

res.cookie(
`${workspace.subdomain ?? 'twentyRoot'}TokenPair`,
JSON.stringify(tokens),
{
expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 7), // 1 week
domain: `.${redirectUrl.hostname}`,
secure: new URL(ServerUrl.get()).protocol === 'https:',
secure: this.environmentService.get('FRONT_PROTOCOL') === 'https',
},
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,17 @@ import {
} from 'src/engine/core-modules/sso/workspace-sso-identity-provider.entity';
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
import { WorkspaceInvitationService } from 'src/engine/core-modules/workspace-invitation/services/workspace-invitation.service';
import { WorkspaceService } from 'src/engine/core-modules/workspace/services/workspace.service';
import { UrlManagerService } from 'src/engine/core-modules/url-manager/service/url-manager.service';

@Controller('auth')
@UseFilters(AuthRestApiExceptionFilter)
export class SSOAuthController {
constructor(
private readonly loginTokenService: LoginTokenService,
private readonly authService: AuthService,
private readonly urlManagerService: UrlManagerService,
private readonly workspaceInvitationService: WorkspaceInvitationService,
private readonly userWorkspaceService: UserWorkspaceService,
private readonly workspaceService: WorkspaceService,
private readonly ssoService: SSOService,
@InjectRepository(WorkspaceSSOIdentityProvider, 'core')
private readonly workspaceSSOIdentityProviderRepository: Repository<WorkspaceSSOIdentityProvider>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ import {
AuthException,
AuthExceptionCode,
} from 'src/engine/core-modules/auth/auth.exception';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
import { UrlManagerService } from 'src/engine/core-modules/url-manager/service/url-manager.service';

@Catch(AuthException)
export class AuthOAuthExceptionFilter implements ExceptionFilter {
constructor(private readonly environmentService: EnvironmentService) {}
constructor(private readonly urlManagerService: UrlManagerService) {}

catch(exception: AuthException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
Expand All @@ -25,7 +25,7 @@ export class AuthOAuthExceptionFilter implements ExceptionFilter {
case AuthExceptionCode.OAUTH_ACCESS_DENIED:
response
.status(403)
.redirect(this.environmentService.get('FRONT_BASE_URL'));
.redirect(this.urlManagerService.getBaseUrl().toString());
break;
default:
throw new InternalServerErrorException(exception.message);
Expand Down
Loading

0 comments on commit c782207

Please sign in to comment.