;; 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.data :as d] [app.common.logging :as l] [app.common.schema :as sm] [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] [integrant.core :as ig])) (defn- generate-random-key [] (-> (bn/random-bytes 64) (bc/bytes->b64u) (bc/bytes->str))) (defn- get-all-props [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))) (def sql:add-prop "INSERT INTO server_prop (id, content, preload) VALUES (?, ?, ?) ON CONFLICT (id) DO UPDATE SET content=?, preload=?") (defn get-prop ([system prop] (get-prop system prop nil)) ([system prop default] (let [prop (d/name prop)] (db/run! system (fn [{:keys [::db/conn]}] (or (db/get* conn :server-prop {:id prop}) default)))))) (defn set-prop! [system prop value] (let [value (db/tjson value) prop (d/name prop)] (db/run! system (fn [{:keys [::db/conn]}] (db/exec-one! conn [sql:add-prop prop value false value false]))))) (defmethod ig/assert-key ::props [_ params] (assert (db/pool? (::db/pool params)) "expected valid database pool")) (defmethod ig/init-key ::props [_ {:keys [::db/pool ::key] :as cfg}] (db/tx-run! cfg (fn [{:keys [::db/conn]}] (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 highly recommended setting up the " "PENPOT_SECRET_KEY environment variable"))) (let [secret (or key (generate-random-key))] (-> (get-all-props conn) (assoc :secret-key secret) (assoc :tokens-key (keys/derive secret :salt "tokens")) (update :instance-id handle-instance-id conn (db/read-only? pool))))))) ;; FIXME (sm/register! ::props :any)