2018-02-10 00:00:55 +00:00
mod accounts ;
mod ciphers ;
mod folders ;
2018-02-17 21:30:19 +00:00
mod organizations ;
2020-05-03 15:24:51 +00:00
pub mod two_factor ;
2018-02-10 00:00:55 +00:00
pub fn routes ( ) -> Vec < Route > {
2018-10-10 18:40:39 +00:00
let mut mod_routes = routes! [
2018-02-10 00:00:55 +00:00
clear_device_token ,
put_device_token ,
get_eq_domains ,
2018-04-20 16:35:11 +00:00
post_eq_domains ,
2018-10-22 22:32:43 +00:00
put_eq_domains ,
2019-01-20 14:36:33 +00:00
hibp_breach ,
2018-10-10 18:40:39 +00:00
] ;
let mut routes = Vec ::new ( ) ;
routes . append ( & mut accounts ::routes ( ) ) ;
routes . append ( & mut ciphers ::routes ( ) ) ;
routes . append ( & mut folders ::routes ( ) ) ;
routes . append ( & mut organizations ::routes ( ) ) ;
routes . append ( & mut two_factor ::routes ( ) ) ;
routes . append ( & mut mod_routes ) ;
2018-04-20 16:35:11 +00:00
2018-10-10 18:40:39 +00:00
routes
2018-02-10 00:00:55 +00:00
}
2018-12-30 22:34:31 +00:00
//
// Move this somewhere else
//
2018-02-10 00:00:55 +00:00
use rocket ::Route ;
2018-10-10 18:40:39 +00:00
use rocket_contrib ::json ::Json ;
use serde_json ::Value ;
2018-02-10 00:00:55 +00:00
2020-07-14 16:00:09 +00:00
use crate ::{
api ::{ EmptyResult , JsonResult , JsonUpcase } ,
auth ::Headers ,
db ::DbConn ,
error ::Error ,
} ;
2018-02-10 00:00:55 +00:00
2018-12-06 15:28:36 +00:00
#[ put( " /devices/identifier/<uuid>/clear-token " ) ]
2018-12-07 17:25:18 +00:00
fn clear_device_token ( uuid : String ) -> EmptyResult {
// This endpoint doesn't have auth header
let _ = uuid ;
// uuid is not related to deviceId
2018-06-01 13:08:03 +00:00
2018-12-06 15:28:36 +00:00
// This only clears push token
// https://github.com/bitwarden/core/blob/master/src/Api/Controllers/DevicesController.cs#L109
// https://github.com/bitwarden/core/blob/master/src/Core/Services/Implementations/DeviceService.cs#L37
Ok ( ( ) )
2018-02-17 19:47:13 +00:00
}
2018-02-10 00:00:55 +00:00
2018-06-01 13:08:03 +00:00
#[ put( " /devices/identifier/<uuid>/token " , data = " <data> " ) ]
2018-12-07 17:25:18 +00:00
fn put_device_token ( uuid : String , data : JsonUpcase < Value > , headers : Headers ) -> JsonResult {
2018-10-10 18:40:39 +00:00
let _data : Value = data . into_inner ( ) . data ;
2018-12-07 17:25:18 +00:00
// Data has a single string value "PushToken"
let _ = uuid ;
// uuid is not related to deviceId
2018-12-06 15:28:36 +00:00
2018-12-07 17:25:18 +00:00
// TODO: This should save the push token, but we don't have push functionality
2018-12-06 15:28:36 +00:00
Ok ( Json ( json! ( {
2018-12-07 17:25:18 +00:00
" Id " : headers . device . uuid ,
" Name " : headers . device . name ,
2019-05-20 19:24:29 +00:00
" Type " : headers . device . atype ,
2018-12-07 17:25:18 +00:00
" Identifier " : headers . device . uuid ,
" CreationDate " : crate ::util ::format_date ( & headers . device . created_at ) ,
2018-12-06 15:28:36 +00:00
} ) ) )
2018-02-17 19:47:13 +00:00
}
2018-02-10 00:00:55 +00:00
2018-02-17 22:21:04 +00:00
#[ derive(Serialize, Deserialize, Debug) ]
#[ allow(non_snake_case) ]
struct GlobalDomain {
Type : i32 ,
Domains : Vec < String > ,
Excluded : bool ,
}
2018-12-18 00:53:21 +00:00
const GLOBAL_DOMAINS : & str = include_str! ( " ../../static/global_domains.json " ) ;
2018-02-17 22:21:04 +00:00
2018-02-10 00:00:55 +00:00
#[ get( " /settings/domains " ) ]
2018-02-20 13:09:00 +00:00
fn get_eq_domains ( headers : Headers ) -> JsonResult {
2019-11-05 02:30:57 +00:00
_get_eq_domains ( headers , false )
}
fn _get_eq_domains ( headers : Headers , no_excluded : bool ) -> JsonResult {
2018-02-17 22:21:04 +00: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 02:30:57 +00:00
if no_excluded {
globals . retain ( | g | ! g . Excluded ) ;
}
2018-02-17 22:21:04 +00:00
Ok ( Json ( json! ( {
" EquivalentDomains " : equivalent_domains ,
2018-02-20 13:09:00 +00:00
" GlobalEquivalentDomains " : globals ,
" Object " : " domains " ,
2018-02-17 22:21:04 +00:00
} ) ) )
2018-02-10 00:00:55 +00:00
}
2018-02-22 23:38:54 +00:00
#[ derive(Deserialize, Debug) ]
#[ allow(non_snake_case) ]
struct EquivDomainData {
ExcludedGlobalEquivalentDomains : Option < Vec < i32 > > ,
EquivalentDomains : Option < Vec < Vec < String > > > ,
}
2018-02-14 23:40:34 +00:00
#[ post( " /settings/domains " , data = " <data> " ) ]
2018-10-22 22:32:43 +00:00
fn post_eq_domains ( data : JsonUpcase < EquivDomainData > , headers : Headers , conn : DbConn ) -> JsonResult {
2018-05-31 22:18:50 +00:00
let data : EquivDomainData = data . into_inner ( ) . data ;
2018-02-14 23:40:34 +00:00
2018-06-11 13:44:37 +00:00
let excluded_globals = data . ExcludedGlobalEquivalentDomains . unwrap_or_default ( ) ;
let equivalent_domains = data . EquivalentDomains . unwrap_or_default ( ) ;
2018-02-14 23:40:34 +00:00
2018-02-17 22:21:04 +00:00
let mut user = headers . user ;
use serde_json ::to_string ;
2018-02-14 23:40:34 +00:00
2019-02-08 17:45:07 +00: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 22:21:04 +00:00
2018-12-19 20:52:53 +00:00
user . save ( & conn ) ? ;
Ok ( Json ( json! ( { } ) ) )
2018-02-10 00:00:55 +00:00
}
2018-10-22 22:32:43 +00:00
#[ put( " /settings/domains " , data = " <data> " ) ]
fn put_eq_domains ( data : JsonUpcase < EquivDomainData > , headers : Headers , conn : DbConn ) -> JsonResult {
post_eq_domains ( data , headers , conn )
}
2019-01-20 14:36:33 +00:00
#[ get( " /hibp/breach?<username> " ) ]
fn hibp_breach ( username : String ) -> JsonResult {
let user_agent = " Bitwarden_RS " ;
2019-08-20 18:07:12 +00:00
let url = format! (
" https://haveibeenpwned.com/api/v3/breachedaccount/{}?truncateResponse=false&includeUnverified=false " ,
username
) ;
2019-01-20 14:36:33 +00:00
2020-07-14 16:00:09 +00:00
use reqwest ::{ blocking ::Client , header ::USER_AGENT } ;
2019-01-20 14:36:33 +00:00
2019-08-20 18:07:12 +00:00
if let Some ( api_key ) = crate ::CONFIG . hibp_api_key ( ) {
2020-03-14 22:12:45 +00:00
let hibp_client = Client ::builder ( ) . build ( ) ? ;
2019-10-08 19:39:11 +00:00
2019-12-27 17:37:14 +00:00
let res = hibp_client
. get ( & url )
2019-08-20 18:07:12 +00:00
. header ( USER_AGENT , user_agent )
. header ( " hibp-api-key " , api_key )
. send ( ) ? ;
// If we get a 404, return a 404, it means no breached accounts
if res . status ( ) = = 404 {
return Err ( Error ::empty ( ) . with_code ( 404 ) ) ;
}
let value : Value = res . error_for_status ( ) ? . json ( ) ? ;
Ok ( Json ( value ) )
} else {
Ok ( Json ( json! ( [ {
2019-10-08 19:39:11 +00:00
" Name " : " HaveIBeenPwned " ,
2019-10-08 20:29:12 +00:00
" Title " : " Manual HIBP Check " ,
2019-10-08 19:39:11 +00:00
" Domain " : " haveibeenpwned.com " ,
" BreachDate " : " 2019-08-18T00:00:00Z " ,
" AddedDate " : " 2019-08-18T00:00:00Z " ,
2019-10-08 20:29:12 +00:00
" Description " : format ! ( " Go to: <a href= \" https://haveibeenpwned.com/account/{account} \" target= \" _blank \" rel= \" noopener \" >https://haveibeenpwned.com/account/{account}</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= \" noopener \" >https://haveibeenpwned.com/API/Key</a> to purchase an API key from HaveIBeenPwned.<br/><br/> " , account = username ) ,
2020-02-19 05:27:00 +00:00
" LogoPath " : " bwrs_static/hibp.png " ,
2019-10-08 19:39:11 +00:00
" PwnCount " : 0 ,
" DataClasses " : [
2019-10-08 20:29:12 +00:00
" Error - No API key set! "
2019-10-08 19:39:11 +00:00
]
2019-08-20 18:07:12 +00:00
} ] ) ) )
2019-03-13 23:17:36 +00:00
}
2019-01-20 14:36:33 +00:00
}