From 6885dfbb38260cff48b4925e523d9feced45ad42 Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Sun, 19 Jan 2025 15:17:38 +0100 Subject: [PATCH 01/26] Add the ability to run cpolis from docker --- Dockerfile | 11 +++++++++++ cmd/backend/config.go | 4 ++-- docker-compose.yml | 22 ++++++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..03b3af7 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM golang:latest + +RUN apk add --no-cache pandoc + +WORKDIR /var/www/cpolis + +COPY . . + +RUN go build -o cpolis cmd/main.go + +CMD ["./cpolis"] diff --git a/cmd/backend/config.go b/cmd/backend/config.go index 1a1dabf..3a28519 100644 --- a/cmd/backend/config.go +++ b/cmd/backend/config.go @@ -51,8 +51,8 @@ func newConfig() *Config { MaxImgWidth: 1920, PDFDir: "/var/www/cpolis/pdfs", PicsDir: "/var/www/cpolis/pics", - Port: ":8080", - Version: "v0.15.3", + Port: ":1664", + Version: "v0.16.0", WebDir: "/var/www/cpolis/web", } } diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..1c3e265 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,22 @@ +services: + app: + build: . + ports: + - "1664:1664" + volumes: + - /path/to/serviceAccountKey.json:/var/www/cpolis/serviceAccountKey.json + - /var/log/cpolis.log:/var/log/cpolis.log + depends_on: + - db + + db: + image: mariadb:latest + environment: + MYSQL_ROOT_PASSWORD: example + MYSQL_DATABASE: cpolis + MYSQL_USER: exampleuser + MYSQL_PASSWORD: examplepass + ports: + - "3306:3306" + volumes: + - ./path/to/create_db.sql:/docker-entrypoint-initdb.d/create_db.sql From 9feb16a8d8a944e954c998b03b3d7c68793ce657 Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Sun, 19 Jan 2025 20:07:32 +0100 Subject: [PATCH 02/26] Change filepaths to use filepath.Join() where possible --- cmd/backend/articles.go | 5 +++-- cmd/backend/config.go | 13 +++++-------- cmd/calls/articles.go | 5 +++-- cmd/calls/pdf.go | 3 ++- cmd/frontend/articles.go | 18 +++++++++--------- cmd/frontend/images.go | 4 ++-- cmd/frontend/issues.go | 4 ++-- 7 files changed, 26 insertions(+), 26 deletions(-) diff --git a/cmd/backend/articles.go b/cmd/backend/articles.go index ffee3af..deeb93c 100644 --- a/cmd/backend/articles.go +++ b/cmd/backend/articles.go @@ -6,6 +6,7 @@ import ( "fmt" "log" "os" + "path/filepath" "time" "github.com/google/uuid" @@ -334,9 +335,9 @@ func (db *DB) DeleteArticle(id int64) error { } func WriteArticleToFile(c *Config, articleUUID uuid.UUID, content []byte) error { - articleAbsName := fmt.Sprint(c.ArticleDir, "/", articleUUID, ".md") + articlePath := filepath.Join(c.ArticleDir, fmt.Sprint(articleUUID, ".md")) - if err := os.WriteFile(articleAbsName, content, 0644); err != nil { + if err := os.WriteFile(articlePath, content, 0644); err != nil { return fmt.Errorf("error writing article %v to file: %v", articleUUID, err) } diff --git a/cmd/backend/config.go b/cmd/backend/config.go index 3a28519..7d55367 100644 --- a/cmd/backend/config.go +++ b/cmd/backend/config.go @@ -58,12 +58,9 @@ func newConfig() *Config { } func mkDir(path string, perm fs.FileMode) (string, error) { - var err error + name := filepath.Base(path) - stringSlice := strings.Split(path, "/") - name := stringSlice[len(stringSlice)-1] - - path, err = filepath.Abs(path) + path, err := filepath.Abs(path) if err != nil { return "", fmt.Errorf("error finding absolute path for %v directory: %v", name, err) } @@ -82,20 +79,20 @@ func mkFile(path string, filePerm, dirPerm fs.FileMode) (string, error) { return "", fmt.Errorf("error finding absolute path for %v: %v", path, err) } - stringSlice := strings.Split(path, "/") _, err = os.Stat(path) if os.IsNotExist(err) { - dir := strings.Join(stringSlice[:len(stringSlice)-1], "/") + dir := filepath.Dir(path) if err = os.MkdirAll(dir, dirPerm); err != nil { return "", fmt.Errorf("error creating %v: %v", dir, err) } - fileName := stringSlice[len(stringSlice)-1] + fileName := filepath.Base(path) file, err := os.Create(filepath.Join(dir, fileName)) if err != nil { return "", fmt.Errorf("error creating %v: %v", fileName, err) } defer file.Close() + if err = file.Chmod(filePerm); err != nil { return "", fmt.Errorf("error setting permissions for %v: %v", fileName, err) } diff --git a/cmd/calls/articles.go b/cmd/calls/articles.go index 3e46703..9908780 100644 --- a/cmd/calls/articles.go +++ b/cmd/calls/articles.go @@ -5,6 +5,7 @@ import ( "log" "net/http" "os" + "path/filepath" "github.com/google/uuid" b "streifling.com/jason/cpolis/cmd/backend" @@ -56,8 +57,8 @@ func ServeArticle(c *b.Config, db *b.DB) http.HandlerFunc { return } - articleAbsName := fmt.Sprint(c.ArticleDir, "/", article.UUID, ".md") - contentBytes, err := os.ReadFile(articleAbsName) + articlePath := filepath.Join(c.ArticleDir, fmt.Sprint(article.UUID, ".md")) + contentBytes, err := os.ReadFile(articlePath) if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) diff --git a/cmd/calls/pdf.go b/cmd/calls/pdf.go index 5de6a20..71bf215 100644 --- a/cmd/calls/pdf.go +++ b/cmd/calls/pdf.go @@ -5,6 +5,7 @@ import ( "log" "net/http" "os" + "path/filepath" b "streifling.com/jason/cpolis/cmd/backend" ) @@ -42,6 +43,6 @@ func ServePDF(c *b.Config) http.HandlerFunc { return } - http.ServeFile(w, r, c.PDFDir+"/"+r.PathValue("id")) + http.ServeFile(w, r, filepath.Join(c.PDFDir, r.PathValue("id"))) } } diff --git a/cmd/frontend/articles.go b/cmd/frontend/articles.go index c8947f5..26088db 100644 --- a/cmd/frontend/articles.go +++ b/cmd/frontend/articles.go @@ -456,8 +456,8 @@ func ReviewRejectedArticle(c *b.Config, db *b.DB, s map[string]*Session) http.Ha data.Image = data.Article.BannerLink - articleAbsName := fmt.Sprint(c.ArticleDir, "/", data.Article.UUID, ".md") - content, err := os.ReadFile(articleAbsName) + articlePath := filepath.Join(c.ArticleDir, fmt.Sprint(data.Article.UUID, ".md")) + content, err := os.ReadFile(articlePath) if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) @@ -587,7 +587,7 @@ func PublishArticle(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFu return } - if err = os.Remove(fmt.Sprint(c.ArticleDir, "/", oldArticle.UUID, ".md")); err != nil { + if err = os.Remove(filepath.Join(c.ArticleDir, fmt.Sprint(oldArticle.UUID, ".md"))); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -765,8 +765,8 @@ func ReviewArticle(c *b.Config, db *b.DB, s map[string]*Session, action, title, return } - articleAbsName := fmt.Sprint(c.ArticleDir, "/", article.UUID, ".md") - content, err := os.ReadFile(articleAbsName) + articlePath := filepath.Join(c.ArticleDir, fmt.Sprint(article.UUID, ".md")) + content, err := os.ReadFile(articlePath) if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) @@ -840,7 +840,7 @@ func DeleteArticle(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFun return } - if err = os.Remove(fmt.Sprint(c.ArticleDir, "/", article.UUID, ".md")); err != nil { + if err = os.Remove(filepath.Join(c.ArticleDir, fmt.Sprint(article.UUID, ".md"))); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -918,8 +918,8 @@ func AllowEditArticle(c *b.Config, db *b.DB, s map[string]*Session) http.Handler return } - src := fmt.Sprint(c.ArticleDir, "/", oldArticle.UUID, ".md") - dst := fmt.Sprint(c.ArticleDir, "/", newArticle.UUID, ".md") + src := filepath.Join(c.ArticleDir, fmt.Sprint(oldArticle.UUID, ".md")) + dst := filepath.Join(c.ArticleDir, fmt.Sprint(newArticle.UUID, ".md")) if err = b.CopyFile(src, dst); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) @@ -995,7 +995,7 @@ func EditArticle(c *b.Config, db *b.DB, s map[string]*Session) http.HandlerFunc data.Image = data.Article.BannerLink - content, err := os.ReadFile(fmt.Sprint(c.ArticleDir, "/", data.Article.UUID, ".md")) + content, err := os.ReadFile(filepath.Join(c.ArticleDir, fmt.Sprint(data.Article.UUID, ".md"))) if err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) diff --git a/cmd/frontend/images.go b/cmd/frontend/images.go index fb785f0..4889818 100644 --- a/cmd/frontend/images.go +++ b/cmd/frontend/images.go @@ -25,7 +25,7 @@ func UploadEasyMDEImage(c *b.Config, s map[string]*Session) http.HandlerFunc { } defer file.Close() - filename, err := b.SaveImage(file, c.MaxImgHeight, c.MaxImgWidth, c.PicsDir+"/") + filename, err := b.SaveImage(file, c.MaxImgHeight, c.MaxImgWidth, c.ImgDir) if err != nil { if err == b.ErrUnsupportedFormat { http.Error(w, "Das Dateiformat wird nicht unterstützt.", http.StatusBadRequest) @@ -57,7 +57,7 @@ func UploadImage(c *b.Config, s map[string]*Session, fileKey, htmlFile, htmlTemp } defer file.Close() - filename, err := b.SaveImage(file, c.MaxBannerHeight, c.MaxBannerWidth, c.PicsDir+"/") + filename, err := b.SaveImage(file, c.MaxBannerHeight, c.MaxBannerWidth, c.ImgDir) if err != nil { if err == b.ErrUnsupportedFormat { http.Error(w, "Das Dateiformat wird nicht unterstützt.", http.StatusBadRequest) diff --git a/cmd/frontend/issues.go b/cmd/frontend/issues.go index 7c41f75..d694c28 100644 --- a/cmd/frontend/issues.go +++ b/cmd/frontend/issues.go @@ -58,8 +58,8 @@ func PublishLatestIssue(c *b.Config, db *b.DB, s map[string]*Session) http.Handl return } - articleAbsName := fmt.Sprint(c.ArticleDir, "/", article.UUID, ".md") - if err = os.WriteFile(articleAbsName, content, 0644); err != nil { + articlePath := filepath.Join(c.ArticleDir, fmt.Sprint(article.UUID, ".md")) + if err = os.WriteFile(articlePath, content, 0644); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return From 43c1cb6d9ad1329c5b90bec7e64e5e6d925d6ae4 Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Sun, 19 Jan 2025 20:08:58 +0100 Subject: [PATCH 03/26] Use proper filepaths for docker-compose --- cmd/backend/config.go | 2 +- docker-compose.yml | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cmd/backend/config.go b/cmd/backend/config.go index 7d55367..787e9f5 100644 --- a/cmd/backend/config.go +++ b/cmd/backend/config.go @@ -43,7 +43,7 @@ func newConfig() *Config { ConfigFile: "/etc/cpolis/config.toml", CookieExpiryHours: 24 * 30, DBName: "cpolis", - FirebaseKey: "/var/www/cpolis/serviceAccountKey.json", + FirebaseKey: "/etc/cpolis/serviceAccountKey.json", LogFile: "/var/log/cpolis.log", MaxBannerHeight: 1080, MaxBannerWidth: 1920, diff --git a/docker-compose.yml b/docker-compose.yml index 1c3e265..b6e62ff 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,8 @@ services: ports: - "1664:1664" volumes: - - /path/to/serviceAccountKey.json:/var/www/cpolis/serviceAccountKey.json + - /etc/cpolis/config.toml:/etc/cpolis/config.toml + - /etc/cpolis/serviceAccountKey.json:/etc/cpolis/serviceAccountKey.json - /var/log/cpolis.log:/var/log/cpolis.log depends_on: - db @@ -19,4 +20,4 @@ services: ports: - "3306:3306" volumes: - - ./path/to/create_db.sql:/docker-entrypoint-initdb.d/create_db.sql + - ./create_db.sql:/docker-entrypoint-initdb.d/create_db.sql From 7b04149a287046b33ef59732ff32c3964e07597c Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Sun, 19 Jan 2025 20:10:06 +0100 Subject: [PATCH 04/26] Rename PicsDir to ImgDir --- cmd/backend/config.go | 30 +++++++++++++++--------------- cmd/backend/docx.go | 2 +- cmd/backend/images.go | 2 +- cmd/calls/images.go | 2 +- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/cmd/backend/config.go b/cmd/backend/config.go index 787e9f5..42d53a6 100644 --- a/cmd/backend/config.go +++ b/cmd/backend/config.go @@ -20,10 +20,10 @@ type Config struct { Description string Domain string FirebaseKey string + ImgDir string Link string LogFile string PDFDir string - PicsDir string Port string Title string Version string @@ -44,13 +44,13 @@ func newConfig() *Config { CookieExpiryHours: 24 * 30, DBName: "cpolis", FirebaseKey: "/etc/cpolis/serviceAccountKey.json", + ImgDir: "/var/www/cpolis/images", LogFile: "/var/log/cpolis.log", MaxBannerHeight: 1080, MaxBannerWidth: 1920, MaxImgHeight: 1080, MaxImgWidth: 1920, PDFDir: "/var/www/cpolis/pdfs", - PicsDir: "/var/www/cpolis/pics", Port: ":1664", Version: "v0.16.0", WebDir: "/var/www/cpolis/web", @@ -113,10 +113,10 @@ func (c *Config) handleCliArgs() error { flag.StringVar(&c.Description, "desc", c.Description, "channel description") flag.StringVar(&c.Domain, "domain", c.Domain, "domain name") flag.StringVar(&c.FirebaseKey, "firebase", c.FirebaseKey, "Firebase service account key file") + flag.StringVar(&c.ImgDir, "pics", c.ImgDir, "pictures directory") flag.StringVar(&c.Link, "link", c.Link, "channel Link") flag.StringVar(&c.LogFile, "log", c.LogFile, "log file") flag.StringVar(&c.PDFDir, "pdfs", c.PDFDir, "pdf directory") - flag.StringVar(&c.PicsDir, "pics", c.PicsDir, "pictures directory") flag.StringVar(&c.Title, "title", c.Title, "channel title") flag.StringVar(&c.WebDir, "web", c.WebDir, "web directory") flag.IntVar(&c.CookieExpiryHours, "cookie-expiry-hours", c.CookieExpiryHours, "cookies expire after this amount of hours") @@ -220,6 +220,18 @@ func (c *Config) setupConfig(cliConfig *Config) error { return fmt.Errorf("error setting up file: %v", err) } + if cliConfig.ImgDir != defaultConfig.ImgDir { + c.ImgDir = cliConfig.ImgDir + } + c.ImgDir, err = filepath.Abs(c.ImgDir) + if err != nil { + return fmt.Errorf("error setting absolute filepath for PicsDir: %v", err) + } + c.ImgDir, err = mkDir(c.ImgDir, 0700) + if err != nil { + return fmt.Errorf("error setting up directory: %v", err) + } + if cliConfig.Link != defaultConfig.Link { c.Link = cliConfig.Link } @@ -264,18 +276,6 @@ func (c *Config) setupConfig(cliConfig *Config) error { return fmt.Errorf("error setting up directory: %v", err) } - if cliConfig.PicsDir != defaultConfig.PicsDir { - c.PicsDir = cliConfig.PicsDir - } - c.PicsDir, err = filepath.Abs(c.PicsDir) - if err != nil { - return fmt.Errorf("error setting absolute filepath for PicsDir: %v", err) - } - c.PicsDir, err = mkDir(c.PicsDir, 0700) - if err != nil { - return fmt.Errorf("error setting up directory: %v", err) - } - if cliConfig.Port != defaultConfig.Port { c.Port = cliConfig.Port } diff --git a/cmd/backend/docx.go b/cmd/backend/docx.go index 37f895c..8e34e07 100644 --- a/cmd/backend/docx.go +++ b/cmd/backend/docx.go @@ -45,7 +45,7 @@ func ConvertToMarkdown(c *Config, filename string) ([]byte, error) { } defer image.Close() - newImageName, err := SaveImage(image, c.MaxImgHeight, c.MaxImgWidth, c.PicsDir) + newImageName, err := SaveImage(image, c.MaxImgHeight, c.MaxImgWidth, c.ImgDir) if err != nil { return nil, fmt.Errorf("error saving image %v: %v", name, err) } diff --git a/cmd/backend/images.go b/cmd/backend/images.go index a8dce5f..861f5d4 100644 --- a/cmd/backend/images.go +++ b/cmd/backend/images.go @@ -48,7 +48,7 @@ func SaveImage(src io.Reader, maxHeight, maxWidth int, path string) (string, err } func CleanUpImages(c *Config, db *DB) error { - if err := filepath.Walk(c.PicsDir, func(path string, info fs.FileInfo, err error) error { + if err := filepath.Walk(c.ImgDir, func(path string, info fs.FileInfo, err error) error { if err != nil { return fmt.Errorf("error walking images filepath: %v", err) } diff --git a/cmd/calls/images.go b/cmd/calls/images.go index e8edab2..de316b0 100644 --- a/cmd/calls/images.go +++ b/cmd/calls/images.go @@ -16,6 +16,6 @@ func ServeImage(c *b.Config, s map[string]*f.Session) http.HandlerFunc { } } - http.ServeFile(w, r, filepath.Join(c.PicsDir, r.PathValue("pic"))) + http.ServeFile(w, r, filepath.Join(c.ImgDir, r.PathValue("pic"))) } } From f99358729cf7aae84c4edd6a80a44ff972e75c84 Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Sun, 19 Jan 2025 20:10:51 +0100 Subject: [PATCH 05/26] Create ValidateSession() to not have unwanted side effects when validating session --- cmd/calls/images.go | 2 +- cmd/frontend/sessions.go | 34 +++++++++++++++++++++------------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/cmd/calls/images.go b/cmd/calls/images.go index de316b0..ea0504a 100644 --- a/cmd/calls/images.go +++ b/cmd/calls/images.go @@ -10,7 +10,7 @@ import ( func ServeImage(c *b.Config, s map[string]*f.Session) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - if _, err := f.ManageSession(w, r, c, s); err != nil { + if _, err := f.ValidateSession(w, r, c, s); err != nil { if !tokenIsVerified(w, r, c) { return } diff --git a/cmd/frontend/sessions.go b/cmd/frontend/sessions.go index 2a4b59d..71c7d94 100644 --- a/cmd/frontend/sessions.go +++ b/cmd/frontend/sessions.go @@ -64,31 +64,39 @@ func StartSessions() (map[string]*Session, chan string) { return sessions, sessionExpiryChan } -// ManageSession is used for verifying that the user is logged in and returns -// their session and an error. It also handles cases where the user is not -// logged in. -func ManageSession(w http.ResponseWriter, r *http.Request, c *b.Config, s map[string]*Session) (*Session, error) { - tmpl, tmplErr := template.ParseFiles(filepath.Join(c.WebDir, "templates", "index.html"), filepath.Join(c.WebDir, "templates", "login.html")) - +// ValidateSession is used for verifying that the user is logged in and returns +// their session and an error. +func ValidateSession(w http.ResponseWriter, r *http.Request, c *b.Config, s map[string]*Session) (*Session, error) { cookie, err := r.Cookie("cpolis_session") if err != nil { - if err = template.Must(tmpl, tmplErr).ExecuteTemplate(w, "page-content", nil); err != nil { - return nil, fmt.Errorf("error executing template: %v", err) - } - return nil, errors.New("no cookie set") } session, ok := s[cookie.Value] if !ok { - cookie.Expires = time.Now() - http.SetCookie(w, cookie) + return nil, errors.New("session does not exist") + } + return session, nil +} + +// ManageSession is used for verifying that the user is logged in and returns +// their session and an error. It also handles cases where the user is not +// logged in. +func ManageSession(w http.ResponseWriter, r *http.Request, c *b.Config, s map[string]*Session) (*Session, error) { + session, err := ValidateSession(w, r, c, s) + if err != nil { + if session.cookie != nil { + session.cookie.Expires = time.Now() + http.SetCookie(w, session.cookie) + } + + tmpl, tmplErr := template.ParseFiles(filepath.Join(c.WebDir, "templates", "index.html"), filepath.Join(c.WebDir, "templates", "login.html")) if err = template.Must(tmpl, tmplErr).ExecuteTemplate(w, "page-content", nil); err != nil { return nil, fmt.Errorf("error executing template: %v", err) } - return nil, errors.New("session does not exist") + return nil, err } session.cookie.Expires = time.Now().Add(time.Hour * time.Duration(c.CookieExpiryHours)) From d882daeb018211288a10c586cb89c7451aeb9bb9 Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Sun, 19 Jan 2025 20:15:56 +0100 Subject: [PATCH 06/26] Correct command line flag for ImgDir --- .air.toml | 2 +- cmd/backend/config.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.air.toml b/.air.toml index 5bb1f10..6fe017d 100644 --- a/.air.toml +++ b/.air.toml @@ -12,11 +12,11 @@ args_bin = [ "-domain localhost", "-feed tmp/cpolis.atom", "-firebase tmp/firebase.json", + "-images tmp/pics", "-img-width 256", "-link https://distrikt-ni-st.de", "-log tmp/cpolis.log", "-pdfs tmp/pdfs", - "-pics tmp/pics", "-port 8080", "-title 'Freimaurer Distrikt Niedersachsen und Sachsen-Anhalt'", "-web web", diff --git a/cmd/backend/config.go b/cmd/backend/config.go index 42d53a6..a35b6c7 100644 --- a/cmd/backend/config.go +++ b/cmd/backend/config.go @@ -113,7 +113,7 @@ func (c *Config) handleCliArgs() error { flag.StringVar(&c.Description, "desc", c.Description, "channel description") flag.StringVar(&c.Domain, "domain", c.Domain, "domain name") flag.StringVar(&c.FirebaseKey, "firebase", c.FirebaseKey, "Firebase service account key file") - flag.StringVar(&c.ImgDir, "pics", c.ImgDir, "pictures directory") + flag.StringVar(&c.ImgDir, "images", c.ImgDir, "images directory") flag.StringVar(&c.Link, "link", c.Link, "channel Link") flag.StringVar(&c.LogFile, "log", c.LogFile, "log file") flag.StringVar(&c.PDFDir, "pdfs", c.PDFDir, "pdf directory") From 04283d5917d16ec64ee903fde0afb1c1a5fa8359 Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Sun, 19 Jan 2025 20:29:10 +0100 Subject: [PATCH 07/26] Restore old way of managing session while keeping slimmed down version --- cmd/frontend/sessions.go | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/cmd/frontend/sessions.go b/cmd/frontend/sessions.go index 71c7d94..153a439 100644 --- a/cmd/frontend/sessions.go +++ b/cmd/frontend/sessions.go @@ -84,19 +84,27 @@ func ValidateSession(w http.ResponseWriter, r *http.Request, c *b.Config, s map[ // their session and an error. It also handles cases where the user is not // logged in. func ManageSession(w http.ResponseWriter, r *http.Request, c *b.Config, s map[string]*Session) (*Session, error) { - session, err := ValidateSession(w, r, c, s) - if err != nil { - if session.cookie != nil { - session.cookie.Expires = time.Now() - http.SetCookie(w, session.cookie) - } + tmpl, tmplErr := template.ParseFiles(filepath.Join(c.WebDir, "templates", "index.html"), filepath.Join(c.WebDir, "templates", "login.html")) - tmpl, tmplErr := template.ParseFiles(filepath.Join(c.WebDir, "templates", "index.html"), filepath.Join(c.WebDir, "templates", "login.html")) + cookie, err := r.Cookie("cpolis_session") + if err != nil { if err = template.Must(tmpl, tmplErr).ExecuteTemplate(w, "page-content", nil); err != nil { return nil, fmt.Errorf("error executing template: %v", err) } - return nil, err + return nil, errors.New("no cookie set") + } + + session, ok := s[cookie.Value] + if !ok { + cookie.Expires = time.Now() + http.SetCookie(w, cookie) + + if err = template.Must(tmpl, tmplErr).ExecuteTemplate(w, "page-content", nil); err != nil { + return nil, fmt.Errorf("error executing template: %v", err) + } + + return nil, errors.New("session does not exist") } session.cookie.Expires = time.Now().Add(time.Hour * time.Duration(c.CookieExpiryHours)) From 5b417ef87dda37eba086293f727381ae5b75c0da Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Sun, 19 Jan 2025 20:34:12 +0100 Subject: [PATCH 08/26] Change ValidateSession() to SessionIsActive() which only returns a bool --- cmd/calls/images.go | 2 +- cmd/frontend/sessions.go | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/cmd/calls/images.go b/cmd/calls/images.go index ea0504a..a2113dc 100644 --- a/cmd/calls/images.go +++ b/cmd/calls/images.go @@ -10,7 +10,7 @@ import ( func ServeImage(c *b.Config, s map[string]*f.Session) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - if _, err := f.ValidateSession(w, r, c, s); err != nil { + if !f.SessionIsActive(r, s) { if !tokenIsVerified(w, r, c) { return } diff --git a/cmd/frontend/sessions.go b/cmd/frontend/sessions.go index 153a439..7aacbe8 100644 --- a/cmd/frontend/sessions.go +++ b/cmd/frontend/sessions.go @@ -66,18 +66,14 @@ func StartSessions() (map[string]*Session, chan string) { // ValidateSession is used for verifying that the user is logged in and returns // their session and an error. -func ValidateSession(w http.ResponseWriter, r *http.Request, c *b.Config, s map[string]*Session) (*Session, error) { +func SessionIsActive(r *http.Request, s map[string]*Session) bool { cookie, err := r.Cookie("cpolis_session") if err != nil { - return nil, errors.New("no cookie set") + return false } - session, ok := s[cookie.Value] - if !ok { - return nil, errors.New("session does not exist") - } - - return session, nil + _, ok := s[cookie.Value] + return ok } // ManageSession is used for verifying that the user is logged in and returns From 2f4d5d4c7ccd9409ed5d7a3fac6ffa87b04ad55a Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Sun, 19 Jan 2025 20:35:35 +0100 Subject: [PATCH 09/26] Correct comment --- cmd/frontend/sessions.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/frontend/sessions.go b/cmd/frontend/sessions.go index 7aacbe8..ae29c81 100644 --- a/cmd/frontend/sessions.go +++ b/cmd/frontend/sessions.go @@ -64,8 +64,8 @@ func StartSessions() (map[string]*Session, chan string) { return sessions, sessionExpiryChan } -// ValidateSession is used for verifying that the user is logged in and returns -// their session and an error. +// SessionIsActive is used for verifying that the user is logged in and returns +// a bool. func SessionIsActive(r *http.Request, s map[string]*Session) bool { cookie, err := r.Cookie("cpolis_session") if err != nil { From a7b6fb9705ebb7e185b76c12621217d32e4cb6b8 Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Sun, 19 Jan 2025 20:41:48 +0100 Subject: [PATCH 10/26] Correct probably last occurance of manually set path delimeter --- cmd/backend/docx.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/backend/docx.go b/cmd/backend/docx.go index 8e34e07..5413c6f 100644 --- a/cmd/backend/docx.go +++ b/cmd/backend/docx.go @@ -33,7 +33,7 @@ func ConvertToMarkdown(c *Config, filename string) ([]byte, error) { return nil, fmt.Errorf("error reading markdown file: %v", err) } - imageNames, err := filepath.Glob(filepath.Join(tmpDir, "/media/*")) + imageNames, err := filepath.Glob(filepath.Join(tmpDir, "media", "*")) if err != nil { return nil, fmt.Errorf("error getting docx images from temporary directory: %v", err) } From 3d08cc7612a27b2245845f0bf5d6b5a435c3bac9 Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Mon, 20 Jan 2025 20:25:50 +0100 Subject: [PATCH 11/26] Make background image check way more efficient --- cmd/backend/images.go | 86 ++++++++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 37 deletions(-) diff --git a/cmd/backend/images.go b/cmd/backend/images.go index 861f5d4..f7c5160 100644 --- a/cmd/backend/images.go +++ b/cmd/backend/images.go @@ -17,6 +17,53 @@ import ( var ErrUnsupportedFormat error = image.ErrFormat // used internally by imaging +func checkImageUsage(c *Config, db *DB, name string) (bool, error) { + imageWasFound := false + + if err := filepath.Walk(c.ArticleDir, func(path string, info fs.FileInfo, err error) error { + if err != nil { + return fmt.Errorf("error walking articles filepath: %v", err) + } + + if !info.IsDir() { + mdFile, err := os.Open(path) + if err != nil { + return fmt.Errorf("error opening article %v: %v", info.Name(), err) + } + defer mdFile.Close() + + scanner := bufio.NewScanner(mdFile) + for scanner.Scan() { + if strings.Contains(scanner.Text(), name) { + imageWasFound = true + return nil + } + } + + return scanner.Err() + } + + return nil + }); err != nil { + return false, fmt.Errorf("error walking articles filepath: %v", err) + } + + if !imageWasFound { + users, err := db.GetAllUsers(c) + if err != nil { + return false, fmt.Errorf("error getting all users: %v", err) + } + + for _, user := range users { + if name == user.ProfilePicLink { + return true, nil + } + } + } + + return imageWasFound, nil +} + func SaveImage(src io.Reader, maxHeight, maxWidth int, path string) (string, error) { img, err := imaging.Decode(src, imaging.AutoOrientation(true)) if err != nil { @@ -56,45 +103,10 @@ func CleanUpImages(c *Config, db *DB) error { if !info.IsDir() { imageName := info.Name() imagePath := path - imageWasFound := false - if err = filepath.Walk(c.ArticleDir, func(path string, info fs.FileInfo, err error) error { - if err != nil { - return fmt.Errorf("error walking articles filepath: %v", err) - } - - if !info.IsDir() { - mdFile, err := os.Open(path) - if err != nil { - return fmt.Errorf("error opening article %v: %v", info.Name(), err) - } - defer mdFile.Close() - - scanner := bufio.NewScanner(mdFile) - - for scanner.Scan() { - if strings.Contains(scanner.Text(), imageName) { - imageWasFound = true - } - } - - return scanner.Err() - } - - return nil - }); err != nil { - return fmt.Errorf("error walking articles filepath: %v", err) - } - - users, err := db.GetAllUsers(c) + imageWasFound, err := checkImageUsage(c, db, imageName) if err != nil { - return fmt.Errorf("error getting all users: %v", err) - } - - for _, user := range users { - if imageName == user.ProfilePicLink { - imageWasFound = true - } + return fmt.Errorf("error checking image usage: %v", err) } if !imageWasFound { From 9199f202bee1955af97cf20f6f263059ae41b180 Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Fri, 24 Jan 2025 17:42:05 +0100 Subject: [PATCH 12/26] Check atom feed for nil returns --- cmd/backend/atom.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/cmd/backend/atom.go b/cmd/backend/atom.go index 0f344c7..25d22e0 100644 --- a/cmd/backend/atom.go +++ b/cmd/backend/atom.go @@ -1,6 +1,7 @@ package backend import ( + "errors" "fmt" "io" "os" @@ -12,6 +13,9 @@ func GenerateAtomFeed(c *Config, db *DB) (*string, error) { feed := atom.NewFeed(c.Title) feed.ID = atom.NewID("urn:feed:1") feed.Subtitle = atom.NewText("text", c.Description) + if feed.Subtitle == nil { + return nil, errors.New("feed subtitle was not created") + } linkID := feed.AddLink(atom.NewLink(c.Link)) feed.Links[linkID].Rel = "self" @@ -34,15 +38,24 @@ func GenerateAtomFeed(c *Config, db *DB) (*string, error) { entry.ID = atom.NewID(fmt.Sprint("urn:entry:", article.ID)) entry.Published = atom.NewDate(article.Created) entry.Content = atom.NewContent(atom.OutOfLine, "text/html", fmt.Sprint(c.Domain, "/article/serve/", article.UUID)) + if entry.Content == nil { + return nil, errors.New("entry content was not created") + } if article.AutoGenerated { entry.Summary = atom.NewText("text", "automatically generated") + if entry.Summary == nil { + return nil, errors.New("entry summary was not created") + } } else { articleSummary, err := ConvertToPlain(article.Summary) if err != nil { return nil, fmt.Errorf("error converting description to plain text for Atom feed: %v", err) } entry.Summary = atom.NewText("text", articleSummary) + if entry.Summary == nil { + return nil, errors.New("entry summary was not created") + } } if len(article.BannerLink) > 0 { From 095576a234e424491b107b6bffcb16c8f6e568c0 Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Fri, 24 Jan 2025 18:13:13 +0100 Subject: [PATCH 13/26] Add tailwindcss to Dockerfile --- Dockerfile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Dockerfile b/Dockerfile index 03b3af7..d017064 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,6 +6,11 @@ WORKDIR /var/www/cpolis COPY . . +RUN curl -sLO https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64 +RUN chmod +x tailwindcss-linux-x64 +RUN mv tailwindcss-linux-x64 tailwindcss +RUN ./web/static/css/input.css -o ./web/static/css/style.css + RUN go build -o cpolis cmd/main.go CMD ["./cpolis"] From b120341d7844e742a676f51374de5d60875c1bd3 Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Fri, 24 Jan 2025 18:28:18 +0100 Subject: [PATCH 14/26] Correct docker-compose.yml --- docker-compose.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index b6e62ff..9e7846a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,10 +13,9 @@ services: db: image: mariadb:latest environment: - MYSQL_ROOT_PASSWORD: example MYSQL_DATABASE: cpolis - MYSQL_USER: exampleuser - MYSQL_PASSWORD: examplepass + MYSQL_USER: cpolis + MYSQL_PASSWORD: ${DB_PASS} ports: - "3306:3306" volumes: From 40fbb937323f46cbd12fe4c84f38f5547cecc6af Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Fri, 24 Jan 2025 18:28:29 +0100 Subject: [PATCH 15/26] Add docker-start.sh --- docker-start.sh | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 docker-start.sh diff --git a/docker-start.sh b/docker-start.sh new file mode 100644 index 0000000..53b23e5 --- /dev/null +++ b/docker-start.sh @@ -0,0 +1,7 @@ +#! /bin/bash - + +read -sp "Enter DB password: " DB_PASS +echo + +export DB_PASS +docker-compose up -d From cafb158323355cd4b2b94331070f5ba3a6cf6630 Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Fri, 24 Jan 2025 18:40:58 +0100 Subject: [PATCH 16/26] Bug fix --- Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index d017064..0dfa506 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,7 @@ FROM golang:latest -RUN apk add --no-cache pandoc +RUN apt update +RUN apt install -y pandoc WORKDIR /var/www/cpolis @@ -9,7 +10,7 @@ COPY . . RUN curl -sLO https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64 RUN chmod +x tailwindcss-linux-x64 RUN mv tailwindcss-linux-x64 tailwindcss -RUN ./web/static/css/input.css -o ./web/static/css/style.css +RUN tailwindcss -i ./web/static/css/input.css -o ./web/static/css/style.css RUN go build -o cpolis cmd/main.go From 2c6b15bc6d3cf30a236017df7ee5ac7d2f25a458 Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Fri, 24 Jan 2025 18:52:00 +0100 Subject: [PATCH 17/26] Make docker-start.sh executable --- docker-start.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 docker-start.sh diff --git a/docker-start.sh b/docker-start.sh old mode 100644 new mode 100755 From 1b72f05add885fc6249a77a428c3ef0ab8433e73 Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Fri, 24 Jan 2025 20:09:23 +0100 Subject: [PATCH 18/26] Fix golang and tailwind version in Dockerfile --- Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 0dfa506..11a067b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:latest +FROM golang:1.23 RUN apt update RUN apt install -y pandoc @@ -7,10 +7,10 @@ WORKDIR /var/www/cpolis COPY . . -RUN curl -sLO https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64 +RUN curl -sLO https://github.com/tailwindlabs/tailwindcss/releases/download/v3.4.15/tailwindcss-linux-x64 RUN chmod +x tailwindcss-linux-x64 RUN mv tailwindcss-linux-x64 tailwindcss -RUN tailwindcss -i ./web/static/css/input.css -o ./web/static/css/style.css +RUN ./tailwindcss -i ./web/static/css/input.css -o ./web/static/css/style.css RUN go build -o cpolis cmd/main.go From a93603eac017da7c01b728d4ba097df7ddc5fd18 Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Fri, 24 Jan 2025 20:09:47 +0100 Subject: [PATCH 19/26] Use generic /bin/sh in docker-start.sh --- docker-start.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-start.sh b/docker-start.sh index 53b23e5..6bacc81 100755 --- a/docker-start.sh +++ b/docker-start.sh @@ -1,4 +1,4 @@ -#! /bin/bash - +#! /bin/sh - read -sp "Enter DB password: " DB_PASS echo From 57953b2cfdfd4a4dc9e1c86e4e2baaaa998f919e Mon Sep 17 00:00:00 2001 From: Jason Streifling Date: Fri, 24 Jan 2025 20:09:58 +0100 Subject: [PATCH 20/26] Fix htmx version --- web/templates/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/templates/index.html b/web/templates/index.html index c46b584..6ddf7f1 100644 --- a/web/templates/index.html +++ b/web/templates/index.html @@ -42,7 +42,7 @@

{{.Version}} - Alpha: Drastische Änderungen und Fehler vorbehalten.

- +