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;
// only use the oldest and and the parent message
let parent_references = if let Some(n) = parent_references.find(' ') {
&parent_references[0..n]
} else {
&parent_references
};
let parent_references = parent_references
.find(' ')
.and_then(|n| parent_references.get(..n))
.unwrap_or(&parent_references);
if !parent_references.is_empty() && !parent_rfc724_mid.is_empty() {
// angle brackets are added by the mimefactory later

View File

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

View File

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

View File

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

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
/// end of the shortened string.
#[allow(clippy::indexing_slicing)]
pub(crate) fn dc_truncate(buf: &str, approx_chars: usize) -> Cow<str> {
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,
];
#[allow(clippy::indexing_slicing)]
pub(crate) fn dc_str_to_color(s: impl AsRef<str>) -> u32 {
let str_lower = s.as_ref().to_lowercase();
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 {
let hostname = from_addr
.find('@')
.map(|k| &from_addr[k..])
.and_then(|k| from_addr.get(k..))
.unwrap_or("@nohost");
match grpid {
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: {}",
mail.ctype.mimetype
);
ensure!(
mail.subparts.len() == 2,
"Invalid Autocrypt Level 1 Mime Parts"
);
if let [first_part, second_part] = &mail.subparts[..] {
ensure!(
first_part.ctype.mimetype == "application/pgp-encrypted",
"Invalid Autocrypt Level 1 version part: {:?}",
first_part.ctype,
);
ensure!(
mail.subparts[0].ctype.mimetype == "application/pgp-encrypted",
"Invalid Autocrypt Level 1 version part: {:?}",
mail.subparts[0].ctype,
);
ensure!(
second_part.ctype.mimetype == "application/octet-stream",
"Invalid Autocrypt Level 1 encrypted part: {:?}",
second_part.ctype
);
ensure!(
mail.subparts[1].ctype.mimetype == "application/octet-stream",
"Invalid Autocrypt Level 1 encrypted part: {:?}",
mail.subparts[1].ctype
);
Ok(&mail.subparts[1])
Ok(second_part)
} else {
bail!("Invalid Autocrypt Level 1 Mime Parts")
}
}
async fn decrypt_if_autocrypt_message<'a>(
@@ -267,6 +266,7 @@ async fn decrypt_part(
Ok(None)
}
#[allow(clippy::indexing_slicing)]
fn has_decrypted_pgp_armor(input: &[u8]) -> bool {
if let Some(index) = input.iter().position(|b| *b > b' ') {
if input.len() - index > 26 {

View File

@@ -3,8 +3,6 @@
//! uses [async-email/async-imap](https://github.com/async-email/async-imap)
//! to implement connect, fetch, delete functionality with standard IMAP servers.
#![forbid(clippy::indexing_slicing)]
use std::collections::BTreeMap;
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.
pub async fn render_setup_file(context: &Context, passphrase: &str) -> Result<String> {
ensure!(
passphrase.len() >= 2,
"Passphrase must be at least 2 chars long."
);
let passphrase_begin = if let Some(passphrase_begin) = passphrase.get(..2) {
passphrase_begin
} else {
bail!("Passphrase must be at least 2 chars long.");
};
let private_key = SignedSecretKey::load_self(context).await?;
let ac_headers = match context.get_config_bool(Config::E2eeEnabled).await {
false => None,
@@ -196,7 +197,7 @@ pub async fn render_setup_file(context: &Context, passphrase: &str) -> Result<St
"Passphrase-Format: numeric9x4\r\n",
"Passphrase-Begin: {}"
),
&passphrase[..2]
passphrase_begin
);
let pgp_msg = encr.replace("-----BEGIN PGP MESSAGE-----", &replacement);

View File

@@ -1,5 +1,10 @@
#![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)]
#[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
/// 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) {
if let [textpart, filepart] = &self.parts[..] {
let need_drop = {
@@ -272,34 +273,34 @@ impl MimeMessage {
fn parse_attachments(&mut self) {
// Attachment messages should be squashed into a single part
// before calling this function.
if self.parts.len() == 1 {
if self.parts[0].typ == Viewtype::Audio
&& self.get(HeaderDef::ChatVoiceMessage).is_some()
{
let part_mut = &mut self.parts[0];
if self.parts.len() != 1 {
return;
}
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;
}
if self.parts[0].typ == Viewtype::Image {
if part_mut.typ == Viewtype::Image {
if let Some(value) = self.get(HeaderDef::ChatContent) {
if value == "sticker" {
let part_mut = &mut self.parts[0];
part_mut.typ = Viewtype::Sticker;
}
}
}
let part = &self.parts[0];
if part.typ == Viewtype::Audio
|| part.typ == Viewtype::Voice
|| part.typ == Viewtype::Video
if part_mut.typ == Viewtype::Audio
|| part_mut.typ == Viewtype::Voice
|| part_mut.typ == Viewtype::Video
{
if let Some(field_0) = self.get(HeaderDef::ChatDuration) {
let duration_ms = field_0.parse().unwrap_or_default();
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);
}
}
}
self.parts.push(part_mut);
}
}
@@ -321,12 +322,11 @@ impl MimeMessage {
}
}
if prepend_subject {
let subj = if let Some(n) = subject.find('[') {
&subject[0..n]
} else {
subject
}
.trim();
let subj = subject
.find('[')
.and_then(|n| subject.get(..n))
.unwrap_or(subject)
.trim();
if !subj.is_empty() {
for part in self.parts.iter_mut() {
@@ -384,8 +384,7 @@ impl MimeMessage {
Some(AvatarAction::Delete)
} else {
let mut i = 0;
while i != self.parts.len() {
let part = &mut self.parts[i];
while let Some(part) = self.parts.get_mut(i) {
if let Some(part_filename) = &part.org_filename {
if part_filename == &header_value {
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>) {
if self.parts.is_empty() {
return;
if let Some(part) = self.parts.first_mut() {
part.typ = Viewtype::Text;
part.msg = format!("[{}]", error_msg.as_ref());
self.parts.truncate(1);
}
let part = &mut self.parts[0];
part.typ = Viewtype::Text;
part.msg = format!("[{}]", error_msg.as_ref());
self.parts.truncate(1);
assert_eq!(self.parts.len(), 1);
}
pub fn get_rfc724_mid(&self) -> Option<String> {
@@ -830,7 +824,11 @@ impl MimeMessage {
report: &mailparse::ParsedMail<'_>,
) -> Result<Option<Report>> {
// 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)?;
// must be present
@@ -908,6 +906,7 @@ impl MimeMessage {
/// 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.
/// 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<()> {
let maybe_ndn = if let Some(from) = self.get(HeaderDef::From_) {
let from = from.to_ascii_lowercase();
@@ -966,11 +965,10 @@ impl MimeMessage {
if let Some(failure_report) = &self.failure_report {
let error = parts.iter().find(|p| p.typ == Viewtype::Text).map(|p| {
let msg = &p.msg;
match msg.find("\n--- ") {
Some(footer_start) => &msg[..footer_start],
None => msg,
}
.trim()
msg.find("\n--- ")
.and_then(|footer_start| msg.get(..footer_start))
.unwrap_or(msg)
.trim()
});
message::handle_ndn(context, failure_report, error).await
}
@@ -1036,6 +1034,7 @@ pub(crate) struct FailureReport {
pub failed_recipient: Option<String>,
}
#[allow(clippy::indexing_slicing)]
pub(crate) fn parse_message_ids(ids: &str) -> Result<Vec<String>> {
// take care with mailparse::msgidparse() that is pretty untolerant eg. wrt missing `<` or `>`
let mut msgids = Vec::new();

View File

@@ -171,7 +171,7 @@ impl str::FromStr for Params {
let key = key.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());
} else {
bail!("Unknown key: {}", key);

View File

@@ -365,11 +365,13 @@ pub async fn symm_decrypt<T: std::io::Read + std::io::Seek>(
let decryptor = enc_msg.decrypt_with_password(|| passphrase)?;
let msgs = decryptor.collect::<pgp::errors::Result<Vec<_>>>()?;
ensure!(!msgs.is_empty(), "No valid messages found");
match msgs[0].get_content()? {
Some(content) => Ok(content),
None => bail!("Decrypted message is empty"),
if let Some(msg) = msgs.first() {
match msg.get_content()? {
Some(content) => Ok(content),
None => bail!("Decrypted message is empty"),
}
} else {
bail!("No valid messages found")
}
})
.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`
/// 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 {
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`
#[allow(clippy::indexing_slicing)]
fn decode_account(_context: &Context, qr: &str) -> Lot {
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,
/// 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
#[allow(clippy::indexing_slicing)]
pub async fn set_config_from_qr(context: &Context, qr: &str) -> Result<(), Error> {
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.
///
/// Scheme: `mailto:addr...?subject=...&body=..`
#[allow(clippy::indexing_slicing)]
async fn decode_mailto(context: &Context, qr: &str) -> Lot {
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.
///
/// Scheme: `SMTP:addr...:subject...:body...`
#[allow(clippy::indexing_slicing)]
async fn decode_smtp(context: &Context, qr: &str) -> Lot {
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...;`
///
/// There may or may not be linebreaks after the fields.
#[allow(clippy::indexing_slicing)]
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.
// we ignore this case.
@@ -316,14 +322,15 @@ lazy_static! {
/// Extract address for the matmsg scheme.
///
/// Scheme: `VCARD:BEGIN\nN:last name;first name;...;\nEMAIL;<type>:addr...;
#[allow(clippy::indexing_slicing)]
async fn decode_vcard(context: &Context, qr: &str) -> Lot {
let name = VCARD_NAME_RE
.captures(qr)
.map(|caps| {
let last_name = &caps[1];
let first_name = &caps[2];
.and_then(|caps| {
let last_name = caps.get(1)?.as_str().trim();
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();

View File

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

View File

@@ -6,6 +6,7 @@
// 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.
// (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 {
if text.starts_with("--") {
"-\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.
#[allow(clippy::indexing_slicing)]
fn remove_message_footer<'a>(lines: &'a [&str]) -> &'a [&'a str] {
let mut nearly_standard_footer = None;
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
/// footer was removed.
#[allow(clippy::indexing_slicing)]
fn remove_nonstandard_footer<'a>(lines: &'a [&str]) -> (&'a [&'a str], bool) {
for (ix, &line) in lines.iter().enumerate() {
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) {
let mut last_quoted_line = None;
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) {
let mut last_quoted_line = None;
let mut has_quoted_headline = false;

View File

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

View File

@@ -586,6 +586,7 @@ pub async fn housekeeping(context: &Context) {
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 {
let name_to_check = if let Some(namespc) = namespc_opt {
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)
}
#[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>) {
if !file.as_ref().starts_with("$BLOBDIR/") {
return;