show README.md in directory listings

This commit is contained in:
ed 2021-09-06 00:23:35 +02:00
parent ca16c4108d
commit a009ff53f7
6 changed files with 100 additions and 4 deletions

View file

@ -477,6 +477,10 @@ and there are *two* editors
* click the bottom-left `π` to open a javascript prompt for debugging * click the bottom-left `π` to open a javascript prompt for debugging
* files named `.prologue.html` / `.epilogue.html` will be rendered before/after directory listings unless `--no-logues`
* files named `README.md` / `readme.md` will be rendered after directory listings unless `--no-readme` (but `.epilogue.html` takes precedence)
## searching ## searching
@ -757,6 +761,24 @@ below are some tweaks roughly ordered by usefulness:
...however it adds an overhead to internal communication so it might be a net loss, see if it works 4 u ...however it adds an overhead to internal communication so it might be a net loss, see if it works 4 u
# security
some notes on hardening
on public copyparty instances with anonymous upload enabled:
* users can upload html/css/js which will evaluate for other visitors in a few ways,
* unless `--no-readme` is set: by uploading/modifying a file named `readme.md`
* if `move` access is granted AND none of `--no-logues`, `--no-dot-mv`, `--no-dot-ren` is set: by uploading some .html file and renaming it to `.epilogue.html` (uploading it directly is blocked)
## gotchas
behavior that might be unexpected
* users without read-access to a folder can still see the `.prologue.html` / `.epilogue.html` / `README.md` contents, for the purpose of showing a description on how to use the uploader for example
# dependencies # dependencies
mandatory deps: mandatory deps:
@ -887,7 +909,6 @@ in the `scripts` folder:
roughly sorted by priority roughly sorted by priority
* hls framework for Someone Else to drop code into :^) * hls framework for Someone Else to drop code into :^)
* readme.md as epilogue
## discarded ideas ## discarded ideas

View file

@ -363,6 +363,7 @@ def run_argparse(argv, formatter):
ap2.add_argument("--no-dot-mv", action="store_true", help="disallow moving dotfiles; makes it impossible to move folders containing dotfiles") ap2.add_argument("--no-dot-mv", action="store_true", help="disallow moving dotfiles; makes it impossible to move folders containing dotfiles")
ap2.add_argument("--no-dot-ren", action="store_true", help="disallow renaming dotfiles; makes it impossible to make something a dotfile") ap2.add_argument("--no-dot-ren", action="store_true", help="disallow renaming dotfiles; makes it impossible to make something a dotfile")
ap2.add_argument("--no-logues", action="store_true", help="disable rendering .prologue/.epilogue.html into directory listings") ap2.add_argument("--no-logues", action="store_true", help="disable rendering .prologue/.epilogue.html into directory listings")
ap2.add_argument("--no-readme", action="store_true", help="disable rendering readme.md into directory listings")
ap2 = ap.add_argument_group('logging options') ap2 = ap.add_argument_group('logging options')
ap2.add_argument("-q", action="store_true", help="quiet") ap2.add_argument("-q", action="store_true", help="quiet")

View file

@ -1875,6 +1875,15 @@ class HttpCli(object):
with open(fsenc(fn), "rb") as f: with open(fsenc(fn), "rb") as f:
logues[n] = f.read().decode("utf-8") logues[n] = f.read().decode("utf-8")
readme = ""
if not self.args.no_readme and not logues[1]:
for fn in ["README.md", "readme.md"]:
fn = os.path.join(abspath, fn)
if bos.path.exists(fn):
with open(fsenc(fn), "rb") as f:
readme = f.read().decode("utf-8")
break
ls_ret = { ls_ret = {
"dirs": [], "dirs": [],
"files": [], "files": [],
@ -1883,6 +1892,7 @@ class HttpCli(object):
"acct": self.uname, "acct": self.uname,
"perms": perms, "perms": perms,
"logues": logues, "logues": logues,
"readme": readme,
} }
j2a = { j2a = {
"vdir": quotep(self.vpath), "vdir": quotep(self.vpath),
@ -1901,6 +1911,7 @@ class HttpCli(object):
"have_b_u": (self.can_write and self.uparam.get("b") == "u"), "have_b_u": (self.can_write and self.uparam.get("b") == "u"),
"url_suf": url_suf, "url_suf": url_suf,
"logues": logues, "logues": logues,
"readme": readme,
"title": html_escape(self.vpath, crlf=True), "title": html_escape(self.vpath, crlf=True),
"srv_info": srv_info, "srv_info": srv_info,
} }

View file

@ -133,7 +133,8 @@
have_mv = {{ have_mv|tojson }}, have_mv = {{ have_mv|tojson }},
have_del = {{ have_del|tojson }}, have_del = {{ have_del|tojson }},
have_unpost = {{ have_unpost|tojson }}, have_unpost = {{ have_unpost|tojson }},
have_zip = {{ have_zip|tojson }}; have_zip = {{ have_zip|tojson }},
readme = {{ readme|tojson }};
</script> </script>
<script src="/.cpr/util.js?_={{ ts }}"></script> <script src="/.cpr/util.js?_={{ ts }}"></script>
<script src="/.cpr/browser.js?_={{ ts }}"></script> <script src="/.cpr/browser.js?_={{ ts }}"></script>

View file

@ -140,9 +140,10 @@ ebi('op_cfg').innerHTML = (
' <div>\n' + ' <div>\n' +
' <a id="tooltips" class="tgl btn" href="#" tt="◔ ◡ ◔"> tooltips</a>\n' + ' <a id="tooltips" class="tgl btn" href="#" tt="◔ ◡ ◔"> tooltips</a>\n' +
' <a id="lightmode" class="tgl btn" href="#">☀️ lightmode</a>\n' + ' <a id="lightmode" class="tgl btn" href="#">☀️ lightmode</a>\n' +
' <a id="dotfiles" class="tgl btn" href="#" tt="show hidden files (if server permits)">dotfiles</a>\n' +
' <a id="griden" class="tgl btn" href="#" tt="toggle icons or list-view$NHotkey: G">田 the grid</a>\n' + ' <a id="griden" class="tgl btn" href="#" tt="toggle icons or list-view$NHotkey: G">田 the grid</a>\n' +
' <a id="thumbs" class="tgl btn" href="#" tt="in icon view, toggle icons or thumbnails$NHotkey: T">🖼️ thumbs</a>\n' + ' <a id="thumbs" class="tgl btn" href="#" tt="in icon view, toggle icons or thumbnails$NHotkey: T">🖼️ thumbs</a>\n' +
' <a id="dotfiles" class="tgl btn" href="#" tt="show hidden files (if server permits)">dotfiles</a>\n' +
' <a id="ireadme" class="tgl btn" href="#" tt="show README.md in folder listings">📜 readme</a>\n' +
' </div>\n' + ' </div>\n' +
'</div>\n' + '</div>\n' +
(have_zip ? ( (have_zip ? (
@ -2999,7 +3000,8 @@ var treectl = (function () {
var treectl = { var treectl = {
"hidden": true, "hidden": true,
"ls_cb": null, "ls_cb": null,
"dir_cb": tree_scrollto "dir_cb": tree_scrollto,
"ireadme": bcfg_get('ireadme', true)
}, },
entreed = false, entreed = false,
fixedpos = false, fixedpos = false,
@ -3320,6 +3322,12 @@ var treectl = (function () {
ebi('pro').innerHTML = res.logues ? res.logues[0] || "" : ""; ebi('pro').innerHTML = res.logues ? res.logues[0] || "" : "";
ebi('epi').innerHTML = res.logues ? res.logues[1] || "" : ""; ebi('epi').innerHTML = res.logues ? res.logues[1] || "" : "";
clmod(ebi('epi'), 'mdo');
if (res.readme)
setTimeout(function () {
show_readme(res.readme);
}, 10);
document.title = '⇆🎉 ' + uricom_dec(document.location.pathname.slice(1, -1))[0]; document.title = '⇆🎉 ' + uricom_dec(document.location.pathname.slice(1, -1))[0];
filecols.set_style(); filecols.set_style();
@ -3372,6 +3380,12 @@ var treectl = (function () {
treectl.goto(get_evpath()); treectl.goto(get_evpath());
} }
function treadme(e) {
ev(e);
treectl.ireadme = !treectl.ireadme;
bcfg_set('ireadme', treectl.ireadme);
}
function dyntree(e) { function dyntree(e) {
ev(e); ev(e);
dyn = !dyn; dyn = !dyn;
@ -3393,6 +3407,7 @@ var treectl = (function () {
ebi('detree').onclick = treectl.detree; ebi('detree').onclick = treectl.detree;
ebi('visdir').onclick = tree_scrollto; ebi('visdir').onclick = tree_scrollto;
ebi('dotfiles').onclick = tdots; ebi('dotfiles').onclick = tdots;
ebi('ireadme').onclick = treadme;
ebi('dyntree').onclick = dyntree; ebi('dyntree').onclick = dyntree;
ebi('twig').onclick = scaletree; ebi('twig').onclick = scaletree;
ebi('twobytwo').onclick = scaletree; ebi('twobytwo').onclick = scaletree;
@ -3823,6 +3838,7 @@ var light;
function freshen() { function freshen() {
clmod(document.documentElement, "light", light); clmod(document.documentElement, "light", light);
clmod(document.documentElement, "dark", !light);
pbar.drawbuf(); pbar.drawbuf();
pbar.drawpos(); pbar.drawpos();
vbar.draw(); vbar.draw();
@ -4036,6 +4052,51 @@ var msel = (function () {
})(); })();
function show_readme(md, url, depth) {
if (!treectl.ireadme)
return;
var div = ebi('epi'),
errmsg = 'cannot show README.md:\n\n',
now = window.location.href.replace(/\/?[?#].*/, "");
url = url || now;
if (url != now)
return;
if (!window['marked']) {
if (depth)
return toast.warn(10, errmsg + 'failed to load marked.js')
return import_js('/.cpr/deps/marked.js', function () {
show_readme(md, url, 1);
});
}
try {
clmod(div, 'mdo', 1);
div.innerHTML = marked(md, {
headerPrefix: 'md-',
breaks: true,
gfm: true
});
var links = QSA('#epi a');
for (var a = 0, aa = links.length; a < aa; a++) {
var href = links[a].getAttribute('href');
if (!href.startsWith('#'))
continue;
links[a].setAttribute('href', '#md-' + href.slice(1));
}
}
catch (ex) {
toast.warn(10, errmsg + ex);
}
}
if (readme)
show_readme(readme);
(function () { (function () {
try { try {
var tr = ebi('files').tBodies[0].rows; var tr = ebi('files').tBodies[0].rows;

View file

@ -365,6 +365,7 @@ html.light #tt em {
overflow-wrap: break-word; overflow-wrap: break-word;
word-wrap: break-word; /*ie*/ word-wrap: break-word; /*ie*/
} }
html.light .mdo a,
.mdo a { .mdo a {
color: #fff; color: #fff;
background: #39b; background: #39b;