Compare commits

...
Author SHA1 Message Date
kasisnu dd1007fa26 updated deps lockfile/hakari crate 2023-12-11 12:40:46 +05:30
kasisnu d372ac3a41 make billing an optional dependency for local dev 2023-12-11 12:38:43 +05:30
kasisnu ba99be7081 openssl remove native on x86 2023-12-11 12:36:32 +05:30
15 changed files with 585 additions and 503 deletions
Generated
+364 -330
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -22,7 +22,7 @@ my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
serde = "1.0.125"
serde_derive = "1.0.125"
sqlx = { version = "0.7.2", features = [ "mysql", "sqlite", "runtime-tokio-native-tls", "chrono" ] }
sqlx = { version = "0.7.2", features = ["mysql", "runtime-tokio", "tls-rustls", "chrono" ] }
sqlx-core = { version = "0.7.2" }
sqlx-mysql= { version = "0.7.2" }
@@ -26,8 +26,7 @@ log = "0.4.14"
# The "never-encode-slash" feature seems to have been removed:
# https://github.com/durch/rust-s3/pull/254
rust-s3 = { version = "0.33.0" }
rust-s3 = { version = "0.33.0" , default-features = false, features = ["tokio-rustls-tls"] }
# Runtime
# NB: We switched to Tokio from `async-std` for broader ecosystem support.
tokio = { version = "1.6.0", features = ["macros"] }
+1 -2
View File
@@ -17,5 +17,4 @@ errors = { path = "../errors" }
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
# External
lettre = "0.11.2"
lettre = { version = "0.11.2" , default-features = false, features = ["tokio1-rustls-tls","smtp-transport", "pool", "hostname", "builder"] }
+31 -46
View File
@@ -16,7 +16,6 @@ publish = false
[dependencies]
actix-rt = { version = "2.9.0" }
ahash = { version = "0.8.6" }
base64 = { version = "0.21.5" }
base64ct = { version = "1.6.0", default-features = false, features = ["alloc"] }
bitflags = { version = "2.4.1", default-features = false, features = ["serde", "std"] }
block-buffer = { version = "0.9.0", default-features = false, features = ["block-padding"] }
@@ -25,58 +24,54 @@ byteorder = { version = "1.5.0" }
chrono = { version = "0.4.31", features = ["alloc", "serde"] }
combine = { version = "4.6.6", default-features = false, features = ["std", "tokio"] }
crossbeam-utils = { version = "0.8.16" }
deranged = { version = "0.3.9", default-features = false, features = ["powerfmt", "serde", "std"] }
deranged = { version = "0.3.10", default-features = false, features = ["powerfmt", "serde", "std"] }
digest = { version = "0.10.7", features = ["mac", "oid", "std"] }
either = { version = "1.9.0", features = ["serde"] }
flate2 = { version = "1.0.28" }
flume = { version = "0.11.0", default-features = false, features = ["async"] }
futures = { version = "0.3.29", features = ["thread-pool"] }
futures-channel = { version = "0.3.29", features = ["sink"] }
futures-core = { version = "0.3.29" }
futures-executor = { version = "0.3.29", features = ["thread-pool"] }
futures-executor = { version = "0.3.29", default-features = false, features = ["thread-pool"] }
futures-io = { version = "0.3.29" }
futures-sink = { version = "0.3.29" }
futures-util = { version = "0.3.29", features = ["channel", "io", "sink"] }
generic-array = { version = "0.14.7", default-features = false, features = ["more_lengths"] }
getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2.11", default-features = false, features = ["std"] }
getrandom-c65f7effa3be6d31 = { package = "getrandom", version = "0.1.16", default-features = false, features = ["std"] }
hashbrown = { version = "0.14.2", features = ["raw"] }
hashbrown = { version = "0.14.3", features = ["raw"] }
hmac = { version = "0.12.1", default-features = false, features = ["reset"] }
hyper = { version = "0.14.27", features = ["client", "http1", "http2", "runtime", "server"] }
indexmap = { version = "2.1.0", features = ["serde"] }
lazy_static = { version = "1.4.0", default-features = false, features = ["spin_no_std"] }
libc = { version = "0.2.150", features = ["extra_traits"] }
libc = { version = "0.2.151", features = ["extra_traits"] }
log = { version = "0.4.20", default-features = false, features = ["std"] }
memchr = { version = "2.6.4", features = ["use_std"] }
miniz_oxide = { version = "0.7.1", features = ["simd"] }
mio = { version = "0.8.9", features = ["net", "os-ext"] }
mio = { version = "0.8.10", features = ["net", "os-ext"] }
native-tls = { version = "0.2.11", default-features = false, features = ["vendored"] }
num-integer = { version = "0.1.45", features = ["i128"] }
num-iter = { version = "0.1.43" }
num-traits = { version = "0.2.17", features = ["i128", "libm"] }
once_cell = { version = "1.18.0", features = ["unstable"] }
once_cell = { version = "1.19.0", features = ["unstable"] }
rand = { version = "0.8.5", features = ["small_rng"] }
rand_core = { version = "0.6.4", default-features = false, features = ["std"] }
regex = { version = "1.10.2" }
regex-automata = { version = "0.4.3", default-features = false, features = ["dfa-onepass", "hybrid", "meta", "nfa-backtrack", "perf-inline", "perf-literal", "unicode"] }
regex-syntax = { version = "0.8.2" }
reqwest = { version = "0.11.22", features = ["gzip", "json", "native-tls", "stream"] }
reqwest = { version = "0.11.22", features = ["blocking", "gzip", "json", "native-tls", "rustls-tls", "stream"] }
rustls = { version = "0.21.10", features = ["dangerous_configuration"] }
serde = { version = "1.0.193", features = ["alloc", "derive", "rc"] }
serde_json = { version = "1.0.108", features = ["raw_value"] }
sha1 = { version = "0.10.6" }
sha2 = { version = "0.10.8" }
simd-adler32 = { version = "0.3.7" }
socket2 = { version = "0.5.5", default-features = false, features = ["all"] }
sqlx = { version = "0.7.3", features = ["chrono", "mysql", "runtime-tokio-native-tls", "sqlite", "tls-rustls"] }
sqlx-core = { version = "0.7.3", features = ["_rt-tokio", "_tls-native-tls", "_tls-rustls", "any", "chrono", "json", "migrate", "offline"] }
sqlx-mysql = { version = "0.7.3", default-features = false, features = ["any", "chrono", "json", "migrate", "offline"] }
sqlx-sqlite = { version = "0.7.3", default-features = false, features = ["any", "chrono", "json", "migrate", "offline"] }
time = { version = "0.3.30", features = ["macros", "serde-well-known"] }
tokio = { version = "1.34.0", features = ["full"] }
tokio = { version = "1.35.0", features = ["full"] }
tokio-rustls = { version = "0.24.1" }
tokio-stream = { version = "0.1.14", features = ["fs"] }
tracing = { version = "0.1.40", features = ["log"] }
twitch_oauth2 = { version = "0.6.1", features = ["reqwest_client"] }
unicode-bidi = { version = "0.3.13" }
unicode-bidi = { version = "0.3.14" }
unicode-normalization = { version = "0.1.22" }
url = { version = "2.5.0", features = ["serde"] }
void = { version = "1.0.2" }
@@ -84,100 +79,90 @@ zip = { version = "0.6.6" }
[build-dependencies]
ahash = { version = "0.8.6" }
base64 = { version = "0.21.5" }
base64ct = { version = "1.6.0", default-features = false, features = ["alloc"] }
bitflags = { version = "2.4.1", default-features = false, features = ["serde", "std"] }
byteorder = { version = "1.5.0" }
cc = { version = "1.0.83", default-features = false, features = ["parallel"] }
chrono = { version = "0.4.31", features = ["alloc", "serde"] }
crossbeam-utils = { version = "0.8.16" }
deranged = { version = "0.3.9", default-features = false, features = ["powerfmt", "serde", "std"] }
deranged = { version = "0.3.10", default-features = false, features = ["powerfmt", "serde", "std"] }
derive_more = { version = "0.99.17" }
digest = { version = "0.10.7", features = ["mac", "oid", "std"] }
either = { version = "1.9.0", features = ["serde"] }
flate2 = { version = "1.0.28" }
flume = { version = "0.11.0", default-features = false, features = ["async"] }
futures-channel = { version = "0.3.29", features = ["sink"] }
futures-core = { version = "0.3.29" }
futures-executor = { version = "0.3.29", features = ["thread-pool"] }
futures-io = { version = "0.3.29" }
futures-sink = { version = "0.3.29" }
futures-util = { version = "0.3.29", features = ["channel", "io", "sink"] }
generic-array = { version = "0.14.7", default-features = false, features = ["more_lengths"] }
getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2.11", default-features = false, features = ["std"] }
hashbrown = { version = "0.14.2", features = ["raw"] }
hashbrown = { version = "0.14.3", features = ["raw"] }
heck = { version = "0.4.1", features = ["unicode"] }
hmac = { version = "0.12.1", default-features = false, features = ["reset"] }
indexmap = { version = "2.1.0", features = ["serde"] }
lazy_static = { version = "1.4.0", default-features = false, features = ["spin_no_std"] }
libc = { version = "0.2.150", features = ["extra_traits"] }
libc = { version = "0.2.151", features = ["extra_traits"] }
log = { version = "0.4.20", default-features = false, features = ["std"] }
memchr = { version = "2.6.4", features = ["use_std"] }
miniz_oxide = { version = "0.7.1", features = ["simd"] }
mio = { version = "0.8.9", features = ["net", "os-ext"] }
native-tls = { version = "0.2.11", default-features = false, features = ["vendored"] }
mio = { version = "0.8.10", features = ["net", "os-ext"] }
num-integer = { version = "0.1.45", features = ["i128"] }
num-iter = { version = "0.1.43" }
num-traits = { version = "0.2.17", features = ["i128", "libm"] }
once_cell = { version = "1.18.0", features = ["unstable"] }
once_cell = { version = "1.19.0", features = ["unstable"] }
rand = { version = "0.8.5", features = ["small_rng"] }
rand_core = { version = "0.6.4", default-features = false, features = ["std"] }
regex = { version = "1.10.2" }
regex-automata = { version = "0.4.3", default-features = false, features = ["dfa-onepass", "hybrid", "meta", "nfa-backtrack", "perf-inline", "perf-literal", "unicode"] }
regex-syntax = { version = "0.8.2" }
rustls = { version = "0.21.10", features = ["dangerous_configuration"] }
serde = { version = "1.0.193", features = ["alloc", "derive", "rc"] }
serde_json = { version = "1.0.108", features = ["raw_value"] }
sha1 = { version = "0.10.6" }
sha2 = { version = "0.10.8" }
simd-adler32 = { version = "0.3.7" }
sqlx-core = { version = "0.7.3", features = ["_rt-tokio", "_tls-native-tls", "_tls-rustls", "any", "chrono", "json", "migrate", "offline"] }
sqlx-macros = { version = "0.7.3", features = ["_rt-tokio", "_tls-native-tls", "_tls-rustls", "chrono", "json", "migrate", "mysql", "sqlite"] }
sqlx-macros-core = { version = "0.7.3", features = ["_rt-tokio", "_tls-native-tls", "_tls-rustls", "chrono", "json", "migrate", "mysql", "sqlite"] }
sqlx-mysql = { version = "0.7.3", default-features = false, features = ["any", "chrono", "json", "migrate", "offline"] }
sqlx-sqlite = { version = "0.7.3", default-features = false, features = ["any", "chrono", "json", "migrate", "offline"] }
syn-dff4ba8e3ae991db = { package = "syn", version = "1.0.109", features = ["extra-traits", "fold", "full", "visit-mut"] }
syn-f595c2ba2a3f28df = { package = "syn", version = "2.0.39", features = ["extra-traits", "fold", "full", "visit", "visit-mut"] }
syn-f595c2ba2a3f28df = { package = "syn", version = "2.0.40", features = ["extra-traits", "fold", "full", "visit", "visit-mut"] }
time = { version = "0.3.30", features = ["macros", "serde-well-known"] }
time-macros = { version = "0.2.15", default-features = false, features = ["formatting", "parsing", "serde"] }
tokio = { version = "1.34.0", features = ["full"] }
tokio = { version = "1.35.0", features = ["full"] }
tokio-stream = { version = "0.1.14", features = ["fs"] }
tracing = { version = "0.1.40", features = ["log"] }
unicode-bidi = { version = "0.3.13" }
unicode-bidi = { version = "0.3.14" }
unicode-normalization = { version = "0.1.22" }
url = { version = "2.5.0", features = ["serde"] }
zip = { version = "0.6.6" }
[target.x86_64-unknown-linux-gnu.dependencies]
openssl = { version = "0.10.60", features = ["vendored"] }
openssl-sys = { version = "0.9.96", default-features = false, features = ["vendored"] }
rustix = { version = "0.38.26", features = ["fs", "termios"] }
hyper-rustls = { version = "0.24.2", default-features = false, features = ["http1", "http2", "logging", "tls12", "webpki-tokio"] }
openssl = { version = "0.10.61", features = ["vendored"] }
openssl-sys = { version = "0.9.97", default-features = false, features = ["vendored"] }
rustix = { version = "0.38.28", features = ["fs", "termios"] }
spin = { version = "0.9.8" }
[target.x86_64-unknown-linux-gnu.build-dependencies]
openssl = { version = "0.10.60", features = ["vendored"] }
openssl-sys = { version = "0.9.96", default-features = false, features = ["vendored"] }
rustix = { version = "0.38.26", features = ["fs", "termios"] }
socket2 = { version = "0.5.5", default-features = false, features = ["all"] }
rustix = { version = "0.38.28", features = ["fs", "termios"] }
spin = { version = "0.9.8" }
[target.x86_64-apple-darwin.dependencies]
rustix = { version = "0.38.26", features = ["fs", "termios"] }
hyper-rustls = { version = "0.24.2", default-features = false, features = ["http1", "http2", "logging", "tls12", "webpki-tokio"] }
rustix = { version = "0.38.28", features = ["fs", "termios"] }
spin = { version = "0.9.8" }
[target.x86_64-apple-darwin.build-dependencies]
rustix = { version = "0.38.26", features = ["fs", "termios"] }
socket2 = { version = "0.5.5", default-features = false, features = ["all"] }
rustix = { version = "0.38.28", features = ["fs", "termios"] }
spin = { version = "0.9.8" }
[target.x86_64-pc-windows-msvc.dependencies]
hyper-rustls = { version = "0.24.2", default-features = false, features = ["http1", "http2", "logging", "tls12", "webpki-tokio"] }
spin = { version = "0.9.8" }
winapi = { version = "0.3.9", default-features = false, features = ["consoleapi", "errhandlingapi", "fibersapi", "fileapi", "handleapi", "knownfolders", "memoryapi", "minwinbase", "minwindef", "namedpipeapi", "ntdef", "ntsecapi", "ntstatus", "objbase", "processenv", "processthreadsapi", "profileapi", "shlobj", "std", "synchapi", "sysinfoapi", "timezoneapi", "winbase", "wincon", "winerror", "winnt", "winsock2", "ws2def", "ws2ipdef", "ws2tcpip", "wtypesbase"] }
windows-sys = { version = "0.48.0", features = ["Win32_Foundation", "Win32_Networking_WinSock", "Win32_Security_Authentication_Identity", "Win32_Security_Credentials", "Win32_Security_Cryptography", "Win32_Storage_FileSystem", "Win32_System_Console", "Win32_System_Diagnostics_Debug", "Win32_System_IO", "Win32_System_Memory", "Win32_System_Pipes", "Win32_System_Registry", "Win32_System_SystemServices", "Win32_System_Threading", "Win32_System_Time", "Win32_System_WindowsProgramming"] }
windows-sys = { version = "0.48.0", features = ["Win32_Foundation", "Win32_Globalization", "Win32_Networking_WinSock", "Win32_Security_Authentication_Identity", "Win32_Security_Credentials", "Win32_Security_Cryptography", "Win32_Storage_FileSystem", "Win32_System_Com", "Win32_System_Console", "Win32_System_Diagnostics_Debug", "Win32_System_IO", "Win32_System_Memory", "Win32_System_Pipes", "Win32_System_Registry", "Win32_System_SystemServices", "Win32_System_Threading", "Win32_System_Time", "Win32_System_WindowsProgramming", "Win32_UI_Shell"] }
[target.x86_64-pc-windows-msvc.build-dependencies]
socket2 = { version = "0.5.5", default-features = false, features = ["all"] }
spin = { version = "0.9.8" }
winapi = { version = "0.3.9", default-features = false, features = ["consoleapi", "errhandlingapi", "fibersapi", "fileapi", "handleapi", "knownfolders", "memoryapi", "minwinbase", "minwindef", "namedpipeapi", "ntdef", "ntsecapi", "ntstatus", "objbase", "processenv", "processthreadsapi", "profileapi", "shlobj", "std", "synchapi", "sysinfoapi", "timezoneapi", "winbase", "wincon", "winerror", "winnt", "winsock2", "ws2def", "ws2ipdef", "ws2tcpip", "wtypesbase"] }
windows-sys = { version = "0.48.0", features = ["Win32_Foundation", "Win32_Networking_WinSock", "Win32_Security_Authentication_Identity", "Win32_Security_Credentials", "Win32_Security_Cryptography", "Win32_Storage_FileSystem", "Win32_System_Console", "Win32_System_Diagnostics_Debug", "Win32_System_IO", "Win32_System_Memory", "Win32_System_Pipes", "Win32_System_Registry", "Win32_System_SystemServices", "Win32_System_Threading", "Win32_System_Time", "Win32_System_WindowsProgramming"] }
windows-sys = { version = "0.48.0", features = ["Win32_Foundation", "Win32_Globalization", "Win32_Networking_WinSock", "Win32_Security_Authentication_Identity", "Win32_Security_Credentials", "Win32_Security_Cryptography", "Win32_Storage_FileSystem", "Win32_System_Com", "Win32_System_Console", "Win32_System_Diagnostics_Debug", "Win32_System_IO", "Win32_System_Memory", "Win32_System_Pipes", "Win32_System_Registry", "Win32_System_SystemServices", "Win32_System_Threading", "Win32_System_Time", "Win32_System_WindowsProgramming", "Win32_UI_Shell"] }
### END HAKARI SECTION
+1 -1
View File
@@ -45,7 +45,7 @@ serde_json = "1.0.108"
toml = "0.5.8"
# Money
async-stripe = { version = "0.25.2", default-features = false, features = ["runtime-tokio-hyper", "connect", "billing", "checkout", "webhook-events"] }
async-stripe = { version = "0.25.2", default-features = false, features = ["runtime-tokio-hyper-rustls-webpki", "connect", "billing", "checkout", "webhook-events"] }
# Async traits
# NB: note: `async` trait functions are not currently supported
@@ -1,60 +1,49 @@
//! These routes are recommended, but do not have to be used by consumers of the billing system.
use actix_web::{App, HttpResponse, web};
use actix_web::body::MessageBody;
use actix_web::dev::{ServiceFactory, ServiceRequest, ServiceResponse};
use actix_web::error::Error;
use crate::stripe::http_endpoints::checkout::create::stripe_create_checkout_session_json_handler::stripe_create_checkout_session_json_handler;
use crate::stripe::http_endpoints::checkout::create::stripe_create_checkout_session_redirect_handler::stripe_create_checkout_session_redirect_handler;
use crate::stripe::http_endpoints::customer_portal::stripe_create_customer_portal_session_json_handler::stripe_create_customer_portal_session_json_handler;
use crate::stripe::http_endpoints::customer_portal::stripe_create_customer_portal_session_redirect_handler::stripe_create_customer_portal_session_redirect_handler;
use crate::stripe::http_endpoints::webhook::stripe_webhook_handler::stripe_webhook_handler;
use actix_web::body::MessageBody;
use actix_web::dev::{ServiceFactory, ServiceRequest, ServiceResponse};
use actix_web::error::Error;
use log::warn;
use crate::users::http_endpoints::list_active_user_subscriptions_handler::list_active_user_subscriptions_handler;
pub fn add_suggested_stripe_billing_routes<T, B> (app: App<T>) -> App<T>
where
B: MessageBody,
T: ServiceFactory<
ServiceRequest,
Config = (),
Response = ServiceResponse<B>,
Error = Error,
InitError = (),
>,
pub fn add_suggested_stripe_billing_routes<T, B>(app: App<T>) -> App<T>
where
B: MessageBody,
T: ServiceFactory<ServiceRequest, Config = (), Response = ServiceResponse<B>, Error = Error, InitError = ()>,
{
app.service(web::scope("/v1")
.service(web::scope("/billing")
.service(web::resource("/active_subscriptions")
.route(web::get().to(list_active_user_subscriptions_handler))
.route(web::head().to(|| HttpResponse::Ok()))
)
)
.service(web::scope("/stripe")
.service(web::resource("/webhook")
.route(web::post().to(stripe_webhook_handler))
.route(web::head().to(|| HttpResponse::Ok()))
)
.service(web::scope("/checkout")
.service(web::resource("/create_redirect")
.route(web::post().to(stripe_create_checkout_session_json_handler))
.route(web::head().to(|| HttpResponse::Ok()))
)
.service(web::resource("/redirect")
.route(web::get().to(stripe_create_checkout_session_redirect_handler))
.route(web::head().to(|| HttpResponse::Ok()))
)
)
.service(web::scope("/portal")
.service(web::resource("/create_redirect")
.route(web::post().to(stripe_create_customer_portal_session_json_handler))
.route(web::head().to(|| HttpResponse::Ok()))
)
.service(web::resource("/redirect")
.route(web::get().to(stripe_create_customer_portal_session_redirect_handler))
.route(web::head().to(|| HttpResponse::Ok()))
)
)
)
warn!("Adding suggested Stripe billing routes to app.");
app.service(
web::scope("/v1")
.service(web::scope("/billing")
.service(web::resource("/active_subscriptions")
.route(web::get().to(list_active_user_subscriptions_handler))
.route(web::head().to(|| HttpResponse::Ok()))))
.service(web::scope("/stripe")
.service(web::resource("/webhook")
.route(web::post().to(stripe_webhook_handler))
.route(web::head().to(|| HttpResponse::Ok())))
.service(web::scope("/checkout")
.service(web::resource("/create_redirect")
.route(web::post().to(stripe_create_checkout_session_json_handler))
.route(web::head().to(|| HttpResponse::Ok())))
.service(web::resource("/redirect")
.route(web::get().to(stripe_create_checkout_session_redirect_handler))
.route(web::head().to(|| HttpResponse::Ok()))))
.service(web::scope("/portal")
.service(web::resource("/create_redirect")
.route(web::post().to(stripe_create_customer_portal_session_json_handler))
.route(web::head().to(|| HttpResponse::Ok())))
.service(web::resource("/redirect")
.route(web::get().to(stripe_create_customer_portal_session_redirect_handler))
.route(web::head().to(|| HttpResponse::Ok()))))),
)
}
+10 -4
View File
@@ -51,7 +51,7 @@ url_config = { path = "../../../lib/url_config" }
user_input_common = { path = "../../../lib/user_input_common" }
# Internal Components
billing_component = { path = "../../plugins/billing" }
billing_component = { path = "../../plugins/billing", optional = true }
users_component = { path = "../../plugins/users" }
# Workspace hack (faster compile times)
@@ -90,7 +90,7 @@ language-tags = "0.3.2" # Parsing single tags richly
# HTTP
# TODO/NB: This is just for Twitch, but we might need it later.
reqwest = { version = "0.11.4" }
reqwest = { version = "0.11.4", default-features = false, features = ["json", "blocking", "rustls-tls"] }
native-tls = { version = "0.2.8", features = ["vendored"] }
# Runtime
@@ -123,7 +123,7 @@ infer = "0.5.0"
# The "never-encode-slash" feature seems to have been removed:
# https://github.com/durch/rust-s3/pull/254
rust-s3 = { version = "0.33.0" }
rust-s3 = { version = "0.33.0" , default-features = false, features = ["tokio-rustls-tls"] }
actix-cors = "0.6.4"
actix-http = "3.4.0"
@@ -139,7 +139,7 @@ jwt = "0.13.0"
hyper = { version = "0.14.24" }
# Money
async-stripe = { version = "0.25.2", default-features = false, features = ["runtime-tokio-hyper", "connect", "billing", "checkout", "webhook-events"] }
#async-stripe = { version = "0.25.2", default-features = false, features = ["runtime-tokio-hyper-rustls-webpki", "connect", "billing", "checkout", "webhook-events"] }
# Crypto
bcrypt = "0.8" # password hashes
@@ -172,3 +172,9 @@ diesel = { version = "2.1.3", features = ["mysql"] }
[dev-dependencies]
speculoos = "0.9.0" # Fluent assertions
[features]
default = ["billing", "dep:billing_component"]
billing = ["dep:billing_component"]
all_except_billing = []
@@ -1,3 +1,5 @@
#[cfg(feature = "billing")]
use billing_component::stripe::traits::internal_product_to_stripe_lookup::{InternalProductToStripeLookup, StripeProduct, StripeProductLookupError};
use reusable_types::server_environment::ServerEnvironment;
@@ -7,6 +9,8 @@ use crate::configs::plans::plan_list::{DEVELOPMENT_PREMIUM_PLANS_BY_SLUG, PRODUC
#[derive(Clone, Copy)]
pub struct InternalProductToStripeLookupImpl;
#[cfg(feature = "billing")]
impl InternalProductToStripeLookup for InternalProductToStripeLookupImpl {
fn lookup_stripe_product_from_internal_product_key(&self, server_environment: ServerEnvironment, internal_product_key: &str) -> Result<Option<StripeProduct>, StripeProductLookupError> {
let plans_by_slug = match server_environment {
@@ -1,5 +1,6 @@
use actix_web::HttpRequest;
#[cfg(feature = "billing")]
use billing_component::stripe::traits::internal_session_cache_purge::InternalSessionCachePurge;
use redis_caching::redis_ttl_cache::RedisTtlCache;
use redis_common::redis_cache_keys::RedisCacheKeys;
@@ -19,6 +20,7 @@ impl InternalSessionCachePurgeImpl {
}
}
#[cfg(feature = "billing")]
impl InternalSessionCachePurge for InternalSessionCachePurgeImpl {
fn best_effort_purge_session_cache(&self, http_request: &HttpRequest) {
// TODO: Clear Redis cache of sessions
@@ -1,3 +1,5 @@
#[cfg(feature = "billing")]
use billing_component::stripe::traits::internal_subscription_product_lookup::{InternalProductLookupError, InternalSubscriptionProduct, InternalSubscriptionProductLookup};
use crate::configs::plans::plan_list::{PLANS_BY_STRIPE_PRICE_ID, PLANS_BY_STRIPE_PRODUCT_ID};
@@ -8,6 +10,7 @@ const SUBSCRIPTION_CATEGORY : &str = "fakeyou";
#[derive(Clone, Copy)]
pub struct StripeInternalSubscriptionProductLookupImpl;
#[cfg(feature = "billing")]
impl InternalSubscriptionProductLookup for StripeInternalSubscriptionProductLookupImpl {
fn lookup_internal_product_from_stripe_product_id(&self, stripe_product_id: &str) -> Result<Option<InternalSubscriptionProduct>, InternalProductLookupError> {
Ok(PLANS_BY_STRIPE_PRODUCT_ID.get(stripe_product_id)
@@ -3,6 +3,7 @@ use async_trait::async_trait;
use chrono::Utc;
use log::warn;
#[cfg(feature = "billing")]
use billing_component::stripe::traits::internal_user_lookup::{InternalUserLookup, InternalUserLookupError, SubscriptionKey, UserMetadata};
use users_component::utils::session_checker::SessionChecker;
@@ -25,6 +26,7 @@ impl StripeInternalUserLookupImpl {
}
// NB: Marking async_trait as not needing Sync/Send. Hopefully this doesn't blow up on us.
#[cfg(feature = "billing")]
#[async_trait(?Send)]
impl InternalUserLookup for StripeInternalUserLookupImpl {
async fn lookup_user_from_http_request(&self, http_request: &HttpRequest) -> Result<Option<UserMetadata>, InternalUserLookupError> {
+113 -67
View File
@@ -46,11 +46,6 @@ use actix_helpers::middleware::disabled_endpoint_filter::disabled_endpoint_filte
use actix_helpers::middleware::disabled_endpoint_filter::disabled_endpoints::disabled_endpoints::DisabledEndpoints;
use actix_helpers::middleware::disabled_endpoint_filter::disabled_endpoints::exact_match_disabled_endpoints::ExactMatchDisabledEndpoints;
use actix_helpers::middleware::disabled_endpoint_filter::disabled_endpoints::prefix_disabled_endpoints::PrefixDisabledEndpoints;
use billing_component::stripe::stripe_config::{FullUrlOrPath, StripeCheckoutConfigs, StripeConfig, StripeCustomerPortalConfigs, StripeSecrets};
use billing_component::stripe::traits::internal_product_to_stripe_lookup::InternalProductToStripeLookup;
use billing_component::stripe::traits::internal_session_cache_purge::InternalSessionCachePurge;
use billing_component::stripe::traits::internal_subscription_product_lookup::InternalSubscriptionProductLookup;
use billing_component::stripe::traits::internal_user_lookup::InternalUserLookup;
use bootstrap::bootstrap::{bootstrap, BootstrapArgs};
use cloud_storage::bucket_client::BucketClient;
use config::common_env::CommonEnv;
@@ -71,10 +66,19 @@ use users_component::cookies::anonymous_visitor_tracking::avt_cookie_manager::Av
use users_component::cookies::session::session_cookie_manager::SessionCookieManager;
use users_component::utils::session_checker::SessionChecker;
use crate::billing::internal_product_to_stripe_lookup_impl::InternalProductToStripeLookupImpl;
use crate::billing::internal_session_cache_purge_impl::InternalSessionCachePurgeImpl;
use crate::billing::stripe_internal_subscription_product_lookup_impl::StripeInternalSubscriptionProductLookupImpl;
use crate::billing::stripe_internal_user_lookup_impl::StripeInternalUserLookupImpl;
#[cfg(feature = "billing")]
use
{
crate::billing::internal_product_to_stripe_lookup_impl::InternalProductToStripeLookupImpl,
crate::billing::internal_session_cache_purge_impl::InternalSessionCachePurgeImpl,
crate::billing::stripe_internal_subscription_product_lookup_impl::StripeInternalSubscriptionProductLookupImpl,
crate::billing::stripe_internal_user_lookup_impl::StripeInternalUserLookupImpl,
billing_component::stripe::stripe_config::{FullUrlOrPath, StripeCheckoutConfigs, StripeConfig, StripeCustomerPortalConfigs, StripeSecrets},
billing_component::stripe::traits::internal_product_to_stripe_lookup::InternalProductToStripeLookup,
billing_component::stripe::traits::internal_session_cache_purge::InternalSessionCachePurge,
billing_component::stripe::traits::internal_subscription_product_lookup::InternalSubscriptionProductLookup,
billing_component::stripe::traits::internal_user_lookup::InternalUserLookup,
};
use crate::configs::static_api_tokens::{StaticApiTokenConfig, StaticApiTokens, StaticApiTokenSet};
use crate::http_server::middleware::pushback_filter_middleware::PushbackFilter;
use crate::http_server::web_utils::redis_rate_limiter::RedisRateLimiter;
@@ -382,6 +386,7 @@ async fn main() -> AnyhowResult<()> {
});
#[cfg(feature = "billing")]
let stripe_configs = StripeConfig {
checkout: StripeCheckoutConfigs {
success_url: FullUrlOrPath::Path(easyenv::get_env_string_required("STRIPE_CHECKOUT_SUCCESS_URL_PATH")?),
@@ -398,6 +403,9 @@ async fn main() -> AnyhowResult<()> {
},
};
#[cfg(not(feature = "billing"))]
let stripe_configs = ();
let server_environment = ServerEnvironment::from_str(&easyenv::get_env_string_required("SERVER_ENVIRONMENT")?)
.ok_or(anyhow!("invalid server environment"))?;
@@ -424,10 +432,6 @@ async fn main() -> AnyhowResult<()> {
let third_party_url_redirector = ThirdPartyUrlRedirector::new(server_environment);
let stripe_client = {
let api_secret = stripe_configs.secrets.secret_key.clone();
stripe::Client::new(api_secret)
};
// NB: Docker creates this file within container builds.
let build_sha = std::fs::read_to_string("/GIT_SHA")
@@ -455,7 +459,6 @@ async fn main() -> AnyhowResult<()> {
},
stripe: StripeSettings {
config: stripe_configs,
client: stripe_client,
},
hostname: server_hostname,
server_environment,
@@ -636,62 +639,105 @@ pub async fn serve(server_state: ServerState) -> AnyhowResult<()>
//let log_format = "[%{HOSTNAME}e] %a \"%r\" %s %b \"%{Referer}i\" \"%{User-Agent}i\" %T";
let log_format = "[%{HOSTNAME}e] IP=[%{X-Forwarded-For}i] \"%r\" %s %b \"%{Referer}i\" \"%{User-Agent}i\" %T";
HttpServer::new(move || {
// NB: Safe to clone due to internal arc
let ip_ban_list = server_state_arc.ip_ban_list.clone();
let cidr_ban_set= server_state_arc.cidr_ban_set.clone();
#[cfg(feature = "billing")]
{
let server = HttpServer::new(move || {
// NB: Safe to clone due to internal arc
let ip_ban_list = server_state_arc.ip_ban_list.clone();
let cidr_ban_set= server_state_arc.cidr_ban_set.clone();
// NB: Dynamic dispatch needs to be wrapped with Arc.
let product_lookup : Arc<dyn InternalSubscriptionProductLookup> = Arc::new(StripeInternalSubscriptionProductLookupImpl {});
let stripe_lookup : Arc<dyn InternalProductToStripeLookup> = Arc::new(InternalProductToStripeLookupImpl{});
let user_lookup : Arc<dyn InternalUserLookup> = Arc::new(StripeInternalUserLookupImpl::new(
server_state_arc.session_checker.clone(),
server_state_arc.mysql_pool.clone(),
));
let session_cache_purge : Arc<dyn InternalSessionCachePurge> = Arc::new(InternalSessionCachePurgeImpl::new(
server_state_arc.session_checker.clone(),
server_state_arc.redis_ttl_cache.clone(),
));
// NB: Dynamic dispatch needs to be wrapped with Arc.
let product_lookup : Arc<dyn InternalSubscriptionProductLookup> = Arc::new(StripeInternalSubscriptionProductLookupImpl {});
let stripe_lookup : Arc<dyn InternalProductToStripeLookup> = Arc::new(InternalProductToStripeLookupImpl{});
let user_lookup : Arc<dyn InternalUserLookup> = Arc::new(StripeInternalUserLookupImpl::new(
server_state_arc.session_checker.clone(),
server_state_arc.mysql_pool.clone(),
));
let session_cache_purge : Arc<dyn InternalSessionCachePurge> = Arc::new(InternalSessionCachePurgeImpl::new(
server_state_arc.session_checker.clone(),
server_state_arc.redis_ttl_cache.clone(),
));
// NB: app_data being clone()'d below should all be safe (dependencies included)
let app = App::new()
.app_data(web::Data::new(server_state_arc.firehose_publisher.clone()))
.app_data(web::Data::new(server_state_arc.mysql_pool.clone()))
.app_data(web::Data::new(server_state_arc.redis_pool.clone()))
.app_data(web::Data::new(server_state_arc.redis_ttl_cache.clone()))
.app_data(web::Data::new(server_state_arc.session_checker.clone()))
.app_data(web::Data::new(server_state_arc.avt_cookie_manager.clone()))
.app_data(web::Data::new(server_state_arc.session_cookie_manager.clone()))
.app_data(web::Data::new(server_state_arc.stripe.clone().config.clone()))
.app_data(web::Data::new(server_state_arc.stripe.clone().client.clone()))
.app_data(web::Data::new(server_state_arc.third_party_url_redirector.clone()))
.app_data(web::Data::new(server_state_arc.email_sender.clone()))
.app_data(web::Data::new(old_server_environment))
.app_data(web::Data::new(new_server_environment))
.app_data(web::Data::from(product_lookup)) // NB: Data::from(Arc<T>) for dynamic dispatch
.app_data(web::Data::from(stripe_lookup)) // NB: Data::from(Arc<T>) for dynamic dispatch
.app_data(web::Data::from(user_lookup)) // NB: Data::from(Arc<T>) for dynamic dispatch
.app_data(web::Data::from(session_cache_purge)) // NB: Data::from(Arc<T>) for dynamic dispatch
.app_data(server_state_arc.clone())
.wrap(build_cors_config(old_server_environment))
.wrap(DefaultHeaders::new()
.header("X-Backend-Hostname", &hostname)
.header("X-Build-Sha", server_state_arc.server_info.build_sha.clone()))
.wrap(PushbackFilter::new(&server_state_arc.flags.clone()))
.wrap(DisabledEndpointFilter::new(disabled_endpoints.clone()))
.wrap(BannedIpFilter::new(ip_ban_list))
.wrap(BannedCidrFilter::new(cidr_ban_set))
.wrap(Logger::new(&log_format)
.exclude("/liveness")
.exclude("/readiness"))
.wrap(middleware::Compress::default());
// NB: app_data being clone()'d below should all be safe (dependencies included)
let app = App::new()
.app_data(web::Data::new(server_state_arc.firehose_publisher.clone()))
.app_data(web::Data::new(server_state_arc.mysql_pool.clone()))
.app_data(web::Data::new(server_state_arc.redis_pool.clone()))
.app_data(web::Data::new(server_state_arc.redis_ttl_cache.clone()))
.app_data(web::Data::new(server_state_arc.session_checker.clone()))
.app_data(web::Data::new(server_state_arc.avt_cookie_manager.clone()))
.app_data(web::Data::new(server_state_arc.session_cookie_manager.clone()))
.app_data(web::Data::new(server_state_arc.stripe.clone().config.clone()))
.app_data(web::Data::new(server_state_arc.third_party_url_redirector.clone()))
.app_data(web::Data::new(server_state_arc.email_sender.clone()))
.app_data(web::Data::new(old_server_environment))
.app_data(web::Data::new(new_server_environment))
.app_data(web::Data::from(product_lookup)) // NB: Data::from(Arc<T>) for dynamic dispatch
.app_data(web::Data::from(stripe_lookup)) // NB: Data::from(Arc<T>) for dynamic dispatch
.app_data(web::Data::from(user_lookup)) // NB: Data::from(Arc<T>) for dynamic dispatch
.app_data(web::Data::from(session_cache_purge)) // NB: Data::from(Arc<T>) for dynamic dispatch
.app_data(server_state_arc.clone())
.wrap(build_cors_config(old_server_environment))
.wrap(DefaultHeaders::new()
.header("X-Backend-Hostname", &hostname)
.header("X-Build-Sha", server_state_arc.server_info.build_sha.clone()))
.wrap(PushbackFilter::new(&server_state_arc.flags.clone()))
.wrap(DisabledEndpointFilter::new(disabled_endpoints.clone()))
.wrap(BannedIpFilter::new(ip_ban_list))
.wrap(BannedCidrFilter::new(cidr_ban_set))
.wrap(Logger::new(&log_format)
.exclude("/liveness")
.exclude("/readiness"))
.wrap(middleware::Compress::default());
add_routes(app, old_server_environment)
})
.bind(bind_address)?
.workers(num_workers)
.run()
.await?;
crate::routes::add_routes(app, old_server_environment)
});
server.bind(bind_address)?
.workers(num_workers)
.run()
.await?;
}
#[cfg(not(feature = "billing"))] {
let server = HttpServer::new(move || {
// NB: Safe to clone due to internal arc
let ip_ban_list = server_state_arc.ip_ban_list.clone();
let cidr_ban_set= server_state_arc.cidr_ban_set.clone();
// NB: app_data being clone()'d below should all be safe (dependencies included)
let app = App::new()
.app_data(web::Data::new(server_state_arc.firehose_publisher.clone()))
.app_data(web::Data::new(server_state_arc.mysql_pool.clone()))
.app_data(web::Data::new(server_state_arc.redis_pool.clone()))
.app_data(web::Data::new(server_state_arc.redis_ttl_cache.clone()))
.app_data(web::Data::new(server_state_arc.session_checker.clone()))
.app_data(web::Data::new(server_state_arc.avt_cookie_manager.clone()))
.app_data(web::Data::new(server_state_arc.session_cookie_manager.clone()))
.app_data(web::Data::new(server_state_arc.third_party_url_redirector.clone()))
.app_data(web::Data::new(server_state_arc.email_sender.clone()))
.app_data(web::Data::new(old_server_environment))
.app_data(web::Data::new(new_server_environment))
.app_data(server_state_arc.clone())
.wrap(build_cors_config(old_server_environment))
.wrap(DefaultHeaders::new()
.header("X-Backend-Hostname", &hostname)
.header("X-Build-Sha", server_state_arc.server_info.build_sha.clone()))
.wrap(PushbackFilter::new(&server_state_arc.flags.clone()))
.wrap(DisabledEndpointFilter::new(disabled_endpoints.clone()))
.wrap(BannedIpFilter::new(ip_ban_list))
.wrap(BannedCidrFilter::new(cidr_ban_set))
.wrap(Logger::new(&log_format)
.exclude("/liveness")
.exclude("/readiness"))
.wrap(middleware::Compress::default());
add_routes(app, old_server_environment)
});
server.bind(bind_address)?
.workers(num_workers)
.run()
.await?;
}
Ok(())
}
@@ -5,6 +5,7 @@ use actix_web::dev::{ServiceRequest, ServiceResponse};
use actix_web::error::Error;
use actix_helpers::route_builder::RouteBuilder;
#[cfg(feature = "billing")]
use billing_component::default_routes::add_suggested_stripe_billing_routes;
use reusable_types::server_environment::ServerEnvironment;
use users_component::default_routes::add_suggested_api_v1_account_creation_and_session_routes;
@@ -228,15 +229,20 @@ pub fn add_routes<T, B> (app: App<T>, server_environment: ServerEnvironment) ->
// ==================== Stats ====================
let mut app = RouteBuilder::from_app(app)
.add_get("/v1/stats/queues", get_unified_queue_stats_handler)
.into_app();
// ==================== COMPONENTS ====================
app = add_suggested_api_v1_account_creation_and_session_routes(app); // /create_account, /session, /login, /logout
app = add_suggested_stripe_billing_routes(app); // /stripe, billing, webhooks, etc.
#[cfg(feature = "billing")]
let mut app = add_suggested_stripe_billing_routes(app); // /stripe, billing, webhooks, etc.
#[cfg(not(feature = "billing"))]
let mut app = app;
// ==================== SERVICE ====================
app.service(
web::resource("/_status")
@@ -4,6 +4,7 @@ use sqlx::MySqlPool;
use actix_helpers::middleware::banned_cidr_filter::banned_cidr_set::BannedCidrSet;
use actix_helpers::middleware::banned_ip_filter::ip_ban_list::ip_ban_list::IpBanList;
#[cfg(feature = "billing")]
use billing_component::stripe::stripe_config::StripeConfig;
use cloud_storage::bucket_client::BucketClient;
use email_sender::smtp_email_sender::SmtpEmailSender;
@@ -197,10 +198,16 @@ pub struct EphemeralInMemoryCaches {
pub leaderboard: SingleItemTtlCache<LeaderboardInfo>,
}
#[cfg(feature = "billing")]
#[derive(Clone)]
pub struct StripeSettings {
pub config: StripeConfig,
pub client: stripe::Client,
}
#[cfg(not(feature = "billing"))]
#[derive(Clone)]
pub struct StripeSettings {
pub config: ()
}
/// Flags set at service startup