From fb0d44f132d64a7cc68fda0fd9020a4e3e4348f7 Mon Sep 17 00:00:00 2001 From: Andrei Marcu Date: Thu, 12 Mar 2020 13:32:35 -0700 Subject: [PATCH] Custom pages: Implement adding custom markdown pages to the site navigation --- .gitignore | 1 + README.md | 1 + custom_pages.go | 40 ++++++++++++++++++ pages.go | 15 +++++++ server.go | 13 ++++++ static/images/404.jpg | Bin 18323 -> 19742 bytes templates.go | 3 ++ templates/404.html | 4 +- templates/API.html | 82 ++++++++++++++++++++---------------- templates/access.html | 4 +- templates/base.html | 13 ++++-- templates/custom_page.html | 19 +++++++++ templates/display/base.html | 50 +++++++++++----------- templates/paste.html | 53 +++++++++++++---------- 14 files changed, 207 insertions(+), 91 deletions(-) create mode 100644 custom_pages.go create mode 100644 templates/custom_page.html diff --git a/.gitignore b/.gitignore index 25b0cd6..c6750eb 100644 --- a/.gitignore +++ b/.gitignore @@ -34,4 +34,5 @@ linx-genkey files/ meta/ binaries/ +custom_pages/ authfile diff --git a/README.md b/README.md index 84da53d..98bf585 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ allowhotlink = true - ```-remoteuploads``` -- (optionally) enable remote uploads (/upload?url=https://...) - ```-nologs``` -- (optionally) disable request logs in stdout - ```-force-random-filename``` -- (optionally) force the use of random filenames +- ```-custompagespath "custom_pages"``` -- (optionally) specify path to directory containing markdown pages (must end in .md) that will be added to the site navigation (this can be useful for providing contact/support information and so on). For example, custom_pages/My_Page.md will become My Page in the site navigation #### Require API Keys for uploads - ```-authfile path/to/authfile``` -- (optionally) require authorization for upload/delete by providing a newline-separated file of scrypted auth keys diff --git a/custom_pages.go b/custom_pages.go new file mode 100644 index 0000000..105a04a --- /dev/null +++ b/custom_pages.go @@ -0,0 +1,40 @@ +package main + +import ( + "io/ioutil" + "log" + "path" + "strings" + + "github.com/microcosm-cc/bluemonday" + "github.com/russross/blackfriday" +) + +func initializeCustomPages(customPagesDir string) { + files, err := ioutil.ReadDir(customPagesDir) + if err != nil { + log.Fatal("Error reading the custom pages directory: ", err) + } + + for _, file := range files { + fileName := file.Name() + + if len(fileName) <= 3 { + continue + } + + if strings.EqualFold(string(fileName[len(fileName)-3:len(fileName)]), ".md") { + contents, err := ioutil.ReadFile(path.Join(customPagesDir, fileName)) + if err != nil { + log.Fatalf("Error reading file %s", fileName) + } + + unsafe := blackfriday.MarkdownCommon(contents) + html := bluemonday.UGCPolicy().SanitizeBytes(unsafe) + + fileName := fileName[0 : len(fileName)-3] + customPages[fileName] = string(html) + customPagesNames[fileName] = strings.ReplaceAll(fileName, "_", " ") + } + } +} diff --git a/pages.go b/pages.go index 6fcc934..ae8de42 100644 --- a/pages.go +++ b/pages.go @@ -50,6 +50,21 @@ func apiDocHandler(c web.C, w http.ResponseWriter, r *http.Request) { } } +func makeCustomPageHandler(fileName string) func(c web.C, w http.ResponseWriter, r *http.Request) { + return func(c web.C, w http.ResponseWriter, r *http.Request) { + err := renderTemplate(Templates["custom_page.html"], pongo2.Context{ + "siteurl": getSiteURL(r), + "forcerandom": Config.forceRandomFilename, + "contents": customPages[fileName], + "filename": fileName, + "pagename": customPagesNames[fileName], + }, r, w) + if err != nil { + oopsHandler(c, w, r, RespHTML, "") + } + } +} + func notFoundHandler(c web.C, w http.ResponseWriter, r *http.Request) { w.WriteHeader(404) err := renderTemplate(Templates["404.html"], pongo2.Context{}, r, w) diff --git a/server.go b/server.go index 661c2ea..e1f0c0a 100644 --- a/server.go +++ b/server.go @@ -70,6 +70,7 @@ var Config struct { s3ForcePathStyle bool forceRandomFilename bool accessKeyCookieExpiry uint64 + customPagesDir string } var Templates = make(map[string]*pongo2.Template) @@ -80,6 +81,8 @@ var timeStartedStr string var remoteAuthKeys []string var metaStorageBackend backends.MetaStorageBackend var storageBackend backends.StorageBackend +var customPages = make(map[string]string) +var customPagesNames = make(map[string]string) func setup() *web.Mux { mux := web.New() @@ -227,6 +230,14 @@ func setup() *web.Mux { mux.Get(selifIndexRe, unauthorizedHandler) mux.Get(torrentRe, fileTorrentHandler) + if Config.customPagesDir != "" { + initializeCustomPages(Config.customPagesDir) + for fileName := range customPagesNames { + mux.Get(Config.sitePath+fileName, makeCustomPageHandler(fileName)) + mux.Get(Config.sitePath+fileName+"/", makeCustomPageHandler(fileName)) + } + } + mux.NotFound(notFoundHandler) return mux @@ -298,6 +309,8 @@ func main() { flag.BoolVar(&Config.forceRandomFilename, "force-random-filename", false, "Force all uploads to use a random filename") flag.Uint64Var(&Config.accessKeyCookieExpiry, "access-cookie-expiry", 0, "Expiration time for access key cookies in seconds (set 0 to use session cookies)") + flag.StringVar(&Config.customPagesDir, "custompagespath", "", + "path to directory containing .md files to render as custom pages") iniflags.Parse() diff --git a/static/images/404.jpg b/static/images/404.jpg index 16ed400d7844ca4485db66802be08e112162f184..57bf16f0bb2a590f15c9c77c7baf5c660b0b2e0e 100644 GIT binary patch literal 19742 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 literal 18323 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 diff --git a/templates.go b/templates.go index ccd90c7..7d38b51 100644 --- a/templates.go +++ b/templates.go @@ -52,6 +52,7 @@ func populateTemplatesMap(tSet *pongo2.TemplateSet, tMap map[string]*pongo2.Temp "404.html", "oops.html", "access.html", + "custom_page.html", "display/audio.html", "display/image.html", @@ -85,6 +86,8 @@ func renderTemplate(tpl *pongo2.Template, context pongo2.Context, r *http.Reques context["sitepath"] = Config.sitePath context["selifpath"] = Config.selifPath + context["custom_pages_names"] = customPagesNames + var a string if Config.authFile == "" { a = "none" diff --git a/templates/404.html b/templates/404.html index 3b3d64e..bfdf439 100644 --- a/templates/404.html +++ b/templates/404.html @@ -1,7 +1,9 @@ {% extends "base.html" %} +{% block title %}{{sitename}} - 404 Not Found{% endblock %} + {% block content %}

-{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/templates/API.html b/templates/API.html index 11d9ab1..d58e398 100644 --- a/templates/API.html +++ b/templates/API.html @@ -1,59 +1,64 @@ {% extends "base.html" %} +{% block title %}{{sitename}} - API{% endblock %} + {% block head %} {% endblock %} {% block content %}
-
+

API

Client

-

To simplify uploading and deleting files, you can use linx-client, which uses this API.

+

To simplify uploading and deleting files, you can use linx-client, which uses this API.

{% if auth != "none" %}

Keys

-

This instance uses API Keys, therefore you will need to provide a key for uploading and deleting files.
To do so, add the Linx-Api-Key header with your key.

+

This instance uses API Keys, therefore you will need to provide a key for uploading and deleting + files.
To do so, add the Linx-Api-Key header with your key.

{% endif %}

Uploading a file

-

To upload a file, make a PUT request to {{ siteurl }}upload/ and you will get the url of your upload back.

+

To upload a file, make a PUT request to {{ siteurl }}upload/ and you will get the url of + your upload back.

Optional headers with the request

-{% if not forcerandom %} -

Randomize the filename
- Linx-Randomize: yes

-{% endif %} + {% if not forcerandom %} +

Randomize the filename
+ Linx-Randomize: yes

+ {% endif %} -

Specify a custom deletion key
- Linx-Delete-Key: mysecret

+

Specify a custom deletion key
+ Linx-Delete-Key: mysecret

-

Protect file with password
- Linx-Access-Key: mysecret

+

Protect file with password
+ Linx-Access-Key: mysecret

-

Specify an expiration time (in seconds)
- Linx-Expiry: 60

+

Specify an expiration time (in seconds)
+ Linx-Expiry: 60

-

Get a json response
- Accept: application/json

+

Get a json response
+ Accept: application/json

The json response will then contain:

-

“url”: the publicly available upload url
- “direct_url”: the url to access the file directly
- “filename”: the (optionally generated) filename
- “delete_key”: the (optionally generated) deletion key,
- “access_key”: the (optionally supplied) access key,
- “expiry”: the unix timestamp at which the file will expire (0 if never)
- “size”: the size in bytes of the file
- “mimetype”: the guessed mimetype of the file
- “sha256sum”: the sha256sum of the file,

+

“url”: the publicly available upload url
+ “direct_url”: the url to access the file directly
+ “filename”: the (optionally generated) filename
+ “delete_key”: the (optionally generated) deletion key,
+ “access_key”: the (optionally supplied) access key,
+ “expiry”: the unix timestamp at which the file will expire (0 if never)
+ “size”: the size in bytes of the file
+ “mimetype”: the guessed mimetype of the file
+ “sha256sum”: the sha256sum of the file,

Examples

@@ -92,7 +97,8 @@

Overwriting a file

-

To overwrite a file you uploaded, simply provide the Linx-Delete-Key header with the original file's deletion key.

+

To overwrite a file you uploaded, simply provide the Linx-Delete-Key header with the + original file's deletion key.

Example

@@ -108,7 +114,8 @@

Deleting a file

-

To delete a file you uploaded, make a DELETE request to {{ siteurl }}yourfile.ext with the delete key set as the Linx-Delete-Key header.

+

To delete a file you uploaded, make a DELETE request to {{ siteurl }}yourfile.ext with the + delete key set as the Linx-Delete-Key header.

Example

@@ -124,16 +131,17 @@ DELETED

Information about a file

-

To retrieve information about a file, make a GET request the public url with Accept: application/json headers and you will receive a json response containing:

+

To retrieve information about a file, make a GET request the public url with + Accept: application/json headers and you will receive a json response containing:

-

“url”: the publicly available upload url
- “direct_url”: the url to access the file directly
- “filename”: the (optionally generated) filename
- “expiry”: the unix timestamp at which the file will expire (0 if never)
- “size”: the size in bytes of the file
- “mimetype”: the guessed mimetype of the file
- “sha256sum”: the sha256sum of the file,

+

“url”: the publicly available upload url
+ “direct_url”: the url to access the file directly
+ “filename”: the (optionally generated) filename
+ “expiry”: the unix timestamp at which the file will expire (0 if never)
+ “size”: the size in bytes of the file
+ “mimetype”: the guessed mimetype of the file
+ “sha256sum”: the sha256sum of the file,

Example

@@ -141,6 +149,6 @@ DELETED
$ curl -H "Accept: application/json" {{ siteurl }}myphoto.jpg
 {"expiry":"0","filename":"myphoto.jpg","mimetype":"image/jpeg","sha256sum":"...","size":"..."}
-
+
-{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/templates/access.html b/templates/access.html index c61cf51..908ed06 100644 --- a/templates/access.html +++ b/templates/access.html @@ -1,5 +1,7 @@ {% extends "base.html" %} +{% block title %}{{sitename}} - Password protected file{% endblock %} + {% block content %}
@@ -9,4 +11,4 @@

-{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/templates/base.html b/templates/base.html index cda6746..86c5a29 100644 --- a/templates/base.html +++ b/templates/base.html @@ -1,5 +1,6 @@ + {% block title %}{{ sitename }}{% endblock %} @@ -16,12 +17,15 @@ {% block content %}{% endblock %} @@ -33,4 +37,5 @@ - + + \ No newline at end of file diff --git a/templates/custom_page.html b/templates/custom_page.html new file mode 100644 index 0000000..ac00341 --- /dev/null +++ b/templates/custom_page.html @@ -0,0 +1,19 @@ +{% extends "base.html" %} + +{% block title %}{{sitename}} - {{ pagename }}{% endblock %} + +{% block head %} + +{% endblock %} + +{% block content %} +
+
+
+

{{ pagename }}

+ + {{ contents|safe }} +
+
+
+{% endblock %} \ No newline at end of file diff --git a/templates/display/base.html b/templates/display/base.html index 935979f..d60f4d8 100644 --- a/templates/display/base.html +++ b/templates/display/base.html @@ -1,36 +1,36 @@ {% extends "../base.html" %} -{% block title %}{{ filename }}{% endblock %} +{% block title %}{{sitename}} - {{ filename }}{% endblock %} {% block bodymore %}{% endblock %} {% block content %} -
-
- {{ filename }} -
- -
- {% if expiry %} - file expires in {{ expiry }} | - {% endif %} - {% block infomore %}{% endblock %} - {{ size }} | - torrent | - get -
- - {% block infoleft %}{% endblock %} +
+
+ {{ filename }}
-
- -
- {% block main %}{% endblock %} -
- +
+ {% if expiry %} + file expires in {{ expiry }} | + {% endif %} + {% block infomore %}{% endblock %} + {{ size }} | + torrent | + get
- -{% endblock %} + {% block infoleft %}{% endblock %} +
+ +
+ +
+ {% block main %}{% endblock %} +
+ +
+ + +{% endblock %} \ No newline at end of file diff --git a/templates/paste.html b/templates/paste.html index eead748..84335d1 100644 --- a/templates/paste.html +++ b/templates/paste.html @@ -1,33 +1,40 @@ {% extends "base.html" %} +{% block title %}{{sitename}} - Paste{% endblock %} + {% block content %} -
-
-
-
- {% if not forcerandom %}{% endif %}. -
-
- - - - - - -
+ +
+
+
+ {% if not forcerandom %}{% endif %}.
+
+ + + -
- + +
- + +
+ +
+
+ -{% endblock %} +{% endblock %} \ No newline at end of file