/
source_validator.go
135 lines (125 loc) · 4.68 KB
/
source_validator.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package sql
import (
neturl "net/url"
"strings"
bigquery "github.com/bonitoo-io/go-sql-bigquery"
"github.com/go-sql-driver/mysql"
"github.com/influxdata/flux/codes"
"github.com/influxdata/flux/dependencies/url"
"github.com/influxdata/flux/internal/errors"
"github.com/influxdata/gosnowflake"
)
// helper function to validate the data source url (postgres, sqlmock) / dsn (mysql, snowflake) using the URLValidator.
func validateDataSource(validator url.Validator, driverName string, dataSourceName string) error {
/*
NOTE: some parsers don't return an error for an "empty path" (a path consisting of nothing at all, or only whitespace) - not an error as such, but here we rely on the driver implementation "doing the right thing"
better not to, and flag this as an error because calling any SQL DB with an empty DSN is likely wrong.
*/
if strings.TrimSpace(dataSourceName) == "" {
return errors.Newf(codes.Invalid, "invalid data source url: %v", "empty path supplied")
}
var u *neturl.URL
var err error
switch driverName {
case "mysql":
// an example is: username:password@tcp(localhost:3306)/dbname?param=value
cfg, err := mysql.ParseDSN(dataSourceName)
if err != nil {
return errors.Newf(codes.Invalid, "invalid data source dsn: %v", err)
}
if cfg.AllowAllFiles {
return errors.New(codes.Invalid, "invalid data source dsn: may not set allowAllFiles")
}
u = &neturl.URL{
Scheme: cfg.Net,
User: neturl.UserPassword(cfg.User, cfg.Passwd),
Host: cfg.Addr,
}
case "postgres", "sqlmock":
// an example for postgres data source is: postgres://pqgotest:password@localhost/pqgotest?sslmode=verify-full
// this follows the URI semantics
u, err = neturl.Parse(dataSourceName)
if err != nil {
return errors.Newf(codes.Invalid, "invalid data source url: %v", err)
}
case "vertica", "vertigo":
// an example for vertica data source is: vertica://dbadmin:password@localhost:5433/VMart
// this follows the URI semantics
u, err = neturl.Parse(dataSourceName)
if err != nil {
return errors.Newf(codes.Invalid, "invalid data source url: %v", err)
}
case "sqlite3":
/*
example SQLite is: file:test.db?cache=shared&mode=memory
SQLite supports a superset of DSNs, including several special cases that net/url will flag as errors:
:memory:
file::memory:
so we need to check for these, otherwise will flag as an error
*/
if dataSourceName == ":memory:" || dataSourceName == "file::memory:" {
return nil
}
// we have a dsn that MIGHT be valid, so need to parse it - if it fails here, it is likely to be invalid
u, err = neturl.Parse(dataSourceName)
if err != nil {
return errors.Newf(codes.Invalid, "invalid data source url: %v", err)
}
case "snowflake":
// an example is: username:password@accountname/dbname/testschema?warehouse=mywh
cfg, err := gosnowflake.ParseDSN(dataSourceName)
if err != nil {
return errors.Newf(codes.Invalid, "invalid data source dsn: %v", err)
}
u = &neturl.URL{
Scheme: cfg.Protocol,
User: neturl.UserPassword(cfg.User, cfg.Password),
Host: cfg.Host,
}
case "mssql", "sqlserver":
// URL example: sqlserver://sa:mypass@localhost:1234?database=master
// ADO example: server=localhost;user id=sa;database=master
cfg, err := mssqlParseDSN(dataSourceName)
if err != nil {
return errors.Newf(codes.Invalid, "invalid data source dsn: %v", err)
}
u = &neturl.URL{
Scheme: cfg.Scheme,
User: neturl.UserPassword(cfg.User, cfg.Password),
Host: cfg.Host,
}
case "awsathena":
// an example is: s3://bucketname/?region=us-west-1&db=dbname&accessID=AKI...&secretAccessKey=NnQ7...
u, err = neturl.Parse(dataSourceName)
if err != nil {
return errors.Newf(codes.Invalid, "invalid data source url: %v", err)
}
case "bigquery":
// an example is: bigquery://projectid/location?dataset=datasetid
cfg, err := bigquery.ConfigFromConnString(dataSourceName)
if err != nil {
return errors.Newf(codes.Invalid, "invalid data source dsn: %v", err)
}
u = &neturl.URL{
Scheme: "bigquery",
Host: cfg.ProjectID,
Path: cfg.Location,
}
case "hdb": // SAP HANA
// an example is: hdb://user:password@host:port
u, err = neturl.Parse(dataSourceName)
if err != nil {
return errors.Newf(codes.Invalid, "invalid data source url: %v", err)
}
default:
return errors.Newf(codes.Invalid, "sql driver %s not supported", driverName)
}
// Bigquery DSNs don't contain any host information, so IP validation is not possible.
// XXX: Revisit if `url.Validate()` is refactored to check more than just IPs.
if driverName != "bigquery" {
if err = validator.Validate(u); err != nil {
return errors.Newf(codes.Invalid, "data source did not pass url validation: %v", err)
}
}
return nil
}