;; 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 Sucursal en España SL (ns backend-tests.binfile-test "Internal binfile test, no RPC involved" (:require [app.binfile.common :as bfc] [app.binfile.v1 :as v1] [app.binfile.v3 :as v3] [app.common.features :as cfeat] [app.common.pprint :as pp] [app.common.thumbnails :as thc] [app.common.types.shape :as cts] [app.common.uuid :as uuid] [app.db :as db] [app.db.sql :as sql] [app.http :as http] [app.rpc :as-alias rpc] [app.storage :as sto] [app.storage.tmp :as tmp] [backend-tests.helpers :as th] [clojure.test :as t] [cuerdas.core :as str] [datoteka.fs :as fs] [datoteka.io :as io]) (:import java.io.ByteArrayInputStream java.io.DataInputStream)) (t/use-fixtures :once th/state-init) (t/use-fixtures :each th/database-reset) (defn- update-file! [& {:keys [profile-id file-id changes revn] :or {revn 0}}] (let [params {::th/type :update-file ::rpc/profile-id profile-id :id file-id :session-id (uuid/random) :revn revn :vern 0 :features cfeat/supported-features :changes changes} out (th/command! params)] ;; (th/print-result! out) (t/is (nil? (:error out))) (:result out))) (defn- prepare-simple-file [profile] (let [page-id-1 (uuid/custom 1 1) page-id-2 (uuid/custom 1 2) shape-id (uuid/custom 2 1) file (th/create-file* 1 {:profile-id (:id profile) :project-id (:default-project-id profile) :is-shared false})] (update-file! :file-id (:id file) :profile-id (:id profile) :revn 0 :vern 0 :changes [{:type :add-page :name "test 1" :id page-id-1} {:type :add-page :name "test 2" :id page-id-2}]) (update-file! :file-id (:id file) :profile-id (:id profile) :revn 0 :vern 0 :changes [{:type :add-obj :page-id page-id-1 :id shape-id :parent-id uuid/zero :frame-id uuid/zero :components-v2 true :obj (cts/setup-shape {:id shape-id :name "image" :frame-id uuid/zero :parent-id uuid/zero :type :rect})}]) (dissoc file :data))) (t/deftest export-binfile-v3 (let [profile (th/create-profile* 1) file (prepare-simple-file profile) output (tmp/tempfile :suffix ".zip")] (v3/export-files! (-> th/*system* (assoc ::bfc/ids #{(:id file)}) (assoc ::bfc/embed-assets false) (assoc ::bfc/include-libraries false)) (io/output-stream output)) (let [result (-> th/*system* (assoc ::bfc/project-id (:default-project-id profile)) (assoc ::bfc/profile-id (:id profile)) (assoc ::bfc/input output) (v3/import-files!))] (t/is (= (count result) 1)) (t/is (every? uuid? result))))) (t/deftest read-obj-rejects-oversized-buffer ;; N1-07: read-obj! must reject objects exceeding max-object-size ;; before attempting to allocate the buffer (let [size (+ bfc/max-object-size 1) baos (java.io.ByteArrayOutputStream. 17) dos (java.io.DataOutputStream. baos)] (.writeByte dos 5) (.writeLong dos (long size)) (.flush dos) (let [input (java.io.DataInputStream. (ByteArrayInputStream. (.toByteArray baos)))] (binding [v1/*position* (atom 0)] (let [out (try (v1/read-obj! input) nil (catch clojure.lang.ExceptionInfo e (ex-data e)))] ;; Without the guard, read-obj! will either OOM or proceed ;; to read-bytes! on a truncated stream (no :max-file-size-reached). ;; With the guard, it raises :validation :max-file-size-reached. (t/is (= :validation (:type out))) (t/is (= :max-file-size-reached (:code out)))))))) (t/deftest import-rejects-too-many-zip-entries ;; N1-09: import must reject ZIP files exceeding max-zip-entries (let [profile (th/create-profile* 1) file (prepare-simple-file profile) output (tmp/tempfile :suffix ".zip")] (v3/export-files! (-> th/*system* (assoc ::bfc/ids #{(:id file)}) (assoc ::bfc/embed-assets false) (assoc ::bfc/include-libraries false)) (io/output-stream output)) ;; Import with max-zip-entries=1 — the exported ZIP has more entries (let [cfg (-> th/*system* (assoc ::bfc/project-id (:default-project-id profile)) (assoc ::bfc/profile-id (:id profile)) (assoc ::bfc/input output) (assoc ::bfc/import-max-zip-entries 1)) out (try (v3/import-files! cfg) :no-error (catch Throwable e (let [d (or (ex-data e) (some-> (ex-cause e) ex-data))] d)))] (t/is (= :validation (:type out))) (t/is (= :too-many-zip-entries (:code out))))))