def get_blockchain_record(fqu):

    data = {}

    try:
        resp = get_name_blockchain_record(fqu)

    except Exception as e:
        data['error'] = e
        return data

    return resp
예제 #2
0
def get_blockchain_record(fqu):

    data = {}

    try:
        resp = get_name_blockchain_record(fqu)

    except Exception as e:
        data['error'] = e
        return data

    return resp
예제 #3
0
def get_profile(username, refresh=False, namespace=DEFAULT_NAMESPACE):
    """ Given a fully-qualified username (username.namespace)
        get the data associated with that fqu.
        Return cached entries, if possible.
    """

    global MEMCACHED_ENABLED
    global mc

    username = username.lower()

    if MEMCACHED_ENABLED and not refresh:
        log.debug("Memcache get DHT: %s" % username)
        dht_cache_reply = mc.get("dht_" + str(username))
    else:
        log.debug("Memcache disabled: %s" % username)
        dht_cache_reply = None

    if dht_cache_reply is None:

        try:
            bs_resp = get_name_blockchain_record(username + "." + namespace)
        except:
            abort(
                500, "Connection to blockstack-server %s:%s timed out" %
                (BLOCKSTACKD_IP, BLOCKSTACKD_PORT))

        if bs_resp is None or 'error' in bs_resp:
            abort(404)

        if 'value_hash' in bs_resp:
            profile_hash = bs_resp['value_hash']
            dht_response = fetch_from_dht(profile_hash)

            dht_data = {}
            dht_data['dht_response'] = dht_response
            dht_data['owner_address'] = bs_resp['address']

            if MEMCACHED_ENABLED or refresh:
                log.debug("Memcache set DHT: %s" % username)
                mc.set("dht_" + str(username), json.dumps(dht_data),
                       int(time() + MEMCACHED_TIMEOUT))
        else:
            dht_data = {"error": "Not found"}
    else:
        dht_data = json.loads(dht_cache_reply)

    data = format_profile(dht_data['dht_response'], username,
                          dht_data['owner_address'])

    return data
예제 #4
0
def get_zonefile_from_atlas(blockchain_id, config_path, name_record=None):
    """
    Get the zone file from the atlas network
    Return the raw zone file on success
    Raise on eror
    """
    import blockstack_client
    import blockstack_client.proxy as proxy

    conf = blockstack_client.get_config(config_path)
    if not conf:
        raise Exception(
            "Failed to load config file from {}".format(config_path))

    if 'server' not in conf or 'port' not in conf:
        raise Exception("Config file is missing 'server' and/or 'port")

    if name_record is not None:
        name_record = proxy.get_name_blockchain_record(blockchain_id)
        if 'error' in name_record:
            raise Exception(
                "Failed to load name record for {}".format(blockchain_id))

    name_zonefile_hash = name_record['value_hash']

    atlas_host = conf['server']
    atlas_port = conf['port']
    hostport = '{}:{}'.format(atlas_host, atlas_port)

    zonefile_txt = None
    expected_zonefile_hash = str(name_zonefile_hash)

    # load from atlas
    res = proxy.get_zonefiles(hostport, [expected_zonefile_hash])
    if 'error' in res:
        raise Exception("Failed to load {} from Atlas network: {}".format(
            expected_zonefile_hash, res['error']))

    zonefile_txt = res['zonefiles'][expected_zonefile_hash]
    return zonefile_txt
def get_zonefile_from_atlas(blockchain_id, config_path, name_record=None):
    """
    Get the zone file from the atlas network
    Return the raw zone file on success
    Raise on eror
    """
    import blockstack_client
    import blockstack_client.proxy as proxy
    
    conf = blockstack_client.get_config(config_path)
    if not conf:
        raise Exception("Failed to load config file from {}".format(config_path))

    if 'server' not in conf or 'port' not in conf:
        raise Exception("Config file is missing 'server' and/or 'port")

    if name_record is not None:
        name_record = proxy.get_name_blockchain_record(blockchain_id)
        if 'error' in name_record:
            raise Exception("Failed to load name record for {}".format(blockchain_id))

    name_zonefile_hash = name_record['value_hash']

    atlas_host = conf['server']
    atlas_port = conf['port']
    hostport = '{}:{}'.format( atlas_host, atlas_port )

    zonefile_txt = None
    expected_zonefile_hash = str(name_zonefile_hash)

    # load from atlas
    res = proxy.get_zonefiles( hostport, [expected_zonefile_hash] )
    if 'error' in res:
        raise Exception("Failed to load {} from Atlas network: {}".format(expected_zonefile_hash, res['error']))

    zonefile_txt = res['zonefiles'][expected_zonefile_hash]
    return zonefile_txt
예제 #6
0
def lookup_index_manifest_url(blockchain_id, driver_name, index_stem,
                              config_path):
    """
    Given a blockchain ID, go and get the index manifest url.

    This is only applicable for certain drivers--i.e. the ones that 
    need a name-to-URL index since the storage system generates URLs
    to data on-the-fly.  This includes Dropbox, Google Drive, Onedrive,
    etc.

    The storage index URL will be located as an 'account', where
    * 'service' will be set to the driver name
    * 'identifier' will be set to 'storage'
    * 'contentUrl' will be set to the index url

    Return the index manifest URL on success.
    Return None if there is no URL
    Raise on error

    TODO: this method needs to be rewritten to use the token file format,
    and to use the proper public key to verify it.
    """
    import blockstack_client
    import blockstack_client.proxy as proxy
    import blockstack_client.user
    import blockstack_client.storage
    import blockstack_client.schemas

    if blockchain_id is None:
        # try getting it directly (we should have it)
        return index_settings_get_index_manifest_url(driver_name, config_path)

    name_record = proxy.get_name_blockchain_record(blockchain_id)
    if 'error' in name_record:
        raise Exception(
            "Failed to load name record for {}".format(blockchain_id))

    zonefile_txt = get_zonefile_from_atlas(blockchain_id,
                                           config_path,
                                           name_record=name_record)
    zonefile_pubkey = None

    try:
        zonefile = blockstack_zones.parse_zone_file(zonefile_txt)
        zonefile = dict(zonefile)
        zonefile_pubkey = blockstack_client.user.user_zonefile_data_pubkey(
            zonefile)
    except:
        raise Exception("Non-standard zonefile for {}".format(blockchain_id))

    # get the profile...
    # we're assuming here that some of the profile URLs are at least HTTP-accessible
    # (i.e. we can get them without having to go through the indexing system)
    # TODO: let drivers report their 'safety'
    profile_txt = None
    urls = blockstack_client.user.user_zonefile_urls(zonefile)
    for url in urls:
        profile_txt = None
        try:
            profile_txt = get_chunk_via_http(url, blockchain_id=blockchain_id)
        except Exception as e:
            if DEBUG:
                log.exception(e)

            log.debug("Failed to load profile from {}".format(url))
            continue

        if profile_txt is None:
            log.debug("Failed to load profile from {}".format(url))
            continue

        profile = blockstack_client.storage.parse_mutable_data(
            profile_txt,
            zonefile_pubkey,
            public_key_hash=name_record['address'])
        if not profile:
            log.debug("Failed to load profile from {}".format(url))
            continue

        # TODO: load this from the tokens file
        # got profile! the storage information will be listed as an account, where the 'service' is the driver name and the 'identifier' is the manifest url
        if 'account' not in profile:
            log.error(
                "No 'account' key in profile for {}".format(blockchain_id))
            return None

        accounts = profile['account']
        if not isinstance(accounts, list):
            log.error("Invalid 'account' key in profile for {}".format(
                blockchain_id))
            return None

        for account in accounts:
            try:
                jsonschema.validate(
                    account, blockstack_client.schemas.PROFILE_ACCOUNT_SCHEMA)
            except jsonschema.ValidationError:
                continue

            if account['service'] != driver_name:
                log.debug("Skipping account for '{}'".format(
                    account['service']))
                continue

            if account['identifier'] != 'storage':
                log.debug("Skipping non-storage account for '{}'".format(
                    account['service']))
                continue

            if not account.has_key('contentUrl'):
                continue

            url = account['contentUrl']
            parsed_url = urlparse.urlparse(url)

            # must be valid http(s) URL, or a test:// URL
            if (not parsed_url.scheme or
                    not parsed_url.netloc) and not url.startswith('test://'):
                log.warning("Skip invalid '{}' driver URL".format(driver_name))
                continue

            log.debug("Index manifest URL for {} is {}".format(
                blockchain_id, url))
            return url

    return None
def lookup_index_manifest_url( blockchain_id, driver_name, index_stem, config_path ):
    """
    Given a blockchain ID, go and get the index manifest url.

    This is only applicable for certain drivers--i.e. the ones that 
    need a name-to-URL index since the storage system generates URLs
    to data on-the-fly.  This includes Dropbox, Google Drive, Onedrive,
    etc.

    The storage index URL will be located as an 'account', where
    * 'service' will be set to the driver name
    * 'identifier' will be set to 'storage'
    * 'contentUrl' will be set to the index url

    Return the index manifest URL on success.
    Return None if there is no URL
    Raise on error

    TODO: this method needs to be rewritten to use the token file format,
    and to use the proper public key to verify it.
    """
    import blockstack_client
    import blockstack_client.proxy as proxy
    import blockstack_client.user
    import blockstack_client.storage
    import blockstack_client.schemas

    if blockchain_id is None:
        # try getting it directly (we should have it)
        return index_settings_get_index_manifest_url(driver_name, config_path)        

    name_record = proxy.get_name_blockchain_record(blockchain_id)
    if 'error' in name_record:
        raise Exception("Failed to load name record for {}".format(blockchain_id))

    zonefile_txt = get_zonefile_from_atlas(blockchain_id, config_path, name_record=name_record)
    zonefile_pubkey = None

    try:
        zonefile = blockstack_zones.parse_zone_file(zonefile_txt) 
        zonefile = dict(zonefile)
        zonefile_pubkey = blockstack_client.user.user_zonefile_data_pubkey(zonefile)
    except:
        raise Exception("Non-standard zonefile for {}".format(blockchain_id))

    # get the profile...
    # we're assuming here that some of the profile URLs are at least HTTP-accessible
    # (i.e. we can get them without having to go through the indexing system)
    # TODO: let drivers report their 'safety'
    profile_txt = None
    urls = blockstack_client.user.user_zonefile_urls(zonefile)
    for url in urls:
        profile_txt = None
        try:
            profile_txt = get_chunk_via_http(url, blockchain_id=blockchain_id)
        except Exception as e:
            if DEBUG:
                log.exception(e)

            log.debug("Failed to load profile from {}".format(url))
            continue

        if profile_txt is None:
            log.debug("Failed to load profile from {}".format(url))
            continue
        
        profile = blockstack_client.storage.parse_mutable_data(profile_txt, zonefile_pubkey, public_key_hash=name_record['address'])
        if not profile:
            log.debug("Failed to load profile from {}".format(url))
            continue
       
        # TODO: load this from the tokens file
        # got profile! the storage information will be listed as an account, where the 'service' is the driver name and the 'identifier' is the manifest url 
        if 'account' not in profile:
            log.error("No 'account' key in profile for {}".format(blockchain_id))
            return None

        accounts = profile['account']
        if not isinstance(accounts, list):
            log.error("Invalid 'account' key in profile for {}".format(blockchain_id))
            return None

        for account in accounts:
            try:
                jsonschema.validate(account, blockstack_client.schemas.PROFILE_ACCOUNT_SCHEMA)
            except jsonschema.ValidationError:
                continue

            if account['service'] != driver_name:
                log.debug("Skipping account for '{}'".format(account['service']))
                continue

            if account['identifier'] != 'storage':
                log.debug("Skipping non-storage account for '{}'".format(account['service']))
                continue
            
            if not account.has_key('contentUrl'):
                continue

            url = account['contentUrl']
            parsed_url = urlparse.urlparse(url)
            
            # must be valid http(s) URL, or a test:// URL
            if (not parsed_url.scheme or not parsed_url.netloc) and not url.startswith('test://'):
                log.warning("Skip invalid '{}' driver URL".format(driver_name))
                continue

            log.debug("Index manifest URL for {} is {}".format(blockchain_id, url))
            return url

    return None