lightspark_remote_signing/
handler.rs1use lightspark::{
2 objects::{
3 id_and_signature::IdAndSignature, remote_signing_sub_event_type::RemoteSigningSubEventType,
4 webhook_event_type::WebhookEventType,
5 },
6 webhooks::WebhookEvent,
7};
8use log::info;
9use serde::Deserialize;
10use serde_json::from_value;
11
12use crate::{response::Response, signer::LightsparkSigner, validation::Validation, Error};
13
14pub struct Handler {
16 signer: LightsparkSigner,
17 validator: Box<dyn Validation>,
18}
19
20impl Handler {
21 pub fn new(signer: LightsparkSigner, validator: Box<dyn Validation>) -> Self {
27 Self { signer, validator }
28 }
29
30 pub fn handle_remote_signing_webhook_msg(
31 &self,
32 event: &WebhookEvent,
33 ) -> Result<Option<Response>, Error> {
34 if !matches!(event.event_type, WebhookEventType::RemoteSigning) {
35 return Err(Error::WebhookEventNotRemoteSigning);
36 }
37
38 let data = &event.data.as_ref().ok_or(Error::WebhookEventDataMissing)?;
39 let sub_type: RemoteSigningSubEventType = from_value(data["sub_event_type"].clone())
40 .map_err(|_| Error::WebhookEventDataMissing)?;
41 println!("handler for sub_type: {:?}", sub_type.to_string());
42 let event_json =
43 serde_json::to_string(&event).expect("Serialize event to json should not fail");
44 if !self.validator.should_sign(event_json) {
45 self.handle_decline_to_sign_messages(event).map(Some)
46 } else {
47 match sub_type {
48 RemoteSigningSubEventType::Ecdh => self.handle_ecdh(event).map(Some),
49 RemoteSigningSubEventType::SignInvoice => self.handle_sign_invoice(event).map(Some),
50 RemoteSigningSubEventType::ReleasePaymentPreimage => {
51 self.handle_release_payment_preimage(event).map(Some)
52 }
53 RemoteSigningSubEventType::GetPerCommitmentPoint => {
54 self.handle_get_per_commitment_point(event).map(Some)
55 }
56 RemoteSigningSubEventType::ReleasePerCommitmentSecret => {
57 self.handle_release_per_commitment_secret(event).map(Some)
58 }
59 RemoteSigningSubEventType::DeriveKeyAndSign => {
60 self.handle_derive_key_and_sign(event).map(Some)
61 }
62 RemoteSigningSubEventType::RequestInvoicePaymentHash => {
63 self.handle_request_invoice_payment_hash(event).map(Some)
64 }
65 RemoteSigningSubEventType::RevealCounterpartyPerCommitmentSecret => Ok(None),
66 }
67 }
68 }
69
70 pub fn handle_request_invoice_payment_hash(
71 &self,
72 event: &WebhookEvent,
73 ) -> Result<Response, Error> {
74 let data = event.data.as_ref().ok_or(Error::WebhookEventDataMissing)?;
75 let invoice_id = data["invoice_id"]
76 .as_str()
77 .ok_or(Error::WebhookEventDataMissing)?;
78 let nonce = self.signer.generate_preimage_nonce();
79 let nonce_str = hex::encode(&nonce);
80
81 let payment_hash = self
82 .signer
83 .generate_preimage_hash(nonce)
84 .map_err(Error::SignerError)?;
85 let payment_hash_str = hex::encode(payment_hash);
86 Ok(Response::set_invoice_payment_hash_response(
87 invoice_id,
88 &payment_hash_str,
89 &nonce_str,
90 ))
91 }
92
93 pub fn handle_decline_to_sign_messages(&self, event: &WebhookEvent) -> Result<Response, Error> {
94 let data = event.data.as_ref().ok_or(Error::WebhookEventDataMissing)?;
95
96 let signing_jobs: Vec<SigningJob> = serde_json::from_value(data["signing_jobs"].clone())
97 .map_err(|_| Error::WebhookEventDataMissing)?;
98
99 let payload_ids: Vec<String> = signing_jobs.iter().map(|job| job.id.clone()).collect();
100 Ok(Response::decline_to_sign_message_response(&payload_ids))
101 }
102
103 pub fn handle_ecdh(&self, event: &WebhookEvent) -> Result<Response, Error> {
104 info!("Handling ECDH webhook event");
105 let data = event.data.as_ref().ok_or(Error::WebhookEventDataMissing)?;
106 let node_id = &event.entity_id;
107 let public_key = data["peer_public_key"]
108 .as_str()
109 .ok_or(Error::WebhookEventDataMissing)?;
110 let public_key_bytes = hex::decode(public_key).map_err(Error::PublicKeyDecodeError)?;
111 let ss = self
112 .signer
113 .ecdh(public_key_bytes.to_vec())
114 .map_err(Error::SignerError)?;
115 let ss_str = hex::encode(ss);
116 Ok(Response::ecdh_response(node_id, &ss_str))
117 }
118
119 pub fn handle_sign_invoice(&self, event: &WebhookEvent) -> Result<Response, Error> {
120 info!("Handling sign invoice webhook event");
121 let data = event.data.as_ref().ok_or(Error::WebhookEventDataMissing)?;
122 let invoice_id = data["invoice_id"]
123 .as_str()
124 .ok_or(Error::WebhookEventDataMissing)?;
125 let invoice_hash = data["payreq_hash"]
126 .as_str()
127 .ok_or(Error::WebhookEventDataMissing)?;
128 let invoice_hash_bytes = hex::decode(invoice_hash).map_err(|_| Error::HexEncodingError)?;
129 let signature = self
130 .signer
131 .sign_invoice_hash(invoice_hash_bytes)
132 .map_err(Error::SignerError)?;
133 Ok(Response::sign_invoice_response(
134 invoice_id,
135 hex::encode(signature.get_signature()).as_str(),
136 signature.get_recovery_id(),
137 ))
138 }
139
140 pub fn handle_release_payment_preimage(&self, event: &WebhookEvent) -> Result<Response, Error> {
141 info!("Handling release payment preimage webhook event");
142 let data = event.data.as_ref().ok_or(Error::WebhookEventDataMissing)?;
143 let nonce = data["preimage_nonce"]
144 .as_str()
145 .ok_or(Error::WebhookEventDataMissing)?;
146 let invoice_id = data["invoice_id"]
147 .as_str()
148 .ok_or(Error::WebhookEventDataMissing)?;
149
150 let nonce_bytes = hex::decode(nonce).map_err(|_| Error::HexEncodingError)?;
151 let preimage = self
152 .signer
153 .generate_preimage(nonce_bytes)
154 .map_err(Error::SignerError)?;
155
156 Ok(Response::release_payment_preimage_response(
157 invoice_id,
158 hex::encode(preimage).as_str(),
159 ))
160 }
161
162 pub fn handle_get_per_commitment_point(&self, event: &WebhookEvent) -> Result<Response, Error> {
163 info!("Handling get per commitment point webhook event");
164 let data = event.data.as_ref().ok_or(Error::WebhookEventDataMissing)?;
165 let per_commitment_point_idx = data["per_commitment_point_idx"]
166 .as_u64()
167 .ok_or(Error::WebhookEventDataMissing)?;
168
169 let derivation_path = data["derivation_path"]
170 .as_str()
171 .ok_or(Error::WebhookEventDataMissing)?;
172
173 let channel_id = &event.entity_id;
174
175 let per_commitment_point = self
176 .signer
177 .get_per_commitment_point(derivation_path.to_string(), per_commitment_point_idx)
178 .map_err(Error::SignerError)?;
179
180 let commitment_point_str = hex::encode(per_commitment_point);
181 Ok(Response::get_channel_per_commitment_response(
182 channel_id,
183 commitment_point_str.as_str(),
184 per_commitment_point_idx,
185 ))
186 }
187
188 pub fn handle_release_per_commitment_secret(
189 &self,
190 event: &WebhookEvent,
191 ) -> Result<Response, Error> {
192 info!("Handling release per commitment secret webhook event");
193 let data = event.data.as_ref().ok_or(Error::WebhookEventDataMissing)?;
194 let per_commitment_point_idx = data["per_commitment_point_idx"]
195 .as_u64()
196 .ok_or(Error::WebhookEventDataMissing)?;
197
198 let derivation_path = data["derivation_path"]
199 .as_str()
200 .ok_or(Error::WebhookEventDataMissing)?;
201
202 let channel_id = &event.entity_id;
203 let commitment_secret = self
204 .signer
205 .release_per_commitment_secret(derivation_path.to_string(), per_commitment_point_idx)
206 .map_err(Error::SignerError)?;
207
208 let commitment_secret_str = hex::encode(commitment_secret);
209
210 Ok(Response::release_channel_per_commitment_secret_response(
211 channel_id,
212 &commitment_secret_str,
213 per_commitment_point_idx as i64,
214 ))
215 }
216
217 pub fn handle_derive_key_and_sign(&self, event: &WebhookEvent) -> Result<Response, Error> {
218 info!("Handling derive key and sign webhook event");
219 let data = event.data.as_ref().ok_or(Error::WebhookEventDataMissing)?;
220
221 let signing_jobs: Vec<SigningJob> = serde_json::from_value(data["signing_jobs"].clone())
222 .map_err(|_| Error::WebhookEventDataMissing)?;
223
224 let mut signatures: Vec<IdAndSignature> = vec![];
225 for signing_job in signing_jobs {
226 let signature = self
227 .signer
228 .derive_key_and_sign(
229 hex::decode(signing_job.message).map_err(|_| Error::HexEncodingError)?,
230 signing_job.derivation_path,
231 signing_job
232 .add_tweak
233 .map(|tweak| hex::decode(tweak).map_err(|_| Error::HexEncodingError))
234 .transpose()?,
235 signing_job
236 .mul_tweak
237 .map(|tweak| hex::decode(tweak).map_err(|_| Error::HexEncodingError))
238 .transpose()?,
239 )
240 .map_err(Error::SignerError)?;
241
242 signatures.push(IdAndSignature {
243 id: signing_job.id,
244 signature: hex::encode(signature),
245 });
246 }
247 Ok(Response::sign_messages_response(signatures))
248 }
249}
250
251#[derive(Clone, Deserialize, Debug)]
252struct SigningJob {
253 id: String,
254 derivation_path: String,
255 message: String,
256 add_tweak: Option<String>,
257 mul_tweak: Option<String>,
258}