~ubuntu-branches/ubuntu/precise/deja-dup/precise-proposed

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
/* -*- Mode: Vala; indent-tabs-mode: nil; tab-width: 2 -*- */
/*
    This file is part of Déjà Dup.
    © 2008,2009,2010 Michael Terry <mike@mterry.name>
    © 2011 Canonical Ltd

    Déjà Dup is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Déjà Dup is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Déjà Dup.  If not, see <http://www.gnu.org/licenses/>.
*/

using GLib;

namespace DejaDup {

public const string S3_ROOT = "S3";
public const string S3_ID_KEY = "id";
public const string S3_BUCKET_KEY = "bucket";
public const string S3_FOLDER_KEY = "folder";

const string S3_SERVER = "s3.amazonaws.com";

public class BackendS3 : Backend
{
  public static Checker get_checker() {
    return PythonChecker.get_checker("boto");
  }

  public override Backend clone() {
    return new BackendS3();
  }
  
  public override void add_argv(Operation.Mode mode, ref List<string> argv) {
    if (mode == Operation.Mode.INVALID)
      argv.append("--s3-use-new-style");
  }
  
  string get_default_bucket() {
    return "deja-dup-auto-%s".printf(id.down());
  }

  public override bool is_native() {
    return false;
  }
  
  public override Icon? get_icon() {
    return new ThemedIcon("deja-dup-cloud");
  }

  public override bool is_ready(out string when) {
    when = _("Backup will begin when a network connection becomes available.");
    return Network.get().connected;
  }

  public override string? get_location() throws Error
  {
    var settings = get_settings(S3_ROOT);
    
    var bucket = settings.get_string(S3_BUCKET_KEY);
    var default_bucket = get_default_bucket();
    if (bucket == null || bucket == "" ||
        (bucket.has_prefix("deja-dup-auto-") &&
         !bucket.has_prefix(default_bucket))) {
      bucket = default_bucket;
      settings.set_string(S3_BUCKET_KEY, bucket);
    }
    
    var folder = get_folder_key(settings, S3_FOLDER_KEY);
    return "s3+http://%s/%s".printf(bucket, folder);
  }
  
  public bool bump_bucket() {
    // OK, the bucket we tried must already exist, so let's use a different
    // one.  We'll take previous bucket name and increment it.
    var settings = get_settings(S3_ROOT);
    
    var bucket = settings.get_string(S3_BUCKET_KEY);
    if (bucket == "deja-dup") {
      // Until 7.4, we exposed the bucket name and defaulted to deja-dup.
      // Since buckets are S3-global, everyone was unable to use that bucket,
      // since I (Mike Terry) owned that bucket.  If we see this setting,
      // we should default to the generic bucket name rather than assume the
      // user chose this bucket and error out.
      bucket = get_default_bucket();
      settings.set_string(S3_BUCKET_KEY, bucket);
      return true;
    }
    
    if (!bucket.has_prefix("deja-dup-auto-"))
      return false;
    
    var bits = bucket.split("-");
    if (bits == null || bits[0] == null || bits[1] == null ||
        bits[2] == null || bits[3] == null)
      return false;
    
    if (bits[4] == null)
      bucket += "-2";
    else {
      var num = long.parse(bits[4]);
      bits[4] = (num + 1).to_string();
      bucket = string.joinv("-", bits);
    }
    
    settings.set_string(S3_BUCKET_KEY, bucket);
    return true;
  }
  
  public override string? get_location_pretty() throws Error
  {
    var settings = get_settings(S3_ROOT);
    var folder = get_folder_key(settings, S3_FOLDER_KEY);
    if (folder == "")
      return _("Amazon S3");
    else
      // Translators: %s is a folder.
      return _("%s on Amazon S3").printf(folder);
  }
  
  string settings_id;
  string id;
  string secret_key;
  public override async void get_envp() throws Error
  {
    var settings = get_settings(S3_ROOT);
    settings_id = settings.get_string(S3_ID_KEY);
    id = settings_id == null ? "" : settings_id;
    
    if (id != "" && secret_key != null) {
      // We've already been run before and got the key
      got_secret_key();
      return;
    }
    
    if (id != "") {
      // First, try user's keyring
      secret_key = null;
      GnomeKeyring.find_network_password(id, null, S3_SERVER, null, "https",
                                         null, 0, found_password);
    }
    else
      ask_password();
  }
  
  void found_password(GnomeKeyring.Result result,
                      GLib.List<GnomeKeyring.NetworkPasswordData>? list)
  {
    if (result == GnomeKeyring.Result.OK && list != null) {
      secret_key = list.data.password;
      got_secret_key();
    }
    else {
      ask_password();
    }
  }
  
  void save_password_callback(GnomeKeyring.Result result, uint32 val)
  {
  }
  
  void got_password_reply(MountOperation mount_op, MountOperationResult result)
  {
    if (result != MountOperationResult.HANDLED) {
      envp_ready(false, new List<string>(), _("Permission denied"));
      return;
    }

    id = mount_op.username;
    secret_key = mount_op.password;

    // Save it
    var remember = mount_op.password_save;
    if (remember != PasswordSave.NEVER) {
      string where = (remember == PasswordSave.FOR_SESSION) ?
                     "session" : GnomeKeyring.DEFAULT;
      GnomeKeyring.set_network_password(where, id, null, S3_SERVER, null,
                                        "https", null, 0, secret_key,
                                        save_password_callback);
    }
    
    got_secret_key();
  }

  void ask_password() {
    mount_op.set("label_help", _("You can sign up for an Amazon S3 account <a href=\"%s\">online</a>.").printf("http://aws.amazon.com/s3/"));
    mount_op.set("label_username", _("_Access key ID:"));
    mount_op.set("label_password", _("_Secret access key:"));
    mount_op.set("label_show_password", _("S_how secret access key"));
    mount_op.set("label_remember_password", _("_Remember secret access key"));
    mount_op.reply.connect(got_password_reply);
    mount_op.ask_password(_("Enter Amazon S3 access key"), id, "",
                          AskPasswordFlags.NEED_PASSWORD |
                          AskPasswordFlags.NEED_USERNAME |
                          AskPasswordFlags.SAVING_SUPPORTED);
  }
  
  void got_secret_key() {
    var settings = get_settings(S3_ROOT);
    if (id != settings_id)
      settings.set_string(S3_ID_KEY, id);
    
    List<string> envp = new List<string>();
    envp.append("AWS_ACCESS_KEY_ID=%s".printf(id));
    envp.append("AWS_SECRET_ACCESS_KEY=%s".printf(secret_key));
    envp_ready(true, envp);
  }
}

} // end namespace