mirror of
https://github.com/oxen-io/session-open-group-server.git
synced 2023-12-13 20:30:35 +01:00
Fix room image expiry, fix file pruning
Uploaded room images shouldn't expire; this makes the expiry column nullable and sets their expiry to null, and adds a trigger to expire replaced room images. Also fixes a panic in file deletion that made it not actually delete files.
This commit is contained in:
parent
5d21033743
commit
a126c072ec
3 changed files with 29 additions and 12 deletions
|
@ -71,6 +71,9 @@ pub const UPLOAD_FILENAME_MAX: usize = 60;
|
|||
pub const UPLOAD_FILENAME_KEEP_PREFIX: usize = 40;
|
||||
pub const UPLOAD_FILENAME_KEEP_SUFFIX: usize = 17;
|
||||
|
||||
// How long until an upload expires. TODO FIXME -- this could easily be a per-room property.
|
||||
// Note that room image uploads do not expire (until they are replaced).
|
||||
pub const UPLOAD_DEFAULT_EXPIRY: Duration = Duration::from_secs(15 * 86400);
|
||||
|
||||
// Backwards compatibility token sizes. We return a "token" consisting of [SESSIONID][SIGNATURE]
|
||||
// where SESSIONID is the provided session id (in bytes) and SIGNATURE is the session ID signed by
|
||||
|
@ -209,7 +212,13 @@ impl Drop for FileUpload<'_> {
|
|||
/// actions, but *must* call `.commit()` on success -- if dropped the FileUpload will clean up the
|
||||
/// temporary file and drop the transaction inserting the records.
|
||||
fn store_file_impl<'a>(
|
||||
conn: &'a mut storage::DatabaseConnection, room: &'a Room, user: &User, auth: AuthorizationRequired, data_b64: &str, filename: Option<&str>,
|
||||
conn: &'a mut storage::DatabaseConnection,
|
||||
room: &'a Room,
|
||||
user: &User,
|
||||
auth: AuthorizationRequired,
|
||||
data_b64: &str,
|
||||
filename: Option<&str>,
|
||||
expires: bool
|
||||
) -> Result<FileUpload<'a>, Rejection> {
|
||||
|
||||
// Determine the file size from the base64 data without decoding it (we'll do that later
|
||||
|
@ -248,10 +257,13 @@ fn store_file_impl<'a>(
|
|||
require_authorization(&upload.tx.as_ref().unwrap(), &user, &room, auth)?;
|
||||
|
||||
let db_filename: Option<String> = filename.map(|f| UPLOAD_FILENAME_BAD.replace_all(f, "_").into());
|
||||
let expiry: Option<f64> = if expires {
|
||||
Some((SystemTime::now() + UPLOAD_DEFAULT_EXPIRY).duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs_f64())
|
||||
} else { None };
|
||||
upload.id = match upload.tx.as_ref().unwrap().prepare_cached(
|
||||
"INSERT INTO files (room, uploader, size, filename, path) VALUES (?, ?, ?, ?, 'tmp') RETURNING id")
|
||||
"INSERT INTO files (room, uploader, size, expiry, filename, path) VALUES (?, ?, ?, ?, ?, 'tmp') RETURNING id")
|
||||
.map_err(db_error)?
|
||||
.query_row(params![room.id, user.id, bytes, db_filename], |row| row.get(0)) {
|
||||
.query_row(params![room.id, user.id, bytes, db_filename, expiry], |row| row.get(0)) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
error!("Couldn't insert file row: {}.", e);
|
||||
|
@ -317,7 +329,7 @@ pub fn store_file(
|
|||
let auth = AuthorizationRequired { upload: true, write: true, ..Default::default() };
|
||||
|
||||
let mut conn = storage::get_conn()?;
|
||||
let mut upload = match store_file_impl(&mut conn, &room, &user, auth, data_b64, filename) {
|
||||
let mut upload = match store_file_impl(&mut conn, &room, &user, auth, data_b64, filename, true) {
|
||||
Ok(id) => id,
|
||||
Err(e) => return Err(e)
|
||||
};
|
||||
|
@ -403,14 +415,12 @@ pub async fn set_room_image(
|
|||
let auth = AuthorizationRequired { moderator: true, ..Default::default() };
|
||||
|
||||
let mut conn = storage::get_conn()?;
|
||||
let mut upload = store_file_impl(&mut conn, &room, &user, auth, data_b64, filename)?;
|
||||
let mut upload = store_file_impl(&mut conn, &room, &user, auth, data_b64, filename, false)?;
|
||||
|
||||
if let Err(e) = upload.prepare_cached("UPDATE rooms SET image = ? WHERE id = ?")
|
||||
upload.prepare_cached("UPDATE rooms SET image = ? WHERE id = ?")
|
||||
.map_err(db_error)?
|
||||
.execute(params![upload.id, room.id]) {
|
||||
error!("Failed to update room file: {}", e);
|
||||
return Err(Error::DatabaseFailedInternally.into());
|
||||
}
|
||||
.execute(params![upload.id, room.id])
|
||||
.map_err(db_error)?;
|
||||
|
||||
if let Err(e) = upload.commit() {
|
||||
error!("File upload failed: {}", e);
|
||||
|
|
|
@ -18,6 +18,13 @@ CREATE TABLE rooms (
|
|||
);
|
||||
CREATE INDEX rooms_token ON rooms(token);
|
||||
|
||||
-- Trigger to expire an old room image attachment when the room image is changed
|
||||
CREATE TRIGGER room_image_expiry AFTER UPDATE ON rooms
|
||||
FOR EACH ROW WHEN NEW.image IS NOT OLD.image AND OLD.image IS NOT NULL
|
||||
BEGIN
|
||||
UPDATE files SET expiry = 0.0 WHERE id = OLD.image;
|
||||
END;
|
||||
|
||||
CREATE TABLE messages (
|
||||
id INTEGER NOT NULL PRIMARY KEY,
|
||||
room INTEGER NOT NULL REFERENCES rooms(id) ON DELETE CASCADE,
|
||||
|
@ -95,7 +102,7 @@ CREATE TABLE files (
|
|||
uploader INTEGER REFERENCES users(id),
|
||||
size INTEGER NOT NULL,
|
||||
uploaded FLOAT NOT NULL DEFAULT ((julianday('now') - 2440587.5)*86400.0), /* unix epoch */
|
||||
expiry FLOAT NOT NULL DEFAULT ((julianday('now') - 2440587.5 + 15.0)*86400.0), /* unix epoch */
|
||||
expiry FLOAT DEFAULT ((julianday('now') - 2440587.5 + 15.0)*86400.0), /* unix epoch */
|
||||
filename TEXT, /* user-provided filename */
|
||||
path TEXT NOT NULL /* path on disk */
|
||||
);
|
||||
|
|
|
@ -152,7 +152,7 @@ fn prune_files(conn: &mut DatabaseConnection, now: &SystemTime) {
|
|||
|
||||
let mut count = 0;
|
||||
while let Ok(Some(row)) = rows.next() {
|
||||
if let Ok(path) = row.get_ref_unwrap(1).as_str() {
|
||||
if let Ok(path) = row.get_ref_unwrap(0).as_str() {
|
||||
if let Err(e) = fs::remove_file(path) {
|
||||
error!("Couldn't delete expired file '{}': {}", path, e);
|
||||
} else {
|
||||
|
|
Loading…
Reference in a new issue