(ns metabase.db.encryption (:require [metabase.util.encryption :as encryption] [metabase.util.honey-sql-2 :as h2x] [metabase.util.i18n :refer [trs]] [metabase.util.json :as json] [toucan2.core :as t2])) | |
(set! *warn-on-reflection* true) | |
Encrypt or decrypts the db using the current The passed make-encrypt-fn is used to generate the encryption/decryption function to use by passing versions of encryption/maybe-encrypt to it. | (defn- do-encryption [db-type data-source encrypting? make-encrypt-fn] (let [encrypt-str-fn (make-encrypt-fn encryption/maybe-encrypt) encrypt-bytes-fn (make-encrypt-fn encryption/maybe-encrypt-bytes)] (t2/with-transaction [conn {:datasource data-source}] (doseq [[id details] (t2/select-pk->fn :details :model/Database)] (when (encryption/possibly-encrypted-string? details) (throw (ex-info (trs "Can''t decrypt app db with MB_ENCRYPTION_SECRET_KEY") {:database-id id}))) (t2/update! :conn conn :metabase_database {:id id} {:details (encrypt-str-fn (json/encode details))})) (doseq [[key value] (t2/select-fn->fn :key :value :model/Setting)] (case key "settings-last-updated" (let [current-timestamp-as-string-honeysql (h2x/cast (if (= db-type :mysql) :char :text) [:raw "current_timestamp"])] (t2/update! :conn conn :setting {:key key} {:value current-timestamp-as-string-honeysql})) "encryption-check" (t2/update! :conn conn :setting {:key key} {:value (if encrypting? (encrypt-str-fn (str (random-uuid))) "unencrypted")}) (t2/update! :conn conn :setting {:key key} {:value (encrypt-str-fn value)}))) ;; update all secret values according to the new encryption key ;; fortunately, we don't need to fetch the latest secret instance per ID, as we would need to in order to update ;; a secret value through the regular database save API path; instead, ALL secret values in the app DB (regardless ;; of whether they are the "current version" or not), should be updated with the new key (doseq [[id value] (t2/select-pk->fn :value :model/Secret)] (when (encryption/possibly-encrypted-string? value) (throw (ex-info (trs "Can''t decrypt secret value with MB_ENCRYPTION_SECRET_KEY") {:secret-id id}))) (t2/update! :conn conn :secret {:id id} {:value (encrypt-bytes-fn value)})) (t2/delete! :conn conn :model/QueryCache)))) |
Encrypt the db using the current | (defn encrypt-db [db-type data-source to-key] (when (and (not (nil? to-key)) (empty? to-key)) (throw (ex-info "Cannot encrypt database with an empty key" {}))) (do-encryption db-type data-source true (fn [maybe-encrypt-fn] (if (nil? to-key) maybe-encrypt-fn (partial maybe-encrypt-fn (encryption/validate-and-hash-secret-key to-key)))))) |
Decrypts the database using the current | (defn decrypt-db [db-type data-source] (do-encryption db-type data-source false (constantly identity))) |