def file_key_retire( blockchain_id, file_key, config_path=CONFIG_PATH, wallet_keys=None ):
    """
    Retire the given key.  Move it to the head of the old key bundle list
    @file_key should be data returned by file_key_lookup
    Return {'status': True} on success
    Return {'error': ...} on error
    """

    config_dir = os.path.dirname(config_path)
    url = file_url_expired_keys( blockchain_id )
    proxy = blockstack_client.get_default_proxy( config_path=config_path )
        
    old_key_bundle_res = blockstack_client.data_get( url, wallet_keys=wallet_keys, proxy=proxy )
    if 'error' in old_key_bundle_res:
        log.warn('Failed to get old key bundle: %s' % old_key_bundle_res['error'])
        old_key_list = []

    else:
        old_key_list = old_key_bundle_res['data']['old_keys']
        for old_key in old_key_list:
            if old_key['key_id'] == file_key['key_id']:
                # already present 
                log.warning("Key %s is already retired" % file_key['key_id'])
                return {'status': True}

    old_key_list.insert(0, file_key )

    res = blockstack_client.data_put( url, {'old_keys': old_key_list}, wallet_keys=wallet_keys, proxy=proxy )
    if 'error' in res:
        log.error("Failed to append to expired key bundle: %s" % res['error'])
        return {'error': 'Failed to append to expired key list'}

    return {'status': True}
Exemplo n.º 2
0
def file_get(blockchain_id,
             hostname,
             sender_blockchain_id,
             data_name,
             output_path,
             passphrase=None,
             config_path=CONFIG_PATH,
             wallet_keys=None):
    """
    Get a file from a known sender.
    Store it to output_path
    Return {'status': True} on success
    Return {'error': error} on failure
    """

    config_dir = os.path.dirname(config_path)
    client_config_path = os.path.join(config_dir,
                                      blockstack_client.CONFIG_FILENAME)
    proxy = blockstack_client.get_default_proxy(config_path=client_config_path)

    # get the ciphertext
    fq_data_name = file_fq_data_name(data_name)
    res = blockstack_client.data_get(blockstack_client.make_mutable_data_url(
        sender_blockchain_id, fq_data_name, None),
                                     wallet_keys=wallet_keys,
                                     proxy=proxy)
    if 'error' in res:
        log.error("Failed to get ciphertext for %s: %s" %
                  (fq_data_name, res['error']))
        return {'error': 'Failed to get encrypted file'}

    # stash
    fd, path = tempfile.mkstemp(prefix="blockstack-file-")
    f = os.fdopen(fd, "w")
    f.write(res['data']['ciphertext'])
    f.flush()
    os.fsync(f.fileno())
    f.close()

    sender_key_id = res['data']['sender_key_id']

    # decrypt it
    res = file_decrypt(blockchain_id,
                       hostname,
                       sender_blockchain_id,
                       sender_key_id,
                       path,
                       output_path,
                       passphrase=passphrase,
                       config_path=config_path,
                       wallet_keys=wallet_keys)
    os.unlink(path)
    if 'error' in res:
        log.error("Failed to decrypt: %s" % res['error'])
        return {'error': 'Failed to decrypt data'}

    else:
        # success!
        return res
def file_get( blockchain_id, hostname, sender_blockchain_id, data_name, output_path, passphrase=None, config_path=CONFIG_PATH, wallet_keys=None ):
    """
    Get a file from a known sender.
    Store it to output_path
    Return {'status': True} on success
    Return {'error': error} on failure
    """
  
    config_dir = os.path.dirname(config_path)
    client_config_path = os.path.join(config_dir, blockstack_client.CONFIG_FILENAME )
    proxy = blockstack_client.get_default_proxy( config_path=client_config_path )

    # get the ciphertext
    fq_data_name = file_fq_data_name( data_name ) 
    res = blockstack_client.data_get( blockstack_client.make_mutable_data_url( sender_blockchain_id, fq_data_name, None ), wallet_keys=wallet_keys, proxy=proxy )
    if 'error' in res:
        log.error("Failed to get ciphertext for %s: %s" % (fq_data_name, res['error']))
        return {'error': 'Failed to get encrypted file'}

    # stash
    fd, path = tempfile.mkstemp( prefix="blockstack-file-" )
    f = os.fdopen(fd, "w")
    f.write( res['data']['ciphertext'] )
    f.flush()
    os.fsync(f.fileno())
    f.close()

    sender_key_id = res['data']['sender_key_id']

    # decrypt it
    res = file_decrypt( blockchain_id, hostname, sender_blockchain_id, sender_key_id, path, output_path, passphrase=passphrase, config_path=config_path, wallet_keys=wallet_keys )
    os.unlink( path )
    if 'error' in res:
        log.error("Failed to decrypt: %s" % res['error'])
        return {'error': 'Failed to decrypt data'}

    else:
        # success!
        return res
Exemplo n.º 4
0
def app_download( sender_blockchain_id, appname, config_path=CONFIG_PATH, wallet_keys=None, version=None, appdir=None ):
    """
    Fetch the application to a temporary location on disk.
    Verify that it was signed by its creator.
    Decompress the contents.
    Return {'status': True, 'root': path, 'tag': version or hash} on success
    Return {'error': ...} on error
    """
     
    config_dir = os.path.dirname(config_path)
    cache_dir = os.path.join( config_dir, CACHE_DIRNAME )
    client_config_path = os.path.join(config_dir, blockstack_client.CONFIG_FILENAME )
    file_config_path = os.path.join(config_dir, blockstack_file.CONFIG_PATH )

    proxy = blockstack_client.get_default_proxy( config_path=client_config_path )

    if appdir is None:
        appdir = tempfile.mkdtemp(dir=cache_dir)

    # get the app data
    fq_data_name = app_fq_data_name( appname ) 
    res = blockstack_client.data_get( blockstack_client.make_mutable_data_url( sender_blockchain_id, fq_data_name, version ), wallet_keys=wallet_keys, proxy=proxy )
    if 'error' in res:
        log.error("Failed to get data for %s: %s" % (fq_data_name, res['error']))
        return {'error': 'Failed to get app data'}

    tag = res.get('version', None)
    if tag is None:
        tag = res.get('hash', None)
        if tag is None:
            log.error("Missing version or hash")
            return {'error': "Missing version or hash"}
    
    # stash
    fd, path = tempfile.mkstemp( prefix="blockstack-app-download-", dir=cache_dir )
    log.debug("Stash app data to %s" % path)
    f = os.fdopen(fd, "w")
    f.write( base64.b64decode(res['data']['app']) )
    f.flush()
    os.fsync(f.fileno())
    f.close()

    sender_key_id = res['data']['sender_key_id']
    sig = res['data']['sig']

    # verify it
    res = blockstack_file.file_verify( sender_blockchain_id, sender_key_id, path, sig, config_path=client_config_path, wallet_keys=wallet_keys )
    if 'error' in res:
        log.error("Failed to verify: %s" % res['error'])
        return {'error': 'Failed to verify app data'}

    # decompress it 
    try:
        ziph = zipfile.ZipFile( path, 'r', zipfile.ZIP_DEFLATED )
        ziph.extractall( path=appdir )
        ziph.close()

        log.debug("Extracted app to '%s'" % appdir)

    except zipfile.BadZipfile:
        log.error("Bad zipfile")
        return {'error': 'Bad zipfile'}
    except Exception, e:
        log.exception(e)
        return {'error': 'Failed to extract'}
Exemplo n.º 5
0
def file_key_lookup(blockchain_id,
                    index,
                    hostname,
                    key_id=None,
                    config_path=CONFIG_PATH,
                    wallet_keys=None):
    """
    Get the file-encryption GPG key for the given blockchain ID, by index.

    if index == 0, then give back the current key
    if index > 0, then give back an older (revoked) key.
    if key_id is given, index and hostname will be ignored

    Return {'status': True, 'key_data': ..., 'key_id': key_id, OPTIONAL['stale_key_index': idx]} on success
    Return {'error': ...} on failure
    """

    log.debug("lookup '%s' key for %s (index %s, key_id = %s)" %
              (hostname, blockchain_id, index, key_id))
    conf = get_config(config_path)
    config_dir = os.path.dirname(config_path)

    proxy = blockstack_client.get_default_proxy(config_path=config_path)
    immutable = conf['immutable_key']

    if key_id is not None:
        # we know exactly which key to get
        # try each current key
        hosts_listing = file_list_hosts(blockchain_id,
                                        wallet_keys=wallet_keys,
                                        config_path=config_path)
        if 'error' in hosts_listing:
            log.error("Failed to list hosts for %s: %s" %
                      (blockchain_id, hosts_listing['error']))
            return {'error': 'Failed to look up hosts'}

        hosts = hosts_listing['hosts']
        for hostname in hosts:
            file_key = blockstack_gpg.gpg_app_get_key(blockchain_id,
                                                      APP_NAME,
                                                      hostname,
                                                      immutable=immutable,
                                                      key_id=key_id,
                                                      config_dir=config_dir)
            if 'error' not in file_key:
                if key_id == file_key['key_id']:
                    # success!
                    return file_key

        # check previous keys...
        url = file_url_expired_keys(blockchain_id)
        old_key_bundle_res = blockstack_client.data_get(
            url, wallet_keys=wallet_keys, proxy=proxy)
        if 'error' in old_key_bundle_res:
            return old_key_bundle_res

        old_key_list = old_key_bundle_res['data']['old_keys']
        for i in xrange(0, len(old_key_list)):
            old_key = old_key_list[i]
            if old_key['key_id'] == key_id:
                # success!
                ret = {}
                ret.update(old_key)
                ret['stale_key_index'] = i + 1
                return old_key

        return {'error': 'No such key %s' % key_id}

    elif index == 0:
        file_key = blockstack_gpg.gpg_app_get_key(blockchain_id,
                                                  APP_NAME,
                                                  hostname,
                                                  immutable=immutable,
                                                  key_id=key_id,
                                                  config_dir=config_dir)
        if 'error' in file_key:
            return file_key

        return file_key

    else:
        # get the bundle of revoked keys
        url = file_url_expired_keys(blockchain_id)
        old_key_bundle_res = blockstack_client.data_get(
            url, wallet_keys=wallet_keys, proxy=proxy)
        if 'error' in old_key_bundle_res:
            return old_key_bundle_res

        old_key_list = old_key_bundle_res['data']['old_keys']
        if index >= len(old_key_list) + 1:
            return {'error': 'Index out of bounds: %s' % index}

        return old_key_list[index - 1]
def file_key_lookup( blockchain_id, index, hostname, key_id=None, config_path=CONFIG_PATH, wallet_keys=None ):
    """
    Get the file-encryption GPG key for the given blockchain ID, by index.

    if index == 0, then give back the current key
    if index > 0, then give back an older (revoked) key.
    if key_id is given, index and hostname will be ignored

    Return {'status': True, 'key_data': ..., 'key_id': key_id, OPTIONAL['stale_key_index': idx]} on success
    Return {'error': ...} on failure
    """

    log.debug("lookup '%s' key for %s (index %s, key_id = %s)" % (hostname, blockchain_id, index, key_id))
    conf = get_config( config_path )
    config_dir = os.path.dirname(config_path)
    
    proxy = blockstack_client.get_default_proxy( config_path=config_path )
    immutable = conf['immutable_key']

    if key_id is not None:
        # we know exactly which key to get 
        # try each current key 
        hosts_listing = file_list_hosts( blockchain_id, wallet_keys=wallet_keys, config_path=config_path )
        if 'error' in hosts_listing:
            log.error("Failed to list hosts for %s: %s" % (blockchain_id, hosts_listing['error']))
            return {'error': 'Failed to look up hosts'}

        hosts = hosts_listing['hosts']
        for hostname in hosts:
            file_key = blockstack_gpg.gpg_app_get_key( blockchain_id, APP_NAME, hostname, immutable=immutable, key_id=key_id, config_dir=config_dir )
            if 'error' not in file_key:
                if key_id == file_key['key_id']:
                    # success!
                    return file_key

        # check previous keys...
        url = file_url_expired_keys( blockchain_id )
        old_key_bundle_res = blockstack_client.data_get( url, wallet_keys=wallet_keys, proxy=proxy )
        if 'error' in old_key_bundle_res:
            return old_key_bundle_res

        old_key_list = old_key_bundle_res['data']['old_keys']
        for i in xrange(0, len(old_key_list)):
            old_key = old_key_list[i]
            if old_key['key_id'] == key_id:
                # success!
                ret = {}
                ret.update( old_key )
                ret['stale_key_index'] = i+1 
                return old_key

        return {'error': 'No such key %s' % key_id}

    elif index == 0:
        file_key = blockstack_gpg.gpg_app_get_key( blockchain_id, APP_NAME, hostname, immutable=immutable, key_id=key_id, config_dir=config_dir )
        if 'error' in file_key:
            return file_key

        return file_key
    
    else:
        # get the bundle of revoked keys
        url = file_url_expired_keys( blockchain_id )
        old_key_bundle_res = blockstack_client.data_get( url, wallet_keys=wallet_keys, proxy=proxy )
        if 'error' in old_key_bundle_res:
            return old_key_bundle_res

        old_key_list = old_key_bundle_res['data']['old_keys']
        if index >= len(old_key_list)+1:
            return {'error': 'Index out of bounds: %s' % index}

        return old_key_list[index-1]