package javacodebook.core.passwd;

import java.security.MessageDigest;
import java.util.Properties;
import java.io.*;

/**
 * Verwaltung von Passwörter für Benutzer. Die Passwörter
 * werden verschlüsselt gespeichert. Als Algorithmus wird
 * MD5 aus dem Paket java.security verwendet
 *
 * @author Mark Donnermeyer
 */
public class Passwd {
    
    // Die 16 hexadezimalen Zahlen
    private static final char[] hex = {
        '0', '1', '2', '3', '4', '5', '6', '7',
        '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
        
        private Properties users = new Properties();
        private File file = null;
        
        /**
         * Erzeugt eine neue Passwortverwaltung. Das File
         * gibt an, wo die Passwörter gespeichert sind.
         */
        public Passwd(File file) throws IOException {
            this.file = file;
            load();
        }
        
        /** 
         * Fügt einen neuen Benutzer zu der Liste der 
         * Benutzer hinzu bzw. setzt das Kennwort des
         * Benutzers neu
         */
        public boolean set(String login, String passwd) 
                                        throws IOException {
            if (login == null || passwd == null)
                return false;
            
            users.setProperty(login, encrypt(passwd));
            store();
            return true;
        }
        
        /**
         * Entfernt einen Benutzer aus der Liste der 
         * Benutzer
         */
        public void remove(String login) throws IOException {
            if (login == null)
                users.remove(login);
            store();
        }
        
        /**
         * Testet, ob es eine entsprechende Kombination aus
         * Login und Passwort gibt. 
         */
        public boolean check(String login, String passwd) {
            if (login == null || passwd == null)
                return false;

            // Das Passwort des Benutzers wird gelesen. 
            // Wenn der Benutzer nicht existiert, dann wird
            // null zurückgegeben.
            String real = users.getProperty(login);
            // Passwort verschlüsseln und mit dem 
            // gespeicherten Passwort vergleichen.
            return encrypt(passwd).equals(real);
        }

        /**
         * Lädt die Benutzer und ihre Passwörter aus einer
         * Datei. Die Daten liegen als Properties vor.
         */
        public void load() {
            try {
                // Wenn die Datei nicht existiert, dann 
                // soll wohl eine neue Datei angelegt werden.
                if (!file.exists())
                    return;
                
                InputStream is = new FileInputStream(file);
                users.load(is);
                is.close();
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }

        /**
         * Speichert die Benutzer und ihre Passwörter als
         * Properties in einer Datei
         */
        private void store() throws IOException {
            try {
                // Wenn die Datei nicht existiert, dann 
                // jetzt eine neue Datei anlegen.
                if (!file.exists())
                    file.createNewFile();
                OutputStream os = new FileOutputStream(file);
                users.store(os, "Knacken sinnlos!");
                os.close();
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        /**
         * Liefert einen 32 Zeichen langen String, der das
         * MD5-verschlüsselte Passwort enthält.
         */
        private static String encrypt(String pass) {
            MessageDigest md;
            try {
                // Eine Instanz des MD5-Algorithmus holen
                md = MessageDigest.getInstance("MD5");
                // Passwort verschlüsseln und in HEX wandeln
                return toHex(md.digest(pass.getBytes()));
            }
            catch (Exception e) {
                return null;
            }
        }
        
        /**
         * Umwandlung eines Arrays von Bytes in einen String
         * von HEX-Werten.
         */
        private static String toHex(byte[] str) {
            
            StringBuffer result = new StringBuffer();
            byte value = 0;
            for (int i=0; i<str.length; i++) {
                value = str[i];
                result.append(hex[(value>>4)&15]);
                result.append(hex[value&15]);
            }
            return result.toString();
        }
}
