{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE CPP #-}
module Servant.Auth.Swagger
  (
  -- | The purpose of this package is provide the instance for 'servant-auth'
  -- combinators needed for 'servant-swagger' documentation generation.
  --
  -- Currently only JWT and BasicAuth are supported.

  -- * Re-export
    JWT
  , BasicAuth
  , Auth

  -- * Needed to define instances of @HasSwagger@
  , HasSecurity (..)
  ) where

import Control.Lens    ((&), (<>~))
import Data.Proxy      (Proxy (Proxy))
import Data.Swagger    (ApiKeyLocation (..), ApiKeyParams (..),
                        SecurityRequirement (..), SecurityScheme (..), 
#if MIN_VERSION_swagger2(2,6,0)
                        SecurityDefinitions(..),
#endif
                        SecuritySchemeType (..), allOperations, security,
                        securityDefinitions)
import GHC.Exts        (fromList)
import Servant.API     hiding (BasicAuth)
import Servant.Auth
import Servant.Swagger

import qualified Data.Text as T

instance (AllHasSecurity xs, HasSwagger api) => HasSwagger (Auth xs r :> api) where
  toSwagger :: Proxy (Auth xs r :> api) -> Swagger
toSwagger Proxy (Auth xs r :> api)
_
    = forall {k} (api :: k). HasSwagger api => Proxy api -> Swagger
toSwagger (forall {k} (t :: k). Proxy t
Proxy :: Proxy api)
        forall a b. a -> (a -> b) -> b
& forall s a. HasSecurityDefinitions s a => Lens' s a
securityDefinitions forall a s t. Semigroup a => ASetter s t a a -> a -> s -> t
<>~ Definitions SecurityScheme -> SecurityDefinitions
mkSec (forall l. IsList l => [Item l] -> l
fromList [(Text, SecurityScheme)]
secs)
        forall a b. a -> (a -> b) -> b
& Traversal' Swagger Operation
allOperationsforall b c a. (b -> c) -> (a -> b) -> a -> c
.forall s a. HasSecurity s a => Lens' s a
security forall a s t. Semigroup a => ASetter s t a a -> a -> s -> t
<>~ [SecurityRequirement]
secReqs
    where
      secs :: [(Text, SecurityScheme)]
secs = forall (x :: [*]).
AllHasSecurity x =>
Proxy x -> [(Text, SecurityScheme)]
securities (forall {k} (t :: k). Proxy t
Proxy :: Proxy xs)
      secReqs :: [SecurityRequirement]
secReqs = [ InsOrdHashMap Text [Text] -> SecurityRequirement
SecurityRequirement (forall l. IsList l => [Item l] -> l
fromList [(Text
s,[])]) | (Text
s,SecurityScheme
_) <- [(Text, SecurityScheme)]
secs]
      mkSec :: Definitions SecurityScheme -> SecurityDefinitions
mkSec =
#if MIN_VERSION_swagger2(2,6,0)
        Definitions SecurityScheme -> SecurityDefinitions
SecurityDefinitions
#else
        id
#endif


class HasSecurity x where
  securityName :: Proxy x -> T.Text
  securityScheme :: Proxy x -> SecurityScheme

instance HasSecurity BasicAuth where
  securityName :: Proxy BasicAuth -> Text
securityName Proxy BasicAuth
_ = Text
"BasicAuth"
  securityScheme :: Proxy BasicAuth -> SecurityScheme
securityScheme Proxy BasicAuth
_ = SecuritySchemeType -> Maybe Text -> SecurityScheme
SecurityScheme SecuritySchemeType
type_ (forall a. a -> Maybe a
Just Text
desc)
    where
      type_ :: SecuritySchemeType
type_ = SecuritySchemeType
SecuritySchemeBasic
      desc :: Text
desc  = Text
"Basic access authentication"

instance HasSecurity JWT where
  securityName :: Proxy JWT -> Text
securityName Proxy JWT
_ = Text
"JwtSecurity"
  securityScheme :: Proxy JWT -> SecurityScheme
securityScheme Proxy JWT
_ = SecuritySchemeType -> Maybe Text -> SecurityScheme
SecurityScheme SecuritySchemeType
type_ (forall a. a -> Maybe a
Just Text
desc)
    where
      type_ :: SecuritySchemeType
type_ = ApiKeyParams -> SecuritySchemeType
SecuritySchemeApiKey (Text -> ApiKeyLocation -> ApiKeyParams
ApiKeyParams Text
"Authorization" ApiKeyLocation
ApiKeyHeader)
      desc :: Text
desc  = Text
"JSON Web Token-based API key"

class AllHasSecurity (x :: [*]) where
  securities :: Proxy x -> [(T.Text,SecurityScheme)]

instance {-# OVERLAPPABLE #-} (HasSecurity x, AllHasSecurity xs) => AllHasSecurity (x ': xs) where
  securities :: Proxy (x : xs) -> [(Text, SecurityScheme)]
securities Proxy (x : xs)
_ = (forall x. HasSecurity x => Proxy x -> Text
securityName Proxy x
px, forall x. HasSecurity x => Proxy x -> SecurityScheme
securityScheme Proxy x
px) forall a. a -> [a] -> [a]
: forall (x :: [*]).
AllHasSecurity x =>
Proxy x -> [(Text, SecurityScheme)]
securities Proxy xs
pxs
    where
      px :: Proxy x
      px :: Proxy x
px = forall {k} (t :: k). Proxy t
Proxy
      pxs :: Proxy xs
      pxs :: Proxy xs
pxs = forall {k} (t :: k). Proxy t
Proxy

instance {-# OVERLAPPING #-} AllHasSecurity xs => AllHasSecurity (Cookie ': xs) where
  securities :: Proxy (Cookie : xs) -> [(Text, SecurityScheme)]
securities Proxy (Cookie : xs)
_ = forall (x :: [*]).
AllHasSecurity x =>
Proxy x -> [(Text, SecurityScheme)]
securities Proxy xs
pxs
    where
      pxs :: Proxy xs
      pxs :: Proxy xs
pxs = forall {k} (t :: k). Proxy t
Proxy

instance AllHasSecurity '[] where
  securities :: Proxy '[] -> [(Text, SecurityScheme)]
securities Proxy '[]
_ = []