|
2 | 2 |
|
3 | 3 | from pathlib import PurePath
|
4 | 4 |
|
| 5 | +from jupyter_core.paths import jupyter_path |
| 6 | + |
| 7 | +import tornado |
| 8 | + |
5 | 9 |
|
6 | 10 | class SnippetsLoader:
|
7 |
| - def __init__(self, snippet_dir): |
8 |
| - self.snippet_dir = snippet_dir |
| 11 | + def __init__(self): |
| 12 | + self.snippet_paths = jupyter_path("code_snippets") |
9 | 13 |
|
10 | 14 | def collect_snippets(self):
|
11 |
| - # TODO: handle multiple directories |
12 |
| - root = self.snippet_dir |
13 | 15 | snippets = []
|
14 |
| - for dirpath, dirnames, filenames in os.walk(root): |
15 |
| - for f in filenames: |
16 |
| - fullpath = PurePath(dirpath).relative_to(root).joinpath(f) |
17 |
| - snippets.append(fullpath.parts) |
| 16 | + for root_path in self.snippet_paths: |
| 17 | + for dirpath, dirnames, filenames in os.walk(root_path): |
| 18 | + for f in filenames: |
| 19 | + fullpath = PurePath(dirpath).relative_to(root_path).joinpath(f) |
| 20 | + |
| 21 | + if fullpath.parts not in snippets: |
| 22 | + snippets.append(fullpath.parts) |
| 23 | + |
18 | 24 | snippets.sort()
|
19 | 25 | return snippets
|
20 | 26 |
|
21 | 27 | def get_snippet_content(self, snippet):
|
22 | 28 | try:
|
23 |
| - path = os.path.join(self.snippet_dir, *snippet) |
24 |
| - with open(path) as f: |
25 |
| - content = f.read() |
26 |
| - except: |
27 |
| - content = '' |
| 29 | + for root_path in self.snippet_paths: |
| 30 | + path = os.path.join(root_path, *snippet) |
| 31 | + |
| 32 | + # Prevent access to the entire file system when the path contains '..' |
| 33 | + accessible = os.path.realpath(path).startswith(root_path) |
28 | 34 |
|
29 |
| - return content |
| 35 | + if accessible and os.path.isfile(path): |
| 36 | + with open(path) as f: |
| 37 | + return f.read() |
| 38 | + except: |
| 39 | + raise tornado.web.HTTPError(status_code=500) |
30 | 40 |
|
| 41 | + raise tornado.web.HTTPError(status_code=404) |
0 commit comments