@@ -1,5 +1,6 @@
11{-# LANGUAGE DataKinds #-}
22{-# LANGUAGE ExplicitNamespaces #-}
3+{-# LANGUAGE OverloadedStrings #-}
34{-# LANGUAGE PolyKinds #-}
45{-# LANGUAGE ScopedTypeVariables #-}
56{-# LANGUAGE TypeFamilies #-}
@@ -18,15 +19,21 @@
1819-- from the underlying OS.
1920module Network.Google.Auth.Scope where
2021
22+import Data.ByteString (ByteString)
23+import qualified Data.ByteString.Char8 as BS8
24+import Data.Coerce (coerce)
25+import Data.Text (Text)
2126import qualified Data.Text as Text
22−import Data.Type.Bool (type (||))
27+import qualified Data.Text.Encoding as Text
28+import Data.Type.Bool (type (||), type If)
2329import Data.Type.Equality (type (==))
2430import Data.Typeable (Proxy (..))
2531import GHC.Exts (Constraint)
2632import GHC.TypeLits (KnownSymbol, Symbol, symbolVal)
2733import Network.Google.Internal.Auth (Credentials)
28−import Network.Google.Prelude (GoogleRequest (Ss),
34+import Network.Google.Prelude (GoogleRequest (..),
2935 OAuthScope (..))
36+import Network.HTTP.Types (urlEncode)
3037
3138-- | Type-restrict the supplied credentials/whatever to the specific scopes.
3239--
@@ -39,6 +46,9 @@ import Network.Google.Prelude (GoogleRequest (Ss),
3946allow :: proxy s -> k s -> k s
4047allow _ = id
4148
49+forbid :: k '[] -> k '[]
50+forbid = id
51+
4252-- | Append the type-level lists of two 'Proxy' values.
4353--
4454-- /See:/ 'allow'.
@@ -47,25 +57,20 @@ allow _ = id
4757
4858-- | Determine if _any_ of the scopes a request requires is a subset
4959-- of the scopes the credentials supports.
60+--
61+-- For error message/presentation purposes, this wraps the result of
62+-- the membership checks below.
5063type family Authorize (s :: [Symbol]) a :: Constraint where
51− Authorize s a = HasScope (Ss a ⊆ s) s
52−
53−-- | For error message/presentation purposes, this wraps the result of
54−-- the membership checks below. When 'False fails to match, it will show
55−-- the reduced error case for '⊆' compared against the full
56−-- set of scopes the credentials ('s') have.
57−type family HasScope p s :: Constraint where
58− HasScope 'True s = ()
64+ Authorize s a = HasScope (Scopes a) s ~ 'True
5965
60−type family (⊆) a s where
61− (⊆) a (x ': xs) = x ∈ a || a ⊆ xs
66+type family HasScope a s where
67+ HasScope '[] s = 'True
68+ HasScope a (x ': xs) = x ∈ a || HasScope a xs
6269
63−-- | Is 'a :: *' an element of 'b :: [*]'.
6470type family (∈) a b where
6571 (∈) x '[] = 'False
6672 (∈) x (y ': xs) = x == y || x ∈ xs
6773
68−-- | Type-level append.
6974type family (++) xs ys where
7075 (++) a '[] = a
7176 (++) '[] b = b
@@ -85,3 +90,12 @@ instance (KnownSymbol x, Allow xs) => Allow (x ': xs) where
8590
8691instance Allow s => Allow (Credentials s) where
8792 getScopes _ = getScopes (Proxy :: Proxy s)
93+
94+concatScopes :: [OAuthScope] -> Text
95+concatScopes = Text.intercalate " " . coerce
96+
97+queryEncodeScopes :: [OAuthScope] -> ByteString
98+queryEncodeScopes =
99+ BS8.intercalate "+"
100+ . map (urlEncode True . Text.encodeUtf8)
101+ . coerce