Example #1
0
def file_url_expired_keys(blockchain_id):
    """
    Make a URL to the expired key list
    """
    url = blockstack_client.make_mutable_data_url(blockchain_id,
                                                  "%s-old" % APP_NAME, None)
    return url
Example #2
0
def file_delete(blockchain_id,
                data_name,
                config_path=CONFIG_PATH,
                wallet_keys=None):
    """
    Remove a file
    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)

    fq_data_name = file_fq_data_name(data_name)
    res = blockstack_client.data_delete(
        blockstack_client.make_mutable_data_url(blockchain_id, fq_data_name,
                                                None),
        proxy=proxy,
        wallet_keys=wallet_keys)
    if 'error' in res:
        log.error("Failed to delete: %s" % res['error'])
        return {'error': 'Failed to delete'}

    return {'status': True}
Example #3
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
Example #4
0
def gpg_list_app_keys(blockchain_id,
                      appname,
                      proxy=None,
                      wallet_keys=None,
                      config_dir=None):
    """
    List the set of available GPG keys tagged for a given application.
    Return list of {'keyName': key name, 'contentUrl': URL to key data}
    Raise on error
    """

    assert is_valid_appname(appname)

    config_dir = get_config_dir(config_dir)
    client_config_path = os.path.join(config_dir,
                                      blockstack_client.CONFIG_FILENAME)

    if proxy is None:
        proxy = blockstack_client.get_default_proxy(
            config_path=client_config_path)

    key_info = []
    key_prefix = "gpg.%s." % appname

    # immutable data key listing (look for keys that start with 'appname:')
    immutable_listing = list_immutable_data(blockchain_id, proxy=proxy)
    if 'error' in immutable_listing:
        raise Exception("Blockstack error: %s" % immutable_listing['error'])

    for immutable in immutable_listing['data']:
        name = immutable['data_id']
        data_hash = immutable['hash']
        if name.startswith(key_prefix):
            key_info.append({
                'keyName':
                name[len(key_prefix):],
                'contentUrl':
                make_immutable_data_url(blockchain_id, name, data_hash)
            })

    # mutable data key listing (look for keys that start with 'appname:')
    mutable_listing = list_mutable_data(blockchain_id,
                                        proxy=proxy,
                                        wallet_keys=wallet_keys)
    if 'error' in mutable_listing:
        raise Exception("Blockstack error: %s" % mutable_listing['error'])

    for mutable in mutable_listing['data']:
        name = mutable['data_id']
        version = mutable['version']
        if name.startswith(key_prefix):
            key_info.append({
                'keyName':
                name[len(key_prefix):],
                'contentUrl':
                make_mutable_data_url(blockchain_id, name, version)
            })

    return key_info
Example #5
0
def gpg_app_get_key(blockchain_id,
                    appname,
                    keyname,
                    immutable=False,
                    key_id=None,
                    key_hash=None,
                    key_version=None,
                    proxy=None,
                    config_dir=None):
    """
    Get an app-specific GPG key.
    Return {'status': True, 'key_id': ..., 'key': ..., 'app_name': ...} on success
    return {'error': ...} on error
    """

    assert is_valid_appname(appname)
    assert is_valid_keyname(keyname)

    if config_dir is None:
        config_dir = get_config_dir()

    fq_key_name = "gpg.%s.%s" % (appname, keyname)
    key_url = None

    if immutable:
        # try immutable
        key_url = blockstack_client.make_immutable_data_url(
            blockchain_id, fq_key_name, key_hash)

    else:
        # try mutable
        key_url = blockstack_client.make_mutable_data_url(
            blockchain_id, fq_key_name, key_version)

    log.debug("fetch '%s'" % key_url)
    key_data = gpg_fetch_key(key_url, key_id=key_id, config_dir=config_dir)
    if key_data is None:
        return {'error': 'Failed to fetch key'}

    if key_id is None:
        key_id = gpg_key_fingerprint(key_data, config_dir=config_dir)

    ret = {
        'status': True,
        'key_id': key_id,
        'key_data': key_data,
        'app_name': appname
    }

    return ret
Example #6
0
def gpg_list_app_keys( blockchain_id, appname, proxy=None, wallet_keys=None, config_dir=None ):
    """
    List the set of available GPG keys tagged for a given application.
    Return list of {'keyName': key name, 'contentUrl': URL to key data}
    Raise on error
    """

    raise Exception("BROKEN; depends on list_mutable_data")

    assert is_valid_appname(appname)

    config_dir = get_config_dir( config_dir )
    client_config_path = os.path.join(config_dir, blockstack_client.CONFIG_FILENAME )

    if proxy is None:
        proxy = blockstack_client.get_default_proxy( config_path=client_config_path )

    key_info = []
    key_prefix = "gpg.%s." % appname

    # immutable data key listing (look for keys that start with 'appname:')
    immutable_listing = list_immutable_data( blockchain_id, proxy=proxy )
    if 'error' in immutable_listing:
        raise Exception("Blockstack error: %s" % immutable_listing['error'])

    for immutable in immutable_listing['data']:
        name = immutable['data_id']
        data_hash = immutable['hash']
        if name.startswith( key_prefix ):
            key_info.append( {
                'keyName': name[len(key_prefix):],
                'contentUrl': make_immutable_data_url( blockchain_id, name, data_hash )
            })

    # mutable data key listing (look for keys that start with 'appname:')
    # TODO: use 'accounts'
    mutable_listing = list_mutable_data( blockchain_id, proxy=proxy, wallet_keys=wallet_keys )
    if 'error' in mutable_listing:
        raise Exception("Blockstack error: %s" % mutable_listing['error'])

    for mutable in mutable_listing['data']:
        name = mutable['data_id']
        version = mutable['version']
        if name.startswith( key_prefix ):
            key_info.append( {
                'keyName': name[len(key_prefix):],
                'contentUrl': make_mutable_data_url( blockchain_id, name, version )
            })

    return key_info
Example #7
0
def gpg_list_app_keys(blockchain_id, appname, proxy=None, wallet_keys=None):
    """
    List the set of available GPG keys tagged for a given application.
    The keys will have the format:
        gpg/appname/keyname

    Return list of {'identifier': key ID, 'contentUrl': URL to key data}
    Raise on error
    """

    key_info = []
    key_prefix = "gpg/%s/" % appname

    # immutable data key listing (look for keys that start with 'appname:')
    immutable_listing = list_immutable_data(blockchain_id, proxy=proxy)
    if 'error' in immutable_listing:
        raise Exception("Blockstack error: %s" % key_listing['error'])

    for immutable in immutable_listing['data']:
        name = immutable['data_id']
        data_hash = immutable['hash']
        if name.startswith(key_prefix):
            key_info.append({
                'identifier':
                name,
                'contentUrl':
                make_immutable_data_url(blockchain_id, name, data_hash)
            })

    # mutable data key listing (look for keys that start with 'appname:')
    mutable_listing = list_mutable_data(blockchain_id,
                                        proxy=proxy,
                                        wallet_keys=wallet_keys)
    if 'error' in mutable_listing:
        raise Exception("Blockstack error: %s" % mutable_listing['error'])

    for mutable in mutable_listing['data']:
        name = mutable['data_id']
        version = mutable['version']
        if name.startswith(key_prefix):
            key_info.append({
                'identifier':
                name,
                'contentUrl':
                make_mutable_data_url(blockchain_id, name, version)
            })

    return key_info
def file_delete( blockchain_id, data_name, config_path=CONFIG_PATH, wallet_keys=None ):
    """
    Remove a file
    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 )

    fq_data_name = file_fq_data_name( data_name ) 
    res = blockstack_client.data_delete( blockstack_client.make_mutable_data_url( blockchain_id, fq_data_name, None ), proxy=proxy, wallet_keys=wallet_keys )
    if 'error' in res:
        log.error("Failed to delete: %s" % res['error'])
        return {'error': 'Failed to delete'}

    return {'status': True}
Example #9
0
def gpg_app_get_key( blockchain_id, appname, keyname, immutable=False, key_id=None, key_hash=None, key_version=None, proxy=None, config_dir=None ):
    """
    Get an app-specific GPG key.
    Return {'status': True, 'key_id': ..., 'key': ..., 'app_name': ...} on success
    return {'error': ...} on error
    """

    assert is_valid_appname(appname)
    assert is_valid_keyname(keyname)

    if config_dir is None:
        config_dir = get_config_dir()

    fq_key_name = "gpg.%s.%s" % (appname, keyname)
    key_url = None 

    if immutable:
        # try immutable
        key_url = blockstack_client.make_immutable_data_url( blockchain_id, fq_key_name, key_hash )

    else:
        # try mutable 
        key_url = blockstack_client.make_mutable_data_url( blockchain_id, fq_key_name, key_version )

    log.debug("fetch '%s'" % key_url)
    key_data = gpg_fetch_key( key_url, key_id, config_dir=config_dir )
    if key_data is None:
        return {'error': 'Failed to fetch key'}

    if key_id is None:
        key_id = gpg_key_fingerprint( key_data, config_dir=config_dir )

    ret = {
        'status': True,
        'key_id': key_id,
        'key_data': key_data,
        'app_name': appname
    }

    return ret
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
Example #11
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'}
Example #12
0
        return {'error': 'Failed to sign'}
   
    # replicate 
    app_bin = None
    with open(path, "r") as f:
        app_bin = f.read()

    data = {
        'sender_key_id': res['sender_key_id'],
        'sig': res['sig'],
        'app': base64.b64encode( app_bin )
    }

    fq_data_name = app_fq_data_name( app_name )
    proxy = blockstack_client.get_default_proxy( config_path=client_config_path )
    res = blockstack_client.data_put( blockstack_client.make_mutable_data_url( sender_blockchain_id, fq_data_name, version ), data, wallet_keys=wallet_keys, proxy=proxy )
    if 'error' in res:
        log.error("Failed to upload app '%s': %s" % (fq_data_name, res['error']))
        return {'error': 'Failed to upload data'}

    return {'status': True, 'sender_key_id': data['sender_key_id'], 'sig': data['sig']}



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
Example #13
0
def file_put(blockchain_id,
             hostname,
             recipient_blockchain_ids,
             data_name,
             input_path,
             passphrase=None,
             config_path=CONFIG_PATH,
             wallet_keys=None):
    """
    Send a file to the given recipient, encrypted and signed with the
    given blockchain ID.
    Allow each recipient to receive the data on each of their hosts.
    Return {'status': True} on success, and upload to cloud storage
    Return {'error': ...} on error
    """
    fd, output_path = tempfile.mkstemp(prefix="blockstack-file-")
    os.fchmod(fd, 0600)
    os.close(fd)

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

    all_recipients = []

    # make available to all other hosts for this blockchain_id
    my_hosts = file_list_hosts(blockchain_id,
                               wallet_keys=wallet_keys,
                               config_path=config_path)
    if 'error' in my_hosts:
        log.error("Failed to list hosts: %s" % my_hosts['error'])
        os.unlink(output_path)
        return {'error': 'Failed to look up sender keys'}

    if hostname in my_hosts:
        my_hosts.remove(hostname)

    all_recipients += [(blockchain_id, host) for host in my_hosts['hosts']]

    # make available to all hosts for each recipient
    for recipient_blockchain_id in recipient_blockchain_ids:
        their_hosts = file_list_hosts(recipient_blockchain_id,
                                      wallet_keys=wallet_keys,
                                      config_path=config_path)
        if 'error' in their_hosts:
            log.error("Failed to list hosts for %s: %s" %
                      (recipient_blockchain_id, their_hosts['error']))
            os.unlink(output_path)
            return {'error': 'Failed to look up recipient keys'}

        all_recipients += [(recipient_blockchain_id, host)
                           for host in their_hosts['hosts']]

    # encrypt
    res = file_encrypt(blockchain_id,
                       hostname,
                       all_recipients,
                       input_path,
                       output_path,
                       passphrase=passphrase,
                       config_path=config_path,
                       wallet_keys=wallet_keys)
    if 'error' in res:
        log.error("Failed to encrypt: %s" % res['error'])
        os.unlink(output_path)
        return {'error': 'Failed to encrypt'}

    # load up
    with open(output_path, "r") as f:
        ciphertext = f.read()

    message = {'ciphertext': ciphertext, 'sender_key_id': res['sender_key_id']}

    # put to mutable storage
    fq_data_name = file_fq_data_name(data_name)
    proxy = blockstack_client.get_default_proxy(config_path=client_config_path)

    res = blockstack_client.data_put(blockstack_client.make_mutable_data_url(
        blockchain_id, fq_data_name, None),
                                     message,
                                     wallet_keys=wallet_keys,
                                     proxy=proxy)
    if 'error' in res:
        log.error("Failed to put data: %s" % res['error'])
        os.unlink(output_path)
        return {'error': 'Failed to replicate data'}

    os.unlink(output_path)
    return {'status': True}
def file_put( blockchain_id, hostname, recipient_blockchain_ids, data_name, input_path, passphrase=None, config_path=CONFIG_PATH, wallet_keys=None ):
    """
    Send a file to the given recipient, encrypted and signed with the
    given blockchain ID.
    Allow each recipient to receive the data on each of their hosts.
    Return {'status': True} on success, and upload to cloud storage
    Return {'error': ...} on error
    """
    fd, output_path = tempfile.mkstemp( prefix="blockstack-file-" )
    os.fchmod( fd, 0600 )
    os.close(fd)

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

    all_recipients = []
    
    # make available to all other hosts for this blockchain_id
    my_hosts = file_list_hosts( blockchain_id, wallet_keys=wallet_keys, config_path=config_path )
    if 'error' in my_hosts:
        log.error("Failed to list hosts: %s" % my_hosts['error'])
        os.unlink(output_path)
        return {'error': 'Failed to look up sender keys'}

    if hostname in my_hosts:
        my_hosts.remove(hostname)

    all_recipients += [(blockchain_id, host) for host in my_hosts['hosts']]

    # make available to all hosts for each recipient 
    for recipient_blockchain_id in recipient_blockchain_ids:
        their_hosts = file_list_hosts( recipient_blockchain_id, wallet_keys=wallet_keys, config_path=config_path )
        if 'error' in their_hosts:
            log.error("Failed to list hosts for %s: %s" % (recipient_blockchain_id, their_hosts['error']))
            os.unlink(output_path)
            return {'error': 'Failed to look up recipient keys'}

        all_recipients += [(recipient_blockchain_id, host) for host in their_hosts['hosts']]

    # encrypt
    res = file_encrypt( blockchain_id, hostname, all_recipients, input_path, output_path, passphrase=passphrase, config_path=config_path, wallet_keys=wallet_keys )
    if 'error' in res:
        log.error("Failed to encrypt: %s" % res['error'])
        os.unlink(output_path)
        return {'error': 'Failed to encrypt'}

    # load up 
    with open(output_path, "r") as f:
        ciphertext = f.read()

    message = {'ciphertext': ciphertext, 'sender_key_id': res['sender_key_id']}

    # put to mutable storage 
    fq_data_name = file_fq_data_name( data_name ) 
    proxy = blockstack_client.get_default_proxy( config_path=client_config_path )

    res = blockstack_client.data_put( blockstack_client.make_mutable_data_url( blockchain_id, fq_data_name, None ), message, wallet_keys=wallet_keys, proxy=proxy )
    if 'error' in res:
        log.error("Failed to put data: %s" % res['error'])
        os.unlink(output_path)
        return {'error': 'Failed to replicate data'}

    os.unlink(output_path)
    return {'status': True}
def file_url_expired_keys( blockchain_id ):
    """
    Make a URL to the expired key list
    """
    url = blockstack_client.make_mutable_data_url( blockchain_id, "%s-old" % APP_NAME, None )
    return url