Remove 'Never' expiry (1-year max) and fix Raw blob URL issue
This commit is contained in:
parent
d0289f85d5
commit
a46cba7143
20
app.py
20
app.py
|
|
@ -261,10 +261,11 @@ def create_paste():
|
|||
else:
|
||||
return jsonify({'error': 'Provide either encrypted_data or content'}), 400
|
||||
|
||||
allowed_expiry = set(_pastes.get('allow_expiry_options', ['never']))
|
||||
expires_in = data.get('expires_in', 'never')
|
||||
allowed_expiry = set(_pastes.get('allow_expiry_options', ['1year']))
|
||||
expires_in = data.get('expires_in', _pastes.get('default_expiry', '1year'))
|
||||
if expires_in not in allowed_expiry:
|
||||
expires_in = 'never'
|
||||
# Fallback to the first allowed option if everything is missing
|
||||
expires_in = _pastes.get('default_expiry', list(allowed_expiry)[0])
|
||||
|
||||
expires_at = None
|
||||
if expires_in != 'never':
|
||||
|
|
@ -273,6 +274,7 @@ def create_paste():
|
|||
'1day': datetime.timedelta(days=1),
|
||||
'1week': datetime.timedelta(weeks=1),
|
||||
'1month': datetime.timedelta(days=30),
|
||||
'1year': datetime.timedelta(days=365),
|
||||
}
|
||||
delta = delta_map.get(expires_in)
|
||||
if delta is None:
|
||||
|
|
@ -322,15 +324,21 @@ def view_paste_raw(paste_id):
|
|||
paste = _get_paste_or_abort(paste_id)
|
||||
stored = paste['encrypted_data']
|
||||
|
||||
# Plaintext pastes are stored as a JSON object; return the content directly.
|
||||
# 1. Plaintext paste — Return content directly as text/plain
|
||||
if not re.match(r'^[A-Za-z0-9_-]+:[A-Za-z0-9_-]+$', stored):
|
||||
try:
|
||||
data = json.loads(stored)
|
||||
return Response(data.get('content', ''), mimetype='text/plain')
|
||||
return Response(data.get('content', ''), mimetype='text/plain; charset=utf-8')
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
pass
|
||||
|
||||
# Encrypted paste — return the raw ciphertext blob for API consumers.
|
||||
# 2. Encrypted paste — Browsers get a minimal decryptor; API consumers get JSON
|
||||
accept = request.headers.get('Accept', '')
|
||||
if 'text/html' in accept:
|
||||
# Minimal HTML shell that handles decryption for browsers (E2E)
|
||||
return render_template('raw_decryptor.html', paste=paste)
|
||||
|
||||
# API response
|
||||
return jsonify({
|
||||
'id': paste['id'],
|
||||
'encrypted_data': stored,
|
||||
|
|
|
|||
|
|
@ -25,14 +25,14 @@
|
|||
"id_length": 8,
|
||||
"recent_limit": 50,
|
||||
"default_language": "text",
|
||||
"default_expiry": "never",
|
||||
"allow_expiry_options": ["never", "1hour", "1day", "1week", "1month"],
|
||||
"default_expiry": "1year",
|
||||
"allow_expiry_options": ["1hour", "1day", "1week", "1month", "1year"],
|
||||
"expiry_labels": {
|
||||
"never": "Never",
|
||||
"1hour": "1 Hour",
|
||||
"1day": "1 Day",
|
||||
"1week": "1 Week",
|
||||
"1month": "1 Month"
|
||||
"1month": "1 Month",
|
||||
"1year": "1 Year"
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -137,15 +137,9 @@ function showError(title, detail) {
|
|||
}
|
||||
|
||||
function rawView() {
|
||||
if (!_decryptedPaste) return;
|
||||
const blob = new Blob([_decryptedPaste.content], { type: 'text/plain; charset=utf-8' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = Object.assign(document.createElement('a'),
|
||||
{ href: url, target: '_blank', rel: 'noopener noreferrer' });
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
setTimeout(() => URL.revokeObjectURL(url), 10000);
|
||||
const key = window.location.hash;
|
||||
const url = window.location.href.split('?')[0].split('#')[0] + '/raw' + key;
|
||||
window.open(url, '_blank');
|
||||
}
|
||||
|
||||
async function copyPaste() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Raw | {{ cfg.site.name }}</title>
|
||||
<style>
|
||||
body { margin: 0; padding: 1rem; background: #fff; color: #000; font-family: monospace; }
|
||||
pre { white-space: pre-wrap; word-wrap: break-word; margin: 0; }
|
||||
#error { display: none; color: red; font-weight: bold; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="rawContent"></pre>
|
||||
<div id="error">Decryption Failed — Key missing or incorrect.</div>
|
||||
|
||||
<script src="{{ url_for('static', filename='js/crypto.js') }}" nonce="{{ csp_nonce }}"></script>
|
||||
<script nonce="{{ csp_nonce }}">
|
||||
(async function decryptRaw() {
|
||||
const raw = {{ paste.encrypted_data | tojson }};
|
||||
const keyBase64 = window.location.hash.slice(1);
|
||||
const pre = document.getElementById('rawContent');
|
||||
const error = document.getElementById('error');
|
||||
|
||||
if (!keyBase64) { error.style.display = 'block'; return; }
|
||||
|
||||
try {
|
||||
const key = await PasteCrypto.importKey(keyBase64);
|
||||
const plaintext = await PasteCrypto.decrypt(raw, key);
|
||||
const data = JSON.parse(plaintext);
|
||||
pre.textContent = data.content;
|
||||
} catch (e) {
|
||||
error.style.display = 'block';
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue