template_loader.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. package pongo2
  2. import (
  3. "bytes"
  4. "io"
  5. "io/ioutil"
  6. "log"
  7. "os"
  8. "path/filepath"
  9. "github.com/juju/errors"
  10. )
  11. // LocalFilesystemLoader represents a local filesystem loader with basic
  12. // BaseDirectory capabilities. The access to the local filesystem is unrestricted.
  13. type LocalFilesystemLoader struct {
  14. baseDir string
  15. }
  16. // MustNewLocalFileSystemLoader creates a new LocalFilesystemLoader instance
  17. // and panics if there's any error during instantiation. The parameters
  18. // are the same like NewLocalFileSystemLoader.
  19. func MustNewLocalFileSystemLoader(baseDir string) *LocalFilesystemLoader {
  20. fs, err := NewLocalFileSystemLoader(baseDir)
  21. if err != nil {
  22. log.Panic(err)
  23. }
  24. return fs
  25. }
  26. // NewLocalFileSystemLoader creates a new LocalFilesystemLoader and allows
  27. // templatesto be loaded from disk (unrestricted). If any base directory
  28. // is given (or being set using SetBaseDir), this base directory is being used
  29. // for path calculation in template inclusions/imports. Otherwise the path
  30. // is calculated based relatively to the including template's path.
  31. func NewLocalFileSystemLoader(baseDir string) (*LocalFilesystemLoader, error) {
  32. fs := &LocalFilesystemLoader{}
  33. if baseDir != "" {
  34. if err := fs.SetBaseDir(baseDir); err != nil {
  35. return nil, err
  36. }
  37. }
  38. return fs, nil
  39. }
  40. // SetBaseDir sets the template's base directory. This directory will
  41. // be used for any relative path in filters, tags and From*-functions to determine
  42. // your template. See the comment for NewLocalFileSystemLoader as well.
  43. func (fs *LocalFilesystemLoader) SetBaseDir(path string) error {
  44. // Make the path absolute
  45. if !filepath.IsAbs(path) {
  46. abs, err := filepath.Abs(path)
  47. if err != nil {
  48. return err
  49. }
  50. path = abs
  51. }
  52. // Check for existence
  53. fi, err := os.Stat(path)
  54. if err != nil {
  55. return err
  56. }
  57. if !fi.IsDir() {
  58. return errors.Errorf("The given path '%s' is not a directory.", path)
  59. }
  60. fs.baseDir = path
  61. return nil
  62. }
  63. // Get reads the path's content from your local filesystem.
  64. func (fs *LocalFilesystemLoader) Get(path string) (io.Reader, error) {
  65. buf, err := ioutil.ReadFile(path)
  66. if err != nil {
  67. return nil, err
  68. }
  69. return bytes.NewReader(buf), nil
  70. }
  71. // Abs resolves a filename relative to the base directory. Absolute paths are allowed.
  72. // When there's no base dir set, the absolute path to the filename
  73. // will be calculated based on either the provided base directory (which
  74. // might be a path of a template which includes another template) or
  75. // the current working directory.
  76. func (fs *LocalFilesystemLoader) Abs(base, name string) string {
  77. if filepath.IsAbs(name) {
  78. return name
  79. }
  80. // Our own base dir has always priority; if there's none
  81. // we use the path provided in base.
  82. var err error
  83. if fs.baseDir == "" {
  84. if base == "" {
  85. base, err = os.Getwd()
  86. if err != nil {
  87. panic(err)
  88. }
  89. return filepath.Join(base, name)
  90. }
  91. return filepath.Join(filepath.Dir(base), name)
  92. }
  93. return filepath.Join(fs.baseDir, name)
  94. }
  95. // SandboxedFilesystemLoader is still WIP.
  96. type SandboxedFilesystemLoader struct {
  97. *LocalFilesystemLoader
  98. }
  99. // NewSandboxedFilesystemLoader creates a new sandboxed local file system instance.
  100. func NewSandboxedFilesystemLoader(baseDir string) (*SandboxedFilesystemLoader, error) {
  101. fs, err := NewLocalFileSystemLoader(baseDir)
  102. if err != nil {
  103. return nil, err
  104. }
  105. return &SandboxedFilesystemLoader{
  106. LocalFilesystemLoader: fs,
  107. }, nil
  108. }
  109. // Move sandbox to a virtual fs
  110. /*
  111. if len(set.SandboxDirectories) > 0 {
  112. defer func() {
  113. // Remove any ".." or other crap
  114. resolvedPath = filepath.Clean(resolvedPath)
  115. // Make the path absolute
  116. absPath, err := filepath.Abs(resolvedPath)
  117. if err != nil {
  118. panic(err)
  119. }
  120. resolvedPath = absPath
  121. // Check against the sandbox directories (once one pattern matches, we're done and can allow it)
  122. for _, pattern := range set.SandboxDirectories {
  123. matched, err := filepath.Match(pattern, resolvedPath)
  124. if err != nil {
  125. panic("Wrong sandbox directory match pattern (see http://golang.org/pkg/path/filepath/#Match).")
  126. }
  127. if matched {
  128. // OK!
  129. return
  130. }
  131. }
  132. // No pattern matched, we have to log+deny the request
  133. set.logf("Access attempt outside of the sandbox directories (blocked): '%s'", resolvedPath)
  134. resolvedPath = ""
  135. }()
  136. }
  137. */