Skip to content

Commit c60bbfb

Browse files
authored
Merge branch 'master' into ar2rsawseen/master2
2 parents c76b5b1 + f2d515e commit c60bbfb

File tree

20 files changed

+385
-145
lines changed

20 files changed

+385
-145
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ jobs:
244244
npx grunt mochaTest
245245
246246
ui-tests:
247-
runs-on: ubuntu-22.04-4core
247+
runs-on: ubuntu-latest
248248

249249
strategy:
250250
matrix:

CHANGELOG.md

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,28 @@
1-
## Version 25.03.X
1+
## Version 25.03.7
2+
Enterprise Features:
3+
- [funnels] Added explanatory tooltip for filters section on Funnel Detail page
4+
25
Fixes:
3-
- [star-rating] Fix consent text limit counter
6+
- [core] Applied some fixes to user-merge, togetExportScripts, sharding, delete_old_drill_events, add_indexes script
7+
- [core] Fix/docker python vulnerabilities
8+
- [core] Allow chrome to launch multiple instances to fix blank dashboard emails
9+
- [formulas] Fix loading state when selecting event count
410

511
Enterprise Fixes:
6-
- [active-users] Fixed bug related to selecting calculation ranges. As a result, some dates were previously calculated on incomplete data set.
12+
- [active-users] Fixed bug related to selecting calculation ranges. As a result, some dates were previously calculated on incomplete data set
13+
- [journey-engine] Undefined value check for cooldown in Engagement Queue
14+
- [star-rating] Fix consent text limit counter
715

16+
Dependencies:
17+
- Bump sass from 1.89.1 to 1.89.2
18+
- Bump puppeteer from 24.10.0 to 24.10.1
19+
- Bump countly-sdk-nodejs from 24.10.1 to 24.10.2
20+
- Bump sass-embedded in /plugins/content from 1.89.1 to 1.89.2
21+
- Bump @vue-flow/node-resizer in /plugins/content from 1.4.0 to 1.5.0
22+
- Bump @vue-flow/core in /plugins/content from 1.44.0 to 1.45.0
23+
- Bump vue-i18n in /plugins/content from 11.1.5 to 11.1.6
24+
- Bump terser in /plugins/content from 5.42.0 to 5.43.0
25+
- Bump mockttp in /plugins/crash_symbolication from 3.17.1 to 4.0.0
826

927
## Version 25.03.6
1028
Enterprise Features:

api/api.js

Lines changed: 101 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
const http = require('http');
2+
const https = require('https');
3+
const fs = require('fs');
24
const cluster = require('cluster');
35
const formidable = require('formidable');
46
const os = require('os');
@@ -357,88 +359,113 @@ plugins.connectToAllDatabases().then(function() {
357359

358360
plugins.dispatch("/worker", {common: common});
359361

360-
http.Server((req, res) => {
361-
const params = {
362-
qstring: {},
363-
res: res,
364-
req: req
362+
const serverOptions = {
363+
port: common.config.api.port,
364+
host: common.config.api.host || ''
365+
};
366+
367+
let server;
368+
if (common.config.api.ssl && common.config.api.ssl.enabled) {
369+
const sslOptions = {
370+
key: fs.readFileSync(common.config.api.ssl.key),
371+
cert: fs.readFileSync(common.config.api.ssl.cert)
365372
};
373+
if (common.config.api.ssl.ca) {
374+
sslOptions.ca = fs.readFileSync(common.config.api.ssl.ca);
375+
}
376+
server = https.createServer(sslOptions, handleRequest);
377+
}
378+
else {
379+
server = http.createServer(handleRequest);
380+
}
366381

367-
if (req.method.toLowerCase() === 'post') {
368-
const formidableOptions = {};
369-
if (countlyConfig.api.maxUploadFileSize) {
370-
formidableOptions.maxFileSize = countlyConfig.api.maxUploadFileSize;
371-
}
382+
server.listen(serverOptions.port, serverOptions.host).timeout = common.config.api.timeout || 120000;
383+
}
384+
});
372385

373-
const form = new formidable.IncomingForm(formidableOptions);
374-
if (/crash_symbols\/(add_symbol|upload_symbol)/.test(req.url)) {
375-
req.body = [];
376-
req.on('data', (data) => {
377-
req.body.push(data);
378-
});
386+
/**
387+
* Handle incoming HTTP/HTTPS requests
388+
* @param {http.IncomingMessage} req - The request object
389+
* @param {http.ServerResponse} res - The response object
390+
*/
391+
function handleRequest(req, res) {
392+
const params = {
393+
qstring: {},
394+
res: res,
395+
req: req
396+
};
397+
398+
if (req.method.toLowerCase() === 'post') {
399+
const formidableOptions = {};
400+
if (countlyConfig.api.maxUploadFileSize) {
401+
formidableOptions.maxFileSize = countlyConfig.api.maxUploadFileSize;
402+
}
403+
404+
const form = new formidable.IncomingForm(formidableOptions);
405+
if (/crash_symbols\/(add_symbol|upload_symbol)/.test(req.url)) {
406+
req.body = [];
407+
req.on('data', (data) => {
408+
req.body.push(data);
409+
});
410+
}
411+
else {
412+
req.body = '';
413+
req.on('data', (data) => {
414+
req.body += data;
415+
});
416+
}
417+
418+
let multiFormData = false;
419+
// Check if we have 'multipart/form-data'
420+
if (req.headers['content-type']?.startsWith('multipart/form-data')) {
421+
multiFormData = true;
422+
}
423+
424+
form.parse(req, (err, fields, files) => {
425+
//handle bakcwards compatability with formiddble v1
426+
for (let i in files) {
427+
if (files[i].filepath) {
428+
files[i].path = files[i].filepath;
379429
}
380-
else {
381-
req.body = '';
382-
req.on('data', (data) => {
383-
req.body += data;
384-
});
430+
if (files[i].mimetype) {
431+
files[i].type = files[i].mimetype;
385432
}
386-
387-
let multiFormData = false;
388-
// Check if we have 'multipart/form-data'
389-
if (req.headers['content-type']?.startsWith('multipart/form-data')) {
390-
multiFormData = true;
433+
if (files[i].originalFilename) {
434+
files[i].name = files[i].originalFilename;
391435
}
392-
393-
form.parse(req, (err, fields, files) => {
394-
//handle bakcwards compatability with formiddble v1
395-
for (let i in files) {
396-
if (files[i].filepath) {
397-
files[i].path = files[i].filepath;
398-
}
399-
if (files[i].mimetype) {
400-
files[i].type = files[i].mimetype;
401-
}
402-
if (files[i].originalFilename) {
403-
files[i].name = files[i].originalFilename;
404-
}
405-
}
406-
params.files = files;
407-
if (multiFormData) {
408-
let formDataUrl = [];
409-
for (const i in fields) {
410-
params.qstring[i] = fields[i];
411-
formDataUrl.push(`${i}=${fields[i]}`);
412-
}
413-
params.formDataUrl = formDataUrl.join('&');
414-
}
415-
else {
416-
for (const i in fields) {
417-
params.qstring[i] = fields[i];
418-
}
419-
}
420-
if (!params.apiPath) {
421-
processRequest(params);
422-
}
423-
});
424-
}
425-
else if (req.method.toLowerCase() === 'options') {
426-
const headers = {};
427-
headers["Access-Control-Allow-Origin"] = "*";
428-
headers["Access-Control-Allow-Methods"] = "POST, GET, OPTIONS";
429-
headers["Access-Control-Allow-Headers"] = "countly-token, Content-Type";
430-
res.writeHead(200, headers);
431-
res.end();
432436
}
433-
//attempt process GET request
434-
else if (req.method.toLowerCase() === 'get') {
435-
processRequest(params);
437+
params.files = files;
438+
if (multiFormData) {
439+
let formDataUrl = [];
440+
for (const i in fields) {
441+
params.qstring[i] = fields[i];
442+
formDataUrl.push(`${i}=${fields[i]}`);
443+
}
444+
params.formDataUrl = formDataUrl.join('&');
436445
}
437446
else {
438-
common.returnMessage(params, 405, "Method not allowed");
447+
for (const i in fields) {
448+
params.qstring[i] = fields[i];
449+
}
439450
}
440-
}).listen(common.config.api.port, common.config.api.host || '').timeout = common.config.api.timeout || 120000;
441-
442-
plugins.loadConfigs(common.db);
451+
if (!params.apiPath) {
452+
processRequest(params);
453+
}
454+
});
443455
}
444-
});
456+
else if (req.method.toLowerCase() === 'options') {
457+
const headers = {};
458+
headers["Access-Control-Allow-Origin"] = "*";
459+
headers["Access-Control-Allow-Methods"] = "POST, GET, OPTIONS";
460+
headers["Access-Control-Allow-Headers"] = "countly-token, Content-Type";
461+
res.writeHead(200, headers);
462+
res.end();
463+
}
464+
//attempt process GET request
465+
else if (req.method.toLowerCase() === 'get') {
466+
processRequest(params);
467+
}
468+
else {
469+
common.returnMessage(params, 405, "Method not allowed");
470+
}
471+
}

api/config.sample.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ var countlyConfig = {
6969
max_sockets: 1024,
7070
timeout: 120000,
7171
maxUploadFileSize: 200 * 1024 * 1024, // 200MB
72+
ssl: {
73+
enabled: false,
74+
key: "/path/to/ssl/private.key",
75+
cert: "/path/to/ssl/certificate.crt",
76+
ca: "/path/to/ssl/ca_bundle.crt" // Optional: for client certificate verification
77+
}
7278
},
7379
/**
7480
* Path to use for countly directory, empty path if installed at root of website

api/configextender.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,26 @@ const OVERRIDES = {
3232

3333
API: {
3434
MAX_SOCKETS: 'max_sockets',
35-
MAX_UPLOAD_FILE_SIZE: 'maxUploadFileSize'
35+
MAX_UPLOAD_FILE_SIZE: 'maxUploadFileSize',
36+
SSL: {
37+
ENABLED: 'enabled',
38+
KEY: 'key',
39+
CERT: 'cert',
40+
CA: 'ca',
41+
},
3642
},
3743

3844
WEB: {
3945
USE_INTERCOM: 'use_intercom',
4046
SECURE_COOKIES: 'secure_cookies',
4147
SESSION_SECRET: 'session_secret',
42-
SESSION_NAME: 'session_name'
48+
SESSION_NAME: 'session_name',
49+
SSL: {
50+
ENABLED: 'enabled',
51+
KEY: 'key',
52+
CERT: 'cert',
53+
CA: 'ca',
54+
},
4355
},
4456

4557
MAIL: {

api/utils/render.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ var chromePath = "";
2525
var countlyFs = require('./countlyFs');
2626
var log = require('./log.js')('core:render');
2727
var countlyConfig = require('./../config', 'dont-enclose');
28+
var fs = require('fs');
2829

2930

3031
/**
@@ -69,7 +70,7 @@ exports.renderView = function(options, cb) {
6970
},
7071
args: ['--no-sandbox', '--disable-setuid-sandbox', '--ignore-certificate-errors'],
7172
ignoreHTTPSErrors: true,
72-
userDataDir: pathModule.resolve(__dirname, "../../dump/chrome")
73+
userDataDir: pathModule.resolve(__dirname, "../../dump/chrome/" + Date.now())
7374
};
7475

7576
if (chromePath) {
@@ -251,6 +252,9 @@ exports.renderView = function(options, cb) {
251252
await bodyHandle.dispose();
252253
await browser.close();
253254

255+
// Remove user data directory after use
256+
fs.rmSync(settings.userDataDir, { recursive: true, force: true });
257+
254258
var imageData = {
255259
image: image,
256260
path: path
@@ -261,6 +265,8 @@ exports.renderView = function(options, cb) {
261265
catch (e) {
262266
log.e("Headless chrome browser error", e);
263267
await browser.close();
268+
// Remove user data directory after use
269+
fs.rmSync(settings.userDataDir, { recursive: true, force: true });
264270
return cb(e);
265271
}
266272
}

0 commit comments

Comments
 (0)