-
Notifications
You must be signed in to change notification settings - Fork 40
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
implement read-only auth #373
Changes from all commits
48f5629
96fb2f6
81a9bb6
b66933c
63dba80
b77b55b
f0cba4e
02214e0
88f9c99
0cdb6af
0c23798
e80aea0
fc50b41
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,14 @@ | ||
use std::collections::HashMap; | ||
|
||
use serde::{Deserialize, Serialize}; | ||
use serde_json::Value; | ||
|
||
#[derive(Serialize)] | ||
pub struct NewDocResponse { | ||
#[serde(rename = "docId")] | ||
pub doc_id: String, | ||
} | ||
|
||
#[derive(Serialize, Deserialize)] | ||
#[derive(Copy, Clone, Serialize, Deserialize)] | ||
pub enum Authorization { | ||
#[serde(rename = "none")] | ||
Nothing, | ||
#[serde(rename = "readonly")] | ||
#[serde(rename = "read-only")] | ||
ReadOnly, | ||
#[serde(rename = "full")] | ||
Full, | ||
|
@@ -26,14 +21,11 @@ impl Authorization { | |
} | ||
|
||
#[derive(Deserialize)] | ||
#[allow(unused)] | ||
pub struct AuthDocRequest { | ||
#[serde(default = "Authorization::full")] | ||
pub authorization: Authorization, | ||
#[serde(rename = "userId")] | ||
pub user_id: Option<String>, | ||
#[serde(default)] | ||
pub metadata: HashMap<String, Value>, | ||
#[serde(skip_serializing_if = "Option::is_none", rename = "validForSeconds")] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't use this at present. And if we did, we'd likely need to encode it into the token which we'd like to avoid since its length is unbounded. Let's just drop this field altogether. |
||
pub valid_for_seconds: Option<u64>, | ||
} | ||
|
@@ -43,7 +35,6 @@ impl Default for AuthDocRequest { | |
Self { | ||
authorization: Authorization::Full, | ||
user_id: None, | ||
metadata: HashMap::new(), | ||
valid_for_seconds: None, | ||
} | ||
} | ||
|
@@ -66,6 +57,10 @@ pub struct ClientToken { | |
/// An optional token that can be used to authenticate the client to the server. | ||
#[serde(skip_serializing_if = "Option::is_none")] | ||
pub token: Option<String>, | ||
|
||
/// The authorization level of the client. | ||
#[serde(rename = "authorization")] | ||
pub authorization: Authorization, | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're now returning |
||
|
||
#[derive(Deserialize, Debug)] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
use crate::api_types::Authorization; | ||
use crate::sync::{ | ||
self, awareness::Awareness, DefaultProtocol, Message, Protocol, SyncMessage, MSG_SYNC, | ||
MSG_SYNC_UPDATE, | ||
|
@@ -30,6 +31,7 @@ pub struct DocConnection { | |
doc_subscription: Subscription, | ||
#[allow(unused)] // acts as RAII guard | ||
awareness_subscription: Subscription, | ||
authorization: Authorization, | ||
callback: Callback, | ||
closed: Arc<OnceLock<()>>, | ||
|
||
|
@@ -48,14 +50,22 @@ impl DocConnection { | |
} | ||
|
||
#[cfg(feature = "sync")] | ||
pub fn new<F>(awareness: Arc<RwLock<Awareness>>, callback: F) -> Self | ||
pub fn new<F>( | ||
awareness: Arc<RwLock<Awareness>>, | ||
authorization: Authorization, | ||
callback: F, | ||
) -> Self | ||
where | ||
F: Fn(&[u8]) + 'static + Send + Sync, | ||
{ | ||
Self::new_inner(awareness, Arc::new(callback)) | ||
Self::new_inner(awareness, authorization, Arc::new(callback)) | ||
} | ||
|
||
pub fn new_inner(awareness: Arc<RwLock<Awareness>>, callback: Callback) -> Self { | ||
pub fn new_inner( | ||
awareness: Arc<RwLock<Awareness>>, | ||
authorization: Authorization, | ||
callback: Callback, | ||
) -> Self { | ||
let closed = Arc::new(OnceLock::new()); | ||
|
||
let (doc_subscription, awareness_subscription) = { | ||
|
@@ -127,6 +137,7 @@ impl DocConnection { | |
awareness, | ||
doc_subscription, | ||
awareness_subscription, | ||
authorization, | ||
callback, | ||
client_id: OnceLock::new(), | ||
closed, | ||
|
@@ -152,6 +163,7 @@ impl DocConnection { | |
protocol: &P, | ||
msg: Message, | ||
) -> Result<Option<Message>, sync::Error> { | ||
let can_write = matches!(self.authorization, Authorization::Full); | ||
let a = &self.awareness; | ||
match msg { | ||
Message::Sync(msg) => match msg { | ||
|
@@ -160,12 +172,24 @@ impl DocConnection { | |
protocol.handle_sync_step1(&awareness, sv) | ||
} | ||
SyncMessage::SyncStep2(update) => { | ||
let mut awareness = a.write().unwrap(); | ||
protocol.handle_sync_step2(&mut awareness, Update::decode_v1(&update)?) | ||
if can_write { | ||
let mut awareness = a.write().unwrap(); | ||
protocol.handle_sync_step2(&mut awareness, Update::decode_v1(&update)?) | ||
} else { | ||
Err(sync::Error::PermissionDenied { | ||
reason: "Token does not have write access".to_string(), | ||
}) | ||
} | ||
} | ||
SyncMessage::Update(update) => { | ||
let mut awareness = a.write().unwrap(); | ||
protocol.handle_update(&mut awareness, Update::decode_v1(&update)?) | ||
if can_write { | ||
let mut awareness = a.write().unwrap(); | ||
protocol.handle_update(&mut awareness, Update::decode_v1(&update)?) | ||
} else { | ||
Err(sync::Error::PermissionDenied { | ||
reason: "Token does not have write access".to_string(), | ||
}) | ||
Comment on lines
+189
to
+191
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we plan to make the clients aware of the authorization level as well? Not sure how these errors are logged/captured/etc but as of now this is an expected code path, since clients will send updates as though they have full write access. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, this just drops out before writing, and the resulting error gets logged in the y-sweet server. It shouldn't interrupt the websocket connection. I think we'll want to include the level of |
||
} | ||
} | ||
}, | ||
Message::Auth(reason) => { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This matches the types in the JS client library