diff --git a/Cargo.toml b/Cargo.toml
index d8710e1..5c97c0b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -96,26 +96,24 @@ ark-groth16 = "0.4.0"
ark-std = { version = "0.4.0", features = ["std"] }
ark-snark = "0.4.0"
-iced = { version = "0.12.1", features = ["advanced", "system","svg"] }
+iced = { version = "0.12.1", features = ["advanced", "system", "svg", "canvas"] }
tempfile = "3.14.0"
url = "2.4"
-# Optional dependencies for tracing
-tracing-subscriber = { version = "0.3", features = ["env-filter","std","tracing-log"], optional = true }
+tracing-subscriber = { version = "0.3", features = ["env-filter","std","tracing-log"] }
intaglio = { version = "1.6", optional = true }
[features]
strict = []
-traceability = ["tracing-subscriber", "tokio/rt-multi-thread", "intaglio"]
+#traceability = ["tracing-subscriber", "tokio/rt-multi-thread", "intaglio"]
irrefutable_audit = []
compressed_store = []
[[bin]]
name = "graymamba"
path = "src/bin/graymamba/main.rs"
-required-features = ["traceability"]
[[bin]]
name = "audit_reader"
path = "src/bin/audit_reader/main.rs"
diff --git a/README.md b/README.md
index 58194ab..8ea2ca5 100644
--- a/README.md
+++ b/README.md
@@ -1,176 +1,86 @@
-Secure Provenance Tracking Filesystem - README
-==============================================
-
-Overview
-========
-
-The Secure Provenance Tracking Filesystem is a cutting-edge Network File System (NFS) developed in Rust. The filesystem incorporates advanced features to support the principle of Secure by Design, ensuring a highly secure IDE and provenance tracking. It employs innovative methods such as the Shamir Secret Sharing Algorithm, Merkle Trees, ZNP Git interception feature to deliver a secure, reliable, and traceable IDE based file storage solution.
-
-Features
-========
-
-1. Shamir Secret Sharing Algorithm:
- - Uses Shamir Secret Sharing to disassemble file contents into secret shares upon creation.
- - Reassembles the secret shares to reconstruct the file contents when the file is read.
- - Enhances security by ensuring that file contents are only accessible when a threshold number of shares are combined.
- - The protocol of disassembly and reassembly os controlled by blockchain and provides audit hooks that are tamper-proof.
-2. Provenance Tracking with Blockchain:
- - Tracks provenance by recording disassembly and reassembly events on Polkadot/Aleph Zero blockchain or similar (e.g. Merkle Tree and append only aidit with ZKPs).
- - Provides tamper-proof records ensuring the integrity and traceability of file operations.
-3. A data store for Persistence that must adhere to the following requirements as embodied in a trait:
- - Store files and directories persistently.
- - Ensure a high availability and fault tolerance.
- - Provide a set of operations that can be used to implement the file system.
- - Currently Redis and RocksDB are the only data stores that adhere to the trait.
-4. Git Interception for Fast Cloning:
- - Enhances the cloning of large Git repositories by utilizing Shamir Secret Sharing.
- - Disassembles repository data into secret shares for faster and secure cloning processes.
-
-Installation
-============
-
-Prerequisites
-=============
-
- - Rust (latest stable version)
- - Polkadot/Aleph Zero node (optional)
- - Redis Cluster or RocksDB
-
-Steps
-=====
-1. Clone the Repository:
-
- `git clone https://github.com/gmawdo/secure-provenance-tracking-filesystem.git`
- `cd secure-provenance-tracking-filesystem`
-
-2. Install Dependencies:
-
- Ensure you have the necessary dependencies installed. You can use cargo for Rust dependencies.
- - $ `cargo build`
-
-3. Configure Redis Cluster:
- Set up your Redis Cluster with 3 node with ports 6380,6381,6382.
- - Install Redis :
- https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/
- - To create redis cluster somewhere in system
- - $ `mkdir Redis Cluster`
- - $ `cd Redis Cluster`
- - create three files with below config: redis-6380.conf, redis-6381.conf, redis-6382.conf
-``` shell
- # Change port
- port 6380
+# A Highly Secure Provenance Tracking Filesystem
- #Expose the port
- bind 0.0.0.0
+A secure filesystem that tracks the provenance of files and directories. Entirely written in Rust for memory safety and performance.
+Built with an NFS protocol layer loosely based on NFSServe, promoting ease of integration into existing systems and workflows.
- #Mode
- protected-mode no
+Can be utilised in both local and distributed environments, with the ability to scale out to multiple nodes. Also deployable to small Linux based IoT devices for secure capture and data transmission.
- # Data directory location
- dir ./Redis_database/redis-6380
+## Overview
- # Enable clustering
- cluster-enabled yes
+## Building
- # Set Password
- requirepass 0rangerY
-```
- - In Redis Cluster folder:
- - $ `mkdir Redis_database`
- - $ `cd Redis_database`
- - $ `mkdir redis-6380`
- - $ `mkdir redis-6381`
- - $ `mkdir redis-6382`
- - To Run Redis Cluster run below commands in 4 different terminals at Redis Cluster folder.
- $ `redis-server redis-6380.conf`
- $ `redis-server redis-6381.conf`
- $ `redis-server redis-6382.conf`
- $ `redis-cli --cluster create 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 --cluster-replicas 0 -a 0rangerY --cluster-yes`
-
-
-
-4. Configure Blockchain Node:
- Set up your Polkadot/Aleph Zero node following below steps
- $ `git clone https://github.com/datasignals/aleph-node-pinkscorpion.git`
- $ `cd aleph-node-pinkscorpion`
- $ `cargo build βrelease`
- $ `scripts/run_nodes.sh`
-
-5. Now to Build the filesystem open terminal at secure-provenance-filesystem folder and run one of (note iirefutable_audit feature compiles in blockchain tech integration):
-
- `cargo build --bin graymamba --features="traceability" --release`
- `cargo build --bin graymamba --features="traceability,irrefutable_audit" --release`
- `cargo test --features irrefutable_audit -- --nocapture`
-
- `cargo build --bin audit_reader --features="traceability,irrefutable_audit" --release`
- `cargo build --bin qrocks --features="traceability,irrefutable_audit" --release`
-
- `cargo clippy --features="traceability,irrefutable_audit"`
-
- `cargo run --bin graymamba --features=traceability,irrefutable_audit`
- `cargo run --bin audit_reader --features=traceability,irrefutable_audit`
+### Features (determines what is built into the binary)
-When the blockchain is compiled in and running then you will see the following type of output on the console when a file is created or read:
----------------
-............................
-Preparing to send event...
-Disassembled call submitted, waiting for transaction to be finalized...
-Disassembled event processed.
-............................
+- Mandatory Backing Store, choose one of [ `rocksdb` | `redis` ]: Enables RocksDB or Redis as backing store for data shares (one of the two options must be chosen)
+- Optional `irrefutable_audit`: Enables irrefutable audit logs for files and directories. (if not specified then no audit logs are created)
+- Optional `compressed_store`: Enables compressed shares (if not specified then works uncompresed with reduced performance but greater traceability
-Testing and performance commands
----------------
+RocksDB is built-in to the filesystem if chosen. If Redis is the store of choice, then it will need to be installed and running on the machine.
-1. Linter:
+### Build and Run Commands
- `cargo clippy`
+ - `To run or test the filesystem`: π
-2. Benchmarking:
-
- `cargo bench`
-
-Docker Commands
----------------
-
-1. Build the Docker Image:
+ cargo build --bin graymamba --features="irrefutable_audit,compressed_store,rocksdb" --release
+ cargo run --bin graymamba --features="irrefutable_audit,compressed_store,rocksdb" --release
+ cargo test --features irrefutable_audit -- --nocapture
+
+ - `To build and run the audit_reader, qrocks, and data-room` (see below for more details on these binaries): π
- `sudo docker build -t graymamba_image .`
+ cargo run --bin audit_reader --features="irrefutable_audit" --release
+ cargo run --bin qrocks --features="irrefutable_audit" --release
+ cargo run --bin data-room --features="irrefutable_audit" --release
-2. Run the Docker Image on a docker container:
+ - `To run the Linter` : π
+
+ cargo clippy --features="irrefutable_audit,compressed_store"
- `sudo docker run -d --name graymamba_container --privileged --network host graymamba_image`
+- `To run bench marking` : π
+
+ cargo bench --features="irrefutable_audit,compressed_store"
-Usage
-=====
+## Explanation of the project's binaries and their purpose
+- `graymamba`: The filesystem itself, which can be mounted as an NFS server. The `main man`.
+- `audit_reader`: Reads the audit logs and allows exploration, verification and proof generation.
+- `qrocks`: A tool for querying the RocksDB database as there seems not to be one in wide circulation
+- `data-room`: An experimental tool for providing a data sandbox for file sharing and collaboration in sensitive environments.
-Basic Commands
---------------
+## Useful references
- - Create a File:
- To create a file, use the standard NFS commands. The filesystem will automatically disassemble the file contents into secret shares.
+### Configure a Redis Cluster:
+ Set up a Redis Cluster with 3 node with ports 6380,6381,6382.
+ - Install Redis : https://redis.io/docs/latest/operate/oss_and_stack/install/install-redis/
-- Read a File:
-To read a file, use the standard NFS commands. The filesystem will reassemble the secret shares to reconstruct the file contents.
+ - This will require a config file for each node: e.g. redis-6380.conf, redis-6381.conf, redis-6382.conf of the format:
-Provenance Tracking
--------------------
+ # Change port
+ port 6380
+ #Expose the port
+ bind 0.0.0.0
+ #Mode
+ protected-mode no
+ # Data directory location
+ dir ./Redis_database/redis-6380
+ # Enable clustering
+ cluster-enabled yes
+ # Set Password
+ requirepass password
+
+
+ redis-cli --cluster create 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 --cluster-replicas 0 -a password --cluster-yes
- - Event Tracking:
- Disassembly and reassembly events are automatically sent to the Polkadot/Aleph Zero blockchain.
- - Use blockchain explorer tools to view the provenance records.
+ nohup redis-server redis-6380.conf > redis0.log 2>&1 &
+ nohup redis-server redis-6381.conf > redis1.log 2>&1 &
+ nohup redis-server redis-6382.conf > redis2.log 2>&1 &
-Git Interception
-----------------
+
- - Fast Cloning:
- The filesystem intercepts Git clone operations to disassemble repository data into secret shares, enhancing the cloning speed and security. Despite continuous disassembly and reassembly, the Git interception feature ensures efficient cloning of git repositories.
- - Clone a repository as usual with Git. The filesystem will handle the disassembly and reassembly processes in the background.
-Security
---------
+### Configure Blockchain Node: (if using Polkadot/Aleph Zero for irrfutable audit)
+ Set up a Polkadot/Aleph Zero node following below steps
+ $ git clone https://github.com/datasignals/aleph-node-pinkscorpion.git (based on aleph-zero fork)
+ $ cd aleph-node-pinkscorpion
+ $ cargo build βrelease
+ $ scripts/run_nodes.sh
- - Data Security:
- File contents are secured using Shamir Secret Sharing, ensuring that data is split into multiple shares and requires a threshold number of shares to reconstruct.
- - Integrity and Traceability:
- Provenance tracking using blockchain ensures that all file operations are recorded in a tamper-proof manner.
diff --git a/src/bin/data_room/main.rs b/src/bin/data_room/main.rs
index a274875..d4ae890 100644
--- a/src/bin/data_room/main.rs
+++ b/src/bin/data_room/main.rs
@@ -11,6 +11,7 @@ use iced::{
Subscription,
widget::container,
Font, Pixels,
+ alignment::Horizontal,
};
use iced::widget::svg::Svg;
use iced::advanced::svg;
@@ -37,7 +38,6 @@ use std::net::SocketAddr;
#[derive(Debug, Default)]
struct LoginState {
username: String,
- password: String,
error: Option,
is_visible: bool,
}
@@ -73,7 +73,6 @@ enum Message {
ShowLogin,
CloseLogin,
UpdateUsername(String),
- UpdatePassword(String),
AttemptLogin,
Logout,
LogoutComplete,
@@ -108,9 +107,9 @@ impl container::StyleSheet for BorderedContainer {
container::Appearance {
text_color: None,
background: Some(Color::from_rgb(
- 0x01 as f32 / 255.0,
- 0x01 as f32 / 255.0,
- 0x01 as f32 / 255.0,
+ 0.75,
+ 0.75,
+ 0.75,
).into()),
border: Border {
radius: 5.0.into(),
@@ -193,10 +192,6 @@ impl Application for DataRoom {
self.login_state.username = username;
Command::none()
}
- Message::UpdatePassword(password) => {
- self.login_state.password = password;
- Command::none()
- }
Message::AttemptLogin => {
let username = self.login_state.username.clone();
let handle = self.runtime_handle.clone();
@@ -353,38 +348,12 @@ impl Application for DataRoom {
}
fn view(&self) -> Element {
- if self.login_state.is_visible {
- self.view_login_modal()
- } else {
- let refresh_button = Button::new(
- Text::new("π Refresh")
- .size(self.font_size)
- )
- .on_press(Message::RefreshFiles)
- .padding(10);
-
- let header = Row::new()
- .align_items(Alignment::Center)
- .spacing(10)
- .push(refresh_button)
- .push(
- if self.authenticated_user.is_none() {
- Button::new(Text::new("Login").size(self.font_size))
- .padding([4, 8])
- .on_press(Message::ShowLogin)
- .style(theme::Button::Primary)
- } else {
- Button::new(Text::new("Logout").size(self.font_size))
- .padding([4, 8])
- .on_press(Message::Logout)
- .style(theme::Button::Secondary)
- }
- );
-
+ let main_content = {
let side_panel = Container::new(
Column::new()
.width(Length::Fixed(72.0))
.height(Length::Fill)
+ .spacing(10)
.push(
Container::new(
Svg::new(svg::Handle::from_path("src/bin/qrocks/RocksDB.svg"))
@@ -394,6 +363,30 @@ impl Application for DataRoom {
.padding(6)
.center_x()
)
+ .push(
+ Container::new(
+ Button::new(Text::new("π Refresh").size(self.font_size))
+ .padding([4, 8])
+ .on_press(Message::RefreshFiles)
+ )
+ .center_x()
+ )
+ .push(
+ Container::new(
+ if self.authenticated_user.is_none() {
+ Button::new(Text::new("π Login").size(self.font_size))
+ .padding([4, 8])
+ .on_press(Message::ShowLogin)
+ .style(theme::Button::Primary)
+ } else {
+ Button::new(Text::new("π Logout").size(self.font_size))
+ .padding([4, 8])
+ .on_press(Message::Logout)
+ .style(theme::Button::Secondary)
+ }
+ )
+ .center_x()
+ )
)
.style(theme::Container::Custom(Box::new(CustomContainer(Self::hex_to_color("#404040")))))
.width(Length::Fixed(72.0))
@@ -408,31 +401,32 @@ impl Application for DataRoom {
Scrollable::new(
Column::new()
.spacing(5)
- .push(Text::new(format!("Connected as: {}",
- self.authenticated_user.as_ref().unwrap_or(&"Guest".to_string()))))
+ //.push(Text::new(format!("Connected as: {}",
+ // self.authenticated_user.as_ref().unwrap_or(&"Guest".to_string()))))
.push(
- Column::new()
- .spacing(5)
- .push(
- Row::new()
- .spacing(20)
- .push(Text::new("Name").size(self.font_size).style(Color::WHITE))
- .push(Text::new("Size").size(self.font_size).style(Color::WHITE))
- .push(Text::new("ID").size(self.font_size).style(Color::WHITE))
- )
+ Row::new()
+ .spacing(20)
.push(
{
- let mut column = Column::new().spacing(5);
+ let mut row = Row::new().spacing(20).padding(10);
for file in &self.files {
- column = column.push(
- Row::new()
- .spacing(20)
- .push(Text::new(&file.name).size(self.font_size).style(Color::WHITE))
- .push(Text::new(format!("{} bytes", file.size)).size(self.font_size).style(Color::WHITE))
- .push(Text::new(format!("{}", file.file_id)).size(self.font_size).style(Color::WHITE))
+ row = row.push(
+ Column::new()
+ .spacing(5)
+ .align_items(Alignment::Center)
+ .push(
+ Text::new(Self::get_file_emoji(&file.name))
+ .size(32.0)
+ )
+ .push(
+ Text::new(&file.name)
+ .size(self.font_size)
+ .width(Length::Fixed(100.0))
+ .horizontal_alignment(Horizontal::Center)
+ )
);
}
- column
+ row
}
)
)
@@ -452,14 +446,45 @@ impl Application for DataRoom {
.padding(20)
.max_width(1200)
.height(Length::Fill)
- .push(header)
.push(files_panel);
- let content = Row::new()
+ Row::new()
.push(side_panel)
- .push(main_content);
+ .push(main_content)
+ };
- Container::new(content)
+ if self.login_state.is_visible {
+ // Stack the login modal on top of the main content
+ Container::new(
+ Column::new()
+ .push(
+ // Main content with blur effect
+ Container::new(main_content)
+ .style(theme::Container::Custom(Box::new(CustomContainer(Color::from_rgba(
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.3, // More transparent to simulate blur
+ )))))
+ )
+ .push(
+ // Login modal
+ Container::new(self.view_login_modal())
+ .width(Length::Fill)
+ .height(Length::Fill)
+ .style(theme::Container::Custom(Box::new(CustomContainer(Color::from_rgba(
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.5,
+ )))))
+ )
+ )
+ .width(Length::Fill)
+ .height(Length::Fill)
+ .into()
+ } else {
+ Container::new(main_content)
.width(Length::Fill)
.height(Length::Fill)
.center_x()
@@ -488,42 +513,6 @@ impl Application for DataRoom {
impl DataRoom {
fn view_main_content(&self) -> Element {
- let header = Row::new()
- .spacing(10)
- .align_items(Alignment::Center)
- .push(Text::new("Data Room").size(self.font_size * 2.0))
- .push(
- if self.authenticated_user.is_none() {
- Button::new(Text::new("Login").size(self.font_size))
- .padding([4, 8])
- .on_press(Message::ShowLogin)
- .style(theme::Button::Primary)
- } else {
- Button::new(Text::new("Logout").size(self.font_size))
- .padding([4, 8])
- .on_press(Message::Logout)
- .style(theme::Button::Secondary)
- }
- );
-
- let side_panel = Container::new(
- Column::new()
- .width(Length::Fixed(72.0))
- .height(Length::Fill)
- .push(
- Container::new(
- Svg::new(svg::Handle::from_path("src/bin/qrocks/RocksDB.svg"))
- .width(Length::Fixed(60.0))
- .height(Length::Fixed(60.0))
- )
- .padding(6)
- .center_x()
- )
- )
- .style(theme::Container::Custom(Box::new(CustomContainer(Self::hex_to_color("#404040")))))
- .width(Length::Fixed(72.0))
- .height(Length::Fill);
-
let files_panel = Container::new(
Column::new()
.spacing(10)
@@ -565,14 +554,9 @@ impl DataRoom {
.padding(20)
.max_width(1200)
.height(Length::Fill)
- .push(header)
.push(files_panel);
- let content = Row::new()
- .push(side_panel)
- .push(main_content);
-
- Container::new(content)
+ Container::new(main_content)
.width(Length::Fill)
.height(Length::Fill)
.center_x()
@@ -583,7 +567,21 @@ impl DataRoom {
let content = Column::new()
.spacing(20)
.padding(20)
- .push(Text::new("Login").size(self.font_size * 1.5))
+ .push(
+ Row::new()
+ .align_items(Alignment::Center)
+ .spacing(10)
+ .push(Text::new("Login").size(self.font_size * 1.5))
+ .push(
+ Container::new(
+ Button::new(Text::new("β").size(self.font_size))
+ .on_press(Message::CloseLogin)
+ .style(theme::Button::Secondary)
+ )
+ .width(Length::Fill)
+ .align_x(Horizontal::Right)
+ )
+ )
.push(
TextInput::new(
"Username",
@@ -593,15 +591,6 @@ impl DataRoom {
.padding(8)
.on_input(Message::UpdateUsername),
)
- .push(
- TextInput::new(
- "Password",
- &self.login_state.password,
- )
- .size(self.font_size)
- .padding(8)
- .on_input(Message::UpdatePassword),
- )
.push(
Button::new(Text::new("Login").size(self.font_size))
.padding([4, 8])
@@ -609,21 +598,17 @@ impl DataRoom {
.style(theme::Button::Primary),
);
- let modal_content = if let Some(error) = &self.login_state.error {
- content.push(
- Text::new(error)
- .size(self.font_size)
- .style(Color::from_rgb(0.8, 0.0, 0.0))
- )
- } else {
- content
- };
-
- Container::new(modal_content)
- .width(Length::Fixed(300.0))
- .padding(20)
- .style(theme::Container::Custom(Box::new(BorderedContainer)))
- .into()
+ Container::new(
+ Container::new(content)
+ .width(Length::Fixed(300.0))
+ .padding(20)
+ .style(theme::Container::Custom(Box::new(BorderedContainer)))
+ )
+ .width(Length::Fill)
+ .height(Length::Fill)
+ .center_x()
+ .center_y()
+ .into()
}
fn hex_to_color(hex: &str) -> Color {
@@ -721,6 +706,25 @@ impl DataRoom {
}
Ok(())
}
+
+ fn get_file_emoji(filename: &str) -> &'static str {
+ debug!("Getting file emoji for: {}", filename);
+ if let Some(extension) = filename.split('.').last() {
+ debug!("Extension: {}", extension);
+ match extension.to_lowercase().as_str() {
+ "txt" | "md" | "doc" | "docx" => "π",
+ "pdf" => "π",
+ "jpg" | "jpeg" | "png" | "gif" | "svg" => "πΌοΈ",
+ "mp3" | "wav" | "ogg" => "π΅",
+ "mp4" | "mov" | "avi" => "π¬",
+ "zip" | "rar" | "7z" => "ποΈ",
+ "exe" | "app" => "βοΈ",
+ _ => "π",
+ }
+ } else {
+ "π" // For files without extensions or directories
+ }
+ }
}
impl NfsSession {