diff --git a/README.md b/README.md
index 2ff5017..14eed11 100644
--- a/README.md
+++ b/README.md
@@ -12,7 +12,6 @@ Although a valid Mattermost Enterprise Edition License is required if using this
If you're running an Enterprise Edition of Mattermost and don't already have a valid license, you can obtain a trial license from **System Console > Edition and License**. If you're running the Team Edition of Mattermost, including when you run the server directly from source, you may instead configure your server to enable both testing (`ServiceSettings.EnableTesting`) and developer mode (`ServiceSettings.EnableDeveloper`). These settings are not recommended in production environments.
-
## How To Install
Download the latest released version and upload to your Mattermost installation on the plugins page
@@ -41,8 +40,8 @@ present in your Mattermost server on the first run of the job will be saved (i.e
already been purged by a data retention policy at the time of the first run will not be included
in the legal hold). Once data is held by the Legal Hold, it will not be affected by Data Retention
policy. However, newly created Legal Holds will not be able to access data that was already purged
-by Data Retention policy at the time of their first run *even if the data is held in an existing
-legal hold*.
+by Data Retention policy at the time of their first run _even if the data is held in an existing
+legal hold_.
You can edit the name, end data and users in a Legal Hold. Adding new users to a legal hold will only
include their data from the next run of the hold. Similarly, removing a user from the hold will
@@ -59,3 +58,9 @@ permanently purged from the storage area, and cannot be recovered.
See the `processor` subdirectory for how to turn the downloaded zip file into a human readable HTML
export that you can view and search in a web browser.
+
+## A note on downlading large legal holds
+
+For large legal holds, the download process can take more time than the HTTP request timeout. If you are experiencing timeouts, you can increase the timeout under **System Console** > **Web server** > **Write timeout** or in your `config.json` file. This is a global setting for the entire server.
+
+Keep in mind that the same applies for reverse proxies, which may have their own timeout settings. If you are using a reverse proxy, you may need to adjust the timeout settings there as well.
diff --git a/plugin.json b/plugin.json
index 277df66..b423ba4 100644
--- a/plugin.json
+++ b/plugin.json
@@ -38,6 +38,11 @@
"key": "LegalHoldsSettings",
"display_name": "Legal Holds:",
"type": "custom"
+ },
+ {
+ "key": "AmazonS3BucketSettings",
+ "display_name": "S3 Bucket:",
+ "type": "custom"
}
]
}
diff --git a/server/api.go b/server/api.go
index a1f21f1..0405c23 100644
--- a/server/api.go
+++ b/server/api.go
@@ -304,8 +304,6 @@ func (p *Plugin) runJobFromAPI(w http.ResponseWriter, _ *http.Request) {
go p.legalHoldJob.RunFromAPI()
}
-// we'll want to store the access secret encrypted in the database
-
// testAmazonS3Connection tests the plugin's custom Amazon S3 connection
func (p *Plugin) testAmazonS3Connection(w http.ResponseWriter, _ *http.Request) {
type messageResponse struct {
diff --git a/server/plugin.go b/server/plugin.go
index 3dd9fb7..48657b2 100644
--- a/server/plugin.go
+++ b/server/plugin.go
@@ -56,6 +56,14 @@ type Plugin struct {
}
func (p *Plugin) OnActivate() error {
+ // Check for an enterprise license or a development environment
+ config := p.API.GetConfig()
+ license := p.API.GetLicense()
+
+ if !pluginapi.IsEnterpriseLicensedOrDevelopment(config, license) {
+ return fmt.Errorf("this plugin requires an Enterprise license")
+ }
+
// Create plugin API client
p.Client = pluginapi.NewClient(p.API, p.Driver)
p.Client.Log.Debug("MM LH Plugin: OnActivate called")
diff --git a/webapp/src/components/admin_console_settings/secret_text_setting.tsx b/webapp/src/components/admin_console_settings/secret_text_setting.tsx
new file mode 100644
index 0000000..2bc4674
--- /dev/null
+++ b/webapp/src/components/admin_console_settings/secret_text_setting.tsx
@@ -0,0 +1,51 @@
+import React, {useEffect, useRef, useState} from 'react';
+
+import BaseSetting from './base_setting';
+
+type Props = {
+ id: string;
+ name: string;
+ helpText: string;
+ onChange: (value: string) => void;
+ value: string;
+ disabled?: boolean;
+};
+
+const SecretTextSetting = (props: Props) => {
+ const [value, setValue] = useState('');
+ const mounted = useRef(false);
+
+ useEffect(() => {
+ if (mounted.current) {
+ setValue(props.value);
+ return;
+ }
+
+ if (props.value) {
+ setValue('*'.repeat(32));
+ }
+
+ mounted.current = true;
+ }, [props.value]);
+
+ const handleChange = (newValue: string) => {
+ setValue(newValue);
+ };
+
+ return (
+
+ handleChange(e.target.value)}
+ disabled={props.disabled}
+ />
+
+ );
+};
+
+export default SecretTextSetting;
diff --git a/webapp/src/components/amazon_s3_bucket_settings.tsx b/webapp/src/components/amazon_s3_bucket_settings.tsx
index 05f74c1..d34de80 100644
--- a/webapp/src/components/amazon_s3_bucket_settings.tsx
+++ b/webapp/src/components/amazon_s3_bucket_settings.tsx
@@ -9,6 +9,7 @@ import TextSetting from './admin_console_settings/text_setting';
import SaveButton from './mattermost-webapp/save_button';
import BaseSetting from './admin_console_settings/base_setting';
import StatusMessage from './admin_console_settings/status_message';
+import SecretTextSetting from './admin_console_settings/secret_text_setting';
type FileSettings = {
DriverName: string;
@@ -185,7 +186,7 @@ const AmazonS3BucketSettings = (props: Props) => {
onChange={(value) => setFormValue('AmazonS3Endpoint', value)}
disabled={!formState.Enable}
/>
- {
background: 'var(--sys-center-channel-bg)',
borderRadius: '4px',
boxShadow: '0 2px 3px rgba(0, 0, 0, 0.08)',
+ marginBottom: '24px',
}}
>