Merge pull request #1229 from BlackDex/email-fixes

Email fixes
This commit is contained in:
Daniel García 2020-11-18 16:16:27 +01:00 committed by GitHub
commit 5379329ef7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 242 additions and 153 deletions

View File

@ -242,9 +242,9 @@
# SMTP_HOST=smtp.domain.tld # SMTP_HOST=smtp.domain.tld
# SMTP_FROM=bitwarden-rs@domain.tld # SMTP_FROM=bitwarden-rs@domain.tld
# SMTP_FROM_NAME=Bitwarden_RS # SMTP_FROM_NAME=Bitwarden_RS
# SMTP_PORT=587 # SMTP_PORT=587 # Ports 587 (submission) and 25 (smtp) are standard without encryption and with encryption via STARTTLS (Explicit TLS). Port 465 is outdated and used with Implicit TLS.
# SMTP_SSL=true # (Explicit) - This variable by default configures Explicit STARTTLS, it will upgrade an insecure connection to a secure one. Unless SMTP_EXPLICIT_TLS is set to true. # SMTP_SSL=true # (Explicit) - This variable by default configures Explicit STARTTLS, it will upgrade an insecure connection to a secure one. Unless SMTP_EXPLICIT_TLS is set to true. Either port 587 or 25 are default.
# SMTP_EXPLICIT_TLS=true # (Implicit) - N.B. This variable configures Implicit TLS. It's currently mislabelled (see bug #851) - SMTP_SSL Needs to be set to true for this option to work. # SMTP_EXPLICIT_TLS=true # (Implicit) - N.B. This variable configures Implicit TLS. It's currently mislabelled (see bug #851) - SMTP_SSL Needs to be set to true for this option to work. Usually port 465 is used here.
# SMTP_USERNAME=username # SMTP_USERNAME=username
# SMTP_PASSWORD=password # SMTP_PASSWORD=password
# SMTP_TIMEOUT=15 # SMTP_TIMEOUT=15
@ -259,6 +259,22 @@
## but might need to be changed in case it trips some anti-spam filters ## but might need to be changed in case it trips some anti-spam filters
# HELO_NAME= # HELO_NAME=
## SMTP debugging
## When set to true this will output very detailed SMTP messages.
## WARNING: This could contain sensitive information like passwords and usernames! Only enable this during troubleshooting!
# SMTP_DEBUG=false
## Accept Invalid Hostnames
## DANGEROUS: This option introduces significant vulnerabilities to man-in-the-middle attacks!
## Only use this as a last resort if you are not able to use a valid certificate.
# SMTP_ACCEPT_INVALID_HOSTNAMES=false
## Accept Invalid Certificates
## DANGEROUS: This option introduces significant vulnerabilities to man-in-the-middle attacks!
## Only use this as a last resort if you are not able to use a valid certificate.
## If the Certificate is valid but the hostname doesn't match, please use SMTP_ACCEPT_INVALID_HOSTNAMES instead.
# SMTP_ACCEPT_INVALID_CERTS=false
## Require new device emails. When a user logs in an email is required to be sent. ## Require new device emails. When a user logs in an email is required to be sent.
## If sending the email fails the login attempt will fail!! ## If sending the email fails the login attempt will fail!!
# REQUIRE_DEVICE_EMAIL=false # REQUIRE_DEVICE_EMAIL=false

72
Cargo.lock generated
View File

@ -33,12 +33,6 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "arrayvec"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]] [[package]]
name = "atty" name = "atty"
version = "0.2.14" version = "0.2.14"
@ -131,6 +125,18 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "bitvec"
version = "0.19.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7ba35e9565969edb811639dbebfe34edc0368e472c5018474c8eb2543397f81"
dependencies = [
"funty",
"radium",
"tap",
"wyz",
]
[[package]] [[package]]
name = "bitwarden_rs" name = "bitwarden_rs"
version = "1.0.0" version = "1.0.0"
@ -638,6 +644,12 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
[[package]]
name = "funty"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ba62103ce691c2fd80fbae2213dfdda9ce60804973ac6b6e97de818ea7f52c8"
[[package]] [[package]]
name = "futf" name = "futf"
version = "0.1.4" version = "0.1.4"
@ -1144,9 +1156,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]] [[package]]
name = "lettre" name = "lettre"
version = "0.10.0-alpha.3" version = "0.10.0-alpha.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e422b6c03563bc47db09bb61a8ece4f1462de131455beb96c091e2998fa316a2" checksum = "dc8c2fc7873920aca23647e5e86d44ff3f40bbc5a5efaab445c9eb0e001c9f71"
dependencies = [ dependencies = [
"base64 0.13.0", "base64 0.13.0",
"hostname", "hostname",
@ -1160,22 +1172,10 @@ dependencies = [
"rand 0.7.3", "rand 0.7.3",
"regex", "regex",
"serde", "serde",
"tracing",
"uuid", "uuid",
] ]
[[package]]
name = "lexical-core"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db65c6da02e61f55dae90a0ae427b2a5f6b3e8db09f58d10efab23af92592616"
dependencies = [
"arrayvec",
"bitflags",
"cfg-if 0.1.10",
"ryu",
"static_assertions",
]
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.80" version = "0.2.80"
@ -1448,11 +1448,11 @@ checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
[[package]] [[package]]
name = "nom" name = "nom"
version = "5.1.2" version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" checksum = "4489ccc7d668957ddf64af7cd027c081728903afa6479d35da7e99bf5728f75f"
dependencies = [ dependencies = [
"lexical-core", "bitvec",
"memchr", "memchr",
"version_check 0.9.2", "version_check 0.9.2",
] ]
@ -1978,6 +1978,12 @@ dependencies = [
"scheduled-thread-pool", "scheduled-thread-pool",
] ]
[[package]]
name = "radium"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8"
[[package]] [[package]]
name = "rand" name = "rand"
version = "0.4.6" version = "0.4.6"
@ -2617,12 +2623,6 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3015a7d0a5fd5105c91c3710d42f9ccf0abfb287d62206484dcc67f9569a6483" checksum = "3015a7d0a5fd5105c91c3710d42f9ccf0abfb287d62206484dcc67f9569a6483"
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]] [[package]]
name = "stdweb" name = "stdweb"
version = "0.4.20" version = "0.4.20"
@ -2782,6 +2782,12 @@ dependencies = [
"time 0.1.44", "time 0.1.44",
] ]
[[package]]
name = "tap"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36474e732d1affd3a6ed582781b3683df3d0563714c59c39591e8ff707cf078e"
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.1.0" version = "3.1.0"
@ -3371,6 +3377,12 @@ dependencies = [
"winapi-build", "winapi-build",
] ]
[[package]]
name = "wyz"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
[[package]] [[package]]
name = "yansi" name = "yansi"
version = "0.5.0" version = "0.5.0"

View File

@ -100,7 +100,7 @@ num-traits = "0.2.14"
num-derive = "0.3.3" num-derive = "0.3.3"
# Email libraries # Email libraries
lettre = { version = "0.10.0-alpha.3", features = ["smtp-transport", "builder", "serde", "native-tls", "hostname"], default-features = false } lettre = { version = "0.10.0-alpha.4", features = ["smtp-transport", "builder", "serde", "native-tls", "hostname", "tracing"], default-features = false }
newline-converter = "0.1.0" newline-converter = "0.1.0"
# Template library # Template library

View File

@ -436,6 +436,12 @@ make_config! {
smtp_timeout: u64, true, def, 15; smtp_timeout: u64, true, def, 15;
/// Server name sent during HELO |> By default this value should be is on the machine's hostname, but might need to be changed in case it trips some anti-spam filters /// Server name sent during HELO |> By default this value should be is on the machine's hostname, but might need to be changed in case it trips some anti-spam filters
helo_name: String, true, option; helo_name: String, true, option;
/// Enable SMTP debugging (Know the risks!) |> DANGEROUS: Enabling this will output very detailed SMTP messages. This could contain sensitive information like passwords and usernames! Only enable this during troubleshooting!
smtp_debug: bool, true, def, false;
/// Accept Invalid Certs (Know the risks!) |> DANGEROUS: Allow invalid certificates. This option introduces significant vulnerabilities to man-in-the-middle attacks!
smtp_accept_invalid_certs: bool, true, def, false;
/// Accept Invalid Hostnames (Know the risks!) |> DANGEROUS: Allow invalid hostnames. This option introduces significant vulnerabilities to man-in-the-middle attacks!
smtp_accept_invalid_hostnames: bool, true, def, false;
}, },
/// Email 2FA Settings /// Email 2FA Settings

View File

@ -7,6 +7,7 @@ use percent_encoding::{percent_encode, NON_ALPHANUMERIC};
use lettre::{ use lettre::{
message::{header, Mailbox, Message, MultiPart, SinglePart}, message::{header, Mailbox, Message, MultiPart, SinglePart},
transport::smtp::authentication::{Credentials, Mechanism as SmtpAuthMechanism}, transport::smtp::authentication::{Credentials, Mechanism as SmtpAuthMechanism},
transport::smtp::client::{Tls, TlsParameters},
transport::smtp::extension::ClientId, transport::smtp::extension::ClientId,
Address, SmtpTransport, Transport, Address, SmtpTransport, Transport,
}; };
@ -22,21 +23,30 @@ fn mailer() -> SmtpTransport {
use std::time::Duration; use std::time::Duration;
let host = CONFIG.smtp_host().unwrap(); let host = CONFIG.smtp_host().unwrap();
// Determine security let smtp_client = SmtpTransport::builder_dangerous(host.as_str())
let smtp_client = if CONFIG.smtp_ssl() {
if CONFIG.smtp_explicit_tls() {
SmtpTransport::relay(host.as_str())
} else {
SmtpTransport::starttls_relay(host.as_str())
}
} else {
Ok(SmtpTransport::builder_dangerous(host.as_str()))
};
let smtp_client = smtp_client.unwrap()
.port(CONFIG.smtp_port()) .port(CONFIG.smtp_port())
.timeout(Some(Duration::from_secs(CONFIG.smtp_timeout()))); .timeout(Some(Duration::from_secs(CONFIG.smtp_timeout())));
// Determine security
let smtp_client = if CONFIG.smtp_ssl() {
let mut tls_parameters = TlsParameters::builder(host);
if CONFIG.smtp_accept_invalid_hostnames() {
tls_parameters.dangerous_accept_invalid_hostnames(true);
}
if CONFIG.smtp_accept_invalid_certs() {
tls_parameters.dangerous_accept_invalid_certs(true);
}
let tls_parameters = tls_parameters.build().unwrap();
if CONFIG.smtp_explicit_tls() {
smtp_client.tls(Tls::Wrapper(tls_parameters))
} else {
smtp_client.tls(Tls::Required(tls_parameters))
}
} else {
smtp_client
};
let smtp_client = match (CONFIG.smtp_username(), CONFIG.smtp_password()) { let smtp_client = match (CONFIG.smtp_username(), CONFIG.smtp_password()) {
(Some(user), Some(pass)) => smtp_client.credentials(Credentials::new(user, pass)), (Some(user), Some(pass)) => smtp_client.credentials(Credentials::new(user, pass)),
_ => smtp_client, _ => smtp_client,
@ -318,14 +328,17 @@ fn send_email(address: &str, subject: &str, body_html: &str, body_text: &str) ->
// The boundary generated by Lettre it self is mostly too large based on the RFC822, so we generate one our selfs. // The boundary generated by Lettre it self is mostly too large based on the RFC822, so we generate one our selfs.
use uuid::Uuid; use uuid::Uuid;
let boundary = format!("_Part_{}_", Uuid::new_v4().to_simple()); let unique_id = Uuid::new_v4().to_simple();
let boundary = format!("_Part_{}_", unique_id);
let alternative = MultiPart::alternative().boundary(boundary).singlepart(text).singlepart(html); let alternative = MultiPart::alternative().boundary(boundary).singlepart(text).singlepart(html);
let smtp_from = &CONFIG.smtp_from();
let email = Message::builder() let email = Message::builder()
.message_id(Some(format!("<{}.{}>", unique_id, smtp_from)))
.to(Mailbox::new(None, Address::from_str(&address)?)) .to(Mailbox::new(None, Address::from_str(&address)?))
.from(Mailbox::new( .from(Mailbox::new(
Some(CONFIG.smtp_from_name()), Some(CONFIG.smtp_from_name()),
Address::from_str(&CONFIG.smtp_from())?, Address::from_str(smtp_from)?,
)) ))
.subject(subject) .subject(subject)
.multipart(alternative)?; .multipart(alternative)?;

View File

@ -115,6 +115,16 @@ fn init_logging(level: log::LevelFilter) -> Result<(), fern::InitError> {
.level_for("rocket::fairing", log::LevelFilter::Off) .level_for("rocket::fairing", log::LevelFilter::Off)
.chain(std::io::stdout()); .chain(std::io::stdout());
// Enable smtp debug logging only specifically for smtp when need.
// This can contain sensitive information we do not want in the default debug/trace logging.
if CONFIG.smtp_debug() {
println!("[WARNING] SMTP Debugging is enabled (SMTP_DEBUG=true). Sensitive information could be disclosed via logs!");
println!("[WARNING] Only enable SMTP_DEBUG during troubleshooting!\n");
logger = logger.level_for("lettre::transport::smtp", log::LevelFilter::Debug)
} else {
logger = logger.level_for("lettre::transport::smtp", log::LevelFilter::Off)
}
if CONFIG.extended_logging() { if CONFIG.extended_logging() {
logger = logger.format(|out, message, record| { logger = logger.format(|out, message, record| {
out.finish(format_args!( out.finish(format_args!(

View File

@ -17,7 +17,7 @@
<div id="g_{{group}}" class="card-body collapse" data-parent="#config-form"> <div id="g_{{group}}" class="card-body collapse" data-parent="#config-form">
{{#each elements}} {{#each elements}}
{{#if editable}} {{#if editable}}
<div class="form-group row" title="[{{name}}] {{doc.description}}"> <div class="form-group row align-items-center" title="[{{name}}] {{doc.description}}">
{{#case type "text" "number" "password"}} {{#case type "text" "number" "password"}}
<label for="input_{{name}}" class="col-sm-3 col-form-label">{{doc.name}}</label> <label for="input_{{name}}" class="col-sm-3 col-form-label">{{doc.name}}</label>
<div class="col-sm-8 input-group"> <div class="col-sm-8 input-group">
@ -34,7 +34,7 @@
</div> </div>
{{/case}} {{/case}}
{{#case type "checkbox"}} {{#case type "checkbox"}}
<div class="col-sm-3">{{doc.name}}</div> <div class="col-sm-3 col-form-label">{{doc.name}}</div>
<div class="col-sm-8"> <div class="col-sm-8">
<div class="form-check"> <div class="form-check">
<input class="form-check-input conf-{{type}}" type="checkbox" id="input_{{name}}" <input class="form-check-input conf-{{type}}" type="checkbox" id="input_{{name}}"
@ -48,7 +48,7 @@
{{/if}} {{/if}}
{{/each}} {{/each}}
{{#case group "smtp"}} {{#case group "smtp"}}
<div class="form-group row pt-3 border-top" title="Send a test email to given email address"> <div class="form-group row align-items-center pt-3 border-top" title="Send a test email to given email address">
<label for="smtp-test-email" class="col-sm-3 col-form-label">Test SMTP</label> <label for="smtp-test-email" class="col-sm-3 col-form-label">Test SMTP</label>
<div class="col-sm-8 input-group"> <div class="col-sm-8 input-group">
<input class="form-control" id="smtp-test-email" type="email" placeholder="Enter test email"> <input class="form-control" id="smtp-test-email" type="email" placeholder="Enter test email">
@ -76,7 +76,7 @@
{{#each config}} {{#each config}}
{{#each elements}} {{#each elements}}
{{#unless editable}} {{#unless editable}}
<div class="form-group row" title="[{{name}}] {{doc.description}}"> <div class="form-group row align-items-center" title="[{{name}}] {{doc.description}}">
{{#case type "text" "number" "password"}} {{#case type "text" "number" "password"}}
<label for="input_{{name}}" class="col-sm-3 col-form-label">{{doc.name}}</label> <label for="input_{{name}}" class="col-sm-3 col-form-label">{{doc.name}}</label>
<div class="col-sm-8 input-group"> <div class="col-sm-8 input-group">
@ -92,9 +92,9 @@
</div> </div>
{{/case}} {{/case}}
{{#case type "checkbox"}} {{#case type "checkbox"}}
<div class="col-sm-3">{{doc.name}}</div> <div class="col-sm-3 col-form-label">{{doc.name}}</div>
<div class="col-sm-8"> <div class="col-sm-8">
<div class="form-check"> <div class="form-check align-middle">
<input disabled class="form-check-input" type="checkbox" id="input_{{name}}" <input disabled class="form-check-input" type="checkbox" id="input_{{name}}"
{{#if value}} checked {{/if}}> {{#if value}} checked {{/if}}>
@ -139,6 +139,10 @@
<script> <script>
function smtpTest() { function smtpTest() {
if (formHasChanges(config_form)) {
alert("Config has been changed but not yet saved.\nPlease save the changes first before sending a test email.");
return false;
}
test_email = document.getElementById("smtp-test-email"); test_email = document.getElementById("smtp-test-email");
data = JSON.stringify({ "email": test_email.value }); data = JSON.stringify({ "email": test_email.value });
_post("{{urlpath}}/admin/test/smtp/", _post("{{urlpath}}/admin/test/smtp/",
@ -205,4 +209,35 @@
// {{#each config}} {{#if grouptoggle}} // {{#each config}} {{#if grouptoggle}}
masterCheck("input_{{grouptoggle}}", "#g_{{group}} input"); masterCheck("input_{{grouptoggle}}", "#g_{{group}} input");
// {{/if}} {{/each}} // {{/if}} {{/each}}
// Two functions to help check if there were changes to the form fields
// Useful for example during the smtp test to prevent people from clicking save before testing there new settings
function initChangeDetection(form) {
const ignore_fields = ["smtp-test-email"];
Array.from(form).forEach((el) => {
if (! ignore_fields.includes(el.id)) {
el.dataset.origValue = el.value
}
});
}
function formHasChanges(form) {
return Array.from(form).some(el => 'origValue' in el.dataset && ( el.dataset.origValue !== el.value));
}
// Trigger Form Change Detection
const config_form = document.getElementById('config-form');
initChangeDetection(config_form);
// Colorize some settings which are high risk
const risk_items = document.getElementsByClassName('col-form-label');
function colorRiskSettings(risk_el) {
Array.from(risk_el).forEach((el) => {
if (el.innerText.toLowerCase().includes('risks') ) {
el.parentElement.className += ' alert-danger'
console.log(el)
}
});
}
colorRiskSettings(risk_items);
</script> </script>

View File

@ -1,6 +1,8 @@
Your Email Change Your Email Change
<!----------------> <!---------------->
<html> To finalize changing your email address enter the following code in web vault: {{token}}
<p>To finalize changing your email address enter the following code in web vault: <b>{{token}}</b></p>
<p>If you did not try to change an email address, you can safely ignore this email.</p> If you did not try to change an email address, you can safely ignore this email.
</html>
===
Github: https://github.com/dani-garcia/bitwarden_rs

View File

@ -1,12 +1,10 @@
Delete Your Account Delete Your Account
<!----------------> <!---------------->
<html> Click the link below to delete your account.
<p>
click the link below to delete your account. Delete Your Account: {{url}}/#/verify-recover-delete?userId={{user_id}}&token={{token}}&email={{email}}
<br>
<br> If you did not request this email to delete your account, you can safely ignore this email.
<a href="{{url}}/#/verify-recover-delete?userId={{user_id}}&token={{token}}&email={{email}}">
Delete Your Account</a> ===
</p> Github: https://github.com/dani-garcia/bitwarden_rs
<p>If you did not request this email to delete your account, you can safely ignore this email.</p>
</html>

View File

@ -1,8 +1,7 @@
Invitation to {{{org_name}}} accepted Invitation to {{{org_name}}} accepted
<!----------------> <!---------------->
<html> Your invitation for *{{email}}* to join *{{org_name}}* was accepted.
<p> Please log in via {{url}} to the bitwarden_rs server and confirm them from the organization management page.
Your invitation for <b>{{email}}</b> to join <b>{{org_name}}</b> was accepted.
Please <a href="{{url}}/">log in</a> to the bitwarden_rs server and confirm them from the organization management page. ===
</p> Github: https://github.com/dani-garcia/bitwarden_rs
</html>

View File

@ -1,8 +1,7 @@
Invitation to {{{org_name}}} confirmed Invitation to {{{org_name}}} confirmed
<!----------------> <!---------------->
<html> Your invitation to join *{{org_name}}* was confirmed.
<p> It will now appear under the Organizations the next time you log in to the web vault at {{url}}.
Your invitation to join <b>{{org_name}}</b> was confirmed.
It will now appear under the Organizations the next time you <a href="{{url}}/">log in</a> to the web vault. ===
</p> Github: https://github.com/dani-garcia/bitwarden_rs
</html>

View File

@ -1,14 +1,12 @@
New Device Logged In From {{{device}}} New Device Logged In From {{{device}}}
<!----------------> <!---------------->
<html>
<p>
Your account was just logged into from a new device. Your account was just logged into from a new device.
Date: {{datetime}} * Date: {{datetime}}
IP Address: {{ip}} * IP Address: {{ip}}
Device Type: {{device}} * Device Type: {{device}}
You can deauthorize all devices that have access to your account from the You can deauthorize all devices that have access to your account from the web vault ( {{url}} ) under Settings > My Account > Deauthorize Sessions.
<a href="{{url}}/">web vault</a> under Settings > My Account > Deauthorize Sessions.
</p> ===
</html> Github: https://github.com/dani-garcia/bitwarden_rs

View File

@ -2,6 +2,9 @@ Your master password hint
<!----------------> <!---------------->
You (or someone) recently requested your master password hint. Unfortunately, your account does not have a master password hint. You (or someone) recently requested your master password hint. Unfortunately, your account does not have a master password hint.
If you cannot remember your master password, there is no way to recover your data. The only option to gain access to your account again is to <a href="{{url}}/#/recover-delete">delete the account</a> so that you can register again and start over. All data associated with your account will be deleted. If you cannot remember your master password, there is no way to recover your data. The only option to gain access to your account again is to delete the account ( {{url}}/#/recover-delete ) so that you can register again and start over. All data associated with your account will be deleted.
If you did not request your master password hint you can safely ignore this email. If you did not request your master password hint you can safely ignore this email.
===
Github: https://github.com/dani-garcia/bitwarden_rs

View File

@ -2,9 +2,12 @@ Your master password hint
<!----------------> <!---------------->
You (or someone) recently requested your master password hint. You (or someone) recently requested your master password hint.
Your hint is: "{{hint}}" Your hint is: *{{hint}}*
Log in: <a href="{{url}}/">Web Vault</a> Log in to the web vault: {{url}}
If you cannot remember your master password, there is no way to recover your data. The only option to gain access to your account again is to <a href="{{url}}/#/recover-delete">delete the account</a> so that you can register again and start over. All data associated with your account will be deleted. If you cannot remember your master password, there is no way to recover your data. The only option to gain access to your account again is to delete the account ( {{url}}/#/recover-delete ) so that you can register again and start over. All data associated with your account will be deleted.
If you did not request your master password hint you can safely ignore this email. If you did not request your master password hint you can safely ignore this email.
===
Github: https://github.com/dani-garcia/bitwarden_rs

View File

@ -1,12 +1,12 @@
Join {{{org_name}}} Join {{{org_name}}}
<!----------------> <!---------------->
<html> You have been invited to join the *{{org_name}}* organization.
<p>
You have been invited to join the <b>{{org_name}}</b> organization.
<br> Click here to join: {{url}}/#/accept-organization/?organizationId={{org_id}}&organizationUserId={{org_user_id}}&email={{email}}&organizationName={{org_name}}&token={{token}}
<br>
<a href="{{url}}/#/accept-organization/?organizationId={{org_id}}&organizationUserId={{org_user_id}}&email={{email}}&organizationName={{org_name}}&token={{token}}">
Click here to join</a> If you do not wish to join this organization, you can safely ignore this email.
</p>
<p>If you do not wish to join this organization, you can safely ignore this email.</p> ===
</html> Github: https://github.com/dani-garcia/bitwarden_rs

View File

@ -1,8 +1,8 @@
Bitwarden_rs SMTP Test Bitwarden_rs SMTP Test
<!----------------> <!---------------->
<html> This is a test email to verify the SMTP configuration for {{url}}.
<p>
This is a test email to verify the SMTP configuration for <a href="{{url}}">{{url}}</a>. When you can read this email it is probably configured correctly.
</p>
<p>When you can read this email it is probably configured correctly.</p> ===
</html> Github: https://github.com/dani-garcia/bitwarden_rs

View File

@ -1,9 +1,8 @@
Your Two-step Login Verification Code Your Two-step Login Verification Code
<!----------------> <!---------------->
<html> Your two-step verification code is: {{token}}
<p>
Your two-step verification code is: <b>{{token}}</b>
Use this code to complete logging in with Bitwarden. Use this code to complete logging in with Bitwarden.
</p>
</html> ===
Github: https://github.com/dani-garcia/bitwarden_rs

View File

@ -1,12 +1,10 @@
Verify Your Email Verify Your Email
<!----------------> <!---------------->
<html>
<p>
Verify this email address for your account by clicking the link below. Verify this email address for your account by clicking the link below.
<br>
<br> Verify Email Address Now: {{url}}/#/verify-email/?userId={{user_id}}&token={{token}}
<a href="{{url}}/#/verify-email/?userId={{user_id}}&token={{token}}">
Verify Email Address Now</a> If you did not request to verify your account, you can safely ignore this email.
</p>
<p>If you did not request to verify your account, you can safely ignore this email.</p> ===
</html> Github: https://github.com/dani-garcia/bitwarden_rs

View File

@ -1,8 +1,8 @@
Welcome Welcome
<!----------------> <!---------------->
<html> Thank you for creating an account at {{url}}. You may now log in with your new account.
<p>
Thank you for creating an account at <a href="{{url}}/">{{url}}</a>. You may now log in with your new account. If you did not request to create an account, you can safely ignore this email.
</p>
<p>If you did not request to create an account, you can safely ignore this email.</p> ===
</html> Github: https://github.com/dani-garcia/bitwarden_rs

View File

@ -1,12 +1,10 @@
Welcome Welcome
<!----------------> <!---------------->
<html> Thank you for creating an account at {{url}}. Before you can login with your new account, you must verify this email address by clicking the link below.
<p>
Thank you for creating an account at <a href="{{url}}/">{{url}}</a>. Before you can login with your new account, you must verify this email address by clicking the link below. Verify Email Address Now: {{url}}/#/verify-email/?userId={{user_id}}&token={{token}}
<br>
<br> If you did not request to create an account, you can safely ignore this email.
<a href="{{url}}/#/verify-email/?userId={{user_id}}&token={{token}}">
Verify Email Address Now</a> ===
</p> Github: https://github.com/dani-garcia/bitwarden_rs
<p>If you did not request to create an account, you can safely ignore this email.</p>
</html>