2018-02-10 01:00:55 +01:00
mod accounts ;
mod ciphers ;
mod folders ;
2018-02-17 22:30:19 +01:00
mod organizations ;
2018-07-12 21:46:50 +02:00
pub ( crate ) mod two_factor ;
2018-02-10 01:00:55 +01:00
pub fn routes ( ) -> Vec < Route > {
2018-10-10 20:40:39 +02:00
let mut mod_routes = routes! [
2018-02-10 01:00:55 +01:00
clear_device_token ,
put_device_token ,
get_eq_domains ,
2018-04-20 18:35:11 +02:00
post_eq_domains ,
2018-10-23 00:32:43 +02:00
put_eq_domains ,
2019-01-20 15:36:33 +01:00
hibp_breach ,
2018-10-10 20:40:39 +02: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 18:35:11 +02:00
2018-10-10 20:40:39 +02:00
routes
2018-02-10 01:00:55 +01:00
}
2018-12-30 23:34:31 +01:00
//
// Move this somewhere else
//
2018-02-10 01:00:55 +01:00
use rocket ::Route ;
2018-10-10 20:40:39 +02:00
use rocket_contrib ::json ::Json ;
use serde_json ::Value ;
2018-02-10 01:00:55 +01:00
2018-12-07 18:25:18 +01:00
use crate ::api ::{ EmptyResult , JsonResult , JsonUpcase } ;
2018-12-07 02:05:45 +01:00
use crate ::auth ::Headers ;
2019-03-14 00:17:36 +01:00
use crate ::db ::DbConn ;
use crate ::error ::Error ;
2018-02-10 01:00:55 +01:00
2018-12-06 16:28:36 +01:00
#[ put( " /devices/identifier/<uuid>/clear-token " ) ]
2018-12-07 18:25:18 +01: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 15:08:03 +02:00
2018-12-06 16:28:36 +01: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 20:47:13 +01:00
}
2018-02-10 01:00:55 +01:00
2018-06-01 15:08:03 +02:00
#[ put( " /devices/identifier/<uuid>/token " , data = " <data> " ) ]
2018-12-07 18:25:18 +01:00
fn put_device_token ( uuid : String , data : JsonUpcase < Value > , headers : Headers ) -> JsonResult {
2018-10-10 20:40:39 +02:00
let _data : Value = data . into_inner ( ) . data ;
2018-12-07 18:25:18 +01:00
// Data has a single string value "PushToken"
let _ = uuid ;
// uuid is not related to deviceId
2018-12-06 16:28:36 +01:00
2018-12-07 18:25:18 +01:00
// TODO: This should save the push token, but we don't have push functionality
2018-12-06 16:28:36 +01:00
Ok ( Json ( json! ( {
2018-12-07 18:25:18 +01:00
" Id " : headers . device . uuid ,
" Name " : headers . device . name ,
2019-05-20 21:24:29 +02:00
" Type " : headers . device . atype ,
2018-12-07 18:25:18 +01:00
" Identifier " : headers . device . uuid ,
" CreationDate " : crate ::util ::format_date ( & headers . device . created_at ) ,
2018-12-06 16:28:36 +01:00
} ) ) )
2018-02-17 20:47:13 +01: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 " ) ]
2018-02-20 14:09:00 +01:00
fn get_eq_domains ( headers : Headers ) -> JsonResult {
2019-11-05 03:30:57 +01:00
_get_eq_domains ( headers , false )
}
fn _get_eq_domains ( headers : Headers , no_excluded : bool ) -> JsonResult {
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 ) ;
}
2018-02-17 23:21:04 +01:00
Ok ( Json ( json! ( {
" EquivalentDomains " : equivalent_domains ,
2018-02-20 14:09:00 +01:00
" GlobalEquivalentDomains " : globals ,
" Object " : " domains " ,
2018-02-17 23:21:04 +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> " ) ]
2018-10-23 00:32:43 +02:00
fn post_eq_domains ( data : JsonUpcase < EquivDomainData > , headers : Headers , conn : DbConn ) -> 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
2018-12-19 21:52:53 +01:00
user . save ( & conn ) ? ;
Ok ( Json ( json! ( { } ) ) )
2018-02-10 01:00:55 +01:00
}
2018-10-23 00:32:43 +02: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 15:36:33 +01:00
#[ get( " /hibp/breach?<username> " ) ]
fn hibp_breach ( username : String ) -> JsonResult {
let user_agent = " Bitwarden_RS " ;
2019-08-20 20:07:12 +02:00
let url = format! (
" https://haveibeenpwned.com/api/v3/breachedaccount/{}?truncateResponse=false&includeUnverified=false " ,
username
) ;
2019-01-20 15:36:33 +01:00
use reqwest ::{ header ::USER_AGENT , Client } ;
2019-08-20 20:07:12 +02:00
if let Some ( api_key ) = crate ::CONFIG . hibp_api_key ( ) {
2019-12-27 18:37:14 +01:00
let hibp_client = Client ::builder ( ) . use_sys_proxy ( ) . build ( ) ? ;
2019-10-08 21:39:11 +02:00
2019-12-27 18:37:14 +01:00
let res = hibp_client
. get ( & url )
2019-08-20 20:07:12 +02: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 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 " ,
2019-10-08 22:29:12 +02: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 ) ,
" LogoPath " : " /bwrs_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
}