mirror of
https://github.com/journeyman-cc/smeagol.git
synced 2026-04-12 18:05:06 +00:00
Added very basic and not-very-secure authentication. Smeagol is now usable.
This commit is contained in:
parent
d437f07fc2
commit
fc89b25a2f
12 changed files with 140 additions and 32 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,3 +1,4 @@
|
||||||
|
smeagol.log
|
||||||
pom.xml
|
pom.xml
|
||||||
pom.xml.asc
|
pom.xml.asc
|
||||||
*jar
|
*jar
|
||||||
|
|
|
||||||
26
README.md
26
README.md
|
|
@ -1,6 +1,28 @@
|
||||||
# Welcome to Smeagol
|
Welcome to Smeagol!
|
||||||
|
|
||||||
Smeagol is a simple Git-backed Wiki inspired by [Gollum](https://github.com/gollum/gollum/wiki).
|
Smeagol is a simple Wiki engine inspired by [Gollum](https://github.com/gollum/gollum/wiki). Gollum is a Wiki engine written in Ruby, which uses a number of simple text formats including [Markdown](http://daringfireball.net/projects/markdown/), which uses [Git](http://git-scm.com/) to provide versioning and backup. I needed a new Wiki for a project and thought Gollum would be ideal - but unfortunately it doesn't provide user authentication, which I needed, and it was simpler for me to reimplement the bits I did need in Clojure than to modify Gollum.
|
||||||
|
|
||||||
|
So at this stage Smeagol is a Wiki engine written in Clojure which uses Markdown as its text format, which does have user authentication, and which will soon use Git as its versioning and backup system.
|
||||||
|
|
||||||
|
## Markup syntax
|
||||||
|
|
||||||
|
Smeagol uses the Markdown format as provided by [markdown-clj](https://github.com/yogthos/markdown-clj), with the addition that anything enclosed in double square brackets, \[\[like this\]\], will be treated as a link into the wiki.
|
||||||
|
|
||||||
|
## Security and authentication
|
||||||
|
|
||||||
|
Currently security is very weak. There is currently a file called *passwd* in the *resources/public* directory, which contains a clojure map of username/plain-text password pairs thus:
|
||||||
|
|
||||||
|
{:admin "admin"}
|
||||||
|
|
||||||
|
that is to say, the username is a keyword and the corresponding password is a string. Obviously, this is a temporary solution while in development which I will fix later.
|
||||||
|
|
||||||
|
## Todo
|
||||||
|
|
||||||
|
* Git integration! Smeagol doesn't have any inbuilt versioning or backup mechanism; it's intended that Git will be used as that mechanism. But it isn't implemented yet.
|
||||||
|
* Image (and other media) upload.
|
||||||
|
* Improved security.
|
||||||
|
* Mechanism to add users through the user interface.
|
||||||
|
* Mechanism to change passwords through the user interface.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,19 @@ Smeagol uses the Markdown format as provided by [markdown-clj](https://github.co
|
||||||
|
|
||||||
## Security and authentication
|
## Security and authentication
|
||||||
|
|
||||||
Not done yet.
|
Currently security is very weak. There is currently a file called *passwd* in the *resources/public* directory, which contains a clojure map of username/plain-text password pairs thus:
|
||||||
|
|
||||||
|
{:admin "admin"}
|
||||||
|
|
||||||
|
that is to say, the username is a keyword and the corresponding password is a string. Obviously, this is a temporary solution while in development which I will fix later.
|
||||||
|
|
||||||
## Todo
|
## Todo
|
||||||
|
|
||||||
Git integration!
|
* Git integration! Smeagol doesn't have any inbuilt versioning or backup mechanism; it's intended that Git will be used as that mechanism. But it isn't implemented yet.
|
||||||
|
* Image (and other media) upload.
|
||||||
|
* Improved security.
|
||||||
|
* Mechanism to add users through the user interface.
|
||||||
|
* Mechanism to change passwords through the user interface.
|
||||||
|
|
||||||
## Editing the framing content
|
## Editing the framing content
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,13 @@ body {
|
||||||
background:rgba(40,40,40,0.8);
|
background:rgba(40,40,40,0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#user {
|
||||||
|
font-height: 66%;
|
||||||
|
float: right;
|
||||||
|
padding: 0.1em 0.75em;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* only needed for fly-out menu effect on tablet and phone stylesheets */
|
/* only needed for fly-out menu effect on tablet and phone stylesheets */
|
||||||
#nav-icon {
|
#nav-icon {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
@ -120,10 +127,15 @@ input {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
input.submit {
|
input.action {
|
||||||
background-color: green;
|
background-color: green;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input.action-dangerous {
|
||||||
|
color: white;
|
||||||
|
background-color: red;
|
||||||
|
}
|
||||||
|
|
||||||
input.required:after {
|
input.required:after {
|
||||||
content: " \*";
|
content: " \*";
|
||||||
color: red;
|
color: red;
|
||||||
|
|
|
||||||
1
resources/public/passwd
Normal file
1
resources/public/passwd
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
{:admin "admin"}
|
||||||
33
resources/templates/auth.html
Normal file
33
resources/templates/auth.html
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
{% extends "templates/base.html" %}
|
||||||
|
{% block content %}
|
||||||
|
<div id="header" class="wiki">
|
||||||
|
<h1>{{title}}</h1>
|
||||||
|
{{header|safe}}
|
||||||
|
</div>
|
||||||
|
<div id="left-bar" class="wiki">
|
||||||
|
{{left-bar|safe}}
|
||||||
|
</div>
|
||||||
|
<div id="content" class="wiki">
|
||||||
|
<form action="{{servlet-context}}/auth" method="POST">
|
||||||
|
{% if user %}
|
||||||
|
<p class="widget">
|
||||||
|
<label for="submit">To finish editing</label>
|
||||||
|
<input name="action" id="action" type="submit" class="action-dangerous" value="Logout!"/>
|
||||||
|
</p>
|
||||||
|
{% else %}
|
||||||
|
<p class="widget">
|
||||||
|
<label for="username">Your username</label>
|
||||||
|
<input name="username" id="username" type="text"/>
|
||||||
|
</p>
|
||||||
|
<p class="widget">
|
||||||
|
<label for="password">Your password</label>
|
||||||
|
<input name="password" id="password" type="password"/>
|
||||||
|
</p>
|
||||||
|
<p class="widget">
|
||||||
|
<label for="submit">To edit this wiki</label>
|
||||||
|
<input name="action" id="action" type="submit" class="action" value="Login!"/>
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
@ -13,10 +13,19 @@
|
||||||
<body>
|
<body>
|
||||||
<!-- navbar -->
|
<!-- navbar -->
|
||||||
<div id="nav">
|
<div id="nav">
|
||||||
|
{% if user %}
|
||||||
|
<p class="user" id="user">You are logged in as {{user}}</p>
|
||||||
|
{% endif %}
|
||||||
<img id="nav-icon" src="{{servlet-context}}/img/threelines.png" alt="Menu"/>
|
<img id="nav-icon" src="{{servlet-context}}/img/threelines.png" alt="Menu"/>
|
||||||
<ul id="nav-menu" class="nav">
|
<ul id="nav-menu" class="nav">
|
||||||
<li class="{{home-selected}}"><a href="{{servlet-context}}/">Home</a></li>
|
<li class="{{wiki-selected}}"><a href="{{servlet-context}}/">Home</a></li>
|
||||||
<li class="{{edit-selected}}"><a href="{{servlet-context}}/edit?content={{title}}">Edit this page</a></li>
|
<li class="{{edit-selected}}"><a href="{{servlet-context}}/edit?content={{title}}">Edit this page</a></li>
|
||||||
|
<li class="{{auth-selected}}"><a href="{{servlet-context}}/auth">
|
||||||
|
{% if user %}
|
||||||
|
Log out
|
||||||
|
{% else %}
|
||||||
|
Log in
|
||||||
|
{% endif %}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
<textarea name="src" id="src" rows="25" cols="80">{{content}}</textarea>
|
<textarea name="src" id="src" rows="25" cols="80">{{content}}</textarea>
|
||||||
<p class="widget">
|
<p class="widget">
|
||||||
<label for="submit">When you have finished editing</label>
|
<label for="submit">When you have finished editing</label>
|
||||||
<input name="submit" id="submit" type="submit" value="Save!"/>
|
<input name="submit" id="submit" type="submit" class="action" value="Save!"/>
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
20
smeagol.log
20
smeagol.log
|
|
@ -1,20 +0,0 @@
|
||||||
2014-Nov-09 20:07:44 +0000 fletcher INFO [smeagol.handler] -
|
|
||||||
-=[ smeagol started successfully using the development profile ]=-
|
|
||||||
2014-Nov-09 20:32:47 +0000 fletcher INFO [smeagol.handler] - smeagol is shutting down...
|
|
||||||
2014-Nov-09 20:32:47 +0000 fletcher INFO [smeagol.handler] - shutdown complete!
|
|
||||||
2014-Nov-09 20:33:00 +0000 fletcher INFO [smeagol.handler] -
|
|
||||||
-=[ smeagol started successfully using the development profile ]=-
|
|
||||||
2014-Nov-09 20:35:05 +0000 fletcher INFO [smeagol.handler] - smeagol is shutting down...
|
|
||||||
2014-Nov-09 20:35:05 +0000 fletcher INFO [smeagol.handler] - shutdown complete!
|
|
||||||
2014-Nov-09 20:35:19 +0000 fletcher INFO [smeagol.handler] -
|
|
||||||
-=[ smeagol started successfully using the development profile ]=-
|
|
||||||
2014-Nov-09 21:07:26 +0000 fletcher INFO [smeagol.handler] - smeagol is shutting down...
|
|
||||||
2014-Nov-09 21:07:26 +0000 fletcher INFO [smeagol.handler] - shutdown complete!
|
|
||||||
2014-Nov-09 21:07:40 +0000 fletcher INFO [smeagol.handler] -
|
|
||||||
-=[ smeagol started successfully using the development profile ]=-
|
|
||||||
2014-Nov-09 21:10:52 +0000 fletcher INFO [smeagol.handler] - smeagol is shutting down...
|
|
||||||
2014-Nov-09 21:10:52 +0000 fletcher INFO [smeagol.handler] - shutdown complete!
|
|
||||||
2014-Nov-10 07:24:44 +0000 fletcher INFO [smeagol.handler] -
|
|
||||||
-=[ smeagol started successfully using the development profile ]=-
|
|
||||||
2014-Nov-10 13:15:36 +0000 fletcher INFO [smeagol.handler] - smeagol is shutting down...
|
|
||||||
2014-Nov-10 13:15:37 +0000 fletcher INFO [smeagol.handler] - shutdown complete!
|
|
||||||
10
src/smeagol/authenticate.clj
Normal file
10
src/smeagol/authenticate.clj
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
(ns smeagol.authenticate (:require [noir.io :as io]))
|
||||||
|
|
||||||
|
(defn authenticate
|
||||||
|
"Return true if this username/password pair match, false otherwise"
|
||||||
|
[username password]
|
||||||
|
(let [path (str (io/resource-path) "passwd")
|
||||||
|
users (read-string (slurp path))
|
||||||
|
user (keyword username)]
|
||||||
|
(println (str "Checking for user " user " with password " password " in " users " from " path))
|
||||||
|
(.equals (user users) password)))
|
||||||
|
|
@ -73,7 +73,7 @@
|
||||||
:middleware (load-middleware)
|
:middleware (load-middleware)
|
||||||
:ring-defaults (mk-defaults false)
|
:ring-defaults (mk-defaults false)
|
||||||
;; add access rules here
|
;; add access rules here
|
||||||
:access-rules [{:redirect "/login"
|
:access-rules [{:redirect "auth"
|
||||||
:rule user-access}]
|
:rule user-access}]
|
||||||
;; serialize/deserialize the following data formats
|
;; serialize/deserialize the following data formats
|
||||||
;; available formats:
|
;; available formats:
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,9 @@
|
||||||
(:require [compojure.core :refer :all]
|
(:require [compojure.core :refer :all]
|
||||||
[noir.io :as io]
|
[noir.io :as io]
|
||||||
[noir.response :as response]
|
[noir.response :as response]
|
||||||
|
[noir.util.route :as route]
|
||||||
|
[noir.session :as session]
|
||||||
|
[smeagol.authenticate :as auth]
|
||||||
[smeagol.layout :as layout]
|
[smeagol.layout :as layout]
|
||||||
[smeagol.util :as util]))
|
[smeagol.util :as util]))
|
||||||
|
|
||||||
|
|
@ -31,9 +34,11 @@
|
||||||
{:title content
|
{:title content
|
||||||
:left-bar (util/md->html "/content/_edit-left-bar.md")
|
:left-bar (util/md->html "/content/_edit-left-bar.md")
|
||||||
:header (util/md->html "/content/_header.md")
|
:header (util/md->html "/content/_header.md")
|
||||||
:content (if exists? (io/slurp-resource file-name) "")}))))
|
:content (if exists? (io/slurp-resource file-name) "")
|
||||||
|
:user (session/get :user)}))))
|
||||||
|
|
||||||
(defn local-links
|
(defn local-links
|
||||||
|
"Rewrite text in `html-src` surrounded by double square brackets as a local link into this wiki."
|
||||||
[html-src]
|
[html-src]
|
||||||
(clojure.string/replace html-src #"\[\[[^\[\]]*\]\]"
|
(clojure.string/replace html-src #"\[\[[^\[\]]*\]\]"
|
||||||
#(let [text (clojure.string/replace %1 #"[\[\]]" "")]
|
#(let [text (clojure.string/replace %1 #"[\[\]]" "")]
|
||||||
|
|
@ -52,9 +57,34 @@
|
||||||
{:title content
|
{:title content
|
||||||
:left-bar (util/md->html "/content/_left-bar.md")
|
:left-bar (util/md->html "/content/_left-bar.md")
|
||||||
:header (util/md->html "/content/_header.md")
|
:header (util/md->html "/content/_header.md")
|
||||||
:content (local-links (util/md->html file-name))})
|
:content (local-links (util/md->html file-name))
|
||||||
|
:user (session/get :user)})
|
||||||
true (response/redirect (str "edit?content=" content)))))
|
true (response/redirect (str "edit?content=" content)))))
|
||||||
|
|
||||||
|
(defn auth-page
|
||||||
|
"Render the auth page"
|
||||||
|
[request]
|
||||||
|
(let [params (keywordize-keys (:params request))
|
||||||
|
username (:username params)
|
||||||
|
password (:password params)
|
||||||
|
action (:action params)
|
||||||
|
user (session/get :user)]
|
||||||
|
(println (str "Action = " action))
|
||||||
|
(cond
|
||||||
|
(= action "Logout!")
|
||||||
|
(do
|
||||||
|
(session/remove! :user)
|
||||||
|
(response/redirect "wiki"))
|
||||||
|
(and username password (auth/authenticate username password))
|
||||||
|
(do
|
||||||
|
(session/put! :user username)
|
||||||
|
(response/redirect "wiki"))
|
||||||
|
true
|
||||||
|
(layout/render "auth.html"
|
||||||
|
{:title (if user (str "Logout " user) "Log in")
|
||||||
|
:left-bar (util/md->html "/content/_left-bar.md")
|
||||||
|
:header (util/md->html "/content/_header.md")
|
||||||
|
:user user}))))
|
||||||
|
|
||||||
(defn about-page []
|
(defn about-page []
|
||||||
(layout/render "about.html"))
|
(layout/render "about.html"))
|
||||||
|
|
@ -62,6 +92,8 @@
|
||||||
(defroutes wiki-routes
|
(defroutes wiki-routes
|
||||||
(GET "/wiki" request (wiki-page request))
|
(GET "/wiki" request (wiki-page request))
|
||||||
(GET "/" request (wiki-page request))
|
(GET "/" request (wiki-page request))
|
||||||
(GET "/edit" request (edit-page request))
|
(GET "/edit" request (route/restricted (edit-page request)))
|
||||||
(POST "/edit" request (edit-page request))
|
(POST "/edit" request (route/restricted (edit-page request)))
|
||||||
|
(GET "/auth" request (auth-page request))
|
||||||
|
(POST "/auth" request (auth-page request))
|
||||||
(GET "/about" [] (about-page)))
|
(GET "/about" [] (about-page)))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue