1 use anyhow
::{bail, format_err, Error}
;
2 use lazy_static
::lazy_static
;
4 use openssl
::rsa
::{Rsa}
;
5 use openssl
::pkey
::{PKey, Public, Private}
;
8 use std
::path
::PathBuf
;
10 use proxmox
::tools
::fs
::{file_get_contents, replace_file, CreateOptions}
;
11 use proxmox
::try_block
;
13 use pbs_buildcfg
::configdir
;
15 use crate::api2
::types
::Userid
;
17 fn compute_csrf_secret_digest(
23 let mut hasher
= sha
::Sha256
::new();
24 let data
= format
!("{:08X}:{}:", timestamp
, userid
);
25 hasher
.update(data
.as_bytes());
26 hasher
.update(secret
);
28 base64
::encode_config(&hasher
.finish(), base64
::STANDARD_NO_PAD
)
31 pub fn assemble_csrf_prevention_token(
36 let epoch
= proxmox
::tools
::time
::epoch_i64();
38 let digest
= compute_csrf_secret_digest(epoch
, secret
, userid
);
40 format
!("{:08X}:{}", epoch
, digest
)
43 pub fn verify_csrf_prevention_token(
49 ) -> Result
<i64, Error
> {
51 use std
::collections
::VecDeque
;
53 let mut parts
: VecDeque
<&str> = token
.split('
:'
).collect();
58 bail
!("format error - wrong number of parts.");
61 let timestamp
= parts
.pop_front().unwrap();
62 let sig
= parts
.pop_front().unwrap();
64 let ttime
= i64::from_str_radix(timestamp
, 16).
65 map_err(|err
| format_err
!("timestamp format error - {}", err
))?
;
67 let digest
= compute_csrf_secret_digest(ttime
, secret
, userid
);
70 bail
!("invalid signature.");
73 let now
= proxmox
::tools
::time
::epoch_i64();
75 let age
= now
- ttime
;
77 bail
!("timestamp newer than expected.");
81 bail
!("timestamp too old.");
85 }).map_err(|err
| format_err
!("invalid csrf token - {}", err
))
88 pub fn generate_csrf_key() -> Result
<(), Error
> {
90 let path
= PathBuf
::from(configdir
!("/csrf.key"));
92 if path
.exists() { return Ok(()); }
94 let rsa
= Rsa
::generate(2048).unwrap();
96 let pem
= rsa
.private_key_to_pem()?
;
98 use nix
::sys
::stat
::Mode
;
100 let backup_user
= crate::backup
::backup_user()?
;
106 .perm(Mode
::from_bits_truncate(0o0640))
107 .owner(nix
::unistd
::ROOT
)
108 .group(backup_user
.gid
),
114 pub fn generate_auth_key() -> Result
<(), Error
> {
116 let priv_path
= PathBuf
::from(configdir
!("/authkey.key"));
118 let mut public_path
= priv_path
.clone();
119 public_path
.set_extension("pub");
121 if priv_path
.exists() && public_path
.exists() { return Ok(()); }
123 let rsa
= Rsa
::generate(4096).unwrap();
125 let priv_pem
= rsa
.private_key_to_pem()?
;
127 use nix
::sys
::stat
::Mode
;
130 &priv_path
, &priv_pem
, CreateOptions
::new().perm(Mode
::from_bits_truncate(0o0600)))?
;
132 let public_pem
= rsa
.public_key_to_pem()?
;
134 let backup_user
= crate::backup
::backup_user()?
;
140 .perm(Mode
::from_bits_truncate(0o0640))
141 .owner(nix
::unistd
::ROOT
)
142 .group(backup_user
.gid
),
148 pub fn csrf_secret() -> &'
static [u8] {
151 static ref SECRET
: Vec
<u8> =
152 file_get_contents(configdir
!("/csrf.key")).unwrap();
158 fn load_private_auth_key() -> Result
<PKey
<Private
>, Error
> {
160 let pem
= file_get_contents(configdir
!("/authkey.key"))?
;
161 let rsa
= Rsa
::private_key_from_pem(&pem
)?
;
162 let key
= PKey
::from_rsa(rsa
)?
;
167 pub fn private_auth_key() -> &'
static PKey
<Private
> {
170 static ref KEY
: PKey
<Private
> = load_private_auth_key().unwrap();
176 fn load_public_auth_key() -> Result
<PKey
<Public
>, Error
> {
178 let pem
= file_get_contents(configdir
!("/authkey.pub"))?
;
179 let rsa
= Rsa
::public_key_from_pem(&pem
)?
;
180 let key
= PKey
::from_rsa(rsa
)?
;
185 pub fn public_auth_key() -> &'
static PKey
<Public
> {
188 static ref KEY
: PKey
<Public
> = load_public_auth_key().unwrap();