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