;; This Source Code Form is subject to the terms of the Mozilla Public ;; License, v. 2.0. If a copy of the MPL was not distributed with this ;; file, You can obtain one at http://mozilla.org/MPL/2.0/. ;; ;; Copyright (c) KALEIDOS INC (ns app.setup "Initial data setup of instance." (:require [app.common.logging :as l] [app.common.spec :as us] [app.common.uuid :as uuid] [app.db :as db] [app.main :as-alias main] [app.setup.keys :as keys] [app.setup.templates] [buddy.core.codecs :as bc] [buddy.core.nonce :as bn] [clojure.spec.alpha :as s] [integrant.core :as ig])) (defn- generate-random-key [] (-> (bn/random-bytes 64) (bc/bytes->b64u) (bc/bytes->str))) (defn- retrieve-all [conn] (->> (db/query conn :server-prop {:preload true}) (filter #(not= "secret-key" (:id %))) (map (fn [row] [(keyword (:id row)) (db/decode-transit-pgobject (:content row))])) (into {}))) (defn- handle-instance-id [instance-id conn read-only?] (or instance-id (let [instance-id (uuid/random)] (when-not read-only? (try (db/insert! conn :server-prop {:id "instance-id" :preload true :content (db/tjson instance-id)}) (catch Throwable cause (l/warn :hint "unable to persist instance-id" :instance-id instance-id :cause cause)))) instance-id))) (s/def ::main/key ::us/string) (s/def ::main/props (s/map-of ::us/keyword some?)) (defmethod ig/pre-init-spec ::props [_] (s/keys :req [::db/pool] :opt [::main/key])) (defmethod ig/init-key ::props [_ {:keys [::db/pool ::main/key] :as cfg}] (db/with-atomic [conn pool] (db/xact-lock! conn 0) (when-not key (l/warn :hint (str "using autogenerated secret-key, it will change on each restart and will invalidate " "all sessions on each restart, it is hightly recommended setting up the " "PENPOT_SECRET_KEY environment variable"))) (let [secret (or key (generate-random-key))] (-> (retrieve-all conn) (assoc :secret-key secret) (assoc :tokens-key (keys/derive secret :salt "tokens")) (update :instance-id handle-instance-id conn (db/read-only? pool))))))