2018-07-27 12:34:50 +03:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
|
|
{-# LANGUAGE TemplateHaskell #-}
|
|
|
|
|
|
|
|
module Hasura.Server.CheckUpdates
|
|
|
|
( checkForUpdates
|
|
|
|
) where
|
|
|
|
|
|
|
|
import Control.Exception (try)
|
|
|
|
import Control.Lens
|
|
|
|
import Control.Monad (forever)
|
2018-09-12 14:03:36 +03:00
|
|
|
import System.Environment (lookupEnv)
|
2018-07-27 12:34:50 +03:00
|
|
|
|
|
|
|
import qualified Control.Concurrent as C
|
|
|
|
import qualified Data.Aeson as A
|
|
|
|
import qualified Data.Aeson.Casing as A
|
|
|
|
import qualified Data.Aeson.TH as A
|
|
|
|
import qualified Data.Text as T
|
|
|
|
import qualified Network.HTTP.Client as H
|
|
|
|
import qualified Network.Wreq as Wreq
|
|
|
|
import qualified System.Log.FastLogger as FL
|
|
|
|
|
|
|
|
import Hasura.Logging (LoggerCtx (..))
|
|
|
|
import Hasura.Prelude
|
|
|
|
import Hasura.Server.Version (currentVersion)
|
|
|
|
|
|
|
|
|
|
|
|
newtype UpdateInfo
|
|
|
|
= UpdateInfo
|
add support for jwt authorization (close #186) (#255)
The API:
1. HGE has `--jwt-secret` flag or `HASURA_GRAPHQL_JWT_SECRET` env var. The value of which is a JSON.
2. The structure of this JSON is: `{"type": "<standard-JWT-algorithms>", "key": "<the-key>"}`
`type` : Standard JWT algos : `HS256`, `RS256`, `RS512` etc. (see jwt.io).
`key`:
i. Incase of symmetric key, the key as it is.
ii. Incase of asymmetric keys, only the public key, in a PEM encoded string or as a X509 certificate.
3. The claims in the JWT token must contain the following:
i. `x-hasura-default-role` field: default role of that user
ii. `x-hasura-allowed-roles` : A list of allowed roles for the user. The default role is overriden by `x-hasura-role` header.
4. The claims in the JWT token, can have other `x-hasura-*` fields where their values can only be strings.
5. The JWT tokens are sent as `Authorization: Bearer <token>` headers.
---
To test:
1. Generate a shared secret (for HMAC-SHA256) or RSA key pair.
2. Goto https://jwt.io/ , add the keys
3. Edit the claims to have `x-hasura-role` (mandatory) and other `x-hasura-*` fields. Add permissions related to the claims to test permissions.
4. Start HGE with `--jwt-secret` flag or `HASURA_GRAPHQL_JWT_SECRET` env var, which takes a JSON string: `{"type": "HS256", "key": "mylongsharedsecret"}` or `{"type":"RS256", "key": "<PEM-encoded-public-key>"}`
5. Copy the JWT token from jwt.io and use it in the `Authorization: Bearer <token>` header.
---
TODO: Support EC public keys. It is blocked on frasertweedale/hs-jose#61
2018-08-30 13:32:09 +03:00
|
|
|
{ _uiLatest :: T.Text
|
2018-07-27 12:34:50 +03:00
|
|
|
} deriving (Show, Eq)
|
|
|
|
|
|
|
|
$(A.deriveJSON (A.aesonDrop 2 A.snakeCase) ''UpdateInfo)
|
|
|
|
|
|
|
|
checkForUpdates :: LoggerCtx -> H.Manager -> IO ()
|
|
|
|
checkForUpdates (LoggerCtx loggerSet _ _) manager = do
|
|
|
|
let options = Wreq.defaults
|
|
|
|
& Wreq.checkResponse ?~ (\_ _ -> return ())
|
|
|
|
& Wreq.manager .~ Right manager
|
2018-09-12 14:03:36 +03:00
|
|
|
url <- getUrl
|
2018-07-27 12:34:50 +03:00
|
|
|
forever $ do
|
|
|
|
resp <- try $ Wreq.getWith options $ T.unpack url
|
|
|
|
case resp of
|
|
|
|
Left ex -> ignoreHttpErr ex
|
|
|
|
Right bs -> do
|
|
|
|
UpdateInfo latestVersion <- decodeResp $ bs ^. Wreq.responseBody
|
|
|
|
when (latestVersion /= currentVersion) $
|
|
|
|
FL.pushLogStrLn loggerSet $ FL.toLogStr $ updateMsg latestVersion
|
|
|
|
|
|
|
|
C.threadDelay aDay
|
|
|
|
|
|
|
|
where
|
|
|
|
updateMsg v = "Update: A new version is available: " <> v
|
2018-09-12 14:03:36 +03:00
|
|
|
getUrl = do
|
|
|
|
let buildUrl a = "https://releases.hasura.io/graphql-engine?agent="
|
|
|
|
<> a
|
|
|
|
<> "&version="
|
|
|
|
<> currentVersion
|
|
|
|
isCI <- lookupEnv "CI"
|
|
|
|
case isCI of
|
|
|
|
Just "true" -> return $ buildUrl "server-ci"
|
|
|
|
_ -> return $ buildUrl "server"
|
|
|
|
|
2018-07-27 12:34:50 +03:00
|
|
|
aDay = 86400 * 1000 * 1000
|
|
|
|
|
|
|
|
-- ignoring if there is any error in response and returning the current version
|
|
|
|
decodeResp bs = case A.eitherDecode bs of
|
|
|
|
Left _ -> return $ UpdateInfo currentVersion
|
|
|
|
Right a -> return a
|
|
|
|
|
|
|
|
ignoreHttpErr :: H.HttpException -> IO ()
|
|
|
|
ignoreHttpErr _ = return ()
|