I am using this library in golang to connect to socket server.https://github.com/hesh915/go-socket.io-client I have to pass an auth object as server is expecting an object which will authenticate the user, but in this implementation, query seems to take map as a parameter. I get an EOF error while sending the stringified struct to Query as given below:
opts.Query["auth"] = str
I have created a nested structure for that purpose, tried converting struct into byte data using marshal and type casted into string, passed it as key value pair to map but that didn't seem to work out. Here is how my auth nested struct looks like:
{"userInfo":{"id":"","username":"","permissionsInfo":{"permissions"["",""]}},"additionalInfo":""}
How to send this information with the implementation given below:
opts := &socketio_client.Options{
Transport: "websocket",
Query: make(map[string]string),
}
opts.Query["user"] = "user"
opts.Query["pwd"] = "pass"
uri := "http://192.168.1.70:9090/socket.io/"
I have provided the link to the library.
Minimal Reproducible Example
type User struct {
Userinfo UserInfo `json:"userInfo"`
AdditionalInfo string `json:"additionalInfo"`
}
type UserInfo struct {
Id string `json:"id"`
Username string `json:"username"`
Permissionsinfo PermissionsInfo `json:"permissionInfo"`
}
type PermissionsInfo struct {
Permissions []string `json:"permissions"`
}
func main() {
user := &User{
Userinfo: UserInfo{
Id: "",
Username: "",
Permissionsinfo: PermissionsInfo{
Permissions: []string{"", ""},
}},
AdditionalInfo: "",
}
b, _ := json.Marshal(user)
fmt.Println(string(b))
opts := &socketio_client.Options{
Transport: "websocket",
Query: make(map[string]string),
}
opts.Query["auth"] = string(b)
uri := origin + "/socket.io"
client, err := socketio_client.NewClient(uri, opts)
if err != nil {
if err == io.EOF {
fmt.Printf("NewClient error:%v\n", err)
return
}
return
}
client.On("error", func() {
fmt.Println("on error")
})
}
The error to the above code, that i'm getting:
NewClient error EOF
My server end has to receive the auth params as socket.handshake.auth and that's understandable because the above functionality doesn't supports for auth instead it does for query. How can I achieve this functionality? Any help would be appreciated.
Related
I am trying to ensure the body of a post request for example contains exact structure of the body and if not ahould throw an error
for example i have the following function
func UpdatePassword(c *fiber.Ctx) error {
type UpdatePasswordData struct {
Password string `json:"password" form:"password"`
NewPassword string `json:"new_password" form:"new_password"`
NewPasswordConfirm string `json:"new_password_confirm" form:"new_password_confirm"`
}
data := UpdatePasswordData{}
if err := c.BodyParser(&data); err != nil {
return err
}
var user models.User
if data.NewPassword != data.NewPasswordConfirm {
c.Status(400)
return c.JSON(fiber.Map{
"message": "passwords do not match",
})
}
email, _ := middlewares.GetUserEmail(c)
newPassword := models.HashPassword(data.NewPassword)
database.DB.Model(&user).Select("Password").Where("email = ?", email).Updates(map[string]interface{}{"Password": newPassword})
return c.JSON(user)
}
the POST request should be looking for body with this structure
{
"password": "oldpassword",
"new_password": "newpassword",
"new_password_confirm": "newpassword",
}
but currently this endpoint accepts body that does not have this exact structure. So how do i enforce the structure in the body of request, so that if structure does not match, i throw an error?
do not like gin, fiber has not builtin validate package
use go-playground/validator
go get github.com/go-playground/validator
example
type UpdatePasswordData struct {
Password string `json:"password" validate:"required,min=8,max=32"`
NewPassword string `json:"new_password" validate:"required,min=8,max=32"`
NewPasswordConfirm string `json:"new_password_confirm" validate:"eqfield=NewPassword"`
}
func UpdatePassword(c *fiber.Ctx) error {
var body UpdatePasswordData
if err := c.BodyParser(&body); err != nil {
return err
}
validate := validator.New()
if err := validate.Struct(body); err != nil {
return err
}
// do others
// get current user, check password == hash(body.password)
// save new passworld
}
or you can see fiber office docs https://docs.gofiber.io/guide/validation#validator-package
We can use struct tag
`validate:"required"`
to ensure that all the mandatory fields are there in the request payload.
Moreover we can validate the fields with the provided tags of the validator package and for additional validations we can implement custom validators and register them like this:
validate := validator.New()
validate.RegisterValidation("password-validator", PasswordValidator)
I am a little bit confused here and although I have searched a lot on this, something is clearly missing from my knowledge and I am asking your help.
I have created a Hyperledger Fabric Network and installed a chaincode in it. And I want to make a function that retrieves all the World State inputs about the Keys. I have done it already with the bytes.Buffer and it worked. But what I want to do is to do it with a struct.
So, I created the following struct that has only the key:
type WSKeys struct {
Key string `json: "key"`
Namespace string `json: "Namespace"`
}
And this is my code function:
func (s *SmartContract) getAllWsDataStruct(APIstub shim.ChaincodeStubInterface , args []string) sc.Response {
var keyArrayStr []WSKeys
resultsIterator, err := APIstub.GetQueryResult("{\"selector\":{\"_id\":{\"$ne\": null }} }")
if err != nil {
return shim.Error("Error occured when trying to fetch data: "+err.Error())
}
for resultsIterator.HasNext() {
// Get the next record
queryResponse, err := resultsIterator.Next()
if err != nil {
return shim.Error(err.Error())
}
fmt.Println(queryResponse)
var qry_key_json WSKeys
json.Unmarshal([]byte(queryResponse), &qry_key_json)
keyArray = append(keyArray, qry_key_json)
}
defer resultsIterator.Close()
all_bytes, _ := json.Marshal(keyArray)
fmt.Println(keyArray)
return shim.Success(all_bytes)
}
When executing the above I get the following error:
cannot convert queryResponse (type *queryresult.KV) to type []byte
I can get the results correctly if I, for example do this:
func (s *SmartContract) getAllWsDataStruct(APIstub shim.ChaincodeStubInterface , args []string) sc.Response {
var keyArray []string
resultsIterator, err := APIstub.GetQueryResult("{\"selector\":{\"_id\":{\"$ne\": null }} }")
if err != nil {
return shim.Error("Error occured when trying to fetch data: "+err.Error())
}
for resultsIterator.HasNext() {
// Get the next record
queryResponse, err := resultsIterator.Next()
if err != nil {
return shim.Error(err.Error())
}
fmt.Println(queryResponse)
keyArray = append(keyArray, queryResponse.Key)
}
defer resultsIterator.Close()
all_bytes, _ := json.Marshal(keyArray)
fmt.Println(keyArray)
return shim.Success(all_bytes)
}
But, why I get the above error when trying to add the queryResponse into a custom struct?
Do I need to add it to a struct that is only its type?
Please someone can explain what I am missing here?
The error statement is verbose enough to indicate, that your []byte conversion failed for the type queryResponse which, with a bit of lookup seems to be a struct type. In Go you cannot natively convert a struct instance to its constituent bytes without encoding using gob or other means.
Perhaps your intention was to use the Key record in the struct for un-marshalling
json.Unmarshal([]byte(queryResponse.Key), &qry_key_json)
I am using Go fiber's body parser to parse the request body. I have the following struct
type SignInCredentials struct {
Email string
Password []byte
}
Where I have a Password as a slice of bytes. When I try to parse the body like so
func SignUp(db *database.Database) fiber.Handler {
return func(c *fiber.Ctx) error {
cred := new(model.SignUpCredentials)
if err := c.BodyParser(cred); err != nil {
return SendParsingError(c)
}
I get a schema error
schema: error converting value for index 0 of \"Password\
because the type of the form data password doesn't match the []byte type. I looked at their examples and I noticed that in the documentation they use a string to store the password. But I am set on storing it as a slice of bytes. How can I do this?
// Field names should start with an uppercase letter
type Person struct {
Name string `json:"name" xml:"name" form:"name"`
Pass string `json:"pass" xml:"pass" form:"pass"`
}
app.Post("/", func(c *fiber.Ctx) error {
p := new(Person)
if err := c.BodyParser(p); err != nil {
return err
}
log.Println(p.Name) // john
log.Println(p.Pass) // doe
// ...
})
It is transmitted as a string, not []byte. You need to parse it as a string first, then you can transform it into the structure you want:
func SignUp(db *database.Database) fiber.Handler {
return func(c *fiber.Ctx) error {
// an anonymous struct to parse the body
body := struct{
Email string
Password string
}{}
if err := c.BodyParser(body); err != nil {
return SendParsingError(c)
}
cred := SignInCredentials{
Email: body.Email,
Password: []byte(body.Password),
}
func Login(c echo.Context) error {
user := &users.User{}
if err := c.Bind(&user); err != nil {
return err
}
return token.SigIn(c, user.Email, user.Password)
}
This is my Login function that retrieve the token when the user send the requests.
the Signin func that handle the token
func SigIn(c echo.Context, email, password string) error {
user := users.User{}
db := database.SetUp()
if err := db.Where("email = ?", email).First(&user).Error; gorm.IsRecordNotFoundError(err) {
restErr := errors.NewBadRequestError("Invalid credentials")
return c.JSON(http.StatusBadRequest, restErr)
}
if user.VerifyPassword(password) != nil {
restErr := errors.NewUnauthorizedError("Couldn't log you in with these credentials")
return c.JSON(http.StatusUnauthorized, restErr)
}
//user is successfull
return CreateToken(c)
}
the CreateToken func is as follow
type TokenJWT struct {
Token string `json:"token"`
}
func CreateToken(c echo.Context) error {
token := jwt.New(jwt.SigningMethodHS256)
claims := token.Claims.(jwt.MapClaims)
claims["authorized"] = true
claims["name"] = "Pascal Gaetan"
claims["exp"] = time.Now().Add(time.Hour * 1).Unix()
// Generate encoded token and send it as response.
t, err := token.SignedString([]byte("my_secret_key"))
if err != nil {
return err
}
return c.JSON(http.StatusOK, TokenJWT{
Token: t,
})
}
when everyhting is succesfull, i would like to get the authenticated user through an URL /api/me that calls a Me function
Let me split your question into two parts: the first one is how to easily encode and decode user in or from JWT token and the second part is how to write a generic code which can retrieve user from everywhere.
From your example I mentioned that you created a MapClaims but to reduce parsing complexity it will be better to create a token using a custom claims type. If you are using dgrijalva/jwt-go, then according to documentation you can do something like that
type UserClaims struct {
Name string `json:"name"`
jwt.StandardClaims
}
// encode it as before, but with your created type
t := jwt.New(signer)
userClaims := &UserClaims{Name: "Burmese"}
t.Claims = userClaims
tokenString, err = t.SignedString(]byte("my_secret_key"))
then you can parse your user in your router/framework middleware with
tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJleHAiOjE1MDAwLCJpc3MiOiJ0ZXN0In0.HE7fK0xOQwFEr4WDgRWj4teRPZ6i3GLwD5YCm6Pwu_c"
token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte("my_secret_key"), nil
})
if claims, ok := token.Claims.(*UserClaims); ok && token.Valid {
fmt.Printf("%v %v", claims.Name, claims.StandardClaims.ExpiresAt)
} else {
fmt.Println(err)
}
This example was adopted from an official documentation here
Now you know how to parse authenticated user struct with ease and the next logic move is to wrap it into your middleware. Whether there are a lot of implementation details like you can retrieve JWT from cookie, header or query, also defining some ordering on them, the gist the following: you should have wrapped abovementioned code into your middleware and after parsing the struct you can pass it via your request context. I don't use echo and other frameworks, but for pure net/http you can pass your parsed struct from middleware with
context.WithValue(ctx, UserCtxKey, claims)
Hope it helps!
This is a fairly common design pattern to create an authenticated client and then call various action methods on it. You could do something like the following:
type Client struct {
... // other members
token string // unexported unless there is a special reason to do otherwise
}
func NewClient(c echo.Context, email, password string) (*Client, error) {
user := users.User{}
cl := Client{}
... // your original method
cl.token = token
return &cl, nil
}
func (c *Client) DoSomething(...) ... { ... }
I'm a bit new to Go and I'm having trouble converting a response object from an API call into different structures based on the request type
Essentially, I have one func which sends out a request
func (fpc *FPClient) request(path string, method string, params interface{}, Token string, response interface{}) *dto.AppError {
client := &http.Client{
Timeout: time.Second * 15,
}
requestBody, err := json.Marshal(params)
if err != nil {
//
}
req, _ := http.NewRequest(method, path, bytes.NewBuffer(requestBody))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Cookie", fmt.Sprintf("cookie=%s;", Token))
req.SetBasicAuth(fpc.username, fpc.password)
resp, err := client.Do(req)
if err != nil {
//
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
//
}
if FPErr := fpc.processErrors(resp, body); FPerr != nil {
return FPErr
}
responseData := FPApiSuccess{Head: response, Body: response}
if err := json.Unmarshal(body, &responseData); err != nil {
//
}
fmt.Printf("\n\n client Response : \n %+v \n", responseData.Body)
return nil
}
The struct for FPApiSuccess is:
type FPApiSuccess struct {
Body interface{} `json:"body"`
Head interface{} `json:"head"`
}
Right now, there are 2 calling functions and the API response expected is a bit different for both
Both API responses have the below structure
{
"head": {},
"body": {}
}
However, the nested details in each key is different based on the API used.
I want to capture the head and body keys in a struct argument I give and send it back to the calling function. The response argument in the request function is a different struct type based on the calling function.
I'm unable to get this to work - I'm only getting back a blank struct from the request function. This is the fmt.PrintF log
client Response :
&{Body:{BOrderID:0 CC: Exch: EOID: Type: Local:0 Message: } Head:{ResponseCode: Status: StatusDescription:}}
This is an empty struct - ideally, it should be populated with the values retrieved from the API.
For reference, heres the struct passed as an argument as response in the request function:
type FPApiResponse struct {
Body FPBodyResponse `json:"body"`
Head FPHeadResponse `json:"head"`
}
type FPHeadResponse struct {
ResponseCode string `json:"responseCode"`
Status string `json:"status"`
StatusDescription string `json:"statusDescription"`
}
type FPBodyResponse struct {
BOrderID int `json:"BOrderID"`
CC string `json:"CC"`
Exch string `json:"Exch"`
EOID string `json:"EOID"`
Type string `json:"Type"`
Local int `json:"Local"`
Message string `json:"Message"`
}
Update
So I did this; instead of
responseData := FPApiSuccess{Head: response, Body: response}
I did this
responseData := fivePaisaApiSuccess{}
So now, I get the below in console
Client Response :
{Body:map[BOrderID:0 CC:52715111 Type:D Local:0 Message:Invalid Session ] Head:map[responseCode:5POrdReq status:0 statusDescription:Success]}
So essentially, this works, but the calling function doesn't seem to get the proper response:
Here's the calling function
func (fpc *FPClient) PlaceOrder(orderParams dto.OrderBodyParams, variety string, Token string) (string, *dto.AppError) {
var result FPApiResponse
headParams := dto.FFPOrderHeadParams{
//
}
FPOrderParams := dto.FPOrderParams{
//
}
FPErr := fpc.request(FPURL+FPPlaceOrder, http.MethodPost, FPOrderParams, brokerAccessToken, &result)
if FPErr != nil {
return "", FPErr
}
fmt.Printf("\n\n Client result : \n %+v \n", result)
if result.Head.Status != "0" {
//
}
if result.Body.Status != 0 {
//
}
return strconv.Itoa(result.Body.Broker), nil
}
The result value is blank:
{Body:{BOId:0 CC: Exch: Type: Local:0 Message: Status:0} Head:{ResponseCode: Status: StatusDescription:}}
I don't understand, this pointer is getting populated in the request function
Here's the struct I'm passing to the request:
type FPApiResponse struct {
Body FPBodyResponse `json:"body"`
Head FPHeadResponse `json:"head"`
}