Refacto environment service (#4473)

* Refacto environment service

* Remove environment variable type
This commit is contained in:
Félix Malfait
2024-03-14 11:51:19 +01:00
committed by GitHub
parent 3caf860848
commit fd06d52a13
42 changed files with 320 additions and 480 deletions

View File

@ -23,12 +23,13 @@ export class AnalyticsService {
workspace: Workspace | undefined,
request: Request,
) {
if (!this.environmentService.isTelemetryEnabled()) {
if (!this.environmentService.get('TELEMETRY_ENABLED')) {
return { success: true };
}
const anonymizationEnabled =
this.environmentService.isTelemetryAnonymizationEnabled();
const anonymizationEnabled = this.environmentService.get(
'TELEMETRY_ANONYMIZATION_ENABLED',
);
const data = {
type: createEventInput.type,

View File

@ -47,7 +47,7 @@ export class ApiRestQueryBuilderFactory {
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.getFrontBaseUrl()}/settings/developers`,
`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`,
);
}

View File

@ -30,9 +30,9 @@ import { AuthService } from './services/auth.service';
const jwtModule = JwtModule.registerAsync({
useFactory: async (environmentService: EnvironmentService) => {
return {
secret: environmentService.getAccessTokenSecret(),
secret: environmentService.get('ACCESS_TOKEN_SECRET'),
signOptions: {
expiresIn: environmentService.getAccessTokenExpiresIn(),
expiresIn: environmentService.get('ACCESS_TOKEN_EXPIRES_IN'),
},
};
},

View File

@ -37,7 +37,7 @@ export class GoogleAPIsAuthController {
const { workspaceMemberId, workspaceId } =
await this.tokenService.verifyTransientToken(transientToken);
const demoWorkspaceIds = this.environmentService.getDemoWorkspaceIds();
const demoWorkspaceIds = this.environmentService.get('DEMO_WORKSPACE_IDS');
if (demoWorkspaceIds.includes(workspaceId)) {
throw new Error('Cannot connect Google account to demo workspace');
@ -57,7 +57,7 @@ export class GoogleAPIsAuthController {
});
return res.redirect(
`${this.environmentService.getFrontBaseUrl()}/settings/accounts`,
`${this.environmentService.get('FRONT_BASE_URL')}/settings/accounts`,
);
}
}

View File

@ -37,7 +37,7 @@ export class GoogleGmailAuthController {
const { workspaceMemberId, workspaceId } =
await this.tokenService.verifyTransientToken(transientToken);
const demoWorkspaceIds = this.environmentService.getDemoWorkspaceIds();
const demoWorkspaceIds = this.environmentService.get('DEMO_WORKSPACE_IDS');
if (demoWorkspaceIds.includes(workspaceId)) {
throw new Error('Cannot connect Gmail account to demo workspace');
@ -58,7 +58,7 @@ export class GoogleGmailAuthController {
});
return res.redirect(
`${this.environmentService.getFrontBaseUrl()}/settings/accounts`,
`${this.environmentService.get('FRONT_BASE_URL')}/settings/accounts`,
);
}
}

View File

@ -11,8 +11,8 @@ export class GoogleAPIsProviderEnabledGuard implements CanActivate {
canActivate(): boolean | Promise<boolean> | Observable<boolean> {
if (
!this.environmentService.isMessagingProviderGmailEnabled() &&
!this.environmentService.isCalendarProviderGoogleEnabled()
!this.environmentService.get('MESSAGING_PROVIDER_GMAIL_ENABLED') &&
!this.environmentService.get('CALENDAR_PROVIDER_GOOGLE_ENABLED')
) {
throw new NotFoundException('Google apis auth is not enabled');
}

View File

@ -0,0 +1,21 @@
import { Injectable, CanActivate, NotFoundException } from '@nestjs/common';
import { Observable } from 'rxjs';
import { GoogleAPIsStrategy } from 'src/core/auth/strategies/google-apis.auth.strategy';
import { EnvironmentService } from 'src/integrations/environment/environment.service';
@Injectable()
export class GoogleGmailProviderEnabledGuard implements CanActivate {
constructor(private readonly environmentService: EnvironmentService) {}
canActivate(): boolean | Promise<boolean> | Observable<boolean> {
if (!this.environmentService.get('MESSAGING_PROVIDER_GMAIL_ENABLED')) {
throw new NotFoundException('Gmail auth is not enabled');
}
new GoogleAPIsStrategy(this.environmentService);
return true;
}
}

View File

@ -10,7 +10,7 @@ export class GoogleProviderEnabledGuard implements CanActivate {
constructor(private readonly environmentService: EnvironmentService) {}
canActivate(): boolean | Promise<boolean> | Observable<boolean> {
if (!this.environmentService.isAuthGoogleEnabled()) {
if (!this.environmentService.get('AUTH_GOOGLE_ENABLED')) {
throw new NotFoundException('Google auth is not enabled');
}

View File

@ -194,7 +194,7 @@ export class AuthService {
const emailTemplate = PasswordUpdateNotifyEmail({
userName: `${user.firstName} ${user.lastName}`,
email: user.email,
link: this.environmentService.getFrontBaseUrl(),
link: this.environmentService.get('FRONT_BASE_URL'),
});
const html = render(emailTemplate, {
@ -205,7 +205,7 @@ export class AuthService {
});
this.emailService.send({
from: `${this.environmentService.getEmailFromName()} <${this.environmentService.getEmailFromAddress()}>`,
from: `${this.environmentService.get('EMAIL_FROM_NAME')} <${this.environmentService.get('EMAIL_FROM_ADDRESS')}>`,
to: user.email,
subject: 'Your Password Has Been Successfully Changed',
text,

View File

@ -88,7 +88,7 @@ export class GoogleAPIsService {
],
);
if (this.environmentService.isMessagingProviderGmailEnabled()) {
if (this.environmentService.get('MESSAGING_PROVIDER_GMAIL_ENABLED')) {
await manager.query(
`INSERT INTO ${dataSourceMetadata.schema}."messageChannel" ("visibility", "handle", "connectedAccountId", "type") VALUES ($1, $2, $3, $4)`,
['share_everything', handle, connectedAccountId, 'email'],
@ -96,7 +96,7 @@ export class GoogleAPIsService {
}
if (
this.environmentService.isCalendarProviderGoogleEnabled() &&
this.environmentService.get('CALENDAR_PROVIDER_GOOGLE_ENABLED') &&
IsCalendarEnabled
) {
await manager.query(
@ -106,7 +106,7 @@ export class GoogleAPIsService {
}
});
if (this.environmentService.isMessagingProviderGmailEnabled()) {
if (this.environmentService.get('MESSAGING_PROVIDER_GMAIL_ENABLED')) {
await this.messageQueueService.add<GmailFullSyncJobData>(
GmailFullSyncJob.name,
{
@ -120,7 +120,7 @@ export class GoogleAPIsService {
}
if (
this.environmentService.isCalendarProviderGoogleEnabled() &&
this.environmentService.get('CALENDAR_PROVIDER_GOOGLE_ENABLED') &&
IsCalendarEnabled
) {
await this.calendarQueueService.add<GoogleCalendarFullSyncJobData>(

View File

@ -190,7 +190,7 @@ export class SignUpService {
}
assert(
!this.environmentService.isSignUpDisabled(),
!this.environmentService.get('IS_SIGN_UP_DISABLED'),
'Sign up is disabled',
ForbiddenException,
);

View File

@ -63,7 +63,7 @@ export class TokenService {
userId: string,
workspaceId?: string,
): Promise<AuthToken> {
const expiresIn = this.environmentService.getAccessTokenExpiresIn();
const expiresIn = this.environmentService.get('ACCESS_TOKEN_EXPIRES_IN');
assert(expiresIn, '', InternalServerErrorException);
const expiresAt = addMilliseconds(new Date().getTime(), ms(expiresIn));
@ -93,8 +93,8 @@ export class TokenService {
}
async generateRefreshToken(userId: string): Promise<AuthToken> {
const secret = this.environmentService.getRefreshTokenSecret();
const expiresIn = this.environmentService.getRefreshTokenExpiresIn();
const secret = this.environmentService.get('REFRESH_TOKEN_SECRET');
const expiresIn = this.environmentService.get('REFRESH_TOKEN_EXPIRES_IN');
assert(expiresIn, '', InternalServerErrorException);
const expiresAt = addMilliseconds(new Date().getTime(), ms(expiresIn));
@ -124,8 +124,8 @@ export class TokenService {
}
async generateLoginToken(email: string): Promise<AuthToken> {
const secret = this.environmentService.getLoginTokenSecret();
const expiresIn = this.environmentService.getLoginTokenExpiresIn();
const secret = this.environmentService.get('LOGIN_TOKEN_SECRET');
const expiresIn = this.environmentService.get('LOGIN_TOKEN_EXPIRES_IN');
assert(expiresIn, '', InternalServerErrorException);
const expiresAt = addMilliseconds(new Date().getTime(), ms(expiresIn));
@ -146,8 +146,8 @@ export class TokenService {
workspaceMemberId: string,
workspaceId: string,
): Promise<AuthToken> {
const secret = this.environmentService.getLoginTokenSecret();
const expiresIn = this.environmentService.getTransientTokenExpiresIn();
const secret = this.environmentService.get('LOGIN_TOKEN_SECRET');
const expiresIn = this.environmentService.get('SHORT_TERM_TOKEN_EXPIRES_IN');
assert(expiresIn, '', InternalServerErrorException);
const expiresAt = addMilliseconds(new Date().getTime(), ms(expiresIn));
@ -176,7 +176,7 @@ export class TokenService {
const jwtPayload = {
sub: workspaceId,
};
const secret = this.environmentService.getAccessTokenSecret();
const secret = this.environmentService.get('ACCESS_TOKEN_SECRET');
let expiresIn: string | number;
if (expiresAt) {
@ -184,7 +184,7 @@ export class TokenService {
(new Date(expiresAt).getTime() - new Date().getTime()) / 1000,
);
} else {
expiresIn = this.environmentService.getApiTokenExpiresIn();
expiresIn = this.environmentService.get('API_TOKEN_EXPIRES_IN');
}
const token = this.jwtService.sign(jwtPayload, {
secret,
@ -209,7 +209,7 @@ export class TokenService {
}
const decoded = await this.verifyJwt(
token,
this.environmentService.getAccessTokenSecret(),
this.environmentService.get('ACCESS_TOKEN_SECRET'),
);
const { user, workspace } = await this.jwtStrategy.validate(
@ -220,7 +220,7 @@ export class TokenService {
}
async verifyLoginToken(loginToken: string): Promise<string> {
const loginTokenSecret = this.environmentService.getLoginTokenSecret();
const loginTokenSecret = this.environmentService.get('LOGIN_TOKEN_SECRET');
const payload = await this.verifyJwt(loginToken, loginTokenSecret);
@ -231,7 +231,7 @@ export class TokenService {
workspaceMemberId: string;
workspaceId: string;
}> {
const transientTokenSecret = this.environmentService.getLoginTokenSecret();
const transientTokenSecret = this.environmentService.get('LOGIN_TOKEN_SECRET');
const payload = await this.verifyJwt(transientToken, transientTokenSecret);
@ -281,8 +281,8 @@ export class TokenService {
}
async verifyRefreshToken(refreshToken: string) {
const secret = this.environmentService.getRefreshTokenSecret();
const coolDown = this.environmentService.getRefreshTokenCoolDown();
const secret = this.environmentService.get('REFRESH_TOKEN_SECRET');
const coolDown = this.environmentService.get('REFRESH_TOKEN_COOL_DOWN');
const jwtPayload = await this.verifyJwt(refreshToken, secret);
assert(
@ -382,7 +382,7 @@ export class TokenService {
assert(user, 'User not found', NotFoundException);
const expiresIn = this.environmentService.getPasswordResetTokenExpiresIn();
const expiresIn = this.environmentService.get('PASSWORD_RESET_TOKEN_EXPIRES_IN');
assert(
expiresIn,
@ -439,7 +439,7 @@ export class TokenService {
assert(user, 'User not found', NotFoundException);
const frontBaseURL = this.environmentService.getFrontBaseUrl();
const frontBaseURL = this.environmentService.get('FRONT_BASE_URL');
const resetLink = `${frontBaseURL}/reset-password/${resetToken.passwordResetToken}`;
const emailData = {
@ -465,7 +465,7 @@ export class TokenService {
});
this.emailService.send({
from: `${this.environmentService.getEmailFromName()} <${this.environmentService.getEmailFromAddress()}>`,
from: `${this.environmentService.get('EMAIL_FROM_NAME')} <${this.environmentService.get('EMAIL_FROM_ADDRESS')}>`,
to: email,
subject: 'Action Needed to Reset Password',
text,

View File

@ -27,20 +27,20 @@ export class GoogleAPIsStrategy extends PassportStrategy(
constructor(environmentService: EnvironmentService) {
const scope = ['email', 'profile'];
if (environmentService.isMessagingProviderGmailEnabled()) {
if (environmentService.get('MESSAGING_PROVIDER_GMAIL_ENABLED')) {
scope.push('https://www.googleapis.com/auth/gmail.readonly');
}
if (environmentService.isCalendarProviderGoogleEnabled()) {
if (environmentService.get('CALENDAR_PROVIDER_GOOGLE_ENABLED')) {
scope.push('https://www.googleapis.com/auth/calendar');
}
super({
clientID: environmentService.getAuthGoogleClientId(),
clientSecret: environmentService.getAuthGoogleClientSecret(),
callbackURL: environmentService.isCalendarProviderGoogleEnabled()
? environmentService.getAuthGoogleAPIsCallbackUrl()
: environmentService.getMessagingProviderGmailCallbackUrl(),
clientID: environmentService.get('AUTH_GOOGLE_CLIENT_ID'),
clientSecret: environmentService.get('AUTH_GOOGLE_CLIENT_SECRET'),
callbackURL: environmentService.get('CALENDAR_PROVIDER_GOOGLE_ENABLED')
? environmentService.get('AUTH_GOOGLE_APIS_CALLBACK_URL')
: environmentService.get('MESSAGING_PROVIDER_GMAIL_CALLBACK_URL'),
scope,
passReqToCallback: true,
});

View File

@ -20,9 +20,9 @@ export type GoogleRequest = Request & {
export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
constructor(environmentService: EnvironmentService) {
super({
clientID: environmentService.getAuthGoogleClientId(),
clientSecret: environmentService.getAuthGoogleClientSecret(),
callbackURL: environmentService.getAuthGoogleCallbackUrl(),
clientID: environmentService.get('AUTH_GOOGLE_CLIENT_ID'),
clientSecret: environmentService.get('AUTH_GOOGLE_CLIENT_SECRET'),
callbackURL: environmentService.get('AUTH_GOOGLE_CALLBACK_URL'),
scope: ['email', 'profile'],
passReqToCallback: true,
});

View File

@ -33,7 +33,7 @@ export class JwtAuthStrategy extends PassportStrategy(Strategy, 'jwt') {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: environmentService.getAccessTokenSecret(),
secretOrKey: environmentService.get('ACCESS_TOKEN_SECRET'),
});
}

View File

@ -42,7 +42,7 @@ export class BillingService {
getProductStripeId(product: AvailableProduct) {
if (product === AvailableProduct.BasePlan) {
return this.environmentService.getBillingStripeBasePlanProductId();
return this.environmentService.get('BILLING_STRIPE_BASE_PLAN_PRODUCT_ID');
}
}
@ -98,7 +98,7 @@ export class BillingService {
async getBillingSubscriptionItem(
workspaceId: string,
stripeProductId = this.environmentService.getBillingStripeBasePlanProductId(),
stripeProductId = this.environmentService.get('BILLING_STRIPE_BASE_PLAN_PRODUCT_ID'),
) {
const billingSubscription = await this.getCurrentBillingSubscription({
workspaceId,
@ -134,7 +134,7 @@ export class BillingService {
where: { workspaceId },
});
const frontBaseUrl = this.environmentService.getFrontBaseUrl();
const frontBaseUrl = this.environmentService.get('FRONT_BASE_URL');
const returnUrl = returnUrlPath
? frontBaseUrl + returnUrlPath
: frontBaseUrl;
@ -154,7 +154,7 @@ export class BillingService {
priceId: string,
successUrlPath?: string,
): Promise<string> {
const frontBaseUrl = this.environmentService.getFrontBaseUrl();
const frontBaseUrl = this.environmentService.get('FRONT_BASE_URL');
const successUrl = successUrlPath
? frontBaseUrl + successUrlPath
: frontBaseUrl;

View File

@ -12,14 +12,14 @@ export class StripeService {
constructor(private readonly environmentService: EnvironmentService) {
this.stripe = new Stripe(
this.environmentService.getBillingStripeApiKey(),
this.environmentService.get('BILLING_STRIPE_API_KEY'),
{},
);
}
constructEventFromPayload(signature: string, payload: Buffer) {
const webhookSecret =
this.environmentService.getBillingStripeWebhookSecret();
this.environmentService.get('BILLING_STRIPE_WEBHOOK_SECRET');
return this.stripe.webhooks.constructEvent(
payload,
@ -48,7 +48,7 @@ export class StripeService {
): Promise<Stripe.BillingPortal.Session> {
return await this.stripe.billingPortal.sessions.create({
customer: stripeCustomerId,
return_url: returnUrl ?? this.environmentService.getFrontBaseUrl(),
return_url: returnUrl ?? this.environmentService.get('FRONT_BASE_URL'),
});
}
@ -73,7 +73,7 @@ export class StripeService {
workspaceId: user.defaultWorkspace.id,
},
trial_period_days:
this.environmentService.getBillingFreeTrialDurationInDays(),
this.environmentService.get('BILLING_FREE_TRIAL_DURATION_IN_DAYS'),
},
automatic_tax: { enabled: true },
tax_id_collection: { enabled: true },

View File

@ -12,30 +12,34 @@ export class ClientConfigResolver {
async clientConfig(): Promise<ClientConfig> {
const clientConfig: ClientConfig = {
authProviders: {
google: this.environmentService.isAuthGoogleEnabled(),
google: this.environmentService.get('AUTH_GOOGLE_ENABLED'),
magicLink: false,
password: true,
},
telemetry: {
enabled: this.environmentService.isTelemetryEnabled(),
anonymizationEnabled:
this.environmentService.isTelemetryAnonymizationEnabled(),
enabled: this.environmentService.get('TELEMETRY_ENABLED'),
anonymizationEnabled: this.environmentService.get(
'TELEMETRY_ANONYMIZATION_ENABLED',
),
},
billing: {
isBillingEnabled: this.environmentService.isBillingEnabled(),
billingUrl: this.environmentService.getBillingUrl(),
billingFreeTrialDurationInDays:
this.environmentService.getBillingFreeTrialDurationInDays(),
isBillingEnabled: this.environmentService.get('IS_BILLING_ENABLED'),
billingUrl: this.environmentService.get('BILLING_PLAN_REQUIRED_LINK'),
billingFreeTrialDurationInDays: this.environmentService.get(
'BILLING_FREE_TRIAL_DURATION_IN_DAYS',
),
},
signInPrefilled: this.environmentService.isSignInPrefilled(),
signUpDisabled: this.environmentService.isSignUpDisabled(),
debugMode: this.environmentService.isDebugMode(),
signInPrefilled: this.environmentService.get('SIGN_IN_PREFILLED'),
signUpDisabled: this.environmentService.get('IS_SIGN_UP_DISABLED'),
debugMode: this.environmentService.get('DEBUG_MODE'),
support: {
supportDriver: this.environmentService.getSupportDriver(),
supportFrontChatId: this.environmentService.getSupportFrontChatId(),
supportDriver: this.environmentService.get('SUPPORT_DRIVER'),
supportFrontChatId: this.environmentService.get(
'SUPPORT_FRONT_CHAT_ID',
),
},
sentry: {
dsn: this.environmentService.getSentryDSN(),
dsn: this.environmentService.get('SENTRY_DSN'),
},
};

View File

@ -37,7 +37,7 @@ export class IntelligenceService {
'https://openrouter.ai/api/v1/chat/completions',
{
headers: {
Authorization: `Bearer ${this.environmentService.getOpenRouterApiKey()}`,
Authorization: `Bearer ${this.environmentService.get('OPENROUTER_API_KEY')}`,
'HTTP-Referer': `https://twenty.com`,
'X-Title': `Twenty CRM`,
'Content-Type': 'application/json',

View File

@ -76,10 +76,10 @@ export class UserResolver {
nullable: true,
})
supportUserHash(@Parent() parent: User): string | null {
if (this.environmentService.getSupportDriver() !== SupportDriver.Front) {
if (this.environmentService.get('SUPPORT_DRIVER') !== SupportDriver.Front) {
return null;
}
const key = this.environmentService.getSupportFrontHMACKey();
const key = this.environmentService.get('SUPPORT_FRONT_HMAC_KEY');
return getHMACKey(parent.email, key);
}
@ -111,7 +111,7 @@ export class UserResolver {
@Mutation(() => User)
async deleteUser(@AuthUser() { id: userId, defaultWorkspace }: User) {
// Get the list of demo workspace IDs
const demoWorkspaceIds = this.environmentService.getDemoWorkspaceIds();
const demoWorkspaceIds = this.environmentService.get('DEMO_WORKSPACE_IDS');
const currentUserWorkspaceId = defaultWorkspace.id;

View File

@ -91,7 +91,7 @@ export class WorkspaceResolver {
@Mutation(() => Workspace)
async deleteCurrentWorkspace(@AuthWorkspace() { id }: Workspace) {
const demoWorkspaceIds = this.environmentService.getDemoWorkspaceIds();
const demoWorkspaceIds = this.environmentService.get('DEMO_WORKSPACE_IDS');
// Check if the id is in the list of demo workspaceIds
if (demoWorkspaceIds.includes(id)) {