Skip to content
config.html 9.68 KiB
Newer Older
<!DOCTYPE html>
<html>
    <head>
        {% for src in js %}
            <script type="text/javascript" src="{{ src }}"></script>
        {% endfor %}
        {% for src in css %}
            <link type="text/css" rel="stylesheet" href="{{ src }}">
        {% endfor %}
        
        <script type="text/javascript" src="{{ url_for( 'send_app_files', path = 'functions.js' ) }}"></script>
        <link type="text/css" rel="stylesheet" href="{{ url_for( 'send_app_files', path = 'app.css' ) }}">
        
        <script type="text/javascript">
            baseurl = "{{ baseurl }}";
            secret = "";
        </script>
    </head>
    <body>
        <div class="icnml_central">
            <h1 style="margin-bottom: 0px">ICNML</h1>
            <h4 style="margin-top: 0px">International Close Non-Matches Library</h4>
            
            <div class="ui-widget-header ui-corner-top icnml_box_top">Please enter your login information</div>
            <div id="icnml_homepage_form" class="ui-widget-content ui-corner-bottom icnml_box_content">
                <div id="icnml_user_configuration">
                    <div id="icnml_box_fields" class="icnml_box_fields">
Marco De Donno's avatar
Marco De Donno committed
                        <div style="text-align: right;">
                            <label for="username">Username</label>
Marco De Donno's avatar
Marco De Donno committed
                        <div>
                            <input id="username" name="username" type="text" />
Marco De Donno's avatar
Marco De Donno committed
                        <div style="text-align: right;">
                            <label for="password">Password</label>
                        </div>
                        <div>
                            <input id="password" name="password" type="password" />
                        </div>
                        <div style="text-align: right;">
                            <label for="password_confirmation">Password confirmation</label>
                        </div>
                        <div>
                            <input id="password_confirmation" name="password_confirmation" type="password" />
                        </div>
                    </div>
                    <div id="icnml_login_error" class="icnml_box_error"></div>
                    <div id="warning" class="icnml_box_warning"></div>
                    <div class="icnml_button">
Marco De Donno's avatar
Marco De Donno committed
                        <a class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" id="set_password_button" role="button" aria-disabled="false">
                            <span class="ui-button-text">Next</span>
                        </a>
                    </div>
                </div>
            </div>
        </div>
    </body>
    
    <script type="text/javascript">
Marco De Donno's avatar
Marco De Donno committed
        var set_password = async function()
        {
            var username = $( '#username' ).val();
            var password = $( '#password' ).val();
            var password_confirmation = $( '#password_confirmation' ).val();
            
            if( ! username )
            {
                $( '#icnml_login_error' )
                    .text( "Enter your username as provided in the email" );

                $( "#username" ).focus();
Marco De Donno's avatar
Marco De Donno committed
            }
            else if( ! password )
            {
                $( '#icnml_login_error' )
                    .text( "The password can not be empty" );

                $( "#password" ).focus();
Marco De Donno's avatar
Marco De Donno committed
            }
            else if( password !== password_confirmation )
            {
                $( '#icnml_login_error' )
                    .text( "The passwords fields does not match" );

                $( "#password" ).focus();
Marco De Donno's avatar
Marco De Donno committed
            } else {
                password = await generateKey( password, "icnml_" + username, 20000 );
                password = password.substring( 0, 128 );
                password = "pbkdf2$sha512$icnml_" + username + "$20000$" + password;
                
                $.ajax( {
                    url:  "{{ url_for( next_step ) }}",
                    dataType: 'json',
                    method: 'POST',
                    data: {
                        'username': username,
                        'password': password,
                        'hash': "{{ hash }}"
                    },
                    success: function( data )
                    {
                        if( ! data.error )
                        {
                            totp_build();
                        } else {
                            toastr.error( data.message, "Configuration error" );
                        }
                    },
                    error: function()
                    {
                        toastr.error( "Network error" );
Marco De Donno's avatar
Marco De Donno committed
                    }
                } );
            }
        }
        
        var totp_build = function()
        {
            var totpvalue = `<div style="min-height: 378px">
                    <img alt="qrcode" id="icnml_qrcode" width="100%">
                </div>
                
                <div style="text-align: center; margin-bottom: 10px;">
                    <div style="font-size: 1.17em; font-weight: bold;">Current TOTP:</div>
                    <h1 id="icnml_current_totp"></h1>
                    <div>Valid for <span id="icnml_totp_timeremaining"></span> second(s)</div>
                </div>
                
                <div style="text-align: center; margin-bottom: 10px;">
                    <div>Secret value:</div>
                    <input class="icnml_monospace" id="totp_secret_value" size="52" />
                </div>
                
                <div class="icnml_button" style="margin-top: 10px;">
                    <a class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" id="set_secret_button" role="button" aria-disabled="false">
                        <span class="ui-button-text">Next</span>
                    <a class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" id="help_button" role="button" aria-disabled="false" href="{{ url_for( 'totp_help' ) }}" target="_blank">
                        <span class="ui-button-text">Help</span>
                    </a>
            $( '#icnml_user_configuration' ).html( totpvalue );
Marco De Donno's avatar
Marco De Donno committed
            
            var fetch_secret = function()
            {
                secret = "";
                
                $.ajax( {
                    url: '{{ url_for( 'request_secret' ) }}',
                    dataType: 'json',
                    method: 'GET',
                    success: function( data )
                    {
                        if( ! data.error )
                        {
                            secret = data.secret;
                            update();
                        }
                    }
                } );
            }
            
            var update_data = function()
            {
                if( secret != "" )
                {
                    var tr = otplib.authenticator.timeRemaining();
                    var h = otplib.authenticator.generate( secret );
                    h = h.substr( 0, 3 ) + " " + h.substr( 3, 6 );
                    
                    $( '#icnml_current_totp' ).text( h );
                    $( '#icnml_totp_timeremaining' ).text( tr );
                    $( "#totp_secret_value" ).val( secret );
                
                } else {
                    $( '#icnml_current_totp' ).text( "-" );
                    $( '#icnml_totp_timeremaining' ).text( "-" );
                    $( "#totp_secret_value" ).val( "-" );
                    
                    fetch_secret();
                }
            }
            
            var update_qrcode = function()
            {
                var uid = Math.floor( Math.random() * 100000000 );
                var url = "{{ url_for( 'send_qrcode' ) }}?" + uid;
                $( '#icnml_qrcode' )
                    .css( 'display', 'block' )
                    .attr( 'src', url );
            }
            
            var update = function()
            {
                update_data();
                update_qrcode();
            }
            
            var set_secret = function()
            {
                $.ajax( {
                    url: '{{ url_for( 'set_secret' ) }}',
                    dataType: 'json',
                    success: function( data )
                    {
                        if( ! data.error )
                        {
                            location.href = "{{ url_for( 'home' ) }}";
                        } else {
                            console.log( "error" );
                            console.log( data );
                        }
                    }
                } );
            }
            
            update();
            setInterval( update_data, 1000 );
            
            $( '#set_secret_button' ).on( 'click', set_secret );
        }
        
        /* Events binding */
        
        $( '#set_password_button' ).on( 'click', set_password );
Marco De Donno's avatar
Marco De Donno committed
        $( '#username' ).focus();
        
        $( document ).ready( function()
        {
            if( !window.crypto || !window.crypto.subtle || !window.TextEncoder || !window.TextDecoder)
            {
                $( '#warning' )
                    .text( "Your browser does not support client-side cryptography. Please use compatible browser (Firefox, Chrome, Opera, Safari, ...) to protect your password before sending it to the ICNML server." );
                
                $( '#username' ).prop( "disabled", true );
                $( '#password' ).prop( "disabled", true );
                $( '#password_confirmation' ).prop( "disabled", true );
                $( '#set_password_button' ).remove();
            }
        } );
    </script>
</html>