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

package engine

import (
	"strings"
	"testing"

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

func TestSaltpackEncrypt(t *testing.T) {
	tc := SetupEngineTest(t, "SaltpackEncrypt")
	defer tc.Cleanup()

	u1 := CreateAndSignupFakeUser(tc, "nalcp")
	u2 := CreateAndSignupFakeUser(tc, "nalcp")
	u3 := CreateAndSignupFakeUser(tc, "nalcp")

	trackUI := &FakeIdentifyUI{
		Proofs: make(map[string]string),
	}
	ctx := &Context{IdentifyUI: trackUI, SecretUI: u3.NewSecretUI()}

	run := func(Recips []string) {
		sink := libkb.NewBufferCloser()
		arg := &SaltpackEncryptArg{
			Opts:   keybase1.SaltpackEncryptOptions{Recipients: Recips},
			Source: strings.NewReader("id2 and encrypt, id2 and encrypt"),
			Sink:   sink,
		}

		eng := NewSaltpackEncrypt(arg, tc.G)
		if err := RunEngine(eng, ctx); err != nil {
			t.Fatal(err)
		}

		out := sink.Bytes()
		if len(out) == 0 {
			t.Fatal("no output")
		}
	}
	run([]string{u1.Username, u2.Username})

	// If we add ourselves, we should be smart and not error out
	// (We are u3 in this case)
	run([]string{u1.Username, u2.Username, u3.Username})
}

func TestSaltpackEncryptSelfNoKey(t *testing.T) {
	tc := SetupEngineTest(t, "SaltpackEncrypt")
	defer tc.Cleanup()

	_, passphrase := createFakeUserWithNoKeys(tc)
	trackUI := &FakeIdentifyUI{
		Proofs: make(map[string]string),
	}
	ctx := &Context{IdentifyUI: trackUI, SecretUI: &libkb.TestSecretUI{Passphrase: passphrase}}

	sink := libkb.NewBufferCloser()
	arg := &SaltpackEncryptArg{
		Opts: keybase1.SaltpackEncryptOptions{
			Recipients: []string{"t_tracy+t_tracy@rooter", "t_george", "t_kb+gbrltest@twitter"},
		},
		Source: strings.NewReader("track and encrypt, track and encrypt"),
		Sink:   sink,
	}

	eng := NewSaltpackEncrypt(arg, tc.G)
	err := RunEngine(eng, ctx)
	if _, ok := err.(libkb.NoKeyError); !ok {
		t.Fatalf("expected error type libkb.NoKeyError, got %T (%s)", err, err)
	}
}

func TestSaltpackEncryptLoggedOut(t *testing.T) {
	tc := SetupEngineTest(t, "SaltpackEncrypt")
	defer tc.Cleanup()

	trackUI := &FakeIdentifyUI{
		Proofs: make(map[string]string),
	}
	ctx := &Context{IdentifyUI: trackUI}

	sink := libkb.NewBufferCloser()
	arg := &SaltpackEncryptArg{
		Opts: keybase1.SaltpackEncryptOptions{
			Recipients: []string{"t_tracy+t_tracy@rooter", "t_george", "t_kb+gbrltest@twitter"},
		},
		Source: strings.NewReader("track and encrypt, track and encrypt"),
		Sink:   sink,
	}

	eng := NewSaltpackEncrypt(arg, tc.G)
	err := RunEngine(eng, ctx)
	if err != nil {
		t.Fatalf("Got unexpected error: %s", err)
	}
}

func TestSaltpackEncryptNoNaclOnlyPGP(t *testing.T) {
	tc := SetupEngineTest(t, "SaltpackEncrypt")
	defer tc.Cleanup()

	u2 := createFakeUserWithPGPOnly(t, tc)
	Logout(tc)
	u1 := CreateAndSignupFakeUser(tc, "nalcp")

	trackUI := &FakeIdentifyUI{
		Proofs: make(map[string]string),
	}
	ctx := &Context{
		IdentifyUI: trackUI,
		SecretUI:   u1.NewSecretUI(),
		SaltpackUI: &fakeSaltpackUI{},
	}

	msg := "this will never work"
	sink := libkb.NewBufferCloser()
	arg := &SaltpackEncryptArg{
		Opts: keybase1.SaltpackEncryptOptions{
			Recipients:    []string{u2.Username},
			NoSelfEncrypt: true,
		},
		Source: strings.NewReader(msg),
		Sink:   sink,
	}

	eng := NewSaltpackEncrypt(arg, tc.G)
	err := RunEngine(eng, ctx)
	if perr, ok := err.(libkb.NoNaClEncryptionKeyError); !ok {
		t.Fatalf("Got wrong error type: %T %v", err, err)
	} else if !perr.HasPGPKey {
		t.Fatalf("Should have a PGP key")
	} else if perr.User != u2.Username {
		t.Fatalf("Wrong username")
	}
}

func TestSaltpackEncryptNoSelf(t *testing.T) {
	tc := SetupEngineTest(t, "SaltpackEncrypt")
	defer tc.Cleanup()

	u1 := CreateAndSignupFakeUser(tc, "nalcp")
	u2 := CreateAndSignupFakeUser(tc, "nalcp")

	msg := "for your eyes only (not even mine!)"

	trackUI := &FakeIdentifyUI{
		Proofs: make(map[string]string),
	}
	ctx := &Context{
		IdentifyUI: trackUI,
		SecretUI:   u2.NewSecretUI(),
		SaltpackUI: &fakeSaltpackUI{},
	}

	sink := libkb.NewBufferCloser()
	arg := &SaltpackEncryptArg{
		Opts: keybase1.SaltpackEncryptOptions{
			Recipients:    []string{u1.Username},
			NoSelfEncrypt: true,
		},
		Source: strings.NewReader(msg),
		Sink:   sink,
	}

	eng := NewSaltpackEncrypt(arg, tc.G)
	if err := RunEngine(eng, ctx); err != nil {
		t.Fatal(err)
	}

	out := sink.Bytes()
	if len(out) == 0 {
		t.Fatal("no output")
	}

	// decrypt it
	decoded := libkb.NewBufferCloser()
	decarg := &SaltpackDecryptArg{
		Source: strings.NewReader(string(out)),
		Sink:   decoded,
	}
	dec := NewSaltpackDecrypt(decarg, tc.G)
	err := RunEngine(dec, ctx)
	if _, ok := err.(libkb.NoDecryptionKeyError); !ok {
		t.Fatalf("Expected err type %T, but got %T", libkb.NoDecryptionKeyError{}, err)
	}

	Logout(tc)
	u1.Login(tc.G)

	ctx.SecretUI = u1.NewSecretUI()
	decarg.Source = strings.NewReader(string(out))
	dec = NewSaltpackDecrypt(decarg, tc.G)
	err = RunEngine(dec, ctx)
	if err != nil {
		t.Fatal(err)
	}
	decmsg := decoded.String()
	if decmsg != msg {
		t.Errorf("decoded: %s, expected: %s", decmsg, msg)
	}
}

func TestSaltpackEncryptBinary(t *testing.T) {
	tc := SetupEngineTest(t, "SaltpackEncryptBinary")
	defer tc.Cleanup()
	fu := CreateAndSignupFakeUser(tc, "enc")

	// encrypt a message
	msg := "10 days in Japan"
	sink := libkb.NewBufferCloser()
	ctx := &Context{
		IdentifyUI: &FakeIdentifyUI{},
		SecretUI:   fu.NewSecretUI(),
		LogUI:      tc.G.UI.GetLogUI(),
		SaltpackUI: &fakeSaltpackUI{},
	}
	// Should encrypt for self, too.
	arg := &SaltpackEncryptArg{
		Source: strings.NewReader(msg),
		Sink:   sink,
		Opts: keybase1.SaltpackEncryptOptions{
			Binary: true,
		},
	}
	enc := NewSaltpackEncrypt(arg, tc.G)
	if err := RunEngine(enc, ctx); err != nil {
		t.Fatal(err)
	}
	out := sink.String()

	// decrypt it
	decoded := libkb.NewBufferCloser()
	decarg := &SaltpackDecryptArg{
		Source: strings.NewReader(out),
		Sink:   decoded,
	}
	dec := NewSaltpackDecrypt(decarg, tc.G)
	if err := RunEngine(dec, ctx); err != nil {
		t.Fatal(err)
	}
	decmsg := decoded.String()
	if decmsg != msg {
		t.Errorf("decoded: %s, expected: %s", decmsg, msg)
	}
}
<commit_msg>Add saltpack anonymous encrypt unit test<commit_after>// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.

package engine

import (
	"strings"
	"testing"

	"github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/go/protocol"
	"github.com/keybase/client/go/saltpack"
	"github.com/ugorji/go/codec"
)

func TestSaltpackEncrypt(t *testing.T) {
	tc := SetupEngineTest(t, "SaltpackEncrypt")
	defer tc.Cleanup()

	u1 := CreateAndSignupFakeUser(tc, "nalcp")
	u2 := CreateAndSignupFakeUser(tc, "nalcp")
	u3 := CreateAndSignupFakeUser(tc, "nalcp")

	trackUI := &FakeIdentifyUI{
		Proofs: make(map[string]string),
	}
	ctx := &Context{IdentifyUI: trackUI, SecretUI: u3.NewSecretUI()}

	run := func(Recips []string) {
		sink := libkb.NewBufferCloser()
		arg := &SaltpackEncryptArg{
			Opts:   keybase1.SaltpackEncryptOptions{Recipients: Recips},
			Source: strings.NewReader("id2 and encrypt, id2 and encrypt"),
			Sink:   sink,
		}

		eng := NewSaltpackEncrypt(arg, tc.G)
		if err := RunEngine(eng, ctx); err != nil {
			t.Fatal(err)
		}

		out := sink.Bytes()
		if len(out) == 0 {
			t.Fatal("no output")
		}
	}
	run([]string{u1.Username, u2.Username})

	// If we add ourselves, we should be smart and not error out
	// (We are u3 in this case)
	run([]string{u1.Username, u2.Username, u3.Username})
}

type receiverKeys struct {
	_struct       bool   `codec:",toarray"`
	ReceiverKID   []byte `codec:"receiver_key_id"`
	PayloadKeyBox []byte `codec:"payloadkey"`
}

type encryptionHeader struct {
	_struct         bool                 `codec:",toarray"`
	FormatName      string               `codec:"format_name"`
	Version         saltpack.Version     `codec:"vers"`
	Type            saltpack.MessageType `codec:"type"`
	Ephemeral       []byte               `codec:"ephemeral"`
	SenderSecretbox []byte               `codec:"sendersecretbox"`
	Receivers       []receiverKeys       `codec:"rcvrs,omitempty"`
	seqno           uint64
}

func TestSaltpackAnonymousEncrypt(t *testing.T) {
	tc := SetupEngineTest(t, "SaltpackEncrypt")
	defer tc.Cleanup()

	u1 := CreateAndSignupFakeUser(tc, "nalcp")
	u2 := CreateAndSignupFakeUser(tc, "nalcp")
	u3 := CreateAndSignupFakeUser(tc, "nalcp")

	trackUI := &FakeIdentifyUI{
		Proofs: make(map[string]string),
	}
	ctx := &Context{IdentifyUI: trackUI, SecretUI: u3.NewSecretUI()}

	run := func(Recips []string) {
		sink := libkb.NewBufferCloser()
		arg := &SaltpackEncryptArg{
			Opts:   keybase1.SaltpackEncryptOptions{Recipients: Recips, Anonymous: true},
			Source: strings.NewReader("id2 and encrypt, id2 and encrypt"),
			Sink:   sink,
		}

		eng := NewSaltpackEncrypt(arg, tc.G)
		if err := RunEngine(eng, ctx); err != nil {
			t.Fatal(err)
		}

		out := sink.Bytes()
		if len(out) == 0 {
			t.Fatal("no output")
		}

		var header encryptionHeader
		dec := codec.NewDecoderBytes(out, &codec.MsgpackHandle{WriteExt: true})
		if err := dec.Decode(&header); err != nil {
			t.Fatal(err)
		}

		if len(header.Receivers) > 0 {
			t.Fatal("receivers included in anonymous saltpack header")
		}

	}
	run([]string{u1.Username, u2.Username})

	// If we add ourselves, we should be smart and not error out
	// (We are u3 in this case)
	run([]string{u1.Username, u2.Username, u3.Username})
}

func TestSaltpackEncryptSelfNoKey(t *testing.T) {
	tc := SetupEngineTest(t, "SaltpackEncrypt")
	defer tc.Cleanup()

	_, passphrase := createFakeUserWithNoKeys(tc)
	trackUI := &FakeIdentifyUI{
		Proofs: make(map[string]string),
	}
	ctx := &Context{IdentifyUI: trackUI, SecretUI: &libkb.TestSecretUI{Passphrase: passphrase}}

	sink := libkb.NewBufferCloser()
	arg := &SaltpackEncryptArg{
		Opts: keybase1.SaltpackEncryptOptions{
			Recipients: []string{"t_tracy+t_tracy@rooter", "t_george", "t_kb+gbrltest@twitter"},
		},
		Source: strings.NewReader("track and encrypt, track and encrypt"),
		Sink:   sink,
	}

	eng := NewSaltpackEncrypt(arg, tc.G)
	err := RunEngine(eng, ctx)
	if _, ok := err.(libkb.NoKeyError); !ok {
		t.Fatalf("expected error type libkb.NoKeyError, got %T (%s)", err, err)
	}
}

func TestSaltpackEncryptLoggedOut(t *testing.T) {
	tc := SetupEngineTest(t, "SaltpackEncrypt")
	defer tc.Cleanup()

	trackUI := &FakeIdentifyUI{
		Proofs: make(map[string]string),
	}
	ctx := &Context{IdentifyUI: trackUI}

	sink := libkb.NewBufferCloser()
	arg := &SaltpackEncryptArg{
		Opts: keybase1.SaltpackEncryptOptions{
			Recipients: []string{"t_tracy+t_tracy@rooter", "t_george", "t_kb+gbrltest@twitter"},
		},
		Source: strings.NewReader("track and encrypt, track and encrypt"),
		Sink:   sink,
	}

	eng := NewSaltpackEncrypt(arg, tc.G)
	err := RunEngine(eng, ctx)
	if err != nil {
		t.Fatalf("Got unexpected error: %s", err)
	}
}

func TestSaltpackEncryptNoNaclOnlyPGP(t *testing.T) {
	tc := SetupEngineTest(t, "SaltpackEncrypt")
	defer tc.Cleanup()

	u2 := createFakeUserWithPGPOnly(t, tc)
	Logout(tc)
	u1 := CreateAndSignupFakeUser(tc, "nalcp")

	trackUI := &FakeIdentifyUI{
		Proofs: make(map[string]string),
	}
	ctx := &Context{
		IdentifyUI: trackUI,
		SecretUI:   u1.NewSecretUI(),
		SaltpackUI: &fakeSaltpackUI{},
	}

	msg := "this will never work"
	sink := libkb.NewBufferCloser()
	arg := &SaltpackEncryptArg{
		Opts: keybase1.SaltpackEncryptOptions{
			Recipients:    []string{u2.Username},
			NoSelfEncrypt: true,
		},
		Source: strings.NewReader(msg),
		Sink:   sink,
	}

	eng := NewSaltpackEncrypt(arg, tc.G)
	err := RunEngine(eng, ctx)
	if perr, ok := err.(libkb.NoNaClEncryptionKeyError); !ok {
		t.Fatalf("Got wrong error type: %T %v", err, err)
	} else if !perr.HasPGPKey {
		t.Fatalf("Should have a PGP key")
	} else if perr.User != u2.Username {
		t.Fatalf("Wrong username")
	}
}

func TestSaltpackEncryptNoSelf(t *testing.T) {
	tc := SetupEngineTest(t, "SaltpackEncrypt")
	defer tc.Cleanup()

	u1 := CreateAndSignupFakeUser(tc, "nalcp")
	u2 := CreateAndSignupFakeUser(tc, "nalcp")

	msg := "for your eyes only (not even mine!)"

	trackUI := &FakeIdentifyUI{
		Proofs: make(map[string]string),
	}
	ctx := &Context{
		IdentifyUI: trackUI,
		SecretUI:   u2.NewSecretUI(),
		SaltpackUI: &fakeSaltpackUI{},
	}

	sink := libkb.NewBufferCloser()
	arg := &SaltpackEncryptArg{
		Opts: keybase1.SaltpackEncryptOptions{
			Recipients:    []string{u1.Username},
			NoSelfEncrypt: true,
		},
		Source: strings.NewReader(msg),
		Sink:   sink,
	}

	eng := NewSaltpackEncrypt(arg, tc.G)
	if err := RunEngine(eng, ctx); err != nil {
		t.Fatal(err)
	}

	out := sink.Bytes()
	if len(out) == 0 {
		t.Fatal("no output")
	}

	// decrypt it
	decoded := libkb.NewBufferCloser()
	decarg := &SaltpackDecryptArg{
		Source: strings.NewReader(string(out)),
		Sink:   decoded,
	}
	dec := NewSaltpackDecrypt(decarg, tc.G)
	err := RunEngine(dec, ctx)
	if _, ok := err.(libkb.NoDecryptionKeyError); !ok {
		t.Fatalf("Expected err type %T, but got %T", libkb.NoDecryptionKeyError{}, err)
	}

	Logout(tc)
	u1.Login(tc.G)

	ctx.SecretUI = u1.NewSecretUI()
	decarg.Source = strings.NewReader(string(out))
	dec = NewSaltpackDecrypt(decarg, tc.G)
	err = RunEngine(dec, ctx)
	if err != nil {
		t.Fatal(err)
	}
	decmsg := decoded.String()
	if decmsg != msg {
		t.Errorf("decoded: %s, expected: %s", decmsg, msg)
	}
}

func TestSaltpackEncryptBinary(t *testing.T) {
	tc := SetupEngineTest(t, "SaltpackEncryptBinary")
	defer tc.Cleanup()
	fu := CreateAndSignupFakeUser(tc, "enc")

	// encrypt a message
	msg := "10 days in Japan"
	sink := libkb.NewBufferCloser()
	ctx := &Context{
		IdentifyUI: &FakeIdentifyUI{},
		SecretUI:   fu.NewSecretUI(),
		LogUI:      tc.G.UI.GetLogUI(),
		SaltpackUI: &fakeSaltpackUI{},
	}
	// Should encrypt for self, too.
	arg := &SaltpackEncryptArg{
		Source: strings.NewReader(msg),
		Sink:   sink,
		Opts: keybase1.SaltpackEncryptOptions{
			Binary: true,
		},
	}
	enc := NewSaltpackEncrypt(arg, tc.G)
	if err := RunEngine(enc, ctx); err != nil {
		t.Fatal(err)
	}
	out := sink.String()

	// decrypt it
	decoded := libkb.NewBufferCloser()
	decarg := &SaltpackDecryptArg{
		Source: strings.NewReader(out),
		Sink:   decoded,
	}
	dec := NewSaltpackDecrypt(decarg, tc.G)
	if err := RunEngine(dec, ctx); err != nil {
		t.Fatal(err)
	}
	decmsg := decoded.String()
	if decmsg != msg {
		t.Errorf("decoded: %s, expected: %s", decmsg, msg)
	}
}
<|endoftext|>


<commit_before>package mappers_test

import (
	"testing"

	"github.com/apoydence/loggrebutterfly/analyst/internal/algorithms/mappers"
	loggregator "github.com/apoydence/loggrebutterfly/api/loggregator/v2"
	v1 "github.com/apoydence/loggrebutterfly/api/v1"
	"github.com/apoydence/onpar"
	. "github.com/apoydence/onpar/expect"
	. "github.com/apoydence/onpar/matchers"
)

type TF struct {
	*testing.T
	tr mappers.Filter
}

func TestFilter(t *testing.T) {
	t.Parallel()
	o := onpar.New()
	defer o.Run(t)

	o.Group("timerange", func() {
		o.BeforeEach(func(t *testing.T) TF {
			req := &v1.QueryInfo{
				Filter: &v1.AnalystFilter{
					SourceId: "some-id",
					TimeRange: &v1.TimeRange{
						Start: 99,
						End:   101,
					},
				},
			}

			f, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
			Expect(t, err == nil).To(BeTrue())

			return TF{
				T:  t,
				tr: f,
			}
		})

		o.Spec("it only returns envelopes that have the correct source ID", func(t TF) {
			e1 := &loggregator.Envelope{SourceId: "wrong"}
			e2 := &loggregator.Envelope{SourceId: "some-id", Timestamp: 99}

			keep := t.tr.Filter(e1)
			Expect(t, keep).To(BeFalse())

			keep = t.tr.Filter(e2)
			Expect(t, keep).To(BeTrue())
		})

		o.Spec("it filters out envelopes that are outside the time range", func(t TF) {
			e1 := &loggregator.Envelope{SourceId: "some-id", Timestamp: 98}
			e2 := &loggregator.Envelope{SourceId: "some-id", Timestamp: 99}
			e3 := &loggregator.Envelope{SourceId: "some-id", Timestamp: 100}
			e4 := &loggregator.Envelope{SourceId: "some-id", Timestamp: 101}

			keep := t.tr.Filter(e1)
			Expect(t, keep).To(BeFalse())

			keep = t.tr.Filter(e2)
			Expect(t, keep).To(BeTrue())

			keep = t.tr.Filter(e3)
			Expect(t, keep).To(BeTrue())

			keep = t.tr.Filter(e4)
			Expect(t, keep).To(BeFalse())
		})
	})

	o.Group("LogFilter", func() {
		o.Group("Empty payload", func() {
			o.BeforeEach(func(t *testing.T) TF {
				req := &v1.QueryInfo{
					Filter: &v1.AnalystFilter{
						SourceId: "some-id",
						Envelopes: &v1.AnalystFilter_Log{
							Log: &v1.LogFilter{},
						},
						TimeRange: &v1.TimeRange{
							Start: 1,
							End:   9223372036854775807,
						},
					},
				}

				f, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
				Expect(t, err == nil).To(BeTrue())

				return TF{
					T:  t,
					tr: f,
				}
			})

			o.Spec("it filters out envelopes that are not logs", func(t TF) {
				e1 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Counter{
						Counter: &loggregator.Counter{
							Name: "some-name",
						},
					},
				}

				e2 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Log{
						Log: &loggregator.Log{
							Payload: []byte("some-value"),
						},
					},
				}

				keep := t.tr.Filter(e1)
				Expect(t, keep).To(BeFalse())

				keep = t.tr.Filter(e2)
				Expect(t, keep).To(BeTrue())
			})
		})

		o.Group("Match", func() {
			o.BeforeEach(func(t *testing.T) TF {
				req := &v1.QueryInfo{
					Filter: &v1.AnalystFilter{
						SourceId: "some-id",
						Envelopes: &v1.AnalystFilter_Log{
							Log: &v1.LogFilter{
								Payload: &v1.LogFilter_Match{
									Match: []byte("some-value"),
								},
							},
						},
					},
				}

				f, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
				Expect(t, err == nil).To(BeTrue())

				return TF{
					T:  t,
					tr: f,
				}
			})

			o.Spec("it filters out envelopes that are not logs", func(t TF) {
				e1 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Counter{
						Counter: &loggregator.Counter{
							Name: "some-name",
						},
					},
				}

				e2 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Log{
						Log: &loggregator.Log{
							Payload: []byte("some-value"),
						},
					},
				}

				keep := t.tr.Filter(e1)
				Expect(t, keep).To(BeFalse())

				keep = t.tr.Filter(e2)
				Expect(t, keep).To(BeTrue())
			})

			o.Spec("it filters out envelopes that don't have the exact payload", func(t TF) {
				e1 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Log{
						Log: &loggregator.Log{
							Payload: []byte("wrong-value"),
						},
					},
				}

				e2 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Log{
						Log: &loggregator.Log{
							Payload: []byte("some-value"),
						},
					},
				}

				keep := t.tr.Filter(e1)
				Expect(t, keep).To(BeFalse())

				keep = t.tr.Filter(e2)
				Expect(t, keep).To(BeTrue())
			})
		})

		o.Group("Regexp", func() {
			o.BeforeEach(func(t *testing.T) TF {
				req := &v1.QueryInfo{
					Filter: &v1.AnalystFilter{
						SourceId: "some-id",
						Envelopes: &v1.AnalystFilter_Log{
							Log: &v1.LogFilter{
								Payload: &v1.LogFilter_Regexp{
									Regexp: "^[sS]ome-value",
								},
							},
						},
					},
				}

				f, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
				Expect(t, err == nil).To(BeTrue())

				return TF{
					T:  t,
					tr: f,
				}
			})

			o.Spec("it returns an error for an invalid regexp pattern", func(t TF) {
				req := &v1.QueryInfo{
					Filter: &v1.AnalystFilter{
						SourceId: "some-id",
						Envelopes: &v1.AnalystFilter_Log{
							Log: &v1.LogFilter{
								Payload: &v1.LogFilter_Regexp{
									Regexp: "[",
								},
							},
						},
					},
				}

				_, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
				Expect(t, err == nil).To(BeFalse())
			})

			o.Spec("it filters out envelopes that are not logs", func(t TF) {
				e1 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Counter{
						Counter: &loggregator.Counter{
							Name: "some-name",
						},
					},
				}

				e2 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Log{
						Log: &loggregator.Log{
							Payload: []byte("some-value"),
						},
					},
				}

				keep := t.tr.Filter(e1)
				Expect(t, keep).To(BeFalse())

				keep = t.tr.Filter(e2)
				Expect(t, keep).To(BeTrue())
			})

			o.Spec("it filters out envelopes that don't have the exact payload", func(t TF) {
				e1 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Log{
						Log: &loggregator.Log{
							Payload: []byte("wrong-some-value"),
						},
					},
				}

				e2 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Log{
						Log: &loggregator.Log{
							Payload: []byte("some-value-thats-good"),
						},
					},
				}

				keep := t.tr.Filter(e1)
				Expect(t, keep).To(BeFalse())

				keep = t.tr.Filter(e2)
				Expect(t, keep).To(BeTrue())
			})
		})
	})

	o.Group("CounterFilter", func() {
		o.Group("empty name", func() {
			o.BeforeEach(func(t *testing.T) TF {
				req := &v1.QueryInfo{
					Filter: &v1.AnalystFilter{
						SourceId: "some-id",
						Envelopes: &v1.AnalystFilter_Counter{
							Counter: &v1.CounterFilter{},
						},
					},
				}

				f, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
				Expect(t, err == nil).To(BeTrue())

				return TF{
					T:  t,
					tr: f,
				}
			})

			o.Spec("it filters out envelopes that are not counters", func(t TF) {
				e1 := &loggregator.Envelope{SourceId: "some-id", Timestamp: 98}
				e2 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Counter{
						Counter: &loggregator.Counter{
							Name: "some-name",
						},
					},
				}

				keep := t.tr.Filter(e1)
				Expect(t, keep).To(BeFalse())

				keep = t.tr.Filter(e2)
				Expect(t, keep).To(BeTrue())
			})
		})

		o.Group("non-empty name", func() {
			o.BeforeEach(func(t *testing.T) TF {
				req := &v1.QueryInfo{
					Filter: &v1.AnalystFilter{
						SourceId: "some-id",
						Envelopes: &v1.AnalystFilter_Counter{
							Counter: &v1.CounterFilter{
								Name: "some-name",
							},
						},
					},
				}

				f, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
				Expect(t, err == nil).To(BeTrue())

				return TF{
					T:  t,
					tr: f,
				}
			})

			o.Spec("it filters out envelopes that are not the right name", func(t TF) {
				e1 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 97,
					Message: &loggregator.Envelope_Counter{
						Counter: &loggregator.Counter{
							Name: "wrong-name",
						},
					},
				}
				e2 := &loggregator.Envelope{
					SourceId:  "some-id",
					Timestamp: 98,
					Message: &loggregator.Envelope_Counter{
						Counter: &loggregator.Counter{
							Name: "some-name",
						},
					},
				}

				keep := t.tr.Filter(e1)
				Expect(t, keep).To(BeFalse())

				keep = t.tr.Filter(e2)
				Expect(t, keep).To(BeTrue())
			})
		})
	})
}
<commit_msg>Move different filter tests to their own func<commit_after>package mappers_test

import (
	"testing"

	"github.com/apoydence/loggrebutterfly/analyst/internal/algorithms/mappers"
	loggregator "github.com/apoydence/loggrebutterfly/api/loggregator/v2"
	v1 "github.com/apoydence/loggrebutterfly/api/v1"
	"github.com/apoydence/onpar"
	. "github.com/apoydence/onpar/expect"
	. "github.com/apoydence/onpar/matchers"
)

type TF struct {
	*testing.T
	tr mappers.Filter
}

func TestFilterTimerange(t *testing.T) {
	t.Parallel()
	o := onpar.New()
	defer o.Run(t)

	o.BeforeEach(func(t *testing.T) TF {
		req := &v1.QueryInfo{
			Filter: &v1.AnalystFilter{
				SourceId: "some-id",
				TimeRange: &v1.TimeRange{
					Start: 99,
					End:   101,
				},
			},
		}

		f, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
		Expect(t, err == nil).To(BeTrue())

		return TF{
			T:  t,
			tr: f,
		}
	})

	o.Spec("it only returns envelopes that have the correct source ID", func(t TF) {
		e1 := &loggregator.Envelope{SourceId: "wrong"}
		e2 := &loggregator.Envelope{SourceId: "some-id", Timestamp: 99}

		keep := t.tr.Filter(e1)
		Expect(t, keep).To(BeFalse())

		keep = t.tr.Filter(e2)
		Expect(t, keep).To(BeTrue())
	})

	o.Spec("it filters out envelopes that are outside the time range", func(t TF) {
		e1 := &loggregator.Envelope{SourceId: "some-id", Timestamp: 98}
		e2 := &loggregator.Envelope{SourceId: "some-id", Timestamp: 99}
		e3 := &loggregator.Envelope{SourceId: "some-id", Timestamp: 100}
		e4 := &loggregator.Envelope{SourceId: "some-id", Timestamp: 101}

		keep := t.tr.Filter(e1)
		Expect(t, keep).To(BeFalse())

		keep = t.tr.Filter(e2)
		Expect(t, keep).To(BeTrue())

		keep = t.tr.Filter(e3)
		Expect(t, keep).To(BeTrue())

		keep = t.tr.Filter(e4)
		Expect(t, keep).To(BeFalse())
	})
}

func TestFilterLogFilter(t *testing.T) {
	t.Parallel()
	o := onpar.New()
	defer o.Run(t)

	o.Group("Empty payload", func() {
		o.BeforeEach(func(t *testing.T) TF {
			req := &v1.QueryInfo{
				Filter: &v1.AnalystFilter{
					SourceId: "some-id",
					Envelopes: &v1.AnalystFilter_Log{
						Log: &v1.LogFilter{},
					},
					TimeRange: &v1.TimeRange{
						Start: 1,
						End:   9223372036854775807,
					},
				},
			}

			f, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
			Expect(t, err == nil).To(BeTrue())

			return TF{
				T:  t,
				tr: f,
			}
		})

		o.Spec("it filters out envelopes that are not logs", func(t TF) {
			e1 := &loggregator.Envelope{
				SourceId:  "some-id",
				Timestamp: 98,
				Message: &loggregator.Envelope_Counter{
					Counter: &loggregator.Counter{
						Name: "some-name",
					},
				},
			}

			e2 := &loggregator.Envelope{
				SourceId:  "some-id",
				Timestamp: 98,
				Message: &loggregator.Envelope_Log{
					Log: &loggregator.Log{
						Payload: []byte("some-value"),
					},
				},
			}

			keep := t.tr.Filter(e1)
			Expect(t, keep).To(BeFalse())

			keep = t.tr.Filter(e2)
			Expect(t, keep).To(BeTrue())
		})
	})

	o.Group("Match", func() {
		o.BeforeEach(func(t *testing.T) TF {
			req := &v1.QueryInfo{
				Filter: &v1.AnalystFilter{
					SourceId: "some-id",
					Envelopes: &v1.AnalystFilter_Log{
						Log: &v1.LogFilter{
							Payload: &v1.LogFilter_Match{
								Match: []byte("some-value"),
							},
						},
					},
				},
			}

			f, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
			Expect(t, err == nil).To(BeTrue())

			return TF{
				T:  t,
				tr: f,
			}
		})

		o.Spec("it filters out envelopes that are not logs", func(t TF) {
			e1 := &loggregator.Envelope{
				SourceId:  "some-id",
				Timestamp: 98,
				Message: &loggregator.Envelope_Counter{
					Counter: &loggregator.Counter{
						Name: "some-name",
					},
				},
			}

			e2 := &loggregator.Envelope{
				SourceId:  "some-id",
				Timestamp: 98,
				Message: &loggregator.Envelope_Log{
					Log: &loggregator.Log{
						Payload: []byte("some-value"),
					},
				},
			}

			keep := t.tr.Filter(e1)
			Expect(t, keep).To(BeFalse())

			keep = t.tr.Filter(e2)
			Expect(t, keep).To(BeTrue())
		})

		o.Spec("it filters out envelopes that don't have the exact payload", func(t TF) {
			e1 := &loggregator.Envelope{
				SourceId:  "some-id",
				Timestamp: 98,
				Message: &loggregator.Envelope_Log{
					Log: &loggregator.Log{
						Payload: []byte("wrong-value"),
					},
				},
			}

			e2 := &loggregator.Envelope{
				SourceId:  "some-id",
				Timestamp: 98,
				Message: &loggregator.Envelope_Log{
					Log: &loggregator.Log{
						Payload: []byte("some-value"),
					},
				},
			}

			keep := t.tr.Filter(e1)
			Expect(t, keep).To(BeFalse())

			keep = t.tr.Filter(e2)
			Expect(t, keep).To(BeTrue())
		})
	})

	o.Group("Regexp", func() {
		o.BeforeEach(func(t *testing.T) TF {
			req := &v1.QueryInfo{
				Filter: &v1.AnalystFilter{
					SourceId: "some-id",
					Envelopes: &v1.AnalystFilter_Log{
						Log: &v1.LogFilter{
							Payload: &v1.LogFilter_Regexp{
								Regexp: "^[sS]ome-value",
							},
						},
					},
				},
			}

			f, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
			Expect(t, err == nil).To(BeTrue())

			return TF{
				T:  t,
				tr: f,
			}
		})

		o.Spec("it returns an error for an invalid regexp pattern", func(t TF) {
			req := &v1.QueryInfo{
				Filter: &v1.AnalystFilter{
					SourceId: "some-id",
					Envelopes: &v1.AnalystFilter_Log{
						Log: &v1.LogFilter{
							Payload: &v1.LogFilter_Regexp{
								Regexp: "[",
							},
						},
					},
				},
			}

			_, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
			Expect(t, err == nil).To(BeFalse())
		})

		o.Spec("it filters out envelopes that are not logs", func(t TF) {
			e1 := &loggregator.Envelope{
				SourceId:  "some-id",
				Timestamp: 98,
				Message: &loggregator.Envelope_Counter{
					Counter: &loggregator.Counter{
						Name: "some-name",
					},
				},
			}

			e2 := &loggregator.Envelope{
				SourceId:  "some-id",
				Timestamp: 98,
				Message: &loggregator.Envelope_Log{
					Log: &loggregator.Log{
						Payload: []byte("some-value"),
					},
				},
			}

			keep := t.tr.Filter(e1)
			Expect(t, keep).To(BeFalse())

			keep = t.tr.Filter(e2)
			Expect(t, keep).To(BeTrue())
		})

		o.Spec("it filters out envelopes that do not match the regexp", func(t TF) {
			e1 := &loggregator.Envelope{
				SourceId:  "some-id",
				Timestamp: 98,
				Message: &loggregator.Envelope_Log{
					Log: &loggregator.Log{
						Payload: []byte("wrong-some-value"),
					},
				},
			}

			e2 := &loggregator.Envelope{
				SourceId:  "some-id",
				Timestamp: 98,
				Message: &loggregator.Envelope_Log{
					Log: &loggregator.Log{
						Payload: []byte("some-value-thats-good"),
					},
				},
			}

			keep := t.tr.Filter(e1)
			Expect(t, keep).To(BeFalse())

			keep = t.tr.Filter(e2)
			Expect(t, keep).To(BeTrue())
		})
	})
}

func TestFilterCounter(t *testing.T) {
	t.Parallel()
	o := onpar.New()
	defer o.Run(t)

	o.Group("empty name", func() {
		o.BeforeEach(func(t *testing.T) TF {
			req := &v1.QueryInfo{
				Filter: &v1.AnalystFilter{
					SourceId: "some-id",
					Envelopes: &v1.AnalystFilter_Counter{
						Counter: &v1.CounterFilter{},
					},
				},
			}

			f, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
			Expect(t, err == nil).To(BeTrue())

			return TF{
				T:  t,
				tr: f,
			}
		})

		o.Spec("it filters out envelopes that are not counters", func(t TF) {
			e1 := &loggregator.Envelope{SourceId: "some-id", Timestamp: 98}
			e2 := &loggregator.Envelope{
				SourceId:  "some-id",
				Timestamp: 98,
				Message: &loggregator.Envelope_Counter{
					Counter: &loggregator.Counter{
						Name: "some-name",
					},
				},
			}

			keep := t.tr.Filter(e1)
			Expect(t, keep).To(BeFalse())

			keep = t.tr.Filter(e2)
			Expect(t, keep).To(BeTrue())
		})
	})

	o.Group("non-empty name", func() {
		o.BeforeEach(func(t *testing.T) TF {
			req := &v1.QueryInfo{
				Filter: &v1.AnalystFilter{
					SourceId: "some-id",
					Envelopes: &v1.AnalystFilter_Counter{
						Counter: &v1.CounterFilter{
							Name: "some-name",
						},
					},
				},
			}

			f, err := mappers.NewFilter(&v1.AggregateInfo{Query: req})
			Expect(t, err == nil).To(BeTrue())

			return TF{
				T:  t,
				tr: f,
			}
		})

		o.Spec("it filters out envelopes that are not the right name", func(t TF) {
			e1 := &loggregator.Envelope{
				SourceId:  "some-id",
				Timestamp: 97,
				Message: &loggregator.Envelope_Counter{
					Counter: &loggregator.Counter{
						Name: "wrong-name",
					},
				},
			}
			e2 := &loggregator.Envelope{
				SourceId:  "some-id",
				Timestamp: 98,
				Message: &loggregator.Envelope_Counter{
					Counter: &loggregator.Counter{
						Name: "some-name",
					},
				},
			}

			keep := t.tr.Filter(e1)
			Expect(t, keep).To(BeFalse())

			keep = t.tr.Filter(e2)
			Expect(t, keep).To(BeTrue())
		})
	})
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"net/url"
	"os"
	"os/signal"
	"syscall"
	"time"

	"honnef.co/go/uzbl/adblock"
	"honnef.co/go/uzbl/event_manager"
)

type blocker struct {
	ab        *adblock.Adblock
	c         net.Conn
	num       int
	curDomain string
}

var (
	fSocket         string
	fCache          int
	fUserStylesheet string
	fAdStylesheet   string
)

func main() {
	flag.Usage = func() {
		fmt.Fprintln(os.Stderr,
			`This program provides a standalone, efficient and feature-rich
adblocker for uzbl-based browsers. It supports the Adblock Plus
filter rules, including element hiding rules.

Adblock listens on a socket for ADBLOCK requests, filters them
and sends back either the original URI or about:blank.
Additionally, it will install a user stylesheet that includes
element hiding rules for the current domain.

For this to work, an instance of adblock needs to be started
before uzbl starts, so that uzbl can connect to its socket.

Adblock uses uzbl's request_handler to filter requests. In order
to use adblock, add the following line to your config:

    set request_handler request ADBLOCK

Additionally, you need to tell uzbl to connect to the adblock socket, e.g. via

    uzbl-core --connect-socket=/tmp/adblock_socket

Since webkit1 only supports a single user stylesheet, and adblock
uses it for element hiding, adblock provides an option to read
and append a file to the generated stylesheet.`)
		fmt.Fprintf(os.Stderr, "\nUsage of %s:\n", os.Args[0])
		flag.PrintDefaults()
	}
	flag.StringVar(&fSocket, "socket", "", "The socket to create and listen on")
	flag.StringVar(&fUserStylesheet, "user-stylesheet", "", "Path to user stylesheet to append")
	flag.StringVar(&fAdStylesheet, "ad-stylesheet", "", "Path where to store temporary ad stylesheet")
	flag.IntVar(&fCache, "cache", 50000, "The number of filter calculations to cache")
	flag.Parse()

	if fSocket == "" {
		fmt.Fprintln(os.Stderr, "No socket given")
		flag.Usage()
		os.Exit(1)
	}

	ab := adblock.New(fCache)

	for _, path := range flag.Args() {
		f, err := os.Open(path)
		if err != nil {
			fmt.Fprintln(os.Stderr, "Could not open rule file:", err)
			f.Close()
			continue
		}
		ab.LoadRules(f)
		f.Close()
	}
	ab.Optimize()

	log.Printf("Loaded %d rules, %d element hiding rules, %d keywords, %d rules without keywords",
		ab.Stats.NumRules, ab.Stats.NumHides, len(ab.Rules)+len(ab.Exceptions), ab.Stats.BlankKeywords)

	addr, err := net.ResolveUnixAddr("unix", fSocket)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Could not parse socket address:", err)
		os.Exit(2)
	}

	l, err := net.ListenUnix("unix", addr)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Could not open socket:", err)
		os.Exit(3)
	}

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, os.Interrupt, os.Kill, syscall.SIGTERM)
	go func() {
		<-ch
		l.Close()
		os.Exit(0)
	}()

	for {
		c, err := l.Accept()
		if err != nil {
			fmt.Fprintln(os.Stderr, "Error in Accept():", err)
			os.Exit(4)
		}
		go runBlocker(&blocker{ab: ab, c: c})
	}
}

func runBlocker(b *blocker) {
	em := event_manager.New(b.c)
	em.AddHandler("REQUEST-ADBLOCK", b.evPolicyRequest)
	em.AddHandler("LOAD_COMMIT", b.evLoadCommit)
	em.Listen()
}

func (b *blocker) evPolicyRequest(ev *event_manager.Event) error {
	args := ev.ParseDetail(2)
	if len(args) != 2 {
		return fmt.Errorf("malformed POLICY_REQUEST")
	}

	uri := args[0]
	t1 := time.Now()
	_, matches := b.ab.Match(b.curDomain, uri)
	t2 := time.Now()
	log.Println("Took", t2.Sub(t1), "to filter")
	if matches {
		uri = "about:blank"
	}

	fmt.Fprintf(b.c, "REPLY-%s %s\n", ev.Cookie, uri)
	b.num++
	if b.num%20 == 0 {
		log.Println(b.ab.Stats)
	}
	return nil
}

func (b *blocker) evLoadCommit(ev *event_manager.Event) error {
	args := ev.ParseDetail(1)
	if len(args) != 1 {
		return fmt.Errorf("malformed NAVIGATION_STARTING")
	}
	u, err := url.Parse(args[0][1 : len(args[0])-1])
	if err != nil {
		return fmt.Errorf("error parsing host: %s", err)
	}
	log.Printf("old: %s, new: %s", b.curDomain, u.Host)
	if u.Host == b.curDomain {
		return nil
	}
	b.curDomain = u.Host

	if fAdStylesheet == "" {
		return nil
	}

	hides := b.ab.Hide(b.curDomain)
	log.Printf("%d hide rules", len(hides))
	f, err := os.Create(fAdStylesheet)
	if err != nil {
		return err
	}
	defer f.Close()
	_, err = hides.WriteStylesheet(f)
	if err != nil {
		return err
	}

	if fUserStylesheet != "" {
		f2, err := os.Open(fUserStylesheet)
		if err != nil {
			return err
		}
		defer f2.Close()
		io.Copy(f, f2)
	}

	fmt.Fprintln(b.c, "css clear")
	fmt.Fprintln(b.c, "css add file://"+fAdStylesheet)
	return nil
}
<commit_msg>adblock: improve usage message<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"net"
	"net/url"
	"os"
	"os/signal"
	"syscall"
	"time"

	"honnef.co/go/uzbl/adblock"
	"honnef.co/go/uzbl/event_manager"
)

type blocker struct {
	ab        *adblock.Adblock
	c         net.Conn
	num       int
	curDomain string
}

var (
	fSocket         string
	fCache          int
	fUserStylesheet string
	fAdStylesheet   string
)

func main() {
	flag.Usage = func() {
		fmt.Fprintln(os.Stderr,
			`This program provides a standalone, efficient and feature-rich
adblocker for uzbl-based browsers. It supports the Adblock Plus
filter rules, including element hiding rules.

Adblock listens on a socket for ADBLOCK requests, filters them
and sends back either the original URI or about:blank.
Additionally, it will install a user stylesheet that includes
element hiding rules for the current domain.

For this to work, an instance of adblock needs to be started
before uzbl starts, so that uzbl can connect to its socket.

Adblock uses uzbl's request_handler to filter requests. In order
to use adblock, add the following line to your config:

    set request_handler request ADBLOCK

Additionally, you need to tell uzbl to connect to the adblock socket, e.g. via

    uzbl-core --connect-socket=/tmp/adblock_socket

Since webkit1 only supports a single user stylesheet, and adblock
uses it for element hiding, adblock provides an option to read
and append a file to the generated stylesheet.`)
		fmt.Fprintf(os.Stderr, "\nUsage: %s [-cache cache-size] [-ad-stylesheet file] [-user-stylesheet file] "+
			"-socket socket rule files...\n", os.Args[0])
		flag.PrintDefaults()
	}
	flag.StringVar(&fSocket, "socket", "", "The socket to create and listen on")
	flag.StringVar(&fUserStylesheet, "user-stylesheet", "", "Path to user stylesheet to append")
	flag.StringVar(&fAdStylesheet, "ad-stylesheet", "", "Path where to store temporary ad stylesheet")
	flag.IntVar(&fCache, "cache", 50000, "The number of filter calculations to cache")
	flag.Parse()

	if fSocket == "" {
		fmt.Fprintln(os.Stderr, "No socket given")
		flag.Usage()
		os.Exit(1)
	}

	ab := adblock.New(fCache)

	for _, path := range flag.Args() {
		f, err := os.Open(path)
		if err != nil {
			fmt.Fprintln(os.Stderr, "Could not open rule file:", err)
			f.Close()
			continue
		}
		ab.LoadRules(f)
		f.Close()
	}
	ab.Optimize()

	log.Printf("Loaded %d rules, %d element hiding rules, %d keywords, %d rules without keywords",
		ab.Stats.NumRules, ab.Stats.NumHides, len(ab.Rules)+len(ab.Exceptions), ab.Stats.BlankKeywords)

	addr, err := net.ResolveUnixAddr("unix", fSocket)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Could not parse socket address:", err)
		os.Exit(2)
	}

	l, err := net.ListenUnix("unix", addr)
	if err != nil {
		fmt.Fprintln(os.Stderr, "Could not open socket:", err)
		os.Exit(3)
	}

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, os.Interrupt, os.Kill, syscall.SIGTERM)
	go func() {
		<-ch
		l.Close()
		os.Exit(0)
	}()

	for {
		c, err := l.Accept()
		if err != nil {
			fmt.Fprintln(os.Stderr, "Error in Accept():", err)
			os.Exit(4)
		}
		go runBlocker(&blocker{ab: ab, c: c})
	}
}

func runBlocker(b *blocker) {
	em := event_manager.New(b.c)
	em.AddHandler("REQUEST-ADBLOCK", b.evPolicyRequest)
	em.AddHandler("LOAD_COMMIT", b.evLoadCommit)
	em.Listen()
}

func (b *blocker) evPolicyRequest(ev *event_manager.Event) error {
	args := ev.ParseDetail(2)
	if len(args) != 2 {
		return fmt.Errorf("malformed POLICY_REQUEST")
	}

	uri := args[0]
	t1 := time.Now()
	_, matches := b.ab.Match(b.curDomain, uri)
	t2 := time.Now()
	log.Println("Took", t2.Sub(t1), "to filter")
	if matches {
		uri = "about:blank"
	}

	fmt.Fprintf(b.c, "REPLY-%s %s\n", ev.Cookie, uri)
	b.num++
	if b.num%20 == 0 {
		log.Println(b.ab.Stats)
	}
	return nil
}

func (b *blocker) evLoadCommit(ev *event_manager.Event) error {
	args := ev.ParseDetail(1)
	if len(args) != 1 {
		return fmt.Errorf("malformed NAVIGATION_STARTING")
	}
	u, err := url.Parse(args[0][1 : len(args[0])-1])
	if err != nil {
		return fmt.Errorf("error parsing host: %s", err)
	}
	log.Printf("old: %s, new: %s", b.curDomain, u.Host)
	if u.Host == b.curDomain {
		return nil
	}
	b.curDomain = u.Host

	if fAdStylesheet == "" {
		return nil
	}

	hides := b.ab.Hide(b.curDomain)
	log.Printf("%d hide rules", len(hides))
	f, err := os.Create(fAdStylesheet)
	if err != nil {
		return err
	}
	defer f.Close()
	_, err = hides.WriteStylesheet(f)
	if err != nil {
		return err
	}

	if fUserStylesheet != "" {
		f2, err := os.Open(fUserStylesheet)
		if err != nil {
			return err
		}
		defer f2.Close()
		io.Copy(f, f2)
	}

	fmt.Fprintln(b.c, "css clear")
	fmt.Fprintln(b.c, "css add file://"+fAdStylesheet)
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/gorilla/websocket"
	"github.com/pborman/uuid"
	log "gopkg.in/inconshreveable/log15.v2"

	"github.com/lxc/lxd/shared"
)

type eventsHandler struct {
}

func logContextMap(ctx []interface{}) map[string]string {
	var key string
	ctxMap := map[string]string{}

	for _, entry := range ctx {
		if key == "" {
			key = entry.(string)
		} else {
			ctxMap[key] = fmt.Sprintf("%s", entry)
			key = ""
		}
	}

	return ctxMap
}

func (h eventsHandler) Log(r *log.Record) error {
	eventSend("logging", shared.Jmap{
		"message": r.Msg,
		"level":   r.Lvl.String(),
		"context": logContextMap(r.Ctx)})
	return nil
}

var eventsLock sync.Mutex
var eventListeners map[string]*eventListener = make(map[string]*eventListener)

type eventListener struct {
	connection   *websocket.Conn
	messageTypes []string
	active       chan bool
	id           string
	msgLock      sync.Mutex
}

type eventsServe struct {
	req *http.Request
}

func (r *eventsServe) Render(w http.ResponseWriter) error {
	return eventsSocket(r.req, w)
}

func eventsSocket(r *http.Request, w http.ResponseWriter) error {
	listener := eventListener{}

	typeStr := r.FormValue("type")
	if typeStr == "" {
		typeStr = "logging,operation"
	}

	c, err := shared.WebsocketUpgrader.Upgrade(w, r, nil)
	if err != nil {
		return err
	}

	listener.active = make(chan bool, 1)
	listener.connection = c
	listener.id = uuid.NewRandom().String()
	listener.messageTypes = strings.Split(typeStr, ",")

	eventsLock.Lock()
	eventListeners[listener.id] = &listener
	eventsLock.Unlock()

	shared.Debugf("New events listener: %s", listener.id)

	<-listener.active

	return nil
}

func eventsGet(d *Daemon, r *http.Request) Response {
	return &eventsServe{r}
}

var eventsCmd = Command{name: "events", get: eventsGet}

func eventSend(eventType string, eventMessage interface{}) error {
	event := shared.Jmap{}
	event["type"] = eventType
	event["timestamp"] = time.Now()
	event["metadata"] = eventMessage

	body, err := json.Marshal(event)
	if err != nil {
		return err
	}

	eventsLock.Lock()
	listeners := eventListeners
	eventsLock.Unlock()

	for _, listener := range listeners {
		if !shared.StringInSlice(eventType, listener.messageTypes) {
			continue
		}

		go func(listener *eventListener, body []byte) {
			listener.msgLock.Lock()
			err = listener.connection.WriteMessage(websocket.TextMessage, body)
			listener.msgLock.Unlock()
			if err != nil {
				listener.connection.Close()
				listener.active <- false

				eventsLock.Lock()
				delete(eventListeners, listener.id)
				eventsLock.Unlock()

				shared.Debugf("Disconnected events listener: %s", listener.id)
			}
		}(listener, body)
	}

	return nil
}
<commit_msg>Better lock around event listeners<commit_after>package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/gorilla/websocket"
	"github.com/pborman/uuid"
	log "gopkg.in/inconshreveable/log15.v2"

	"github.com/lxc/lxd/shared"
)

type eventsHandler struct {
}

func logContextMap(ctx []interface{}) map[string]string {
	var key string
	ctxMap := map[string]string{}

	for _, entry := range ctx {
		if key == "" {
			key = entry.(string)
		} else {
			ctxMap[key] = fmt.Sprintf("%s", entry)
			key = ""
		}
	}

	return ctxMap
}

func (h eventsHandler) Log(r *log.Record) error {
	eventSend("logging", shared.Jmap{
		"message": r.Msg,
		"level":   r.Lvl.String(),
		"context": logContextMap(r.Ctx)})
	return nil
}

var eventsLock sync.Mutex
var eventListeners map[string]*eventListener = make(map[string]*eventListener)

type eventListener struct {
	connection   *websocket.Conn
	messageTypes []string
	active       chan bool
	id           string
	msgLock      sync.Mutex
	wgUsed       sync.WaitGroup
}

type eventsServe struct {
	req *http.Request
}

func (r *eventsServe) Render(w http.ResponseWriter) error {
	return eventsSocket(r.req, w)
}

func eventsSocket(r *http.Request, w http.ResponseWriter) error {
	listener := eventListener{}

	typeStr := r.FormValue("type")
	if typeStr == "" {
		typeStr = "logging,operation"
	}

	c, err := shared.WebsocketUpgrader.Upgrade(w, r, nil)
	if err != nil {
		return err
	}

	listener.active = make(chan bool, 1)
	listener.connection = c
	listener.id = uuid.NewRandom().String()
	listener.messageTypes = strings.Split(typeStr, ",")

	eventsLock.Lock()
	eventListeners[listener.id] = &listener
	eventsLock.Unlock()

	shared.Debugf("New events listener: %s", listener.id)

	<-listener.active

	return nil
}

func eventsGet(d *Daemon, r *http.Request) Response {
	return &eventsServe{r}
}

var eventsCmd = Command{name: "events", get: eventsGet}

func eventSend(eventType string, eventMessage interface{}) error {
	event := shared.Jmap{}
	event["type"] = eventType
	event["timestamp"] = time.Now()
	event["metadata"] = eventMessage

	body, err := json.Marshal(event)
	if err != nil {
		return err
	}

	eventsLock.Lock()
	listeners := eventListeners
	for _, listener := range listeners {
		if !shared.StringInSlice(eventType, listener.messageTypes) {
			continue
		}

		listener.wgUsed.Add(1)
		go func(listener *eventListener, body []byte) {
			listener.msgLock.Lock()
			err = listener.connection.WriteMessage(websocket.TextMessage, body)
			listener.msgLock.Unlock()
			listener.wgUsed.Done()

			if err != nil {
				listener.wgUsed.Wait()
				listener.connection.Close()
				listener.active <- false

				eventsLock.Lock()
				delete(eventListeners, listener.id)
				eventsLock.Unlock()

				shared.Debugf("Disconnected events listener: %s", listener.id)
				return
			}

		}(listener, body)
	}
	eventsLock.Unlock()

	return nil
}
<|endoftext|>


<commit_before>package lexer

import (
	"errors"
	"fmt"
	"io"
	"text/scanner"
)

type Lex struct {
	*scanner.Scanner
	Token rune
}

// New returns new lexer
func New() *Lex {
	var s scanner.Scanner
	// only scan characters. implement lexer myself.
	s.Mode &^= scanner.ScanChars | scanner.ScanRawStrings
	return &Lex{
		Scanner: &s,
	}
}

// Init initialize lexer
func (l *Lex) Init(r io.Reader) {
	l.Scanner.Init(r)
}

// NextToken gets next token to lexer
func (lex *Lex) NextToken() {
	lex.Token = lex.Scanner.Scan()
}

// Error creates error including current token context.
func (lex *Lex) Error(msg string) error {
	return fmt.Errorf("%s: %v", msg, lex.Token)
}

type Tokens []string

// Scan starts scan the whole program and return tokens
func (lex *Lex) Scan() (tokens Tokens, err error) {
	// start s-expression
	if lex.Token == '(' {
		lex.NextToken()
		// recursive scan until ')'
		for {
			switch lex.Token {
			case ')':
				return tokens, nil
			default:
				ts, err := lex.Scan()
				if err != nil {
					return tokens, err
				}
				for _, t := range ts {
					tokens = append(tokens, t)
				}
			}
		}
	} else if lex.Token == ')' {
		return tokens, errors.New("unexpected ')'")
	} else {
		tokens = append(tokens, lex.TokenText())
		lex.NextToken()
		return tokens, nil
	}
	tokens = append(tokens, lex.TokenText())
	return tokens, nil
}
<commit_msg>change type<commit_after>package lexer

import (
	"errors"
	"fmt"
	"github.com/suzuken/gs/types"
	"io"
	"text/scanner"
)

type Lex struct {
	*scanner.Scanner
	Token rune
}

// New returns new lexer
func New() *Lex {
	var s scanner.Scanner
	// only scan characters. implement lexer myself.
	s.Mode &^= scanner.ScanChars | scanner.ScanRawStrings
	return &Lex{
		Scanner: &s,
	}
}

// Init initialize lexer
func (l *Lex) Init(r io.Reader) {
	l.Scanner.Init(r)
}

// NextToken gets next token to lexer
func (lex *Lex) NextToken() {
	lex.Token = lex.Scanner.Scan()
}

// Error creates error including current token context.
func (lex *Lex) Error(msg string) error {
	return fmt.Errorf("%s: %v", msg, lex.Token)
}

// Scan starts scan the whole program and return tokens
func (lex *Lex) Scan() (exps []types.Expression, err error) {
	// start s-expression
	if lex.Token == '(' {
		lex.NextToken()
		// recursive scan until ')'
		for {
			switch lex.Token {
			case ')':
				return exps, nil
			default:
				ts, err := lex.Scan()
				if err != nil {
					return exps, err
				}
				for _, t := range ts {
					exps = append(exps, t)
				}
			}
		}
	} else if lex.Token == ')' {
		return exps, errors.New("unexpected ')'")
	} else {
		exps = append(exps, lex.TokenText())
		lex.NextToken()
		return exps, nil
	}
	exps = append(exps, lex.TokenText())
	return exps, nil
}
<|endoftext|>


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

package build

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

// Path is a validated list of Trees derived from $GOPATH at init.
var Path []*Tree

// Tree describes a Go source tree, either $GOROOT or one from $GOPATH.
type Tree struct {
	Path   string
	Goroot bool
}

func newTree(p string) (*Tree, os.Error) {
	if !filepath.IsAbs(p) {
		return nil, os.NewError("must be absolute")
	}
	ep, err := filepath.EvalSymlinks(p)
	if err != nil {
		return nil, err
	}
	return &Tree{Path: ep}, nil
}

// SrcDir returns the tree's package source directory.
func (t *Tree) SrcDir() string {
	if t.Goroot {
		return filepath.Join(t.Path, "src", "pkg")
	}
	return filepath.Join(t.Path, "src")
}

// PkgDir returns the tree's package object directory.
func (t *Tree) PkgDir() string {
	goos, goarch := runtime.GOOS, runtime.GOARCH
	if e := os.Getenv("GOOS"); e != "" {
		goos = e
	}
	if e := os.Getenv("GOARCH"); e != "" {
		goarch = e
	}
	return filepath.Join(t.Path, "pkg", goos+"_"+goarch)
}

// BinDir returns the tree's binary executable directory.
func (t *Tree) BinDir() string {
	return filepath.Join(t.Path, "bin")
}

// HasSrc returns whether the given package's
// source can be found inside this Tree.
func (t *Tree) HasSrc(pkg string) bool {
	fi, err := os.Stat(filepath.Join(t.SrcDir(), pkg))
	if err != nil {
		return false
	}
	return fi.IsDirectory()
}

// HasPkg returns whether the given package's
// object file can be found inside this Tree.
func (t *Tree) HasPkg(pkg string) bool {
	fi, err := os.Stat(filepath.Join(t.PkgDir(), pkg+".a"))
	if err != nil {
		return false
	}
	return fi.IsRegular()
	// TODO(adg): check object version is consistent
}

var ErrNotFound = os.NewError("package could not be found locally")

// FindTree takes an import or filesystem path and returns the
// tree where the package source should be and the package import path.
func FindTree(path string) (tree *Tree, pkg string, err os.Error) {
	if isLocalPath(path) {
		if path, err = filepath.Abs(path); err != nil {
			return
		}
		for _, t := range Path {
			tpath := t.SrcDir() + string(filepath.Separator)
			if !strings.HasPrefix(path, tpath) {
				continue
			}
			tree = t
			pkg = path[len(tpath):]
			return
		}
		err = fmt.Errorf("path %q not inside a GOPATH", path)
		return
	}
	tree = defaultTree
	pkg = path
	for _, t := range Path {
		if t.HasSrc(pkg) {
			tree = t
			return
		}
	}
	err = ErrNotFound
	return
}

// isLocalPath returns whether the given path is local (/foo ./foo ../foo . ..)
func isLocalPath(s string) bool {
	const sep = string(filepath.Separator)
	return strings.HasPrefix(s, sep) || strings.HasPrefix(s, "."+sep) || strings.HasPrefix(s, ".."+sep) || s == "." || s == ".."
}

var (
	// argument lists used by the build's gc and ld methods
	gcImportArgs []string
	ldImportArgs []string

	// default tree for remote packages
	defaultTree *Tree
)

// set up Path: parse and validate GOROOT and GOPATH variables
func init() {
	root := runtime.GOROOT()
	p, err := newTree(root)
	if err != nil {
		log.Fatalf("Invalid GOROOT %q: %v", root, err)
	}
	p.Goroot = true
	Path = []*Tree{p}

	for _, p := range filepath.SplitList(os.Getenv("GOPATH")) {
		if p == "" {
			continue
		}
		t, err := newTree(p)
		if err != nil {
			log.Printf("Invalid GOPATH %q: %v", p, err)
			continue
		}
		Path = append(Path, t)
		gcImportArgs = append(gcImportArgs, "-I", t.PkgDir())
		ldImportArgs = append(ldImportArgs, "-L", t.PkgDir())

		// select first GOPATH entry as default
		if defaultTree == nil {
			defaultTree = t
		}
	}

	// use GOROOT if no valid GOPATH specified
	if defaultTree == nil {
		defaultTree = Path[0]
	}
}
<commit_msg>go/build: evaluate symlinks before comparing path to GOPATH<commit_after>// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package build

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

// Path is a validated list of Trees derived from $GOPATH at init.
var Path []*Tree

// Tree describes a Go source tree, either $GOROOT or one from $GOPATH.
type Tree struct {
	Path   string
	Goroot bool
}

func newTree(p string) (*Tree, os.Error) {
	if !filepath.IsAbs(p) {
		return nil, os.NewError("must be absolute")
	}
	ep, err := filepath.EvalSymlinks(p)
	if err != nil {
		return nil, err
	}
	return &Tree{Path: ep}, nil
}

// SrcDir returns the tree's package source directory.
func (t *Tree) SrcDir() string {
	if t.Goroot {
		return filepath.Join(t.Path, "src", "pkg")
	}
	return filepath.Join(t.Path, "src")
}

// PkgDir returns the tree's package object directory.
func (t *Tree) PkgDir() string {
	goos, goarch := runtime.GOOS, runtime.GOARCH
	if e := os.Getenv("GOOS"); e != "" {
		goos = e
	}
	if e := os.Getenv("GOARCH"); e != "" {
		goarch = e
	}
	return filepath.Join(t.Path, "pkg", goos+"_"+goarch)
}

// BinDir returns the tree's binary executable directory.
func (t *Tree) BinDir() string {
	return filepath.Join(t.Path, "bin")
}

// HasSrc returns whether the given package's
// source can be found inside this Tree.
func (t *Tree) HasSrc(pkg string) bool {
	fi, err := os.Stat(filepath.Join(t.SrcDir(), pkg))
	if err != nil {
		return false
	}
	return fi.IsDirectory()
}

// HasPkg returns whether the given package's
// object file can be found inside this Tree.
func (t *Tree) HasPkg(pkg string) bool {
	fi, err := os.Stat(filepath.Join(t.PkgDir(), pkg+".a"))
	if err != nil {
		return false
	}
	return fi.IsRegular()
	// TODO(adg): check object version is consistent
}

var ErrNotFound = os.NewError("package could not be found locally")

// FindTree takes an import or filesystem path and returns the
// tree where the package source should be and the package import path.
func FindTree(path string) (tree *Tree, pkg string, err os.Error) {
	if isLocalPath(path) {
		if path, err = filepath.Abs(path); err != nil {
			return
		}
		if path, err = filepath.EvalSymlinks(path); err != nil {
			return
		}
		for _, t := range Path {
			tpath := t.SrcDir() + string(filepath.Separator)
			if !strings.HasPrefix(path, tpath) {
				continue
			}
			tree = t
			pkg = path[len(tpath):]
			return
		}
		err = fmt.Errorf("path %q not inside a GOPATH", path)
		return
	}
	tree = defaultTree
	pkg = path
	for _, t := range Path {
		if t.HasSrc(pkg) {
			tree = t
			return
		}
	}
	err = ErrNotFound
	return
}

// isLocalPath returns whether the given path is local (/foo ./foo ../foo . ..)
func isLocalPath(s string) bool {
	const sep = string(filepath.Separator)
	return strings.HasPrefix(s, sep) || strings.HasPrefix(s, "."+sep) || strings.HasPrefix(s, ".."+sep) || s == "." || s == ".."
}

var (
	// argument lists used by the build's gc and ld methods
	gcImportArgs []string
	ldImportArgs []string

	// default tree for remote packages
	defaultTree *Tree
)

// set up Path: parse and validate GOROOT and GOPATH variables
func init() {
	root := runtime.GOROOT()
	p, err := newTree(root)
	if err != nil {
		log.Fatalf("Invalid GOROOT %q: %v", root, err)
	}
	p.Goroot = true
	Path = []*Tree{p}

	for _, p := range filepath.SplitList(os.Getenv("GOPATH")) {
		if p == "" {
			continue
		}
		t, err := newTree(p)
		if err != nil {
			log.Printf("Invalid GOPATH %q: %v", p, err)
			continue
		}
		Path = append(Path, t)
		gcImportArgs = append(gcImportArgs, "-I", t.PkgDir())
		ldImportArgs = append(ldImportArgs, "-L", t.PkgDir())

		// select first GOPATH entry as default
		if defaultTree == nil {
			defaultTree = t
		}
	}

	// use GOROOT if no valid GOPATH specified
	if defaultTree == nil {
		defaultTree = Path[0]
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/slugalisk/overrustlelogs/common"
)

// Logger logger
type Logger struct {
	logs *ChatLogs
}

// NewLogger instantiates destiny chat logger
func NewLogger(logs *ChatLogs) *Logger {
	return &Logger{
		logs: logs,
	}
}

// DestinyLog starts logging loop
func (l *Logger) DestinyLog(mc <-chan *common.Message) {
	var subTrigger bool
	giftRegex := regexp.MustCompile("^[a-zA-Z0-9_]+ gifted [a-zA-Z0-9_]+ a Tier (I|II|II|IV) subscription!")

loop:
	for m := range mc {
		switch m.Type {
		case "BAN":
			l.writeLine(m.Time, m.Channel, "Ban", fmt.Sprintf("%s banned by %s", m.Data, m.Nick))
		case "UNBAN":
			l.writeLine(m.Time, m.Channel, "Ban", fmt.Sprintf("%s unbanned by %s", m.Data, m.Nick))
		case "MUTE":
			l.writeLine(m.Time, m.Channel, "Ban", fmt.Sprintf("%s muted by %s", m.Data, m.Nick))
		case "UNMUTE":
			l.writeLine(m.Time, m.Channel, "Ban", fmt.Sprintf("%s unmuted by %s", m.Data, m.Nick))
		case "BROADCAST":
			subMessages := []string{"subscriber!", "subscribed on Twitch!", "has resubscribed! Active for"}

			for _, smsg := range subMessages {
				if strings.Contains(m.Data, smsg) {
					l.writeLine(m.Time, m.Channel, "Subscriber", m.Data)
					subTrigger = !subTrigger
					continue loop
				}
			}
			if giftRegex.MatchString(m.Data) {
				l.writeLine(m.Time, m.Channel, "Subscriber", m.Data)
				subTrigger = !subTrigger
				continue loop
			}

			if subTrigger {
				l.writeLine(m.Time, m.Channel, "SubscriberMessage", m.Data)
				subTrigger = !subTrigger
				continue
			}
			l.writeLine(m.Time, m.Channel, "Broadcast", m.Data)
		case "MSG":
			l.writeLine(m.Time, m.Channel, m.Nick, m.Data)
			subTrigger = false
		}
	}
}

// TwitchLog starts logging loop
func (l *Logger) TwitchLog(mc <-chan *common.Message) {
	for m := range mc {
		if m.Type == "MSG" {
			l.writeLine(m.Time, m.Channel, m.Nick, m.Data)
		}
	}
}

func (l *Logger) writeLine(timestamp time.Time, channel, nick, message string) {
	logs, err := l.logs.Get(filepath.Join(common.GetConfig().LogPath, strings.Title(channel)+" chatlog", timestamp.Format("January 2006"), timestamp.Format("2006-01-02")+".txt"))
	if err != nil {
		log.Printf("error opening log %s", err)
		return
	}
	logs.Write(timestamp, nick, message)
}
<commit_msg>new sub message in dgg<commit_after>package main

import (
	"fmt"
	"log"
	"path/filepath"
	"regexp"
	"strings"
	"time"

	"github.com/slugalisk/overrustlelogs/common"
)

// Logger logger
type Logger struct {
	logs *ChatLogs
}

// NewLogger instantiates destiny chat logger
func NewLogger(logs *ChatLogs) *Logger {
	return &Logger{
		logs: logs,
	}
}

// DestinyLog starts logging loop
func (l *Logger) DestinyLog(mc <-chan *common.Message) {
	var subTrigger bool
	giftRegex := regexp.MustCompile("^[a-zA-Z0-9_]+ gifted [a-zA-Z0-9_]+ a Tier (I|II|II|IV) subscription!")

loop:
	for m := range mc {
		switch m.Type {
		case "BAN":
			l.writeLine(m.Time, m.Channel, "Ban", fmt.Sprintf("%s banned by %s", m.Data, m.Nick))
		case "UNBAN":
			l.writeLine(m.Time, m.Channel, "Ban", fmt.Sprintf("%s unbanned by %s", m.Data, m.Nick))
		case "MUTE":
			l.writeLine(m.Time, m.Channel, "Ban", fmt.Sprintf("%s muted by %s", m.Data, m.Nick))
		case "UNMUTE":
			l.writeLine(m.Time, m.Channel, "Ban", fmt.Sprintf("%s unmuted by %s", m.Data, m.Nick))
		case "BROADCAST":
			subMessages := []string{"subscriber!", "subscribed on Twitch!", "has resubscribed! Active for", "has resubscribed on Twitch! active"}

			for _, smsg := range subMessages {
				if strings.Contains(m.Data, smsg) {
					l.writeLine(m.Time, m.Channel, "Subscriber", m.Data)
					subTrigger = !subTrigger
					continue loop
				}
			}
			if giftRegex.MatchString(m.Data) {
				l.writeLine(m.Time, m.Channel, "Subscriber", m.Data)
				subTrigger = !subTrigger
				continue loop
			}

			if subTrigger {
				l.writeLine(m.Time, m.Channel, "SubscriberMessage", m.Data)
				subTrigger = !subTrigger
				continue
			}
			l.writeLine(m.Time, m.Channel, "Broadcast", m.Data)
		case "MSG":
			l.writeLine(m.Time, m.Channel, m.Nick, m.Data)
			subTrigger = false
		}
	}
}

// TwitchLog starts logging loop
func (l *Logger) TwitchLog(mc <-chan *common.Message) {
	for m := range mc {
		if m.Type == "MSG" {
			l.writeLine(m.Time, m.Channel, m.Nick, m.Data)
		}
	}
}

func (l *Logger) writeLine(timestamp time.Time, channel, nick, message string) {
	logs, err := l.logs.Get(filepath.Join(common.GetConfig().LogPath, strings.Title(channel)+" chatlog", timestamp.Format("January 2006"), timestamp.Format("2006-01-02")+".txt"))
	if err != nil {
		log.Printf("error opening log %s", err)
		return
	}
	logs.Write(timestamp, nick, message)
}
<|endoftext|>


<commit_before>// Package ipv4utils provides utilities
// for working with IPv4 addresses.
package ipv4utils

import (
	"fmt"
	"net"
)

// Merge merges an IP to a value.
//
// Merging an IP allows for the use of operations on the IP.
func Merge(ip []byte) (merged uint32, err error) {
	if len(ip) != 4 {
		return 0, fmt.Errorf("%s is not an IPv4 address.", ip)
	}
	merged = uint32(0)
	// Takes the most significant octet,
	// shifts it to the left end of merged,
	// takes the next lesser significant octet,
	// shifts it to the start of the last shifted octet in merged, etc.
	for i, octet := range ip {
		merged |= uint32(octet) << (8 * (3 - uint32(i)))
	}
	return merged, nil
}

// Split splits a value into an IP.
//
// After merging an IP to perform operations on it, Split
// can be used to put the IP back into a slice.
func Split(merged uint32) []byte {
	ip := make([]byte, 4)
	for i := 3; i >= 0; i-- {
		// Takes the current least significant octet of merged,
		// inserts it into ip, disposes the least significant
		// octet of merged and moves the next more significant octet
		// into the position of the least significant octet.
		ip[i] = byte(merged & 0xFF)
		merged >>= 8
	}
	return ip
}

// Subnet subnets a network with the provided amount of bits.
//
// The network IP may have host bits set, as long as
// this address is a valid network address within the new subnet mask.
//
// This means that you can provide an offset for subnetting through the network IP:
//
// Network IP: 192.168.1.128/24, bits: 1 -> First subnet is 192.168.1.128/25, not 192.168.1.0/25
//
// The channel to provide the subnets is closed once subnetting is completed.
func Subnet(network net.IPNet, bits uint) (subnets chan net.IPNet, err error) {
	unchecked := network.IP
	originalMask := network.Mask
	if bits > 31 {
		return nil, fmt.Errorf("%d exceeds the maximum amount of subnettable bits (31).", bits)
	}
	maskLen, _ := originalMask.Size()
	newMaskLen := uint(maskLen) + bits
	if newMaskLen > 31 {
		return nil, fmt.Errorf("/%d subnetted with %d bits to /%d exceeds the size of valid IPv4 subnets (31).",
			maskLen, bits, newMaskLen)
	}
	uncheckedVal, err := Merge(unchecked)
	if err != nil {
		return nil, err
	}
	ip := uint64(uncheckedVal)
	hostBits := 32 - newMaskLen
	hosts := uint64(1 << hostBits)
	if ip&(hosts-1) != 0 {
		return nil, fmt.Errorf("%s has host bits set in /%d.", unchecked, newMaskLen)
	}

	subnets = make(chan net.IPNet)
	go func() {
		maskVal, _ := Merge(originalMask)
		baseIP := ip & uint64(maskVal)
		totalSubnets := uint64(1 << bits)
		totalHosts := totalSubnets * hosts
		nextIP := baseIP + totalHosts
		lastIP := nextIP - hosts
		newMask := net.CIDRMask(int(newMaskLen), 32)
		for ip <= lastIP {
			subnets <- net.IPNet{
				IP:   Split(uint32(ip)),
				Mask: newMask,
			}
			ip += hosts
		}
		close(subnets)
	}()
	return subnets, nil
}
<commit_msg>Removed redundant cast<commit_after>// Package ipv4utils provides utilities
// for working with IPv4 addresses.
package ipv4utils

import (
	"fmt"
	"net"
)

// Merge merges an IP to a value.
//
// Merging an IP allows for the use of operations on the IP.
func Merge(ip []byte) (merged uint32, err error) {
	if len(ip) != 4 {
		return 0, fmt.Errorf("%s is not an IPv4 address.", ip)
	}
	merged = 0
	// Takes the most significant octet,
	// shifts it to the left end of merged,
	// takes the next lesser significant octet,
	// shifts it to the start of the last shifted octet in merged, etc.
	for i, octet := range ip {
		merged |= uint32(octet) << (8 * (3 - uint32(i)))
	}
	return merged, nil
}

// Split splits a value into an IP.
//
// After merging an IP to perform operations on it, Split
// can be used to put the IP back into a slice.
func Split(merged uint32) []byte {
	ip := make([]byte, 4)
	for i := 3; i >= 0; i-- {
		// Takes the current least significant octet of merged,
		// inserts it into ip, disposes the least significant
		// octet of merged and moves the next more significant octet
		// into the position of the least significant octet.
		ip[i] = byte(merged & 0xFF)
		merged >>= 8
	}
	return ip
}

// Subnet subnets a network with the provided amount of bits.
//
// The network IP may have host bits set, as long as
// this address is a valid network address within the new subnet mask.
//
// This means that you can provide an offset for subnetting through the network IP:
//
// Network IP: 192.168.1.128/24, bits: 1 -> First subnet is 192.168.1.128/25, not 192.168.1.0/25
//
// The channel to provide the subnets is closed once subnetting is completed.
func Subnet(network net.IPNet, bits uint) (subnets chan net.IPNet, err error) {
	unchecked := network.IP
	originalMask := network.Mask
	if bits > 31 {
		return nil, fmt.Errorf("%d exceeds the maximum amount of subnettable bits (31).", bits)
	}
	maskLen, _ := originalMask.Size()
	newMaskLen := uint(maskLen) + bits
	if newMaskLen > 31 {
		return nil, fmt.Errorf("/%d subnetted with %d bits to /%d exceeds the size of valid IPv4 subnets (31).",
			maskLen, bits, newMaskLen)
	}
	uncheckedVal, err := Merge(unchecked)
	if err != nil {
		return nil, err
	}
	ip := uint64(uncheckedVal)
	hostBits := 32 - newMaskLen
	hosts := uint64(1 << hostBits)
	if ip&(hosts-1) != 0 {
		return nil, fmt.Errorf("%s has host bits set in /%d.", unchecked, newMaskLen)
	}

	subnets = make(chan net.IPNet)
	go func() {
		maskVal, _ := Merge(originalMask)
		baseIP := ip & uint64(maskVal)
		totalSubnets := uint64(1 << bits)
		totalHosts := totalSubnets * hosts
		nextIP := baseIP + totalHosts
		lastIP := nextIP - hosts
		newMask := net.CIDRMask(int(newMaskLen), 32)
		for ip <= lastIP {
			subnets <- net.IPNet{
				IP:   Split(uint32(ip)),
				Mask: newMask,
			}
			ip += hosts
		}
		close(subnets)
	}()
	return subnets, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"github.com/wellington/wellington"
)

func init() {
	s := new(string)
	wtCmd.PersistentFlags().StringVarP(s, "test", "t", "", "dummy for testing")

}

func TestHTTP(t *testing.T) {
	wtCmd.SetArgs([]string{
		"serve",
	})

	// No way to shut this down
	go main()

	req, err := http.NewRequest("POST", "http://localhost:12345",
		bytes.NewBufferString(`div { p { color: red; } }`))

	if err != nil {
		t.Fatal(err)
	}

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	if resp.Body == nil {
		t.Fatal("no response")
	}
	bs, _ := ioutil.ReadAll(resp.Body)

	var r wellington.Response
	err = json.Unmarshal(bs, &r)
	if err != nil {
		t.Fatal(err)
	}

	e := "/* line 1, stdin */\ndiv p {\n  color: red; }\n"
	if e != r.Contents {
		t.Errorf("got:\n%s\nwanted:\n%s", r.Contents, e)
	}
}

func TestStdin_import(t *testing.T) {
	wtCmd.ResetFlags()

	oldOut := os.Stdout

	r, w, _ := os.Pipe()
	os.Stdout = w
	pwd, err := os.Getwd()
	if err != nil {
		t.Fatal(err)
	}

	includeDir := filepath.Join(pwd, "..", "test", "sass")
	wtCmd.SetArgs([]string{
		"-p", includeDir,
		"compile", "../test/sass/import.scss"})
	main()

	outC := make(chan string)

	go func() {
		var buf bytes.Buffer
		io.Copy(&buf, r)
		outC <- buf.String()
	}()

	w.Close()
	os.Stdout = oldOut

	out := <-outC
	out = strings.Replace(out, includeDir, "", 1)
	e := `div {
  background: #00FF00;
  font-size: 10pt; }
`

	if !bytes.Contains([]byte(out), []byte(e)) {
		t.Errorf("got:\n%s\nwanted:\n%s", out, e)
	}

}

func TestStdin_sprite(t *testing.T) {
	wtCmd.ResetFlags()

	oldStd := os.Stdin
	var oldOut *os.File
	oldOut = os.Stdout

	r, w, _ := os.Pipe()
	os.Stdout = w
	wtCmd.SetArgs([]string{
		"--dir", "../test/img",
		"--gen", "../test/img/build",
		"compile"})

	var err error
	os.Stdin, err = os.Open("../test/sass/sprite.scss")
	if err != nil {
		t.Fatal(err)
	}
	main()

	outC := make(chan string)

	go func() {
		var buf bytes.Buffer
		io.Copy(&buf, r)
		outC <- buf.String()
	}()

	w.Close()
	os.Stdin = oldStd
	os.Stdout = oldOut

	out := <-outC

	e := `div {
  height: 139px;
  width: 96px;
  background: url("../test/img/build/f0a220.png") 0px 0px; }
`

	if !bytes.Contains([]byte(out), []byte(e)) {
		t.Errorf("got:\n%s\nwanted:\n%s", out, e)
	}

}

func TestFile(t *testing.T) {
	// TODO: Tests for file importing here
}

func TestFile_comprehensive(t *testing.T) {
	wtCmd.ResetFlags()

	oldStd := os.Stdin
	oldOut := os.Stdout

	r, w, _ := os.Pipe()
	os.Stdout = w
	wtCmd.SetArgs([]string{
		"--dir", "../test/img",
		"--gen", "../test/img/build",
		"--comment=false",
		"compile", "../test/comprehensive/compreh.scss"})
	main()

	outC := make(chan bytes.Buffer)

	go func() {
		var buf bytes.Buffer
		io.Copy(&buf, r)
		outC <- buf
	}()

	w.Close()
	os.Stdin = oldStd
	os.Stdout = oldOut

	out := <-outC

	e, err := ioutil.ReadFile("../test/comprehensive/expected.css")
	if err != nil {
		t.Fatal(err)
	}

	if bytes.Compare(out.Bytes(), e) != 0 {
		t.Errorf("got:\n%s\nwanted:\n%s", out.String(), string(e))
	}

}

func TestWatch_comprehensive(t *testing.T) {
	os.RemoveAll("../test/build/testwatch")
	wtCmd.ResetFlags()

	wtCmd.SetArgs([]string{
		"--dir", "../test/img",
		"-b", "../test/build/testwatch",
		"--gen", "../test/build/testwatch/img",
		"--comment=false",
		"watch", "../test/comprehensive/compreh.scss",
	})
	main()
	_, err := os.Stat("../test/build/testwatch/compreh.css")
	if err != nil {
		t.Fatal(err)
	}

	_, err = os.Stat("../test/build/testwatch/img/5905b8.png")
	if err != nil {
		t.Fatal(err)
	}
}
<commit_msg>sync wtCmd flag usage<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"testing"

	"github.com/wellington/wellington"
)

// Sometimes circleci detects races in these tests. This may prevent it
var wtCmdMu sync.RWMutex

func init() {
	s := new(string)
	wtCmdMu.Lock()
	wtCmd.PersistentFlags().StringVarP(s, "test", "t", "", "dummy for testing")
	wtCmdMu.Unlock()

}

func resetFlags() {
	wtCmdMu.Lock()
	defer wtCmdMu.Unlock()
	wtCmd.ResetFlags()
}

func TestHTTP(t *testing.T) {
	wtCmd.SetArgs([]string{
		"serve",
	})

	// No way to shut this down
	go main()

	req, err := http.NewRequest("POST", "http://localhost:12345",
		bytes.NewBufferString(`div { p { color: red; } }`))

	if err != nil {
		t.Fatal(err)
	}

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		t.Fatal(err)
	}
	if resp.Body == nil {
		t.Fatal("no response")
	}
	bs, _ := ioutil.ReadAll(resp.Body)

	var r wellington.Response
	err = json.Unmarshal(bs, &r)
	if err != nil {
		t.Fatal(err)
	}

	e := "/* line 1, stdin */\ndiv p {\n  color: red; }\n"
	if e != r.Contents {
		t.Errorf("got:\n%s\nwanted:\n%s", r.Contents, e)
	}
}

func TestStdin_import(t *testing.T) {
	resetFlags()

	oldOut := os.Stdout

	r, w, _ := os.Pipe()
	os.Stdout = w
	pwd, err := os.Getwd()
	if err != nil {
		t.Fatal(err)
	}

	includeDir := filepath.Join(pwd, "..", "test", "sass")
	wtCmd.SetArgs([]string{
		"-p", includeDir,
		"compile", "../test/sass/import.scss"})
	main()

	outC := make(chan string)

	go func() {
		var buf bytes.Buffer
		io.Copy(&buf, r)
		outC <- buf.String()
	}()

	w.Close()
	os.Stdout = oldOut

	out := <-outC
	out = strings.Replace(out, includeDir, "", 1)
	e := `div {
  background: #00FF00;
  font-size: 10pt; }
`

	if !bytes.Contains([]byte(out), []byte(e)) {
		t.Errorf("got:\n%s\nwanted:\n%s", out, e)
	}

}

func TestStdin_sprite(t *testing.T) {
	resetFlags()

	oldStd := os.Stdin
	var oldOut *os.File
	oldOut = os.Stdout

	r, w, _ := os.Pipe()
	os.Stdout = w
	wtCmd.SetArgs([]string{
		"--dir", "../test/img",
		"--gen", "../test/img/build",
		"compile"})

	var err error
	os.Stdin, err = os.Open("../test/sass/sprite.scss")
	if err != nil {
		t.Fatal(err)
	}
	main()

	outC := make(chan string)

	go func() {
		var buf bytes.Buffer
		io.Copy(&buf, r)
		outC <- buf.String()
	}()

	w.Close()
	os.Stdin = oldStd
	os.Stdout = oldOut

	out := <-outC

	e := `div {
  height: 139px;
  width: 96px;
  background: url("../test/img/build/f0a220.png") 0px 0px; }
`

	if !bytes.Contains([]byte(out), []byte(e)) {
		t.Errorf("got:\n%s\nwanted:\n%s", out, e)
	}

}

func TestFile(t *testing.T) {
	// TODO: Tests for file importing here
}

func TestFile_comprehensive(t *testing.T) {
	resetFlags()

	oldStd := os.Stdin
	oldOut := os.Stdout

	r, w, _ := os.Pipe()
	os.Stdout = w
	wtCmd.SetArgs([]string{
		"--dir", "../test/img",
		"--gen", "../test/img/build",
		"--comment=false",
		"compile", "../test/comprehensive/compreh.scss"})
	main()

	outC := make(chan bytes.Buffer)

	go func() {
		var buf bytes.Buffer
		io.Copy(&buf, r)
		outC <- buf
	}()

	w.Close()
	os.Stdin = oldStd
	os.Stdout = oldOut

	out := <-outC

	e, err := ioutil.ReadFile("../test/comprehensive/expected.css")
	if err != nil {
		t.Fatal(err)
	}

	if bytes.Compare(out.Bytes(), e) != 0 {
		t.Errorf("got:\n%s\nwanted:\n%s", out.String(), string(e))
	}

}

func TestWatch_comprehensive(t *testing.T) {
	os.RemoveAll("../test/build/testwatch")
	resetFlags()

	wtCmd.SetArgs([]string{
		"--dir", "../test/img",
		"-b", "../test/build/testwatch",
		"--gen", "../test/build/testwatch/img",
		"--comment=false",
		"watch", "../test/comprehensive/compreh.scss",
	})
	main()
	_, err := os.Stat("../test/build/testwatch/compreh.css")
	if err != nil {
		t.Fatal(err)
	}

	_, err = os.Stat("../test/build/testwatch/img/5905b8.png")
	if err != nil {
		t.Fatal(err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/nelhage/livegrep/server/api"
	"net/http"
	"net/url"
	"os"
)

var (
	server = flag.String("server", "http://localhost:8910", "The livegrep server to connect to")
)

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [flags] REGEX\n", os.Args[0])
		flag.PrintDefaults()
	}
	flag.Parse()

	if len(flag.Args()) != 1 {
		flag.Usage()
		os.Exit(1)
	}

	uri, err := url.Parse(*server)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Parsing server %s: %s\n", *server, err.Error())
		os.Exit(1)
	}

	uri.Path = "/api/v1/search/"
	uri.RawQuery = url.Values{"line": []string{flag.Arg(0)}}.Encode()

	resp, err := http.Get(uri.String())

	if err != nil {
		fmt.Fprintf(os.Stderr, "Requesting %s: %s\n", uri.String(), err.Error())
		os.Exit(1)
	}

	if resp.StatusCode != 200 {
		var reply api.ReplyError
		if e := json.NewDecoder(resp.Body).Decode(&reply); e != nil {
			fmt.Fprintf(os.Stderr,
				"Error reading reply (status=%d): %s\n", resp.StatusCode, e.Error())
		} else {
			fmt.Fprintf(os.Stderr, "Error: %s: %s", reply.Err.Code, reply.Err.Message)
		}
		os.Exit(1)
	}

	var reply api.ReplySearch

	if e := json.NewDecoder(resp.Body).Decode(&reply); e != nil {
		fmt.Fprintf(os.Stderr,
			"Error reading reply (status=%d): %s\n", resp.StatusCode, e.Error())
		os.Exit(1)
	}

	for _, r := range reply.Results {
		ctx := r.Contexts[0]
		p := ctx.Paths[0]
		if p.Repo != "" {
			fmt.Printf("%s:", p.Repo)
		}
		fmt.Printf("%s:%s:%d: ", p.Ref, p.Path, ctx.LineNumber)
		fmt.Printf("%s\n", r.Line)
	}
}
<commit_msg>lg: Be more lenient with -server<commit_after>package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/nelhage/livegrep/server/api"
	"net/http"
	"net/url"
	"os"
	"strings"
)

var (
	server = flag.String("server", "http://localhost:8910", "The livegrep server to connect to")
)

func main() {
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [flags] REGEX\n", os.Args[0])
		flag.PrintDefaults()
	}
	flag.Parse()

	if len(flag.Args()) != 1 {
		flag.Usage()
		os.Exit(1)
	}

	var uri *url.URL
	var err error

	if strings.Contains(*server, ":") {
		if uri, err = url.Parse(*server); err != nil {
			fmt.Fprintf(os.Stderr, "Parsing server %s: %s\n", *server, err.Error())
			os.Exit(1)
		}
	} else {
		uri = &url.URL{Scheme: "http", Host: *server}
	}

	uri.Path = "/api/v1/search/"
	uri.RawQuery = url.Values{"line": []string{flag.Arg(0)}}.Encode()

	resp, err := http.Get(uri.String())

	if err != nil {
		fmt.Fprintf(os.Stderr, "Requesting %s: %s\n", uri.String(), err.Error())
		os.Exit(1)
	}

	if resp.StatusCode != 200 {
		var reply api.ReplyError
		if e := json.NewDecoder(resp.Body).Decode(&reply); e != nil {
			fmt.Fprintf(os.Stderr,
				"Error reading reply (status=%d): %s\n", resp.StatusCode, e.Error())
		} else {
			fmt.Fprintf(os.Stderr, "Error: %s: %s", reply.Err.Code, reply.Err.Message)
		}
		os.Exit(1)
	}

	var reply api.ReplySearch

	if e := json.NewDecoder(resp.Body).Decode(&reply); e != nil {
		fmt.Fprintf(os.Stderr,
			"Error reading reply (status=%d): %s\n", resp.StatusCode, e.Error())
		os.Exit(1)
	}

	for _, r := range reply.Results {
		ctx := r.Contexts[0]
		p := ctx.Paths[0]
		if p.Repo != "" {
			fmt.Printf("%s:", p.Repo)
		}
		fmt.Printf("%s:%s:%d: ", p.Ref, p.Path, ctx.LineNumber)
		fmt.Printf("%s\n", r.Line)
	}
}
<|endoftext|>