Exemple #1
0
  def get(self):
    parts = self.decode_state_parameter(util.get_required_param(self, 'state'))
    callback = parts and parts.get('callback')

    if self.request.get('declined'):
      if callback:
        # disable declined means no change took place
        callback = util.add_query_params(callback, {'result': 'declined'})
      else:
        self.messages.add('If you want to disable, please approve the prompt.')
      self.redirect(callback.encode('utf-8') if callback else '/')
      return

    if (not parts or 'feature' not in parts or 'source' not in parts):
      self.abort(400, 'state query parameter must include "feature" and "source"')

    feature = parts['feature']
    if feature not in (Source.FEATURES):
      self.abort(400, 'cannot delete unknown feature %s' % feature)

    logged_in_as = ndb.Key(
      urlsafe=util.get_required_param(self, 'auth_entity')).get()
    source = ndb.Key(urlsafe=parts['source']).get()

    if logged_in_as and logged_in_as.is_authority_for(source.auth_entity):
      # TODO: remove credentials
      if feature in source.features:
        source.features.remove(feature)
        source.put()
      noun = 'webmentions' if feature == 'webmention' else feature + 'ing'
      if callback:
        callback = util.add_query_params(callback, {
          'result': 'success',
          'user': source.bridgy_url(self),
          'key': source.key.urlsafe(),
        })
      else:
        self.messages.add('Disabled %s for %s. Sorry to see you go!' %
                          (noun, source.label()))
      # util.email_me(subject='Deleted Bridgy %s user: %s %s' %
      #               (feature, source.label(), source.key.string_id()),
      #               body=source.bridgy_url(self))
    else:
      if callback:
        callback = util.add_query_params(callback, {'result': 'failure'})
      else:
        self.messages.add('Please log into %s as %s to disable it here.' %
                          (source.GR_CLASS.NAME, source.name))

    self.redirect(callback.encode('utf-8') if callback
                  else source.bridgy_url(self) if source.features
                  else '/')
Exemple #2
0
  def new(handler, auth_entity=None, **kwargs):
    """Creates and returns a GooglePlusPage for the logged in user.

    Args:
      handler: the current RequestHandler
      auth_entity: oauth_dropins.googleplus.GooglePlusAuth
    """
    # Google+ Person resource
    # https://developers.google.com/+/api/latest/people#resource
    user = json.loads(auth_entity.user_json)
    type = 'user' if user.get('objectType', 'person') == 'person' else 'page'

    # override the sz param to ask for a 128x128 image. if there's an existing
    # sz query param (there usually is), the new one will come afterward and
    # override it.
    picture = user.get('image', {}).get('url')
    picture = util.add_query_params(picture, {'sz': '128'})

    return GooglePlusPage(id=user['id'],
                          auth_entity=auth_entity.key,
                          url=user.get('url'),
                          name=user.get('displayName'),
                          picture=picture,
                          type=type,
                          **kwargs)
Exemple #3
0
    def new(handler, auth_entity=None, **kwargs):
        """Creates and returns a GooglePlusPage for the logged in user.

    Args:
      handler: the current RequestHandler
      auth_entity: oauth_dropins.googleplus.GooglePlusAuth
    """
        # Google+ Person resource
        # https://developers.google.com/+/api/latest/people#resource
        user = json.loads(auth_entity.user_json)
        type = "user" if user.get("objectType", "person") == "person" else "page"

        # override the sz param to ask for a 128x128 image. if there's an existing
        # sz query param (there usually is), the new one will come afterward and
        # override it.
        picture = user.get("image", {}).get("url")
        picture = util.add_query_params(picture, {"sz": "128"})

        return GooglePlusPage(
            id=user["id"],
            auth_entity=auth_entity.key,
            url=user.get("url"),
            name=user.get("displayName"),
            picture=picture,
            type=type,
            **kwargs
        )
Exemple #4
0
    def new(handler, auth_entity=None, **kwargs):
        """Creates and returns a :class:`GooglePlusPage` for the logged in user.

    Args:
      handler: the current :class:`webapp2.RequestHandler`
      auth_entity: :class:`oauth_dropins.googleplus.GooglePlusAuth`
    """
        # Google+ Person resource
        # https://developers.google.com/+/api/latest/people#resource
        user = json.loads(auth_entity.user_json)
        type = 'user' if user.get('objectType',
                                  'person') == 'person' else 'page'

        # override the sz param to ask for a 128x128 image. if there's an existing
        # sz query param (there usually is), the new one will come afterward and
        # override it.
        picture = user.get('image', {}).get('url')
        picture = util.add_query_params(picture, {'sz': '128'})

        return GooglePlusPage(id=user['id'],
                              auth_entity=auth_entity.key,
                              url=user.get('url'),
                              name=user.get('displayName'),
                              picture=picture,
                              type=type,
                              **kwargs)
Exemple #5
0
  def finish(self, auth_entity, state=None):
    if 'target_url' in self.decode_state_parameter(state):
      # this is an interactive publish
      return self.redirect(util.add_query_params(
        '/publish/instagram/finish',
        util.trim_nulls({'auth_entity': auth_entity.key.urlsafe(), 'state': state})))

    self.maybe_add_or_delete_source(Instagram, auth_entity, state)
Exemple #6
0
  def test_add_query_param(self):
    for expected, url, params in (
      ('http://a.com?x=', 'http://a.com', [('x', '')]),
      ('http://a.com?x=y', 'http://a.com', [('x', 'y')]),
      ('http://a.com?x=y&u=v', 'http://a.com', [('x', 'y'), ('u', 'v')]),
      ('http://a.com?x=y&u=v', 'http://a.com?x=y', [('u', 'v')]),
      ('http://a.com?x=y&u=v', 'http://a.com?x=y', [('u', 'v')]),
      ('http://a.com?x=y&x=z', 'http://a.com', [('x', 'y'), ('x', 'z')]),
      ('http://a.com?x=y&x=z&x=w', 'http://a.com?x=y&x=z', [('x', 'w')]),
      ('http://a.com?x=y', 'http://a.com', {'x': 'y'}),
      # note encoding declaration at top of file
      ('http://a.com?x=R+%C3%87', 'http://a.com', {'x': u'R Ç'}),
      ('http://a.com?x=R+%C3%87&x=R+%C3%87', 'http://a.com?x=R+%C3%87', {'x': u'R Ç'}),
      ):
      self.assertEqual(expected, util.add_query_params(url, params))

    for expected, req, params in (
      (urllib2.Request('http://a.com?x=y'), urllib2.Request('http://a.com'),
       [('x', 'y')]),
      (urllib2.Request('http://a.com?x=y&u=v'), urllib2.Request('http://a.com?x=y'),
       [('u', 'v')]),
      (urllib2.Request('http://a.com?x=y', data='my data', headers={'X': 'Y'}),
       urllib2.Request('http://a.com', data='my data', headers={'X': 'Y'}),
       [('x', 'y')]),
      ):
      actual = util.add_query_params(req, params)
      self.assertIsInstance(actual, urllib2.Request)
      self.assertEqual(expected.get_full_url(), actual.get_full_url())
      self.assertEqual(expected.get_data(), actual.get_data())
      self.assertEqual(expected.headers, actual.headers)

    query_string = ''
    for i in range(2):
      query_string = util.add_query_params(query_string, {'x': u'Ryan Çelik'})
      for key, val in urlparse.parse_qsl(query_string[1:]):
        self.assertEquals('x', key)
        self.assertEquals(u'Ryan Çelik', val.decode('utf-8'))
Exemple #7
0
  def test_add_query_param(self):
    for expected, url, params in (
      ('http://a.com?x=', 'http://a.com', [('x', '')]),
      ('http://a.com?x=y', 'http://a.com', [('x', 'y')]),
      ('http://a.com?x=y&u=v', 'http://a.com', [('x', 'y'), ('u', 'v')]),
      ('http://a.com?x=y&u=v', 'http://a.com?x=y', [('u', 'v')]),
      ('http://a.com?x=y&u=v', 'http://a.com?x=y', [('u', 'v')]),
      ('http://a.com?x=y&x=z', 'http://a.com', [('x', 'y'), ('x', 'z')]),
      ('http://a.com?x=y&x=z&x=w', 'http://a.com?x=y&x=z', [('x', 'w')]),
      ('http://a.com?x=y', 'http://a.com', {'x': 'y'}),
      # note encoding declaration at top of file
      ('http://a.com?x=R+%C3%87', 'http://a.com', {'x': u'R Ç'}),
      ('http://a.com?x=R+%C3%87&x=R+%C3%87', 'http://a.com?x=R+%C3%87', {'x': u'R Ç'}),
      ):
      self.assertEqual(expected, util.add_query_params(url, params))

    for expected, req, params in (
      (urllib2.Request('http://a.com?x=y'), urllib2.Request('http://a.com'),
       [('x', 'y')]),
      (urllib2.Request('http://a.com?x=y&u=v'), urllib2.Request('http://a.com?x=y'),
       [('u', 'v')]),
      (urllib2.Request('http://a.com?x=y', data='my data', headers={'X': 'Y'}),
       urllib2.Request('http://a.com', data='my data', headers={'X': 'Y'}),
       [('x', 'y')]),
      ):
      actual = util.add_query_params(req, params)
      self.assertIsInstance(actual, urllib2.Request)
      self.assertEqual(expected.get_full_url(), actual.get_full_url())
      self.assertEqual(expected.get_data(), actual.get_data())
      self.assertEqual(expected.headers, actual.headers)

    query_string = ''
    for i in range(2):
      query_string = util.add_query_params(query_string, {'x': u'Ryan Çelik'})
      for key, val in urlparse.parse_qsl(query_string[1:]):
        self.assertEquals('x', key)
        self.assertEquals(u'Ryan Çelik', val.decode('utf-8'))
Exemple #8
0
 def get(self, feature):
   """Redirect to the front page."""
   self.redirect(util.add_query_params('/', self.request.params.items()),
                 permanent=True)
Exemple #9
0
  def get(self):
    parts = self.decode_state_parameter(self.request.get('state') or '')
    callback = parts and parts.get('callback')

    if self.request.get('declined'):
      # disable declined means no change took place
      if callback:
        callback = util.add_query_params(callback, {'result': 'declined'})
        self.redirect(callback.encode('utf-8'))
      else:
        self.messages.add('If you want to disable, please approve the prompt.')
        self.redirect('/')
      return

    if (not parts or 'feature' not in parts or 'source' not in parts):
      self.abort(400, 'state query parameter must include "feature" and "source"')

    feature = parts['feature']
    if feature not in (Source.FEATURES):
      self.abort(400, 'cannot delete unknown feature %s' % feature)

    logged_in_as = ndb.Key(
      urlsafe=util.get_required_param(self, 'auth_entity')).get()
    source = ndb.Key(urlsafe=parts['source']).get()

    if logged_in_as and logged_in_as.is_authority_for(source.auth_entity):
      # TODO: remove credentials
      if feature in source.features:
        source.features.remove(feature)
        source.put()

        # remove login cookie
        logins = self.get_logins()
        login = util.Login(path=source.bridgy_path(), site=source.SHORT_NAME,
                           name=source.label_name())
        if login in logins:
          logins.remove(login)
          self.set_logins(logins)

      noun = 'webmentions' if feature == 'webmention' else feature + 'ing'
      if callback:
        callback = util.add_query_params(callback, {
          'result': 'success',
          'user': source.bridgy_url(self),
          'key': source.key.urlsafe(),
        })
      else:
        self.messages.add('Disabled %s for %s. Sorry to see you go!' %
                          (noun, source.label()))
      # util.email_me(subject='Deleted Bridgy %s user: %s %s' %
      #               (feature, source.label(), source.key.string_id()),
      #               body=source.bridgy_url(self))
    else:
      if callback:
        callback = util.add_query_params(callback, {'result': 'failure'})
      else:
        self.messages.add('Please log into %s as %s to disable it here.' %
                          (source.GR_CLASS.NAME, source.name))

    self.redirect(callback.encode('utf-8') if callback
                  else source.bridgy_url(self) if source.features
                  else '/')
Exemple #10
0
 def get(self, feature):
   """Redirect to the front page."""
   self.redirect(util.add_query_params('/', self.request.params.items()),
                 permanent=True)
Exemple #11
0
  def test_live(self):
    # sign up (use the form inputs in our actual HTML template)
    with open('templates/facebook_signup.html') as f:
      resp = self.submit_form(f.read())

    self.assertEqual(302, resp.status_int)
    to = resp.headers['Location']
    self.assertTrue(to.startswith('https://www.facebook.com/v2.6/dialog/oauth?'), to)
    redirect = urlparse.parse_qs(urlparse.urlparse(to).query)['redirect_uri'][0]
    self.dot()

    # pretend the user approves the prompt and facebook redirects back to us.
    # mock out the access token request since we use a canned token.
    self.expect_urlopen(oauth_facebook.GET_ACCESS_TOKEN_URL % {
        'client_id': appengine_config.FACEBOOK_APP_ID,
        'client_secret': appengine_config.FACEBOOK_APP_SECRET,
        'redirect_uri': urllib.quote_plus(redirect),
        'auth_code': 'fake_code',
      },
      '{"access_token": "%s"}' % appengine_config.FACEBOOK_TEST_USER_TOKEN,
      ).WithSideEffects(lambda *args, **kwargs: self.mox.stubs.UnsetAll())
    self.mox.ReplayAll()

    resp = facebook.application.get_response(
      util.add_query_params(redirect, {'code': 'fake_code'}))
    self.assertEqual(302, resp.status_int)
    source = facebook.FacebookPage.get_by_id(TEST_USER_ID)
    self.assertEqual('enabled', source.status)
    self.assertEqual(['listen'], source.features)
    self.dot()

    # ignore all domains except example.zz
    util.in_webmention_blacklist = lambda domain: domain != 'example.zz'

    # poll
    self.stub_requests_head()
    resp = self.run_task(self.taskqueue_stub.GetTasks('poll')[0])
    self.assertEqual(200, resp.status_int)
    self.dot()

    # three propagates, one for the like and one for each comment
    source_urls = []

    def handle_post_body(params):
      self.assertEqual('http://example.zz/abc', params['target'])
      source_urls.append(params['source'])
      return True

    self.mox.StubOutWithMock(requests, 'post', use_mock_anything=True)
    self.expect_requests_post(
      'http://example.zz/wm', timeout=mox.IgnoreArg(), verify=mox.IgnoreArg(),
      data=mox.Func(handle_post_body)
      ).MultipleTimes()
    self.mox.ReplayAll()

    memcache.set('W http example.zz', 'http://example.zz/wm')
    for task in self.taskqueue_stub.GetTasks('propagate'):
      resp = self.run_task(task)
      self.assertEqual(200, resp.status_int)

    self.mox.stubs.UnsetAll()
    self.dot()

    # fetch the response handler URLs
    for url in source_urls:
      resp = handlers.application.get_response(url)
      self.assertEqual(200, resp.status_int)
      self.dot()
Exemple #12
0
  def test_live(self):
    # sign up (use the form inputs in our actual HTML template)
    with open('templates/facebook_signup.html') as f:
      resp = self.submit_form(f.read())

    self.assertEqual(302, resp.status_int)
    to = resp.headers['Location']
    self.assertTrue(to.startswith('https://www.facebook.com/v2.10/dialog/oauth?'), to)
    params = urlparse.parse_qs(urlparse.urlparse(to).query)
    redirect = params['redirect_uri'][0]
    state = params['state'][0]
    self.dot()

    # pretend the user approves the prompt and facebook redirects back to us.
    # mock out the access token request since we use a canned token.
    self.expect_urlopen(oauth_facebook.GET_ACCESS_TOKEN_URL % {
        'client_id': appengine_config.FACEBOOK_APP_ID,
        'client_secret': appengine_config.FACEBOOK_APP_SECRET,
        'redirect_uri': urllib.quote_plus(redirect),
        'auth_code': 'fake_code',
      },
      '{"access_token": "%s"}' % appengine_config.FACEBOOK_TEST_USER_TOKEN,
    ).WithSideEffects(lambda *args, **kwargs: self.mox.stubs.UnsetAll())
    self.mox.ReplayAll()

    resp = facebook.application.get_response(
      util.add_query_params(redirect, {
        'code': 'fake_code',
        'state': urllib.unquote(state),
      }))
    self.assertEqual(302, resp.status_int)
    source = facebook.FacebookPage.get_by_id(TEST_USER_ID)
    self.assertEqual('enabled', source.status)
    self.assertEqual(['listen'], source.features)
    self.dot()

    # ignore all domains except example.zz
    util.in_webmention_blacklist = lambda domain: domain != 'example.zz'

    # poll
    self.stub_requests_head()
    resp = self.run_task(self.taskqueue_stub.GetTasks('poll')[0])
    self.assertEqual(200, resp.status_int)
    self.dot()

    # three propagates, one for the like and one for each comment
    source_urls = []

    def handle_post_body(params):
      self.assertEqual('http://example.zz/abc', params['target'])
      source_urls.append(params['source'])
      return True

    self.mox.StubOutWithMock(requests, 'post', use_mock_anything=True)
    self.expect_requests_post(
      'http://example.zz/wm', timeout=mox.IgnoreArg(), verify=mox.IgnoreArg(),
      data=mox.Func(handle_post_body), allow_redirects=False,
      headers={'Accept': '*/*'}).MultipleTimes()
    self.mox.ReplayAll()

    memcache.set('W http example.zz', 'http://example.zz/wm')
    for task in self.taskqueue_stub.GetTasks('propagate'):
      resp = self.run_task(task)
      self.assertEqual(200, resp.status_int)

    self.mox.stubs.UnsetAll()
    self.dot()

    # fetch the response handler URLs
    for url in source_urls:
      resp = handlers.application.get_response(url)
      self.assertEqual(200, resp.status_int)
      self.dot()
Exemple #13
0
def redirect_to_front_page(_):
    """Redirect to the front page."""
    return redirect(util.add_query_params('/', request.values.items()),
                    code=301)
Exemple #14
0
def delete_finish():
    parts = util.decode_oauth_state(request.values.get('state') or '')
    callback = parts and parts.get('callback')

    if request.values.get('declined'):
        # disable declined means no change took place
        if callback:
            callback = util.add_query_params(callback, {'result': 'declined'})
            return redirect(callback)
        else:
            flash('If you want to disable, please approve the prompt.')
            return redirect('/')
        return

    if not parts or 'feature' not in parts or 'source' not in parts:
        error('state query parameter must include "feature" and "source"')

    feature = parts['feature']
    if feature not in (Source.FEATURES):
        error(f'cannot delete unknown feature {feature}')

    logged_in_as = ndb.Key(urlsafe=request.args['auth_entity']).get()
    source = ndb.Key(urlsafe=parts['source']).get()

    logins = None
    if logged_in_as and logged_in_as.is_authority_for(source.auth_entity):
        # TODO: remove credentials
        if feature in source.features:
            source.features.remove(feature)
            source.put()

            # remove login cookie
            logins = util.get_logins()
            login = util.Login(path=source.bridgy_path(),
                               site=source.SHORT_NAME,
                               name=source.label_name())
            if login in logins:
                logins.remove(login)

        if callback:
            callback = util.add_query_params(
                callback, {
                    'result': 'success',
                    'user': source.bridgy_url(),
                    'key': source.key.urlsafe().decode(),
                })
        else:
            nouns = {
                'webmention': 'webmentions',
                'listen': 'backfeed',
                'publish': 'publishing',
            }
            msg = f'Disabled {nouns[feature]} for {source.label()}.'
            if not source.features:
                msg += ' Sorry to see you go!'
            flash(msg)
    elif callback:
        callback = util.add_query_params(callback, {'result': 'failure'})
    else:
        flash(
            f'Please log into {source.GR_CLASS.NAME} as {source.name} to disable it here.'
        )

    url = callback if callback else source.bridgy_url(
    ) if source.features else '/'
    return redirect(url, logins=logins)