<commit_before>package offsets

import (
	"math"
	"testing"
	"time"

	"github.com/Shopify/sarama"
)

func TestNoOlderThanNow(t *testing.T) {
	sa, ooor := NoOlderThan(0)
	cl := &fakeClient{}

	o, err := sa("topic1", 0, 100, cl)
	if err != nil {
		t.Error(err)
	}
	if o != sarama.OffsetNewest {
		t.Error("unexpected", o)
	}

	o, err = ooor("topic1", 0, cl)
	if err != nil {
		t.Error(err)
	}
	if o != sarama.OffsetNewest {
		t.Error("unexpected", o)
	}
}

func TestNoOlderThan1Minute(t *testing.T) {
	sa, ooor := NoOlderThan(time.Minute)

	cl := &fakeClient{}

	approx := time.Now().Add(-time.Minute).UnixNano()
	o, err := sa("topic1", 0, 100, cl)
	if err != nil {
		t.Error(err)
	}
	if math.Abs(float64(o-approx)) > 1000000 {
		t.Error("unexpected", o)
	}

	approx = time.Now().Add(-time.Minute).UnixNano()
	o, err = ooor("topic1", 0, cl)
	if err != nil {
		t.Error(err)
	}
	if math.Abs(float64(o-approx)) > 1000000 {
		t.Error("unexpected", o)
	}
}

// a fake sarama.Client which maps time -> offsets using time
type fakeClient struct{}

func (*fakeClient) Config() *sarama.Config                                         { return nil }
func (*fakeClient) Brokers() []*sarama.Broker                                      { return nil }
func (*fakeClient) Topics() ([]string, error)                                      { return nil, nil }
func (*fakeClient) Partitions(topic string) ([]int32, error)                       { return nil, nil }
func (*fakeClient) WritablePartitions(topic string) ([]int32, error)               { return nil, nil }
func (*fakeClient) Leader(topic string, partitionID int32) (*sarama.Broker, error) { return nil, nil }
func (*fakeClient) Replicas(topic string, partitionID int32) ([]int32, error)      { return nil, nil }
func (*fakeClient) RefreshMetadata(topics ...string) error                         { return nil }
func (*fakeClient) Coordinator(consumerGroup string) (*sarama.Broker, error)       { return nil, nil }
func (*fakeClient) RefreshCoordinator(consumerGroup string) error                  { return nil }
func (*fakeClient) Close() error                                                   { return nil }
func (*fakeClient) Closed() bool                                                   { return false }

func (*fakeClient) GetOffset(topic string, partition int32, ts_msec int64) (int64, error) {
	return time.Unix(ts_msec/1000, (ts_msec%1000)*1000000).UnixNano(), nil
}
<commit_msg>add more unit tests, including some that fail on the broken code<commit_after>package offsets

import (
	"math"
	"testing"
	"time"

	"github.com/Shopify/sarama"
)

func TestNoOlderThanNow(t *testing.T) {
	sa, ooor := NoOlderThan(0)
	cl := &fakeClient{t}

	o, err := sa("topic1", 0, 100, cl)
	t.Logf("StartingOffset(100) -> %d", o)
	if err != nil {
		t.Error(err)
	}
	if o != sarama.OffsetNewest {
		t.Error("unexpected", o)
	}

	o, err = ooor("topic1", 0, cl)
	t.Logf("OffsetOutOfRange() -> %d", o)
	if err != nil {
		t.Error(err)
	}
	if o != sarama.OffsetNewest {
		t.Error("unexpected", o)
	}
}

func TestNoOlderThan1Minute(t *testing.T) {
	sa, ooor := NoOlderThan(time.Minute)

	cl := &fakeClient{t}

	approx := time.Now().Add(-time.Minute).UnixNano()
	o, err := sa("topic1", 0, -1, cl)
	t.Logf("StartingOffset(-1) -> %d", o)
	if err != nil {
		t.Error(err)
	}
	if math.Abs(float64(o-approx)) > 1000000 {
		t.Error("unexpected", o)
	}

	approx = time.Now().Add(-time.Minute).UnixNano()
	o, err = sa("topic1", 0, 100, cl)
	t.Logf("StartingOffset(100) -> %d", o)
	if err != nil {
		t.Error(err)
	}
	if math.Abs(float64(o-approx)) > 1000000 {
		t.Error("unexpected", o)
	}

	approx = time.Now().UnixNano()
	o, err = sa("topic1", 0, approx, cl)
	t.Logf("StartingOffset(100) -> %d", o)
	if err != nil {
		t.Error(err)
	}
	if math.Abs(float64(o-approx)) > 1000000 {
		t.Error("unexpected", o)
	}

	approx = time.Now().Add(-time.Minute).UnixNano()
	o, err = ooor("topic1", 0, cl)
	t.Logf("OffsetOutOfRange() -> %d", o)
	if err != nil {
		t.Error(err)
	}
	if math.Abs(float64(o-approx)) > 1000000 {
		t.Error("unexpected", o)
	}
}

// a fake sarama.Client which maps time -> offsets using time
type fakeClient struct{ t *testing.T }

func (*fakeClient) Brokers() []*sarama.Broker                                      { return nil }
func (*fakeClient) Topics() ([]string, error)                                      { return nil, nil }
func (*fakeClient) Partitions(topic string) ([]int32, error)                       { return nil, nil }
func (*fakeClient) WritablePartitions(topic string) ([]int32, error)               { return nil, nil }
func (*fakeClient) Leader(topic string, partitionID int32) (*sarama.Broker, error) { return nil, nil }
func (*fakeClient) Replicas(topic string, partitionID int32) ([]int32, error)      { return nil, nil }
func (*fakeClient) RefreshMetadata(topics ...string) error                         { return nil }
func (*fakeClient) Coordinator(consumerGroup string) (*sarama.Broker, error)       { return nil, nil }
func (*fakeClient) RefreshCoordinator(consumerGroup string) error                  { return nil }
func (*fakeClient) Close() error                                                   { return nil }
func (*fakeClient) Closed() bool                                                   { return false }

func (cl *fakeClient) GetOffset(topic string, partition int32, ts_msec int64) (int64, error) {
	offset := time.Unix(ts_msec/1000, (ts_msec%1000)*1000000).UnixNano()
	cl.t.Logf("GetOffset(%q,%d,%d) -> %d", topic, partition, ts_msec, offset)
	return offset, nil
}
func (*fakeClient) Config() *sarama.Config {
	cfg := sarama.NewConfig()
	return cfg
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
)

func main() {
	if len(os.Args) < 2 {
		perror(fmt.Errorf("%s: no arguments\n", os.Args[0]))
	}

	for _, path := range os.Args {
		if e := os.Mkdir(path, 0777); e != nil {
			perror(e)
		}
	}
}

func perror(err error) {
	fmt.Fprintf(os.Stderr, "[error] %v\n", err)
}
<commit_msg>mkdir.go: forget return statement<commit_after>package main

import (
	"fmt"
	"os"
)

func main() {
	if len(os.Args) < 2 {
		perror(fmt.Errorf("%s: no arguments\n", os.Args[0]))
		return
	}

	for _, path := range os.Args {
		if e := os.Mkdir(path, 0777); e != nil {
			perror(e)
		}
	}
}

func perror(err error) {
	fmt.Fprintf(os.Stderr, "[error] %v\n", err)
}
<|endoftext|>


<commit_before>// Copyright 2017 Benjamin 'Benno' Falkner. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// code is based on some c experiments (more efficient less platform independent)
// feel free to implement this code in CGO

/** mdb.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MDB_PAGE_SIZE 4096

#define MDB_VER_JET3 0
#define MDB_VER_JET4 1
#define MDB_VER_ACCDB2007 0x02
#define MDB_VER_ACCDB2010 0x0103

static char  JET3_XOR[] = { 0x86,0xfb,0xec,0x37,0x5d,0x44,0x9c,0xfa,0xc6,
                            0x5e,0x28,0xe6,0x13,0xb6,0x8a,0x60,0x54,0x94};

static short JET4_XOR[] = { 0x6aba,0x37ec,0xd561,0xfa9c,0xcffa,
                            0xe628,0x272f,0x608a,0x0568,0x367b,
                            0xe3c9,0xb1df,0x654b,0x4313,0x3ef3,
                            0x33b1,0xf008,0x5b79,0x24ae,0x2a7c};

size_t readMDBPage(char *filen, size_t pageSize, char *buffer)
{
    size_t r;
    FILE *f;

    f = fopen(filen,"rb");
    if( f==NULL ) {
        fprintf(stderr,"ERROR: could not open %s\n",filen);
        exit(1);
    }
    r = fread(buffer,1,pageSize,f);
    if( r != pageSize ) {
        fprintf(stderr,"ERROR: could not read page from %s (%li/%li)\n",filen,r,pageSize);
        exit(1);
    }
    fclose(f);
    return r;
}

int scanMDBPage(char *buffer){
    int i;
    int version;
    char pwd[40];
    short *pwd4 = (short*)pwd;
    short magic;

    //page id
    if(buffer[0]!=0){
        fprintf(stderr,"ERROR no vaild db\n");
        return 1;
    }

    //Version
    version = *((int*)&buffer[0x14]);
    switch(version){
        case MDB_VER_JET3:
                printf("DB Version: JET 3\n");
                break;
        case MDB_VER_JET4:
                printf("DB Version: JET 4\n");
                break;
        case MDB_VER_ACCDB2007:
                printf("DB Version: AccessDB 2007\n");
                break;
        case MDB_VER_ACCDB2010:
                printf("DB Version: AccessDB 2010\n");
                break;
        default:
                fprintf(stderr,"ERROR unkown version: %x\n",version);
                return 1;
    }

    //Password extract
    if( version==0 ) { // JET 3
        memcpy(pwd,buffer+0x42,20);
        for(i=0;i<18;i++){
            pwd[i] ^= JET3_XOR[i];
        }
        printf("Password: %20s\n",pwd);

    } else if ( version==1 ) { // JET 4
        memcpy(pwd,buffer+0x42,40);
        magic = *((short*)&buffer[0x66]);
        magic ^= JET4_XOR[18];

        for(i=0;i<18;i++){
            pwd4[i] ^= JET4_XOR[i];
            if(pwd4[i]>255){
                pwd4[i] ^= magic;
            }
            pwd[i] = pwd4[i];
        }
	        printf("Password: %20s\n",pwd);
    }
    return 0;
}

int main (int argc, char **argv)
{
    char page[MDB_PAGE_SIZE];

    //Check Arguments
    printf("MDB Access Tool\n");
    if (argc < 2){
        printf("Missing: file\n");
        return 1;
    }

    //Read data
    printf("Reading: %s\n", argv[1]);
    readMDBPage(argv[1],MDB_PAGE_SIZE,page);
    scanMDBPage(page);

    return 0;
}
**/

package accessdbwe

import (
	"io"
	"os"
	"errors"
	"encoding/binary"
	"strings"
	"fmt"
	"database/sql"
	_ "github.com/mattn/go-adodb"
)

//
// Implementing decoding of the so called password
//

// setting XOR Values
var JET3_XOR = []byte { 0x86,0xfb,0xec,0x37,0x5d,0x44,0x9c,0xfa,0xc6,
                        0x5e,0x28,0xe6,0x13,0xb6,0x8a,0x60,0x54,0x94}
var JET4_XOR = []byte { 0x6a,0xba,0x37,0xec,0xd5,0x61,0xfa,0x9c,0xcf,0xfa,
                        0xe6,0x28,0x27,0x2f,0x60,0x8a,0x05,0x68,0x36,0x7b,
                        0xe3,0xc9,0xb1,0xdf,0x65,0x4b,0x43,0x13,0x3e,0xf3,
                        0x33,0xb1,0xf0,0x08,0x5b,0x79,0x24,0xae,0x2a,0x7c}

func readEncoding(filen string) (string,error) {
	file, err := os.Open(filen)
	if err != nil {return "", err}
	defer file.Close()

	p, err := readPage(file)
	if err != nil {return "", err}

	if p[0] != 0 {return "", errors.New("ERROR no vaild db")}

	buf := make([]byte,20)
	switch binary.LittleEndian.Uint32(p[0x14:0x18]) {
		case 0x0:     //Jet3
			for i:=0; i<18; i++ {
				buf[i] = p[0x42+i] ^ JET3_XOR[i]
			}

		case 0x1,0x02,0x0103:     //Jet4
		 // sorry messed up byteorder
			p[0x66] = p[0x66] ^ JET4_XOR[36+1]
			p[0x67] = p[0x67] ^ JET4_XOR[36  ]
			for i:=0; i<18; i++ {
				p[0x42+2*i  ] = p[0x42+2*i  ] ^ JET4_XOR[2*i+1]
				p[0x42+2*i+1] = p[0x42+2*i+1] ^ JET4_XOR[2*i  ]

				if p[0x42+2*i+1] > 0 {
						p[0x42+2*i  ] = p[0x42+2*i  ] ^ p[0x66]
						p[0x42+2*i+1] = p[0x42+2*i+1] ^ p[0x67]
				}
				buf[i] = p[0x42+2*i]
			}
		//case 0x02:    //ACCDB2007  //should use same encoding as JET4
		//case 0x0103:  //ACCDB2010
		default:
			return "", errors.New("ERROR unknown encoding")
	}

	var i int
	for i=0; i<20; i++ {
		if buf[i]==0 {break}
	}
	return string(buf[:i]), nil

}

func readPage(r io.Reader) ([]byte, error) {
	p := make([]byte,4096)
	s, err := r.Read(p)
	if err != nil {return nil,err}
	if s != 4096 {return p,errors.New("ERROR incomplete page")}
	return p,nil
}

//
// Implementing new open function
//
func Open(driver, filen string) (*sql.DB, error){
	var err error
	var db *sql.DB

	// extract filename from filen string
	toks := strings.Split(filen,";")
	for _,tok := range toks {
		pair := strings.Split(tok,"=")
		if len(pair)>1 && pair[0] == "Data Source" {
			db.enc, err = readEncoding(pair[1])
			if err != nil {
				return nil,err
			}
			filen = filen + `;Jet OLEDB:Database Password=` + db.enc + `;`
		}
	}

	db, err = sql.Open("adodb", `Provider=Microsoft.ACE.OLEDB.12.0;Data Source=`+ filen +)
	if err != nil {return nil,err}

	err = db.Ping()
	if err != nil {return nil,err}
	return db,nil
}<commit_msg>Some changes to be more compatible with windows ado driver chaos<commit_after>// Copyright 2017 Benjamin 'Benno' Falkner. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// code is based on some c experiments (more efficient less platform independent)
// feel free to implement this code in CGO

/** mdb.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MDB_PAGE_SIZE 4096

#define MDB_VER_JET3 0
#define MDB_VER_JET4 1
#define MDB_VER_ACCDB2007 0x02
#define MDB_VER_ACCDB2010 0x0103

static char  JET3_XOR[] = { 0x86,0xfb,0xec,0x37,0x5d,0x44,0x9c,0xfa,0xc6,
                            0x5e,0x28,0xe6,0x13,0xb6,0x8a,0x60,0x54,0x94};

static short JET4_XOR[] = { 0x6aba,0x37ec,0xd561,0xfa9c,0xcffa,
                            0xe628,0x272f,0x608a,0x0568,0x367b,
                            0xe3c9,0xb1df,0x654b,0x4313,0x3ef3,
                            0x33b1,0xf008,0x5b79,0x24ae,0x2a7c};

size_t readMDBPage(char *filen, size_t pageSize, char *buffer)
{
    size_t r;
    FILE *f;

    f = fopen(filen,"rb");
    if( f==NULL ) {
        fprintf(stderr,"ERROR: could not open %s\n",filen);
        exit(1);
    }
    r = fread(buffer,1,pageSize,f);
    if( r != pageSize ) {
        fprintf(stderr,"ERROR: could not read page from %s (%li/%li)\n",filen,r,pageSize);
        exit(1);
    }
    fclose(f);
    return r;
}

int scanMDBPage(char *buffer){
    int i;
    int version;
    char pwd[40];
    short *pwd4 = (short*)pwd;
    short magic;

    //page id
    if(buffer[0]!=0){
        fprintf(stderr,"ERROR no vaild db\n");
        return 1;
    }

    //Version
    version = *((int*)&buffer[0x14]);
    switch(version){
        case MDB_VER_JET3:
                printf("DB Version: JET 3\n");
                break;
        case MDB_VER_JET4:
                printf("DB Version: JET 4\n");
                break;
        case MDB_VER_ACCDB2007:
                printf("DB Version: AccessDB 2007\n");
                break;
        case MDB_VER_ACCDB2010:
                printf("DB Version: AccessDB 2010\n");
                break;
        default:
                fprintf(stderr,"ERROR unkown version: %x\n",version);
                return 1;
    }

    //Password extract
    if( version==0 ) { // JET 3
        memcpy(pwd,buffer+0x42,20);
        for(i=0;i<18;i++){
            pwd[i] ^= JET3_XOR[i];
        }
        printf("Password: %20s\n",pwd);

    } else if ( version==1 ) { // JET 4
        memcpy(pwd,buffer+0x42,40);
        magic = *((short*)&buffer[0x66]);
        magic ^= JET4_XOR[18];

        for(i=0;i<18;i++){
            pwd4[i] ^= JET4_XOR[i];
            if(pwd4[i]>255){
                pwd4[i] ^= magic;
            }
            pwd[i] = pwd4[i];
        }
	        printf("Password: %20s\n",pwd);
    }
    return 0;
}

int main (int argc, char **argv)
{
    char page[MDB_PAGE_SIZE];

    //Check Arguments
    printf("MDB Access Tool\n");
    if (argc < 2){
        printf("Missing: file\n");
        return 1;
    }

    //Read data
    printf("Reading: %s\n", argv[1]);
    readMDBPage(argv[1],MDB_PAGE_SIZE,page);
    scanMDBPage(page);

    return 0;
}
**/

package accessdbwe

import (
	"io"
	"os"
	"errors"
	"encoding/binary"
	"strings"
	"database/sql"
	_ "github.com/mattn/go-adodb"
)

//
// Implementing decoding of the so called password
//

// setting XOR Values
var JET3_XOR = []byte { 0x86,0xfb,0xec,0x37,0x5d,0x44,0x9c,0xfa,0xc6,
                        0x5e,0x28,0xe6,0x13,0xb6,0x8a,0x60,0x54,0x94}
var JET4_XOR = []byte { 0x6a,0xba,0x37,0xec,0xd5,0x61,0xfa,0x9c,0xcf,0xfa,
                        0xe6,0x28,0x27,0x2f,0x60,0x8a,0x05,0x68,0x36,0x7b,
                        0xe3,0xc9,0xb1,0xdf,0x65,0x4b,0x43,0x13,0x3e,0xf3,
                        0x33,0xb1,0xf0,0x08,0x5b,0x79,0x24,0xae,0x2a,0x7c}

func readEncoding(filen string) (string,error) {
	file, err := os.Open(filen)
	if err != nil {return "", err}
	defer file.Close()

	p, err := readPage(file)
	if err != nil {return "", err}

	if p[0] != 0 {return "", errors.New("ERROR no vaild db")}

	buf := make([]byte,20)
	switch binary.LittleEndian.Uint32(p[0x14:0x18]) {
		case 0x0:     //Jet3
			for i:=0; i<18; i++ {
				buf[i] = p[0x42+i] ^ JET3_XOR[i]
			}

		case 0x1,0x02,0x0103:     //Jet4
		 // sorry messed up byteorder
			p[0x66] = p[0x66] ^ JET4_XOR[36+1]
			p[0x67] = p[0x67] ^ JET4_XOR[36  ]
			for i:=0; i<18; i++ {
				p[0x42+2*i  ] = p[0x42+2*i  ] ^ JET4_XOR[2*i+1]
				p[0x42+2*i+1] = p[0x42+2*i+1] ^ JET4_XOR[2*i  ]

				if p[0x42+2*i+1] > 0 {
						p[0x42+2*i  ] = p[0x42+2*i  ] ^ p[0x66]
						p[0x42+2*i+1] = p[0x42+2*i+1] ^ p[0x67]
				}
				buf[i] = p[0x42+2*i]
			}
		//case 0x02:    //ACCDB2007  //should use same encoding as JET4
		//case 0x0103:  //ACCDB2010
		default:
			return "", errors.New("ERROR unknown encoding")
	}

	var i int
	for i=0; i<20; i++ {
		if buf[i]==0 {break}
	}
	return string(buf[:i]), nil

}

func readPage(r io.Reader) ([]byte, error) {
	p := make([]byte,4096)
	s, err := r.Read(p)
	if err != nil {return nil,err}
	if s != 4096 {return p,errors.New("ERROR incomplete page")}
	return p,nil
}

//
// Implementing new open function
//
func Open(driver, filen string) (*sql.DB, error){
	var err error
	var db *sql.DB

	// extract filename from filen string
	toks := strings.Split(filen,";")
	for _,tok := range toks {
		pair := strings.Split(tok,"=")
		if len(pair)>1 && pair[0] == "Data Source" {
			enc, err := readEncoding(pair[1])
			if err != nil {
				return nil,err
			}
			filen = filen + `;Jet OLEDB:Database Password=` + enc + `;`
		}
	}

	db, err = sql.Open("adodb", filen)
	if err != nil {return nil,err}

	err = db.Ping()
	if err != nil {return nil,err}
	return db,nil
}<|endoftext|>


<commit_before>package boolmap

import (
	// 	"fmt"
	"testing"
)

func TestBoolMap(t *testing.T) {
	m := NewMap()
	tests := []struct {
		position    uint64
		value       bool
		mapPosition uint64
		mapValue    uint64
	}{
		{0, true, 0, 1},
		{1, true, 0, 3},
		{2, true, 0, 7},
		{63, true, 0, 9223372036854775815},
		{64, true, 1, 1},
		{64, false, 1, 0},
		{1, false, 0, 9223372036854775813},
	}
	for n, test := range tests {
		m.Set(test.position, test.value)
		if m.data[test.mapPosition] != test.mapValue {
			t.Errorf("test %d: expecting value %d, got %d", n+1, test.mapValue, m.data[test.mapPosition])
		} else if test.mapValue == 0 {
			if _, ok := m.data[test.mapPosition]; ok {
				t.Errorf("test %d: map entry should have been removed on a zero value", n+1)
			}
		}
	}
}
<commit_msg>Removed unneeded import<commit_after>package boolmap

import "testing"

func TestBoolMap(t *testing.T) {
	m := NewMap()
	tests := []struct {
		position    uint64
		value       bool
		mapPosition uint64
		mapValue    uint64
	}{
		{0, true, 0, 1},
		{1, true, 0, 3},
		{2, true, 0, 7},
		{63, true, 0, 9223372036854775815},
		{64, true, 1, 1},
		{64, false, 1, 0},
		{1, false, 0, 9223372036854775813},
	}
	for n, test := range tests {
		m.Set(test.position, test.value)
		if m.data[test.mapPosition] != test.mapValue {
			t.Errorf("test %d: expecting value %d, got %d", n+1, test.mapValue, m.data[test.mapPosition])
		} else if test.mapValue == 0 {
			if _, ok := m.data[test.mapPosition]; ok {
				t.Errorf("test %d: map entry should have been removed on a zero value", n+1)
			}
		}
	}
}
<|endoftext|>


<commit_before>package api

import (
	"context"
	"database/sql"
	"encoding/json"
	"io/ioutil"
	"net/http"

	"github.com/FederationOfFathers/dashboard/config"
	"github.com/bwmarrin/discordgo"
	"github.com/jinzhu/gorm"
	"go.uber.org/zap"
	"golang.org/x/oauth2"
)

var discordEndpoint = oauth2.Endpoint{
	AuthURL:  "https://discordapp.com/api/oauth2/authorize",
	TokenURL: "https://discordapp.com/api/oauth2/token",
}

var conf = &oauth2.Config{
	ClientID:     "",
	ClientSecret: "",
	Scopes:       []string{"identify"},
	Endpoint:     discordEndpoint,
	RedirectURL:  "https://dashboard.fofgaming.com/api/v1/oauth/discord/verify",
}

func init() {
	initDiscordOauth()
}

func initDiscordOauth() {

	if config.DiscordConfig != nil {
		// Discord OAuth2
		conf.ClientID = config.DiscordConfig.ClientId
		conf.ClientSecret = config.DiscordConfig.Secret

		Router.Path("/api/v1/oauth/discord").Methods("GET").HandlerFunc(discordOauthHandler)
		Router.Path("/api/v1/oauth/discord/verify").Methods("GET").Handler(authenticated(discordOauthVerify))
		Router.Path("/api/v1/oauth/discord/login").Methods("GET").HandlerFunc(discordOauthVerify)
	} else {
		Router.Path("/api/v1/oauth/discord").Methods("GET").HandlerFunc(NotImplemented)
	}

}

func discordOauthHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain")

	authURL := conf.AuthCodeURL("asdasdasd13424yhion2f0") // TODO get proper state
	json.NewEncoder(w).Encode(authURL)

}

func discordOauthVerify(w http.ResponseWriter, r *http.Request) {
	query := r.URL.Query()
	code := query.Get("code")
	state := query.Get("state")

	// get authenticated user
	id := getMemberID(r)

	// if id == 0, then this is a login, not a sync
	isAuthenticated := id != ""

	if code == "" || state == "" {
		w.WriteHeader(http.StatusBadRequest)
	} else {

		// exchange code for a user token
		ctx := context.Background()
		token, err := conf.Exchange(ctx, code)
		if err != nil {
			Logger.Error("Could not get token", zap.Error(err))
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		// create a new client with the token and get the user/@me endpoint
		client := conf.Client(ctx, token)
		res, err := client.Get("https://discordapp.com/api/users/@me")
		if err != nil {
			Logger.Error("Could not get user object", zap.Error(err))
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		// unmarshall the Body to a User{}
		body, err := ioutil.ReadAll(res.Body)
		if err != nil {
			Logger.Error("Could not parse body", zap.Error(err))
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		userObj := discordgo.User{}
		err = json.Unmarshal(body, &userObj)
		if err != nil {
			Logger.Error("Could not parse JSON", zap.Error(err))
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		// unauthenticated user
		if !isAuthenticated {
			member, err := DB.MemberByDiscordID(userObj.ID)
			if err == gorm.ErrRecordNotFound || err == sql.ErrNoRows {
				w.WriteHeader(http.StatusForbidden)
				w.Write([]byte("not authorizes"))
				return
			} else if err != nil {
				Logger.Error("unable to check member", zap.String("discordid", userObj.ID), zap.Error(err))
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte("error"))
			}

			// set auth cookie and redirect
			authorize("", member.ID, w, r)

		} else {
			member, err := DB.MemberByAny(id)
			if err != nil {
				Logger.Error("could not find member", zap.String("member_id", id), zap.Error(err))
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte("error"))
				return
			}

			// set discord id
			member.Discord = userObj.ID

			if err := member.Save(); err != nil {
				Logger.Error("unable to save discord id", zap.Int("member", member.ID), zap.String("discord id", userObj.ID), zap.Error(err))
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte("error"))
				return
			}
		}

		// redirect
		http.Redirect(w, r, "https://ui.fofgaming.com/#main=members", http.StatusTemporaryRedirect)
	}

}
<commit_msg>Adding some oauth logging<commit_after>package api

import (
	"context"
	"database/sql"
	"encoding/json"
	"io/ioutil"
	"net/http"

	"github.com/FederationOfFathers/dashboard/config"
	"github.com/bwmarrin/discordgo"
	"github.com/jinzhu/gorm"
	"go.uber.org/zap"
	"golang.org/x/oauth2"
)

var discordEndpoint = oauth2.Endpoint{
	AuthURL:  "https://discordapp.com/api/oauth2/authorize",
	TokenURL: "https://discordapp.com/api/oauth2/token",
}

var conf = &oauth2.Config{
	ClientID:     "",
	ClientSecret: "",
	Scopes:       []string{"identify"},
	Endpoint:     discordEndpoint,
	RedirectURL:  "https://dashboard.fofgaming.com/api/v1/oauth/discord/verify",
}

func init() {
	initDiscordOauth()
}

func initDiscordOauth() {

	if config.DiscordConfig != nil {
		// Discord OAuth2
		conf.ClientID = config.DiscordConfig.ClientId
		conf.ClientSecret = config.DiscordConfig.Secret

		Router.Path("/api/v1/oauth/discord").Methods("GET").HandlerFunc(discordOauthHandler)
		Router.Path("/api/v1/oauth/discord/verify").Methods("GET").Handler(authenticated(discordOauthVerify))
		Router.Path("/api/v1/oauth/discord/login").Methods("GET").HandlerFunc(discordOauthVerify)
	} else {
		Router.Path("/api/v1/oauth/discord").Methods("GET").HandlerFunc(NotImplemented)
	}

}

func discordOauthHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain")

	authURL := conf.AuthCodeURL("asdasdasd13424yhion2f0") // TODO get proper state
	json.NewEncoder(w).Encode(authURL)

}

func discordOauthVerify(w http.ResponseWriter, r *http.Request) {
	query := r.URL.Query()
	code := query.Get("code")
	state := query.Get("state")

	// get authenticated user
	id := getMemberID(r)

	// if id == 0, then this is a login, not a sync
	isAuthenticated := id != ""

	if code == "" || state == "" {
		w.WriteHeader(http.StatusBadRequest)
	} else {

		// exchange code for a user token
		ctx := context.Background()
		token, err := conf.Exchange(ctx, code)
		if err != nil {
			Logger.Error("Could not get token",
				zap.String("code", code),
				zap.String("state", state),
				zap.String("id", id),
				zap.Error(err))
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		// create a new client with the token and get the user/@me endpoint
		client := conf.Client(ctx, token)
		res, err := client.Get("https://discordapp.com/api/users/@me")
		if err != nil {
			Logger.Error("Could not get user object", zap.Error(err))
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		// unmarshall the Body to a User{}
		body, err := ioutil.ReadAll(res.Body)
		if err != nil {
			Logger.Error("Could not parse body", zap.Error(err))
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		userObj := discordgo.User{}
		err = json.Unmarshal(body, &userObj)
		if err != nil {
			Logger.Error("Could not parse JSON", zap.Error(err))
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		// unauthenticated user
		if !isAuthenticated {
			member, err := DB.MemberByDiscordID(userObj.ID)
			if err == gorm.ErrRecordNotFound || err == sql.ErrNoRows {
				w.WriteHeader(http.StatusForbidden)
				w.Write([]byte("not authorizes"))
				return
			} else if err != nil {
				Logger.Error("unable to check member", zap.String("discordid", userObj.ID), zap.Error(err))
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte("error"))
			}

			// set auth cookie and redirect
			authorize("", member.ID, w, r)

		} else {
			member, err := DB.MemberByAny(id)
			if err != nil {
				Logger.Error("could not find member", zap.String("member_id", id), zap.Error(err))
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte("error"))
				return
			}

			// set discord id
			member.Discord = userObj.ID

			if err := member.Save(); err != nil {
				Logger.Error("unable to save discord id", zap.Int("member", member.ID), zap.String("discord id", userObj.ID), zap.Error(err))
				w.WriteHeader(http.StatusInternalServerError)
				w.Write([]byte("error"))
				return
			}
		}

		// redirect
		http.Redirect(w, r, "https://ui.fofgaming.com/#main=members", http.StatusTemporaryRedirect)
	}

}
<|endoftext|>


<commit_before>// +build !local_tests

package sessiontest

import (
	"testing"

	"github.com/privacybydesign/irmago"
	"github.com/privacybydesign/irmago/internal/test"
	"github.com/privacybydesign/irmago/irmaclient"
	"github.com/stretchr/testify/require"
)

func TestManualKeyshareSession(t *testing.T) {
	request := irma.NewSignatureRequest("I owe you everything", irma.NewAttributeTypeIdentifier("test.test.mijnirma.email"))
	ms := createManualSessionHandler(t, nil)

	_, status := manualSessionHelper(t, nil, ms, request, request, false)
	require.Equal(t, irma.ProofStatusValid, status)
	_, status = manualSessionHelper(t, nil, ms, request, nil, false)
	require.Equal(t, irma.ProofStatusValid, status)
}

func TestRequestorIssuanceKeyshareSession(t *testing.T) {
	testRequestorIssuance(t, true)
}

func TestKeyshareRegister(t *testing.T) {
	client, handler := parseStorage(t)
	defer test.ClearTestStorage(t)

	require.NoError(t, client.KeyshareRemoveAll())
	require.NoError(t, client.RemoveAllCredentials())

	client.KeyshareEnroll(irma.NewSchemeManagerIdentifier("test"), nil, "12345", "en")
	require.NoError(t, <-handler.c)

	require.Len(t, client.CredentialInfoList(), 1)

	sessionHelper(t, getIssuanceRequest(true), "issue", client)
	keyshareSessions(t, client)
}

// Use the existing keyshare enrollment and credentials
// in a keyshare session of each session type.
// Use keyshareuser.sql to enroll the user at the keyshare server.
func TestKeyshareSessions(t *testing.T) {
	client, _ := parseStorage(t)
	defer test.ClearTestStorage(t)
	keyshareSessions(t, client)
}

func keyshareSessions(t *testing.T, client *irmaclient.Client) {
	id := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
	expiry := irma.Timestamp(irma.NewMetadataAttribute(0).Expiry())
	issuanceRequest := getCombinedIssuanceRequest(id)
	issuanceRequest.Credentials = append(issuanceRequest.Credentials,
		&irma.CredentialRequest{
			Validity:         &expiry,
			CredentialTypeID: irma.NewCredentialTypeIdentifier("test.test.mijnirma"),
			Attributes:       map[string]string{"email": "testusername"},
		},
	)
	sessionHelper(t, issuanceRequest, "issue", client)

	disclosureRequest := getDisclosureRequest(id)
	disclosureRequest.AddSingle(irma.NewAttributeTypeIdentifier("test.test.mijnirma.email"), nil, nil)
	sessionHelper(t, disclosureRequest, "verification", client)

	sigRequest := getSigningRequest(id)
	sigRequest.AddSingle(irma.NewAttributeTypeIdentifier("test.test.mijnirma.email"), nil, nil)
	sessionHelper(t, sigRequest, "signature", client)
}

func TestIssuanceCombinedMultiSchemeSession(t *testing.T) {
	id := irma.NewAttributeTypeIdentifier("test.test.mijnirma.email")
	request := getCombinedIssuanceRequest(id)
	sessionHelper(t, request, "issue", nil)

	sessionHelper(t, irma.NewIssuanceRequest([]*irma.CredentialRequest{
		{
			CredentialTypeID: irma.NewCredentialTypeIdentifier("test.test.email"),
			Attributes: map[string]string{
				"email": "example@example.com",
			},
		},
	}, irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")), "issue", nil)
}
<commit_msg>use new removal function in keyshare tests<commit_after>// +build !local_tests

package sessiontest

import (
	"testing"

	"github.com/privacybydesign/irmago"
	"github.com/privacybydesign/irmago/internal/test"
	"github.com/privacybydesign/irmago/irmaclient"
	"github.com/stretchr/testify/require"
)

func TestManualKeyshareSession(t *testing.T) {
	request := irma.NewSignatureRequest("I owe you everything", irma.NewAttributeTypeIdentifier("test.test.mijnirma.email"))
	ms := createManualSessionHandler(t, nil)

	_, status := manualSessionHelper(t, nil, ms, request, request, false)
	require.Equal(t, irma.ProofStatusValid, status)
	_, status = manualSessionHelper(t, nil, ms, request, nil, false)
	require.Equal(t, irma.ProofStatusValid, status)
}

func TestRequestorIssuanceKeyshareSession(t *testing.T) {
	testRequestorIssuance(t, true)
}

func TestKeyshareRegister(t *testing.T) {
	client, handler := parseStorage(t)
	defer test.ClearTestStorage(t)

	require.NoError(t, client.KeyshareRemoveAll())
	require.NoError(t, client.RemoveStorage())

	client.KeyshareEnroll(irma.NewSchemeManagerIdentifier("test"), nil, "12345", "en")
	require.NoError(t, <-handler.c)

	require.Len(t, client.CredentialInfoList(), 1)

	sessionHelper(t, getIssuanceRequest(true), "issue", client)
	keyshareSessions(t, client)
}

// Use the existing keyshare enrollment and credentials
// in a keyshare session of each session type.
// Use keyshareuser.sql to enroll the user at the keyshare server.
func TestKeyshareSessions(t *testing.T) {
	client, _ := parseStorage(t)
	defer test.ClearTestStorage(t)
	keyshareSessions(t, client)
}

func keyshareSessions(t *testing.T, client *irmaclient.Client) {
	id := irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")
	expiry := irma.Timestamp(irma.NewMetadataAttribute(0).Expiry())
	issuanceRequest := getCombinedIssuanceRequest(id)
	issuanceRequest.Credentials = append(issuanceRequest.Credentials,
		&irma.CredentialRequest{
			Validity:         &expiry,
			CredentialTypeID: irma.NewCredentialTypeIdentifier("test.test.mijnirma"),
			Attributes:       map[string]string{"email": "testusername"},
		},
	)
	sessionHelper(t, issuanceRequest, "issue", client)

	disclosureRequest := getDisclosureRequest(id)
	disclosureRequest.AddSingle(irma.NewAttributeTypeIdentifier("test.test.mijnirma.email"), nil, nil)
	sessionHelper(t, disclosureRequest, "verification", client)

	sigRequest := getSigningRequest(id)
	sigRequest.AddSingle(irma.NewAttributeTypeIdentifier("test.test.mijnirma.email"), nil, nil)
	sessionHelper(t, sigRequest, "signature", client)
}

func TestIssuanceCombinedMultiSchemeSession(t *testing.T) {
	id := irma.NewAttributeTypeIdentifier("test.test.mijnirma.email")
	request := getCombinedIssuanceRequest(id)
	sessionHelper(t, request, "issue", nil)

	sessionHelper(t, irma.NewIssuanceRequest([]*irma.CredentialRequest{
		{
			CredentialTypeID: irma.NewCredentialTypeIdentifier("test.test.email"),
			Attributes: map[string]string{
				"email": "example@example.com",
			},
		},
	}, irma.NewAttributeTypeIdentifier("irma-demo.RU.studentCard.studentID")), "issue", nil)
}
<|endoftext|>


<commit_before>package comb

import (
	"fmt"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestMany(t *testing.T) {
	for _, str := range []string{"", "  "} {
		s := NewState(str)
		result, err := s.Many(s.Char(' '))()

		t.Logf("%#v", result)

		assert.NotEqual(t, result, nil)
		assert.Equal(t, err, nil)
	}
}

func TestManyFail(t *testing.T) {
	for _, str := range []string{"="} {
		s := NewState(str)
		result, err := s.Exhaust(s.Many(func() (interface{}, error) {
			x, err := s.String("=")()

			if err != nil {
				return nil, err
			}

			if x.(string) == "=" {
				return nil, fmt.Errorf("Invalid word")
			}

			return x, nil
		}))()

		t.Logf("%#v", result)

		assert.Equal(t, result, nil)
		assert.NotEqual(t, err, nil)
	}
}

func testMany1Space(str string) (interface{}, error) {
	s := NewState(str)
	return s.Many1(s.Char(' '))()
}

func TestMany1(t *testing.T) {
	result, err := testMany1Space(" ")

	t.Logf("%#v", result)

	assert.NotEqual(t, result, nil)
	assert.Equal(t, err, nil)
}

func TestXFailMany1(t *testing.T) {
	result, err := testMany1Space("")

	t.Log(err)

	assert.Equal(t, result, nil)
	assert.NotEqual(t, err, nil)
}

func TestMany1Nest(t *testing.T) {
	s := NewState("    ")
	result, err := s.Many1(s.Many1(s.Char(' ')))()

	t.Logf("%#v", result)

	assert.NotEqual(t, result, nil)
	assert.Equal(t, err, nil)
}

func testOr(str string) (interface{}, error) {
	s := NewState(str)
	return s.Or(s.Char('a'), s.Char('b'))()
}

func TestOr(t *testing.T) {
	for _, str := range []string{"a", "b"} {
		result, err := testOr(str)

		t.Logf("%#v", result)

		assert.NotEqual(t, result, nil)
		assert.Equal(t, err, nil)
	}
}

func TestXFailOr(t *testing.T) {
	result, err := testOr("c")

	t.Log(err)

	assert.Equal(t, result, nil)
	assert.NotEqual(t, err, nil)
}

func TestMaybeSuccess(t *testing.T) {
	s := NewState("foo")
	result, err := s.Maybe(s.String("foo"))()

	t.Log(result)

	assert.Equal(t, "foo", result)
	assert.Equal(t, nil, err)
}

func TestMaybeFailure(t *testing.T) {
	s := NewState("bar")
	result, err := s.Maybe(s.String("foo"))()

	t.Log(result)

	assert.Equal(t, nil, result)
	assert.Equal(t, nil, err)
}

func TestExhaustWithErroneousParser(t *testing.T) {
	s := NewState("")
	_, err := s.Exhaust(s.String("foo"))()
	assert.NotEqual(t, err, nil)
}
<commit_msg>Test stringify combinators<commit_after>package comb

import (
	"fmt"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestMany(t *testing.T) {
	for _, str := range []string{"", "  "} {
		s := NewState(str)
		result, err := s.Many(s.Char(' '))()

		t.Logf("%#v", result)

		assert.NotEqual(t, result, nil)
		assert.Equal(t, err, nil)
	}
}

func TestManyFail(t *testing.T) {
	for _, str := range []string{"="} {
		s := NewState(str)
		result, err := s.Exhaust(s.Many(func() (interface{}, error) {
			x, err := s.String("=")()

			if err != nil {
				return nil, err
			}

			if x.(string) == "=" {
				return nil, fmt.Errorf("Invalid word")
			}

			return x, nil
		}))()

		t.Logf("%#v", result)

		assert.Equal(t, result, nil)
		assert.NotEqual(t, err, nil)
	}
}

func testMany1Space(str string) (interface{}, error) {
	s := NewState(str)
	return s.Many1(s.Char(' '))()
}

func TestMany1(t *testing.T) {
	result, err := testMany1Space(" ")

	t.Logf("%#v", result)

	assert.NotEqual(t, result, nil)
	assert.Equal(t, err, nil)
}

func TestXFailMany1(t *testing.T) {
	result, err := testMany1Space("")

	t.Log(err)

	assert.Equal(t, result, nil)
	assert.NotEqual(t, err, nil)
}

func TestMany1Nest(t *testing.T) {
	s := NewState("    ")
	result, err := s.Many1(s.Many1(s.Char(' ')))()

	t.Logf("%#v", result)

	assert.NotEqual(t, result, nil)
	assert.Equal(t, err, nil)
}

func testOr(str string) (interface{}, error) {
	s := NewState(str)
	return s.Or(s.Char('a'), s.Char('b'))()
}

func TestOr(t *testing.T) {
	for _, str := range []string{"a", "b"} {
		result, err := testOr(str)

		t.Logf("%#v", result)

		assert.NotEqual(t, result, nil)
		assert.Equal(t, err, nil)
	}
}

func TestXFailOr(t *testing.T) {
	result, err := testOr("c")

	t.Log(err)

	assert.Equal(t, result, nil)
	assert.NotEqual(t, err, nil)
}

func TestMaybeSuccess(t *testing.T) {
	s := NewState("foo")
	result, err := s.Maybe(s.String("foo"))()

	t.Log(result)

	assert.Equal(t, "foo", result)
	assert.Equal(t, nil, err)
}

func TestMaybeFailure(t *testing.T) {
	s := NewState("bar")
	result, err := s.Maybe(s.String("foo"))()

	t.Log(result)

	assert.Equal(t, nil, result)
	assert.Equal(t, nil, err)
}

func TestExhaustWithErroneousParser(t *testing.T) {
	s := NewState("")
	_, err := s.Exhaust(s.String("foo"))()
	assert.NotEqual(t, err, nil)
}

func TestStringify(t *testing.T) {
	str := "foo"
	s := NewState(str)
	result, err := s.Exhaust(s.Stringify(s.And(s.String(str))))()
	assert.Equal(t, str, result.(string))
	assert.Equal(t, err, nil)
}

func TestStringifyFail(t *testing.T) {
	defer func() {
		if r := recover(); r == nil {
			t.Fail()
		}
	}()

	stringify(42)
}
<|endoftext|>


<commit_before>package renderer

import (
	"strings"
	"text/template"
)

var templateFuncs = template.FuncMap{
	"Replace":          strings.Replace,
	"ToUpper":          strings.ToUpper,
	"ToLower":          strings.ToLower,
	"SafeComputerName": SafeComputerName,
}

// SafeComputerName modifies the specified string to make it Windows computer
// name valid
func SafeComputerName(name string) string {
	if len(name) <= 0 {
		return "computername"
	}
	invalidChars := []string{"\\", "/", ":", "*", "?", "\"", "<", ">", "|"}
	for _, s := range invalidChars {
		name = strings.Replace(name, s, "", -1)
	}
	i := len(name)
	if i > 15 {
		i = 15
	}
	return name[0:i]
}
<commit_msg>Add Contains template function<commit_after>package renderer

import (
	"strings"
	"text/template"
)

var templateFuncs = template.FuncMap{
	"Contains":         strings.Contains,
	"Replace":          strings.Replace,
	"ToUpper":          strings.ToUpper,
	"ToLower":          strings.ToLower,
	"SafeComputerName": SafeComputerName,
}

// SafeComputerName modifies the specified string to make it Windows computer
// name valid
func SafeComputerName(name string) string {
	if len(name) <= 0 {
		return "computername"
	}
	invalidChars := []string{"\\", "/", ":", "*", "?", "\"", "<", ">", "|"}
	for _, s := range invalidChars {
		name = strings.Replace(name, s, "", -1)
	}
	i := len(name)
	if i > 15 {
		i = 15
	}
	return name[0:i]
}
<|endoftext|>


<commit_before>// Copyright 2016 Lars Wiegman. All rights reserved. Use of this source code is
// governed by a BSD-style license that can be found in the LICENSE file.

package email

import "testing"

func TestPathMatch(t *testing.T) {
	tests := []struct {
		pattern, path string
		match         bool //want
	}{
		{"/private", "/private", true},
		{"/private/", "/private/a/b", true},
		{"domain.tld:8080/private/", "domain.tld:8080/private/a/b", true},
		{"/", "/private/a/b", true},
		{"/private/", "/private", false},
		{"/private", "/privat", false},
		{"/", "", false},
		{"domain.tld:8080/private", "domain.tld:8080/private/a/b", false},
		{"private", "/private", false},
	}

	for i, test := range tests {
		want, got := test.match, pathMatch(test.pattern, test.path)
		if want != got {
			t.Errorf("test #%d; want %t, got %t", i, want, got)
		}
	}
}
<commit_msg>Add email.UserService tests to improve code coverage<commit_after>// Copyright 2016 Lars Wiegman. All rights reserved. Use of this source code is
// governed by a BSD-style license that can be found in the LICENSE file.

package email

import (
	"bytes"
	"net/mail"
	"testing"
	"text/template"

	gomail "gopkg.in/gomail.v2"
)

func TestPathMatch(t *testing.T) {
	tests := []struct {
		pattern, path string
		match         bool //want
	}{
		{"/private", "/private", true},
		{"/private/", "/private/a/b", true},
		{"domain.tld:8080/private/", "domain.tld:8080/private/a/b", true},
		{"/", "/private/a/b", true},
		{"/private/", "/private", false},
		{"/private", "/privat", false},
		{"/", "", false},
		{"domain.tld:8080/private", "domain.tld:8080/private/a/b", false},
		{"private", "/private", false},
		{"/private", "/private/", false},
		{"", "/private", false},
	}

	for i, test := range tests {
		want, got := test.match, pathMatch(test.pattern, test.path)
		if want != got {
			t.Errorf("test #%d; want %t, got %t", i, want, got)
		}
	}
}

func TestAddPattern(t *testing.T) {
	s := &UserService{}
	if err := s.AddPattern("/private"); err != nil {
		t.Error(err)
	}
	if err := s.AddPattern(""); err == nil {
		t.Error("expect error, got nil")
	}
}

func TestListed(t *testing.T) {
	s := &UserService{}
	if actual, expect := s.Listed("leeloo"), false; actual != expect {
		t.Error("expect %t, got %t", expect, actual)
	}
	if actual, expect := s.Listed("leeloo@dallas"), false; actual != expect {
		t.Error("expect %t, got %t", expect, actual)
	}
}

func TestRegister(t *testing.T) {
	s := &UserService{}
	if err := s.Register("leeloo@dallas"); err != nil {
		t.Error(err)
	}
	if err := s.Register("leeloo"); err == nil {
		t.Error("expect Register to error, but did not")
	}
}

func TestAuthorized(t *testing.T) {
	s := &UserService{}
	pattern, handle, rawurl := "/private/", "leeloo@dallas", "/private/a"
	if err := s.Register(handle); err != nil {
		t.Error(err)
	}
	if err := s.AddPattern(pattern); err != nil {
		t.Error(err)
	}
	if actual, expect := s.Authorized(handle, rawurl), true; actual != expect {
		t.Error("want %t, got %t", expect, actual)
	}
	if actual, expect := s.Authorized("korben@dallas", rawurl), false; actual != expect {
		t.Error("want %t, got %t", expect, actual)
	}
	if actual, expect := s.Authorized("anonymous", "/public"), true; actual != expect {
		t.Error("want %t, got %t", expect, actual)
	}
}

func TestNotify(t *testing.T) {
	s := &UserService{}
	s.template = template.Must(template.New("").Parse(msgTmpl))
	s.channel = make(chan *gomail.Message)

	from, err := mail.ParseAddress("Multipass Bot <no-reply@dallas>")
	if err != nil {
		t.Error(err)
	}
	s.from = from

	handle := "leeloo@dallas"
	loginurl := "http://example.com/multipass/login?token="
	if err := s.Notify("leeloo", loginurl); err == nil {
		t.Error("expect Notify to error, but did not")
	}
	go func() {
		if err := s.Notify(handle, loginurl); err != nil {
			t.Error(err)
		}
	}()

	buf := new(bytes.Buffer)
	message, ok := <-s.channel
	if !ok {
		t.Error("oops")
	}
	n, err := message.WriteTo(buf)
	if err != nil {
		t.Error(err)
	}
	if n < 1 {
		t.Error("want n > 0, got %d", n)
	}
	if err := s.Close(); err != nil {
		t.Error(err)
	}
}
<|endoftext|>


<commit_before>package models

type User struct {
	Login    string `json:"login" bson:"login"`
	Password string `json:"password" bson:"password"`
	Email    string `json:"email" bson:"email"`
}
<commit_msg>Add user model implement Stringer<commit_after>package models

import "fmt"

type User struct {
	Login    string `json:"login" bson:"login"`
	Password string `json:"password" bson:"password"`
	Email    string `json:"email" bson:"email"`
}

func (u User) String() string {
	return fmt.Sprintf("Login: %v\tPassword: %v\tEmail: %v\n", u.Login, u.Password, u.Email)
}
<|endoftext|>


<commit_before>package models

import (
	"crypto/rand"
	"crypto/sha256"
	"database/sql"
	"encoding/hex"
	"io"
	"strconv"
	"time"

	"golang.org/x/crypto/scrypt"
)

const (
	passwordSaltBytes = 32
	passwordHashBytes = 64
)

// User contains the information of an User
type User struct {
	ID           int            `db:"id"`
	FirstName    string         `db:"first_name"`
	LastName     string         `db:"last_name"`
	Email        string         `db:"email"`
	Address      sql.NullString `db:"address"`
	Invites      int            `db:"invites"`
	Credit       int            `db:"credit"`
	Confirmed    bool           `db:"confirmed"`
	Referral     string         `db:"referral"`
	Referrer     sql.NullInt64  `db:"referrer"`
	PasswordSalt string         `db:"password_salt"`
	PasswordHash string         `db:"password_hash"`
}

// Update updates the current User struct into the database
func (u User) Update(fields ...string) error {
	// Starts writing the query
	query := "UPDATE users SET "

	// Add the fields that we are going to update to the queyr
	for i := range fields {
		if i == len(fields)-1 {
			query += fields[i] + "=:" + fields[i]
		} else {
			query += fields[i] + ":" + fields[i] + ", "
		}
	}

	// Finish the query adding the 'id' filter
	query += " WHERE id=" + strconv.Itoa(u.ID)

	// Execute the query and returns the error/nil
	_, err := db.NamedExec(query, u)
	return err
}

// Insert inserts the current User struct into the database and returns an error
// if something goes wrong.
func (u User) Insert() error {
	if u.ID != 0 {
		return nil
	}

	_, err := db.NamedExec(
		`INSERT INTO users
		            (first_name,
		             last_name,
		             email,
		             address,
		             invites,
		             credit,
		             confirmed,
		             referral,
		             referrer,
		             password_salt,
		             password_hash)
		VALUES      (:first_name,
		             :last_name,
		             :email,
		             :address,
		             :invites,
		             :credit,
		             :confirmed,
		             :referral,
		             :referrer,
		             :password_salt,
		             :password_hash)`, u)

	return err
}

// SetPassword generates the salt and the hash of the user password
func (u *User) SetPassword(password string) error {
	// Generates a random salt
	salt := make([]byte, passwordSaltBytes)
	_, err := io.ReadFull(rand.Reader, salt)
	if err != nil {
		return err
	}

	// Creates the hash from the salt and password
	hash, err := scrypt.Key([]byte(password), salt, 1<<14, 8, 1, passwordHashBytes)
	if err != nil {
		return err
	}

	// Stores the hash and salt in hexadecimal form
	u.PasswordSalt = hex.EncodeToString(salt)
	u.PasswordHash = hex.EncodeToString(hash)
	return nil
}

// CheckPassword checks if the password of the user is correct
func (u User) CheckPassword(password string) (bool, error) {
	// Decodes the hexadecimal salt into a []byte
	salt, err := hex.DecodeString(u.PasswordSalt)
	if err != nil {
		return false, err
	}

	// Makes an hash from the password and salt
	hash, err := scrypt.Key([]byte(password), salt, 1<<14, 8, 1, passwordHashBytes)
	if err != nil {
		return false, err
	}

	return (hex.EncodeToString(hash) == u.PasswordHash), nil
}

// GenerateReferralHash generates a new referrer hash for a new user
func (u *User) GenerateReferralHash() {
	if u.Referral != "" {
		return
	}

	data := u.Email + time.Now().Format(time.ANSIC)
	hash := sha256.Sum256([]byte(data))
	u.Referral = hex.EncodeToString(hash[:])
}

// DeleteUser deletes a user from the database using its email
func DeleteUser(email string) error {
	_, err := db.Exec("DELETE FROM users WHERE email=?", email)
	return err
}

// GetUserByEmail retrieves a user from the database using its email
func GetUserByEmail(email string) (*User, error) {
	user := User{}
	err := db.Get(&user, "SELECT * FROM users WHERE email=?", email)
	return &user, err
}

// GetUserByReferral retrieves a user from the database using its email
func GetUserByReferral(referral string) (*User, error) {
	user := User{}
	err := db.Get(&user, "SELECT * FROM users WHERE referral=?", referral)
	return &user, err
}
<commit_msg>get user by id function<commit_after>package models

import (
	"crypto/rand"
	"crypto/sha256"
	"database/sql"
	"encoding/hex"
	"io"
	"strconv"
	"time"

	"golang.org/x/crypto/scrypt"
)

const (
	passwordSaltBytes = 32
	passwordHashBytes = 64
)

// User contains the information of an User
type User struct {
	ID           int            `db:"id"`
	FirstName    string         `db:"first_name"`
	LastName     string         `db:"last_name"`
	Email        string         `db:"email"`
	Address      sql.NullString `db:"address"`
	Invites      int            `db:"invites"`
	Credit       int            `db:"credit"`
	Confirmed    bool           `db:"confirmed"`
	Referral     string         `db:"referral"`
	Referrer     sql.NullInt64  `db:"referrer"`
	PasswordSalt string         `db:"password_salt"`
	PasswordHash string         `db:"password_hash"`
}

// Update updates the current User struct into the database
func (u User) Update(fields ...string) error {
	// Starts writing the query
	query := "UPDATE users SET "

	// Add the fields that we are going to update to the queyr
	for i := range fields {
		if i == len(fields)-1 {
			query += fields[i] + "=:" + fields[i]
		} else {
			query += fields[i] + ":" + fields[i] + ", "
		}
	}

	// Finish the query adding the 'id' filter
	query += " WHERE id=" + strconv.Itoa(u.ID)

	// Execute the query and returns the error/nil
	_, err := db.NamedExec(query, u)
	return err
}

// Insert inserts the current User struct into the database and returns an error
// if something goes wrong.
func (u User) Insert() error {
	if u.ID != 0 {
		return nil
	}

	_, err := db.NamedExec(
		`INSERT INTO users
		            (first_name,
		             last_name,
		             email,
		             address,
		             invites,
		             credit,
		             confirmed,
		             referral,
		             referrer,
		             password_salt,
		             password_hash)
		VALUES      (:first_name,
		             :last_name,
		             :email,
		             :address,
		             :invites,
		             :credit,
		             :confirmed,
		             :referral,
		             :referrer,
		             :password_salt,
		             :password_hash)`, u)

	return err
}

// SetPassword generates the salt and the hash of the user password
func (u *User) SetPassword(password string) error {
	// Generates a random salt
	salt := make([]byte, passwordSaltBytes)
	_, err := io.ReadFull(rand.Reader, salt)
	if err != nil {
		return err
	}

	// Creates the hash from the salt and password
	hash, err := scrypt.Key([]byte(password), salt, 1<<14, 8, 1, passwordHashBytes)
	if err != nil {
		return err
	}

	// Stores the hash and salt in hexadecimal form
	u.PasswordSalt = hex.EncodeToString(salt)
	u.PasswordHash = hex.EncodeToString(hash)
	return nil
}

// CheckPassword checks if the password of the user is correct
func (u User) CheckPassword(password string) (bool, error) {
	// Decodes the hexadecimal salt into a []byte
	salt, err := hex.DecodeString(u.PasswordSalt)
	if err != nil {
		return false, err
	}

	// Makes an hash from the password and salt
	hash, err := scrypt.Key([]byte(password), salt, 1<<14, 8, 1, passwordHashBytes)
	if err != nil {
		return false, err
	}

	return (hex.EncodeToString(hash) == u.PasswordHash), nil
}

// GenerateReferralHash generates a new referrer hash for a new user
func (u *User) GenerateReferralHash() {
	if u.Referral != "" {
		return
	}

	data := u.Email + time.Now().Format(time.ANSIC)
	hash := sha256.Sum256([]byte(data))
	u.Referral = hex.EncodeToString(hash[:])
}

// DeleteUser deletes a user from the database using its email
func DeleteUser(email string) error {
	_, err := db.Exec("DELETE FROM users WHERE email=?", email)
	return err
}

// GetUserByID retrieves a user from the database using its ID
func GetUserByID(id string) (*User, error) {
	user := User{}
	err := db.Get(&user, "SELECT * FROM users WHERE id=?", id)
	return &user, err
}

// GetUserByEmail retrieves a user from the database using its email
func GetUserByEmail(email string) (*User, error) {
	user := User{}
	err := db.Get(&user, "SELECT * FROM users WHERE email=?", email)
	return &user, err
}

// GetUserByReferral retrieves a user from the database using its email
func GetUserByReferral(referral string) (*User, error) {
	user := User{}
	err := db.Get(&user, "SELECT * FROM users WHERE referral=?", referral)
	return &user, err
}
<|endoftext|>


<commit_before>package pxemgr

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"path"
	"strconv"
	"strings"

	"github.com/golang/glog"
	"github.com/gorilla/mux"
)

type EtcdNode struct {
	Key   string      `json:"key"`
	Value string      `json:"value,omitempty"`
	Nodes []*EtcdNode `json:"nodes,omitempty"`
	Dir   bool        `json:"dir,omitempty"`
}

type EtcdResponse struct {
	Action string    `json:"action"`
	Node   *EtcdNode `json:"node,omitempty"`
}

type EtcdResponseError struct {
	ErrorCode int    `json:"errorCode"`
	Message   string `json:"message"`
	Cause     string `json:"cause"`
}

func (mgr *pxeManagerT) defineEtcdDiscoveryRoutes(etcdRouter *mux.Router) {
	etcdRouter.PathPrefix("/new").Methods("PUT").HandlerFunc(mgr.etcdDiscoveryNewCluster)

	tokenRouter := etcdRouter.PathPrefix("/{token:[a-f0-9]{32}}").Subrouter()
	tokenRouter.PathPrefix("/_config/size").Methods("GET").HandlerFunc(mgr.etcdDiscoveryProxyHandler)
	tokenRouter.PathPrefix("/_config/size").Methods("PUT").HandlerFunc(mgr.etcdDiscoveryProxyHandler)
	tokenRouter.PathPrefix("/{machine}").Methods("PUT").HandlerFunc(mgr.etcdDiscoveryProxyHandler)
	tokenRouter.PathPrefix("/{machine}").Methods("GET").HandlerFunc(mgr.etcdDiscoveryProxyHandler)
	tokenRouter.PathPrefix("/{machine}").Methods("DELETE").HandlerFunc(mgr.etcdDiscoveryProxyHandler)
	tokenRouter.Methods("GET").HandlerFunc(mgr.etcdDiscoveryProxyHandler)

	etcdRouter.Methods("GET").HandlerFunc(mgr.etcdDiscoveryHandler)
}

func (mgr *pxeManagerT) etcdDiscoveryHandler(w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r,
		"https://github.com/giantswarm/mayu/blob/master/docs/etcd-discovery.md",
		http.StatusMovedPermanently,
	)
}

func (mgr *pxeManagerT) etcdDiscoveryNewCluster(w http.ResponseWriter, r *http.Request) {
	var err error
	size := mgr.defaultEtcdQuorumSize
	s := r.FormValue("size")
	if s != "" {
		size, err = strconv.Atoi(s)
		if err != nil {
			httpError(w, err.Error(), http.StatusBadRequest)
			return
		}
	}

	token, err := mgr.cluster.GenerateEtcdDiscoveryToken()
	if err != nil {
		httpError(w, fmt.Sprintf("Unable to generate token '%v'", err), 400)
		return
	}

	err = mgr.cluster.StoreEtcdDiscoveryToken(mgr.etcdEndpoint, mgr.etcdCAFile, token, size)
	if err != nil {
		httpError(w, fmt.Sprintf("Unable to store token in etcd '%v'", err), 400)
		return
	}

	glog.V(2).Infof("New cluster created '%s'", token)

	fmt.Fprintf(w, "%s/%s", mgr.etcdDiscoveryBaseURL(), token)
}

func (mgr *pxeManagerT) etcdDiscoveryBaseURL() string {
	return fmt.Sprintf("%s/etcd", mgr.thisHost())
}

func (mgr *pxeManagerT) etcdDiscoveryProxyHandler(w http.ResponseWriter, r *http.Request) {
	resp, err := mgr.etcdDiscoveryProxyRequest(r)
	if err != nil {
		httpError(w, fmt.Sprintf("Error proxying request to etcd '%v'", err), 500)
	}

	copyHeader(w.Header(), resp.Header)
	w.WriteHeader(resp.StatusCode)
	io.Copy(w, resp.Body)
}

func (mgr *pxeManagerT) etcdDiscoveryProxyRequest(r *http.Request) (*http.Response, error) {
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return nil, err
	}

	for i := 0; i <= 10; i++ {
		u := url.URL{
			Scheme:   "http",
			Host:     mgr.etcdEndpoint,
			Path:     path.Join("v2", "keys", "_etcd", "registry", strings.TrimPrefix(r.URL.Path, "/etcd")),
			RawQuery: r.URL.RawQuery,
		}

		buf := bytes.NewBuffer(body)
		glog.V(2).Infof("Body '%s'", body)

		outreq, err := http.NewRequest(r.Method, u.String(), buf)
		if err != nil {
			return nil, err
		}

		copyHeader(outreq.Header, r.Header)

		client := http.Client{}
		resp, err := client.Do(outreq)
		if err != nil {
			return nil, err
		}

		return resp, nil
	}

	return nil, errors.New("All attempts at proxying to etcd failed")
}

// copyHeader copies all of the headers from dst to src.
func copyHeader(dst, src http.Header) {
	for k, v := range src {
		for _, q := range v {
			dst.Add(k, q)
		}
	}
}
<commit_msg>fixed etcd proxy for https etcd<commit_after>package pxemgr

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"path"
	"strconv"
	"strings"

	"github.com/golang/glog"
	"github.com/gorilla/mux"
	"crypto/x509"
	"crypto/tls"
)

type EtcdNode struct {
	Key   string      `json:"key"`
	Value string      `json:"value,omitempty"`
	Nodes []*EtcdNode `json:"nodes,omitempty"`
	Dir   bool        `json:"dir,omitempty"`
}

type EtcdResponse struct {
	Action string    `json:"action"`
	Node   *EtcdNode `json:"node,omitempty"`
}

type EtcdResponseError struct {
	ErrorCode int    `json:"errorCode"`
	Message   string `json:"message"`
	Cause     string `json:"cause"`
}

func (mgr *pxeManagerT) defineEtcdDiscoveryRoutes(etcdRouter *mux.Router) {
	etcdRouter.PathPrefix("/new").Methods("PUT").HandlerFunc(mgr.etcdDiscoveryNewCluster)

	tokenRouter := etcdRouter.PathPrefix("/{token:[a-f0-9]{32}}").Subrouter()
	tokenRouter.PathPrefix("/_config/size").Methods("GET").HandlerFunc(mgr.etcdDiscoveryProxyHandler)
	tokenRouter.PathPrefix("/_config/size").Methods("PUT").HandlerFunc(mgr.etcdDiscoveryProxyHandler)
	tokenRouter.PathPrefix("/{machine}").Methods("PUT").HandlerFunc(mgr.etcdDiscoveryProxyHandler)
	tokenRouter.PathPrefix("/{machine}").Methods("GET").HandlerFunc(mgr.etcdDiscoveryProxyHandler)
	tokenRouter.PathPrefix("/{machine}").Methods("DELETE").HandlerFunc(mgr.etcdDiscoveryProxyHandler)
	tokenRouter.Methods("GET").HandlerFunc(mgr.etcdDiscoveryProxyHandler)

	etcdRouter.Methods("GET").HandlerFunc(mgr.etcdDiscoveryHandler)
}

func (mgr *pxeManagerT) etcdDiscoveryHandler(w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r,
		"https://github.com/giantswarm/mayu/blob/master/docs/etcd-discovery.md",
		http.StatusMovedPermanently,
	)
}

func (mgr *pxeManagerT) etcdDiscoveryNewCluster(w http.ResponseWriter, r *http.Request) {
	var err error
	size := mgr.defaultEtcdQuorumSize
	s := r.FormValue("size")
	if s != "" {
		size, err = strconv.Atoi(s)
		if err != nil {
			httpError(w, err.Error(), http.StatusBadRequest)
			return
		}
	}

	token, err := mgr.cluster.GenerateEtcdDiscoveryToken()
	if err != nil {
		httpError(w, fmt.Sprintf("Unable to generate token '%v'", err), 400)
		return
	}

	err = mgr.cluster.StoreEtcdDiscoveryToken(mgr.etcdEndpoint, mgr.etcdCAFile, token, size)
	if err != nil {
		httpError(w, fmt.Sprintf("Unable to store token in etcd '%v'", err), 400)
		return
	}

	glog.V(2).Infof("New cluster created '%s'", token)

	fmt.Fprintf(w, "%s/%s", mgr.etcdDiscoveryBaseURL(), token)
}

func (mgr *pxeManagerT) etcdDiscoveryBaseURL() string {
	return fmt.Sprintf("%s/etcd", mgr.thisHost())
}

func (mgr *pxeManagerT) etcdDiscoveryProxyHandler(w http.ResponseWriter, r *http.Request) {
	resp, err := mgr.etcdDiscoveryProxyRequest(r)
	if err != nil {
		httpError(w, fmt.Sprintf("Error proxying request to etcd '%v'", err), 500)
	}

	copyHeader(w.Header(), resp.Header)
	w.WriteHeader(resp.StatusCode)
	io.Copy(w, resp.Body)
}

func (mgr *pxeManagerT) etcdDiscoveryProxyRequest(r *http.Request) (*http.Response, error) {
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return nil, err
	}
	var transport = http.DefaultTransport

	if strings.HasPrefix(mgr.etcdEndpoint, "https") && mgr.etcdCAFile != "" {
		customCA := x509.NewCertPool()

		pemData, err := ioutil.ReadFile(mgr.etcdCAFile)
		if err != nil {
			return nil, errors.New("Unable to read custom CA file: "+err.Error())
		}
		customCA.AppendCertsFromPEM(pemData)
		transport = &http.Transport{
			TLSClientConfig: &tls.Config{RootCAs:customCA},
		}
	}

	scheme := strings.Split(mgr.etcdEndpoint,":")[0]
	host := strings.Split(mgr.etcdEndpoint,"/")[2]

	for i := 0; i <= 10; i++ {
		u := url.URL{
			Scheme:   scheme,
			Host:     host,
			Path:     path.Join("v2", "keys", "_etcd", "registry", strings.TrimPrefix(r.URL.Path, "/etcd")),
			RawQuery: r.URL.RawQuery,
		}

		buf := bytes.NewBuffer(body)
		glog.V(2).Infof("Body '%s'", body)

		outreq, err := http.NewRequest(r.Method, u.String(), buf)
		if err != nil {
			return nil, err
		}

		copyHeader(outreq.Header, r.Header)

		client := http.Client{Transport:transport}
		resp, err := client.Do(outreq)
		if err != nil {
			return nil, err
		}

		return resp, nil
	}

	return nil, errors.New("All attempts at proxying to etcd failed")
}

// copyHeader copies all of the headers from dst to src.
func copyHeader(dst, src http.Header) {
	for k, v := range src {
		for _, q := range v {
			dst.Add(k, q)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright (c) Alex Ellis 2017. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

package requests

// CreateFunctionRequest create a function in the swarm.
type CreateFunctionRequest struct {
	Service string `json:"service"`
	Image   string `json:"image"`
	Network string `json:"network"`

	// EnvProcess corresponds to the fprocess variable for your container watchdog.
	EnvProcess string `json:"envProcess"`

	// EnvVars provides overrides for functions.
	EnvVars map[string]string `json:"envVars"`
}

type DeleteFunctionRequest struct {
	FunctionName string `json:"functionName"`
}

type AlexaSessionApplication struct {
	ApplicationId string `json:"applicationId"`
}

type AlexaSession struct {
	SessionId   string                  `json:"sessionId"`
	Application AlexaSessionApplication `json:"application"`
}

type AlexaIntent struct {
	Name string `json:"name"`
}

type AlexaRequest struct {
	Intent AlexaIntent `json:"intent"`
}

// AlexaRequestBody top-level request produced by Alexa SDK
type AlexaRequestBody struct {
	Session AlexaSession `json:"session"`
	Request AlexaRequest `json:"request"`
}

type PrometheusInnerAlertLabel struct {
	AlertName    string `json:"alertname"`
	FunctionName string `json:"function_name"`
}

type PrometheusInnerAlert struct {
	Status string                    `json:"status"`
	Labels PrometheusInnerAlertLabel `json:"labels"`
}

// PrometheusAlert as produced by AlertManager
type PrometheusAlert struct {
	Status   string                 `json:"status"`
	Receiver string                 `json:"receiver"`
	Alerts   []PrometheusInnerAlert `json:"alerts"`
}

// Function exported for system/functions endpoint
type Function struct {
	Name            string  `json:"name"`
	Image           string  `json:"image"`
	InvocationCount float64 `json:"invocationCount"`
	Replicas        uint64  `json:"replicas"`
}
<commit_msg>Requests update<commit_after>// Copyright (c) Alex Ellis 2017. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

package requests

// CreateFunctionRequest create a function in the swarm.
type CreateFunctionRequest struct {
	// Service corresponds to a Docker Service
	Service string `json:"service"`
	// Image corresponds to a Docker image
	Image string `json:"image"`

	// Network is a Docker overlay network in Swarm - the default value is func_functions
	Network string `json:"network"`

	// EnvProcess corresponds to the fprocess variable for your container watchdog.
	EnvProcess string `json:"envProcess"`

	// EnvVars provides overrides for functions.
	EnvVars map[string]string `json:"envVars"`
}

type DeleteFunctionRequest struct {
	FunctionName string `json:"functionName"`
}

type AlexaSessionApplication struct {
	ApplicationId string `json:"applicationId"`
}

type AlexaSession struct {
	SessionId   string                  `json:"sessionId"`
	Application AlexaSessionApplication `json:"application"`
}

type AlexaIntent struct {
	Name string `json:"name"`
}

type AlexaRequest struct {
	Intent AlexaIntent `json:"intent"`
}

// AlexaRequestBody top-level request produced by Alexa SDK
type AlexaRequestBody struct {
	Session AlexaSession `json:"session"`
	Request AlexaRequest `json:"request"`
}

type PrometheusInnerAlertLabel struct {
	AlertName    string `json:"alertname"`
	FunctionName string `json:"function_name"`
}

type PrometheusInnerAlert struct {
	Status string                    `json:"status"`
	Labels PrometheusInnerAlertLabel `json:"labels"`
}

// PrometheusAlert as produced by AlertManager
type PrometheusAlert struct {
	Status   string                 `json:"status"`
	Receiver string                 `json:"receiver"`
	Alerts   []PrometheusInnerAlert `json:"alerts"`
}

// Function exported for system/functions endpoint
type Function struct {
	Name            string  `json:"name"`
	Image           string  `json:"image"`
	InvocationCount float64 `json:"invocationCount"`
	Replicas        uint64  `json:"replicas"`
}
<|endoftext|>


<commit_before>package s3

import (
	"fmt"
	"net/http"

	"github.com/pachyderm/pachyderm/src/client/auth"
)

func (c *controller) SecretKey(r *http.Request, accessKey string, region *string) (*string, error) {
	pc, err := c.pachClient(accessKey)
	if err != nil {
		return nil, fmt.Errorf("could not create a pach client for auth: %s", err)
	}

	_, err = pc.WhoAmI(pc.Ctx(), &auth.WhoAmIRequest{})
	if err != nil {
		// Some S3 clients (like minio) require the use of authenticated
		// requests, so in the case that auth is not enabled on pachyderm,
		// just allow any access credentials.

		// allow any access key when auth is disabled
		if auth.IsErrNotActivated(err) {
			blankAccessKey := ""
			return &blankAccessKey, nil
		}
		return nil, nil
	}
	return &accessKey, nil
}

func (c *controller) CustomAuth(r *http.Request) (bool, error) {
	pc, err := c.pachClient("")
	if err != nil {
		return false, fmt.Errorf("could not create a pach client for auth: %s", err)
	}

	active, err := pc.IsAuthActive()
	if err != nil {
		return false, fmt.Errorf("could not check whether auth is active: %s", err)
	}
	return !active, nil
}
<commit_msg>Fixed comment<commit_after>package s3

import (
	"fmt"
	"net/http"

	"github.com/pachyderm/pachyderm/src/client/auth"
)

func (c *controller) SecretKey(r *http.Request, accessKey string, region *string) (*string, error) {
	pc, err := c.pachClient(accessKey)
	if err != nil {
		return nil, fmt.Errorf("could not create a pach client for auth: %s", err)
	}

	_, err = pc.WhoAmI(pc.Ctx(), &auth.WhoAmIRequest{})
	if err != nil {
		// Some S3 clients (like minio) require the use of authenticated
		// requests, so in the case that auth is not enabled on pachyderm,
		// just allow any access credentials.
		if auth.IsErrNotActivated(err) {
			blankAccessKey := ""
			return &blankAccessKey, nil
		}
		return nil, nil
	}
	return &accessKey, nil
}

func (c *controller) CustomAuth(r *http.Request) (bool, error) {
	pc, err := c.pachClient("")
	if err != nil {
		return false, fmt.Errorf("could not create a pach client for auth: %s", err)
	}

	active, err := pc.IsAuthActive()
	if err != nil {
		return false, fmt.Errorf("could not check whether auth is active: %s", err)
	}
	return !active, nil
}
<|endoftext|>


<commit_before>package obj

import (
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/url"
	"time"

	"github.com/cenkalti/backoff"
	"github.com/pachyderm/pachyderm/src/client/pkg/uuid"
	"go.pedge.io/lion"
	"golang.org/x/net/context"
)

// Client is an interface to object storage.
type Client interface {
	// Writer returns a writer which writes to an object.
	// It should error if the object already exists or we don't have sufficient
	// permissions to write it.
	Writer(name string) (io.WriteCloser, error)
	// Reader returns a reader which reads from an object.
	// If `size == 0`, the reader should read from the offset till the end of the object.
	// It should error if the object doesn't exist or we don't have sufficient
	// permission to read it.
	Reader(name string, offset uint64, size uint64) (io.ReadCloser, error)
	// Delete deletes an object.
	// It should error if the object doesn't exist or we don't have sufficient
	// permission to delete it.
	Delete(name string) error
	// Walk calls `fn` with the names of objects which can be found under `prefix`.
	Walk(prefix string, fn func(name string) error) error
	// Exsits checks if a given object already exists
	Exists(name string) bool
	// isRetryable determines if an operation should be retried given an error
	isRetryable(err error) bool
	// IsNotExist returns true if err is a non existence error
	IsNotExist(err error) bool
	// IsIgnorable returns true if the error can be ignored
	IsIgnorable(err error) bool
}

// NewGoogleClient creates a google client with the given bucket name.
func NewGoogleClient(ctx context.Context, bucket string) (Client, error) {
	return newGoogleClient(ctx, bucket)
}

// NewGoogleClientFromSecret creates a google client by reading credentials
// from a mounted GoogleSecret. You may pass "" for bucket in which case it
// will read the bucket from the secret.
func NewGoogleClientFromSecret(ctx context.Context, bucket string) (Client, error) {
	if bucket == "" {
		_bucket, err := ioutil.ReadFile("/google-secret/bucket")
		if err != nil {
			return nil, err
		}
		bucket = string(_bucket)
	}
	return NewGoogleClient(ctx, bucket)
}

// NewMicrosoftClient creates a microsoft client:
//	container   - Azure Blob Container name
//	accountName - Azure Storage Account name
// 	accountKey  - Azure Storage Account key
func NewMicrosoftClient(container string, accountName string, accountKey string) (Client, error) {
	return newMicrosoftClient(container, accountName, accountKey)
}

// NewMicrosoftClientFromSecret creates a microsoft client by reading
// credentials from a mounted MicrosoftSecret. You may pass "" for container in
// which case it will read the container from the secret.
func NewMicrosoftClientFromSecret(container string) (Client, error) {
	if container == "" {
		_container, err := ioutil.ReadFile("/microsoft-secret/container")
		if err != nil {
			return nil, err
		}
		container = string(_container)
	}
	id, err := ioutil.ReadFile("/microsoft-secret/id")
	if err != nil {
		return nil, err
	}
	secret, err := ioutil.ReadFile("/microsoft-secret/secret")
	if err != nil {
		return nil, err
	}
	return NewMicrosoftClient(container, string(id), string(secret))
}

// NewMinioClient creates an s3 compatible client with the following credentials:
//   endpoint - S3 compatible endpoint
//   bucket - S3 bucket name
//   id     - AWS access key id
//   secret - AWS secret access key
//   secure - Set to true if connection is secure.
func NewMinioClient(endpoint, bucket, id, secret string, secure bool) (Client, error) {
	return newMinioClient(endpoint, bucket, id, secret, secure)
}

// NewAmazonClient creates an amazon client with the following credentials:
//   bucket - S3 bucket name
//   distribution - cloudfront distribution ID
//   id     - AWS access key id
//   secret - AWS secret access key
//   token  - AWS access token
//   region - AWS region
func NewAmazonClient(bucket string, distribution string, id string, secret string, token string,
	region string) (Client, error) {
	return newAmazonClient(bucket, distribution, id, secret, token, region)
}

// NewMinioClientFromSecret constructs an s3 compatible client by reading
// credentials from a mounted AmazonSecret. You may pass "" for bucket in which case it
// will read the bucket from the secret.
func NewMinioClientFromSecret(bucket string) (Client, error) {
	if bucket == "" {
		_bucket, err := ioutil.ReadFile("/minio-secret/bucket")
		if err != nil {
			return nil, err
		}
		bucket = string(_bucket)
	}
	endpoint, err := ioutil.ReadFile("/minio-secret/endpoint")
	if err != nil {
		return nil, err
	}
	id, err := ioutil.ReadFile("/minio-secret/id")
	if err != nil {
		return nil, err
	}
	secret, err := ioutil.ReadFile("/minio-secret/secret")
	if err != nil {
		return nil, err
	}
	secure, err := ioutil.ReadFile("/minio-secret/secure")
	if err != nil {
		return nil, err
	}
	return NewMinioClient(string(endpoint), bucket, string(id), string(secret), string(secure) == "1")
}

// NewAmazonClientFromSecret constructs an amazon client by reading credentials
// from a mounted AmazonSecret. You may pass "" for bucket in which case it
// will read the bucket from the secret.
func NewAmazonClientFromSecret(bucket string) (Client, error) {
	if bucket == "" {
		_bucket, err := ioutil.ReadFile("/amazon-secret/bucket")
		if err != nil {
			return nil, err
		}
		bucket = string(_bucket)
	}
	var distribution []byte
	distribution, err := ioutil.ReadFile("/amazon-secret/distribution")
	if err != nil {
		// Distribution is not required, but we can log a warning
		lion.Warnln("AWS deployed without cloudfront distribution\n")
	}
	id, err := ioutil.ReadFile("/amazon-secret/id")
	if err != nil {
		return nil, err
	}
	secret, err := ioutil.ReadFile("/amazon-secret/secret")
	if err != nil {
		return nil, err
	}
	token, err := ioutil.ReadFile("/amazon-secret/token")
	if err != nil {
		return nil, err
	}
	region, err := ioutil.ReadFile("/amazon-secret/region")
	if err != nil {
		return nil, err
	}
	return NewAmazonClient(bucket, string(distribution), string(id), string(secret), string(token), string(region))
}

// NewClientFromURLAndSecret constructs a client by parsing `URL` and then
// constructing the correct client for that URL using secrets.
func NewClientFromURLAndSecret(ctx context.Context, URL string) (Client, error) {
	_URL, err := url.Parse(URL)
	if err != nil {
		return nil, err
	}
	switch _URL.Scheme {
	case "s3":
		return NewAmazonClientFromSecret(_URL.Host)
	case "gcs":
		fallthrough
	case "gs":
		return NewGoogleClientFromSecret(ctx, _URL.Host)
	case "as":
		fallthrough
	case "wasb":
		return NewMicrosoftClientFromSecret(_URL.Host)
	}
	return nil, fmt.Errorf("unrecognized object store: %s", _URL.Scheme)
}

// NewExponentialBackOffConfig creates an exponential back-off config with
// longer wait times than the default.
func NewExponentialBackOffConfig() *backoff.ExponentialBackOff {
	config := backoff.NewExponentialBackOff()
	// We want to backoff more aggressively (i.e. wait longer) than the default
	config.InitialInterval = 1 * time.Second
	config.Multiplier = 2
	config.MaxElapsedTime = 15 * time.Minute
	return config
}

// RetryError is used to log retry attempts.
type RetryError struct {
	Err               string
	TimeTillNextRetry string
	BytesProcessed    int
}

// BackoffReadCloser retries with exponential backoff in the case of failures
type BackoffReadCloser struct {
	client        Client
	reader        io.ReadCloser
	backoffConfig *backoff.ExponentialBackOff
}

func newBackoffReadCloser(client Client, reader io.ReadCloser) io.ReadCloser {
	return &BackoffReadCloser{
		client:        client,
		reader:        reader,
		backoffConfig: NewExponentialBackOffConfig(),
	}
}

func (b *BackoffReadCloser) Read(data []byte) (int, error) {
	bytesRead := 0
	var n int
	var err error
	backoff.RetryNotify(func() error {
		n, err = b.reader.Read(data[bytesRead:])
		bytesRead += n
		if err != nil && IsRetryable(b.client, err) {
			return err
		}
		return nil
	}, b.backoffConfig, func(err error, d time.Duration) {
		lion.Infof("Error reading; retrying in %s: %#v", d, RetryError{
			Err:               err.Error(),
			TimeTillNextRetry: d.String(),
			BytesProcessed:    bytesRead,
		})
	})
	return bytesRead, err
}

// Close closes the ReaderCloser contained in b.
func (b *BackoffReadCloser) Close() error {
	return b.reader.Close()
}

// BackoffWriteCloser retries with exponential backoff in the case of failures
type BackoffWriteCloser struct {
	client        Client
	writer        io.WriteCloser
	backoffConfig *backoff.ExponentialBackOff
}

func newBackoffWriteCloser(client Client, writer io.WriteCloser) io.WriteCloser {
	return &BackoffWriteCloser{
		client:        client,
		writer:        writer,
		backoffConfig: NewExponentialBackOffConfig(),
	}
}

func (b *BackoffWriteCloser) Write(data []byte) (int, error) {
	bytesWritten := 0
	var n int
	var err error
	backoff.RetryNotify(func() error {
		n, err = b.writer.Write(data[bytesWritten:])
		bytesWritten += n
		if err != nil && IsRetryable(b.client, err) {
			return err
		}
		return nil
	}, b.backoffConfig, func(err error, d time.Duration) {
		lion.Infof("Error writing; retrying in %s: %#v", d, RetryError{
			Err:               err.Error(),
			TimeTillNextRetry: d.String(),
			BytesProcessed:    bytesWritten,
		})
	})
	return bytesWritten, err
}

// Close closes the WriteCloser contained in b.
func (b *BackoffWriteCloser) Close() error {
	err := b.writer.Close()
	if b.client.IsIgnorable(err) {
		return nil
	}
	return err
}

// IsRetryable determines if an operation should be retried given an error
func IsRetryable(client Client, err error) bool {
	return isNetRetryable(err) || client.isRetryable(err)
}

func byteRange(offset uint64, size uint64) string {
	if offset == 0 && size == 0 {
		return ""
	} else if size == 0 {
		return fmt.Sprintf("%d-", offset)
	}
	return fmt.Sprintf("%d-%d", offset, offset+size-1)
}

func isNetRetryable(err error) bool {
	netErr, ok := err.(net.Error)
	return ok && netErr.Temporary()
}

// TestIsNotExist is a defensive method for checking to make sure IsNotExist is
// satisfying its semantics.
func TestIsNotExist(c Client) error {
	_, err := c.Reader(uuid.NewWithoutDashes(), 0, 0)
	if !c.IsNotExist(err) {
		return fmt.Errorf("storage is unable to discern NotExist errors, \"%s\" should count as NotExist", err.Error())
	}
	return nil
}
<commit_msg>Only read the distribution when using the secret bucket as well<commit_after>package obj

import (
	"fmt"
	"io"
	"io/ioutil"
	"net"
	"net/url"
	"time"

	"github.com/cenkalti/backoff"
	"github.com/pachyderm/pachyderm/src/client/pkg/uuid"
	"go.pedge.io/lion"
	"golang.org/x/net/context"
)

// Client is an interface to object storage.
type Client interface {
	// Writer returns a writer which writes to an object.
	// It should error if the object already exists or we don't have sufficient
	// permissions to write it.
	Writer(name string) (io.WriteCloser, error)
	// Reader returns a reader which reads from an object.
	// If `size == 0`, the reader should read from the offset till the end of the object.
	// It should error if the object doesn't exist or we don't have sufficient
	// permission to read it.
	Reader(name string, offset uint64, size uint64) (io.ReadCloser, error)
	// Delete deletes an object.
	// It should error if the object doesn't exist or we don't have sufficient
	// permission to delete it.
	Delete(name string) error
	// Walk calls `fn` with the names of objects which can be found under `prefix`.
	Walk(prefix string, fn func(name string) error) error
	// Exsits checks if a given object already exists
	Exists(name string) bool
	// isRetryable determines if an operation should be retried given an error
	isRetryable(err error) bool
	// IsNotExist returns true if err is a non existence error
	IsNotExist(err error) bool
	// IsIgnorable returns true if the error can be ignored
	IsIgnorable(err error) bool
}

// NewGoogleClient creates a google client with the given bucket name.
func NewGoogleClient(ctx context.Context, bucket string) (Client, error) {
	return newGoogleClient(ctx, bucket)
}

// NewGoogleClientFromSecret creates a google client by reading credentials
// from a mounted GoogleSecret. You may pass "" for bucket in which case it
// will read the bucket from the secret.
func NewGoogleClientFromSecret(ctx context.Context, bucket string) (Client, error) {
	if bucket == "" {
		_bucket, err := ioutil.ReadFile("/google-secret/bucket")
		if err != nil {
			return nil, err
		}
		bucket = string(_bucket)
	}
	return NewGoogleClient(ctx, bucket)
}

// NewMicrosoftClient creates a microsoft client:
//	container   - Azure Blob Container name
//	accountName - Azure Storage Account name
// 	accountKey  - Azure Storage Account key
func NewMicrosoftClient(container string, accountName string, accountKey string) (Client, error) {
	return newMicrosoftClient(container, accountName, accountKey)
}

// NewMicrosoftClientFromSecret creates a microsoft client by reading
// credentials from a mounted MicrosoftSecret. You may pass "" for container in
// which case it will read the container from the secret.
func NewMicrosoftClientFromSecret(container string) (Client, error) {
	if container == "" {
		_container, err := ioutil.ReadFile("/microsoft-secret/container")
		if err != nil {
			return nil, err
		}
		container = string(_container)
	}
	id, err := ioutil.ReadFile("/microsoft-secret/id")
	if err != nil {
		return nil, err
	}
	secret, err := ioutil.ReadFile("/microsoft-secret/secret")
	if err != nil {
		return nil, err
	}
	return NewMicrosoftClient(container, string(id), string(secret))
}

// NewMinioClient creates an s3 compatible client with the following credentials:
//   endpoint - S3 compatible endpoint
//   bucket - S3 bucket name
//   id     - AWS access key id
//   secret - AWS secret access key
//   secure - Set to true if connection is secure.
func NewMinioClient(endpoint, bucket, id, secret string, secure bool) (Client, error) {
	return newMinioClient(endpoint, bucket, id, secret, secure)
}

// NewAmazonClient creates an amazon client with the following credentials:
//   bucket - S3 bucket name
//   distribution - cloudfront distribution ID
//   id     - AWS access key id
//   secret - AWS secret access key
//   token  - AWS access token
//   region - AWS region
func NewAmazonClient(bucket string, distribution string, id string, secret string, token string,
	region string) (Client, error) {
	return newAmazonClient(bucket, distribution, id, secret, token, region)
}

// NewMinioClientFromSecret constructs an s3 compatible client by reading
// credentials from a mounted AmazonSecret. You may pass "" for bucket in which case it
// will read the bucket from the secret.
func NewMinioClientFromSecret(bucket string) (Client, error) {
	if bucket == "" {
		_bucket, err := ioutil.ReadFile("/minio-secret/bucket")
		if err != nil {
			return nil, err
		}
		bucket = string(_bucket)
	}
	endpoint, err := ioutil.ReadFile("/minio-secret/endpoint")
	if err != nil {
		return nil, err
	}
	id, err := ioutil.ReadFile("/minio-secret/id")
	if err != nil {
		return nil, err
	}
	secret, err := ioutil.ReadFile("/minio-secret/secret")
	if err != nil {
		return nil, err
	}
	secure, err := ioutil.ReadFile("/minio-secret/secure")
	if err != nil {
		return nil, err
	}
	return NewMinioClient(string(endpoint), bucket, string(id), string(secret), string(secure) == "1")
}

// NewAmazonClientFromSecret constructs an amazon client by reading credentials
// from a mounted AmazonSecret. You may pass "" for bucket in which case it
// will read the bucket from the secret.
func NewAmazonClientFromSecret(bucket string) (Client, error) {
	var distribution []byte
	if bucket == "" {
		_bucket, err := ioutil.ReadFile("/amazon-secret/bucket")
		if err != nil {
			return nil, err
		}
		bucket = string(_bucket)
		distribution, err := ioutil.ReadFile("/amazon-secret/distribution")
		if err != nil {
			// Distribution is not required, but we can log a warning
			lion.Warnln("AWS deployed without cloudfront distribution\n")
		}
	}
	id, err := ioutil.ReadFile("/amazon-secret/id")
	if err != nil {
		return nil, err
	}
	secret, err := ioutil.ReadFile("/amazon-secret/secret")
	if err != nil {
		return nil, err
	}
	token, err := ioutil.ReadFile("/amazon-secret/token")
	if err != nil {
		return nil, err
	}
	region, err := ioutil.ReadFile("/amazon-secret/region")
	if err != nil {
		return nil, err
	}
	return NewAmazonClient(bucket, string(distribution), string(id), string(secret), string(token), string(region))
}

// NewClientFromURLAndSecret constructs a client by parsing `URL` and then
// constructing the correct client for that URL using secrets.
func NewClientFromURLAndSecret(ctx context.Context, URL string) (Client, error) {
	_URL, err := url.Parse(URL)
	if err != nil {
		return nil, err
	}
	switch _URL.Scheme {
	case "s3":
		return NewAmazonClientFromSecret(_URL.Host)
	case "gcs":
		fallthrough
	case "gs":
		return NewGoogleClientFromSecret(ctx, _URL.Host)
	case "as":
		fallthrough
	case "wasb":
		return NewMicrosoftClientFromSecret(_URL.Host)
	}
	return nil, fmt.Errorf("unrecognized object store: %s", _URL.Scheme)
}

// NewExponentialBackOffConfig creates an exponential back-off config with
// longer wait times than the default.
func NewExponentialBackOffConfig() *backoff.ExponentialBackOff {
	config := backoff.NewExponentialBackOff()
	// We want to backoff more aggressively (i.e. wait longer) than the default
	config.InitialInterval = 1 * time.Second
	config.Multiplier = 2
	config.MaxElapsedTime = 15 * time.Minute
	return config
}

// RetryError is used to log retry attempts.
type RetryError struct {
	Err               string
	TimeTillNextRetry string
	BytesProcessed    int
}

// BackoffReadCloser retries with exponential backoff in the case of failures
type BackoffReadCloser struct {
	client        Client
	reader        io.ReadCloser
	backoffConfig *backoff.ExponentialBackOff
}

func newBackoffReadCloser(client Client, reader io.ReadCloser) io.ReadCloser {
	return &BackoffReadCloser{
		client:        client,
		reader:        reader,
		backoffConfig: NewExponentialBackOffConfig(),
	}
}

func (b *BackoffReadCloser) Read(data []byte) (int, error) {
	bytesRead := 0
	var n int
	var err error
	backoff.RetryNotify(func() error {
		n, err = b.reader.Read(data[bytesRead:])
		bytesRead += n
		if err != nil && IsRetryable(b.client, err) {
			return err
		}
		return nil
	}, b.backoffConfig, func(err error, d time.Duration) {
		lion.Infof("Error reading; retrying in %s: %#v", d, RetryError{
			Err:               err.Error(),
			TimeTillNextRetry: d.String(),
			BytesProcessed:    bytesRead,
		})
	})
	return bytesRead, err
}

// Close closes the ReaderCloser contained in b.
func (b *BackoffReadCloser) Close() error {
	return b.reader.Close()
}

// BackoffWriteCloser retries with exponential backoff in the case of failures
type BackoffWriteCloser struct {
	client        Client
	writer        io.WriteCloser
	backoffConfig *backoff.ExponentialBackOff
}

func newBackoffWriteCloser(client Client, writer io.WriteCloser) io.WriteCloser {
	return &BackoffWriteCloser{
		client:        client,
		writer:        writer,
		backoffConfig: NewExponentialBackOffConfig(),
	}
}

func (b *BackoffWriteCloser) Write(data []byte) (int, error) {
	bytesWritten := 0
	var n int
	var err error
	backoff.RetryNotify(func() error {
		n, err = b.writer.Write(data[bytesWritten:])
		bytesWritten += n
		if err != nil && IsRetryable(b.client, err) {
			return err
		}
		return nil
	}, b.backoffConfig, func(err error, d time.Duration) {
		lion.Infof("Error writing; retrying in %s: %#v", d, RetryError{
			Err:               err.Error(),
			TimeTillNextRetry: d.String(),
			BytesProcessed:    bytesWritten,
		})
	})
	return bytesWritten, err
}

// Close closes the WriteCloser contained in b.
func (b *BackoffWriteCloser) Close() error {
	err := b.writer.Close()
	if b.client.IsIgnorable(err) {
		return nil
	}
	return err
}

// IsRetryable determines if an operation should be retried given an error
func IsRetryable(client Client, err error) bool {
	return isNetRetryable(err) || client.isRetryable(err)
}

func byteRange(offset uint64, size uint64) string {
	if offset == 0 && size == 0 {
		return ""
	} else if size == 0 {
		return fmt.Sprintf("%d-", offset)
	}
	return fmt.Sprintf("%d-%d", offset, offset+size-1)
}

func isNetRetryable(err error) bool {
	netErr, ok := err.(net.Error)
	return ok && netErr.Temporary()
}

// TestIsNotExist is a defensive method for checking to make sure IsNotExist is
// satisfying its semantics.
func TestIsNotExist(c Client) error {
	_, err := c.Reader(uuid.NewWithoutDashes(), 0, 0)
	if !c.IsNotExist(err) {
		return fmt.Errorf("storage is unable to discern NotExist errors, \"%s\" should count as NotExist", err.Error())
	}
	return nil
}
<|endoftext|>


<commit_before>package fuse

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"os/exec"
	"sync"
	"syscall"
)

func lineLogger(wg *sync.WaitGroup, prefix string, r io.ReadCloser) {
	defer wg.Done()

	scanner := bufio.NewScanner(r)
	for scanner.Scan() {
		switch line := scanner.Text(); line {
		case `fusermount: failed to open /etc/fuse.conf: Permission denied`:
			// Silence this particular message, it occurs way too
			// commonly and isn't very relevant to whether the mount
			// succeeds or not.
			continue
		default:
			log.Printf("%s: %s", prefix, line)
		}
	}
	if err := scanner.Err(); err != nil {
		log.Printf("%s, error reading: %v", prefix, err)
	}
}

// Begin the process of mounting at the given directory, returning a connection
// to the kernel. Mounting continues in the background, and is complete when an
// error is written to the supplied channel. The file system may need to
// service the connection in order for mounting to complete.
func mount(
	dir string,
	cfg *MountConfig,
	ready chan<- error) (dev *os.File, err error) {
	// On linux, mounting is never delayed.
	ready <- nil

	// Create a socket pair.
	fds, err := syscall.Socketpair(syscall.AF_FILE, syscall.SOCK_STREAM, 0)
	if err != nil {
		err = fmt.Errorf("Socketpair: %v", err)
		return
	}

	// Wrap the sockets into os.File objects that we will pass off to fusermount.
	writeFile := os.NewFile(uintptr(fds[0]), "fusermount-child-writes")
	defer writeFile.Close()

	readFile := os.NewFile(uintptr(fds[1]), "fusermount-parent-reads")
	defer readFile.Close()

	// Start fusermount, passing it pipes for stdout and stderr.
	cmd := exec.Command(
		"fusermount",
		"-o", cfg.toOptionsString(),
		"--",
		dir,
	)

	cmd.Env = append(os.Environ(), "_FUSE_COMMFD=3")
	cmd.ExtraFiles = []*os.File{writeFile}

	stdout, err := cmd.StdoutPipe()
	if err != nil {
		err = fmt.Errorf("StdoutPipe: %v", err)
		return
	}

	stderr, err := cmd.StderrPipe()
	if err != nil {
		err = fmt.Errorf("StderrPipe: %v", err)
		return
	}

	err = cmd.Start()
	if err != nil {
		err = fmt.Errorf("Starting fusermount: %v", err)
		return
	}

	// Log fusermount output until it closes stdout and stderr.
	var wg sync.WaitGroup
	wg.Add(2)
	go lineLogger(&wg, "mount helper output", stdout)
	go lineLogger(&wg, "mount helper error", stderr)
	wg.Wait()

	// Wait for the command.
	err = cmd.Wait()
	if err != nil {
		err = fmt.Errorf("fusermount: %v", err)
		return
	}

	// Wrap the socket file in a connection.
	c, err := net.FileConn(readFile)
	if err != nil {
		err = fmt.Errorf("FileConn: %v", err)
		return
	}
	defer c.Close()

	// We expect to have a Unix domain socket.
	uc, ok := c.(*net.UnixConn)
	if !ok {
		err = fmt.Errorf("Expected UnixConn, got %T", c)
		return
	}

	// Read a message.
	buf := make([]byte, 32) // expect 1 byte
	oob := make([]byte, 32) // expect 24 bytes
	_, oobn, _, _, err := uc.ReadMsgUnix(buf, oob)
	if err != nil {
		err = fmt.Errorf("ReadMsgUnix: %v", err)
		return
	}

	// Parse the message.
	scms, err := syscall.ParseSocketControlMessage(oob[:oobn])
	if err != nil {
		err = fmt.Errorf("ParseSocketControlMessage: %v", err)
		return
	}

	// We expect one message.
	if len(scms) != 1 {
		err = fmt.Errorf("expected 1 SocketControlMessage; got scms = %#v", scms)
		return
	}

	scm := scms[0]

	// Pull out the FD returned by fusermount
	gotFds, err := syscall.ParseUnixRights(&scm)
	if err != nil {
		err = fmt.Errorf("syscall.ParseUnixRights: %v", err)
		return
	}

	if len(gotFds) != 1 {
		err = fmt.Errorf("wanted 1 fd; got %#v", gotFds)
		return
	}

	// Turn the FD into an os.File.
	dev = os.NewFile(uintptr(gotFds[0]), "/dev/fuse")

	return
}
<commit_msg>Kill off silly fusermount screen scraping.<commit_after>package fuse

import (
	"bytes"
	"fmt"
	"net"
	"os"
	"os/exec"
	"syscall"
)

// Begin the process of mounting at the given directory, returning a connection
// to the kernel. Mounting continues in the background, and is complete when an
// error is written to the supplied channel. The file system may need to
// service the connection in order for mounting to complete.
func mount(
	dir string,
	cfg *MountConfig,
	ready chan<- error) (dev *os.File, err error) {
	// On linux, mounting is never delayed.
	ready <- nil

	// Create a socket pair.
	fds, err := syscall.Socketpair(syscall.AF_FILE, syscall.SOCK_STREAM, 0)
	if err != nil {
		err = fmt.Errorf("Socketpair: %v", err)
		return
	}

	// Wrap the sockets into os.File objects that we will pass off to fusermount.
	writeFile := os.NewFile(uintptr(fds[0]), "fusermount-child-writes")
	defer writeFile.Close()

	readFile := os.NewFile(uintptr(fds[1]), "fusermount-parent-reads")
	defer readFile.Close()

	// Start fusermount, passing it a buffer in which to write stderr.
	var stderr bytes.Buffer

	cmd := exec.Command(
		"fusermount",
		"-o", cfg.toOptionsString(),
		"--",
		dir,
	)

	cmd.Env = append(os.Environ(), "_FUSE_COMMFD=3")
	cmd.ExtraFiles = []*os.File{writeFile}
	cmd.Stderr = &stderr

	// Run the command.
	err = cmd.Run()
	if err != nil {
		err = fmt.Errorf("running fusermount: %v\n\nstderr:\n%s", err, stderr.Bytes())
		return
	}

	// Wrap the socket file in a connection.
	c, err := net.FileConn(readFile)
	if err != nil {
		err = fmt.Errorf("FileConn: %v", err)
		return
	}
	defer c.Close()

	// We expect to have a Unix domain socket.
	uc, ok := c.(*net.UnixConn)
	if !ok {
		err = fmt.Errorf("Expected UnixConn, got %T", c)
		return
	}

	// Read a message.
	buf := make([]byte, 32) // expect 1 byte
	oob := make([]byte, 32) // expect 24 bytes
	_, oobn, _, _, err := uc.ReadMsgUnix(buf, oob)
	if err != nil {
		err = fmt.Errorf("ReadMsgUnix: %v", err)
		return
	}

	// Parse the message.
	scms, err := syscall.ParseSocketControlMessage(oob[:oobn])
	if err != nil {
		err = fmt.Errorf("ParseSocketControlMessage: %v", err)
		return
	}

	// We expect one message.
	if len(scms) != 1 {
		err = fmt.Errorf("expected 1 SocketControlMessage; got scms = %#v", scms)
		return
	}

	scm := scms[0]

	// Pull out the FD returned by fusermount
	gotFds, err := syscall.ParseUnixRights(&scm)
	if err != nil {
		err = fmt.Errorf("syscall.ParseUnixRights: %v", err)
		return
	}

	if len(gotFds) != 1 {
		err = fmt.Errorf("wanted 1 fd; got %#v", gotFds)
		return
	}

	// Turn the FD into an os.File.
	dev = os.NewFile(uintptr(gotFds[0]), "/dev/fuse")

	return
}
<|endoftext|>