Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions src/Rokt-Kit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,11 @@ function generateThankYouElementScript(domain: string | undefined) {

function generateBaseUrl(domain: string | undefined) {
const resolvedDomain = typeof domain !== 'undefined' ? domain : DEFAULT_ROKT_DOMAIN;

if (resolvedDomain.includes('://')) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about keeping reporting on the API domain for non-HTTP schemes, or separating the asset and reporting base URLs? Because generateReportingUrl also calls generateBaseUrl. maybe something like:

const hasNonHttpScheme = domain?.includes('://') && !/^https?:\/\//i.test(domain);
const reportingDomain = hasNonHttpScheme ? undefined : domain;

return generateBaseUrl(reportingDomain) + endpoint;

This keeps bare CNAME and HTTP(S) reporting behavior while falling back to the default API domain for extension schemes.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — I missed that generateBaseUrl is shared with reporting. Fixed in 365c143: generateReportingUrl now falls back to the default API domain for non-http(s) schemes (your snippet), so bare-host and http(s) reporting are unchanged, while an extension domain reports to apps.rokt-api.com instead of chrome-extension://…/v1/log. Added a test proving a chrome-extension:// integrationDomain falls back to the API error URL, plus one proving a full https:// integrationDomain is used verbatim.

return resolvedDomain.replace(/\/+$/, '');
}

const protocol = 'https://';

return [protocol, resolvedDomain].join('');
Expand All @@ -331,7 +336,10 @@ function generateReportingUrl(configuredUrl: string | undefined, domain: string
return 'https://' + configuredUrl;
}

return generateBaseUrl(domain) + endpoint;
const hasNonHttpScheme = domain?.includes('://') && !/^https?:\/\//i.test(domain);
const reportingDomain = hasNonHttpScheme ? undefined : domain;

return generateBaseUrl(reportingDomain) + endpoint;
}

function loadRoktScript(
Expand Down Expand Up @@ -511,6 +519,10 @@ function sendAdBlockMeasurementSignals(domain: string | undefined, version: stri
return;
}

if (domain && domain.includes('://') && !/^https:\/\//i.test(domain)) {
return;
}

const pageUrl = window.location.href.split('?')[0].split('#')[0];
const params =
'version=' +
Expand All @@ -520,8 +532,8 @@ function sendAdBlockMeasurementSignals(domain: string | undefined, version: stri
'&pageUrl=' +
encodeURIComponent(pageUrl);

const existingDomain = domain || 'apps.rokt.com';
createAutoRemovedIframe('https://' + existingDomain + '/v1/wsdk-init/index.html?' + params);
const existingBaseUrl = domain ? generateBaseUrl(domain) : 'https://apps.rokt.com';
createAutoRemovedIframe(existingBaseUrl + '/v1/wsdk-init/index.html?' + params);

createAutoRemovedIframe(
'https://' + ADBLOCK_CONTROL_DOMAIN + '/v1/wsdk-init/index.html?' + params + '&isControl=true',
Expand Down
81 changes: 81 additions & 0 deletions test/src/tests.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4117,6 +4117,24 @@ describe('Rokt Forwarder', () => {
);
});

it('should use a chrome-extension origin verbatim so the launcher loads from the bundled extension', () => {
expect(
(window as any).mParticle.forwarder.testHelpers.generateLauncherScript('chrome-extension://abcdef123/rokt'),
).toBe('chrome-extension://abcdef123/rokt/wsdk/integrations/launcher.js');
});

it('should trim a trailing slash from a full origin so the path join stays clean', () => {
expect(
(window as any).mParticle.forwarder.testHelpers.generateLauncherScript('chrome-extension://abcdef123/rokt/'),
).toBe('chrome-extension://abcdef123/rokt/wsdk/integrations/launcher.js');
});

it('should preserve an http origin for local development', () => {
expect((window as any).mParticle.forwarder.testHelpers.generateLauncherScript('http://localhost:8001')).toBe(
'http://localhost:8001/wsdk/integrations/launcher.js',
);
});

it('should return base URL when no extensions are provided', () => {
const url = (window as any).mParticle.forwarder.testHelpers.generateLauncherScript();
expect(url).toBe(baseUrl);
Expand Down Expand Up @@ -4165,6 +4183,13 @@ describe('Rokt Forwarder', () => {
const url = (window as any).mParticle.forwarder.testHelpers.generateThankYouElementScript('cname.rokt.com');
expect(url).toBe('https://cname.rokt.com/rokt-elements/rokt-element-thank-you.js');
});

it('should use a full custom origin verbatim', () => {
const url = (window as any).mParticle.forwarder.testHelpers.generateThankYouElementScript(
'chrome-extension://abcdef123/rokt',
);
expect(url).toBe('chrome-extension://abcdef123/rokt/rokt-elements/rokt-element-thank-you.js');
});
});

describe('#roktExtensions', () => {
Expand Down Expand Up @@ -6973,6 +6998,42 @@ describe('Rokt Forwarder', () => {
expect(defaultDomainIframe).toBeTruthy();
});

it('should still create the probe for a full https origin', () => {
Math.random = () => 0.05;
(window as any).__rokt_li_guid__ = 'test-guid-123';

(window as any).mParticle.forwarder.testHelpers.sendAdBlockMeasurementSignals(
'https://custom.rokt.com',
'test-version',
);

const iframes = document.querySelectorAll('iframe');
const srcs = Array.prototype.map.call(iframes, (iframe: any) => iframe.src) as string[];

const httpsDomainIframe = srcs.find(
(src) => src.indexOf('https://custom.rokt.com/v1/wsdk-init/index.html') !== -1,
);

expect(httpsDomainIframe).toBeTruthy();
});

it('should not create the probe for a chrome-extension origin', () => {
Math.random = () => 0.05;
(window as any).__rokt_li_guid__ = 'test-guid-123';

(window as any).mParticle.forwarder.testHelpers.sendAdBlockMeasurementSignals(
'chrome-extension://abcdef123/rokt',
'test-version',
);

const iframes = document.querySelectorAll('iframe');
const srcs = Array.prototype.map.call(iframes, (iframe: any) => iframe.src) as string[];

const anyProbe = srcs.find((src) => src.indexOf('/v1/wsdk-init/index.html') !== -1);

expect(anyProbe).toBeUndefined();
});

it('should not create iframes when sampled out', () => {
Math.random = () => 0.5; // Above 0.1 threshold
(window as any).__rokt_li_guid__ = 'test-guid-123';
Expand Down Expand Up @@ -7262,6 +7323,26 @@ describe('Rokt Forwarder', () => {
expect(fetchCalls[0].url).toBe('https://apps.rokt-api.com/v1/errors');
});

it('should use a full https integration domain for the error URL', () => {
const service = new ErrorReportingServiceClass(
{ isLoggingEnabled: true, integrationDomain: 'https://custom.rokt.com' },
'1.0.0',
'test-guid',
);
service.report({ message: 'test error', severity: WSDKErrorSeverityConst.ERROR });
expect(fetchCalls[0].url).toBe('https://custom.rokt.com/v1/errors');
});

it('should fall back to the default error URL for a chrome-extension integration domain', () => {
const service = new ErrorReportingServiceClass(
{ isLoggingEnabled: true, integrationDomain: 'chrome-extension://abcdef123/rokt' },
'1.0.0',
'test-guid',
);
service.report({ message: 'test error', severity: WSDKErrorSeverityConst.ERROR });
expect(fetchCalls[0].url).toBe('https://apps.rokt-api.com/v1/errors');
});

it('should include all required fields in the log request body', () => {
const service = new ErrorReportingServiceClass({ isLoggingEnabled: true }, 'test-integration', 'test-guid');
service.report({
Expand Down
Loading