From 742251d742038f9a51815a4a1f946512ef57500e Mon Sep 17 00:00:00 2001 From: Maas Lalani Date: Sun, 27 Jun 2021 12:25:30 -0400 Subject: [PATCH] Ensure file is executable for preprocessing to work --- README.md | 23 ++++++++++++++---- examples/import.md | 2 ++ examples/preprocess.md | 48 +++++++++++++++++++++++++++----------- internal/file/file.go | 6 +++++ internal/file/file_test.go | 44 ++++++++++++++++++++++++++++++++++ internal/model/model.go | 13 ++++++++--- 6 files changed, 114 insertions(+), 22 deletions(-) create mode 100644 examples/import.md mode change 100644 => 100755 examples/preprocess.md diff --git a/README.md b/README.md index e7fcaca..554720e 100644 --- a/README.md +++ b/README.md @@ -65,13 +65,26 @@ Create slides and present them without ever leaving your terminal. --- -Include ASCII graphs with GraphViz + graph-easy. -https://dot-to-ascii.ggerganov.com/ +# Pre-process slides -┌──────────┐ ┌────────────┐ ┌────────┐ -│ GraphViz │ ──▶ │ graph-easy │ ──▶ │ slides │ -└──────────┘ └────────────┘ └────────┘ +You can add a code block with ~~~ and write a command to run before displaying +the slides, the text inside the code block will be passed as stdin to the command +and the code block will be replaced with the stdout of the command. +~~~graph-easy --as=boxart +[ A ] - to -> [ B ] +~~~ + +The above will be pre-processed to look like: + +┌───┐ to ┌───┐ +│ A │ ────> │ B │ +└───┘ └───┘ + +For security reasons, you must pass a file that has execution permissions +for the slides to be pre-processed. + +chmod +x file.md ``` Checkout the [example slides](./examples). diff --git a/examples/import.md b/examples/import.md new file mode 100644 index 0000000..dbb8049 --- /dev/null +++ b/examples/import.md @@ -0,0 +1,2 @@ +This is just an example of how to import text from other files with +preprocess.md diff --git a/examples/preprocess.md b/examples/preprocess.md old mode 100644 new mode 100755 index c1e359f..e1e84d0 --- a/examples/preprocess.md +++ b/examples/preprocess.md @@ -1,8 +1,36 @@ # Slides +You can add a code block with three tildes (~) and write a command to run before displaying +the slides, the text inside the code block will be passed as stdin to the command +and the code block will be replaced with the stdout of the command. + +``` +~~~graph-easy --as=boxart +[ A ] - to -> [ B ] +~~~ +``` + +The above will be pre-processed to look like: + +NOTE: You need `graph-easy` installed and in your `$PATH` + +``` +┌───┐ to ┌───┐ +│ A │ ────> │ B │ +└───┘ └───┘ +``` + +For security reasons, you must pass a file that has execution permissions +for the slides to be pre-processed. + +``` +chmod +x file.md +``` + +--- + ~~~sd replaced processed -This content will be replaced and passed into stdin -of the command above +This content will be passed in as stdin and will be replaced. ~~~ --- @@ -11,21 +39,13 @@ Any command will work ~~~echo "You can do whatever, really" This doesn't matter, since it will be replaced by the stdout -of the command above +of the command above because the command will disregard stdin. ~~~ --- -Pre-process Graphs +You can use this to import snippets of code from other files: -~~~graph-easy --as=boxart -[ A ] - to -> [ B ] +~~~xargs cat +examples/import.md ~~~ - -The above will be pre-processed to look like: - -``` -┌───┐ to ┌───┐ -│ A │ ────> │ B │ -└───┘ └───┘ -``` diff --git a/internal/file/file.go b/internal/file/file.go index a5f6bc2..c1afe0c 100644 --- a/internal/file/file.go +++ b/internal/file/file.go @@ -3,6 +3,7 @@ package file import ( + "io/fs" "os" ) @@ -16,3 +17,8 @@ func Exists(filepath string) bool { } return !info.IsDir() } + +// IsExecutable returns whether a file has execution permissions +func IsExecutable(s fs.FileInfo) bool { + return s.Mode().Perm()&0111 == 0111 +} diff --git a/internal/file/file_test.go b/internal/file/file_test.go index ff16f6f..d459721 100644 --- a/internal/file/file_test.go +++ b/internal/file/file_test.go @@ -1,6 +1,9 @@ package file_test import ( + "fmt" + "io/fs" + "os" "testing" "github.com/maaslalani/slides/internal/file" @@ -26,3 +29,44 @@ func TestExists(t *testing.T) { }) } } + +func TestIsExecutable(t *testing.T) { + tests := []struct { + perm fs.FileMode + expected bool + }{ + {0101, false}, + {0111, true}, + {0644, false}, + {0666, false}, + {0777, true}, + } + + for _, tc := range tests { + t.Run(fmt.Sprint(tc.perm), func(t *testing.T) { + tmp, err := os.CreateTemp(os.TempDir(), "slides-*") + if err != nil { + t.Fatal("failed to create temp file") + } + defer os.Remove(tmp.Name()) + + err = tmp.Chmod(tc.perm) + if err != nil { + t.Fatal(err) + } + + s, err := tmp.Stat() + if err != nil { + t.Fatal("failed to stat file") + } + + want := tc.expected + got := file.IsExecutable(s) + if tc.expected != got { + t.Log(want) + t.Log(got) + t.Fatalf("IsExecutable returned an incorrect result, want: %t, got %t", want, got) + } + }) + } +} diff --git a/internal/model/model.go b/internal/model/model.go index fdaa5fa..b25a5f5 100644 --- a/internal/model/model.go +++ b/internal/model/model.go @@ -14,6 +14,7 @@ import ( tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/glamour" "github.com/maaslalani/slides/internal/code" + "github.com/maaslalani/slides/internal/file" "github.com/maaslalani/slides/internal/meta" "github.com/maaslalani/slides/internal/process" "github.com/maaslalani/slides/styles" @@ -68,8 +69,6 @@ func (m *Model) Load() error { return err } - content = process.Pre(content) - slides := strings.Split(content, delimiter) metaData, exists := meta.New().ParseHeader(slides[0]) @@ -162,7 +161,15 @@ func readFile(path string) (string, error) { if err != nil { return "", err } - return string(b), err + content := string(b) + + // Pre-process slides if the file is executable to avoid + // unintentional code execution when presenting slides + if file.IsExecutable(s) { + content = process.Pre(content) + } + + return content, err } func readStdin() (string, error) {