package runner

import (
	"strings"
	"testing"

	"gopkg.in/stretchr/testify.v1/assert"
)

// https://wfuzz.googlecode.com/svn/trunk/wordlist/Injections/SQL.txt
var fuzzList = `
'
"
#
-
--
'%20--
--';
'%20;
=%20'
=%20;
=%20--
\x23
\x27
\x3D%20\x3B'
\x3D%20\x27
\x27\x4F\x52 SELECT *
\x27\x6F\x72 SELECT *
'or%20select *
admin'--
<>"'%;)(&+
'%20or%20''='
'%20or%20'x'='x
"%20or%20"x"="x
')%20or%20('x'='x
0 or 1=1
' or 0=0 --
" or 0=0 --
or 0=0 --
' or 0=0 #
" or 0=0 #
or 0=0 #
' or 1=1--
" or 1=1--
' or '1'='1'--
"' or 1 --'"
or 1=1--
or%201=1
or%201=1 --
' or 1=1 or ''='
" or 1=1 or ""="
' or a=a--
" or "a"="a
') or ('a'='a
") or ("a"="a
hi" or "a"="a
hi" or 1=1 --
hi' or 1=1 --
hi' or 'a'='a
hi') or ('a'='a
hi") or ("a"="a
'hi' or 'x'='x';
@variable
,@variable
PRINT
PRINT @@variable
select
insert
as
or
procedure
limit
order by
asc
desc
delete
update
distinct
having
truncate
replace
like
handler
bfilename
' or username like '%
' or uname like '%
' or userid like '%
' or uid like '%
' or user like '%
exec xp
exec sp
'; exec master..xp_cmdshell
'; exec xp_regread
t'exec master..xp_cmdshell 'nslookup www.google.com'--
--sp_password
\x27UNION SELECT
' UNION SELECT
' UNION ALL SELECT
' or (EXISTS)
' (select top 1
'||UTL_HTTP.REQUEST
1;SELECT%20*
to_timestamp_tz
tz_offset
&lt;&gt;&quot;'%;)(&amp;+
'%20or%201=1
%27%20or%201=1
%20$(sleep%2050)
%20'sleep%2050'
char%4039%41%2b%40SELECT
&apos;%20OR
'sqlattempt1
(sqlattempt2)
|
%7C
*|
%2A%7C
*(|(mail=*))
%2A%28%7C%28mail%3D%2A%29%29
*(|(objectclass=*))
%2A%28%7C%28objectclass%3D%2A%29%29
(
%28
)
%29
&
%26
!
%21
' or 1=1 or ''='
' or ''='
x' or 1=1 or 'x'='y
/
//
//*
*/*
`

func init() {
	fuzzList += "\b"
	fuzzList += "\n"
	fuzzList += "\n"
	fuzzList += "\r"
	fuzzList += "\t"
	fuzzList += "Hello\tworld"
}

func TestSQLInjectionBuilder(t *testing.T) {
	for _, fuzz := range strings.Split(fuzzList, "\n") {
		if fuzz == "" {
			continue
		}
		fuzz = strings.Trim(fuzz, " \t")

		var id int64
		var comment string
		err := testDB.
			InsertInto("comments").
			Columns("comment").
			Values(fuzz).
			SetIsInterpolated(true).
			Returning("id", "comment").
			QueryScalar(&id, &comment)

		assert.True(t, id > 0)
		assert.Equal(t, fuzz, comment)

		var result int
		err = testDB.SQL(`
			SELECT 42
			FROM comments
			WHERE id = $1 AND comment = $2
		`, id, comment).QueryScalar(&result)

		assert.NoError(t, err)
		assert.Equal(t, 42, result)
	}
}

func TestSQLInjectionSQL(t *testing.T) {
	for _, fuzz := range strings.Split(fuzzList, "\n") {
		if fuzz == "" {
			continue
		}
		fuzz = strings.Trim(fuzz, " \t")

		var id int64
		var comment string
		err := testDB.
			SQL(`
				INSERT INTO comments (comment)
				VALUES ($1)
				RETURNING id, comment
			`, fuzz).
			SetIsInterpolated(true).
			QueryScalar(&id, &comment)

		assert.True(t, id > 0)
		assert.Equal(t, fuzz, comment)

		var result int
		err = testDB.SQL(`
			SELECT 42
			FROM comments
			WHERE id = $1 AND comment = $2
		`, id, comment).QueryScalar(&result)

		assert.NoError(t, err)
		assert.Equal(t, 42, result)
	}
}
