195 lines
3.7 KiB
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)
|
|
} |