Remove some and deny new indexing and slicing

This commit is contained in:
Alexander Krotov
2020-06-22 02:07:10 +03:00
committed by link2xt
parent ee7b7eb4f2
commit 18e4abc1df
18 changed files with 107 additions and 95 deletions

View File

@@ -907,11 +907,10 @@ impl Chat {
// the whole list of messages referenced may be huge; // the whole list of messages referenced may be huge;
// only use the oldest and and the parent message // only use the oldest and and the parent message
let parent_references = if let Some(n) = parent_references.find(' ') { let parent_references = parent_references
&parent_references[0..n] .find(' ')
} else { .and_then(|n| parent_references.get(..n))
&parent_references .unwrap_or(&parent_references);
};
if !parent_references.is_empty() && !parent_rfc724_mid.is_empty() { if !parent_references.is_empty() && !parent_rfc724_mid.is_empty() {
// angle brackets are added by the mimefactory later // angle brackets are added by the mimefactory later

View File

@@ -1,7 +1,5 @@
//! Email accounts autoconfiguration process module //! Email accounts autoconfiguration process module
#![forbid(clippy::indexing_slicing)]
mod auto_mozilla; mod auto_mozilla;
mod auto_outlook; mod auto_outlook;
mod read_url; mod read_url;

View File

@@ -1,7 +1,5 @@
//! Contacts module //! Contacts module
#![forbid(clippy::indexing_slicing)]
use async_std::path::PathBuf; use async_std::path::PathBuf;
use deltachat_derive::*; use deltachat_derive::*;
use itertools::Itertools; use itertools::Itertools;

View File

@@ -1515,6 +1515,7 @@ async fn create_adhoc_grp_id(context: &Context, member_ids: &[u32]) -> String {
hex_hash(&members) hex_hash(&members)
} }
#[allow(clippy::indexing_slicing)]
fn hex_hash(s: impl AsRef<str>) -> String { fn hex_hash(s: impl AsRef<str>) -> String {
let bytes = s.as_ref().as_bytes(); let bytes = s.as_ref().as_bytes();
let result = Sha256::digest(bytes); let result = Sha256::digest(bytes);
@@ -1567,7 +1568,7 @@ async fn search_chat_ids_by_contact_ids(
matches = 0; matches = 0;
mismatches = 0; mismatches = 0;
} }
if matches < contact_ids.len() && contact_id == contact_ids[matches] { if contact_ids.get(matches) == Some(&contact_id) {
matches += 1; matches += 1;
} else { } else {
mismatches += 1; mismatches += 1;
@@ -1695,12 +1696,13 @@ async fn check_verified_properties(
fn set_better_msg(mime_parser: &mut MimeMessage, better_msg: impl AsRef<str>) { fn set_better_msg(mime_parser: &mut MimeMessage, better_msg: impl AsRef<str>) {
let msg = better_msg.as_ref(); let msg = better_msg.as_ref();
if !msg.is_empty() && !mime_parser.parts.is_empty() { if !msg.is_empty() {
let part = &mut mime_parser.parts[0]; if let Some(part) = mime_parser.parts.get_mut(0) {
if part.typ == Viewtype::Text { if part.typ == Viewtype::Text {
part.msg = msg.to_string(); part.msg = msg.to_string();
} }
} }
}
} }
async fn is_reply_to_known_message(context: &Context, mime_parser: &MimeMessage) -> bool { async fn is_reply_to_known_message(context: &Context, mime_parser: &MimeMessage) -> bool {

View File

@@ -22,6 +22,7 @@ pub(crate) fn dc_exactly_one_bit_set(v: i32) -> bool {
/// Shortens a string to a specified length and adds "[...]" to the /// Shortens a string to a specified length and adds "[...]" to the
/// end of the shortened string. /// end of the shortened string.
#[allow(clippy::indexing_slicing)]
pub(crate) fn dc_truncate(buf: &str, approx_chars: usize) -> Cow<str> { pub(crate) fn dc_truncate(buf: &str, approx_chars: usize) -> Cow<str> {
let ellipse = "[...]"; let ellipse = "[...]";
@@ -54,6 +55,7 @@ const COLORS: [u32; 16] = [
0xf2_30_30, 0x39_b2_49, 0xbb_24_3b, 0x96_40_78, 0x66_87_4f, 0x30_8a_b9, 0x12_7e_d0, 0xbe_45_0c, 0xf2_30_30, 0x39_b2_49, 0xbb_24_3b, 0x96_40_78, 0x66_87_4f, 0x30_8a_b9, 0x12_7e_d0, 0xbe_45_0c,
]; ];
#[allow(clippy::indexing_slicing)]
pub(crate) fn dc_str_to_color(s: impl AsRef<str>) -> u32 { pub(crate) fn dc_str_to_color(s: impl AsRef<str>) -> u32 {
let str_lower = s.as_ref().to_lowercase(); let str_lower = s.as_ref().to_lowercase();
let mut checksum = 0; let mut checksum = 0;
@@ -198,7 +200,7 @@ fn encode_66bits_as_base64(v1: u32, v2: u32, fill: u32) -> String {
pub(crate) fn dc_create_outgoing_rfc724_mid(grpid: Option<&str>, from_addr: &str) -> String { pub(crate) fn dc_create_outgoing_rfc724_mid(grpid: Option<&str>, from_addr: &str) -> String {
let hostname = from_addr let hostname = from_addr
.find('@') .find('@')
.map(|k| &from_addr[k..]) .and_then(|k| from_addr.get(k..))
.unwrap_or("@nohost"); .unwrap_or("@nohost");
match grpid { match grpid {
Some(grpid) => format!("Gr.{}.{}{}", grpid, dc_create_id(), hostname), Some(grpid) => format!("Gr.{}.{}{}", grpid, dc_create_id(), hostname),

View File

@@ -187,24 +187,23 @@ fn get_autocrypt_mime<'a, 'b>(mail: &'a ParsedMail<'b>) -> Result<&'a ParsedMail
"Not a multipart/encrypted message: {}", "Not a multipart/encrypted message: {}",
mail.ctype.mimetype mail.ctype.mimetype
); );
if let [first_part, second_part] = &mail.subparts[..] {
ensure!( ensure!(
mail.subparts.len() == 2, first_part.ctype.mimetype == "application/pgp-encrypted",
"Invalid Autocrypt Level 1 Mime Parts"
);
ensure!(
mail.subparts[0].ctype.mimetype == "application/pgp-encrypted",
"Invalid Autocrypt Level 1 version part: {:?}", "Invalid Autocrypt Level 1 version part: {:?}",
mail.subparts[0].ctype, first_part.ctype,
); );
ensure!( ensure!(
mail.subparts[1].ctype.mimetype == "application/octet-stream", second_part.ctype.mimetype == "application/octet-stream",
"Invalid Autocrypt Level 1 encrypted part: {:?}", "Invalid Autocrypt Level 1 encrypted part: {:?}",
mail.subparts[1].ctype second_part.ctype
); );
Ok(&mail.subparts[1]) Ok(second_part)
} else {
bail!("Invalid Autocrypt Level 1 Mime Parts")
}
} }
async fn decrypt_if_autocrypt_message<'a>( async fn decrypt_if_autocrypt_message<'a>(
@@ -267,6 +266,7 @@ async fn decrypt_part(
Ok(None) Ok(None)
} }
#[allow(clippy::indexing_slicing)]
fn has_decrypted_pgp_armor(input: &[u8]) -> bool { fn has_decrypted_pgp_armor(input: &[u8]) -> bool {
if let Some(index) = input.iter().position(|b| *b > b' ') { if let Some(index) = input.iter().position(|b| *b > b' ') {
if input.len() - index > 26 { if input.len() - index > 26 {

View File

@@ -3,8 +3,6 @@
//! uses [async-email/async-imap](https://github.com/async-email/async-imap) //! uses [async-email/async-imap](https://github.com/async-email/async-imap)
//! to implement connect, fetch, delete functionality with standard IMAP servers. //! to implement connect, fetch, delete functionality with standard IMAP servers.
#![forbid(clippy::indexing_slicing)]
use std::collections::BTreeMap; use std::collections::BTreeMap;
use async_imap::{ use async_imap::{

View File

@@ -178,10 +178,11 @@ async fn do_initiate_key_transfer(context: &Context) -> Result<String> {
/// ///
/// The `passphrase` must be at least 2 characters long. /// The `passphrase` must be at least 2 characters long.
pub async fn render_setup_file(context: &Context, passphrase: &str) -> Result<String> { pub async fn render_setup_file(context: &Context, passphrase: &str) -> Result<String> {
ensure!( let passphrase_begin = if let Some(passphrase_begin) = passphrase.get(..2) {
passphrase.len() >= 2, passphrase_begin
"Passphrase must be at least 2 chars long." } else {
); bail!("Passphrase must be at least 2 chars long.");
};
let private_key = SignedSecretKey::load_self(context).await?; let private_key = SignedSecretKey::load_self(context).await?;
let ac_headers = match context.get_config_bool(Config::E2eeEnabled).await { let ac_headers = match context.get_config_bool(Config::E2eeEnabled).await {
false => None, false => None,
@@ -196,7 +197,7 @@ pub async fn render_setup_file(context: &Context, passphrase: &str) -> Result<St
"Passphrase-Format: numeric9x4\r\n", "Passphrase-Format: numeric9x4\r\n",
"Passphrase-Begin: {}" "Passphrase-Begin: {}"
), ),
&passphrase[..2] passphrase_begin
); );
let pgp_msg = encr.replace("-----BEGIN PGP MESSAGE-----", &replacement); let pgp_msg = encr.replace("-----BEGIN PGP MESSAGE-----", &replacement);

View File

@@ -1,5 +1,10 @@
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
#![deny(clippy::correctness, missing_debug_implementations, clippy::all)] #![deny(
clippy::correctness,
missing_debug_implementations,
clippy::all,
clippy::indexing_slicing
)]
#![allow(clippy::match_bool)] #![allow(clippy::match_bool)]
#[macro_use] #[macro_use]

View File

@@ -239,6 +239,7 @@ impl MimeMessage {
/// ///
/// Delta Chat sends attachments, such as images, in two-part messages, with the first message /// Delta Chat sends attachments, such as images, in two-part messages, with the first message
/// containing an explanation. If such a message is detected, first part can be safely dropped. /// containing an explanation. If such a message is detected, first part can be safely dropped.
#[allow(clippy::indexing_slicing)]
fn squash_attachment_parts(&mut self) { fn squash_attachment_parts(&mut self) {
if let [textpart, filepart] = &self.parts[..] { if let [textpart, filepart] = &self.parts[..] {
let need_drop = { let need_drop = {
@@ -272,34 +273,34 @@ impl MimeMessage {
fn parse_attachments(&mut self) { fn parse_attachments(&mut self) {
// Attachment messages should be squashed into a single part // Attachment messages should be squashed into a single part
// before calling this function. // before calling this function.
if self.parts.len() == 1 { if self.parts.len() != 1 {
if self.parts[0].typ == Viewtype::Audio return;
&& self.get(HeaderDef::ChatVoiceMessage).is_some() }
{
let part_mut = &mut self.parts[0]; if let Some(mut part_mut) = self.parts.pop() {
if part_mut.typ == Viewtype::Audio && self.get(HeaderDef::ChatVoiceMessage).is_some() {
part_mut.typ = Viewtype::Voice; part_mut.typ = Viewtype::Voice;
} }
if self.parts[0].typ == Viewtype::Image { if part_mut.typ == Viewtype::Image {
if let Some(value) = self.get(HeaderDef::ChatContent) { if let Some(value) = self.get(HeaderDef::ChatContent) {
if value == "sticker" { if value == "sticker" {
let part_mut = &mut self.parts[0];
part_mut.typ = Viewtype::Sticker; part_mut.typ = Viewtype::Sticker;
} }
} }
} }
let part = &self.parts[0]; if part_mut.typ == Viewtype::Audio
if part.typ == Viewtype::Audio || part_mut.typ == Viewtype::Voice
|| part.typ == Viewtype::Voice || part_mut.typ == Viewtype::Video
|| part.typ == Viewtype::Video
{ {
if let Some(field_0) = self.get(HeaderDef::ChatDuration) { if let Some(field_0) = self.get(HeaderDef::ChatDuration) {
let duration_ms = field_0.parse().unwrap_or_default(); let duration_ms = field_0.parse().unwrap_or_default();
if duration_ms > 0 && duration_ms < 24 * 60 * 60 * 1000 { if duration_ms > 0 && duration_ms < 24 * 60 * 60 * 1000 {
let part_mut = &mut self.parts[0];
part_mut.param.set_int(Param::Duration, duration_ms); part_mut.param.set_int(Param::Duration, duration_ms);
} }
} }
} }
self.parts.push(part_mut);
} }
} }
@@ -321,11 +322,10 @@ impl MimeMessage {
} }
} }
if prepend_subject { if prepend_subject {
let subj = if let Some(n) = subject.find('[') { let subj = subject
&subject[0..n] .find('[')
} else { .and_then(|n| subject.get(..n))
subject .unwrap_or(subject)
}
.trim(); .trim();
if !subj.is_empty() { if !subj.is_empty() {
@@ -384,8 +384,7 @@ impl MimeMessage {
Some(AvatarAction::Delete) Some(AvatarAction::Delete)
} else { } else {
let mut i = 0; let mut i = 0;
while i != self.parts.len() { while let Some(part) = self.parts.get_mut(i) {
let part = &mut self.parts[i];
if let Some(part_filename) = &part.org_filename { if let Some(part_filename) = &part.org_filename {
if part_filename == &header_value { if part_filename == &header_value {
if let Some(blob) = part.param.get(Param::File) { if let Some(blob) = part.param.get(Param::File) {
@@ -770,16 +769,11 @@ impl MimeMessage {
} }
pub fn repl_msg_by_error(&mut self, error_msg: impl AsRef<str>) { pub fn repl_msg_by_error(&mut self, error_msg: impl AsRef<str>) {
if self.parts.is_empty() { if let Some(part) = self.parts.first_mut() {
return;
}
let part = &mut self.parts[0];
part.typ = Viewtype::Text; part.typ = Viewtype::Text;
part.msg = format!("[{}]", error_msg.as_ref()); part.msg = format!("[{}]", error_msg.as_ref());
self.parts.truncate(1); self.parts.truncate(1);
}
assert_eq!(self.parts.len(), 1);
} }
pub fn get_rfc724_mid(&self) -> Option<String> { pub fn get_rfc724_mid(&self) -> Option<String> {
@@ -830,7 +824,11 @@ impl MimeMessage {
report: &mailparse::ParsedMail<'_>, report: &mailparse::ParsedMail<'_>,
) -> Result<Option<Report>> { ) -> Result<Option<Report>> {
// parse as mailheaders // parse as mailheaders
let report_body = report.subparts[1].get_body_raw()?; let report_body = if let Some(subpart) = report.subparts.get(1) {
subpart.get_body_raw()?
} else {
bail!("Report does not have second MIME part");
};
let (report_fields, _) = mailparse::parse_headers(&report_body)?; let (report_fields, _) = mailparse::parse_headers(&report_body)?;
// must be present // must be present
@@ -908,6 +906,7 @@ impl MimeMessage {
/// Some providers like GMX and Yahoo do not send standard NDNs (Non Delivery notifications). /// Some providers like GMX and Yahoo do not send standard NDNs (Non Delivery notifications).
/// If you improve heuristics here you might also have to change prefetch_should_download() in imap/mod.rs. /// If you improve heuristics here you might also have to change prefetch_should_download() in imap/mod.rs.
/// Also you should add a test in dc_receive_imf.rs (there already are lots of test_parse_ndn_* tests). /// Also you should add a test in dc_receive_imf.rs (there already are lots of test_parse_ndn_* tests).
#[allow(clippy::indexing_slicing)]
async fn heuristically_parse_ndn(&mut self, context: &Context) -> Option<()> { async fn heuristically_parse_ndn(&mut self, context: &Context) -> Option<()> {
let maybe_ndn = if let Some(from) = self.get(HeaderDef::From_) { let maybe_ndn = if let Some(from) = self.get(HeaderDef::From_) {
let from = from.to_ascii_lowercase(); let from = from.to_ascii_lowercase();
@@ -966,10 +965,9 @@ impl MimeMessage {
if let Some(failure_report) = &self.failure_report { if let Some(failure_report) = &self.failure_report {
let error = parts.iter().find(|p| p.typ == Viewtype::Text).map(|p| { let error = parts.iter().find(|p| p.typ == Viewtype::Text).map(|p| {
let msg = &p.msg; let msg = &p.msg;
match msg.find("\n--- ") { msg.find("\n--- ")
Some(footer_start) => &msg[..footer_start], .and_then(|footer_start| msg.get(..footer_start))
None => msg, .unwrap_or(msg)
}
.trim() .trim()
}); });
message::handle_ndn(context, failure_report, error).await message::handle_ndn(context, failure_report, error).await
@@ -1036,6 +1034,7 @@ pub(crate) struct FailureReport {
pub failed_recipient: Option<String>, pub failed_recipient: Option<String>,
} }
#[allow(clippy::indexing_slicing)]
pub(crate) fn parse_message_ids(ids: &str) -> Result<Vec<String>> { pub(crate) fn parse_message_ids(ids: &str) -> Result<Vec<String>> {
// take care with mailparse::msgidparse() that is pretty untolerant eg. wrt missing `<` or `>` // take care with mailparse::msgidparse() that is pretty untolerant eg. wrt missing `<` or `>`
let mut msgids = Vec::new(); let mut msgids = Vec::new();

View File

@@ -171,7 +171,7 @@ impl str::FromStr for Params {
let key = key.unwrap_or_default().trim(); let key = key.unwrap_or_default().trim();
let value = value.unwrap_or_default().trim(); let value = value.unwrap_or_default().trim();
if let Some(key) = Param::from_u8(key.as_bytes()[0]) { if let Some(key) = key.as_bytes().first().and_then(|key| Param::from_u8(*key)) {
inner.insert(key, value.to_string()); inner.insert(key, value.to_string());
} else { } else {
bail!("Unknown key: {}", key); bail!("Unknown key: {}", key);

View File

@@ -365,12 +365,14 @@ pub async fn symm_decrypt<T: std::io::Read + std::io::Seek>(
let decryptor = enc_msg.decrypt_with_password(|| passphrase)?; let decryptor = enc_msg.decrypt_with_password(|| passphrase)?;
let msgs = decryptor.collect::<pgp::errors::Result<Vec<_>>>()?; let msgs = decryptor.collect::<pgp::errors::Result<Vec<_>>>()?;
ensure!(!msgs.is_empty(), "No valid messages found"); if let Some(msg) = msgs.first() {
match msg.get_content()? {
match msgs[0].get_content()? {
Some(content) => Ok(content), Some(content) => Ok(content),
None => bail!("Decrypted message is empty"), None => bail!("Decrypted message is empty"),
} }
} else {
bail!("No valid messages found")
}
}) })
.await .await
} }

View File

@@ -68,6 +68,7 @@ pub async fn check_qr(context: &Context, qr: impl AsRef<str>) -> Lot {
/// scheme: `OPENPGP4FPR:FINGERPRINT#a=ADDR&n=NAME&i=INVITENUMBER&s=AUTH` /// scheme: `OPENPGP4FPR:FINGERPRINT#a=ADDR&n=NAME&i=INVITENUMBER&s=AUTH`
/// or: `OPENPGP4FPR:FINGERPRINT#a=ADDR&g=GROUPNAME&x=GROUPID&i=INVITENUMBER&s=AUTH` /// or: `OPENPGP4FPR:FINGERPRINT#a=ADDR&g=GROUPNAME&x=GROUPID&i=INVITENUMBER&s=AUTH`
#[allow(clippy::indexing_slicing)]
async fn decode_openpgp(context: &Context, qr: &str) -> Lot { async fn decode_openpgp(context: &Context, qr: &str) -> Lot {
let payload = &qr[OPENPGP4FPR_SCHEME.len()..]; let payload = &qr[OPENPGP4FPR_SCHEME.len()..];
@@ -187,6 +188,7 @@ async fn decode_openpgp(context: &Context, qr: &str) -> Lot {
} }
/// scheme: `DCACCOUNT:https://example.org/new_email?t=1w_7wDjgjelxeX884x96v3` /// scheme: `DCACCOUNT:https://example.org/new_email?t=1w_7wDjgjelxeX884x96v3`
#[allow(clippy::indexing_slicing)]
fn decode_account(_context: &Context, qr: &str) -> Lot { fn decode_account(_context: &Context, qr: &str) -> Lot {
let payload = &qr[DCACCOUNT_SCHEME.len()..]; let payload = &qr[DCACCOUNT_SCHEME.len()..];
@@ -217,6 +219,7 @@ struct CreateAccountResponse {
/// take a qr of the type DC_QR_ACCOUNT, parse it's parameters, /// take a qr of the type DC_QR_ACCOUNT, parse it's parameters,
/// download additional information from the contained url and set the parameters. /// download additional information from the contained url and set the parameters.
/// on success, a configure::configure() should be able to log in to the account /// on success, a configure::configure() should be able to log in to the account
#[allow(clippy::indexing_slicing)]
pub async fn set_config_from_qr(context: &Context, qr: &str) -> Result<(), Error> { pub async fn set_config_from_qr(context: &Context, qr: &str) -> Result<(), Error> {
let url_str = &qr[DCACCOUNT_SCHEME.len()..]; let url_str = &qr[DCACCOUNT_SCHEME.len()..];
@@ -240,6 +243,7 @@ pub async fn set_config_from_qr(context: &Context, qr: &str) -> Result<(), Error
/// Extract address for the mailto scheme. /// Extract address for the mailto scheme.
/// ///
/// Scheme: `mailto:addr...?subject=...&body=..` /// Scheme: `mailto:addr...?subject=...&body=..`
#[allow(clippy::indexing_slicing)]
async fn decode_mailto(context: &Context, qr: &str) -> Lot { async fn decode_mailto(context: &Context, qr: &str) -> Lot {
let payload = &qr[MAILTO_SCHEME.len()..]; let payload = &qr[MAILTO_SCHEME.len()..];
@@ -261,6 +265,7 @@ async fn decode_mailto(context: &Context, qr: &str) -> Lot {
/// Extract address for the smtp scheme. /// Extract address for the smtp scheme.
/// ///
/// Scheme: `SMTP:addr...:subject...:body...` /// Scheme: `SMTP:addr...:subject...:body...`
#[allow(clippy::indexing_slicing)]
async fn decode_smtp(context: &Context, qr: &str) -> Lot { async fn decode_smtp(context: &Context, qr: &str) -> Lot {
let payload = &qr[SMTP_SCHEME.len()..]; let payload = &qr[SMTP_SCHEME.len()..];
@@ -283,6 +288,7 @@ async fn decode_smtp(context: &Context, qr: &str) -> Lot {
/// Scheme: `MATMSG:TO:addr...;SUB:subject...;BODY:body...;` /// Scheme: `MATMSG:TO:addr...;SUB:subject...;BODY:body...;`
/// ///
/// There may or may not be linebreaks after the fields. /// There may or may not be linebreaks after the fields.
#[allow(clippy::indexing_slicing)]
async fn decode_matmsg(context: &Context, qr: &str) -> Lot { async fn decode_matmsg(context: &Context, qr: &str) -> Lot {
// Does not work when the text `TO:` is used in subject/body _and_ TO: is not the first field. // Does not work when the text `TO:` is used in subject/body _and_ TO: is not the first field.
// we ignore this case. // we ignore this case.
@@ -316,14 +322,15 @@ lazy_static! {
/// Extract address for the matmsg scheme. /// Extract address for the matmsg scheme.
/// ///
/// Scheme: `VCARD:BEGIN\nN:last name;first name;...;\nEMAIL;<type>:addr...; /// Scheme: `VCARD:BEGIN\nN:last name;first name;...;\nEMAIL;<type>:addr...;
#[allow(clippy::indexing_slicing)]
async fn decode_vcard(context: &Context, qr: &str) -> Lot { async fn decode_vcard(context: &Context, qr: &str) -> Lot {
let name = VCARD_NAME_RE let name = VCARD_NAME_RE
.captures(qr) .captures(qr)
.map(|caps| { .and_then(|caps| {
let last_name = &caps[1]; let last_name = caps.get(1)?.as_str().trim();
let first_name = &caps[2]; let first_name = caps.get(2)?.as_str().trim();
format!("{} {}", first_name.trim(), last_name.trim()) Some(format!("{} {}", first_name, last_name))
}) })
.unwrap_or_default(); .unwrap_or_default();

View File

@@ -1,5 +1,3 @@
#![warn(clippy::indexing_slicing)]
use async_std::prelude::*; use async_std::prelude::*;
use async_std::sync::{channel, Receiver, Sender}; use async_std::sync::{channel, Receiver, Sender};
use async_std::task; use async_std::task;

View File

@@ -352,9 +352,8 @@ async fn send_handshake_msg(
} }
async fn chat_id_2_contact_id(context: &Context, contact_chat_id: ChatId) -> u32 { async fn chat_id_2_contact_id(context: &Context, contact_chat_id: ChatId) -> u32 {
let contacts = chat::get_chat_contacts(context, contact_chat_id).await; if let [contact_id] = chat::get_chat_contacts(context, contact_chat_id).await[..] {
if contacts.len() == 1 { contact_id
contacts[0]
} else { } else {
0 0
} }
@@ -365,10 +364,8 @@ async fn fingerprint_equals_sender(
fingerprint: &Fingerprint, fingerprint: &Fingerprint,
contact_chat_id: ChatId, contact_chat_id: ChatId,
) -> bool { ) -> bool {
let contacts = chat::get_chat_contacts(context, contact_chat_id).await; if let [contact_id] = chat::get_chat_contacts(context, contact_chat_id).await[..] {
if let Ok(contact) = Contact::load_from_db(context, contact_id).await {
if contacts.len() == 1 {
if let Ok(contact) = Contact::load_from_db(context, contacts[0]).await {
if let Some(peerstate) = Peerstate::from_addr(context, contact.get_addr()).await { if let Some(peerstate) = Peerstate::from_addr(context, contact.get_addr()).await {
if peerstate.public_key_fingerprint.is_some() if peerstate.public_key_fingerprint.is_some()
&& fingerprint == peerstate.public_key_fingerprint.as_ref().unwrap() && fingerprint == peerstate.public_key_fingerprint.as_ref().unwrap()
@@ -426,6 +423,7 @@ pub(crate) enum HandshakeMessage {
/// When handle_securejoin_handshake() is called, /// When handle_securejoin_handshake() is called,
/// the message is not yet filed in the database; /// the message is not yet filed in the database;
/// this is done by receive_imf() later on as needed. /// this is done by receive_imf() later on as needed.
#[allow(clippy::indexing_slicing)]
pub(crate) async fn handle_securejoin_handshake( pub(crate) async fn handle_securejoin_handshake(
context: &Context, context: &Context,
mime_message: &MimeMessage, mime_message: &MimeMessage,

View File

@@ -6,6 +6,7 @@
// this escapes a bit more than actually needed by delta (eg. also lines as "-- footer"), // this escapes a bit more than actually needed by delta (eg. also lines as "-- footer"),
// but for non-delta-compatibility, that seems to be better. // but for non-delta-compatibility, that seems to be better.
// (to be only compatible with delta, only "[\r\n|\n]-- {0,2}[\r\n|\n]" needs to be replaced) // (to be only compatible with delta, only "[\r\n|\n]-- {0,2}[\r\n|\n]" needs to be replaced)
#[allow(clippy::indexing_slicing)]
pub fn escape_message_footer_marks(text: &str) -> String { pub fn escape_message_footer_marks(text: &str) -> String {
if text.starts_with("--") { if text.starts_with("--") {
"-\u{200B}-".to_string() + &text[2..].replace("\n--", "\n-\u{200B}-") "-\u{200B}-".to_string() + &text[2..].replace("\n--", "\n-\u{200B}-")
@@ -15,6 +16,7 @@ pub fn escape_message_footer_marks(text: &str) -> String {
} }
/// Remove standard (RFC 3676, §4.3) footer if it is found. /// Remove standard (RFC 3676, §4.3) footer if it is found.
#[allow(clippy::indexing_slicing)]
fn remove_message_footer<'a>(lines: &'a [&str]) -> &'a [&'a str] { fn remove_message_footer<'a>(lines: &'a [&str]) -> &'a [&'a str] {
let mut nearly_standard_footer = None; let mut nearly_standard_footer = None;
for (ix, &line) in lines.iter().enumerate() { for (ix, &line) in lines.iter().enumerate() {
@@ -41,6 +43,7 @@ fn remove_message_footer<'a>(lines: &'a [&str]) -> &'a [&'a str] {
/// Remove nonstandard footer and a boolean indicating whether such /// Remove nonstandard footer and a boolean indicating whether such
/// footer was removed. /// footer was removed.
#[allow(clippy::indexing_slicing)]
fn remove_nonstandard_footer<'a>(lines: &'a [&str]) -> (&'a [&'a str], bool) { fn remove_nonstandard_footer<'a>(lines: &'a [&str]) -> (&'a [&'a str], bool) {
for (ix, &line) in lines.iter().enumerate() { for (ix, &line) in lines.iter().enumerate() {
if line == "--" if line == "--"
@@ -107,6 +110,7 @@ fn skip_forward_header<'a>(lines: &'a [&str]) -> (&'a [&'a str], bool) {
} }
} }
#[allow(clippy::indexing_slicing)]
fn remove_bottom_quote<'a>(lines: &'a [&str]) -> (&'a [&'a str], bool) { fn remove_bottom_quote<'a>(lines: &'a [&str]) -> (&'a [&'a str], bool) {
let mut last_quoted_line = None; let mut last_quoted_line = None;
for (l, line) in lines.iter().enumerate().rev() { for (l, line) in lines.iter().enumerate().rev() {
@@ -132,6 +136,7 @@ fn remove_bottom_quote<'a>(lines: &'a [&str]) -> (&'a [&'a str], bool) {
} }
} }
#[allow(clippy::indexing_slicing)]
fn remove_top_quote<'a>(lines: &'a [&str]) -> (&'a [&'a str], bool) { fn remove_top_quote<'a>(lines: &'a [&str]) -> (&'a [&'a str], bool) {
let mut last_quoted_line = None; let mut last_quoted_line = None;
let mut has_quoted_headline = false; let mut has_quoted_headline = false;

View File

@@ -1,7 +1,5 @@
//! # SMTP transport module //! # SMTP transport module
#![forbid(clippy::indexing_slicing)]
pub mod send; pub mod send;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};

View File

@@ -586,6 +586,7 @@ pub async fn housekeeping(context: &Context) {
info!(context, "Housekeeping done.",); info!(context, "Housekeeping done.",);
} }
#[allow(clippy::indexing_slicing)]
fn is_file_in_use(files_in_use: &HashSet<String>, namespc_opt: Option<&str>, name: &str) -> bool { fn is_file_in_use(files_in_use: &HashSet<String>, namespc_opt: Option<&str>, name: &str) -> bool {
let name_to_check = if let Some(namespc) = namespc_opt { let name_to_check = if let Some(namespc) = namespc_opt {
let name_len = name.len(); let name_len = name.len();
@@ -600,6 +601,7 @@ fn is_file_in_use(files_in_use: &HashSet<String>, namespc_opt: Option<&str>, nam
files_in_use.contains(name_to_check) files_in_use.contains(name_to_check)
} }
#[allow(clippy::indexing_slicing)] // TODO: use str.strip_prefix once it is released in stable
fn maybe_add_file(files_in_use: &mut HashSet<String>, file: impl AsRef<str>) { fn maybe_add_file(files_in_use: &mut HashSet<String>, file: impl AsRef<str>) {
if !file.as_ref().starts_with("$BLOBDIR/") { if !file.as_ref().starts_with("$BLOBDIR/") {
return; return;