packages feed

yesod-recaptcha 0.1 → 0.1.1

raw patch · 2 files changed

+81/−43 lines, 2 files

Files

src/Yesod/ReCAPTCHA.hs view
@@ -48,9 +48,43 @@ -- The 'YA.YesodAuth' superclass is used only for the HTTP -- request.  Please fill a bug report if you think that this -- @YesodReCAPTCHA@ may be useful without @YesodAuth@.+--+-- /Minimum complete definition:/ 'recaptchaPublicKey' and+-- 'recaptchaPrivateKey'. class YA.YesodAuth master => YesodReCAPTCHA master where+    -- | Your reCAPTCHA public key.     recaptchaPublicKey  :: YC.GHandler sub master T.Text+    -- | Your reCAPTCHA private key.     recaptchaPrivateKey :: YC.GHandler sub master T.Text+    -- | A backdoor to the reCAPTCHA mechanism.  While doing+    -- automated tests you may need to fill a form that is+    -- protected by a CAPTCHA.  The whole point of using a+    -- CAPTCHA is disallowing access to non-humans, which+    -- hopefully your test suite is.+    --+    -- In order to solve this problem, you may define+    --+    -- > insecureRecaptchaBackdoor = return (Just "<secret CAPTCHA>")+    --+    -- Now, whenever someone fills @\<secret CAPTCHA\>@ as the+    -- CAPTCHA, the @yesod-recaptcha@ library will /not/ contact+    -- reCAPTCHA's servers and instead will blindly accept the+    -- secret CAPTCHA.+    --+    -- Note that this is a *huge* security hole in the wrong+    -- hands.  We /do not/ recommend using this function on a+    -- production environment without a good reason.  If for+    -- whatever reason you must use this function on a production+    -- environment, please make use of its access to 'GHandler'+    -- in order to return @Just@ only when strictly necessary.+    -- For example, you may return @Just@ only when the request+    -- comes from @localhost@ and read its contents from a secret+    -- file accessible only by SSH which is afterwards removed.+    --+    -- By default, this function returns @Nothing@, which+    -- completely disables the backdoor.+    insecureRecaptchaBackdoor :: YC.GHandler sub master (Maybe T.Text)+    insecureRecaptchaBackdoor = return Nothing   -- | A reCAPTCHA field.  This 'YF.AForm' returns @()@ because@@ -124,48 +158,52 @@ check "" _ = return $ Error "invalid-request-cookie" check _ "" = return $ Error "incorrect-captcha-sol" check challenge response = do-  manager    <- YA.authHttpManager <$> YC.getYesod-  privateKey <- recaptchaPrivateKey-  sockaddr   <- W.remoteHost <$> YC.waiRequest-  case sockaddr of-    HS.SockAddrUnix _ -> do-      $(YC.logError) $ "Yesod.ReCAPTCHA: Couldn't find out remote IP, \-                       \are you using a reverse proxy?  If yes, then \-                       \please file a bug report at \-                       \<https://github.com/meteficha/yesod-recaptcha>."-      fail "Could not find remote IP address for reCAPTCHA."-    _ -> do-      let remoteip = case sockaddr of-                       HS.SockAddrInet _ hostAddr ->-                         show $ NI.IPv4 hostAddr-                       HS.SockAddrInet6 _ _ (w1, w2, w3, w4) _ ->-                         show $ NI.IPv6 w1 w2 w3 w4-                       HS.SockAddrUnix _ -> error "ReCAPTCHA.check"-          req = H.def-                  { H.method      = HT.methodPost-                  , H.host        = "www.google.com"-                  , H.path        = "/recaptcha/api/verify"-                  , H.queryString = HT.renderSimpleQuery False query-                  }-          query = [ ("privatekey", TE.encodeUtf8 privateKey)-                  , ("remoteip",   B8.pack       remoteip)-                  , ("challenge",  TE.encodeUtf8 challenge)-                  , ("response",   TE.encodeUtf8 response)-                  ]-      eresp <- E.try $ C.runResourceT $ H.httpLbs req manager-      case (L8.lines . H.responseBody) <$> eresp of-        Right ("true":_)      -> return Ok-        Right ("false":why:_) -> return . Error . TL.toStrict $-                                 TLE.decodeUtf8With TEE.lenientDecode why-        Right other -> do-          $(YC.logError) $ T.concat [ "Yesod.ReCAPTCHA: could not parse "-                                    , T.pack (show other) ]-          return (Error "recaptcha-not-reachable")-        Left exc -> do-          $(YC.logError) $ T.concat [ "Yesod.ReCAPTCHA: could not contact server ("-                                    , T.pack (show (exc :: E.SomeException))-                                    , ")" ]-          return (Error "recaptcha-not-reachable")+  backdoor <- insecureRecaptchaBackdoor+  if Just response == backdoor+    then return Ok+    else do+      manager    <- YA.authHttpManager <$> YC.getYesod+      privateKey <- recaptchaPrivateKey+      sockaddr   <- W.remoteHost <$> YC.waiRequest+      case sockaddr of+        HS.SockAddrUnix _ -> do+          $(YC.logError) $ "Yesod.ReCAPTCHA: Couldn't find out remote IP, \+                           \are you using a reverse proxy?  If yes, then \+                           \please file a bug report at \+                           \<https://github.com/meteficha/yesod-recaptcha>."+          fail "Could not find remote IP address for reCAPTCHA."+        _ -> do+          let remoteip = case sockaddr of+                           HS.SockAddrInet _ hostAddr ->+                             show $ NI.IPv4 hostAddr+                           HS.SockAddrInet6 _ _ (w1, w2, w3, w4) _ ->+                             show $ NI.IPv6 w1 w2 w3 w4+                           HS.SockAddrUnix _ -> error "ReCAPTCHA.check"+              req = H.def+                      { H.method      = HT.methodPost+                      , H.host        = "www.google.com"+                      , H.path        = "/recaptcha/api/verify"+                      , H.queryString = HT.renderSimpleQuery False query+                      }+              query = [ ("privatekey", TE.encodeUtf8 privateKey)+                      , ("remoteip",   B8.pack       remoteip)+                      , ("challenge",  TE.encodeUtf8 challenge)+                      , ("response",   TE.encodeUtf8 response)+                      ]+          eresp <- E.try $ C.runResourceT $ H.httpLbs req manager+          case (L8.lines . H.responseBody) <$> eresp of+            Right ("true":_)      -> return Ok+            Right ("false":why:_) -> return . Error . TL.toStrict $+                                     TLE.decodeUtf8With TEE.lenientDecode why+            Right other -> do+              $(YC.logError) $ T.concat [ "Yesod.ReCAPTCHA: could not parse "+                                        , T.pack (show other) ]+              return (Error "recaptcha-not-reachable")+            Left exc -> do+              $(YC.logError) $ T.concat [ "Yesod.ReCAPTCHA: could not contact server ("+                                        , T.pack (show (exc :: E.SomeException))+                                        , ")" ]+              return (Error "recaptcha-not-reachable")   -- | See 'check'.
yesod-recaptcha.cabal view
@@ -1,5 +1,5 @@ Name:                yesod-recaptcha-Version:             0.1+Version:             0.1.1 Synopsis:            Dead simple support for reCAPTCHA on Yesod applications. Homepage:            https://github.com/meteficha/yesod-recaptcha License:             BSD3