def __init__(self, provider): self.provider = provider self.consumer_class = None self.log_debug = logging.DEBUG >= log.getEffectiveLevel() self.config = get_oauth_config(provider) self.endpoint_regex = self.config.get('endpoint_regex') # application config items, dont use self.config store = config.get('openid_store', 'mem') if store == u"file": store_file_path = config.get('openid_store_path', None) self.openid_store = filestore.FileOpenIDStore(store_file_path) elif store == u"mem": self.openid_store = memstore.MemoryStore() elif store == u"sql": # TODO: This does not work as we need a connection, not a string # XXX #self.openid_store = sqlstore.SQLStore(sql_connstring, # sql_associations_table, sql_connstring) raise NotImplementedError() self.scope = self.config.get('scope', None) self.return_to_query = {}
def save_capture(self, reason="no reason"): host = self.pc_get_host() try: base_path = config.get('protocol_capture_path') if not base_path: log.warn("want to write a request capture, " "but no protocol_capture_path is defined") return if not os.path.isdir(base_path): log.warn( "want to write a request capture, " "but directory %r does not exist", base_path) return thisdir = "%s-%s-%s-%s" % (self.pc_protocol, host, time.time(), random.getrandbits(32)) dirname = os.path.join(base_path, thisdir) os.makedirs(dirname) # call the subclass to save itself and return the metadata meta = {'protocol': self.pc_protocol, 'reason': reason} submeta = self._save_capture(dirname) if submeta: meta.update(submeta) meta_file = os.path.join(dirname, "meta.json") with open(meta_file, "wb") as f: json.dump(meta, f, sort_keys=True, indent=4) f.write("\n") log.info("wrote '%s' capture to %s", self.pc_protocol, dirname) except Exception: log.exception("failed to write a capture log")
def sendmessage(self, message, options, headers): share_type = options.get('shareType', None) if share_type == 'groupWall': direct = options.get('to', None) if not direct: return None, {'code': 400, 'message': 'Wall name is missing'} url = "https://graph.facebook.com/%s/feed" % (direct, ) elif share_type == 'wall': url = config.get("oauth.facebook.com.feed", "https://graph.facebook.com/me/feed") else: return None, {'code': 400, 'message': 'Share type is missing'} body = {"message": message} for ours, yours in self.post_map.items(): if ours in options: body[yours] = options[ours] return self.rawcall(url, body, "POST", headers=headers)
def _get_credentials(self, access_token): profile_url = config.get("oauth.facebook.com.profile", self.profile_url) fields = ('id,first_name,last_name,name,link,birthday,email,' 'website,verified,picture,gender,timezone') client = HttpRequestor() url = build_url(profile_url, access_token=access_token, fields=fields) resp, content = client.request(url) if resp['status'] != '200': reason = "Error status: %r", resp['status'] client.save_capture(reason) raise Exception(reason) try: fb_profile = json.loads(content) except ValueError: client.save_capture('non-json facebook 200 response') raise profile = extract_fb_data(fb_profile) result_data = {'profile': profile, 'oauth_token': access_token} return result_data
def sendmessage(self, message, options, headers): profile = self.account.get('profile', {}) from_ = profile.get('verifiedEmail') fullname = profile.get('displayName', None) address_list = AddressList(options.get('to', '')) if len(address_list) == 0: return None, { "provider": domain, "message": "recipient address must be specified", "status": 0} to_ = [] for addr in address_list: if not addr[1] or not '@' in addr[1]: return None, { "provider": domain, "message": "recipient address '%s' is invalid" % \ (addr[1],), "status": 0} # expect normal email address formats, parse them to_.append({'name': addr[0], 'email': addr[1]}) if len(to_) == 0: raise OptionError('the To header cannot be empty') subject = options.get('subject', config.get('share_subject', 'A web link has been shared with you')) title = options.get('title', options.get('link', options.get('shorturl', ''))) description = options.get('description', '')[:280] extra_vars = {'safeHTML': safeHTML} extra_vars['options'] = options # insert the url if it is not already in the message extra_vars['longurl'] = options.get('link') extra_vars['shorturl'] = options.get('shorturl') # reset to unwrapped for html email, they will be escaped extra_vars['from_name'] = fullname extra_vars['subject'] = subject extra_vars['from_header'] = from_ extra_vars['title'] = title extra_vars['description'] = description extra_vars['message'] = message extra_vars['thumbnail'] = False html_message = render('/html_email.mako', extra_vars=extra_vars).encode('utf-8') # get the title, or the long url or the short url or nothing # wrap these in literal for text email extra_vars['from_name'] = literal(fullname) extra_vars['subject'] = literal(subject) extra_vars['from_header'] = literal(from_) extra_vars['title'] = literal(title) extra_vars['description'] = literal(description) extra_vars['message'] = literal(message) text_message = render('/text_email.mako', extra_vars=extra_vars).encode('utf-8') params = [{ "message": {"subject":subject, "from":{"name": fullname, "email":from_}, "to":to_, "simplebody":{ "text": text_message, "html": html_message}}, "savecopy":1}] return self.jsonrpc(self.endpoints['mail'], 'SendMessage', params, options, headers)
def request(self, uri, method="GET", body='', headers=None): response, data = self.http.request(uri, method, body, headers) if (300 > int(response['status']) >= 200 and asbool(config.get('protocol_capture_success'))): self.save_capture("automatic success save") return response, data
def sendmessage(self, message, options, headers): if options is None: options = {} share_type = str(options.get('shareType', '')) if not share_type or share_type not in \ ('public', 'myConnections', 'contact'): return None, { 'code': 400, 'provider': 'linkedin', 'message': 'Invalid share type' } # TODO: this needs a bit work, it is not really "direct". if share_type in ('public', 'myConnections'): direct = options.get('to', 'anyone') if (share_type == 'public' and direct != 'anyone') or \ (share_type == 'myConnections' and direct != 'connections-only'): return None, { 'code': 400, 'provider': 'linkedin', 'message': 'Incorrect addressing for post' } url = "http://api.linkedin.com/v1/people/~/shares" body = { "comment": message, "content": { "title": options.get('subject', ''), "submitted-url": options.get('link', ''), "submitted-image-url": options.get('picture', ''), "description": options.get('description', ''), }, "visibility": { "code": direct } } else: # we have to do a direct message, different api url = "http://api.linkedin.com/v1/people/~/mailbox" profile = self.account.get('profile', {}) from_ = profile.get('verifiedEmail') fullname = profile.get('displayName') to_addrs = AddressList(options['to']) subject = options.get( 'subject', config.get('share_subject', 'A web link has been shared with you')) title = options.get( 'title', options.get('link', options.get('shorturl', ''))) description = options.get('description', '')[:280] to_ = [] ids = [a[1] for a in to_addrs.addresslist] if not ids: return None, { 'code': 400, 'message': 'Missing contacts for direct messaging.' } for id in ids: to_.append({'person': {'_path': '/people/' + id}}) extra_vars = {'safeHTML': safeHTML} extra_vars['options'] = options # insert the url if it is not already in the message extra_vars['longurl'] = options.get('link') extra_vars['shorturl'] = options.get('shorturl') # get the title, or the long url or the short url or nothing # wrap these in literal for text email extra_vars['from_name'] = literal(fullname) extra_vars['subject'] = literal(subject) extra_vars['from_header'] = literal(from_) extra_vars['to_header'] = literal(to_) extra_vars['title'] = literal(title) extra_vars['description'] = literal(description) extra_vars['message'] = literal(message) text_message = render('/text_email.mako', extra_vars=extra_vars).encode('utf-8') body = { 'recipients': { 'values': to_ }, 'subject': subject, 'body': text_message } return self.rawcall(url, body, method="POST", headers=headers)
def sendmessage(self, message, options, headers): if options is None: options = {} result = error = None profile = self.account.get('profile', {}) from_email = from_ = profile['emails'][0]['value'] fullname = profile.get('displayName', None) if fullname: from_email = '"%s" <%s>' % (Header( fullname, 'utf-8').encode(), Header(from_, 'utf-8').encode()) url = "https://mail.google.com/mail/b/%s/smtp/" % from_ # 'to' parsing address_list = AddressList(options.get('to', '')) if len(address_list) == 0: return None, { "provider": self.host, "message": "recipient address must be specified", "status": 0 } to_headers = [] for addr in address_list: if not addr[1] or not '@' in addr[1]: return None, { "provider": self.host, "message": "recipient address '%s' is invalid" % addr[1], "status": 0 } if addr[0]: to_ = '"%s" <%s>' % (Header(addr[0], 'utf-8').encode(), Header(addr[1], 'utf-8').encode()) else: to_ = Header(addr[1], 'utf-8').encode() to_headers.append(to_) if len(to_headers) == 0: raise OptionError('the To header cannot be empty') subject = options.get( 'subject', config.get('share_subject', 'A web link has been shared with you')) title = options.get('title', options.get('link', options.get('shorturl', ''))) description = options.get('description', '')[:280] msg = MIMEMultipart('alternative') msg.set_charset('utf-8') msg.add_header('Subject', Header(subject, 'utf-8').encode()) msg.add_header('From', from_email) for to_ in to_headers: msg.add_header('To', to_) extra_vars = {'safeHTML': safeHTML, 'options': options} # insert the url if it is not already in the message extra_vars['longurl'] = options.get('link') extra_vars['shorturl'] = options.get('shorturl') # reset to unwrapped for html email, they will be escaped extra_vars['from_name'] = fullname extra_vars['subject'] = subject extra_vars['from_header'] = from_ extra_vars['title'] = title extra_vars['description'] = description extra_vars['message'] = message extra_vars['thumbnail'] = options.get('picture_base64', "") != "" mail = render('/html_email.mako', extra_vars=extra_vars) mail = mail.encode('utf-8') if extra_vars['thumbnail']: part2 = MIMEMultipart('related') html = MIMEText(mail, 'html') html.set_charset('utf-8') # FIXME: we decode the base64 data just so MIMEImage # can re-encode it as base64 image = MIMEImage(base64.b64decode(options.get('picture_base64')), 'png') image.add_header('Content-Id', '<thumbnail>') image.add_header('Content-Disposition', 'inline; filename=thumbnail.png') part2.attach(html) part2.attach(image) else: part2 = MIMEText(mail, 'html') part2.set_charset('utf-8') # get the title, or the long url or the short url or nothing # wrap these in literal for text email extra_vars['from_name'] = literal(fullname) extra_vars['subject'] = literal(subject) extra_vars['from_header'] = literal(from_) extra_vars['title'] = literal(title) extra_vars['description'] = literal(description) extra_vars['message'] = literal(message) rendered = render('/text_email.mako', extra_vars=extra_vars) part1 = MIMEText(rendered.encode('utf-8'), 'plain') part1.set_charset('utf-8') msg.attach(part1) msg.attach(part2) server = None try: server = SMTPRequestor(self.host, self.port) # in the app:main set debug = true to enable if asbool(config.get('debug', False)): server.set_debuglevel(True) try: try: server.starttls() except smtplib.SMTPException: log.info("smtp server does not support TLS") try: server.ehlo_or_helo_if_needed() server.authenticate(url, self.consumer, self.oauth_token) server.sendmail(from_, to_headers, msg.as_string()) except smtplib.SMTPRecipientsRefused, exc: server.save_capture("rejected recipients") for to_, err in exc.recipients.items(): error = { "provider": self.host, "message": err[1], "status": err[0] } break except smtplib.SMTPResponseException, exc: server.save_capture("smtp response exception") error = { "provider": self.host, "message": "%s: %s" % (exc.smtp_code, exc.smtp_error), "status": exc.smtp_code } except smtplib.SMTPException, exc: server.save_capture("smtp exception") error = {"provider": self.host, "message": str(exc)}
def sendmail(self, *args, **kw): SMTP.sendmail(self, *args, **kw) if asbool(config.get('protocol_capture_success')): self.save_capture("automatic success save")