check input for empty strings for metadata api (close #2302) (#2300)

This commit is contained in:
Ajeet D'Souza
2019-07-11 09:00:45 +00:00
committed by Shahidh K Muhammed
parent 605f8633f3
commit 92c4cff79e
25 changed files with 297 additions and 84 deletions

View File

@@ -29,10 +29,9 @@ import Hasura.GraphQL.Resolve.Mutation
import Hasura.GraphQL.Resolve.Select
import Hasura.GraphQL.Validate.Field
import Hasura.GraphQL.Validate.Types
import Hasura.RQL.DML.Internal ( dmlTxErrorHandler
, convPartialSQLExp
, sessVarFromCurrentSetting
)
import Hasura.RQL.DML.Internal (convPartialSQLExp,
dmlTxErrorHandler,
sessVarFromCurrentSetting)
import Hasura.RQL.DML.Mutation
import Hasura.RQL.GBoolExp (toSQLBoolExp)
import Hasura.RQL.Types
@@ -115,8 +114,9 @@ traverseInsObj rim (gName, annVal) defVal@(AnnInsObj cols objRels arrRels) =
-- if relational insert input is 'null' then ignore
-- return default value
fmap (fromMaybe defVal) $ forM objM $ \obj -> do
let relName = RelName $ G.unName gName
let relNameM = RelName <$> mkNonEmptyText (G.unName gName)
onConflictM = OMap.lookup "on_conflict" obj
relName <- onNothing relNameM $ throw500 "found empty GName String"
dataVal <- onNothing (OMap.lookup "data" obj) $
throw500 "\"data\" object not found"
relInfo <- onNothing (Map.lookup relName rim) $
@@ -280,7 +280,7 @@ validateInsert insCols objRels addCols = do
forM_ objRels $ \relInfo -> do
let lCols = map fst $ riMapping relInfo
relName = riName relInfo
relNameTxt = getRelTxt relName
relNameTxt = relNameToTxt relName
lColConflicts = lCols `intersect` (addCols <> insCols)
withPathK relNameTxt $ unless (null lColConflicts) $ throwVE $
"cannot insert object relation ship " <> relName
@@ -311,7 +311,7 @@ insertObjRel strfyNum role objRelIns =
RelIns singleObjIns relInfo = objRelIns
multiObjIns = singleToMulti singleObjIns
relName = riName relInfo
relNameTxt = getRelTxt relName
relNameTxt = relNameToTxt relName
mapCols = riMapping relInfo
tn = riRTable relInfo
allCols = _aiTableCols singleObjIns
@@ -352,7 +352,7 @@ insertArrRel strfyNum role resCols arrRelIns =
RelIns multiObjIns relInfo = arrRelIns
colMapping = riMapping relInfo
tn = riRTable relInfo
relNameTxt = getRelTxt $ riName relInfo
relNameTxt = relNameToTxt $ riName relInfo
mutFlds = [("affected_rows", RR.MCount)]
-- | insert an object with object and array relationships

View File

@@ -63,8 +63,7 @@ isValidCol :: PGCol -> Bool
isValidCol = isValidName . G.Name . getPGColTxt
isValidRel :: ToTxt a => RelName -> QualifiedObject a -> Bool
isValidRel rn rt = isValidName (G.Name $ getRelTxt rn)
&& isValidObjectName rt
isValidRel rn rt = isValidName (mkRelName rn) && isValidObjectName rt
isValidField :: FieldInfo -> Bool
isValidField = \case
@@ -114,10 +113,10 @@ mkColName :: PGCol -> G.Name
mkColName (PGCol n) = G.Name n
mkRelName :: RelName -> G.Name
mkRelName (RelName r) = G.Name r
mkRelName rn = G.Name $ relNameToTxt rn
mkAggRelName :: RelName -> G.Name
mkAggRelName (RelName r) = G.Name $ r <> "_aggregate"
mkAggRelName rn = G.Name $ relNameToTxt rn <> "_aggregate"
mkBoolExpName :: QualifiedTable -> G.Name
mkBoolExpName tn =
@@ -225,13 +224,13 @@ mkRelFld allowAgg (RelInfo rn rTy _ remTab isManual) isNullable = case rTy of
ObjRel -> [objRelFld]
where
objRelFld = mkHsraObjFldInfo (Just "An object relationship")
(G.Name $ getRelTxt rn) Map.empty objRelTy
(mkRelName rn) Map.empty objRelTy
objRelTy = bool (G.toGT $ G.toNT relTabTy) (G.toGT relTabTy) isObjRelNullable
isObjRelNullable = isManual || isNullable
relTabTy = mkTableTy remTab
arrRelFld =
mkHsraObjFldInfo (Just "An array relationship") (G.Name $ getRelTxt rn)
mkHsraObjFldInfo (Just "An array relationship") (mkRelName rn)
(fromInpValL $ mkSelArgs remTab) arrRelTy
arrRelTy = G.toGT $ G.toNT $ G.toLT $ G.toNT $ mkTableTy remTab
aggArrRelFld = mkHsraObjFldInfo (Just "An aggregated array relationship")
@@ -533,7 +532,7 @@ mkBoolExpInp tn fields =
Left (PGColInfo colName colTy _) ->
mk (mkColName colName) (mkCompExpTy colTy)
Right (RelInfo relName _ _ remTab _, _, _, _, _) ->
mk (G.Name $ getRelTxt relName) (mkBoolExpTy remTab)
mk (mkRelName relName) (mkBoolExpTy remTab)
mkPGColInp :: PGColInfo -> InpValInfo
mkPGColInp (PGColInfo colName colTy _) =
@@ -937,13 +936,13 @@ mkInsInp tn insCols relInfoMap =
relInps = flip map (Map.toList relInfoMap) $
\(relName, relInfo) ->
let rty = riType relInfo
remoteQT = riRTable relInfo
in case rty of
ObjRel -> InpValInfo Nothing (G.Name $ getRelTxt relName) Nothing $
G.toGT $ mkObjInsInpTy remoteQT
ArrRel -> InpValInfo Nothing (G.Name $ getRelTxt relName) Nothing $
G.toGT $ mkArrInsInpTy remoteQT
let remoteQT = riRTable relInfo
tyMaker = case riType relInfo of
ObjRel -> mkObjInsInpTy
ArrRel -> mkArrInsInpTy
in InpValInfo Nothing (mkRelName relName) Nothing $
G.toGT $ tyMaker remoteQT
{-
@@ -1319,7 +1318,7 @@ mkGCtxRole' tn insPermM selPermM updColsM
mkFld ty = \case
Left ci -> [((ty, mkColName $ pgiName ci), Left ci)]
Right (ri, allowAgg, perm, lim, _) ->
let relFld = ( (ty, G.Name $ getRelTxt $ riName ri)
let relFld = ( (ty, mkRelName $ riName ri)
, Right (ri, False, perm, lim)
)
aggRelFld = ( (ty, mkAggRelName $ riName ri)

View File

@@ -42,7 +42,7 @@ triggerTmplt = case parseGingerTmplt $(FE.embedStringFile "src-rsr/trigger.sql.j
Right tmplt -> Just tmplt
pgIdenTrigger:: Ops -> TriggerName -> T.Text
pgIdenTrigger op trn = pgFmtIden (qualifyTriggerName op trn)
pgIdenTrigger op trn = pgFmtIden . qualifyTriggerName op $ triggerNameToTxt trn
where
qualifyTriggerName op' trn' = "notify_hasura_" <> trn' <> "_" <> T.pack (show op')
@@ -61,7 +61,7 @@ getTriggerSql
-> Maybe T.Text
getTriggerSql op trn qt allCols strfyNum spec =
let globalCtx = HashMap.fromList
[ (T.pack "NAME", trn)
[ (T.pack "NAME", triggerNameToTxt trn)
, (T.pack "QUALIFIED_TRIGGER_NAME", pgIdenTrigger op trn)
, (T.pack "QUALIFIED_TABLE", toSQLTxt qt)
]

View File

@@ -82,9 +82,9 @@ type InsPermDef = PermDef InsPerm
type CreateInsPerm = CreatePerm InsPerm
buildViewName :: QualifiedTable -> RoleName -> PermType -> QualifiedTable
buildViewName (QualifiedObject sn tn) (RoleName rTxt) pt =
buildViewName (QualifiedObject sn tn) rn pt =
QualifiedObject hdbViewsSchema $ TableName
(rTxt <> "__" <> T.pack (show pt) <> "__" <> snTxt <> "__" <> tnTxt)
(roleNameToTxt rn <> "__" <> T.pack (show pt) <> "__" <> snTxt <> "__" <> tnTxt)
where
snTxt = getSchemaTxt sn
tnTxt = getTableTxt tn

View File

@@ -34,7 +34,7 @@ addCollectionP2 (CollectionDef queryList) =
withPathK "queries" $
unless (null duplicateNames) $ throw400 NotSupported $
"found duplicate query names "
<> T.intercalate ", " (map (T.dquote . unQueryName) duplicateNames)
<> T.intercalate ", " (map (T.dquote . unNonEmptyText . unQueryName) duplicateNames)
where
duplicateNames = duplicates $ map _lqName queryList

View File

@@ -133,14 +133,13 @@ checkPermOnCol pt allowedCols pgCol = do
unless (HS.member pgCol allowedCols) $
throw400 PermissionDenied $ permErrMsg roleName
where
permErrMsg (RoleName "admin") =
"no such column exists : " <>> pgCol
permErrMsg roleName =
mconcat
[ "role " <>> roleName
, " does not have permission to "
, permTypeToCode pt <> " column " <>> pgCol
]
permErrMsg roleName
| roleName == adminRole = "no such column exists : " <>> pgCol
| otherwise = mconcat
[ "role " <>> roleName
, " does not have permission to "
, permTypeToCode pt <> " column " <>> pgCol
]
binRHSBuilder
:: PGColType -> Value -> DMLP1 S.SQLExp

View File

@@ -641,7 +641,7 @@ mkAggSelect :: AnnAggSel -> S.Select
mkAggSelect annAggSel =
prefixNumToAliases $ arrNodeToSelect bn extr $ S.BELit True
where
aggSel = AnnRelG (RelName "root") [] annAggSel
aggSel = AnnRelG rootRelName [] annAggSel
ArrNode extr _ bn =
aggSelToArrNode (Iden "root") (FieldName "root") aggSel

View File

@@ -104,7 +104,7 @@ askTabInfoFromTrigger trn = do
let tabInfos = M.elems $ scTables sc
liftMaybe (err400 NotExists errMsg) $ find (isJust.M.lookup trn.tiEventTriggerInfoMap) tabInfos
where
errMsg = "event trigger " <> trn <<> " does not exist"
errMsg = "event trigger " <> triggerNameToTxt trn <<> " does not exist"
askEventTriggerInfo
:: (QErrM m, CacheRM m)
@@ -114,7 +114,7 @@ askEventTriggerInfo trn = do
let etim = tiEventTriggerInfoMap ti
liftMaybe (err400 NotExists errMsg) $ M.lookup trn etim
where
errMsg = "event trigger " <> trn <<> " does not exist"
errMsg = "event trigger " <> triggerNameToTxt trn <<> " does not exist"
askQTemplateInfo
:: (P1C m)

View File

@@ -288,7 +288,7 @@ instance ToJSON AnnBoolExpPartialSQL where
, toJSON (pci, map opExpSToJSON opExps)
)
AVRel ri relBoolExp ->
( getRelTxt $ riName ri
( relNameToTxt $ riName ri
, toJSON (ri, toJSON relBoolExp)
)
opExpSToJSON :: OpExpG PartialSQLExp -> Value

View File

@@ -1,7 +1,9 @@
module Hasura.RQL.Types.Common
( PGColInfo(..)
, RelName(..)
, relNameToTxt
, RelType(..)
, rootRelName
, relTypeToTxt
, RelInfo(..)
@@ -17,6 +19,12 @@ module Hasura.RQL.Types.Common
, ColVals
, MutateResp(..)
, ForeignKey(..)
, NonEmptyText
, mkNonEmptyText
, unNonEmptyText
, adminText
, rootText
) where
import Hasura.Prelude
@@ -25,6 +33,7 @@ import Hasura.SQL.Types
import Data.Aeson
import Data.Aeson.Casing
import Data.Aeson.TH
import Data.Aeson.Types
import qualified Data.HashMap.Strict as HM
import qualified Data.Text as T
import qualified Database.PG.Query as Q
@@ -41,15 +50,49 @@ data PGColInfo
$(deriveJSON (aesonDrop 3 snakeCase) ''PGColInfo)
newtype NonEmptyText = NonEmptyText {unNonEmptyText :: T.Text}
deriving (Show, Eq, Ord, Hashable, ToJSON, ToJSONKey, Lift, Q.ToPrepArg, DQuote)
mkNonEmptyText :: T.Text -> Maybe NonEmptyText
mkNonEmptyText "" = Nothing
mkNonEmptyText text = Just $ NonEmptyText text
parseNonEmptyText :: T.Text -> Parser NonEmptyText
parseNonEmptyText text = case mkNonEmptyText text of
Nothing -> fail "empty string not allowed"
Just neText -> return neText
instance FromJSON NonEmptyText where
parseJSON = withText "String" parseNonEmptyText
instance FromJSONKey NonEmptyText where
fromJSONKey = FromJSONKeyTextParser parseNonEmptyText
instance Q.FromCol NonEmptyText where
fromCol bs = mkNonEmptyText <$> Q.fromCol bs
>>= maybe (Left "empty string not allowed") Right
adminText :: NonEmptyText
adminText = NonEmptyText "admin"
rootText :: NonEmptyText
rootText = NonEmptyText "root"
newtype RelName
= RelName {getRelTxt :: T.Text}
= RelName {getRelTxt :: NonEmptyText}
deriving (Show, Eq, Hashable, FromJSON, ToJSON, Q.ToPrepArg, Q.FromCol, Lift)
instance IsIden RelName where
toIden (RelName r) = Iden r
toIden rn = Iden $ relNameToTxt rn
instance DQuote RelName where
dquoteTxt (RelName r) = r
dquoteTxt = relNameToTxt
rootRelName :: RelName
rootRelName = RelName rootText
relNameToTxt :: RelName -> T.Text
relNameToTxt = unNonEmptyText . getRelTxt
relTypeToTxt :: RelType -> T.Text
relTypeToTxt ObjRel = "object"
@@ -101,18 +144,18 @@ fromPGCol :: PGCol -> FieldName
fromPGCol (PGCol c) = FieldName c
fromRel :: RelName -> FieldName
fromRel (RelName r) = FieldName r
fromRel = FieldName . relNameToTxt
newtype TQueryName
= TQueryName { getTQueryName :: T.Text }
= TQueryName { getTQueryName :: NonEmptyText }
deriving ( Show, Eq, Hashable, FromJSONKey, ToJSONKey
, FromJSON, ToJSON, Q.ToPrepArg, Q.FromCol, Lift)
instance IsIden TQueryName where
toIden (TQueryName r) = Iden r
toIden (TQueryName r) = Iden $ unNonEmptyText r
instance DQuote TQueryName where
dquoteTxt (TQueryName r) = r
dquoteTxt (TQueryName r) = unNonEmptyText r
newtype TemplateParam
= TemplateParam { getTemplateParam :: T.Text }

View File

@@ -2,7 +2,8 @@ module Hasura.RQL.Types.EventTrigger
( CreateEventTriggerQuery(..)
, SubscribeOpSpec(..)
, SubscribeColumns(..)
, TriggerName
, TriggerName(..)
, triggerNameToTxt
, Ops(..)
, EventId
, TriggerOpsDef(..)
@@ -27,15 +28,22 @@ import Data.Aeson.Casing
import Data.Aeson.TH
import Hasura.Prelude
import Hasura.RQL.DDL.Headers
import Hasura.RQL.Types.Common (NonEmptyText (..))
import Hasura.SQL.Types
import Language.Haskell.TH.Syntax (Lift)
import qualified Data.ByteString.Lazy as LBS
import qualified Data.Text as T
import qualified Database.PG.Query as Q
import qualified Text.Regex.TDFA as TDFA
type TriggerName = T.Text
type EventId = T.Text
newtype TriggerName = TriggerName { unTriggerName :: NonEmptyText }
deriving (Show, Eq, Hashable, Lift, FromJSON, ToJSON, ToJSONKey, Q.FromCol, Q.ToPrepArg)
triggerNameToTxt :: TriggerName -> Text
triggerNameToTxt = unNonEmptyText . unTriggerName
type EventId = T.Text
data Ops = INSERT | UPDATE | DELETE | MANUAL deriving (Show)
@@ -106,7 +114,7 @@ $(deriveToJSON (aesonDrop 3 snakeCase){omitNothingFields=True} ''WebhookConfInfo
data CreateEventTriggerQuery
= CreateEventTriggerQuery
{ cetqName :: !T.Text
{ cetqName :: !TriggerName
, cetqTable :: !QualifiedTable
, cetqInsert :: !(Maybe SubscribeOpSpec)
, cetqUpdate :: !(Maybe SubscribeOpSpec)
@@ -134,7 +142,7 @@ instance FromJSON CreateEventTriggerQuery where
replace <- o .:? "replace" .!= False
let regex = "^[A-Za-z]+[A-Za-z0-9_\\-]*$" :: LBS.ByteString
compiledRegex = TDFA.makeRegex regex :: TDFA.Regex
isMatch = TDFA.match compiledRegex (T.unpack name)
isMatch = TDFA.match compiledRegex . T.unpack $ triggerNameToTxt name
if isMatch then return ()
else fail "only alphanumeric and underscore and hyphens allowed for name"
if any isJust [insert, update, delete] || enableManual then
@@ -170,7 +178,7 @@ $(deriveJSON (aesonDrop 2 snakeCase){omitNothingFields=True} ''TriggerOpsDef)
data DeleteEventTriggerQuery
= DeleteEventTriggerQuery
{ detqName :: !T.Text
{ detqName :: !TriggerName
} deriving (Show, Eq, Lift)
$(deriveJSON (aesonDrop 4 snakeCase){omitNothingFields=True} ''DeleteEventTriggerQuery)
@@ -187,16 +195,16 @@ data EventTriggerConf
$(deriveJSON (aesonDrop 3 snakeCase){omitNothingFields=True} ''EventTriggerConf)
data RedeliverEventQuery
newtype RedeliverEventQuery
= RedeliverEventQuery
{ rdeqEventId :: !EventId
{ rdeqEventId :: EventId
} deriving (Show, Eq, Lift)
$(deriveJSON (aesonDrop 4 snakeCase){omitNothingFields=True} ''RedeliverEventQuery)
data InvokeEventTriggerQuery
= InvokeEventTriggerQuery
{ ietqName :: !T.Text
{ ietqName :: !TriggerName
, ietqPayload :: !Value
} deriving (Show, Eq, Lift)

View File

@@ -1,5 +1,6 @@
module Hasura.RQL.Types.Permission
( RoleName(..)
, roleNameToTxt
, SessVar
, SessVarVal
@@ -23,6 +24,8 @@ module Hasura.RQL.Types.Permission
) where
import Hasura.Prelude
import Hasura.RQL.Types.Common (NonEmptyText, adminText, mkNonEmptyText,
unNonEmptyText)
import Hasura.Server.Utils (adminSecretHeader,
deprecatedAccessKeyHeader,
userRoleHeader)
@@ -40,15 +43,18 @@ import qualified Data.Text as T
import qualified PostgreSQL.Binary.Decoding as PD
newtype RoleName
= RoleName {getRoleTxt :: T.Text}
= RoleName {getRoleTxt :: NonEmptyText}
deriving ( Show, Eq, Hashable, FromJSONKey, ToJSONKey, FromJSON
, ToJSON, Q.FromCol, Q.ToPrepArg, Lift)
instance DQuote RoleName where
dquoteTxt (RoleName r) = r
dquoteTxt = roleNameToTxt
roleNameToTxt :: RoleName -> Text
roleNameToTxt = unNonEmptyText . getRoleTxt
adminRole :: RoleName
adminRole = RoleName "admin"
adminRole = RoleName adminText
isAdmin :: RoleName -> Bool
isAdmin = (adminRole ==)
@@ -63,9 +69,10 @@ newtype UserVars
isUserVar :: T.Text -> Bool
isUserVar = T.isPrefixOf "x-hasura-" . T.toLower
-- returns Nothing if x-hasura-role is an empty string
roleFromVars :: UserVars -> Maybe RoleName
roleFromVars =
fmap RoleName . getVarVal userRoleHeader
roleFromVars uv =
getVarVal userRoleHeader uv >>= fmap RoleName . mkNonEmptyText
getVarVal :: SessVar -> UserVars -> Maybe SessVarVal
getVarVal k =
@@ -90,7 +97,7 @@ data UserInfo
mkUserInfo :: RoleName -> UserVars -> UserInfo
mkUserInfo rn (UserVars v) =
UserInfo rn $ UserVars $ Map.insert userRoleHeader (getRoleTxt rn) $
UserInfo rn $ UserVars $ Map.insert userRoleHeader (roleNameToTxt rn) $
foldl (flip Map.delete) v [adminSecretHeader, deprecatedAccessKeyHeader]
instance Hashable UserInfo
@@ -102,7 +109,7 @@ instance Hashable UserInfo
userInfoToList :: UserInfo -> [(Text, Text)]
userInfoToList userInfo =
let vars = Map.toList $ unUserVars . userVars $ userInfo
rn = getRoleTxt . userRole $ userInfo
rn = roleNameToTxt . userRole $ userInfo
in (userRoleHeader, rn) : vars
adminUserInfo :: UserInfo
@@ -162,7 +169,7 @@ instance Show PermId where
show $ mconcat
[ getTableTxt tn
, "."
, getRoleTxt rn
, roleNameToTxt rn
, "."
, T.pack $ show pType
]

View File

@@ -2,6 +2,7 @@ module Hasura.RQL.Types.QueryCollection where
import Hasura.GraphQL.Validate.Types (stripTypenames)
import Hasura.Prelude
import Hasura.RQL.Types.Common (NonEmptyText)
import Hasura.SQL.Types
import Data.Aeson
@@ -15,13 +16,13 @@ import qualified Database.PG.Query as Q
import qualified Language.GraphQL.Draft.Syntax as G
newtype CollectionName
= CollectionName {unCollectionName :: T.Text}
= CollectionName {unCollectionName :: NonEmptyText}
deriving ( Show, Eq, Ord, Hashable, ToJSON, ToJSONKey, Lift
, FromJSON, Q.FromCol, Q.ToPrepArg, DQuote
)
newtype QueryName
= QueryName {unQueryName :: T.Text}
= QueryName {unQueryName :: NonEmptyText}
deriving (Show, Eq, Ord, Hashable, Lift, ToJSON, ToJSONKey, FromJSON, DQuote)
newtype GQLQuery

View File

@@ -1,6 +1,7 @@
module Hasura.RQL.Types.RemoteSchema where
import Hasura.Prelude
import Hasura.RQL.Types.Common (NonEmptyText)
import Language.Haskell.TH.Syntax (Lift)
import System.Environment (lookupEnv)
@@ -19,7 +20,7 @@ type UrlFromEnv = Text
newtype RemoteSchemaName
= RemoteSchemaName
{ unRemoteSchemaName :: Text}
{ unRemoteSchemaName :: NonEmptyText }
deriving ( Show, Eq, Lift, Hashable, J.ToJSON, J.ToJSONKey
, J.FromJSON, Q.ToPrepArg, Q.FromCol, DQuote
)

View File

@@ -36,18 +36,18 @@ reportSchemaObj :: SchemaObjId -> T.Text
reportSchemaObj (SOTable tn) = "table " <> qualObjectToText tn
reportSchemaObj (SOFunction fn) = "function " <> qualObjectToText fn
reportSchemaObj (SOQTemplate qtn) =
"query-template " <> getTQueryName qtn
"query-template " <> unNonEmptyText (getTQueryName qtn)
reportSchemaObj (SOTableObj tn (TOCol cn)) =
"column " <> qualObjectToText tn <> "." <> getPGColTxt cn
reportSchemaObj (SOTableObj tn (TORel cn)) =
"relationship " <> qualObjectToText tn <> "." <> getRelTxt cn
"relationship " <> qualObjectToText tn <> "." <> relNameToTxt cn
reportSchemaObj (SOTableObj tn (TOCons cn)) =
"constraint " <> qualObjectToText tn <> "." <> getConstraintTxt cn
reportSchemaObj (SOTableObj tn (TOPerm rn pt)) =
"permission " <> qualObjectToText tn <> "." <> getRoleTxt rn
"permission " <> qualObjectToText tn <> "." <> roleNameToTxt rn
<> "." <> permTypeToCode pt
reportSchemaObj (SOTableObj tn (TOTrigger trn )) =
"event-trigger " <> qualObjectToText tn <> "." <> trn
"event-trigger " <> qualObjectToText tn <> "." <> triggerNameToTxt trn
instance Show SchemaObjId where
show soi = T.unpack $ reportSchemaObj soi

View File

@@ -585,20 +585,25 @@ httpApp corsCfg serverCtx enableConsole consoleAssetsDir enableTelemetry = do
mkSpockAction encodeQErr id serverCtx $ mkPostHandler $
mkAPIRespHandler gqlExplainHandler
mkTmpltName tmpltText =
onNothing (mkNonEmptyText tmpltText) $ throw400 NotSupported "template name is empty string"
enableGraphQL = isGraphQLEnabled serverCtx
enableMetadata = isMetadataEnabled serverCtx
enablePGDump = isPGDumpEnabled serverCtx
enableConfig = isConfigEnabled serverCtx
tmpltGetOrDeleteH tmpltName = do
tmpltGetOrDeleteH tmpltText = do
tmpltArgs <- tmpltArgsFromQueryParams
mkSpockAction encodeQErr id serverCtx $ mkGetHandler $
mkSpockAction encodeQErr id serverCtx $ mkGetHandler $ do
tmpltName <- mkTmpltName tmpltText
JSONResp <$> mkQTemplateAction tmpltName tmpltArgs
tmpltPutOrPostH tmpltName = do
tmpltPutOrPostH tmpltText = do
tmpltArgs <- tmpltArgsFromQueryParams
mkSpockAction encodeQErr id serverCtx $ mkPostHandler $
mkAPIRespHandler $ \bodyTmpltArgs ->
mkAPIRespHandler $ \bodyTmpltArgs -> do
tmpltName <- mkTmpltName tmpltText
mkQTemplateAction tmpltName $ M.union bodyTmpltArgs tmpltArgs
tmpltArgsFromQueryParams = do

View File

@@ -264,7 +264,7 @@ processAuthZHeader jwtCtx headers authzHeader = do
getCurrentRole defaultRole =
let userRoleHeaderB = CS.cs userRoleHeader
mUserRole = snd <$> find (\h -> fst h == CI.mk userRoleHeaderB) headers
in maybe defaultRole (RoleName . bsToTxt) mUserRole
in maybe defaultRole RoleName $ mUserRole >>= mkNonEmptyText . bsToTxt
decodeJSON val = case A.fromJSON val of
A.Error e -> throw400 JWTInvalidClaims ("x-hasura-* claims: " <> T.pack e)

View File

@@ -21,8 +21,9 @@ import qualified Hasura.Logging as L
import qualified Text.PrettyPrint.ANSI.Leijen as PP
import Hasura.Prelude
import Hasura.RQL.Types (RoleName (..),
SchemaCache (..))
import Hasura.RQL.Types ( RoleName (..)
, SchemaCache (..)
, mkNonEmptyText )
import Hasura.Server.Auth
import Hasura.Server.Cors
import Hasura.Server.Logging
@@ -167,7 +168,9 @@ instance FromEnv AdminSecret where
fromEnv = Right . AdminSecret . T.pack
instance FromEnv RoleName where
fromEnv = Right . RoleName . T.pack
fromEnv string = case mkNonEmptyText (T.pack string) of
Nothing -> Left "empty string not allowed"
Just neText -> Right $ RoleName neText
instance FromEnv Bool where
fromEnv = parseStrAsBool
@@ -817,11 +820,13 @@ jwtSecretHelp = "The JSON containing type and the JWK used for verifying. e.g: "
<> "`{\"type\": \"RS256\", \"key\": \"<your-PEM-RSA-public-key>\", \"claims_namespace\": \"<optional-custom-claims-key-name>\"}`"
parseUnAuthRole :: Parser (Maybe RoleName)
parseUnAuthRole = optional $
RoleName <$> strOption ( long "unauthorized-role" <>
metavar "<ROLE>" <>
help (snd unAuthRoleEnv)
)
parseUnAuthRole = fmap mkRoleName $ optional $
strOption ( long "unauthorized-role" <>
metavar "<ROLE>" <>
help (snd unAuthRoleEnv)
)
where
mkRoleName mText = mText >>= (fmap RoleName . mkNonEmptyText)
parseCorsConfig :: Parser (Maybe CorsConfig)
parseCorsConfig = mapCC <$> disableCors <*> corsDomain

View File

@@ -0,0 +1,31 @@
description: Create event trigger with role ""
url: /v1/query
status: 400
response:
path: $.name
error: >-
empty string not allowed
code: parse-failed
query:
type: create_event_trigger
args:
name: ""
table: users
webhook: https://httpbin.org/post
insert:
columns: "*"
payload:
- username
update:
columns:
- username
- real_name
payload: "*"
delete:
columns: "*"
headers:
- name: X-Hasura-From-Val
value: myvalue
- name: X-Hasura-From-Env
value_from_env: EVENT_WEBHOOK_HEADER
replace: false

View File

@@ -0,0 +1,21 @@
description: Create permission with role ""
url: /v1/query
status: 400
response:
path: $.role
error: >-
empty string not allowed
code: parse-failed
query:
type: create_insert_permission
args:
table: article
role: ""
permission:
check:
author_id: X-HASURA-USER-ID
"$or":
- category: editorial
is_reviewed: false
- category:
"$neq": editorial

View File

@@ -0,0 +1,15 @@
description: Create object relationship with name ""
url: /v1/query
status: 400
response:
path: $.name
error: >-
empty string not allowed
code: parse-failed
query:
type: create_object_relationship
args:
table: article
name: ""
using:
foreign_key_constraint_on: author_id

View File

@@ -0,0 +1,17 @@
description: Create query collection with name ""
url: /v1/query
status: 400
response:
path: $.name
error: >-
empty string not allowed
code: parse-failed
query:
type: create_query_collection
args:
name: ""
comment: an optional comment
definition:
queries:
- name: query_1
query: query { test {id name}}

View File

@@ -0,0 +1,17 @@
description: Create query collection with name ""
url: /v1/query
status: 400
response:
path: $.name
error: >-
empty string not allowed
code: parse-failed
query:
type: create_query_collection
args:
name: ""
comment: an optional comment
definition:
queries:
- name: query_1
query: query { test {id name}}

View File

@@ -0,0 +1,19 @@
description: Create remote schema with name ""
url: /v1/query
status: 400
response:
path: $.name
error: >-
empty string not allowed
code: parse-failed
query:
type: add_remote_schema
args:
name: ""
definition:
url: https://remote-server.com/graphql
headers:
- name: X-Server-Request-From
value: Hasura
forward_client_headers: false
comment: some optional comment

View File

@@ -582,3 +582,28 @@ class TestCreatePermission(DefaultTestQueries):
@classmethod
def dir(cls):
return "queries/v1/permissions"
class TestNonEmptyText:
def test_create_event_trigger(self, hge_ctx):
check_query_f(hge_ctx, self.dir() + '/create_event_trigger.yaml')
def test_create_insert_permission(self, hge_ctx):
check_query_f(hge_ctx, self.dir() + '/create_insert_permission.yaml')
def test_create_query_collection(self, hge_ctx):
check_query_f(hge_ctx, self.dir() + '/create_query_collection.yaml')
def test_create_query_collection_queryname(self, hge_ctx):
check_query_f(hge_ctx, self.dir() + '/create_query_collection_queryname.yaml')
def test_create_object_relationship(self, hge_ctx):
check_query_f(hge_ctx, self.dir() + '/create_object_relationship.yaml')
def test_create_remote_schema(self, hge_ctx):
check_query_f(hge_ctx, self.dir() + '/create_remote_schema.yaml')
@classmethod
def dir(cls):
return "queries/v1/non_empty_text"