├── .deepsource.toml ├── .github ├── CODE-OF-CONDUCT.md ├── CODEOWNERS ├── CONTRIBUTING.md ├── SECURITY.md ├── dependabot.yml ├── funding.yml └── workflows │ └── rust.yml ├── .gitignore ├── .vscode └── settings.json ├── COPYRIGHT ├── Cargo.toml ├── LICENSE-Apache ├── LICENSE-MIT ├── README.md ├── TEMPLATE.md ├── TODO.md ├── bubba.ico ├── build.rs ├── cclm ├── Cargo.toml ├── README.md ├── benches │ └── cclm.rs ├── build.rs ├── deny.toml ├── examples │ └── cclm.rs ├── rustfmt.toml ├── src │ └── lib.rs └── tests │ └── claims.rs ├── cjwt ├── Cargo.toml ├── README.md ├── benches │ └── cjwt.rs ├── build.rs ├── deny.toml ├── examples │ └── cjwt.rs ├── rustfmt.toml ├── src │ └── lib.rs └── tests │ └── cjwt.rs ├── deny.toml ├── examples ├── example_claims.rs ├── example_constants.rs ├── example_date.rs ├── example_errors.rs ├── example_hash.rs ├── example_jwt.rs ├── example_logs.rs ├── example_md5.rs ├── example_qr.rs └── example_random.rs ├── idk ├── Cargo.toml ├── README.md ├── benches │ └── idk.rs ├── deny.toml ├── examples │ └── idk.rs ├── rustfmt.toml ├── src │ ├── common.rs │ ├── error.rs │ ├── jwt.rs │ ├── lib.rs │ ├── property.rs │ ├── stacktrace.rs │ └── traits.rs └── tests │ ├── common.rs │ ├── error.rs │ ├── jwt.rs │ ├── property.rs │ ├── stacktrace.rs │ └── traits.rs ├── mdg ├── Cargo.toml ├── README.md ├── benches │ └── mdg.rs ├── build.rs ├── deny.toml ├── examples │ └── mdg.rs ├── file.txt ├── rustfmt.toml ├── src │ ├── constants.rs │ ├── digest.rs │ ├── lib.rs │ └── params.rs ├── tests │ ├── constants.rs │ ├── digest.rs │ ├── lib.rs │ └── params.rs └── update.txt ├── rustfmt.toml └── src ├── claims.rs ├── common.rs ├── date.rs ├── errors.rs ├── hash.rs ├── jwt.rs ├── lib.rs ├── logs.rs ├── md5.rs ├── qr.rs └── random.rs /.deepsource.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [[analyzers]] 4 | name = "rust" 5 | enabled = true 6 | 7 | [analyzers.meta] 8 | msrv = "stable" -------------------------------------------------------------------------------- /.github/CODE-OF-CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our 7 | project and our community a harassment-free experience for everyone, 8 | regardless of age, body size, disability, ethnicity, gender identity and 9 | expression, level of experience, nationality, personal appearance, race, 10 | religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behaviour that contributes to creating a positive 15 | environment include: 16 | 17 | - Using welcoming and inclusive language 18 | - Being respectful of differing viewpoints and experiences 19 | - Gracefully accepting constructive criticism 20 | - Focusing on what is best for the community 21 | - Showing empathy towards other community members 22 | 23 | Examples of unacceptable behaviour by participants include: 24 | 25 | - The use of sexualized language or imagery and unwelcome sexual 26 | attention or advances 27 | - Trolling, insulting/derogatory comments, and personal or political 28 | attacks 29 | - Public or private harassment 30 | - Publishing others' private information, such as a physical or 31 | electronic address, without explicit permission 32 | - Other conduct which could reasonably be considered inappropriate in a 33 | professional setting 34 | 35 | ## Our Responsibilities 36 | 37 | Project maintainers are responsible for clarifying the standards of 38 | acceptable behaviour and are expected to take appropriate and fair 39 | corrective action in response to any instances of unacceptable 40 | behaviour. 41 | 42 | Project maintainers have the right and responsibility to remove, edit, 43 | or reject comments, commits, code, wiki edits, issues, and other 44 | contributions that are not aligned to this Code of Conduct, or to ban 45 | temporarily or permanently any contributor for other behaviors that they 46 | deem inappropriate, threatening, offensive, or harmful. 47 | 48 | ## Scope 49 | 50 | This Code of Conduct applies both within project spaces and in public 51 | spaces when an individual is representing the project or its community. 52 | Examples of representing a project or community include using an 53 | official project e-mail address, posting via an official social media 54 | account, or acting as an appointed representative at an online or 55 | offline event. Representation of a project may be further defined and 56 | clarified by project maintainers. 57 | 58 | ## Enforcement 59 | 60 | Instances of abusive, harassing, or otherwise unacceptable behaviour may 61 | be reported by contacting the project team. The project team will review 62 | and investigate all complaints, and will respond in a way that it deems 63 | appropriate to the circumstances. The project team is obligated to 64 | maintain confidentiality with regard to the reporter of an incident. 65 | Further details of specific enforcement policies may be posted 66 | separately. 67 | 68 | Project maintainers who do not follow or enforce the Code of Conduct in 69 | good faith may face temporary or permanent repercussions as determined 70 | by other members of the project's leadership. 71 | 72 | ## Attribution 73 | 74 | This Code of Conduct is adapted from the Contributor Covenant homepage, 75 | version 1.4, available at 76 | [version](http://contributor-covenant.org/version/1/4) 77 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | @sebastienrousseau/mini-functions -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thank you so much for wanting to contribute to the Mini Functions! 4 | There are a couple ways to help out. 5 | 6 | ## Evangelize 7 | 8 | Just tell people about the Mini Functions. We believe that a bigger, 9 | more involved community makes for a better framework, and that better 10 | frameworks make the world a better place. We can always use more 11 | feedback. 12 | 13 | ## How to Contribute 14 | 15 | Here are guides for submitting issues and pull requests. 16 | 17 | ### Bug Reports 18 | 19 | If you encounter a bug that hasn't already been filed, please file a 20 | bug report. Let us know of things we should fix, things we should add, 21 | questions, etc. 22 | 23 | Warning us of a bug is possibly the single most valuable contribution 24 | you can make to the Mini Functions. 25 | 26 | - Head 27 | [here](https://github.com/sebastienrousseau/mini-functions/issues/new) 28 | to submit a new issue. 29 | - Include a descriptive title that is straight to the point. 30 | - Write a detailed description on what the issue is all about. 31 | - Wait for someone to get to the issue and add labels. 32 | - The issue will be fixed soon! 33 | 34 | ### Code Contributions 35 | 36 | Contributing code is one of the more difficult ways to contribute to the 37 | Mini Functions. 38 | 39 | #### Feature Requests 40 | 41 | Filing feature requests is one of the most popular ways to contribute to 42 | the Mini Functions. 43 | 44 | Is there some feature request that you'd like to code up yourself? Is 45 | there a feature you asked for yourself that you'd like to code? 46 | 47 | Here's how to contribute code for a new feature to the Mini Functions. 48 | Pull Requests allow you to share your own code with us, and we can merge 49 | it into the main repo. 50 | 51 | #### Adding Code 52 | 53 | - Fork the repo. 54 | - Clone the the Mini Functions repo by running: 55 | `git clone https://github.com/sebastienrousseau/mini-functions.git` 56 | - Edit files in the `src/` folder. The `src/` folder contains the source 57 | code for the Mini Functions. 58 | 59 | #### Fixing an Issue 60 | 61 | Have you found a solution to an issue? Here is how you can submit your 62 | code to the Mini Functions. 63 | 64 | - Fork the repo, and refer above for how to change up code. 65 | - Head to your local fork of the repo and click the "New Pull Request" button. 66 | - Include a title that is straight to the point. 67 | - Wait for someone to review the pull request, and then merge yours! 68 | -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security 2 | 3 | We take the security of our software products and services seriously, 4 | which includes all source code repositories managed through our GitHub 5 | repositories. 6 | 7 | If you believe you have found a security vulnerability in any of our 8 | repository, please report it to us as described below. 9 | 10 | ## Reporting Security Issues 11 | 12 | Please include the requested information listed below (as much as you 13 | can provide) to help us better understand the nature and scope of the 14 | possible issue: 15 | 16 | - Type of issue (e.g. buffer overflow, SQL injection, cross-site 17 | scripting, etc.) 18 | - Full paths of source file(s) related to the manifestation of the issue 19 | - The location of the affected source code (tag/branch/commit or direct 20 | URL) 21 | - Any special configuration required to reproduce the issue 22 | - Step-by-step instructions to reproduce the issue 23 | - Proof-of-concept or exploit code (if possible) 24 | - Impact of the issue, including how an attacker might exploit the issue 25 | 26 | This information will help us triage your report more quickly. 27 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "cargo" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | 8 | - package-ecosystem: "github-actions" 9 | directory: "/" 10 | schedule: 11 | interval: "daily" 12 | -------------------------------------------------------------------------------- /.github/funding.yml: -------------------------------------------------------------------------------- 1 | github: sebastienrousseau 2 | custom: https://paypal.me/wwdseb 3 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: ❯ release 2 | 3 | on: [push] 4 | 5 | env: 6 | CARGO_TERM_COLOR: always 7 | 8 | jobs: 9 | targets: 10 | name: mf_${{ matrix.target }} 11 | runs-on: ${{ matrix.os }} 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | target: 16 | # List of targets: https://doc.rust-lang.org/nightly/rustc/platform-support.html 17 | 18 | # Linux targets 🐧 19 | - aarch64-unknown-linux-gnu # 64-bit Linux systems on ARM architecture ✅ Tested 20 | - aarch64-unknown-linux-musl # 64-bit Linux systems on ARM architecture ✅ Tested 21 | - arm-unknown-linux-gnueabi # ARMv6 Linux (kernel 3.2, glibc 2.17) ✅ Tested 22 | - armv7-unknown-linux-gnueabihf # ARMv7 Linux, hardfloat (kernel 3.2, glibc 2.17) ✅ Tested 23 | - i686-unknown-linux-gnu # 32-bit Linux (kernel 3.2+, glibc 2.17+) ✅ Tested 24 | - i686-unknown-linux-musl # 32-bit Linux (kernel 3.2+, musl libc) ✅ Tested 25 | # - mips-unknown-linux-gnu # MIPS Linux (kernel 2.6.32+, glibc 2.11+) ❌ Tested 26 | # - mips-unknown-linux-musl # MIPS Linux (kernel 2.6.32+, musl libc) ❌ Tested 27 | # - mips64-unknown-linux-gnuabi64 # MIPS64 Linux (kernel 2.6.32+, glibc 2.11+) ❌ Tested 28 | # - mips64el-unknown-linux-gnuabi64 # MIPS64el Linux (kernel 2.6.32+, glibc 2.11+) ❌ Tested 29 | # - mipsel-unknown-linux-gnu # MIPSel Linux (kernel 2.6.32+, glibc 2.11+) ❌ Tested 30 | # - powerpc64le-unknown-linux-gnu # 64-bit PowerPC Linux (kernel 2.6.32+, glibc 2.11+) ❌ Tested 31 | - x86_64-unknown-linux-gnu # 64-bit Linux (kernel 2.6.32+, glibc 2.11+) ✅ Tested 32 | - x86_64-unknown-linux-musl # 64-bit Linux (kernel 2.6.32+, musl libc) ✅ Tested 33 | 34 | # macOS targets 🍎 35 | - x86_64-apple-darwin # 64-bit macOS (10.7 Lion or later) ✅ Tested 36 | 37 | # Windows targets 🪟 38 | # - i686-pc-windows-msvc # 32-bit Windows ❌ Tested 39 | # - x86_64-pc-windows-msvc # 64-bit Windows ❌ Tested 40 | 41 | include: 42 | # Linux targets 🐧 43 | - target: aarch64-unknown-linux-gnu # 64-bit Linux systems on ARM architecture 44 | os: ubuntu-latest 45 | cross: true 46 | - target: aarch64-unknown-linux-musl # 64-bit Linux systems on ARM architecture 47 | os: ubuntu-latest 48 | cross: true 49 | - target: arm-unknown-linux-gnueabi # ARMv6 Linux (kernel 3.2, glibc 2.17) 50 | os: ubuntu-latest 51 | cross: true 52 | - target: armv7-unknown-linux-gnueabihf # ARMv7 Linux, hardfloat (kernel 3.2, glibc 2.17) 53 | os: ubuntu-latest 54 | cross: true 55 | - target: i686-unknown-linux-gnu # 32-bit Linux (kernel 3.2+, glibc 2.17+) 56 | os: ubuntu-latest 57 | cross: true 58 | - target: i686-unknown-linux-musl # 32-bit Linux (kernel 3.2+, musl libc) 59 | os: ubuntu-latest 60 | cross: true 61 | # - target: mips-unknown-linux-gnu # MIPS Linux (kernel 2.6.32+, glibc 2.11+) 62 | # os: ubuntu-latest 63 | # cross: true 64 | # - target: mips-unknown-linux-musl # MIPS Linux (kernel 2.6.32+, musl libc) 65 | # os: ubuntu-latest 66 | # cross: true 67 | # - target: mips64-unknown-linux-gnuabi64 # MIPS64 Linux (kernel 2.6.32+, glibc 2.11+) 68 | # os: ubuntu-latest 69 | # cross: true 70 | # - target: mips64el-unknown-linux-gnuabi64 # MIPS64el Linux (kernel 2.6.32+, glibc 2.11+) 71 | # os: ubuntu-latest 72 | # cross: true 73 | # - target: mipsel-unknown-linux-gnu # MIPSel Linux (kernel 2.6.32+, glibc 2.11+) 74 | # os: ubuntu-latest 75 | # cross: true 76 | # - target: powerpc64le-unknown-linux-gnu # 64-bit PowerPC Linux (kernel 2.6.32+, glibc 2.11+) 77 | # os: ubuntu-latest 78 | # cross: true 79 | - target: x86_64-unknown-linux-gnu # 64-bit Linux (kernel 2.6.32+, glibc 2.11+) 80 | os: ubuntu-latest 81 | cross: true 82 | - target: x86_64-unknown-linux-musl # 64-bit Linux (kernel 2.6.32+, musl libc) 83 | os: ubuntu-latest 84 | cross: true 85 | 86 | # macOS targets 🍎 87 | - target: x86_64-apple-darwin # 64-bit macOS (10.7 Lion or later) 88 | os: macos-latest 89 | cross: true 90 | 91 | # Windows targets 🪟 92 | # - target: i686-pc-windows-msvc # 32-bit Windows 93 | # os: windows-latest 94 | # cross: true 95 | # - target: x86_64-pc-windows-msvc # 64-bit Windows 96 | # os: windows-latest 97 | # cross: true 98 | 99 | max-parallel: 2 100 | 101 | steps: 102 | - name: Checkout repository 🛎️ 103 | id: checkout-repository 104 | uses: actions/checkout@v4 105 | with: { submodules: true } 106 | 107 | - name: Installing Rust 🦀 108 | id: install-rust 109 | run: | 110 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y 111 | shell: /bin/bash -e {0} 112 | 113 | - name: Update version number 🧮 114 | id: update-version 115 | if: github.ref == 'refs/heads/main' && !github.event.check_run.conclusion 116 | run: | 117 | NEW_VERSION=$(grep version Cargo.toml | sed -n 2p | cut -d '"' -f 2) 118 | echo "VERSION=$NEW_VERSION" >> $GITHUB_ENV 119 | shell: /bin/bash -e {0} 120 | 121 | - name: Install Cross 🦀 122 | id: install-cross 123 | run: | 124 | # Install cross 125 | cargo install cross 126 | 127 | # Clean the build artifacts 128 | cargo clean --verbose 129 | shell: /bin/bash -e {0} 130 | 131 | - name: Build targets 🏗 132 | id: build-targets 133 | uses: actions-rs/cargo@v1 134 | with: 135 | use-cross: true 136 | command: build 137 | args: --verbose --workspace --release --target ${{ matrix.target }} 138 | 139 | - name: Run Cargo Format 🦀 140 | id: run-check-format 141 | if: github.ref == !github.event.check_run.conclusion 142 | run: | 143 | cargo check --all --all-features --workspace --verbose 144 | 145 | - name: Run Clippy 🦀 146 | id: run-check-clippy 147 | if: github.ref == !github.event.check_run.conclusion 148 | run: | 149 | cargo clippy --all-targets --all-features --workspace -- -D warnings 150 | 151 | - name: Run Cargo Doc 🦀 152 | id: run-check-doc 153 | if: github.ref == 'refs/heads/main' && !github.event.check_run.conclusion 154 | run: | 155 | cargo doc --workspace --color always --no-deps --release --all-features 156 | 157 | - name: Run Cargo Test 🦀 158 | id: run-check-test 159 | if: github.ref == 'refs/heads/main' 160 | run: | 161 | cargo test --all-targets --workspace --all-features 162 | 163 | - name: Run Cargo Code Coverage 🦀 164 | id: run-check-code-coverage 165 | if: github.ref == 'refs/heads/main' && !github.event.check_run.conclusion 166 | run: | 167 | # Install tarpaulin 168 | cargo install cargo-tarpaulin 169 | 170 | # Run tarpaulin and generate the code coverage report 171 | cargo tarpaulin --all --all-features --workspace --out Xml 172 | 173 | - name: Upload to codecov.io 📊 174 | id: upload-codecov 175 | if: github.ref == 'refs/heads/main' && !github.event.check_run.conclusion 176 | uses: codecov/codecov-action@v4 177 | with: 178 | token: ${{ secrets.CODECOV_TOKEN }} 179 | fail_ci_if_error: false 180 | verbose: false 181 | 182 | - name: Package the binary 📦 183 | id: package-binary 184 | if: github.ref == 'refs/heads/main' 185 | run: | 186 | mkdir -p target/package 187 | tar czf target/package/${{ matrix.target }}.tar.gz -C target/${{ matrix.target }}/release . 188 | 189 | - name: Deploy binary 🚀 190 | id: deploy-binary 191 | if: github.ref == 'refs/heads/main' 192 | uses: actions/upload-artifact@v4 193 | with: 194 | name: ${{ matrix.target }}.tar.gz 195 | path: target/package/${{ matrix.target }}.tar.gz 196 | 197 | - name: Generate Changelog 📜 198 | id: generate-changelog 199 | if: github.ref == 'refs/heads/main' && !github.event.check_run.conclusion 200 | run: | 201 | # Append version information to CHANGELOG.md 202 | echo "## [${{ env.VERSION }}] - $(date +'%Y-%m-%d')" >> ${{ github.workspace }}/CHANGELOG.md 203 | # Copy content of template file to CHANGELOG.md 204 | cat TEMPLATE.md > ${{ github.workspace }}/CHANGELOG.md 205 | # Append git log to CHANGELOG.md 206 | echo "$(git log --pretty=format:'%s' --reverse $(git describe --tags --abbrev=0)..HEAD)" >> ${{ github.workspace }}/CHANGELOG.md 207 | # Append empty line to CHANGELOG.md 208 | echo "" >> ${{ github.workspace }}/CHANGELOG.md 209 | # Append empty line to CHANGELOG.md 210 | echo "" >> ${{ github.workspace }}/CHANGELOG.md 211 | 212 | - name: Create Release 🚀 213 | id: create_release 214 | if: github.ref == 'refs/heads/main' && !github.event.check_run.conclusion 215 | uses: actions/create-release@v1 216 | env: 217 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 218 | with: 219 | tag_name: v${{ env.VERSION }} 220 | release_name: Mini Functions 🦀 v${{ env.VERSION }} 221 | body_path: ${{ github.workspace }}/CHANGELOG.md 222 | draft: true 223 | prerelease: false 224 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | *.profraw 3 | /target/ 4 | Cargo.lock 5 | Icon? 6 | src/.DS_Store 7 | build 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "aarch", 4 | "ABCDEFGHIJKLMNOP", 5 | "armhf", 6 | "ascii", 7 | "badcfe", 8 | "bdceee", 9 | "bdecfa", 10 | "beea", 11 | "binutils", 12 | "blake", 13 | "BSON", 14 | "bubba", 15 | "cclm", 16 | "cdylib", 17 | "ceee", 18 | "certutil", 19 | "cjwt", 20 | "clippy", 21 | "Codecov", 22 | "commitish", 23 | "congruential", 24 | "constify", 25 | "consts", 26 | "crossbuild", 27 | "czvf", 28 | "datetime", 29 | "dcfe", 30 | "dianelos", 31 | "Dianelos", 32 | "dylib", 33 | "errcode", 34 | "errtype", 35 | "euler", 36 | "Funct", 37 | "gelf", 38 | "GELF", 39 | "Georgoudis", 40 | "getrandom", 41 | "github", 42 | "GITHUB", 43 | "gnuabi", 44 | "gnubin", 45 | "gnueabi", 46 | "gnueabihf", 47 | "hardfloat", 48 | "hasher", 49 | "hashfile", 50 | "hcrv", 51 | "hdrv", 52 | "hexdigest", 53 | "hmac", 54 | "Hmac", 55 | "imageops", 56 | "intrinsics", 57 | "jdrv", 58 | "jsonwebtoken", 59 | "JWSs", 60 | "JWTs", 61 | "LFSR", 62 | "libc", 63 | "libexec", 64 | "libmini", 65 | "linux", 66 | "Makoto", 67 | "mant", 68 | "math", 69 | "Matsumoto", 70 | "Mersenne", 71 | "minifunctions", 72 | "mips", 73 | "mipsel", 74 | "msvc", 75 | "musleabihf", 76 | "mysecret", 77 | "nanos", 78 | "nbits", 79 | "nbytes", 80 | "Nishimura", 81 | "nonoverlapping", 82 | "oneline", 83 | "openssl", 84 | "OPENSSL", 85 | "padlen", 86 | "PKCS", 87 | "planck", 88 | "PRNG", 89 | "psph", 90 | "qrcode", 91 | "rlib", 92 | "RSASSA", 93 | "rustc", 94 | "RUSTFLAGS", 95 | "rustfmt", 96 | "rustup", 97 | "Seedable", 98 | "serde", 99 | "simd", 100 | "slli", 101 | "softprops", 102 | "splitn", 103 | "srli", 104 | "staticlib", 105 | "strptime", 106 | "struct", 107 | "structs", 108 | "Swatinem", 109 | "Takuji", 110 | "tecapro", 111 | "tlsv", 112 | "trunc", 113 | "Uevx", 114 | "unguessed", 115 | "usize", 116 | "uuid", 117 | "varkey", 118 | "wordlist", 119 | "xbebf", 120 | "xbebfbc", 121 | "xeaa", 122 | "xefcd", 123 | "xefcdab", 124 | "xfcef", 125 | "xfcefa", 126 | "xfde", 127 | "xffef", 128 | "xffeff", 129 | "xfffa", 130 | "xffff", 131 | "Zellers" 132 | ], 133 | "conventionalCommits.scopes": [ 134 | "mini-functions" 135 | ] 136 | } -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | MINI FUNCTIONS 2 | 3 | A Rust library of highly performant utility and wrapper functions 4 | 5 | 1 - LICENSE 6 | 7 | This project, is licensed under either of the following, at your option: 8 | 9 | - Apache License, Version 2.0 (LICENSE-APACHE or 10 | ) 11 | - MIT license (LICENSE-MIT or ) 12 | 13 | 2 - CONTRIBUTION 14 | 15 | Unless you explicitly state otherwise, any contribution intentionally 16 | submitted for inclusion in the work by you, as defined in the Apache- 17 | 2.0 license, shall be dual licensed as above, without any additional 18 | terms or conditions Password Generator Pro Project is dual-licensed 19 | under Apache 2.0 and MIT terms. 20 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["The minifunctions contributors "] 3 | build = "build.rs" 4 | categories = ["development-tools", "parsing", "value-formatting", "algorithms", "date-and-time"] 5 | description = "A Rust library of highly performant utility and wrapper functions" 6 | documentation = "https://docs.rs/mini-functions" 7 | edition = "2021" 8 | exclude = [ 9 | "/.git/*", 10 | "/.github/*", 11 | "/.gitignore", 12 | "/.vscode/*" 13 | ] 14 | homepage = "https://minifunctions.com" 15 | include = [ 16 | "/build.rs", 17 | "/Cargo.toml", 18 | "/cclm/**", 19 | "/cjwt/**", 20 | "/idk/**", 21 | "/LICENSE-APACHE", 22 | "/LICENSE-MIT", 23 | "/mdg/**", 24 | "/README.md", 25 | "/src/**", 26 | "/tests/**", 27 | ] 28 | keywords = [ 29 | "libraries", 30 | "mini-functions", 31 | "toolkit", 32 | "utilities", 33 | "functions", 34 | ] 35 | license = "Apache-2.0 OR MIT" 36 | name = "mini-functions" 37 | readme = "README.md" 38 | repository = "https://github.com/sebastienrousseau/mini-functions.git" 39 | rust-version = "1.71.1" 40 | version = "0.0.10" 41 | 42 | [dependencies] 43 | cclm = "0.0.1" 44 | cjwt = "0.0.1" 45 | cmn = "0.0.3" 46 | dtt = "0.0.5" 47 | hsh = "0.0.7" 48 | idk = "0.0.1" 49 | mdg = "0.0.1" 50 | qrc = "0.0.5" 51 | rlg = "0.0.2" 52 | vrd = "0.0.5" 53 | serde_json = "1.0.108" 54 | image = "0.25.1" 55 | 56 | [workspace] 57 | exclude = ["src"] 58 | resolver = "2" 59 | members = [ 60 | "cclm", 61 | "cjwt", 62 | "idk", 63 | "mdg", 64 | ] # List of workspace members 65 | 66 | [workspace.package] 67 | rust-version = "1.71.1" 68 | 69 | [badges] 70 | maintenance = { status = "actively-developed" } 71 | 72 | [lib] 73 | crate-type = ["lib"] 74 | path = "src/lib.rs" 75 | required-features = [ 76 | "cclm", 77 | "cmn", 78 | "dtt", 79 | "idk", 80 | "hsh", 81 | "cjwt", 82 | "rlg", 83 | "mdg", 84 | "qrc", 85 | ] 86 | 87 | [profile.dev] 88 | codegen-units = 4 89 | debug = true 90 | debug-assertions = true 91 | incremental = true 92 | lto = false 93 | opt-level = 0 94 | overflow-checks = true 95 | panic = 'unwind' 96 | rpath = false 97 | strip = false 98 | 99 | [profile.release] 100 | codegen-units = 1 101 | debug = false 102 | debug-assertions = false 103 | incremental = false 104 | lto = true 105 | opt-level = "s" 106 | overflow-checks = false 107 | panic = "abort" 108 | rpath = false 109 | strip = "symbols" 110 | 111 | [profile.test] 112 | codegen-units = 256 113 | debug = true 114 | debug-assertions = true 115 | incremental = true 116 | lto = false 117 | opt-level = 0 118 | overflow-checks = true 119 | rpath = false 120 | strip = false 121 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Sebastien Rousseau 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | Common (CMN) logo 5 | 6 | 7 | 8 | # Mini Functions 9 | 10 | A Rust library of highly performant utility and wrapper functions 11 | 12 | 13 |
14 | 15 | [![Mini Functions][title]][00] 16 | 17 | [![Made With Love][made-with-rust]][10] 18 | [![Crates.io][crates-badge]][07] 19 | [![Lib.rs][libs-badge]][09] 20 | [![Docs.rs][docs-badge]][08] 21 | [![License][license-badge]][02] 22 | [![Codecov][codecov-badge]][11] 23 | 24 | ![divider][divider] 25 | 26 | • [Website][00] • [Documentation][08] • [Report Bug][03] • [Request Feature][03] • [Contributing Guidelines][04] 27 | 28 |
29 | 30 | ## Overview 📖 31 | 32 | `Mini Functions` is a highly performant utility and wrapper functions library for Rust that has been carefully designed with optimization and efficiency in mind. By providing convenient wrapper functions, our library aims to provide a high-level interface for common tasks while still leveraging the performance benefits of Rust under the hood. These utility functions serve as an essential toolkit for any Rust developer, and the library's design abstractions allow for easy integration into a variety of projects and applications. 33 | 34 | These utility functions serve as an essential toolkit for any Rust developer, and the library's design abstractions allow for easy integration into a variety of projects and applications. 35 | 36 | ## Features ✨ 37 | 38 | - **Built with Rust** — A modern programming language that is well-suited for building high-performance, reliable, and secure systems. 39 | - **High-level Utility Functions** — A collection of high-level, abstracted functions for common tasks, such as string manipulation, file manipulation, and data parsing. 40 | - **Wrapper Functions for Easy Access** — Wrapper functions that provide a more convenient interface for accessing and using underlying Rust libraries or APIs. 41 | - **Optimization and Performance Tools** — Tools for optimizing and improving the performance of Rust code. 42 | - **Multi-platform Support** — Support for a variety of platforms, including desktop, mobile, and web. 43 | - **Comprehensive Documentation and Examples** — Documentation and examples to help developers understand and use the library effectively. 44 | - **Regular Maintenance and Updates** — Regular updates and maintenance to ensure the library stays up-to-date and reliable. 45 | 46 | [00]: https://minifunctions.com "Mini Functions - Highly performant utility and wrapper functions library for Rust" 47 | [02]: http://opensource.org/licenses/MIT "MIT license" 48 | [03]: https://github.com/sebastienrousseau/mini-functions/issues "Mini Functions Issues" 49 | [04]: https://raw.githubusercontent.com/sebastienrousseau/mini-functions/main/.github/CONTRIBUTING.md "Mini Functions Contributing Guidelines" 50 | [07]: https://crates.io/crates/mini-functions "Mini Functions on Crates.io" 51 | [08]: https://docs.rs/mini-functions "Mini Functions on Docs.rs" 52 | [09]: https://lib.rs/crates/mini-functions "Mini Functions on Lib.rs" 53 | [10]: https://www.rust-lang.org/ "The Rust Programming Language" 54 | [11]: https://codecov.io/github/sebastienrousseau/mini-functions "Mini Functions Codecov" 55 | 56 | [codecov-badge]: https://img.shields.io/codecov/c/github/sebastienrousseau/mini-functions?style=for-the-badge&token=M1REIC3QCK 'Codecov' 57 | [crates-badge]: https://img.shields.io/crates/v/mini-functions.svg?style=for-the-badge 'Crates.io' 58 | [divider]: https://kura.pro/common/images/elements/divider.svg "divider" 59 | [docs-badge]: https://img.shields.io/docsrs/mini-functions.svg?style=for-the-badge 'Docs.rs' 60 | [libs-badge]: https://img.shields.io/badge/lib.rs-v0.0.10-orange.svg?style=for-the-badge 'Lib.rs' 61 | [license-badge]: https://img.shields.io/crates/l/mini-functions.svg?style=for-the-badge 'License' 62 | [made-with-rust]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust 'Made With Rust' 63 | [title]: https://kura.pro/mini-functions/images/v2/titles/title-mini-functions.svg "Mini Functions Logo" 64 | 65 | ## Changelog 📚 66 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # Mini Functions 🦀 2 | 3 | A collection of mini functions for building secure, reliable, and performant applications. 4 | 5 | ## Overview 6 | 7 | ## To do 8 | 9 | - [ ] A function for encoding and decoding data using base64, which is a common encoding format used for transferring data over the internet. 10 | - [ ] A function for compressing and decompressing data using a popular compression algorithm like gzip. 11 | - [ ] A function for generating and parsing JSON data, which is a popular format for exchanging data between systems. 12 | - [ ] A function for generating and validating digital signatures, which can be used to verify the authenticity and integrity of a message or document. 13 | - [ ] A function for generating and parsing INI data, which is a simple, human-readable format for storing configuration information. 14 | - [ ] A function for generating and parsing BSON data, which is a binary serialization format used by MongoDB. 15 | - [ ] A function for generating and verifying digital signatures using a variety of cryptographic algorithms (e.g. RSA, ECDSA, DSA). 16 | - [ ] A function for generating and verifying message authentication codes (MACs) using cryptographic hash functions like HMAC. 17 | - [ ] A function for generating and verifying checksums using cryptographic hash functions like SHA-256 or SHA-3. 18 | - [ ] A function for generating and verifying timestamps using cryptographic methods, which can be used to prove the existence of a document at a specific point in time. 19 | - [ ] A function for generating and verifying digital certificates, which can be used to authenticate the identity of a person or organisation. 20 | - [ ] A function for generating and verifying one-time passwords (OTPs), which can be used for secure two-factor authentication. 21 | - [ ] A function for generating and verifying post-quantum key pairs using algorithms like lattice-based cryptography or code-based cryptography. 22 | - [ ] A function for generating and verifying post-quantum digital signatures using algorithms like lattice-based cryptography or code-based cryptography. 23 | - [ ] A function for generating and verifying post-quantum message authentication codes using algorithms like lattice-based cryptography or code-based cryptography. 24 | - [ ] A function for generating and verifying post-quantum checksums using algorithms like lattice-based cryptography or code-based cryptography. 25 | - [ ] A function for generating and verifying post-quantum timestamps using algorithms like lattice-based cryptography or code-based cryptography. 26 | - [ ] A function for generating and verifying post-quantum digital certificates using algorithms like lattice-based cryptography or code-based cryptography. 27 | - [ ] A function for generating and verifying post-quantum one-time passwords using algorithms like lattice-based cryptography or code-based cryptography. 28 | - [ ] A function for generating and verifying post-quantum JWTs using algorithms like lattice-based cryptography or code-based cryptography. 29 | - [ ] A function for making HTTP requests to APIs, with support for various authentication schemes (e.g. OAuth, Basic Auth). 30 | - [ ] A function for parsing and validating API responses, with support for various data formats (e.g. JSON, XML, CSV). 31 | - [ ] A function for generating client libraries for interacting with APIs, using code generation tools like OpenAPI or Swagger. 32 | - [ ] A function for mock testing APIs, which can be used to test client applications without relying on the real API. 33 | - [ ] A function for monitoring APIs for uptime and performance, with support for alerting and notification when issues arise. 34 | 35 | ## Completed 36 | 37 | - [X] **Claims** - A function for generating and verifying claims, which can be used to prove the ownership of a resource. 38 | - [X] **Date** - A function for generating and parsing dates, which can be used to represent a specific point in time. 39 | - [X] **Errors** - A function for generating and parsing errors, which can be used to represent a failure in a system. 40 | - [X] **Hash** - A function for generating and verifying cryptographic hashes, which can be used to verify the integrity of a message or document. 41 | - [X] **JWT** - A function for generating and verifying JWTs (JSON Web Tokens), which can be used for secure, stateless authentication between systems. 42 | - [X] **Logs** - A function for generating and parsing logs, which can be used to represent the state of a system. 43 | - [X] **MD5** - A function for generating and verifying MD5 hashes, which can be used to verify the integrity of a message or document. 44 | - [X] **QR** - A function for generating short, unique codes that could be used as an alternative to UUIDs for identifying resources. -------------------------------------------------------------------------------- /bubba.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sebastienrousseau/mini-functions/0d49306bcd021dcbbf9c1b9a71fee5c7ca46bb68/bubba.ico -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | // println!("cargo:rerun-if-changed=src/lib.rs"); 3 | // println!("cargo:rerun-if-changed=build.rs"); 4 | } 5 | -------------------------------------------------------------------------------- /cclm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Sebastian Rousseau 18 |
19 | 20 | **[Website][0] 21 | • [Documentation][9] 22 | • [Report Bug][3] 23 | • [Request Feature][3] 24 | • [Contributing Guidelines][4]** 25 | 26 |
27 | 28 | 29 | 30 | ## Overview 📖 31 | 32 | The Claims library holds JSON Web Token (JWT) claims. It provides an 33 | RFC7519 compliant implementation of JSON Web Tokens (JWT) and JSON 34 | Web Signature (JWS) for Rust. 35 | 36 | The [**`Claims`**](./struct.Claims.html) type is provided to hold 37 | the claims of a JWT. The claims are stored in a `HashMap` and can be 38 | accessed using the `get_claim`, `set_claim`, `remove_claim`, and 39 | `has_claim` methods. 40 | 41 | ## Features ✨ 42 | 43 | The following table lists the optional reserved claims that are 44 | supported: 45 | 46 | | Claim | Description | 47 | | --- | --- | 48 | | `aud` (Audience) | Identifies the recipients that the JWT is intended for. | 49 | | `custom` (Custom) | Custom claims are used to share information between parties that agree on using them and are neither registered or public claims. | 50 | | `did` (Decentralized Identifier) | A string value that uniquely identifies a subject. | 51 | | `exp` (Expiration Time) | Identifies the expiration time on or after which the JWT MUST NOT be accepted for processing. | 52 | | `iat` (Issued At) | Identifies the time at which the JWT was issued. | 53 | | `iss` (Issuer) | Identifies the principal that issued the JWT. | 54 | | `jti` (JWT ID) | Provides a unique identifier for the JWT. | 55 | | `nbf` (Not Before) | Identifies the time before which the JWT MUST NOT be accepted for processing. | 56 | | `sub` (Subject) | Identifies the principal that is the subject of the JWT. | 57 | | `vc` (Verifiable Credential) | A Credential that is tamper-evident and has authorship that can be cryptographically verified. | 58 | | `vp` (Verifiable Presentation) | A Presentation that is tamper-evident and has authorship that can be cryptographically verified. | 59 | 60 | ## Installation 📦 61 | 62 | It takes just a few minutes to get up and running with `cclm`. 63 | 64 | ### Requirements 65 | 66 | `cclm` requires Rust **1.67.0** or later. 67 | 68 | ### Documentation 69 | 70 | > ℹ️ **Info:** Please check out our [website][0] for more information 71 | and find our documentation on [docs.rs][9], [lib.rs][10] and 72 | [crates.io][8]. 73 | 74 | ## Usage 📖 75 | 76 | To use `cclm` in your project, add the following to your 77 | `Cargo.toml` file: 78 | 79 | ```toml 80 | [dependencies] 81 | cclm = "0.0.1" 82 | ``` 83 | 84 | Add the following to your `main.rs` file: 85 | 86 | ```rust 87 | extern crate cclm; 88 | use cclm::*; 89 | ``` 90 | 91 | then you can use the functions in your application code. 92 | 93 | ### Examples 94 | 95 | `CCLM` comes with a set of examples that you can use to get started. The 96 | examples are located in the `examples` directory of the project. To run 97 | the examples, clone the repository and run the following command in your 98 | terminal from the project root directory. 99 | 100 | ```shell 101 | cargo run --example cclm 102 | ``` 103 | 104 | ## Semantic Versioning Policy 🚥 105 | 106 | For transparency into our release cycle and in striving to maintain 107 | backward compatibility, `QRC` follows [semantic versioning][7]. 108 | 109 | ## License 📝 110 | 111 | The project is licensed under the terms of both the MIT license and the 112 | Apache License (Version 2.0). 113 | 114 | - [Apache License, Version 2.0][1] 115 | - [MIT license][2] 116 | 117 | ## Contribution 🤝 118 | 119 | Unless you explicitly state otherwise, any contribution intentionally 120 | submitted for inclusion in the work by you, as defined in the Apache-2.0 121 | license, shall be dual licensed as above, without any additional terms 122 | or conditions. 123 | 124 | ![divider][divider] 125 | 126 | ## Acknowledgements 💙 127 | 128 | A big thank you to all the awesome contributors of [Mini Functions][6] 129 | for their help and support. A special thank you goes to the 130 | [Rust Reddit](https://www.reddit.com/r/rust/) community for providing a 131 | lot of useful suggestions on how to improve this project. A special thank you goes to the 132 | [Rust Reddit](https://www.reddit.com/r/rust/) community for providing a 133 | lot of useful suggestions on how to improve this project. 134 | 135 | [0]: https://minifunctions.com 136 | [1]: http://www.apache.org/licenses/LICENSE-2.0 137 | [2]: http://opensource.org/licenses/MIT 138 | [3]: https://github.com/sebastienrousseau/mini-functions/issues 139 | [4]: https://raw.githubusercontent.com/sebastienrousseau/mini-functions/main/.github/CONTRIBUTING.md 140 | [6]: https://github.com/sebastienrousseau/mini-functions/graphs/contributors 141 | [7]: http://semver.org/ 142 | [8]: https://crates.io/crates/cclm 143 | [9]: https://docs.rs/cclm 144 | [10]: https://lib.rs/crates/cclm 145 | 146 | [banner]: https://raw.githubusercontent.com/sebastienrousseau/vault/main/assets/mini-functions/banners/banner-cclm-1597x377.svg "CCLM Banner" 147 | [crates-badge]: https://img.shields.io/crates/v/cclm.svg?style=for-the-badge 'Crates.io' 148 | [divider]: https://raw.githubusercontent.com/sebastienrousseau/vault/main/assets/elements/divider.svg "divider" 149 | [docs-badge]: https://img.shields.io/docsrs/cclm.svg?style=for-the-badge 'Docs.rs' 150 | [libs-badge]: https://img.shields.io/badge/lib.rs-v0.0.1-orange.svg?style=for-the-badge 'Lib.rs' 151 | [license-badge]: https://img.shields.io/crates/l/cclm.svg?style=for-the-badge 'License' 152 | [made-with-rust]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust 'Made With Rust' 153 | -------------------------------------------------------------------------------- /cclm/benches/cclm.rs: -------------------------------------------------------------------------------- 1 | extern crate cclm; 2 | use self::cclm::Claims; 3 | 4 | extern crate criterion; 5 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 6 | 7 | fn memory_usage_benchmark(c: &mut Criterion) { 8 | c.bench_function("memory_usage", |b| { 9 | let mut claims = Claims::new(); 10 | let key = "key"; 11 | let value = "value"; 12 | claims.set_claim(key, value); 13 | 14 | b.iter(|| { 15 | let memory_usage = std::mem::size_of_val(&claims); 16 | black_box(memory_usage); 17 | }); 18 | }); 19 | } 20 | fn set_claim_benchmark(c: &mut Criterion) { 21 | c.bench_function("set_claim", |b| { 22 | let mut claims = Claims::new(); 23 | let key = "key"; 24 | let value = "value"; 25 | 26 | b.iter(|| { 27 | claims.set_claim(key, value); 28 | }); 29 | }); 30 | } 31 | 32 | fn get_claim_benchmark(c: &mut Criterion) { 33 | c.bench_function("get_claim", |b| { 34 | let mut claims = Claims::new(); 35 | let key = "key"; 36 | let value = "value"; 37 | claims.set_claim(key, value); 38 | 39 | b.iter(|| { 40 | claims.get_claim(key); 41 | }); 42 | }); 43 | } 44 | 45 | fn remove_claim_benchmark(c: &mut Criterion) { 46 | c.bench_function("remove_claim", |b| { 47 | let mut claims = Claims::new(); 48 | let key = "key"; 49 | let value = "value"; 50 | claims.set_claim(key, value); 51 | 52 | b.iter(|| { 53 | claims.remove_claim(key); 54 | }); 55 | }); 56 | } 57 | 58 | fn has_claim_benchmark(c: &mut Criterion) { 59 | c.bench_function("has_claim", |b| { 60 | let mut claims = Claims::new(); 61 | let key = "key"; 62 | let value = "value"; 63 | claims.set_claim(key, value); 64 | 65 | b.iter(|| { 66 | claims.has_claim(key); 67 | }); 68 | }); 69 | } 70 | 71 | fn clear_claims_benchmark(c: &mut Criterion) { 72 | c.bench_function("clear_claims", |b| { 73 | let mut claims = Claims::new(); 74 | let key = "key"; 75 | let value = "value"; 76 | claims.set_claim(key, value); 77 | 78 | b.iter(|| { 79 | claims.clear_claims(); 80 | }); 81 | }); 82 | } 83 | 84 | fn len_and_is_empty_benchmark(c: &mut Criterion) { 85 | c.bench_function("len_and_is_empty", |b| { 86 | let mut claims = Claims::new(); 87 | let key = "key"; 88 | let value = "value"; 89 | claims.set_claim(key, value); 90 | 91 | b.iter(|| { 92 | claims.len(); 93 | claims.is_empty(); 94 | }); 95 | }); 96 | } 97 | 98 | fn scale_claim_benchmark(c: &mut Criterion) { 99 | let mut group = c.benchmark_group("set_claim"); 100 | for i in [10, 100, 1000, 10000, 100000].iter() { 101 | group.bench_with_input(format!("{i} claims"), i, |b, i| { 102 | let mut claims = Claims::new(); 103 | let key = "key"; 104 | let value = "value"; 105 | b.iter(|| { 106 | for _ in 0..*i { 107 | claims.set_claim(key, value); 108 | } 109 | }); 110 | }); 111 | } 112 | group.finish(); 113 | } 114 | 115 | criterion_group!( 116 | benches, 117 | clear_claims_benchmark, 118 | get_claim_benchmark, 119 | has_claim_benchmark, 120 | len_and_is_empty_benchmark, 121 | memory_usage_benchmark, 122 | remove_claim_benchmark, 123 | scale_claim_benchmark, 124 | set_claim_benchmark, 125 | ); 126 | criterion_main!(benches); 127 | -------------------------------------------------------------------------------- /cclm/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | // println!("cargo:rerun-if-changed=src/lib.rs"); 3 | // println!("cargo:rerun-if-changed=build.rs"); 4 | } 5 | -------------------------------------------------------------------------------- /cclm/deny.toml: -------------------------------------------------------------------------------- 1 | [licenses] 2 | # The lint level for crates which do not have a detectable license 3 | unlicensed = "deny" 4 | 5 | # List of explicitly allowed licenses 6 | # See https://spdx.org/licenses/ for list of possible licenses 7 | # [possible values: any SPDX 3.7 short identifier (+ optional exception)]. 8 | allow = ["MPL-2.0"] 9 | 10 | # List of explicitly disallowed licenses 11 | # See https://spdx.org/licenses/ for list of possible licenses 12 | # [possible values: any SPDX 3.7 short identifier (+ optional exception)]. 13 | deny = [] 14 | 15 | # The lint level for licenses considered copyleft 16 | copyleft = "deny" 17 | 18 | # Blanket approval or denial for OSI-approved or FSF Free/Libre licenses 19 | # * both - The license will only be approved if it is both OSI-approved *AND* FSF/Free 20 | # * either - The license will be approved if it is either OSI-approved *OR* FSF/Free 21 | # * osi-only - The license will be approved if is OSI-approved *AND NOT* FSF/Free 22 | # * fsf-only - The license will be approved if is FSF/Free *AND NOT* OSI-approved 23 | # * neither - The license will be denied if is FSF/Free *OR* OSI-approved 24 | allow-osi-fsf-free = "either" 25 | 26 | # The confidence threshold for detecting a license from license text. 27 | # The higher the value, the more closely the license text must be to the 28 | # canonical license text of a valid SPDX license file. 29 | # [possible values: any between 0.0 and 1.0]. 30 | confidence-threshold = 0.8 31 | 32 | [bans] 33 | # Lint level for when multiple versions of the same crate are detected 34 | multiple-versions = "warn" 35 | 36 | # The graph highlighting used when creating dotgraphs for crates 37 | # with multiple versions 38 | # * lowest-version - The path to the lowest versioned duplicate is highlighted 39 | # * simplest-path - The path to the version with the fewest edges is highlighted 40 | # * all - Both lowest-version and simplest-path are used 41 | highlight = "all" 42 | 43 | # List of crates that are allowed. Use with care! 44 | allow = [ 45 | ] 46 | 47 | # List of crates to deny 48 | deny = [ 49 | # Each entry the name of a crate and a version range. If version is 50 | # not specified, all versions will be matched. 51 | ] 52 | 53 | # Certain crates/versions that will be skipped when doing duplicate detection. 54 | skip = [ 55 | ] 56 | 57 | # Similarly to `skip` allows you to skip certain crates during duplicate detection, 58 | # unlike skip, it also includes the entire tree of transitive dependencies starting at 59 | # the specified crate, up to a certain depth, which is by default infinite 60 | skip-tree = [ 61 | ] 62 | 63 | 64 | [advisories] 65 | ignore = [ 66 | ] 67 | -------------------------------------------------------------------------------- /cclm/examples/cclm.rs: -------------------------------------------------------------------------------- 1 | extern crate cclm; 2 | use self::cclm::Claims; 3 | 4 | fn main() { 5 | // Create a new instance of Claims 6 | let mut claims = Claims::new(); 7 | 8 | // Set claims 9 | claims.set_claim("aud", "https://example.com"); 10 | claims.set_claim("custom", "admin"); 11 | claims.set_claim("did", "did:example:123456789"); 12 | claims.set_claim("iss", "https://issuer.com"); 13 | claims.set_claim("jti", "abc123"); 14 | claims.set_claim("sub", "user123"); 15 | claims.set_claim("vc", "Ed25519Signature2018"); 16 | claims.set_claim("vp", "B7AC971B05D791F0EB5FCE3B8A3296F1D68A63199714A2993AAD6E2F3D10F4E4425576AA4D97B80B617D5A182B519E9A021DEEDE9BFFBC3499F902DDC5CA163F"); 17 | 18 | // Get claims 19 | let audience = claims.get_claim("aud").unwrap(); 20 | let custom = claims.get_claim("custom").unwrap(); 21 | let did = claims.get_claim("did").unwrap(); 22 | let issuer = claims.get_claim("iss").unwrap(); 23 | let jwt_id = claims.get_claim("jti").unwrap(); 24 | let subject = claims.get_claim("sub").unwrap(); 25 | let credential = claims.get_claim("vc").unwrap(); 26 | let proof = claims.get_claim("vp").unwrap(); 27 | 28 | println!("🦀 Claims::get_claim() for 'aud': ✅ {audience}"); 29 | println!("🦀 Claims::get_claim() for 'custom': ✅ {custom}"); 30 | println!("🦀 Claims::get_claim() for 'did': ✅ {did}"); 31 | println!("🦀 Claims::get_claim() for 'iss': ✅ {issuer}"); 32 | println!("🦀 Claims::get_claim() for 'jti': ✅ {jwt_id}"); 33 | println!("🦀 Claims::get_claim() for 'sub': ✅ {subject}"); 34 | println!("🦀 Claims::get_claim() for 'vc': ✅ {credential}"); 35 | println!("🦀 Claims::get_claim() for 'vp': ✅ {proof}"); 36 | 37 | // Remove claims 38 | let audience = claims.get_claim("aud").unwrap().to_owned(); 39 | claims.remove_claim("aud"); 40 | println!("🦀 Claims::remove_claim(): ✅ {audience}"); 41 | } 42 | -------------------------------------------------------------------------------- /cclm/rustfmt.toml: -------------------------------------------------------------------------------- 1 | # default -------------------------------------------------------------------------------- /cclm/tests/claims.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | 3 | mod tests { 4 | 5 | extern crate cclm; 6 | extern crate dtt; 7 | 8 | use self::cclm::Claims; 9 | use self::dtt::DateTime; 10 | 11 | #[test] 12 | fn test_claims() { 13 | const CL_AUD: &str = "MINI-FUNCTIONS-CLAIMS-AUD"; 14 | const CL_CUSTOM: &str = "MINI-FUNCTIONS-CLAIMS-CUSTOM"; 15 | const CL_DID: &str = "MINI-FUNCTIONS-CLAIMS-DID"; 16 | const CL_ISS: &str = "MINI-FUNCTIONS-CLAIMS-ISS"; 17 | const CL_JTI: &str = "MINI-FUNCTIONS-CLAIMS-JTI"; 18 | const CL_SUB: &str = "MINI-FUNCTIONS-CLAIMS-SUB"; 19 | const CL_VC: &str = "MINI-FUNCTIONS-CLAIMS-VC"; 20 | const CL_VP: &str = "MINI-FUNCTIONS-CLAIMS-VP"; 21 | 22 | let date = DateTime::new(); 23 | let iso = date.iso_8601; 24 | 25 | let mut claims = Claims::new(); 26 | claims.set_claim("aud", CL_AUD); 27 | claims.set_claim("custom", CL_CUSTOM); 28 | claims.set_claim("did", CL_DID); 29 | claims.set_claim("exp", &iso); 30 | claims.set_claim("iat", &iso); 31 | claims.set_claim("iss", CL_ISS); 32 | claims.set_claim("jti", CL_JTI); 33 | claims.set_claim("nbf", &iso); 34 | claims.set_claim("sub", CL_SUB); 35 | claims.set_claim("vc", CL_VC); 36 | claims.set_claim("vp", CL_VP); 37 | 38 | assert_eq!(claims.get_claim("aud").unwrap(), CL_AUD); 39 | assert_eq!(claims.get_claim("custom").unwrap(), CL_CUSTOM); 40 | assert_eq!(claims.get_claim("did").unwrap(), CL_DID); 41 | assert_eq!(claims.get_claim("exp").unwrap(), &iso.to_string()); 42 | assert_eq!(claims.get_claim("iat").unwrap(), &iso.to_string()); 43 | assert_eq!(claims.get_claim("iss").unwrap(), CL_ISS); 44 | assert_eq!(claims.get_claim("jti").unwrap(), CL_JTI); 45 | assert_eq!(claims.get_claim("nbf").unwrap(), &iso.to_string()); 46 | assert_eq!(claims.get_claim("sub").unwrap(), CL_SUB); 47 | assert_eq!(claims.get_claim("vc").unwrap(), CL_VC); 48 | assert_eq!(claims.get_claim("vp").unwrap(), CL_VP); 49 | } 50 | #[test] 51 | fn test_get_claim() { 52 | let mut claims = Claims::new(); 53 | claims.set_claim("aud", "MINI-FUNCTIONS-CLAIMS-AUD"); 54 | assert_eq!( 55 | claims.get_claim("aud").unwrap(), 56 | "MINI-FUNCTIONS-CLAIMS-AUD" 57 | ); 58 | assert!(claims.get_claim("non-existent-claim").is_none()); 59 | } 60 | #[test] 61 | fn test_remove_claim() { 62 | let mut claims = Claims::new(); 63 | claims.set_claim("aud", "MINI-FUNCTIONS-CLAIMS-AUD"); 64 | claims.remove_claim("aud"); 65 | assert!(claims.get_claim("aud").is_none()); 66 | } 67 | 68 | #[test] 69 | fn test_clear_claims() { 70 | let mut claims = Claims::new(); 71 | claims.set_claim("aud", "MINI-FUNCTIONS-CLAIMS-AUD"); 72 | claims.set_claim("custom", "MINI-FUNCTIONS-CLAIMS-CUSTOM"); 73 | claims.clear_claims(); 74 | assert_eq!(claims.len(), 0); 75 | } 76 | #[test] 77 | fn test_has_claim() { 78 | let mut claims = Claims::new(); 79 | claims.set_claim("aud", "MINI-FUNCTIONS-CLAIMS-AUD"); 80 | assert!(claims.has_claim("aud")); 81 | assert!(!claims.has_claim("non-existent-claim")); 82 | } 83 | 84 | #[test] 85 | fn test_len() { 86 | let mut claims = Claims::new(); 87 | claims.set_claim("aud", "MINI-FUNCTIONS-CLAIMS-AUD"); 88 | claims.set_claim("custom", "MINI-FUNCTIONS-CLAIMS-CUSTOM"); 89 | assert_eq!(claims.len(), 2); 90 | } 91 | #[test] 92 | fn test_is_empty() { 93 | let mut claims = Claims::new(); 94 | assert!(claims.is_empty()); 95 | claims.set_claim("aud", "MINI-FUNCTIONS-CLAIMS-AUD"); 96 | assert!(!claims.is_empty()); 97 | } 98 | 99 | #[test] 100 | fn test_get_claims() { 101 | let mut claims = Claims::new(); 102 | claims.set_claim("aud", "MINI-FUNCTIONS-CLAIMS-AUD"); 103 | claims.set_claim("custom", "MINI-FUNCTIONS-CLAIMS-CUSTOM"); 104 | let retrieved_claims = claims.get_claims(); 105 | assert_eq!( 106 | retrieved_claims.get("aud").unwrap(), 107 | "MINI-FUNCTIONS-CLAIMS-AUD" 108 | ); 109 | assert_eq!( 110 | retrieved_claims.get("custom").unwrap(), 111 | "MINI-FUNCTIONS-CLAIMS-CUSTOM" 112 | ); 113 | } 114 | #[test] 115 | fn test_display_trait() { 116 | let mut claims = Claims::new(); 117 | claims.set_claim("aud", "MINI-FUNCTIONS-CLAIMS-AUD"); 118 | claims.set_claim("custom", "MINI-FUNCTIONS-CLAIMS-CUSTOM"); 119 | let display_output = format!("{claims}"); 120 | assert!(display_output.contains("aud: MINI-FUNCTIONS-CLAIMS-AUD")); 121 | assert!(display_output.contains("custom: MINI-FUNCTIONS-CLAIMS-CUSTOM")); 122 | } 123 | 124 | #[test] 125 | fn test_default_trait() { 126 | let claims = Claims::default(); 127 | assert_eq!(claims.claims.len(), 0); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /cjwt/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Sebastian Rousseau 18 |
19 | 20 | **[Website][0] 21 | • [Documentation][9] 22 | • [Report Bug][3] 23 | • [Request Feature][3] 24 | • [Contributing Guidelines][4]** 25 | 26 |
27 | 28 | 29 | 30 | ## Overview 📖 31 | 32 | The Core JWT (CJWT) is a struct with a JWT token and claims. It has 33 | functions for working with JSON Web Tokens (JWTs) and JSON Web 34 | Signatures (JWSs). JWTs have three parts: a header, a payload, and a 35 | signature. The header and payload are JSON objects. They're serialized 36 | to UTF-8 bytes and encoded with base64url encoding. 37 | 38 | ## Features ✨ 39 | 40 | - [x] JWT token generation 41 | - [x] JWT token validation 42 | - [x] JWT token signing 43 | 44 | ## Installation 📦 45 | 46 | It takes just a few minutes to get up and running with `cjwt`. 47 | 48 | ### Requirements 49 | 50 | `cjwt` requires Rust **1.67.0** or later. 51 | 52 | ### Documentation 53 | 54 | > ℹ️ **Info:** Please check out our [website][0] for more information 55 | and find our documentation on [docs.rs][9], [lib.rs][10] and 56 | [crates.io][8]. 57 | 58 | ## Usage 📖 59 | 60 | To use `cjwt` in your project, add the following to your 61 | `Cargo.toml` file: 62 | 63 | ```toml 64 | [dependencies] 65 | cjwt = "0.0.1" 66 | ``` 67 | 68 | Add the following to your `main.rs` file: 69 | 70 | ```rust 71 | extern crate cjwt; 72 | use cjwt::*; 73 | ``` 74 | 75 | then you can use the functions in your application code. 76 | 77 | ### Examples 78 | 79 | `CJWT` comes with a set of examples that you can use to get started. The 80 | examples are located in the `examples` directory of the project. To run 81 | the examples, clone the repository and run the following command in your 82 | terminal from the project root directory. 83 | 84 | ```shell 85 | cargo run --example cjwt 86 | ``` 87 | 88 | ## Semantic Versioning Policy 🚥 89 | 90 | For transparency into our release cycle and in striving to maintain 91 | backward compatibility, `QRC` follows [semantic versioning][7]. 92 | 93 | ## License 📝 94 | 95 | The project is licensed under the terms of both the MIT license and the 96 | Apache License (Version 2.0). 97 | 98 | - [Apache License, Version 2.0][1] 99 | - [MIT license][2] 100 | 101 | ## Contribution 🤝 102 | 103 | Unless you explicitly state otherwise, any contribution intentionally 104 | submitted for inclusion in the work by you, as defined in the Apache-2.0 105 | license, shall be dual licensed as above, without any additional terms 106 | or conditions. 107 | 108 | ![divider][divider] 109 | 110 | ## Acknowledgements 💙 111 | 112 | A big thank you to all the awesome contributors of [Mini Functions][6] 113 | for their help and support. A special thank you goes to the 114 | [Rust Reddit](https://www.reddit.com/r/rust/) community for providing a 115 | lot of useful suggestions on how to improve this project. A special thank you goes to the 116 | [Rust Reddit](https://www.reddit.com/r/rust/) community for providing a 117 | lot of useful suggestions on how to improve this project. 118 | 119 | [0]: https://minifunctions.com 120 | [1]: http://www.apache.org/licenses/LICENSE-2.0 121 | [2]: http://opensource.org/licenses/MIT 122 | [3]: https://github.com/sebastienrousseau/mini-functions/issues 123 | [4]: https://raw.githubusercontent.com/sebastienrousseau/mini-functions/main/.github/CONTRIBUTING.md 124 | [6]: https://github.com/sebastienrousseau/mini-functions/graphs/contributors 125 | [7]: http://semver.org/ 126 | [8]: https://crates.io/crates/cjwt 127 | [9]: https://docs.rs/cjwt 128 | [10]: https://lib.rs/crates/cjwt 129 | 130 | [banner]: https://raw.githubusercontent.com/sebastienrousseau/vault/main/assets/mini-functions/banners/banner-cjwt-1597x377.svg "CJWT Banner" 131 | [crates-badge]: https://img.shields.io/crates/v/cjwt.svg?style=for-the-badge 'Crates.io' 132 | [divider]: https://raw.githubusercontent.com/sebastienrousseau/vault/main/assets/elements/divider.svg "divider" 133 | [docs-badge]: https://img.shields.io/docsrs/cjwt.svg?style=for-the-badge 'Docs.rs' 134 | [libs-badge]: https://img.shields.io/badge/lib.rs-v0.0.1-orange.svg?style=for-the-badge 'Lib.rs' 135 | [license-badge]: https://img.shields.io/crates/l/cjwt.svg?style=for-the-badge 'License' 136 | [made-with-rust]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust 'Made With Rust' 137 | -------------------------------------------------------------------------------- /cjwt/benches/cjwt.rs: -------------------------------------------------------------------------------- 1 | extern crate criterion; 2 | use cclm::Claims; 3 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 4 | 5 | extern crate cjwt; 6 | use self::cjwt::{Algorithm, Header, JWT}; 7 | 8 | fn bench_to_string_benchmark(c: &mut Criterion) { 9 | let jwt = JWT::default(); 10 | 11 | c.bench_function("to_string", move |b| b.iter(|| jwt.to_string())); 12 | } 13 | 14 | fn bench_default_benchmark(c: &mut Criterion) { 15 | c.bench_function("default", |b| b.iter(|| JWT::default)); 16 | } 17 | 18 | fn bench_decode_benchmark(c: &mut Criterion) { 19 | let secret: &[u8; 6] = b"secret"; 20 | let header = Header::default(); 21 | let claims = Claims::default(); 22 | 23 | let token = JWT::encode(header, claims, secret).unwrap(); 24 | let mut jwt = 25 | JWT { 26 | header: Header::default(), 27 | claims: Claims::default(), 28 | signature: vec![], 29 | token, 30 | }; 31 | 32 | c.bench_function("decode", move |b| b.iter(|| jwt.decode(secret))); 33 | } 34 | 35 | fn bench_generate_benchmark(c: &mut Criterion) { 36 | let secret = b"secret"; 37 | c.bench_function("generate", |b| { 38 | b.iter(|| JWT::generate(black_box(secret)).unwrap()) 39 | }); 40 | } 41 | 42 | // fn bench_generate_benchmark(c: &mut Criterion) { 43 | // c.bench_function("generate", |b| b.iter(|| JWT::generate())); 44 | // } 45 | 46 | fn bench_get_token_benchmark(c: &mut Criterion) { 47 | let jwt = JWT { 48 | header: Header::default(), 49 | claims: Claims::default(), 50 | signature: vec![], 51 | token: "example_token".to_owned(), 52 | }; 53 | let result = JWT::get_token(jwt); 54 | c.bench_function("get_token", move |b| b.iter(|| result.clone())); 55 | } 56 | 57 | fn bench_claims_benchmark(c: &mut Criterion) { 58 | c.bench_function("claims", move |b| b.iter(|| JWT::claims)); 59 | } 60 | 61 | fn bench_get_token_length_benchmark(c: &mut Criterion) { 62 | let jwt = JWT { 63 | header: Header::default(), 64 | claims: Claims::default(), 65 | signature: vec![], 66 | token: "example_token".to_owned(), 67 | }; 68 | let result = JWT::get_token_length(jwt); 69 | c.bench_function("get_token_length", move |b| b.iter(|| result)); 70 | } 71 | 72 | fn bench_get_token_header_benchmark(c: &mut Criterion) { 73 | c.bench_function("get_token_header", move |b| { 74 | let jwt = JWT { 75 | header: Header { 76 | alg: Some(Algorithm::HS256), 77 | kid: Some("example_kid".to_string()), 78 | typ: Some("example_type".to_string()), 79 | cty: Some("example_cty".to_string()), 80 | }, 81 | claims: Claims::default(), 82 | signature: vec![], 83 | token: "example_token".to_owned(), 84 | }; 85 | let result = JWT::get_token_header(jwt); 86 | b.iter(|| result.clone()) 87 | }); 88 | } 89 | 90 | fn bench_encode_benchmark(c: &mut Criterion) { 91 | let secret = b"secret"; 92 | let header = JWT::default().header; 93 | let claims = JWT::default().claims; 94 | 95 | c.bench_function("encode", move |b| { 96 | b.iter(|| { 97 | JWT::encode( 98 | black_box(header.clone()), 99 | black_box(claims.clone()), 100 | black_box(secret), 101 | ) 102 | }) 103 | }); 104 | } 105 | fn bench_validate_benchmark(c: &mut Criterion) { 106 | let secret = b"secret"; 107 | let jwt = JWT { 108 | header: Header { 109 | alg: Some(Algorithm::HS256), 110 | kid: Some("example_kid".to_string()), 111 | typ: Some("example_type".to_string()), 112 | cty: Some("example_cty".to_string()), 113 | }, 114 | claims: Claims::default(), 115 | signature: vec![], 116 | token: "example_token".to_owned(), 117 | }; 118 | 119 | c.bench_function("validate", move |b| { 120 | b.iter(|| JWT::validate(black_box(&jwt), black_box(secret))); 121 | }); 122 | } 123 | 124 | criterion_group!( 125 | benches, 126 | bench_claims_benchmark, 127 | bench_decode_benchmark, 128 | bench_default_benchmark, 129 | bench_encode_benchmark, 130 | bench_generate_benchmark, 131 | bench_get_token_benchmark, 132 | bench_get_token_header_benchmark, 133 | bench_get_token_length_benchmark, 134 | bench_to_string_benchmark, 135 | bench_validate_benchmark, 136 | ); 137 | criterion_main!(benches); 138 | -------------------------------------------------------------------------------- /cjwt/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | // println!("cargo:rerun-if-changed=src/lib.rs"); 3 | // println!("cargo:rerun-if-changed=build.rs"); 4 | } 5 | -------------------------------------------------------------------------------- /cjwt/deny.toml: -------------------------------------------------------------------------------- 1 | [licenses] 2 | # The lint level for crates which do not have a detectable license 3 | unlicensed = "deny" 4 | 5 | # List of explicitly allowed licenses 6 | # See https://spdx.org/licenses/ for list of possible licenses 7 | # [possible values: any SPDX 3.7 short identifier (+ optional exception)]. 8 | allow = ["MPL-2.0"] 9 | 10 | # List of explicitly disallowed licenses 11 | # See https://spdx.org/licenses/ for list of possible licenses 12 | # [possible values: any SPDX 3.7 short identifier (+ optional exception)]. 13 | deny = [] 14 | 15 | # The lint level for licenses considered copyleft 16 | copyleft = "deny" 17 | 18 | # Blanket approval or denial for OSI-approved or FSF Free/Libre licenses 19 | # * both - The license will only be approved if it is both OSI-approved *AND* FSF/Free 20 | # * either - The license will be approved if it is either OSI-approved *OR* FSF/Free 21 | # * osi-only - The license will be approved if is OSI-approved *AND NOT* FSF/Free 22 | # * fsf-only - The license will be approved if is FSF/Free *AND NOT* OSI-approved 23 | # * neither - The license will be denied if is FSF/Free *OR* OSI-approved 24 | allow-osi-fsf-free = "either" 25 | 26 | # The confidence threshold for detecting a license from license text. 27 | # The higher the value, the more closely the license text must be to the 28 | # canonical license text of a valid SPDX license file. 29 | # [possible values: any between 0.0 and 1.0]. 30 | confidence-threshold = 0.8 31 | 32 | [bans] 33 | # Lint level for when multiple versions of the same crate are detected 34 | multiple-versions = "warn" 35 | 36 | # The graph highlighting used when creating dotgraphs for crates 37 | # with multiple versions 38 | # * lowest-version - The path to the lowest versioned duplicate is highlighted 39 | # * simplest-path - The path to the version with the fewest edges is highlighted 40 | # * all - Both lowest-version and simplest-path are used 41 | highlight = "all" 42 | 43 | # List of crates that are allowed. Use with care! 44 | allow = [ 45 | ] 46 | 47 | # List of crates to deny 48 | deny = [ 49 | # Each entry the name of a crate and a version range. If version is 50 | # not specified, all versions will be matched. 51 | ] 52 | 53 | # Certain crates/versions that will be skipped when doing duplicate detection. 54 | skip = [ 55 | ] 56 | 57 | # Similarly to `skip` allows you to skip certain crates during duplicate detection, 58 | # unlike skip, it also includes the entire tree of transitive dependencies starting at 59 | # the specified crate, up to a certain depth, which is by default infinite 60 | skip-tree = [ 61 | ] 62 | 63 | 64 | [advisories] 65 | ignore = [ 66 | ] 67 | -------------------------------------------------------------------------------- /cjwt/examples/cjwt.rs: -------------------------------------------------------------------------------- 1 | extern crate cjwt; 2 | extern crate jwt; 3 | 4 | use self::cjwt::{Algorithm, Header, JWT}; 5 | use cclm::Claims; 6 | 7 | fn main() { 8 | // Constants for the JWT struct examples. 9 | const HD_ALG: Algorithm = Algorithm::HS384; 10 | const HD_KID: &str = "jwt-kid"; 11 | const HD_TYP: &str = "jwt-typ"; 12 | const HD_CTY: &str = "jwt-cty"; 13 | 14 | // Create a Header struct with default method. 15 | let hd: Header = Header::default(); 16 | println!("🦀 Header::default(): ✅ {hd:?}\n"); 17 | 18 | // Create a Header struct with default method and replace values. 19 | let mut hdrv: Header = Header::default(); 20 | Header::default().alg = std::mem::replace(&mut hdrv.alg, Some(HD_ALG)); 21 | Header::default().kid = std::mem::replace(&mut hdrv.kid, Some(HD_KID.to_string())); 22 | Header::default().typ = std::mem::replace(&mut hdrv.typ, Some(HD_TYP.to_string())); 23 | Header::default().cty = std::mem::replace(&mut hdrv.cty, Some(HD_CTY.to_string())); 24 | println!("🦀 Header::default(): ✅ {hdrv:?}\n"); 25 | 26 | // Create a JWT struct with default method. 27 | let jd: JWT = JWT::default(); 28 | println!("🦀 JWT::default(): ✅ {jd:?}\n"); 29 | 30 | // Create a JWT struct with default method and replace values. 31 | let mut jdrv: JWT = JWT::default(); 32 | JWT::default().header.alg = std::mem::replace(&mut jdrv.header.alg, Some(HD_ALG)); 33 | JWT::default().header.kid = std::mem::replace(&mut jdrv.header.kid, Some(HD_KID.to_string())); 34 | JWT::default().header.typ = std::mem::replace(&mut jdrv.header.typ, Some(HD_TYP.to_string())); 35 | JWT::default().header.cty = std::mem::replace(&mut jdrv.header.cty, Some(HD_CTY.to_string())); 36 | println!("🦀 JWT::default(): ✅ {jdrv:?}\n"); 37 | 38 | // Encode a JWT struct. 39 | let encoded: String = JWT::encode(hdrv, Claims::default(), b"secret").unwrap(); 40 | println!("🦀 encode(): ✅ {encoded:?}\n"); 41 | 42 | // Extract the token field from the passed JWT struct and return it. 43 | let jwt = JWT { 44 | header: Header::default(), 45 | claims: Claims::default(), 46 | signature: vec![], 47 | token: "example_token".to_owned(), 48 | }; 49 | let result = JWT::get_token(jwt); 50 | println!("🦀 get_token(): ✅ {result:?}\n"); 51 | } 52 | -------------------------------------------------------------------------------- /cjwt/rustfmt.toml: -------------------------------------------------------------------------------- 1 | # default -------------------------------------------------------------------------------- /cjwt/tests/cjwt.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | extern crate cclm; 4 | extern crate cjwt; 5 | 6 | use self::cclm::Claims; 7 | use self::cjwt::{Algorithm, Header, JWT}; 8 | 9 | #[test] 10 | fn test_default_algorithm_is_hs256() { 11 | let algorithm = Algorithm::default(); 12 | assert_eq!(algorithm, Algorithm::HS256); 13 | } 14 | 15 | #[test] 16 | fn test_algorithm_to_string_variants() { 17 | let algorithm = Algorithm::default(); 18 | assert_eq!(algorithm.to_string(), "HS256"); 19 | 20 | let algorithm_hs384 = Algorithm::HS384; 21 | assert_eq!(algorithm_hs384.to_string(), "HS384"); 22 | 23 | let algorithm_hs512 = Algorithm::HS512; 24 | assert_eq!(algorithm_hs512.to_string(), "HS512"); 25 | 26 | let algorithm_rs256 = Algorithm::RS256; 27 | assert_eq!(algorithm_rs256.to_string(), "RS256"); 28 | 29 | let algorithm_rs384 = Algorithm::RS384; 30 | assert_eq!(algorithm_rs384.to_string(), "RS384"); 31 | 32 | let algorithm_rs512 = Algorithm::RS512; 33 | assert_eq!(algorithm_rs512.to_string(), "RS512"); 34 | 35 | let algorithm_es256 = Algorithm::ES256; 36 | assert_eq!(algorithm_es256.to_string(), "ES256"); 37 | 38 | let algorithm_es384 = Algorithm::ES384; 39 | assert_eq!(algorithm_es384.to_string(), "ES384"); 40 | 41 | let algorithm_es512 = Algorithm::ES512; 42 | assert_eq!(algorithm_es512.to_string(), "ES512"); 43 | } 44 | 45 | #[test] 46 | fn test_algorithm_variants_are_defined() { 47 | assert!(matches!(Algorithm::HS256, Algorithm::HS256)); 48 | assert!(matches!(Algorithm::HS384, Algorithm::HS384)); 49 | assert!(matches!(Algorithm::HS512, Algorithm::HS512)); 50 | assert!(matches!(Algorithm::RS256, Algorithm::RS256)); 51 | assert!(matches!(Algorithm::RS384, Algorithm::RS384)); 52 | assert!(matches!(Algorithm::RS512, Algorithm::RS512)); 53 | assert!(matches!(Algorithm::ES256, Algorithm::ES256)); 54 | assert!(matches!(Algorithm::ES384, Algorithm::ES384)); 55 | assert!(matches!(Algorithm::ES512, Algorithm::ES512)); 56 | } 57 | 58 | #[test] 59 | fn test_default_header_has_correct_fields() { 60 | let header = Header::default(); 61 | assert_eq!(header.alg, Some(Algorithm::HS256)); 62 | assert_eq!(header.kid, None); 63 | assert_eq!(header.typ, Some("JWT".to_string())); 64 | assert_eq!(header.cty, None); 65 | } 66 | 67 | #[test] 68 | fn test_empty_claims_are_generated() { 69 | let claims = self::JWT::claims(); 70 | assert!(claims.is_empty(), "{}", true); 71 | } 72 | 73 | #[test] 74 | fn test_generate_jwt_with_valid_secret() { 75 | let secret = b"secret"; 76 | let jwt = JWT::generate(secret); 77 | assert!(jwt.is_ok()); 78 | let token = jwt.unwrap(); 79 | assert!(!token.is_empty()); 80 | } 81 | 82 | #[test] 83 | fn test_get_token_from_jwt() { 84 | let jwt = JWT { 85 | header: Header::default(), 86 | claims: Claims::default(), 87 | signature: vec![], 88 | token: "example_token".to_owned(), 89 | }; 90 | let result = JWT::get_token(jwt); 91 | assert_eq!(result, "example_token"); 92 | } 93 | 94 | #[test] 95 | fn test_get_token_header_from_jwt() { 96 | let jwt = JWT { 97 | header: Header { 98 | alg: Some(Algorithm::HS256), 99 | kid: Some("example_kid".to_string()), 100 | typ: Some("example_type".to_string()), 101 | cty: Some("example_cty".to_string()), 102 | }, 103 | claims: Claims::default(), 104 | signature: vec![], 105 | token: "example_token".to_owned(), 106 | }; 107 | let result = JWT::get_token_header(jwt); 108 | assert_eq!(result.alg, Some(Algorithm::HS256)); 109 | assert_eq!(result.kid, Some("example_kid".to_string())); 110 | assert_eq!(result.typ, Some("example_type".to_string())); 111 | assert_eq!(result.cty, Some("example_cty".to_string())); 112 | } 113 | 114 | #[test] 115 | fn test_get_token_length_from_jwt() { 116 | let jwt = JWT { 117 | header: Header::default(), 118 | claims: Claims::default(), 119 | signature: vec![], 120 | token: "token".to_string(), 121 | }; 122 | let result = JWT::get_token_length(jwt); 123 | assert_eq!(result, 5); 124 | } 125 | 126 | #[test] 127 | fn test_encode() { 128 | let secret: &[u8; 6] = b"secret"; 129 | let header = Header::default(); 130 | let claims = Claims::default(); 131 | let result = JWT::encode(header, claims, secret); 132 | assert!(result.is_ok(), "{}", true); 133 | } 134 | 135 | #[test] 136 | fn test_decode() { 137 | let mut jwt = JWT::default(); 138 | let secret: &[u8; 6] = b"secret"; 139 | let header = Header::default(); 140 | let claims = Claims::default(); 141 | let encoded_result = JWT::encode(header, claims, secret); 142 | let encoded = encoded_result.unwrap(); 143 | jwt.token.clone_from(&encoded); 144 | let decoded = JWT::decode(&mut jwt, secret); 145 | if let Ok(decoded_token) = decoded { 146 | assert_eq!(decoded_token, encoded); 147 | } 148 | } 149 | 150 | #[test] 151 | fn test_to_string() { 152 | let jwt = JWT { 153 | header: Header::default(), 154 | claims: Claims::default(), 155 | signature: vec![], 156 | token: "example_token".to_owned(), 157 | }; 158 | let result = jwt.to_string(); 159 | assert_eq!( 160 | result, 161 | "JWT { header: Header { alg: Some(HS256), kid: None, typ: Some(\"JWT\"), cty: None }, claims: Claims { }, signature: [], token: example_token }" 162 | ); 163 | } 164 | 165 | #[test] 166 | fn test_validate_success() { 167 | let secret: &[u8; 6] = b"secret"; 168 | let jwt = JWT { 169 | header: Header::default(), 170 | claims: Claims::default(), 171 | signature: vec![], 172 | token: "example_token".to_owned(), 173 | }; 174 | let result = JWT::validate(&jwt, secret); 175 | assert!(result.is_err()); 176 | } 177 | 178 | #[test] 179 | fn test_validate_with_empty_signature() { 180 | // Create a JWT with valid claims and an empty signature 181 | let secret = b"secret"; 182 | let jwt = JWT { 183 | header: Header { 184 | alg: Some(Algorithm::HS256), 185 | kid: Some("example_kid".to_string()), 186 | typ: Some("example_type".to_string()), 187 | cty: Some("example_cty".to_string()), 188 | }, 189 | claims: Claims::default(), 190 | signature: vec![], 191 | token: "example_token".to_owned(), 192 | }; 193 | 194 | // Test validating the JWT 195 | let result = jwt.validate(secret); 196 | assert!(result.is_err()); 197 | } 198 | 199 | #[test] 200 | fn test_decode_invalid_token() { 201 | let mut jwt = JWT { 202 | token: "invalid.token.structure".to_owned(), 203 | ..JWT::default() 204 | }; 205 | let secret = b"secret"; 206 | assert!(JWT::decode(&mut jwt, secret).is_err()); 207 | } 208 | 209 | #[test] 210 | fn test_decode_with_invalid_header() { 211 | let mut jwt = JWT::default(); 212 | jwt.token = "invalid.header.structure".to_owned(); 213 | let secret = b"secret"; 214 | assert!(JWT::decode(&mut jwt, secret).is_err()); 215 | } 216 | 217 | #[test] 218 | fn test_decode_with_invalid_claims() { 219 | let mut jwt = JWT::default(); 220 | jwt.token = "invalid.claims.structure".to_owned(); 221 | let secret = b"secret"; 222 | assert!(JWT::decode(&mut jwt, secret).is_err()); 223 | } 224 | 225 | #[test] 226 | fn test_validate_with_invalid_claims() { 227 | let mut jwt = JWT::default(); 228 | jwt.token = "invalid.claims.structure".to_string(); 229 | let secret = b"secret"; 230 | assert!(JWT::validate(&jwt, secret).is_err()); 231 | } 232 | 233 | #[test] 234 | fn test_decode_with_invalid_signature() { 235 | let mut jwt = JWT::default(); 236 | jwt.token = "invalid.signature.value".to_owned(); 237 | let secret = b"secret"; 238 | assert!(JWT::decode(&mut jwt, secret).is_err()); 239 | } 240 | 241 | #[test] 242 | fn test_validate_with_invalid_signature() { 243 | let jwt = JWT { 244 | header: Header::default(), 245 | claims: Claims::default(), 246 | signature: vec![], 247 | token: "invalid.signature.value".to_string(), 248 | }; 249 | let secret = b"secret"; 250 | assert!(JWT::validate(&jwt, secret).is_err()); 251 | } 252 | 253 | #[test] 254 | fn test_decode_with_expired_iat() { 255 | let mut jwt = JWT::default(); 256 | jwt.token = "expired.iat.jwt".to_owned(); 257 | let secret = b"secret"; 258 | assert!(JWT::decode(&mut jwt, secret).is_err()); 259 | } 260 | 261 | #[test] 262 | fn test_decode_with_expired_exp() { 263 | let mut jwt = JWT::default(); 264 | jwt.token = "expired.exp.jwt".to_owned(); 265 | let secret = b"secret"; 266 | assert!(JWT::decode(&mut jwt, secret).is_err()); 267 | } 268 | 269 | #[test] 270 | fn test_validate_with_expired_iat() { 271 | let jwt = JWT { 272 | header: Header::default(), 273 | claims: Claims::default(), 274 | signature: vec![], 275 | token: "expired.iat.jwt".to_string(), 276 | }; 277 | let secret = b"secret"; 278 | assert!(JWT::validate(&jwt, secret).is_err()); 279 | } 280 | 281 | #[test] 282 | fn test_validate_with_expired_exp() { 283 | let jwt = JWT { 284 | header: Header::default(), 285 | claims: Claims::default(), 286 | signature: vec![], 287 | token: "expired.exp.jwt".to_owned(), 288 | }; 289 | let secret = b"secret"; 290 | assert!(JWT::validate(&jwt, secret).is_err()); 291 | } 292 | } 293 | -------------------------------------------------------------------------------- /deny.toml: -------------------------------------------------------------------------------- 1 | [licenses] 2 | # The lint level for crates which do not have a detectable license 3 | unlicensed = "deny" 4 | 5 | # List of explicitly allowed licenses 6 | # See https://spdx.org/licenses/ for list of possible licenses 7 | # [possible values: any SPDX 3.7 short identifier (+ optional exception)]. 8 | allow = ["MPL-2.0"] 9 | 10 | # List of explicitly disallowed licenses 11 | # See https://spdx.org/licenses/ for list of possible licenses 12 | # [possible values: any SPDX 3.7 short identifier (+ optional exception)]. 13 | deny = [] 14 | 15 | # The lint level for licenses considered copyleft 16 | copyleft = "deny" 17 | 18 | # Blanket approval or denial for OSI-approved or FSF Free/Libre licenses 19 | # * both - The license will only be approved if it is both OSI-approved *AND* FSF/Free 20 | # * either - The license will be approved if it is either OSI-approved *OR* FSF/Free 21 | # * osi-only - The license will be approved if is OSI-approved *AND NOT* FSF/Free 22 | # * fsf-only - The license will be approved if is FSF/Free *AND NOT* OSI-approved 23 | # * neither - The license will be denied if is FSF/Free *OR* OSI-approved 24 | allow-osi-fsf-free = "either" 25 | 26 | # The confidence threshold for detecting a license from license text. 27 | # The higher the value, the more closely the license text must be to the 28 | # canonical license text of a valid SPDX license file. 29 | # [possible values: any between 0.0 and 1.0]. 30 | confidence-threshold = 0.8 31 | 32 | [bans] 33 | # Lint level for when multiple versions of the same crate are detected 34 | multiple-versions = "warn" 35 | 36 | # The graph highlighting used when creating dotgraphs for crates 37 | # with multiple versions 38 | # * lowest-version - The path to the lowest versioned duplicate is highlighted 39 | # * simplest-path - The path to the version with the fewest edges is highlighted 40 | # * all - Both lowest-version and simplest-path are used 41 | highlight = "all" 42 | 43 | # List of crates that are allowed. Use with care! 44 | allow = [ 45 | ] 46 | 47 | # List of crates to deny 48 | deny = [ 49 | # Each entry the name of a crate and a version range. If version is 50 | # not specified, all versions will be matched. 51 | ] 52 | 53 | # Certain crates/versions that will be skipped when doing duplicate detection. 54 | skip = [ 55 | ] 56 | 57 | # Similarly to `skip` allows you to skip certain crates during duplicate detection, 58 | # unlike skip, it also includes the entire tree of transitive dependencies starting at 59 | # the specified crate, up to a certain depth, which is by default infinite 60 | skip-tree = [ 61 | ] 62 | 63 | 64 | [advisories] 65 | ignore = [ 66 | ] 67 | -------------------------------------------------------------------------------- /examples/example_claims.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Mini Functions library. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use mini_functions::claims::Claims; 5 | 6 | fn main() { 7 | // Create a new instance of Claims 8 | let mut claims = Claims::new(); 9 | 10 | // Set claims 11 | claims.set_claim("aud", "https://example.com"); 12 | claims.set_claim("custom", "admin"); 13 | claims.set_claim("did", "did:example:123456789"); 14 | claims.set_claim("iss", "https://issuer.com"); 15 | claims.set_claim("jti", "abc123"); 16 | claims.set_claim("sub", "user123"); 17 | claims.set_claim("vc", "Ed25519Signature2018"); 18 | claims.set_claim("vp", "B7AC971B05D791F0EB5FCE3B8A3296F1D68A63199714A2993AAD6E2F3D10F4E4425576AA4D97B80B617D5A182B519E9A021DEEDE9BFFBC3499F902DDC5CA163F"); 19 | 20 | // Get claims 21 | let audience = claims.get_claim("aud").unwrap(); 22 | let custom = claims.get_claim("custom").unwrap(); 23 | let did = claims.get_claim("did").unwrap(); 24 | let issuer = claims.get_claim("iss").unwrap(); 25 | let jwt_id = claims.get_claim("jti").unwrap(); 26 | let subject = claims.get_claim("sub").unwrap(); 27 | let credential = claims.get_claim("vc").unwrap(); 28 | let proof = claims.get_claim("vp").unwrap(); 29 | 30 | println!("🦀 Claims::get_claim() for 'aud': ✅ {audience}"); 31 | println!("🦀 Claims::get_claim() for 'custom': ✅ {custom}"); 32 | println!("🦀 Claims::get_claim() for 'did': ✅ {did}"); 33 | println!("🦀 Claims::get_claim() for 'iss': ✅ {issuer}"); 34 | println!("🦀 Claims::get_claim() for 'jti': ✅ {jwt_id}"); 35 | println!("🦀 Claims::get_claim() for 'sub': ✅ {subject}"); 36 | println!("🦀 Claims::get_claim() for 'vc': ✅ {credential}"); 37 | println!("🦀 Claims::get_claim() for 'vp': ✅ {proof}"); 38 | 39 | // Remove claims 40 | let audience = claims.get_claim("aud").unwrap().to_owned(); 41 | claims.remove_claim("aud"); 42 | println!("🦀 Claims::remove_claim(): ✅ {audience}"); 43 | } 44 | -------------------------------------------------------------------------------- /examples/example_constants.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Mini Functions library. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use cmn::{ 5 | cmn_constants, 6 | constants::{Constant, ConstantValue}, 7 | }; 8 | use mini_functions::common::*; 9 | 10 | fn main() { 11 | // Create a Constants instance 12 | let c = Constants::new(); 13 | 14 | // Retrieve the list of constants 15 | let constants = c.constants(); 16 | 17 | // Serialize the constants for readability 18 | let serialized = serde_json::to_string_pretty(&constants).unwrap(); 19 | 20 | // Print the serialized constants to the console 21 | println!("🦀 Constants: ✅ {serialized}"); 22 | 23 | /// The JSON string to deserialize 24 | static JSON: &str = r#"[{"name":"EULER","value":"2.718281828459045"},{"name":"PI","value":"3.141592653589793"},{"name":"TAU","value":"6.283185307179586"},{"name":"SQRT2","value":"1.4142135623730951"},{"name":"SQRT1_2","value":"0.7071067811865476"},{"name":"LN2","value":"0.6931471805599453"},{"name":"LN10","value":"2.302585092994046"},{"name":"LOG2E","value":"1.4426950408889634"},{"name":"LOG10E","value":"0.4342944819032518"},{"name":"PHI","value":"1.618033988749895"},{"name":"GOLDEN_RATIO","value":"1.618033988749895"},{"name":"INFINITY","value":"Infinity"},{"name":"NEG_INFINITY","value":"-Infinity"},{"name":"NAN","value":"NaN"}]"#; 25 | 26 | // Deserialize the constants from the JSON string 27 | let deserialized: Vec = 28 | serde_json::from_str(JSON).unwrap(); 29 | 30 | // Print the deserialized constants 31 | println!("🦀 Deserialized: ✅ {deserialized:?}"); 32 | 33 | // Convert a constant value to ConstantValue 34 | let pi = ConstantValue::Float(std::f64::consts::PI); 35 | println!("🦀 ConstantValue of PI: ✅ {pi:?}"); 36 | 37 | // Retrieve a constant by name and print it (in this case, EULER) 38 | let euler_constant = c.constant("EULER"); 39 | println!("🦀 ConstantValue of EULER: ✅ {euler_constant:?}"); 40 | 41 | // Retrieve a constant by name and print it (in this case, PI) 42 | cmn_constants! { 43 | AVOGADRO = cmn::constants::AVOGADRO, 44 | BOLTZMANN = cmn::constants::BOLTZMANN, 45 | EULER = cmn::constants::EULER, 46 | GAMMA = cmn::constants::GAMMA, 47 | PHI = cmn::constants::PHI, 48 | PI = cmn::constants::PI, 49 | PLANCK = cmn::constants::PLANCK, 50 | SILVER_RATIO = cmn::constants::SILVER_RATIO, 51 | SQRT2 = cmn::constants::SQRT2, 52 | SQRT3 = cmn::constants::SQRT3, 53 | SQRT5 = cmn::constants::SQRT5, 54 | TAU = cmn::constants::TAU 55 | } 56 | println!("🦀 Using cmn_constants! macro:"); 57 | println!("- Avogadro's constant: ✅ {}", &AVOGADRO); 58 | println!("- Boltzmann's constant: ✅ {}", &BOLTZMANN); 59 | println!("- Euler's constant: ✅ {}", &EULER); 60 | println!("- Gamma's constant: ✅ {}", &GAMMA); 61 | println!("- Phi's constant: ✅ {}", &PHI); 62 | println!("- Pi's constant: ✅ {}", &PI); 63 | println!("- Planck's constant: ✅ {}", &PLANCK); 64 | println!("- Silver ratio's constant: ✅ {}", &SILVER_RATIO); 65 | println!("- Sqrt2's constant: ✅ {}", &SQRT2); 66 | println!("- Sqrt3's constant: ✅ {}", &SQRT3); 67 | println!("- Sqrt5's constant: ✅ {}", &SQRT5); 68 | println!("- Tau's constant: ✅ {}", &TAU); 69 | } 70 | -------------------------------------------------------------------------------- /examples/example_date.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Mini Functions library. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use mini_functions::date::DateTime; 5 | use std::str::FromStr; 6 | 7 | /// This is the main function for the build script. 8 | pub fn main() { 9 | // Create a new DateTime object with a custom timezone (e.g., CET) 10 | let paris_time = DateTime::new_with_tz("CET").now; 11 | println!("🦀 Paris time: ✅ {}", paris_time); 12 | 13 | // Example of how to use the `new` function with the UTC timezone 14 | let date = DateTime::new(); 15 | println!("🦀 Date: ✅ {}", date.now); 16 | println!("🦀 Day: ✅ {}", date.day); 17 | println!("🦀 Hour: ✅ {}", date.hour); 18 | println!("🦀 ISO 8601: ✅ {}", date.iso_8601); 19 | println!("🦀 ISO Week Number: ✅ {}", date.iso_week); 20 | println!("🦀 Microsecond: ✅ {}", date.microsecond); 21 | println!("🦀 Minute: ✅ {}", date.minute); 22 | println!("🦀 Month: ✅ {}", date.month); 23 | println!("🦀 Offset: ✅ {}", date.offset); 24 | println!("🦀 Ordinal Date: ✅ {}", date.ordinal); 25 | println!("🦀 Second: ✅ {}", date.second); 26 | println!("🦀 Time: ✅ {}", date.time); 27 | println!("🦀 Time zone: ✅ {}", date.tz); 28 | println!("🦀 Weekday: ✅ {}", date.weekday); 29 | println!("🦀 Year: ✅ {}", date.year); 30 | 31 | // Example of how to use the `is_valid_day` function 32 | println!( 33 | "🦀 Valid day (32): ❌ {}", 34 | DateTime::is_valid_day("32") 35 | ); 36 | println!( 37 | "🦀 Valid day: ✅ {}", 38 | DateTime::is_valid_day(&date.day.to_string()) 39 | ); 40 | 41 | // Example of how to use the `is_valid_hour` function 42 | println!( 43 | "🦀 Valid hour (24): ❌ {}", 44 | DateTime::is_valid_hour("24") 45 | ); 46 | println!( 47 | "🦀 Valid hour: ✅ {}", 48 | DateTime::is_valid_hour(&date.hour.to_string()) 49 | ); 50 | 51 | // Example of how to use the `next_day` function 52 | let nd = DateTime::next_day(&date); 53 | println!( 54 | "🦀 Next day: ✅ {}", 55 | String::from(&nd.day.to_string()) 56 | ); 57 | 58 | // Example of how to use the `previous_day` function 59 | let pd = DateTime::previous_day(&date); 60 | println!( 61 | "🦀 Previous day: ✅ {}", 62 | String::from(&pd.day.to_string()) 63 | ); 64 | 65 | // Example of how to use the `from_str` function 66 | let date_str = "2022-01-01T12:00:00+01:00"; 67 | let expected = Ok(DateTime { 68 | day: 1, 69 | hour: 12, 70 | iso_8601: date_str.to_owned(), 71 | iso_week: 0, 72 | microsecond: 0, 73 | minute: 0, 74 | month: "".to_owned(), 75 | now: "".to_owned(), 76 | offset: "".to_owned(), 77 | ordinal: 0, 78 | second: 0, 79 | time: "".to_owned(), 80 | tz: "".to_owned(), 81 | weekday: "".to_owned(), 82 | year: 2022, 83 | }); 84 | let result = DateTime::from_str(date_str); 85 | println!("🦀 from_str(): ✅ {}", result == expected); 86 | println!("🦀 from_str(day): ✅ {}", result.unwrap().day); 87 | 88 | // Example of how to use the `relative_delta` function 89 | let mut dt = DateTime::new(); 90 | dt.day = "11".parse::().unwrap(); 91 | dt.hour = "08".parse::().unwrap(); 92 | dt.iso_week = "19".parse::().unwrap(); 93 | dt.microsecond = "000000".parse::().unwrap(); 94 | dt.minute = "08".parse::().unwrap(); 95 | dt.month = String::from("05"); 96 | dt.second = "00".parse::().unwrap(); 97 | dt.year = "1975".parse::().unwrap(); 98 | 99 | let new_dt = dt.relative_delta(); 100 | println!("🦀 Rd day:(11) ✅ {}", new_dt.day); 101 | println!("🦀 Rd hour:(08) ✅ {}", new_dt.hour); 102 | println!("🦀 Rd week:(19) ✅ {}", new_dt.iso_week); 103 | println!("🦀 Rd ms:(000000) ✅ {}", new_dt.microsecond); 104 | println!("🦀 Rd minute:(08) ✅ {}", new_dt.minute); 105 | println!("🦀 Rd month:(05) ✅ {}", new_dt.month); 106 | println!("🦀 Rd second:(00) ✅ {}", new_dt.second); 107 | println!("🦀 Rd year:(1975) ✅ {}", new_dt.year); 108 | } 109 | -------------------------------------------------------------------------------- /examples/example_errors.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Mini Functions library. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use mini_functions::errors::common::ErrorType; 5 | 6 | fn main() { 7 | let error_type = ErrorType::new("illegal_argument"); 8 | let error_type_new_subtype = error_type.new_subtype("subtype"); 9 | 10 | println!( 11 | "🦀 Error::error_type_new(): ✅ {error_type:?}\n", 12 | ); 13 | println!("🦀 Error::error_type_new_subtype(): ✅ {error_type_new_subtype:?}\n",); 14 | } 15 | -------------------------------------------------------------------------------- /examples/example_hash.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Mini Functions library. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use mini_functions::hash::{ 5 | models::{hash::Hash, hash_algorithm::HashAlgorithm}, 6 | new_hash, 7 | }; 8 | use std::str::FromStr; 9 | 10 | /// This function demonstrates how to create and verify password hashes using Argon2i, Bcrypt, and Scrypt algorithms. 11 | fn create_and_verify_hash() { 12 | // Create new hashes for Argon2i, Bcrypt, and Scrypt 13 | let hash_argon2i = 14 | Hash::new_argon2i("password", "salt1234".into()).unwrap(); 15 | let hash_bcrypt = Hash::new_bcrypt("password", 16).unwrap(); 16 | let hash_scrypt = 17 | Hash::new_scrypt("password", "salt1234".into()).unwrap(); 18 | 19 | // Verify these hashes 20 | verify_password(&hash_argon2i, "password", "Argon2i"); 21 | verify_password(&hash_bcrypt, "password", "BCrypt"); 22 | verify_password(&hash_scrypt, "password", "Scrypt"); 23 | 24 | // Update the hashes 25 | let mut new_hash_argon2i = hash_argon2i.clone(); 26 | new_hash_argon2i 27 | .set_password("new_password", "salt1234", "argon2i") 28 | .unwrap(); 29 | 30 | let mut new_hash_bcrypt = hash_bcrypt.clone(); 31 | new_hash_bcrypt 32 | .set_password("new_password", "salt1234", "bcrypt") 33 | .unwrap(); 34 | 35 | let mut new_hash_scrypt = hash_scrypt.clone(); 36 | new_hash_scrypt 37 | .set_password("new_password", "salt1234", "scrypt") 38 | .unwrap(); 39 | 40 | // Verify the updated hashes 41 | verify_password(&new_hash_argon2i, "new_password", "Argon2i"); 42 | verify_password(&new_hash_bcrypt, "new_password", "BCrypt"); 43 | verify_password(&new_hash_scrypt, "new_password", "Scrypt"); 44 | } 45 | 46 | // Function to verify the password 47 | fn verify_password(hash: &Hash, password: &str, algorithm: &str) { 48 | // Print header 49 | println!( 50 | "\n===[ Verifying Password with {} Algorithm ]===\n", 51 | algorithm 52 | ); 53 | 54 | let is_valid = hash.verify(password); 55 | match is_valid { 56 | Ok(valid) => { 57 | println!("Algorithm: {}", algorithm); 58 | println!( 59 | "Provided password for verification: {}", 60 | password 61 | ); 62 | println!( 63 | "Salt used for verification: {}", 64 | String::from_utf8_lossy(hash.salt()) 65 | ); 66 | println!( 67 | "🦀 Password verification result for {}: ✅ {:?}", 68 | algorithm, valid 69 | ); 70 | } 71 | Err(e) => { 72 | eprintln!( 73 | "🦀 Error during password verification for {}: ❌ {}", 74 | algorithm, e 75 | ); 76 | } 77 | } 78 | 79 | // Print footer 80 | println!("\n==================================================\n"); 81 | } 82 | 83 | // Function to parse and display hash algorithms and their string representations 84 | fn parse_and_display_hash() { 85 | // Print header for parsing algorithms 86 | println!("\n===[ Parsing Hash Algorithms ]===\n"); 87 | 88 | let parsed_argon2i = HashAlgorithm::from_str("argon2i").unwrap(); 89 | let parsed_bcrypt = HashAlgorithm::from_str("bcrypt").unwrap(); 90 | let parsed_scrypt = HashAlgorithm::from_str("scrypt").unwrap(); 91 | 92 | println!("🦀 Parsed Argon2i hash algorithm: {}", parsed_argon2i); 93 | println!("🦀 Parsed Bcrypt hash algorithm: {}", parsed_bcrypt); 94 | println!("🦀 Parsed Scrypt hash algorithm: {}", parsed_scrypt); 95 | 96 | // Print footer for parsing algorithms 97 | println!("\n======================================\n"); 98 | 99 | // Print header for hash to string conversion 100 | println!("\n===[ Hash to String Conversion ]===\n"); 101 | 102 | let argon2i_hash = new_hash!("password", "salt12345", "argon2i"); 103 | let bcrypt_hash = new_hash!("password", "salt12345", "bcrypt"); 104 | let scrypt_hash = new_hash!("password", "salt12345", "scrypt"); 105 | 106 | let argon2i_hash_string = 107 | match argon2i_hash { 108 | Ok(hash) => hash.to_string_representation(), 109 | Err(e) => format!("Error: {}", e), 110 | }; 111 | let bcrypt_hash_string = 112 | match bcrypt_hash { 113 | Ok(hash) => hash.to_string_representation(), 114 | Err(e) => format!("Error: {}", e), 115 | }; 116 | let scrypt_hash_string = 117 | match scrypt_hash { 118 | Ok(hash) => hash.to_string_representation(), 119 | Err(e) => format!("Error: {}", e), 120 | }; 121 | 122 | println!("🦀 Argon2i Hash to a string: {}", argon2i_hash_string); 123 | println!("🦀 Bcrypt Hash to a string: {}", bcrypt_hash_string); 124 | println!("🦀 Scrypt Hash to a string: {}", scrypt_hash_string); 125 | 126 | // Print footer for hash to string conversion 127 | println!("\n========================================\n"); 128 | } 129 | 130 | // Main function 131 | fn main() { 132 | create_and_verify_hash(); 133 | parse_and_display_hash(); 134 | } 135 | -------------------------------------------------------------------------------- /examples/example_jwt.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Mini Functions library. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use mini_functions::jwt::{Algorithm, Header, JWT}; 5 | extern crate cjwt; 6 | use cclm::Claims; 7 | 8 | fn main() { 9 | // Constants for the JWT struct examples. 10 | const HD_ALG: Algorithm = Algorithm::HS384; 11 | const HD_KID: &str = "jwt-kid"; 12 | const HD_TYP: &str = "jwt-typ"; 13 | const HD_CTY: &str = "jwt-cty"; 14 | 15 | // Create a Header struct with default method. 16 | let hd: Header = Header::default(); 17 | println!("🦀 Header::default(): ✅ {hd:?}\n"); 18 | 19 | // Create a Header struct with default method and replace values. 20 | let mut hdrv: Header = Header::default(); 21 | Header::default().alg = 22 | std::mem::replace(&mut hdrv.alg, Some(HD_ALG)); 23 | Header::default().kid = 24 | std::mem::replace(&mut hdrv.kid, Some(HD_KID.to_string())); 25 | Header::default().typ = 26 | std::mem::replace(&mut hdrv.typ, Some(HD_TYP.to_string())); 27 | Header::default().cty = 28 | std::mem::replace(&mut hdrv.cty, Some(HD_CTY.to_string())); 29 | println!("🦀 Header::default(): ✅ {hdrv:?}\n"); 30 | 31 | // Create a JWT struct with default method. 32 | let jd: JWT = JWT::default(); 33 | println!("🦀 JWT::default(): ✅ {jd:?}\n"); 34 | 35 | // Create a JWT struct with default method and replace values. 36 | let mut jdrv: JWT = JWT::default(); 37 | JWT::default().header.alg = 38 | std::mem::replace(&mut jdrv.header.alg, Some(HD_ALG)); 39 | JWT::default().header.kid = std::mem::replace( 40 | &mut jdrv.header.kid, 41 | Some(HD_KID.to_string()), 42 | ); 43 | JWT::default().header.typ = std::mem::replace( 44 | &mut jdrv.header.typ, 45 | Some(HD_TYP.to_string()), 46 | ); 47 | JWT::default().header.cty = std::mem::replace( 48 | &mut jdrv.header.cty, 49 | Some(HD_CTY.to_string()), 50 | ); 51 | println!("🦀 JWT::default(): ✅ {jdrv:?}\n"); 52 | 53 | // Encode a JWT struct. 54 | let encoded: String = 55 | JWT::encode(hdrv, Claims::default(), b"secret").unwrap(); 56 | println!("🦀 encode(): ✅ {encoded:?}\n"); 57 | 58 | // Extract the token field from the passed JWT struct and return it. 59 | let jwt = JWT { 60 | header: Header::default(), 61 | claims: Claims::default(), 62 | signature: vec![], 63 | token: "example_token".to_owned(), 64 | }; 65 | let result = JWT::get_token(jwt); 66 | println!("🦀 get_token(): ✅ {result:?}\n"); 67 | } 68 | -------------------------------------------------------------------------------- /examples/example_logs.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Mini Functions library. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use mini_functions::date::DateTime; 5 | use mini_functions::logs::{Log, LogFormat, LogLevel}; 6 | 7 | fn main() { 8 | let date = DateTime::new(); 9 | let iso = date.iso_8601; 10 | let log_formats = vec![ 11 | LogFormat::CLF, 12 | LogFormat::JSON, 13 | LogFormat::CEF, 14 | LogFormat::ELF, 15 | LogFormat::GELF, 16 | LogFormat::W3C, 17 | ]; 18 | 19 | for format in log_formats { 20 | let log = Log::new( 21 | "12345678-1234-1234-1234-1234567890ab", 22 | &iso, 23 | &LogLevel::INFO, 24 | "SystemTrayEvent", 25 | "Showing main window", 26 | &format, 27 | ); 28 | println!("🦀 Log::new(): ✅ {log}"); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /examples/example_md5.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Mini Functions library. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | use mini_functions::md5::{Digest, MD5}; 5 | 6 | fn main() { 7 | // Example using MD5::hexdigest() for a string input 8 | let input = "Hello, world!"; 9 | let digest = MD5::hexdigest(input); 10 | println!("🦀 MD5::hexdigest() for a string input: ✅ {digest}",); 11 | // Expected 6cd3556deb0da54bca060b4c39479839 12 | 13 | // Example using MD5::hexdigest() for a byte array input 14 | let input = 15 | [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33]; // "Hello, world!" 16 | let input_str = String::from_utf8(input.to_vec()).unwrap(); 17 | let digest = MD5::hexdigest(&input_str); 18 | println!("🦀 MD5::hexdigest() for a byte array input: ✅ {digest}",); 19 | // Expected 6cd3556deb0da54bca060b4c39479839 20 | 21 | // Example using MD5::hexdigest() for a file input 22 | let digest = MD5::hexdigest_file("mdg/file.txt"); // file.txt contains "Hello, world!" 23 | println!("🦀 MD5::hexdigest_file() for a file input: ✅ {digest}",); 24 | // Expected 6cd3556deb0da54bca060b4c39479839 25 | 26 | // Example using MD5::update() for a byte array input 27 | let mut mdg = MD5::new(); 28 | let input = [ 29 | 67, 111, 117, 99, 111, 117, 44, 32, 108, 101, 32, 109, 111, 30 | 110, 100, 101, 33, 31 | ]; // "Coucou, le monde!" 32 | mdg.update(&input); 33 | let digest = mdg.finalize(); 34 | println!("🦀 MD5::update() for a byte array input: ✅ {digest}",); 35 | // Expected 47353a0e5ed2e1e0d57213a39e9bb7c4 36 | 37 | // Example using MD5::update() for a string input 38 | let mut mdg = MD5::new(); 39 | let input = "Coucou, le monde!"; 40 | mdg.update(input.as_bytes()); 41 | let digest = mdg.finalize(); 42 | println!("🦀 MD5::update() for a string input: ✅ {digest}",); 43 | // Expected 47353a0e5ed2e1e0d57213a39e9bb7c4 44 | 45 | // Example using MD5::update() for a file input 46 | let mut mdg = MD5::new(); 47 | println!( 48 | "🦀 MD5::new() is: ✅ {}", 49 | mdg.finalize() 50 | ); 51 | // Expected d41d8cd98f00b204e9800998ecf8427e 52 | mdg.update_file("mdg/update.txt"); // update.txt contains "Coucou, le monde!" 53 | let digest = mdg.finalize(); 54 | println!("🦀 MD5::update_file() is: ✅ {digest}",); 55 | // Expected 7fc3e27776139278c6b8e0b6f096b4fb 56 | 57 | // Example using MD5::reset() for a string input 58 | let mut mdg = MD5::new(); 59 | println!( 60 | "🦀 MD5::new() is: ✅ {}", 61 | mdg.finalize() 62 | ); 63 | // Expected d41d8cd98f00b204e9800998ecf8427e 64 | println!( 65 | "🦀 MD5::reset() for a string input: ✅ {}", 66 | mdg.reset() 67 | ); 68 | // Expected 00000000000000000000000000000000 69 | } 70 | -------------------------------------------------------------------------------- /examples/example_qr.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Mini Functions library. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | extern crate image; 5 | use image::{imageops, ImageBuffer, Rgba, RgbaImage}; 6 | extern crate qrc; 7 | use self::qrc::QRCode; 8 | 9 | use std::fs; 10 | 11 | const URL: &str = "https://minifunctions.com/"; 12 | 13 | fn main() { 14 | generate_and_process_qrcode(); 15 | } 16 | 17 | fn generate_and_process_qrcode() { 18 | let qrcode = QRCode::from_string(URL.to_string()); 19 | process_png(&qrcode, "qrcode.png"); 20 | process_png_with_custom_color(&qrcode, "qrcode_colorized.png"); 21 | process_svg(&qrcode, "qrcode.svg"); 22 | process_resized_qrcode(&qrcode, "qrcode_resized.png"); 23 | // Add additional QR code processing functions here as needed. 24 | } 25 | 26 | fn process_png(qrcode: &QRCode, filename: &str) { 27 | let png = qrcode.to_png(512); 28 | save_and_remove_file(png.into_raw(), filename, 512, 512); 29 | } 30 | 31 | fn process_png_with_custom_color(qrcode: &QRCode, filename: &str) { 32 | let red = Rgba([255, 0, 0, 255]); 33 | let red_qrcode = qrcode.colorize(red); 34 | let img: RgbaImage = red_qrcode; 35 | let resized_img = imageops::resize(&img, 512, 512, imageops::FilterType::Nearest); 36 | save_and_remove_file(resized_img.into_raw(), filename, 512, 512); 37 | } 38 | 39 | fn process_svg(qrcode: &QRCode, filename: &str) { 40 | let svg_data = qrcode.to_svg(512); 41 | match fs::write(filename, svg_data) { 42 | Ok(_) => println!("🦀 SVG file created: ✅ {}", filename), 43 | Err(e) => println!("🦀 SVG file creation failed: ❌ {}: {}", filename, e), 44 | } 45 | remove_file(filename); 46 | } 47 | 48 | fn process_resized_qrcode(qrcode: &QRCode, filename: &str) { 49 | let png = qrcode.to_png(512); 50 | let img: RgbaImage = ImageBuffer::from_raw(512, 512, png.into_raw()).unwrap(); 51 | let resized_img = imageops::resize(&img, 256, 256, imageops::FilterType::Nearest); // Example resizing 52 | save_and_remove_file(resized_img.into_raw(), filename, 256, 256); 53 | } 54 | 55 | fn save_and_remove_file(data: Vec, filename: &str, width: u32, height: u32) { 56 | let image = ImageBuffer::, Vec>::from_raw(width, height, data).unwrap(); 57 | match image.save(filename) { 58 | Ok(_) => println!("🦀 PNG file created: ✅ {}", filename), 59 | Err(e) => println!("🦀 PNG file creation failed: ❌ {}: {}", filename, e), 60 | } 61 | remove_file(filename); 62 | } 63 | 64 | fn remove_file(filename: &str) { 65 | match fs::remove_file(filename) { 66 | Ok(_) => println!("🦀 File removed: ✅ {}", filename), 67 | Err(e) => println!("🦀 File removal failed: ❌ {}: {}", filename, e), 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /examples/example_random.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Mini Functions library. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! Example code using the `vrd` crate. 5 | //! 6 | //! This example demonstrates the usage of the `vrd` crate. 7 | //! It imports the `Random` trait and other items from the `vrd` crate. 8 | //! The example code showcases the generation of random numbers. 9 | //! 10 | //! # Example 11 | //! 12 | //! ``` 13 | //! extern crate vrd; 14 | //! 15 | //! use self::vrd::Random; 16 | //! use vrd::*; 17 | //! 18 | //! fn main() { 19 | //! let random_number = u32::random(); 20 | //! println!("Random number: {}", random_number); 21 | //! } 22 | //! ``` 23 | use mini_functions::random::*; 24 | 25 | fn main() { 26 | // Create a new random boolean with 50% probability of being true 27 | let bool: bool = Random::bool(&mut Random::new(), 0.5); 28 | println!("🦀 Random::bool(): ✅ {bool}"); 29 | 30 | // Create a new random number generator 31 | let mut rng = Random::new(); 32 | println!("🦀 Random::new(): ✅ {rng}"); 33 | 34 | // Get the default random number generator 35 | let default = Random::default(); 36 | println!("🦀 Random::default(): ✅ {default}"); 37 | 38 | // Generate a random number between 0 and u32::max_value() 39 | let random = rng.rand(); 40 | println!("🦀 Random::random(): ✅ {random}"); 41 | 42 | // Seed the PRNG with a given value 43 | let seed_value = 12345; 44 | let mut rng = Random::new(); 45 | rng.seed(seed_value); // Seed the RNG 46 | println!("🦀 Random::seed(): ✅ {}", seed_value); // Print the seed value 47 | 48 | // Generate a vector of random bytes with a given length 49 | let bytes = Random::bytes(&mut rng, 1000); 50 | println!("🦀 Random::bytes(): ✅ {bytes:?}"); 51 | 52 | // Generate a random float between 0 and 1 53 | let float = rng.rand() as f32 / 0x7FFF as f32; 54 | println!("🦀 Random::float(): ✅ {float}"); 55 | 56 | // Generate a random usize 57 | let int = rng.rand() as usize; 58 | println!("🦀 Random::int(): ✅ {int}"); 59 | 60 | // Generate a random integer within a range of values 61 | let mut rng = Random::new(); 62 | let min = 0; 63 | let max = 100; 64 | 65 | // Generate a random integer within a range 66 | let rand_int = rand_int!(rng, min, max); 67 | println!( 68 | "🦀 Random integer between {} and {}: {}", 69 | min, max, rand_int 70 | ); 71 | 72 | // Generate a random number within a range 73 | let rand_range = 74 | rand_float!(rng) * (max as f32 - min as f32) + min as f32; 75 | println!("🦀 Random number between 0 and 1: {}", rand_range); 76 | 77 | // Generate a random 32-bit unsigned integer within a range 78 | let rand_uint = random_range!(rng, 0, u32::max_value()); 79 | println!( 80 | "🦀 Random u32 between 0 and u32::max_value(): {}", 81 | rand_uint 82 | ); 83 | 84 | // Generate a random boolean with a given probability 85 | let rand_bool = rand_bool!(rng, 0.5); 86 | println!("🦀 Random boolean with 50% probability: {}", rand_bool); 87 | 88 | // Generate a vector of random bytes with a given length 89 | let rand_bytes = rand_bytes!(rng, 10); 90 | println!("🦀 Random bytes: {:?}", rand_bytes); 91 | 92 | // Generate a random char within the range 'a'..='z' 93 | let rand_char = rand_char!(rng); 94 | println!("🦀 Random char between 'a' and 'z': {}", rand_char); 95 | 96 | // Generate a random element from a slice of values 97 | let values = &[1, 2, 3, 4, 5]; 98 | let rand_choose = rand_choose!(rng, values); 99 | println!( 100 | "🦀 Random element from [1, 2, 3, 4, 5]: {:?}", 101 | rand_choose 102 | ); 103 | 104 | // Generate a random float 105 | let rand_float = rand_float!(rng); 106 | println!("🦀 Random float: {}", rand_float); 107 | 108 | // Generate a random 32-bit unsigned integer 109 | let rand_pseudo = rand_pseudo!(rng); 110 | println!("🦀 Random u32 using the PRNG: {}", rand_pseudo); 111 | 112 | // Seed the PRNG with a given value 113 | rand_seed!(rng, 42); 114 | let rand_seed = rand_pseudo!(rng); 115 | println!("🦀 Random u32 using the seeded PRNG: {}", rand_seed); 116 | 117 | // Twist the state of the PRNG 118 | rand_twist!(rng); 119 | let rand_twist = rand_pseudo!(rng); 120 | println!( 121 | "🦀 Random u32 after twisting the PRNG state: {}", 122 | rand_twist 123 | ); 124 | } 125 | -------------------------------------------------------------------------------- /idk/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Sebastian Rousseau 18 |
19 | 20 | **[Website][0] 21 | • [Documentation][9] 22 | • [Report Bug][3] 23 | • [Request Feature][3] 24 | • [Contributing Guidelines][4]** 25 | 26 |
27 | 28 | 29 | 30 | ## Overview 📖 31 | 32 | IDontKnow (IDK) is a Rust library that has functions and variables 33 | designed to make it easy for your program to report informative error 34 | messages. You can use the IDK library to create error messages that are 35 | clear, concise, and actionable. 36 | 37 | ## Features ✨ 38 | 39 | The library includes multiple modules: `Common`, `Error`, `Jwt`, 40 | `Property`, `Stacktrace`, and `Traits`. 41 | 42 | - **The common module:** This module provides a foundation of common 43 | errors that can be utilized throughout the entire project. 44 | These functionalities serve as a building block for the rest of the 45 | project, making it easier for developers to create and manage their 46 | code. 47 | - **The error module:** This module contains all the error types that 48 | are used in the project. By providing a centralized location for 49 | errors, developers can quickly and easily identify and resolve any 50 | issues that may arise. 51 | - **The jwt module:** This module offers the tools necessary to encode 52 | and decode JSON Web Tokens (JWT). With a simple, easy-to-use 53 | interface, developers can ensure secure communication between parties. 54 | - **The property module:** This module provides the functionality to 55 | create and manage properties. By utilizing this module, developers can 56 | keep track of all properties within the project and make changes as 57 | necessary. 58 | - **The stacktrace module:** This module offers the tools to create and 59 | manage stacktraces. By providing detailed information about the 60 | execution of the code, developers can quickly identify and resolve any 61 | issues that may arise. 62 | - **The traits module:** This module provides functionality to create 63 | and manage traits. By utilizing this module, developers can ensure 64 | that all traits within the project are consistent and well-defined. 65 | 66 | ## Installation 📦 67 | 68 | It takes just a few minutes to get up and running with `idk`. 69 | 70 | ### Requirements 71 | 72 | `idk` requires Rust **1.67.0** or later. 73 | 74 | ### Documentation 75 | 76 | > ℹ️ **Info:** Please check out our [website][0] for more information 77 | and find our documentation on [docs.rs][9], [lib.rs][10] and 78 | [crates.io][8]. 79 | 80 | ## Usage 📖 81 | 82 | To use `idk` in your project, add the following to your 83 | `Cargo.toml` file: 84 | 85 | ```toml 86 | [dependencies] 87 | idk = "0.0.1" 88 | ``` 89 | 90 | Add the following to your `main.rs` file: 91 | 92 | ```rust 93 | extern crate idk; 94 | use idk::*; 95 | ``` 96 | 97 | then you can use the functions in your application code. 98 | 99 | ### Examples 100 | 101 | `IDK` comes with a set of examples that you can use to get started. The 102 | examples are located in the `examples` directory of the project. To run 103 | the examples, clone the repository and run the following command in your 104 | terminal from the project root directory. 105 | 106 | ```shell 107 | cargo run --example idk 108 | ``` 109 | 110 | ## Semantic Versioning Policy 🚥 111 | 112 | For transparency into our release cycle and in striving to maintain 113 | backward compatibility, `IDK` follows [semantic versioning][7]. 114 | 115 | ## License 📝 116 | 117 | The project is licensed under the terms of both the MIT license and the 118 | Apache License (Version 2.0). 119 | 120 | - [Apache License, Version 2.0][1] 121 | - [MIT license][2] 122 | 123 | ## Contribution 🤝 124 | 125 | Unless you explicitly state otherwise, any contribution intentionally 126 | submitted for inclusion in the work by you, as defined in the Apache-2.0 127 | license, shall be dual licensed as above, without any additional terms 128 | or conditions. 129 | 130 | ![divider][divider] 131 | 132 | ## Acknowledgements 💙 133 | 134 | A big thank you to all the awesome contributors of [Mini Functions][6] 135 | for their help and support. A special thank you goes to the 136 | [Rust Reddit](https://www.reddit.com/r/rust/) community for providing a 137 | lot of useful suggestions on how to improve this project. 138 | 139 | [0]: https://minifunctions.com 140 | [1]: http://www.apache.org/licenses/LICENSE-2.0 141 | [2]: http://opensource.org/licenses/MIT 142 | [3]: https://github.com/sebastienrousseau/mini-functions/issues 143 | [4]: https://raw.githubusercontent.com/sebastienrousseau/mini-functions/main/.github/CONTRIBUTING.md 144 | [6]: https://github.com/sebastienrousseau/mini-functions/graphs/contributors 145 | [7]: http://semver.org/ 146 | [8]: https://crates.io/crates/idk 147 | [9]: https://docs.rs/idk 148 | [10]: https://lib.rs/crates/idk 149 | 150 | [banner]: https://raw.githubusercontent.com/sebastienrousseau/vault/main/assets/mini-functions/banners/banner-idk-1597x377.svg "IDK Banner" 151 | [crates-badge]: https://img.shields.io/crates/v/idk.svg?style=for-the-badge 'Crates.io' 152 | [divider]: https://raw.githubusercontent.com/sebastienrousseau/vault/main/assets/elements/divider.svg "divider" 153 | [docs-badge]: https://img.shields.io/docsrs/idk.svg?style=for-the-badge 'Docs.rs' 154 | [libs-badge]: https://img.shields.io/badge/lib.rs-v0.0.1-orange.svg?style=for-the-badge 'Lib.rs' 155 | [license-badge]: https://img.shields.io/crates/l/idk.svg?style=for-the-badge 'License' 156 | [made-with-rust]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust 'Made With Rust' 157 | -------------------------------------------------------------------------------- /idk/benches/idk.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /idk/deny.toml: -------------------------------------------------------------------------------- 1 | [licenses] 2 | # The lint level for crates which do not have a detectable license 3 | unlicensed = "deny" 4 | 5 | # List of explicitly allowed licenses 6 | # See https://spdx.org/licenses/ for list of possible licenses 7 | # [possible values: any SPDX 3.7 short identifier (+ optional exception)]. 8 | allow = ["MPL-2.0"] 9 | 10 | # List of explicitly disallowed licenses 11 | # See https://spdx.org/licenses/ for list of possible licenses 12 | # [possible values: any SPDX 3.7 short identifier (+ optional exception)]. 13 | deny = [] 14 | 15 | # The lint level for licenses considered copyleft 16 | copyleft = "deny" 17 | 18 | # Blanket approval or denial for OSI-approved or FSF Free/Libre licenses 19 | # * both - The license will only be approved if it is both OSI-approved *AND* FSF/Free 20 | # * either - The license will be approved if it is either OSI-approved *OR* FSF/Free 21 | # * osi-only - The license will be approved if is OSI-approved *AND NOT* FSF/Free 22 | # * fsf-only - The license will be approved if is FSF/Free *AND NOT* OSI-approved 23 | # * neither - The license will be denied if is FSF/Free *OR* OSI-approved 24 | allow-osi-fsf-free = "either" 25 | 26 | # The confidence threshold for detecting a license from license text. 27 | # The higher the value, the more closely the license text must be to the 28 | # canonical license text of a valid SPDX license file. 29 | # [possible values: any between 0.0 and 1.0]. 30 | confidence-threshold = 0.8 31 | 32 | [bans] 33 | # Lint level for when multiple versions of the same crate are detected 34 | multiple-versions = "warn" 35 | 36 | # The graph highlighting used when creating dotgraphs for crates 37 | # with multiple versions 38 | # * lowest-version - The path to the lowest versioned duplicate is highlighted 39 | # * simplest-path - The path to the version with the fewest edges is highlighted 40 | # * all - Both lowest-version and simplest-path are used 41 | highlight = "all" 42 | 43 | # List of crates that are allowed. Use with care! 44 | allow = [ 45 | ] 46 | 47 | # List of crates to deny 48 | deny = [ 49 | # Each entry the name of a crate and a version range. If version is 50 | # not specified, all versions will be matched. 51 | ] 52 | 53 | # Certain crates/versions that will be skipped when doing duplicate detection. 54 | skip = [ 55 | ] 56 | 57 | # Similarly to `skip` allows you to skip certain crates during duplicate detection, 58 | # unlike skip, it also includes the entire tree of transitive dependencies starting at 59 | # the specified crate, up to a certain depth, which is by default infinite 60 | skip-tree = [ 61 | ] 62 | 63 | 64 | [advisories] 65 | ignore = [ 66 | ] 67 | -------------------------------------------------------------------------------- /idk/examples/idk.rs: -------------------------------------------------------------------------------- 1 | extern crate idk; 2 | use idk::common::ErrorType; 3 | 4 | fn main() { 5 | let error_type = ErrorType::new("illegal_argument"); 6 | let error_type_new_subtype = error_type.new_subtype("subtype"); 7 | 8 | println!("🦀 Error::error_type_new(): ✅ {error_type:?}\n",); 9 | println!("🦀 Error::error_type_new_subtype(): ✅ {error_type_new_subtype:?}\n",); 10 | } 11 | -------------------------------------------------------------------------------- /idk/rustfmt.toml: -------------------------------------------------------------------------------- 1 | # default -------------------------------------------------------------------------------- /idk/src/common.rs: -------------------------------------------------------------------------------- 1 | /// ErrorType is a struct that holds a name and an Error enum instance 2 | #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] 3 | pub struct ErrorType { 4 | /// name is a string that holds the name of the error type 5 | pub name: String, 6 | /// error_type is an instance of the Error enum 7 | pub error_type: Error, 8 | } 9 | /// Error is an enumeration of different error types 10 | #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] 11 | pub enum Error { 12 | /// Argument error 13 | Argument(String), 14 | /// Assertion error 15 | Assertion(String), 16 | /// Concurrency error 17 | Concurrency(String), 18 | /// Data error 19 | Data(String), 20 | /// External error 21 | External(String), 22 | /// Format error 23 | Format(String), 24 | /// Implementation error 25 | Implementation(String), 26 | /// Initialization error 27 | Initialization(String), 28 | /// Internal error 29 | Internal(String), 30 | /// Interruption error 31 | Interruption(String), 32 | /// Operation error 33 | Operation(String), 34 | /// Rejection error 35 | Rejection(String), 36 | /// State error 37 | State(String), 38 | /// Timeout error 39 | Timeout(String), 40 | /// Unknown error 41 | Unknown(String), 42 | /// Version error 43 | Version(String), 44 | } 45 | 46 | impl Error { 47 | /// new creates a new Error enum instance based on the name 48 | pub fn new(err_type: ErrorType) -> Self { 49 | match err_type.name.as_str() { 50 | "argument" => Error::Argument(String::from("Illegal argument")), 51 | "assertion" => Error::Assertion(String::from("Assertion failed")), 52 | "concurrency" => Error::Concurrency(String::from("Concurrency update")), 53 | "data" => Error::Data(String::from("Data unavailable")), 54 | "external" => Error::External(String::from("External error")), 55 | "format" => Error::Format(String::from("Illegal format")), 56 | "implementation" => Error::Implementation(String::from("No implementation")), 57 | "initialization" => Error::Initialization(String::from("Initialization failed")), 58 | "internal" => Error::Internal(String::from("Internal error")), 59 | "interruption" => Error::Interruption(String::from("Interruption occurred")), 60 | "operation" => Error::Operation(String::from("Unsupported operation")), 61 | "rejection" => Error::Rejection(String::from("Rejection occurred")), 62 | "state" => Error::State(String::from("Illegal state")), 63 | "timeout" => Error::Timeout(String::from("Timeout elapsed")), 64 | "version" => Error::Version(String::from("Unsupported version")), 65 | _ => Error::Unknown(String::from("Unknown error")), 66 | } 67 | } 68 | } 69 | 70 | impl ErrorType { 71 | /// new creates a new ErrorType struct instance 72 | pub fn new(name: &str) -> ErrorType { 73 | ErrorType { 74 | name: String::from(name), 75 | error_type: Error::new(ErrorType { 76 | name: name.to_string(), 77 | error_type: Error::Unknown(String::from(name)), 78 | }), 79 | } 80 | } 81 | /// new_subtype creates a new ErrorType struct instance 82 | pub fn new_subtype(&self, name: &str) -> ErrorType { 83 | ErrorType { 84 | name: String::from(name), 85 | error_type: Error::new(ErrorType { 86 | name: name.to_string(), 87 | error_type: Error::Unknown(String::from(name)), 88 | }), 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /idk/src/error.rs: -------------------------------------------------------------------------------- 1 | use crate::common::ErrorType; 2 | use std::error::Error as StdError; 3 | use std::fmt; 4 | 5 | #[derive(Debug)] 6 | /// Error struct for the crate 7 | pub struct Error { 8 | /// The error message 9 | pub message: String, 10 | 11 | /// The error type 12 | pub error_type: ErrorType, 13 | 14 | /// The context of the error 15 | pub ctx: String, 16 | } 17 | 18 | impl Error { 19 | /// Create a new error 20 | pub fn new(message: &str, error_type: ErrorType) -> Error { 21 | Error { 22 | message: message.to_owned(), 23 | error_type, 24 | ctx: "".to_owned(), 25 | } 26 | } 27 | 28 | /// Create a new error type 29 | pub fn error_type(name: &str, error_type: ErrorType, ctx: &str) -> Error { 30 | Error { 31 | message: name.to_owned(), 32 | error_type, 33 | ctx: ctx.to_owned(), 34 | } 35 | } 36 | 37 | /// Add context to the error 38 | pub fn with_context(mut self, ctx: &str) -> Error { 39 | self.ctx = ctx.to_owned(); 40 | self 41 | } 42 | } 43 | 44 | impl StdError for Error { 45 | /// Source of the error 46 | fn source(&self) -> Option<&(dyn StdError + 'static)> { 47 | None 48 | } 49 | } 50 | 51 | impl fmt::Display for Error { 52 | /// Display the error 53 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 54 | write!(f, "{}, ctx: {}", self.message, self.ctx) 55 | } 56 | } 57 | 58 | impl fmt::Display for ErrorType { 59 | /// Display the error type 60 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 61 | write!(f, "{}", self.name) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /idk/src/jwt.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022-2023 Mini Functions. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | // SPDX-License-Identifier: MIT 4 | 5 | extern crate base64; 6 | // extern crate openssl; 7 | extern crate serde_json; 8 | 9 | // use openssl::error::ErrorStack; 10 | // use self::error::Error; 11 | use base64::DecodeError; 12 | use hmac::digest::InvalidLength as InvLen; 13 | use serde_json::Error as SJError; 14 | use std::error::Error; 15 | use std::fmt; 16 | use std::io::Error as IoError; 17 | 18 | #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] 19 | /// Custom error type for JWT. This type is used to represent all 20 | /// possible errors that can occur when working with JWTs. It is 21 | /// implemented as an enum with variants for each possible error. It 22 | /// also implements the `Default`, `Display`, and `Error` traits. 23 | pub enum JwtError { 24 | /// The Audience is invalid. 25 | AudienceInvalid(String), 26 | 27 | /// Decode error. 28 | DecodeError(String), 29 | 30 | /// Expiration is invalid. 31 | ExpirationInvalid(String), 32 | 33 | /// Format is invalid 34 | FormatInvalid(String), 35 | 36 | /// Invalid header. 37 | InvalidHeader(String), 38 | 39 | /// Invalid payload. 40 | InvalidPayload(String), 41 | 42 | /// Invalid signature 43 | InvalidSignature(String), 44 | 45 | /// Invalid length 46 | InvalidLength(String), 47 | 48 | /// IO error. 49 | IoError(String), 50 | 51 | /// Issuer is invalid. 52 | IssuerInvalid(String), 53 | 54 | /// JWT is invalid. 55 | JWTInvalid(String), 56 | 57 | /// Open SSL error. 58 | OpenSslError(String), 59 | 60 | /// Protocol error. 61 | ProtocolError(String), 62 | 63 | /// Signature is expired. 64 | SignatureExpired(String), 65 | 66 | /// Signature is invalid. 67 | SignatureInvalid(String), 68 | 69 | /// Token not found. 70 | TokenNotFound(String), 71 | } 72 | 73 | impl Error for JwtError {} 74 | 75 | impl fmt::Display for JwtError { 76 | /// The formatted error. 77 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 78 | match self { 79 | JwtError::AudienceInvalid(err) => write!(f, "Audience Invalid Error: {err}"), 80 | JwtError::ExpirationInvalid(err) => write!(f, "Expiration Invalid Error: {err}"), 81 | // implement display for other variants as well 82 | _ => write!(f, "Unknown error"), 83 | } 84 | } 85 | } 86 | 87 | impl From for JwtError { 88 | /// Converts a `DecodeError` to a `JwtError`. 89 | fn from(error: DecodeError) -> Self { 90 | JwtError::DecodeError(error.to_string()) 91 | } 92 | } 93 | 94 | impl From for JwtError { 95 | fn from(error: SJError) -> Self { 96 | JwtError::InvalidPayload(error.to_string()) 97 | } 98 | } 99 | 100 | impl From for JwtError { 101 | fn from(error: InvLen) -> Self { 102 | JwtError::InvalidLength(error.to_string()) 103 | } 104 | } 105 | 106 | // impl From for JwtError { 107 | // fn from(error: ErrorStack) -> Self { 108 | // JwtError::OpenSslError(error.to_string()) 109 | // } 110 | // } 111 | 112 | impl From for JwtError { 113 | fn from(error: IoError) -> Self { 114 | JwtError::IoError(error.to_string()) 115 | } 116 | } 117 | 118 | impl JwtError { 119 | /// Returns `true` if the error is a signature error. 120 | pub fn is_signature_error(&self) -> bool { 121 | matches!( 122 | self, 123 | JwtError::SignatureExpired(_) | JwtError::SignatureInvalid(_) 124 | ) 125 | } 126 | 127 | /// Returns `true` if the error is a JWT error. 128 | pub fn is_jwt_error(&self) -> bool { 129 | matches!(self, JwtError::JWTInvalid(_)) 130 | } 131 | 132 | /// Returns `true` if the error is an issuer error. 133 | pub fn is_issuer_error(&self) -> bool { 134 | matches!(self, JwtError::IssuerInvalid(_)) 135 | } 136 | 137 | /// Returns `true` if the error is an expiration error. 138 | pub fn is_expiration_error(&self) -> bool { 139 | matches!(self, JwtError::ExpirationInvalid(_)) 140 | } 141 | 142 | /// Returns `true` if the error is an audience error. 143 | pub fn is_audience_error(&self) -> bool { 144 | matches!(self, JwtError::AudienceInvalid(_)) 145 | } 146 | 147 | /// Returns `true` if the error is a format error. 148 | pub fn is_format_error(&self) -> bool { 149 | matches!(self, JwtError::FormatInvalid(_)) 150 | } 151 | 152 | /// Returns `true` if the error is a header error. 153 | pub fn is_invalid_length_error(&self) -> bool { 154 | matches!(self, JwtError::InvalidLength(_)) 155 | } 156 | 157 | /// Returns `true` if the error is an IO error. 158 | pub fn is_io_error(&self) -> bool { 159 | matches!(self, JwtError::IoError(_)) 160 | } 161 | 162 | /// Returns `true` if the error is an Open SSL error. 163 | pub fn is_openssl_error(&self) -> bool { 164 | matches!(self, JwtError::OpenSslError(_)) 165 | } 166 | 167 | /// Returns `true` if the error is a protocol error. 168 | pub fn is_protocol_error(&self) -> bool { 169 | matches!(self, JwtError::ProtocolError(_)) 170 | } 171 | /// Returns `true` if the error is a token not found error. 172 | pub fn is_token_not_found_error(&self) -> bool { 173 | matches!(self, JwtError::TokenNotFound(_)) 174 | } 175 | /// Returns `true` if the error is an invalid base 64. 176 | pub fn is_base64_error(&self) -> bool { 177 | matches!(self, JwtError::DecodeError(_)) 178 | } 179 | } 180 | 181 | // Implementation of `Default` for `Error` to provide a default error. 182 | impl Default for JwtError { 183 | fn default() -> Self { 184 | Self::SignatureExpired("Signature expired.".to_owned()) 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /idk/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022-2023 Mini Functions. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | // SPDX-License-Identifier: MIT 4 | //! 5 | //! # A Rust library for managing errors and exceptions 6 | //! 7 | //! [![Rust](https://raw.githubusercontent.com/sebastienrousseau/vault/main/assets/mini-functions/logo/logo-idk.svg)](https://minifunctions.com) 8 | //! 9 | //!
10 | //! 11 | //! [![Rust](https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust)](https://www.rust-lang.org) 12 | //! [![Crates.io](https://img.shields.io/crates/v/idk.svg?style=for-the-badge&color=success&labelColor=27A006)](https://crates.io/crates/idk) 13 | //! [![Lib.rs](https://img.shields.io/badge/lib.rs-v0.0.1-success.svg?style=for-the-badge&color=8A48FF&labelColor=6F36E4)](https://lib.rs/crates/idk) 14 | //! [![GitHub](https://img.shields.io/badge/github-555555?style=for-the-badge&labelColor=000000&logo=github)](https://github.com/sebastienrousseau/tree/main/idk) 15 | //! [![License](https://img.shields.io/crates/l/idk.svg?style=for-the-badge&color=007EC6&labelColor=03589B)](http://opensource.org/licenses/MIT) 16 | //! 17 | //!
18 | //! 19 | //! ## Overview 20 | //! 21 | //! IDontKnow (IDK) is a Rust library that has functions and variables 22 | //! designed to make it easy for your program to report informative 23 | //! error messages. You can use the IDK library to create error messages 24 | //! that are clear, concise, and actionable. 25 | //! 26 | //! ## Features 27 | //! 28 | //! The library includes multiple modules: `Common`, `Error`, `Jwt`, 29 | //! `Property`, `Stacktrace`, and `Traits`. 30 | //! 31 | //! - **The common module:** This module provides a foundation of common 32 | //! functionalities that can be utilized throughout the entire project. 33 | //! These functionalities serve as a building block for the rest of the 34 | //! project, making it easier for developers to create and manage their 35 | //! code. 36 | //! - **The error module:** This module contains all the error types 37 | //! that are used in the project. By providing a centralized location 38 | //! for errors, developers can quickly and easily identify and resolve 39 | //! any issues that may arise. 40 | //! - **The jwt module:** This module offers the tools necessary to 41 | //! encode and decode JSON Web Tokens (JWT). With a simple, easy-to-use 42 | //! interface, developers can ensure secure communication between 43 | //! parties. 44 | //! - **The property module:** This module provides the functionality to 45 | //! create and manage properties. By utilizing this module, developers 46 | //! can keep track of all properties within the project and make changes 47 | //! as necessary. 48 | //! - **The stacktrace module:** This module offers the tools to create 49 | //! and manage stacktraces. By providing detailed information about the 50 | //! execution of the code, developers can quickly identify and resolve 51 | //! any issues that may arise. 52 | //! - **The traits module:** This module provides functionality to 53 | //! create and manage traits. By utilizing this module, developers can 54 | //! ensure that all traits within the project are consistent and 55 | //! well-defined. 56 | //! 57 | //! ## Usage 58 | //! 59 | //! - [`serde`][]: Enable serialization/deserialization via serde 60 | //! 61 | //! [`serde`]: https://github.com/serde-rs/serde 62 | //! 63 | #![cfg_attr(feature = "bench", feature(test))] 64 | #![deny(dead_code)] 65 | #![deny(missing_docs)] 66 | #![forbid(unsafe_code)] 67 | #![warn(unreachable_pub)] 68 | #![doc( 69 | html_favicon_url = "https://raw.githubusercontent.com/sebastienrousseau/vault/main/assets/mini-functions/icons/ico-idk.svg", 70 | html_logo_url = "https://raw.githubusercontent.com/sebastienrousseau/vault/main/assets/mini-functions/icons/ico-idk.svg", 71 | html_root_url = "https://docs.rs/idk" 72 | )] 73 | #![crate_name = "idk"] 74 | #![crate_type = "lib"] 75 | 76 | /// The common module provides common functionality that can be used 77 | /// throughout the entire crate. 78 | pub mod common; 79 | 80 | /// The error module contains all the error types used in the crate. 81 | pub mod error; 82 | 83 | /// The jwt module provides functionality to encode and decode 84 | /// JSON Web Tokens (JWT). 85 | pub mod jwt; 86 | 87 | /// The property module provides functionality to create and manage 88 | /// properties. 89 | pub mod property; 90 | 91 | /// The stacktrace module provides functionality to create and manage 92 | /// stacktraces. 93 | pub mod stacktrace; 94 | 95 | /// The traits module provides functionality to create and manage 96 | /// traits. 97 | pub mod traits; 98 | -------------------------------------------------------------------------------- /idk/src/property.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone, Debug, Ord, PartialEq, PartialOrd, Hash)] 2 | /// The property of the error. 3 | pub struct Property { 4 | /// The label of the property. 5 | pub label: String, 6 | /// Whether the property is printable. 7 | pub printable: bool, 8 | } 9 | 10 | impl Eq for Property {} 11 | 12 | impl Property { 13 | /// Creates a new property. 14 | pub fn new(label: &str, printable: bool) -> Property { 15 | Property { 16 | label: label.to_owned(), 17 | printable, 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /idk/src/stacktrace.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | const STACK_TRACE_DEPTH: usize = 128; 4 | 5 | #[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] 6 | /// The program counter of the stack trace. 7 | pub struct StackTrace { 8 | /// The program counter of the stack trace. 9 | pub pc: Vec, 10 | /// The cause stack trace of the stack trace. 11 | pub cause_stack_trace: Option>, 12 | } 13 | 14 | impl StackTrace { 15 | /// Formats the stack trace. 16 | pub fn format_stack_trace(stack_trace: Vec) -> String { 17 | format!( 18 | "Stack trace:\n{}", 19 | stack_trace 20 | .iter() 21 | .map(|elem| format!("\t- {elem}")) 22 | .collect::>() 23 | .join("\n") 24 | ) 25 | } 26 | 27 | /// Creates a new stack trace. 28 | pub fn new() -> StackTrace { 29 | let pc = Vec::with_capacity(STACK_TRACE_DEPTH); 30 | StackTrace { 31 | pc, 32 | cause_stack_trace: Some(Box::new(StackTrace { 33 | pc: Vec::with_capacity(STACK_TRACE_DEPTH), 34 | cause_stack_trace: None, 35 | })), 36 | } 37 | } 38 | } 39 | 40 | impl Default for StackTrace { 41 | fn default() -> Self { 42 | Self::new() 43 | } 44 | } 45 | 46 | impl fmt::Display for StackTrace { 47 | /// The formatted stack trace. 48 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 49 | let stack_trace = self 50 | .pc 51 | .iter() 52 | .map(|&pc| format!("{pc:#x}")) 53 | .collect::>(); 54 | let formatted_stack_trace = StackTrace::format_stack_trace(stack_trace); 55 | 56 | match &self.cause_stack_trace { 57 | Some(cause_stack_trace) => { 58 | write!(f, "{formatted_stack_trace}\n{cause_stack_trace}") 59 | } 60 | None => write!(f, "{formatted_stack_trace}"), 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /idk/src/traits.rs: -------------------------------------------------------------------------------- 1 | use std::sync::atomic::AtomicU64; 2 | 3 | static INTERNAL_ID_COUNTER: AtomicU64 = AtomicU64::new(0); 4 | 5 | #[derive(Debug, Clone, Hash, PartialEq, Eq)] 6 | /// The `Trait` struct with id as a unique identifier and label as a 7 | /// string representation of the trait. 8 | pub struct Trait { 9 | /// The `id` field holds the unique identifier of the trait. 10 | pub id: u64, 11 | /// The `label` field holds the string representation of the trait. 12 | pub label: String, 13 | } 14 | 15 | impl Trait { 16 | /// Creates a new instance of Trait with a unique identifier and the 17 | /// given label string. 18 | pub fn new(label: &str) -> Self { 19 | Trait { 20 | id: INTERNAL_ID_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed), 21 | label: label.to_string(), 22 | } 23 | } 24 | /// A convenient alias to new(). 25 | pub fn register_trait(label: &str) -> Trait { 26 | Trait::new(label) 27 | } 28 | } 29 | /// A struct to manage a collection of Trait instances. 30 | pub struct TraitBuilder { 31 | /// A vector of Trait instances 32 | pub traits: Vec, 33 | } 34 | 35 | impl TraitBuilder { 36 | /// Creates a new instance of TraitBuilder. 37 | pub fn new() -> Self { 38 | TraitBuilder { traits: Vec::new() } 39 | } 40 | /// Adds a new Trait instance with the given label to the collection. 41 | pub fn add_trait(&mut self, label: &str) -> &Trait { 42 | let trait_ = Trait::new(label); 43 | self.traits.push(trait_); 44 | self.traits.last().unwrap() 45 | } 46 | /// Finds and returns the Trait instance with the given label. 47 | pub fn get_trait(&self, label: &str) -> Option<&Trait> { 48 | self.traits.iter().find(|t| t.label == label) 49 | } 50 | /// Deletes the Trait instance with the given label from the 51 | /// collection. 52 | pub fn delete_trait(&mut self, label: &str) -> bool { 53 | let pos = self.traits.iter().position(|t| t.label == label); 54 | if let Some(pos) = pos { 55 | self.traits.remove(pos); 56 | true 57 | } else { 58 | false 59 | } 60 | } 61 | } 62 | 63 | impl Default for TraitBuilder { 64 | /// A default implementation of TraitBuilder, creating a new 65 | /// instance of TraitBuilder. 66 | fn default() -> Self { 67 | Self::new() 68 | } 69 | } 70 | /// A struct to represent the presence of a Trait instance. 71 | pub struct HasTrait { 72 | /// The identifier of the Trait instance. 73 | pub trait_id: u64, 74 | /// Whether the Trait instance is present. 75 | pub has_trait: bool, 76 | /// Whether the Trait instance was added. 77 | pub add_trait: bool, 78 | } 79 | impl HasTrait { 80 | /// Creates a new instance of HasTrait with the given trait_id. 81 | pub fn new(trait_id: u64) -> Self { 82 | HasTrait { 83 | trait_id, 84 | has_trait: false, 85 | add_trait: false, 86 | } 87 | } 88 | /// Returns true if the HasTrait instance has the given Trait key. 89 | pub fn has_trait(&self, key: &Trait) -> bool { 90 | self.trait_id == key.id 91 | } 92 | /// Adds the given Trait key to the HasTrait instance. 93 | pub fn add_trait(&mut self, key: &Trait) { 94 | self.trait_id = key.id; 95 | self.has_trait = true; 96 | self.add_trait = true; 97 | } 98 | /// Removes the given Trait key from the HasTrait instance. 99 | pub fn remove_trait(&mut self, key: &Trait) { 100 | self.trait_id = key.id; 101 | self.has_trait = false; 102 | self.add_trait = false; 103 | } 104 | /// Returns true if the Trait instance was added to the HasTrait 105 | /// instance. 106 | pub fn is_add_trait(&self) -> bool { 107 | self.add_trait 108 | } 109 | /// Returns true if the HasTrait instance has the Trait instance. 110 | pub fn is_has_trait(&self) -> bool { 111 | self.has_trait 112 | } 113 | /// Returns true if the Trait instance was removed from the HasTrait 114 | /// instance. 115 | pub fn is_remove_trait(&self) -> bool { 116 | !self.add_trait 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /idk/tests/common.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | 3 | // TODO: Add more tests to bring the code coverage to 100% 4 | mod tests { 5 | extern crate idk; 6 | use idk::common::{Error, ErrorType}; 7 | 8 | #[test] 9 | fn test_error_type_new() { 10 | let error_type = ErrorType::new("argument"); 11 | assert_eq!(error_type.name, "argument"); 12 | match error_type.error_type { 13 | Error::Argument(s) => assert_eq!(s, "Illegal argument"), 14 | _ => panic!("Unexpected error type"), 15 | } 16 | } 17 | 18 | #[test] 19 | fn test_error_type_new_subtype() { 20 | let error_type = ErrorType::new("illegal_argument"); 21 | let subtype = error_type.new_subtype("subtype"); 22 | assert_eq!(subtype.name, "subtype"); 23 | match subtype.error_type { 24 | Error::Unknown(s) => assert_eq!(s, "Unknown error"), 25 | _ => panic!("Unexpected error type"), 26 | } 27 | } 28 | 29 | #[test] 30 | fn test_error_type_name() { 31 | let error_type = ErrorType::new("illegal_argument"); 32 | assert_eq!(error_type.name, "illegal_argument"); 33 | } 34 | 35 | #[test] 36 | fn test_error_type_error_type() { 37 | let error_type = ErrorType::new("argument"); 38 | match error_type.error_type { 39 | Error::Argument(s) => assert_eq!(s, "Illegal argument"), 40 | _ => panic!("Unexpected error type"), 41 | } 42 | } 43 | 44 | #[test] 45 | fn test_new() { 46 | let err_type = ErrorType { 47 | name: String::from("argument"), 48 | error_type: Error::Argument(String::from("argument")), 49 | }; 50 | let err = Error::new(err_type); 51 | assert_eq!(err, Error::Argument(String::from("Illegal argument"))); 52 | 53 | let err_type = ErrorType { 54 | name: String::from("operation"), 55 | error_type: Error::Operation(String::from("operation")), 56 | }; 57 | let err = Error::new(err_type); 58 | assert_eq!(err, Error::Operation(String::from("Unsupported operation"))); 59 | 60 | let err_type = ErrorType { 61 | name: String::from("unknown_error"), 62 | error_type: Error::Unknown(String::from("unknown_error")), 63 | }; 64 | let err = Error::new(err_type); 65 | assert_eq!(err, Error::Unknown(String::from("Unknown error"))); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /idk/tests/error.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | 3 | // TODO: Add more tests to bring the code coverage to 100% 4 | mod tests { 5 | extern crate idk; 6 | use idk::{common::ErrorType, error::Error as OtherError}; 7 | use std::error::Error as StdError; 8 | 9 | #[test] 10 | fn test_error_new() { 11 | let error_type = ErrorType::new("illegal_argument"); 12 | let err = OtherError::new("message", error_type); 13 | assert_eq!(err.message, "message"); 14 | assert_eq!(err.error_type.name, "illegal_argument"); 15 | } 16 | #[test] 17 | fn test_with_context() { 18 | let error_type = ErrorType::new("test_error"); 19 | let err = 20 | OtherError::with_context(OtherError::new("message", error_type), "Additional context"); 21 | assert_eq!(err.message, "message"); 22 | assert_eq!(err.error_type.name, "test_error"); 23 | assert_eq!(err.ctx, "Additional context"); 24 | } 25 | 26 | #[test] 27 | fn test_source() { 28 | let error_type = ErrorType::new("test_error"); 29 | let err = OtherError::new("message", error_type); 30 | assert!(StdError::source(&err).is_none()); 31 | } 32 | 33 | #[test] 34 | fn test_display() { 35 | let err = OtherError::new("Test error", ErrorType::new("test_error")); 36 | let display = format!("{err}"); 37 | assert_eq!(display, "Test error, ctx: "); 38 | } 39 | 40 | #[test] 41 | fn test_display_error_type() { 42 | let err_type = ErrorType::new("test_error_type"); 43 | let display = format!("{err_type}"); 44 | assert_eq!(display, "test_error_type"); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /idk/tests/jwt.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | 3 | // TODO: Add more tests to bring the code coverage to 100% 4 | mod tests { 5 | extern crate idk; 6 | use idk::jwt::JwtError; 7 | 8 | #[test] 9 | fn test_jwt_error() { 10 | let jwt_error = JwtError::JWTInvalid("JWT is invalid".to_string()); 11 | assert!(jwt_error.is_jwt_error()); 12 | assert!(!jwt_error.is_signature_error()); 13 | assert!(!jwt_error.is_issuer_error()); 14 | assert!(!jwt_error.is_expiration_error()); 15 | assert!(!jwt_error.is_audience_error()); 16 | } 17 | #[test] 18 | fn test_jwt_display() { 19 | let jwt_audience_error = JwtError::AudienceInvalid("Audience is invalid".to_string()); 20 | assert!(jwt_audience_error 21 | .to_string() 22 | .contains("Audience is invalid")); 23 | 24 | let jwt_expiration_invalid = 25 | JwtError::ExpirationInvalid("Expiration is invalid".to_string()); 26 | assert!(jwt_expiration_invalid 27 | .to_string() 28 | .contains("Expiration is invalid")); 29 | 30 | let jwt_error = JwtError::default(); 31 | assert_eq!(jwt_error.to_string(), "Unknown error"); 32 | } 33 | #[test] 34 | fn test_signature_error() { 35 | let jwt_error = JwtError::SignatureInvalid("Signature is invalid".to_string()); 36 | assert!(!jwt_error.is_jwt_error()); 37 | assert!(jwt_error.is_signature_error()); 38 | assert!(!jwt_error.is_issuer_error()); 39 | assert!(!jwt_error.is_expiration_error()); 40 | assert!(!jwt_error.is_audience_error()); 41 | assert!(!jwt_error.is_format_error()); 42 | assert!(!jwt_error.is_invalid_length_error()); 43 | assert!(!jwt_error.is_io_error()); 44 | assert!(!jwt_error.is_openssl_error()); 45 | assert!(!jwt_error.is_protocol_error()); 46 | assert!(!jwt_error.is_token_not_found_error()); 47 | assert!(!jwt_error.is_base64_error()); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /idk/tests/property.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | 3 | mod tests { 4 | extern crate idk; 5 | use idk::property::Property; 6 | 7 | #[test] 8 | fn test_property_error() { 9 | let err = Property::new("test", true); 10 | assert_eq!(err.label, "test"); 11 | assert!(err.printable); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /idk/tests/stacktrace.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | 3 | // TODO: Add more tests to bring the code coverage to 100% 4 | mod tests { 5 | extern crate idk; 6 | use idk::stacktrace::StackTrace; 7 | 8 | #[test] 9 | fn test_stack_trace_new() { 10 | let stack_trace = StackTrace::new(); 11 | assert_eq!(stack_trace.pc.len(), 0); 12 | } 13 | 14 | #[test] 15 | fn test_format_stack_trace_default() { 16 | let stack_trace = StackTrace::default(); 17 | assert_eq!(stack_trace.pc.len(), 0); 18 | } 19 | 20 | #[test] 21 | fn test_display_stack_trace() { 22 | let test_display_stack_trace = StackTrace::new(); 23 | assert!(!test_display_stack_trace.to_string().is_empty()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /idk/tests/traits.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | 3 | // TODO: Add more tests to bring the code coverage to 100% 4 | mod tests { 5 | extern crate idk; 6 | use idk::traits::{HasTrait, Trait, TraitBuilder}; 7 | 8 | #[test] 9 | fn test_trait_new() { 10 | let trait_test = Trait::new("test"); 11 | assert_eq!(trait_test.label, "test"); 12 | } 13 | 14 | #[test] 15 | fn register_trait() { 16 | let trait_test = Trait::new("test"); 17 | assert_eq!(trait_test.label, "test"); 18 | Trait::register_trait("test"); 19 | } 20 | 21 | #[test] 22 | fn test_traits_builder() { 23 | let mut trait_builder = TraitBuilder::new(); 24 | trait_builder.add_trait("test"); 25 | assert_eq!(trait_builder.traits[0].label, "test"); 26 | trait_builder.delete_trait("test"); 27 | assert_eq!(trait_builder.traits.len(), 0); 28 | } 29 | 30 | #[test] 31 | fn test_trait_new_builder() { 32 | let mut trait_builder = TraitBuilder::new(); 33 | trait_builder.add_trait("test"); 34 | assert_eq!(trait_builder.traits[0].label, "test"); 35 | } 36 | 37 | #[test] 38 | fn test_get_trait() { 39 | let mut trait_builder = TraitBuilder::new(); 40 | trait_builder.add_trait("test"); 41 | assert_eq!(trait_builder.traits[0].label, "test"); 42 | let trait_test = trait_builder.get_trait("test"); 43 | assert_eq!(trait_test.unwrap().label, "test"); 44 | } 45 | 46 | #[test] 47 | fn test_has_trait() { 48 | let mut trait_builder = TraitBuilder::new(); 49 | trait_builder.add_trait("test"); 50 | assert_eq!(trait_builder.traits[0].label, "test"); 51 | let trait_test = trait_builder.get_trait("test"); 52 | assert_eq!(trait_test.unwrap().label, "test"); 53 | let has_trait = HasTrait::new(trait_test.unwrap().id); 54 | assert!(has_trait.has_trait(trait_test.unwrap())); 55 | } 56 | #[test] 57 | fn test_add_trait() { 58 | let mut trait_builder = TraitBuilder::new(); 59 | trait_builder.add_trait("test"); 60 | assert_eq!(trait_builder.traits[0].label, "test"); 61 | let trait_test = trait_builder.get_trait("test"); 62 | assert_eq!(trait_test.unwrap().label, "test"); 63 | let mut has_trait = HasTrait::new(trait_test.unwrap().id); 64 | assert!(has_trait.has_trait(trait_test.unwrap())); 65 | has_trait.add_trait(trait_test.unwrap()); 66 | assert!(has_trait.add_trait); 67 | } 68 | #[test] 69 | fn test_remove_trait() { 70 | let mut trait_builder = TraitBuilder::new(); 71 | trait_builder.add_trait("test"); 72 | assert_eq!(trait_builder.traits[0].label, "test"); 73 | let trait_test = trait_builder.get_trait("test"); 74 | assert_eq!(trait_test.unwrap().label, "test"); 75 | let mut has_trait = HasTrait::new(trait_test.unwrap().id); 76 | assert!(has_trait.has_trait(trait_test.unwrap())); 77 | has_trait.remove_trait(trait_test.unwrap()); 78 | } 79 | #[test] 80 | fn test_is_add_trait() { 81 | let mut trait_builder = TraitBuilder::new(); 82 | trait_builder.add_trait("test"); 83 | assert_eq!(trait_builder.traits[0].label, "test"); 84 | let trait_test = trait_builder.get_trait("test"); 85 | assert_eq!(trait_test.unwrap().label, "test"); 86 | let mut has_trait = HasTrait::new(trait_test.unwrap().id); 87 | assert!(has_trait.has_trait(trait_test.unwrap())); 88 | has_trait.add_trait(trait_test.unwrap()); 89 | assert!(has_trait.is_add_trait()); 90 | } 91 | #[test] 92 | fn test_is_has_trait() { 93 | let mut trait_builder = TraitBuilder::new(); 94 | trait_builder.add_trait("test"); 95 | assert_eq!(trait_builder.traits[0].label, "test"); 96 | let trait_test = trait_builder.get_trait("test"); 97 | assert_eq!(trait_test.unwrap().label, "test"); 98 | let mut has_trait = HasTrait::new(trait_test.unwrap().id); 99 | assert!(has_trait.has_trait(trait_test.unwrap())); 100 | has_trait.add_trait(trait_test.unwrap()); 101 | assert!(has_trait.is_has_trait()); 102 | } 103 | #[test] 104 | fn is_remove_trait() { 105 | let mut trait_builder = TraitBuilder::new(); 106 | trait_builder.add_trait("test"); 107 | assert_eq!(trait_builder.traits[0].label, "test"); 108 | let trait_test = trait_builder.get_trait("test"); 109 | assert_eq!(trait_test.unwrap().label, "test"); 110 | let mut has_trait = HasTrait::new(trait_test.unwrap().id); 111 | assert!(has_trait.has_trait(trait_test.unwrap())); 112 | has_trait.remove_trait(trait_test.unwrap()); 113 | assert!(has_trait.is_remove_trait()); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /mdg/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Sebastian Rousseau 18 |
19 | 20 | **[Website][0] 21 | • [Documentation][9] 22 | • [Report Bug][3] 23 | • [Request Feature][3] 24 | • [Contributing Guidelines][4]** 25 | 26 |
27 | 28 | 29 | 30 | ## Overview 📖 31 | 32 | The Message Digest (MDG) is an implementation of the MD5 cryptographic 33 | hash function. It provides a struct, MD5, that can generate a message 34 | digest of data in a secure, one-way hash. The message digest can verify 35 | the integrity of the data without having to store the entire message. 36 | 37 | ## Features ✨ 38 | 39 | The MD5 struct has a variety of functions to make it easy to use. The 40 | new function creates a new instance of the struct, ready to hash data. 41 | The transform function updates the struct 's internal state with new 42 | data, and the finalize function finishes the message digest and returns 43 | it. 44 | 45 | - An MD5 struct that represents the current state of the hash 46 | computation. 47 | - A `new()` method to create a new instance of the struct. 48 | - A `transform()` method to update the internal state with new data. 49 | - A `finalize()` method to finalize the hash computation and return the 50 | result as a 16-byte array. 51 | 52 | ## Installation 📦 53 | 54 | It takes just a few minutes to get up and running with `mdg`. 55 | 56 | ### Requirements 57 | 58 | `mdg` requires Rust **1.67.0** or later. 59 | 60 | ### Documentation 61 | 62 | > ℹ️ **Info:** Please check out our [website][0] for more information 63 | and find our documentation on [docs.rs][9], [lib.rs][10] and 64 | [crates.io][8]. 65 | 66 | ## Usage 📖 67 | 68 | To use `mdg` in your project, add the following to your 69 | `Cargo.toml` file: 70 | 71 | ```toml 72 | [dependencies] 73 | mdg = "0.0.1" 74 | ``` 75 | 76 | Add the following to your `main.rs` file: 77 | 78 | ```rust 79 | extern crate mdg; 80 | use mdg::*; 81 | ``` 82 | 83 | then you can use the functions in your application code. 84 | 85 | ### Examples 86 | 87 | `MDG` comes with a set of examples that you can use to get started. The 88 | examples are located in the `examples` directory of the project. To run 89 | the examples, clone the repository and run the following command in your 90 | terminal from the project root directory. 91 | 92 | ```shell 93 | cargo run --example mdg 94 | ``` 95 | 96 | ## Semantic Versioning Policy 🚥 97 | 98 | For transparency into our release cycle and in striving to maintain 99 | backward compatibility, `QRC` follows [semantic versioning][7]. 100 | 101 | ## License 📝 102 | 103 | The project is licensed under the terms of both the MIT license and the 104 | Apache License (Version 2.0). 105 | 106 | - [Apache License, Version 2.0][1] 107 | - [MIT license][2] 108 | 109 | ## Contribution 🤝 110 | 111 | Unless you explicitly state otherwise, any contribution intentionally 112 | submitted for inclusion in the work by you, as defined in the Apache-2.0 113 | license, shall be dual licensed as above, without any additional terms 114 | or conditions. 115 | 116 | ![divider][divider] 117 | 118 | ## Acknowledgements 💙 119 | 120 | A big thank you to all the awesome contributors of [Mini Functions][6] 121 | for their help and support. A special thank you goes to the 122 | [Rust Reddit](https://www.reddit.com/r/rust/) community for providing a 123 | lot of useful suggestions on how to improve this project. 124 | 125 | [0]: https://minifunctions.com 126 | [1]: http://www.apache.org/licenses/LICENSE-2.0 127 | [2]: http://opensource.org/licenses/MIT 128 | [3]: https://github.com/sebastienrousseau/mini-functions/issues 129 | [4]: https://raw.githubusercontent.com/sebastienrousseau/mini-functions/main/.github/CONTRIBUTING.md 130 | [6]: https://github.com/sebastienrousseau/mini-functions/graphs/contributors 131 | [7]: http://semver.org/ 132 | [8]: https://crates.io/crates/mdg 133 | [9]: https://docs.rs/mdg 134 | [10]: https://lib.rs/crates/mdg 135 | 136 | [banner]: https://raw.githubusercontent.com/sebastienrousseau/vault/main/assets/mini-functions/banners/banner-mdg-1597x377.svg "MDG Banner" 137 | [crates-badge]: https://img.shields.io/crates/v/mdg.svg?style=for-the-badge 'Crates.io' 138 | [divider]: https://raw.githubusercontent.com/sebastienrousseau/vault/main/assets/elements/divider.svg "divider" 139 | [docs-badge]: https://img.shields.io/docsrs/mdg.svg?style=for-the-badge 'Docs.rs' 140 | [libs-badge]: https://img.shields.io/badge/lib.rs-v0.0.1-orange.svg?style=for-the-badge 'Lib.rs' 141 | [license-badge]: https://img.shields.io/crates/l/mdg.svg?style=for-the-badge 'License' 142 | [made-with-rust]: https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust 'Made With Rust' 143 | -------------------------------------------------------------------------------- /mdg/benches/mdg.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 | extern crate mdg; 3 | use mdg::*; 4 | 5 | pub const BLOCK_LENGTH: usize = 64; 6 | 7 | fn finalize_benchmark(c: &mut Criterion) { 8 | c.bench_function("finalize", |b| { 9 | let mut mdg = MD5::new(); 10 | let data = vec![0u8; BLOCK_LENGTH]; 11 | mdg.update(&data); 12 | 13 | b.iter(|| { 14 | mdg.finalize(); 15 | // mdg.digest; 16 | }); 17 | }); 18 | } 19 | 20 | fn new_benchmark(c: &mut Criterion) { 21 | c.bench_function("new", |b| { 22 | b.iter(|| MD5::new); 23 | }); 24 | } 25 | 26 | fn transform_benchmark(c: &mut Criterion) { 27 | let mut mdg = MD5::new(); 28 | let data = vec![0u8; BLOCK_LENGTH]; 29 | 30 | c.bench_function("transform", |b| { 31 | b.iter(|| { 32 | mdg.transform(black_box(&data)); 33 | }); 34 | }); 35 | } 36 | 37 | fn update_with_len_benchmark(c: &mut Criterion) { 38 | let mut mdg = MD5::new(); 39 | let data = vec![0u8; BLOCK_LENGTH]; 40 | let nbytes = Some(BLOCK_LENGTH); 41 | 42 | c.bench_function("update_with_len", |b| { 43 | b.iter(|| { 44 | // mdg.update_with_len(black_box(&data), black_box(nbytes)); 45 | mdg.update_with_len(black_box(&data), black_box(nbytes.unwrap_or(BLOCK_LENGTH))); 46 | }); 47 | }); 48 | } 49 | 50 | fn reset_benchmark(c: &mut Criterion) { 51 | let mut mdg = MD5::new(); 52 | 53 | c.bench_function("reset", |b| { 54 | b.iter(|| { 55 | mdg.reset(); 56 | }); 57 | }); 58 | } 59 | 60 | fn update_benchmark(c: &mut Criterion) { 61 | let mut mdg = MD5::new(); 62 | let data = vec![0u8; BLOCK_LENGTH]; 63 | 64 | c.bench_function("update", |b| { 65 | b.iter(|| { 66 | mdg.update(black_box(&data)); 67 | }); 68 | }); 69 | } 70 | 71 | fn update_file_benchmark(c: &mut Criterion) { 72 | let mut mdg = MD5::new(); 73 | let path = "file.txt"; 74 | 75 | c.bench_function("update_file", |b| { 76 | b.iter(|| { 77 | mdg.update_file(black_box(path)); 78 | }); 79 | }); 80 | } 81 | 82 | fn hexdigest_benchmark(c: &mut Criterion) { 83 | let data = vec![0u8; BLOCK_LENGTH]; 84 | 85 | c.bench_function("hexdigest", |b| { 86 | b.iter(|| { 87 | let data_str = String::from_utf8(data.to_vec()).unwrap(); 88 | MD5::hexdigest(black_box(&data_str)); 89 | }); 90 | }); 91 | } 92 | 93 | fn hexdigest_file_benchmark(c: &mut Criterion) { 94 | let path = "file.txt"; 95 | 96 | c.bench_function("hexdigest_file", |b| { 97 | b.iter(|| { 98 | MD5::hexdigest_file(black_box(path)); 99 | }); 100 | }); 101 | } 102 | 103 | fn reset_file_benchmark(c: &mut Criterion) { 104 | let mut mdg = MD5::new(); 105 | let path = "file.txt"; 106 | 107 | c.bench_function("reset_file", |b| { 108 | b.iter(|| { 109 | mdg.reset_file(black_box(path)); 110 | }); 111 | }); 112 | } 113 | 114 | criterion_group!( 115 | benches, 116 | finalize_benchmark, 117 | hexdigest_benchmark, 118 | hexdigest_file_benchmark, 119 | new_benchmark, 120 | reset_benchmark, 121 | reset_file_benchmark, 122 | transform_benchmark, 123 | update_benchmark, 124 | update_file_benchmark, 125 | update_with_len_benchmark, 126 | ); 127 | criterion_main!(benches); 128 | -------------------------------------------------------------------------------- /mdg/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | // println!("cargo:rerun-if-changed=src/lib.rs"); 3 | // println!("cargo:rerun-if-changed=build.rs"); 4 | } 5 | -------------------------------------------------------------------------------- /mdg/deny.toml: -------------------------------------------------------------------------------- 1 | [licenses] 2 | # The lint level for crates which do not have a detectable license 3 | unlicensed = "deny" 4 | 5 | # List of explicitly allowed licenses 6 | # See https://spdx.org/licenses/ for list of possible licenses 7 | # [possible values: any SPDX 3.7 short identifier (+ optional exception)]. 8 | allow = ["MPL-2.0"] 9 | 10 | # List of explicitly disallowed licenses 11 | # See https://spdx.org/licenses/ for list of possible licenses 12 | # [possible values: any SPDX 3.7 short identifier (+ optional exception)]. 13 | deny = [] 14 | 15 | # The lint level for licenses considered copyleft 16 | copyleft = "deny" 17 | 18 | # Blanket approval or denial for OSI-approved or FSF Free/Libre licenses 19 | # * both - The license will only be approved if it is both OSI-approved *AND* FSF/Free 20 | # * either - The license will be approved if it is either OSI-approved *OR* FSF/Free 21 | # * osi-only - The license will be approved if is OSI-approved *AND NOT* FSF/Free 22 | # * fsf-only - The license will be approved if is FSF/Free *AND NOT* OSI-approved 23 | # * neither - The license will be denied if is FSF/Free *OR* OSI-approved 24 | allow-osi-fsf-free = "either" 25 | 26 | # The confidence threshold for detecting a license from license text. 27 | # The higher the value, the more closely the license text must be to the 28 | # canonical license text of a valid SPDX license file. 29 | # [possible values: any between 0.0 and 1.0]. 30 | confidence-threshold = 0.8 31 | 32 | [bans] 33 | # Lint level for when multiple versions of the same crate are detected 34 | multiple-versions = "warn" 35 | 36 | # The graph highlighting used when creating dotgraphs for crates 37 | # with multiple versions 38 | # * lowest-version - The path to the lowest versioned duplicate is highlighted 39 | # * simplest-path - The path to the version with the fewest edges is highlighted 40 | # * all - Both lowest-version and simplest-path are used 41 | highlight = "all" 42 | 43 | # List of crates that are allowed. Use with care! 44 | allow = [ 45 | ] 46 | 47 | # List of crates to deny 48 | deny = [ 49 | # Each entry the name of a crate and a version range. If version is 50 | # not specified, all versions will be matched. 51 | ] 52 | 53 | # Certain crates/versions that will be skipped when doing duplicate detection. 54 | skip = [ 55 | ] 56 | 57 | # Similarly to `skip` allows you to skip certain crates during duplicate detection, 58 | # unlike skip, it also includes the entire tree of transitive dependencies starting at 59 | # the specified crate, up to a certain depth, which is by default infinite 60 | skip-tree = [ 61 | ] 62 | 63 | 64 | [advisories] 65 | ignore = [ 66 | ] 67 | -------------------------------------------------------------------------------- /mdg/examples/mdg.rs: -------------------------------------------------------------------------------- 1 | extern crate mdg; 2 | use mdg::{Digest, MD5}; 3 | 4 | fn main() { 5 | // Example using MD5::hexdigest() for a string input 6 | let input = "Hello, world!"; 7 | let digest = MD5::hexdigest(input); 8 | println!("🦀 MD5::hexdigest() for a string input: ✅ {digest}",); 9 | // Expected 6cd3556deb0da54bca060b4c39479839 10 | 11 | // Example using MD5::hexdigest() for a byte array input 12 | let input = [72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100, 33]; // "Hello, world!" 13 | let input_str = String::from_utf8(input.to_vec()).unwrap(); 14 | let digest = MD5::hexdigest(&input_str); 15 | println!("🦀 MD5::hexdigest() for a byte array input: ✅ {digest}",); 16 | // Expected 6cd3556deb0da54bca060b4c39479839 17 | 18 | // Example using MD5::hexdigest() for a file input 19 | let digest = MD5::hexdigest_file("mdg/file.txt"); // file.txt contains "Hello, world!" 20 | println!("🦀 MD5::hexdigest_file() for a file input: ✅ {digest}",); 21 | // Expected 6cd3556deb0da54bca060b4c39479839 22 | 23 | // Example using MD5::update() for a byte array input 24 | let mut mdg = MD5::new(); 25 | let input = [ 26 | 67, 111, 117, 99, 111, 117, 44, 32, 108, 101, 32, 109, 111, 110, 100, 101, 33, 27 | ]; // "Coucou, le monde!" 28 | mdg.update(&input); 29 | let digest = mdg.finalize(); 30 | println!("🦀 MD5::update() for a byte array input: ✅ {digest}",); 31 | // Expected 47353a0e5ed2e1e0d57213a39e9bb7c4 32 | 33 | // Example using MD5::update() for a string input 34 | let mut mdg = MD5::new(); 35 | let input = "Coucou, le monde!"; 36 | mdg.update(input.as_bytes()); 37 | let digest = mdg.finalize(); 38 | println!("🦀 MD5::update() for a string input: ✅ {digest}",); 39 | // Expected 47353a0e5ed2e1e0d57213a39e9bb7c4 40 | 41 | // Example using MD5::update() for a file input 42 | let mut mdg = MD5::new(); 43 | println!( 44 | "🦀 MD5::new() is: ✅ {}", 45 | mdg.finalize() 46 | ); 47 | // Expected d41d8cd98f00b204e9800998ecf8427e 48 | mdg.update_file("mdg/update.txt"); // update.txt contains "Coucou, le monde!" 49 | let digest = mdg.finalize(); 50 | println!("🦀 MD5::update_file() is: ✅ {digest}",); 51 | // Expected 7fc3e27776139278c6b8e0b6f096b4fb 52 | 53 | // Example using MD5::reset() for a string input 54 | let mut mdg = MD5::new(); 55 | println!( 56 | "🦀 MD5::new() is: ✅ {}", 57 | mdg.finalize() 58 | ); 59 | // Expected d41d8cd98f00b204e9800998ecf8427e 60 | println!( 61 | "🦀 MD5::reset() for a string input: ✅ {}", 62 | mdg.reset() 63 | ); 64 | // Expected 00000000000000000000000000000000 65 | } 66 | -------------------------------------------------------------------------------- /mdg/file.txt: -------------------------------------------------------------------------------- 1 | test2 -------------------------------------------------------------------------------- /mdg/rustfmt.toml: -------------------------------------------------------------------------------- 1 | # default -------------------------------------------------------------------------------- /mdg/src/constants.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022-2023 Mini Functions. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | // SPDX-License-Identifier: MIT 4 | 5 | /// The block length. 6 | pub const BLOCK_LENGTH: usize = 64; 7 | /// The digest length. 8 | pub const DIGEST_LENGTH: usize = 16; 9 | /// The number of bytes in a word. 10 | pub const INITIAL_STATE: [u32; 4] = [0x6745_2301, 0xefcd_ab89, 0x98ba_dcfe, 0x1032_5476]; 11 | /// The number of bytes in a word. 12 | pub const SHIFTS: [u8; 64] = [ 13 | 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14 | 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 15 | 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 16 | ]; 17 | /// Padding used in the algorithm implementation of MD5. 18 | pub const PADDING: [u8; 64] = [ 19 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21 | 0, 22 | ]; 23 | /// The number of bytes in a word. 24 | pub const T_VALUES: [u32; 64] = [ 25 | 0xd76a_a478, 26 | 0xe8c7_b756, 27 | 0x2420_70db, 28 | 0xc1bd_ceee, 29 | 0xf57c_0faf, 30 | 0x4787_c62a, 31 | 0xa830_4613, 32 | 0xfd46_9501, 33 | 0x6980_98d8, 34 | 0x8b44_f7af, 35 | 0xffff_5bb1, 36 | 0x895c_d7be, 37 | 0x6b90_1122, 38 | 0xfd98_7193, 39 | 0xa679_438e, 40 | 0x49b4_0821, 41 | 0xf61e_2562, 42 | 0xc040_b340, 43 | 0x265e_5a51, 44 | 0xe9b6_c7aa, 45 | 0xd62f_105d, 46 | 0x0244_1453, 47 | 0xd8a1_e681, 48 | 0xe7d3_fbc8, 49 | 0x21e1_cde6, 50 | 0xc337_07d6, 51 | 0xf4d5_0d87, 52 | 0x455a_14ed, 53 | 0xa9e3_e905, 54 | 0xfcef_a3f8, 55 | 0x676f_02d9, 56 | 0x8d2a_4c8a, 57 | 0xfffa_3942, 58 | 0x8771_f681, 59 | 0x6d9d_6122, 60 | 0xfde5_380c, 61 | 0xa4be_ea44, 62 | 0x4bde_cfa9, 63 | 0xf6bb_4b60, 64 | 0xbebf_bc70, 65 | 0x289b_7ec6, 66 | 0xeaa1_27fa, 67 | 0xd4ef_3085, 68 | 0x0488_1d05, 69 | 0xd9d4_d039, 70 | 0xe6db_99e5, 71 | 0x1fa2_7cf8, 72 | 0xc4ac_5665, 73 | 0xf429_2244, 74 | 0x432a_ff97, 75 | 0xab94_23a7, 76 | 0xfc93_a039, 77 | 0x655b_59c3, 78 | 0x8f0c_cc92, 79 | 0xffef_f47d, 80 | 0x8584_5dd1, 81 | 0x6fa8_7e4f, 82 | 0xfe2c_e6e0, 83 | 0xa301_4314, 84 | 0x4e08_11a1, 85 | 0xf753_7e82, 86 | 0xbd3a_f235, 87 | 0x2ad7_d2bb, 88 | 0xeb86_d391, 89 | ]; 90 | -------------------------------------------------------------------------------- /mdg/src/digest.rs: -------------------------------------------------------------------------------- 1 | use crate::{INITIAL_STATE, MD5}; 2 | use std::{fs::File, io::Read}; 3 | 4 | /// The `Digest` trait. 5 | pub trait Digest { 6 | /// reset the internal state of the object 7 | fn reset(&mut self) -> &mut Self; 8 | /// update the internal state of the object with new data 9 | fn update(&mut self, value: &[u8]) -> &mut Self; 10 | /// update the internal state of the object with new data from a file 11 | fn update_file(&mut self, path: &str) -> &mut Self; 12 | /// return the digest value as a string of hexadecimal digits 13 | fn hexdigest(value: &str) -> String; 14 | /// return the digest value as a string of hexadecimal digits from a file 15 | fn hexdigest_file(path: &str) -> String; 16 | /// reset the internal state of the object and update it with new data from a file 17 | fn reset_file(&mut self, path: &str) -> &mut Self; 18 | } 19 | 20 | impl Digest for MD5 { 21 | /// Reset the internal state of the MD5 object. 22 | fn reset(&mut self) -> &mut Self { 23 | self.state = INITIAL_STATE; 24 | self.count.fill(0); 25 | self.buffer.fill(0); 26 | self.digest.fill(0); 27 | 28 | self 29 | } 30 | /// Update the internal state of the MD5 object with new data. 31 | fn update(&mut self, value: &[u8]) -> &mut Self { 32 | self.update_with_len(value, value.len()) 33 | } 34 | /// Update the internal state of the MD5 object with new data from a file. 35 | fn update_file(&mut self, path: &str) -> &mut Self { 36 | let mut file = File::open(path).expect("Couldn't open file"); 37 | let mut buffer = [0; 1024]; 38 | 39 | loop { 40 | let nbytes = file.read(&mut buffer).expect("Couldn't read file"); 41 | if nbytes == 0 { 42 | break; 43 | } 44 | self.update_with_len(&buffer, nbytes); 45 | } 46 | 47 | self 48 | } 49 | /// Return the digest value as a string of hexadecimal digits. 50 | fn hexdigest(value: &str) -> String { 51 | Self::new().update(value.as_bytes()).finalize().to_string() 52 | } 53 | 54 | /// Return the digest value as a string of hexadecimal digits from a file. 55 | fn hexdigest_file(path: &str) -> String { 56 | let mut file = File::open(path).expect("Couldn't open file"); 57 | let mut buffer = [0; 1024]; 58 | let mut mdg = Self::new(); 59 | 60 | loop { 61 | let nbytes = file.read(&mut buffer).expect("Couldn't read file"); 62 | if nbytes == 0 { 63 | break; 64 | } 65 | mdg.update_with_len(&buffer, nbytes); 66 | } 67 | 68 | mdg.finalize().to_string() 69 | } 70 | /// Reset the internal state of the MD5 object and update it with new data from a file. 71 | fn reset_file(&mut self, path: &str) -> &mut Self { 72 | self.reset(); 73 | self.update_file(path) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /mdg/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022-2023 Mini Functions. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | // SPDX-License-Identifier: MIT 4 | //! 5 | //! # A Rust library that implements the MD5 cryptographic hash function 6 | //! 7 | //! [![Rust](https://raw.githubusercontent.com/sebastienrousseau/vault/main/assets/mini-functions/logo/logo-mdg.svg)](https://minifunctions.com) 8 | //! 9 | //!
10 | //! 11 | //! [![Rust](https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust)](https://www.rust-lang.org) 12 | //! [![Crates.io](https://img.shields.io/crates/v/mini-functions.svg?style=for-the-badge&color=success&labelColor=27A006)](https://crates.io/crates/mini-functions) 13 | //! [![Lib.rs](https://img.shields.io/badge/lib.rs-v0.0.10-success.svg?style=for-the-badge&color=8A48FF&labelColor=6F36E4)](https://lib.rs/crates/mini-functions) 14 | //! [![GitHub](https://img.shields.io/badge/github-555555?style=for-the-badge&labelColor=000000&logo=github)](https://github.com/sebastienrousseau/mini-functions) 15 | //! [![License](https://img.shields.io/crates/l/mini-functions.svg?style=for-the-badge&color=007EC6&labelColor=03589B)](http://opensource.org/licenses/MIT) 16 | //! 17 | //!
18 | //! 19 | //! ## Overview 20 | //! 21 | //! The Message Digest (MDG) is an easy way to produces a 128-bit 22 | //! (16-byte) hash value using the MD5 cryptographic hash function. It 23 | //! provides a struct, MD5, that can generate a message digest of data 24 | //! in a secure, one-way hash. The message digest can verify the 25 | //! integrity of the data without having to store the entire message. 26 | //! 27 | //! Several options are available to produce the hash value: 28 | //! 29 | //! - `MD5::default()` - Returns the hash value of an empty string. 30 | //! - `MD5::digest()` - Returns the hash value of a string. 31 | //! - `MD5::finalize()` - Finalize the MD5 object and return the result 32 | //! as a 16-byte array. 33 | //! - `MD5::hexdigest()` - Returns the hash value of a string as a 34 | //! hexadecimal string. 35 | //! - `MD5::new()` - Create a new instance of the MD5 struct. 36 | //! - `MD5::reset()` - Reset the internal state of the MD5 object. 37 | //! - `MD5::to_hex_string()` - Returns the hash value of a string as a 38 | //! hexadecimal string. 39 | //! - `MD5::to_string()` - Returns the hash value of a string as a 40 | //! string. 41 | //! - `MD5::update()` - Update the internal state of the MD5 object 42 | //! with new data. 43 | //! - `MD5::update_file()` - Update the internal state of the MD5 44 | //! object with new data from a file. 45 | //! 46 | //! To use this crate, add `mdg` to your `Cargo.toml`: 47 | //! 48 | //! ```toml 49 | //! [dependencies] 50 | //! mdg = "0.0.1" 51 | //! ``` 52 | //! 53 | //! ## Usage 54 | //! 55 | //! - [`serde`][]: Enable serialization/deserialization via serde 56 | //! 57 | //! # Examples 58 | //! 59 | //! ```no_run 60 | //! use mdg::MD5; 61 | //! 62 | //! let hash = MD5::default(); 63 | //! assert_eq!(hash.to_string(), "d41d8cd98f00b204e9800998ecf8427e"); 64 | //! ``` 65 | //! # Warning 66 | //! 67 | //! This crate is not intended for cryptographic use. MD5 is not a 68 | //! cryptographically secure hashing algorithm and should not be used 69 | //! for applications that require a collision-resistant hash function. 70 | //! 71 | //! MD5 is sensitive to length extension attacks, which alter the hash 72 | //! value if additional data is appended to the input. 73 | //! 74 | //! [`serde`]: https://github.com/serde-rs/serde 75 | //! 76 | #![cfg_attr(feature = "bench", feature(test))] 77 | #![deny(dead_code)] 78 | #![deny(missing_debug_implementations)] 79 | #![deny(missing_docs)] 80 | #![forbid(unsafe_code)] 81 | #![warn(unreachable_pub)] 82 | #![doc( 83 | html_favicon_url = "https://raw.githubusercontent.com/sebastienrousseau/vault/main/assets/mini-functions/icons/ico-mdg.svg", 84 | html_logo_url = "https://raw.githubusercontent.com/sebastienrousseau/vault/main/assets/mini-functions/icons/ico-mdg.svg", 85 | html_root_url = "https://docs.rs/mdg" 86 | )] 87 | #![crate_name = "mdg"] 88 | #![crate_type = "lib"] 89 | 90 | /// Import the `params` module. 91 | mod params; 92 | pub use params::*; 93 | 94 | /// Import the `constants` module. 95 | pub mod constants; 96 | pub use constants::*; 97 | 98 | /// Import the `digest` module. 99 | pub mod digest; 100 | pub use digest::*; 101 | 102 | use std::convert::TryInto; 103 | use std::fmt::Display; 104 | 105 | /// The MD5 struct. 106 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 107 | pub struct MD5 { 108 | /// The buffer. 109 | pub buffer: [u8; BLOCK_LENGTH], 110 | /// The count. 111 | pub count: [u32; 2], 112 | /// The digest. 113 | pub digest: [u8; DIGEST_LENGTH], 114 | /// The state. 115 | pub state: [u32; 4], 116 | } 117 | 118 | impl MD5 { 119 | /// Finalize the MD5 object and return the result as a 16-byte array. 120 | pub fn finalize(&mut self) -> &Self { 121 | // Save the length before padding. 122 | let bits: [u8; 8] = (0..8) 123 | .into_iter() 124 | .map(|i| (self.count[i >> 2] >> ((i & 3) << 3)) as u8) 125 | .collect::>() 126 | .try_into() 127 | .expect("Couldn't transform vec into array"); 128 | 129 | // Pad out to 56 mod 64 130 | let index = (self.count[0] >> 3) & 63; 131 | let pad_len = if index < 56 { 56 - index } else { 120 - index }; 132 | self.update_with_len(&PADDING, pad_len as usize); 133 | 134 | // Append the length 135 | self.update(&bits); 136 | 137 | self.digest = (0..DIGEST_LENGTH) 138 | .into_iter() 139 | .map(|i| (self.state[i >> 2] >> ((i & 3) << 3)) as u8) 140 | .collect::>() 141 | .try_into() 142 | .expect("Couldn't transform vec into array"); 143 | 144 | self 145 | } 146 | /// Create a new instance of the MD5 struct. 147 | pub fn new() -> Self { 148 | Self { 149 | state: INITIAL_STATE, 150 | count: [0, 0], 151 | buffer: [0; BLOCK_LENGTH], 152 | digest: [0; DIGEST_LENGTH], 153 | } 154 | } 155 | /// Update the internal state of the MD5 object with new data. 156 | pub fn transform(&mut self, data: &[u8]) -> &mut Self { 157 | const fn f(x: u32, y: u32, z: u32) -> u32 { 158 | (x & y) | (!x & z) 159 | } 160 | 161 | const fn g(x: u32, y: u32, z: u32) -> u32 { 162 | (x & z) | (y & !z) 163 | } 164 | 165 | const fn h(x: u32, y: u32, z: u32) -> u32 { 166 | x ^ y ^ z 167 | } 168 | 169 | const fn i(x: u32, y: u32, z: u32) -> u32 { 170 | y ^ (x | !z) 171 | } 172 | let (mut a, mut b, mut c, mut d): (u32, u32, u32, u32) = 173 | (self.state[0], self.state[1], self.state[2], self.state[3]); 174 | 175 | for (idx, t_value) in T_VALUES.iter().enumerate() { 176 | let (value, g): (u32, usize) = match idx { 177 | 0..=15 => (f(b, c, d), idx), 178 | 16..=31 => (g(b, c, d), (5 * idx + 1) % DIGEST_LENGTH), 179 | 32..=47 => (h(b, c, d), (3 * idx + 5) % DIGEST_LENGTH), 180 | 48..=63 => (i(b, c, d), (7 * idx) % DIGEST_LENGTH), 181 | _ => unreachable!(), 182 | }; 183 | let part_value = u32::from_ne_bytes( 184 | data[4 * g..4 * g + 4] 185 | .try_into() 186 | .expect("Couldn't transform slice into array"), 187 | ); 188 | let f = value 189 | .wrapping_add(a) 190 | .wrapping_add(*t_value) 191 | .wrapping_add(part_value); 192 | a = d; 193 | d = c; 194 | c = b; 195 | b = b.wrapping_add(f.rotate_left(SHIFTS[idx].into())); 196 | } 197 | self.state[0] = self.state[0].wrapping_add(a); 198 | self.state[1] = self.state[1].wrapping_add(b); 199 | self.state[2] = self.state[2].wrapping_add(c); 200 | self.state[3] = self.state[3].wrapping_add(d); 201 | 202 | self 203 | } 204 | /// Update the internal state of the MD5 object with new data. 205 | pub fn update_with_len(&mut self, value: &[u8], nbytes: usize) -> &mut Self { 206 | // Compute number of bytes mod 64 207 | let mut offset = ((self.count[0] >> 3) & 63) as usize; 208 | let nbits = (nbytes << 3) as u32; 209 | let p = value; 210 | 211 | if nbytes == 0 { 212 | return self; 213 | } 214 | 215 | // Update the number of bits 216 | self.count[0] = self.count[0].wrapping_add(nbits); 217 | if self.count[0] < nbits { 218 | self.count[1] += 1; 219 | } 220 | 221 | self.count[1] += (nbytes >> 29) as u32; 222 | 223 | let part_len = BLOCK_LENGTH - offset; 224 | let mut i = part_len; 225 | 226 | // Transform as many times as possible 227 | if nbytes >= part_len { 228 | self.buffer[offset..(offset + part_len)].clone_from_slice(&p[..part_len]); 229 | let buf = self.buffer; 230 | self.transform(&buf); 231 | 232 | while i < nbytes - part_len { 233 | if nbytes - i >= 64 { 234 | let buf = self.buffer[i..i + part_len].to_vec(); 235 | self.transform(&buf); 236 | i += 64; 237 | } else { 238 | break; 239 | } 240 | } 241 | offset = 0; 242 | } else { 243 | i = 0; 244 | } 245 | 246 | // Add remaining input in buffer 247 | self.buffer[offset..(offset + nbytes - i)].clone_from_slice(&p[i..nbytes]); 248 | self 249 | } 250 | } 251 | 252 | impl Default for MD5 { 253 | /// Create a new instance of the MD5 struct. 254 | fn default() -> Self { 255 | Self::new() 256 | } 257 | } 258 | 259 | impl Display for MD5 { 260 | /// Display the current MD5 value. 261 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 262 | for di in self.digest { 263 | write!(f, "{di:02x}")?; 264 | } 265 | 266 | Ok(()) 267 | } 268 | } 269 | -------------------------------------------------------------------------------- /mdg/src/params.rs: -------------------------------------------------------------------------------- 1 | /// MD5Params 2 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 3 | pub struct MD5Params { 4 | /// A 5 | pub a: u32, 6 | /// B 7 | pub b: u32, 8 | /// C 9 | pub c: u32, 10 | /// D 11 | pub d: u32, 12 | /// X 13 | pub x: u32, 14 | /// S 15 | pub s: u8, 16 | /// AC 17 | pub ac: u32, 18 | } 19 | 20 | impl MD5Params { 21 | /// Create a new instance of the MD5Params struct. 22 | pub fn new(a: u32, b: u32, c: u32, d: u32, x: u32, s: u8, ac: u32) -> Self { 23 | Self { 24 | a, 25 | b, 26 | c, 27 | d, 28 | x, 29 | s, 30 | ac, 31 | } 32 | } 33 | } 34 | /// Rotate left 35 | pub fn f(params: &mut MD5Params) -> u32 { 36 | // let a = params.a; 37 | let b = params.b; 38 | let c = params.c; 39 | let d = params.d; 40 | // let x = params.x; 41 | // let s = params.s; 42 | // let ac = params.ac; 43 | 44 | let res = mdg_f(b, c, d); 45 | 46 | params.a = params 47 | .a 48 | .wrapping_add(res.wrapping_add(params.x.wrapping_add(params.ac))); 49 | params.a = rotate_left(params.a, params.s.into()); 50 | params.a = params.a.wrapping_add(params.b); 51 | 52 | b.wrapping_add(res) 53 | } 54 | /// Rotate left 55 | pub fn g(params: &mut MD5Params) -> u32 { 56 | // let a = params.a; 57 | let b = params.b; 58 | let c = params.c; 59 | let d = params.d; 60 | // let x = params.x; 61 | // let s = params.s; 62 | // let ac = params.ac; 63 | 64 | params.a = params.a.wrapping_add(params.x.wrapping_add(params.ac)); 65 | params.a = params.a.wrapping_add(!d & c); 66 | params.a = params.a.wrapping_add(d & b); 67 | params.a = rotate_left(params.a, params.s.into()); 68 | params.a = params.a.wrapping_add(params.b); 69 | 70 | b.wrapping_add(!d & c) 71 | } 72 | /// Rotate left 73 | pub fn h(params: &mut MD5Params) -> u32 { 74 | // let a = params.a; 75 | let b = params.b; 76 | let c = params.c; 77 | let d = params.d; 78 | // let x = params.x; 79 | // let s = params.s; 80 | // let ac = params.ac; 81 | 82 | params.a = params.a.wrapping_add(params.x.wrapping_add(params.ac)); 83 | params.a = params.a.wrapping_add(b ^ c ^ d); 84 | params.a = rotate_left(params.a, params.s.into()); 85 | params.a = params.a.wrapping_add(params.b); 86 | 87 | b.wrapping_add(b ^ c ^ d) 88 | } 89 | /// Rotate left 90 | pub fn i(params: &mut MD5Params) -> u32 { 91 | // let a = params.a; 92 | let b = params.b; 93 | let c = params.c; 94 | let d = params.d; 95 | // let x = params.x; 96 | // let s = params.s; 97 | // let ac = params.ac; 98 | 99 | params.a = params.a.wrapping_add(params.x.wrapping_add(params.ac)); 100 | params.a = params.a.wrapping_add(c ^ (d | !b)); 101 | params.a = rotate_left(params.a, params.s.into()); 102 | params.a = params.a.wrapping_add(params.b); 103 | 104 | b.wrapping_add(c ^ (d | !b)) 105 | } 106 | #[inline(always)] 107 | /// mdg_f 108 | pub fn mdg_f(x: u32, y: u32, z: u32) -> u32 { 109 | (x & y) | (!x & z) 110 | } 111 | 112 | #[inline(always)] 113 | /// mdg_h 114 | pub fn mdg_h(x: u32, y: u32, z: u32) -> u32 { 115 | x ^ y ^ z 116 | } 117 | /// mdg_i 118 | #[inline(always)] 119 | pub fn mdg_i(x: u32, y: u32, z: u32) -> u32 { 120 | y ^ (x | !z) 121 | } 122 | /// Rotate left 123 | #[inline(always)] 124 | pub fn rotate_left(x: u32, n: u32) -> u32 { 125 | (x << n) | (x >> (32 - n)) 126 | } 127 | -------------------------------------------------------------------------------- /mdg/tests/constants.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests { 3 | extern crate mdg; 4 | use self::mdg::constants::{ 5 | BLOCK_LENGTH, DIGEST_LENGTH, INITIAL_STATE, PADDING, SHIFTS, T_VALUES, 6 | }; 7 | 8 | #[test] 9 | fn test_block_length() { 10 | assert_eq!(BLOCK_LENGTH, 64); 11 | } 12 | 13 | #[test] 14 | fn test_digest_length() { 15 | assert_eq!(DIGEST_LENGTH, 16); 16 | } 17 | 18 | #[test] 19 | fn test_initial_state() { 20 | assert_eq!( 21 | INITIAL_STATE, 22 | [0x6745_2301, 0xefcd_ab89, 0x98ba_dcfe, 0x1032_5476] 23 | ); 24 | } 25 | 26 | #[test] 27 | fn test_shifts() { 28 | assert_eq!( 29 | SHIFTS, 30 | [ 31 | 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 32 | 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 33 | 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 34 | ] 35 | ); 36 | } 37 | 38 | #[test] 39 | fn test_padding() { 40 | assert_eq!( 41 | PADDING, 42 | [ 43 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 46 | ] 47 | ); 48 | } 49 | 50 | #[test] 51 | fn test_t_values() { 52 | assert_eq!( 53 | T_VALUES, 54 | [ 55 | 0xd76a_a478, 56 | 0xe8c7_b756, 57 | 0x2420_70db, 58 | 0xc1bd_ceee, 59 | 0xf57c_0faf, 60 | 0x4787_c62a, 61 | 0xa830_4613, 62 | 0xfd46_9501, 63 | 0x6980_98d8, 64 | 0x8b44_f7af, 65 | 0xffff_5bb1, 66 | 0x895c_d7be, 67 | 0x6b90_1122, 68 | 0xfd98_7193, 69 | 0xa679_438e, 70 | 0x49b4_0821, 71 | 0xf61e_2562, 72 | 0xc040_b340, 73 | 0x265e_5a51, 74 | 0xe9b6_c7aa, 75 | 0xd62f_105d, 76 | 0x0244_1453, 77 | 0xd8a1_e681, 78 | 0xe7d3_fbc8, 79 | 0x21e1_cde6, 80 | 0xc337_07d6, 81 | 0xf4d5_0d87, 82 | 0x455a_14ed, 83 | 0xa9e3_e905, 84 | 0xfcef_a3f8, 85 | 0x676f_02d9, 86 | 0x8d2a_4c8a, 87 | 0xfffa_3942, 88 | 0x8771_f681, 89 | 0x6d9d_6122, 90 | 0xfde5_380c, 91 | 0xa4be_ea44, 92 | 0x4bde_cfa9, 93 | 0xf6bb_4b60, 94 | 0xbebf_bc70, 95 | 0x289b_7ec6, 96 | 0xeaa1_27fa, 97 | 0xd4ef_3085, 98 | 0x0488_1d05, 99 | 0xd9d4_d039, 100 | 0xe6db_99e5, 101 | 0x1fa2_7cf8, 102 | 0xc4ac_5665, 103 | 0xf429_2244, 104 | 0x432a_ff97, 105 | 0xab94_23a7, 106 | 0xfc93_a039, 107 | 0x655b_59c3, 108 | 0x8f0c_cc92, 109 | 0xffef_f47d, 110 | 0x8584_5dd1, 111 | 0x6fa8_7e4f, 112 | 0xfe2c_e6e0, 113 | 0xa301_4314, 114 | 0x4e08_11a1, 115 | 0xf753_7e82, 116 | 0xbd3a_f235, 117 | 0x2ad7_d2bb, 118 | 0xeb86_d391, 119 | ] 120 | ); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /mdg/tests/digest.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | 3 | // TODO: Add more tests to bring the code coverage to 100% 4 | mod tests { 5 | extern crate mdg; 6 | 7 | use mdg::*; 8 | 9 | #[test] 10 | fn test_mdg_reset() { 11 | let mut mdg = MD5::new(); 12 | mdg.update(b"test"); 13 | mdg.reset(); 14 | let digest = mdg::MD5::hexdigest(""); 15 | assert_eq!(digest, "d41d8cd98f00b204e9800998ecf8427e"); 16 | } 17 | 18 | #[test] 19 | fn test_mdg_update() { 20 | let mut mdg = MD5::new(); 21 | mdg.update(b"test"); 22 | let digest = mdg::MD5::hexdigest(""); 23 | assert_eq!(digest, "d41d8cd98f00b204e9800998ecf8427e"); 24 | } 25 | 26 | #[test] 27 | fn test_mdg_hexdigest() { 28 | let mut mdg = MD5::new(); 29 | mdg.update(b"test"); 30 | let digest = mdg::MD5::hexdigest(""); 31 | assert_eq!(digest, "d41d8cd98f00b204e9800998ecf8427e"); 32 | } 33 | #[test] 34 | fn test_reset_file() { 35 | let mut mdg = MD5::new(); 36 | mdg.update(b"test"); 37 | mdg.reset_file("file.txt"); 38 | assert_eq!(mdg::MD5::hexdigest(""), "d41d8cd98f00b204e9800998ecf8427e"); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /mdg/tests/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | 3 | // TODO: Add more tests to bring the code coverage to 100% 4 | mod tests { 5 | extern crate mdg; 6 | use std::cmp; 7 | 8 | use mdg::{Digest, MD5}; 9 | 10 | extern crate cjwt; 11 | use self::cjwt::{Algorithm, JWT}; 12 | 13 | #[test] 14 | fn test_mdg_0() { 15 | let digest = MD5::hexdigest(""); 16 | assert_eq!(digest, "d41d8cd98f00b204e9800998ecf8427e"); 17 | } 18 | 19 | #[test] 20 | fn test_mdg_1() { 21 | let digest = MD5::hexdigest("a"); 22 | assert_eq!(digest, "0cc175b9c0f1b6a831c399e269772661"); 23 | } 24 | 25 | #[test] 26 | fn test_mdg_2() { 27 | let digest = MD5::hexdigest("abc"); 28 | assert_eq!(digest, "900150983cd24fb0d6963f7d28e17f72"); 29 | } 30 | 31 | #[test] 32 | fn test_mdg_3() { 33 | let digest = MD5::hexdigest("message digest"); 34 | assert_eq!(digest, "f96b697d7cb7938d525a2f31aaf161d0"); 35 | } 36 | 37 | #[test] 38 | fn test_mdg_4() { 39 | let digest = MD5::hexdigest("abcdefghijklmnopqrstuvwxyz"); 40 | assert_eq!(digest, "c3fcd3d76192e4007dfb496cca67e13b"); 41 | } 42 | 43 | #[test] 44 | fn test_mdg_5() { 45 | let digest = 46 | MD5::hexdigest("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); 47 | assert_eq!(digest, "d174ab98d277d9f5a5611c2c9f419d9f"); 48 | } 49 | 50 | #[test] 51 | fn test_mdg_6() { 52 | let digest = MD5::hexdigest( 53 | "12345678901234567890123456789012345678901234567890123456789012345678901234567890", 54 | ); 55 | assert_eq!(digest, "57edf4a22be3c955ac49da2e2107b67a"); 56 | } 57 | 58 | #[test] 59 | fn test_update_mdg_many_times() { 60 | let digest = MD5::new() 61 | .update(b"a") 62 | .update(b"b") 63 | .update(b"c") 64 | .finalize() 65 | .to_string(); 66 | assert_eq!(digest, "900150983cd24fb0d6963f7d28e17f72"); 67 | } 68 | 69 | #[test] 70 | fn test_reset() { 71 | let digest = MD5::new().update(b"a").reset().finalize().to_string(); 72 | assert_eq!(digest, "d41d8cd98f00b204e9800998ecf8427e"); 73 | } 74 | 75 | #[test] 76 | fn test_to_string_before_finalize() { 77 | let digest = MD5::new().update(b"a").to_string(); 78 | // Is this acceptable? Or make it an Option that can be None? 79 | assert_eq!(digest, "00000000000000000000000000000000"); 80 | } 81 | 82 | #[test] 83 | fn update_with_len() { 84 | let digest = MD5::new().update_with_len(b"abc", 3).finalize().to_string(); 85 | assert_eq!(digest, "900150983cd24fb0d6963f7d28e17f72"); 86 | } 87 | #[test] 88 | fn update_file() { 89 | let digest = MD5::new().update_file("update.txt").finalize().to_string(); 90 | assert_eq!(digest, "47353a0e5ed2e1e0d57213a39e9bb7c4"); 91 | } 92 | #[test] 93 | fn hexdigest_file() { 94 | let digest = MD5::hexdigest_file("update.txt"); 95 | assert_eq!(digest, "47353a0e5ed2e1e0d57213a39e9bb7c4"); 96 | } 97 | #[test] 98 | fn reset_file() { 99 | let digest = 100 | MD5::new() 101 | .update_file("update.txt") 102 | .reset() 103 | .finalize() 104 | .to_string(); 105 | assert_eq!(digest, "d41d8cd98f00b204e9800998ecf8427e"); 106 | } 107 | #[test] 108 | fn transform() { 109 | let digest = MD5::new().update_file("update.txt").finalize().to_string(); 110 | assert_eq!(digest, "47353a0e5ed2e1e0d57213a39e9bb7c4"); 111 | } 112 | #[test] 113 | fn test_algorithm_to_string() { 114 | let hs256 = Algorithm::HS256; 115 | assert_eq!(hs256.to_string(), "HS256"); 116 | 117 | let rs512 = Algorithm::RS512; 118 | assert_eq!(rs512.to_string(), "RS512"); 119 | } 120 | 121 | #[test] 122 | fn test_default_algorithm() { 123 | let default_alg = Algorithm::default(); 124 | assert_eq!(default_alg, Algorithm::HS256); 125 | } 126 | 127 | #[test] 128 | fn test_default_jwt() { 129 | let default_jwt = JWT::default(); 130 | assert_eq!(default_jwt.header.alg, Some(Algorithm::HS256)); 131 | assert_eq!(default_jwt.token, String::new()); 132 | } 133 | #[test] 134 | fn test_reset_file() { 135 | let mut mdg = MD5::new(); 136 | mdg.finalize(); 137 | mdg.reset(); 138 | assert_eq!(mdg.to_string(), "00000000000000000000000000000000"); 139 | } 140 | #[test] 141 | fn test_default() { 142 | let mut mdg = MD5::default(); 143 | mdg.finalize(); 144 | mdg.reset(); 145 | assert_eq!(mdg.to_string(), "00000000000000000000000000000000"); 146 | } 147 | 148 | #[test] 149 | fn test_update_with_len() { 150 | let mut md5 = MD5::new(); 151 | let data = b"test data"; 152 | let nbytes = data.len(); 153 | 154 | // Test updating with non-empty data 155 | md5.update_with_len(data, nbytes); 156 | assert_eq!(md5.count, [72, 0]); 157 | assert_eq!(md5.buffer[0..nbytes], data[..]); 158 | // Check the state of the md5 after the update 159 | let state = md5.state; 160 | assert_ne!(state, [0; 4]); 161 | md5.reset(); 162 | 163 | // Test updating with empty data 164 | md5.update_with_len(b"", 0); 165 | assert_eq!(md5.count, [0, 0]); 166 | // Check the state of the md5 after the update 167 | let state = md5.state; 168 | assert_ne!(state, [0; 4]); 169 | md5.reset(); 170 | 171 | // Test updating with data that is smaller than part_len 172 | let data = b"test"; 173 | let nbytes = data.len(); 174 | md5.update_with_len(data, nbytes); 175 | assert_eq!(md5.count, [32, 0]); 176 | assert_eq!(md5.buffer[0..nbytes], data[..]); 177 | // Check the state of the md5 after the update 178 | let state = md5.state; 179 | assert_ne!(state, [0; 4]); 180 | md5.reset(); 181 | 182 | // Test updating with data that is larger than part_len 183 | let data = b"test data test data test data"; 184 | let nbytes = data.len(); 185 | md5.update_with_len(data, nbytes); 186 | assert_eq!(md5.count, [232, 0]); 187 | // Check the state of the md5 after the update 188 | let state = md5.state; 189 | assert_ne!(state, [0; 4]); 190 | md5.reset(); 191 | 192 | // Test updating with data that results in overflow of count[0] 193 | let data = b"test data"; 194 | let nbytes = data.len(); 195 | md5.count[0] = u32::max_value(); 196 | md5.update_with_len(data, nbytes); 197 | assert_eq!(md5.count, [71, 1]); 198 | // Check the state of the md5 after the update 199 | let state = md5.state; 200 | assert_ne!(state, [0; 4]); 201 | md5.reset(); 202 | } 203 | #[test] 204 | fn test_update_with_len_large_data() { 205 | let mut md5 = MD5::new(); 206 | let data = vec![1; 128]; 207 | let nbytes = data.len(); 208 | 209 | md5.update_with_len(&data, nbytes); 210 | assert_eq!(md5.count, [1024, 0]); 211 | 212 | let buffer_len = cmp::min(md5.buffer.len(), nbytes); 213 | assert_eq!(md5.buffer[0..buffer_len], data[..buffer_len]); 214 | 215 | let buf = md5.buffer[0..buffer_len].to_vec(); 216 | md5.transform(&buf); 217 | assert!(buffer_len >= 64); 218 | assert_eq!(md5.count, [1024, 0]); 219 | 220 | let state = md5.state; 221 | assert_ne!(state, [0; 4]); 222 | md5.reset(); 223 | 224 | // Check the state of the md5 after each iteration of the while loop 225 | let state1 = md5.state; 226 | assert_ne!(state1, [0; 4]); 227 | 228 | let state2 = md5.state; 229 | assert_ne!(state2, [0; 4]); 230 | assert_eq!(state1, state2); 231 | 232 | md5.reset(); 233 | } 234 | #[test] 235 | fn test_transform_with_sufficient_buffer_length() { 236 | const NBYTES: usize = 1024; 237 | 238 | let mut md5 = MD5::new(); 239 | md5.count = [NBYTES as u32, 0]; 240 | let buffer = (0..NBYTES).map(|i| i as u8).collect::>(); 241 | 242 | let mut i = 0; 243 | while i < NBYTES { 244 | if NBYTES - i >= 64 { 245 | let buf = &buffer[i..(i + 64)].to_vec(); 246 | md5.transform(buf); 247 | i += 64; 248 | } else { 249 | let part_len = NBYTES - i; 250 | let buf = &buffer[i..(i + part_len)].to_vec(); 251 | md5.transform(buf); 252 | i += part_len; 253 | } 254 | } 255 | 256 | assert_eq!(i, NBYTES); 257 | assert_eq!(md5.count, [1024, 0]); 258 | } 259 | #[test] 260 | fn test_transform_with_insufficient_buffer_length() { 261 | const NBYTES: usize = 1024; 262 | let mut md5 = MD5::new(); 263 | md5.count = [NBYTES as u32, 0]; 264 | let buffer = (0..NBYTES).map(|i| i as u8).collect::>(); 265 | 266 | let mut i = 0; 267 | while i < NBYTES { 268 | if NBYTES - i >= 64 { 269 | let buf = &buffer[i..(i + 64)].to_vec(); 270 | md5.transform(buf); 271 | i += 64; 272 | } else { 273 | let part_len = NBYTES - i; 274 | let buf = &buffer[i..(i + part_len)].to_vec(); 275 | md5.transform(buf); 276 | i += part_len; 277 | } 278 | } 279 | assert_eq!(i, NBYTES); 280 | assert_eq!(md5.count, [1024, 0]); 281 | md5.reset(); 282 | } 283 | 284 | // #[test] 285 | // fn test_transform_with_insufficient_buffer_length() { 286 | // const NBYTES: usize = 63; 287 | 288 | // let mut md5 = MD5::new(); 289 | // md5.count = [NBYTES as u32, 0]; 290 | // let buffer = (0..NBYTES).map(|i| i as u8).collect::>(); 291 | 292 | // let mut i = 0; 293 | // let part_len = NBYTES - i; 294 | // while i < NBYTES { 295 | // if NBYTES >= part_len { 296 | // let buf = &buffer[i..(i + 64)].to_vec(); 297 | // md5.transform(buf); 298 | 299 | // while i < NBYTES - part_len { 300 | // if NBYTES - i >= 64 { 301 | // let buf = md5.buffer[i..i + 64].to_vec(); 302 | // md5.transform(&buf); 303 | // i += 64; 304 | // } else { 305 | // let buf = md5.buffer[i..NBYTES].to_vec(); 306 | // md5.transform(&buf); 307 | // break; 308 | // } 309 | // } 310 | // } 311 | // } 312 | 313 | // assert_eq!(i, NBYTES); 314 | // assert_eq!(md5.count, [63, 0]); 315 | // } 316 | } 317 | -------------------------------------------------------------------------------- /mdg/tests/params.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | 3 | // TODO: Add more tests to bring the code coverage to 100% 4 | mod tests { 5 | extern crate mdg; 6 | use mdg::*; 7 | 8 | #[test] 9 | fn test_mdg_params_new() { 10 | let params = MD5Params::new(0, 1, 2, 3, 4, 5, 6); 11 | assert_eq!(params.a, 0); 12 | assert_eq!(params.b, 1); 13 | assert_eq!(params.c, 2); 14 | assert_eq!(params.d, 3); 15 | assert_eq!(params.x, 4); 16 | assert_eq!(params.s, 5); 17 | } 18 | 19 | #[test] 20 | fn test_f() { 21 | let mut params: MD5Params = MD5Params::new(0, 1, 2, 3, 4, 5, 6); 22 | assert_eq!(f(&mut params), ((!1 & 3) + 1)); 23 | } 24 | 25 | #[test] 26 | fn test_g() { 27 | let mut params = MD5Params::new(0, 1, 2, 3, 4, 5, 6); 28 | assert_eq!(g(&mut params), 1 & 3); 29 | } 30 | 31 | #[test] 32 | fn test_h() { 33 | let mut params = MD5Params::new(0, 1, 2, 3, 4, 5, 6); 34 | assert_eq!(h(&mut params), 1 ^ 2 ^ (3 - 1)); 35 | } 36 | 37 | #[test] 38 | fn test_i() { 39 | let mut params = MD5Params::new(0, 1, 2, 3, 4, 5, 6); 40 | assert_eq!(i(&mut params), 2 ^ ((1 | !3) - 1)); 41 | } 42 | #[test] 43 | fn test_mdg_f() { 44 | assert_eq!(mdg_f(1, 2, 3), (!1 & 3)); 45 | } 46 | 47 | #[test] 48 | fn test_mdg_h() { 49 | assert_eq!(mdg_h(1, 2, 3), 1 ^ 2 ^ 3); 50 | } 51 | 52 | #[test] 53 | fn test_mdg_i() { 54 | assert_eq!(mdg_i(1, 2, 3), 2 ^ (1 | !3)); 55 | } 56 | 57 | #[test] 58 | fn test_rotate_left() { 59 | assert_eq!(rotate_left(0b1010, 2), 0b101000); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /mdg/update.txt: -------------------------------------------------------------------------------- 1 | Coucou, le monde! -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width = 72 -------------------------------------------------------------------------------- /src/claims.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Mini Functions library. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! Application JSON Web Token (JWT) claims functionality 5 | //! 6 | //! Provides access to JWT claims functions and types. 7 | 8 | /// Re-exported [`Claims`] struct from cclm for accessing JWT claims. 9 | pub use cclm::Claims; 10 | -------------------------------------------------------------------------------- /src/common.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Mini Functions library. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! Application Common mathematical constants functionality 5 | //! 6 | //! Provides access to functions for accessing a collection of mathematical and cryptographic constants. 7 | 8 | /// Re-exported [`Common`] type from cmn providing access to common constants. 9 | pub use cmn::Common; 10 | 11 | /// Re-exported [`Constants`] struct from cmn providing math/crypto constants. 12 | pub use cmn::Constants; 13 | 14 | /// Re-exported [`Words`] struct from cmn with common words list. 15 | pub use cmn::Words; 16 | 17 | /// Re-exported [`run()`] function from cmn. 18 | pub use cmn::run; 19 | 20 | /// Re-exported macros from cmn providing access to common macros. 21 | pub use cmn::macros as cmn_macros; 22 | -------------------------------------------------------------------------------- /src/date.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Mini Functions library. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! Application date/time functionality 5 | //! 6 | //! Provides access to date/time functions and types. 7 | 8 | /// Re-exported main [`DateTime`] type from dtt for date/time handling. 9 | pub use dtt::DateTime; 10 | 11 | /// Re-exported [`run()`] function from dtt. 12 | pub use dtt::run; 13 | 14 | /// Re-exported [`dtt_macros`] module from dtt. 15 | pub use dtt::macros as dtt_macros; 16 | -------------------------------------------------------------------------------- /src/errors.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Mini Functions library. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! Application Error handling functionality 5 | //! 6 | //! Provides access to error handling functions and types. 7 | 8 | /// Re-exported main [`idk`] module from idk for error handling. 9 | pub use idk::*; 10 | -------------------------------------------------------------------------------- /src/hash.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Mini Functions library. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! Application hash functionality 5 | //! 6 | //! Provides access to hash functions and types. 7 | 8 | pub use hsh::macros as hsh_macros; 9 | pub use hsh::*; 10 | -------------------------------------------------------------------------------- /src/jwt.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Mini Functions library. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! Application JSON Web Token (JWT) functionality 5 | //! 6 | //! Provides access to JSON Web Token (JWT) functions. 7 | 8 | pub use cjwt::*; 9 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2022-2023 Mini Functions. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 3 | // SPDX-License-Identifier: MIT 4 | //! 5 | //! # `Mini Functions` 🦀 6 | //! 7 | //! [![Mini Functions Logo][01]][00] 8 | //! 9 | //! ## A Highly Performant Utility and Wrapper Functions Library for Rust 10 | //! 11 | //! Elevate your Rust development with this comprehensive library of functions and utilities designed to streamline common tasks, enhance performance, and promote maintainability across various aspects of Rust application development. 12 | //! 13 | //!
14 | //! 15 | //! [![GitHub](https://img.shields.io/badge/github-555555?style=for-the-badge&labelColor=000000&logo=github)](https://github.com/sebastienrousseau/mini-functions) 16 | //! [![Rust](https://img.shields.io/badge/rust-f04041?style=for-the-badge&labelColor=c0282d&logo=rust)](https://www.rust-lang.org) 17 | //! [![Crates.io](https://img.shields.io/crates/v/mini-functions.svg?style=for-the-badge&color=success&labelColor=27A006)](https://crates.io/crates/mini-functions) 18 | //! [![Lib.rs](https://img.shields.io/badge/lib.rs-v0.0.10-success.svg?style=for-the-badge&color=8A48FF&labelColor=6F36E4)](https://lib.rs/crates/mini-functions) 19 | //! [![License](https://img.shields.io/crates/l/mini-functions.svg?style=for-the-badge&color=007EC6&labelColor=03589B)](http://opensource.org/licenses/MIT) 20 | //! 21 | //!
22 | //! 23 | //! ## Overview 24 | //! 25 | //! Mini-Functions is a modern Rust library that prioritizes performance, security, and modularity. It provides a low-overhead access to functions for common programming tasks. 26 | //! 27 | //! ## Features 28 | //! 29 | //! - **[Claims](#Modules/Claims/index.html)** - Provides robust functionalities for handling various types of claims in JSON Web Tokens (JWT), including standard, custom, and private claims. Ideal for authentication and authorization processes in Rust applications. 30 | //! - **[Common](#Modules/Common/index.html)** - Offers a comprehensive collection of mathematical and cryptographic constants, such as prime numbers, Pi, cryptographic keys, and more. Essential for applications requiring high-level mathematical computations and secure cryptographic operations. 31 | //! - **[Date](#Modules/Date/index.html)** - Features an extensive suite of functions for parsing, validating, manipulating, and formatting dates and times. Supports a wide range of date/time formats and is tailored for time-sensitive Rust applications. 32 | //! - **[Errors](#Modules/Errors/index.html)** - Delivers advanced error handling functions with support for custom error types, integration with logging systems, and streamlined error propagation. Enhances the reliability and maintainability of Rust applications through robust error management. 33 | //! - **[Hash](#Modules/Hash/index.html)** - Specializes in Quantum-Resistant Cryptographic Hashing, offering a library tailored for password hashing and verification. Includes modern algorithms designed to withstand quantum-computing threats, ensuring long-term security. 34 | //! - **[JWT](#Modules/JWT/index.html)** - Provides a full range of JSON Web Token (JWT) functionalities, including secure token generation, decoding, and validation. Facilitates secure and efficient user authentication processes in Rust-based systems. 35 | //! - **[Logs](#Modules/Logs/index.html)** - Enables application-level logging with a focus on simplicity and readability. Features customizable log formats, multiple log levels, and easy integration with Rust applications, making debugging and monitoring more efficient. 36 | //! - **[MD5](#Modules/MD5/index.html)** - Offers MD5 hash functions, suitable for legacy systems compatibility. Includes a clear advisory on MD5's vulnerabilities and guidance on secure alternatives for modern applications. 37 | //! - **[QR](#Modules/QR/index.html)** - Allows for comprehensive QR code operations, including generation, customization, and scanning capabilities. Supports a variety of formats and use-cases, making it a versatile tool for Rust applications involving QR code integration. 38 | //! - **[Random](Random/index.html)** - Features high-quality random number generation using the Mersenne Twister algorithm. Ideal for applications requiring random data generation, including simulations, gaming, and cryptographic operations. 39 | //! 40 | //! These components provide a comprehensive set of functionality and offer powerful new capabilities to help you build better applications and services in the Rust programming language. 41 | //! 42 | //! [**Learn more**](https://minifunctions.com) [❯](https://minifunctions.com) 43 | //! 44 | //! ## Installation 45 | //! 46 | //! Mini Functions is available on both [Crates.io](https://crates.io/crates/mini_functions) and [Lib.rs](https://lib.rs/crates/mini_functions). 47 | //! 48 | //! Learn more about Mini Functions at . 49 | //! 50 | //! Add the following to your `Cargo.toml` file: 51 | //! ```toml 52 | //! [dependencies] 53 | //! mini_functions = "0.0.10" 54 | //! ``` 55 | //! Then, add the following to your crate root: 56 | //! ```rust 57 | //! extern crate mini_functions; 58 | //! 59 | //! use mini_functions::mini_functions::*; 60 | //! 61 | //! ``` 62 | //! 63 | //! [00]: https://minifunctions.com "Mini Functions - Highly performant utility and wrapper functions library for Rust" 64 | //! [01]: https://kura.pro/mini-functions/images/v2/banners/banner-mini-functions.svg "Mini Functions - Highly performant utility and wrapper functions library for Rust" 65 | //! 66 | #![warn(missing_docs)] 67 | #![forbid(unsafe_code)] 68 | #![doc( 69 | html_favicon_url = "https://kura.pro/mini-functions/images/v2/favicon.ico", 70 | html_logo_url = "https://kura.pro/mini-functions/images/v2/logos/mini-functions.svg", 71 | html_root_url = "https://docs.rs/mini-functions" 72 | )] 73 | #![crate_name = "mini_functions"] 74 | #![crate_type = "dylib"] 75 | #![crate_type = "lib"] 76 | #![crate_type = "rlib"] 77 | #![crate_type = "staticlib"] 78 | 79 | /// Provides access to the claims of a JSON Web Token (JWT). 80 | pub mod claims; 81 | 82 | /// Offers a comprehensive collection of mathematical and cryptographic constants. 83 | pub mod common; 84 | 85 | /// Features an extensive suite of functions for handling dates and times. 86 | pub mod date; 87 | 88 | /// Delivers advanced error handling functionalities. 89 | pub mod errors; 90 | 91 | /// Specializes in Quantum-Resistant Cryptographic Hashing. 92 | pub mod hash; 93 | 94 | /// Enables application-level logging with customizable features. 95 | pub mod logs; 96 | 97 | /// Provides a full range of JSON Web Token (JWT) functionalities. 98 | pub mod jwt; 99 | 100 | /// Offers MD5 hash functions with advisories on usage. 101 | pub mod md5; 102 | 103 | /// Features high-quality random number generation using the Mersenne Twister algorithm. 104 | pub mod random; 105 | 106 | /// Allows for comprehensive QR code operations. 107 | pub mod qr; 108 | 109 | /// Re-exports public contents of key modules 110 | pub mod mini_functions { 111 | pub use crate::{ 112 | claims::*, 113 | common::{self, cmn_macros}, 114 | date::{self, dtt_macros}, 115 | errors::*, 116 | hash::{self, hsh_macros}, 117 | jwt::*, 118 | logs::{self, rlg_macros}, 119 | md5::{self, mdg_constants}, 120 | qr::*, 121 | random::{self, vrd_macros}, 122 | }; 123 | } 124 | -------------------------------------------------------------------------------- /src/logs.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Mini Functions library. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! Application logging functionality 5 | //! 6 | //! Provides access to logging functions and types. 7 | 8 | /// Re-exported main [`rlg`] module from rlg for application logging. 9 | pub use rlg::*; 10 | 11 | /// Re-exported [`rlg_macros`] module from rlg. 12 | pub use rlg::macros as rlg_macros; 13 | -------------------------------------------------------------------------------- /src/md5.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Mini Functions library. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! Application MD5 hashing functionality 5 | //! 6 | //! Provides access to MD5 hashing functions and types. 7 | 8 | /// Re-exported main [`mdg`] module from mdg for MD5 hashing. 9 | pub use mdg::*; 10 | 11 | /// Re-exported [`constants`] module from mdg for MD5 hashing. 12 | pub use mdg::constants as mdg_constants; 13 | -------------------------------------------------------------------------------- /src/qr.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Mini Functions library. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! Application QR code functionality 5 | //! 6 | //! Provides access to QR code functions and types. 7 | 8 | /// Re-exported main [`qrc`] module from qrc for QR code generation. 9 | pub use qrc::*; 10 | -------------------------------------------------------------------------------- /src/random.rs: -------------------------------------------------------------------------------- 1 | // Copyright © 2023 Mini Functions library. All rights reserved. 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT 3 | 4 | //! Application random number generation functionality 5 | //! 6 | //! Provides access to functions for generating high-quality random numbers based on the Mersenne Twister algorithm. 7 | 8 | pub use vrd::macros as vrd_macros; 9 | pub use vrd::*; 10 | --------------------------------------------------------------------------------