Skip to main content

pray_core/
auth.rs

1#[cfg(not(feature = "auth"))]
2use crate::hashing::sha256_prefixed;
3#[cfg(not(feature = "auth"))]
4use crate::{PrayError, PrayResult};
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
8pub struct AuthRegistrationRequest {
9    pub email: String,
10}
11
12#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
13pub struct AuthVerificationRequest {
14    pub email: String,
15    pub code: String,
16}
17
18#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
19pub struct AuthSessionRequest {
20    pub email: String,
21}
22
23#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
24pub struct AuthPasskeyEnrollmentRequest {
25    pub email: String,
26    pub credential_id: String,
27    pub public_key: String,
28    #[serde(default)]
29    pub label: Option<String>,
30}
31
32#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
33pub struct AuthPasskeyChallengeRequest {
34    pub credential_id: String,
35}
36
37#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
38pub struct AuthPasskeyChallengeResponse {
39    pub credential_id: String,
40    pub challenge_id: String,
41    pub challenge: String,
42}
43
44#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
45pub struct AuthPasskeyLoginRequest {
46    pub credential_id: String,
47    pub challenge_id: String,
48    pub signature: String,
49}
50
51#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
52pub struct AuthSshKeyEnrollmentRequest {
53    pub email: String,
54    pub public_key: String,
55    #[serde(default)]
56    pub label: Option<String>,
57}
58
59#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
60pub struct AuthSshKeyChallengeRequest {
61    pub public_key: String,
62}
63
64#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
65pub struct AuthSshKeyChallengeResponse {
66    pub fingerprint: String,
67    pub challenge_id: String,
68    pub challenge: String,
69}
70
71#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
72pub struct AuthSshKeyLoginRequest {
73    pub public_key: String,
74    pub challenge_id: String,
75    pub signature: String,
76}
77
78#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
79pub struct AuthRegistrationResponse {
80    pub email: String,
81    pub verified: bool,
82    #[serde(default)]
83    pub verification_code: Option<String>,
84}
85
86#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
87pub struct AuthVerificationResponse {
88    pub email: String,
89    pub verified: bool,
90    pub token: String,
91    pub kind: AuthSessionKind,
92}
93
94#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
95#[serde(rename_all = "snake_case")]
96pub enum AuthSessionKind {
97    Email,
98    Passkey,
99    SshKey,
100}
101
102#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
103pub struct AuthSessionResponse {
104    pub email: String,
105    pub token: String,
106    pub kind: AuthSessionKind,
107}
108
109#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
110pub struct AuthPasskeyEnrollmentResponse {
111    pub email: String,
112    pub credential_id: String,
113    pub enrolled: bool,
114}
115
116#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
117pub struct AuthPasskeyLoginResponse {
118    pub email: String,
119    pub token: String,
120}
121
122#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
123pub struct AuthChallengeResponse {
124    pub challenge_id: String,
125    pub challenge: String,
126}
127
128#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
129pub struct AuthSshKeyEnrollmentResponse {
130    pub email: String,
131    pub fingerprint: String,
132    pub enrolled: bool,
133}
134
135#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
136pub struct AuthSshKeyLoginResponse {
137    pub email: String,
138    pub token: String,
139}
140
141#[cfg(feature = "auth")]
142pub use crate::auth_store::{
143    bearer_token_from_authorization, ssh_public_key_fingerprint_text, PublishTokenRecord,
144    RegistryAuthStore, PUBLISH_SCOPE,
145};
146
147#[cfg(not(feature = "auth"))]
148pub fn ssh_public_key_fingerprint_text(public_key: &str) -> PrayResult<String> {
149    let mut fields = public_key.split_whitespace();
150    let algorithm = fields.next().ok_or_else(|| PrayError::Parse {
151        kind: "public key",
152        message: "public key must include an algorithm".to_string(),
153    })?;
154    let encoded_key = fields.next().ok_or_else(|| PrayError::Parse {
155        kind: "public key",
156        message: "public key must include key bytes".to_string(),
157    })?;
158    if algorithm != "ssh-ed25519" {
159        return Err(PrayError::Unsupported(format!(
160            "unsupported public key algorithm: {algorithm}"
161        )));
162    }
163
164    Ok(sha256_prefixed(format!("{algorithm} {encoded_key}").as_bytes()).to_ascii_uppercase())
165}