import { int } from 'aws-sdk/clients/datapipeline' ; import { ETLD_NAMES_LIST } from './etld_names_list.js' ; import { getOriginFromUrl } from './url' ; export const BAD_APPID = 2 ; param facet param appId function checkCanFacetClaimAppId ( facet , appId ) { if ( appId === facet ) { return true ; } const appIdOrigin = getOriginFromUrl ( appId ) ; if ( ! appIdOrigin ) { return false ; } const appIdLspl = getLeastSpecificPrivateLabel ( appIdOrigin ) ; const facetLspl = getLeastSpecificPrivateLabel ( facet ) ; if ( facetLspl === appIdLspl ) { return true ; } if ( facetLspl === 'google.com' ) { return appIdLspl === 'gstatic.com' ; } return false ; } param originalHost param hostSuffixString export function checkIsRegistrableDomainSuffix ( origin , hostSuffixString ) { if ( ! hostSuffixString || hostSuffixString === '' ) { return false ; } const originUrl = new URL ( origin ) ; const originalHost = originUrl . hostname ; const host = hostSuffixString ; if ( host !== originalHost ) { const hostLspl = getLeastSpecificPrivateLabel ( host ) ; const originalHostLspl = getLeastSpecificPrivateLabel ( originalHost ) ; if ( ! hostLspl || ! originalHostLspl ) { return false ; } if ( ! originalHost . endsWith ( '.' + host ) ) { return false ; } } return true ; } param appId export function fetchAppIdUrl ( appId ) { return new Promise ( function ( resolve , reject ) { const xhr = new XMLHttpRequest ( ) ; xhr . open ( 'GET' , appId , true ) ; xhr . onloadend = function ( ) { if ( xhr . status !== 200 ) { reject ( xhr . status ) ; return ; } resolve ( xhr . responseText ) ; } ; xhr . onerror = function ( ) { reject ( 404 ) ; } ; xhr . send ( ) ; } ) ; } param origin function getLeastSpecificPrivateLabel ( origin ) { let host ; if ( origin . indexOf ( 'http://' ) === 0 ) { host = origin . substring ( 7 ) ; } else if ( origin . indexOf ( 'https://' ) === 0 ) { host = origin . substring ( 8 ) ; } else { host = origin ; } if ( host . indexOf ( ':' ) !== - 1 ) { host = host . substring ( 0 , host . indexOf ( ':' ) ) ; } if ( host === 'localhost' ) { return host ; } let prev = '' ; let next = host ; while ( true ) { const dot = next . indexOf ( '.' ) ; if ( dot === - 1 ) { return null ; } prev = next ; next = next . substring ( dot + 1 ) ; if ( ETLD_NAMES_LIST . indexOf ( next ) >= 0 ) { return prev ; } } } param { string } text return { ! Array < string > } function getOriginsFromJson ( text ) { try { let urls ; const appIdData = JSON . parse ( text ) ; if ( Array . isArray ( appIdData ) ) { urls = appIdData ; } else { const trustedFacets = appIdData [ 'trustedFacets' ] ; if ( trustedFacets ) { for ( const versionBlock of trustedFacets ) { if ( versionBlock [ 'version' ] && versionBlock [ 'version' ] [ 'major' ] === 1 && versionBlock [ 'version' ] [ 'minor' ] === 0 ) { urls = versionBlock [ 'ids' ] ; break ; } } } if ( typeof urls === 'undefined' ) { throw Error ( 'Could not find trustedFacets for version 1.0' ) ; } } const origins = { } ; for ( const url of urls ) { const origin = getOriginFromUrl ( url ) ; if ( origin ) { if ( origin . indexOf ( 'https://' ) === 0 ) { origins [ origin ] = origin ; } } } return Object . keys ( origins ) ; } catch ( e ) { console . error ( 'could not parse ' + text ) ; return [ ] ; } } /**
 * FIDO AppId (v1.2) 3.1.2.10-13
 */ async function getTrustedFacetsFromAppId ( appId , remainingRetryAttempts , fetcher ) { { if ( remainingRetryAttempts <= 0 ) { return [ ] ; } if ( ! appId ) { return Promise . resolve ( [ ] ) ; } if ( appId . indexOf ( 'http://' ) === 0 ) { console . error ( 'http app ids not allowed' ) ; return Promise . resolve ( [ ] ) ; } const origin = getOriginFromUrl ( appId ) ; if ( ! origin ) { return Promise . resolve ( [ ] ) ; } } { const text = fetcher ( appId ) ; const facets = await text . then ( getOriginsFromJson , async function ( rc_ ) { const rc = ( rc_ ) ; console . error ( 'fetching ' + appId + ' failed: ' + rc ) ; if ( ! ( rc >= 400 && rc < 500 ) ) { await new Promise ( ( resolve ) => setTimeout ( resolve , 1000 ) ) ; return getTrustedFacetsFromAppId ( appId , remainingRetryAttempts - 1 , fetcher ) ; } return [ ] ; } ) ; return facets . map ( ( facet ) => facet . toLowerCase ( ) ) . filter ( ( facet ) => checkCanFacetClaimAppId ( facet , appId ) ) ; } } param facetId param appId export async function verifyU2fAppId ( facetId , appId , fetcher ) { if ( appId ) { const appIdOrigin = getOriginFromUrl ( appId ) ; if ( appIdOrigin == null ) { return Promise . reject ( "appId '" + appId + "' does not have a valid origin" ) ; } const appIdNonOrigin = appId . substring ( appIdOrigin . length , appId . length ) ; appId = appIdOrigin . toLowerCase ( ) + appIdNonOrigin ; } facetId = facetId . toLowerCase ( ) ; if ( appId === facetId ) { return Promise . resolve ( ) ; } if ( ! appId ) { return Promise . resolve ( ) ; } if ( ! checkCanFacetClaimAppId ( facetId , appId ) ) { return Promise . reject ( 'FacetID cannot claim given AppID ' + appId ) ; } const trustedFacets = await getTrustedFacetsFromAppId ( appId , 5 , fetcher ) ; if ( trustedFacets . indexOf ( facetId ) === - 1 ) { return Promise . reject ( 'Trusted Facets list does not include the requesting FacetID ' + facetId ) ; } return Promise . resolve ( ) ; }