yesod-csp 0.2.1.0 → 0.2.2.0
raw patch · 5 files changed
+46/−42 lines, 5 filesdep −uniplatePVP ok
version bump matches the API change (PVP)
Dependencies removed: uniplate
API changes (from Hackage documentation)
+ Yesod.Csp: FrameAncestors :: SourceList -> Directive
Files
- src/Yesod/Csp.hs +2/−0
- src/Yesod/Csp/Example.hs +15/−14
- src/Yesod/Csp/TH.hs +2/−0
- test/Test.hs +26/−26
- yesod-csp.cabal +1/−2
src/Yesod/Csp.hs view
@@ -130,6 +130,7 @@ | ObjectSrc SourceList | MediaSrc SourceList | FrameSrc SourceList+ | FrameAncestors SourceList -- | Applies a sandbox to the result. <http://content-security-policy.com/ See here> for more info. | Sandbox [SandboxOptions] | ReportUri EscapedURI deriving (Eq, Show, Data, Typeable)@@ -150,6 +151,7 @@ textDirective (ObjectSrc x) = w "object-src" x textDirective (MediaSrc x) = w "media-src" x textDirective (FrameSrc x) = w "frame-src" x+textDirective (FrameAncestors x) = w "frame-ancestors" x textDirective (ReportUri t) = mconcat ["report-uri ", (pack . show) t] textDirective (Sandbox []) = "sandbox" textDirective (Sandbox s) = mconcat ["sandbox ", T.unwords . fmap textSandbox $ s]
src/Yesod/Csp/Example.hs view
@@ -5,7 +5,6 @@ -- | Assorted examples demonstrating different policies. module Yesod.Csp.Example where -import Data.Generics.Uniplate.Data import Data.List.NonEmpty import Data.Maybe import Yesod hiding (get)@@ -103,25 +102,17 @@ cdn :: Source cdn = Host (fromJust $ escapeAndParseURI "https://cdn.com") + getExample8R :: Handler Html getExample8R = do- let policy = [csp|script-src 'self'|]- cspPolicy $ addCdn <$> policy- defaultLayout [whamlet|wooo|]- where addCdn = transform f- f (ScriptSrc x) = ScriptSrc $ cdn <| x- f x = x--getExample9R :: Handler Html-getExample9R = do cspPolicy [csp|script-src 'nonce-foo'|] defaultLayout $ [whamlet| <script nonce="foo"> alert("ayyyy"); |] -getExample10R :: Handler Html-getExample10R = do+getExample9R :: Handler Html+getExample9R = do let n = "foo" cspPolicy [csp|script-src $nonce-n|] defaultLayout $ [whamlet|@@ -129,14 +120,24 @@ alert("ayyyy"); |] -getExample11R :: Handler Html-getExample11R = do+getExample10R :: Handler Html+getExample10R = do let n = "bar" cspPolicy [csp|script-src $nonce-n|] defaultLayout $ [whamlet| <script nonce="foo"> alert("ayyyy"); |]++getExample11R :: Handler Html+getExample11R = do+ let google = fromJust (escapeAndParseURI "https://google.ie")+ cspPolicy [FrameAncestors (Host google :| [])]+ defaultLayout $+ [whamlet|+ I should only be iframe-able by Google!+ |]+ -- | Run a webserver to serve these examples at /1, /2, etc. runExamples :: IO ()
src/Yesod/Csp/TH.hs view
@@ -103,6 +103,7 @@ <|> objectSrc <|> mediaSrc <|> frameSrc+ <|> frameAncestors where defaultSrc = d "default-src" DefaultSrc scriptSrc = d "script-src" ScriptSrc styleSrc = d "style-src" StyleSrc@@ -112,6 +113,7 @@ objectSrc = d "object-src" ObjectSrc mediaSrc = d "media-src" MediaSrc frameSrc = d "frame-src" FrameSrc+ frameAncestors = d "frame-ancestors" FrameAncestors d x y = string x >> s >> slist >>= mkWithSource y slist = sepBy1 source (char ' ') s = spaces
test/Test.hs view
@@ -28,24 +28,24 @@ ydescribe "Generation" $ do yit "works" $ do let header = getCspPolicy [ScriptSrc (Self :| []), StyleSrc (Https :| [Self])]- assertEqual "simple header" header "script-src 'self'; style-src https: 'self'"+ assertEq "simple header" header "script-src 'self'; style-src https: 'self'" yit "works with domains" $ do let dom = fromJust $ escapeAndParseURI "https://foo.com/bar *" header = getCspPolicy [ScriptSrc (Host dom :| [])]- assertEqual "foo.com script-src" header "script-src https://foo.com/bar%20%2A"+ assertEq "foo.com script-src" header "script-src https://foo.com/bar%20%2A" yit "works with nonce-source" $ do let header = getCspPolicy [ScriptSrc (nonce "foo" :| [])]- assertEqual "basic nonce-source" header "script-src 'nonce-foo'"+ assertEq "basic nonce-source" header "script-src 'nonce-foo'" yit "works with report_uri" $ do let dom = fromJust $ escapeAndParseURI "https://foo.com" header = getCspPolicy [ReportUri dom]- assertEqual "report-uri" header "report-uri https://foo.com"+ assertEq "report-uri" header "report-uri https://foo.com" yit "enforces wildcards" $ do let header = getCspPolicy [ScriptSrc (Wildcard :| [Https])]- assertEqual "* should be alone" header "script-src *"+ assertEq "* should be alone" header "script-src *" yit "enforces nones" $ do let header = getCspPolicy [ScriptSrc (None :| [Https])]- assertEqual "none should be alone" header "script-src 'none'"+ assertEq "none should be alone" header "script-src 'none'" ydescribe "Headers" $ yit "get set" $ do get HomeR@@ -53,38 +53,38 @@ ydescribe "Sandboxes" $ do yit "works when empty" $ do let header = getCspPolicy [Sandbox []]- assertEqual "empty sandbox" header "sandbox"+ assertEq "empty sandbox" header "sandbox" yit "works when not empty" $ do let header = getCspPolicy [Sandbox [AllowForms, AllowScripts]]- assertEqual "empty sandbox" header "sandbox allow-forms allow-scripts"+ assertEq "empty sandbox" header "sandbox allow-forms allow-scripts" ydescribe "Parsing" $ do yit "works" $ do- assertEqual "*" (parseOnly source "*") (Right Wildcard)- assertEqual "nonce" (parseOnly source "'nonce-foo'") (Right $ nonce "foo")- assertEqual "none" (parseOnly source "'none'") (Right None)- assertEqual "self" (parseOnly source "'self'") (Right Self)- assertEqual "data:" (parseOnly source "data:") (Right DataScheme)- assertEqual "https://foo.com" (parseOnly source "https://foo.com") (Right $ Host (fromJust (escapeAndParseURI "https://foo.com")))- assertEqual "https:" (parseOnly source "https:") (Right Https)- assertEqual "unsafe-inline" (parseOnly source "unsafe-inline") (Right UnsafeInline)- assertEqual "unsafe-eval" (parseOnly source "unsafe-eval") (Right UnsafeEval)- assertEqual "default-src self data:" (parseOnly withSourceList "default-src 'self' data:") (Right $ DefaultSrc (Self :| [DataScheme]))- assertEqual "report-uri http://hello.com" (parseOnly reportUri "report-uri http://hello.com") (Right $ ReportUri (fromJust (escapeAndParseURI "http://hello.com")))- assertEqual "sandbox allow-forms allow-scripts" (parseOnly sandbox "sandbox allow-forms allow-scripts") (Right $ Sandbox [AllowForms, AllowScripts])+ assertEq "*" (parseOnly source "*") (Right Wildcard)+ assertEq "nonce" (parseOnly source "'nonce-foo'") (Right $ nonce "foo")+ assertEq "none" (parseOnly source "'none'") (Right None)+ assertEq "self" (parseOnly source "'self'") (Right Self)+ assertEq "data:" (parseOnly source "data:") (Right DataScheme)+ assertEq "https://foo.com" (parseOnly source "https://foo.com") (Right $ Host (fromJust (escapeAndParseURI "https://foo.com")))+ assertEq "https:" (parseOnly source "https:") (Right Https)+ assertEq "unsafe-inline" (parseOnly source "unsafe-inline") (Right UnsafeInline)+ assertEq "unsafe-eval" (parseOnly source "unsafe-eval") (Right UnsafeEval)+ assertEq "default-src self data:" (parseOnly withSourceList "default-src 'self' data:") (Right $ DefaultSrc (Self :| [DataScheme]))+ assertEq "report-uri http://hello.com" (parseOnly reportUri "report-uri http://hello.com") (Right $ ReportUri (fromJust (escapeAndParseURI "http://hello.com")))+ assertEq "sandbox allow-forms allow-scripts" (parseOnly sandbox "sandbox allow-forms allow-scripts") (Right $ Sandbox [AllowForms, AllowScripts]) yit "works with lists" $ do let result = [ImgSrc $ Self :| [Https], ScriptSrc $ Host (fromJust $ escapeAndParseURI "https://foo.com") :| []]- assertEqual "scripts and images" (parseOnly directive "img-src 'self' https:; script-src https://foo.com") (Right result)+ assertEq "scripts and images" (parseOnly directive "img-src 'self' https:; script-src https://foo.com") (Right result) let result = [ImgSrc $ Self :| [DataScheme, Host (fromJust $ escapeAndParseURI "https://foo.com")]]- assertEqual "data and hosts" (parseOnly directive "img-src 'self' data: https://foo.com") (Right result)+ assertEq "data and hosts" (parseOnly directive "img-src 'self' data: https://foo.com") (Right result) yit "works with nonces and th" $ do let result = [ScriptSrc $ (nonce "foo") :| []]- assertEqual "nonces and th" [csp|script-src 'nonce-foo'|] result+ assertEq "nonces and th" [csp|script-src 'nonce-foo'|] result yit "works with dynamic nonces and th" $ do let n = "bar" result = [ScriptSrc $ (nonce "bar") :| []]- assertEqual "dynamic nonces and th" [csp|script-src $nonce-n|] result+ assertEq "dynamic nonces and th" [csp|script-src $nonce-n|] result yit "works with th" $ do let result = [ImgSrc $ Self :| [Https], ScriptSrc $ Host (fromJust $ escapeAndParseURI "https://foo.com") :| []]- assertEqual "with th" [csp|img-src 'self' https:; script-src https://foo.com|] result+ assertEq "with th" [csp|img-src 'self' https:; script-src https://foo.com|] result let url = fromJust $ escapeAndParseURI "https://foo.com"- assertEqual "with antiquoting" [csp|img-src 'self' https:; script-src $url|] result+ assertEq "with antiquoting" [csp|img-src 'self' https:; script-src $url|] result
yesod-csp.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: yesod-csp-version: 0.2.1.0+version: 0.2.2.0 synopsis: Add CSP headers to Yesod apps description: Add CSP headers to Yesod apps. This helps reduce exposure to XSS attacks and bad assets. license: MIT@@ -31,7 +31,6 @@ , mono-traversable , attoparsec , template-haskell- , uniplate , syb hs-source-dirs: src default-language: Haskell2010