mirror of
https://github.com/9001/copyparty.git
synced 2025-08-18 09:22:31 -06:00
hmac uploader-ip when avoiding filename collisions
This commit is contained in:
parent
0484f97c9c
commit
0006f933a2
|
@ -583,6 +583,7 @@ def run_argparse(argv: list[str], formatter: Any, retry: bool) -> argparse.Names
|
||||||
|
|
||||||
ap2 = ap.add_argument_group('upload options')
|
ap2 = ap.add_argument_group('upload options')
|
||||||
ap2.add_argument("--dotpart", action="store_true", help="dotfile incomplete uploads, hiding them from clients unless -ed")
|
ap2.add_argument("--dotpart", action="store_true", help="dotfile incomplete uploads, hiding them from clients unless -ed")
|
||||||
|
ap2.add_argument("--plain-ip", action="store_true", help="when avoiding filename collisions by appending the uploader's ip to the filename: append the plaintext ip instead of salting and hashing the ip")
|
||||||
ap2.add_argument("--unpost", metavar="SEC", type=int, default=3600*12, help="grace period where uploads can be deleted by the uploader, even without delete permissions; 0=disabled")
|
ap2.add_argument("--unpost", metavar="SEC", type=int, default=3600*12, help="grace period where uploads can be deleted by the uploader, even without delete permissions; 0=disabled")
|
||||||
ap2.add_argument("--reg-cap", metavar="N", type=int, default=38400, help="max number of uploads to keep in memory when running without -e2d; roughly 1 MiB RAM per 600")
|
ap2.add_argument("--reg-cap", metavar="N", type=int, default=38400, help="max number of uploads to keep in memory when running without -e2d; roughly 1 MiB RAM per 600")
|
||||||
ap2.add_argument("--no-fpool", action="store_true", help="disable file-handle pooling -- instead, repeatedly close and reopen files during upload")
|
ap2.add_argument("--no-fpool", action="store_true", help="disable file-handle pooling -- instead, repeatedly close and reopen files during upload")
|
||||||
|
|
|
@ -6,12 +6,13 @@ import signal
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
|
import os
|
||||||
import queue
|
import queue
|
||||||
|
|
||||||
from .authsrv import AuthSrv
|
from .authsrv import AuthSrv
|
||||||
from .broker_util import BrokerCli, ExceptionalQueue
|
from .broker_util import BrokerCli, ExceptionalQueue
|
||||||
from .httpsrv import HttpSrv
|
from .httpsrv import HttpSrv
|
||||||
from .util import FAKE_MP
|
from .util import FAKE_MP, HMaccas
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from types import FrameType
|
from types import FrameType
|
||||||
|
@ -54,6 +55,7 @@ class MpWorker(BrokerCli):
|
||||||
self.asrv = AuthSrv(args, None, False)
|
self.asrv = AuthSrv(args, None, False)
|
||||||
|
|
||||||
# instantiate all services here (TODO: inheritance?)
|
# instantiate all services here (TODO: inheritance?)
|
||||||
|
self.iphash = HMaccas(os.path.join(self.args.E.cfg, "iphash"), 8)
|
||||||
self.httpsrv = HttpSrv(self, n)
|
self.httpsrv = HttpSrv(self, n)
|
||||||
|
|
||||||
# on winxp and some other platforms,
|
# on winxp and some other platforms,
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
from __future__ import print_function, unicode_literals
|
from __future__ import print_function, unicode_literals
|
||||||
|
|
||||||
|
import os
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from .__init__ import TYPE_CHECKING
|
from .__init__ import TYPE_CHECKING
|
||||||
from .broker_util import BrokerCli, ExceptionalQueue, try_exec
|
from .broker_util import BrokerCli, ExceptionalQueue, try_exec
|
||||||
from .httpsrv import HttpSrv
|
from .httpsrv import HttpSrv
|
||||||
|
from .util import HMaccas
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .svchub import SvcHub
|
from .svchub import SvcHub
|
||||||
|
@ -31,6 +33,7 @@ class BrokerThr(BrokerCli):
|
||||||
self.num_workers = 1
|
self.num_workers = 1
|
||||||
|
|
||||||
# instantiate all services here (TODO: inheritance?)
|
# instantiate all services here (TODO: inheritance?)
|
||||||
|
self.iphash = HMaccas(os.path.join(self.args.E.cfg, "iphash"), 8)
|
||||||
self.httpsrv = HttpSrv(self, None)
|
self.httpsrv = HttpSrv(self, None)
|
||||||
self.reload = self.noop
|
self.reload = self.noop
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ from queue import Queue
|
||||||
|
|
||||||
from .__init__ import TYPE_CHECKING
|
from .__init__ import TYPE_CHECKING
|
||||||
from .authsrv import AuthSrv
|
from .authsrv import AuthSrv
|
||||||
from .util import Pebkac
|
from .util import Pebkac, HMaccas
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from typing import Any, Optional, Union
|
from typing import Any, Optional, Union
|
||||||
|
@ -46,6 +46,7 @@ class BrokerCli(object):
|
||||||
self.args: argparse.Namespace = None
|
self.args: argparse.Namespace = None
|
||||||
self.asrv: AuthSrv = None
|
self.asrv: AuthSrv = None
|
||||||
self.httpsrv: "HttpSrv" = None
|
self.httpsrv: "HttpSrv" = None
|
||||||
|
self.iphash: HMaccas = None
|
||||||
|
|
||||||
def ask(self, dest: str, *args: Any) -> ExceptionalQueue:
|
def ask(self, dest: str, *args: Any) -> ExceptionalQueue:
|
||||||
return ExceptionalQueue(1)
|
return ExceptionalQueue(1)
|
||||||
|
|
|
@ -123,7 +123,6 @@ class HttpCli(object):
|
||||||
self.ua = " "
|
self.ua = " "
|
||||||
self.is_rclone = False
|
self.is_rclone = False
|
||||||
self.is_ancient = False
|
self.is_ancient = False
|
||||||
self.dip = " "
|
|
||||||
self.ouparam: dict[str, str] = {}
|
self.ouparam: dict[str, str] = {}
|
||||||
self.uparam: dict[str, str] = {}
|
self.uparam: dict[str, str] = {}
|
||||||
self.cookies: dict[str, str] = {}
|
self.cookies: dict[str, str] = {}
|
||||||
|
@ -264,8 +263,6 @@ class HttpCli(object):
|
||||||
|
|
||||||
self.log_src = self.conn.set_rproxy(self.ip)
|
self.log_src = self.conn.set_rproxy(self.ip)
|
||||||
|
|
||||||
self.dip = self.ip.replace(":", ".")
|
|
||||||
|
|
||||||
if self.args.ihead:
|
if self.args.ihead:
|
||||||
keys = self.args.ihead
|
keys = self.args.ihead
|
||||||
if "*" in keys:
|
if "*" in keys:
|
||||||
|
@ -403,6 +400,12 @@ class HttpCli(object):
|
||||||
except Pebkac:
|
except Pebkac:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def dip(self) -> str:
|
||||||
|
if self.args.plain_ip:
|
||||||
|
return self.ip.replace(":", ".")
|
||||||
|
else:
|
||||||
|
return self.conn.iphash.s(self.ip)
|
||||||
|
|
||||||
def permit_caching(self) -> None:
|
def permit_caching(self) -> None:
|
||||||
cache = self.uparam.get("cache")
|
cache = self.uparam.get("cache")
|
||||||
if cache is None:
|
if cache is None:
|
||||||
|
@ -778,7 +781,7 @@ class HttpCli(object):
|
||||||
else:
|
else:
|
||||||
self.log("fallthrough? thats a bug", 1)
|
self.log("fallthrough? thats a bug", 1)
|
||||||
|
|
||||||
suffix = "-{:.6f}-{}".format(time.time(), self.dip)
|
suffix = "-{:.6f}-{}".format(time.time(), self.dip())
|
||||||
if not fn:
|
if not fn:
|
||||||
suffix += ".bin"
|
suffix += ".bin"
|
||||||
fn = "put" + suffix
|
fn = "put" + suffix
|
||||||
|
@ -1262,6 +1265,7 @@ class HttpCli(object):
|
||||||
files: list[tuple[int, str, str, str, str, str]] = []
|
files: list[tuple[int, str, str, str, str, str]] = []
|
||||||
# sz, sha_hex, sha_b64, p_file, fname, abspath
|
# sz, sha_hex, sha_b64, p_file, fname, abspath
|
||||||
errmsg = ""
|
errmsg = ""
|
||||||
|
dip = self.dip()
|
||||||
t0 = time.time()
|
t0 = time.time()
|
||||||
try:
|
try:
|
||||||
assert self.parser.gen
|
assert self.parser.gen
|
||||||
|
@ -1278,7 +1282,7 @@ class HttpCli(object):
|
||||||
if not bos.path.isdir(fdir):
|
if not bos.path.isdir(fdir):
|
||||||
raise Pebkac(404, "that folder does not exist")
|
raise Pebkac(404, "that folder does not exist")
|
||||||
|
|
||||||
suffix = "-{:.6f}-{}".format(time.time(), self.dip)
|
suffix = "-{:.6f}-{}".format(time.time(), dip)
|
||||||
open_args = {"fdir": fdir, "suffix": suffix}
|
open_args = {"fdir": fdir, "suffix": suffix}
|
||||||
|
|
||||||
# reserve destination filename
|
# reserve destination filename
|
||||||
|
|
|
@ -23,7 +23,7 @@ from .mtag import HAVE_FFMPEG
|
||||||
from .th_cli import ThumbCli
|
from .th_cli import ThumbCli
|
||||||
from .th_srv import HAVE_PIL, HAVE_VIPS
|
from .th_srv import HAVE_PIL, HAVE_VIPS
|
||||||
from .u2idx import U2idx
|
from .u2idx import U2idx
|
||||||
from .util import shut_socket
|
from .util import HMaccas, shut_socket
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from typing import Optional, Pattern, Union
|
from typing import Optional, Pattern, Union
|
||||||
|
@ -54,6 +54,7 @@ class HttpConn(object):
|
||||||
self.asrv: AuthSrv = hsrv.asrv # mypy404
|
self.asrv: AuthSrv = hsrv.asrv # mypy404
|
||||||
self.cert_path = hsrv.cert_path
|
self.cert_path = hsrv.cert_path
|
||||||
self.u2fh: Util.FHC = hsrv.u2fh # mypy404
|
self.u2fh: Util.FHC = hsrv.u2fh # mypy404
|
||||||
|
self.iphash: HMaccas = hsrv.broker.iphash
|
||||||
|
|
||||||
enth = (HAVE_PIL or HAVE_VIPS or HAVE_FFMPEG) and not self.args.no_thumb
|
enth = (HAVE_PIL or HAVE_VIPS or HAVE_FFMPEG) and not self.args.no_thumb
|
||||||
self.thumbcli: Optional[ThumbCli] = ThumbCli(hsrv) if enth else None # mypy404
|
self.thumbcli: Optional[ThumbCli] = ThumbCli(hsrv) if enth else None # mypy404
|
||||||
|
|
|
@ -32,6 +32,7 @@ from .th_srv import HAVE_PIL, HAVE_VIPS, HAVE_WEBP, ThumbSrv
|
||||||
from .up2k import Up2k
|
from .up2k import Up2k
|
||||||
from .util import (
|
from .util import (
|
||||||
VERSIONS,
|
VERSIONS,
|
||||||
|
HMaccas,
|
||||||
alltrace,
|
alltrace,
|
||||||
ansi_re,
|
ansi_re,
|
||||||
min_ex,
|
min_ex,
|
||||||
|
@ -72,6 +73,8 @@ class SvcHub(object):
|
||||||
self.next_day = 0
|
self.next_day = 0
|
||||||
self.tstack = 0.0
|
self.tstack = 0.0
|
||||||
|
|
||||||
|
self.iphash = HMaccas(os.path.join(self.E.cfg, "iphash"), 8)
|
||||||
|
|
||||||
if args.sss or args.s >= 3:
|
if args.sss or args.s >= 3:
|
||||||
args.ss = True
|
args.ss = True
|
||||||
args.lo = args.lo or "cpp-%Y-%m%d-%H%M%S.txt.xz"
|
args.lo = args.lo or "cpp-%Y-%m%d-%H%M%S.txt.xz"
|
||||||
|
|
|
@ -2101,9 +2101,12 @@ class Up2k(object):
|
||||||
if self.args.nw:
|
if self.args.nw:
|
||||||
return fname
|
return fname
|
||||||
|
|
||||||
# TODO broker which avoid this race and
|
if self.args.plain_ip:
|
||||||
# provides a new filename if taken (same as bup)
|
dip = ip.replace(":", ".")
|
||||||
suffix = "-{:.6f}-{}".format(ts, ip.replace(":", "."))
|
else:
|
||||||
|
dip = self.hub.iphash.s(ip)
|
||||||
|
|
||||||
|
suffix = "-{:.6f}-{}".format(ts, dip)
|
||||||
with ren_open(fname, "wb", fdir=fdir, suffix=suffix) as zfw:
|
with ren_open(fname, "wb", fdir=fdir, suffix=suffix) as zfw:
|
||||||
return zfw["orz"][1]
|
return zfw["orz"][1]
|
||||||
|
|
||||||
|
@ -2842,7 +2845,11 @@ class Up2k(object):
|
||||||
del self.registry[job["ptop"]][job["wark"]]
|
del self.registry[job["ptop"]][job["wark"]]
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if self.args.plain_ip:
|
||||||
dip = job["addr"].replace(":", ".")
|
dip = job["addr"].replace(":", ".")
|
||||||
|
else:
|
||||||
|
dip = self.hub.iphash.s(job["addr"])
|
||||||
|
|
||||||
suffix = "-{:.6f}-{}".format(job["t0"], dip)
|
suffix = "-{:.6f}-{}".format(job["t0"], dip)
|
||||||
with ren_open(tnam, "wb", fdir=pdir, suffix=suffix) as zfw:
|
with ren_open(tnam, "wb", fdir=pdir, suffix=suffix) as zfw:
|
||||||
f, job["tnam"] = zfw["orz"]
|
f, job["tnam"] = zfw["orz"]
|
||||||
|
|
|
@ -4,6 +4,7 @@ from __future__ import print_function, unicode_literals
|
||||||
import base64
|
import base64
|
||||||
import contextlib
|
import contextlib
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import hmac
|
||||||
import math
|
import math
|
||||||
import mimetypes
|
import mimetypes
|
||||||
import os
|
import os
|
||||||
|
@ -597,6 +598,33 @@ class MTHash(object):
|
||||||
return nch, udig, ofs0, chunk_sz
|
return nch, udig, ofs0, chunk_sz
|
||||||
|
|
||||||
|
|
||||||
|
class HMaccas(object):
|
||||||
|
def __init__(self, keypath: str, retlen: int) -> None:
|
||||||
|
self.retlen = retlen
|
||||||
|
self.cache: dict[bytes, str] = {}
|
||||||
|
try:
|
||||||
|
with open(keypath, "rb") as f:
|
||||||
|
self.key = f.read()
|
||||||
|
if len(self.key) != 64:
|
||||||
|
raise Exception()
|
||||||
|
except:
|
||||||
|
self.key = os.urandom(64)
|
||||||
|
with open(keypath, "wb") as f:
|
||||||
|
f.write(self.key)
|
||||||
|
|
||||||
|
def b(self, msg: bytes) -> str:
|
||||||
|
try:
|
||||||
|
return self.cache[msg]
|
||||||
|
except:
|
||||||
|
zb = hmac.new(self.key, msg, hashlib.sha512).digest()
|
||||||
|
zs = base64.urlsafe_b64encode(zb)[: self.retlen].decode("utf-8")
|
||||||
|
self.cache[msg] = zs
|
||||||
|
return zs
|
||||||
|
|
||||||
|
def s(self, msg: str) -> str:
|
||||||
|
return self.b(msg.encode("utf-8", "replace"))
|
||||||
|
|
||||||
|
|
||||||
def uprint(msg: str) -> None:
|
def uprint(msg: str) -> None:
|
||||||
try:
|
try:
|
||||||
print(msg, end="")
|
print(msg, end="")
|
||||||
|
|
Loading…
Reference in a new issue