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 = {}
Example #2
0
    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
Example #5
0
    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)
Example #6
0
 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
Example #7
0
    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)
Example #8
0
    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)}
Example #9
0
 def sendmail(self, *args, **kw):
     SMTP.sendmail(self, *args, **kw)
     if asbool(config.get('protocol_capture_success')):
         self.save_capture("automatic success save")