Hello community, here is the log from the commit of package ghc-gogol for openSUSE:Factory checked in at 2017-08-31 20:51:23 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ghc-gogol (Old) and /work/SRC/openSUSE:Factory/.ghc-gogol.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ghc-gogol" Thu Aug 31 20:51:23 2017 rev:2 rq:513260 version:0.3.0 Changes: -------- --- /work/SRC/openSUSE:Factory/ghc-gogol/ghc-gogol.changes 2017-05-10 20:42:02.730573318 +0200 +++ /work/SRC/openSUSE:Factory/.ghc-gogol.new/ghc-gogol.changes 2017-08-31 20:51:24.442031855 +0200 @@ -1,0 +2,5 @@ +Thu Jul 27 14:07:30 UTC 2017 - [email protected] + +- Update to version 0.3.0. + +------------------------------------------------------------------- Old: ---- gogol-0.1.1.tar.gz New: ---- gogol-0.3.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ghc-gogol.spec ++++++ --- /var/tmp/diff_new_pack.Y14c9g/_old 2017-08-31 20:51:25.485885328 +0200 +++ /var/tmp/diff_new_pack.Y14c9g/_new 2017-08-31 20:51:25.497883644 +0200 @@ -18,7 +18,7 @@ %global pkg_name gogol Name: ghc-%{pkg_name} -Version: 0.1.1 +Version: 0.3.0 Release: 0 Summary: Comprehensive Google Services SDK License: MPL-2.0 ++++++ gogol-0.1.1.tar.gz -> gogol-0.3.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gogol-0.1.1/CHANGELOG.md new/gogol-0.3.0/CHANGELOG.md --- old/gogol-0.1.1/CHANGELOG.md 2016-11-03 14:21:01.000000000 +0100 +++ new/gogol-0.3.0/CHANGELOG.md 2017-07-12 16:45:05.000000000 +0200 @@ -1,5 +1,41 @@ # Change Log +## [0.3.0](https://github.com/brendanhay/gogol/tree/0.3.0) + +Released: **12 July, 2017**, Compare: [0.3.0](https://github.com/brendanhay/gogol/compare/0.2.0...0.3.0) + +### Added + +- Addition of offline mode and save + refresh for credentials. [\#66](https://github.com/brendanhay/gogol/pull/66) + +### Fixed + +- Corrected `Duration` type serialisation. [\#68](https://github.com/brendanhay/gogol/pull/68) + + +## [0.2.0](https://github.com/brendanhay/gogol/tree/0.2.0) + +Released: **12 February, 2017**, Compare: [0.1.1](https://github.com/brendanhay/gogol/compare/0.1.1...0.2.0) + +### Fixed + +- Removal of 'smart'-deserialisation of Base64-encoded byte streams. [\#47](https://github.com/brendanhay/gogol/issues/47) [\#58](https://github.com/brendanhay/gogol/pull/58) +- Various fixes for Installed Application AuthN/AuthZ example. [\#39](https://github.com/brendanhay/gogol/pull/39) +- Various fixes for token-based refresh requests. [\#37](https://github.com/brendanhay/gogol/pull/37) [\#53](https://github.com/brendanhay/gogol/pull/53) [\#55](https://github.com/brendanhay/gogol/pull/55) [\#57](https://github.com/brendanhay/gogol/pull/57) +- CSV quote parameters in BigQuery should be optional. [\#52](https://github.com/brendanhay/gogol/issues/52) +- Fixed the incocrrect construction of URL's containing mode suffixes, such as `:commit`. [\#33](https://github.com/brendanhay/gogol/issues/33) [\#34](https://github.com/brendanhay/gogol/pull/34) [\#49](https://github.com/brendanhay/gogol/issues/49) + +### New Libraries + +- `gogol-manufacturers`: [Manage](https://developers.google.com/manufacturers/) your product listings for [Google Manufacturer Center](https://www.google.com/retail/manufacturer-center/). +- `gogol-slides`: [Slides Overview](https://developers.google.com/slides/how-tos/overview). +- `gogol-language`: [Natural Language Overview](https://cloud.google.com/natural-language/). + +### Updated Service Definitions + +- All service definitions have been updated to their latest respective versions. + + ## [0.1.1](https://github.com/brendanhay/gogol/tree/0.1.1) Released: **03 November, 2016**, Compare: [0.1.0](https://github.com/brendanhay/gogol/compare/0.1.0...0.1.1) @@ -9,7 +45,6 @@ - Correcting `/computeMetadta/V1` path prefix for metadata token refresh URLs. [\#37](https://github.com/brendanhay/gogol/pull/37) - Fixes for Installed Application authentication flow. [\#39](https://github.com/brendanhay/gogol/pull/34) - ### Updated Service Definitions - All service definitions have been updated to their latest respective versions. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gogol-0.1.1/gogol.cabal new/gogol-0.3.0/gogol.cabal --- old/gogol-0.1.1/gogol.cabal 2016-11-03 14:21:01.000000000 +0100 +++ new/gogol-0.3.0/gogol.cabal 2017-07-12 16:45:05.000000000 +0200 @@ -1,5 +1,5 @@ name: gogol -version: 0.1.1 +version: 0.3.0 synopsis: Comprehensive Google Services SDK. homepage: https://github.com/brendanhay/gogol bug-reports: https://github.com/brendanhay/gogol/issues @@ -66,7 +66,7 @@ , directory >= 1.2 , exceptions >= 0.6 , filepath >= 1.2 - , gogol-core == 0.1.1.* + , gogol-core == 0.3.0.* , http-client >= 0.5 && < 1 , http-conduit >= 2.2 && < 3 , http-media >= 0.6 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gogol-0.1.1/src/Network/Google/Auth/ApplicationDefault.hs new/gogol-0.3.0/src/Network/Google/Auth/ApplicationDefault.hs --- old/gogol-0.1.1/src/Network/Google/Auth/ApplicationDefault.hs 2016-11-03 14:21:01.000000000 +0100 +++ new/gogol-0.3.0/src/Network/Google/Auth/ApplicationDefault.hs 2017-07-12 16:45:05.000000000 +0200 @@ -20,20 +20,21 @@ import Control.Applicative import Control.Exception.Lens (catching, throwingM) -import Control.Monad (unless) +import Control.Monad (unless, when) import Control.Monad.Catch import Control.Monad.IO.Class (MonadIO (..)) import Data.Aeson import Data.Aeson.Types (parseEither) import qualified Data.ByteString.Lazy as LBS +import Data.Maybe (maybe) import qualified Data.Text as Text import Network.Google.Compute.Metadata (isGCE) import Network.Google.Internal.Auth import Network.HTTP.Conduit (Manager) -import System.Directory (doesFileExist, getHomeDirectory) +import System.Directory (doesFileExist, getHomeDirectory, createDirectoryIfMissing) import System.Environment (lookupEnv) -import System.FilePath ((</>)) +import System.FilePath ((</>), takeDirectory) import System.Info (os) -- | The environment variable name which is used to specify the directory @@ -126,6 +127,30 @@ either (throwM . InvalidFileError f . Text.pack) pure (fromJSONCredentials bs) +-- | Save 'AuthorizedUser' +-- /See:/ 'cloudSDKConfigPath', 'defaultCredentialsPath'. +saveAuthorizedUserToWellKnownPath :: (MonadIO m, MonadCatch m) + => Bool -- ^ Force to save if True + -> AuthorizedUser + -> m () +saveAuthorizedUserToWellKnownPath b a = do + d <- defaultCredentialsPath + f <- maybe cloudSDKConfigPath pure d + liftIO $ createDirectoryIfMissing True $ takeDirectory f + saveAuthorizedUser f b a + +-- | Save 'AuthorizedUser' +saveAuthorizedUser :: (MonadIO m, MonadCatch m) + => FilePath + -> Bool -- ^ Force to save if True + -> AuthorizedUser + -> m () +saveAuthorizedUser f b a = do + p <- liftIO (doesFileExist f) + when (p && not b) $ + throwM (FileExistError f) + liftIO (LBS.writeFile f $ encode a) + -- | Attempt to parse either a @service_account@ or @authorized_user@ formatted -- JSON value to obtain credentials. fromJSONCredentials :: LBS.ByteString -> Either String (Credentials s) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gogol-0.1.1/src/Network/Google/Auth/InstalledApplication.hs new/gogol-0.3.0/src/Network/Google/Auth/InstalledApplication.hs --- old/gogol-0.1.1/src/Network/Google/Auth/InstalledApplication.hs 2016-11-03 14:21:01.000000000 +0100 +++ new/gogol-0.3.0/src/Network/Google/Auth/InstalledApplication.hs 2017-07-12 16:45:05.000000000 +0200 @@ -22,9 +22,12 @@ ( installedApplication -- * Forming the URL + , AccessType (..) , redirectURI , formURL + , formAccessTypeURL , formURLWith + , formAccessTypeURLWith -- * Internal Exchange and Refresh , exchangeCode @@ -33,6 +36,7 @@ import Control.Monad.Catch (MonadCatch) import Control.Monad.IO.Class (MonadIO) +import qualified Data.Text as Text import qualified Data.Text.Encoding as Text import GHC.TypeLits (Symbol) import Network.Google.Auth.Scope (AllowScopes (..), @@ -77,6 +81,9 @@ installedApplication :: OAuthClient -> OAuthCode s -> Credentials s installedApplication = FromClient +-- /See:/ <https://developers.google.com/identity/protocols/OAuth2WebServer#offline> +data AccessType = Online | Offline deriving (Show, Eq) + -- | The redirection URI used in 'formURL': @urn:ietf:wg:oauth:2.0:oob@. redirectURI :: Text redirectURI = "urn:ietf:wg:oauth:2.0:oob" @@ -88,6 +95,12 @@ formURL :: AllowScopes (s :: [Symbol]) => OAuthClient -> proxy s -> Text formURL c = formURLWith c . allowScopes +-- | 'formURL' for 'AccessType' +-- +-- /See:/ 'formUrl'. +formAccessTypeURL :: AllowScopes (s :: [Symbol]) => OAuthClient -> AccessType -> proxy s -> Text +formAccessTypeURL c a = formAccessTypeURLWith c a . allowScopes + -- | Form a URL using 'OAuthScope' values. -- -- /See:/ 'formURL'. @@ -98,6 +111,13 @@ <> "&redirect_uri=" <> redirectURI <> "&scope=" <> Text.decodeUtf8 (queryEncodeScopes ss) +-- | 'formURLWith' for 'AccessType' +-- +-- /See:/ 'formURLWith'. +formAccessTypeURLWith :: OAuthClient -> AccessType -> [OAuthScope] -> Text +formAccessTypeURLWith c a ss = formURLWith c ss + <> "&access_type=" <> (Text.toLower . Text.pack $ show a) + -- | Exchange 'OAuthClient' details and the received 'OAuthCode' for a new -- 'OAuthToken'. -- @@ -109,7 +129,7 @@ -> Manager -> m (OAuthToken s) exchangeCode c n = refreshRequest $ - accountsRequest + tokenRequest { Client.requestBody = textBody $ "grant_type=authorization_code" <> "&client_id=" <> toQueryParam (_clientId c) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gogol-0.1.1/src/Network/Google/Auth/ServiceAccount.hs new/gogol-0.3.0/src/Network/Google/Auth/ServiceAccount.hs --- old/gogol-0.1.1/src/Network/Google/Auth/ServiceAccount.hs 2016-11-03 14:21:01.000000000 +0100 +++ new/gogol-0.3.0/src/Network/Google/Auth/ServiceAccount.hs 2017-07-12 16:45:05.000000000 +0200 @@ -68,7 +68,7 @@ -> Manager -> m (OAuthToken s) authorizedUserToken u r = refreshRequest $ - accountsRequest + tokenRequest { Client.requestBody = textBody $ "grant_type=refresh_token" <> "&client_id=" <> toQueryParam (_userId u) @@ -86,7 +86,7 @@ -> m (OAuthToken s) serviceAccountToken s p l m = do b <- encodeBearerJWT s p - let rq = accountsRequest + let rq = tokenRequest { Client.requestBody = RequestBodyBS $ "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer" <> "&assertion=" @@ -126,7 +126,7 @@ ] payload = base64Encode - [ "aud" .= accountsURL + [ "aud" .= tokenURL , "scope" .= concatScopes (allowScopes p) , "iat" .= n , "exp" .= (n + seconds maxTokenLifetime) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gogol-0.1.1/src/Network/Google/Auth.hs new/gogol-0.3.0/src/Network/Google/Auth.hs --- old/gogol-0.1.1/src/Network/Google/Auth.hs 2016-11-03 14:21:01.000000000 +0100 +++ new/gogol-0.3.0/src/Network/Google/Auth.hs 2017-07-12 16:45:05.000000000 +0200 @@ -22,6 +22,8 @@ , getApplicationDefault , fromWellKnownPath , fromFilePath + , saveAuthorizedUserToWellKnownPath + , saveAuthorizedUser -- ** Installed Application Credentials , installedApplication @@ -33,8 +35,10 @@ -- ** Thread-safe Storage , Store , initStore + , retrieveAuthFromStore , Auth (..) + , authToAuthorizedUser , exchange , refresh @@ -81,6 +85,19 @@ import qualified Network.HTTP.Conduit as Client import Network.HTTP.Types (hAuthorization) +-- | 'authToAuthorizedUser' converts 'Auth' into an 'AuthorizedUser' +-- by returning 'Right' if there is a 'FromClient'-constructed +-- Credentials and a refreshed token; otherwise, returning +-- 'Left' with error message. +authToAuthorizedUser :: AllowScopes s => Auth s -> Either Text AuthorizedUser +authToAuthorizedUser a = AuthorizedUser + <$> (_clientId <$> getClient) + <*> maybe (Left "no refresh token") Right (_tokenRefresh (_token a)) + <*> (_clientSecret <$> getClient) + where getClient = case _credentials a of + FromClient c _ -> Right c + _ -> Left "not FromClient" + -- | An 'OAuthToken' that can potentially be expired, with the original -- credentials that can be used to perform a refresh. data Auth (s :: [Symbol]) = Auth @@ -110,6 +127,12 @@ -> m (Store s) initStore c l m = exchange c l m >>= fmap Store . liftIO . newMVar +-- | Retrieve auth from storage +retrieveAuthFromStore :: (MonadIO m, MonadCatch m, AllowScopes s) + => Store s + -> m (Auth s) +retrieveAuthFromStore (Store s) = liftIO (readMVar s) + -- | Concurrently read the current token, and if expired, then -- safely perform a single serial refresh. getToken :: (MonadIO m, MonadCatch m, AllowScopes s) @@ -145,7 +168,7 @@ FromClient x n -> exchangeCode x n FromUser u -> authorizedUserToken u Nothing --- | Refresh an existing 'OAuthToken' using +-- | Refresh an existing 'OAuthToken'. refresh :: forall m s. (MonadIO m, MonadCatch m, AllowScopes s) => Auth s -> Logger diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gogol-0.1.1/src/Network/Google/Internal/Auth.hs new/gogol-0.3.0/src/Network/Google/Internal/Auth.hs --- old/gogol-0.1.1/src/Network/Google/Internal/Auth.hs 2016-11-03 14:21:01.000000000 +0100 +++ new/gogol-0.3.0/src/Network/Google/Internal/Auth.hs 2017-07-12 16:45:05.000000000 +0200 @@ -129,6 +129,13 @@ , _userSecret :: !Secret } deriving (Eq, Show) +instance ToJSON AuthorizedUser where + toJSON (AuthorizedUser i r s) = + object [ "client_id" .= i + , "refresh_token" .= r + , "client_secret" .= s + ] + instance FromJSON AuthorizedUser where parseJSON = withObject "authorized_user" $ \o -> AuthorizedUser <$> o .: "client_id" @@ -175,12 +182,13 @@ toQueryParam (OAuthCode c) = c toHeader (OAuthCode c) = Text.encodeUtf8 c --- | An error thrown when attempting to read AuthN/AuthZ information. +-- | An error thrown when attempting to read/write AuthN/AuthZ information. data AuthError = RetrievalError HttpException | MissingFileError FilePath | InvalidFileError FilePath Text | TokenRefreshError Status Text (Maybe Text) + | FileExistError FilePath deriving (Show, Typeable) instance Exception AuthError @@ -258,6 +266,22 @@ , Client.requestHeaders = [ (hContentType, "application/x-www-form-urlencoded") ] + } + +-- | @https://www.googleapis.com/oauth2/v4/token@. +tokenURL :: Text +tokenURL = "https://www.googleapis.com/oauth2/v4/token" + +tokenRequest :: Client.Request +tokenRequest = Client.defaultRequest + { Client.host = "www.googleapis.com" + , Client.port = 443 + , Client.secure = True + , Client.method = "POST" + , Client.path = "/oauth2/v4/token" + , Client.requestHeaders = + [ (hContentType, "application/x-www-form-urlencoded") + ] } refreshRequest :: (MonadIO m, MonadCatch m) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gogol-0.1.1/src/Network/Google.hs new/gogol-0.3.0/src/Network/Google.hs --- old/gogol-0.1.1/src/Network/Google.hs 2016-11-03 14:21:01.000000000 +0100 +++ new/gogol-0.3.0/src/Network/Google.hs 2017-07-12 16:45:05.000000000 +0200 @@ -312,7 +312,7 @@ > bkt = "my-storage-bucket" > > runResourceT . runGoogle env $ > -- (5) -> upload (objectsInsert bkt object' & oiName ?~ key) bkt +> upload (objectsInsert bkt object' & oiName ?~ key) body Breaking down the above example, we have the following points of interest:
