secret-mediator.vala 5.87 KB
Newer Older
1
/* Copyright 2011-2014 Yorba Foundation
2 3
 *
 * This software is licensed under the GNU Lesser General Public License
4
 * (version 2.1 or later).  See the COPYING file in this distribution.
5 6
 */

7 8
// LibSecret password adapter.
public class SecretMediator : Geary.CredentialsMediator, Object {
9 10
    private const string OLD_GEARY_USERNAME_PREFIX = "org.yorba.geary username:";
    
11
    private string get_key_name(Geary.Service service, string user) {
12
        switch (service) {
13
            case Geary.Service.IMAP:
14 15
                return "org.yorba.geary imap_username:" + user;
            
16
            case Geary.Service.SMTP:
17 18 19 20 21 22
                return "org.yorba.geary smtp_username:" + user;
            
            default:
                assert_not_reached();
        }
    }
23

24
    private Geary.Credentials get_credentials(Geary.Service service, Geary.AccountInformation account_information) {
25
        switch (service) {
26
            case Geary.Service.IMAP:
27 28
                return account_information.imap_credentials;

29
            case Geary.Service.SMTP:
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
                return account_information.smtp_credentials;

            default:
                assert_not_reached();
        }
    }

    private async string? migrate_old_password(string old_key, string new_key, Cancellable? cancellable)
        throws Error {
        string? password = yield Secret.password_lookup(Secret.SCHEMA_COMPAT_NETWORK, cancellable,
            "user", old_key);
        if (password != null) {
            bool result = yield Secret.password_store(Secret.SCHEMA_COMPAT_NETWORK,
                null, new_key, password, cancellable, "user", new_key);
            if (result)
                yield Secret.password_clear(Secret.SCHEMA_COMPAT_NETWORK, cancellable, "user", old_key);
        }
        
        return password;
    }
50 51
    
    public virtual async string? get_password_async(
52
        Geary.Service service, Geary.AccountInformation account_information, Cancellable? cancellable = null)
53
        throws Error {
54
        string key_name = get_key_name(service, account_information.email);
55
        string? password = yield Secret.password_lookup(Secret.SCHEMA_COMPAT_NETWORK, cancellable,
56
            "user", key_name);
57
        
58
        // fallback to the old keyring key string for upgrading users
59
        if (password == null) {
60 61 62 63 64 65 66 67 68 69 70
            Geary.Credentials creds = get_credentials(service, account_information);
            
            // <= 0.6
            password = yield migrate_old_password(get_key_name(service, creds.user),
                key_name, cancellable);
            
            // 0.1
            if (password == null) {
                password = yield migrate_old_password(OLD_GEARY_USERNAME_PREFIX + creds.user,
                    key_name, cancellable);
            }
71 72
        }
        
73
        if (password == null)
74
            debug("Unable to fetch password in libsecret keyring for %s", account_information.email);
75
        
76
        return password;
77 78 79
    }
    
    public virtual async void set_password_async(
80
        Geary.Service service, Geary.AccountInformation account_information,
81
        Cancellable? cancellable = null) throws Error {
82 83
        string key_name = get_key_name(service, account_information.email);
        Geary.Credentials credentials = get_credentials(service, account_information);
84
        
85 86 87
        bool result = yield Secret.password_store(Secret.SCHEMA_COMPAT_NETWORK,
            null, key_name, credentials.pass, cancellable, "user", key_name);
        if (!result)
88
            debug("Unable to store password for \"%s\" in libsecret keyring", key_name);
89 90 91
    }
    
    public virtual async void clear_password_async(
92
        Geary.Service service, Geary.AccountInformation account_information, Cancellable? cancellable = null)
93
        throws Error {
94
        // delete new-style and old-style locations
95 96 97 98 99
        Geary.Credentials credentials = get_credentials(service, account_information);
        // new-style
        yield Secret.password_clear(Secret.SCHEMA_COMPAT_NETWORK, cancellable, "user",
            get_key_name(service, account_information.email));
        // <= 0.6
100
        yield Secret.password_clear(Secret.SCHEMA_COMPAT_NETWORK, cancellable, "user",
101 102
            get_key_name(service, credentials.user));
        // 0.1
103
        yield Secret.password_clear(Secret.SCHEMA_COMPAT_NETWORK, cancellable, "user",
104
            OLD_GEARY_USERNAME_PREFIX + credentials.user);
105 106
    }
    
107
    public virtual async bool prompt_passwords_async(Geary.ServiceFlag services,
108 109 110
        Geary.AccountInformation account_information,
        out string? imap_password, out string? smtp_password,
        out bool imap_remember_password, out bool smtp_remember_password) throws Error {
111 112 113
        // Our dialog doesn't support asking for both at once, even though this
        // API would indicate it does.  We need to revamp the API.
        assert(!services.has_imap() || !services.has_smtp());
114
        
115 116
        PasswordDialog password_dialog = new PasswordDialog(services.has_smtp(),
            account_information, services);
117 118 119 120 121 122 123 124 125 126 127
        
        if (!password_dialog.run()) {
            imap_password = null;
            smtp_password = null;
            imap_remember_password = false;
            smtp_remember_password = false;
            return false;
        }
        
        // password_dialog.password should never be null at this point. It will only be null when
        // password_dialog.run() returns false, in which case we have already returned.
128 129 130 131 132 133 134 135 136 137 138
        if (services.has_smtp()) {
            imap_password = null;
            imap_remember_password = false;
            smtp_password = password_dialog.password;
            smtp_remember_password = password_dialog.remember_password;
        } else {
            imap_password = password_dialog.password;
            imap_remember_password = password_dialog.remember_password;
            smtp_password = null;
            smtp_remember_password = false;
        }
139 140 141
        return true;
    }
}