<commit_before># -*- coding: utf-8 -*-

from __future__ import print_function, absolute_import, unicode_literals

import struct
import json
import base64
from flask import Blueprint, session, Response
from flask import current_app, request

from fido2.client import ClientData
from fido2.server import Fido2Server, RelyingParty
from fido2.ctap2 import AttestationObject
from fido2 import cbor
from fido2.utils import websafe_encode
from fido2.ctap2 import AttestedCredentialData

from cryptography import x509
from cryptography.hazmat.backends import default_backend
from OpenSSL import crypto

from eduid_userdb.credentials import Webauthn
from eduid_userdb.security import SecurityUser
from eduid_common.api.decorators import require_user, MarshalWith, UnmarshalWith
from eduid_common.api.utils import save_and_sync_user
from eduid_common.api.schemas.base import FluxStandardAction
from eduid_webapp.security.helpers import credentials_to_registered_keys, compile_credential_list
from eduid_webapp.security.schemas import WebauthnOptionsResponseSchema, WebauthnRegisterRequestSchema
from eduid_webapp.security.schemas import SecurityResponseSchema, RemoveWebauthnTokenRequestSchema
from eduid_webapp.security.schemas import VerifyWithWebauthnTokenRequestSchema
from eduid_webapp.security.schemas import VerifyWithWebauthnTokenResponseSchema


def get_webauthn_server(rp_id, name='eduID security API'):
    rp = RelyingParty(rp_id, name)
    return Fido2Server(rp)


def make_credentials(creds):
    credentials = []
    for cred in creds:
        cred_data = base64.b64decode(cred.credential_data.encode('ascii'))
        credential_data, rest = AttestedCredentialData.unpack_from(cred_data)
        if rest:
            continue
        credentials.append(credential_data)
    return credentials


webauthn_views = Blueprint('webauthn', __name__, url_prefix='/webauthn', template_folder='templates')

@webauthn_views.route('/register/begin', methods=['GET'])
@MarshalWith(FluxStandardAction)
@require_user
def registration_begin(user):
    user_webauthn_tokens = user.credentials.filter(Webauthn)
    if user_webauthn_tokens.count >= current_app.config['WEBAUTHN_MAX_ALLOWED_TOKENS']:
        current_app.logger.error('User tried to register more than {} tokens.'.format(
            current_app.config['WEBAUTHN_MAX_ALLOWED_TOKENS']))
        return {'_status': 'error', 'message': 'security.webauthn.max_allowed_tokens'}
    creds = make_credentials(user_webauthn_tokens.to_list())
    server = get_webauthn_server(current_app.config['FIDO2_RP_ID'])
    if user.given_name is None or user.surname is None or user.display_name is None:
        return {'_status': 'error', 'message': 'security.webauthn-missing-pdata'}
    registration_data, state = server.register_begin({
        'id': str(user.eppn).encode('ascii'),
        'name': "{} {}".format(user.given_name, user.surname),
        'displayName': user.display_name,
        'icon': ''
    }, creds)
    session['_webauthn_state_'] = state

    current_app.logger.info('User {} has started registration of a webauthn token'.format(user))
    current_app.logger.debug('Webauthn Registration data: {}.'.format(registration_data))
    current_app.stats.count(name='webauthn_register_begin')

    encoded_data = base64.b64encode(cbor.dumps(registration_data)).decode('ascii')
    return {
        'csrf_token': session.new_csrf_token(),
        'registration_data': encoded_data
    }


@webauthn_views.route('/register/complete', methods=['POST'])
@UnmarshalWith(WebauthnRegisterRequestSchema)
@MarshalWith(SecurityResponseSchema)
@require_user
def registration_complete(user, credential_id, attestation_object, client_data, description):<commit_msg>send webauthn registration data without empty icon<commit_after># -*- coding: utf-8 -*-

from __future__ import print_function, absolute_import, unicode_literals

import struct
import json
import base64
from flask import Blueprint, session, Response
from flask import current_app, request

from fido2.client import ClientData
from fido2.server import Fido2Server, RelyingParty
from fido2.ctap2 import AttestationObject
from fido2 import cbor
from fido2.utils import websafe_encode
from fido2.ctap2 import AttestedCredentialData

from cryptography import x509
from cryptography.hazmat.backends import default_backend
from OpenSSL import crypto

from eduid_userdb.credentials import Webauthn
from eduid_userdb.security import SecurityUser
from eduid_common.api.decorators import require_user, MarshalWith, UnmarshalWith
from eduid_common.api.utils import save_and_sync_user
from eduid_common.api.schemas.base import FluxStandardAction
from eduid_webapp.security.helpers import credentials_to_registered_keys, compile_credential_list
from eduid_webapp.security.schemas import WebauthnOptionsResponseSchema, WebauthnRegisterRequestSchema
from eduid_webapp.security.schemas import SecurityResponseSchema, RemoveWebauthnTokenRequestSchema
from eduid_webapp.security.schemas import VerifyWithWebauthnTokenRequestSchema
from eduid_webapp.security.schemas import VerifyWithWebauthnTokenResponseSchema


def get_webauthn_server(rp_id, name='eduID security API'):
    rp = RelyingParty(rp_id, name)
    return Fido2Server(rp)


def make_credentials(creds):
    credentials = []
    for cred in creds:
        cred_data = base64.b64decode(cred.credential_data.encode('ascii'))
        credential_data, rest = AttestedCredentialData.unpack_from(cred_data)
        if rest:
            continue
        credentials.append(credential_data)
    return credentials


webauthn_views = Blueprint('webauthn', __name__, url_prefix='/webauthn', template_folder='templates')

@webauthn_views.route('/register/begin', methods=['GET'])
@MarshalWith(FluxStandardAction)
@require_user
def registration_begin(user):
    user_webauthn_tokens = user.credentials.filter(Webauthn)
    if user_webauthn_tokens.count >= current_app.config['WEBAUTHN_MAX_ALLOWED_TOKENS']:
        current_app.logger.error('User tried to register more than {} tokens.'.format(
            current_app.config['WEBAUTHN_MAX_ALLOWED_TOKENS']))
        return {'_status': 'error', 'message': 'security.webauthn.max_allowed_tokens'}
    creds = make_credentials(user_webauthn_tokens.to_list())
    server = get_webauthn_server(current_app.config['FIDO2_RP_ID'])
    if user.given_name is None or user.surname is None or user.display_name is None:
        return {'_status': 'error', 'message': 'security.webauthn-missing-pdata'}
    registration_data, state = server.register_begin({
        'id': str(user.eppn).encode('ascii'),
        'name': "{} {}".format(user.given_name, user.surname),
        'displayName': user.display_name
    }, creds)
    session['_webauthn_state_'] = state

    current_app.logger.info('User {} has started registration of a webauthn token'.format(user))
    current_app.logger.debug('Webauthn Registration data: {}.'.format(registration_data))
    current_app.stats.count(name='webauthn_register_begin')

    encoded_data = base64.b64encode(cbor.dumps(registration_data)).decode('ascii')
    return {
        'csrf_token': session.new_csrf_token(),
        'registration_data': encoded_data
    }


@webauthn_views.route('/register/complete', methods=['POST'])
@UnmarshalWith(WebauthnRegisterRequestSchema)
@MarshalWith(SecurityResponseSchema)
@require_user
def registration_complete(user, credential_id, attestation_object, client_data, description):
{'fraction_non_alphanumeric': 0.0901385712363783, 'fraction_numerical': 0.006726759047490919, 'mean_word_length': 5.727601809954751, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1358965', 'n_tokens_mistral': 2298, 'n_tokens_neox': 2227, 'n_words': 466}