fix: bug with single quote ecape in production mode
This commit is contained in:
parent
ec2f8d0c58
commit
38ed6dbc5f
2
Makefile
2
Makefile
|
@ -45,7 +45,7 @@ changelog: $(GITCHGLOG)
|
||||||
@git-chglog $(ARGS)
|
@git-chglog $(ARGS)
|
||||||
|
|
||||||
$(GOLANGCILINT):
|
$(GOLANGCILINT):
|
||||||
@GO111MODULE=off curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s -- -b $(GOPATH)/bin v1.21.0
|
@GO111MODULE=off curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s -- -b $(GOPATH)/bin v1.25.1
|
||||||
|
|
||||||
lint: $(GOLANGCILINT)
|
lint: $(GOLANGCILINT)
|
||||||
@golangci-lint run ./... --skip-dirs-use-default
|
@golangci-lint run ./... --skip-dirs-use-default
|
||||||
|
|
|
@ -174,7 +174,7 @@ func (sg *SuperGraph) GraphQL(c context.Context, query string, vars json.RawMess
|
||||||
// use the chirino/graphql library for introspection queries
|
// use the chirino/graphql library for introspection queries
|
||||||
// disabled when allow list is enforced
|
// disabled when allow list is enforced
|
||||||
if !sg.conf.UseAllowList && res.name == "IntrospectionQuery" {
|
if !sg.conf.UseAllowList && res.name == "IntrospectionQuery" {
|
||||||
r := sg.ge.ExecuteOne(&graphql.EngineRequest{Query: query})
|
r := sg.ge.ServeGraphQL(&graphql.Request{Query: query})
|
||||||
res.Data = r.Data
|
res.Data = r.Data
|
||||||
|
|
||||||
if r.Error() != nil {
|
if r.Error() != nil {
|
||||||
|
|
33
core/args.go
33
core/args.go
|
@ -9,6 +9,8 @@ import (
|
||||||
"github.com/dosco/super-graph/jsn"
|
"github.com/dosco/super-graph/jsn"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// argMap function is used to string replace variables with values by
|
||||||
|
// the fasttemplate code
|
||||||
func (c *scontext) argMap() func(w io.Writer, tag string) (int, error) {
|
func (c *scontext) argMap() func(w io.Writer, tag string) (int, error) {
|
||||||
return func(w io.Writer, tag string) (int, error) {
|
return func(w io.Writer, tag string) (int, error) {
|
||||||
switch tag {
|
switch tag {
|
||||||
|
@ -56,10 +58,13 @@ func (c *scontext) argMap() func(w io.Writer, tag string) (int, error) {
|
||||||
return w.Write(v1)
|
return w.Write(v1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return w.Write(escQuote(fields[0].Value))
|
return w.Write(escSQuote(fields[0].Value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// argList function is used to create a list of arguments to pass
|
||||||
|
// to a prepared statement. FYI no escaping of single quotes is
|
||||||
|
// needed here
|
||||||
func (c *scontext) argList(args [][]byte) ([]interface{}, error) {
|
func (c *scontext) argList(args [][]byte) ([]interface{}, error) {
|
||||||
vars := make([]interface{}, len(args))
|
vars := make([]interface{}, len(args))
|
||||||
|
|
||||||
|
@ -113,7 +118,7 @@ func (c *scontext) argList(args [][]byte) ([]interface{}, error) {
|
||||||
if v, ok := fields[string(av)]; ok {
|
if v, ok := fields[string(av)]; ok {
|
||||||
switch v[0] {
|
switch v[0] {
|
||||||
case '[', '{':
|
case '[', '{':
|
||||||
vars[i] = escQuote(v)
|
vars[i] = v
|
||||||
default:
|
default:
|
||||||
var val interface{}
|
var val interface{}
|
||||||
if err := json.Unmarshal(v, &val); err != nil {
|
if err := json.Unmarshal(v, &val); err != nil {
|
||||||
|
@ -132,27 +137,25 @@ func (c *scontext) argList(args [][]byte) ([]interface{}, error) {
|
||||||
return vars, nil
|
return vars, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func escQuote(b []byte) []byte {
|
//
|
||||||
f := false
|
func escSQuote(b []byte) []byte {
|
||||||
for i := range b {
|
var buf *bytes.Buffer
|
||||||
if b[i] == '\'' {
|
|
||||||
f = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !f {
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
s := 0
|
s := 0
|
||||||
for i := range b {
|
for i := range b {
|
||||||
if b[i] == '\'' {
|
if b[i] == '\'' {
|
||||||
|
if buf == nil {
|
||||||
|
buf = &bytes.Buffer{}
|
||||||
|
}
|
||||||
buf.Write(b[s:i])
|
buf.Write(b[s:i])
|
||||||
buf.WriteString(`''`)
|
buf.WriteString(`''`)
|
||||||
s = i + 1
|
s = i + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if buf == nil {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
l := len(b)
|
l := len(b)
|
||||||
if s < (l - 1) {
|
if s < (l - 1) {
|
||||||
buf.Write(b[s:l])
|
buf.Write(b[s:l])
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package core
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestEscQuote(t *testing.T) {
|
||||||
|
val := "That's the worst, don''t be calling me's again"
|
||||||
|
exp := "That''s the worst, don''''t be calling me''s again"
|
||||||
|
ret := escSQuote([]byte(val))
|
||||||
|
|
||||||
|
if exp != string(ret) {
|
||||||
|
t.Errorf("escSQuote failed: %s", string(ret))
|
||||||
|
}
|
||||||
|
}
|
|
@ -167,16 +167,16 @@ func (sg *SuperGraph) renderUserQuery(stmts []stmt) (string, error) {
|
||||||
return w.String(), nil
|
return w.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sg *SuperGraph) hasTablesWithConfig(qc *qcode.QCode, role *Role) bool {
|
// func (sg *SuperGraph) hasTablesWithConfig(qc *qcode.QCode, role *Role) bool {
|
||||||
for _, id := range qc.Roots {
|
// for _, id := range qc.Roots {
|
||||||
t, err := sg.schema.GetTable(qc.Selects[id].Name)
|
// t, err := sg.schema.GetTable(qc.Selects[id].Name)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
return false
|
// return false
|
||||||
}
|
// }
|
||||||
|
|
||||||
if r := role.GetTable(t.Name); r == nil {
|
// if r := role.GetTable(t.Name); r == nil {
|
||||||
return false
|
// return false
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return true
|
// return true
|
||||||
}
|
// }
|
||||||
|
|
|
@ -40,8 +40,12 @@ func TestCockroachDB(t *testing.T) {
|
||||||
stopDatabase := func() {
|
stopDatabase := func() {
|
||||||
fmt.Println("stopping temporary cockroach db")
|
fmt.Println("stopping temporary cockroach db")
|
||||||
if atomic.CompareAndSwapInt32(&stopped, 0, 1) {
|
if atomic.CompareAndSwapInt32(&stopped, 0, 1) {
|
||||||
cmd.Process.Kill()
|
if err := cmd.Process.Kill(); err != nil {
|
||||||
cmd.Process.Wait()
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
if _, err := cmd.Process.Wait(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
os.RemoveAll(dir)
|
os.RemoveAll(dir)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -382,7 +382,7 @@ func (s *DBSchema) updateSchemaOTMT(
|
||||||
|
|
||||||
func (s *DBSchema) GetTableNames() []string {
|
func (s *DBSchema) GetTableNames() []string {
|
||||||
var names []string
|
var names []string
|
||||||
for name, _ := range s.t {
|
for name := range s.t {
|
||||||
names = append(names, name)
|
names = append(names, name)
|
||||||
}
|
}
|
||||||
return names
|
return names
|
||||||
|
|
|
@ -29,12 +29,9 @@ func (sg *SuperGraph) initGraphQLEgine() error {
|
||||||
engineSchema := engine.Schema
|
engineSchema := engine.Schema
|
||||||
dbSchema := sg.schema
|
dbSchema := sg.schema
|
||||||
|
|
||||||
engineSchema.Parse(`
|
if err := engineSchema.Parse(`enum OrderDirection { asc desc }`); err != nil {
|
||||||
enum OrderDirection {
|
return err
|
||||||
asc
|
}
|
||||||
desc
|
|
||||||
}
|
|
||||||
`)
|
|
||||||
|
|
||||||
gqltype := func(col psql.DBColumn) schema.Type {
|
gqltype := func(col psql.DBColumn) schema.Type {
|
||||||
typeName := typeMap[strings.ToLower(col.Type)]
|
typeName := typeMap[strings.ToLower(col.Type)]
|
||||||
|
@ -341,7 +338,7 @@ enum OrderDirection {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
for typeName, _ := range scalarExpressionTypesNeeded {
|
for typeName := range scalarExpressionTypesNeeded {
|
||||||
expressionType := &schema.InputObject{
|
expressionType := &schema.InputObject{
|
||||||
Name: typeName + "Expression",
|
Name: typeName + "Expression",
|
||||||
Fields: schema.InputValueList{
|
Fields: schema.InputValueList{
|
||||||
|
@ -471,8 +468,7 @@ enum OrderDirection {
|
||||||
engineSchema.Types[expressionType.Name] = expressionType
|
engineSchema.Types[expressionType.Name] = expressionType
|
||||||
}
|
}
|
||||||
|
|
||||||
err := engineSchema.ResolveTypes()
|
if err := engineSchema.ResolveTypes(); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,7 +120,7 @@ func buildFn(r Remote) func(http.Header, []byte) ([]byte, error) {
|
||||||
}
|
}
|
||||||
defer res.Body.Close()
|
defer res.Body.Close()
|
||||||
|
|
||||||
if r.Debug {
|
// if r.Debug {
|
||||||
// reqDump, err := httputil.DumpRequestOut(req, true)
|
// reqDump, err := httputil.DumpRequestOut(req, true)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// return nil, err
|
// return nil, err
|
||||||
|
@ -133,7 +133,7 @@ func buildFn(r Remote) func(http.Header, []byte) ([]byte, error) {
|
||||||
|
|
||||||
// logger.Debug().Msgf("Remote Request Debug:\n%s\n%s",
|
// logger.Debug().Msgf("Remote Request Debug:\n%s\n%s",
|
||||||
// reqDump, resDump)
|
// reqDump, resDump)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if res.StatusCode != 200 {
|
if res.StatusCode != 200 {
|
||||||
return nil,
|
return nil,
|
||||||
|
|
|
@ -32,7 +32,6 @@ var (
|
||||||
conf *Config // parsed config
|
conf *Config // parsed config
|
||||||
confPath string // path to the config file
|
confPath string // path to the config file
|
||||||
db *sql.DB // database connection pool
|
db *sql.DB // database connection pool
|
||||||
secretKey [32]byte // encryption key
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Cmd() {
|
func Cmd() {
|
||||||
|
|
|
@ -415,6 +415,7 @@ func setFakeFuncs(f *goja.Object) {
|
||||||
//f.Set("programming_language", gofakeit.ProgrammingLanguage)
|
//f.Set("programming_language", gofakeit.ProgrammingLanguage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint: errcheck
|
||||||
func setUtilFuncs(f *goja.Object) {
|
func setUtilFuncs(f *goja.Object) {
|
||||||
// Slugs
|
// Slugs
|
||||||
f.Set("make_slug", slug.Make)
|
f.Set("make_slug", slug.Make)
|
||||||
|
|
|
@ -77,7 +77,7 @@ func apiV1(w http.ResponseWriter, r *http.Request) {
|
||||||
doLog := true
|
doLog := true
|
||||||
res, err := sg.GraphQL(ct, req.Query, req.Vars)
|
res, err := sg.GraphQL(ct, req.Query, req.Vars)
|
||||||
|
|
||||||
if !conf.Production && res.QueryName() == "IntrospectionQuery" {
|
if !conf.Production && res.QueryName() == introspectionQuery {
|
||||||
doLog = false
|
doLog = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +89,7 @@ func apiV1(w http.ResponseWriter, r *http.Request) {
|
||||||
if len(conf.CacheControl) != 0 && res.Operation() == core.OpQuery {
|
if len(conf.CacheControl) != 0 && res.Operation() == core.OpQuery {
|
||||||
w.Header().Set("Cache-Control", conf.CacheControl)
|
w.Header().Set("Cache-Control", conf.CacheControl)
|
||||||
}
|
}
|
||||||
|
//nolint: errcheck
|
||||||
json.NewEncoder(w).Encode(res)
|
json.NewEncoder(w).Encode(res)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
package serv
|
|
||||||
|
|
||||||
import "net/http"
|
|
||||||
|
|
||||||
//nolint: errcheck
|
|
||||||
func introspect(w http.ResponseWriter) {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
w.Write([]byte(`{
|
|
||||||
"data": {
|
|
||||||
"__schema": {
|
|
||||||
"queryType": {
|
|
||||||
"name": "Query"
|
|
||||||
},
|
|
||||||
"mutationType": null,
|
|
||||||
"subscriptionType": null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"extensions":{
|
|
||||||
"tracing":{
|
|
||||||
"version":1,
|
|
||||||
"startTime":"2019-06-04T19:53:31.093Z",
|
|
||||||
"endTime":"2019-06-04T19:53:31.108Z",
|
|
||||||
"duration":15219720,
|
|
||||||
"execution": {
|
|
||||||
"resolvers": [{
|
|
||||||
"path": ["__schema"],
|
|
||||||
"parentType": "Query",
|
|
||||||
"fieldName": "__schema",
|
|
||||||
"returnType": "__Schema!",
|
|
||||||
"startOffset": 50950,
|
|
||||||
"duration": 17187
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`))
|
|
||||||
}
|
|
Loading…
Reference in New Issue