go/pastee.go

195 lines
3.7 KiB
Go

package pastee
import (
"bytes"
"encoding/json"
"io"
"math/rand"
"net/http"
"net/url"
"strconv"
"time"
"paste.ee/go/cryptojs"
)
func New(key string) *Pastee {
return &Pastee{ApiKey: key, Base: "https://api.paste.ee/v1", Client: &http.Client{Timeout: time.Minute}}
}
func (p *Pastee) Authenticate(username, password string) (*AuthResponse, error) {
body, err := json.Marshal(&authRequest{username, password})
if err != nil {
return nil, err
}
req, err := p.newRequest("POST", "users/authenticate", bytes.NewReader(body))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Content-Length", strconv.Itoa(len(body)))
res, err := p.Client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
var response AuthResponse
if err := json.NewDecoder(res.Body).Decode(&response); err != nil {
return nil, err
}
return &response, nil
}
func (p *Pastee) List() (*PasteListResponse, error) {
q := &url.Values{}
q.Set("perpage", "25")
q.Set("page", "1")
req, err := p.newRequest("GET", "pastes?" + q.Encode(), nil)
if err != nil {
return nil, err
}
res, err := p.Client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
var response PasteListResponse
if err := json.NewDecoder(res.Body).Decode(&response); err != nil {
return nil, err
}
return &response, nil
}
func (p *Pastee) Get(id string) (*Paste, error) {
req, err := p.newRequest("GET", "pastes/" + id, nil)
if err != nil {
return nil, err
}
res, err := p.Client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
var response Paste
if err := json.NewDecoder(res.Body).Decode(&response); err != nil {
return nil, err
}
return &response, nil
}
func (p *Pastee) Submit(paste *Paste) (*PasteResponse, error) {
var key string
if paste.Encrypted {
key = RandStringBytesMaskImprSrc(32)
var err error
for _, section := range paste.Sections {
section.Contents, err = cryptojs.Encrypt(section.Contents, key)
if err != nil {
return nil, err
}
}
}
body, err := json.Marshal(paste)
if err != nil {
return nil, err
}
req, err := p.newRequest("POST", "pastes", bytes.NewReader(body))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Content-Length", strconv.Itoa(len(body)))
res, err := p.Client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
var response PasteResponse
if err := json.NewDecoder(res.Body).Decode(&response); err != nil {
return nil, err
}
if key != "" {
response.Key = key
}
return &response, nil
}
func (p *Pastee) newRequest(method, path string, body io.Reader) (*http.Request, error) {
req, err := http.NewRequest(method, p.Base + "/" + path, body)
if err != nil {
return nil, err
}
req.Header.Set("X-Auth-Token", p.ApiKey)
return req, nil
}
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const (
letterIdxBits = 6 // 6 bits to represent a letter index
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
)
var src = rand.NewSource(time.Now().UnixNano())
func RandStringBytesMaskImprSrc(n int) string {
b := make([]byte, n)
// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
if remain == 0 {
cache, remain = src.Int63(), letterIdxMax
}
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
b[i] = letterBytes[idx]
i--
}
cache >>= letterIdxBits
remain--
}
return string(b)
}