Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop' into feat/marketplace-a…
Browse files Browse the repository at this point in the history
…pp-info-releases-tab
  • Loading branch information
rique223 committed Jun 29, 2022
2 parents 80f582b + d949f9a commit 62fa83e
Show file tree
Hide file tree
Showing 284 changed files with 6,567 additions and 2,476 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/auto-label.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ jobs:
steps:
- uses: ggazzo/gh-action-auto-label@beta-5
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.RC_AUTOLABEL_TOKEN }}
17 changes: 8 additions & 9 deletions .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ env:
MONGO_URL: mongodb://localhost:27017/rocketchat
MONGO_OPLOG_URL: mongodb://mongo:27017/local
TOOL_NODE_FLAGS: --max_old_space_size=4096
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}

jobs:
Expand Down Expand Up @@ -140,17 +139,17 @@ jobs:
- name: TurboRepo local server
uses: felixmosh/turborepo-gh-artifacts@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
repo-token: ${{ secrets.RC_TURBO_GH_TOKEN }}
server-token: ${{ secrets.TURBO_SERVER_TOKEN }}

- name: Lint
run: yarn lint --api="http://127.0.0.1:9080"
run: yarn lint --api="http://127.0.0.1:9080" --token="${{ secrets.TURBO_SERVER_TOKEN }}" --team='rc'

- name: Translation check
run: yarn turbo run translation-check --api="http://127.0.0.1:9080"
run: yarn turbo run translation-check --api="http://127.0.0.1:9080" --token="${{ secrets.TURBO_SERVER_TOKEN }}" --team='rc'

- name: TS typecheck
run: yarn turbo run typecheck --api="http://127.0.0.1:9080"
run: yarn turbo run typecheck --api="http://127.0.0.1:9080" --token="${{ secrets.TURBO_SERVER_TOKEN }}" --team='rc'

- name: Reset Meteor
if: startsWith(github.ref, 'refs/tags/') == 'true' || github.ref == 'refs/heads/develop'
Expand Down Expand Up @@ -251,11 +250,11 @@ jobs:
- name: TurboRepo local server
uses: felixmosh/turborepo-gh-artifacts@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
repo-token: ${{ secrets.RC_TURBO_GH_TOKEN }}
server-token: ${{ secrets.TURBO_SERVER_TOKEN }}

- name: Unit Test
run: yarn testunit --api="http://127.0.0.1:9080"
run: yarn testunit --api="http://127.0.0.1:9080" --token="${{ secrets.TURBO_SERVER_TOKEN }}" --team='rc'

- name: Restore build
uses: actions/download-artifact@v2
Expand Down Expand Up @@ -410,14 +409,14 @@ jobs:
- name: TurboRepo local server
uses: felixmosh/turborepo-gh-artifacts@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
repo-token: ${{ secrets.RC_TURBO_GH_TOKEN }}
server-token: ${{ secrets.TURBO_SERVER_TOKEN }}

- name: yarn install
run: yarn

- name: Unit Test
run: yarn testunit --api="http://127.0.0.1:9080"
run: yarn testunit --api="http://127.0.0.1:9080" --token="${{ secrets.TURBO_SERVER_TOKEN }}" --team='rc'

- name: Restore build
uses: actions/download-artifact@v2
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/no-new-js-files.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: "JS file preventer"
name: 'JS file preventer'
on:
pull_request:
types: [opened, synchronize]
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/pr-title-checker.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: "PR Title Checker"
name: 'PR Title Checker'
on:
pull_request:
types: [opened, edited]
Expand All @@ -9,4 +9,4 @@ jobs:
steps:
- uses: thehanimo/pr-title-checker@v1.3.4
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.RC_TITLE_CHECKER }}
2 changes: 1 addition & 1 deletion _templates/package/new/package.json.ejs.t
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ to: packages/<%= name %>/package.json
"lint:fix": "eslint --ext .js,.jsx,.ts,.tsx . --fix",
"jest": "jest",
"build": "rm -rf dist && tsc -p tsconfig.json",
"dev": "tsc -p --watch --preserveWatchOutput tsconfig.json"
"dev": "tsc -p tsconfig.json --watch --preserveWatchOutput"
},
"main": "./dist/index.js",
"typings": "./dist/index.d.ts",
Expand Down
33 changes: 33 additions & 0 deletions apps/meteor/app/api/server/middlewares/authentication.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Request, Response, NextFunction } from 'express';

import { Users } from '../../../models/server';
import { oAuth2ServerAuth } from '../../../oauth2-server-config/server/oauth/oauth2-server';

export type AuthenticationMiddlewareConfig = {
rejectUnauthorized: boolean;
};

export const defaultAuthenticationMiddlewareConfig = {
rejectUnauthorized: true,
};

export function authenticationMiddleware(config: AuthenticationMiddlewareConfig = defaultAuthenticationMiddlewareConfig) {
return (req: Request, res: Response, next: NextFunction): void => {
const { 'x-user-id': userId, 'x-auth-token': authToken } = req.headers;

if (userId && authToken) {
req.user = Users.findOneByIdAndLoginToken(userId, authToken);
} else {
req.user = oAuth2ServerAuth(req)?.user;
}

if (config.rejectUnauthorized && !req.user) {
res.status(401).send('Unauthorized');
return;
}

req.userId = req.user?._id;

next();
};
}
3 changes: 2 additions & 1 deletion apps/meteor/app/api/server/v1/import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { API } from '../api';
import { hasPermission } from '../../../authorization/server';
import { Imports } from '../../../models/server';
import { Importers } from '../../../importer/server';
import { executeUploadImportFile } from '../../../importer/server/methods/uploadImportFile';

API.v1.addRoute(
'uploadImportFile',
Expand All @@ -26,7 +27,7 @@ API.v1.addRoute(
post() {
const { binaryContent, contentType, fileName, importerKey } = this.bodyParams;

return API.v1.success(Meteor.call('uploadImportFile', binaryContent, contentType, fileName, importerKey));
return API.v1.success(executeUploadImportFile(this.userId, binaryContent, contentType, fileName, importerKey));
},
},
);
Expand Down
56 changes: 36 additions & 20 deletions apps/meteor/app/api/server/v1/voip/rooms.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Match, check } from 'meteor/check';
import { Random } from 'meteor/random';
import type { ILivechatAgent } from '@rocket.chat/core-typings';
import type { ILivechatAgent, IVoipRoom } from '@rocket.chat/core-typings';
import { isVoipRoomProps, isVoipRoomsProps, isVoipRoomCloseProps } from '@rocket.chat/rest-typings/dist/v1/voip';
import { VoipRoom, LivechatVisitors, Users } from '@rocket.chat/models';
import { isVoipRoomCloseProps } from '@rocket.chat/rest-typings/dist/v1/voip';

import { API } from '../../api';
import { LivechatVoip } from '../../../../../server/sdk';
Expand All @@ -25,6 +24,7 @@ const validateDateParams = (property: string, date: DateParam = {}): DateParam =
const parseAndValidate = (property: string, date?: string): DateParam => {
return validateDateParams(property, parseDateParams(date));
};

/**
* @openapi
* /voip/server/api/v1/voip/room
Expand Down Expand Up @@ -81,23 +81,38 @@ const parseAndValidate = (property: string, date?: string): DateParam => {
* $ref: '#/components/schemas/ApiFailureV1'
*/

const isRoomSearchProps = (props: any): props is { rid: string; token: string } => {
return 'rid' in props && 'token' in props;
};

const isRoomCreationProps = (props: any): props is { agentId: string; direction: IVoipRoom['direction'] } => {
return 'agentId' in props && 'direction' in props;
};

API.v1.addRoute(
'voip/room',
{
authRequired: true,
rateLimiterOptions: { numRequestsAllowed: 5, intervalTimeInMS: 60000 },
permissionsRequired: ['inbound-voip-calls'],
validateParams: isVoipRoomProps,
},
{
async get() {
const defaultCheckParams = {
token: String,
agentId: Match.Maybe(String),
rid: Match.Maybe(String),
};
check(this.queryParams, defaultCheckParams);

const { token, rid, agentId } = this.queryParams;
const { token } = this.queryParams;
let agentId: string | undefined = undefined;
let direction: IVoipRoom['direction'] = 'inbound';
let rid: string | undefined = undefined;

if (isRoomCreationProps(this.queryParams)) {
agentId = this.queryParams.agentId;
direction = this.queryParams.direction;
}

if (isRoomSearchProps(this.queryParams)) {
rid = this.queryParams.rid;
}

const guest = await LivechatVisitors.getVisitorByToken(token, {});
if (!guest) {
return API.v1.failure('invalid-token');
Expand All @@ -123,7 +138,11 @@ API.v1.addRoute(
const agent = { agentId: _id, username };
const rid = Random.id();

return API.v1.success(await LivechatVoip.getNewRoom(guest, agent, rid, { projection: API.v1.defaultFieldsToExclude }));
return API.v1.success(
await LivechatVoip.getNewRoom(guest, agent, rid, direction, {
projection: API.v1.defaultFieldsToExclude,
}),
);
}

const room = await VoipRoom.findOneByIdAndVisitorToken(rid, token, { projection: API.v1.defaultFieldsToExclude });
Expand All @@ -137,20 +156,15 @@ API.v1.addRoute(

API.v1.addRoute(
'voip/rooms',
{ authRequired: true },
{ authRequired: true, validateParams: isVoipRoomsProps },
{
async get() {
const { offset, count } = this.getPaginationItems();

const { sort, fields } = this.parseJsonQuery();
const { agents, open, tags, queue, visitorId } = this.requestParams();
const { agents, open, tags, queue, visitorId, direction, roomName } = this.requestParams();
const { createdAt: createdAtParam, closedAt: closedAtParam } = this.requestParams();

check(agents, Match.Maybe([String]));
check(open, Match.Maybe(String));
check(tags, Match.Maybe([String]));
check(queue, Match.Maybe(String));
check(visitorId, Match.Maybe(String));

// Reusing same L room permissions for simplicity
const hasAdminAccess = hasPermission(this.userId, 'view-livechat-rooms');
const hasAgentAccess = hasPermission(this.userId, 'view-l-room') && agents?.includes(this.userId) && agents?.length === 1;
Expand All @@ -170,6 +184,8 @@ API.v1.addRoute(
visitorId,
createdAt,
closedAt,
direction,
roomName,
options: { sort, offset, count, fields },
}),
);
Expand Down
17 changes: 12 additions & 5 deletions apps/meteor/app/apps/server/bridges/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@ import { AppApi } from '@rocket.chat/apps-engine/server/managers/AppApi';
import { RequestMethod } from '@rocket.chat/apps-engine/definition/accessors';

import { AppServerOrchestrator } from '../orchestrator';
import { authenticationMiddleware } from '../../../api/server/middlewares/authentication';

const apiServer = express();

apiServer.disable('x-powered-by');

WebApp.connectHandlers.use(apiServer);

type RequestWithPrivateHash = Request & {
interface IRequestWithPrivateHash extends Request {
_privateHash?: string;
content?: any;
};
}

export class AppApisBridge extends ApiBridge {
appRouters: Map<string, IRouter>;
Expand All @@ -27,7 +28,7 @@ export class AppApisBridge extends ApiBridge {
super();
this.appRouters = new Map();

apiServer.use('/api/apps/private/:appId/:hash', (req: RequestWithPrivateHash, res: Response) => {
apiServer.use('/api/apps/private/:appId/:hash', (req: IRequestWithPrivateHash, res: Response) => {
const notFound = (): Response => res.sendStatus(404);

const router = this.appRouters.get(req.params.appId);
Expand Down Expand Up @@ -73,7 +74,7 @@ export class AppApisBridge extends ApiBridge {
}

if (router[method] instanceof Function) {
router[method](routePath, Meteor.bindEnvironment(this._appApiExecutor(endpoint, appId)));
router[method](routePath, this._authMiddleware(endpoint, appId), Meteor.bindEnvironment(this._appApiExecutor(endpoint, appId)));
}
}

Expand All @@ -85,6 +86,11 @@ export class AppApisBridge extends ApiBridge {
}
}

private _authMiddleware(endpoint: IApiEndpoint, _appId: string): RequestHandler {
const authFunction = authenticationMiddleware({ rejectUnauthorized: !!endpoint.authRequired });
return Meteor.bindEnvironment(authFunction);
}

private _verifyApi(api: IApi, endpoint: IApiEndpoint): void {
if (typeof api !== 'object') {
throw new Error('Invalid Api parameter provided, it must be a valid IApi object.');
Expand All @@ -96,14 +102,15 @@ export class AppApisBridge extends ApiBridge {
}

private _appApiExecutor(endpoint: IApiEndpoint, appId: string): RequestHandler {
return (req: RequestWithPrivateHash, res: Response): void => {
return (req: IRequestWithPrivateHash, res: Response): void => {
const request: IApiRequest = {
method: req.method.toLowerCase() as RequestMethod,
headers: req.headers as { [key: string]: string },
query: (req.query as { [key: string]: string }) || {},
params: req.params || {},
content: req.body,
privateHash: req._privateHash,
user: req.user && this.orch.getConverters()?.get('users')?.convertToApp(req.user),
};

this.orch
Expand Down
12 changes: 11 additions & 1 deletion apps/meteor/app/apps/server/bridges/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ export class AppSettingBridge extends ServerSettingBridge {
throw new Error(`The setting "${setting.id}" is not readable.`);
}

throw new Error('Method not implemented.');
await Settings.updateValueById(setting.id, setting.value);
}

protected async incrementValue(id: string, value: number, appId: string): Promise<void> {
this.orch.debugLog(`The App ${appId} is incrementing the value of the setting ${id}.`);

if (!(await this.isReadableById(id, appId))) {
throw new Error(`The setting "${id}" is not readable.`);
}

await Settings.incrementValueById(id, value);
}
}
12 changes: 5 additions & 7 deletions apps/meteor/app/apps/server/communication/uikit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import { WebApp } from 'meteor/webapp';
import { UIKitIncomingInteractionType } from '@rocket.chat/apps-engine/definition/uikit';
import { AppInterface } from '@rocket.chat/apps-engine/definition/metadata';

import { Users } from '../../../models/server';
import { settings } from '../../../settings/server';
import { Apps, AppServerOrchestrator } from '../orchestrator';
import { UiKitCoreApp } from '../../../../server/sdk';
import { authenticationMiddleware } from '../../../api/server/middlewares/authentication';

const apiServer = express();

Expand Down Expand Up @@ -51,16 +51,14 @@ Meteor.startup(() => {
settings.get('API_Enable_Rate_Limiter') !== true ||
(process.env.NODE_ENV === 'development' && settings.get('API_Enable_Rate_Limiter_Dev') !== true),
});

router.use(apiLimiter);
});

router.use((req, res, next) => {
const { 'x-user-id': userId, 'x-auth-token': authToken, 'x-visitor-token': visitorToken } = req.headers;
router.use(authenticationMiddleware({ rejectUnauthorized: false }));

if (userId && authToken) {
req.body.user = Users.findOneByIdAndLoginToken(userId, authToken);
req.body.userId = req.body.user._id;
}
router.use((req, res, next) => {
const { 'x-visitor-token': visitorToken } = req.headers;

if (visitorToken) {
req.body.visitor = Apps.getConverters()?.get('visitors').convertByToken(visitorToken);
Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/app/emoji/client/emojiPicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ Template.emojiPicker.events({
'click .add-custom'(event) {
event.stopPropagation();
event.preventDefault();
FlowRouter.go('/admin/emoji-custom');
FlowRouter.go('/admin/emoji-custom/new');
EmojiPicker.close();
},
'click .category-link'(event) {
Expand Down
Loading

0 comments on commit 62fa83e

Please sign in to comment.