Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(942)

Side by Side Diff: mailer.py

Issue 19878007: Add build mailer capability to support gatekeeper_ng. (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/chromium-build@master
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 import datetime
2 from google.appengine.api import mail
3 import hashlib
4 import hmac
5 import logging
6 import json
7 import webapp2
8 from webapp2_extras import jinja2
9
10 import gatekeeper_mailer
11
12
13 class BaseHandler(webapp2.RequestHandler):
14 """Provide a cached Jinja environment to each request."""
15 @webapp2.cached_property
16 def jinja2(self):
17 # Returns a Jinja2 renderer cached in the app registry.
18 return jinja2.get_jinja2(app=self.app)
19
20 def render_response(self, _template, **context):
21 # Renders a template and writes the result to the response.
22 rv = self.jinja2.render_template(_template, **context)
23 self.response.write(rv)
24
25
26 class MainPage(BaseHandler):
27 def get(self):
28 context = {'title': 'Chromium Gatekeeper Mailer'}
29 self.render_response('main_mailer.html', **context)
30
31
32 class Email(BaseHandler):
33 @staticmethod
34 def _validate_message(message, secret):
35 # Make this backwards compatable with python 2.6, since total_seconds()
36 # exists only in python 2.7.
37 utc_now_td = (datetime.datetime.utcnow() -
38 datetime.datetime.utcfromtimestamp(0))
39 utc_now = utc_now_td.days * 86400 + utc_now_td.seconds
40
41 if (utc_now < message['time']) or (utc_now - message['time'] > 60):
42 logging.error('message was rejected due to time')
43 return False
44
45 hasher = hmac.new(secret, '%s:%d:%d' % (message['message'],
46 message['time'],
47 message['salt']),
48 hashlib.sha256)
49
50 client_hash = hasher.hexdigest()
51
52 return client_hash == message['sha256']
53
54
55 @staticmethod
56 def _verify_json(build_data):
57 fields = ['waterfall_url',
58 'build_url',
59 'project_name',
60 'builderName',
61 'steps',
62 'unsatisfied',
63 'revisions',
64 'blamelist',
65 'result',
66 'number',
67 'changes',
68 'reason',
69 'recipients']
70
71 for field in fields:
72 if field not in build_data:
73 logging.error('build_data did not contain field %s' % field)
74 return False
75
76 stepfields = ['started',
77 'text',
78 'results',
79 'name',
80 'logs',
81 'urls']
82
83 if not build_data['steps']:
84 logging.error('build_data did not contain any steps')
85 return False
86 for step in build_data['steps']:
87 for field in stepfields:
88 if field not in step:
89 logging.error('build_step did not contain field %s' % field)
90 return False
91
92 return True
93
94 def post(self):
95 blob = self.request.get('json')
96 if not blob:
97 self.response.out.write('no json data sent')
98 logging.error('error no json sent')
99 self.error(400)
100 return
101
102 message = {}
103 try:
104 message = json.loads(blob)
105 except ValueError as e:
106 self.response.out.write('couldn\'t decode json')
107 logging.error('error decoding incoming json: %s' % e)
108 self.error(400)
109 return
110
111 if not self._validate_message(message, 'pajamas'):
agable 2013/08/01 17:52:44 Nice secret :)
112 self.response.out.write('unauthorized')
113 logging.error('incoming message did not validate')
114 self.error(403)
115 return
116
117 build_data = json.loads(message['message'])
118
119 if not self._verify_json(build_data):
120 logging.error('error verifying incoming json: %s' % build_data)
121 self.response.out.write('json build format is incorrect')
agable 2013/08/01 17:52:44 Could be a more informative error message -- what
122 self.error(400)
123 return
124
125 from_addr = build_data.get('from_addr', 'buildbot@chromium.org')
agable 2013/08/01 17:52:44 Does sending as this address work, or does appengi
Mike Stip (use stip instead) 2013/08/29 19:56:46 it doesn't, fixed
126 recipients = ', '.join(build_data['recipients'])
127
128 template = gatekeeper_mailer.MailTemplate(build_data['waterfall_url'],
129 build_data['build_url'],
130 build_data['project_name'],
131 from_addr)
132
133
134 text_content, html_content, subject = template.genMessageContent(build_data)
135
136 message = mail.EmailMessage(sender=from_addr,
137 subject=subject,
138 #to=recipients,
139 to=['xusydoc@chromium.org'],
140 body=text_content,
141 html=html_content)
142 logging.info('sending email to %s', recipients)
143 message.send()
144 self.response.out.write('email sent')
145
146
147 app = webapp2.WSGIApplication([('/mailer', MainPage),
148 ('/mailer/email', Email)],
149 debug=True)
OLDNEW
« gatekeeper_mailer.py ('K') | « gatekeeper_mailer.py ('k') | templates/base_mailer.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698