Browse Source

serve home icon from proxy and remove unused bottle app

Pi 1 week ago
parent
commit
7262062a1c
57 changed files with 3 additions and 1826 deletions
  1. 1 0
      docker-compose.yml
  2. 2 0
      nginx.conf
  3. 0 7
      rest/Dockerfile
  4. 0 18
      rest/__init__.py
  5. 0 14
      rest/bar.py
  6. 0 15
      rest/cherrypy.py
  7. 0 1
      rest/dev-requirements.txt
  8. 0 181
      rest/hash_util.py
  9. 0 166
      rest/pyapi.py
  10. 0 36
      rest/qr.py
  11. 0 7
      rest/requirements.txt
  12. BIN
      rest/static/clip/144.png
  13. BIN
      rest/static/clip/192.png
  14. BIN
      rest/static/clip/48.png
  15. BIN
      rest/static/clip/512.png
  16. BIN
      rest/static/clip/72.png
  17. BIN
      rest/static/clip/96.png
  18. 0 9
      rest/static/clip/clip-favicon.svg
  19. 0 93
      rest/static/clip/clip-favicon_square.svg
  20. 0 61
      rest/static/clip/manifest.json
  21. 0 1
      rest/static/clip/qr.svg
  22. 0 1
      rest/static/code/qr.svg
  23. BIN
      rest/static/ftark-open.png
  24. 0 138
      rest/static/ftark-open.svg
  25. BIN
      rest/static/goto/144.png
  26. BIN
      rest/static/goto/192.png
  27. BIN
      rest/static/goto/48.png
  28. BIN
      rest/static/goto/512.png
  29. BIN
      rest/static/goto/72.png
  30. BIN
      rest/static/goto/96.png
  31. 0 69
      rest/static/goto/chain-link-3-2.svg
  32. 0 49
      rest/static/goto/chain-link-cut-away.svg
  33. 0 50
      rest/static/goto/chain-link.svg
  34. 0 62
      rest/static/goto/chain-link2-3-2.svg
  35. 0 51
      rest/static/goto/chain-link2-cut-away.svg
  36. 0 51
      rest/static/goto/chain-link2.svg
  37. 0 76
      rest/static/goto/chain-link2fr-3-2.svg
  38. 0 75
      rest/static/goto/chain-link2r-3-2.svg
  39. 0 61
      rest/static/goto/manifest.json
  40. 0 1
      rest/static/goto/qr.svg
  41. BIN
      rest/static/shandanone-small.png
  42. 0 68
      rest/static/shandanone-small.svg
  43. 0 78
      rest/static/shandanone2.svg
  44. BIN
      rest/static/upload/144.png
  45. BIN
      rest/static/upload/192.png
  46. BIN
      rest/static/upload/48.png
  47. BIN
      rest/static/upload/512.png
  48. BIN
      rest/static/upload/72.png
  49. BIN
      rest/static/upload/96.png
  50. 0 61
      rest/static/upload/manifest.json
  51. 0 1
      rest/static/upload/qr.svg
  52. 0 46
      rest/static/upload/upload-favicon.svg
  53. 0 63
      rest/static/upload/upload-favicon_maskable.svg
  54. 0 65
      rest/static/upload/upload-favicon_square.svg
  55. 0 5
      rest/tool_color.py
  56. 0 146
      rest/validate.py
  57. 0 0
      static/shandanone2.png

+ 1 - 0
docker-compose.yml

@@ -49,6 +49,7 @@ services:
     volumes:
       - /home/pi/www/feed:/usr/share/nginx/html/feed
       - /home/cropswap-archive/www:/usr/share/nginx/html/mail-archive
+      - ./static:/usr/share/nginx/html/static
       - ./media:/usr/share/nginx/html/media
       - ./.well-known:/usr/share/nginx/html/.well-known
     networks:

+ 2 - 0
nginx.conf

@@ -16,6 +16,8 @@ http {
     }
     location /media/ {
     }
+    location /static {
+    }
     location /license/ {
       charset UTF-8;
       autoindex on;

+ 0 - 7
rest/Dockerfile

@@ -1,7 +0,0 @@
-FROM python:3-slim
-WORKDIR /usr/src/app
-COPY rest/requirements.txt ./
-RUN python3 -m pip install --upgrade pip && \
-    python3 -m pip install --no-cache-dir -r requirements.txt
-COPY rest rest
-CMD [ "python", "-m", "rest.cherrypy" ]

+ 0 - 18
rest/__init__.py

@@ -1,18 +0,0 @@
-#
-# Copyright (c) Daniel Sheffield 2023
-#
-# All rights reserved
-#
-# THIS SOFTWARE IS PROVIDED AS IS WITHOUT WARRANTY
-from bottle import TEMPLATE_PATH
-
-TEMPLATE_PATH.append("rest/templates")
-ALL_UNITS = { 'g', 'kg', 'mL', 'L', 'Pieces', 'Bunches', 'Bags' }
-PARAMS = { 'group', 'category', 'product', 'unit', 'tag', 'organic' }
-BOOLEAN = {
-    "1": True,
-    True: "1",
-    "0": False,
-    False: "0",
-    None: "0.5",
-}

+ 0 - 14
rest/bar.py

@@ -1,14 +0,0 @@
-from barcode import EAN13, Code128, Code39
-
-BARCODE_MAP = {
-  'EAN_13': EAN13,
-  'CODE_128': Code128,
-  'CODE_39': Code39,
-}
-
-def get_bar_code(meta):
-    f = BARCODE_MAP.get(meta['format'], None)
-    if f is not None:
-        return f(meta['content']).render()
-
-    return None

+ 0 - 15
rest/cherrypy.py

@@ -1,15 +0,0 @@
-import cherrypy
-import bottle
-from .pyapi import *
-
-application = bottle.default_app()
-
-cherrypy.config.update({
-    'server.socket_host': "0.0.0.0",
-    'server.socket_port': 6772,
-})
-
-cherrypy.tree.graft(application, "/")
-
-cherrypy.engine.start()
-cherrypy.engine.block()

+ 0 - 1
rest/dev-requirements.txt

@@ -1 +0,0 @@
-pytest

+ 0 - 181
rest/hash_util.py

@@ -1,181 +0,0 @@
-from hashlib import blake2b, shake_128, md5, sha256, sha1
-import os
-from base64 import b64encode, b64decode, b85encode, b85decode
-import base32_lib as b32
-
-DIGEST_SIZE_BYTES = 3
-DIGEST_SIZE_BITMASK = 0xffffff
-DIGEST_SIZE_SIGNED_TO_UNSIGNED_BITMASK = 0x1ffffff
-DIGEST_SIZE_SIGNED_TO_UNSIGNED_BIT = 0x1000000
-DIGEST_SIZE_NIBBLES = DIGEST_SIZE_BYTES * 2
-B64ALTCHARS = b'.-'
-B32REGEX = r'[0-9a-tv-zA-TV-Z]'
-
-def sha1hash(data: str):
-    return sha1(data.encode("utf-8"), usedforsecurity=False).hexdigest()[:DIGEST_SIZE_BYTES]
-
-def sha256hash(data: str):
-    return sha256(data.encode("utf-8"), usedforsecurity=False).hexdigest()[:DIGEST_SIZE_BYTES]
-
-def md5hash(data: str):
-    return md5(data.encode("utf-8"), usedforsecurity=False).hexdigest()[:DIGEST_SIZE_BYTES]
-
-def shake(data: str):
-    return shake_128(data.encode("utf-8"), usedforsecurity=False).hexdigest(DIGEST_SIZE_BYTES)
-
-def blake(data: bytes, person: bytes = None) -> bytes:
-    return blake2b(
-        data,
-        usedforsecurity=False,
-        digest_size=DIGEST_SIZE_BYTES,
-        person=person
-    ).digest()
-
-def blake_file(path: str, person: bytes = None, root: str ='rest/static') -> bytes:
-    fd = os.open(f'{root}/{path}', os.O_RDONLY, 0o600)
-    with open(fd, "rb") as f:
-        f.seek(0)
-        _blake = blake2b(usedforsecurity=False, digest_size=DIGEST_SIZE_BYTES, person=person)
-        while f.peek(1):
-            _blake.update(f.read(1024))
-    return _blake.digest()
-        
-
-def python(data: str):
-    return hash(data)
-
-def normalize_hash(_hash: int) -> int:
-    #hex = hash_to_hex(_hash)
-    #return int(hex, 16)
-    #_bytes = _hash.to_bytes(8, byteorder='big', signed=True)
-    #return bytes_to_hash(_bytes)
-    return _hash & DIGEST_SIZE_BITMASK
-
-def normalize_bytes(_bytes: bytes) -> bytes:
-    return (b'\x00' * DIGEST_SIZE_BYTES + _bytes)[-DIGEST_SIZE_BYTES:]
-
-def normalize_hex(_hex: str) -> str:
-    #_bytes = hex_to_bytes(hex)
-    #return _bytes.hex()
-    return _hex.zfill(DIGEST_SIZE_NIBBLES)[-DIGEST_SIZE_NIBBLES:]
-
-def hex_to_bytes(_hex: str) -> bytes:
-    _bytes = bytes.fromhex(_hex.zfill(DIGEST_SIZE_NIBBLES))
-    return normalize_bytes(_bytes)
-
-def bytes_to_hex(_bytes: bytes) -> str:
-    return normalize_bytes(_bytes).hex()
-
-def hash_to_bytes(_hash: int) -> bytes:
-    _bytes = _hash.to_bytes(8, byteorder='big', signed=True)
-    return normalize_bytes(_bytes)
-
-def bytes_to_hash(_bytes: bytes) -> int:
-    norm = normalize_bytes(_bytes)
-    return int.from_bytes(norm, byteorder='big', signed=False)
-
-def hash_to_hex(_hash: int) -> str:
-    #return hash_to_bytes(_hash).hex()
-    #return normalize_hex(
-    #return f"{_hash + (1 << 64):x}"[-4:]
-    #return hex(_hash + (1<<64))[2:][-4:]
-    #return f"{_hash & 0xffff:04x}"
-    return hex((_hash|DIGEST_SIZE_SIGNED_TO_UNSIGNED_BIT) & DIGEST_SIZE_SIGNED_TO_UNSIGNED_BITMASK)[3:]
-
-def hex_to_hash(_hex: str) -> int:
-    #_bytes = bytes.fromhex(hex.zfill(4))
-    #return bytes_to_hash(_bytes)
-    #return int(normalize_hex(hex), 16)
-    return int(_hex, 16) & DIGEST_SIZE_BITMASK
-
-def remove_padding(f):
-    def wrap(*args, **kwargs):
-        return f(*args, **kwargs).split('=')[0]
-    return wrap
-
-def fix_padding(f):
-    def wrap(_b64, *args, **kwargs):
-        pad = (4 - len(_b64)) % 4
-        fixed = _b64 + '='*pad
-        return f(fixed, *args, **kwargs)
-    return wrap
-
-def normalize_base32(_b32: str):
-    return b32.encode(b32.decode(_b32)).upper().zfill(DIGEST_SIZE_BYTES*8//5+1)
-
-def add_padding_base32(f):
-    def wrap(*args, **kwargs):
-        return normalize_base32(f(*args, **kwargs))
-    return wrap
-
-@remove_padding
-def hash_to_base64(_hash: int) -> str:
-    return b64encode(hash_to_bytes(_hash), altchars=B64ALTCHARS).decode("utf-8")
-
-@remove_padding
-def hex_to_base64(_hex: str) -> str:
-    return b64encode(hex_to_bytes(_hex), altchars=B64ALTCHARS).decode("utf-8")
-
-@remove_padding
-def bytes_to_base64(_bytes: str) -> str:
-    return b64encode(normalize_bytes(_bytes), altchars=B64ALTCHARS).decode("utf-8")
-
-@fix_padding
-def base64_to_hash(_b64: str) -> str:
-    return bytes_to_hash(b64decode(_b64, altchars=B64ALTCHARS))
-
-@fix_padding
-def base64_to_hex(_b64: str) -> str:
-    return bytes_to_hex(b64decode(_b64, altchars=B64ALTCHARS))
-
-@fix_padding
-def base64_to_bytes(_b64: str) -> str:
-    return normalize_bytes(b64decode(_b64, altchars=B64ALTCHARS))
-
-#@remove_padding
-def hash_to_base85(_hash: int) -> str:
-    return b85encode(hash_to_bytes(_hash)).decode("utf-8")
-
-#@remove_padding
-def hex_to_base85(_hex: str) -> str:
-    return b85encode(hex_to_bytes(_hex)).decode("utf-8")
-
-#@remove_padding
-def bytes_to_base85(_bytes: str) -> str:
-    return b85encode(normalize_bytes(_bytes)).decode("utf-8")
-
-#@fix_padding
-def base85_to_hash(_b64: str) -> str:
-    return bytes_to_hash(b85decode(_b64))
-
-#@fix_padding
-def base85_to_hex(_b64: str) -> str:
-    return bytes_to_hex(b85decode(_b64))
-
-#@fix_padding
-def base85_to_bytes(_b64: str) -> str:
-    return normalize_bytes(b85decode(_b64))
-
-@add_padding_base32
-def hash_to_base32(_hash: int) -> str:
-    return b32.encode(_hash & DIGEST_SIZE_BITMASK)
-
-@add_padding_base32
-def hex_to_base32(_hex: str) -> str:
-    return b32.encode(hex_to_hash(_hex))
-
-@add_padding_base32
-def bytes_to_base32(_bytes: bytes) -> str:
-    return b32.encode(bytes_to_hash(_bytes))
-
-#@fix_padding
-def base32_to_hash(_b64: str) -> str:
-    return b32.decode(_b64)
-
-#@fix_padding
-def base32_to_hex(_b64: str) -> str:
-    return hash_to_hex(base32_to_hash(_b64))
-
-#@fix_padding
-def base32_to_bytes(_b64: str) -> str:
-    return hash_to_bytes(base32_to_hash(_b64))

+ 0 - 166
rest/pyapi.py

@@ -1,166 +0,0 @@
-#
-# Copyright (c) Daniel Sheffield 2024
-# All rights reserved
-#
-# THIS SOFTWARE IS PROVIDED AS IS WITHOUT WARRANTY
-
-import time
-from bottle import (
-    route, request, response,
-    redirect, abort, static_file,
-    HTTPResponse,
-)
-from itertools import chain
-from base64 import b64decode, b64encode
-from linkpreview import link_preview
-
-from .hash_util import B32REGEX, normalize_base32, blake, bytes_to_base32
-from .qr import get_qr_code
-from .bar import get_bar_code
-from json import dumps, load, loads
-from sqlite3 import connect
-from datetime import datetime, timezone
-
-SCHEME = "https://"
-HOST = ""
-DOMAIN = "shandan.one"
-PORT = ""
-LOCATION = SCHEME + (f"{HOST}." if HOST else "") + DOMAIN + (f":{PORT}" if PORT else "")
-
-def parse_data_uri(content):
-    # extract bytes from data url
-    _, *media, data = chain.from_iterable(map(
-        lambda x: x.split(',', 1), content.split(':', 1)
-    ))
-    media = media and media[0]
-    mimetype, *params, encoding = media.split(';')
-    if '=' in encoding:
-        params.append(encoding)
-        encoding = None
-    
-    return {
-        'mimetype': mimetype,
-        'params': dict(map(lambda x: x.split('='), params)),
-        'encoding': encoding,
-        'data': data,
-    }
-
-
-def parse_upload_placeholder(rowid):
-    rowid = int(rowid)
-    con = connect('util.db')
-    content = None
-    try:
-        content = con.cursor().execute("""
-SELECT content FROM upload_temp WHERE rowid = ? LIMIT 1;
-""", (rowid,)).fetchall()[0][0]
-    finally:
-        con.close()
-    
-    data = parse_data_uri(content)
-    assert data['encoding'] == 'base64', f"unsupported encoding: {data['encoding']}"
-    data = b64decode(data['data'] + '==')
-    return data
-
-
-@route('/<route:re:(clip|goto|upload|code)>/meta', method=['POST'])
-def get_meta(route):
-    response.content_type = 'application/json'
-    body = load(request.body)
-    person = route
-    if route == 'upload':
-        data = parse_upload_placeholder(body['data'])
-    elif route == 'code':
-        data = dumps(body['data'], sort_keys=True).encode('utf-8')
-    else:
-        data = body['data'].encode('utf-8')
-
-    _bytes = blake(data, person = person and person.encode('utf-8'))
-    hash = bytes_to_base32(_bytes)
-    fallback = f'https://shandan.one/{route}/{hash}'
-
-    preview = None
-    if route == 'goto':
-        link = data.decode('utf-8')
-        try:
-            page = link_preview(link, parser="lxml")
-            preview = {
-                'title': page.title,
-                'img': page.absolute_image,
-                'domain': page.site_name,
-                'link': link,
-            }
-        except:
-            pass
-    elif route == 'code':
-        if body['data']['format'] == 'QR_CODE':
-            preview = b64encode(get_qr_code(body['data']['content'], err_lvl=body['data']['errorCorrectionLevel']))
-        else:
-            preview = b64encode(get_bar_code(body['data']))
-        preview = preview.decode('utf-8')
-
-    qr = None
-    if route != 'code':
-        qr = get_qr_code(data, fallback = fallback).decode('utf-8')
-
-    return dumps({
-        'hash': hash,
-        'qr': qr,
-        'preview': preview,
-    })
-
-@route('/<route:re:(clip|goto|upload)>/normalize', method=['GET'])
-def normalize(route):
-    _hash = request.params.hash
-    response.content_type = 'application/json'
-    return dumps({
-        'i': _hash,
-        'o': normalize_base32(_hash) if _hash else None,
-    })
-
-@route('/static/<filename:path>')
-def send_static(filename):
-    return static_file(filename, root='rest/static')
-
-@route(f'/<route:re:(clip|goto|code)>/<hash:re:{B32REGEX}{{1,5}}>', method='GET')
-def get_clip(route, hash):
-    hash = hash and normalize_base32(hash)
-    return redirect(f'/{route}/?hash={hash}&go=true')
-
-
-@route(f'/upload/<hash:re:{B32REGEX}{{1,5}}>', method='GET')
-def get_upload(hash):
-    hash = hash and normalize_base32(hash)
-    con = connect('util.db')
-    fname, mimetype, content = (None, None, None)
-    try:
-        fname, mimetype, content, created = con.cursor().execute("""
-SELECT name, mime, content, created FROM upload WHERE hash = ? LIMIT 1;
-""", (hash,)).fetchall()[0]
-    finally:
-        con.close()
-
-    created = datetime.strptime(created, '%Y-%m-%d %H:%M:%S').replace(tzinfo=timezone.utc).timestamp()
-    data = parse_data_uri(content)
-    assert data['mimetype'].split(';', 1)[0] == mimetype.split(';', 1)[0].split('+')[0], f"mimetype in db and data uri differ"
-    charset = data['params'].get('charset', None)
-    assert data['encoding'] == 'base64', f"unsupported encoding: {data['encoding']}"
-    content = b64decode(data['data'] + '==')
-
-    headers = {}
-    headers['Content-Length'] = len(content)
-
-    # TODO: create ext from mime type?
-    headers['Content-Disposition'] = 'attachment; filename="%s"' % (fname or hash)
-    headers['Content-Encoding'] = 'application/octet-stream'
-
-    if mimetype:
-        if mimetype[:5] == 'text/' and charset and 'charset' not in mimetype:
-            mimetype += '; charset=%s' % charset
-        headers['Content-Type'] = mimetype
-    lm = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(created))
-    headers['Last-Modified'] = lm
-    return HTTPResponse(content, **headers)
-
-@route('/<any>/', method='GET')
-def redirect_trailing_slash(any): return redirect(f'/{any}')

+ 0 - 36
rest/qr.py

@@ -1,36 +0,0 @@
-from io import BytesIO
-from typing import Union
-from qrcode import QRCode
-from qrcode.constants import ERROR_CORRECT_L, ERROR_CORRECT_M, ERROR_CORRECT_Q, ERROR_CORRECT_H
-from qrcode.image.svg import SvgPathFillImage
-
-QR_MAX_BYTES = {
-    ERROR_CORRECT_H: 1273,
-    ERROR_CORRECT_Q: 1663,
-    ERROR_CORRECT_M: 2331,
-    ERROR_CORRECT_L: 2953,
-}
-QR_QUALITY_MAP = {
-  q: locals().get(f'ERROR_CORRECT_{q}') for q in (
-    'H', 'Q', 'M', 'L'
-  )
-}
-def get_qr_code(data: Union[bytes, str], fallback: Union[bytes, str] = None, err_lvl='H'):
-    err_lvl = QR_QUALITY_MAP.get(err_lvl, err_lvl)
-    qr = QRCode(error_correction=err_lvl)
-    if data is not None and isinstance(data, str):
-        data = data.encode('utf-8')
-    if fallback is not None and isinstance(fallback, str):
-        fallback = fallback.encode('utf-8')
-    if fallback is not None and data and len(data) > QR_MAX_BYTES[err_lvl]:
-        qr.add_data(fallback, optimize=0)
-    else:
-        qr.add_data(data or fallback, optimize=0)
-
-    img_1 = qr.make_image(image_factory=SvgPathFillImage)
-    with BytesIO() as f:
-        img_1.save(f)
-        f.flush()
-        ret = f.getvalue()
-    return ret
-    

+ 0 - 7
rest/requirements.txt

@@ -1,7 +0,0 @@
-bottle
-cherrypy
-base32-lib
-lxml
-linkpreview
-qrcode
-python-barcode

BIN
rest/static/clip/144.png


BIN
rest/static/clip/192.png


BIN
rest/static/clip/48.png


BIN
rest/static/clip/512.png


BIN
rest/static/clip/72.png


BIN
rest/static/clip/96.png


+ 0 - 9
rest/static/clip/clip-favicon.svg

@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!--
-  Source: https://commons.wikimedia.org/wiki/File:Clipboard_(1714)_-_The_Noun_Project.svg
-  Author: Seth Taylor, CC0, via Wikimedia Commons
-  License: https://creativecommons.org/publicdomain/zero/1.0/deed.en
--->
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 71 100" enable-background="new 0 0 71 100" xml:space="preserve">
-<rect fill="#fff" y="10" x="15" width="60" height="85"/>
-<path d="M70,7.583H56.625V5.961c0-0.55-0.45-1-1-1H43.443V2c0-1.1-0.9-2-2-2H29.557c-1.1,0-2,0.9-2,2v2.961H15.375  c-0.55,0-1,0.45-1,1v1.623H1c-0.55,0-1,0.45-1,1V99c0,0.55,0.45,1,1,1h69c0.55,0,1-0.45,1-1V8.583C71,8.034,70.55,7.583,70,7.583z   M35.5,2.319c1.094,0,1.981,0.887,1.981,1.98c0,1.094-0.888,1.981-1.981,1.981c-1.094,0-1.981-0.887-1.981-1.981  C33.519,3.206,34.406,2.319,35.5,2.319z M63.495,92.395c0,0.55-0.45,1-1,1H8.505c-0.55,0-1-0.45-1-1V15.188c0-0.55,0.45-1,1-1h5.87  v1.669c0,0.55,0.45,1,1,1h40.25c0.55,0,1-0.45,1-1v-1.669h5.87c0.55,0,1,0.45,1,1V92.395z"></path><rect x="14.375" y="25.5" width="38.125" height="2.375"></rect><rect x="14.375" y="31.625" width="38.125" height="2.375"></rect><rect x="14.375" y="37.75" width="29.125" height="2.375"></rect><rect x="14.375" y="50" width="38.125" height="2.375"></rect><rect x="14.375" y="56.125" width="38.125" height="2.375"></rect><rect x="14.375" y="62.25" width="29.125" height="2.375"></rect></svg>

+ 0 - 93
rest/static/clip/clip-favicon_square.svg

@@ -1,93 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!--
-  Source: https://commons.wikimedia.org/wiki/File:Clipboard_(1714)_-_The_Noun_Project.svg
-  Author: Seth Taylor, CC0, via Wikimedia Commons
-  License: https://creativecommons.org/publicdomain/zero/1.0/deed.en
--->
-
-<svg
-   version="1.1"
-   x="0px"
-   y="0px"
-   viewBox="0 0 100 100"
-   enable-background="new 0 0 71 100"
-   xml:space="preserve"
-   id="svg68"
-   sodipodi:docname="clip-favicon_square.svg"
-   width="100"
-   height="100"
-   inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
-   inkscape:export-filename="/home/das/git/home-launcher/rest/static/clip-favicon_512.png"
-   inkscape:export-xdpi="491.51999"
-   inkscape:export-ydpi="491.51999"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:svg="http://www.w3.org/2000/svg"><defs
-   id="defs72" /><sodipodi:namedview
-   id="namedview70"
-   pagecolor="#ffffff"
-   bordercolor="#666666"
-   borderopacity="1.0"
-   inkscape:pageshadow="2"
-   inkscape:pageopacity="0.0"
-   inkscape:pagecheckerboard="0"
-   showgrid="false"
-   width="100px"
-   inkscape:zoom="5.94"
-   inkscape:cx="23.063973"
-   inkscape:cy="49.915825"
-   inkscape:window-width="1680"
-   inkscape:window-height="997"
-   inkscape:window-x="0"
-   inkscape:window-y="0"
-   inkscape:window-maximized="1"
-   inkscape:current-layer="svg68" />
-<rect
-   fill="#ffffff"
-   opacity="0"
-   y="10"
-   x="20"
-   width="60"
-   height="85"
-   id="rect4" />
-<path
-   fill="#2fb344"
-   d="M 84.5,7.583 H 71.125 V 5.961 c 0,-0.55 -0.45,-1 -1,-1 H 57.943 V 2 c 0,-1.1 -0.9,-2 -2,-2 H 44.057 c -1.1,0 -2,0.9 -2,2 V 4.961 H 29.875 c -0.55,0 -1,0.45 -1,1 V 7.584 H 15.5 c -0.55,0 -1,0.45 -1,1 V 99 c 0,0.55 0.45,1 1,1 h 69 c 0.55,0 1,-0.45 1,-1 V 8.583 c 0,-0.549 -0.45,-1 -1,-1 z M 50,2.319 c 1.094,0 1.981,0.887 1.981,1.98 0,1.094 -0.888,1.981 -1.981,1.981 -1.094,0 -1.981,-0.887 -1.981,-1.981 0,-1.093 0.887,-1.98 1.981,-1.98 z m 27.995,90.076 c 0,0.55 -0.45,1 -1,1 h -53.99 c -0.55,0 -1,-0.45 -1,-1 V 15.188 c 0,-0.55 0.45,-1 1,-1 h 5.87 v 1.669 c 0,0.55 0.45,1 1,1 h 40.25 c 0.55,0 1,-0.45 1,-1 v -1.669 h 5.87 c 0.55,0 1,0.45 1,1 z"
-   id="path54" /><rect
-   fill="#2fb344"
-   x="28.875"
-   y="25.5"
-   width="38.125"
-   height="2.375"
-   id="rect56" /><rect
-   fill="#2fb344"
-   x="28.875"
-   y="31.625"
-   width="38.125"
-   height="2.375"
-   id="rect58" /><rect
-   fill="#2fb344"
-   x="28.875"
-   y="37.75"
-   width="29.125"
-   height="2.375"
-   id="rect60" /><rect
-   fill="#2fb344"
-   x="28.875"
-   y="50"
-   width="38.125"
-   height="2.375"
-   id="rect62" /><rect
-   fill="#2fb344"
-   x="28.875"
-   y="56.125"
-   width="38.125"
-   height="2.375"
-   id="rect64" /><rect
-   fill="#2fb344"
-   x="28.875"
-   y="62.25"
-   width="29.125"
-   height="2.375"
-   id="rect66" /></svg>

+ 0 - 61
rest/static/clip/manifest.json

@@ -1,61 +0,0 @@
-{
-  "id": "/clip",
-  "name": "Paste & Clip",
-  "short_name": "Clip",
-  "description": "Save snippets of text to a virtual clipboard to share via a short URL",
-  "start_url": "/clip/",
-  "shortcuts": [
-    {
-      "name": "Open",
-      "url": "/clip?action=open",
-      "icons": [{ "src": "/static/ftark-open.png", "sizes": "96x96" }]
-    },
-    {
-      "name": "New",
-      "url": "/clip",
-      "icons": [{ "src": "/static/clip/96.png", "sizes": "96x96" }]
-    }
-  ],
-  "scope": "/clip/",
-  "theme_color": "#4f8f4f",
-  "background_color": "black",
-  "display": "standalone",
-  "icons": [
-    {
-      "src": "/static/clip/512.png",
-      "sizes": "512x512",
-      "type": "image/png",
-      "purpose": "any"
-    },
-    {
-      "src": "/static/clip/192.png",
-      "sizes": "192x192",
-      "type": "image/png",
-      "purpose": "any"
-    },
-    {
-      "src": "/static/clip/144.png",
-      "sizes": "144x144",
-      "type": "image/png",
-      "purpose": "any"
-    },
-    {
-      "src": "/static/clip/96.png",
-      "sizes": "96x96",
-      "type": "image/png",
-      "purpose": "any"
-    },
-    {
-      "src": "/static/clip/72.png",
-      "sizes": "72x72",
-      "type": "image/png",
-      "purpose": "any"
-    },
-    {
-      "src": "/static/clip/48.png",
-      "sizes": "48x48",
-      "type": "image/png",
-      "purpose": "any"
-    }
-  ]
-}

File diff suppressed because it is too large
+ 0 - 1
rest/static/clip/qr.svg


File diff suppressed because it is too large
+ 0 - 1
rest/static/code/qr.svg


BIN
rest/static/ftark-open.png


+ 0 - 138
rest/static/ftark-open.svg

@@ -1,138 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<!-- 
-  Source: https://publicdomainvectors.org/en/free-clipart/Open-folder-monochrome-icon/87757.html
-  License: Public Domain
--->
-
-<svg
-   id="svg1"
-   sodipodi:docname="ftark-open.svg"
-   viewBox="0 0 60 60"
-   sodipodi:version="0.32"
-   version="1.0"
-   y="0"
-   x="0"
-   inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
-   width="60"
-   height="60"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-   xmlns:cc="http://creativecommons.org/ns#"
-   xmlns:dc="http://purl.org/dc/elements/1.1/">
-  <defs
-     id="defs8" />
-  <sodipodi:namedview
-     id="base"
-     bordercolor="#666666"
-     inkscape:pageshadow="2"
-     inkscape:window-width="1680"
-     pagecolor="#ffffff"
-     inkscape:zoom="6.9465337"
-     inkscape:window-x="0"
-     borderopacity="1.0"
-     inkscape:cx="37.716653"
-     inkscape:cy="31.74245"
-     inkscape:window-y="0"
-     inkscape:window-height="997"
-     inkscape:pageopacity="0.0"
-     inkscape:pagecheckerboard="0"
-     showgrid="false"
-     inkscape:window-maximized="1"
-     inkscape:current-layer="svg1"
-     fit-margin-top="0"
-     fit-margin-left="0"
-     fit-margin-right="0"
-     fit-margin-bottom="0" />
-  <rect
-     style="fill:none;stroke-width:4.27435"
-     id="rect845"
-     width="60"
-     height="60"
-     x="0"
-     y="0"
-     rx="0"
-     ry="0"
-     inkscape:export-filename="/home/das/git/home-launcher/rest/static/ftark-open.png"
-     inkscape:export-xdpi="153.60001"
-     inkscape:export-ydpi="153.60001" />
-  <g
-     id="g929"
-     transform="translate(-0.60199608,-0.73891072)"
-     inkscape:export-filename="/home/das/git/home-launcher/rest/static/ftark-open.png"
-     inkscape:export-xdpi="153.60001"
-     inkscape:export-ydpi="153.60001">
-    <path
-       id="path938"
-       style="fill:#b3b3b3;fill-rule:evenodd;stroke:#333333;stroke-width:3.125;stroke-linejoin:round"
-       d="m 5.433,8.4867 c -0.5262,0 -0.9687,0.4425 -0.9687,0.9687 V 14.33 C 4.4631,14.355 4.433,14.368 4.433,14.393 v 37 c 0,0.884 0.71,1.594 1.5938,1.594 h 37.281 c 0.884,0 1.594,-0.71 1.594,-1.594 v -37 c 0,-0.884 -0.71,-1.594 -1.594,-1.594 H 28.5888 V 9.4554 c 0,-0.5262 -0.442,-0.9687 -0.968,-0.9687 H 5.4328 Z" />
-    <rect
-       id="rect922"
-       style="fill:#7f7f7f;fill-rule:evenodd;stroke:#333333;stroke-width:3.2351;stroke-linejoin:round"
-       rx="1.5953"
-       transform="matrix(1,0,-0.35965,0.93309,0,0)"
-       width="40.476002"
-       sodipodi:stroke-cmyk="(0 0 0 0.8)"
-       y="23.398001"
-       x="25.032"
-       height="33.450001"
-       sodipodi:fill-cmyk="(0 0 0 0.5)" />
-  </g>
-  <metadata
-     id="metadata5">
-    <rdf:RDF>
-      <cc:Work>
-        <dc:format>image/svg+xml</dc:format>
-        <dc:type
-           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-        <cc:license
-           rdf:resource="http://creativecommons.org/publicdomain/zero/1.0/" />
-        <dc:publisher>
-          <cc:Agent
-             rdf:about="http://openclipart.org/">
-            <dc:title>Openclipart</dc:title>
-          </cc:Agent>
-        </dc:publisher>
-        <dc:title>ftark open</dc:title>
-        <dc:date>2011-01-31T02:01:08</dc:date>
-        <dc:description>Originally uploaded by Danny Allen for OCAL 0.18 this icon is part of the flat theme</dc:description>
-        <dc:source>https://openclipart.org/detail/111721/ftark-open-by-anonymous</dc:source>
-        <dc:creator>
-          <cc:Agent>
-            <dc:title>Anonymous</dc:title>
-          </cc:Agent>
-        </dc:creator>
-        <dc:subject>
-          <rdf:Bag>
-            <rdf:li>flat</rdf:li>
-            <rdf:li>icon</rdf:li>
-            <rdf:li>theme</rdf:li>
-          </rdf:Bag>
-        </dc:subject>
-      </cc:Work>
-      <cc:License
-         rdf:about="http://creativecommons.org/publicdomain/zero/1.0/">
-        <cc:permits
-           rdf:resource="http://creativecommons.org/ns#Reproduction" />
-        <cc:permits
-           rdf:resource="http://creativecommons.org/ns#Distribution" />
-        <cc:permits
-           rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
-      </cc:License>
-    </rdf:RDF>
-  </metadata>
-  <rect
-     style="fill:#8f4f4f;stroke-width:4"
-     id="rect1382"
-     width="0.14395669"
-     height="1.1516535"
-     x="29.928022"
-     y="29.424173"
-     inkscape:export-filename="/home/das/git/home-launcher/rest/static/ftark-open.png"
-     inkscape:export-xdpi="153.60001"
-     inkscape:export-ydpi="153.60001" />
-</svg>

BIN
rest/static/goto/144.png


BIN
rest/static/goto/192.png


BIN
rest/static/goto/48.png


BIN
rest/static/goto/512.png


BIN
rest/static/goto/72.png


BIN
rest/static/goto/96.png


File diff suppressed because it is too large
+ 0 - 69
rest/static/goto/chain-link-3-2.svg


File diff suppressed because it is too large
+ 0 - 49
rest/static/goto/chain-link-cut-away.svg


File diff suppressed because it is too large
+ 0 - 50
rest/static/goto/chain-link.svg


File diff suppressed because it is too large
+ 0 - 62
rest/static/goto/chain-link2-3-2.svg


File diff suppressed because it is too large
+ 0 - 51
rest/static/goto/chain-link2-cut-away.svg


File diff suppressed because it is too large
+ 0 - 51
rest/static/goto/chain-link2.svg


File diff suppressed because it is too large
+ 0 - 76
rest/static/goto/chain-link2fr-3-2.svg


File diff suppressed because it is too large
+ 0 - 75
rest/static/goto/chain-link2r-3-2.svg


+ 0 - 61
rest/static/goto/manifest.json

@@ -1,61 +0,0 @@
-{
-  "id": "/goto",
-  "name": "GoTo... Tiny URL",
-  "short_name": "GoTo",
-  "description": "Share links by generating a short URL that can be easily typed or verbalised",
-  "start_url": "/goto",
-  "shortcuts": [
-    {
-      "name": "Open",
-      "url": "/goto?action=open",
-      "icons": [{ "src": "/static/ftark-open.png", "sizes": "96x96" }]
-    },
-    {
-      "name": "New",
-      "url": "/goto",
-      "icons": [{ "src": "/static/goto/96.png", "sizes": "96x96" }]
-    }
-  ],
-  "scope": "/goto",
-  "theme_color": "#8f4f4f",
-  "background_color": "black",
-  "display": "standalone",
-  "icons": [
-    {
-      "src": "/static/goto/512.png",
-      "sizes": "512x512",
-      "type": "image/png",
-      "purpose": "any"
-    },
-    {
-      "src": "/static/goto/192.png",
-      "sizes": "192x192",
-      "type": "image/png",
-      "purpose": "any"
-    },
-    {
-      "src": "/static/goto/144.png",
-      "sizes": "144x144",
-      "type": "image/png",
-      "purpose": "any"
-    },
-    {
-      "src": "/static/goto/96.png",
-      "sizes": "96x96",
-      "type": "image/png",
-      "purpose": "any"
-    },
-    {
-      "src": "/static/goto/72.png",
-      "sizes": "72x72",
-      "type": "image/png",
-      "purpose": "any"
-    },
-    {
-      "src": "/static/goto/48.png",
-      "sizes": "48x48",
-      "type": "image/png",
-      "purpose": "any"
-    }
-  ]
-}

File diff suppressed because it is too large
+ 0 - 1
rest/static/goto/qr.svg


BIN
rest/static/shandanone-small.png


+ 0 - 68
rest/static/shandanone-small.svg

@@ -1,68 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
-   width="104.20946mm"
-   height="95.790558mm"
-   viewBox="0 0 104.20946 95.790558"
-   version="1.1"
-   id="svg5"
-   inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
-   sodipodi:docname="shandanone-small.svg"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:svg="http://www.w3.org/2000/svg">
-  <sodipodi:namedview
-     id="namedview7"
-     pagecolor="#ffffff"
-     bordercolor="#666666"
-     borderopacity="1.0"
-     inkscape:pageshadow="2"
-     inkscape:pageopacity="0.0"
-     inkscape:pagecheckerboard="true"
-     inkscape:document-units="mm"
-     showgrid="false"
-     fit-margin-top="0"
-     fit-margin-left="0"
-     fit-margin-right="0"
-     fit-margin-bottom="0"
-     inkscape:zoom="0.56569164"
-     inkscape:cx="61.871164"
-     inkscape:cy="181.19412"
-     inkscape:window-width="1680"
-     inkscape:window-height="997"
-     inkscape:window-x="1920"
-     inkscape:window-y="0"
-     inkscape:window-maximized="1"
-     inkscape:current-layer="layer1" />
-  <defs
-     id="defs2" />
-  <g
-     inkscape:label="Layer 1"
-     inkscape:groupmode="layer"
-     id="layer1"
-     transform="translate(-52.895271,-100.60472)">
-    <rect
-       style="fill:#00ffff;stroke-width:1.58288"
-       id="rect9235"
-       width="104.20946"
-       height="95.790558"
-       x="52.895271"
-       y="100.60472"
-       rx="9.1908665"
-       ry="8.2469568" />
-    <text
-       xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:82.0971px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.05243"
-       x="45.846691"
-       y="180.05571"
-       id="text1948"
-       transform="scale(1.040286,0.96127411)"><tspan
-         sodipodi:role="line"
-         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:FreeMono;-inkscape-font-specification:'FreeMono Bold';stroke-width:2.05243"
-         x="45.846691"
-         y="180.05571"
-         id="tspan31781">.1</tspan></text>
-  </g>
-</svg>

+ 0 - 78
rest/static/shandanone2.svg

@@ -1,78 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
-   width="104.20946mm"
-   height="95.790558mm"
-   viewBox="0 0 104.20946 95.790558"
-   version="1.1"
-   id="svg5"
-   inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
-   sodipodi:docname="shandanone2.svg"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:svg="http://www.w3.org/2000/svg">
-  <sodipodi:namedview
-     id="namedview7"
-     pagecolor="#ffffff"
-     bordercolor="#666666"
-     borderopacity="1.0"
-     inkscape:pageshadow="2"
-     inkscape:pageopacity="0.0"
-     inkscape:pagecheckerboard="true"
-     inkscape:document-units="mm"
-     showgrid="false"
-     fit-margin-top="0"
-     fit-margin-left="0"
-     fit-margin-right="0"
-     fit-margin-bottom="0"
-     inkscape:zoom="0.56569164"
-     inkscape:cx="61.871164"
-     inkscape:cy="181.19412"
-     inkscape:window-width="1680"
-     inkscape:window-height="997"
-     inkscape:window-x="1920"
-     inkscape:window-y="0"
-     inkscape:window-maximized="1"
-     inkscape:current-layer="layer1" />
-  <defs
-     id="defs2" />
-  <g
-     inkscape:label="Layer 1"
-     inkscape:groupmode="layer"
-     id="layer1"
-     transform="translate(-52.895271,-100.60472)">
-    <rect
-       style="fill:#00ffff;stroke-width:1.58288"
-       id="rect9235"
-       width="104.20946"
-       height="95.790558"
-       x="52.895271"
-       y="100.60472"
-       rx="9.1908665"
-       ry="8.2469568" />
-    <text
-       xml:space="preserve"
-       style="font-style:normal;font-weight:normal;font-size:23.4617px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.586543"
-       x="66.327843"
-       y="131.03873"
-       id="text1948"
-       transform="scale(1.040286,0.96127411)"><tspan
-         sodipodi:role="line"
-         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:FreeMono;-inkscape-font-specification:'FreeMono Bold';stroke-width:0.586543"
-         x="66.327843"
-         y="131.03873"
-         id="tspan4071">SHAN</tspan><tspan
-         sodipodi:role="line"
-         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:FreeMono;-inkscape-font-specification:'FreeMono Bold';stroke-width:0.586543"
-         x="66.327843"
-         y="161.30981"
-         id="tspan6473"> DAN</tspan><tspan
-         sodipodi:role="line"
-         style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:FreeMono;-inkscape-font-specification:'FreeMono Bold';stroke-width:0.586543"
-         x="66.327843"
-         y="191.58092"
-         id="tspan6475"> .ONE</tspan></text>
-  </g>
-</svg>

BIN
rest/static/upload/144.png


BIN
rest/static/upload/192.png


BIN
rest/static/upload/48.png


BIN
rest/static/upload/512.png


BIN
rest/static/upload/72.png


BIN
rest/static/upload/96.png


+ 0 - 61
rest/static/upload/manifest.json

@@ -1,61 +0,0 @@
-{
-  "id": "/upload",
-  "name": "Upload Files",
-  "short_name": "Upload",
-  "description": "Upload a file for sharing via a short URL",
-  "start_url": "/upload",
-  "shortcuts": [
-    {
-      "name": "Open",
-      "url": "/upload?action=open",
-      "icons": [{ "src": "/static/ftark-open.png", "sizes": "96x96" }]
-    },
-    {
-      "name": "New",
-      "url": "/upload",
-      "icons": [{ "src": "/static/upload/96.png", "sizes": "96x96" }]
-    }
-  ],
-  "scope": "/upload",
-  "theme_color": "#afaf0f",
-  "background_color": "black",
-  "display": "standalone",
-  "icons": [
-    {
-      "src": "/static/upload/512.png",
-      "sizes": "512x512",
-      "type": "image/png",
-      "purpose": "any"
-    },
-    {
-      "src": "/static/upload/192.png",
-      "sizes": "192x192",
-      "type": "image/png",
-      "purpose": "any"
-    },
-    {
-      "src": "/static/upload/144.png",
-      "sizes": "144x144",
-      "type": "image/png",
-      "purpose": "any"
-    },
-    {
-      "src": "/static/upload/96.png",
-      "sizes": "96x96",
-      "type": "image/png",
-      "purpose": "any"
-    },
-    {
-      "src": "/static/upload/72.png",
-      "sizes": "72x72",
-      "type": "image/png",
-      "purpose": "any"
-    },
-    {
-      "src": "/static/upload/48.png",
-      "sizes": "48x48",
-      "type": "image/png",
-      "purpose": "any"
-    }
-  ]
-}

File diff suppressed because it is too large
+ 0 - 1
rest/static/upload/qr.svg


+ 0 - 46
rest/static/upload/upload-favicon.svg

@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!--
-  Source: https://commons.wikimedia.org/wiki/File:Upload_(89524)_-_The_Noun_Project.svg
-  Author: Consumer Financial Protection Bureau, CC0, via Wikimedia Commons
-  License: https://creativecommons.org/publicdomain/zero/1.0/deed.en
--->
-
-<svg
-   version="1.1"
-   x="0px"
-   y="0px"
-   viewBox="0 0 90 100"
-   enable-background="new 0 0 100 100"
-   xml:space="preserve"
-   id="svg51"
-   sodipodi:docname="upload-favicon.svg"
-   inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
-   width="90"
-   height="100"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:svg="http://www.w3.org/2000/svg"><defs
-     id="defs55" /><sodipodi:namedview
-     id="namedview53"
-     pagecolor="#ffffff"
-     bordercolor="#666666"
-     borderopacity="1.0"
-     inkscape:pageshadow="2"
-     inkscape:pageopacity="0.0"
-     inkscape:pagecheckerboard="0"
-     showgrid="false"
-     inkscape:zoom="7.65"
-     inkscape:cx="16.013072"
-     inkscape:cy="50"
-     inkscape:window-width="1680"
-     inkscape:window-height="997"
-     inkscape:window-x="0"
-     inkscape:window-y="0"
-     inkscape:window-maximized="1"
-     inkscape:current-layer="svg51" />
-<rect fill="#fff" y="10" x="10" width="42" height="23"/>
-<rect fill="#fff" y="31" x="10" width="60" height="58"/>
-<path
-     d="m 47.8,34.8 c -1.5,-1.6 -4.1,-1.6 -5.6,0 0,0 -12.1,12.1 -12.5,12.5 -1.6,1.6 -1.6,4.1 0,5.7 1.5,1.6 4.1,1.6 5.7,0 0.4,-0.4 5.6,-5.6 5.6,-5.6 V 76 c 0,2.2 1.9,4.1 4,4.1 2.2,0 4,-1.9 4,-4.1 V 47.4 c 0,0 5.5,5.4 5.6,5.6 1.6,1.6 4.1,1.6 5.8,0 1.5,-1.6 1.5,-4.1 0,-5.7 C 60.3,47.1 47.8,34.8 47.8,34.8 Z m 31.5,-9.2 c 0,0 -0.4,-0.4 -19.4,-19.4 C 59.4,5.6 58.3,5 57,5 H 13.6 C 11.3,5 9.5,6.8 9.5,9.1 v 81.8 c 0,2.3 1.8,4.1 4.1,4.1 h 62.8 c 2.3,0 4,-1.8 4,-4.1 V 28.5 C 80.5,27.2 80,26.2 79.3,25.6 Z M 17.7,13.2 H 52.9 L 53,28.5 c 0,2.2 1.8,4 4,4 H 72.3 V 86.8 H 17.7 Z"
-     id="path49" /></svg>

+ 0 - 63
rest/static/upload/upload-favicon_maskable.svg

@@ -1,63 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!--
-  Source: https://commons.wikimedia.org/wiki/File:Upload_(89524)_-_The_Noun_Project.svg
-  Author: Consumer Financial Protection Bureau, CC0, via Wikimedia Commons
-  License: https://creativecommons.org/publicdomain/zero/1.0/deed.en
--->
-
-<svg
-   version="1.1"
-   x="0px"
-   y="0px"
-   viewBox="0 0 145 145"
-   enable-background="new 0 0 100 100"
-   xml:space="preserve"
-   id="svg51"
-   sodipodi:docname="upload-favicon_maskable.svg"
-   inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
-   width="145"
-   height="145"
-   inkscape:export-filename="/home/das/git/home-launcher/rest/static/upload-favicon_maskable_72.png"
-   inkscape:export-xdpi="47.668964"
-   inkscape:export-ydpi="47.668964"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:svg="http://www.w3.org/2000/svg"><defs
-   id="defs55" /><sodipodi:namedview
-   id="namedview53"
-   pagecolor="#ffffff"
-   bordercolor="#666666"
-   borderopacity="1.0"
-   inkscape:pageshadow="2"
-   inkscape:pageopacity="1"
-   inkscape:pagecheckerboard="0"
-   showgrid="false"
-   inkscape:zoom="5.4642857"
-   inkscape:cx="69.908497"
-   inkscape:cy="70.366013"
-   inkscape:window-width="1680"
-   inkscape:window-height="997"
-   inkscape:window-x="0"
-   inkscape:window-y="0"
-   inkscape:window-maximized="1"
-   inkscape:current-layer="svg51"
-   width="100px"
-   units="px" />
-<rect
-   fill="#ffffff"
-   y="32.5"
-   x="42.5"
-   width="42"
-   height="23"
-   id="rect169" />
-<rect
-   fill="#ffffff"
-   y="53.5"
-   x="42.5"
-   width="60"
-   height="58"
-   id="rect171" />
-<path
-   d="m 75.3,57.3 c -1.5,-1.6 -4.1,-1.6 -5.6,0 0,0 -12.1,12.1 -12.5,12.5 -1.6,1.6 -1.6,4.1 0,5.7 1.5,1.6 4.1,1.6 5.7,0 0.4,-0.4 5.6,-5.6 5.6,-5.6 v 28.6 c 0,2.2 1.9,4.1 4,4.1 2.2,0 4,-1.9 4,-4.1 V 69.9 c 0,0 5.5,5.4 5.6,5.6 1.6,1.6 4.1,1.6 5.8,0 1.5,-1.6 1.5,-4.1 0,-5.7 C 87.8,69.6 75.3,57.3 75.3,57.3 Z m 31.5,-9.2 c 0,0 -0.4,-0.4 -19.4,-19.4 -0.5,-0.6 -1.6,-1.2 -2.9,-1.2 H 41.1 c -2.3,0 -4.1,1.8 -4.1,4.1 v 81.8 c 0,2.3 1.8,4.1 4.1,4.1 h 62.8 c 2.3,0 4,-1.8 4,-4.1 V 51 c 0.1,-1.3 -0.4,-2.3 -1.1,-2.9 z M 45.2,35.7 H 80.4 L 80.5,51 c 0,2.2 1.8,4 4,4 h 15.3 v 54.3 H 45.2 Z"
-   id="path49" /></svg>

+ 0 - 65
rest/static/upload/upload-favicon_square.svg

@@ -1,65 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!--
-  Source: https://commons.wikimedia.org/wiki/File:Upload_(89524)_-_The_Noun_Project.svg
-  Author: Consumer Financial Protection Bureau, CC0, via Wikimedia Commons
-  License: https://creativecommons.org/publicdomain/zero/1.0/deed.en
--->
-
-<svg
-   version="1.1"
-   x="0px"
-   y="0px"
-   viewBox="0 0 100 100"
-   enable-background="new 0 0 100 100"
-   xml:space="preserve"
-   id="svg51"
-   sodipodi:docname="upload-favicon_square.svg"
-   inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
-   width="100"
-   height="100"
-   inkscape:export-filename="/home/das/git/home-launcher/rest/static/upload-favicon_512.png"
-   inkscape:export-xdpi="491.51999"
-   inkscape:export-ydpi="491.51999"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:svg="http://www.w3.org/2000/svg"><defs
-   id="defs55" /><sodipodi:namedview
-   id="namedview53"
-   pagecolor="#ffffff"
-   bordercolor="#666666"
-   borderopacity="1.0"
-   inkscape:pageshadow="2"
-   inkscape:pageopacity="1"
-   inkscape:pagecheckerboard="0"
-   showgrid="false"
-   inkscape:zoom="7.65"
-   inkscape:cx="49.150327"
-   inkscape:cy="50"
-   inkscape:window-width="1680"
-   inkscape:window-height="997"
-   inkscape:window-x="0"
-   inkscape:window-y="0"
-   inkscape:window-maximized="1"
-   inkscape:current-layer="svg51"
-   width="100px" />
-<rect
-   fill="#ffffff"
-   opacity="0"
-   y="10"
-   x="20"
-   width="42"
-   height="23"
-   id="rect603" />
-<rect
-   fill="#ffffff"
-   opacity="0"
-   y="31"
-   x="20"
-   width="60"
-   height="58"
-   id="rect605" />
-<path
-   fill="#f59f00"
-   d="m 52.8,34.8 c -1.5,-1.6 -4.1,-1.6 -5.6,0 0,0 -12.1,12.1 -12.5,12.5 -1.6,1.6 -1.6,4.1 0,5.7 1.5,1.6 4.1,1.6 5.7,0 0.4,-0.4 5.6,-5.6 5.6,-5.6 V 76 c 0,2.2 1.9,4.1 4,4.1 2.2,0 4,-1.9 4,-4.1 V 47.4 c 0,0 5.5,5.4 5.6,5.6 1.6,1.6 4.1,1.6 5.8,0 1.5,-1.6 1.5,-4.1 0,-5.7 C 65.3,47.1 52.8,34.8 52.8,34.8 Z m 31.5,-9.2 c 0,0 -0.4,-0.4 -19.4,-19.4 C 64.4,5.6 63.3,5 62,5 H 18.6 c -2.3,0 -4.1,1.8 -4.1,4.1 v 81.8 c 0,2.3 1.8,4.1 4.1,4.1 h 62.8 c 2.3,0 4,-1.8 4,-4.1 V 28.5 C 85.5,27.2 85,26.2 84.3,25.6 Z M 22.7,13.2 H 57.9 L 58,28.5 c 0,2.2 1.8,4 4,4 H 77.3 V 86.8 H 22.7 Z"
-   id="path49" /></svg>

+ 0 - 5
rest/tool_color.py

@@ -1,5 +0,0 @@
-color = {
-    'clip': '#4f8f4f',
-    'goto': '#8f4f4f',
-    'upload': '#afaf0f',
-}

+ 0 - 146
rest/validate.py

@@ -1,146 +0,0 @@
-#
-# Copyright (c) Daniel Sheffield 2024
-# All rights reserved
-#
-# THIS SOFTWARE IS PROVIDED AS IS WITHOUT WARRANTY
-
-# https://www.ietf.org/rfc/rfc3696.txt
-
-"""
-   Without quotes, local-parts may consist of any combination of
-   alphabetic characters, digits, or any of the special characters
-
-      ! # $ % & ' * + - / = ?  ^ _ ` . { | } ~
-
-   period (".") may also appear, but may not be used to start or end the
-   local part, nor may two or more consecutive periods appear.  Stated
-   differently, any ASCII graphic (printing) character other than the
-   at-sign ("@"), backslash, double quote, comma, or square brackets may
-   appear without quoting.  If any of that list of excluded characters
-   are to appear, they must be quoted.
-"""
-
-from io import BufferedReader
-import mimetypes
-from itertools import chain
-import os
-from bottle import static_file, HTTPError, abort, LocalRequest, HTTPResponse
-from urllib.parse import urlparse, quote, quote_plus
-from .hash_util import blake_file, bytes_to_base32, blake
-
-# according to rfc3696
-URL_MUST_ESCAPE = bytes([
-    x for x in chain(
-        # control characters
-        range(int('0x1F', 0)+1),
-        # 0x7F and non 7bit-ASCII
-        range(int('0x7F', 0,), int('0xFF', 0)+1),
-        # specifically excluded
-        b'@\\",[]'
-    )
-])
-# so give this list to urllib.parse.quote which follows rfc3986
-URL_SAFE = bytes(( i for i in range(int('0xff',0)+1) if i not in map(int, URL_MUST_ESCAPE) ))
-
-CLIP_SIZE_LIMIT = 65535
-
-def get_filename(filename: str, root: str = 'rest/static/files'):
-    path = '/'.join([filename,]*2)
-    try:
-        with open(f'{root}/{path}.name', "r") as f:
-            name = f.read()
-        return name
-    except:
-        pass
-
-def get_file_size(filename: str, root: str = 'rest/static/files'):
-    path = '/'.join([filename,]*2)
-    try:
-        return os.stat(f'{root}/{path}.file').st_sizea
-    except:
-        pass
-
-def get_file_mimetype(name):
-    mimetype = mimetypes.guess_type(name, strict=False)[0] if name else True
-    return mimetype
-
-def validate_file(filename: str, root: str = 'rest/static/files', download=True, mimetype=True) -> HTTPResponse:
-    path = '/'.join([filename,]*2)
-
-    name = get_filename(filename)
-    mimetype = mimetype if mimetype and mimetype is not True else get_file_mimetype(name)
-    
-    ret = static_file(
-        f'{path}.file',
-        root=root,
-        download=name if name and download else download,
-        mimetype='auto' if mimetype is True else mimetype
-    )
-    if isinstance(ret, HTTPError):
-        return abort(404, f"No such `Upload`: {filename}")
-
-    _bytes = blake_file(f'{path}.file', person='upload'.encode('utf-8'), root=root)
-    _b32 = bytes_to_base32(_bytes)
-    if _b32 != filename:
-        return abort(410, f"Uploaded content differs")
-    return ret
-
-
-def validate_parameter(request: LocalRequest, name: str) -> bytes:
-    if name not in request.params:
-        return abort(400, f"Missing parameter: '{name}'")
-
-    # TODO: what is correct overhead for form content?
-    OVERHEAD = 1024
-    content: bytes = request.query.get(name, None)
-    content_length = request.content_length
-    if content_length == -1:
-        return abort(418, f"Content-Length must be specified")
-    if content_length > CLIP_SIZE_LIMIT + OVERHEAD:
-        return abort(418, f"Content-Length can not exceed {CLIP_SIZE_LIMIT*3} bytes")
-
-    # TODO: add test for both query/form param
-    if 'multipart/form-data' in request.content_type:
-        # TODO: what about binary data ?
-        content: bytes = (content or request.params[name].encode('utf-8'))
-    else:
-        content: bytes = (content or request.params[name].encode('latin-1'))
-
-    if len(content) > CLIP_SIZE_LIMIT:
-        return abort(418, f"Paste can not exceed {CLIP_SIZE_LIMIT} bytes")
-    return content
-
-
-def validate_url(url: str) -> str:
-    scheme, netloc, path, params, query, fragment = urlparse(url)
-
-    if not scheme: return abort(400, "URL has no scheme")
-
-    if scheme == 'file' and not path: return abort(400, "File URL has no path")
-
-    if scheme in ('http', 'https') and not netloc: return abort(400, "HTTP(S) URL has no netloc")
-
-    if netloc:
-        try:
-            user_info, loc = netloc.rsplit('@', 1)
-        except ValueError:
-            user_info = ''
-            loc = ''
-        if user_info:
-            user_info = quote(user_info, safe=URL_SAFE)
-            netloc = f"{user_info}@{''.join(loc)}"
-        else:
-            # TODO: do this properly, ie, valid dns-name/ip/port etc
-            netloc = quote(netloc, safe=URL_SAFE)
-    
-    path = quote(path, safe=URL_SAFE)
-    params = quote_plus(params, safe=URL_SAFE)
-    query = quote(query, safe=URL_SAFE)
-    fragment = quote(fragment, safe=URL_SAFE)
-    
-    url = f'{scheme}://{netloc}{path}{params}'
-    if query:
-        url = f'{url}?{query}'
-    if fragment:
-        url = f'{url}#{fragment}'
-    return url

+ 0 - 0
rest/static/shandanone2.png → static/shandanone2.png


Some files were not shown because too many files changed in this diff