Skip to content

Commit 2174683

Browse files
authored
[DEVEX-2333]: Implement caching using dynamo (#183)
1 parent da1935e commit 2174683

29 files changed

+874
-380
lines changed

.github/workflows/ci.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@ jobs:
2121
- run: cargo make deny-check
2222
- run: cargo make docs
2323
test:
24+
services:
25+
aws:
26+
image: public.ecr.aws/localstack/localstack:4
27+
ports:
28+
- "4566:4566"
29+
env:
30+
AWS_ACCESS_KEY_ID: test
31+
AWS_SECRET_ACCESS_KEY: test
32+
AWS_ENDPOINT_URL: http://localhost:4566
33+
AWS_REGION: eu-west-1
2434
# Avoid duplicate jobs on PR from a branch on the same repo
2535
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name
2636
runs-on: ubuntu-latest

.rustfmt.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
edition = "2021"
12
reorder_imports = true
23
reorder_modules = true
34
max_width = 120

CHANGELOG.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,22 @@ and this project adheres to
1010

1111
---
1212

13+
## [0.21.0] - 2025-02-10
14+
15+
# Fixed
16+
17+
- Fixed docs.rs not building the documentation
18+
19+
# Deprecated
20+
21+
- Deprecated a lot of old auth0 APIs. See the docs for alternatives to use.
22+
23+
# Added
24+
25+
- DynamoDB cache provider
26+
27+
---
28+
1329
## [0.20.0] - 2024-12-02
1430

1531
### Added
@@ -496,7 +512,9 @@ Request::rest(&bridge).send()
496512

497513
The old API is still available but deprecated. It will be removed soon.
498514

499-
[Unreleased]: https://github.com/primait/bridge.rs/compare/0.20.0...HEAD
515+
516+
[Unreleased]: https://github.com/primait/bridge.rs/compare/0.21.0...HEAD
517+
[0.21.0]: https://github.com/primait/bridge.rs/compare/0.20.0...0.21.0
500518
[0.20.0]: https://github.com/primait/bridge.rs/compare/0.19.0...0.20.0
501519
[0.19.0]: https://github.com/primait/bridge.rs/compare/0.18.0...0.19.0
502520
[0.18.0]: https://github.com/primait/bridge.rs/compare/0.17.0...0.18.0

Cargo.toml

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@ license = "MIT"
66
name = "prima_bridge"
77
readme = "README.md"
88
repository = "https://github.com/primait/bridge.rs"
9-
version = "0.20.0"
9+
version = "0.21.0"
1010
# See https://github.com/rust-lang/rust/issues/107557
11-
rust-version = "1.72"
11+
rust-version = "1.81"
1212

1313
[features]
1414
default = ["tracing_opentelemetry"]
1515

16+
# Feature set that should be used
17+
# This exists to avoid compatibility issues with otel version conflicts
18+
_docs = ["auth0", "cache-dynamodb", "grpc", "gzip", "redis-tls", "tracing_opentelemetry"]
19+
1620
auth0 = [
1721
"rand",
1822
"redis",
@@ -22,9 +26,12 @@ auth0 = [
2226
"dashmap",
2327
"tracing",
2428
]
25-
grpc = ["tonic"]
29+
grpc = [ "_any_otel_version", "tonic"]
2630
gzip = ["reqwest/gzip"]
27-
redis-tls = ["redis/tls", "redis/tokio-native-tls-comp"]
31+
32+
redis-tls = [ "redis", "redis/tls", "redis/tokio-native-tls-comp"]
33+
cache-dynamodb = [ "aws-sdk-dynamodb" ]
34+
2835
tracing_opentelemetry = ["tracing_opentelemetry_0_27"]
2936

3037
tracing_opentelemetry_0_21 = [
@@ -102,6 +109,7 @@ tonic = { version = "0.12", default-features = false, optional = true }
102109
tracing = { version = "0.1", optional = true }
103110
uuid = { version = ">=0.7.0, <2.0.0", features = ["serde", "v4"] }
104111
chacha20poly1305 = { version = "0.10.1", features = ["std"], optional = true }
112+
aws-sdk-dynamodb = { version = "1.63", optional = true }
105113

106114
reqwest-middleware = { version = "0.4.0", features = ["json", "multipart"] }
107115
http = "1.0.0"
@@ -129,6 +137,7 @@ tracing-opentelemetry_0_27_pkg = { package = "tracing-opentelemetry", version =
129137
tracing-opentelemetry_0_28_pkg = { package = "tracing-opentelemetry", version = "0.28", optional = true }
130138

131139
[dev-dependencies]
140+
aws-config = { version = "1.5.16", features = ["behavior-version-latest"] }
132141
flate2 = "1.0"
133142
mockito = "1.0"
134143
tokio = { version = "1.16", features = ["macros", "rt-multi-thread"] }
@@ -139,7 +148,11 @@ codegen-units = 1
139148
lto = "thin"
140149

141150
[package.metadata.docs.rs]
142-
all-features = true
151+
all-features = false
152+
# Avoid opentelemetry version conflicts
153+
features = [
154+
"_docs"
155+
]
143156
rustdoc-args = ["--cfg", "docsrs"]
144157

145158
[[example]]

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM rust:1.72
1+
FROM rust:1.81
22

33
WORKDIR /code
44

Makefile.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ dependencies = ["build"]
4242

4343
[tasks.test-auth0]
4444
command = "cargo"
45-
args = ["test", "--features=auth0,gzip", "${@}"]
45+
args = ["test", "--features=auth0,gzip,cache-dynamodb", "${@}"]
4646
dependencies = ["build"]
4747

4848
[tasks.test-all-otel-versions]
@@ -80,7 +80,7 @@ dependencies = ["build"]
8080
command = "cargo"
8181
args = [
8282
"clippy",
83-
"--features=auth0,gzip",
83+
"--features=auth0,cache-dynamodb,gzip",
8484
"--all-targets",
8585
"--",
8686
"-D",

docker-compose.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ services:
88
CARGO_HOME: /home/app/.cargo
99
CARGO_TARGET_DIR: /home/app/target
1010
CARGO_MAKE_DISABLE_UPDATE_CHECK: 1
11+
AWS_ACCESS_KEY_ID: test
12+
AWS_SECRET_ACCESS_KEY: test
13+
AWS_ENDPOINT_URL: http://aws:4566
14+
AWS_REGION: eu-west-1
1115
volumes:
1216
- ".:/code"
1317
- "app:/home/app/"
@@ -17,6 +21,12 @@ services:
1721
- "~/.gitignore:/home/app/.gitignore"
1822
tty: true
1923
stdin_open: true
24+
depends_on:
25+
- aws
26+
aws:
27+
image: public.ecr.aws/localstack/localstack:4
28+
ports:
29+
- "4566:4566"
2030

2131
volumes:
2232
app:

examples/auth0.rs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ const QUERY: &str = "query($input:JobsInput!){jobs(input:$input) {\nid\n title\n
3535
#[tokio::main]
3636
async fn main() {
3737
let bridge: Bridge = Bridge::builder()
38-
.with_auth0(auth0::config())
38+
.with_refreshing_token(auth0::refreshing_token().await)
3939
.await
4040
.build(URL.parse().unwrap());
4141

@@ -113,30 +113,30 @@ pub struct Job {
113113
mod auth0 {
114114
use std::time::Duration;
115115

116-
use prima_bridge::auth0::{CacheType, Config, StalenessCheckPercentage};
117-
118-
pub fn config() -> Config {
119-
use reqwest::Url;
120-
use std::str::FromStr;
116+
use prima_bridge::auth0::{cache::InMemoryCache, Auth0Client, RefreshingToken, StalenessCheckPercentage};
121117

118+
pub async fn refreshing_token() -> RefreshingToken {
122119
let token_url: String = std::env::var("TOKEN_URL").unwrap();
123-
let jwks_url: String = std::env::var("JWKS_URL").unwrap();
124120
let client_id: String = std::env::var("CLIENT_ID").unwrap();
125121
let client_secret: String = std::env::var("CLIENT_SECRET").unwrap();
126122
let audience: String = std::env::var("AUDIENCE").unwrap();
127123

128-
Config {
129-
token_url: Url::from_str(token_url.as_str()).unwrap(),
130-
jwks_url: Url::from_str(jwks_url.as_str()).unwrap(),
131-
caller: "paperboy".to_string(),
132-
audience,
133-
cache_type: CacheType::Inmemory,
134-
token_encryption_key: "32char_long_token_encryption_key".to_string(),
135-
check_interval: Duration::from_secs(2),
136-
staleness_check_percentage: StalenessCheckPercentage::new(0.1, 0.5),
124+
let auth0_client = Auth0Client::new(
125+
token_url.parse().unwrap(),
126+
reqwest::Client::default(),
137127
client_id,
138128
client_secret,
139-
scope: Some("profile email".to_string()),
140-
}
129+
);
130+
131+
RefreshingToken::new(
132+
auth0_client,
133+
Duration::from_secs(10),
134+
StalenessCheckPercentage::default(),
135+
Box::new(InMemoryCache::default()),
136+
audience,
137+
None,
138+
)
139+
.await
140+
.unwrap()
141141
}
142142
}

src/auth0/cache/crypto.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,17 @@ use chacha20poly1305::{aead::Aead, AeadCore, KeyInit, XChaCha20Poly1305};
22
use rand::thread_rng;
33
use serde::{Deserialize, Serialize};
44

5-
use crate::auth0::errors::Auth0Error;
6-
75
const NONCE_SIZE: usize = 24;
86

9-
pub fn encrypt<T: Serialize>(value_ref: &T, token_encryption_key_str: &str) -> Result<Vec<u8>, Auth0Error> {
7+
#[derive(thiserror::Error, Debug)]
8+
pub enum CryptoError {
9+
#[error(transparent)]
10+
Serde(#[from] serde_json::Error),
11+
#[error(transparent)]
12+
ChaCha20Poly1305(#[from] chacha20poly1305::Error),
13+
}
14+
15+
pub fn encrypt<T: Serialize>(value_ref: &T, token_encryption_key_str: &str) -> Result<Vec<u8>, CryptoError> {
1016
let json: String = serde_json::to_string(value_ref)?;
1117

1218
let enc = XChaCha20Poly1305::new_from_slice(token_encryption_key_str.as_bytes()).unwrap();
@@ -18,7 +24,7 @@ pub fn encrypt<T: Serialize>(value_ref: &T, token_encryption_key_str: &str) -> R
1824
Ok(ciphertext)
1925
}
2026

21-
pub fn decrypt<T>(token_encryption_key_str: &str, encrypted: &[u8]) -> Result<T, Auth0Error>
27+
pub fn decrypt<T>(token_encryption_key_str: &str, encrypted: &[u8]) -> Result<T, CryptoError>
2228
where
2329
for<'de> T: Deserialize<'de>,
2430
{
@@ -28,7 +34,7 @@ where
2834
let nonce = encrypted.get(encrypted.len() - NONCE_SIZE..);
2935

3036
let (Some(ciphertext), Some(nonce)) = (ciphertext, nonce) else {
31-
return Err(Auth0Error::CryptoError(chacha20poly1305::Error));
37+
return Err(CryptoError::ChaCha20Poly1305(chacha20poly1305::Error));
3238
};
3339

3440
let nonce = chacha20poly1305::XNonce::from_slice(nonce);

0 commit comments

Comments
 (0)