Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix hoormund bug so we don't ignore errors from fetching tokens #749

Merged
merged 1 commit into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 17 additions & 19 deletions handlers/hormuud/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"log/slog"
"net/http"
Expand All @@ -15,7 +16,6 @@
"github.com/nyaruka/courier"
"github.com/nyaruka/courier/handlers"
"github.com/nyaruka/gocommon/urns"
"github.com/pkg/errors"
)

var (
Expand Down Expand Up @@ -77,10 +77,17 @@
}

func (h *handler) Send(ctx context.Context, msg courier.MsgOut, res *courier.SendResult, clog *courier.ChannelLog) error {
token, err := h.FetchToken(ctx, msg.Channel(), msg, clog)
username := msg.Channel().StringConfigForKey(courier.ConfigUsername, "")
password := msg.Channel().StringConfigForKey(courier.ConfigPassword, "")
if username == "" || password == "" {
return courier.ErrChannelConfig
}

Check warning on line 84 in handlers/hormuud/handler.go

View check run for this annotation

Codecov / codecov/patch

handlers/hormuud/handler.go#L83-L84

Added lines #L83 - L84 were not covered by tests

token, err := h.FetchToken(ctx, msg.Channel(), msg, username, password, clog)
if err != nil {
return errors.Wrapf(err, "unable to fetch token")
return err
}

parts := handlers.SplitMsgByChannel(msg.Channel(), handlers.GetTextAndAttachments(msg), maxMsgLength)
for _, part := range parts {
payload := &mtPayload{}
Expand Down Expand Up @@ -121,7 +128,7 @@
}

// FetchToken gets the current token for this channel, either from Redis if cached or by requesting it
func (h *handler) FetchToken(ctx context.Context, channel courier.Channel, msg courier.MsgOut, clog *courier.ChannelLog) (string, error) {
func (h *handler) FetchToken(ctx context.Context, channel courier.Channel, msg courier.MsgOut, username, password string, clog *courier.ChannelLog) (string, error) {
// first check whether we have it in redis
conn := h.Backend().RedisPool().Get()
token, _ := redis.String(conn.Do("GET", fmt.Sprintf("hm_token_%s", channel.UUID())))
Expand All @@ -132,17 +139,6 @@
return token, nil
}

// no token, lets go fetch one
username := channel.StringConfigForKey(courier.ConfigUsername, "")
if username == "" {
return "", fmt.Errorf("Missing 'username' config for HM channel")
}

password := channel.StringConfigForKey(courier.ConfigPassword, "")
if password == "" {
return "", fmt.Errorf("Missing 'password' config for HM channel")
}

form := url.Values{
"Username": []string{username},
"Password": []string{password},
Expand All @@ -155,16 +151,18 @@
req.Header.Set("Accept", "application/json")

resp, respBody, err := h.RequestHTTP(req, clog)
if err != nil || resp.StatusCode/100 != 2 {
return "", errors.Wrapf(err, "error making token request")
if err != nil {
return "", courier.ErrConnectionFailed

Check warning on line 155 in handlers/hormuud/handler.go

View check run for this annotation

Codecov / codecov/patch

handlers/hormuud/handler.go#L155

Added line #L155 was not covered by tests
} else if resp.StatusCode/100 != 2 {
return "", courier.ErrResponseStatus
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this check isn't quite right in so many handlers... maybe we should tweak RequestHTTP to returnErrConnectionFailed or ErrResponseStatus... is there ever a case where we need to handle a non-200 response differently?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can check on that

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the issue is that some handlers want to parse a 400 response to extract an error code

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well either way I think you need to do an audit of RequestHTTP calls...

}

token, err = jsonparser.GetString(respBody, "access_token")
if err != nil {
return "", errors.Wrapf(err, "error getting access_token from response")
return "", fmt.Errorf("error getting access_token from response: %w", err)

Check warning on line 162 in handlers/hormuud/handler.go

View check run for this annotation

Codecov / codecov/patch

handlers/hormuud/handler.go#L162

Added line #L162 was not covered by tests
}
if token == "" {
return "", errors.Errorf("no access token returned")
return "", errors.New("no access token returned")

Check warning on line 165 in handlers/hormuud/handler.go

View check run for this annotation

Codecov / codecov/patch

handlers/hormuud/handler.go#L165

Added line #L165 was not covered by tests
}

expiration, err := jsonparser.GetInt(respBody, "expires_in")
Expand Down
11 changes: 0 additions & 11 deletions handlers/hormuud/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,6 @@ var tokenTestCases = []OutgoingTestCase{
MsgText: "Simple Message",
MsgURN: "tel:+250788383383",
MockResponses: map[string][]*httpx.MockResponse{
"https://smsapi.hormuud.com/api/SendSMS": {
httpx.NewMockResponse(400, nil, []byte(`{"error": "invalid token"}`)),
},
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we shouldn't be making this call if fetching the token failed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

"https://smsapi.hormuud.com/token": {
httpx.NewMockResponse(400, nil, []byte(`{"error": "invalid password"}`)),
},
Expand All @@ -201,14 +198,6 @@ var tokenTestCases = []OutgoingTestCase{
"grant_type": {"password"},
},
},
{
Headers: map[string]string{
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer ",
},
Body: `{"mobile":"250788383383","message":"Simple Message","senderid":"2020","mType":-1,"eType":-1,"UDH":""}`,
},
},
ExpectedError: courier.ErrResponseStatus,
},
Expand Down
Loading