// core_test.go: tests for core.go
//
// Copyright (c) 2013 CloudFlare, Inc.

package core

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"os"
	"reflect"
	"sort"
	"testing"

	"github.com/cloudflare/redoctober/config"
	"github.com/cloudflare/redoctober/passvault"
	"github.com/cloudflare/redoctober/persist"
	"golang.org/x/crypto/ssh"
)

func tempName(t *testing.T) string {
	tmpf, err := ioutil.TempFile("", "ro_core")
	if err != nil {
		t.Fatalf("failed to get a temporary file: %s", err)
	}

	name := tmpf.Name()
	tmpf.Close()
	return name
}

func TestCreate(t *testing.T) {
	createJson := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\"}")
	cfg := config.New()

	Init("memory", cfg)

	respJson, err := Create(createJson)
	if err != nil {
		t.Fatalf("Error in creating account, %v", err)
	}

	var s ResponseData
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in creating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in creating account, %v", s.Status)
	}

	// check to see if creation can happen twice
	respJson, err = Create(createJson)
	if err != nil {
		t.Fatalf("Error in creating account when one exists, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in creating account when one exists, %v", err)
	}
	if s.Status == "ok" {
		t.Fatalf("Error in creating account when one exists, %v", s.Status)
	}
}

func TestSummary(t *testing.T) {
	createJson := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\"}")
	delegateJson := []byte("{\"Name\":\"Bob\",\"Password\":\"Rob\",\"Time\":\"2h\",\"Uses\":1}")

	// check for summary of uninitialized vault
	respJson, err := Summary(createJson)
	if err != nil {
		t.Fatalf("Error in summary of account with no vault, %v", err)
	}
	var s SummaryData
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in summary of account with no vault, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in summary of account with no vault, %v", s.Status)
	}

	cfg := config.New()
	Init("memory", cfg)

	// check for summary of initialized vault
	respJson, err = Create(createJson)
	if err != nil {
		t.Fatalf("Error in creating account, %v", err)
	}

	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in creating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in creating account, %v", s.Status)
	}

	// redoctober should be in a non-persisting state at this
	// time.
	respJson, err = Status(createJson)
	if err != nil {
		t.Fatalf("Error in creating account, %v", err)
	}

	var rd ResponseData
	var st StatusData
	err = json.Unmarshal(respJson, &rd)
	if err != nil {
		t.Fatalf("Error getting status, %v", err)
	}
	err = json.Unmarshal(rd.Response, &st)
	if err != nil {
		t.Fatalf("Error getting status, %v", err)
	}
	if st.Status != persist.Disabled {
		t.Fatalf("Persistent delegations should be '%s' but are '%s'",
			persist.Disabled, st.Status)
	}

	respJson, err = Summary(createJson)
	if err != nil {
		t.Fatalf("Error in summary of account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in summary of account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in summary of account, %v", s.Status)
	}

	data, ok := s.All["Alice"]
	if !ok {
		t.Fatalf("Error in summary of account, record missing")
	}
	if data.Admin != true {
		t.Fatalf("Error in summary of account, record incorrect")
	}
	if data.Type != passvault.DefaultRecordType {
		t.Fatalf("Error in summary of account, record incorrect")
	}

	// check for summary of initialized vault with new member
	respJson, err = Delegate(delegateJson)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in delegating account, %v", s.Status)
	}

	respJson, err = Summary(createJson)
	if err != nil {
		t.Fatalf("Error in summary of account with no vault, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in summary of account with no vault, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in summary of account with no vault, %v", s.Status)
	}

	data, ok = s.All["Alice"]
	if !ok {
		t.Fatalf("Error in summary of account, record missing")
	}
	if data.Admin != true {
		t.Fatalf("Error in summary of account, record missing")
	}
	if data.Type != passvault.DefaultRecordType {
		t.Fatalf("Error in summary of account, record missing")
	}

	data, ok = s.All["Bob"]
	if !ok {
		t.Fatalf("Error in summary of account, record missing")
	}
	if data.Admin != false {
		t.Fatalf("Error in summary of account, record missing")
	}
	if data.Type != passvault.DefaultRecordType {
		t.Fatalf("Error in summary of account, record missing")
	}

	dataLive, ok := s.Live["Bob"]
	if !ok {
		t.Fatalf("Error in summary of account, record missing, %v", crypt.LiveSummary())
	}
	if dataLive.Admin != false {
		t.Fatalf("Error in summary of account, record missing")
	}
	if dataLive.Type != passvault.DefaultRecordType {
		t.Fatalf("Error in summary of account, record missing")
	}

	var s1 SummaryData
	delegations := crypt.LiveSummary()
	if len(delegations) == 0 {
		t.Fatal("no delegations active")
	}

	// check for summary of initialized vault without non-admin members after purge
	respJson, err = Purge(createJson)
	if err != nil {
		t.Fatalf("Error in purging, %v", err)
	}
	err = json.Unmarshal(respJson, &s1)
	if err != nil {
		t.Fatalf("Error in purging, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in purging, %v", s.Status)
	}

	respJson, err = Summary(createJson)
	if err != nil {
		t.Fatalf("Error in summary of account with no vault, %v", err)
	}
	err = json.Unmarshal(respJson, &s1)
	if err != nil {
		t.Fatalf("Error in summary of account with no vault, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in summary of account with no vault, %v", s.Status)
	}

	data, ok = s1.All["Alice"]
	if !ok {
		t.Fatalf("Error in summary of account, record missing")
	}
	if data.Admin != true {
		t.Fatalf("Error in summary of account, record missing")
	}
	if data.Type != passvault.DefaultRecordType {
		t.Fatalf("Error in summary of account, record missing")
	}

	_, ok = s1.All["Bob"]
	if !ok {
		t.Fatal("Bob was removed from the list of users")
	}

	delegations = crypt.LiveSummary()
	if len(delegations) != 0 {
		t.Fatalf("purge failed to clear delegations (%d delegations remain)", len(delegations))
	}
}

func TestCreateUser(t *testing.T) {
	createUserJson := []byte("{\"Name\":\"Bill\",\"Password\":\"Lizard\"}")
	createUserECCJson := []byte("{\"Name\":\"Cat\",\"Password\":\"Cheshire\",\"UserType\":\"ECC\"}")
	createVaultJson := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\"}")
	cfg := config.New()

	Init("memory", cfg)

	// Check that users cannot be created before a vault is
	respJson, err := CreateUser(createUserJson)
	if err != nil {
		t.Fatalf("Error in creating user before vault is created, %v", err)
	}

	var s ResponseData
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in creating user before vault is created, %v", err)
	}
	if s.Status == "ok" {
		t.Fatalf("Error in creating user before vault is created, %v", s.Status)
	}

	// Check that a user can be created after a vault has been created
	respJson, err = Create(createVaultJson)
	if err != nil {
		t.Fatalf("Error in creating account, %v", err)
	}

	respJson, err = CreateUser(createUserJson)
	if err != nil {
		t.Fatalf("Error in creating user, %v", err)
	}

	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in creating user, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in creating user, %v", s.Status)
	}

	// Check that user creation can't happen twice with the same name
	respJson, err = CreateUser(createUserJson)
	if err != nil {
		t.Fatalf("Error in creating user when one exists, %v", err)
	}

	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in creating user when one exists, %v", err)
	}
	if s.Status == "ok" {
		t.Fatalf("Error in creating user when one exists, %v", s.Status)
	}

	// Check that a UserType can be specified for a user
	respJson, err = CreateUser(createUserECCJson)
	if err != nil {
		t.Fatalf("Error in creating user with ECC UserType, %v", err)
	}

	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in creating user with ECC UserType, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in creating user with ECC UserType, %v", s.Status)
	}
}

func TestPassword(t *testing.T) {
	createJson := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\"}")
	delegateJson := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Time\":\"2h\",\"Uses\":1}")
	passwordJson := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"NewPassword\":\"Olleh\"}")
	delegateJson2 := []byte("{\"Name\":\"Alice\",\"Password\":\"Olleh\",\"Time\":\"2h\",\"Uses\":1}")
	passwordJson2 := []byte("{\"Name\":\"Alice\",\"Password\":\"Olleh\",\"NewPassword\":\"Hello\"}")
	cfg := config.New()

	Init("memory", cfg)

	// check for summary of initialized vault with new member
	var s ResponseData
	respJson, err := Create(createJson)
	if err != nil {
		t.Fatalf("Error in creating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in creating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in creating account, %v", s.Status)
	}

	respJson, err = Delegate(delegateJson)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in delegating account, %v", s.Status)
	}

	respJson, err = Password(passwordJson2)
	if err != nil {
		t.Fatalf("Error in password, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in password, %v", err)
	}
	if s.Status == "ok" {
		t.Fatalf("Error in password, %v", s.Status)
	}

	respJson, err = Password(passwordJson)
	if err != nil {
		t.Fatalf("Error in password, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in password, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in password, %v", s.Status)
	}

	respJson, err = Delegate(delegateJson)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	if s.Status == "ok" {
		t.Fatalf("Error in delegating account, %v", s.Status)
	}

	respJson, err = Delegate(delegateJson2)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in delegating account, %v", s.Status)
	}

	respJson, err = Password(passwordJson2)
	if err != nil {
		t.Fatalf("Error in password, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in password %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in password, %v", s.Status)
	}

	respJson, err = Delegate(delegateJson)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in delegating account, %v", s.Status)
	}
}

func TestEncryptDecrypt(t *testing.T) {
	summaryJson := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\"}")
	delegateJson := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Time\":\"0s\",\"Uses\":0}")
	delegateJson2 := []byte("{\"Name\":\"Bob\",\"Password\":\"Hello\",\"Time\":\"0s\",\"Uses\":0}")
	delegateJson3 := []byte("{\"Name\":\"Carol\",\"Password\":\"Hello\",\"Time\":\"0s\",\"Uses\":0}")
	delegateJson4 := []byte("{\"Name\":\"Bob\",\"Password\":\"Hello\",\"Time\":\"10s\",\"Uses\":2,\"Users\":[\"Alice\"],\"Labels\":[\"blue\"]}")
	delegateJson5 := []byte("{\"Name\":\"Carol\",\"Password\":\"Hello\",\"Time\":\"10s\",\"Uses\":2,\"Users\":[\"Alice\"],\"Labels\":[\"blue\"]}")
	delegateJson6 := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Time\":\"10s\",\"Uses\":1}")
	encryptJson := []byte("{\"Name\":\"Carol\",\"Password\":\"Hello\",\"Minimum\":2,\"Owners\":[\"Alice\",\"Bob\",\"Carol\"],\"Data\":\"SGVsbG8gSmVsbG8=\"}")
	encryptJson2 := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Minimum\":2,\"Owners\":[\"Alice\",\"Bob\",\"Carol\"],\"Data\":\"SGVsbG8gSmVsbG8=\",\"Labels\":[\"blue\",\"red\"]}")
	encryptJson3 := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Minimum\":1,\"Owners\":[\"Alice\"],\"Data\":\"SGVsbG8gSmVsbG8=\"}")
	encryptJson4 := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Minimum\":1,\"Owners\":[\"Alice\"],\"Data\":\"SGVsbG8gSmVsbG8=\",\"Usages\":[\"decrypt\"]}")
	encryptJson5 := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Minimum\":1,\"Owners\":[\"Alice\"],\"Data\":\"SGVsbG8gSmVsbG8=\",\"Usages\":[\"unused\"]}")
	cfg := config.New()

	Init("memory", cfg)

	// check for summary of initialized vault with new member
	var s ResponseData
	respJson, err := Create(delegateJson)
	if err != nil {
		t.Fatalf("Error in creating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in creating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in creating account, %v", s.Status)
	}

	respJson, err = Delegate(delegateJson2)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in delegating account, %v", s.Status)
	}

	respJson, err = Delegate(delegateJson3)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in delegating account, %v", s.Status)
	}

	// check summary to see if none are delegated
	err = crypt.Refresh()
	if err != nil {
		t.Fatalf("Error in summary: %s", err)
	}

	respJson, err = Summary(summaryJson)
	if err != nil {
		t.Fatalf("Error in summary, %v", err)
	}
	var sum SummaryData
	err = json.Unmarshal(respJson, &sum)
	if err != nil {
		t.Fatalf("Error in summary, %v", err)
	}
	if sum.Status != "ok" {
		t.Fatalf("Error in summary, %v", sum.Status)
	}
	if len(sum.Live) != 0 {
		t.Fatalf("Error in summary, %v", sum.Status)
	}

	// Encrypt with non-admin
	respJson, err = Encrypt(encryptJson)
	if err != nil {
		t.Fatalf("Error in encrypt, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in encrypt, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in encrypt, %v", s.Status)
	}

	// Encrypt
	respJson, err = Encrypt(encryptJson2)
	if err != nil {
		t.Fatalf("Error in encrypt, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in encrypt, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in encrypt, %v", s.Status)
	}

	// decrypt file
	decryptJson, err := json.Marshal(DecryptRequest{Name: "Alice", Password: "Hello", Data: s.Response})
	if err != nil {
		t.Fatalf("Error in marshalling decryption, %v", err)
	}

	respJson2, err := Decrypt(decryptJson)
	if err != nil {
		t.Fatalf("Error in decrypt, %v", err)
	}
	err = json.Unmarshal(respJson2, &s)
	if err != nil {
		t.Fatalf("Error in decrypt, %v", err)
	}
	if s.Status == "ok" {
		t.Fatalf("Error in decrypt, %v", s.Status)
	}

	// delegate two valid decryptors
	respJson, err = Delegate(delegateJson4)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in delegating account, %v", s.Status)
	}

	respJson, err = Delegate(delegateJson5)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in delegating account, %v", s.Status)
	}

	// verify the presence of the two delgations
	err = crypt.Refresh()
	if err != nil {
		t.Fatalf("Error in summary: %s", err)
	}

	var sum2 SummaryData
	respJson, err = Summary(summaryJson)
	if err != nil {
		t.Fatalf("Error in summary, %v", err)
	}
	err = json.Unmarshal(respJson, &sum2)
	if err != nil {
		t.Fatalf("Error in summary, %v", err)
	}
	if sum2.Status != "ok" {
		t.Fatalf("Error in summary, %v", sum2.Status)
	}
	if len(sum2.Live) != 2 {
		t.Fatalf("Error in summary, %v", sum2.Live)
	}

	respJson2, err = Decrypt(decryptJson)
	if err != nil {
		t.Fatalf("Error in decrypt, %v", err)
	}
	err = json.Unmarshal(respJson2, &s)
	if err != nil {
		t.Fatalf("Error in decrypt, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in decrypt, %v", s.Status)
	}

	var d DecryptWithDelegates
	err = json.Unmarshal(s.Response, &d)
	if err != nil {
		t.Fatalf("Error in decrypt, %v", err)
	}

	if string(d.Data) != "Hello Jello" {
		t.Fatalf("Error in decrypt, %v", string(d.Data))
	}

	if d.Delegates[0] != "Bob" && d.Delegates[1] != "Carol" {
		if d.Delegates[1] != "Bob" && d.Delegates[0] != "Carol" {
			t.Fatalf("Error in decrypt, %v", d.Delegates)
		}
	}

	// Encrypt with only a single owner
	respJson, err = Encrypt(encryptJson3)
	if err != nil {
		t.Fatalf("Error in encrypt, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in encrypt, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in encrypt, %v", s.Status)
	}

	respJson, err = Delegate(delegateJson6)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in delegating account, %v", s.Status)
	}

	// decrypt file
	decryptJson2, err := json.Marshal(DecryptRequest{Name: "Alice", Password: "Hello", Data: s.Response})
	if err != nil {
		t.Fatalf("Error in marshalling decryption, %v", err)
	}

	respJson2, err = Decrypt(decryptJson2)
	if err != nil {
		t.Fatalf("Error in decrypt, %v", err)
	}
	err = json.Unmarshal(respJson2, &s)
	if err != nil {
		t.Fatalf("Error in decrypt, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in decrypt, %v", s.Status)
	}

	// Encrypt with "decrypt" usage
	respJson, err = Encrypt(encryptJson4)
	if err != nil {
	        t.Fatalf("Error in encrypt, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
	        t.Fatalf("Error in encrypt, %v", err)
	}
	if s.Status != "ok" {
	        t.Fatalf("Error in encrypt, %v", s.Status)
	}

	respJson, err = Delegate(delegateJson6)
	if err != nil {
	        t.Fatalf("Error in delegating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
	        t.Fatalf("Error in delegating account, %v", err)
	}
	if s.Status != "ok" {
	        t.Fatalf("Error in delegating account, %v", s.Status)
	}

	// decrypt file
	decryptJson3, err := json.Marshal(DecryptRequest{Name: "Alice", Password: "Hello", Data: s.Response})
	if err != nil {
	        t.Fatalf("Error in marshalling decryption, %v", err)
	}

	respJson2, err = Decrypt(decryptJson3)
	if err != nil {
	        t.Fatalf("Error in decrypt, %v", err)
	}
	err = json.Unmarshal(respJson2, &s)
	if err != nil {
	        t.Fatalf("Error in decrypt, %v", err)
	}
	if s.Status != "ok" {
	        t.Fatalf("Error in decrypt, %v", s.Status)
	}

	// Encrypt with "unused" usage
	respJson, err = Encrypt(encryptJson5)
	if err != nil {
	        t.Fatalf("Error in encrypt, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
	        t.Fatalf("Error in encrypt, %v", err)
	}
	if s.Status != "ok" {
	        t.Fatalf("Error in encrypt, %v", s.Status)
	}

	respJson, err = Delegate(delegateJson6)
	if err != nil {
	        t.Fatalf("Error in delegating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
	        t.Fatalf("Error in delegating account, %v", err)
	}
	if s.Status != "ok" {
	        t.Fatalf("Error in delegating account, %v", s.Status)
	}

	// decrypt file
	decryptJson4, err := json.Marshal(DecryptRequest{Name: "Alice", Password: "Hello", Data: s.Response})
	if err != nil {
	        t.Fatalf("Error in marshalling decryption, %v", err)
	}

	respJson2, err = Decrypt(decryptJson4)
	if err != nil {
	        t.Fatalf("Error in decrypt, %v", err)
	}
	err = json.Unmarshal(respJson2, &s)
	if err != nil {
	        t.Fatalf("Error in decrypt, %v", err)
	}
	if s.Status == "ok" {
	        t.Fatalf("Expected error decrypting blob without \"decrypt\" usage")
	}
}

func TestReEncrypt(t *testing.T) {
	delegateJson := []byte(`{"Name":"Alice","Password":"Hello","Time":"0s","Uses":0}`)
	delegateJson2 := []byte(`{"Name":"Bob","Password":"Hello","Time":"0s","Uses":0}`)
	delegateJson3 := []byte(`{"Name":"Carol","Password":"Hello","Time":"0s","Uses":0}`)
	delegateJson4 := []byte(`{"Name":"Bob","Password":"Hello","Time":"10s","Uses":2,"Users":["Alice"],"Labels":["blue"]}`)
	delegateJson5 := []byte(`{"Name":"Carol","Password":"Hello","Time":"10s","Uses":2,"Users":["Alice"],"Labels":["blue"]}`)
	delegateJson6 := []byte(`{"Name":"Bob","Password":"Hello","Time":"10s","Uses":2,"Users":["Alice"],"Labels":["red"]}`)
	delegateJson7 := []byte(`{"Name":"Carol","Password":"Hello","Time":"10s","Uses":2,"Users":["Alice"],"Labels":["red"]}`)
	encryptJson := []byte(`{"Name":"Carol","Password":"Hello","Minimum":2,"Owners":["Alice","Bob","Carol"],"Data":"SGVsbG8gSmVsbG8=","Labels":["blue"]}`)
	cfg := config.New()

	Init("memory", cfg)

	// check for summary of initialized vault with new member
	var s ResponseData
	respJson, err := Create(delegateJson)
	if err != nil {
		t.Fatalf("Error in creating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in creating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in creating account, %v", s.Status)
	}

	respJson, err = Delegate(delegateJson2)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in delegating account, %v", s.Status)
	}

	respJson, err = Delegate(delegateJson3)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in delegating account, %v", s.Status)
	}

	// delegate two valid decryptors for label blue
	respJson, err = Delegate(delegateJson4)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in delegating account, %v", s.Status)
	}

	respJson, err = Delegate(delegateJson5)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in delegating account, %v", s.Status)
	}

	// Encrypt
	respJson, err = Encrypt(encryptJson)
	if err != nil {
		t.Fatalf("Error in encrypt, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in encrypt, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in encrypt, %v", s.Status)
	}

	// Prepare ReEncryptRequest
	reEncryptJson, err := json.Marshal(
		ReEncryptRequest{
			Name:     "Alice",
			Password: "Hello",
			Data:     s.Response,
			Minimum:  2,
			Owners:   []string{"Alice", "Bob", "Carol"},
			Labels:   []string{"red"},
		})
	if err != nil {
		t.Fatalf("Error in re-encrypt, %v", err)
	}

	// Re-Encrypt
	respJson, err = ReEncrypt(reEncryptJson)
	if err != nil {
		t.Fatalf("Error in re-encrypt, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in re-encrypt, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in re-encrypt, %v", s.Status)
	}

	// Prepare DecryptRequest
	decryptJson, err := json.Marshal(
		DecryptRequest{
			Name:     "Alice",
			Password: "Hello",
			Data:     s.Response,
		})
	if err != nil {
		t.Fatalf("Error in dencrypt, %v", err)
	}

	// delegate two valid decryptors for label red
	respJson, err = Delegate(delegateJson6)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in delegating account, %v", s.Status)
	}

	respJson, err = Delegate(delegateJson7)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in delegating account, %v", s.Status)
	}

	// Decrypt
	respJson, err = Decrypt(decryptJson)
	if err != nil {
		t.Fatalf("Error in decrypt, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in decrypt, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in decrypt, %v", s.Status)
	}

	var d DecryptWithDelegates
	err = json.Unmarshal(s.Response, &d)
	if err != nil {
		t.Fatalf("Error in decrypt, %v", err)
	}

	if string(d.Data) != "Hello Jello" {
		t.Fatalf("Error in decrypt, %v", string(d.Data))
	}

	if d.Delegates[0] != "Bob" && d.Delegates[1] != "Carol" {
		if d.Delegates[1] != "Bob" && d.Delegates[0] != "Carol" {
			t.Fatalf("Error in decrypt, %v", d.Delegates)
		}
	}
}

func TestOwners(t *testing.T) {
	delegateJson := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Time\":\"0s\",\"Uses\":0}")
	delegateJson2 := []byte("{\"Name\":\"Bob\",\"Password\":\"Hello\",\"Time\":\"0s\",\"Uses\":0}")
	delegateJson3 := []byte("{\"Name\":\"Carol\",\"Password\":\"Hello\",\"Time\":\"0s\",\"Uses\":0}")
	encryptJson := []byte("{\"Name\":\"Carol\",\"Password\":\"Hello\",\"Minimum\":2,\"Owners\":[\"Alice\",\"Bob\",\"Carol\"],\"Data\":\"SGVsbG8gSmVsbG8=\"}")
	cfg := config.New()

	var s ResponseData
	var l OwnersData

	Init("memory", cfg)

	Create(delegateJson)
	Delegate(delegateJson2)
	Delegate(delegateJson3)

	// Encrypt with non-admin
	respJson, err := Encrypt(encryptJson)
	if err != nil {
		t.Fatalf("Error in encrypt, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in encrypt, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in encrypt, %v", s.Status)
	}

	// Get owners list
	ownersJson, err := json.Marshal(OwnersRequest{Data: s.Response})
	if err != nil {
		t.Fatalf("Error in owners, %v", err)
	}
	respJson, err = Owners(ownersJson)
	if err != nil {
		t.Fatalf("Error in owners, %v", err)
	}
	err = json.Unmarshal(respJson, &l)
	if err != nil {
		t.Fatalf("Error in owners, %v", err)
	}
	if l.Status != "ok" {
		t.Fatalf("Error in owners, %v", l.Status)
	}

	sort.Strings(l.Owners)

	expectedOwners := []string{"Alice", "Bob", "Carol"}
	if !reflect.DeepEqual(l.Owners, expectedOwners) {
		t.Fatalf("Owners list mismatch, %v", l.Owners)
	}
}

func TestModify(t *testing.T) {
	summaryJson := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\"}")
	summaryJson2 := []byte("{\"Name\":\"Carol\",\"Password\":\"Hello\"}")
	delegateJson := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Time\":\"0s\",\"Uses\":0}")
	delegateJson2 := []byte("{\"Name\":\"Bob\",\"Password\":\"Hello\",\"Time\":\"0s\",\"Uses\":0}")
	delegateJson3 := []byte("{\"Name\":\"Carol\",\"Password\":\"Hello\",\"Time\":\"0s\",\"Uses\":0}")
	modifyJson := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"ToModify\":\"Alice\",\"Command\":\"admin\"}")
	modifyJson2 := []byte("{\"Name\":\"Carol\",\"Password\":\"Hello\",\"ToModify\":\"Alice\",\"Command\":\"revoke\"}")
	modifyJson3 := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"ToModify\":\"Carol\",\"Command\":\"admin\"}")
	modifyJson4 := []byte("{\"Name\":\"Carol\",\"Password\":\"Hello\",\"ToModify\":\"Alice\",\"Command\":\"revoke\"}")
	modifyJson5 := []byte("{\"Name\":\"Carol\",\"Password\":\"Hello\",\"ToModify\":\"Alice\",\"Command\":\"delete\"}")
	cfg := config.New()

	Init("memory", cfg)

	// check for summary of initialized vault with new member
	var s ResponseData
	respJson, err := Create(delegateJson)
	if err != nil {
		t.Fatalf("Error in creating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in creating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in creating account, %v", s.Status)
	}

	respJson, err = Delegate(delegateJson2)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in delegating account, %v", s.Status)
	}

	respJson, err = Delegate(delegateJson3)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in delegating account, %v", s.Status)
	}

	// check summary to see if none are delegated
	err = crypt.Refresh()
	if err != nil {
		t.Fatalf("Error refreshing: %s", err)
	}

	respJson, err = Summary(summaryJson)
	if err != nil {
		t.Fatalf("Error in summary, %v", err)
	}
	var sum SummaryData
	err = json.Unmarshal(respJson, &sum)
	if err != nil {
		t.Fatalf("Error in summary, %v", err)
	}
	if sum.Status != "ok" {
		t.Fatalf("Error in summary, %v", sum.Status)
	}
	if len(sum.Live) != 0 {
		t.Fatalf("Error in summary, %v", sum.Status)
	}

	// Modify from non-admin (fail)
	respJson, err = Modify(modifyJson)
	if err != nil {
		t.Fatalf("Error in modify, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in modify, %v", err)
	}
	if s.Status == "ok" {
		t.Fatalf("Error in modify, %v", s.Status)
	}

	// Modify self from admin (fail)
	respJson, err = Modify(modifyJson2)
	if err != nil {
		t.Fatalf("Error in modify, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in modify, %v", err)
	}
	if s.Status == "ok" {
		t.Fatalf("Error in modify, %v", s.Status)
	}

	// Modify admin from admin
	respJson, err = Modify(modifyJson3)
	if err != nil {
		t.Fatalf("Error in modify, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in modify, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in modify, %v", s.Status)
	}

	respJson, err = Summary(summaryJson)
	if err != nil {
		t.Fatalf("Error in summary, %v", err)
	}
	err = json.Unmarshal(respJson, &sum)
	if err != nil {
		t.Fatalf("Error in summary, %v", err)
	}
	if sum.Status != "ok" {
		t.Fatalf("Error in summary, %v", sum.Status)
	}
	if sum.All["Carol"].Admin != true {
		t.Fatalf("Error in summary, %v", sum.All)
	}

	// Revoke admin from admin
	respJson, err = Modify(modifyJson4)
	if err != nil {
		t.Fatalf("Error in modify, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in modify, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in modify, %v", s.Status)
	}

	respJson, err = Summary(summaryJson2)
	if err != nil {
		t.Fatalf("Error in summary, %v", err)
	}
	err = json.Unmarshal(respJson, &sum)
	if err != nil {
		t.Fatalf("Error in summary, %v", err)
	}
	if sum.Status != "ok" {
		t.Fatalf("Error in summary, %v", sum.Status)
	}
	if sum.All["Alice"].Admin == true {
		t.Fatalf("Error in summary, %v", sum.All)
	}

	// Delete from admin
	respJson, err = Modify(modifyJson5)
	if err != nil {
		t.Fatalf("Error in modify, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in modify, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in modify, %v", s.Status)
	}

	var sum3 SummaryData
	respJson, err = Summary(summaryJson2)
	if err != nil {
		t.Fatalf("Error in summary, %v", err)
	}
	err = json.Unmarshal(respJson, &sum3)
	if err != nil {
		t.Fatalf("Error in summary, %v", err)
	}
	if sum3.Status != "ok" {
		t.Fatalf("Error in summary, %v", sum3.Status)
	}
	if len(sum3.All) != 2 {
		t.Fatalf("Error in summary, %v", sum3.All)
	}
}

func TestStatic(t *testing.T) {
	expected := []byte("this is a secret string, shhhhhhhh. don't tell anyone, ok? whatever you do, don't tell the cops\n")
	delegateJson2 := []byte("{\"Name\":\"Bob\",\"Password\":\"Rob\",\"Time\":\"1m\",\"Uses\":5}")
	delegateJson3 := []byte("{\"Name\":\"Carol\",\"Password\":\"~~~222\",\"Time\":\"1h\",\"Uses\":30}")
	decryptJson := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Data\":\"eyJWZXJzaW9uIjoxLCJWYXVsdElkIjo1Mjk4NTM4OTU3NzU0NTQwODEwLCJLZXlTZXQiOlt7Ik5hbWUiOlsiQm9iIiwiQWxpY2UiXSwiS2V5IjoiMmozdEkyUEJGQmJ3RlgwQmxRZFV1QT09In0seyJOYW1lIjpbIkJvYiIsIkNhcm9sIl0sIktleSI6InlMU1NCL1U2KzVyYzFFK2dqR1hUNHc9PSJ9LHsiTmFtZSI6WyJBbGljZSIsIkJvYiJdLCJLZXkiOiJERGxXSEY3c3p6SVN1WFdhRXo4bGxRPT0ifSx7Ik5hbWUiOlsiQWxpY2UiLCJDYXJvbCJdLCJLZXkiOiJUa0ExM2FQcllGTmJ2ZUlibDBxZHd3PT0ifSx7Ik5hbWUiOlsiQ2Fyb2wiLCJCb2IiXSwiS2V5IjoiS1htMHVPYm1SSjJadlNZRVdQd2syQT09In0seyJOYW1lIjpbIkNhcm9sIiwiQWxpY2UiXSwiS2V5IjoiTDljK1BxdHhQaDl5NmFwUnZ0YkNRdz09In1dLCJLZXlTZXRSU0EiOnsiQWxpY2UiOnsiS2V5IjoiZmo1bXFucTd5NUtDYWZDR1QxSTUxeEk1SnNYNzQ2KzlUVFNzcC84eWJmM2laamhGelNsd1AzYU5tc094M1NVS1RtWmxmcytiK01lRDRlS0oydUtCRnpRSEFJUE8wZndvaUNES0hoS0g2S3NvbE5xNCtqZ3BrTEFNT0xzUUdzOGc2QmhKeTZiQ0ZSalpWYzNJZGxRQUJQTTZQa1RidVN2S2huOWF0REZ3WlFENVRKQklTaTdkMmh3NExyYWR0TElUYk5xd2lGTVRRUTkrcHNYenlhdlk4SDNMTkhLR2dmNU9kN0lwdGhFUVBDSGk0bnc3WC9ZVlJURU1mb0lWY01jS093WWpsQzQ1L1ZKRUhLOVp5M0RTaUxCemptcjU3WU5JVmp3OFlaWTVER0JXcWJndTUxUlViSWNycXlMcGhCaFhvQlJ1NFIreXJoeWdCTldidmtraWZBPT0ifSwiQm9iIjp7IktleSI6IkhUWWlaMThzZjcyMWNBTjFMUk5rSi8rTDRBS1dpbE1ya015TmlCaldjbDlIUlRWUE5YSVRxUUJYZDBmQmdnR05QaVpyNlZRVHlTSzRaRnZKS0dER2l6MTdUZS9Ub0RuOFlrL0I5Y3FNc041ZkhvUXRYdmw4SVpvMndpb0E2N2NjQUoxZ0hNTU5wUHlMZEY0M1NRcWdJK1hhUTJsTVNZTE1meHhEbUJCT1ExU1dBdG8wQkRSZG5zcXB3VXdJUEtROVkzLzFvc21yakxtSm9BQzNNUHBsZXhZV2hleE53SnRTZCttRmRWWjNRZTR4OVJzUkhjTi9teWloT3QvNjdWNjBxenMxM0YwUlprTVNEemo1RGRnKzFLVk5KWlk5ZG1vbFBOa0Faajh6MjBMOXV6cGF0clRZVFI2QThxL3NSbitpbk83WlFWUTAwWE82cTZsWVlRenhudz09In0sIkNhcm9sIjp7IktleSI6Ikl0cnZTMDJuU2ZiY0EyZmwxTDFpNjF4cVBFREtSZHNyWWUzK1VDYmtUK2lwaGVpUVJQU3Vpa2J6ZVYya3NobjR5SkRla3U1Ym1UTnFXOEhTR3RVN0dUZ0NvSVdWOFdtRWY0dzZvdnpTaFBidStWckladlJ6M3dqaDJvWUhUL2d0UFZBUW5CYS83MUZlb0JOeHk1bC9oQmNVbUJreTQzajgzTWx0Mis4UVp4NlBFVURtcGFQUWVtVmg5OStDMjBuUXRrQVVGZU1jMkdlNHk3UmxIU3h0ZkFCdndsWHgxTnpDRDQwbnlKZkYxU2pWL2ZaaC9FMkFsNFRhdng2RE9Ka1lHb0oybXA3WEJ2WDBJRjJ0cDhUM1U1VnBuVGVrL1d1TnJMTDl6Ny9qcXpXaDg3bFo1S2hlV1hoR2tVMUJOSDRsZklqNDNwRGtTeTUwYUR2UzB6WWZIUT09In19LCJJViI6IjU4cjlNejhlMDZtSXRCRzluU1YvMFE9PSIsIkRhdGEiOiJRRTlaaGNHWE5YYXVVZE1rMDRiaVVHeTFTb1A1SDJuRi9qMkpqaWlWRktQZElkUnAvR2MrQVp2VUk5bjIyWk00cSt6RGlKejdxdks0YkthUHBYaFRtR1AwWGhlYUZVdWtlVk5TOVNUTW9UYk5jWS9adFZPejZoaXpVUEY3Z1NxMzg4UVBVc1QrQXhtbDNyRVVUV09obnc9PSIsIlNpZ25hdHVyZSI6IlZWaVJvYUN4cUtBdk54eU14RGhydFlvMENaQT0ifQ==\"}")
	diskVault := []byte("{\"Version\":1,\"VaultId\":5298538957754540810,\"HmacKey\":\"Qugc5ZQ0vC7KQSgmDHTVgQ==\",\"Passwords\":{\"Alice\":{\"Type\":\"RSA\",\"PasswordSalt\":\"HrVbQ4JvEdORxWN6FrSy4w==\",\"HashedPassword\":\"nanadB0t/EmVuHyRUNtfyQ==\",\"KeySalt\":\"u0cwMmHikadpxm9wClrf3g==\",\"AESKey\":\"pOcxCYMk0l+kaEM5IHolfA==\",\"RSAKey\":{\"RSAExp\":\"yDBotK0XkaDk6rt35ciBnlyPGSXjp9ypdTH2j89CybXe2ReF6xLVZ10CCoz91UUFpbiQi2tVWFS8V7lxUehx7C6HI30Zr0iwJMXk8sgRKs2Ee3rAGCrM9vvQMO8ApKwe4kvB+PrFgnhIEgZI7zyPJPcdZnxbcVFyUC3uIivFS4Bv3jVBnrkAx71keQqrkKzu3jTquCIS3rTEm2hrgsZ3n1t/4BADvUpcMpII2Phv2Senonp1EMz9sRFsR4w9HVep8AgfUGuPTcQ/uv9R16xiHvlN80rOtWzVLpEruzGw/JTvlsshFBU5SY/zthGl9TwxWz1yZpVHYhIWhbxw34CXYczB6q19bdEPkJJldi/1coI=\",\"RSAExpIV\":\"RI9B8nzwW/CXiIU4lSYRWg==\",\"RSAPrimeP\":\"yB3TMdRhWLiZ/ayPlu/iLDHxWsuMi9pA8Ctps7WZFxVsxYEzy/s0Otzsbtgay8of72xVkO64MaudXXRjj26kVSQhS8WhPmv7xDO5ba3SsTffCA99aSr3MH+JmUoL+EDjYviUf5F1DSZniv+Ae+6x9AMbbRQqRvmdH/INW76rFbLX4VtsMpgVkAhADwCUSfNS\",\"RSAPrimePIV\":\"ZE8xe7zVqz4fTN1XWvD1Tg==\",\"RSAPrimeQ\":\"pq7rEAmXoiMWhuEpTy2pQiheLHuzcGeGm1IsgtP7TRIpHaumBAjasxhMY95ODspzehfHp8RPb3pz550g+EXpRP5bfmZkiPMGWKsFUWY7h51hm2Yg6t7yOSXxQvzseWDUjJqBXIG56su0ItD/7NT9YPnhOWAcLaV+L/D3dLdUOP3sgrfp2fcz5IWgcAHUKwLj\",\"RSAPrimeQIV\":\"po4GB9LNDJEFwVo7pd7M+w==\",\"RSAPublic\":{\"N\":23149224936745228096494487629641309516714939646787578848987096719230079441991920927625328021835418605829165905957281054739040782220661415211495551591590967025905842090248342119030961900558364831442589592519977574953153506098793781379522492850670706181134690851176026007414311463584686376540335844073069224992659463459793269384975134553539299820716318523937519020382533972574258510063896159690996712751336541794097684994088922002126390397554509324964165816682788604802958437629743951677011277308533675371215221012180522157452368867794857042597831942805118364469257052754518983480732149823871291876054393236400292711237,\"E\":65537}},\"Admin\":true},\"Bob\":{\"Type\":\"RSA\",\"PasswordSalt\":\"yqWZFNuuCRMw+snL83FcWQ==\",\"HashedPassword\":\"jYLSUIdvw8UVXhxVSS5uKQ==\",\"KeySalt\":\"ZJDOGSv9yUlJ5+83+FV6Nw==\",\"AESKey\":\"9bj4qQDJKglD9eIm7MNeag==\",\"RSAKey\":{\"RSAExp\":\"rnmHX1FgAN0KFm89Uj+O4L7/njDlQPwGHSYjGKB7qMyNPGF4jKn9ez1LI9e9jI8uE475KBhoXRmIuHdap6HtD+sH+nHugDzD3np6Dbq1MM+19PW41n9xblwx6tsNwvufCYgb2qtZd0bLXemeKBszJg2UXlTeSHkXGmjY/VAbZYbUFUNKIykiJWnQ+3HlAo7UHjjKSDI6HtiMnODwYucKH9uYdmroM3DqRUP+j+AhMctyeyOt68q6RuVyubzG0PM1/T9QqPgTIzFvg9dxk+LmPYmlv4b7Euea7KQHww4kTUlpNYondRisuA436G7EfWIJFeRShFuSVk0GvmrgN5vK+/FkdqMuikPaPV1dITFzaCU=\",\"RSAExpIV\":\"eoIov2XYwK19tpFkZyTL+Q==\",\"RSAPrimeP\":\"x9VqeHfHZBMksWNz3Bq90KyLYO0+y9tbfH17uAxQHIZbhn6RUHMXJFs4/H+TnL9s7D05HdxKNCD3ilISkhLZ/DQVD+VMvSFQ/2DL/OoKNg4UyxeGpKefJxCU9LOeXGTfN+UpGHN4Myal3PL2yi0yWCVZvX+zPks05Nqmzkmtx1Yz0IqeUaR+I1jw2y0xy+nc\",\"RSAPrimePIV\":\"h+J0h35kSaNFjBFyejmqSQ==\",\"RSAPrimeQ\":\"CUGaukdC8slcy1Qm6kBw8QYhVenJWFylPqJTvf03ATkkaxQJ8ZSK/RodXFiKCztRSx/HVw0LoGGx9RiavSxl1I+NPIiGEBXiYnLCwWjIbohEIviX0XrKEegECKZtEPxlkDGI8C5ScmUiUOoCUFODqPi1ymEPPIpqj6NZu0Q3lOXseZ7vHbCwiO7Nxznoed2V\",\"RSAPrimeQIV\":\"fglAccK/JKbbP6FKd3MoPA==\",\"RSAPublic\":{\"N\":28335031342838743289078885439639803673108967200362163631216970159249785951860249148476503896024171065194110189927394386737974335124568755441420594193064949823336810514078294805084876384362160530316962043860952904024334641317905429962254720146672817625880231384279651687169091903559644110839987019710966818515746956556387614880164417442090115347521394174077031531398826388780347541493782387177778507223791525305993050791342196579264299166530031123364885677134064847664024722422373550942639559346558112737229502294633354781474882714474174085566901518771722057743396746938093859383451665388899451851738694979184054459471,\"E\":65537}},\"Admin\":false},\"Carol\":{\"Type\":\"RSA\",\"PasswordSalt\":\"kPCA68PNIi3qODVfBHonMA==\",\"HashedPassword\":\"L05ueGkNhqRI7xo7OaG5fQ==\",\"KeySalt\":\"bUXHAjmdtpcYMNN/YzHvhA==\",\"AESKey\":\"34sh2HYt11JMd63CTC2g3Q==\",\"RSAKey\":{\"RSAExp\":\"blJ6FvmAC6ZegcR6ITdg8WDSMljcikrUp3dRGbRDgKIfK0sx7b9i/kDtp4uD7/3IuTpD/qq09k07PO10T5R9NI2OdaEUGsoKJ4wqyzP6XzC9l/KeQmU7cMTh5OHO5UcqXWBn+g1INWaWI6DNAPFKK+4jcTyy6gTQQZQKSYRvRmgN6GkjOhbsdH0eM29eZScShJy2cGemZwbx8g2x7+cebALJmnJxycq29uBZaNBq4gV2/oNXxUhAogJY8SVhgPzCgig2MAJBLK/PzzxJ2LgnBLosZkUXo4vLPKSELX0qXSkSOoC/qPXvcQGawsknqUkSaaDwB1T1MYHmcJS/wpiIRM89Qru0Oy8sy8NRApk3ef0=\",\"RSAExpIV\":\"pQnJ6tvdJkPmMkqFjwJg5g==\",\"RSAPrimeP\":\"xTwgxhDvEvMCn8W6Mqv4ogRnBXFTLbuLP8YC2exQ+RwKmUbNsjB1eBlHyYRtKwc7qoDLf/zqpMZk3yPPcQDP+szAS5mmhCgpd+ePee8vvwVR5DImDuCquMGrPNEgpg3LL1aBHMF66pfnYGob+P6GZYzJP3mhlewUlh86NDzP8YkoVlrNRZrarB1/ZmA+w2Y2\",\"RSAPrimePIV\":\"BYynxyFw7WxrpSKJ3ogwOw==\",\"RSAPrimeQ\":\"wrSXyN/gpDTvK/BMeH+04uhzGUFVbBrfo47L3i+E1QsQndJDy2yyyE1D26mFcvyiefObaD097M3ruR9Wz7WfjxmyawG8N2W/BgtHZz/Ds2ThN/T9t1XqskxnIV8l2eq9LL7SqjAyp8jUGMNVS4WODDtDngLIR6OeehfyHpgwVZRuqQMxIT3wA78SwDcWo41s\",\"RSAPrimeQIV\":\"nh42rsJHRpRyrT7DUHCSGQ==\",\"RSAPublic\":{\"N\":21157349824302424474586534982259249211803834319040688464355493234801787797103302507532796077498450217821871970018694577875997137564403612290101696297388762661598985028358214691463545987525906601624475015641369758738594698734277968689933610815708041386873182005594893971935327515126641632178583839753604241275307504709356922001828087700047657269629468786192584360390570302228520684623917906322926285597325969441240603594319235541820769758760147548185811818605055779607442920451051925838835969679126714958513824527149123555098280031335447316080110515987423541389176918537439220114191601986031091845506241054078769049741,\"E\":65537}},\"Admin\":false}}}")
	cfg := config.New()

	file := tempName(t)
	defer os.Remove(file)

	err := ioutil.WriteFile(file, diskVault, 0644)
	if err != nil {
		t.Fatalf("Error writing file, %v", err)
	}

	Init(file, cfg)

	// check for summary of initialized vault with new member
	var s ResponseData
	respJson, err := Delegate(delegateJson2)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in delegating account, %v", s.Status)
	}

	respJson, err = Delegate(delegateJson3)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error in delegating account, %v", err)
	}
	if s.Status != "ok" {
		t.Fatalf("Error in delegating account, %v", s.Status)
	}

	var r ResponseData
	respJson, err = Decrypt(decryptJson)
	if err != nil {
		t.Fatalf("Error in decrypt, %v", err)
	}
	err = json.Unmarshal(respJson, &r)
	if err != nil {
		t.Fatalf("Error in decrypt, %v", err)
	}
	if r.Status != "ok" {
		t.Fatalf("Error in summary, %v", r.Status)
	}

	var d DecryptWithDelegates
	err = json.Unmarshal(r.Response, &d)
	if err != nil {
		t.Fatalf("Error in decrypt, %v", err)
	}

	if bytes.Compare(expected, d.Data) != 0 {
		t.Fatalf("Error in summary, %v, %v", expected, r.Response)
	}

	err = crypt.Flush()
	if err != nil {
		t.Fatalf("Error flushing cache: %s", err)
	}
}

func TestValidateName(t *testing.T) {
	err := validateName("", "password")
	if err == nil {
		t.Fatal("Error expected when no name is provided")
	}

	err = validateName("?", "password")
	if err == nil {
		t.Fatal("Error expected when non alphanumeric is used in name")
	}

	err = validateName("-name", "password")
	if err == nil {
		t.Fatal("Error expected when name starts with '-' or '_'")
	}

	err = validateName("username", "")
	if err == nil {
		t.Fatal("Error expected when no password is provided")
	}

	err = validateName("username", "password")
	if err != nil {
		t.Fatalf("No error expected when username and password provided, %v", err)
	}
}

func TestSSHSignWith(t *testing.T) {
	delegateJson := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Time\":\"10s\",\"Uses\":10}")
	cfg := config.New()
	Init("memory", cfg)

	// check for summary of initialized vault with new member
	var s ResponseData
	respJson, err := Create(delegateJson)
	if err != nil {
	        t.Fatalf("Error in creating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
	        t.Fatalf("Error in creating account, %v", err)
	}
	if s.Status != "ok" {
	        t.Fatalf("Error in creating account, %v", s.Status)
	}

	respJson, err = Delegate(delegateJson)
	if err != nil {
	        t.Fatalf("Error in delegating account, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
	        t.Fatalf("Error in delegating account, %v", err)
	}
	if s.Status != "ok" {
	        t.Fatalf("Error in delegating account, %v", s.Status)
	}

	sshKey, err := ioutil.ReadFile("../testdata/ssh_key")
	if err != nil {
	        t.Fatalf("Error loading test SSH key, %v", err)
	}

	sshPubKeyBytes, err := ioutil.ReadFile("../testdata/ssh_key.pub")
	if err != nil {
	        t.Fatalf("Error loading test SSH pubkey, %v", err)
	}

	sshPubKey, _, _, _, err := ssh.ParseAuthorizedKey(sshPubKeyBytes)
	if err != nil {
	        t.Fatalf("Error loading test SSH pubkey, %v", err)
	}

	e := EncryptRequest{Name: "Alice", Password: "Hello",
	        Owners: []string{"Alice"}, Minimum: 1, Data: sshKey}

	encryptJson, err := json.Marshal(e)
	if err != nil {
	        t.Fatalf("Error marshalling encrypt request, %v", err)
	}

	// Encrypt SSH key
	respJson, err = Encrypt(encryptJson)
	if err != nil {
	        t.Fatalf("Error in encrypt, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
	        t.Fatalf("Error in encrypt, %v", err)
	}
	if s.Status != "ok" {
	        t.Fatalf("Error in encrypt, %v", s.Status)
	}

	// try to generate a signature
	sshSignWithJson, err := json.Marshal(SSHSignWithRequest{Name: "Alice", Password: "Hello", Data: s.Response, TBSData: []byte("signme")})
	if err != nil {
	        t.Fatalf("Error marshalling ssh-sign-with request, %v", err)
	}

	respJson, err = SSHSignWith(sshSignWithJson)
	if err != nil {
	        t.Fatalf("Error in ssh-sign-with, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
	        t.Fatalf("Error in ssh-sign-with, %v", err)
	}
	if s.Status != "cannot sign with this file" {
	        t.Fatalf("Expected error using ssh-sign-with without 'ssh-sign-with' usage, got %v", s.Status)
	}

	e.Usages = []string{"ssh-sign-with"}
	encryptJson, err = json.Marshal(e)
	if err != nil {
	        t.Fatalf("Error marshalling encrypt request, %v", err)
	}

	respJson, err = Encrypt(encryptJson)
	if err != nil {
	        t.Fatalf("Error in encrypt, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
	        t.Fatalf("Error in encrypt, %v", err)
	}
	if s.Status != "ok" {
	        t.Fatalf("Error in encrypt, %v", s.Status)
	}

	sshSignWithJson, err = json.Marshal(SSHSignWithRequest{Name: "Alice", Password: "Hello", Data: s.Response, TBSData: []byte("signme")})
	if err != nil {
	        t.Fatalf("Error marshalling ssh-sign-with request, %v", err)
	}

	respJson, err = SSHSignWith(sshSignWithJson)
	if err != nil {
	        t.Fatalf("Error in ssh-sign-with, %v", err)
	}
	err = json.Unmarshal(respJson, &s)
	if err != nil {
	        t.Fatalf("Error in ssh-sign-with, %v", err)
	}
	if s.Status != "ok" {
	        t.Fatalf("Error in ssh-sign-with, %v", s.Status)
	}

	var sshSignWithResponse SSHSignatureWithDelegates
	err = json.Unmarshal(s.Response, &sshSignWithResponse)
	if err != nil {
	        t.Fatalf("Error unmarshalling ssh-sign-with response, %v", err)
	}

	sshSignature := ssh.Signature{
		Format: sshSignWithResponse.SignatureFormat,
		Blob:   sshSignWithResponse.Signature,
	}
	err = sshPubKey.Verify([]byte("signme"), &sshSignature)
	if err != nil {
	        t.Fatalf("Error verifying ssh-sign-with signature, %v", err)
	}
}

// Create a vault for the restore tests.
func restoreCreateVault(t *testing.T, pstore, file string) {
	cfg := config.New()
	cfg.Delegations = &config.Delegations{
		Persist:   true,
		Mechanism: persist.FileMechanism,
		Policy:    "Alice & Carl",
		Users:     []string{"Alice", "Carl"},
		Location:  pstore,
	}

	if err := Init(file, cfg); err != nil {
		t.Fatalf("Unable to initialise core: %s", err)
	}
}

func restoreState(t *testing.T, expected string) {
	statusJson := []byte("{\"Name\":\"Admin\",\"Password\":\"Admin\"}")

	var rd ResponseData
	var st StatusData

	if respJson, err := Status(statusJson); err != nil {
		t.Fatalf("Failed to look up vault state: %s", err)
	} else if err = json.Unmarshal(respJson, &rd); err != nil {
		t.Fatalf("Error getting status, %v", err)
	} else if err = json.Unmarshal(rd.Response, &st); err != nil {
		t.Fatalf("Error getting status, %v", err)
	} else if st.Status != expected {
		t.Fatalf("Persistent delegations should be '%s' but are '%s'",
			expected, st.Status)
	}
}

// beforeRestartRestore contains the test sequence to run before
// simulating a restart of the vault.
func beforeRestartRestore(t *testing.T) {
	adminUser := []byte("{\"Name\":\"Admin\",\"Password\":\"Admin\"}")
	createUser := []byte("{\"Name\":\"Carl\",\"Password\":\"Hello\"}")

	_, err := Create(adminUser)
	if err != nil {
		t.Fatalf("Unable to create new diskrecord: %s", err)
	}

	var s ResponseData
	respJson, err := CreateUser(createUser)
	if err != nil {
		t.Fatalf("Error creating user: %s", err)
	} else if err = json.Unmarshal(respJson, &s); err != nil {
		t.Fatalf("Error creating user: %s", err)
	} else if s.Status != "ok" {
		t.Fatalf("Failed to create user: %v", s)
	}

	restoreState(t, persist.Active)
	restoreDelegateNormal(t)
}

// restoreDelegateNormal performs standard delegations against the
// vault; the test will make sure these exist.
func restoreDelegateNormal(t *testing.T) {
	delegateJson1 := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Time\":\"5m\",\"Uses\":2}")
	delegateJson2 := []byte("{\"Name\":\"Bob\",\"Password\":\"Hello\",\"Time\":\"15m\",\"Uses\":3}")

	var s ResponseData
	respJson, err := Delegate(delegateJson1)
	if err != nil {
		t.Fatalf("Error delegating: %s", err)
	}

	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error delegating: %s", err)
	} else if s.Status != "ok" {
		t.Fatalf("Error delegating: %s", s.Status)
	}

	respJson, err = Delegate(delegateJson2)
	if err != nil {
		t.Fatalf("Error delegating: %s", err)
	}

	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error delegating: %s", err)
	} else if s.Status != "ok" {
		t.Fatalf("Error delegating: %s", s.Status)
	}
}

func restoreGetSummary(t *testing.T) SummaryData {
	adminUser := []byte("{\"Name\":\"Admin\",\"Password\":\"Admin\"}")
	respJson, err := Summary(adminUser)
	if err != nil {
		t.Fatalf("Error retrieving vault summary: %s", err)
	}

	var s SummaryData
	if err = json.Unmarshal(respJson, &s); err != nil {
		t.Fatalf("Error unmarshalling summary data: %s", err)
	} else if s.Status != "ok" {
		t.Fatalf("Vault returned error retrieving summary: %s", err)
	}

	return s
}

func afterRestartRestore(t *testing.T) {
	restoreState(t, persist.Inactive)

	// Ensure there are no active delegations after the restart.
	summary := restoreGetSummary(t)
	if len(summary.Live) != 0 {
		t.Fatalf("There should be no live users after restart, but there are %d", len(summary.Live))
	}

	restoreDelegateRestore(t)
}

func restoreDelegateRestore(t *testing.T) {
	adminUser := []byte("{\"Name\":\"Admin\",\"Password\":\"Admin\"}")
	delegateJsonBad := []byte("{\"Name\":\"Alice\",\"Password\":\"Hi\",\"Time\":\"5m\",\"Uses\":3}")
	delegateJson1 := []byte("{\"Name\":\"Alice\",\"Password\":\"Hello\",\"Time\":\"5m\",\"Uses\":3}")
	delegateJson2 := []byte("{\"Name\":\"Carl\",\"Password\":\"Hello\",\"Time\":\"5m\",\"Uses\":3}")
	delegateJson3 := []byte("{\"Name\":\"Carl\",\"Password\":\"Hello\",\"Time\":\"5m\",\"Uses\":3}")

	var s ResponseData
	respJson, err := Restore(delegateJsonBad)
	if err != nil {
		t.Fatalf("Error making restore request: %s", err)
	}

	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error delegating: %s", err)
	} else if s.Status != "Wrong Password" {
		t.Fatal("Restore should fail with bad password.")
	}

	restoreState(t, persist.Inactive)

	respJson, err = Restore(delegateJson1)
	if err != nil {
		t.Fatalf("Error delegating: %s", err)
	}

	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error delegating: %s", err)
	} else if s.Status != "ok" {
		t.Fatalf("Error delegating: %s", s.Status)
	}
	restoreState(t, persist.Inactive)

	// The following delegation should be lost in the restoration.
	respJson, err = Delegate(delegateJson2)
	if err != nil {
		t.Fatalf("Error delegating: %s", err)
	}

	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error delegating: %s", err)
	} else if s.Status != "ok" {
		t.Fatalf("Error delegating: %s", s.Status)
	}

	summary := restoreGetSummary(t)
	if len(summary.Live) != 1 {
		t.Fatalf("There should be a single live delegation, but there are %d", len(summary.Live))
	}

	respJson, err = Restore(delegateJson3)
	if err != nil {
		t.Fatalf("Error delegating: %s", err)
	}

	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error delegating: %s", err)
	} else if s.Status != "ok" {
		t.Fatalf("Error delegating: %s", s.Status)
	}
	restoreState(t, persist.Active)

	summary = restoreGetSummary(t)
	if len(summary.Live) != 2 {
		t.Fatalf("There should be two active delegations, but there are %d", len(summary.Live))
	}

	if _, ok := summary.Live["Carl"]; ok {
		t.Fatalf("Bob shouldn't be present in the active delegations.")
	} else if _, ok = summary.Live["Alice"]; !ok {
		t.Fatalf("Alice should be present in the active delegations.")
	} else if _, ok = summary.Live["Bob"]; !ok {
		t.Fatalf("Bob should be present in the active delegations.")
	}

	respJson, err = ResetPersisted(adminUser)
	if err != nil {
		t.Fatalf("Resetting persisted delegations failed: %s", err)
	}

	err = json.Unmarshal(respJson, &s)
	if err != nil {
		t.Fatalf("Error resetting persisted delegations: %s", err)
	} else if s.Status != "ok" {
		t.Fatalf("Error resetting persisted delegations: %s", s.Status)
	}
	restoreState(t, persist.Active)
}

func TestRestore(t *testing.T) {
	pstore := tempName(t)
	defer os.Remove(pstore)

	file := tempName(t)
	defer os.Remove(file)

	// Create the vault, an admin user, and perform some delegations.
	restoreCreateVault(t, pstore, file)
	beforeRestartRestore(t)

	// Restart the vault; this simulates restarting the Red
	// October server.
	restoreCreateVault(t, pstore, file)
	afterRestartRestore(t)
}
