Working libsecret keystore
[moonshot-ui.git] / src / moonshot-keyring-store-secret.vala
1 /*
2 * Copyright (C) 2018   Sam Hartman
3 * Copyright (c) 2011-2016, JANET(UK)
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of JANET(UK) nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32 */
33
34 #if LIBSECRET_KEYRING
35
36 using Secret;
37
38 private Collection? find_secret_collection()
39 {
40     Collection secret_collection = null;
41     stdout.printf("In find_secret_collection\n");
42     try {
43         Service service = Service.get_sync(ServiceFlags.OPEN_SESSION);
44         secret_collection = Collection.for_alias_sync(service, COLLECTION_DEFAULT,
45                                                       CollectionFlags.NONE);
46     } catch(GLib.Error e) {
47         stdout.printf("Unable to load secret service: %s\n", e.message);
48         }
49     return secret_collection;
50     }
51
52 public class KeyringStore : KeyringStoreBase {
53     /*
54     * We choose to remain compatible with the way we stored secrets
55     * using libgnomekeyring.  As a result, we cannot use our own schema
56     * identifier.  Using our own schema might get us a nice icon in
57     * seahorse, but would not save much code. 
58     */
59     private const SchemaAttributeType sstring = SchemaAttributeType.STRING;
60     private static Schema schema = new Schema("org.freedesktop.Secret.Generic", SchemaFlags.NONE,
61                                               "Moonshot", sstring,
62                                               "Issuer", sstring,
63                                               "Username", sstring,
64                                               "DisplayName", sstring,
65                                               "Services", sstring,
66                                               "Rules-Pattern", sstring,
67                                               "Rules-AlwaysConfirm", sstring,
68                                               "CA-Cert", sstring,
69                                               "Server-Cert", sstring,
70                                               "Subject", sstring,
71                                               "Subject-Alt", sstring,
72                                               "TA_DateTime_Added", sstring,
73                                               "StorePassword", sstring);
74     private static Collection? secret_collection = find_secret_collection();
75
76     
77     
78
79     /* clear all keyring-stored ids (in preparation to store current list) */
80     protected override void clear_keyring() {
81         GLib.List<Item> items;
82         try {
83             items = secret_collection.search_sync(schema, match_attributes,
84                                                   SearchFlags.ALL);
85         } catch (GLib.Error e) {
86             stdout.printf("Failed to find items to delete: %s\n", e.message);
87             return;
88         }
89         foreach(unowned Item  entry in items) {
90             try {
91                 bool res = entry.delete_sync();
92                 if (!res) {
93                     stdout.printf("Failed to delete item: %s\n", entry.get_label());
94                 }
95             } catch (GLib.Error e) {
96                 stdout.printf("Error deleting item: %s\n", e.message);
97             }
98         }
99     }
100
101     protected override void load_id_cards()  throws GLib.Error {
102         id_card_list.clear();
103
104         GLib.List<Item> items = secret_collection.search_sync(
105                                                               schema, match_attributes,
106                                                               SearchFlags.UNLOCK|SearchFlags.LOAD_SECRETS|SearchFlags.ALL);
107         foreach(unowned Item entry in items) {
108             var secret = entry.get_secret();
109             string secret_text = null;
110             if (secret != null)
111                 secret_text = secret.get_text();
112             var id_card = deserialize(entry.attributes, secret_text);
113             id_card_list.add(id_card);
114         }
115     }
116
117     internal override void store_id_cards() {
118         logger.trace("store_id_cards");
119         clear_keyring();
120         foreach (IdCard id_card in this.id_card_list) {
121             try {
122 var attributes = serialize(id_card);
123                 password_storev_sync(schema, attributes, null, id_card.display_name,
124                                      id_card.store_password?id_card.password: "");
125             } catch(GLib.Error e) {
126                 logger.error(@"Unable to store $(id_card.display_name): $(e.message)\n");
127         }
128         
129         }
130         try {
131             load_id_cards();
132         } catch (GLib.Error e) {
133             logger.error(@"Unable to load ID Cards: $(e.message)\n");
134         }
135         
136     }
137
138     public static bool is_available()
139     {
140         if (secret_collection == null) {
141             secret_collection = find_secret_collection();
142         }
143         
144         return secret_collection != null;
145     }
146     
147 }
148
149 #endif