Merge pull request #379 from smowton/model-revel

Model Revel
This commit is contained in:
Chris Smowton
2020-10-28 09:56:25 +00:00
committed by GitHub
24 changed files with 1497 additions and 5 deletions

View File

@@ -20,7 +20,7 @@ jobs:
echo "Done"
cd $HOME
echo "Downloading CodeQL CLI..."
curl https://github.com/github/codeql-cli-binaries/releases/download/v2.3.0/codeql.zip -L -o codeql.zip
curl https://github.com/github/codeql-cli-binaries/releases/download/v2.3.1/codeql.zip -L -o codeql.zip
echo "Done"
echo "Unpacking CodeQL CLI..."
unzip -q codeql.zip
@@ -65,7 +65,7 @@ jobs:
echo "Done"
cd $HOME
echo "Downloading CodeQL CLI..."
curl https://github.com/github/codeql-cli-binaries/releases/download/v2.2.5/codeql.zip -L -o codeql.zip
curl https://github.com/github/codeql-cli-binaries/releases/download/v2.3.1/codeql.zip -L -o codeql.zip
echo "Done"
echo "Unpacking CodeQL CLI..."
unzip -q codeql.zip
@@ -98,7 +98,7 @@ jobs:
echo "Done"
cd "$HOME"
echo "Downloading CodeQL CLI..."
Invoke-WebRequest -Uri https://github.com/github/codeql-cli-binaries/releases/download/v2.2.5/codeql.zip -OutFile codeql.zip
Invoke-WebRequest -Uri https://github.com/github/codeql-cli-binaries/releases/download/v2.3.1/codeql.zip -OutFile codeql.zip
echo "Done"
echo "Unpacking CodeQL CLI..."
Expand-Archive codeql.zip -DestinationPath $HOME

View File

@@ -0,0 +1,2 @@
lgtm,codescanning
* Added basic support for the Revel web framework.

View File

@@ -40,6 +40,7 @@ import semmle.go.frameworks.Macaron
import semmle.go.frameworks.Mux
import semmle.go.frameworks.NoSQL
import semmle.go.frameworks.Protobuf
import semmle.go.frameworks.Revel
import semmle.go.frameworks.Spew
import semmle.go.frameworks.SQL
import semmle.go.frameworks.Stdlib

View File

@@ -177,8 +177,10 @@ predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
localAdditionalTaintStep(src, sink)
}
abstract class DefaultTaintSanitizer extends DataFlow::Node { }
/**
* Holds if `node` should be a sanitizer in all global taint flow configurations
* but not in local taint.
*/
predicate defaultTaintSanitizer(DataFlow::Node node) { none() }
predicate defaultTaintSanitizer(DataFlow::Node node) { node instanceof DefaultTaintSanitizer }

View File

@@ -0,0 +1,218 @@
/**
* Provides classes for working with untrusted flow sources from the `github.com/revel/revel` package.
*/
import go
private import semmle.go.security.OpenUrlRedirectCustomizations
module Revel {
/** Gets the package name. */
bindingset[result]
string packagePath() { result = package(["github.com/revel", "github.com/robfig"], "revel") }
private class ControllerParams extends UntrustedFlowSource::Range, DataFlow::FieldReadNode {
ControllerParams() {
exists(Field f |
this.readsField(_, f) and
f.hasQualifiedName(packagePath(), "Controller", "Params")
)
}
}
private class ParamsFixedSanitizer extends TaintTracking::DefaultTaintSanitizer,
DataFlow::FieldReadNode {
ParamsFixedSanitizer() {
exists(Field f |
this.readsField(_, f) and
f.hasQualifiedName(packagePath(), "Params", "Fixed")
)
}
}
private class ParamsBind extends TaintTracking::FunctionModel, Method {
ParamsBind() { this.hasQualifiedName(packagePath(), "Params", ["Bind", "BindJSON"]) }
override predicate hasTaintFlow(FunctionInput inp, FunctionOutput outp) {
inp.isReceiver() and outp.isParameter(0)
}
}
private class RouteMatchParams extends UntrustedFlowSource::Range, DataFlow::FieldReadNode {
RouteMatchParams() {
exists(Field f |
this.readsField(_, f) and
f.hasQualifiedName(packagePath(), "RouteMatch", "Params")
)
}
}
/** An access to an HTTP request field whose value may be controlled by an untrusted user. */
private class UserControlledRequestField extends UntrustedFlowSource::Range,
DataFlow::FieldReadNode {
UserControlledRequestField() {
exists(string fieldName |
this.getField().hasQualifiedName(packagePath(), "Request", fieldName)
|
fieldName in ["Header", "ContentType", "AcceptLanguages", "Locale", "URL", "Form",
"MultipartForm"]
)
}
}
private class UserControlledRequestMethod extends UntrustedFlowSource::Range,
DataFlow::MethodCallNode {
UserControlledRequestMethod() {
this
.getTarget()
.hasQualifiedName(packagePath(), "Request",
["FormValue", "PostFormValue", "GetQuery", "GetForm", "GetMultipartForm", "GetBody",
"Cookie", "GetHttpHeader", "GetRequestURI", "MultipartReader", "Referer",
"UserAgent"])
}
}
private class ServerCookieGetValue extends TaintTracking::FunctionModel, Method {
ServerCookieGetValue() { this.hasQualifiedName(packagePath(), "ServerCookie", "GetValue") }
override predicate hasTaintFlow(FunctionInput inp, FunctionOutput outp) {
inp.isReceiver() and outp.isResult()
}
}
private class ServerMultipartFormGetFiles extends TaintTracking::FunctionModel, Method {
ServerMultipartFormGetFiles() {
this.hasQualifiedName(packagePath(), "ServerMultipartForm", ["GetFiles", "GetValues"])
}
override predicate hasTaintFlow(FunctionInput inp, FunctionOutput outp) {
inp.isReceiver() and outp.isResult()
}
}
private string contentTypeFromFilename(DataFlow::Node filename) {
if filename.getStringValue().toLowerCase().matches(["%.htm", "%.html"])
then result = "text/html"
else result = "application/octet-stream"
// Actually Revel can figure out a variety of other content-types, but none of our analyses care to
// distinguish ones other than text/html.
}
/**
* `revel.Controller` methods which set the response content-type to and designate a result in one operation.
*
* Note these don't actually generate the response, they return a struct which is then returned by the controller
* method, but it is very likely if a string is being rendered that it will end up sent to the user.
*
* The `Render` and `RenderTemplate` methods are excluded for now because both execute HTML templates, and deciding
* whether a particular value is exposed unescaped or not requires parsing the template.
*
* The `RenderError` method can actually return HTML content, but again only via an HTML template if one exists;
* we assume it falls back to return plain text as this implies there is probably not an injection opportunity
* but there is an information leakage issue.
*
* The `RenderBinary` method can also return a variety of content-types based on the file extension passed.
* We look particularly for html file extensions, since these are the only ones we currently have special rules
* for (in particular, detecting XSS vulnerabilities).
*/
private class ControllerRenderMethods extends HTTP::ResponseBody::Range {
string contentType;
ControllerRenderMethods() {
exists(Method m, string methodName, DataFlow::CallNode methodCall |
m.hasQualifiedName(packagePath(), "Controller", methodName) and
methodCall = m.getACall()
|
exists(int exposedArgument |
this = methodCall.getArgument(exposedArgument) and
(
methodName = "RenderBinary" and
contentType = contentTypeFromFilename(methodCall.getArgument(1)) and
exposedArgument = 0
or
methodName = "RenderError" and contentType = "text/plain" and exposedArgument = 0
or
methodName = "RenderHTML" and contentType = "text/html" and exposedArgument = 0
or
methodName = "RenderJSON" and contentType = "application/json" and exposedArgument = 0
or
methodName = "RenderJSONP" and
contentType = "application/javascript" and
exposedArgument = 1
or
methodName = "RenderXML" and contentType = "text/xml" and exposedArgument = 0
)
)
or
methodName = "RenderText" and
contentType = "text/plain" and
this = methodCall.getAnArgument()
)
}
override HTTP::ResponseWriter getResponseWriter() { none() }
override string getAContentType() { result = contentType }
}
/**
* The `revel.Controller.RenderFileName` method, which instructs Revel to open a file and return its contents.
* We extend FileSystemAccess rather than HTTP::ResponseBody as this will usually mean exposing a user-controlled
* file rather than the actual contents being user-controlled.
*/
private class RenderFileNameCall extends FileSystemAccess::Range, DataFlow::CallNode {
RenderFileNameCall() {
this =
any(Method m | m.hasQualifiedName(packagePath(), "Controller", "RenderFileName")).getACall()
}
override DataFlow::Node getAPathArgument() { result = getArgument(0) }
}
/**
* The `revel.Controller.Redirect` method.
*
* It is currently assumed that a tainted `value` in `Redirect(url, value)`, which calls `Sprintf(url, value)`
* internally, cannot lead to an open redirect vulnerability.
*/
private class ControllerRedirectMethod extends HTTP::Redirect::Range, DataFlow::CallNode {
ControllerRedirectMethod() {
exists(Method m | m.hasQualifiedName(packagePath(), "Controller", "Redirect") |
this = m.getACall()
)
}
override DataFlow::Node getUrl() { result = this.getArgument(0) }
override HTTP::ResponseWriter getResponseWriter() { none() }
}
/**
* The getter and setter methods of `revel.RevelHeader`.
*
* Note we currently don't implement `HeaderWrite` and related concepts, as they are currently only used
* to track content-type, and directly setting headers does not seem to be the usual way to set the response
* content-type for this framework. If and when the `HeaderWrite` concept has a more abstract idea of the
* relationship between header-writes and HTTP responses than looking for a particular `http.ResponseWriter`
* instance connecting the two, then we may implement it here for completeness.
*/
private class RevelHeaderMethods extends TaintTracking::FunctionModel {
FunctionInput input;
FunctionOutput output;
string name;
RevelHeaderMethods() {
this.(Method).hasQualifiedName(packagePath(), "RevelHeader", name) and
(
name = ["Add", "Set"] and input.isParameter([0, 1]) and output.isReceiver()
or
name = ["Get", "GetAll"] and input.isReceiver() and output.isResult()
or
name = "SetCookie" and input.isParameter(0) and output.isReceiver()
)
}
override predicate hasTaintFlow(FunctionInput inp, FunctionOutput outp) {
inp = input and outp = output
}
}
}

View File

@@ -271,4 +271,28 @@ module WebSocketReader {
override FunctionOutput getAnOutput() { result.isResult(1) }
}
/**
* The `ServerWebSocket.MessageReceive` method of the `github.com/revel/revel` package.
*/
private class RevelServerWebSocketMessageReceive extends Range, Method {
RevelServerWebSocketMessageReceive() {
// func MessageReceive(v interface{}) error
this.hasQualifiedName(Revel::packagePath(), "ServerWebSocket", "MessageReceive")
}
override FunctionOutput getAnOutput() { result.isParameter(0) }
}
/**
* The `ServerWebSocket.MessageReceiveJSON` method of the `github.com/revel/revel` package.
*/
private class RevelServerWebSocketMessageReceiveJSON extends Range, Method {
RevelServerWebSocketMessageReceiveJSON() {
// func MessageReceiveJSON(v interface{}) error
this.hasQualifiedName(Revel::packagePath(), "ServerWebSocket", "MessageReceiveJSON")
}
override FunctionOutput getAnOutput() { result.isParameter(0) }
}
}

View File

@@ -33,6 +33,9 @@ module OpenUrlRedirect {
// taint steps that do not include flow through fields
TaintTracking::localTaintStep(pred, succ) and not TaintTracking::fieldReadStep(pred, succ)
or
// explicit extra taint steps for this query
any(AdditionalStep s).hasTaintStep(pred, succ)
or
// propagate to a URL when its host is assigned to
exists(Write w, Field f, SsaWithFields v | f.hasQualifiedName("net/url", "URL", "Host") |
w.writesField(v.getAUse(), f, pred) and succ = v.getAUse()

View File

@@ -34,6 +34,14 @@ module OpenUrlRedirect {
*/
abstract class BarrierGuard extends DataFlow::BarrierGuard { }
/**
* An additional taint propagation step specific to this query.
*/
bindingset[this]
abstract class AdditionalStep extends string {
abstract predicate hasTaintStep(DataFlow::Node pred, DataFlow::Node succ);
}
/**
* A source of third-party user input, considered as a flow source for URL redirects.
*/
@@ -120,3 +128,20 @@ private class UnsafeFieldReadSanitizer extends SafeUrlFlow::SanitizerEdge {
)
}
}
/**
* Reinstate the usual field propagation rules for fields, which the OpenURLRedirect
* query usually excludes, for fields of `Params` other than `Params.Fixed`.
*/
private class PropagateParamsFields extends OpenUrlRedirect::AdditionalStep {
PropagateParamsFields() { this = "PropagateParamsFields" }
override predicate hasTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
exists(Field f, string field |
f.hasQualifiedName(Revel::packagePath(), "Params", field) and
field != "Fixed"
|
succ.(Read).readsField(pred, f)
)
}
}

View File

@@ -56,6 +56,8 @@ module ReflectedXss {
private predicate nonHtmlContentType(HTTP::ResponseBody body) {
not htmlTypeSpecified(body) and
(
exists(body.getAContentType())
or
exists(body.getAContentTypeNode())
or
exists(DataFlow::CallNode call | call.getTarget().hasQualifiedName("fmt", "Fprintf") |

View File

@@ -1,4 +1,3 @@
import go
import semmle.go.frameworks.Gin
select any(UntrustedFlowSource src)

View File

@@ -0,0 +1,95 @@
package main
import (
"bytes"
"errors"
staticControllers "github.com/revel/modules/static/app/controllers"
"github.com/revel/revel"
"os"
"time"
)
// Use typical inheritence pattern, per github.com/revel/examples/booking:
// Doesn't really matter which controller is used here since it'll be stubbed--
// the important thing is we're inheriting a controller from a Revel module, which
// itself implements revel.Controller.
type MyApplication struct {
staticControllers.Static
}
// ...then it's common for files to inherit the whole-appliction controller.
type MyRoute struct {
MyApplication
}
// Implement some request handlers on that Controller exhibiting some common problems:
func (c MyRoute) Handler1() revel.Result {
// GOOD: the Render function is likely to properly escape the user-controlled parameter.
return c.Render("someviewparam", c.Params.Form.Get("someField"))
}
func (c MyRoute) Handler2() revel.Result {
// BAD: the RenderBinary function copies an `io.Reader` to the user's browser.
buf := &bytes.Buffer{}
buf.WriteString(c.Params.Form.Get("someField"))
return c.RenderBinary(buf, "index.html", revel.Inline, time.Now())
}
func (c MyRoute) Handler3() revel.Result {
// GOOD: the RenderBinary function copies an `io.Reader` to the user's browser, but the filename
// means it will be given a safe content-type.
buf := &bytes.Buffer{}
buf.WriteString(c.Params.Form.Get("someField"))
return c.RenderBinary(buf, "index.txt", revel.Inline, time.Now())
}
func (c MyRoute) Handler4() revel.Result {
// GOOD: the RenderError function either uses an HTML template with probable escaping,
// or it uses content-type text/plain.
err := errors.New(c.Params.Form.Get("someField"))
return c.RenderError(err)
}
func (c MyRoute) Handler5() revel.Result {
// BAD: returning an arbitrary file (but this is detected at the os.Open call, not
// due to modelling Revel)
f, _ := os.Open(c.Params.Form.Get("someField"))
return c.RenderFile(f, revel.Inline)
}
func (c MyRoute) Handler6() revel.Result {
// BAD: returning an arbitrary file (detected as a user-controlled file-op, not XSS)
return c.RenderFileName(c.Params.Form.Get("someField"), revel.Inline)
}
func (c MyRoute) Handler7() revel.Result {
// BAD: straightforward XSS
return c.RenderHTML(c.Params.Form.Get("someField"))
}
func (c MyRoute) Handler8() revel.Result {
// GOOD: uses JSON content-type
return c.RenderJSON(c.Params.Form.Get("someField"))
}
func (c MyRoute) Handler9() revel.Result {
// GOOD: uses Javascript content-type
return c.RenderJSONP("callback", c.Params.Form.Get("someField"))
}
func (c MyRoute) Handler10() revel.Result {
// GOOD: uses text content-type
return c.RenderText(c.Params.Form.Get("someField"))
}
func (c MyRoute) Handler11() revel.Result {
// GOOD: uses xml content-type
return c.RenderXML(c.Params.Form.Get("someField"))
}
func (c MyRoute) Handler12() revel.Result {
// BAD: open redirect
return c.Redirect(c.Params.Form.Get("someField"))
}

View File

@@ -0,0 +1,13 @@
edges
| EndToEnd.go:94:20:94:27 | implicit dereference : Params | EndToEnd.go:94:20:94:27 | implicit dereference : Params |
| EndToEnd.go:94:20:94:27 | implicit dereference : Params | EndToEnd.go:94:20:94:27 | selection of Params : pointer type |
| EndToEnd.go:94:20:94:27 | implicit dereference : Params | EndToEnd.go:94:20:94:49 | call to Get |
| EndToEnd.go:94:20:94:27 | selection of Params : pointer type | EndToEnd.go:94:20:94:27 | implicit dereference : Params |
| EndToEnd.go:94:20:94:27 | selection of Params : pointer type | EndToEnd.go:94:20:94:27 | selection of Params : pointer type |
| EndToEnd.go:94:20:94:27 | selection of Params : pointer type | EndToEnd.go:94:20:94:49 | call to Get |
nodes
| EndToEnd.go:94:20:94:27 | implicit dereference : Params | semmle.label | implicit dereference : Params |
| EndToEnd.go:94:20:94:27 | selection of Params : pointer type | semmle.label | selection of Params : pointer type |
| EndToEnd.go:94:20:94:49 | call to Get | semmle.label | call to Get |
#select
| EndToEnd.go:94:20:94:49 | call to Get | EndToEnd.go:94:20:94:27 | selection of Params : pointer type | EndToEnd.go:94:20:94:49 | call to Get | Untrusted URL redirection due to $@. | EndToEnd.go:94:20:94:27 | selection of Params | user-provided value |

View File

@@ -0,0 +1 @@
Security/CWE-601/OpenUrlRedirect.ql

View File

@@ -0,0 +1,23 @@
edges
| EndToEnd.go:36:18:36:25 | implicit dereference : Params | EndToEnd.go:36:18:36:25 | implicit dereference : Params |
| EndToEnd.go:36:18:36:25 | implicit dereference : Params | EndToEnd.go:36:18:36:25 | selection of Params : pointer type |
| EndToEnd.go:36:18:36:25 | implicit dereference : Params | EndToEnd.go:37:24:37:26 | buf |
| EndToEnd.go:36:18:36:25 | selection of Params : pointer type | EndToEnd.go:36:18:36:25 | implicit dereference : Params |
| EndToEnd.go:36:18:36:25 | selection of Params : pointer type | EndToEnd.go:36:18:36:25 | selection of Params : pointer type |
| EndToEnd.go:36:18:36:25 | selection of Params : pointer type | EndToEnd.go:37:24:37:26 | buf |
| EndToEnd.go:69:22:69:29 | implicit dereference : Params | EndToEnd.go:69:22:69:29 | implicit dereference : Params |
| EndToEnd.go:69:22:69:29 | implicit dereference : Params | EndToEnd.go:69:22:69:29 | selection of Params : pointer type |
| EndToEnd.go:69:22:69:29 | implicit dereference : Params | EndToEnd.go:69:22:69:51 | call to Get |
| EndToEnd.go:69:22:69:29 | selection of Params : pointer type | EndToEnd.go:69:22:69:29 | implicit dereference : Params |
| EndToEnd.go:69:22:69:29 | selection of Params : pointer type | EndToEnd.go:69:22:69:29 | selection of Params : pointer type |
| EndToEnd.go:69:22:69:29 | selection of Params : pointer type | EndToEnd.go:69:22:69:51 | call to Get |
nodes
| EndToEnd.go:36:18:36:25 | implicit dereference : Params | semmle.label | implicit dereference : Params |
| EndToEnd.go:36:18:36:25 | selection of Params : pointer type | semmle.label | selection of Params : pointer type |
| EndToEnd.go:37:24:37:26 | buf | semmle.label | buf |
| EndToEnd.go:69:22:69:29 | implicit dereference : Params | semmle.label | implicit dereference : Params |
| EndToEnd.go:69:22:69:29 | selection of Params : pointer type | semmle.label | selection of Params : pointer type |
| EndToEnd.go:69:22:69:51 | call to Get | semmle.label | call to Get |
#select
| EndToEnd.go:37:24:37:26 | buf | EndToEnd.go:36:18:36:25 | selection of Params : pointer type | EndToEnd.go:37:24:37:26 | buf | Cross-site scripting vulnerability due to $@. | EndToEnd.go:36:18:36:25 | selection of Params | user-provided value |
| EndToEnd.go:69:22:69:51 | call to Get | EndToEnd.go:69:22:69:29 | selection of Params : pointer type | EndToEnd.go:69:22:69:51 | call to Get | Cross-site scripting vulnerability due to $@. | EndToEnd.go:69:22:69:29 | selection of Params | user-provided value |

View File

@@ -0,0 +1 @@
Security/CWE-079/ReflectedXss.ql

View File

@@ -0,0 +1,136 @@
package main
//go:generate depstubber -vendor github.com/revel/revel Controller,Params,Request,Router HTTP_QUERY
import (
"io/ioutil"
"mime/multipart"
"net/url"
"github.com/revel/revel"
)
func main() {}
type myAppController struct {
*revel.Controller
OtherStuff string
}
type person struct {
Name string `form:"name"`
Address string `form:"address"`
}
func useString(val string) {}
func useFiles(val *multipart.FileHeader) {}
func useJSON(val []byte) {}
func useURLValues(v url.Values) {
useString(v["key"][0])
useString(v.Get("key"))
}
func usePerson(p person) {}
func (c myAppController) accessingParamsDirectlyIsUnsafe() {
useString(c.Params.Get("key")) // NOT OK
useURLValues(c.Params.Values) // NOT OK
val4 := ""
c.Params.Bind(&val4, "key") // NOT OK
useString(val4)
useString(c.Request.FormValue("key")) // NOT OK
}
func (c myAppController) accessingFixedIsSafe(mainRouter *revel.Router) {
useURLValues(c.Params.Fixed) // OK
useString(mainRouter.Route(c.Request).FixedParams[0]) // OK
}
func (c myAppController) accessingRouteIsUnsafe(mainRouter *revel.Router) {
useURLValues(c.Params.Route) // NOT OK
useURLValues(mainRouter.Route(c.Request).Params) // NOT OK
}
func (c myAppController) accessingParamsQueryIsUnsafe() {
useURLValues(c.Params.Query) // NOT OK
}
func (c myAppController) accessingParamsFormIsUnsafe() {
useURLValues(c.Params.Form) // NOT OK
useString(c.Request.PostFormValue("key")) // NOT OK
}
func (c myAppController) accessingParamsFilesIsUnsafe() {
useFiles(c.Params.Files["key"][0]) // NOT OK
}
func (c myAppController) accessingParamsJSONIsUnsafe() {
useJSON(c.Params.JSON) // NOT OK
var val2 map[string]interface{}
c.Params.BindJSON(&val2) // NOT OK
useString(val2["name"].(string))
}
func accessingRequestDirectlyIsUnsafe(c *revel.Controller) {
useURLValues(c.Request.GetQuery()) // NOT OK
useURLValues(c.Request.Form) // NOT OK
useURLValues(c.Request.MultipartForm.Value) // NOT OK
useString(c.Request.ContentType) // NOT OK
useString(c.Request.AcceptLanguages[0].Language) // NOT OK
useString(c.Request.Locale) // NOT OK
form, _ := c.Request.GetForm() // NOT OK
useURLValues(form)
smp1, _ := c.Request.GetMultipartForm() // NOT OK
useURLValues(smp1.GetValues())
smp2, _ := c.Request.GetMultipartForm() // NOT OK
useFiles(smp2.GetFiles()["key"][0])
useFiles(c.Request.MultipartForm.File["key"][0]) // NOT OK
json, _ := ioutil.ReadAll(c.Request.GetBody()) // NOT OK
useJSON(json)
cookie, _ := c.Request.Cookie("abc")
useString(cookie.GetValue()) // NOT OK
useString(c.Request.GetHttpHeader("headername")) // NOT OK
useString(c.Request.GetRequestURI()) // NOT OK
reader, _ := c.Request.MultipartReader()
part, _ := reader.NextPart()
partbody := make([]byte, 100)
part.Read(partbody)
useString(string(partbody)) // NOT OK
useString(c.Request.Referer()) // NOT OK
useString(c.Request.UserAgent()) // NOT OK
}
func accessingServerRequest(c *revel.Controller) {
var message string
c.Request.WebSocket.MessageReceive(&message) // NOT OK
useString(message)
var p person
c.Request.WebSocket.MessageReceiveJSON(&p) // NOT OK
usePerson(p)
}
func accessingHeaders(c *revel.Controller) {
tainted := c.Request.Header.Get("somekey") // NOT OK
useString(tainted)
tainted2 := c.Request.Header.GetAll("somekey") // NOT OK
useString(tainted2[0])
}

View File

@@ -0,0 +1,43 @@
| Revel.go:39:12:39:19 | selection of Params : pointer type | Revel.go:39:12:39:30 | call to Get | 39 |
| Revel.go:40:15:40:22 | selection of Params : pointer type | Revel.go:32:12:32:22 | index expression | 40 |
| Revel.go:40:15:40:22 | selection of Params : pointer type | Revel.go:33:12:33:23 | call to Get | 40 |
| Revel.go:43:2:43:9 | selection of Params : pointer type | Revel.go:44:12:44:15 | val4 | 43 |
| Revel.go:46:12:46:37 | call to FormValue | Revel.go:46:12:46:37 | call to FormValue | 46 |
| Revel.go:55:15:55:22 | selection of Params : pointer type | Revel.go:32:12:32:22 | index expression | 55 |
| Revel.go:55:15:55:22 | selection of Params : pointer type | Revel.go:33:12:33:23 | call to Get | 55 |
| Revel.go:56:15:56:48 | selection of Params : map type | Revel.go:32:12:32:22 | index expression | 56 |
| Revel.go:56:15:56:48 | selection of Params : map type | Revel.go:33:12:33:23 | call to Get | 56 |
| Revel.go:60:15:60:22 | selection of Params : pointer type | Revel.go:32:12:32:22 | index expression | 60 |
| Revel.go:60:15:60:22 | selection of Params : pointer type | Revel.go:33:12:33:23 | call to Get | 60 |
| Revel.go:64:15:64:22 | selection of Params : pointer type | Revel.go:32:12:32:22 | index expression | 64 |
| Revel.go:64:15:64:22 | selection of Params : pointer type | Revel.go:33:12:33:23 | call to Get | 64 |
| Revel.go:65:12:65:41 | call to PostFormValue | Revel.go:65:12:65:41 | call to PostFormValue | 65 |
| Revel.go:69:11:69:18 | selection of Params : pointer type | Revel.go:69:11:69:34 | index expression | 69 |
| Revel.go:73:10:73:17 | selection of Params : pointer type | Revel.go:73:10:73:22 | selection of JSON | 73 |
| Revel.go:76:2:76:9 | selection of Params : pointer type | Revel.go:77:12:77:32 | type assertion | 76 |
| Revel.go:81:15:81:34 | call to GetQuery : Values | Revel.go:32:12:32:22 | index expression | 81 |
| Revel.go:81:15:81:34 | call to GetQuery : Values | Revel.go:33:12:33:23 | call to Get | 81 |
| Revel.go:82:15:82:28 | selection of Form : Values | Revel.go:32:12:32:22 | index expression | 82 |
| Revel.go:82:15:82:28 | selection of Form : Values | Revel.go:33:12:33:23 | call to Get | 82 |
| Revel.go:83:15:83:37 | selection of MultipartForm : pointer type | Revel.go:32:12:32:22 | index expression | 83 |
| Revel.go:83:15:83:37 | selection of MultipartForm : pointer type | Revel.go:33:12:33:23 | call to Get | 83 |
| Revel.go:84:12:84:32 | selection of ContentType | Revel.go:84:12:84:32 | selection of ContentType | 84 |
| Revel.go:85:12:85:36 | selection of AcceptLanguages : AcceptLanguages | Revel.go:85:12:85:48 | selection of Language | 85 |
| Revel.go:86:12:86:27 | selection of Locale | Revel.go:86:12:86:27 | selection of Locale | 86 |
| Revel.go:88:13:88:31 | call to GetForm : tuple type | Revel.go:32:12:32:22 | index expression | 88 |
| Revel.go:88:13:88:31 | call to GetForm : tuple type | Revel.go:33:12:33:23 | call to Get | 88 |
| Revel.go:91:13:91:40 | call to GetMultipartForm : tuple type | Revel.go:32:12:32:22 | index expression | 91 |
| Revel.go:91:13:91:40 | call to GetMultipartForm : tuple type | Revel.go:33:12:33:23 | call to Get | 91 |
| Revel.go:94:13:94:40 | call to GetMultipartForm : tuple type | Revel.go:95:11:95:35 | index expression | 94 |
| Revel.go:97:11:97:33 | selection of MultipartForm : pointer type | Revel.go:97:11:97:48 | index expression | 97 |
| Revel.go:99:28:99:46 | call to GetBody : Reader | Revel.go:100:10:100:13 | json | 99 |
| Revel.go:102:15:102:37 | call to Cookie : tuple type | Revel.go:103:12:103:28 | call to GetValue | 102 |
| Revel.go:105:12:105:48 | call to GetHttpHeader | Revel.go:105:12:105:48 | call to GetHttpHeader | 105 |
| Revel.go:107:12:107:36 | call to GetRequestURI | Revel.go:107:12:107:36 | call to GetRequestURI | 107 |
| Revel.go:109:15:109:41 | call to MultipartReader : tuple type | Revel.go:113:12:113:27 | type conversion | 109 |
| Revel.go:115:12:115:30 | call to Referer | Revel.go:115:12:115:30 | call to Referer | 115 |
| Revel.go:117:12:117:32 | call to UserAgent | Revel.go:117:12:117:32 | call to UserAgent | 117 |
| Revel.go:122:37:122:44 | &... : pointer type | Revel.go:123:12:123:18 | message | 122 |
| Revel.go:126:41:126:42 | &... : pointer type | Revel.go:127:12:127:12 | p | 126 |
| Revel.go:131:13:131:28 | selection of Header : pointer type | Revel.go:132:12:132:18 | tainted | 131 |
| Revel.go:134:14:134:29 | selection of Header : pointer type | Revel.go:135:12:135:22 | index expression | 134 |

View File

@@ -0,0 +1,19 @@
import go
class SinkFunction extends Function {
SinkFunction() { this.getName() = ["useFiles", "useJSON", "usePerson", "useString"] }
}
class TestConfig extends TaintTracking::Configuration {
TestConfig() { this = "testconfig" }
override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
override predicate isSink(DataFlow::Node sink) {
sink = any(SinkFunction f).getACall().getAnArgument()
}
}
from TaintTracking::Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink, int i
where config.hasFlowPath(source, sink) and source.hasLocationInfo(_, i, _, _, _)
select source, sink, i order by i

View File

@@ -0,0 +1,23 @@
edges
| EndToEnd.go:58:18:58:25 | implicit dereference : Params | EndToEnd.go:58:18:58:25 | implicit dereference : Params |
| EndToEnd.go:58:18:58:25 | implicit dereference : Params | EndToEnd.go:58:18:58:25 | selection of Params : pointer type |
| EndToEnd.go:58:18:58:25 | implicit dereference : Params | EndToEnd.go:58:18:58:47 | call to Get |
| EndToEnd.go:58:18:58:25 | selection of Params : pointer type | EndToEnd.go:58:18:58:25 | implicit dereference : Params |
| EndToEnd.go:58:18:58:25 | selection of Params : pointer type | EndToEnd.go:58:18:58:25 | selection of Params : pointer type |
| EndToEnd.go:58:18:58:25 | selection of Params : pointer type | EndToEnd.go:58:18:58:47 | call to Get |
| EndToEnd.go:64:26:64:33 | implicit dereference : Params | EndToEnd.go:64:26:64:33 | implicit dereference : Params |
| EndToEnd.go:64:26:64:33 | implicit dereference : Params | EndToEnd.go:64:26:64:33 | selection of Params : pointer type |
| EndToEnd.go:64:26:64:33 | implicit dereference : Params | EndToEnd.go:64:26:64:55 | call to Get |
| EndToEnd.go:64:26:64:33 | selection of Params : pointer type | EndToEnd.go:64:26:64:33 | implicit dereference : Params |
| EndToEnd.go:64:26:64:33 | selection of Params : pointer type | EndToEnd.go:64:26:64:33 | selection of Params : pointer type |
| EndToEnd.go:64:26:64:33 | selection of Params : pointer type | EndToEnd.go:64:26:64:55 | call to Get |
nodes
| EndToEnd.go:58:18:58:25 | implicit dereference : Params | semmle.label | implicit dereference : Params |
| EndToEnd.go:58:18:58:25 | selection of Params : pointer type | semmle.label | selection of Params : pointer type |
| EndToEnd.go:58:18:58:47 | call to Get | semmle.label | call to Get |
| EndToEnd.go:64:26:64:33 | implicit dereference : Params | semmle.label | implicit dereference : Params |
| EndToEnd.go:64:26:64:33 | selection of Params : pointer type | semmle.label | selection of Params : pointer type |
| EndToEnd.go:64:26:64:55 | call to Get | semmle.label | call to Get |
#select
| EndToEnd.go:58:18:58:47 | call to Get | EndToEnd.go:58:18:58:25 | selection of Params : pointer type | EndToEnd.go:58:18:58:47 | call to Get | This path depends on $@. | EndToEnd.go:58:18:58:25 | selection of Params | a user-provided value |
| EndToEnd.go:64:26:64:55 | call to Get | EndToEnd.go:64:26:64:33 | selection of Params : pointer type | EndToEnd.go:64:26:64:55 | call to Get | This path depends on $@. | EndToEnd.go:64:26:64:33 | selection of Params | a user-provided value |

View File

@@ -0,0 +1 @@
Security/CWE-022/TaintedPath.ql

View File

@@ -0,0 +1,13 @@
module codeql-go-tests/frameworks/Revel
go 1.14
require (
github.com/github/depstubber v0.0.0-20200916130315-f3217697abd4 // indirect
github.com/go-stack/stack v1.8.0 // indirect
github.com/mattn/go-colorable v0.1.7 // indirect
github.com/revel/config v1.0.0 // indirect
github.com/revel/modules v1.0.0
github.com/revel/revel v1.0.0
golang.org/x/net v0.0.0-20200904194848-62affa334b73 // indirect
)

View File

@@ -0,0 +1,130 @@
// Code generated by depstubber. DO NOT EDIT.
// This is a simple stub for github.com/revel/modules/static/app/controllers, strictly for use in testing.
// See the LICENSE file for information about the licensing of the original library.
// Source: github.com/revel/modules/static/app/controllers (exports: Static; functions: )
// Package controllers is a stub of github.com/revel/modules/static/app/controllers, generated by depstubber.
package controllers
import (
"github.com/revel/revel"
)
/*
import (
io "io"
http "net/http"
os "os"
time "time"
)
*/
type Static struct {
*revel.Controller
}
/*
func (_ Static) Destroy() {}
func (_ Static) FlashParams() {}
func (_ Static) Forbidden(_ string, _ ...interface{}) interface{} {
return nil
}
func (_ Static) Message(_ string, _ ...interface{}) string {
return ""
}
func (_ Static) NotFound(_ string, _ ...interface{}) interface{} {
return nil
}
func (_ Static) Redirect(_ interface{}, _ ...interface{}) interface{} {
return nil
}
func (_ Static) Render(_ ...interface{}) interface{} {
return nil
}
func (_ Static) RenderBinary(_ io.Reader, _ string, _ interface{}, _ time.Time) interface{} {
return nil
}
func (_ Static) RenderError(_ error) interface{} {
return nil
}
func (_ Static) RenderFile(_ *os.File, _ interface{}) interface{} {
return nil
}
func (_ Static) RenderFileName(_ string, _ interface{}) interface{} {
return nil
}
func (_ Static) RenderHTML(_ string) interface{} {
return nil
}
func (_ Static) RenderJSON(_ interface{}) interface{} {
return nil
}
func (_ Static) RenderJSONP(_ string, _ interface{}) interface{} {
return nil
}
func (_ Static) RenderTemplate(_ string) interface{} {
return nil
}
func (_ Static) RenderText(_ string, _ ...interface{}) interface{} {
return nil
}
func (_ Static) RenderXML(_ interface{}) interface{} {
return nil
}
func (_ Static) Serve(_ string, _ string) interface{} {
return nil
}
func (_ Static) ServeDir(_ string, _ string) interface{} {
return nil
}
func (_ Static) ServeModule(_ string, _ string, _ string) interface{} {
return nil
}
func (_ Static) ServeModuleDir(_ string, _ string, _ string) interface{} {
return nil
}
func (_ Static) SetAction(_ string, _ string) error {
return nil
}
func (_ Static) SetController(_ interface{}) {}
func (_ Static) SetCookie(_ *http.Cookie) {}
func (_ Static) SetTypeAction(_ string, _ string, _ interface{}) error {
return nil
}
func (_ Static) Stats() map[string]interface{} {
return nil
}
func (_ Static) TemplateOutput(_ string) ([]byte, error) {
return nil, nil
}
func (_ Static) Todo() interface{} {
return nil
}
*/

View File

@@ -0,0 +1,697 @@
// Code generated by depstubber. It has been edited to fix a problem with embedded fields.
// This is a simple stub for github.com/revel/revel, strictly for use in testing.
// See the LICENSE file for information about the licensing of the original library.
// Source: github.com/revel/revel (exports: Controller,Params,Request,Router; functions: HTTP_QUERY)
// Package revel is a stub of github.com/revel/revel, generated by depstubber, with minor edits.
package revel
import (
context "context"
io "io"
multipart "mime/multipart"
http "net/http"
url "net/url"
os "os"
reflect "reflect"
regexp "regexp"
time "time"
)
type AcceptLanguage struct {
Language string
Quality float32
}
type AcceptLanguages []AcceptLanguage
func (_ AcceptLanguages) Len() int {
return 0
}
func (_ AcceptLanguages) Less(_ int, _ int) bool {
return false
}
func (_ AcceptLanguages) String() string {
return ""
}
func (_ AcceptLanguages) Swap(_ int, _ int) {}
type ActionDefinition struct {
Host string
Method string
URL string
Action string
Star bool
Args map[string]string
}
func (_ *ActionDefinition) String() string {
return ""
}
type ContentDisposition string
var (
NoDisposition ContentDisposition = ""
Attachment ContentDisposition = "attachment"
Inline ContentDisposition = "inline"
)
type Controller struct {
Name string
Type *ControllerType
MethodName string
MethodType *MethodType
AppController interface{}
Action string
ClientIP string
Request *Request
Response *Response
Result Result
Flash Flash
Session interface{}
Params *Params
Args map[string]interface{}
ViewArgs map[string]interface{}
Validation *Validation
Log interface{}
}
func (_ *Controller) Destroy() {}
func (_ *Controller) FlashParams() {}
func (_ *Controller) Forbidden(_ string, _ ...interface{}) Result {
return nil
}
func (_ *Controller) Message(_ string, _ ...interface{}) string {
return ""
}
func (_ *Controller) NotFound(_ string, _ ...interface{}) Result {
return nil
}
func (_ *Controller) Redirect(_ interface{}, _ ...interface{}) Result {
return nil
}
func (_ *Controller) Render(_ ...interface{}) Result {
return nil
}
func (_ *Controller) RenderBinary(_ io.Reader, _ string, _ ContentDisposition, _ time.Time) Result {
return nil
}
func (_ *Controller) RenderError(_ error) Result {
return nil
}
func (_ *Controller) RenderFile(_ *os.File, _ ContentDisposition) Result {
return nil
}
func (_ *Controller) RenderFileName(_ string, _ ContentDisposition) Result {
return nil
}
func (_ *Controller) RenderHTML(_ string) Result {
return nil
}
func (_ *Controller) RenderJSON(_ interface{}) Result {
return nil
}
func (_ *Controller) RenderJSONP(_ string, _ interface{}) Result {
return nil
}
func (_ *Controller) RenderTemplate(_ string) Result {
return nil
}
func (_ *Controller) RenderText(_ string, _ ...interface{}) Result {
return nil
}
func (_ *Controller) RenderXML(_ interface{}) Result {
return nil
}
func (_ *Controller) SetAction(_ string, _ string) error {
return nil
}
func (_ *Controller) SetController(_ ServerContext) {}
func (_ *Controller) SetCookie(_ *http.Cookie) {}
func (_ *Controller) SetTypeAction(_ string, _ string, _ *ControllerType) error {
return nil
}
func (_ *Controller) Stats() map[string]interface{} {
return nil
}
func (_ *Controller) TemplateOutput(_ string) ([]byte, error) {
return nil, nil
}
func (_ *Controller) Todo() Result {
return nil
}
type ControllerFieldPath struct {
IsPointer bool
FieldIndexPath []int
FunctionCall reflect.Value
}
func (_ *ControllerFieldPath) Invoke(_ reflect.Value, _ []reflect.Value) []reflect.Value {
return nil
}
type ControllerType struct {
Namespace string
ModuleSource *Module
Type reflect.Type
Methods []*MethodType
ControllerIndexes [][]int
ControllerEvents *ControllerTypeEvents
}
func (_ *ControllerType) Method(_ string) *MethodType {
return nil
}
func (_ *ControllerType) Name() string {
return ""
}
func (_ *ControllerType) ShortName() string {
return ""
}
type ControllerTypeEvents struct {
Before []*ControllerFieldPath
After []*ControllerFieldPath
Finally []*ControllerFieldPath
Panic []*ControllerFieldPath
}
type Error struct {
SourceType string
Title string
Path string
Description string
Line int
Column int
SourceLines []string
Stack string
MetaError string
Link string
}
func (_ *Error) ContextSource() []SourceLine {
return nil
}
func (_ *Error) Error() string {
return ""
}
func (_ *Error) SetLink(_ string) {}
type Flash struct {
Data map[string]string
Out map[string]string
}
func (_ Flash) Error(_ string, _ ...interface{}) {}
func (_ Flash) Success(_ string, _ ...interface{}) {}
var HTTP_QUERY int = 0
type MethodArg struct {
Name string
Type reflect.Type
}
type MethodType struct {
Name string
Args []*MethodArg
RenderArgNames map[int][]string
Index int
}
type Module struct {
Name string
ImportPath string
Path string
ControllerTypeList []*ControllerType
Log interface{}
}
func (_ *Module) AddController(_ *ControllerType) {}
func (_ *Module) ControllerByName(_ string, _ string) *ControllerType {
return nil
}
func (_ *Module) Namespace() string {
return ""
}
type MultipartForm struct {
File map[string][]*multipart.FileHeader
Value url.Values
}
type OutResponse struct {
Server ServerResponse
}
func (_ *OutResponse) Destroy() {}
func (_ *OutResponse) Header() *RevelHeader {
return nil
}
func (_ *OutResponse) Write(_ []byte) (int, error) {
return 0, nil
}
type Params struct {
url.Values
Fixed url.Values
Route url.Values
Query url.Values
Form url.Values
Files map[string][]*multipart.FileHeader
JSON []byte
}
func (_ *Params) Bind(_ interface{}, _ string) {}
func (_ *Params) BindJSON(_ interface{}) error {
return nil
}
type Request struct {
In ServerRequest
Header *RevelHeader
ContentType string
Format string
AcceptLanguages AcceptLanguages
Locale string
WebSocket ServerWebSocket
Method string
RemoteAddr string
Host string
URL *url.URL
Form url.Values
MultipartForm *MultipartForm
}
func (_ *Request) Args() map[string]interface{} {
return nil
}
func (_ *Request) Context() context.Context {
return nil
}
func (_ *Request) Cookie(_ string) (ServerCookie, error) {
return nil, nil
}
func (_ *Request) Destroy() {}
func (_ *Request) FormValue(_ string) string {
return ""
}
func (_ *Request) GetBody() io.Reader {
return nil
}
func (_ *Request) GetForm() (url.Values, error) {
return nil, nil
}
func (_ *Request) GetHttpHeader(_ string) string {
return ""
}
func (_ *Request) GetMultipartForm() (ServerMultipartForm, error) {
return nil, nil
}
func (_ *Request) GetPath() string {
return ""
}
func (_ *Request) GetQuery() url.Values {
return nil
}
func (_ *Request) GetRequestURI() string {
return ""
}
func (_ *Request) GetValue(_ int) interface{} {
return nil
}
func (_ *Request) MultipartReader() (*multipart.Reader, error) {
return nil, nil
}
func (_ *Request) ParseForm() error {
return nil
}
func (_ *Request) ParseMultipartForm(_ int64) error {
return nil
}
func (_ *Request) PostFormValue(_ string) string {
return ""
}
func (_ *Request) Referer() string {
return ""
}
func (_ *Request) SetRequest(_ ServerRequest) {}
func (_ *Request) UserAgent() string {
return ""
}
type Response struct {
Status int
ContentType string
Out OutResponse
}
func (_ *Response) Destroy() {}
func (_ *Response) GetStreamWriter() StreamWriter {
return nil
}
func (_ *Response) GetWriter() io.Writer {
return nil
}
func (_ *Response) SetResponse(_ ServerResponse) {}
func (_ *Response) SetStatus(_ int) {}
func (_ *Response) SetWriter(_ io.Writer) bool {
return false
}
func (_ *Response) WriteHeader(_ int, _ string) {}
type Result interface {
Apply(_ *Request, _ *Response)
}
type RevelHeader struct {
Server ServerHeader
}
func (_ *RevelHeader) Add(_ string, _ string) {}
func (_ *RevelHeader) Destroy() {}
func (_ *RevelHeader) Get(_ string) string {
return ""
}
func (_ *RevelHeader) GetAll(_ string) []string {
return nil
}
func (_ *RevelHeader) Set(_ string, _ string) {}
func (_ *RevelHeader) SetCookie(_ string) {}
func (_ *RevelHeader) SetStatus(_ int) {}
type Route struct {
ModuleSource *Module
Method string
Path string
Action string
ControllerNamespace string
ControllerName string
MethodName string
FixedParams []string
TreePath string
TypeOfController *ControllerType
}
func (_ *Route) ActionPath() string {
return ""
}
type RouteMatch struct {
Action string
ControllerName string
MethodName string
FixedParams []string
Params map[string][]string
TypeOfController *ControllerType
ModuleSource *Module
}
type Router struct {
Routes []*Route
Tree interface{}
Module string
}
func (_ *Router) Refresh() *Error {
return nil
}
func (_ *Router) Reverse(_ string, _ map[string]string) *ActionDefinition {
return nil
}
func (_ *Router) ReverseError(_ string, _ map[string]string, _ *Request) (*ActionDefinition, error) {
return nil, nil
}
func (_ *Router) Route(_ *Request) *RouteMatch {
return nil
}
type ServerContext interface {
GetRequest() ServerRequest
GetResponse() ServerResponse
}
type ServerCookie interface {
GetValue() string
}
type ServerHeader interface {
Add(_ string, _ string)
Del(_ string)
Get(_ string) []string
GetCookie(_ string) (ServerCookie, error)
GetKeys() []string
Set(_ string, _ string)
SetCookie(_ string)
SetStatus(_ int)
}
type ServerMultipartForm interface {
GetFiles() map[string][]*multipart.FileHeader
GetValues() url.Values
RemoveAll() error
}
type ServerRequest interface {
Get(_ int) (interface{}, error)
GetRaw() interface{}
Set(_ int, _ interface{}) bool
}
type ServerResponse interface {
Get(_ int) (interface{}, error)
GetRaw() interface{}
Set(_ int, _ interface{}) bool
}
type ServerWebSocket interface {
Get(_ int) (interface{}, error)
GetRaw() interface{}
MessageReceive(_ interface{}) error
MessageReceiveJSON(_ interface{}) error
MessageSend(_ interface{}) error
MessageSendJSON(_ interface{}) error
Set(_ int, _ interface{}) bool
}
type SourceLine struct {
Source string
Line int
IsError bool
}
type StreamWriter interface {
WriteStream(_ string, _ int64, _ time.Time, _ io.Reader) error
}
type Validation struct {
Errors []*ValidationError
Request *Request
Translator func(string, string, ...interface{}) string
}
func (_ *Validation) Check(_ interface{}, _ ...Validator) *ValidationResult {
return nil
}
func (_ *Validation) Clear() {}
func (_ *Validation) Domain(_ string) *ValidationResult {
return nil
}
func (_ *Validation) Email(_ string) *ValidationResult {
return nil
}
func (_ *Validation) Error(_ string, _ ...interface{}) *ValidationResult {
return nil
}
func (_ *Validation) ErrorKey(_ string, _ ...interface{}) *ValidationResult {
return nil
}
func (_ *Validation) ErrorMap() map[string]*ValidationError {
return nil
}
func (_ *Validation) FilePath(_ string, _ int) *ValidationResult {
return nil
}
func (_ *Validation) HasErrors() bool {
return false
}
func (_ *Validation) IPAddr(_ string, _ ...int) *ValidationResult {
return nil
}
func (_ *Validation) Keep() {}
func (_ *Validation) Length(_ interface{}, _ int) *ValidationResult {
return nil
}
func (_ *Validation) MacAddr(_ string) *ValidationResult {
return nil
}
func (_ *Validation) Match(_ string, _ *regexp.Regexp) *ValidationResult {
return nil
}
func (_ *Validation) Max(_ int, _ int) *ValidationResult {
return nil
}
func (_ *Validation) MaxFloat(_ float64, _ float64) *ValidationResult {
return nil
}
func (_ *Validation) MaxSize(_ interface{}, _ int) *ValidationResult {
return nil
}
func (_ *Validation) Min(_ int, _ int) *ValidationResult {
return nil
}
func (_ *Validation) MinFloat(_ float64, _ float64) *ValidationResult {
return nil
}
func (_ *Validation) MinSize(_ interface{}, _ int) *ValidationResult {
return nil
}
func (_ *Validation) PureText(_ string, _ int) *ValidationResult {
return nil
}
func (_ *Validation) Range(_ int, _ int, _ int) *ValidationResult {
return nil
}
func (_ *Validation) RangeFloat(_ float64, _ float64, _ float64) *ValidationResult {
return nil
}
func (_ *Validation) Required(_ interface{}) *ValidationResult {
return nil
}
func (_ *Validation) URL(_ string) *ValidationResult {
return nil
}
func (_ *Validation) ValidationResult(_ bool) *ValidationResult {
return nil
}
type ValidationError struct {
Message string
Key string
}
func (_ *ValidationError) String() string {
return ""
}
type ValidationResult struct {
Error *ValidationError
Ok bool
Locale string
Translator func(string, string, ...interface{}) string
}
func (_ *ValidationResult) Key(_ string) *ValidationResult {
return nil
}
func (_ *ValidationResult) Message(_ string, _ ...interface{}) *ValidationResult {
return nil
}
func (_ *ValidationResult) MessageKey(_ string, _ ...interface{}) *ValidationResult {
return nil
}
type Validator interface {
DefaultMessage() string
IsSatisfied(_ interface{}) bool
}

View File

@@ -0,0 +1,21 @@
# github.com/github/depstubber v0.0.0-20200916130315-f3217697abd4
## explicit
github.com/github/depstubber
# github.com/go-stack/stack v1.8.0
## explicit
github.com/go-stack/stack
# github.com/mattn/go-colorable v0.1.7
## explicit
github.com/mattn/go-colorable
# github.com/revel/config v1.0.0
## explicit
github.com/revel/config
# github.com/revel/modules v1.0.0
## explicit
github.com/revel/modules
# github.com/revel/revel v1.0.0
## explicit
github.com/revel/revel
# golang.org/x/net v0.0.0-20200904194848-62affa334b73
## explicit
golang.org/x/net