Don't store padding in db

Trim padding when storing and repad on the fly when retrieving.
This commit is contained in:
Jason Rhinelander 2021-09-27 18:18:24 -03:00
parent c0e0d61dbf
commit 4e27e8d60b
3 changed files with 28 additions and 8 deletions

View File

@ -557,10 +557,19 @@ pub fn insert_message(
if recent_posts >= RATE_LIMIT_POSTS {
return Err(warp::reject::custom(Error::RateLimited));
}
// Don't store useless padding; we'll repad (since it's needed for signature verification) when
// we retrieve.
let size = data.len();
let trimmed = match data.iter().rposition(|&c| c != 0u8) {
Some(last) => &data[0..last+1],
None => &data
};
// Insert the message
let message = match tx.prepare_cached("INSERT INTO messages (room, user, data, signature) VALUES (?, ?, ?, ?) RETURNING *")
let message = match tx.prepare_cached("INSERT INTO messages (room, user, data, data_size, signature) VALUES (?, ?, ?, ?, ?) RETURNING *")
.map_err(db_error)?
.query_row(params![room.id, user.id, data, signature], OldMessage::from_row) {
.query_row(params![room.id, user.id, trimmed, size, signature], OldMessage::from_row) {
Ok(m) => m,
Err(e) => {
error!("Couldn't insert message: {}.", e);
@ -670,7 +679,7 @@ pub fn delete_message(
require_authorization(conn, user, room, auth_req)?;
let mut del_st = conn.prepare_cached("UPDATE messages SET data = NULL, signature = NULL WHERE id = ?")
let mut del_st = conn.prepare_cached("UPDATE messages SET data = NULL, data_size = NULL, signature = NULL WHERE id = ?")
.map_err(db_error)?;
if let Err(e) = del_st.execute(params![id]) {
@ -879,7 +888,7 @@ pub async fn ban(session_id: &str, delete_all: bool, user: &User, room: &Room) -
let mut posts_removed = 0;
let mut files_removed = 0;
if delete_all {
posts_removed += match tx.prepare_cached("UPDATE messages SET data = NULL, signature = NULL WHERE room = ? AND user = ?")
posts_removed += match tx.prepare_cached("UPDATE messages SET data = NULL, data_size = NULL, signature = NULL WHERE room = ? AND user = ?")
.map_err(db_error)?
.execute(params![room.id, userid]) {
Ok(count) => count,

View File

@ -56,7 +56,8 @@ pub struct OldMessage {
impl OldMessage {
pub fn from_row(row: &rusqlite::Row) -> Result<OldMessage, rusqlite::Error> {
let data: Option<Vec<u8>> = row.get(row.column_index("data")?)?;
let mut data: Option<Vec<u8>> = row.get(row.column_index("data")?)?;
repad(&mut data, row.get::<_, Option<usize>>(row.column_index("data_size")?)?);
let session_id = match row.column_index("session_id") {
Ok(index) => Some(row.get(index)?),
Err(_) => None
@ -98,9 +99,18 @@ pub struct Message {
pub deleted: Option<bool>,
}
fn repad(data: &mut Option<Vec<u8>>, size: Option<usize>) {
if let Some(size) = size {
if data.is_some() && data.as_ref().unwrap().len() < size {
data.as_mut().unwrap().resize(size, 0);
}
}
}
impl Message {
pub fn from_row(row: &rusqlite::Row) -> Result<Message, rusqlite::Error> {
let data: Option<Vec<u8>> = row.get(row.column_index("data")?)?;
let mut data: Option<Vec<u8>> = row.get(row.column_index("data")?)?;
repad(&mut data, row.get::<_, Option<usize>>(row.column_index("data_size")?)?);
let deleted = if data.is_none() { Some(true) } else { None };
let session_id = match row.column_index("session_id") {
Ok(index) => Some(row.get(index)?),

View File

@ -66,7 +66,8 @@ CREATE TABLE messages (
posted FLOAT NOT NULL DEFAULT ((julianday('now') - 2440587.5)*86400.0), /* unix epoch */
edited FLOAT,
updated INTEGER NOT NULL DEFAULT 0, /* set to the room's `updates` counter when posted/edited/deleted */
data BLOB, /* Actual message content; set to null to delete a message */
data BLOB, /* Actual message content, not including trailing padding; set to null to delete a message */
data_size INTEGER, /* The message size, including trailing padding (needed because the signature is over the padded data) */
signature BLOB /* Signature of `data` by `public_key`; set to null when deleting a message */
);
CREATE INDEX messages_room ON messages(room, posted);
@ -184,7 +185,7 @@ SELECT messages.*, users.session_id FROM messages JOIN users ON messages.user =
-- View of `messages` that is useful for manually inspecting table contents by only returning the
-- length (rather than raw bytes) for data/signature.
CREATE VIEW message_metadata AS
SELECT id, room, user, session_id, posted, edited, updated, length(data) AS data_length, length(signature) as signature_length
SELECT id, room, user, session_id, posted, edited, updated, length(data) AS data_unpadded, data_size, length(signature) as signature_length
FROM message_details;