1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
//! `SigningPort` — request signing abstraction.
//!
//! Implement this trait to attach signatures, HMAC tokens, timestamps, or any
//! other authentication material to outbound requests without coupling the
//! calling adapter to the specific signing scheme.
//!
//! # Common use cases
//!
//! - **Frida RPC bridge**: delegate to a sidecar that calls native `.so`
//! signing functions inside a real mobile app (Tinder, Snapchat, etc.)
//! - **AWS Signature V4**: sign S3 or API Gateway requests
//! - **OAuth 1.0a**: generate per-request `oauth_signature`
//! - **Custom HMAC**: add `X-Request-Signature` / `X-Signed-At` headers
//! - **Device attestation**: attach Play Integrity / Apple DeviceCheck tokens
//! - **Timestamp + nonce**: anti-replay headers for trading or payment APIs
use HashMap;
use Future;
use async_trait;
use crate;
// ─────────────────────────────────────────────────────────────────────────────
// Input / Output types
// ─────────────────────────────────────────────────────────────────────────────
/// The request material passed to a [`SigningPort`] for signing.
///
/// # Example
///
/// ```rust
/// use stygian_graph::ports::signing::SigningInput;
/// use serde_json::json;
///
/// let input = SigningInput {
/// method: "GET".to_string(),
/// url: "https://api.example.com/v2/profile".to_string(),
/// headers: Default::default(),
/// body: None,
/// context: json!({"nonce_seed": 42}),
/// };
/// ```
/// The signing material to merge into the outbound request.
///
/// All fields are additive — they are merged on top of the existing request.
/// A `SigningOutput` with all-default values is a valid no-op.
///
/// # Example
///
/// ```rust
/// use stygian_graph::ports::signing::SigningOutput;
/// use std::collections::HashMap;
///
/// let mut headers = HashMap::new();
/// headers.insert("Authorization".to_string(), "HMAC-SHA256 sig=abc123".to_string());
/// headers.insert("X-Signed-At".to_string(), "1710676800000".to_string());
///
/// let output = SigningOutput {
/// headers,
/// query_params: vec![],
/// body_override: None,
/// };
/// ```
// ─────────────────────────────────────────────────────────────────────────────
// Error
// ─────────────────────────────────────────────────────────────────────────────
/// Errors produced by [`SigningPort`] implementations.
// ─────────────────────────────────────────────────────────────────────────────
// Trait
// ─────────────────────────────────────────────────────────────────────────────
/// Port for request signing.
///
/// Implement this trait to attach signatures, HMAC tokens, timestamps, or any
/// other authentication material to outbound requests. The calling adapter
/// merges the returned [`SigningOutput`] into the request before sending.
///
/// The trait uses native `async fn` in traits (Rust 2024 edition) so it is
/// *not* object-safe. Use [`ErasedSigningPort`] with `Arc<dyn ...>` when
/// runtime dispatch is required.
///
/// # Example implementation (passthrough — no signing)
///
/// ```rust
/// use stygian_graph::ports::signing::{SigningPort, SigningInput, SigningOutput, SigningError};
///
/// struct NoSigning;
///
/// impl SigningPort for NoSigning {
/// async fn sign(&self, _input: SigningInput) -> Result<SigningOutput, SigningError> {
/// Ok(SigningOutput::default())
/// }
/// }
/// ```
// ─────────────────────────────────────────────────────────────────────────────
// ErasedSigningPort — object-safe wrapper for Arc<dyn ...>
// ─────────────────────────────────────────────────────────────────────────────
/// Object-safe version of [`SigningPort`] for runtime dispatch.
///
/// [`SigningPort`] uses native `async fn in trait` (Rust 2024) and is NOT
/// object-safe. `ErasedSigningPort` wraps it via `async_trait`, producing
/// `Pin<Box<dyn Future>>` return types required by `Arc<dyn ...>`.
///
/// A blanket `impl<T: SigningPort> ErasedSigningPort for T` is provided — you
/// never need to implement this trait directly.
///
/// # Example
///
/// ```rust
/// use std::sync::Arc;
/// use stygian_graph::ports::signing::ErasedSigningPort;
/// use stygian_graph::adapters::signing::NoopSigningAdapter;
///
/// let signer: Arc<dyn ErasedSigningPort> = Arc::new(NoopSigningAdapter);
/// ```