From b7acd39051a293289c182f2a9166f681bbe8b07f Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Mon, 9 Sep 2019 22:04:20 +0200 Subject: [PATCH 01/69] Add Cache-Control headers on AP endpoints Includes: * AP Collection fetching via canonical URL * AP Collection fetching via API * AP Post fetching via canonical URL * AP Post fetching via API Ref T693 --- activitypub.go | 10 ++++++++++ collections.go | 1 + posts.go | 2 ++ 3 files changed, 13 insertions(+) diff --git a/activitypub.go b/activitypub.go index 997609d..f436a87 100644 --- a/activitypub.go +++ b/activitypub.go @@ -37,6 +37,8 @@ import ( const ( // TODO: delete. don't use this! apCustomHandleDefault = "blog" + + apCacheTime = time.Minute ) type RemoteUser struct { @@ -84,6 +86,7 @@ func handleFetchCollectionActivities(app *App, w http.ResponseWriter, r *http.Re p := c.PersonObject() + setCacheControl(w, apCacheTime) return impart.RenderActivityJSON(w, p, http.StatusOK) } @@ -137,6 +140,7 @@ func handleFetchCollectionOutbox(app *App, w http.ResponseWriter, r *http.Reques ocp.OrderedItems = append(ocp.OrderedItems, *a) } + setCacheControl(w, apCacheTime) return impart.RenderActivityJSON(w, ocp, http.StatusOK) } @@ -183,6 +187,7 @@ func handleFetchCollectionFollowers(app *App, w http.ResponseWriter, r *http.Req ocp.OrderedItems = append(ocp.OrderedItems, f.ActorID) } */ + setCacheControl(w, apCacheTime) return impart.RenderActivityJSON(w, ocp, http.StatusOK) } @@ -219,6 +224,7 @@ func handleFetchCollectionFollowing(app *App, w http.ResponseWriter, r *http.Req // Return outbox page ocp := activitystreams.NewOrderedCollectionPage(accountRoot, "following", 0, p) ocp.OrderedItems = []interface{}{} + setCacheControl(w, apCacheTime) return impart.RenderActivityJSON(w, ocp, http.StatusOK) } @@ -703,3 +709,7 @@ func unmarshalActor(actorResp []byte, actor *activitystreams.Person) error { return nil } + +func setCacheControl(w http.ResponseWriter, ttl time.Duration) { + w.Header().Set("Cache-Control", fmt.Sprintf("public, max-age=%.0f", ttl.Seconds())) +} diff --git a/collections.go b/collections.go index 997d4d7..a13aad2 100644 --- a/collections.go +++ b/collections.go @@ -730,6 +730,7 @@ func handleViewCollection(app *App, w http.ResponseWriter, r *http.Request) erro if strings.Contains(r.Header.Get("Accept"), "application/activity+json") { ac := c.PersonObject() ac.Context = []interface{}{activitystreams.Namespace} + setCacheControl(w, apCacheTime) return impart.RenderActivityJSON(w, ac, http.StatusOK) } diff --git a/posts.go b/posts.go index 2f3606f..625410b 100644 --- a/posts.go +++ b/posts.go @@ -1034,6 +1034,7 @@ func fetchPost(app *App, w http.ResponseWriter, r *http.Request) error { p.Collection = &CollectionObj{Collection: *coll} po := p.ActivityObject() po.Context = []interface{}{activitystreams.Namespace} + setCacheControl(w, apCacheTime) return impart.RenderActivityJSON(w, po, http.StatusOK) } @@ -1359,6 +1360,7 @@ Are you sure it was ever here?`, p.extractData() ap := p.ActivityObject() ap.Context = []interface{}{activitystreams.Namespace} + setCacheControl(w, apCacheTime) return impart.RenderActivityJSON(w, ap, http.StatusOK) } else { p.extractData() From caca8f0ae26f586e4736eeefd01eef0e6ed80808 Mon Sep 17 00:00:00 2001 From: Rob Loranger Date: Thu, 3 Oct 2019 09:47:08 -0700 Subject: [PATCH 02/69] show timestamps in local date/locale this adds a helper script to rewrite all time elements with a proper datetime attribute into the users locale via the browser navigator.language. collection, collection-post and chorus-collection-post templates now include this script --- static/js/localdate.js | 9 +++++++++ templates/chorus-collection-post.tmpl | 1 + templates/collection-post.tmpl | 1 + templates/collection.tmpl | 1 + 4 files changed, 12 insertions(+) create mode 100644 static/js/localdate.js diff --git a/static/js/localdate.js b/static/js/localdate.js new file mode 100644 index 0000000..19fa502 --- /dev/null +++ b/static/js/localdate.js @@ -0,0 +1,9 @@ +function toLocalDate(el) { + var d = new Date(el.getAttribute("datetime")); + el.textContent = d.toLocaleDateString(navigator.language || "en-US", { year: 'numeric', month: 'long', day: 'numeric' }); +} + +var $dates = document.querySelectorAll("time"); +for (var i=0; i < $dates.length; i++) { + toLocalDate($dates[i]); +} diff --git a/templates/chorus-collection-post.tmpl b/templates/chorus-collection-post.tmpl index bab2e31..e60a435 100644 --- a/templates/chorus-collection-post.tmpl +++ b/templates/chorus-collection-post.tmpl @@ -90,6 +90,7 @@ article time.dt-published { {{range .Collection.ExternalScripts}}{{end}} {{if .Collection.Script}}{{end}} {{end}} + {{end}} {{if .Collection.Script}}{{end}} {{end}} + + {{end}} {{end}} + + {{end}} {{end}} From 4d5c89e7efec6fad7b3fae7f36f92f0c58a9b30a Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Thu, 16 Jan 2020 13:37:44 -0500 Subject: [PATCH 29/69] Fix false login state on OAuth signup page Having a `Username` field populated in the page data tells the base template to display navigation that only a logged in user should see. So this renames the field to `LoginUsername`, similar to our login.tmpl page. Ref T712 --- oauth_signup.go | 12 ++++++------ pages/signup-oauth.tmpl | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/oauth_signup.go b/oauth_signup.go index cf90af6..96b9936 100644 --- a/oauth_signup.go +++ b/oauth_signup.go @@ -29,9 +29,9 @@ type viewOauthSignupVars struct { ClientID string TokenHash string - Username string - Alias string - Email string + LoginUsername string + Alias string + Email string } const ( @@ -184,9 +184,9 @@ func (h oauthHandler) showOauthSignupPage(app *App, w http.ResponseWriter, r *ht ClientID: tp.ClientID, TokenHash: tp.TokenHash, - Username: username, - Alias: alias, - Email: email, + LoginUsername: username, + Alias: collTitle, + Email: email, } // Display any error messages diff --git a/pages/signup-oauth.tmpl b/pages/signup-oauth.tmpl index 3fd4255..40cc2e6 100644 --- a/pages/signup-oauth.tmpl +++ b/pages/signup-oauth.tmpl @@ -85,7 +85,7 @@ form dd { From 6842ab2e3be7ffae9ce46a0613714a95cc1dd135 Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Thu, 16 Jan 2020 13:50:37 -0500 Subject: [PATCH 30/69] Rename collTitle from alias "alias" is the name of a different collection field, so this renames the variable internally to make things clearer. --- oauth_signup.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/oauth_signup.go b/oauth_signup.go index 96b9936..58071c6 100644 --- a/oauth_signup.go +++ b/oauth_signup.go @@ -22,7 +22,7 @@ type viewOauthSignupVars struct { AccessToken string TokenUsername string - TokenAlias string + TokenAlias string // TODO: rename this to match the data it represents: the collection title TokenEmail string TokenRemoteUser string Provider string @@ -30,7 +30,7 @@ type viewOauthSignupVars struct { TokenHash string LoginUsername string - Alias string + Alias string // TODO: rename this to match the data it represents: the collection title Email string } @@ -52,7 +52,7 @@ const ( type oauthSignupPageParams struct { AccessToken string TokenUsername string - TokenAlias string + TokenAlias string // TODO: rename this to match the data it represents: the collection title TokenEmail string TokenRemoteUser string ClientID string @@ -131,8 +131,8 @@ func (h oauthHandler) validateOauthSignup(r *http.Request) error { if len(username) > 100 { return impart.HTTPError{Status: http.StatusBadRequest, Message: "Username is too long."} } - alias := r.FormValue(oauthParamAlias) - if len(alias) == 0 { + collTitle := r.FormValue(oauthParamAlias) + if len(collTitle) == 0 { return impart.HTTPError{Status: http.StatusBadRequest, Message: "Alias is too short."} } password := r.FormValue("password") @@ -151,7 +151,7 @@ func (h oauthHandler) validateOauthSignup(r *http.Request) error { func (h oauthHandler) showOauthSignupPage(app *App, w http.ResponseWriter, r *http.Request, tp *oauthSignupPageParams, errMsg error) error { username := tp.TokenUsername - alias := tp.TokenAlias + collTitle := tp.TokenAlias email := tp.TokenEmail session, err := app.sessionStore.Get(r, cookieName) @@ -164,7 +164,7 @@ func (h oauthHandler) showOauthSignupPage(app *App, w http.ResponseWriter, r *ht username = tmpValue } if tmpValue := r.FormValue(oauthParamAlias); len(tmpValue) > 0 { - alias = tmpValue + collTitle = tmpValue } if tmpValue := r.FormValue(oauthParamEmail); len(tmpValue) > 0 { email = tmpValue From 130c9eb7475d93ab7d3a4a016c26d09ce3a8464c Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Thu, 16 Jan 2020 13:58:14 -0500 Subject: [PATCH 31/69] Change Blog Title to Display Name in OAuth signup Ref T712 --- oauth_signup.go | 2 +- pages/signup-oauth.tmpl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/oauth_signup.go b/oauth_signup.go index 58071c6..5b960ca 100644 --- a/oauth_signup.go +++ b/oauth_signup.go @@ -133,7 +133,7 @@ func (h oauthHandler) validateOauthSignup(r *http.Request) error { } collTitle := r.FormValue(oauthParamAlias) if len(collTitle) == 0 { - return impart.HTTPError{Status: http.StatusBadRequest, Message: "Alias is too short."} + return impart.HTTPError{Status: http.StatusBadRequest, Message: "Display name is too short."} } password := r.FormValue("password") if len(password) == 0 { diff --git a/pages/signup-oauth.tmpl b/pages/signup-oauth.tmpl index 40cc2e6..21e8ed5 100644 --- a/pages/signup-oauth.tmpl +++ b/pages/signup-oauth.tmpl @@ -77,9 +77,9 @@ form dd {
-
From dcdd4dd1ef19170e22f47ebef4be30a698fcd7eb Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Thu, 16 Jan 2020 14:39:18 -0500 Subject: [PATCH 35/69] Add and update copyright notices --- author/author.go | 2 +- oauth_signup.go | 10 ++++++++++ oauth_slack.go | 10 ++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/author/author.go b/author/author.go index e2e9508..0114905 100644 --- a/author/author.go +++ b/author/author.go @@ -1,5 +1,5 @@ /* - * Copyright © 2018 A Bunch Tell LLC. + * Copyright © 2018-2020 A Bunch Tell LLC. * * This file is part of WriteFreely. * diff --git a/oauth_signup.go b/oauth_signup.go index 10d2306..220afbd 100644 --- a/oauth_signup.go +++ b/oauth_signup.go @@ -1,3 +1,13 @@ +/* + * Copyright © 2020 A Bunch Tell LLC. + * + * This file is part of WriteFreely. + * + * WriteFreely is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, included + * in the LICENSE file in this source code package. + */ + package writefreely import ( diff --git a/oauth_slack.go b/oauth_slack.go index f700c2c..1db3613 100644 --- a/oauth_slack.go +++ b/oauth_slack.go @@ -1,3 +1,13 @@ +/* + * Copyright © 2020 A Bunch Tell LLC. + * + * This file is part of WriteFreely. + * + * WriteFreely is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, included + * in the LICENSE file in this source code package. + */ + package writefreely import ( From c1ec6b26051ee76f63d12f9581218fe479bf8f64 Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Thu, 16 Jan 2020 14:43:32 -0500 Subject: [PATCH 36/69] Fix copyright years in oauth_slack.go --- oauth_slack.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oauth_slack.go b/oauth_slack.go index 1db3613..35db156 100644 --- a/oauth_slack.go +++ b/oauth_slack.go @@ -1,5 +1,5 @@ /* - * Copyright © 2020 A Bunch Tell LLC. + * Copyright © 2019-2020 A Bunch Tell LLC. * * This file is part of WriteFreely. * From 8e09e72979128d1d16d28df0df17e544037da9f0 Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Thu, 16 Jan 2020 14:47:23 -0500 Subject: [PATCH 37/69] Require authenticated user for editor access Previously, anyone could access the editor even if they weren't logged in. They couldn't do much in that case (publishing would fail), but it could potentially cause some confusion. Now, users will be sent to the login page, and then redirected back to the editor once successfully logged in. --- routes.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/routes.go b/routes.go index 7784d71..ba531fb 100644 --- a/routes.go +++ b/routes.go @@ -169,9 +169,9 @@ func InitRoutes(apper Apper, r *mux.Router) *mux.Router { draftEditPrefix := "" if apper.App().cfg.App.SingleUser { draftEditPrefix = "/d" - write.HandleFunc("/me/new", handler.Web(handleViewPad, UserLevelOptional)).Methods("GET") + write.HandleFunc("/me/new", handler.Web(handleViewPad, UserLevelUser)).Methods("GET") } else { - write.HandleFunc("/new", handler.Web(handleViewPad, UserLevelOptional)).Methods("GET") + write.HandleFunc("/new", handler.Web(handleViewPad, UserLevelUser)).Methods("GET") } // All the existing stuff From 2c075c0347a4d123bc260eb935e1becd67edb2bc Mon Sep 17 00:00:00 2001 From: Rob Loranger Date: Sun, 19 Jan 2020 15:57:58 -0800 Subject: [PATCH 38/69] update upgrade script for recent changes changes accounted for - the tar directory structure had changed to use a subdirectory - there are now multiple linux targets released bugs - the service must be stopped before replacing the binary - migrations were not being run during an upgrade --- scripts/upgrade-server.sh | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/scripts/upgrade-server.sh b/scripts/upgrade-server.sh index c8e004a..ef10452 100755 --- a/scripts/upgrade-server.sh +++ b/scripts/upgrade-server.sh @@ -31,7 +31,7 @@ fi # go ahead and check for the latest release on linux echo "Checking for updates..." -url=`curl -s https://api.github.com/repos/writeas/writefreely/releases/latest | grep 'browser_' | grep linux | cut -d\" -f4` +url=`curl -s https://api.github.com/repos/writeas/writefreely/releases/latest | grep 'browser_' | grep 'linux' | grep 'amd64' | cut -d\" -f4` # check current version @@ -82,13 +82,25 @@ filename=${parts[-1]} echo "Extracting files..." tar -zxf $tempdir/$filename -C $tempdir +# stop service +echo "Stopping writefreely systemd service..." +if `systemctl start writefreely`; then + echo "Success, service stopped." +else + echo "Upgrade failed to stop the systemd service, exiting early." + exit 1 +fi + # copy files echo "Copying files..." -cp -r $tempdir/{pages,static,templates,writefreely} . +cp -r $tempdir/writefreely/{pages,static,templates,writefreely} . + +# migrate db +./writefreely -migrate # restart service echo "Restarting writefreely systemd service..." -if `systemctl restart writefreely`; then +if `systemctl start writefreely`; then echo "Success, version has been upgraded to $latest." else echo "Upgrade complete, but failed to restart service." From b336e95e1244007426a4c3fb66d7691424c9d3ed Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Mon, 20 Jan 2020 15:20:45 -0500 Subject: [PATCH 39/69] Render HTML entities in Drafts list Previously, we'd show the raw HTML entities in the summaries of Draft posts, instead of rendering them. This fixes that. --- posts.go | 4 ++++ templates/user/articles.tmpl | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/posts.go b/posts.go index d2fbcca..608f2fc 100644 --- a/posts.go +++ b/posts.go @@ -229,6 +229,10 @@ func (p Post) Summary() string { return shortPostDescription(p.Content) } +func (p Post) SummaryHTML() template.HTML { + return template.HTML(p.Summary()) +} + // Excerpt shows any text that comes before a (more) tag. // TODO: use HTMLExcerpt in templates instead of this method func (p *Post) Excerpt() template.HTML { diff --git a/templates/user/articles.tmpl b/templates/user/articles.tmpl index 3edb89c..5dbe47b 100644 --- a/templates/user/articles.tmpl +++ b/templates/user/articles.tmpl @@ -34,7 +34,7 @@ {{end}} {{ end }} - {{if .Summary}}

{{.Summary}}

{{end}} + {{if .Summary}}

{{.SummaryHTML}}

{{end}} {{end}} {{ else }}

You haven't saved any drafts yet.

They'll show up here once you do. {{if not .SingleUser}}Find your blog posts from the Blogs page.{{end}}

From 30032e74a0199c247aea8f0efdeb0a6f28c63db3 Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Mon, 20 Jan 2020 15:25:37 -0500 Subject: [PATCH 40/69] Add helpful text on Drafts page --- templates/user/articles.tmpl | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/templates/user/articles.tmpl b/templates/user/articles.tmpl index 5dbe47b..16fb4e3 100644 --- a/templates/user/articles.tmpl +++ b/templates/user/articles.tmpl @@ -12,7 +12,10 @@

drafts

-{{ if .AnonymousPosts }}
+{{ if .AnonymousPosts }} +

These are your draft posts. You can share them individually (without a blog) or move them to your blog when you're ready.

+ +
{{ range $el := .AnonymousPosts }}

@@ -36,8 +39,9 @@

{{if .Summary}}

{{.SummaryHTML}}

{{end}}
{{end}} -
{{ else }}

You haven't saved any drafts yet.

-

They'll show up here once you do. {{if not .SingleUser}}Find your blog posts from the Blogs page.{{end}}

+
{{ else }}
+

Your anonymous and draft posts will show up here once you've published some. You'll be able to share them individually (without a blog) or move them to a blog when you're ready.

+ {{if not .SingleUser}}

Alternatively, see your blogs and their posts on your Blogs page.

{{end}}

Start writing

{{ end }}
From bc9843dfa37dd0714c0c20c8f5f21234815535c3 Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Thu, 23 Jan 2020 11:47:35 -0500 Subject: [PATCH 41/69] Add timeout on ActivityPub requests --- activitypub.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/activitypub.go b/activitypub.go index a18a636..62294cd 100644 --- a/activitypub.go +++ b/activitypub.go @@ -1,5 +1,5 @@ /* - * Copyright © 2018-2019 A Bunch Tell LLC. + * Copyright © 2018-2020 A Bunch Tell LLC. * * This file is part of WriteFreely. * @@ -62,6 +62,12 @@ func (ru *RemoteUser) AsPerson() *activitystreams.Person { } } +func activityPubClient() http.Client { + return http.Client{ + Timeout: 15 * time.Second, + } +} + func handleFetchCollectionActivities(app *App, w http.ResponseWriter, r *http.Request) error { w.Header().Set("Server", serverSoftware) @@ -502,7 +508,7 @@ func makeActivityPost(hostName string, p *activitystreams.Person, url string, m } } - resp, err := http.DefaultClient.Do(r) + resp, err := activityPubClient().Do(r) if err != nil { return err } @@ -538,7 +544,7 @@ func resolveIRI(hostName, url string) ([]byte, error) { } } - resp, err := http.DefaultClient.Do(r) + resp, err := activityPubClient().Do(r) if err != nil { return nil, err } From 8d3e755c8f5b0afe3b5bb2950dd3806a4af08f45 Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Thu, 23 Jan 2020 12:03:23 -0500 Subject: [PATCH 42/69] Return pointer to http.Client in activityPubClient() --- activitypub.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activitypub.go b/activitypub.go index 62294cd..b133f9d 100644 --- a/activitypub.go +++ b/activitypub.go @@ -62,8 +62,8 @@ func (ru *RemoteUser) AsPerson() *activitystreams.Person { } } -func activityPubClient() http.Client { - return http.Client{ +func activityPubClient() *http.Client { + return &http.Client{ Timeout: 15 * time.Second, } } From bf8dcff01eb26e0dcb9941fdf151d5c3f4af8317 Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Mon, 27 Jan 2020 09:19:12 -0500 Subject: [PATCH 43/69] Quit AP goroutine early when there's no "to" Previously, we'd sleep for 2 seconds and then return for no reason. This fixes that. --- activitypub.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/activitypub.go b/activitypub.go index b133f9d..ba2bb27 100644 --- a/activitypub.go +++ b/activitypub.go @@ -388,6 +388,11 @@ func handleFetchCollectionInbox(app *App, w http.ResponseWriter, r *http.Request } go func() { + if to == nil { + log.Error("No to! %v", err) + return + } + time.Sleep(2 * time.Second) am, err := a.Serialize() if err != nil { @@ -396,10 +401,6 @@ func handleFetchCollectionInbox(app *App, w http.ResponseWriter, r *http.Request } am["@context"] = []string{activitystreams.Namespace} - if to == nil { - log.Error("No to! %v", err) - return - } err = makeActivityPost(app.cfg.App.Host, p, fullActor.Inbox, am) if err != nil { log.Error("Unable to make activity POST: %v", err) From ae1a892be00d4b38486658b658a12bd14420194d Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Wed, 29 Jan 2020 04:56:23 -0500 Subject: [PATCH 44/69] Upgrade gorilla/sessions to v1.2.0 This gets rid of the gorilla/context dependency, which might have been causing a memory leak. We noticed some serious memory leakage on Write.as that seemed to point to this library. One heap snapshot: flat flat% sum% cum cum% 259.13MB 30.41% 30.41% 268.13MB 31.46% net/textproto.(*Reader).ReadMIMEHeader 105.71MB 12.40% 42.81% 105.71MB 12.40% github.com/gorilla/context.Set 78.53MB 9.21% 52.03% 125.53MB 14.73% github.com/gorilla/sessions.(*Registry).Get 55.51MB 6.51% 58.54% 82.52MB 9.68% net/http.(*Request).WithContext 38.01MB 4.46% 63.00% 38.01MB 4.46% github.com/gorilla/mux.extractVars 35MB 4.11% 67.11% 53MB 6.22% context.WithCancel 34.50MB 4.05% 71.16% 34.50MB 4.05% context.WithValue 27MB 3.17% 74.32% 27MB 3.17% net/http.cloneURL 26MB 3.05% 77.38% 26MB 3.05% github.com/gorilla/sessions.NewSession 18MB 2.11% 79.49% 18MB 2.11% context.(*cancelCtx).Done 16.50MB 1.94% 81.42% 16.50MB 1.94% syscall.anyToSockaddr 14MB 1.64% 83.07% 47MB 5.52% github.com/gorilla/sessions.(*CookieStore).New 13.50MB 1.58% 84.65% 51.51MB 6.04% github.com/gorilla/mux.(*Route).Match 11.67MB 1.37% 86.02% 13.21MB 1.55% regexp.(*Regexp).replaceAll 9.72MB 1.14% 87.16% 22.94MB 2.69% regexp.(*Regexp).ReplaceAllString 9.50MB 1.11% 88.28% 115.21MB 13.52% github.com/gorilla/sessions.GetRegistry With the help of these articles, we tracked it down to this dependency, and upgraded the library, which seems to have completely fixed the issue so far: https://rover.rocks/golang-memory-leak/ https://medium.com/@walterwu_22843/golang-memory-leak-while-handling-huge-amount-of-http-request-35cc970cb75e This should fix #133 --- go.mod | 2 +- go.sum | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index f6aa8b7..adfcccb 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/gorilla/feeds v1.1.0 github.com/gorilla/mux v1.7.0 github.com/gorilla/schema v1.0.2 - github.com/gorilla/sessions v1.1.3 + github.com/gorilla/sessions v1.2.0 github.com/guregu/null v3.4.0+incompatible github.com/hashicorp/go-multierror v1.0.0 github.com/ikeikeikeike/go-sitemap-generator v1.0.1 diff --git a/go.sum b/go.sum index 5b8b88a..f958de2 100644 --- a/go.sum +++ b/go.sum @@ -46,8 +46,6 @@ github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1 github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gordonklaus/ineffassign v0.0.0-20180909121442-1003c8bd00dc h1:cJlkeAx1QYgO5N80aF5xRGstVsRQwgLR7uA2FnP1ZjY= github.com/gordonklaus/ineffassign v0.0.0-20180909121442-1003c8bd00dc/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU= -github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/feeds v1.1.0 h1:pcgLJhbdYgaUESnj3AmXPcB7cS3vy63+jC/TI14AGXk= github.com/gorilla/feeds v1.1.0/go.mod h1:Nk0jZrvPFZX1OBe5NPiddPw7CfwF6Q9eqzaBbaightA= github.com/gorilla/mux v1.7.0 h1:tOSd0UKHQd6urX6ApfOn4XdBMY6Sh1MfxV3kmaazO+U= @@ -56,8 +54,8 @@ github.com/gorilla/schema v1.0.2 h1:sAgNfOcNYvdDSrzGHVy9nzCQahG+qmsg+nE8dK85QRA= github.com/gorilla/schema v1.0.2/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= -github.com/gorilla/sessions v1.1.3 h1:uXoZdcdA5XdXF3QzuSlheVRUvjl+1rKY7zBXL68L9RU= -github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= +github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ= +github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/guregu/null v3.4.0+incompatible h1:a4mw37gBO7ypcBlTJeZGuMpSxxFTV9qFfFKgWxQSGaM= github.com/guregu/null v3.4.0+incompatible/go.mod h1:ePGpQaN9cw0tj45IR5E5ehMvsFlLlQZAkkOXZurJ3NM= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= From 8fce34b70b039b5ff9528ad8494a6f4a7921ae6c Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Wed, 29 Jan 2020 05:24:22 -0500 Subject: [PATCH 45/69] Tidy up Go mod files --- go.mod | 6 ++---- go.sum | 10 ---------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/go.mod b/go.mod index adfcccb..519a6ea 100644 --- a/go.mod +++ b/go.mod @@ -18,10 +18,8 @@ require ( github.com/gorilla/sessions v1.2.0 github.com/guregu/null v3.4.0+incompatible github.com/hashicorp/go-multierror v1.0.0 - github.com/ikeikeikeike/go-sitemap-generator v1.0.1 github.com/ikeikeikeike/go-sitemap-generator/v2 v2.0.2 github.com/jtolds/gls v4.2.1+incompatible // indirect - github.com/kr/pretty v0.1.0 github.com/kylemcc/twitter-text-go v0.0.0-20180726194232-7f582f6736ec github.com/lunixbochs/vtclean v1.0.0 // indirect github.com/manifoldco/promptui v0.3.2 @@ -32,7 +30,7 @@ require ( github.com/nicksnyder/go-i18n v1.10.0 // indirect github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d github.com/pelletier/go-toml v1.2.0 // indirect - github.com/pkg/errors v0.8.1 + github.com/pkg/errors v0.8.1 // indirect github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be // indirect github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 // indirect github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c // indirect @@ -53,7 +51,7 @@ require ( golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1 // indirect golang.org/x/net v0.0.0-20190206173232-65e2d4e15006 // indirect golang.org/x/sys v0.0.0-20190209173611-3b5209105503 // indirect - golang.org/x/tools v0.0.0-20190208222737-3744606dbb67 + golang.org/x/tools v0.0.0-20190208222737-3744606dbb67 // indirect google.golang.org/appengine v1.4.0 // indirect gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20180810215634-df19058c872c // indirect gopkg.in/ini.v1 v1.41.0 diff --git a/go.sum b/go.sum index f958de2..4cb46da 100644 --- a/go.sum +++ b/go.sum @@ -62,8 +62,6 @@ github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/U github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/ikeikeikeike/go-sitemap-generator v1.0.1 h1:49Fn8gro/B12vCY8pf5/+/Jpr3kwB9TvP0MSymo69SY= -github.com/ikeikeikeike/go-sitemap-generator v1.0.1/go.mod h1:QI+zWsz6yQyxkG9LWNcnu0f7aiAE5tPdsZOsICgmd1c= github.com/ikeikeikeike/go-sitemap-generator/v2 v2.0.2 h1:wIdDEle9HEy7vBPjC6oKz6ejs3Ut+jmsYvuOoAW2pSM= github.com/ikeikeikeike/go-sitemap-generator/v2 v2.0.2/go.mod h1:WtaVKD9TeruTED9ydiaOJU08qGoEPP/LyzTKiD3jEsw= github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= @@ -135,12 +133,6 @@ github.com/writeas/impart v1.1.0 h1:nPnoO211VscNkp/gnzir5UwCDEvdHThL5uELU60NFSE= github.com/writeas/impart v1.1.0/go.mod h1:g0MpxdnTOHHrl+Ca/2oMXUHJ0PcRAEWtkCzYCJUXC9Y= github.com/writeas/impart v1.1.1-0.20191230230525-d3c45ced010d h1:PK7DOj3JE6MGf647esPrKzXEHFjGWX2hl22uX79ixaE= github.com/writeas/impart v1.1.1-0.20191230230525-d3c45ced010d/go.mod h1:g0MpxdnTOHHrl+Ca/2oMXUHJ0PcRAEWtkCzYCJUXC9Y= -github.com/writeas/import v0.0.0-20190815214647-baae8acd8d06 h1:S6oKKP8GhSoyZUvVuhO9UiQ9f+U1aR/x5B4MP7YQHaU= -github.com/writeas/import v0.0.0-20190815214647-baae8acd8d06/go.mod h1:f3K8z7YnJwKnPIT4h7980n9C6cQb4DIB2QcxVCTB7lE= -github.com/writeas/import v0.0.0-20190815235139-628d10daaa9e h1:31PkvDTWkjzC1nGzWw9uAE92ZfcVyFX/K9L9ejQjnEs= -github.com/writeas/import v0.0.0-20190815235139-628d10daaa9e/go.mod h1:f3K8z7YnJwKnPIT4h7980n9C6cQb4DIB2QcxVCTB7lE= -github.com/writeas/import v0.1.1 h1:SbYltT+nxrJBUe0xQWJqeKMHaupbxV0a6K3RtwcE4yY= -github.com/writeas/import v0.1.1/go.mod h1:gFe0Pl7ZWYiXbI0TJxeMMyylPGZmhVvCfQxhMEc8CxM= github.com/writeas/import v0.2.0 h1:Ov23JW9Rnjxk06rki1Spar45bNX647HhwhAZj3flJiY= github.com/writeas/import v0.2.0/go.mod h1:gFe0Pl7ZWYiXbI0TJxeMMyylPGZmhVvCfQxhMEc8CxM= github.com/writeas/monday v0.0.0-20181024183321-54a7dd579219 h1:baEp0631C8sT2r/hqwypIw2snCFZa6h7U6TojoLHu/c= @@ -154,8 +146,6 @@ github.com/writeas/saturday v1.7.1 h1:lYo1EH6CYyrFObQoA9RNWHVlpZA5iYL5Opxo7PYAnZ github.com/writeas/saturday v1.7.1/go.mod h1:ETE1EK6ogxptJpAgUbcJD0prAtX48bSloie80+tvnzQ= github.com/writeas/slug v1.2.0 h1:EMQ+cwLiOcA6EtFwUgyw3Ge18x9uflUnOnR6bp/J+/g= github.com/writeas/slug v1.2.0/go.mod h1:RE8shOqQP3YhsfsQe0L3RnuejfQ4Mk+JjY5YJQFubfQ= -github.com/writeas/web-core v1.0.0 h1:5VKkCakQgdKZcbfVKJXtRpc5VHrkflusCl/KRCPzpQ0= -github.com/writeas/web-core v1.0.0/go.mod h1:Si3chV7VWgY8CsV+3gRolMXSO2Vx1ZFAQ/mkrpvmyEE= github.com/writeas/web-core v1.2.0 h1:CYqvBd+byi1cK4mCr1NZ6CjILuMOFmiFecv+OACcmG0= github.com/writeas/web-core v1.2.0/go.mod h1:vTYajviuNBAxjctPp2NUYdgjofywVkxUGpeaERF3SfI= github.com/writefreely/go-nodeinfo v1.2.0 h1:La+YbTCvmpTwFhBSlebWDDL81N88Qf/SCAvRLR7F8ss= From be0885698e5afdaf689d23f54e1798cf9ce56160 Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Wed, 29 Jan 2020 05:46:59 -0500 Subject: [PATCH 46/69] Change "restarting" to "starting" in upgrade script --- scripts/upgrade-server.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/upgrade-server.sh b/scripts/upgrade-server.sh index ef10452..36281bf 100755 --- a/scripts/upgrade-server.sh +++ b/scripts/upgrade-server.sh @@ -99,7 +99,7 @@ cp -r $tempdir/writefreely/{pages,static,templates,writefreely} . ./writefreely -migrate # restart service -echo "Restarting writefreely systemd service..." +echo "Starting writefreely systemd service..." if `systemctl start writefreely`; then echo "Success, version has been upgraded to $latest." else From b25cec8381006780f39a0433fef4ddaa03ca6545 Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Wed, 29 Jan 2020 05:49:12 -0500 Subject: [PATCH 47/69] Update copyright in upgrade script --- scripts/upgrade-server.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/upgrade-server.sh b/scripts/upgrade-server.sh index 36281bf..581085d 100755 --- a/scripts/upgrade-server.sh +++ b/scripts/upgrade-server.sh @@ -11,7 +11,7 @@ ## have not installed the binary `writefreely` in another location. ## ############################################################################### # -# Copyright © 2019 A Bunch Tell LLC. +# Copyright © 2019-2020 A Bunch Tell LLC. # # This file is part of WriteFreely. # From 4d5f58a7e65733f1fe6e4c8819708abdfcc295cd Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Wed, 29 Jan 2020 06:42:32 -0500 Subject: [PATCH 48/69] Fix date-based post header links Posts without an explicit title render the date as the post header in lists of posts (like on the blog index and tag pages). This updates localdate.js to properly adjust those dates, too. --- static/js/localdate.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/static/js/localdate.js b/static/js/localdate.js index 19fa502..879ebe4 100644 --- a/static/js/localdate.js +++ b/static/js/localdate.js @@ -1,9 +1,16 @@ -function toLocalDate(el) { - var d = new Date(el.getAttribute("datetime")); - el.textContent = d.toLocaleDateString(navigator.language || "en-US", { year: 'numeric', month: 'long', day: 'numeric' }); +function toLocalDate(dateEl, displayEl) { + var d = new Date(dateEl.getAttribute("datetime")); + displayEl.textContent = d.toLocaleDateString(navigator.language || "en-US", { year: 'numeric', month: 'long', day: 'numeric' }); } -var $dates = document.querySelectorAll("time"); +// Adjust dates on individual post pages, and on posts in a list *with* an explicit title +var $dates = document.querySelectorAll("article > time"); for (var i=0; i < $dates.length; i++) { - toLocalDate($dates[i]); + toLocalDate($dates[i], $dates[i]); } + +// Adjust dates on posts in a list without an explicit title, where they act as the header +$dates = document.querySelectorAll("h2.post-title > time"); +for (i=0; i < $dates.length; i++) { + toLocalDate($dates[i], $dates[i].querySelector('a')); +} \ No newline at end of file From d6b7a5925f20ba7ca3d9f210188a3f1ceba07cf1 Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Wed, 29 Jan 2020 09:11:02 -0500 Subject: [PATCH 49/69] Restrict /invite/{code} route to valid chars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, loading something like /invite/fFdblk😄 would return a 500, due to a mix of collations in MySQL while SELECTing for an invite with an ID of 'fFdblk😄'. This restricts the route to [a-zA-Z0-9] chars, to prevent this. --- routes.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes.go b/routes.go index ba531fb..023aca2 100644 --- a/routes.go +++ b/routes.go @@ -161,7 +161,7 @@ func InitRoutes(apper Apper, r *mux.Router) *mux.Router { // Handle special pages first write.HandleFunc("/login", handler.Web(viewLogin, UserLevelNoneRequired)) write.HandleFunc("/signup", handler.Web(handleViewLanding, UserLevelNoneRequired)) - write.HandleFunc("/invite/{code}", handler.Web(handleViewInvite, UserLevelOptional)).Methods("GET") + write.HandleFunc("/invite/{code:[a-zA-Z0-9]+}", handler.Web(handleViewInvite, UserLevelOptional)).Methods("GET") // TODO: show a reader-specific 404 page if the function is disabled write.HandleFunc("/read", handler.Web(viewLocalTimeline, UserLevelReader)) RouteRead(handler, UserLevelReader, write.PathPrefix("/read").Subrouter()) From 50901d2446ca9dc473a3820778aaff5aae250607 Mon Sep 17 00:00:00 2001 From: Matt Baer Date: Wed, 29 Jan 2020 13:01:21 -0500 Subject: [PATCH 50/69] Fix date format in `datetime` attribute Previously, the date format in this attribute for posts was invalid. This caused local date rendering to fail in Firefox. This fixes that. Closes #253 --- templates/chorus-collection-post.tmpl | 2 +- templates/collection-post.tmpl | 2 +- templates/include/posts.tmpl | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/templates/chorus-collection-post.tmpl b/templates/chorus-collection-post.tmpl index c231b64..f88e334 100644 --- a/templates/chorus-collection-post.tmpl +++ b/templates/chorus-collection-post.tmpl @@ -58,7 +58,7 @@ body#post header { {{if .Suspended}} {{template "user-suspended"}} {{end}} -
{{if .IsScheduled}}

Scheduled

{{end}}{{if .Title.String}}

{{.FormattedDisplayTitle}}

{{end}}{{if $.Collection.Format.ShowDates}}{{end}}
{{.HTMLContent}}
+
{{if .IsScheduled}}

Scheduled

{{end}}{{if .Title.String}}

{{.FormattedDisplayTitle}}

{{end}}{{if $.Collection.Format.ShowDates}}{{end}}
{{.HTMLContent}}
{{ if .Collection.ShowFooterBranding }}