From ae8625a7b63ec2b76e401bb8a0e6bdba280b1d0d Mon Sep 17 00:00:00 2001 From: Wolfgang Walther Date: Thu, 27 Oct 2022 10:55:47 +0200 Subject: [PATCH] fix: Stricter query string parsing - no jsonpath in embedding Signed-off-by: Wolfgang Walther --- CHANGELOG.md | 1 + src/PostgREST/ApiRequest/QueryParams.hs | 29 ++++++++++++++++--------- src/PostgREST/ApiRequest/Types.hs | 2 +- src/PostgREST/Plan.hs | 2 +- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8363c468..d5e77f789 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - #2444, Removed `db-pool-timeout` option, because this was removed upstream in hasql-pool. - @robx - #2343, PATCH requests that don't affect any rows no longer return 404 - @wolfgangwalther + - #2537, Stricter parsing of query string. Instead of silently ignoring, the parser now throws on invalid syntax like json paths for embeddings etc. - @wolfgangwalther ### Deprecated diff --git a/src/PostgREST/ApiRequest/QueryParams.hs b/src/PostgREST/ApiRequest/QueryParams.hs index 5a428e141..6d9919843 100644 --- a/src/PostgREST/ApiRequest/QueryParams.hs +++ b/src/PostgREST/ApiRequest/QueryParams.hs @@ -309,10 +309,10 @@ pTreePath = do -- Right [Node {rootLabel = SelectField {selField = ("id",[]), selCast = Nothing, selAlias = Nothing}, subForest = []}] -- -- >>> P.parse pFieldForest "" "client(id)" --- Right [Node {rootLabel = SelectRelation {selField = ("client",[]), selAlias = Nothing, selHint = Nothing, selJoinType = Nothing}, subForest = [Node {rootLabel = SelectField {selField = ("id",[]), selCast = Nothing, selAlias = Nothing}, subForest = []}]}] +-- Right [Node {rootLabel = SelectRelation {selRelation = "client", selAlias = Nothing, selHint = Nothing, selJoinType = Nothing}, subForest = [Node {rootLabel = SelectField {selField = ("id",[]), selCast = Nothing, selAlias = Nothing}, subForest = []}]}] -- -- >>> P.parse pFieldForest "" "*,client(*,nested(*))" --- Right [Node {rootLabel = SelectField {selField = ("*",[]), selCast = Nothing, selAlias = Nothing}, subForest = []},Node {rootLabel = SelectRelation {selField = ("client",[]), selAlias = Nothing, selHint = Nothing, selJoinType = Nothing}, subForest = [Node {rootLabel = SelectField {selField = ("*",[]), selCast = Nothing, selAlias = Nothing}, subForest = []},Node {rootLabel = SelectRelation {selField = ("nested",[]), selAlias = Nothing, selHint = Nothing, selJoinType = Nothing}, subForest = [Node {rootLabel = SelectField {selField = ("*",[]), selCast = Nothing, selAlias = Nothing}, subForest = []}]}]}] +-- Right [Node {rootLabel = SelectField {selField = ("*",[]), selCast = Nothing, selAlias = Nothing}, subForest = []},Node {rootLabel = SelectRelation {selRelation = "client", selAlias = Nothing, selHint = Nothing, selJoinType = Nothing}, subForest = [Node {rootLabel = SelectField {selField = ("*",[]), selCast = Nothing, selAlias = Nothing}, subForest = []},Node {rootLabel = SelectRelation {selRelation = "nested", selAlias = Nothing, selHint = Nothing, selJoinType = Nothing}, subForest = [Node {rootLabel = SelectField {selField = ("*",[]), selCast = Nothing, selAlias = Nothing}, subForest = []}]}]}] pFieldForest :: Parser [Tree SelectItem] pFieldForest = pFieldTree `sepBy1` lexeme (char ',') where @@ -384,29 +384,38 @@ aliasSeparator = char ':' >> notFollowedBy (char ':') -- Parse regular fields in select -- -- >>> P.parse pRelationSelect "" "rel(*)" --- Right (SelectRelation {selField = ("rel",[]), selAlias = Nothing, selHint = Nothing, selJoinType = Nothing}) +-- Right (SelectRelation {selRelation = "rel", selAlias = Nothing, selHint = Nothing, selJoinType = Nothing}) -- -- >>> P.parse pRelationSelect "" "alias:rel(*)" --- Right (SelectRelation {selField = ("rel",[]), selAlias = Just "alias", selHint = Nothing, selJoinType = Nothing}) +-- Right (SelectRelation {selRelation = "rel", selAlias = Just "alias", selHint = Nothing, selJoinType = Nothing}) -- -- >>> P.parse pRelationSelect "" "rel!hint(*)" --- Right (SelectRelation {selField = ("rel",[]), selAlias = Nothing, selHint = Just "hint", selJoinType = Nothing}) +-- Right (SelectRelation {selRelation = "rel", selAlias = Nothing, selHint = Just "hint", selJoinType = Nothing}) -- -- >>> P.parse pRelationSelect "" "rel!inner(*)" --- Right (SelectRelation {selField = ("rel",[]), selAlias = Nothing, selHint = Nothing, selJoinType = Just JTInner}) +-- Right (SelectRelation {selRelation = "rel", selAlias = Nothing, selHint = Nothing, selJoinType = Just JTInner}) -- -- >>> P.parse pRelationSelect "" "rel!hint!inner(*)" --- Right (SelectRelation {selField = ("rel",[]), selAlias = Nothing, selHint = Just "hint", selJoinType = Just JTInner}) +-- Right (SelectRelation {selRelation = "rel", selAlias = Nothing, selHint = Just "hint", selJoinType = Just JTInner}) -- -- >>> P.parse pRelationSelect "" "alias:rel!inner!hint(*)" --- Right (SelectRelation {selField = ("rel",[]), selAlias = Just "alias", selHint = Just "hint", selJoinType = Just JTInner}) +-- Right (SelectRelation {selRelation = "rel", selAlias = Just "alias", selHint = Just "hint", selJoinType = Just JTInner}) +-- +-- >>> P.parse pRelationSelect "" "rel->jsonpath(*)" +-- Left (line 1, column 6): +-- unexpected '>' +-- +-- >>> P.parse pRelationSelect "" "rel->jsonpath!hint(*)" +-- Left (line 1, column 6): +-- unexpected '>' pRelationSelect :: Parser SelectItem pRelationSelect = lexeme $ try ( do alias <- optionMaybe ( try(pFieldName <* aliasSeparator) ) - fld <- pField + name <- pFieldName prm1 <- optionMaybe pEmbedParam prm2 <- optionMaybe pEmbedParam - return $ SelectRelation fld alias (embedParamHint prm1 <|> embedParamHint prm2) (embedParamJoin prm1 <|> embedParamJoin prm2) + try (void $ lookAhead (string "(")) + return $ SelectRelation name alias (embedParamHint prm1 <|> embedParamHint prm2) (embedParamJoin prm1 <|> embedParamJoin prm2) ) where pEmbedParam :: Parser EmbedParam diff --git a/src/PostgREST/ApiRequest/Types.hs b/src/PostgREST/ApiRequest/Types.hs index 5d7e4f3e5..0fbcbe53f 100644 --- a/src/PostgREST/ApiRequest/Types.hs +++ b/src/PostgREST/ApiRequest/Types.hs @@ -46,7 +46,7 @@ data SelectItem , selAlias :: Maybe Alias } | SelectRelation - { selField :: Field + { selRelation :: FieldName , selAlias :: Maybe Alias , selHint :: Maybe Hint , selJoinType :: Maybe JoinType diff --git a/src/PostgREST/Plan.hs b/src/PostgREST/Plan.hs index 4442f3ce5..78241d360 100644 --- a/src/PostgREST/Plan.hs +++ b/src/PostgREST/Plan.hs @@ -113,7 +113,7 @@ initReadRequest qi@QualifiedIdentifier{..} = let nxtDepth = succ depth in Node q $ foldr (treeEntry nxtDepth) - (Node defReadPlan{from=QualifiedIdentifier qiSchema (fst selField), relName=fst selField, relAlias=selAlias, relHint=selHint, relJoinType=selJoinType, depth=nxtDepth} []) + (Node defReadPlan{from=QualifiedIdentifier qiSchema selRelation, relName=selRelation, relAlias=selAlias, relHint=selHint, relJoinType=selJoinType, depth=nxtDepth} []) fldForest:rForest treeEntry _ (Node SelectField{..} _) (Node q rForest) = Node q{select=(selField, selCast, selAlias):select q} rForest