diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9bbb5a452..e55182335 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -63,7 +63,7 @@ jobs: - name: Setup Sonar Scanner uses: warchant/setup-sonar-scanner@v7 with: - version: 4.6.2.2472 + version: 5.0.2.4997 - name: Run Sonar Scanner env: @@ -182,4 +182,4 @@ jobs: push: true tags: > ${{ inputs.DOCKER_REPO }}/api:${{ inputs.DOCKER_TAG }}, - ${{ inputs.DOCKER_REPO }}/api:latest \ No newline at end of file + ${{ inputs.DOCKER_REPO }}/api:latest diff --git a/code/sonar-project.properties b/code/sonar-project.properties index 326a7d1f0..f3d2a9087 100644 --- a/code/sonar-project.properties +++ b/code/sonar-project.properties @@ -3,6 +3,8 @@ sonar.projectKey=nuvla-api-server sonar.projectName=nuvla-api-server sonar.sources=src,project.clj sonar.inclusions=**/*.clj, **/*.cljc +sonar.clojure.file.suffixes=.clj,.cljc +sonar.lang.patterns.clj=**/*.clj,**/*.cljc sonar.tests=test sonar.testExecutionReportPaths=test-reports/sonar/testExecutions.xml sonar.clojure.sensors.timeout=3600 diff --git a/code/src/com/sixsq/nuvla/server/resources/callback/utils.clj b/code/src/com/sixsq/nuvla/server/resources/callback/utils.clj index 762402a4e..9130a8b3d 100644 --- a/code/src/com/sixsq/nuvla/server/resources/callback/utils.clj +++ b/code/src/com/sixsq/nuvla/server/resources/callback/utils.clj @@ -1,8 +1,10 @@ (ns com.sixsq.nuvla.server.resources.callback.utils (:require + [clojure.string :as str] [com.sixsq.nuvla.db.impl :as db] [com.sixsq.nuvla.server.resources.common.crud :as crud] - [com.sixsq.nuvla.server.resources.common.utils :as u])) + [com.sixsq.nuvla.server.resources.common.utils :as u] + [com.sixsq.nuvla.server.util.general :as gen-util])) (defn executable? @@ -37,3 +39,8 @@ db/edit) (catch Exception e (or (ex-data e) (throw e))))) + +(defn callback-ui-url + [callback-url] + (let [base-uri (first (str/split callback-url #"api/callback"))] + (str base-uri "ui/callback?callback-url=" (gen-util/encode-uri-component callback-url)))) diff --git a/code/src/com/sixsq/nuvla/server/resources/email.clj b/code/src/com/sixsq/nuvla/server/resources/email.clj index f528141d2..d20e23a3f 100644 --- a/code/src/com/sixsq/nuvla/server/resources/email.clj +++ b/code/src/com/sixsq/nuvla/server/resources/email.clj @@ -15,6 +15,7 @@ address. When the callback is triggered, the `validated` flag is set to true. [com.sixsq.nuvla.server.resources.common.std-crud :as std-crud] [com.sixsq.nuvla.server.resources.common.utils :as u] [com.sixsq.nuvla.server.resources.email.utils :as email-utils] + [com.sixsq.nuvla.server.resources.callback.utils :as callback-utils] [com.sixsq.nuvla.server.resources.resource-metadata :as md] [com.sixsq.nuvla.server.resources.spec.email :as email] [com.sixsq.nuvla.server.util.metadata :as gen-md] @@ -131,6 +132,7 @@ address. When the callback is triggered, the `validated` flag is set to true. (if-not validated (try (-> (email-utils/create-callback id base-uri) + callback-utils/callback-ui-url (email-utils/send-validation-email address)) (r/map-response "check your mailbox for a validation message" 202) (catch Exception e diff --git a/code/src/com/sixsq/nuvla/server/resources/group.clj b/code/src/com/sixsq/nuvla/server/resources/group.clj index 44f02e025..31cd6ff5c 100644 --- a/code/src/com/sixsq/nuvla/server/resources/group.clj +++ b/code/src/com/sixsq/nuvla/server/resources/group.clj @@ -13,6 +13,7 @@ that start with 'nuvla-' are reserved for the server. [com.sixsq.nuvla.db.filter.parser :as parser] [com.sixsq.nuvla.db.impl :as db] [com.sixsq.nuvla.server.resources.callback-join-group :as callback-join-group] + [com.sixsq.nuvla.server.resources.callback.utils :as callback-utils] [com.sixsq.nuvla.server.resources.common.crud :as crud] [com.sixsq.nuvla.server.resources.common.std-crud :as std-crud] [com.sixsq.nuvla.server.resources.common.utils :as u] @@ -246,7 +247,7 @@ that start with 'nuvla-' are reserved for the server. (str set-password-url "?callback=" (gen-util/encode-uri-component callback-url) "&type=" (gen-util/encode-uri-component "invitation") "&username=" (gen-util/encode-uri-component email)) - callback-url)] + (callback-utils/callback-ui-url callback-url))] (email-utils/send-join-group-email id invited-by invite-url email) (r/map-response (format "successfully invited to %s" id) 200 id)) (catch Exception e diff --git a/code/src/com/sixsq/nuvla/server/resources/user_email_password.clj b/code/src/com/sixsq/nuvla/server/resources/user_email_password.clj index 3f9a837e2..db71f930f 100644 --- a/code/src/com/sixsq/nuvla/server/resources/user_email_password.clj +++ b/code/src/com/sixsq/nuvla/server/resources/user_email_password.clj @@ -6,6 +6,7 @@ address and password. (:require [com.sixsq.nuvla.server.resources.callback :as callback] [com.sixsq.nuvla.server.resources.callback-user-email-validation :as user-email-callback] + [com.sixsq.nuvla.server.resources.callback.utils :as callback-utils] [com.sixsq.nuvla.server.resources.common.utils :as u] [com.sixsq.nuvla.server.resources.email.utils :as email-utils] [com.sixsq.nuvla.server.resources.spec.user-template-email-password :as spec-email-password] @@ -61,6 +62,7 @@ address and password. :password password :customer customer) (-> (create-user-email-callback base-uri id :data callback-data) + callback-utils/callback-ui-url (email-utils/send-validation-email email))) (catch Exception e (user-utils/delete-user id) diff --git a/code/test/com/sixsq/nuvla/server/resources/callback/utils_test.clj b/code/test/com/sixsq/nuvla/server/resources/callback/utils_test.clj index bd9fd3d96..81dc5e0b2 100644 --- a/code/test/com/sixsq/nuvla/server/resources/callback/utils_test.clj +++ b/code/test/com/sixsq/nuvla/server/resources/callback/utils_test.clj @@ -19,3 +19,8 @@ false {:state "SUCCEEDED", :expires past} false {:state "SUCCEEDED"} false {}))) + +(deftest callback-ui-url + (are [expected arg] (= expected (t/callback-ui-url arg)) + "https://nuid.localhost/ui/callback?callback-url=https%3A%2F%2Fnuid.localhost%2Fapi%2Fcallback%2Fa1f08e95-7caf-4f84-8b62-dfa621eaad34%2Fexecute" "https://nuid.localhost/api/callback/a1f08e95-7caf-4f84-8b62-dfa621eaad34/execute" + "https://nuvla.io/ui/callback?callback-url=https%3A%2F%2Fnuvla.io%2Fapi%2Fcallback%2Fa1f08e95-7caf-4f84-8b62-dfa621eaad34%2Fexecute" "https://nuvla.io/api/callback/a1f08e95-7caf-4f84-8b62-dfa621eaad34/execute")) diff --git a/code/test/com/sixsq/nuvla/server/resources/email_lifecycle_test.clj b/code/test/com/sixsq/nuvla/server/resources/email_lifecycle_test.clj index 1b5582865..f503bd622 100644 --- a/code/test/com/sixsq/nuvla/server/resources/email_lifecycle_test.clj +++ b/code/test/com/sixsq/nuvla/server/resources/email_lifecycle_test.clj @@ -8,6 +8,7 @@ [com.sixsq.nuvla.server.resources.email.sending :as email-sending] [com.sixsq.nuvla.server.resources.lifecycle-test-utils :as ltu] [com.sixsq.nuvla.server.resources.resource-metadata :as md] + [com.sixsq.nuvla.server.util.general :as gen-util] [com.sixsq.nuvla.server.util.metadata-test-utils :as mdtu] [jsonista.core :as j] [peridot.core :refer [content-type header request session]] @@ -140,11 +141,8 @@ :pass "password"}) ;; WARNING: This is a fragile! Regex matching to recover callback URL. - postal/send-message (fn [_ {:keys [body]}] - (let [url (->> body second :content - (re-matches #"(?s).*visit:\n\n\s+(.*?)\n.*") - second)] - (reset! validation-link url)) + postal/send-message (fn [_ msg] + (reset! validation-link (ltu/extract-msg-callback-url msg)) {:code 0, :error :SUCCESS, :message "OK"})] (-> session-anon diff --git a/code/test/com/sixsq/nuvla/server/resources/hook_reset_password_lifecycle_test.clj b/code/test/com/sixsq/nuvla/server/resources/hook_reset_password_lifecycle_test.clj index 1be2f07fa..d8b48a196 100644 --- a/code/test/com/sixsq/nuvla/server/resources/hook_reset_password_lifecycle_test.clj +++ b/code/test/com/sixsq/nuvla/server/resources/hook_reset_password_lifecycle_test.clj @@ -8,12 +8,10 @@ [com.sixsq.nuvla.server.resources.hook-reset-password :as hrp] [com.sixsq.nuvla.server.resources.lifecycle-test-utils :as ltu] [com.sixsq.nuvla.server.resources.session-password-lifecycle-test :as password-test] - [com.sixsq.nuvla.server.resources.session-template :as st] [com.sixsq.nuvla.server.util.general :as gen-util] [jsonista.core :as j] [peridot.core :refer [content-type header request session]] - [postal.core :as postal] - [ring.util.codec :as codec])) + [postal.core :as postal])) (use-fixtures :once ltu/with-test-server-fixture) @@ -21,9 +19,6 @@ (def base-uri (str p/service-context t/resource-type "/" hrp/action)) - -(def session-template-base-uri (str p/service-context st/resource-type)) - (deftest lifecycle (let [reset-link (atom nil) diff --git a/code/test/com/sixsq/nuvla/server/resources/lifecycle_test_utils.clj b/code/test/com/sixsq/nuvla/server/resources/lifecycle_test_utils.clj index d7c4aa0f7..db4fd50cc 100644 --- a/code/test/com/sixsq/nuvla/server/resources/lifecycle_test_utils.clj +++ b/code/test/com/sixsq/nuvla/server/resources/lifecycle_test_utils.clj @@ -20,6 +20,7 @@ [com.sixsq.nuvla.server.middleware.logger :refer [wrap-logger]] [com.sixsq.nuvla.server.resources.common.dynamic-load :as dyn] [com.sixsq.nuvla.server.resources.event.utils :as event-utils] + [com.sixsq.nuvla.server.util.general :as gen-util] [com.sixsq.nuvla.server.util.kafka :as ka] [com.sixsq.nuvla.server.util.zookeeper :as uzk] [compojure.core :as cc] @@ -628,3 +629,10 @@ (is-event expected-event# actual-event#)) ~expected-events events#)))) + +(defn extract-msg-callback-url + [{:keys [body] :as _msg}] + (->> body second :content + (re-matches #"(?s).*visit:\n\n\s+.*callback-url=(.*?)\n.*") + second + gen-util/decode-uri-component)) diff --git a/code/test/com/sixsq/nuvla/server/resources/session/utils_test.clj b/code/test/com/sixsq/nuvla/server/resources/session/utils_test.clj index f0e87278c..64fe17385 100644 --- a/code/test/com/sixsq/nuvla/server/resources/session/utils_test.clj +++ b/code/test/com/sixsq/nuvla/server/resources/session/utils_test.clj @@ -15,16 +15,10 @@ [peridot.core :refer [content-type header request session]] [postal.core :as postal])) - (use-fixtures :once ltu/with-test-server-fixture) - (def base-uri (str p/service-context session/resource-type)) - -(def session-template-base-uri (str p/service-context st/resource-type)) - - (defn create-user [session-admin & {:keys [username password email activated?]}] (let [validation-link (atom nil) @@ -41,11 +35,8 @@ :user "admin" :pass "password"}) - ;; WARNING: This is a fragile! Regex matching to recover callback URL. - postal/send-message (fn [_ {:keys [body]}] - (let [url (->> body second :content - (re-matches #"(?s).*visit:\n\n\s+(.*?)\n.*") - second)] + postal/send-message (fn [_ msg] + (let [url (ltu/extract-msg-callback-url msg)] (reset! validation-link url)) {:code 0, :error :SUCCESS, :message "OK"})] diff --git a/code/test/com/sixsq/nuvla/server/resources/session_password_lifecycle_test.clj b/code/test/com/sixsq/nuvla/server/resources/session_password_lifecycle_test.clj index dda6ef283..489c5fbfd 100644 --- a/code/test/com/sixsq/nuvla/server/resources/session_password_lifecycle_test.clj +++ b/code/test/com/sixsq/nuvla/server/resources/session_password_lifecycle_test.clj @@ -48,11 +48,8 @@ :pass "password"}) ;; WARNING: This is a fragile! Regex matching to recover callback URL. - postal/send-message (fn [_ {:keys [body]}] - (let [url (->> body second :content - (re-matches #"(?s).*visit:\n\n\s+(.*?)\n.*") - second)] - (reset! validation-link url)) + postal/send-message (fn [_ msg] + (reset! validation-link (ltu/extract-msg-callback-url msg)) {:code 0, :error :SUCCESS, :message "OK"})] (let [user-id (-> session-admin diff --git a/code/test/com/sixsq/nuvla/server/resources/user_email_password_2fa_lifecycle_test.clj b/code/test/com/sixsq/nuvla/server/resources/user_email_password_2fa_lifecycle_test.clj index 389ebe85d..6efe9fe41 100644 --- a/code/test/com/sixsq/nuvla/server/resources/user_email_password_2fa_lifecycle_test.clj +++ b/code/test/com/sixsq/nuvla/server/resources/user_email_password_2fa_lifecycle_test.clj @@ -31,7 +31,7 @@ (deftest lifecycle-email - (let [email-body (atom nil) + (let [email-msg (atom nil) session (-> (ltu/ring-app) session (content-type "application/json")) @@ -46,8 +46,8 @@ :pass "password"}) ;; WARNING: This is a fragile Regex matching to recover callback URL. - postal/send-message (fn [_ {:keys [body]}] - (reset! email-body body) + postal/send-message (fn [_ msg] + (reset! email-msg msg) {:code 0, :error :SUCCESS, :message "OK"})] (let [href (str user-tpl/resource-type "/" email-password/registration-method) @@ -78,10 +78,9 @@ (ltu/is-operation-present :enable-2fa) (ltu/is-operation-absent :disable-2fa) (ltu/get-op-url :enable-2fa)) - - validation-link (->> @email-body second :content - (re-matches #"(?s).*visit:\n\n\s+(.*?)\n.*") - second) + validation-link (ltu/extract-msg-callback-url @email-msg) + get-user-token #(->> @email-msg :body second :content + (re-find #"\d+")) session-base-url (str p/service-context session/resource-type) valid-session-create {:template {:href (str st/resource-type "/password") @@ -152,8 +151,7 @@ (re-matches #"http.*(\/api.*)\/execute") second) callback-exec-url (str callback-url "/execute") - user-token (->> @email-body second :content - (re-find #"\d+"))] + user-token (get-user-token)] (-> session-admin (request callback-url) @@ -222,8 +220,7 @@ (re-matches #"http.*(\/api.*)\/execute") second) callback-exec-url (str callback-url "/execute") - user-token (->> @email-body second :content - (re-find #"\d+"))] + user-token (get-user-token)] (-> session-admin (request callback-url) @@ -295,8 +292,7 @@ (re-matches #"http.*(\/api.*)\/execute") second) callback-exec-url (str callback-url "/execute") - user-token (->> @email-body second :content - (re-find #"\d+"))] + user-token (get-user-token)] (-> session-admin (request callback-url) @@ -364,8 +360,7 @@ (re-matches #"http.*(\/api.*)\/execute") second) callback-exec-url (str callback-url "/execute") - user-token (->> @email-body second :content - (re-find #"\d+"))] + user-token (get-user-token)] (-> session-admin (request callback-url) @@ -424,7 +419,7 @@ (deftest lifecycle-totp - (let [email-body (atom nil) + (let [email-msg (atom nil) session (-> (ltu/ring-app) session (content-type "application/json")) @@ -439,8 +434,8 @@ :pass "password"}) ;; WARNING: This is a fragile Regex matching to recover callback URL. - postal/send-message (fn [_ {:keys [body]}] - (reset! email-body body) + postal/send-message (fn [_ msg] + (reset! email-msg msg) {:code 0, :error :SUCCESS, :message "OK"})] (let [href (str user-tpl/resource-type "/" email-password/registration-method) @@ -473,9 +468,7 @@ (ltu/is-operation-absent :disable-2fa) (ltu/get-op-url :enable-2fa)) - validation-link (->> @email-body second :content - (re-matches #"(?s).*visit:\n\n\s+(.*?)\n.*") - second) + validation-link (ltu/extract-msg-callback-url @email-msg) session-base-url (str p/service-context session/resource-type) valid-session-create {:template {:href (str st/resource-type "/password") @@ -782,10 +775,10 @@ (testing "credential totp should be delete at deactivation" (let [cred-totp (-> session-created-user - (request user-url) - (ltu/body->edn) - (ltu/is-status 200) - :credential-totp)] + (request user-url) + (ltu/body->edn) + (ltu/is-status 200) + :credential-totp)] (-> session-admin (request (str p/service-context cred-totp)) (ltu/body->edn) diff --git a/code/test/com/sixsq/nuvla/server/resources/user_email_password_lifecycle_test.clj b/code/test/com/sixsq/nuvla/server/resources/user_email_password_lifecycle_test.clj index 1c8aa30a5..4daf99523 100644 --- a/code/test/com/sixsq/nuvla/server/resources/user_email_password_lifecycle_test.clj +++ b/code/test/com/sixsq/nuvla/server/resources/user_email_password_lifecycle_test.clj @@ -46,12 +46,8 @@ :user "admin" :pass "password"}) - ;; WARNING: This is a fragile! Regex matching to recover callback URL. - postal/send-message (fn [_ {:keys [body]}] - (let [url (->> body second :content - (re-matches #"(?s).*visit:\n\n\s+(.*?)\n.*") - second)] - (reset! validation-link url)) + postal/send-message (fn [_ msg] + (reset! validation-link (ltu/extract-msg-callback-url msg)) {:code 0, :error :SUCCESS, :message "OK"})] (let [template (-> session-admin