<commit_before>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package keybase

import (
	"encoding/base64"
	"errors"
	"fmt"
	"net"
	"sync"

	"github.com/keybase/client/go/externals"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/logger"
	"github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/client/go/service"
	"github.com/keybase/go-framed-msgpack-rpc/rpc"
	"github.com/keybase/kbfs/fsrpc"
	"github.com/keybase/kbfs/libkbfs"
)

var kbCtx *libkb.GlobalContext
var conn net.Conn
var startOnce sync.Once
var logSendContext libkb.LogSendContext
var kbfsConfig libkbfs.Config

// InitOnce runs the Keybase services (only runs one time)
func InitOnce(homeDir string, logFile string, runModeStr string, accessGroupOverride bool) {
	startOnce.Do(func() {
		if err := Init(homeDir, logFile, runModeStr, accessGroupOverride); err != nil {
			kbCtx.Log.Errorf("Init error: %s", err)
		}
	})
}

// Init runs the Keybase services
func Init(homeDir string, logFile string, runModeStr string, accessGroupOverride bool) error {
	fmt.Println("Go: Initializing")
	fmt.Printf("Go: Using log: %s\n", logFile)
	kbCtx = libkb.G
	kbCtx.Init()
	kbCtx.SetServices(externals.GetServices())
	usage := libkb.Usage{
		Config:    true,
		API:       true,
		KbKeyring: true,
	}
	runMode, err := libkb.StringToRunMode(runModeStr)
	if err != nil {
		return err
	}
	config := libkb.AppConfig{
		HomeDir:                     homeDir,
		LogFile:                     logFile,
		RunMode:                     runMode,
		Debug:                       true,
		LocalRPCDebug:               "",
		SecurityAccessGroupOverride: accessGroupOverride,
	}
	err = kbCtx.Configure(config, usage)
	if err != nil {
		return err
	}

	svc := service.NewService(kbCtx, false)
	svc.StartLoopbackServer()
	kbCtx.SetService()
	uir := service.NewUIRouter(kbCtx)
	kbCtx.SetUIRouter(uir)
	svc.RunBackgroundOperations(uir)

	serviceLog := config.GetLogFile()
	logs := libkb.Logs{
		Service: serviceLog,
	}

	logSendContext = libkb.LogSendContext{
		Contextified: libkb.NewContextified(kbCtx),
		Logs:         logs,
	}

	// FIXME (MBG): This is causing RPC responses to sometimes not be recieved
	// on iOS. Repro by hooking up getExtendedStatus to a button in the iOS
	// client and watching JS logs. Disabling until we have a root cause / fix.
	kbfsParams := libkbfs.DefaultInitParams(kbCtx)
	kbfsConfig, err = libkbfs.Init(kbCtx, kbfsParams, serviceCn{}, func() {}, kbCtx.Log)
	if err != nil {
		return err
	}

	return Reset()
}

type serviceCn struct {
	ctx *libkb.GlobalContext
}

func (s serviceCn) NewKeybaseService(config libkbfs.Config, params libkbfs.InitParams, ctx libkbfs.Context, log logger.Logger) (libkbfs.KeybaseService, error) {
	keybaseService := libkbfs.NewKeybaseDaemonRPC(config, ctx, log, true)
	keybaseService.AddProtocols([]rpc.Protocol{
		keybase1.FsProtocol(fsrpc.NewFS(config, log)),
	})
	return keybaseService, nil
}

func (s serviceCn) NewCrypto(config libkbfs.Config, params libkbfs.InitParams, ctx libkbfs.Context, log logger.Logger) (libkbfs.Crypto, error) {
	return libkbfs.NewCryptoClientRPC(config, ctx), nil
}

// LogSend sends a log to Keybase
func LogSend(uiLogPath string) (string, error) {
	logSendContext.Logs.Desktop = uiLogPath
	return logSendContext.LogSend("", 10000)
}

// WriteB64 sends a base64 encoded msgpack rpc payload
func WriteB64(str string) error {
	data, err := base64.StdEncoding.DecodeString(str)
	if err != nil {
		return fmt.Errorf("Base64 decode error: %s; %s", err, str)
	}
	n, err := conn.Write(data)
	if err != nil {
		return fmt.Errorf("Write error: %s", err)
	}
	if n != len(data) {
		return errors.New("Did not write all the data")
	}
	return nil
}

const targetBufferSize = 50 * 1024

// bufferSize must be divisible by 3 to ensure that we don't split
// our b64 encode across a payload boundary if we go over our buffer
// size.
const bufferSize = targetBufferSize - (targetBufferSize % 3)

// ReadB64 is a blocking read for base64 encoded msgpack rpc data.
func ReadB64() (string, error) {
	data := make([]byte, bufferSize)

	n, err := conn.Read(data)
	if n > 0 && err == nil {
		str := base64.StdEncoding.EncodeToString(data[0:n])
		return str, nil
	}

	if err != nil {
		// Attempt to fix the connection
		Reset()
		return "", fmt.Errorf("Read error: %s", err)
	}

	return "", nil
}

// Reset resets the socket connection
func Reset() error {
	if conn != nil {
		conn.Close()
	}

	var err error
	conn, err = kbCtx.LoopbackListener.Dial()
	if err != nil {
		return fmt.Errorf("Socket error: %s", err)
	}
	return nil
}

// Version returns semantic version string
func Version() string {
	return libkb.VersionString()
}
<commit_msg>Reuse read buffer<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package keybase

import (
	"encoding/base64"
	"errors"
	"fmt"
	"net"
	"net/http"
	_ "net/http/pprof"
	"sync"

	"github.com/keybase/client/go/externals"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/logger"
	"github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/client/go/service"
	"github.com/keybase/go-framed-msgpack-rpc/rpc"
	"github.com/keybase/kbfs/fsrpc"
	"github.com/keybase/kbfs/libkbfs"
)

var kbCtx *libkb.GlobalContext
var conn net.Conn
var startOnce sync.Once
var logSendContext libkb.LogSendContext
var kbfsConfig libkbfs.Config

// InitOnce runs the Keybase services (only runs one time)
func InitOnce(homeDir string, logFile string, runModeStr string, accessGroupOverride bool) {
	startOnce.Do(func() {
		if err := Init(homeDir, logFile, runModeStr, accessGroupOverride); err != nil {
			kbCtx.Log.Errorf("Init error: %s", err)
		}
	})
}

// Init runs the Keybase services
func Init(homeDir string, logFile string, runModeStr string, accessGroupOverride bool) error {
	fmt.Println("Go: Initializing")
	fmt.Printf("Go: Using log: %s\n", logFile)

	go func() {
		fmt.Println(http.ListenAndServe(":6060", nil))
	}()

	kbCtx = libkb.G
	kbCtx.Init()
	kbCtx.SetServices(externals.GetServices())
	usage := libkb.Usage{
		Config:    true,
		API:       true,
		KbKeyring: true,
	}
	runMode, err := libkb.StringToRunMode(runModeStr)
	if err != nil {
		return err
	}
	config := libkb.AppConfig{
		HomeDir:                     homeDir,
		LogFile:                     logFile,
		RunMode:                     runMode,
		Debug:                       true,
		LocalRPCDebug:               "",
		SecurityAccessGroupOverride: accessGroupOverride,
	}
	err = kbCtx.Configure(config, usage)
	if err != nil {
		return err
	}

	svc := service.NewService(kbCtx, false)
	svc.StartLoopbackServer()
	kbCtx.SetService()
	uir := service.NewUIRouter(kbCtx)
	kbCtx.SetUIRouter(uir)
	svc.RunBackgroundOperations(uir)

	serviceLog := config.GetLogFile()
	logs := libkb.Logs{
		Service: serviceLog,
	}

	logSendContext = libkb.LogSendContext{
		Contextified: libkb.NewContextified(kbCtx),
		Logs:         logs,
	}

	// FIXME (MBG): This is causing RPC responses to sometimes not be recieved
	// on iOS. Repro by hooking up getExtendedStatus to a button in the iOS
	// client and watching JS logs. Disabling until we have a root cause / fix.
	kbfsParams := libkbfs.DefaultInitParams(kbCtx)
	kbfsConfig, err = libkbfs.Init(kbCtx, kbfsParams, serviceCn{}, func() {}, kbCtx.Log)
	if err != nil {
		return err
	}

	return Reset()
}

type serviceCn struct {
	ctx *libkb.GlobalContext
}

func (s serviceCn) NewKeybaseService(config libkbfs.Config, params libkbfs.InitParams, ctx libkbfs.Context, log logger.Logger) (libkbfs.KeybaseService, error) {
	keybaseService := libkbfs.NewKeybaseDaemonRPC(config, ctx, log, true)
	keybaseService.AddProtocols([]rpc.Protocol{
		keybase1.FsProtocol(fsrpc.NewFS(config, log)),
	})
	return keybaseService, nil
}

func (s serviceCn) NewCrypto(config libkbfs.Config, params libkbfs.InitParams, ctx libkbfs.Context, log logger.Logger) (libkbfs.Crypto, error) {
	return libkbfs.NewCryptoClientRPC(config, ctx), nil
}

// LogSend sends a log to Keybase
func LogSend(uiLogPath string) (string, error) {
	logSendContext.Logs.Desktop = uiLogPath
	return logSendContext.LogSend("", 10000)
}

// WriteB64 sends a base64 encoded msgpack rpc payload
func WriteB64(str string) error {
	data, err := base64.StdEncoding.DecodeString(str)
	if err != nil {
		return fmt.Errorf("Base64 decode error: %s; %s", err, str)
	}
	n, err := conn.Write(data)
	if err != nil {
		return fmt.Errorf("Write error: %s", err)
	}
	if n != len(data) {
		return errors.New("Did not write all the data")
	}
	return nil
}

const targetBufferSize = 50 * 1024

// bufferSize must be divisible by 3 to ensure that we don't split
// our b64 encode across a payload boundary if we go over our buffer
// size.
const bufferSize = targetBufferSize - (targetBufferSize % 3)

// buffer for the conn.Read
var buffer = make([]byte, bufferSize)

// ReadB64 is a blocking read for base64 encoded msgpack rpc data.
// It is called serially by the mobile run loops.
func ReadB64() (string, error) {
	n, err := conn.Read(buffer)
	if n > 0 && err == nil {
		str := base64.StdEncoding.EncodeToString(data[0:n])
		return str, nil
	}

	if err != nil {
		// Attempt to fix the connection
		Reset()
		return "", fmt.Errorf("Read error: %s", err)
	}

	return "", nil
}

// Reset resets the socket connection
func Reset() error {
	if conn != nil {
		conn.Close()
	}

	var err error
	conn, err = kbCtx.LoopbackListener.Dial()
	if err != nil {
		return fmt.Errorf("Socket error: %s", err)
	}
	return nil
}

// Version returns semantic version string
func Version() string {
	return libkb.VersionString()
}
<|endoftext|>


<commit_before>// Copyright 2016 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package service

import (
	"golang.org/x/net/context"

	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol"
	rpc "github.com/keybase/go-framed-msgpack-rpc"
	"github.com/keybase/gregor/protocol/chat1"
)

type chatLocalHandler struct {
	*BaseHandler
	libkb.Contextified
	gh *gregorHandler
}

func newChatLocalHandler(xp rpc.Transporter, g *libkb.GlobalContext, gh *gregorHandler) *chatLocalHandler {
	return &chatLocalHandler{
		BaseHandler:  NewBaseHandler(xp),
		Contextified: libkb.NewContextified(g),
		gh:           gh,
	}
}

func (h *chatLocalHandler) GetInboxLocal(ctx context.Context, p *chat1.Pagination) (chat1.InboxView, error) {
	return h.remoteClient().GetInboxRemote(ctx, p)
}

func (h *chatLocalHandler) GetThreadLocal(ctx context.Context, arg keybase1.GetThreadLocalArg) (keybase1.ThreadView, error) {
	rarg := chat1.GetThreadRemoteArg{
		ConversationID: arg.ConversationID,
		Pagination:     arg.Pagination,
	}
	boxed, err := h.remoteClient().GetThreadRemote(ctx, rarg)
	if err != nil {
		return keybase1.ThreadView{}, err
	}

	// TODO: ThreadViewBoxed -> ThreadView
	_ = boxed

	return keybase1.ThreadView{}, nil
}

func (h *chatLocalHandler) NewConversationLocal(context.Context, chat1.ConversationIDTriple) error {
	return nil
}

func (h *chatLocalHandler) PostLocal(ctx context.Context, arg keybase1.PostLocalArg) error {
	rarg := chat1.PostRemoteArg{
		ConversationID: arg.ConversationID,
	}

	// TODO: arg.MessagePlaintext => rarg.MessageBoxed

	return h.remoteClient().PostRemote(ctx, rarg)
}

func (h *chatLocalHandler) remoteClient() *chat1.RemoteClient {
	return &chat1.RemoteClient{Cli: h.gh.cli}
}
<commit_msg>Progress on unbox thread<commit_after>// Copyright 2016 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package service

import (
	"errors"
	"fmt"

	"golang.org/x/net/context"

	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol"
	rpc "github.com/keybase/go-framed-msgpack-rpc"
	"github.com/keybase/gregor/protocol/chat1"
)

type chatLocalHandler struct {
	*BaseHandler
	libkb.Contextified
	gh   *gregorHandler
	tlfh *tlfHandler
}

func newChatLocalHandler(xp rpc.Transporter, g *libkb.GlobalContext, gh *gregorHandler) *chatLocalHandler {
	return &chatLocalHandler{
		BaseHandler:  NewBaseHandler(xp),
		Contextified: libkb.NewContextified(g),
		gh:           gh,
		tlfh:         newTlfHandler(xp, g),
	}
}

func (h *chatLocalHandler) GetInboxLocal(ctx context.Context, p *chat1.Pagination) (chat1.InboxView, error) {
	return h.remoteClient().GetInboxRemote(ctx, p)
}

func (h *chatLocalHandler) GetThreadLocal(ctx context.Context, arg keybase1.GetThreadLocalArg) (keybase1.ThreadView, error) {
	rarg := chat1.GetThreadRemoteArg{
		ConversationID: arg.ConversationID,
		Pagination:     arg.Pagination,
	}
	boxed, err := h.remoteClient().GetThreadRemote(ctx, rarg)
	if err != nil {
		return keybase1.ThreadView{}, err
	}

	return h.unboxThread(ctx, boxed)
}

func (h *chatLocalHandler) NewConversationLocal(context.Context, chat1.ConversationIDTriple) error {
	return nil
}

func (h *chatLocalHandler) PostLocal(ctx context.Context, arg keybase1.PostLocalArg) error {
	rarg := chat1.PostRemoteArg{
		ConversationID: arg.ConversationID,
	}

	// TODO: arg.MessagePlaintext => rarg.MessageBoxed

	return h.remoteClient().PostRemote(ctx, rarg)
}

func (h *chatLocalHandler) remoteClient() *chat1.RemoteClient {
	return &chat1.RemoteClient{Cli: h.gh.cli}
}

func (h *chatLocalHandler) unboxThread(ctx context.Context, boxed chat1.ThreadViewBoxed) (keybase1.ThreadView, error) {
	thread := keybase1.ThreadView{
		Pagination: boxed.Pagination,
	}

	for _, msg := range boxed.Messages {
		unboxed, err := h.unboxMessage(ctx, msg)
		if err != nil {
			return keybase1.ThreadView{}, err
		}
		thread.Messages = append(thread.Messages, unboxed)
	}

	return thread, nil
}

func (h *chatLocalHandler) unboxMessage(ctx context.Context, msg chat1.MessageBoxed) (keybase1.Message, error) {
	if msg.ServerHeader == nil {
		return keybase1.Message{}, errors.New("nil ServerHeader in MessageBoxed")
	}

	unboxed := keybase1.Message{
		ServerHeader: *msg.ServerHeader,
		MessagePlaintext: keybase1.MessagePlaintext{
			ClientHeader: msg.ClientHeader,
		},
	}

	tlfID := msg.ClientHeader.Conv.Tlfid
	keys, err := h.tlfKeys(ctx, tlfID)
	if err != nil {
		return keybase1.Message{}, err
	}

	var keyBytes *keybase1.Bytes32
	for _, key := range keys.CryptKeys {
		if key.KeyGeneration == msg.KeyGeneration {
			keyBytes = &key.Key
		}
	}

	if keyBytes == nil {
		return keybase1.Message{}, fmt.Errorf("no key found for generation %d", msg.KeyGeneration)
	}

	return unboxed, nil
}

func (h *chatLocalHandler) tlfKeys(ctx context.Context, tlfID chat1.TLFID) (keybase1.TLFCryptKeys, error) {
	return keybase1.TLFCryptKeys{}, nil
}
<|endoftext|>


<commit_before>package teams

import (
	"bytes"
	"fmt"

	"crypto/hmac"
	"crypto/rand"
	"crypto/sha512"
	"encoding/base64"
	"encoding/hex"
	"errors"

	"golang.org/x/crypto/nacl/secretbox"
	"golang.org/x/crypto/scrypt"
	"golang.org/x/net/context"

	libkb "github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/saltpack/encoding/basex"
)

const SeitanRawIKeyLength = 10
const SeitanEncodedIKeyLength = 16

// Key-Base 33 encoding. lower case letters except 'l' and digits except for '0' and '1'.
const KBase33EncodeStd = "abcdefghijkmnopqrstuvwxyz23456789"

var Base33Encoding = basex.NewEncoding(KBase33EncodeStd, SeitanRawIKeyLength, "")

// "Invite Key"
type SeitanIKey string

// "Packed Encrypted Invite Key"
type SeitanPEIKey struct {
	_struct           bool `codec:",toarray"`
	Version           uint
	TeamKeyGeneration keybase1.PerTeamKeyGeneration
	RandomNonce       keybase1.BoxNonce
	EIKey             []byte
}

func GenerateIKey() (ikey SeitanIKey, err error) {
	rawKey, err := libkb.RandBytes(SeitanRawIKeyLength)
	if err != nil {
		return ikey, err
	}

	var encodedKey [SeitanEncodedIKeyLength]byte
	Base33Encoding.Encode(encodedKey[:], rawKey)

	var verify [10]byte
	_, err = Base33Encoding.Decode(verify[:], encodedKey[:])
	if err != nil {
		return ikey, err
	}

	if !bytes.Equal(verify[:], rawKey) {
		return ikey, errors.New("Internal error - ikey encoding failed")
	}

	ikey = SeitanIKey(encodedKey[:])
	return ikey, nil
}

func GenerateIKeyFromString(token string) (ikey SeitanIKey, err error) {
	if len(token) != SeitanEncodedIKeyLength {
		return ikey, fmt.Errorf("invalid token length: expected %d characters, got %d", SeitanEncodedIKeyLength, len(token))
	}

	return SeitanIKey(token), nil
}

func (ikey SeitanIKey) String() string {
	return string(ikey)
}

// "Stretched Invite Key"
type SeitanSIKey [32]byte

const (
	SeitanScryptCost   = 1 << 10
	SeitanScryptR      = 8
	SeitanScryptP      = 1
	SeitanScryptKeylen = 32
)

func (ikey SeitanIKey) GenerateSIKey() (sikey SeitanSIKey, err error) {
	ret, err := scrypt.Key([]byte(ikey), nil, SeitanScryptCost, SeitanScryptR, SeitanScryptP, SeitanScryptKeylen)
	if err != nil {
		return sikey, err
	}
	if len(ret) != 32 {
		return sikey, errors.New("internal error - scrypt did not return 32 bytes")
	}
	copy(sikey[:], ret)
	return sikey, nil
}

func (sikey SeitanSIKey) GenerateTeamInviteID() (id SCTeamInviteID, err error) {
	type InviteStagePayload struct {
		Stage string `codec:"stage" json:"stage"`
	}

	payload, err := libkb.MsgpackEncode(InviteStagePayload{Stage: "invite_id"})
	if err != nil {
		return id, err
	}

	mac := hmac.New(sha512.New, sikey[:])
	_, err = mac.Write(payload)
	if err != nil {
		return id, err
	}

	out := mac.Sum(nil)
	out = out[0:15]
	out = append(out, libkb.InviteIDTag)
	id = SCTeamInviteID(hex.EncodeToString(out[:]))
	return id, nil
}

func (ikey SeitanIKey) GeneratePackedEncryptedIKey(ctx context.Context, team *Team) (peikey SeitanPEIKey, encoded string, err error) {
	appKey, err := team.SeitanInviteTokenKey(ctx)
	if err != nil {
		return peikey, encoded, err
	}

	var nonce keybase1.BoxNonce
	if _, err = rand.Read(nonce[:]); err != nil {
		return peikey, encoded, err
	}

	var encKey [libkb.NaclSecretBoxKeySize]byte = appKey.Key
	var naclNonce [libkb.NaclDHNonceSize]byte = nonce
	eikey := secretbox.Seal(nil, []byte(ikey), &naclNonce, &encKey)

	peikey = SeitanPEIKey{
		Version:           1,
		TeamKeyGeneration: appKey.KeyGeneration,
		RandomNonce:       nonce,
		EIKey:             eikey,
	}

	packed, err := libkb.MsgpackEncode(peikey)
	if err != nil {
		return peikey, encoded, err
	}

	encoded = base64.StdEncoding.EncodeToString(packed)
	return peikey, encoded, nil
}

func SeitanDecodePEIKey(base64Buffer string) (peikey SeitanPEIKey, err error) {
	packed, err := base64.StdEncoding.DecodeString(base64Buffer)
	if err != nil {
		return peikey, err
	}

	err = libkb.MsgpackDecode(&peikey, packed)
	return peikey, err
}

func (peikey SeitanPEIKey) DecryptIKey(ctx context.Context, team *Team) (ikey SeitanIKey, err error) {
	appKey, err := team.ApplicationKeyAtGeneration(keybase1.TeamApplication_SEITAN_INVITE_TOKEN, peikey.TeamKeyGeneration)
	if err != nil {
		return ikey, err
	}

	var encKey [libkb.NaclSecretBoxKeySize]byte = appKey.Key
	var naclNonce [libkb.NaclDHNonceSize]byte = peikey.RandomNonce
	plain, ok := secretbox.Open(nil, peikey.EIKey, &naclNonce, &encKey)
	if !ok {
		return ikey, errors.New("failed to decrypt seitan ikey")
	}

	ikey = SeitanIKey(plain)
	return ikey, nil
}

// "Acceptance Key"
type SeitanAKey []byte

func (sikey SeitanSIKey) GenerateAcceptanceKey(uid keybase1.UID, eldestSeqno keybase1.Seqno, unixTime int64) (akey SeitanAKey, encoded string, err error) {
	type AKeyPayload struct {
		Stage       string         `codec:"stage" json:"stage"`
		UID         keybase1.UID   `codec:"uid" json:"uid"`
		EldestSeqno keybase1.Seqno `codec:"eldest_seqno" json:"eldest_seqno"`
		CTime       int64          `codec:"ctime" json:"ctime"`
	}

	payload, err := libkb.MsgpackEncode(AKeyPayload{
		Stage:       "accept",
		UID:         uid,
		EldestSeqno: eldestSeqno,
		CTime:       unixTime,
	})
	if err != nil {
		return akey, encoded, err
	}

	fmt.Printf("msg pack is %q\n", payload)

	mac := hmac.New(sha512.New, sikey[:])
	_, err = mac.Write(payload)
	if err != nil {
		return akey, encoded, err
	}

	out := mac.Sum(nil)
	akey = out[:32]
	encoded = base64.StdEncoding.EncodeToString(akey)
	return akey, encoded, nil
}
<commit_msg>Const cleanup, use secure arr comp when veryfing IKey generation<commit_after>package teams

import (
	"fmt"

	"crypto/hmac"
	"crypto/rand"
	"crypto/sha512"
	"encoding/base64"
	"encoding/hex"
	"errors"

	"golang.org/x/crypto/nacl/secretbox"
	"golang.org/x/crypto/scrypt"
	"golang.org/x/net/context"

	libkb "github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/saltpack/encoding/basex"
)

const SeitanRawIKeyLength = 10
const SeitanEncodedIKeyLength = 16

// Key-Base 33 encoding. lower case letters except 'l' and digits except for '0' and '1'.
const KBase33EncodeStd = "abcdefghijkmnopqrstuvwxyz23456789"

var Base33Encoding = basex.NewEncoding(KBase33EncodeStd, SeitanRawIKeyLength, "")

// "Invite Key"
type SeitanIKey string

// "Packed Encrypted Invite Key"
type SeitanPEIKey struct {
	_struct           bool `codec:",toarray"`
	Version           uint
	TeamKeyGeneration keybase1.PerTeamKeyGeneration
	RandomNonce       keybase1.BoxNonce
	EIKey             []byte
}

func GenerateIKey() (ikey SeitanIKey, err error) {
	rawKey, err := libkb.RandBytes(SeitanRawIKeyLength)
	if err != nil {
		return ikey, err
	}

	var encodedKey [SeitanEncodedIKeyLength]byte
	Base33Encoding.Encode(encodedKey[:], rawKey)

	var verify [SeitanRawIKeyLength]byte
	_, err = Base33Encoding.Decode(verify[:], encodedKey[:])
	if err != nil {
		return ikey, err
	}

	if !libkb.SecureByteArrayEq(verify[:], rawKey) {
		return ikey, errors.New("Internal error - ikey encoding failed")
	}

	ikey = SeitanIKey(encodedKey[:])
	return ikey, nil
}

func GenerateIKeyFromString(token string) (ikey SeitanIKey, err error) {
	if len(token) != SeitanEncodedIKeyLength {
		return ikey, fmt.Errorf("invalid token length: expected %d characters, got %d", SeitanEncodedIKeyLength, len(token))
	}

	return SeitanIKey(token), nil
}

func (ikey SeitanIKey) String() string {
	return string(ikey)
}

const (
	SeitanScryptCost   = 1 << 10
	SeitanScryptR      = 8
	SeitanScryptP      = 1
	SeitanScryptKeylen = 32
)

// "Stretched Invite Key"
type SeitanSIKey [SeitanScryptKeylen]byte

func (ikey SeitanIKey) GenerateSIKey() (sikey SeitanSIKey, err error) {
	ret, err := scrypt.Key([]byte(ikey), nil, SeitanScryptCost, SeitanScryptR, SeitanScryptP, SeitanScryptKeylen)
	if err != nil {
		return sikey, err
	}
	copy(sikey[:], ret)
	return sikey, nil
}

func (sikey SeitanSIKey) GenerateTeamInviteID() (id SCTeamInviteID, err error) {
	type InviteStagePayload struct {
		Stage string `codec:"stage" json:"stage"`
	}

	payload, err := libkb.MsgpackEncode(InviteStagePayload{Stage: "invite_id"})
	if err != nil {
		return id, err
	}

	mac := hmac.New(sha512.New, sikey[:])
	_, err = mac.Write(payload)
	if err != nil {
		return id, err
	}

	out := mac.Sum(nil)
	out = out[0:15]
	out = append(out, libkb.InviteIDTag)
	id = SCTeamInviteID(hex.EncodeToString(out[:]))
	return id, nil
}

func (ikey SeitanIKey) GeneratePackedEncryptedIKey(ctx context.Context, team *Team) (peikey SeitanPEIKey, encoded string, err error) {
	appKey, err := team.SeitanInviteTokenKey(ctx)
	if err != nil {
		return peikey, encoded, err
	}

	var nonce keybase1.BoxNonce
	if _, err = rand.Read(nonce[:]); err != nil {
		return peikey, encoded, err
	}

	var encKey [libkb.NaclSecretBoxKeySize]byte = appKey.Key
	var naclNonce [libkb.NaclDHNonceSize]byte = nonce
	eikey := secretbox.Seal(nil, []byte(ikey), &naclNonce, &encKey)

	peikey = SeitanPEIKey{
		Version:           1,
		TeamKeyGeneration: appKey.KeyGeneration,
		RandomNonce:       nonce,
		EIKey:             eikey,
	}

	packed, err := libkb.MsgpackEncode(peikey)
	if err != nil {
		return peikey, encoded, err
	}

	encoded = base64.StdEncoding.EncodeToString(packed)
	return peikey, encoded, nil
}

func SeitanDecodePEIKey(base64Buffer string) (peikey SeitanPEIKey, err error) {
	packed, err := base64.StdEncoding.DecodeString(base64Buffer)
	if err != nil {
		return peikey, err
	}

	err = libkb.MsgpackDecode(&peikey, packed)
	return peikey, err
}

func (peikey SeitanPEIKey) DecryptIKey(ctx context.Context, team *Team) (ikey SeitanIKey, err error) {
	appKey, err := team.ApplicationKeyAtGeneration(keybase1.TeamApplication_SEITAN_INVITE_TOKEN, peikey.TeamKeyGeneration)
	if err != nil {
		return ikey, err
	}

	var encKey [libkb.NaclSecretBoxKeySize]byte = appKey.Key
	var naclNonce [libkb.NaclDHNonceSize]byte = peikey.RandomNonce
	plain, ok := secretbox.Open(nil, peikey.EIKey, &naclNonce, &encKey)
	if !ok {
		return ikey, errors.New("failed to decrypt seitan ikey")
	}

	ikey = SeitanIKey(plain)
	return ikey, nil
}

// "Acceptance Key"
type SeitanAKey []byte

func (sikey SeitanSIKey) GenerateAcceptanceKey(uid keybase1.UID, eldestSeqno keybase1.Seqno, unixTime int64) (akey SeitanAKey, encoded string, err error) {
	type AKeyPayload struct {
		Stage       string         `codec:"stage" json:"stage"`
		UID         keybase1.UID   `codec:"uid" json:"uid"`
		EldestSeqno keybase1.Seqno `codec:"eldest_seqno" json:"eldest_seqno"`
		CTime       int64          `codec:"ctime" json:"ctime"`
	}

	payload, err := libkb.MsgpackEncode(AKeyPayload{
		Stage:       "accept",
		UID:         uid,
		EldestSeqno: eldestSeqno,
		CTime:       unixTime,
	})
	if err != nil {
		return akey, encoded, err
	}

	fmt.Printf("msg pack is %q\n", payload)

	mac := hmac.New(sha512.New, sikey[:])
	_, err = mac.Write(payload)
	if err != nil {
		return akey, encoded, err
	}

	out := mac.Sum(nil)
	akey = out[:32]
	encoded = base64.StdEncoding.EncodeToString(akey)
	return akey, encoded, nil
}
<|endoftext|>


<commit_before>package goarmorapi

import (
	"context"
	"encoding/json"
	"errors"
	"strings"
	"time"

	"github.com/armor5games/goarmor/goarmorconfigs"
)

type JSONRequest struct {
	Payload interface{} `json:",omitempty"`
	Time    uint64      `json:",omitempty"`
}

type JSONResponse struct {
	Success bool
	Errors  []*ErrorJSON `json:",omitempty"`
	Payload interface{}  `json:",omitempty"`
	Time    uint64       `json:",omitempty"`
}

type ErrorJSON struct {
	Code uint64
	// TODO: Rename "Error" to "Err"
	Error    error  `json:"Message,omitempty"`
	Public   bool   `json:"-"`
	Severity uint64 `json:"-"`
}

type ErrorJSONSeverity uint64

const (
	ErrSeverityDebug ErrorJSONSeverity = iota
	ErrSeverityInfo
	ErrSeverityWarn
	ErrSeverityError
	ErrSeverityFatal
	ErrSeverityPanic
)

func (s ErrorJSONSeverity) ErrorDefaultCode() uint64 {
	var c ErrorJSONCode

	switch s {
	default:
		return 0

	case ErrSeverityDebug:
		c = ErrCodeDefautlDebug

	case ErrSeverityInfo:
		c = ErrCodeDefautlInfo

	case ErrSeverityWarn:
		c = ErrCodeDefautlWarn

	case ErrSeverityError:
		c = ErrCodeDefautlError

	case ErrSeverityFatal:
		c = ErrCodeDefautlFatal

	case ErrSeverityPanic:
		c = ErrCodeDefautlPanic
	}

	return uint64(c)
}

type ErrorJSONCode uint64

const (
	ErrCodeDefautlDebug ErrorJSONCode = 1100
	ErrCodeDefautlInfo

	ErrCodeDefautlWarn ErrorJSONCode = 4100

	ErrCodeDefautlError ErrorJSONCode = 5100
	ErrCodeDefautlFatal
	ErrCodeDefautlPanic
)

type ResponseErrorer interface {
	ResponseErrors() []*ErrorJSON
}

func (e *ErrorJSON) MarshalJSON() ([]byte, error) {
	var m string

	if e.Error != nil {
		m = e.Error.Error()
	}

	return json.Marshal(&struct {
		Code    uint64
		Message string `json:",omitempty"`
	}{
		Code:    uint64(e.Code),
		Message: m})
}

func (e *ErrorJSON) UnmarshalJSON(b []byte) error {
	s := &struct {
		Code    uint64
		Message string
	}{}

	if err := json.Unmarshal(b, &s); err != nil {
		return err
	}

	e.Code = s.Code

	if s.Message != "" {
		e.Error = errors.New(s.Message)
	}

	return nil
}

func (j *JSONResponse) KV() (KV, error) {
	if j == nil {
		return nil, errors.New("empty api response")
	}

	if len(j.Errors) == 0 {
		return nil, errors.New("empty key values")
	}

	kv := NewKV()

	for _, e := range j.Errors {
		if e.Code != uint64(ErrCodeDefautlDebug) {
			continue
		}

		if e.Error.Error() == "" {
			return nil, errors.New("empty kv")
		}

		x := strings.SplitN(e.Error.Error(), ":", 2)
		if len(x) != 2 {
			return nil, errors.New("bad kv format")
		}

		kv[x[0]] = x[1]
	}

	if len(kv) == 0 {
		return nil, errors.New("empty kv")
	}

	return kv, nil
}

func NewJSONRequest(
	ctx context.Context,
	responsePayload interface{}) (*JSONRequest, error) {
	return &JSONRequest{
		Payload: responsePayload,
		Time:    uint64(time.Now().Unix())}, nil
}

func NewJSONResponse(
	ctx context.Context,
	isSuccess bool,
	responsePayload interface{},
	responseErrorer ResponseErrorer,
	errs ...*ErrorJSON) (*JSONResponse, error) {
	publicErrors, err := newJSONResponseErrors(ctx, responseErrorer, errs...)
	if err != nil {
		return nil, err
	}

	return &JSONResponse{
		Success: isSuccess,
		Errors:  publicErrors,
		Payload: responsePayload,
		Time:    uint64(time.Now().Unix())}, nil
}

func newJSONResponseErrors(
	ctx context.Context,
	responseErrorer ResponseErrorer,
	errs ...*ErrorJSON) ([]*ErrorJSON, error) {
	config, ok := ctx.Value(CtxKeyConfig).(goarmorconfigs.Configer)
	if !ok {
		return nil, errors.New("context.Value fn error")
	}

	errs = append(errs, responseErrorer.ResponseErrors()...)

	var publicErrors []*ErrorJSON

	if config.ServerDebuggingLevel() > 0 {
		for _, x := range errs {
			publicErrors = append(publicErrors,
				&ErrorJSON{
					Code:     x.Code,
					Error:    errors.New(x.Error.Error()),
					Public:   x.Public,
					Severity: x.Severity})
		}

	} else {
		isKVRemoved := false

		for _, x := range errs {
			if x.Public {
				publicErrors = append(publicErrors,
					&ErrorJSON{
						Code:     x.Code,
						Error:    errors.New(x.Error.Error()),
						Public:   x.Public,
						Severity: x.Severity})

				continue
			}

			if x.Code == uint64(ErrCodeDefautlDebug) {
				isKVRemoved = true

				continue
			}

			publicErrors = append(publicErrors,
				&ErrorJSON{Code: x.Code, Severity: x.Severity})
		}

		if isKVRemoved {
			// Add empty (only with "code") "ErrorJSON" structure in order to be able to
			// determine was an key-values in hadler's response.
			publicErrors = append(publicErrors, &ErrorJSON{Code: uint64(ErrCodeDefautlDebug)})
		}
	}

	return publicErrors, nil
}
<commit_msg>minor<commit_after>package goarmorapi

import (
	"context"
	"encoding/json"
	"errors"
	"strings"
	"time"

	"github.com/armor5games/goarmor/goarmorconfigs"
)

type JSONRequest struct {
	Payload interface{} `json:",omitempty"`
	Time    uint64      `json:",omitempty"`
}

type JSONResponse struct {
	Success bool
	Errors  []*ErrorJSON `json:",omitempty"`
	Payload interface{}  `json:",omitempty"`
	Time    uint64       `json:",omitempty"`
}

type ErrorJSON struct {
	Code uint64
	// TODO: Rename "Error" to "Err"
	Error    error  `json:"Message,omitempty"`
	Public   bool   `json:"-"`
	Severity uint64 `json:"-"`
}

type ErrorJSONSeverity uint64

const (
	ErrSeverityDebug ErrorJSONSeverity = iota
	ErrSeverityInfo
	ErrSeverityWarn
	ErrSeverityError
	ErrSeverityFatal
	ErrSeverityPanic
)

func (s ErrorJSONSeverity) ErrorDefaultCode() uint64 {
	var c ErrorJSONCode

	switch s {
	default:
		return 0

	case ErrSeverityDebug:
		c = ErrCodeDefautlDebug

	case ErrSeverityInfo:
		c = ErrCodeDefautlInfo

	case ErrSeverityWarn:
		c = ErrCodeDefautlWarn

	case ErrSeverityError:
		c = ErrCodeDefautlError

	case ErrSeverityFatal:
		c = ErrCodeDefautlFatal

	case ErrSeverityPanic:
		c = ErrCodeDefautlPanic
	}

	return uint64(c)
}

type ErrorJSONCode uint64

const (
	ErrCodeDefautlDebug ErrorJSONCode = 1100
	ErrCodeDefautlInfo
	ErrCodeDefautlWarn

	ErrCodeDefautlError ErrorJSONCode = 5100
	ErrCodeDefautlFatal
	ErrCodeDefautlPanic
)

type ResponseErrorer interface {
	ResponseErrors() []*ErrorJSON
}

func (e *ErrorJSON) MarshalJSON() ([]byte, error) {
	var m string

	if e.Error != nil {
		m = e.Error.Error()
	}

	return json.Marshal(&struct {
		Code    uint64
		Message string `json:",omitempty"`
	}{
		Code:    uint64(e.Code),
		Message: m})
}

func (e *ErrorJSON) UnmarshalJSON(b []byte) error {
	s := &struct {
		Code    uint64
		Message string
	}{}

	if err := json.Unmarshal(b, &s); err != nil {
		return err
	}

	e.Code = s.Code

	if s.Message != "" {
		e.Error = errors.New(s.Message)
	}

	return nil
}

func (j *JSONResponse) KV() (KV, error) {
	if j == nil {
		return nil, errors.New("empty api response")
	}

	if len(j.Errors) == 0 {
		return nil, errors.New("empty key values")
	}

	kv := NewKV()

	for _, e := range j.Errors {
		if e.Code != uint64(ErrCodeDefautlDebug) {
			continue
		}

		if e.Error.Error() == "" {
			return nil, errors.New("empty kv")
		}

		x := strings.SplitN(e.Error.Error(), ":", 2)
		if len(x) != 2 {
			return nil, errors.New("bad kv format")
		}

		kv[x[0]] = x[1]
	}

	if len(kv) == 0 {
		return nil, errors.New("empty kv")
	}

	return kv, nil
}

func NewJSONRequest(
	ctx context.Context,
	responsePayload interface{}) (*JSONRequest, error) {
	return &JSONRequest{
		Payload: responsePayload,
		Time:    uint64(time.Now().Unix())}, nil
}

func NewJSONResponse(
	ctx context.Context,
	isSuccess bool,
	responsePayload interface{},
	responseErrorer ResponseErrorer,
	errs ...*ErrorJSON) (*JSONResponse, error) {
	publicErrors, err := newJSONResponseErrors(ctx, responseErrorer, errs...)
	if err != nil {
		return nil, err
	}

	return &JSONResponse{
		Success: isSuccess,
		Errors:  publicErrors,
		Payload: responsePayload,
		Time:    uint64(time.Now().Unix())}, nil
}

func newJSONResponseErrors(
	ctx context.Context,
	responseErrorer ResponseErrorer,
	errs ...*ErrorJSON) ([]*ErrorJSON, error) {
	config, ok := ctx.Value(CtxKeyConfig).(goarmorconfigs.Configer)
	if !ok {
		return nil, errors.New("context.Value fn error")
	}

	errs = append(errs, responseErrorer.ResponseErrors()...)

	var publicErrors []*ErrorJSON

	if config.ServerDebuggingLevel() > 0 {
		for _, x := range errs {
			publicErrors = append(publicErrors,
				&ErrorJSON{
					Code:     x.Code,
					Error:    errors.New(x.Error.Error()),
					Public:   x.Public,
					Severity: x.Severity})
		}

	} else {
		isKVRemoved := false

		for _, x := range errs {
			if x.Public {
				publicErrors = append(publicErrors,
					&ErrorJSON{
						Code:     x.Code,
						Error:    errors.New(x.Error.Error()),
						Public:   x.Public,
						Severity: x.Severity})

				continue
			}

			if x.Code == uint64(ErrCodeDefautlDebug) {
				isKVRemoved = true

				continue
			}

			publicErrors = append(publicErrors,
				&ErrorJSON{Code: x.Code, Severity: x.Severity})
		}

		if isKVRemoved {
			// Add empty (only with "code") "ErrorJSON" structure in order to be able to
			// determine was an key-values in hadler's response.
			publicErrors = append(publicErrors, &ErrorJSON{Code: uint64(ErrCodeDefautlDebug)})
		}
	}

	return publicErrors, nil
}
<|endoftext|>


<commit_before>package goarmorapi

import (
	"context"
	"encoding/json"
	"errors"
	"strings"
	"time"

	"github.com/armor5games/goarmor/goarmorconfigs"
)

type JSONRequest struct {
	Payload interface{} `json:"payload,omitempty"`
	Time    uint64      `json:"time,omitempty"`
}

type JSONResponse struct {
	Success bool         `json:"success"`
	Errors  []*ErrorJSON `json:"messages,omitempty"`
	Payload interface{}  `json:"payload,omitempty"`
	Time    uint64       `json:"time,omitempty"`
}

type ErrorJSON struct {
	Code uint64
	// TODO: Rename "Error" to "Err"
	Err      error  `json:"message,omitempty"`
	Public   bool   `json:"-"`
	Severity uint64 `json:"-"`
}

type ErrorJSONSeverity uint64

const (
	ErrSeverityUnknown ErrorJSONSeverity = iota
	ErrSeverityDebug
	ErrSeverityInfo
	ErrSeverityWarn
	ErrSeverityError
	ErrSeverityFatal
	ErrSeverityPanic
)

func (s ErrorJSONSeverity) ErrorDefaultCode() uint64 {
	var c ErrorJSONCode

	switch s {
	default:
		return 0

	case ErrSeverityDebug:
		c = ErrCodeDefautlDebug

	case ErrSeverityInfo:
		c = ErrCodeDefautlInfo

	case ErrSeverityWarn:
		c = ErrCodeDefautlWarn

	case ErrSeverityError:
		c = ErrCodeDefautlError

	case ErrSeverityFatal:
		c = ErrCodeDefautlFatal

	case ErrSeverityPanic:
		c = ErrCodeDefautlPanic
	}

	return uint64(c)
}

type ErrorJSONCode uint64

const (
	ErrCodeDefautlDebug ErrorJSONCode = 1100
	ErrCodeDefautlInfo
	ErrCodeDefautlWarn

	ErrCodeDefautlError ErrorJSONCode = 5100
	ErrCodeDefautlFatal
	ErrCodeDefautlPanic
)

type ResponseErrorer interface {
	ResponseErrors() []*ErrorJSON
}

func (e *ErrorJSON) Error() string {
	return e.Err.Error()
}

func (e *ErrorJSON) MarshalJSON() ([]byte, error) {
	var m string

	if e.Err != nil {
		m = e.Error()
	}

	return json.Marshal(&struct {
		Code    uint64 `json:"code,omitempty"`
		Message string `json:"message,omitempty"`
	}{
		Code:    e.Code,
		Message: m})
}

func (e *ErrorJSON) UnmarshalJSON(b []byte) error {
	s := &struct {
		Code    uint64 `json:"code"`
		Message string `json:"message"`
	}{}

	if err := json.Unmarshal(b, &s); err != nil {
		return err
	}

	e.Code = s.Code

	if s.Message != "" {
		e.Err = errors.New(s.Message)
	}

	return nil
}

func (j *JSONResponse) KV() (KV, error) {
	if j == nil {
		return nil, errors.New("empty api response")
	}

	if len(j.Errors) == 0 {
		return nil, errors.New("empty key values")
	}

	kv := NewKV()

	for _, e := range j.Errors {
		if e.Code != uint64(ErrCodeDefautlDebug) {
			continue
		}

		if e.Error() == "" {
			return nil, errors.New("empty kv")
		}

		x := strings.SplitN(e.Error(), ":", 2)
		if len(x) != 2 {
			return nil, errors.New("bad kv format")
		}

		kv[x[0]] = x[1]
	}

	if len(kv) == 0 {
		return nil, errors.New("empty kv")
	}

	return kv, nil
}

func NewJSONRequest(
	ctx context.Context,
	responsePayload interface{}) (*JSONRequest, error) {
	return &JSONRequest{
		Payload: responsePayload,
		Time:    uint64(time.Now().Unix())}, nil
}

func NewJSONResponse(
	ctx context.Context,
	isSuccess bool,
	responsePayload interface{},
	responseErrorer ResponseErrorer,
	errs ...*ErrorJSON) (*JSONResponse, error) {
	publicErrors, err := newJSONResponseErrors(ctx, responseErrorer, errs...)
	if err != nil {
		return nil, err
	}

	return &JSONResponse{
		Success: isSuccess,
		Errors:  publicErrors,
		Payload: responsePayload,
		Time:    uint64(time.Now().Unix())}, nil
}

func newJSONResponseErrors(
	ctx context.Context,
	responseErrorer ResponseErrorer,
	errs ...*ErrorJSON) ([]*ErrorJSON, error) {
	config, ok := ctx.Value(CtxKeyConfig).(goarmorconfigs.Configer)
	if !ok {
		return nil, errors.New("context.Value fn error")
	}

	errs = append(errs, responseErrorer.ResponseErrors()...)

	var publicErrors []*ErrorJSON

	if config.ServerDebuggingLevel() > 0 {
		for _, x := range errs {
			publicErrors = append(publicErrors,
				&ErrorJSON{
					Code:     x.Code,
					Err:      errors.New(x.Error()),
					Public:   x.Public,
					Severity: x.Severity})
		}

	} else {
		isKVRemoved := false

		for _, x := range errs {
			if x.Public {
				publicErrors = append(publicErrors,
					&ErrorJSON{
						Code:     x.Code,
						Err:      errors.New(x.Error()),
						Public:   x.Public,
						Severity: x.Severity})

				continue
			}

			if x.Code == uint64(ErrCodeDefautlDebug) {
				isKVRemoved = true

				continue
			}

			publicErrors = append(publicErrors,
				&ErrorJSON{Code: x.Code, Severity: x.Severity})
		}

		if isKVRemoved {
			// Add empty (only with "code") "ErrorJSON" structure in order to be able to
			// determine was an key-values in hadler's response.
			publicErrors = append(publicErrors, &ErrorJSON{Code: uint64(ErrCodeDefautlDebug)})
		}
	}

	return publicErrors, nil
}
<commit_msg>feat: print error stack trace in json response's errors<commit_after>package goarmorapi

import (
	"context"
	"encoding/json"
	"fmt"
	"strings"
	"time"

	"github.com/armor5games/goarmor/goarmorconfigs"
	"github.com/pkg/errors"
)

type JSONRequest struct {
	Payload interface{} `json:"payload,omitempty"`
	Time    uint64      `json:"time,omitempty"`
}

type JSONResponse struct {
	Success bool         `json:"success"`
	Errors  []*ErrorJSON `json:"messages,omitempty"`
	Payload interface{}  `json:"payload,omitempty"`
	Time    uint64       `json:"time,omitempty"`
}

type ErrorJSON struct {
	Code     uint64 `json:"code"`
	Err      error  `json:"message,omitempty"`
	Public   bool   `json:"-"`
	Severity uint64 `json:"-"`
}

type ErrorJSONSeverity uint64

const (
	ErrSeverityUnknown ErrorJSONSeverity = iota
	ErrSeverityDebug
	ErrSeverityInfo
	ErrSeverityWarn
	ErrSeverityError
	ErrSeverityFatal
	ErrSeverityPanic
)

func (s ErrorJSONSeverity) ErrorDefaultCode() uint64 {
	var c ErrorJSONCode

	switch s {
	default:
		return 0

	case ErrSeverityDebug:
		c = ErrCodeDefautlDebug

	case ErrSeverityInfo:
		c = ErrCodeDefautlInfo

	case ErrSeverityWarn:
		c = ErrCodeDefautlWarn

	case ErrSeverityError:
		c = ErrCodeDefautlError

	case ErrSeverityFatal:
		c = ErrCodeDefautlFatal

	case ErrSeverityPanic:
		c = ErrCodeDefautlPanic
	}

	return uint64(c)
}

type ErrorJSONCode uint64

const (
	ErrCodeDefautlDebug ErrorJSONCode = 1100
	ErrCodeDefautlInfo
	ErrCodeDefautlWarn

	ErrCodeDefautlError ErrorJSONCode = 5100
	ErrCodeDefautlFatal
	ErrCodeDefautlPanic
)

type ResponseErrorer interface {
	ResponseErrors() []*ErrorJSON
}

func (e *ErrorJSON) Error() string {
	return e.Err.Error()
}

func (e *ErrorJSON) MarshalJSON() ([]byte, error) {
	var (
		s string
		a []string
	)

	if e.Err != nil {
		s = e.Error()

		switch ErrorJSONSeverity(e.Severity) {
		case ErrSeverityError, ErrSeverityFatal, ErrSeverityPanic:
			a = strings.Split(fmt.Sprintf("%+v", e.Err), "\n")
			a = append(a[1:2], a[2:]...)
		}
	}

	return json.Marshal(&struct {
		Code       uint64   `json:"code,omitempty"`
		Message    string   `json:"message,omitempty"`
		StackTrace []string `json:"stackTrace,omitempty"`
	}{
		Code:       e.Code,
		Message:    s,
		StackTrace: a})
}

func (e *ErrorJSON) UnmarshalJSON(b []byte) error {
	s := &struct {
		Code    uint64 `json:"code"`
		Message string `json:"message"`
	}{}

	if err := json.Unmarshal(b, &s); err != nil {
		return err
	}

	e.Code = s.Code

	if s.Message != "" {
		e.Err = errors.New(s.Message)
	}

	return nil
}

func (j *JSONResponse) KV() (KV, error) {
	if j == nil {
		return nil, errors.New("empty api response")
	}

	if len(j.Errors) == 0 {
		return nil, errors.New("empty key values")
	}

	kv := NewKV()

	for _, e := range j.Errors {
		if e.Code != uint64(ErrCodeDefautlDebug) {
			continue
		}

		if e.Error() == "" {
			return nil, errors.New("empty kv")
		}

		x := strings.SplitN(e.Error(), ":", 2)
		if len(x) != 2 {
			return nil, errors.New("bad kv format")
		}

		kv[x[0]] = x[1]
	}

	if len(kv) == 0 {
		return nil, errors.New("empty kv")
	}

	return kv, nil
}

func NewJSONRequest(
	ctx context.Context,
	responsePayload interface{}) (*JSONRequest, error) {
	return &JSONRequest{
		Payload: responsePayload,
		Time:    uint64(time.Now().Unix())}, nil
}

func NewJSONResponse(
	ctx context.Context,
	isSuccess bool,
	responsePayload interface{},
	responseErrorer ResponseErrorer,
	errs ...*ErrorJSON) (*JSONResponse, error) {
	publicErrors, err := newJSONResponseErrors(ctx, responseErrorer, errs...)
	if err != nil {
		return nil, err
	}

	return &JSONResponse{
		Success: isSuccess,
		Errors:  publicErrors,
		Payload: responsePayload,
		Time:    uint64(time.Now().Unix())}, nil
}

func newJSONResponseErrors(
	ctx context.Context,
	responseErrorer ResponseErrorer,
	errs ...*ErrorJSON) ([]*ErrorJSON, error) {
	config, ok := ctx.Value(CtxKeyConfig).(goarmorconfigs.Configer)
	if !ok {
		return nil, errors.New("context.Value fn error")
	}

	errs = append(errs, responseErrorer.ResponseErrors()...)

	var publicErrors []*ErrorJSON

	if config.ServerDebuggingLevel() > 0 {
		for _, x := range errs {
			publicErrors = append(publicErrors,
				&ErrorJSON{
					Code:     x.Code,
					Err:      errors.New(x.Error()),
					Public:   x.Public,
					Severity: x.Severity})
		}

	} else {
		isKVRemoved := false

		for _, x := range errs {
			if x.Public {
				publicErrors = append(publicErrors,
					&ErrorJSON{
						Code:     x.Code,
						Err:      errors.New(x.Error()),
						Public:   x.Public,
						Severity: x.Severity})

				continue
			}

			if x.Code == uint64(ErrCodeDefautlDebug) {
				isKVRemoved = true

				continue
			}

			publicErrors = append(publicErrors,
				&ErrorJSON{Code: x.Code, Severity: x.Severity})
		}

		if isKVRemoved {
			// Add empty (only with "code") "ErrorJSON" structure in order to be able to
			// determine was an key-values in hadler's response.
			publicErrors = append(publicErrors, &ErrorJSON{Code: uint64(ErrCodeDefautlDebug)})
		}
	}

	return publicErrors, nil
}
<|endoftext|>


<commit_before>package goflags

import (
	"fmt"
	"os"
	"reflect"
	"strconv"
	"strings"

	"flag"

	"github.com/crgimenes/goconfig/structtag"
)

type parameterMeta struct {
	Kind  reflect.Kind
	Value interface{}
	Tag   string
}

var parametersMetaMap map[*reflect.Value]parameterMeta
var visitedMap map[string]*flag.Flag
var disableFags bool

// Preserve disable default values and get only visited parameters thus preserving the values passed in the structure, default false
var Preserve bool

// Prefix is a string that would be placed at the beginning of the generated tags.
var Prefix string

//Usage is a function to show the help, can be replaced by your own version.
var Usage func()

// Setup maps and variables
func Setup(tag string, tagDefault string) {
	Usage = DefaultUsage
	parametersMetaMap = make(map[*reflect.Value]parameterMeta)
	visitedMap = make(map[string]*flag.Flag)

	structtag.Setup()
	structtag.Prefix = Prefix
	SetTag(tag)
	SetTagDefault(tagDefault)

	structtag.ParseMap[reflect.Int64] = reflectInt
	structtag.ParseMap[reflect.Int] = reflectInt
	structtag.ParseMap[reflect.Float64] = reflectFloat
	structtag.ParseMap[reflect.String] = reflectString
	structtag.ParseMap[reflect.Bool] = reflectBool
}

// SetTag set a new tag
func SetTag(tag string) {
	structtag.Tag = tag
}

// SetTagDefault set a new TagDefault to retorn default values
func SetTagDefault(tag string) {
	structtag.TagDefault = tag
}

// Parse configuration
func Parse(config interface{}) (err error) {
	if disableFags {
		return
	}

	flag.Usage = Usage
	err = structtag.Parse(config, "")
	if err != nil {
		return
	}

	flag.Parse()

	flag.Visit(loadVisit)

	for k, v := range parametersMetaMap {
		if _, ok := visitedMap[v.Tag]; !ok && Preserve {
			continue
		}

		switch v.Kind {
		case reflect.String:
			value := *v.Value.(*string)
			k.SetString(value)
		case reflect.Int:
			value := *v.Value.(*int)
			k.SetInt(int64(value))
		case reflect.Float64:
			value := *v.Value.(*float64)
			k.SetFloat(value)
		case reflect.Bool:
			value := *v.Value.(*bool)
			k.SetBool(value)
		}
	}

	disableFags = true
	return
}

// Reset maps caling setup function
func Reset() {
	disableFags = false
	flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
	flag.Usage = nil

	structtag.Reset()
	Setup(structtag.Tag, structtag.TagDefault)
}

func loadVisit(f *flag.Flag) {
	visitedMap[f.Name] = f
}

func reflectInt(field *reflect.StructField, value *reflect.Value, tag string) (err error) {
	var aux int
	var defaltValue string
	var defaltValueInt int

	defaltValue = field.Tag.Get(structtag.TagDefault)

	if defaltValue == "" || defaltValue == "0" {
		defaltValueInt = 0
	} else {
		defaltValueInt, err = strconv.Atoi(defaltValue)
		if err != nil {
			return
		}
	}

	meta := parameterMeta{}
	meta.Value = &aux
	meta.Tag = strings.ToLower(tag)
	meta.Kind = reflect.Int
	parametersMetaMap[value] = meta

	flag.IntVar(&aux, meta.Tag, defaltValueInt, "")

	//fmt.Println(tag, defaltValue)

	return
}

func reflectFloat(field *reflect.StructField, value *reflect.Value, tag string) (err error) {
	var aux float64
	var defaltValue string
	var defaltValueFloat float64

	defaltValue = field.Tag.Get(structtag.TagDefault)

	if defaltValue == "" || defaltValue == "0" {
		defaltValueFloat = 0
	} else {
		defaltValueFloat, err = strconv.ParseFloat(defaltValue, 64)
		if err != nil {
			return
		}
	}

	meta := parameterMeta{}
	meta.Value = &aux
	meta.Tag = strings.ToLower(tag)
	meta.Kind = reflect.Float64
	parametersMetaMap[value] = meta

	flag.Float64Var(&aux, meta.Tag, defaltValueFloat, "")

	return
}

func reflectString(field *reflect.StructField, value *reflect.Value, tag string) (err error) {

	var aux, defaltValue string
	defaltValue = field.Tag.Get(structtag.TagDefault)

	meta := parameterMeta{}
	meta.Value = &aux
	meta.Tag = strings.ToLower(tag)
	meta.Kind = reflect.String
	parametersMetaMap[value] = meta

	flag.StringVar(&aux, meta.Tag, defaltValue, "")

	//fmt.Println(tag, defaltValue)

	return
}

func reflectBool(field *reflect.StructField, value *reflect.Value, tag string) (err error) {

	var aux bool
	var defaltValue bool
	defaltTag := field.Tag.Get(structtag.TagDefault)
	defaltValue = defaltTag == "true" || defaltTag == "t"

	meta := parameterMeta{}
	meta.Value = &aux
	meta.Tag = strings.ToLower(tag)
	meta.Kind = reflect.Bool
	parametersMetaMap[value] = meta

	flag.BoolVar(&aux, meta.Tag, defaltValue, "")

	//fmt.Println(tag, defaltValue)

	return
}

// PrintDefaults print the default help
func PrintDefaults() {
	flag.PrintDefaults()

}

// DefaultUsage is assigned for Usage function by default
func DefaultUsage() {
	fmt.Println("Usage")
	PrintDefaults()
}
<commit_msg>implement TagUsage<commit_after>package goflags

import (
	"fmt"
	"os"
	"reflect"
	"strconv"
	"strings"

	"flag"

	"github.com/crgimenes/goconfig/structtag"
)

type parameterMeta struct {
	Kind  reflect.Kind
	Value interface{}
	Tag   string
}

var parametersMetaMap map[*reflect.Value]parameterMeta
var visitedMap map[string]*flag.Flag
var disableFags bool

// Preserve disable default values and get only visited parameters thus preserving the values passed in the structure, default false
var Preserve bool

// Prefix is a string that would be placed at the beginning of the generated tags.
var Prefix string

//Usage is a function to show the help, can be replaced by your own version.
var Usage func()

// Setup maps and variables
func Setup(tag, tagDefault, tagUsage string) {
	Usage = DefaultUsage
	parametersMetaMap = make(map[*reflect.Value]parameterMeta)
	visitedMap = make(map[string]*flag.Flag)

	structtag.Setup()
	structtag.Prefix = Prefix
	SetTag(tag)
	SetTagDefault(tagDefault)
	SetTagUsage(tagUsage)

	structtag.ParseMap[reflect.Int64] = reflectInt
	structtag.ParseMap[reflect.Int] = reflectInt
	structtag.ParseMap[reflect.Float64] = reflectFloat
	structtag.ParseMap[reflect.String] = reflectString
	structtag.ParseMap[reflect.Bool] = reflectBool
}

// SetTag set a new tag
func SetTag(tag string) {
	structtag.Tag = tag
}

// SetTagDefault set a new TagDefault to retorn default values
func SetTagDefault(tag string) {
	structtag.TagDefault = tag
}

// SetTagUsage set a new TagUsage
func SetTagUsage(tag string) {
	structtag.TagUsage = tag
}

// Parse configuration
func Parse(config interface{}) (err error) {
	if disableFags {
		return
	}

	flag.Usage = Usage
	err = structtag.Parse(config, "")
	if err != nil {
		return
	}

	flag.Parse()

	flag.Visit(loadVisit)

	for k, v := range parametersMetaMap {
		if _, ok := visitedMap[v.Tag]; !ok && Preserve {
			continue
		}

		switch v.Kind {
		case reflect.String:
			value := *v.Value.(*string)
			k.SetString(value)
		case reflect.Int:
			value := *v.Value.(*int)
			k.SetInt(int64(value))
		case reflect.Float64:
			value := *v.Value.(*float64)
			k.SetFloat(value)
		case reflect.Bool:
			value := *v.Value.(*bool)
			k.SetBool(value)
		}
	}

	disableFags = true
	return
}

// Reset maps caling setup function
func Reset() {
	disableFags = false
	flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
	flag.Usage = nil

	structtag.Reset()
	Setup(structtag.Tag, structtag.TagDefault, structtag.TagUsage)
}

func loadVisit(f *flag.Flag) {
	visitedMap[f.Name] = f
}

func reflectInt(field *reflect.StructField, value *reflect.Value, tag string) (err error) {
	var aux int
	var defaltValue string
	var defaltValueInt int

	defaltValue = field.Tag.Get(structtag.TagDefault)
	usage := field.Tag.Get(structtag.TagUsage)

	if defaltValue == "" || defaltValue == "0" {
		defaltValueInt = 0
	} else {
		defaltValueInt, err = strconv.Atoi(defaltValue)
		if err != nil {
			return
		}
	}

	meta := parameterMeta{}
	meta.Value = &aux
	meta.Tag = strings.ToLower(tag)
	meta.Kind = reflect.Int
	parametersMetaMap[value] = meta

	flag.IntVar(&aux, meta.Tag, defaltValueInt, usage)

	return
}

func reflectFloat(field *reflect.StructField, value *reflect.Value, tag string) (err error) {
	var aux float64
	var defaltValue string
	var defaltValueFloat float64

	defaltValue = field.Tag.Get(structtag.TagDefault)
	usage := field.Tag.Get(structtag.TagUsage)

	if defaltValue == "" || defaltValue == "0" {
		defaltValueFloat = 0
	} else {
		defaltValueFloat, err = strconv.ParseFloat(defaltValue, 64)
		if err != nil {
			return
		}
	}

	meta := parameterMeta{}
	meta.Value = &aux
	meta.Tag = strings.ToLower(tag)
	meta.Kind = reflect.Float64
	parametersMetaMap[value] = meta

	flag.Float64Var(&aux, meta.Tag, defaltValueFloat, usage)

	return
}

func reflectString(field *reflect.StructField, value *reflect.Value, tag string) (err error) {

	var aux, defaltValue string
	defaltValue = field.Tag.Get(structtag.TagDefault)
	usage := field.Tag.Get(structtag.TagUsage)

	meta := parameterMeta{}
	meta.Value = &aux
	meta.Tag = strings.ToLower(tag)
	meta.Kind = reflect.String
	parametersMetaMap[value] = meta

	flag.StringVar(&aux, meta.Tag, defaltValue, usage)

	return
}

func reflectBool(field *reflect.StructField, value *reflect.Value, tag string) (err error) {

	var aux bool
	var defaltValue bool
	defaltTag := field.Tag.Get(structtag.TagDefault)
	defaltValue = defaltTag == "true" || defaltTag == "t"
	usage := field.Tag.Get(structtag.TagUsage)

	meta := parameterMeta{}
	meta.Value = &aux
	meta.Tag = strings.ToLower(tag)
	meta.Kind = reflect.Bool
	parametersMetaMap[value] = meta

	flag.BoolVar(&aux, meta.Tag, defaltValue, usage)

	return
}

// PrintDefaults print the default help
func PrintDefaults() {
	flag.PrintDefaults()

}

// DefaultUsage is assigned for Usage function by default
func DefaultUsage() {
	fmt.Println("Usage")
	PrintDefaults()
}
<|endoftext|>


<commit_before>package tc

import (
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"unicode"
)

// No - models TC Number
type No struct {
	ID        string
	FirstName string
	LastName  string
	BirthYear int
}

type response struct {
	XMLName xml.Name
	Body    body
}

type body struct {
	XMLName  xml.Name
	Response result `xml:"TCKimlikNoDogrulaResponse"`
}

type result struct {
	XMLName xml.Name `xml:"TCKimlikNoDogrulaResponse"`
	Result  bool     `xml:"TCKimlikNoDogrulaResult"`
}

var reqBody = `<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
      <TCKimlikNoDogrula xmlns="http://tckimlik.nvi.gov.tr/WS">
	<TCKimlikNo>%s</TCKimlikNo>
	<Ad>%s</Ad>
	<Soyad>%s</Soyad>
	<DogumYili>%d</DogumYili>
      </TCKimlikNoDogrula>
  </soap:Body>
</soap:Envelope>
`

// IsValidFor checks given TC No is valid or not for given
// first, last name and birth year.
func IsValidFor(id, firstName, lastName string, birthYear int) (bool, error) {
	if len(id) != 11 {
		return false, fmt.Errorf("TC No must be 11 characters")
	}
	r := strings.NewReader(fmt.Sprintf(reqBody, id, toUpper(firstName), toUpper(lastName), birthYear))
	req, err := http.NewRequest("POST", "https://tckimlik.nvi.gov.tr/Service/KPSPublic.asmx?WSDL", r)
	if err != nil {
		return false, err
	}
	req.Header.Add("Content-Type", "text/xml; charset=utf-8")
	req.Header.Add("SOAPAction", "http://tckimlik.nvi.gov.tr/WS/TCKimlikNoDogrula")
	resp, err := (&http.Client{}).Do(req)
	if err != nil {
		return false, err
	}
	defer resp.Body.Close()
	res, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return false, err
	}
	var b response
	if err = xml.Unmarshal(res, &b); err != nil {
		return false, err
	}
	return b.Body.Response.Result, nil
}

func toUpper(s string) string {
	return strings.ToUpperSpecial(unicode.TurkishCase, s)
}

// IsValid verifies given identification is a valid possible id.
func IsValid(id string) bool {
	return len(id) == 11 && contains(id) && tenthDigit(id) && eleventhDigit(id)
}

func contains(id string) bool {
	for _, c := range id {
		if c < '0' || c > '9' {
			return false
		}
	}
	return true
}

func tenthDigit(id string) bool {
	return int(id[9])-'0' == mode(3*sum(id, 0, 9, 2)+sum(id, 1, 8, 2))
}

func eleventhDigit(id string) bool {
	return int(id[10])-'0' == mode(sum(id, 0, 9, 2)+3*sum(id, 1, 10, 2))
}

func mode(x int) int {
	x = (10 - x) % 10
	if x < 0 {
		x += 10
	}
	return x
}

func sum(id string, s, e, t int) int {
	var n int
	for ; s < e; s += t {
		n += int(id[s]) - '0'
	}
	return n
}
<commit_msg>s/contains/validChars/<commit_after>package tc

import (
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"unicode"
)

// No - models TC Number
type No struct {
	ID        string
	FirstName string
	LastName  string
	BirthYear int
}

type response struct {
	XMLName xml.Name
	Body    body
}

type body struct {
	XMLName  xml.Name
	Response result `xml:"TCKimlikNoDogrulaResponse"`
}

type result struct {
	XMLName xml.Name `xml:"TCKimlikNoDogrulaResponse"`
	Result  bool     `xml:"TCKimlikNoDogrulaResult"`
}

var reqBody = `<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
      <TCKimlikNoDogrula xmlns="http://tckimlik.nvi.gov.tr/WS">
	<TCKimlikNo>%s</TCKimlikNo>
	<Ad>%s</Ad>
	<Soyad>%s</Soyad>
	<DogumYili>%d</DogumYili>
      </TCKimlikNoDogrula>
  </soap:Body>
</soap:Envelope>
`

// IsValidFor checks given TC No is valid or not for given
// first, last name and birth year.
func IsValidFor(id, firstName, lastName string, birthYear int) (bool, error) {
	if len(id) != 11 {
		return false, fmt.Errorf("TC No must be 11 characters")
	}
	r := strings.NewReader(fmt.Sprintf(reqBody, id, toUpper(firstName), toUpper(lastName), birthYear))
	req, err := http.NewRequest("POST", "https://tckimlik.nvi.gov.tr/Service/KPSPublic.asmx?WSDL", r)
	if err != nil {
		return false, err
	}
	req.Header.Add("Content-Type", "text/xml; charset=utf-8")
	req.Header.Add("SOAPAction", "http://tckimlik.nvi.gov.tr/WS/TCKimlikNoDogrula")
	resp, err := (&http.Client{}).Do(req)
	if err != nil {
		return false, err
	}
	defer resp.Body.Close()
	res, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return false, err
	}
	var b response
	if err = xml.Unmarshal(res, &b); err != nil {
		return false, err
	}
	return b.Body.Response.Result, nil
}

func toUpper(s string) string {
	return strings.ToUpperSpecial(unicode.TurkishCase, s)
}

// IsValid verifies given identification is a valid possible id.
func IsValid(id string) bool {
	return len(id) == 11 && validChars(id) && tenthDigit(id) && eleventhDigit(id)
}

func validChars(id string) bool {
	for _, c := range id {
		if c < '0' || c > '9' {
			return false
		}
	}
	return true
}

func tenthDigit(id string) bool {
	return int(id[9])-'0' == mode(3*sum(id, 0, 9, 2)+sum(id, 1, 8, 2))
}

func eleventhDigit(id string) bool {
	return int(id[10])-'0' == mode(sum(id, 0, 9, 2)+3*sum(id, 1, 10, 2))
}

func mode(x int) int {
	x = (10 - x) % 10
	if x < 0 {
		x += 10
	}
	return x
}

func sum(id string, s, e, t int) int {
	var n int
	for ; s < e; s += t {
		n += int(id[s]) - '0'
	}
	return n
}
<|endoftext|>


<commit_before>// Copyright 2016, Cossack Labs Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package keystore

import (
	"fmt"
	. "github.com/cossacklabs/acra/utils"
	"github.com/cossacklabs/acra/zone"
	"github.com/cossacklabs/themis/gothemis/keys"
	"io/ioutil"
	"log"
	"os"
	"errors"
	"runtime"
)

func GetPublicKeyFilename(id []byte) string {
	return fmt.Sprintf("%s_zone.pub", string(id))
}

type FilesystemKeyStore struct {
	keys      map[string][]byte
	directory string
}

func NewFilesystemKeyStore(directory string) (*FilesystemKeyStore, error) {
	fi, err:=os.Stat(directory)
	if nil == err && runtime.GOOS == "linux" && fi.Mode().Perm().String() != "-rwx------"{
		log.Printf("Error: key store folder has an incorrect permissions")
		return nil, errors.New("key store folder has an incorrect permissions")
	}
	return &FilesystemKeyStore{directory: directory, keys: make(map[string][]byte)}, nil
}

func (*FilesystemKeyStore) get_zone_key_filename(id []byte) string {
	return fmt.Sprintf("%s_zone", string(id))
}

func (store *FilesystemKeyStore) GenerateZoneKey() ([]byte, []byte, error) {
	/* save private key in fs, return id and public key*/
	var id []byte
	for {
		// generate until key not exists
		id = zone.GenerateZoneId()
		if !store.HasZonePrivateKey(id) {
			break
		}
	}

	keypair, err := keys.New(keys.KEYTYPE_EC)
	if err != nil {
		return []byte{}, []byte{}, err
	}
	keydir, err := GetDefaultKeyDir()
	if err != nil {
		return []byte{}, []byte{}, err
	}
	err = os.MkdirAll(keydir, 0700)
	if err != nil {
		return []byte{}, []byte{}, err
	}
	err = ioutil.WriteFile(store.get_file_path(store.get_zone_key_filename(id)), keypair.Private.Value, 0600)
	if err != nil {
		return []byte{}, []byte{}, err
	}
	// cache key
	store.keys[store.get_zone_key_filename(id)] = keypair.Private.Value
	return id, keypair.Public.Value, nil
}

func (store *FilesystemKeyStore) get_file_path(filename string) string {
	return fmt.Sprintf("%s%s%s", store.directory, string(os.PathSeparator), filename)
}

func (store *FilesystemKeyStore) GetZonePrivateKey(id []byte) (*keys.PrivateKey, error) {
	fname := store.get_zone_key_filename(id)
	key, ok := store.keys[fname]
	if ok {
		log.Printf("Debug: load cached key: %s\n", fname)
		return &keys.PrivateKey{Value: key}, nil
	}
	private_key, err := LoadPrivateKey(store.get_file_path(fname))
	if err != nil {
		return nil, err
	}
	log.Printf("Debug: load key from fs: %s\n", fname)
	store.keys[fname] = private_key.Value
	return private_key, nil
}

func (store *FilesystemKeyStore) HasZonePrivateKey(id []byte) bool {
	// add caching false answers. now if key doesn't exists than always checks on fs
	// it's system call and slow.
	if len(id) == 0 {
		return false
	}
	fname := store.get_zone_key_filename(id)
	_, ok := store.keys[fname]
	if ok {
		return true
	}
	exists, _ := FileExists(store.get_file_path(fname))
	return exists
}

func (store *FilesystemKeyStore) GetProxyPublicKey(id []byte) (*keys.PublicKey, error) {
	fname := GetPublicKeyFilename(id)
	key, ok := store.keys[fname]
	if ok {
		log.Printf("Debug: load cached key: %s\n", fname)
		return &keys.PublicKey{Value: key}, nil
	}
	public_key, err := LoadPublicKey(store.get_file_path(fname))
	if err != nil {
		return nil, err
	}
	log.Printf("Debug: load key from fs: %s\n", fname)
	store.keys[fname] = public_key.Value
	return public_key, nil
}

func (store *FilesystemKeyStore) GetServerPrivateKey(id []byte) (*keys.PrivateKey, error) {
	fname := fmt.Sprintf("%s_server", id)
	key, ok := store.keys[fname]
	if ok {
		log.Printf("Debug: load cached key: %s\n", fname)
		return &keys.PrivateKey{Value: key}, nil
	}
	private_key, err := LoadPrivateKey(store.get_file_path(fname))
	if err != nil {
		return nil, err
	}
	log.Printf("Debug: load key from fs: %s\n", fname)
	store.keys[fname] = private_key.Value
	return private_key, nil
}
<commit_msg>fix concurrent write to map<commit_after>// Copyright 2016, Cossack Labs Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package keystore

import (
	"fmt"
	. "github.com/cossacklabs/acra/utils"
	"github.com/cossacklabs/acra/zone"
	"github.com/cossacklabs/themis/gothemis/keys"
	"io/ioutil"
	"log"
	"os"
	"errors"
	"runtime"
	"sync"
)

var lock = sync.RWMutex{}

func GetPublicKeyFilename(id []byte) string {
	return fmt.Sprintf("%s_zone.pub", string(id))
}

type FilesystemKeyStore struct {
	keys      map[string][]byte
	directory string
}

func NewFilesystemKeyStore(directory string) (*FilesystemKeyStore, error) {
	fi, err:=os.Stat(directory)
	if nil == err && runtime.GOOS == "linux" && fi.Mode().Perm().String() != "-rwx------"{
		log.Printf("Error: key store folder has an incorrect permissions")
		return nil, errors.New("key store folder has an incorrect permissions")
	}
	return &FilesystemKeyStore{directory: directory, keys: make(map[string][]byte)}, nil
}

func (*FilesystemKeyStore) get_zone_key_filename(id []byte) string {
	return fmt.Sprintf("%s_zone", string(id))
}

func (store *FilesystemKeyStore) GenerateZoneKey() ([]byte, []byte, error) {
	/* save private key in fs, return id and public key*/
	var id []byte
	for {
		// generate until key not exists
		id = zone.GenerateZoneId()
		if !store.HasZonePrivateKey(id) {
			break
		}
	}

	keypair, err := keys.New(keys.KEYTYPE_EC)
	if err != nil {
		return []byte{}, []byte{}, err
	}
	keydir, err := GetDefaultKeyDir()
	if err != nil {
		return []byte{}, []byte{}, err
	}
	err = os.MkdirAll(keydir, 0700)
	if err != nil {
		return []byte{}, []byte{}, err
	}
	err = ioutil.WriteFile(store.get_file_path(store.get_zone_key_filename(id)), keypair.Private.Value, 0600)
	if err != nil {
		return []byte{}, []byte{}, err
	}
	lock.Lock()
	defer lock.Unlock()
	// cache key
	store.keys[store.get_zone_key_filename(id)] = keypair.Private.Value
	return id, keypair.Public.Value, nil
}

func (store *FilesystemKeyStore) get_file_path(filename string) string {
	return fmt.Sprintf("%s%s%s", store.directory, string(os.PathSeparator), filename)
}

func (store *FilesystemKeyStore) GetZonePrivateKey(id []byte) (*keys.PrivateKey, error) {
	fname := store.get_zone_key_filename(id)
	lock.Lock()
	defer lock.Unlock()
	key, ok := store.keys[fname]
	if ok {
		log.Printf("Debug: load cached key: %s\n", fname)
		return &keys.PrivateKey{Value: key}, nil
	}
	private_key, err := LoadPrivateKey(store.get_file_path(fname))
	if err != nil {
		return nil, err
	}
	log.Printf("Debug: load key from fs: %s\n", fname)
	store.keys[fname] = private_key.Value
	return private_key, nil
}

func (store *FilesystemKeyStore) HasZonePrivateKey(id []byte) bool {
	// add caching false answers. now if key doesn't exists than always checks on fs
	// it's system call and slow.
	if len(id) == 0 {
		return false
	}
	fname := store.get_zone_key_filename(id)
	lock.RLock()
	defer lock.RUnlock()
	_, ok := store.keys[fname]
	if ok {
		return true
	}
	exists, _ := FileExists(store.get_file_path(fname))
	return exists
}

func (store *FilesystemKeyStore) GetProxyPublicKey(id []byte) (*keys.PublicKey, error) {
	fname := GetPublicKeyFilename(id)
	lock.Lock()
	defer lock.Unlock()
	key, ok := store.keys[fname]
	if ok {
		log.Printf("Debug: load cached key: %s\n", fname)
		return &keys.PublicKey{Value: key}, nil
	}
	public_key, err := LoadPublicKey(store.get_file_path(fname))
	if err != nil {
		return nil, err
	}
	log.Printf("Debug: load key from fs: %s\n", fname)
	store.keys[fname] = public_key.Value
	return public_key, nil
}

func (store *FilesystemKeyStore) GetServerPrivateKey(id []byte) (*keys.PrivateKey, error) {
	fname := fmt.Sprintf("%s_server", id)
	lock.Lock()
	defer lock.Unlock()
	key, ok := store.keys[fname]
	if ok {
		log.Printf("Debug: load cached key: %s\n", fname)
		return &keys.PrivateKey{Value: key}, nil
	}
	private_key, err := LoadPrivateKey(store.get_file_path(fname))
	if err != nil {
		return nil, err
	}
	log.Printf("Debug: load key from fs: %s\n", fname)
	store.keys[fname] = private_key.Value
	return private_key, nil
}
<|endoftext|>


<commit_before>// #cgo LDFLAGS: -Lwindows/lib -lglop
// #include "windows/include/glop.h"
package gos

import "C"

import (
	"github.com/runningwild/glop/gin"
	"github.com/runningwild/glop/system"
	"unsafe"
)

type win32SystemObject struct {
	horizon int64
	window  uintptr
}

var (
	win32_system_object win32SystemObject
)

// Call after runtime.LockOSThread(), *NOT* in an init function
func (win32 *win32SystemObject) Startup() {
	C.GlopInit()
}

func GetSystemInterface() system.Os {
	return &win32_system_object
}

func (win32 *win32SystemObject) Run() {
	//  C.Run()
}

func (win32 *win32SystemObject) Quit() {
	//  C.Quit()
}

func (win32 *win32SystemObject) CreateWindow(x, y, width, height int) {
	title := []byte("Mob Rules")
	title = append(title, 0)
	win32.window = uintptr(unsafe.Pointer(C.GlopCreateWindow(
		unsafe.Pointer(&title[0]),
		C.int(x), C.int(y), C.int(width), C.int(height), 0, 8, 0)))
}

func (win32 *win32SystemObject) SwapBuffers() {
	C.GlopSwapBuffers(unsafe.Pointer(win32.window))
}

func (win32 *win32SystemObject) Think() {
	C.GlopThink()
}

// TODO: Make sure that events are given in sorted order (by timestamp)
// TODO: Adjust timestamp on events so that the oldest timestamp is newer than the
//       newest timestemp from the events from the previous call to GetInputEvents
//       Actually that should be in system
func (win32 *win32SystemObject) GetInputEvents() ([]gin.OsEvent, int64) {
	var first_event *C.GlopKeyEvent
	cp := (*unsafe.Pointer)(unsafe.Pointer(&first_event))
	var length C.int
	var horizon C.longlong
	C.GlopGetInputEvents(unsafe.Pointer(win32.window), cp, unsafe.Pointer(&length), unsafe.Pointer(&horizon))
	win32.horizon = int64(horizon)
	c_events := (*[10000]C.GlopKeyEvent)(unsafe.Pointer(first_event))[:length]
	events := make([]gin.OsEvent, length)
	for i := range c_events {
		wx, wy := win32.rawCursorToWindowCoords(int(c_events[i].cursor_x), int(c_events[i].cursor_y))
		events[i] = gin.OsEvent{
			KeyId:     gin.KeyId(c_events[i].index),
			Press_amt: float64(c_events[i].press_amt),
			Timestamp: int64(c_events[i].timestamp),
			X:         wx,
			Y:         wy,
		}
	}
	return events, win32.horizon
}

func (win32 *win32SystemObject) rawCursorToWindowCoords(x, y int) (int, int) {
	wx, wy, _, wdy := win32.GetWindowDims()
	return x - wx, wy + wdy - y
}

func (win32 *win32SystemObject) GetCursorPos() (int, int) {
	var x, y C.int
	C.GlopGetMousePosition(&x, &y)
	return win32.rawCursorToWindowCoords(int(x), int(y))
}

func (win32 *win32SystemObject) GetWindowDims() (int, int, int, int) {
	var x, y, dx, dy C.int
	C.GlopGetWindowDims(unsafe.Pointer(win32.window), &x, &y, &dx, &dy)
	return int(x), int(y), int(dx), int(dy)
}

func (win32 *win32SystemObject) EnableVSync(enable bool) {
	var _enable C.int
	if enable {
		_enable = 1
	}
	C.GlopEnableVSync(_enable)
}

func (win32 *win32SystemObject) HideCursor(hide bool) {
}

func (win32 *win32SystemObject) HasFocus() bool {
	// TODO: Implement me!
	return true
}
<commit_msg>Trying to fix some windows bugs<commit_after>package gos

// #cgo LDFLAGS: -Lwindows/lib -lglop
// #include "windows/include/glop.h"
import "C"

import (
	"github.com/runningwild/glop/gin"
	"github.com/runningwild/glop/system"
	"unsafe"
)

type win32SystemObject struct {
	horizon int64
	window  uintptr
}

var (
	win32_system_object win32SystemObject
)

// Call after runtime.LockOSThread(), *NOT* in an init function
func (win32 *win32SystemObject) Startup() {
	C.GlopInit()
}

func GetSystemInterface() system.Os {
	return &win32_system_object
}

func (win32 *win32SystemObject) GetActiveDevices() map[gin.DeviceType][]gin.DeviceIndex {
	return nil
}

func (win32 *win32SystemObject) Run() {
	//  C.Run()
}

func (win32 *win32SystemObject) Quit() {
	//  C.Quit()
}

func (win32 *win32SystemObject) CreateWindow(x, y, width, height int) {
	title := []byte("Glop")
	title = append(title, 0)
	win32.window = uintptr(unsafe.Pointer(C.GlopCreateWindow(
		unsafe.Pointer(&title[0]),
		C.int(x), C.int(y), C.int(width), C.int(height), 0, 8, 0)))
}

func (win32 *win32SystemObject) SwapBuffers() {
	C.GlopSwapBuffers(unsafe.Pointer(win32.window))
}

func (win32 *win32SystemObject) Think() {
	C.GlopThink()
}

// TODO: Make sure that events are given in sorted order (by timestamp)
// TODO: Adjust timestamp on events so that the oldest timestamp is newer than the
//       newest timestemp from the events from the previous call to GetInputEvents
//       Actually that should be in system
func (win32 *win32SystemObject) GetInputEvents() ([]gin.OsEvent, int64) {
	var first_event *C.GlopKeyEvent
	cp := (*unsafe.Pointer)(unsafe.Pointer(&first_event))
	var length C.int
	var horizon C.longlong
	C.GlopGetInputEvents(unsafe.Pointer(win32.window), cp, unsafe.Pointer(&length), unsafe.Pointer(&horizon))
	win32.horizon = int64(horizon)
	c_events := (*[10000]C.GlopKeyEvent)(unsafe.Pointer(first_event))[:length]
	events := make([]gin.OsEvent, length)
	for i := range c_events {
		wx, wy := win32.rawCursorToWindowCoords(int(c_events[i].cursor_x), int(c_events[i].cursor_y))
		events[i] = gin.OsEvent{
			KeyId: gin.KeyId{
				Device: gin.DeviceId{
					Index: 5,
					Type:  gin.DeviceTypeKeyboard,
				},
				Index: gin.KeyIndex(c_events[i].index),
			},
			Press_amt: float64(c_events[i].press_amt),
			Timestamp: int64(c_events[i].timestamp),
		}
	}
	return events, win32.horizon
}

func (win32 *win32SystemObject) rawCursorToWindowCoords(x, y int) (int, int) {
	wx, wy, _, wdy := win32.GetWindowDims()
	return x - wx, wy + wdy - y
}

func (win32 *win32SystemObject) GetCursorPos() (int, int) {
	var x, y C.int
	C.GlopGetMousePosition(&x, &y)
	return win32.rawCursorToWindowCoords(int(x), int(y))
}

func (win32 *win32SystemObject) GetWindowDims() (int, int, int, int) {
	var x, y, dx, dy C.int
	C.GlopGetWindowDims(unsafe.Pointer(win32.window), &x, &y, &dx, &dy)
	return int(x), int(y), int(dx), int(dy)
}

func (win32 *win32SystemObject) EnableVSync(enable bool) {
	var _enable C.int
	if enable {
		_enable = 1
	}
	C.GlopEnableVSync(_enable)
}

func (win32 *win32SystemObject) HideCursor(hide bool) {
}

func (win32 *win32SystemObject) HasFocus() bool {
	// TODO: Implement me!
	return true
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"time"

	"github.com/gocolly/colly/v2"
)

type item struct {
	StoryURL  string
	Source    string
	comments  string
	CrawledAt time.Time
	Comments  string
	Title     string
}

func main() {
	stories := []item{}
	// Instantiate default collector
	c := colly.NewCollector(
		// Visit only domains: old.reddit.com
		colly.AllowedDomains("old.reddit.com"),
		colly.Async(),
	)

	// On every a element which has .top-matter attribute call callback
	// This class is unique to the div that holds all information about a story
	c.OnHTML(".top-matter", func(e *colly.HTMLElement) {
		temp := item{}
		temp.StoryURL = e.ChildAttr("a[data-event-action=title]", "href")
		temp.Source = "https://old.reddit.com/r/programming/"
		temp.Title = e.ChildText("a[data-event-action=title]")
		temp.Comments = e.ChildAttr("a[data-event-action=comments]", "href")
		temp.CrawledAt = time.Now()
		stories = append(stories, temp)
	})

	// On every span tag with the class next-button
	c.OnHTML("span.next-button", func(h *colly.HTMLElement) {
		t := h.ChildAttr("a", "href")
		c.Visit(t)
	})

	// Set max Parallelism and introduce a Random Delay
	c.Limit(&colly.LimitRule{
		Parallelism: 2,
		RandomDelay: 5 * time.Second,
	})

	// Before making a request print "Visiting ..."
	c.OnRequest(func(r *colly.Request) {
		fmt.Println("Visiting", r.URL.String())

	})

	// Crawl all reddits the user passes in
	reddits := os.Args[1:]
	for _, reddit := range reddits {
		c.Visit(reddit)

	}

	c.Wait()
	fmt.Println(stories)

}
<commit_msg>Updated reddit example with correct arguments for calling colly.Async<commit_after>package main

import (
	"fmt"
	"os"
	"time"

	"github.com/gocolly/colly/v2"
)

type item struct {
	StoryURL  string
	Source    string
	comments  string
	CrawledAt time.Time
	Comments  string
	Title     string
}

func main() {
	stories := []item{}
	// Instantiate default collector
	c := colly.NewCollector(
		// Visit only domains: old.reddit.com
		colly.AllowedDomains("old.reddit.com"),
		colly.Async(true),
	)

	// On every a element which has .top-matter attribute call callback
	// This class is unique to the div that holds all information about a story
	c.OnHTML(".top-matter", func(e *colly.HTMLElement) {
		temp := item{}
		temp.StoryURL = e.ChildAttr("a[data-event-action=title]", "href")
		temp.Source = "https://old.reddit.com/r/programming/"
		temp.Title = e.ChildText("a[data-event-action=title]")
		temp.Comments = e.ChildAttr("a[data-event-action=comments]", "href")
		temp.CrawledAt = time.Now()
		stories = append(stories, temp)
	})

	// On every span tag with the class next-button
	c.OnHTML("span.next-button", func(h *colly.HTMLElement) {
		t := h.ChildAttr("a", "href")
		c.Visit(t)
	})

	// Set max Parallelism and introduce a Random Delay
	c.Limit(&colly.LimitRule{
		Parallelism: 2,
		RandomDelay: 5 * time.Second,
	})

	// Before making a request print "Visiting ..."
	c.OnRequest(func(r *colly.Request) {
		fmt.Println("Visiting", r.URL.String())

	})

	// Crawl all reddits the user passes in
	reddits := os.Args[1:]
	for _, reddit := range reddits {
		c.Visit(reddit)

	}

	c.Wait()
	fmt.Println(stories)

}
<|endoftext|>


<commit_before>package bgfx_glfw

// #cgo darwin LDFLAGS: -lglfw3 -framework Cocoa -framework OpenGL
// #cgo darwin LDFLAGS: -framework IOKit -framework CoreVideo
// #define GLFW_EXPOSE_NATIVE_COCOA
// #define GLFW_EXPOSE_NATIVE_NSGL
// #include <GLFW/glfw3.h>
// #include <GLFW/glfw3native.h>
import "C"

import (
	"unsafe"

	glfw "github.com/go-gl/glfw3"
	"github.com/james4k/go-bgfx"
)

func SetWindow(wnd *glfw.Window) {
	cwnd := *(*unsafe.Pointer)(unsafe.Pointer(wnd))
	nswnd := C.glfwGetNSGLContext((*C.GLFWwindow)(cwnd))
	bgfx.SetCocoaWindow(uintptr(unsafe.Pointer(nswnd)))
}
<commit_msg>updated to use go-gl/glfw3's new native api<commit_after>package bgfx_glfw

import (
	"unsafe"

	glfw "github.com/go-gl/glfw3"
	"github.com/james4k/go-bgfx"
)

func SetWindow(wnd *glfw.Window) {
	nswnd := wnd.GetNSGLContext()
	bgfx.SetCocoaWindow(uintptr(unsafe.Pointer(nswnd)))
}
<|endoftext|>


<commit_before>package pgx

import (
	"errors"
	"fmt"
)

// Transaction isolation levels
const (
	Serializable    = "serializable"
	RepeatableRead  = "repeatable read"
	ReadCommitted   = "read committed"
	ReadUncommitted = "read uncommitted"
)

var ErrTxClosed = errors.New("tx is closed")

// Begin starts a transaction with the default isolation level for the current
// connection. To use a specific isolation level see BeginIso.
func (c *Conn) Begin() (*Tx, error) {
	return c.begin("")
}

// BeginIso starts a transaction with isoLevel as the transaction isolation
// level.
//
// Valid isolation levels (and their constants) are:
//   serializable (pgx.Serializable)
//   repeatable read (pgx.RepeatableRead)
//   read committed (pgx.ReadCommitted)
//   read uncommitted (pgx.ReadUncommitted)
func (c *Conn) BeginIso(isoLevel string) (*Tx, error) {
	return c.begin(isoLevel)
}

func (c *Conn) begin(isoLevel string) (*Tx, error) {
	var beginSql string
	if isoLevel == "" {
		beginSql = "begin"
	} else {
		beginSql = fmt.Sprintf("begin isolation level %s", isoLevel)
	}

	_, err := c.Exec(beginSql)
	if err != nil {
		return nil, err
	}

	return &Tx{conn: c}, nil
}

// Tx represents a database transaction.
//
// All Tx methods return ErrTxClosed if Commit or Rollback has already been
// called on the Tx.
type Tx struct {
	conn       *Conn
	afterClose func(*Tx)
	closed     bool
}

// Commit commits the transaction
func (tx *Tx) Commit() error {
	if tx.closed {
		return ErrTxClosed
	}

	_, err := tx.conn.Exec("commit")
	tx.close()
	return err
}

// Rollback rolls back the transaction. Rollback will return ErrTxClosed if the
// Tx is already closed, but is otherwise safe to call multiple times. Hence, a
// defer tx.Rollback() is safe even if tx.Commit() will be called first in a
// non-error condition.
func (tx *Tx) Rollback() error {
	if tx.closed {
		return ErrTxClosed
	}

	_, err := tx.conn.Exec("rollback")
	tx.close()
	return err
}

func (tx *Tx) close() {
	if tx.afterClose != nil {
		tx.afterClose(tx)
	}
	tx.closed = true
}

// Exec delegates to the underlying *Conn
func (tx *Tx) Exec(sql string, arguments ...interface{}) (commandTag CommandTag, err error) {
	if tx.closed {
		return CommandTag(""), ErrTxClosed
	}

	return tx.conn.Exec(sql, arguments...)
}

// Query delegates to the underlying *Conn
func (tx *Tx) Query(sql string, args ...interface{}) (*Rows, error) {
	if tx.closed {
		// Because checking for errors can be deferred to the *Rows, build one with the error
		err := ErrTxClosed
		return &Rows{closed: true, err: err}, err
	}

	return tx.conn.Query(sql, args...)
}

// QueryRow delegates to the underlying *Conn
func (tx *Tx) QueryRow(sql string, args ...interface{}) *Row {
	rows, _ := tx.Query(sql, args...)
	return (*Row)(rows)
}

// AfterClose adds f to a LILO queue of functions that will be called when
// the transaction is closed (either Commit or Rollback).
func (tx *Tx) AfterClose(f func(*Tx)) {
	if tx.afterClose == nil {
		tx.afterClose = f
	} else {
		prevFn := tx.afterClose
		tx.afterClose = func(tx *Tx) {
			f(tx)
			prevFn(tx)
		}
	}
}
<commit_msg>Add *Tx.Conn getter method<commit_after>package pgx

import (
	"errors"
	"fmt"
)

// Transaction isolation levels
const (
	Serializable    = "serializable"
	RepeatableRead  = "repeatable read"
	ReadCommitted   = "read committed"
	ReadUncommitted = "read uncommitted"
)

var ErrTxClosed = errors.New("tx is closed")

// Begin starts a transaction with the default isolation level for the current
// connection. To use a specific isolation level see BeginIso.
func (c *Conn) Begin() (*Tx, error) {
	return c.begin("")
}

// BeginIso starts a transaction with isoLevel as the transaction isolation
// level.
//
// Valid isolation levels (and their constants) are:
//   serializable (pgx.Serializable)
//   repeatable read (pgx.RepeatableRead)
//   read committed (pgx.ReadCommitted)
//   read uncommitted (pgx.ReadUncommitted)
func (c *Conn) BeginIso(isoLevel string) (*Tx, error) {
	return c.begin(isoLevel)
}

func (c *Conn) begin(isoLevel string) (*Tx, error) {
	var beginSql string
	if isoLevel == "" {
		beginSql = "begin"
	} else {
		beginSql = fmt.Sprintf("begin isolation level %s", isoLevel)
	}

	_, err := c.Exec(beginSql)
	if err != nil {
		return nil, err
	}

	return &Tx{conn: c}, nil
}

// Tx represents a database transaction.
//
// All Tx methods return ErrTxClosed if Commit or Rollback has already been
// called on the Tx.
type Tx struct {
	conn       *Conn
	afterClose func(*Tx)
	closed     bool
}

// Commit commits the transaction
func (tx *Tx) Commit() error {
	if tx.closed {
		return ErrTxClosed
	}

	_, err := tx.conn.Exec("commit")
	tx.close()
	return err
}

// Rollback rolls back the transaction. Rollback will return ErrTxClosed if the
// Tx is already closed, but is otherwise safe to call multiple times. Hence, a
// defer tx.Rollback() is safe even if tx.Commit() will be called first in a
// non-error condition.
func (tx *Tx) Rollback() error {
	if tx.closed {
		return ErrTxClosed
	}

	_, err := tx.conn.Exec("rollback")
	tx.close()
	return err
}

func (tx *Tx) close() {
	if tx.afterClose != nil {
		tx.afterClose(tx)
	}
	tx.closed = true
}

// Exec delegates to the underlying *Conn
func (tx *Tx) Exec(sql string, arguments ...interface{}) (commandTag CommandTag, err error) {
	if tx.closed {
		return CommandTag(""), ErrTxClosed
	}

	return tx.conn.Exec(sql, arguments...)
}

// Query delegates to the underlying *Conn
func (tx *Tx) Query(sql string, args ...interface{}) (*Rows, error) {
	if tx.closed {
		// Because checking for errors can be deferred to the *Rows, build one with the error
		err := ErrTxClosed
		return &Rows{closed: true, err: err}, err
	}

	return tx.conn.Query(sql, args...)
}

// QueryRow delegates to the underlying *Conn
func (tx *Tx) QueryRow(sql string, args ...interface{}) *Row {
	rows, _ := tx.Query(sql, args...)
	return (*Row)(rows)
}

// Conn returns the *Conn this transaction is using.
func (tx *Tx) Conn() *Conn {
	return tx.conn
}

// AfterClose adds f to a LILO queue of functions that will be called when
// the transaction is closed (either Commit or Rollback).
func (tx *Tx) AfterClose(f func(*Tx)) {
	if tx.afterClose == nil {
		tx.afterClose = f
	} else {
		prevFn := tx.afterClose
		tx.afterClose = func(tx *Tx) {
			f(tx)
			prevFn(tx)
		}
	}
}
<|endoftext|>


<commit_before>package goidoit

// export getID
func TgetID() int {
	return getID()
}

// reset id
func TResetID() {
	id = 0
}

// export debug func
func TdebugPrint(format string, a ...interface{}) (n int, err error) {
	return debugPrint(format, a)
}

func TgetDebug() bool {
	return debug
}
<commit_msg>fixed internal_test wrapper<commit_after>package goidoit

// export getID
func TgetID() int {
	return getID()
}

// reset id
func TResetID() {
	id = 0
}

// export debug func
func TdebugPrint(format string, a ...interface{}) (n int, err error) {
	return debugPrint(format, a...)
}

func TgetDebug() bool {
	return debug
}
<|endoftext|>


<commit_before>// Copyright (c) 2017, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package interp

import (
	"bytes"
	"fmt"
	"io"
	"strconv"

	"github.com/mvdan/sh/syntax"
)

// A Runner interprets shell programs. It cannot be reused once a
// program has been interpreted.
//
// TODO: add context to kill the runner before it's done
type Runner struct {
	// TODO: syntax.Node instead of *syntax.File?
	File *syntax.File

	err  error // current fatal error
	exit int   // current (last) exit code

	// TODO: stdin, stderr
	Stdout io.Writer
}

type ExitCode uint8

func (e ExitCode) Error() string { return fmt.Sprintf("exit status %d", e) }

type InterpError struct {
	syntax.Position
	Text string
}

func (i InterpError) Error() string {
	return fmt.Sprintf("%s: %s", i.Position.String(), i.Text)
}

func (r *Runner) interpErr(pos syntax.Pos, format string, a ...interface{}) {
	if r.err == nil {
		r.err = InterpError{
			Position: r.File.Position(pos),
			Text:     fmt.Sprintf(format, a...),
		}
	}
}

// Run starts the interpreter and returns any error.
func (r *Runner) Run() error {
	r.node(r.File)
	if r.err == nil && r.exit != 0 {
		r.err = ExitCode(r.exit)
	}
	return r.err
}

func (r *Runner) node(node syntax.Node) {
	if r.err != nil {
		return
	}
	switch x := node.(type) {
	case *syntax.File:
		r.stmts(x.Stmts)
	case *syntax.Block:
		r.stmts(x.Stmts)
	case *syntax.Subshell:
		r.stmts(x.Stmts)
	case *syntax.Stmt:
		r.node(x.Cmd)
		if x.Negated {
			if r.exit == 0 {
				r.exit = 1
			} else {
				r.exit = 0
			}
		}
	case *syntax.CallExpr:
		r.call(x.Args[0], x.Args[1:])
	case *syntax.IfClause:
		r.stmts(x.CondStmts)
		if r.exit == 0 {
			r.stmts(x.ThenStmts)
			return
		}
		for _, el := range x.Elifs {
			r.stmts(el.CondStmts)
			if r.exit == 0 {
				r.stmts(el.ThenStmts)
				return
			}
		}
		r.stmts(x.ElseStmts)
		if len(x.Elifs)+len(x.ElseStmts) == 0 {
			r.exit = 0
		}
	case *syntax.WhileClause:
		for r.err == nil {
			r.stmts(x.CondStmts)
			if r.exit != 0 {
				r.exit = 0
				break
			}
			r.stmts(x.DoStmts)
		}
	default:
		panic(fmt.Sprintf("unhandled node: %T", x))
	}
}

func (r *Runner) stmts(stmts []*syntax.Stmt) {
	for _, stmt := range stmts {
		r.node(stmt)
	}
}

func (r *Runner) word(word *syntax.Word) string {
	var buf bytes.Buffer
	for _, wp := range word.Parts {
		switch x := wp.(type) {
		case *syntax.Lit:
			buf.WriteString(x.Value)
		default:
			panic(fmt.Sprintf("unhandled word part: %T", x))
		}
	}
	return buf.String()
}

func (r *Runner) call(prog *syntax.Word, args []*syntax.Word) {
	exit := 0
	name := r.word(prog)
	switch name {
	case "true", ":":
	case "false":
		exit = 1
	case "exit":
		switch len(args) {
		case 0:
			if r.exit != 0 {
				r.err = ExitCode(r.exit)
			}
		case 1:
			str := r.word(args[0])
			if n, err := strconv.Atoi(str); err != nil {
				r.interpErr(args[0].Pos(), "invalid exit code: %q", str)
			} else if n != 0 {
				r.err = ExitCode(n)
			}
		default:
			r.interpErr(prog.Pos(), "exit cannot take multiple arguments")
		}
	case "echo":
		for _, arg := range args {
			fmt.Fprint(r.Stdout, r.word(arg))
		}
		fmt.Fprintln(r.Stdout)
	default:
		panic(fmt.Sprintf("unhandled builtin: %s", name))
	}
	r.exit = exit
}
<commit_msg>interp: add some TODOs<commit_after>// Copyright (c) 2017, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package interp

import (
	"bytes"
	"fmt"
	"io"
	"strconv"

	"github.com/mvdan/sh/syntax"
)

// A Runner interprets shell programs. It cannot be reused once a
// program has been interpreted.
//
// TODO: add context to kill the runner before it's done
type Runner struct {
	// TODO: syntax.Node instead of *syntax.File?
	File *syntax.File

	err  error // current fatal error
	exit int   // current (last) exit code

	// TODO: stdin, stderr
	Stdout io.Writer
}

type ExitCode uint8

func (e ExitCode) Error() string { return fmt.Sprintf("exit status %d", e) }

type InterpError struct {
	syntax.Position
	Text string
}

func (i InterpError) Error() string {
	return fmt.Sprintf("%s: %s", i.Position.String(), i.Text)
}

func (r *Runner) interpErr(pos syntax.Pos, format string, a ...interface{}) {
	if r.err == nil {
		r.err = InterpError{
			Position: r.File.Position(pos),
			Text:     fmt.Sprintf(format, a...),
		}
	}
}

// Run starts the interpreter and returns any error.
func (r *Runner) Run() error {
	r.node(r.File)
	if r.err == nil && r.exit != 0 {
		r.err = ExitCode(r.exit)
	}
	return r.err
}

func (r *Runner) node(node syntax.Node) {
	if r.err != nil {
		return
	}
	switch x := node.(type) {
	case *syntax.File:
		r.stmts(x.Stmts)
	case *syntax.Block:
		r.stmts(x.Stmts)
	case *syntax.Subshell:
		// TODO: child process? encapsulate somehow anyway
		r.stmts(x.Stmts)
	case *syntax.Stmt:
		// TODO: handle background
		// TODO: assignments
		// TODO: redirects
		r.node(x.Cmd)
		if x.Negated {
			if r.exit == 0 {
				r.exit = 1
			} else {
				r.exit = 0
			}
		}
	case *syntax.CallExpr:
		r.call(x.Args[0], x.Args[1:])
	case *syntax.IfClause:
		r.stmts(x.CondStmts)
		if r.exit == 0 {
			r.stmts(x.ThenStmts)
			return
		}
		for _, el := range x.Elifs {
			r.stmts(el.CondStmts)
			if r.exit == 0 {
				r.stmts(el.ThenStmts)
				return
			}
		}
		r.stmts(x.ElseStmts)
		if len(x.Elifs)+len(x.ElseStmts) == 0 {
			r.exit = 0
		}
	case *syntax.WhileClause:
		for r.err == nil {
			r.stmts(x.CondStmts)
			if r.exit != 0 {
				r.exit = 0
				break
			}
			r.stmts(x.DoStmts)
		}
	default:
		panic(fmt.Sprintf("unhandled node: %T", x))
	}
}

func (r *Runner) stmts(stmts []*syntax.Stmt) {
	for _, stmt := range stmts {
		r.node(stmt)
	}
}

func (r *Runner) word(word *syntax.Word) string {
	var buf bytes.Buffer
	for _, wp := range word.Parts {
		switch x := wp.(type) {
		case *syntax.Lit:
			buf.WriteString(x.Value)
		default:
			panic(fmt.Sprintf("unhandled word part: %T", x))
		}
	}
	return buf.String()
}

func (r *Runner) call(prog *syntax.Word, args []*syntax.Word) {
	exit := 0
	name := r.word(prog)
	// TODO: builtins can be re-defined as funcs, vars, etc
	switch name {
	case "true", ":":
	case "false":
		exit = 1
	case "exit":
		switch len(args) {
		case 0:
			if r.exit != 0 {
				r.err = ExitCode(r.exit)
			}
		case 1:
			str := r.word(args[0])
			if n, err := strconv.Atoi(str); err != nil {
				r.interpErr(args[0].Pos(), "invalid exit code: %q", str)
			} else if n != 0 {
				r.err = ExitCode(n)
			}
		default:
			r.interpErr(prog.Pos(), "exit cannot take multiple arguments")
		}
	case "echo":
		for _, arg := range args {
			fmt.Fprint(r.Stdout, r.word(arg))
		}
		fmt.Fprintln(r.Stdout)
	default:
		// TODO: default should call binary in $PATH
		panic(fmt.Sprintf("unhandled builtin: %s", name))
	}
	r.exit = exit
}
<|endoftext|>