content: /*
   * Universal Password Manager
   * Copyright (C) 2005-2013 Adrian Smith
   *
   * This file is part of Universal Password Manager.
   *   
   * Universal Password Manager is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * Universal Password Manager is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with Universal Password Manager; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   */
  package com._17od.upm.database;
  
  import java.io.ByteArrayOutputStream;
  import java.io.File;
  import java.io.FileOutputStream;
  import java.io.IOException;
  
  import junit.framework.TestCase;
  
  import com._17od.upm.crypto.CryptoException;
  import com._17od.upm.crypto.DESDecryptionService;
  import com._17od.upm.crypto.EncryptionService;
  import com._17od.upm.crypto.InvalidPasswordException;
  
  public class PasswordDatabasePersistenceTest extends TestCase {
  
      private String password = "password";
      private PasswordDatabasePersistence passwordDatabasePersistence;
  
      public void setUp() {
          passwordDatabasePersistence = new PasswordDatabasePersistence();
      }
  
      public void testLoadVer2DB() throws ProblemReadingDatabaseFile, CryptoException, IOException, InvalidPasswordException {
          File f = createVer2Db();
          PasswordDatabase db = passwordDatabasePersistence.load(f, password.toCharArray());
          assertEquals(4, db.getRevision());
          assertEquals("rl", db.getDbOptions().getRemoteLocation());
          assertEquals("adbe", db.getDbOptions().getAuthDBEntry());
          assertEquals(1, db.getAccounts().size());
          AccountInformation account = (AccountInformation) db.getAccounts().get(0);
          assertEquals("test account", account.getAccountName());
          assertEquals("auserid", new String(account.getUserId()));
          assertEquals("apassword", new String(account.getPassword()));
          assertEquals("http://www.a.com", new String(account.getUrl()));
          assertEquals("some notes", new String(account.getNotes()));
      }
  
      public void testLoadVer110DB() throws ProblemReadingDatabaseFile, CryptoException, IOException, InvalidPasswordException {
          File f = createVer110Db();
          PasswordDatabase db = passwordDatabasePersistence.load(f, password.toCharArray());
          assertEquals(6, db.getRevision());
          assertEquals("qwe", db.getDbOptions().getRemoteLocation());
          assertEquals("fdef", db.getDbOptions().getAuthDBEntry());
          assertEquals(1, db.getAccounts().size());
          AccountInformation account = (AccountInformation) db.getAccounts().get(0);
          assertEquals("test account110", account.getAccountName());
          assertEquals("auserid110", new String(account.getUserId()));
          assertEquals("apassword110", new String(account.getPassword()));
          assertEquals("http://www.a.com/110", new String(account.getUrl()));
          assertEquals("some notes110", new String(account.getNotes()));
      }
  
      public void testLoadVer100DB() throws ProblemReadingDatabaseFile, CryptoException, IOException, InvalidPasswordException {
          File f = createVer100Db();
          PasswordDatabase db = passwordDatabasePersistence.load(f, password.toCharArray());
          assertEquals(1, db.getAccounts().size());
          AccountInformation account = (AccountInformation) db.getAccounts().get(0);
          assertEquals("test account100", account.getAccountName());
          assertEquals("auserid100", new String(account.getUserId()));
          assertEquals("apassword100", new String(account.getPassword()));
          assertEquals("http://www.a.com/100", new String(account.getUrl()));
          assertEquals("some notes100", new String(account.getNotes()));
      }
  
      private File createVer100Db() throws IOException, CryptoException {
          byte[] b = createVer100DbBytes();
          return saveToFile(b);
      }
  
      private File createVer110Db() throws IOException, CryptoException {
          byte[] b = createVer110DbBytes();
          return saveToFile(b);
      }
  
      private File createVer2Db() throws IOException, CryptoException {
          byte[] b = createVer2DbBytes();
          return saveToFile(b);
      }
  
      private byte[] createVer100DbBytes() throws IOException, CryptoException {
          // SALT [DB_HEADER ACCOUNTS]
          ByteArrayOutputStream partToEncryptOS = new ByteArrayOutputStream();
          partToEncryptOS.write("00011".getBytes());      // db version: major
          partToEncryptOS.write("00010".getBytes());      // db version: minor
          partToEncryptOS.write("00010".getBytes());      // db version: patch
          partToEncryptOS.write("0015test account100".getBytes());      // account name
          partToEncryptOS.write("0010auserid100".getBytes());           // userid
          partToEncryptOS.write("0012apassword100".getBytes());         // password
          partToEncryptOS.write("0020http://www.a.com/100".getBytes()); // url
          partToEncryptOS.write("0013some notes100".getBytes());        // notes
          partToEncryptOS.close();
          byte[] salt = DESDecryptionService.generateSalt();
          byte[] encryptedPart = DESDecryptionService.encrypt(password.toCharArray(), salt, partToEncryptOS.toByteArray());
  
          ByteArrayOutputStream dbOS = new ByteArrayOutputStream();
          dbOS.write(salt);             // salt
          dbOS.write(encryptedPart);    // encrypted body
          dbOS.close();
          
          return dbOS.toByteArray();
      }
  
      private byte[] createVer110DbBytes() throws IOException, CryptoException {
          // SALT [DB_HEADER DB_REVISION DB_OPTIONS ACCOUNTS]
          ByteArrayOutputStream partToEncryptOS = new ByteArrayOutputStream();
          partToEncryptOS.write("00011".getBytes());      // db version: major
          partToEncryptOS.write("00011".getBytes());      // db version: minor
          partToEncryptOS.write("00010".getBytes());      // db version: patch
          partToEncryptOS.write("00016".getBytes());      // revision
          partToEncryptOS.write("0003qwe".getBytes());    // remoteLocation
          partToEncryptOS.write("0004fdef".getBytes());   // authDBEntry
          partToEncryptOS.write("0015test account110".getBytes());      // account name
          partToEncryptOS.write("0010auserid110".getBytes());           // userid
          partToEncryptOS.write("0012apassword110".getBytes());         // password
          partToEncryptOS.write("0020http://www.a.com/110".getBytes()); // url
          partToEncryptOS.write("0013some notes110".getBytes());        // notes
          partToEncryptOS.close();
          byte[] salt = DESDecryptionService.generateSalt();
          byte[] encryptedPart = DESDecryptionService.encrypt(password.toCharArray(), salt, partToEncryptOS.toByteArray());
          
          ByteArrayOutputStream dbOS = new ByteArrayOutputStream();
          dbOS.write(salt);              // salt
          dbOS.write(encryptedPart);    // encrypted body
          dbOS.close();
          
          return dbOS.toByteArray();
      }
      
      private byte[] createVer2DbBytes() throws CryptoException, IOException {
          EncryptionService ec = new EncryptionService(password.toCharArray());
  
          // MAGIC_NUMBER DB_VERSION SALT [DB_REVISION DB_OPTIONS ACCOUNTS]
          ByteArrayOutputStream partToEncryptOS = new ByteArrayOutputStream();
          partToEncryptOS.write("00014".getBytes());      // revision
          partToEncryptOS.write("0002rl".getBytes());     // remoteLocation
          partToEncryptOS.write("0004adbe".getBytes());   // authDBEntry
          partToEncryptOS.write("0012test account".getBytes());     // account name
          partToEncryptOS.write("0007auserid".getBytes());          // userid
          partToEncryptOS.write("0009apassword".getBytes());        // password
          partToEncryptOS.write("0016http://www.a.com".getBytes()); // url
          partToEncryptOS.write("0010some notes".getBytes());       // notes
          partToEncryptOS.close();
          byte[] encryptedPart = ec.encrypt(partToEncryptOS.toByteArray());
  
          ByteArrayOutputStream dbOS = new ByteArrayOutputStream();
          dbOS.write("UPM".getBytes());   // magic number
          dbOS.write(0x2);                // db version (2)
          dbOS.write(ec.getSalt());       // salt
          dbOS.write(encryptedPart);      // encrypted body
          dbOS.close();
          
          return dbOS.toByteArray();
      }
  
      private File saveToFile(byte[] b) throws IOException {
          File f = File.createTempFile("upm", "upm");
          FileOutputStream fos = new FileOutputStream(f);
          fos.write(b);
          fos.close();
          return f;
      }
  
  }
  