Files
stacks-puppet-node/blockstack_client/backend/drivers/blockstack_resolver.py
2017-01-17 11:16:19 -05:00

195 lines
5.3 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Blockstack-client
~~~~~
copyright: (c) 2014-2015 by Halfmoon Labs, Inc.
copyright: (c) 2016 by Blockstack.org
This file is part of Blockstack-client.
Blockstack-client is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Blockstack-client is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Blockstack-client. If not, see <http://www.gnu.org/licenses/>.
"""
# use Blockstack Labs as a read-only reader for zonefile/profile data
import os
import sys
import traceback
import logging
import json
import requests
import pybitcoin
from ConfigParser import SafeConfigParser
import blockstack_zones
from common import get_logger, DEBUG
log = get_logger("blockstack-storage-driver-blockstack-s3-readonly")
if os.environ.get("BLOCKSTACK_TEST") is None:
RESOLVER_URL = "https://onename.com"
STORAGE_URL = "https://blockstack.s3.amazonaws.com"
else:
RESOLVER_URL = "http://localhost:8081"
STORAGE_URL = "http://localhost:8081"
def get_zonefile( fqu, zonefile_hash ):
"""
Try to get a zonefile, from onename.com
Return the zonefile (serialized as a string) on success
Return None on error
"""
fqu_json = fqu.split(".")[0] + ".json"
url = "%s/%s" % (RESOLVER_URL, fqu_json)
req = requests.get(url)
if req.status_code != 200:
log.debug("GET %s status code %s" % (url, req.status_code))
return None
try:
res = json.loads(req.content)
except Exception, e:
log.exception(e)
log.debug("Failed to parse request to %s" % url)
return None
if 'zone_file' not in res.keys():
log.debug("No zonefile in request to %s" % url)
return None
zone_file_str = str(res['zone_file'])
if pybitcoin.hex_hash160( zone_file_str ) != zonefile_hash:
log.debug("Hash mismatch: expected %s, got %s" % (zonefile_hash, pybitcoin.hex_hash160(zone_file_str)))
return None
return zone_file_str
def get_profile( fqu ):
"""
Try to get a profile, from S3
"""
url = "%s/%s" % (STORAGE_URL, fqu)
req = requests.get(url)
if req.status_code != 200:
log.debug("GET %s status code %s" % (url, req.status_code))
return None
try:
res = json.loads(req.content)
except Exception, e:
log.exception(e)
log.debug("Failed to parse request to %s" % url)
return None
try:
res = res[0]
except:
log.debug("JWT is not a list")
return None
for k in ['token', 'parentPublicKey']:
if k not in res.keys():
log.debug("Missing required key '%s' in request to %s" % (k, url))
return None
ret = {}
ret['token'] = res['token']
ret['parentPublicKey'] = res['parentPublicKey']
return json.dumps([ret])
def storage_init(conf):
# read config options from the config file, if given
global STORAGE_URL, RESOLVER_URL
config_path = conf['path']
if os.path.exists( config_path ):
parser = SafeConfigParser()
try:
parser.read(config_path)
except Exception, e:
log.exception(e)
return False
if parser.has_section('blockstack-resolver-storage'):
if parser.has_option('blockstack-resolver-storage', 'storage_url'):
SERVER_NAME = parser.get('blockstack-resolver-storage', 'storage_url')
if parser.has_option('blockstack-resolver-storage', 'resolver_url'):
SERVER_PORT = int(parser.get('blockstack-resolver-storage', 'resolver_url'))
# we can't proceed unless we have them.
if STORAGE_URL is None or RESOLVER_URL is None:
log.error("Config file '%s': section 'blockstack_resolver_storage' is missing 'resolver_url' and/or 'storage_url'")
return False
return True
def handles_url( url ):
if RESOLVER_URL in url or STORAGE_URL in url:
return True
else:
return False
def make_mutable_url( data_id ):
# only deal with names
if ':' in data_id:
return None
else:
return "%s/%s" % (STORAGE_URL, data_id)
def get_immutable_handler( key, **kw ):
# only works for zonefiles, and we need the name
if 'zonefile' in kw and not kw['zonefile']:
return None
fqu = kw.get('fqu', None)
if fqu is None:
return None
return get_zonefile( fqu, key )
def get_mutable_handler( url, **kw ):
# only works for profiles
fqu = kw.get('fqu', None)
if fqu is None:
return None
return get_profile( fqu )
def put_immutable_handler( key, data, txid, **kw ):
# read only
return False
def put_mutable_handler( data_id, data_bin, **kw ):
# read only
return False
def delete_immutable_handler( key, txid, sig_key_txid, **kw ):
return True
def delete_mutable_handler( data_id, signature, **kw ):
return True