From 9fdc3082ca9363fda2cd15a3a670cde89444eba7 Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Thu, 5 Mar 2015 22:17:17 +0100 Subject: [PATCH 01/10] Drafts label, fixed #94 --- routes/accounts.go | 4 ++++ routes/emails.go | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/routes/accounts.go b/routes/accounts.go index bb535bb..421270e 100644 --- a/routes/accounts.go +++ b/routes/accounts.go @@ -321,6 +321,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..9619627 100644 --- a/routes/emails.go +++ b/routes/emails.go @@ -272,7 +272,6 @@ func EmailsCreate(c web.C, w http.ResponseWriter, r *http.Request) { }) return } - } } else { hash := sha256.Sum256([]byte(input.Subject)) From f6412267bc241fc8820a9555aeb67e42d73311dd Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Sat, 7 Mar 2015 10:54:07 +0100 Subject: [PATCH 02/10] Removed file fingerprint count check --- routes/files.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/routes/files.go b/routes/files.go index 8f9de53..264e40f 100644 --- a/routes/files.go +++ b/routes/files.go @@ -75,8 +75,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", From 068c330e5c2b54d5377fc0305baac0be19aa707f Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Sat, 7 Mar 2015 13:11:52 +0100 Subject: [PATCH 03/10] List files by name --- db/table_files.go | 26 ++++++++++++++++++++++++++ routes/files.go | 14 +++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) 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/routes/files.go b/routes/files.go index 264e40f..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(), From 590ce8c87778a55a0270196ad710ff40ff9e0b23 Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Sun, 8 Mar 2015 11:48:22 +0100 Subject: [PATCH 04/10] Disabled files tests --- routes/{files_test.go => files_test.go_} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename routes/{files_test.go => files_test.go_} (100%) 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_ From 8e6c462e79a9710e743d4f3a3fbe39ed1a92bee9 Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Sun, 8 Mar 2015 12:07:03 +0100 Subject: [PATCH 05/10] Email injection into files --- setup/setup.go | 1 + 1 file changed, 1 insertion(+) 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, From 4b8557ed1b2144a9c35dd8aafb0a0dcb391c8f85 Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Sun, 8 Mar 2015 13:43:19 +0100 Subject: [PATCH 06/10] Directly inject subject hashes --- routes/emails.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/routes/emails.go b/routes/emails.go index 9619627..c38b1ee 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. @@ -274,8 +276,6 @@ func EmailsCreate(c web.C, w http.ResponseWriter, r *http.Request) { } } } else { - hash := sha256.Sum256([]byte(input.Subject)) - secure := "all" if input.Kind == "raw" { secure = "none" @@ -287,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, } From 8e3e77418c976918b3742b7899e922887c05c5dd Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Fri, 13 Mar 2015 22:35:47 +0100 Subject: [PATCH 07/10] Support for username styling --- models/account.go | 2 ++ routes/accounts.go | 18 ++++++++++++++---- routes/tokens.go | 4 ++++ utils/normalize.go | 22 ++++++++++++++++++++++ 4 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 utils/normalize.go 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 421270e..428366e 100644 --- a/routes/accounts.go +++ b/routes/accounts.go @@ -114,12 +114,16 @@ func AccountsCreate(w http.ResponseWriter, r *http.Request) { return } + // Normalize the username + input.Username = utils.NormalizeUsername(input.Username) + // 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) 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/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) +} From 36330e906442c92746b20e01322b1dc1164169b6 Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Fri, 13 Mar 2015 22:44:25 +0100 Subject: [PATCH 08/10] Moved username normalization --- routes/accounts.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/routes/accounts.go b/routes/accounts.go index 428366e..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 { @@ -114,9 +117,6 @@ func AccountsCreate(w http.ResponseWriter, r *http.Request) { return } - // Normalize the username - input.Username = utils.NormalizeUsername(input.Username) - // Both username and email are filled, so we can create a new account. account := &models.Account{ Resource: models.MakeResource("", utils.RemoveDots(input.Username)), From 2cdc3e4a73f340e5858b75bba08b33e6c357f06a Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Fri, 13 Mar 2015 22:59:10 +0100 Subject: [PATCH 09/10] Styled names support for outbound emails --- routes/emails.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/emails.go b/routes/emails.go index c38b1ee..7393730 100644 --- a/routes/emails.go +++ b/routes/emails.go @@ -314,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, From 0eef5218c071efaf0cd9e6bdf7f59ae7049df803 Mon Sep 17 00:00:00 2001 From: Piotr Zduniak Date: Fri, 13 Mar 2015 23:01:28 +0100 Subject: [PATCH 10/10] Styled username support for keys --- routes/keys.go | 4 ++++ 1 file changed, 4 insertions(+) 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 {