def header(url, method, options=None):
    """
    :param uri: 'http://example.com/resource?a=b'
    :param method: HTTP verb ('GET', 'POST', etc)
    :param options:

    Required Options:
    credentials (id, key, algorithm)

    Optional:
    ext:
    Application specific data (string)
    timestamp:
    A pre-calculated timestamp
    nonce:
    '2334f34f':  A pre-generated nonce
    localtimeOffsetMsec:
    Time offset to sync with server time (ignored if timestamp
    provided) (Example 400)
    payload:
    UTF-8 encoded string for body hash generation (ignored if hash
    provided) (Example '{"some":"payload"}')
    contentType:
    Payload content-type (ignored if hash provided) (Example
    'application/json')
    hash:
    Pre-calculated payload hash (Example 'U4MKKSmiVxk37JCCrAVIjV=')
    app:
    Oz application id ('24s23423f34dx')
    dlg:
    Oz delegated-by application id - '234sz34tww3sd'
    """
    result = {'field': '', 'artifacts': {}}

    if url is None or len(url) == 0:
        log.info("Bad URL skipping")
        return result

    if method is None or len(method) == 0:
        log.info("Bad method skipping")
        return result

    if not isinstance(options, dict):
        log.info("Bad options skipping")
        return result

    if 'credentials' not in options:
        log.info("Bad credentials skipping")
        return result

    cred = options['credentials']
    if 'id' not in cred or 'key' not in cred or 'algorithm' not in cred:
        log.info("Bad credentail elements skipping")
        return result

    timestamp = math.floor(time.time())
    if 'timestamp' in options:
        offset = 0
        if 'localtimeOffsetMsec' in options:
            offset = int(options['localtimeOffsetMsec'])
        timestamp = math.floor(options['timestamp'] + offset)

    if 'nonce' not in options:
        options['nonce'] = hcrypto.random_string(6)

    url_parts = util.parse_normalized_url(url)

    # TODO use None or '' for these optional artifacts?
    if 'hash' not in options:
        options['hash'] = None
    if 'ext' not in options:
        options['ext'] = None
    if 'app' not in options:
        options['app'] = None
    if 'dlg' not in options:
        options['dlg'] = None

    resource = url_parts['resource']

    log.debug('parsed URL parts: %s' % pprint.pformat(url_parts))

    artifacts = {
        'ts': int(timestamp),
        'nonce': options['nonce'],
        'method': method,
        'resource': resource,
        'host': url_parts['hostname'],
        'port': url_parts['port'],
        'hash': options['hash'],
        'ext': options['ext'],
        'app': options['app'],
        'dlg': options['dlg']
    }

    result['artifacts'] = artifacts

    if artifacts['hash'] is None and 'payload' in options:
        if 'contentType' not in options:
            options['contentType'] = 'text/plain'
        log.debug('about to hash payload: %s' % options['payload'])
        log.debug('algorithm=%s, contentType=%s' %
                  (cred['algorithm'], options['contentType']))
        artifacts['hash'] = hcrypto.calculate_payload_hash(
            options['payload'], cred['algorithm'], options['contentType'])

    log.debug('artifacts=%s' % pprint.pformat(artifacts))

    mac = hcrypto.calculate_mac('header', cred, artifacts)

    _header = ''.join([
        'Hawk id="',
        cred['id'],
        '"',
        ', ts="',
        str(artifacts['ts']),
        '"',
        ', nonce="',
        artifacts['nonce'],
        '"',
    ])

    if len(artifacts['hash']) > 0:
        _header += ', hash="' + artifacts['hash'] + '"'

    if artifacts['ext'] is not None and len(artifacts['ext']) > 0:
        util.check_header_attribute(artifacts['ext'])
        h_ext = artifacts['ext'].replace('\\', '\\\\').replace('\n', '\\n')
        _header += ', ext="' + h_ext + '"'

    _header += ', mac="' + mac + '"'

    if artifacts['app'] is not None:
        _header += ', app="' + artifacts['app'] + '"'
        if artifacts['dlg'] is not None:
            _header += ', dlg="' + artifacts['dlg'] + '"'

    result['field'] = _header

    return result
Beispiel #2
0
def before_insert_posts(documents):
    meta_post = current_app.config.get('META_POST')
    posts_endpoint = meta_post['server']['urls']['posts_feed']
    app_type = str(url_for('server_info.types_item', name='app', _external=True))
    credentials_type = str(url_for('server_info.types_item', name='credentials', _external=True))
    
    for document in documents:
        # Create version information, but save app version data if present
        current_time = time.time()
        time_seconds = int(current_time)
        time_millisec = int(current_time * 1000)
        time_microsec = int(current_time * 1000000)
        app_version = get_app_version(document)
        digest = create_version_digest(document)
        document['version'] = create_version_document(digest, time_millisec, app_version)
        
        # Create an ID for the document
        if document['type'] == credentials_type:
            # Since credentials posts are created automatically by the server,
            # we need to specify their IDs in microseconds
            document['_id'] = str(NewBase60(time_microsec))
        else:
            document['_id'] = str(NewBase60(time_seconds))
        
        # Additional processing for certain post types
        if document['type'] == app_type:
            # For app posts, we must create an additional credentials post
            # and make sure they link to each other
            hawk_key = str(random_string(64))
            hawk_algorithm = 'sha256'
            credentials_post = {
                'entity': str(meta_post['entity']),
                'type': credentials_type,
                'content': {
                    'hawk_key': hawk_key,
                    'hawk_algorithm': hawk_algorithm
                },
                'links': [
                    {
                        'post': str(document['_id']),
                        'url': str(posts_endpoint + "/" + document['_id']),
                        'type': app_type
                    }
                ]
            }
            response, _, _, status = post_internal('posts', credentials_post)
            if not 'links' in document:
                document['links'] = []
            cred_id = str(response['_id'])
            cred_url = str(posts_endpoint + "/" + cred_id)
            document['links'].append({
                    'post': cred_id,
                    'url': cred_url,
                    'type': credentials_type
                })
            # Create a signal to change the POST response envelope
            g.app_POST = True
            credentials = {
                'id': cred_id,
                'key': hawk_key,
                'algorithm': hawk_algorithm
            }
            g.cred_bewit_url = cred_url + '?bewit=' + hawk_get_bewit(cred_url, {'credentials': credentials, 'ttl_sec': BEWIT_TTL})
Beispiel #3
0
def header(url, method, options=None):
    """
    :param uri: 'http://example.com/resource?a=b'
    :param method: HTTP verb ('GET', 'POST', etc)
    :param options:

    Required Options:
    credentials (id, key, algorithm)

    Optional:
    ext:
    Application specific data (string)
    timestamp:
    A pre-calculated timestamp
    nonce:
    '2334f34f':  A pre-generated nonce
    localtimeOffsetMsec:
    Time offset to sync with server time (ignored if timestamp
    provided) (Example 400)
    payload:
    UTF-8 encoded string for body hash generation (ignored if hash
    provided) (Example '{"some":"payload"}')
    contentType:
    Payload content-type (ignored if hash provided) (Example
    'application/json')
    hash:
    Pre-calculated payload hash (Example 'U4MKKSmiVxk37JCCrAVIjV=')
    app:
    Oz application id ('24s23423f34dx')
    dlg:
    Oz delegated-by application id - '234sz34tww3sd'
    """
    result = {'field': '', 'artifacts': {}}

    if url is None or len(url) == 0:
        print "Bad URL skipping"
        return result

    if method is None or len(method) == 0:
        print "Bad method skipping"
        return result

    if not isinstance(options, dict):
        print "Bad options skipping"
        return result

    if 'credentials' not in options:
        print "Bad credentials skipping"
        return result

    cred = options['credentials']
    if 'id' not in cred or 'key' not in cred or 'algorithm' not in cred:
        print "Bad credentail elements skipping"
        return result

    timestamp = math.floor(time.time())
    if 'timestamp' in options:
        offset = 0
        if 'localtimeOffsetMsec' in options:
            offset = int(options['localtimeOffsetMsec'])
        timestamp = math.floor(options['timestamp'] + offset)

    if 'nonce' not in options:
        options['nonce'] = hcrypto.random_string(6)

    url_parts = parse_normalized_url(url)

    # TODO use None or '' for these optional artifacts?
    if 'hash' not in options:
        options['hash'] = None
    if 'ext' not in options:
        options['ext'] = None
    if 'app' not in options:
        options['app'] = None
    if 'dlg' not in options:
        options['dlg'] = None

    resource = url_parts['path']
    if len(url_parts['query']) > 0:
        resource += '?' + url_parts['query']

    artifacts = {
        'ts': int(timestamp),
        'nonce': options['nonce'],
        'method': method,
        'resource': resource,
        'host': url_parts['hostname'],
        'port': url_parts['port'],
        'hash': options['hash'],
        'ext': options['ext'],
        'app': options['app'],
        'dlg': options['dlg']
    }

    result['artifacts'] = artifacts

    if artifacts['hash'] is None and 'payload' in options:
        if 'contentType' not in options:
            options['contentType'] = 'text/plain'
        artifacts['hash'] = hcrypto.calculate_payload_hash(
               options['payload'], cred['algorithm'], options['contentType'])

    mac = hcrypto.calculate_mac('header', cred, artifacts)

    _header = ''.join([
        'Hawk id="', cred['id'], '"',
        ', ts="', str(artifacts['ts']), '"',
        ', nonce="', artifacts['nonce'], '"',
    ])

    if len(artifacts['hash']) > 0:
        _header += ', hash="' + artifacts['hash'] + '"'

    if artifacts['ext'] is not None and len(artifacts['ext']) > 0:
        util.check_header_attribute(artifacts['ext'])
        h_ext = artifacts['ext'].replace('\\', '\\\\').replace('\n', '\\n')
        _header += ', ext="' + h_ext + '"'

    _header += ', mac="' + mac + '"'

    if artifacts['app'] is not None:
        _header += ', app="' + artifacts['app'] + '"'
        if artifacts['dlg'] is not None:
            _header += ', dlg="' + artifacts['dlg'] + '"'

    result['field'] = _header

    return result