(ns fudo.server-test (:require [fudo.api.request.generator :as gen] [fudo.api.request :as req] [fudo.server.config :as config] [fudo.server.services.dyndns :as dyndns] [fudo.server.services.auth :as auth] [fudo.server.service :as service] [fudo.server.services :as services] [fudo.crypto.utils :as crypt] [fudo.crypto.keys :as key] [fudo.db.dyndns-db :as dyndns-db] [fudo.db.transient-dyndns-db :as test-dyndns-db] [fudo.db.auth-db :as auth-db] [fudo.db.transient-auth-db :as test-auth-db] [fudo.net.ip :as ip] [fudo.net.dns :as dns] [fudo.api.request.authenticator.auth-db :as authenticator] [clojure.data.json :as json] [clojure.test :refer [deftest is]] [orchestra.spec.test :as spectest])) (defn pp [obj] (println (format "TEST_DBG: %s" obj)) obj) (spectest/instrument) (let [test-domain "test.com" test-host "my-host" config (config/init-mock-config {}) test-v4ip "4.3.2.1" test-v6ip "6::2" test-sshfp ["0 0 b9c019543f72777aee2d9b4ba883856f2f1f83e4e62ee8717" "1 1 00a8f69cddae085451dec5d7b54e36e0bedb42241728751b81355f7abe8f99ffb"] test-hosts { "my-v4ip-host" {::dns/v4ip (ip/address test-v4ip)} "my-v6ip-host" {::dns/v6ip (ip/address test-v6ip)} "my-sshfp-host" {::dns/sshfp test-sshfp} } dyndns-db (test-dyndns-db/create true config test-domain test-hosts) dyndns-service (service/initialize (dyndns/create true config dyndns-db)) dyndns-handler (service/generate-handler dyndns-service)] (deftest dyndns-domain (is (= test-domain (-> (gen/make-get "/dyndns/domain") (gen/add-host-header test-host) dyndns-handler :body clojure.string/trim)))) (deftest dyndns-domain-success (is (= 200 (-> (gen/make-get "/dyndns/domain") (gen/add-host-header test-host) dyndns-handler :status)))) (deftest insert-v4ip (is (= 200 (-> (gen/make-put (format "/dyndns/%s/v4ip" test-host) "4.3.2.1") (gen/add-host-header test-host) dyndns-handler :status)))) (deftest read-v4ip (is (= (ip/address test-v4ip) (-> (gen/make-get (format "/dyndns/my-v4ip-host/v4ip")) (gen/add-host-header test-host) dyndns-handler :body clojure.string/trim ip/address)))) (deftest read-v4ip-success (is (= 200 (-> (gen/make-get (format "/dyndns/my-v4ip-host/v4ip")) (gen/add-host-header test-host) dyndns-handler :status)))) (deftest insert-v6ip (is (= 200 (-> (gen/make-put (format "/dyndns/%s/v6ip" test-host) "4::1") (gen/add-host-header test-host) dyndns-handler :status)))) (deftest read-v6ip (is (= (ip/address test-v6ip) (-> (gen/make-get (format "/dyndns/my-v6ip-host/v6ip")) (gen/add-host-header test-host) dyndns-handler :body clojure.string/trim ip/address)))) (deftest read-v6ip-success (is (= 200 (-> (gen/make-get (format "/dyndns/my-v6ip-host/v6ip")) (gen/add-host-header test-host) dyndns-handler :status)))) (deftest insert-sshfp (is (= 200 (-> (gen/make-put (format "/dyndns/%s/sshfp" test-host) (clojure.string/join "\n" test-sshfp)) (gen/add-host-header test-host) dyndns-handler :status)))) (deftest read-sshfp (is (= test-sshfp (-> (gen/make-get (format "/dyndns/my-sshfp-host/sshfp")) (gen/add-host-header test-host) dyndns-handler :body clojure.string/trim (clojure.string/split #"\n"))))) (deftest read-sshfp-success (is (= 200 (-> (gen/make-get (format "/dyndns/my-sshfp-host/sshfp")) (gen/add-host-header test-host) dyndns-handler :status)))) (deftest read-missing-v4ip (is (= 404 (-> (gen/make-get "/dyndns/nonexistent-host/v4ip") (gen/add-host-header test-host) dyndns-handler :status)))) (deftest read-missing-v6ip (is (= 404 (-> (gen/make-get "/dyndns/nonexistent-host/v6ip") (gen/add-host-header test-host) dyndns-handler :status)))) (deftest read-missing-sshfp (is (= 404 (-> (gen/make-get "/dyndns/nonexistent-host/sshfp") (gen/add-host-header test-host) dyndns-handler :status))))) (let [config (config/init-mock-config {}) keypair (key/generate-public-private-pair) pubkey (-> keypair ::key/public-key) key-id (-> pubkey key/pubkey->string crypt/sha1-hash) test-host "test-host" auth-hosts {test-host (auth-db/make-entity test-host pubkey)} auth-db (test-auth-db/create true config auth-hosts) auth-service (auth/create true config auth-db) auth-handler (service/generate-handler auth-service)] (deftest get-key (is (= (key/pubkey->string pubkey) (-> (gen/make-get (format "/auth/entity/%s/key" test-host)) (gen/add-host-header test-host) auth-handler :body clojure.string/trim)))) (deftest get-key-success (is (= 200 (-> (gen/make-get (format "/auth/entity/%s/key" test-host)) (gen/add-host-header test-host) auth-handler :status)))) (deftest get-missing-key (is (= 404 (-> (gen/make-get "/auth/entity/nonexistent-host/key") (gen/add-host-header test-host) auth-handler :status)))) (deftest get-key-id (is (= key-id (-> (gen/make-get (format "/auth/entity/%s/key-id" test-host)) (gen/add-host-header test-host) auth-handler :body clojure.string/trim)))) (deftest get-key-id-success (is (= 200 (-> (gen/make-get (format "/auth/entity/%s/key-id" test-host)) (gen/add-host-header test-host) auth-handler :status)))) (deftest get-missing-key-id (is (= 404 (-> (gen/make-get "/auth/entity/nonexistent-host/key-id") (gen/add-host-header test-host) auth-handler :status))))) (let [debug false test-domain "test.com" test-host "my-host" config (config/init-mock-config {"FUDO_SECRET" "test-secret"}) keypair (key/generate-public-private-pair) privkey (-> keypair ::key/private-key) pubkey (-> keypair ::key/public-key) key-id (-> pubkey key/pubkey->string crypt/sha1-hash) auth-hosts {test-host (auth-db/make-entity test-host pubkey)} auth-db (test-auth-db/create debug config auth-hosts) auth-service (auth/create debug config auth-db) test-v4ip "4.3.2.1" test-v6ip "6::2" test-sshfp ["0 0 b9c019543f72777aee2d9b4ba883856f2f1f83e4e62ee8717" "1 1 00a8f69cddae085451dec5d7b54e36e0bedb42241728751b81355f7abe8f99ffb"] test-hosts { "my-v4ip-host" {::dns/v4ip (ip/address test-v4ip)} "my-v6ip-host" {::dns/v6ip (ip/address test-v6ip)} "my-sshfp-host" {::dns/sshfp test-sshfp} } dyndns-db (test-dyndns-db/create debug config test-domain test-hosts) dyndns-service (service/initialize (dyndns/create debug config dyndns-db)) authenticator (authenticator/init-mock debug config auth-db) local-services {:services [auth-service dyndns-service]} services (services/init-mock debug config local-services authenticator) handler (service/generate-handler services) get-result (fn [url] (-> (gen/make-get url) (gen/add-fudo-secret "test-secret") (gen/authenticate-request test-host privkey key-id) handler)) get-status (fn [url] (:status (get-result url))) get-body (fn [url] (json/read-str (:body (get-result url)))) put-result (fn [url data] (-> (gen/make-put url (json/write-str data)) (gen/add-fudo-secret "test-secret") (gen/authenticate-request test-host privkey key-id) handler)) put-status (fn [url data] (:status (pp (put-result url data))))] (deftest authenticated-get-v4ip-success (is (= 200 (get-status "/api/private/dyndns/my-v4ip-host/v4ip")))) (deftest authenticated-get-v4ip (is (= (ip/address test-v4ip) (ip/address (get-body (format "/api/private/dyndns/my-v4ip-host/v4ip")))))) (deftest authenticated-get-missing-v4ip (is (= 404 (get-status "/api/private/dyndns/nonexistent-host/v4ip")))) (deftest authenticated-put-new-v4ip-unauthorized (is (= 401 (put-status "/api/private/dyndns/new-host/v4ip" "4.5.3.6")))) (deftest authenticated-put-new-v4ip-authorized (is (= 200 (put-status (format "/api/private/dyndns/%s/v4ip" test-host) "4.5.3.6")))) (deftest authenticated-put-new-v6ip-unauthorized (is (= 401 (put-status "/api/private/dyndns/other-host/v6ip" "5::3")))) (deftest authenticated-put-new-v6ip-authorized (is (= 200 (put-status (format "/api/private/dyndns/%s/v6ip" test-host) "5::3")))) (deftest authenticated-get-v6ip-success (is (= 200 (get-status "/api/private/dyndns/my-v6ip-host/v6ip")))) (deftest authenticated-get-v6ip (is (= (ip/address test-v6ip) (ip/address (get-body "/api/private/dyndns/my-v6ip-host/v6ip"))))) (deftest authenticated-get-missing-v6ip (is (= 404 (get-status "/api/private/dyndns/nonexistent-host/v6ip")))) (deftest missing-fudo-secret (is (= 400 (-> (gen/make-get "/api/private/dyndns/my-v4ip-host/v4ip") (gen/authenticate-request test-host privkey key-id) handler :status)))) (deftest missing-fudo-entity-header (is (= 400 (-> (gen/make-get "/api/private/dyndns/my-v4ip-host/v4ip") (gen/add-fudo-secret "test-secret") (gen/authenticate-request test-host privkey key-id) (gen/remove-header "fudo-entity") handler :status)))) (deftest missing-fudo-key-id-header (is (= 400 (-> (gen/make-get "/api/private/dyndns/my-v4ip-host/v4ip") (gen/add-fudo-secret "test-secret") (gen/authenticate-request test-host privkey key-id) (gen/remove-header "fudo-key-id") handler :status)))) (deftest missing-fudo-timestamp-header (is (= 400 (-> (gen/make-get "/api/private/dyndns/my-v4ip-host/v4ip") (gen/add-fudo-secret "test-secret") (gen/authenticate-request test-host privkey key-id) (gen/remove-header "fudo-timestamp") handler :status)))) (deftest missing-fudo-signature-header (is (= 400 (-> (gen/make-get "/api/private/dyndns/my-v4ip-host/v4ip") (gen/add-fudo-secret "test-secret") (gen/authenticate-request test-host privkey key-id) (gen/remove-header "fudo-signature") handler :status)))) (deftest bad-fudo-signature-header (is (= 400 (-> (gen/make-get "/api/private/dyndns/my-v4ip-host/v4ip") (gen/add-fudo-secret "test-secret") (gen/authenticate-request test-host privkey key-id) (req/set-header "fudo-signature" "gobbledigook") handler :status)))))