Submitting form with golang http library - forms

Oke, I'm currently trying to login in to my school website, with my own Crawler. Altough they have some protection against login. First I do a Get request to the Website so I get the token from the hidden Input field. That token I use in my next Post request to login to the url! But for some reason the http response is that I cannot resubmit the form. But with doing the same in Postman rest client (chrome plugin) I can login!
When I try to submit a form to this url:
postLoginUrl = "?username=%s&password=%s&submit=inloggen&_eventId=submit&credentialsType=ldap&lt=%s"
loginUrl = "https://login.hro.nl/v1/login"
where %s are filled in credentials
req, err := client.Post(loginUrl, "application/x-www-form-urlencoded", strings.NewReader(uri))
I'm getting as response that the Form cannot be resubmitted.
But when I try it with Postman rest client, I'm allowed to login.
code for Csrf token:
func getCSRFtoken() (key string) {
doc, err := goquery.NewDocument(loginUrl)
if err != nil {
log.Fatal(err)
}
types := doc.Find("input")
for node := range types.Nodes {
singlething := types.Eq(node)
hidden_input, _ := singlething.Attr("type")
if hidden_input == "hidden" {
key, _ := singlething.Attr("value")
return key
}
}
return ""
}
goquery.NewDocument is a http.Get()
My question now is, how does the URL get's formatted from the library

Maybe you would be better off using:
(c *Client)PostForm(url string, data url.Values) (resp *Response, err error)
from net/http like http://play.golang.org/p/8D6XI6arkz
With the params in url.Values (instead of concatenating the strings, like you are doing now.)

Related

Receive Consumption REQUEST NOTIFY and Send Consumption Info

apple will send a Consumption_Request notify to merchant server if user start a refund.
When I tried to process the Consumption Request notify and call the Send Consumption Info interface to send user consumption info to apple server, I got two forms of response.
case 1 :
when my param is wrong , the response like this :enter image description here
case 2 :
when my param is right , the response code is 401 ,like this : enter image description here
And I found 401 mean Unauthorized . So maybe my JWT check failed.
SO my question is how do you generate your JWT token? Is any demo ?
and how do you get your secret key file(the .p8 file. I suspect that I got a wrong file)?
how do you generate your JWT token?
here is one sample by golang
func readPrivateKeyFromFile(keyFile string) (*ecdsa.PrivateKey, error) {
bytes, err := ioutil.ReadFile(keyFile)
if err != nil {
return nil, err
}
block, _ := pem.Decode(bytes)
if block == nil {
return nil, errors.New("appstore private key must be a valid .p8 PEM file")
}
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
switch pk := key.(type) {
case *ecdsa.PrivateKey:
return pk, nil
default:
return nil, errors.New("appstore private key must be of type ecdsa.PrivateKey")
}
}
func generateToken(privateKey *ecdsa.PrivateKey) (string, error) {
token := jwt.NewWithClaims(jwt.SigningMethodES256, jwt.MapClaims{
"iss": "issuerId,
"isa": time.Now().Unix(),
"exp": expireTIme,
"aud": "appstoreconnect-v1",
"nonce": "uuid",
"bid": "bid",
})
token.Header["kid"] = "keyId"
token.Header["alg"] = "ES256"
token.Header["typ"] = "JWT"
return token.SignedString(privateKey)
}
how do you get your secret key file(the .p8 file. I suspect that I got a wrong file)?
Please refer to doc https://developer.apple.com/documentation/appstoreserverapi/creating_api_keys_to_use_with_the_app_store_server_api?changes=latest_major

Building a Rest Request with Dynamic Segments

I am trying to test a handler, the handler is below:
router.HandleFunc("/address/{id}", DeletePerson).Methods("DELETE")
The request that I created was:
request, _ := http.NewRequest("DELETE", "/address/2", nil)
DeletePerson(response, request)
using github.com/gorilla/mux I attempted to extract the "id" with
params = mux.Vars(request)
item := params["id"]
returns: params = map[] and item = ""
However, if I call DeletePerson with the curl command:
curl -X DELETE http://localhost:8000/address/2
I get: params = map["id"] and item = "2"
HOW Do I construct a URL request that get the results like Curl?
I think the problem is that you don't put the full URL in the request. And I guess that you ignore the error while executing the request. If you don't put the full URL it will complains something like this: panic: Delete /address/2: unsupported protocol scheme ""
The following code works OK in my machine:
package main
import "net/http"
func main() {
r, err := http.NewRequest("DELETE", "http://localhost:8080/address/2", nil)
if err != nil {
panic(err)
}
if _, err := http.DefaultClient.Do(r); err != nil {
panic(err)
}
}
Hope this helps :)
If you call DeletePerson directly, the request doesn't pass through the router, which parses the parameters in the request path.
Also, http.NewRequest returns a client request. Either add scheme and host to the URL and pass the request to http.Client.Do, or use httptest.NewRequest to create a server request directly.
NewRequest returns a new incoming server Request, suitable for passing to an http.Handler for testing.
request := httptest.NewRequest("DELETE", "/address/2", nil)
mux.ServeHTTP(response, request)

Sending data from client to server - REST webservice

I am developing a client-server application using RESTful web services.
I want to ask for user input on the client and send it to the server and use that name in the rest of my program but I cannot send the name to the server properly.
Below is a part of my program:
Client:
func main() {
//getting input
fmt.Println("Please enter your name: ")
reader := bufio.NewReader(os.Stdin)
myName, _ := reader.ReadString('\n')
client := &http.Client{
CheckRedirect: nil,
}
reply, err := http.NewRequest("GET", "http://localhost:8080/", nil)
reply.Header.Add("username", myName)
client.Do(reply)
if err != nil {
fmt.Println(err)
}
Server:
func CreateClient(w http.ResponseWriter, r *http.Request) {
clientName := r.Header.Get("username")
fmt.Println(clientName, "---------")//it's empty
cli := &Client{
currentRoom: nil, //starts as nil because the user is not initally in a room
outputChannel: make(chan string),
name: clientName,
}
Members = append(Members, cli)
reply := cli.name
fmt.Fprintf(w, reply)
}
on the client side, reply (reply.Header.Add("username", myName)) has the user name in the header but on the server side clientName (clientName := r.Header.Get("username")) is empty so the rest of my program won't run.
My problem is that I cannot send the user input to the server and take it back on the client side.
Can someone tell me how I can solve the problem?
You may want to have a look at http query string. Wikipedia
Sending the username.
req := http.NewRequest("GET","localhost:8080",nil)
q:=req.URL.Query()
q.Add("username",myName)
req.URL.RawQuery = q.Encode()
Resp,err:=http. Client{}.Do(req)
Recieving the username:
clientName := r.URL.Query()["username"][0]
Note that if your are going to do the same with password or any other sensitive data, please do some research on how to make it secure and DO NOT copy this code.

sending cookie in API Rest golang

am working in Golang, I am building an API-Rest and am wondering, can I set cookies using restful?
I am building the methos related to the authentication of the users: login, logout,sign up, etc. and by now am trying to set a cookie in the response with the generated uuid. I have this:
func Login(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
...some code....
c := &http.Cookie{
Name: "session",
Value: uuid.NewV4().String(),
}
http.SetCookie(w, c)
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
json.NewEncoder(w).Encode(user)
w.WriteHeader(fasthttp.StatusOK)
}
But in the response I don't get any cookie, so, if is possible, how is the proper way to make it? Thank you!
You can indeed set cookies.
This would feel like it's too short of an answer though. Remember that a REST API is nothing more than a HTTP server with a very strict usage of how it should be called and what it returns. As such, you can safely set cookies.
The question is though, if that is really something you should do, have a look at JSON Web Tokens and JSON Web Encryption instead. There are Go libraries available for both. The rationale for using JWE and JWT over cookies is that you usually want a REST API to be as stateless as possible; preferring for the Client to keep state instead.
If you insist on using cookies though, consider using Gorilla's securecookie API instead, as you probably do not want people peeking into your cookie's contents. You can use it as so:
import "github.com/gorilla/securecookie"
s := securecoookie.New([]byte("very-secret-1234"), byte[]("much-hidden-5678"))
func SetCookieHandler(w http.ResponseWriter, r *http.Request) {
value := map[string]string{
"foo": "bar",
}
if encoded, err := s.Encode("cookie-name", value); err == nil {
cookie := &http.Cookie{
Name: "cookie-name",
Value: encoded,
Path: "/",
Secure: true,
HttpOnly: true,
}
http.SetCookie(w, cookie)
}
}
Similarly, you can retrieve the Cookie's contents like this:
func ReadCookieHandler(w http.ResponseWriter, r *http.Request) {
if cookie, err := r.Cookie("cookie-name"); err == nil {
value := make(map[string]string)
if err = s2.Decode("cookie-name", cookie.Value, &value); err == nil {
fmt.Fprintf(w, "The value of foo is %q", value["foo"])
}
}
}

Parsing Github response for access_token

Just messing around with Github API and oauth. I have got to the point where I receive the access_token back from GH.
I have so far:
url := "https://github.com/login/oauth/access_token"
params := map[string]string{"client_id": client_id, "client_secret": client_secret, "code": code}
data, _ := json.Marshal(params)
resp, _ := http.Post(url, "application/json", bytes.NewBuffer(data))
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
but I would now like to access the response parts. According to the GH docs, they are in the form
access_token=e72e16c7e42f292c6912e7710c838347ae178b4a&scope=user%2Cgist&token_type=bearer
Do I need to parse the string or is there a "better" way?
This is a URL query string. You can use the url package to parse it and get a url.Values (which is just a map) out.
resp := "access_token=e72e16c7e42f292c6912e7710c838347ae178b4a&scope=user%2Cgist&token_type=bearer"
values, err := url.ParseQuery(resp)
if err != nil {
panic(err)
}
fmt.Println("access_token:", values["access_token"])
fmt.Println("token_type:", values["token_type"])
Play link