import { StepBuilder } from "../../../src/steps/stepBuilder"; import { FakeRequestBuilder } from "../fakeRequestBuilder"; import CategoryService from "../../../src/services/category.service"; import { CategoryRating, CategoryProviderType } from "../../../src/categories/categoryProvider"; import { reset, verify, mock, when, instance, objectContaining } from "ts-mockito"; import FeatureConfigFake from "../fake/FeatureConfigFake"; import { FeatureConfigService } from "../../../src/services/FeatureConfig.service"; import { expect } from "chai"; import { StepResult } from "../../../src/steps/stepResult"; import { FakeCampaign } from "../fake/Campaign"; import { MockCategoryValue } from "../../../src/categories/mockCategoryProvider"; import { CampaignModelFake } from "../fake/CampaignModelFake"; import { CampaignModel } from "../../../src/models/CampaignModel"; import PublisherFraudStep from "../../../src/steps/prebid/publisherFraud.step"; import { ChoiceRequest } from "../../../src/models/request.model"; const featureConfigService = FeatureConfigService.getInstance(); const mockedFeatureConf: FeatureConfigFake = new FeatureConfigFake(); const campaignModel: CampaignModel = new CampaignModelFake(); const innerPublisherFraudStep = new PublisherFraudStep( campaignModel, CategoryProviderType.DV, false ); const publisherFraudStep = new StepBuilder(innerPublisherFraudStep).build(); let categoryService: CategoryService; describe("PublisherFraudStep", function () { before(async () => { categoryService = mock(CategoryService); innerPublisherFraudStep.categoryService = instance(categoryService); (innerPublisherFraudStep as any).featureConfigService = featureConfigService; featureConfigService.setFeatureConfig(mockedFeatureConf); }); after(async () => {}); beforeEach(async () => { reset(categoryService); when( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/safe")), CategoryProviderType.DV ) ).thenResolve(new MockCategoryValue("safe")); when( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafe")), CategoryProviderType.DV ) ).thenResolve(new MockCategoryValue("unsafe")); when( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unknown")), CategoryProviderType.DV ) ).thenResolve(new MockCategoryValue("unknown")); when( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafeMedium")), CategoryProviderType.DV ) ).thenResolve(new MockCategoryValue("safe:unsafe:unsafe")); when( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafeLow")), CategoryProviderType.DV ) ).thenResolve(new MockCategoryValue("safe:safe:unsafe")); when( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/safeWar")), CategoryProviderType.DV ) ).thenResolve(new MockCategoryValue("safe:safe:safe:80222009")); }); describe("Application are always safe", function () { it("should flag this app bundle as safe", async function () { const request = new FakeRequestBuilder() .withValidIpAndUserAgent() .withAppBundleOrDomain("http://www.ogury.com/unsafe") .withEnvironmentType("in-app") .withPrebid({ type: "publisher-fraud", provider: "dv" }) .withDeviceOS("android") .build(); const stepRes = await publisherFraudStep.execute(request); shouldBeSafe(stepRes, false, true, undefined, undefined); expect(request.campaigns[0].stepsPassedStatus["pass_publisher_fraud_dv"]).to.be.equal( "bypassed" ); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafe")), CategoryProviderType.DV ) ).never(); }); it("should flag unknown appbundle as safe ", async function () { const request = new FakeRequestBuilder() .withValidIpAndUserAgent() .withAppBundleOrDomain("http://www.ogury.com/unknown") .withEnvironmentType("in-app") .withPrebid({ type: "publisher-fraud", provider: "dv" }) .withDeviceOS("android") .build(); const stepRes = await publisherFraudStep.execute(request); shouldBeSafe(stepRes, false, true, undefined, undefined); expect(request.campaigns[0].stepsPassedStatus["pass_publisher_fraud_dv"]).to.be.equal( "bypassed" ); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafe")), CategoryProviderType.DV ) ).never(); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/safe")), CategoryProviderType.DV ) ).never(); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unknown")), CategoryProviderType.DV ) ).never(); }); }); describe("Publisher fraud (WEB)", function () { it("should flag this domain as unsafe", async function () { const request = new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unsafe") .withPrebid({ type: "publisher-fraud", provider: "dv" }) .withEnvironmentType("web") .build(); const stepRes = await publisherFraudStep.execute(request); shouldBeSafe(stepRes, true, false, CategoryRating.Unsafe, CategoryRating.Unsafe); checkPrebidResult(request, CategoryProviderType.DV, CategoryRating.Unsafe); const excluded = request?.excluded || []; expect(excluded[0].stepsPassedStatus["pass_publisher_fraud_dv"]).to.be.equal("false"); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafe")), CategoryProviderType.DV ) ).once(); }); it("should flag this domain as unsafe with multiple campaigns", async function () { const request = new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unsafe") .withEnvironmentType("web") .withCampaigns( new FakeCampaign("10001"), new FakeCampaign("10002"), new FakeCampaign("10003") ) .withCampaignPrebid("10002", { type: "publisher-fraud", provider: "ias" }) .withPrebid({ type: "publisher-fraud", provider: "dv" }) .withCampaignPrebid("10003", { type: "publisher-fraud", provider: "ias" }) .build(); const stepRes = await publisherFraudStep.execute(request); shouldBeSafe(stepRes, true, false, CategoryRating.Unsafe, CategoryRating.Unsafe); checkPrebidResult(request, CategoryProviderType.DV, CategoryRating.Unsafe); const excluded = request?.excluded || []; expect(excluded[0].stepsPassedStatus["pass_publisher_fraud_dv"]).to.be.equal("false"); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafe")), CategoryProviderType.DV ) ).once(); }); it("should flag this domain as unsafe with multiple campaigns on other provider", async function () { const request = new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unsafe") .withEnvironmentType("web") .withCampaigns( new FakeCampaign("10001"), new FakeCampaign("10002"), new FakeCampaign("10003") ) .withPrebid({ type: "publisher-fraud", provider: "ias" }) .build(); const stepRes = await publisherFraudStep.execute(request); shouldBeSafe(stepRes, true, true, undefined, undefined); expect(request.campaigns[0].stepsPassedStatus["pass_publisher_fraud_dv"]).to.be.equal( "bypassed" ); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafe")), CategoryProviderType.DV ) ).never(); }); it("should flag this domain as unsafe with multiple campaigns and various provider", async function () { const request = new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unsafe") .withEnvironmentType("web") .withCampaigns( new FakeCampaign("10001"), new FakeCampaign("10002"), new FakeCampaign("10003") ) .withCampaignPrebid("10001", { type: "publisher-fraud", provider: "dv" }) .withCampaignPrebid("10002", { type: "publisher-fraud", provider: "ias" }) .withCampaignPrebid("10003", { type: "publisher-fraud", provider: "dv" }) .build(); const stepRes = await publisherFraudStep.execute(request); shouldBeSafeWithoutCampaignLength( stepRes, true, false, CategoryRating.Unsafe, CategoryRating.Unsafe ); stepRes.passedCampaigns.length.should.be.equal(1); stepRes.passedCampaigns[0].id.should.be.equal("10002"); checkPrebidResult(request, CategoryProviderType.DV, CategoryRating.Unsafe); const excluded = request?.excluded || []; expect(excluded[0].stepsPassedStatus["pass_publisher_fraud_dv"]).to.be.equal("false"); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafe")), CategoryProviderType.DV ) ).once(); }); it("should flag this domain as safe", async function () { const stepRes = await publisherFraudStep.execute( new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/safe") .withPrebid({ type: "publisher-fraud", provider: "dv" }) .withEnvironmentType("web") .build() ); shouldBeSafe(stepRes, true, true, CategoryRating.Safe, CategoryRating.Safe); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/safe")), CategoryProviderType.DV ) ).once(); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafe")), CategoryProviderType.DV ) ).never(); }); it("should flag this unknown domain as unsafe", async function () { const stepRes = await publisherFraudStep.execute( new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unknown") .withPrebid({ type: "publisher-fraud", provider: "dv" }) .withEnvironmentType("web") .build() ); shouldBeSafe(stepRes, true, false, CategoryRating.Unknown, CategoryRating.Unknown); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unknown")), CategoryProviderType.DV ) ).once(); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafe")), CategoryProviderType.DV ) ).never(); }); it("should flag this unknown domain as safe", async function () { mockedFeatureConf.setParam("ms-choices.publisher-fraud.allow-unknown.dv", "true"); const stepRes = await publisherFraudStep.execute( new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unknown") .withPrebid({ type: "publisher-fraud", provider: "dv" }) .withEnvironmentType("web") .build() ); shouldBeSafe(stepRes, true, true, CategoryRating.Unknown, CategoryRating.Unknown); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unknown")), CategoryProviderType.DV ) ).once(); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafe")), CategoryProviderType.DV ) ).never(); }); describe("Publisher fraud check with different level with medium unsafe", function () { it("should flag this domain as safe", async function () { mockedFeatureConf.removeParams(["ms-choices.publisher-fraud.severity.dv"]); const stepRes = await publisherFraudStep.execute( new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unsafeMedium") .withPrebid({ type: "publisher-fraud", provider: "dv" }) .withEnvironmentType("web") .build() ); shouldBeSafe(stepRes, true, true, CategoryRating.Safe, CategoryRating.Unsafe); }); it("should flag this domain as safe with featureConfig High", async function () { mockedFeatureConf.setParam("ms-choices.publisher-fraud.severity.dv", "high"); const stepRes = await publisherFraudStep.execute( new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unsafeMedium") .withPrebid({ type: "publisher-fraud", provider: "dv" }) .withEnvironmentType("web") .build() ); shouldBeSafe(stepRes, true, true, CategoryRating.Safe, CategoryRating.Unsafe); }); it("should flag this domain as safe with garbage featureConfig ", async function () { mockedFeatureConf.setParam("ms-choices.publisher-fraud.severity.dv", "garbage"); const stepRes = await publisherFraudStep.execute( new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unsafeMedium") .withPrebid({ type: "publisher-fraud", provider: "dv" }) .withEnvironmentType("web") .build() ); shouldBeSafe(stepRes, true, true, CategoryRating.Safe, CategoryRating.Unsafe); }); it("should flag this domain as unsafe with featureConfig medium ", async function () { mockedFeatureConf.setParam("ms-choices.publisher-fraud.severity.dv", "medium"); const stepRes = await publisherFraudStep.execute( new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unsafeMedium") .withPrebid({ type: "publisher-fraud", provider: "dv" }) .withEnvironmentType("web") .build() ); shouldBeSafe(stepRes, true, false, CategoryRating.Safe, CategoryRating.Unsafe); }); }); }); }); function shouldBeSafe( stepRes: StepResult, webmobile: boolean, passed: boolean, high: CategoryRating | undefined, medium: CategoryRating | undefined ) { const passedCampaignLength = stepRes.passedCampaigns.length; if (passed) { passedCampaignLength.should.be.above(0); } else { passedCampaignLength.should.be.equal(0); } shouldBeSafeWithoutCampaignLength(stepRes, webmobile, passed, high, medium); } function shouldBeSafeWithoutCampaignLength( stepRes: StepResult, webmobile: boolean, passed: boolean, high: CategoryRating | undefined, medium: CategoryRating | undefined ) { expect(stepRes.getMetricLabel("is_web_mobile")).to.be.equal(String(webmobile)); expect(stepRes.getMetricLabel("passed_publisher_fraud")).to.be.equal(String(passed)); expect(stepRes.getMetricLabel("publisher_fraud_high")).to.be.equal(high); expect(stepRes.getMetricLabel("publisher_fraud_medium")).to.be.equal(medium); } function expectedRequest(url: string): Object { return { site: { page: url, }, }; } function checkPrebidResult(request: ChoiceRequest, provider: CategoryProviderType, value: string) { expect(request.metadata.prebid_result).to.be.not.null; const result = request.metadata.prebid_result?.filter( (value) => value.step === "publisher_fraud" && value.provider === provider ); expect(result?.length).to.be.equal(1); expect(result![0].result).to.be.equal(value); }