I'm trying to implement a go program which can handle http requests and send response in nested JSON. When i run my code and call the URL, I'm getting a runtime error,what does it mean? how can i handle this?
panic serving 192.168.0.101:50760: interface conversion: interface {} is int64, not []uint8
goroutine 5 [running]
This is my function code which is called on hitting the url
func logInPass(res http.ResponseWriter, req *http.Request) {
type Resp struct {
Result []map[string]interface{} `json:"Result,omitempty"`
Status string `json:"Status"`
}
type AxleUser struct {
Mobile string `json:"Mobile"`
Password string `json:"Password"`
}
var Response Resp
Response.Status = "failed"
Result := make(map[string]interface{})
db, err := sql.Open("mysql", "root:chikkIbuddI57#tcp(127.0.0.1:3306)/b2b")
if err != nil {
panic(err.Error())
}
defer db.Close()
rnd := render.New()
b, err := ioutil.ReadAll(req.Body)
defer req.Body.Close()
if err != nil {
panic(err.Error())
}
// Unmarshal the request body
var msg AxleUser
err = json.Unmarshal(b, &msg)
if err != nil {
panic(err.Error())
}
// get shop id from emp table using mobile number and password
userrows, usererr := db.Query("SELECT b2b_emp_id,b2b_shop_id,b2b_shop_name,b2b_emp_name,b2b_emp_mobile_number FROM b2b_employee_tbl WHERE b2b_emp_mobile_number=? and b2b_password=?", msg.Mobile, msg.Password)
if usererr != nil {
panic(usererr.Error())
}
usercolumns, usererr := userrows.Columns()
if usererr != nil {
panic(usererr.Error())
}
usercount := len(usercolumns)
values := make([]interface{}, usercount)
scanArgs := make([]interface{}, usercount)
for i := range values {
scanArgs[i] = &values[i]
}
for userrows.Next() {
usererr := userrows.Scan(scanArgs...)
if usererr != nil {
panic(usererr.Error())
}
for i, v := range values {
if v != nil {
Result[usercolumns[i]] = fmt.Sprintf("%s", string(v.([]byte)))
}
}
Response.Result = append(Response.Result, Result)
Response.Status = "success"
}
res.Header().Set("Content-Type", "application/json")
rnd.JSON(res, http.StatusOK, Response)
}
Thanks in Advance!
I've changed this line
values := make([]interface{}, usercount)
To
values := make([]string, usercount)
And this line
Result[usercolumns[i]] = fmt.Sprintf("%s", string(v.([]byte)))
To
Result[usercolumns[i]] = v
Related
When I tried to send post with json,
401 error (unauthorized messages) showed.
But with multipart, then succeeded.
In the following code,
I could get the token with only requestTokenByBuff which includes multipart.
Everytime I send post with json, I got failed.
I tried to print json body, and there was no error.
No header with body also made same result(401 error).
I did not test http.Post because Header should be inputed.
Why does post with json fail?
type AuthConfig struct {
ClientId string `json:"client_id"`
ClientSecret string `json:"client_secret"`
Code string `json:"data"`
GrantType string `json:"grant_type"`
}
var host string
func initAuthConfig(a *AuthConfig) {
host = "https://xxxxxxx"
a.ClientId = "xxxxxxx"
a.ClientSecret = "xxxxxxx"
a.Code = "xxxxx"
a.GrantType = "xxxx"
}
func initAuthConfig2() {
host = "https://xxxxxxx"
}
func requestToken(auth *AuthConfig) {
authbytes, _ := json.Marshal(auth)
authbuff := bytes.NewBuffer(authbytes)
client := &http.Client{}
req, err := http.NewRequest("POST", host, authbuff)
if err != nil {
log.Fatalln(err)
}
req.Header.Add("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.xxxxxx")
req.Header.Add("Cookie", "SCOUTER=xxxxxxx")
req.Header.Add("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
log.Fatalln(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalln(err)
}
data := string(body)
fmt.Println(data)
}
func requestTokenByBuff(buff *bytes.Buffer) {
writer := multipart.NewWriter(buff)
_ = writer.WriteField("client_id", "xxxxxxxxxx")
_ = writer.WriteField("client_secret", "xxxxxxxx")
_ = writer.WriteField("data", "xxxxxx")
_ = writer.WriteField("grant_type", "xxxxxxx")
err := writer.Close()
if err != nil {
log.Fatalln(err)
return
}
client := &http.Client{}
req, err := http.NewRequest("POST", host, buff)
if err != nil {
log.Fatalln(err)
}
req.Header.Add("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.xxxx")
req.Header.Add("Cookie", "SCOUTER=xxxxxxxx")
req.Header.Set("Content-Type", writer.FormDataContentType())
resp, err := client.Do(req)
if err != nil {
log.Fatalln(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalln(err)
}
data := string(body)
fmt.Println(data)
}
func main() {
// config := new(AuthConfig)
// initAuthConfig(config)
// requestToken(config)
buff := &bytes.Buffer{}
initAuthConfig2()
requestTokenByBuff(buff)
}
Fairly unremarkable code here:
type Response struct {
Status string `json:"status"`
Msg string `json:"msg"`
ErrorCode string `json:"error-code"`
Data interface{} `json:"data"`
Eof bool `json:"eof"`
}
func main() {
data := [][]string{
[]string{"description", "BILL NO 2362 EXTRA 5%"},
}
r := &Response{
Data: data,
}
str, _ := json.Marshal(r)
fmt.Println(string(str))
}
It prints the following:
{"status":"","msg":"","error-code":"","data":[["description","BILL NO 2362 EXTRA 5%"]],"eof":false}
No problem so far. However if I try to marshal JSON from exactly the same data, but fetched from a DB, I get a weird output:
func TestJson(t *testing.T) {
var pool *sql.DB
pool, err := sql.Open("mysql", "user:pass#tcp(127.0.0.1:3306)/db")
if err != nil {
t.Errorf("%s\n", err.Error())
}
defer pool.Close()
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
if err := pool.PingContext(ctx); err != nil {
t.Errorf("%s\n", err.Error())
}
data := fetchAll(t, ctx, pool)
fmt.Println(data)
res := &Response{
Data: data,
}
str, err := json.Marshal(res)
if err != nil {
t.Errorf("%s\n", err.Error())
}
fmt.Printf(string(str))
}
func fetchAll(t *testing.T, ctx context.Context, pool *sql.DB) [][]string {
rows, err := pool.QueryContext(ctx, "select description from vouchers where id = 1")
if err != nil {
t.Fatalf("%s\n", err.Error())
}
cols, err := rows.Columns()
if err != nil {
t.Fatalf("%s\n", err.Error())
}
vals := make([]interface{}, len(cols))
var results [][]string
for rows.Next() {
for i := range cols {
vals[i] = &vals[i]
}
err = rows.Scan(vals...)
if err != nil {
t.Fatalf("%s\n", err.Error())
}
var r []string
for i, c := range cols {
r = append(r, c)
var v string
if vals[i] == nil {
v = "NULL"
} else {
b, _ := vals[i].([]byte)
v = string(b)
}
fmt.Printf("byte len %d\n", len(v))
fmt.Printf("rune len %d\n", utf8.RuneCountInString(v))
r = append(r, v)
}
results = append(results, r)
}
if rows.Err() != nil {
t.Fatalf("%s\n", err.Error())
}
return results
}
The test code prints this:
=== RUN TestJson
byte len 21
rune len 21
[[description BILL NO 2362 EXTRA 5%]]
{"status":"","msg":"","error-code":"","data":[["description","BILL NO 2362 EXTRA 5%!"(MISSING)]],"eof":false}--- PASS: TestJson (0.35s)
PASS
ok command-line-arguments 0.836s
Note the corrupted JSON. I printed the rune length of the string to make sure the string contains
just plain ascii characters. The print before the marshal confirms that we are looking at exactly the same string. Why on earth is the output different ?
If I remove the last "%" then life returns to normal:
byte len 20
rune len 20
[[description BILL NO 2362 EXTRA 5]]
{"status":"","msg":"","error-code":"","data":[["description","BILL NO 2362 EXTRA 5"]],"eof":false}--- PASS: TestJson (0.35s)
PASS
ok command-line-arguments 0.534s
Based on the suggestions modify the program as follows:
func TestJson(t *testing.T) {
var pool *sql.DB
pool, err := sql.Open("mysql", "user:pass#tcp(127.0.0.1:3306)/db")
if err != nil {
t.Errorf("%s\n", err.Error())
}
defer pool.Close()
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel()
if err := pool.PingContext(ctx); err != nil {
t.Errorf("%s\n", err.Error())
}
data := fetchAll(t, ctx, pool)
fmt.Println(data)
res := &Response{
Data: data,
}
str, err := json.Marshal(res)
if err != nil {
t.Errorf("%s\n", err.Error())
}
fmt.Print(string(str))
}
func fetchAll(t *testing.T, ctx context.Context, pool *sql.DB) [][]string {
rows, err := pool.QueryContext(ctx, "select description from vouchers where id = 1")
if err != nil {
t.Fatalf("%s\n", err.Error())
}
cols, err := rows.Columns()
if err != nil {
t.Fatalf("%s\n", err.Error())
}
vals := make([]interface{}, len(cols))
var results [][]string
for rows.Next() {
for i := range cols {
vals[i] = &vals[i]
}
err = rows.Scan(vals...)
if err != nil {
t.Fatalf("%s\n", err.Error())
}
var r []string
for i, c := range cols {
r = append(r, c)
var v string
if vals[i] == nil {
v = "NULL"
} else {
b, _ := vals[i].([]byte)
v = string(b)
}
fmt.Printf("byte len %d\n", len(v))
fmt.Printf("rune len %d\n", utf8.RuneCountInString(v))
r = append(r, v)
}
results = append(results, r)
}
if rows.Err() != nil {
t.Fatalf("%s\n", err.Error())
}
return results
}
I am trying to build a TCP server that loads dataset from a CSV file and provide an interface to query the dataset. TCP server will expose port 4040. CSV file contains the following columns related to corona virus cases:
Cumulative Test Positive
Cumulative Tests Performed
Date
Discharged
Expired
Admitted
Region
Users should be able to connect to the server using NetCat nc localhost 4040 command on Linux/Unix based systems.
Once connected to TCP, the user should be able to communicate with the application by sending queries in JSON format.
{
"query": {
"region": "Sindh"
}
}
{
"query": {
"date": "2020-03-20"
}
}
My server.go
package main
import (
"fmt"
"net"
"os"
"flag"
"log"
"encoding/csv"
"encoding/json"
"bufio"
"io"
"strings"
)
type CovidPatient struct {
Positive string `json:"Covid_Positive"`
Performed string `json:"Coivd_Performed"`
Date string `json:"Covid_Date"`
Discharged string `json:"Covid_Discharged"`
Expired string `json:"Covid_Expired"`
Region string `json:"Covid_Region"`
Admitted string `json:"Covid_Admitted"`
}
type DataRequest struct {
Get string `json:"get"`
}
type DataError struct {
Error string `json:"Covid_error"`
}
func Load(path string) []CovidPatient {
table := make([]CovidPatient, 0)
var patient CovidPatient
file, err := os.Open(path)
if err != nil {
panic(err.Error())
}
defer file.Close()
reader := csv.NewReader(file)
csvData, err := reader.ReadAll()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
for _, row := range csvData{
patient.Positive = row[0]
patient.Performed = row[1]
patient.Date = row[2]
patient.Discharged = row[3]
patient.Expired = row[4]
patient.Region = row[5]
patient.Admitted = row[6]
table = append(table, patient)
}
return table
}
func Find(table []CovidPatient, filter string) []CovidPatient {
if filter == "" || filter == "*" {
return table
}
result := make([]CovidPatient, 0)
filter = strings.ToUpper(filter)
for _, cp := range table {
if cp.Date == filter ||
cp.Region == filter ||
strings.Contains(strings.ToUpper(cp.Positive), filter) ||
strings.Contains(strings.ToUpper(cp.Performed), filter) ||
strings.Contains(strings.ToUpper(cp.Date), filter) ||
strings.Contains(strings.ToUpper(cp.Discharged), filter) ||
strings.Contains(strings.ToUpper(cp.Expired), filter) ||
strings.Contains(strings.ToUpper(cp.Region), filter) ||
strings.Contains(strings.ToUpper(cp.Admitted), filter){
result = append(result, cp)
}
}
return result
}
var (
patientsDetail = Load("./covid_final_data.csv")
)
func main(){
var addr string
var network string
flag.StringVar(&addr, "e", ":4040", "service endpoint [ip addr or socket path]")
flag.StringVar(&network, "n", "tcp", "network protocol [tcp,unix]")
flag.Parse()
switch network {
case "tcp", "tcp4", "tcp6", "unix":
default:
fmt.Println("unsupported network protocol")
os.Exit(1)
}
ln, err := net.Listen(network, addr)
if err != nil {
log.Println(err)
os.Exit(1)
}
defer ln.Close()
log.Println("Covid19 Condition in Pakistan")
log.Printf("Service started: (%s) %s\n", network, addr)
for {
conn, err := ln.Accept()
if err != nil {
log.Println(err)
conn.Close()
continue
}
log.Println("Connected to ", conn.RemoteAddr())
go handleConnection(conn)
}
}
func handleConnection(conn net.Conn) {
defer func() {
if err := conn.Close(); err != nil {
log.Println("error closing connection:", err)
}
}()
reader := bufio.NewReaderSize(conn, 4)
for {
buf, err := reader.ReadSlice('}')
if err != nil {
if err != io.EOF {
log.Println("connection read error:", err)
return
}
}
reader.Reset(conn)
var req DataRequest
if err := json.Unmarshal(buf, &req); err != nil {
log.Println("failed to unmarshal request:", err)
cerr, jerr := json.Marshal(DataError{Error: err.Error()})
if jerr != nil {
log.Println("failed to marshal DataError:", jerr)
continue
}
if _, werr := conn.Write(cerr); werr != nil {
log.Println("failed to write to DataError:", werr)
return
}
continue
}
result := Find(patientsDetail, req.Get)
rsp, err := json.Marshal(&result)
if err != nil {
log.Println("failed to marshal data:", err)
if _, err := fmt.Fprintf(conn, `{"data_error":"internal error"}`); err != nil {
log.Printf("failed to write to client: %v", err)
return
}
continue
}
if _, err := conn.Write(rsp); err != nil {
log.Println("failed to write response:", err)
return
}
}
}
This correctly loads the csv and convert it into JSON. But, when I try to run query using NetCat command it return empty JSON element. Kindly guide me where is error.
Guess you want this:
╭─root#DESKTOP-OCDRD7Q ~
╰─# nc localhost 4040
{"get": "Sindh"}
[{"Covid_Positive":"1","Coivd_Performed":"1","Covid_Date":"1","Covid_Discharged":"1","Covid_Expired":"1","Covid_Region":"Sindh","Covid_Admitted":"1"}]
What you should do is just to modify your json request.
package main
import (
"bufio"
"encoding/csv"
"encoding/json"
"flag"
"fmt"
"io"
"log"
"net"
"os"
)
type CovidPatient struct {
Positive string `json:"Covid_Positive"`
Performed string `json:"Coivd_Performed"`
Date string `json:"Covid_Date"`
Discharged string `json:"Covid_Discharged"`
Expired string `json:"Covid_Expired"`
Region string `json:"Covid_Region"`
Admitted string `json:"Covid_Admitted"`
}
type DataRequest struct {
Get CovidPatient `json:"get"`
}
type DataError struct {
Error string `json:"Covid_error"`
}
func Load(path string) []CovidPatient {
table := make([]CovidPatient, 0)
var patient CovidPatient
file, err := os.Open(path)
if err != nil {
panic(err.Error())
}
defer file.Close()
reader := csv.NewReader(file)
csvData, err := reader.ReadAll()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
for _, row := range csvData {
patient.Positive = row[0]
patient.Performed = row[1]
patient.Date = row[2]
patient.Discharged = row[3]
patient.Expired = row[4]
patient.Region = row[5]
patient.Admitted = row[6]
table = append(table, patient)
}
return table
}
func Find(table []CovidPatient, filter CovidPatient) []CovidPatient {
result := make([]CovidPatient, 0)
log.Println(filter, table)
for _, cp := range table {
if filter.Positive == "" {
} else if filter.Positive != cp.Positive {
continue
}
if filter.Performed == "" {
} else if filter.Performed != cp.Performed {
continue
}
if filter.Date == "" {
} else if filter.Date != cp.Date {
continue
}
if filter.Discharged == "" {
} else if filter.Discharged != cp.Discharged {
continue
}
if filter.Expired == "" {
} else if filter.Expired != cp.Expired {
continue
}
if filter.Region == "" {
} else if filter.Region != cp.Region {
continue
}
if filter.Admitted == "" {
} else if filter.Admitted != cp.Admitted {
continue
}
result = append(result, cp)
}
return result
}
var (
patientsDetail = Load("./covid_final_data.csv")
)
func main() {
log.SetFlags(log.Lshortfile | log.Ltime)
var addr string
var network string
flag.StringVar(&addr, "e", ":4040", "service endpoint [ip addr or socket path]")
flag.StringVar(&network, "n", "tcp", "network protocol [tcp,unix]")
flag.Parse()
switch network {
case "tcp", "tcp4", "tcp6", "unix":
default:
fmt.Println("unsupported network protocol")
os.Exit(1)
}
ln, err := net.Listen(network, addr)
if err != nil {
log.Println(err)
os.Exit(1)
}
defer ln.Close()
log.Println("Covid19 Condition in Pakistan")
log.Printf("Service started: (%s) %s\n", network, addr)
for {
conn, err := ln.Accept()
if err != nil {
log.Println(err)
conn.Close()
continue
}
log.Println("Connected to ", conn.RemoteAddr())
go handleConnection(conn)
}
}
func handleConnection(conn net.Conn) {
defer func() {
if err := conn.Close(); err != nil {
log.Println("error closing connection:", err)
}
}()
reader := bufio.NewReaderSize(conn, 100)
for {
buf, err := reader.ReadBytes('|')
if err != nil {
if err != io.EOF {
log.Println("connection read error:", err)
return
}
}
reader.Reset(conn)
var req DataRequest
if err := json.Unmarshal(buf[:len(buf)-1], &req); err != nil {
log.Println("failed to unmarshal request:", string(buf), err)
cerr, jerr := json.Marshal(DataError{Error: err.Error()})
if jerr != nil {
log.Println("failed to marshal DataError:", jerr)
continue
}
if _, werr := conn.Write(cerr); werr != nil {
log.Println("failed to write to DataError:", werr)
return
}
continue
}
result := Find(patientsDetail, req.Get)
rsp, err := json.Marshal(&result)
if err != nil {
log.Println("failed to marshal data:", err)
if _, err := fmt.Fprintf(conn, `{"data_error":"internal error"}`); err != nil {
log.Printf("failed to write to client: %v", err)
return
}
continue
}
if _, err := conn.Write(rsp); err != nil {
log.Println("failed to write response:", err)
return
}
}
}
The query is:
╭─root#DESKTOP-OCDRD7Q ~
╰─# nc localhost 4040 127 ↵
{
"get": {
"Covid_Region": "Sindh",
"Covid_Date": "2020-03-20"
}
}|
[{"Covid_Positive":"1","Coivd_Performed":"1","Covid_Date":"2020-03-20","Covid_Discharged":"1","Covid_Expired":"1","Covid_Region":"Sindh","Covid_Admitted":"1"}]
Inside function handleConnection, the first thing is "read until you find the first }", imagine the user is sending the request:
{ "get": { "Covid_Region": "Sindh", "Covid_Date": "2020-03-20" } }
then that step read:
{ "get": { "Covid_Region": "Sindh", "Covid_Date": "2020-03-20" }
Notice the trailing } is missing, then the json.Unmarshal is trying to unmarshal the query without the last } (which is an invalid json).
This problem can take advantage of JSON streaming decoding, in other words, use json.NewDecoder(r io.Reader) instead of json.Unmarshal. Let me copy and modify the first part of that function:
func handleConnection(conn net.Conn) {
defer func() {
if err := conn.Close(); err != nil {
log.Println("error closing connection:", err)
}
}()
jsonDecoder := json.NewDecoder(conn) // A json decoder read a stream to find a
// valid JSON and stop just the byte
// after the JSON ends. Process can be
// repeated.
for {
var req DataRequest
err := jsonDecoder.Decode(&req)
if err == io.EOF {
log.Println("finish")
return
}
if err != nil {
log.Println("unmarshal:", err)
return
}
result := Find(patientsDetail, req.Get) // Here query the system
// ...
Probably now it works, but you can also take advantage of json streaming to send the response back with a jsonEncoder := json.NewEncoder(conn) before de for loop and sending the request like this:
err := jsonEncoder.Encode(&result)
if err != nil {
log.Println("failed to marshal data:", err)
// ...
continue
}
I have JSON string like
"{\"a\": \"b\", \"a\":true,\"c\":[\"field_3 string 1\",\"field3 string2\"]}"
how to detect the duplicate attribute in this json string using Golang
Use the json.Decoder to walk through the JSON. When an object is found, walk through keys and values checking for duplicate keys.
func check(d *json.Decoder, path []string, dup func(path []string) error) error {
// Get next token from JSON
t, err := d.Token()
if err != nil {
return err
}
// Is it a delimiter?
delim, ok := t.(json.Delim)
// No, nothing more to check.
if !ok {
// scaler type, nothing to do
return nil
}
switch delim {
case '{':
keys := make(map[string]bool)
for d.More() {
// Get field key.
t, err := d.Token()
if err != nil {
return err
}
key := t.(string)
// Check for duplicates.
if keys[key] {
// Duplicate found. Call the application's dup function. The
// function can record the duplicate or return an error to stop
// the walk through the document.
if err := dup(append(path, key)); err != nil {
return err
}
}
keys[key] = true
// Check value.
if err := check(d, append(path, key), dup); err != nil {
return err
}
}
// consume trailing }
if _, err := d.Token(); err != nil {
return err
}
case '[':
i := 0
for d.More() {
if err := check(d, append(path, strconv.Itoa(i)), dup); err != nil {
return err
}
i++
}
// consume trailing ]
if _, err := d.Token(); err != nil {
return err
}
}
return nil
}
Here's how to call it:
func printDup(path []string) error {
fmt.Printf("Duplicate %s\n", strings.Join(path, "/"))
return nil
}
...
data := `{"a": "b", "a":true,"c":["field_3 string 1","field3 string2"], "d": {"e": 1, "e": 2}}`
if err := check(json.NewDecoder(strings.NewReader(data)), nil, printDup); err != nil {
log.Fatal(err)
}
The output is:
Duplicate a
Duplicate d/e
Run it on the Playground
Here's how to generate an error on the first duplicate key:
var ErrDuplicate = errors.New("duplicate")
func dupErr(path []string) error {
return ErrDuplicate
}
...
data := `{"a": "b", "a":true,"c":["field_3 string 1","field3 string2"], "d": {"e": 1, "e": 2}}`
err := check(json.NewDecoder(strings.NewReader(data)), nil, dupErr)
if err == ErrDuplicate {
fmt.Println("found a duplicate")
} else if err != nil {
// some other error
log.Fatal(err)
}
One that would probably work well would be to simply decode, reencode, then check the length of the new json against the old json:
https://play.golang.org/p/50P-x1fxCzp
package main
import (
"encoding/json"
"fmt"
)
func main() {
jsn := []byte("{\"a\": \"b\", \"a\":true,\"c\":[\"field_3 string 1\",\"field3 string2\"]}")
var m map[string]interface{}
err := json.Unmarshal(jsn, &m)
if err != nil {
panic(err)
}
l := len(jsn)
jsn, err = json.Marshal(m)
if err != nil {
panic(err)
}
if l != len(jsn) {
panic(fmt.Sprintf("%s: %d (%d)", "duplicate key", l, len(jsn)))
}
}
The right way to do it would be to re-implement the json.Decode function, and store a map of keys found, but the above should work (especially if you first stripped any spaces from the json using jsn = bytes.Replace(jsn, []byte(" "), []byte(""), -1) to guard against false positives.
I build a client and a server in golang both are using this functions to encrypt/decrypt
func encrypt(text []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
b := base64.StdEncoding.EncodeToString(text)
ciphertext := make([]byte, aes.BlockSize+len(b))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err
}
cfb := cipher.NewCFBEncrypter(block, iv)
cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b))
return ciphertext, nil
}
func decrypt(text []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
if len(text) < aes.BlockSize {
return nil, errors.New("ciphertext too short")
}
iv := text[:aes.BlockSize]
text = text[aes.BlockSize:]
cfb := cipher.NewCFBDecrypter(block, iv)
cfb.XORKeyStream(text, text)
data, err := base64.StdEncoding.DecodeString(string(text))
if err != nil {
return nil, err
}
return data, nil
}
so yeah I make a normal post request
url := "https://"+configuration.Server+configuration.Port+"/get"
// TODO maybe bugs rest here
ciphertext, err := encrypt([]byte(*getUrl))
if err != nil {
fmt.Println("Error: " + err.Error())
}
fmt.Println(string(ciphertext))
values := map[string]interface{}{"url": *getUrl, "urlCrypted": ciphertext}
jsonValue, _ := json.Marshal(values)
jsonStr := bytes.NewBuffer(jsonValue)
req, err := http.NewRequest("POST", url, jsonStr)
and the servercode is as following
requestContent := getRequestContentFromRequest(req)
url := requestContent["url"].(string)
undecryptedUrl := requestContent["urlCrypted"].(string)
decryptedurl, err := decrypt([]byte(undecryptedUrl))
if err != nil {
fmt.Println("Error: " + err.Error())
}
fmt.Println(decryptedurl)
where getRequestContentFromRequest is as following
func getRequestContentFromRequest(req *http.Request)
map[string]interface{} {
buf := new(bytes.Buffer)
buf.ReadFrom(req.Body)
data := buf.Bytes()
var requestContent map[string]interface{}
err := json.Unmarshal(data, &requestContent)
if err != nil {
fmt.Println(err)
}
return requestContent
}
Now to the problem.
If I encrypt my string in the client and decrypt it direct after that everything is fine.
But, when I send the encrypted string to the server and try to decrypt it with literrally the same function as in the client, the decrypt function throws an error.
Error: illegal base64 data at input byte 0
I think the Problem is the unmarshalling of the JSON.
Thanks for help.
P.S.
Repos are
github.com/BelphegorPrime/goSafeClient and github.com/BelphegorPrime/goSafe
UPDATE
Example JSON
{"url":"facebook2.com","urlCrypted":"/}\ufffd\ufffd\ufffdgP\ufffdN뼞\ufffd\u0016\ufffd)\ufffd\ufffd\ufffdy\u001c\u000f\ufffd\ufffd\ufffdep\ufffd\rY\ufffd\ufffd$\ufffd\ufffd"}
UPDATE2
I made a playground here
The problem is that you encode in base64 twice. The first time in the encrypt function and the second time during the JSON marshalling. byte slices are automatically converted into base64 strings by the encoding/json marshaller.
The solution is to decode the base64 string before calling decrypt.
Example on the Go PlayGround
EDIT
Working solution here