Dennis Kempin | cee3761 | 2013-06-14 10:40:41 -0700 | [diff] [blame] | 1 | # Copyright (c) 2013 The Chromium OS Authors. All rights reserved. |
| 2 | # Use of this source code is governed by a BSD-style license that can be |
| 3 | # found in the LICENSE file. |
| 4 | |
| 5 | import cookielib |
| 6 | import getpass |
| 7 | import imghdr |
| 8 | import os |
| 9 | import os.path |
Dennis Kempin | 13d948e | 2014-04-18 11:23:32 -0700 | [diff] [blame] | 10 | import re |
Dennis Kempin | cee3761 | 2013-06-14 10:40:41 -0700 | [diff] [blame] | 11 | import sys |
| 12 | import urllib |
| 13 | import urllib2 |
| 14 | |
| 15 | # path to current script directory |
| 16 | script_dir = os.path.dirname(os.path.realpath(__file__)) |
| 17 | cache_dir = os.path.realpath(os.path.join(script_dir, "..", "cache")) |
| 18 | if not os.path.exists(cache_dir): |
| 19 | os.mkdir(cache_dir) |
| 20 | |
| 21 | # path to the cookies file used for storing the login cookies. |
| 22 | cookies_file = os.path.join(cache_dir, "cookies") |
| 23 | |
| 24 | # path to folder where downloaded reports are cached |
| 25 | log_cache_dir = os.path.join(cache_dir, "reports") |
| 26 | if not os.path.exists(log_cache_dir): |
| 27 | os.mkdir(log_cache_dir) |
| 28 | |
| 29 | class FeedbackDownloader(): |
Dennis Kempin | 13d948e | 2014-04-18 11:23:32 -0700 | [diff] [blame] | 30 | def __init__(self, force_login=False): |
| 31 | if force_login and os.path.exists(cookies_file): |
| 32 | os.remove(cookies_file) |
Dennis Kempin | cee3761 | 2013-06-14 10:40:41 -0700 | [diff] [blame] | 33 | # setup cookies file and url opener |
| 34 | self.cookies = cookielib.MozillaCookieJar(cookies_file) |
| 35 | if os.path.exists(cookies_file): |
| 36 | self.cookies.load() |
| 37 | cookie_processor = urllib2.HTTPCookieProcessor(self.cookies) |
| 38 | self.opener = urllib2.build_opener(cookie_processor) |
| 39 | self._Login() |
| 40 | |
| 41 | def _Login(self): |
| 42 | username = getpass.getuser() |
| 43 | |
| 44 | # check if already logged in |
Dennis Kempin | 13d948e | 2014-04-18 11:23:32 -0700 | [diff] [blame] | 45 | url = "https://feedback.corp.google.com" |
Dennis Kempin | cee3761 | 2013-06-14 10:40:41 -0700 | [diff] [blame] | 46 | data = self.opener.open(url).read() |
Dennis Kempin | 13d948e | 2014-04-18 11:23:32 -0700 | [diff] [blame] | 47 | if "loginForm" not in data: |
Dennis Kempin | cee3761 | 2013-06-14 10:40:41 -0700 | [diff] [blame] | 48 | return |
| 49 | |
| 50 | # ask for credentials |
| 51 | print "Login to corp.google.com:" |
| 52 | password = getpass.getpass() |
| 53 | sys.stdout.write("OTP: ") |
| 54 | otp = sys.stdin.readline().strip() |
| 55 | |
Dennis Kempin | 13d948e | 2014-04-18 11:23:32 -0700 | [diff] [blame] | 56 | values = { |
| 57 | 'u': username, |
| 58 | 'pw': password, |
| 59 | 'otp': otp |
| 60 | } |
Dennis Kempin | cee3761 | 2013-06-14 10:40:41 -0700 | [diff] [blame] | 61 | |
Dennis Kempin | 13d948e | 2014-04-18 11:23:32 -0700 | [diff] [blame] | 62 | # extract hidden form values |
| 63 | regex = ("<input type=\"hidden\" id=\"([^\"]*)\" " + |
| 64 | "name=\"([^\"]*)\" value=\"([^\"]*)\"/>") |
| 65 | for match in re.finditer(regex, data): |
| 66 | values[match.group(2)] = match.group(3) |
| 67 | |
| 68 | # execute login by posting userdata to login.corp.google.com |
| 69 | query = urllib.urlencode(values) |
| 70 | url = ("https://login.corp.google.com/login") |
| 71 | result = self.opener.open(url, query).read() |
Dennis Kempin | cee3761 | 2013-06-14 10:40:41 -0700 | [diff] [blame] | 72 | # check if the result displays error |
| 73 | if "error" in result >= 0: |
| 74 | print "Login failed" |
| 75 | exit(-1) |
| 76 | |
| 77 | # login was successful. save cookies to file to be reused later. |
| 78 | self.cookies.save() |
| 79 | |
| 80 | def DownloadFile(self, url): |
| 81 | try: |
| 82 | return self.opener.open(url).read() |
| 83 | except urllib2.URLError: |
| 84 | return None |
| 85 | |
| 86 | def _GetAndUpdateCachedFile(self, filename, url): |
| 87 | cached_filename = os.path.join(log_cache_dir, filename) |
| 88 | try: |
| 89 | return open(cached_filename).read() |
| 90 | except IOError: |
| 91 | data = self.DownloadFile(url) |
| 92 | if not data: |
| 93 | return None |
| 94 | # Cache the data on disk |
| 95 | file(cached_filename, "w").write(data) |
| 96 | return data |
| 97 | |
| 98 | def DownloadSystemLog(self, id): |
| 99 | # First download the report.zip file |
| 100 | logfile = urllib.quote("report-%s-system_logs.zip" % id) |
| 101 | query = urllib.urlencode({"id": id, "logIndex": "0"}) |
| 102 | url = ("https://feedback.corp.googleusercontent.com/binarydata/%s?%s" % |
| 103 | (logfile, query)) |
Dennis Kempin | c6c981d | 2014-04-18 11:49:16 -0700 | [diff] [blame] | 104 | |
| 105 | print "Feedback downloads are currently not supported." |
| 106 | print "Please manually download this file:" |
| 107 | print " ", url |
| 108 | print "Then pass the file name '%s' as a parameter instead. e.g.:" % logfile |
| 109 | print " mtedit", logfile |
| 110 | print " mtreplay", logfile |
| 111 | print " touchtests testname -c", logfile |
| 112 | sys.exit(1) |
| 113 | |
Dennis Kempin | cee3761 | 2013-06-14 10:40:41 -0700 | [diff] [blame] | 114 | report = self._GetAndUpdateCachedFile(id + ".zip", url) |
Dennis Kempin | 13d948e | 2014-04-18 11:23:32 -0700 | [diff] [blame] | 115 | if "<html>" in report: |
| 116 | print "Received a website, you have been logged out." |
| 117 | print "Please re-login by running:" |
| 118 | print " mtedit --login" |
| 119 | return None |
Dennis Kempin | cee3761 | 2013-06-14 10:40:41 -0700 | [diff] [blame] | 120 | if not report or (report[0:2] != "BZ" and report[0:2] != "PK"): |
| 121 | print "Report does not include log files at %s" % url |
| 122 | return None |
| 123 | return report |
| 124 | |
| 125 | def DownloadScreenshot(self, id): |
| 126 | query = urllib.urlencode({"id": id}) |
| 127 | url = "https://feedback.corp.googleusercontent.com/screenshot?%s" % query |
| 128 | image = self._GetAndUpdateCachedFile(id + ".jpg", url) |
| 129 | if not image or imghdr.what("", image) != 'jpeg': |
| 130 | print "No screenshots available at %s" % url |
| 131 | return None |
| 132 | return image |