2022-03-20 18:51:24 +01:00
pub mod accounts ;
2018-02-10 01:00:55 +01:00
mod ciphers ;
Added web-vault v2.21.x support + some misc fixes
- The new web-vault v2.21.0+ has support for Master Password Reset. For
this to work it generates a public/private key-pair which needs to be
stored in the database. Currently the Master Password Reset is not
fixed, but there are endpoints which are needed even if we do not
support this feature (yet). This PR fixes those endpoints, and stores
the keys already in the database.
- There was an issue when you want to do a key-rotate when you change
your password, it also called an Emergency Access endpoint, which we do
not yet support. Because this endpoint failed to reply correctly
produced some errors, and also prevent the user from being forced to
logout. This resolves #1826 by adding at least that endpoint.
Because of that extra endpoint check to Emergency Access is done using
an old user stamp, i also modified the stamp exception to allow multiple
rocket routes to be called, and added an expiration timestamp to it.
During these tests i stumbled upon an issue that after my key-change was
done, it triggered the websockets to try and reload my ciphers, because
they were updated. This shouldn't happen when rotating they keys, since
all access should be invalided. Now there will be no websocket
notification for this, which also prevents error toasts.
- Increased Send Size limit to 500MB (with a litle overhead)
As a side note, i tested these changes on both v2.20.4 and v2.21.1 web-vault versions, all keeps working.
2021-07-04 23:02:56 +02:00
mod emergency_access ;
2022-11-20 19:15:45 +01:00
mod events ;
2018-02-10 01:00:55 +01:00
mod folders ;
2018-02-17 22:30:19 +01:00
mod organizations ;
2023-06-02 22:28:30 +02:00
mod public ;
2021-03-14 23:35:55 +01:00
mod sends ;
2021-03-31 22:18:35 +02:00
pub mod two_factor ;
2018-02-10 01:00:55 +01:00
2023-08-04 21:12:23 +02:00
pub use accounts ::purge_auth_requests ;
2023-01-01 15:09:10 +01:00
pub use ciphers ::{ purge_trashed_ciphers , CipherData , CipherSyncData , CipherSyncType } ;
2021-03-24 20:15:55 +01:00
pub use emergency_access ::{ emergency_notification_reminder_job , emergency_request_timeout_job } ;
2022-11-20 19:15:45 +01:00
pub use events ::{ event_cleanup_job , log_event , log_user_event } ;
2021-04-03 05:16:49 +02:00
pub use sends ::purge_sends ;
2021-10-25 10:36:05 +02:00
pub use two_factor ::send_incomplete_2fa_notifications ;
2021-03-22 19:57:35 +01:00
2018-02-10 01:00:55 +01:00
pub fn routes ( ) -> Vec < Route > {
2022-04-24 08:47:49 +02:00
let mut eq_domains_routes = routes! [ get_eq_domains , post_eq_domains , put_eq_domains ] ;
let mut hibp_routes = routes! [ hibp_breach ] ;
2022-09-08 17:38:00 +02:00
let mut meta_routes = routes! [ alive , now , version , config ] ;
2018-10-10 20:40:39 +02:00
let mut routes = Vec ::new ( ) ;
routes . append ( & mut accounts ::routes ( ) ) ;
routes . append ( & mut ciphers ::routes ( ) ) ;
Added web-vault v2.21.x support + some misc fixes
- The new web-vault v2.21.0+ has support for Master Password Reset. For
this to work it generates a public/private key-pair which needs to be
stored in the database. Currently the Master Password Reset is not
fixed, but there are endpoints which are needed even if we do not
support this feature (yet). This PR fixes those endpoints, and stores
the keys already in the database.
- There was an issue when you want to do a key-rotate when you change
your password, it also called an Emergency Access endpoint, which we do
not yet support. Because this endpoint failed to reply correctly
produced some errors, and also prevent the user from being forced to
logout. This resolves #1826 by adding at least that endpoint.
Because of that extra endpoint check to Emergency Access is done using
an old user stamp, i also modified the stamp exception to allow multiple
rocket routes to be called, and added an expiration timestamp to it.
During these tests i stumbled upon an issue that after my key-change was
done, it triggered the websockets to try and reload my ciphers, because
they were updated. This shouldn't happen when rotating they keys, since
all access should be invalided. Now there will be no websocket
notification for this, which also prevents error toasts.
- Increased Send Size limit to 500MB (with a litle overhead)
As a side note, i tested these changes on both v2.20.4 and v2.21.1 web-vault versions, all keeps working.
2021-07-04 23:02:56 +02:00
routes . append ( & mut emergency_access ::routes ( ) ) ;
2022-11-20 19:15:45 +01:00
routes . append ( & mut events ::routes ( ) ) ;
2018-10-10 20:40:39 +02:00
routes . append ( & mut folders ::routes ( ) ) ;
routes . append ( & mut organizations ::routes ( ) ) ;
routes . append ( & mut two_factor ::routes ( ) ) ;
2021-03-14 23:35:55 +01:00
routes . append ( & mut sends ::routes ( ) ) ;
2023-06-02 22:28:30 +02:00
routes . append ( & mut public ::routes ( ) ) ;
2022-04-24 08:47:49 +02:00
routes . append ( & mut eq_domains_routes ) ;
routes . append ( & mut hibp_routes ) ;
routes . append ( & mut meta_routes ) ;
2018-04-20 18:35:11 +02:00
2018-10-10 20:40:39 +02:00
routes
2018-02-10 01:00:55 +01:00
}
2022-11-20 19:15:45 +01:00
pub fn events_routes ( ) -> Vec < Route > {
let mut routes = Vec ::new ( ) ;
routes . append ( & mut events ::main_routes ( ) ) ;
routes
}
2018-12-30 23:34:31 +01:00
//
// Move this somewhere else
//
2022-12-30 21:23:55 +01:00
use rocket ::{ serde ::json ::Json , Catcher , Route } ;
2018-10-10 20:40:39 +02:00
use serde_json ::Value ;
2018-02-10 01:00:55 +01:00
2020-07-14 18:00:09 +02:00
use crate ::{
2022-12-30 21:23:55 +01:00
api ::{ JsonResult , JsonUpcase , Notify , UpdateType } ,
2020-07-14 18:00:09 +02:00
auth ::Headers ,
db ::DbConn ,
error ::Error ,
2021-04-06 22:04:37 +02:00
util ::get_reqwest_client ,
2020-07-14 18:00:09 +02:00
} ;
2018-02-10 01:00:55 +01:00
2018-02-17 23:21:04 +01:00
#[ derive(Serialize, Deserialize, Debug) ]
#[ allow(non_snake_case) ]
struct GlobalDomain {
Type : i32 ,
Domains : Vec < String > ,
Excluded : bool ,
}
2018-12-18 01:53:21 +01:00
const GLOBAL_DOMAINS : & str = include_str! ( " ../../static/global_domains.json " ) ;
2018-02-17 23:21:04 +01:00
2018-02-10 01:00:55 +01:00
#[ get( " /settings/domains " ) ]
2021-03-27 16:07:26 +01:00
fn get_eq_domains ( headers : Headers ) -> Json < Value > {
2019-11-05 03:30:57 +01:00
_get_eq_domains ( headers , false )
}
2021-03-27 16:07:26 +01:00
fn _get_eq_domains ( headers : Headers , no_excluded : bool ) -> Json < Value > {
2018-02-17 23:21:04 +01:00
let user = headers . user ;
use serde_json ::from_str ;
let equivalent_domains : Vec < Vec < String > > = from_str ( & user . equivalent_domains ) . unwrap ( ) ;
let excluded_globals : Vec < i32 > = from_str ( & user . excluded_globals ) . unwrap ( ) ;
let mut globals : Vec < GlobalDomain > = from_str ( GLOBAL_DOMAINS ) . unwrap ( ) ;
for global in & mut globals {
global . Excluded = excluded_globals . contains ( & global . Type ) ;
}
2019-11-05 03:30:57 +01:00
if no_excluded {
globals . retain ( | g | ! g . Excluded ) ;
}
2021-03-27 16:07:26 +01:00
Json ( json! ( {
2018-02-17 23:21:04 +01:00
" EquivalentDomains " : equivalent_domains ,
2018-02-20 14:09:00 +01:00
" GlobalEquivalentDomains " : globals ,
" Object " : " domains " ,
2021-03-27 16:07:26 +01:00
} ) )
2018-02-10 01:00:55 +01:00
}
2018-02-23 00:38:54 +01:00
#[ derive(Deserialize, Debug) ]
#[ allow(non_snake_case) ]
struct EquivDomainData {
ExcludedGlobalEquivalentDomains : Option < Vec < i32 > > ,
EquivalentDomains : Option < Vec < Vec < String > > > ,
}
2018-02-15 00:40:34 +01:00
#[ post( " /settings/domains " , data = " <data> " ) ]
2022-12-30 21:23:55 +01:00
async fn post_eq_domains (
data : JsonUpcase < EquivDomainData > ,
headers : Headers ,
mut conn : DbConn ,
nt : Notify < '_ > ,
) -> JsonResult {
2018-06-01 00:18:50 +02:00
let data : EquivDomainData = data . into_inner ( ) . data ;
2018-02-15 00:40:34 +01:00
2018-06-11 15:44:37 +02:00
let excluded_globals = data . ExcludedGlobalEquivalentDomains . unwrap_or_default ( ) ;
let equivalent_domains = data . EquivalentDomains . unwrap_or_default ( ) ;
2018-02-15 00:40:34 +01:00
2018-02-17 23:21:04 +01:00
let mut user = headers . user ;
use serde_json ::to_string ;
2018-02-15 00:40:34 +01:00
2019-02-08 18:45:07 +01:00
user . excluded_globals = to_string ( & excluded_globals ) . unwrap_or_else ( | _ | " [] " . to_string ( ) ) ;
user . equivalent_domains = to_string ( & equivalent_domains ) . unwrap_or_else ( | _ | " [] " . to_string ( ) ) ;
2018-02-17 23:21:04 +01:00
2022-05-20 23:39:47 +02:00
user . save ( & mut conn ) . await ? ;
2018-12-19 21:52:53 +01:00
2022-12-30 21:23:55 +01:00
nt . send_user_update ( UpdateType ::SyncSettings , & user ) . await ;
2018-12-19 21:52:53 +01:00
Ok ( Json ( json! ( { } ) ) )
2018-02-10 01:00:55 +01:00
}
2018-10-23 00:32:43 +02:00
#[ put( " /settings/domains " , data = " <data> " ) ]
2022-12-30 21:23:55 +01:00
async fn put_eq_domains (
data : JsonUpcase < EquivDomainData > ,
headers : Headers ,
conn : DbConn ,
nt : Notify < '_ > ,
) -> JsonResult {
post_eq_domains ( data , headers , conn , nt ) . await
2018-10-23 00:32:43 +02:00
}
2019-01-20 15:36:33 +01:00
#[ get( " /hibp/breach?<username> " ) ]
2023-04-30 17:18:12 +02:00
async fn hibp_breach ( username : & str ) -> JsonResult {
2019-08-20 20:07:12 +02:00
let url = format! (
2022-12-29 14:11:52 +01:00
" https://haveibeenpwned.com/api/v3/breachedaccount/{username}?truncateResponse=false&includeUnverified=false "
2019-08-20 20:07:12 +02:00
) ;
2019-01-20 15:36:33 +01:00
2019-08-20 20:07:12 +02:00
if let Some ( api_key ) = crate ::CONFIG . hibp_api_key ( ) {
2021-04-06 22:04:37 +02:00
let hibp_client = get_reqwest_client ( ) ;
2019-10-08 21:39:11 +02:00
2021-11-07 18:53:39 +01:00
let res = hibp_client . get ( & url ) . header ( " hibp-api-key " , api_key ) . send ( ) . await ? ;
2019-08-20 20:07:12 +02:00
// If we get a 404, return a 404, it means no breached accounts
if res . status ( ) = = 404 {
return Err ( Error ::empty ( ) . with_code ( 404 ) ) ;
}
2021-11-07 18:53:39 +01:00
let value : Value = res . error_for_status ( ) ? . json ( ) . await ? ;
2019-08-20 20:07:12 +02:00
Ok ( Json ( value ) )
} else {
Ok ( Json ( json! ( [ {
2019-10-08 21:39:11 +02:00
" Name " : " HaveIBeenPwned " ,
2019-10-08 22:29:12 +02:00
" Title " : " Manual HIBP Check " ,
2019-10-08 21:39:11 +02:00
" Domain " : " haveibeenpwned.com " ,
" BreachDate " : " 2019-08-18T00:00:00Z " ,
" AddedDate " : " 2019-08-18T00:00:00Z " ,
2022-12-29 14:11:52 +01:00
" Description " : format ! ( " Go to: <a href= \" https://haveibeenpwned.com/account/{username} \" target= \" _blank \" rel= \" noreferrer \" >https://haveibeenpwned.com/account/{username}</a> for a manual check.<br/><br/>HaveIBeenPwned API key not set!<br/>Go to <a href= \" https://haveibeenpwned.com/API/Key \" target= \" _blank \" rel= \" noreferrer \" >https://haveibeenpwned.com/API/Key</a> to purchase an API key from HaveIBeenPwned.<br/><br/> " ) ,
2022-01-23 23:40:59 +01:00
" LogoPath " : " vw_static/hibp.png " ,
2019-10-08 21:39:11 +02:00
" PwnCount " : 0 ,
" DataClasses " : [
2019-10-08 22:29:12 +02:00
" Error - No API key set! "
2019-10-08 21:39:11 +02:00
]
2019-08-20 20:07:12 +02:00
} ] ) ) )
2019-03-14 00:17:36 +01:00
}
2019-01-20 15:36:33 +01:00
}
2022-04-24 08:47:49 +02:00
// We use DbConn here to let the alive healthcheck also verify the database connection.
#[ get( " /alive " ) ]
fn alive ( _conn : DbConn ) -> Json < String > {
now ( )
}
#[ get( " /now " ) ]
pub fn now ( ) -> Json < String > {
Json ( crate ::util ::format_date ( & chrono ::Utc ::now ( ) . naive_utc ( ) ) )
}
#[ get( " /version " ) ]
fn version ( ) -> Json < & 'static str > {
Json ( crate ::VERSION . unwrap_or_default ( ) )
}
2022-09-08 17:38:00 +02:00
#[ get( " /config " ) ]
fn config ( ) -> Json < Value > {
let domain = crate ::CONFIG . domain ( ) ;
Json ( json! ( {
2023-10-23 00:18:14 +02:00
// Note: The clients use this version to handle backwards compatibility concerns
// This means they expect a version that closely matches the Bitwarden server version
// We should make sure that we keep this updated when we support the new server features
// Version history:
// - Individual cipher key encryption: 2023.9.1
" version " : " 2023.9.1 " ,
2022-09-08 18:01:27 +02:00
" gitHash " : option_env ! ( " GIT_REV " ) ,
2022-09-08 17:38:00 +02:00
" server " : {
" name " : " Vaultwarden " ,
" url " : " https://github.com/dani-garcia/vaultwarden "
} ,
" environment " : {
" vault " : domain ,
" api " : format ! ( " {domain}/api " ) ,
" identity " : format ! ( " {domain}/identity " ) ,
" notifications " : format ! ( " {domain}/notifications " ) ,
" sso " : " " ,
} ,
2023-10-23 00:18:14 +02:00
" featureStates " : {
// Any feature flags that we want the clients to use
// Can check the enabled ones at:
// https://vault.bitwarden.com/api/config
2023-11-04 03:08:45 +01:00
" autofill-v2 " : true ,
" fido2-vault-credentials " : true
2023-10-23 00:18:14 +02:00
} ,
2023-02-27 16:37:58 +01:00
" object " : " config " ,
2022-09-08 17:38:00 +02:00
} ) )
}
2022-09-25 10:55:55 +02:00
pub fn catchers ( ) -> Vec < Catcher > {
catchers! [ api_not_found ]
}
#[ catch(404) ]
fn api_not_found ( ) -> Json < Value > {
Json ( json! ( {
" error " : {
" code " : 404 ,
" reason " : " Not Found " ,
" description " : " The requested resource could not be found. "
}
} ) )
}