mirror of
https://github.com/axllent/mailpit.git
synced 2026-06-28 06:56:06 +00:00
Merge branch 'release/v1.28.2'
This commit is contained in:
13
CHANGELOG.md
13
CHANGELOG.md
@@ -2,6 +2,19 @@
|
||||
|
||||
Notable changes to Mailpit will be documented in this file.
|
||||
|
||||
## [v1.28.2]
|
||||
|
||||
### Security
|
||||
- Prevent Cross-Site WebSocket Hijacking (CSWSH) allowing unauthenticated access to message data [CVE-2026-22689](https://github.com/axllent/mailpit/security/advisories/GHSA-524m-q5m7-79mm)
|
||||
|
||||
### Feature
|
||||
- Allow default mail addresses to be set when releasing message ([#594](https://github.com/axllent/mailpit/issues/594))
|
||||
|
||||
### Chore
|
||||
- Remove webkit warnings about missing template / render functions
|
||||
- Avoid empty URL query parameter when returning to inbox from message view
|
||||
|
||||
|
||||
## [v1.28.1]
|
||||
|
||||
### Security
|
||||
|
||||
@@ -53,5 +53,10 @@ export default {
|
||||
navigator.setAppBadge(this.mailboxUnread);
|
||||
},
|
||||
},
|
||||
|
||||
render() {
|
||||
// to remove webkit warnings about missing template or render function
|
||||
return false;
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -112,5 +112,10 @@ export default {
|
||||
this.favicon.href = canvas.toDataURL("image/png");
|
||||
},
|
||||
},
|
||||
|
||||
render() {
|
||||
// to remove webkit warnings about missing template or render function
|
||||
return false;
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -14,6 +14,9 @@ export default {
|
||||
timezones,
|
||||
chaosConfig: false,
|
||||
chaosUpdated: false,
|
||||
defaultReleaseAddressesOptions: localStorage.getItem("defaultReleaseAddresses")
|
||||
? JSON.parse(localStorage.getItem("defaultReleaseAddresses"))
|
||||
: [], // set with default release addresses
|
||||
};
|
||||
},
|
||||
|
||||
@@ -45,11 +48,13 @@ export default {
|
||||
|
||||
mounted() {
|
||||
this.setTheme();
|
||||
this.$nextTick(() => {
|
||||
Tags.init("select.tz");
|
||||
});
|
||||
|
||||
mailbox.skipConfirmations = !!localStorage.getItem("skip-confirmations");
|
||||
mailbox.skipConfirmations = localStorage.getItem("skip-confirmations");
|
||||
|
||||
window.setTimeout(() => {
|
||||
Tags.init("select.tz");
|
||||
Tags.init("select.default-release-addresses");
|
||||
}, 500);
|
||||
},
|
||||
|
||||
methods: {
|
||||
@@ -98,7 +103,7 @@ export default {
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<ul v-if="mailbox.uiConfig.ChaosEnabled" id="myTab" class="nav nav-tabs" role="tablist">
|
||||
<ul id="myTab" class="nav nav-tabs" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button
|
||||
id="ui-tab"
|
||||
@@ -113,7 +118,25 @@ export default {
|
||||
Web UI
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<li
|
||||
v-if="mailbox.uiConfig.MessageRelay && mailbox.uiConfig.MessageRelay.Enabled"
|
||||
class="nav-item"
|
||||
role="presentation"
|
||||
>
|
||||
<button
|
||||
id="relay-tab"
|
||||
class="nav-link"
|
||||
data-bs-toggle="tab"
|
||||
data-bs-target="#relay-tab-pane"
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-controls="relay-tab-pane"
|
||||
aria-selected="false"
|
||||
>
|
||||
Message release
|
||||
</button>
|
||||
</li>
|
||||
<li v-if="mailbox.uiConfig.ChaosEnabled" class="nav-item" role="presentation">
|
||||
<button
|
||||
id="chaos-tab"
|
||||
class="nav-link"
|
||||
@@ -234,6 +257,50 @@ export default {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Default relay addresses -->
|
||||
<div
|
||||
v-if="mailbox.uiConfig.MessageRelay && mailbox.uiConfig.MessageRelay.Enabled"
|
||||
id="relay-tab-pane"
|
||||
class="tab-pane fade"
|
||||
role="tabpanel"
|
||||
aria-labelledby="relay-tab"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="my-3 mb-5">
|
||||
<label class="form-label">Default release address(es)</label>
|
||||
<div class="form-text mb-2">
|
||||
You can designate the default "send to" addresses here, which will automatically
|
||||
populate the field in the message release dialog. This setting applies only to your
|
||||
browser. If this field is left empty, it will revert to the original recipients of
|
||||
the message.
|
||||
</div>
|
||||
<select
|
||||
v-model="mailbox.defaultReleaseAddresses"
|
||||
class="form-select tag-selector default-release-addresses"
|
||||
multiple
|
||||
data-allow-new="true"
|
||||
data-clear-end="true"
|
||||
data-allow-clear="true"
|
||||
data-placeholder="Enter email addresses..."
|
||||
data-add-on-blur="true"
|
||||
data-badge-style="primary"
|
||||
data-regex='^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|.(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'
|
||||
data-separator="|,|"
|
||||
>
|
||||
<option value="">Enter email addresses...</option>
|
||||
<!-- you need at least one option with the placeholder -->
|
||||
<option
|
||||
v-for="t in defaultReleaseAddressesOptions"
|
||||
:key="'address+' + t"
|
||||
:value="t"
|
||||
>
|
||||
{{ t }}
|
||||
</option>
|
||||
</select>
|
||||
<div class="invalid-feedback">Invalid email address</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="mailbox.uiConfig.ChaosEnabled"
|
||||
id="chaos-tab-pane"
|
||||
|
||||
@@ -44,7 +44,20 @@ export default {
|
||||
// include only unique email addresses, regardless of casing
|
||||
this.allAddresses = JSON.parse(JSON.stringify([...new Map(a.map((ad) => [ad.toLowerCase(), ad])).values()]));
|
||||
|
||||
this.addresses = this.allAddresses;
|
||||
// include default release addresses from mailbox settings
|
||||
const defaultAddr = mailbox.defaultReleaseAddresses;
|
||||
for (const i in defaultAddr) {
|
||||
if (!this.allAddresses.includes(defaultAddr[i])) {
|
||||
this.allAddresses.push(defaultAddr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultAddr.length === 0) {
|
||||
// prefill with all addresses if no default is set
|
||||
this.addresses = this.allAddresses;
|
||||
} else {
|
||||
this.addresses = defaultAddr;
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
@@ -140,6 +153,13 @@ export default {
|
||||
<option v-for="t in allAddresses" :key="'address+' + t" :value="t">{{ t }}</option>
|
||||
</select>
|
||||
<div class="invalid-feedback">Invalid email address</div>
|
||||
<div class="form-text mt-1">
|
||||
Default release addresses can be configured in
|
||||
<a href="#" data-bs-toggle="modal" data-bs-target="#SettingsModal">
|
||||
<i class="bi bi-gear-fill ms-1"></i>
|
||||
Settings </a
|
||||
>.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
|
||||
@@ -20,6 +20,9 @@ export const mailbox = reactive({
|
||||
appInfo: {}, // application information
|
||||
uiConfig: {}, // configuration for UI
|
||||
lastMessage: false, // return scrolling
|
||||
defaultReleaseAddresses: localStorage.getItem("defaultReleaseAddresses")
|
||||
? JSON.parse(localStorage.getItem("defaultReleaseAddresses"))
|
||||
: [], // default release addresses for released messages
|
||||
|
||||
// settings
|
||||
showTagColors: !localStorage.getItem("hideTagColors"),
|
||||
@@ -82,6 +85,17 @@ watch(
|
||||
},
|
||||
);
|
||||
|
||||
watch(
|
||||
() => mailbox.defaultReleaseAddresses,
|
||||
(v) => {
|
||||
if (v.length) {
|
||||
localStorage.setItem("defaultReleaseAddresses", JSON.stringify(v));
|
||||
} else {
|
||||
localStorage.removeItem("defaultReleaseAddresses");
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
watch(
|
||||
() => mailbox.timeZone,
|
||||
(v) => {
|
||||
|
||||
@@ -442,7 +442,11 @@ export default {
|
||||
if (pagination.limit !== pagination.defaultLimit) {
|
||||
p.limit = pagination.limit.toString();
|
||||
}
|
||||
this.$router.push("/?" + new URLSearchParams(p).toString());
|
||||
if (p.start || p.limit) {
|
||||
this.$router.push("/?" + new URLSearchParams(p).toString());
|
||||
} else {
|
||||
this.$router.push("/");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -455,7 +459,6 @@ export default {
|
||||
window.setTimeout(() => {
|
||||
// delay to allow elements to load / focus
|
||||
this.$refs.ReleaseRef.initTags();
|
||||
document.querySelector('#ReleaseModal input[role="combobox"]').focus();
|
||||
}, 500);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -34,8 +34,7 @@ var (
|
||||
var upgrader = websocket.Upgrader{
|
||||
ReadBufferSize: 1024,
|
||||
WriteBufferSize: 1024,
|
||||
CheckOrigin: func(r *http.Request) bool { return true }, // allow multi-domain
|
||||
EnableCompression: true, // experimental compression
|
||||
EnableCompression: true,
|
||||
}
|
||||
|
||||
// Client is a middleman between the websocket connection and the hub.
|
||||
|
||||
Reference in New Issue
Block a user