# Makefile for catlfish

PREFIX=.
INSTDIR=$(PREFIX)/catlfish
SOFTHSM=/usr/local/bin/softhsm2-util

build all:
	./make.erl

clean:
	-rm ebin/*.beam

release: all
	rm -rf $(INSTDIR)
	mkdir $(INSTDIR)
	./makerelease.erl $(INSTDIR)

-include test/test.mk

tests-prepare:
	rm -r $(INSTDIR)/tests || true
	mkdir $(INSTDIR)/tests
	make tests-createca
	make tests-createcert
	mkdir $(INSTDIR)/tests/keys
	(cd $(INSTDIR)/tests/keys ; ../../../tools/create-key.sh logkey)
	openssl pkcs8 -topk8 -nocrypt -in $(INSTDIR)/tests/keys/logkey-private.pem -out $(INSTDIR)/tests/keys/logkey-private.pkcs8
	mkdir $(INSTDIR)/tests/mergedb
	mkdir $(INSTDIR)/tests/mergedb/chains
	touch $(INSTDIR)/tests/mergedb/logorder
	mkdir $(INSTDIR)/tests/mergedb-secondary
	touch $(INSTDIR)/tests/mergedb-secondary/logorder
	printf 0 > $(INSTDIR)/tests/mergedb-secondary/verifiedsize
	mkdir $(INSTDIR)/tests/known_roots
	cp tools/testcerts/roots/* $(INSTDIR)/tests/known_roots
	@for machine in $(MACHINES); do \
	  (cd $(INSTDIR); ../tools/compileconfig.py --config ../test/catlfish-test.cfg --localconfig ../test/catlfish-test-local-$$machine.cfg) && \
	  mkdir -p $(INSTDIR)/tests/machine/machine-$$machine/db && \
	  touch $(INSTDIR)/tests/machine/machine-$$machine/db/index && \
	  touch $(INSTDIR)/tests/machine/machine-$$machine/db/newentries ; \
	done
	(cd $(INSTDIR); ../tools/compileconfig.py --config ../test/catlfish-test.cfg --localconfig ../test/catlfish-test-local-merge-2.cfg)
	(cd $(INSTDIR); ../tools/compileconfig.py --config ../test/catlfish-test.cfg --localconfig ../test/catlfish-test-local-signing.cfg)
	mkdir $(INSTDIR)/tests/privatekeys
	mkdir $(INSTDIR)/tests/publickeys
	@for node in $(NODES); do \
	  (cd $(INSTDIR)/tests/privatekeys ; ../../../tools/create-key.sh $$node) ; \
	  mv $(INSTDIR)/tests/privatekeys/$$node.pem $(INSTDIR)/tests/publickeys/ ; \
	  mkdir -p test/nodes/$$node/log ; \
	done
	(cd $(INSTDIR)/tests/privatekeys ; ../../../tools/create-key.sh merge-1)
	mv $(INSTDIR)/tests/privatekeys/merge-1.pem $(INSTDIR)/tests/publickeys/
	(cd $(INSTDIR)/tests/privatekeys ; ../../../tools/create-key.sh merge-2)
	mv $(INSTDIR)/tests/privatekeys/merge-2.pem $(INSTDIR)/tests/publickeys/
	-test -x $(SOFTHSM) && $(SOFTHSM) --init-token --slot=0 --label=mylabel --so-pin=ffff --pin=ffff
	-test -x $(SOFTHSM) && $(SOFTHSM) --import $(INSTDIR)/tests/keys/logkey-private.pkcs8 --slot 0 --label mylabel --pin ffff --id 00
	rm -f $(INSTDIR)/cur-sth.json

tests-start:
	@for node in $(ERLANGNODES); do \
	  (cd $(INSTDIR) ; bin/run_erl -daemon ../test/nodes/$$node/ ../test/nodes/$$node/log/ "exec bin/erl -config $$node") \
	done
	@for i in 1 2 3 4 5 6 7 8 9 10; do \
	  echo "waiting for system to start" ; \
	  sleep 0.5 ; \
	  allstarted=1 ; \
	  notstarted= ; \
	  for testurl in $(TESTURLS); do \
	    if curl -s --cacert $(INSTDIR)/tests/httpsca/demoCA/cacert.pem -4 https://$$testurl > /dev/null ; then : ; else allstarted=0 ; notstarted="$$testurl $$notstarted" ; fi ; \
	    : ; \
	  done ; \
	  if [ $$allstarted -eq 1 ]; then break ; \
	  elif [ $$i -eq 10 ]; then echo Not started: $$notstarted ; fi ; \
	done

tests-run:
	@(cd $(INSTDIR) && python ../tools/testcase1.py https://localhost:8080/ tests/keys/logkey.pem tests/httpsca/demoCA/cacert.pem) || (echo "Tests failed" ; false)
	@(cd $(INSTDIR) && ../tools/verifysth.py $(BASEURL) --publickey=tests/keys/logkey.pem --cur-sth=stored-sth --cafile tests/httpsca/demoCA/cacert.pem)
	@(cd $(INSTDIR) && python ../tools/check-sth.py --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem https://localhost:8080/) || (echo "Check failed" ; false)
	@(cd $(INSTDIR) && python ../tools/fetchallcerts.py $(BASEURL) --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Verification failed" ; false)
	@(cd $(INSTDIR) && rm -f submittedcerts)
	@(cd $(INSTDIR) && python ../tools/storagegc.py --config ../test/catlfish-test.cfg --localconfig ../test/catlfish-test-local-1.cfg)  || (echo "GC failed" ; false)
	@(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/cert1.txt --check-sct --sct-file=submittedcerts $(BASEURL) --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Submission failed" ; false)
	@(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/cert2.txt --check-sct --sct-file=submittedcerts $(BASEURL) --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Submission failed" ; false)
	@(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/cert3.txt --check-sct --sct-file=submittedcerts $(BASEURL) --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Submission failed" ; false)
	@(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/cert4.txt --check-sct --sct-file=submittedcerts $(BASEURL) --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Submission failed" ; false)
	@(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/cert5.txt --check-sct --sct-file=submittedcerts $(BASEURL) --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Submission failed" ; false)
	@(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/pre1.txt --check-sct --sct-file=submittedcerts $(BASEURL) --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Submission failed" ; false)
	@(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/pre2.txt --check-sct --sct-file=submittedcerts $(BASEURL) --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Submission failed" ; false)
	@(cd $(INSTDIR) && python ../tools/storagegc.py --config ../test/catlfish-test.cfg --localconfig ../test/catlfish-test-local-1.cfg)  || (echo "GC failed" ; false)
	@(cd $(INSTDIR) && ../tools/merge --config ../test/catlfish-test.cfg --localconfig ../test/catlfish-test-local-merge.cfg) || (echo "Merge failed" ; false)
	@(cd $(INSTDIR) && ../tools/verifysth.py $(BASEURL) --publickey=tests/keys/logkey.pem --cur-sth=stored-sth --cafile tests/httpsca/demoCA/cacert.pem)
	@(cd $(INSTDIR) && python ../tools/check-sth.py --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem https://localhost:8080/) || (echo "Check failed" ; false)
	@(cd $(INSTDIR) && rm -r fetchcertstore || true)
	@(cd $(INSTDIR) && mkdir fetchcertstore)
	@(cd $(INSTDIR) && python ../tools/fetchallcerts.py $(BASEURL) --store fetchcertstore --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Verification failed" ; false)
	@(cd $(INSTDIR)/fetchcertstore && unzip 0000.zip)
	@(cd $(INSTDIR) && python ../tools/comparecert.py ../tools/testcerts/cert1.txt fetchcertstore/00000000) || (echo "Verification failed" ; false)
	@(cd $(INSTDIR) && python ../tools/comparecert.py ../tools/testcerts/cert2.txt fetchcertstore/00000001) || (echo "Verification failed" ; false)
	@(cd $(INSTDIR) && python ../tools/comparecert.py ../tools/testcerts/cert3.txt fetchcertstore/00000002) || (echo "Verification failed" ; false)
	@(cd $(INSTDIR) && python ../tools/comparecert.py ../tools/testcerts/cert4.txt fetchcertstore/00000003) || (echo "Verification failed" ; false)
	@(cd $(INSTDIR) && python ../tools/comparecert.py ../tools/testcerts/cert5.txt fetchcertstore/00000004) || (echo "Verification failed" ; false)
	@(cd $(INSTDIR) && python ../tools/comparecert.py ../tools/testcerts/pre1.txt:../tools/testcerts/pre2.txt fetchcertstore/00000005:fetchcertstore/00000006) || (echo "Verification failed" ; false)
	@(cd $(INSTDIR) && python ../tools/storagegc.py --config ../test/catlfish-test.cfg --localconfig ../test/catlfish-test-local-1.cfg)  || (echo "GC failed" ; false)

	@./tools/to_catlfish.py to_erl test/nodes/merge-2/ "init:stop()"
	@(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/cert6.txt --check-sct --sct-file=submittedcerts $(BASEURL) --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Submission failed" ; false)
	@echo NOTE: merge backup should fail with 111 Connection refused
	@(cd $(INSTDIR) && ../tools/merge --config ../test/catlfish-test.cfg --localconfig ../test/catlfish-test-local-merge.cfg) || (echo "Merge failed" ; false)
	@(cd $(INSTDIR) && treesize=$$(../tools/loginfo.py --config ../test/catlfish-test.cfg --localconfig ../test/catlfish-test-local-merge.cfg --treesize https://localhost:8080/) ; \
	  test "$$treesize" = "7" || (echo "Tree size $$treesize != expected 7" ; false))
	@(cd $(INSTDIR) && ../tools/verifysth.py $(BASEURL) --publickey=tests/keys/logkey.pem --cur-sth=stored-sth --cafile tests/httpsca/demoCA/cacert.pem)
	@(cd $(INSTDIR) && bin/run_erl -daemon ../test/nodes/merge-2/ ../test/nodes/merge-2/log/ "exec bin/erl -config merge-2")
	@for i in 1 2 3 4 5 6 7 8 9 10; do \
	  echo "waiting for system to start" ; \
	  sleep 0.5 ; \
	  if curl -s --cacert $(INSTDIR)/tests/httpsca/demoCA/cacert.pem -4 https://localhost:8181 > /dev/null ; then break; fi ; \
	done
	@(cd $(INSTDIR) && ../tools/merge --config ../test/catlfish-test.cfg --localconfig ../test/catlfish-test-local-merge.cfg) || (echo "Merge failed" ; false)
	@(cd $(INSTDIR) && treesize=$$(../tools/loginfo.py --config ../test/catlfish-test.cfg --localconfig ../test/catlfish-test-local-merge.cfg --treesize https://localhost:8080/) ; \
	  test "$$treesize" = "8" || (echo "Tree size $$treesize != expected 8" ; false))
	@(cd $(INSTDIR) && ../tools/verifysth.py $(BASEURL) --publickey=tests/keys/logkey.pem --cur-sth=stored-sth --cafile tests/httpsca/demoCA/cacert.pem)

tests-run2:
	@(cd $(INSTDIR) ; python ../tools/verifysct.py --sct-file=submittedcerts --parallel 1 $(BASEURL) --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || echo "Verification of SCT:s failed"
	@(cd $(INSTDIR) && ../tools/verifysth.py $(BASEURL) --publickey=tests/keys/logkey.pem --cur-sth=stored-sth --cafile tests/httpsca/demoCA/cacert.pem)
	@(cd $(INSTDIR) && python ../tools/storagegc.py --config ../test/catlfish-test.cfg --localconfig ../test/catlfish-test-local-1.cfg)  || (echo "GC failed" ; false)

tests-prepare-merge-takeover:
	@echo $@
	mv $(INSTDIR)/tests/mergedb catlfish/tests/mergedb-down
	mv $(INSTDIR)/tests/mergedb-secondary catlfish/tests/mergedb
	mkdir $(INSTDIR)/tests/mergedb-secondary
	touch $(INSTDIR)/tests/mergedb-secondary/logorder
	printf 0 > $(INSTDIR)/tests/mergedb-secondary/verifiedsize

tests-run3:
	@echo $@
	@(cd $(INSTDIR) && ../tools/merge --config ../test/catlfish-test.cfg --localconfig ../test/catlfish-test-local-merge.cfg) || (echo "Merge failed" ; false)
	@(cd $(INSTDIR) && ../tools/verifysth.py $(BASEURL) --publickey=tests/keys/logkey.pem --cur-sth=stored-sth --cafile tests/httpsca/demoCA/cacert.pem)
	@(cd $(INSTDIR) && python ../tools/submitcert.py --parallel=1 --store ../tools/testcerts/cert7.txt --check-sct --sct-file=submittedcerts-7 $(BASEURL) --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Submission failed" ; false)
	@(cd $(INSTDIR) && ../tools/merge --config ../test/catlfish-test.cfg --localconfig ../test/catlfish-test-local-merge.cfg) || (echo "Merge failed" ; false)
	@(cd $(INSTDIR) ; python ../tools/verifysct.py --sct-file=submittedcerts --parallel 1 $(BASEURL) --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || echo "Verification of SCT:s failed"
	@(cd $(INSTDIR) && ../tools/verifysth.py $(BASEURL) --publickey=tests/keys/logkey.pem --cur-sth=stored-sth --cafile tests/httpsca/demoCA/cacert.pem)


tests-prepare-redistribute-frontend:
	@echo $@
	mv $(INSTDIR)/tests/machine/machine-1 $(INSTDIR)/tests/machine/machine-1-down && \
	mkdir -p $(INSTDIR)/tests/machine/machine-1/db && \
	touch $(INSTDIR)/tests/machine/machine-1/db/index && \
	touch $(INSTDIR)/tests/machine/machine-1/db/newentries ; \

tests-run4:
	@echo $@
	@(cd $(INSTDIR) && ../tools/merge --config ../test/catlfish-test.cfg --localconfig ../test/catlfish-test-local-merge.cfg) || (echo "Merge failed" ; false)
	@(cd $(INSTDIR) && ../tools/verifysth.py $(BASEURL) --publickey=tests/keys/logkey.pem --cur-sth=stored-sth --cafile tests/httpsca/demoCA/cacert.pem)

tests-stop:
	@for node in $(NODES); do \
	  ./tools/to_catlfish.py to_erl test/nodes/$$node/ "init:stop()"; \
	done

tests-wait:
	sleep 5

tests-makemk:
	tools/compileconfig.py --config=test/catlfish-test.cfg --testmakefile=test/test.mk --machines 1

tests-formatupgrade-prepare:
	rm -r $(INSTDIR)/tests/mergedb
	rm -r $(INSTDIR)/tests/machine/machine-1
	mkdir $(INSTDIR)/tests/machine/machine-1
	cp -r test/oldformat/db $(INSTDIR)/tests/machine/machine-1
	cp -r test/oldformat/mergedb $(INSTDIR)/tests
	@(cd $(INSTDIR) && python ../tools/convertdb.py tests/machine/machine-1/db/certentries)

tests-formatupgrade-run:
	@(cd $(INSTDIR) && rm -r fetchcertstore-old || true)
	@(cd $(INSTDIR) && mkdir fetchcertstore-old)
	@(cd $(INSTDIR) && python ../tools/fetchallcerts.py $(BASEURL) --no-check-signature --store fetchcertstore-old --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Verification failed" ; false)
	@(cd $(INSTDIR)/fetchcertstore-old && unzip 0000.zip)
	@(cd $(INSTDIR) && python ../tools/comparecert.py ../tools/testcerts/cert1.txt fetchcertstore-old/00000000) || (echo "Verification failed" ; false)
	@(cd $(INSTDIR) && python ../tools/comparecert.py ../tools/testcerts/cert2.txt fetchcertstore-old/00000001) || (echo "Verification failed" ; false)
	@(cd $(INSTDIR) && python ../tools/comparecert.py ../tools/testcerts/cert3.txt fetchcertstore-old/00000002) || (echo "Verification failed" ; false)
	@(cd $(INSTDIR) && python ../tools/comparecert.py ../tools/testcerts/cert4.txt fetchcertstore-old/00000003) || (echo "Verification failed" ; false)
	@(cd $(INSTDIR) && python ../tools/comparecert.py ../tools/testcerts/cert5.txt fetchcertstore-old/00000004) || (echo "Verification failed" ; false)
	@(cd $(INSTDIR) && python ../tools/comparecert.py ../tools/testcerts/pre1.txt:../tools/testcerts/pre2.txt fetchcertstore-old/00000005:fetchcertstore-old/00000006) || (echo "Verification failed" ; false)

tests-formatupgrade-prepare2:
	-rm $(INSTDIR)/tests/machine/machine-1/db/sth
	@(cd $(INSTDIR) && python ../tools/convertdb.py tests/mergedb/chains)
	rm -r $(INSTDIR)/tests/mergedb-secondary
	mkdir $(INSTDIR)/tests/mergedb-secondary
	mkdir $(INSTDIR)/tests/mergedb-secondary/chains
	touch $(INSTDIR)/tests/mergedb-secondary/logorder
	printf 0 > $(INSTDIR)/tests/mergedb-secondary/verifiedsize

tests-formatupgrade-run2:
	@(cd $(INSTDIR) && ../tools/merge --config ../test/catlfish-test.cfg --localconfig ../test/catlfish-test-local-merge.cfg) || (echo "Merge failed" ; false)
	@diff -r -x nursery -x verifiedsize -x fetched -x sth -x verified.\* catlfish/tests/mergedb catlfish/tests/mergedb-secondary || (echo "Merge databases not matching" ; false)
	@(cd $(INSTDIR) && rm -r fetchcertstore-old || true)
	@(cd $(INSTDIR) && mkdir fetchcertstore-old)
	@(cd $(INSTDIR) && python ../tools/fetchallcerts.py $(BASEURL) --no-check-signature --store fetchcertstore-old --publickey=tests/keys/logkey.pem --cafile tests/httpsca/demoCA/cacert.pem) || (echo "Verification failed" ; false)
	@(cd $(INSTDIR)/fetchcertstore-old && unzip 0000.zip)
	@(cd $(INSTDIR) && python ../tools/comparecert.py ../tools/testcerts/cert1.txt fetchcertstore-old/00000000) || (echo "Verification failed" ; false)
	@(cd $(INSTDIR) && python ../tools/comparecert.py ../tools/testcerts/cert2.txt fetchcertstore-old/00000001) || (echo "Verification failed" ; false)
	@(cd $(INSTDIR) && python ../tools/comparecert.py ../tools/testcerts/cert3.txt fetchcertstore-old/00000002) || (echo "Verification failed" ; false)
	@(cd $(INSTDIR) && python ../tools/comparecert.py ../tools/testcerts/cert4.txt fetchcertstore-old/00000003) || (echo "Verification failed" ; false)
	@(cd $(INSTDIR) && python ../tools/comparecert.py ../tools/testcerts/cert5.txt fetchcertstore-old/00000004) || (echo "Verification failed" ; false)
	@(cd $(INSTDIR) && python ../tools/comparecert.py ../tools/testcerts/pre1.txt:../tools/testcerts/pre2.txt fetchcertstore-old/00000005:fetchcertstore-old/00000006) || (echo "Verification failed" ; false)

tests:
	@make tests-makemk
	@make tests-prepare
	@make tests-start
	@make tests-run || (sleep 5; make tests-stop ; false)
	@make tests-wait
	@make tests-stop
	@make tests-wait
	@make tests-start
	@make tests-run2 || (sleep 5; make tests-stop ; false)
	@make tests-wait
	@make tests-stop
	@make tests-wait
	@make tests-prepare-merge-takeover
	@make tests-start
	@make tests-run3 || (sleep 5; make tests-stop ; false)
	@make tests-wait
	@make tests-stop
	@make tests-wait
	@make tests-prepare-redistribute-frontend
	@make tests-start
	@make tests-run4 || (sleep 5; make tests-stop ; false)
	@make tests-wait
	@make tests-stop

tests-formatupgrade:
	@make tests-makemk
	@make tests-prepare
	@make tests-formatupgrade-prepare
	@make tests-start
	@make tests-formatupgrade-run || (make tests-stop ; false)
	@make tests-wait
	@make tests-stop
	@make tests-formatupgrade-prepare2
	@make tests-start
	@make tests-formatupgrade-run2 || (make tests-stop ; false)
	@make tests-wait
	@make tests-stop

tests-createca:
	mkdir $(INSTDIR)/tests/httpsca
	( cd $(INSTDIR)/tests/httpsca ; \
	  mkdir -p demoCA/newcerts ; \
	  touch demoCA/index.txt ; \
	  echo 00 > demoCA/serial ; \
	  echo '[ req ]' > caconfig.txt ; \
	  echo 'distinguished_name = req_distinguished_name' >> caconfig.txt ; \
	  echo 'x509_extensions = v3_ca' >> caconfig.txt ; \
	  echo 'string_mask = utf8only' >> caconfig.txt ; \
	  echo '[ req_distinguished_name ]' >> caconfig.txt ; \
	  echo '[ v3_ca ]' >> caconfig.txt ; \
	  echo 'basicConstraints=CA:true' >> caconfig.txt ; \
	  openssl req -newkey rsa:2048 -keyout key.pem -out req.csr -nodes -subj '/countryName=SE/stateOrProvinceName=Stockholm/organizationName=Test/commonName=ca/O=ca' -config caconfig.txt ; \
	  openssl ca -in req.csr -selfsign -keyfile key.pem -out demoCA/cacert.pem -batch \
	)

tests-createcert:
	mkdir $(INSTDIR)/tests/httpscert
	openssl req -new -newkey rsa:2048 -keyout $(INSTDIR)/tests/httpscert/httpskey-1.pem -out $(INSTDIR)/tests/httpsca/httpscert-1.csr -nodes -subj '/countryName=SE/stateOrProvinceName=Stockholm/organizationName=Test/CN=localhost'
	( cd $(INSTDIR)/tests/httpsca ; \
	  openssl ca -in httpscert-1.csr -keyfile key.pem -out httpscert-1.pem -batch \
	)
	cp $(INSTDIR)/tests/httpsca/httpscert-1.pem $(INSTDIR)/tests/httpscert/

dialyze: build
	dialyzer ebin

tags:
	find . -name \*.?rl -o -name \*.py | etags -

# Unit testing.
check: all
	test/check.erl