mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Ratpack: Better support for Promise API
This commit is contained in:
@@ -29,8 +29,8 @@ private class RatpackHttpSource extends SourceModelCsv {
|
||||
row =
|
||||
["ratpack.handling;", "ratpack.core.handling;"] + "Context;true;parse;" +
|
||||
[
|
||||
"(java.lang.Class);", "(com.google.common.reflect.TypeToken);", "(java.lang.Class,O);",
|
||||
"(com.google.common.reflect.TypeToken,O);", "(ratpack.core.parse.Parse);",
|
||||
"(java.lang.Class);", "(com.google.common.reflect.TypeToken);", "(java.lang.Class,java.lang.Object);",
|
||||
"(com.google.common.reflect.TypeToken,java.lang.Object);", "(ratpack.core.parse.Parse);",
|
||||
"(ratpack.parse.Parse);"
|
||||
] + ";ReturnValue;remote"
|
||||
}
|
||||
|
||||
@@ -15,31 +15,82 @@ private class RatpackPromiseValueMethod extends Method, TaintPreservingCallable
|
||||
override predicate returnsTaintFrom(int arg) { arg = 0 }
|
||||
}
|
||||
|
||||
abstract private class SimpleFluentLambdaMethod extends Method {
|
||||
SimpleFluentLambdaMethod() { getNumberOfParameters() = 1 }
|
||||
abstract private class FluentLambdaMethod extends Method {
|
||||
/**
|
||||
* Holds if this lambda consumes taint from the quaifier when `lambdaArg`
|
||||
* for `methodArg` is tainted.
|
||||
* Eg. `tainted.map(stillTainted -> ..)`
|
||||
*/
|
||||
abstract predicate consumesTaint(int methodArg, int lambdaArg);
|
||||
|
||||
/**
|
||||
* Holds if the lambda passed at the given `arg` position produces taint
|
||||
* that taints the result of this method.
|
||||
* Eg. `var tainted = CompletableFuture.supplyAsync(() -> taint());`
|
||||
*/
|
||||
predicate doesReturnTaint(int arg) { none() }
|
||||
}
|
||||
|
||||
private class RatpackPromiseProviderethod extends Method, FluentLambdaMethod {
|
||||
RatpackPromiseProviderethod() { isStatic() and hasName(["flatten", "sync"]) }
|
||||
|
||||
override predicate consumesTaint(int methodArg, int lambdaArg) { none() }
|
||||
|
||||
override predicate doesReturnTaint(int arg) { arg = 0 }
|
||||
}
|
||||
|
||||
abstract private class SimpleFluentLambdaMethod extends FluentLambdaMethod {
|
||||
override predicate consumesTaint(int methodArg, int lambdaArg) {
|
||||
methodArg = 0 and consumesTaint(lambdaArg)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this lambda consumes taint from the quaifier when `arg` is tainted.
|
||||
* Eg. `tainted.map(stillTainted -> ..)`
|
||||
*/
|
||||
abstract predicate consumesTaint(int arg);
|
||||
|
||||
/**
|
||||
* Holds if the lambda passed produces taint that taints the result of this method.
|
||||
* Eg. `var tainted = CompletableFuture.supplyAsync(() -> taint());`
|
||||
*/
|
||||
predicate doesReturnTaint() { none() }
|
||||
abstract predicate consumesTaint(int lambdaArg);
|
||||
}
|
||||
|
||||
private class RatpackPromiseMapMethod extends SimpleFluentLambdaMethod {
|
||||
RatpackPromiseMapMethod() {
|
||||
getDeclaringType() instanceof RatpackPromise and
|
||||
hasName(["map", "flatMap"])
|
||||
hasName(["map", "flatMap", "blockingMap"])
|
||||
}
|
||||
|
||||
override predicate consumesTaint(int arg) { arg = 0 }
|
||||
override predicate consumesTaint(int lambdaArg) { lambdaArg = 0 }
|
||||
|
||||
override predicate doesReturnTaint() { any() }
|
||||
override predicate doesReturnTaint(int arg) { arg = 0 }
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the `mapIf` and `flatMapIf` method.
|
||||
*
|
||||
* `<O> Promise<O> mapIf(Predicate<T> predicate, Function<T, O> onTrue, Function<T, O> onFalse)`
|
||||
* `<O> Promise<O> flatMapIf(Predicate<T> predicate, Function<T, Promise<O>> onTrue, Function<T, Promise<O>> onFalse)`
|
||||
*/
|
||||
private class RatpackPromiseMapIfMethod extends FluentLambdaMethod {
|
||||
RatpackPromiseMapIfMethod() {
|
||||
getDeclaringType() instanceof RatpackPromise and
|
||||
hasName(["mapIf", "flatMapIf"]) and
|
||||
getNumberOfParameters() = 3
|
||||
}
|
||||
|
||||
override predicate consumesTaint(int methodArg, int lambdaArg) {
|
||||
methodArg = [1, 2, 3] and lambdaArg = 0
|
||||
}
|
||||
|
||||
override predicate doesReturnTaint(int arg) { arg = [1, 2] }
|
||||
}
|
||||
|
||||
private class RatpackPromiseMapErrorMethod extends FluentLambdaMethod {
|
||||
RatpackPromiseMapErrorMethod() {
|
||||
getDeclaringType() instanceof RatpackPromise and
|
||||
hasName(["mapError", "flatMapError"])
|
||||
}
|
||||
|
||||
override predicate consumesTaint(int methodArg, int lambdaArg) { none() }
|
||||
|
||||
override predicate doesReturnTaint(int arg) { arg = getNumberOfParameters() - 1 }
|
||||
}
|
||||
|
||||
private class RatpackPromiseThenMethod extends SimpleFluentLambdaMethod {
|
||||
@@ -48,16 +99,29 @@ private class RatpackPromiseThenMethod extends SimpleFluentLambdaMethod {
|
||||
hasName("then")
|
||||
}
|
||||
|
||||
override predicate consumesTaint(int arg) { arg = 0 }
|
||||
override predicate consumesTaint(int lambdaArg) { lambdaArg = 0 }
|
||||
}
|
||||
|
||||
private class RatpackPromiseNextMethod extends FluentMethod, SimpleFluentLambdaMethod {
|
||||
RatpackPromiseNextMethod() {
|
||||
private class RatpackPromiseFluentMethod extends FluentMethod, FluentLambdaMethod {
|
||||
RatpackPromiseFluentMethod() {
|
||||
getDeclaringType() instanceof RatpackPromise and
|
||||
hasName("next")
|
||||
not isStatic() and
|
||||
exists(ParameterizedType t |
|
||||
t instanceof RatpackPromise and
|
||||
t = getDeclaringType() and
|
||||
t = getReturnType()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate consumesTaint(int arg) { arg = 0 }
|
||||
override predicate consumesTaint(int methodArg, int lambdaArg) {
|
||||
hasName(["next"]) and methodArg = 0 and lambdaArg = 0
|
||||
or
|
||||
hasName(["cacheIf"]) and methodArg = 0 and lambdaArg = 0
|
||||
or
|
||||
hasName(["route"]) and methodArg = [0, 1] and lambdaArg = 0
|
||||
}
|
||||
|
||||
override predicate doesReturnTaint(int arg) { hasName(["flatMapIf"]) and arg = 1 }
|
||||
}
|
||||
|
||||
private class RatpackPromiseTaintPreservingStep extends AdditionalTaintStep {
|
||||
@@ -70,10 +134,13 @@ private class RatpackPromiseTaintPreservingStep extends AdditionalTaintStep {
|
||||
* Holds if the method access qualifier `node1` has dataflow to the functional expression parameter `node2`.
|
||||
*/
|
||||
predicate stepIntoLambda(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(MethodAccess ma, SimpleFluentLambdaMethod sflm, int arg | sflm.consumesTaint(arg) |
|
||||
ma.getMethod() = sflm and
|
||||
exists(MethodAccess ma, FluentLambdaMethod flm, int methodArg, int lambdaArg |
|
||||
flm.consumesTaint(methodArg, lambdaArg)
|
||||
|
|
||||
ma.getMethod() = flm and
|
||||
node1.asExpr() = ma.getQualifier() and
|
||||
ma.getArgument(0).(FunctionalExpr).asMethod().getParameter(arg) = node2.asParameter()
|
||||
ma.getArgument(methodArg).(FunctionalExpr).asMethod().getParameter(lambdaArg) =
|
||||
node2.asParameter()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -82,13 +149,13 @@ private class RatpackPromiseTaintPreservingStep extends AdditionalTaintStep {
|
||||
* method access result `node2`.
|
||||
*/
|
||||
predicate stepOutOfLambda(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
exists(SimpleFluentLambdaMethod sflm, MethodAccess ma, FunctionalExpr fe |
|
||||
sflm.doesReturnTaint()
|
||||
exists(FluentLambdaMethod flm, MethodAccess ma, FunctionalExpr fe, int arg |
|
||||
flm.doesReturnTaint(arg)
|
||||
|
|
||||
fe.asMethod().getBody().getAStmt().(ReturnStmt).getResult() = node1.asExpr() and
|
||||
ma.getMethod() = sflm and
|
||||
ma.getMethod() = flm and
|
||||
node2.asExpr() = ma and
|
||||
ma.getArgument(0) = fe
|
||||
ma.getArgument(arg) = fe
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import ratpack.core.form.Form;
|
||||
import ratpack.core.form.UploadedFile;
|
||||
import ratpack.core.parse.Parse;
|
||||
import ratpack.exec.Promise;
|
||||
import ratpack.func.Action;
|
||||
import java.io.OutputStream;
|
||||
|
||||
class Resource {
|
||||
@@ -100,5 +101,92 @@ class Resource {
|
||||
.then(form -> {
|
||||
sink(form); //$hasTaintFlow
|
||||
});
|
||||
ctx
|
||||
.parse(Form.class, "Some Object")
|
||||
.then(form -> {
|
||||
sink(form); //$hasTaintFlow
|
||||
});
|
||||
}
|
||||
|
||||
void test7() {
|
||||
String tainted = taint();
|
||||
Promise
|
||||
.flatten(() -> Promise.value(tainted))
|
||||
.next(value -> {
|
||||
sink(value); //$hasTaintFlow
|
||||
})
|
||||
.onError(Action.noop())
|
||||
.next(value -> {
|
||||
sink(value); //$hasTaintFlow
|
||||
})
|
||||
.cache()
|
||||
.next(value -> {
|
||||
sink(value); //$hasTaintFlow
|
||||
})
|
||||
.fork()
|
||||
.next(value -> {
|
||||
sink(value); //$hasTaintFlow
|
||||
})
|
||||
.route(value -> {
|
||||
sink(value); //$hasTaintFlow
|
||||
return false;
|
||||
}, value -> {
|
||||
sink(value); //$hasTaintFlow
|
||||
})
|
||||
.next(value -> {
|
||||
sink(value); //$hasTaintFlow
|
||||
})
|
||||
.cacheIf(value -> {
|
||||
sink(value); //$hasTaintFlow
|
||||
return true;
|
||||
})
|
||||
.next(value -> {
|
||||
sink(value); //$hasTaintFlow
|
||||
})
|
||||
.onError(RuntimeException.class, Action.noop())
|
||||
.next(value -> {
|
||||
sink(value); //$hasTaintFlow
|
||||
})
|
||||
.then(value -> {
|
||||
sink(value); //$hasTaintFlow
|
||||
});
|
||||
}
|
||||
|
||||
void test8() {
|
||||
String tainted = taint();
|
||||
Promise
|
||||
.sync(() -> tainted)
|
||||
.mapError(RuntimeException.class, exception -> {
|
||||
sink(exception); // no taint
|
||||
return "potato";
|
||||
})
|
||||
.then(value -> {
|
||||
sink(value); //$hasTaintFlow
|
||||
});
|
||||
Promise
|
||||
.value("potato")
|
||||
.mapError(RuntimeException.class, exception -> {
|
||||
return taint();
|
||||
})
|
||||
.then(value -> {
|
||||
sink(value); //$hasTaintFlow
|
||||
});
|
||||
Promise
|
||||
.value(tainted)
|
||||
.flatMapError(RuntimeException.class, exception -> {
|
||||
sink(exception); // no taint
|
||||
return Promise.value("potato");
|
||||
})
|
||||
.then(value -> {
|
||||
sink(value); //$hasTaintFlow
|
||||
});
|
||||
Promise
|
||||
.value("potato")
|
||||
.flatMapError(RuntimeException.class, exception -> {
|
||||
return Promise.value(taint());
|
||||
})
|
||||
.then(value -> {
|
||||
sink(value); //$hasTaintFlow
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,9 @@
|
||||
package ratpack.exec;
|
||||
|
||||
import ratpack.func.Action;
|
||||
import ratpack.func.Factory;
|
||||
import ratpack.func.Function;
|
||||
import ratpack.func.Predicate;
|
||||
|
||||
/**
|
||||
* A promise for a single value.
|
||||
@@ -43,6 +45,15 @@ import ratpack.func.Function;
|
||||
*/
|
||||
@SuppressWarnings("JavadocReference")
|
||||
public interface Promise<T> {
|
||||
|
||||
static <T> Promise<T> sync(Factory<T> factory) {
|
||||
return null;
|
||||
}
|
||||
|
||||
static <T> Promise<T> flatten(Factory<? extends Promise<T>> factory) {
|
||||
return null;
|
||||
}
|
||||
|
||||
static <T> Promise<T> value(T t) {
|
||||
return null;
|
||||
}
|
||||
@@ -54,4 +65,52 @@ public interface Promise<T> {
|
||||
void then(Action<? super T> then);
|
||||
|
||||
Promise<T> next(Action<? super T> action);
|
||||
|
||||
default <E extends Throwable> Promise<T> onError(Class<E> errorType, Action<? super E> errorHandler) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default Promise<T> onError(Action<? super Throwable> errorHandler) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default Promise<T> mapError(Function<? super Throwable, ? extends T> transformer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default <E extends Throwable> Promise<T> mapError(Class<E> type, Function<? super E, ? extends T> function) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default Promise<T> mapError(Predicate<? super Throwable> predicate, Function<? super Throwable, ? extends T> function) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default Promise<T> flatMapError(Function<? super Throwable, ? extends Promise<T>> function) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default <E extends Throwable> Promise<T> flatMapError(Class<E> type, Function<? super E, ? extends Promise<T>> function) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default Promise<T> flatMapError(Predicate<? super Throwable> predicate, Function<? super Throwable, ? extends Promise<T>> function) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default Promise<T> route(Predicate<? super T> predicate, Action<? super T> action) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default Promise<T> cache() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default Promise<T> cacheIf(Predicate<? super T> shouldCache) {
|
||||
return null;
|
||||
}
|
||||
|
||||
default Promise<T> fork() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
50
java/ql/test/stubs/ratpack-1.9.x/ratpack/func/Factory.java
generated
Normal file
50
java/ql/test/stubs/ratpack-1.9.x/ratpack/func/Factory.java
generated
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package ratpack.func;
|
||||
|
||||
/**
|
||||
* An object that creates another.
|
||||
*
|
||||
* Factories are expected to create a new object each time.
|
||||
* Implementors should explain there behaviour if they do not do this.
|
||||
*
|
||||
* @param <T> the type of object that this factory creates
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface Factory<T> {
|
||||
|
||||
/**
|
||||
* Creates a new object.
|
||||
*
|
||||
* @return a newly created object
|
||||
* @throws Exception any
|
||||
*/
|
||||
T create() throws Exception;
|
||||
|
||||
/**
|
||||
* Creates a factory that always returns the given item.
|
||||
*
|
||||
* @param item the item to always provide
|
||||
* @param <T> the type of the item
|
||||
* @return a factory that always returns {@code item}
|
||||
* @since 1.1
|
||||
*/
|
||||
static <T> Factory<T> constant(T item) {
|
||||
return () -> item;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user