Beispiel #1
0
    def _get(self, resource_url, params={}, data = {}):
        """
        Функція підписує заголовки, указані в SIGNATURE_HEADERS, і відправляє запит до вказаного API resource_url,
        передаючи серверу параметри із params
        Повертає словник в форматі json
        """

        auth = HTTPSignatureAuth(key_id = self.API_KEY,
                    secret = self.API_SECRET,
                    algorithm = 'hmac-sha256',
                    headers = SIGNATURE_HEADERS)

        # Відсилаємо запит до api, параметри кодуємо функцією urlencode.
        # Особливість urlencode - кодує значення somevar = None в строку "somevar=None", тому замінюємо всі None на пусті значення
        try:
            response = requests.get('%s/%s/?%s'%(self.API_URL, resource_url, urlencode(params).replace('None', '')),
                                    auth = auth,
                                    headers = self.HEADERS,
                                    data=json.dumps(data))
        except RequestException as error:
            raise APIGetError("Error, while loading data. %s"%error)

        # Якщо сервер повертає помилку, виводимо її
        # Формат відповіді сервера {'detail':'error message'}
        if not response.status_code in [requests.codes.OK, requests.codes.CREATED]:
            try:
                error = response.json().get('detail', '')
                raise APIGetError('Error, while loading data. %s'%error)
            # Якщо сервер не повернув помилку, як об’єкт json
            except ValueError:
                raise APIGetError('%s %s'%(response.status_code, response.reason))
        # Інакше повертаємо результат
        if response.text:
            return response.json()
        return {}
    def __init__(self, api_endpoint, api_key, api_secret, debug=False):
        """
        :param str      api_endpoint:   the base url to use for all API requests
        :param str      api_key:        the API_KEY to use for authentication
        :param str      api_secret:     the API_SECRET to use for authentication
        :param bool     debug:          print debug information when requests fail
        """
        self.api_endpoint = api_endpoint
        self.debug = debug

        # create a default User-Agent
        self.default_headers = {
            'User-Agent':
            "%s/%s" % (blocktrail.SDK_USER_AGENT, blocktrail.SDK_VERSION)
        }

        # api_key is always in the query string
        self.default_params = {'api_key': api_key}

        # prepare HTTP-Signature Auth signer
        self.auth = HTTPSignatureAuth(
            key_id=api_key,
            secret=api_secret,
            algorithm='hmac-sha256',
            headers=['(request-target)', 'Date', 'Content-MD5'])
Beispiel #3
0
    def logon(cls, username=None, password=None):
        config = ConfigDict("cloudmesh.yaml")
        cometConf = config["cloudmesh.comet"]
        cls.set_endpoint(cometConf["active"])
        cls.set_base_uri(cometConf["endpoints"][cls.endpoint]["nucleus_base_url"])
        cls.set_api_version(cometConf["endpoints"][cls.endpoint]["api_version"])
        cls.set_auth_provider()
        # print (cls.endpoint)
        # print (cls.base_uri)
        # print (cls.api_version)
        # print (cls.auth_provider)
        ret = False
        if "USERPASS" == cls.auth_provider:
            # for unit testing only.
            if username is None:
                username = cometConf["endpoints"][cls.endpoint]["userpass"]["username"]
                if username == '' or username == 'TBD':
                    username = cometConf["username"]
            if password is None:
                password = cometConf["endpoints"][cls.endpoint]["userpass"]["password"]
                if password.lower() == "readline":
                    password = getpass.getpass()
                elif password.lower() == "env":
                    password = os.environ.get("COMET_PASSWORD", getpass.getpass())

            if cls.token is None:
                if cls.auth_uri:
                    if cls.tunnelled:
                        authuri = "%s/login/" % cls.local_auth_uri
                    else:
                        authuri = "%s/login/" % cls.auth_uri
                    data = {"username": username, "password": password}
                    r = requests.post(authuri,
                                      data=json.dumps(data),
                                      headers=cls.HEADER,
                                      verify=cls.verify)
                    try:
                        cls.token = r.json()["key"]
                        cls.AUTH_HEADER['Authorization'] = "Token {:}".format(
                            cls.token)
                    except:
                        ret = False
                    ret = cls.token
            else:
                ret = cls.token
        elif "APIKEY" == cls.auth_provider:
            # print ("API KEY based auth goes here")
            cls.api_key = cometConf["endpoints"][cls.endpoint]["apikey"]["api_key"]
            cls.api_secret = cometConf["endpoints"][cls.endpoint]["apikey"]["api_secret"]
            cls.api_auth = HTTPSignatureAuth(secret=cls.api_secret, headers=["nonce", "timestamp"])
            #
            # api key based auth does not maintain a session
            # once values specified, considered as AuthNed.
            if cls.api_key and cls.api_secret and cls.api_auth:
                ret = True
        else:
            print("The specified AUTH Provider Not Currently Supported")
            pass
        return ret
Beispiel #4
0
 def _options(self, resource_url):
     auth = HTTPSignatureAuth(key_id = self.API_KEY,
                 secret = self.API_SECRET,
                 algorithm = 'hmac-sha256',
                 headers = SIGNATURE_HEADERS)
     try:
         response = requests.options('%s/%s/'%(self.API_URL, resource_url), auth = auth, headers = self.HEADERS)
     except RequestException as error:
         raise APIUploadError("Error, while loading data. %s"%error)
     return response.json()
Beispiel #5
0
    def __init__(self,
                 api_key,
                 api_secret,
                 app_id,
                 version='v1.0',
                 timeout=6.0,
                 base_url=None,
                 location=None):
        '''
        Initialize the client with the given api key and secret

        :param api_key: the api key
        :param api_secret: the api secret
        :param app_id: the app id

        **Example usage**::

            import stream
            # initialize the client
            client = stream.connect('key', 'secret')
            # get a feed object
            feed = client.feed('aggregated:1')
            # write data to the feed
            activity_data = {'actor': 1, 'verb': 'tweet', 'object': 1}
            activity_id = feed.add_activity(activity_data)['id']
            activities = feed.get()

            feed.follow('flat:3')
            activities = feed.get()
            feed.unfollow('flat:3')
            feed.remove_activity(activity_id)
        '''
        self.api_key = api_key
        self.api_secret = api_secret
        self.app_id = app_id
        self.version = version
        self.timeout = timeout
        self.location = location

        if os.environ.get('LOCAL'):
            self.base_url = 'http://localhost:8000/api/'
            self.timeout = 20
        elif base_url is not None:
            self.base_url = base_url
        elif location is not None:
            self.base_url = 'https://%s-api.getstream.io/api/' % location

        self.base_analytics_url = 'https://analytics.getstream.io/analytics/'

        self.session = requests.Session()
        # TODO: turn this back on after we verify it doesnt retry on slower requests
        self.session.mount(self.base_url, HTTPAdapter(max_retries=0))
        self.auth = HTTPSignatureAuth(api_key, secret=api_secret)
Beispiel #6
0
 def test_signed_request(self):
     signature_headers = ['(request-target)', 'accept', 'date', 'host']
     headers = {
         'Host': 'localhost:8000',
         'Accept': 'application/json',
         'Date': "Mon, 6 Jul 2020 10:11:00 GMT"
     }
     auth = HTTPSignatureAuth(key_id=KEY_ID,
                              secret=SECRET,
                              algorithm='rsa-sha256',
                              headers=signature_headers)
     data = {'auth': auth, 'headers': headers}
     response = self.client.get(
         'http://localhost:8000/api/premiumguapshit/', data, format='json')
     print(response.json())
     self.assertEqual(response.json()['status'], 'VIP')
Beispiel #7
0
    def _post(self, resource_url, params={}, data = {}, chunk = False):
        """
        Функція підписує заголовки, указані в SIGNATURE_HEADERS, і відправляє запит до вказаного API resource_url,
        передаючи серверу параметри із params
        Повертає словник в форматі json
        """
        signature_headers = ['accept', 'date', 'host', '(request-target)']
        headers = self.HEADERS
        headers['content-type'] = "application/json"
        auth = HTTPSignatureAuth(key_id = self.API_KEY,
                    secret = self.API_SECRET,
                    algorithm = 'hmac-sha256',
                    headers = signature_headers)

        # Відсилаємо запит до api, параметри кодуємо функцією urlencode.
        try:
            response = requests.post('%s/%s/'%(self.API_URL, resource_url), data = json.dumps(data),  auth = auth, headers = headers)
        except RequestException as error:
            raise APIUploadError("Error, while loading data. %s"%error)

        # Якщо сервер повертає помилку, виводимо її
        # Формат відповіді сервера {'detail':'error message'}
        if not response.status_code in [requests.codes.OK, requests.codes.CREATED]:
            try:
                error = response.json()
                print(error)
                # print error
                # Якщо data - це чанк, виду [obj, obj, ...]
                if chunk and isinstance(error, list):
                    # Вичисляємо список індексів елементів чанку, які викликали помилку
                    failed_elements = [error.index(x) for x in error if x!={}]
                    # Формуємо чанк, який не буде викликати помилку на сервері
                    data = [x for x in data if data.index(x) not in failed_elements]
                    # Відправляємо сформований чанк на сервер
                    requests.post('%s/%s/'%(API_URL, resource_url), data = json.dumps(data),  auth = auth, headers = headers)
                    # Повертаємо індекси невірних елементів, для подальшої обробки, або виводу користувачу
                    return failed_elements
                raise APIUploadError('Error, while loading data. %s'%str(error.get('detail', '')))
            # Якщо сервер не повернув помилку, як об’єкт json
            except ValueError:
                raise APIUploadError('%s %s'%(response.status_code, response.reason))
        # Інакше повертаємо результат
        if response.text and not chunk:
            return response.json()
        return {}
Beispiel #8
0
    def sign(self, headers: dict, body=None, more_sign_headers=None):
        now = gmt_time()

        # Add a request ID, if not any
        if 'X-Request-Id' not in headers:
            request_id = str(uuid.uuid4())
            headers['X-Request-Id'] = request_id

        # Add headers needed by HTTPSig
        headers['Date'] = now
        headers['Original-Date'] = now
        headers['Accept-Signature'] = self.algorithm

        # Which headers will be signed
        sign_headers = ['(request-target)', 'Host', 'Date', 'Original-Date', 'Digest', 'X-Request-Id']

        # Add other headers to sign the user might want to add
        if more_sign_headers:
            for h in more_sign_headers:
                if h not in sign_headers:
                    sign_headers.append(h)

        # Not sure if this is required, I think it is not on the draft, but
        # the lib we use from EWP requires a digest even if no body is passed
        if not body:
            body = "".encode('utf-8')

        # Calculate body digest, even if no body is passed
        if "Digest" not in sign_headers:
            sign_headers.append("Digest")
        digest = self._base64_digest(body)
        logging.debug("Digest: " + digest)
        headers["Digest"] = "SHA-256=" + digest

        logging.debug("Headers: " + str(headers))
        logging.debug("Sign-Headers: " + str(sign_headers))

        # Create the signature handler
        auth = HTTPSignatureAuth(key_id=self.key_id,
                                 #key=self.privkey,
                                 secret=self.privkey,
                                 algorithm=self.algorithm,
                                 headers=sign_headers)

        return {'auth': auth, 'headers': headers}
Beispiel #9
0
def send(activity, inbox_url, user_domain):
    """Sends an ActivityPub request to an inbox.

    Args:
      activity: dict, AS2 activity
      inbox_url: string
      user_domain: string, domain of the bridgy fed user sending the request

    Returns:
      requests.Response
    """
    logging.info(
        'Sending AP request from {user_domain}: {json_dumps(activity, indent=2)}'
    )

    # prepare HTTP Signature (required by Mastodon)
    # https://w3c.github.io/activitypub/#authorization
    # https://tools.ietf.org/html/draft-cavage-http-signatures-07
    # https://github.com/tootsuite/mastodon/issues/4906#issuecomment-328844846
    acct = 'acct:%s@%s' % (user_domain, user_domain)
    key = MagicKey.get_or_create(user_domain)
    auth = HTTPSignatureAuth(secret=key.private_pem(),
                             key_id=acct,
                             algorithm='rsa-sha256',
                             sign_header='signature',
                             headers=('Date', 'Digest', 'Host'))

    # deliver to inbox
    body = json_dumps(activity).encode()
    headers = {
        'Content-Type': common.CONTENT_TYPE_AS2,
        # required for HTTP Signature
        # https://tools.ietf.org/html/draft-cavage-http-signatures-07#section-2.1.3
        'Date':
        datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT'),
        # required by Mastodon
        # https://github.com/tootsuite/mastodon/pull/14556#issuecomment-674077648
        'Digest': 'SHA-256=' + b64encode(sha256(body).digest()).decode(),
        'Host': util.domain_from_link(inbox_url),
    }
    return common.requests_post(inbox_url,
                                data=body,
                                auth=auth,
                                headers=headers)
Beispiel #10
0
    def _put(self, resource_url, params={}, data={}):
        """
        Функція підписує заголовки, указані в SIGNATURE_HEADERS, і відправляє запит до вказаного API resource_url,
        передаючи серверу параметри із params
        Повертає словник в форматі json
        """

        auth = HTTPSignatureAuth(key_id=self.API_KEY,
                                 secret=self.API_SECRET,
                                 algorithm='hmac-sha256',
                                 headers=SIGNATURE_HEADERS)

        # Відсилаємо запит до api, параметри кодуємо функцією urlencode.
        try:
            response = requests.put('%s/%s/' % (API_URL, resource_url),
                                    params=params,
                                    data=json.dumps(data),
                                    auth=auth,
                                    headers=HEADERS)
        except RequestException, error:
            raise APIUploadError("Error, while loading data. %s" % error)
Beispiel #11
0
    def _get(self, resource_url, params={}, data={}):
        """
        Функція підписує заголовки, указані в SIGNATURE_HEADERS, і відправляє запит до вказаного API resource_url,
        передаючи серверу параметри із params
        Повертає словник в форматі json
        """

        auth = HTTPSignatureAuth(key_id=self.API_KEY,
                                 secret=self.API_SECRET,
                                 algorithm='hmac-sha256',
                                 headers=SIGNATURE_HEADERS)

        # Відсилаємо запит до api, параметри кодуємо функцією urlencode.
        # Особливість urlencode - кодує значення somevar = None в строку "somevar=None", тому замінюємо всі None на пусті значення
        try:
            response = requests.get(
                '%s/%s/?%s' % (API_URL, resource_url,
                               urllib.urlencode(params).replace('None', '')),
                auth=auth,
                headers=HEADERS,
                data=json.dumps(data))
        except RequestException, error:
            raise APIGetError("Error, while loading data. %s" % error)
Beispiel #12
0
def send(activity, inbox_url, user_domain):
    """Sends an ActivityPub request to an inbox.

    Args:
      activity: dict, AS2 activity
      inbox_url: string
      user_domain: string, domain of the bridgy fed user sending the request

    Returns:
      requests.Response
    """
    logging.info('Sending AP request from %s: %s', user_domain,
                 json.dumps(activity, indent=2))

    # prepare HTTP Signature (required by Mastodon)
    # https://w3c.github.io/activitypub/#authorization-lds
    # https://tools.ietf.org/html/draft-cavage-http-signatures-07
    # https://github.com/tootsuite/mastodon/issues/4906#issuecomment-328844846
    acct = 'acct:%s@%s' % (user_domain, user_domain)
    key = MagicKey.get_or_create(user_domain)
    auth = HTTPSignatureAuth(secret=key.private_pem(),
                             key_id=acct,
                             algorithm='rsa-sha256')

    # deliver to inbox
    headers = {
        'Content-Type': common.CONTENT_TYPE_AS2,
        # required for HTTP Signature
        # https://tools.ietf.org/html/draft-cavage-http-signatures-07#section-2.1.3
        'Date':
        datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT'),
    }
    return common.requests_post(inbox_url,
                                json=activity,
                                auth=auth,
                                headers=headers)
Beispiel #13
0
    def try_activitypub(self):
        source = util.get_required_param(self, 'source')

        # fetch source page, convert to ActivityStreams
        source_resp = common.requests_get(source)
        source_url = source_resp.url or source
        source_mf2 = mf2py.parse(source_resp.text, url=source_url)
        # logging.debug('Parsed mf2 for %s: %s', source_resp.url, json.dumps(source_mf2, indent=2))

        entry = mf2util.find_first_entry(source_mf2, ['h-entry'])
        logging.info('First entry: %s', json.dumps(entry, indent=2))
        # make sure it has url, since we use that for AS2 id, which is required
        # for ActivityPub.
        props = entry.setdefault('properties', {})
        if not props.get('url'):
            props['url'] = [source_url]

        source_obj = microformats2.json_to_object(entry, fetch_mf2=True)
        logging.info('Converted to AS: %s', json.dumps(source_obj, indent=2))

        # fetch target page as AS object. target is first in-reply-to, like-of,
        # or repost-of, *not* target query param.)
        target = util.get_url(util.get_first(source_obj, 'inReplyTo') or
                              util.get_first(source_obj, 'object'))
        if not target:
            common.error(self, 'No u-in-reply-to, u-like-of, or u-repost-of '
                         'found in %s' % source_url)

        try:
            target_resp = common.get_as2(target)
        except (requests.HTTPError, exc.HTTPBadGateway) as e:
            if (e.response.status_code // 100 == 2 and
                common.content_type(e.response).startswith('text/html')):
                self.resp = Response.get_or_create(
                    source=source_url, target=e.response.url or target,
                    direction='out', source_mf2=json.dumps(source_mf2))
                return self.send_salmon(source_obj, target_resp=e.response)
            raise

        target_url = target_resp.url or target
        self.resp = Response.get_or_create(
            source=source_url, target=target_url, direction='out',
            protocol='activitypub', source_mf2=json.dumps(source_mf2))

        # find actor's inbox
        target_obj = target_resp.json()
        inbox_url = target_obj.get('inbox')

        if not inbox_url:
            # TODO: test actor/attributedTo and not, with/without inbox
            actor = target_obj.get('actor') or target_obj.get('attributedTo')
            if isinstance(actor, dict):
                inbox_url = actor.get('inbox')
                actor = actor.get('url')
            if not inbox_url and not actor:
                common.error(self, 'Target object has no actor or attributedTo URL')

        if not inbox_url:
            # fetch actor as AS object
            actor = common.get_as2(actor).json()
            inbox_url = actor.get('inbox')

        if not inbox_url:
            # TODO: probably need a way to save errors like this so that we can
            # return them if ostatus fails too.
            # common.error(self, 'Target actor has no inbox')
            return self.send_salmon(source_obj, target_resp=target_resp)

        # convert to AS2
        source_domain = urlparse.urlparse(source_url).netloc
        key = MagicKey.get_or_create(source_domain)
        source_activity = common.postprocess_as2(
            as2.from_as1(source_obj), target=target_obj, key=key)

        if self.resp.status == 'complete':
            source_activity['type'] = 'Update'

        # prepare HTTP Signature (required by Mastodon)
        # https://w3c.github.io/activitypub/#authorization-lds
        # https://tools.ietf.org/html/draft-cavage-http-signatures-07
        # https://github.com/tootsuite/mastodon/issues/4906#issuecomment-328844846
        acct = 'acct:%s@%s' % (source_domain, source_domain)
        auth = HTTPSignatureAuth(secret=key.private_pem(), key_id=acct,
                                 algorithm='rsa-sha256')

        # deliver source object to target actor's inbox.
        headers = {
            'Content-Type': common.CONTENT_TYPE_AS2,
            # required for HTTP Signature
            # https://tools.ietf.org/html/draft-cavage-http-signatures-07#section-2.1.3
            'Date': datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT'),
        }
        inbox_url = urlparse.urljoin(target_url, inbox_url)
        resp = common.requests_post(inbox_url, json=source_activity, auth=auth,
                                    headers=headers)
        self.response.status_int = resp.status_code
        if resp.status_code == 202:
            self.response.write('202 response! If this is Mastodon 1.x, their '
                                'signature verification probably failed. :(\n')
        self.response.write(resp.text)
Beispiel #14
0
"""

import json
import logging
from datetime import datetime
from time import mktime
from wsgiref.handlers import format_date_time

import requests
from django.conf import settings
from httpsig.requests_auth import HTTPSignatureAuth

logger = logging.getLogger(__name__)

_httpsig_auth = HTTPSignatureAuth(key_id=settings.ORCHESTRA_PROJECT_API_KEY,
                                  secret=settings.ORCHESTRA_PROJECT_API_SECRET,
                                  algorithm='hmac-sha256')
_api_root_url = '{}/orchestra/api/project/'.format(settings.ORCHESTRA_URL)


class OrchestraError(Exception):
    pass


def _make_api_request(method, endpoint, *args, **kwargs):
    func = getattr(requests, method)
    # Adding 'date' header as per
    # https://github.com/zzsnzmn/py-http-signature/blob/e2e2c753db7da45fab4b215d84e8d490bd708833/http_signature/sign.py#L155  # noqa
    headers = {
        'date': format_date_time(mktime(datetime.now().timetuple())),
        'X-Api-Version': '~6.5',
 def auth():
     auth = HTTPSignatureAuth(key_id=ApiAuthentication.access_key_id(),
                              secret=ApiAuthentication.secret_access_key(),
                              algorithm='hmac-sha256',
                              headers=ApiAuthentication.signature_headers())
     return auth