18F/cg-dashboard

View on GitHub
helpers/helpers.go

Summary

Maintainability
A
0 mins
Test Coverage
package helpers

import (
    "crypto/rand"
    "encoding/base64"
    "net/http"
    "time"

    "golang.org/x/oauth2"
)

// TimeoutConstant is a constant which holds how long any incoming request should wait until we timeout.
// This is useful as some calls from the Go backend to the external API may take a long time.
// If the user decides to refresh or if the client is polling, multiple requests might build up. This timecaps them.
var TimeoutConstant = time.Second * 20

// GetValidToken is a helper function that returns a token struct only if it finds a non expired token for the session.
func GetValidToken(req *http.Request, rw http.ResponseWriter, settings *Settings) *oauth2.Token {
    // Get session from session store.
    session, _ := settings.Sessions.Get(req, "session")
    // If for some reason we can't get or create a session, bail out.
    if session == nil {
        return nil
    }

    // Attempt to get the token from this session.
    token, ok := session.Values["token"].(oauth2.Token)
    if !ok {
        return nil
    }

    // Save our original refresh token, we might need it further down
    originalRefreshToken := token.RefreshToken

    // Will ensure not expired
    rv, err := settings.OAuthConfig.TokenSource(settings.CreateContext(), &token).Token()
    if err != nil {
        return nil
    }

    // Did it change? if so save it in our cookie so we don't have to refresh again on every request
    if rv.AccessToken != token.AccessToken || !rv.Expiry.Equal(token.Expiry) {
        // We are using opaque UAA tokens, so make sure we replace any new refresh
        // token received with the smaller opaque one that we saved off earlier, or we
        // may hit session storage limits.
        rv.RefreshToken = originalRefreshToken
        session.Values["token"] = *rv
        session.Save(req, rw)
    }

    return rv
}

// GenerateRandomBytes returns securely generated random bytes.
// Borrowed from https://elithrar.github.io/article/generating-secure-random-numbers-crypto-rand/
func GenerateRandomBytes(n int) ([]byte, error) {
    b := make([]byte, n)
    _, err := rand.Read(b)
    // Note that err == nil only if we read len(b) bytes.
    if err != nil {
        return nil, err
    }

    return b, nil
}

// GenerateRandomString returns a URL-safe, base64 encoded
// securely generated random string.
// Borrowed from https://elithrar.github.io/article/generating-secure-random-numbers-crypto-rand/
func GenerateRandomString(s int) (string, error) {
    b, err := GenerateRandomBytes(s)
    return base64.URLEncoding.EncodeToString(b), err
}