forest/rpc/methods/
auth.rs1use crate::{
5 KeyStore,
6 auth::*,
7 lotus_json::lotus_json_with_self,
8 rpc::{ApiPaths, Ctx, Permission, RpcMethod, ServerError},
9};
10use anyhow::Result;
11use chrono::Duration;
12use enumflags2::BitFlags;
13use schemars::JsonSchema;
14use serde::{Deserialize, Serialize};
15use serde_with::{DurationSeconds, serde_as};
16
17pub enum AuthNew {}
19
20impl AuthNew {
21 pub fn create_token(
22 keystore: &KeyStore,
23 token_exp: Duration,
24 permissions: Vec<String>,
25 ) -> anyhow::Result<String> {
26 let ki = keystore.get(JWT_IDENTIFIER)?;
27 Ok(create_token(permissions, ki.private_key(), token_exp)?)
28 }
29}
30
31impl RpcMethod<2> for AuthNew {
32 const NAME: &'static str = "Filecoin.AuthNew";
33 const N_REQUIRED_PARAMS: usize = 1;
34 const PARAM_NAMES: [&'static str; 2] = ["permissions", "expirationSecs"];
36 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
37 const PERMISSION: Permission = Permission::Admin;
38 const DESCRIPTION: &'static str =
39 "Creates a new JWT authentication token with the given permissions.";
40 type Params = (Vec<String>, Option<i64>);
41 type Ok = Vec<u8>;
42 async fn handle(
43 ctx: Ctx,
44 (permissions, expiration_secs): Self::Params,
45 _: &http::Extensions,
46 ) -> Result<Self::Ok, ServerError> {
47 let ks = ctx.keystore.read();
48 let token_exp = expiration_secs
52 .map(chrono::Duration::seconds)
53 .unwrap_or_else(|| chrono::Duration::days(365 * 100));
54 let token = Self::create_token(&ks, token_exp, permissions)?;
55 Ok(token.as_bytes().to_vec())
56 }
57}
58
59pub enum AuthVerify {}
60impl RpcMethod<1> for AuthVerify {
61 const NAME: &'static str = "Filecoin.AuthVerify";
62 const PARAM_NAMES: [&'static str; 1] = ["token"];
63 const API_PATHS: BitFlags<ApiPaths> = ApiPaths::all();
64 const PERMISSION: Permission = Permission::Read;
65 const DESCRIPTION: &'static str =
66 "Verifies a JWT authentication token and returns its permissions.";
67 type Params = (String,);
68 type Ok = Vec<String>;
69 async fn handle(
70 ctx: Ctx,
71 (token,): Self::Params,
72 _: &http::Extensions,
73 ) -> Result<Self::Ok, ServerError> {
74 let ks = ctx.keystore.read();
75 let ki = ks.get(JWT_IDENTIFIER)?;
76 let perms = verify_token(&token, ki.private_key())?;
77 Ok(perms)
78 }
79}
80
81#[serde_as]
82#[derive(Clone, Deserialize, Serialize, JsonSchema)]
83pub struct AuthNewParams {
84 pub perms: Vec<String>,
85 #[serde_as(as = "DurationSeconds<i64>")]
86 #[schemars(with = "i64")]
87 pub token_exp: Duration,
88}
89lotus_json_with_self!(AuthNewParams);
90
91impl AuthNewParams {
92 pub fn process_perms(perm: String) -> Result<Vec<String>, ServerError> {
93 Ok(match perm.to_lowercase().as_str() {
94 "admin" => ADMIN,
95 "sign" => SIGN,
96 "write" => WRITE,
97 "read" => READ,
98 _ => return Err(ServerError::invalid_params("unknown permission", None)),
99 }
100 .iter()
101 .map(ToString::to_string)
102 .collect())
103 }
104}
105
106impl From<AuthNewParams> for (Vec<String>, Option<i64>) {
107 fn from(value: AuthNewParams) -> Self {
108 (value.perms, Some(value.token_exp.num_seconds()))
109 }
110}