kenhuuu commented on code in PR #3402:
URL: https://github.com/apache/tinkerpop/pull/3402#discussion_r3205017735
##########
gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/GremlinQueryParser.java:
##########
@@ -91,4 +88,94 @@ public static Object parse(final String query, final
GremlinVisitor<Object> visi
throw new GremlinParserException("Failed to interpret Gremlin
query: " + ex.getMessage(), ex);
}
}
+
+ /**
+ * Parses a gremlin-lang map literal string into a {@code Map<String,
Object>} for use as parameters.
+ * <p>
+ * Uses {@link ParameterMapVisitor} to prevent traversal injection and
validates that all keys are strings
+ * and no values contain traversals.
+ *
+ * @param parameterMapString the gremlin-lang map literal string (e.g.
{@code [x:1,y:"marko"]}) or {@code null}/empty
+ * @return the parsed and validated parameter map
+ * @throws GremlinParserException if parsing fails or validation detects
invalid content
+ */
+ public static Map<String, Object> parseParameters(final String
parameterMapString) {
+ if (parameterMapString == null || parameterMapString.isEmpty()) {
+ return Map.of();
+ }
+
+ final GremlinParser parser = createParser(parameterMapString);
+ final GremlinParser.GenericMapLiteralContext mapCtx =
parser.genericMapLiteral();
+
+ final ParameterMapVisitor visitor = new ParameterMapVisitor(new
GremlinAntlrToJava());
+ final Map<Object, Object> rawMap = (Map<Object, Object>)
visitor.visitGenericMapLiteral(mapCtx);
+
+ if (rawMap == null) {
+ return Map.of();
+ }
+
+ for (final Map.Entry<?, ?> entry : rawMap.entrySet()) {
+ if (!(entry.getKey() instanceof String)) {
+ throw new GremlinParserException(
+ String.format("Parameter map keys must be String,
found: %s",
+ entry.getKey() == null ? "null" :
entry.getKey().getClass().getSimpleName()));
+ }
+ final String key = (String) entry.getKey();
+ if (!SourceVersion.isIdentifier(key)) {
+ throw new GremlinParserException(
+ String.format("Parameter map key must be a valid
identifier: %s", key));
+ }
+ validateParameterValue(entry.getValue());
+ }
+
+ return (Map<String, Object>) (Map<?, ?>) rawMap;
+ }
+
+ /**
+ * Recursively validates that a parameter value does not contain a {@link
Traversal}. Nested validation is needed
+ * because steps like mergeV iterate map values, so a Traversal hiding
inside a nested map or collection would still
+ * be dangerous.
+ */
+ private static void validateParameterValue(final Object value) {
+ if (value instanceof Traversal) {
+ throw new GremlinParserException("Traversals are not allowed as
parameter values");
Review Comment:
That's a good point and we might have to relax some of these rules in the
future.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]