How to use secrets manager?

I’ve recently returned to Sailfish OS and am trying to get back to development. Currently I’m trying to start using secrets manager but I can’t seem to get it working at all.

From what I found I need to add sailfishsecrets to PKGCONFIG but when I do that, I get this error:

Project ERROR: sailfishsecrets development package not found

Any help to get it working? Thanks.

Well, the error message states that you don’t have the sailfishsecrets development package installed in your target.

What’s missing is BuildRequires: pkgconfig(sailfishsecrets) in your .spec file. Or, if you prefer yaml, - sailfishsecrets in the PkgConfigBR section of the .yaml file.

1 Like

Thanks, that worked! Now I get this error when deploying to emulator:

Unable to connect to secrets daemon: QDBusError("org.freedesktop.DBus.Error.FileNotFound", "Failed to connect to socket /run/user/100000/sailfishsecretsd/p2pSocket: No such file or directory") 1 "org.freedesktop.DBus.Error.FileNotFound"

Any idea how to run the daemon on the emulator?

The same way you run it on a device :wink:

You should have Requires: sailfishsecretsdaemon on your spec file. That way, when you deploy your app on the emulator, it will pull the daemon in with it. If I remember correctly, there’s still the issue that the daemon doesn’t start immediately after installing it, so you might need to restart the emulator after installation.

Thanks again! Is there any place where I can find documentation for this? I can’t find anything regarding this topic.

I’m afraid there isn’t. Someone should write that documentation. We do have Secrets and Crypto | Sailfish OS Documentation though, so it’s just one PR away. Another possibility would be adding it to the API documentation, which is currently only published as part of the SDK.

It seems to not want to work with me… Now I get this error:

No such encrypted storage plugin exists: org.sailfishos.secrets.plugin.encryptedstorage.sqlcipher

Is it just because of the emulator? I used Sailfish::Secrets::SecretManager::DefaultEncryptedStoragePluginName not the name directly.

Try adding Requires: sailfishsecretsdaemon-secretsplugins-default in the spec.

We really shoud write the documentation for this stuff :frowning:

Sadly the same error :confused:

@vige Do you have any other ideas what could help?

Not really. It would help if you could share the source code of your project so I could try it myself.

Bumping this because I’m also trying to get a simple secure storage for a password in pure QML, and am trying to navigate the maze that are the Secrets QML types.

Anyway, on my system, libsailfishsecrets-sqlcipher.so is in sailfishsecretsdaemon-secretsplugin-common, not sailfishsecretsdaemon-secretsplugins-default. (Note the plugin vs plugins naming difference.)

It is installed, but still, the error given above is output when running the following example code:

import QtQuick 2.6
import Sailfish.Silica 1.0
import Sailfish.Crypto 1.0 as Crypto
import Sailfish.Secrets 1.0 as Secrets

ApplicationWindow { initialPage: Component { Page { id: page
    SilicaFlickable {
        anchors.fill: parent
        contentHeight: col.height
        Column { id: col
            anchors.centerIn: parent
            width: parent.width
            ButtonLayout{
                anchors.horizontalCenter: parent.horizontalCenter
                Button { text: qsTr("create Collection") ; onClicked: secrets.setupCollection() }
            }
        }
    }}}

    Item { id: secrets
        visible: false

        readonly property string collectionName: Qt.application.name

        function setupCollection() {
            ccr.startRequest()
        }

        Secrets.SecretManager { id: manager }

        Secrets.CreateCollectionRequest { id: ccr
            manager: manager
            collectionName: secrets.collectionName
            storagePluginName: manager.defaultEncryptedStoragePluginName
            encryptionPluginName: manager.defaultEncryptionPluginName
            onResultChanged: {
                if (result.code == Crypto.Result.Failed) {
                    console.log("CCR: error: " + result.errorMessage)
                } else if (result.code == Crypto.Result.Succeeded) {
                    console.log("CCR: succeeded")
                }
            }
        }
    }
}

Output below. Packaging it in a “full” app with .desktop file and everything and running via sailfish-qml or invoker sailfish-qmlgives the same error.

nemo@PGXperiiia10:~/tmp $ qmlscene testccr.qml
11:59:36.135 unknown:0 unknown Using Wayland-EGL
library "libGLESv2_adreno.so" not found
library "eglSubDriverAndroid.so" not found
library "vendor.qti.qspmhal@1.0.so" not found
11:59:38.426 qml: file:///home/nemo/tmp/testccr.qml:38 onResultChanged CCR: error: No such storage plugin exists: org.sailfishos.secrets.plugin.encryptedstorage.sqlcipher
nemo@PGXperiiia10:~/tmp $ secrets-tool --list-plugins
Authentication plugins:
         "org.sailfishos.secrets.plugin.authentication.inapp"
         "org.sailfishos.secrets.plugin.authentication.passwordagent"
Encryption plugins:
         "org.sailfishos.secrets.plugin.encryption.openssl"
Storage plugins:
         "org.sailfishos.secrets.plugin.storage.sqlite"
Encrypted storage plugins:
         "org.sailfishos.crypto.plugin.gnupg.openpgp"
         "org.sailfishos.crypto.plugin.gnupg.smime"
         "org.sailfishos.secrets.plugin.encryptedstorage.sqlcipher"
Crypto storage plugins:
         "org.sailfishos.crypto.plugin.gnupg.openpgp"
         "org.sailfishos.crypto.plugin.gnupg.smime"
         "org.sailfishos.secrets.plugin.encryptedstorage.sqlcipher"
Crypto plugins:
         "org.sailfishos.crypto.plugin.crypto.openssl"

Aha!

From createcollectionrequest.cpp#L55

So we set them to be the same, which makes the error go away and the Collection gets created successfully…

Secrets.CreateCollectionRequest { id: ccr
             [...]
             storagePluginName:    manager.defaultEncryptedStoragePluginName
             //encryptionPluginName: manager.defaultEncryptionPluginName
             encryptionPluginName: storagePluginName
             [...]
}
3 Likes

Question. That is then a ‘device lock’ block level protected collection? Does that mean that with device unlock more than one app can access the collection, or are you doing this with an additional secret?

I don’t know, but now I have everything working (collection create, collection delete, secret save (but NOT secret update), secret load), when trying to delete a collection I get:

Request error: Collection QtQmlViewer is locked and requires device lock authentication

which I don’t know how to solve.

I think you’ve answered my question! Looks like you have to force device lock auth. I’m not sure how it’s done, but, it’s sure to be present in those area of the Settings app like Developer where you’re prompted with the device lock?

Well there’s the Secrets.LockCodeRequest type which looks like it’s for querying and changing lock status.

I believe (but it’s only guesswork ATM) that access by others i managed managed by the SecretManager.accessControlMode -> enum AccessControlMode which has OwnerOnlyMode, SystemAccessControlMode, and NoAccessControlMode, although I understand other applications can not access foreign collections by design. See secretmanager.h#L48

What I find is that ‘owning application’ is determined with great bias, as a secret created by e.g.

qmlscene /path/to/qml/myapp.qml

can not be accessed/modified/deleted by

qmlscene -some_commandline_parameter /path/to/qml/myapp.qml

where myapp.qml is exactly the same.

1 Like

Ok, that’s reassuring. The use case I’m looking at (tooter mastodon api keys) I’m not sure if it makes more sense just to store encrypted values. I believe you now have an encrypted store/collection with ‘plain values’?

You mean that addition of the parameter alone leads to a denial? Hmmmm. That might make sense if qmlscene could ‘leak’ secrets depending on how it’s called?

I would appear so. I suspect owning_app_id = sha1sum(app.argc + " " + app.argv[]) or something like that.

1 Like