Skip to content
Snippets Groups Projects
Select Git revision
  • master protected
  • test default protected
  • feat/custom-css
  • feat/redesign-improvements-10
  • feat/redesign-improvements-8
  • feat/redesign-fixes-3
  • feat/pirstan-changes
  • feat/separate-import-thread
  • feat/dary-improvements
  • features/add-pdf-page
  • features/add-typed-table
  • features/fix-broken-calendar-categories
  • features/add-embed-to-articles
  • features/create-mastodon-feed-block
  • features/add-custom-numbering-for-candidates
  • features/add-timeline
  • features/create-wordcloud-from-article-page
  • features/create-collapsible-extra-legal-info
  • features/extend-hero-banner
  • features/add-link-to-images
20 results

forms.py

Blame
  • CSRF.hs NaN GiB
    {-|
    Module      :  Hikaru.CSRF
    Copyright   :  Jan Hamal Dvořák
    License     :  AGPL-3
    
    Maintainer  :  mordae@anilinux.org
    Stability   :  unstable
    Portability :  non-portable (ghc)
    
    This module provides CSRF mitigation utilities.
    -}
    
    module Hikaru.CSRF
      ( generateToken
      , isTokenValid
      )
    where
      import Relude
    
      import Crypto.Hash
      import Crypto.MAC.HMAC
      import Data.String.Conversions
      import Data.Text (splitOn)
      import Data.Time.Clock.POSIX (getPOSIXTime)
    
      import Hikaru.Action
    
    
      -- |
      -- Generate an anti-CSRF token to be used with forms.
      --
      -- Uses the @CSRF_SECRET@ configuration key.
      --
      generateToken :: (MonadAction m) => m Text
      generateToken = do
        now    <- getTimestamp
        secret <- getConfigDefault "CSRF_SECRET" ""
    
        let signature = sign now secret
         in return $ mconcat [ show now, ":", signature ]
    
    
      -- |
      -- Verify that the anti-CSRF token is currently valid.
      --
      -- Uses the @CSRF_SECRET@ and @CSRF_VALIDITY@ configuration keys.
      -- Valididy defaults to 86400 seconds (24 hours).
      --
      isTokenValid :: (MonadAction m) => Text -> m Bool
      isTokenValid token = do
        case splitOn ":" token of
          [time, signature] -> do
            case readMaybe (cs time) of
              Just (timestamp :: Int64) -> do
                now    <- getTimestamp
                valid  <- getConfigDefault "CSRF_VALIDITY" 86400
                secret <- getConfigDefault "CSRF_SECRET" ""
    
                if timestamp + valid >= now
                   then return (sign timestamp secret == signature)
                   else return False
    
              Nothing -> return False
    
          _else -> return False
    
    
      -- Internals --------------------------------------------------------------
    
    
      getTimestamp :: (MonadIO m) => m Int64
      getTimestamp = round <$> liftIO getPOSIXTime
    
    
      sign :: Int64 -> Text -> Text
      sign timestamp secret = show $ hmacGetDigest digest
        where
          digest      = hmac timeBytes secretBytes :: HMAC SHA256
          secretBytes = cs secret :: ByteString
          timeBytes   = show timestamp :: ByteString
    
    
    -- vim:set ft=haskell sw=2 ts=2 et: