session-open-group-server/src/models.rs
2021-10-14 15:00:32 +11:00

315 lines
12 KiB
Rust

use base64;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[derive(Debug, Deserialize, Serialize)]
pub struct User {
pub id: i64,
pub session_id: String,
pub created: f64,
pub last_active: f64,
pub banned: bool,
pub moderator: bool,
pub admin: bool,
}
impl User {
pub fn from_row(row: &rusqlite::Row) -> Result<User, rusqlite::Error> {
return Ok(User {
id: row.get(row.column_index("id")?)?,
session_id: row.get(row.column_index("session_id")?)?,
created: row.get(row.column_index("created")?)?,
last_active: row.get(row.column_index("last_active")?)?,
banned: row.get(row.column_index("banned")?)?,
moderator: row.get(row.column_index("moderator")?)?,
admin: row.get(row.column_index("admin")?)?,
});
}
}
fn as_opt_base64<S>(val: &Option<Vec<u8>>, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
s.serialize_str(&base64::encode(val.as_ref().unwrap()))
}
/// Old message structure returned by the deprecated compact_poll endpoint.
#[derive(Debug, Serialize)]
pub struct OldMessage {
/// Server-side message id. Migration: this becomes `id` in the new Message format.
pub server_id: i64,
/// Session id of the poster. Omitted when the information isn't available/useful (such as
/// submitting new messages). Migration: this becomes `session_id` in the new Message format.
#[serde(skip_serializing_if = "Option::is_none")]
pub public_key: Option<String>,
/// Timestamp, in unix epoch milliseconds. Migration: in the new Message format this value is
/// a floating point value (rather than integer) *and* is returned as actual unix time (i.e.
/// seconds) rather than milliseconds.
pub timestamp: i64,
/// Message data, encoded in base64
#[serde(serialize_with = "as_opt_base64")]
pub data: Option<Vec<u8>>,
/// XEd25519 message signature of the `data` bytes (not the base64 representation), encoded in
/// base64
#[serde(serialize_with = "as_opt_base64")]
pub signature: Option<Vec<u8>>,
}
impl OldMessage {
pub fn from_row(row: &rusqlite::Row) -> Result<OldMessage, rusqlite::Error> {
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,
};
return Ok(OldMessage {
server_id: row.get(row.column_index("id")?)?,
public_key: session_id,
timestamp: (row.get::<_, f64>(row.column_index("posted")?)? * 1000.0) as i64,
data,
signature: row.get(row.column_index("signature")?)?,
});
}
}
#[derive(Debug, Serialize)]
pub struct Message {
/// The message id.
pub id: i64,
/// The session ID of the user who posted this message, in hex. Omitted in contexts where the
/// information isn't available or isn't useful, such as when inserting a message.
#[serde(skip_serializing_if = "Option::is_none")]
pub session_id: Option<String>,
/// unix timestamp of when the message was received on the server.
pub timestamp: f64,
/// unix timestamp of when the message was last edited (null if never edited).
pub edited: Option<f64>,
/// set to the room's current `updates` value at the time this message was created, last
/// edited, or deleted.
pub updated: i64,
/// The message data, encoded in base64. This field is omitted if the message is deleted.
#[serde(skip_serializing_if = "Option::is_none", serialize_with = "as_opt_base64")]
pub data: Option<Vec<u8>>,
/// The message signature, encoded in base64. This field is omitted if the message is deleted.
#[serde(skip_serializing_if = "Option::is_none", serialize_with = "as_opt_base64")]
pub signature: Option<Vec<u8>>,
/// Flag set to true if the message is deleted, and omitted otherwise.
#[serde(skip_serializing_if = "Option::is_none")]
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 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)?),
Err(_) => None,
};
return Ok(Message {
id: row.get(row.column_index("id")?)?,
session_id,
timestamp: row.get(row.column_index("posted")?)?,
edited: row.get(row.column_index("edited")?)?,
updated: row.get(row.column_index("updated")?)?,
data,
signature: row.get(row.column_index("signature")?)?,
deleted,
});
}
}
fn bytes_from_base64<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
use serde::de::Error;
String::deserialize(deserializer)
.and_then(|str| base64::decode(&str).map_err(|err| Error::custom(err.to_string())))
}
#[derive(Debug, Deserialize)]
pub struct PostMessage {
#[serde(deserialize_with = "bytes_from_base64")]
pub data: Vec<u8>,
#[serde(deserialize_with = "bytes_from_base64")]
pub signature: Vec<u8>,
}
#[derive(Debug, Serialize)]
pub struct DeletedMessage {
#[serde(rename = "id")]
pub updated: i64,
pub deleted_message_id: i64,
}
#[derive(Debug, Serialize)]
pub struct Room {
#[serde(skip)]
pub id: i64,
#[serde(rename = "id")]
pub token: String,
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub image_file_id: Option<i64>,
pub created: f64,
pub updates: i64,
pub default_read: bool,
pub default_write: bool,
pub default_upload: bool,
}
impl Room {
pub fn from_row(row: &rusqlite::Row) -> Result<Room, rusqlite::Error> {
return Ok(Room {
id: row.get(row.column_index("id")?)?,
token: row.get(row.column_index("token")?)?,
name: row.get(row.column_index("name")?)?,
description: row.get(row.column_index("description")?)?,
image_file_id: row.get(row.column_index("image")?)?,
created: row.get(row.column_index("created")?)?,
updates: row.get(row.column_index("updates")?)?,
default_read: row.get(row.column_index("read")?)?,
default_write: row.get(row.column_index("write")?)?,
default_upload: row.get(row.column_index("upload")?)?,
});
}
}
// FIXME: this appears to be used for both add/remove. But what if we want to promote to admin, or
// demote to moderator?
#[derive(Debug, Deserialize)]
pub struct ChangeModeratorRequestBody {
#[serde(rename = "room_id")]
pub room_token: String,
#[serde(rename = "public_key")]
pub session_id: String,
pub admin: Option<bool>,
}
#[derive(Debug, Deserialize)]
pub struct PollRoomMetadata {
/// Token of the room to poll
pub room: String,
/// The last `info_update` value the client has; results are only returned if the room has been
/// modified since the value provided by the client.
pub since_update: i64,
}
#[derive(Debug, Serialize)]
pub struct RoomDetails {
/// The token of this room
pub token: String,
/// Number of recently active users in the room
pub active_users: i64,
/// Metadata of the room; this omitted from the response when polling if the room metadata
/// (other than active user count) has not changed since the request update counter.
#[serde(skip_serializing_if = "Option::is_none")]
pub details: Option<RoomMetadata>,
}
#[derive(Debug, Serialize)]
pub struct RoomMetadata {
/// A counter that is updated whenever this room's metadata changes; clients are expected to
/// poll for updates using this id.
pub info_update: i64,
/// Unix timestamp (seconds since epoch) when this room was created
pub created: f64,
/// The human-readable room name
pub name: String,
/// Text description of the room
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
/// ID of an uploaded file that contains the image for this room
#[serde(skip_serializing_if = "Option::is_none")]
pub image_id: Option<i64>,
/// IDs of any pinned message in this room.
pub pinned_messages: Vec<i64>,
/// List of non-admin public moderator Session IDs. This list includes both room-specific and
/// global moderators, but not admins and only if the moderator is configured as visible.
pub moderators: Vec<String>,
/// List of public admin session IDs for this room. In addition to everything moderators can
/// do, admins can also add/remove/ban other moderators and admins. As with `moderators` only
/// visible admins are included.
pub admins: Vec<String>,
/// List of hidden moderator Session IDs. This field is omitted if the requesting user is not
/// a moderator or admin.
#[serde(skip_serializing_if = "Option::is_none")]
pub hidden_mods: Option<Vec<String>>,
/// List of hidden admin Session IDs. This field is omitted if the requesting user is not a
/// moderator or admin.
#[serde(skip_serializing_if = "Option::is_none")]
pub hidden_admins: Option<Vec<String>>,
/// Will be present and true if the requesting user has moderator powers, omitted otherwise.
#[serde(skip_serializing_if = "Option::is_none")]
pub moderator: Option<bool>,
/// Will be present and true if the requesting user has admin powers, omitted otherwise.
pub admin: Option<bool>,
}
#[derive(Debug, Deserialize)]
pub struct PollRoomMessages {
/// Token of the room to poll for messages.
pub room: String,
/// Return new messages, edit, and deletions posted since this `updates` value. Clients should
/// poll with the most recent updates value they have received.
pub since_update: i64,
}
#[derive(Debug, Serialize)]
pub struct RoomMessages {
/// The token of this room
pub room: String,
/// Vector of new/edited/deleted message posted to the room since the requested update.
pub messages: Vec<Message>,
}
#[derive(Debug, Deserialize)]
pub struct CompactPollRequestBody {
#[serde(rename = "room_id")]
pub room_token: String,
// Deprecated: older Session clients pass the authorization token through this. Newer clients
// should use signed requests instead.
pub auth_token: Option<String>,
// Input parameters to query. If these are omitted (or null) then this returns the latest 256
// messages/deletions, in reverse order from what you get with regular polling. New clients
// should update to the new polling endpoints ASAP.
pub from_message_server_id: Option<i64>,
pub from_deletion_server_id: Option<i64>,
}
#[derive(Debug, Serialize)]
pub struct CompactPollResponseBody {
#[serde(rename = "room_id")]
pub room_token: String,
pub status_code: u16,
pub deletions: Vec<DeletedMessage>,
pub messages: Vec<OldMessage>,
pub moderators: Vec<String>,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct Challenge {
pub ciphertext: String,
pub ephemeral_public_key: String,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct StatusCode {
pub status_code: u16,
}