diff --git a/mysql/spec/hyperion/mysql_spec.clj b/mysql/spec/hyperion/mysql_spec.clj index 31a481d..07853cc 100644 --- a/mysql/spec/hyperion/mysql_spec.clj +++ b/mysql/spec/hyperion/mysql_spec.clj @@ -2,7 +2,7 @@ (:use [speclj.core] [hyperion.sql.spec-helper] [hyperion.dev.spec :only [it-behaves-like-a-datastore]] - [hyperion.api :only [*ds* new-datastore]] + [hyperion.api :only [*ds* new-datastore save find-by-key]] [hyperion.sql.jdbc :only [execute-mutation]] [hyperion.sql.query] [hyperion.mysql :only [new-mysql-datastore]])) @@ -57,5 +57,20 @@ (it-behaves-like-a-datastore) + (context "SQL Injection" + (it "sanitizes strings to be inserted" + (let [evil-string "my evil string' --" + record (save {:kind :testing :name evil-string})] + (should= evil-string (:name (find-by-key (:key record)))))) + + (it "sanitizes table names" + (error-msg-contains? + "Table 'hyperion.my_evil_name`___' doesn't exist" + (save {:kind "my-evil-name` --" :name "test"}))) + + (it "sanitizes column names" + (error-msg-contains? + "Unknown column 'my_evil_name`___' in 'field list'" + (save {:kind :testing (keyword "my-evil-name` --") "test"})))) ) ) diff --git a/postgres/spec/hyperion/postgres_spec.clj b/postgres/spec/hyperion/postgres_spec.clj index f9d59e7..20553ee 100644 --- a/postgres/spec/hyperion/postgres_spec.clj +++ b/postgres/spec/hyperion/postgres_spec.clj @@ -2,11 +2,12 @@ (:use [speclj.core] [hyperion.sql.spec-helper] [hyperion.dev.spec :only [it-behaves-like-a-datastore]] - [hyperion.api :only [*ds*]] + [hyperion.api :only [*ds* save find-by-key]] [hyperion.sql.jdbc :only [execute-mutation]] [hyperion.sql.connection :only [connection]] [hyperion.sql.query] - [hyperion.postgres :only [new-postgres-datastore]])) + [hyperion.postgres :only [new-postgres-datastore]]) + (:import [speclj SpecFailure])) (def create-table-query "CREATE TABLE %s ( @@ -21,17 +22,19 @@ (execute-mutation (make-query (format create-table-query table-name)))) +(def connection-url "jdbc:postgresql://localhost:5432/hyperion") + (describe "Postgres Datastore" (context "creation" (it "with a string as the only param" - (let [ds (new-postgres-datastore "jdbc:postgresql://localhost:5432/hyperion")] + (let [ds (new-postgres-datastore connection-url)] (should= false (.isClosed (.connection ds))) (.close (.connection ds)))) (it "with a kv pairs as params" - (let [ds (new-postgres-datastore :connection-url "jdbc:postgresql://localhost:5432/hyperion")] + (let [ds (new-postgres-datastore :connection-url connection-url)] (should= false (.isClosed (.connection ds))) (.close (.connection ds)))) @@ -39,7 +42,7 @@ (context "live" - (with-connection-and-rollback "jdbc:postgresql://localhost:5432/hyperion") + (with-rollback connection-url) (around [it] (create-table "testing") @@ -48,5 +51,21 @@ (it))) (it-behaves-like-a-datastore) + + (context "SQL Injection" + (it "sanitizes strings to be inserted" + (let [evil-string "my evil string' --" + record (save {:kind :testing :name evil-string})] + (should= evil-string (:name (find-by-key (:key record)))))) + + (it "sanitizes table names" + (error-msg-contains? + "relation \"my_evil_name\"___\" does not exist" + (save {:kind "my-evil-name\" --" :name "test"}))) + + (it "sanitizes column names" + (error-msg-contains? + "column \"my_evil_name\"___\" of relation \"testing\" does not exist" + (save {:kind :testing (keyword "my-evil-name\" --") "test"})))) ) ) diff --git a/sql/src/hyperion/sql/format.clj b/sql/src/hyperion/sql/format.clj index 74abd89..1ba7576 100644 --- a/sql/src/hyperion/sql/format.clj +++ b/sql/src/hyperion/sql/format.clj @@ -1,10 +1,10 @@ (ns hyperion.sql.format - (:use [chee.string :only [snake-case spear-case]] + (:use [chee.string :only [snake-case spear-case gsub]] [hyperion.sql.key :only [compose-key decompose-key]]) (:require [clojure.string :as str])) (defn- add-quotes [s quote] - (str quote s quote)) + (str quote (.replaceAll s quote (str quote quote)) quote)) (defprotocol FormattableForDatabase (table->db [this quote]) diff --git a/sql/src/hyperion/sql/spec_helper.clj b/sql/src/hyperion/sql/spec_helper.clj index 8c37122..e4bfc25 100644 --- a/sql/src/hyperion/sql/spec_helper.clj +++ b/sql/src/hyperion/sql/spec_helper.clj @@ -2,7 +2,30 @@ (:use [speclj.core] [hyperion.sql.connection :only [with-connection-url]] - [hyperion.sql.jdbc :only [rollback]])) + [hyperion.sql.jdbc :only [rollback]]) + (:import [speclj SpecFailure])) + +(defn str-contains? [s sub] + (not= -1 (.indexOf s sub))) + +(defmacro error-msg-contains? [msg form] + `(try + ~form + (throw (SpecFailure. (str "Expected and exception with a message containing " ~msg " but no exception was thrown"))) + (catch Exception e# + (let [message# (.getMessage e#)] + (cond + (.isInstance SpecFailure e#) + (throw e#) + (not (str-contains? (.getMessage e#) ~msg)) + (throw (SpecFailure. (str "Expected and exception with a message containing \"" ~msg "\" but got: \"" message# "\""))) + :else e#))))) + +(defn with-rollback [url] + (around [it] + (with-connection-url url + (rollback + (it))))) (defn with-connection-and-rollback [url] (around [it]