Browse Source

bugfix in signature compuation

master
Christian Mueller 12 years ago
parent
commit
2e50f713fb
  1. 3
      API.md
  2. 136
      src/notehub/api.clj
  3. 2
      src/notehub/storage.clj
  4. 10
      test/notehub/test/api.clj

3
API.md

@ -1,9 +1,10 @@
# NoteHub API # NoteHub API
**Version 1.3, status: released.** **Version 1.4, status: released.**
## Changelog ## Changelog
- **V1.4**: Bugfix: no whitespace elimination from the note text is needed now for the signature compuation.
- **V1.3**: New note ID format. - **V1.3**: New note ID format.
- **V1.2**: Theme & fonts can be specified during the publishing. - **V1.2**: Theme & fonts can be specified during the publishing.
- **V1.1**: fields `publisher` and `title` in the response to the note retrieval. - **V1.1**: fields `publisher` and `title` in the response to the note retrieval.

136
src/notehub/api.clj

@ -1,23 +1,23 @@
(ns notehub.api (ns notehub.api
(:import (:import
[java.util Calendar]) [java.util Calendar])
(:use (:use
[notehub.settings] [notehub.settings]
[ring.util.codec :only [url-encode]] [ring.util.codec :only [url-encode]]
[clojure.string :rename {replace sreplace} [clojure.string :rename {replace sreplace}
:only [replace blank? trim lower-case split-lines split]]) :only [replace blank? trim lower-case split-lines split]])
(:require (:require
[ring.util.codec] [ring.util.codec]
[hiccup.util :as util] [hiccup.util :as util]
[notehub.storage :as storage])) [notehub.storage :as storage]))
(def version "1.3") (def version "1.4")
(def domain (def domain
(get-setting (get-setting
(if (get-setting :dev-mode) (if (get-setting :dev-mode)
:dev-domain :dev-domain
:prod-domain))) :prod-domain)))
(defn log (defn log
"Logs args to the server stdout" "Logs args to the server stdout"
@ -37,8 +37,8 @@
(apply str (interpose "/" [year month day title]))) (apply str (interpose "/" [year month day title])))
(defn derive-title [md-text] (defn derive-title [md-text]
(sreplace (first (split-lines md-text)) (sreplace (first (split-lines md-text))
#"(#+|_|\*+|<.*?>)" "")) #"(#+|_|\*+|<.*?>)" ""))
(defn get-date (defn get-date
"Returns today's date" "Returns today's date"
@ -60,19 +60,28 @@
(str domain (url year month day title)))))) (str domain (url year month day title))))))
(defn version-manager [f params] (defn version-manager [f params]
(if-let [version (:version params)] (if-let [req-version (:version params)]
(if (and (:noteID params) (< (Double/parseDouble version) 1.3)) (let [req-version (Double/parseDouble req-version)
(let [resp (f (assoc params version (Double/parseDouble version)]
:noteID (sreplace (params :noteID) #" " "/") (if (< req-version version)
:noteID* (params :noteID))) (let [args params
server-message (get-in resp [:status :message])] args (if (and (:noteID args) (< req-version 1.3))
(assoc-in resp [:status :message] (assoc args
(str :noteID (sreplace (args :noteID) #" " "/")
server-message :noteID* (args :noteID))
(when server-message "; ") args)
"this API version is deprecated and " args (if (and (:note args) (< req-version 1.4))
"will be disabled by the end of June 2014!"))) (assoc args :note* (sreplace (args :note) #"[\n\r]" ""))
(f params)) args)
resp (f args)
server-message (get-in resp [:status :message])]
(assoc-in resp [:status :message]
(str
server-message
(when server-message "; ")
"this API version is deprecated and "
"will be disabled by the end of June 2014!")))
(f params)))
{:status (create-response false "API version expected")})) {:status (create-response false "API version expected")}))
(defn get-note [{:keys [noteID]}] (defn get-note [{:keys [noteID]}]
@ -88,45 +97,48 @@
{:status (create-response false "noteID '%s' unknown" noteID)})) {:status (create-response false "noteID '%s' unknown" noteID)}))
(defn post-note (defn post-note
[{:keys [note pid signature password] :as params}] [{:keys [note pid signature password note*] :as params}]
;(log "post-note: %s" {:pid pid :signature signature :password password :note note}) ;(log "post-note: %s" {:pid pid :signature signature :password password :note note})
(let [errors (filter identity (let [errors (filter identity
[(when-not (storage/valid-publisher? pid) "pid invalid") [(when-not (storage/valid-publisher? pid) "pid invalid")
(when-not (= signature (storage/sign pid (storage/get-psk pid) note)) ; TODO: remove note* after June 2014
"signature invalid") (when-not (= signature (storage/sign pid (storage/get-psk pid) (or note* note)))
(when (blank? note) "note is empty")])] "signature invalid")
(if (empty? errors) (when (blank? note) "note is empty")])]
(let [[year month day] (map str (get-date)) (if (empty? errors)
params (dissoc params :note :pid :signature :password :version) (let [[year month day] (map str (get-date))
raw-title (filter #(or (= \- %) (Character/isLetterOrDigit %)) params (dissoc params :note :pid :signature :password :version)
(-> note derive-title trim (sreplace " " "-") lower-case)) raw-title (filter #(or (= \- %) (Character/isLetterOrDigit %))
max-length (get-setting :max-title-length #(Integer/parseInt %) 80) (-> note derive-title trim (sreplace " " "-") lower-case))
proposed-title (apply str (take max-length raw-title)) max-length (get-setting :max-title-length #(Integer/parseInt %) 80)
title (first (drop-while #(storage/note-exists? (build-key year month day %)) proposed-title (apply str (take max-length raw-title))
(cons proposed-title title (first (drop-while #(storage/note-exists? (build-key year month day %))
(map #(str proposed-title "-" (+ 2 %)) (range))))) (cons proposed-title
noteID (build-key year month day title) (map #(str proposed-title "-" (+ 2 %)) (range)))))
new-params (assoc params :year year :month month :day day :title title) noteID (build-key year month day title)
short-url (get-path (storage/create-short-url noteID new-params) :url) new-params (assoc params :year year :month month :day day :title title)
long-url (get-path noteID)] short-url (get-path (storage/create-short-url noteID new-params) :url)
(do long-url (get-path noteID)]
(storage/add-note noteID note pid password) (do
{:noteID noteID (storage/add-note noteID note pid password)
:longURL (if (empty? params) long-url (str (util/url long-url params))) {:noteID noteID
:shortURL short-url :longURL (if (empty? params) long-url (str (util/url long-url params)))
:status (create-response true)})) :shortURL short-url
{:status (create-response false (first errors))}))) :status (create-response true)}))
{:status (create-response false (first errors))})))
(defn update-note [{:keys [noteID note pid signature password noteID*]}] (defn update-note [{:keys [noteID note pid signature password noteID* note*]}]
;(log "update-note: %s" {:pid pid :noteID noteID :signature signature :password password :note note}) ;(log "update-note: %s" {:pid pid :noteID noteID :signature signature :password password :note note})
(let [errors (filter identity (let [errors (filter identity
[(when-not (storage/valid-publisher? pid) "pid invalid") [(when-not (storage/valid-publisher? pid) "pid invalid")
; TODO: noteID* is a hack introduced by backwards-comp. to older APIs ; TODO: noteID* is a hack introduced by backwards-comp. to older APIs
(when-not (= signature (storage/sign pid (storage/get-psk pid) (or noteID* noteID) note password)) (when-not (= signature (storage/sign pid (storage/get-psk pid) (or noteID* noteID)
"signature invalid") ; TODO: remove note* after June 2014
(when (blank? note) "note is empty") (or note* note) password))
(when-not (storage/valid-password? noteID password) "password invalid")])] "signature invalid")
(when (blank? note) "note is empty")
(when-not (storage/valid-password? noteID password) "password invalid")])]
(if (empty? errors) (if (empty? errors)
(do (do
(storage/edit-note noteID note) (storage/edit-note noteID note)

2
src/notehub/storage.clj

@ -9,7 +9,7 @@
(defn sign (defn sign
"Returns the MD5 hash for the concatenation of all passed parameters" "Returns the MD5 hash for the concatenation of all passed parameters"
[& args] [& args]
(let [input (sreplace (apply str args) #"[\r\n]" "")] (let [input (apply str args)]
(do (.reset md5Instance) (do (.reset md5Instance)
(.update md5Instance (.getBytes input)) (.update md5Instance (.getBytes input))
(apply str (apply str

10
test/notehub/test/api.clj

@ -69,7 +69,7 @@
(is (= "noteID 'randomString' unknown" (is (= "noteID 'randomString' unknown"
(get-in (get-in
(parse-string (parse-string
(:body (send-request "/api/note" {:version "1.3" :noteID "randomString"}))) (:body (send-request "/api/note" {:version "1.4" :noteID "randomString"})))
["status" "message"]))) ["status" "message"])))
(is (= "3" (get-in (get-note post-response) [:statistics :views]))))) (is (= "3" (get-in (get-note post-response) [:statistics :views])))))
(testing "creation with wrong signature" (testing "creation with wrong signature"
@ -119,7 +119,7 @@
{:note note {:note note
:pid pid :pid pid
:signature (storage/sign pid psk note) :signature (storage/sign pid psk note)
:version "1.0"}) :version "1.4"})
body (parse-string (:body response)) body (parse-string (:body response))
noteID (body "noteID")] noteID (body "noteID")]
(is (has-status response 200)) (is (has-status response 200))
@ -132,7 +132,7 @@
(:body (send-request [:get "/api/note"] {:version "1.1" (:body (send-request [:get "/api/note"] {:version "1.1"
:noteID (clojure.string/replace noteID #"/" " ")}))) "note"))) :noteID (clojure.string/replace noteID #"/" " ")}))) "note")))
(isnt (= note ((parse-string (isnt (= note ((parse-string
(:body (send-request [:get "/api/note"] {:version "1.3" (:body (send-request [:get "/api/note"] {:version "1.4"
:noteID (clojure.string/replace noteID #"/" " ")}))) "note"))) :noteID (clojure.string/replace noteID #"/" " ")}))) "note")))
(is (do (is (do
(storage/delete-note noteID) (storage/delete-note noteID)
@ -145,7 +145,7 @@
{:note note {:note note
:pid pid :pid pid
:signature (storage/sign pid psk note) :signature (storage/sign pid psk note)
:version "1.0" :version "1.4"
:theme "dark" :theme "dark"
:text-font "Helvetica"}) :text-font "Helvetica"})
body (parse-string (:body response)) body (parse-string (:body response))
@ -167,7 +167,7 @@
{:note note {:note note
:pid pid :pid pid
:signature (storage/sign pid psk note) :signature (storage/sign pid psk note)
:version "1.0" :version "1.4"
:password "qwerty"}) :password "qwerty"})
body (parse-string (:body response)) body (parse-string (:body response))
origID (body "noteID") origID (body "noteID")

Loading…
Cancel
Save