Exemple #1
0
func TestTemplateEmailer(t *testing.T) {
	Convey("TemplateEmailer", t, func() {
		tmpl, err := template.New("test").Parse(`
			{{define "test.html"}}html part{{end}}
			{{define "test.txt"}}text part{{end}}
			{{define "test.hdr"}}Subject: test{{end}}`)
		So(err, ShouldBeNil)

		e := &TemplateEmailer{
			Deliverer: &TestDeliverer{},
			Templater: &templates.Templater{Templates: map[string]*template.Template{"test": tmpl}},
		}

		Convey("Send test email", func() {
			c := e.Deliverer.(MockDeliverer).Inbox("*****@*****.**")
			msgID, err := e.Send(scope.New(), "*****@*****.**", "test", nil)
			So(err, ShouldBeNil)

			email := parseEmail(<-c)
			So(email.Header.Get("Message-ID"), ShouldEqual, msgID)
			So(email.Header.Get("Subject"), ShouldEqual, "test")
			So(string(email.Text), ShouldEqual, "text part")
			So(string(email.HTML), ShouldEqual, "html part")
		})
	})
}
Exemple #2
0
func main() {
	go func() {
		// goto: http://localhost:6060/debug/pprof/ for goroutine info!
		fmt.Println(http.ListenAndServe("localhost:6060", nil))
	}()

	bcfg := babel.BotConfig{
		Nick:     "babelbot",
		RoomName: "test",
		Cmds: []plugin.CmdPluginDialer{
			plugin.CmdPluginDialer{
				Cmd:  "python",
				Args: []string{"log_everything.py"},
			},
		},
	}
	ws := &connection.WSConnectionDialer{
		UrlFormat: connection.EUPHORIA_URL_FORMAT,
	}

	ctx := scope.New()
	proto.SetLogger(ctx, logrus.StandardLogger())

	err := bcfg.Start(ctx, ws)
	if err != nil {
		proto.GetLogger(ctx).Errorf("bcfg.Start failure in main(): %s", err)
	}
}
Exemple #3
0
func TestRunHandler(t *testing.T) {
	ctrl := &Controller{}
	ctx := scope.New()

	Convey("Successfully runs", t, func() {
		term := &testTerm{}
		runHandler(ctx, testHandler{}, cmdConsole(ctrl, "test", term), []string{"test"})
		So(term.String(), ShouldEqual, "ok\r\n")
	})

	Convey("Usage error", t, func() {
		Convey("Handler serves usage", func() {
			term := &testTerm{}
			runHandler(ctx, testHandlerWithUsage{}, cmdConsole(ctrl, "test", term), nil)
			So(term.String(), ShouldEqual,
				"error: invalid number of arguments: 0\r\nusage\r\n\r\nOPTIONS:\r\n")
		})

		Convey("Handler doesn't serve usage", func() {
			term := &testTerm{}
			runHandler(ctx, testHandler{}, cmdConsole(ctrl, "test", term), nil)
			So(term.String(), ShouldEqual, "error: invalid number of arguments: 0\r\n")
		})
	})
}
Exemple #4
0
func TestRoomPresence(t *testing.T) {
	userA := newSession("A", "A1", "ip1")
	userA2 := newSession("A", "A2", "ip2")
	userB := newSession("B", "B1", "ip3")

	ctx := scope.New()
	kms := security.LocalKMS()
	kms.SetMasterKey(make([]byte, security.AES256.KeySize()))

	roomp, err := NewRoom(ctx, kms, false, "test", "testver")
	if err != nil {
		t.Fatal(err)
	}

	room := roomp.(*memRoom)

	client := &proto.Client{Agent: &proto.Agent{}}
	client.FromRequest(ctx, &http.Request{})

	Convey("First join", t, func() {
		_, err := room.Join(ctx, userA)
		So(err, ShouldBeNil)
		So(room.identities, ShouldResemble,
			map[proto.UserID]proto.Identity{"A": userA.Identity()})
		So(room.live, ShouldResemble,
			map[proto.UserID][]proto.Session{"A": []proto.Session{userA}})
	})

	Convey("Second join", t, func() {
		_, err := room.Join(ctx, userB)
		So(err, ShouldBeNil)
		So(room.identities["B"], ShouldResemble, userB.Identity())
		So(room.live["B"], ShouldResemble, []proto.Session{userB})
	})

	Convey("Duplicate join", t, func() {
		_, err := room.Join(ctx, userA2)
		So(err, ShouldBeNil)
		So(room.live["A"], ShouldResemble, []proto.Session{userA, userA2})
	})

	Convey("Deduplicate part", t, func() {
		So(room.Part(ctx, userA), ShouldBeNil)
		So(room.identities["A"], ShouldResemble, userA.Identity())
		So(room.live["A"], ShouldResemble, []proto.Session{userA2})
	})

	Convey("More parts", t, func() {
		So(room.Part(ctx, userA2), ShouldBeNil)
		So(room.identities["A"], ShouldBeNil)
		So(room.live["A"], ShouldBeNil)
		So(room.Part(ctx, userB), ShouldBeNil)
		So(room.identities["B"], ShouldBeNil)
		So(room.live["B"], ShouldBeNil)
	})
}
Exemple #5
0
func (s *EtcdServer) Join(root, id, era string) cluster.Cluster {
	desc := &cluster.PeerDesc{
		ID:  id,
		Era: era,
	}
	c, err := etcd.EtcdCluster(scope.New(), root, s.addr, desc)
	if err != nil {
		panic(fmt.Sprintf("error joining cluster: %s", err))
	}
	return c
}
Exemple #6
0
func TestBackend(t *testing.T) {
	etcd, err := clustertest.StartEtcd()
	if err != nil {
		t.Fatal(err)
	}
	if etcd == nil {
		t.Fatal("etcd not available in PATH, can't test backend")
	}
	defer etcd.Shutdown()

	dsn := *dsn
	if env := os.Getenv("DSN"); env != "" {
		// for running in CI container
		dsn = env
	}

	db, err := sql.Open("postgres", dsn)
	if err != nil {
		t.Fatalf("sql.Open: %s", err)
	}

	// Drop all tables.
	for _, item := range schema {
		if _, err := db.Exec("DROP TABLE IF EXISTS " + item.Name + " CASCADE"); err != nil {
			t.Fatalf("failed to drop table %s: %s", item.Name, err)
		}
	}
	if _, err := db.Exec("DROP TABLE IF EXISTS gorp_migrations"); err != nil {
		t.Fatal(err)
	}

	// Recreate all tables.
	src := migrate.FileMigrationSource{"migrations"}
	if _, err := migrate.Exec(db, "postgres", src, migrate.Up); err != nil {
		t.Fatal(err)
	}

	// Start up backend.
	c := etcd.Join("/test", "testcase", "era")
	desc := &cluster.PeerDesc{
		ID:      "testcase",
		Era:     "era",
		Version: "testver",
	}
	b, err := NewBackend(scope.New(), dsn, c, desc)
	if err != nil {
		t.Fatal(err)
	}
	defer b.Close()

	// Run test suite.
	backend.IntegrationTest(t, func() proto.Backend { return nonClosingBackend{b} })
}
Exemple #7
0
func main() {
	logger := &log.Logger{
		Handler: cli.New(os.Stdout),
		Level:   log.DebugLevel,
	}
	ctx := scope.New()
	ctx.Set("logger", logger)
	b := bot.NewBot(ctx, []proto.Handler{&handlers.PingHandler{}, &handlers.PongHandler{}}, connection.NewWSDialer(ctx.Fork(), fmt.Sprintf(url, "test")))
	if err := b.Run(); err != nil {
		logger.Fatalf("Bot.Run: Fatal error (%s)", err)
	}
}
Exemple #8
0
func (s *Server) handleRoomStatic(w http.ResponseWriter, r *http.Request) {
	if !s.allowRoomCreation {
		roomName := mux.Vars(r)["room"]
		_, err := s.b.GetRoom(scope.New(), roomName)
		if err != nil {
			if err == proto.ErrRoomNotFound {
				http.Error(w, "404 page not found", http.StatusNotFound)
				return
			}
		}
	}
	s.serveGzippedFile(w, r, "index.html", false)
}
Exemple #9
0
func TestMemLogLatest(t *testing.T) {
	ctx := scope.New()
	msgs := []proto.Message{
		{ID: 1, Content: "A"},
		{ID: 2, Content: "B"},
		{ID: 15, Content: "C"},
		{ID: 19, Content: "D"},
		{ID: 20, Content: "E"},
	}

	Convey("Partial response", t, func() {
		log := newMemLog()
		slice, err := log.Latest(ctx, 5, 0)
		So(err, ShouldBeNil)
		So(slice, ShouldNotBeNil)
		So(len(slice), ShouldEqual, 0)

		log.post(&msgs[0])
		log.post(&msgs[1])
		log.post(&msgs[2])
		slice, err = log.Latest(ctx, 5, 0)
		So(err, ShouldBeNil)
		So(slice, ShouldResemble, msgs[:3])
	})

	Convey("Full response", t, func() {
		log := newMemLog()
		for _, msg := range msgs {
			posted := msg
			log.post(&posted)
		}

		slice, err := log.Latest(ctx, 3, 0)
		So(err, ShouldBeNil)
		So(slice, ShouldResemble, msgs[2:])
	})

	Convey("Before", t, func() {
		log := newMemLog()
		for _, msg := range msgs {
			posted := msg
			log.post(&posted)
		}

		slice, err := log.Latest(ctx, 3, 20)
		So(err, ShouldBeNil)
		So(slice, ShouldResemble, msgs[1:4])
	})
}
Exemple #10
0
func Run(args []string) {
	out = tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0)

	if len(args) == 0 {
		generalHelp()
		return
	}

	exe := filepath.Base(os.Args[0])
	cmd, ok := subcommands[args[0]]
	if !ok {
		fmt.Fprintf(os.Stderr, "%s: invalid command: %s\n", exe, args[0])
		fmt.Fprintf(os.Stderr, "Run '%s help' for usage.\n", exe)
		os.Exit(2)
	}

	flags := cmd.flags()
	if err := flags.Parse(args[1:]); err != nil {
		fmt.Fprintf(os.Stderr, "%s %s: %s\n", exe, args[0], err)
		os.Exit(2)
	}

	ctx := logging.LoggingContext(scope.New(), os.Stdout, fmt.Sprintf("[%s] ", args[0]))
	logging.Logger(ctx).Printf("starting up")
	if err := cmd.run(ctx, flags.Args()); err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(1)
	}

	timeout := time.After(10 * time.Second)
	completed := make(chan struct{})
	go func() {
		ctx.WaitGroup().Wait()
		close(completed)
	}()

	fmt.Println("waiting for graceful shutdown...")
	select {
	case <-timeout:
		fmt.Println("timed out")
		os.Exit(1)
	case <-completed:
		fmt.Println("ok")
		os.Exit(0)
	}
}
Exemple #11
0
func TestRunCommand(t *testing.T) {
	ctx := scope.New()

	Convey("Unregistered command prints error", t, func() {
		term := &testTerm{}
		runCommand(ctx, nil, "asdf", term, nil)
		So(term.String(), ShouldEqual, "invalid command: asdf\r\n")
	})

	Convey("Registered command is invoked", t, func() {
		save := handlers
		defer func() { handlers = save }()
		handlers = map[string]handler{}
		register("test", testHandler{})
		term := &testTerm{}
		runCommand(ctx, &Controller{}, "test", term, []string{"arg"})
		So(term.String(), ShouldEqual, "ok\r\n")
	})
}
Exemple #12
0
// NewBot creates a bot with the given configuration. It will create a bolt DB
// if it does not already exist at the specified location.
func NewBot(cfg BotConfig) (*Bot, error) {
	db, err := bolt.Open(cfg.DbPath, 0666, nil)
	if err != nil {
		return nil, err
	}
	ctx := scope.New()
	logger := logrus.New()
	logger.Level = logrus.DebugLevel
	cmd := make(chan interface{})
	rooms := make(map[string]*Room)
	return &Bot{
		Rooms:   rooms,
		BotName: cfg.Name,
		ctx:     ctx,
		DB:      db,
		Logger:  logger,
		cmd:     cmd,
	}, nil
}
Exemple #13
0
// AddRoom adds a new Room to the bot with the given configuration. The context
// for this room is distinct from the Bot's context.
func (b *Bot) AddRoom(cfg RoomConfig) {
	b.Logger.Debugf("%s", len(cfg.AddlHandlers))
	ctx := scope.New()
	logger := logrus.New()
	logger.Level = logrus.DebugLevel
	room := Room{
		RoomName: cfg.RoomName,
		password: cfg.Password,
		Ctx:      ctx,
		outbound: make(chan *proto.Packet, 5),
		inbound:  make(chan *proto.Packet, 5),
		BotName:  b.BotName,
		msgID:    0,
		Logger:   logger,
		Handlers: cfg.AddlHandlers,
		DB:       b.DB,
		conn:     cfg.Conn,
	}
	b.Rooms[room.RoomName] = &room
}
Exemple #14
0
func (s *Server) handleRoomStatic(w http.ResponseWriter, r *http.Request) {
	ctx := scope.New()

	// Before creating an agent cookie, make this visitor look like a human.
	if err := r.ParseForm(); err != nil {
		s.serveErrorPage("bad request", http.StatusBadRequest, w, r)
		return
	}
	r.Form.Set("h", "1")

	// Tag the agent.
	client, cookie, _, err := getClient(ctx, s, r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if cookie != nil {
		w.Header().Add("Set-Cookie", cookie.String())
	}

	// Parameterize and serve the page.
	prefix := mux.Vars(r)["prefix"]
	roomName := mux.Vars(r)["room"]
	room, err := s.resolveRoom(ctx, prefix, roomName, client)
	if err != nil {
		if err == proto.ErrRoomNotFound {
			if !s.allowRoomCreation || prefix != "" {
				s.serveErrorPage("room not found", http.StatusNotFound, w, r)
				return
			}
		} else {
			s.serveErrorPage(err.Error(), http.StatusInternalServerError, w, r)
			return
		}
	}
	params := map[string]interface{}{"RoomTitle": strings.TrimPrefix(room.Title(), "&")}
	s.servePage("room.html", params, w, r)
}
Exemple #15
0
func TestRoomBroadcast(t *testing.T) {
	userA := newSession("A", "A1", "ip1")
	userB := newSession("B", "B1", "ip2")
	userC := newSession("C", "C1", "ip3")

	ctx := scope.New()
	kms := security.LocalKMS()
	kms.SetMasterKey(make([]byte, security.AES256.KeySize()))

	roomp, err := NewRoom(ctx, kms, false, "test", "testver")
	if err != nil {
		t.Fatal(err)
	}
	room := roomp.(*memRoom)

	client := &proto.Client{Agent: &proto.Agent{}}
	client.FromRequest(ctx, &http.Request{})

	Convey("Setup", t, func() {
		_, err := room.Join(ctx, userA)
		So(err, ShouldBeNil)
		_, err = room.Join(ctx, userB)
		So(err, ShouldBeNil)
		_, err = room.Join(ctx, userC)
		So(err, ShouldBeNil)
	})

	Convey("Multiple exclude", t, func() {
		So(room.broadcast(ctx, proto.SendType, proto.Message{Content: "1"}, userA, userB),
			ShouldBeNil)
		So(userA.history, ShouldResemble,
			[]message{
				{
					cmdType: proto.JoinEventType,
					payload: &proto.PresenceEvent{
						SessionID:    "B",
						IdentityView: proto.IdentityView{ID: "B"},
					},
				},
				{
					cmdType: proto.JoinEventType,
					payload: &proto.PresenceEvent{
						SessionID:    "C",
						IdentityView: proto.IdentityView{ID: "C"},
					},
				},
			})
		So(userB.history, ShouldResemble,
			[]message{
				{
					cmdType: proto.JoinEventType,
					payload: &proto.PresenceEvent{
						SessionID:    "C",
						IdentityView: proto.IdentityView{ID: "C"},
					},
				},
			})
		So(userC.history, ShouldResemble,
			[]message{{cmdType: proto.SendEventType, payload: proto.Message{Content: "1"}}})
	})

	Convey("No exclude", t, func() {
		So(room.broadcast(ctx, proto.SendType, proto.Message{Content: "2"}), ShouldBeNil)
		So(userA.history, ShouldResemble,
			[]message{
				{
					cmdType: proto.JoinEventType,
					payload: &proto.PresenceEvent{
						SessionID:    "B",
						IdentityView: proto.IdentityView{ID: "B"},
					},
				},
				{
					cmdType: proto.JoinEventType,
					payload: &proto.PresenceEvent{
						SessionID:    "C",
						IdentityView: proto.IdentityView{ID: "C"},
					},
				},
				{
					cmdType: proto.SendEventType,
					payload: proto.Message{Content: "2"},
				},
			})
		So(userB.history, ShouldResemble,
			[]message{
				{
					cmdType: proto.JoinEventType,
					payload: &proto.PresenceEvent{
						SessionID:    "C",
						IdentityView: proto.IdentityView{ID: "C"},
					},
				},
				{cmdType: proto.SendEventType, payload: proto.Message{Content: "2"}},
			})
		So(userC.history, ShouldResemble,
			[]message{
				{cmdType: proto.SendEventType, payload: proto.Message{Content: "1"}},
				{cmdType: proto.SendEventType, payload: proto.Message{Content: "2"}},
			})
	})
}
Exemple #16
0
func TestDeleteMessage(t *testing.T) {
	ctx := scope.New()
	kms := security.LocalKMS()
	kms.SetMasterKey(make([]byte, security.AES256.KeySize()))
	session := mock.TestSession("test", "T1", "ip1")

	sendMessage := func(room proto.Room) (proto.Message, error) {
		msg := proto.Message{
			Sender: proto.SessionView{
				SessionID:    "test",
				IdentityView: proto.IdentityView{ID: "test"},
			},
			Content: "test",
		}

		if managedRoom, ok := room.(proto.ManagedRoom); ok {
			key, err := managedRoom.MessageKey(ctx)
			if err != nil {
				return proto.Message{}, err
			}

			if key != nil {
				mkey := key.ManagedKey()
				if err := kms.DecryptKey(&mkey); err != nil {
					return proto.Message{}, err
				}
				if err := proto.EncryptMessage(&msg, key.KeyID(), &mkey); err != nil {
					return proto.Message{}, err
				}
			}
		}

		return room.Send(ctx, session, msg)
	}

	Convey("Delete message in public room", t, func() {
		ctrl := &Controller{
			backend: &mock.TestBackend{},
			kms:     kms,
		}
		term := &testTerm{}

		public, err := ctrl.backend.CreateRoom(ctx, kms, false, "public")
		So(err, ShouldBeNil)
		sent, err := sendMessage(public)
		So(err, ShouldBeNil)

		runCommand(ctx, ctrl, "delete-message", term, []string{"public:" + sent.ID.String()})

		deleted, err := public.GetMessage(ctx, sent.ID)
		So(err, ShouldBeNil)
		So(time.Time(deleted.Deleted).IsZero(), ShouldBeFalse)
	})

	Convey("Delete message in private room", t, func() {
		ctrl := &Controller{
			backend: &mock.TestBackend{},
			kms:     kms,
		}
		term := &testTerm{}

		private, err := ctrl.backend.CreateRoom(ctx, kms, true, "private")
		So(err, ShouldBeNil)
		runCommand(ctx, ctrl, "lock-room", term, []string{"private"})

		sent, err := sendMessage(private)
		So(err, ShouldBeNil)

		runCommand(ctx, ctrl, "delete-message", term, []string{"private:" + sent.ID.String()})

		deleted, err := private.GetMessage(ctx, sent.ID)
		So(err, ShouldBeNil)
		So(time.Time(deleted.Deleted).IsZero(), ShouldBeFalse)
	})
}
Exemple #17
0
func TestGrants(t *testing.T) {
	Convey("Grant a capability on a room", t, func() {
		kms := security.LocalKMS()
		kms.SetMasterKey(make([]byte, security.AES256.KeySize()))
		ctx := scope.New()
		client := &proto.Client{Agent: &proto.Agent{}}
		client.FromRequest(ctx, &http.Request{})
		backend := &mock.TestBackend{}
		room, err := backend.CreateRoom(ctx, kms, true, "test")
		So(err, ShouldBeNil)

		rkey, err := room.MessageKey(ctx)
		So(err, ShouldBeNil)
		mkey := rkey.ManagedKey()
		So(kms.DecryptKey(&mkey), ShouldBeNil)

		// Sign in as alice and send an encrypted message with aliceSendTime
		// as the nonce.
		aliceSendTime := time.Now()
		msgNonce := []byte(snowflake.NewFromTime(aliceSendTime).String())

		aliceKey := &security.ManagedKey{
			KeyType:   security.AES256,
			Plaintext: make([]byte, security.AES256.KeySize()),
		}

		grant, err := security.GrantSharedSecretCapability(aliceKey, rkey.Nonce(), nil, mkey.Plaintext)
		So(err, ShouldBeNil)

		alice := mock.TestSession("Alice", "A1", "ip1")
		_, err = room.Join(ctx, alice)
		So(err, ShouldBeNil)

		msg := proto.Message{
			ID:       snowflake.NewFromTime(aliceSendTime),
			UnixTime: proto.Time(aliceSendTime),
			Content:  "hello",
		}

		iv, err := base64.URLEncoding.DecodeString(grant.CapabilityID())
		So(err, ShouldBeNil)
		payload := grant.EncryptedPayload()
		So(aliceKey.BlockCrypt(iv, aliceKey.Plaintext, payload, false), ShouldBeNil)
		key := &security.ManagedKey{
			KeyType: security.AES128,
		}
		So(json.Unmarshal(aliceKey.Unpad(payload), &key.Plaintext), ShouldBeNil)

		digest, ciphertext, err := security.EncryptGCM(
			key, msgNonce, []byte(msg.Content), []byte("Alice"))
		So(err, ShouldBeNil)

		digestStr := base64.URLEncoding.EncodeToString(digest)
		cipherStr := base64.URLEncoding.EncodeToString(ciphertext)
		msg.Content = digestStr + "/" + cipherStr
		_, err = room.Send(ctx, alice, msg)
		So(err, ShouldBeNil)

		// Now sign in as bob and decrypt the message.
		bobKey := &security.ManagedKey{
			KeyType:   security.AES256,
			Plaintext: make([]byte, security.AES256.KeySize()),
		}
		//bobKey.Plaintext[0] = 1
		grant, err = security.GrantSharedSecretCapability(bobKey, rkey.Nonce(), nil, mkey.Plaintext)
		So(err, ShouldBeNil)

		iv, err = base64.URLEncoding.DecodeString(grant.CapabilityID())
		So(err, ShouldBeNil)
		payload = grant.EncryptedPayload()
		So(bobKey.BlockCrypt(iv, bobKey.Plaintext, payload, false), ShouldBeNil)
		key = &security.ManagedKey{
			KeyType: security.AES128,
		}
		So(json.Unmarshal(bobKey.Unpad(payload), &key.Plaintext), ShouldBeNil)

		bob := mock.TestSession("Bob", "B1", "ip2")
		_, err = room.Join(ctx, bob)
		So(err, ShouldBeNil)
		log, err := room.Latest(ctx, 1, 0)
		So(err, ShouldBeNil)
		So(len(log), ShouldEqual, 1)
		msg = log[0]

		parts := strings.Split(msg.Content, "/")
		So(len(parts), ShouldEqual, 2)
		digest, err = base64.URLEncoding.DecodeString(parts[0])
		So(err, ShouldBeNil)
		ciphertext, err = base64.URLEncoding.DecodeString(parts[1])
		So(err, ShouldBeNil)

		plaintext, err := security.DecryptGCM(key, msgNonce, digest, ciphertext, []byte("Alice"))
		So(err, ShouldBeNil)
		So(string(plaintext), ShouldEqual, "hello")
	})
}