Receive Consumption REQUEST NOTIFY and Send Consumption Info - jwt

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

Related

Validation using golang, gin and gorm with postgres like email already exist in database

I have something like this and I would like to check if email already exist in DB:
func RegisterUser(c *gin) {
var user models.User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"messAge": err.Error(),
"data": "",
})
return
}
// **I TRIED SOEMTHING LIKE THIS**
err := database.DB.Find(&user.Email).Error
if err != nil {
c.JSON(401, gin.H{"MESSAGE": "Email ALREADY exist",
return
}
// **but is not working, because ANY mail it give me error**
if !strings.Contains(user.Email, "#") {
c.JSON(400, gin.H{"MESSAGE": utils.ErrEmailWrong})
return
}
if len(user.Password) < 4 {
c.JSON(400, gin.H{"MESSAGE": utils.ErrPasswordLength})
return
}
database.DB.Create(&user)
c.JSON(200, gin.H{
"MESSAGE": "CREATED",
})
}
With this code, every time is telling me that : Email already exist, only works for the first time.
plase read the document:
https://gorm.io/docs/query.html
var userFind models.User
database.DB.Where("email = ?", user.Email).First(&userFind)
Since, your struct object is not a slice. You should use ErrRecordNotFound.
Note : ErrRecordNotFound only works with First, Last, Take which is expected to return some result. And RecordNotFound is removed in V2.
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound){
c.JSON(401, gin.H{"MESSAGE": "Email Not Found",
return
}
c.JSON(401, gin.H{"MESSAGE": "Your Message",
return
}
OR
If you want to avoid the ErrRecordNotFound error, you could use Find like db.Limit(1).Find(&user), the Find method accepts both struct and slice data. And check like this :
result.RowsAffected // returns count of records found
For better understanding refer the link here : https://gorm.io/docs/v2_release_note.html#ErrRecordNotFound and https://gorm.io/docs/query.html
And, If you want to add record in DB though email exist then you should remove unique constraint and also check the error while creating the record. If record successfully created then return success response else return the appropriate error message.
you should validate the input after binding and before db queries
alter your email column to be unique
try to insert the validated data to db
if success => 200 (there was no similar email)
if err => check err code
for example:
func IsUniqueContraintViolation(err error) bool {
if pgError, ok := err.(*pgconn.PgError); ok && errors.Is(err, pgError) {
if pgError.Code == "23505" {
return true
}
}
return false
}
For more Information, you should look GoDoc pg lib and Possible Error Codes
and then, then you can return a suitable error code
btw. hopefully you don't save clear passwords to db :D
ITS FINALLY WORKING ! Thanks for everyone thats answered !

Persistent InvalidCiphertextException using KMS to Decrypt

I have generated my KMS key in Golang using this code
// Create the key
result, err := svc.CreateKey(&kms.CreateKeyInput{
Tags: []*kms.Tag{
{
TagKey: aws.String("CreatedBy"),
TagValue: aws.String("User"),
},
},
})
And this is the line causing the error during Decrypt
//Get body bytes
body, _ := ioutil.ReadAll(resp.Body)
//base64Text := make([]byte, base64.StdEncoding.EncodedLen(len(body)))
//base64.StdEncoding.Encode(base64Text, []byte(body))
//Needs decrypting?
var newfile *bytes.Reader
if decrypt == true {
log.Println("Now decrypting data")
log.Println("resp.SSECustomerAlgorithm : ", resp.SSECustomerAlgorithm)
log.Println("resp.SSEKMSKeyId : ", aws.StringValue(resp.SSEKMSKeyId)) //right key found.
newkms := inputfs.NewKms()
//n := map[string]*string{"CreatedBy": aws.String("User") }
params := &kms.DecryptInput{
CiphertextBlob: body,
//EncryptionContext:n,
}
output, err := newkms.Decrypt(params)
if err != nil {
log.Println("Decrypt error :", err)
}
newbody := output.Plaintext
newfile = bytes.NewReader(newbody)
}
Error at Decrypt error
Decrypt error : InvalidCiphertextException:
status code: 400, request id: b69a8634-1784-4c57-8d3d-2439041249fe
What could possibly cause this? Nothing I do seems to work. Here is a related question: Decrypting using AWS go sdk but i don't see the answer.
It turns out my objects were already decrypted.
My objects were originally KMS encrypted using S3 PUTobject operation.
AWS S3 automatically decrypts such objects on S3 GETobject operation.
I can actually get the particular object in plaintext, so this supports the above statement.
See Request Headers and the Amazon S3 API

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)

go-restful + JWT authentication

I'm trying to plug JWT authentication within a very simple go service written with go-restful.
The code is very similar to:
package main
import (
"github.com/emicklei/go-restful"
"log"
"net/http"
)
type User struct {
Id, Name string
}
type UserList struct {
Users []User
}
func getAllUsers(request *restful.Request, response *restful.Response) {
log.Printf("getAllUsers")
response.WriteEntity(UserList{[]User{{"42", "Gandalf"}, {"3.14", "Pi"}}})
}
func NewUserService() *restful.WebService {
ws := new(restful.WebService)
ws.
Path("/users").
Consumes(restful.MIME_XML, restful.MIME_JSON).
Produces(restful.MIME_JSON, restful.MIME_XML)
ws.Route(ws.GET("").To(getAllUsers))
return ws
}
func main() {
restful.Add(NewUserService())
log.Printf("start listening on localhost:8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
where restful.Request is a wrapper around http.Request.
That being said, it might be possible to use the Auth0 jwt middleware.
But as a golang newbie, I'm a bit lost in the plumbing process. I see that I must use a Filter function like
ws.Filter(jwtAuthentication)
where
func jwtAuthentication(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
// Jwt Magic goes here \o
chain.ProcessFilter(req, resp)
}
But I don't figure how and where should I instanciate the JWT middleware.
Here is the example of filter implementation using auth0/go-jwt-middleware. In real life you probably want to avoid creating new instance of jwtMiddleware every time.
func jwtAuthentication(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
jwtMiddleware := jwtmiddleware.New(jwtmiddleware.Options{
ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
return []byte("My Secret"), nil
},
SigningMethod: jwt.SigningMethodHS256,
})
if err := jwtMiddleware.CheckJWT(resp.ResponseWriter, req.Request); err != nil {
logger.Errorf("Authentication error: %v", err)
}
chain.ProcessFilter(req, resp)
}
After the filter the parsed token will be in the context (auth0/go-jwt-middleware uses gorilla/context). Default context key is user.
Note: when JWTMiddleware.SigningMethod is set, the middleware verifies that tokens are signed with the specific signing algorithm.
If the signing method is not constant, the ValidationKeyGetter callback can be used to implement additional checks.
Important to avoid security issues described here.
Here is example of Login API to generate Token, and JWT Authentication filter to check authentication
import (
"os"
"strings"
"github.com/dgrijalva/jwt-go"
"golang.org/x/crypto/bcrypt"
)
type Token struct {
UserId uint
Username string
jwt.StandardClaims
}
type Account struct {
ID uint
Email string
Password string
Token string
}
func Login(request *restful.Request, response *restful.Response) {
account := &Account{ID: 1, Email: "test#email.com" }
// TODO - account should be pulled from database
tk := &Token{ UserId: account.ID }
token := jwt.NewWithClaims(jwt.GetSigningMethod("HS256"), tk)
tokenString, _ := token.SignedString([]byte("JWT-SECRET-GOES-RIGHT-HERE"))
account.Token = tokenString
account.Password = ''
response.WriteEntity(account)
}
func JwtAuthentication(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
tokenHeader := req.Request.HeaderParameter("Authorization")
if tokenHeader == "" {
resp.WriteErrorString(http.StatusForbidden, "Not Authorized")
return
}
splitted := strings.Split(tokenHeader, " ")
if len(splitted) != 2 {
resp.WriteErrorString(http.StatusForbidden, "Not Authorized")
return
}
tokenPart := splitted[1]
tk := &Token{}
token, err := jwt.ParseWithClaims(tokenPart, tk, func(token *jwt.Token) (interface{}, error) {
return []byte("JWT-SECRET-GOES-RIGHT-HERE"), nil
})
if err != nil { //Malformed token, returns with http code 403 as usual
resp.WriteErrorString(http.StatusForbidden, "Not Authorized")
return
}
if !token.Valid { //Token is invalid, maybe not signed on this server
resp.WriteErrorString(http.StatusForbidden, "Not Authorized")
return
}
chain.ProcessFilter(req, resp)
}
And then apply filter
ws.Filter(JwtAuthentication)

Submitting form with golang http library

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.)