async def test_negative_timestamp(self):

        signing_key = TEST_PRIVATE_KEY
        timestamp = int(time.time())
        signature = sign_request(signing_key, "GET", "/", timestamp, None)

        resp = await self.fetch_signed("/",
                                       method="GET",
                                       address=TEST_ADDRESS,
                                       timestamp=timestamp,
                                       signature=signature)

        self.assertResponseCodeEqual(resp, 204)

        # try replay simply changing the timestamp to negative
        timestamp = -timestamp
        resp = await self.fetch_signed("/",
                                       method="GET",
                                       address=TEST_ADDRESS,
                                       timestamp=timestamp,
                                       signature=signature)

        self.assertResponseCodeEqual(resp, 400)

        # sign with negative timestamp
        signature = sign_request(signing_key, "GET", "/", timestamp, None)
        resp = await self.fetch_signed("/",
                                       method="GET",
                                       address=TEST_ADDRESS,
                                       timestamp=timestamp,
                                       signature=signature)

        self.assertResponseCodeEqual(resp, 400)
    async def test_transactions_with_known_sender_token_id_but_invalid_signature(
            self):

        body = {"from": FAUCET_ADDRESS, "to": TEST_ADDRESS, "value": 10**10}

        resp = await self.fetch("/tx/skel", method="POST", body=body)

        self.assertEqual(resp.code, 200)

        tx = sign_transaction(json_decode(resp.body)['tx'], FAUCET_PRIVATE_KEY)

        body = {"tx": tx}

        timestamp = int(time.time())
        signature = sign_request(FAUCET_PRIVATE_KEY, "POST", "/v1/tx",
                                 timestamp,
                                 json_encode(body).encode('utf-8'))

        resp = await self.fetch_signed("/tx",
                                       method="POST",
                                       body=body,
                                       address=TEST_ADDRESS_2,
                                       signature=signature,
                                       timestamp=timestamp)

        self.assertEqual(resp.code, 400, resp.body)
        self.assertIsNotNone(resp.body)
        error = json_decode(resp.body)
        self.assertIn('errors', error)
        self.assertEqual(len(error['errors']), 1)
    async def test_invalid_signature_in_deregistration(self):

        async with self.pool.acquire() as con:

            await con.fetchrow("INSERT INTO notification_registrations VALUES ($1, $2)",
                               TEST_ID_ADDRESS, TEST_WALLET_ADDRESS)

        body = {
            "addresses": [TEST_ID_ADDRESS, TEST_WALLET_ADDRESS]
        }

        timestamp = int(time.time())
        signature = sign_request(FAUCET_PRIVATE_KEY, "POST", "/v1/deregister", timestamp, json_encode(body).encode('utf-8'))

        resp = await self.fetch_signed("/deregister", method="POST", body=body,
                                       address=TEST_ID_ADDRESS, signature=signature, timestamp=timestamp)

        self.assertEqual(resp.code, 400, resp.body)

        async with self.pool.acquire() as con:

            rows = await con.fetch("SELECT * FROM notification_registrations WHERE token_id = $1", TEST_ID_ADDRESS)

        self.assertIsNotNone(rows)
        self.assertEqual(len(rows), 1)
    async def test_urlencoded_data(self):

        # generate random 2048 byte "file"
        filedata = os.urandom(2048)

        content_type, body = encode_multipart_formdata(
            [], [("file", "test.bin", filedata)])
        headers = {
            "Content-Type": content_type,
            'content-length': str(len(body))
        }

        timestamp = int(time.time())
        signature = sign_request(TEST_PRIVATE_KEY, "POST", "/", timestamp,
                                 body)

        resp = await self.fetch_signed("/",
                                       method="POST",
                                       body=body,
                                       headers=headers,
                                       signature=signature,
                                       timestamp=timestamp,
                                       address=TEST_ADDRESS)

        self.assertResponseCodeEqual(resp, 204)
示例#5
0
    async def test_invalid_signature_in_pn_registration(self):

        body = {
            "registration_id": TEST_APN_ID,
        }

        timestamp = int(time.time())
        signature = sign_request(FAUCET_PRIVATE_KEY, "POST",
                                 "/v1/apn/register", timestamp,
                                 json_encode(body).encode('utf-8'))

        resp = await self.fetch_signed("/apn/register",
                                       method="POST",
                                       body=body,
                                       signature=signature,
                                       address=TEST_ADDRESS,
                                       timestamp=timestamp)

        self.assertEqual(resp.code, 400, resp.body)

        async with self.pool.acquire() as con:

            rows = await con.fetch(
                "SELECT * FROM push_notification_registrations WHERE token_id = $1",
                TEST_ADDRESS)

        self.assertIsNotNone(rows)
        self.assertEqual(len(rows), 0)
    async def test_query_argument_fetch(self):

        signing_key = TEST_PRIVATE_KEY
        address = TEST_ADDRESS
        timestamp = int(time.time())
        signature = sign_request(signing_key, "GET", "/", timestamp, None)

        resp = await self.fetch("/?{}".format(
            generate_query_args(signature=signature,
                                address=address,
                                timestamp=timestamp)))

        self.assertResponseCodeEqual(resp, 204)
    def __call__(self, r):

        method = r.method
        path = "/{}".format(r.url.split('/', 3)[-1])
        body = r.body

        timestamp = int(time.time())

        signature = sign_request(self.signing_key, method, path, timestamp, body)

        r.headers[TOKEN_ID_ADDRESS_HEADER] = self.address
        r.headers[TOKEN_SIGNATURE_HEADER] = signature
        r.headers[TOKEN_TIMESTAMP_HEADER] = str(timestamp)

        return r
    async def test_wrong_address(self):

        timestamp = int(time.time())
        body = {"payment_address": TEST_PAYMENT_ADDRESS}
        signature = sign_request(TEST_PRIVATE_KEY, "POST", "/v1/user",
                                 timestamp, body)
        address = "{}00000".format(TEST_ADDRESS[:-5])

        resp = await self.fetch_signed("/user",
                                       method="POST",
                                       timestamp=timestamp,
                                       address=address,
                                       signature=signature,
                                       body=body)

        self.assertResponseCodeEqual(resp, 400, resp.body)
示例#9
0
    async def connect(self):

        # find out if there's a path prefix added by get_url
        path = "/{}".format(self.url.split('/', 3)[-1])

        address = private_key_to_address(self.signing_key)
        timestamp = int(time.time())
        signature = sign_request(self.signing_key, "GET", path, timestamp,
                                 None)

        request = tornado.httpclient.HTTPRequest(self.url,
                                                 headers={
                                                     TOKEN_ID_ADDRESS_HEADER:
                                                     address,
                                                     TOKEN_SIGNATURE_HEADER:
                                                     signature,
                                                     TOKEN_TIMESTAMP_HEADER:
                                                     str(timestamp)
                                                 })

        self.con = await tornado.websocket.websocket_connect(request)
        return self.con
    async def test_invalid_signature(self):

        body = {"registration_id": "1234567890"}

        timestamp = int(time.time())
        signature = sign_request(FAUCET_PRIVATE_KEY, "POST", "/", timestamp,
                                 json_encode(body).encode('utf-8'))

        resp = await self.fetch_signed("/",
                                       method="POST",
                                       body=body,
                                       address=TEST_ADDRESS,
                                       timestamp=timestamp,
                                       signature=signature)

        self.assertEqual(resp.code, 400, resp.body)

        # make sure query string also fails
        resp = await self.fetch("/?{}".format(
            generate_query_args(signature=signature,
                                address=TEST_ADDRESS,
                                timestamp=timestamp)))

        self.assertEqual(resp.code, 400, resp.body)
示例#11
0
    def fetch_signed(self,
                     path,
                     *,
                     signing_key=None,
                     signature=None,
                     timestamp=None,
                     address=None,
                     **kwargs):

        if not isinstance(path, str) or not path.startswith("/"):
            # for simplicity's sake, don't accept HTTPRequest objects or external urls in the tests
            raise Exception(
                "first argument must be path string starting with a / (e.g. /v1/tx)"
            )

        # find out if there's a path prefix added by get_url
        prefix = "/{}".format(self.get_url(path).split('/',
                                                       3)[-1]).split(path)[0]

        headers = kwargs.setdefault('headers', tornado.httputil.HTTPHeaders())

        if 'body' in kwargs:
            body = kwargs.pop('body')
            if isinstance(body, dict):
                headers['Content-Type'] = "application/json"
                body = tornado.escape.json_encode(body).encode('utf-8')
            elif isinstance(body, str):
                # try and find the charset to use to encode this
                if 'Content-Type' in headers:
                    idx = headers['Content-Type'].find('charset=')
                    if idx >= 0:
                        charset = headers['Content-Type'][idx + 8:]
                        idx = charset.find(';')
                        if idx >= 0:
                            charset = charset[:idx]
                    else:
                        charset = 'utf-8'
                else:
                    charset = 'utf-8'
                # encode to a byte string
                body = body.encode(charset)
            elif not isinstance(body, bytes):
                raise Exception("Unable to handle bodys of type '{}'".format(
                    type(body)))
        else:
            body = None

        method = kwargs.setdefault('method', 'GET').upper()

        if signing_key is None and (address is None or signature is None):
            raise Exception(
                "signing_key is required unless address and signature is given"
            )

        if timestamp is None and signature is not None:
            raise Exception(
                "timestamp is required if signature is given explicitly")

        if address is None:
            address = private_key_to_address(signing_key)
        if timestamp is None:
            timestamp = int(time.time())
        if signature is None:
            signature = sign_request(signing_key, method,
                                     "{}{}".format(prefix,
                                                   path), timestamp, body)

        headers[TOKEN_ID_ADDRESS_HEADER] = address
        headers[TOKEN_SIGNATURE_HEADER] = signature
        headers[TOKEN_TIMESTAMP_HEADER] = str(timestamp)

        # because tornado doesn't like POSTs with body set to None
        if body is None and method == "POST":
            body = b""

        return self.fetch(path, body=body, **kwargs)