[![Contributors][contributors-shield]][contributors-url] [![Forks][forks-shield]][forks-url] [![Stargazers][stars-shield]][stars-url] [![Issues][issues-shield]][issues-url] [![MIT License][license-shield]][license-url]

encrypt-config

A rust crate to manage, persist and encrypt your configurations.
Explore the docs »

View Demo · Report Bug · Request Feature

Table of Contents
  1. Import
  2. About The Project
  3. Usage
  4. Changelog
  5. Roadmap
  6. Contributing
  7. License
  8. Contact
  9. Acknowledgments
## Import ```toml [dependencies] encrypt_config = { version = "1.0", features = ["full"] } [profile.dev.package.num-bigint-dig] opt-level = 3 ``` # Caution On linux, the keys will expired or removed after reboot or long-term unused. So the rsa private key will be lost which leads this crate unable to decrypt the encrypted config file. So we recommend to easily use `PersistSource` instead of `SecretSource` on linux even other platforms, they are actually safe enough. ## About The Project Sometimes, we need to store config in our application that we don't want to expose to the public. For example, the database password, the api key, etc. One solution is to store them in the OS' secret manager, such as `Keychain` on macOS, `Credential Manager` on Windows, `libsecret` on Linux. However, they usually have limitation on the secret length. For example, `Keychain` only allows 255 bytes for the secret, `Credential Manager` is even shorter. So we can't store a long secret in it. Another solution is to store the secret in a file and encrypt it with a rsa public key, and store the private key in the OS' secret manager. This is what this crate does. This crate provides 3 ways to manage your config: - [`NormalSource`]: A normal source, not persisted or encrypted - [`PersistSource`]: A source that will be persisted to local file, not encrypted - [`SecretSource`]: A source that will be persisted to local file and encrypted This crate also has some optional features: - `persist`: If enabled, you can use the [`PersistSource`] trait. - `secret`: If enabled, you can use the [`PersistSource`] and the [`SecretSource`] trait. - `mock`: If enabled, you can use the mock for testing, which will not use the OS' secret manager. - `default_config_dir`: If enabled, the default config dir will be used. Implemented through [dirs](https://crates.io/crates/dirs). Moreover, as development progresses, a memory cache design is added for persistent data access speeding up. This leads this crate actually behaving more like bevy_ecs's resource system (or dependencies injecion with only args retrieving implemented). The cache is released as an independent crate [rom_cache](https://crates.io/crates/rom_cache). The `Config` in this crate is a wrapper of `rom_cache::Cache`, only if the config is modified and marked dirty will the data be persisted to the storage.

(back to top)

### Built With * Rust * Keyring

(back to top)

## Usage ### Example ```rust no_run # #[cfg(all(feature = "full", feature = "mock", feature = "default_config_dir"))] # { use encrypt_config::{Config, NormalSource, PersistSource, SecretSource}; use serde::{Deserialize, Serialize}; use std::sync::OnceLock; #[derive(Default, NormalSource)] struct NormalConfig { count: usize, } #[derive(Default, Serialize, Deserialize, PersistSource)] #[source(name = "persist_config.json")] struct PersistConfig { name: String, age: usize, } #[derive(Default, Serialize, Deserialize, SecretSource)] #[source(name = "secret_config", keyring_entry = "secret")] struct SecretConfig { password: String, } { // Here we have 2 kinds of config at the same time at most, so N is 2 let cfg: Config<2> = Config::default(); { let normal = cfg.get::(); // default value assert_eq!(normal.count, 0); } { let mut normal = cfg.get_mut::(); normal.count = 42; assert_eq!(normal.count, 42); } { let mut persist = cfg.get_mut::(); persist.name = "Louis".to_string(); persist.age = 22; let mut secret = cfg.get_mut::(); secret.password = "123456".to_string(); } // Changes will be saved automatically as Config dropped } { // Assume this is a new config in the next start // Here we have 1 kinds of config at the same time at most, so N is 1 let cfg: Config<1> = Config::default(); { // normal config will not be saved assert_eq!(cfg.get::().count, 0); // persist config will be saved assert_eq!(cfg.get::().name, "Louis"); // secret config will be encrypted assert_eq!(cfg.get::().password, "123456"); } // The secret config file should not be able to load directly let encrypted_file = std::fs::File::open(SecretConfig::path()).unwrap(); assert!(serde_json::from_reader::<_, SecretConfig>(encrypted_file).is_err()); } # } ``` Surely, you can also easily use methods provided by `PersistSource` and `SecretSource` to load and save the config manually, instead of the complex `Config` cache. _For more examples, please refer to the [tests](https://github.com/kingwingfly/encrypt-config/tree/dev/tests), [Example](https://github.com/kingwingfly/encrypt-config/blob/dev/examples/example.rs) or [Documentation](https://docs.rs/encrypt_config)_

(back to top)

## Changelog - 0.5.x -> 1.0.x: no feature difference between linux and others; user define cache size - 0.4.x -> 0.5.x: Cache inside `Config` now behaves **totally** like a native cache. Changes will be saved as `Config` dropped automatically. - v0.3.x -> v0.4.x: Cache inside `Config` now behaves more like a native cache. Changes will be saved as `ConfigMut` dropped automatically. - v0.2.x -> v0.3.x: Now, multi-config-sources can be saved and loaded through `Config` in one go. But `add_xx_source`s are removed. By the way, one can defined their own sources by implementing `Source` trait while `NormalSource` `PersistSource` `SecretSource` are still provided. - v0.1.x -> v0.2.x: A broken change has been made. Heavily refactored with `std::any` and methods from `dependencies injection`. [more detailed changelog](https://github.com/kingwingfly/encrypt-config/blob/dev/CHANGELOG.md)

(back to top)

## Roadmap - [ ] Enable protobuf instead of json for better performance See the [open issues](https://github.com/kingwingfly/encrypt-config/issues) for a full list of proposed features (and known issues).

(back to top)

## Contributing Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again! 1. Fork the Project 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`) 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`) 4. Push to the Branch (`git push origin feature/AmazingFeature`) 5. Open a Pull Request

(back to top)

## License Distributed under the MIT License. See `LICENSE.txt` for more information.

(back to top)

## Contact Louis - 836250617@qq.com Project Link: [https://github.com/kingwingfly/encrypt-config](https://github.com/kingwingfly/encrypt-config)

(back to top)

[contributors-shield]: https://img.shields.io/github/contributors/kingwingfly/encrypt-config.svg?style=for-the-badge [contributors-url]: https://github.com/kingwingfly/encrypt-config/graphs/contributors [forks-shield]: https://img.shields.io/github/forks/kingwingfly/encrypt-config.svg?style=for-the-badge [forks-url]: https://github.com/kingwingfly/encrypt-config/network/members [stars-shield]: https://img.shields.io/github/stars/kingwingfly/encrypt-config.svg?style=for-the-badge [stars-url]: https://github.com/kingwingfly/encrypt-config/stargazers [issues-shield]: https://img.shields.io/github/issues/kingwingfly/encrypt-config.svg?style=for-the-badge [issues-url]: https://github.com/kingwingfly/encrypt-config/issues [license-shield]: https://img.shields.io/github/license/kingwingfly/encrypt-config.svg?style=for-the-badge [license-url]: https://github.com/kingwingfly/encrypt-config/blob/master/LICENSE.txt [linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=for-the-badge&logo=linkedin&colorB=555 [product-screenshot]: images/screenshot.png