Fix workspace hydratation (#12452)
We must separate the concept of hydratation which happens at the request level (take the token and pass auth/user context), from the concept of authorization which happens at the query/endpoint/mutation level. Previously, hydratation exemption happened at the operation name level which is not correct because the operation name is meaningless and optional. Still this gave an impression of security by enforcing a blacklist. So in this PR we introduce linting rule that aim to achieve a similar behavior, now every api method has to have a guard. That way if and endpoint is not protected by AuthUserGuard or AuthWorspaceGuard, then it has to be stated explicitly next to its code. --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
import { UseFilters } from '@nestjs/common';
|
||||
import { UseFilters, UseGuards } from '@nestjs/common';
|
||||
import { Args, Mutation, Resolver } from '@nestjs/graphql';
|
||||
|
||||
import { AuditExceptionFilter } from 'src/engine/core-modules/audit/audit-exception-filter';
|
||||
@ -11,6 +11,8 @@ import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator';
|
||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
||||
import { PublicEndpointGuard } from 'src/engine/guards/public-endpoint.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
|
||||
import {
|
||||
CreateAnalyticsInputV2,
|
||||
@ -29,13 +31,14 @@ export class AuditResolver {
|
||||
async createPageview(
|
||||
@Args()
|
||||
createAnalyticsInput: CreateAnalyticsInputV2,
|
||||
@AuthWorkspace() workspace: Workspace | undefined,
|
||||
@AuthWorkspace({ allowUndefined: true }) workspace: Workspace | undefined,
|
||||
@AuthUser({ allowUndefined: true }) user: User | undefined,
|
||||
) {
|
||||
return this.trackAnalytics(createAnalyticsInput, workspace, user);
|
||||
}
|
||||
|
||||
@Mutation(() => Analytics)
|
||||
@UseGuards(WorkspaceAuthGuard)
|
||||
async createObjectEvent(
|
||||
@Args()
|
||||
createObjectEventInput: CreateObjectEventInput,
|
||||
@ -63,10 +66,11 @@ export class AuditResolver {
|
||||
}
|
||||
|
||||
@Mutation(() => Analytics)
|
||||
@UseGuards(PublicEndpointGuard)
|
||||
async trackAnalytics(
|
||||
@Args()
|
||||
createAnalyticsInput: CreateAnalyticsInputV2,
|
||||
@AuthWorkspace() workspace: Workspace | undefined,
|
||||
@AuthWorkspace({ allowUndefined: true }) workspace: Workspace | undefined,
|
||||
@AuthUser({ allowUndefined: true }) user: User | undefined,
|
||||
) {
|
||||
const analyticsContext = this.auditService.createContext({
|
||||
|
||||
@ -49,6 +49,7 @@ import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';
|
||||
import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator';
|
||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
||||
import { PublicEndpointGuard } from 'src/engine/guards/public-endpoint.guard';
|
||||
import { SettingsPermissionsGuard } from 'src/engine/guards/settings-permissions.guard';
|
||||
import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
@ -94,7 +95,7 @@ export class AuthResolver {
|
||||
private sSOService: SSOService,
|
||||
) {}
|
||||
|
||||
@UseGuards(CaptchaGuard)
|
||||
@UseGuards(CaptchaGuard, PublicEndpointGuard)
|
||||
@Query(() => UserExistsOutput)
|
||||
async checkUserExists(
|
||||
@Args() checkUserExistsInput: CheckUserExistsInput,
|
||||
@ -105,6 +106,7 @@ export class AuthResolver {
|
||||
}
|
||||
|
||||
@Mutation(() => GetAuthorizationUrlForSSOOutput)
|
||||
@UseGuards(PublicEndpointGuard)
|
||||
async getAuthorizationUrlForSSO(
|
||||
@Args('input') params: GetAuthorizationUrlForSSOInput,
|
||||
) {
|
||||
@ -115,6 +117,7 @@ export class AuthResolver {
|
||||
}
|
||||
|
||||
@Query(() => WorkspaceInviteHashValid)
|
||||
@UseGuards(PublicEndpointGuard)
|
||||
async checkWorkspaceInviteHashIsValid(
|
||||
@Args() workspaceInviteHashValidInput: WorkspaceInviteHashValidInput,
|
||||
): Promise<WorkspaceInviteHashValid> {
|
||||
@ -124,6 +127,7 @@ export class AuthResolver {
|
||||
}
|
||||
|
||||
@Query(() => Workspace)
|
||||
@UseGuards(PublicEndpointGuard)
|
||||
async findWorkspaceFromInviteHash(
|
||||
@Args() workspaceInviteHashValidInput: WorkspaceInviteHashValidInput,
|
||||
): Promise<Workspace> {
|
||||
@ -132,7 +136,7 @@ export class AuthResolver {
|
||||
);
|
||||
}
|
||||
|
||||
@UseGuards(CaptchaGuard)
|
||||
@UseGuards(CaptchaGuard, PublicEndpointGuard)
|
||||
@Mutation(() => LoginToken)
|
||||
async getLoginTokenFromCredentials(
|
||||
@Args()
|
||||
@ -166,6 +170,7 @@ export class AuthResolver {
|
||||
}
|
||||
|
||||
@Mutation(() => GetLoginTokenFromEmailVerificationTokenOutput)
|
||||
@UseGuards(PublicEndpointGuard)
|
||||
async getLoginTokenFromEmailVerificationToken(
|
||||
@Args()
|
||||
getLoginTokenFromEmailVerificationTokenInput: GetLoginTokenFromEmailVerificationTokenInput,
|
||||
@ -197,7 +202,7 @@ export class AuthResolver {
|
||||
return { loginToken, workspaceUrls };
|
||||
}
|
||||
|
||||
@UseGuards(CaptchaGuard)
|
||||
@UseGuards(CaptchaGuard, PublicEndpointGuard)
|
||||
@Mutation(() => SignUpOutput)
|
||||
async signUp(@Args() signUpInput: SignUpInput): Promise<SignUpOutput> {
|
||||
const currentWorkspace = await this.authService.findWorkspaceForSignInUp({
|
||||
@ -269,6 +274,7 @@ export class AuthResolver {
|
||||
}
|
||||
|
||||
@Mutation(() => SignUpOutput)
|
||||
@UseGuards(UserAuthGuard)
|
||||
async signUpInNewWorkspace(
|
||||
@AuthUser() currentUser: User,
|
||||
): Promise<SignUpOutput> {
|
||||
@ -300,7 +306,7 @@ export class AuthResolver {
|
||||
// }
|
||||
|
||||
@Mutation(() => TransientToken)
|
||||
@UseGuards(WorkspaceAuthGuard, UserAuthGuard)
|
||||
@UseGuards(UserAuthGuard)
|
||||
async generateTransientToken(
|
||||
@AuthUser() user: User,
|
||||
@AuthWorkspace() workspace: Workspace,
|
||||
@ -324,6 +330,7 @@ export class AuthResolver {
|
||||
}
|
||||
|
||||
@Mutation(() => AuthTokens)
|
||||
@UseGuards(PublicEndpointGuard)
|
||||
async getAuthTokensFromLoginToken(
|
||||
@Args() getAuthTokensFromLoginTokenInput: GetAuthTokensFromLoginTokenInput,
|
||||
@Args('origin') origin: string,
|
||||
@ -351,7 +358,7 @@ export class AuthResolver {
|
||||
}
|
||||
|
||||
@Mutation(() => AuthorizeApp)
|
||||
@UseGuards(WorkspaceAuthGuard, UserAuthGuard)
|
||||
@UseGuards(UserAuthGuard)
|
||||
async authorizeApp(
|
||||
@Args() authorizeAppInput: AuthorizeAppInput,
|
||||
@AuthUser() user: User,
|
||||
@ -365,6 +372,7 @@ export class AuthResolver {
|
||||
}
|
||||
|
||||
@Mutation(() => AuthTokens)
|
||||
@UseGuards(PublicEndpointGuard)
|
||||
async renewToken(@Args() args: AppTokenInput): Promise<AuthTokens> {
|
||||
const tokens = await this.renewTokenService.generateTokensFromRefreshToken(
|
||||
args.appToken,
|
||||
@ -390,6 +398,7 @@ export class AuthResolver {
|
||||
}
|
||||
|
||||
@Mutation(() => EmailPasswordResetLink)
|
||||
@UseGuards(PublicEndpointGuard)
|
||||
async emailPasswordResetLink(
|
||||
@Args() emailPasswordResetInput: EmailPasswordResetLinkInput,
|
||||
@Context() context: I18nContext,
|
||||
@ -408,6 +417,7 @@ export class AuthResolver {
|
||||
}
|
||||
|
||||
@Mutation(() => InvalidatePassword)
|
||||
@UseGuards(PublicEndpointGuard)
|
||||
async updatePasswordViaResetToken(
|
||||
@Args()
|
||||
{ passwordResetToken, newPassword }: UpdatePasswordViaResetTokenInput,
|
||||
@ -428,6 +438,7 @@ export class AuthResolver {
|
||||
}
|
||||
|
||||
@Query(() => ValidatePasswordResetToken)
|
||||
@UseGuards(PublicEndpointGuard)
|
||||
async validatePasswordResetToken(
|
||||
@Args() args: ValidatePasswordResetTokenInput,
|
||||
): Promise<ValidatePasswordResetToken> {
|
||||
|
||||
@ -26,6 +26,7 @@ import { GuardRedirectService } from 'src/engine/core-modules/guard-redirect/ser
|
||||
import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { PublicEndpointGuard } from 'src/engine/guards/public-endpoint.guard';
|
||||
|
||||
@Controller('auth/google-apis')
|
||||
@UseFilters(AuthRestApiExceptionFilter)
|
||||
@ -42,14 +43,14 @@ export class GoogleAPIsAuthController {
|
||||
) {}
|
||||
|
||||
@Get()
|
||||
@UseGuards(GoogleAPIsOauthRequestCodeGuard)
|
||||
@UseGuards(GoogleAPIsOauthRequestCodeGuard, PublicEndpointGuard)
|
||||
async googleAuth() {
|
||||
// As this method is protected by Google Auth guard, it will trigger Google SSO flow
|
||||
return;
|
||||
}
|
||||
|
||||
@Get('get-access-token')
|
||||
@UseGuards(GoogleAPIsOauthExchangeCodeForTokenGuard)
|
||||
@UseGuards(GoogleAPIsOauthExchangeCodeForTokenGuard, PublicEndpointGuard)
|
||||
async googleAuthGetAccessToken(
|
||||
@Req() req: GoogleAPIsRequest,
|
||||
@Res() res: Response,
|
||||
|
||||
@ -21,6 +21,7 @@ import { LoginTokenService } from 'src/engine/core-modules/auth/token/services/l
|
||||
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service';
|
||||
import { GuardRedirectService } from 'src/engine/core-modules/guard-redirect/services/guard-redirect.service';
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import { PublicEndpointGuard } from 'src/engine/guards/public-endpoint.guard';
|
||||
|
||||
@Controller('auth/google')
|
||||
@UseFilters(AuthRestApiExceptionFilter)
|
||||
@ -35,14 +36,14 @@ export class GoogleAuthController {
|
||||
) {}
|
||||
|
||||
@Get()
|
||||
@UseGuards(GoogleProviderEnabledGuard, GoogleOauthGuard)
|
||||
@UseGuards(GoogleProviderEnabledGuard, GoogleOauthGuard, PublicEndpointGuard)
|
||||
async googleAuth() {
|
||||
// As this method is protected by Google Auth guard, it will trigger Google SSO flow
|
||||
return;
|
||||
}
|
||||
|
||||
@Get('redirect')
|
||||
@UseGuards(GoogleProviderEnabledGuard, GoogleOauthGuard)
|
||||
@UseGuards(GoogleProviderEnabledGuard, GoogleOauthGuard, PublicEndpointGuard)
|
||||
@UseFilters(AuthOAuthExceptionFilter)
|
||||
async googleAuthRedirect(@Req() req: GoogleRequest, @Res() res: Response) {
|
||||
const {
|
||||
|
||||
@ -26,6 +26,7 @@ import { GuardRedirectService } from 'src/engine/core-modules/guard-redirect/ser
|
||||
import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { PublicEndpointGuard } from 'src/engine/guards/public-endpoint.guard';
|
||||
|
||||
@Controller('auth/microsoft-apis')
|
||||
@UseFilters(AuthRestApiExceptionFilter)
|
||||
@ -42,14 +43,14 @@ export class MicrosoftAPIsAuthController {
|
||||
) {}
|
||||
|
||||
@Get()
|
||||
@UseGuards(MicrosoftAPIsOauthRequestCodeGuard)
|
||||
@UseGuards(MicrosoftAPIsOauthRequestCodeGuard, PublicEndpointGuard)
|
||||
async MicrosoftAuth() {
|
||||
// As this method is protected by Microsoft Auth guard, it will trigger Microsoft SSO flow
|
||||
return;
|
||||
}
|
||||
|
||||
@Get('get-access-token')
|
||||
@UseGuards(MicrosoftAPIsOauthExchangeCodeForTokenGuard)
|
||||
@UseGuards(MicrosoftAPIsOauthExchangeCodeForTokenGuard, PublicEndpointGuard)
|
||||
async MicrosoftAuthGetAccessToken(
|
||||
@Req() req: MicrosoftAPIsRequest,
|
||||
@Res() res: Response,
|
||||
|
||||
@ -20,6 +20,7 @@ import { LoginTokenService } from 'src/engine/core-modules/auth/token/services/l
|
||||
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service';
|
||||
import { GuardRedirectService } from 'src/engine/core-modules/guard-redirect/services/guard-redirect.service';
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import { PublicEndpointGuard } from 'src/engine/guards/public-endpoint.guard';
|
||||
|
||||
@Controller('auth/microsoft')
|
||||
@UseFilters(AuthRestApiExceptionFilter)
|
||||
@ -34,14 +35,22 @@ export class MicrosoftAuthController {
|
||||
) {}
|
||||
|
||||
@Get()
|
||||
@UseGuards(MicrosoftProviderEnabledGuard, MicrosoftOAuthGuard)
|
||||
@UseGuards(
|
||||
MicrosoftProviderEnabledGuard,
|
||||
MicrosoftOAuthGuard,
|
||||
PublicEndpointGuard,
|
||||
)
|
||||
async microsoftAuth() {
|
||||
// As this method is protected by Microsoft Auth guard, it will trigger Microsoft SSO flow
|
||||
return;
|
||||
}
|
||||
|
||||
@Get('redirect')
|
||||
@UseGuards(MicrosoftProviderEnabledGuard, MicrosoftOAuthGuard)
|
||||
@UseGuards(
|
||||
MicrosoftProviderEnabledGuard,
|
||||
MicrosoftOAuthGuard,
|
||||
PublicEndpointGuard,
|
||||
)
|
||||
async microsoftAuthRedirect(
|
||||
@Req() req: MicrosoftRequest,
|
||||
@Res() res: Response,
|
||||
|
||||
@ -38,6 +38,7 @@ import {
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';
|
||||
import { PublicEndpointGuard } from 'src/engine/guards/public-endpoint.guard';
|
||||
|
||||
@Controller('auth')
|
||||
export class SSOAuthController {
|
||||
@ -55,7 +56,7 @@ export class SSOAuthController {
|
||||
) {}
|
||||
|
||||
@Get('saml/metadata/:identityProviderId')
|
||||
@UseGuards(EnterpriseFeaturesEnabledGuard)
|
||||
@UseGuards(EnterpriseFeaturesEnabledGuard, PublicEndpointGuard)
|
||||
@UseFilters(AuthRestApiExceptionFilter)
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
async generateMetadata(@Req() req: any): Promise<string | void> {
|
||||
@ -73,7 +74,7 @@ export class SSOAuthController {
|
||||
}
|
||||
|
||||
@Get('oidc/login/:identityProviderId')
|
||||
@UseGuards(EnterpriseFeaturesEnabledGuard, OIDCAuthGuard)
|
||||
@UseGuards(EnterpriseFeaturesEnabledGuard, OIDCAuthGuard, PublicEndpointGuard)
|
||||
@UseFilters(AuthRestApiExceptionFilter)
|
||||
async oidcAuth() {
|
||||
// As this method is protected by OIDC Auth guard, it will trigger OIDC SSO flow
|
||||
@ -81,7 +82,7 @@ export class SSOAuthController {
|
||||
}
|
||||
|
||||
@Get('saml/login/:identityProviderId')
|
||||
@UseGuards(EnterpriseFeaturesEnabledGuard, SAMLAuthGuard)
|
||||
@UseGuards(EnterpriseFeaturesEnabledGuard, SAMLAuthGuard, PublicEndpointGuard)
|
||||
@UseFilters(AuthRestApiExceptionFilter)
|
||||
async samlAuth() {
|
||||
// As this method is protected by SAML Auth guard, it will trigger SAML SSO flow
|
||||
@ -89,14 +90,14 @@ export class SSOAuthController {
|
||||
}
|
||||
|
||||
@Get('oidc/callback')
|
||||
@UseGuards(EnterpriseFeaturesEnabledGuard, OIDCAuthGuard)
|
||||
@UseGuards(EnterpriseFeaturesEnabledGuard, OIDCAuthGuard, PublicEndpointGuard)
|
||||
@UseFilters(AuthOAuthExceptionFilter)
|
||||
async oidcAuthCallback(@Req() req: OIDCRequest, @Res() res: Response) {
|
||||
return await this.authCallback(req, res);
|
||||
}
|
||||
|
||||
@Post('saml/callback/:identityProviderId')
|
||||
@UseGuards(EnterpriseFeaturesEnabledGuard, SAMLAuthGuard)
|
||||
@UseGuards(EnterpriseFeaturesEnabledGuard, SAMLAuthGuard, PublicEndpointGuard)
|
||||
@UseFilters(AuthOAuthExceptionFilter)
|
||||
async samlAuthCallback(@Req() req: SAMLRequest, @Res() res: Response) {
|
||||
try {
|
||||
|
||||
@ -9,6 +9,7 @@ import {
|
||||
Req,
|
||||
Res,
|
||||
UseFilters,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
|
||||
import { Response } from 'express';
|
||||
@ -29,6 +30,8 @@ import { BillingWebhookInvoiceService } from 'src/engine/core-modules/billing/we
|
||||
import { BillingWebhookPriceService } from 'src/engine/core-modules/billing/webhooks/services/billing-webhook-price.service';
|
||||
import { BillingWebhookProductService } from 'src/engine/core-modules/billing/webhooks/services/billing-webhook-product.service';
|
||||
import { BillingWebhookSubscriptionService } from 'src/engine/core-modules/billing/webhooks/services/billing-webhook-subscription.service';
|
||||
import { PublicEndpointGuard } from 'src/engine/guards/public-endpoint.guard';
|
||||
|
||||
@Controller()
|
||||
@UseFilters(BillingRestApiExceptionFilter)
|
||||
export class BillingController {
|
||||
@ -47,6 +50,7 @@ export class BillingController {
|
||||
) {}
|
||||
|
||||
@Post(['webhooks/stripe'])
|
||||
@UseGuards(PublicEndpointGuard)
|
||||
async handleWebhooks(
|
||||
@Headers('stripe-signature') signature: string,
|
||||
@Req() req: RawBodyRequest<Request>,
|
||||
|
||||
@ -1,13 +1,15 @@
|
||||
import { Controller, Get } from '@nestjs/common';
|
||||
import { Controller, Get, UseGuards } from '@nestjs/common';
|
||||
|
||||
import { ClientConfig } from 'src/engine/core-modules/client-config/client-config.entity';
|
||||
import { ClientConfigService } from 'src/engine/core-modules/client-config/services/client-config.service';
|
||||
import { PublicEndpointGuard } from 'src/engine/guards/public-endpoint.guard';
|
||||
|
||||
@Controller('/client-config')
|
||||
export class ClientConfigController {
|
||||
constructor(private readonly clientConfigService: ClientConfigService) {}
|
||||
|
||||
@Get()
|
||||
@UseGuards(PublicEndpointGuard)
|
||||
async getClientConfig(): Promise<ClientConfig> {
|
||||
return this.clientConfigService.getClientConfig();
|
||||
}
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import { UseGuards } from '@nestjs/common';
|
||||
import { Query, Resolver } from '@nestjs/graphql';
|
||||
|
||||
import { ClientConfigService } from 'src/engine/core-modules/client-config/services/client-config.service';
|
||||
import { PublicEndpointGuard } from 'src/engine/guards/public-endpoint.guard';
|
||||
|
||||
import { ClientConfig } from './client-config.entity';
|
||||
|
||||
@ -9,6 +11,7 @@ export class ClientConfigResolver {
|
||||
constructor(private clientConfigService: ClientConfigService) {}
|
||||
|
||||
@Query(() => ClientConfig)
|
||||
@UseGuards(PublicEndpointGuard)
|
||||
async clientConfig(): Promise<ClientConfig> {
|
||||
return this.clientConfigService.getClientConfig();
|
||||
}
|
||||
|
||||
@ -25,8 +25,8 @@ import { CustomDomainService } from 'src/engine/core-modules/domain-manager/serv
|
||||
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service';
|
||||
import { ExceptionHandlerService } from 'src/engine/core-modules/exception-handler/exception-handler.service';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { PublicEndpointGuard } from 'src/engine/guards/public-endpoint.guard';
|
||||
import { handleException } from 'src/engine/utils/global-exception-handler.util';
|
||||
|
||||
@Controller()
|
||||
@UseFilters(AuthRestApiExceptionFilter)
|
||||
export class CloudflareController {
|
||||
@ -40,7 +40,7 @@ export class CloudflareController {
|
||||
) {}
|
||||
|
||||
@Post(['cloudflare/custom-hostname-webhooks', 'webhooks/cloudflare'])
|
||||
@UseGuards(CloudflareSecretMatchGuard)
|
||||
@UseGuards(CloudflareSecretMatchGuard, PublicEndpointGuard)
|
||||
async customHostnameWebhooks(@Req() req: Request, @Res() res: Response) {
|
||||
if (!req.body?.data?.data?.hostname) {
|
||||
handleException({
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { UseFilters } from '@nestjs/common';
|
||||
import { UseFilters, UseGuards } from '@nestjs/common';
|
||||
import { Args, Context, Mutation, Resolver } from '@nestjs/graphql';
|
||||
|
||||
import { SOURCE_LOCALE } from 'twenty-shared/translations';
|
||||
@ -9,6 +9,7 @@ import { ResendEmailVerificationTokenOutput } from 'src/engine/core-modules/emai
|
||||
import { EmailVerificationExceptionFilter } from 'src/engine/core-modules/email-verification/email-verification-exception-filter.util';
|
||||
import { EmailVerificationService } from 'src/engine/core-modules/email-verification/services/email-verification.service';
|
||||
import { I18nContext } from 'src/engine/core-modules/i18n/types/i18n-context.type';
|
||||
import { PublicEndpointGuard } from 'src/engine/guards/public-endpoint.guard';
|
||||
|
||||
@Resolver()
|
||||
@UseFilters(EmailVerificationExceptionFilter)
|
||||
@ -19,6 +20,7 @@ export class EmailVerificationResolver {
|
||||
) {}
|
||||
|
||||
@Mutation(() => ResendEmailVerificationTokenOutput)
|
||||
@UseGuards(PublicEndpointGuard)
|
||||
async resendEmailVerificationToken(
|
||||
@Args()
|
||||
resendEmailVerificationTokenInput: ResendEmailVerificationTokenInput,
|
||||
|
||||
@ -23,6 +23,7 @@ import { FileApiExceptionFilter } from 'src/engine/core-modules/file/filters/fil
|
||||
import { FilePathGuard } from 'src/engine/core-modules/file/guards/file-path-guard';
|
||||
import { FileService } from 'src/engine/core-modules/file/services/file.service';
|
||||
import { extractFileInfoFromRequest } from 'src/engine/core-modules/file/utils/extract-file-info-from-request.utils';
|
||||
import { PublicEndpointGuard } from 'src/engine/guards/public-endpoint.guard';
|
||||
|
||||
@Controller('files')
|
||||
@UseFilters(FileApiExceptionFilter)
|
||||
@ -31,6 +32,7 @@ export class FileController {
|
||||
constructor(private readonly fileService: FileService) {}
|
||||
|
||||
@Get('*/:filename')
|
||||
@UseGuards(PublicEndpointGuard)
|
||||
async getFile(
|
||||
@Param() params: string[],
|
||||
@Res() res: Response,
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
import { BadRequestException, Controller, Get, Param } from '@nestjs/common';
|
||||
import {
|
||||
BadRequestException,
|
||||
Controller,
|
||||
Get,
|
||||
Param,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { HealthCheck, HealthCheckService } from '@nestjs/terminus';
|
||||
|
||||
import { HealthIndicatorId } from 'src/engine/core-modules/health/enums/health-indicator-id.enum';
|
||||
@ -7,6 +13,8 @@ import { ConnectedAccountHealth } from 'src/engine/core-modules/health/indicator
|
||||
import { DatabaseHealthIndicator } from 'src/engine/core-modules/health/indicators/database.health';
|
||||
import { RedisHealthIndicator } from 'src/engine/core-modules/health/indicators/redis.health';
|
||||
import { WorkerHealthIndicator } from 'src/engine/core-modules/health/indicators/worker.health';
|
||||
import { PublicEndpointGuard } from 'src/engine/guards/public-endpoint.guard';
|
||||
|
||||
@Controller('healthz')
|
||||
export class HealthController {
|
||||
constructor(
|
||||
@ -19,12 +27,14 @@ export class HealthController {
|
||||
) {}
|
||||
|
||||
@Get()
|
||||
@UseGuards(PublicEndpointGuard)
|
||||
@HealthCheck()
|
||||
check() {
|
||||
return this.health.check([]);
|
||||
}
|
||||
|
||||
@Get(':indicatorId')
|
||||
@UseGuards(PublicEndpointGuard)
|
||||
@HealthCheck()
|
||||
checkService(@Param('indicatorId') indicatorId: HealthIndicatorId) {
|
||||
const checks = {
|
||||
|
||||
@ -1,14 +1,16 @@
|
||||
import { Controller, Get, Req, Res } from '@nestjs/common';
|
||||
import { Controller, Get, Req, Res, UseGuards } from '@nestjs/common';
|
||||
|
||||
import { Request, Response } from 'express';
|
||||
|
||||
import { OpenApiService } from 'src/engine/core-modules/open-api/open-api.service';
|
||||
import { PublicEndpointGuard } from 'src/engine/guards/public-endpoint.guard';
|
||||
|
||||
@Controller()
|
||||
export class OpenApiController {
|
||||
constructor(private readonly openApiService: OpenApiService) {}
|
||||
|
||||
@Get(['open-api/core', 'rest/open-api/core'])
|
||||
@UseGuards(PublicEndpointGuard)
|
||||
async generateOpenApiSchemaCore(
|
||||
@Req() request: Request,
|
||||
@Res() res: Response,
|
||||
@ -19,6 +21,7 @@ export class OpenApiController {
|
||||
}
|
||||
|
||||
@Get(['open-api/metadata', 'rest/open-api/metadata'])
|
||||
@UseGuards(PublicEndpointGuard)
|
||||
async generateOpenApiSchemaMetaData(
|
||||
@Req() request: Request,
|
||||
@Res() res: Response,
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
import { UseFilters } from '@nestjs/common';
|
||||
import { UseFilters, UseGuards } from '@nestjs/common';
|
||||
import { Args, Query, Resolver } from '@nestjs/graphql';
|
||||
|
||||
import { SearchArgs } from 'src/engine/core-modules/search/dtos/search-args';
|
||||
import { SearchResultConnectionDTO } from 'src/engine/core-modules/search/dtos/search-result-connection.dto';
|
||||
import { SearchApiExceptionFilter } from 'src/engine/core-modules/search/filters/search-api-exception.filter';
|
||||
import { SearchService } from 'src/engine/core-modules/search/services/search.service';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
||||
import { SearchResultConnectionDTO } from 'src/engine/core-modules/search/dtos/search-result-connection.dto';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
|
||||
@Resolver()
|
||||
@UseFilters(SearchApiExceptionFilter)
|
||||
@ -14,6 +15,7 @@ export class SearchResolver {
|
||||
constructor(private readonly searchService: SearchService) {}
|
||||
|
||||
@Query(() => SearchResultConnectionDTO)
|
||||
@UseGuards(WorkspaceAuthGuard)
|
||||
async search(
|
||||
@AuthWorkspace() workspace: Workspace,
|
||||
@Args()
|
||||
|
||||
@ -1,9 +1,18 @@
|
||||
import { Controller, Get, Param, Post, Req, UseFilters } from '@nestjs/common';
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Param,
|
||||
Post,
|
||||
Req,
|
||||
UseFilters,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
|
||||
import { Request } from 'express';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { WorkflowTriggerRestApiExceptionFilter } from 'src/engine/core-modules/workflow/filters/workflow-trigger-rest-api-exception.filter';
|
||||
import { PublicEndpointGuard } from 'src/engine/guards/public-endpoint.guard';
|
||||
import { FieldActorSource } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type';
|
||||
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
|
||||
import {
|
||||
@ -27,6 +36,7 @@ export class WorkflowTriggerController {
|
||||
) {}
|
||||
|
||||
@Post('workflows/:workspaceId/:workflowId')
|
||||
@UseGuards(PublicEndpointGuard)
|
||||
async runWorkflowByPostRequest(
|
||||
@Param('workspaceId') workspaceId: string,
|
||||
@Param('workflowId') workflowId: string,
|
||||
@ -40,6 +50,7 @@ export class WorkflowTriggerController {
|
||||
}
|
||||
|
||||
@Get('workflows/:workspaceId/:workflowId')
|
||||
@UseGuards(PublicEndpointGuard)
|
||||
async runWorkflowByGetRequest(
|
||||
@Param('workspaceId') workspaceId: string,
|
||||
@Param('workflowId') workflowId: string,
|
||||
|
||||
@ -24,6 +24,7 @@ import { DomainManagerService } from 'src/engine/core-modules/domain-manager/ser
|
||||
import { FeatureFlagDTO } from 'src/engine/core-modules/feature-flag/dtos/feature-flag-dto';
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
import { SignedFileDTO } from 'src/engine/core-modules/file/file-upload/dtos/signed-file.dto';
|
||||
import { FileUploadService } from 'src/engine/core-modules/file/file-upload/services/file-upload.service';
|
||||
import { FileService } from 'src/engine/core-modules/file/services/file.service';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
@ -43,6 +44,7 @@ import { AuthApiKey } from 'src/engine/decorators/auth/auth-api-key.decorator';
|
||||
import { AuthUserWorkspaceId } from 'src/engine/decorators/auth/auth-user-workspace-id.decorator';
|
||||
import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator';
|
||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
||||
import { PublicEndpointGuard } from 'src/engine/guards/public-endpoint.guard';
|
||||
import { SettingsPermissionsGuard } from 'src/engine/guards/settings-permissions.guard';
|
||||
import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
@ -52,7 +54,6 @@ import { RoleDTO } from 'src/engine/metadata-modules/role/dtos/role.dto';
|
||||
import { RoleService } from 'src/engine/metadata-modules/role/role.service';
|
||||
import { GraphqlValidationExceptionFilter } from 'src/filters/graphql-validation-exception.filter';
|
||||
import { streamToBuffer } from 'src/utils/stream-to-buffer';
|
||||
import { SignedFileDTO } from 'src/engine/core-modules/file/file-upload/dtos/signed-file.dto';
|
||||
|
||||
import { Workspace } from './workspace.entity';
|
||||
|
||||
@ -283,6 +284,7 @@ export class WorkspaceResolver {
|
||||
}
|
||||
|
||||
@Query(() => PublicWorkspaceDataOutput)
|
||||
@UseGuards(PublicEndpointGuard)
|
||||
async getPublicWorkspaceDataByDomain(
|
||||
@Args('origin') origin: string,
|
||||
): Promise<PublicWorkspaceDataOutput | undefined> {
|
||||
|
||||
Reference in New Issue
Block a user