lockbook_server_lib/
defense.rs1use std::{
2 collections::HashMap,
3 net::IpAddr,
4 ops::Deref,
5 time::{SystemTime, UNIX_EPOCH},
6};
7
8use google_androidpublisher3::chrono::{Datelike, Local};
9use serde::{Deserialize, Serialize};
10use time::Duration;
11
12use crate::{
13 ServerState,
14 billing::{
15 app_store_client::AppStoreClient, google_play_client::GooglePlayClient,
16 stripe_client::StripeClient,
17 },
18 document_service::DocumentService,
19};
20
21#[derive(Debug, Clone, Serialize, Deserialize, Default)]
22pub struct BandwidthReport {
23 monthly_agg: HashMap<YearMonth, usize>,
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
27pub struct YearMonth {
28 pub year: i32,
29 pub month: u32,
30}
31
32impl YearMonth {
33 fn current() -> Self {
34 let now = Local::now();
35 Self { year: now.year(), month: now.month() }
36 }
37}
38
39pub static SERVER_BANDWIDTH_CAP: usize = 1_000_000_000_000; impl BandwidthReport {
42 pub fn current_bandwidth(&self) -> usize {
43 self.monthly_agg
44 .get(&YearMonth::current())
45 .copied()
46 .unwrap_or_default()
47 }
48
49 pub fn all_bandwidth(&self) -> usize {
50 self.monthly_agg.values().sum()
51 }
52
53 pub fn increase_by(&mut self, inc: usize) {
54 let now = YearMonth::current();
55 match self.monthly_agg.get_mut(&YearMonth::current()) {
56 Some(new) => *new += inc,
57 None => {
58 self.monthly_agg.insert(now, inc);
59 }
60 }
61 }
62}
63
64#[derive(Copy, Debug, Clone, Serialize, Deserialize)]
68pub struct IpData {
69 ip: IpAddr,
70 time: u64,
71}
72static MAX_IPS: u16 = 1000;
73
74impl<S, A, G, D> ServerState<S, A, G, D>
75where
76 S: StripeClient,
77 A: AppStoreClient,
78 G: GooglePlayClient,
79 D: DocumentService,
80{
81 pub async fn can_create_account(&self, ip: IpAddr) -> bool {
84 if !self.config.features.new_account_rate_limit {
85 return true;
86 }
87
88 let ips = self.recent_new_account_ips.lock().await;
89 for visitor in ips.deref() {
90 if visitor.ip == ip {
91 let now = SystemTime::now()
92 .duration_since(UNIX_EPOCH)
93 .unwrap()
94 .as_millis() as u64;
95 if now - visitor.time > Duration::minutes(1).whole_milliseconds() as u64 {
96 return true;
97 } else {
98 tracing::error!("account creation not permitted due to rate limit");
99 return false;
100 }
101 }
102 }
103 true
104 }
105
106 pub async fn did_create_account(&self, ip: IpAddr) {
107 let mut ips = self.recent_new_account_ips.lock().await;
108 ips.retain(|visitor| visitor.ip != ip);
109 if ips.len() > MAX_IPS as usize {
110 ips.pop_front();
111 }
112
113 ips.push_back(IpData {
114 ip,
115 time: SystemTime::now()
116 .duration_since(UNIX_EPOCH)
117 .unwrap()
118 .as_millis() as u64,
119 });
120 }
121}