diff --git a/README.md b/README.md index b2342a0..40e4229 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Security is now greatly improved. There is a file called *passwd* in the *resour {:admin {:password "admin" :email "admin@localhost"} :adam {:password "secret" :email "adam@localhost"}} -that is to say, the username is a keyword and the corresponding password is a string. However, since version 0.5.0, users can now change their own passwords, and when the user changes their password their new password is encrypted using the [scrypt](http://www.tarsnap.com/scrypt.html) one-way encryption scheme. The password file is now no longer either in the *resources/public* directory so cannot be downloaded through the browser, and is no longer in the git archive to which the Wiki content is stored, so that even if that git archive is remotely clonable an attacker cannot get the password file that way. +that is to say, the username is a keyword and the corresponding password is a string. However, since version 0.5.0, users can now change their own passwords, and when the user changes their password their new password is encrypted using the [scrypt](http://www.tarsnap.com/scrypt.html) one-way encryption scheme. The password file is now no longer either in the *resources/public* directory so cannot be downloaded through the browser, nor in the git archive to which the Wiki content is stored, so that even if that git archive is remotely clonable an attacker cannot get the password file that way. There's still no mechanism to add a new user to the system through the user interface; you do sill have to do that by editing the password file in an editor. diff --git a/project.clj b/project.clj index 3095341..a3ee664 100644 --- a/project.clj +++ b/project.clj @@ -4,6 +4,7 @@ :dependencies [[org.clojure/clojure "1.6.0"] [org.clojure/core.memoize "0.5.6"] [lib-noir "0.9.4" :exclusions [org.clojure/tools.reader]] + [com.cemerick/url "0.1.1"] [ring-server "0.3.1"] [selmer "0.7.2"] [com.taoensso/timbre "3.3.1" :exclusions [org.clojure/tools.reader]] diff --git a/resources/public/content/Introduction.md b/resources/public/content/Introduction.md index b247b03..7a2ea63 100644 --- a/resources/public/content/Introduction.md +++ b/resources/public/content/Introduction.md @@ -20,7 +20,7 @@ Security is now greatly improved. There is a file called *passwd* in the *resour {:admin {:password "admin" :email "admin@localhost"} :adam {:password "secret" :email "adam@localhost"}} -that is to say, the username is a keyword and the corresponding password is a string. However, since version 0.5.0, users can now change their own passwords, and when the user changes their password their new password is encrypted using the [scrypt](http://www.tarsnap.com/scrypt.html) one-way encryption scheme. The password file is now no longer either in the *resources/public* directory so cannot be downloaded through the browser, and is no longer in the git archive to which the Wiki content is stored, so that even if that git archive is remotely clonable an attacker cannot get the password file that way. +that is to say, the username is a keyword and the corresponding password is a string. However, since version 0.5.0, users can now change their own passwords, and when the user changes their password their new password is encrypted using the [scrypt](http://www.tarsnap.com/scrypt.html) one-way encryption scheme. The password file is now no longer either in the *resources/public* directory so cannot be downloaded through the browser, nor in the git archive to which the Wiki content is stored, so that even if that git archive is remotely clonable an attacker cannot get the password file that way. There's still no mechanism to add a new user to the system through the user interface; you do sill have to do that by editing the password file in an editor. diff --git a/resources/public/content/_header.md b/resources/public/content/_header.md index b5d7dc2..d50260c 100644 --- a/resources/public/content/_header.md +++ b/resources/public/content/_header.md @@ -1 +1 @@ -This is the header. There isn't yet much in it. You could [edit](edit?content=_header) it to provide internal navigation or branding. +This is the header. There isn't yet much in it. You could [edit](edit?page=_header) it to provide internal navigation or branding. diff --git a/resources/public/content/_left-bar.md b/resources/public/content/_left-bar.md index 5586090..4eb8b93 100644 --- a/resources/public/content/_left-bar.md +++ b/resources/public/content/_left-bar.md @@ -1 +1 @@ -This is the left bar. There's nothing in it yet. You could [edit](edit?content=_left-bar) it to provide internal navigation or branding. +This is the left bar. There's nothing in it yet. You could [edit](edit?page=_left-bar) it to provide internal navigation or branding. diff --git a/resources/public/css/standard.css b/resources/public/css/standard.css index 0d23bf9..5a8b7ed 100644 --- a/resources/public/css/standard.css +++ b/resources/public/css/standard.css @@ -122,6 +122,7 @@ li.nav-item a:active { background: gray; color: white; } /* padding: 0.1em 10%; */ bottom:0; position:fixed; + vertical-align: top; z-index:150; _position:absolute; _top:expression(eval(document.documentElement.scrollTop+ diff --git a/resources/public/css/tablet.css b/resources/public/css/tablet.css index 9a61600..f1cb2c5 100644 --- a/resources/public/css/tablet.css +++ b/resources/public/css/tablet.css @@ -57,6 +57,7 @@ body { #nav-icon { padding: 0.25em; + float: left; } #nav-menu { diff --git a/resources/templates/base.html b/resources/templates/base.html index d40b940..ca4c3e7 100644 --- a/resources/templates/base.html +++ b/resources/templates/base.html @@ -3,7 +3,6 @@ {{title}} - {{title}} @@ -11,25 +10,25 @@ - - @@ -56,10 +55,10 @@ diff --git a/src/smeagol/history.clj b/src/smeagol/history.clj index e9250f6..d9aaf24 100644 --- a/src/smeagol/history.clj +++ b/src/smeagol/history.clj @@ -1,13 +1,14 @@ (ns smeagol.history - (:require [clj-jgit.porcelain :as git] + (:require [taoensso.timbre :as timbre] + [clj-jgit.porcelain :as git] [clj-jgit.internal :as i] [clj-jgit.querying :as q]) - (:import [org.eclipse.jgit.api Git] - [org.eclipse.jgit.lib Repository ObjectId] - [org.eclipse.jgit.revwalk RevCommit RevTree RevWalk] - [org.eclipse.jgit.treewalk TreeWalk AbstractTreeIterator CanonicalTreeParser] - [org.eclipse.jgit.treewalk.filter PathFilter] - [org.eclipse.jgit.diff DiffEntry DiffFormatter])) + (:import [org.eclipse.jgit.api Git] + [org.eclipse.jgit.lib Repository ObjectId] + [org.eclipse.jgit.revwalk RevCommit RevTree RevWalk] + [org.eclipse.jgit.treewalk TreeWalk AbstractTreeIterator CanonicalTreeParser] + [org.eclipse.jgit.treewalk.filter PathFilter] + [org.eclipse.jgit.diff DiffEntry DiffFormatter])) ;; Smeagol: a very simple Wiki engine ;; Copyright (C) 2014 Simon Brooke @@ -30,6 +31,7 @@ "If this `log-entry` contains a reference to this `file-path`, return the entry; else nil." [^String log-entry ^String file-path] + (timbre/info (format "searching '%s' for '%s'" log-entry file-path)) (cond (not (empty? @@ -60,19 +62,19 @@ reader (.newObjectReader (.getRepository repo))] (try (.reset result reader (.getId tree)) - (finally + (finally (.release reader) (.dispose walk))) result)) -(defn diff +(defn diff "Find the diff in the file at `file-path` within the repository at `git-directory-path` between versions `older` and `newer` or between the specified `version` and the current version of the file. Returns the diff as a string. Based on JGit Cookbook ShowFileDiff." ([^String git-directory-path ^String file-path ^String version] - (diff git-directory-path file-path version + (diff git-directory-path file-path version (:id (first (find-history git-directory-path file-path))))) ([^String git-directory-path ^String file-path ^String older ^String newer] (let [git-r (git/load-repo git-directory-path) @@ -86,8 +88,8 @@ %) (.call (.setOutputStream - (.setPathFilter - (.setNewTree + (.setPathFilter + (.setNewTree (.setOldTree (.diff git-r) old-parse) new-parse) (PathFilter/create file-path)) @@ -110,9 +112,8 @@ (.addTree tw tree) (.setRecursive tw true) (.setFilter tw (PathFilter/create file-path)) - (if (not (.next tw)) - (throw (IllegalStateException. + (if (not (.next tw)) + (throw (IllegalStateException. (str "Did not find expected file '" file-path "'")))) (.copyTo (.open repo (.getObjectId tw 0)) out) (.toString out))) - \ No newline at end of file diff --git a/src/smeagol/routes/wiki.clj b/src/smeagol/routes/wiki.clj index ce79660..3eb3026 100644 --- a/src/smeagol/routes/wiki.clj +++ b/src/smeagol/routes/wiki.clj @@ -19,7 +19,9 @@ (:use clojure.walk) (:require [compojure.core :refer :all] [clj-jgit.porcelain :as git] + [cemerick.url :refer (url url-encode url-decode)] [markdown.core :as md] + [clojure.java.io :as cjio] [noir.io :as io] [noir.response :as response] [noir.util.route :as route] @@ -35,8 +37,18 @@ "Rewrite text in `html-src` surrounded by double square brackets as a local link into this wiki." [html-src] (clojure.string/replace html-src #"\[\[[^\[\]]*\]\]" - #(let [text (clojure.string/replace %1 #"[\[\]]" "")] - (str "" text "")))) + #(let [text (clojure.string/replace %1 #"[\[\]]" "") + encoded (url-encode text)] + (timbre/debug (format "URL encode: '%s' -> '%s'" text encoded)) + (format "%s" encoded text)))) + +(defn get-git-repo + "Get the git repository for my content, creating it if necessary" + [] + (let [path (str (io/resource-path) "/content/") + repo (cjio/as-file (str path ".git"))] + (if (.exists repo) (git/load-repo repo) + (git/git-init path)))) (defn process-source "Process `source-text` and save it to the specified `file-path`, committing it @@ -47,15 +59,15 @@ file-name (str page ".md") file-path (str (io/resource-path) "/content/" file-name) exists? (.exists (clojure.java.io/as-file file-path)) - git-repo (git/load-repo (str (io/resource-path) "/content/.git")) + git-repo (get-git-repo) user (session/get :user) email (auth/get-email user) - summary (str user ": " (or (:summary params) "no summary"))] - (timbre/info (str "Saving " user "'s changes (" summary ") to " page)) + summary (format "%s: %s" user (or (:summary params) "no summary"))] + (timbre/info (format "Saving %s's changes ('%s') to %s" user summary page)) (spit file-path source-text) (if (not exists?) (git/git-add git-repo file-name)) (git/git-commit git-repo summary {:name user :email email}) - (response/redirect (str "/wiki?page=" page)) + (response/redirect (str "/wiki?page=" (url-encode page))) )) (defn edit-page @@ -66,7 +78,8 @@ src-text (:src params) page (or (:page params) "Introduction") file-path (str (io/resource-path) "content/" page ".md") - exists? (.exists (clojure.java.io/as-file file-path))] + exists? (.exists (cjio/as-file file-path))] + (if (not exists?) (timbre/info (format "File '%s' not found; creating a new file" file-path))) (cond src-text (process-source params) true (layout/render "edit.html" @@ -82,7 +95,7 @@ "Render the markdown page specified in this `request`, if any. If none found, redirect to edit-page" [request] (let [params (keywordize-keys (:params request)) - page (or (:content params) (:page params) "Introduction") + page (or (:page params) "Introduction") file-name (str "/content/" page ".md") file-path (str (io/resource-path) file-name) exists? (.exists (clojure.java.io/as-file file-path))] @@ -101,7 +114,7 @@ if any. If none, error?" [request] (let [params (keywordize-keys (:params request)) - page (or (:page params) "Introduction") + page (url-decode (or (:page params) "Introduction")) file-name (str page ".md") repo-path (str (io/resource-path) "/content/")] (layout/render "history.html" @@ -115,7 +128,7 @@ "Render a specific historical version of a page" [request] (let [params (keywordize-keys (:params request)) - page (or (:page params) "Introduction") + page (url-decode (or (:page params) "Introduction")) version (:version params) file-name (str page ".md") repo-path (str (io/resource-path) "/content/")] @@ -136,7 +149,7 @@ "Render a diff between two versions of a page" [request] (let [params (keywordize-keys (:params request)) - page (or (:page params) "Introduction") + page (url-decode (or (:page params) "Introduction")) version (:version params) file-name (str page ".md") repo-path (str (io/resource-path) "/content/")]