Beispiel #1
0
    async def post(self):

        try:
            # normalize inputs
            if 'from' in self.json:
                self.json['from_address'] = self.json.pop('from')
            if 'to' in self.json:
                self.json['to_address'] = self.json.pop('to')
            elif 'to_address' not in self.json:
                self.json['to_address'] = None
            # the following are to deal with different representations
            # of the same concept from different places
            if 'gasPrice' in self.json:
                self.json['gas_price'] = self.json.pop('gasPrice')
            if 'gasprice' in self.json:
                self.json['gas_price'] = self.json.pop('gasprice')
            if 'startgas' in self.json:
                self.json['gas'] = self.json.pop('startgas')
            result = await ToshiEthJsonRPC(
                None, self.application,
                self.request).create_transaction_skeleton(**self.json)
        except JsonRPCError as e:
            raise JSONHTTPError(400, body={'errors': [e.data]})
        except TypeError:
            raise JSONHTTPError(400,
                                body={
                                    'errors': [{
                                        'id': 'bad_arguments',
                                        'message': 'Bad Arguments'
                                    }]
                                })

        self.write({"tx": result})
Beispiel #2
0
    async def post(self):

        self.set_header("Access-Control-Allow-Origin", "*")
        self.set_header("Access-Control-Allow-Headers", "x-requested-with")
        self.set_header('Access-Control-Allow-Methods', 'POST')

        if 'tx_hash' not in self.json or 'signature' not in self.json:
            raise JSONHTTPError(400,
                                body={
                                    'errors': [{
                                        'id': 'bad_arguments',
                                        'message': 'Bad Arguments'
                                    }]
                                })

        tx_hash = self.json['tx_hash']
        signature = self.json['signature']

        try:
            await ToshiEthJsonRPC(None, self.application,
                                  self.request).cancel_queued_transaction(
                                      tx_hash, signature)
        except JsonRPCError as e:
            raise JSONHTTPError(400, body={'errors': [e.data]})

        self.set_status(204)
Beispiel #3
0
    async def post(self):

        if self.is_request_signed():
            sender_toshi_id = self.verify_request()
        else:
            # this is an anonymous transaction
            sender_toshi_id = None

        try:
            result = await ToshiEthJsonRPC(
                sender_toshi_id, self.application,
                self.request).send_transaction(**self.json)
        except JsonRPCInternalError as e:
            raise JSONHTTPError(500, body={'errors': [e.data]})
        except JsonRPCError as e:
            raise JSONHTTPError(400, body={'errors': [e.data]})
        except TypeError:
            raise JSONHTTPError(400,
                                body={
                                    'errors': [{
                                        'id': 'bad_arguments',
                                        'message': 'Bad Arguments'
                                    }]
                                })

        self.write({"tx_hash": result})
Beispiel #4
0
    async def get(self, dapp_id):
        try:
            dapp_id = int(dapp_id)
        except ValueError:
            raise JSONHTTPError(400,
                                body={
                                    'errors': [{
                                        'id': 'invalid_dapp_id',
                                        'message': 'Invalid Dapp Id'
                                    }]
                                })
        async with self.db:
            dapp = await self.db.fetchrow(
                "SELECT d.*, JSONB_OBJECT_AGG(cat.category_id, cat.name) AS category_map, ARRAY_AGG(cat.category_id) as categories "
                "FROM dapps d "
                "JOIN dapp_categories dc ON d.dapp_id = dc.dapp_id "
                "JOIN categories cat ON dc.category_id = cat.category_id "
                "WHERE d.dapp_id = $1 "
                "GROUP BY d.dapp_id", dapp_id)
        if not dapp:
            raise JSONHTTPError(404,
                                body={
                                    'errors': [{
                                        'id': 'invalid_dapp_id',
                                        'message': 'Invalid Dapp Id'
                                    }]
                                })

        dapp_json = map_dapp_json(dapp)

        self.write({
            'dapp': dapp_json,
            'categories': json_decode(dapp['category_map'])
        })
Beispiel #5
0
    async def post(self):

        toshi_id = self.verify_request()
        payload = self.json

        if 'addresses' not in payload or len(payload['addresses']) == 0:
            raise JSONHTTPError(400,
                                body={
                                    'errors': [{
                                        'id': 'bad_arguments',
                                        'message': 'Bad Arguments'
                                    }]
                                })

        addresses = payload['addresses']

        for address in addresses:
            if not validate_address(address):
                raise JSONHTTPError(400,
                                    body={
                                        'errors': [{
                                            'id': 'bad_arguments',
                                            'message': 'Bad Arguments'
                                        }]
                                    })

        async with self.db:

            # see if this toshi_id is already registered, listening to it's own toshi_id
            rows = await self.db.fetch(
                "SELECT * FROM notification_registrations "
                "WHERE toshi_id = $1 AND eth_address = $1 AND service != 'ws'",
                toshi_id)
            if rows:
                if len(rows) > 1:
                    log.warning(
                        "LEGACY REGISTRATION FOR '{}' HAS MORE THAN ONE DEVICE OR SERVICE"
                        .format(toshi_id))
                registration_id = rows[0]['registration_id']
                service = rows[0]['service']
            else:
                service = 'LEGACY'
                registration_id = 'LEGACY'

            # simply store all the entered addresses with no service/registrations id
            for address in addresses:
                await self.db.execute(
                    "INSERT INTO notification_registrations (toshi_id, service, registration_id, eth_address) "
                    "VALUES ($1, $2, $3, $4) ON CONFLICT (toshi_id, service, registration_id, eth_address) DO NOTHING",
                    toshi_id, service, registration_id, address)

            await self.db.commit()

        self.set_status(204)
Beispiel #6
0
    async def post(self, service):

        toshi_id = self.verify_request()
        payload = self.json

        if 'registration_id' not in payload:
            raise JSONHTTPError(400,
                                body={
                                    'errors': [{
                                        'id': 'bad_arguments',
                                        'message': 'Bad Arguments'
                                    }]
                                })

        # eth address verification (if none is supplied, delete all the matching addresses)
        if 'address' in payload:
            eth_addresses = [payload['address']]
        elif 'addresses' in payload:
            eth_addresses = payload['addresses']
            if not type(eth_addresses) == list:
                raise JSONHTTPError(400,
                                    data={
                                        'id': 'bad_arguments',
                                        'message': '`addresses` must be a list'
                                    })
        else:
            eth_addresses = []

        if not all(
                validate_address(eth_address)
                for eth_address in eth_addresses):
            raise JSONHTTPError(400,
                                data={
                                    'id': 'bad_arguments',
                                    'message': 'Bad Arguments'
                                })

        async with self.db:
            if eth_addresses:
                await self.db.executemany(
                    "DELETE FROM notification_registrations WHERE toshi_id = $1 AND service = $2 AND registration_id = $3 and eth_address = $4",
                    [(toshi_id, service, payload['registration_id'],
                      eth_address) for eth_address in eth_addresses])
            else:
                await self.db.execute(
                    "DELETE FROM notification_registrations WHERE toshi_id = $1 AND service = $2 AND registration_id = $3",
                    toshi_id, service, payload['registration_id'])

            await self.db.commit()

        request_to_migrate(toshi_id)
        self.set_status(204)
        self.track(toshi_id, "Deregistered ETH notifications")
Beispiel #7
0
    async def get(self, key):

        if self.is_request_signed():

            address = self.verify_request()
            await self.set_login_result(key, address)
            self.set_status(204)

        else:

            try:
                self._future = LoginManager.create_login_check(key)
                address = await self._future

                if address is None:
                    raise JSONHTTPError(400,
                                        body={
                                            'errors': [{
                                                'id':
                                                'login_failed',
                                                'message':
                                                'Login failed'
                                            }]
                                        })
                if hasattr(self, 'on_login'):
                    f = self.on_login(address)
                    if asyncio.iscoroutine(f):
                        f = await f
                    return f
                # else
                self.write({"address": address})

            except TimeoutError:
                raise JSONHTTPError(408,
                                    body={
                                        'errors': [{
                                            'id':
                                            'request_timeout',
                                            'message':
                                            'Login request timed out'
                                        }]
                                    })
            except asyncio.CancelledError:
                raise JSONHTTPError(400,
                                    body={
                                        'errors': [{
                                            'id':
                                            'connection_closed',
                                            'message':
                                            'Login request connection closed'
                                        }]
                                    })
Beispiel #8
0
    async def post(self, service):
        toshi_id = self.verify_request()
        payload = self.json

        if not all(arg in payload for arg in ['registration_id']):
            raise JSONHTTPError(400,
                                body={
                                    'errors': [{
                                        'id': 'bad_arguments',
                                        'message': 'Bad Arguments'
                                    }]
                                })

        # eth address verification (default to toshi_id if eth_address is not supplied)
        if 'address' in payload:
            eth_addresses = [payload['address']]
        elif 'addresses' in payload:
            eth_addresses = payload['addresses']
            if not type(eth_addresses) == list:
                raise JSONHTTPError(400,
                                    data={
                                        'id': 'bad_arguments',
                                        'message': '`addresses` must be a list'
                                    })
        else:
            raise JSONHTTPError(400,
                                data={
                                    'id': 'bad_arguments',
                                    'message': 'Bad Arguments'
                                })

        if not all(
                validate_address(eth_address)
                for eth_address in eth_addresses):
            raise JSONHTTPError(400,
                                data={
                                    'id': 'bad_arguments',
                                    'message': 'Bad Arguments'
                                })

        async with self.db:

            await self.db.executemany(
                "INSERT INTO notification_registrations (toshi_id, service, registration_id, eth_address) "
                "VALUES ($1, $2, $3, $4) ON CONFLICT (toshi_id, service, registration_id, eth_address) DO NOTHING",
                [(toshi_id, service, payload['registration_id'], eth_address)
                 for eth_address in eth_addresses])

            await self.db.commit()

        request_to_migrate(toshi_id)
        self.set_status(204)
Beispiel #9
0
    async def get(self, tx_hash):

        self.set_header("Access-Control-Allow-Origin", "*")
        self.set_header("Access-Control-Allow-Headers", "x-requested-with")
        self.set_header('Access-Control-Allow-Methods', 'GET')

        format = self.get_query_argument('format', 'rpc').lower()

        try:
            tx = await ToshiEthJsonRPC(None, self.application,
                                       self.request).get_transaction(tx_hash)
        except JsonRPCError as e:
            raise JSONHTTPError(400, body={'errors': [e.data]})

        if tx is None and format != 'sofa':
            raise JSONHTTPError(
                404,
                body={'error': [{
                    'id': 'not_found',
                    'message': 'Not Found'
                }]})

        if format == 'sofa':

            async with self.db:
                row = await self.db.fetchrow(
                    "SELECT * FROM transactions where hash = $1 ORDER BY transaction_id DESC",
                    tx_hash)
            if row is None:
                raise JSONHTTPError(404,
                                    body={
                                        'error': [{
                                            'id': 'not_found',
                                            'message': 'Not Found'
                                        }]
                                    })
            if tx is None:
                tx = transaction_to_json(
                    database_transaction_to_rlp_transaction(row))
            if row['status'] == 'error':
                tx['error'] = True
            payment = SofaPayment.from_transaction(
                tx,
                networkId=self.application.config['ethereum']['network_id'])
            message = payment.render()
            self.set_header('Content-Type', 'text/plain')
            self.write(message.encode('utf-8'))

        else:

            self.write(tx)
Beispiel #10
0
    async def get(self, token):

        user = None
        async with self.db:
            row = await self.db.fetchrow(
                "SELECT u.*, a.created AS auth_token_created FROM auth_tokens a "
                "JOIN users u ON a.address = u.toshi_id "
                "WHERE a.token = $1", token)
            if row is not None:
                # only allow tokens to be used for 10 minutes
                print(row)
                if row['auth_token_created'] + timedelta(
                        minutes=10) > datetime.utcnow():
                    user = user_row_for_json(self.request, row)
                else:
                    print('expired')
                # remove token after single use
                await self.db.execute(
                    "DELETE FROM auth_tokens WHERE token = $1", token)
                await self.db.commit()
            else:
                print('not found')

        if user:
            self.write(user)
        else:
            raise JSONHTTPError(404)
Beispiel #11
0
        def is_request_signed(self, raise_if_partial=True):
            """Returns true if the request contains the headers needed to be considered signed.
            Designed for use in situations where a signature may be optional.

            if `raise_if_partial` is true (default) this will raise a HTTPError if the
            request contains only some of the headers needed for the signature
            verification, otherwise False will be returned"""

            count_token_headers = sum(
                1 if x in self.request.headers else 0 for x in [
                    TOKEN_ID_ADDRESS_HEADER, TOKEN_SIGNATURE_HEADER,
                    TOKEN_TIMESTAMP_HEADER
                ])
            count_toshi_headers = sum(
                1 if x in self.request.headers else 0 for x in [
                    TOSHI_ID_ADDRESS_HEADER, TOSHI_SIGNATURE_HEADER,
                    TOSHI_TIMESTAMP_HEADER
                ])

            if count_token_headers == 3 or count_toshi_headers == 3:
                return True
            if count_token_headers == 0 or count_toshi_headers == 0:
                return False
            if raise_if_partial:
                raise JSONHTTPError(
                    400,
                    body={
                        'errors': [{
                            'id':
                            'bad_arguments',
                            'message':
                            'Missing headers required for authentication'
                        }]
                    })
Beispiel #12
0
    async def post(self):

        try:
            # normalize inputs
            if 'from' in self.json:
                self.json['from_address'] = self.json.pop('from')
            if 'to' in self.json:
                self.json['to_address'] = self.json.pop('to')
            elif 'to_address' not in self.json:
                self.json['to_address'] = None
            # the following are to deal with different representations
            # of the same concept from different places
            if 'gasPrice' in self.json:
                self.json['gas_price'] = self.json.pop('gasPrice')
            if 'gasprice' in self.json:
                self.json['gas_price'] = self.json.pop('gasprice')
            if 'startgas' in self.json:
                self.json['gas'] = self.json.pop('startgas')
            if 'gasLimit' in self.json:
                self.json['gas'] = self.json.pop('gasLimit')
            if 'networkId' in self.json:
                self.json['network_id'] = self.json.pop('networkId')
            if 'chainId' in self.json:
                self.json['network_id'] = self.json.pop('chainId')
            if 'chain_id' in self.json:
                self.json['network_id'] = self.json.pop('chain_id')
            if 'tokenAddress' in self.json:
                self.json['token_address'] = self.json.pop('tokenAddress')
            result = await ToshiEthJsonRPC(
                None, self.application,
                self.request).create_transaction_skeleton(**self.json)
        except JsonRPCError as e:
            log.warning("/tx/skel failed: " + json_encode(e.data) +
                        "\" -> arguments: " + json_encode(self.json) + "\"")
            raise JSONHTTPError(400, body={'errors': [e.data]})
        except TypeError:
            log.warning("/tx/skel failed: bad arguments \"" +
                        json_encode(self.json) + "\"")
            raise JSONHTTPError(400,
                                body={
                                    'errors': [{
                                        'id': 'bad_arguments',
                                        'message': 'Bad Arguments'
                                    }]
                                })

        self.write(result)
Beispiel #13
0
    async def get(self, address):

        try:
            result = await ToshiEthJsonRPC(None, self.application,
                                           self.request).get_balance(address)
        except JsonRPCError as e:
            raise JSONHTTPError(400, body={'errors': [e.data]})

        self.write(result)
Beispiel #14
0
    async def get(self, eth_address, token_address=None):

        self.set_header("Access-Control-Allow-Origin", "*")
        self.set_header("Access-Control-Allow-Headers", "x-requested-with")
        self.set_header('Access-Control-Allow-Methods', 'GET')

        try:
            result = await ToshiEthJsonRPC(None, self.application,
                                           self.request).get_token_balances(
                                               eth_address,
                                               token_address=token_address)
        except JsonRPCError as e:
            raise JSONHTTPError(400, body={'errors': [e.data]})

        if token_address:
            if result is None:
                raise JSONHTTPError(404)
            self.write(result)
        else:
            self.write({"tokens": result})
Beispiel #15
0
    async def get(self, key):

        if self.is_request_signed():

            address = self.verify_request()
            self.set_login_result(key, address)
            self.set_status(204)

        else:

            if key not in self.login_requests:
                self.create_new_login_future(key)

            address = await self.login_requests[key]

            if address is None:
                raise JSONHTTPError(400,
                                    body={
                                        'errors': [{
                                            'id':
                                            'request_timeout',
                                            'message':
                                            'Login request timed out'
                                        }]
                                    })
            if address is False:
                raise JSONHTTPError(401,
                                    body={
                                        'errors': [{
                                            'id': 'login_failed',
                                            'message': 'Login failed'
                                        }]
                                    })

            if hasattr(self, 'on_login'):
                f = self.on_login(address)
                if asyncio.iscoroutine(f):
                    f = await f
                return f
            # else
            self.write({"address": address})
Beispiel #16
0
 async def get(self, token):
     key = "{}{}".format(AUTH_TOKEN_REDIS_PREFIX, token)
     toshi_id = await self.redis.get(key, encoding='utf-8')
     if toshi_id is not None:
         await self.redis.delete(key)
         async with self.db:
             user = await self.db.fetchrow(
                 "SELECT * FROM users WHERE toshi_id = $1", toshi_id)
         if user:
             self.write(user_row_for_json(user))
             return
     raise JSONHTTPError(404)
Beispiel #17
0
    async def get(self, address, contract_address=None):

        self.set_header("Access-Control-Allow-Origin", "*")
        self.set_header("Access-Control-Allow-Headers", "x-requested-with")
        self.set_header('Access-Control-Allow-Methods', 'GET')

        try:
            result = await ToshiEthJsonRPC(None, self.application,
                                           self.request).get_collectibles(
                                               address, contract_address)
        except JsonRPCError as e:
            raise JSONHTTPError(400, body={'errors': [e.data]})

        if result is None:
            raise JSONHTTPError(
                404,
                body={'errors': [{
                    'id': 'not_found',
                    'message': 'Not Found'
                }]})
        self.write(result)
Beispiel #18
0
    async def delete(self, contract_address):

        eth_address = self.verify_request()

        try:
            await ToshiEthJsonRPC(
                eth_address, self.application,
                self.request).remove_token(contract_address=contract_address)
        except JsonRPCInternalError as e:
            raise JSONHTTPError(500, body={'errors': [e.data]})
        except JsonRPCError as e:
            raise JSONHTTPError(400, body={'errors': [e.data]})
        except TypeError:
            raise JSONHTTPError(400,
                                body={
                                    'errors': [{
                                        'id': 'bad_arguments',
                                        'message': 'Bad Arguments'
                                    }]
                                })

        self.set_status(204)
Beispiel #19
0
    async def post(self):

        eth_address = self.verify_request()

        try:
            result = await ToshiEthJsonRPC(eth_address, self.application,
                                           self.request).add_token(**self.json)
        except JsonRPCInternalError as e:
            raise JSONHTTPError(500, body={'errors': [e.data]})
        except JsonRPCError as e:
            raise JSONHTTPError(400, body={'errors': [e.data]})
        except TypeError:
            log.exception("bad_arguments")
            raise JSONHTTPError(400,
                                body={
                                    'errors': [{
                                        'id': 'bad_arguments',
                                        'message': 'Bad Arguments'
                                    }]
                                })

        self.write(result)
Beispiel #20
0
    async def get(self, address):

        self.set_header("Access-Control-Allow-Origin", "*")
        self.set_header("Access-Control-Allow-Headers", "x-requested-with")
        self.set_header('Access-Control-Allow-Methods', 'GET')

        try:
            result = await ToshiEthJsonRPC(None, self.application,
                                           self.request).get_balance(address)
        except JsonRPCError as e:
            raise JSONHTTPError(400, body={'errors': [e.data]})

        self.write(result)
Beispiel #21
0
    async def post(self):

        toshi_id = self.verify_request()
        payload = self.json

        if 'addresses' not in payload or len(payload['addresses']) == 0:
            raise JSONHTTPError(400,
                                body={
                                    'errors': [{
                                        'id': 'bad_arguments',
                                        'message': 'Bad Arguments'
                                    }]
                                })

        addresses = payload['addresses']

        for address in addresses:
            if not validate_address(address):
                raise JSONHTTPError(400,
                                    body={
                                        'errors': [{
                                            'id': 'bad_arguments',
                                            'message': 'Bad Arguments'
                                        }]
                                    })

        async with self.db:

            await self.db.execute(
                "DELETE FROM notification_registrations WHERE service != 'ws' AND toshi_id = $1 AND ({})"
                .format(' OR '.join('eth_address = ${}'.format(i + 2)
                                    for i, _ in enumerate(addresses))),
                toshi_id, *addresses)

            await self.db.commit()

        self.set_status(204)
        self.track(toshi_id, "Deregistered ETH notifications")
Beispiel #22
0
    async def post(self, service):

        toshi_id = self.verify_request()
        payload = self.json

        if 'registration_id' not in payload:
            raise JSONHTTPError(400,
                                body={
                                    'errors': [{
                                        'id': 'bad_arguments',
                                        'message': 'Bad Arguments'
                                    }]
                                })

        # TODO: registration id verification

        # eth address verification (if none is supplied, delete all the matching addresses)
        eth_address = payload.get('address', None)
        if eth_address and not validate_address(eth_address):
            raise JSONHTTPError(data={
                'id': 'bad_arguments',
                'message': 'Bad Arguments'
            })

        async with self.db:

            args = [toshi_id, service, payload['registration_id']]
            if eth_address:
                args.append(eth_address)
            await self.db.execute(
                "DELETE FROM notification_registrations WHERE toshi_id = $1 AND service = $2 AND registration_id = $3{}"
                .format("AND eth_address = $4" if eth_address else ""), *args)

            await self.db.commit()

        self.set_status(204)
        self.track(toshi_id, "Deregistered ETH notifications")
Beispiel #23
0
    async def on_login(self, address):

        num = int(data_encoder(os.urandom(16))[2:], 16)
        token = b62encode(num)

        async with self.db:
            row = await self.db.fetchrow(
                "SELECT * FROM users where toshi_id = $1", address)
            if row is None:
                raise JSONHTTPError(401)
            await self.db.execute(
                "INSERT INTO auth_tokens (token, address) VALUES ($1, $2)",
                token, address)
            await self.db.commit()
        self.write({'auth_token': token})
Beispiel #24
0
    async def list_users(self, *, toshi_ids=None, payment_addresses=None):

        sql = "SELECT u.* FROM users u JOIN (VALUES "
        values = []
        if toshi_ids is not None:
            column = 'toshi_id'
            addresses = toshi_ids
        elif payment_addresses is not None:
            column = 'payment_address'
            addresses = payment_addresses
        else:
            raise Exception(
                "list_users called without toshi_ids or payment_addresses")
        for i, address in enumerate(addresses):
            if not validate_address(address):
                raise JSONHTTPError(400,
                                    body={
                                        'errors': [{
                                            'id': 'bad_arguments',
                                            'message': 'Bad Arguments'
                                        }]
                                    })
            values.append("('{}', {}) ".format(address, i))
            # in case this request is made with a lot of ids
            # make sure we yield to other processes rather
            # than taking up all resources on this
            if i > 0 and i % 100 == 0:
                await asyncio.sleep(0.001)
        sql += ", ".join(values)
        sql += ") AS v ({column}, ordering) ON u.{column} = v.{column} ".format(
            column=column)
        sql += "ORDER BY v.ordering"

        async with self.db:
            rows = await self.db.fetch(sql)

        self.write({
            'limit': len(rows),
            'total': len(rows),
            'offset': 0,
            'query': '',
            'results': [user_row_for_json(row) for row in rows]
        })
Beispiel #25
0
    async def get(self):
        client_filter = self.get_client_type
        async with self.db:
            try:
                offset = int(self.get_argument('offset', 0))
            except ValueError:
                raise JSONHTTPError(400,
                                    body={
                                        'errors': [{
                                            'id':
                                            'invalid_offset',
                                            'message':
                                            'Invalid type for offset'
                                        }]
                                    })

            try:
                limit = min(
                    int(self.get_argument('limit', DEFAULT_DAPP_SEARCH_LIMIT)),
                    MAX_DAPP_SEARCH_LIMIT)
            except ValueError:
                raise JSONHTTPError(400,
                                    body={
                                        'errors': [{
                                            'id':
                                            'invalid_limit',
                                            'message':
                                            'Invalid type for limit'
                                        }]
                                    })

            try:
                category = self.get_argument('category', None)
                if category:
                    category = int(category)
            except ValueError:
                raise JSONHTTPError(400,
                                    body={
                                        'errors': [{
                                            'id':
                                            'invalid_category',
                                            'message':
                                            'Invalid type for category'
                                        }]
                                    })

            query = self.get_argument('query', '')

            dapps, total = await get_apps_by_filter(
                self.db,
                category,
                query,
                limit,
                offset,
                client_filter=client_filter,
                filter_special=self.should_filter_special_dapps)
            all_categories = await self.db.fetch(
                "SELECT * FROM categories WHERE hidden_on != 'all'{} ORDER BY category_id ASC"
                .format(" AND hidden_on != '{}'".format(client_filter)
                        if client_filter != UNKNOWN_CLIENT else ""))
            all_category_ids = [cat['category_id'] for cat in all_categories]
            used_categories = filter_categories_in_dapps(
                dapps, all_category_ids)
            categories = {}

            for cat in all_categories:
                category_id = cat['category_id']
                if category_id in used_categories:
                    categories[category_id] = cat['name']

            self.write({
                'results': {
                    'dapps': dapps,
                    'categories': categories
                },
                'offset': offset,
                'limit': limit,
                'total': total,
                'query': query,
                'category': category
            })
Beispiel #26
0
    async def post(self, service):
        toshi_id = self.verify_request()
        payload = self.json

        if not all(arg in payload for arg in ['registration_id']):
            raise JSONHTTPError(400,
                                body={
                                    'errors': [{
                                        'id': 'bad_arguments',
                                        'message': 'Bad Arguments'
                                    }]
                                })

        # TODO: registration id verification

        # XXX: BACKWARDS COMPAT FOR OLD PN REGISTARTION
        # remove when no longer needed
        if 'address' not in payload:
            async with self.db:
                legacy = await self.db.fetch(
                    "SELECT eth_address FROM notification_registrations "
                    "WHERE toshi_id = $1 AND service = 'LEGACY' AND registration_id = 'LEGACY'",
                    toshi_id)
        else:
            legacy = False

        if legacy:

            async with self.db:

                for row in legacy:
                    eth_address = row['eth_address']
                    await self.db.execute(
                        "INSERT INTO notification_registrations (toshi_id, service, registration_id, eth_address) "
                        "VALUES ($1, $2, $3, $4) ON CONFLICT (toshi_id, service, registration_id, eth_address) DO NOTHING",
                        toshi_id, service, payload['registration_id'],
                        eth_address)
                await self.db.execute(
                    "DELETE FROM notification_registrations "
                    "WHERE toshi_id = $1 AND service = 'LEGACY' AND registration_id = 'LEGACY'",
                    toshi_id)
                await self.db.commit()

        else:

            # eth address verification (default to toshi_id if eth_address is not supplied)
            eth_address = payload[
                'address'] if 'address' in payload else toshi_id
            if not validate_address(eth_address):
                raise JSONHTTPError(data={
                    'id': 'bad_arguments',
                    'message': 'Bad Arguments'
                })

            async with self.db:

                await self.db.execute(
                    "INSERT INTO notification_registrations (toshi_id, service, registration_id, eth_address) "
                    "VALUES ($1, $2, $3, $4) ON CONFLICT (toshi_id, service, registration_id, eth_address) DO NOTHING",
                    toshi_id, service, payload['registration_id'], eth_address)

                # XXX: temporary fix for old ios versions sending their payment address as toshi_id
                # should be removed after enough time has passed that most people should be using the fixed version
                if eth_address != toshi_id:
                    # remove any apn registrations where toshi_id == eth_address for this eth_address
                    await self.db.execute(
                        "DELETE FROM notification_registrations "
                        "WHERE toshi_id = $1 AND eth_address = $1 AND service = 'apn'",
                        eth_address)

                await self.db.commit()

        self.set_status(204)
Beispiel #27
0
    async def get(self, address):

        self.set_header("Access-Control-Allow-Origin", "*")
        self.set_header("Access-Control-Allow-Headers", "x-requested-with")
        self.set_header('Access-Control-Allow-Methods', 'GET')

        offset = parse_int(self.get_argument('offset', '0'))
        limit = parse_int(self.get_argument('limit', '10'))
        status = set([s.lower() for s in self.get_arguments('status')])
        direction = set([d.lower() for d in self.get_arguments('direction')])
        order = self.get_argument('order', 'desc').upper()

        if not validate_address(address) or \
           offset is None or \
           limit is None or \
           (status and not status.issubset(['confirmed', 'unconfirmed', 'queued', 'error'])) or \
           (direction and not direction.issubset(['in', 'out'])) or \
           (order not in ['DESC', 'ASC']):
            raise JSONHTTPError(400,
                                body={
                                    'id': 'bad_arguments',
                                    'message': 'Bad Arguments'
                                })

        query = "SELECT * FROM transactions WHERE "
        args = [address, offset, limit]

        if len(direction) == 0 or len(direction) == 2:
            query += "(from_address = $1 OR to_address = $1) "
        elif 'in' in direction:
            query += "to_address = $1 "
        elif 'out' in direction:
            query += "from_address = $1 "

        if len(status) == 0:
            query += "AND (status != $4 OR status IS NULL) "
            args.append('error')
        else:
            status_query = []
            for s in status:
                if s == 'queued':
                    status_query.extend([
                        "status = ${}".format(len(args) + 1), "status IS NULL"
                    ])
                else:
                    status_query.append("status = ${}".format(len(args) + 1))
                args.append(s)
            query += "AND (" + " OR ".join(status_query) + ") "

        query += "ORDER BY created {} OFFSET $2 LIMIT $3".format(order)

        async with self.db:
            rows = await self.db.fetch(query, *args)

        transactions = []
        for row in rows:
            transactions.append({
                "hash":
                row['hash'],
                "to":
                row['to_address'],
                "from":
                row['from_address'],
                "nonce":
                hex(row['nonce']),
                "value":
                row['value'],
                "gas":
                row['gas'],
                "gas_price":
                row['gas_price'],
                "created_data":
                row['created'].isoformat(),
                "confirmed_data":
                row['updated'].isoformat() if row['blocknumber'] else None,
                "status":
                row['status'] if row['status'] is not None else 'queued',
                "data":
                row['data']
            })
        resp = {
            "transactions": transactions,
            "offset": offset,
            "limit": limit,
            "order": order
        }
        if len(direction) == 1:
            resp['direction'] = direction.pop()
        if status:
            resp['status'] = "&".join(status)
        self.write(resp)
Beispiel #28
0
 def get_json_argument(self, name, default=DEFAULT_JSON_ARGUMENT):
     if name not in self.json:
         if default is DEFAULT_JSON_ARGUMENT:
             raise JSONHTTPError(400, "missing_arguments")
         return default
     return self.json[name]
Beispiel #29
0
        def verify_request(self):
            """Verifies that the signature and the payload match the expected address
            raising a JSONHTTPError (400) if something is wrong with the request"""

            if TOSHI_ID_ADDRESS_HEADER in self.request.headers:
                expected_address = self.request.headers[
                    TOSHI_ID_ADDRESS_HEADER]
            elif self.get_argument(TOSHI_ID_ADDRESS_QUERY_ARG, None):
                expected_address = self.get_argument(
                    TOSHI_ID_ADDRESS_QUERY_ARG)
            elif TOKEN_ID_ADDRESS_HEADER in self.request.headers:
                expected_address = self.request.headers[
                    TOKEN_ID_ADDRESS_HEADER]
            elif self.get_argument(TOKEN_ID_ADDRESS_QUERY_ARG, None):
                expected_address = self.get_argument(
                    TOKEN_ID_ADDRESS_QUERY_ARG)
            else:
                raise JSONHTTPError(400,
                                    body={
                                        'errors': [{
                                            'id':
                                            'bad_arguments',
                                            'message':
                                            'Missing Toshi-ID-Address'
                                        }]
                                    })

            if TOSHI_SIGNATURE_HEADER in self.request.headers:
                signature = self.request.headers[TOSHI_SIGNATURE_HEADER]
            elif self.get_argument(TOSHI_SIGNATURE_QUERY_ARG, None):
                signature = self.get_argument(TOSHI_SIGNATURE_QUERY_ARG)
            elif TOKEN_SIGNATURE_HEADER in self.request.headers:
                signature = self.request.headers[TOKEN_SIGNATURE_HEADER]
            elif self.get_argument(TOKEN_SIGNATURE_QUERY_ARG, None):
                signature = self.get_argument(TOKEN_SIGNATURE_QUERY_ARG)
            else:
                raise JSONHTTPError(400,
                                    body={
                                        'errors': [{
                                            'id':
                                            'bad_arguments',
                                            'message':
                                            'Missing Toshi-Signature'
                                        }]
                                    })

            if TOSHI_TIMESTAMP_HEADER in self.request.headers:
                timestamp = self.request.headers[TOSHI_TIMESTAMP_HEADER]
            elif self.get_argument(TOSHI_TIMESTAMP_QUERY_ARG, None):
                timestamp = self.get_argument(TOSHI_TIMESTAMP_QUERY_ARG)
            elif TOKEN_TIMESTAMP_HEADER in self.request.headers:
                timestamp = self.request.headers[TOKEN_TIMESTAMP_HEADER]
            elif self.get_argument(TOKEN_TIMESTAMP_QUERY_ARG, None):
                timestamp = self.get_argument(TOKEN_TIMESTAMP_QUERY_ARG)
            else:
                raise JSONHTTPError(400,
                                    body={
                                        'errors': [{
                                            'id':
                                            'bad_arguments',
                                            'message':
                                            'Missing Toshi-Timestamp'
                                        }]
                                    })

            timestamp = parse_int(timestamp)
            if timestamp is None:
                raise JSONHTTPError(400,
                                    body={
                                        'errors': [{
                                            'id':
                                            'invalid_timestamp',
                                            'message':
                                            'Given Toshi-Timestamp is invalid'
                                        }]
                                    })

            if not validate_address(expected_address):
                raise JSONHTTPError(400,
                                    body={
                                        'errors': [{
                                            'id':
                                            'invalid_id_address',
                                            'message':
                                            'Invalid Toshi-ID-Address'
                                        }]
                                    })

            if not validate_signature(signature):
                raise JSONHTTPError(400,
                                    body={
                                        'errors': [{
                                            'id':
                                            'invalid_signature',
                                            'message':
                                            'Invalid Toshi-Signature'
                                        }]
                                    })

            try:
                signature = data_decoder(signature)
            except Exception:
                raise JSONHTTPError(400,
                                    body={
                                        'errors': [{
                                            'id':
                                            'invalid_signature',
                                            'message':
                                            'Invalid Toshi-Signature'
                                        }]
                                    })

            verb = self.request.method
            uri = self.request.path

            if self.request.body:
                datahash = self.request.body
            else:
                datahash = ""

            data_string = generate_request_signature_data_string(
                verb, uri, timestamp, datahash)

            if not ecrecover(data_string, signature, expected_address):
                raise JSONHTTPError(400,
                                    body={
                                        'errors': [{
                                            'id':
                                            'invalid_signature',
                                            'message':
                                            'Invalid Toshi-Signature'
                                        }]
                                    })

            if abs(int(time.time()) - timestamp) > TIMESTAMP_EXPIRY:
                raise JSONHTTPError(
                    400,
                    body={
                        'errors': [{
                            'id':
                            'invalid_timestamp',
                            'message':
                            'The difference between the timestamp and the current time is too large'
                        }]
                    })

            return expected_address