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
//! ### Environment Variables
//!
//!  Each field in the struct `EnvVars` corresponds to an environment variable. The environment variable name will be in all capitals. The default values are set using the `arg()` macro of the `clap` crate. Check the source code for the defaults.

use std::path::PathBuf;

use clap::Parser;
use hmac::{digest::InvalidLength, Hmac, Mac};
use sha2::Sha256;

use crate::pathutils::Paths;

#[derive(Parser, Clone)]
pub struct EnvVars {
    // Database
    #[arg(env)]
    /// Database name
    pub db_name: String,
    #[arg(env)]
    /// Database hostname
    pub db_host: String,
    #[arg(env)]
    /// Database port
    pub db_port: String,
    #[arg(env)]
    /// Database username
    pub db_user: String,
    #[arg(env)]
    /// Database password
    pub db_password: String,

    // Auth
    #[arg(env)]
    /// OAuth app client id (public token)
    pub gh_client_id: String,
    #[arg(env)]
    /// OAuth app client secret
    pub gh_client_secret: String,
    #[arg(env)]
    /// Github organization name
    pub gh_org_name: String,
    #[arg(env)]
    /// Github organization team slug (this team has access to admin dashboard)
    pub gh_org_team_slug: String,
    #[arg(env)]
    /// An org admin's Github token (with the `read:org` permission)
    pub gh_org_admin_token: String,
    #[arg(env)]
    /// JWT encryption secret (make it a long, randomized string)
    jwt_secret: String,

    // Other configs
    #[arg(env, default_value = "10")]
    /// Maximum number of papers that can be uploaded at a time
    pub max_upload_limit: usize,
    #[arg(env, default_value = "./log/application.log")]
    /// Location where logs are stored
    pub log_location: PathBuf,

    // Paths
    #[arg(env, default_value = "https://static.metakgp.org")]
    /// The URL of the static files server (odin's vault)
    static_files_url: String,
    #[arg(env, default_value = "/srv/static")]
    /// The path where static files are served from
    static_file_storage_location: PathBuf,
    #[arg(env, default_value = "/iqps/uploaded")]
    /// The path where uploaded papers are stored temporarily, relative to the `static_file_storage_location`
    uploaded_qps_path: PathBuf,
    #[arg(env, default_value = "/peqp/qp")]
    /// The path where library papers (scrapped) are stored, relative to the `static_file_storage_location`
    library_qps_path: PathBuf,

    // Server
    #[arg(env, default_value = "8080")]
    /// The port the server listens on
    pub server_port: i32,

    // CORS
    #[arg(env, default_value = "https://qp.metakgp.org,http://localhost:5173")]
    /// List of origins allowed (as a list of values separated by commas `origin1, origin2`)
    pub cors_allowed_origins: String,

    #[arg(skip)]
    /// All paths must be handled using this
    pub paths: Paths,
}

impl EnvVars {
    /// Processes the environment variables after reading.
    pub fn process(mut self) -> Result<Self, Box<dyn std::error::Error>> {
        self.paths = Paths::new(
            &self.static_files_url,
            &self.static_file_storage_location,
            &self.uploaded_qps_path,
            &self.library_qps_path,
        )?;
        self.log_location = std::path::absolute(self.log_location)?;

        Ok(self)
    }

    /// Returns the JWT signing key
    pub fn get_jwt_key(&self) -> Result<Hmac<Sha256>, InvalidLength> {
        Hmac::new_from_slice(self.jwt_secret.as_bytes())
    }
}