Skip to content
Snippets Groups Projects
Unverified Commit c2fe38cb authored by Douglas Gubert's avatar Douglas Gubert Committed by GitHub
Browse files

feat: Ability to disable private app installation and updates via envvars (#30227)

parent bcf147f5
No related branches found
No related tags found
No related merge requests found
---
'@rocket.chat/meteor': patch
---
Added ability to disable private app installation via envvar (DISABLE_PRIVATE_APP_INSTALLATION)
......@@ -76,23 +76,23 @@ function AppInstallPage() {
} else {
app = await uploadAppEndpoint(fileData);
}
router.navigate({
name: 'marketplace',
params: {
context: 'private',
page: 'info',
id: appId || app.app.id,
},
});
reload();
} catch (e) {
handleAPIError(e);
} finally {
setInstalling(false);
setModal(null);
}
router.navigate({
name: 'marketplace',
params: {
context: 'private',
page: 'info',
id: appId || app.app.id,
},
});
reload();
setInstalling(false);
setModal(null);
};
const cancelAction = useCallback(() => {
......
import { t } from '../../../../app/utils/lib/i18n';
import { dispatchToastMessage } from '../../../lib/toast';
const shouldHandleErrorAsWarning = (message: string): boolean => {
......@@ -6,15 +7,12 @@ const shouldHandleErrorAsWarning = (message: string): boolean => {
return warnings.includes(message);
};
export const handleAPIError = (error: unknown): void => {
if (error instanceof Error) {
const { message } = error;
export const handleAPIError = (errorObject: unknown): void => {
const { message = '', error = '' } = errorObject as { message?: string; error?: string };
if (shouldHandleErrorAsWarning(message)) {
dispatchToastMessage({ type: 'warning', message });
return;
}
dispatchToastMessage({ type: 'error', message });
if (shouldHandleErrorAsWarning(message)) {
return dispatchToastMessage({ type: 'warning', message: t(message) });
}
dispatchToastMessage({ type: 'error', message: t(`Apps_Error_${error}`) });
};
......@@ -383,6 +383,11 @@ export class AppsRestApi {
return API.v1.failure({ error: 'Failed to get a file to install for the App. ' });
}
// Used mostly in Cloud hosting for security reasons
if (!marketplaceInfo && orchestrator.shouldDisablePrivateAppInstallation()) {
return API.v1.internalError('private_app_install_disabled');
}
const user = orchestrator
?.getConverters()
?.get('users')
......@@ -666,6 +671,7 @@ export class AppsRestApi {
async post() {
let buff;
let permissionsGranted;
let isPrivateAppUpload = false;
if (this.bodyParams.url) {
const response = await fetch(this.bodyParams.url);
......@@ -708,6 +714,8 @@ export class AppsRestApi {
return API.v1.internalError();
}
} else {
isPrivateAppUpload = true;
const app = await getUploadFormData(
{
request: this.request,
......@@ -732,6 +740,10 @@ export class AppsRestApi {
return API.v1.failure({ error: 'Failed to get a file to install for the App. ' });
}
if (isPrivateAppUpload && orchestrator.shouldDisablePrivateAppInstallation()) {
return API.v1.internalError('private_app_install_disabled');
}
const aff = await manager.update(buff, permissionsGranted);
const info: IAppInfo & { status?: AppStatus } = aff.getAppInfo();
......
......@@ -26,6 +26,8 @@ function isTesting() {
return process.env.TEST_MODE === 'true';
}
const DISABLED_PRIVATE_APP_INSTALLATION = ['yes', 'true'].includes(String(process.env.DISABLE_PRIVATE_APP_INSTALLATION).toLowerCase());
let appsSourceStorageType;
let appsSourceStorageFilesystemPath;
......@@ -137,6 +139,10 @@ export class AppServerOrchestrator {
return !isTesting();
}
shouldDisablePrivateAppInstallation() {
return DISABLED_PRIVATE_APP_INSTALLATION;
}
/**
* @returns {Logger}
*/
......
......@@ -521,6 +521,7 @@
"Apps_disabled_when_Enterprise_trial_ended_description": "Workspaces on Community Edition can have up to 5 marketplace apps and 3 private apps enabled. Ask your workspace admin to reenable apps.",
"Apps_disabled_when_Enterprise_trial_ended_description_admin": "Workspaces on Community Edition can have up to 5 marketplace apps and 3 private apps enabled. Reenable the apps you require.",
"Apps_Engine_Version": "Apps Engine Version",
"Apps_Error_private_app_install_disabled": "Private app installation and updates are disabled in this workspace",
"Apps_Essential_Alert": "This app is essential for the following events:",
"Apps_Essential_Disclaimer": "Events listed above will be disrupted if this app is disabled. If you want Rocket.Chat to work without this app's functionality, you need to uninstall it",
"Apps_Framework_Source_Package_Storage_Type": "Apps' Source Package Storage type",
......@@ -622,6 +623,7 @@
"Apps_Manual_Update_Modal_Title": "This app is already installed",
"Apps_Manual_Update_Modal_Body": "Do you want to update it?",
"Apps_User_Already_Exists": "The username \"{{username}}\" is already being used. Rename or remove the user using it to install this App",
"AutoLinker": "AutoLinker",
"Apps_WhatIsIt": "Apps: What Are They?",
"Apps_WhatIsIt_paragraph1": "A new icon in the administration area! What does this mean and what are Apps?",
......
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