mirror of
https://github.com/9001/copyparty.git
synced 2025-08-17 00:52:16 -06:00
share folders as qr-codes
This commit is contained in:
parent
21be82ef8b
commit
e45420646f
|
@ -37,6 +37,7 @@ from .__version__ import S_VERSION
|
|||
from .authsrv import VFS # typechk
|
||||
from .bos import bos
|
||||
from .star import StreamTar
|
||||
from .stolen.qrcodegen import QrCode, qr2svg
|
||||
from .sutil import StreamArc, gfilter
|
||||
from .szip import StreamZip
|
||||
from .up2k import up2k_chunksize
|
||||
|
@ -495,6 +496,9 @@ class HttpCli(object):
|
|||
self.vpath + "/" if self.trailing_slash and self.vpath else self.vpath
|
||||
)
|
||||
|
||||
if "qr" in uparam:
|
||||
return self.tx_qr()
|
||||
|
||||
if relchk(self.vpath) and (self.vpath != "*" or self.mode != "OPTIONS"):
|
||||
self.log("invalid relpath [{}]".format(self.vpath))
|
||||
self.cbonk(self.conn.hsrv.gmal, self.req, "bad_vp", "invalid relpaths")
|
||||
|
@ -3934,6 +3938,33 @@ class HttpCli(object):
|
|||
self.reply(ico, mime=mime, headers={"Last-Modified": lm})
|
||||
return True
|
||||
|
||||
def tx_qr(self):
|
||||
url = "%s://%s%s%s" % (
|
||||
"https" if self.is_https else "http",
|
||||
self.host,
|
||||
self.args.SRS,
|
||||
self.vpaths,
|
||||
)
|
||||
uhash = ""
|
||||
uparams = []
|
||||
if self.ouparam:
|
||||
for k, v in self.ouparam.items():
|
||||
if k == "qr":
|
||||
continue
|
||||
if k == "uhash":
|
||||
uhash = v
|
||||
continue
|
||||
uparams.append(k if v is "" else "%s=%s" % (k, v))
|
||||
if uparams:
|
||||
url += "?" + "&".join(uparams)
|
||||
if uhash:
|
||||
url += "#" + uhash
|
||||
|
||||
self.log("qrcode(%r)" % (url,))
|
||||
ret = qr2svg(QrCode.encode_binary(url.encode("utf-8")), 2)
|
||||
self.reply(ret.encode("utf-8"), mime="image/svg+xml")
|
||||
return True
|
||||
|
||||
def tx_md(self, vn: VFS, fs_path: str) -> bool:
|
||||
logmsg = " %s @%s " % (self.req, self.uname)
|
||||
|
||||
|
@ -4505,9 +4536,6 @@ class HttpCli(object):
|
|||
if self.uname != self.args.shr_adm:
|
||||
rows = [x for x in rows if x[5] == self.uname]
|
||||
|
||||
for x in rows:
|
||||
x[1] = "yes" if x[1] else ""
|
||||
|
||||
html = self.j2s(
|
||||
"shares", this=self, shr=self.args.shr, rows=rows, now=int(time.time())
|
||||
)
|
||||
|
@ -4585,7 +4613,7 @@ class HttpCli(object):
|
|||
else:
|
||||
for zs in vps:
|
||||
if zs.endswith("/"):
|
||||
t = "you cannot select more than one folder, or mix flies and folders in one selection"
|
||||
t = "you cannot select more than one folder, or mix files and folders in one selection"
|
||||
raise Pebkac(400, t)
|
||||
vp = vps[0].rsplit("/", 1)[0]
|
||||
for zs in vps:
|
||||
|
|
|
@ -594,3 +594,20 @@ def _get_bit(x: int, i: int) -> bool:
|
|||
|
||||
class DataTooLongError(ValueError):
|
||||
pass
|
||||
|
||||
|
||||
def qr2svg(qr: QrCode, border: int) -> str:
|
||||
parts: list[str] = []
|
||||
for y in range(qr.size):
|
||||
sy = border + y
|
||||
for x in range(qr.size):
|
||||
if qr.modules[y][x]:
|
||||
parts.append("M%d,%dh1v1h-1z" % (border + x, sy))
|
||||
t = """\
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 {0} {0}" stroke="none">
|
||||
<rect width="100%" height="100%" fill="#F7F7F7"/>
|
||||
<path d="{1}" fill="#111111"/>
|
||||
</svg>
|
||||
"""
|
||||
return t.format(qr.size + border * 2, " ".join(parts))
|
||||
|
|
|
@ -345,7 +345,7 @@ var Ls = {
|
|||
"fs_tsrc": "the file or folder to share",
|
||||
"fs_ppwd": "optional password",
|
||||
"fs_w8": "creating share...",
|
||||
"fs_ok": "<h6>share-URL created</h6>\npress <code>Enter/OK</code> to Clipboard\npress <code>ESC/Cancel</code> to Close\n\n",
|
||||
"fs_ok": "press <code>Enter/OK</code> to Clipboard\npress <code>ESC/Cancel</code> to Close",
|
||||
|
||||
"frt_dec": "may fix some cases of broken filenames\">url-decode",
|
||||
"frt_rst": "reset modified filenames back to the original ones\">↺ reset",
|
||||
|
@ -913,7 +913,7 @@ var Ls = {
|
|||
"fs_tsrc": "fil/mappe som skal deles",
|
||||
"fs_ppwd": "frivillig passord",
|
||||
"fs_w8": "oppretter deling...",
|
||||
"fs_ok": "<h6>URL opprettet</h6>\ntrykk <code>Enter/OK</code> for å kopiere linken (for CTRL-V)\ntrykk <code>ESC/Avbryt</code> for å bare bekrefte\n\n",
|
||||
"fs_ok": "trykk <code>Enter/OK</code> for å kopiere linken (for CTRL-V)\ntrykk <code>ESC/Avbryt</code> for å bare bekrefte",
|
||||
|
||||
"frt_dec": "kan korrigere visse ødelagte filnavn\">url-decode",
|
||||
"frt_rst": "nullstiller endringer (tilbake til de originale filnavnene)\">↺ reset",
|
||||
|
@ -1481,7 +1481,7 @@ var Ls = {
|
|||
"fs_tsrc": "共享的文件或文件夹",
|
||||
"fs_ppwd": "密码可选",
|
||||
"fs_w8": "正在创建文件共享...",
|
||||
"fs_ok": "<h6>分享链接已创建</h6>\n按 <code>Enter/OK</code> 复制到剪贴板\n按 <code>ESC/Cancel</code> 关闭\n\n",
|
||||
"fs_ok": "按 <code>Enter/OK</code> 复制到剪贴板\n按 <code>ESC/Cancel</code> 关闭",
|
||||
|
||||
"frt_dec": "可能修复一些损坏的文件名\">url-decode",
|
||||
"frt_rst": "将修改后的文件名重置为原始文件名\">↺ 重置",
|
||||
|
@ -1788,7 +1788,7 @@ ebi('widget').innerHTML = (
|
|||
' <canvas id="barbuf"></canvas>' +
|
||||
'</div>' +
|
||||
'<div id="np_inf">' +
|
||||
' <img id="np_img"></span>' +
|
||||
' <img id="np_img" />' +
|
||||
' <span id="np_url"></span>' +
|
||||
' <span id="np_circle"></span>' +
|
||||
' <span id="np_album"></span>' +
|
||||
|
@ -4596,11 +4596,12 @@ var fileman = (function () {
|
|||
return;
|
||||
}
|
||||
surl = surl.slice(15);
|
||||
modal.confirm(L.fs_ok + esc(surl), function() {
|
||||
var txt = esc(surl) + '<img class="b64" src="' + surl + '?qr" />';
|
||||
modal.confirm(txt + L.fs_ok, function() {
|
||||
cliptxt(surl, function () {
|
||||
toast.ok(2, L.clipped);
|
||||
});
|
||||
});
|
||||
}, null);
|
||||
}
|
||||
|
||||
sh_apply.onclick = function () {
|
||||
|
|
|
@ -27,7 +27,7 @@ a {
|
|||
padding: .2em .6em;
|
||||
margin: 0 .3em;
|
||||
}
|
||||
td a {
|
||||
#wrap td a {
|
||||
margin: 0;
|
||||
}
|
||||
#w {
|
||||
|
@ -53,12 +53,13 @@ th {
|
|||
position: sticky;
|
||||
background: #f7f7f7;
|
||||
}
|
||||
td, th {
|
||||
#wrap td,
|
||||
#wrap th {
|
||||
padding: .3em .6em;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
}
|
||||
td+td+td+td+td+td+td+td {
|
||||
#wrap td+td+td+td+td+td+td+td {
|
||||
font-family: var(--font-mono), monospace, monospace;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
<span>min/hrs = time left</span>
|
||||
|
||||
<table id="tab"><thead><tr>
|
||||
<th>delete</th>
|
||||
<th>sharekey</th>
|
||||
<th>delete</th>
|
||||
<th>pw</th>
|
||||
<th>source</th>
|
||||
<th>axs</th>
|
||||
|
@ -37,10 +37,13 @@
|
|||
</tr></thead><tbody>
|
||||
{% for k, pw, vp, pr, st, un, t0, t1 in rows %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ r }}{{ shr }}{{ k }}?qr">qr</a>
|
||||
<a href="{{ r }}{{ shr }}{{ k }}">{{ k }}</a>
|
||||
</td>
|
||||
<td><a href="#" k="{{ k }}">delete</a></td>
|
||||
<td><a href="{{ r }}{{ shr }}{{ k }}">{{ k }}</a></td>
|
||||
<td>{{ pw }}</td>
|
||||
<td><a href="{{ r }}/{{ vp|e }}">{{ vp|e }}</a></td>
|
||||
<td>{{ "yes" if pw else "--" }}</td>
|
||||
<td><a href="{{ r }}/{{ vp|e }}">/{{ vp|e }}</a></td>
|
||||
<td>{{ pr }}</td>
|
||||
<td>{{ st }}</td>
|
||||
<td>{{ un|e }}</td>
|
||||
|
|
|
@ -12,7 +12,7 @@ function rm() {
|
|||
}
|
||||
|
||||
function bump() {
|
||||
var k = this.closest('tr').getElementsByTagName('a')[0].getAttribute('k'),
|
||||
var k = this.closest('tr').getElementsByTagName('a')[2].getAttribute('k'),
|
||||
u = SR + shr + uricom_enc(k) + '?eshare=' + this.value,
|
||||
xhr = new XHR();
|
||||
|
||||
|
@ -28,14 +28,36 @@ function cb() {
|
|||
document.location = '?shares';
|
||||
}
|
||||
|
||||
function qr(e) {
|
||||
ev(e);
|
||||
var href = this.href,
|
||||
pw = this.closest('tr').cells[2].textContent;
|
||||
|
||||
if (pw.indexOf('yes') < 0)
|
||||
return showqr(href);
|
||||
|
||||
modal.prompt("if you want to bypass the password protection by\nembedding the password into the qr-code, then\ntype the password now, otherwise leave this empty", "", function (v) {
|
||||
if (v)
|
||||
href += "&pw=" + v;
|
||||
showqr(href);
|
||||
});
|
||||
}
|
||||
|
||||
function showqr(href) {
|
||||
var vhref = href.replace('?qr&', '?').replace('?qr', '');
|
||||
modal.alert(esc(vhref) + '<img class="b64" src="' + href + '" />');
|
||||
}
|
||||
|
||||
(function() {
|
||||
var tab = ebi('tab').tBodies[0],
|
||||
tr = Array.prototype.slice.call(tab.rows, 0);
|
||||
|
||||
var buf = [];
|
||||
for (var a = 0; a < tr.length; a++)
|
||||
for (var a = 0; a < tr.length; a++) {
|
||||
tr[a].cells[0].getElementsByTagName('a')[0].onclick = qr;
|
||||
for (var b = 7; b < 9; b++)
|
||||
buf.push(parseInt(tr[a].cells[b].innerHTML));
|
||||
}
|
||||
|
||||
var ibuf = 0;
|
||||
for (var a = 0; a < tr.length; a++)
|
||||
|
|
|
@ -293,6 +293,12 @@ html.y #tth {
|
|||
#modalc a {
|
||||
color: #07b;
|
||||
}
|
||||
#modalc .b64 {
|
||||
display: block;
|
||||
margin: .1em auto;
|
||||
width: 60%;
|
||||
height: 60%;
|
||||
}
|
||||
#modalb {
|
||||
position: sticky;
|
||||
text-align: right;
|
||||
|
|
|
@ -426,7 +426,7 @@ var tl_browser = {
|
|||
"fs_tsrc": "the file or folder to share",
|
||||
"fs_ppwd": "optional password",
|
||||
"fs_w8": "creating share...",
|
||||
"fs_ok": "<h6>share-URL created</h6>\npress <code>Enter/OK</code> to Clipboard\npress <code>ESC/Cancel</code> to Close\n\n",
|
||||
"fs_ok": "press <code>Enter/OK</code> to Clipboard\npress <code>ESC/Cancel</code> to Close",
|
||||
|
||||
"frt_dec": "may fix some cases of broken filenames\">url-decode",
|
||||
"frt_rst": "reset modified filenames back to the original ones\">↺ reset",
|
||||
|
|
Loading…
Reference in a new issue