feat: renamed config options with prefixes; added aliases for old names

* secret-is-base64 -> jwt-secret-is-base64
* role-claim-key -> jwt-role-claim-key
* max-rows -> db-max-rows
* pre-request -> db-pre-request
* root-spec -> db-root-spec
* db-schema -> db-schemas

This is not a breaking change, because aliases are added as well.

refactor: sorted all config keys alphabetically where applicable
This commit is contained in:
Wolfgang Walther
2020-12-06 21:59:03 +01:00
committed by Wolfgang Walther
parent ab3375998d
commit ed58511de3
21 changed files with 269 additions and 224 deletions
+8 -8
View File
@@ -28,7 +28,7 @@ import System.IO (BufferMode (..), hSetBuffering)
import PostgREST.App (postgrest) import PostgREST.App (postgrest)
import PostgREST.Config (AppConfig (..), CLI (..), Command (..), import PostgREST.Config (AppConfig (..), CLI (..), Command (..),
configPoolTimeout', dumpAppConfig, configDbPoolTimeout', dumpAppConfig,
prettyVersion, readCLIShowHelp, prettyVersion, readCLIShowHelp,
readValidateConfig) readValidateConfig)
import PostgREST.DbStructure (getDbStructure, getPgVersion) import PostgREST.DbStructure (getDbStructure, getPgVersion)
@@ -68,11 +68,11 @@ main = do
-- These are config values that can't be reloaded at runtime. Reloading some of them would imply restarting the web server. -- These are config values that can't be reloaded at runtime. Reloading some of them would imply restarting the web server.
let let
host = configHost conf host = configServerHost conf
port = configPort conf port = configServerPort conf
maybeSocketAddr = configSocket conf maybeSocketAddr = configServerUnixSocket conf
#ifndef mingw32_HOST_OS #ifndef mingw32_HOST_OS
socketFileMode = configSocketMode conf socketFileMode = configServerUnixSocketMode conf
#endif #endif
dbUri = toS (configDbUri conf) dbUri = toS (configDbUri conf)
(dbChannelEnabled, dbChannel) = (configDbChannelEnabled conf, toS $ configDbChannel conf) (dbChannelEnabled, dbChannel) = (configDbChannelEnabled conf, toS $ configDbChannel conf)
@@ -81,8 +81,8 @@ main = do
. setPort port . setPort port
. setServerName (toS $ "postgrest/" <> prettyVersion) $ . setServerName (toS $ "postgrest/" <> prettyVersion) $
defaultSettings defaultSettings
poolSize = configPoolSize conf poolSize = configDbPoolSize conf
poolTimeout = configPoolTimeout' conf poolTimeout = configDbPoolTimeout' conf
logLevel = configLogLevel conf logLevel = configLogLevel conf
-- create connection pool with the provided settings, returns either a 'Connection' or a 'ConnectionError'. Does not throw. -- create connection pool with the provided settings, returns either a 'Connection' or a 'ConnectionError'. Does not throw.
@@ -248,7 +248,7 @@ connectionStatus pool =
fillSchemaCache :: P.Pool -> PgVersion -> IORef AppConfig -> IORef (Maybe DbStructure) -> IO () fillSchemaCache :: P.Pool -> PgVersion -> IORef AppConfig -> IORef (Maybe DbStructure) -> IO ()
fillSchemaCache pool actualPgVersion refConf refDbStructure = do fillSchemaCache pool actualPgVersion refConf refDbStructure = do
conf <- readIORef refConf conf <- readIORef refConf
result <- P.use pool $ HT.transaction HT.ReadCommitted HT.Read $ getDbStructure (toList $ configSchemas conf) (configExtraSearchPath conf) actualPgVersion (configDbPrepared conf) result <- P.use pool $ HT.transaction HT.ReadCommitted HT.Read $ getDbStructure (toList $ configDbSchemas conf) (configDbExtraSearchPath conf) actualPgVersion (configDbPreparedStatements conf)
case result of case result of
Left e -> do Left e -> do
-- If this error happens it would mean the connection is down again. Improbable because connectionStatus ensured the connection. -- If this error happens it would mean the connection is down again. Improbable because connectionStatus ensured the connection.
+10 -10
View File
@@ -75,25 +75,25 @@ postgrest logLev refConf refDbStructure pool getTime connWorker =
Nothing -> respond . errorResponseFor $ ConnectionLostError Nothing -> respond . errorResponseFor $ ConnectionLostError
Just dbStructure -> do Just dbStructure -> do
response <- do response <- do
let apiReq = userApiRequest (configSchemas conf) (configRootSpec conf) dbStructure req body let apiReq = userApiRequest (configDbSchemas conf) (configDbRootSpec conf) dbStructure req body
case apiReq of case apiReq of
Left err -> return . errorResponseFor $ err Left err -> return . errorResponseFor $ err
Right apiRequest -> do Right apiRequest -> do
-- The jwt must be checked before touching the db. -- The jwt must be checked before touching the db.
attempt <- attemptJwtClaims (configJWKS conf) (configJwtAudience conf) (toS $ iJWT apiRequest) time (rightToMaybe $ configRoleClaimKey conf) attempt <- attemptJwtClaims (configJWKS conf) (configJwtAudience conf) (toS $ iJWT apiRequest) time (rightToMaybe $ configJwtRoleClaimKey conf)
case jwtClaims attempt of case jwtClaims attempt of
Left errJwt -> return . errorResponseFor $ errJwt Left errJwt -> return . errorResponseFor $ errJwt
Right claims -> do Right claims -> do
let let
authed = containsRole claims authed = containsRole claims
shouldCommit = configTxAllowOverride conf && iPreferTransaction apiRequest == Just Commit shouldCommit = configDbTxAllowOverride conf && iPreferTransaction apiRequest == Just Commit
shouldRollback = configTxAllowOverride conf && iPreferTransaction apiRequest == Just Rollback shouldRollback = configDbTxAllowOverride conf && iPreferTransaction apiRequest == Just Rollback
preferenceApplied preferenceApplied
| shouldCommit = addHeadersIfNotIncluded [(hPreferenceApplied, BS.pack (show Commit))] | shouldCommit = addHeadersIfNotIncluded [(hPreferenceApplied, BS.pack (show Commit))]
| shouldRollback = addHeadersIfNotIncluded [(hPreferenceApplied, BS.pack (show Rollback))] | shouldRollback = addHeadersIfNotIncluded [(hPreferenceApplied, BS.pack (show Rollback))]
| otherwise = identity | otherwise = identity
handleReq = do handleReq = do
when (shouldRollback || (configTxRollbackAll conf && not shouldCommit)) HT.condemn when (shouldRollback || (configDbTxRollbackAll conf && not shouldCommit)) HT.condemn
mapResponseHeaders preferenceApplied <$> runPgLocals conf claims (app dbStructure conf) apiRequest mapResponseHeaders preferenceApplied <$> runPgLocals conf claims (app dbStructure conf) apiRequest
dbResp <- P.use pool $ HT.transaction HT.ReadCommitted (txMode apiRequest) handleReq dbResp <- P.use pool $ HT.transaction HT.ReadCommitted (txMode apiRequest) handleReq
return $ either (errorResponseFor . PgError authed) identity dbResp return $ either (errorResponseFor . PgError authed) identity dbResp
@@ -320,9 +320,9 @@ app dbStructure conf apiRequest =
return $ responseLBS status headers rBody return $ responseLBS status headers rBody
(ActionInspect headersOnly, TargetDefaultSpec tSchema) -> do (ActionInspect headersOnly, TargetDefaultSpec tSchema) -> do
let host = configHost conf let host = configServerHost conf
port = toInteger $ configPort conf port = toInteger $ configServerPort conf
proxy = pickProxy $ toS <$> configOpenAPIProxyUri conf proxy = pickProxy $ toS <$> configOpenApiServerProxyUri conf
uri Nothing = ("http", host, port, "/") uri Nothing = ("http", host, port, "/")
uri (Just Proxy { proxyScheme = s, proxyHost = h, proxyPort = p, proxyPath = b }) = (s, h, p, b) uri (Just Proxy { proxyScheme = s, proxyHost = h, proxyPort = p, proxyPath = b }) = (s, h, p, b)
uri' = uri proxy uri' = uri proxy
@@ -340,8 +340,8 @@ app dbStructure conf apiRequest =
where where
notFound = responseLBS status404 [] "" notFound = responseLBS status404 [] ""
maxRows = configMaxRows conf maxRows = configDbMaxRows conf
prepared = configDbPrepared conf prepared = configDbPreparedStatements conf
exactCount = iPreferCount apiRequest == Just ExactCount exactCount = iPreferCount apiRequest == Just ExactCount
estimatedCount = iPreferCount apiRequest == Just EstimatedCount estimatedCount = iPreferCount apiRequest == Just EstimatedCount
plannedCount = iPreferCount apiRequest == Just PlannedCount plannedCount = iPreferCount apiRequest == Just PlannedCount
+111 -99
View File
@@ -22,7 +22,7 @@ module PostgREST.Config ( prettyVersion
, CLI (..) , CLI (..)
, Command (..) , Command (..)
, AppConfig (..) , AppConfig (..)
, configPoolTimeout' , configDbPoolTimeout'
, dumpAppConfig , dumpAppConfig
, readCLIShowHelp , readCLIShowHelp
, readValidateConfig , readValidateConfig
@@ -78,46 +78,39 @@ data Command = CmdRun | CmdDumpConfig deriving (Eq)
-- | Config file settings for the server -- | Config file settings for the server
data AppConfig = AppConfig { data AppConfig = AppConfig {
configDbUri :: Text configAppSettings :: [(Text, Text)]
, configAnonRole :: Text , configDbAnonRole :: Text
, configOpenAPIProxyUri :: Maybe Text , configDbChannel :: Text
, configSchemas :: NonEmpty Text , configDbChannelEnabled :: Bool
, configHost :: Text , configDbExtraSearchPath :: [Text]
, configPort :: Int , configDbMaxRows :: Maybe Integer
, configSocket :: Maybe FilePath , configDbPoolSize :: Int
, configSocketMode :: Either Text FileMode , configDbPoolTimeout :: Int
, configDbChannel :: Text , configDbPreRequest :: Maybe Text
, configDbChannelEnabled :: Bool , configDbPreparedStatements :: Bool
, configDbRootSpec :: Maybe Text
, configJwtSecret :: Maybe B.ByteString , configDbSchemas :: NonEmpty Text
, configJwtSecretIsBase64 :: Bool , configDbTxAllowOverride :: Bool
, configJwtAudience :: Maybe StringOrURI , configDbTxRollbackAll :: Bool
, configDbUri :: Text
, configPoolSize :: Int , configJWKS :: Maybe JWKSet
, configPoolTimeout :: Int , configJwtAudience :: Maybe StringOrURI
, configMaxRows :: Maybe Integer , configJwtRoleClaimKey :: Either Text JSPath
, configPreReq :: Maybe Text , configJwtSecret :: Maybe B.ByteString
, configSettings :: [(Text, Text)] , configJwtSecretIsBase64 :: Bool
, configRoleClaimKey :: Either Text JSPath , configLogLevel :: LogLevel
, configExtraSearchPath :: [Text] , configOpenApiServerProxyUri :: Maybe Text
, configRawMediaTypes :: [B.ByteString]
, configRootSpec :: Maybe Text , configServerHost :: Text
, configRawMediaTypes :: [B.ByteString] , configServerPort :: Int
, configServerUnixSocket :: Maybe FilePath
, configJWKS :: Maybe JWKSet , configServerUnixSocketMode :: Either Text FileMode
, configLogLevel :: LogLevel
, configTxRollbackAll :: Bool
, configTxAllowOverride :: Bool
, configDbPrepared :: Bool
} }
deriving (Show) deriving (Show)
configPoolTimeout' :: (Fractional a) => AppConfig -> a configDbPoolTimeout' :: (Fractional a) => AppConfig -> a
configPoolTimeout' = configDbPoolTimeout' =
fromRational . toRational . configPoolTimeout fromRational . toRational . configDbPoolTimeout
-- | User friendly version number -- | User friendly version number
prettyVersion :: Text prettyVersion :: Text
@@ -179,6 +172,16 @@ readCLIShowHelp = customExecParser parserPrefs opts
|## extra schemas to add to the search_path of every request |## extra schemas to add to the search_path of every request
|db-extra-search-path = "public" |db-extra-search-path = "public"
| |
|## limit rows in response
|# db-max-rows = 1000
|
|## stored proc to exec immediately after auth
|# db-pre-request = "stored_proc_name"
|
|## stored proc that overrides the root "/" spec
|## it must be inside the db-schema
|# db-root-spec = "stored_proc_name"
|
|## Notification channel for reloading the schema cache |## Notification channel for reloading the schema cache
|db-channel = "pgrst" |db-channel = "pgrst"
| |
@@ -219,20 +222,10 @@ readCLIShowHelp = customExecParser parserPrefs opts
|## (use "@filename" to load from separate file) |## (use "@filename" to load from separate file)
|# jwt-secret = "secret_with_at_least_32_characters" |# jwt-secret = "secret_with_at_least_32_characters"
|# jwt-aud = "your_audience_claim" |# jwt-aud = "your_audience_claim"
|secret-is-base64 = false |jwt-secret-is-base64 = false
| |
|## jspath to the role claim key |## jspath to the role claim key
|role-claim-key = ".role" |jwt-role-claim-key = ".role"
|
|## limit rows in response
|# max-rows = 1000
|
|## stored proc to exec immediately after auth
|# pre-request = "stored_proc_name"
|
|## stored proc that overrides the root "/" spec
|## it must be inside the db-schema
|# root-spec = "stored_proc_name"
| |
|## content types to produce raw output |## content types to produce raw output
|# raw-media-types="image/png, image/jpg" |# raw-media-types="image/png, image/jpg"
@@ -253,49 +246,49 @@ dumpAppConfig conf = do
-- apply conf to all pgrst settings -- apply conf to all pgrst settings
pgrstSettings = (\(k, v) -> (k, v conf)) <$> pgrstSettings = (\(k, v) -> (k, v conf)) <$>
[("db-uri", q . configDbUri) [("db-anon-role", q . configDbAnonRole)
,("db-schema", q . intercalate "," . toList . configSchemas)
,("db-anon-role", q . configAnonRole)
,("db-pool", show . configPoolSize)
,("db-pool-timeout", show . configPoolTimeout)
,("db-extra-search-path", q . intercalate "," . configExtraSearchPath)
,("db-channel", q . configDbChannel) ,("db-channel", q . configDbChannel)
,("db-channel-enabled", toLower . show . configDbChannelEnabled) ,("db-channel-enabled", toLower . show . configDbChannelEnabled)
,("db-extra-search-path", q . intercalate "," . configDbExtraSearchPath)
,("db-max-rows", maybe "\"\"" show . configDbMaxRows)
,("db-pool", show . configDbPoolSize)
,("db-pool-timeout", show . configDbPoolTimeout)
,("db-pre-request", q . fromMaybe mempty . configDbPreRequest)
,("db-prepared-statements", toLower . show . configDbPreparedStatements)
,("db-root-spec", q . fromMaybe mempty . configDbRootSpec)
,("db-schemas", q . intercalate "," . toList . configDbSchemas)
,("db-tx-end", q . showTxEnd) ,("db-tx-end", q . showTxEnd)
,("db-prepared-statements", toLower . show . configDbPrepared) ,("db-uri", q . configDbUri)
,("server-host", q . configHost)
,("server-port", show . configPort)
,("server-unix-socket", q . maybe mempty pack . configSocket)
,("server-unix-socket-mode", q . pack . showSocketMode)
,("openapi-server-proxy-uri", q . fromMaybe mempty . configOpenAPIProxyUri)
,("jwt-secret", q . toS . showJwtSecret)
,("jwt-aud", toS . encode . maybe "" toJSON . configJwtAudience) ,("jwt-aud", toS . encode . maybe "" toJSON . configJwtAudience)
,("secret-is-base64", toLower . show . configJwtSecretIsBase64) ,("jwt-role-claim-key", q . intercalate mempty . fmap show . fromRight' . configJwtRoleClaimKey)
,("role-claim-key", q . intercalate mempty . fmap show . fromRight' . configRoleClaimKey) ,("jwt-secret", q . toS . showJwtSecret)
,("max-rows", maybe "\"\"" show . configMaxRows) ,("jwt-secret-is-base64", toLower . show . configJwtSecretIsBase64)
,("pre-request", q . fromMaybe mempty . configPreReq)
,("root-spec", q . fromMaybe mempty . configRootSpec)
,("raw-media-types", q . toS . B.intercalate "," . configRawMediaTypes)
,("log-level", q . show . configLogLevel) ,("log-level", q . show . configLogLevel)
,("openapi-server-proxy-uri", q . fromMaybe mempty . configOpenApiServerProxyUri)
,("raw-media-types", q . toS . B.intercalate "," . configRawMediaTypes)
,("server-host", q . configServerHost)
,("server-port", show . configServerPort)
,("server-unix-socket", q . maybe mempty pack . configServerUnixSocket)
,("server-unix-socket-mode", q . pack . showSocketMode)
] ]
-- quote all app.settings -- quote all app.settings
appSettings = second q <$> configSettings conf appSettings = second q <$> configAppSettings conf
-- quote strings and replace " with \" -- quote strings and replace " with \"
q s = "\"" <> replace "\"" "\\\"" s <> "\"" q s = "\"" <> replace "\"" "\\\"" s <> "\""
showTxEnd c = case (configTxRollbackAll c, configTxAllowOverride c) of showTxEnd c = case (configDbTxRollbackAll c, configDbTxAllowOverride c) of
( False, False ) -> "commit" ( False, False ) -> "commit"
( False, True ) -> "commit-allow-override" ( False, True ) -> "commit-allow-override"
( True , False ) -> "rollback" ( True , False ) -> "rollback"
( True , True ) -> "rollback-allow-override" ( True , True ) -> "rollback-allow-override"
showSocketMode c = showOct (fromRight' $ configSocketMode c) ""
showJwtSecret c showJwtSecret c
| configJwtSecretIsBase64 c = B64.encode secret | configJwtSecretIsBase64 c = B64.encode secret
| otherwise = toS secret | otherwise = toS secret
where where
secret = fromMaybe mempty $ configJwtSecret c secret = fromMaybe mempty $ configJwtSecret c
showSocketMode c = showOct (fromRight' $ configServerUnixSocketMode c) ""
-- | Parse the config file -- | Parse the config file
readAppConfig :: FilePath -> IO AppConfig readAppConfig :: FilePath -> IO AppConfig
@@ -315,33 +308,40 @@ readAppConfig cfgPath = do
where where
parseConfig = parseConfig =
AppConfig AppConfig
<$> reqString "db-uri" <$> (fmap (fmap coerceText) <$> C.subassocs "app.settings" C.value)
<*> reqString "db-anon-role" <*> reqString "db-anon-role"
<*> (fromMaybe "pgrst" <$> optString "db-channel")
<*> (fromMaybe False <$> optBool "db-channel-enabled")
<*> (maybe ["public"] splitOnCommas <$> optValue "db-extra-search-path")
<*> optWithAlias (optInt "db-max-rows")
(optInt "max-rows")
<*> (fromMaybe 10 <$> optInt "db-pool")
<*> (fromMaybe 10 <$> optInt "db-pool-timeout")
<*> optWithAlias (optString "db-pre-request")
(optString "pre-request")
<*> (fromMaybe True <$> optBool "db-prepared-statements")
<*> optWithAlias (optString "db-root-spec")
(optString "root-spec")
<*> (fromList . splitOnCommas <$> reqWithAlias (optValue "db-schemas")
(optValue "db-schema")
"missing key: either db-schemas or db-schema must be set")
<*> parseTxEnd "db-tx-end" snd
<*> parseTxEnd "db-tx-end" fst
<*> reqString "db-uri"
<*> pure Nothing
<*> parseJwtAudience "jwt-aud"
<*> (maybe (Right [JSPKey "role"]) parseRoleClaimKey <$> optWithAlias (optValue "jwt-role-claim-key")
(optValue "role-claim-key"))
<*> (fmap encodeUtf8 <$> optString "jwt-secret")
<*> (fromMaybe False <$> optWithAlias (optBool "jwt-secret-is-base64")
(optBool "secret-is-base64"))
<*> parseLogLevel "log-level"
<*> optString "openapi-server-proxy-uri" <*> optString "openapi-server-proxy-uri"
<*> (fromList . splitOnCommas <$> reqValue "db-schema") <*> (maybe [] (fmap encodeUtf8 . splitOnCommas) <$> optValue "raw-media-types")
<*> (fromMaybe "!4" <$> optString "server-host") <*> (fromMaybe "!4" <$> optString "server-host")
<*> (fromMaybe 3000 <$> optInt "server-port") <*> (fromMaybe 3000 <$> optInt "server-port")
<*> (fmap unpack <$> optString "server-unix-socket") <*> (fmap unpack <$> optString "server-unix-socket")
<*> parseSocketFileMode "server-unix-socket-mode" <*> parseSocketFileMode "server-unix-socket-mode"
<*> (fromMaybe "pgrst" <$> optString "db-channel")
<*> (fromMaybe False <$> optBool "db-channel-enabled")
<*> (fmap encodeUtf8 <$> optString "jwt-secret")
<*> (fromMaybe False <$> optBool "secret-is-base64")
<*> parseJwtAudience "jwt-aud"
<*> (fromMaybe 10 <$> optInt "db-pool")
<*> (fromMaybe 10 <$> optInt "db-pool-timeout")
<*> optInt "max-rows"
<*> optString "pre-request"
<*> (fmap (fmap coerceText) <$> C.subassocs "app.settings" C.value)
<*> (maybe (Right [JSPKey "role"]) parseRoleClaimKey <$> optValue "role-claim-key")
<*> (maybe ["public"] splitOnCommas <$> optValue "db-extra-search-path")
<*> optString "root-spec"
<*> (maybe [] (fmap encodeUtf8 . splitOnCommas) <$> optValue "raw-media-types")
<*> pure Nothing
<*> parseLogLevel "log-level"
<*> parseTxEnd "db-tx-end" fst
<*> parseTxEnd "db-tx-end" snd
<*> (fromMaybe True <$> optBool "db-prepared-statements")
parseSocketFileMode :: C.Key -> C.Parser C.Config (Either Text FileMode) parseSocketFileMode :: C.Key -> C.Parser C.Config (Either Text FileMode)
parseSocketFileMode k = parseSocketFileMode k =
@@ -388,12 +388,24 @@ readAppConfig cfgPath = do
Just "rollback-allow-override" -> pure $ f (True, True) Just "rollback-allow-override" -> pure $ f (True, True)
Just _ -> fail "Invalid transaction termination. Check your configuration." Just _ -> fail "Invalid transaction termination. Check your configuration."
reqWithAlias :: C.Parser C.Config (Maybe a) -> C.Parser C.Config (Maybe a) -> [Char] -> C.Parser C.Config a
reqWithAlias orig alias err =
orig >>= \case
Just v -> pure v
Nothing ->
alias >>= \case
Just v -> pure v
Nothing -> fail err
optWithAlias :: C.Parser C.Config (Maybe a) -> C.Parser C.Config (Maybe a) -> C.Parser C.Config (Maybe a)
optWithAlias orig alias =
orig >>= \case
Just v -> pure $ Just v
Nothing -> alias
reqString :: C.Key -> C.Parser C.Config Text reqString :: C.Key -> C.Parser C.Config Text
reqString k = C.required k C.string reqString k = C.required k C.string
reqValue :: C.Key -> C.Parser C.Config C.Value
reqValue k = C.required k C.value
optString :: C.Key -> C.Parser C.Config (Maybe Text) optString :: C.Key -> C.Parser C.Config (Maybe Text)
optString k = mfilter (/= "") <$> C.optional k C.string optString k = mfilter (/= "") <$> C.optional k C.string
@@ -438,13 +450,13 @@ readValidateConfig :: FilePath -> IO AppConfig
readValidateConfig path = do readValidateConfig path = do
conf <- loadDbUriFile =<< loadSecretFile =<< readAppConfig path conf <- loadDbUriFile =<< loadSecretFile =<< readAppConfig path
-- Checks that the provided proxy uri is formated correctly -- Checks that the provided proxy uri is formated correctly
when (isMalformedProxyUri $ toS <$> configOpenAPIProxyUri conf) $ when (isMalformedProxyUri $ toS <$> configOpenApiServerProxyUri conf) $
panic panic
"Malformed proxy uri, a correct example: https://example.com:8443/basePath" "Malformed proxy uri, a correct example: https://example.com:8443/basePath"
-- Checks that the provided jspath is valid -- Checks that the provided jspath is valid
whenLeft (configRoleClaimKey conf) panic whenLeft (configJwtRoleClaimKey conf) panic
-- Check the file mode is valid -- Check the file mode is valid
whenLeft (configSocketMode conf) panic whenLeft (configServerUnixSocketMode conf) panic
return $ conf { configJWKS = parseSecret <$> configJwtSecret conf} return $ conf { configJWKS = parseSecret <$> configJwtSecret conf}
{-| {-|
+4 -4
View File
@@ -53,14 +53,14 @@ runPgLocals conf claims app req = do
headersSql = setLocalQuery "request.header." <$> iHeaders req headersSql = setLocalQuery "request.header." <$> iHeaders req
cookiesSql = setLocalQuery "request.cookie." <$> iCookies req cookiesSql = setLocalQuery "request.cookie." <$> iCookies req
claimsSql = setLocalQuery "request.jwt.claim." <$> [(c,unquoted v) | (c,v) <- M.toList claimsWithRole] claimsSql = setLocalQuery "request.jwt.claim." <$> [(c,unquoted v) | (c,v) <- M.toList claimsWithRole]
appSettingsSql = setLocalQuery mempty <$> configSettings conf appSettingsSql = setLocalQuery mempty <$> configAppSettings conf
setRoleSql = maybeToList $ (\x -> setRoleSql = maybeToList $ (\x ->
setLocalQuery mempty ("role", unquoted x)) <$> M.lookup "role" claimsWithRole setLocalQuery mempty ("role", unquoted x)) <$> M.lookup "role" claimsWithRole
setSearchPathSql = setLocalSearchPathQuery (iSchema req : configExtraSearchPath conf) setSearchPathSql = setLocalSearchPathQuery (iSchema req : configDbExtraSearchPath conf)
-- role claim defaults to anon if not specified in jwt -- role claim defaults to anon if not specified in jwt
claimsWithRole = M.union claims (M.singleton "role" anon) claimsWithRole = M.union claims (M.singleton "role" anon)
anon = JSON.String . toS $ configAnonRole conf anon = JSON.String . toS $ configDbAnonRole conf
preReq = (\f -> "select " <> toS f <> "();") <$> configPreReq conf preReq = (\f -> "select " <> toS f <> "();") <$> configDbPreRequest conf
-- | Log in apache format. Only requests that have a status greater than minStatus are logged. -- | Log in apache format. Only requests that have a status greater than minStatus are logged.
-- | There's no way to filter logs in the apache format on wai-extra: https://hackage.haskell.org/package/wai-extra-3.0.29.2/docs/Network-Wai-Middleware-RequestLogger.html#t:OutputFormat. -- | There's no way to filter logs in the apache format on wai-extra: https://hackage.haskell.org/package/wai-extra-3.0.29.2/docs/Network-Wai-Middleware-RequestLogger.html#t:OutputFormat.
+2 -2
View File
@@ -63,7 +63,7 @@ main = do
actualPgVersion <- either (panic.show) id <$> P.use pool getPgVersion actualPgVersion <- either (panic.show) id <$> P.use pool getPgVersion
refDbStructure <- (newIORef . Just) =<< setupDbStructure pool (configSchemas $ testCfg testDbConn) (configExtraSearchPath $ testCfg testDbConn) actualPgVersion refDbStructure <- (newIORef . Just) =<< setupDbStructure pool (configDbSchemas $ testCfg testDbConn) (configDbExtraSearchPath $ testCfg testDbConn) actualPgVersion
let let
-- For tests that run with the same refDbStructure -- For tests that run with the same refDbStructure
@@ -73,7 +73,7 @@ main = do
-- For tests that run with a different DbStructure(depends on configSchemas) -- For tests that run with a different DbStructure(depends on configSchemas)
appDbs cfg = do appDbs cfg = do
dbs <- (newIORef . Just) =<< setupDbStructure pool (configSchemas $ cfg testDbConn) (configExtraSearchPath $ cfg testDbConn) actualPgVersion dbs <- (newIORef . Just) =<< setupDbStructure pool (configDbSchemas $ cfg testDbConn) (configDbExtraSearchPath $ cfg testDbConn) actualPgVersion
refConf <- newIORef $ cfg testDbConn refConf <- newIORef $ cfg testDbConn
return ((), postgrest LogCrit refConf dbs pool getTime $ pure ()) return ((), postgrest LogCrit refConf dbs pool getTime $ pure ())
+37 -37
View File
@@ -66,55 +66,55 @@ getEnvVarWithDefault var def = toS <$>
_baseCfg :: AppConfig _baseCfg :: AppConfig
_baseCfg = let secret = Just $ encodeUtf8 "reallyreallyreallyreallyverysafe" in _baseCfg = let secret = Just $ encodeUtf8 "reallyreallyreallyreallyverysafe" in
AppConfig { AppConfig {
configDbUri = mempty configAppSettings = [ ("app.settings.app_host", "localhost") , ("app.settings.external_api_secret", "0123456789abcdef") ]
, configAnonRole = "postgrest_test_anonymous" , configDbAnonRole = "postgrest_test_anonymous"
, configOpenAPIProxyUri = Nothing , configDbChannel = mempty
, configSchemas = fromList ["test"] , configDbChannelEnabled = False
, configHost = "localhost" , configDbExtraSearchPath = []
, configPort = 3000 , configDbMaxRows = Nothing
, configSocket = Nothing , configDbPoolSize = 10
, configSocketMode = Right 432 , configDbPoolTimeout = 10
, configDbChannel = mempty , configDbPreRequest = Just "test.switch_role"
, configDbChannelEnabled = False , configDbPreparedStatements = True
, configJwtSecret = secret , configDbRootSpec = Nothing
, configJwtSecretIsBase64 = False , configDbSchemas = fromList ["test"]
, configJwtAudience = Nothing , configDbUri = mempty
, configPoolSize = 10 , configJWKS = parseSecret <$> secret
, configPoolTimeout = 10 , configJwtAudience = Nothing
, configMaxRows = Nothing , configJwtRoleClaimKey = Right [JSPKey "role"]
, configPreReq = Just "test.switch_role" , configJwtSecret = secret
, configSettings = [ ("app.settings.app_host", "localhost") , ("app.settings.external_api_secret", "0123456789abcdef") ] , configJwtSecretIsBase64 = False
, configRoleClaimKey = Right [JSPKey "role"] , configLogLevel = LogCrit
, configExtraSearchPath = [] , configOpenApiServerProxyUri = Nothing
, configRootSpec = Nothing , configRawMediaTypes = []
, configRawMediaTypes = [] , configServerHost = "localhost"
, configJWKS = parseSecret <$> secret , configServerPort = 3000
, configLogLevel = LogCrit , configServerUnixSocket = Nothing
, configTxRollbackAll = True , configServerUnixSocketMode = Right 432
, configTxAllowOverride = True , configDbTxAllowOverride = True
, configDbPrepared = True , configDbTxRollbackAll = True
} }
testCfg :: Text -> AppConfig testCfg :: Text -> AppConfig
testCfg testDbConn = _baseCfg { configDbUri = testDbConn } testCfg testDbConn = _baseCfg { configDbUri = testDbConn }
testCfgDisallowRollback :: Text -> AppConfig testCfgDisallowRollback :: Text -> AppConfig
testCfgDisallowRollback testDbConn = (testCfg testDbConn) { configTxRollbackAll = False, configTxAllowOverride = False } testCfgDisallowRollback testDbConn = (testCfg testDbConn) { configDbTxAllowOverride = False, configDbTxRollbackAll = False }
testCfgForceRollback :: Text -> AppConfig testCfgForceRollback :: Text -> AppConfig
testCfgForceRollback testDbConn = (testCfg testDbConn) { configTxRollbackAll = True, configTxAllowOverride = False } testCfgForceRollback testDbConn = (testCfg testDbConn) { configDbTxAllowOverride = False, configDbTxRollbackAll = True }
testCfgNoJWT :: Text -> AppConfig testCfgNoJWT :: Text -> AppConfig
testCfgNoJWT testDbConn = (testCfg testDbConn) { configJwtSecret = Nothing, configJWKS = Nothing } testCfgNoJWT testDbConn = (testCfg testDbConn) { configJwtSecret = Nothing, configJWKS = Nothing }
testUnicodeCfg :: Text -> AppConfig testUnicodeCfg :: Text -> AppConfig
testUnicodeCfg testDbConn = (testCfg testDbConn) { configSchemas = fromList ["تست"] } testUnicodeCfg testDbConn = (testCfg testDbConn) { configDbSchemas = fromList ["تست"] }
testMaxRowsCfg :: Text -> AppConfig testMaxRowsCfg :: Text -> AppConfig
testMaxRowsCfg testDbConn = (testCfg testDbConn) { configMaxRows = Just 2 } testMaxRowsCfg testDbConn = (testCfg testDbConn) { configDbMaxRows = Just 2 }
testProxyCfg :: Text -> AppConfig testProxyCfg :: Text -> AppConfig
testProxyCfg testDbConn = (testCfg testDbConn) { configOpenAPIProxyUri = Just "https://postgrest.com/openapi.json" } testProxyCfg testDbConn = (testCfg testDbConn) { configOpenApiServerProxyUri = Just "https://postgrest.com/openapi.json" }
testCfgBinaryJWT :: Text -> AppConfig testCfgBinaryJWT :: Text -> AppConfig
testCfgBinaryJWT testDbConn = testCfgBinaryJWT testDbConn =
@@ -150,22 +150,22 @@ testCfgAsymJWKSet testDbConn =
} }
testNonexistentSchemaCfg :: Text -> AppConfig testNonexistentSchemaCfg :: Text -> AppConfig
testNonexistentSchemaCfg testDbConn = (testCfg testDbConn) { configSchemas = fromList ["nonexistent"] } testNonexistentSchemaCfg testDbConn = (testCfg testDbConn) { configDbSchemas = fromList ["nonexistent"] }
testCfgExtraSearchPath :: Text -> AppConfig testCfgExtraSearchPath :: Text -> AppConfig
testCfgExtraSearchPath testDbConn = (testCfg testDbConn) { configExtraSearchPath = ["public", "extensions"] } testCfgExtraSearchPath testDbConn = (testCfg testDbConn) { configDbExtraSearchPath = ["public", "extensions"] }
testCfgRootSpec :: Text -> AppConfig testCfgRootSpec :: Text -> AppConfig
testCfgRootSpec testDbConn = (testCfg testDbConn) { configRootSpec = Just "root"} testCfgRootSpec testDbConn = (testCfg testDbConn) { configDbRootSpec = Just "root"}
testCfgHtmlRawOutput :: Text -> AppConfig testCfgHtmlRawOutput :: Text -> AppConfig
testCfgHtmlRawOutput testDbConn = (testCfg testDbConn) { configRawMediaTypes = ["text/html"] } testCfgHtmlRawOutput testDbConn = (testCfg testDbConn) { configRawMediaTypes = ["text/html"] }
testCfgResponseHeaders :: Text -> AppConfig testCfgResponseHeaders :: Text -> AppConfig
testCfgResponseHeaders testDbConn = (testCfg testDbConn) { configPreReq = Just "custom_headers" } testCfgResponseHeaders testDbConn = (testCfg testDbConn) { configDbPreRequest = Just "custom_headers" }
testMultipleSchemaCfg :: Text -> AppConfig testMultipleSchemaCfg :: Text -> AppConfig
testMultipleSchemaCfg testDbConn = (testCfg testDbConn) { configSchemas = fromList ["v1", "v2"] } testMultipleSchemaCfg testDbConn = (testCfg testDbConn) { configDbSchemas = fromList ["v1", "v2"] }
resetDb :: Text -> IO () resetDb :: Text -> IO ()
resetDb dbConn = loadFixture dbConn "data" resetDb dbConn = loadFixture dbConn "data"
+4 -4
View File
@@ -316,17 +316,17 @@ checkDbSchemaReload(){
# wait for the server to start # wait for the server to start
sleep 0.1 sleep 0.1
done done
# add v1 schema to db-schema # add v1 schema to db-schemas
replaceConfigValue "db-schema" "test, v1" "$configFile" replaceConfigValue "db-schemas" "test, v1" "$configFile"
# reload # reload
kill -s SIGUSR2 $pgrPID kill -s SIGUSR2 $pgrPID
kill -s SIGUSR1 $pgrPID kill -s SIGUSR1 $pgrPID
httpStatus="$(v1SchemaParentsStatus)" httpStatus="$(v1SchemaParentsStatus)"
if test "$httpStatus" -eq 200 if test "$httpStatus" -eq 200
then then
ok "db-schema config reloaded with SIGUSR2" ok "db-schemas config reloaded with SIGUSR2"
else else
ko "db-schema config not reloaded with SIGUSR2. Got: $httpStatus" ko "db-schemas config not reloaded with SIGUSR2. Got: $httpStatus"
fi fi
pgrStop pgrStop
} }
+9
View File
@@ -0,0 +1,9 @@
db-anon-role = "required"
db-uri = "required"
db-schema = "provided_through_alias"
max-rows = 1000
pre-request = "check_alias"
role-claim-key = ".aliased"
root-spec = "open_alias"
secret-is-base64 = true
+1 -1
View File
@@ -1,5 +1,5 @@
db-uri = "$(POSTGREST_TEST_CONNECTION)" db-uri = "$(POSTGREST_TEST_CONNECTION)"
db-schema = "test" db-schemas = "test"
db-anon-role = "postgrest_test_anonymous" db-anon-role = "postgrest_test_anonymous"
db-pool = 1 db-pool = 1
db-pool-timeout = 1 db-pool-timeout = 1
@@ -1,5 +1,5 @@
db-uri = "$(POSTGREST_TEST_CONNECTION)" db-uri = "$(POSTGREST_TEST_CONNECTION)"
db-schema = "test" db-schemas = "test"
db-anon-role = "postgrest_test_anonymous" db-anon-role = "postgrest_test_anonymous"
db-pool = 1 db-pool = 1
server-host = "127.0.0.1" server-host = "127.0.0.1"
@@ -7,4 +7,4 @@ server-port = 49421
# Read secret from a file: /dev/stdin (alias for standard input) # Read secret from a file: /dev/stdin (alias for standard input)
jwt-secret = "@/dev/stdin" jwt-secret = "@/dev/stdin"
secret-is-base64 = true jwt-secret-is-base64 = true
+1 -1
View File
@@ -1,5 +1,5 @@
db-uri = "@/dev/stdin" db-uri = "@/dev/stdin"
db-schema = "test" db-schemas = "test"
db-anon-role = "postgrest_test_anonymous" db-anon-role = "postgrest_test_anonymous"
db-pool = 1 db-pool = 1
server-host = "127.0.0.1" server-host = "127.0.0.1"
+1 -1
View File
@@ -1,3 +1,3 @@
db-uri = "required" db-uri = "required"
db-schema = "required" db-schemas = "required"
db-anon-role = "required" db-anon-role = "required"
@@ -0,0 +1,24 @@
db-anon-role = "required"
db-channel = "pgrst"
db-channel-enabled = false
db-extra-search-path = "public"
db-max-rows = 1000
db-pool = 10
db-pool-timeout = 10
db-pre-request = "check_alias"
db-prepared-statements = true
db-root-spec = "open_alias"
db-schemas = "provided_through_alias"
db-tx-end = "commit"
db-uri = "required"
jwt-aud = ""
jwt-role-claim-key = ".\"aliased\""
jwt-secret = ""
jwt-secret-is-base64 = true
log-level = "error"
openapi-server-proxy-uri = ""
raw-media-types = ""
server-host = "!4"
server-port = 3000
server-unix-socket = ""
server-unix-socket-mode = "660"
+16 -16
View File
@@ -1,24 +1,24 @@
db-uri = "required"
db-schema = "required"
db-anon-role = "required" db-anon-role = "required"
db-pool = 10
db-pool-timeout = 10
db-extra-search-path = "public"
db-channel = "pgrst" db-channel = "pgrst"
db-channel-enabled = false db-channel-enabled = false
db-tx-end = "commit" db-extra-search-path = "public"
db-max-rows = ""
db-pool = 10
db-pool-timeout = 10
db-pre-request = ""
db-prepared-statements = true db-prepared-statements = true
db-root-spec = ""
db-schemas = "required"
db-tx-end = "commit"
db-uri = "required"
jwt-aud = ""
jwt-role-claim-key = ".\"role\""
jwt-secret = ""
jwt-secret-is-base64 = false
log-level = "error"
openapi-server-proxy-uri = ""
raw-media-types = ""
server-host = "!4" server-host = "!4"
server-port = 3000 server-port = 3000
server-unix-socket = "" server-unix-socket = ""
server-unix-socket-mode = "660" server-unix-socket-mode = "660"
openapi-server-proxy-uri = ""
jwt-secret = ""
jwt-aud = ""
secret-is-base64 = false
role-claim-key = ".\"role\""
max-rows = ""
pre-request = ""
root-spec = ""
raw-media-types = ""
log-level = "error"
@@ -1,26 +1,26 @@
db-uri = "tmp_db"
db-schema = "multi,tenant,setup"
db-anon-role = "root" db-anon-role = "root"
db-pool = 1
db-pool-timeout = 100
db-extra-search-path = "public,test"
db-channel = "postgrest" db-channel = "postgrest"
db-channel-enabled = true db-channel-enabled = true
db-tx-end = "rollback-allow-override" db-extra-search-path = "public,test"
db-max-rows = 1000
db-pool = 1
db-pool-timeout = 100
db-pre-request = "please_run_fast"
db-prepared-statements = false db-prepared-statements = false
db-root-spec = "openapi_v3"
db-schemas = "multi,tenant,setup"
db-tx-end = "rollback-allow-override"
db-uri = "tmp_db"
jwt-aud = "https://postgrest.org"
jwt-role-claim-key = ".\"user\"[0].\"real-role\""
jwt-secret = "c2VjdXJpdHl0aHJvdWdob2JzY3VyaXR5"
jwt-secret-is-base64 = true
log-level = "info"
openapi-server-proxy-uri = "https://postgrest.org"
raw-media-types = "application/vnd.pgrst.config"
server-host = "0.0.0.0" server-host = "0.0.0.0"
server-port = 80 server-port = 80
server-unix-socket = "/tmp/pgrst_io_test.sock" server-unix-socket = "/tmp/pgrst_io_test.sock"
server-unix-socket-mode = "777" server-unix-socket-mode = "777"
openapi-server-proxy-uri = "https://postgrest.org"
jwt-secret = "c2VjdXJpdHl0aHJvdWdob2JzY3VyaXR5"
jwt-aud = "https://postgrest.org"
secret-is-base64 = true
role-claim-key = ".\"user\"[0].\"real-role\""
max-rows = 1000
pre-request = "please_run_fast"
root-spec = "openapi_v3"
raw-media-types = "application/vnd.pgrst.config"
log-level = "info"
app.settings.test = "test" app.settings.test = "test"
app.settings.test2 = "test" app.settings.test2 = "test"
+16 -16
View File
@@ -1,26 +1,26 @@
db-uri = "tmp_db"
db-schema = "multi, tenant,setup"
db-anon-role = "root" db-anon-role = "root"
db-pool = 1
db-pool-timeout = 100
db-extra-search-path = "public, test"
db-channel = "postgrest" db-channel = "postgrest"
db-channel-enabled = true db-channel-enabled = true
db-tx-end = "rollback-allow-override" db-extra-search-path = "public, test"
db-max-rows = 1000
db-pool = 1
db-pool-timeout = 100
db-pre-request = "please_run_fast"
db-prepared-statements = false db-prepared-statements = false
db-root-spec = "openapi_v3"
db-schemas = "multi, tenant,setup"
db-tx-end = "rollback-allow-override"
db-uri = "tmp_db"
jwt-aud = "https://postgrest.org"
jwt-role-claim-key = ".user[0].\"real-role\""
jwt-secret = "c2VjdXJpdHl0aHJvdWdob2JzY3VyaXR5"
jwt-secret-is-base64 = true
log-level = "info"
openapi-server-proxy-uri = "https://postgrest.org"
raw-media-types = "application/vnd.pgrst.config"
server-host = "0.0.0.0" server-host = "0.0.0.0"
server-port = 80 server-port = 80
server-unix-socket = "/tmp/pgrst_io_test.sock" server-unix-socket = "/tmp/pgrst_io_test.sock"
server-unix-socket-mode = "777" server-unix-socket-mode = "777"
openapi-server-proxy-uri = "https://postgrest.org"
jwt-secret = "c2VjdXJpdHl0aHJvdWdob2JzY3VyaXR5"
jwt-aud = "https://postgrest.org"
secret-is-base64 = true
role-claim-key = ".user[0].\"real-role\""
max-rows = 1000
pre-request = "please_run_fast"
root-spec = "openapi_v3"
raw-media-types = "application/vnd.pgrst.config"
log-level = "info"
app.settings.test = "test" app.settings.test = "test"
app.settings.test2 = "test" app.settings.test2 = "test"
+2 -2
View File
@@ -1,8 +1,8 @@
db-uri = "$(POSTGREST_TEST_CONNECTION)" db-uri = "$(POSTGREST_TEST_CONNECTION)"
db-schema = "test" db-schemas = "test"
db-anon-role = "postgrest_test_anonymous" db-anon-role = "postgrest_test_anonymous"
db-pool = 1 db-pool = 1
server-host = "127.0.0.1" server-host = "127.0.0.1"
server-port = 49421 server-port = 49421
role-claim-key = "$(ROLE_CLAIM_KEY)" jwt-role-claim-key = "$(ROLE_CLAIM_KEY)"
jwt-secret = "reallyreallyreallyreallyverysafe" jwt-secret = "reallyreallyreallyreallyverysafe"
@@ -1,5 +1,5 @@
db-uri = "$(POSTGREST_TEST_CONNECTION)" db-uri = "$(POSTGREST_TEST_CONNECTION)"
db-schema = "test" db-schemas = "test"
db-anon-role = "postgrest_test_anonymous" db-anon-role = "postgrest_test_anonymous"
db-pool = 1 db-pool = 1
server-host = "127.0.0.1" server-host = "127.0.0.1"
@@ -7,4 +7,4 @@ server-port = 49421
# Read secret from a file: /dev/stdin (alias for standard input) # Read secret from a file: /dev/stdin (alias for standard input)
jwt-secret = "@/dev/stdin" jwt-secret = "@/dev/stdin"
secret-is-base64 = false jwt-secret-is-base64 = false
@@ -1,5 +1,5 @@
db-uri = "$(POSTGREST_TEST_CONNECTION)" db-uri = "$(POSTGREST_TEST_CONNECTION)"
db-schema = "test" db-schemas = "test"
db-anon-role = "postgrest_test_anonymous" db-anon-role = "postgrest_test_anonymous"
db-pool = 1 db-pool = 1
server-host = "127.0.0.1" server-host = "127.0.0.1"
+1 -1
View File
@@ -1,5 +1,5 @@
db-uri = "$(POSTGREST_TEST_CONNECTION)" db-uri = "$(POSTGREST_TEST_CONNECTION)"
db-schema = "test" db-schemas = "test"
db-anon-role = "postgrest_test_anonymous" db-anon-role = "postgrest_test_anonymous"
db-pool = 1 db-pool = 1
server-host = "127.0.0.1" server-host = "127.0.0.1"
+1 -1
View File
@@ -1,5 +1,5 @@
db-uri = "$(POSTGREST_TEST_CONNECTION)" db-uri = "$(POSTGREST_TEST_CONNECTION)"
db-schema = "test" db-schemas = "test"
db-anon-role = "postgrest_test_anonymous" db-anon-role = "postgrest_test_anonymous"
db-pool = 1 db-pool = 1
server-host = "127.0.0.1" server-host = "127.0.0.1"