mirror of
https://github.com/optim-enterprises-bv/databunker.git
synced 2025-11-01 10:27:56 +00:00
format go code
This commit is contained in:
@@ -47,7 +47,7 @@ type Config struct {
|
|||||||
CreateUserWithoutAccessToken bool `yaml:"create_user_without_access_token" default:"false"`
|
CreateUserWithoutAccessToken bool `yaml:"create_user_without_access_token" default:"false"`
|
||||||
UseSeparateAppTables bool `yaml:"use_separate_app_tables" default:"false"`
|
UseSeparateAppTables bool `yaml:"use_separate_app_tables" default:"false"`
|
||||||
UserRecordSchema string `yaml:"user_record_schema"`
|
UserRecordSchema string `yaml:"user_record_schema"`
|
||||||
DisableAudit bool `yaml:"disable_audit" default:"false"`
|
DisableAudit bool `yaml:"disable_audit" default:"false"`
|
||||||
AdminEmail string `yaml:"admin_email" envconfig:"ADMIN_EMAIL"`
|
AdminEmail string `yaml:"admin_email" envconfig:"ADMIN_EMAIL"`
|
||||||
ListUsers bool `yaml:"list_users" default:"false"`
|
ListUsers bool `yaml:"list_users" default:"false"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ func decrypt(masterKey []byte, userKey []byte, data []byte) ([]byte, error) {
|
|||||||
// DO NOT USE THE FOLLOWING LINE. It is broken!!!
|
// DO NOT USE THE FOLLOWING LINE. It is broken!!!
|
||||||
//key := append(masterKey, userKey...)
|
//key := append(masterKey, userKey...)
|
||||||
la := len(masterKey)
|
la := len(masterKey)
|
||||||
key := make([]byte, la + len(userKey))
|
key := make([]byte, la+len(userKey))
|
||||||
copy(key, masterKey)
|
copy(key, masterKey)
|
||||||
copy(key[la:], userKey)
|
copy(key[la:], userKey)
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ func encrypt(masterKey []byte, userKey []byte, plaintext []byte) ([]byte, error)
|
|||||||
// comprising 24 master key
|
// comprising 24 master key
|
||||||
// and 8 bytes record key
|
// and 8 bytes record key
|
||||||
la := len(masterKey)
|
la := len(masterKey)
|
||||||
key := make([]byte, la + len(userKey))
|
key := make([]byte, la+len(userKey))
|
||||||
copy(key, masterKey)
|
copy(key, masterKey)
|
||||||
copy(key[la:], userKey)
|
copy(key[la:], userKey)
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ func encrypt(masterKey []byte, userKey []byte, plaintext []byte) ([]byte, error)
|
|||||||
// apppend random nonce bvalue to the end
|
// apppend random nonce bvalue to the end
|
||||||
//ciphertext := append(ciphertext0, nonce...)
|
//ciphertext := append(ciphertext0, nonce...)
|
||||||
la = len(ciphertext0)
|
la = len(ciphertext0)
|
||||||
ciphertext := make([]byte, la + len(nonce))
|
ciphertext := make([]byte, la+len(nonce))
|
||||||
copy(ciphertext, ciphertext0)
|
copy(ciphertext, ciphertext0)
|
||||||
copy(ciphertext[la:], nonce)
|
copy(ciphertext[la:], nonce)
|
||||||
return ciphertext, nil
|
return ciphertext, nil
|
||||||
@@ -91,7 +91,7 @@ func basicStringEncrypt(plaintext string, masterKey []byte, code []byte) (string
|
|||||||
//log.Printf("Going to encrypt %s", plaintext)
|
//log.Printf("Going to encrypt %s", plaintext)
|
||||||
nonce := []byte("$DataBunker$")
|
nonce := []byte("$DataBunker$")
|
||||||
la := len(masterKey)
|
la := len(masterKey)
|
||||||
key := make([]byte, la + len(code))
|
key := make([]byte, la+len(code))
|
||||||
copy(key, masterKey)
|
copy(key, masterKey)
|
||||||
copy(key[la:], code)
|
copy(key[la:], code)
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@ func basicStringDecrypt(data string, masterKey []byte, code []byte) (string, err
|
|||||||
}
|
}
|
||||||
nonce := []byte("$DataBunker$")
|
nonce := []byte("$DataBunker$")
|
||||||
la := len(masterKey)
|
la := len(masterKey)
|
||||||
key := make([]byte, la + len(code))
|
key := make([]byte, la+len(code))
|
||||||
copy(key, masterKey)
|
copy(key, masterKey)
|
||||||
copy(key[la:], code)
|
copy(key[la:], code)
|
||||||
block, err := aes.NewCipher(key)
|
block, err := aes.NewCipher(key)
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
"strings"
|
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func helpGetExpStatus(utoken string) (map[string]interface{}, error) {
|
func helpGetExpStatus(utoken string) (map[string]interface{}, error) {
|
||||||
@@ -130,7 +130,7 @@ func TestExpCancel(t *testing.T) {
|
|||||||
|
|
||||||
func TestExpAuto(t *testing.T) {
|
func TestExpAuto(t *testing.T) {
|
||||||
userJSON := `{"login":"william4"}`
|
userJSON := `{"login":"william4"}`
|
||||||
now := int32(time.Now().Unix())+1
|
now := int32(time.Now().Unix()) + 1
|
||||||
raw, _ := helpCreateUser(userJSON)
|
raw, _ := helpCreateUser(userJSON)
|
||||||
if _, ok := raw["status"]; !ok || raw["status"].(string) != "ok" {
|
if _, ok := raw["status"]; !ok || raw["status"].(string) != "ok" {
|
||||||
t.Fatalf("Failed to create user")
|
t.Fatalf("Failed to create user")
|
||||||
|
|||||||
@@ -5,16 +5,16 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gobuffalo/packr"
|
"github.com/gobuffalo/packr"
|
||||||
"github.com/oschwald/geoip2-golang"
|
"github.com/oschwald/geoip2-golang"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
geoipBytes []byte
|
geoipBytes []byte
|
||||||
geoip * geoip2.Reader
|
geoip *geoip2.Reader
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
func initGeoIP() {
|
func initGeoIP() {
|
||||||
var err error
|
var err error
|
||||||
box := packr.NewBox("../ui")
|
box := packr.NewBox("../ui")
|
||||||
|
|||||||
@@ -56,10 +56,10 @@ func notifyConsentChange(notifyURL string, brief string, status string, mode str
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
requestBody, _ := json.Marshal(map[string]string{
|
requestBody, _ := json.Marshal(map[string]string{
|
||||||
"action": "consentchange",
|
"action": "consentchange",
|
||||||
"brief": brief,
|
"brief": brief,
|
||||||
"status": status,
|
"status": status,
|
||||||
"mode": mode,
|
"mode": mode,
|
||||||
"identity": identity,
|
"identity": identity,
|
||||||
})
|
})
|
||||||
host := autocontext.GetAuto("host")
|
host := autocontext.GetAuto("host")
|
||||||
|
|||||||
@@ -217,9 +217,9 @@ func (e mainEnv) approveUserRequest(w http.ResponseWriter, r *http.Request, ps h
|
|||||||
event.Msg = "failed to delete"
|
event.Msg = "failed to delete"
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
returnError(w, r, "internal error", 405, err, event)
|
returnError(w, r, "internal error", 405, err, event)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
notifyURL := e.conf.Notification.NotificationURL
|
notifyURL := e.conf.Notification.NotificationURL
|
||||||
notifyForgetMe(notifyURL, userJSON, "token", userTOKEN)
|
notifyForgetMe(notifyURL, userJSON, "token", userTOKEN)
|
||||||
} else if action == "change-profile" {
|
} else if action == "change-profile" {
|
||||||
|
|||||||
@@ -20,8 +20,10 @@ var userSchema *jsonschema.Schema
|
|||||||
|
|
||||||
// IsAdmin - admin/DPO approval is required
|
// IsAdmin - admin/DPO approval is required
|
||||||
type IsAdmin bool
|
type IsAdmin bool
|
||||||
|
|
||||||
// IsLocked - variable is locked from changes
|
// IsLocked - variable is locked from changes
|
||||||
type IsLocked bool
|
type IsLocked bool
|
||||||
|
|
||||||
// IsPreserve variable can never be deleted
|
// IsPreserve variable can never be deleted
|
||||||
type IsPreserve bool
|
type IsPreserve bool
|
||||||
|
|
||||||
|
|||||||
@@ -247,15 +247,15 @@ func (dbobj MySQLDB) decodeFieldsValues(data interface{}) (string, []interface{}
|
|||||||
|
|
||||||
func (dbobj MySQLDB) decodeForCleanup(bdel []string) string {
|
func (dbobj MySQLDB) decodeForCleanup(bdel []string) string {
|
||||||
fields := ""
|
fields := ""
|
||||||
if bdel != nil {
|
if bdel != nil {
|
||||||
for _, colname := range bdel {
|
for _, colname := range bdel {
|
||||||
if len(fields) == 0 {
|
if len(fields) == 0 {
|
||||||
fields = dbobj.escapeName(colname) + "=null"
|
fields = dbobj.escapeName(colname) + "=null"
|
||||||
} else {
|
} else {
|
||||||
fields = fields + "," + dbobj.escapeName(colname) + "=null"
|
fields = fields + "," + dbobj.escapeName(colname) + "=null"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fields
|
return fields
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,15 +281,15 @@ func (dbobj MySQLDB) decodeForUpdate(bdoc *bson.M, bdel []string) (string, []int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if bdel != nil {
|
if bdel != nil {
|
||||||
for _, colname := range bdel {
|
for _, colname := range bdel {
|
||||||
if len(fields) == 0 {
|
if len(fields) == 0 {
|
||||||
fields = dbobj.escapeName(colname) + "=null"
|
fields = dbobj.escapeName(colname) + "=null"
|
||||||
} else {
|
} else {
|
||||||
fields = fields + "," + dbobj.escapeName(colname) + "=null"
|
fields = fields + "," + dbobj.escapeName(colname) + "=null"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fields, values
|
return fields, values
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ func (dbobj PGSQLDB) getConnectionString(dbname *string) string {
|
|||||||
//fmt.Printf("myql connection string: %s\n", str0)
|
//fmt.Printf("myql connection string: %s\n", str0)
|
||||||
//str := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s", user, pass, host, port, dbnameString)
|
//str := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s", user, pass, host, port, dbnameString)
|
||||||
str := fmt.Sprintf("user='%s' password='%s' host='%s' port='%s' dbname='%s'",
|
str := fmt.Sprintf("user='%s' password='%s' host='%s' port='%s' dbname='%s'",
|
||||||
user, pass, host, port, dbnameString)
|
user, pass, host, port, dbnameString)
|
||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,8 +123,8 @@ func (dbobj *PGSQLDB) OpenDB(dbname *string) error {
|
|||||||
}
|
}
|
||||||
dbobj.db = db
|
dbobj.db = db
|
||||||
// load all table names
|
// load all table names
|
||||||
q := "SELECT table_name FROM information_schema.tables where table_schema NOT IN ('pg_catalog', 'information_schema');"
|
q := "SELECT table_name FROM information_schema.tables where table_schema NOT IN ('pg_catalog', 'information_schema');"
|
||||||
tx, err := dbobj.db.Begin()
|
tx, err := dbobj.db.Begin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -244,17 +244,17 @@ func (dbobj PGSQLDB) decodeFieldsValues(data interface{}) (string, []interface{}
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (dbobj PGSQLDB) decodeForCleanup(bdel []string) string {
|
func (dbobj PGSQLDB) decodeForCleanup(bdel []string) string {
|
||||||
fields := ""
|
fields := ""
|
||||||
if bdel != nil {
|
if bdel != nil {
|
||||||
for _, colname := range bdel {
|
for _, colname := range bdel {
|
||||||
if len(fields) == 0 {
|
if len(fields) == 0 {
|
||||||
fields = dbobj.escapeName(colname) + "=null"
|
fields = dbobj.escapeName(colname) + "=null"
|
||||||
} else {
|
} else {
|
||||||
fields = fields + "," + dbobj.escapeName(colname) + "=null"
|
fields = fields + "," + dbobj.escapeName(colname) + "=null"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fields
|
return fields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbobj PGSQLDB) decodeForUpdate(bdoc *bson.M, bdel []string) (string, []interface{}) {
|
func (dbobj PGSQLDB) decodeForUpdate(bdoc *bson.M, bdel []string) (string, []interface{}) {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
_ "modernc.org/sqlite"
|
_ "modernc.org/sqlite"
|
||||||
//"github.com/schollz/sqlite3dump"
|
//"github.com/schollz/sqlite3dump"
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
@@ -176,13 +176,14 @@ func (dbobj *SQLiteDB) CloseDB() {
|
|||||||
|
|
||||||
// BackupDB function backups existing database and prints database structure to http.ResponseWriter
|
// BackupDB function backups existing database and prints database structure to http.ResponseWriter
|
||||||
func (dbobj SQLiteDB) BackupDB(w http.ResponseWriter) {
|
func (dbobj SQLiteDB) BackupDB(w http.ResponseWriter) {
|
||||||
/*
|
/*
|
||||||
err := sqlite3dump.DumpDB(dbobj.db, w)
|
err := sqlite3dump.DumpDB(dbobj.db, w)
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
if err != nil {
|
||||||
log.Printf("error in backup: %s", err)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
}
|
log.Printf("error in backup: %s", err)
|
||||||
*/
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbobj SQLiteDB) escapeName(name string) string {
|
func (dbobj SQLiteDB) escapeName(name string) string {
|
||||||
@@ -234,17 +235,17 @@ func (dbobj SQLiteDB) decodeFieldsValues(data interface{}) (string, []interface{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (dbobj SQLiteDB) decodeForCleanup(bdel []string) string {
|
func (dbobj SQLiteDB) decodeForCleanup(bdel []string) string {
|
||||||
fields := ""
|
fields := ""
|
||||||
if bdel != nil {
|
if bdel != nil {
|
||||||
for _, colname := range bdel {
|
for _, colname := range bdel {
|
||||||
if len(fields) == 0 {
|
if len(fields) == 0 {
|
||||||
fields = dbobj.escapeName(colname) + "=null"
|
fields = dbobj.escapeName(colname) + "=null"
|
||||||
} else {
|
} else {
|
||||||
fields = fields + "," + dbobj.escapeName(colname) + "=null"
|
fields = fields + "," + dbobj.escapeName(colname) + "=null"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fields
|
return fields
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dbobj SQLiteDB) decodeForUpdate(bdoc *bson.M, bdel []string) (string, []interface{}) {
|
func (dbobj SQLiteDB) decodeForUpdate(bdoc *bson.M, bdel []string) (string, []interface{}) {
|
||||||
@@ -269,15 +270,15 @@ func (dbobj SQLiteDB) decodeForUpdate(bdoc *bson.M, bdel []string) (string, []in
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if bdel != nil {
|
if bdel != nil {
|
||||||
for _, colname := range bdel {
|
for _, colname := range bdel {
|
||||||
if len(fields) == 0 {
|
if len(fields) == 0 {
|
||||||
fields = dbobj.escapeName(colname) + "=null"
|
fields = dbobj.escapeName(colname) + "=null"
|
||||||
} else {
|
} else {
|
||||||
fields = fields + "," + dbobj.escapeName(colname) + "=null"
|
fields = fields + "," + dbobj.escapeName(colname) + "=null"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fields, values
|
return fields, values
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ var TblName = &listTbls{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
allTables []string
|
allTables []string
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetTable(t Tbl) string {
|
func GetTable(t Tbl) string {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ func (dbobj dbcon) deleteUserApp(userTOKEN string, appName string, conf Config)
|
|||||||
|
|
||||||
func (dbobj dbcon) deleteUserApps(userTOKEN string, conf Config) {
|
func (dbobj dbcon) deleteUserApps(userTOKEN string, conf Config) {
|
||||||
if conf.Generic.UseSeparateAppTables == true {
|
if conf.Generic.UseSeparateAppTables == true {
|
||||||
userApps, _:= dbobj.listAllAppsOnly(conf)
|
userApps, _ := dbobj.listAllAppsOnly(conf)
|
||||||
// delete all user app records
|
// delete all user app records
|
||||||
for _, appName := range userApps {
|
for _, appName := range userApps {
|
||||||
appNameFull := "app_" + appName
|
appNameFull := "app_" + appName
|
||||||
@@ -84,7 +84,7 @@ func (dbobj dbcon) createAppRecord(jsonData []byte, userTOKEN string, appName st
|
|||||||
}
|
}
|
||||||
if record != nil {
|
if record != nil {
|
||||||
_, err = dbobj.store.UpdateRecordInTable(appNameFull, "token", userTOKEN, &bdoc)
|
_, err = dbobj.store.UpdateRecordInTable(appNameFull, "token", userTOKEN, &bdoc)
|
||||||
} else {
|
} else {
|
||||||
_, err = dbobj.store.CreateRecordInTable(appNameFull, bdoc)
|
_, err = dbobj.store.CreateRecordInTable(appNameFull, bdoc)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http/httptest"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"net/http/httptest"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
uuid "github.com/hashicorp/go-uuid"
|
|
||||||
jsonpatch "github.com/evanphx/json-patch"
|
jsonpatch "github.com/evanphx/json-patch"
|
||||||
|
uuid "github.com/hashicorp/go-uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
func helpCreateUserApp(userTOKEN string, appName string, appJSON string) (map[string]interface{}, error) {
|
func helpCreateUserApp(userTOKEN string, appName string, appJSON string) (map[string]interface{}, error) {
|
||||||
|
|||||||
@@ -81,9 +81,9 @@ func (e mainEnv) userCreate(w http.ResponseWriter, r *http.Request, ps httproute
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(parsedData.loginIdx) == 0 &&
|
if len(parsedData.loginIdx) == 0 &&
|
||||||
len(parsedData.emailIdx) == 0 &&
|
len(parsedData.emailIdx) == 0 &&
|
||||||
len(parsedData.phoneIdx) == 0 &&
|
len(parsedData.phoneIdx) == 0 &&
|
||||||
len(parsedData.customIdx) == 0 {
|
len(parsedData.customIdx) == 0 {
|
||||||
returnError(w, r, "failed to create user, all user lookup fields are missing", 405, err, event)
|
returnError(w, r, "failed to create user, all user lookup fields are missing", 405, err, event)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -454,7 +454,6 @@ func (dbobj dbcon) dumpUserPII(email string, conf Config) (string, error) {
|
|||||||
return fullJSON, err
|
return fullJSON, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (dbobj dbcon) getUserJSONByIndex(indexValue string, indexName string, conf Config) ([]byte, string, error) {
|
func (dbobj dbcon) getUserJSONByIndex(indexValue string, indexName string, conf Config) ([]byte, string, error) {
|
||||||
userBson, err := dbobj.lookupUserRecordByIndex(indexName, indexValue, conf)
|
userBson, err := dbobj.lookupUserRecordByIndex(indexName, indexValue, conf)
|
||||||
if userBson == nil || err != nil {
|
if userBson == nil || err != nil {
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"log"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
uuid "github.com/hashicorp/go-uuid"
|
|
||||||
jsonpatch "github.com/evanphx/json-patch"
|
jsonpatch "github.com/evanphx/json-patch"
|
||||||
|
uuid "github.com/hashicorp/go-uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
func helpCreateUser(userJSON string) (map[string]interface{}, error) {
|
func helpCreateUser(userJSON string) (map[string]interface{}, error) {
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"strings"
|
"strings"
|
||||||
|
|||||||
Reference in New Issue
Block a user