Encryption
This commit is contained in:
		
							
								
								
									
										126
									
								
								cryptojs/cryptojs.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								cryptojs/cryptojs.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,126 @@
 | 
				
			|||||||
 | 
					package cryptojs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/base64"
 | 
				
			||||||
 | 
						"crypto/md5"
 | 
				
			||||||
 | 
						"crypto/aes"
 | 
				
			||||||
 | 
						"crypto/cipher"
 | 
				
			||||||
 | 
						"math/rand"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"git.meow.tf/tyler/go-pastee/evpkdf"
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						keySize = 32
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Encrypt(data, passphrase string) (string, error) {
 | 
				
			||||||
 | 
						salt := make([]byte, 8)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if _, err := rand.Read(salt); err != nil {
 | 
				
			||||||
 | 
							return "", err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						key := make([]byte, keySize)
 | 
				
			||||||
 | 
						iv := make([]byte, aes.BlockSize)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						keymat := evpkdf.New(md5.New, []byte(passphrase), salt, keySize + aes.BlockSize, 1)
 | 
				
			||||||
 | 
						keymatbuf := bytes.NewReader(keymat)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						n, err := keymatbuf.Read(key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if n != keySize || err != nil {
 | 
				
			||||||
 | 
							return "", err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						n, err = keymatbuf.Read(iv)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if n != aes.BlockSize || err != nil {
 | 
				
			||||||
 | 
							return "", err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						block, err := aes.NewCipher(key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return "", err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						padded, err := pkcs7Pad([]byte(data), block.BlockSize())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return "", err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ciphertext := make([]byte, len(padded))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cbc := cipher.NewCBCEncrypter(block, iv)
 | 
				
			||||||
 | 
						cbc.CryptBlocks(ciphertext, padded)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return encode(ciphertext, salt), nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Decrypt(b64, passphrase string) ([]byte, error) {
 | 
				
			||||||
 | 
						salt, ct, err := decode(b64)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						key := make([]byte, keySize)
 | 
				
			||||||
 | 
						iv := make([]byte, aes.BlockSize)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						keymat := evpkdf.New(md5.New, []byte(passphrase), salt, keySize + aes.BlockSize, 1)
 | 
				
			||||||
 | 
						keymatbuf := bytes.NewReader(keymat)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						n, err := keymatbuf.Read(key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if n != keySize || err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						n, err = keymatbuf.Read(iv)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if n != aes.BlockSize || err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						block, err := aes.NewCipher(key)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cbc := cipher.NewCBCDecrypter(block, iv)
 | 
				
			||||||
 | 
						cbc.CryptBlocks(ct, ct)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						plain, err := pkcs7Unpad(ct, block.BlockSize())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return plain, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func encode(ct []byte, salt []byte) string {
 | 
				
			||||||
 | 
						b := []byte("Salted__")
 | 
				
			||||||
 | 
						b = append(b, salt...)
 | 
				
			||||||
 | 
						b = append(b, ct...)
 | 
				
			||||||
 | 
						return base64.StdEncoding.EncodeToString(b)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func decode(b64 string) ([]byte, []byte, error) {
 | 
				
			||||||
 | 
						decoded, err := base64.StdEncoding.DecodeString(b64)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if string(decoded[0:8]) != "Salted__" {
 | 
				
			||||||
 | 
							return nil, nil, errors.New("invalid data")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return decoded[8:16], decoded[16:], nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										47
									
								
								cryptojs/cryptojs_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								cryptojs/cryptojs_test.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					package cryptojs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Test_EncryptDecrypt(t *testing.T) {
 | 
				
			||||||
 | 
						enc, err := Encrypt("testing123", "testing")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal("Unable to encrypt:", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						b, err := Decrypt(enc, "testing")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal("Unable to decrypt:", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						final := string(b)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if final != "testing123" {
 | 
				
			||||||
 | 
							t.Fatal("Final text does not match:", final)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Test_WebsiteEncrypt(t *testing.T) {
 | 
				
			||||||
 | 
						enc, err := Encrypt("Testing Paste.ee", "wXBbztgFOsZtTvhK1vcZlR7izK84bmUW")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal("Error:", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if enc != "U2FsdGVkX183sL2jzqJiJdhIl0O7R9v46TIkKnORreGpUufYUsqjqYO9b++CSyvV" {
 | 
				
			||||||
 | 
							t.Fatal("Unexpected output:", enc)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Test_WebsiteDecrypt(t *testing.T) {
 | 
				
			||||||
 | 
						b, err := Decrypt("U2FsdGVkX183sL2jzqJiJdhIl0O7R9v46TIkKnORreGpUufYUsqjqYO9b++CSyvV", "wXBbztgFOsZtTvhK1vcZlR7izK84bmUW")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal("Unable to decrypt:", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if string(b) != "Testing Paste.ee" {
 | 
				
			||||||
 | 
							t.Fatal("Unexpected output:", string(b))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										48
									
								
								cryptojs/pkcs7.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								cryptojs/pkcs7.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					package cryptojs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Appends padding.
 | 
				
			||||||
 | 
					func pkcs7Pad(data []byte, blocklen int) ([]byte, error) {
 | 
				
			||||||
 | 
						if blocklen <= 0 {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("invalid blocklen %d", blocklen)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						padlen := uint8(1)
 | 
				
			||||||
 | 
						for ((len(data) + int(padlen)) % blocklen) != 0 {
 | 
				
			||||||
 | 
							padlen++
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if int(padlen) > blocklen {
 | 
				
			||||||
 | 
							panic(fmt.Sprintf("generated invalid padding length %v for block length %v", padlen, blocklen))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pad := bytes.Repeat([]byte{byte(padlen)}, int(padlen))
 | 
				
			||||||
 | 
						return append(data, pad...), nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Returns slice of the original data without padding.
 | 
				
			||||||
 | 
					func pkcs7Unpad(data []byte, blocklen int) ([]byte, error) {
 | 
				
			||||||
 | 
						if blocklen <= 0 {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("invalid blocklen %d", blocklen)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(data)%blocklen != 0 || len(data) == 0 {
 | 
				
			||||||
 | 
							return nil, fmt.Errorf("invalid data len %d", len(data))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						padlen := int(data[len(data)-1])
 | 
				
			||||||
 | 
						if padlen > blocklen || padlen == 0 {
 | 
				
			||||||
 | 
							// Not padded
 | 
				
			||||||
 | 
							return data, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// check padding
 | 
				
			||||||
 | 
						pad := data[len(data)-padlen:]
 | 
				
			||||||
 | 
						for i := 0; i < padlen; i++ {
 | 
				
			||||||
 | 
							if pad[i] != byte(padlen) {
 | 
				
			||||||
 | 
								return data, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return data[:len(data)-padlen], nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										55
									
								
								evpkdf/evpkdf.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								evpkdf/evpkdf.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					// Copyright (c) 2016 Tristan Colgate-McFarlane
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// This file is part of evpkdf.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// radia is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					// it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					// the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					// (at your option) any later version.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// radia is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					// GNU General Public License for more details.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					// along with radia.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Package evpkdf implements OpenSSL EVP Key derivation function, aiming to
 | 
				
			||||||
 | 
					// be compatible with crypto-js default behaviour.
 | 
				
			||||||
 | 
					package evpkdf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"hash"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//New creates a key derivation function that should match the EVP kdf in crypto-js, which, in turn
 | 
				
			||||||
 | 
					// should be compatible with openssl's EVP kdf
 | 
				
			||||||
 | 
					func New(hash func() hash.Hash, password []byte, salt []byte, keysize int, iterations int) []byte {
 | 
				
			||||||
 | 
						hasher := hash()
 | 
				
			||||||
 | 
						derivedKey := []byte{}
 | 
				
			||||||
 | 
						block := []byte{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Generate key
 | 
				
			||||||
 | 
						for len(derivedKey) < keysize {
 | 
				
			||||||
 | 
							if len(block) != 0 {
 | 
				
			||||||
 | 
								io.Copy(hasher, bytes.NewBuffer(block))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							io.Copy(hasher, bytes.NewBuffer(password))
 | 
				
			||||||
 | 
							io.Copy(hasher, bytes.NewBuffer(salt))
 | 
				
			||||||
 | 
							block = hasher.Sum(nil)
 | 
				
			||||||
 | 
							hasher.Reset()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Iterations
 | 
				
			||||||
 | 
							for i := 1; i < iterations; i++ {
 | 
				
			||||||
 | 
								io.Copy(hasher, bytes.NewBuffer(block))
 | 
				
			||||||
 | 
								block = hasher.Sum(nil)
 | 
				
			||||||
 | 
								hasher.Reset()
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							derivedKey = append(derivedKey, block...)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return derivedKey[0:keysize]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										140
									
								
								pastee.go
									
									
									
									
									
								
							
							
						
						
									
										140
									
								
								pastee.go
									
									
									
									
									
								
							@ -1,17 +1,118 @@
 | 
				
			|||||||
package pastee
 | 
					package GoPastee
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
 | 
						"math/rand"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"git.meow.tf/tyler/go-pastee/cryptojs"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func New(key string) *Pastee {
 | 
					func New(key string) *Pastee {
 | 
				
			||||||
	return &Pastee{ApiKey: key, Base: "https://api.paste.ee/v1", Client: &http.Client{}}
 | 
						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) {
 | 
					func (p *Pastee) Submit(paste *Paste) (*PasteResponse, error) {
 | 
				
			||||||
 | 
						var key string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if paste.Encrypted {
 | 
				
			||||||
 | 
							key = RandStringBytesMaskImprSrc(32)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for _, section := range paste.Sections {
 | 
				
			||||||
 | 
								section.Contents = cryptojs.Encrypt(section.Contents, key)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	body, err := json.Marshal(paste)
 | 
						body, err := json.Marshal(paste)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@ -25,7 +126,7 @@ func (p *Pastee) Submit(paste *Paste) (*PasteResponse, error) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	req.Header.Set("Content-Type", "application/json")
 | 
						req.Header.Set("Content-Type", "application/json")
 | 
				
			||||||
	req.Header.Set("Content-Length", len(body))
 | 
						req.Header.Set("Content-Length", strconv.Itoa(len(body)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	res, err := p.Client.Do(req)
 | 
						res, err := p.Client.Do(req)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -41,11 +142,15 @@ func (p *Pastee) Submit(paste *Paste) (*PasteResponse, error) {
 | 
				
			|||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if key != "" {
 | 
				
			||||||
 | 
							response.Key = key
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &response, nil
 | 
						return &response, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (p *Pastee) newRequest(method, path string, body io.Reader) (*http.Request, error) {
 | 
					func (p *Pastee) newRequest(method, path string, body io.Reader) (*http.Request, error) {
 | 
				
			||||||
	req, err := http.NewRequest(method, p.Base + path, body)
 | 
						req, err := http.NewRequest(method, p.Base + "/" + path, body)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
@ -54,4 +159,31 @@ func (p *Pastee) newRequest(method, path string, body io.Reader) (*http.Request,
 | 
				
			|||||||
	req.Header.Set("X-Auth-Token", p.ApiKey)
 | 
						req.Header.Set("X-Auth-Token", p.ApiKey)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return req, nil
 | 
						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)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										32
									
								
								structs.go
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								structs.go
									
									
									
									
									
								
							@ -1,4 +1,4 @@
 | 
				
			|||||||
package pastee
 | 
					package GoPastee
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "net/http"
 | 
					import "net/http"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -9,6 +9,8 @@ type Pastee struct {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Paste struct {
 | 
					type Paste struct {
 | 
				
			||||||
 | 
						ID string `json:"id,omitempty"`
 | 
				
			||||||
 | 
						Views int `json:"views,omitempty"`
 | 
				
			||||||
	Encrypted bool `json:"encrypted,omitempty"`
 | 
						Encrypted bool `json:"encrypted,omitempty"`
 | 
				
			||||||
	Description string `json:"description,omitempty"`
 | 
						Description string `json:"description,omitempty"`
 | 
				
			||||||
	Sections []*Section `json:"sections"`
 | 
						Sections []*Section `json:"sections"`
 | 
				
			||||||
@ -29,6 +31,34 @@ type Error struct {
 | 
				
			|||||||
type PasteResponse struct {
 | 
					type PasteResponse struct {
 | 
				
			||||||
	Success bool `json:"success"`
 | 
						Success bool `json:"success"`
 | 
				
			||||||
	Errors []*Error `json:"errors"`
 | 
						Errors []*Error `json:"errors"`
 | 
				
			||||||
 | 
						Key string `json:"-"`
 | 
				
			||||||
	ID string `json:"id"`
 | 
						ID string `json:"id"`
 | 
				
			||||||
	Link string `json:"link"`
 | 
						Link string `json:"link"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type authRequest struct {
 | 
				
			||||||
 | 
						username string `json:"username"`
 | 
				
			||||||
 | 
						password string `json:"password"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type AuthResponse struct {
 | 
				
			||||||
 | 
						Success bool `json:"success"`
 | 
				
			||||||
 | 
						Key string `json:"key"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type PaginationResponse struct {
 | 
				
			||||||
 | 
						Total int `json:"total"`
 | 
				
			||||||
 | 
						PerPage int `json:"per_page"`
 | 
				
			||||||
 | 
						CurrentPage int `json:"current_page"`
 | 
				
			||||||
 | 
						LastPage int `json:"last_page"`
 | 
				
			||||||
 | 
						NextPageURL string `json:"next_page_url"`
 | 
				
			||||||
 | 
						PreviousPageURL string `json:"prev_page_url"`
 | 
				
			||||||
 | 
						From int `json:"from"`
 | 
				
			||||||
 | 
						To int `json:"to"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type PasteListResponse struct {
 | 
				
			||||||
 | 
						*PaginationResponse
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Data []*Paste `json:"data"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user