Merge branch 'master' into crowdin-translation
This commit is contained in:
commit
4db0db320b
10 changed files with 111 additions and 54 deletions
|
@ -3,8 +3,13 @@
|
|||
## 1.6.3 (not yet released)
|
||||
* ADDED: Translations for Romanian
|
||||
* ADDED: Detect and report on damaged pastes (#1218)
|
||||
* CHANGED: Upgrading libraries to: zlib 1.3
|
||||
* CHANGED: Ask for confirmation, before loading burn after reading pastes #1237
|
||||
* CHANGED: Focus on password input in modal dialog
|
||||
* CHANGED: Upgrading libraries to: DOMpurify 3.0.8 & zlib 1.3.1
|
||||
* FIXED: Support more types of valid URLs for shorteners, incl. IDN ones (#1224)
|
||||
* FIXED: Email timezone buttons overlapping in some languages #1039
|
||||
* FIXED: Changing language mangles URL #1191
|
||||
* FIXED: Needless reload when visiting default URL
|
||||
|
||||
## 1.6.2 (2023-12-15)
|
||||
* FIXED: English not selectable when `languageselection` enabled (#1208)
|
||||
|
|
|
@ -214,5 +214,7 @@
|
|||
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response."
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
|
@ -12,12 +12,12 @@ global.WebCrypto = require('@peculiar/webcrypto').Crypto;
|
|||
// application libraries to test
|
||||
global.$ = global.jQuery = require('./jquery-3.7.0');
|
||||
global.RawDeflate = require('./rawinflate-0.3').RawDeflate;
|
||||
global.zlib = require('./zlib-1.3').zlib;
|
||||
global.zlib = require('./zlib-1.3.1').zlib;
|
||||
require('./prettify');
|
||||
global.prettyPrint = window.PR.prettyPrint;
|
||||
global.prettyPrintOne = window.PR.prettyPrintOne;
|
||||
global.showdown = require('./showdown-2.1.0');
|
||||
global.DOMPurify = require('./purify-3.0.6');
|
||||
global.DOMPurify = require('./purify-3.0.8');
|
||||
global.baseX = require('./base-x-4.0.0').baseX;
|
||||
global.Legacy = require('./legacy').Legacy;
|
||||
require('./bootstrap-3.4.1');
|
||||
|
|
|
@ -77,6 +77,13 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* URL fragment prefix requiring load confirmation
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
const loadConfirmPrefix = '#-';
|
||||
|
||||
/**
|
||||
* CryptoData class
|
||||
*
|
||||
|
@ -228,7 +235,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
'\'': ''',
|
||||
'/': '/',
|
||||
'`': '`',
|
||||
'=': '='
|
||||
|
@ -1514,10 +1521,11 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
me.getPasteKey = function()
|
||||
{
|
||||
if (symmetricKey === null) {
|
||||
let newKey = window.location.hash.substring(1);
|
||||
if (newKey === '') {
|
||||
throw 'no encryption key given';
|
||||
let startPos = 1;
|
||||
if(window.location.hash.startsWith(loadConfirmPrefix)) {
|
||||
startPos = loadConfirmPrefix.length;
|
||||
}
|
||||
let newKey = window.location.hash.substring(startPos);
|
||||
|
||||
// Some web 2.0 services and redirectors add data AFTER the anchor
|
||||
// (such as &utm_source=...). We will strip any additional data.
|
||||
|
@ -1526,6 +1534,9 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
{
|
||||
newKey = newKey.substring(0, ampersandPos);
|
||||
}
|
||||
if (newKey === '') {
|
||||
throw 'no encryption key given';
|
||||
}
|
||||
|
||||
// version 2 uses base58, version 1 uses base64 without decoding
|
||||
try {
|
||||
|
@ -2252,6 +2263,34 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
PasteDecrypter.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Request users confirmation to load possibly burn after reading paste
|
||||
*
|
||||
* @name Prompt.requestLoadConfirmation
|
||||
* @function
|
||||
*/
|
||||
me.requestLoadConfirmation = function()
|
||||
{
|
||||
const $loadconfirmmodal = $('#loadconfirmmodal');
|
||||
if ($loadconfirmmodal.length > 0) {
|
||||
const $loadconfirmOpenNow = $loadconfirmmodal.find('#loadconfirm-open-now');
|
||||
$loadconfirmOpenNow.off('click.loadPaste');
|
||||
$loadconfirmOpenNow.on('click.loadPaste', PasteDecrypter.run);
|
||||
const $loadconfirmClose = $loadconfirmmodal.find('.close');
|
||||
$loadconfirmClose.off('click.close');
|
||||
$loadconfirmClose.on('click.close', Controller.newPaste);
|
||||
$loadconfirmmodal.modal('show');
|
||||
} else {
|
||||
if (window.confirm(
|
||||
I18n._('Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?')
|
||||
)) {
|
||||
PasteDecrypter.run();
|
||||
} else {
|
||||
Controller.newPaste();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ask the user for the password and set it
|
||||
*
|
||||
|
@ -2266,6 +2305,12 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
backdrop: 'static',
|
||||
keyboard: false
|
||||
});
|
||||
// focus password input
|
||||
$passwordDecrypt.focus();
|
||||
// then re-focus it, when modal causes it to loose focus again
|
||||
setTimeout(function () {
|
||||
$passwordDecrypt.focus();
|
||||
}, 500);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2325,13 +2370,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
$passwordForm = $('#passwordform');
|
||||
$passwordModal = $('#passwordmodal');
|
||||
|
||||
// bind events
|
||||
|
||||
// focus password input when it is shown
|
||||
$passwordModal.on('shown.bs.Model', function () {
|
||||
$passwordDecrypt.focus();
|
||||
});
|
||||
// handle Model password submission
|
||||
// bind events - handle Model password submission
|
||||
$passwordForm.submit(submitPasswordModal);
|
||||
};
|
||||
|
||||
|
@ -3565,7 +3604,6 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
if (fadeOut === true) {
|
||||
setTimeout(function () {
|
||||
$comment.removeClass('highlight');
|
||||
|
||||
}, 300);
|
||||
}
|
||||
};
|
||||
|
@ -3813,6 +3851,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
{
|
||||
document.cookie = 'lang=' + $(event.target).data('lang') + ';secure';
|
||||
UiHelper.reloadHome();
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3968,10 +4007,6 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
const $emailconfirmmodal = $('#emailconfirmmodal');
|
||||
if ($emailconfirmmodal.length > 0) {
|
||||
if (expirationDate !== null) {
|
||||
I18n._(
|
||||
$emailconfirmmodal.find('#emailconfirm-display'),
|
||||
'Recipient may become aware of your timezone, convert time to UTC?'
|
||||
);
|
||||
const $emailconfirmTimezoneCurrent = $emailconfirmmodal.find('#emailconfirm-timezone-current');
|
||||
const $emailconfirmTimezoneUtc = $emailconfirmmodal.find('#emailconfirm-timezone-utc');
|
||||
$emailconfirmTimezoneCurrent.off('click.sendEmailCurrentTimezone');
|
||||
|
@ -4826,7 +4861,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
|
||||
// show notification
|
||||
const baseUri = Helper.baseUri() + '?',
|
||||
url = baseUri + data.id + '#' + CryptTool.base58encode(data.encryptionKey),
|
||||
url = baseUri + data.id + (TopNav.getBurnAfterReading() ? loadConfirmPrefix : '#') + CryptTool.base58encode(data.encryptionKey),
|
||||
deleteUrl = baseUri + 'pasteid=' + data.id + '&deletetoken=' + data.deletetoken;
|
||||
PasteStatus.createPasteNotification(url, deleteUrl);
|
||||
|
||||
|
@ -5245,7 +5280,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
Alert.hideMessages();
|
||||
Alert.showLoading('Decrypting paste…', 'cloud-download');
|
||||
|
||||
if (typeof paste === 'undefined') {
|
||||
if (typeof paste === 'undefined' || paste.type === 'click') {
|
||||
// get cipher data and wait until it is available
|
||||
Model.getPasteData(me.run);
|
||||
return;
|
||||
|
@ -5352,7 +5387,10 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
AttachmentViewer.removeAttachmentData();
|
||||
|
||||
Alert.hideLoading();
|
||||
history.pushState({type: 'create'}, document.title, Helper.baseUri());
|
||||
// only push new state if we are coming from a different one
|
||||
if (Helper.baseUri() != window.location) {
|
||||
history.pushState({type: 'create'}, document.title, Helper.baseUri());
|
||||
}
|
||||
|
||||
// clear discussion
|
||||
DiscussionViewer.prepareNewDiscussion();
|
||||
|
@ -5378,6 +5416,12 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
}
|
||||
}
|
||||
|
||||
// check if we should request loading confirmation
|
||||
if(window.location.hash.startsWith(loadConfirmPrefix)) {
|
||||
Prompt.requestLoadConfirmation();
|
||||
return;
|
||||
}
|
||||
|
||||
// show proper elements on screen
|
||||
PasteDecrypter.run();
|
||||
};
|
||||
|
|
File diff suppressed because one or more lines are too long
2
js/purify-3.0.8.js
Normal file
2
js/purify-3.0.8.js
Normal file
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -55,7 +55,7 @@ if ($ZEROBINCOMPATIBILITY) :
|
|||
<?php
|
||||
endif;
|
||||
?>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/zlib-1.3.js" integrity="sha512-VL3lLnt8EexTr22ze4a4HfVghpgY48c/Lhf4CcQa8bgYaIRRPjV1nP7EA8RiciGoXXQ1IeiU7tjrclPeVEfxOQ==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/zlib-1.3.1.js" integrity="sha512-VL3lLnt8EexTr22ze4a4HfVghpgY48c/Lhf4CcQa8bgYaIRRPjV1nP7EA8RiciGoXXQ1IeiU7tjrclPeVEfxOQ==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/base-x-4.0.0.js" integrity="sha512-nNPg5IGCwwrveZ8cA/yMGr5HiRS5Ps2H+s0J/mKTPjCPWUgFGGw7M5nqdnPD3VsRwCVysUh3Y8OWjeSKGkEQJQ==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/rawinflate-0.3.js" integrity="sha512-g8uelGgJW9A/Z1tB6Izxab++oj5kdD7B4qC7DHwZkB6DGMXKyzx7v5mvap2HXueI2IIn08YlRYM56jwWdm2ucQ==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/bootstrap-3.4.1.js" integrity="sha512-oBTprMeNEKCnqfuqKd6sbvFzmFQtlXS3e0C/RGFV0hD6QzhHV+ODfaQbAlmY6/q0ubbwlAM/nCJjkrgA3waLzg==" crossorigin="anonymous"></script>
|
||||
|
@ -71,9 +71,9 @@ if ($MARKDOWN) :
|
|||
<?php
|
||||
endif;
|
||||
?>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/purify-3.0.6.js" integrity="sha512-N3y6/HOk3pbsw3lFh4O8CKKEVwu1B2CF8kinhjURf8Yqa5OfSUt+/arozxFW+TUPOPw3TsDCRT/0u7BGRTEVUw==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/purify-3.0.8.js" integrity="sha512-wWBDKh5wYGtJ1Df+PPZIn59jHVBnJ4/Yb2W/pVnzaXab8cmlZnHVx+FEBGu5JX39s3P2Qlt+aNQou0XnjW86hg==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/legacy.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-LYos+qXHIRqFf5ZPNphvtTB0cgzHUizu2wwcOwcwz/VIpRv9lpcBgPYz4uq6jx0INwCAj6Fbnl5HoKiLufS2jg==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-cfRk8a/8RpvMb4g9Su9kcKNcs7+PyGioUxH6z6k9e4vcdZmtz+gM2HwIP/Gd/1r6h3qoxrkO4jodn2E7gtZ7EA==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-FPqSHNhZoXQX1vV5+Sd9vn/indcihNkt0KLmpRpDfXRMM9tTWxokUpbsD07GGpYibfG4mPbCwFy13c2VLvagIg==" crossorigin="anonymous"></script>
|
||||
<!-- icon -->
|
||||
<link rel="apple-touch-icon" href="<?php echo I18n::encode($BASEPATH); ?>img/apple-touch-icon.png" sizes="180x180" />
|
||||
<link rel="icon" type="image/png" href="img/favicon-32x32.png" sizes="32x32" />
|
||||
|
@ -123,22 +123,32 @@ if (count($class)) {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="loadconfirmmodal" tabindex="-1" class="modal fade" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="<?php echo I18n::_('Close') ?>"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title"><?php echo I18n::_('Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?') ?></h4>
|
||||
</div>
|
||||
<div class="modal-body text-center">
|
||||
<button id="loadconfirm-open-now" type="button" class="btn btn-success" data-dismiss="modal"><span class="glyphicon glyphicon-download"></span> <?php echo I18n::_('Yes, load it') ?></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
if ($QRCODE) :
|
||||
?>
|
||||
<div id="qrcodemodal" tabindex="-1" class="modal fade" aria-labelledby="qrcodemodalTitle" role="dialog" aria-hidden="true">
|
||||
<div id="qrcodemodal" tabindex="-1" class="modal fade" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="<?php echo I18n::_('Close') ?>"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title"><?php echo I18n::_('QR code') ?></h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mx-auto" id="qrcode-display"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="btn-group col-xs-12">
|
||||
<span class="col-xs-12">
|
||||
<button type="button" class="btn btn-primary btn-block" data-dismiss="modal"><?php echo I18n::_('Close') ?></button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -146,23 +156,19 @@ if ($QRCODE) :
|
|||
endif;
|
||||
if ($EMAIL) :
|
||||
?>
|
||||
<div id="emailconfirmmodal" tabindex="-1" class="modal fade" aria-labelledby="emailconfirmmodalTitle" role="dialog" aria-hidden="true">
|
||||
<div id="emailconfirmmodal" tabindex="-1" class="modal fade" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-body">
|
||||
<div id="emailconfirm-display"></div>
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="<?php echo I18n::_('Close') ?>"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title"><?php echo I18n::_('Recipient may become aware of your timezone, convert time to UTC?') ?></h4>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="btn-group col-xs-12" data-toggle="buttons">
|
||||
<span class="col-xs-12 col-md-4">
|
||||
<button id="emailconfirm-timezone-current" type="button" class="btn btn-danger btn-block" data-dismiss="modal"><?php echo I18n::_('Use Current Timezone') ?></button>
|
||||
</span>
|
||||
<span class="col-xs-12 col-md-4">
|
||||
<button id="emailconfirm-timezone-utc" type="button" class="btn btn-default btn-block" data-dismiss="modal"><?php echo I18n::_('Convert To UTC') ?></button>
|
||||
</span>
|
||||
<span class="col-xs-12 col-md-4">
|
||||
<button type="button" class="btn btn-primary btn-block" data-dismiss="modal"><?php echo I18n::_('Close') ?></button>
|
||||
</span>
|
||||
<div class="modal-body row">
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<button id="emailconfirm-timezone-current" type="button" class="btn btn-danger"><span class="glyphicon glyphicon-time"></span> <?php echo I18n::_('Use Current Timezone') ?></button>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-6 text-right">
|
||||
<button id="emailconfirm-timezone-utc" type="button" class="btn btn-success"><span class="glyphicon glyphicon-globe"></span> <?php echo I18n::_('Convert To UTC') ?></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -34,7 +34,7 @@ if ($ZEROBINCOMPATIBILITY):
|
|||
<?php
|
||||
endif;
|
||||
?>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/zlib-1.3.js" integrity="sha512-VL3lLnt8EexTr22ze4a4HfVghpgY48c/Lhf4CcQa8bgYaIRRPjV1nP7EA8RiciGoXXQ1IeiU7tjrclPeVEfxOQ==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/zlib-1.3.1.js" integrity="sha512-VL3lLnt8EexTr22ze4a4HfVghpgY48c/Lhf4CcQa8bgYaIRRPjV1nP7EA8RiciGoXXQ1IeiU7tjrclPeVEfxOQ==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/base-x-4.0.0.js" integrity="sha512-nNPg5IGCwwrveZ8cA/yMGr5HiRS5Ps2H+s0J/mKTPjCPWUgFGGw7M5nqdnPD3VsRwCVysUh3Y8OWjeSKGkEQJQ==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/rawinflate-0.3.js" integrity="sha512-g8uelGgJW9A/Z1tB6Izxab++oj5kdD7B4qC7DHwZkB6DGMXKyzx7v5mvap2HXueI2IIn08YlRYM56jwWdm2ucQ==" crossorigin="anonymous"></script>
|
||||
<?php
|
||||
|
@ -49,9 +49,9 @@ if ($MARKDOWN):
|
|||
<?php
|
||||
endif;
|
||||
?>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/purify-3.0.6.js" integrity="sha512-N3y6/HOk3pbsw3lFh4O8CKKEVwu1B2CF8kinhjURf8Yqa5OfSUt+/arozxFW+TUPOPw3TsDCRT/0u7BGRTEVUw==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/purify-3.0.8.js" integrity="sha512-wWBDKh5wYGtJ1Df+PPZIn59jHVBnJ4/Yb2W/pVnzaXab8cmlZnHVx+FEBGu5JX39s3P2Qlt+aNQou0XnjW86hg==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/legacy.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-LYos+qXHIRqFf5ZPNphvtTB0cgzHUizu2wwcOwcwz/VIpRv9lpcBgPYz4uq6jx0INwCAj6Fbnl5HoKiLufS2jg==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-cfRk8a/8RpvMb4g9Su9kcKNcs7+PyGioUxH6z6k9e4vcdZmtz+gM2HwIP/Gd/1r6h3qoxrkO4jodn2E7gtZ7EA==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-FPqSHNhZoXQX1vV5+Sd9vn/indcihNkt0KLmpRpDfXRMM9tTWxokUpbsD07GGpYibfG4mPbCwFy13c2VLvagIg==" crossorigin="anonymous"></script>
|
||||
<!-- icon -->
|
||||
<link rel="apple-touch-icon" href="img/apple-touch-icon.png?<?php echo rawurlencode($VERSION); ?>" sizes="180x180" />
|
||||
<link rel="icon" type="image/png" href="img/favicon-32x32.png?<?php echo rawurlencode($VERSION); ?>" sizes="32x32" />
|
||||
|
|
Loading…
Reference in a new issue