48
49
def set_token(self, token, token_secret):
49
self.token = oauth.OAuthToken(token, token_secret)
50
self.token = oauth.OAuthToken( token, token_secret)
51
52
def _get_oauth_request_header(self, url, method):
52
53
"""Get an oauth request header given the token and the url"""
53
54
query = urlparse(url).query
55
56
oauth_request = oauth.OAuthRequest.from_consumer_and_token(
58
oauth_consumer = self.consumer,
60
parameters = dict(parse_qsl(query))
59
oauth_consumer=self.consumer,
61
parameters=dict(parse_qsl(query))
62
63
oauth_request.sign_request(oauth.OAuthSignatureMethod_HMAC_SHA1(),
63
64
self.consumer, self.token)
64
65
return oauth_request.to_header()
66
def request(self, url, method = "GET", body = None, headers = {}, ignore = None):
67
def request(self, url, method="GET", body=None, headers={}, ignore=None):
67
68
oauth_header = self._get_oauth_request_header(url, method)
68
69
headers.update(oauth_header)
70
for n in range(1, globals.num_retries + 1):
71
log.Info("making %s request to %s (attempt %d)" % (method, url, n))
71
for n in range(1, globals.num_retries+1):
72
log.Info("making %s request to %s (attempt %d)" % (method,url,n))
73
resp, content = self.client.request(url, method, headers = headers, body = body)
74
resp, content = self.client.request(url, method, headers=headers, body=body)
74
75
except Exception, e:
75
log.Info("request failed, exception %s" % e)
76
if n >= globals.num_retries + 1:
77
log.FatalError("Giving up on request after %d attempts, last exception %s" % (n, e))
76
log.Info("request failed, exception %s" % e);
77
if n == globals.num_retries:
78
log.FatalError("Giving up on request after %d attempts, last exception %s" % (n,e))
80
log.Info("completed request with status %s %s" % (resp.status, resp.reason))
82
log.Info("completed request with status %s %s" % (resp.status,resp.reason))
81
83
oops_id = resp.get('x-oops-id', None)
83
85
log.Debug("Server Error: method %s url %s Oops-ID %s" % (method, url, oops_id))
96
98
elif numcode == 404:
97
99
ecode = log.ErrorCode.backend_not_found
99
if n >= globals.num_retries + 1:
100
log.FatalError("Giving up on request after %d attempts, last status %d %s" % (n, numcode.resp.reason), ecode)
103
def get_and_set_token(self, email, password, hostname):
101
if n < globals.num_retries:
104
log.FatalError("Giving up on request after %d attempts, last status %d %s" % (n,numcode,resp.reason),
108
def get_and_set_token(self,email, password, hostname):
104
109
"""Acquire an Ubuntu One access token via OAuth with the Ubuntu SSO service.
105
110
See https://one.ubuntu.com/developer/account_admin/auth/otherplatforms for details.
108
113
# Request new access token from the Ubuntu SSO service
109
self.client.add_credentials(email, password)
114
self.client.add_credentials(email,password)
110
115
resp, content = self.client.request('https://login.ubuntu.com/api/1.0/authentications?'
111
+ 'ws.op=authenticate&token_name=Ubuntu%%20One%%20@%%20%s' % hostname)
112
if resp.status != 200:
113
log.FatalError("Token request failed: Incorrect Ubuntu One credentials", log.ErrorCode.backend_permission_denied)
116
+'ws.op=authenticate&token_name=Ubuntu%%20One%%20@%%20%s' % hostname)
118
log.FatalError("Token request failed: Incorrect Ubuntu One credentials",log.ErrorCode.backend_permission_denied)
114
119
self.client.clear_credentials()
116
tokendata = loads(content)
117
self.set_consumer(tokendata['consumer_key'], tokendata['consumer_secret'])
118
self.set_token(tokendata['token'], tokendata['token_secret'])
121
tokendata=loads(content)
122
self.set_consumer(tokendata['consumer_key'],tokendata['consumer_secret'])
123
self.set_token(tokendata['token'],tokendata['token_secret'])
120
125
# and finally tell Ubuntu One about the token
121
126
resp, content = self.request('https://one.ubuntu.com/oauth/sso-finished-so-get-tokens/')
122
if resp.status != 200:
123
log.FatalError("Ubuntu One token was not accepted: %s %s" % (resp.status, resp.reason))
128
log.FatalError("Ubuntu One token was not accepted: %s %s" % (resp.status,resp.reason))
141
146
self.volume_uri = "%s/volumes/~/%s" % (self.api_base, path)
142
147
self.meta_base = "%s/~/%s/" % (self.api_base, path)
144
self.client = OAuthHttpClient()
149
self.client=OAuthHttpClient();
146
151
if 'FTP_PASSWORD' not in os.environ:
147
152
sys.stderr.write("No Ubuntu One token found in $FTP_PASSWORD, requesting a new one\n")
148
email = raw_input('Enter Ubuntu One account email: ')
149
password = getpass.getpass("Enter Ubuntu One password: ")
150
hostname = os.uname()[1]
153
email=raw_input('Enter Ubuntu One account email: ')
154
password=getpass.getpass("Enter Ubuntu One password: ")
155
hostname=os.uname()[1]
152
tokendata = self.client.get_and_set_token(email, password, hostname)
157
tokendata=self.client.get_and_set_token(email,password,hostname)
153
158
sys.stderr.write("\nPlease record your new Ubuntu One access token for future use with duplicity:\n"
154
+ "FTP_PASSWORD=%s:%s:%s:%s\n\n"
155
% (tokendata['consumer_key'], tokendata['consumer_secret'],
156
tokendata['token'], tokendata['token_secret']))
159
+"FTP_PASSWORD=%s:%s:%s:%s\n\n"
160
% (tokendata['consumer_key'],tokendata['consumer_secret'],
161
tokendata['token'],tokendata['token_secret']))
158
(consumer, consumer_secret, token, token_secret) = os.environ['FTP_PASSWORD'].split(':')
163
(consumer,consumer_secret,token,token_secret) = os.environ['FTP_PASSWORD'].split(':')
159
164
self.client.set_consumer(consumer, consumer_secret)
160
165
self.client.set_token(token, token_secret)
162
resp, content = self.client.request(self.api_base, ignore = [400, 401, 403])
163
if resp['status'] != '200':
164
log.FatalError("Access failed: Ubuntu One credentials incorrect",
167
resp, content = self.client.request(self.api_base,ignore=[400,401,403])
168
if resp['status']!='200':
169
log.FatalError("Access failed: Ubuntu One credentials incorrect",
165
170
log.ErrorCode.user_error)
167
172
# Create volume, but check existence first
168
resp, content = self.client.request(self.volume_uri, ignore = [404])
169
if resp['status'] == '404':
170
resp, content = self.client.request(self.volume_uri, "PUT")
173
resp, content = self.client.request(self.volume_uri,ignore=[404])
174
if resp['status']=='404':
175
resp, content = self.client.request(self.volume_uri,"PUT")
172
177
def quote(self, url):
173
return urllib.quote(url, safe = "/~").replace(" ", "%20")
178
return urllib.quote(url, safe="/~").replace(" ","%20")
175
180
def put(self, source_path, remote_filename = None):
176
181
"""Copy file to remote"""
178
183
remote_filename = source_path.get_filename()
179
184
remote_full = self.meta_base + self.quote(remote_filename)
180
185
# check if it exists already, returns existing content_path
181
resp, content = self.client.request(remote_full, ignore = [404])
182
if resp['status'] == '404':
186
resp, content = self.client.request(remote_full,ignore=[404])
187
if resp['status']=='404':
183
188
# put with path returns new content_path
184
189
resp, content = self.client.request(remote_full,
186
191
headers = { 'content-type': 'application/json' },
187
body = dumps({"kind":"file"}))
188
elif resp['status'] != '200':
192
body=dumps({"kind":"file"}))
193
elif resp['status']!='200':
189
194
raise BackendException("access to %s failed, code %s" % (remote_filename, resp['status']))
191
196
assert(content['content_path'] is not None)