You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by ma...@apache.org on 2021/04/22 20:08:44 UTC

[netbeans] branch master updated: NETBEANS-4150 added a KeyringProvider using libsecret for new versions of Gnome

This is an automated email from the ASF dual-hosted git repository.

matthiasblaesing pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new 887a663  NETBEANS-4150 added a KeyringProvider using libsecret for new versions of Gnome
     new 3b964b0  Merge pull request #2906 from premek/NETBEANS-4150-libsecret-keyring-provider
887a663 is described below

commit 887a66372051aca686d8bf6b5e124807f5b59d2d
Author: Premysl Vyhnal <pr...@gmail.com>
AuthorDate: Sun Apr 18 23:25:00 2021 +0200

    NETBEANS-4150 added a KeyringProvider using libsecret for new versions of Gnome
---
 .../modules/keyring/gnome/libsecret/Gio.java       |  35 ++++
 .../modules/keyring/gnome/libsecret/Glib.java      |  39 +++++
 .../gnome/libsecret/GnomeLibSecretProvider.java    | 178 +++++++++++++++++++++
 .../modules/keyring/gnome/libsecret/LibSecret.java |  72 +++++++++
 .../libsecret/GnomeLibSecretProviderTest.java      |  35 ++++
 5 files changed, 359 insertions(+)

diff --git a/platform/keyring.impl/src/org/netbeans/modules/keyring/gnome/libsecret/Gio.java b/platform/keyring.impl/src/org/netbeans/modules/keyring/gnome/libsecret/Gio.java
new file mode 100644
index 0000000..f76708c
--- /dev/null
+++ b/platform/keyring.impl/src/org/netbeans/modules/keyring/gnome/libsecret/Gio.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.keyring.gnome.libsecret;
+
+import com.sun.jna.Library;
+import com.sun.jna.Native;
+
+public interface Gio extends Library {
+
+    Gio INSTANCE = Native.load("gio-2.0", Gio.class);
+
+    class GCancelable {
+
+        public GCancelable() {
+            throw new RuntimeException("CANCELING NOT IMPLEMENTED!");
+        }
+
+    }
+}
diff --git a/platform/keyring.impl/src/org/netbeans/modules/keyring/gnome/libsecret/Glib.java b/platform/keyring.impl/src/org/netbeans/modules/keyring/gnome/libsecret/Glib.java
new file mode 100644
index 0000000..7ad406c
--- /dev/null
+++ b/platform/keyring.impl/src/org/netbeans/modules/keyring/gnome/libsecret/Glib.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.keyring.gnome.libsecret;
+
+import com.sun.jna.Library;
+import com.sun.jna.Native;
+import com.sun.jna.Pointer;
+import com.sun.jna.Structure;
+
+public interface Glib extends Library {
+
+    Glib INSTANCE = Native.load("glib-2.0", Glib.class);
+
+    public void g_error_free(Pointer gerror);
+
+    @Structure.FieldOrder({"domain", "code", "message"})
+    class GError extends Structure {
+
+        public int domain;
+        public int code;
+        public String message;
+    }
+}
diff --git a/platform/keyring.impl/src/org/netbeans/modules/keyring/gnome/libsecret/GnomeLibSecretProvider.java b/platform/keyring.impl/src/org/netbeans/modules/keyring/gnome/libsecret/GnomeLibSecretProvider.java
new file mode 100644
index 0000000..540c0eb
--- /dev/null
+++ b/platform/keyring.impl/src/org/netbeans/modules/keyring/gnome/libsecret/GnomeLibSecretProvider.java
@@ -0,0 +1,178 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.keyring.gnome.libsecret;
+
+import com.sun.jna.Native;
+import com.sun.jna.Pointer;
+import com.sun.jna.Structure;
+import com.sun.jna.ptr.PointerByReference;
+import java.io.ByteArrayOutputStream;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.text.MessageFormat;
+import java.util.MissingResourceException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.netbeans.modules.keyring.gnome.libsecret.Glib.GError;
+import org.netbeans.modules.keyring.gnome.libsecret.LibSecret.SecretSchema;
+import org.netbeans.modules.keyring.gnome.libsecret.LibSecret.SecretSchemaAttribute;
+import org.netbeans.spi.keyring.KeyringProvider;
+import org.openide.util.NbBundle;
+import org.openide.util.lookup.ServiceProvider;
+
+@ServiceProvider(service = KeyringProvider.class, position = 90)
+public class GnomeLibSecretProvider implements KeyringProvider {
+
+    private static final Logger LOG = Logger.getLogger(GnomeLibSecretProvider.class.getName());
+    private static final String KEY = "key"; // NOI18N
+    private static final Charset CHARSET = Charset.forName(Native.getDefaultStringEncoding());
+
+    private final String appName;
+
+    private SecretSchema secretSchema = null;
+
+    public GnomeLibSecretProvider() {
+        appName = getAppName();
+    }
+
+    private SecretSchema getSchema() {
+        if (secretSchema != null) {
+            return secretSchema;
+        }
+
+        secretSchema = new SecretSchema();
+        secretSchema.name = appName;
+        secretSchema.flags = LibSecret.SECRET_SCHEMA_NONE;
+        secretSchema.attributes[0] = new SecretSchemaAttribute();
+        secretSchema.attributes[0].name = KEY;
+        secretSchema.attributes[0].type = LibSecret.SECRET_SCHEMA_ATTRIBUTE_STRING;
+        return secretSchema;
+    }
+
+    private String getAppName() {
+        try {
+            return MessageFormat.format(
+                    NbBundle.getBundle("org.netbeans.core.windows.view.ui.Bundle").getString("CTL_MainWindow_Title_No_Project"),
+                    "…");
+        } catch (MissingResourceException x) {
+            return "NetBeans"; // NOI18N
+        }
+    }
+
+    @Override
+    public boolean enabled() {
+        if (Boolean.getBoolean("netbeans.keyring.no.native")) {
+            LOG.fine("native keyring integration disabled");
+            return false;
+        }
+
+        try {
+            read("NoNeXiStEnT"); // NOI18N
+            return true;
+        } catch (RuntimeException e) {
+            LOG.log(Level.WARNING, null, e);
+            return false;
+        } catch (UnsatisfiedLinkError e) {
+            LOG.log(Level.FINE, null, e);
+            return false;
+        }
+    }
+
+    @Override
+    public char[] read(String key) {
+        PointerByReference gerrorBuffer = new PointerByReference();
+        SecretSchema schema = getSchema();
+
+        Pointer pointer = LibSecret.INSTANCE.secret_password_lookup_sync(schema, null, gerrorBuffer, KEY, key);
+
+        if (gerrorBuffer.getValue() != null) {
+            processError(gerrorBuffer);
+            return null;
+        }
+
+        if (pointer == null) {
+            return null;
+        }
+
+        return decode(readZeroTerminatedBytes(pointer));
+    }
+
+    @Override
+    public void save(String key, char[] password, String description) {
+        PointerByReference gerrorBuffer = new PointerByReference();
+        SecretSchema schema = getSchema();
+
+        String label = appName + " - " + (description != null ? description : key);
+        LibSecret.INSTANCE.secret_password_store_sync(schema, LibSecret.SECRET_COLLECTION_DEFAULT, label, encode(password), null, gerrorBuffer, KEY, key);
+
+        if (gerrorBuffer.getValue() != null) {
+            processError(gerrorBuffer);
+        }
+    }
+
+    @Override
+    public void delete(String key) {
+        PointerByReference gerrorBuffer = new PointerByReference();
+        SecretSchema schema = getSchema();
+
+        LibSecret.INSTANCE.secret_password_clear_sync(schema, null, gerrorBuffer, KEY, key);
+
+        if (gerrorBuffer.getValue() != null) {
+            processError(gerrorBuffer);
+        }
+    }
+
+    private void processError(PointerByReference gerrorBuffer) throws IllegalArgumentException {
+        try {
+            GError gerror = Structure.newInstance(GError.class, gerrorBuffer.getValue());
+            gerror.read();
+            LOG.warning(String.format("%d/%d: %s", gerror.domain, gerror.code, gerror.message));
+        } finally {
+            Glib.INSTANCE.g_error_free(gerrorBuffer.getValue());
+        }
+    }
+
+    private byte[] encode(char[] password) {
+        ByteBuffer encodedPasswordBuffer = CHARSET.encode(CharBuffer.wrap(password));
+        byte[] encodedPassword = new byte[encodedPasswordBuffer.limit() + 1]; // zero terminated
+        encodedPasswordBuffer.get(encodedPassword, 0, encodedPasswordBuffer.limit());
+        return encodedPassword;
+    }
+
+    private char[] decode(byte[] bytes) {
+        CharBuffer decodedPasswordBuffer = CHARSET.decode(ByteBuffer.wrap(bytes));
+        char[] decodedPassword = new char[decodedPasswordBuffer.limit()];
+        decodedPasswordBuffer.get(decodedPassword, 0, decodedPasswordBuffer.limit());
+        return decodedPassword;
+    }
+
+    private byte[] readZeroTerminatedBytes(Pointer pointer) {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        for (int i = 0; i < 100000; i++) {
+            byte curVal = pointer.getByte(i);
+            if (curVal == 0) {
+                break;
+            }
+            baos.write(curVal);
+        }
+        return baos.toByteArray();
+    }
+
+}
diff --git a/platform/keyring.impl/src/org/netbeans/modules/keyring/gnome/libsecret/LibSecret.java b/platform/keyring.impl/src/org/netbeans/modules/keyring/gnome/libsecret/LibSecret.java
new file mode 100644
index 0000000..9411e49
--- /dev/null
+++ b/platform/keyring.impl/src/org/netbeans/modules/keyring/gnome/libsecret/LibSecret.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.keyring.gnome.libsecret;
+
+import com.sun.jna.Library;
+import com.sun.jna.Native;
+import com.sun.jna.Pointer;
+import com.sun.jna.Structure;
+import com.sun.jna.ptr.PointerByReference;
+import org.netbeans.modules.keyring.gnome.libsecret.Gio.GCancelable;
+
+public interface LibSecret extends Library {
+
+    LibSecret INSTANCE = Native.load("secret-1", LibSecret.class);
+
+    Pointer secret_password_lookup_sync(SecretSchema schema, GCancelable cancellable, PointerByReference gerror, Object... attributes);
+
+    Pointer secret_password_store_sync(SecretSchema schema, String collection, String label, byte[] password, GCancelable cancelable, PointerByReference gerror, Object... attributes);
+
+    Pointer secret_password_clear_sync(SecretSchema schema, GCancelable cancellable, PointerByReference gerror, Object... attributes);
+
+    void secret_password_free(Pointer pointer);
+
+    @Structure.FieldOrder({"name", "flags", "attributes", "reserved", "reserved1", "reserved2", "reserved3", "reserved4", "reserved5", "reserved6", "reserved7"})
+    class SecretSchema extends Structure {
+
+        public String name;
+        public int flags;
+        public SecretSchemaAttribute[] attributes = new SecretSchemaAttribute[32];
+        public int reserved;
+        public Pointer reserved1;
+        public Pointer reserved2;
+        public Pointer reserved3;
+        public Pointer reserved4;
+        public Pointer reserved5;
+        public Pointer reserved6;
+        public Pointer reserved7;
+    }
+
+    @Structure.FieldOrder({"name", "type"})
+    class SecretSchemaAttribute extends Structure {
+
+        public String name;
+        public int type;
+    }
+
+    final int SECRET_SCHEMA_ATTRIBUTE_STRING = 0;
+    final int SECRET_SCHEMA_ATTRIBUTE_INTEGER = 1;
+    final int SECRET_SCHEMA_ATTRIBUTE_BOOLEAN = 2;
+
+    final int SECRET_SCHEMA_NONE = 0;
+    final int SECRET_SCHEMA_DONT_MATCH_NAME = 1;
+
+    final String SECRET_COLLECTION_DEFAULT = "default";
+    final String SECRET_COLLECTION_SESSION = "session";
+}
diff --git a/platform/keyring.impl/test/unit/src/org/netbeans/modules/keyring/gnome/libsecret/GnomeLibSecretProviderTest.java b/platform/keyring.impl/test/unit/src/org/netbeans/modules/keyring/gnome/libsecret/GnomeLibSecretProviderTest.java
new file mode 100644
index 0000000..0d03722
--- /dev/null
+++ b/platform/keyring.impl/test/unit/src/org/netbeans/modules/keyring/gnome/libsecret/GnomeLibSecretProviderTest.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.keyring.gnome.libsecret;
+
+import org.netbeans.modules.keyring.KeyringProviderTestBase;
+import org.netbeans.spi.keyring.KeyringProvider;
+
+public class GnomeLibSecretProviderTest extends KeyringProviderTestBase {
+
+    public GnomeLibSecretProviderTest(String n) {
+        super(n);
+    }
+
+    @Override
+    protected KeyringProvider createProvider() {
+        return new GnomeLibSecretProvider();
+    }
+
+}

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists