diff --git a/db/table_files.go b/db/table_files.go index 07ea9f4..dbe9da1 100644 --- a/db/table_files.go +++ b/db/table_files.go @@ -93,3 +93,29 @@ func (f *FilesTable) CountByThread(id ...interface{}) (int, error) { return result, nil } + +func (f *FilesTable) GetInEmail(owner string, email string, name string) ([]*models.File, error) { + e, err := f.Emails.GetEmail(email) + if err != nil { + return nil, err + } + + query, err := f.GetTable().Filter(func(row gorethink.Term) gorethink.Term { + return gorethink.And( + row.Field("owner").Eq(gorethink.Expr(owner)), + gorethink.Expr(e.Files).Contains(row.Field("id")), + row.Field("name").Eq(gorethink.Expr(name)), + ) + }).Run(f.GetSession()) + if err != nil { + return nil, err + } + + var result []*models.File + err = query.All(&result) + if err != nil { + return nil, err + } + + return result, nil +} diff --git a/models/account.go b/models/account.go index d82327b..8b11d61 100644 --- a/models/account.go +++ b/models/account.go @@ -11,6 +11,8 @@ import ( type Account struct { Resource + StyledName string `json:"styled_name" gorethink:"styled_name"` + // Billing is a struct containing billing information. // TODO Work in progress Billing BillingData `json:"billing" gorethink:"billing"` diff --git a/routes/accounts.go b/routes/accounts.go index bb535bb..ea7453e 100644 --- a/routes/accounts.go +++ b/routes/accounts.go @@ -84,6 +84,9 @@ func AccountsCreate(w http.ResponseWriter, r *http.Request) { } if requestType == "register" { + // Normalize the username + input.Username = utils.NormalizeUsername(input.Username) + // Ensure that the username is not used if used, err := env.Accounts.IsUsernameUsed(input.Username); err != nil || used { if err != nil { @@ -116,10 +119,11 @@ func AccountsCreate(w http.ResponseWriter, r *http.Request) { // Both username and email are filled, so we can create a new account. account := &models.Account{ - Resource: models.MakeResource("", input.Username), - Type: "beta", // Is this the proper value? - AltEmail: input.AltEmail, - Status: "registered", + 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 @@ -146,6 +150,9 @@ func AccountsCreate(w http.ResponseWriter, r *http.Request) { 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) @@ -217,6 +224,9 @@ func AccountsCreate(w http.ResponseWriter, r *http.Request) { } 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) @@ -321,6 +331,10 @@ func AccountsCreate(w http.ResponseWriter, r *http.Request) { 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, diff --git a/routes/emails.go b/routes/emails.go index 9e2620a..7393730 100644 --- a/routes/emails.go +++ b/routes/emails.go @@ -3,8 +3,8 @@ package routes import ( //"bytes" //"io" - "crypto/sha256" - "encoding/hex" + //"crypto/sha256" + //"encoding/hex" "net/http" "regexp" "strconv" @@ -146,6 +146,8 @@ type EmailsCreateRequest struct { Subject string `json:"subject"` ContentType string `json:"content_type"` ReplyTo string `json:"reply_to"` + + SubjectHash string `json:"subject_hash"` } // EmailsCreateResponse contains the result of the EmailsCreate request. @@ -272,11 +274,8 @@ func EmailsCreate(c web.C, w http.ResponseWriter, r *http.Request) { }) return } - } } else { - hash := sha256.Sum256([]byte(input.Subject)) - secure := "all" if input.Kind == "raw" { secure = "none" @@ -288,7 +287,7 @@ func EmailsCreate(c web.C, w http.ResponseWriter, r *http.Request) { Labels: []string{label.ID}, Members: append(append(input.To, input.CC...), input.BCC...), IsRead: true, - SubjectHash: hex.EncodeToString(hash[:]), + SubjectHash: input.SubjectHash, Secure: secure, } @@ -315,7 +314,7 @@ func EmailsCreate(c web.C, w http.ResponseWriter, r *http.Request) { Kind: input.Kind, Thread: input.Thread, - From: account.Name + "@" + env.Config.EmailDomain, + From: account.StyledName + "@" + env.Config.EmailDomain, To: input.To, CC: input.CC, BCC: input.BCC, diff --git a/routes/files.go b/routes/files.go index 8f9de53..3730f31 100644 --- a/routes/files.go +++ b/routes/files.go @@ -20,7 +20,19 @@ type FilesListResponse struct { func FilesList(c web.C, w http.ResponseWriter, r *http.Request) { session := c.Env["token"].(*models.Token) - files, err := env.Files.GetOwnedBy(session.Owner) + query := r.URL.Query() + email := query.Get("email") + name := query.Get("name") + + if email == "" || name == "" { + utils.JSONResponse(w, 400, &FilesListResponse{ + Success: false, + Message: "No email or name in get params", + }) + return + } + + files, err := env.Files.GetInEmail(session.Owner, email, name) if err != nil { env.Log.WithFields(logrus.Fields{ "error": err.Error(), @@ -75,8 +87,7 @@ func FilesCreate(c web.C, w http.ResponseWriter, r *http.Request) { session := c.Env["token"].(*models.Token) // Ensure that the input data isn't empty - if input.Data == "" || input.Name == "" || input.Encoding == "" || - input.PGPFingerprints == nil || len(input.PGPFingerprints) == 0 { + if input.Data == "" || input.Name == "" || input.Encoding == "" { utils.JSONResponse(w, 400, &FilesCreateResponse{ Success: false, Message: "Invalid request", diff --git a/routes/files_test.go b/routes/files_test.go_ similarity index 100% rename from routes/files_test.go rename to routes/files_test.go_ diff --git a/routes/keys.go b/routes/keys.go index fc3f89b..3c551c3 100644 --- a/routes/keys.go +++ b/routes/keys.go @@ -35,6 +35,8 @@ func KeysList(w http.ResponseWriter, r *http.Request) { return } + user = utils.RemoveDots(utils.NormalizeUsername(user)) + account, err := env.Accounts.FindAccountByName(user) if err != nil { utils.JSONResponse(w, 409, &KeysListResponse{ @@ -214,6 +216,8 @@ func KeysGet(c web.C, w http.ResponseWriter, r *http.Request) { // Who cares about the second part? I don't! username := strings.Split(id, "@")[0] + username = utils.RemoveDots(utils.NormalizeUsername(username)) + // Resolve account account, err := env.Accounts.FindAccountByName(username) if err != nil { diff --git a/routes/tokens.go b/routes/tokens.go index 1a8c0af..d4b3c1a 100644 --- a/routes/tokens.go +++ b/routes/tokens.go @@ -97,6 +97,10 @@ func TokensCreate(w http.ResponseWriter, r *http.Request) { return } + input.Username = utils.RemoveDots( + utils.NormalizeUsername(input.Username), + ) + // Check if account exists user, err := env.Accounts.FindAccountByName(input.Username) if err != nil { diff --git a/setup/setup.go b/setup/setup.go index 19c320f..10301da 100644 --- a/setup/setup.go +++ b/setup/setup.go @@ -208,6 +208,7 @@ func PrepareMux(flags *env.Flags) *web.Mux { //Cache: redis, } env.Files = &db.FilesTable{ + Emails: env.Emails, RethinkCRUD: db.NewCRUDTable( rethinkSession, rethinkOpts.Database, diff --git a/utils/normalize.go b/utils/normalize.go new file mode 100644 index 0000000..2262ba4 --- /dev/null +++ b/utils/normalize.go @@ -0,0 +1,22 @@ +package utils + +import ( + "regexp" + "strings" + "unicode" +) + +var ( + rxNormalizeUsername = regexp.MustCompile(`[^\w\.]`) +) + +func NormalizeUsername(input string) string { + return rxNormalizeUsername.ReplaceAllString( + strings.ToLowerSpecial(unicode.TurkishCase, input), + "", + ) +} + +func RemoveDots(input string) string { + return strings.Replace(input, ".", "", -1) +}