mirror of
https://github.com/standardnotes/server
synced 2026-09-12 15:45:26 -04:00
fix: Prevents self invites to subscriptions
This commit is contained in:
+24
-5
@@ -65,7 +65,7 @@ describe('AcceptSharedSubscriptionInvitation', () => {
|
||||
|
||||
inviteeSubscription = { endsAt: 3, planName: SubscriptionName.PlusPlan } as jest.Mocked<UserSubscription>
|
||||
|
||||
inviterSubscription = { endsAt: 3, planName: SubscriptionName.PlusPlan } as jest.Mocked<UserSubscription>
|
||||
inviterSubscription = { endsAt: 3, planName: SubscriptionName.PlusPlan, userUuid: '456' } as jest.Mocked<UserSubscription>
|
||||
|
||||
userSubscriptionRepository = {} as jest.Mocked<UserSubscriptionRepositoryInterface>
|
||||
userSubscriptionRepository.findBySubscriptionIdAndType = jest.fn().mockReturnValue([inviterSubscription])
|
||||
@@ -114,8 +114,8 @@ describe('AcceptSharedSubscriptionInvitation', () => {
|
||||
})
|
||||
|
||||
it('should create a shared subscription upon accepting the invitation if inviter has a second subscription', async () => {
|
||||
const inviterSubscription1 = { endsAt: 1, planName: SubscriptionName.PlusPlan } as jest.Mocked<UserSubscription>
|
||||
const inviterSubscription2 = { endsAt: 5, planName: SubscriptionName.PlusPlan } as jest.Mocked<UserSubscription>
|
||||
const inviterSubscription1 = { endsAt: 1, planName: SubscriptionName.PlusPlan, userUuid: '456' } as jest.Mocked<UserSubscription>
|
||||
const inviterSubscription2 = { endsAt: 5, planName: SubscriptionName.PlusPlan, userUuid: '456' } as jest.Mocked<UserSubscription>
|
||||
|
||||
timer.getTimestampInMicroseconds = jest.fn().mockReturnValue(3)
|
||||
|
||||
@@ -208,6 +208,25 @@ describe('AcceptSharedSubscriptionInvitation', () => {
|
||||
expect(applyDefaultSubscriptionSettings.execute).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should not create a shared subscription if invitee is the inviter', async () => {
|
||||
inviterSubscription = { endsAt: 3, planName: SubscriptionName.PlusPlan, userUuid: '123' } as jest.Mocked<UserSubscription>
|
||||
userSubscriptionRepository.findBySubscriptionIdAndType = jest.fn().mockReturnValue([inviterSubscription])
|
||||
|
||||
expect(
|
||||
await createUseCase().execute({
|
||||
sharedSubscriptionInvitationUuid: '1-2-3',
|
||||
}),
|
||||
).toEqual({
|
||||
success: false,
|
||||
message: 'You cannot accept a subscription invitation sent to yourself.',
|
||||
})
|
||||
|
||||
expect(sharedSubscriptionInvitationRepository.save).not.toHaveBeenCalled()
|
||||
expect(userSubscriptionRepository.save).not.toHaveBeenCalled()
|
||||
expect(roleService.addUserRoleBasedOnSubscription).not.toHaveBeenCalled()
|
||||
expect(applyDefaultSubscriptionSettings.execute).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should not create a shared subscription if inviter subscription is not found', async () => {
|
||||
userSubscriptionRepository.findBySubscriptionIdAndType = jest.fn().mockReturnValue([])
|
||||
expect(
|
||||
@@ -226,8 +245,8 @@ describe('AcceptSharedSubscriptionInvitation', () => {
|
||||
})
|
||||
|
||||
it('should not create a shared subscription if inviter subscriptions are not active', async () => {
|
||||
const inviterSubscription1 = { endsAt: 1, planName: SubscriptionName.PlusPlan } as jest.Mocked<UserSubscription>
|
||||
const inviterSubscription2 = { endsAt: 2, planName: SubscriptionName.PlusPlan } as jest.Mocked<UserSubscription>
|
||||
const inviterSubscription1 = { endsAt: 1, planName: SubscriptionName.PlusPlan, userUuid: '456' } as jest.Mocked<UserSubscription>
|
||||
const inviterSubscription2 = { endsAt: 2, planName: SubscriptionName.PlusPlan, userUuid: '456' } as jest.Mocked<UserSubscription>
|
||||
|
||||
timer.getTimestampInMicroseconds = jest.fn().mockReturnValue(3)
|
||||
|
||||
|
||||
+7
@@ -74,6 +74,13 @@ export class AcceptSharedSubscriptionInvitation implements UseCaseInterface {
|
||||
}
|
||||
const inviterUserSubscription = activeUserSubscriptions[0]
|
||||
|
||||
if (invitee.uuid === inviterUserSubscription.userUuid) {
|
||||
return {
|
||||
success: false,
|
||||
message: 'You cannot accept a subscription invitation sent to yourself.',
|
||||
}
|
||||
}
|
||||
|
||||
sharedSubscriptionInvitation.status = InvitationStatus.Accepted
|
||||
sharedSubscriptionInvitation.updatedAt = this.timer.getTimestampInMicroseconds()
|
||||
|
||||
|
||||
+32
@@ -58,6 +58,38 @@ describe('InviteToSharedSubscription', () => {
|
||||
domainEventFactory.createEmailRequestedEvent = jest.fn().mockReturnValue({} as jest.Mocked<EmailRequestedEvent>)
|
||||
})
|
||||
|
||||
it('should not create an invitation if user invites themselves', async () => {
|
||||
expect(
|
||||
await createUseCase().execute({
|
||||
inviteeIdentifier: '[email protected]',
|
||||
inviterUuid: '1-2-3',
|
||||
inviterEmail: '[email protected]',
|
||||
inviterRoles: [RoleName.NAMES.ProUser],
|
||||
}),
|
||||
).toEqual({
|
||||
success: false,
|
||||
})
|
||||
|
||||
expect(sharedSubscriptionInvitationRepository.save).not.toHaveBeenCalled()
|
||||
expect(domainEventFactory.createSharedSubscriptionInvitationCreatedEvent).not.toHaveBeenCalled()
|
||||
expect(domainEventPublisher.publish).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should not create an inivitation if user invites themselves with different email casing', async () => {
|
||||
expect(
|
||||
await createUseCase().execute({
|
||||
inviteeIdentifier: '[email protected]',
|
||||
inviterUuid: '1-2-3',
|
||||
inviterEmail: '[email protected]',
|
||||
inviterRoles: [RoleName.NAMES.ProUser],
|
||||
}),
|
||||
).toEqual({
|
||||
success: false,
|
||||
})
|
||||
|
||||
expect(sharedSubscriptionInvitationRepository.save).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should not create an inivitation for sharing the subscription if inviter has no subscription', async () => {
|
||||
userSubscriptionRepository.findOneByUserUuid = jest.fn().mockReturnValue(null)
|
||||
|
||||
|
||||
+23
-5
@@ -45,6 +45,16 @@ export class InviteToSharedSubscription implements UseCaseInterface {
|
||||
}
|
||||
}
|
||||
|
||||
const inviteeIdentifierType = this.isInviteeIdentifierPotentiallyAPrivateUsernameAccount(dto.inviteeIdentifier)
|
||||
? InviteeIdentifierType.Hash
|
||||
: InviteeIdentifierType.Email
|
||||
|
||||
if (this.isSelfInvite(dto.inviteeIdentifier, dto.inviterEmail, inviteeIdentifierType)) {
|
||||
return {
|
||||
success: false,
|
||||
}
|
||||
}
|
||||
|
||||
const numberOfUsedInvites = await this.sharedSubscriptionInvitationRepository.countByInviterEmailAndStatus(
|
||||
dto.inviterEmail,
|
||||
[InvitationStatus.Sent, InvitationStatus.Accepted],
|
||||
@@ -69,11 +79,7 @@ export class InviteToSharedSubscription implements UseCaseInterface {
|
||||
sharedSubscriptionInvition.inviterIdentifier = dto.inviterEmail
|
||||
sharedSubscriptionInvition.inviterIdentifierType = InviterIdentifierType.Email
|
||||
sharedSubscriptionInvition.inviteeIdentifier = dto.inviteeIdentifier
|
||||
sharedSubscriptionInvition.inviteeIdentifierType = this.isInviteeIdentifierPotentiallyAPrivateUsernameAccount(
|
||||
dto.inviteeIdentifier,
|
||||
)
|
||||
? InviteeIdentifierType.Hash
|
||||
: InviteeIdentifierType.Email
|
||||
sharedSubscriptionInvition.inviteeIdentifierType = inviteeIdentifierType
|
||||
sharedSubscriptionInvition.status = InvitationStatus.Sent
|
||||
sharedSubscriptionInvition.subscriptionId = inviterUserSubscription.subscriptionId as number
|
||||
sharedSubscriptionInvition.createdAt = this.timer.getTimestampInMicroseconds()
|
||||
@@ -110,4 +116,16 @@ export class InviteToSharedSubscription implements UseCaseInterface {
|
||||
private isInviteeIdentifierPotentiallyAPrivateUsernameAccount(identifier: string): boolean {
|
||||
return identifier.length === 64 && !identifier.includes('@')
|
||||
}
|
||||
|
||||
private isSelfInvite(
|
||||
inviteeIdentifier: string,
|
||||
inviterEmail: string,
|
||||
inviteeIdentifierType: InviteeIdentifierType,
|
||||
): boolean {
|
||||
if (inviteeIdentifierType !== InviteeIdentifierType.Email) {
|
||||
return false
|
||||
}
|
||||
|
||||
return inviteeIdentifier.trim().toLowerCase() === inviterEmail.trim().toLowerCase()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user