├── .cargo └── config.toml ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── docs.yml │ └── test-features.yaml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTION.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── SECURITY.md ├── crates ├── ___private │ └── codora-core │ │ ├── Cargo.toml │ │ └── src │ │ └── lib.rs ├── adapter │ ├── actix │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ ├── axum │ │ ├── Cargo.toml │ │ ├── examples │ │ │ └── simple-auth.rs │ │ └── src │ │ │ └── lib.rs │ └── poem │ │ ├── Cargo.toml │ │ └── src │ │ └── lib.rs ├── codora │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ └── main.rs └── web │ └── security │ ├── Cargo.toml │ └── src │ ├── authentication │ ├── claim.rs │ ├── handler │ │ ├── bearer │ │ │ └── mod.rs │ │ ├── cookie │ │ │ └── mod.rs │ │ ├── jwt │ │ │ └── mod.rs │ │ ├── mod.rs │ │ └── oauth │ │ │ └── mod.rs │ └── mod.rs │ ├── authorization │ └── mod.rs │ ├── identity │ └── mod.rs │ └── lib.rs ├── examples └── README.md ├── modules └── README.md ├── packages └── README.md └── rustfmt.toml /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | # Simple workflow for deploying static content to GitHub Pages 2 | name: Deploy codora docs to github pages 3 | 4 | on: 5 | # Runs on pushes targeting the default branch 6 | push: 7 | branches: ['main'] 8 | 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 13 | permissions: 14 | contents: read 15 | pages: write 16 | id-token: write 17 | 18 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 19 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 20 | concurrency: 21 | group: 'pages' 22 | cancel-in-progress: false 23 | 24 | jobs: 25 | # Single deploy job since we're just deploying 26 | deploy: 27 | runs-on: ubuntu-latest 28 | steps: 29 | - name: Checkout 30 | uses: actions/checkout@v4 31 | - name: Setup Pages 32 | uses: actions/configure-pages@v5 33 | - name: Upload artifact 34 | uses: actions/upload-pages-artifact@v3 35 | with: 36 | # Upload the build from the docs directory 37 | path: 'docs/build/' 38 | - name: Deploy to GitHub Pages 39 | id: deployment 40 | uses: actions/deploy-pages@v4 41 | -------------------------------------------------------------------------------- /.github/workflows/test-features.yaml: -------------------------------------------------------------------------------- 1 | # Test only features 2 | name: Test Features 3 | 4 | on: 5 | push: 6 | branches: 7 | - main 8 | 9 | jobs: 10 | test: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v4 15 | # with: 16 | # fetch-depth: 0 17 | # - name: Test 18 | # run: | 19 | # npm ci 20 | # npm run test:features 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore Node.js dependencies and lockfiles 2 | node_modules/ 3 | package-lock.json 4 | pnpm-lock.yaml 5 | yarn.lock 6 | bun.lockb 7 | coverage 8 | 9 | # Ignore Rust target directory (compiled binaries) 10 | target/ 11 | **/target/ 12 | 13 | # Ignore Rust-specific files 14 | Cargo.lock 15 | *.rs.bk 16 | *.rmeta 17 | 18 | # Ignore environment variables and secrets 19 | .env 20 | .env.local 21 | .env.development.local 22 | .env.test.local 23 | .env.production.local 24 | 25 | # Ignore build and generated files 26 | dist/ 27 | out/ 28 | .build/ 29 | .cache/ 30 | .docusaurus/ 31 | .svelte-kit/ 32 | .next/ 33 | .vite/ 34 | wasm-pack/ 35 | pkg/ 36 | 37 | # Ignore logs and debug files 38 | npm-debug.log* 39 | yarn-debug.log* 40 | yarn-error.log* 41 | pnpm-debug.log* 42 | cargo-debug.log* 43 | cargo-test.log* 44 | turbo-debug.log* 45 | lerna-debug.log* 46 | *.log 47 | 48 | # Ignore temporary files 49 | .DS_Store 50 | Thumbs.db 51 | *.swp 52 | *.swo 53 | *.sublime-workspace 54 | 55 | # Ignore IDE and editor files 56 | .idea/ 57 | .vscode/ 58 | *.iml 59 | *.suo 60 | *.ntvs* 61 | *.njsproj 62 | *.sln 63 | *.sw? 64 | 65 | # Ignore GitHub Actions and deployment artifacts 66 | .github/workflows/node_modules/ 67 | .github/workflows/dist/ 68 | 69 | # Ignore WebAssembly (WASM) build artifacts 70 | *.wasm 71 | *.wat 72 | *.wast 73 | 74 | # docusaurus 75 | docs/.docusaurus 76 | .docusaurus 77 | **/.docusaurus 78 | 79 | # templates 80 | templates/* 81 | **/templates 82 | 83 | dev.*rs 84 | dev/** 85 | **/dev/** 86 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | theproject.org. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /CONTRIBUTION.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getcodora/codora/acef29043e69271790186913c6c5b030dada6bf0/CONTRIBUTION.md -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.24.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler2" 16 | version = "2.0.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 19 | 20 | [[package]] 21 | name = "anyhow" 22 | version = "1.0.97" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" 25 | 26 | [[package]] 27 | name = "autocfg" 28 | version = "1.4.0" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 31 | 32 | [[package]] 33 | name = "backtrace" 34 | version = "0.3.74" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 37 | dependencies = [ 38 | "addr2line", 39 | "cfg-if", 40 | "libc", 41 | "miniz_oxide", 42 | "object", 43 | "rustc-demangle", 44 | "windows-targets", 45 | ] 46 | 47 | [[package]] 48 | name = "bitflags" 49 | version = "2.9.0" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" 52 | 53 | [[package]] 54 | name = "bytes" 55 | version = "1.10.1" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" 58 | 59 | [[package]] 60 | name = "cfg-if" 61 | version = "1.0.0" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 64 | 65 | [[package]] 66 | name = "codora" 67 | version = "0.1.0" 68 | dependencies = [ 69 | "anyhow", 70 | "codora-core", 71 | "codora-security", 72 | "tokio", 73 | ] 74 | 75 | [[package]] 76 | name = "codora-core" 77 | version = "0.1.0" 78 | dependencies = [ 79 | "derive-new", 80 | ] 81 | 82 | [[package]] 83 | name = "codora-security" 84 | version = "0.1.0" 85 | dependencies = [ 86 | "codora-core", 87 | "futures-util", 88 | "http", 89 | "tokio", 90 | ] 91 | 92 | [[package]] 93 | name = "derive-new" 94 | version = "0.7.0" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "2cdc8d50f426189eef89dac62fabfa0abb27d5cc008f25bf4156a0203325becc" 97 | dependencies = [ 98 | "proc-macro2", 99 | "quote", 100 | "syn", 101 | ] 102 | 103 | [[package]] 104 | name = "fnv" 105 | version = "1.0.7" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 108 | 109 | [[package]] 110 | name = "futures-core" 111 | version = "0.3.31" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 114 | 115 | [[package]] 116 | name = "futures-macro" 117 | version = "0.3.31" 118 | source = "registry+https://github.com/rust-lang/crates.io-index" 119 | checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" 120 | dependencies = [ 121 | "proc-macro2", 122 | "quote", 123 | "syn", 124 | ] 125 | 126 | [[package]] 127 | name = "futures-task" 128 | version = "0.3.31" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 131 | 132 | [[package]] 133 | name = "futures-util" 134 | version = "0.3.31" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 137 | dependencies = [ 138 | "futures-core", 139 | "futures-macro", 140 | "futures-task", 141 | "pin-project-lite", 142 | "pin-utils", 143 | "slab", 144 | ] 145 | 146 | [[package]] 147 | name = "gimli" 148 | version = "0.31.1" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 151 | 152 | [[package]] 153 | name = "http" 154 | version = "1.3.1" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" 157 | dependencies = [ 158 | "bytes", 159 | "fnv", 160 | "itoa", 161 | ] 162 | 163 | [[package]] 164 | name = "itoa" 165 | version = "1.0.15" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 168 | 169 | [[package]] 170 | name = "libc" 171 | version = "0.2.171" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" 174 | 175 | [[package]] 176 | name = "lock_api" 177 | version = "0.4.12" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 180 | dependencies = [ 181 | "autocfg", 182 | "scopeguard", 183 | ] 184 | 185 | [[package]] 186 | name = "memchr" 187 | version = "2.7.4" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 190 | 191 | [[package]] 192 | name = "miniz_oxide" 193 | version = "0.8.8" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" 196 | dependencies = [ 197 | "adler2", 198 | ] 199 | 200 | [[package]] 201 | name = "mio" 202 | version = "1.0.3" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" 205 | dependencies = [ 206 | "libc", 207 | "wasi", 208 | "windows-sys", 209 | ] 210 | 211 | [[package]] 212 | name = "object" 213 | version = "0.36.7" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" 216 | dependencies = [ 217 | "memchr", 218 | ] 219 | 220 | [[package]] 221 | name = "parking_lot" 222 | version = "0.12.3" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 225 | dependencies = [ 226 | "lock_api", 227 | "parking_lot_core", 228 | ] 229 | 230 | [[package]] 231 | name = "parking_lot_core" 232 | version = "0.9.10" 233 | source = "registry+https://github.com/rust-lang/crates.io-index" 234 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 235 | dependencies = [ 236 | "cfg-if", 237 | "libc", 238 | "redox_syscall", 239 | "smallvec", 240 | "windows-targets", 241 | ] 242 | 243 | [[package]] 244 | name = "pin-project-lite" 245 | version = "0.2.16" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 248 | 249 | [[package]] 250 | name = "pin-utils" 251 | version = "0.1.0" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 254 | 255 | [[package]] 256 | name = "proc-macro2" 257 | version = "1.0.95" 258 | source = "registry+https://github.com/rust-lang/crates.io-index" 259 | checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" 260 | dependencies = [ 261 | "unicode-ident", 262 | ] 263 | 264 | [[package]] 265 | name = "quote" 266 | version = "1.0.40" 267 | source = "registry+https://github.com/rust-lang/crates.io-index" 268 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 269 | dependencies = [ 270 | "proc-macro2", 271 | ] 272 | 273 | [[package]] 274 | name = "redox_syscall" 275 | version = "0.5.11" 276 | source = "registry+https://github.com/rust-lang/crates.io-index" 277 | checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" 278 | dependencies = [ 279 | "bitflags", 280 | ] 281 | 282 | [[package]] 283 | name = "rustc-demangle" 284 | version = "0.1.24" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 287 | 288 | [[package]] 289 | name = "scopeguard" 290 | version = "1.2.0" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 293 | 294 | [[package]] 295 | name = "signal-hook-registry" 296 | version = "1.4.2" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" 299 | dependencies = [ 300 | "libc", 301 | ] 302 | 303 | [[package]] 304 | name = "slab" 305 | version = "0.4.9" 306 | source = "registry+https://github.com/rust-lang/crates.io-index" 307 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 308 | dependencies = [ 309 | "autocfg", 310 | ] 311 | 312 | [[package]] 313 | name = "smallvec" 314 | version = "1.15.0" 315 | source = "registry+https://github.com/rust-lang/crates.io-index" 316 | checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" 317 | 318 | [[package]] 319 | name = "socket2" 320 | version = "0.5.9" 321 | source = "registry+https://github.com/rust-lang/crates.io-index" 322 | checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" 323 | dependencies = [ 324 | "libc", 325 | "windows-sys", 326 | ] 327 | 328 | [[package]] 329 | name = "syn" 330 | version = "2.0.100" 331 | source = "registry+https://github.com/rust-lang/crates.io-index" 332 | checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" 333 | dependencies = [ 334 | "proc-macro2", 335 | "quote", 336 | "unicode-ident", 337 | ] 338 | 339 | [[package]] 340 | name = "tokio" 341 | version = "1.44.2" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" 344 | dependencies = [ 345 | "backtrace", 346 | "bytes", 347 | "libc", 348 | "mio", 349 | "parking_lot", 350 | "pin-project-lite", 351 | "signal-hook-registry", 352 | "socket2", 353 | "tokio-macros", 354 | "windows-sys", 355 | ] 356 | 357 | [[package]] 358 | name = "tokio-macros" 359 | version = "2.5.0" 360 | source = "registry+https://github.com/rust-lang/crates.io-index" 361 | checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" 362 | dependencies = [ 363 | "proc-macro2", 364 | "quote", 365 | "syn", 366 | ] 367 | 368 | [[package]] 369 | name = "unicode-ident" 370 | version = "1.0.18" 371 | source = "registry+https://github.com/rust-lang/crates.io-index" 372 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 373 | 374 | [[package]] 375 | name = "wasi" 376 | version = "0.11.0+wasi-snapshot-preview1" 377 | source = "registry+https://github.com/rust-lang/crates.io-index" 378 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 379 | 380 | [[package]] 381 | name = "windows-sys" 382 | version = "0.52.0" 383 | source = "registry+https://github.com/rust-lang/crates.io-index" 384 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 385 | dependencies = [ 386 | "windows-targets", 387 | ] 388 | 389 | [[package]] 390 | name = "windows-targets" 391 | version = "0.52.6" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 394 | dependencies = [ 395 | "windows_aarch64_gnullvm", 396 | "windows_aarch64_msvc", 397 | "windows_i686_gnu", 398 | "windows_i686_gnullvm", 399 | "windows_i686_msvc", 400 | "windows_x86_64_gnu", 401 | "windows_x86_64_gnullvm", 402 | "windows_x86_64_msvc", 403 | ] 404 | 405 | [[package]] 406 | name = "windows_aarch64_gnullvm" 407 | version = "0.52.6" 408 | source = "registry+https://github.com/rust-lang/crates.io-index" 409 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 410 | 411 | [[package]] 412 | name = "windows_aarch64_msvc" 413 | version = "0.52.6" 414 | source = "registry+https://github.com/rust-lang/crates.io-index" 415 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 416 | 417 | [[package]] 418 | name = "windows_i686_gnu" 419 | version = "0.52.6" 420 | source = "registry+https://github.com/rust-lang/crates.io-index" 421 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 422 | 423 | [[package]] 424 | name = "windows_i686_gnullvm" 425 | version = "0.52.6" 426 | source = "registry+https://github.com/rust-lang/crates.io-index" 427 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 428 | 429 | [[package]] 430 | name = "windows_i686_msvc" 431 | version = "0.52.6" 432 | source = "registry+https://github.com/rust-lang/crates.io-index" 433 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 434 | 435 | [[package]] 436 | name = "windows_x86_64_gnu" 437 | version = "0.52.6" 438 | source = "registry+https://github.com/rust-lang/crates.io-index" 439 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 440 | 441 | [[package]] 442 | name = "windows_x86_64_gnullvm" 443 | version = "0.52.6" 444 | source = "registry+https://github.com/rust-lang/crates.io-index" 445 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 446 | 447 | [[package]] 448 | name = "windows_x86_64_msvc" 449 | version = "0.52.6" 450 | source = "registry+https://github.com/rust-lang/crates.io-index" 451 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 452 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "crates/codora", 4 | # Adapter 5 | # "crates/adapter/*", 6 | # Internal crate mean't for internal used 7 | "crates/___private/*", 8 | # Codora Web 9 | "crates/web/*", 10 | ] 11 | resolver = "2" 12 | 13 | 14 | [workspace.package] 15 | version = "0.1.0" 16 | edition = "2024" 17 | license = "MIT" 18 | repository = "https://github.com/getcodora/codora" 19 | keywords = ["web", "server", "orm", "authentication", "security", "logging"] 20 | categories = ["web-programming", "web-framework", "orm"] 21 | authors = ["West Sheriff "] 22 | 23 | [workspace.dependencies] 24 | # Workspace Crates 25 | codora = { path = "./crates/codora" } 26 | codora-core = { path = "./crates/___private/codora-core" } 27 | codora-security = { path = "./crates/web/security" } 28 | # Adapter Crates 29 | 30 | 31 | # External Crates 32 | anyhow = "1.0.87" 33 | serde = "1.0.215" 34 | serde_json = "1.0.140" 35 | tokio = { version = "1.44.0" } 36 | 37 | [workspace.lints.clippy] 38 | 39 | # TODO 40 | # Setup Compiler Profile 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2024 theProject.dev 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # codora 2 | 3 | ## Getting Started 4 | 5 | codora is a framework designed to simplify web and any sort of development in the Rust ecosystem. To learn more about it: 6 | 7 | - **Documentation:** [codora Docs](https://codora.github.io "codora Docs") 8 | - **Repository:** [codora GitHub](https://github.com/codetheproject/codora "codora Repo") 9 | 10 | ⚠️ **Warning:** 11 | codora is currently **work in progress (WIP)** — expect **frequent breaking API changes** as we continue to iterate and improve the framework. Please pin your versions carefully and stay updated with the latest changelogs. 12 | 13 | ## Community 14 | 15 | We’re in the process of building a community. Stay tuned for an official community link — we’d love to have you join us! 16 | 17 | ## Contribution 18 | 19 | codora is open to contributions, and we highly appreciate your support, whether through code, monetary contributions, or other forms of assistance. Before contributing, please read our **[Contribution Guidelines](CONTRIBUTION.md)** to understand the coding style and project structure. If you have any suggestions, feel free to contact the maintainer: 20 | 21 | - **Discord:** [WIP] 22 | - **Email:** [WIP] 23 | 24 | ## Security 25 | 26 | If you discover a security vulnerability, please report it through our official security disclosure process. Submit your security concerns via [Security](SECURITY.md). 27 | 28 | --- 29 | 30 | Stay tuned for updates as we improve codora! 🚀 31 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Security Contact 4 | 5 | If you believe you've discovered a security issue in this project, please contact us: 6 | 7 | - **[Email Us](mailto://west.sh.mail@gmail.com, "West Sheriff email address")** 8 | 9 | Please **do not report security vulnerabilities through public GitHub issues**. 10 | 11 | ## Reporting a Vulnerability 12 | 13 | When reporting a vulnerability, include: 14 | 15 | 1. **Description of the issue** 16 | 2. **Steps to reproduce** 17 | 3. **Expected vs. actual behavior** 18 | 4. **Affected versions** 19 | 5. **Additional context** (if relevant) 20 | 21 | Your report will be reviewed promptly. A public acknowledgment will be made once the issue is resolved. 22 | 23 | ## Response and Coordination 24 | 25 | We will aim to respond to all security reports within **7 business days**. Once the issue is confirmed, we will: 26 | 27 | 1. Fix the issue promptly or release an appropriate workaround. 28 | 2. Publish a security advisory through GitHub Security Advisories when necessary. 29 | -------------------------------------------------------------------------------- /crates/___private/codora-core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "codora-core" 3 | version.workspace = true 4 | edition.workspace = true 5 | license.workspace = true 6 | repository.workspace = true 7 | keywords.workspace = true 8 | categories.workspace = true 9 | authors.workspace = true 10 | 11 | [dependencies] 12 | derive-new = "0.7.0" 13 | 14 | [lints] 15 | workspace = true 16 | -------------------------------------------------------------------------------- /crates/___private/codora-core/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![forbid(unsafe_code)] 2 | // Silence the noise in development! 3 | #![cfg_attr(debug_assertions, allow(dead_code, unused_variables))] 4 | // Docs and linting rules 5 | #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))] 6 | #![cfg_attr(test, allow(clippy::float_cmp))] 7 | #![cfg_attr(not(test), deny(clippy::print_stdout, clippy::dbg_macro))] 8 | // - Lint for missing docs 9 | #![cfg_attr(not(debug_assertions), deny(missing_docs))] 10 | //! 11 | 12 | #[doc(inline)] 13 | /// Re-exports the [`new`](https://docs.rs/derive-new/latest/derive_new/derive/fn.new.html) macro from the `derive-new` crate. 14 | /// 15 | /// This is a procedural macro that derives a basic constructor for structs and enums. 16 | /// The macro is provided by the [`derive-new`](https://crates.io/crates/derive-new) crate. 17 | /// 18 | /// # Features 19 | /// This re-export is only available when the `derive-new` feature is enabled. 20 | /// 21 | /// # Example 22 | /// ```rust 23 | /// use your_crate::new; 24 | /// 25 | /// #[derive(new)] 26 | /// struct Point { 27 | /// x: i32, 28 | /// y: i32, 29 | /// } 30 | /// 31 | /// let point = Point::new(1, 2); 32 | /// ``` 33 | /// 34 | /// # License 35 | /// The `derive-new` crate is licensed under either of: 36 | /// * Apache License, Version 2.0 37 | /// * MIT License 38 | /// 39 | /// at your option. 40 | /// 41 | /// # Attribution 42 | /// Original crate authored by Nika Layzell and maintained by the Rust community. 43 | /// For more information, visit the [derive-new repository](https://github.com/nrc/derive-new). 44 | pub use derive_new::new; 45 | 46 | /// Retrieves an environment variable's value. 47 | /// 48 | /// # Arguments 49 | /// 50 | /// * `name` - The name of the environment variable to retrieve 51 | /// 52 | /// # Returns 53 | /// 54 | /// * `Ok(String)` - The value of the environment variable 55 | /// * `Err(String)` - Error message if the variable is not found 56 | /// 57 | /// # Example 58 | /// 59 | /// ```rust 60 | /// let database_url = get_env("DATABASE_URL")?; 61 | /// ``` 62 | #[inline] 63 | pub fn get_env(name: &'static str) -> Result { 64 | std::env::var(name).map_err(|_| format!("Environment variable '{name}' not found")) 65 | } 66 | 67 | /// Retrieves and parses an environment variable into a specified type. 68 | /// 69 | /// # Type Parameters 70 | /// 71 | /// * `T` - The target type that implements FromStr 72 | /// 73 | /// # Arguments 74 | /// 75 | /// * `name` - The name of the environment variable to retrieve 76 | /// 77 | /// # Returns 78 | /// 79 | /// * `Ok(T)` - The parsed value of the environment variable 80 | /// * `Err(String)` - Error message if variable is not found or parsing fails 81 | /// 82 | /// # Example 83 | /// 84 | /// ```rust 85 | /// let port: u16 = get_env_parse("PORT")?; 86 | /// ``` 87 | #[inline] 88 | pub fn get_env_parse(name: &'static str) -> Result 89 | where 90 | T: std::str::FromStr, 91 | { 92 | get_env(name).and_then(|value| { 93 | value 94 | .parse::() 95 | .map_err(|_| format!("Failed to parse '{name}' into {}", std::any::type_name::())) 96 | }) 97 | } 98 | 99 | #[macro_export] 100 | macro_rules! lazy_lock { 101 | ($definition:expr) => { 102 | std::sync::LazyLock::new(|| $definition) 103 | }; 104 | (() => $block:block) => { 105 | std::sync::LazyLock::new(|| $block) 106 | }; 107 | } 108 | 109 | /// Ensure a predicate is true; return an error otherwise. 110 | #[macro_export] 111 | macro_rules! ensure { 112 | ($pred:expr, $err:expr) => { 113 | if !$pred { 114 | return Err($err); 115 | } 116 | }; 117 | } 118 | 119 | /// Always return an error; used for early exits. 120 | #[macro_export] 121 | macro_rules! err { 122 | ($err:expr) => { 123 | return Err($err) 124 | }; 125 | } 126 | 127 | /// Clone an expression. 128 | #[macro_export] 129 | macro_rules! clone { 130 | ($expr:expr) => { 131 | $expr.clone() 132 | }; 133 | } 134 | 135 | /// Get the duration since a specific `Instant`. 136 | #[macro_export] 137 | macro_rules! duration_since { 138 | ($earlier:expr) => { 139 | std::time::Instant::now().duration_since($earlier) 140 | }; 141 | } 142 | 143 | /// Simplified string formatting. 144 | #[macro_export] 145 | macro_rules! f { 146 | ($($arg:tt)*) => { 147 | format!($($arg)*) 148 | }; 149 | } 150 | 151 | /// Implement `Error` and `Display` for a type. 152 | #[macro_export] 153 | macro_rules! impl_error__and_display { 154 | ($ident:ident) => { 155 | const _: () = { 156 | impl std::error::Error for $ident {} 157 | impl std::fmt::Display for $ident { 158 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 159 | write!(f, "Error: {:?}", self) 160 | } 161 | } 162 | }; 163 | }; 164 | } 165 | 166 | /// Return `Some` for an optional value, or `None` otherwise. 167 | #[macro_export] 168 | macro_rules! opt { 169 | ($( $value:expr )?) => { 170 | match ($(Some($value))?) { 171 | Some(_) => Some($value), 172 | _ => None, 173 | } 174 | }; 175 | } 176 | 177 | /// Create an `Arc` for a value. 178 | #[macro_export] 179 | macro_rules! arc { 180 | ($value:expr) => { 181 | std::sync::Arc::new($value) 182 | }; 183 | } 184 | 185 | /// Create a `Mutex` for a value. 186 | #[macro_export] 187 | macro_rules! mutex { 188 | ($value:expr) => { 189 | std::sync::Mutex::new($value) 190 | }; 191 | } 192 | 193 | /// Create a static reference from a type and data using `LazyLock`. 194 | #[macro_export] 195 | macro_rules! to_static { 196 | ($ty:ty, $data:expr) => { 197 | static DATA: std::sync::LazyLock<$ty> = $crate::lazy_lock!($data); 198 | &*DATA 199 | }; 200 | } 201 | 202 | /// A macro to create `String` instances in various formats. 203 | /// 204 | /// # Usage 205 | /// ```rust 206 | /// use std_rs::string; 207 | /// 208 | /// let empty = string!(); 209 | /// let simple = string!("Hello, world!"); 210 | /// let with_capacity = string!("Hello", 20); 211 | /// 212 | /// let from_utf8 = string!(u8: vec![72, 101, 108, 108, 111]).unwrap(); 213 | /// let from_utf8_lossy = string!(u8l: &[255, 72, 101, 108, 108, 111]); 214 | /// 215 | /// let from_utf16 = string!(u16: &[72, 101, 108, 108, 111]).unwrap(); 216 | /// let from_utf16_lossy = string!(u16l: &[72, 101, 108, 108, 111]); 217 | /// 218 | /// let repeat_chars = string!(repeat: 'A', 5); 219 | /// let from_char_iter = string!(iter: ['H', 'e', 'l', 'l', 'o']); 220 | /// 221 | /// let with_capacity_only = string!(capacity: 30); 222 | /// ``` 223 | /// 224 | /// # Supported Variants 225 | /// - `string!()` → Creates an empty `String`. 226 | /// - `string!(content)` → Converts input into a `String`. 227 | /// - `string!(content, capacity)` → Creates a `String` with initial capacity and content. 228 | /// - `string!(u8: content)` → Creates a `String` from `Vec`. Can fail. 229 | /// - `string!(u8l: content)` → Creates a lossy `String` from `&[u8]`. 230 | /// - `string!(u16: content)` → Creates a `String` from `&[u16]`. Can fail. 231 | /// - `string!(u16l: content)` → Creates a lossy `String` from `&[u16]`. 232 | /// - `string!(repeat: char, count)` → Creates a `String` by repeating a character `count` times. 233 | /// - `string!(iter: iterable)` → Creates a `String` from an iterator of characters. 234 | /// - `string!(capacity: size)` → Creates an empty `String` with the given capacity. 235 | /// A macro for flexible string creation with various input types and configurations. 236 | /// 237 | /// # Variants 238 | /// 239 | /// - `string!()` - Creates an empty string 240 | /// - `string!("content")` - Creates a string from a string literal 241 | /// - `string!("content", capacity)` - Creates a string with specified content and capacity 242 | /// - `string!(u8: vec![...])` - Creates a string from UTF-8 bytes (Vec) 243 | /// - `string!(u8l: &[...])` - Creates a string from UTF-8 bytes with lossy conversion 244 | /// - `string!(u16: &[...])` - Creates a string from UTF-16 bytes 245 | /// - `string!(u16l: &[...])` - Creates a string from UTF-16 bytes with lossy conversion 246 | /// - `string!(repeat: 'c', n)` - Creates a string by repeating a character n times 247 | /// - `string!(iter: iterator)` - Creates a string from an iterator of chars 248 | /// - `string!(capacity: n)` - Creates an empty string with specified capacity 249 | /// 250 | /// # Examples 251 | /// 252 | /// ``` 253 | /// // Empty string 254 | /// let empty = string!(); 255 | /// 256 | /// // From string literal 257 | /// let hello = string!("Hello, World!"); 258 | /// 259 | /// // With capacity 260 | /// let with_cap = string!("Hello", 10); 261 | /// 262 | /// // From UTF-8 bytes 263 | /// let bytes = vec![72, 101, 108, 108, 111]; 264 | /// let from_utf8 = string!(u8: bytes); 265 | /// 266 | /// // From UTF-16 bytes 267 | /// let utf16 = vec![72, 101, 108, 108, 111]; 268 | /// let from_utf16 = string!(u16: &utf16); 269 | /// 270 | /// // Repeat character 271 | /// let repeated = string!(repeat: '*', 5); // "*****" 272 | /// 273 | /// // From iterator 274 | /// let chars = vec!['H', 'e', 'l', 'l', 'o']; 275 | /// let from_iter = string!(iter: chars); 276 | /// 277 | /// // With capacity 278 | /// let reserved = string!(capacity: 100); 279 | /// ``` 280 | /// 281 | /// # Note 282 | /// 283 | /// The macro provides both safe and potentially fallible conversions: 284 | /// - `u8` and `u16` variants return `Result` types that should be handled 285 | /// - `u8l` and `u16l` variants perform lossy conversion, always succeeding 286 | #[macro_export] 287 | macro_rules! string { 288 | // Empty string 289 | () => { 290 | String::new() 291 | }; 292 | 293 | // String from content 294 | ($content:expr) => { 295 | String::from($content) 296 | }; 297 | 298 | // String from content with specified capacity 299 | ($content:expr, $cap:expr) => {{ 300 | let mut string = String::with_capacity($cap); 301 | string.push_str($content); 302 | string 303 | }}; 304 | 305 | // String from Vec (UTF-8), returns Result 306 | (u8: $content:expr) => { 307 | String::from_utf8($content) 308 | }; 309 | 310 | // Lossy String from &[u8] (UTF-8) 311 | (u8l: $content:expr) => { 312 | String::from_utf8_lossy($content).to_string() 313 | }; 314 | 315 | // String from &[u16] (UTF-16), returns Result 316 | (u16: $content:expr) => { 317 | String::from_utf16($content) 318 | }; 319 | 320 | // Lossy String from &[u16] (UTF-16) 321 | (u16l: $content:expr) => { 322 | String::from_utf16_lossy($content) 323 | }; 324 | 325 | // Repeat a character `count` times 326 | (repeat: $ch:expr, $count:expr) => { 327 | std::iter::repeat($ch) 328 | .take($count) 329 | .collect::() 330 | }; 331 | 332 | // Create String from iterator of chars 333 | (iter: $iterable:expr) => { 334 | $iterable 335 | .into_iter() 336 | .collect::() 337 | }; 338 | 339 | // Create String with specific capacity 340 | (capacity: $size:expr) => { 341 | String::with_capacity($size) 342 | }; 343 | } 344 | -------------------------------------------------------------------------------- /crates/adapter/actix/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "codora-adapter-actix" 3 | version.workspace = true 4 | edition.workspace = true 5 | license.workspace = true 6 | repository.workspace = true 7 | keywords.workspace = true 8 | categories.workspace = true 9 | authors.workspace = true 10 | 11 | [dependencies] 12 | 13 | [lints] 14 | workspace = true 15 | -------------------------------------------------------------------------------- /crates/adapter/actix/src/lib.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /crates/adapter/axum/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "codora-adapter-axum" 3 | version.workspace = true 4 | edition.workspace = true 5 | license.workspace = true 6 | repository.workspace = true 7 | keywords.workspace = true 8 | categories.workspace = true 9 | authors.workspace = true 10 | 11 | [dependencies] 12 | codora-util = { workspace = true } 13 | codora-security = { workspace = true } 14 | axum = { version = "0.8.4", features = ["macros"] } 15 | tokio = { workspace = true, features = ["full"] } 16 | anyhow = { workspace = true } 17 | 18 | [lints] 19 | workspace = true 20 | -------------------------------------------------------------------------------- /crates/adapter/axum/examples/simple-auth.rs: -------------------------------------------------------------------------------- 1 | use axum::{debug_handler, routing::get}; 2 | use codora_util::string; 3 | use tokio::net::TcpListener; 4 | 5 | #[debug_handler] 6 | // () is a Temporary Response 7 | // Context will hold previous claim and current claim which would all be used when authenticating! 8 | async fn handler() -> Result<((), String), &'static str> { 9 | Ok((res, string!("ok!"))) 10 | } 11 | 12 | #[tokio::main] 13 | async fn main() -> anyhow::Result<()> { 14 | let auth = AuthenticationLayer::new(); 15 | 16 | let app = axum::Router::new() 17 | .route("/sign-in", get(handler)) 18 | .layer(auth); 19 | 20 | let listener = TcpListener::bind("127.0.0.1:2345").await?; 21 | axum::serve(listener, app).await?; 22 | Ok(()) 23 | } 24 | -------------------------------------------------------------------------------- /crates/adapter/axum/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! This should explain how codora-security used axum 2 | //! 3 | //! 4 | //! 5 | //! 6 | //! 7 | //! 8 | //! 9 | //! More Docs! 10 | -------------------------------------------------------------------------------- /crates/adapter/poem/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "codora-adapter-poem" 3 | version.workspace = true 4 | edition.workspace = true 5 | license.workspace = true 6 | repository.workspace = true 7 | keywords.workspace = true 8 | categories.workspace = true 9 | authors.workspace = true 10 | 11 | [dependencies] 12 | 13 | [lints] 14 | workspace = true 15 | -------------------------------------------------------------------------------- /crates/adapter/poem/src/lib.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getcodora/codora/acef29043e69271790186913c6c5b030dada6bf0/crates/adapter/poem/src/lib.rs -------------------------------------------------------------------------------- /crates/codora/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "codora" 3 | version = { workspace = true } 4 | edition = { workspace = true } 5 | 6 | 7 | [features] 8 | core = ["dep:codora-core"] 9 | default = ["core", "security"] 10 | security = ["dep:codora-security"] 11 | 12 | 13 | [dependencies] 14 | codora-core = { workspace = true, optional = true } 15 | codora-security = { workspace = true, optional = true } 16 | 17 | 18 | [dev-dependencies] 19 | anyhow = { workspace = true } 20 | tokio = { workspace = true, features = ["full"] } 21 | -------------------------------------------------------------------------------- /crates/codora/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![forbid(unsafe_code)] 2 | // Silence the noise in development! 3 | #![cfg_attr(debug_assertions, allow(dead_code, unused_variables))] 4 | // Docs and linting rules 5 | #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))] 6 | #![cfg_attr(test, allow(clippy::float_cmp))] 7 | #![cfg_attr(not(test), deny(clippy::print_stdout, clippy::dbg_macro))] 8 | // - Lint for missing docs 9 | #![cfg_attr(not(debug_assertions), deny(missing_docs))] 10 | #![doc = include_str!("../../../README.md")] 11 | 12 | #[cfg(not(any(feature = "core", feature = "security")))] 13 | compile_error!("You must enable at least one feature to use codora"); 14 | 15 | #[cfg(feature = "core")] 16 | pub use codora_core::*; 17 | 18 | // TODO -> Inline docs, setup getcodora, learn about action, update readme, changelog, otherstuff 19 | #[cfg(feature = "security")] 20 | pub mod security { 21 | //! 22 | //! This is the security module for codora 23 | } 24 | -------------------------------------------------------------------------------- /crates/codora/src/main.rs: -------------------------------------------------------------------------------- 1 | // const _: () = {}; 2 | // Use this bin for codora cli 3 | 4 | fn main() {} 5 | // #[derive(Authentication)] 6 | // #[signin_with()] 7 | // #[signout_with()] 8 | // pub struct AuthProvider; 9 | 10 | // Impl the Provider Trait 11 | 12 | // pub struct Authentication 13 | // This will hold the provider 14 | // Hold the State 15 | // Hold everything we need to authenticate peroperly 16 | // auth.signin(pass in a context that could have a handler to this would allow us to switch handler at run time) 17 | // We don't need to manage context you know we would have TemporaryResponse with body this would allow us to fake Response then we can set how we want to match it at runtime 18 | 19 | /* 20 | use extension method to generate response tailored to each framework 21 | 22 | handler can be a struct no need to hold hot one created when needed 23 | handler can 24 | 25 | Rule of thumb if you think user might need to decide how a service would be created creata a factory for it 26 | Recieves Request, caim yada yada whatever is available at the point of use 27 | 28 | let sign_in = auth.sign_in(Claim).await?; 29 | 30 | auth.into_response(sign_in) 31 | auth.into_response_with_body(sign_in, Body) 32 | */ 33 | // # codora 34 | 35 | // This would allow us to write frontend in JSX and take advantage of all the React ecosystem while having the flexibility to continue in typescript for the backend or Rusr 36 | 37 | // ```code 38 | // | - functions 39 | // - rust server will be marked here and typescript too and they will be available to be called immediately from routes 40 | // | - routes 41 | // | - app 42 | // - font 43 | // - component 44 | // - styles 45 | // package.json 46 | // Cargo.toml 47 | // codora.toml 48 | // 49 | 50 | // #[server] 51 | // async fn get_user(ctx: Context) -> Result<()> {} 52 | 53 | // #[middleware] 54 | // async fn log(ctx: Context) -> Result<()> {} 55 | 56 | // async fn handler(migrator) -> Result<()> { 57 | // migrator.exec("Run some sql here or code here").await?; 58 | // } 59 | 60 | // #[derive(schema, before_schema=handler)] 61 | // struct User { 62 | // #[schema(nullable=true, other_configs)] 63 | // name: String 64 | // } 65 | 66 | // #[derive(schema)] 67 | // struct Address { 68 | // name: String, 69 | 70 | // #[schema(owner=User, unique=true, unique_index=true)] 71 | // user_id: String, 72 | // } 73 | 74 | // #[migrator] 75 | // async fn (migrator) -> Result<()> { 76 | // Migrator::new() 77 | // .schema::() 78 | // .migrator(migrator) 79 | // .await?; 80 | // } 81 | 82 | // #[config] 83 | // async fn (ctx) -> Result<()> { 84 | // Config::new() 85 | // .matcher(Match("^/(api|user).*$"), vec![log, other_middleware]) 86 | // .matcher(Match("*"), log) 87 | // .function(get_user) 88 | // 89 | // } 90 | 91 | // 92 | // @schema 93 | // class User { 94 | // public name: string = query() 95 | // } 96 | 97 | // type Data = { 98 | // name: string; 99 | // } 100 | 101 | // export async function getUser() -> Result { 102 | // Ok({ name: "West" } ) 103 | // } 104 | 105 | // 106 | // export function Page() { 107 | // 108 | // let user = await getUser(); 109 | 110 | // return ( 111 | //
{user.name}
112 | // ) 113 | // } 114 | // ``` 115 | 116 | // codora wouldn't stop here it would provide third party lib like payment, websocket an infra to make working with codora easily, then maybe we could have another framework that allow building 117 | // ML projects and data science in Javascript with Rust Backed 118 | 119 | // ## Features 120 | 121 | // * Dashboard - manage orm, job, request execution 122 | // * Command to manage project and we could add it dynamically 123 | // * Track request execution and provide interface to be used by prometheus which we would intrgrate with the dashboard 124 | // * Queue system and User can add an adapter that forward it to external services 125 | // * Cron Framework 126 | 127 | // ### Libraries 128 | 129 | // * Authentication and Authorization Lib 130 | 131 | // Certainly! Here's a **markdown-formatted list** highlighting features provided by frameworks like **.NET**, **Spring**, **Elixir (Phoenix)**, **Next.js**, and **Vercel**. This comparison will help identify areas where **Codora** can enhance its offerings: 132 | 133 | // --- 134 | 135 | // ### **1. .NET Framework** 136 | 137 | // * **Language Support**: Multiple languages including C#, F#, and Visual Basic. 138 | // * **Integrated Development Environment (IDE)**: Deep integration with Visual Studio, providing robust debugging and development tools. 139 | // * **Comprehensive Libraries**: Extensive standard libraries for various functionalities like networking, IO, and data structures. 140 | // * **Entity Framework**: Object-Relational Mapper (ORM) for database interactions. 141 | // * **ASP.NET Core**: Framework for building web applications and APIs. 142 | // * **Blazor**: Framework for building interactive web UIs using C# instead of JavaScript. 143 | // * **Azure Integration**: Seamless deployment and services integration with Microsoft Azure. 144 | // * **Security Features**: Built-in authentication and authorization mechanisms. 145 | 146 | // **Potential Enhancements for Codora**: 147 | 148 | // * **IDE Integration**: Consider developing plugins or extensions for popular IDEs to improve the developer experience. 149 | // * **Comprehensive Standard Library**: Expand Codora's standard library to include more built-in functionalities. 150 | // * **Official Cloud Integrations**: Develop official integrations with major cloud providers for seamless deployment and service integration. 151 | 152 | // --- 153 | 154 | // ### **2. Spring Framework (Java)** 155 | 156 | // * **Inversion of Control (IoC) Container**: Manages object creation and lifecycle, promoting loose coupling. 157 | // * **Spring Boot**: Simplifies the setup of new Spring applications with embedded servers and starters. 158 | // * **Spring Security**: Comprehensive security services for authentication and authorization. 159 | // * **Spring Data**: Simplifies data access and integrates with various databases. 160 | // * **Spring Cloud**: Tools for building cloud-native applications and microservices. 161 | // * **Aspect-Oriented Programming (AOP)**: Separates cross-cutting concerns like logging and transaction management. 162 | 163 | // **Potential Enhancements for Codora**: 164 | 165 | // * **IoC Container**: Implement an IoC container to manage dependencies and promote modularity. 166 | // * **Security Module**: Develop a comprehensive security module for authentication and authorization. 167 | // * **Cloud-Native Tools**: Introduce tools and patterns for building cloud-native applications. 168 | // * **AOP Support**: Consider adding AOP capabilities to manage cross-cutting concerns effectively. 169 | 170 | // --- 171 | 172 | // ### **3. Elixir (Phoenix Framework)** 173 | 174 | // * **Concurrency**: Leverages the Erlang VM for high concurrency and fault tolerance. 175 | // * **Real-Time Communication**: Built-in support for WebSockets and real-time features. 176 | // * **Functional Programming**: Emphasizes a functional programming paradigm for cleaner code. 177 | // * **Hot Code Reloading**: Allows updating code without stopping the system. 178 | // * **Scalability**: Designed for building scalable and maintainable applications. 179 | 180 | // **Potential Enhancements for Codora**: 181 | 182 | // * **Concurrency Model**: Explore implementing a robust concurrency model to handle numerous simultaneous connections. 183 | // * **Functional Programming Support**: Incorporate functional programming paradigms to enhance code clarity and maintainability. 184 | // * **Hot Code Reloading**: Develop features that allow code updates without system downtime. 185 | 186 | // --- 187 | 188 | // ### **4. Next.js** 189 | 190 | // * **Hybrid Rendering**: Supports both static site generation (SSG) and server-side rendering (SSR). 191 | // * **File-Based Routing**: Automatic routing based on the file system structure. 192 | // * **API Routes**: Built-in API endpoints within the application. 193 | // * **Incremental Static Regeneration (ISR)**: Updates static content after deployment without rebuilding the entire site. 194 | // * **Image Optimization**: Automatic image optimization for faster load times. 195 | // * **Internationalization (i18n)**: Built-in support for multiple languages and locales. 196 | 197 | // **Potential Enhancements for Codora**: 198 | 199 | // * **Hybrid Rendering**: Implement support for both SSG and SSR to provide flexibility in content delivery. 200 | // * **File-Based Routing**: Introduce a file-based routing system for intuitive route management. 201 | // * **Image Optimization**: Develop automatic image optimization features to enhance performance. 202 | // * **Internationalization**: Add built-in support for i18n to cater to a global audience. 203 | 204 | // --- 205 | 206 | // ### **5. Vercel** 207 | 208 | // * **Serverless Functions**: Deploy backend functions without managing servers. 209 | // * **Edge Network**: Global edge network for fast content delivery. 210 | // * **Continuous Deployment**: Automatic deployments from Git repositories. 211 | // * **Analytics**: Built-in analytics for performance monitoring. 212 | // * **Environment Management**: Manage environment variables and settings across deployments. 213 | // * **Preview Deployments**: Generate preview URLs for testing before production release. 214 | 215 | // **Potential Enhancements for Codora**: 216 | 217 | // * **Serverless Functions**: Integrate serverless function capabilities for backend logic. 218 | // * **Edge Network Integration**: Partner with CDN providers to offer global content delivery. 219 | // * **Continuous Deployment**: Develop CI/CD pipelines for seamless deployments. 220 | // * **Built-In Analytics**: Provide analytics tools for monitoring application performance. 221 | // * **Environment Management**: Implement features to manage environment variables and configurations. 222 | // * 223 | -------------------------------------------------------------------------------- /crates/web/security/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "codora-security" 3 | version.workspace = true 4 | edition.workspace = true 5 | license.workspace = true 6 | repository.workspace = true 7 | keywords.workspace = true 8 | categories.workspace = true 9 | authors.workspace = true 10 | 11 | [features] 12 | 13 | [dependencies] 14 | futures-util = "0.3.31" 15 | http = "1.3.1" 16 | codora-core = { workspace = true } 17 | 18 | [dev-dependencies] 19 | tokio = { workspace = true, features = ["full"] } 20 | 21 | [lints] 22 | workspace = true 23 | -------------------------------------------------------------------------------- /crates/web/security/src/authentication/claim.rs: -------------------------------------------------------------------------------- 1 | use std::{borrow::Cow, collections::HashMap}; 2 | 3 | // TODO Implement other API and Study the Code well to fish out bugs or any issues! 4 | // Implement IterMut and remove function iter_all, entry and other iterator trait for state 5 | 6 | // A claim is a claim that can compose claim 7 | /* 8 | 9 | | 10 | |--| 11 | 12 | */ 13 | #[derive(Default)] 14 | pub struct Claim { 15 | value: Entry, 16 | visibility: Visibility, 17 | label: Cow<'static, str>, 18 | } 19 | 20 | #[derive(Default)] 21 | pub enum Visibility { 22 | Private, 23 | 24 | #[default] 25 | Public, 26 | } 27 | 28 | #[derive(Default)] 29 | pub enum Entry { 30 | #[default] 31 | Single, 32 | } 33 | 34 | /// # State 35 | /// Used for holding authentication state during request lifecycle 36 | /// ### Notes 37 | /// * State contain's None to avoid carrying empty Map all around 38 | #[derive(Default, Debug)] 39 | pub struct State { 40 | properties: Option>>>, 41 | } 42 | 43 | impl State { 44 | pub fn new() -> Self { 45 | State::default() 46 | } 47 | 48 | /// Add a properties into the state 49 | /// 50 | /// # Example 51 | /// 52 | /// ``` 53 | /// use codora::security::State; 54 | /// let mut state = State::new(); 55 | /// state.add("authenticated", "true"); 56 | /// state.add("members", String::from("codora")); 57 | /// state.add("name", "west"); 58 | /// assert_eq!(state.len(), 3) 59 | /// ``` 60 | pub fn add(&mut self, key: &'static str, value: V) 61 | where 62 | V: IntoIterator>, 63 | { 64 | // let map = self 65 | // .properties 66 | // .get_or_insert_with(HashMap::new); 67 | 68 | // match map.get_mut(key) { 69 | // Some(entry) => entry.extend(value.into()), 70 | // None => { 71 | // map.insert(key, value.into()); 72 | // } 73 | // } 74 | 75 | todo!() 76 | } 77 | 78 | /// Returns a mutable reference to the value corresponding to the key. 79 | /// 80 | /// # Examples 81 | /// 82 | /// ``` 83 | /// use codora::security::State; 84 | /// use codora::security::state::Entry; 85 | /// 86 | /// let mut state = State::new(); 87 | /// state.add("role", "user"); 88 | /// 89 | /// if let Some(entry) = state.get_mut("role") { 90 | /// match entry { 91 | /// Entry::Single(v) => { 92 | /// *v = "admin".into(); 93 | /// assert_eq!(v, "admin"); 94 | /// assert_ne!(v, "user"); 95 | /// }, 96 | /// _ => {} 97 | /// } 98 | /// } 99 | /// ``` 100 | pub fn get_mut(&mut self, key: &'static str) -> Option<&mut Vec>> { 101 | // self.properties 102 | // .as_mut() 103 | // .and_then(|props| props.get_mut(key)) 104 | 105 | todo!() 106 | } 107 | 108 | /// Returns a reference to the value corresponding to the key. 109 | /// 110 | /// # Examples 111 | /// 112 | /// ``` 113 | /// use codora::security::State; 114 | /// use codora::security::state::Entry; 115 | /// 116 | /// let mut state = State::new(); 117 | /// state.add("role", "user"); 118 | /// 119 | /// if let Some(entry) = state.get_mut("role") { 120 | /// match entry { 121 | /// Entry::Single(v) => { 122 | /// assert_eq!(v, "user"); 123 | /// }, 124 | /// _ => {} 125 | /// } 126 | /// } 127 | /// ``` 128 | // pub fn get(&self, key: &'static str) -> Option<&Entry> { 129 | // self.properties 130 | // .as_ref() 131 | // .and_then(|props| props.get(key)) 132 | // } 133 | 134 | /// Returns true if the map contains a value for the specified key. 135 | /// 136 | /// The key may be any borrowed form of the map's key type, but Hash and Eq 137 | /// on the borrowed form must match those for the key type. 138 | /// 139 | /// # Examples 140 | /// 141 | /// ``` 142 | /// use codora::security::State; 143 | /// 144 | /// let mut state = State::new(); 145 | /// state.add("authenticated", "true"); 146 | /// assert_eq!(state.contains_key("authenticated"), true); 147 | /// ``` 148 | // pub fn contains_key(&self, k: &'static str) -> bool { 149 | // self.properties 150 | // .as_ref() 151 | // .map_or(false, |properties| properties.contains_key(k)) 152 | // } 153 | 154 | /// Check whether the state is empty or not. 155 | /// 156 | /// # Example 157 | /// 158 | /// ``` 159 | /// use codora::security::State; 160 | /// let mut state = State::new(); 161 | /// assert!(state.is_empty()); 162 | /// state.add("authenticated", "true"); 163 | /// assert!(!state.is_empty()) 164 | /// ``` 165 | #[inline] 166 | pub fn is_empty(&self) -> bool { 167 | self.properties 168 | .as_ref() 169 | .map_or(true, |properties| properties.is_empty()) 170 | } 171 | 172 | /// Get the len of the state. 173 | /// 174 | /// # Example 175 | /// 176 | /// ``` 177 | /// use codora::security::State; 178 | /// let mut state = State::new(); 179 | /// assert_eq!(state.len(), 0); 180 | /// state.add("authenticated", "true"); 181 | /// assert_eq!(state.len(), 1) 182 | /// ``` 183 | #[inline] 184 | pub fn len(&self) -> usize { 185 | self.properties 186 | .as_ref() 187 | .map_or(0, |properties| properties.len()) 188 | } 189 | 190 | /// Clear the `State`. 191 | /// 192 | /// # Example 193 | /// 194 | /// ``` 195 | /// # use codora::security::State; 196 | /// let mut state = State::new(); 197 | /// state.add("authenticated", "true"); 198 | /// state.clear(); 199 | /// assert!(state.is_empty()) 200 | /// ``` 201 | #[inline] 202 | pub fn clear(&mut self) { 203 | if let Some(ref mut properties) = self.properties { 204 | properties.clear(); 205 | } 206 | } 207 | } 208 | 209 | /// Implements the [`Index`] trait to allow indexing into a [`State`] using string literals. 210 | /// 211 | /// # Examples 212 | /// 213 | /// ``` 214 | /// use codora::security::State; 215 | /// use codora::security::state::Entry; 216 | /// 217 | /// let mut state = State::new(); 218 | /// state.add("key", "value"); 219 | /// 220 | /// // Access value using index notation 221 | /// // assert_eq!(&state["key"], &Entry::Single("new_value".into())); 222 | /// ``` 223 | /// 224 | /// # Panics 225 | /// 226 | /// Panics if the key does not exist in the state. 227 | /// Consider using [`State::get`] if you want to handle missing keys gracefully. 228 | // impl Index<&'static str> for State { 229 | // type Output = Entry; 230 | 231 | // fn index(&self, index: &'static str) -> &Self::Output { 232 | // self.get(index).unwrap() 233 | // } 234 | // } 235 | 236 | /// Implements the [`IndexMut`] trait to allow mutable indexing into a [`State`] using string literals. 237 | /// 238 | /// # Examples 239 | /// 240 | /// ``` 241 | /// use codora::security::State; 242 | /// use codora::security::state::Entry; 243 | /// 244 | /// let mut state = State::new(); 245 | /// state.add("key", "value"); 246 | /// 247 | /// // Modify value using mutable index notation 248 | /// state["key"] = Entry::Single("new_value".into()); 249 | /// // assert_eq!(&state["key"], &Entry::Single("new_value".into())) 250 | /// ``` 251 | /// 252 | /// # Panics 253 | /// 254 | /// Panics if the key does not exist in the state. 255 | /// Consider using [`State::get_mut`] if you want to handle missing keys gracefully. 256 | // impl IndexMut<&'static str> for State { 257 | // #[inline] 258 | // fn index_mut(&mut self, index: &'static str) -> &mut Self::Output { 259 | // // Using unwrap is intentional here as index operations are meant to panic on missing keys 260 | // self.get_mut(index) 261 | // .expect("no entry found for key") 262 | // } 263 | // } 264 | 265 | #[cfg(test)] 266 | mod test { 267 | #[allow(unused_imports)] 268 | use super::State; 269 | 270 | #[test] 271 | fn test() { 272 | // let value = String::new(); 273 | // let mut state = State::new(); 274 | 275 | // state.add("add", "+"); 276 | // state.add("add", "plus"); 277 | // state.add("add", vec!["hey"]); 278 | // state.add("add", "plus".to_string()); 279 | // state.add("add", vec!["hey".to_string()]); 280 | 281 | // let test_index = &mut state["add"]; 282 | 283 | // println!("{:?}", test_index); 284 | // println!("{:?}", state); 285 | } 286 | } 287 | -------------------------------------------------------------------------------- /crates/web/security/src/authentication/handler/bearer/mod.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getcodora/codora/acef29043e69271790186913c6c5b030dada6bf0/crates/web/security/src/authentication/handler/bearer/mod.rs -------------------------------------------------------------------------------- /crates/web/security/src/authentication/handler/cookie/mod.rs: -------------------------------------------------------------------------------- 1 | // use crate::authentication::Authentication; 2 | 3 | // pub struct CookieOption {} 4 | 5 | // pub trait CookieAuthenticationExt { 6 | // fn add_cookie(self, func: F) -> Self 7 | // where 8 | // F: Fn(&Authentication) -> CookieOption; 9 | // } 10 | 11 | // impl CookieAuthenticationExt for Authentication { 12 | // fn add_cookie(self, func: F) -> Self 13 | // where 14 | // F: Fn(&Authentication) -> CookieOption, 15 | // { 16 | // let opt = func(&self); 17 | 18 | // todo!() 19 | // } 20 | // } 21 | -------------------------------------------------------------------------------- /crates/web/security/src/authentication/handler/jwt/mod.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getcodora/codora/acef29043e69271790186913c6c5b030dada6bf0/crates/web/security/src/authentication/handler/jwt/mod.rs -------------------------------------------------------------------------------- /crates/web/security/src/authentication/handler/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod bearer; 2 | pub(crate) mod cookie; 3 | pub(crate) mod jwt; 4 | pub(crate) mod oauth; 5 | 6 | use std::future::Future; 7 | 8 | use super::{Context, claim::Claim}; 9 | 10 | pub trait Handler { 11 | type Error; 12 | 13 | /// The name of the handler 14 | /// This is used to identify the handler in logs and other contexts 15 | const NAME: &'static str; 16 | 17 | /// Authenticate the current request 18 | /// 19 | /// This method is called to authenticate the current request 20 | fn authenticate(&self, contex: &Context, claim: &Claim) -> impl Future> + Send; 21 | 22 | /// Forbid the current request 23 | /// 24 | /// This method is called to forbid the current request 25 | /// 26 | /// # Arguments 27 | /// `state` - The current state of the request `S` 28 | fn forbid(&self, contex: &Context, claim: &Claim) -> impl Future> + Send; 29 | 30 | /// Challenge the current request 31 | /// 32 | /// This method is called to challenge the current request 33 | /// 34 | /// # Arguments 35 | /// `state` - The current state of the request `Self::State` 36 | fn challenge(&self, contex: &Context, claim: &Claim) -> impl Future> + Send; 37 | } 38 | 39 | pub mod handler { 40 | use crate::authentication::{Context, claim::Claim}; 41 | 42 | pub struct Handler { 43 | handler: H, 44 | } 45 | 46 | impl Handler { 47 | async fn sign_out(&self, req: &Context, claim: &Claim) -> Result<(), H::Error> 48 | where 49 | H: super::Handler, 50 | { 51 | // Delegate the Request to the handler 52 | todo!() 53 | } 54 | } 55 | } 56 | 57 | pub mod sign_in { 58 | use super::sign_out::SignOutHandler; 59 | use crate::authentication::{Context, claim::Claim}; 60 | use std::future::Future; 61 | 62 | pub trait SignInHandler: SignOutHandler { 63 | type Success; 64 | 65 | fn sign_in(&self, contex: &Context, claim: &Claim) -> impl Future> + Send; 66 | } 67 | 68 | /* 69 | We want the api to be like 70 | 71 | // Sign in can create it self from request part via state a state populated when the application starts and shared among the request 72 | // SignIn works with any T as long as T::Option is in State which would be used to create T 73 | async fn get_users(sign_in_ctx: SignIn, claim: Context) -> Response { 74 | let claim = Claim::default(); 75 | let res = sign_in_ctx.sign_in(context, claim).await?; 76 | 77 | Ok(res) 78 | } 79 | */ 80 | #[derive(Clone)] 81 | pub struct SignIn { 82 | handler: H, 83 | // Other Stuff goes in here 84 | } 85 | 86 | impl SignIn { 87 | async fn sign_in(&self, req: &Context, claim: &Claim) -> Result 88 | where 89 | H: SignInHandler, 90 | { 91 | // Delegate the Request to the handler 92 | todo!() 93 | } 94 | } 95 | } 96 | // 97 | pub mod sign_out { 98 | use crate::authentication::{Context, claim::Claim, handler::Handler}; 99 | use std::future::Future; 100 | 101 | pub trait SignOutHandler: Handler { 102 | fn sign_out(&self, ctx: Context, claim: &Claim) -> impl Future> + Send; 103 | } 104 | 105 | #[derive(Clone)] 106 | pub struct SignOut { 107 | handler: H, 108 | // Other Stuff goes in here 109 | } 110 | 111 | impl SignOut { 112 | async fn sign_out(&self, req: &Context, claim: &Claim) -> Result<(), H::Error> 113 | where 114 | H: SignOutHandler, 115 | { 116 | // Delegate the Request to the handler 117 | todo!() 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /crates/web/security/src/authentication/handler/oauth/mod.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/getcodora/codora/acef29043e69271790186913c6c5b030dada6bf0/crates/web/security/src/authentication/handler/oauth/mod.rs -------------------------------------------------------------------------------- /crates/web/security/src/authentication/mod.rs: -------------------------------------------------------------------------------- 1 | use claim::Claim; 2 | use codora_core::new; 3 | use std::sync::{Arc, RwLock}; 4 | 5 | pub mod claim; 6 | pub mod handler; 7 | 8 | // Replace this with state! we want something that could store any T like extension used in http::Extension! 9 | /* 10 | All the state added in this layer are transient which means it's shared among request 11 | tapped into request run authenticate which populate the context claim! 12 | let auth = AuthenticationBuilder::new(/Some State/) 13 | .add_cookie() 14 | .add_jwt() 15 | .add_state(|state| state.add(String::new())) 16 | */ 17 | // THis state should be shared among Context you see 18 | 19 | pub struct State {} 20 | 21 | pub struct AuthenticationBuilder { 22 | handler: Option>, 23 | } 24 | 25 | // Hot context created on every Request so each Request has it's own context 26 | #[derive(Clone, new)] 27 | pub struct Context { 28 | state: Arc, 29 | claim: Arc>, 30 | request: Request, 31 | } 32 | 33 | #[cfg(test)] 34 | mod test { 35 | 36 | #[tokio::test] 37 | async fn test_context() {} 38 | } 39 | -------------------------------------------------------------------------------- /crates/web/security/src/authorization/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /crates/web/security/src/identity/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /crates/web/security/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![forbid(unsafe_code)] 2 | // Silence the noise in development! 3 | #![cfg_attr(debug_assertions, allow(dead_code, unused_variables))] 4 | // Docs and linting rules 5 | #![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg))] 6 | #![cfg_attr(test, allow(clippy::float_cmp))] 7 | #![cfg_attr(not(test), deny(clippy::print_stdout, clippy::dbg_macro))] 8 | // - Lint for missing docs 9 | #![cfg_attr(not(debug_assertions), deny(missing_docs))] 10 | 11 | // TODO fix this later to export nicely! 12 | pub mod authentication; 13 | pub mod authorization; 14 | mod identity; -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Codora Examples 2 | 3 | This will ocntains all codora examples 4 | -------------------------------------------------------------------------------- /modules/README.md: -------------------------------------------------------------------------------- 1 | # Codora 2 | 3 | Python modules for codora-py 4 | -------------------------------------------------------------------------------- /packages/README.md: -------------------------------------------------------------------------------- 1 | # Codora 2 | 3 | Javascript Packages for codora-js 4 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | array_width = 100 2 | attr_fn_like_width = 120 3 | chain_width = 40 4 | fn_call_width = 120 5 | fn_params_layout = "Compressed" 6 | max_width = 140 7 | merge_derives = true 8 | remove_nested_parens = true 9 | reorder_imports = true 10 | reorder_modules = true 11 | short_array_element_width_threshold = 100 12 | single_line_if_else_max_width = 40 13 | single_line_let_else_max_width = 40 14 | tab_spaces = 4 15 | use_field_init_shorthand = true 16 | --------------------------------------------------------------------------------