1use std::time::Duration;
24
25use crate::msg::Msg;
26
27
28const TOKEN_OFFSET: u64 = 2700;
29const TEAM_ID: &str = "5U8LBRXG3A";
30const AUTH_KEY_ID: &str = "LH4T9V5U4R";
31const TOPIC: &str = "me.fin.bark";
32
33const KEY: &str = r#"-----BEGIN PRIVATE KEY-----
34MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQg4vtC3g5L5HgKGJ2+
35T1eA0tOivREvEAY2g+juRXJkYL2gCgYIKoZIzj0DAQehRANCAASmOs3JkSyoGEWZ
36sUGxFs/4pw1rIlSV2IC19M8u3G5kq36upOwyFWj9Gi3Ejc9d3sC7+SHRqXrEAJow
378/7tRpV+
38-----END PRIVATE KEY-----
39"#;
40pub struct Bark {
41 team_id: String,
42 auth_key_id: String,
43 topic: String,
44 key: String,
45 token: String
46}
47
48
49impl Bark {
50 pub fn new() -> Self {
51 Self {
52 team_id : TEAM_ID.to_string(),
53 auth_key_id : AUTH_KEY_ID.to_string(),
54 topic : TOPIC.to_string(),
55 key : KEY.to_string(),
56 token : ".".to_string(),
57 }
58 }
59
60 pub fn born(timestamp: u64, token: String) -> Self {
61 if timestamp + TOKEN_OFFSET <= Self::ts() {
62 println!("warning: token expired, bark will new one");
63 return Self::new();
64 }
65 Self {
66 team_id : TEAM_ID.to_string(),
67 auth_key_id : AUTH_KEY_ID.to_string(),
68 topic: TOPIC.to_string(),
69 key: KEY.to_string(),
70 token: format!("{}.{}", timestamp, token),
71 }
72 }
73
74 fn ts() -> u64 {
75 std::time::SystemTime::now()
76 .duration_since(std::time::UNIX_EPOCH)
77 .unwrap_or_else(|_e| Duration::from_secs(0))
78 .as_secs()
79 }
80
81 pub fn token(&mut self) -> (u64, String) {
85 let token = self.token.split_once(".").unwrap();
86 (token.0.parse::<u64>().unwrap_or_else(|_e| 0), token.1.to_string())
87 }
88
89 pub fn force_refresh_token(&mut self) -> (u64, String) {
93 self.get_token();
94 self.token()
95 }
96 pub fn send(&mut self, msg: &Msg, devices: &Vec<&str>) -> Option<Vec<String>> {
100 crate::apns::send(&msg, self.topic.clone().as_str(), &self.get_token(), devices)
101 }
102
103 pub async fn async_send(&mut self, msg: &Msg, devices: &Vec<&str>) -> Option<Vec<String>> {
107 crate::apns::async_send(&msg, self.topic.clone().as_str(), &self.get_token(), devices).await
108 }
109
110 fn get_token(&mut self) -> String {
111 let time_stamp: u64 = Self::ts();
112
113 if let Some((ts, token)) = self.token.split_once(".") {
114 if ts.parse::<u64>().unwrap_or_else(|_e| 0) + TOKEN_OFFSET >= time_stamp {
116 return token.to_string();
117 }
118 }
119
120 let jwt_header: String = Self::clean_str(
121 openssl::base64::encode_block(
122 format!("{{ \"alg\": \"ES256\", \"kid\": \"{}\" }}", self.auth_key_id)
123 .as_bytes()
124 )
125 );
126
127 let jwt_claims: String = Self::clean_str(
128 openssl::base64::encode_block(
129 format!("{{ \"iss\": \"{}\", \"iat\": {} }}",
130 self.team_id, time_stamp
131 )
132 .as_bytes()
133 )
134 );
135
136 let mut singer: openssl::sign::Signer<'_> = openssl::sign::Signer::new(
137 openssl::hash::MessageDigest::sha256(),
138 &openssl::pkey::PKey::from_ec_key(
139 openssl::ec::EcKey::private_key_from_pem(self.key.as_bytes()).expect("init key data failed")
140 ).expect("generate private key failed")
141 ).expect("init signer failed");
142
143 let jwt_header: String = format!("{}.{}", jwt_header, jwt_claims);
144 singer.update(jwt_header.as_bytes()).expect("fill sign data failed");
145 let sign: Vec<u8> = singer.sign_to_vec().expect("sign failed");
146 let jwt_signature: String = Self::clean_str(openssl::base64::encode_block(&sign));
147 let token: String= format!("{}.{}", jwt_header, jwt_signature);
148
149 self.token = format!("{}.{}", time_stamp, token);
150 token
151 }
152
153 fn clean_str(str: String) -> String {
154 str.replace("+", "-")
155 .replace("/", "_")
156 .replace("=", "")
157 }
158
159
160}