mirror of
https://github.com/002Hub/IPass.git
synced 2025-04-19 22:01:21 +02:00
add sync feature
Co-authored-by: Alpisc <Alpisc@users.noreply.github.com>
This commit is contained in:
parent
7fcbd71e99
commit
0c9f796658
2
.gitignore
vendored
2
.gitignore
vendored
@ -2,3 +2,5 @@
|
|||||||
comp.bat
|
comp.bat
|
||||||
comp.sh
|
comp.sh
|
||||||
report.json
|
report.json
|
||||||
|
*.ipass
|
||||||
|
*.ipassx
|
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -193,7 +193,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipass"
|
name = "ipass"
|
||||||
version = "0.3.1"
|
version = "0.4.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes-gcm",
|
"aes-gcm",
|
||||||
"brotli",
|
"brotli",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ipass"
|
name = "ipass"
|
||||||
version = "0.3.1"
|
version = "0.4.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
@ -19,4 +19,4 @@ opt-level = 'z' # Optimize for size
|
|||||||
lto = true # Enable link-time optimization
|
lto = true # Enable link-time optimization
|
||||||
codegen-units = 1 # Reduce number of codegen units to increase optimizations
|
codegen-units = 1 # Reduce number of codegen units to increase optimizations
|
||||||
panic = 'abort' # Abort on panic
|
panic = 'abort' # Abort on panic
|
||||||
strip = true # Strip symbols from binary; remove pdb
|
# strip = true # Strip symbols from binary; remove pdb
|
||||||
|
205
src/main.rs
205
src/main.rs
@ -1,5 +1,10 @@
|
|||||||
|
#![warn(missing_docs, single_use_lifetimes, unused_lifetimes, trivial_casts, trivial_numeric_casts)]
|
||||||
|
#![forbid(unsafe_code)]
|
||||||
|
|
||||||
|
//! IPass Password Manager
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io::{Read, Write};
|
use std::io::Write;
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use rand::RngCore;
|
use rand::RngCore;
|
||||||
mod utils;
|
mod utils;
|
||||||
@ -17,6 +22,19 @@ fn main() {
|
|||||||
|
|
||||||
let mode: &str = &args[1].trim().to_lowercase().to_owned();
|
let mode: &str = &args[1].trim().to_lowercase().to_owned();
|
||||||
|
|
||||||
|
let sync_file_loc = utils::get_home_folder_str()+"/.sync.ipass";
|
||||||
|
let sync_file_path = std::path::Path::new(&sync_file_loc);
|
||||||
|
|
||||||
|
let sync_enabled = sync_file_path.clone().exists();
|
||||||
|
let sync_loc: String;
|
||||||
|
|
||||||
|
if sync_enabled {
|
||||||
|
sync_loc = std::fs::read_to_string(sync_file_path).expect("Should have been able to read the sync file");
|
||||||
|
utils::import_file(&sync_loc);
|
||||||
|
} else {
|
||||||
|
sync_loc = "".to_string(); //sync is disabled, no location needed
|
||||||
|
}
|
||||||
|
|
||||||
match mode {
|
match mode {
|
||||||
"list" => list(),
|
"list" => list(),
|
||||||
"add" => add(&args),
|
"add" => add(&args),
|
||||||
@ -28,9 +46,14 @@ fn main() {
|
|||||||
"export" => export(&args),
|
"export" => export(&args),
|
||||||
"rename" => rename(&args),
|
"rename" => rename(&args),
|
||||||
"version" => version_help(version),
|
"version" => version_help(version),
|
||||||
|
"sync" => sync(&args),
|
||||||
|
"isync" => isync(&args),
|
||||||
"clear" => clear(),
|
"clear" => clear(),
|
||||||
_ => help_message(&args),
|
_ => help_message(&args),
|
||||||
}
|
}
|
||||||
|
if sync_enabled {
|
||||||
|
utils::export_file(&sync_loc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn version_help(version: &str) {
|
fn version_help(version: &str) {
|
||||||
@ -90,6 +113,14 @@ fn help_message(args: &Vec<String>) {
|
|||||||
"clear".to_string(),
|
"clear".to_string(),
|
||||||
"clears all entries".to_string(),
|
"clears all entries".to_string(),
|
||||||
);
|
);
|
||||||
|
help_messages.insert(
|
||||||
|
"sync".to_string(),
|
||||||
|
"automatically sync your data with a specified file".to_string(),
|
||||||
|
);
|
||||||
|
help_messages.insert(
|
||||||
|
"isync".to_string(),
|
||||||
|
"not fully implemented yet; ignore this for now | Syncs the database to IPass servers".to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
if args.len() < 3 {
|
if args.len() < 3 {
|
||||||
println!("You can use the following commands:");
|
println!("You can use the following commands:");
|
||||||
@ -103,7 +134,7 @@ fn help_message(args: &Vec<String>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn list() {
|
fn list() {
|
||||||
let mut paths = std::fs::read_dir(utils::get_ipass_folder()).unwrap();
|
let mut paths: std::fs::ReadDir = std::fs::read_dir(utils::get_ipass_folder()).unwrap();
|
||||||
|
|
||||||
let mut has_entry:bool = false;
|
let mut has_entry:bool = false;
|
||||||
|
|
||||||
@ -123,6 +154,7 @@ fn list() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn add(args: &Vec<String>) {
|
fn add(args: &Vec<String>) {
|
||||||
|
//! arguments: program add [name] {password}
|
||||||
|
|
||||||
if args.len() < 4 || args.len() > 5 {
|
if args.len() < 4 || args.len() > 5 {
|
||||||
println!("Incorrect usage of \"add\"");
|
println!("Incorrect usage of \"add\"");
|
||||||
@ -135,12 +167,12 @@ fn add(args: &Vec<String>) {
|
|||||||
if args.len() > 4 {
|
if args.len() > 4 {
|
||||||
pw = username+";"+args[4].trim();
|
pw = username+";"+args[4].trim();
|
||||||
} else {
|
} else {
|
||||||
let alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!\"$%&/()=?{[]}\\,.-;:_><|+*#'";
|
let alphabet: &str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!\"$%&/()=?{[]}\\,.-;:_><|+*#'";
|
||||||
let alph_len = alphabet.chars().count();
|
let alph_len: usize = alphabet.chars().count();
|
||||||
let char_set:Vec<char> = alphabet.chars().collect();
|
let char_set:Vec<char> = alphabet.chars().collect();
|
||||||
let mut chars_index: Vec<u8> = vec![0;20];
|
let mut chars_index: Vec<u8> = vec![0;20];
|
||||||
OsRng.fill_bytes(&mut chars_index);
|
OsRng.fill_bytes(&mut chars_index);
|
||||||
let mut chars = String::new();
|
let mut chars: String = String::new();
|
||||||
|
|
||||||
for index in chars_index {
|
for index in chars_index {
|
||||||
// println!("{} - {} - {}",index,(index as usize)%(alph_len-1),alph_len);
|
// println!("{} - {} - {}",index,(index as usize)%(alph_len-1),alph_len);
|
||||||
@ -154,7 +186,7 @@ fn add(args: &Vec<String>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
println!("Adding password for {}",args[2]);
|
println!("Adding password for {}",args[2]);
|
||||||
let succeeded = utils::create_entry(&args[2], pw);
|
let succeeded: bool = utils::create_entry(&args[2], pw);
|
||||||
if !succeeded {
|
if !succeeded {
|
||||||
println!("You already have an entry with that name! Did you mean to use \"edit\"?");
|
println!("You already have an entry with that name! Did you mean to use \"edit\"?");
|
||||||
return;
|
return;
|
||||||
@ -163,15 +195,16 @@ fn add(args: &Vec<String>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get(args: &Vec<String>) {
|
fn get(args: &Vec<String>) {
|
||||||
|
//! arguments: program get [name]
|
||||||
if args.len() < 3 {
|
if args.len() < 3 {
|
||||||
println!("Invalid usage of \"get\"");
|
println!("Invalid usage of \"get\"");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let name = &args[2];
|
let name: &String = &args[2];
|
||||||
let filepath = &(utils::get_ipass_folder()+name+".ipass");
|
let filepath = &(utils::get_ipass_folder()+name+".ipass");
|
||||||
if std::path::Path::new(filepath).exists() {
|
if std::path::Path::new(filepath).exists() {
|
||||||
println!("Getting entry");
|
println!("Getting entry");
|
||||||
let entry = utils::get_entry(name);
|
let entry: String = utils::get_entry(name);
|
||||||
let mut data = entry.split(";");
|
let mut data = entry.split(";");
|
||||||
println!("Username: '{}' Password: '{}'",data.next().unwrap(),data.next().unwrap());
|
println!("Username: '{}' Password: '{}'",data.next().unwrap(),data.next().unwrap());
|
||||||
} else {
|
} else {
|
||||||
@ -180,7 +213,8 @@ fn get(args: &Vec<String>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn changepw(args: &Vec<String>) { //rename func to changepw
|
fn changepw(args: &Vec<String>) {
|
||||||
|
//! arguments: program changepw [name] {new_password}
|
||||||
if args.len() < 3 {
|
if args.len() < 3 {
|
||||||
println!("Invalid usage of \"changepw\"");
|
println!("Invalid usage of \"changepw\"");
|
||||||
return;
|
return;
|
||||||
@ -203,6 +237,7 @@ fn changepw(args: &Vec<String>) { //rename func to changepw
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn changeuser(args: &Vec<String>) {
|
fn changeuser(args: &Vec<String>) {
|
||||||
|
//! arguments: program changeuser [name] {new_username}
|
||||||
if args.len() < 3 {
|
if args.len() < 3 {
|
||||||
println!("Invalid usage of \"changeuser\"");
|
println!("Invalid usage of \"changeuser\"");
|
||||||
return;
|
return;
|
||||||
@ -224,7 +259,8 @@ fn changeuser(args: &Vec<String>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rename(args: &Vec<String>) { // prog ren old new
|
fn rename(args: &Vec<String>) {
|
||||||
|
//! arguments: program rename [name] [new_name]
|
||||||
if args.len() < 4 {
|
if args.len() < 4 {
|
||||||
println!("Invalid usage of \"rename\"");
|
println!("Invalid usage of \"rename\"");
|
||||||
return;
|
return;
|
||||||
@ -239,6 +275,7 @@ fn rename(args: &Vec<String>) { // prog ren old new
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn remove(args: &Vec<String>) {
|
fn remove(args: &Vec<String>) {
|
||||||
|
//! arguments: program remove [name]
|
||||||
if args.len() < 3 {
|
if args.len() < 3 {
|
||||||
println!("Invalid usage of \"remove\"");
|
println!("Invalid usage of \"remove\"");
|
||||||
return;
|
return;
|
||||||
@ -259,6 +296,7 @@ fn remove(args: &Vec<String>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn import(args: &Vec<String>) {
|
fn import(args: &Vec<String>) {
|
||||||
|
//! arguments: program import {location}
|
||||||
let mut location = utils::get_home_folder_str();
|
let mut location = utils::get_home_folder_str();
|
||||||
if args.len() == 3 {
|
if args.len() == 3 {
|
||||||
location = args[2].clone();
|
location = args[2].clone();
|
||||||
@ -268,42 +306,7 @@ fn import(args: &Vec<String>) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if std::path::Path::new(&(location.clone()+"/export.ipassx")).exists() {
|
if utils::import_file(&location) {
|
||||||
let mut reader = brotli::Decompressor::new(
|
|
||||||
std::fs::File::open(location.clone()+"/export.ipassx").unwrap(),
|
|
||||||
4096, // buffer size
|
|
||||||
);
|
|
||||||
let mut content: String = String::new();
|
|
||||||
let mut buf = [0u8; 4096];
|
|
||||||
loop {
|
|
||||||
match reader.read(&mut buf[..]) {
|
|
||||||
Err(e) => {
|
|
||||||
if let std::io::ErrorKind::Interrupted = e.kind() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
panic!("{}", e);
|
|
||||||
}
|
|
||||||
Ok(size) => {
|
|
||||||
if size == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
content += &std::str::from_utf8(&buf[..size]).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let lines = content.lines();
|
|
||||||
let mut name = "";
|
|
||||||
for i in lines {
|
|
||||||
if name == "" {
|
|
||||||
name = i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut file = std::fs::File::create(format!("{}/{}.ipass",utils::get_ipass_folder(), name)).unwrap();
|
|
||||||
file.write_all(i.as_bytes()).unwrap();
|
|
||||||
name = "";
|
|
||||||
}
|
|
||||||
println!("Imported all entries!");
|
println!("Imported all entries!");
|
||||||
} else {
|
} else {
|
||||||
println!("No such file found!");
|
println!("No such file found!");
|
||||||
@ -312,6 +315,7 @@ fn import(args: &Vec<String>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn export(args: &Vec<String>) {
|
fn export(args: &Vec<String>) {
|
||||||
|
//! arguments: program export {location}
|
||||||
let mut location = utils::get_home_folder_str();
|
let mut location = utils::get_home_folder_str();
|
||||||
if args.len() == 3 {
|
if args.len() == 3 {
|
||||||
location = args[2].clone();
|
location = args[2].clone();
|
||||||
@ -321,37 +325,11 @@ fn export(args: &Vec<String>) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if utils::export_file(&location) {
|
||||||
let mut collected_data: String = String::new();
|
|
||||||
|
|
||||||
let paths = std::fs::read_dir(utils::get_ipass_folder()).unwrap();
|
|
||||||
|
|
||||||
for p in paths {
|
|
||||||
if let Ok(path) = p {
|
|
||||||
let content = &mut std::fs::read_to_string(utils::get_ipass_folder()+&path.file_name().into_string().unwrap()).expect("Should have been able to read the file");
|
|
||||||
collected_data += format!("{}\n{}\n", path.file_name().into_string().unwrap().replace(".ipass", ""),content).as_str();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if let Ok(file) = std::fs::File::create(location.clone()+"/export.ipassx") {
|
|
||||||
let mut writer = brotli::CompressorWriter::new(
|
|
||||||
file,
|
|
||||||
4096,
|
|
||||||
11,
|
|
||||||
22);
|
|
||||||
|
|
||||||
match writer.write_all(collected_data.as_bytes()) {
|
|
||||||
Err(e) => panic!("{}", e),
|
|
||||||
Ok(_) => {},
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("Saved at: '{}/export.ipassx'", location);
|
println!("Saved at: '{}/export.ipassx'", location);
|
||||||
} else {
|
} else {
|
||||||
println!("Failed saving at '{}/export.ipassx' does it exist?",location)
|
println!("Failed saving at '{}/export.ipassx' does it exist?",location);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear() {
|
fn clear() {
|
||||||
@ -369,3 +347,82 @@ fn clear() {
|
|||||||
}
|
}
|
||||||
println!("Cleared all entries!");
|
println!("Cleared all entries!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sync(args: &Vec<String>) {
|
||||||
|
//! arguments: program sync [on/off] {location if on}
|
||||||
|
let arg: String;
|
||||||
|
if args.len() < 3 {
|
||||||
|
println!("Invalid usage of \"sync\"");
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
arg = args[2].to_lowercase();
|
||||||
|
}
|
||||||
|
|
||||||
|
match arg.as_str() {
|
||||||
|
"on" => {
|
||||||
|
let location: String;
|
||||||
|
|
||||||
|
if args.len() < 4 {
|
||||||
|
location = utils::prompt_answer("No location specified, please provide the location of the file you want to sync: ".to_string());
|
||||||
|
} else {
|
||||||
|
location = args[3].clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut sync_file = std::fs::File::create(utils::get_home_folder_str()+"/.sync.ipass").expect("could not open sync file");
|
||||||
|
sync_file.write(location.as_bytes()).expect("could not write to sync file");
|
||||||
|
|
||||||
|
if !utils::export_file(&location) {
|
||||||
|
eprintln!("Test sync error, make sure you specified a valid folder!");
|
||||||
|
} else {
|
||||||
|
println!("Sync is now Enabled!");
|
||||||
|
println!("Sync file: {}",location);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
"off" => {
|
||||||
|
|
||||||
|
let sync_file_loc = utils::get_home_folder_str()+"/.sync.ipass";
|
||||||
|
let sync_file_path = std::path::Path::new(&sync_file_loc);
|
||||||
|
|
||||||
|
let sync_enabled = sync_file_path.clone().exists();
|
||||||
|
|
||||||
|
if sync_enabled {
|
||||||
|
|
||||||
|
std::fs::remove_file(utils::get_home_folder_str()+"/.sync.ipass").expect("could not disable sync, is it already disabled?");
|
||||||
|
|
||||||
|
println!("Sync is now Disabled!");
|
||||||
|
} else {
|
||||||
|
println!("Sync is already disabled!");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
println!("Invalid argument, check \"help\" for help");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isync(args: &Vec<String>) {
|
||||||
|
//! arguments: program isync [on/off]
|
||||||
|
if args.len() > 2 {
|
||||||
|
println!("Invalid usage of \"isync\"");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let arg: String = args[2].clone().to_lowercase();
|
||||||
|
|
||||||
|
match arg.as_str() {
|
||||||
|
"on" => {
|
||||||
|
todo!("ISync");
|
||||||
|
|
||||||
|
// println!("ISync is now Enabled!");
|
||||||
|
},
|
||||||
|
"off" => {
|
||||||
|
println!("ISync is now Disabled!");
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
println!("Invalid argument, check \"help\" for help");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
75
src/utils.rs
75
src/utils.rs
@ -1,4 +1,4 @@
|
|||||||
use std::io::Write;
|
use std::io::{Read, Write};
|
||||||
use aes_gcm::{
|
use aes_gcm::{
|
||||||
aead::{Aead, KeyInit},
|
aead::{Aead, KeyInit},
|
||||||
Aes256Gcm, Nonce
|
Aes256Gcm, Nonce
|
||||||
@ -9,6 +9,79 @@ pub fn get_args() -> Vec<String> {
|
|||||||
std::env::args().collect() // [0] = file path; [n>0] = argument
|
std::env::args().collect() // [0] = file path; [n>0] = argument
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn import_file(location:&String) -> bool {
|
||||||
|
if std::path::Path::new(&(location.clone()+"/export.ipassx")).exists() {
|
||||||
|
let mut reader = brotli::Decompressor::new(
|
||||||
|
std::fs::File::open(location.clone()+"/export.ipassx").unwrap(),
|
||||||
|
4096, // buffer size
|
||||||
|
);
|
||||||
|
let mut content: String = String::new();
|
||||||
|
let mut buf = [0u8; 4096];
|
||||||
|
loop {
|
||||||
|
match reader.read(&mut buf[..]) {
|
||||||
|
Err(e) => {
|
||||||
|
if let std::io::ErrorKind::Interrupted = e.kind() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
panic!("{}", e);
|
||||||
|
}
|
||||||
|
Ok(size) => {
|
||||||
|
if size == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
content += &std::str::from_utf8(&buf[..size]).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let lines = content.lines();
|
||||||
|
let mut name = "";
|
||||||
|
for i in lines {
|
||||||
|
if name == "" {
|
||||||
|
name = i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut file = std::fs::File::create(format!("{}/{}.ipass",get_ipass_folder(), name)).unwrap();
|
||||||
|
file.write_all(i.as_bytes()).unwrap();
|
||||||
|
name = "";
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn export_file(location:&String) -> bool {
|
||||||
|
let mut collected_data: String = String::new();
|
||||||
|
|
||||||
|
let paths = std::fs::read_dir(get_ipass_folder()).unwrap();
|
||||||
|
|
||||||
|
for p in paths {
|
||||||
|
if let Ok(path) = p {
|
||||||
|
let content = &mut std::fs::read_to_string(get_ipass_folder()+&path.file_name().into_string().unwrap()).expect("Should have been able to read the file");
|
||||||
|
collected_data += format!("{}\n{}\n", path.file_name().into_string().unwrap().replace(".ipass", ""),content).as_str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(file) = std::fs::File::create(location.clone()+"/export.ipassx") {
|
||||||
|
let mut writer = brotli::CompressorWriter::new(
|
||||||
|
file,
|
||||||
|
4096,
|
||||||
|
11,
|
||||||
|
22);
|
||||||
|
|
||||||
|
match writer.write_all(collected_data.as_bytes()) {
|
||||||
|
Err(e) => panic!("{}", e),
|
||||||
|
Ok(_) => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn vecu8_to_string(vec: Vec<u8>) -> String {
|
fn vecu8_to_string(vec: Vec<u8>) -> String {
|
||||||
let mut do_print_warning = false;
|
let mut do_print_warning = false;
|
||||||
let mut out: String = String::new();
|
let mut out: String = String::new();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user