1 use std
::path
::PathBuf
;
3 use anyhow
::{bail, format_err, Error}
;
4 use lazy_static
::lazy_static
;
5 use openssl
::pkey
::{PKey, Private, Public}
;
9 use proxmox_sys
::fs
::{file_get_contents, replace_file, CreateOptions}
;
10 use proxmox_lang
::try_block
;
12 use pbs_buildcfg
::configdir
;
13 use pbs_api_types
::Userid
;
15 fn compute_csrf_secret_digest(
21 let mut hasher
= sha
::Sha256
::new();
22 let data
= format
!("{:08X}:{}:", timestamp
, userid
);
23 hasher
.update(data
.as_bytes());
24 hasher
.update(secret
);
26 base64
::encode_config(&hasher
.finish(), base64
::STANDARD_NO_PAD
)
29 pub fn assemble_csrf_prevention_token(
34 let epoch
= proxmox_time
::epoch_i64();
36 let digest
= compute_csrf_secret_digest(epoch
, secret
, userid
);
38 format
!("{:08X}:{}", epoch
, digest
)
41 pub fn verify_csrf_prevention_token(
47 ) -> Result
<i64, Error
> {
49 use std
::collections
::VecDeque
;
51 let mut parts
: VecDeque
<&str> = token
.split('
:'
).collect();
56 bail
!("format error - wrong number of parts.");
59 let timestamp
= parts
.pop_front().unwrap();
60 let sig
= parts
.pop_front().unwrap();
62 let ttime
= i64::from_str_radix(timestamp
, 16).
63 map_err(|err
| format_err
!("timestamp format error - {}", err
))?
;
65 let digest
= compute_csrf_secret_digest(ttime
, secret
, userid
);
68 bail
!("invalid signature.");
71 let now
= proxmox_time
::epoch_i64();
73 let age
= now
- ttime
;
75 bail
!("timestamp newer than expected.");
79 bail
!("timestamp too old.");
83 }).map_err(|err
| format_err
!("invalid csrf token - {}", err
))
86 pub fn generate_csrf_key() -> Result
<(), Error
> {
88 let path
= PathBuf
::from(configdir
!("/csrf.key"));
90 if path
.exists() { return Ok(()); }
92 let rsa
= Rsa
::generate(2048).unwrap();
94 let pem
= rsa
.private_key_to_pem()?
;
96 use nix
::sys
::stat
::Mode
;
98 let backup_user
= pbs_config
::backup_user()?
;
104 .perm(Mode
::from_bits_truncate(0o0640))
105 .owner(nix
::unistd
::ROOT
)
106 .group(backup_user
.gid
),
113 pub fn generate_auth_key() -> Result
<(), Error
> {
115 let priv_path
= PathBuf
::from(configdir
!("/authkey.key"));
117 let mut public_path
= priv_path
.clone();
118 public_path
.set_extension("pub");
120 if priv_path
.exists() && public_path
.exists() { return Ok(()); }
122 let rsa
= Rsa
::generate(4096).unwrap();
124 let priv_pem
= rsa
.private_key_to_pem()?
;
126 use nix
::sys
::stat
::Mode
;
131 CreateOptions
::new().perm(Mode
::from_bits_truncate(0o0600)),
135 let public_pem
= rsa
.public_key_to_pem()?
;
137 let backup_user
= pbs_config
::backup_user()?
;
143 .perm(Mode
::from_bits_truncate(0o0640))
144 .owner(nix
::unistd
::ROOT
)
145 .group(backup_user
.gid
),
152 pub fn csrf_secret() -> &'
static [u8] {
155 static ref SECRET
: Vec
<u8> =
156 file_get_contents(configdir
!("/csrf.key")).unwrap();
162 fn load_public_auth_key() -> Result
<PKey
<Public
>, Error
> {
164 let pem
= file_get_contents(configdir
!("/authkey.pub"))?
;
165 let rsa
= Rsa
::public_key_from_pem(&pem
)?
;
166 let key
= PKey
::from_rsa(rsa
)?
;
171 pub fn public_auth_key() -> &'
static PKey
<Public
> {
174 static ref KEY
: PKey
<Public
> = load_public_auth_key().unwrap();
180 fn load_private_auth_key() -> Result
<PKey
<Private
>, Error
> {
181 let pem
= file_get_contents(configdir
!("/authkey.key"))?
;
182 let rsa
= Rsa
::private_key_from_pem(&pem
)?
;
183 let key
= PKey
::from_rsa(rsa
)?
;
188 pub fn private_auth_key() -> &'
static PKey
<Private
> {
190 static ref KEY
: PKey
<Private
> = load_private_auth_key().unwrap();