mirror of
https://github.com/narrrl/proton-sdk-rs.git
synced 2026-11-03 16:41:26 +01:00
feature (public link retrievel)
This commit is contained in:
1 parent
64f977edb3
commit
2fa9b90265
2 files changed
+41
-12
No files matched your search
@@ -54,10 +54,10 @@ use crate::dtos::{
|
||||
NodeNameAvailabilityRequest, NodeNameAvailabilityResponse, PhotosAttributesDto,
|
||||
RenameLinkRequest, RevisionCreationRequest, RevisionCreationResponse, RevisionDto,
|
||||
RevisionResponse, RevisionUpdateRequest, ShareInvitationDto, ShareInvitationsResponse,
|
||||
ShareMembersResponse, ShareResponse, ShareTargetType, ShareUrlsResponse, SharedWithMeResponse,
|
||||
ThumbnailBlockListRequest, ThumbnailBlockListResponse, ThumbnailCreationRequest, ThumbnailDto,
|
||||
TimelinePhotoListResponse, UpdatePermissionsRequest, VolumeCreationRequest, VolumeEventDto,
|
||||
VolumeEventListResponse, VolumeTrashResponse,
|
||||
ShareMembersResponse, ShareResponse, ShareTargetType, ShareUrlDto, ShareUrlsResponse,
|
||||
SharedWithMeResponse, ThumbnailBlockListRequest, ThumbnailBlockListResponse,
|
||||
ThumbnailCreationRequest, ThumbnailDto, TimelinePhotoListResponse, UpdatePermissionsRequest,
|
||||
VolumeCreationRequest, VolumeEventDto, VolumeEventListResponse, VolumeTrashResponse,
|
||||
};
|
||||
use crate::events::{DriveEvent, DriveEventScopeId};
|
||||
use crate::node::{FileThumbnail, Node, NodeKind, RevisionState, Thumbnail, ThumbnailType};
|
||||
@@ -1889,22 +1889,23 @@ impl ProtonDriveClient {
|
||||
})
|
||||
}
|
||||
|
||||
/// The public link on a node, if one exists (metadata only — the secret URL
|
||||
/// fragment is not reconstructed).
|
||||
/// The public link on a node, if one exists. The secret URL fragment is
|
||||
/// recovered by decrypting the stored link password with the owner's address
|
||||
/// key and taking the generated (non-custom) portion — the same recovery the
|
||||
/// web client does when re-displaying an existing link.
|
||||
pub async fn get_public_link(&self, uid: &NodeUid) -> Result<Option<PublicLink>> {
|
||||
let mut timer = self.telemetry.start("get_public_link");
|
||||
let link = match self.node_share_id(uid).await? {
|
||||
Some(share_id) => {
|
||||
let path = format!("shares/{share_id}/urls");
|
||||
let response: ShareUrlsResponse = self.http.get(&path).await?;
|
||||
response
|
||||
.share_urls
|
||||
.into_iter()
|
||||
.next()
|
||||
.map(|dto| PublicLink {
|
||||
match response.share_urls.into_iter().next() {
|
||||
Some(dto) => {
|
||||
let url = self.recover_public_link_url(&dto).await;
|
||||
Some(PublicLink {
|
||||
share_id,
|
||||
public_link_id: dto.share_url_id,
|
||||
url: None,
|
||||
url,
|
||||
role: MemberRole::from_permissions(dto.permissions),
|
||||
creation_time: dto.create_time,
|
||||
expiration_time: dto.expiration_time,
|
||||
@@ -1912,11 +1913,34 @@ impl ProtonDriveClient {
|
||||
})
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
timer.success();
|
||||
Ok(link)
|
||||
}
|
||||
|
||||
/// Rebuild the full public URL (`{public_url}#{generated}`) for an existing
|
||||
/// link by decrypting its stored `Password` with the owner's address key. The
|
||||
/// stored secret is the generated password with any custom password appended;
|
||||
/// only the leading generated portion belongs in the URL fragment (the
|
||||
/// recipient supplies the custom password separately). Returns `None` if the
|
||||
/// link carries no password or it can't be decrypted, so the caller still gets
|
||||
/// the link's metadata.
|
||||
async fn recover_public_link_url(&self, dto: &ShareUrlDto) -> Option<String> {
|
||||
if dto.public_url.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let enc = dto.password.as_deref()?;
|
||||
let (_, email, _) = self.membership_address().await.ok()?;
|
||||
let (address_keys, _) = self.own_address_keys(&email).await.ok()?;
|
||||
let bytes = decrypt_armored_with_keys(enc, &address_keys).ok()?;
|
||||
let full = String::from_utf8_lossy(&bytes);
|
||||
let generated: String = full.chars().take(PUBLIC_LINK_PASSWORD_LEN).collect();
|
||||
Some(format!("{}#{generated}", dto.public_url))
|
||||
}
|
||||
|
||||
/// Remove a public link, revoking access via the URL
|
||||
/// (`DELETE shares/{sid}/urls/{urlID}`).
|
||||
pub async fn remove_public_link(&self, link: &PublicLink) -> Result<()> {
|
||||
|
||||
@@ -1522,6 +1522,11 @@ pub struct ShareUrlDto {
|
||||
pub share_id: Option<ShareId>,
|
||||
#[serde(rename = "PublicUrl", default)]
|
||||
pub public_url: String,
|
||||
/// The link password (generated portion + any custom password), PGP-encrypted
|
||||
/// to the share creator's address key. Decrypting it recovers the secret URL
|
||||
/// fragment. Absent on the create response, present when listing.
|
||||
#[serde(rename = "Password", default)]
|
||||
pub password: Option<String>,
|
||||
#[serde(rename = "CreateTime", default)]
|
||||
pub create_time: i64,
|
||||
#[serde(rename = "ExpirationTime", default)]
|
||||
|
||||
Reference in new issue
Block a user