@@ -47,6 +47,9 @@ pub trait NilauthClient {
4747 key : & PublicKey ,
4848 ) -> Result < TxHash , PaySubscriptionError > ;
4949
50+ /// Get our subscription status.
51+ async fn subscription_status ( & self , key : & SecretKey ) -> Result < Subscription , SubscriptionStatusError > ;
52+
5053 /// Get the cost of a subscription.
5154 async fn subscription_cost ( & self ) -> Result < TokenAmount , SubscriptionCostError > ;
5255
@@ -66,11 +69,8 @@ pub enum RequestTokenError {
6669 #[ error( "fetching server's about: {0}" ) ]
6770 About ( #[ from] AboutError ) ,
6871
69- #[ error( "serde: {0}" ) ]
70- Serde ( #[ from] serde_json:: Error ) ,
71-
72- #[ error( "invalid public key" ) ]
73- InvalidPublicKey ,
72+ #[ error( "signing request: {0}" ) ]
73+ Signing ( #[ from] SigningError ) ,
7474
7575 #[ error( "http: {0}" ) ]
7676 Http ( #[ from] reqwest:: Error ) ,
@@ -107,6 +107,22 @@ pub enum PaySubscriptionError {
107107 Request ( RequestError ) ,
108108}
109109
110+ /// An error when fetching the subscription status.
111+ #[ derive( Debug , thiserror:: Error ) ]
112+ pub enum SubscriptionStatusError {
113+ #[ error( "fetching server's about: {0}" ) ]
114+ About ( #[ from] AboutError ) ,
115+
116+ #[ error( "http: {0}" ) ]
117+ Http ( #[ from] reqwest:: Error ) ,
118+
119+ #[ error( "signing request: {0}" ) ]
120+ Signing ( #[ from] SigningError ) ,
121+
122+ #[ error( "request: {0:?}" ) ]
123+ Request ( RequestError ) ,
124+ }
125+
110126/// An error when fetching the subscription cost.
111127#[ derive( Debug , thiserror:: Error ) ]
112128pub enum SubscriptionCostError {
@@ -183,6 +199,7 @@ macro_rules! impl_from_request_error {
183199impl_from_request_error ! (
184200 RequestTokenError ,
185201 PaySubscriptionError ,
202+ SubscriptionStatusError ,
186203 SubscriptionCostError ,
187204 RevokeTokenError ,
188205 AboutError ,
@@ -253,13 +270,7 @@ impl NilauthClient for DefaultNilauthClient {
253270 expires_at : Utc :: now ( ) + TOKEN_REQUEST_EXPIRATION ,
254271 target_public_key : about. public_key ,
255272 } ;
256- let payload = serde_json:: to_string ( & payload) ?;
257- let signature: Signature = SigningKey :: from ( key) . sign ( payload. as_bytes ( ) ) ;
258-
259- let public_key =
260- key. public_key ( ) . to_sec1_bytes ( ) . as_ref ( ) . try_into ( ) . map_err ( |_| RequestTokenError :: InvalidPublicKey ) ?;
261- let request =
262- CreateNucRequest { public_key, signature : signature. to_bytes ( ) . into ( ) , payload : payload. into_bytes ( ) } ;
273+ let request = SignedRequest :: new ( key, & payload) ?;
263274 let url = self . make_url ( "/api/v1/nucs/create" ) ;
264275 let response: Result < CreateNucResponse , RequestTokenError > = self . post ( & url, & request) . await ;
265276 Ok ( response?. token )
@@ -299,6 +310,14 @@ impl NilauthClient for DefaultNilauthClient {
299310 Err ( PaySubscriptionError :: PaymentValidation { tx_hash, payload } )
300311 }
301312
313+ async fn subscription_status ( & self , key : & SecretKey ) -> Result < Subscription , SubscriptionStatusError > {
314+ let payload =
315+ SubscriptionStatusRequest { nonce : rand:: random ( ) , expires_at : Utc :: now ( ) + TOKEN_REQUEST_EXPIRATION } ;
316+ let request = SignedRequest :: new ( key, & payload) ?;
317+ let url = self . make_url ( "/api/v1/subscriptions/status" ) ;
318+ self . post ( & url, & request) . await
319+ }
320+
302321 async fn subscription_cost ( & self ) -> Result < TokenAmount , SubscriptionCostError > {
303322 let url = self . make_url ( "/api/v1/payments/cost" ) ;
304323 let response: Result < GetCostResponse , SubscriptionCostError > = self . get ( & url) . await ;
@@ -349,35 +368,60 @@ impl Display for TxHash {
349368#[ derive( Clone , Deserialize ) ]
350369pub struct About {
351370 /// The server's public key.
352- #[ serde( deserialize_with = "hex::serde::deserialize " ) ]
371+ #[ serde( with = "hex::serde" ) ]
353372 pub public_key : [ u8 ; 33 ] ,
354373}
355374
356375#[ derive( Serialize ) ]
357- struct CreateNucRequest {
358- #[ serde( serialize_with = "hex::serde::serialize " ) ]
376+ struct SignedRequest {
377+ #[ serde( with = "hex::serde" ) ]
359378 public_key : [ u8 ; 33 ] ,
360379
361- #[ serde( serialize_with = "hex::serde::serialize " ) ]
380+ #[ serde( with = "hex::serde" ) ]
362381 signature : [ u8 ; 64 ] ,
363382
364- #[ serde( serialize_with = "hex::serde::serialize " ) ]
383+ #[ serde( with = "hex::serde" ) ]
365384 payload : Vec < u8 > ,
366385}
367386
387+ impl SignedRequest {
388+ fn new < T > ( key : & SecretKey , payload : & T ) -> Result < Self , SigningError >
389+ where
390+ T : Serialize ,
391+ {
392+ let payload = serde_json:: to_string ( & payload) ?;
393+ let signature: Signature = SigningKey :: from ( key) . sign ( payload. as_bytes ( ) ) ;
394+
395+ let public_key =
396+ key. public_key ( ) . to_sec1_bytes ( ) . as_ref ( ) . try_into ( ) . map_err ( |_| SigningError :: InvalidPublicKey ) ?;
397+ let request = Self { public_key, signature : signature. to_bytes ( ) . into ( ) , payload : payload. into_bytes ( ) } ;
398+ Ok ( request)
399+ }
400+ }
401+
402+ /// An error when signing a request.
403+ #[ derive( Debug , thiserror:: Error ) ]
404+ pub enum SigningError {
405+ #[ error( "payload serialization: {0}" ) ]
406+ PayloadSerde ( #[ from] serde_json:: Error ) ,
407+
408+ #[ error( "invalid public key" ) ]
409+ InvalidPublicKey ,
410+ }
411+
368412#[ derive( Serialize ) ]
369413struct CreateNucRequestPayload {
370414 // A nonce, to add entropy.
371- #[ serde( serialize_with = "hex::serde::serialize " ) ]
415+ #[ serde( with = "hex::serde" ) ]
372416 nonce : [ u8 ; 16 ] ,
373417
374418 // When this payload is no longer considered valid, to prevent reusing this forever if it
375419 // leaks.
376- #[ serde( serialize_with = "chrono::serde::ts_seconds::serialize " ) ]
420+ #[ serde( with = "chrono::serde::ts_seconds" ) ]
377421 expires_at : DateTime < Utc > ,
378422
379423 // Our public key, to ensure this request can't be redirected to another authority service.
380- #[ serde( serialize_with = "hex::serde::serialize " ) ]
424+ #[ serde( with = "hex::serde" ) ]
381425 target_public_key : [ u8 ; 33 ] ,
382426}
383427
@@ -390,20 +434,20 @@ struct CreateNucResponse {
390434struct ValidatePaymentRequest {
391435 tx_hash : String ,
392436
393- #[ serde( serialize_with = "hex::serde::serialize " ) ]
437+ #[ serde( with = "hex::serde" ) ]
394438 payload : Vec < u8 > ,
395439
396- #[ serde( serialize_with = "hex::serde::serialize " ) ]
440+ #[ serde( with = "hex::serde" ) ]
397441 public_key : [ u8 ; 33 ] ,
398442}
399443
400444#[ derive( Serialize ) ]
401445struct ValidatePaymentRequestPayload {
402446 #[ allow( dead_code) ]
403- #[ serde( serialize_with = "hex::serde::serialize " ) ]
447+ #[ serde( with = "hex::serde" ) ]
404448 nonce : [ u8 ; 16 ] ,
405449
406- #[ serde( serialize_with = "hex::serde::serialize " ) ]
450+ #[ serde( with = "hex::serde" ) ]
407451 service_public_key : [ u8 ; 33 ] ,
408452}
409453
@@ -442,3 +486,29 @@ pub struct RequestError {
442486 /// The error code.
443487 pub error_code : String ,
444488}
489+
490+ #[ derive( Serialize ) ]
491+ struct SubscriptionStatusRequest {
492+ #[ serde( with = "hex::serde" ) ]
493+ nonce : [ u8 ; 16 ] ,
494+
495+ #[ serde( with = "chrono::serde::ts_seconds" ) ]
496+ expires_at : DateTime < Utc > ,
497+ }
498+
499+ #[ derive( Deserialize ) ]
500+ pub struct Subscription {
501+ /// Whether the user is actively subscribed.
502+ pub subscribed : bool ,
503+
504+ /// The details about the subscription.
505+ pub details : Option < SubscriptionDetails > ,
506+ }
507+
508+ /// The subscription information.
509+ #[ derive( Deserialize ) ]
510+ pub struct SubscriptionDetails {
511+ /// The timestamp at which the subscription expires.
512+ #[ serde( with = "chrono::serde::ts_seconds" ) ]
513+ pub expires_at : DateTime < Utc > ,
514+ }
0 commit comments