Add experimental library: gin web framework (#117)

This commit is contained in:
Slavomir
2020-05-12 16:27:11 +03:00
committed by GitHub
parent 6f21b4030e
commit 84e2a5ddd2
9 changed files with 1032 additions and 0 deletions

View File

@@ -0,0 +1,173 @@
/**
* Provides classes for working with untrusted flow sources from the `github.com/gin-gonic/gin` package.
*/
import go
private module Gin {
/**
* Data from a `Context` struct, considered as a source of untrusted flow.
*/
private class GithubComGinGonicGinContextSource extends UntrustedFlowSource::Range {
GithubComGinGonicGinContextSource() {
exists(string packagePath, string typeName |
packagePath = "github.com/gin-gonic/gin" and
typeName = "Context"
|
// Method calls:
exists(DataFlow::MethodCallNode call, string methodName |
call.getTarget().hasQualifiedName(packagePath, typeName, methodName) and
(
methodName = "FullPath"
or
methodName = "GetHeader"
or
methodName = "QueryArray"
or
methodName = "Query"
or
methodName = "PostFormArray"
or
methodName = "PostForm"
or
methodName = "Param"
or
methodName = "GetStringSlice"
or
methodName = "GetString"
or
methodName = "GetRawData"
or
methodName = "ClientIP"
or
methodName = "ContentType"
or
methodName = "Cookie"
or
methodName = "GetQueryArray"
or
methodName = "GetQuery"
or
methodName = "GetPostFormArray"
or
methodName = "GetPostForm"
or
methodName = "DefaultPostForm"
or
methodName = "DefaultQuery"
or
methodName = "GetPostFormMap"
or
methodName = "GetQueryMap"
or
methodName = "GetStringMap"
or
methodName = "GetStringMapString"
or
methodName = "GetStringMapStringSlice"
or
methodName = "PostFormMap"
or
methodName = "QueryMap"
)
|
this = call.getResult(0)
or
this = call.getResult()
)
or
// Field reads:
exists(DataFlow::Field fld |
fld.hasQualifiedName(packagePath, typeName, "Accepted") and
this = fld.getARead()
)
)
}
}
/**
* Data from a `Params` slice, considered as a source of untrusted flow.
*/
private class GithubComGinGonicGinParamsSource extends UntrustedFlowSource::Range {
GithubComGinGonicGinParamsSource() {
exists(string packagePath, string typeName |
packagePath = "github.com/gin-gonic/gin" and
typeName = "Params"
|
// Any read of a variable of this type:
exists(DataFlow::ReadNode read | read.getType().hasQualifiedName(packagePath, typeName) |
this = read
)
or
// Method calls:
exists(DataFlow::MethodCallNode call |
call.getTarget().hasQualifiedName(packagePath, typeName, ["ByName", "Get"])
|
this = call.getResult(0)
or
this = call.getResult()
)
)
}
}
/**
* Data from a `Param` struct, considered as a source of untrusted flow.
*/
private class GithubComGinGonicGinParamSource extends UntrustedFlowSource::Range {
GithubComGinGonicGinParamSource() {
exists(string packagePath, string typeName |
packagePath = "github.com/gin-gonic/gin" and
typeName = "Param"
|
// Any read of a variable of this type:
exists(DataFlow::ReadNode read | read.getType().hasQualifiedName(packagePath, typeName) |
this = read
)
or
// Field reads:
exists(DataFlow::Field fld | fld.hasQualifiedName(packagePath, typeName, ["Key", "Value"]) |
this = fld.getARead()
)
)
}
}
/**
* A call to a method on `Context` struct that unmarshals data into a target.
*/
private class GithubComGinGonicGinContextBindSource extends UntrustedFlowSource::Range {
GithubComGinGonicGinContextBindSource() {
exists(string packagePath, string typeName |
packagePath = "github.com/gin-gonic/gin" and
typeName = "Context"
|
exists(DataFlow::MethodCallNode call, string methodName |
call.getTarget().hasQualifiedName(packagePath, typeName, methodName) and
(
methodName = "BindJSON" or
methodName = "BindYAML" or
methodName = "BindXML" or
methodName = "BindUri" or
methodName = "BindQuery" or
methodName = "BindWith" or
methodName = "BindHeader" or
methodName = "MustBindWith" or
methodName = "Bind" or
methodName = "ShouldBind" or
methodName = "ShouldBindBodyWith" or
methodName = "ShouldBindJSON" or
methodName = "ShouldBindQuery" or
methodName = "ShouldBindUri" or
methodName = "ShouldBindHeader" or
methodName = "ShouldBindWith" or
methodName = "ShouldBindXML" or
methodName = "ShouldBindYAML"
)
|
this = call.getArgument(0)
)
)
}
}
}

View File

@@ -0,0 +1,63 @@
| Gin.go:23:10:23:29 | call to GetHeader |
| Gin.go:27:10:27:30 | call to QueryArray |
| Gin.go:31:10:31:25 | call to Query |
| Gin.go:35:10:35:33 | call to PostFormArray |
| Gin.go:39:10:39:28 | call to PostForm |
| Gin.go:43:10:43:25 | call to Param |
| Gin.go:47:10:47:34 | call to GetStringSlice |
| Gin.go:51:10:51:29 | call to GetString |
| Gin.go:55:3:55:28 | ... := ...[0] |
| Gin.go:59:10:59:23 | call to ClientIP |
| Gin.go:63:10:63:26 | call to ContentType |
| Gin.go:67:3:67:29 | ... := ...[0] |
| Gin.go:71:3:71:36 | ... := ...[0] |
| Gin.go:75:3:75:31 | ... := ...[0] |
| Gin.go:79:3:79:39 | ... := ...[0] |
| Gin.go:83:3:83:34 | ... := ...[0] |
| Gin.go:87:10:87:52 | call to DefaultPostForm |
| Gin.go:91:10:91:49 | call to DefaultQuery |
| Gin.go:95:3:95:37 | ... := ...[0] |
| Gin.go:99:3:99:34 | ... := ...[0] |
| Gin.go:103:10:103:32 | call to GetStringMap |
| Gin.go:107:10:107:38 | call to GetStringMapString |
| Gin.go:111:10:111:43 | call to GetStringMapStringSlice |
| Gin.go:115:10:115:31 | call to PostFormMap |
| Gin.go:119:10:119:28 | call to QueryMap |
| Gin.go:123:10:123:23 | call to FullPath |
| Gin.go:129:10:129:21 | selection of Accepted |
| Gin.go:133:10:133:19 | selection of Params |
| Gin.go:134:7:134:9 | val |
| Gin.go:134:7:134:12 | index expression |
| Gin.go:134:7:134:18 | selection of Value |
| Gin.go:139:10:139:19 | selection of Params |
| Gin.go:139:10:139:22 | index expression |
| Gin.go:140:7:140:9 | val |
| Gin.go:140:7:140:15 | selection of Value |
| Gin.go:143:10:143:19 | selection of Params |
| Gin.go:143:10:143:34 | call to ByName |
| Gin.go:147:3:147:34 | ... := ...[0] |
| Gin.go:147:13:147:22 | selection of Params |
| Gin.go:153:12:153:21 | selection of Params |
| Gin.go:153:12:153:24 | index expression |
| Gin.go:154:10:154:14 | param |
| Gin.go:154:10:154:18 | selection of Key |
| Gin.go:155:10:155:14 | param |
| Gin.go:155:10:155:20 | selection of Value |
| Gin.go:163:16:163:22 | &... |
| Gin.go:168:15:168:21 | &... |
| Gin.go:173:16:173:22 | &... |
| Gin.go:178:15:178:21 | &... |
| Gin.go:183:17:183:23 | &... |
| Gin.go:188:20:188:26 | &... |
| Gin.go:193:16:193:22 | &... |
| Gin.go:198:12:198:18 | &... |
| Gin.go:203:18:203:24 | &... |
| Gin.go:208:26:208:32 | &... |
| Gin.go:213:22:213:28 | &... |
| Gin.go:218:23:218:29 | &... |
| Gin.go:223:21:223:27 | &... |
| Gin.go:228:22:228:28 | &... |
| Gin.go:233:21:233:27 | &... |
| Gin.go:238:22:238:28 | &... |
| Gin.go:243:18:243:24 | &... |
| Gin.go:248:24:248:30 | &... |

View File

@@ -0,0 +1,251 @@
package main
//go:generate depstubber -vendor github.com/gin-gonic/gin Context
//go:generate depstubber -vendor github.com/gin-gonic/gin/binding "" YAML
import (
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
)
func main() {}
type Person struct {
Name string `form:"name"`
Address string `form:"address"`
}
func use(val string) {}
// gin
func ginHandler(ctx *gin.Context) {
{
val := ctx.GetHeader("key")
use(val)
}
{
val := ctx.QueryArray("key")
use(val[0])
}
{
val := ctx.Query("key")
use(val)
}
{
val := ctx.PostFormArray("key")
use(val[0])
}
{
val := ctx.PostForm("key")
use(val)
}
{
val := ctx.Param("key")
use(val)
}
{
val := ctx.GetStringSlice("key")
use(val[0])
}
{
val := ctx.GetString("key")
use(val)
}
{
val, _ := ctx.GetRawData()
use(string(val))
}
{
val := ctx.ClientIP()
use(val)
}
{
val := ctx.ContentType()
use(val)
}
{
val, _ := ctx.Cookie("key")
use(val)
}
{
val, _ := ctx.GetQueryArray("key")
use(val[0])
}
{
val, _ := ctx.GetQuery("key")
use(val)
}
{
val, _ := ctx.GetPostFormArray("key")
use(val[0])
}
{
val, _ := ctx.GetPostForm("key")
use(val)
}
{
val := ctx.DefaultPostForm("key", "default-value")
use(val)
}
{
val := ctx.DefaultQuery("key", "default-value")
use(val)
}
{
val, _ := ctx.GetPostFormMap("key")
use(val["a"])
}
{
val, _ := ctx.GetQueryMap("key")
use(val["a"])
}
{
val := ctx.GetStringMap("key")
use(val["a"].(string))
}
{
val := ctx.GetStringMapString("key")
use(val["a"])
}
{
val := ctx.GetStringMapStringSlice("key")
use(val["a"][0])
}
{
val := ctx.PostFormMap("key")
use(val["a"])
}
{
val := ctx.QueryMap("key")
use(val["a"])
}
{
val := ctx.FullPath()
use(val)
}
// fields:
{
val := ctx.Accepted
use(val[0])
}
{
val := ctx.Params
use(val[0].Value)
}
// Params:
{
val := ctx.Params[0]
use(val.Value)
}
{
val := ctx.Params.ByName("name")
use(val)
}
{
val, _ := ctx.Params.Get("name")
use(val)
}
// Param:
{
param := ctx.Params[0]
key := param.Key
val := param.Value
use(key)
use(val)
}
// bind:
{
var person Person
ctx.BindYAML(&person)
use(person.Name)
}
{
var person Person
ctx.BindXML(&person)
use(person.Name)
}
{
var person Person
ctx.BindWith(&person, binding.YAML)
use(person.Name)
}
{
var person Person
ctx.BindUri(&person)
use(person.Name)
}
{
var person Person
ctx.BindQuery(&person)
use(person.Name)
}
{
var person Person
ctx.MustBindWith(&person, binding.YAML)
use(person.Name)
}
{
var person Person
ctx.BindJSON(&person)
use(person.Name)
}
{
var person Person
ctx.Bind(&person)
use(person.Name)
}
{
var person Person
ctx.ShouldBind(&person)
use(person.Name)
}
{
var person Person
ctx.ShouldBindBodyWith(&person, binding.YAML)
use(person.Name)
}
{
var person Person
ctx.ShouldBindJSON(&person)
use(person.Name)
}
{
var person Person
ctx.ShouldBindQuery(&person)
use(person.Name)
}
{
var person Person
ctx.ShouldBindUri(&person)
use(person.Name)
}
{
var person Person
ctx.ShouldBindWith(&person, binding.YAML)
use(person.Name)
}
{
var person Person
ctx.ShouldBindXML(&person)
use(person.Name)
}
{
var person Person
ctx.ShouldBindYAML(&person)
use(person.Name)
}
{
var person Person
ctx.BindHeader(&person)
use(person.Name)
}
{
var person Person
ctx.ShouldBindHeader(&person)
use(person.Name)
}
}

View File

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

View File

@@ -0,0 +1,5 @@
module example.com/m
go 1.14
require github.com/gin-gonic/gin v1.6.2

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Manuel Martínez-Almeida
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,12 @@
// Code generated by depstubber. DO NOT EDIT.
// This is a simple stub for github.com/gin-gonic/gin/binding, strictly for use in testing.
// See the LICENSE file for information about the licensing of the original library.
// Source: github.com/gin-gonic/gin/binding (exports: ; functions: YAML)
// Package binding is a stub of github.com/gin-gonic/gin/binding, generated by depstubber.
package binding
import ()
var YAML interface{} = nil

View File

@@ -0,0 +1,500 @@
// Code generated by depstubber. DO NOT EDIT.
// This is a simple stub for github.com/gin-gonic/gin, strictly for use in testing.
// See the LICENSE file for information about the licensing of the original library.
// Source: github.com/gin-gonic/gin (exports: Context; functions: )
// Package gin is a stub of github.com/gin-gonic/gin, generated by depstubber.
package gin
import (
bufio "bufio"
io "io"
multipart "mime/multipart"
net "net"
http "net/http"
sync "sync"
time "time"
)
type Context struct {
Request *http.Request
Writer ResponseWriter
Params Params
KeysMutex *sync.RWMutex
Keys map[string]interface{}
Errors interface{}
Accepted []string
}
func (_ *Context) Abort() {}
func (_ *Context) AbortWithError(_ int, _ interface {
Error() string
}) *Error {
return nil
}
func (_ *Context) AbortWithStatus(_ int) {}
func (_ *Context) AbortWithStatusJSON(_ int, _ interface{}) {}
func (_ *Context) AsciiJSON(_ int, _ interface{}) {}
func (_ *Context) Bind(_ interface{}) interface {
Error() string
} {
return nil
}
func (_ *Context) BindHeader(_ interface{}) interface {
Error() string
} {
return nil
}
func (_ *Context) BindJSON(_ interface{}) interface {
Error() string
} {
return nil
}
func (_ *Context) BindQuery(_ interface{}) interface {
Error() string
} {
return nil
}
func (_ *Context) BindUri(_ interface{}) interface {
Error() string
} {
return nil
}
func (_ *Context) BindWith(_ interface{}, _ interface{}) interface {
Error() string
} {
return nil
}
func (_ *Context) BindXML(_ interface{}) interface {
Error() string
} {
return nil
}
func (_ *Context) BindYAML(_ interface{}) interface {
Error() string
} {
return nil
}
func (_ *Context) ClientIP() string {
return ""
}
func (_ *Context) ContentType() string {
return ""
}
func (_ *Context) Cookie(_ string) (string, interface {
Error() string
}) {
return "", nil
}
func (_ *Context) Copy() *Context {
return nil
}
func (_ *Context) Data(_ int, _ string, _ []uint8) {}
func (_ *Context) DataFromReader(_ int, _ int64, _ string, _ io.Reader, _ map[string]string) {}
func (_ *Context) Deadline() (time.Time, bool) {
return time.Time{}, false
}
func (_ *Context) DefaultPostForm(_ string, _ string) string {
return ""
}
func (_ *Context) DefaultQuery(_ string, _ string) string {
return ""
}
func (_ *Context) Done() <-chan struct{} {
return nil
}
func (_ *Context) Err() interface {
Error() string
} {
return nil
}
func (_ *Context) Error(_ interface {
Error() string
}) *Error {
return nil
}
func (_ *Context) File(_ string) {}
func (_ *Context) FileAttachment(_ string, _ string) {}
func (_ *Context) FileFromFS(_ string, _ http.FileSystem) {}
func (_ *Context) FormFile(_ string) (*multipart.FileHeader, interface {
Error() string
}) {
return nil, nil
}
func (_ *Context) FullPath() string {
return ""
}
func (_ *Context) Get(_ string) (interface{}, bool) {
return nil, false
}
func (_ *Context) GetBool(_ string) bool {
return false
}
func (_ *Context) GetDuration(_ string) time.Duration {
return 0
}
func (_ *Context) GetFloat64(_ string) float64 {
return 0
}
func (_ *Context) GetHeader(_ string) string {
return ""
}
func (_ *Context) GetInt(_ string) int {
return 0
}
func (_ *Context) GetInt64(_ string) int64 {
return 0
}
func (_ *Context) GetPostForm(_ string) (string, bool) {
return "", false
}
func (_ *Context) GetPostFormArray(_ string) ([]string, bool) {
return nil, false
}
func (_ *Context) GetPostFormMap(_ string) (map[string]string, bool) {
return nil, false
}
func (_ *Context) GetQuery(_ string) (string, bool) {
return "", false
}
func (_ *Context) GetQueryArray(_ string) ([]string, bool) {
return nil, false
}
func (_ *Context) GetQueryMap(_ string) (map[string]string, bool) {
return nil, false
}
func (_ *Context) GetRawData() ([]uint8, interface {
Error() string
}) {
return nil, nil
}
func (_ *Context) GetString(_ string) string {
return ""
}
func (_ *Context) GetStringMap(_ string) map[string]interface{} {
return nil
}
func (_ *Context) GetStringMapString(_ string) map[string]string {
return nil
}
func (_ *Context) GetStringMapStringSlice(_ string) map[string][]string {
return nil
}
func (_ *Context) GetStringSlice(_ string) []string {
return nil
}
func (_ *Context) GetTime(_ string) time.Time {
return time.Time{}
}
func (_ *Context) HTML(_ int, _ string, _ interface{}) {}
func (_ *Context) Handler() HandlerFunc {
return nil
}
func (_ *Context) HandlerName() string {
return ""
}
func (_ *Context) HandlerNames() []string {
return nil
}
func (_ *Context) Header(_ string, _ string) {}
func (_ *Context) IndentedJSON(_ int, _ interface{}) {}
func (_ *Context) IsAborted() bool {
return false
}
func (_ *Context) IsWebsocket() bool {
return false
}
func (_ *Context) JSON(_ int, _ interface{}) {}
func (_ *Context) JSONP(_ int, _ interface{}) {}
func (_ *Context) MultipartForm() (*multipart.Form, interface {
Error() string
}) {
return nil, nil
}
func (_ *Context) MustBindWith(_ interface{}, _ interface{}) interface {
Error() string
} {
return nil
}
func (_ *Context) MustGet(_ string) interface{} {
return nil
}
func (_ *Context) Negotiate(_ int, _ Negotiate) {}
func (_ *Context) NegotiateFormat(_ ...string) string {
return ""
}
func (_ *Context) Next() {}
func (_ *Context) Param(_ string) string {
return ""
}
func (_ *Context) PostForm(_ string) string {
return ""
}
func (_ *Context) PostFormArray(_ string) []string {
return nil
}
func (_ *Context) PostFormMap(_ string) map[string]string {
return nil
}
func (_ *Context) ProtoBuf(_ int, _ interface{}) {}
func (_ *Context) PureJSON(_ int, _ interface{}) {}
func (_ *Context) Query(_ string) string {
return ""
}
func (_ *Context) QueryArray(_ string) []string {
return nil
}
func (_ *Context) QueryMap(_ string) map[string]string {
return nil
}
func (_ *Context) Redirect(_ int, _ string) {}
func (_ *Context) Render(_ int, _ interface{}) {}
func (_ *Context) SSEvent(_ string, _ interface{}) {}
func (_ *Context) SaveUploadedFile(_ *multipart.FileHeader, _ string) interface {
Error() string
} {
return nil
}
func (_ *Context) SecureJSON(_ int, _ interface{}) {}
func (_ *Context) Set(_ string, _ interface{}) {}
func (_ *Context) SetAccepted(_ ...string) {}
func (_ *Context) SetCookie(_ string, _ string, _ int, _ string, _ string, _ bool, _ bool) {}
func (_ *Context) SetSameSite(_ http.SameSite) {}
func (_ *Context) ShouldBind(_ interface{}) interface {
Error() string
} {
return nil
}
func (_ *Context) ShouldBindBodyWith(_ interface{}, _ interface{}) interface {
Error() string
} {
return nil
}
func (_ *Context) ShouldBindHeader(_ interface{}) interface {
Error() string
} {
return nil
}
func (_ *Context) ShouldBindJSON(_ interface{}) interface {
Error() string
} {
return nil
}
func (_ *Context) ShouldBindQuery(_ interface{}) interface {
Error() string
} {
return nil
}
func (_ *Context) ShouldBindUri(_ interface{}) interface {
Error() string
} {
return nil
}
func (_ *Context) ShouldBindWith(_ interface{}, _ interface{}) interface {
Error() string
} {
return nil
}
func (_ *Context) ShouldBindXML(_ interface{}) interface {
Error() string
} {
return nil
}
func (_ *Context) ShouldBindYAML(_ interface{}) interface {
Error() string
} {
return nil
}
func (_ *Context) Status(_ int) {}
func (_ *Context) Stream(_ func(io.Writer) bool) bool {
return false
}
func (_ *Context) String(_ int, _ string, _ ...interface{}) {}
func (_ *Context) Value(_ interface{}) interface{} {
return nil
}
func (_ *Context) XML(_ int, _ interface{}) {}
func (_ *Context) YAML(_ int, _ interface{}) {}
type Error struct {
Err interface {
Error() string
}
Type ErrorType
Meta interface{}
}
func (_ Error) Error() string {
return ""
}
func (_ *Error) IsType(_ ErrorType) bool {
return false
}
func (_ *Error) JSON() interface{} {
return nil
}
func (_ *Error) MarshalJSON() ([]uint8, interface {
Error() string
}) {
return nil, nil
}
func (_ *Error) SetMeta(_ interface{}) *Error {
return nil
}
func (_ *Error) SetType(_ ErrorType) *Error {
return nil
}
type ErrorType uint64
type HandlerFunc func(*Context)
type Negotiate struct {
Offered []string
HTMLName string
HTMLData interface{}
JSONData interface{}
XMLData interface{}
YAMLData interface{}
Data interface{}
}
type Param struct {
Key string
Value string
}
type Params []Param
func (_ Params) ByName(_ string) string {
return ""
}
func (_ Params) Get(_ string) (string, bool) {
return "", false
}
type ResponseWriter interface {
CloseNotify() <-chan bool
Flush()
Header() http.Header
Hijack() (net.Conn, *bufio.ReadWriter, interface {
Error() string
})
Pusher() http.Pusher
Size() int
Status() int
Write(_ []uint8) (int, interface {
Error() string
})
WriteHeader(_ int)
WriteHeaderNow()
WriteString(_ string) (int, interface {
Error() string
})
Written() bool
}

View File

@@ -0,0 +1,3 @@
# github.com/gin-gonic/gin v1.6.2
## explicit
github.com/gin-gonic/gin