Skip to content
Snippets Groups Projects
Commit 0179e1b5 authored by albuquerquefabio's avatar albuquerquefabio
Browse files

Squashed commit of the following:


commit 19a996ac
Author: Douglas Fabris <devfabris@gmail.com>
Date:   Thu Jun 2 11:58:46 2022 -0300

    [FIX] Unnecessary padding on teams channels footer (#25712)

commit 8274ba3f
Author: Hugo Costa <hugocarreiracosta@gmail.com>
Date:   Thu Jun 2 11:00:52 2022 -0300

    [FIX] Messages spacing (#25631)

    * fix(fuselage): adding sequential param to Message Component

    * chore: updating fuselage version

    * fix: updating yarn.lock

    * fix yarn.lock

    * Update fuselage

    * remove dev deps

Co-authored-by: default avatargabriellsh <gabriel.henriques@rocket.chat>

commit d24789ab
Author: Guilherme Gazzo <guilhermegazzo@gmail.com>
Date:   Wed Jun 1 17:09:34 2022 -0300

    Chore: Custom Sounds Endpoints (#25633)

commit db257d32
Author: Murtaza Patrawala <34130764+murtaza98@users.noreply.github.com>
Date:   Wed Jun 1 22:11:12 2022 +0530

    [FIX] User's with non-agent role shown on voip agent association model (#25682)

commit c8fba6fb
Author: Guilherme Gazzo <guilhermegazzo@gmail.com>
Date:   Wed Jun 1 13:37:58 2022 -0300

    Fix CI

commit afbb7082
Author: Guilherme Gazzo <guilhermegazzo@gmail.com>
Date:   Wed Jun 1 13:09:17 2022 -0300

    fix CI

commit c5def579
Author: Júlia Jaeger Foresti <60678893+juliajforesti@users.noreply.github.com>
Date:   Wed Jun 1 12:27:08 2022 -0300

    Chore: Convert CreateChannelWithData (#25667)

commit bcd4b1b9
Author: Júlia Jaeger Foresti <60678893+juliajforesti@users.noreply.github.com>
Date:   Wed Jun 1 12:25:58 2022 -0300

    Chore: Convert UserAutoCompleteMultiple (#25587)

Co-authored-by: default avatarjulia foresti <juliaforesti@julias-MacBook-Pro.local>

commit 08656e3f
Author: amolghode1981 <86001342+amolghode1981@users.noreply.github.com>
Date:   Wed Jun 1 20:55:32 2022 +0530

    Chore: Converting files from app/livechat folder from JS to TS (#25658)

commit c2c1bf42
Author: Jean Brito <jeanfbrito@gmail.com>
Date:   Wed Jun 1 11:36:08 2022 -0300

    Chore: Convert sidebar/header/actions (#25581)

Co-authored-by: default avatarGuilherme Gazzo <guilhermegazzo@gmail.com>

commit 44d67982
Author: Aleksander Nicacio da Silva <aleksander.silva@rocket.chat>
Date:   Tue May 31 23:00:14 2022 -0300

    Chore: Converting omnichannel installation files to ts (#25665)

commit cd32f091
Author: Jean Brito <jeanfbrito@gmail.com>
Date:   Tue May 31 22:55:02 2022 -0300

    Chore: Convert to TS omnichannel/agent (#25511)

Co-authored-by: default avatarGuilherme Gazzo <guilhermegazzo@gmail.com>

commit 6b41aa62
Author: Jean Brito <jeanfbrito@gmail.com>
Date:   Tue May 31 22:52:51 2022 -0300

    Chore: Convert components/sidebar to TS (#25429)

Co-authored-by: default avatarGuilherme Gazzo <guilhermegazzo@gmail.com>

commit 6c1a7b1a
Author: Júlia Jaeger Foresti <60678893+juliajforesti@users.noreply.github.com>
Date:   Tue May 31 22:52:04 2022 -0300

    Chore: Convert apps/meteor/client/sidebar/header/index (#25671)

commit 5b81dbad
Author: Tasso Evangelista <tasso.evangelista@rocket.chat>
Date:   Tue May 31 22:51:27 2022 -0300

    Chore: Migrate some small helper functions to TypeScript (#25666)

commit ad67cd3f
Author: Douglas Gubert <douglas.gubert@gmail.com>
Date:   Tue May 31 22:50:13 2022 -0300

    Merge master into develop & Set version to 5.0.0 (#25702)

commit 80fc5b7e
Author: Douglas Gubert <douglas.gubert@gmail.com>
Date:   Tue May 31 17:05:29 2022 -0300

    Chore: Update Apps-Engine and Fuselage (#25700)

commit 88a8e8e1
Author: Douglas Gubert <douglas.gubert@gmail.com>
Date:   Tue May 31 11:06:52 2022 -0300

    Regression: App event listeners broke Slackbridge integration and importers (#25689)

commit bf3483d7
Author: Guilherme Gazzo <guilhermegazzo@gmail.com>
Date:   Mon May 30 23:44:01 2022 -0300

    [FIX] Fix max-width message block (#25686)

commit b1d855e4
Author: Sinyoung "Divinespear" Kang <divinespear@gmail.com>
Date:   Tue May 31 10:27:14 2022 +0900

    [FIX] Change form body parameter charset to UTF-8 to fix issue #25456 (#25673)

commit 51845b14
Author: Guilherme Gazzo <guilhermegazzo@gmail.com>
Date:   Mon May 30 22:26:55 2022 -0300

    Regression: Fix sort field files.list (#25687)

Co-authored-by: default avatarFábio Albuquerque <albuquerquefabio@icloud.com>

commit 713120eb
Author: Carlos Rodrigues <carlos.1994hrs@gmail.com>
Date:   Mon May 30 17:59:57 2022 -0300

    fix git conflict (#25684)

commit 62405c60
Author: Marcos Spessatto Defendi <marcos.defendi@rocket.chat>
Date:   Mon May 30 12:47:44 2022 -0300

    [FIX] Prevent federation crash on invite users as a non-owner user (#25683)

    * fix: prevent crashing when inviting someone as non-owner

    * chore: fix lint

commit d364be43
Author: Tasso Evangelista <tasso.evangelista@rocket.chat>
Date:   Mon May 30 11:21:16 2022 -0300

    Regression: Broken components on Federation and Engagement dashboards (#25653)

    * Fix odd typechecking issues with JSON modules

    * Avoid `data` as directory for modules

    * rename other `data` folder

Co-authored-by: default avatargabriellsh <gabriel.henriques@rocket.chat>

commit 4894fc2d
Author: Douglas Fabris <devfabris@gmail.com>
Date:   Fri May 27 16:23:07 2022 -0300

    Regression: Update settings groups description (#25663)

commit 5a0d29f5
Author: Hugo Costa <hugocarreiracosta@gmail.com>
Date:   Fri May 27 13:45:51 2022 -0300

    [FIX] Click to join button Jitsi Call (#25569)

    * fix: Click to join button Jitsi Call

    * Fix `yarn` references

    * fix: Old message Jitsi Button

    * Fix yarn references (again)

    * Update apps/meteor/app/action-links/client/lib/actionLinks.ts

Co-authored-by: default avatarTasso Evangelista <tasso.evangelista@rocket.chat>

    * fix: changing instance type

Co-authored-by: default avatarTasso Evangelista <tasso.evangelista@rocket.chat>

commit 78e57f5a
Author: Fábio Albuquerque <albuquerquefabio@icloud.com>
Date:   Fri May 27 12:54:04 2022 -0300

    Regression: Endpoint types with Ajv Coercing data types (#25644)

commit 7dd89fc0
Author: Kevin Aleman <kaleman960@gmail.com>
Date:   Fri May 27 02:20:57 2022 -0600

    Regression: Change logic to check if connection is online on unstable networks (#25618)

    * Change .race for .allsettled so rejections are handled better

    * improve to unstable check logic

    * CR suggestions

commit 195f90a8
Author: Douglas Fabris <devfabris@gmail.com>
Date:   Thu May 26 23:37:56 2022 -0300

    Regression: Missing settings group descriptions (#25639)

commit 31ae30f3
Author: Guilherme Gazzo <guilhermegazzo@gmail.com>
Date:   Thu May 26 19:11:41 2022 -0300

    Chore: Rest API query parameters handling (#25648)

commit 052858d5
Author: Aleksander Nicacio da Silva <aleksander.nsilva@gmail.com>
Date:   Thu May 26 18:36:07 2022 -0300

    Regression: VoIp wrap up modal not opening after call disconnect (#25651)

commit 3cd0cabe
Author: Guilherme Jun Grillo <48109548+guijun13@users.noreply.github.com>
Date:   Thu May 26 15:39:15 2022 -0300

    [FIX] Remove 'total' text in admin info page (#25638)

    * fix: rm intial 'total' from rooms & total groups

    * fix: change key of 'total messages' title

    * feat: cr8 'total_rooms'='Total Rooms' in en.i18n

    replace it from 'rooms' title in rooms group

    * fix: change pt-BR.i18n to remove initial 'total'

commit 6f3133f4
Author: Rodrigo Nascimento <rodrigoknascimento@gmail.com>
Date:   Thu May 26 13:28:48 2022 -0300

    Chore: Increase performance and security of integrations’ scripts (#25641)

commit cbb0844c
Author: Hugo Costa <hugocarreiracosta@gmail.com>
Date:   Thu May 26 12:12:32 2022 -0300

    [FIX] Quote message spacing (#25613)

    * fix: default margins for outer quote

    * fix: Removing condition to style differently the inner quote

    * fix: updating yarn.lock

commit 2452448e
Author: Douglas Fabris <devfabris@gmail.com>
Date:   Wed May 25 15:10:07 2022 -0300

    Regression: Assets & Slack Bridge Setting Page not rendering (#25629)

    * fix: RoomPickSettingInput

    * fix: assets page broken

commit ca4c020e
Author: Henrique Guimarães Ribeiro <henrique.jobs1@gmail.com>
Date:   Tue May 24 22:39:11 2022 -0300

    Regression: Subscription menu not appearing for non installed but subscribed apps (#25627)

    * fix: :bug: Fix subscribe menu option not appearing

    Fixed a problem on which the AppMenu component did not appear for apps that had an active subscription but weren't installed, now the rendering of the component is also based on the isSubscribed flag, and the appearance of the uninstall and enable/disable options are based on the app.installed flag.

    * fix: :bug: Fix AppMenu overflow error on Marketplace/AppRow

    Fixed a visual error on which the AppMenu component would overflow the right side of its container and have part of itself hidden.

    * fix: :bug: FIx isSubscribed wrongful typing

    Fixed an oversight where I've typed isSubscribed as string instead of boolean
parent 0cb20c83
No related branches found
No related tags found
No related merge requests found
Showing
with 14682 additions and 1580 deletions
...@@ -124,6 +124,20 @@ ...@@ -124,6 +124,20 @@
"pierre-lehnen-rc" "pierre-lehnen-rc"
] ]
}], }],
"3.18.6": [{
"title": "[FIX] Security Hotfix (https://docs.rocket.chat/guides/security/security-updates)",
"userLogin": "d-gubert",
"contributors": [
"ggazzo"
]
}],
"3.18.7": [{
"title": "[FIX] Security Hotfix (https://docs.rocket.chat/guides/security/security-updates)",
"userLogin": "d-gubert",
"contributors": [
"ggazzo"
]
}],
"4.1.1": [{ "4.1.1": [{
"title": "[FIX] Security Hotfix (https://docs.rocket.chat/guides/security/security-updates)", "title": "[FIX] Security Hotfix (https://docs.rocket.chat/guides/security/security-updates)",
"userLogin": "sampaiodiego", "userLogin": "sampaiodiego",
...@@ -147,5 +161,33 @@ ...@@ -147,5 +161,33 @@
"contributors": [ "contributors": [
"gronke" "gronke"
] ]
}],
"4.4.4": [{
"title": "[FIX] Security Hotfix (https://docs.rocket.chat/guides/security/security-updates)",
"userLogin": "d-gubert",
"contributors": [
"ggazzo"
]
}],
"4.4.5": [{
"title": "[FIX] Security Hotfix (https://docs.rocket.chat/guides/security/security-updates)",
"userLogin": "d-gubert",
"contributors": [
"ggazzo"
]
}],
"4.7.3": [{
"title": "[FIX] Security Hotfix (https://docs.rocket.chat/guides/security/security-updates)",
"userLogin": "d-gubert",
"contributors": [
"ggazzo"
]
}],
"4.7.4": [{
"title": "[FIX] Security Hotfix (https://docs.rocket.chat/guides/security/security-updates)",
"userLogin": "d-gubert",
"contributors": [
"ggazzo"
]
}] }]
} }
This diff is collapsed.
...@@ -2,12 +2,14 @@ nodeLinker: node-modules ...@@ -2,12 +2,14 @@ nodeLinker: node-modules
plugins: plugins:
- path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
spec: "@yarnpkg/plugin-workspace-tools" spec: '@yarnpkg/plugin-workspace-tools'
- path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs - path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs
spec: "@yarnpkg/plugin-interactive-tools" spec: '@yarnpkg/plugin-interactive-tools'
- path: .yarn/plugins/@yarnpkg/plugin-engines.cjs - path: .yarn/plugins/@yarnpkg/plugin-engines.cjs
spec: "https://raw.githubusercontent.com/devoto13/yarn-plugin-engines/main/bundles/%40yarnpkg/plugin-engines.js" spec: 'https://raw.githubusercontent.com/devoto13/yarn-plugin-engines/main/bundles/%40yarnpkg/plugin-engines.js'
- path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs - path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs
spec: "@yarnpkg/plugin-typescript" spec: '@yarnpkg/plugin-typescript'
yarnPath: .yarn/releases/yarn-3.2.0.cjs yarnPath: .yarn/releases/yarn-3.2.0.cjs
checksumBehavior: 'update'
This diff is collapsed.
FROM registry.access.redhat.com/ubi8/nodejs-12 FROM registry.access.redhat.com/ubi8/nodejs-12
ENV RC_VERSION 4.8.0-develop ENV RC_VERSION 5.0.0
MAINTAINER buildmaster@rocket.chat MAINTAINER buildmaster@rocket.chat
......
...@@ -9,5 +9,5 @@ module.exports = { ...@@ -9,5 +9,5 @@ module.exports = {
timeout: 10000, timeout: 10000,
bail: true, bail: true,
file: 'tests/end-to-end/teardown.js', file: 'tests/end-to-end/teardown.js',
spec: ['tests/end-to-end/api/*.js', 'tests/end-to-end/api/*.ts', 'tests/end-to-end/apps/*.js'], spec: ['tests/unit/app/api/server/v1/*.spec.ts', 'tests/end-to-end/api/*.js', 'tests/end-to-end/api/*.ts', 'tests/end-to-end/apps/*.js'],
}; };
#!/bin/bash #!/bin/bash
curl -SLf "https://releases.rocket.chat/4.8.0-develop/download/" -o rocket.chat.tgz curl -SLf "https://releases.rocket.chat/5.0.0/download/" -o rocket.chat.tgz
tar xf rocket.chat.tgz --strip 1 tar xf rocket.chat.tgz --strip 1
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
# 5. `snapcraft snap` # 5. `snapcraft snap`
name: rocketchat-server name: rocketchat-server
version: 4.8.0-develop version: 5.0.0
summary: Rocket.Chat server summary: Rocket.Chat server
description: Have your own Slack like online chat, built with Meteor. https://rocket.chat/ description: Have your own Slack like online chat, built with Meteor. https://rocket.chat/
confinement: strict confinement: strict
......
...@@ -42,7 +42,7 @@ export const actionLinks = { ...@@ -42,7 +42,7 @@ export const actionLinks = {
// return message; // return message;
// }, // },
run(method: string, message: IMessage, instance: undefined): void { run(method: string, message: IMessage, instance?: Blaze.TemplateInstance | Function): void {
const actionLink = message.actionLinks && message.actionLinks.find((action) => action.method_id === method); const actionLink = message.actionLinks && message.actionLinks.find((action) => action.method_id === method);
if (!actionLink) { if (!actionLink) {
......
...@@ -143,7 +143,7 @@ type Operations<TPathPattern extends PathPattern, TOptions extends Options = {}> ...@@ -143,7 +143,7 @@ type Operations<TPathPattern extends PathPattern, TOptions extends Options = {}>
}; };
declare class APIClass<TBasePath extends string = '/'> { declare class APIClass<TBasePath extends string = '/'> {
fieldSeparator(fieldSeparator: unknown): void; fieldSeparator: string;
limitedUserFieldsToExclude(fields: { [x: string]: unknown }, limitedUserFieldsToExclude: unknown): { [x: string]: unknown }; limitedUserFieldsToExclude(fields: { [x: string]: unknown }, limitedUserFieldsToExclude: unknown): { [x: string]: unknown };
......
...@@ -425,6 +425,9 @@ export class APIClass extends Restivus { ...@@ -425,6 +425,9 @@ export class APIClass extends Restivus {
connection, connection,
}); });
this.queryOperations = options.queryOperations;
this.queryFields = options.queryFields;
result = DDP._CurrentInvocation.withValue(invocation, () => Promise.await(originalAction.apply(this))) || API.v1.success(); result = DDP._CurrentInvocation.withValue(invocation, () => Promise.await(originalAction.apply(this))) || API.v1.success();
log.http({ log.http({
......
import { Meteor } from 'meteor/meteor';
import { Users } from '../../../models/server'; import { Users } from '../../../models/server';
import { API } from '../api'; import { API } from '../api';
API.helperMethods.set( API.helperMethods.set(
'insertUserObject', 'insertUserObject',
function _addUserToObject({ object, userId }: { object: { [key: string]: unknown }; userId: string }) { Meteor.bindEnvironment(function _addUserToObject({ object, userId }: { object: { [key: string]: unknown }; userId: string }) {
// Maybe `object: { [key: string]: Meteor.User }`? // Maybe `object: { [key: string]: Meteor.User }`?
const user = Users.findOneById(userId); const user = Users.findOneById(userId);
if (user) { if (user) {
object.user = { object.user = {
...@@ -16,5 +17,5 @@ API.helperMethods.set( ...@@ -16,5 +17,5 @@ API.helperMethods.set(
} }
return object; return object;
}, }),
); );
import { Meteor } from 'meteor/meteor';
import { EJSON } from 'meteor/ejson';
import { hasPermission } from '../../../authorization';
import { clean } from '../lib/cleanQuery';
import { API } from '../api';
const pathAllowConf = {
'/api/v1/users.list': ['$or', '$regex', '$and'],
'def': ['$or', '$and', '$regex'],
};
API.helperMethods.set('parseJsonQuery', function _parseJsonQuery() {
let sort;
if (this.queryParams.sort) {
try {
sort = JSON.parse(this.queryParams.sort);
Object.entries(sort).forEach(([key, value]) => {
if (value !== 1 && value !== -1) {
throw new Meteor.Error('error-invalid-sort-parameter', `Invalid sort parameter: ${key}`, {
helperMethod: 'parseJsonQuery',
});
}
});
} catch (e) {
this.logger.warn(`Invalid sort parameter provided "${this.queryParams.sort}":`, e);
throw new Meteor.Error('error-invalid-sort', `Invalid sort parameter provided: "${this.queryParams.sort}"`, {
helperMethod: 'parseJsonQuery',
});
}
}
let fields;
if (this.queryParams.fields) {
try {
fields = JSON.parse(this.queryParams.fields);
Object.entries(fields).forEach(([key, value]) => {
if (value !== 1 && value !== 0) {
throw new Meteor.Error('error-invalid-sort-parameter', `Invalid fields parameter: ${key}`, {
helperMethod: 'parseJsonQuery',
});
}
});
} catch (e) {
this.logger.warn(`Invalid fields parameter provided "${this.queryParams.fields}":`, e);
throw new Meteor.Error('error-invalid-fields', `Invalid fields parameter provided: "${this.queryParams.fields}"`, {
helperMethod: 'parseJsonQuery',
});
}
}
// Verify the user's selected fields only contains ones which their role allows
if (typeof fields === 'object') {
let nonSelectableFields = Object.keys(API.v1.defaultFieldsToExclude);
if (this.request.route.includes('/v1/users.')) {
const getFields = () =>
Object.keys(
hasPermission(this.userId, 'view-full-other-user-info')
? API.v1.limitedUserFieldsToExcludeIfIsPrivilegedUser
: API.v1.limitedUserFieldsToExclude,
);
nonSelectableFields = nonSelectableFields.concat(getFields());
}
Object.keys(fields).forEach((k) => {
if (nonSelectableFields.includes(k) || nonSelectableFields.includes(k.split(API.v1.fieldSeparator)[0])) {
delete fields[k];
}
});
}
// Limit the fields by default
fields = Object.assign({}, fields, API.v1.defaultFieldsToExclude);
if (this.request.route.includes('/v1/users.')) {
if (hasPermission(this.userId, 'view-full-other-user-info')) {
fields = Object.assign(fields, API.v1.limitedUserFieldsToExcludeIfIsPrivilegedUser);
} else {
fields = Object.assign(fields, API.v1.limitedUserFieldsToExclude);
}
}
let query = {};
if (this.queryParams.query) {
try {
query = EJSON.parse(this.queryParams.query);
query = clean(query, pathAllowConf[this.request.route] || pathAllowConf.def);
} catch (e) {
this.logger.warn(`Invalid query parameter provided "${this.queryParams.query}":`, e);
throw new Meteor.Error('error-invalid-query', `Invalid query parameter provided: "${this.queryParams.query}"`, {
helperMethod: 'parseJsonQuery',
});
}
}
// Verify the user has permission to query the fields they are
if (typeof query === 'object') {
let nonQueryableFields = Object.keys(API.v1.defaultFieldsToExclude);
if (this.request.route.includes('/v1/users.')) {
if (hasPermission(this.userId, 'view-full-other-user-info')) {
nonQueryableFields = nonQueryableFields.concat(Object.keys(API.v1.limitedUserFieldsToExcludeIfIsPrivilegedUser));
} else {
nonQueryableFields = nonQueryableFields.concat(Object.keys(API.v1.limitedUserFieldsToExclude));
}
}
Object.keys(query).forEach((k) => {
if (nonQueryableFields.includes(k) || nonQueryableFields.includes(k.split(API.v1.fieldSeparator)[0])) {
delete query[k];
}
});
}
return {
sort,
fields,
query,
};
});
import { Meteor } from 'meteor/meteor';
import { EJSON } from 'meteor/ejson';
import { hasPermission } from '../../../authorization/server';
import { isValidQuery } from '../lib/isValidQuery';
import { clean } from '../lib/cleanQuery';
import { API } from '../api';
const pathAllowConf = {
'/api/v1/users.list': ['$or', '$regex', '$and'],
'def': ['$or', '$and', '$regex'],
};
API.helperMethods.set(
'parseJsonQuery',
function _parseJsonQuery(this: {
request: {
route: string;
};
queryParams: {
query?: string;
sort?: string;
fields?: string;
};
logger: any;
userId: string;
queryFields: string[];
queryOperations: string[];
}) {
let sort;
if (this.queryParams.sort) {
try {
sort = JSON.parse(this.queryParams.sort);
Object.entries(sort).forEach(([key, value]) => {
if (value !== 1 && value !== -1) {
throw new Meteor.Error('error-invalid-sort-parameter', `Invalid sort parameter: ${key}`, {
helperMethod: 'parseJsonQuery',
});
}
});
} catch (e) {
this.logger.warn(`Invalid sort parameter provided "${this.queryParams.sort}":`, e);
throw new Meteor.Error('error-invalid-sort', `Invalid sort parameter provided: "${this.queryParams.sort}"`, {
helperMethod: 'parseJsonQuery',
});
}
}
let fields: Record<string, 0 | 1> | undefined;
if (this.queryParams.fields) {
try {
fields = JSON.parse(this.queryParams.fields) as Record<string, 0 | 1>;
Object.entries(fields).forEach(([key, value]) => {
if (value !== 1 && value !== 0) {
throw new Meteor.Error('error-invalid-sort-parameter', `Invalid fields parameter: ${key}`, {
helperMethod: 'parseJsonQuery',
});
}
});
} catch (e) {
this.logger.warn(`Invalid fields parameter provided "${this.queryParams.fields}":`, e);
throw new Meteor.Error('error-invalid-fields', `Invalid fields parameter provided: "${this.queryParams.fields}"`, {
helperMethod: 'parseJsonQuery',
});
}
}
// Verify the user's selected fields only contains ones which their role allows
if (typeof fields === 'object') {
let nonSelectableFields = Object.keys(API.v1.defaultFieldsToExclude);
if (this.request.route.includes('/v1/users.')) {
const getFields = () =>
Object.keys(
hasPermission(this.userId, 'view-full-other-user-info')
? API.v1.limitedUserFieldsToExcludeIfIsPrivilegedUser
: API.v1.limitedUserFieldsToExclude,
);
nonSelectableFields = nonSelectableFields.concat(getFields());
}
Object.keys(fields).forEach((k) => {
if (nonSelectableFields.includes(k) || nonSelectableFields.includes(k.split(API.v1.fieldSeparator)[0])) {
fields && delete fields[k as keyof typeof fields];
}
});
}
// Limit the fields by default
fields = Object.assign({}, fields, API.v1.defaultFieldsToExclude);
if (this.request.route.includes('/v1/users.')) {
if (hasPermission(this.userId, 'view-full-other-user-info')) {
fields = Object.assign(fields, API.v1.limitedUserFieldsToExcludeIfIsPrivilegedUser);
} else {
fields = Object.assign(fields, API.v1.limitedUserFieldsToExclude);
}
}
let query: Record<string, any> = {};
if (this.queryParams.query) {
this.logger.warn('attribute query is deprecated');
try {
query = EJSON.parse(this.queryParams.query);
query = clean(query, pathAllowConf.def);
} catch (e) {
this.logger.warn(`Invalid query parameter provided "${this.queryParams.query}":`, e);
throw new Meteor.Error('error-invalid-query', `Invalid query parameter provided: "${this.queryParams.query}"`, {
helperMethod: 'parseJsonQuery',
});
}
}
// Verify the user has permission to query the fields they are
if (typeof query === 'object') {
let nonQueryableFields = Object.keys(API.v1.defaultFieldsToExclude);
if (this.request.route.includes('/v1/users.')) {
if (hasPermission(this.userId, 'view-full-other-user-info')) {
nonQueryableFields = nonQueryableFields.concat(Object.keys(API.v1.limitedUserFieldsToExcludeIfIsPrivilegedUser));
} else {
nonQueryableFields = nonQueryableFields.concat(Object.keys(API.v1.limitedUserFieldsToExclude));
}
}
if (this.queryFields && !isValidQuery(query, this.queryFields || ['*'], this.queryOperations ?? pathAllowConf.def)) {
throw new Meteor.Error('error-invalid-query', isValidQuery.errors.join('\n'));
}
Object.keys(query).forEach((k) => {
if (nonQueryableFields.includes(k) || nonQueryableFields.includes(k.split(API.v1.fieldSeparator)[0])) {
query && delete query[k];
}
});
}
return {
sort,
fields,
query,
};
},
);
...@@ -2,7 +2,7 @@ type Query = { [k: string]: any }; ...@@ -2,7 +2,7 @@ type Query = { [k: string]: any };
const denyList = ['constructor', '__proto__', 'prototype']; const denyList = ['constructor', '__proto__', 'prototype'];
const removeDangerousProps = (v: Query): Query => { export const removeDangerousProps = (v: Query): Query => {
const query = Object.create(null); const query = Object.create(null);
for (const key in v) { for (const key in v) {
if (v.hasOwnProperty(key) && !denyList.includes(key)) { if (v.hasOwnProperty(key) && !denyList.includes(key)) {
...@@ -12,7 +12,7 @@ const removeDangerousProps = (v: Query): Query => { ...@@ -12,7 +12,7 @@ const removeDangerousProps = (v: Query): Query => {
return query; return query;
}; };
/* @deprecated */
export function clean(v: Query, allowList: string[] = []): Query { export function clean(v: Query, allowList: string[] = []): Query {
const typedParam = removeDangerousProps(v); const typedParam = removeDangerousProps(v);
if (v instanceof Object) { if (v instanceof Object) {
......
import { CustomSounds } from '../../../models/server/raw';
export async function findCustomSounds({ query = {}, pagination: { offset, count, sort } }) {
const cursor = await CustomSounds.find(query, {
sort: sort || { name: 1 },
skip: offset,
limit: count,
});
const total = await cursor.count();
const sounds = await cursor.toArray();
return {
sounds,
count: sounds.length,
offset,
total,
};
}
import { CustomUserStatus } from '../../../models/server/raw';
export async function findCustomUserStatus({ query = {}, pagination: { offset, count, sort } }) {
const cursor = await CustomUserStatus.find(query, {
sort: sort || { name: 1 },
skip: offset,
limit: count,
});
const total = await cursor.count();
const statuses = await cursor.toArray();
return {
statuses,
count: statuses.length,
offset,
total,
};
}
...@@ -2,7 +2,7 @@ import busboy from 'busboy'; ...@@ -2,7 +2,7 @@ import busboy from 'busboy';
export const getUploadFormData = async ({ request }) => export const getUploadFormData = async ({ request }) =>
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
const bb = busboy({ headers: request.headers }); const bb = busboy({ headers: request.headers, defParamCharset: 'utf8' });
const fields = {}; const fields = {};
......
import { removeDangerousProps } from './cleanQuery';
type Query = { [k: string]: any };
export const isValidQuery: {
(query: Query, allowedAttributes: string[], allowedOperations: string[]): boolean;
errors: string[];
} = Object.assign(
(query: Query, allowedAttributes: string[], allowedOperations: string[]): boolean => {
isValidQuery.errors = [];
if (!(query instanceof Object)) {
throw new Error('query must be an object');
}
// eslint-disable-next-line @typescript-eslint/no-use-before-define
return verifyQuery(query, allowedAttributes, allowedOperations);
},
{
errors: [],
},
);
export const verifyQuery = (query: Query, allowedAttributes: string[], allowedOperations: string[], parent = ''): boolean => {
return Object.entries(removeDangerousProps(query)).every(([key, value]) => {
const path = parent ? `${parent}.${key}` : key;
if (parent === '' && path.startsWith('$')) {
if (!allowedOperations.includes(path)) {
isValidQuery.errors.push(`Invalid operation: ${path}`);
return false;
}
if (!Array.isArray(value)) {
isValidQuery.errors.push(`Invalid parameter for operation: ${path} : ${value}`);
return false;
}
return value.every((v) => verifyQuery(v, allowedAttributes, allowedOperations));
}
if (
!allowedAttributes.some((allowedAttribute) => {
if (allowedAttribute.endsWith('.*')) {
return path.startsWith(allowedAttribute.replace('.*', ''));
}
if (allowedAttribute.endsWith('*') && !allowedAttribute.endsWith('.*')) {
return true;
}
return path === allowedAttribute;
})
) {
isValidQuery.errors.push(`Invalid attribute: ${path}`);
return false;
}
if (value instanceof Object) {
return verifyQuery(value, allowedAttributes, allowedOperations, path);
}
return true;
});
};
import { CustomSounds } from '../../../models/server/raw';
import { API } from '../api'; import { API } from '../api';
import { findCustomSounds } from '../lib/custom-sounds';
API.v1.addRoute( API.v1.addRoute(
'custom-sounds.list', 'custom-sounds.list',
{ authRequired: true }, { authRequired: true },
{ {
get() { async get() {
const { offset, count } = this.getPaginationItems(); const { offset, count } = this.getPaginationItems();
const { sort, query } = this.parseJsonQuery(); const { sort, query } = this.parseJsonQuery();
const cursor = await CustomSounds.find(query, {
sort: sort || { name: 1 },
skip: offset,
limit: count,
});
return API.v1.success( const total = await cursor.count();
Promise.await(
findCustomSounds({ const sounds = await cursor.toArray();
query,
pagination: { return API.v1.success({
offset, sounds,
count, count: sounds.length,
sort, offset,
}, total,
}), });
),
);
}, },
}, },
); );
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment