Filen.io is a cloud storage provider with an open-source desktop client.

Overview

Library to call Filen.io API from Rust

Filen.io is a cloud storage provider with an open-source desktop client. My goal is to write a library which calls Filen's API in a meaningful way, and to learn Rust in process. Filen's API is currently undocumented and I try to get it right by studying the client's sources, so take it all with a grain of salt.

This library is not in a usable state. It is possible to login, receive user's RSA keys, perform CRUD on user folders, check Filen Sync folder contents and rename/move/trash files, and even download decrypted files, but file uploading and sharing/linking are still not done.

If you're interested, that's how it looks:

Some examples

Import all we need for exemplary purposes:

use crate::{filen_settings::FilenSettings, retry_settings::RetrySettings, v1::auth, v1::fs::*};
use anyhow::*;  // or crate::anyhow::*, it re-exports anyhow just in case
use secstr::SecUtf8;    // or crate::secstr::SecUtf8, it re-exports secstr just in case

There are async versions of every API query, but examples will be blocking, this README is big enough as it is. Let's login first.

Getting auth info

Actually, before logging in, we have to know how to do so.

// First let's calculate Filen password used for logging in.
// For that we need to know user's password, of course,
// and 'version' number which tells us which encryption algorithm to use.
// To get it all, call `/auth/info` endpoint:
let user_email = SecUtf8::from("[email protected]");
let user_password = SecUtf8::from("user.password.in.plaintext");
let user_two_factor_key = SecUtf8::from("XXXXXX"); // Filen actually uses XXXXXX when 2FA is absent.
let filen_settings = FilenSettings::default();  // Provides Filen server URLs.

let auth_info_request_payload = auth::AuthInfoRequestPayload {
    email: user_email.clone(),
    two_factor_key: user_two_factor_key.clone(),
};
let auth_info_response = auth::auth_info_request(&auth_info_request_payload, &filen_settings)?;
if !auth_info_response.status || auth_info_response.data.is_none() {
    bail!("Filen API failed to return auth info: {:?}", auth_info_response.message);
}
let auth_info_response_data = auth_info_response.data.unwrap();
// filen_password_with_master_key() helper calculates Filen password for us,
// depending on returned auth_info_response_data.
let filen_password_and_m_key = auth_info_response_data
    .filen_password_with_master_key(&user_password)
    .unwrap();

Logging in

// Now that we have Filen password, we can login. Master key is not needed for login,
// but is also very important, since it is used often throughout the API to encrypt/decrypt metadata.
let login_request_payload = auth::LoginRequestPayload {
    email: user_email.clone(),
    password: filen_password_and_m_key.sent_password.clone(),
    two_factor_key: user_two_factor_key.clone(),
    auth_version: auth_info_response_data.auth_version,
};
let login_response = auth::login_request(&login_request_payload, &filen_settings)?;
if !login_response.status || login_response.data.is_none() {
    bail!("Filen API failed to login: {:?}", auth_info_response.message);
}
// Login confirmed, now you can take API key and user's master key from the LoginResponseData
// and go perform some API calls!
let login_response_data = login_response.data.unwrap();
let api_key = login_response_data.api_key;
let last_master_key = filen_password_and_m_key.m_key;
// Just using filen_password_and_m_key.m_key everywhere is not correct,
// but it will work for the demo purposes.

Gettings user's default folder

// Let's start by finding user's default folder:
let user_dir_request_payload = UserDirsRequestPayload {
    api_key: api_key.clone(),
};
let user_dirs_response = user_dirs_request(&user_dir_request_payload, &filen_settings)?;
if !user_dirs_response.status || user_dirs_response.data.is_empty() {
    bail!(
        "Filen API failed to provide user dirs: {:?}",
        user_dirs_response.message
    );
}
// That's just a convenience helper, you can iterate folders in user_dirs_response.data yourself
let default_folder_data = user_dirs_response.find_default_folder().unwrap();

Getting remote folder contents

// Alright, we have our default folder, let's check out its contents.
let download_dir_request_payload = DownloadDirRequestPayload {
    api_key: api_key.clone(),
    uuid: default_folder_data.uuid.clone(),
};
let download_dir_response = download_dir_request(&download_dir_request_payload, &filen_settings)?;
if !download_dir_response.status || download_dir_response.data.is_none() {
    bail!(
        "Filen API failed to provide default folder contents: {:?}",
        download_dir_response.message
    );
}
// Again, this is just a helper method, feel free to decrypt metadata for every [DownloadedFileData] yourself.
let download_dir_response_data = download_dir_response.data.unwrap();
let default_folder_files_and_properties = download_dir_response_data.decrypt_all_files(&last_master_key)?;

Downloading and decrypting a file

// Let's say user has a file 'some file.png' located in the default folder. Let's find and download it:
let (some_file_data, some_file_properties) = default_folder_files_and_properties
    .iter()
    .find(|(data, properties)| data.parent == default_folder_data.uuid && properties.name == "some file.png")
    .unwrap();
let file_key = some_file_properties.key.clone();
// Let's store file in-memory via writer over vec:
let mut file_buffer = std::io::BufWriter::new(Vec::new());
let retry_settings = RetrySettings::from_max_tries(7); // Lucky number.
let sync_file_download_result = download_and_decrypt_file_from_data_and_key(
    &some_file_data,
    &file_key,
    &retry_settings,
    &filen_settings,
    &mut file_buffer,
);
// And now we have downloaded and decrypted bytes in memory.
let file_bytes = sync_file_download_result.map(|_| file_buffer.into_inner().unwrap());

This is it for examples, at least for now.

You might also like...
A library-first, lightweight, high-performance, cloud-native supported API gateway🪐 by RUST

Preview version, will not guarantee the stability of the API! Do NOT use in production environment! A library-first, lightweight, high-performance, cl

Acts as an IRC server and a nostr client. Connect with your IRC client using your nostr private key as the password.

nostr-irc Acts as an IRC server and a nostr client. Connect with your IRC client using your nostr private key as the password. Experimental code, use

Modular IPC-based desktop launcher service

Pop Launcher Modular IPC-based desktop launcher service, written in Rust. Desktop launchers may interface with this service via spawning the pop-launc

Sanzu is a graphical remote desktop solution

Sanzu Sanzu is a graphical remote desktop solution. It is composed of: a server running on Unix or Windows which can stream a X11 or a Windows GUI env

Open Internet Service to store transaction history for NFTs/Tokens on the Internet Computer
Open Internet Service to store transaction history for NFTs/Tokens on the Internet Computer

CAP - Certified Asset Provenance Transaction history & asset provenance for NFT’s & Tokens on the Internet Computer CAP is an open internet service pr

Cover is an open internet service for canister code verification on the Internet Computer
Cover is an open internet service for canister code verification on the Internet Computer

Cover Cover (short for Code Verification) is an open internet service that helps verify the code of canisters on the Internet Computer. Visit our webs

A open port scanner.
A open port scanner.

opscan A open port scanner. Install With cargo cargo install --force opscan With docker docker run --rm -it sigoden/opscan opscan.nmap.org Binaries

Tiny CLI application in rust to scan ports from a given IP and find how many are open. You can also pass the amount of threads for that scan

Port Scanner A simple multi-threaded port scanner written in Rust. Usage Run the port scanner by providing the target IP address and optional flags. $

FTP client for Rust

rust-ftp FTP client for Rust Documentation rust-ftp Installation Usage License Contribution Development environment Installation FTPS support is achie

Comments
  • fix: update servers lists

    fix: update servers lists

    Hello there! :wave:

    I have been trying out your library, mostly going through the examples, and getting a lot of failed to lookup address information: Temporary failure in name resolution errors, it appears the host names have changed:

    https://github.com/FilenCloudDienste/filen-desktop/commit/bd466a28cbf251565318de49664d2766ea6516f4#diff-900b2578438f0dfc98ec3ea732e1fed0aba5c31be5f21201c4311f0737c76fa0

    opened by maxbrunet 1
Owner
Konstantin Zakharov
Konstantin Zakharov
Network Block Storage server, written in Rust. Supports pluggable and chainable underlying storage

nbd-rs Disclaimer DO NEVER USE THIS FOR PRODUCTION Do not use this for any data that you cannot afford to lose any moment. Expect data loss, corruptio

Rainlab Inc 10 Sep 30, 2022
Obtain (wildcard) certificates from let's encrypt using dns-01 without the need for API access to your DNS provider.

Agnos Presentation Agnos is a single-binary program allowing you to easily obtain certificates (including wildcards) from Let's Encrypt using DNS-01 c

Arthur Carcano 246 Dec 20, 2022
Rust client for NATS, the cloud native messaging system.

A Rust client for the NATS messaging system. Status Motivation Rust may be the most interesting new language the NATS ecosystem has seen. We believe t

NATS - The Cloud Native Messaging System 651 Jan 3, 2023
A rust client and structures to interact with the Clever-Cloud API.

Clever-Cloud Software Development Kit - Rust edition This crate provides structures and client to interact with the Clever-Cloud API. Status This crat

Clever Cloud 6 Jun 3, 2022
SpringQL: Open-source stream processor for IoT devices and in-vehicle computers

What is SpringQL? SpringQL is an open-source stream processor specialized in memory efficiency. It is supposed to run on embedded systems like IoT dev

SpringQL 25 Dec 26, 2022
The open source distributed web search engine that searches by meaning.

DawnSearch DawnSearch is an open source distributed web search engine that searches by meaning. It uses semantic search (searching on meaning), using

DawnSearch 4 Aug 8, 2023
A wrapper for the Google Cloud DNS API

cloud-dns is a crate providing a client to interact with Google Cloud DNS v1

Embark 5 May 24, 2022
A CLI test program for HNU Cloud Computing Lab 2, built with Rust.

HTTP Server Tester This is a CLI test program for HNU Cloud Computing Lab 2. Install For most student, you don't neet to rebuild this project. We prov

null 5 Apr 21, 2022
📊 Collect cloud usage data, so that it can be combined with impact data of Boavizta API.

cloud-scanner Collect aws cloud usage data, so that it can be combined with impact data of Boavizta API. ⚠ Very early Work in progress ! At the moment

Boavizta 10 Dec 7, 2022
Cloud Native high performance security and privacy SQL proxy.

Fern proxy With the advent of Cloud Native applications, architecture patterns evolved and emerged to take advantage of cloud computing, and build mor

Fern 12 Nov 7, 2022