123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- from io import BytesIO
- from bottle import (
- route, request, response,
- redirect, abort,
- template, static_file,
- HTTPResponse, HTTPError,
- )
- from linkpreview import link_preview
- from .validate import CLIP_SIZE_LIMIT, get_file_mimetype, get_file_size, get_filename, validate, validate_file, validate_parameter, validate_url
- from .hash_util import normalize_base32
- from .save import save, save_upload
- SCHEME = "https://"
- HOST = ""
- DOMAIN = "shandan.one"
- PORT = ""
- LOCATION = SCHEME + (f"{HOST}." if HOST else "") + DOMAIN + (f":{PORT}" if PORT else "")
- @route('/clip', method=['GET', 'POST'])
- def clip():
- if request.method == 'GET':
- _hash = request.params.hash
- if _hash:
- _hash = normalize_base32(_hash)
- content = validate(_hash).decode('utf-8')
- else:
- content = None
- link = f'{LOCATION}/clip/{_hash}' if content else f'{LOCATION}/clip'
- response.content_type = 'text/html; charset=utf-8'
- form = template(
- 'clip-form',
- action='/clip',
- method='post',
- content=content,
- disabled=True if content else False
- )
- return template(
- 'paste',
- form=form,
- qr=f'{LOCATION}/clip/{_hash}.qr' if content else f'{LOCATION}/grocery/static/clip-qr.svg',
- link=link,
- disabled=True if content else False,
- download=f'/clip/{_hash}' if content else None
- )
- if request.method == 'POST':
- content = validate_parameter(request, 'paste')
- if request.params.copy != 'true':
- _b32 = save(content, LOCATION)
- return redirect(f'/clip?hash={_b32}')
- response.content_type = 'text/html; charset=utf-8'
- form = template(
- 'clip-form',
- action='/clip',
- method='post',
- content=content,
- disabled=False
- )
- link = f'{LOCATION}/clip'
- return template(
- 'paste',
- form=form,
- qr=f'{LOCATION}/grocery/static/clip-qr.svg',
- link=link,
- disabled=False,
- download=None
- )
- @route('/clip/<filename:path>', method='GET')
- def get_clip(filename):
- ext = 'file'
- if filename and filename.endswith('.qr'):
- filename, ext = filename.split('.', 1)
-
- filename = filename and normalize_base32(filename)
- path = f'{filename}/{filename}.{ext}'
-
- if ext == 'qr':
- return static_file(path, root='rest/static', mimetype='image/svg+xml')
-
- filename = filename and normalize_base32(filename)
- if not request.params.raw.lower() == 'true':
-
- return redirect(f'/clip?hash={filename}')
- ret = validate(filename)
- if isinstance(ret, HTTPError):
- return ret
- return static_file(path, root='rest/static')
- @route('/upload', method=['GET', 'POST'])
- def upload():
- if request.method == 'GET':
- _hash = request.params.hash
- mimetype = None
- if _hash:
- _hash = normalize_base32(_hash)
- size = get_file_size(_hash)
- name = get_filename(_hash)
- mimetype = get_file_mimetype(name)
- if mimetype is not True and mimetype.startswith('text'):
- mimetype = None if size > CLIP_SIZE_LIMIT else mimetype
-
- link = f'{LOCATION}/upload/{_hash}' if _hash else f'{LOCATION}/upload'
- response.content_type = 'text/html; charset=utf-8'
- disabled = True if _hash else False
- form = template('file-form', action='/upload', method='post', disabled=disabled)
-
- return template(
- 'upload',
- form=form,
- qr=f'{LOCATION}/upload/{_hash}.qr' if _hash else f'{LOCATION}/grocery/static/upload-qr.svg',
- link=link,
- mimetype=mimetype,
- disabled=disabled
- )
- if request.method == 'POST':
- if 'paste' not in request.files:
- return abort(400, "Parameter 'paste' must be specified")
- upload = request.files['paste']
- if isinstance(upload.file, BytesIO):
- if len(upload.file.read()) == 0:
- return abort(400, "File is empty")
- _b32 = save_upload(upload.raw_filename, LOCATION, upload.file, root='rest/static')
- return redirect(f'/upload?hash={_b32}')
- @route('/upload/<filename:path>', method='GET')
- def get_upload(filename):
- ext = 'file'
- if filename and filename.endswith('.qr'):
- filename, ext = filename.split('.', 1)
-
- filename = filename and normalize_base32(filename)
- path = f'{filename}/{filename}.{ext}'
-
- if ext == 'qr':
- return static_file(path, root='rest/static', mimetype='image/svg+xml')
-
- download = True
- mimetype = True
- if request.params.download == "false":
- download = False
- mimetype = request.params.mimetype or None
- return validate_file(filename, download=download, mimetype=mimetype)
- @route('/goto', method=['GET', 'POST'])
- def goto():
- if request.method == 'GET':
- _hash = request.params.hash
- if _hash:
- _hash = normalize_base32(_hash)
- content = validate(_hash).decode('utf-8')
- else:
- content = None
- if content and request.params.go == 'true':
- target = validate_url(content)
- return redirect(target)
- link = f'{LOCATION}/goto/{_hash}' if content else f'{LOCATION}/goto'
- disabled = True if content else False
- response.content_type = 'text/html; charset=utf-8'
- form = template(
- 'goto-form',
- action='/goto',
- method='post',
- content=content,
- disabled=disabled
- )
- preview = dict()
- if content:
- try:
- page = link_preview(link, parser="lxml")
- preview['title'] = page.title
- preview['img'] = page.absolute_image
- preview['domain'] = page.site_name
- preview['link'] = content
- except:
- pass
- return template(
- 'goto',
- form=form,
- qr=f'{LOCATION}/goto/{_hash}.qr' if content else f'{LOCATION}/grocery/static/goto-qr.svg',
- link=link,
- disabled=disabled,
- preview=preview,
- )
- if request.method == 'POST':
- content = validate_parameter(request, 'url')
- _b32 = save(content, LOCATION)
-
- _ = validate_url(content.decode('utf-8'))
- return redirect(f'/goto?hash={_b32}')
- @route('/goto/<filename:path>', method='GET')
- def redirect_goto(filename):
- ext = 'file'
- if filename and filename.endswith('.qr'):
- filename, ext = filename.split('.', 1)
-
- filename = filename and normalize_base32(filename)
- path = f'{filename}/{filename}.{ext}'
-
- if ext == 'qr':
- return static_file(path, root='rest/static', mimetype='image/svg+xml')
-
- return redirect(f'/goto?hash={filename}&go=true')
- @route('/<any>/', method='GET')
- def redirect_trailing_slash(any): return redirect(f'/{any}')
|