Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QgsMapLayer::publicSource(): make it redact/remove GDAL credentials #60384

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion python/PyQt6/core/auto_generated/qgsmaplayer.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -567,13 +567,14 @@ or other problem. Child classes set this flag when initialized.
:return: ``True`` if the layer is valid and can be accessed
%End


QString publicSource( bool hidePassword = false ) const;
%Docstring
Gets a version of the internal layer definition that has sensitive
bits removed (for example, the password). This function should
be used when displaying the source name for general viewing.

:param hidePassword: False, if the password should be removed or replaced by an arbitrary string, since QGIS 3.34
:param hidePassword: ``True`` to replace the value of credentials with 'xxxxxxxx', ``False`` to completely remove credentials (key and value). Since QGIS 3.34

.. seealso:: :py:func:`source`
%End
Expand Down
3 changes: 2 additions & 1 deletion python/core/auto_generated/qgsmaplayer.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -567,13 +567,14 @@ or other problem. Child classes set this flag when initialized.
:return: ``True`` if the layer is valid and can be accessed
%End


QString publicSource( bool hidePassword = false ) const;
%Docstring
Gets a version of the internal layer definition that has sensitive
bits removed (for example, the password). This function should
be used when displaying the source name for general viewing.

:param hidePassword: False, if the password should be removed or replaced by an arbitrary string, since QGIS 3.34
:param hidePassword: ``True`` to replace the value of credentials with 'xxxxxxxx', ``False`` to completely remove credentials (key and value). Since QGIS 3.34

.. seealso:: :py:func:`source`
%End
Expand Down
36 changes: 31 additions & 5 deletions src/core/qgsmaplayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -473,13 +473,37 @@ QString QgsMapLayer::metadataUrlFormat() const
}
}

QString QgsMapLayer::publicSource( bool hidePassword ) const
QString QgsMapLayer::publicSource( bool redactCredentials ) const
{
QGIS_PROTECT_QOBJECT_THREAD_ACCESS

QString safeName = mDataSource;

if ( providerType() == QLatin1String( "gdal" ) )
{
QVariantMap components = QgsProviderRegistry::instance()->decodeUri( providerType(), safeName );
QVariantMap credentialOptions = components.value( QStringLiteral( "credentialOptions" ) ).toMap();
if ( !credentialOptions.empty() )
{
if ( redactCredentials )
{
for ( auto it = credentialOptions.begin(); it != credentialOptions.end(); ++it )
{
it.value() = QStringLiteral( "XXXXXXXX" );
}
components.insert( QStringLiteral( "credentialOptions" ), credentialOptions );
}
else
{
components.remove( QStringLiteral( "credentialOptions" ) );
}
}
safeName = QgsProviderRegistry::instance()->encodeUri( providerType(), components );
}

// Redo this every time we're asked for it, as we don't know if
// dataSource has changed.
QString safeName = QgsDataSourceUri::removePassword( mDataSource, hidePassword );
safeName = QgsDataSourceUri::removePassword( safeName, redactCredentials );
return safeName;
}

Expand Down Expand Up @@ -3232,12 +3256,14 @@ QString QgsMapLayer::generalHtmlMetadata() const
// name
metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Name" ) + QStringLiteral( "</td><td>" ) + name() + QStringLiteral( "</td></tr>\n" );

const QString lPublicSource = publicSource();

QString path;
bool isLocalPath = false;
if ( dataProvider() )
{
// local path
QVariantMap uriComponents = QgsProviderRegistry::instance()->decodeUri( dataProvider()->name(), publicSource() );
QVariantMap uriComponents = QgsProviderRegistry::instance()->decodeUri( dataProvider()->name(), lPublicSource );
if ( uriComponents.contains( QStringLiteral( "path" ) ) )
{
path = uriComponents[QStringLiteral( "path" )].toString();
Expand Down Expand Up @@ -3283,8 +3309,8 @@ QString QgsMapLayer::generalHtmlMetadata() const
}

// data source
if ( publicSource() != path || !isLocalPath )
metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Source" ) + QStringLiteral( "</td><td>%1" ).arg( publicSource() != path ? publicSource() : path ) + QStringLiteral( "</td></tr>\n" );
if ( lPublicSource != path || !isLocalPath )
metadata += QStringLiteral( "<tr><td class=\"highlight\">" ) + tr( "Source" ) + QStringLiteral( "</td><td>%1" ).arg( lPublicSource != path ? lPublicSource : path ) + QStringLiteral( "</td></tr>\n" );

// provider
if ( dataProvider() )
Expand Down
11 changes: 7 additions & 4 deletions src/core/qgsmaplayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -573,12 +573,15 @@ class CORE_EXPORT QgsMapLayer : public QObject
*/
bool isValid() const;

// TODO QGIS 4.0: consider changing bool hidePassword to an enumeration: HIDE_CREDENTIALS / REDACT_CREDENTIALS
// to avoid the ambiguity of the double negation (hide = false)

/**
* Gets a version of the internal layer definition that has sensitive
* bits removed (for example, the password). This function should
* be used when displaying the source name for general viewing.
* \param hidePassword False, if the password should be removed or replaced by an arbitrary string, since QGIS 3.34
* \see source()
* bits removed (for example, the password). This function should
* be used when displaying the source name for general viewing.
* \param hidePassword TRUE to replace the value of credentials with 'xxxxxxxx', FALSE to completely remove credentials (key and value). Since QGIS 3.34
* \see source()
*/
QString publicSource( bool hidePassword = false ) const;

Expand Down
13 changes: 13 additions & 0 deletions tests/src/core/testqgsmaplayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

//qgis includes...
#include <qgsmaplayer.h>
#include <qgsrasterlayer.h>
#include <qgsvectorlayer.h>
#include <qgsapplication.h>
#include <qgsproviderregistry.h>
Expand Down Expand Up @@ -73,6 +74,8 @@ class TestQgsMapLayer : public QObject

void readCustomProperties();

void publicSourceOnGdalWithCredentials();

private:
QgsVectorLayer *mpLayer = nullptr;
};
Expand Down Expand Up @@ -510,5 +513,15 @@ void TestQgsMapLayer::readCustomProperties()
QCOMPARE( spy.at( 1 ).at( 0 ), "my_property_two" );
}

void TestQgsMapLayer::publicSourceOnGdalWithCredentials()
{
QgsRasterLayer rl(
QStringLiteral( "test.tif|option:AN=OPTION|credential:SOMEKEY=AAAAA|credential:ANOTHER=BBB" ), QString(), QStringLiteral( "gdal" )
);
QCOMPARE( rl.publicSource( true ), QStringLiteral( "test.tif|option:AN=OPTION|credential:ANOTHER=XXXXXXXX|credential:SOMEKEY=XXXXXXXX" ) );
QCOMPARE( rl.publicSource( false ), QStringLiteral( "test.tif|option:AN=OPTION" ) );
QCOMPARE( rl.publicSource(), QStringLiteral( "test.tif|option:AN=OPTION" ) );
}

QGSTEST_MAIN( TestQgsMapLayer )
#include "testqgsmaplayer.moc"
Loading