Skip to content
user_config.html 8.69 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_password_configuration">
                    <div id="icnml_box_fields" class="icnml_box_fields">
                    	<div style="text-align: right;">
                    		<label for="username">Username</label>
                    	</div>
                    	<div>
                    		<input id="username" name="username" type="text" />
                        </div>
                    	<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">
                    	<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">
    	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 by mail" );	
			}
    		else if( ! password )
    		{
        		$( '#icnml_login_error' )
        			.text( "The password can not be empty" );
    		}
        	else if( password !== password_confirmation )
    		{
        		$( '#icnml_login_error' )
        			.text( "The passwords fields does not match" );
    		} else {
            	password = await generateKey( password, "icnml_" + username, 20000 );
        		password = password.substring( 0, 128 );
        		password = "pbkdf2$sha512$icnml_" + username + "$20000$" + password;
        		
        		$.ajax( {
    	            url:  "{{ url_for( 'do_config_new_user' ) }}",
    	            dataType: 'json',
    	            method: 'POST',
    	            data: {
    	            	'username': username,
    	            	'password': password
    	            },
    	            success: function( data )
    	            {
    	                if( true ) //! data.error )
    	                {
    	                	totp_build();
    	                } else {
    	                	toastr.error( data.message, "Configuration error" );
    	                }
    	            }
    	        } );
    		}
    	}
    	
    	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>
                </div>`;
            
    		$( '#icnml_password_configuration' ).html( totpvalue );
        	
    		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 );
		$( '#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>