From d0d41fe84745fabae98a99aa7806ce1d045305cd Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Thu, 6 Jul 2023 17:55:53 +0100 Subject: [PATCH] rclone config redacted: implement support mechanism for showing redacted config This introduces a new fs.Option flag, Sensitive and uses this along with IsPassword to redact the info in the config file for support purposes. It adds this flag into backends where appropriate. It was necessary to add oauthutil.SharedOptions to some backends as they were missing them. Fixes #5209 --- backend/azureblob/azureblob.go | 30 ++++++--- backend/b2/b2.go | 14 +++-- backend/box/box.go | 14 +++-- backend/cache/cache.go | 14 +++-- backend/drive/drive.go | 33 +++++----- backend/dropbox/dropbox.go | 5 +- backend/fichier/fichier.go | 5 +- backend/filefabric/filefabric.go | 5 +- backend/ftp/ftp.go | 14 +++-- .../googlecloudstorage/googlecloudstorage.go | 17 ++--- backend/hdfs/hdfs.go | 11 ++-- backend/internetarchive/internetarchive.go | 10 +-- backend/jottacloud/jottacloud.go | 4 +- backend/koofr/koofr.go | 7 ++- backend/mailru/mailru.go | 11 ++-- backend/mega/mega.go | 7 ++- backend/netstorage/netstorage.go | 10 +-- backend/onedrive/onedrive.go | 15 +++-- backend/opendrive/opendrive.go | 7 ++- backend/oracleobjectstorage/options.go | 16 ++--- backend/pcloud/pcloud.go | 12 ++-- backend/pikpak/pikpak.go | 10 +-- backend/premiumizeme/premiumizeme.go | 9 +-- backend/putio/putio.go | 4 +- backend/qingstor/qingstor.go | 10 +-- backend/s3/s3.go | 21 ++++--- backend/seafile/seafile.go | 17 +++-- backend/sftp/sftp.go | 20 +++--- backend/sharefile/sharefile.go | 5 +- backend/sia/sia.go | 3 +- backend/smb/smb.go | 22 ++++--- backend/storj/fs.go | 21 ++++--- backend/sugarsync/sugarsync.go | 50 ++++++++------- backend/swift/swift.go | 55 +++++++++------- backend/uptobox/uptobox.go | 5 +- backend/webdav/webdav.go | 10 +-- cmd/config/config.go | 30 +++++++++ fs/config/ui.go | 62 ++++++++++++++++--- fs/fs_test.go | 1 + fs/registry.go | 1 + lib/oauthutil/oauthutil.go | 17 ++--- 41 files changed, 407 insertions(+), 227 deletions(-) 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.",