Skip to content

Commit 6bc1b53

Browse files
committed
fix(zapier-oauth): improve zapier oauth authorization implementation
1 parent a4ca046 commit 6bc1b53

File tree

4 files changed

+79
-18
lines changed

4 files changed

+79
-18
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { Injectable, Logger } from '@nestjs/common';
2+
import * as moment from 'moment';
3+
import { v4 as uuidv4 } from 'uuid';
4+
import { ID } from '@gauzy/contracts';
5+
6+
@Injectable()
7+
export class ZapierAuthCodeService {
8+
private readonly logger = new Logger(ZapierAuthCodeService.name);
9+
10+
// Using a Map to store temporary auth codes - this is temporary storage
11+
// and doesn't need to be persisted to the database
12+
private authCodes: Map<string, {
13+
userId: string,
14+
expiresAt: Date,
15+
tenantId: string,
16+
organizationId?: string
17+
}> = new Map();
18+
19+
/**
20+
* Generates and stores an authentication code for a user
21+
*
22+
* @param userId The user's ID
23+
* @param tenantId The tenant ID
24+
* @param organizationId The organization ID
25+
* @returns The generated authorization code
26+
*/
27+
28+
generateAuthCode(userId: ID, tenantId: ID, organizationId?: ID): String {
29+
// Generation of a unique code
30+
const code = uuidv4();
31+
// Auth codes expire in 60 minutes
32+
const expiresAt = moment().add(60, 'minutes').toDate();
33+
34+
// Stores the code with user infos
35+
this.authCodes.set(code, {
36+
userId: userId.toString(),
37+
tenantId: tenantId.toString(),
38+
organizationId: organizationId?.toString(),
39+
expiresAt
40+
});
41+
this.logger.debug(`Generated auth code for user ${userId}, expires at ${expiresAt}`);
42+
return code;
43+
}
44+
45+
/**
46+
* Gets the user information associated with an auth code
47+
*
48+
* @param code The authorization code
49+
* @returns The user info or null if code is invalid or expired
50+
*/
51+
getUserInfoFromAuthCode(code: string): {
52+
userId: string,
53+
tenantId: string,
54+
organizationId?: string
55+
} | null {
56+
const authCodeData = this.authCodes.get(code);
57+
58+
// Check if code exists and is not expired
59+
if (authCodeData && moment().isBefore(authCodeData.expiresAt)) {
60+
this.authCodes.delete(code);
61+
62+
return {
63+
userId: authCodeData.userId,
64+
tenantId: authCodeData.tenantId,
65+
organizationId: authCodeData.organizationId
66+
};
67+
}
68+
return null;
69+
}
70+
}

packages/plugins/integration-zapier/src/lib/zapier-authorization.controller.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export class ZapierAuthorizationController {
7070

7171
// Store these parameters in the session or state
7272
// Redirect to the login page with these parameters preserved
73-
const loginPageUrl = `${process.env['API_BASE_URL']}/auth/login?zapier_redirect_uri=${encodeURIComponent(redirectUri)}&zapier_state=${encodeURIComponent(state)}`;
73+
const loginPageUrl = `${process.env['CLIENT_BASE_URL']}/#/auth/login?zapier_redirect_uri=${encodeURIComponent(redirectUri)}&zapier_state=${encodeURIComponent(state)}`;
7474
this.logger.debug(`Redirecting to: ${loginPageUrl}`);
7575

7676
res.redirect(loginPageUrl);

packages/plugins/integration-zapier/src/lib/zapier-webhook.service.ts

+8-11
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@ import { Injectable, Logger, ForbiddenException, NotFoundException, InternalServ
22
import { ID } from '@gauzy/contracts';
33
import { ZapierWebhookSubscription } from './zapier-webhook-subscription.entity';
44
import { TypeOrmZapierWebhookSubscriptionRepository } from './repository/type-orm-zapier.repository';
5+
import { HttpService } from '@nestjs/axios';
6+
import { catchError, firstValueFrom, of } from 'rxjs';
57

68
@Injectable()
79
export class ZapierWebhookService {
810
private readonly logger = new Logger(ZapierWebhookService.name);
911

1012
constructor(
1113
private readonly subscriptionRepository: TypeOrmZapierWebhookSubscriptionRepository,
14+
private readonly _httpService: HttpService,
1215
) { }
1316

1417
async createSubscription(input: {
@@ -96,23 +99,17 @@ export class ZapierWebhookService {
9699

97100
// Notify each subscriber
98101
for (const subscription of subscriptions) {
99-
try {
100-
await this._httpService.post(subscription.targetUrl, {
102+
await firstValueFrom(
103+
this._httpService.post(subscription.targetUrl, {
101104
event: 'timer.status.changed',
102105
data: timerData
103106
}).pipe(
104107
catchError(error => {
105-
this.logger.error(
106-
`Failed to notify webhook ${subscription.id} at ${subscription.targetUrl}`,
107-
error
108-
);
108+
this.logger.error(`Failed to notify webhook ${subscription.id} at ${subscription.targetUrl}`, error);
109109
return of(null);
110110
})
111-
).toPromise();
112-
} catch (error) {
113-
this.logger.error(`Error notifying webhook ${subscription.id}`, error);
114-
// Continue with other webhooks even if this one fails
115-
}
111+
)
112+
);
116113
}
117114
} catch (error) {
118115
this.logger.error('Failed to process timer status change webhooks', error);

packages/plugins/integration-zapier/src/lib/zapier.module.ts

-6
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ import {
1313
UserModule,
1414
RolePermissionModule,
1515
TimerModule,
16-
CommandHandlers,
17-
QueryHandlers
1816
} from '@gauzy/core';
1917
import { ZapierService } from './zapier.service';
2018
import { ZapierController } from './zapier.controller';
@@ -24,10 +22,6 @@ import { ZapierWebhookController } from './zapier-webhook.controller';
2422
import { ZapierWebhookSubscription } from './zapier-webhook-subscription.entity';
2523
import { MikroOrmZapierWebhookSubscriptionRepository } from './repository/mikro-orm-zapier.repository';
2624
import { TypeOrmZapierWebhookSubscriptionRepository } from './repository/type-orm-zapier.repository';
27-
import { ZapierWebhookSubscriptionRepository } from './repository/zapier-repository.entity';
28-
import { TypeOrmModule } from '@nestjs/typeorm';
29-
import { MikroOrmModule } from '@mikro-orm/nestjs';
30-
import { TimerModule } from '@gauzy/core';
3125
import { EventHandlers } from './handlers';
3226
import { ZapierAuthCodeService } from './zapier-auth-code.service';
3327

0 commit comments

Comments
 (0)