Example #1
0
func TestDeregisterMailbox(t *testing.T) {
	mb, _ := mailbox.Create("test.deregister")
	_, err := pmClient.DeregisterMailbox(mb.Id)
	if err != nil {
		t.Fatal(err)
	}
	_mb, _ := mailbox.Find(mb.Id)
	if _mb != nil {
		t.Fatal("Mailbox not removed")
	}

}
Example #2
0
func TestRegister(t *testing.T) {
	key := mailbox.AccessKey{FullAccess: true}
	key.Create()
	req := api.RegisterRequest{Mailbox: "register.test"}
	req.Sign(key.Name, key.Secret)
	var resp api.RegisterResponse
	code := doRequest(t, req, &resp, "register")
	if code != 200 {
		t.Fatalf("Server repsponded with %d", code)
	}
	mb, err := mailbox.Find("register.test")
	if err != nil {
		t.Fatal(err)
	}
	if mb == nil {
		t.Fatal("Mailbox not registered")
	}
	if !key.CanGet(mb) {
		t.Fatal("Key not bound to mailbox")
	}
}
Example #3
0
func getMessage(w http.ResponseWriter, r *http.Request) {
	id := r.URL.String()[9:]

	mb, err := mailbox.Find(id)
	if err != nil {
		e := &ResponseError{Error: err.Error()}
		json.NewEncoder(w).Encode(e)
		return
	}
	if mb == nil {
		e := &ResponseError{Error: "Mailbox not found."}
		json.NewEncoder(w).Encode(e)
		return
	}
	msg, err := mb.GetMessage()
	if err != nil {
		e := &ResponseError{Error: err.Error()}
		json.NewEncoder(w).Encode(e)
	} else {
		json.NewEncoder(w).Encode(msg)
	}
}
Example #4
0
// getMessage is used by clients to poll for mailbox messages. This method will
// search the database for messages for the given mailbox. If the mailbox is
// empty and long_polling is enabled it will create a channel and add it to
// pollingChannels. It will then wait for a message to be pushed to that
// channel. It will then continue to output that message. Messages are pushed by
// the putMessage method.
func getMessage(w http.ResponseWriter, r *http.Request) {
	if !EnableLongPolling {
		time.Sleep(ThrottleDelay)
	}
	var request api.GetMessageRequest
	err := readRequest(r, &request)
	if err != nil {
		sendError(w, err.Error())
		return
	}

	mb, err := mailbox.Find(request.Mailbox)
	if err != nil {
		sendError(w, err.Error())
		return
	}

	if mb == nil {
		log.Warnf("Could not find a mailbox named '%s'", request.Mailbox)
		sendError(w, fmt.Sprintf("Mailbox %s not found.", request.Mailbox))
		return
	}

	log.Debugf("Message request from %s", mb.Id)

	accessKey, err := mailbox.FindKeyByName(request.AccessKeyName)
	if accessKey == nil {
		log.Warnf("Could not find an access key named '%s'", request.AccessKeyName)
		sendError(w, "Access key is invalid")
		return
	}

	if !request.Validate(accessKey.Secret) {
		log.Warnf(fmt.Sprintf("Signature for %s invalid", mb.Id))
		sendError(w, "Signature is invalid")
		return
	}

	if !accessKey.CanGet(mb) {
		sendError(w, "Not allowed to get messages from this mailbox.")
		return
	}

	if err := mb.Checkin(r.RemoteAddr, request.Version); err != nil {
		sendError(w, err.Error())
		return
	}

	msg, err := mb.GetMessage()
	if err != nil {
		sendError(w, err.Error())
		log.Errorf("Error retrieving messages: %s", err.Error())
		return
	}

	if EnableLongPolling == true && msg == nil {
		if _, ok := pollingChannels[mb.Id]; ok {
			delete(pollingChannels, mb.Id)
		}
		// Create a channel for the client. This channel has a message pushed to it
		// from the putMessage function. When a message gets delivered.
		pollingChannels[mb.Id] = make(chan *mailbox.Message)
		timeout := make(chan bool, 1)
		// This goroutine will create a timeout to close the long polling connection
		// and force the client to reconnect.
		go func() {
			// Randomize the polling timeout in order to stagger client reconnects.
			sleepTime := rand.Intn(500) + 200
			time.Sleep(time.Duration(sleepTime) * time.Second)
			timeout <- true
		}()
		// Wait for either a timeout or a message to be sent to a channel.
		select {
		case m := <-pollingChannels[mb.Id]:
			msg = m
		case <-timeout:
			response := api.GetMessageResponse{}
			response.Sign(accessKey.Name, accessKey.Secret)
			writeResponse(&w, response)
			delete(pollingChannels, mb.Id)
			return
		}
		delete(pollingChannels, mb.Id)
	}

	if msg == nil {
		writeResponse(&w, nil)
		return
	}

	dep, err := msg.GetDeployment()
	if err != nil {
		sendError(w, err.Error())
		return
	}

	response := api.GetMessageResponse{
		Message:      msg.Id,
		Body:         msg.Body,
		CreatedAt:    msg.CreatedAt,
		ReceiveCount: msg.ReceiveCount,
		Deployment:   msg.Deployment,
		Asset:        dep.Asset,
	}

	response.Sign(accessKey.Name, accessKey.Secret)
	log.Infof("Delivering message %s to %s", response.Message, mb.Id)

	writeResponse(&w, response)
}
Example #5
0
// deployRespond is used by scripts to "respond" with information from the
// remote system. These responses can then be reported to the admin client that
// deployed the original script.
func deployRespond(w http.ResponseWriter, r *http.Request) {
	var request api.ResponseRequest
	err := readRequest(r, &request)

	if err != nil {
		sendError(w, "Could not parse request")
		return
	}
	accessKey, err := mailbox.FindKeyByName(request.AccessKeyName)
	if accessKey == nil {
		sendError(w, "Access key is not valid")
		return
	}

	if !request.Validate(accessKey.Secret) {
		sendError(w, "Could not validate signature")
		return
	}

	msg, err := mailbox.FindMessage(request.Message)
	if err != nil {
		sendError(w, err.Error())
		return
	}

	if msg == nil {
		sendError(w, "Could not find message "+request.Message)
		return
	}

	mb, err := mailbox.Find(msg.Mailbox)
	if err != nil {
		sendError(w, err.Error())
		return
	}

	if mb == nil {
		sendError(w, "Mailbox not found")
		return
	}

	dep, err := mailbox.FindDeployment(msg.Deployment)
	if err != nil {
		sendError(w, err.Error())
		return
	}
	if dep == nil {
		sendError(w, "Could not find deployment "+msg.Deployment)
		return
	}
	if !accessKey.CanGet(mb) {
		sendError(w, "Not allowed to respond to deploys")
		return
	}
	err = dep.AddResponse(msg.Mailbox, request.Response, request.Error)
	if err != nil {
		sendError(w, err.Error())
		return
	}
	response := api.SimpleResponse{Success: true}
	response.Sign(accessKey.Name, accessKey.Secret)
	log.Infof("Reponse added to %s from %s", dep.Id, msg.Mailbox)
	writeResponse(&w, response)
}
Example #6
0
// putMessage is used to deploy messages to mailboxes, etiher by a list of
// mailboxes or a pattern. Messages are organized into a deployment and
// persisted to the database. If any receiptients are currently polling the
// message will be forwarded to that session.
func putMessage(w http.ResponseWriter, r *http.Request) {
	var request api.PutMessageRequest
	err := readRequest(r, &request)
	if err != nil {
		sendError(w, "Could not parse request")
	}
	mailboxes := []mailbox.Mailbox{}
	if request.Pattern != "" {
		results, err := mailbox.Search(request.Pattern)
		if err != nil {
			sendError(w, err.Error())
			return
		}
		for _, mb := range results {
			mailboxes = append(mailboxes, mb)
		}
	}
	for _, mbId := range request.Mailboxes {
		mb, err := mailbox.Find(mbId)
		if err != nil {
			sendError(w, err.Error())
		}
		if mb == nil {
			sendError(w, fmt.Sprintf("Mailbox not found (%s)", mbId))
			return
		}
		mailboxes = append(mailboxes, *mb)
	}

	if len(mailboxes) == 0 {
		sendError(w, "No mailboxes specified")
		return
	}

	if request.Asset != "" {
		assetPath := filepath.Join(filesPath(), request.Asset)
		if _, err := os.Stat(assetPath); os.IsNotExist(err) {
			sendError(w, "Asset does not exist on server")
			return
		}
	}

	mbList := []string{}
	// dep, err := mailbox.CreateDeployment(request.DeploymentName, request.Token,
	// 	request.Body)

	dep := mailbox.Deployment{
		Name:        request.DeploymentName,
		DeployedBy:  request.AccessKeyName,
		MessageBody: request.Body,
		Asset:       request.Asset,
	}

	err = dep.Create()

	if err != nil {
		sendError(w, err.Error())
		return
	}

	accessKey, err := mailbox.FindKeyByName(request.AccessKeyName)
	if err != nil || accessKey == nil {
		sendError(w, "Access key is invalid")
		return
	}

	if !request.Validate(accessKey.Secret) {
		sendError(w, "Signature not valid")
		return
	}

	for _, mb := range mailboxes {
		if !accessKey.CanPut(&mb) {
			sendError(w, "Not allowed to send messages to "+mb.Id)
			return
		}
		var msg *mailbox.Message
		msg, err = dep.Deploy(&mb)
		mbList = append(mbList, mb.Id)
		if err != nil {
			sendError(w, err.Error())
			return
		}
		if pollChannel, ok := pollingChannels[mb.Id]; ok {
			time.Sleep(50 * time.Millisecond)
			pollChannel <- msg
		}
	}

	resp := api.PutMessageResponse{
		MessageSize: r.ContentLength,
		Mailboxes:   mbList,
		Deployment:  dep.Id,
	}
	resp.Sign(accessKey.Name, accessKey.Secret)

	log.Infof("Message received for %d mailboxes from %s", len(mbList),
		dep.DeployedBy)
	writeResponse(&w, resp)
}
Example #7
0
)

// purgeCmd represents the purge command
var purgeCmd = &cobra.Command{
	Use:   "purge [mailbox]",
	Short: "Purge all messages for a mailbox.",
	Long: `Delete all messages for the local server for a given mailbox. This
purges local data from the server's database. To purge a remote server use
conduit purge instead.`,
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) == 0 {
			log.Fatal("No mailbox specified.")
		}
		mailbox.OpenDB()
		mailboxId := args[0]
		mb, err := mailbox.Find(mailboxId)
		if err != nil {
			log.Fatal("Could not lookup mailbox.")
			log.Debug(err.Error())
		}
		if mb == nil {
			log.Fatal("Could not find the mailbox specified")
		}
		c, err := mb.Purge()
		if err != nil {
			log.Fatal("Could not purge mailbox")
			log.Debug(err.Error())
		}
		log.Infof("Mailbox purged of %d messages.", c)
	},
}