def get_blockchain_record(fqu): data = {} try: resp = get_name_blockchain_record(fqu) except Exception as e: data['error'] = e return data return resp
def get_blockchain_record(fqu): data = {} try: resp = get_name_blockchain_record(fqu) except Exception as e: data['error'] = e return data return resp
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
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
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