mirror of
https://github.com/github/codeql.git
synced 2026-01-04 18:20:18 +01:00
193 lines
7.0 KiB
Plaintext
193 lines
7.0 KiB
Plaintext
/**
|
|
* Provides classes and predicates for working with JSON schema libraries.
|
|
*/
|
|
|
|
import javascript
|
|
|
|
/**
|
|
* Provides classes and predicates for working with JSON schema libraries.
|
|
*/
|
|
module JsonSchema {
|
|
/** A call that validates an input against a JSON schema. */
|
|
abstract class ValidationCall extends DataFlow::CallNode {
|
|
/** Gets the data flow node whose value is being validated. */
|
|
abstract DataFlow::Node getInput();
|
|
|
|
/**
|
|
* Gets the return value that indicates successful validation, if any.
|
|
*
|
|
* Has no result if the return value from this call does not directly
|
|
* indicate success.
|
|
*/
|
|
boolean getPolarity() { result = true }
|
|
|
|
/**
|
|
* Gets a value that indicates whether the validation was successful.
|
|
*/
|
|
DataFlow::Node getAValidationResultAccess(boolean polarity) {
|
|
result = this and polarity = this.getPolarity()
|
|
}
|
|
}
|
|
|
|
/** A data flow node that is used a JSON schema. */
|
|
abstract class SchemaRoot extends DataFlow::Node { }
|
|
|
|
/** An object literal with a `$schema` property indicating it is the root of a JSON schema. */
|
|
private class SchemaNodeByTag extends SchemaRoot, DataFlow::ObjectLiteralNode {
|
|
SchemaNodeByTag() {
|
|
this.getAPropertyWrite("$schema").getRhs().getStringValue().matches("%//json-schema.org%")
|
|
}
|
|
}
|
|
|
|
/** Gets a data flow node that is part of a JSON schema. */
|
|
private DataFlow::SourceNode getAPartOfJsonSchema(DataFlow::TypeBackTracker t) {
|
|
t.start() and
|
|
result = any(SchemaRoot n).getALocalSource()
|
|
or
|
|
result = getAPartOfJsonSchema(t.continue()).getAPropertySource()
|
|
or
|
|
exists(DataFlow::TypeBackTracker t2 | result = getAPartOfJsonSchema(t2).backtrack(t2, t))
|
|
}
|
|
|
|
/** Gets a data flow node that is part of a JSON schema. */
|
|
DataFlow::SourceNode getAPartOfJsonSchema() {
|
|
result = getAPartOfJsonSchema(DataFlow::TypeBackTracker::end())
|
|
}
|
|
|
|
/** Provides a model of the `ajv` library. */
|
|
module Ajv {
|
|
/** Gets a method on `Ajv` that returns `this`. */
|
|
private string chainedMethod() {
|
|
result =
|
|
["addSchema", "addMetaSchema", "removeSchema", "addFormat", "addKeyword", "removeKeyword"]
|
|
}
|
|
|
|
/** An instance of `ajv`. */
|
|
class Instance extends API::InvokeNode {
|
|
Instance() { this = API::moduleImport("ajv").getAnInstantiation() }
|
|
|
|
/** Gets the data flow node holding the options passed to this `Ajv` instance. */
|
|
DataFlow::Node getOptionsArg() { result = this.getArgument(0) }
|
|
|
|
/** Gets an API node that refers to this object. */
|
|
API::Node ref() {
|
|
result = this.getReturn()
|
|
or
|
|
result = this.ref().getMember(chainedMethod()).getReturn()
|
|
}
|
|
|
|
/**
|
|
* Gets an API node for a function produced by `new Ajv().compile()` or similar.
|
|
*
|
|
* Note that this does not include the instance method `new Ajv().validate` as its
|
|
* signature is different.
|
|
*/
|
|
API::Node getAValidationFunction() {
|
|
result = this.ref().getMember(["compile", "getSchema"]).getReturn()
|
|
or
|
|
result = this.ref().getMember("compileAsync").getPromised()
|
|
}
|
|
|
|
/**
|
|
* Gets an API node that refers to an error produced by this Ajv instance.
|
|
*/
|
|
API::Node getAValidationError() {
|
|
exists(API::Node base | base = [this.ref(), this.getAValidationFunction()] |
|
|
result = base.getMember("errors")
|
|
or
|
|
result = base.getMember("errorsText").getReturn()
|
|
)
|
|
}
|
|
}
|
|
|
|
/** A call to the `validate` method of `ajv`. */
|
|
class AjvValidationCall extends ValidationCall {
|
|
Instance instance;
|
|
int argIndex;
|
|
|
|
AjvValidationCall() {
|
|
this = instance.ref().getMember("validate").getACall() and argIndex = 1
|
|
or
|
|
this = instance.getAValidationFunction().getACall() and argIndex = 0
|
|
}
|
|
|
|
override DataFlow::Node getInput() { result = this.getArgument(argIndex) }
|
|
|
|
/** Gets the argument holding additional options to the call. */
|
|
DataFlow::Node getOwnOptionsArg() { result = this.getArgument(argIndex + 1) }
|
|
|
|
/** Gets a data flow passed as the extra options to this validation call or to the underlying `Ajv` instance. */
|
|
DataFlow::Node getAnOptionsArg() {
|
|
result = this.getOwnOptionsArg()
|
|
or
|
|
result = instance.getOptionsArg()
|
|
}
|
|
|
|
/** Gets the ajv instance doing the validation. */
|
|
Instance getAjvInstance() { result = instance }
|
|
}
|
|
|
|
private class AjvSchemaNode extends SchemaRoot {
|
|
AjvSchemaNode() {
|
|
this =
|
|
any(Instance i)
|
|
.ref()
|
|
.getMember(["addSchema", "validate", "compile", "compileAsync"])
|
|
.getParameter(0)
|
|
.asSink()
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Provides a model for working with the [`joi`](https://npmjs.org/package/joi) library. */
|
|
module Joi {
|
|
/** Gets a schema created using `joi.object()` or other schemas that might refer an object schema. */
|
|
private API::Node objectSchema() {
|
|
// A call that creates a schema that might be an object schema.
|
|
result =
|
|
API::moduleImport("joi")
|
|
.getMember([
|
|
"object", "alternatives", "all", "link", "compile", "allow", "valid", "when",
|
|
"build", "options"
|
|
])
|
|
.getReturn()
|
|
or
|
|
// A call to a schema that returns another schema.
|
|
// Read from the [index.d.ts](https://github.com/sideway/joi/blob/master/lib/index.d.ts) file.
|
|
result =
|
|
objectSchema()
|
|
.getMember([
|
|
// AnySchema
|
|
"allow", "alter", "bind", "cache", "cast", "concat", "default", "description",
|
|
"disallow", "empty", "equal", "error", "example", "exist", "external", "failover",
|
|
"forbidden", "fork", "id", "invalid", "keep", "label", "message", "messages",
|
|
"meta", "not", "note", "only", "optional", "options", "prefs", "preferences",
|
|
"presence", "raw", "required", "rule", "shared", "strict", "strip", "tag", "tailor",
|
|
"unit", "valid", "warn", "warning", "when",
|
|
// ObjectSchema
|
|
"and", "append", "assert", "instance", "keys", "length", "max", "min", "nand", "or",
|
|
"oxor", "pattern", "ref", "regex", "rename", "schema", "unknown", "with", "without",
|
|
"xor"
|
|
])
|
|
.getReturn()
|
|
}
|
|
|
|
/**
|
|
* A call to the `validate` method from the [`joi`](https://npmjs.org/package/joi) library.
|
|
* The `error` property in the result indicates whether the validation was successful.
|
|
*/
|
|
class JoiValidationErrorRead extends ValidationCall, API::CallNode {
|
|
JoiValidationErrorRead() { this = objectSchema().getMember("validate").getACall() }
|
|
|
|
override DataFlow::Node getInput() { result = this.getArgument(0) }
|
|
|
|
override boolean getPolarity() { none() }
|
|
|
|
override DataFlow::Node getAValidationResultAccess(boolean polarity) {
|
|
result = this.getReturn().getMember("error").asSource() and
|
|
polarity = false
|
|
}
|
|
}
|
|
}
|
|
}
|