Skip to content

Commit

Permalink
fix: add backend url validation (#4009)
Browse files Browse the repository at this point in the history
* fix: add backend url validation

* test: update links to be valid

* fix: add url validation for building selection criteria

* test: update buildingSelectionCriteria to be valid url
  • Loading branch information
KrissDrawing authored Apr 22, 2024
1 parent e7cf68d commit d926e8f
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 24 deletions.
31 changes: 31 additions & 0 deletions api/src/decorators/hasHttps.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {
registerDecorator,
ValidationArguments,
ValidationOptions,
ValidatorConstraint,
ValidatorConstraintInterface,
} from 'class-validator';

export function hasHttps(validationOptions?: ValidationOptions) {
return function (object: unknown, propertyName: string) {
registerDecorator({
target: object.constructor,
propertyName,
options: validationOptions,
constraints: [],
validator: hasHttpsConstraint,
});
};
}

@ValidatorConstraint({ name: 'hasHttps' })
export class hasHttpsConstraint implements ValidatorConstraintInterface {
validate(url: string) {
const httpsRegex = /^https?:\/\//i;
return httpsRegex.test(url);
}

defaultMessage(args: ValidationArguments) {
return `${args.property} must have https://`;
}
}
11 changes: 11 additions & 0 deletions api/src/dtos/application-methods/application-method.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ import {
IsString,
MaxLength,
ValidateNested,
ValidateIf,
IsUrl,
} from 'class-validator';
import { ValidationsGroupsEnum } from '../../enums/shared/validation-groups-enum';
import { AbstractDTO } from '../shared/abstract.dto';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { ApplicationMethodsTypeEnum } from '@prisma/client';
import { PaperApplication } from '../paper-applications/paper-application.dto';
import { hasHttps } from '../../decorators/hasHttps.decorator';

export class ApplicationMethod extends AbstractDTO {
@Expose()
Expand All @@ -36,6 +39,14 @@ export class ApplicationMethod extends AbstractDTO {
@IsString({ groups: [ValidationsGroupsEnum.default] })
@MaxLength(4096, { groups: [ValidationsGroupsEnum.default] })
@ApiPropertyOptional()
@ValidateIf((o) => o.type === ApplicationMethodsTypeEnum.ExternalLink, {
groups: [ValidationsGroupsEnum.default],
})
@hasHttps({ groups: [ValidationsGroupsEnum.default] })
@IsUrl(
{ require_protocol: true },
{ groups: [ValidationsGroupsEnum.default] },
)
externalReference?: string;

@Expose()
Expand Down
9 changes: 9 additions & 0 deletions api/src/dtos/listings/listing-event.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {
IsDefined,
IsString,
ValidateNested,
ValidateIf,
IsUrl,
} from 'class-validator';
import { ValidationsGroupsEnum } from '../../enums/shared/validation-groups-enum';
import { ListingEventsTypeEnum } from '@prisma/client';
Expand Down Expand Up @@ -43,6 +45,13 @@ export class ListingEvent extends AbstractDTO {
@Expose()
@IsString({ groups: [ValidationsGroupsEnum.default] })
@ApiPropertyOptional()
@ValidateIf((o) => o.url && o.url.length > 0, {
groups: [ValidationsGroupsEnum.default],
})
@IsUrl(
{ require_protocol: true },
{ groups: [ValidationsGroupsEnum.default] },
)
url?: string;

@Expose()
Expand Down
5 changes: 5 additions & 0 deletions api/src/dtos/listings/listing.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
IsEnum,
IsNumber,
IsString,
IsUrl,
MaxLength,
ValidateNested,
} from 'class-validator';
Expand Down Expand Up @@ -192,6 +193,10 @@ class Listing extends AbstractDTO {
@Expose()
@IsString({ groups: [ValidationsGroupsEnum.default] })
@ApiPropertyOptional()
@IsUrl(
{ require_protocol: true },
{ groups: [ValidationsGroupsEnum.default] },
)
buildingSelectionCriteria?: string;

@Expose()
Expand Down
6 changes: 5 additions & 1 deletion api/src/dtos/multiselect-questions/multiselect-link.dto.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Expose } from 'class-transformer';
import { IsString, IsDefined } from 'class-validator';
import { IsString, IsDefined, IsUrl } from 'class-validator';
import { ValidationsGroupsEnum } from '../../enums/shared/validation-groups-enum';
import { ApiProperty } from '@nestjs/swagger';

Expand All @@ -14,5 +14,9 @@ export class MultiselectLink {
@IsString({ groups: [ValidationsGroupsEnum.default] })
@IsDefined({ groups: [ValidationsGroupsEnum.default] })
@ApiProperty()
@IsUrl(
{ require_protocol: true },
{ groups: [ValidationsGroupsEnum.default] },
)
url: string;
}
2 changes: 1 addition & 1 deletion api/test/integration/listing.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ describe('Listing Controller Tests', () => {
applicationDropOffAddressOfficeHours: 'drop off office hours string',
applicationDropOffAddressType: ApplicationAddressTypeEnum.leasingAgent,
applicationMailingAddressType: ApplicationAddressTypeEnum.leasingAgent,
buildingSelectionCriteria: 'selection criteria',
buildingSelectionCriteria: 'https://selection-criteria.com',
costsNotIncluded: 'all costs included',
creditHistory: 'credit history',
criminalBackground: 'criminal background',
Expand Down
24 changes: 12 additions & 12 deletions api/test/integration/multiselect-question.e2e-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,11 @@ describe('MultiselectQuestion Controller Tests', () => {
links: [
{
title: 'title 1',
url: 'title 1',
url: 'https://title-1.com',
},
{
title: 'title 2',
url: 'title 2',
url: 'https://title-2.com',
},
],
jurisdictions: [{ id: jurisdictionId }],
Expand All @@ -162,7 +162,7 @@ describe('MultiselectQuestion Controller Tests', () => {
links: [
{
title: 'title 3',
url: 'title 3',
url: 'https://title-3.com',
},
],
collectAddress: true,
Expand All @@ -175,7 +175,7 @@ describe('MultiselectQuestion Controller Tests', () => {
links: [
{
title: 'title 4',
url: 'title 4',
url: 'https://title-4.com',
},
],
collectAddress: true,
Expand Down Expand Up @@ -204,11 +204,11 @@ describe('MultiselectQuestion Controller Tests', () => {
links: [
{
title: 'title 1',
url: 'title 1',
url: 'https://title-1.com',
},
{
title: 'title 2',
url: 'title 2',
url: 'https://title-2.com',
},
],
jurisdictions: [{ id: jurisdictionId }],
Expand All @@ -220,7 +220,7 @@ describe('MultiselectQuestion Controller Tests', () => {
links: [
{
title: 'title 3',
url: 'title 3',
url: 'https://title-3.com',
},
],
collectAddress: true,
Expand All @@ -233,7 +233,7 @@ describe('MultiselectQuestion Controller Tests', () => {
links: [
{
title: 'title 4',
url: 'title 4',
url: 'https://title-4.com',
},
],
collectAddress: true,
Expand Down Expand Up @@ -266,11 +266,11 @@ describe('MultiselectQuestion Controller Tests', () => {
links: [
{
title: 'title 1',
url: 'title 1',
url: 'https://title-1.com',
},
{
title: 'title 2',
url: 'title 2',
url: 'https://title-2.com',
},
],
jurisdictions: [{ id: jurisdictionId }],
Expand All @@ -282,7 +282,7 @@ describe('MultiselectQuestion Controller Tests', () => {
links: [
{
title: 'title 3',
url: 'title 3',
url: 'https://title-3.com',
},
],
collectAddress: true,
Expand All @@ -295,7 +295,7 @@ describe('MultiselectQuestion Controller Tests', () => {
links: [
{
title: 'title 4',
url: 'title 4',
url: 'https://title-4.com',
},
],
collectAddress: true,
Expand Down
18 changes: 9 additions & 9 deletions api/test/integration/permission-tests/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,11 @@ export const buildMultiselectQuestionCreateMock = (
links: [
{
title: 'title 1',
url: 'title 1',
url: 'https://title-1.com',
},
{
title: 'title 2',
url: 'title 2',
url: 'https://title-2.com',
},
],
jurisdictions: [{ id: jurisId }],
Expand All @@ -181,7 +181,7 @@ export const buildMultiselectQuestionCreateMock = (
links: [
{
title: 'title 3',
url: 'title 3',
url: 'https://title-3.com',
},
],
collectAddress: true,
Expand All @@ -194,7 +194,7 @@ export const buildMultiselectQuestionCreateMock = (
links: [
{
title: 'title 4',
url: 'title 4',
url: 'https://title-4.com',
},
],
collectAddress: true,
Expand All @@ -219,11 +219,11 @@ export const buildMultiselectQuestionUpdateMock = (
links: [
{
title: 'title 1',
url: 'title 1',
url: 'https://title-1.com',
},
{
title: 'title 2',
url: 'title 2',
url: 'https://title-2.com',
},
],
jurisdictions: [{ id: jurisId }],
Expand All @@ -235,7 +235,7 @@ export const buildMultiselectQuestionUpdateMock = (
links: [
{
title: 'title 3',
url: 'title 3',
url: 'https://title-3.com',
},
],
collectAddress: true,
Expand All @@ -248,7 +248,7 @@ export const buildMultiselectQuestionUpdateMock = (
links: [
{
title: 'title 4',
url: 'title 4',
url: 'https://title-4.com',
},
],
collectAddress: true,
Expand Down Expand Up @@ -662,7 +662,7 @@ export const constructFullListingData = async (
applicationDropOffAddressOfficeHours: 'drop off office hours string',
applicationDropOffAddressType: ApplicationAddressTypeEnum.leasingAgent,
applicationMailingAddressType: ApplicationAddressTypeEnum.leasingAgent,
buildingSelectionCriteria: 'selection criteria',
buildingSelectionCriteria: 'https://selection-criteria.com',
costsNotIncluded: 'all costs included',
creditHistory: 'credit history',
criminalBackground: 'criminal background',
Expand Down
2 changes: 1 addition & 1 deletion api/test/unit/services/listing.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ describe('Testing listing service', () => {
applicationDropOffAddressOfficeHours: 'drop off office hours string',
applicationDropOffAddressType: ApplicationAddressTypeEnum.leasingAgent,
applicationMailingAddressType: ApplicationAddressTypeEnum.leasingAgent,
buildingSelectionCriteria: 'selection criteria',
buildingSelectionCriteria: 'https://selection-criteria.com',
costsNotIncluded: 'all costs included',
creditHistory: 'credit history',
criminalBackground: 'criminal background',
Expand Down

0 comments on commit d926e8f

Please sign in to comment.