mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 01:56:46 +00:00
feat: Proxy all RudderStack frontend telemetry events through the backend (#17177)
Co-authored-by: Nikhil Kuriakose <nikhil.kuriakose@n8n.io>
This commit is contained in:
@@ -31,6 +31,8 @@ describe('NpsSurvey', () => {
|
|||||||
config: {
|
config: {
|
||||||
key: 'test',
|
key: 'test',
|
||||||
url: 'https://telemetry-test.n8n.io',
|
url: 'https://telemetry-test.n8n.io',
|
||||||
|
proxy: 'http://localhost:5678/rest/telemetry/proxy',
|
||||||
|
sourceConfig: 'http://localhost:5678/rest/telemetry/rudderstack',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -77,6 +79,8 @@ describe('NpsSurvey', () => {
|
|||||||
config: {
|
config: {
|
||||||
key: 'test',
|
key: 'test',
|
||||||
url: 'https://telemetry-test.n8n.io',
|
url: 'https://telemetry-test.n8n.io',
|
||||||
|
proxy: 'http://localhost:5678/rest/telemetry/proxy',
|
||||||
|
sourceConfig: 'http://localhost:5678/rest/telemetry/rudderstack',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ export interface IVersionNotificationSettings {
|
|||||||
export interface ITelemetryClientConfig {
|
export interface ITelemetryClientConfig {
|
||||||
url: string;
|
url: string;
|
||||||
key: string;
|
key: string;
|
||||||
|
proxy: string;
|
||||||
|
sourceConfig: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITelemetrySettings {
|
export interface ITelemetrySettings {
|
||||||
|
|||||||
@@ -130,6 +130,7 @@
|
|||||||
"formidable": "3.5.4",
|
"formidable": "3.5.4",
|
||||||
"handlebars": "4.7.8",
|
"handlebars": "4.7.8",
|
||||||
"helmet": "8.1.0",
|
"helmet": "8.1.0",
|
||||||
|
"http-proxy-middleware": "^3.0.5",
|
||||||
"infisical-node": "1.3.0",
|
"infisical-node": "1.3.0",
|
||||||
"ioredis": "5.3.2",
|
"ioredis": "5.3.2",
|
||||||
"isbot": "3.6.13",
|
"isbot": "3.6.13",
|
||||||
|
|||||||
59
packages/cli/src/controllers/telemetry.controller.ts
Normal file
59
packages/cli/src/controllers/telemetry.controller.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import { GlobalConfig } from '@n8n/config';
|
||||||
|
import { AuthenticatedRequest } from '@n8n/db';
|
||||||
|
import { Get, Post, RestController } from '@n8n/decorators';
|
||||||
|
import { NextFunction, Response } from 'express';
|
||||||
|
import { createProxyMiddleware, fixRequestBody } from 'http-proxy-middleware';
|
||||||
|
|
||||||
|
@RestController('/telemetry')
|
||||||
|
export class TelemetryController {
|
||||||
|
proxy;
|
||||||
|
|
||||||
|
constructor(private readonly globalConfig: GlobalConfig) {
|
||||||
|
this.proxy = createProxyMiddleware({
|
||||||
|
target: this.globalConfig.diagnostics.frontendConfig.split(';')[1],
|
||||||
|
changeOrigin: true,
|
||||||
|
pathRewrite: {
|
||||||
|
'^/proxy/': '/', // /proxy/v1/track -> /v1/track
|
||||||
|
},
|
||||||
|
on: {
|
||||||
|
proxyReq: (proxyReq, req) => {
|
||||||
|
proxyReq.removeHeader('cookie');
|
||||||
|
fixRequestBody(proxyReq, req);
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('/proxy/:version/track', { skipAuth: true, rateLimit: { limit: 100, windowMs: 60_000 } })
|
||||||
|
async track(req: AuthenticatedRequest, res: Response, next: NextFunction) {
|
||||||
|
await this.proxy(req, res, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('/proxy/:version/identify', { skipAuth: true, rateLimit: true })
|
||||||
|
async identify(req: AuthenticatedRequest, res: Response, next: NextFunction) {
|
||||||
|
await this.proxy(req, res, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('/proxy/:version/page', { skipAuth: true, rateLimit: { limit: 50, windowMs: 60_000 } })
|
||||||
|
async page(req: AuthenticatedRequest, res: Response, next: NextFunction) {
|
||||||
|
await this.proxy(req, res, next);
|
||||||
|
}
|
||||||
|
@Get('/rudderstack/sourceConfig', { skipAuth: true, rateLimit: { limit: 50, windowMs: 60_000 } })
|
||||||
|
async sourceConfig() {
|
||||||
|
const response = await fetch('https://api-rs.n8n.io/sourceConfig', {
|
||||||
|
headers: {
|
||||||
|
authorization:
|
||||||
|
'Basic ' + btoa(`${this.globalConfig.diagnostics.frontendConfig.split(';')[0]}:`),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Failed to fetch source config: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const config: unknown = await response.json();
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -151,6 +151,10 @@ export class Server extends AbstractServer {
|
|||||||
this.logger.warn(`SAML initialization failed: ${(error as Error).message}`);
|
this.logger.warn(`SAML initialization failed: ${(error as Error).message}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.globalConfig.diagnostics.enabled) {
|
||||||
|
await import('@/controllers/telemetry.controller');
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
// OIDC
|
// OIDC
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
|
|||||||
@@ -89,13 +89,15 @@ export class FrontendService {
|
|||||||
if (telemetrySettings.enabled) {
|
if (telemetrySettings.enabled) {
|
||||||
const conf = this.globalConfig.diagnostics.frontendConfig;
|
const conf = this.globalConfig.diagnostics.frontendConfig;
|
||||||
const [key, url] = conf.split(';');
|
const [key, url] = conf.split(';');
|
||||||
|
const proxy = `${instanceBaseUrl}/${restEndpoint}/telemetry/proxy`;
|
||||||
|
const sourceConfig = `${instanceBaseUrl}/${restEndpoint}/telemetry/rudderstack`;
|
||||||
|
|
||||||
if (!key || !url) {
|
if (!key || !url) {
|
||||||
this.logger.warn('Diagnostics frontend config is invalid');
|
this.logger.warn('Diagnostics frontend config is invalid');
|
||||||
telemetrySettings.enabled = false;
|
telemetrySettings.enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
telemetrySettings.config = { key, url };
|
telemetrySettings.config = { key, url, proxy, sourceConfig };
|
||||||
}
|
}
|
||||||
|
|
||||||
this.settings = {
|
this.settings = {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ describe('telemetry', () => {
|
|||||||
setActivePinia(createPinia());
|
setActivePinia(createPinia());
|
||||||
settingsStore = useSettingsStore();
|
settingsStore = useSettingsStore();
|
||||||
telemetry.init(
|
telemetry.init(
|
||||||
{ enabled: true, config: { url: '', key: '' } },
|
{ enabled: true, config: { proxy: '', key: '', sourceConfig: '', url: '' } },
|
||||||
{ versionCli: '1', instanceId: '1' },
|
{ versionCli: '1', instanceId: '1' },
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export class Telemetry {
|
|||||||
if (!telemetrySettings.enabled || !telemetrySettings.config || this.rudderStack) return;
|
if (!telemetrySettings.enabled || !telemetrySettings.config || this.rudderStack) return;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
config: { key, url },
|
config: { key, proxy, sourceConfig },
|
||||||
} = telemetrySettings;
|
} = telemetrySettings;
|
||||||
|
|
||||||
const settingsStore = useSettingsStore();
|
const settingsStore = useSettingsStore();
|
||||||
@@ -57,10 +57,10 @@ export class Telemetry {
|
|||||||
|
|
||||||
const logging = logLevel === 'debug' ? { logLevel: 'DEBUG' } : {};
|
const logging = logLevel === 'debug' ? { logLevel: 'DEBUG' } : {};
|
||||||
|
|
||||||
this.initRudderStack(key, url, {
|
this.initRudderStack(key, proxy, {
|
||||||
integrations: { All: false },
|
integrations: { All: false },
|
||||||
loadIntegration: false,
|
loadIntegration: false,
|
||||||
configUrl: 'https://api-rs.n8n.io',
|
configUrl: sourceConfig,
|
||||||
...logging,
|
...logging,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -201,7 +201,7 @@ export class Telemetry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private initRudderStack(key: string, url: string, options: IDataObject) {
|
private initRudderStack(key: string, proxy: string, options: IDataObject) {
|
||||||
window.rudderanalytics = window.rudderanalytics || [];
|
window.rudderanalytics = window.rudderanalytics || [];
|
||||||
if (!this.rudderStack) {
|
if (!this.rudderStack) {
|
||||||
return;
|
return;
|
||||||
@@ -252,7 +252,7 @@ export class Telemetry {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.rudderStack.loadJS();
|
this.rudderStack.loadJS();
|
||||||
this.rudderStack.load(key, url, options);
|
this.rudderStack.load(key, proxy, options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
37
pnpm-lock.yaml
generated
37
pnpm-lock.yaml
generated
@@ -1429,6 +1429,9 @@ importers:
|
|||||||
helmet:
|
helmet:
|
||||||
specifier: 8.1.0
|
specifier: 8.1.0
|
||||||
version: 8.1.0
|
version: 8.1.0
|
||||||
|
http-proxy-middleware:
|
||||||
|
specifier: ^3.0.5
|
||||||
|
version: 3.0.5
|
||||||
infisical-node:
|
infisical-node:
|
||||||
specifier: 1.3.0
|
specifier: 1.3.0
|
||||||
version: 1.3.0
|
version: 1.3.0
|
||||||
@@ -7089,6 +7092,9 @@ packages:
|
|||||||
'@types/html-to-text@9.0.4':
|
'@types/html-to-text@9.0.4':
|
||||||
resolution: {integrity: sha512-pUY3cKH/Nm2yYrEmDlPR1mR7yszjGx4DrwPjQ702C4/D5CwHuZTgZdIdwPkRbcuhs7BAh2L5rg3CL5cbRiGTCQ==}
|
resolution: {integrity: sha512-pUY3cKH/Nm2yYrEmDlPR1mR7yszjGx4DrwPjQ702C4/D5CwHuZTgZdIdwPkRbcuhs7BAh2L5rg3CL5cbRiGTCQ==}
|
||||||
|
|
||||||
|
'@types/http-proxy@1.17.16':
|
||||||
|
resolution: {integrity: sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==}
|
||||||
|
|
||||||
'@types/humanize-duration@3.27.1':
|
'@types/humanize-duration@3.27.1':
|
||||||
resolution: {integrity: sha512-K3e+NZlpCKd6Bd/EIdqjFJRFHbrq5TzPPLwREk5Iv/YoIjQrs6ljdAUCo+Lb2xFlGNOjGSE0dqsVD19cZL137w==}
|
resolution: {integrity: sha512-K3e+NZlpCKd6Bd/EIdqjFJRFHbrq5TzPPLwREk5Iv/YoIjQrs6ljdAUCo+Lb2xFlGNOjGSE0dqsVD19cZL137w==}
|
||||||
|
|
||||||
@@ -10849,6 +10855,14 @@ packages:
|
|||||||
resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
|
resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
|
||||||
engines: {node: '>= 14'}
|
engines: {node: '>= 14'}
|
||||||
|
|
||||||
|
http-proxy-middleware@3.0.5:
|
||||||
|
resolution: {integrity: sha512-GLZZm1X38BPY4lkXA01jhwxvDoOkkXqjgVyUzVxiEK4iuRu03PZoYHhHRwxnfhQMDuaxi3vVri0YgSro/1oWqg==}
|
||||||
|
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||||
|
|
||||||
|
http-proxy@1.18.1:
|
||||||
|
resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==}
|
||||||
|
engines: {node: '>=8.0.0'}
|
||||||
|
|
||||||
http-signature@1.4.0:
|
http-signature@1.4.0:
|
||||||
resolution: {integrity: sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg==}
|
resolution: {integrity: sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg==}
|
||||||
engines: {node: '>=0.10'}
|
engines: {node: '>=0.10'}
|
||||||
@@ -21621,6 +21635,10 @@ snapshots:
|
|||||||
|
|
||||||
'@types/html-to-text@9.0.4': {}
|
'@types/html-to-text@9.0.4': {}
|
||||||
|
|
||||||
|
'@types/http-proxy@1.17.16':
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 20.19.1
|
||||||
|
|
||||||
'@types/humanize-duration@3.27.1': {}
|
'@types/humanize-duration@3.27.1': {}
|
||||||
|
|
||||||
'@types/imap@0.8.40':
|
'@types/imap@0.8.40':
|
||||||
@@ -26311,6 +26329,25 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
http-proxy-middleware@3.0.5:
|
||||||
|
dependencies:
|
||||||
|
'@types/http-proxy': 1.17.16
|
||||||
|
debug: 4.4.1(supports-color@8.1.1)
|
||||||
|
http-proxy: 1.18.1(debug@4.4.1)
|
||||||
|
is-glob: 4.0.3
|
||||||
|
is-plain-object: 5.0.0
|
||||||
|
micromatch: 4.0.8
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
http-proxy@1.18.1(debug@4.4.1):
|
||||||
|
dependencies:
|
||||||
|
eventemitter3: 4.0.7
|
||||||
|
follow-redirects: 1.15.9(debug@4.4.1)
|
||||||
|
requires-port: 1.0.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- debug
|
||||||
|
|
||||||
http-signature@1.4.0:
|
http-signature@1.4.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
assert-plus: 1.0.0
|
assert-plus: 1.0.0
|
||||||
|
|||||||
Reference in New Issue
Block a user