-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(tenant-management): change the table name to tenant mgmt configs
add another interceptor for callback methods GH-47
- Loading branch information
1 parent
add92c6
commit ff7705e
Showing
16 changed files
with
191 additions
and
74 deletions.
There are no files selected for viewing
2 changes: 1 addition & 1 deletion
2
...nt-service/migrations/pg/migrations/sqls/20240925102459-add-table-tenant-configs-down.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
drop table main.tenant_configs; | ||
drop table main.tenant_mgmt_configs; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
100 changes: 100 additions & 0 deletions
100
services/tenant-management-service/src/interceptors/callback-verifier.interceptor.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import { | ||
Interceptor, | ||
InvocationContext, | ||
Provider, | ||
Setter, | ||
ValueOrPromise, | ||
inject, | ||
} from '@loopback/core'; | ||
import {AnyObject, repository} from '@loopback/repository'; | ||
import {HttpErrors, RequestContext} from '@loopback/rest'; | ||
import {ILogger, LOGGER} from '@sourceloop/core'; | ||
import {createHmac, timingSafeEqual} from 'crypto'; | ||
import {AuthenticationBindings, IAuthUser} from 'loopback4-authentication'; | ||
import {SYSTEM_USER} from '../keys'; | ||
import {WebhookSecretRepository} from '../repositories'; | ||
|
||
const DEFAULT_TIME_TOLERANCE = 10000; | ||
|
||
export class CallbackVerifierProvider implements Provider<Interceptor> { | ||
constructor( | ||
@inject(LOGGER.LOGGER_INJECT) | ||
private readonly logger: ILogger, | ||
@repository(WebhookSecretRepository) | ||
private readonly webhookSecretRepo: WebhookSecretRepository, | ||
@inject.setter(AuthenticationBindings.CURRENT_USER) | ||
private readonly setCurrentUser: Setter<IAuthUser>, | ||
@inject(SYSTEM_USER) | ||
private readonly systemUser: IAuthUser, | ||
) {} | ||
|
||
value() { | ||
return this.intercept.bind(this); | ||
} | ||
|
||
async intercept<T>( | ||
invocationCtx: InvocationContext, | ||
next: () => ValueOrPromise<T>, | ||
) { | ||
const {request} = invocationCtx.parent as RequestContext; | ||
const value: AnyObject = request.body; | ||
const TIMESTAMP_TOLERANCE = +DEFAULT_TIME_TOLERANCE; | ||
const timestamp = Number(request.headers['x-timestamp']); | ||
if (isNaN(timestamp)) { | ||
this.logger.error('Invalid timestamp'); | ||
throw new HttpErrors.Unauthorized(); | ||
} | ||
|
||
const signature = request.headers['x-signature']; | ||
if (!signature || typeof signature !== 'string') { | ||
this.logger.error('Missing signature string'); | ||
throw new HttpErrors.Unauthorized(); | ||
} | ||
|
||
const tenantId = value.tenant?.id; | ||
if (!tenantId) { | ||
this.logger.error('Missing secret'); | ||
throw new HttpErrors.Unauthorized(); | ||
} | ||
|
||
const secretInfo = await this.webhookSecretRepo.get(tenantId); | ||
if (!secretInfo) { | ||
this.logger.error('No secret found for this initiator'); | ||
throw new HttpErrors.Unauthorized(); | ||
} | ||
|
||
const expectedSignature = createHmac('sha256', secretInfo.secret) | ||
.update(`${JSON.stringify(value)}${timestamp}`) | ||
.digest('hex'); | ||
|
||
try { | ||
// actual signature should be equal to expected signature | ||
// timing safe equal is used to prevent timing attacks | ||
if ( | ||
!timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature)) | ||
) { | ||
this.logger.error('Invalid signature'); | ||
throw new HttpErrors.Unauthorized(); | ||
} | ||
|
||
const hh = Math.abs(timestamp - Date.now()); | ||
// timestamp should be within 10 seconds | ||
if (hh > TIMESTAMP_TOLERANCE) { | ||
this.logger.error('Timestamp out of tolerance'); | ||
throw new HttpErrors.Unauthorized(); | ||
} | ||
} catch (e) { | ||
this.logger.error(e); | ||
throw new HttpErrors.Unauthorized(); | ||
} | ||
|
||
this.setCurrentUser(this.systemUser); | ||
return next(); | ||
} | ||
} | ||
|
||
export type TempUser = { | ||
userTenantId: string; | ||
tenantType: string; | ||
tenantId?: string; | ||
} & IAuthUser; |
Oops, something went wrong.