| 566 | |
| 567 | # ------------------------[ mirror <path> ]--------------------------- |
| 568 | def mirror(self, name, size): |
| 569 | target, vol = self.basename(self.target), self.get_vol() |
| 570 | root = os.path.abspath(os.path.join("mirror", target, vol)) |
| 571 | lpath = os.path.join(root, name) |
| 572 | """ |
| 573 | ┌───────────────────────────────────────────────────────────┐ |
| 574 | │ mitigating path traversal │ |
| 575 | ├───────────────────────────────────────────────────────────┤ |
| 576 | │ creating a mirror can be a potential security risk if the │ |
| 577 | │ path contains traversal characters, environment variables │ |
| 578 | │ or other things we have not thought about; while the user │ |
| 579 | │ is in total control of the path (via 'cd' and 'traversal' │ |
| 580 | │ commands), she might accidentally overwrite her files... │ |
| 581 | │ │ |
| 582 | │ our strategy is to first replace trivial path traversal │ |
| 583 | │ strings (while still being able to download the files) │ |
| 584 | │ and simply give up on more sophisticated ones for now. │ |
| 585 | └───────────────────────────────────────────────────────────┘ |
| 586 | """ |
| 587 | # replace path traversal (poor man's version) |
| 588 | lpath = re.sub(r"(\.)+" + c.SEP, "", lpath) |
| 589 | # abort if we are still out of the mirror root |
| 590 | if not os.path.realpath(lpath).startswith(root): |
| 591 | output().errmsg( |
| 592 | "Not saving data out of allowed path", |
| 593 | "I'm sorry Dave, I'm afraid I can't do that.", |
| 594 | ) |
| 595 | elif size: # download current file |
| 596 | output().raw(self.vol + name + " -> " + lpath) |
| 597 | self.makedirs(os.path.dirname(lpath)) |
| 598 | self.do_get(self.vol + name, lpath, False) |
| 599 | else: # create current directory |
| 600 | self.chitchat("Traversing " + name) |
| 601 | self.makedirs(lpath) |
| 602 | |
| 603 | # recursive directory creation |
| 604 | def makedirs(self, path): |