@auths-dev/sdk 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.toml +45 -0
- package/README.md +163 -4
- package/__test__/client.spec.ts +78 -0
- package/__test__/exports.spec.ts +57 -0
- package/__test__/integration.spec.ts +407 -0
- package/__test__/policy.spec.ts +202 -0
- package/__test__/verify.spec.ts +88 -0
- package/build.rs +5 -0
- package/index.d.ts +259 -0
- package/index.js +622 -1
- package/lib/artifacts.ts +124 -0
- package/lib/attestations.ts +126 -0
- package/lib/audit.ts +189 -0
- package/lib/client.ts +293 -0
- package/lib/commits.ts +70 -0
- package/lib/devices.ts +178 -0
- package/lib/errors.ts +306 -0
- package/lib/identity.ts +280 -0
- package/lib/index.ts +125 -0
- package/lib/native.ts +255 -0
- package/lib/org.ts +235 -0
- package/lib/pairing.ts +271 -0
- package/lib/policy.ts +669 -0
- package/lib/signing.ts +204 -0
- package/lib/trust.ts +152 -0
- package/lib/types.ts +179 -0
- package/lib/verify.ts +241 -0
- package/lib/witness.ts +91 -0
- package/npm/darwin-arm64/README.md +3 -0
- package/npm/darwin-arm64/package.json +23 -0
- package/npm/linux-arm64-gnu/README.md +3 -0
- package/npm/linux-arm64-gnu/package.json +26 -0
- package/npm/linux-x64-gnu/README.md +3 -0
- package/npm/linux-x64-gnu/package.json +26 -0
- package/npm/win32-arm64-msvc/README.md +3 -0
- package/npm/win32-arm64-msvc/package.json +23 -0
- package/npm/win32-x64-msvc/README.md +3 -0
- package/npm/win32-x64-msvc/package.json +23 -0
- package/package.json +51 -16
- package/src/artifact.rs +217 -0
- package/src/attestation_query.rs +104 -0
- package/src/audit.rs +128 -0
- package/src/commit_sign.rs +63 -0
- package/src/device.rs +212 -0
- package/src/diagnostics.rs +106 -0
- package/src/error.rs +5 -0
- package/src/helpers.rs +60 -0
- package/src/identity.rs +467 -0
- package/src/lib.rs +26 -0
- package/src/org.rs +430 -0
- package/src/pairing.rs +454 -0
- package/src/policy.rs +147 -0
- package/src/sign.rs +215 -0
- package/src/trust.rs +189 -0
- package/src/types.rs +205 -0
- package/src/verify.rs +447 -0
- package/src/witness.rs +138 -0
- package/tsconfig.json +19 -0
- package/typedoc.json +18 -0
- package/vitest.config.ts +12 -0
package/src/sign.rs
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
use auths_core::signing::{PrefilledPassphraseProvider, SecureSigner, StorageSigner};
|
|
2
|
+
use auths_core::storage::keychain::{KeyAlias, get_platform_keychain_with_config};
|
|
3
|
+
use auths_verifier::core::MAX_ATTESTATION_JSON_SIZE;
|
|
4
|
+
use auths_verifier::types::IdentityDID;
|
|
5
|
+
use napi_derive::napi;
|
|
6
|
+
|
|
7
|
+
use crate::error::format_error;
|
|
8
|
+
use crate::helpers::{make_env_config, resolve_passphrase};
|
|
9
|
+
use crate::types::{NapiActionEnvelope, NapiCommitSignResult};
|
|
10
|
+
|
|
11
|
+
fn make_signer(
|
|
12
|
+
passphrase: &str,
|
|
13
|
+
repo_path: &str,
|
|
14
|
+
) -> napi::Result<(
|
|
15
|
+
StorageSigner<Box<dyn auths_core::storage::keychain::KeyStorage + Send + Sync>>,
|
|
16
|
+
PrefilledPassphraseProvider,
|
|
17
|
+
)> {
|
|
18
|
+
let env_config = make_env_config(passphrase, repo_path);
|
|
19
|
+
let keychain = get_platform_keychain_with_config(&env_config)
|
|
20
|
+
.map_err(|e| format_error("AUTHS_KEYCHAIN_ERROR", format!("Keychain error: {e}")))?;
|
|
21
|
+
let signer = StorageSigner::new(keychain);
|
|
22
|
+
let provider = PrefilledPassphraseProvider::new(passphrase);
|
|
23
|
+
Ok((signer, provider))
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
#[napi]
|
|
27
|
+
pub fn sign_as_identity(
|
|
28
|
+
message: napi::bindgen_prelude::Buffer,
|
|
29
|
+
identity_did: String,
|
|
30
|
+
repo_path: String,
|
|
31
|
+
passphrase: Option<String>,
|
|
32
|
+
) -> napi::Result<NapiCommitSignResult> {
|
|
33
|
+
let passphrase_str = resolve_passphrase(passphrase);
|
|
34
|
+
let (signer, provider) = make_signer(&passphrase_str, &repo_path)?;
|
|
35
|
+
let did =
|
|
36
|
+
IdentityDID::parse(&identity_did).map_err(|e| format_error("AUTHS_INVALID_INPUT", e))?;
|
|
37
|
+
|
|
38
|
+
let sig_bytes = signer
|
|
39
|
+
.sign_for_identity(&did, &provider, message.as_ref())
|
|
40
|
+
.map_err(|e| format_error("AUTHS_SIGNING_FAILED", format!("Signing failed: {e}")))?;
|
|
41
|
+
|
|
42
|
+
Ok(NapiCommitSignResult {
|
|
43
|
+
signature: hex::encode(sig_bytes),
|
|
44
|
+
signer_did: identity_did,
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
#[napi]
|
|
49
|
+
pub fn sign_action_as_identity(
|
|
50
|
+
action_type: String,
|
|
51
|
+
payload_json: String,
|
|
52
|
+
identity_did: String,
|
|
53
|
+
repo_path: String,
|
|
54
|
+
passphrase: Option<String>,
|
|
55
|
+
) -> napi::Result<NapiActionEnvelope> {
|
|
56
|
+
if payload_json.len() > MAX_ATTESTATION_JSON_SIZE {
|
|
57
|
+
return Err(format_error(
|
|
58
|
+
"AUTHS_INVALID_INPUT",
|
|
59
|
+
format!(
|
|
60
|
+
"Payload JSON too large: {} bytes, max {MAX_ATTESTATION_JSON_SIZE}",
|
|
61
|
+
payload_json.len()
|
|
62
|
+
),
|
|
63
|
+
));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let payload: serde_json::Value = serde_json::from_str(&payload_json)
|
|
67
|
+
.map_err(|e| format_error("AUTHS_INVALID_INPUT", format!("Invalid payload JSON: {e}")))?;
|
|
68
|
+
|
|
69
|
+
#[allow(clippy::disallowed_methods)] // Presentation boundary
|
|
70
|
+
let timestamp = chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true);
|
|
71
|
+
|
|
72
|
+
let signing_data = serde_json::json!({
|
|
73
|
+
"version": "1.0",
|
|
74
|
+
"type": action_type,
|
|
75
|
+
"identity": identity_did,
|
|
76
|
+
"payload": payload,
|
|
77
|
+
"timestamp": ×tamp,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
let canonical = json_canon::to_string(&signing_data).map_err(|e| {
|
|
81
|
+
format_error(
|
|
82
|
+
"AUTHS_SERIALIZATION_ERROR",
|
|
83
|
+
format!("Canonicalization failed: {e}"),
|
|
84
|
+
)
|
|
85
|
+
})?;
|
|
86
|
+
|
|
87
|
+
let passphrase_str = resolve_passphrase(passphrase);
|
|
88
|
+
let (signer, provider) = make_signer(&passphrase_str, &repo_path)?;
|
|
89
|
+
let did =
|
|
90
|
+
IdentityDID::parse(&identity_did).map_err(|e| format_error("AUTHS_INVALID_INPUT", e))?;
|
|
91
|
+
|
|
92
|
+
let sig_bytes = signer
|
|
93
|
+
.sign_for_identity(&did, &provider, canonical.as_bytes())
|
|
94
|
+
.map_err(|e| format_error("AUTHS_SIGNING_FAILED", format!("Signing failed: {e}")))?;
|
|
95
|
+
|
|
96
|
+
let sig_hex = hex::encode(sig_bytes);
|
|
97
|
+
|
|
98
|
+
let envelope = serde_json::json!({
|
|
99
|
+
"version": "1.0",
|
|
100
|
+
"type": action_type,
|
|
101
|
+
"identity": identity_did,
|
|
102
|
+
"payload": payload,
|
|
103
|
+
"timestamp": timestamp,
|
|
104
|
+
"signature": sig_hex,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
let envelope_json = serde_json::to_string(&envelope).map_err(|e| {
|
|
108
|
+
format_error(
|
|
109
|
+
"AUTHS_SERIALIZATION_ERROR",
|
|
110
|
+
format!("Failed to serialize envelope: {e}"),
|
|
111
|
+
)
|
|
112
|
+
})?;
|
|
113
|
+
|
|
114
|
+
Ok(NapiActionEnvelope {
|
|
115
|
+
envelope_json,
|
|
116
|
+
signature_hex: sig_hex,
|
|
117
|
+
signer_did: identity_did,
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
#[napi]
|
|
122
|
+
pub fn sign_as_agent(
|
|
123
|
+
message: napi::bindgen_prelude::Buffer,
|
|
124
|
+
key_alias: String,
|
|
125
|
+
repo_path: String,
|
|
126
|
+
passphrase: Option<String>,
|
|
127
|
+
) -> napi::Result<NapiCommitSignResult> {
|
|
128
|
+
let passphrase_str = resolve_passphrase(passphrase);
|
|
129
|
+
let (signer, provider) = make_signer(&passphrase_str, &repo_path)?;
|
|
130
|
+
let alias = KeyAlias::new(&key_alias)
|
|
131
|
+
.map_err(|e| format_error("AUTHS_KEY_NOT_FOUND", format!("Invalid key alias: {e}")))?;
|
|
132
|
+
|
|
133
|
+
let sig_bytes = signer
|
|
134
|
+
.sign_with_alias(&alias, &provider, message.as_ref())
|
|
135
|
+
.map_err(|e| format_error("AUTHS_SIGNING_FAILED", format!("Signing failed: {e}")))?;
|
|
136
|
+
|
|
137
|
+
Ok(NapiCommitSignResult {
|
|
138
|
+
signature: hex::encode(sig_bytes),
|
|
139
|
+
signer_did: key_alias,
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
#[napi]
|
|
144
|
+
pub fn sign_action_as_agent(
|
|
145
|
+
action_type: String,
|
|
146
|
+
payload_json: String,
|
|
147
|
+
key_alias: String,
|
|
148
|
+
agent_did: String,
|
|
149
|
+
repo_path: String,
|
|
150
|
+
passphrase: Option<String>,
|
|
151
|
+
) -> napi::Result<NapiActionEnvelope> {
|
|
152
|
+
if payload_json.len() > MAX_ATTESTATION_JSON_SIZE {
|
|
153
|
+
return Err(format_error(
|
|
154
|
+
"AUTHS_INVALID_INPUT",
|
|
155
|
+
format!(
|
|
156
|
+
"Payload JSON too large: {} bytes, max {MAX_ATTESTATION_JSON_SIZE}",
|
|
157
|
+
payload_json.len()
|
|
158
|
+
),
|
|
159
|
+
));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
let payload: serde_json::Value = serde_json::from_str(&payload_json)
|
|
163
|
+
.map_err(|e| format_error("AUTHS_INVALID_INPUT", format!("Invalid payload JSON: {e}")))?;
|
|
164
|
+
|
|
165
|
+
#[allow(clippy::disallowed_methods)]
|
|
166
|
+
let timestamp = chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true);
|
|
167
|
+
|
|
168
|
+
let signing_data = serde_json::json!({
|
|
169
|
+
"version": "1.0",
|
|
170
|
+
"type": action_type,
|
|
171
|
+
"identity": agent_did,
|
|
172
|
+
"payload": payload,
|
|
173
|
+
"timestamp": ×tamp,
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
let canonical = json_canon::to_string(&signing_data).map_err(|e| {
|
|
177
|
+
format_error(
|
|
178
|
+
"AUTHS_SERIALIZATION_ERROR",
|
|
179
|
+
format!("Canonicalization failed: {e}"),
|
|
180
|
+
)
|
|
181
|
+
})?;
|
|
182
|
+
|
|
183
|
+
let passphrase_str = resolve_passphrase(passphrase);
|
|
184
|
+
let (signer, provider) = make_signer(&passphrase_str, &repo_path)?;
|
|
185
|
+
let alias = KeyAlias::new(&key_alias)
|
|
186
|
+
.map_err(|e| format_error("AUTHS_KEY_NOT_FOUND", format!("Invalid key alias: {e}")))?;
|
|
187
|
+
|
|
188
|
+
let sig_bytes = signer
|
|
189
|
+
.sign_with_alias(&alias, &provider, canonical.as_bytes())
|
|
190
|
+
.map_err(|e| format_error("AUTHS_SIGNING_FAILED", format!("Signing failed: {e}")))?;
|
|
191
|
+
|
|
192
|
+
let sig_hex = hex::encode(sig_bytes);
|
|
193
|
+
|
|
194
|
+
let envelope = serde_json::json!({
|
|
195
|
+
"version": "1.0",
|
|
196
|
+
"type": action_type,
|
|
197
|
+
"identity": agent_did,
|
|
198
|
+
"payload": payload,
|
|
199
|
+
"timestamp": timestamp,
|
|
200
|
+
"signature": sig_hex,
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
let envelope_json = serde_json::to_string(&envelope).map_err(|e| {
|
|
204
|
+
format_error(
|
|
205
|
+
"AUTHS_SERIALIZATION_ERROR",
|
|
206
|
+
format!("Failed to serialize envelope: {e}"),
|
|
207
|
+
)
|
|
208
|
+
})?;
|
|
209
|
+
|
|
210
|
+
Ok(NapiActionEnvelope {
|
|
211
|
+
envelope_json,
|
|
212
|
+
signature_hex: sig_hex,
|
|
213
|
+
signer_did: agent_did,
|
|
214
|
+
})
|
|
215
|
+
}
|
package/src/trust.rs
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
use std::path::PathBuf;
|
|
2
|
+
use std::sync::Arc;
|
|
3
|
+
|
|
4
|
+
use auths_core::trust::pinned::{PinnedIdentity, PinnedIdentityStore, TrustLevel};
|
|
5
|
+
use auths_id::identity::resolve::{DefaultDidResolver, DidResolver, RegistryDidResolver};
|
|
6
|
+
use auths_storage::git::{GitRegistryBackend, RegistryConfig};
|
|
7
|
+
use auths_verifier::PublicKeyHex;
|
|
8
|
+
use napi_derive::napi;
|
|
9
|
+
|
|
10
|
+
use crate::error::format_error;
|
|
11
|
+
|
|
12
|
+
fn resolve_repo(repo_path: &str) -> PathBuf {
|
|
13
|
+
PathBuf::from(shellexpand::tilde(repo_path).as_ref())
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
fn store_path(repo_path: &str) -> PathBuf {
|
|
17
|
+
resolve_repo(repo_path).join("known_identities.json")
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
fn parse_trust_level(s: &str) -> napi::Result<TrustLevel> {
|
|
21
|
+
match s {
|
|
22
|
+
"tofu" => Ok(TrustLevel::Tofu),
|
|
23
|
+
"manual" => Ok(TrustLevel::Manual),
|
|
24
|
+
"org_policy" => Ok(TrustLevel::OrgPolicy),
|
|
25
|
+
_ => Err(format_error(
|
|
26
|
+
"AUTHS_INVALID_INPUT",
|
|
27
|
+
format!(
|
|
28
|
+
"Invalid trust_level '{}': must be one of 'tofu', 'manual', 'org_policy'",
|
|
29
|
+
s
|
|
30
|
+
),
|
|
31
|
+
)),
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
fn trust_level_str(tl: &TrustLevel) -> &'static str {
|
|
36
|
+
match tl {
|
|
37
|
+
TrustLevel::Tofu => "tofu",
|
|
38
|
+
TrustLevel::Manual => "manual",
|
|
39
|
+
TrustLevel::OrgPolicy => "org_policy",
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
#[napi(object)]
|
|
44
|
+
#[derive(Clone)]
|
|
45
|
+
pub struct NapiPinnedIdentity {
|
|
46
|
+
pub did: String,
|
|
47
|
+
pub label: Option<String>,
|
|
48
|
+
pub trust_level: String,
|
|
49
|
+
pub first_seen: String,
|
|
50
|
+
pub kel_sequence: Option<u32>,
|
|
51
|
+
pub pinned_at: String,
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
#[napi]
|
|
55
|
+
pub fn pin_identity(
|
|
56
|
+
did: String,
|
|
57
|
+
repo_path: String,
|
|
58
|
+
label: Option<String>,
|
|
59
|
+
trust_level: Option<String>,
|
|
60
|
+
) -> napi::Result<NapiPinnedIdentity> {
|
|
61
|
+
let tl = parse_trust_level(&trust_level.unwrap_or_else(|| "manual".to_string()))?;
|
|
62
|
+
let store = PinnedIdentityStore::new(store_path(&repo_path));
|
|
63
|
+
let repo = resolve_repo(&repo_path);
|
|
64
|
+
|
|
65
|
+
let resolved = DefaultDidResolver::with_repo(&repo)
|
|
66
|
+
.resolve(&did)
|
|
67
|
+
.or_else(|_| {
|
|
68
|
+
let backend: Arc<dyn auths_id::ports::registry::RegistryBackend + Send + Sync> =
|
|
69
|
+
Arc::new(GitRegistryBackend::from_config_unchecked(
|
|
70
|
+
RegistryConfig::single_tenant(&repo),
|
|
71
|
+
));
|
|
72
|
+
RegistryDidResolver::new(backend).resolve(&did)
|
|
73
|
+
})
|
|
74
|
+
.map_err(|e| {
|
|
75
|
+
format_error(
|
|
76
|
+
"AUTHS_TRUST_ERROR",
|
|
77
|
+
format!("Cannot resolve public key for {did}: {e}"),
|
|
78
|
+
)
|
|
79
|
+
})?;
|
|
80
|
+
#[allow(clippy::disallowed_methods)] // INVARIANT: hex::encode always produces valid hex
|
|
81
|
+
let public_key_hex = PublicKeyHex::new_unchecked(hex::encode(resolved.public_key().as_bytes()));
|
|
82
|
+
|
|
83
|
+
#[allow(clippy::disallowed_methods)]
|
|
84
|
+
let now = chrono::Utc::now();
|
|
85
|
+
|
|
86
|
+
if let Ok(Some(existing)) = store.lookup(&did) {
|
|
87
|
+
let _ = store.remove(&did);
|
|
88
|
+
let pin = PinnedIdentity {
|
|
89
|
+
did: did.clone(),
|
|
90
|
+
public_key_hex: if public_key_hex.as_ref().is_empty() {
|
|
91
|
+
existing.public_key_hex
|
|
92
|
+
} else {
|
|
93
|
+
public_key_hex
|
|
94
|
+
},
|
|
95
|
+
kel_tip_said: existing.kel_tip_said,
|
|
96
|
+
kel_sequence: existing.kel_sequence,
|
|
97
|
+
first_seen: existing.first_seen,
|
|
98
|
+
origin: label.clone().unwrap_or(existing.origin),
|
|
99
|
+
trust_level: tl.clone(),
|
|
100
|
+
};
|
|
101
|
+
store
|
|
102
|
+
.pin(pin.clone())
|
|
103
|
+
.map_err(|e| format_error("AUTHS_TRUST_ERROR", e))?;
|
|
104
|
+
return Ok(NapiPinnedIdentity {
|
|
105
|
+
did: pin.did,
|
|
106
|
+
label,
|
|
107
|
+
trust_level: trust_level_str(&pin.trust_level).to_string(),
|
|
108
|
+
first_seen: pin.first_seen.to_rfc3339(),
|
|
109
|
+
kel_sequence: pin.kel_sequence.map(|s| s as u32),
|
|
110
|
+
pinned_at: now.to_rfc3339(),
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
let pin = PinnedIdentity {
|
|
115
|
+
did: did.clone(),
|
|
116
|
+
public_key_hex,
|
|
117
|
+
kel_tip_said: None,
|
|
118
|
+
kel_sequence: None,
|
|
119
|
+
first_seen: now,
|
|
120
|
+
origin: label.clone().unwrap_or_else(|| "manual".to_string()),
|
|
121
|
+
trust_level: tl.clone(),
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
store
|
|
125
|
+
.pin(pin)
|
|
126
|
+
.map_err(|e| format_error("AUTHS_TRUST_ERROR", e))?;
|
|
127
|
+
|
|
128
|
+
Ok(NapiPinnedIdentity {
|
|
129
|
+
did,
|
|
130
|
+
label,
|
|
131
|
+
trust_level: trust_level_str(&tl).to_string(),
|
|
132
|
+
first_seen: now.to_rfc3339(),
|
|
133
|
+
kel_sequence: None,
|
|
134
|
+
pinned_at: now.to_rfc3339(),
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
#[napi]
|
|
139
|
+
pub fn remove_pinned_identity(did: String, repo_path: String) -> napi::Result<()> {
|
|
140
|
+
let store = PinnedIdentityStore::new(store_path(&repo_path));
|
|
141
|
+
store
|
|
142
|
+
.remove(&did)
|
|
143
|
+
.map_err(|e| format_error("AUTHS_TRUST_ERROR", e))?;
|
|
144
|
+
Ok(())
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
#[napi]
|
|
148
|
+
pub fn list_pinned_identities(repo_path: String) -> napi::Result<String> {
|
|
149
|
+
let store = PinnedIdentityStore::new(store_path(&repo_path));
|
|
150
|
+
let entries = store
|
|
151
|
+
.list()
|
|
152
|
+
.map_err(|e| format_error("AUTHS_TRUST_ERROR", e))?;
|
|
153
|
+
|
|
154
|
+
let json_entries: Vec<serde_json::Value> = entries
|
|
155
|
+
.iter()
|
|
156
|
+
.map(|e| {
|
|
157
|
+
serde_json::json!({
|
|
158
|
+
"did": e.did,
|
|
159
|
+
"label": e.origin,
|
|
160
|
+
"trust_level": trust_level_str(&e.trust_level),
|
|
161
|
+
"first_seen": e.first_seen.to_rfc3339(),
|
|
162
|
+
"kel_sequence": e.kel_sequence,
|
|
163
|
+
"pinned_at": e.first_seen.to_rfc3339(),
|
|
164
|
+
})
|
|
165
|
+
})
|
|
166
|
+
.collect();
|
|
167
|
+
|
|
168
|
+
serde_json::to_string(&json_entries).map_err(|e| format_error("AUTHS_TRUST_ERROR", e))
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
#[napi]
|
|
172
|
+
pub fn get_pinned_identity(
|
|
173
|
+
did: String,
|
|
174
|
+
repo_path: String,
|
|
175
|
+
) -> napi::Result<Option<NapiPinnedIdentity>> {
|
|
176
|
+
let store = PinnedIdentityStore::new(store_path(&repo_path));
|
|
177
|
+
let entry = store
|
|
178
|
+
.lookup(&did)
|
|
179
|
+
.map_err(|e| format_error("AUTHS_TRUST_ERROR", e))?;
|
|
180
|
+
|
|
181
|
+
Ok(entry.map(|e| NapiPinnedIdentity {
|
|
182
|
+
did: e.did,
|
|
183
|
+
label: Some(e.origin),
|
|
184
|
+
trust_level: trust_level_str(&e.trust_level).to_string(),
|
|
185
|
+
first_seen: e.first_seen.to_rfc3339(),
|
|
186
|
+
kel_sequence: e.kel_sequence.map(|s| s as u32),
|
|
187
|
+
pinned_at: e.first_seen.to_rfc3339(),
|
|
188
|
+
}))
|
|
189
|
+
}
|
package/src/types.rs
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
use napi_derive::napi;
|
|
2
|
+
|
|
3
|
+
use auths_verifier::types::{
|
|
4
|
+
ChainLink as RustChainLink, VerificationReport as RustVerificationReport,
|
|
5
|
+
VerificationStatus as RustVerificationStatus,
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
#[napi(object)]
|
|
9
|
+
#[derive(Clone)]
|
|
10
|
+
pub struct NapiVerificationResult {
|
|
11
|
+
pub valid: bool,
|
|
12
|
+
pub error: Option<String>,
|
|
13
|
+
pub error_code: Option<String>,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
#[napi(object)]
|
|
17
|
+
#[derive(Clone)]
|
|
18
|
+
pub struct NapiVerificationStatus {
|
|
19
|
+
pub status_type: String,
|
|
20
|
+
pub at: Option<String>,
|
|
21
|
+
pub step: Option<u32>,
|
|
22
|
+
pub missing_link: Option<String>,
|
|
23
|
+
pub required: Option<u32>,
|
|
24
|
+
pub verified: Option<u32>,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
impl NapiVerificationStatus {
|
|
28
|
+
pub fn is_valid(&self) -> bool {
|
|
29
|
+
self.status_type == "Valid"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
impl From<RustVerificationStatus> for NapiVerificationStatus {
|
|
34
|
+
fn from(status: RustVerificationStatus) -> Self {
|
|
35
|
+
match status {
|
|
36
|
+
RustVerificationStatus::Valid => NapiVerificationStatus {
|
|
37
|
+
status_type: "Valid".to_string(),
|
|
38
|
+
at: None,
|
|
39
|
+
step: None,
|
|
40
|
+
missing_link: None,
|
|
41
|
+
required: None,
|
|
42
|
+
verified: None,
|
|
43
|
+
},
|
|
44
|
+
RustVerificationStatus::Expired { at } => NapiVerificationStatus {
|
|
45
|
+
status_type: "Expired".to_string(),
|
|
46
|
+
at: Some(at.to_rfc3339()),
|
|
47
|
+
step: None,
|
|
48
|
+
missing_link: None,
|
|
49
|
+
required: None,
|
|
50
|
+
verified: None,
|
|
51
|
+
},
|
|
52
|
+
RustVerificationStatus::Revoked { at } => NapiVerificationStatus {
|
|
53
|
+
status_type: "Revoked".to_string(),
|
|
54
|
+
at: at.map(|t| t.to_rfc3339()),
|
|
55
|
+
step: None,
|
|
56
|
+
missing_link: None,
|
|
57
|
+
required: None,
|
|
58
|
+
verified: None,
|
|
59
|
+
},
|
|
60
|
+
RustVerificationStatus::InvalidSignature { step } => NapiVerificationStatus {
|
|
61
|
+
status_type: "InvalidSignature".to_string(),
|
|
62
|
+
at: None,
|
|
63
|
+
step: Some(step as u32),
|
|
64
|
+
missing_link: None,
|
|
65
|
+
required: None,
|
|
66
|
+
verified: None,
|
|
67
|
+
},
|
|
68
|
+
RustVerificationStatus::BrokenChain { missing_link } => NapiVerificationStatus {
|
|
69
|
+
status_type: "BrokenChain".to_string(),
|
|
70
|
+
at: None,
|
|
71
|
+
step: None,
|
|
72
|
+
missing_link: Some(missing_link),
|
|
73
|
+
required: None,
|
|
74
|
+
verified: None,
|
|
75
|
+
},
|
|
76
|
+
RustVerificationStatus::InsufficientWitnesses { required, verified } => {
|
|
77
|
+
NapiVerificationStatus {
|
|
78
|
+
status_type: "InsufficientWitnesses".to_string(),
|
|
79
|
+
at: None,
|
|
80
|
+
step: None,
|
|
81
|
+
missing_link: None,
|
|
82
|
+
required: Some(required as u32),
|
|
83
|
+
verified: Some(verified as u32),
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
#[napi(object)]
|
|
91
|
+
#[derive(Clone)]
|
|
92
|
+
pub struct NapiChainLink {
|
|
93
|
+
pub issuer: String,
|
|
94
|
+
pub subject: String,
|
|
95
|
+
pub valid: bool,
|
|
96
|
+
pub error: Option<String>,
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
impl From<RustChainLink> for NapiChainLink {
|
|
100
|
+
fn from(link: RustChainLink) -> Self {
|
|
101
|
+
NapiChainLink {
|
|
102
|
+
issuer: link.issuer,
|
|
103
|
+
subject: link.subject,
|
|
104
|
+
valid: link.valid,
|
|
105
|
+
error: link.error,
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
#[napi(object)]
|
|
111
|
+
#[derive(Clone)]
|
|
112
|
+
pub struct NapiVerificationReport {
|
|
113
|
+
pub status: NapiVerificationStatus,
|
|
114
|
+
pub chain: Vec<NapiChainLink>,
|
|
115
|
+
pub warnings: Vec<String>,
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
impl NapiVerificationReport {
|
|
119
|
+
pub fn is_valid(&self) -> bool {
|
|
120
|
+
self.status.is_valid()
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
impl From<RustVerificationReport> for NapiVerificationReport {
|
|
125
|
+
fn from(report: RustVerificationReport) -> Self {
|
|
126
|
+
NapiVerificationReport {
|
|
127
|
+
status: report.status.into(),
|
|
128
|
+
chain: report.chain.into_iter().map(|l| l.into()).collect(),
|
|
129
|
+
warnings: report.warnings,
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Identity types
|
|
135
|
+
|
|
136
|
+
#[napi(object)]
|
|
137
|
+
#[derive(Clone)]
|
|
138
|
+
pub struct NapiIdentityResult {
|
|
139
|
+
pub did: String,
|
|
140
|
+
pub key_alias: String,
|
|
141
|
+
pub public_key_hex: String,
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
#[napi(object)]
|
|
145
|
+
#[derive(Clone)]
|
|
146
|
+
pub struct NapiAgentIdentityBundle {
|
|
147
|
+
pub agent_did: String,
|
|
148
|
+
pub key_alias: String,
|
|
149
|
+
pub attestation_json: String,
|
|
150
|
+
pub public_key_hex: String,
|
|
151
|
+
pub repo_path: Option<String>,
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
#[napi(object)]
|
|
155
|
+
#[derive(Clone)]
|
|
156
|
+
pub struct NapiDelegatedAgentBundle {
|
|
157
|
+
pub agent_did: String,
|
|
158
|
+
pub key_alias: String,
|
|
159
|
+
pub attestation_json: String,
|
|
160
|
+
pub public_key_hex: String,
|
|
161
|
+
pub repo_path: Option<String>,
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
#[napi(object)]
|
|
165
|
+
#[derive(Clone)]
|
|
166
|
+
pub struct NapiRotationResult {
|
|
167
|
+
pub controller_did: String,
|
|
168
|
+
pub new_key_fingerprint: String,
|
|
169
|
+
pub previous_key_fingerprint: String,
|
|
170
|
+
pub sequence: i64,
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Device types
|
|
174
|
+
|
|
175
|
+
#[napi(object)]
|
|
176
|
+
#[derive(Clone)]
|
|
177
|
+
pub struct NapiLinkResult {
|
|
178
|
+
pub device_did: String,
|
|
179
|
+
pub attestation_id: String,
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
#[napi(object)]
|
|
183
|
+
#[derive(Clone)]
|
|
184
|
+
pub struct NapiExtensionResult {
|
|
185
|
+
pub device_did: String,
|
|
186
|
+
pub new_expires_at: String,
|
|
187
|
+
pub previous_expires_at: Option<String>,
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Signing types
|
|
191
|
+
|
|
192
|
+
#[napi(object)]
|
|
193
|
+
#[derive(Clone)]
|
|
194
|
+
pub struct NapiCommitSignResult {
|
|
195
|
+
pub signature: String,
|
|
196
|
+
pub signer_did: String,
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
#[napi(object)]
|
|
200
|
+
#[derive(Clone)]
|
|
201
|
+
pub struct NapiActionEnvelope {
|
|
202
|
+
pub envelope_json: String,
|
|
203
|
+
pub signature_hex: String,
|
|
204
|
+
pub signer_did: String,
|
|
205
|
+
}
|