Skip to content

Commit

Permalink
Merge branch 'QT-235v2' of github.com:Countly/countly-server into QT-…
Browse files Browse the repository at this point in the history
…235v2
  • Loading branch information
can-angun committed Nov 14, 2024
2 parents 0ecf14b + 84b1de0 commit 6fa1189
Show file tree
Hide file tree
Showing 30 changed files with 249 additions and 128 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ Enterprise fixes:
- [nps] Fixed bug in the editor where the "internal name" field was not mandatory
- [ratings] Fixed UI bug where "Internal name" was not a mandatory field

Security:
- Fixing minor vulnerability that would allow for unauthorized file upload

## Version 24.05.16
Fixes:
- [core] Replaced "Users" with "Sessions" label on technology home widgets
Expand Down
21 changes: 19 additions & 2 deletions api/utils/requestProcessor.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const Promise = require('bluebird');
const url = require('url');
const common = require('./common.js');
const countlyCommon = require('../lib/countly.common.js');
const { validateAppAdmin, validateUser, validateRead, validateUserForRead, validateUserForWrite, validateGlobalAdmin, dbUserHasAccessToCollection, validateUpdate, validateDelete, validateCreate } = require('./rights.js');
const { validateAppAdmin, validateUser, validateRead, validateUserForRead, validateUserForWrite, validateGlobalAdmin, dbUserHasAccessToCollection, validateUpdate, validateDelete, validateCreate, getBaseAppFilter } = require('./rights.js');
const authorize = require('./authorizer.js');
const taskmanager = require('./taskmanager.js');
const plugins = require('../../plugins/pluginManager.js');
Expand Down Expand Up @@ -2131,7 +2131,7 @@ const processRequest = (params) => {
}

dbUserHasAccessToCollection(params, params.qstring.collection, (hasAccess) => {
if (hasAccess) {
if (hasAccess || (params.qstring.db === "countly_drill" && params.qstring.collection === "drill_events") || (params.qstring.db === "countly" && params.qstring.collection === "events_data")) {
var dbs = { countly: common.db, countly_drill: common.drillDb, countly_out: common.outDb, countly_fs: countlyFs.gridfs.getHandler() };
var db = "";
if (params.qstring.db && dbs[params.qstring.db]) {
Expand All @@ -2140,6 +2140,23 @@ const processRequest = (params) => {
else {
db = common.db;
}
if (!params.member.global_admin && params.qstring.collection === "drill_events" || params.qstring.collection === "events_data") {
var base_filter = getBaseAppFilter(params.member, params.qstring.db, params.qstring.collection);
if (base_filter && Object.keys(base_filter).length > 0) {
params.qstring.query = params.qstring.query || {};
for (var key in base_filter) {
if (params.qstring.query[key]) {
params.qstring.query.$and = params.qstring.query.$and || [];
params.qstring.query.$and.push({[key]: base_filter[key]});
params.qstring.query.$and.push({[key]: params.qstring.query[key]});
delete params.qstring.query[key];
}
else {
params.qstring.query[key] = base_filter[key];
}
}
}
}
countlyApi.data.exports.fromDatabase({
db: db,
params: params,
Expand Down
27 changes: 26 additions & 1 deletion api/utils/rights.js
Original file line number Diff line number Diff line change
Expand Up @@ -1083,7 +1083,32 @@ function validateWrite(params, feature, accessType, callback, callbackParam) {
});
});
}

/**
* Creates filter object to filter by member allowed collections
* @param {object} member - members object from params
* @param {string} dbName - database name as string
* @param {string} collectionName - collection Name
* @returns {object} filter object
*/
exports.getBaseAppFilter = function(member, dbName, collectionName) {
var base_filter = {};
var apps = exports.getUserApps(member);
if (dbName === "countly_drill" && collectionName === "drill_events") {
if (Array.isArray(apps) && apps.length > 0) {
base_filter.a = {"$in": apps};
}
}
else if (dbName === "countly" && collectionName === "events_data") {
var in_array = [];
if (Array.isArray(apps) && apps.length > 0) {
for (var i = 0; i < apps.length; i++) {
in_array.push(new RegExp("^" + apps[i] + "_.*"));
}
base_filter = {"_id": {"$in": in_array}};
}
}
return base_filter;
};
/**
* Validate user for create access by api_key for provided app_id (both required parameters for the request).
* @param {params} params - {@link params} object
Expand Down
4 changes: 4 additions & 0 deletions frontend/express/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,10 @@ Promise.all([plugins.dbConnection(countlyConfig), plugins.dbConnection("countly_
app.use(function(req, res, next) {
var contentType = req.headers['content-type'];
if (req.method.toLowerCase() === 'post' && contentType && contentType.indexOf('multipart/form-data') >= 0) {
if (!req.session?.uid || Date.now() > req.session?.expires) {
res.status(401).send('Unauthorized');
return;
}
var form = new formidable.IncomingForm();
form.uploadDir = __dirname + '/uploads';
form.parse(req, function(err, fields, files) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@
>
<template v-slot:header-right>
<cly-more-options v-if="topDropdown" size="small">
<el-dropdown-item :key="idx" v-for="(item, idx) in topDropdown">
<!--<span :class="item.icon"></span>-->
<a :href="item.value" class="bu-ml-1">{{item.label}}</a>
</el-dropdown-item>
<el-dropdown-item :key="idx" v-for="(item, idx) in topDropdown" :command="{url: item.value}">{{item.label}}</el-dropdown-item>
</cly-more-options>
</template>
</cly-header>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@
>
<template v-slot:header-right>
<cly-more-options v-if="topDropdown" size="small">
<el-dropdown-item :key="idx" v-for="(item, idx) in topDropdown">
<!--<span :class="item.icon"></span>-->
<a :href="item.value" class="bu-ml-1">{{item.label}}</a>
</el-dropdown-item>
<el-dropdown-item :key="idx" v-for="(item, idx) in topDropdown" :command="{url: item.value}">{{item.label}}</el-dropdown-item>
</cly-more-options>
</template>
</cly-header>
Expand Down
5 changes: 1 addition & 4 deletions frontend/express/public/core/carrier/templates/carrier.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@
>
<template v-slot:header-right>
<cly-more-options v-if="topDropdown" size="small">
<el-dropdown-item :key="idx" v-for="(item, idx) in topDropdown">
<!--<span :class="item.icon"></span>-->
<a :href="item.value" class="bu-ml-1">{{item.label}}</a>
</el-dropdown-item>
<el-dropdown-item :key="idx" v-for="(item, idx) in topDropdown" :command="{url: item.value}">{{item.label}}</el-dropdown-item>
</cly-more-options>
</template>
</cly-header>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,20 @@ var GridComponent = countlyVue.views.create({
}
return val;
},
onWidgetCommand: function(event) {
if (event === 'add' || event === 'manage' || event === 'show') {
this.graphNotesHandleCommand(event);
return;
}
else if (event === 'zoom') {
this.triggerZoom();
return;
}
else {
this.$emit('command', event);
return;
}
},
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@
>
<template v-slot:header-right>
<cly-more-options v-if="topDropdown" size="small">
<el-dropdown-item :key="idx" v-for="(item, idx) in topDropdown">
<!--<span :class="item.icon"></span>-->
<a :href="item.value" class="bu-ml-1">{{item.label}}</a>
</el-dropdown-item>
<el-dropdown-item :key="idx" v-for="(item, idx) in topDropdown" :command="{url: item.value}">{{item.label}}</el-dropdown-item>
</cly-more-options>
</template>
<template v-slot:header-tabs>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@
>
<template v-slot:header-right>
<cly-more-options v-if="topDropdown" size="small">
<el-dropdown-item :key="idx" v-for="(item, idx) in topDropdown">
<!--<span :class="item.icon"></span>-->
<a :href="item.value" class="bu-ml-1">{{item.label}}</a>
</el-dropdown-item>
<el-dropdown-item :key="idx" v-for="(item, idx) in topDropdown" :command="{url: item.value}">{{item.label}}</el-dropdown-item>
</cly-more-options>
</template>
</cly-header>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@
>
<template v-slot:header-right>
<cly-more-options v-if="topDropdown" size="small">
<el-dropdown-item :key="idx" v-for="(item, idx) in topDropdown">
<!--<span :class="item.icon"></span>-->
<a :href="item.value" class="bu-ml-1">{{item.label}}</a>
</el-dropdown-item>
<el-dropdown-item :key="idx" v-for="(item, idx) in topDropdown" :command="{url: item.value}">{{item.label}}</el-dropdown-item>
</cly-more-options>
</template>
</cly-header>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ <h2> {{i18n('user-analytics.overview-title')}} </h2>
</template>
<template v-slot:header-right>
<cly-more-options v-if="topDropdown" size="small">
<el-dropdown-item :key="idx" v-for="(item, idx) in topDropdown">
<!--<span :class="item.icon"></span>-->
<a :href="item.value" class="bu-ml-1">{{item.label}}</a>
</el-dropdown-item>
<el-dropdown-item :key="idx" v-for="(item, idx) in topDropdown" :command="{url: item.value}">{{item.label}}</el-dropdown-item>
</cly-more-options>
</template>
</cly-header>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,12 @@
if (options.isExternalLink) {
window.open(options.url, '_blank', 'noopener,noreferrer');
}
else if (options.download) {
var a = document.createElement('a');
a.href = options.url;
a.download = options.download;
a.click();
}
else {
app.backlinkUrl = options.from;
app.backlinkTitle = options.title;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* global jQuery, Vue, ELEMENT, CV */
/* global jQuery, Vue, ELEMENT, CV, CountlyHelpers */

(function(countlyVue) {

Expand Down Expand Up @@ -612,7 +612,12 @@
methods: {
handleMenuItemClick: function(command, instance) {
if (!this.disabled) {
this.$emit('command', command, instance);
if (command && command.url) {
CountlyHelpers.goTo({url: command.url, download: !!command.download, isExternalLink: !!command.isExternalLink});
}
else {
this.$emit('command', command, instance);
}
this.$refs.dropdown.handleClose();
}
},
Expand Down
5 changes: 1 addition & 4 deletions plugins/browser/frontend/public/templates/browser.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@
>
<template v-slot:header-right>
<cly-more-options v-if="topDropdown" size="small">
<el-dropdown-item :key="idx" v-for="(item, idx) in topDropdown">
<!--<span :class="item.icon"></span>-->
<a :href="item.value" class="bu-ml-1">{{item.label}}</a>
</el-dropdown-item>
<el-dropdown-item :key="idx" v-for="(item, idx) in topDropdown" :command="{url: item.value}">{{item.label}}</el-dropdown-item>
</cly-more-options>
</template>
</cly-header>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@
this.$store.dispatch("countlyConsentManager/fetchUserDataResource");
},
methods: {
switchToConsentHistory: function(uid) {
window.location.hash = "#/manage/compliance/history/" + uid;
},
deleteUserData: function(uid) {
var self = this;
CountlyHelpers.confirm(this.i18n("app-users.delete-userdata-confirm"), "popStyleGreen", function(result) {
Expand Down Expand Up @@ -77,8 +74,21 @@
downloadExportedData: function(uid) {
var win = window.open(countlyCommon.API_PARTS.data.r + "/app_users/download/appUser_" + countlyCommon.ACTIVE_APP_ID + "_" + uid + "?auth_token=" + countlyGlobal.auth_token + "&app_id=" + countlyCommon.ACTIVE_APP_ID, '_blank');
win.focus();
},
handleCommand: function(command, uid) {
if (command === "deleteUserData") {
this.deleteUserData(uid);
}
else if (command === "exportUserData") {
this.exportUserData(uid);
}
else if (command === "deleteExport") {
this.deleteExport(uid);
}
else if (command === "downloadExportedData") {
this.downloadExportedData(uid);
}
}

}
});
var ConsentView = countlyVue.views.create({
Expand Down
28 changes: 6 additions & 22 deletions plugins/compliance-hub/frontend/public/templates/user.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,28 +51,12 @@
</el-table-column>
<el-table-column type="options">
<template v-slot="rowScope">
<cly-more-options test-id="compliance-hub-users" v-if="rowScope.row.hover" size="small">
<el-dropdown-item>
<el-link v-if="canUserRead" class="bu-ml-1" plain @click="switchToConsentHistory(rowScope.row.uid)" :data-test-id="'datatable-more-button-go-to-consent-history-select-' + rowScope.$index"> {{i18n("consent.go-history")}} </el-link>
</el-dropdown-item>
<el-dropdown-item v-if="!rowScope.row.appUserExport && canUserRead">
<el-link class="bu-ml-1" plain @click="exportUserData(rowScope.row.uid)" :data-test-id="'datatable-more-button-export-user-data-select-' + rowScope.$index">
{{i18n("app-users.export-userdata")}}</el-link>
</el-dropdown-item>
<el-dropdown-item v-if="rowScope.row.appUserExport && canUserRead">
<el-link class="bu-ml-1" plain @click="downloadExportedData(rowScope.row.uid)" :data-test-id="'datatable-more-button-download-export-select-' + rowScope.$index">
{{i18n("app-users.download-export")}}</span>
</el-link>
</el-dropdown-item>
<el-dropdown-item v-if="rowScope.row.appUserExport && canUserDelete">
<el-link class="bu-ml-1" plain @click="deleteExport(rowScope.row.uid)" :data-test-id="'datatable-more-button-delete-export-' + rowScope.$index">
{{i18n("app-users.delete-export")}}</span>
</el-link>
</el-dropdown-item>
<el-dropdown-item v-if="canUserDelete">
<el-link class="bu-ml-1" @click="deleteUserData(rowScope.row.uid)" :data-test-id="'datatable-more-button-delete-user-data-' + rowScope.$index" plain>
{{i18n("app-users.delete-userdata")}}</el-link>
</el-dropdown-item>
<cly-more-options test-id="compliance-hub-users" v-if="rowScope.row.hover" size="small" @command="handleCommand($event, rowScope.row.uid)">
<el-dropdown-item v-if="canUserRead" :command="{url: '#/manage/compliance/history/' + rowScope.row.uid}" :data-test-id="'datatable-more-button-go-to-consent-history-select-' + rowScope.$index"> {{i18n("consent.go-history")}} </el-dropdown-item>
<el-dropdown-item v-if="!rowScope.row.appUserExport && canUserRead" command="exportUserData" :data-test-id="'datatable-more-button-export-user-data-select-' + rowScope.$index">{{i18n("app-users.export-userdata")}}</el-dropdown-item>
<el-dropdown-item v-if="rowScope.row.appUserExport && canUserRead" command="downloadExportedData" :data-test-id="'datatable-more-button-download-export-select-' + rowScope.$index">{{i18n("app-users.download-export")}}</el-dropdown-item>
<el-dropdown-item v-if="rowScope.row.appUserExport && canUserDelete" command="deleteExport" :data-test-id="'datatable-more-button-delete-export-' + rowScope.$index">{{i18n("app-users.delete-export")}}</el-dropdown-item>
<el-dropdown-item v-if="canUserDelete" command="deleteUserData" :data-test-id="'datatable-more-button-delete-user-data-' + rowScope.$index">{{i18n("app-users.delete-userdata")}}</el-dropdown-item>
</cly-more-options>
</template>

Expand Down
Loading

0 comments on commit 6fa1189

Please sign in to comment.