diff --git a/backend/azureblob/azureblob.go b/backend/azureblob/azureblob.go index 404b143c0..149938b6e 100644 --- a/backend/azureblob/azureblob.go +++ b/backend/azureblob/azureblob.go @@ -95,6 +95,7 @@ Leave blank to use SAS URL or Emulator, otherwise it needs to be set. If this is blank and if env_auth is set it will be read from the environment variable ` + "`AZURE_STORAGE_ACCOUNT_NAME`" + ` if possible. `, + Sensitive: true, }, { Name: "env_auth", Help: `Read credentials from runtime (environment variables, CLI or MSI). @@ -106,11 +107,13 @@ See the [authentication docs](/azureblob#authentication) for full info.`, Help: `Storage Account Shared Key. Leave blank to use SAS URL or Emulator.`, + Sensitive: true, }, { Name: "sas_url", Help: `SAS URL for container level access only. Leave blank if using account/key or Emulator.`, + Sensitive: true, }, { Name: "tenant", Help: `ID of the service principal's tenant. Also called its directory ID. @@ -120,6 +123,7 @@ Set this if using - Service principal with certificate - User with username and password `, + Sensitive: true, }, { Name: "client_id", Help: `The ID of the client in use. @@ -129,6 +133,7 @@ Set this if using - Service principal with certificate - User with username and password `, + Sensitive: true, }, { Name: "client_secret", Help: `One of the service principal's client secrets @@ -136,6 +141,7 @@ Set this if using Set this if using - Service principal with client secret `, + Sensitive: true, }, { Name: "client_certificate_path", Help: `Path to a PEM or PKCS12 certificate file including the private key. @@ -173,7 +179,8 @@ Optionally set this if using Set this if using - User with username and password `, - Advanced: true, + Advanced: true, + Sensitive: true, }, { Name: "password", Help: `The user's password @@ -216,17 +223,20 @@ msi_client_id, or msi_mi_res_id parameters.`, Default: false, Advanced: true, }, { - Name: "msi_object_id", - Help: "Object ID of the user-assigned MSI to use, if any.\n\nLeave blank if msi_client_id or msi_mi_res_id specified.", - Advanced: true, + Name: "msi_object_id", + Help: "Object ID of the user-assigned MSI to use, if any.\n\nLeave blank if msi_client_id or msi_mi_res_id specified.", + Advanced: true, + Sensitive: true, }, { - Name: "msi_client_id", - Help: "Object ID of the user-assigned MSI to use, if any.\n\nLeave blank if msi_object_id or msi_mi_res_id specified.", - Advanced: true, + Name: "msi_client_id", + Help: "Object ID of the user-assigned MSI to use, if any.\n\nLeave blank if msi_object_id or msi_mi_res_id specified.", + Advanced: true, + Sensitive: true, }, { - Name: "msi_mi_res_id", - Help: "Azure resource ID of the user-assigned MSI to use, if any.\n\nLeave blank if msi_client_id or msi_object_id specified.", - Advanced: true, + Name: "msi_mi_res_id", + Help: "Azure resource ID of the user-assigned MSI to use, if any.\n\nLeave blank if msi_client_id or msi_object_id specified.", + Advanced: true, + Sensitive: true, }, { Name: "use_emulator", Help: "Uses local storage emulator if provided as 'true'.\n\nLeave blank if using real azure storage endpoint.", diff --git a/backend/b2/b2.go b/backend/b2/b2.go index aa0a80e7b..211ec05e4 100644 --- a/backend/b2/b2.go +++ b/backend/b2/b2.go @@ -75,13 +75,15 @@ func init() { Description: "Backblaze B2", NewFs: NewFs, Options: []fs.Option{{ - Name: "account", - Help: "Account ID or Application Key ID.", - Required: true, + Name: "account", + Help: "Account ID or Application Key ID.", + Required: true, + Sensitive: true, }, { - Name: "key", - Help: "Application Key.", - Required: true, + Name: "key", + Help: "Application Key.", + Required: true, + Sensitive: true, }, { Name: "endpoint", Help: "Endpoint for the service.\n\nLeave blank normally.", diff --git a/backend/box/box.go b/backend/box/box.go index 474443d39..57e8d4f23 100644 --- a/backend/box/box.go +++ b/backend/box/box.go @@ -107,16 +107,18 @@ func init() { return nil, nil }, Options: append(oauthutil.SharedOptions, []fs.Option{{ - Name: "root_folder_id", - Help: "Fill in for rclone to use a non root folder as its starting point.", - Default: "0", - Advanced: true, + Name: "root_folder_id", + Help: "Fill in for rclone to use a non root folder as its starting point.", + Default: "0", + Advanced: true, + Sensitive: true, }, { Name: "box_config_file", Help: "Box App config.json location\n\nLeave blank normally." + env.ShellExpandHelp, }, { - Name: "access_token", - Help: "Box App Primary Access Token\n\nLeave blank normally.", + Name: "access_token", + Help: "Box App Primary Access Token\n\nLeave blank normally.", + Sensitive: true, }, { Name: "box_sub_type", Default: "user", diff --git a/backend/cache/cache.go b/backend/cache/cache.go index 3a0bc05ae..828744c47 100644 --- a/backend/cache/cache.go +++ b/backend/cache/cache.go @@ -76,17 +76,19 @@ func init() { Name: "plex_url", Help: "The URL of the Plex server.", }, { - Name: "plex_username", - Help: "The username of the Plex user.", + Name: "plex_username", + Help: "The username of the Plex user.", + Sensitive: true, }, { Name: "plex_password", Help: "The password of the Plex user.", IsPassword: true, }, { - Name: "plex_token", - Help: "The plex token for authentication - auto set normally.", - Hide: fs.OptionHideBoth, - Advanced: true, + Name: "plex_token", + Help: "The plex token for authentication - auto set normally.", + Hide: fs.OptionHideBoth, + Advanced: true, + Sensitive: true, }, { Name: "plex_insecure", Help: "Skip all certificate verification when connecting to the Plex server.", diff --git a/backend/drive/drive.go b/backend/drive/drive.go index 059c3cd91..91f617324 100644 --- a/backend/drive/drive.go +++ b/backend/drive/drive.go @@ -277,20 +277,23 @@ Leave blank normally. Fill in to access "Computers" folders (see docs), or for rclone to use a non root folder as its starting point. `, - Advanced: true, + Advanced: true, + Sensitive: true, }, { Name: "service_account_file", Help: "Service Account Credentials JSON file path.\n\nLeave blank normally.\nNeeded only if you want use SA instead of interactive login." + env.ShellExpandHelp, }, { - Name: "service_account_credentials", - Help: "Service Account Credentials JSON blob.\n\nLeave blank normally.\nNeeded only if you want use SA instead of interactive login.", - Hide: fs.OptionHideConfigurator, - Advanced: true, + Name: "service_account_credentials", + Help: "Service Account Credentials JSON blob.\n\nLeave blank normally.\nNeeded only if you want use SA instead of interactive login.", + Hide: fs.OptionHideConfigurator, + Advanced: true, + Sensitive: true, }, { - Name: "team_drive", - Help: "ID of the Shared Drive (Team Drive).", - Hide: fs.OptionHideConfigurator, - Advanced: true, + Name: "team_drive", + Help: "ID of the Shared Drive (Team Drive).", + Hide: fs.OptionHideConfigurator, + Advanced: true, + Sensitive: true, }, { Name: "auth_owner_only", Default: false, @@ -416,10 +419,11 @@ date is used.`, Help: "Size of listing chunk 100-1000, 0 to disable.", Advanced: true, }, { - Name: "impersonate", - Default: "", - Help: `Impersonate this user when using a service account.`, - Advanced: true, + Name: "impersonate", + Default: "", + Help: `Impersonate this user when using a service account.`, + Advanced: true, + Sensitive: true, }, { Name: "alternate_export", Default: false, @@ -592,7 +596,8 @@ Note also that opening the folder once in the web interface (with the user you've authenticated rclone with) seems to be enough so that the resource key is no needed. `, - Advanced: true, + Advanced: true, + Sensitive: true, }, { Name: config.ConfigEncoding, Help: config.ConfigEncodingHelp, diff --git a/backend/dropbox/dropbox.go b/backend/dropbox/dropbox.go index 8963cd655..6a9ced2c1 100644 --- a/backend/dropbox/dropbox.go +++ b/backend/dropbox/dropbox.go @@ -182,8 +182,9 @@ client_secret) to use this option as currently rclone's default set of permissions doesn't include "members.read". This can be added once v1.55 or later is in use everywhere. `, - Default: "", - Advanced: true, + Default: "", + Advanced: true, + Sensitive: true, }, { Name: "shared_files", Help: `Instructs rclone to work on individual shared files. diff --git a/backend/fichier/fichier.go b/backend/fichier/fichier.go index c7ff25f52..25df3d971 100644 --- a/backend/fichier/fichier.go +++ b/backend/fichier/fichier.go @@ -38,8 +38,9 @@ func init() { Description: "1Fichier", NewFs: NewFs, Options: []fs.Option{{ - Help: "Your API Key, get it from https://1fichier.com/console/params.pl.", - Name: "api_key", + Help: "Your API Key, get it from https://1fichier.com/console/params.pl.", + Name: "api_key", + Sensitive: true, }, { Help: "If you want to download a shared folder, add this parameter.", Name: "shared_folder", diff --git a/backend/filefabric/filefabric.go b/backend/filefabric/filefabric.go index 3d157f8fb..adb0b8acf 100644 --- a/backend/filefabric/filefabric.go +++ b/backend/filefabric/filefabric.go @@ -84,6 +84,7 @@ Leave blank normally. Fill in to make rclone start with directory of a given ID. `, + Sensitive: true, }, { Name: "permanent_token", Help: `Permanent Authentication Token. @@ -97,6 +98,7 @@ These tokens are normally valid for several years. For more info see: https://docs.storagemadeeasy.com/organisationcloud/api-tokens `, + Sensitive: true, }, { Name: "token", Help: `Session Token. @@ -106,7 +108,8 @@ usually valid for 1 hour. Don't set this value - rclone will set it automatically. `, - Advanced: true, + Advanced: true, + Sensitive: true, }, { Name: "token_expiry", Help: `Token expiry time. diff --git a/backend/ftp/ftp.go b/backend/ftp/ftp.go index cedd07861..6a2758911 100644 --- a/backend/ftp/ftp.go +++ b/backend/ftp/ftp.go @@ -48,13 +48,15 @@ func init() { Description: "FTP", NewFs: NewFs, Options: []fs.Option{{ - Name: "host", - Help: "FTP host to connect to.\n\nE.g. \"ftp.example.com\".", - Required: true, + Name: "host", + Help: "FTP host to connect to.\n\nE.g. \"ftp.example.com\".", + Required: true, + Sensitive: true, }, { - Name: "user", - Help: "FTP username.", - Default: currentUser, + Name: "user", + Help: "FTP username.", + Default: currentUser, + Sensitive: true, }, { Name: "port", Help: "FTP port number.", diff --git a/backend/googlecloudstorage/googlecloudstorage.go b/backend/googlecloudstorage/googlecloudstorage.go index 4bd7a41e4..5f8458788 100644 --- a/backend/googlecloudstorage/googlecloudstorage.go +++ b/backend/googlecloudstorage/googlecloudstorage.go @@ -91,18 +91,21 @@ func init() { }) }, Options: append(oauthutil.SharedOptions, []fs.Option{{ - Name: "project_number", - Help: "Project number.\n\nOptional - needed only for list/create/delete buckets - see your developer console.", + Name: "project_number", + Help: "Project number.\n\nOptional - needed only for list/create/delete buckets - see your developer console.", + Sensitive: true, }, { - Name: "user_project", - Help: "User project.\n\nOptional - needed only for requester pays.", + Name: "user_project", + Help: "User project.\n\nOptional - needed only for requester pays.", + Sensitive: true, }, { Name: "service_account_file", Help: "Service Account Credentials JSON file path.\n\nLeave blank normally.\nNeeded only if you want use SA instead of interactive login." + env.ShellExpandHelp, }, { - Name: "service_account_credentials", - Help: "Service Account Credentials JSON blob.\n\nLeave blank normally.\nNeeded only if you want use SA instead of interactive login.", - Hide: fs.OptionHideBoth, + Name: "service_account_credentials", + Help: "Service Account Credentials JSON blob.\n\nLeave blank normally.\nNeeded only if you want use SA instead of interactive login.", + Hide: fs.OptionHideBoth, + Sensitive: true, }, { Name: "anonymous", Help: "Access public buckets and objects without credentials.\n\nSet to 'true' if you just want to download files and don't configure credentials.", diff --git a/backend/hdfs/hdfs.go b/backend/hdfs/hdfs.go index fad1866e9..896b7c18f 100644 --- a/backend/hdfs/hdfs.go +++ b/backend/hdfs/hdfs.go @@ -19,9 +19,10 @@ func init() { Description: "Hadoop distributed file system", NewFs: NewFs, Options: []fs.Option{{ - Name: "namenode", - Help: "Hadoop name node and port.\n\nE.g. \"namenode:8020\" to connect to host namenode at port 8020.", - Required: true, + Name: "namenode", + Help: "Hadoop name node and port.\n\nE.g. \"namenode:8020\" to connect to host namenode at port 8020.", + Required: true, + Sensitive: true, }, { Name: "username", Help: "Hadoop user name.", @@ -29,6 +30,7 @@ func init() { Value: "root", Help: "Connect to hdfs as root.", }}, + Sensitive: true, }, { Name: "service_principal_name", Help: `Kerberos service principal name for the namenode. @@ -36,7 +38,8 @@ func init() { Enables KERBEROS authentication. Specifies the Service Principal Name (SERVICE/FQDN) for the namenode. E.g. \"hdfs/namenode.hadoop.docker\" for namenode running as service 'hdfs' with FQDN 'namenode.hadoop.docker'.`, - Advanced: true, + Advanced: true, + Sensitive: true, }, { Name: "data_transfer_protection", Help: `Kerberos data transfer protection: authentication|integrity|privacy. diff --git a/backend/internetarchive/internetarchive.go b/backend/internetarchive/internetarchive.go index 4c1dc7f82..ad03ead4c 100644 --- a/backend/internetarchive/internetarchive.go +++ b/backend/internetarchive/internetarchive.go @@ -133,11 +133,13 @@ Owner is able to add custom keys. Metadata feature grabs all the keys including }, Options: []fs.Option{{ - Name: "access_key_id", - Help: "IAS3 Access Key.\n\nLeave blank for anonymous access.\nYou can find one here: https://archive.org/account/s3.php", + Name: "access_key_id", + Help: "IAS3 Access Key.\n\nLeave blank for anonymous access.\nYou can find one here: https://archive.org/account/s3.php", + Sensitive: true, }, { - Name: "secret_access_key", - Help: "IAS3 Secret Key (password).\n\nLeave blank for anonymous access.", + Name: "secret_access_key", + Help: "IAS3 Secret Key (password).\n\nLeave blank for anonymous access.", + Sensitive: true, }, { // their official client (https://github.com/jjjake/internetarchive) hardcodes following the two Name: "endpoint", diff --git a/backend/jottacloud/jottacloud.go b/backend/jottacloud/jottacloud.go index 0e6f087ed..9cce7b723 100644 --- a/backend/jottacloud/jottacloud.go +++ b/backend/jottacloud/jottacloud.go @@ -88,7 +88,7 @@ func init() { Description: "Jottacloud", NewFs: NewFs, Config: Config, - Options: []fs.Option{{ + Options: append(oauthutil.SharedOptions, []fs.Option{{ Name: "md5_memory_limit", Help: "Files bigger than this will be cached on disk to calculate the MD5 if required.", Default: fs.SizeSuffix(10 * 1024 * 1024), @@ -123,7 +123,7 @@ func init() { Default: (encoder.Display | encoder.EncodeWin | // :?"*<>| encoder.EncodeInvalidUtf8), - }}, + }}...), }) } diff --git a/backend/koofr/koofr.go b/backend/koofr/koofr.go index 7b2dfefe2..e71fb4168 100644 --- a/backend/koofr/koofr.go +++ b/backend/koofr/koofr.go @@ -61,9 +61,10 @@ func init() { Default: true, Advanced: true, }, { - Name: "user", - Help: "Your user name.", - Required: true, + Name: "user", + Help: "Your user name.", + Required: true, + Sensitive: true, }, { Name: "password", Help: "Your password for rclone (generate one at https://app.koofr.net/app/admin/preferences/password).", diff --git a/backend/mailru/mailru.go b/backend/mailru/mailru.go index 28fafe702..b1cb6e775 100644 --- a/backend/mailru/mailru.go +++ b/backend/mailru/mailru.go @@ -85,10 +85,11 @@ func init() { Name: "mailru", Description: "Mail.ru Cloud", NewFs: NewFs, - Options: []fs.Option{{ - Name: "user", - Help: "User name (usually email).", - Required: true, + Options: append(oauthutil.SharedOptions, []fs.Option{{ + Name: "user", + Help: "User name (usually email).", + Required: true, + Sensitive: true, }, { Name: "pass", Help: `Password. @@ -213,7 +214,7 @@ Supported quirks: atomicmkdir binlist unknowndirs`, encoder.EncodeWin | // :?"*<>| encoder.EncodeBackSlash | encoder.EncodeInvalidUtf8), - }}, + }}...), }) } diff --git a/backend/mega/mega.go b/backend/mega/mega.go index d2f3b5ac1..31ef39a7f 100644 --- a/backend/mega/mega.go +++ b/backend/mega/mega.go @@ -58,9 +58,10 @@ func init() { Description: "Mega", NewFs: NewFs, Options: []fs.Option{{ - Name: "user", - Help: "User name.", - Required: true, + Name: "user", + Help: "User name.", + Required: true, + Sensitive: true, }, { Name: "pass", Help: "Password.", diff --git a/backend/netstorage/netstorage.go b/backend/netstorage/netstorage.go index 40db98501..d5a0e9c6b 100755 --- a/backend/netstorage/netstorage.go +++ b/backend/netstorage/netstorage.go @@ -65,11 +65,13 @@ HTTP is provided primarily for debugging purposes.`, Help: `Domain+path of NetStorage host to connect to. Format should be ` + "`/`", - Required: true, + Required: true, + Sensitive: true, }, { - Name: "account", - Help: "Set the NetStorage account name", - Required: true, + Name: "account", + Help: "Set the NetStorage account name", + Required: true, + Sensitive: true, }, { Name: "secret", Help: `Set the NetStorage account secret/G2O key for authentication. diff --git a/backend/onedrive/onedrive.go b/backend/onedrive/onedrive.go index 36041905d..d6e179394 100644 --- a/backend/onedrive/onedrive.go +++ b/backend/onedrive/onedrive.go @@ -131,10 +131,11 @@ Note that the chunks will be buffered into memory.`, Default: defaultChunkSize, Advanced: true, }, { - Name: "drive_id", - Help: "The ID of the drive to use.", - Default: "", - Advanced: true, + Name: "drive_id", + Help: "The ID of the drive to use.", + Default: "", + Advanced: true, + Sensitive: true, }, { Name: "drive_type", Help: "The type of the drive (" + driveTypePersonal + " | " + driveTypeBusiness + " | " + driveTypeSharepoint + ").", @@ -148,7 +149,8 @@ This isn't normally needed, but in special circumstances you might know the folder ID that you wish to access but not be able to get there through a path traversal. `, - Advanced: true, + Advanced: true, + Sensitive: true, }, { Name: "access_scopes", Help: `Set scopes to be requested by rclone. @@ -260,7 +262,8 @@ this flag there. At the time of writing this only works with OneDrive personal paid accounts. `, - Advanced: true, + Advanced: true, + Sensitive: true, }, { Name: "hash_type", Default: "auto", diff --git a/backend/opendrive/opendrive.go b/backend/opendrive/opendrive.go index 037372e13..263daa223 100644 --- a/backend/opendrive/opendrive.go +++ b/backend/opendrive/opendrive.go @@ -42,9 +42,10 @@ func init() { Description: "OpenDrive", NewFs: NewFs, Options: []fs.Option{{ - Name: "username", - Help: "Username.", - Required: true, + Name: "username", + Help: "Username.", + Required: true, + Sensitive: true, }, { Name: "password", Help: "Password.", diff --git a/backend/oracleobjectstorage/options.go b/backend/oracleobjectstorage/options.go index ee5e80761..3f89badaf 100644 --- a/backend/oracleobjectstorage/options.go +++ b/backend/oracleobjectstorage/options.go @@ -92,14 +92,16 @@ func newOptions() []fs.Option { Help: noAuthHelpText, }}, }, { - Name: "namespace", - Help: "Object storage namespace", - Required: true, + Name: "namespace", + Help: "Object storage namespace", + Required: true, + Sensitive: true, }, { - Name: "compartment", - Help: "Object storage compartment OCID", - Provider: "!no_auth", - Required: true, + Name: "compartment", + Help: "Object storage compartment OCID", + Provider: "!no_auth", + Required: true, + Sensitive: true, }, { Name: "region", Help: "Object storage Region", diff --git a/backend/pcloud/pcloud.go b/backend/pcloud/pcloud.go index 726d9ee8b..9d6256b1a 100644 --- a/backend/pcloud/pcloud.go +++ b/backend/pcloud/pcloud.go @@ -110,10 +110,11 @@ func init() { encoder.EncodeBackSlash | encoder.EncodeInvalidUtf8), }, { - Name: "root_folder_id", - Help: "Fill in for rclone to use a non root folder as its starting point.", - Default: "d0", - Advanced: true, + Name: "root_folder_id", + Help: "Fill in for rclone to use a non root folder as its starting point.", + Default: "d0", + Advanced: true, + Sensitive: true, }, { Name: "hostname", Help: `Hostname to connect to. @@ -138,7 +139,8 @@ with rclone authorize. This is only required when you want to use the cleanup command. Due to a bug in the pcloud API the required API does not support OAuth authentication so we have to rely on user password authentication for it.`, - Advanced: true, + Advanced: true, + Sensitive: true, }, { Name: "password", Help: "Your pcloud password.", diff --git a/backend/pikpak/pikpak.go b/backend/pikpak/pikpak.go index 1f9790a1c..d82361022 100644 --- a/backend/pikpak/pikpak.go +++ b/backend/pikpak/pikpak.go @@ -158,9 +158,10 @@ func init() { return nil, fmt.Errorf("unknown state %q", config.State) }, Options: append(pikpakOAuthOptions(), []fs.Option{{ - Name: "user", - Help: "Pikpak username.", - Required: true, + Name: "user", + Help: "Pikpak username.", + Required: true, + Sensitive: true, }, { Name: "pass", Help: "Pikpak password.", @@ -173,7 +174,8 @@ Leave blank normally. Fill in for rclone to use a non root folder as its starting point. `, - Advanced: true, + Advanced: true, + Sensitive: true, }, { Name: "use_trash", Default: true, diff --git a/backend/premiumizeme/premiumizeme.go b/backend/premiumizeme/premiumizeme.go index 8f3aa1ce8..4adaa5af2 100644 --- a/backend/premiumizeme/premiumizeme.go +++ b/backend/premiumizeme/premiumizeme.go @@ -82,14 +82,15 @@ func init() { OAuth2Config: oauthConfig, }) }, - Options: []fs.Option{{ + Options: append(oauthutil.SharedOptions, []fs.Option{{ Name: "api_key", Help: `API Key. This is not normally used - use oauth instead. `, - Hide: fs.OptionHideBoth, - Default: "", + Hide: fs.OptionHideBoth, + Default: "", + Sensitive: true, }, { Name: config.ConfigEncoding, Help: config.ConfigEncodingHelp, @@ -99,7 +100,7 @@ This is not normally used - use oauth instead. encoder.EncodeBackSlash | encoder.EncodeDoubleQuote | encoder.EncodeInvalidUtf8), - }}, + }}...), }) } diff --git a/backend/putio/putio.go b/backend/putio/putio.go index 692364166..a12be5f9b 100644 --- a/backend/putio/putio.go +++ b/backend/putio/putio.go @@ -67,7 +67,7 @@ func init() { NoOffline: true, }) }, - Options: []fs.Option{{ + Options: append(oauthutil.SharedOptions, []fs.Option{{ Name: config.ConfigEncoding, Help: config.ConfigEncodingHelp, Advanced: true, @@ -77,7 +77,7 @@ func init() { Default: (encoder.Display | encoder.EncodeBackSlash | encoder.EncodeInvalidUtf8), - }}, + }}...), }) } diff --git a/backend/qingstor/qingstor.go b/backend/qingstor/qingstor.go index a3d0bd639..9f3a2a016 100644 --- a/backend/qingstor/qingstor.go +++ b/backend/qingstor/qingstor.go @@ -49,11 +49,13 @@ func init() { Help: "Get QingStor credentials from the environment (env vars or IAM).", }}, }, { - Name: "access_key_id", - Help: "QingStor Access Key ID.\n\nLeave blank for anonymous access or runtime credentials.", + Name: "access_key_id", + Help: "QingStor Access Key ID.\n\nLeave blank for anonymous access or runtime credentials.", + Sensitive: true, }, { - Name: "secret_access_key", - Help: "QingStor Secret Access Key (password).\n\nLeave blank for anonymous access or runtime credentials.", + Name: "secret_access_key", + Help: "QingStor Secret Access Key (password).\n\nLeave blank for anonymous access or runtime credentials.", + Sensitive: true, }, { Name: "endpoint", Help: "Enter an endpoint URL to connection QingStor API.\n\nLeave blank will use the default value \"https://qingstor.com:443\".", diff --git a/backend/s3/s3.go b/backend/s3/s3.go index ae7a5f05b..d51702279 100644 --- a/backend/s3/s3.go +++ b/backend/s3/s3.go @@ -182,11 +182,13 @@ func init() { Help: "Get AWS credentials from the environment (env vars or IAM).", }}, }, { - Name: "access_key_id", - Help: "AWS Access Key ID.\n\nLeave blank for anonymous access or runtime credentials.", + Name: "access_key_id", + Help: "AWS Access Key ID.\n\nLeave blank for anonymous access or runtime credentials.", + Sensitive: true, }, { - Name: "secret_access_key", - Help: "AWS Secret Access Key (password).\n\nLeave blank for anonymous access or runtime credentials.", + Name: "secret_access_key", + Help: "AWS Secret Access Key (password).\n\nLeave blank for anonymous access or runtime credentials.", + Sensitive: true, }, { // References: // 1. https://docs.aws.amazon.com/general/latest/gr/rande.html @@ -1818,6 +1820,7 @@ header is added and the default (private) will be used. Value: "arn:aws:kms:us-east-1:*", Help: "arn:aws:kms:*", }}, + Sensitive: true, }, { Name: "sse_customer_key", Help: `To use SSE-C you may provide the secret encryption key used to encrypt/decrypt your data. @@ -1829,6 +1832,7 @@ Alternatively you can provide --sse-customer-key-base64.`, Value: "", Help: "None", }}, + Sensitive: true, }, { Name: "sse_customer_key_base64", Help: `If using SSE-C you must provide the secret encryption key encoded in base64 format to encrypt/decrypt your data. @@ -1840,6 +1844,7 @@ Alternatively you can provide --sse-customer-key.`, Value: "", Help: "None", }}, + Sensitive: true, }, { Name: "sse_customer_key_md5", Help: `If using SSE-C you may provide the secret encryption key MD5 checksum (optional). @@ -1852,6 +1857,7 @@ If you leave it blank, this is calculated automatically from the sse_customer_ke Value: "", Help: "None", }}, + Sensitive: true, }, { Name: "storage_class", Help: "The storage class to use when storing new objects in S3.", @@ -2093,9 +2099,10 @@ If empty it will default to the environment variable "AWS_PROFILE" or `, Advanced: true, }, { - Name: "session_token", - Help: "An AWS session token.", - Advanced: true, + Name: "session_token", + Help: "An AWS session token.", + Advanced: true, + Sensitive: true, }, { Name: "upload_concurrency", Help: `Concurrency for multipart uploads. diff --git a/backend/seafile/seafile.go b/backend/seafile/seafile.go index 58dfd79c2..3fa3e317a 100644 --- a/backend/seafile/seafile.go +++ b/backend/seafile/seafile.go @@ -67,15 +67,18 @@ func init() { Value: "https://cloud.seafile.com/", Help: "Connect to cloud.seafile.com.", }}, + Sensitive: true, }, { - Name: configUser, - Help: "User name (usually email address).", - Required: true, + Name: configUser, + Help: "User name (usually email address).", + Required: true, + Sensitive: true, }, { // Password is not required, it will be left blank for 2FA Name: configPassword, Help: "Password.", IsPassword: true, + Sensitive: true, }, { Name: config2FA, Help: "Two-factor authentication ('true' if the account has 2FA enabled).", @@ -87,6 +90,7 @@ func init() { Name: configLibraryKey, Help: "Library password (for encrypted libraries only).\n\nLeave blank if you pass it through the command line.", IsPassword: true, + Sensitive: true, }, { Name: configCreateLibrary, Help: "Should rclone create a library if it doesn't exist.", @@ -94,9 +98,10 @@ func init() { Default: false, }, { // Keep the authentication token after entering the 2FA code - Name: configAuthToken, - Help: "Authentication token.", - Hide: fs.OptionHideBoth, + Name: configAuthToken, + Help: "Authentication token.", + Hide: fs.OptionHideBoth, + Sensitive: true, }, { Name: config.ConfigEncoding, Help: config.ConfigEncodingHelp, diff --git a/backend/sftp/sftp.go b/backend/sftp/sftp.go index aaec27b60..8a9e0f3c3 100644 --- a/backend/sftp/sftp.go +++ b/backend/sftp/sftp.go @@ -59,13 +59,15 @@ func init() { Description: "SSH/SFTP", NewFs: NewFs, Options: []fs.Option{{ - Name: "host", - Help: "SSH host to connect to.\n\nE.g. \"example.com\".", - Required: true, + Name: "host", + Help: "SSH host to connect to.\n\nE.g. \"example.com\".", + Required: true, + Sensitive: true, }, { - Name: "user", - Help: "SSH username.", - Default: currentUser, + Name: "user", + Help: "SSH username.", + Default: currentUser, + Sensitive: true, }, { Name: "port", Help: "SSH port number.", @@ -75,8 +77,9 @@ func init() { Help: "SSH password, leave blank to use ssh-agent.", IsPassword: true, }, { - Name: "key_pem", - Help: "Raw PEM-encoded private key.\n\nIf specified, will override key_file parameter.", + Name: "key_pem", + Help: "Raw PEM-encoded private key.\n\nIf specified, will override key_file parameter.", + Sensitive: true, }, { Name: "key_file", Help: "Path to PEM-encoded private key file.\n\nLeave blank or set key-use-agent to use ssh-agent." + env.ShellExpandHelp, @@ -87,6 +90,7 @@ func init() { Only PEM encrypted key files (old OpenSSH format) are supported. Encrypted keys in the new OpenSSH format can't be used.`, IsPassword: true, + Sensitive: true, }, { Name: "pubkey_file", Help: `Optional path to public key file. diff --git a/backend/sharefile/sharefile.go b/backend/sharefile/sharefile.go index f7cf4c87a..92e618010 100644 --- a/backend/sharefile/sharefile.go +++ b/backend/sharefile/sharefile.go @@ -155,7 +155,7 @@ func init() { CheckAuth: checkAuth, }) }, - Options: []fs.Option{{ + Options: append(oauthutil.SharedOptions, []fs.Option{{ Name: "upload_cutoff", Help: "Cutoff for switching to multipart upload.", Default: defaultUploadCutoff, @@ -182,6 +182,7 @@ standard values here or any folder ID (long hex number ID).`, Value: "top", Help: "Access the home, favorites, and shared folders as well as the connectors.", }}, + Sensitive: true, }, { Name: "chunk_size", Default: defaultChunkSize, @@ -216,7 +217,7 @@ be set manually to something like: https://XXX.sharefile.com encoder.EncodeLeftSpace | encoder.EncodeLeftPeriod | encoder.EncodeInvalidUtf8), - }}, + }}...), }) } diff --git a/backend/sia/sia.go b/backend/sia/sia.go index b86faae61..5d6c92f2d 100644 --- a/backend/sia/sia.go +++ b/backend/sia/sia.go @@ -45,7 +45,8 @@ func init() { Note that siad must run with --disable-api-security to open API port for other hosts (not recommended). Keep default if Sia daemon runs on localhost.`, - Default: "http://127.0.0.1:9980", + Default: "http://127.0.0.1:9980", + Sensitive: true, }, { Name: "api_password", Help: `Sia Daemon API Password. diff --git a/backend/smb/smb.go b/backend/smb/smb.go index e3fa0e666..b4e953354 100644 --- a/backend/smb/smb.go +++ b/backend/smb/smb.go @@ -41,13 +41,15 @@ func init() { NewFs: NewFs, Options: []fs.Option{{ - Name: "host", - Help: "SMB server hostname to connect to.\n\nE.g. \"example.com\".", - Required: true, + Name: "host", + Help: "SMB server hostname to connect to.\n\nE.g. \"example.com\".", + Required: true, + Sensitive: true, }, { - Name: "user", - Help: "SMB username.", - Default: currentUser, + Name: "user", + Help: "SMB username.", + Default: currentUser, + Sensitive: true, }, { Name: "port", Help: "SMB port number.", @@ -57,9 +59,10 @@ func init() { Help: "SMB password.", IsPassword: true, }, { - Name: "domain", - Help: "Domain name for NTLM authentication.", - Default: "WORKGROUP", + Name: "domain", + Help: "Domain name for NTLM authentication.", + Default: "WORKGROUP", + Sensitive: true, }, { Name: "spn", Help: `Service principal name. @@ -71,6 +74,7 @@ authentication, and it often needs to be set for clusters. For example: Leave blank if not sure. `, + Sensitive: true, }, { Name: "idle_timeout", Default: fs.Duration(60 * time.Second), diff --git a/backend/storj/fs.go b/backend/storj/fs.go index 7f7d4d4a6..1200c40d6 100644 --- a/backend/storj/fs.go +++ b/backend/storj/fs.go @@ -98,9 +98,10 @@ func init() { }, }}, { - Name: "access_grant", - Help: "Access grant.", - Provider: "existing", + Name: "access_grant", + Help: "Access grant.", + Provider: "existing", + Sensitive: true, }, { Name: "satellite_address", @@ -120,14 +121,16 @@ func init() { }, }, { - Name: "api_key", - Help: "API key.", - Provider: newProvider, + Name: "api_key", + Help: "API key.", + Provider: newProvider, + Sensitive: true, }, { - Name: "passphrase", - Help: "Encryption passphrase.\n\nTo access existing objects enter passphrase used for uploading.", - Provider: newProvider, + Name: "passphrase", + Help: "Encryption passphrase.\n\nTo access existing objects enter passphrase used for uploading.", + Provider: newProvider, + Sensitive: true, }, }, }) diff --git a/backend/sugarsync/sugarsync.go b/backend/sugarsync/sugarsync.go index 1676c0949..da5143643 100644 --- a/backend/sugarsync/sugarsync.go +++ b/backend/sugarsync/sugarsync.go @@ -132,42 +132,50 @@ func init() { } return nil, fmt.Errorf("unknown state %q", config.State) }, Options: []fs.Option{{ - Name: "app_id", - Help: "Sugarsync App ID.\n\nLeave blank to use rclone's.", + Name: "app_id", + Help: "Sugarsync App ID.\n\nLeave blank to use rclone's.", + Sensitive: true, }, { - Name: "access_key_id", - Help: "Sugarsync Access Key ID.\n\nLeave blank to use rclone's.", + Name: "access_key_id", + Help: "Sugarsync Access Key ID.\n\nLeave blank to use rclone's.", + Sensitive: true, }, { - Name: "private_access_key", - Help: "Sugarsync Private Access Key.\n\nLeave blank to use rclone's.", + Name: "private_access_key", + Help: "Sugarsync Private Access Key.\n\nLeave blank to use rclone's.", + Sensitive: true, }, { Name: "hard_delete", Help: "Permanently delete files if true\notherwise put them in the deleted files.", Default: false, }, { - Name: "refresh_token", - Help: "Sugarsync refresh token.\n\nLeave blank normally, will be auto configured by rclone.", - Advanced: true, + Name: "refresh_token", + Help: "Sugarsync refresh token.\n\nLeave blank normally, will be auto configured by rclone.", + Advanced: true, + Sensitive: true, }, { - Name: "authorization", - Help: "Sugarsync authorization.\n\nLeave blank normally, will be auto configured by rclone.", - Advanced: true, + Name: "authorization", + Help: "Sugarsync authorization.\n\nLeave blank normally, will be auto configured by rclone.", + Advanced: true, + Sensitive: true, }, { Name: "authorization_expiry", Help: "Sugarsync authorization expiry.\n\nLeave blank normally, will be auto configured by rclone.", Advanced: true, }, { - Name: "user", - Help: "Sugarsync user.\n\nLeave blank normally, will be auto configured by rclone.", - Advanced: true, + Name: "user", + Help: "Sugarsync user.\n\nLeave blank normally, will be auto configured by rclone.", + Advanced: true, + Sensitive: true, }, { - Name: "root_id", - Help: "Sugarsync root id.\n\nLeave blank normally, will be auto configured by rclone.", - Advanced: true, + Name: "root_id", + Help: "Sugarsync root id.\n\nLeave blank normally, will be auto configured by rclone.", + Advanced: true, + Sensitive: true, }, { - Name: "deleted_id", - Help: "Sugarsync deleted folder id.\n\nLeave blank normally, will be auto configured by rclone.", - Advanced: true, + Name: "deleted_id", + Help: "Sugarsync deleted folder id.\n\nLeave blank normally, will be auto configured by rclone.", + Advanced: true, + Sensitive: true, }, { Name: config.ConfigEncoding, Help: config.ConfigEncodingHelp, diff --git a/backend/swift/swift.go b/backend/swift/swift.go index b02bf7ee5..85ce87f25 100644 --- a/backend/swift/swift.go +++ b/backend/swift/swift.go @@ -116,11 +116,13 @@ func init() { }, }, }, { - Name: "user", - Help: "User name to log in (OS_USERNAME).", + Name: "user", + Help: "User name to log in (OS_USERNAME).", + Sensitive: true, }, { - Name: "key", - Help: "API key or password (OS_PASSWORD).", + Name: "key", + Help: "API key or password (OS_PASSWORD).", + Sensitive: true, }, { Name: "auth", Help: "Authentication URL for server (OS_AUTH_URL).", @@ -147,20 +149,25 @@ func init() { Help: "Blomp Cloud Storage", }}, }, { - Name: "user_id", - Help: "User ID to log in - optional - most swift systems use user and leave this blank (v3 auth) (OS_USER_ID).", + Name: "user_id", + Help: "User ID to log in - optional - most swift systems use user and leave this blank (v3 auth) (OS_USER_ID).", + Sensitive: true, }, { - Name: "domain", - Help: "User domain - optional (v3 auth) (OS_USER_DOMAIN_NAME)", + Name: "domain", + Help: "User domain - optional (v3 auth) (OS_USER_DOMAIN_NAME)", + Sensitive: true, }, { - Name: "tenant", - Help: "Tenant name - optional for v1 auth, this or tenant_id required otherwise (OS_TENANT_NAME or OS_PROJECT_NAME).", + Name: "tenant", + Help: "Tenant name - optional for v1 auth, this or tenant_id required otherwise (OS_TENANT_NAME or OS_PROJECT_NAME).", + Sensitive: true, }, { - Name: "tenant_id", - Help: "Tenant ID - optional for v1 auth, this or tenant required otherwise (OS_TENANT_ID).", + Name: "tenant_id", + Help: "Tenant ID - optional for v1 auth, this or tenant required otherwise (OS_TENANT_ID).", + Sensitive: true, }, { - Name: "tenant_domain", - Help: "Tenant domain - optional (v3 auth) (OS_PROJECT_DOMAIN_NAME).", + Name: "tenant_domain", + Help: "Tenant domain - optional (v3 auth) (OS_PROJECT_DOMAIN_NAME).", + Sensitive: true, }, { Name: "region", Help: "Region name - optional (OS_REGION_NAME).", @@ -168,17 +175,21 @@ func init() { Name: "storage_url", Help: "Storage URL - optional (OS_STORAGE_URL).", }, { - Name: "auth_token", - Help: "Auth Token from alternate authentication - optional (OS_AUTH_TOKEN).", + Name: "auth_token", + Help: "Auth Token from alternate authentication - optional (OS_AUTH_TOKEN).", + Sensitive: true, }, { - Name: "application_credential_id", - Help: "Application Credential ID (OS_APPLICATION_CREDENTIAL_ID).", + Name: "application_credential_id", + Help: "Application Credential ID (OS_APPLICATION_CREDENTIAL_ID).", + Sensitive: true, }, { - Name: "application_credential_name", - Help: "Application Credential Name (OS_APPLICATION_CREDENTIAL_NAME).", + Name: "application_credential_name", + Help: "Application Credential Name (OS_APPLICATION_CREDENTIAL_NAME).", + Sensitive: true, }, { - Name: "application_credential_secret", - Help: "Application Credential Secret (OS_APPLICATION_CREDENTIAL_SECRET).", + Name: "application_credential_secret", + Help: "Application Credential Secret (OS_APPLICATION_CREDENTIAL_SECRET).", + Sensitive: true, }, { Name: "auth_version", Help: "AuthVersion - optional - set to (1,2,3) if your auth URL has no version (ST_AUTH_VERSION).", diff --git a/backend/uptobox/uptobox.go b/backend/uptobox/uptobox.go index 29f83187d..1db823ef4 100644 --- a/backend/uptobox/uptobox.go +++ b/backend/uptobox/uptobox.go @@ -43,8 +43,9 @@ func init() { Description: "Uptobox", NewFs: NewFs, Options: []fs.Option{{ - Help: "Your access token.\n\nGet it from https://uptobox.com/my_account.", - Name: "access_token", + Help: "Your access token.\n\nGet it from https://uptobox.com/my_account.", + Name: "access_token", + Sensitive: true, }, { Help: "Set to make uploaded files private", Name: "private", diff --git a/backend/webdav/webdav.go b/backend/webdav/webdav.go index ed562bb98..801e8d970 100644 --- a/backend/webdav/webdav.go +++ b/backend/webdav/webdav.go @@ -96,15 +96,17 @@ func init() { Help: "Other site/service or software", }}, }, { - Name: "user", - Help: "User name.\n\nIn case NTLM authentication is used, the username should be in the format 'Domain\\User'.", + Name: "user", + Help: "User name.\n\nIn case NTLM authentication is used, the username should be in the format 'Domain\\User'.", + Sensitive: true, }, { Name: "pass", Help: "Password.", IsPassword: true, }, { - Name: "bearer_token", - Help: "Bearer token instead of user/pass (e.g. a Macaroon).", + Name: "bearer_token", + Help: "Bearer token instead of user/pass (e.g. a Macaroon).", + Sensitive: true, }, { Name: "bearer_token_command", Help: "Command to run to get a bearer token.", diff --git a/cmd/config/config.go b/cmd/config/config.go index e3b916aad..fe5f4d939 100644 --- a/cmd/config/config.go +++ b/cmd/config/config.go @@ -26,6 +26,7 @@ func init() { configCommand.AddCommand(configTouchCommand) configCommand.AddCommand(configPathsCommand) configCommand.AddCommand(configShowCommand) + configCommand.AddCommand(configRedactedCommand) configCommand.AddCommand(configDumpCommand) configCommand.AddCommand(configProvidersCommand) configCommand.AddCommand(configCreateCommand) @@ -118,6 +119,35 @@ var configShowCommand = &cobra.Command{ }, } +var configRedactedCommand = &cobra.Command{ + Use: "redacted []", + Short: `Print redacted (decrypted) config file, or the redacted config for a single remote.`, + Long: `This prints a redacted copy of the config file, either the +whole config file or for a given remote. + +The config file will be redacted by replacing all passwords and other +sensitive info with XXX. + +This makes the config file suitable for posting online for support. + +It should be double checked before posting as the redaction may not be perfect. + +`, + Annotations: map[string]string{ + "versionIntroduced": "v1.64", + }, + Run: func(command *cobra.Command, args []string) { + cmd.CheckArgs(0, 1, command, args) + if len(args) == 0 { + config.ShowRedactedConfig() + } else { + name := strings.TrimRight(args[0], ":") + config.ShowRedactedRemote(name) + } + fmt.Println("### Double check the config for sensitive info before posting publicly") + }, +} + var configDumpCommand = &cobra.Command{ Use: "dump", Short: `Dump the config file as JSON.`, diff --git a/fs/config/ui.go b/fs/config/ui.go index 1531884f6..c58fb92e4 100644 --- a/fs/config/ui.go +++ b/fs/config/ui.go @@ -302,19 +302,41 @@ func mustFindByName(name string) *fs.RegInfo { return fs.MustFind(fsType) } +// findByName finds the RegInfo for the remote name passed in or +// returns an error +func findByName(name string) (*fs.RegInfo, error) { + fsType := FileGet(name, "type") + if fsType == "" { + return nil, fmt.Errorf("couldn't find type of fs for %q", name) + } + return fs.Find(fsType) +} + // printRemoteOptions prints the options of the remote -func printRemoteOptions(name string, prefix string, sep string) { - fs := mustFindByName(name) +func printRemoteOptions(name string, prefix string, sep string, redacted bool) { + fsInfo, err := findByName(name) + if err != nil { + fmt.Printf("# %v\n", err) + fsInfo = nil + } for _, key := range LoadedData().GetKeyList(name) { isPassword := false - for _, option := range fs.Options { - if option.Name == key && option.IsPassword { - isPassword = true - break + isSensitive := false + if fsInfo != nil { + for _, option := range fsInfo.Options { + if option.Name == key { + if option.IsPassword { + isPassword = true + } else if option.Sensitive { + isSensitive = true + } + } } } value := FileGet(name, key) - if isPassword && value != "" { + if redacted && (isSensitive || isPassword) && value != "" { + fmt.Printf("%s%s%sXXX\n", prefix, key, sep) + } else if isPassword && value != "" { fmt.Printf("%s%s%s*** ENCRYPTED ***\n", prefix, key, sep) } else { fmt.Printf("%s%s%s%s\n", prefix, key, sep, value) @@ -324,13 +346,19 @@ func printRemoteOptions(name string, prefix string, sep string) { // listRemoteOptions lists the options of the remote func listRemoteOptions(name string) { - printRemoteOptions(name, "- ", ": ") + printRemoteOptions(name, "- ", ": ", false) } // ShowRemote shows the contents of the remote in config file format func ShowRemote(name string) { fmt.Printf("[%s]\n", name) - printRemoteOptions(name, "", " = ") + printRemoteOptions(name, "", " = ", false) +} + +// ShowRedactedRemote shows the contents of the remote in config file format +func ShowRedactedRemote(name string) { + fmt.Printf("[%s]\n", name) + printRemoteOptions(name, "", " = ", true) } // OkRemote prints the contents of the remote and ask if it is OK @@ -634,6 +662,22 @@ func ShowConfig() { fmt.Printf("%s", str) } +// ShowRedactedConfig prints the redacted (unencrypted) config options +func ShowRedactedConfig() { + remotes := LoadedData().GetSectionList() + if len(remotes) == 0 { + fmt.Println("; empty config") + return + } + sort.Strings(remotes) + for i, remote := range remotes { + if i != 0 { + fmt.Println() + } + ShowRedactedRemote(remote) + } +} + // EditConfig edits the config file interactively func EditConfig(ctx context.Context) (err error) { for { diff --git a/fs/fs_test.go b/fs/fs_test.go index 4e316b9b5..862ab34c4 100644 --- a/fs/fs_test.go +++ b/fs/fs_test.go @@ -243,6 +243,7 @@ func TestOptionMarshalJSON(t *testing.T) { "NoPrefix": false, "Advanced": true, "Exclusive": false, +"Sensitive": false, "DefaultStr": "false", "ValueStr": "true", "Type": "bool" diff --git a/fs/registry.go b/fs/registry.go index adf891ad2..622cf8e87 100644 --- a/fs/registry.go +++ b/fs/registry.go @@ -154,6 +154,7 @@ type Option struct { NoPrefix bool // set if the option for this should not use the backend prefix Advanced bool // set if this is an advanced config option Exclusive bool // set if the answer can only be one of the examples (empty string allowed unless Required or Default is set) + Sensitive bool // set if this option should be redacted when using rclone config redacted } // BaseOption is an alias for Option used internally diff --git a/lib/oauthutil/oauthutil.go b/lib/oauthutil/oauthutil.go index 470270795..d3562e41a 100644 --- a/lib/oauthutil/oauthutil.go +++ b/lib/oauthutil/oauthutil.go @@ -82,15 +82,18 @@ All done. Please go back to rclone. // SharedOptions are shared between backends the utilize an OAuth flow var SharedOptions = []fs.Option{{ - Name: config.ConfigClientID, - Help: "OAuth Client Id.\n\nLeave blank normally.", + Name: config.ConfigClientID, + Help: "OAuth Client Id.\n\nLeave blank normally.", + Sensitive: true, }, { - Name: config.ConfigClientSecret, - Help: "OAuth Client Secret.\n\nLeave blank normally.", + Name: config.ConfigClientSecret, + Help: "OAuth Client Secret.\n\nLeave blank normally.", + Sensitive: true, }, { - Name: config.ConfigToken, - Help: "OAuth Access Token as a JSON blob.", - Advanced: true, + Name: config.ConfigToken, + Help: "OAuth Access Token as a JSON blob.", + Advanced: true, + Sensitive: true, }, { Name: config.ConfigAuthURL, Help: "Auth server URL.\n\nLeave blank to use the provider defaults.",