Skip to content

Commit

Permalink
QgsMapLayer::publicSource(): make it redact/remove GDAL credentials
Browse files Browse the repository at this point in the history
Fixes #60292
  • Loading branch information
rouault committed Jan 31, 2025
1 parent f999386 commit d787926
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 11 deletions.
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"

0 comments on commit d787926

Please sign in to comment.