about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Blog.hs25
-rw-r--r--src/Locales.hs6
-rw-r--r--src/Main.hs32
3 files changed, 49 insertions, 14 deletions
diff --git a/src/Blog.hs b/src/Blog.hs
index 631bfa013d34..2d3fe305bf85 100644
--- a/src/Blog.hs
+++ b/src/Blog.hs
@@ -9,12 +9,14 @@ import           Data.Monoid (mempty)
 import           Data.Text (Text)
 import qualified Data.Text as T
 import           Data.Time
+import           Network.Captcha.ReCaptcha
 import           System.Locale (defaultTimeLocale)
-import           Text.Blaze (toValue, preEscapedText)
+import           Text.Blaze (toValue, preEscapedText, preEscapedString)
 import           Text.Blaze.Html5 (Html, (!), a, form, input, p, toHtml, label)
 import           Text.Blaze.Html5.Attributes (action, enctype, href, name, size, type_, value)
 import qualified Text.Blaze.Html5 as H
 import qualified Text.Blaze.Html5.Attributes as A
+import           Text.XHtml.Strict (showHtmlFragment)
 
 import           Locales
 import           BlogDB
@@ -26,6 +28,21 @@ intersperse' sep l = sep : intersperse sep l
 replace :: Eq a => a -> a -> [a] -> [a]
 replace x y = map (\z -> if z == x then y else z)
 
+-- javascript and others
+
+captcha :: Html
+captcha = H.div ! A.class_ "cCaptcha" $
+          do H.script ! A.src "http://api.recaptcha.net/challenge?k=6LfQXccSAAAAAIjKm26XlFnBMAgvaKlOAjVWEEnM" ! A.type_ "text/javascript" $ ""
+             H.noscript $ H.iframe ! A.src "http://api.recaptcha.net/noscript?k=6LfQXccSAAAAAIjKm26XlFnBMAgvaKlOAjVWEEnM" ! A.height "300" !
+                               A.width "500" ! A.seamless "" $ do
+                                    H.br
+                                    H.textarea ! A.name "recaptcha_challenge_field" ! A.rows "3" ! A.cols "40" $ ""
+                                    H.input ! A.type_ "hidden" ! A.name "recaptcha_response_field" ! A.value "manual_challenge"
+
+captchaOptions :: BlogLang ->  Html
+captchaOptions lang = H.script ! A.type_ "text/javascript" $ toHtml $ 
+                        T.concat ["var RecaptchaOptions = { theme: 'clean', lang: '", showLangText lang, "'};"]
+
 analytics :: Text
 analytics = T.pack $ unlines ["<script type=\"text/javascript\">"
                              ,"  var _gaq = _gaq || [];"
@@ -38,12 +55,14 @@ analytics = T.pack $ unlines ["<script type=\"text/javascript\">"
                              ,"  })();"
                              ,"</script>"]
 
+-- blog HTML
+
 blogTemplate :: BlogLang -> Text -> Html -> Html
 blogTemplate lang t_append body = H.docTypeHtml $ do --add body
     H.head $ do
         H.title $ (toHtml $ blogTitle lang t_append)
         H.link ! A.rel "alternate" ! A.type_ "application/rss+xml" ! A.title "RSS-Feed" ! A.href (toValue feedURL)
-        H.link ! A.rel "stylesheet" ! A.type_ "text/css" ! A.href "/static/blogv312.css" ! A.media "all"
+        H.link ! A.rel "stylesheet" ! A.type_ "text/css" ! A.href "/static/blogv33.css" ! A.media "all"
         --H.link ! A.rel "stylesheet" ! A.type_ "text/css" ! A.href "/res/blogstyle.css" ! A.media "all"
         H.meta ! A.httpEquiv "content-type" ! A.content "text/html;charset=UTF-8"
         --H.style ! A.type_ "text/css" ! A.title "iOS iMessage" ! A.media "screen and (max-device-width: 1024px)" $ "#cosx{display:none;}"
@@ -116,10 +135,12 @@ renderEntry (Entry{..}) = do
 renderCommentBox :: BlogLang -> EntryId -> Html
 renderCommentBox cLang cId = do
     H.div ! A.class_ "cHead" $ toHtml $ cwHead cLang
+    captchaOptions cLang
     H.form ! A.method "POST" ! A.action (toValue $ "/" ++ (show cLang) ++  "/postcomment/" ++ show cId) $ do
         H.p $ H.input ! A.name "cname" ! A.placeholder "Name" ! A.class_ "cInput"
         H.p $ H.label $ H.textarea ! A.name "ctext" ! A.cols "50" ! A.rows "13" ! A.class_ "cInput" !
                         A.placeholder (toValue $ cTextPlaceholder cLang) $ mempty
+        H.p $ H.label $ captcha
         H.p $ H.input ! A.class_ "cInput" ! A.style "width: 120px;" ! A.type_ "submit" ! A.value (toValue $ cSend cLang)
 
 renderComments :: [Comment] -> BlogLang -> Html
diff --git a/src/Locales.hs b/src/Locales.hs
index 8041c4178b0f..b49434303658 100644
--- a/src/Locales.hs
+++ b/src/Locales.hs
@@ -16,7 +16,7 @@ import    BlogDB (BlogLang (..))
 
 data BlogError = NotFound | DBError
 
-version = "3.2"
+version = "3.3"
 
 allLang = [EN, DE]
 
@@ -28,6 +28,10 @@ blogTitle :: BlogLang -> Text -> Text
 blogTitle DE s = T.concat ["Tazjins Blog", s]
 blogTitle EN s = T.concat ["Tazjin's Blog", s]
 
+showLangText :: BlogLang -> Text
+showLangText EN = "en"
+showLangText DE = "de"
+
 -- index site headline
 topText DE = "Aktuelle Einträge"
 topText EN = "Latest entries"
diff --git a/src/Main.hs b/src/Main.hs
index 0ad5d979c288..203d0af0af85 100644
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -24,6 +24,7 @@ import           Data.Time
 import           Data.SafeCopy (base, deriveSafeCopy)
 import           Happstack.Server hiding (Session)
 import           Happstack.Server.Compression
+import           Network.Captcha.ReCaptcha
 import           Options
 import           System.Locale (defaultTimeLocale)
 
@@ -38,6 +39,8 @@ defineOptions "MainOptions" $ do
   stringOption "optState" "statedir" "../"
     "Directory in which the /BlogState dir is located.\
     \ The default is ../ (if run from src/)"
+  stringOption "optCaptcha" "captchakey" ""
+    "The reCaptcha private key"
   intOption "optPort" "port" 8000
     "The port to run the web server on. Default is 8000"
 
@@ -50,12 +53,12 @@ main = do
     runCommand $ \opts args ->
       bracket (openLocalStateFrom (optState opts ++ "BlogState") initialBlogState)
               (createCheckpointAndClose)
-              (\acid -> simpleHTTP nullConf {port = optPort opts} $ tazBlog acid)
+              (\acid -> simpleHTTP nullConf {port = optPort opts} $ tazBlog acid $ optCaptcha opts)
 
-tazBlog :: AcidState Blog -> ServerPart Response
-tazBlog acid = do
+tazBlog :: AcidState Blog -> String -> ServerPart Response
+tazBlog acid captchakey = do
     compr <- compressedResponseFilter
-    msum [ path $ \(lang :: BlogLang) -> blogHandler acid lang
+    msum [ path $ \(lang :: BlogLang) -> blogHandler acid lang captchakey
          , nullDir >> showIndex acid DE
          , dir " " $ nullDir >>
             seeOther ("https://plus.google.com/115916629925754851590" :: Text) (toResponse ())
@@ -87,12 +90,12 @@ tazBlog acid = do
          , notFound $ toResponse $ showError NotFound DE
          ]
 
-blogHandler :: AcidState Blog -> BlogLang -> ServerPart Response
-blogHandler acid lang = 
+blogHandler :: AcidState Blog -> BlogLang -> String -> ServerPart Response
+blogHandler acid lang captchakey = 
     msum [ path $ \(eId :: Integer) -> showEntry acid lang $ EntryId eId
          , do decodeBody tmpPolicy
               dir "postcomment" $ path $ 
-                \(eId :: Integer) -> addComment acid lang $ EntryId eId
+                \(eId :: Integer) -> addComment acid lang captchakey $ EntryId eId
          , nullDir >> showIndex acid lang
          , dir "rss" $ nullDir >> showRSS acid lang
          , dir "rss.xml" $ nullDir >> showRSS acid lang
@@ -134,15 +137,22 @@ showRSS acid lang = do
     setHeaderM "content-type" "text/xml"
     ok $ toResponse feed
 
-addComment :: AcidState Blog -> BlogLang -> EntryId -> ServerPart Response
-addComment acid lang eId = do
+addComment :: AcidState Blog -> BlogLang -> String -> EntryId -> ServerPart Response
+addComment acid lang captchakey eId = do
   now <- liftIO $ getCurrentTime >>= return
   nCtext <- lookText' "ctext"
   nComment <- Comment <$> pure now
                       <*> lookText' "cname"
                       <*> pure (commentEscape nCtext)
-  update' acid (AddComment eId nComment)
-  seeOther ("/" ++ show lang ++ "/" ++ show eId) (toResponse())
+  -- captcha verification
+  challenge <- look "recaptcha_challenge_field"
+  response <- look "recaptcha_response_field"
+  (userIp, _) <- askRq >>= return . rqPeer
+  validation <- liftIO $ validateCaptcha captchakey userIp challenge response
+  case validation of 
+    Right _ -> update' acid (AddComment eId nComment) 
+                >> seeOther ("/" ++ show lang ++ "/" ++ show eId) (toResponse())
+    Left _ -> (liftIO $ putStrLn "Captcha failed") >> seeOther ("/" ++ show lang ++ "/" ++ show eId) (toResponse())
 
 commentEscape :: Text -> Text
 commentEscape = newlineEscape . ltEscape . gtEscape . ampEscape