Files
aleesa-webapp-go/vendor/gopkg.in/masci/flickr.v3/client.go
2024-09-17 23:59:38 +03:00

162 lines
4.3 KiB
Go

package flickr
import (
"bytes"
"crypto/hmac"
"crypto/md5"
"crypto/sha1"
"encoding/base64"
"fmt"
"math/rand"
"net/http"
"net/url"
"sort"
"strings"
"time"
)
// Generate a random string of 8 chars, needed for OAuth signature
func generateNonce() string {
rand.Seed(time.Now().UTC().UnixNano())
// For convenience, use a set of chars we don't need to url-escape
var letters = []rune("123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ")
b := make([]rune, 8)
for i := range b {
b[i] = letters[rand.Intn(len(letters))]
}
return string(b)
}
// An utility type to wrap all resources and data needed to complete requests
// to the Flickr API
type FlickrClient struct {
// Flickr application api key
ApiKey string
// Flickr application api secret
ApiSecret string
// A generic HTTP client to perform GET and POST requests
HTTPClient *http.Client
// The base url for API endpoints
EndpointUrl string
// A string containing POST or GET, needed for OAuth signing
HTTPVerb string
// A set of url params to query the API
Args url.Values
// User access token
OAuthToken string
// User secret token
OAuthTokenSecret string
// User flickr ID
Id string
}
// Create a Flickr client, apiKey and apiSecret are mandatory
func NewFlickrClient(apiKey string, apiSecret string) *FlickrClient {
return &FlickrClient{
ApiKey: apiKey,
ApiSecret: apiSecret,
HTTPClient: &http.Client{},
HTTPVerb: "GET",
Args: url.Values{},
}
}
// Sign the next request performed by the FlickrClient
func (c *FlickrClient) Sign(tokenSecret string) {
// the "oauth_signature" param must not be included in the signing process
c.Args.Del("oauth_signature")
c.Args.Set("oauth_signature", c.getSignature(tokenSecret))
}
// Set the mandatory params for an OAuth request
func (c *FlickrClient) SetOAuthDefaults() {
c.Args.Add("oauth_version", "1.0")
c.Args.Add("oauth_signature_method", "HMAC-SHA1")
c.Args.Add("oauth_nonce", generateNonce())
c.Args.Add("oauth_timestamp", fmt.Sprintf("%d", time.Now().Unix()))
}
// Sign the request with a default set of OAuth parameters, needed to authorize
// users for certain writing/destructive operations.
func (c *FlickrClient) OAuthSign() {
c.SetOAuthDefaults()
c.Args.Set("oauth_token", c.OAuthToken)
c.Args.Set("oauth_consumer_key", c.ApiKey)
c.Args.Set("api_key", c.ApiKey)
c.Sign(c.OAuthTokenSecret)
}
// Specific signing process for API calls: not the same as OAuth sign, used
// for requests that don't need user authorizations.
func (c *FlickrClient) ApiSign() {
c.Args.Set("api_key", c.ApiKey)
// the "api_sig" param must not be included in the signing process
c.Args.Del("api_sig")
c.Args.Set("api_sig", c.getApiSignature(c.ApiSecret))
}
// Evaluate the complete URL to make requests (base url + params)
func (c *FlickrClient) GetUrl() string {
return fmt.Sprintf("%s?%s", c.EndpointUrl, c.Args.Encode())
}
// Remove all query params
func (c *FlickrClient) ClearArgs() {
c.Args = url.Values{}
}
// Reset Args and set the default endpoint
func (c *FlickrClient) Init() {
c.ClearArgs()
c.EndpointUrl = API_ENDPOINT
}
// Get the base string to compose the signature
func (c *FlickrClient) getSigningBaseString() string {
request_url := url.QueryEscape(c.EndpointUrl)
flickr_encoded := strings.Replace(c.Args.Encode(), "+", "%20", -1)
query := url.QueryEscape(flickr_encoded)
ret := fmt.Sprintf("%s&%s&%s", c.HTTPVerb, request_url, query)
return ret
}
// Compute the signature of a signed request
func (c *FlickrClient) getSignature(token_secret string) string {
key := fmt.Sprintf("%s&%s", url.QueryEscape(c.ApiSecret), url.QueryEscape(token_secret))
base_string := c.getSigningBaseString()
mac := hmac.New(sha1.New, []byte(key))
mac.Write([]byte(base_string))
ret := base64.StdEncoding.EncodeToString(mac.Sum(nil))
return ret
}
// Sign API requests. This method differs from the signing process needed for
// OAuth authenticated requests.
func (c *FlickrClient) getApiSignature(token_secret string) string {
var buf bytes.Buffer
buf.WriteString(token_secret)
keys := make([]string, 0, len(c.Args))
for k := range c.Args {
keys = append(keys, k)
}
// args needs to be in alphabetical order
sort.Strings(keys)
for _, k := range keys {
arg := c.Args[k][0]
buf.WriteString(k)
buf.WriteString(arg)
}
base := buf.String()
data := []byte(base)
return fmt.Sprintf("%x", md5.Sum(data))
}