// ToTransactionMutator returns go-stellar-base TransactionMutator func (op AllowTrustOperationBody) ToTransactionMutator() b.TransactionMutator { mutators := []interface{}{ b.AllowTrustAsset{op.AssetCode}, b.Trustor{op.Trustor}, b.Authorize{op.Authorize}, } if op.Source != nil { mutators = append(mutators, b.SourceAccount{*op.Source}) } return b.AllowTrust(mutators...) }
// Authorize implements /authorize endpoint func (rh *RequestHandler) Authorize(w http.ResponseWriter, r *http.Request) { request := &bridge.AuthorizeRequest{} request.FromRequest(r) err := request.Validate(rh.Config.Assets, rh.Config.Accounts.IssuingAccountID) if err != nil { errorResponse := err.(*protocols.ErrorResponse) log.WithFields(errorResponse.LogData).Error(errorResponse.Error()) server.Write(w, errorResponse) return } operationMutator := b.AllowTrust( b.Trustor{request.AccountID}, b.Authorize{true}, b.AllowTrustAsset{request.AssetCode}, ) submitResponse, err := rh.TransactionSubmitter.SubmitTransaction( rh.Config.Accounts.AuthorizingSeed, operationMutator, nil, ) if err != nil { log.WithFields(log.Fields{"err": err}).Error("Error submitting transaction") server.Write(w, protocols.InternalServerError) return } errorResponse := bridge.ErrorFromHorizonResponse(submitResponse) if errorResponse != nil { log.WithFields(errorResponse.LogData).Error(errorResponse.Error()) server.Write(w, errorResponse) return } server.Write(w, &submitResponse) }
func (rh *RequestHandler) Authorize(w http.ResponseWriter, r *http.Request) { accountId := r.PostFormValue("account_id") assetCode := r.PostFormValue("asset_code") _, err := keypair.Parse(accountId) if err != nil { log.Print("Invalid accountId parameter: ", accountId) errorBadRequest(w, errorResponseString("invalid_account_id", "accountId parameter is invalid")) return } if !rh.isAssetAllowed(assetCode) { log.Print("Asset code not allowed: ", assetCode) errorBadRequest(w, errorResponseString("invalid_asset_code", "Given assetCode not allowed")) return } operationMutator := b.AllowTrust( b.Trustor{accountId}, b.Authorize{true}, b.AllowTrustAsset{assetCode}, ) submitResponse, err := rh.TransactionSubmitter.SubmitTransaction( *rh.Config.Accounts.AuthorizingSeed, operationMutator, nil, ) if err != nil { log.Print("Error submitting transaction ", err) errorServerError(w) return } if submitResponse.Errors != nil { var errorString string if submitResponse.Errors.OperationErrorCode != "" { switch submitResponse.Errors.OperationErrorCode { case "allow_trust_malformed": errorString = errorResponseString( "allow_trust_malformed", "Asset name is malformed.", ) case "allow_trust_not_trustline": errorString = errorResponseString( "allow_trust_not_trustline", "Trustor does not have a trustline yet.", ) case "allow_trust_trust_not_required": errorString = errorResponseString( "allow_trust_trust_not_required", "Authorizing account does not require allowing trust. Set AUTH_REQUIRED_FLAG on your account to use this feature.", ) case "allow_trust_trust_cant_revoke": errorString = errorResponseString( "allow_trust_trust_cant_revoke", "Authorizing account has AUTH_REVOCABLE_FLAG set. Can't revoke the trustline.", ) default: errorServerError(w) return } } else if submitResponse.Errors.TransactionErrorCode != "" { switch submitResponse.Errors.TransactionErrorCode { case "transaction_bad_seq": errorString = errorResponseString( "transaction_bad_seq", "Bad Sequence. Please, try again.", ) default: errorServerError(w) return } } errorBadRequest(w, errorString) return } json, err := json.MarshalIndent(submitResponse, "", " ") if err != nil { errorServerError(w) return } w.Write(json) }
func TestRequestHandlerAuthorize(t *testing.T) { mockTransactionSubmitter := new(mocks.MockTransactionSubmitter) IssuingSeed := "SC34WILLHVADXMP6ACPMIRA6TRAWJMVCLPFNW7S6MUMXJVLAZUC4EWHP" AuthorizingSeed := "SC37TBSIAYKIDQ6GTGLT2HSORLIHZQHBXVFI5P5K4Q5TSHRTRBK3UNWG" config := config.Config{ Assets: []string{"USD", "EUR"}, Accounts: &config.Accounts{ // GD4I7AFSLZGTDL34TQLWJOM2NHLIIOEKD5RHHZUW54HERBLSIRKUOXRR IssuingSeed: &IssuingSeed, // GBQXA3ABGQGTCLEVZIUTDRWWJOQD5LSAEDZAG7GMOGD2HBLWONGUVO4I AuthorizingSeed: &AuthorizingSeed, }, } requestHandler := RequestHandler{Config: &config, TransactionSubmitter: mockTransactionSubmitter} testServer := httptest.NewServer(http.HandlerFunc(requestHandler.Authorize)) defer testServer.Close() Convey("Given authorize request", t, func() { Convey("When accountId is invalid", func() { accountId := "GD3YBOYIUVLU" assetCode := "USD" Convey("it should return error", func() { statusCode, response := getResponse(testServer, url.Values{"account_id": {accountId}, "asset_code": {assetCode}}) responseString := strings.TrimSpace(string(response)) assert.Equal(t, 400, statusCode) assert.Equal(t, errorResponseString("invalid_account_id", "accountId parameter is invalid"), responseString) }) }) Convey("When assetCode is invalid", func() { accountId := "GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632" assetCode := "GBP" Convey("it should return error", func() { statusCode, response := getResponse(testServer, url.Values{"account_id": {accountId}, "asset_code": {assetCode}}) responseString := strings.TrimSpace(string(response)) assert.Equal(t, 400, statusCode) assert.Equal(t, errorResponseString("invalid_asset_code", "Given assetCode not allowed"), responseString) }) }) Convey("When params are valid", func() { accountId := "GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632" assetCode := "USD" operation := b.AllowTrust( b.Trustor{accountId}, b.Authorize{true}, b.AllowTrustAsset{assetCode}, ) Convey("transaction fails", func() { mockTransactionSubmitter.On( "SubmitTransaction", *config.Accounts.AuthorizingSeed, operation, nil, ).Return( horizon.SubmitTransactionResponse{}, errors.New("Error sending transaction"), ).Once() Convey("it should return server error", func() { statusCode, response := getResponse(testServer, url.Values{"account_id": {accountId}, "asset_code": {assetCode}}) responseString := strings.TrimSpace(string(response)) assert.Equal(t, 500, statusCode) assert.Equal(t, getServerErrorResponseString(), responseString) mockTransactionSubmitter.AssertExpectations(t) }) }) Convey("transaction succeeds", func() { var ledger uint64 ledger = 100 expectedSubmitResponse := horizon.SubmitTransactionResponse{ Ledger: &ledger, } mockTransactionSubmitter.On( "SubmitTransaction", *config.Accounts.AuthorizingSeed, operation, nil, ).Return(expectedSubmitResponse, nil).Once() Convey("it should succeed", func() { statusCode, response := getResponse(testServer, url.Values{"account_id": {accountId}, "asset_code": {assetCode}}) var actualSubmitTransactionResponse horizon.SubmitTransactionResponse json.Unmarshal(response, &actualSubmitTransactionResponse) assert.Equal(t, 200, statusCode) assert.Equal(t, expectedSubmitResponse, actualSubmitTransactionResponse) mockTransactionSubmitter.AssertExpectations(t) }) }) }) }) }
func TestRequestHandlerAuthorize(t *testing.T) { mockTransactionSubmitter := new(mocks.MockTransactionSubmitter) config := config.Config{ Assets: []config.Asset{ {Code: "USD", Issuer: "GD4I7AFSLZGTDL34TQLWJOM2NHLIIOEKD5RHHZUW54HERBLSIRKUOXRR"}, {Code: "EUR", Issuer: "GD4I7AFSLZGTDL34TQLWJOM2NHLIIOEKD5RHHZUW54HERBLSIRKUOXRR"}, }, Accounts: config.Accounts{ IssuingAccountID: "GD4I7AFSLZGTDL34TQLWJOM2NHLIIOEKD5RHHZUW54HERBLSIRKUOXRR", // GBQXA3ABGQGTCLEVZIUTDRWWJOQD5LSAEDZAG7GMOGD2HBLWONGUVO4I AuthorizingSeed: "SC37TBSIAYKIDQ6GTGLT2HSORLIHZQHBXVFI5P5K4Q5TSHRTRBK3UNWG", }, } requestHandler := RequestHandler{Config: &config, TransactionSubmitter: mockTransactionSubmitter} testServer := httptest.NewServer(http.HandlerFunc(requestHandler.Authorize)) defer testServer.Close() Convey("Given authorize request", t, func() { Convey("When accountId is invalid", func() { accountID := "GD3YBOYIUVLU" assetCode := "USD" Convey("it should return error", func() { statusCode, response := net.GetResponse(testServer, url.Values{"account_id": {accountID}, "asset_code": {assetCode}}) responseString := strings.TrimSpace(string(response)) assert.Equal(t, 400, statusCode) expected := test.StringToJSONMap(`{ "code": "invalid_parameter", "message": "Invalid parameter.", "data": { "name": "account_id" } }`) assert.Equal(t, expected, test.StringToJSONMap(responseString)) }) }) Convey("When assetCode is invalid", func() { accountID := "GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632" assetCode := "GBP" Convey("it should return error", func() { statusCode, response := net.GetResponse(testServer, url.Values{"account_id": {accountID}, "asset_code": {assetCode}}) responseString := strings.TrimSpace(string(response)) assert.Equal(t, 400, statusCode) expected := test.StringToJSONMap(`{ "code": "invalid_parameter", "message": "Invalid parameter.", "data": { "name": "asset_code" } }`) assert.Equal(t, expected, test.StringToJSONMap(responseString)) }) }) Convey("When params are valid", func() { accountID := "GDSIKW43UA6JTOA47WVEBCZ4MYC74M3GNKNXTVDXFHXYYTNO5GGVN632" assetCode := "USD" operation := b.AllowTrust( b.Trustor{accountID}, b.Authorize{true}, b.AllowTrustAsset{assetCode}, ) Convey("transaction fails", func() { mockTransactionSubmitter.On( "SubmitTransaction", config.Accounts.AuthorizingSeed, operation, nil, ).Return( horizon.SubmitTransactionResponse{}, errors.New("Error sending transaction"), ).Once() Convey("it should return server error", func() { statusCode, response := net.GetResponse(testServer, url.Values{"account_id": {accountID}, "asset_code": {assetCode}}) responseString := strings.TrimSpace(string(response)) assert.Equal(t, 500, statusCode) expected := test.StringToJSONMap(`{ "code": "internal_server_error", "message": "Internal Server Error, please try again." }`) assert.Equal(t, expected, test.StringToJSONMap(responseString)) mockTransactionSubmitter.AssertExpectations(t) }) }) Convey("transaction succeeds", func() { var ledger uint64 ledger = 100 expectedSubmitResponse := horizon.SubmitTransactionResponse{ Ledger: &ledger, } mockTransactionSubmitter.On( "SubmitTransaction", config.Accounts.AuthorizingSeed, operation, nil, ).Return(expectedSubmitResponse, nil).Once() Convey("it should succeed", func() { statusCode, response := net.GetResponse(testServer, url.Values{"account_id": {accountID}, "asset_code": {assetCode}}) var actualSubmitTransactionResponse horizon.SubmitTransactionResponse json.Unmarshal(response, &actualSubmitTransactionResponse) assert.Equal(t, 200, statusCode) assert.Equal(t, expectedSubmitResponse, actualSubmitTransactionResponse) mockTransactionSubmitter.AssertExpectations(t) }) }) }) }) }