示例#1
0
// LabelsCreate does *something* - TODO
func LabelsCreate(c web.C, w http.ResponseWriter, req *http.Request) {
	// Decode the request
	var input LabelsCreateRequest
	err := utils.ParseRequest(req, &input)
	if err != nil {
		env.Log.WithFields(logrus.Fields{
			"error": err.Error(),
		}).Warn("Unable to decode a request")

		utils.JSONResponse(w, 400, &LabelsCreateResponse{
			Success: false,
			Message: "Invalid input format",
		})
		return
	}

	// Fetch the current session from the middleware
	session := c.Env["token"].(*models.Token)

	// Ensure that the input data isn't empty
	if input.Name == "" {
		utils.JSONResponse(w, 400, &LabelsCreateResponse{
			Success: false,
			Message: "Invalid request",
		})
		return
	}

	if _, err := env.Labels.GetLabelByNameAndOwner(session.Owner, input.Name); err == nil {
		utils.JSONResponse(w, 409, &LabelsCreateResponse{
			Success: false,
			Message: "Label with such name already exists",
		})
		return
	}

	// Create a new label struct
	label := &models.Label{
		Resource: models.MakeResource(session.Owner, input.Name),
		Builtin:  false,
	}

	// Insert the label into the database
	if err := env.Labels.Insert(label); err != nil {
		utils.JSONResponse(w, 500, &LabelsCreateResponse{
			Success: false,
			Message: "internal server error - LA/CR/01",
		})

		env.Log.WithFields(logrus.Fields{
			"error": err.Error(),
		}).Error("Could not insert a label into the database")
		return
	}

	utils.JSONResponse(w, 201, &LabelsCreateResponse{
		Success: true,
		Label:   label,
	})
}
示例#2
0
// FilesCreate creates a new file
func FilesCreate(c web.C, w http.ResponseWriter, r *http.Request) {
	// Decode the request
	var input FilesCreateRequest
	err := utils.ParseRequest(r, &input)
	if err != nil {
		env.Log.WithFields(logrus.Fields{
			"error": err.Error(),
		}).Warn("Unable to decode a request")

		utils.JSONResponse(w, 400, &FilesCreateResponse{
			Success: false,
			Message: "Invalid input format",
		})
		return
	}

	// Fetch the current session from the middleware
	session := c.Env["token"].(*models.Token)

	// Ensure that the input data isn't empty
	if input.Data == "" || input.Name == "" || input.Encoding == "" {
		utils.JSONResponse(w, 400, &FilesCreateResponse{
			Success: false,
			Message: "Invalid request",
		})
		return
	}

	// Create a new file struct
	file := &models.File{
		Encrypted: models.Encrypted{
			Encoding:        input.Encoding,
			Data:            input.Data,
			Schema:          "file",
			VersionMajor:    input.VersionMajor,
			VersionMinor:    input.VersionMinor,
			PGPFingerprints: input.PGPFingerprints,
		},
		Resource: models.MakeResource(session.Owner, input.Name),
	}

	// Insert the file into the database
	if err := env.Files.Insert(file); err != nil {
		utils.JSONResponse(w, 500, &FilesCreateResponse{
			Success: false,
			Message: "internal server error - FI/CR/01",
		})

		env.Log.WithFields(logrus.Fields{
			"error": err.Error(),
		}).Error("Could not insert a file into the database")
		return
	}

	utils.JSONResponse(w, 201, &FilesCreateResponse{
		Success: true,
		Message: "A new file was successfully created",
		File:    file,
	})
}
示例#3
0
func TestContactsRoute(t *testing.T) {
	Convey("Given a working account", t, func() {
		account := &models.Account{
			Resource: models.MakeResource("", "johnorange2"),
			Status:   "complete",
			AltEmail: "*****@*****.**",
		}
		err := account.SetPassword("fruityloops")
		So(err, ShouldBeNil)

		err = env.Accounts.Insert(account)
		So(err, ShouldBeNil)

		result, err := goreq.Request{
			Method:      "POST",
			Uri:         server.URL + "/tokens",
			ContentType: "application/json",
			Body: `{
				"type": "auth",
				"username": "******",
				"password": "******"
			}`,
		}.Do()
		So(err, ShouldBeNil)

		var response routes.TokensCreateResponse
		err = result.Body.FromJsonTo(&response)
		So(err, ShouldBeNil)

		So(response.Success, ShouldBeTrue)
		authToken := response.Token

		Convey("Creating a contact with missing parts should fail", func() {
			request := goreq.Request{
				Method:      "POST",
				Uri:         server.URL + "/contacts",
				ContentType: "application/json",
				Body: `{
					"data": "` + uniuri.NewLen(64) + `",
					"encoding": "json",
					"version_major": 1,
					"version_minor": 0,
					"pgp_fingerprints": ["` + uniuri.New() + `"]
				}`,
			}
			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.ContactsCreateResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Message, ShouldEqual, "Invalid request")
			So(response.Success, ShouldBeFalse)
		})

		Convey("Creating a contact with invalid input data should fail", func() {
			request := goreq.Request{
				Method:      "POST",
				Uri:         server.URL + "/contacts",
				ContentType: "application/json",
				Body:        "!@#!@#!@#",
			}
			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.ContactsCreateResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Message, ShouldEqual, "Invalid input format")
			So(response.Success, ShouldBeFalse)
		})

		Convey("Getting a non-owned contact should fail", func() {
			contact := &models.Contact{
				Encrypted: models.Encrypted{
					Encoding:     "json",
					Data:         uniuri.NewLen(64),
					Schema:       "contact",
					VersionMajor: 1,
					VersionMinor: 0,
				},
				Resource: models.MakeResource("not", uniuri.New()),
			}

			err := env.Contacts.Insert(contact)
			So(err, ShouldBeNil)

			request := goreq.Request{
				Method: "GET",
				Uri:    server.URL + "/contacts/" + contact.ID,
			}
			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.ContactsGetResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Success, ShouldBeFalse)
			So(response.Message, ShouldEqual, "Contact not found")

			Convey("Update of a not-owned contact should fail", func() {
				request := goreq.Request{
					Method:      "PUT",
					Uri:         server.URL + "/contacts/" + contact.ID,
					ContentType: "application/json",
					Body: `{
						"data": "` + uniuri.NewLen(64) + `",
						"name": "` + uniuri.New() + `",
						"encoding": "xml",
						"version_major": 8,
						"version_minor": 3
					}`,
				}
				request.AddHeader("Authorization", "Bearer "+authToken.ID)
				result, err := request.Do()
				So(err, ShouldBeNil)

				var response routes.ContactsUpdateResponse
				err = result.Body.FromJsonTo(&response)
				So(err, ShouldBeNil)

				So(response.Success, ShouldBeFalse)
				So(response.Message, ShouldEqual, "Contact not found")
			})

			Convey("Deleting it should fail", func() {
				request := goreq.Request{
					Method: "DELETE",
					Uri:    server.URL + "/contacts/" + contact.ID,
				}
				request.AddHeader("Authorization", "Bearer "+authToken.ID)
				result, err := request.Do()
				So(err, ShouldBeNil)

				var response routes.ContactsDeleteResponse
				err = result.Body.FromJsonTo(&response)
				So(err, ShouldBeNil)

				So(response.Success, ShouldBeFalse)
				So(response.Message, ShouldEqual, "Contact not found")
			})
		})

		Convey("Getting a non-existing contact should fail", func() {
			request := goreq.Request{
				Method: "GET",
				Uri:    server.URL + "/contacts/" + uniuri.New(),
			}
			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.ContactsGetResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Success, ShouldBeFalse)
			So(response.Message, ShouldEqual, "Contact not found")
		})

		Convey("Creating a contact should succeed", func() {
			request := goreq.Request{
				Method:      "POST",
				Uri:         server.URL + "/contacts",
				ContentType: "application/json",
				Body: `{
					"data": "` + uniuri.NewLen(64) + `",
					"name": "` + uniuri.New() + `",
					"encoding": "json",
					"version_major": 1,
					"version_minor": 0,
					"pgp_fingerprints": ["` + uniuri.New() + `"]
				}`,
			}
			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.ContactsCreateResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Message, ShouldEqual, "A new contact was successfully created")
			So(response.Success, ShouldBeTrue)
			So(response.Contact.ID, ShouldNotBeNil)

			contact := response.Contact

			Convey("The contact should be visible on the list", func() {
				request := goreq.Request{
					Method: "GET",
					Uri:    server.URL + "/contacts",
				}
				request.AddHeader("Authorization", "Bearer "+authToken.ID)
				result, err := request.Do()
				So(err, ShouldBeNil)

				var response routes.ContactsListResponse
				err = result.Body.FromJsonTo(&response)
				So(err, ShouldBeNil)

				So(len(*response.Contacts), ShouldBeGreaterThan, 0)
				So(response.Success, ShouldBeTrue)

				found := false
				for _, c := range *response.Contacts {
					if c.ID == contact.ID {
						found = true
						break
					}
				}

				So(found, ShouldBeTrue)
			})

			Convey("Getting that contact should succeed", func() {
				request := goreq.Request{
					Method: "GET",
					Uri:    server.URL + "/contacts/" + contact.ID,
				}
				request.AddHeader("Authorization", "Bearer "+authToken.ID)
				result, err := request.Do()
				So(err, ShouldBeNil)

				var response routes.ContactsGetResponse
				err = result.Body.FromJsonTo(&response)
				So(err, ShouldBeNil)

				So(response.Success, ShouldBeTrue)
				So(response.Contact.Name, ShouldEqual, contact.Name)
			})

			Convey("Updating that contact should succeed", func() {
				newName := uniuri.New()

				request := goreq.Request{
					Method:      "PUT",
					Uri:         server.URL + "/contacts/" + contact.ID,
					ContentType: "application/json",
					Body: `{
						"data": "` + uniuri.NewLen(64) + `",
						"name": "` + newName + `",
						"encoding": "xml",
						"version_major": 8,
						"version_minor": 3
					}`,
				}
				request.AddHeader("Authorization", "Bearer "+authToken.ID)
				result, err := request.Do()
				So(err, ShouldBeNil)

				var response routes.ContactsUpdateResponse
				err = result.Body.FromJsonTo(&response)
				So(err, ShouldBeNil)

				So(response.Success, ShouldBeTrue)
				So(response.Contact.Name, ShouldEqual, newName)
			})

			Convey("Deleting that contact should succeed", func() {
				request := goreq.Request{
					Method: "DELETE",
					Uri:    server.URL + "/contacts/" + contact.ID,
				}
				request.AddHeader("Authorization", "Bearer "+authToken.ID)
				result, err := request.Do()
				So(err, ShouldBeNil)

				var response routes.ContactsDeleteResponse
				err = result.Body.FromJsonTo(&response)
				So(err, ShouldBeNil)

				So(response.Success, ShouldBeTrue)
				So(response.Message, ShouldEqual, "Contact successfully removed")
			})
		})

		Convey("Update with invalid input should fail", func() {
			request := goreq.Request{
				Method:      "PUT",
				Uri:         server.URL + "/contacts/" + uniuri.New(),
				ContentType: "application/json",
				Body:        "123123!@#!@#",
			}
			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.ContactsUpdateResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Success, ShouldBeFalse)
			So(response.Message, ShouldEqual, "Invalid input format")
		})

		Convey("Update of a non-existing contact should fail", func() {
			request := goreq.Request{
				Method:      "PUT",
				Uri:         server.URL + "/contacts/gibberish",
				ContentType: "application/json",
				Body: `{
						"data": "` + uniuri.NewLen(64) + `",
						"name": "` + uniuri.New() + `",
						"encoding": "xml",
						"version_major": 8,
						"version_minor": 3
					}`,
			}
			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.ContactsUpdateResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Success, ShouldBeFalse)
			So(response.Message, ShouldEqual, "Contact not found")
		})

		Convey("Deleting a non-existing contact should fail", func() {
			request := goreq.Request{
				Method: "DELETE",
				Uri:    server.URL + "/contacts/gibberish",
			}
			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.ContactsDeleteResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Success, ShouldBeFalse)
			So(response.Message, ShouldEqual, "Contact not found")
		})
	})
}
示例#4
0
func TestKeysRoute(t *testing.T) {
	Convey("Given a working account", t, func() {
		account := &models.Account{
			Resource: models.MakeResource("", "johnorange4"),
			Status:   "complete",
			AltEmail: "*****@*****.**",
		}
		err := account.SetPassword("fruityloops")
		So(err, ShouldBeNil)

		err = env.Accounts.Insert(account)
		So(err, ShouldBeNil)

		result, err := goreq.Request{
			Method:      "POST",
			Uri:         server.URL + "/tokens",
			ContentType: "application/json",
			Body: `{
				"type": "auth",
				"username": "******",
				"password": "******"
			}`,
		}.Do()
		So(err, ShouldBeNil)

		var response routes.TokensCreateResponse
		err = result.Body.FromJsonTo(&response)
		So(err, ShouldBeNil)

		So(response.Success, ShouldBeTrue)
		authToken := response.Token

		Convey("Uploading a new key using an invalid JSON format should fail", func() {
			request := goreq.Request{
				Method:      "POST",
				Uri:         server.URL + "/keys",
				ContentType: "application/json",
				Body:        "!@#!@!@#",
			}
			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.KeysCreateResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Message, ShouldEqual, "Invalid input format")
			So(response.Success, ShouldBeFalse)
		})

		Convey("Uploading an invalid key should fail", func() {
			request := goreq.Request{
				Method:      "POST",
				Uri:         server.URL + "/keys",
				ContentType: "application/json",
				Body: `{
					"key": "hbnjmvnbhvm nbhm jhbjmnghnbgjvgbhvf bgvmj gvhnft"
				}`,
			}
			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.KeysCreateResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Message, ShouldEqual, "Invalid key format")
			So(response.Success, ShouldBeFalse)
		})

		Convey("Uploading a key should succeed", func() {
			request := goreq.Request{
				Method:      "POST",
				Uri:         server.URL + "/keys",
				ContentType: "application/json",
				Body: `{
			"key": "` + strings.Join(strings.Split(`-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1

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
=r/yh
-----END PGP PUBLIC KEY BLOCK-----`, "\n"), "\\n") + `"
		}`,
			}

			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.KeysCreateResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Message, ShouldEqual, "A new key has been successfully inserted")
			So(response.Success, ShouldBeTrue)
			So(response.Key.ID, ShouldNotBeNil)

			key := response.Key

			Convey("Key should be visible on the user's key list", func() {
				request := goreq.Request{
					Method: "GET",
					Uri:    server.URL + "/keys?user=johnorange4",
				}
				request.AddHeader("Authorization", "Bearer "+authToken.ID)
				result, err := request.Do()
				So(err, ShouldBeNil)

				var response routes.KeysListResponse
				err = result.Body.FromJsonTo(&response)
				So(err, ShouldBeNil)

				So(response.Success, ShouldBeTrue)
				So(len(*response.Keys), ShouldBeGreaterThan, 0)
			})

			Convey("Getting that key should succeed", func() {
				request := goreq.Request{
					Method: "GET",
					Uri:    server.URL + "/keys/" + key.ID,
				}
				request.AddHeader("Authorization", "Bearer "+authToken.ID)
				result, err := request.Do()
				So(err, ShouldBeNil)

				var response routes.KeysGetResponse
				err = result.Body.FromJsonTo(&response)
				So(err, ShouldBeNil)

				So(response.Success, ShouldBeTrue)
				So(response.Key.ID, ShouldEqual, key.ID)
			})
		})

		Convey("Listing keys without passing a username should fail", func() {
			request := goreq.Request{
				Method: "GET",
				Uri:    server.URL + "/keys",
			}
			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.KeysListResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Success, ShouldBeFalse)
			So(response.Message, ShouldEqual, "Invalid username")
		})

		Convey("Getting a non-existing key should fail", func() {
			request := goreq.Request{
				Method: "GET",
				Uri:    server.URL + "/keys/123",
			}
			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.KeysGetResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Success, ShouldBeFalse)
			So(response.Message, ShouldEqual, "Requested key does not exist on our server")
		})
	})
}
示例#5
0
// EmailsCreate sends a new email
func EmailsCreate(c web.C, w http.ResponseWriter, r *http.Request) {
	// Decode the request
	var input EmailsCreateRequest
	err := utils.ParseRequest(r, &input)
	if err != nil {
		env.Log.WithFields(logrus.Fields{
			"error": err.Error(),
		}).Warn("Unable to decode a request")

		utils.JSONResponse(w, 400, &EmailsCreateResponse{
			Success: false,
			Message: "Invalid input format",
		})
		return
	}

	// Fetch the current session from the middleware
	session := c.Env["token"].(*models.Token)

	// Ensure that the kind is valid
	if input.Kind != "raw" && input.Kind != "manifest" && input.Kind != "pgpmime" {
		utils.JSONResponse(w, 400, &EmailsCreateResponse{
			Success: false,
			Message: "Invalid email encryption kind",
		})
		return
	}

	// Ensure that there's at least one recipient and that there's body
	if len(input.To) == 0 || input.Body == "" {
		utils.JSONResponse(w, 400, &EmailsCreateResponse{
			Success: false,
			Message: "Invalid email",
		})
		return
	}

	if input.Files != nil && len(input.Files) > 0 {
		// Check rights to files
		files, err := env.Files.GetFiles(input.Files...)
		if err != nil {
			utils.JSONResponse(w, 500, &EmailsCreateResponse{
				Success: false,
				Message: "Unable to fetch emails",
			})
			return
		}
		for _, file := range files {
			if file.Owner != session.Owner {
				utils.JSONResponse(w, 403, &EmailsCreateResponse{
					Success: false,
					Message: "You are not the owner of file " + file.ID,
				})
				return
			}
		}
	}

	// Create an email resource
	resource := models.MakeResource(session.Owner, input.Subject)

	// Generate metadata for manifests
	if input.Kind == "manifest" {
		resource.Name = "Encrypted message (" + resource.ID + ")"
	}

	// Fetch the user object from the database
	account, err := env.Accounts.GetTokenOwner(c.Env["token"].(*models.Token))
	if err != nil {
		// The session refers to a non-existing user
		env.Log.WithFields(logrus.Fields{
			"id":    session.ID,
			"error": err.Error(),
		}).Warn("Valid session referred to a removed account")

		utils.JSONResponse(w, 410, &EmailsCreateResponse{
			Success: false,
			Message: "Account disabled",
		})
		return
	}

	// Get the "Sent" label's ID
	var label *models.Label
	err = env.Labels.WhereAndFetchOne(map[string]interface{}{
		"name":    "Sent",
		"builtin": true,
		"owner":   account.ID,
	}, &label)
	if err != nil {
		env.Log.WithFields(logrus.Fields{
			"id":    account.ID,
			"error": err.Error(),
		}).Warn("Account has no sent label")

		utils.JSONResponse(w, 410, &EmailsCreateResponse{
			Success: false,
			Message: "Misconfigured account",
		})
		return
	}

	if input.From != "" {
		// Parse the from field
		from, err := mail.ParseAddress(input.From)
		if err != nil {
			utils.JSONResponse(w, 400, &EmailsCreateResponse{
				Success: false,
				Message: "Invalid email.From",
			})
			return
		}

		// We have a specified address
		if from.Address != "" {
			parts := strings.SplitN(from.Address, "@", 2)

			if parts[1] != env.Config.EmailDomain {
				utils.JSONResponse(w, 400, &EmailsCreateResponse{
					Success: false,
					Message: "Invalid email.From (invalid domain)",
				})
				return
			}

			address, err := env.Addresses.GetAddress(parts[0])
			if err != nil {
				utils.JSONResponse(w, 400, &EmailsCreateResponse{
					Success: false,
					Message: "Invalid email.From (invalid username)",
				})
				return
			}

			if address.Owner != account.ID {
				utils.JSONResponse(w, 400, &EmailsCreateResponse{
					Success: false,
					Message: "Invalid email.From (address not owned)",
				})
				return
			}
		}
	} else {
		displayName := ""

		if x, ok := account.Settings.(map[string]interface{}); ok {
			if y, ok := x["displayName"]; ok {
				if z, ok := y.(string); ok {
					displayName = z
				}
			}
		}

		addr := &mail.Address{
			Name:    displayName,
			Address: account.StyledName + "@" + env.Config.EmailDomain,
		}

		input.From = addr.String()
	}

	// Check if Thread is set
	if input.Thread != "" {
		// todo: make it an actual exists check to reduce lan bandwidth
		thread, err := env.Threads.GetThread(input.Thread)
		if err != nil {
			env.Log.WithFields(logrus.Fields{
				"id":    input.Thread,
				"error": err.Error(),
			}).Warn("Cannot retrieve a thread")

			utils.JSONResponse(w, 400, &EmailsCreateResponse{
				Success: false,
				Message: "Invalid thread",
			})
			return
		}

		// update thread.secure depending on email's kind
		if (input.Kind == "raw" && thread.Secure == "all") ||
			(input.Kind == "manifest" && thread.Secure == "none") ||
			(input.Kind == "pgpmime" && thread.Secure == "none") {
			if err := env.Threads.UpdateID(thread.ID, map[string]interface{}{
				"secure": "some",
			}); err != nil {
				env.Log.WithFields(logrus.Fields{
					"id":    input.Thread,
					"error": err.Error(),
				}).Warn("Cannot update a thread")

				utils.JSONResponse(w, 400, &EmailsCreateResponse{
					Success: false,
					Message: "Unable to update the thread",
				})
				return
			}
		}
	} else {
		secure := "all"
		if input.Kind == "raw" {
			secure = "none"
		}

		thread := &models.Thread{
			Resource:    models.MakeResource(account.ID, "Encrypted thread"),
			Emails:      []string{resource.ID},
			Labels:      []string{label.ID},
			Members:     append(append(input.To, input.CC...), input.BCC...),
			IsRead:      true,
			SubjectHash: input.SubjectHash,
			Secure:      secure,
		}

		err := env.Threads.Insert(thread)
		if err != nil {
			utils.JSONResponse(w, 500, &EmailsCreateResponse{
				Success: false,
				Message: "Unable to create a new thread",
			})

			env.Log.WithFields(logrus.Fields{
				"error": err.Error(),
			}).Error("Unable to create a new thread")
			return
		}

		input.Thread = thread.ID
	}

	// Calculate the message ID
	idHash := sha256.Sum256([]byte(resource.ID))
	messageID := hex.EncodeToString(idHash[:]) + "@" + env.Config.EmailDomain

	// Create a new email struct
	email := &models.Email{
		Resource:  resource,
		MessageID: messageID,

		Kind:   input.Kind,
		Thread: input.Thread,

		From: input.From,
		To:   input.To,
		CC:   input.CC,
		BCC:  input.BCC,

		PGPFingerprints: input.PGPFingerprints,
		Manifest:        input.Manifest,
		Body:            input.Body,
		Files:           input.Files,

		ContentType: input.ContentType,
		ReplyTo:     input.ReplyTo,

		Status: "queued",
	}

	// Insert the email into the database
	if err := env.Emails.Insert(email); err != nil {
		utils.JSONResponse(w, 500, &EmailsCreateResponse{
			Success: false,
			Message: "internal server error - EM/CR/01",
		})

		env.Log.WithFields(logrus.Fields{
			"error": err.Error(),
		}).Error("Could not insert an email into the database")
		return
	}

	// I'm going to whine at this part, as we are doubling the email sending code

	// Check if To contains lavaboom emails
	/*for _, address := range email.To {
		parts := strings.SplitN(address, "@", 2)
		if parts[1] == env.Config.EmailDomain {
			go sendEmail(parts[0], email)
		}
	}

	// Check if CC contains lavaboom emails
	for _, address := range email.CC {
		parts := strings.SplitN(address, "@", 2)
		if parts[1] == env.Config.EmailDomain {
			go sendEmail(parts[0], email)
		}
	}

	// Check if BCC contains lavaboom emails
	for _, address := range email.BCC {
		parts := strings.SplitN(address, "@", 2)
		if parts[1] == env.Config.EmailDomain {
			go sendEmail(parts[0], email)
		}
	}*/

	// Add a send request to the queue
	err = env.Producer.Publish("send_email", []byte(`"`+email.ID+`"`))
	if err != nil {
		utils.JSONResponse(w, 500, &EmailsCreateResponse{
			Success: false,
			Message: "internal server error - EM/CR/03",
		})

		env.Log.WithFields(logrus.Fields{
			"error": err.Error(),
		}).Error("Could not publish an email send request")
		return
	}

	utils.JSONResponse(w, 201, &EmailsCreateResponse{
		Success: true,
		Created: []string{email.ID},
	})
}
示例#6
0
func TestLabelsRoute(t *testing.T) {
	Convey("Given a working account", t, func() {
		account := &models.Account{
			Resource: models.MakeResource("", "johnorange2"),
			Status:   "complete",
			AltEmail: "*****@*****.**",
		}
		err := account.SetPassword("fruityloops")
		So(err, ShouldBeNil)

		err = env.Accounts.Insert(account)
		So(err, ShouldBeNil)

		result, err := goreq.Request{
			Method:      "POST",
			Uri:         server.URL + "/tokens",
			ContentType: "application/json",
			Body: `{
				"type": "auth",
				"username": "******",
				"password": "******"
			}`,
		}.Do()
		So(err, ShouldBeNil)

		var response routes.TokensCreateResponse
		err = result.Body.FromJsonTo(&response)
		So(err, ShouldBeNil)

		So(response.Success, ShouldBeTrue)
		authToken := response.Token

		Convey("Creating a new label using invalid input should fail", func() {
			request := goreq.Request{
				Method:      "POST",
				Uri:         server.URL + "/labels",
				ContentType: "application/json",
				Body:        "!@#!@!@#",
			}
			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.LabelsCreateResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Message, ShouldEqual, "Invalid input format")
			So(response.Success, ShouldBeFalse)
		})

		Convey("Updating a label using invalid input should fail", func() {
			request := goreq.Request{
				Method:      "PUT",
				Uri:         server.URL + "/labels/anything",
				ContentType: "application/json",
				Body:        "!@#!@!@#",
			}
			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.LabelsUpdateResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Message, ShouldEqual, "Invalid input format")
			So(response.Success, ShouldBeFalse)
		})

		Convey("Creating a new label without enough information should fail", func() {
			request := goreq.Request{
				Method:      "POST",
				Uri:         server.URL + "/labels",
				ContentType: "application/json",
				Body:        "{}",
			}
			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.LabelsCreateResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Message, ShouldEqual, "Invalid request")
			So(response.Success, ShouldBeFalse)
		})

		Convey("Getting a non-existing label should fail", func() {
			request := goreq.Request{
				Method: "GET",
				Uri:    server.URL + "/labels/nonexisting",
			}
			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.LabelsCreateResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Message, ShouldEqual, "Label not found")
			So(response.Success, ShouldBeFalse)
		})

		Convey("Updating a non-existing label should fail", func() {
			request := goreq.Request{
				Method:      "PUT",
				Uri:         server.URL + "/labels/anything",
				ContentType: "application/json",
				Body:        "{}",
			}
			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.LabelsUpdateResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Message, ShouldEqual, "Label not found")
			So(response.Success, ShouldBeFalse)
		})

		Convey("Deleting a non-existing label should fail", func() {
			request := goreq.Request{
				Method: "DELETE",
				Uri:    server.URL + "/labels/anything",
			}
			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.LabelsDeleteResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Message, ShouldEqual, "Label not found")
			So(response.Success, ShouldBeFalse)
		})

		Convey("Getting a non-owned label should fail", func() {
			label := &models.Label{
				Resource: models.MakeResource("not", uniuri.New()),
				Builtin:  false,
			}

			err := env.Labels.Insert(label)
			So(err, ShouldBeNil)

			request := goreq.Request{
				Method: "GET",
				Uri:    server.URL + "/labels/" + label.ID,
			}
			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.LabelsGetResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Message, ShouldEqual, "Label not found")
			So(response.Success, ShouldBeFalse)

			Convey("Updating it should fail", func() {
				request := goreq.Request{
					Method:      "PUT",
					Uri:         server.URL + "/labels/" + label.ID,
					ContentType: "application/json",
					Body:        "{}",
				}
				request.AddHeader("Authorization", "Bearer "+authToken.ID)
				result, err := request.Do()
				So(err, ShouldBeNil)

				var response routes.LabelsUpdateResponse
				err = result.Body.FromJsonTo(&response)
				So(err, ShouldBeNil)

				So(response.Message, ShouldEqual, "Label not found")
				So(response.Success, ShouldBeFalse)
			})

			Convey("Deleting it should fail", func() {
				request := goreq.Request{
					Method: "DELETE",
					Uri:    server.URL + "/labels/" + label.ID,
				}
				request.AddHeader("Authorization", "Bearer "+authToken.ID)
				result, err := request.Do()
				So(err, ShouldBeNil)

				var response routes.LabelsDeleteResponse
				err = result.Body.FromJsonTo(&response)
				So(err, ShouldBeNil)

				So(response.Message, ShouldEqual, "Label not found")
				So(response.Success, ShouldBeFalse)
			})
		})

		Convey("Creating a label should succeed", func() {
			request := goreq.Request{
				Method:      "POST",
				Uri:         server.URL + "/labels",
				ContentType: "application/json",
				Body: `{
					"name": "` + uniuri.New() + `"
				}`,
			}
			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.LabelsCreateResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Label.Name, ShouldNotBeEmpty)
			So(response.Success, ShouldBeTrue)

			label := response.Label

			Convey("That label should be visible on the labels list", func() {
				request := goreq.Request{
					Method: "GET",
					Uri:    server.URL + "/labels",
				}
				request.AddHeader("Authorization", "Bearer "+authToken.ID)
				result, err := request.Do()
				So(err, ShouldBeNil)

				var response routes.LabelsListResponse
				err = result.Body.FromJsonTo(&response)
				So(err, ShouldBeNil)

				So(response.Message, ShouldBeEmpty)
				So(len(*response.Labels), ShouldBeGreaterThan, 0)
				So(response.Success, ShouldBeTrue)
			})

			Convey("Getting that label should succeed", func() {
				request := goreq.Request{
					Method: "GET",
					Uri:    server.URL + "/labels/" + label.ID,
				}
				request.AddHeader("Authorization", "Bearer "+authToken.ID)
				result, err := request.Do()
				So(err, ShouldBeNil)

				var response routes.LabelsGetResponse
				err = result.Body.FromJsonTo(&response)
				So(err, ShouldBeNil)

				So(response.Label.ID, ShouldEqual, label.ID)
				So(response.Success, ShouldBeTrue)
			})

			Convey("Updating that label should succeed", func() {
				request := goreq.Request{
					Method:      "PUT",
					Uri:         server.URL + "/labels/" + label.ID,
					ContentType: "application/json",
					Body: `{
						"name": "test123"
					}`,
				}
				request.AddHeader("Authorization", "Bearer "+authToken.ID)
				result, err := request.Do()
				So(err, ShouldBeNil)

				var response routes.LabelsUpdateResponse
				err = result.Body.FromJsonTo(&response)
				So(err, ShouldBeNil)

				So(response.Label.Name, ShouldEqual, "test123")
				So(response.Success, ShouldBeTrue)
			})

			Convey("Deleting that label should succeed", func() {
				request := goreq.Request{
					Method: "DELETE",
					Uri:    server.URL + "/labels/" + label.ID,
				}
				request.AddHeader("Authorization", "Bearer "+authToken.ID)
				result, err := request.Do()
				So(err, ShouldBeNil)

				var response routes.LabelsDeleteResponse
				err = result.Body.FromJsonTo(&response)
				So(err, ShouldBeNil)

				So(response.Message, ShouldEqual, "Label successfully removed")
				So(response.Success, ShouldBeTrue)
			})
		})
	})
}
示例#7
0
// AccountsCreate creates a new account in the system.
func AccountsCreate(w http.ResponseWriter, r *http.Request) {
	// Decode the request
	var input AccountsCreateRequest
	err := utils.ParseRequest(r, &input)
	if err != nil {
		env.Log.WithFields(logrus.Fields{
			"error": err.Error(),
		}).Warn("Unable to decode a request")

		utils.JSONResponse(w, 400, &AccountsCreateResponse{
			Success: false,
			Message: "Invalid input format",
		})
		return
	}

	// TODO: Sanitize the username
	// TODO: Hash the password if it's not hashed already

	// Accounts flow:
	// 1) POST /accounts {username, alt_email}             => status = registered
	// 2) POST /accounts {username, invite_code}           => checks invite_code validity
	// 3) POST /accounts {username, invite_code, password} => status = setup
	requestType := "unknown"
	if input.Username != "" && input.Password == "" && input.AltEmail != "" && input.InviteCode == "" {
		requestType = "register"
	} else if input.Username != "" && input.Password == "" && input.AltEmail == "" && input.InviteCode != "" {
		requestType = "verify"
	} else if input.Username != "" && input.Password != "" && input.AltEmail == "" && input.InviteCode != "" {
		requestType = "setup"
	}

	// "unknown" requests are empty and invalid
	if requestType == "unknown" {
		utils.JSONResponse(w, 400, &AccountsCreateResponse{
			Success: false,
			Message: "Invalid request",
		})
		return
	}

	if requestType == "register" {
		// Normalize the username
		input.Username = utils.NormalizeUsername(input.Username)

		// Validate the username
		if len(input.Username) < 3 || len(utils.RemoveDots(input.Username)) < 3 || len(input.Username) > 32 {
			utils.JSONResponse(w, 400, &AccountsCreateResponse{
				Success: false,
				Message: "Invalid username - it has to be at least 3 and at max 32 characters long",
			})
			return
		}

		// Ensure that the username is not used in address table
		if used, err := env.Addresses.GetAddress(utils.RemoveDots(input.Username)); err == nil || used != nil {
			utils.JSONResponse(w, 409, &AccountsCreateResponse{
				Success: false,
				Message: "Username already used",
			})
			return
		}

		// Then check it in the accounts table
		if ok, err := env.Accounts.IsUsernameUsed(utils.RemoveDots(input.Username)); ok || err != nil {
			utils.JSONResponse(w, 409, &AccountsCreateResponse{
				Success: false,
				Message: "Username already used",
			})
			return
		}

		// Also check that the email is unique
		if used, err := env.Accounts.IsEmailUsed(input.AltEmail); err != nil || used {
			if err != nil {
				env.Log.WithFields(logrus.Fields{
					"error": err.Error(),
				}).Error("Unable to lookup registered accounts for emails")
			}

			utils.JSONResponse(w, 409, &AccountsCreateResponse{
				Success: false,
				Message: "Email already used",
			})
			return
		}

		// Both username and email are filled, so we can create a new account.
		account := &models.Account{
			Resource:   models.MakeResource("", utils.RemoveDots(input.Username)),
			StyledName: input.Username,
			Type:       "beta", // Is this the proper value?
			AltEmail:   input.AltEmail,
			Status:     "registered",
		}

		// Try to save it in the database
		if err := env.Accounts.Insert(account); err != nil {
			utils.JSONResponse(w, 500, &AccountsCreateResponse{
				Success: false,
				Message: "Internal server error - AC/CR/02",
			})

			env.Log.WithFields(logrus.Fields{
				"error": err.Error(),
			}).Error("Could not insert an user into the database")
			return
		}

		// TODO: Send emails here. Depends on @andreis work.

		// Return information about the account
		utils.JSONResponse(w, 201, &AccountsCreateResponse{
			Success: true,
			Message: "Your account has been added to the beta queue",
			Account: account,
		})
		return
	} else if requestType == "verify" {
		// We're pretty much checking whether an invitation code can be used by the user
		input.Username = utils.RemoveDots(
			utils.NormalizeUsername(input.Username),
		)

		// Fetch the user from database
		account, err := env.Accounts.FindAccountByName(input.Username)
		if err != nil {
			env.Log.WithFields(logrus.Fields{
				"error":    err.Error(),
				"username": input.Username,
			}).Warn("User not found in the database")

			utils.JSONResponse(w, 400, &AccountsCreateResponse{
				Success: false,
				Message: "Invalid username",
			})
			return
		}

		// Fetch the token from the database
		token, err := env.Tokens.GetToken(input.InviteCode)
		if err != nil {
			env.Log.WithFields(logrus.Fields{
				"error": err.Error(),
			}).Warn("Unable to fetch a registration token from the database")

			utils.JSONResponse(w, 400, &AccountsCreateResponse{
				Success: false,
				Message: "Invalid invitation code",
			})
			return
		}

		// Ensure that the invite code was given to this particular user.
		if token.Owner != account.ID {
			env.Log.WithFields(logrus.Fields{
				"user_id": account.ID,
				"owner":   token.Owner,
			}).Warn("Not owned invitation code used by an user")

			utils.JSONResponse(w, 400, &AccountsCreateResponse{
				Success: false,
				Message: "Invalid invitation code",
			})
			return
		}

		// Ensure that the token's type is valid
		if token.Type != "verify" {
			utils.JSONResponse(w, 400, &AccountsCreateResponse{
				Success: false,
				Message: "Invalid invitation code",
			})
			return
		}

		// Check if it's expired
		if token.Expired() {
			utils.JSONResponse(w, 400, &AccountsCreateResponse{
				Success: false,
				Message: "Expired invitation code",
			})
			return
		}

		// Ensure that the account is "registered"
		if account.Status != "registered" {
			utils.JSONResponse(w, 403, &AccountsCreateResponse{
				Success: true,
				Message: "This account was already configured",
			})
			return
		}

		// Everything is fine, return it.
		utils.JSONResponse(w, 200, &AccountsCreateResponse{
			Success: true,
			Message: "Valid token was provided",
		})
		return
	} else if requestType == "setup" {
		// User is setting the password in the setup wizard. This should be one of the first steps,
		// as it's required for him to acquire an authentication token to configure their account.
		input.Username = utils.RemoveDots(
			utils.NormalizeUsername(input.Username),
		)

		// Fetch the user from database
		account, err := env.Accounts.FindAccountByName(input.Username)
		if err != nil {
			env.Log.WithFields(logrus.Fields{
				"error":    err.Error(),
				"username": input.Username,
			}).Warn("User not found in the database")

			utils.JSONResponse(w, 400, &AccountsCreateResponse{
				Success: false,
				Message: "Invalid username",
			})
			return
		}

		// Fetch the token from the database
		token, err := env.Tokens.GetToken(input.InviteCode)
		if err != nil {
			env.Log.WithFields(logrus.Fields{
				"error": err.Error(),
			}).Warn("Unable to fetch a registration token from the database")

			utils.JSONResponse(w, 400, &AccountsCreateResponse{
				Success: false,
				Message: "Invalid invitation code",
			})
			return
		}

		// Ensure that the invite code was given to this particular user.
		if token.Owner != account.ID {
			env.Log.WithFields(logrus.Fields{
				"user_id": account.ID,
				"owner":   token.Owner,
			}).Warn("Not owned invitation code used by an user")

			utils.JSONResponse(w, 400, &AccountsCreateResponse{
				Success: false,
				Message: "Invalid invitation code",
			})
			return
		}

		// Ensure that the token's type is valid
		if token.Type != "verify" {
			utils.JSONResponse(w, 400, &AccountsCreateResponse{
				Success: false,
				Message: "Invalid invitation code",
			})
			return
		}

		// Check if it's expired
		if token.Expired() {
			utils.JSONResponse(w, 400, &AccountsCreateResponse{
				Success: false,
				Message: "Expired invitation code",
			})
			return
		}

		// Ensure that the account is "registered"
		if account.Status != "registered" {
			utils.JSONResponse(w, 403, &AccountsCreateResponse{
				Success: true,
				Message: "This account was already configured",
			})
			return
		}

		// Our token is fine, next part: password.

		// Ensure that user has chosen a secure password (check against 10k most used)
		if env.PasswordBF.TestString(input.Password) {
			utils.JSONResponse(w, 403, &AccountsCreateResponse{
				Success: false,
				Message: "Weak password",
			})
			return
		}

		// We can't really make more checks on the password, user could as well send us a hash
		// of a simple password, but we assume that no developer is that stupid (actually,
		// considering how many people upload their private keys and AWS credentials, I'm starting
		// to doubt the competence of some so-called "web deyvelopayrs")

		// Set the password
		err = account.SetPassword(input.Password)
		if err != nil {
			utils.JSONResponse(w, 500, &AccountsCreateResponse{
				Success: false,
				Message: "Internal server error - AC/CR/01",
			})

			env.Log.WithFields(logrus.Fields{
				"error": err.Error(),
			}).Error("Unable to hash the password")
			return
		}

		account.Status = "setup"

		// Create labels
		err = env.Labels.Insert([]*models.Label{
			&models.Label{
				Resource: models.MakeResource(account.ID, "Inbox"),
				Builtin:  true,
			},
			&models.Label{
				Resource: models.MakeResource(account.ID, "Sent"),
				Builtin:  true,
			},
			&models.Label{
				Resource: models.MakeResource(account.ID, "Drafts"),
				Builtin:  true,
			},
			&models.Label{
				Resource: models.MakeResource(account.ID, "Trash"),
				Builtin:  true,
			},
			&models.Label{
				Resource: models.MakeResource(account.ID, "Spam"),
				Builtin:  true,
			},
			&models.Label{
				Resource: models.MakeResource(account.ID, "Starred"),
				Builtin:  true,
			},
		})
		if err != nil {
			utils.JSONResponse(w, 500, &AccountsCreateResponse{
				Success: false,
				Message: "Internal server error - AC/CR/03",
			})

			env.Log.WithFields(logrus.Fields{
				"error": err.Error(),
			}).Error("Could not insert labels into the database")
			return
		}

		// Add a new mapping
		err = env.Addresses.Insert(&models.Address{
			Resource: models.Resource{
				ID:           account.Name,
				DateCreated:  time.Now(),
				DateModified: time.Now(),
				Owner:        account.ID,
			},
		})
		if err != nil {
			utils.JSONResponse(w, 500, &AccountsCreateResponse{
				Success: false,
				Message: "Unable to create a new address mapping",
			})

			env.Log.WithFields(logrus.Fields{
				"error": err.Error(),
			}).Error("Could not insert an address mapping into db")
			return
		}

		// Update the account
		err = env.Accounts.UpdateID(account.ID, account)
		if err != nil {
			env.Log.WithFields(logrus.Fields{
				"error": err.Error(),
				"id":    account.ID,
			}).Error("Unable to update an account")

			utils.JSONResponse(w, 500, &AccountsCreateResponse{
				Success: false,
				Message: "Unable to update the account",
			})
			return
		}

		// Remove the token and return a response
		err = env.Tokens.DeleteID(input.InviteCode)
		if err != nil {
			env.Log.WithFields(logrus.Fields{
				"error": err.Error(),
				"id":    input.InviteCode,
			}).Error("Could not remove the token from database")
		}

		utils.JSONResponse(w, 200, &AccountsCreateResponse{
			Success: true,
			Message: "Your account has been initialized successfully",
			Account: account,
		})
		return
	}
}
示例#8
0
func create(w http.ResponseWriter, req *http.Request) {
	// Decode the body
	var msg createInput
	err := json.NewDecoder(req.Body).Decode(&msg)
	if err != nil {
		writeJSON(w, errorMsg{
			Success: false,
			Message: err.Error(),
		})
		return
	}

	// Fetch the invite from database
	cursor, err := r.Db(*rethinkName).Table("invites").Get(msg.Token).Run(session)
	if err != nil {
		writeJSON(w, errorMsg{
			Success: false,
			Message: err.Error(),
		})
		return
	}
	var invite *Invite
	err = cursor.One(&invite)
	if err != nil {
		writeJSON(w, errorMsg{
			Success: false,
			Message: err.Error(),
		})
		return
	}

	// Normalize the username
	styledName := msg.Username
	msg.Username = utils.RemoveDots(utils.NormalizeUsername(msg.Username))

	var account *models.Account

	// If there's no account id, then simply check args
	if invite.AccountID == "" {
		if !govalidator.IsEmail(msg.Email) {
			writeJSON(w, errorMsg{
				Success: false,
				Message: "Invalid email address",
			})
			return
		}

		// Check if address is taken
		cursor, err = r.Db(*rethinkAPIName).Table("addresses").Get(msg.Username).Run(session)
		if err == nil || cursor != nil {
			writeJSON(w, freeMsg{
				Success:       false,
				UsernameTaken: true,
			})
			return
		}

		// Check if email is used
		cursor, err = r.Db(*rethinkAPIName).Table("accounts").
			GetAllByIndex("alt_email", msg.Email).
			Filter(r.Row.Field("id").Ne(r.Expr(invite.AccountID))).
			Count().Run(session)
		if err != nil {
			writeJSON(w, errorMsg{
				Success: false,
				Message: err.Error(),
			})
			return
		}
		var emailCount int
		err = cursor.One(&emailCount)
		if err != nil {
			writeJSON(w, errorMsg{
				Success: false,
				Message: err.Error(),
			})
			return
		}
		if emailCount > 0 {
			writeJSON(w, freeMsg{
				Success:   false,
				EmailUsed: true,
			})
			return
		}

		// Prepare a new account
		account = &models.Account{
			Resource:   models.MakeResource("", msg.Username),
			AltEmail:   msg.Email,
			StyledName: styledName,
			Status:     "registered",
			Type:       "supporter",
		}

		// Update the invite
		invite.AccountID = account.ID
		err = r.Db(*rethinkName).Table("invites").Get(invite.ID).Update(map[string]interface{}{
			"account_id": invite.AccountID,
		}).Exec(session)
		if err != nil {
			writeJSON(w, errorMsg{
				Success: false,
				Message: err.Error(),
			})
			return
		}

		// Insert the account into db
		err = r.Db(*rethinkAPIName).Table("accounts").Insert(account).Exec(session)
		if err != nil {
			writeJSON(w, errorMsg{
				Success: false,
				Message: err.Error(),
			})
			return
		}
	} else {
		cursor, err = r.Db(*rethinkAPIName).Table("accounts").Get(invite.AccountID).Run(session)
		if err != nil {
			writeJSON(w, errorMsg{
				Success: false,
				Message: err.Error(),
			})
			return
		}
		defer cursor.Close()
		if err := cursor.One(&account); err != nil {
			writeJSON(w, errorMsg{
				Success: false,
				Message: err.Error(),
			})
			return
		}

		if account.Name != "" && account.Name != msg.Username {
			writeJSON(w, errorMsg{
				Success: false,
				Message: "Invalid username",
			})
			return
		} else if account.Name == "" {
			// Check if address is taken
			cursor, err = r.Db(*rethinkAPIName).Table("addresses").Get(msg.Username).Run(session)
			if err == nil || cursor != nil {
				writeJSON(w, errorMsg{
					Success: false,
					Message: "Username is taken",
				})
				return
			}
		}

		if account.AltEmail != "" && account.AltEmail != msg.Email {
			writeJSON(w, errorMsg{
				Success: false,
				Message: "Invalid email",
			})
			return
		}

		if account.AltEmail == "" {
			if !govalidator.IsEmail(msg.Email) {
				writeJSON(w, errorMsg{
					Success: false,
					Message: "Invalid email address",
				})
				return
			}

			// Check if email is used
			cursor, err = r.Db(*rethinkAPIName).Table("accounts").
				GetAllByIndex("alt_email", msg.Email).
				Filter(r.Row.Field("id").Ne(r.Expr(invite.AccountID))).
				Count().Run(session)
			if err != nil {
				writeJSON(w, errorMsg{
					Success: false,
					Message: err.Error(),
				})
				return
			}
			defer cursor.Close()

			var emailCount int
			err = cursor.One(&emailCount)
			if err != nil {
				writeJSON(w, errorMsg{
					Success: false,
					Message: err.Error(),
				})
				return
			}
			if emailCount > 0 {
				writeJSON(w, errorMsg{
					Success: false,
					Message: "Email is already used",
				})
				return
			}
		}

		if err := r.Db(*rethinkAPIName).Table("accounts").Get(invite.AccountID).Update(map[string]interface{}{
			"type": "supporter",
		}).Exec(session); err != nil {
			writeJSON(w, errorMsg{
				Success: false,
				Message: err.Error(),
			})
			return
		}
	}

	// Generate a new invite token for the user
	token := &models.Token{
		Resource: models.MakeResource(account.ID, "Invitation token from invite-api"),
		Type:     "verify",
		Expiring: models.Expiring{
			ExpiryDate: time.Now().UTC().Add(time.Hour * 12),
		},
	}

	// Insert it into db
	err = r.Db(*rethinkAPIName).Table("tokens").Insert(token).Exec(session)
	if err != nil {
		writeJSON(w, errorMsg{
			Success: false,
			Message: err.Error(),
		})
		return
	}

	// Here be dragons. Thou art forewarned.
	/*go func() {
		// Watch the changes
		cursor, err := r.Db(*rethinkAPIName).Table("accounts").Get(account.ID).Changes().Run(session)
		if err != nil {
			log.Print("Error while watching changes of user " + account.Name + " - " + err.Error())
			return
		}
		defer cursor.Close()

		// Generate a timeout "flag"
		ts := uniuri.New()

		// Read them
		c := make(chan struct{})
		go func() {
			var change struct {
				NewValue map[string]interface{} `gorethink:"new_val"`
			}
			for cursor.Next(&change) {
				if status, ok := change.NewValue["status"]; ok {
					if x, ok := status.(string); ok && x == "setup" {
						c <- struct{}{}
						return
					}
				}

				if iat, ok := change.NewValue["_invite_api_timeout"]; ok {
					if x, ok := iat.(string); ok && x == ts {
						log.Print("Account setup watcher timeout for name " + account.Name)
						return
					}
				}
			}
		}()

		// Block the goroutine
		select {
		case <-c:
			if err := r.Db(*rethinkName).Table("invites").Get(invite.ID).Delete().Exec(session); err != nil {
				log.Print("Unable to delete an invite. " + invite.ID + " - " + account.ID)
				return
			}
			return
		case <-time.After(12 * time.Hour):
			if err := r.Db(*rethinkAPIName).Table("accounts").Get(account.ID).Update(map[string]interface{}{
				"_invite_api_timeout": ts,
			}).Exec(session); err != nil {
				log.Print("Failed to make a goroutine timeout. " + account.ID)
			}
			return
		}
	}()*/

	// jk f**k that
	if err := r.Db(*rethinkName).Table("invites").Get(invite.ID).Delete().Exec(session); err != nil {
		log.Print("Unable to delete an invite. " + invite.ID + " - " + account.ID)
		return
	}

	// Return the token
	writeJSON(w, createMsg{
		Success: true,
		Code:    token.ID,
	})
}
示例#9
0
文件: keys.go 项目: carriercomm/api-1
// KeysCreate appens a new key to the server
func KeysCreate(c web.C, w http.ResponseWriter, r *http.Request) {
	// Decode the request
	var input KeysCreateRequest
	err := utils.ParseRequest(r, &input)
	if err != nil {
		env.Log.WithFields(logrus.Fields{
			"error": err.Error(),
		}).Warn("Unable to decode a request")

		utils.JSONResponse(w, 409, &KeysCreateResponse{
			Success: false,
			Message: "Invalid input format",
		})
		return
	}

	// Get the session
	session := c.Env["token"].(*models.Token)

	// Parse the armored key
	entityList, err := openpgp.ReadArmoredKeyRing(strings.NewReader(input.Key))
	if err != nil {
		utils.JSONResponse(w, 409, &KeysCreateResponse{
			Success: false,
			Message: "Invalid key format",
		})

		env.Log.WithFields(logrus.Fields{
			"error": err.Error(),
			"list":  entityList,
		}).Warn("Cannot parse an armored key")
		return
	}

	// Parse using armor pkg
	block, err := armor.Decode(strings.NewReader(input.Key))
	if err != nil {
		utils.JSONResponse(w, 409, &KeysCreateResponse{
			Success: false,
			Message: "Invalid key format",
		})

		env.Log.WithFields(logrus.Fields{
			"error": err.Error(),
			"list":  entityList,
		}).Warn("Cannot parse an armored key #2")
		return
	}

	// Get the account from db
	account, err := env.Accounts.GetAccount(session.Owner)
	if err != nil {
		utils.JSONResponse(w, 500, &KeysCreateResponse{
			Success: false,
			Message: "Internal server error - KE/CR/01",
		})

		env.Log.WithFields(logrus.Fields{
			"error": err.Error(),
			"id":    session.Owner,
		}).Error("Cannot fetch user from database")
		return
	}

	// Let's hope that the user is capable of sending proper armored keys
	publicKey := entityList[0]

	// Encode the fingerprint
	id := hex.EncodeToString(publicKey.PrimaryKey.Fingerprint[:])

	// Get the key's bit length - should not return an error
	bitLength, _ := publicKey.PrimaryKey.BitLength()

	// Allocate a new key
	key := &models.Key{
		Resource: models.MakeResource(
			account.ID,
			fmt.Sprintf(
				"%s/%d/%s",
				utils.GetAlgorithmName(publicKey.PrimaryKey.PubKeyAlgo),
				bitLength,
				publicKey.PrimaryKey.KeyIdString(),
			),
		),
		Headers:     block.Header,
		Algorithm:   utils.GetAlgorithmName(publicKey.PrimaryKey.PubKeyAlgo),
		Length:      bitLength,
		Key:         input.Key,
		KeyID:       publicKey.PrimaryKey.KeyIdString(),
		KeyIDShort:  publicKey.PrimaryKey.KeyIdShortString(),
		Reliability: 0,
	}

	// Update id as we can't do it directly during allocation
	key.ID = id

	// Try to insert it into the database
	if err := env.Keys.Insert(key); err != nil {
		utils.JSONResponse(w, 500, &KeysCreateResponse{
			Success: false,
			Message: "Internal server error - KE/CR/02",
		})

		env.Log.WithFields(logrus.Fields{
			"error": err.Error(),
		}).Error("Could not insert a key to the database")
		return
	}

	// Return the inserted key
	utils.JSONResponse(w, 201, &KeysCreateResponse{
		Success: true,
		Message: "A new key has been successfully inserted",
		Key:     key,
	})
}
示例#10
0
// TokensCreate allows logging in to an account.
func TokensCreate(w http.ResponseWriter, r *http.Request) {
	// Decode the request
	var input TokensCreateRequest
	err := utils.ParseRequest(r, &input)
	if err != nil {
		env.Log.WithFields(logrus.Fields{
			"error": err.Error(),
		}).Warn("Unable to decode a request")

		utils.JSONResponse(w, 409, &TokensCreateResponse{
			Success: false,
			Message: "Invalid input format",
		})
		return
	}

	// We can only create "auth" tokens now
	if input.Type != "auth" {
		utils.JSONResponse(w, 409, &TokensCreateResponse{
			Success: false,
			Message: "Only auth tokens are implemented",
		})
		return
	}

	input.Username = utils.RemoveDots(
		utils.NormalizeUsername(input.Username),
	)

	// Check if account exists
	user, err := env.Accounts.FindAccountByName(input.Username)
	if err != nil {
		utils.JSONResponse(w, 403, &TokensCreateResponse{
			Success: false,
			Message: "Wrong username or password",
		})
		return
	}

	// "registered" accounts can't log in
	if user.Status == "registered" {
		utils.JSONResponse(w, 403, &TokensCreateResponse{
			Success: false,
			Message: "Your account is not confirmed",
		})
		return
	}

	// Verify the password
	valid, updated, err := user.VerifyPassword(input.Password)
	if err != nil || !valid {
		utils.JSONResponse(w, 403, &TokensCreateResponse{
			Success: false,
			Message: "Wrong username or password",
		})
		return
	}

	// Update the user if password was updated
	if updated {
		user.DateModified = time.Now()
		err := env.Accounts.UpdateID(user.ID, user)
		if err != nil {
			env.Log.WithFields(logrus.Fields{
				"user":  user.Name,
				"error": err.Error(),
			}).Error("Could not update user")

			// DO NOT RETURN!
		}
	}

	// Check for 2nd factor
	if user.FactorType != "" {
		factor, ok := env.Factors[user.FactorType]
		if ok {
			// Verify the 2FA
			verified, challenge, err := user.Verify2FA(factor, input.Token)
			if err != nil {
				utils.JSONResponse(w, 500, &TokensCreateResponse{
					Success: false,
					Message: "Internal 2FA error",
				})

				env.Log.WithFields(logrus.Fields{
					"err":    err.Error(),
					"factor": user.FactorType,
				}).Warn("2FA authentication error")
				return
			}

			// Token was probably empty. Return the challenge.
			if !verified && challenge != "" {
				utils.JSONResponse(w, 403, &TokensCreateResponse{
					Success:         false,
					Message:         "2FA token was not passed",
					FactorType:      user.FactorType,
					FactorChallenge: challenge,
				})
				return
			}

			// Token was incorrect
			if !verified {
				utils.JSONResponse(w, 403, &TokensCreateResponse{
					Success:    false,
					Message:    "Invalid token passed",
					FactorType: user.FactorType,
				})
				return
			}
		}
	}

	// Calculate the expiry date
	expDate := time.Now().Add(time.Hour * time.Duration(env.Config.SessionDuration))

	// Create a new token
	token := &models.Token{
		Expiring: models.Expiring{ExpiryDate: expDate},
		Resource: models.MakeResource(user.ID, "Auth token expiring on "+expDate.Format(time.RFC3339)),
		Type:     input.Type,
	}

	// Insert int into the database
	env.Tokens.Insert(token)

	// Respond with the freshly created token
	utils.JSONResponse(w, 201, &TokensCreateResponse{
		Success: true,
		Message: "Authentication successful",
		Token:   token,
	})
}
示例#11
0
func TestTokensRoute(t *testing.T) {
	Convey("Given a working account", t, func() {
		account := &models.Account{
			Resource: models.MakeResource("", "johnorange5"),
			Status:   "complete",
			AltEmail: "*****@*****.**",
		}
		err := account.SetPassword("fruityloops")
		So(err, ShouldBeNil)

		err = env.Accounts.Insert(account)
		So(err, ShouldBeNil)

		result, err := goreq.Request{
			Method:      "POST",
			Uri:         server.URL + "/tokens",
			ContentType: "application/json",
			Body: `{
				"type": "auth",
				"username": "******",
				"password": "******"
			}`,
		}.Do()
		So(err, ShouldBeNil)

		var response routes.TokensCreateResponse
		err = result.Body.FromJsonTo(&response)
		So(err, ShouldBeNil)

		So(response.Success, ShouldBeTrue)
		authToken := response.Token

		Convey("Creating a non-auth token should fail", func() {
			request, err := goreq.Request{
				Method:      "POST",
				Uri:         server.URL + "/tokens",
				ContentType: "application/json",
				Body: `{
					"type": "not-auth"
				}`,
			}.Do()
			So(err, ShouldBeNil)

			var response routes.TokensCreateResponse
			err = request.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Success, ShouldBeFalse)
			So(response.Message, ShouldEqual, "Only auth tokens are implemented")
		})

		Convey("Trying to sign in using wrong username should fail", func() {
			request, err := goreq.Request{
				Method:      "POST",
				Uri:         server.URL + "/tokens",
				ContentType: "application/json",
				Body: `{
					"type": "auth",
					"username": "******",
					"password": "******"
				}`,
			}.Do()
			So(err, ShouldBeNil)

			var response routes.TokensCreateResponse
			err = request.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Success, ShouldBeFalse)
			So(response.Message, ShouldEqual, "Wrong username or password")
		})

		Convey("Trying to sign in using wrong password should fail", func() {
			request, err := goreq.Request{
				Method:      "POST",
				Uri:         server.URL + "/tokens",
				ContentType: "application/json",
				Body: `{
					"type": "auth",
					"username": "******",
					"password": "******"
				}`,
			}.Do()
			So(err, ShouldBeNil)

			var response routes.TokensCreateResponse
			err = request.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Success, ShouldBeFalse)
			So(response.Message, ShouldEqual, "Wrong username or password")
		})

		Convey("Trying to sign in using an invalid JSON input should fail", func() {
			request, err := goreq.Request{
				Method:      "POST",
				Uri:         server.URL + "/tokens",
				ContentType: "application/json",
				Body:        "123123123###434$#$",
			}.Do()
			So(err, ShouldBeNil)

			var response routes.TokensCreateResponse
			err = request.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Success, ShouldBeFalse)
			So(response.Message, ShouldEqual, "Invalid input format")
		})

		Convey("Getting the currently used token should succeed", func() {
			request := goreq.Request{
				Method: "GET",
				Uri:    server.URL + "/tokens",
			}
			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.TokensGetResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Success, ShouldBeTrue)
			So(response.Token.ExpiryDate.After(time.Now().UTC()), ShouldBeTrue)
		})

		Convey("Deleting the token by ID should succeed", func() {
			request := goreq.Request{
				Method: "DELETE",
				Uri:    server.URL + "/tokens/" + authToken.ID,
			}
			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.TokensDeleteResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Success, ShouldBeTrue)
			So(response.Message, ShouldEqual, "Successfully logged out")
		})

		Convey("Deleting a non-existing token should fail", func() {
			request := goreq.Request{
				Method: "DELETE",
				Uri:    server.URL + "/tokens/123",
			}
			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.TokensDeleteResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Success, ShouldBeFalse)
			So(response.Message, ShouldEqual, "Invalid token ID")
		})

		Convey("Deleting current token should succeed", func() {
			request := goreq.Request{
				Method: "DELETE",
				Uri:    server.URL + "/tokens",
			}
			request.AddHeader("Authorization", "Bearer "+authToken.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.TokensDeleteResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Success, ShouldBeTrue)
			So(response.Message, ShouldEqual, "Successfully logged out")
		})
	})
}
示例#12
0
func TestMiddleware(t *testing.T) {
	Convey("While querying a secure endpoint", t, func() {
		Convey("No header should fail", func() {
			result, err := goreq.Request{
				Method: "GET",
				Uri:    server.URL + "/accounts/me",
			}.Do()
			So(err, ShouldBeNil)

			var response routes.AuthMiddlewareResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Success, ShouldBeFalse)
			So(response.Message, ShouldEqual, "Missing auth token")
		})

		Convey("An invalid header should fail", func() {
			request := goreq.Request{
				Method: "GET",
				Uri:    server.URL + "/accounts/me",
			}
			request.AddHeader("Authorization", "123")
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.AuthMiddlewareResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Success, ShouldBeFalse)
			So(response.Message, ShouldEqual, "Invalid authorization header")
		})

		Convey("Invalid token should fail", func() {
			request := goreq.Request{
				Method: "GET",
				Uri:    server.URL + "/accounts/me",
			}
			request.AddHeader("Authorization", "Bearer 123")
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.AuthMiddlewareResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Success, ShouldBeFalse)
			So(response.Message, ShouldEqual, "Invalid authorization token")
		})

		Convey("Expired token should fail", func() {
			account := &models.Account{
				Resource: models.MakeResource("", "johnorange"),
				Status:   "complete",
				AltEmail: "*****@*****.**",
			}
			err := account.SetPassword("fruityloops")
			So(err, ShouldBeNil)

			err = env.Accounts.Insert(account)
			So(err, ShouldBeNil)

			token := models.Token{
				Resource: models.MakeResource(account.ID, "test invite token"),
				Expiring: models.Expiring{
					ExpiryDate: time.Now().UTC().Truncate(time.Hour * 8),
				},
				Type: "auth",
			}

			err = env.Tokens.Insert(token)
			So(err, ShouldBeNil)

			request := goreq.Request{
				Method: "GET",
				Uri:    server.URL + "/accounts/me",
			}
			request.AddHeader("Authorization", "Bearer "+token.ID)
			result, err := request.Do()
			So(err, ShouldBeNil)

			var response routes.AuthMiddlewareResponse
			err = result.Body.FromJsonTo(&response)
			So(err, ShouldBeNil)

			So(response.Success, ShouldBeFalse)
			So(response.Message, ShouldEqual, "Authorization token has expired")
		})
	})
}